am "am c44430a3: Merge "Tools attribute improvements for RecyclerView LayoutManager." into lmp-mr1-dev automerge: 713e7cc"

merged from goog/mirror-m-wireless-internal-release
fbabcb0 am c44430a3: Merge "Tools attribute improvements for RecyclerView LayoutManager." into lmp-mr1-dev automerge: 713e7cc
diff --git a/Android.mk b/Android.mk
index 81113f7..452d72c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -199,12 +199,14 @@
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/IPermissionController.aidl \
+	core/java/android/os/IProcessInfoService.aidl \
 	core/java/android/os/IPowerManager.aidl \
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
 	core/java/android/os/IUpdateLock.aidl \
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
+	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
@@ -236,6 +238,8 @@
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
 	core/java/android/service/wallpaper/IWallpaperEngine.aidl \
 	core/java/android/service/wallpaper/IWallpaperService.aidl \
+	core/java/android/service/chooser/IChooserTargetService.aidl \
+	core/java/android/service/chooser/IChooserTargetResult.aidl \
 	core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl\
 	core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl\
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
@@ -330,11 +334,20 @@
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
 	media/java/android/media/IVolumeController.aidl \
-        media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/midi/IMidiDeviceListener.aidl \
+	media/java/android/media/midi/IMidiDeviceServer.aidl \
+	media/java/android/media/midi/IMidiManager.aidl \
 	media/java/android/media/projection/IMediaProjection.aidl \
 	media/java/android/media/projection/IMediaProjectionCallback.aidl \
 	media/java/android/media/projection/IMediaProjectionManager.aidl \
 	media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
+	media/java/android/media/routing/IMediaRouteService.aidl \
+	media/java/android/media/routing/IMediaRouteClientCallback.aidl \
+	media/java/android/media/routing/IMediaRouter.aidl \
+	media/java/android/media/routing/IMediaRouterDelegate.aidl \
+	media/java/android/media/routing/IMediaRouterRoutingCallback.aidl \
+	media/java/android/media/routing/IMediaRouterStateCallback.aidl \
 	media/java/android/media/session/IActiveSessionsListener.aidl \
 	media/java/android/media/session/ISessionController.aidl \
 	media/java/android/media/session/ISessionControllerCallback.aidl \
@@ -383,10 +396,10 @@
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/IMms.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
+	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
-	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
 	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
@@ -405,6 +418,7 @@
 LOCAL_MODULE := framework
 
 LOCAL_DX_FLAGS := --core-library --multi-dex
+LOCAL_JACK_FLAGS := --multi-dex native
 
 LOCAL_RMTYPEDEFS := true
 
@@ -416,6 +430,7 @@
 framework_res_R_stamp := \
 	$(call intermediates-dir-for,APPS,framework-res,,COMMON)/src/R.stamp
 $(full_classes_compiled_jar): $(framework_res_R_stamp)
+$(built_dex_intermediate): $(framework_res_R_stamp)
 
 $(framework_module): | $(dir $(framework_module))framework-res.apk
 
@@ -428,6 +443,7 @@
 
 aidl_files := \
 	frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
+	frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/CellInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/SignalStrength.aidl \
 	frameworks/base/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl \
@@ -437,6 +453,7 @@
 	frameworks/base/location/java/android/location/Criteria.aidl \
 	frameworks/base/media/java/android/media/MediaMetadata.aidl \
 	frameworks/base/media/java/android/media/MediaDescription.aidl \
+	frameworks/base/media/java/android/media/routing/MediaRouteSelector.aidl \
 	frameworks/base/media/java/android/media/Rating.aidl \
 	frameworks/base/media/java/android/media/AudioAttributes.aidl \
 	frameworks/base/media/java/android/media/AudioFocusInfo.aidl \
@@ -530,8 +547,11 @@
 	frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
 	frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
+	frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
+	frameworks/base/core/java/android/app/AssistStructure.aidl \
+	frameworks/base/core/java/android/app/AssistContent.aidl \
 	frameworks/base/core/java/android/app/Notification.aidl \
 	frameworks/base/core/java/android/app/WallpaperInfo.aidl \
 	frameworks/base/core/java/android/app/AppOpsManager.aidl \
@@ -584,7 +604,7 @@
 	frameworks/base/core/java/android/bluetooth/le/ScanFilter.aidl \
 	frameworks/base/core/java/android/bluetooth/le/ScanResult.aidl \
 	frameworks/base/core/java/android/bluetooth/BluetoothDevice.aidl \
-	frameworks/base/core/java/android/database/CursorWindow.aidl
+	frameworks/base/core/java/android/database/CursorWindow.aidl \
 
 gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
 $(gen): PRIVATE_SRC_FILES := $(aidl_files)
@@ -599,7 +619,10 @@
 # TODO: deal with com/google/android/googleapps
 packages_to_document := \
 	android \
-	javax/microedition/khronos
+	javax/microedition/khronos \
+	org/apache/http/conn \
+	org/apache/http/params
+
 
 # Search through the base framework dirs for these packages.
 # The result will be relative to frameworks/base.
@@ -620,7 +643,6 @@
 include external/junit/Common.mk
 
 non_base_dirs := \
-	../../external/apache-http/src/org/apache/http \
 	../opt/telephony/src/java/android/provider \
 	../opt/telephony/src/java/android/telephony \
 	../opt/telephony/src/java/android/telephony/gsm \
@@ -1010,21 +1032,12 @@
 # Build ext.jar
 # ============================================================
 
-# NOTICE notes for non-obvious sections
-# apache-http - covered by the Apache Commons section.
-
-
 ext_dirs := \
 	../../external/nist-sip/java \
-	../../external/apache-http/src \
 	../../external/tagsoup/src \
-	../../external/libphonenumber/java/src
 
 ext_src_files := $(call all-java-files-under,$(ext_dirs))
 
-ext_res_dirs := \
-	../../external/libphonenumber/java/src
-
 # ====  the library  =========================================
 include $(CLEAR_VARS)
 
@@ -1032,7 +1045,7 @@
 
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core-libart
-LOCAL_JAVA_RESOURCE_DIRS := $(ext_res_dirs)
+LOCAL_STATIC_JAVA_LIBRARIES := libphonenumber-platform
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := ext
 
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d660224..c812b6a 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -225,6 +225,14 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RsFountainFbo_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java/com/android/internal/telecomm)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/widget/ILockSettingsObserver.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/SystemUI_intermediates/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/Keyguard_intermediates/)
+$(call add-clean-step, rm -f $(OUT_DIR)/target/product/*/system/framework/android.policy.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/inputflinger $(PRODUCT_OUT)/symbols/system/bin/inputflinger)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libinputflingerhost.so $(PRODUCT_OUT)/system/lib64/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libinputflingerhost.so $(PRODUCT_OUT)/symbols/system/lib64/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libinputflingerhost.so $(PRODUCT_OUT)/obj_arm/lib/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
 
 # ******************************************************************
 # 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 4663a0d..2e51637 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,9 +21,11 @@
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+    field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+    field public static final java.lang.String BIND_MEDIA_ROUTE_SERVICE = "android.permission.BIND_MEDIA_ROUTE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -140,6 +142,7 @@
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
+    field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
     field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
     field public static final java.lang.String WAKE_LOCK = "android.permission.WAKE_LOCK";
@@ -295,6 +298,7 @@
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
+    field public static final int allowUndo = 16844006; // 0x10104e6
     field public static final int alpha = 16843551; // 0x101031f
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
@@ -409,6 +413,7 @@
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
+    field public static final int colorBackgroundFloating = 16844007; // 0x10104e7
     field public static final int colorButtonNormal = 16843819; // 0x101042b
     field public static final int colorControlActivated = 16843818; // 0x101042a
     field public static final int colorControlHighlight = 16843820; // 0x101042c
@@ -481,7 +486,7 @@
     field public static final int dialogTitle = 16843250; // 0x10101f2
     field public static final int digits = 16843110; // 0x1010166
     field public static final int direction = 16843217; // 0x10101d1
-    field public static final int directionDescriptions = 16843681; // 0x10103a1
+    field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
     field public static final int disableDependentsState = 16843249; // 0x10101f1
     field public static final int disabledAlpha = 16842803; // 0x1010033
@@ -501,6 +506,8 @@
     field public static final int drawablePadding = 16843121; // 0x1010171
     field public static final int drawableRight = 16843120; // 0x1010170
     field public static final int drawableStart = 16843666; // 0x1010392
+    field public static final int drawableTint = 16843990; // 0x10104d6
+    field public static final int drawableTintMode = 16843991; // 0x10104d7
     field public static final int drawableTop = 16843117; // 0x101016d
     field public static final int drawingCacheQuality = 16842984; // 0x10100e8
     field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -526,6 +533,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -590,6 +598,7 @@
     field public static final int format = 16843013; // 0x1010105
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
+    field public static final int fraction = 16843992; // 0x10104d8
     field public static final int fragment = 16843491; // 0x10102e3
     field public static final int fragmentAllowEnterTransitionOverlap = 16843976; // 0x10104c8
     field public static final int fragmentAllowReturnTransitionOverlap = 16843977; // 0x10104c9
@@ -659,6 +668,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844000; // 0x10104e0
+    field public static final int iconTintMode = 16844001; // 0x10104e1
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -868,6 +879,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
+    field public static final int navigationTint = 16844004; // 0x10104e4
+    field public static final int navigationTintMode = 16844005; // 0x10104e5
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -881,6 +894,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
+    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -898,6 +912,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overflowTint = 16844002; // 0x10104e2
+    field public static final int overflowTintMode = 16844003; // 0x10104e3
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -1010,6 +1026,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1123,6 +1140,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1196,7 +1214,7 @@
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
     field public static final int targetClass = 16842799; // 0x101002f
-    field public static final int targetDescriptions = 16843680; // 0x10103a0
+    field public static final deprecated int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
@@ -1312,6 +1330,8 @@
     field public static final int topRightRadius = 16843178; // 0x10101aa
     field public static final int touchscreenBlocksFocus = 16843919; // 0x101048f
     field public static final int track = 16843631; // 0x101036f
+    field public static final int trackTint = 16843993; // 0x10104d9
+    field public static final int trackTintMode = 16843994; // 0x10104da
     field public static final int transcriptMode = 16843008; // 0x1010100
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
@@ -1403,6 +1423,7 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
+    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
@@ -1699,8 +1720,11 @@
     field public static final int message = 16908299; // 0x102000b
     field public static final int navigationBarBackground = 16908336; // 0x1020030
     field public static final int paste = 16908322; // 0x1020022
+    field public static final int pasteAsPlainText = 16908337; // 0x1020031
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908339; // 0x1020033
+    field public static final int replaceText = 16908340; // 0x1020034
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1717,6 +1741,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908338; // 0x1020032
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -2005,6 +2030,7 @@
     field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
     field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
     field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+    field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
     field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -2076,6 +2102,21 @@
     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 = 16974372; // 0x1030224
+    field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+    field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+    field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+    field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+    field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2095,6 +2136,7 @@
     field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974396; // 0x103023c
     field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974397; // 0x103023d
     field public static final int Theme_Material_Light_Dialog_Presentation = 16974398; // 0x103023e
+    field public static final int Theme_Material_Light_LightStatusBar = 16974563; // 0x10302e3
     field public static final int Theme_Material_Light_NoActionBar = 16974401; // 0x1030241
     field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974402; // 0x1030242
     field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
@@ -2406,6 +2448,7 @@
     field public static final int Widget_Material_Button_Borderless = 16974425; // 0x1030259
     field public static final int Widget_Material_Button_Borderless_Colored = 16974426; // 0x103025a
     field public static final int Widget_Material_Button_Borderless_Small = 16974427; // 0x103025b
+    field public static final int Widget_Material_Button_Colored = 16974547; // 0x10302d3
     field public static final int Widget_Material_Button_Inset = 16974428; // 0x103025c
     field public static final int Widget_Material_Button_Small = 16974429; // 0x103025d
     field public static final int Widget_Material_Button_Toggle = 16974430; // 0x103025e
@@ -3317,6 +3360,7 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
+    method public android.app.VoiceInteractor getVoiceInteractor();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3328,6 +3372,7 @@
     method public boolean isFinishing();
     method public boolean isImmersive();
     method public boolean isTaskRoot();
+    method public boolean isVoiceInteraction();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
@@ -3384,6 +3429,7 @@
     method public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+    method public void onProvideAssistContent(android.app.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
@@ -3405,6 +3451,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void overridePendingTransition(int, int);
@@ -3451,6 +3498,7 @@
     method public final deprecated void showDialog(int);
     method public final deprecated boolean showDialog(int, android.os.Bundle);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startActivityForResult(android.content.Intent, int);
     method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
     method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
@@ -3502,6 +3550,7 @@
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
+    method public int getLockTaskModeState();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3512,7 +3561,7 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
-    method public boolean isInLockTaskMode();
+    method public deprecated boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
@@ -3520,6 +3569,9 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+    field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+    field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
     field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -3668,6 +3720,7 @@
   }
 
   public class ActivityOptions {
+    method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
@@ -3712,8 +3765,8 @@
 
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
-    ctor protected AlertDialog(android.content.Context, int);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    ctor protected AlertDialog(android.content.Context, int);
     method public android.widget.Button getButton(int);
     method public android.widget.ListView getListView();
     method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3732,11 +3785,11 @@
     method public void setMessage(java.lang.CharSequence);
     method public void setView(android.view.View);
     method public void setView(android.view.View, int, int, int, int);
-    field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
-    field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
-    field public static final int THEME_HOLO_DARK = 2; // 0x2
-    field public static final int THEME_HOLO_LIGHT = 3; // 0x3
-    field public static final int THEME_TRADITIONAL = 1; // 0x1
+    field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+    field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+    field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+    field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+    field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
   }
 
   public static class AlertDialog.Builder {
@@ -3751,7 +3804,7 @@
     method public android.app.AlertDialog.Builder setIcon(int);
     method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
     method public android.app.AlertDialog.Builder setIconAttribute(int);
-    method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
     method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setMessage(int);
@@ -3907,6 +3960,69 @@
     field public java.lang.String serviceDetails;
   }
 
+  public class AssistContent implements android.os.Parcelable {
+    ctor public AssistContent();
+    method public int describeContents();
+    method public static android.app.AssistContent getAssistContent(android.os.Bundle);
+    method public android.content.ClipData getClipData();
+    method public android.content.Intent getIntent();
+    method public void setClipData(android.content.ClipData);
+    method public void setIntent(android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist_content";
+    field public static final android.os.Parcelable.Creator<android.app.AssistContent> CREATOR;
+  }
+
+  public final class AssistStructure implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
+    method public void getWindowAt(int, android.app.AssistStructure.ViewNode);
+    method public int getWindowCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
+    field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
+  }
+
+  public static class AssistStructure.ViewNode {
+    ctor public AssistStructure.ViewNode();
+    method public void getChildAt(int, android.app.AssistStructure.ViewNode);
+    method public int getChildCount();
+    method public java.lang.String getClassName();
+    method public java.lang.String getContentDescription();
+    method public android.os.Bundle getExtras();
+    method public int getHeight();
+    method public java.lang.String getHint();
+    method public int getLeft();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public java.lang.CharSequence getText();
+    method public int getTextBackgroundColor();
+    method public int getTextColor();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public float getTextSize();
+    method public int getTextStyle();
+    method public int getTop();
+    method public int getVisibility();
+    method public int getWidth();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActivated();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isLongClickable();
+    method public boolean isSelected();
+    field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
+    field public static final int TEXT_STYLE_BOLD = 1; // 0x1
+    field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
+    field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
+    field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
+  }
+
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -3982,6 +4098,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void registerForContextMenu(android.view.View);
@@ -4375,10 +4492,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -4760,6 +4877,37 @@
     method public android.app.Notification.Builder setWhen(long);
   }
 
+  public static final class Notification.CarExtender implements android.app.Notification.Extender {
+    ctor public Notification.CarExtender();
+    ctor public Notification.CarExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.app.Notification.CarExtender setColor(int);
+    method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
+  }
+
+  public static class Notification.CarExtender.Builder {
+    ctor public Notification.CarExtender.Builder(java.lang.String);
+    method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
+    method public android.app.Notification.CarExtender.UnreadConversation build();
+    method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
+    method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.app.Notification.CarExtender.Builder setReplyAction(android.app.PendingIntent, android.app.RemoteInput);
+  }
+
+  public static class Notification.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
@@ -5182,6 +5330,41 @@
     field public static final int MODE_NIGHT_YES = 2; // 0x2
   }
 
+  public class VoiceInteractor {
+    method public boolean submitRequest(android.app.VoiceInteractor.Request);
+    method public boolean[] supportsCommands(java.lang.String[]);
+  }
+
+  public static class VoiceInteractor.AbortVoiceRequest extends android.app.VoiceInteractor.Request {
+    ctor public VoiceInteractor.AbortVoiceRequest(java.lang.CharSequence, android.os.Bundle);
+    method public void onAbortResult(android.os.Bundle);
+  }
+
+  public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
+    ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
+    method public void onCommandResult(boolean, android.os.Bundle);
+  }
+
+  public static class VoiceInteractor.CompleteVoiceRequest extends android.app.VoiceInteractor.Request {
+    ctor public VoiceInteractor.CompleteVoiceRequest(java.lang.CharSequence, android.os.Bundle);
+    method public void onCompleteResult(android.os.Bundle);
+  }
+
+  public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
+    ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle);
+    method public void onConfirmationResult(boolean, android.os.Bundle);
+  }
+
+  public static abstract class VoiceInteractor.Request {
+    ctor public VoiceInteractor.Request();
+    method public void cancel();
+    method public android.app.Activity getActivity();
+    method public android.content.Context getContext();
+    method public void onAttached(android.app.Activity);
+    method public void onCancel();
+    method public void onDetached();
+  }
+
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -5214,6 +5397,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
@@ -5268,6 +5452,7 @@
     ctor public DeviceAdminReceiver();
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
+    method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, java.lang.String, int, java.lang.String, java.lang.String);
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
     method public void onEnabled(android.content.Context, android.content.Intent);
@@ -5278,6 +5463,7 @@
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
     method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
     method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
+    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5289,6 +5475,7 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5300,6 +5487,7 @@
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
+    method public void clearDeviceInitializerApp(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
@@ -5336,6 +5524,7 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
+    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5343,6 +5532,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isDeviceInitializerApp(java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5359,6 +5549,7 @@
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5384,12 +5575,16 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
+    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setUserEnabled(android.content.ComponentName);
+    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -5401,14 +5596,20 @@
     field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -5630,6 +5831,7 @@
     method public java.lang.String getPackageName();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+    field public static final int INTERACTION = 6; // 0x6
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
@@ -6944,7 +7146,11 @@
     method public android.content.ContentProviderResult apply(android.content.ContentProvider, android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
     method public int describeContents();
     method public android.net.Uri getUri();
+    method public boolean isAssertQuery();
+    method public boolean isDelete();
+    method public boolean isInsert();
     method public boolean isReadOperation();
+    method public boolean isUpdate();
     method public boolean isWriteOperation();
     method public boolean isYieldAllowed();
     method public static android.content.ContentProviderOperation.Builder newAssertQuery(android.net.Uri);
@@ -7145,6 +7351,8 @@
     method public abstract java.io.File getCacheDir();
     method public abstract java.lang.ClassLoader getClassLoader();
     method public abstract java.io.File getCodeCacheDir();
+    method public final int getColor(int);
+    method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
     method public abstract java.io.File getDir(java.lang.String, int);
@@ -7169,6 +7377,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
+    method public final T getSystemService(java.lang.Class<T>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
     method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7298,7 +7507,7 @@
     method public int checkPermission(java.lang.String, int, int);
     method public int checkUriPermission(android.net.Uri, int, int, int);
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
-    method public void clearWallpaper() throws java.io.IOException;
+    method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7341,20 +7550,21 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
-    method public android.graphics.drawable.Drawable getWallpaper();
-    method public int getWallpaperDesiredMinimumHeight();
-    method public int getWallpaperDesiredMinimumWidth();
+    method public deprecated android.graphics.drawable.Drawable getWallpaper();
+    method public deprecated int getWallpaperDesiredMinimumHeight();
+    method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public android.graphics.drawable.Drawable peekWallpaper();
+    method public deprecated android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public void removeStickyBroadcast(android.content.Intent);
-    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void removeStickyBroadcast(android.content.Intent);
+    method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
@@ -7363,13 +7573,13 @@
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyBroadcast(android.content.Intent);
-    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyBroadcast(android.content.Intent);
+    method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
-    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
     method public void startActivities(android.content.Intent[], android.os.Bundle);
     method public void startActivity(android.content.Intent);
@@ -7728,6 +7938,7 @@
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
+    field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
     field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -7735,6 +7946,7 @@
     field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
     field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
+    field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -9073,7 +9285,10 @@
 
   public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
-    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void applyTheme(android.content.res.Resources.Theme);
+    method public boolean canApplyTheme();
+    method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
@@ -9203,8 +9418,10 @@
     method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
     method public boolean getBoolean(int) throws android.content.res.Resources.NotFoundException;
-    method public int getColor(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+    method public deprecated int getColor(int) throws android.content.res.Resources.NotFoundException;
+    method public int getColor(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public deprecated android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ColorStateList getColorStateList(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.Configuration getConfiguration();
     method public float getDimension(int) throws android.content.res.Resources.NotFoundException;
     method public int getDimensionPixelOffset(int) throws android.content.res.Resources.NotFoundException;
@@ -10785,6 +11002,8 @@
   public class ImageFormat {
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
+    field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
@@ -11640,15 +11859,8 @@
     method public final void setTileModeY(android.graphics.Shader.TileMode);
   }
 
-  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     field public static final int HORIZONTAL = 1; // 0x1
     field public static final int VERTICAL = 2; // 0x2
   }
@@ -11688,8 +11900,12 @@
     method public android.graphics.drawable.Drawable.ConstantState getConstantState();
     method public android.graphics.drawable.Drawable getCurrent();
     method public android.graphics.Rect getDirtyBounds();
+    method public boolean getDither();
+    method public boolean getFilterBitmap();
+    method public void getHotspotBounds(android.graphics.Rect);
     method public int getIntrinsicHeight();
     method public int getIntrinsicWidth();
+    method public int getLayoutDirection();
     method public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
@@ -11707,6 +11923,7 @@
     method public void jumpToCurrentState();
     method public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
+    method public boolean onLayoutDirectionChange(int);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
@@ -11723,6 +11940,7 @@
     method public void setFilterBitmap(boolean);
     method public void setHotspot(float, float);
     method public void setHotspotBounds(int, int, int, int);
+    method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
     method public boolean setState(int[]);
     method public void setTint(int);
@@ -11787,6 +12005,19 @@
     method public final void setVariablePadding(boolean);
   }
 
+  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public DrawableWrapper(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
@@ -11834,25 +12065,28 @@
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
   }
 
-  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    method public int addLayer(android.graphics.drawable.Drawable);
     method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+    method public int findIndexByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerInsetBottom(int);
+    method public int getLayerInsetEnd(int);
+    method public int getLayerInsetLeft(int);
+    method public int getLayerInsetRight(int);
+    method public int getLayerInsetStart(int);
+    method public int getLayerInsetTop(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -11860,9 +12094,21 @@
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(int, android.graphics.drawable.Drawable);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
+    method public void setLayerHeight(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetBottom(int, int);
+    method public void setLayerInsetEnd(int, int);
+    method public void setLayerInsetLeft(int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerInsetRight(int, int);
+    method public void setLayerInsetStart(int, int);
+    method public void setLayerInsetTop(int, int);
+    method public void setLayerSize(int, int, int);
+    method public void setLayerWidth(int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -11909,44 +12155,30 @@
 
   public class RippleDrawable extends android.graphics.drawable.LayerDrawable {
     ctor public RippleDrawable(android.content.res.ColorStateList, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public int getRadius();
     method public void setColor(android.content.res.ColorStateList);
+    method public void setRadius(int);
+    field public static final int RADIUS_AUTO = -1; // 0xffffffff
   }
 
-  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public RotateDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
     method public float getFromDegrees();
-    method public int getOpacity();
     method public float getPivotX();
     method public float getPivotY();
     method public float getToDegrees();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public boolean isPivotXRelative();
     method public boolean isPivotYRelative();
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setDrawable(android.graphics.drawable.Drawable);
     method public void setFromDegrees(float);
     method public void setPivotX(float);
     method public void setPivotXRelative(boolean);
     method public void setPivotY(float);
     method public void setPivotYRelative(boolean);
     method public void setToDegrees(float);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
-  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
@@ -12558,6 +12790,8 @@
     field public static final int CAMERA_DISABLED = 1; // 0x1
     field public static final int CAMERA_DISCONNECTED = 2; // 0x2
     field public static final int CAMERA_ERROR = 3; // 0x3
+    field public static final int CAMERA_IN_USE = 4; // 0x4
+    field public static final int MAX_CAMERAS_IN_USE = 5; // 0x5
   }
 
   public abstract class CameraCaptureSession implements java.lang.AutoCloseable {
@@ -12601,11 +12835,14 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_COMPENSATION_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AWB_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
@@ -12624,6 +12861,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
@@ -12643,6 +12881,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -12653,8 +12892,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
@@ -12698,7 +12939,10 @@
     method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
     method public void openCamera(java.lang.String, android.hardware.camera2.CameraDevice.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public void registerAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback, android.os.Handler);
+    method public void registerTorchCallback(android.hardware.camera2.CameraManager.TorchCallback, android.os.Handler);
+    method public void setTorchMode(java.lang.String, boolean) throws android.hardware.camera2.CameraAccessException;
     method public void unregisterAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback);
+    method public void unregisterTorchCallback(android.hardware.camera2.CameraManager.TorchCallback);
   }
 
   public static abstract class CameraManager.AvailabilityCallback {
@@ -12707,6 +12951,12 @@
     method public void onCameraUnavailable(java.lang.String);
   }
 
+  public static abstract class CameraManager.TorchCallback {
+    ctor public CameraManager.TorchCallback();
+    method public void onTorchModeChanged(java.lang.String, boolean);
+    method public void onTorchModeUnavailable(java.lang.String);
+  }
+
   public abstract class CameraMetadata {
     method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
@@ -12724,6 +12974,7 @@
     field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2; // 0x2
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
     field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
@@ -12820,6 +13071,7 @@
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
     field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_EXTERNAL = 2; // 0x2
     field public static final int LENS_FACING_FRONT = 0; // 0x0
     field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1; // 0x1
     field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2; // 0x2
@@ -12830,13 +13082,16 @@
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int NOISE_REDUCTION_MODE_MINIMAL = 3; // 0x3
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
@@ -12886,7 +13141,11 @@
     field public static final int SYNC_MAX_LATENCY_UNKNOWN = -1; // 0xffffffff
     field public static final int TONEMAP_MODE_CONTRAST_CURVE = 0; // 0x0
     field public static final int TONEMAP_MODE_FAST = 1; // 0x1
+    field public static final int TONEMAP_MODE_GAMMA_VALUE = 3; // 0x3
     field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int TONEMAP_MODE_PRESET_CURVE = 4; // 0x4
+    field public static final int TONEMAP_PRESET_CURVE_REC709 = 1; // 0x1
+    field public static final int TONEMAP_PRESET_CURVE_SRGB = 0; // 0x0
   }
 
   public class CaptureFailure {
@@ -12942,6 +13201,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_FRAME_DURATION;
@@ -12953,7 +13213,9 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureRequest.Builder {
@@ -13019,6 +13281,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
@@ -13040,7 +13303,9 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureResult.Key {
@@ -13929,7 +14194,8 @@
 
   public class AsyncPlayer {
     ctor public AsyncPlayer(java.lang.String);
-    method public void play(android.content.Context, android.net.Uri, boolean, int);
+    method public deprecated void play(android.content.Context, android.net.Uri, boolean, int);
+    method public void play(android.content.Context, android.net.Uri, boolean, android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void stop();
   }
 
@@ -14057,6 +14323,7 @@
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
     method public boolean isSpeakerphoneOn();
+    method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
     method public deprecated boolean isWiredHeadsetOn();
     method public void loadSoundEffects();
@@ -14075,8 +14342,8 @@
     method public void setRingerMode(int);
     method public deprecated void setRouting(int, int, int);
     method public void setSpeakerphoneOn(boolean);
-    method public void setStreamMute(int, boolean);
-    method public void setStreamSolo(int, boolean);
+    method public deprecated void setStreamMute(int, boolean);
+    method public deprecated void setStreamSolo(int, boolean);
     method public void setStreamVolume(int, int, int);
     method public deprecated void setVibrateSetting(int, int);
     method public deprecated void setWiredHeadsetOn(boolean);
@@ -14094,8 +14361,11 @@
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
+    field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
     field public static final int ADJUST_SAME = 0; // 0x0
+    field public static final int ADJUST_TOGGLE_MUTE = 101; // 0x65
+    field public static final int ADJUST_UNMUTE = 100; // 0x64
     field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
     field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
@@ -14608,6 +14878,7 @@
     field public static final int COLOR_Format24bitBGR888 = 12; // 0xc
     field public static final int COLOR_Format24bitRGB888 = 11; // 0xb
     field public static final int COLOR_Format25bitARGB1888 = 14; // 0xe
+    field public static final int COLOR_Format32BitRGBA8888 = 2130747392; // 0x7f00a000
     field public static final int COLOR_Format32bitARGB8888 = 16; // 0x10
     field public static final int COLOR_Format32bitBGRA8888 = 15; // 0xf
     field public static final int COLOR_Format8bitRGB332 = 2; // 0x2
@@ -14857,6 +15128,7 @@
     field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
     field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
     field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
     field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
@@ -15184,6 +15456,7 @@
     method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
     method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
     method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
+    method public void setPlaybackRate(float, int);
     method public void setScreenOnWhilePlaying(boolean);
     method public void setSurface(android.view.Surface);
     method public void setVideoScalingMode(int);
@@ -15209,6 +15482,7 @@
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -16144,6 +16418,7 @@
     method public void connect();
     method public void disconnect();
     method public android.os.Bundle getExtras();
+    method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
     method public java.lang.String getRoot();
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
@@ -16173,6 +16448,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
+  public static abstract class MediaBrowser.MediaItemCallback {
+    ctor public MediaBrowser.MediaItemCallback();
+    method public void onError();
+    method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -16236,6 +16517,85 @@
 
 }
 
+package android.media.midi {
+
+  public final class MidiDeviceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method public int getInputPortCount();
+    method public android.media.midi.MidiDeviceInfo.PortInfo getInputPortInfo(int);
+    method public int getOutputPortCount();
+    method public android.media.midi.MidiDeviceInfo.PortInfo getOutputPortInfo(int);
+    method public android.os.Bundle getProperties();
+    method public int getType();
+    method public boolean isPrivate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.midi.MidiDeviceInfo> CREATOR;
+    field public static final java.lang.String PROPERTY_MANUFACTURER = "manufacturer";
+    field public static final java.lang.String PROPERTY_NAME = "name";
+    field public static final java.lang.String PROPERTY_PRODUCT = "product";
+    field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
+    field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final int TYPE_USB = 1; // 0x1
+    field public static final int TYPE_VIRTUAL = 2; // 0x2
+  }
+
+  public static final class MidiDeviceInfo.PortInfo {
+    method public java.lang.String getName();
+    method public int getPortNumber();
+    method public int getType();
+    field public static final int TYPE_INPUT = 1; // 0x1
+    field public static final int TYPE_OUTPUT = 2; // 0x2
+  }
+
+  public abstract class MidiDeviceService extends android.app.Service {
+    ctor public MidiDeviceService();
+    method public final android.media.midi.MidiDeviceInfo getDeviceInfo();
+    method public final android.media.midi.MidiReceiver[] getOutputPortReceivers();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
+    method public abstract android.media.midi.MidiReceiver[] onGetInputPortReceivers();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
+  }
+
+  public final class MidiDeviceStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.media.midi.MidiDeviceInfo getDeviceInfo();
+    method public int getOutputPortOpenCount(int);
+    method public boolean isInputPortOpen(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.midi.MidiDeviceStatus> CREATOR;
+  }
+
+  public final class MidiInputPort extends android.media.midi.MidiReceiver implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public final int getPortNumber();
+    method public void onReceive(byte[], int, int, long) throws java.io.IOException;
+  }
+
+  public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public void connect(android.media.midi.MidiReceiver);
+    method public void disconnect(android.media.midi.MidiReceiver);
+    method public final int getPortNumber();
+  }
+
+  public abstract class MidiReceiver {
+    ctor public MidiReceiver();
+    method public int getMaxMessageSize();
+    method public abstract void onReceive(byte[], int, int, long) throws java.io.IOException;
+    method public void send(byte[], int, int) throws java.io.IOException;
+    method public void sendWithTimestamp(byte[], int, int, long) throws java.io.IOException;
+  }
+
+  public abstract class MidiSender {
+    ctor public MidiSender();
+    method public abstract void connect(android.media.midi.MidiReceiver);
+    method public abstract void disconnect(android.media.midi.MidiReceiver);
+  }
+
+}
+
 package android.media.projection {
 
   public final class MediaProjection {
@@ -16257,11 +16617,248 @@
 
 }
 
+package android.media.routing {
+
+  public final class MediaRouteSelector implements android.os.Parcelable {
+    method public boolean containsProtocol(java.lang.Class<?>);
+    method public boolean containsProtocol(java.lang.String);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public int getOptionalFeatures();
+    method public java.util.List<java.lang.String> getOptionalProtocols();
+    method public int getRequiredFeatures();
+    method public java.util.List<java.lang.String> getRequiredProtocols();
+    method public java.lang.String getServicePackageName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.routing.MediaRouteSelector> CREATOR;
+  }
+
+  public static final class MediaRouteSelector.Builder {
+    ctor public MediaRouteSelector.Builder();
+    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.Class<?>);
+    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.String);
+    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.Class<?>);
+    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.String);
+    method public android.media.routing.MediaRouteSelector build();
+    method public android.media.routing.MediaRouteSelector.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouteSelector.Builder setOptionalFeatures(int);
+    method public android.media.routing.MediaRouteSelector.Builder setRequiredFeatures(int);
+    method public android.media.routing.MediaRouteSelector.Builder setServicePackageName(java.lang.String);
+  }
+
+  public abstract class MediaRouteService extends android.app.Service {
+    ctor public MediaRouteService();
+    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.media.routing.MediaRouteService.ClientSession onCreateClientSession(android.media.routing.MediaRouteService.ClientInfo);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.routing.MediaRouteService";
+  }
+
+  public static final class MediaRouteService.ClientInfo {
+    method public java.lang.String getPackageName();
+    method public int getUid();
+  }
+
+  public static abstract class MediaRouteService.ClientSession {
+    ctor public MediaRouteService.ClientSession();
+    method public abstract boolean onConnect(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouteService.ConnectionCallback);
+    method public abstract void onDisconnect();
+    method public void onPauseStream();
+    method public void onRelease();
+    method public void onResumeStream();
+    method public abstract boolean onStartDiscovery(android.media.routing.MediaRouter.DiscoveryRequest, android.media.routing.MediaRouteService.DiscoveryCallback);
+    method public abstract void onStopDiscovery();
+  }
+
+  public final class MediaRouteService.ConnectionCallback {
+    method public void onConnected(android.media.routing.MediaRouter.ConnectionInfo);
+    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onDisconnected();
+  }
+
+  public final class MediaRouteService.DiscoveryCallback {
+    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
+    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
+  }
+
+  public final class MediaRouter {
+    ctor public MediaRouter(android.content.Context);
+    method public void addSelector(android.media.routing.MediaRouteSelector);
+    method public void clearSelectors();
+    method public android.media.routing.MediaRouter.Delegate createDelegate();
+    method public android.media.routing.MediaRouter.ConnectionInfo getConnection();
+    method public int getConnectionState();
+    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
+    method public java.util.List<android.media.routing.MediaRouter.RouteInfo> getDiscoveredRoutes(android.media.routing.MediaRouter.DestinationInfo);
+    method public int getDiscoveryState();
+    method public android.media.AudioAttributes getPreferredAudioAttributes();
+    method public android.view.Display getPreferredPresentationDisplay();
+    method public android.media.VolumeProvider getPreferredVolumeProvider();
+    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
+    method public android.media.routing.MediaRouter.RouteInfo getSelectedRoute();
+    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
+    method public boolean isReleased();
+    method public void pauseStream();
+    method public void release();
+    method public void removeSelector(android.media.routing.MediaRouteSelector);
+    method public void resumeStream();
+    method public void setRoutingCallback(android.media.routing.MediaRouter.RoutingCallback, android.os.Handler);
+    field public static final int CONNECTION_ERROR_ABORTED = 1; // 0x1
+    field public static final int CONNECTION_ERROR_BARGED = 7; // 0x7
+    field public static final int CONNECTION_ERROR_BROKEN = 6; // 0x6
+    field public static final int CONNECTION_ERROR_BUSY = 4; // 0x4
+    field public static final int CONNECTION_ERROR_TIMEOUT = 5; // 0x5
+    field public static final int CONNECTION_ERROR_UNAUTHORIZED = 2; // 0x2
+    field public static final int CONNECTION_ERROR_UNKNOWN = 0; // 0x0
+    field public static final int CONNECTION_ERROR_UNREACHABLE = 3; // 0x3
+    field public static final int CONNECTION_FLAG_BARGE = 1; // 0x1
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DISCONNECTION_REASON_APPLICATION_REQUEST = 0; // 0x0
+    field public static final int DISCONNECTION_REASON_ERROR = 2; // 0x2
+    field public static final int DISCONNECTION_REASON_USER_REQUEST = 1; // 0x1
+    field public static final int DISCOVERY_ERROR_ABORTED = 1; // 0x1
+    field public static final int DISCOVERY_ERROR_NO_CONNECTIVITY = 2; // 0x2
+    field public static final int DISCOVERY_ERROR_UNKNOWN = 0; // 0x0
+    field public static final int DISCOVERY_FLAG_BACKGROUND = 1; // 0x1
+    field public static final int DISCOVERY_STATE_STARTED = 1; // 0x1
+    field public static final int DISCOVERY_STATE_STOPPED = 0; // 0x0
+    field public static final int ROUTE_FEATURE_LIVE_AUDIO = 1; // 0x1
+    field public static final int ROUTE_FEATURE_LIVE_VIDEO = 2; // 0x2
+  }
+
+  public static final class MediaRouter.ConnectionInfo {
+    method public android.media.AudioAttributes getAudioAttributes();
+    method public android.os.Bundle getExtras();
+    method public int getFeatures();
+    method public android.view.Display getPresentationDisplay();
+    method public android.os.IBinder getProtocolBinder(java.lang.String);
+    method public android.os.IBinder getProtocolBinder(int);
+    method public T getProtocolObject(java.lang.Class<T>);
+    method public java.util.List<java.lang.String> getProtocols();
+    method public android.media.routing.MediaRouter.RouteInfo getRoute();
+    method public android.media.VolumeProvider getVolumeProvider();
+  }
+
+  public static final class MediaRouter.ConnectionInfo.Builder {
+    ctor public MediaRouter.ConnectionInfo.Builder(android.media.routing.MediaRouter.RouteInfo);
+    method public android.media.routing.MediaRouter.ConnectionInfo build();
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setAudioAttributes(android.media.AudioAttributes);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setPresentationDisplay(android.view.Display);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolBinder(java.lang.String, android.os.IBinder);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolStub(java.lang.Class<?>, android.os.IInterface);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setVolumeProvider(android.media.VolumeProvider);
+  }
+
+  public static final class MediaRouter.ConnectionRequest {
+    method public android.os.Bundle getExtras();
+    method public int getFlags();
+    method public android.media.routing.MediaRouter.RouteInfo getRoute();
+    method public void setExtras(android.os.Bundle);
+    method public void setFlags(int);
+    method public void setRoute(android.media.routing.MediaRouter.RouteInfo);
+  }
+
+  public static final class MediaRouter.Delegate {
+    ctor public MediaRouter.Delegate();
+    method public void addStateCallback(android.media.routing.MediaRouter.StateCallback, android.os.Handler);
+    method public void connect(android.media.routing.MediaRouter.DestinationInfo, int);
+    method public void disconnect(int);
+    method public int getConnectionState();
+    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
+    method public int getDiscoveryState();
+    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
+    method public boolean isReleased();
+    method public void removeStateCallback(android.media.routing.MediaRouter.StateCallback);
+    method public void startDiscovery(int);
+    method public void stopDiscovery();
+  }
+
+  public static final class MediaRouter.DestinationInfo {
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public int getIconResourceId();
+    method public java.lang.String getId();
+    method public java.lang.CharSequence getName();
+    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
+  }
+
+  public static final class MediaRouter.DestinationInfo.Builder {
+    ctor public MediaRouter.DestinationInfo.Builder(java.lang.String, android.media.routing.MediaRouter.ServiceMetadata, java.lang.CharSequence);
+    method public android.media.routing.MediaRouter.DestinationInfo build();
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setDescription(java.lang.CharSequence);
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setIconResourceId(int);
+  }
+
+  public static final class MediaRouter.DiscoveryRequest {
+    method public int getFlags();
+    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
+    method public void setFlags(int);
+    method public void setSelectors(java.util.List<android.media.routing.MediaRouteSelector>);
+  }
+
+  public static final class MediaRouter.RouteInfo {
+    method public android.media.routing.MediaRouter.DestinationInfo getDestination();
+    method public android.os.Bundle getExtras();
+    method public int getFeatures();
+    method public java.lang.String getId();
+    method public java.util.List<java.lang.String> getProtocols();
+    method public android.media.routing.MediaRouteSelector getSelector();
+  }
+
+  public static final class MediaRouter.RouteInfo.Builder {
+    ctor public MediaRouter.RouteInfo.Builder(java.lang.String, android.media.routing.MediaRouter.DestinationInfo, android.media.routing.MediaRouteSelector);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.Class<T>);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.String);
+    method public android.media.routing.MediaRouter.RouteInfo build();
+    method public android.media.routing.MediaRouter.RouteInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder setFeatures(int);
+  }
+
+  public static abstract class MediaRouter.RoutingCallback extends android.media.routing.MediaRouter.StateCallback {
+    ctor public MediaRouter.RoutingCallback();
+    method public boolean onPrepareConnectionRequest(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
+    method public boolean onPrepareDiscoveryRequest(android.media.routing.MediaRouter.DiscoveryRequest, java.util.List<android.media.routing.MediaRouteSelector>);
+  }
+
+  public static final class MediaRouter.ServiceMetadata {
+    method public android.content.ComponentName getComponentName();
+    method public android.graphics.drawable.Drawable getIcon(android.content.pm.PackageManager);
+    method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
+    method public java.lang.String getPackageName();
+    method public android.content.pm.ServiceInfo getService();
+  }
+
+  public static abstract class MediaRouter.StateCallback {
+    ctor public MediaRouter.StateCallback();
+    method public void onConnected();
+    method public void onConnecting();
+    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onConnectionStateChanged(int);
+    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDisconnected();
+    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onDiscoveryStarted();
+    method public void onDiscoveryStateChanged(int);
+    method public void onDiscoveryStopped();
+    method public void onReleased();
+    method public void onSelectedDestinationChanged(android.media.routing.MediaRouter.DestinationInfo);
+  }
+
+}
+
 package android.media.session {
 
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
+    method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
     method public long getFlags();
@@ -16334,6 +16931,7 @@
     method public void setExtras(android.os.Bundle);
     method public void setFlags(int);
     method public void setMediaButtonReceiver(android.app.PendingIntent);
+    method public void setMediaRouter(android.media.routing.MediaRouter);
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
@@ -17260,7 +17858,6 @@
     method public static javax.net.SocketFactory getDefault(int);
     method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
     method public java.lang.String[] getDefaultCipherSuites();
-    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
@@ -17480,30 +18077,6 @@
 
 package android.net.http {
 
-  public final deprecated class AndroidHttpClient implements org.apache.http.client.HttpClient {
-    method public void close();
-    method public void disableCurlLogging();
-    method public void enableCurlLogging(java.lang.String, int);
-    method public org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public static org.apache.http.entity.AbstractHttpEntity getCompressedEntity(byte[], android.content.ContentResolver) throws java.io.IOException;
-    method public org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public static long getMinGzipSize(android.content.ContentResolver);
-    method public org.apache.http.params.HttpParams getParams();
-    method public static java.io.InputStream getUngzippedContent(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static void modifyRequestToAcceptGzipResponse(org.apache.http.HttpRequest);
-    method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String, android.content.Context);
-    method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String);
-    method public static long parseDate(java.lang.String);
-    field public static long DEFAULT_SYNC_MIN_GZIP_BYTES;
-  }
-
   public final class HttpResponseCache extends java.net.ResponseCache implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void delete() throws java.io.IOException;
@@ -17513,7 +18086,7 @@
     method public static android.net.http.HttpResponseCache getInstalled();
     method public int getNetworkCount();
     method public int getRequestCount();
-    method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
+    method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
     method public long maxSize();
     method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
     method public long size();
@@ -21369,7 +21942,6 @@
   }
 
   public class BatteryManager {
-    ctor public BatteryManager();
     method public int getIntProperty(int);
     method public long getLongProperty(int);
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -21490,6 +22062,7 @@
     field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int LOLLIPOP = 21; // 0x15
     field public static final int LOLLIPOP_MR1 = 22; // 0x16
+    field public static final int MNC = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -21602,47 +22175,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -21661,10 +22234,10 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
-  public static class Debug.InstructionCount {
+  public static deprecated class Debug.InstructionCount {
     ctor public Debug.InstructionCount();
     method public boolean collect();
     method public int globalMethodInvocations();
@@ -21865,7 +22438,9 @@
   public final class Looper {
     method public void dump(android.util.Printer, java.lang.String);
     method public static android.os.Looper getMainLooper();
+    method public android.os.MessageQueue getQueue();
     method public java.lang.Thread getThread();
+    method public boolean isCurrentThread();
     method public static void loop();
     method public static android.os.Looper myLooper();
     method public static android.os.MessageQueue myQueue();
@@ -21923,7 +22498,18 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public boolean isIdle();
+    method public void registerFileDescriptorCallback(java.io.FileDescriptor, int, android.os.MessageQueue.FileDescriptorCallback);
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public void unregisterFileDescriptorCallback(java.io.FileDescriptor);
+  }
+
+  public static abstract class MessageQueue.FileDescriptorCallback {
+    ctor public MessageQueue.FileDescriptorCallback();
+    method public int onFileDescriptorEvents(java.io.FileDescriptor, int);
+    field public static final int EVENT_ERROR = 4; // 0x4
+    field public static final int EVENT_INPUT = 1; // 0x1
+    field public static final int EVENT_OUTPUT = 2; // 0x2
   }
 
   public static abstract interface MessageQueue.IdleHandler {
@@ -22313,6 +22899,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskReads();
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
+    method public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeathOnNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
@@ -22324,6 +22911,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskReads();
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
+    method public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
   }
 
   public static final class StrictMode.VmPolicy {
@@ -22336,11 +22924,13 @@
     method public android.os.StrictMode.VmPolicy build();
     method public android.os.StrictMode.VmPolicy.Builder detectActivityLeaks();
     method public android.os.StrictMode.VmPolicy.Builder detectAll();
+    method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
+    method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -22874,6 +23464,7 @@
   public final class PrintAttributes implements android.os.Parcelable {
     method public int describeContents();
     method public int getColorMode();
+    method public int getDuplexMode();
     method public android.print.PrintAttributes.MediaSize getMediaSize();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public android.print.PrintAttributes.Resolution getResolution();
@@ -22881,12 +23472,16 @@
     field public static final int COLOR_MODE_COLOR = 2; // 0x2
     field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR;
+    field public static final int DUPLEX_MODE_LONG_EDGE = 2; // 0x2
+    field public static final int DUPLEX_MODE_NONE = 1; // 0x1
+    field public static final int DUPLEX_MODE_SHORT_EDGE = 4; // 0x4
   }
 
   public static final class PrintAttributes.Builder {
     ctor public PrintAttributes.Builder();
     method public android.print.PrintAttributes build();
     method public android.print.PrintAttributes.Builder setColorMode(int);
+    method public android.print.PrintAttributes.Builder setDuplexMode(int);
     method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
     method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
     method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
@@ -23104,6 +23699,7 @@
     method public int describeContents();
     method public int getColorModes();
     method public android.print.PrintAttributes getDefaults();
+    method public int getDuplexModes();
     method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
@@ -23117,6 +23713,7 @@
     method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
     method public android.print.PrinterCapabilitiesInfo build();
     method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
     method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
   }
 
@@ -23606,6 +24203,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -23963,6 +24561,13 @@
     field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1
   }
 
+  public static final class ContactsContract.Authorization {
+    ctor public ContactsContract.Authorization();
+    field public static final java.lang.String AUTHORIZATION_METHOD = "authorize";
+    field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri";
+    field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
+  }
+
   protected static abstract interface ContactsContract.BaseSyncColumns {
     field public static final java.lang.String SYNC1 = "sync1";
     field public static final java.lang.String SYNC2 = "sync2";
@@ -24306,12 +24911,21 @@
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final java.lang.String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
     field public static final java.lang.String CONTENT_DIRECTORY = "suggestions";
   }
 
+  public static final class ContactsContract.Contacts.AggregationSuggestions.Builder {
+    ctor public ContactsContract.Contacts.AggregationSuggestions.Builder();
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder addNameParameter(java.lang.String);
+    method public android.net.Uri build();
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setContactId(long);
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setLimit(int);
+  }
+
   public static final class ContactsContract.Contacts.Data implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
     field public static final java.lang.String CONTENT_DIRECTORY = "data";
   }
@@ -24449,6 +25063,7 @@
     field public static final int ORGANIZATION = 30; // 0x1e
     field public static final int PHONE = 20; // 0x14
     field public static final int STRUCTURED_NAME = 40; // 0x28
+    field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
     field public static final int UNDEFINED = 0; // 0x0
   }
 
@@ -24514,6 +25129,8 @@
     field public static final java.lang.String EMAIL = "email";
     field public static final java.lang.String EMAIL_ISPRIMARY = "email_isprimary";
     field public static final java.lang.String EMAIL_TYPE = "email_type";
+    field public static final java.lang.String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
+    field public static final java.lang.String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
     field public static final java.lang.String FULL_MODE = "full_mode";
     field public static final java.lang.String IM_HANDLE = "im_handle";
     field public static final java.lang.String IM_ISPRIMARY = "im_isprimary";
@@ -24594,12 +25211,26 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
+  public static final class ContactsContract.ProviderStatus {
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String STATUS = "status";
+    field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3
+    field public static final int STATUS_NORMAL = 0; // 0x0
+    field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4
+    field public static final int STATUS_UPGRADING = 1; // 0x1
+  }
+
   public static final class ContactsContract.QuickContact {
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, java.lang.String[], java.lang.String);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, java.lang.String[], java.lang.String);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
+    field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
+    field public static final java.lang.String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -25251,12 +25882,14 @@
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
     field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
     field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
     field public static final java.lang.String AUTHORITY = "settings";
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
+    field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
   }
@@ -25366,7 +25999,7 @@
     field public static final int LOCATION_MODE_OFF = 0; // 0x0
     field public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
     field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-    field public static final java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
+    field public static final deprecated java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
     field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
     field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
     field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
@@ -25439,7 +26072,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -25502,14 +26134,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -25828,6 +26452,8 @@
   }
 
   public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
+    method public static long getOrCreateThreadId(android.content.Context, java.lang.String);
+    method public static long getOrCreateThreadId(android.content.Context, java.util.Set<java.lang.String>);
     field public static final int BROADCAST_THREAD = 1; // 0x1
     field public static final int COMMON_THREAD = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
@@ -26875,6 +27501,7 @@
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
+    method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String, java.lang.String);
     method public static android.content.Intent createInstallIntent();
     method public static java.security.cert.X509Certificate[] getCertificateChain(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method public static java.security.PrivateKey getPrivateKey(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
@@ -26988,6 +27615,30 @@
 
 }
 
+package android.service.chooser {
+
+  public final class ChooserTarget implements android.os.Parcelable {
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public android.content.IntentSender getIntentSender();
+    method public float getScore();
+    method public java.lang.CharSequence getTitle();
+    method public boolean sendIntent(android.content.Context, android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
+  }
+
+  public abstract class ChooserTargetService extends android.app.Service {
+    ctor public ChooserTargetService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
@@ -27025,6 +27676,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void setContentView(int);
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
@@ -27043,6 +27695,7 @@
   public abstract class MediaBrowserService extends android.app.Service {
     ctor public MediaBrowserService();
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
     method public android.os.IBinder onBind(android.content.Intent);
@@ -27093,6 +27746,7 @@
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
+    field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
   }
 
@@ -27207,23 +27861,67 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onReady();
     method public void onShutdown();
-    method public void startSession(android.os.Bundle);
+    method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final int START_WITH_ASSIST = 1; // 0x1
   }
 
   public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void finish();
+    method public android.view.LayoutInflater getLayoutInflater();
+    method public android.app.Dialog getWindow();
+    method public void hide();
+    method public void hideWindow();
+    method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
+    method public void onBackPressed();
+    method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
     method public void onCloseSystemDialogs();
-    method public void onCreate(android.os.Bundle);
+    method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
+    method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
+    method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
+    method public void onCreate(android.os.Bundle, int);
+    method public android.view.View onCreateContentView();
     method public void onDestroy();
+    method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+    method public void onHandleAssist(android.os.Bundle);
+    method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onShow(android.os.Bundle, int);
+    method public void onTaskFinished(android.content.Intent, int);
+    method public void onTaskStarted(android.content.Intent, int);
     method public void setContentView(android.view.View);
+    method public void setTheme(int);
+    method public void show();
+    method public void showWindow();
+    method public void startVoiceActivity(android.content.Intent);
+  }
+
+  public static class VoiceInteractionSession.Caller {
+  }
+
+  public static final class VoiceInteractionSession.Insets {
+    ctor public VoiceInteractionSession.Insets();
+    field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
+    field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
+    field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
+    field public final android.graphics.Rect contentInsets;
+    field public int touchableInsets;
+    field public final android.graphics.Region touchableRegion;
+  }
+
+  public static class VoiceInteractionSession.Request {
+    method public void sendAbortVoiceResult(android.os.Bundle);
+    method public void sendCancelResult();
+    method public void sendCommandResult(boolean, android.os.Bundle);
+    method public void sendCompleteVoiceResult(android.os.Bundle);
+    method public void sendConfirmResult(boolean, android.os.Bundle);
   }
 
   public abstract class VoiceInteractionSessionService extends android.app.Service {
@@ -27533,6 +28231,7 @@
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
     method public abstract void onStart(java.lang.String);
+    method public void onStop(java.lang.String, boolean);
   }
 
   public class Voice implements android.os.Parcelable {
@@ -28018,6 +28717,15 @@
     field public static final int STDERR_FILENO;
     field public static final int STDIN_FILENO;
     field public static final int STDOUT_FILENO;
+    field public static final int ST_MANDLOCK;
+    field public static final int ST_NOATIME;
+    field public static final int ST_NODEV;
+    field public static final int ST_NODIRATIME;
+    field public static final int ST_NOEXEC;
+    field public static final int ST_NOSUID;
+    field public static final int ST_RDONLY;
+    field public static final int ST_RELATIME;
+    field public static final int ST_SYNCHRONOUS;
     field public static final int S_IFBLK;
     field public static final int S_IFCHR;
     field public static final int S_IFDIR;
@@ -28273,7 +28981,9 @@
     method public boolean handleMmi(java.lang.String);
     method public boolean isInCall();
     method public void showInCallScreen(boolean);
+    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
@@ -28555,6 +29265,7 @@
     method public static java.lang.String formatNumber(java.lang.String, java.lang.String);
     method public static java.lang.String formatNumber(java.lang.String, java.lang.String, java.lang.String);
     method public static java.lang.String formatNumberToE164(java.lang.String, java.lang.String);
+    method public static java.lang.String formatNumberToRFC3966(java.lang.String, java.lang.String);
     method public static deprecated int getFormatTypeForLocale(java.util.Locale);
     method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
     method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
@@ -28815,6 +29526,7 @@
   }
 
   public class TelephonyManager {
+    method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
     method public android.telephony.CellLocation getCellLocation();
@@ -28850,6 +29562,7 @@
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
@@ -29396,6 +30109,7 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
@@ -31264,6 +31978,13 @@
     method public void captureStartValues(android.transition.TransitionValues);
   }
 
+  public class ChangeScroll extends android.transition.Transition {
+    ctor public ChangeScroll();
+    ctor public ChangeScroll(android.content.Context, android.util.AttributeSet);
+    method public void captureEndValues(android.transition.TransitionValues);
+    method public void captureStartValues(android.transition.TransitionValues);
+  }
+
   public class ChangeTransform extends android.transition.Transition {
     ctor public ChangeTransform();
     ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
@@ -31344,6 +32065,7 @@
     method public android.transition.Transition addTarget(java.lang.String);
     method public android.transition.Transition addTarget(java.lang.Class);
     method public android.transition.Transition addTarget(android.view.View);
+    method protected boolean areValuesChanged(android.transition.TransitionValues, android.transition.TransitionValues);
     method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
     method public abstract void captureStartValues(android.transition.TransitionValues);
@@ -32168,6 +32890,7 @@
     method public java.lang.Object getTag();
     method public abstract java.lang.CharSequence getTitle();
     method public boolean getTitleOptionalHint();
+    method public int getType();
     method public abstract void invalidate();
     method public boolean isTitleOptional();
     method public abstract void setCustomView(android.view.View);
@@ -32177,6 +32900,9 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
+    method public void setType(int);
+    field public static final int TYPE_FLOATING = 1; // 0x1
+    field public static final int TYPE_PRIMARY = 0; // 0x0
   }
 
   public static abstract interface ActionMode.Callback {
@@ -32234,6 +32960,7 @@
   public class ContextThemeWrapper extends android.content.ContextWrapper {
     ctor public ContextThemeWrapper();
     ctor public ContextThemeWrapper(android.content.Context, int);
+    ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme);
     method public void applyOverrideConfiguration(android.content.res.Configuration);
     method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
   }
@@ -33020,6 +33747,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -33323,6 +34052,7 @@
     method public int describeContents();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
+    method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
     method public deprecated void unlockCanvas(android.graphics.Canvas);
@@ -33525,6 +34255,7 @@
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
+    method public java.lang.CharSequence getAccessibilityClassName();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public int getAccessibilityTraversalAfter();
@@ -33533,6 +34264,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.graphics.drawable.Drawable getBackground();
+    method public int getBackgroundColor();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method public int getBaseline();
@@ -33612,6 +34344,7 @@
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
     method public android.view.View getRootView();
+    method public android.view.WindowInsets getRootWindowInsets();
     method public float getRotation();
     method public float getRotationX();
     method public float getRotationY();
@@ -33749,6 +34482,7 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -33866,6 +34600,7 @@
     method public void setOnHoverListener(android.view.View.OnHoverListener);
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(android.view.View.OnLongClickListener);
+    method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
     method public void setOutlineProvider(android.view.ViewOutlineProvider);
@@ -33916,6 +34651,7 @@
     method public void setZ(float);
     method public boolean showContextMenu();
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startAnimation(android.view.animation.Animation);
     method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
     method public boolean startNestedScroll(int);
@@ -34023,6 +34759,7 @@
     field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
     field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
     field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
+    field public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
@@ -34133,6 +34870,10 @@
     method public abstract boolean onLongClick(android.view.View);
   }
 
+  public static abstract interface View.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.view.View, int, int, int, int);
+  }
+
   public static abstract interface View.OnSystemUiVisibilityChangeListener {
     method public abstract void onSystemUiVisibilityChange(int);
   }
@@ -34145,6 +34886,18 @@
     method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
   }
 
+  public abstract class ViewAssistStructure {
+    ctor public ViewAssistStructure();
+    method public abstract java.lang.CharSequence getHint();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract int getTextSelectionEnd();
+    method public abstract int getTextSelectionStart();
+    method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence, int, int);
+    method public abstract void setTextPaint(android.text.TextPaint);
+  }
+
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
@@ -34355,6 +35108,7 @@
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
     method public void startLayoutAnimation();
     method public void startViewTransition(android.view.View);
     method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
@@ -34475,6 +35229,7 @@
     method public abstract void requestTransparentRegion(android.view.View);
     method public abstract boolean showContextMenuForChild(android.view.View);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
+    method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
   }
 
   public class ViewPropertyAnimator {
@@ -34763,6 +35518,7 @@
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public abstract void onWindowFocusChanged(boolean);
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
@@ -36372,6 +37128,32 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public class WebMessage {
+    ctor public WebMessage(java.lang.String);
+    ctor public WebMessage(java.lang.String, android.webkit.WebMessagePort[]);
+    method public java.lang.String getData();
+    method public android.webkit.WebMessagePort[] getPorts();
+  }
+
+  public abstract class WebMessagePort {
+    ctor public WebMessagePort();
+    method public abstract void close();
+    method public abstract void postMessage(android.webkit.WebMessage);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback, android.os.Handler);
+  }
+
+  public static abstract class WebMessagePort.WebMessageCallback {
+    ctor public WebMessagePort.WebMessageCallback();
+    method public void onMessage(android.webkit.WebMessagePort, android.webkit.WebMessage);
+  }
+
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -36380,7 +37162,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -36396,6 +37178,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -36429,6 +37221,7 @@
     method public abstract int getMinimumFontSize();
     method public abstract int getMinimumLogicalFontSize();
     method public abstract int getMixedContentMode();
+    method public abstract boolean getOffscreenPreRaster();
     method public abstract deprecated android.webkit.WebSettings.PluginState getPluginState();
     method public abstract java.lang.String getSansSerifFontFamily();
     method public abstract boolean getSaveFormData();
@@ -36475,6 +37268,7 @@
     method public abstract void setMinimumLogicalFontSize(int);
     method public abstract void setMixedContentMode(int);
     method public abstract void setNeedInitialFocus(boolean);
+    method public abstract void setOffscreenPreRaster(boolean);
     method public abstract deprecated void setPluginState(android.webkit.WebSettings.PluginState);
     method public abstract deprecated void setRenderPriority(android.webkit.WebSettings.RenderPriority);
     method public abstract void setSansSerifFontFamily(java.lang.String);
@@ -36599,6 +37393,7 @@
     method public android.webkit.WebBackForwardList copyBackForwardList();
     method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
     method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public void documentHasImages(android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
@@ -36639,6 +37434,7 @@
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
+    method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public void postUrl(java.lang.String, byte[]);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
@@ -36710,8 +37506,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -36724,6 +37522,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
+    field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
@@ -36938,6 +37737,8 @@
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public boolean showOverflowMenu();
   }
@@ -37091,7 +37892,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -37105,6 +37906,7 @@
     method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
     method public android.content.Context getContext();
     method public int getCount();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public T getItem(int);
     method public long getItemId(int);
@@ -37113,6 +37915,7 @@
     method public void insert(T, int);
     method public void remove(T);
     method public void setDropDownViewResource(int);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setNotifyOnChange(boolean);
     method public void sort(java.util.Comparator<? super T>);
   }
@@ -37313,6 +38116,7 @@
     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.graphics.drawable.Drawable getButtonDrawable();
     method public android.content.res.ColorStateList getButtonTintList();
     method public android.graphics.PorterDuff.Mode getButtonTintMode();
     method public boolean isChecked();
@@ -37329,7 +38133,7 @@
     method public abstract void onCheckedChanged(android.widget.CompoundButton, boolean);
   }
 
-  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
@@ -37338,6 +38142,7 @@
     method public java.lang.CharSequence convertToString(android.database.Cursor);
     method public int getCount();
     method public android.database.Cursor getCursor();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public android.widget.FilterQueryProvider getFilterQueryProvider();
     method public java.lang.Object getItem(int);
@@ -37348,6 +38153,7 @@
     method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
     method protected void onContentChanged();
     method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
     method public android.database.Cursor swapCursor(android.database.Cursor);
     field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
@@ -38114,9 +38920,11 @@
     ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
     method public void dismiss();
     method public android.view.View.OnTouchListener getDragToOpenListener();
+    method public int getGravity();
     method public android.view.Menu getMenu();
     method public android.view.MenuInflater getMenuInflater();
     method public void inflate(int);
+    method public void setGravity(int);
     method public void setOnDismissListener(android.widget.PopupMenu.OnDismissListener);
     method public void setOnMenuItemClickListener(android.widget.PopupMenu.OnMenuItemClickListener);
     method public void show();
@@ -38149,6 +38957,7 @@
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
     method public int getMaxAvailableHeight(android.view.View, int);
+    method public boolean getOverlapAnchor();
     method public int getSoftInputMode();
     method public int getWidth();
     method public boolean isAboveAnchor();
@@ -38165,12 +38974,15 @@
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
+    method public void setEnterTransition(android.transition.Transition);
+    method public void setExitTransition(android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
     method public void setInputMethodMode(int);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
     method public void setOutsideTouchable(boolean);
+    method public void setOverlapAnchor(boolean);
     method public void setSoftInputMode(int);
     method public void setSplitTouchEnabled(boolean);
     method public void setTouchInterceptor(android.view.View.OnTouchListener);
@@ -38255,6 +39067,7 @@
     method public void setImageToDefault();
     method public void setMode(int);
     method public void setOverlay(android.graphics.drawable.Drawable);
+    method public void setPrioritizedMimeType(java.lang.String);
     field protected java.lang.String[] mExcludeMimes;
   }
 
@@ -38352,6 +39165,7 @@
     method public void addRule(int);
     method public void addRule(int, int);
     method public java.lang.String debug(java.lang.String);
+    method public int getRule(int);
     method public int[] getRules();
     method public void removeRule(int);
     field public boolean alignWithParent;
@@ -38586,15 +39400,17 @@
     method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
   }
 
-  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
     method public int getCount();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public java.lang.Object getItem(int);
     method public long getItemId(int);
     method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
     method public android.widget.SimpleAdapter.ViewBinder getViewBinder();
     method public void setDropDownViewResource(int);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setViewBinder(android.widget.SimpleAdapter.ViewBinder);
     method public void setViewImage(android.widget.ImageView, int);
     method public void setViewImage(android.widget.ImageView, java.lang.String);
@@ -38713,11 +39529,13 @@
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int);
+    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.Context);
     method public int getDropDownHorizontalOffset();
     method public int getDropDownVerticalOffset();
     method public int getDropDownWidth();
     method public int getGravity();
     method public android.graphics.drawable.Drawable getPopupBackground();
+    method public android.content.Context getPopupContext();
     method public java.lang.CharSequence getPrompt();
     method public void onClick(android.content.DialogInterface, int);
     method public void setDropDownHorizontalOffset(int);
@@ -38732,6 +39550,11 @@
     field public static final int MODE_DROPDOWN = 1; // 0x1
   }
 
+  public static abstract interface Spinner.ThemedSpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
   public abstract interface SpinnerAdapter implements android.widget.Adapter {
     method public abstract android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
   }
@@ -38756,7 +39579,11 @@
     method public java.lang.CharSequence getTextOn();
     method public android.graphics.drawable.Drawable getThumbDrawable();
     method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
     method public void onMeasure(int, int);
     method public void setShowText(boolean);
     method public void setSplitTrack(boolean);
@@ -38770,8 +39597,12 @@
     method public void setThumbDrawable(android.graphics.drawable.Drawable);
     method public void setThumbResource(int);
     method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
     method public void setTrackDrawable(android.graphics.drawable.Drawable);
     method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
@@ -38917,6 +39748,8 @@
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
     method public int getCompoundDrawablePadding();
+    method public android.content.res.ColorStateList getCompoundDrawableTintList();
+    method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
     method public android.graphics.drawable.Drawable[] getCompoundDrawables();
     method public android.graphics.drawable.Drawable[] getCompoundDrawablesRelative();
     method public int getCompoundPaddingBottom();
@@ -39016,6 +39849,8 @@
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
     method public void setCompoundDrawablePadding(int);
+    method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
+    method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
     method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public void setCompoundDrawablesRelative(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public void setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int);
@@ -39200,7 +40035,11 @@
     method public void setNavigationIcon(int);
     method public void setNavigationIcon(android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setNavigationTintList(android.content.res.ColorStateList);
+    method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public void setSubtitle(int);
     method public void setSubtitle(java.lang.CharSequence);
@@ -41682,7 +42521,7 @@
     method public static double nextUp(double);
     method public static float nextUp(float);
     method public static double pow(double, double);
-    method public static synchronized double random();
+    method public static double random();
     method public static double rint(double);
     method public static long round(double);
     method public static int round(float);
@@ -54364,1105 +55203,13 @@
 
 }
 
-package org.apache.commons.logging {
-
-  public abstract deprecated interface Log {
-    method public abstract void debug(java.lang.Object);
-    method public abstract void debug(java.lang.Object, java.lang.Throwable);
-    method public abstract void error(java.lang.Object);
-    method public abstract void error(java.lang.Object, java.lang.Throwable);
-    method public abstract void fatal(java.lang.Object);
-    method public abstract void fatal(java.lang.Object, java.lang.Throwable);
-    method public abstract void info(java.lang.Object);
-    method public abstract void info(java.lang.Object, java.lang.Throwable);
-    method public abstract boolean isDebugEnabled();
-    method public abstract boolean isErrorEnabled();
-    method public abstract boolean isFatalEnabled();
-    method public abstract boolean isInfoEnabled();
-    method public abstract boolean isTraceEnabled();
-    method public abstract boolean isWarnEnabled();
-    method public abstract void trace(java.lang.Object);
-    method public abstract void trace(java.lang.Object, java.lang.Throwable);
-    method public abstract void warn(java.lang.Object);
-    method public abstract void warn(java.lang.Object, java.lang.Throwable);
-  }
-
-}
-
-package org.apache.http {
-
-  public deprecated class ConnectionClosedException extends java.io.IOException {
-    ctor public ConnectionClosedException(java.lang.String);
-  }
-
-  public abstract deprecated interface ConnectionReuseStrategy {
-    method public abstract boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface FormattedHeader implements org.apache.http.Header {
-    method public abstract org.apache.http.util.CharArrayBuffer getBuffer();
-    method public abstract int getValuePos();
-  }
-
-  public abstract deprecated interface Header {
-    method public abstract org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getValue();
-  }
-
-  public abstract deprecated interface HeaderElement {
-    method public abstract java.lang.String getName();
-    method public abstract org.apache.http.NameValuePair getParameter(int);
-    method public abstract org.apache.http.NameValuePair getParameterByName(java.lang.String);
-    method public abstract int getParameterCount();
-    method public abstract org.apache.http.NameValuePair[] getParameters();
-    method public abstract java.lang.String getValue();
-  }
-
-  public abstract deprecated interface HeaderElementIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract org.apache.http.HeaderElement nextElement();
-  }
-
-  public abstract deprecated interface HeaderIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract org.apache.http.Header nextHeader();
-  }
-
-  public abstract deprecated interface HttpClientConnection implements org.apache.http.HttpConnection {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract boolean isResponseAvailable(int) throws java.io.IOException;
-    method public abstract void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpConnection {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract org.apache.http.HttpConnectionMetrics getMetrics();
-    method public abstract int getSocketTimeout();
-    method public abstract boolean isOpen();
-    method public abstract boolean isStale();
-    method public abstract void setSocketTimeout(int);
-    method public abstract void shutdown() throws java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpConnectionMetrics {
-    method public abstract java.lang.Object getMetric(java.lang.String);
-    method public abstract long getReceivedBytesCount();
-    method public abstract long getRequestCount();
-    method public abstract long getResponseCount();
-    method public abstract long getSentBytesCount();
-    method public abstract void reset();
-  }
-
-  public abstract deprecated interface HttpEntity {
-    method public abstract void consumeContent() throws java.io.IOException;
-    method public abstract java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException;
-    method public abstract org.apache.http.Header getContentEncoding();
-    method public abstract long getContentLength();
-    method public abstract org.apache.http.Header getContentType();
-    method public abstract boolean isChunked();
-    method public abstract boolean isRepeatable();
-    method public abstract boolean isStreaming();
-    method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpEntityEnclosingRequest implements org.apache.http.HttpRequest {
-    method public abstract boolean expectContinue();
-    method public abstract org.apache.http.HttpEntity getEntity();
-    method public abstract void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class HttpException extends java.lang.Exception {
-    ctor public HttpException();
-    ctor public HttpException(java.lang.String);
-    ctor public HttpException(java.lang.String, java.lang.Throwable);
-  }
-
-  public final deprecated class HttpHost implements java.lang.Cloneable {
-    ctor public HttpHost(java.lang.String, int, java.lang.String);
-    ctor public HttpHost(java.lang.String, int);
-    ctor public HttpHost(java.lang.String);
-    ctor public HttpHost(org.apache.http.HttpHost);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getHostName();
-    method public int getPort();
-    method public java.lang.String getSchemeName();
-    method public java.lang.String toHostString();
-    method public java.lang.String toURI();
-    field public static final java.lang.String DEFAULT_SCHEME_NAME = "http";
-    field protected final java.lang.String hostname;
-    field protected final java.lang.String lcHostname;
-    field protected final int port;
-    field protected final java.lang.String schemeName;
-  }
-
-  public abstract deprecated interface HttpInetConnection implements org.apache.http.HttpConnection {
-    method public abstract java.net.InetAddress getLocalAddress();
-    method public abstract int getLocalPort();
-    method public abstract java.net.InetAddress getRemoteAddress();
-    method public abstract int getRemotePort();
-  }
-
-  public abstract deprecated interface HttpMessage {
-    method public abstract void addHeader(org.apache.http.Header);
-    method public abstract void addHeader(java.lang.String, java.lang.String);
-    method public abstract boolean containsHeader(java.lang.String);
-    method public abstract org.apache.http.Header[] getAllHeaders();
-    method public abstract org.apache.http.Header getFirstHeader(java.lang.String);
-    method public abstract org.apache.http.Header[] getHeaders(java.lang.String);
-    method public abstract org.apache.http.Header getLastHeader(java.lang.String);
-    method public abstract org.apache.http.params.HttpParams getParams();
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract org.apache.http.HeaderIterator headerIterator();
-    method public abstract org.apache.http.HeaderIterator headerIterator(java.lang.String);
-    method public abstract void removeHeader(org.apache.http.Header);
-    method public abstract void removeHeaders(java.lang.String);
-    method public abstract void setHeader(org.apache.http.Header);
-    method public abstract void setHeader(java.lang.String, java.lang.String);
-    method public abstract void setHeaders(org.apache.http.Header[]);
-    method public abstract void setParams(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated interface HttpRequest implements org.apache.http.HttpMessage {
-    method public abstract org.apache.http.RequestLine getRequestLine();
-  }
-
-  public abstract deprecated interface HttpRequestFactory {
-    method public abstract org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException;
-    method public abstract org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException;
-  }
-
-  public abstract deprecated interface HttpRequestInterceptor {
-    method public abstract void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpResponse implements org.apache.http.HttpMessage {
-    method public abstract org.apache.http.HttpEntity getEntity();
-    method public abstract java.util.Locale getLocale();
-    method public abstract org.apache.http.StatusLine getStatusLine();
-    method public abstract void setEntity(org.apache.http.HttpEntity);
-    method public abstract void setLocale(java.util.Locale);
-    method public abstract void setReasonPhrase(java.lang.String) throws java.lang.IllegalStateException;
-    method public abstract void setStatusCode(int) throws java.lang.IllegalStateException;
-    method public abstract void setStatusLine(org.apache.http.StatusLine);
-    method public abstract void setStatusLine(org.apache.http.ProtocolVersion, int);
-    method public abstract void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-  }
-
-  public abstract deprecated interface HttpResponseFactory {
-    method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.ProtocolVersion, int, org.apache.http.protocol.HttpContext);
-    method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.StatusLine, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface HttpResponseInterceptor {
-    method public abstract void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpServerConnection implements org.apache.http.HttpConnection {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract void receiveRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract org.apache.http.HttpRequest receiveRequestHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpStatus {
-    field public static final int SC_ACCEPTED = 202; // 0xca
-    field public static final int SC_BAD_GATEWAY = 502; // 0x1f6
-    field public static final int SC_BAD_REQUEST = 400; // 0x190
-    field public static final int SC_CONFLICT = 409; // 0x199
-    field public static final int SC_CONTINUE = 100; // 0x64
-    field public static final int SC_CREATED = 201; // 0xc9
-    field public static final int SC_EXPECTATION_FAILED = 417; // 0x1a1
-    field public static final int SC_FAILED_DEPENDENCY = 424; // 0x1a8
-    field public static final int SC_FORBIDDEN = 403; // 0x193
-    field public static final int SC_GATEWAY_TIMEOUT = 504; // 0x1f8
-    field public static final int SC_GONE = 410; // 0x19a
-    field public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; // 0x1f9
-    field public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; // 0x1a3
-    field public static final int SC_INSUFFICIENT_STORAGE = 507; // 0x1fb
-    field public static final int SC_INTERNAL_SERVER_ERROR = 500; // 0x1f4
-    field public static final int SC_LENGTH_REQUIRED = 411; // 0x19b
-    field public static final int SC_LOCKED = 423; // 0x1a7
-    field public static final int SC_METHOD_FAILURE = 420; // 0x1a4
-    field public static final int SC_METHOD_NOT_ALLOWED = 405; // 0x195
-    field public static final int SC_MOVED_PERMANENTLY = 301; // 0x12d
-    field public static final int SC_MOVED_TEMPORARILY = 302; // 0x12e
-    field public static final int SC_MULTIPLE_CHOICES = 300; // 0x12c
-    field public static final int SC_MULTI_STATUS = 207; // 0xcf
-    field public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; // 0xcb
-    field public static final int SC_NOT_ACCEPTABLE = 406; // 0x196
-    field public static final int SC_NOT_FOUND = 404; // 0x194
-    field public static final int SC_NOT_IMPLEMENTED = 501; // 0x1f5
-    field public static final int SC_NOT_MODIFIED = 304; // 0x130
-    field public static final int SC_NO_CONTENT = 204; // 0xcc
-    field public static final int SC_OK = 200; // 0xc8
-    field public static final int SC_PARTIAL_CONTENT = 206; // 0xce
-    field public static final int SC_PAYMENT_REQUIRED = 402; // 0x192
-    field public static final int SC_PRECONDITION_FAILED = 412; // 0x19c
-    field public static final int SC_PROCESSING = 102; // 0x66
-    field public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; // 0x197
-    field public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; // 0x1a0
-    field public static final int SC_REQUEST_TIMEOUT = 408; // 0x198
-    field public static final int SC_REQUEST_TOO_LONG = 413; // 0x19d
-    field public static final int SC_REQUEST_URI_TOO_LONG = 414; // 0x19e
-    field public static final int SC_RESET_CONTENT = 205; // 0xcd
-    field public static final int SC_SEE_OTHER = 303; // 0x12f
-    field public static final int SC_SERVICE_UNAVAILABLE = 503; // 0x1f7
-    field public static final int SC_SWITCHING_PROTOCOLS = 101; // 0x65
-    field public static final int SC_TEMPORARY_REDIRECT = 307; // 0x133
-    field public static final int SC_UNAUTHORIZED = 401; // 0x191
-    field public static final int SC_UNPROCESSABLE_ENTITY = 422; // 0x1a6
-    field public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; // 0x19f
-    field public static final int SC_USE_PROXY = 305; // 0x131
-  }
-
-  public final deprecated class HttpVersion extends org.apache.http.ProtocolVersion implements java.io.Serializable {
-    ctor public HttpVersion(int, int);
-    field public static final java.lang.String HTTP = "HTTP";
-    field public static final org.apache.http.HttpVersion HTTP_0_9;
-    field public static final org.apache.http.HttpVersion HTTP_1_0;
-    field public static final org.apache.http.HttpVersion HTTP_1_1;
-  }
-
-  public deprecated class MalformedChunkCodingException extends java.io.IOException {
-    ctor public MalformedChunkCodingException();
-    ctor public MalformedChunkCodingException(java.lang.String);
-  }
-
-  public deprecated class MethodNotSupportedException extends org.apache.http.HttpException {
-    ctor public MethodNotSupportedException(java.lang.String);
-    ctor public MethodNotSupportedException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface NameValuePair {
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getValue();
-  }
-
-  public deprecated class NoHttpResponseException extends java.io.IOException {
-    ctor public NoHttpResponseException(java.lang.String);
-  }
-
-  public deprecated class ParseException extends java.lang.RuntimeException {
-    ctor public ParseException();
-    ctor public ParseException(java.lang.String);
-  }
-
-  public deprecated class ProtocolException extends org.apache.http.HttpException {
-    ctor public ProtocolException();
-    ctor public ProtocolException(java.lang.String);
-    ctor public ProtocolException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class ProtocolVersion implements java.lang.Cloneable java.io.Serializable {
-    ctor public ProtocolVersion(java.lang.String, int, int);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public int compareToVersion(org.apache.http.ProtocolVersion);
-    method public final boolean equals(java.lang.Object);
-    method public org.apache.http.ProtocolVersion forVersion(int, int);
-    method public final int getMajor();
-    method public final int getMinor();
-    method public final java.lang.String getProtocol();
-    method public final boolean greaterEquals(org.apache.http.ProtocolVersion);
-    method public final int hashCode();
-    method public boolean isComparable(org.apache.http.ProtocolVersion);
-    method public final boolean lessEquals(org.apache.http.ProtocolVersion);
-    field protected final int major;
-    field protected final int minor;
-    field protected final java.lang.String protocol;
-  }
-
-  public abstract deprecated interface ReasonPhraseCatalog {
-    method public abstract java.lang.String getReason(int, java.util.Locale);
-  }
-
-  public abstract deprecated interface RequestLine {
-    method public abstract java.lang.String getMethod();
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract java.lang.String getUri();
-  }
-
-  public abstract deprecated interface StatusLine {
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract java.lang.String getReasonPhrase();
-    method public abstract int getStatusCode();
-  }
-
-  public abstract deprecated interface TokenIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract java.lang.String nextToken();
-  }
-
-  public deprecated class UnsupportedHttpVersionException extends org.apache.http.ProtocolException {
-    ctor public UnsupportedHttpVersionException();
-    ctor public UnsupportedHttpVersionException(java.lang.String);
-  }
-
-}
-
-package org.apache.http.auth {
-
-  public final deprecated class AUTH {
-    field public static final java.lang.String PROXY_AUTH = "Proxy-Authenticate";
-    field public static final java.lang.String PROXY_AUTH_RESP = "Proxy-Authorization";
-    field public static final java.lang.String WWW_AUTH = "WWW-Authenticate";
-    field public static final java.lang.String WWW_AUTH_RESP = "Authorization";
-  }
-
-  public abstract deprecated interface AuthScheme {
-    method public abstract org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public abstract java.lang.String getParameter(java.lang.String);
-    method public abstract java.lang.String getRealm();
-    method public abstract java.lang.String getSchemeName();
-    method public abstract boolean isComplete();
-    method public abstract boolean isConnectionBased();
-    method public abstract void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public abstract deprecated interface AuthSchemeFactory {
-    method public abstract org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public final deprecated class AuthSchemeRegistry {
-    ctor public AuthSchemeRegistry();
-    method public synchronized org.apache.http.auth.AuthScheme getAuthScheme(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException;
-    method public synchronized java.util.List<java.lang.String> getSchemeNames();
-    method public synchronized void register(java.lang.String, org.apache.http.auth.AuthSchemeFactory);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.auth.AuthSchemeFactory>);
-    method public synchronized void unregister(java.lang.String);
-  }
-
-  public deprecated class AuthScope {
-    ctor public AuthScope(java.lang.String, int, java.lang.String, java.lang.String);
-    ctor public AuthScope(java.lang.String, int, java.lang.String);
-    ctor public AuthScope(java.lang.String, int);
-    ctor public AuthScope(org.apache.http.auth.AuthScope);
-    method public java.lang.String getHost();
-    method public int getPort();
-    method public java.lang.String getRealm();
-    method public java.lang.String getScheme();
-    method public int match(org.apache.http.auth.AuthScope);
-    field public static final org.apache.http.auth.AuthScope ANY;
-    field public static final java.lang.String ANY_HOST;
-    field public static final int ANY_PORT = -1; // 0xffffffff
-    field public static final java.lang.String ANY_REALM;
-    field public static final java.lang.String ANY_SCHEME;
-  }
-
-  public deprecated class AuthState {
-    ctor public AuthState();
-    method public org.apache.http.auth.AuthScheme getAuthScheme();
-    method public org.apache.http.auth.AuthScope getAuthScope();
-    method public org.apache.http.auth.Credentials getCredentials();
-    method public void invalidate();
-    method public boolean isValid();
-    method public void setAuthScheme(org.apache.http.auth.AuthScheme);
-    method public void setAuthScope(org.apache.http.auth.AuthScope);
-    method public void setCredentials(org.apache.http.auth.Credentials);
-  }
-
-  public deprecated class AuthenticationException extends org.apache.http.ProtocolException {
-    ctor public AuthenticationException();
-    ctor public AuthenticationException(java.lang.String);
-    ctor public AuthenticationException(java.lang.String, java.lang.Throwable);
-  }
-
-  public final deprecated class BasicUserPrincipal implements java.security.Principal {
-    ctor public BasicUserPrincipal(java.lang.String);
-    method public java.lang.String getName();
-  }
-
-  public abstract deprecated interface Credentials {
-    method public abstract java.lang.String getPassword();
-    method public abstract java.security.Principal getUserPrincipal();
-  }
-
-  public deprecated class InvalidCredentialsException extends org.apache.http.auth.AuthenticationException {
-    ctor public InvalidCredentialsException();
-    ctor public InvalidCredentialsException(java.lang.String);
-    ctor public InvalidCredentialsException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class MalformedChallengeException extends org.apache.http.ProtocolException {
-    ctor public MalformedChallengeException();
-    ctor public MalformedChallengeException(java.lang.String);
-    ctor public MalformedChallengeException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class NTCredentials implements org.apache.http.auth.Credentials {
-    ctor public NTCredentials(java.lang.String);
-    ctor public NTCredentials(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getDomain();
-    method public java.lang.String getPassword();
-    method public java.lang.String getUserName();
-    method public java.security.Principal getUserPrincipal();
-    method public java.lang.String getWorkstation();
-  }
-
-  public deprecated class NTUserPrincipal implements java.security.Principal {
-    ctor public NTUserPrincipal(java.lang.String, java.lang.String);
-    method public java.lang.String getDomain();
-    method public java.lang.String getName();
-    method public java.lang.String getUsername();
-  }
-
-  public deprecated class UsernamePasswordCredentials implements org.apache.http.auth.Credentials {
-    ctor public UsernamePasswordCredentials(java.lang.String);
-    ctor public UsernamePasswordCredentials(java.lang.String, java.lang.String);
-    method public java.lang.String getPassword();
-    method public java.lang.String getUserName();
-    method public java.security.Principal getUserPrincipal();
-  }
-
-}
-
-package org.apache.http.auth.params {
-
-  public abstract deprecated interface AuthPNames {
-    field public static final java.lang.String CREDENTIAL_CHARSET = "http.auth.credential-charset";
-  }
-
-  public deprecated class AuthParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public AuthParamBean(org.apache.http.params.HttpParams);
-    method public void setCredentialCharset(java.lang.String);
-  }
-
-  public final deprecated class AuthParams {
-    method public static java.lang.String getCredentialCharset(org.apache.http.params.HttpParams);
-    method public static void setCredentialCharset(org.apache.http.params.HttpParams, java.lang.String);
-  }
-
-}
-
-package org.apache.http.client {
-
-  public abstract deprecated interface AuthenticationHandler {
-    method public abstract java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public abstract boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-    method public abstract org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException;
-  }
-
-  public deprecated class CircularRedirectException extends org.apache.http.client.RedirectException {
-    ctor public CircularRedirectException();
-    ctor public CircularRedirectException(java.lang.String);
-    ctor public CircularRedirectException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class ClientProtocolException extends java.io.IOException {
-    ctor public ClientProtocolException();
-    ctor public ClientProtocolException(java.lang.String);
-    ctor public ClientProtocolException(java.lang.Throwable);
-    ctor public ClientProtocolException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface CookieStore {
-    method public abstract void addCookie(org.apache.http.cookie.Cookie);
-    method public abstract void clear();
-    method public abstract boolean clearExpired(java.util.Date);
-    method public abstract java.util.List<org.apache.http.cookie.Cookie> getCookies();
-  }
-
-  public abstract deprecated interface CredentialsProvider {
-    method public abstract void clear();
-    method public abstract org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope);
-    method public abstract void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials);
-  }
-
-  public abstract deprecated interface HttpClient {
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public abstract org.apache.http.params.HttpParams getParams();
-  }
-
-  public abstract deprecated interface HttpRequestRetryHandler {
-    method public abstract boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class HttpResponseException extends org.apache.http.client.ClientProtocolException {
-    ctor public HttpResponseException(int, java.lang.String);
-    method public int getStatusCode();
-  }
-
-  public deprecated class NonRepeatableRequestException extends org.apache.http.ProtocolException {
-    ctor public NonRepeatableRequestException();
-    ctor public NonRepeatableRequestException(java.lang.String);
-  }
-
-  public deprecated class RedirectException extends org.apache.http.ProtocolException {
-    ctor public RedirectException();
-    ctor public RedirectException(java.lang.String);
-    ctor public RedirectException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface RedirectHandler {
-    method public abstract java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException;
-    method public abstract boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface RequestDirector {
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface ResponseHandler {
-    method public abstract T handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-  }
-
-  public abstract deprecated interface UserTokenHandler {
-    method public abstract java.lang.Object getUserToken(org.apache.http.protocol.HttpContext);
-  }
-
-}
-
-package org.apache.http.client.entity {
-
-  public deprecated class UrlEncodedFormEntity extends org.apache.http.entity.StringEntity {
-    ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>) throws java.io.UnsupportedEncodingException;
-  }
-
-}
-
-package org.apache.http.client.methods {
-
-  public abstract deprecated interface AbortableHttpRequest {
-    method public abstract void abort();
-    method public abstract void setConnectionRequest(org.apache.http.conn.ClientConnectionRequest) throws java.io.IOException;
-    method public abstract void setReleaseTrigger(org.apache.http.conn.ConnectionReleaseTrigger) throws java.io.IOException;
-  }
-
-  public deprecated class HttpDelete extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpDelete();
-    ctor public HttpDelete(java.net.URI);
-    ctor public HttpDelete(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "DELETE";
-  }
-
-  public abstract deprecated class HttpEntityEnclosingRequestBase extends org.apache.http.client.methods.HttpRequestBase implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public HttpEntityEnclosingRequestBase();
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class HttpGet extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpGet();
-    ctor public HttpGet(java.net.URI);
-    ctor public HttpGet(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "GET";
-  }
-
-  public deprecated class HttpHead extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpHead();
-    ctor public HttpHead(java.net.URI);
-    ctor public HttpHead(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "HEAD";
-  }
-
-  public deprecated class HttpOptions extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpOptions();
-    ctor public HttpOptions(java.net.URI);
-    ctor public HttpOptions(java.lang.String);
-    method public java.util.Set<java.lang.String> getAllowedMethods(org.apache.http.HttpResponse);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "OPTIONS";
-  }
-
-  public deprecated class HttpPost extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase {
-    ctor public HttpPost();
-    ctor public HttpPost(java.net.URI);
-    ctor public HttpPost(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "POST";
-  }
-
-  public deprecated class HttpPut extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase {
-    ctor public HttpPut();
-    ctor public HttpPut(java.net.URI);
-    ctor public HttpPut(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "PUT";
-  }
-
-  public abstract deprecated class HttpRequestBase extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.AbortableHttpRequest java.lang.Cloneable org.apache.http.client.methods.HttpUriRequest {
-    ctor public HttpRequestBase();
-    method public void abort();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public abstract java.lang.String getMethod();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-    method public java.net.URI getURI();
-    method public boolean isAborted();
-    method public void setConnectionRequest(org.apache.http.conn.ClientConnectionRequest) throws java.io.IOException;
-    method public void setReleaseTrigger(org.apache.http.conn.ConnectionReleaseTrigger) throws java.io.IOException;
-    method public void setURI(java.net.URI);
-  }
-
-  public deprecated class HttpTrace extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpTrace();
-    ctor public HttpTrace(java.net.URI);
-    ctor public HttpTrace(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "TRACE";
-  }
-
-  public abstract deprecated interface HttpUriRequest implements org.apache.http.HttpRequest {
-    method public abstract void abort() throws java.lang.UnsupportedOperationException;
-    method public abstract java.lang.String getMethod();
-    method public abstract java.net.URI getURI();
-    method public abstract boolean isAborted();
-  }
-
-}
-
-package org.apache.http.client.params {
-
-  public abstract deprecated interface AllClientPNames implements org.apache.http.auth.params.AuthPNames org.apache.http.client.params.ClientPNames org.apache.http.conn.params.ConnConnectionPNames org.apache.http.conn.params.ConnManagerPNames org.apache.http.conn.params.ConnRoutePNames org.apache.http.cookie.params.CookieSpecPNames org.apache.http.params.CoreConnectionPNames org.apache.http.params.CoreProtocolPNames {
-  }
-
-  public final deprecated class AuthPolicy {
-    field public static final java.lang.String BASIC = "Basic";
-    field public static final java.lang.String DIGEST = "Digest";
-    field public static final java.lang.String NTLM = "NTLM";
-  }
-
-  public abstract deprecated interface ClientPNames {
-    field public static final java.lang.String ALLOW_CIRCULAR_REDIRECTS = "http.protocol.allow-circular-redirects";
-    field public static final java.lang.String CONNECTION_MANAGER_FACTORY = "http.connection-manager.factory-object";
-    field public static final java.lang.String CONNECTION_MANAGER_FACTORY_CLASS_NAME = "http.connection-manager.factory-class-name";
-    field public static final java.lang.String COOKIE_POLICY = "http.protocol.cookie-policy";
-    field public static final java.lang.String DEFAULT_HEADERS = "http.default-headers";
-    field public static final java.lang.String DEFAULT_HOST = "http.default-host";
-    field public static final java.lang.String HANDLE_AUTHENTICATION = "http.protocol.handle-authentication";
-    field public static final java.lang.String HANDLE_REDIRECTS = "http.protocol.handle-redirects";
-    field public static final java.lang.String MAX_REDIRECTS = "http.protocol.max-redirects";
-    field public static final java.lang.String REJECT_RELATIVE_REDIRECT = "http.protocol.reject-relative-redirect";
-    field public static final java.lang.String VIRTUAL_HOST = "http.virtual-host";
-  }
-
-  public deprecated class ClientParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ClientParamBean(org.apache.http.params.HttpParams);
-    method public void setAllowCircularRedirects(boolean);
-    method public void setConnectionManagerFactory(org.apache.http.conn.ClientConnectionManagerFactory);
-    method public void setConnectionManagerFactoryClassName(java.lang.String);
-    method public void setCookiePolicy(java.lang.String);
-    method public void setDefaultHeaders(java.util.Collection<org.apache.http.Header>);
-    method public void setDefaultHost(org.apache.http.HttpHost);
-    method public void setHandleAuthentication(boolean);
-    method public void setHandleRedirects(boolean);
-    method public void setMaxRedirects(int);
-    method public void setRejectRelativeRedirect(boolean);
-    method public void setVirtualHost(org.apache.http.HttpHost);
-  }
-
-  public final deprecated class CookiePolicy {
-    field public static final java.lang.String BEST_MATCH = "best-match";
-    field public static final java.lang.String BROWSER_COMPATIBILITY = "compatibility";
-    field public static final java.lang.String NETSCAPE = "netscape";
-    field public static final java.lang.String RFC_2109 = "rfc2109";
-    field public static final java.lang.String RFC_2965 = "rfc2965";
-  }
-
-  public deprecated class HttpClientParams {
-    method public static java.lang.String getCookiePolicy(org.apache.http.params.HttpParams);
-    method public static boolean isAuthenticating(org.apache.http.params.HttpParams);
-    method public static boolean isRedirecting(org.apache.http.params.HttpParams);
-    method public static void setAuthenticating(org.apache.http.params.HttpParams, boolean);
-    method public static void setCookiePolicy(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setRedirecting(org.apache.http.params.HttpParams, boolean);
-  }
-
-}
-
-package org.apache.http.client.protocol {
-
-  public abstract deprecated interface ClientContext {
-    field public static final java.lang.String AUTHSCHEME_REGISTRY = "http.authscheme-registry";
-    field public static final java.lang.String AUTH_SCHEME_PREF = "http.auth.scheme-pref";
-    field public static final java.lang.String COOKIESPEC_REGISTRY = "http.cookiespec-registry";
-    field public static final java.lang.String COOKIE_ORIGIN = "http.cookie-origin";
-    field public static final java.lang.String COOKIE_SPEC = "http.cookie-spec";
-    field public static final java.lang.String COOKIE_STORE = "http.cookie-store";
-    field public static final java.lang.String CREDS_PROVIDER = "http.auth.credentials-provider";
-    field public static final java.lang.String PROXY_AUTH_STATE = "http.auth.proxy-scope";
-    field public static final java.lang.String TARGET_AUTH_STATE = "http.auth.target-scope";
-    field public static final java.lang.String USER_TOKEN = "http.user-token";
-  }
-
-  public deprecated class ClientContextConfigurer implements org.apache.http.client.protocol.ClientContext {
-    ctor public ClientContextConfigurer(org.apache.http.protocol.HttpContext);
-    method public void setAuthSchemePref(java.util.List<java.lang.String>);
-    method public void setAuthSchemeRegistry(org.apache.http.auth.AuthSchemeRegistry);
-    method public void setCookieSpecRegistry(org.apache.http.cookie.CookieSpecRegistry);
-    method public void setCookieStore(org.apache.http.client.CookieStore);
-    method public void setCredentialsProvider(org.apache.http.client.CredentialsProvider);
-  }
-
-  public deprecated class RequestAddCookies implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestAddCookies();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestDefaultHeaders implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestDefaultHeaders();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestProxyAuthentication implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestProxyAuthentication();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestTargetAuthentication implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestTargetAuthentication();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseProcessCookies implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseProcessCookies();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-}
-
-package org.apache.http.client.utils {
-
-  public deprecated class CloneUtils {
-    method public static java.lang.Object clone(java.lang.Object) throws java.lang.CloneNotSupportedException;
-  }
-
-  public deprecated class URIUtils {
-    method public static java.net.URI createURI(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
-    method public static java.net.URI resolve(java.net.URI, java.lang.String);
-    method public static java.net.URI resolve(java.net.URI, java.net.URI);
-    method public static java.net.URI rewriteURI(java.net.URI, org.apache.http.HttpHost, boolean) throws java.net.URISyntaxException;
-    method public static java.net.URI rewriteURI(java.net.URI, org.apache.http.HttpHost) throws java.net.URISyntaxException;
-  }
-
-  public deprecated class URLEncodedUtils {
-    ctor public URLEncodedUtils();
-    method public static java.lang.String format(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String);
-    method public static boolean isEncoded(org.apache.http.HttpEntity);
-    method public static java.util.List<org.apache.http.NameValuePair> parse(java.net.URI, java.lang.String);
-    method public static java.util.List<org.apache.http.NameValuePair> parse(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static void parse(java.util.List<org.apache.http.NameValuePair>, java.util.Scanner, java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "application/x-www-form-urlencoded";
-  }
-
-}
-
 package org.apache.http.conn {
 
-  public deprecated class BasicEofSensorWatcher implements org.apache.http.conn.EofSensorWatcher {
-    ctor public BasicEofSensorWatcher(org.apache.http.conn.ManagedClientConnection, boolean);
-    method public boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-    field protected boolean attemptReuse;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-  }
-
-  public deprecated class BasicManagedEntity extends org.apache.http.entity.HttpEntityWrapper implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.conn.EofSensorWatcher {
-    ctor public BasicManagedEntity(org.apache.http.HttpEntity, org.apache.http.conn.ManagedClientConnection, boolean);
-    method public void abortConnection() throws java.io.IOException;
-    method public boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public void releaseConnection() throws java.io.IOException;
-    method protected void releaseManagedConnection() throws java.io.IOException;
-    method public boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-    field protected final boolean attemptReuse;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-  }
-
-  public abstract deprecated interface ClientConnectionManager {
-    method public abstract void closeExpiredConnections();
-    method public abstract void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method public abstract org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public abstract void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public abstract org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public abstract void shutdown();
-  }
-
-  public abstract deprecated interface ClientConnectionManagerFactory {
-    method public abstract org.apache.http.conn.ClientConnectionManager newInstance(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-  }
-
-  public abstract deprecated interface ClientConnectionOperator {
-    method public abstract org.apache.http.conn.OperatedClientConnection createConnection();
-    method public abstract void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void updateSecureConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public abstract deprecated interface ClientConnectionRequest {
-    method public abstract void abortRequest();
-    method public abstract org.apache.http.conn.ManagedClientConnection getConnection(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-  }
-
   public deprecated class ConnectTimeoutException extends java.io.InterruptedIOException {
     ctor public ConnectTimeoutException();
     ctor public ConnectTimeoutException(java.lang.String);
   }
 
-  public abstract deprecated interface ConnectionKeepAliveStrategy {
-    method public abstract long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class ConnectionPoolTimeoutException extends org.apache.http.conn.ConnectTimeoutException {
-    ctor public ConnectionPoolTimeoutException();
-    ctor public ConnectionPoolTimeoutException(java.lang.String);
-  }
-
-  public abstract deprecated interface ConnectionReleaseTrigger {
-    method public abstract void abortConnection() throws java.io.IOException;
-    method public abstract void releaseConnection() throws java.io.IOException;
-  }
-
-  public deprecated class EofSensorInputStream extends java.io.InputStream implements org.apache.http.conn.ConnectionReleaseTrigger {
-    ctor public EofSensorInputStream(java.io.InputStream, org.apache.http.conn.EofSensorWatcher);
-    method public void abortConnection() throws java.io.IOException;
-    method protected void checkAbort() throws java.io.IOException;
-    method protected void checkClose() throws java.io.IOException;
-    method protected void checkEOF(int) throws java.io.IOException;
-    method protected boolean isReadAllowed() throws java.io.IOException;
-    method public int read() throws java.io.IOException;
-    method public void releaseConnection() throws java.io.IOException;
-    field protected java.io.InputStream wrappedStream;
-  }
-
-  public abstract deprecated interface EofSensorWatcher {
-    method public abstract boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public abstract boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public abstract boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-  }
-
-  public deprecated class HttpHostConnectException extends java.net.ConnectException {
-    ctor public HttpHostConnectException(org.apache.http.HttpHost, java.net.ConnectException);
-    method public org.apache.http.HttpHost getHost();
-  }
-
-  public abstract deprecated interface ManagedClientConnection implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection {
-    method public abstract org.apache.http.conn.routing.HttpRoute getRoute();
-    method public abstract javax.net.ssl.SSLSession getSSLSession();
-    method public abstract java.lang.Object getState();
-    method public abstract boolean isMarkedReusable();
-    method public abstract boolean isSecure();
-    method public abstract void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void markReusable();
-    method public abstract void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void setIdleDuration(long, java.util.concurrent.TimeUnit);
-    method public abstract void setState(java.lang.Object);
-    method public abstract void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void unmarkReusable();
-  }
-
-  public final deprecated class MultihomePlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory {
-    method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.Socket createSocket();
-    method public static org.apache.http.conn.MultihomePlainSocketFactory getSocketFactory();
-    method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
-  }
-
-  public abstract deprecated interface OperatedClientConnection implements org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection {
-    method public abstract java.net.Socket getSocket();
-    method public abstract org.apache.http.HttpHost getTargetHost();
-    method public abstract boolean isSecure();
-    method public abstract void openCompleted(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void opening(java.net.Socket, org.apache.http.HttpHost) throws java.io.IOException;
-    method public abstract void update(java.net.Socket, org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.conn.params {
-
-  public abstract deprecated interface ConnConnectionPNames {
-    field public static final java.lang.String MAX_STATUS_LINE_GARBAGE = "http.connection.max-status-line-garbage";
-  }
-
-  public deprecated class ConnConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnConnectionParamBean(org.apache.http.params.HttpParams);
-    method public void setMaxStatusLineGarbage(int);
-  }
-
-  public abstract deprecated interface ConnManagerPNames {
-    field public static final java.lang.String MAX_CONNECTIONS_PER_ROUTE = "http.conn-manager.max-per-route";
-    field public static final java.lang.String MAX_TOTAL_CONNECTIONS = "http.conn-manager.max-total";
-    field public static final java.lang.String TIMEOUT = "http.conn-manager.timeout";
-  }
-
-  public deprecated class ConnManagerParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnManagerParamBean(org.apache.http.params.HttpParams);
-    method public void setConnectionsPerRoute(org.apache.http.conn.params.ConnPerRouteBean);
-    method public void setMaxTotalConnections(int);
-    method public void setTimeout(long);
-  }
-
-  public final deprecated class ConnManagerParams implements org.apache.http.conn.params.ConnManagerPNames {
-    ctor public ConnManagerParams();
-    method public static org.apache.http.conn.params.ConnPerRoute getMaxConnectionsPerRoute(org.apache.http.params.HttpParams);
-    method public static int getMaxTotalConnections(org.apache.http.params.HttpParams);
-    method public static long getTimeout(org.apache.http.params.HttpParams);
-    method public static void setMaxConnectionsPerRoute(org.apache.http.params.HttpParams, org.apache.http.conn.params.ConnPerRoute);
-    method public static void setMaxTotalConnections(org.apache.http.params.HttpParams, int);
-    method public static void setTimeout(org.apache.http.params.HttpParams, long);
-    field public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20; // 0x14
-  }
-
-  public abstract deprecated interface ConnPerRoute {
-    method public abstract int getMaxForRoute(org.apache.http.conn.routing.HttpRoute);
-  }
-
-  public final deprecated class ConnPerRouteBean implements org.apache.http.conn.params.ConnPerRoute {
-    ctor public ConnPerRouteBean(int);
-    ctor public ConnPerRouteBean();
-    method public int getDefaultMax();
-    method public int getMaxForRoute(org.apache.http.conn.routing.HttpRoute);
-    method public void setDefaultMaxPerRoute(int);
-    method public void setMaxForRoute(org.apache.http.conn.routing.HttpRoute, int);
-    method public void setMaxForRoutes(java.util.Map<org.apache.http.conn.routing.HttpRoute, java.lang.Integer>);
-    field public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2; // 0x2
-  }
-
-  public abstract deprecated interface ConnRoutePNames {
-    field public static final java.lang.String DEFAULT_PROXY = "http.route.default-proxy";
-    field public static final java.lang.String FORCED_ROUTE = "http.route.forced-route";
-    field public static final java.lang.String LOCAL_ADDRESS = "http.route.local-address";
-  }
-
-  public deprecated class ConnRouteParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnRouteParamBean(org.apache.http.params.HttpParams);
-    method public void setDefaultProxy(org.apache.http.HttpHost);
-    method public void setForcedRoute(org.apache.http.conn.routing.HttpRoute);
-    method public void setLocalAddress(java.net.InetAddress);
-  }
-
-  public deprecated class ConnRouteParams implements org.apache.http.conn.params.ConnRoutePNames {
-    method public static org.apache.http.HttpHost getDefaultProxy(org.apache.http.params.HttpParams);
-    method public static org.apache.http.conn.routing.HttpRoute getForcedRoute(org.apache.http.params.HttpParams);
-    method public static java.net.InetAddress getLocalAddress(org.apache.http.params.HttpParams);
-    method public static void setDefaultProxy(org.apache.http.params.HttpParams, org.apache.http.HttpHost);
-    method public static void setForcedRoute(org.apache.http.params.HttpParams, org.apache.http.conn.routing.HttpRoute);
-    method public static void setLocalAddress(org.apache.http.params.HttpParams, java.net.InetAddress);
-    field public static final org.apache.http.HttpHost NO_HOST;
-    field public static final org.apache.http.conn.routing.HttpRoute NO_ROUTE;
-  }
-
-}
-
-package org.apache.http.conn.routing {
-
-  public deprecated class BasicRouteDirector implements org.apache.http.conn.routing.HttpRouteDirector {
-    ctor public BasicRouteDirector();
-    method protected int directStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    method protected int firstStep(org.apache.http.conn.routing.RouteInfo);
-    method public int nextStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    method protected int proxiedStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-  }
-
-  public final deprecated class HttpRoute implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo {
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost[], boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost, boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, boolean);
-    ctor public HttpRoute(org.apache.http.HttpHost);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost, boolean);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public final boolean equals(java.lang.Object);
-    method public final int getHopCount();
-    method public final org.apache.http.HttpHost getHopTarget(int);
-    method public final org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public final java.net.InetAddress getLocalAddress();
-    method public final org.apache.http.HttpHost getProxyHost();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public final int hashCode();
-    method public final boolean isLayered();
-    method public final boolean isSecure();
-    method public final boolean isTunnelled();
-    method public final java.lang.String toString();
-  }
-
-  public abstract deprecated interface HttpRouteDirector {
-    method public abstract int nextStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    field public static final int COMPLETE = 0; // 0x0
-    field public static final int CONNECT_PROXY = 2; // 0x2
-    field public static final int CONNECT_TARGET = 1; // 0x1
-    field public static final int LAYER_PROTOCOL = 5; // 0x5
-    field public static final int TUNNEL_PROXY = 4; // 0x4
-    field public static final int TUNNEL_TARGET = 3; // 0x3
-    field public static final int UNREACHABLE = -1; // 0xffffffff
-  }
-
-  public abstract deprecated interface HttpRoutePlanner {
-    method public abstract org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-  }
-
-  public abstract deprecated interface RouteInfo {
-    method public abstract int getHopCount();
-    method public abstract org.apache.http.HttpHost getHopTarget(int);
-    method public abstract org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public abstract java.net.InetAddress getLocalAddress();
-    method public abstract org.apache.http.HttpHost getProxyHost();
-    method public abstract org.apache.http.HttpHost getTargetHost();
-    method public abstract org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public abstract boolean isLayered();
-    method public abstract boolean isSecure();
-    method public abstract boolean isTunnelled();
-  }
-
-  public static final class RouteInfo.LayerType extends java.lang.Enum {
-    method public static org.apache.http.conn.routing.RouteInfo.LayerType valueOf(java.lang.String);
-    method public static final org.apache.http.conn.routing.RouteInfo.LayerType[] values();
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.LayerType LAYERED;
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.LayerType PLAIN;
-  }
-
-  public static final class RouteInfo.TunnelType extends java.lang.Enum {
-    method public static org.apache.http.conn.routing.RouteInfo.TunnelType valueOf(java.lang.String);
-    method public static final org.apache.http.conn.routing.RouteInfo.TunnelType[] values();
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.TunnelType PLAIN;
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.TunnelType TUNNELLED;
-  }
-
-  public final deprecated class RouteTracker implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo {
-    ctor public RouteTracker(org.apache.http.HttpHost, java.net.InetAddress);
-    ctor public RouteTracker(org.apache.http.conn.routing.HttpRoute);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public final void connectProxy(org.apache.http.HttpHost, boolean);
-    method public final void connectTarget(boolean);
-    method public final boolean equals(java.lang.Object);
-    method public final int getHopCount();
-    method public final org.apache.http.HttpHost getHopTarget(int);
-    method public final org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public final java.net.InetAddress getLocalAddress();
-    method public final org.apache.http.HttpHost getProxyHost();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public final int hashCode();
-    method public final boolean isConnected();
-    method public final boolean isLayered();
-    method public final boolean isSecure();
-    method public final boolean isTunnelled();
-    method public final void layerProtocol(boolean);
-    method public final org.apache.http.conn.routing.HttpRoute toRoute();
-    method public final java.lang.String toString();
-    method public final void tunnelProxy(org.apache.http.HttpHost, boolean);
-    method public final void tunnelTarget(boolean);
-  }
-
 }
 
 package org.apache.http.conn.scheme {
@@ -55475,37 +55222,6 @@
     method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
   }
 
-  public final deprecated class PlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory {
-    ctor public PlainSocketFactory(org.apache.http.conn.scheme.HostNameResolver);
-    ctor public PlainSocketFactory();
-    method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.Socket createSocket();
-    method public static org.apache.http.conn.scheme.PlainSocketFactory getSocketFactory();
-    method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
-  }
-
-  public final deprecated class Scheme {
-    ctor public Scheme(java.lang.String, org.apache.http.conn.scheme.SocketFactory, int);
-    method public final boolean equals(java.lang.Object);
-    method public final int getDefaultPort();
-    method public final java.lang.String getName();
-    method public final org.apache.http.conn.scheme.SocketFactory getSocketFactory();
-    method public final boolean isLayered();
-    method public final int resolvePort(int);
-    method public final java.lang.String toString();
-  }
-
-  public final deprecated class SchemeRegistry {
-    ctor public SchemeRegistry();
-    method public final synchronized org.apache.http.conn.scheme.Scheme get(java.lang.String);
-    method public final synchronized org.apache.http.conn.scheme.Scheme getScheme(java.lang.String);
-    method public final synchronized org.apache.http.conn.scheme.Scheme getScheme(org.apache.http.HttpHost);
-    method public final synchronized java.util.List<java.lang.String> getSchemeNames();
-    method public final synchronized org.apache.http.conn.scheme.Scheme register(org.apache.http.conn.scheme.Scheme);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.conn.scheme.Scheme>);
-    method public final synchronized org.apache.http.conn.scheme.Scheme unregister(java.lang.String);
-  }
-
   public abstract deprecated interface SocketFactory {
     method public abstract java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws org.apache.http.conn.ConnectTimeoutException, java.io.IOException, java.net.UnknownHostException;
     method public abstract java.net.Socket createSocket() throws java.io.IOException;
@@ -55575,1818 +55291,8 @@
 
 }
 
-package org.apache.http.conn.util {
-
-  public deprecated class InetAddressUtils {
-    method public static boolean isIPv4Address(java.lang.String);
-    method public static boolean isIPv6Address(java.lang.String);
-    method public static boolean isIPv6HexCompressedAddress(java.lang.String);
-    method public static boolean isIPv6StdAddress(java.lang.String);
-  }
-
-}
-
-package org.apache.http.cookie {
-
-  public abstract deprecated interface ClientCookie implements org.apache.http.cookie.Cookie {
-    method public abstract boolean containsAttribute(java.lang.String);
-    method public abstract java.lang.String getAttribute(java.lang.String);
-    field public static final java.lang.String COMMENTURL_ATTR = "commenturl";
-    field public static final java.lang.String COMMENT_ATTR = "comment";
-    field public static final java.lang.String DISCARD_ATTR = "discard";
-    field public static final java.lang.String DOMAIN_ATTR = "domain";
-    field public static final java.lang.String EXPIRES_ATTR = "expires";
-    field public static final java.lang.String MAX_AGE_ATTR = "max-age";
-    field public static final java.lang.String PATH_ATTR = "path";
-    field public static final java.lang.String PORT_ATTR = "port";
-    field public static final java.lang.String SECURE_ATTR = "secure";
-    field public static final java.lang.String VERSION_ATTR = "version";
-  }
-
-  public abstract deprecated interface Cookie {
-    method public abstract java.lang.String getComment();
-    method public abstract java.lang.String getCommentURL();
-    method public abstract java.lang.String getDomain();
-    method public abstract java.util.Date getExpiryDate();
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getPath();
-    method public abstract int[] getPorts();
-    method public abstract java.lang.String getValue();
-    method public abstract int getVersion();
-    method public abstract boolean isExpired(java.util.Date);
-    method public abstract boolean isPersistent();
-    method public abstract boolean isSecure();
-  }
-
-  public abstract deprecated interface CookieAttributeHandler {
-    method public abstract boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public abstract void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class CookieIdentityComparator implements java.util.Comparator java.io.Serializable {
-    ctor public CookieIdentityComparator();
-    method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie);
-  }
-
-  public final deprecated class CookieOrigin {
-    ctor public CookieOrigin(java.lang.String, int, java.lang.String, boolean);
-    method public java.lang.String getHost();
-    method public java.lang.String getPath();
-    method public int getPort();
-    method public boolean isSecure();
-  }
-
-  public deprecated class CookiePathComparator implements java.util.Comparator java.io.Serializable {
-    ctor public CookiePathComparator();
-    method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie);
-  }
-
-  public abstract deprecated interface CookieSpec {
-    method public abstract java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public abstract int getVersion();
-    method public abstract org.apache.http.Header getVersionHeader();
-    method public abstract boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public abstract java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public abstract deprecated interface CookieSpecFactory {
-    method public abstract org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public final deprecated class CookieSpecRegistry {
-    ctor public CookieSpecRegistry();
-    method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException;
-    method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String) throws java.lang.IllegalStateException;
-    method public synchronized java.util.List<java.lang.String> getSpecNames();
-    method public synchronized void register(java.lang.String, org.apache.http.cookie.CookieSpecFactory);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.cookie.CookieSpecFactory>);
-    method public synchronized void unregister(java.lang.String);
-  }
-
-  public deprecated class MalformedCookieException extends org.apache.http.ProtocolException {
-    ctor public MalformedCookieException();
-    ctor public MalformedCookieException(java.lang.String);
-    ctor public MalformedCookieException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface SM {
-    field public static final java.lang.String COOKIE = "Cookie";
-    field public static final java.lang.String COOKIE2 = "Cookie2";
-    field public static final java.lang.String SET_COOKIE = "Set-Cookie";
-    field public static final java.lang.String SET_COOKIE2 = "Set-Cookie2";
-  }
-
-  public abstract deprecated interface SetCookie implements org.apache.http.cookie.Cookie {
-    method public abstract void setComment(java.lang.String);
-    method public abstract void setDomain(java.lang.String);
-    method public abstract void setExpiryDate(java.util.Date);
-    method public abstract void setPath(java.lang.String);
-    method public abstract void setSecure(boolean);
-    method public abstract void setValue(java.lang.String);
-    method public abstract void setVersion(int);
-  }
-
-  public abstract deprecated interface SetCookie2 implements org.apache.http.cookie.SetCookie {
-    method public abstract void setCommentURL(java.lang.String);
-    method public abstract void setDiscard(boolean);
-    method public abstract void setPorts(int[]);
-  }
-
-}
-
-package org.apache.http.cookie.params {
-
-  public abstract deprecated interface CookieSpecPNames {
-    field public static final java.lang.String DATE_PATTERNS = "http.protocol.cookie-datepatterns";
-    field public static final java.lang.String SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
-  }
-
-  public deprecated class CookieSpecParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public CookieSpecParamBean(org.apache.http.params.HttpParams);
-    method public void setDatePatterns(java.util.Collection<java.lang.String>);
-    method public void setSingleHeader(boolean);
-  }
-
-}
-
-package org.apache.http.entity {
-
-  public abstract deprecated class AbstractHttpEntity implements org.apache.http.HttpEntity {
-    ctor protected AbstractHttpEntity();
-    method public void consumeContent() throws java.io.IOException, java.lang.UnsupportedOperationException;
-    method public org.apache.http.Header getContentEncoding();
-    method public org.apache.http.Header getContentType();
-    method public boolean isChunked();
-    method public void setChunked(boolean);
-    method public void setContentEncoding(org.apache.http.Header);
-    method public void setContentEncoding(java.lang.String);
-    method public void setContentType(org.apache.http.Header);
-    method public void setContentType(java.lang.String);
-    field protected boolean chunked;
-    field protected org.apache.http.Header contentEncoding;
-    field protected org.apache.http.Header contentType;
-  }
-
-  public deprecated class BasicHttpEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public BasicHttpEntity();
-    method public java.io.InputStream getContent() throws java.lang.IllegalStateException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void setContent(java.io.InputStream);
-    method public void setContentLength(long);
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class BufferedHttpEntity extends org.apache.http.entity.HttpEntityWrapper {
-    ctor public BufferedHttpEntity(org.apache.http.HttpEntity) throws java.io.IOException;
-  }
-
-  public deprecated class ByteArrayEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public ByteArrayEntity(byte[]);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent();
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final byte[] content;
-  }
-
-  public abstract deprecated interface ContentLengthStrategy {
-    method public abstract long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-    field public static final int CHUNKED = -2; // 0xfffffffe
-    field public static final int IDENTITY = -1; // 0xffffffff
-  }
-
-  public abstract deprecated interface ContentProducer {
-    method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class EntityTemplate extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public EntityTemplate(org.apache.http.entity.ContentProducer);
-    method public java.io.InputStream getContent();
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class FileEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public FileEntity(java.io.File, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final java.io.File file;
-  }
-
-  public deprecated class HttpEntityWrapper implements org.apache.http.HttpEntity {
-    ctor public HttpEntityWrapper(org.apache.http.HttpEntity);
-    method public void consumeContent() throws java.io.IOException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public org.apache.http.Header getContentEncoding();
-    method public long getContentLength();
-    method public org.apache.http.Header getContentType();
-    method public boolean isChunked();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected org.apache.http.HttpEntity wrappedEntity;
-  }
-
-  public deprecated class InputStreamEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public InputStreamEntity(java.io.InputStream, long);
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class SerializableEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public SerializableEntity(java.io.Serializable, boolean) throws java.io.IOException;
-    method public java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class StringEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public StringEntity(java.lang.String, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public StringEntity(java.lang.String) throws java.io.UnsupportedEncodingException;
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final byte[] content;
-  }
-
-}
-
-package org.apache.http.impl {
-
-  public abstract deprecated class AbstractHttpClientConnection implements org.apache.http.HttpClientConnection {
-    ctor public AbstractHttpClientConnection();
-    method protected abstract void assertOpen() throws java.lang.IllegalStateException;
-    method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer();
-    method protected org.apache.http.impl.entity.EntitySerializer createEntitySerializer();
-    method protected org.apache.http.HttpResponseFactory createHttpResponseFactory();
-    method protected org.apache.http.io.HttpMessageWriter createRequestWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method protected org.apache.http.io.HttpMessageParser createResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected void doFlush() throws java.io.IOException;
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method protected void init(org.apache.http.io.SessionInputBuffer, org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method public boolean isResponseAvailable(int) throws java.io.IOException;
-    method public boolean isStale();
-    method public void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated class AbstractHttpServerConnection implements org.apache.http.HttpServerConnection {
-    ctor public AbstractHttpServerConnection();
-    method protected abstract void assertOpen() throws java.lang.IllegalStateException;
-    method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer();
-    method protected org.apache.http.impl.entity.EntitySerializer createEntitySerializer();
-    method protected org.apache.http.HttpRequestFactory createHttpRequestFactory();
-    method protected org.apache.http.io.HttpMessageParser createRequestParser(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpRequestFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.io.HttpMessageWriter createResponseWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method protected void doFlush() throws java.io.IOException;
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method protected void init(org.apache.http.io.SessionInputBuffer, org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method public boolean isStale();
-    method public void receiveRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpRequest receiveRequestHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class DefaultConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy {
-    ctor public DefaultConnectionReuseStrategy();
-    method protected org.apache.http.TokenIterator createTokenIterator(org.apache.http.HeaderIterator);
-    method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultHttpClientConnection extends org.apache.http.impl.SocketHttpClientConnection {
-    ctor public DefaultHttpClientConnection();
-    method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class DefaultHttpRequestFactory implements org.apache.http.HttpRequestFactory {
-    ctor public DefaultHttpRequestFactory();
-    method public org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException;
-    method public org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException;
-  }
-
-  public deprecated class DefaultHttpResponseFactory implements org.apache.http.HttpResponseFactory {
-    ctor public DefaultHttpResponseFactory(org.apache.http.ReasonPhraseCatalog);
-    ctor public DefaultHttpResponseFactory();
-    method protected java.util.Locale determineLocale(org.apache.http.protocol.HttpContext);
-    method public org.apache.http.HttpResponse newHttpResponse(org.apache.http.ProtocolVersion, int, org.apache.http.protocol.HttpContext);
-    method public org.apache.http.HttpResponse newHttpResponse(org.apache.http.StatusLine, org.apache.http.protocol.HttpContext);
-    field protected final org.apache.http.ReasonPhraseCatalog reasonCatalog;
-  }
-
-  public deprecated class DefaultHttpServerConnection extends org.apache.http.impl.SocketHttpServerConnection {
-    ctor public DefaultHttpServerConnection();
-    method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class EnglishReasonPhraseCatalog implements org.apache.http.ReasonPhraseCatalog {
-    ctor protected EnglishReasonPhraseCatalog();
-    method public java.lang.String getReason(int, java.util.Locale);
-    field public static final org.apache.http.impl.EnglishReasonPhraseCatalog INSTANCE;
-  }
-
-  public deprecated class HttpConnectionMetricsImpl implements org.apache.http.HttpConnectionMetrics {
-    ctor public HttpConnectionMetricsImpl(org.apache.http.io.HttpTransportMetrics, org.apache.http.io.HttpTransportMetrics);
-    method public java.lang.Object getMetric(java.lang.String);
-    method public long getReceivedBytesCount();
-    method public long getRequestCount();
-    method public long getResponseCount();
-    method public long getSentBytesCount();
-    method public void incrementRequestCount();
-    method public void incrementResponseCount();
-    method public void reset();
-    method public void setMetric(java.lang.String, java.lang.Object);
-    field public static final java.lang.String RECEIVED_BYTES_COUNT = "http.received-bytes-count";
-    field public static final java.lang.String REQUEST_COUNT = "http.request-count";
-    field public static final java.lang.String RESPONSE_COUNT = "http.response-count";
-    field public static final java.lang.String SENT_BYTES_COUNT = "http.sent-bytes-count";
-  }
-
-  public deprecated class NoConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy {
-    ctor public NoConnectionReuseStrategy();
-    method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class SocketHttpClientConnection extends org.apache.http.impl.AbstractHttpClientConnection implements org.apache.http.HttpInetConnection {
-    ctor public SocketHttpClientConnection();
-    method protected void assertNotOpen();
-    method protected void assertOpen();
-    method protected void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method protected org.apache.http.io.SessionInputBuffer createSessionInputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected org.apache.http.io.SessionOutputBuffer createSessionOutputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method protected java.net.Socket getSocket();
-    method public int getSocketTimeout();
-    method public boolean isOpen();
-    method public void setSocketTimeout(int);
-    method public void shutdown() throws java.io.IOException;
-  }
-
-  public deprecated class SocketHttpServerConnection extends org.apache.http.impl.AbstractHttpServerConnection implements org.apache.http.HttpInetConnection {
-    ctor public SocketHttpServerConnection();
-    method protected void assertNotOpen();
-    method protected void assertOpen();
-    method protected void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method protected org.apache.http.io.SessionInputBuffer createHttpDataReceiver(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected org.apache.http.io.SessionOutputBuffer createHttpDataTransmitter(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method protected java.net.Socket getSocket();
-    method public int getSocketTimeout();
-    method public boolean isOpen();
-    method public void setSocketTimeout(int);
-    method public void shutdown() throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.impl.auth {
-
-  public abstract deprecated class AuthSchemeBase implements org.apache.http.auth.AuthScheme {
-    ctor public AuthSchemeBase();
-    method public boolean isProxy();
-    method protected abstract void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-    method public void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public deprecated class BasicScheme extends org.apache.http.impl.auth.RFC2617Scheme {
-    ctor public BasicScheme();
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public static org.apache.http.Header authenticate(org.apache.http.auth.Credentials, java.lang.String, boolean);
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-  }
-
-  public deprecated class BasicSchemeFactory implements org.apache.http.auth.AuthSchemeFactory {
-    ctor public BasicSchemeFactory();
-    method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class DigestScheme extends org.apache.http.impl.auth.RFC2617Scheme {
-    ctor public DigestScheme();
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public static java.lang.String createCnonce();
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-    method public void overrideParamter(java.lang.String, java.lang.String);
-  }
-
-  public deprecated class DigestSchemeFactory implements org.apache.http.auth.AuthSchemeFactory {
-    ctor public DigestSchemeFactory();
-    method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated interface NTLMEngine {
-    method public abstract java.lang.String generateType1Msg(java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException;
-    method public abstract java.lang.String generateType3Msg(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException;
-  }
-
-  public deprecated class NTLMEngineException extends org.apache.http.auth.AuthenticationException {
-    ctor public NTLMEngineException();
-    ctor public NTLMEngineException(java.lang.String);
-    ctor public NTLMEngineException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class NTLMScheme extends org.apache.http.impl.auth.AuthSchemeBase {
-    ctor public NTLMScheme(org.apache.http.impl.auth.NTLMEngine);
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public java.lang.String getParameter(java.lang.String);
-    method public java.lang.String getRealm();
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-    method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public abstract deprecated class RFC2617Scheme extends org.apache.http.impl.auth.AuthSchemeBase {
-    ctor public RFC2617Scheme();
-    method public java.lang.String getParameter(java.lang.String);
-    method protected java.util.Map<java.lang.String, java.lang.String> getParameters();
-    method public java.lang.String getRealm();
-    method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public deprecated class UnsupportedDigestAlgorithmException extends java.lang.RuntimeException {
-    ctor public UnsupportedDigestAlgorithmException();
-    ctor public UnsupportedDigestAlgorithmException(java.lang.String);
-    ctor public UnsupportedDigestAlgorithmException(java.lang.String, java.lang.Throwable);
-  }
-
-}
-
-package org.apache.http.impl.client {
-
-  public abstract deprecated class AbstractAuthenticationHandler implements org.apache.http.client.AuthenticationHandler {
-    ctor public AbstractAuthenticationHandler();
-    method protected java.util.List<java.lang.String> getAuthPreferences();
-    method protected java.util.Map<java.lang.String, org.apache.http.Header> parseChallenges(org.apache.http.Header[]) throws org.apache.http.auth.MalformedChallengeException;
-    method public org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException;
-  }
-
-  public abstract deprecated class AbstractHttpClient implements org.apache.http.client.HttpClient {
-    ctor protected AbstractHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams);
-    method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public synchronized void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public synchronized void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public synchronized void clearRequestInterceptors();
-    method public synchronized void clearResponseInterceptors();
-    method protected abstract org.apache.http.auth.AuthSchemeRegistry createAuthSchemeRegistry();
-    method protected abstract org.apache.http.conn.ClientConnectionManager createClientConnectionManager();
-    method protected org.apache.http.client.RequestDirector createClientRequestDirector(org.apache.http.protocol.HttpRequestExecutor, org.apache.http.conn.ClientConnectionManager, org.apache.http.ConnectionReuseStrategy, org.apache.http.conn.ConnectionKeepAliveStrategy, org.apache.http.conn.routing.HttpRoutePlanner, org.apache.http.protocol.HttpProcessor, org.apache.http.client.HttpRequestRetryHandler, org.apache.http.client.RedirectHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.UserTokenHandler, org.apache.http.params.HttpParams);
-    method protected abstract org.apache.http.conn.ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
-    method protected abstract org.apache.http.ConnectionReuseStrategy createConnectionReuseStrategy();
-    method protected abstract org.apache.http.cookie.CookieSpecRegistry createCookieSpecRegistry();
-    method protected abstract org.apache.http.client.CookieStore createCookieStore();
-    method protected abstract org.apache.http.client.CredentialsProvider createCredentialsProvider();
-    method protected abstract org.apache.http.protocol.HttpContext createHttpContext();
-    method protected abstract org.apache.http.params.HttpParams createHttpParams();
-    method protected abstract org.apache.http.protocol.BasicHttpProcessor createHttpProcessor();
-    method protected abstract org.apache.http.client.HttpRequestRetryHandler createHttpRequestRetryHandler();
-    method protected abstract org.apache.http.conn.routing.HttpRoutePlanner createHttpRoutePlanner();
-    method protected abstract org.apache.http.client.AuthenticationHandler createProxyAuthenticationHandler();
-    method protected abstract org.apache.http.client.RedirectHandler createRedirectHandler();
-    method protected abstract org.apache.http.protocol.HttpRequestExecutor createRequestExecutor();
-    method protected abstract org.apache.http.client.AuthenticationHandler createTargetAuthenticationHandler();
-    method protected abstract org.apache.http.client.UserTokenHandler createUserTokenHandler();
-    method protected org.apache.http.params.HttpParams determineParams(org.apache.http.HttpRequest);
-    method public final org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final synchronized org.apache.http.auth.AuthSchemeRegistry getAuthSchemes();
-    method public final synchronized org.apache.http.conn.ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy();
-    method public final synchronized org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public final synchronized org.apache.http.ConnectionReuseStrategy getConnectionReuseStrategy();
-    method public final synchronized org.apache.http.cookie.CookieSpecRegistry getCookieSpecs();
-    method public final synchronized org.apache.http.client.CookieStore getCookieStore();
-    method public final synchronized org.apache.http.client.CredentialsProvider getCredentialsProvider();
-    method protected final synchronized org.apache.http.protocol.BasicHttpProcessor getHttpProcessor();
-    method public final synchronized org.apache.http.client.HttpRequestRetryHandler getHttpRequestRetryHandler();
-    method public final synchronized org.apache.http.params.HttpParams getParams();
-    method public final synchronized org.apache.http.client.AuthenticationHandler getProxyAuthenticationHandler();
-    method public final synchronized org.apache.http.client.RedirectHandler getRedirectHandler();
-    method public final synchronized org.apache.http.protocol.HttpRequestExecutor getRequestExecutor();
-    method public synchronized org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public synchronized int getRequestInterceptorCount();
-    method public synchronized org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public synchronized int getResponseInterceptorCount();
-    method public final synchronized org.apache.http.conn.routing.HttpRoutePlanner getRoutePlanner();
-    method public final synchronized org.apache.http.client.AuthenticationHandler getTargetAuthenticationHandler();
-    method public final synchronized org.apache.http.client.UserTokenHandler getUserTokenHandler();
-    method public void removeRequestInterceptorByClass(java.lang.Class<? extends org.apache.http.HttpRequestInterceptor>);
-    method public void removeResponseInterceptorByClass(java.lang.Class<? extends org.apache.http.HttpResponseInterceptor>);
-    method public synchronized void setAuthSchemes(org.apache.http.auth.AuthSchemeRegistry);
-    method public synchronized void setCookieSpecs(org.apache.http.cookie.CookieSpecRegistry);
-    method public synchronized void setCookieStore(org.apache.http.client.CookieStore);
-    method public synchronized void setCredentialsProvider(org.apache.http.client.CredentialsProvider);
-    method public synchronized void setHttpRequestRetryHandler(org.apache.http.client.HttpRequestRetryHandler);
-    method public synchronized void setKeepAliveStrategy(org.apache.http.conn.ConnectionKeepAliveStrategy);
-    method public synchronized void setParams(org.apache.http.params.HttpParams);
-    method public synchronized void setProxyAuthenticationHandler(org.apache.http.client.AuthenticationHandler);
-    method public synchronized void setRedirectHandler(org.apache.http.client.RedirectHandler);
-    method public synchronized void setReuseStrategy(org.apache.http.ConnectionReuseStrategy);
-    method public synchronized void setRoutePlanner(org.apache.http.conn.routing.HttpRoutePlanner);
-    method public synchronized void setTargetAuthenticationHandler(org.apache.http.client.AuthenticationHandler);
-    method public synchronized void setUserTokenHandler(org.apache.http.client.UserTokenHandler);
-  }
-
-  public deprecated class BasicCookieStore implements org.apache.http.client.CookieStore {
-    ctor public BasicCookieStore();
-    method public synchronized void addCookie(org.apache.http.cookie.Cookie);
-    method public synchronized void addCookies(org.apache.http.cookie.Cookie[]);
-    method public synchronized void clear();
-    method public synchronized boolean clearExpired(java.util.Date);
-    method public synchronized java.util.List<org.apache.http.cookie.Cookie> getCookies();
-  }
-
-  public deprecated class BasicCredentialsProvider implements org.apache.http.client.CredentialsProvider {
-    ctor public BasicCredentialsProvider();
-    method public synchronized void clear();
-    method public synchronized org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope);
-    method public synchronized void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials);
-  }
-
-  public deprecated class BasicResponseHandler implements org.apache.http.client.ResponseHandler {
-    ctor public BasicResponseHandler();
-    method public java.lang.String handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.HttpResponseException, java.io.IOException;
-  }
-
-  public deprecated class ClientParamsStack extends org.apache.http.params.AbstractHttpParams {
-    ctor public ClientParamsStack(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack);
-    ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    method public org.apache.http.params.HttpParams copy();
-    method public final org.apache.http.params.HttpParams getApplicationParams();
-    method public final org.apache.http.params.HttpParams getClientParams();
-    method public final org.apache.http.params.HttpParams getOverrideParams();
-    method public java.lang.Object getParameter(java.lang.String);
-    method public final org.apache.http.params.HttpParams getRequestParams();
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object) throws java.lang.UnsupportedOperationException;
-    field protected final org.apache.http.params.HttpParams applicationParams;
-    field protected final org.apache.http.params.HttpParams clientParams;
-    field protected final org.apache.http.params.HttpParams overrideParams;
-    field protected final org.apache.http.params.HttpParams requestParams;
-  }
-
-  public deprecated class DefaultConnectionKeepAliveStrategy implements org.apache.http.conn.ConnectionKeepAliveStrategy {
-    ctor public DefaultConnectionKeepAliveStrategy();
-    method public long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultHttpClient extends org.apache.http.impl.client.AbstractHttpClient {
-    ctor public DefaultHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams);
-    ctor public DefaultHttpClient(org.apache.http.params.HttpParams);
-    ctor public DefaultHttpClient();
-    method protected org.apache.http.auth.AuthSchemeRegistry createAuthSchemeRegistry();
-    method protected org.apache.http.conn.ClientConnectionManager createClientConnectionManager();
-    method protected org.apache.http.conn.ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
-    method protected org.apache.http.ConnectionReuseStrategy createConnectionReuseStrategy();
-    method protected org.apache.http.cookie.CookieSpecRegistry createCookieSpecRegistry();
-    method protected org.apache.http.client.CookieStore createCookieStore();
-    method protected org.apache.http.client.CredentialsProvider createCredentialsProvider();
-    method protected org.apache.http.protocol.HttpContext createHttpContext();
-    method protected org.apache.http.params.HttpParams createHttpParams();
-    method protected org.apache.http.protocol.BasicHttpProcessor createHttpProcessor();
-    method protected org.apache.http.client.HttpRequestRetryHandler createHttpRequestRetryHandler();
-    method protected org.apache.http.conn.routing.HttpRoutePlanner createHttpRoutePlanner();
-    method protected org.apache.http.client.AuthenticationHandler createProxyAuthenticationHandler();
-    method protected org.apache.http.client.RedirectHandler createRedirectHandler();
-    method protected org.apache.http.protocol.HttpRequestExecutor createRequestExecutor();
-    method protected org.apache.http.client.AuthenticationHandler createTargetAuthenticationHandler();
-    method protected org.apache.http.client.UserTokenHandler createUserTokenHandler();
-  }
-
-  public deprecated class DefaultHttpRequestRetryHandler implements org.apache.http.client.HttpRequestRetryHandler {
-    ctor public DefaultHttpRequestRetryHandler(int, boolean);
-    ctor public DefaultHttpRequestRetryHandler();
-    method public int getRetryCount();
-    method public boolean isRequestSentRetryEnabled();
-    method public boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultProxyAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler {
-    ctor public DefaultProxyAuthenticationHandler();
-    method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultRedirectHandler implements org.apache.http.client.RedirectHandler {
-    ctor public DefaultRedirectHandler();
-    method public java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException;
-    method public boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultRequestDirector implements org.apache.http.client.RequestDirector {
-    ctor public DefaultRequestDirector(org.apache.http.protocol.HttpRequestExecutor, org.apache.http.conn.ClientConnectionManager, org.apache.http.ConnectionReuseStrategy, org.apache.http.conn.ConnectionKeepAliveStrategy, org.apache.http.conn.routing.HttpRoutePlanner, org.apache.http.protocol.HttpProcessor, org.apache.http.client.HttpRequestRetryHandler, org.apache.http.client.RedirectHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.UserTokenHandler, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpRequest createConnectRequest(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext);
-    method protected boolean createTunnelToProxy(org.apache.http.conn.routing.HttpRoute, int, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected boolean createTunnelToTarget(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method protected void establishRoute(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.impl.client.RoutedRequest handleResponse(org.apache.http.impl.client.RoutedRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected void releaseConnection();
-    method protected void rewriteRequestURI(org.apache.http.impl.client.RequestWrapper, org.apache.http.conn.routing.HttpRoute) throws org.apache.http.ProtocolException;
-    field protected final org.apache.http.conn.ClientConnectionManager connManager;
-    field protected final org.apache.http.protocol.HttpProcessor httpProcessor;
-    field protected final org.apache.http.conn.ConnectionKeepAliveStrategy keepAliveStrategy;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-    field protected final org.apache.http.params.HttpParams params;
-    field protected final org.apache.http.client.RedirectHandler redirectHandler;
-    field protected final org.apache.http.protocol.HttpRequestExecutor requestExec;
-    field protected final org.apache.http.client.HttpRequestRetryHandler retryHandler;
-    field protected final org.apache.http.ConnectionReuseStrategy reuseStrategy;
-    field protected final org.apache.http.conn.routing.HttpRoutePlanner routePlanner;
-  }
-
-  public deprecated class DefaultTargetAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler {
-    ctor public DefaultTargetAuthenticationHandler();
-    method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultUserTokenHandler implements org.apache.http.client.UserTokenHandler {
-    ctor public DefaultUserTokenHandler();
-    method public java.lang.Object getUserToken(org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class EntityEnclosingRequestWrapper extends org.apache.http.impl.client.RequestWrapper implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public EntityEnclosingRequestWrapper(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.ProtocolException;
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class RedirectLocations {
-    ctor public RedirectLocations();
-    method public void add(java.net.URI);
-    method public boolean contains(java.net.URI);
-    method public boolean remove(java.net.URI);
-  }
-
-  public deprecated class RequestWrapper extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.HttpUriRequest {
-    ctor public RequestWrapper(org.apache.http.HttpRequest) throws org.apache.http.ProtocolException;
-    method public void abort() throws java.lang.UnsupportedOperationException;
-    method public int getExecCount();
-    method public java.lang.String getMethod();
-    method public org.apache.http.HttpRequest getOriginal();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-    method public java.net.URI getURI();
-    method public void incrementExecCount();
-    method public boolean isAborted();
-    method public boolean isRepeatable();
-    method public void resetHeaders();
-    method public void setMethod(java.lang.String);
-    method public void setProtocolVersion(org.apache.http.ProtocolVersion);
-    method public void setURI(java.net.URI);
-  }
-
-  public deprecated class RoutedRequest {
-    ctor public RoutedRequest(org.apache.http.impl.client.RequestWrapper, org.apache.http.conn.routing.HttpRoute);
-    method public final org.apache.http.impl.client.RequestWrapper getRequest();
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-    field protected final org.apache.http.impl.client.RequestWrapper request;
-    field protected final org.apache.http.conn.routing.HttpRoute route;
-  }
-
-  public deprecated class TunnelRefusedException extends org.apache.http.HttpException {
-    ctor public TunnelRefusedException(java.lang.String, org.apache.http.HttpResponse);
-    method public org.apache.http.HttpResponse getResponse();
-  }
-
-}
-
-package org.apache.http.impl.conn {
-
-  public abstract deprecated class AbstractClientConnAdapter implements org.apache.http.conn.ManagedClientConnection {
-    ctor protected AbstractClientConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.conn.OperatedClientConnection);
-    method public void abortConnection();
-    method protected final void assertNotAborted() throws java.io.InterruptedIOException;
-    method protected final void assertValid(org.apache.http.conn.OperatedClientConnection);
-    method protected void detach();
-    method public void flush() throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method protected org.apache.http.conn.ClientConnectionManager getManager();
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method public javax.net.ssl.SSLSession getSSLSession();
-    method public int getSocketTimeout();
-    method protected org.apache.http.conn.OperatedClientConnection getWrappedConnection();
-    method public boolean isMarkedReusable();
-    method public boolean isOpen();
-    method public boolean isResponseAvailable(int) throws java.io.IOException;
-    method public boolean isSecure();
-    method public boolean isStale();
-    method public void markReusable();
-    method public void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void releaseConnection();
-    method public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void setIdleDuration(long, java.util.concurrent.TimeUnit);
-    method public void setSocketTimeout(int);
-    method public void unmarkReusable();
-  }
-
-  public abstract deprecated class AbstractPoolEntry {
-    ctor protected AbstractPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute);
-    method public java.lang.Object getState();
-    method public void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void setState(java.lang.Object);
-    method protected void shutdownEntry();
-    method public void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected final org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected final org.apache.http.conn.OperatedClientConnection connection;
-    field protected volatile org.apache.http.conn.routing.HttpRoute route;
-    field protected volatile java.lang.Object state;
-    field protected volatile org.apache.http.conn.routing.RouteTracker tracker;
-  }
-
-  public abstract deprecated class AbstractPooledConnAdapter extends org.apache.http.impl.conn.AbstractClientConnAdapter {
-    ctor protected AbstractPooledConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.impl.conn.AbstractPoolEntry);
-    method protected final void assertAttached();
-    method public void close() throws java.io.IOException;
-    method public org.apache.http.conn.routing.HttpRoute getRoute();
-    method public java.lang.Object getState();
-    method public void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void setState(java.lang.Object);
-    method public void shutdown() throws java.io.IOException;
-    method public void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected volatile org.apache.http.impl.conn.AbstractPoolEntry poolEntry;
-  }
-
-  public deprecated class DefaultClientConnection extends org.apache.http.impl.SocketHttpClientConnection implements org.apache.http.conn.OperatedClientConnection {
-    ctor public DefaultClientConnection();
-    method public final java.net.Socket getSocket();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final boolean isSecure();
-    method public void openCompleted(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void opening(java.net.Socket, org.apache.http.HttpHost) throws java.io.IOException;
-    method public void update(java.net.Socket, org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class DefaultClientConnectionOperator implements org.apache.http.conn.ClientConnectionOperator {
-    ctor public DefaultClientConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.OperatedClientConnection createConnection();
-    method public void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected void prepareSocket(java.net.Socket, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void updateSecureConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class DefaultHttpRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner {
-    ctor public DefaultHttpRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class DefaultResponseParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public DefaultResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class IdleConnectionHandler {
-    ctor public IdleConnectionHandler();
-    method public void add(org.apache.http.HttpConnection, long, java.util.concurrent.TimeUnit);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long);
-    method public boolean remove(org.apache.http.HttpConnection);
-    method public void removeAll();
-  }
-
-  public deprecated class LoggingSessionInputBuffer implements org.apache.http.io.SessionInputBuffer {
-    ctor public LoggingSessionInputBuffer(org.apache.http.io.SessionInputBuffer, org.apache.http.impl.conn.Wire);
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public boolean isDataAvailable(int) throws java.io.IOException;
-    method public int read(byte[], int, int) throws java.io.IOException;
-    method public int read() throws java.io.IOException;
-    method public int read(byte[]) throws java.io.IOException;
-    method public java.lang.String readLine() throws java.io.IOException;
-    method public int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-  public deprecated class LoggingSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer {
-    ctor public LoggingSessionOutputBuffer(org.apache.http.io.SessionOutputBuffer, org.apache.http.impl.conn.Wire);
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public void write(byte[], int, int) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method public void write(byte[]) throws java.io.IOException;
-    method public void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public void writeLine(java.lang.String) throws java.io.IOException;
-  }
-
-  public deprecated class ProxySelectorRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner {
-    ctor public ProxySelectorRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry, java.net.ProxySelector);
-    method protected java.net.Proxy chooseProxy(java.util.List<java.net.Proxy>, org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext);
-    method protected org.apache.http.HttpHost determineProxy(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method public org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method protected java.lang.String getHost(java.net.InetSocketAddress);
-    method public java.net.ProxySelector getProxySelector();
-    method public void setProxySelector(java.net.ProxySelector);
-    field protected java.net.ProxySelector proxySelector;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class SingleClientConnManager implements org.apache.http.conn.ClientConnectionManager {
-    ctor public SingleClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-    method protected final void assertStillUp() throws java.lang.IllegalStateException;
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method protected org.apache.http.conn.ClientConnectionOperator createConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.ManagedClientConnection getConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public final org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method protected void revokeConnection();
-    method public void shutdown();
-    field public static final java.lang.String MISUSE_MESSAGE = "Invalid use of SingleClientConnManager: connection still allocated.\nMake sure to release the connection before allocating another one.";
-    field protected boolean alwaysShutDown;
-    field protected org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected long connectionExpiresTime;
-    field protected volatile boolean isShutDown;
-    field protected long lastReleaseTime;
-    field protected org.apache.http.impl.conn.SingleClientConnManager.ConnAdapter managedConn;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-    field protected org.apache.http.impl.conn.SingleClientConnManager.PoolEntry uniquePoolEntry;
-  }
-
-  protected class SingleClientConnManager.ConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter {
-    ctor protected SingleClientConnManager.ConnAdapter(org.apache.http.impl.conn.SingleClientConnManager.PoolEntry, org.apache.http.conn.routing.HttpRoute);
-  }
-
-  protected class SingleClientConnManager.PoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry {
-    ctor protected SingleClientConnManager.PoolEntry();
-    method protected void close() throws java.io.IOException;
-    method protected void shutdown() throws java.io.IOException;
-  }
-
-  public deprecated class Wire {
-    ctor public Wire(org.apache.commons.logging.Log);
-    method public boolean enabled();
-    method public void input(java.io.InputStream) throws java.io.IOException;
-    method public void input(byte[], int, int) throws java.io.IOException;
-    method public void input(byte[]) throws java.io.IOException;
-    method public void input(int) throws java.io.IOException;
-    method public void input(java.lang.String) throws java.io.IOException;
-    method public void output(java.io.InputStream) throws java.io.IOException;
-    method public void output(byte[], int, int) throws java.io.IOException;
-    method public void output(byte[]) throws java.io.IOException;
-    method public void output(int) throws java.io.IOException;
-    method public void output(java.lang.String) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.impl.conn.tsccm {
-
-  public abstract deprecated class AbstractConnPool implements org.apache.http.impl.conn.tsccm.RefQueueHandler {
-    ctor protected AbstractConnPool();
-    method protected void closeConnection(org.apache.http.conn.OperatedClientConnection);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method public abstract void deleteClosedConnections();
-    method public void enableConnectionGC() throws java.lang.IllegalStateException;
-    method public abstract void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry, boolean, long, java.util.concurrent.TimeUnit);
-    method public final org.apache.http.impl.conn.tsccm.BasicPoolEntry getEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object, long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-    method protected abstract void handleLostEntry(org.apache.http.conn.routing.HttpRoute);
-    method public void handleReference(java.lang.ref.Reference);
-    method public abstract org.apache.http.impl.conn.tsccm.PoolEntryRequest requestPoolEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public void shutdown();
-    field protected org.apache.http.impl.conn.IdleConnectionHandler idleConnHandler;
-    field protected volatile boolean isShutDown;
-    field protected java.util.Set<org.apache.http.impl.conn.tsccm.BasicPoolEntryRef> issuedConnections;
-    field protected int numConnections;
-    field protected final java.util.concurrent.locks.Lock poolLock;
-    field protected java.lang.ref.ReferenceQueue<java.lang.Object> refQueue;
-  }
-
-  public deprecated class BasicPoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry {
-    ctor public BasicPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute, java.lang.ref.ReferenceQueue<java.lang.Object>);
-    method protected final org.apache.http.conn.OperatedClientConnection getConnection();
-    method protected final org.apache.http.conn.routing.HttpRoute getPlannedRoute();
-    method protected final org.apache.http.impl.conn.tsccm.BasicPoolEntryRef getWeakRef();
-  }
-
-  public deprecated class BasicPoolEntryRef extends java.lang.ref.WeakReference {
-    ctor public BasicPoolEntryRef(org.apache.http.impl.conn.tsccm.BasicPoolEntry, java.lang.ref.ReferenceQueue<java.lang.Object>);
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-  }
-
-  public deprecated class BasicPooledConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter {
-    ctor protected BasicPooledConnAdapter(org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager, org.apache.http.impl.conn.AbstractPoolEntry);
-    method protected org.apache.http.impl.conn.AbstractPoolEntry getPoolEntry();
-  }
-
-  public deprecated class ConnPoolByRoute extends org.apache.http.impl.conn.tsccm.AbstractConnPool {
-    ctor public ConnPoolByRoute(org.apache.http.conn.ClientConnectionOperator, org.apache.http.params.HttpParams);
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry createEntry(org.apache.http.impl.conn.tsccm.RouteSpecificPool, org.apache.http.conn.ClientConnectionOperator);
-    method protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> createFreeConnQueue();
-    method protected java.util.Map<org.apache.http.conn.routing.HttpRoute, org.apache.http.impl.conn.tsccm.RouteSpecificPool> createRouteToPoolMap();
-    method protected java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> createWaitingThreadQueue();
-    method public void deleteClosedConnections();
-    method protected void deleteEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method protected void deleteLeastUsedEntry();
-    method public void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry, boolean, long, java.util.concurrent.TimeUnit);
-    method public int getConnectionsInPool(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry getEntryBlocking(org.apache.http.conn.routing.HttpRoute, java.lang.Object, long, java.util.concurrent.TimeUnit, org.apache.http.impl.conn.tsccm.WaitingThreadAborter) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry getFreeEntry(org.apache.http.impl.conn.tsccm.RouteSpecificPool, java.lang.Object);
-    method protected org.apache.http.impl.conn.tsccm.RouteSpecificPool getRoutePool(org.apache.http.conn.routing.HttpRoute, boolean);
-    method protected void handleLostEntry(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.RouteSpecificPool newRouteSpecificPool(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.WaitingThread newWaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method protected void notifyWaitingThread(org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method public org.apache.http.impl.conn.tsccm.PoolEntryRequest requestPoolEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    field protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeConnections;
-    field protected final int maxTotalConnections;
-    field protected final org.apache.http.conn.ClientConnectionOperator operator;
-    field protected final java.util.Map<org.apache.http.conn.routing.HttpRoute, org.apache.http.impl.conn.tsccm.RouteSpecificPool> routeToPool;
-    field protected java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads;
-  }
-
-  public abstract deprecated interface PoolEntryRequest {
-    method public abstract void abortRequest();
-    method public abstract org.apache.http.impl.conn.tsccm.BasicPoolEntry getPoolEntry(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-  }
-
-  public abstract deprecated interface RefQueueHandler {
-    method public abstract void handleReference(java.lang.ref.Reference<?>);
-  }
-
-  public deprecated class RefQueueWorker implements java.lang.Runnable {
-    ctor public RefQueueWorker(java.lang.ref.ReferenceQueue<?>, org.apache.http.impl.conn.tsccm.RefQueueHandler);
-    method public void run();
-    method public void shutdown();
-    field protected final org.apache.http.impl.conn.tsccm.RefQueueHandler refHandler;
-    field protected final java.lang.ref.ReferenceQueue<?> refQueue;
-    field protected volatile java.lang.Thread workerThread;
-  }
-
-  public deprecated class RouteSpecificPool {
-    ctor public RouteSpecificPool(org.apache.http.conn.routing.HttpRoute, int);
-    method public org.apache.http.impl.conn.tsccm.BasicPoolEntry allocEntry(java.lang.Object);
-    method public void createdEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public boolean deleteEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public void dropEntry();
-    method public void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public int getCapacity();
-    method public final int getEntryCount();
-    method public final int getMaxEntries();
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-    method public boolean hasThread();
-    method public boolean isUnused();
-    method public org.apache.http.impl.conn.tsccm.WaitingThread nextThread();
-    method public void queueThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-    method public void removeThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-    field protected final java.util.LinkedList<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeEntries;
-    field protected final int maxEntries;
-    field protected int numEntries;
-    field protected final org.apache.http.conn.routing.HttpRoute route;
-    field protected final java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads;
-  }
-
-  public deprecated class ThreadSafeClientConnManager implements org.apache.http.conn.ClientConnectionManager {
-    ctor public ThreadSafeClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method protected org.apache.http.conn.ClientConnectionOperator createConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method protected org.apache.http.impl.conn.tsccm.AbstractConnPool createConnectionPool(org.apache.http.params.HttpParams);
-    method public int getConnectionsInPool(org.apache.http.conn.routing.HttpRoute);
-    method public int getConnectionsInPool();
-    method public org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public void shutdown();
-    field protected org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected final org.apache.http.impl.conn.tsccm.AbstractConnPool connectionPool;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class WaitingThread {
-    ctor public WaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method public boolean await(java.util.Date) throws java.lang.InterruptedException;
-    method public final java.util.concurrent.locks.Condition getCondition();
-    method public final org.apache.http.impl.conn.tsccm.RouteSpecificPool getPool();
-    method public final java.lang.Thread getThread();
-    method public void interrupt();
-    method public void wakeup();
-  }
-
-  public deprecated class WaitingThreadAborter {
-    ctor public WaitingThreadAborter();
-    method public void abort();
-    method public void setWaitingThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-  }
-
-}
-
-package org.apache.http.impl.cookie {
-
-  public abstract deprecated class AbstractCookieAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public AbstractCookieAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public abstract deprecated class AbstractCookieSpec implements org.apache.http.cookie.CookieSpec {
-    ctor public AbstractCookieSpec();
-    method protected org.apache.http.cookie.CookieAttributeHandler findAttribHandler(java.lang.String);
-    method protected org.apache.http.cookie.CookieAttributeHandler getAttribHandler(java.lang.String);
-    method protected java.util.Collection<org.apache.http.cookie.CookieAttributeHandler> getAttribHandlers();
-    method public void registerAttribHandler(java.lang.String, org.apache.http.cookie.CookieAttributeHandler);
-  }
-
-  public deprecated class BasicClientCookie implements org.apache.http.cookie.ClientCookie java.lang.Cloneable org.apache.http.cookie.SetCookie {
-    ctor public BasicClientCookie(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public boolean containsAttribute(java.lang.String);
-    method public java.lang.String getAttribute(java.lang.String);
-    method public java.lang.String getComment();
-    method public java.lang.String getCommentURL();
-    method public java.lang.String getDomain();
-    method public java.util.Date getExpiryDate();
-    method public java.lang.String getName();
-    method public java.lang.String getPath();
-    method public int[] getPorts();
-    method public java.lang.String getValue();
-    method public int getVersion();
-    method public boolean isExpired(java.util.Date);
-    method public boolean isPersistent();
-    method public boolean isSecure();
-    method public void setAttribute(java.lang.String, java.lang.String);
-    method public void setComment(java.lang.String);
-    method public void setDomain(java.lang.String);
-    method public void setExpiryDate(java.util.Date);
-    method public void setPath(java.lang.String);
-    method public void setSecure(boolean);
-    method public void setValue(java.lang.String);
-    method public void setVersion(int);
-  }
-
-  public deprecated class BasicClientCookie2 extends org.apache.http.impl.cookie.BasicClientCookie implements org.apache.http.cookie.SetCookie2 {
-    ctor public BasicClientCookie2(java.lang.String, java.lang.String);
-    method public void setCommentURL(java.lang.String);
-    method public void setDiscard(boolean);
-    method public void setPorts(int[]);
-  }
-
-  public deprecated class BasicCommentHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicCommentHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicDomainHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public BasicDomainHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicExpiresHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicExpiresHandler(java.lang.String[]);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicMaxAgeHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicMaxAgeHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicPathHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public BasicPathHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicSecureHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicSecureHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BestMatchSpec implements org.apache.http.cookie.CookieSpec {
-    ctor public BestMatchSpec(java.lang.String[], boolean);
-    ctor public BestMatchSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BestMatchSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public BestMatchSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class BrowserCompatSpec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public BrowserCompatSpec(java.lang.String[]);
-    ctor public BrowserCompatSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    field protected static final java.lang.String[] DATE_PATTERNS;
-  }
-
-  public deprecated class BrowserCompatSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public BrowserCompatSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated class CookieSpecBase extends org.apache.http.impl.cookie.AbstractCookieSpec {
-    ctor public CookieSpecBase();
-    method protected static java.lang.String getDefaultDomain(org.apache.http.cookie.CookieOrigin);
-    method protected static java.lang.String getDefaultPath(org.apache.http.cookie.CookieOrigin);
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method protected java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.HeaderElement[], org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class DateParseException extends java.lang.Exception {
-    ctor public DateParseException();
-    ctor public DateParseException(java.lang.String);
-  }
-
-  public final deprecated class DateUtils {
-    method public static java.lang.String formatDate(java.util.Date);
-    method public static java.lang.String formatDate(java.util.Date, java.lang.String);
-    method public static java.util.Date parseDate(java.lang.String) throws org.apache.http.impl.cookie.DateParseException;
-    method public static java.util.Date parseDate(java.lang.String, java.lang.String[]) throws org.apache.http.impl.cookie.DateParseException;
-    method public static java.util.Date parseDate(java.lang.String, java.lang.String[], java.util.Date) throws org.apache.http.impl.cookie.DateParseException;
-    field public static final java.util.TimeZone GMT;
-    field public static final java.lang.String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
-    field public static final java.lang.String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
-    field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
-  }
-
-  public deprecated class NetscapeDomainHandler extends org.apache.http.impl.cookie.BasicDomainHandler {
-    ctor public NetscapeDomainHandler();
-  }
-
-  public deprecated class NetscapeDraftHeaderParser {
-    ctor public NetscapeDraftHeaderParser();
-    method public org.apache.http.HeaderElement parseHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    field public static final org.apache.http.impl.cookie.NetscapeDraftHeaderParser DEFAULT;
-  }
-
-  public deprecated class NetscapeDraftSpec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public NetscapeDraftSpec(java.lang.String[]);
-    ctor public NetscapeDraftSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    field protected static final java.lang.String EXPIRES_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
-  }
-
-  public deprecated class NetscapeDraftSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public NetscapeDraftSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2109DomainHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2109DomainHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2109Spec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public RFC2109Spec(java.lang.String[], boolean);
-    ctor public RFC2109Spec();
-    method protected void formatCookieAsVer(org.apache.http.util.CharArrayBuffer, org.apache.http.cookie.Cookie, int);
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method protected void formatParamAsVer(org.apache.http.util.CharArrayBuffer, java.lang.String, java.lang.String, int);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2109SpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public RFC2109SpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2109VersionHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public RFC2109VersionHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965CommentUrlAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965CommentUrlAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965DiscardAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965DiscardAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965DomainAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965DomainAttributeHandler();
-    method public boolean domainMatch(java.lang.String, java.lang.String);
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965PortAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965PortAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965Spec extends org.apache.http.impl.cookie.RFC2109Spec {
-    ctor public RFC2965Spec();
-    ctor public RFC2965Spec(java.lang.String[], boolean);
-  }
-
-  public deprecated class RFC2965SpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public RFC2965SpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2965VersionAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965VersionAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-}
-
-package org.apache.http.impl.entity {
-
-  public deprecated class EntityDeserializer {
-    ctor public EntityDeserializer(org.apache.http.entity.ContentLengthStrategy);
-    method public org.apache.http.HttpEntity deserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.entity.BasicHttpEntity doDeserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class EntitySerializer {
-    ctor public EntitySerializer(org.apache.http.entity.ContentLengthStrategy);
-    method protected java.io.OutputStream doSerialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method public void serialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage, org.apache.http.HttpEntity) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class LaxContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy {
-    ctor public LaxContentLengthStrategy();
-    method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-  }
-
-  public deprecated class StrictContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy {
-    ctor public StrictContentLengthStrategy();
-    method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-  }
-
-}
-
-package org.apache.http.impl.io {
-
-  public abstract deprecated class AbstractMessageParser implements org.apache.http.io.HttpMessageParser {
-    ctor public AbstractMessageParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.params.HttpParams);
-    method public org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException;
-    method protected abstract org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-    method public static org.apache.http.Header[] parseHeaders(org.apache.http.io.SessionInputBuffer, int, int, org.apache.http.message.LineParser) throws org.apache.http.HttpException, java.io.IOException;
-    field protected final org.apache.http.message.LineParser lineParser;
-  }
-
-  public abstract deprecated class AbstractMessageWriter implements org.apache.http.io.HttpMessageWriter {
-    ctor public AbstractMessageWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method public void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method protected abstract void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-    field protected final org.apache.http.util.CharArrayBuffer lineBuf;
-    field protected final org.apache.http.message.LineFormatter lineFormatter;
-    field protected final org.apache.http.io.SessionOutputBuffer sessionBuffer;
-  }
-
-  public abstract deprecated class AbstractSessionInputBuffer implements org.apache.http.io.SessionInputBuffer {
-    ctor public AbstractSessionInputBuffer();
-    method protected int fillBuffer() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method protected boolean hasBufferedData();
-    method protected void init(java.io.InputStream, int, org.apache.http.params.HttpParams);
-    method public int read() throws java.io.IOException;
-    method public int read(byte[], int, int) throws java.io.IOException;
-    method public int read(byte[]) throws java.io.IOException;
-    method public int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public java.lang.String readLine() throws java.io.IOException;
-  }
-
-  public abstract deprecated class AbstractSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer {
-    ctor public AbstractSessionOutputBuffer();
-    method public void flush() throws java.io.IOException;
-    method protected void flushBuffer() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method protected void init(java.io.OutputStream, int, org.apache.http.params.HttpParams);
-    method public void write(byte[], int, int) throws java.io.IOException;
-    method public void write(byte[]) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method public void writeLine(java.lang.String) throws java.io.IOException;
-    method public void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-  public deprecated class ChunkedInputStream extends java.io.InputStream {
-    ctor public ChunkedInputStream(org.apache.http.io.SessionInputBuffer);
-    method public org.apache.http.Header[] getFooters();
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class ChunkedOutputStream extends java.io.OutputStream {
-    ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer, int) throws java.io.IOException;
-    ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer) throws java.io.IOException;
-    method public void finish() throws java.io.IOException;
-    method protected void flushCache() throws java.io.IOException;
-    method protected void flushCacheWithAppend(byte[], int, int) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method protected void writeClosingChunk() throws java.io.IOException;
-  }
-
-  public deprecated class ContentLengthInputStream extends java.io.InputStream {
-    ctor public ContentLengthInputStream(org.apache.http.io.SessionInputBuffer, long);
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class ContentLengthOutputStream extends java.io.OutputStream {
-    ctor public ContentLengthOutputStream(org.apache.http.io.SessionOutputBuffer, long);
-    method public void write(int) throws java.io.IOException;
-  }
-
-  public deprecated class HttpRequestParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public HttpRequestParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpRequestFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public deprecated class HttpRequestWriter extends org.apache.http.impl.io.AbstractMessageWriter {
-    ctor public HttpRequestWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-  }
-
-  public deprecated class HttpResponseParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public HttpResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public deprecated class HttpResponseWriter extends org.apache.http.impl.io.AbstractMessageWriter {
-    ctor public HttpResponseWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-  }
-
-  public deprecated class HttpTransportMetricsImpl implements org.apache.http.io.HttpTransportMetrics {
-    ctor public HttpTransportMetricsImpl();
-    method public long getBytesTransferred();
-    method public void incrementBytesTransferred(long);
-    method public void reset();
-    method public void setBytesTransferred(long);
-  }
-
-  public deprecated class IdentityInputStream extends java.io.InputStream {
-    ctor public IdentityInputStream(org.apache.http.io.SessionInputBuffer);
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class IdentityOutputStream extends java.io.OutputStream {
-    ctor public IdentityOutputStream(org.apache.http.io.SessionOutputBuffer);
-    method public void write(int) throws java.io.IOException;
-  }
-
-  public deprecated class SocketInputBuffer extends org.apache.http.impl.io.AbstractSessionInputBuffer {
-    ctor public SocketInputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public boolean isDataAvailable(int) throws java.io.IOException;
-  }
-
-  public deprecated class SocketOutputBuffer extends org.apache.http.impl.io.AbstractSessionOutputBuffer {
-    ctor public SocketOutputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.io {
-
-  public abstract deprecated interface HttpMessageParser {
-    method public abstract org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpMessageWriter {
-    method public abstract void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpTransportMetrics {
-    method public abstract long getBytesTransferred();
-    method public abstract void reset();
-  }
-
-  public abstract deprecated interface SessionInputBuffer {
-    method public abstract org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public abstract boolean isDataAvailable(int) throws java.io.IOException;
-    method public abstract int read(byte[], int, int) throws java.io.IOException;
-    method public abstract int read(byte[]) throws java.io.IOException;
-    method public abstract int read() throws java.io.IOException;
-    method public abstract int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public abstract java.lang.String readLine() throws java.io.IOException;
-  }
-
-  public abstract deprecated interface SessionOutputBuffer {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public abstract void write(byte[], int, int) throws java.io.IOException;
-    method public abstract void write(byte[]) throws java.io.IOException;
-    method public abstract void write(int) throws java.io.IOException;
-    method public abstract void writeLine(java.lang.String) throws java.io.IOException;
-    method public abstract void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.message {
-
-  public abstract deprecated class AbstractHttpMessage implements org.apache.http.HttpMessage {
-    ctor protected AbstractHttpMessage(org.apache.http.params.HttpParams);
-    ctor protected AbstractHttpMessage();
-    method public void addHeader(org.apache.http.Header);
-    method public void addHeader(java.lang.String, java.lang.String);
-    method public boolean containsHeader(java.lang.String);
-    method public org.apache.http.Header[] getAllHeaders();
-    method public org.apache.http.Header getFirstHeader(java.lang.String);
-    method public org.apache.http.Header[] getHeaders(java.lang.String);
-    method public org.apache.http.Header getLastHeader(java.lang.String);
-    method public org.apache.http.params.HttpParams getParams();
-    method public org.apache.http.HeaderIterator headerIterator();
-    method public org.apache.http.HeaderIterator headerIterator(java.lang.String);
-    method public void removeHeader(org.apache.http.Header);
-    method public void removeHeaders(java.lang.String);
-    method public void setHeader(org.apache.http.Header);
-    method public void setHeader(java.lang.String, java.lang.String);
-    method public void setHeaders(org.apache.http.Header[]);
-    method public void setParams(org.apache.http.params.HttpParams);
-    field protected org.apache.http.message.HeaderGroup headergroup;
-    field protected org.apache.http.params.HttpParams params;
-  }
-
-  public deprecated class BasicHeader implements java.lang.Cloneable org.apache.http.Header {
-    ctor public BasicHeader(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicHeaderElement implements java.lang.Cloneable org.apache.http.HeaderElement {
-    ctor public BasicHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]);
-    ctor public BasicHeaderElement(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getName();
-    method public org.apache.http.NameValuePair getParameter(int);
-    method public org.apache.http.NameValuePair getParameterByName(java.lang.String);
-    method public int getParameterCount();
-    method public org.apache.http.NameValuePair[] getParameters();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicHeaderElementIterator implements org.apache.http.HeaderElementIterator {
-    ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator, org.apache.http.message.HeaderValueParser);
-    ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.HeaderElement nextElement() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-  }
-
-  public deprecated class BasicHeaderIterator implements org.apache.http.HeaderIterator {
-    ctor public BasicHeaderIterator(org.apache.http.Header[], java.lang.String);
-    method protected boolean filterHeader(int);
-    method protected int findNext(int);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.Header nextHeader() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-    field protected final org.apache.http.Header[] allHeaders;
-    field protected int currentIndex;
-    field protected java.lang.String headerName;
-  }
-
-  public deprecated class BasicHeaderValueFormatter implements org.apache.http.message.HeaderValueFormatter {
-    ctor public BasicHeaderValueFormatter();
-    method protected void doFormatValue(org.apache.http.util.CharArrayBuffer, java.lang.String, boolean);
-    method protected int estimateElementsLen(org.apache.http.HeaderElement[]);
-    method protected int estimateHeaderElementLen(org.apache.http.HeaderElement);
-    method protected int estimateNameValuePairLen(org.apache.http.NameValuePair);
-    method protected int estimateParametersLen(org.apache.http.NameValuePair[]);
-    method public static final java.lang.String formatElements(org.apache.http.HeaderElement[], boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatElements(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement[], boolean);
-    method public static final java.lang.String formatHeaderElement(org.apache.http.HeaderElement, boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement, boolean);
-    method public static final java.lang.String formatNameValuePair(org.apache.http.NameValuePair, boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair, boolean);
-    method public static final java.lang.String formatParameters(org.apache.http.NameValuePair[], boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair[], boolean);
-    method protected boolean isSeparator(char);
-    method protected boolean isUnsafe(char);
-    field public static final org.apache.http.message.BasicHeaderValueFormatter DEFAULT;
-    field public static final java.lang.String SEPARATORS = " ;,:@()<>\\\"/[]?={}\t";
-    field public static final java.lang.String UNSAFE_CHARS = "\"\\";
-  }
-
-  public deprecated class BasicHeaderValueParser implements org.apache.http.message.HeaderValueParser {
-    ctor public BasicHeaderValueParser();
-    method protected org.apache.http.HeaderElement createHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]);
-    method protected org.apache.http.NameValuePair createNameValuePair(java.lang.String, java.lang.String);
-    method public static final org.apache.http.HeaderElement[] parseElements(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.HeaderElement[] parseElements(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.HeaderElement parseHeaderElement(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.HeaderElement parseHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.NameValuePair parseNameValuePair(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor, char[]);
-    method public static final org.apache.http.NameValuePair[] parseParameters(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.NameValuePair[] parseParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    field public static final org.apache.http.message.BasicHeaderValueParser DEFAULT;
-  }
-
-  public deprecated class BasicHttpEntityEnclosingRequest extends org.apache.http.message.BasicHttpRequest implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String);
-    ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    ctor public BasicHttpEntityEnclosingRequest(org.apache.http.RequestLine);
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class BasicHttpRequest extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpRequest {
-    ctor public BasicHttpRequest(java.lang.String, java.lang.String);
-    ctor public BasicHttpRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    ctor public BasicHttpRequest(org.apache.http.RequestLine);
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-  }
-
-  public deprecated class BasicHttpResponse extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpResponse {
-    ctor public BasicHttpResponse(org.apache.http.StatusLine, org.apache.http.ReasonPhraseCatalog, java.util.Locale);
-    ctor public BasicHttpResponse(org.apache.http.StatusLine);
-    ctor public BasicHttpResponse(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public org.apache.http.HttpEntity getEntity();
-    method public java.util.Locale getLocale();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method protected java.lang.String getReason(int);
-    method public org.apache.http.StatusLine getStatusLine();
-    method public void setEntity(org.apache.http.HttpEntity);
-    method public void setLocale(java.util.Locale);
-    method public void setReasonPhrase(java.lang.String);
-    method public void setStatusCode(int);
-    method public void setStatusLine(org.apache.http.StatusLine);
-    method public void setStatusLine(org.apache.http.ProtocolVersion, int);
-    method public void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-  }
-
-  public deprecated class BasicLineFormatter implements org.apache.http.message.LineFormatter {
-    ctor public BasicLineFormatter();
-    method public org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion);
-    method protected void doFormatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method protected void doFormatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method protected void doFormatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-    method protected int estimateProtocolVersionLen(org.apache.http.ProtocolVersion);
-    method public static final java.lang.String formatHeader(org.apache.http.Header, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method public static final java.lang.String formatProtocolVersion(org.apache.http.ProtocolVersion, org.apache.http.message.LineFormatter);
-    method public static final java.lang.String formatRequestLine(org.apache.http.RequestLine, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method public static final java.lang.String formatStatusLine(org.apache.http.StatusLine, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-    method protected org.apache.http.util.CharArrayBuffer initBuffer(org.apache.http.util.CharArrayBuffer);
-    field public static final org.apache.http.message.BasicLineFormatter DEFAULT;
-  }
-
-  public deprecated class BasicLineParser implements org.apache.http.message.LineParser {
-    ctor public BasicLineParser(org.apache.http.ProtocolVersion);
-    ctor public BasicLineParser();
-    method protected org.apache.http.ProtocolVersion createProtocolVersion(int, int);
-    method protected org.apache.http.RequestLine createRequestLine(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    method protected org.apache.http.StatusLine createStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public boolean hasProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.Header parseHeader(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.Header parseHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public static final org.apache.http.ProtocolVersion parseProtocolVersion(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.ProtocolVersion parseProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public static final org.apache.http.RequestLine parseRequestLine(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.RequestLine parseRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public static final org.apache.http.StatusLine parseStatusLine(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.StatusLine parseStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method protected void skipWhitespace(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    field public static final org.apache.http.message.BasicLineParser DEFAULT;
-    field protected final org.apache.http.ProtocolVersion protocol;
-  }
-
-  public deprecated class BasicListHeaderIterator implements org.apache.http.HeaderIterator {
-    ctor public BasicListHeaderIterator(java.util.List, java.lang.String);
-    method protected boolean filterHeader(int);
-    method protected int findNext(int);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.Header nextHeader() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-    field protected final java.util.List allHeaders;
-    field protected int currentIndex;
-    field protected java.lang.String headerName;
-    field protected int lastIndex;
-  }
-
-  public deprecated class BasicNameValuePair implements java.lang.Cloneable org.apache.http.NameValuePair {
-    ctor public BasicNameValuePair(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicRequestLine implements java.lang.Cloneable org.apache.http.RequestLine {
-    ctor public BasicRequestLine(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getMethod();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public java.lang.String getUri();
-  }
-
-  public deprecated class BasicStatusLine implements java.lang.Cloneable org.apache.http.StatusLine {
-    ctor public BasicStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public java.lang.String getReasonPhrase();
-    method public int getStatusCode();
-  }
-
-  public deprecated class BasicTokenIterator implements org.apache.http.TokenIterator {
-    ctor public BasicTokenIterator(org.apache.http.HeaderIterator);
-    method protected java.lang.String createToken(java.lang.String, int, int);
-    method protected int findNext(int) throws org.apache.http.ParseException;
-    method protected int findTokenEnd(int);
-    method protected int findTokenSeparator(int);
-    method protected int findTokenStart(int);
-    method public boolean hasNext();
-    method protected boolean isHttpSeparator(char);
-    method protected boolean isTokenChar(char);
-    method protected boolean isTokenSeparator(char);
-    method protected boolean isWhitespace(char);
-    method public final java.lang.Object next() throws java.util.NoSuchElementException, org.apache.http.ParseException;
-    method public java.lang.String nextToken() throws java.util.NoSuchElementException, org.apache.http.ParseException;
-    method public final void remove() throws java.lang.UnsupportedOperationException;
-    field public static final java.lang.String HTTP_SEPARATORS = " ,;=()<>@:\\\"/[]?{}\t";
-    field protected java.lang.String currentHeader;
-    field protected java.lang.String currentToken;
-    field protected final org.apache.http.HeaderIterator headerIt;
-    field protected int searchPos;
-  }
-
-  public deprecated class BufferedHeader implements java.lang.Cloneable org.apache.http.FormattedHeader {
-    ctor public BufferedHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.util.CharArrayBuffer getBuffer();
-    method public org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-    method public int getValuePos();
-  }
-
-  public deprecated class HeaderGroup implements java.lang.Cloneable {
-    ctor public HeaderGroup();
-    method public void addHeader(org.apache.http.Header);
-    method public void clear();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public boolean containsHeader(java.lang.String);
-    method public org.apache.http.message.HeaderGroup copy();
-    method public org.apache.http.Header[] getAllHeaders();
-    method public org.apache.http.Header getCondensedHeader(java.lang.String);
-    method public org.apache.http.Header getFirstHeader(java.lang.String);
-    method public org.apache.http.Header[] getHeaders(java.lang.String);
-    method public org.apache.http.Header getLastHeader(java.lang.String);
-    method public org.apache.http.HeaderIterator iterator();
-    method public org.apache.http.HeaderIterator iterator(java.lang.String);
-    method public void removeHeader(org.apache.http.Header);
-    method public void setHeaders(org.apache.http.Header[]);
-    method public void updateHeader(org.apache.http.Header);
-  }
-
-  public abstract deprecated interface HeaderValueFormatter {
-    method public abstract org.apache.http.util.CharArrayBuffer formatElements(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement[], boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement, boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair, boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair[], boolean);
-  }
-
-  public abstract deprecated interface HeaderValueParser {
-    method public abstract org.apache.http.HeaderElement[] parseElements(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.HeaderElement parseHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.NameValuePair[] parseParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-  }
-
-  public abstract deprecated interface LineFormatter {
-    method public abstract org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion);
-    method public abstract org.apache.http.util.CharArrayBuffer formatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method public abstract org.apache.http.util.CharArrayBuffer formatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method public abstract org.apache.http.util.CharArrayBuffer formatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-  }
-
-  public abstract deprecated interface LineParser {
-    method public abstract boolean hasProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public abstract org.apache.http.Header parseHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.ProtocolVersion parseProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.RequestLine parseRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.StatusLine parseStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-  }
-
-  public deprecated class ParserCursor {
-    ctor public ParserCursor(int, int);
-    method public boolean atEnd();
-    method public int getLowerBound();
-    method public int getPos();
-    method public int getUpperBound();
-    method public void updatePos(int);
-  }
-
-}
-
 package org.apache.http.params {
 
-  public abstract deprecated class AbstractHttpParams implements org.apache.http.params.HttpParams {
-    ctor protected AbstractHttpParams();
-    method public boolean getBooleanParameter(java.lang.String, boolean);
-    method public double getDoubleParameter(java.lang.String, double);
-    method public int getIntParameter(java.lang.String, int);
-    method public long getLongParameter(java.lang.String, long);
-    method public boolean isParameterFalse(java.lang.String);
-    method public boolean isParameterTrue(java.lang.String);
-    method public org.apache.http.params.HttpParams setBooleanParameter(java.lang.String, boolean);
-    method public org.apache.http.params.HttpParams setDoubleParameter(java.lang.String, double);
-    method public org.apache.http.params.HttpParams setIntParameter(java.lang.String, int);
-    method public org.apache.http.params.HttpParams setLongParameter(java.lang.String, long);
-  }
-
-  public final deprecated class BasicHttpParams extends org.apache.http.params.AbstractHttpParams implements java.lang.Cloneable java.io.Serializable {
-    ctor public BasicHttpParams();
-    method public void clear();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.params.HttpParams copy();
-    method protected void copyParams(org.apache.http.params.HttpParams);
-    method public java.lang.Object getParameter(java.lang.String);
-    method public boolean isParameterSet(java.lang.String);
-    method public boolean isParameterSetLocally(java.lang.String);
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
-    method public void setParameters(java.lang.String[], java.lang.Object);
-  }
-
   public abstract deprecated interface CoreConnectionPNames {
     field public static final java.lang.String CONNECTION_TIMEOUT = "http.connection.timeout";
     field public static final java.lang.String MAX_HEADER_COUNT = "http.connection.max-header-count";
@@ -57398,41 +55304,6 @@
     field public static final java.lang.String TCP_NODELAY = "http.tcp.nodelay";
   }
 
-  public abstract deprecated interface CoreProtocolPNames {
-    field public static final java.lang.String HTTP_CONTENT_CHARSET = "http.protocol.content-charset";
-    field public static final java.lang.String HTTP_ELEMENT_CHARSET = "http.protocol.element-charset";
-    field public static final java.lang.String ORIGIN_SERVER = "http.origin-server";
-    field public static final java.lang.String PROTOCOL_VERSION = "http.protocol.version";
-    field public static final java.lang.String STRICT_TRANSFER_ENCODING = "http.protocol.strict-transfer-encoding";
-    field public static final java.lang.String USER_AGENT = "http.useragent";
-    field public static final java.lang.String USE_EXPECT_CONTINUE = "http.protocol.expect-continue";
-    field public static final java.lang.String WAIT_FOR_CONTINUE = "http.protocol.wait-for-continue";
-  }
-
-  public final deprecated class DefaultedHttpParams extends org.apache.http.params.AbstractHttpParams {
-    ctor public DefaultedHttpParams(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    method public org.apache.http.params.HttpParams copy();
-    method public org.apache.http.params.HttpParams getDefaults();
-    method public java.lang.Object getParameter(java.lang.String);
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
-  }
-
-  public abstract deprecated class HttpAbstractParamBean {
-    ctor public HttpAbstractParamBean(org.apache.http.params.HttpParams);
-    field protected final org.apache.http.params.HttpParams params;
-  }
-
-  public deprecated class HttpConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public HttpConnectionParamBean(org.apache.http.params.HttpParams);
-    method public void setConnectionTimeout(int);
-    method public void setLinger(int);
-    method public void setSoTimeout(int);
-    method public void setSocketBufferSize(int);
-    method public void setStaleCheckingEnabled(boolean);
-    method public void setTcpNoDelay(boolean);
-  }
-
   public final deprecated class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames {
     method public static int getConnectionTimeout(org.apache.http.params.HttpParams);
     method public static int getLinger(org.apache.http.params.HttpParams);
@@ -57465,359 +55336,6 @@
     method public abstract org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
   }
 
-  public deprecated class HttpProtocolParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public HttpProtocolParamBean(org.apache.http.params.HttpParams);
-    method public void setContentCharset(java.lang.String);
-    method public void setHttpElementCharset(java.lang.String);
-    method public void setUseExpectContinue(boolean);
-    method public void setUserAgent(java.lang.String);
-    method public void setVersion(org.apache.http.HttpVersion);
-  }
-
-  public final deprecated class HttpProtocolParams implements org.apache.http.params.CoreProtocolPNames {
-    method public static java.lang.String getContentCharset(org.apache.http.params.HttpParams);
-    method public static java.lang.String getHttpElementCharset(org.apache.http.params.HttpParams);
-    method public static java.lang.String getUserAgent(org.apache.http.params.HttpParams);
-    method public static org.apache.http.ProtocolVersion getVersion(org.apache.http.params.HttpParams);
-    method public static void setContentCharset(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setHttpElementCharset(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setUseExpectContinue(org.apache.http.params.HttpParams, boolean);
-    method public static void setUserAgent(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setVersion(org.apache.http.params.HttpParams, org.apache.http.ProtocolVersion);
-    method public static boolean useExpectContinue(org.apache.http.params.HttpParams);
-  }
-
-}
-
-package org.apache.http.protocol {
-
-  public deprecated class BasicHttpContext implements org.apache.http.protocol.HttpContext {
-    ctor public BasicHttpContext();
-    ctor public BasicHttpContext(org.apache.http.protocol.HttpContext);
-    method public java.lang.Object getAttribute(java.lang.String);
-    method public java.lang.Object removeAttribute(java.lang.String);
-    method public void setAttribute(java.lang.String, java.lang.Object);
-  }
-
-  public final deprecated class BasicHttpProcessor implements java.lang.Cloneable org.apache.http.protocol.HttpProcessor org.apache.http.protocol.HttpRequestInterceptorList org.apache.http.protocol.HttpResponseInterceptorList {
-    ctor public BasicHttpProcessor();
-    method public final void addInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public final void addInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public final void addInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public final void addInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public void clearInterceptors();
-    method public void clearRequestInterceptors();
-    method public void clearResponseInterceptors();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.protocol.BasicHttpProcessor copy();
-    method protected void copyInterceptors(org.apache.http.protocol.BasicHttpProcessor);
-    method public org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public int getRequestInterceptorCount();
-    method public org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public int getResponseInterceptorCount();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void removeRequestInterceptorByClass(java.lang.Class);
-    method public void removeResponseInterceptorByClass(java.lang.Class);
-    method public void setInterceptors(java.util.List);
-    field protected java.util.List requestInterceptors;
-    field protected java.util.List responseInterceptors;
-  }
-
-  public final deprecated class DefaultedHttpContext implements org.apache.http.protocol.HttpContext {
-    ctor public DefaultedHttpContext(org.apache.http.protocol.HttpContext, org.apache.http.protocol.HttpContext);
-    method public java.lang.Object getAttribute(java.lang.String);
-    method public org.apache.http.protocol.HttpContext getDefaults();
-    method public java.lang.Object removeAttribute(java.lang.String);
-    method public void setAttribute(java.lang.String, java.lang.Object);
-  }
-
-  public abstract deprecated interface ExecutionContext {
-    field public static final java.lang.String HTTP_CONNECTION = "http.connection";
-    field public static final java.lang.String HTTP_PROXY_HOST = "http.proxy_host";
-    field public static final java.lang.String HTTP_REQUEST = "http.request";
-    field public static final java.lang.String HTTP_REQ_SENT = "http.request_sent";
-    field public static final java.lang.String HTTP_RESPONSE = "http.response";
-    field public static final java.lang.String HTTP_TARGET_HOST = "http.target_host";
-  }
-
-  public final deprecated class HTTP {
-    method public static boolean isWhitespace(char);
-    field public static final java.lang.String ASCII = "ASCII";
-    field public static final java.lang.String CHARSET_PARAM = "; charset=";
-    field public static final java.lang.String CHUNK_CODING = "chunked";
-    field public static final java.lang.String CONN_CLOSE = "Close";
-    field public static final java.lang.String CONN_DIRECTIVE = "Connection";
-    field public static final java.lang.String CONN_KEEP_ALIVE = "Keep-Alive";
-    field public static final java.lang.String CONTENT_ENCODING = "Content-Encoding";
-    field public static final java.lang.String CONTENT_LEN = "Content-Length";
-    field public static final java.lang.String CONTENT_TYPE = "Content-Type";
-    field public static final int CR = 13; // 0xd
-    field public static final java.lang.String DATE_HEADER = "Date";
-    field public static final java.lang.String DEFAULT_CONTENT_CHARSET = "ISO-8859-1";
-    field public static final java.lang.String DEFAULT_CONTENT_TYPE = "application/octet-stream";
-    field public static final java.lang.String DEFAULT_PROTOCOL_CHARSET = "US-ASCII";
-    field public static final java.lang.String EXPECT_CONTINUE = "100-continue";
-    field public static final java.lang.String EXPECT_DIRECTIVE = "Expect";
-    field public static final int HT = 9; // 0x9
-    field public static final java.lang.String IDENTITY_CODING = "identity";
-    field public static final java.lang.String ISO_8859_1 = "ISO-8859-1";
-    field public static final int LF = 10; // 0xa
-    field public static final java.lang.String OCTET_STREAM_TYPE = "application/octet-stream";
-    field public static final java.lang.String PLAIN_TEXT_TYPE = "text/plain";
-    field public static final java.lang.String SERVER_HEADER = "Server";
-    field public static final int SP = 32; // 0x20
-    field public static final java.lang.String TARGET_HOST = "Host";
-    field public static final java.lang.String TRANSFER_ENCODING = "Transfer-Encoding";
-    field public static final java.lang.String USER_AGENT = "User-Agent";
-    field public static final java.lang.String US_ASCII = "US-ASCII";
-    field public static final java.lang.String UTF_16 = "UTF-16";
-    field public static final java.lang.String UTF_8 = "UTF-8";
-  }
-
-  public abstract deprecated interface HttpContext {
-    method public abstract java.lang.Object getAttribute(java.lang.String);
-    method public abstract java.lang.Object removeAttribute(java.lang.String);
-    method public abstract void setAttribute(java.lang.String, java.lang.Object);
-    field public static final java.lang.String RESERVED_PREFIX = "http.";
-  }
-
-  public deprecated class HttpDateGenerator {
-    ctor public HttpDateGenerator();
-    method public synchronized java.lang.String getCurrentDate();
-    field public static final java.util.TimeZone GMT;
-    field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
-  }
-
-  public abstract deprecated interface HttpExpectationVerifier {
-    method public abstract void verify(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-  }
-
-  public abstract deprecated interface HttpProcessor implements org.apache.http.HttpRequestInterceptor org.apache.http.HttpResponseInterceptor {
-  }
-
-  public deprecated class HttpRequestExecutor {
-    ctor public HttpRequestExecutor();
-    method protected boolean canResponseHaveBody(org.apache.http.HttpRequest, org.apache.http.HttpResponse);
-    method protected org.apache.http.HttpResponse doReceiveResponse(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.HttpResponse doSendRequest(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void postProcess(org.apache.http.HttpResponse, org.apache.http.protocol.HttpProcessor, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void preProcess(org.apache.http.HttpRequest, org.apache.http.protocol.HttpProcessor, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpRequestHandler {
-    method public abstract void handle(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class HttpRequestHandlerRegistry implements org.apache.http.protocol.HttpRequestHandlerResolver {
-    ctor public HttpRequestHandlerRegistry();
-    method public org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String);
-    method protected deprecated boolean matchUriRequestPattern(java.lang.String, java.lang.String);
-    method public void register(java.lang.String, org.apache.http.protocol.HttpRequestHandler);
-    method public void setHandlers(java.util.Map);
-    method public void unregister(java.lang.String);
-  }
-
-  public abstract deprecated interface HttpRequestHandlerResolver {
-    method public abstract org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String);
-  }
-
-  public abstract deprecated interface HttpRequestInterceptorList {
-    method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public abstract void clearRequestInterceptors();
-    method public abstract org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public abstract int getRequestInterceptorCount();
-    method public abstract void removeRequestInterceptorByClass(java.lang.Class);
-    method public abstract void setInterceptors(java.util.List);
-  }
-
-  public abstract deprecated interface HttpResponseInterceptorList {
-    method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public abstract void clearResponseInterceptors();
-    method public abstract org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public abstract int getResponseInterceptorCount();
-    method public abstract void removeResponseInterceptorByClass(java.lang.Class);
-    method public abstract void setInterceptors(java.util.List);
-  }
-
-  public deprecated class HttpService {
-    ctor public HttpService(org.apache.http.protocol.HttpProcessor, org.apache.http.ConnectionReuseStrategy, org.apache.http.HttpResponseFactory);
-    method protected void doService(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.params.HttpParams getParams();
-    method protected void handleException(org.apache.http.HttpException, org.apache.http.HttpResponse);
-    method public void handleRequest(org.apache.http.HttpServerConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void setConnReuseStrategy(org.apache.http.ConnectionReuseStrategy);
-    method public void setExpectationVerifier(org.apache.http.protocol.HttpExpectationVerifier);
-    method public void setHandlerResolver(org.apache.http.protocol.HttpRequestHandlerResolver);
-    method public void setHttpProcessor(org.apache.http.protocol.HttpProcessor);
-    method public void setParams(org.apache.http.params.HttpParams);
-    method public void setResponseFactory(org.apache.http.HttpResponseFactory);
-  }
-
-  public deprecated class RequestConnControl implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestConnControl();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestContent implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestContent();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestDate implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestDate();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestExpectContinue implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestExpectContinue();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestTargetHost implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestTargetHost();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestUserAgent implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestUserAgent();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseConnControl implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseConnControl();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseContent implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseContent();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseDate implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseDate();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseServer implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseServer();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class SyncBasicHttpContext extends org.apache.http.protocol.BasicHttpContext {
-    ctor public SyncBasicHttpContext(org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class UriPatternMatcher {
-    ctor public UriPatternMatcher();
-    method public java.lang.Object lookup(java.lang.String);
-    method protected boolean matchUriRequestPattern(java.lang.String, java.lang.String);
-    method public void register(java.lang.String, java.lang.Object);
-    method public void setHandlers(java.util.Map);
-    method public void unregister(java.lang.String);
-  }
-
-}
-
-package org.apache.http.util {
-
-  public final deprecated class ByteArrayBuffer {
-    ctor public ByteArrayBuffer(int);
-    method public void append(byte[], int, int);
-    method public void append(int);
-    method public void append(char[], int, int);
-    method public void append(org.apache.http.util.CharArrayBuffer, int, int);
-    method public byte[] buffer();
-    method public int byteAt(int);
-    method public int capacity();
-    method public void clear();
-    method public boolean isEmpty();
-    method public boolean isFull();
-    method public int length();
-    method public void setLength(int);
-    method public byte[] toByteArray();
-  }
-
-  public final deprecated class CharArrayBuffer {
-    ctor public CharArrayBuffer(int);
-    method public void append(char[], int, int);
-    method public void append(java.lang.String);
-    method public void append(org.apache.http.util.CharArrayBuffer, int, int);
-    method public void append(org.apache.http.util.CharArrayBuffer);
-    method public void append(char);
-    method public void append(byte[], int, int);
-    method public void append(org.apache.http.util.ByteArrayBuffer, int, int);
-    method public void append(java.lang.Object);
-    method public char[] buffer();
-    method public int capacity();
-    method public char charAt(int);
-    method public void clear();
-    method public void ensureCapacity(int);
-    method public int indexOf(int, int, int);
-    method public int indexOf(int);
-    method public boolean isEmpty();
-    method public boolean isFull();
-    method public int length();
-    method public void setLength(int);
-    method public java.lang.String substring(int, int);
-    method public java.lang.String substringTrimmed(int, int);
-    method public char[] toCharArray();
-  }
-
-  public final deprecated class EncodingUtils {
-    method public static byte[] getAsciiBytes(java.lang.String);
-    method public static java.lang.String getAsciiString(byte[], int, int);
-    method public static java.lang.String getAsciiString(byte[]);
-    method public static byte[] getBytes(java.lang.String, java.lang.String);
-    method public static java.lang.String getString(byte[], int, int, java.lang.String);
-    method public static java.lang.String getString(byte[], java.lang.String);
-  }
-
-  public final deprecated class EntityUtils {
-    method public static java.lang.String getContentCharSet(org.apache.http.HttpEntity) throws org.apache.http.ParseException;
-    method public static byte[] toByteArray(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static java.lang.String toString(org.apache.http.HttpEntity, java.lang.String) throws java.io.IOException, org.apache.http.ParseException;
-    method public static java.lang.String toString(org.apache.http.HttpEntity) throws java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public final deprecated class ExceptionUtils {
-    method public static void initCause(java.lang.Throwable, java.lang.Throwable);
-  }
-
-  public final deprecated class LangUtils {
-    method public static boolean equals(java.lang.Object, java.lang.Object);
-    method public static boolean equals(java.lang.Object[], java.lang.Object[]);
-    method public static int hashCode(int, int);
-    method public static int hashCode(int, boolean);
-    method public static int hashCode(int, java.lang.Object);
-    field public static final int HASH_OFFSET = 37; // 0x25
-    field public static final int HASH_SEED = 17; // 0x11
-  }
-
-  public deprecated class VersionInfo {
-    ctor protected VersionInfo(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method protected static final org.apache.http.util.VersionInfo fromMap(java.lang.String, java.util.Map, java.lang.ClassLoader);
-    method public final java.lang.String getClassloader();
-    method public final java.lang.String getModule();
-    method public final java.lang.String getPackage();
-    method public final java.lang.String getRelease();
-    method public final java.lang.String getTimestamp();
-    method public static final org.apache.http.util.VersionInfo[] loadVersionInfo(java.lang.String[], java.lang.ClassLoader);
-    method public static final org.apache.http.util.VersionInfo loadVersionInfo(java.lang.String, java.lang.ClassLoader);
-    field public static final java.lang.String PROPERTY_MODULE = "info.module";
-    field public static final java.lang.String PROPERTY_RELEASE = "info.release";
-    field public static final java.lang.String PROPERTY_TIMESTAMP = "info.timestamp";
-    field public static final java.lang.String UNAVAILABLE = "UNAVAILABLE";
-    field public static final java.lang.String VERSION_PROPERTY_FILE = "version.properties";
-  }
-
 }
 
 package org.json {
diff --git a/api/removed.txt b/api/removed.txt
index 1b69ee8..1b209a9 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -6,8 +6,20 @@
 
 }
 
+package android.net {
+
+  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
+  }
+
+}
+
 package android.os {
 
+  public class BatteryManager {
+    ctor public BatteryManager();
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
@@ -22,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index ec0559f..3821544 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -29,6 +29,7 @@
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+    field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
     field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
     field public static final java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
@@ -37,6 +38,7 @@
     field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
+    field public static final java.lang.String BIND_MEDIA_ROUTE_SERVICE = "android.permission.BIND_MEDIA_ROUTE_SERVICE";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
@@ -128,6 +130,7 @@
     field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
     field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final java.lang.String NFC = "android.permission.NFC";
+    field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
     field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
@@ -164,6 +167,7 @@
     field public static final java.lang.String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
     field public static final java.lang.String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
     field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
+    field public static final java.lang.String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
     field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
     field public static final java.lang.String RECOVERY = "android.permission.RECOVERY";
     field public static final java.lang.String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
@@ -207,6 +211,7 @@
     field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
+    field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
     field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
     field public static final java.lang.String WAKE_LOCK = "android.permission.WAKE_LOCK";
@@ -365,6 +370,7 @@
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
+    field public static final int allowUndo = 16844006; // 0x10104e6
     field public static final int alpha = 16843551; // 0x101031f
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
@@ -479,6 +485,7 @@
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
+    field public static final int colorBackgroundFloating = 16844007; // 0x10104e7
     field public static final int colorButtonNormal = 16843819; // 0x101042b
     field public static final int colorControlActivated = 16843818; // 0x101042a
     field public static final int colorControlHighlight = 16843820; // 0x101042c
@@ -551,7 +558,7 @@
     field public static final int dialogTitle = 16843250; // 0x10101f2
     field public static final int digits = 16843110; // 0x1010166
     field public static final int direction = 16843217; // 0x10101d1
-    field public static final int directionDescriptions = 16843681; // 0x10103a1
+    field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
     field public static final int disableDependentsState = 16843249; // 0x10101f1
     field public static final int disabledAlpha = 16842803; // 0x1010033
@@ -571,6 +578,8 @@
     field public static final int drawablePadding = 16843121; // 0x1010171
     field public static final int drawableRight = 16843120; // 0x1010170
     field public static final int drawableStart = 16843666; // 0x1010392
+    field public static final int drawableTint = 16843990; // 0x10104d6
+    field public static final int drawableTintMode = 16843991; // 0x10104d7
     field public static final int drawableTop = 16843117; // 0x101016d
     field public static final int drawingCacheQuality = 16842984; // 0x10100e8
     field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -596,6 +605,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -660,6 +670,7 @@
     field public static final int format = 16843013; // 0x1010105
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
+    field public static final int fraction = 16843992; // 0x10104d8
     field public static final int fragment = 16843491; // 0x10102e3
     field public static final int fragmentAllowEnterTransitionOverlap = 16843976; // 0x10104c8
     field public static final int fragmentAllowReturnTransitionOverlap = 16843977; // 0x10104c9
@@ -729,6 +740,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844000; // 0x10104e0
+    field public static final int iconTintMode = 16844001; // 0x10104e1
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -938,6 +951,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
+    field public static final int navigationTint = 16844004; // 0x10104e4
+    field public static final int navigationTintMode = 16844005; // 0x10104e5
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -951,6 +966,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
+    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -968,6 +984,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overflowTint = 16844002; // 0x10104e2
+    field public static final int overflowTintMode = 16844003; // 0x10104e3
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -1080,6 +1098,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16843995; // 0x10104db
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1197,6 +1216,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -1270,7 +1290,7 @@
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
     field public static final int targetClass = 16842799; // 0x101002f
-    field public static final int targetDescriptions = 16843680; // 0x10103a0
+    field public static final deprecated int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
@@ -1386,6 +1406,8 @@
     field public static final int topRightRadius = 16843178; // 0x10101aa
     field public static final int touchscreenBlocksFocus = 16843919; // 0x101048f
     field public static final int track = 16843631; // 0x101036f
+    field public static final int trackTint = 16843993; // 0x10104d9
+    field public static final int trackTintMode = 16843994; // 0x10104da
     field public static final int transcriptMode = 16843008; // 0x1010100
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
@@ -1477,6 +1499,7 @@
     field public static final int windowExitTransition = 16843832; // 0x1010438
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
+    field public static final int windowHasLightStatusBar = 16843998; // 0x10104de
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
@@ -1773,8 +1796,11 @@
     field public static final int message = 16908299; // 0x102000b
     field public static final int navigationBarBackground = 16908336; // 0x1020030
     field public static final int paste = 16908322; // 0x1020022
+    field public static final int pasteAsPlainText = 16908337; // 0x1020031
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908339; // 0x1020033
+    field public static final int replaceText = 16908340; // 0x1020034
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1791,6 +1817,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908338; // 0x1020032
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -2081,6 +2108,7 @@
     field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
     field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
     field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+    field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
     field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -2153,6 +2181,21 @@
     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 = 16974372; // 0x1030224
+    field public static final int Theme_Material_DayNight = 16974548; // 0x10302d4
+    field public static final int Theme_Material_DayNight_DarkActionBar = 16974549; // 0x10302d5
+    field public static final int Theme_Material_DayNight_Dialog = 16974550; // 0x10302d6
+    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974556; // 0x10302dc
+    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974557; // 0x10302dd
+    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974551; // 0x10302d7
+    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974552; // 0x10302d8
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974553; // 0x10302d9
+    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974554; // 0x10302da
+    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974555; // 0x10302db
+    field public static final int Theme_Material_DayNight_NoActionBar = 16974558; // 0x10302de
+    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974559; // 0x10302df
+    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974560; // 0x10302e0
+    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974561; // 0x10302e1
+    field public static final int Theme_Material_DayNight_Panel = 16974562; // 0x10302e2
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2172,6 +2215,7 @@
     field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974396; // 0x103023c
     field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974397; // 0x103023d
     field public static final int Theme_Material_Light_Dialog_Presentation = 16974398; // 0x103023e
+    field public static final int Theme_Material_Light_LightStatusBar = 16974563; // 0x10302e3
     field public static final int Theme_Material_Light_NoActionBar = 16974401; // 0x1030241
     field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974402; // 0x1030242
     field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974403; // 0x1030243
@@ -2483,6 +2527,7 @@
     field public static final int Widget_Material_Button_Borderless = 16974425; // 0x1030259
     field public static final int Widget_Material_Button_Borderless_Colored = 16974426; // 0x103025a
     field public static final int Widget_Material_Button_Borderless_Small = 16974427; // 0x103025b
+    field public static final int Widget_Material_Button_Colored = 16974547; // 0x10302d3
     field public static final int Widget_Material_Button_Inset = 16974428; // 0x103025c
     field public static final int Widget_Material_Button_Small = 16974429; // 0x103025d
     field public static final int Widget_Material_Button_Toggle = 16974430; // 0x103025e
@@ -3467,6 +3512,7 @@
     method public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+    method public void onProvideAssistContent(android.app.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
@@ -3488,6 +3534,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void overridePendingTransition(int, int);
@@ -3534,6 +3581,7 @@
     method public final deprecated void showDialog(int);
     method public final deprecated boolean showDialog(int, android.os.Bundle);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startActivityForResult(android.content.Intent, int);
     method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
     method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
@@ -3590,6 +3638,7 @@
     method public int getLargeMemoryClass();
     method public int getLauncherLargeIconDensity();
     method public int getLauncherLargeIconSize();
+    method public int getLockTaskModeState();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
@@ -3600,7 +3649,7 @@
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
     method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
-    method public boolean isInLockTaskMode();
+    method public deprecated boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
@@ -3608,6 +3657,9 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
+    field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
+    field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
     field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
@@ -3756,6 +3808,7 @@
   }
 
   public class ActivityOptions {
+    method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
@@ -3801,8 +3854,8 @@
 
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
-    ctor protected AlertDialog(android.content.Context, int);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    ctor protected AlertDialog(android.content.Context, int);
     method public android.widget.Button getButton(int);
     method public android.widget.ListView getListView();
     method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3821,11 +3874,11 @@
     method public void setMessage(java.lang.CharSequence);
     method public void setView(android.view.View);
     method public void setView(android.view.View, int, int, int, int);
-    field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
-    field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
-    field public static final int THEME_HOLO_DARK = 2; // 0x2
-    field public static final int THEME_HOLO_LIGHT = 3; // 0x3
-    field public static final int THEME_TRADITIONAL = 1; // 0x1
+    field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+    field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+    field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+    field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+    field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
   }
 
   public static class AlertDialog.Builder {
@@ -3840,7 +3893,7 @@
     method public android.app.AlertDialog.Builder setIcon(int);
     method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
     method public android.app.AlertDialog.Builder setIconAttribute(int);
-    method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
     method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setMessage(int);
@@ -3997,6 +4050,69 @@
     field public java.lang.String serviceDetails;
   }
 
+  public class AssistContent implements android.os.Parcelable {
+    ctor public AssistContent();
+    method public int describeContents();
+    method public static android.app.AssistContent getAssistContent(android.os.Bundle);
+    method public android.content.ClipData getClipData();
+    method public android.content.Intent getIntent();
+    method public void setClipData(android.content.ClipData);
+    method public void setIntent(android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist_content";
+    field public static final android.os.Parcelable.Creator<android.app.AssistContent> CREATOR;
+  }
+
+  public final class AssistStructure implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivityComponent();
+    method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
+    method public void getWindowAt(int, android.app.AssistStructure.ViewNode);
+    method public int getWindowCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
+    field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
+  }
+
+  public static class AssistStructure.ViewNode {
+    ctor public AssistStructure.ViewNode();
+    method public void getChildAt(int, android.app.AssistStructure.ViewNode);
+    method public int getChildCount();
+    method public java.lang.String getClassName();
+    method public java.lang.String getContentDescription();
+    method public android.os.Bundle getExtras();
+    method public int getHeight();
+    method public java.lang.String getHint();
+    method public int getLeft();
+    method public int getScrollX();
+    method public int getScrollY();
+    method public java.lang.CharSequence getText();
+    method public int getTextBackgroundColor();
+    method public int getTextColor();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public float getTextSize();
+    method public int getTextStyle();
+    method public int getTop();
+    method public int getVisibility();
+    method public int getWidth();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActivated();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isLongClickable();
+    method public boolean isSelected();
+    field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
+    field public static final int TEXT_STYLE_BOLD = 1; // 0x1
+    field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
+    field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
+    field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
+  }
+
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -4072,6 +4188,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void registerForContextMenu(android.view.View);
@@ -4465,10 +4582,10 @@
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public void startAllocCounting();
+    method public deprecated void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public void stopAllocCounting();
+    method public deprecated void stopAllocCounting();
     method public void stopProfiling();
     method public void waitForIdle(java.lang.Runnable);
     method public void waitForIdleSync();
@@ -4850,6 +4967,37 @@
     method public android.app.Notification.Builder setWhen(long);
   }
 
+  public static final class Notification.CarExtender implements android.app.Notification.Extender {
+    ctor public Notification.CarExtender();
+    ctor public Notification.CarExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public int getColor();
+    method public android.graphics.Bitmap getLargeIcon();
+    method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
+    method public android.app.Notification.CarExtender setColor(int);
+    method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
+    method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
+  }
+
+  public static class Notification.CarExtender.Builder {
+    ctor public Notification.CarExtender.Builder(java.lang.String);
+    method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
+    method public android.app.Notification.CarExtender.UnreadConversation build();
+    method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
+    method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
+    method public android.app.Notification.CarExtender.Builder setReplyAction(android.app.PendingIntent, android.app.RemoteInput);
+  }
+
+  public static class Notification.CarExtender.UnreadConversation {
+    method public long getLatestTimestamp();
+    method public java.lang.String[] getMessages();
+    method public java.lang.String getParticipant();
+    method public java.lang.String[] getParticipants();
+    method public android.app.PendingIntent getReadPendingIntent();
+    method public android.app.RemoteInput getRemoteInput();
+    method public android.app.PendingIntent getReplyPendingIntent();
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
@@ -5284,7 +5432,7 @@
 
   public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
     ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
-    method public void onCommandResult(android.os.Bundle);
+    method public void onCommandResult(boolean, android.os.Bundle);
   }
 
   public static class VoiceInteractor.CompleteVoiceRequest extends android.app.VoiceInteractor.Request {
@@ -5327,6 +5475,7 @@
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clearWallpaper();
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5339,6 +5488,7 @@
     method public static android.app.WallpaperManager getInstance(android.content.Context);
     method public android.app.WallpaperInfo getWallpaperInfo();
     method public boolean hasResourceWallpaper(int);
+    method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
@@ -5347,6 +5497,7 @@
     method public void setDisplayPadding(android.graphics.Rect);
     method public void setResource(int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
+    method public boolean setWallpaperComponent(android.content.ComponentName);
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5395,6 +5546,7 @@
     ctor public DeviceAdminReceiver();
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
+    method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, java.lang.String, int, java.lang.String, java.lang.String);
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
     method public void onEnabled(android.content.Context, android.content.Intent);
@@ -5405,6 +5557,7 @@
     method public void onPasswordFailed(android.content.Context, android.content.Intent);
     method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
     method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
+    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
     field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5416,6 +5569,7 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5427,6 +5581,7 @@
     method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
     method public void addUserRestriction(android.content.ComponentName, java.lang.String);
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
+    method public void clearDeviceInitializerApp(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
     method public void clearProfileOwner(android.content.ComponentName);
@@ -5443,6 +5598,7 @@
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
+    method public java.lang.String getDeviceInitializerApp();
     method public java.lang.String getDeviceOwner();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5469,6 +5625,7 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
+    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5476,6 +5633,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isDeviceInitializerApp(java.lang.String);
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5493,6 +5651,7 @@
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
+    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5518,12 +5677,16 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
+    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setUserEnabled(android.content.ComponentName);
+    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
@@ -5537,14 +5700,20 @@
     field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -5842,6 +6011,7 @@
     method public java.lang.String getPackageName();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+    field public static final int INTERACTION = 6; // 0x6
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
@@ -7181,7 +7351,11 @@
     method public android.content.ContentProviderResult apply(android.content.ContentProvider, android.content.ContentProviderResult[], int) throws android.content.OperationApplicationException;
     method public int describeContents();
     method public android.net.Uri getUri();
+    method public boolean isAssertQuery();
+    method public boolean isDelete();
+    method public boolean isInsert();
     method public boolean isReadOperation();
+    method public boolean isUpdate();
     method public boolean isWriteOperation();
     method public boolean isYieldAllowed();
     method public static android.content.ContentProviderOperation.Builder newAssertQuery(android.net.Uri);
@@ -7383,6 +7557,8 @@
     method public abstract java.io.File getCacheDir();
     method public abstract java.lang.ClassLoader getClassLoader();
     method public abstract java.io.File getCodeCacheDir();
+    method public final int getColor(int);
+    method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
     method public abstract java.io.File getDir(java.lang.String, int);
@@ -7407,6 +7583,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
+    method public final T getSystemService(java.lang.Class<T>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
     method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7542,7 +7719,7 @@
     method public int checkPermission(java.lang.String, int, int);
     method public int checkUriPermission(android.net.Uri, int, int, int);
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
-    method public void clearWallpaper() throws java.io.IOException;
+    method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7585,20 +7762,21 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
-    method public android.graphics.drawable.Drawable getWallpaper();
-    method public int getWallpaperDesiredMinimumHeight();
-    method public int getWallpaperDesiredMinimumWidth();
+    method public deprecated android.graphics.drawable.Drawable getWallpaper();
+    method public deprecated int getWallpaperDesiredMinimumHeight();
+    method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public android.graphics.drawable.Drawable peekWallpaper();
+    method public deprecated android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public void removeStickyBroadcast(android.content.Intent);
-    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void removeStickyBroadcast(android.content.Intent);
+    method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
@@ -7607,13 +7785,13 @@
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyBroadcast(android.content.Intent);
-    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyBroadcast(android.content.Intent);
+    method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
-    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
     method public void startActivities(android.content.Intent[], android.os.Bundle);
     method public void startActivity(android.content.Intent);
@@ -7910,6 +8088,7 @@
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+    field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
@@ -7981,6 +8160,7 @@
     field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
     field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
+    field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
     field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
     field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
@@ -8008,6 +8188,7 @@
     field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -9379,7 +9560,10 @@
 
   public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
-    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void applyTheme(android.content.res.Resources.Theme);
+    method public boolean canApplyTheme();
+    method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
@@ -9509,8 +9693,10 @@
     method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
     method public boolean getBoolean(int) throws android.content.res.Resources.NotFoundException;
-    method public int getColor(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+    method public deprecated int getColor(int) throws android.content.res.Resources.NotFoundException;
+    method public int getColor(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public deprecated android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.ColorStateList getColorStateList(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.Configuration getConfiguration();
     method public float getDimension(int) throws android.content.res.Resources.NotFoundException;
     method public int getDimensionPixelOffset(int) throws android.content.res.Resources.NotFoundException;
@@ -11091,6 +11277,8 @@
   public class ImageFormat {
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
+    field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
@@ -11946,15 +12134,8 @@
     method public final void setTileModeY(android.graphics.Shader.TileMode);
   }
 
-  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     field public static final int HORIZONTAL = 1; // 0x1
     field public static final int VERTICAL = 2; // 0x2
   }
@@ -11994,8 +12175,12 @@
     method public android.graphics.drawable.Drawable.ConstantState getConstantState();
     method public android.graphics.drawable.Drawable getCurrent();
     method public android.graphics.Rect getDirtyBounds();
+    method public boolean getDither();
+    method public boolean getFilterBitmap();
+    method public void getHotspotBounds(android.graphics.Rect);
     method public int getIntrinsicHeight();
     method public int getIntrinsicWidth();
+    method public int getLayoutDirection();
     method public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
@@ -12013,6 +12198,7 @@
     method public void jumpToCurrentState();
     method public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
+    method public boolean onLayoutDirectionChange(int);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
@@ -12029,6 +12215,7 @@
     method public void setFilterBitmap(boolean);
     method public void setHotspot(float, float);
     method public void setHotspotBounds(int, int, int, int);
+    method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
     method public boolean setState(int[]);
     method public void setTint(int);
@@ -12093,6 +12280,19 @@
     method public final void setVariablePadding(boolean);
   }
 
+  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public DrawableWrapper(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
@@ -12140,25 +12340,28 @@
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
   }
 
-  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    method public int addLayer(android.graphics.drawable.Drawable);
     method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
+    method public int findIndexByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerInsetBottom(int);
+    method public int getLayerInsetEnd(int);
+    method public int getLayerInsetLeft(int);
+    method public int getLayerInsetRight(int);
+    method public int getLayerInsetStart(int);
+    method public int getLayerInsetTop(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -12166,9 +12369,21 @@
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setDrawable(int, android.graphics.drawable.Drawable);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
+    method public void setLayerHeight(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetBottom(int, int);
+    method public void setLayerInsetEnd(int, int);
+    method public void setLayerInsetLeft(int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerInsetRight(int, int);
+    method public void setLayerInsetStart(int, int);
+    method public void setLayerInsetTop(int, int);
+    method public void setLayerSize(int, int, int);
+    method public void setLayerWidth(int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -12215,44 +12430,30 @@
 
   public class RippleDrawable extends android.graphics.drawable.LayerDrawable {
     ctor public RippleDrawable(android.content.res.ColorStateList, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public int getRadius();
     method public void setColor(android.content.res.ColorStateList);
+    method public void setRadius(int);
+    field public static final int RADIUS_AUTO = -1; // 0xffffffff
   }
 
-  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public RotateDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
     method public float getFromDegrees();
-    method public int getOpacity();
     method public float getPivotX();
     method public float getPivotY();
     method public float getToDegrees();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public boolean isPivotXRelative();
     method public boolean isPivotYRelative();
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setDrawable(android.graphics.drawable.Drawable);
     method public void setFromDegrees(float);
     method public void setPivotX(float);
     method public void setPivotXRelative(boolean);
     method public void setPivotY(float);
     method public void setPivotYRelative(boolean);
     method public void setToDegrees(float);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
-  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
@@ -12709,6 +12910,7 @@
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+    field public static final java.lang.String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -12731,6 +12933,7 @@
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
+    field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
   }
 
   public class SensorEvent {
@@ -12864,6 +13067,8 @@
     field public static final int CAMERA_DISABLED = 1; // 0x1
     field public static final int CAMERA_DISCONNECTED = 2; // 0x2
     field public static final int CAMERA_ERROR = 3; // 0x3
+    field public static final int CAMERA_IN_USE = 4; // 0x4
+    field public static final int MAX_CAMERAS_IN_USE = 5; // 0x5
   }
 
   public abstract class CameraCaptureSession implements java.lang.AutoCloseable {
@@ -12907,11 +13112,14 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_COMPENSATION_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AWB_AVAILABLE_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AWB_LOCK_AVAILABLE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
@@ -12930,6 +13138,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW;
@@ -12949,6 +13158,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> SENSOR_INFO_LENS_SHADING_APPLIED;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE;
@@ -12959,8 +13169,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SHADING_AVAILABLE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES;
@@ -13004,7 +13216,10 @@
     method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
     method public void openCamera(java.lang.String, android.hardware.camera2.CameraDevice.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public void registerAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback, android.os.Handler);
+    method public void registerTorchCallback(android.hardware.camera2.CameraManager.TorchCallback, android.os.Handler);
+    method public void setTorchMode(java.lang.String, boolean) throws android.hardware.camera2.CameraAccessException;
     method public void unregisterAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback);
+    method public void unregisterTorchCallback(android.hardware.camera2.CameraManager.TorchCallback);
   }
 
   public static abstract class CameraManager.AvailabilityCallback {
@@ -13013,6 +13228,12 @@
     method public void onCameraUnavailable(java.lang.String);
   }
 
+  public static abstract class CameraManager.TorchCallback {
+    ctor public CameraManager.TorchCallback();
+    method public void onTorchModeChanged(java.lang.String, boolean);
+    method public void onTorchModeUnavailable(java.lang.String);
+  }
+
   public abstract class CameraMetadata {
     method public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
@@ -13030,6 +13251,7 @@
     field public static final int CONTROL_AE_MODE_ON_ALWAYS_FLASH = 3; // 0x3
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH = 2; // 0x2
     field public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4; // 0x4
+    field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2; // 0x2
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_IDLE = 0; // 0x0
     field public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1; // 0x1
     field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
@@ -13126,6 +13348,7 @@
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
     field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_EXTERNAL = 2; // 0x2
     field public static final int LENS_FACING_FRONT = 0; // 0x0
     field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1; // 0x1
     field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2; // 0x2
@@ -13136,13 +13359,16 @@
     field public static final int LENS_STATE_STATIONARY = 0; // 0x0
     field public static final int NOISE_REDUCTION_MODE_FAST = 1; // 0x1
     field public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int NOISE_REDUCTION_MODE_MINIMAL = 3; // 0x3
     field public static final int NOISE_REDUCTION_MODE_OFF = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4; // 0x4
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3; // 0x3
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
     field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
@@ -13192,7 +13418,11 @@
     field public static final int SYNC_MAX_LATENCY_UNKNOWN = -1; // 0xffffffff
     field public static final int TONEMAP_MODE_CONTRAST_CURVE = 0; // 0x0
     field public static final int TONEMAP_MODE_FAST = 1; // 0x1
+    field public static final int TONEMAP_MODE_GAMMA_VALUE = 3; // 0x3
     field public static final int TONEMAP_MODE_HIGH_QUALITY = 2; // 0x2
+    field public static final int TONEMAP_MODE_PRESET_CURVE = 4; // 0x4
+    field public static final int TONEMAP_PRESET_CURVE_REC709 = 1; // 0x1
+    field public static final int TONEMAP_PRESET_CURVE_SRGB = 0; // 0x0
   }
 
   public class CaptureFailure {
@@ -13248,6 +13478,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_FRAME_DURATION;
@@ -13259,7 +13490,9 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureRequest.Builder {
@@ -13325,6 +13558,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
     field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> SCALER_CROP_REGION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_EXPOSURE_TIME;
@@ -13346,7 +13580,9 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER;
     field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> TONEMAP_GAMMA;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_PRESET_CURVE;
   }
 
   public static final class CaptureResult.Key {
@@ -14927,12 +15163,14 @@
 
   public class AsyncPlayer {
     ctor public AsyncPlayer(java.lang.String);
-    method public void play(android.content.Context, android.net.Uri, boolean, int);
+    method public deprecated void play(android.content.Context, android.net.Uri, boolean, int);
+    method public void play(android.content.Context, android.net.Uri, boolean, android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void stop();
   }
 
   public final class AudioAttributes implements android.os.Parcelable {
     method public int describeContents();
+    method public int getAllFlags();
     method public int getCapturePreset();
     method public int getContentType();
     method public int getFlags();
@@ -14946,6 +15184,8 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_BEACON = 8; // 0x8
+    field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 64; // 0x40
+    field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
     field public static final int FLAG_HW_HOTWORD = 32; // 0x20
     field public static final int USAGE_ALARM = 4; // 0x4
@@ -14972,6 +15212,7 @@
     method public android.media.AudioAttributes.Builder setCapturePreset(int);
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
+    method public android.media.AudioAttributes.Builder setInternalCapturePreset(int);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
@@ -15073,6 +15314,7 @@
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
     method public boolean isSpeakerphoneOn();
+    method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
     method public deprecated boolean isWiredHeadsetOn();
     method public void loadSoundEffects();
@@ -15094,8 +15336,8 @@
     method public void setRingerMode(int);
     method public deprecated void setRouting(int, int, int);
     method public void setSpeakerphoneOn(boolean);
-    method public void setStreamMute(int, boolean);
-    method public void setStreamSolo(int, boolean);
+    method public deprecated void setStreamMute(int, boolean);
+    method public deprecated void setStreamSolo(int, boolean);
     method public void setStreamVolume(int, int, int);
     method public deprecated void setVibrateSetting(int, int);
     method public deprecated void setWiredHeadsetOn(boolean);
@@ -15114,8 +15356,11 @@
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
+    field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
     field public static final int ADJUST_SAME = 0; // 0x0
+    field public static final int ADJUST_TOGGLE_MUTE = 101; // 0x65
+    field public static final int ADJUST_UNMUTE = 100; // 0x64
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
@@ -15200,6 +15445,7 @@
 
   public class AudioRecord {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
@@ -15631,6 +15877,7 @@
     field public static final int COLOR_Format24bitBGR888 = 12; // 0xc
     field public static final int COLOR_Format24bitRGB888 = 11; // 0xb
     field public static final int COLOR_Format25bitARGB1888 = 14; // 0xe
+    field public static final int COLOR_Format32BitRGBA8888 = 2130747392; // 0x7f00a000
     field public static final int COLOR_Format32bitARGB8888 = 16; // 0x10
     field public static final int COLOR_Format32bitBGRA8888 = 15; // 0xf
     field public static final int COLOR_Format8bitRGB332 = 2; // 0x2
@@ -15881,6 +16128,7 @@
     field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
     field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
     field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
     field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
@@ -16208,6 +16456,7 @@
     method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
     method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
     method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
+    method public void setPlaybackRate(float, int);
     method public void setScreenOnWhilePlaying(boolean);
     method public void setSurface(android.view.Surface);
     method public void setVideoScalingMode(int);
@@ -16233,6 +16482,7 @@
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
     field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -16335,7 +16585,9 @@
   public final class MediaRecorder.AudioSource {
     field public static final int CAMCORDER = 5; // 0x5
     field public static final int DEFAULT = 0; // 0x0
+    field public static final int HOTWORD = 1999; // 0x7cf
     field public static final int MIC = 1; // 0x1
+    field public static final int RADIO_TUNER = 1998; // 0x7ce
     field public static final int REMOTE_SUBMIX = 8; // 0x8
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
@@ -17232,6 +17484,7 @@
     method public void connect();
     method public void disconnect();
     method public android.os.Bundle getExtras();
+    method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
     method public java.lang.String getRoot();
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
@@ -17261,6 +17514,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
+  public static abstract class MediaBrowser.MediaItemCallback {
+    ctor public MediaBrowser.MediaItemCallback();
+    method public void onError();
+    method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+  }
+
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -17324,6 +17583,85 @@
 
 }
 
+package android.media.midi {
+
+  public final class MidiDeviceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getId();
+    method public int getInputPortCount();
+    method public android.media.midi.MidiDeviceInfo.PortInfo getInputPortInfo(int);
+    method public int getOutputPortCount();
+    method public android.media.midi.MidiDeviceInfo.PortInfo getOutputPortInfo(int);
+    method public android.os.Bundle getProperties();
+    method public int getType();
+    method public boolean isPrivate();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.midi.MidiDeviceInfo> CREATOR;
+    field public static final java.lang.String PROPERTY_MANUFACTURER = "manufacturer";
+    field public static final java.lang.String PROPERTY_NAME = "name";
+    field public static final java.lang.String PROPERTY_PRODUCT = "product";
+    field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
+    field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final int TYPE_USB = 1; // 0x1
+    field public static final int TYPE_VIRTUAL = 2; // 0x2
+  }
+
+  public static final class MidiDeviceInfo.PortInfo {
+    method public java.lang.String getName();
+    method public int getPortNumber();
+    method public int getType();
+    field public static final int TYPE_INPUT = 1; // 0x1
+    field public static final int TYPE_OUTPUT = 2; // 0x2
+  }
+
+  public abstract class MidiDeviceService extends android.app.Service {
+    ctor public MidiDeviceService();
+    method public final android.media.midi.MidiDeviceInfo getDeviceInfo();
+    method public final android.media.midi.MidiReceiver[] getOutputPortReceivers();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
+    method public abstract android.media.midi.MidiReceiver[] onGetInputPortReceivers();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
+  }
+
+  public final class MidiDeviceStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.media.midi.MidiDeviceInfo getDeviceInfo();
+    method public int getOutputPortOpenCount(int);
+    method public boolean isInputPortOpen(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.midi.MidiDeviceStatus> CREATOR;
+  }
+
+  public final class MidiInputPort extends android.media.midi.MidiReceiver implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public final int getPortNumber();
+    method public void onReceive(byte[], int, int, long) throws java.io.IOException;
+  }
+
+  public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public void connect(android.media.midi.MidiReceiver);
+    method public void disconnect(android.media.midi.MidiReceiver);
+    method public final int getPortNumber();
+  }
+
+  public abstract class MidiReceiver {
+    ctor public MidiReceiver();
+    method public int getMaxMessageSize();
+    method public abstract void onReceive(byte[], int, int, long) throws java.io.IOException;
+    method public void send(byte[], int, int) throws java.io.IOException;
+    method public void sendWithTimestamp(byte[], int, int, long) throws java.io.IOException;
+  }
+
+  public abstract class MidiSender {
+    ctor public MidiSender();
+    method public abstract void connect(android.media.midi.MidiReceiver);
+    method public abstract void disconnect(android.media.midi.MidiReceiver);
+  }
+
+}
+
 package android.media.projection {
 
   public final class MediaProjection {
@@ -17345,11 +17683,248 @@
 
 }
 
+package android.media.routing {
+
+  public final class MediaRouteSelector implements android.os.Parcelable {
+    method public boolean containsProtocol(java.lang.Class<?>);
+    method public boolean containsProtocol(java.lang.String);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public int getOptionalFeatures();
+    method public java.util.List<java.lang.String> getOptionalProtocols();
+    method public int getRequiredFeatures();
+    method public java.util.List<java.lang.String> getRequiredProtocols();
+    method public java.lang.String getServicePackageName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.routing.MediaRouteSelector> CREATOR;
+  }
+
+  public static final class MediaRouteSelector.Builder {
+    ctor public MediaRouteSelector.Builder();
+    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.Class<?>);
+    method public android.media.routing.MediaRouteSelector.Builder addOptionalProtocol(java.lang.String);
+    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.Class<?>);
+    method public android.media.routing.MediaRouteSelector.Builder addRequiredProtocol(java.lang.String);
+    method public android.media.routing.MediaRouteSelector build();
+    method public android.media.routing.MediaRouteSelector.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouteSelector.Builder setOptionalFeatures(int);
+    method public android.media.routing.MediaRouteSelector.Builder setRequiredFeatures(int);
+    method public android.media.routing.MediaRouteSelector.Builder setServicePackageName(java.lang.String);
+  }
+
+  public abstract class MediaRouteService extends android.app.Service {
+    ctor public MediaRouteService();
+    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.media.routing.MediaRouteService.ClientSession onCreateClientSession(android.media.routing.MediaRouteService.ClientInfo);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.media.routing.MediaRouteService";
+  }
+
+  public static final class MediaRouteService.ClientInfo {
+    method public java.lang.String getPackageName();
+    method public int getUid();
+  }
+
+  public static abstract class MediaRouteService.ClientSession {
+    ctor public MediaRouteService.ClientSession();
+    method public abstract boolean onConnect(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouteService.ConnectionCallback);
+    method public abstract void onDisconnect();
+    method public void onPauseStream();
+    method public void onRelease();
+    method public void onResumeStream();
+    method public abstract boolean onStartDiscovery(android.media.routing.MediaRouter.DiscoveryRequest, android.media.routing.MediaRouteService.DiscoveryCallback);
+    method public abstract void onStopDiscovery();
+  }
+
+  public final class MediaRouteService.ConnectionCallback {
+    method public void onConnected(android.media.routing.MediaRouter.ConnectionInfo);
+    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onDisconnected();
+  }
+
+  public final class MediaRouteService.DiscoveryCallback {
+    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
+    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
+  }
+
+  public final class MediaRouter {
+    ctor public MediaRouter(android.content.Context);
+    method public void addSelector(android.media.routing.MediaRouteSelector);
+    method public void clearSelectors();
+    method public android.media.routing.MediaRouter.Delegate createDelegate();
+    method public android.media.routing.MediaRouter.ConnectionInfo getConnection();
+    method public int getConnectionState();
+    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
+    method public java.util.List<android.media.routing.MediaRouter.RouteInfo> getDiscoveredRoutes(android.media.routing.MediaRouter.DestinationInfo);
+    method public int getDiscoveryState();
+    method public android.media.AudioAttributes getPreferredAudioAttributes();
+    method public android.view.Display getPreferredPresentationDisplay();
+    method public android.media.VolumeProvider getPreferredVolumeProvider();
+    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
+    method public android.media.routing.MediaRouter.RouteInfo getSelectedRoute();
+    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
+    method public boolean isReleased();
+    method public void pauseStream();
+    method public void release();
+    method public void removeSelector(android.media.routing.MediaRouteSelector);
+    method public void resumeStream();
+    method public void setRoutingCallback(android.media.routing.MediaRouter.RoutingCallback, android.os.Handler);
+    field public static final int CONNECTION_ERROR_ABORTED = 1; // 0x1
+    field public static final int CONNECTION_ERROR_BARGED = 7; // 0x7
+    field public static final int CONNECTION_ERROR_BROKEN = 6; // 0x6
+    field public static final int CONNECTION_ERROR_BUSY = 4; // 0x4
+    field public static final int CONNECTION_ERROR_TIMEOUT = 5; // 0x5
+    field public static final int CONNECTION_ERROR_UNAUTHORIZED = 2; // 0x2
+    field public static final int CONNECTION_ERROR_UNKNOWN = 0; // 0x0
+    field public static final int CONNECTION_ERROR_UNREACHABLE = 3; // 0x3
+    field public static final int CONNECTION_FLAG_BARGE = 1; // 0x1
+    field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
+    field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
+    field public static final int CONNECTION_STATE_DISCONNECTED = 0; // 0x0
+    field public static final int DISCONNECTION_REASON_APPLICATION_REQUEST = 0; // 0x0
+    field public static final int DISCONNECTION_REASON_ERROR = 2; // 0x2
+    field public static final int DISCONNECTION_REASON_USER_REQUEST = 1; // 0x1
+    field public static final int DISCOVERY_ERROR_ABORTED = 1; // 0x1
+    field public static final int DISCOVERY_ERROR_NO_CONNECTIVITY = 2; // 0x2
+    field public static final int DISCOVERY_ERROR_UNKNOWN = 0; // 0x0
+    field public static final int DISCOVERY_FLAG_BACKGROUND = 1; // 0x1
+    field public static final int DISCOVERY_STATE_STARTED = 1; // 0x1
+    field public static final int DISCOVERY_STATE_STOPPED = 0; // 0x0
+    field public static final int ROUTE_FEATURE_LIVE_AUDIO = 1; // 0x1
+    field public static final int ROUTE_FEATURE_LIVE_VIDEO = 2; // 0x2
+  }
+
+  public static final class MediaRouter.ConnectionInfo {
+    method public android.media.AudioAttributes getAudioAttributes();
+    method public android.os.Bundle getExtras();
+    method public int getFeatures();
+    method public android.view.Display getPresentationDisplay();
+    method public android.os.IBinder getProtocolBinder(java.lang.String);
+    method public android.os.IBinder getProtocolBinder(int);
+    method public T getProtocolObject(java.lang.Class<T>);
+    method public java.util.List<java.lang.String> getProtocols();
+    method public android.media.routing.MediaRouter.RouteInfo getRoute();
+    method public android.media.VolumeProvider getVolumeProvider();
+  }
+
+  public static final class MediaRouter.ConnectionInfo.Builder {
+    ctor public MediaRouter.ConnectionInfo.Builder(android.media.routing.MediaRouter.RouteInfo);
+    method public android.media.routing.MediaRouter.ConnectionInfo build();
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setAudioAttributes(android.media.AudioAttributes);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setPresentationDisplay(android.view.Display);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolBinder(java.lang.String, android.os.IBinder);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setProtocolStub(java.lang.Class<?>, android.os.IInterface);
+    method public android.media.routing.MediaRouter.ConnectionInfo.Builder setVolumeProvider(android.media.VolumeProvider);
+  }
+
+  public static final class MediaRouter.ConnectionRequest {
+    method public android.os.Bundle getExtras();
+    method public int getFlags();
+    method public android.media.routing.MediaRouter.RouteInfo getRoute();
+    method public void setExtras(android.os.Bundle);
+    method public void setFlags(int);
+    method public void setRoute(android.media.routing.MediaRouter.RouteInfo);
+  }
+
+  public static final class MediaRouter.Delegate {
+    ctor public MediaRouter.Delegate();
+    method public void addStateCallback(android.media.routing.MediaRouter.StateCallback, android.os.Handler);
+    method public void connect(android.media.routing.MediaRouter.DestinationInfo, int);
+    method public void disconnect(int);
+    method public int getConnectionState();
+    method public java.util.List<android.media.routing.MediaRouter.DestinationInfo> getDiscoveredDestinations();
+    method public int getDiscoveryState();
+    method public android.media.routing.MediaRouter.DestinationInfo getSelectedDestination();
+    method public boolean isReleased();
+    method public void removeStateCallback(android.media.routing.MediaRouter.StateCallback);
+    method public void startDiscovery(int);
+    method public void stopDiscovery();
+  }
+
+  public static final class MediaRouter.DestinationInfo {
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public int getIconResourceId();
+    method public java.lang.String getId();
+    method public java.lang.CharSequence getName();
+    method public android.media.routing.MediaRouter.ServiceMetadata getServiceMetadata();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
+  }
+
+  public static final class MediaRouter.DestinationInfo.Builder {
+    ctor public MediaRouter.DestinationInfo.Builder(java.lang.String, android.media.routing.MediaRouter.ServiceMetadata, java.lang.CharSequence);
+    method public android.media.routing.MediaRouter.DestinationInfo build();
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setDescription(java.lang.CharSequence);
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.DestinationInfo.Builder setIconResourceId(int);
+  }
+
+  public static final class MediaRouter.DiscoveryRequest {
+    method public int getFlags();
+    method public java.util.List<android.media.routing.MediaRouteSelector> getSelectors();
+    method public void setFlags(int);
+    method public void setSelectors(java.util.List<android.media.routing.MediaRouteSelector>);
+  }
+
+  public static final class MediaRouter.RouteInfo {
+    method public android.media.routing.MediaRouter.DestinationInfo getDestination();
+    method public android.os.Bundle getExtras();
+    method public int getFeatures();
+    method public java.lang.String getId();
+    method public java.util.List<java.lang.String> getProtocols();
+    method public android.media.routing.MediaRouteSelector getSelector();
+  }
+
+  public static final class MediaRouter.RouteInfo.Builder {
+    ctor public MediaRouter.RouteInfo.Builder(java.lang.String, android.media.routing.MediaRouter.DestinationInfo, android.media.routing.MediaRouteSelector);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.Class<T>);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder addProtocol(java.lang.String);
+    method public android.media.routing.MediaRouter.RouteInfo build();
+    method public android.media.routing.MediaRouter.RouteInfo.Builder setExtras(android.os.Bundle);
+    method public android.media.routing.MediaRouter.RouteInfo.Builder setFeatures(int);
+  }
+
+  public static abstract class MediaRouter.RoutingCallback extends android.media.routing.MediaRouter.StateCallback {
+    ctor public MediaRouter.RoutingCallback();
+    method public boolean onPrepareConnectionRequest(android.media.routing.MediaRouter.ConnectionRequest, android.media.routing.MediaRouter.DestinationInfo, java.util.List<android.media.routing.MediaRouter.RouteInfo>);
+    method public boolean onPrepareDiscoveryRequest(android.media.routing.MediaRouter.DiscoveryRequest, java.util.List<android.media.routing.MediaRouteSelector>);
+  }
+
+  public static final class MediaRouter.ServiceMetadata {
+    method public android.content.ComponentName getComponentName();
+    method public android.graphics.drawable.Drawable getIcon(android.content.pm.PackageManager);
+    method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
+    method public java.lang.String getPackageName();
+    method public android.content.pm.ServiceInfo getService();
+  }
+
+  public static abstract class MediaRouter.StateCallback {
+    ctor public MediaRouter.StateCallback();
+    method public void onConnected();
+    method public void onConnecting();
+    method public void onConnectionFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onConnectionStateChanged(int);
+    method public void onDestinationFound(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDestinationLost(android.media.routing.MediaRouter.DestinationInfo);
+    method public void onDisconnected();
+    method public void onDiscoveryFailed(int, java.lang.CharSequence, android.os.Bundle);
+    method public void onDiscoveryStarted();
+    method public void onDiscoveryStateChanged(int);
+    method public void onDiscoveryStopped();
+    method public void onReleased();
+    method public void onSelectedDestinationChanged(android.media.routing.MediaRouter.DestinationInfo);
+  }
+
+}
+
 package android.media.session {
 
   public final class MediaController {
     ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
+    method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
     method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
     method public android.os.Bundle getExtras();
     method public long getFlags();
@@ -17422,6 +17997,7 @@
     method public void setExtras(android.os.Bundle);
     method public void setFlags(int);
     method public void setMediaButtonReceiver(android.app.PendingIntent);
+    method public void setMediaRouter(android.media.routing.MediaRouter);
     method public void setMetadata(android.media.MediaMetadata);
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
@@ -18558,7 +19134,6 @@
     method public static javax.net.SocketFactory getDefault(int);
     method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
     method public java.lang.String[] getDefaultCipherSuites();
-    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public byte[] getNpnSelectedProtocol(java.net.Socket);
     method public java.lang.String[] getSupportedCipherSuites();
@@ -18804,30 +19379,6 @@
 
 package android.net.http {
 
-  public final deprecated class AndroidHttpClient implements org.apache.http.client.HttpClient {
-    method public void close();
-    method public void disableCurlLogging();
-    method public void enableCurlLogging(java.lang.String, int);
-    method public org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public static org.apache.http.entity.AbstractHttpEntity getCompressedEntity(byte[], android.content.ContentResolver) throws java.io.IOException;
-    method public org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public static long getMinGzipSize(android.content.ContentResolver);
-    method public org.apache.http.params.HttpParams getParams();
-    method public static java.io.InputStream getUngzippedContent(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static void modifyRequestToAcceptGzipResponse(org.apache.http.HttpRequest);
-    method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String, android.content.Context);
-    method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String);
-    method public static long parseDate(java.lang.String);
-    field public static long DEFAULT_SYNC_MIN_GZIP_BYTES;
-  }
-
   public final class HttpResponseCache extends java.net.ResponseCache implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void delete() throws java.io.IOException;
@@ -18837,7 +19388,7 @@
     method public static android.net.http.HttpResponseCache getInstalled();
     method public int getNetworkCount();
     method public int getRequestCount();
-    method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
+    method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
     method public long maxSize();
     method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
     method public long size();
@@ -19343,11 +19894,11 @@
     field public java.util.BitSet allowedKeyManagement;
     field public java.util.BitSet allowedPairwiseCiphers;
     field public java.util.BitSet allowedProtocols;
-    field public int apBand;
-    field public int apChannel;
+    field public java.lang.String creatorName;
     field public int creatorUid;
     field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
     field public boolean hiddenSSID;
+    field public java.lang.String lastUpdateName;
     field public int lastUpdateUid;
     field public int networkId;
     field public int numAssociation;
@@ -19355,8 +19906,6 @@
     field public int numScorerOverrideAndSwitchedNetwork;
     field public java.lang.String preSharedKey;
     field public int priority;
-    field public java.lang.String providerFriendlyName;
-    field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
     field public int status;
     field public java.lang.String[] wepKeys;
     field public int wepTxKeyIndex;
@@ -19429,7 +19978,6 @@
     ctor public WifiEnterpriseConfig();
     ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
-    method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
     method public java.security.cert.X509Certificate getClientCertificate();
@@ -19437,10 +19985,7 @@
     method public java.lang.String getIdentity();
     method public java.lang.String getPassword();
     method public int getPhase2Method();
-    method public java.lang.String getPlmn();
-    method public java.lang.String getRealm();
-    method public deprecated java.lang.String getSubjectMatch();
-    method public void setAltSubjectMatch(java.lang.String);
+    method public java.lang.String getSubjectMatch();
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
@@ -19448,9 +19993,7 @@
     method public void setIdentity(java.lang.String);
     method public void setPassword(java.lang.String);
     method public void setPhase2Method(int);
-    method public void setPlmn(java.lang.String);
-    method public void setRealm(java.lang.String);
-    method public deprecated void setSubjectMatch(java.lang.String);
+    method public void setSubjectMatch(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
   }
@@ -19552,6 +20095,8 @@
     field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
     field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
     field public static final java.lang.String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+    field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
     field public static final java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
     field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
     field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
@@ -19560,6 +20105,9 @@
     field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
     field public static final java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
     field public static final java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+    field public static final java.lang.String WIFI_CREDENTIAL_CHANGED_ACTION = "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+    field public static final int WIFI_CREDENTIAL_FORGOT = 1; // 0x1
+    field public static final int WIFI_CREDENTIAL_SAVED = 0; // 0x0
     field public static final int WIFI_MODE_FULL = 1; // 0x1
     field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
     field public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
@@ -19612,7 +20160,7 @@
   public class WifiScanner {
     method public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
     method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
-    method public android.net.wifi.ScanResult[] getScanResults();
+    method public boolean getScanResults();
     method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
     method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
     method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
@@ -19700,7 +20248,6 @@
   public static abstract interface WifiScanner.ScanListener implements android.net.wifi.WifiScanner.ActionListener {
     method public abstract void onFullResult(android.net.wifi.ScanResult);
     method public abstract void onPeriodChanged(int);
-    method public abstract deprecated void onResults(android.net.wifi.ScanResult[]);
     method public abstract void onResults(android.net.wifi.WifiScanner.ScanData[]);
   }
 
@@ -22980,7 +23527,6 @@
   }
 
   public class BatteryManager {
-    ctor public BatteryManager();
     method public int getIntProperty(int);
     method public long getLongProperty(int);
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -23101,6 +23647,7 @@
     field public static final int KITKAT_WATCH = 20; // 0x14
     field public static final int LOLLIPOP = 21; // 0x15
     field public static final int LOLLIPOP_MR1 = 22; // 0x16
+    field public static final int MNC = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -23213,47 +23760,47 @@
     method public static final int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static int getGlobalAllocCount();
-    method public static int getGlobalAllocSize();
-    method public static int getGlobalClassInitCount();
-    method public static int getGlobalClassInitTime();
+    method public static deprecated int getGlobalAllocCount();
+    method public static deprecated int getGlobalAllocSize();
+    method public static deprecated int getGlobalClassInitCount();
+    method public static deprecated int getGlobalClassInitTime();
     method public static deprecated int getGlobalExternalAllocCount();
     method public static deprecated int getGlobalExternalAllocSize();
     method public static deprecated int getGlobalExternalFreedCount();
     method public static deprecated int getGlobalExternalFreedSize();
-    method public static int getGlobalFreedCount();
-    method public static int getGlobalFreedSize();
-    method public static int getGlobalGcInvocationCount();
+    method public static deprecated int getGlobalFreedCount();
+    method public static deprecated int getGlobalFreedSize();
+    method public static deprecated int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static int getThreadAllocCount();
-    method public static int getThreadAllocSize();
+    method public static deprecated int getThreadAllocCount();
+    method public static deprecated int getThreadAllocSize();
     method public static deprecated int getThreadExternalAllocCount();
     method public static deprecated int getThreadExternalAllocSize();
-    method public static int getThreadGcInvocationCount();
+    method public static deprecated int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static void resetAllCounts();
-    method public static void resetGlobalAllocCount();
-    method public static void resetGlobalAllocSize();
-    method public static void resetGlobalClassInitCount();
-    method public static void resetGlobalClassInitTime();
+    method public static deprecated void resetAllCounts();
+    method public static deprecated void resetGlobalAllocCount();
+    method public static deprecated void resetGlobalAllocSize();
+    method public static deprecated void resetGlobalClassInitCount();
+    method public static deprecated void resetGlobalClassInitTime();
     method public static deprecated void resetGlobalExternalAllocCount();
     method public static deprecated void resetGlobalExternalAllocSize();
     method public static deprecated void resetGlobalExternalFreedCount();
     method public static deprecated void resetGlobalExternalFreedSize();
-    method public static void resetGlobalFreedCount();
-    method public static void resetGlobalFreedSize();
-    method public static void resetGlobalGcInvocationCount();
-    method public static void resetThreadAllocCount();
-    method public static void resetThreadAllocSize();
+    method public static deprecated void resetGlobalFreedCount();
+    method public static deprecated void resetGlobalFreedSize();
+    method public static deprecated void resetGlobalGcInvocationCount();
+    method public static deprecated void resetThreadAllocCount();
+    method public static deprecated void resetThreadAllocSize();
     method public static deprecated void resetThreadExternalAllocCount();
     method public static deprecated void resetThreadExternalAllocSize();
-    method public static void resetThreadGcInvocationCount();
+    method public static deprecated void resetThreadGcInvocationCount();
     method public static deprecated int setAllocationLimit(int);
     method public static deprecated int setGlobalAllocationLimit(int);
     method public static deprecated void startAllocCounting();
@@ -23272,10 +23819,10 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
-  public static class Debug.InstructionCount {
+  public static deprecated class Debug.InstructionCount {
     ctor public Debug.InstructionCount();
     method public boolean collect();
     method public int globalMethodInvocations();
@@ -23476,7 +24023,9 @@
   public final class Looper {
     method public void dump(android.util.Printer, java.lang.String);
     method public static android.os.Looper getMainLooper();
+    method public android.os.MessageQueue getQueue();
     method public java.lang.Thread getThread();
+    method public boolean isCurrentThread();
     method public static void loop();
     method public static android.os.Looper myLooper();
     method public static android.os.MessageQueue myQueue();
@@ -23534,7 +24083,18 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public boolean isIdle();
+    method public void registerFileDescriptorCallback(java.io.FileDescriptor, int, android.os.MessageQueue.FileDescriptorCallback);
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public void unregisterFileDescriptorCallback(java.io.FileDescriptor);
+  }
+
+  public static abstract class MessageQueue.FileDescriptorCallback {
+    ctor public MessageQueue.FileDescriptorCallback();
+    method public int onFileDescriptorEvents(java.io.FileDescriptor, int);
+    field public static final int EVENT_ERROR = 4; // 0x4
+    field public static final int EVENT_INPUT = 1; // 0x1
+    field public static final int EVENT_OUTPUT = 2; // 0x2
   }
 
   public static abstract interface MessageQueue.IdleHandler {
@@ -23930,6 +24490,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskReads();
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
+    method public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeathOnNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
@@ -23941,6 +24502,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskReads();
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
+    method public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
   }
 
   public static final class StrictMode.VmPolicy {
@@ -23953,11 +24515,13 @@
     method public android.os.StrictMode.VmPolicy build();
     method public android.os.StrictMode.VmPolicy.Builder detectActivityLeaks();
     method public android.os.StrictMode.VmPolicy.Builder detectAll();
+    method public android.os.StrictMode.VmPolicy.Builder detectCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
+    method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -24495,6 +25059,7 @@
   public final class PrintAttributes implements android.os.Parcelable {
     method public int describeContents();
     method public int getColorMode();
+    method public int getDuplexMode();
     method public android.print.PrintAttributes.MediaSize getMediaSize();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public android.print.PrintAttributes.Resolution getResolution();
@@ -24502,12 +25067,16 @@
     field public static final int COLOR_MODE_COLOR = 2; // 0x2
     field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR;
+    field public static final int DUPLEX_MODE_LONG_EDGE = 2; // 0x2
+    field public static final int DUPLEX_MODE_NONE = 1; // 0x1
+    field public static final int DUPLEX_MODE_SHORT_EDGE = 4; // 0x4
   }
 
   public static final class PrintAttributes.Builder {
     ctor public PrintAttributes.Builder();
     method public android.print.PrintAttributes build();
     method public android.print.PrintAttributes.Builder setColorMode(int);
+    method public android.print.PrintAttributes.Builder setDuplexMode(int);
     method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
     method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
     method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
@@ -24725,6 +25294,7 @@
     method public int describeContents();
     method public int getColorModes();
     method public android.print.PrintAttributes getDefaults();
+    method public int getDuplexModes();
     method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
     method public android.print.PrintAttributes.Margins getMinMargins();
     method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
@@ -24738,6 +25308,7 @@
     method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
     method public android.print.PrinterCapabilitiesInfo build();
     method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
     method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
   }
 
@@ -25227,6 +25798,7 @@
     field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
     field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
     field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
+    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
@@ -25584,6 +26156,13 @@
     field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1
   }
 
+  public static final class ContactsContract.Authorization {
+    ctor public ContactsContract.Authorization();
+    field public static final java.lang.String AUTHORIZATION_METHOD = "authorize";
+    field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri";
+    field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
+  }
+
   protected static abstract interface ContactsContract.BaseSyncColumns {
     field public static final java.lang.String SYNC1 = "sync1";
     field public static final java.lang.String SYNC2 = "sync2";
@@ -25927,12 +26506,21 @@
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
     field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final java.lang.String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
     field public static final java.lang.String CONTENT_DIRECTORY = "suggestions";
   }
 
+  public static final class ContactsContract.Contacts.AggregationSuggestions.Builder {
+    ctor public ContactsContract.Contacts.AggregationSuggestions.Builder();
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder addNameParameter(java.lang.String);
+    method public android.net.Uri build();
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setContactId(long);
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setLimit(int);
+  }
+
   public static final class ContactsContract.Contacts.Data implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
     field public static final java.lang.String CONTENT_DIRECTORY = "data";
   }
@@ -26070,6 +26658,7 @@
     field public static final int ORGANIZATION = 30; // 0x1e
     field public static final int PHONE = 20; // 0x14
     field public static final int STRUCTURED_NAME = 40; // 0x28
+    field public static final int STRUCTURED_PHONETIC_NAME = 37; // 0x25
     field public static final int UNDEFINED = 0; // 0x0
   }
 
@@ -26135,6 +26724,8 @@
     field public static final java.lang.String EMAIL = "email";
     field public static final java.lang.String EMAIL_ISPRIMARY = "email_isprimary";
     field public static final java.lang.String EMAIL_TYPE = "email_type";
+    field public static final java.lang.String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
+    field public static final java.lang.String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
     field public static final java.lang.String FULL_MODE = "full_mode";
     field public static final java.lang.String IM_HANDLE = "im_handle";
     field public static final java.lang.String IM_ISPRIMARY = "im_isprimary";
@@ -26215,12 +26806,26 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
+  public static final class ContactsContract.ProviderStatus {
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String STATUS = "status";
+    field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3
+    field public static final int STATUS_NORMAL = 0; // 0x0
+    field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4
+    field public static final int STATUS_UPGRADING = 1; // 0x1
+  }
+
   public static final class ContactsContract.QuickContact {
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, java.lang.String[], java.lang.String);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, java.lang.String[], java.lang.String);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
+    field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
+    field public static final java.lang.String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -26922,6 +27527,7 @@
     field public static final java.lang.String SHOW_PROCESSES = "show_processes";
     field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
     field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_global_version";
+    field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
     field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
@@ -26989,7 +27595,7 @@
     field public static final int LOCATION_MODE_OFF = 0; // 0x0
     field public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
     field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-    field public static final java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
+    field public static final deprecated java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
     field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
     field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
     field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
@@ -27062,7 +27668,6 @@
     field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
@@ -27125,14 +27730,6 @@
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
     field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
     field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
     field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
@@ -27451,6 +28048,8 @@
   }
 
   public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
+    method public static long getOrCreateThreadId(android.content.Context, java.lang.String);
+    method public static long getOrCreateThreadId(android.content.Context, java.util.Set<java.lang.String>);
     field public static final int BROADCAST_THREAD = 1; // 0x1
     field public static final int COMMON_THREAD = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
@@ -28498,6 +29097,7 @@
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
+    method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String, java.lang.String);
     method public static android.content.Intent createInstallIntent();
     method public static java.security.cert.X509Certificate[] getCertificateChain(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method public static java.security.PrivateKey getPrivateKey(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
@@ -28611,6 +29211,30 @@
 
 }
 
+package android.service.chooser {
+
+  public final class ChooserTarget implements android.os.Parcelable {
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public android.content.IntentSender getIntentSender();
+    method public float getScore();
+    method public java.lang.CharSequence getTitle();
+    method public boolean sendIntent(android.content.Context, android.content.Intent);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
+  }
+
+  public abstract class ChooserTargetService extends android.app.Service {
+    ctor public ChooserTargetService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
@@ -28648,6 +29272,7 @@
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void setContentView(int);
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
@@ -28666,6 +29291,7 @@
   public abstract class MediaBrowserService extends android.app.Service {
     ctor public MediaBrowserService();
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
     method public android.os.IBinder onBind(android.content.Intent);
@@ -28759,6 +29385,7 @@
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
+    field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int TRIM_FULL = 0; // 0x0
     field public static final int TRIM_LIGHT = 1; // 0x1
@@ -28919,9 +29546,10 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onReady();
     method public void onShutdown();
-    method public void startSession(android.os.Bundle);
+    method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final int START_WITH_ASSIST = 1; // 0x1
   }
 
   public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
@@ -28930,19 +29558,32 @@
     method public void finish();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
+    method public void hide();
     method public void hideWindow();
+    method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onBackPressed();
+    method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
     method public void onCloseSystemDialogs();
+    method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+    method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
-    method public void onCreate(android.os.Bundle);
+    method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
+    method public void onCreate(android.os.Bundle, int);
     method public android.view.View onCreateContentView();
     method public void onDestroy();
+    method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+    method public void onHandleAssist(android.os.Bundle);
+    method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onShow(android.os.Bundle, int);
+    method public void onTaskFinished(android.content.Intent, int);
+    method public void onTaskStarted(android.content.Intent, int);
     method public void setContentView(android.view.View);
     method public void setTheme(int);
+    method public void show();
     method public void showWindow();
     method public void startVoiceActivity(android.content.Intent);
   }
@@ -29275,6 +29916,7 @@
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
     method public abstract void onStart(java.lang.String);
+    method public void onStop(java.lang.String, boolean);
   }
 
   public class Voice implements android.os.Parcelable {
@@ -29760,6 +30402,15 @@
     field public static final int STDERR_FILENO;
     field public static final int STDIN_FILENO;
     field public static final int STDOUT_FILENO;
+    field public static final int ST_MANDLOCK;
+    field public static final int ST_NOATIME;
+    field public static final int ST_NODEV;
+    field public static final int ST_NODIRATIME;
+    field public static final int ST_NOEXEC;
+    field public static final int ST_NOSUID;
+    field public static final int ST_RDONLY;
+    field public static final int ST_RELATIME;
+    field public static final int ST_SYNCHRONOUS;
     field public static final int S_IFBLK;
     field public static final int S_IFCHR;
     field public static final int S_IFDIR;
@@ -30139,6 +30790,7 @@
     method public final void setDisconnected(android.telecom.DisconnectCause);
     method public final void setInitialized();
     method public final void setInitializing();
+    method public final void setNextPostDialChar(char);
     method public final void setOnHold();
     method public final void setPostDialWait(java.lang.String);
     method public final void setRingbackRequested(boolean);
@@ -30446,7 +31098,9 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
@@ -30731,6 +31385,7 @@
     method public static java.lang.String formatNumber(java.lang.String, java.lang.String);
     method public static java.lang.String formatNumber(java.lang.String, java.lang.String, java.lang.String);
     method public static java.lang.String formatNumberToE164(java.lang.String, java.lang.String);
+    method public static java.lang.String formatNumberToRFC3966(java.lang.String, java.lang.String);
     method public static deprecated int getFormatTypeForLocale(java.util.Locale);
     method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
     method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
@@ -30993,6 +31648,7 @@
   public class TelephonyManager {
     method public void answerRingingCall();
     method public void call(java.lang.String, java.lang.String);
+    method public boolean canChangeDtmfToneLength();
     method public int checkCarrierPrivilegesForPackage(java.lang.String);
     method public void dial(java.lang.String);
     method public boolean disableDataConnectivity();
@@ -31052,6 +31708,7 @@
     method public boolean isSmsCapable();
     method public boolean isVideoCallingEnabled();
     method public boolean isVoiceCapable();
+    method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
@@ -31610,6 +32267,7 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
@@ -33478,6 +34136,13 @@
     method public void captureStartValues(android.transition.TransitionValues);
   }
 
+  public class ChangeScroll extends android.transition.Transition {
+    ctor public ChangeScroll();
+    ctor public ChangeScroll(android.content.Context, android.util.AttributeSet);
+    method public void captureEndValues(android.transition.TransitionValues);
+    method public void captureStartValues(android.transition.TransitionValues);
+  }
+
   public class ChangeTransform extends android.transition.Transition {
     ctor public ChangeTransform();
     ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
@@ -33558,6 +34223,7 @@
     method public android.transition.Transition addTarget(java.lang.String);
     method public android.transition.Transition addTarget(java.lang.Class);
     method public android.transition.Transition addTarget(android.view.View);
+    method protected boolean areValuesChanged(android.transition.TransitionValues, android.transition.TransitionValues);
     method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
     method public abstract void captureStartValues(android.transition.TransitionValues);
@@ -34382,6 +35048,7 @@
     method public java.lang.Object getTag();
     method public abstract java.lang.CharSequence getTitle();
     method public boolean getTitleOptionalHint();
+    method public int getType();
     method public abstract void invalidate();
     method public boolean isTitleOptional();
     method public abstract void setCustomView(android.view.View);
@@ -34391,6 +35058,9 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
     method public void setTitleOptionalHint(boolean);
+    method public void setType(int);
+    field public static final int TYPE_FLOATING = 1; // 0x1
+    field public static final int TYPE_PRIMARY = 0; // 0x0
   }
 
   public static abstract interface ActionMode.Callback {
@@ -34448,6 +35118,7 @@
   public class ContextThemeWrapper extends android.content.ContextWrapper {
     ctor public ContextThemeWrapper();
     ctor public ContextThemeWrapper(android.content.Context, int);
+    ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme);
     method public void applyOverrideConfiguration(android.content.res.Configuration);
     method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
   }
@@ -35234,6 +35905,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -35537,6 +36210,7 @@
     method public int describeContents();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
+    method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
     method public deprecated void unlockCanvas(android.graphics.Canvas);
@@ -35739,6 +36413,7 @@
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
+    method public java.lang.CharSequence getAccessibilityClassName();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
     method public int getAccessibilityTraversalAfter();
@@ -35747,6 +36422,7 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.graphics.drawable.Drawable getBackground();
+    method public int getBackgroundColor();
     method public android.content.res.ColorStateList getBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method public int getBaseline();
@@ -35826,6 +36502,7 @@
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
     method public android.view.View getRootView();
+    method public android.view.WindowInsets getRootWindowInsets();
     method public float getRotation();
     method public float getRotationX();
     method public float getRotationY();
@@ -35963,6 +36640,7 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -36080,6 +36758,7 @@
     method public void setOnHoverListener(android.view.View.OnHoverListener);
     method public void setOnKeyListener(android.view.View.OnKeyListener);
     method public void setOnLongClickListener(android.view.View.OnLongClickListener);
+    method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
     method public void setOutlineProvider(android.view.ViewOutlineProvider);
@@ -36130,6 +36809,7 @@
     method public void setZ(float);
     method public boolean showContextMenu();
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startAnimation(android.view.animation.Animation);
     method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
     method public boolean startNestedScroll(int);
@@ -36237,6 +36917,7 @@
     field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
     field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
     field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
+    field public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 8192; // 0x2000
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
@@ -36347,6 +37028,10 @@
     method public abstract boolean onLongClick(android.view.View);
   }
 
+  public static abstract interface View.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.view.View, int, int, int, int);
+  }
+
   public static abstract interface View.OnSystemUiVisibilityChangeListener {
     method public abstract void onSystemUiVisibilityChange(int);
   }
@@ -36359,6 +37044,18 @@
     method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
   }
 
+  public abstract class ViewAssistStructure {
+    ctor public ViewAssistStructure();
+    method public abstract java.lang.CharSequence getHint();
+    method public abstract java.lang.CharSequence getText();
+    method public abstract int getTextSelectionEnd();
+    method public abstract int getTextSelectionStart();
+    method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence);
+    method public abstract void setText(java.lang.CharSequence, int, int);
+    method public abstract void setTextPaint(android.text.TextPaint);
+  }
+
   public class ViewConfiguration {
     ctor public deprecated ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
@@ -36569,6 +37266,7 @@
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
     method public void startLayoutAnimation();
     method public void startViewTransition(android.view.View);
     method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
@@ -36689,6 +37387,7 @@
     method public abstract void requestTransparentRegion(android.view.View);
     method public abstract boolean showContextMenuForChild(android.view.View);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
+    method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
   }
 
   public class ViewPropertyAnimator {
@@ -36978,6 +37677,7 @@
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public abstract void onWindowFocusChanged(boolean);
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
@@ -37057,8 +37757,10 @@
     method public java.lang.String debug(java.lang.String);
     method public int describeContents();
     method public final java.lang.CharSequence getTitle();
+    method public final long getUserActivityTimeout();
     method public static boolean mayUseInputMethod(int);
     method public final void setTitle(java.lang.CharSequence);
+    method public final void setUserActivityTimeout(long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALPHA_CHANGED = 128; // 0x80
     field public static final int ANIMATION_CHANGED = 16; // 0x10
@@ -38645,6 +39347,32 @@
     method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
   }
 
+  public class WebMessage {
+    ctor public WebMessage(java.lang.String);
+    ctor public WebMessage(java.lang.String, android.webkit.WebMessagePort[]);
+    method public java.lang.String getData();
+    method public android.webkit.WebMessagePort[] getPorts();
+  }
+
+  public abstract class WebMessagePort {
+    ctor public WebMessagePort();
+    method public abstract void close();
+    method public abstract void postMessage(android.webkit.WebMessage);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback);
+    method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback, android.os.Handler);
+  }
+
+  public static abstract class WebMessagePort.WebMessageCallback {
+    ctor public WebMessagePort.WebMessageCallback();
+    method public void onMessage(android.webkit.WebMessagePort, android.webkit.WebMessage);
+  }
+
+  public abstract class WebResourceError {
+    ctor public WebResourceError();
+    method public abstract java.lang.String getDescription();
+    method public abstract int getErrorCode();
+  }
+
   public abstract interface WebResourceRequest {
     method public abstract java.lang.String getMethod();
     method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
@@ -38653,7 +39381,7 @@
     method public abstract boolean isForMainFrame();
   }
 
-  public class WebResourceResponse {
+  public class WebResourceResponse extends android.webkit.WebResourceResponseBase {
     ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
     ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
@@ -38669,6 +39397,16 @@
     method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
   }
 
+  public abstract class WebResourceResponseBase {
+    ctor public WebResourceResponseBase();
+    method public abstract java.io.InputStream getData();
+    method public abstract java.lang.String getEncoding();
+    method public abstract java.lang.String getMimeType();
+    method public abstract java.lang.String getReasonPhrase();
+    method public abstract java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public abstract int getStatusCode();
+  }
+
   public abstract class WebSettings {
     ctor public WebSettings();
     method public abstract deprecated boolean enableSmoothTransition();
@@ -38704,6 +39442,7 @@
     method public abstract int getMinimumLogicalFontSize();
     method public abstract int getMixedContentMode();
     method public abstract deprecated boolean getNavDump();
+    method public abstract boolean getOffscreenPreRaster();
     method public abstract deprecated android.webkit.WebSettings.PluginState getPluginState();
     method public abstract deprecated boolean getPluginsEnabled();
     method public abstract java.lang.String getSansSerifFontFamily();
@@ -38756,6 +39495,7 @@
     method public abstract void setMixedContentMode(int);
     method public abstract deprecated void setNavDump(boolean);
     method public abstract void setNeedInitialFocus(boolean);
+    method public abstract void setOffscreenPreRaster(boolean);
     method public abstract deprecated void setPluginState(android.webkit.WebSettings.PluginState);
     method public abstract deprecated void setPluginsEnabled(boolean);
     method public abstract deprecated void setRenderPriority(android.webkit.WebSettings.RenderPriority);
@@ -38886,6 +39626,7 @@
     method public android.webkit.WebBackForwardList copyBackForwardList();
     method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
     method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public void documentHasImages(android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
@@ -38927,6 +39668,7 @@
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
+    method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public void postUrl(java.lang.String, byte[]);
     method public void reload();
     method public void removeJavascriptInterface(java.lang.String);
@@ -39028,8 +39770,10 @@
     method public void onPageFinished(android.webkit.WebView, java.lang.String);
     method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
     method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponseBase);
     method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public void onScaleChanged(android.webkit.WebView, float, float);
@@ -39042,6 +39786,7 @@
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
+    field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
     field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
     field public static final int ERROR_FILE = -13; // 0xfffffff3
@@ -39136,6 +39881,7 @@
     method public abstract void clearView();
     method public abstract android.webkit.WebBackForwardList copyBackForwardList();
     method public abstract android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method public abstract android.webkit.WebMessagePort[] createWebMessageChannel();
     method public abstract void destroy();
     method public abstract void documentHasImages(android.os.Message);
     method public abstract void dumpViewHierarchyWithProperties(java.io.BufferedWriter, int);
@@ -39182,6 +39928,7 @@
     method public abstract boolean pageDown(boolean);
     method public abstract boolean pageUp(boolean);
     method public abstract void pauseTimers();
+    method public abstract void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
     method public abstract void postUrl(java.lang.String, byte[]);
     method public abstract void reload();
     method public abstract void removeJavascriptInterface(java.lang.String);
@@ -39448,6 +40195,8 @@
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public boolean showOverflowMenu();
   }
@@ -39601,7 +40350,7 @@
     ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public class ArrayAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public ArrayAdapter(android.content.Context, int);
     ctor public ArrayAdapter(android.content.Context, int, int);
     ctor public ArrayAdapter(android.content.Context, int, T[]);
@@ -39615,6 +40364,7 @@
     method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
     method public android.content.Context getContext();
     method public int getCount();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public T getItem(int);
     method public long getItemId(int);
@@ -39623,6 +40373,7 @@
     method public void insert(T, int);
     method public void remove(T);
     method public void setDropDownViewResource(int);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setNotifyOnChange(boolean);
     method public void sort(java.util.Comparator<? super T>);
   }
@@ -39823,6 +40574,7 @@
     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.graphics.drawable.Drawable getButtonDrawable();
     method public android.content.res.ColorStateList getButtonTintList();
     method public android.graphics.PorterDuff.Mode getButtonTintMode();
     method public boolean isChecked();
@@ -39839,7 +40591,7 @@
     method public abstract void onCheckedChanged(android.widget.CompoundButton, boolean);
   }
 
-  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
@@ -39848,6 +40600,7 @@
     method public java.lang.CharSequence convertToString(android.database.Cursor);
     method public int getCount();
     method public android.database.Cursor getCursor();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public android.widget.FilterQueryProvider getFilterQueryProvider();
     method public java.lang.Object getItem(int);
@@ -39858,6 +40611,7 @@
     method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
     method protected void onContentChanged();
     method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
     method public android.database.Cursor swapCursor(android.database.Cursor);
     field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
@@ -40624,9 +41378,11 @@
     ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
     method public void dismiss();
     method public android.view.View.OnTouchListener getDragToOpenListener();
+    method public int getGravity();
     method public android.view.Menu getMenu();
     method public android.view.MenuInflater getMenuInflater();
     method public void inflate(int);
+    method public void setGravity(int);
     method public void setOnDismissListener(android.widget.PopupMenu.OnDismissListener);
     method public void setOnMenuItemClickListener(android.widget.PopupMenu.OnMenuItemClickListener);
     method public void show();
@@ -40659,6 +41415,7 @@
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
     method public int getMaxAvailableHeight(android.view.View, int);
+    method public boolean getOverlapAnchor();
     method public int getSoftInputMode();
     method public int getWidth();
     method public boolean isAboveAnchor();
@@ -40675,12 +41432,15 @@
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
+    method public void setEnterTransition(android.transition.Transition);
+    method public void setExitTransition(android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
     method public void setInputMethodMode(int);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
     method public void setOutsideTouchable(boolean);
+    method public void setOverlapAnchor(boolean);
     method public void setSoftInputMode(int);
     method public void setSplitTouchEnabled(boolean);
     method public void setTouchInterceptor(android.view.View.OnTouchListener);
@@ -40765,6 +41525,7 @@
     method public void setImageToDefault();
     method public void setMode(int);
     method public void setOverlay(android.graphics.drawable.Drawable);
+    method public void setPrioritizedMimeType(java.lang.String);
     field protected java.lang.String[] mExcludeMimes;
   }
 
@@ -40862,6 +41623,7 @@
     method public void addRule(int);
     method public void addRule(int, int);
     method public java.lang.String debug(java.lang.String);
+    method public int getRule(int);
     method public int[] getRules();
     method public void removeRule(int);
     field public boolean alignWithParent;
@@ -41096,15 +41858,17 @@
     method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
   }
 
-  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+  public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.Spinner.ThemedSpinnerAdapter {
     ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
     method public int getCount();
+    method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public java.lang.Object getItem(int);
     method public long getItemId(int);
     method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
     method public android.widget.SimpleAdapter.ViewBinder getViewBinder();
     method public void setDropDownViewResource(int);
+    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setViewBinder(android.widget.SimpleAdapter.ViewBinder);
     method public void setViewImage(android.widget.ImageView, int);
     method public void setViewImage(android.widget.ImageView, java.lang.String);
@@ -41223,11 +41987,13 @@
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int);
     ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int);
+    ctor public Spinner(android.content.Context, android.util.AttributeSet, int, int, int, android.content.Context);
     method public int getDropDownHorizontalOffset();
     method public int getDropDownVerticalOffset();
     method public int getDropDownWidth();
     method public int getGravity();
     method public android.graphics.drawable.Drawable getPopupBackground();
+    method public android.content.Context getPopupContext();
     method public java.lang.CharSequence getPrompt();
     method public void onClick(android.content.DialogInterface, int);
     method public void setDropDownHorizontalOffset(int);
@@ -41242,6 +42008,11 @@
     field public static final int MODE_DROPDOWN = 1; // 0x1
   }
 
+  public static abstract interface Spinner.ThemedSpinnerAdapter {
+    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  }
+
   public abstract interface SpinnerAdapter implements android.widget.Adapter {
     method public abstract android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
   }
@@ -41266,7 +42037,11 @@
     method public java.lang.CharSequence getTextOn();
     method public android.graphics.drawable.Drawable getThumbDrawable();
     method public int getThumbTextPadding();
+    method public android.content.res.ColorStateList getThumbTintList();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTrackDrawable();
+    method public android.content.res.ColorStateList getTrackTintList();
+    method public android.graphics.PorterDuff.Mode getTrackTintMode();
     method public void onMeasure(int, int);
     method public void setShowText(boolean);
     method public void setSplitTrack(boolean);
@@ -41280,8 +42055,12 @@
     method public void setThumbDrawable(android.graphics.drawable.Drawable);
     method public void setThumbResource(int);
     method public void setThumbTextPadding(int);
+    method public void setThumbTintList(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
     method public void setTrackDrawable(android.graphics.drawable.Drawable);
     method public void setTrackResource(int);
+    method public void setTrackTintList(android.content.res.ColorStateList);
+    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
@@ -41427,6 +42206,8 @@
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
     method public int getCompoundDrawablePadding();
+    method public android.content.res.ColorStateList getCompoundDrawableTintList();
+    method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
     method public android.graphics.drawable.Drawable[] getCompoundDrawables();
     method public android.graphics.drawable.Drawable[] getCompoundDrawablesRelative();
     method public int getCompoundPaddingBottom();
@@ -41526,6 +42307,8 @@
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
     method public void setCompoundDrawablePadding(int);
+    method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
+    method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
     method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public void setCompoundDrawablesRelative(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method public void setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int);
@@ -41710,7 +42493,11 @@
     method public void setNavigationIcon(int);
     method public void setNavigationIcon(android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setNavigationTintList(android.content.res.ColorStateList);
+    method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public void setSubtitle(int);
     method public void setSubtitle(java.lang.CharSequence);
@@ -44192,7 +44979,7 @@
     method public static double nextUp(double);
     method public static float nextUp(float);
     method public static double pow(double, double);
-    method public static synchronized double random();
+    method public static double random();
     method public static double rint(double);
     method public static long round(double);
     method public static int round(float);
@@ -56874,1105 +57661,13 @@
 
 }
 
-package org.apache.commons.logging {
-
-  public abstract deprecated interface Log {
-    method public abstract void debug(java.lang.Object);
-    method public abstract void debug(java.lang.Object, java.lang.Throwable);
-    method public abstract void error(java.lang.Object);
-    method public abstract void error(java.lang.Object, java.lang.Throwable);
-    method public abstract void fatal(java.lang.Object);
-    method public abstract void fatal(java.lang.Object, java.lang.Throwable);
-    method public abstract void info(java.lang.Object);
-    method public abstract void info(java.lang.Object, java.lang.Throwable);
-    method public abstract boolean isDebugEnabled();
-    method public abstract boolean isErrorEnabled();
-    method public abstract boolean isFatalEnabled();
-    method public abstract boolean isInfoEnabled();
-    method public abstract boolean isTraceEnabled();
-    method public abstract boolean isWarnEnabled();
-    method public abstract void trace(java.lang.Object);
-    method public abstract void trace(java.lang.Object, java.lang.Throwable);
-    method public abstract void warn(java.lang.Object);
-    method public abstract void warn(java.lang.Object, java.lang.Throwable);
-  }
-
-}
-
-package org.apache.http {
-
-  public deprecated class ConnectionClosedException extends java.io.IOException {
-    ctor public ConnectionClosedException(java.lang.String);
-  }
-
-  public abstract deprecated interface ConnectionReuseStrategy {
-    method public abstract boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface FormattedHeader implements org.apache.http.Header {
-    method public abstract org.apache.http.util.CharArrayBuffer getBuffer();
-    method public abstract int getValuePos();
-  }
-
-  public abstract deprecated interface Header {
-    method public abstract org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getValue();
-  }
-
-  public abstract deprecated interface HeaderElement {
-    method public abstract java.lang.String getName();
-    method public abstract org.apache.http.NameValuePair getParameter(int);
-    method public abstract org.apache.http.NameValuePair getParameterByName(java.lang.String);
-    method public abstract int getParameterCount();
-    method public abstract org.apache.http.NameValuePair[] getParameters();
-    method public abstract java.lang.String getValue();
-  }
-
-  public abstract deprecated interface HeaderElementIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract org.apache.http.HeaderElement nextElement();
-  }
-
-  public abstract deprecated interface HeaderIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract org.apache.http.Header nextHeader();
-  }
-
-  public abstract deprecated interface HttpClientConnection implements org.apache.http.HttpConnection {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract boolean isResponseAvailable(int) throws java.io.IOException;
-    method public abstract void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpConnection {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract org.apache.http.HttpConnectionMetrics getMetrics();
-    method public abstract int getSocketTimeout();
-    method public abstract boolean isOpen();
-    method public abstract boolean isStale();
-    method public abstract void setSocketTimeout(int);
-    method public abstract void shutdown() throws java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpConnectionMetrics {
-    method public abstract java.lang.Object getMetric(java.lang.String);
-    method public abstract long getReceivedBytesCount();
-    method public abstract long getRequestCount();
-    method public abstract long getResponseCount();
-    method public abstract long getSentBytesCount();
-    method public abstract void reset();
-  }
-
-  public abstract deprecated interface HttpEntity {
-    method public abstract void consumeContent() throws java.io.IOException;
-    method public abstract java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException;
-    method public abstract org.apache.http.Header getContentEncoding();
-    method public abstract long getContentLength();
-    method public abstract org.apache.http.Header getContentType();
-    method public abstract boolean isChunked();
-    method public abstract boolean isRepeatable();
-    method public abstract boolean isStreaming();
-    method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpEntityEnclosingRequest implements org.apache.http.HttpRequest {
-    method public abstract boolean expectContinue();
-    method public abstract org.apache.http.HttpEntity getEntity();
-    method public abstract void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class HttpException extends java.lang.Exception {
-    ctor public HttpException();
-    ctor public HttpException(java.lang.String);
-    ctor public HttpException(java.lang.String, java.lang.Throwable);
-  }
-
-  public final deprecated class HttpHost implements java.lang.Cloneable {
-    ctor public HttpHost(java.lang.String, int, java.lang.String);
-    ctor public HttpHost(java.lang.String, int);
-    ctor public HttpHost(java.lang.String);
-    ctor public HttpHost(org.apache.http.HttpHost);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getHostName();
-    method public int getPort();
-    method public java.lang.String getSchemeName();
-    method public java.lang.String toHostString();
-    method public java.lang.String toURI();
-    field public static final java.lang.String DEFAULT_SCHEME_NAME = "http";
-    field protected final java.lang.String hostname;
-    field protected final java.lang.String lcHostname;
-    field protected final int port;
-    field protected final java.lang.String schemeName;
-  }
-
-  public abstract deprecated interface HttpInetConnection implements org.apache.http.HttpConnection {
-    method public abstract java.net.InetAddress getLocalAddress();
-    method public abstract int getLocalPort();
-    method public abstract java.net.InetAddress getRemoteAddress();
-    method public abstract int getRemotePort();
-  }
-
-  public abstract deprecated interface HttpMessage {
-    method public abstract void addHeader(org.apache.http.Header);
-    method public abstract void addHeader(java.lang.String, java.lang.String);
-    method public abstract boolean containsHeader(java.lang.String);
-    method public abstract org.apache.http.Header[] getAllHeaders();
-    method public abstract org.apache.http.Header getFirstHeader(java.lang.String);
-    method public abstract org.apache.http.Header[] getHeaders(java.lang.String);
-    method public abstract org.apache.http.Header getLastHeader(java.lang.String);
-    method public abstract org.apache.http.params.HttpParams getParams();
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract org.apache.http.HeaderIterator headerIterator();
-    method public abstract org.apache.http.HeaderIterator headerIterator(java.lang.String);
-    method public abstract void removeHeader(org.apache.http.Header);
-    method public abstract void removeHeaders(java.lang.String);
-    method public abstract void setHeader(org.apache.http.Header);
-    method public abstract void setHeader(java.lang.String, java.lang.String);
-    method public abstract void setHeaders(org.apache.http.Header[]);
-    method public abstract void setParams(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated interface HttpRequest implements org.apache.http.HttpMessage {
-    method public abstract org.apache.http.RequestLine getRequestLine();
-  }
-
-  public abstract deprecated interface HttpRequestFactory {
-    method public abstract org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException;
-    method public abstract org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException;
-  }
-
-  public abstract deprecated interface HttpRequestInterceptor {
-    method public abstract void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpResponse implements org.apache.http.HttpMessage {
-    method public abstract org.apache.http.HttpEntity getEntity();
-    method public abstract java.util.Locale getLocale();
-    method public abstract org.apache.http.StatusLine getStatusLine();
-    method public abstract void setEntity(org.apache.http.HttpEntity);
-    method public abstract void setLocale(java.util.Locale);
-    method public abstract void setReasonPhrase(java.lang.String) throws java.lang.IllegalStateException;
-    method public abstract void setStatusCode(int) throws java.lang.IllegalStateException;
-    method public abstract void setStatusLine(org.apache.http.StatusLine);
-    method public abstract void setStatusLine(org.apache.http.ProtocolVersion, int);
-    method public abstract void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-  }
-
-  public abstract deprecated interface HttpResponseFactory {
-    method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.ProtocolVersion, int, org.apache.http.protocol.HttpContext);
-    method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.StatusLine, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface HttpResponseInterceptor {
-    method public abstract void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpServerConnection implements org.apache.http.HttpConnection {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract void receiveRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract org.apache.http.HttpRequest receiveRequestHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public abstract void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpStatus {
-    field public static final int SC_ACCEPTED = 202; // 0xca
-    field public static final int SC_BAD_GATEWAY = 502; // 0x1f6
-    field public static final int SC_BAD_REQUEST = 400; // 0x190
-    field public static final int SC_CONFLICT = 409; // 0x199
-    field public static final int SC_CONTINUE = 100; // 0x64
-    field public static final int SC_CREATED = 201; // 0xc9
-    field public static final int SC_EXPECTATION_FAILED = 417; // 0x1a1
-    field public static final int SC_FAILED_DEPENDENCY = 424; // 0x1a8
-    field public static final int SC_FORBIDDEN = 403; // 0x193
-    field public static final int SC_GATEWAY_TIMEOUT = 504; // 0x1f8
-    field public static final int SC_GONE = 410; // 0x19a
-    field public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; // 0x1f9
-    field public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; // 0x1a3
-    field public static final int SC_INSUFFICIENT_STORAGE = 507; // 0x1fb
-    field public static final int SC_INTERNAL_SERVER_ERROR = 500; // 0x1f4
-    field public static final int SC_LENGTH_REQUIRED = 411; // 0x19b
-    field public static final int SC_LOCKED = 423; // 0x1a7
-    field public static final int SC_METHOD_FAILURE = 420; // 0x1a4
-    field public static final int SC_METHOD_NOT_ALLOWED = 405; // 0x195
-    field public static final int SC_MOVED_PERMANENTLY = 301; // 0x12d
-    field public static final int SC_MOVED_TEMPORARILY = 302; // 0x12e
-    field public static final int SC_MULTIPLE_CHOICES = 300; // 0x12c
-    field public static final int SC_MULTI_STATUS = 207; // 0xcf
-    field public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; // 0xcb
-    field public static final int SC_NOT_ACCEPTABLE = 406; // 0x196
-    field public static final int SC_NOT_FOUND = 404; // 0x194
-    field public static final int SC_NOT_IMPLEMENTED = 501; // 0x1f5
-    field public static final int SC_NOT_MODIFIED = 304; // 0x130
-    field public static final int SC_NO_CONTENT = 204; // 0xcc
-    field public static final int SC_OK = 200; // 0xc8
-    field public static final int SC_PARTIAL_CONTENT = 206; // 0xce
-    field public static final int SC_PAYMENT_REQUIRED = 402; // 0x192
-    field public static final int SC_PRECONDITION_FAILED = 412; // 0x19c
-    field public static final int SC_PROCESSING = 102; // 0x66
-    field public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; // 0x197
-    field public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; // 0x1a0
-    field public static final int SC_REQUEST_TIMEOUT = 408; // 0x198
-    field public static final int SC_REQUEST_TOO_LONG = 413; // 0x19d
-    field public static final int SC_REQUEST_URI_TOO_LONG = 414; // 0x19e
-    field public static final int SC_RESET_CONTENT = 205; // 0xcd
-    field public static final int SC_SEE_OTHER = 303; // 0x12f
-    field public static final int SC_SERVICE_UNAVAILABLE = 503; // 0x1f7
-    field public static final int SC_SWITCHING_PROTOCOLS = 101; // 0x65
-    field public static final int SC_TEMPORARY_REDIRECT = 307; // 0x133
-    field public static final int SC_UNAUTHORIZED = 401; // 0x191
-    field public static final int SC_UNPROCESSABLE_ENTITY = 422; // 0x1a6
-    field public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; // 0x19f
-    field public static final int SC_USE_PROXY = 305; // 0x131
-  }
-
-  public final deprecated class HttpVersion extends org.apache.http.ProtocolVersion implements java.io.Serializable {
-    ctor public HttpVersion(int, int);
-    field public static final java.lang.String HTTP = "HTTP";
-    field public static final org.apache.http.HttpVersion HTTP_0_9;
-    field public static final org.apache.http.HttpVersion HTTP_1_0;
-    field public static final org.apache.http.HttpVersion HTTP_1_1;
-  }
-
-  public deprecated class MalformedChunkCodingException extends java.io.IOException {
-    ctor public MalformedChunkCodingException();
-    ctor public MalformedChunkCodingException(java.lang.String);
-  }
-
-  public deprecated class MethodNotSupportedException extends org.apache.http.HttpException {
-    ctor public MethodNotSupportedException(java.lang.String);
-    ctor public MethodNotSupportedException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface NameValuePair {
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getValue();
-  }
-
-  public deprecated class NoHttpResponseException extends java.io.IOException {
-    ctor public NoHttpResponseException(java.lang.String);
-  }
-
-  public deprecated class ParseException extends java.lang.RuntimeException {
-    ctor public ParseException();
-    ctor public ParseException(java.lang.String);
-  }
-
-  public deprecated class ProtocolException extends org.apache.http.HttpException {
-    ctor public ProtocolException();
-    ctor public ProtocolException(java.lang.String);
-    ctor public ProtocolException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class ProtocolVersion implements java.lang.Cloneable java.io.Serializable {
-    ctor public ProtocolVersion(java.lang.String, int, int);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public int compareToVersion(org.apache.http.ProtocolVersion);
-    method public final boolean equals(java.lang.Object);
-    method public org.apache.http.ProtocolVersion forVersion(int, int);
-    method public final int getMajor();
-    method public final int getMinor();
-    method public final java.lang.String getProtocol();
-    method public final boolean greaterEquals(org.apache.http.ProtocolVersion);
-    method public final int hashCode();
-    method public boolean isComparable(org.apache.http.ProtocolVersion);
-    method public final boolean lessEquals(org.apache.http.ProtocolVersion);
-    field protected final int major;
-    field protected final int minor;
-    field protected final java.lang.String protocol;
-  }
-
-  public abstract deprecated interface ReasonPhraseCatalog {
-    method public abstract java.lang.String getReason(int, java.util.Locale);
-  }
-
-  public abstract deprecated interface RequestLine {
-    method public abstract java.lang.String getMethod();
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract java.lang.String getUri();
-  }
-
-  public abstract deprecated interface StatusLine {
-    method public abstract org.apache.http.ProtocolVersion getProtocolVersion();
-    method public abstract java.lang.String getReasonPhrase();
-    method public abstract int getStatusCode();
-  }
-
-  public abstract deprecated interface TokenIterator implements java.util.Iterator {
-    method public abstract boolean hasNext();
-    method public abstract java.lang.String nextToken();
-  }
-
-  public deprecated class UnsupportedHttpVersionException extends org.apache.http.ProtocolException {
-    ctor public UnsupportedHttpVersionException();
-    ctor public UnsupportedHttpVersionException(java.lang.String);
-  }
-
-}
-
-package org.apache.http.auth {
-
-  public final deprecated class AUTH {
-    field public static final java.lang.String PROXY_AUTH = "Proxy-Authenticate";
-    field public static final java.lang.String PROXY_AUTH_RESP = "Proxy-Authorization";
-    field public static final java.lang.String WWW_AUTH = "WWW-Authenticate";
-    field public static final java.lang.String WWW_AUTH_RESP = "Authorization";
-  }
-
-  public abstract deprecated interface AuthScheme {
-    method public abstract org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public abstract java.lang.String getParameter(java.lang.String);
-    method public abstract java.lang.String getRealm();
-    method public abstract java.lang.String getSchemeName();
-    method public abstract boolean isComplete();
-    method public abstract boolean isConnectionBased();
-    method public abstract void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public abstract deprecated interface AuthSchemeFactory {
-    method public abstract org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public final deprecated class AuthSchemeRegistry {
-    ctor public AuthSchemeRegistry();
-    method public synchronized org.apache.http.auth.AuthScheme getAuthScheme(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException;
-    method public synchronized java.util.List<java.lang.String> getSchemeNames();
-    method public synchronized void register(java.lang.String, org.apache.http.auth.AuthSchemeFactory);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.auth.AuthSchemeFactory>);
-    method public synchronized void unregister(java.lang.String);
-  }
-
-  public deprecated class AuthScope {
-    ctor public AuthScope(java.lang.String, int, java.lang.String, java.lang.String);
-    ctor public AuthScope(java.lang.String, int, java.lang.String);
-    ctor public AuthScope(java.lang.String, int);
-    ctor public AuthScope(org.apache.http.auth.AuthScope);
-    method public java.lang.String getHost();
-    method public int getPort();
-    method public java.lang.String getRealm();
-    method public java.lang.String getScheme();
-    method public int match(org.apache.http.auth.AuthScope);
-    field public static final org.apache.http.auth.AuthScope ANY;
-    field public static final java.lang.String ANY_HOST;
-    field public static final int ANY_PORT = -1; // 0xffffffff
-    field public static final java.lang.String ANY_REALM;
-    field public static final java.lang.String ANY_SCHEME;
-  }
-
-  public deprecated class AuthState {
-    ctor public AuthState();
-    method public org.apache.http.auth.AuthScheme getAuthScheme();
-    method public org.apache.http.auth.AuthScope getAuthScope();
-    method public org.apache.http.auth.Credentials getCredentials();
-    method public void invalidate();
-    method public boolean isValid();
-    method public void setAuthScheme(org.apache.http.auth.AuthScheme);
-    method public void setAuthScope(org.apache.http.auth.AuthScope);
-    method public void setCredentials(org.apache.http.auth.Credentials);
-  }
-
-  public deprecated class AuthenticationException extends org.apache.http.ProtocolException {
-    ctor public AuthenticationException();
-    ctor public AuthenticationException(java.lang.String);
-    ctor public AuthenticationException(java.lang.String, java.lang.Throwable);
-  }
-
-  public final deprecated class BasicUserPrincipal implements java.security.Principal {
-    ctor public BasicUserPrincipal(java.lang.String);
-    method public java.lang.String getName();
-  }
-
-  public abstract deprecated interface Credentials {
-    method public abstract java.lang.String getPassword();
-    method public abstract java.security.Principal getUserPrincipal();
-  }
-
-  public deprecated class InvalidCredentialsException extends org.apache.http.auth.AuthenticationException {
-    ctor public InvalidCredentialsException();
-    ctor public InvalidCredentialsException(java.lang.String);
-    ctor public InvalidCredentialsException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class MalformedChallengeException extends org.apache.http.ProtocolException {
-    ctor public MalformedChallengeException();
-    ctor public MalformedChallengeException(java.lang.String);
-    ctor public MalformedChallengeException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class NTCredentials implements org.apache.http.auth.Credentials {
-    ctor public NTCredentials(java.lang.String);
-    ctor public NTCredentials(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getDomain();
-    method public java.lang.String getPassword();
-    method public java.lang.String getUserName();
-    method public java.security.Principal getUserPrincipal();
-    method public java.lang.String getWorkstation();
-  }
-
-  public deprecated class NTUserPrincipal implements java.security.Principal {
-    ctor public NTUserPrincipal(java.lang.String, java.lang.String);
-    method public java.lang.String getDomain();
-    method public java.lang.String getName();
-    method public java.lang.String getUsername();
-  }
-
-  public deprecated class UsernamePasswordCredentials implements org.apache.http.auth.Credentials {
-    ctor public UsernamePasswordCredentials(java.lang.String);
-    ctor public UsernamePasswordCredentials(java.lang.String, java.lang.String);
-    method public java.lang.String getPassword();
-    method public java.lang.String getUserName();
-    method public java.security.Principal getUserPrincipal();
-  }
-
-}
-
-package org.apache.http.auth.params {
-
-  public abstract deprecated interface AuthPNames {
-    field public static final java.lang.String CREDENTIAL_CHARSET = "http.auth.credential-charset";
-  }
-
-  public deprecated class AuthParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public AuthParamBean(org.apache.http.params.HttpParams);
-    method public void setCredentialCharset(java.lang.String);
-  }
-
-  public final deprecated class AuthParams {
-    method public static java.lang.String getCredentialCharset(org.apache.http.params.HttpParams);
-    method public static void setCredentialCharset(org.apache.http.params.HttpParams, java.lang.String);
-  }
-
-}
-
-package org.apache.http.client {
-
-  public abstract deprecated interface AuthenticationHandler {
-    method public abstract java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public abstract boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-    method public abstract org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException;
-  }
-
-  public deprecated class CircularRedirectException extends org.apache.http.client.RedirectException {
-    ctor public CircularRedirectException();
-    ctor public CircularRedirectException(java.lang.String);
-    ctor public CircularRedirectException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class ClientProtocolException extends java.io.IOException {
-    ctor public ClientProtocolException();
-    ctor public ClientProtocolException(java.lang.String);
-    ctor public ClientProtocolException(java.lang.Throwable);
-    ctor public ClientProtocolException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface CookieStore {
-    method public abstract void addCookie(org.apache.http.cookie.Cookie);
-    method public abstract void clear();
-    method public abstract boolean clearExpired(java.util.Date);
-    method public abstract java.util.List<org.apache.http.cookie.Cookie> getCookies();
-  }
-
-  public abstract deprecated interface CredentialsProvider {
-    method public abstract void clear();
-    method public abstract org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope);
-    method public abstract void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials);
-  }
-
-  public abstract deprecated interface HttpClient {
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public abstract org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public abstract org.apache.http.params.HttpParams getParams();
-  }
-
-  public abstract deprecated interface HttpRequestRetryHandler {
-    method public abstract boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class HttpResponseException extends org.apache.http.client.ClientProtocolException {
-    ctor public HttpResponseException(int, java.lang.String);
-    method public int getStatusCode();
-  }
-
-  public deprecated class NonRepeatableRequestException extends org.apache.http.ProtocolException {
-    ctor public NonRepeatableRequestException();
-    ctor public NonRepeatableRequestException(java.lang.String);
-  }
-
-  public deprecated class RedirectException extends org.apache.http.ProtocolException {
-    ctor public RedirectException();
-    ctor public RedirectException(java.lang.String);
-    ctor public RedirectException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface RedirectHandler {
-    method public abstract java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException;
-    method public abstract boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public abstract deprecated interface RequestDirector {
-    method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface ResponseHandler {
-    method public abstract T handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-  }
-
-  public abstract deprecated interface UserTokenHandler {
-    method public abstract java.lang.Object getUserToken(org.apache.http.protocol.HttpContext);
-  }
-
-}
-
-package org.apache.http.client.entity {
-
-  public deprecated class UrlEncodedFormEntity extends org.apache.http.entity.StringEntity {
-    ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>) throws java.io.UnsupportedEncodingException;
-  }
-
-}
-
-package org.apache.http.client.methods {
-
-  public abstract deprecated interface AbortableHttpRequest {
-    method public abstract void abort();
-    method public abstract void setConnectionRequest(org.apache.http.conn.ClientConnectionRequest) throws java.io.IOException;
-    method public abstract void setReleaseTrigger(org.apache.http.conn.ConnectionReleaseTrigger) throws java.io.IOException;
-  }
-
-  public deprecated class HttpDelete extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpDelete();
-    ctor public HttpDelete(java.net.URI);
-    ctor public HttpDelete(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "DELETE";
-  }
-
-  public abstract deprecated class HttpEntityEnclosingRequestBase extends org.apache.http.client.methods.HttpRequestBase implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public HttpEntityEnclosingRequestBase();
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class HttpGet extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpGet();
-    ctor public HttpGet(java.net.URI);
-    ctor public HttpGet(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "GET";
-  }
-
-  public deprecated class HttpHead extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpHead();
-    ctor public HttpHead(java.net.URI);
-    ctor public HttpHead(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "HEAD";
-  }
-
-  public deprecated class HttpOptions extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpOptions();
-    ctor public HttpOptions(java.net.URI);
-    ctor public HttpOptions(java.lang.String);
-    method public java.util.Set<java.lang.String> getAllowedMethods(org.apache.http.HttpResponse);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "OPTIONS";
-  }
-
-  public deprecated class HttpPost extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase {
-    ctor public HttpPost();
-    ctor public HttpPost(java.net.URI);
-    ctor public HttpPost(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "POST";
-  }
-
-  public deprecated class HttpPut extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase {
-    ctor public HttpPut();
-    ctor public HttpPut(java.net.URI);
-    ctor public HttpPut(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "PUT";
-  }
-
-  public abstract deprecated class HttpRequestBase extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.AbortableHttpRequest java.lang.Cloneable org.apache.http.client.methods.HttpUriRequest {
-    ctor public HttpRequestBase();
-    method public void abort();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public abstract java.lang.String getMethod();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-    method public java.net.URI getURI();
-    method public boolean isAborted();
-    method public void setConnectionRequest(org.apache.http.conn.ClientConnectionRequest) throws java.io.IOException;
-    method public void setReleaseTrigger(org.apache.http.conn.ConnectionReleaseTrigger) throws java.io.IOException;
-    method public void setURI(java.net.URI);
-  }
-
-  public deprecated class HttpTrace extends org.apache.http.client.methods.HttpRequestBase {
-    ctor public HttpTrace();
-    ctor public HttpTrace(java.net.URI);
-    ctor public HttpTrace(java.lang.String);
-    method public java.lang.String getMethod();
-    field public static final java.lang.String METHOD_NAME = "TRACE";
-  }
-
-  public abstract deprecated interface HttpUriRequest implements org.apache.http.HttpRequest {
-    method public abstract void abort() throws java.lang.UnsupportedOperationException;
-    method public abstract java.lang.String getMethod();
-    method public abstract java.net.URI getURI();
-    method public abstract boolean isAborted();
-  }
-
-}
-
-package org.apache.http.client.params {
-
-  public abstract deprecated interface AllClientPNames implements org.apache.http.auth.params.AuthPNames org.apache.http.client.params.ClientPNames org.apache.http.conn.params.ConnConnectionPNames org.apache.http.conn.params.ConnManagerPNames org.apache.http.conn.params.ConnRoutePNames org.apache.http.cookie.params.CookieSpecPNames org.apache.http.params.CoreConnectionPNames org.apache.http.params.CoreProtocolPNames {
-  }
-
-  public final deprecated class AuthPolicy {
-    field public static final java.lang.String BASIC = "Basic";
-    field public static final java.lang.String DIGEST = "Digest";
-    field public static final java.lang.String NTLM = "NTLM";
-  }
-
-  public abstract deprecated interface ClientPNames {
-    field public static final java.lang.String ALLOW_CIRCULAR_REDIRECTS = "http.protocol.allow-circular-redirects";
-    field public static final java.lang.String CONNECTION_MANAGER_FACTORY = "http.connection-manager.factory-object";
-    field public static final java.lang.String CONNECTION_MANAGER_FACTORY_CLASS_NAME = "http.connection-manager.factory-class-name";
-    field public static final java.lang.String COOKIE_POLICY = "http.protocol.cookie-policy";
-    field public static final java.lang.String DEFAULT_HEADERS = "http.default-headers";
-    field public static final java.lang.String DEFAULT_HOST = "http.default-host";
-    field public static final java.lang.String HANDLE_AUTHENTICATION = "http.protocol.handle-authentication";
-    field public static final java.lang.String HANDLE_REDIRECTS = "http.protocol.handle-redirects";
-    field public static final java.lang.String MAX_REDIRECTS = "http.protocol.max-redirects";
-    field public static final java.lang.String REJECT_RELATIVE_REDIRECT = "http.protocol.reject-relative-redirect";
-    field public static final java.lang.String VIRTUAL_HOST = "http.virtual-host";
-  }
-
-  public deprecated class ClientParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ClientParamBean(org.apache.http.params.HttpParams);
-    method public void setAllowCircularRedirects(boolean);
-    method public void setConnectionManagerFactory(org.apache.http.conn.ClientConnectionManagerFactory);
-    method public void setConnectionManagerFactoryClassName(java.lang.String);
-    method public void setCookiePolicy(java.lang.String);
-    method public void setDefaultHeaders(java.util.Collection<org.apache.http.Header>);
-    method public void setDefaultHost(org.apache.http.HttpHost);
-    method public void setHandleAuthentication(boolean);
-    method public void setHandleRedirects(boolean);
-    method public void setMaxRedirects(int);
-    method public void setRejectRelativeRedirect(boolean);
-    method public void setVirtualHost(org.apache.http.HttpHost);
-  }
-
-  public final deprecated class CookiePolicy {
-    field public static final java.lang.String BEST_MATCH = "best-match";
-    field public static final java.lang.String BROWSER_COMPATIBILITY = "compatibility";
-    field public static final java.lang.String NETSCAPE = "netscape";
-    field public static final java.lang.String RFC_2109 = "rfc2109";
-    field public static final java.lang.String RFC_2965 = "rfc2965";
-  }
-
-  public deprecated class HttpClientParams {
-    method public static java.lang.String getCookiePolicy(org.apache.http.params.HttpParams);
-    method public static boolean isAuthenticating(org.apache.http.params.HttpParams);
-    method public static boolean isRedirecting(org.apache.http.params.HttpParams);
-    method public static void setAuthenticating(org.apache.http.params.HttpParams, boolean);
-    method public static void setCookiePolicy(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setRedirecting(org.apache.http.params.HttpParams, boolean);
-  }
-
-}
-
-package org.apache.http.client.protocol {
-
-  public abstract deprecated interface ClientContext {
-    field public static final java.lang.String AUTHSCHEME_REGISTRY = "http.authscheme-registry";
-    field public static final java.lang.String AUTH_SCHEME_PREF = "http.auth.scheme-pref";
-    field public static final java.lang.String COOKIESPEC_REGISTRY = "http.cookiespec-registry";
-    field public static final java.lang.String COOKIE_ORIGIN = "http.cookie-origin";
-    field public static final java.lang.String COOKIE_SPEC = "http.cookie-spec";
-    field public static final java.lang.String COOKIE_STORE = "http.cookie-store";
-    field public static final java.lang.String CREDS_PROVIDER = "http.auth.credentials-provider";
-    field public static final java.lang.String PROXY_AUTH_STATE = "http.auth.proxy-scope";
-    field public static final java.lang.String TARGET_AUTH_STATE = "http.auth.target-scope";
-    field public static final java.lang.String USER_TOKEN = "http.user-token";
-  }
-
-  public deprecated class ClientContextConfigurer implements org.apache.http.client.protocol.ClientContext {
-    ctor public ClientContextConfigurer(org.apache.http.protocol.HttpContext);
-    method public void setAuthSchemePref(java.util.List<java.lang.String>);
-    method public void setAuthSchemeRegistry(org.apache.http.auth.AuthSchemeRegistry);
-    method public void setCookieSpecRegistry(org.apache.http.cookie.CookieSpecRegistry);
-    method public void setCookieStore(org.apache.http.client.CookieStore);
-    method public void setCredentialsProvider(org.apache.http.client.CredentialsProvider);
-  }
-
-  public deprecated class RequestAddCookies implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestAddCookies();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestDefaultHeaders implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestDefaultHeaders();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestProxyAuthentication implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestProxyAuthentication();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestTargetAuthentication implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestTargetAuthentication();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseProcessCookies implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseProcessCookies();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-}
-
-package org.apache.http.client.utils {
-
-  public deprecated class CloneUtils {
-    method public static java.lang.Object clone(java.lang.Object) throws java.lang.CloneNotSupportedException;
-  }
-
-  public deprecated class URIUtils {
-    method public static java.net.URI createURI(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
-    method public static java.net.URI resolve(java.net.URI, java.lang.String);
-    method public static java.net.URI resolve(java.net.URI, java.net.URI);
-    method public static java.net.URI rewriteURI(java.net.URI, org.apache.http.HttpHost, boolean) throws java.net.URISyntaxException;
-    method public static java.net.URI rewriteURI(java.net.URI, org.apache.http.HttpHost) throws java.net.URISyntaxException;
-  }
-
-  public deprecated class URLEncodedUtils {
-    ctor public URLEncodedUtils();
-    method public static java.lang.String format(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String);
-    method public static boolean isEncoded(org.apache.http.HttpEntity);
-    method public static java.util.List<org.apache.http.NameValuePair> parse(java.net.URI, java.lang.String);
-    method public static java.util.List<org.apache.http.NameValuePair> parse(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static void parse(java.util.List<org.apache.http.NameValuePair>, java.util.Scanner, java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "application/x-www-form-urlencoded";
-  }
-
-}
-
 package org.apache.http.conn {
 
-  public deprecated class BasicEofSensorWatcher implements org.apache.http.conn.EofSensorWatcher {
-    ctor public BasicEofSensorWatcher(org.apache.http.conn.ManagedClientConnection, boolean);
-    method public boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-    field protected boolean attemptReuse;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-  }
-
-  public deprecated class BasicManagedEntity extends org.apache.http.entity.HttpEntityWrapper implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.conn.EofSensorWatcher {
-    ctor public BasicManagedEntity(org.apache.http.HttpEntity, org.apache.http.conn.ManagedClientConnection, boolean);
-    method public void abortConnection() throws java.io.IOException;
-    method public boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public void releaseConnection() throws java.io.IOException;
-    method protected void releaseManagedConnection() throws java.io.IOException;
-    method public boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-    field protected final boolean attemptReuse;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-  }
-
-  public abstract deprecated interface ClientConnectionManager {
-    method public abstract void closeExpiredConnections();
-    method public abstract void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method public abstract org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public abstract void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public abstract org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public abstract void shutdown();
-  }
-
-  public abstract deprecated interface ClientConnectionManagerFactory {
-    method public abstract org.apache.http.conn.ClientConnectionManager newInstance(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-  }
-
-  public abstract deprecated interface ClientConnectionOperator {
-    method public abstract org.apache.http.conn.OperatedClientConnection createConnection();
-    method public abstract void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void updateSecureConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public abstract deprecated interface ClientConnectionRequest {
-    method public abstract void abortRequest();
-    method public abstract org.apache.http.conn.ManagedClientConnection getConnection(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-  }
-
   public deprecated class ConnectTimeoutException extends java.io.InterruptedIOException {
     ctor public ConnectTimeoutException();
     ctor public ConnectTimeoutException(java.lang.String);
   }
 
-  public abstract deprecated interface ConnectionKeepAliveStrategy {
-    method public abstract long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class ConnectionPoolTimeoutException extends org.apache.http.conn.ConnectTimeoutException {
-    ctor public ConnectionPoolTimeoutException();
-    ctor public ConnectionPoolTimeoutException(java.lang.String);
-  }
-
-  public abstract deprecated interface ConnectionReleaseTrigger {
-    method public abstract void abortConnection() throws java.io.IOException;
-    method public abstract void releaseConnection() throws java.io.IOException;
-  }
-
-  public deprecated class EofSensorInputStream extends java.io.InputStream implements org.apache.http.conn.ConnectionReleaseTrigger {
-    ctor public EofSensorInputStream(java.io.InputStream, org.apache.http.conn.EofSensorWatcher);
-    method public void abortConnection() throws java.io.IOException;
-    method protected void checkAbort() throws java.io.IOException;
-    method protected void checkClose() throws java.io.IOException;
-    method protected void checkEOF(int) throws java.io.IOException;
-    method protected boolean isReadAllowed() throws java.io.IOException;
-    method public int read() throws java.io.IOException;
-    method public void releaseConnection() throws java.io.IOException;
-    field protected java.io.InputStream wrappedStream;
-  }
-
-  public abstract deprecated interface EofSensorWatcher {
-    method public abstract boolean eofDetected(java.io.InputStream) throws java.io.IOException;
-    method public abstract boolean streamAbort(java.io.InputStream) throws java.io.IOException;
-    method public abstract boolean streamClosed(java.io.InputStream) throws java.io.IOException;
-  }
-
-  public deprecated class HttpHostConnectException extends java.net.ConnectException {
-    ctor public HttpHostConnectException(org.apache.http.HttpHost, java.net.ConnectException);
-    method public org.apache.http.HttpHost getHost();
-  }
-
-  public abstract deprecated interface ManagedClientConnection implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection {
-    method public abstract org.apache.http.conn.routing.HttpRoute getRoute();
-    method public abstract javax.net.ssl.SSLSession getSSLSession();
-    method public abstract java.lang.Object getState();
-    method public abstract boolean isMarkedReusable();
-    method public abstract boolean isSecure();
-    method public abstract void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void markReusable();
-    method public abstract void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void setIdleDuration(long, java.util.concurrent.TimeUnit);
-    method public abstract void setState(java.lang.Object);
-    method public abstract void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void unmarkReusable();
-  }
-
-  public final deprecated class MultihomePlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory {
-    method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.Socket createSocket();
-    method public static org.apache.http.conn.MultihomePlainSocketFactory getSocketFactory();
-    method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
-  }
-
-  public abstract deprecated interface OperatedClientConnection implements org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection {
-    method public abstract java.net.Socket getSocket();
-    method public abstract org.apache.http.HttpHost getTargetHost();
-    method public abstract boolean isSecure();
-    method public abstract void openCompleted(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public abstract void opening(java.net.Socket, org.apache.http.HttpHost) throws java.io.IOException;
-    method public abstract void update(java.net.Socket, org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.conn.params {
-
-  public abstract deprecated interface ConnConnectionPNames {
-    field public static final java.lang.String MAX_STATUS_LINE_GARBAGE = "http.connection.max-status-line-garbage";
-  }
-
-  public deprecated class ConnConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnConnectionParamBean(org.apache.http.params.HttpParams);
-    method public void setMaxStatusLineGarbage(int);
-  }
-
-  public abstract deprecated interface ConnManagerPNames {
-    field public static final java.lang.String MAX_CONNECTIONS_PER_ROUTE = "http.conn-manager.max-per-route";
-    field public static final java.lang.String MAX_TOTAL_CONNECTIONS = "http.conn-manager.max-total";
-    field public static final java.lang.String TIMEOUT = "http.conn-manager.timeout";
-  }
-
-  public deprecated class ConnManagerParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnManagerParamBean(org.apache.http.params.HttpParams);
-    method public void setConnectionsPerRoute(org.apache.http.conn.params.ConnPerRouteBean);
-    method public void setMaxTotalConnections(int);
-    method public void setTimeout(long);
-  }
-
-  public final deprecated class ConnManagerParams implements org.apache.http.conn.params.ConnManagerPNames {
-    ctor public ConnManagerParams();
-    method public static org.apache.http.conn.params.ConnPerRoute getMaxConnectionsPerRoute(org.apache.http.params.HttpParams);
-    method public static int getMaxTotalConnections(org.apache.http.params.HttpParams);
-    method public static long getTimeout(org.apache.http.params.HttpParams);
-    method public static void setMaxConnectionsPerRoute(org.apache.http.params.HttpParams, org.apache.http.conn.params.ConnPerRoute);
-    method public static void setMaxTotalConnections(org.apache.http.params.HttpParams, int);
-    method public static void setTimeout(org.apache.http.params.HttpParams, long);
-    field public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20; // 0x14
-  }
-
-  public abstract deprecated interface ConnPerRoute {
-    method public abstract int getMaxForRoute(org.apache.http.conn.routing.HttpRoute);
-  }
-
-  public final deprecated class ConnPerRouteBean implements org.apache.http.conn.params.ConnPerRoute {
-    ctor public ConnPerRouteBean(int);
-    ctor public ConnPerRouteBean();
-    method public int getDefaultMax();
-    method public int getMaxForRoute(org.apache.http.conn.routing.HttpRoute);
-    method public void setDefaultMaxPerRoute(int);
-    method public void setMaxForRoute(org.apache.http.conn.routing.HttpRoute, int);
-    method public void setMaxForRoutes(java.util.Map<org.apache.http.conn.routing.HttpRoute, java.lang.Integer>);
-    field public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2; // 0x2
-  }
-
-  public abstract deprecated interface ConnRoutePNames {
-    field public static final java.lang.String DEFAULT_PROXY = "http.route.default-proxy";
-    field public static final java.lang.String FORCED_ROUTE = "http.route.forced-route";
-    field public static final java.lang.String LOCAL_ADDRESS = "http.route.local-address";
-  }
-
-  public deprecated class ConnRouteParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public ConnRouteParamBean(org.apache.http.params.HttpParams);
-    method public void setDefaultProxy(org.apache.http.HttpHost);
-    method public void setForcedRoute(org.apache.http.conn.routing.HttpRoute);
-    method public void setLocalAddress(java.net.InetAddress);
-  }
-
-  public deprecated class ConnRouteParams implements org.apache.http.conn.params.ConnRoutePNames {
-    method public static org.apache.http.HttpHost getDefaultProxy(org.apache.http.params.HttpParams);
-    method public static org.apache.http.conn.routing.HttpRoute getForcedRoute(org.apache.http.params.HttpParams);
-    method public static java.net.InetAddress getLocalAddress(org.apache.http.params.HttpParams);
-    method public static void setDefaultProxy(org.apache.http.params.HttpParams, org.apache.http.HttpHost);
-    method public static void setForcedRoute(org.apache.http.params.HttpParams, org.apache.http.conn.routing.HttpRoute);
-    method public static void setLocalAddress(org.apache.http.params.HttpParams, java.net.InetAddress);
-    field public static final org.apache.http.HttpHost NO_HOST;
-    field public static final org.apache.http.conn.routing.HttpRoute NO_ROUTE;
-  }
-
-}
-
-package org.apache.http.conn.routing {
-
-  public deprecated class BasicRouteDirector implements org.apache.http.conn.routing.HttpRouteDirector {
-    ctor public BasicRouteDirector();
-    method protected int directStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    method protected int firstStep(org.apache.http.conn.routing.RouteInfo);
-    method public int nextStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    method protected int proxiedStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-  }
-
-  public final deprecated class HttpRoute implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo {
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost[], boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost, boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, boolean);
-    ctor public HttpRoute(org.apache.http.HttpHost);
-    ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost, boolean);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public final boolean equals(java.lang.Object);
-    method public final int getHopCount();
-    method public final org.apache.http.HttpHost getHopTarget(int);
-    method public final org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public final java.net.InetAddress getLocalAddress();
-    method public final org.apache.http.HttpHost getProxyHost();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public final int hashCode();
-    method public final boolean isLayered();
-    method public final boolean isSecure();
-    method public final boolean isTunnelled();
-    method public final java.lang.String toString();
-  }
-
-  public abstract deprecated interface HttpRouteDirector {
-    method public abstract int nextStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo);
-    field public static final int COMPLETE = 0; // 0x0
-    field public static final int CONNECT_PROXY = 2; // 0x2
-    field public static final int CONNECT_TARGET = 1; // 0x1
-    field public static final int LAYER_PROTOCOL = 5; // 0x5
-    field public static final int TUNNEL_PROXY = 4; // 0x4
-    field public static final int TUNNEL_TARGET = 3; // 0x3
-    field public static final int UNREACHABLE = -1; // 0xffffffff
-  }
-
-  public abstract deprecated interface HttpRoutePlanner {
-    method public abstract org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-  }
-
-  public abstract deprecated interface RouteInfo {
-    method public abstract int getHopCount();
-    method public abstract org.apache.http.HttpHost getHopTarget(int);
-    method public abstract org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public abstract java.net.InetAddress getLocalAddress();
-    method public abstract org.apache.http.HttpHost getProxyHost();
-    method public abstract org.apache.http.HttpHost getTargetHost();
-    method public abstract org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public abstract boolean isLayered();
-    method public abstract boolean isSecure();
-    method public abstract boolean isTunnelled();
-  }
-
-  public static final class RouteInfo.LayerType extends java.lang.Enum {
-    method public static org.apache.http.conn.routing.RouteInfo.LayerType valueOf(java.lang.String);
-    method public static final org.apache.http.conn.routing.RouteInfo.LayerType[] values();
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.LayerType LAYERED;
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.LayerType PLAIN;
-  }
-
-  public static final class RouteInfo.TunnelType extends java.lang.Enum {
-    method public static org.apache.http.conn.routing.RouteInfo.TunnelType valueOf(java.lang.String);
-    method public static final org.apache.http.conn.routing.RouteInfo.TunnelType[] values();
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.TunnelType PLAIN;
-    enum_constant public static final org.apache.http.conn.routing.RouteInfo.TunnelType TUNNELLED;
-  }
-
-  public final deprecated class RouteTracker implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo {
-    ctor public RouteTracker(org.apache.http.HttpHost, java.net.InetAddress);
-    ctor public RouteTracker(org.apache.http.conn.routing.HttpRoute);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public final void connectProxy(org.apache.http.HttpHost, boolean);
-    method public final void connectTarget(boolean);
-    method public final boolean equals(java.lang.Object);
-    method public final int getHopCount();
-    method public final org.apache.http.HttpHost getHopTarget(int);
-    method public final org.apache.http.conn.routing.RouteInfo.LayerType getLayerType();
-    method public final java.net.InetAddress getLocalAddress();
-    method public final org.apache.http.HttpHost getProxyHost();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final org.apache.http.conn.routing.RouteInfo.TunnelType getTunnelType();
-    method public final int hashCode();
-    method public final boolean isConnected();
-    method public final boolean isLayered();
-    method public final boolean isSecure();
-    method public final boolean isTunnelled();
-    method public final void layerProtocol(boolean);
-    method public final org.apache.http.conn.routing.HttpRoute toRoute();
-    method public final java.lang.String toString();
-    method public final void tunnelProxy(org.apache.http.HttpHost, boolean);
-    method public final void tunnelTarget(boolean);
-  }
-
 }
 
 package org.apache.http.conn.scheme {
@@ -57985,37 +57680,6 @@
     method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
   }
 
-  public final deprecated class PlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory {
-    ctor public PlainSocketFactory(org.apache.http.conn.scheme.HostNameResolver);
-    ctor public PlainSocketFactory();
-    method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.Socket createSocket();
-    method public static org.apache.http.conn.scheme.PlainSocketFactory getSocketFactory();
-    method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
-  }
-
-  public final deprecated class Scheme {
-    ctor public Scheme(java.lang.String, org.apache.http.conn.scheme.SocketFactory, int);
-    method public final boolean equals(java.lang.Object);
-    method public final int getDefaultPort();
-    method public final java.lang.String getName();
-    method public final org.apache.http.conn.scheme.SocketFactory getSocketFactory();
-    method public final boolean isLayered();
-    method public final int resolvePort(int);
-    method public final java.lang.String toString();
-  }
-
-  public final deprecated class SchemeRegistry {
-    ctor public SchemeRegistry();
-    method public final synchronized org.apache.http.conn.scheme.Scheme get(java.lang.String);
-    method public final synchronized org.apache.http.conn.scheme.Scheme getScheme(java.lang.String);
-    method public final synchronized org.apache.http.conn.scheme.Scheme getScheme(org.apache.http.HttpHost);
-    method public final synchronized java.util.List<java.lang.String> getSchemeNames();
-    method public final synchronized org.apache.http.conn.scheme.Scheme register(org.apache.http.conn.scheme.Scheme);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.conn.scheme.Scheme>);
-    method public final synchronized org.apache.http.conn.scheme.Scheme unregister(java.lang.String);
-  }
-
   public abstract deprecated interface SocketFactory {
     method public abstract java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws org.apache.http.conn.ConnectTimeoutException, java.io.IOException, java.net.UnknownHostException;
     method public abstract java.net.Socket createSocket() throws java.io.IOException;
@@ -58085,1818 +57749,8 @@
 
 }
 
-package org.apache.http.conn.util {
-
-  public deprecated class InetAddressUtils {
-    method public static boolean isIPv4Address(java.lang.String);
-    method public static boolean isIPv6Address(java.lang.String);
-    method public static boolean isIPv6HexCompressedAddress(java.lang.String);
-    method public static boolean isIPv6StdAddress(java.lang.String);
-  }
-
-}
-
-package org.apache.http.cookie {
-
-  public abstract deprecated interface ClientCookie implements org.apache.http.cookie.Cookie {
-    method public abstract boolean containsAttribute(java.lang.String);
-    method public abstract java.lang.String getAttribute(java.lang.String);
-    field public static final java.lang.String COMMENTURL_ATTR = "commenturl";
-    field public static final java.lang.String COMMENT_ATTR = "comment";
-    field public static final java.lang.String DISCARD_ATTR = "discard";
-    field public static final java.lang.String DOMAIN_ATTR = "domain";
-    field public static final java.lang.String EXPIRES_ATTR = "expires";
-    field public static final java.lang.String MAX_AGE_ATTR = "max-age";
-    field public static final java.lang.String PATH_ATTR = "path";
-    field public static final java.lang.String PORT_ATTR = "port";
-    field public static final java.lang.String SECURE_ATTR = "secure";
-    field public static final java.lang.String VERSION_ATTR = "version";
-  }
-
-  public abstract deprecated interface Cookie {
-    method public abstract java.lang.String getComment();
-    method public abstract java.lang.String getCommentURL();
-    method public abstract java.lang.String getDomain();
-    method public abstract java.util.Date getExpiryDate();
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getPath();
-    method public abstract int[] getPorts();
-    method public abstract java.lang.String getValue();
-    method public abstract int getVersion();
-    method public abstract boolean isExpired(java.util.Date);
-    method public abstract boolean isPersistent();
-    method public abstract boolean isSecure();
-  }
-
-  public abstract deprecated interface CookieAttributeHandler {
-    method public abstract boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public abstract void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class CookieIdentityComparator implements java.util.Comparator java.io.Serializable {
-    ctor public CookieIdentityComparator();
-    method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie);
-  }
-
-  public final deprecated class CookieOrigin {
-    ctor public CookieOrigin(java.lang.String, int, java.lang.String, boolean);
-    method public java.lang.String getHost();
-    method public java.lang.String getPath();
-    method public int getPort();
-    method public boolean isSecure();
-  }
-
-  public deprecated class CookiePathComparator implements java.util.Comparator java.io.Serializable {
-    ctor public CookiePathComparator();
-    method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie);
-  }
-
-  public abstract deprecated interface CookieSpec {
-    method public abstract java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public abstract int getVersion();
-    method public abstract org.apache.http.Header getVersionHeader();
-    method public abstract boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public abstract java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public abstract deprecated interface CookieSpecFactory {
-    method public abstract org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public final deprecated class CookieSpecRegistry {
-    ctor public CookieSpecRegistry();
-    method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException;
-    method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String) throws java.lang.IllegalStateException;
-    method public synchronized java.util.List<java.lang.String> getSpecNames();
-    method public synchronized void register(java.lang.String, org.apache.http.cookie.CookieSpecFactory);
-    method public synchronized void setItems(java.util.Map<java.lang.String, org.apache.http.cookie.CookieSpecFactory>);
-    method public synchronized void unregister(java.lang.String);
-  }
-
-  public deprecated class MalformedCookieException extends org.apache.http.ProtocolException {
-    ctor public MalformedCookieException();
-    ctor public MalformedCookieException(java.lang.String);
-    ctor public MalformedCookieException(java.lang.String, java.lang.Throwable);
-  }
-
-  public abstract deprecated interface SM {
-    field public static final java.lang.String COOKIE = "Cookie";
-    field public static final java.lang.String COOKIE2 = "Cookie2";
-    field public static final java.lang.String SET_COOKIE = "Set-Cookie";
-    field public static final java.lang.String SET_COOKIE2 = "Set-Cookie2";
-  }
-
-  public abstract deprecated interface SetCookie implements org.apache.http.cookie.Cookie {
-    method public abstract void setComment(java.lang.String);
-    method public abstract void setDomain(java.lang.String);
-    method public abstract void setExpiryDate(java.util.Date);
-    method public abstract void setPath(java.lang.String);
-    method public abstract void setSecure(boolean);
-    method public abstract void setValue(java.lang.String);
-    method public abstract void setVersion(int);
-  }
-
-  public abstract deprecated interface SetCookie2 implements org.apache.http.cookie.SetCookie {
-    method public abstract void setCommentURL(java.lang.String);
-    method public abstract void setDiscard(boolean);
-    method public abstract void setPorts(int[]);
-  }
-
-}
-
-package org.apache.http.cookie.params {
-
-  public abstract deprecated interface CookieSpecPNames {
-    field public static final java.lang.String DATE_PATTERNS = "http.protocol.cookie-datepatterns";
-    field public static final java.lang.String SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
-  }
-
-  public deprecated class CookieSpecParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public CookieSpecParamBean(org.apache.http.params.HttpParams);
-    method public void setDatePatterns(java.util.Collection<java.lang.String>);
-    method public void setSingleHeader(boolean);
-  }
-
-}
-
-package org.apache.http.entity {
-
-  public abstract deprecated class AbstractHttpEntity implements org.apache.http.HttpEntity {
-    ctor protected AbstractHttpEntity();
-    method public void consumeContent() throws java.io.IOException, java.lang.UnsupportedOperationException;
-    method public org.apache.http.Header getContentEncoding();
-    method public org.apache.http.Header getContentType();
-    method public boolean isChunked();
-    method public void setChunked(boolean);
-    method public void setContentEncoding(org.apache.http.Header);
-    method public void setContentEncoding(java.lang.String);
-    method public void setContentType(org.apache.http.Header);
-    method public void setContentType(java.lang.String);
-    field protected boolean chunked;
-    field protected org.apache.http.Header contentEncoding;
-    field protected org.apache.http.Header contentType;
-  }
-
-  public deprecated class BasicHttpEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public BasicHttpEntity();
-    method public java.io.InputStream getContent() throws java.lang.IllegalStateException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void setContent(java.io.InputStream);
-    method public void setContentLength(long);
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class BufferedHttpEntity extends org.apache.http.entity.HttpEntityWrapper {
-    ctor public BufferedHttpEntity(org.apache.http.HttpEntity) throws java.io.IOException;
-  }
-
-  public deprecated class ByteArrayEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public ByteArrayEntity(byte[]);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent();
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final byte[] content;
-  }
-
-  public abstract deprecated interface ContentLengthStrategy {
-    method public abstract long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-    field public static final int CHUNKED = -2; // 0xfffffffe
-    field public static final int IDENTITY = -1; // 0xffffffff
-  }
-
-  public abstract deprecated interface ContentProducer {
-    method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class EntityTemplate extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public EntityTemplate(org.apache.http.entity.ContentProducer);
-    method public java.io.InputStream getContent();
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class FileEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public FileEntity(java.io.File, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final java.io.File file;
-  }
-
-  public deprecated class HttpEntityWrapper implements org.apache.http.HttpEntity {
-    ctor public HttpEntityWrapper(org.apache.http.HttpEntity);
-    method public void consumeContent() throws java.io.IOException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public org.apache.http.Header getContentEncoding();
-    method public long getContentLength();
-    method public org.apache.http.Header getContentType();
-    method public boolean isChunked();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected org.apache.http.HttpEntity wrappedEntity;
-  }
-
-  public deprecated class InputStreamEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public InputStreamEntity(java.io.InputStream, long);
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class SerializableEntity extends org.apache.http.entity.AbstractHttpEntity {
-    ctor public SerializableEntity(java.io.Serializable, boolean) throws java.io.IOException;
-    method public java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-  }
-
-  public deprecated class StringEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable {
-    ctor public StringEntity(java.lang.String, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public StringEntity(java.lang.String) throws java.io.UnsupportedEncodingException;
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.io.InputStream getContent() throws java.io.IOException;
-    method public long getContentLength();
-    method public boolean isRepeatable();
-    method public boolean isStreaming();
-    method public void writeTo(java.io.OutputStream) throws java.io.IOException;
-    field protected final byte[] content;
-  }
-
-}
-
-package org.apache.http.impl {
-
-  public abstract deprecated class AbstractHttpClientConnection implements org.apache.http.HttpClientConnection {
-    ctor public AbstractHttpClientConnection();
-    method protected abstract void assertOpen() throws java.lang.IllegalStateException;
-    method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer();
-    method protected org.apache.http.impl.entity.EntitySerializer createEntitySerializer();
-    method protected org.apache.http.HttpResponseFactory createHttpResponseFactory();
-    method protected org.apache.http.io.HttpMessageWriter createRequestWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method protected org.apache.http.io.HttpMessageParser createResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected void doFlush() throws java.io.IOException;
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method protected void init(org.apache.http.io.SessionInputBuffer, org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method public boolean isResponseAvailable(int) throws java.io.IOException;
-    method public boolean isStale();
-    method public void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated class AbstractHttpServerConnection implements org.apache.http.HttpServerConnection {
-    ctor public AbstractHttpServerConnection();
-    method protected abstract void assertOpen() throws java.lang.IllegalStateException;
-    method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer();
-    method protected org.apache.http.impl.entity.EntitySerializer createEntitySerializer();
-    method protected org.apache.http.HttpRequestFactory createHttpRequestFactory();
-    method protected org.apache.http.io.HttpMessageParser createRequestParser(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpRequestFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.io.HttpMessageWriter createResponseWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method protected void doFlush() throws java.io.IOException;
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method protected void init(org.apache.http.io.SessionInputBuffer, org.apache.http.io.SessionOutputBuffer, org.apache.http.params.HttpParams);
-    method public boolean isStale();
-    method public void receiveRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpRequest receiveRequestHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class DefaultConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy {
-    ctor public DefaultConnectionReuseStrategy();
-    method protected org.apache.http.TokenIterator createTokenIterator(org.apache.http.HeaderIterator);
-    method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultHttpClientConnection extends org.apache.http.impl.SocketHttpClientConnection {
-    ctor public DefaultHttpClientConnection();
-    method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class DefaultHttpRequestFactory implements org.apache.http.HttpRequestFactory {
-    ctor public DefaultHttpRequestFactory();
-    method public org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException;
-    method public org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException;
-  }
-
-  public deprecated class DefaultHttpResponseFactory implements org.apache.http.HttpResponseFactory {
-    ctor public DefaultHttpResponseFactory(org.apache.http.ReasonPhraseCatalog);
-    ctor public DefaultHttpResponseFactory();
-    method protected java.util.Locale determineLocale(org.apache.http.protocol.HttpContext);
-    method public org.apache.http.HttpResponse newHttpResponse(org.apache.http.ProtocolVersion, int, org.apache.http.protocol.HttpContext);
-    method public org.apache.http.HttpResponse newHttpResponse(org.apache.http.StatusLine, org.apache.http.protocol.HttpContext);
-    field protected final org.apache.http.ReasonPhraseCatalog reasonCatalog;
-  }
-
-  public deprecated class DefaultHttpServerConnection extends org.apache.http.impl.SocketHttpServerConnection {
-    ctor public DefaultHttpServerConnection();
-    method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class EnglishReasonPhraseCatalog implements org.apache.http.ReasonPhraseCatalog {
-    ctor protected EnglishReasonPhraseCatalog();
-    method public java.lang.String getReason(int, java.util.Locale);
-    field public static final org.apache.http.impl.EnglishReasonPhraseCatalog INSTANCE;
-  }
-
-  public deprecated class HttpConnectionMetricsImpl implements org.apache.http.HttpConnectionMetrics {
-    ctor public HttpConnectionMetricsImpl(org.apache.http.io.HttpTransportMetrics, org.apache.http.io.HttpTransportMetrics);
-    method public java.lang.Object getMetric(java.lang.String);
-    method public long getReceivedBytesCount();
-    method public long getRequestCount();
-    method public long getResponseCount();
-    method public long getSentBytesCount();
-    method public void incrementRequestCount();
-    method public void incrementResponseCount();
-    method public void reset();
-    method public void setMetric(java.lang.String, java.lang.Object);
-    field public static final java.lang.String RECEIVED_BYTES_COUNT = "http.received-bytes-count";
-    field public static final java.lang.String REQUEST_COUNT = "http.request-count";
-    field public static final java.lang.String RESPONSE_COUNT = "http.response-count";
-    field public static final java.lang.String SENT_BYTES_COUNT = "http.sent-bytes-count";
-  }
-
-  public deprecated class NoConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy {
-    ctor public NoConnectionReuseStrategy();
-    method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class SocketHttpClientConnection extends org.apache.http.impl.AbstractHttpClientConnection implements org.apache.http.HttpInetConnection {
-    ctor public SocketHttpClientConnection();
-    method protected void assertNotOpen();
-    method protected void assertOpen();
-    method protected void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method protected org.apache.http.io.SessionInputBuffer createSessionInputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected org.apache.http.io.SessionOutputBuffer createSessionOutputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method protected java.net.Socket getSocket();
-    method public int getSocketTimeout();
-    method public boolean isOpen();
-    method public void setSocketTimeout(int);
-    method public void shutdown() throws java.io.IOException;
-  }
-
-  public deprecated class SocketHttpServerConnection extends org.apache.http.impl.AbstractHttpServerConnection implements org.apache.http.HttpInetConnection {
-    ctor public SocketHttpServerConnection();
-    method protected void assertNotOpen();
-    method protected void assertOpen();
-    method protected void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method protected org.apache.http.io.SessionInputBuffer createHttpDataReceiver(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected org.apache.http.io.SessionOutputBuffer createHttpDataTransmitter(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method protected java.net.Socket getSocket();
-    method public int getSocketTimeout();
-    method public boolean isOpen();
-    method public void setSocketTimeout(int);
-    method public void shutdown() throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.impl.auth {
-
-  public abstract deprecated class AuthSchemeBase implements org.apache.http.auth.AuthScheme {
-    ctor public AuthSchemeBase();
-    method public boolean isProxy();
-    method protected abstract void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-    method public void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public deprecated class BasicScheme extends org.apache.http.impl.auth.RFC2617Scheme {
-    ctor public BasicScheme();
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public static org.apache.http.Header authenticate(org.apache.http.auth.Credentials, java.lang.String, boolean);
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-  }
-
-  public deprecated class BasicSchemeFactory implements org.apache.http.auth.AuthSchemeFactory {
-    ctor public BasicSchemeFactory();
-    method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class DigestScheme extends org.apache.http.impl.auth.RFC2617Scheme {
-    ctor public DigestScheme();
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public static java.lang.String createCnonce();
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-    method public void overrideParamter(java.lang.String, java.lang.String);
-  }
-
-  public deprecated class DigestSchemeFactory implements org.apache.http.auth.AuthSchemeFactory {
-    ctor public DigestSchemeFactory();
-    method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated interface NTLMEngine {
-    method public abstract java.lang.String generateType1Msg(java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException;
-    method public abstract java.lang.String generateType3Msg(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException;
-  }
-
-  public deprecated class NTLMEngineException extends org.apache.http.auth.AuthenticationException {
-    ctor public NTLMEngineException();
-    ctor public NTLMEngineException(java.lang.String);
-    ctor public NTLMEngineException(java.lang.String, java.lang.Throwable);
-  }
-
-  public deprecated class NTLMScheme extends org.apache.http.impl.auth.AuthSchemeBase {
-    ctor public NTLMScheme(org.apache.http.impl.auth.NTLMEngine);
-    method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException;
-    method public java.lang.String getParameter(java.lang.String);
-    method public java.lang.String getRealm();
-    method public java.lang.String getSchemeName();
-    method public boolean isComplete();
-    method public boolean isConnectionBased();
-    method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public abstract deprecated class RFC2617Scheme extends org.apache.http.impl.auth.AuthSchemeBase {
-    ctor public RFC2617Scheme();
-    method public java.lang.String getParameter(java.lang.String);
-    method protected java.util.Map<java.lang.String, java.lang.String> getParameters();
-    method public java.lang.String getRealm();
-    method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException;
-  }
-
-  public deprecated class UnsupportedDigestAlgorithmException extends java.lang.RuntimeException {
-    ctor public UnsupportedDigestAlgorithmException();
-    ctor public UnsupportedDigestAlgorithmException(java.lang.String);
-    ctor public UnsupportedDigestAlgorithmException(java.lang.String, java.lang.Throwable);
-  }
-
-}
-
-package org.apache.http.impl.client {
-
-  public abstract deprecated class AbstractAuthenticationHandler implements org.apache.http.client.AuthenticationHandler {
-    ctor public AbstractAuthenticationHandler();
-    method protected java.util.List<java.lang.String> getAuthPreferences();
-    method protected java.util.Map<java.lang.String, org.apache.http.Header> parseChallenges(org.apache.http.Header[]) throws org.apache.http.auth.MalformedChallengeException;
-    method public org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException;
-  }
-
-  public abstract deprecated class AbstractHttpClient implements org.apache.http.client.HttpClient {
-    ctor protected AbstractHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams);
-    method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public synchronized void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public synchronized void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public synchronized void clearRequestInterceptors();
-    method public synchronized void clearResponseInterceptors();
-    method protected abstract org.apache.http.auth.AuthSchemeRegistry createAuthSchemeRegistry();
-    method protected abstract org.apache.http.conn.ClientConnectionManager createClientConnectionManager();
-    method protected org.apache.http.client.RequestDirector createClientRequestDirector(org.apache.http.protocol.HttpRequestExecutor, org.apache.http.conn.ClientConnectionManager, org.apache.http.ConnectionReuseStrategy, org.apache.http.conn.ConnectionKeepAliveStrategy, org.apache.http.conn.routing.HttpRoutePlanner, org.apache.http.protocol.HttpProcessor, org.apache.http.client.HttpRequestRetryHandler, org.apache.http.client.RedirectHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.UserTokenHandler, org.apache.http.params.HttpParams);
-    method protected abstract org.apache.http.conn.ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
-    method protected abstract org.apache.http.ConnectionReuseStrategy createConnectionReuseStrategy();
-    method protected abstract org.apache.http.cookie.CookieSpecRegistry createCookieSpecRegistry();
-    method protected abstract org.apache.http.client.CookieStore createCookieStore();
-    method protected abstract org.apache.http.client.CredentialsProvider createCredentialsProvider();
-    method protected abstract org.apache.http.protocol.HttpContext createHttpContext();
-    method protected abstract org.apache.http.params.HttpParams createHttpParams();
-    method protected abstract org.apache.http.protocol.BasicHttpProcessor createHttpProcessor();
-    method protected abstract org.apache.http.client.HttpRequestRetryHandler createHttpRequestRetryHandler();
-    method protected abstract org.apache.http.conn.routing.HttpRoutePlanner createHttpRoutePlanner();
-    method protected abstract org.apache.http.client.AuthenticationHandler createProxyAuthenticationHandler();
-    method protected abstract org.apache.http.client.RedirectHandler createRedirectHandler();
-    method protected abstract org.apache.http.protocol.HttpRequestExecutor createRequestExecutor();
-    method protected abstract org.apache.http.client.AuthenticationHandler createTargetAuthenticationHandler();
-    method protected abstract org.apache.http.client.UserTokenHandler createUserTokenHandler();
-    method protected org.apache.http.params.HttpParams determineParams(org.apache.http.HttpRequest);
-    method public final org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public T execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.client.ResponseHandler<? extends T>, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException;
-    method public final synchronized org.apache.http.auth.AuthSchemeRegistry getAuthSchemes();
-    method public final synchronized org.apache.http.conn.ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy();
-    method public final synchronized org.apache.http.conn.ClientConnectionManager getConnectionManager();
-    method public final synchronized org.apache.http.ConnectionReuseStrategy getConnectionReuseStrategy();
-    method public final synchronized org.apache.http.cookie.CookieSpecRegistry getCookieSpecs();
-    method public final synchronized org.apache.http.client.CookieStore getCookieStore();
-    method public final synchronized org.apache.http.client.CredentialsProvider getCredentialsProvider();
-    method protected final synchronized org.apache.http.protocol.BasicHttpProcessor getHttpProcessor();
-    method public final synchronized org.apache.http.client.HttpRequestRetryHandler getHttpRequestRetryHandler();
-    method public final synchronized org.apache.http.params.HttpParams getParams();
-    method public final synchronized org.apache.http.client.AuthenticationHandler getProxyAuthenticationHandler();
-    method public final synchronized org.apache.http.client.RedirectHandler getRedirectHandler();
-    method public final synchronized org.apache.http.protocol.HttpRequestExecutor getRequestExecutor();
-    method public synchronized org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public synchronized int getRequestInterceptorCount();
-    method public synchronized org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public synchronized int getResponseInterceptorCount();
-    method public final synchronized org.apache.http.conn.routing.HttpRoutePlanner getRoutePlanner();
-    method public final synchronized org.apache.http.client.AuthenticationHandler getTargetAuthenticationHandler();
-    method public final synchronized org.apache.http.client.UserTokenHandler getUserTokenHandler();
-    method public void removeRequestInterceptorByClass(java.lang.Class<? extends org.apache.http.HttpRequestInterceptor>);
-    method public void removeResponseInterceptorByClass(java.lang.Class<? extends org.apache.http.HttpResponseInterceptor>);
-    method public synchronized void setAuthSchemes(org.apache.http.auth.AuthSchemeRegistry);
-    method public synchronized void setCookieSpecs(org.apache.http.cookie.CookieSpecRegistry);
-    method public synchronized void setCookieStore(org.apache.http.client.CookieStore);
-    method public synchronized void setCredentialsProvider(org.apache.http.client.CredentialsProvider);
-    method public synchronized void setHttpRequestRetryHandler(org.apache.http.client.HttpRequestRetryHandler);
-    method public synchronized void setKeepAliveStrategy(org.apache.http.conn.ConnectionKeepAliveStrategy);
-    method public synchronized void setParams(org.apache.http.params.HttpParams);
-    method public synchronized void setProxyAuthenticationHandler(org.apache.http.client.AuthenticationHandler);
-    method public synchronized void setRedirectHandler(org.apache.http.client.RedirectHandler);
-    method public synchronized void setReuseStrategy(org.apache.http.ConnectionReuseStrategy);
-    method public synchronized void setRoutePlanner(org.apache.http.conn.routing.HttpRoutePlanner);
-    method public synchronized void setTargetAuthenticationHandler(org.apache.http.client.AuthenticationHandler);
-    method public synchronized void setUserTokenHandler(org.apache.http.client.UserTokenHandler);
-  }
-
-  public deprecated class BasicCookieStore implements org.apache.http.client.CookieStore {
-    ctor public BasicCookieStore();
-    method public synchronized void addCookie(org.apache.http.cookie.Cookie);
-    method public synchronized void addCookies(org.apache.http.cookie.Cookie[]);
-    method public synchronized void clear();
-    method public synchronized boolean clearExpired(java.util.Date);
-    method public synchronized java.util.List<org.apache.http.cookie.Cookie> getCookies();
-  }
-
-  public deprecated class BasicCredentialsProvider implements org.apache.http.client.CredentialsProvider {
-    ctor public BasicCredentialsProvider();
-    method public synchronized void clear();
-    method public synchronized org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope);
-    method public synchronized void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials);
-  }
-
-  public deprecated class BasicResponseHandler implements org.apache.http.client.ResponseHandler {
-    ctor public BasicResponseHandler();
-    method public java.lang.String handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.HttpResponseException, java.io.IOException;
-  }
-
-  public deprecated class ClientParamsStack extends org.apache.http.params.AbstractHttpParams {
-    ctor public ClientParamsStack(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack);
-    ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    method public org.apache.http.params.HttpParams copy();
-    method public final org.apache.http.params.HttpParams getApplicationParams();
-    method public final org.apache.http.params.HttpParams getClientParams();
-    method public final org.apache.http.params.HttpParams getOverrideParams();
-    method public java.lang.Object getParameter(java.lang.String);
-    method public final org.apache.http.params.HttpParams getRequestParams();
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object) throws java.lang.UnsupportedOperationException;
-    field protected final org.apache.http.params.HttpParams applicationParams;
-    field protected final org.apache.http.params.HttpParams clientParams;
-    field protected final org.apache.http.params.HttpParams overrideParams;
-    field protected final org.apache.http.params.HttpParams requestParams;
-  }
-
-  public deprecated class DefaultConnectionKeepAliveStrategy implements org.apache.http.conn.ConnectionKeepAliveStrategy {
-    ctor public DefaultConnectionKeepAliveStrategy();
-    method public long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultHttpClient extends org.apache.http.impl.client.AbstractHttpClient {
-    ctor public DefaultHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams);
-    ctor public DefaultHttpClient(org.apache.http.params.HttpParams);
-    ctor public DefaultHttpClient();
-    method protected org.apache.http.auth.AuthSchemeRegistry createAuthSchemeRegistry();
-    method protected org.apache.http.conn.ClientConnectionManager createClientConnectionManager();
-    method protected org.apache.http.conn.ConnectionKeepAliveStrategy createConnectionKeepAliveStrategy();
-    method protected org.apache.http.ConnectionReuseStrategy createConnectionReuseStrategy();
-    method protected org.apache.http.cookie.CookieSpecRegistry createCookieSpecRegistry();
-    method protected org.apache.http.client.CookieStore createCookieStore();
-    method protected org.apache.http.client.CredentialsProvider createCredentialsProvider();
-    method protected org.apache.http.protocol.HttpContext createHttpContext();
-    method protected org.apache.http.params.HttpParams createHttpParams();
-    method protected org.apache.http.protocol.BasicHttpProcessor createHttpProcessor();
-    method protected org.apache.http.client.HttpRequestRetryHandler createHttpRequestRetryHandler();
-    method protected org.apache.http.conn.routing.HttpRoutePlanner createHttpRoutePlanner();
-    method protected org.apache.http.client.AuthenticationHandler createProxyAuthenticationHandler();
-    method protected org.apache.http.client.RedirectHandler createRedirectHandler();
-    method protected org.apache.http.protocol.HttpRequestExecutor createRequestExecutor();
-    method protected org.apache.http.client.AuthenticationHandler createTargetAuthenticationHandler();
-    method protected org.apache.http.client.UserTokenHandler createUserTokenHandler();
-  }
-
-  public deprecated class DefaultHttpRequestRetryHandler implements org.apache.http.client.HttpRequestRetryHandler {
-    ctor public DefaultHttpRequestRetryHandler(int, boolean);
-    ctor public DefaultHttpRequestRetryHandler();
-    method public int getRetryCount();
-    method public boolean isRequestSentRetryEnabled();
-    method public boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultProxyAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler {
-    ctor public DefaultProxyAuthenticationHandler();
-    method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultRedirectHandler implements org.apache.http.client.RedirectHandler {
-    ctor public DefaultRedirectHandler();
-    method public java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException;
-    method public boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultRequestDirector implements org.apache.http.client.RequestDirector {
-    ctor public DefaultRequestDirector(org.apache.http.protocol.HttpRequestExecutor, org.apache.http.conn.ClientConnectionManager, org.apache.http.ConnectionReuseStrategy, org.apache.http.conn.ConnectionKeepAliveStrategy, org.apache.http.conn.routing.HttpRoutePlanner, org.apache.http.protocol.HttpProcessor, org.apache.http.client.HttpRequestRetryHandler, org.apache.http.client.RedirectHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.UserTokenHandler, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpRequest createConnectRequest(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext);
-    method protected boolean createTunnelToProxy(org.apache.http.conn.routing.HttpRoute, int, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected boolean createTunnelToTarget(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method protected void establishRoute(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.impl.client.RoutedRequest handleResponse(org.apache.http.impl.client.RoutedRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected void releaseConnection();
-    method protected void rewriteRequestURI(org.apache.http.impl.client.RequestWrapper, org.apache.http.conn.routing.HttpRoute) throws org.apache.http.ProtocolException;
-    field protected final org.apache.http.conn.ClientConnectionManager connManager;
-    field protected final org.apache.http.protocol.HttpProcessor httpProcessor;
-    field protected final org.apache.http.conn.ConnectionKeepAliveStrategy keepAliveStrategy;
-    field protected org.apache.http.conn.ManagedClientConnection managedConn;
-    field protected final org.apache.http.params.HttpParams params;
-    field protected final org.apache.http.client.RedirectHandler redirectHandler;
-    field protected final org.apache.http.protocol.HttpRequestExecutor requestExec;
-    field protected final org.apache.http.client.HttpRequestRetryHandler retryHandler;
-    field protected final org.apache.http.ConnectionReuseStrategy reuseStrategy;
-    field protected final org.apache.http.conn.routing.HttpRoutePlanner routePlanner;
-  }
-
-  public deprecated class DefaultTargetAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler {
-    ctor public DefaultTargetAuthenticationHandler();
-    method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException;
-    method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class DefaultUserTokenHandler implements org.apache.http.client.UserTokenHandler {
-    ctor public DefaultUserTokenHandler();
-    method public java.lang.Object getUserToken(org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class EntityEnclosingRequestWrapper extends org.apache.http.impl.client.RequestWrapper implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public EntityEnclosingRequestWrapper(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.ProtocolException;
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class RedirectLocations {
-    ctor public RedirectLocations();
-    method public void add(java.net.URI);
-    method public boolean contains(java.net.URI);
-    method public boolean remove(java.net.URI);
-  }
-
-  public deprecated class RequestWrapper extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.HttpUriRequest {
-    ctor public RequestWrapper(org.apache.http.HttpRequest) throws org.apache.http.ProtocolException;
-    method public void abort() throws java.lang.UnsupportedOperationException;
-    method public int getExecCount();
-    method public java.lang.String getMethod();
-    method public org.apache.http.HttpRequest getOriginal();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-    method public java.net.URI getURI();
-    method public void incrementExecCount();
-    method public boolean isAborted();
-    method public boolean isRepeatable();
-    method public void resetHeaders();
-    method public void setMethod(java.lang.String);
-    method public void setProtocolVersion(org.apache.http.ProtocolVersion);
-    method public void setURI(java.net.URI);
-  }
-
-  public deprecated class RoutedRequest {
-    ctor public RoutedRequest(org.apache.http.impl.client.RequestWrapper, org.apache.http.conn.routing.HttpRoute);
-    method public final org.apache.http.impl.client.RequestWrapper getRequest();
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-    field protected final org.apache.http.impl.client.RequestWrapper request;
-    field protected final org.apache.http.conn.routing.HttpRoute route;
-  }
-
-  public deprecated class TunnelRefusedException extends org.apache.http.HttpException {
-    ctor public TunnelRefusedException(java.lang.String, org.apache.http.HttpResponse);
-    method public org.apache.http.HttpResponse getResponse();
-  }
-
-}
-
-package org.apache.http.impl.conn {
-
-  public abstract deprecated class AbstractClientConnAdapter implements org.apache.http.conn.ManagedClientConnection {
-    ctor protected AbstractClientConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.conn.OperatedClientConnection);
-    method public void abortConnection();
-    method protected final void assertNotAborted() throws java.io.InterruptedIOException;
-    method protected final void assertValid(org.apache.http.conn.OperatedClientConnection);
-    method protected void detach();
-    method public void flush() throws java.io.IOException;
-    method public java.net.InetAddress getLocalAddress();
-    method public int getLocalPort();
-    method protected org.apache.http.conn.ClientConnectionManager getManager();
-    method public org.apache.http.HttpConnectionMetrics getMetrics();
-    method public java.net.InetAddress getRemoteAddress();
-    method public int getRemotePort();
-    method public javax.net.ssl.SSLSession getSSLSession();
-    method public int getSocketTimeout();
-    method protected org.apache.http.conn.OperatedClientConnection getWrappedConnection();
-    method public boolean isMarkedReusable();
-    method public boolean isOpen();
-    method public boolean isResponseAvailable(int) throws java.io.IOException;
-    method public boolean isSecure();
-    method public boolean isStale();
-    method public void markReusable();
-    method public void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse receiveResponseHeader() throws org.apache.http.HttpException, java.io.IOException;
-    method public void releaseConnection();
-    method public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException;
-    method public void setIdleDuration(long, java.util.concurrent.TimeUnit);
-    method public void setSocketTimeout(int);
-    method public void unmarkReusable();
-  }
-
-  public abstract deprecated class AbstractPoolEntry {
-    ctor protected AbstractPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute);
-    method public java.lang.Object getState();
-    method public void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void setState(java.lang.Object);
-    method protected void shutdownEntry();
-    method public void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected final org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected final org.apache.http.conn.OperatedClientConnection connection;
-    field protected volatile org.apache.http.conn.routing.HttpRoute route;
-    field protected volatile java.lang.Object state;
-    field protected volatile org.apache.http.conn.routing.RouteTracker tracker;
-  }
-
-  public abstract deprecated class AbstractPooledConnAdapter extends org.apache.http.impl.conn.AbstractClientConnAdapter {
-    ctor protected AbstractPooledConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.impl.conn.AbstractPoolEntry);
-    method protected final void assertAttached();
-    method public void close() throws java.io.IOException;
-    method public org.apache.http.conn.routing.HttpRoute getRoute();
-    method public java.lang.Object getState();
-    method public void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void open(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void setState(java.lang.Object);
-    method public void shutdown() throws java.io.IOException;
-    method public void tunnelProxy(org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void tunnelTarget(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected volatile org.apache.http.impl.conn.AbstractPoolEntry poolEntry;
-  }
-
-  public deprecated class DefaultClientConnection extends org.apache.http.impl.SocketHttpClientConnection implements org.apache.http.conn.OperatedClientConnection {
-    ctor public DefaultClientConnection();
-    method public final java.net.Socket getSocket();
-    method public final org.apache.http.HttpHost getTargetHost();
-    method public final boolean isSecure();
-    method public void openCompleted(boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void opening(java.net.Socket, org.apache.http.HttpHost) throws java.io.IOException;
-    method public void update(java.net.Socket, org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-  public deprecated class DefaultClientConnectionOperator implements org.apache.http.conn.ClientConnectionOperator {
-    ctor public DefaultClientConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.OperatedClientConnection createConnection();
-    method public void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method protected void prepareSocket(java.net.Socket, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public void updateSecureConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class DefaultHttpRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner {
-    ctor public DefaultHttpRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class DefaultResponseParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public DefaultResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class IdleConnectionHandler {
-    ctor public IdleConnectionHandler();
-    method public void add(org.apache.http.HttpConnection, long, java.util.concurrent.TimeUnit);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long);
-    method public boolean remove(org.apache.http.HttpConnection);
-    method public void removeAll();
-  }
-
-  public deprecated class LoggingSessionInputBuffer implements org.apache.http.io.SessionInputBuffer {
-    ctor public LoggingSessionInputBuffer(org.apache.http.io.SessionInputBuffer, org.apache.http.impl.conn.Wire);
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public boolean isDataAvailable(int) throws java.io.IOException;
-    method public int read(byte[], int, int) throws java.io.IOException;
-    method public int read() throws java.io.IOException;
-    method public int read(byte[]) throws java.io.IOException;
-    method public java.lang.String readLine() throws java.io.IOException;
-    method public int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-  public deprecated class LoggingSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer {
-    ctor public LoggingSessionOutputBuffer(org.apache.http.io.SessionOutputBuffer, org.apache.http.impl.conn.Wire);
-    method public void flush() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public void write(byte[], int, int) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method public void write(byte[]) throws java.io.IOException;
-    method public void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public void writeLine(java.lang.String) throws java.io.IOException;
-  }
-
-  public deprecated class ProxySelectorRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner {
-    ctor public ProxySelectorRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry, java.net.ProxySelector);
-    method protected java.net.Proxy chooseProxy(java.util.List<java.net.Proxy>, org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext);
-    method protected org.apache.http.HttpHost determineProxy(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method public org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-    method protected java.lang.String getHost(java.net.InetSocketAddress);
-    method public java.net.ProxySelector getProxySelector();
-    method public void setProxySelector(java.net.ProxySelector);
-    field protected java.net.ProxySelector proxySelector;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class SingleClientConnManager implements org.apache.http.conn.ClientConnectionManager {
-    ctor public SingleClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-    method protected final void assertStillUp() throws java.lang.IllegalStateException;
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method protected org.apache.http.conn.ClientConnectionOperator createConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method public org.apache.http.conn.ManagedClientConnection getConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public final org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method protected void revokeConnection();
-    method public void shutdown();
-    field public static final java.lang.String MISUSE_MESSAGE = "Invalid use of SingleClientConnManager: connection still allocated.\nMake sure to release the connection before allocating another one.";
-    field protected boolean alwaysShutDown;
-    field protected org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected long connectionExpiresTime;
-    field protected volatile boolean isShutDown;
-    field protected long lastReleaseTime;
-    field protected org.apache.http.impl.conn.SingleClientConnManager.ConnAdapter managedConn;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-    field protected org.apache.http.impl.conn.SingleClientConnManager.PoolEntry uniquePoolEntry;
-  }
-
-  protected class SingleClientConnManager.ConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter {
-    ctor protected SingleClientConnManager.ConnAdapter(org.apache.http.impl.conn.SingleClientConnManager.PoolEntry, org.apache.http.conn.routing.HttpRoute);
-  }
-
-  protected class SingleClientConnManager.PoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry {
-    ctor protected SingleClientConnManager.PoolEntry();
-    method protected void close() throws java.io.IOException;
-    method protected void shutdown() throws java.io.IOException;
-  }
-
-  public deprecated class Wire {
-    ctor public Wire(org.apache.commons.logging.Log);
-    method public boolean enabled();
-    method public void input(java.io.InputStream) throws java.io.IOException;
-    method public void input(byte[], int, int) throws java.io.IOException;
-    method public void input(byte[]) throws java.io.IOException;
-    method public void input(int) throws java.io.IOException;
-    method public void input(java.lang.String) throws java.io.IOException;
-    method public void output(java.io.InputStream) throws java.io.IOException;
-    method public void output(byte[], int, int) throws java.io.IOException;
-    method public void output(byte[]) throws java.io.IOException;
-    method public void output(int) throws java.io.IOException;
-    method public void output(java.lang.String) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.impl.conn.tsccm {
-
-  public abstract deprecated class AbstractConnPool implements org.apache.http.impl.conn.tsccm.RefQueueHandler {
-    ctor protected AbstractConnPool();
-    method protected void closeConnection(org.apache.http.conn.OperatedClientConnection);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method public abstract void deleteClosedConnections();
-    method public void enableConnectionGC() throws java.lang.IllegalStateException;
-    method public abstract void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry, boolean, long, java.util.concurrent.TimeUnit);
-    method public final org.apache.http.impl.conn.tsccm.BasicPoolEntry getEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object, long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-    method protected abstract void handleLostEntry(org.apache.http.conn.routing.HttpRoute);
-    method public void handleReference(java.lang.ref.Reference);
-    method public abstract org.apache.http.impl.conn.tsccm.PoolEntryRequest requestPoolEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public void shutdown();
-    field protected org.apache.http.impl.conn.IdleConnectionHandler idleConnHandler;
-    field protected volatile boolean isShutDown;
-    field protected java.util.Set<org.apache.http.impl.conn.tsccm.BasicPoolEntryRef> issuedConnections;
-    field protected int numConnections;
-    field protected final java.util.concurrent.locks.Lock poolLock;
-    field protected java.lang.ref.ReferenceQueue<java.lang.Object> refQueue;
-  }
-
-  public deprecated class BasicPoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry {
-    ctor public BasicPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute, java.lang.ref.ReferenceQueue<java.lang.Object>);
-    method protected final org.apache.http.conn.OperatedClientConnection getConnection();
-    method protected final org.apache.http.conn.routing.HttpRoute getPlannedRoute();
-    method protected final org.apache.http.impl.conn.tsccm.BasicPoolEntryRef getWeakRef();
-  }
-
-  public deprecated class BasicPoolEntryRef extends java.lang.ref.WeakReference {
-    ctor public BasicPoolEntryRef(org.apache.http.impl.conn.tsccm.BasicPoolEntry, java.lang.ref.ReferenceQueue<java.lang.Object>);
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-  }
-
-  public deprecated class BasicPooledConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter {
-    ctor protected BasicPooledConnAdapter(org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager, org.apache.http.impl.conn.AbstractPoolEntry);
-    method protected org.apache.http.impl.conn.AbstractPoolEntry getPoolEntry();
-  }
-
-  public deprecated class ConnPoolByRoute extends org.apache.http.impl.conn.tsccm.AbstractConnPool {
-    ctor public ConnPoolByRoute(org.apache.http.conn.ClientConnectionOperator, org.apache.http.params.HttpParams);
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry createEntry(org.apache.http.impl.conn.tsccm.RouteSpecificPool, org.apache.http.conn.ClientConnectionOperator);
-    method protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> createFreeConnQueue();
-    method protected java.util.Map<org.apache.http.conn.routing.HttpRoute, org.apache.http.impl.conn.tsccm.RouteSpecificPool> createRouteToPoolMap();
-    method protected java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> createWaitingThreadQueue();
-    method public void deleteClosedConnections();
-    method protected void deleteEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method protected void deleteLeastUsedEntry();
-    method public void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry, boolean, long, java.util.concurrent.TimeUnit);
-    method public int getConnectionsInPool(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry getEntryBlocking(org.apache.http.conn.routing.HttpRoute, java.lang.Object, long, java.util.concurrent.TimeUnit, org.apache.http.impl.conn.tsccm.WaitingThreadAborter) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-    method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry getFreeEntry(org.apache.http.impl.conn.tsccm.RouteSpecificPool, java.lang.Object);
-    method protected org.apache.http.impl.conn.tsccm.RouteSpecificPool getRoutePool(org.apache.http.conn.routing.HttpRoute, boolean);
-    method protected void handleLostEntry(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.RouteSpecificPool newRouteSpecificPool(org.apache.http.conn.routing.HttpRoute);
-    method protected org.apache.http.impl.conn.tsccm.WaitingThread newWaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method protected void notifyWaitingThread(org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method public org.apache.http.impl.conn.tsccm.PoolEntryRequest requestPoolEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    field protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeConnections;
-    field protected final int maxTotalConnections;
-    field protected final org.apache.http.conn.ClientConnectionOperator operator;
-    field protected final java.util.Map<org.apache.http.conn.routing.HttpRoute, org.apache.http.impl.conn.tsccm.RouteSpecificPool> routeToPool;
-    field protected java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads;
-  }
-
-  public abstract deprecated interface PoolEntryRequest {
-    method public abstract void abortRequest();
-    method public abstract org.apache.http.impl.conn.tsccm.BasicPoolEntry getPoolEntry(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException;
-  }
-
-  public abstract deprecated interface RefQueueHandler {
-    method public abstract void handleReference(java.lang.ref.Reference<?>);
-  }
-
-  public deprecated class RefQueueWorker implements java.lang.Runnable {
-    ctor public RefQueueWorker(java.lang.ref.ReferenceQueue<?>, org.apache.http.impl.conn.tsccm.RefQueueHandler);
-    method public void run();
-    method public void shutdown();
-    field protected final org.apache.http.impl.conn.tsccm.RefQueueHandler refHandler;
-    field protected final java.lang.ref.ReferenceQueue<?> refQueue;
-    field protected volatile java.lang.Thread workerThread;
-  }
-
-  public deprecated class RouteSpecificPool {
-    ctor public RouteSpecificPool(org.apache.http.conn.routing.HttpRoute, int);
-    method public org.apache.http.impl.conn.tsccm.BasicPoolEntry allocEntry(java.lang.Object);
-    method public void createdEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public boolean deleteEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public void dropEntry();
-    method public void freeEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry);
-    method public int getCapacity();
-    method public final int getEntryCount();
-    method public final int getMaxEntries();
-    method public final org.apache.http.conn.routing.HttpRoute getRoute();
-    method public boolean hasThread();
-    method public boolean isUnused();
-    method public org.apache.http.impl.conn.tsccm.WaitingThread nextThread();
-    method public void queueThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-    method public void removeThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-    field protected final java.util.LinkedList<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeEntries;
-    field protected final int maxEntries;
-    field protected int numEntries;
-    field protected final org.apache.http.conn.routing.HttpRoute route;
-    field protected final java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads;
-  }
-
-  public deprecated class ThreadSafeClientConnManager implements org.apache.http.conn.ClientConnectionManager {
-    ctor public ThreadSafeClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry);
-    method public void closeExpiredConnections();
-    method public void closeIdleConnections(long, java.util.concurrent.TimeUnit);
-    method protected org.apache.http.conn.ClientConnectionOperator createConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry);
-    method protected org.apache.http.impl.conn.tsccm.AbstractConnPool createConnectionPool(org.apache.http.params.HttpParams);
-    method public int getConnectionsInPool(org.apache.http.conn.routing.HttpRoute);
-    method public int getConnectionsInPool();
-    method public org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry();
-    method public void releaseConnection(org.apache.http.conn.ManagedClientConnection, long, java.util.concurrent.TimeUnit);
-    method public org.apache.http.conn.ClientConnectionRequest requestConnection(org.apache.http.conn.routing.HttpRoute, java.lang.Object);
-    method public void shutdown();
-    field protected org.apache.http.conn.ClientConnectionOperator connOperator;
-    field protected final org.apache.http.impl.conn.tsccm.AbstractConnPool connectionPool;
-    field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry;
-  }
-
-  public deprecated class WaitingThread {
-    ctor public WaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool);
-    method public boolean await(java.util.Date) throws java.lang.InterruptedException;
-    method public final java.util.concurrent.locks.Condition getCondition();
-    method public final org.apache.http.impl.conn.tsccm.RouteSpecificPool getPool();
-    method public final java.lang.Thread getThread();
-    method public void interrupt();
-    method public void wakeup();
-  }
-
-  public deprecated class WaitingThreadAborter {
-    ctor public WaitingThreadAborter();
-    method public void abort();
-    method public void setWaitingThread(org.apache.http.impl.conn.tsccm.WaitingThread);
-  }
-
-}
-
-package org.apache.http.impl.cookie {
-
-  public abstract deprecated class AbstractCookieAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public AbstractCookieAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public abstract deprecated class AbstractCookieSpec implements org.apache.http.cookie.CookieSpec {
-    ctor public AbstractCookieSpec();
-    method protected org.apache.http.cookie.CookieAttributeHandler findAttribHandler(java.lang.String);
-    method protected org.apache.http.cookie.CookieAttributeHandler getAttribHandler(java.lang.String);
-    method protected java.util.Collection<org.apache.http.cookie.CookieAttributeHandler> getAttribHandlers();
-    method public void registerAttribHandler(java.lang.String, org.apache.http.cookie.CookieAttributeHandler);
-  }
-
-  public deprecated class BasicClientCookie implements org.apache.http.cookie.ClientCookie java.lang.Cloneable org.apache.http.cookie.SetCookie {
-    ctor public BasicClientCookie(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public boolean containsAttribute(java.lang.String);
-    method public java.lang.String getAttribute(java.lang.String);
-    method public java.lang.String getComment();
-    method public java.lang.String getCommentURL();
-    method public java.lang.String getDomain();
-    method public java.util.Date getExpiryDate();
-    method public java.lang.String getName();
-    method public java.lang.String getPath();
-    method public int[] getPorts();
-    method public java.lang.String getValue();
-    method public int getVersion();
-    method public boolean isExpired(java.util.Date);
-    method public boolean isPersistent();
-    method public boolean isSecure();
-    method public void setAttribute(java.lang.String, java.lang.String);
-    method public void setComment(java.lang.String);
-    method public void setDomain(java.lang.String);
-    method public void setExpiryDate(java.util.Date);
-    method public void setPath(java.lang.String);
-    method public void setSecure(boolean);
-    method public void setValue(java.lang.String);
-    method public void setVersion(int);
-  }
-
-  public deprecated class BasicClientCookie2 extends org.apache.http.impl.cookie.BasicClientCookie implements org.apache.http.cookie.SetCookie2 {
-    ctor public BasicClientCookie2(java.lang.String, java.lang.String);
-    method public void setCommentURL(java.lang.String);
-    method public void setDiscard(boolean);
-    method public void setPorts(int[]);
-  }
-
-  public deprecated class BasicCommentHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicCommentHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicDomainHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public BasicDomainHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicExpiresHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicExpiresHandler(java.lang.String[]);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicMaxAgeHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicMaxAgeHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicPathHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public BasicPathHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BasicSecureHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public BasicSecureHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BestMatchSpec implements org.apache.http.cookie.CookieSpec {
-    ctor public BestMatchSpec(java.lang.String[], boolean);
-    ctor public BestMatchSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class BestMatchSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public BestMatchSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class BrowserCompatSpec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public BrowserCompatSpec(java.lang.String[]);
-    ctor public BrowserCompatSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    field protected static final java.lang.String[] DATE_PATTERNS;
-  }
-
-  public deprecated class BrowserCompatSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public BrowserCompatSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public abstract deprecated class CookieSpecBase extends org.apache.http.impl.cookie.AbstractCookieSpec {
-    ctor public CookieSpecBase();
-    method protected static java.lang.String getDefaultDomain(org.apache.http.cookie.CookieOrigin);
-    method protected static java.lang.String getDefaultPath(org.apache.http.cookie.CookieOrigin);
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method protected java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.HeaderElement[], org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class DateParseException extends java.lang.Exception {
-    ctor public DateParseException();
-    ctor public DateParseException(java.lang.String);
-  }
-
-  public final deprecated class DateUtils {
-    method public static java.lang.String formatDate(java.util.Date);
-    method public static java.lang.String formatDate(java.util.Date, java.lang.String);
-    method public static java.util.Date parseDate(java.lang.String) throws org.apache.http.impl.cookie.DateParseException;
-    method public static java.util.Date parseDate(java.lang.String, java.lang.String[]) throws org.apache.http.impl.cookie.DateParseException;
-    method public static java.util.Date parseDate(java.lang.String, java.lang.String[], java.util.Date) throws org.apache.http.impl.cookie.DateParseException;
-    field public static final java.util.TimeZone GMT;
-    field public static final java.lang.String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
-    field public static final java.lang.String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
-    field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
-  }
-
-  public deprecated class NetscapeDomainHandler extends org.apache.http.impl.cookie.BasicDomainHandler {
-    ctor public NetscapeDomainHandler();
-  }
-
-  public deprecated class NetscapeDraftHeaderParser {
-    ctor public NetscapeDraftHeaderParser();
-    method public org.apache.http.HeaderElement parseHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    field public static final org.apache.http.impl.cookie.NetscapeDraftHeaderParser DEFAULT;
-  }
-
-  public deprecated class NetscapeDraftSpec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public NetscapeDraftSpec(java.lang.String[]);
-    ctor public NetscapeDraftSpec();
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-    field protected static final java.lang.String EXPIRES_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
-  }
-
-  public deprecated class NetscapeDraftSpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public NetscapeDraftSpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2109DomainHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2109DomainHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2109Spec extends org.apache.http.impl.cookie.CookieSpecBase {
-    ctor public RFC2109Spec(java.lang.String[], boolean);
-    ctor public RFC2109Spec();
-    method protected void formatCookieAsVer(org.apache.http.util.CharArrayBuffer, org.apache.http.cookie.Cookie, int);
-    method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>);
-    method protected void formatParamAsVer(org.apache.http.util.CharArrayBuffer, java.lang.String, java.lang.String, int);
-    method public int getVersion();
-    method public org.apache.http.Header getVersionHeader();
-    method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2109SpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public RFC2109SpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2109VersionHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler {
-    ctor public RFC2109VersionHandler();
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965CommentUrlAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965CommentUrlAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965DiscardAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965DiscardAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965DomainAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965DomainAttributeHandler();
-    method public boolean domainMatch(java.lang.String, java.lang.String);
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965PortAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965PortAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-  public deprecated class RFC2965Spec extends org.apache.http.impl.cookie.RFC2109Spec {
-    ctor public RFC2965Spec();
-    ctor public RFC2965Spec(java.lang.String[], boolean);
-  }
-
-  public deprecated class RFC2965SpecFactory implements org.apache.http.cookie.CookieSpecFactory {
-    ctor public RFC2965SpecFactory();
-    method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams);
-  }
-
-  public deprecated class RFC2965VersionAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler {
-    ctor public RFC2965VersionAttributeHandler();
-    method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin);
-    method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException;
-    method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException;
-  }
-
-}
-
-package org.apache.http.impl.entity {
-
-  public deprecated class EntityDeserializer {
-    ctor public EntityDeserializer(org.apache.http.entity.ContentLengthStrategy);
-    method public org.apache.http.HttpEntity deserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.entity.BasicHttpEntity doDeserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class EntitySerializer {
-    ctor public EntitySerializer(org.apache.http.entity.ContentLengthStrategy);
-    method protected java.io.OutputStream doSerialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method public void serialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage, org.apache.http.HttpEntity) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class LaxContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy {
-    ctor public LaxContentLengthStrategy();
-    method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-  }
-
-  public deprecated class StrictContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy {
-    ctor public StrictContentLengthStrategy();
-    method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException;
-  }
-
-}
-
-package org.apache.http.impl.io {
-
-  public abstract deprecated class AbstractMessageParser implements org.apache.http.io.HttpMessageParser {
-    ctor public AbstractMessageParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.params.HttpParams);
-    method public org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException;
-    method protected abstract org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-    method public static org.apache.http.Header[] parseHeaders(org.apache.http.io.SessionInputBuffer, int, int, org.apache.http.message.LineParser) throws org.apache.http.HttpException, java.io.IOException;
-    field protected final org.apache.http.message.LineParser lineParser;
-  }
-
-  public abstract deprecated class AbstractMessageWriter implements org.apache.http.io.HttpMessageWriter {
-    ctor public AbstractMessageWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method public void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-    method protected abstract void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-    field protected final org.apache.http.util.CharArrayBuffer lineBuf;
-    field protected final org.apache.http.message.LineFormatter lineFormatter;
-    field protected final org.apache.http.io.SessionOutputBuffer sessionBuffer;
-  }
-
-  public abstract deprecated class AbstractSessionInputBuffer implements org.apache.http.io.SessionInputBuffer {
-    ctor public AbstractSessionInputBuffer();
-    method protected int fillBuffer() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method protected boolean hasBufferedData();
-    method protected void init(java.io.InputStream, int, org.apache.http.params.HttpParams);
-    method public int read() throws java.io.IOException;
-    method public int read(byte[], int, int) throws java.io.IOException;
-    method public int read(byte[]) throws java.io.IOException;
-    method public int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public java.lang.String readLine() throws java.io.IOException;
-  }
-
-  public abstract deprecated class AbstractSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer {
-    ctor public AbstractSessionOutputBuffer();
-    method public void flush() throws java.io.IOException;
-    method protected void flushBuffer() throws java.io.IOException;
-    method public org.apache.http.io.HttpTransportMetrics getMetrics();
-    method protected void init(java.io.OutputStream, int, org.apache.http.params.HttpParams);
-    method public void write(byte[], int, int) throws java.io.IOException;
-    method public void write(byte[]) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method public void writeLine(java.lang.String) throws java.io.IOException;
-    method public void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-  public deprecated class ChunkedInputStream extends java.io.InputStream {
-    ctor public ChunkedInputStream(org.apache.http.io.SessionInputBuffer);
-    method public org.apache.http.Header[] getFooters();
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class ChunkedOutputStream extends java.io.OutputStream {
-    ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer, int) throws java.io.IOException;
-    ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer) throws java.io.IOException;
-    method public void finish() throws java.io.IOException;
-    method protected void flushCache() throws java.io.IOException;
-    method protected void flushCacheWithAppend(byte[], int, int) throws java.io.IOException;
-    method public void write(int) throws java.io.IOException;
-    method protected void writeClosingChunk() throws java.io.IOException;
-  }
-
-  public deprecated class ContentLengthInputStream extends java.io.InputStream {
-    ctor public ContentLengthInputStream(org.apache.http.io.SessionInputBuffer, long);
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class ContentLengthOutputStream extends java.io.OutputStream {
-    ctor public ContentLengthOutputStream(org.apache.http.io.SessionOutputBuffer, long);
-    method public void write(int) throws java.io.IOException;
-  }
-
-  public deprecated class HttpRequestParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public HttpRequestParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpRequestFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public deprecated class HttpRequestWriter extends org.apache.http.impl.io.AbstractMessageWriter {
-    ctor public HttpRequestWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-  }
-
-  public deprecated class HttpResponseParser extends org.apache.http.impl.io.AbstractMessageParser {
-    ctor public HttpResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams);
-    method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public deprecated class HttpResponseWriter extends org.apache.http.impl.io.AbstractMessageWriter {
-    ctor public HttpResponseWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams);
-    method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException;
-  }
-
-  public deprecated class HttpTransportMetricsImpl implements org.apache.http.io.HttpTransportMetrics {
-    ctor public HttpTransportMetricsImpl();
-    method public long getBytesTransferred();
-    method public void incrementBytesTransferred(long);
-    method public void reset();
-    method public void setBytesTransferred(long);
-  }
-
-  public deprecated class IdentityInputStream extends java.io.InputStream {
-    ctor public IdentityInputStream(org.apache.http.io.SessionInputBuffer);
-    method public int read() throws java.io.IOException;
-  }
-
-  public deprecated class IdentityOutputStream extends java.io.OutputStream {
-    ctor public IdentityOutputStream(org.apache.http.io.SessionOutputBuffer);
-    method public void write(int) throws java.io.IOException;
-  }
-
-  public deprecated class SocketInputBuffer extends org.apache.http.impl.io.AbstractSessionInputBuffer {
-    ctor public SocketInputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public boolean isDataAvailable(int) throws java.io.IOException;
-  }
-
-  public deprecated class SocketOutputBuffer extends org.apache.http.impl.io.AbstractSessionOutputBuffer {
-    ctor public SocketOutputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.io {
-
-  public abstract deprecated interface HttpMessageParser {
-    method public abstract org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpMessageWriter {
-    method public abstract void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpTransportMetrics {
-    method public abstract long getBytesTransferred();
-    method public abstract void reset();
-  }
-
-  public abstract deprecated interface SessionInputBuffer {
-    method public abstract org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public abstract boolean isDataAvailable(int) throws java.io.IOException;
-    method public abstract int read(byte[], int, int) throws java.io.IOException;
-    method public abstract int read(byte[]) throws java.io.IOException;
-    method public abstract int read() throws java.io.IOException;
-    method public abstract int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-    method public abstract java.lang.String readLine() throws java.io.IOException;
-  }
-
-  public abstract deprecated interface SessionOutputBuffer {
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract org.apache.http.io.HttpTransportMetrics getMetrics();
-    method public abstract void write(byte[], int, int) throws java.io.IOException;
-    method public abstract void write(byte[]) throws java.io.IOException;
-    method public abstract void write(int) throws java.io.IOException;
-    method public abstract void writeLine(java.lang.String) throws java.io.IOException;
-    method public abstract void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException;
-  }
-
-}
-
-package org.apache.http.message {
-
-  public abstract deprecated class AbstractHttpMessage implements org.apache.http.HttpMessage {
-    ctor protected AbstractHttpMessage(org.apache.http.params.HttpParams);
-    ctor protected AbstractHttpMessage();
-    method public void addHeader(org.apache.http.Header);
-    method public void addHeader(java.lang.String, java.lang.String);
-    method public boolean containsHeader(java.lang.String);
-    method public org.apache.http.Header[] getAllHeaders();
-    method public org.apache.http.Header getFirstHeader(java.lang.String);
-    method public org.apache.http.Header[] getHeaders(java.lang.String);
-    method public org.apache.http.Header getLastHeader(java.lang.String);
-    method public org.apache.http.params.HttpParams getParams();
-    method public org.apache.http.HeaderIterator headerIterator();
-    method public org.apache.http.HeaderIterator headerIterator(java.lang.String);
-    method public void removeHeader(org.apache.http.Header);
-    method public void removeHeaders(java.lang.String);
-    method public void setHeader(org.apache.http.Header);
-    method public void setHeader(java.lang.String, java.lang.String);
-    method public void setHeaders(org.apache.http.Header[]);
-    method public void setParams(org.apache.http.params.HttpParams);
-    field protected org.apache.http.message.HeaderGroup headergroup;
-    field protected org.apache.http.params.HttpParams params;
-  }
-
-  public deprecated class BasicHeader implements java.lang.Cloneable org.apache.http.Header {
-    ctor public BasicHeader(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicHeaderElement implements java.lang.Cloneable org.apache.http.HeaderElement {
-    ctor public BasicHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]);
-    ctor public BasicHeaderElement(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getName();
-    method public org.apache.http.NameValuePair getParameter(int);
-    method public org.apache.http.NameValuePair getParameterByName(java.lang.String);
-    method public int getParameterCount();
-    method public org.apache.http.NameValuePair[] getParameters();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicHeaderElementIterator implements org.apache.http.HeaderElementIterator {
-    ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator, org.apache.http.message.HeaderValueParser);
-    ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.HeaderElement nextElement() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-  }
-
-  public deprecated class BasicHeaderIterator implements org.apache.http.HeaderIterator {
-    ctor public BasicHeaderIterator(org.apache.http.Header[], java.lang.String);
-    method protected boolean filterHeader(int);
-    method protected int findNext(int);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.Header nextHeader() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-    field protected final org.apache.http.Header[] allHeaders;
-    field protected int currentIndex;
-    field protected java.lang.String headerName;
-  }
-
-  public deprecated class BasicHeaderValueFormatter implements org.apache.http.message.HeaderValueFormatter {
-    ctor public BasicHeaderValueFormatter();
-    method protected void doFormatValue(org.apache.http.util.CharArrayBuffer, java.lang.String, boolean);
-    method protected int estimateElementsLen(org.apache.http.HeaderElement[]);
-    method protected int estimateHeaderElementLen(org.apache.http.HeaderElement);
-    method protected int estimateNameValuePairLen(org.apache.http.NameValuePair);
-    method protected int estimateParametersLen(org.apache.http.NameValuePair[]);
-    method public static final java.lang.String formatElements(org.apache.http.HeaderElement[], boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatElements(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement[], boolean);
-    method public static final java.lang.String formatHeaderElement(org.apache.http.HeaderElement, boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement, boolean);
-    method public static final java.lang.String formatNameValuePair(org.apache.http.NameValuePair, boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair, boolean);
-    method public static final java.lang.String formatParameters(org.apache.http.NameValuePair[], boolean, org.apache.http.message.HeaderValueFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair[], boolean);
-    method protected boolean isSeparator(char);
-    method protected boolean isUnsafe(char);
-    field public static final org.apache.http.message.BasicHeaderValueFormatter DEFAULT;
-    field public static final java.lang.String SEPARATORS = " ;,:@()<>\\\"/[]?={}\t";
-    field public static final java.lang.String UNSAFE_CHARS = "\"\\";
-  }
-
-  public deprecated class BasicHeaderValueParser implements org.apache.http.message.HeaderValueParser {
-    ctor public BasicHeaderValueParser();
-    method protected org.apache.http.HeaderElement createHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]);
-    method protected org.apache.http.NameValuePair createNameValuePair(java.lang.String, java.lang.String);
-    method public static final org.apache.http.HeaderElement[] parseElements(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.HeaderElement[] parseElements(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.HeaderElement parseHeaderElement(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.HeaderElement parseHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.NameValuePair parseNameValuePair(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor, char[]);
-    method public static final org.apache.http.NameValuePair[] parseParameters(java.lang.String, org.apache.http.message.HeaderValueParser) throws org.apache.http.ParseException;
-    method public org.apache.http.NameValuePair[] parseParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    field public static final org.apache.http.message.BasicHeaderValueParser DEFAULT;
-  }
-
-  public deprecated class BasicHttpEntityEnclosingRequest extends org.apache.http.message.BasicHttpRequest implements org.apache.http.HttpEntityEnclosingRequest {
-    ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String);
-    ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    ctor public BasicHttpEntityEnclosingRequest(org.apache.http.RequestLine);
-    method public boolean expectContinue();
-    method public org.apache.http.HttpEntity getEntity();
-    method public void setEntity(org.apache.http.HttpEntity);
-  }
-
-  public deprecated class BasicHttpRequest extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpRequest {
-    ctor public BasicHttpRequest(java.lang.String, java.lang.String);
-    ctor public BasicHttpRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    ctor public BasicHttpRequest(org.apache.http.RequestLine);
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public org.apache.http.RequestLine getRequestLine();
-  }
-
-  public deprecated class BasicHttpResponse extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpResponse {
-    ctor public BasicHttpResponse(org.apache.http.StatusLine, org.apache.http.ReasonPhraseCatalog, java.util.Locale);
-    ctor public BasicHttpResponse(org.apache.http.StatusLine);
-    ctor public BasicHttpResponse(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public org.apache.http.HttpEntity getEntity();
-    method public java.util.Locale getLocale();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method protected java.lang.String getReason(int);
-    method public org.apache.http.StatusLine getStatusLine();
-    method public void setEntity(org.apache.http.HttpEntity);
-    method public void setLocale(java.util.Locale);
-    method public void setReasonPhrase(java.lang.String);
-    method public void setStatusCode(int);
-    method public void setStatusLine(org.apache.http.StatusLine);
-    method public void setStatusLine(org.apache.http.ProtocolVersion, int);
-    method public void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-  }
-
-  public deprecated class BasicLineFormatter implements org.apache.http.message.LineFormatter {
-    ctor public BasicLineFormatter();
-    method public org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion);
-    method protected void doFormatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method protected void doFormatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method protected void doFormatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-    method protected int estimateProtocolVersionLen(org.apache.http.ProtocolVersion);
-    method public static final java.lang.String formatHeader(org.apache.http.Header, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method public static final java.lang.String formatProtocolVersion(org.apache.http.ProtocolVersion, org.apache.http.message.LineFormatter);
-    method public static final java.lang.String formatRequestLine(org.apache.http.RequestLine, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method public static final java.lang.String formatStatusLine(org.apache.http.StatusLine, org.apache.http.message.LineFormatter);
-    method public org.apache.http.util.CharArrayBuffer formatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-    method protected org.apache.http.util.CharArrayBuffer initBuffer(org.apache.http.util.CharArrayBuffer);
-    field public static final org.apache.http.message.BasicLineFormatter DEFAULT;
-  }
-
-  public deprecated class BasicLineParser implements org.apache.http.message.LineParser {
-    ctor public BasicLineParser(org.apache.http.ProtocolVersion);
-    ctor public BasicLineParser();
-    method protected org.apache.http.ProtocolVersion createProtocolVersion(int, int);
-    method protected org.apache.http.RequestLine createRequestLine(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    method protected org.apache.http.StatusLine createStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public boolean hasProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public static final org.apache.http.Header parseHeader(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.Header parseHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public static final org.apache.http.ProtocolVersion parseProtocolVersion(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.ProtocolVersion parseProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public static final org.apache.http.RequestLine parseRequestLine(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.RequestLine parseRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public static final org.apache.http.StatusLine parseStatusLine(java.lang.String, org.apache.http.message.LineParser) throws org.apache.http.ParseException;
-    method public org.apache.http.StatusLine parseStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method protected void skipWhitespace(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    field public static final org.apache.http.message.BasicLineParser DEFAULT;
-    field protected final org.apache.http.ProtocolVersion protocol;
-  }
-
-  public deprecated class BasicListHeaderIterator implements org.apache.http.HeaderIterator {
-    ctor public BasicListHeaderIterator(java.util.List, java.lang.String);
-    method protected boolean filterHeader(int);
-    method protected int findNext(int);
-    method public boolean hasNext();
-    method public final java.lang.Object next() throws java.util.NoSuchElementException;
-    method public org.apache.http.Header nextHeader() throws java.util.NoSuchElementException;
-    method public void remove() throws java.lang.UnsupportedOperationException;
-    field protected final java.util.List allHeaders;
-    field protected int currentIndex;
-    field protected java.lang.String headerName;
-    field protected int lastIndex;
-  }
-
-  public deprecated class BasicNameValuePair implements java.lang.Cloneable org.apache.http.NameValuePair {
-    ctor public BasicNameValuePair(java.lang.String, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-  }
-
-  public deprecated class BasicRequestLine implements java.lang.Cloneable org.apache.http.RequestLine {
-    ctor public BasicRequestLine(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public java.lang.String getMethod();
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public java.lang.String getUri();
-  }
-
-  public deprecated class BasicStatusLine implements java.lang.Cloneable org.apache.http.StatusLine {
-    ctor public BasicStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String);
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.ProtocolVersion getProtocolVersion();
-    method public java.lang.String getReasonPhrase();
-    method public int getStatusCode();
-  }
-
-  public deprecated class BasicTokenIterator implements org.apache.http.TokenIterator {
-    ctor public BasicTokenIterator(org.apache.http.HeaderIterator);
-    method protected java.lang.String createToken(java.lang.String, int, int);
-    method protected int findNext(int) throws org.apache.http.ParseException;
-    method protected int findTokenEnd(int);
-    method protected int findTokenSeparator(int);
-    method protected int findTokenStart(int);
-    method public boolean hasNext();
-    method protected boolean isHttpSeparator(char);
-    method protected boolean isTokenChar(char);
-    method protected boolean isTokenSeparator(char);
-    method protected boolean isWhitespace(char);
-    method public final java.lang.Object next() throws java.util.NoSuchElementException, org.apache.http.ParseException;
-    method public java.lang.String nextToken() throws java.util.NoSuchElementException, org.apache.http.ParseException;
-    method public final void remove() throws java.lang.UnsupportedOperationException;
-    field public static final java.lang.String HTTP_SEPARATORS = " ,;=()<>@:\\\"/[]?{}\t";
-    field protected java.lang.String currentHeader;
-    field protected java.lang.String currentToken;
-    field protected final org.apache.http.HeaderIterator headerIt;
-    field protected int searchPos;
-  }
-
-  public deprecated class BufferedHeader implements java.lang.Cloneable org.apache.http.FormattedHeader {
-    ctor public BufferedHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.util.CharArrayBuffer getBuffer();
-    method public org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException;
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
-    method public int getValuePos();
-  }
-
-  public deprecated class HeaderGroup implements java.lang.Cloneable {
-    ctor public HeaderGroup();
-    method public void addHeader(org.apache.http.Header);
-    method public void clear();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public boolean containsHeader(java.lang.String);
-    method public org.apache.http.message.HeaderGroup copy();
-    method public org.apache.http.Header[] getAllHeaders();
-    method public org.apache.http.Header getCondensedHeader(java.lang.String);
-    method public org.apache.http.Header getFirstHeader(java.lang.String);
-    method public org.apache.http.Header[] getHeaders(java.lang.String);
-    method public org.apache.http.Header getLastHeader(java.lang.String);
-    method public org.apache.http.HeaderIterator iterator();
-    method public org.apache.http.HeaderIterator iterator(java.lang.String);
-    method public void removeHeader(org.apache.http.Header);
-    method public void setHeaders(org.apache.http.Header[]);
-    method public void updateHeader(org.apache.http.Header);
-  }
-
-  public abstract deprecated interface HeaderValueFormatter {
-    method public abstract org.apache.http.util.CharArrayBuffer formatElements(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement[], boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement, boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair, boolean);
-    method public abstract org.apache.http.util.CharArrayBuffer formatParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair[], boolean);
-  }
-
-  public abstract deprecated interface HeaderValueParser {
-    method public abstract org.apache.http.HeaderElement[] parseElements(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.HeaderElement parseHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.NameValuePair[] parseParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-  }
-
-  public abstract deprecated interface LineFormatter {
-    method public abstract org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion);
-    method public abstract org.apache.http.util.CharArrayBuffer formatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header);
-    method public abstract org.apache.http.util.CharArrayBuffer formatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine);
-    method public abstract org.apache.http.util.CharArrayBuffer formatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine);
-  }
-
-  public abstract deprecated interface LineParser {
-    method public abstract boolean hasProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor);
-    method public abstract org.apache.http.Header parseHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.ProtocolVersion parseProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.RequestLine parseRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-    method public abstract org.apache.http.StatusLine parseStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException;
-  }
-
-  public deprecated class ParserCursor {
-    ctor public ParserCursor(int, int);
-    method public boolean atEnd();
-    method public int getLowerBound();
-    method public int getPos();
-    method public int getUpperBound();
-    method public void updatePos(int);
-  }
-
-}
-
 package org.apache.http.params {
 
-  public abstract deprecated class AbstractHttpParams implements org.apache.http.params.HttpParams {
-    ctor protected AbstractHttpParams();
-    method public boolean getBooleanParameter(java.lang.String, boolean);
-    method public double getDoubleParameter(java.lang.String, double);
-    method public int getIntParameter(java.lang.String, int);
-    method public long getLongParameter(java.lang.String, long);
-    method public boolean isParameterFalse(java.lang.String);
-    method public boolean isParameterTrue(java.lang.String);
-    method public org.apache.http.params.HttpParams setBooleanParameter(java.lang.String, boolean);
-    method public org.apache.http.params.HttpParams setDoubleParameter(java.lang.String, double);
-    method public org.apache.http.params.HttpParams setIntParameter(java.lang.String, int);
-    method public org.apache.http.params.HttpParams setLongParameter(java.lang.String, long);
-  }
-
-  public final deprecated class BasicHttpParams extends org.apache.http.params.AbstractHttpParams implements java.lang.Cloneable java.io.Serializable {
-    ctor public BasicHttpParams();
-    method public void clear();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.params.HttpParams copy();
-    method protected void copyParams(org.apache.http.params.HttpParams);
-    method public java.lang.Object getParameter(java.lang.String);
-    method public boolean isParameterSet(java.lang.String);
-    method public boolean isParameterSetLocally(java.lang.String);
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
-    method public void setParameters(java.lang.String[], java.lang.Object);
-  }
-
   public abstract deprecated interface CoreConnectionPNames {
     field public static final java.lang.String CONNECTION_TIMEOUT = "http.connection.timeout";
     field public static final java.lang.String MAX_HEADER_COUNT = "http.connection.max-header-count";
@@ -59908,41 +57762,6 @@
     field public static final java.lang.String TCP_NODELAY = "http.tcp.nodelay";
   }
 
-  public abstract deprecated interface CoreProtocolPNames {
-    field public static final java.lang.String HTTP_CONTENT_CHARSET = "http.protocol.content-charset";
-    field public static final java.lang.String HTTP_ELEMENT_CHARSET = "http.protocol.element-charset";
-    field public static final java.lang.String ORIGIN_SERVER = "http.origin-server";
-    field public static final java.lang.String PROTOCOL_VERSION = "http.protocol.version";
-    field public static final java.lang.String STRICT_TRANSFER_ENCODING = "http.protocol.strict-transfer-encoding";
-    field public static final java.lang.String USER_AGENT = "http.useragent";
-    field public static final java.lang.String USE_EXPECT_CONTINUE = "http.protocol.expect-continue";
-    field public static final java.lang.String WAIT_FOR_CONTINUE = "http.protocol.wait-for-continue";
-  }
-
-  public final deprecated class DefaultedHttpParams extends org.apache.http.params.AbstractHttpParams {
-    ctor public DefaultedHttpParams(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams);
-    method public org.apache.http.params.HttpParams copy();
-    method public org.apache.http.params.HttpParams getDefaults();
-    method public java.lang.Object getParameter(java.lang.String);
-    method public boolean removeParameter(java.lang.String);
-    method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
-  }
-
-  public abstract deprecated class HttpAbstractParamBean {
-    ctor public HttpAbstractParamBean(org.apache.http.params.HttpParams);
-    field protected final org.apache.http.params.HttpParams params;
-  }
-
-  public deprecated class HttpConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public HttpConnectionParamBean(org.apache.http.params.HttpParams);
-    method public void setConnectionTimeout(int);
-    method public void setLinger(int);
-    method public void setSoTimeout(int);
-    method public void setSocketBufferSize(int);
-    method public void setStaleCheckingEnabled(boolean);
-    method public void setTcpNoDelay(boolean);
-  }
-
   public final deprecated class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames {
     method public static int getConnectionTimeout(org.apache.http.params.HttpParams);
     method public static int getLinger(org.apache.http.params.HttpParams);
@@ -59975,359 +57794,6 @@
     method public abstract org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
   }
 
-  public deprecated class HttpProtocolParamBean extends org.apache.http.params.HttpAbstractParamBean {
-    ctor public HttpProtocolParamBean(org.apache.http.params.HttpParams);
-    method public void setContentCharset(java.lang.String);
-    method public void setHttpElementCharset(java.lang.String);
-    method public void setUseExpectContinue(boolean);
-    method public void setUserAgent(java.lang.String);
-    method public void setVersion(org.apache.http.HttpVersion);
-  }
-
-  public final deprecated class HttpProtocolParams implements org.apache.http.params.CoreProtocolPNames {
-    method public static java.lang.String getContentCharset(org.apache.http.params.HttpParams);
-    method public static java.lang.String getHttpElementCharset(org.apache.http.params.HttpParams);
-    method public static java.lang.String getUserAgent(org.apache.http.params.HttpParams);
-    method public static org.apache.http.ProtocolVersion getVersion(org.apache.http.params.HttpParams);
-    method public static void setContentCharset(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setHttpElementCharset(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setUseExpectContinue(org.apache.http.params.HttpParams, boolean);
-    method public static void setUserAgent(org.apache.http.params.HttpParams, java.lang.String);
-    method public static void setVersion(org.apache.http.params.HttpParams, org.apache.http.ProtocolVersion);
-    method public static boolean useExpectContinue(org.apache.http.params.HttpParams);
-  }
-
-}
-
-package org.apache.http.protocol {
-
-  public deprecated class BasicHttpContext implements org.apache.http.protocol.HttpContext {
-    ctor public BasicHttpContext();
-    ctor public BasicHttpContext(org.apache.http.protocol.HttpContext);
-    method public java.lang.Object getAttribute(java.lang.String);
-    method public java.lang.Object removeAttribute(java.lang.String);
-    method public void setAttribute(java.lang.String, java.lang.Object);
-  }
-
-  public final deprecated class BasicHttpProcessor implements java.lang.Cloneable org.apache.http.protocol.HttpProcessor org.apache.http.protocol.HttpRequestInterceptorList org.apache.http.protocol.HttpResponseInterceptorList {
-    ctor public BasicHttpProcessor();
-    method public final void addInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public final void addInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public final void addInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public final void addInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public void clearInterceptors();
-    method public void clearRequestInterceptors();
-    method public void clearResponseInterceptors();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public org.apache.http.protocol.BasicHttpProcessor copy();
-    method protected void copyInterceptors(org.apache.http.protocol.BasicHttpProcessor);
-    method public org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public int getRequestInterceptorCount();
-    method public org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public int getResponseInterceptorCount();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void removeRequestInterceptorByClass(java.lang.Class);
-    method public void removeResponseInterceptorByClass(java.lang.Class);
-    method public void setInterceptors(java.util.List);
-    field protected java.util.List requestInterceptors;
-    field protected java.util.List responseInterceptors;
-  }
-
-  public final deprecated class DefaultedHttpContext implements org.apache.http.protocol.HttpContext {
-    ctor public DefaultedHttpContext(org.apache.http.protocol.HttpContext, org.apache.http.protocol.HttpContext);
-    method public java.lang.Object getAttribute(java.lang.String);
-    method public org.apache.http.protocol.HttpContext getDefaults();
-    method public java.lang.Object removeAttribute(java.lang.String);
-    method public void setAttribute(java.lang.String, java.lang.Object);
-  }
-
-  public abstract deprecated interface ExecutionContext {
-    field public static final java.lang.String HTTP_CONNECTION = "http.connection";
-    field public static final java.lang.String HTTP_PROXY_HOST = "http.proxy_host";
-    field public static final java.lang.String HTTP_REQUEST = "http.request";
-    field public static final java.lang.String HTTP_REQ_SENT = "http.request_sent";
-    field public static final java.lang.String HTTP_RESPONSE = "http.response";
-    field public static final java.lang.String HTTP_TARGET_HOST = "http.target_host";
-  }
-
-  public final deprecated class HTTP {
-    method public static boolean isWhitespace(char);
-    field public static final java.lang.String ASCII = "ASCII";
-    field public static final java.lang.String CHARSET_PARAM = "; charset=";
-    field public static final java.lang.String CHUNK_CODING = "chunked";
-    field public static final java.lang.String CONN_CLOSE = "Close";
-    field public static final java.lang.String CONN_DIRECTIVE = "Connection";
-    field public static final java.lang.String CONN_KEEP_ALIVE = "Keep-Alive";
-    field public static final java.lang.String CONTENT_ENCODING = "Content-Encoding";
-    field public static final java.lang.String CONTENT_LEN = "Content-Length";
-    field public static final java.lang.String CONTENT_TYPE = "Content-Type";
-    field public static final int CR = 13; // 0xd
-    field public static final java.lang.String DATE_HEADER = "Date";
-    field public static final java.lang.String DEFAULT_CONTENT_CHARSET = "ISO-8859-1";
-    field public static final java.lang.String DEFAULT_CONTENT_TYPE = "application/octet-stream";
-    field public static final java.lang.String DEFAULT_PROTOCOL_CHARSET = "US-ASCII";
-    field public static final java.lang.String EXPECT_CONTINUE = "100-continue";
-    field public static final java.lang.String EXPECT_DIRECTIVE = "Expect";
-    field public static final int HT = 9; // 0x9
-    field public static final java.lang.String IDENTITY_CODING = "identity";
-    field public static final java.lang.String ISO_8859_1 = "ISO-8859-1";
-    field public static final int LF = 10; // 0xa
-    field public static final java.lang.String OCTET_STREAM_TYPE = "application/octet-stream";
-    field public static final java.lang.String PLAIN_TEXT_TYPE = "text/plain";
-    field public static final java.lang.String SERVER_HEADER = "Server";
-    field public static final int SP = 32; // 0x20
-    field public static final java.lang.String TARGET_HOST = "Host";
-    field public static final java.lang.String TRANSFER_ENCODING = "Transfer-Encoding";
-    field public static final java.lang.String USER_AGENT = "User-Agent";
-    field public static final java.lang.String US_ASCII = "US-ASCII";
-    field public static final java.lang.String UTF_16 = "UTF-16";
-    field public static final java.lang.String UTF_8 = "UTF-8";
-  }
-
-  public abstract deprecated interface HttpContext {
-    method public abstract java.lang.Object getAttribute(java.lang.String);
-    method public abstract java.lang.Object removeAttribute(java.lang.String);
-    method public abstract void setAttribute(java.lang.String, java.lang.Object);
-    field public static final java.lang.String RESERVED_PREFIX = "http.";
-  }
-
-  public deprecated class HttpDateGenerator {
-    ctor public HttpDateGenerator();
-    method public synchronized java.lang.String getCurrentDate();
-    field public static final java.util.TimeZone GMT;
-    field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
-  }
-
-  public abstract deprecated interface HttpExpectationVerifier {
-    method public abstract void verify(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException;
-  }
-
-  public abstract deprecated interface HttpProcessor implements org.apache.http.HttpRequestInterceptor org.apache.http.HttpResponseInterceptor {
-  }
-
-  public deprecated class HttpRequestExecutor {
-    ctor public HttpRequestExecutor();
-    method protected boolean canResponseHaveBody(org.apache.http.HttpRequest, org.apache.http.HttpResponse);
-    method protected org.apache.http.HttpResponse doReceiveResponse(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method protected org.apache.http.HttpResponse doSendRequest(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.HttpResponse execute(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void postProcess(org.apache.http.HttpResponse, org.apache.http.protocol.HttpProcessor, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void preProcess(org.apache.http.HttpRequest, org.apache.http.protocol.HttpProcessor, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public abstract deprecated interface HttpRequestHandler {
-    method public abstract void handle(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class HttpRequestHandlerRegistry implements org.apache.http.protocol.HttpRequestHandlerResolver {
-    ctor public HttpRequestHandlerRegistry();
-    method public org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String);
-    method protected deprecated boolean matchUriRequestPattern(java.lang.String, java.lang.String);
-    method public void register(java.lang.String, org.apache.http.protocol.HttpRequestHandler);
-    method public void setHandlers(java.util.Map);
-    method public void unregister(java.lang.String);
-  }
-
-  public abstract deprecated interface HttpRequestHandlerResolver {
-    method public abstract org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String);
-  }
-
-  public abstract deprecated interface HttpRequestInterceptorList {
-    method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor);
-    method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int);
-    method public abstract void clearRequestInterceptors();
-    method public abstract org.apache.http.HttpRequestInterceptor getRequestInterceptor(int);
-    method public abstract int getRequestInterceptorCount();
-    method public abstract void removeRequestInterceptorByClass(java.lang.Class);
-    method public abstract void setInterceptors(java.util.List);
-  }
-
-  public abstract deprecated interface HttpResponseInterceptorList {
-    method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor);
-    method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int);
-    method public abstract void clearResponseInterceptors();
-    method public abstract org.apache.http.HttpResponseInterceptor getResponseInterceptor(int);
-    method public abstract int getResponseInterceptorCount();
-    method public abstract void removeResponseInterceptorByClass(java.lang.Class);
-    method public abstract void setInterceptors(java.util.List);
-  }
-
-  public deprecated class HttpService {
-    ctor public HttpService(org.apache.http.protocol.HttpProcessor, org.apache.http.ConnectionReuseStrategy, org.apache.http.HttpResponseFactory);
-    method protected void doService(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public org.apache.http.params.HttpParams getParams();
-    method protected void handleException(org.apache.http.HttpException, org.apache.http.HttpResponse);
-    method public void handleRequest(org.apache.http.HttpServerConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-    method public void setConnReuseStrategy(org.apache.http.ConnectionReuseStrategy);
-    method public void setExpectationVerifier(org.apache.http.protocol.HttpExpectationVerifier);
-    method public void setHandlerResolver(org.apache.http.protocol.HttpRequestHandlerResolver);
-    method public void setHttpProcessor(org.apache.http.protocol.HttpProcessor);
-    method public void setParams(org.apache.http.params.HttpParams);
-    method public void setResponseFactory(org.apache.http.HttpResponseFactory);
-  }
-
-  public deprecated class RequestConnControl implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestConnControl();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestContent implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestContent();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestDate implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestDate();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestExpectContinue implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestExpectContinue();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestTargetHost implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestTargetHost();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class RequestUserAgent implements org.apache.http.HttpRequestInterceptor {
-    ctor public RequestUserAgent();
-    method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseConnControl implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseConnControl();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseContent implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseContent();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseDate implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseDate();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class ResponseServer implements org.apache.http.HttpResponseInterceptor {
-    ctor public ResponseServer();
-    method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException;
-  }
-
-  public deprecated class SyncBasicHttpContext extends org.apache.http.protocol.BasicHttpContext {
-    ctor public SyncBasicHttpContext(org.apache.http.protocol.HttpContext);
-  }
-
-  public deprecated class UriPatternMatcher {
-    ctor public UriPatternMatcher();
-    method public java.lang.Object lookup(java.lang.String);
-    method protected boolean matchUriRequestPattern(java.lang.String, java.lang.String);
-    method public void register(java.lang.String, java.lang.Object);
-    method public void setHandlers(java.util.Map);
-    method public void unregister(java.lang.String);
-  }
-
-}
-
-package org.apache.http.util {
-
-  public final deprecated class ByteArrayBuffer {
-    ctor public ByteArrayBuffer(int);
-    method public void append(byte[], int, int);
-    method public void append(int);
-    method public void append(char[], int, int);
-    method public void append(org.apache.http.util.CharArrayBuffer, int, int);
-    method public byte[] buffer();
-    method public int byteAt(int);
-    method public int capacity();
-    method public void clear();
-    method public boolean isEmpty();
-    method public boolean isFull();
-    method public int length();
-    method public void setLength(int);
-    method public byte[] toByteArray();
-  }
-
-  public final deprecated class CharArrayBuffer {
-    ctor public CharArrayBuffer(int);
-    method public void append(char[], int, int);
-    method public void append(java.lang.String);
-    method public void append(org.apache.http.util.CharArrayBuffer, int, int);
-    method public void append(org.apache.http.util.CharArrayBuffer);
-    method public void append(char);
-    method public void append(byte[], int, int);
-    method public void append(org.apache.http.util.ByteArrayBuffer, int, int);
-    method public void append(java.lang.Object);
-    method public char[] buffer();
-    method public int capacity();
-    method public char charAt(int);
-    method public void clear();
-    method public void ensureCapacity(int);
-    method public int indexOf(int, int, int);
-    method public int indexOf(int);
-    method public boolean isEmpty();
-    method public boolean isFull();
-    method public int length();
-    method public void setLength(int);
-    method public java.lang.String substring(int, int);
-    method public java.lang.String substringTrimmed(int, int);
-    method public char[] toCharArray();
-  }
-
-  public final deprecated class EncodingUtils {
-    method public static byte[] getAsciiBytes(java.lang.String);
-    method public static java.lang.String getAsciiString(byte[], int, int);
-    method public static java.lang.String getAsciiString(byte[]);
-    method public static byte[] getBytes(java.lang.String, java.lang.String);
-    method public static java.lang.String getString(byte[], int, int, java.lang.String);
-    method public static java.lang.String getString(byte[], java.lang.String);
-  }
-
-  public final deprecated class EntityUtils {
-    method public static java.lang.String getContentCharSet(org.apache.http.HttpEntity) throws org.apache.http.ParseException;
-    method public static byte[] toByteArray(org.apache.http.HttpEntity) throws java.io.IOException;
-    method public static java.lang.String toString(org.apache.http.HttpEntity, java.lang.String) throws java.io.IOException, org.apache.http.ParseException;
-    method public static java.lang.String toString(org.apache.http.HttpEntity) throws java.io.IOException, org.apache.http.ParseException;
-  }
-
-  public final deprecated class ExceptionUtils {
-    method public static void initCause(java.lang.Throwable, java.lang.Throwable);
-  }
-
-  public final deprecated class LangUtils {
-    method public static boolean equals(java.lang.Object, java.lang.Object);
-    method public static boolean equals(java.lang.Object[], java.lang.Object[]);
-    method public static int hashCode(int, int);
-    method public static int hashCode(int, boolean);
-    method public static int hashCode(int, java.lang.Object);
-    field public static final int HASH_OFFSET = 37; // 0x25
-    field public static final int HASH_SEED = 17; // 0x11
-  }
-
-  public deprecated class VersionInfo {
-    ctor protected VersionInfo(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method protected static final org.apache.http.util.VersionInfo fromMap(java.lang.String, java.util.Map, java.lang.ClassLoader);
-    method public final java.lang.String getClassloader();
-    method public final java.lang.String getModule();
-    method public final java.lang.String getPackage();
-    method public final java.lang.String getRelease();
-    method public final java.lang.String getTimestamp();
-    method public static final org.apache.http.util.VersionInfo[] loadVersionInfo(java.lang.String[], java.lang.ClassLoader);
-    method public static final org.apache.http.util.VersionInfo loadVersionInfo(java.lang.String, java.lang.ClassLoader);
-    field public static final java.lang.String PROPERTY_MODULE = "info.module";
-    field public static final java.lang.String PROPERTY_RELEASE = "info.release";
-    field public static final java.lang.String PROPERTY_TIMESTAMP = "info.timestamp";
-    field public static final java.lang.String UNAVAILABLE = "UNAVAILABLE";
-    field public static final java.lang.String VERSION_PROPERTY_FILE = "version.properties";
-  }
-
 }
 
 package org.json {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 1b69ee8..1b209a9 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,8 +6,20 @@
 
 }
 
+package android.net {
+
+  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
+  }
+
+}
+
 package android.os {
 
+  public class BatteryManager {
+    ctor public BatteryManager();
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
@@ -22,6 +34,22 @@
 
 }
 
+package android.provider {
+
+  public static final class Settings.System extends android.provider.Settings.NameValueTable {
+    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
+    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
+    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final java.lang.String VOLUME_RING = "volume_ring";
+    field public static final java.lang.String[] VOLUME_SETTINGS;
+    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
+    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 2ea1d4d..29ba1d7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -44,7 +44,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SELinux;
@@ -118,6 +117,8 @@
                 "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
                 "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
                 "       am clear-debug-app\n" +
+                "       am set-watch-heap <PROCESS> <MEM-LIMIT>\n" +
+                "       am clear-watch-heap\n" +
                 "       am monitor [--gdb <port>]\n" +
                 "       am hang [--allow-restart]\n" +
                 "       am restart\n" +
@@ -132,10 +133,13 @@
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack split <STACK_ID> <v|h> [INTENT]\n" +
                 "       am stack list\n" +
                 "       am stack info <STACK_ID>\n" +
-                "       am lock-task <TASK_ID>\n" +
-                "       am lock-task stop\n" +
+                "       am task lock <TASK_ID>\n" +
+                "       am task lock stop\n" +
+                "       am task resizeable <TASK_ID> [true|false]\n" +
+                "       am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am get-config\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
@@ -209,6 +213,11 @@
                 "\n" +
                 "am clear-debug-app: clear the previously set-debug-app.\n" +
                 "\n" +
+                "am set-watch-heap: start monitoring pss size of <PROCESS>, if it is at or\n" +
+                "    above <HEAP-LIMIT> then a heap dump is collected for the user to report\n" +
+                "\n" +
+                "am clear-watch-heap: clear the previously set-watch-heap.\n" +
+                "\n" +
                 "am bug-report: request bug report generation; will launch UI\n" +
                 "    when done to select where it should be delivered.\n" +
                 "\n" +
@@ -244,13 +253,28 @@
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>" +
+                ".\n" +
+                "\n" +
+                "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" +
+                "   starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" +
+                "   specified and the current stack has more than one task, then the top task\n" +
+                "   of the current task will be moved to the new stack. Command will also force\n" +
+                "   all current tasks in both stacks to be resizeable.\n" +
                 "\n" +
                 "am stack list: list all of the activity stacks and their sizes.\n" +
                 "\n" +
                 "am stack info: display the information about activity stack <STACK_ID>.\n" +
                 "\n" +
-                "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+                "am task lock: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+                "\n" +
+                "am task lock stop: end the current task lock\n" +
+                "\n" +
+                "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
+                "\n" +
+                "am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" +
+                "   Forces the task to be resizeable and creates a stack if no existing stack\n" +
+                "   has the specified bounds.\n" +
                 "\n" +
                 "am get-config: retrieve the configuration and any recent configurations\n" +
                 "  of the device\n" +
@@ -325,6 +349,10 @@
             runSetDebugApp();
         } else if (op.equals("clear-debug-app")) {
             runClearDebugApp();
+        } else if (op.equals("set-watch-heap")) {
+            runSetWatchHeap();
+        } else if (op.equals("clear-watch-heap")) {
+            runClearWatchHeap();
         } else if (op.equals("bug-report")) {
             runBugReport();
         } else if (op.equals("monitor")) {
@@ -351,8 +379,8 @@
             runStopUser();
         } else if (op.equals("stack")) {
             runStack();
-        } else if (op.equals("lock-task")) {
-            runLockTask();
+        } else if (op.equals("task")) {
+            runTask();
         } else if (op.equals("get-config")) {
             runGetConfig();
         } else {
@@ -1155,6 +1183,17 @@
         mAm.setDebugApp(null, false, true);
     }
 
+    private void runSetWatchHeap() throws Exception {
+        String proc = nextArgRequired();
+        String limit = nextArgRequired();
+        mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit));
+    }
+
+    private void runClearWatchHeap() throws Exception {
+        String proc = nextArgRequired();
+        mAm.setDumpHeapDebugLimit(proc, -1);
+    }
+
     private void runBugReport() throws Exception {
         mAm.requestBugReport();
         System.out.println("Your lovely bug report is being created; please be patient.");
@@ -1682,6 +1721,8 @@
             runStackList();
         } else if (op.equals("info")) {
             runStackInfo();
+        } else if (op.equals("split")) {
+            runStackSplit();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
@@ -1694,10 +1735,10 @@
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
 
         try {
-            IBinder homeActivityToken = mAm.getHomeActivityToken();
-            IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null);
-            container.attachToDisplay(displayId);
-            container.startActivity(intent);
+            IActivityContainer container = mAm.createStackOnDisplay(displayId);
+            if (container != null) {
+                container.startActivity(intent);
+            }
         } catch (RemoteException e) {
         }
     }
@@ -1727,17 +1768,14 @@
     private void runStackResize() throws Exception {
         String stackIdStr = nextArgRequired();
         int stackId = Integer.valueOf(stackIdStr);
-        String leftStr = nextArgRequired();
-        int left = Integer.valueOf(leftStr);
-        String topStr = nextArgRequired();
-        int top = Integer.valueOf(topStr);
-        String rightStr = nextArgRequired();
-        int right = Integer.valueOf(rightStr);
-        String bottomStr = nextArgRequired();
-        int bottom = Integer.valueOf(bottomStr);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
 
         try {
-            mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
+            mAm.resizeStack(stackId, bounds);
         } catch (RemoteException e) {
         }
     }
@@ -1762,7 +1800,79 @@
         }
     }
 
-    private void runLockTask() throws Exception {
+    private void runStackSplit() throws Exception {
+        final int stackId = Integer.valueOf(nextArgRequired());
+        final String splitDirection = nextArgRequired();
+        Intent intent = null;
+        try {
+            intent = makeIntent(UserHandle.USER_CURRENT);
+        } catch (IllegalArgumentException e) {
+            // no intent supplied.
+        }
+
+        try {
+            final StackInfo currentStackInfo = mAm.getStackInfo(stackId);
+            // Calculate bounds for new and current stack.
+            final Rect currentStackBounds = new Rect(currentStackInfo.bounds);
+            final Rect newStackBounds = new Rect(currentStackInfo.bounds);
+            if ("v".equals(splitDirection)) {
+                currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX();
+            } else if ("h".equals(splitDirection)) {
+                currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY();
+            } else {
+                showError("Error: unknown split direction '" + splitDirection + "'");
+                return;
+            }
+
+            // Create new stack
+            IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId);
+            if (container == null) {
+                showError("Error: Unable to create new stack...");
+            }
+
+            final int newStackId = container.getStackId();
+
+            if (intent != null) {
+                container.startActivity(intent);
+            } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) {
+                // Move top task over to new stack
+                mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1],
+                        newStackId, true);
+            }
+
+            final StackInfo newStackInfo = mAm.getStackInfo(newStackId);
+
+            // Make all tasks in the stacks resizeable.
+            for (int taskId : currentStackInfo.taskIds) {
+                mAm.setTaskResizeable(taskId, true);
+            }
+
+            for (int taskId : newStackInfo.taskIds) {
+                mAm.setTaskResizeable(taskId, true);
+            }
+
+            // Resize stacks
+            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds);
+            mAm.resizeStack(newStackInfo.stackId, newStackBounds);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runTask() throws Exception {
+        String op = nextArgRequired();
+        if (op.equals("lock")) {
+            runTaskLock();
+        } else if (op.equals("resizeable")) {
+            runTaskResizeable();
+        } else if (op.equals("resize")) {
+            runTaskResize();
+        } else {
+            showError("Error: unknown command '" + op + "'");
+            return;
+        }
+    }
+
+    private void runTaskLock() throws Exception {
         String taskIdStr = nextArgRequired();
         try {
             if (taskIdStr.equals("stop")) {
@@ -1777,6 +1887,32 @@
         }
     }
 
+    private void runTaskResizeable() throws Exception {
+        final String taskIdStr = nextArgRequired();
+        final int taskId = Integer.valueOf(taskIdStr);
+        final String resizeableStr = nextArgRequired();
+        final boolean resizeable = Boolean.valueOf(resizeableStr);
+
+        try {
+            mAm.setTaskResizeable(taskId, resizeable);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runTaskResize() throws Exception {
+        final String taskIdStr = nextArgRequired();
+        final int taskId = Integer.valueOf(taskIdStr);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        try {
+            mAm.resizeTask(taskId, bounds);
+        } catch (RemoteException e) {
+        }
+    }
+
     private List<Configuration> getRecentConfigurations(int days) {
         IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
                     Context.USAGE_STATS_SERVICE));
@@ -1873,4 +2009,32 @@
         }
         return fd;
     }
+
+    private Rect getBounds() {
+        String leftStr = nextArgRequired();
+        int left = Integer.valueOf(leftStr);
+        String topStr = nextArgRequired();
+        int top = Integer.valueOf(topStr);
+        String rightStr = nextArgRequired();
+        int right = Integer.valueOf(rightStr);
+        String bottomStr = nextArgRequired();
+        int bottom = Integer.valueOf(bottomStr);
+        if (left < 0) {
+            System.err.println("Error: bad left arg: " + leftStr);
+            return null;
+        }
+        if (top < 0) {
+            System.err.println("Error: bad top arg: " + topStr);
+            return null;
+        }
+        if (right <= 0) {
+            System.err.println("Error: bad right arg: " + rightStr);
+            return null;
+        }
+        if (bottom <= 0) {
+            System.err.println("Error: bad bottom arg: " + bottomStr);
+            return null;
+        }
+        return new Rect(left, top, right, bottom);
+    }
 }
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 397a7d1..dd5e0ea 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -3,17 +3,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	app_main.cpp
+    app_main.cpp
 
 LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
 
 LOCAL_SHARED_LIBRARIES := \
-	libdl \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-	libandroid_runtime
+    libdl \
+    libcutils \
+    libutils \
+    liblog \
+    libbinder \
+    libandroid_runtime
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
 
@@ -21,6 +21,9 @@
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := app_process32
 LOCAL_MODULE_STEM_64 := app_process64
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
 
 # Create a symlink from app_process to app_process32 or 64
@@ -34,14 +37,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	app_main.cpp
+    app_main.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	liblog \
-	libbinder \
-	libandroid_runtime
+    libcutils \
+    libutils \
+    liblog \
+    libbinder \
+    libandroid_runtime
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
 
@@ -54,6 +57,8 @@
 LOCAL_MODULE_STEM := app_process
 LOCAL_ADDRESS_SANITIZER := true
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
 
 endif # ifeq($(TARGET_ARCH),arm)
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 1bb28c3..c86fd53 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -24,7 +24,7 @@
 
 namespace android {
 
-void app_usage()
+static void app_usage()
 {
     fprintf(stderr,
         "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
@@ -146,8 +146,10 @@
     static const char kInstructionSet[] = "arm";
 #elif defined(__i386__)
     static const char kInstructionSet[] = "x86";
-#elif defined (__mips__)
+#elif defined (__mips__) && !defined(__LP64__)
     static const char kInstructionSet[] = "mips";
+#elif defined (__mips__) && defined(__LP64__)
+    static const char kInstructionSet[] = "mips64";
 #else
 #error "Unknown instruction set"
 #endif
diff --git a/cmds/backup/Android.mk b/cmds/backup/Android.mk
index 42e5133..8e1508c 100644
--- a/cmds/backup/Android.mk
+++ b/cmds/backup/Android.mk
@@ -12,4 +12,6 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index ea1888b..8d9b528 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -25,8 +25,7 @@
 
 #include <unistd.h>
 
-int
-usage(int argc, const char** argv)
+static int usage(int /* argc */, const char** argv)
 {
     const char* p = argv[0];
 
@@ -44,15 +43,13 @@
     return 1;
 }
 
-int
-perform_full_backup()
+static int perform_full_backup()
 {
     printf("this would have written all of your data to stdout\n");
     return 0;
 }
 
-int
-perform_list(const char* filename)
+static int perform_list(const char* filename)
 {
     int err;
     int fd;
@@ -78,7 +75,7 @@
                 size_t dataSize;
                 err = reader.ReadEntityHeader(&key, &dataSize);
                 if (err == 0) {
-                    printf("   entity: %s (%d bytes)\n", key.string(), dataSize);
+                    printf("   entity: %s (%zu bytes)\n", key.string(), dataSize);
                 } else {
                     printf("   Error reading entity header\n");
                 }
@@ -95,14 +92,13 @@
     return 0;
 }
 
-int perform_print(const char* entityname, const char* filename)
+static int perform_print(const char* entityname, const char* filename)
 {
     printf("perform_print(%s, %s);", entityname, filename);
     return 0;
 }
 
-int
-main(int argc, const char** argv)
+int main(int argc, const char** argv)
 {
     if (argc <= 1) {
         return perform_full_backup();
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index d6ecbe3..2ee586f 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -2,22 +2,24 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	bootanimation_main.cpp \
-	AudioPlayer.cpp \
-	BootAnimation.cpp
+    bootanimation_main.cpp \
+    AudioPlayer.cpp \
+    BootAnimation.cpp
 
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 LOCAL_C_INCLUDES += external/tinyalsa/include
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	liblog \
-	libandroidfw \
-	libutils \
-	libbinder \
+    libcutils \
+    liblog \
+    libandroidfw \
+    libutils \
+    libbinder \
     libui \
-	libskia \
+    libskia \
     libEGL \
     libGLESv1_CM \
     libgui \
diff --git a/cmds/bootanimation/AudioPlayer.cpp b/cmds/bootanimation/AudioPlayer.cpp
index 471b77f..2932130 100644
--- a/cmds/bootanimation/AudioPlayer.cpp
+++ b/cmds/bootanimation/AudioPlayer.cpp
@@ -98,16 +98,16 @@
                         ALOGE("mixer_ctl_set_value failed for %s %d", name, intValue);
                     }
                 } else {
-                    ALOGE("Could not parse %s as int for %d", intValue, name);
+                    ALOGE("Could not parse %s as int for %s", values, name);
                 }
                 break;
             case MIXER_CTL_TYPE_ENUM:
                 if (sscanf(values, "%s", stringValue) == 1) {
                     if (mixer_ctl_set_enum_by_string(ctl, stringValue) != 0) {
-                        ALOGE("mixer_ctl_set_enum_by_string failed for %s %%s", name, stringValue);
+                        ALOGE("mixer_ctl_set_enum_by_string failed for %s %s", name, stringValue);
                     }
                 } else {
-                    ALOGE("Could not parse %s as enum for %d", stringValue, name);
+                    ALOGE("Could not parse %s as enum for %s", values, name);
                 }
                 break;
             default:
@@ -193,7 +193,7 @@
     return false;
 }
 
-void AudioPlayer::playFile(struct FileMap* fileMap) {
+void AudioPlayer::playFile(FileMap* fileMap) {
     // stop any currently playing sound
     requestExitAndWait();
 
@@ -207,7 +207,6 @@
     struct pcm *pcm = NULL;
     bool moreChunks = true;
     const struct chunk_fmt* chunkFmt = NULL;
-    void* buffer = NULL;
     int bufferSize;
     const uint8_t* wavData;
     size_t wavLength;
@@ -306,7 +305,7 @@
 exit:
     if (pcm)
         pcm_close(pcm);
-    mCurrentFile->release();
+    delete mCurrentFile;
     mCurrentFile = NULL;
     return false;
 }
diff --git a/cmds/bootanimation/AudioPlayer.h b/cmds/bootanimation/AudioPlayer.h
index 7e82a07..1def0ae 100644
--- a/cmds/bootanimation/AudioPlayer.h
+++ b/cmds/bootanimation/AudioPlayer.h
@@ -18,6 +18,7 @@
 #define _BOOTANIMATION_AUDIOPLAYER_H
 
 #include <utils/Thread.h>
+#include <utils/FileMap.h>
 
 namespace android {
 
@@ -28,7 +29,7 @@
     virtual     ~AudioPlayer();
     bool        init(const char* config);
 
-    void        playFile(struct FileMap* fileMap);
+    void        playFile(FileMap* fileMap);
 
 private:
     virtual bool        threadLoop();
@@ -39,7 +40,7 @@
     int                 mPeriodSize;
     int                 mPeriodCount;
 
-    struct FileMap*     mCurrentFile;
+    FileMap*            mCurrentFile;
 };
 
 } // namespace android
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index b2474f2..bb25ec6 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 #include <utils/misc.h>
 #include <signal.h>
+#include <time.h>
 
 #include <cutils/properties.h>
 
@@ -41,9 +42,13 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
+// TODO: Fix Skia.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
 #include <SkStream.h>
 #include <SkImageDecoder.h>
+#pragma GCC diagnostic pop
 
 #include <GLES/gl.h>
 #include <GLES/glext.h>
@@ -57,10 +62,6 @@
 #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
 #define EXIT_PROP_NAME "service.bootanim.exit"
 
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
-                           const struct timespec *request,
-                           struct timespec *remain);
-
 namespace android {
 
 static const int ANIM_ENTRY_NAME_MAX = 256;
@@ -108,7 +109,7 @@
 status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
         const char* name) {
     Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
-    if (!asset)
+    if (asset == NULL)
         return NO_INIT;
     SkBitmap bitmap;
     SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
@@ -167,7 +168,7 @@
     SkBitmap bitmap;
     SkMemoryStream  stream(frame.map->getDataPtr(), frame.map->getDataLength());
     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
-    if (codec) {
+    if (codec != NULL) {
         codec->setDitherImage(false);
         codec->decode(&stream, &bitmap,
                 kN32_SkColorType,
@@ -178,7 +179,7 @@
     // FileMap memory is never released until application exit.
     // Release it now as the texture is already loaded and the memory used for
     // the packed resource can be released.
-    frame.map->release();
+    delete frame.map;
 
     // ensure we can call getPixels(). No need to call unlock, since the
     // bitmap will go out of scope when we return from this method.
@@ -255,7 +256,7 @@
             EGL_DEPTH_SIZE, 0,
             EGL_NONE
     };
-    EGLint w, h, dummy;
+    EGLint w, h;
     EGLint numConfigs;
     EGLConfig config;
     EGLSurface surface;
@@ -445,7 +446,7 @@
     }
 
     outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
-    entryMap->release();
+    delete entryMap;
     return true;
 }
 
@@ -473,7 +474,7 @@
     // Parse the description file
     for (;;) {
         const char* endl = strstr(s, "\n");
-        if (!endl) break;
+        if (endl == NULL) break;
         String8 line(s, endl - s);
         const char* l = line.string();
         int fps, width, height, count, pause;
@@ -575,7 +576,6 @@
 
     const int xc = (mWidth - animation.width) / 2;
     const int yc = ((mHeight - animation.height) / 2);
-    nsecs_t lastFrame = systemTime();
     nsecs_t frameDuration = s2ns(1) / animation.fps;
 
     Region clearReg(Rect(mWidth, mHeight));
@@ -623,9 +623,9 @@
                     Region::const_iterator tail(clearReg.end());
                     glEnable(GL_SCISSOR_TEST);
                     while (head != tail) {
-                        const Rect& r(*head++);
-                        glScissor(r.left, mHeight - r.bottom,
-                                r.width(), r.height());
+                        const Rect& r2(*head++);
+                        glScissor(r2.left, mHeight - r2.bottom,
+                                r2.width(), r2.height());
                         glClear(GL_COLOR_BUFFER_BIT);
                     }
                     glDisable(GL_SCISSOR_TEST);
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 417e138..48a34e7 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -16,31 +16,23 @@
 
 #define LOG_TAG "BootAnimation"
 
-#include <cutils/properties.h>
-
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-
+#include <cutils/properties.h>
+#include <sys/resource.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
 
-#if defined(HAVE_PTHREADS)
-# include <pthread.h>
-# include <sys/resource.h>
-#endif
-
 #include "BootAnimation.h"
 
 using namespace android;
 
 // ---------------------------------------------------------------------------
 
-int main(int argc, char** argv)
+int main()
 {
-#if defined(HAVE_PTHREADS)
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
-#endif
 
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.nobootanimation", value, "0");
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index bd34a9c..c0ed893 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
 
@@ -426,6 +427,22 @@
             }
         }
 
+        public static String resolveCallingPackage() {
+            switch (Process.myUid()) {
+                case Process.ROOT_UID: {
+                    return "root";
+                }
+
+                case Process.SHELL_UID: {
+                    return "com.android.shell";
+                }
+
+                default: {
+                    return null;
+                }
+            }
+        }
+
         protected abstract void onExecute(IContentProvider provider) throws Exception;
     }
 
@@ -439,7 +456,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.insert(null, mUri, mContentValues);
+            provider.insert(resolveCallingPackage(), mUri, mContentValues);
         }
     }
 
@@ -453,7 +470,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.delete(null, mUri, mWhere, null);
+            provider.delete(resolveCallingPackage(), mUri, mWhere, null);
         }
     }
 
@@ -532,7 +549,8 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            Cursor cursor = provider.query(null, mUri, mProjection, mWhere, null, mSortOrder, null);
+            Cursor cursor = provider.query(resolveCallingPackage(), mUri, mProjection, mWhere,
+                    null, mSortOrder, null);
             if (cursor == null) {
                 System.out.println("No result found.");
                 return;
@@ -594,7 +612,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.update(null, mUri, mContentValues, mWhere, null);
+            provider.update(resolveCallingPackage(), mUri, mContentValues, mWhere, null);
         }
     }
 
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 781fb96..3d86ac1 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -52,7 +52,7 @@
                 "usage: dpm [subcommand] [options]\n" +
                 "usage: dpm set-active-admin [ --user <USER_ID> ] <COMPONENT>\n" +
                 "usage: dpm set-device-owner <COMPONENT>\n" +
-                "usage: dpm set-profile-owner <COMPONENT> <USER_ID>\n" +
+                "usage: dpm set-profile-owner [ --user <USER_ID> ] <COMPONENT>\n" +
                 "\n" +
                 "dpm set-active-admin: Sets the given component as active admin" +
                 " for an existing user.\n" +
@@ -125,23 +125,21 @@
     }
 
     private void runSetProfileOwner() throws RemoteException {
-        // To be refactored later to use parseArgs(boolean). Currently in use by existing tests.
-        ComponentName component = parseComponentName(nextArgRequired());
-        int userId = parseInt(nextArgRequired());
-        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, userId);
+        parseArgs(true);
+        mDevicePolicyManager.setActiveAdmin(mComponent, true /*refreshing*/, mUserId);
 
         try {
-            if (!mDevicePolicyManager.setProfileOwner(component, "" /*ownerName*/, userId)) {
-                throw new RuntimeException("Can't set component " + component.toShortString() +
-                        " as profile owner for user " + userId);
+            if (!mDevicePolicyManager.setProfileOwner(mComponent, "" /*ownerName*/, mUserId)) {
+                throw new RuntimeException("Can't set component " + mComponent.toShortString() +
+                        " as profile owner for user " + mUserId);
             }
         } catch (Exception e) {
             // Need to remove the admin that we just added.
-            mDevicePolicyManager.removeActiveAdmin(component, userId);
+            mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId);
             throw e;
         }
         System.out.println("Success: Active admin and profile owner set to "
-                + component.toShortString() + " for user " + userId);
+                + mComponent.toShortString() + " for user " + mUserId);
     }
 
     private ComponentName parseComponentName(String component) {
diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk
index ffa83f2..50ccb07 100644
--- a/cmds/idmap/Android.mk
+++ b/cmds/idmap/Android.mk
@@ -25,4 +25,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index 593a197..16532b8 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -7,6 +7,7 @@
 #include <utils/String8.h>
 
 #include <fcntl.h>
+#include <sys/file.h>
 #include <sys/stat.h>
 
 using namespace android;
@@ -22,7 +23,7 @@
         if (entry == NULL) {
             return -1;
         }
-        if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)crc)) {
+        if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, reinterpret_cast<long*>(crc))) {
             return -1;
         }
         zip->releaseEntry(entry);
@@ -66,7 +67,7 @@
                 fprintf(stderr, "error: write: %s\n", strerror(errno));
                 return -1;
             }
-            bytesLeft -= w;
+            bytesLeft -= static_cast<size_t>(w);
         }
         return 0;
     }
@@ -78,13 +79,13 @@
         if (fstat(idmap_fd, &st) == -1) {
             return true;
         }
-        if (st.st_size < N) {
+        if (st.st_size < static_cast<off_t>(N)) {
             // file is empty or corrupt
             return true;
         }
 
         char buf[N];
-        ssize_t bytesLeft = N;
+        size_t bytesLeft = N;
         if (lseek(idmap_fd, SEEK_SET, 0) < 0) {
             return true;
         }
@@ -93,7 +94,7 @@
             if (r < 0) {
                 return true;
             }
-            bytesLeft -= r;
+            bytesLeft -= static_cast<size_t>(r);
             if (bytesLeft == 0) {
                 break;
             }
diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp
index b9ac8a5..f6afc85 100644
--- a/cmds/idmap/inspect.cpp
+++ b/cmds/idmap/inspect.cpp
@@ -152,13 +152,13 @@
             printe("failed to get resource name id=0x%08x\n", res_id);
             return UNKNOWN_ERROR;
         }
-        if (package) {
+        if (package != NULL) {
             *package = String8(String16(data.package, data.packageLen));
         }
-        if (type) {
+        if (type != NULL) {
             *type = String8(String16(data.type, data.typeLen));
         }
-        if (name) {
+        if (name != NULL) {
             *name = String8(String16(data.name, data.nameLen));
         }
         return NO_ERROR;
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 1153f38..197e36b 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -64,30 +64,6 @@
         return String8(tmp);
     }
 
-    int mkdir_p(const String8& path, uid_t uid, gid_t gid)
-    {
-        static const mode_t mode =
-            S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH;
-        struct stat st;
-
-        if (stat(path.string(), &st) == 0) {
-            return 0;
-        }
-        if (mkdir_p(path.getPathDir(), uid, gid) < 0) {
-            return -1;
-        }
-        if (mkdir(path.string(), 0755) != 0) {
-            return -1;
-        }
-        if (chown(path.string(), uid, gid) == -1) {
-            return -1;
-        }
-        if (chmod(path.string(), mode) == -1) {
-            return -1;
-        }
-        return 0;
-    }
-
     int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
     {
         const size_t N = parser.getAttributeCount();
@@ -97,8 +73,8 @@
             size_t len;
             String16 key(parser.getAttributeName(i, &len));
             if (key == String16("targetPackage")) {
-                const uint16_t *p = parser.getAttributeStringValue(i, &len);
-                if (p) {
+                const char16_t *p = parser.getAttributeStringValue(i, &len);
+                if (p != NULL) {
                     target = String16(p, len);
                 }
             } else if (key == String16("priority")) {
@@ -164,27 +140,27 @@
             return -1;
         }
         FileMap *dataMap = zip->createEntryFileMap(entry);
-        if (!dataMap) {
+        if (dataMap == NULL) {
             ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
             return -1;
         }
         char *buf = new char[uncompLen];
         if (NULL == buf) {
-            ALOGW("%s: failed to allocate %d byte\n", __FUNCTION__, uncompLen);
-            dataMap->release();
+            ALOGW("%s: failed to allocate %zd byte\n", __FUNCTION__, uncompLen);
+            delete dataMap;
             return -1;
         }
         StreamingZipInflater inflater(dataMap, uncompLen);
         if (inflater.read(buf, uncompLen) < 0) {
-            ALOGW("%s: failed to inflate %d byte\n", __FUNCTION__, uncompLen);
+            ALOGW("%s: failed to inflate %zd byte\n", __FUNCTION__, uncompLen);
             delete[] buf;
-            dataMap->release();
+            delete dataMap;
             return -1;
         }
 
         int priority = parse_manifest(buf, uncompLen, target_package_name);
         delete[] buf;
-        dataMap->release();
+        delete dataMap;
         return priority;
     }
 }
diff --git a/cmds/input/input b/cmds/input/input
index fa9dced..7f1a18e 100755
--- a/cmds/input/input
+++ b/cmds/input/input
@@ -3,5 +3,5 @@
 #
 base=/system
 export CLASSPATH=$base/framework/input.jar
-exec app_process $base/bin com.android.commands.input.Input $*
+exec app_process $base/bin com.android.commands.input.Input "$@"
 
diff --git a/cmds/interrupter/Android.mk b/cmds/interrupter/Android.mk
index e324627..97a96bf 100644
--- a/cmds/interrupter/Android.mk
+++ b/cmds/interrupter/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_MODULE := interrupter
 LOCAL_MODULE_TAGS := eng tests
 LOCAL_LDFLAGS := -ldl
+LOCAL_CFLAGS := -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -17,5 +18,6 @@
 LOCAL_MODULE := interrupter
 LOCAL_MODULE_TAGS := eng tests
 LOCAL_LDFLAGS := -ldl
+LOCAL_CFLAGS := -Wall -Werror -Wunused -Wunreachable-code
 
-include $(BUILD_HOST_SHARED_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 6a8fb05..d7f23cb 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -24,7 +24,6 @@
 import android.media.session.ISessionController;
 import android.media.session.ISessionControllerCallback;
 import android.media.session.ISessionManager;
-import android.media.session.MediaController;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 0a573ca..c48a618 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -48,7 +48,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IUserManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -549,7 +548,10 @@
         if (res != 0) {
             Resources r = getResources(pii);
             if (r != null) {
-                return r.getString(res);
+                try {
+                    return r.getString(res);
+                } catch (Resources.NotFoundException e) {
+                }
             }
         }
         return null;
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
index 5c11b75..b0dc422 100644
--- a/cmds/screencap/Android.mk
+++ b/cmds/screencap/Android.mk
@@ -2,13 +2,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	screencap.cpp
+    screencap.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-	libbinder \
-	libskia \
+    libcutils \
+    libutils \
+    libbinder \
+    libskia \
     libui \
     libgui
 
@@ -16,4 +16,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 6b2a0e2..dbc35af 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -18,6 +18,8 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <linux/fb.h>
 #include <sys/ioctl.h>
@@ -30,10 +32,12 @@
 
 #include <ui/PixelFormat.h>
 
+// TODO: Fix Skia.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkImageEncoder.h>
-#include <SkBitmap.h>
 #include <SkData.h>
-#include <SkStream.h>
+#pragma GCC diagnostic pop
 
 using namespace android;
 
@@ -86,6 +90,21 @@
     return NO_ERROR;
 }
 
+static status_t notifyMediaScanner(const char* fileName) {
+    String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
+    String8 fileUrl("\"");
+    fileUrl.append(fileName);
+    fileUrl.append("\"");
+    cmd.append(fileName);
+    cmd.append(" > /dev/null");
+    int result = system(cmd.string());
+    if (result < 0) {
+        fprintf(stderr, "Unable to broadcast intent for media scanner.\n");
+        return UNKNOWN_ERROR;
+    }
+    return NO_ERROR;
+}
+
 int main(int argc, char** argv)
 {
     ProcessState::self()->startThreadPool();
@@ -112,10 +131,11 @@
     argv += optind;
 
     int fd = -1;
+    const char* fn = NULL;
     if (argc == 0) {
         fd = dup(STDOUT_FILENO);
     } else if (argc == 1) {
-        const char* fn = argv[0];
+        fn = argv[0];
         fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
         if (fd == -1) {
             fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
@@ -135,7 +155,7 @@
     void const* mapbase = MAP_FAILED;
     ssize_t mapsize = -1;
 
-    void const* base = 0;
+    void const* base = NULL;
     uint32_t w, s, h, f;
     size_t size = 0;
 
@@ -172,18 +192,18 @@
         }
     }
 
-    if (base) {
+    if (base != NULL) {
         if (png) {
             const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
                                                        kPremul_SkAlphaType);
-            SkBitmap b;
-            b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f));
-            SkDynamicMemoryWStream stream;
-            SkImageEncoder::EncodeStream(&stream, b,
-                    SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
-            SkData* streamData = stream.copyToData();
-            write(fd, streamData->data(), streamData->size());
-            streamData->unref();
+            SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f),
+                    SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality));
+            if (data.get()) {
+                write(fd, data->data(), data->size());
+            }
+            if (fn != NULL) {
+                notifyMediaScanner(fn);
+            }
         } else {
             write(fd, &w, 4);
             write(fd, &h, 4);
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index e6847a9..c27d0c0 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,22 +20,28 @@
 import android.app.IActivityManager;
 import android.app.IActivityManager.ContentProviderHolder;
 import android.content.IContentProvider;
+import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 public final class SettingsCmd {
-    static final String TAG = "settings";
 
     enum CommandVerb {
         UNSPECIFIED,
         GET,
         PUT,
-        DELETE
+        DELETE,
+        LIST,
     }
 
     static String[] mArgs;
@@ -47,7 +53,7 @@
     String mValue = null;
 
     public static void main(String[] args) {
-        if (args == null || args.length < 3) {
+        if (args == null || args.length < 2) {
             printUsage();
             return;
         }
@@ -78,6 +84,8 @@
                         mVerb = CommandVerb.PUT;
                     } else if ("delete".equalsIgnoreCase(arg)) {
                         mVerb = CommandVerb.DELETE;
+                    } else if ("list".equalsIgnoreCase(arg)) {
+                        mVerb = CommandVerb.LIST;
                     } else {
                         // invalid
                         System.err.println("Invalid command: " + arg);
@@ -91,6 +99,10 @@
                         break;  // invalid
                     }
                     mTable = arg.toLowerCase();
+                    if (mVerb == CommandVerb.LIST) {
+                        valid = true;
+                        break;
+                    }
                 } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
                     mKey = arg;
                     if (mNextArg >= mArgs.length) {
@@ -144,6 +156,11 @@
                             System.out.println("Deleted "
                                     + deleteForUser(provider, mUser, mTable, mKey) + " rows");
                             break;
+                        case LIST:
+                            for (String line : listForUser(provider, mUser, mTable)) {
+                                System.out.println(line);
+                            }
+                            break;
                         default:
                             System.err.println("Unspecified command");
                             break;
@@ -164,6 +181,34 @@
         }
     }
 
+    private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
+        final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
+                : "secure".equals(table) ? Settings.Secure.CONTENT_URI
+                : "global".equals(table) ? Settings.Global.CONTENT_URI
+                : null;
+        final ArrayList<String> lines = new ArrayList<String>();
+        if (uri == null) {
+            return lines;
+        }
+        try {
+            final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null, null,
+                    null, null);
+            try {
+                while (cursor != null && cursor.moveToNext()) {
+                    lines.add(cursor.getString(1) + "=" + cursor.getString(2));
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            Collections.sort(lines);
+        } catch (RemoteException e) {
+            System.err.println("List failed in " + table + " for user " + userHandle);
+        }
+        return lines;
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -188,7 +233,7 @@
         try {
             Bundle arg = new Bundle();
             arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-            Bundle b = provider.call(null, callGetCommand, key, arg);
+            Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg);
             if (b != null) {
                 result = b.getPairValue();
             }
@@ -213,7 +258,7 @@
             Bundle arg = new Bundle();
             arg.putString(Settings.NameValueTable.VALUE, value);
             arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-            provider.call(null, callPutCommand, key, arg);
+            provider.call(resolveCallingPackage(), callPutCommand, key, arg);
         } catch (RemoteException e) {
             System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
         }
@@ -232,7 +277,7 @@
 
         int num = 0;
         try {
-            num = provider.delete(null, targetUri, null, null);
+            num = provider.delete(resolveCallingPackage(), targetUri, null, null);
         } catch (RemoteException e) {
             System.err.println("Can't clear key " + key + " in " + table + " for user "
                     + userHandle);
@@ -244,7 +289,24 @@
         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("        settings [--user NUM] list namespace");
         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.");
     }
+
+    public static String resolveCallingPackage() {
+        switch (android.os.Process.myUid()) {
+            case Process.ROOT_UID: {
+                return "root";
+            }
+
+            case Process.SHELL_UID: {
+                return "com.android.shell";
+            }
+
+            default: {
+                return null;
+            }
+        }
+    }
 }
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index 406e33b..35510cf 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -18,8 +18,6 @@
 
 import android.os.ServiceManager;
 import android.os.RemoteException;
-import android.net.IConnectivityManager;
-import android.net.ConnectivityManager;
 import android.content.Context;
 import com.android.internal.telephony.ITelephony;
 
diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
index 39f0e35..94214ff 100644
--- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
@@ -19,8 +19,6 @@
 import android.os.ServiceManager;
 import android.os.RemoteException;
 import android.net.wifi.IWifiManager;
-import android.net.IConnectivityManager;
-import android.net.ConnectivityManager;
 import android.content.Context;
 
 public class WifiCommand extends Svc.Command {
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index 7cc0884..2123f25 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -65,6 +65,7 @@
 include $(BUILD_STATIC_JAVA_LIBRARY)
 # Make sure to run droiddoc first to generate the stub source files.
 $(full_classes_compiled_jar) : $(uiautomator_stubs_stamp)
+$(built_dex_intermediate) : $(uiautomator_stubs_stamp)
 uiautomator_stubs_jar := $(full_classes_compiled_jar)
 
 ###############################################
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3f1845a..9d6aa13 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -27,7 +27,6 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
deleted file mode 100644
index 8b44881..0000000
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ /dev/null
@@ -1,116 +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.alsa;
-
-import android.util.Slog;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Vector;
-
-/**
- * @hide Retrieves information from an ALSA "cards" file.
- */
-public class AlsaCardsParser {
-    private static final String TAG = "AlsaCardsParser";
-
-    private static LineTokenizer tokenizer_ = new LineTokenizer(" :[]");
-
-    public class AlsaCardRecord {
-        public int mCardNum = -1;
-        public String mField1 = "";
-        public String mCardName = "";
-        public String mCardDescription = "";
-
-        public AlsaCardRecord() {}
-
-        public boolean parse(String line, int lineIndex) {
-            int tokenIndex = 0;
-            int delimIndex = 0;
-            if (lineIndex == 0) {
-                // line # (skip)
-                tokenIndex = tokenizer_.nextToken(line, tokenIndex);
-                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
-
-                // mField1
-                tokenIndex = tokenizer_.nextToken(line, delimIndex);
-                delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
-                mField1 = line.substring(tokenIndex, delimIndex);
-
-                // mCardName
-                tokenIndex = tokenizer_.nextToken(line, delimIndex);
-                // delimIndex = tokenizer_.nextDelimiter(line, tokenIndex);
-                mCardName = line.substring(tokenIndex);
-                // done
-              } else if (lineIndex == 1) {
-                  tokenIndex = tokenizer_.nextToken(line, 0);
-                  if (tokenIndex != -1) {
-                      mCardDescription = line.substring(tokenIndex);
-                  }
-            }
-
-            return true;
-        }
-
-        public String textFormat() {
-          return mCardName + " : " + mCardDescription;
-        }
-    }
-
-    private Vector<AlsaCardRecord> cardRecords_ = new Vector<AlsaCardRecord>();
-
-    public void scan() {
-          cardRecords_.clear();
-          final String cardsFilePath = "/proc/asound/cards";
-          File cardsFile = new File(cardsFilePath);
-          try {
-              FileReader reader = new FileReader(cardsFile);
-              BufferedReader bufferedReader = new BufferedReader(reader);
-              String line = "";
-              while ((line = bufferedReader.readLine()) != null) {
-                  AlsaCardRecord cardRecord = new AlsaCardRecord();
-                  cardRecord.parse(line, 0);
-                  cardRecord.parse(line = bufferedReader.readLine(), 1);
-                  cardRecords_.add(cardRecord);
-              }
-              reader.close();
-          } catch (FileNotFoundException e) {
-              e.printStackTrace();
-          } catch (IOException e) {
-              e.printStackTrace();
-          }
-      }
-
-      public AlsaCardRecord getCardRecordAt(int index) {
-          return cardRecords_.get(index);
-      }
-
-      public int getNumCardRecords() {
-          return cardRecords_.size();
-      }
-
-    public void Log() {
-      int numCardRecs = getNumCardRecords();
-      for (int index = 0; index < numCardRecs; ++index) {
-          Slog.w(TAG, "usb:" + getCardRecordAt(index).textFormat());
-      }
-    }
-
-    public AlsaCardsParser() {}
-}
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
deleted file mode 100644
index 82cc1ae..0000000
--- a/core/java/android/alsa/AlsaDevicesParser.java
+++ /dev/null
@@ -1,275 +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.alsa;
-
-import android.util.Slog;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Vector;
-
-/**
- * @hide
- * Retrieves information from an ALSA "devices" file.
- */
-public class AlsaDevicesParser {
-    private static final String TAG = "AlsaDevicesParser";
-
-    private static final int kIndex_CardDeviceField = 5;
-    private static final int kStartIndex_CardNum = 6;
-    private static final int kEndIndex_CardNum = 8; // one past
-    private static final int kStartIndex_DeviceNum = 9;
-    private static final int kEndIndex_DeviceNum = 11; // one past
-    private static final int kStartIndex_Type = 14;
-
-    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
-
-    private boolean mHasCaptureDevices = false;
-    private boolean mHasPlaybackDevices = false;
-    private boolean mHasMIDIDevices = false;
-
-    public class AlsaDeviceRecord {
-        public static final int kDeviceType_Unknown = -1;
-        public static final int kDeviceType_Audio = 0;
-        public static final int kDeviceType_Control = 1;
-        public static final int kDeviceType_MIDI = 2;
-
-        public static final int kDeviceDir_Unknown = -1;
-        public static final int kDeviceDir_Capture = 0;
-        public static final int kDeviceDir_Playback = 1;
-
-        int mCardNum = -1;
-        int mDeviceNum = -1;
-        int mDeviceType = kDeviceType_Unknown;
-        int mDeviceDir = kDeviceDir_Unknown;
-
-        public AlsaDeviceRecord() {
-        }
-
-        public boolean parse(String line) {
-            // "0123456789012345678901234567890"
-            // "  2: [ 0-31]: digital audio playback"
-            // "  3: [ 0-30]: digital audio capture"
-            // " 35: [ 1]   : control"
-            // " 36: [ 2- 0]: raw midi"
-
-            final int kToken_LineNum = 0;
-            final int kToken_CardNum = 1;
-            final int kToken_DeviceNum = 2;
-            final int kToken_Type0 = 3; // "digital", "control", "raw"
-            final int kToken_Type1 = 4; // "audio", "midi"
-            final int kToken_Type2 = 5; // "capture", "playback"
-
-            int tokenOffset = 0;
-            int delimOffset = 0;
-            int tokenIndex = kToken_LineNum;
-            while (true) {
-                tokenOffset = mTokenizer.nextToken(line, delimOffset);
-                if (tokenOffset == LineTokenizer.kTokenNotFound) {
-                    break; // bail
-                }
-                delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
-                if (delimOffset == LineTokenizer.kTokenNotFound) {
-                    delimOffset = line.length();
-                }
-                String token = line.substring(tokenOffset, delimOffset);
-
-                switch (tokenIndex) {
-                case kToken_LineNum:
-                    // ignore
-                    break;
-
-                case kToken_CardNum:
-                    mCardNum = Integer.parseInt(token);
-                    if (line.charAt(delimOffset) != '-') {
-                        tokenIndex++; // no device # in the token stream
-                    }
-                    break;
-
-                case kToken_DeviceNum:
-                    mDeviceNum = Integer.parseInt(token);
-                    break;
-
-                case kToken_Type0:
-                    if (token.equals("digital")) {
-                        // NOP
-                    } else if (token.equals("control")) {
-                        mDeviceType = kDeviceType_Control;
-                    } else if (token.equals("raw")) {
-                        // NOP
-                    }
-                    break;
-
-                case kToken_Type1:
-                    if (token.equals("audio")) {
-                        mDeviceType = kDeviceType_Audio;
-                    } else if (token.equals("midi")) {
-                        mDeviceType = kDeviceType_MIDI;
-                        mHasMIDIDevices = true;
-                    }
-                    break;
-
-                case kToken_Type2:
-                    if (token.equals("capture")) {
-                        mDeviceDir = kDeviceDir_Capture;
-                        mHasCaptureDevices = true;
-                    } else if (token.equals("playback")) {
-                        mDeviceDir = kDeviceDir_Playback;
-                        mHasPlaybackDevices = true;
-                    }
-                    break;
-                } // switch (tokenIndex)
-
-                tokenIndex++;
-            } // while (true)
-
-            return true;
-        } // parse()
-
-        public String textFormat() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
-
-            switch (mDeviceType) {
-            case kDeviceType_Unknown:
-                sb.append(" N/A");
-                break;
-            case kDeviceType_Audio:
-                sb.append(" Audio");
-                break;
-            case kDeviceType_Control:
-                sb.append(" Control");
-                break;
-            case kDeviceType_MIDI:
-                sb.append(" MIDI");
-                break;
-            }
-
-            switch (mDeviceDir) {
-            case kDeviceDir_Unknown:
-                sb.append(" N/A");
-                break;
-            case kDeviceDir_Capture:
-                sb.append(" Capture");
-                break;
-            case kDeviceDir_Playback:
-                sb.append(" Playback");
-                break;
-            }
-
-            return sb.toString();
-        }
-    }
-
-    private Vector<AlsaDeviceRecord>
-            deviceRecords_ = new Vector<AlsaDeviceRecord>();
-
-    private boolean isLineDeviceRecord(String line) {
-        return line.charAt(kIndex_CardDeviceField) == '[';
-    }
-
-    public AlsaDevicesParser() {
-    }
-
-    public int getNumDeviceRecords() {
-        return deviceRecords_.size();
-    }
-
-    public AlsaDeviceRecord getDeviceRecordAt(int index) {
-        return deviceRecords_.get(index);
-    }
-
-    public void Log() {
-        int numDevRecs = getNumDeviceRecords();
-        for (int index = 0; index < numDevRecs; ++index) {
-            Slog.w(TAG, "usb:" + getDeviceRecordAt(index).textFormat());
-        }
-    }
-
-    public boolean hasPlaybackDevices() {
-        return mHasPlaybackDevices;
-    }
-
-    public boolean hasPlaybackDevices(int card) {
-        for (int index = 0; index < deviceRecords_.size(); index++) {
-            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
-            if (deviceRecord.mCardNum == card &&
-                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
-                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean hasCaptureDevices() {
-        return mHasCaptureDevices;
-    }
-
-    public boolean hasCaptureDevices(int card) {
-        for (int index = 0; index < deviceRecords_.size(); index++) {
-            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
-            if (deviceRecord.mCardNum == card &&
-                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
-                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean hasMIDIDevices() {
-        return mHasMIDIDevices;
-    }
-
-    public boolean hasMIDIDevices(int card) {
-        for (int index = 0; index < deviceRecords_.size(); index++) {
-            AlsaDeviceRecord deviceRecord = deviceRecords_.get(index);
-            if (deviceRecord.mCardNum == card &&
-                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void scan() {
-        deviceRecords_.clear();
-
-        final String devicesFilePath = "/proc/asound/devices";
-        File devicesFile = new File(devicesFilePath);
-        try {
-            FileReader reader = new FileReader(devicesFile);
-            BufferedReader bufferedReader = new BufferedReader(reader);
-            String line = "";
-            while ((line = bufferedReader.readLine()) != null) {
-                if (isLineDeviceRecord(line)) {
-                    AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
-                    deviceRecord.parse(line);
-                    deviceRecords_.add(deviceRecord);
-                }
-            }
-            reader.close();
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-} // class AlsaDevicesParser
-
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
deleted file mode 100644
index 78c91b5..0000000
--- a/core/java/android/alsa/LineTokenizer.java
+++ /dev/null
@@ -1,57 +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.alsa;
-
-/**
- * @hide
- * Breaks lines in an ALSA "cards" or "devices" file into tokens.
- * TODO(pmclean) Look into replacing this with String.split().
- */
-public class LineTokenizer {
-    public static final int kTokenNotFound = -1;
-
-    private String mDelimiters = "";
-
-    public LineTokenizer(String delimiters) {
-        mDelimiters = delimiters;
-    }
-
-    int nextToken(String line, int startIndex) {
-        int len = line.length();
-        int offset = startIndex;
-        for (; offset < len; offset++) {
-            if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
-                // past a delimiter
-                break;
-            }
-      }
-
-      return offset < len ? offset : kTokenNotFound;
-    }
-
-    int nextDelimiter(String line, int startIndex) {
-        int len = line.length();
-        int offset = startIndex;
-        for (; offset < len; offset++) {
-            if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
-                // past a delimiter
-                break;
-            }
-        }
-
-      return offset < len ? offset : kTokenNotFound;
-    }
-}
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 688d7e4..021194c 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -15,6 +15,7 @@
  */
 package android.animation;
 
+import android.annotation.AnimatorRes;
 import android.content.Context;
 import android.content.res.ConfigurationBoundResourceCache;
 import android.content.res.ConstantState;
@@ -66,8 +67,7 @@
     private static final int VALUE_TYPE_FLOAT       = 0;
     private static final int VALUE_TYPE_INT         = 1;
     private static final int VALUE_TYPE_PATH        = 2;
-    private static final int VALUE_TYPE_COLOR       = 4;
-    private static final int VALUE_TYPE_CUSTOM      = 5;
+    private static final int VALUE_TYPE_COLOR       = 3;
 
     private static final boolean DBG_ANIMATOR_INFLATER = false;
 
@@ -82,7 +82,7 @@
      * @return The animator object reference by the specified id
      * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
      */
-    public static Animator loadAnimator(Context context, int id)
+    public static Animator loadAnimator(Context context, @AnimatorRes int id)
             throws NotFoundException {
         return loadAnimator(context.getResources(), context.getTheme(), id);
     }
@@ -296,6 +296,134 @@
         }
     }
 
+    private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType,
+            int valueFromId, int valueToId, String propertyName) {
+
+        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
+
+        TypedValue tvFrom = styledAttributes.peekValue(valueFromId);
+        boolean hasFrom = (tvFrom != null);
+        int fromType = hasFrom ? tvFrom.type : 0;
+        TypedValue tvTo = styledAttributes.peekValue(valueToId);
+        boolean hasTo = (tvTo != null);
+        int toType = hasTo ? tvTo.type : 0;
+
+        PropertyValuesHolder returnValue = null;
+
+        if (valueType == VALUE_TYPE_PATH) {
+            String fromString = styledAttributes.getString(valueFromId);
+            String toString = styledAttributes.getString(valueToId);
+            PathParser.PathDataNode[] nodesFrom = PathParser.createNodesFromPathData(fromString);
+            PathParser.PathDataNode[] nodesTo = PathParser.createNodesFromPathData(toString);
+
+            if (nodesFrom != null || nodesTo != null) {
+                if (nodesFrom != null) {
+                    TypeEvaluator evaluator =
+                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesFrom));
+                    if (nodesTo != null) {
+                        if (!PathParser.canMorph(nodesFrom, nodesTo)) {
+                            throw new InflateException(" Can't morph from " + fromString + " to " +
+                                    toString);
+                        }
+                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
+                                nodesFrom, nodesTo);
+                    } else {
+                        returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
+                                (Object) nodesFrom);
+                    }
+                } else if (nodesTo != null) {
+                    TypeEvaluator evaluator =
+                            new PathDataEvaluator(PathParser.deepCopyNodes(nodesTo));
+                    returnValue = PropertyValuesHolder.ofObject(propertyName, evaluator,
+                            (Object) nodesTo);
+                }
+            }
+        } else {
+            TypeEvaluator evaluator = null;
+            // Integer and float value types are handled here.
+            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
+                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+                // special case for colors: ignore valueType and get ints
+                getFloats = false;
+                evaluator = ArgbEvaluator.getInstance();
+            }
+            if (getFloats) {
+                float valueFrom;
+                float valueTo;
+                if (hasFrom) {
+                    if (fromType == TypedValue.TYPE_DIMENSION) {
+                        valueFrom = styledAttributes.getDimension(valueFromId, 0f);
+                    } else {
+                        valueFrom = styledAttributes.getFloat(valueFromId, 0f);
+                    }
+                    if (hasTo) {
+                        if (toType == TypedValue.TYPE_DIMENSION) {
+                            valueTo = styledAttributes.getDimension(valueToId, 0f);
+                        } else {
+                            valueTo = styledAttributes.getFloat(valueToId, 0f);
+                        }
+                        returnValue = PropertyValuesHolder.ofFloat(propertyName,
+                                valueFrom, valueTo);
+                    } else {
+                        returnValue = PropertyValuesHolder.ofFloat(propertyName, valueFrom);
+                    }
+                } else {
+                    if (toType == TypedValue.TYPE_DIMENSION) {
+                        valueTo = styledAttributes.getDimension(valueToId, 0f);
+                    } else {
+                        valueTo = styledAttributes.getFloat(valueToId, 0f);
+                    }
+                    returnValue = PropertyValuesHolder.ofFloat(propertyName, valueTo);
+                }
+            } else {
+                int valueFrom;
+                int valueTo;
+                if (hasFrom) {
+                    if (fromType == TypedValue.TYPE_DIMENSION) {
+                        valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f);
+                    } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                            (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                        valueFrom = styledAttributes.getColor(valueFromId, 0);
+                    } else {
+                        valueFrom = styledAttributes.getInt(valueFromId, 0);
+                    }
+                    if (hasTo) {
+                        if (toType == TypedValue.TYPE_DIMENSION) {
+                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
+                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                            valueTo = styledAttributes.getColor(valueToId, 0);
+                        } else {
+                            valueTo = styledAttributes.getInt(valueToId, 0);
+                        }
+                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom, valueTo);
+                    } else {
+                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueFrom);
+                    }
+                } else {
+                    if (hasTo) {
+                        if (toType == TypedValue.TYPE_DIMENSION) {
+                            valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
+                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                            valueTo = styledAttributes.getColor(valueToId, 0);
+                        } else {
+                            valueTo = styledAttributes.getInt(valueToId, 0);
+                        }
+                        returnValue = PropertyValuesHolder.ofInt(propertyName, valueTo);
+                    }
+                }
+            }
+            if (returnValue != null && evaluator != null) {
+                returnValue.setEvaluator(evaluator);
+            }
+        }
+
+        return returnValue;
+    }
+
     /**
      * @param anim The animator, must not be null
      * @param arrayAnimator Incoming typed array for Animator's attributes.
@@ -310,35 +438,12 @@
 
         long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
 
-        int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType,
-                VALUE_TYPE_FLOAT);
+        int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_FLOAT);
 
-        TypeEvaluator evaluator = null;
-
-        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
-
-        TypedValue tvFrom = arrayAnimator.peekValue(R.styleable.Animator_valueFrom);
-        boolean hasFrom = (tvFrom != null);
-        int fromType = hasFrom ? tvFrom.type : 0;
-        TypedValue tvTo = arrayAnimator.peekValue(R.styleable.Animator_valueTo);
-        boolean hasTo = (tvTo != null);
-        int toType = hasTo ? tvTo.type : 0;
-
-        // TODO: Further clean up this part of code into 4 types : path, color,
-        // integer and float.
-        if (valueType == VALUE_TYPE_PATH) {
-            evaluator = setupAnimatorForPath(anim, arrayAnimator);
-        } else {
-            // Integer and float value types are handled here.
-            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
-                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
-                // special case for colors: ignore valueType and get ints
-                getFloats = false;
-                evaluator = ArgbEvaluator.getInstance();
-            }
-            setupValues(anim, arrayAnimator, getFloats, hasFrom, fromType, hasTo, toType);
+        PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType,
+                R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, "");
+        if (pvh != null) {
+            anim.setValues(pvh);
         }
 
         anim.setDuration(duration);
@@ -353,12 +458,10 @@
                     arrayAnimator.getInt(R.styleable.Animator_repeatMode,
                             ValueAnimator.RESTART));
         }
-        if (evaluator != null) {
-            anim.setEvaluator(evaluator);
-        }
 
         if (arrayObjectAnimator != null) {
-            setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize);
+            setupObjectAnimator(anim, arrayObjectAnimator, valueType == VALUE_TYPE_FLOAT,
+                    pixelSize);
         }
     }
 
@@ -570,6 +673,7 @@
             }
 
             String name = parser.getName();
+            boolean gotValues = false;
 
             if (name.equals("objectAnimator")) {
                 anim = loadObjectAnimator(res, theme, attrs, pixelSize);
@@ -588,11 +692,18 @@
                 createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
                         pixelSize);
                 a.recycle();
+            } else if (name.equals("propertyValuesHolder")) {
+                PropertyValuesHolder[] values = loadValues(res, theme, parser,
+                        Xml.asAttributeSet(parser));
+                if (values != null && anim != null && (anim instanceof ValueAnimator)) {
+                    ((ValueAnimator) anim).setValues(values);
+                }
+                gotValues = true;
             } else {
                 throw new RuntimeException("Unknown animator name: " + parser.getName());
             }
 
-            if (parent != null) {
+            if (parent != null && !gotValues) {
                 if (childAnims == null) {
                     childAnims = new ArrayList<Animator>();
                 }
@@ -612,7 +723,233 @@
             }
         }
         return anim;
+    }
 
+    private static PropertyValuesHolder[] loadValues(Resources res, Theme theme,
+            XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
+        ArrayList<PropertyValuesHolder> values = null;
+
+        int type;
+        while ((type = parser.getEventType()) != XmlPullParser.END_TAG &&
+                type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                parser.next();
+                continue;
+            }
+
+            String name = parser.getName();
+
+            if (name.equals("propertyValuesHolder")) {
+                TypedArray a;
+                if (theme != null) {
+                    a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyValuesHolder, 0, 0);
+                } else {
+                    a = res.obtainAttributes(attrs, R.styleable.PropertyValuesHolder);
+                }
+                String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName);
+                int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType,
+                        VALUE_TYPE_FLOAT);
+                PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType);
+                if (pvh == null) {
+                    pvh = getPVH(a, valueType,
+                            R.styleable.PropertyValuesHolder_valueFrom,
+                            R.styleable.PropertyValuesHolder_valueTo, propertyName);
+                }
+                if (pvh != null) {
+                    if (values == null) {
+                        values = new ArrayList<PropertyValuesHolder>();
+                    }
+                    values.add(pvh);
+                }
+                a.recycle();
+            }
+
+            parser.next();
+        }
+
+        PropertyValuesHolder[] valuesArray = null;
+        if (values != null) {
+            int count = values.size();
+            valuesArray = new PropertyValuesHolder[count];
+            for (int i = 0; i < count; ++i) {
+                valuesArray[i] = values.get(i);
+            }
+        }
+        return valuesArray;
+    }
+
+    private static void dumpKeyframes(Object[] keyframes, String header) {
+        if (keyframes == null || keyframes.length == 0) {
+            return;
+        }
+        Log.d(TAG, header);
+        int count = keyframes.length;
+        for (int i = 0; i < count; ++i) {
+            Keyframe keyframe = (Keyframe) keyframes[i];
+            Log.d(TAG, "Keyframe " + i + ": fraction " +
+                    (keyframe.getFraction() < 0 ? "null" : keyframe.getFraction()) + ", " +
+                    ", value : " + ((keyframe.hasValue()) ? keyframe.getValue() : "null"));
+        }
+    }
+
+    private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser,
+            String propertyName, int valueType)
+            throws XmlPullParserException, IOException {
+
+        PropertyValuesHolder value = null;
+        ArrayList<Keyframe> keyframes = null;
+
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_TAG &&
+                type != XmlPullParser.END_DOCUMENT) {
+            String name = parser.getName();
+            if (name.equals("keyframe")) {
+                Keyframe keyframe = loadKeyframe(res, theme, Xml.asAttributeSet(parser), valueType);
+                if (keyframe != null) {
+                    if (keyframes == null) {
+                        keyframes = new ArrayList<Keyframe>();
+                    }
+                    keyframes.add(keyframe);
+                }
+                parser.next();
+            }
+        }
+
+        int count;
+        if (keyframes != null && (count = keyframes.size()) > 0) {
+            // make sure we have keyframes at 0 and 1
+            // If we have keyframes with set fractions, add keyframes at start/end
+            // appropriately. If start/end have no set fractions:
+            // if there's only one keyframe, set its fraction to 1 and add one at 0
+            // if >1 keyframe, set the last fraction to 1, the first fraction to 0
+            Keyframe firstKeyframe = keyframes.get(0);
+            Keyframe lastKeyframe = keyframes.get(count - 1);
+            float endFraction = lastKeyframe.getFraction();
+            if (endFraction < 1) {
+                if (endFraction < 0) {
+                    lastKeyframe.setFraction(1);
+                } else {
+                    keyframes.add(keyframes.size(), createNewKeyframe(lastKeyframe, 1));
+                    ++count;
+                }
+            }
+            float startFraction = firstKeyframe.getFraction();
+            if (startFraction != 0) {
+                if (startFraction < 0) {
+                    firstKeyframe.setFraction(0);
+                } else {
+                    keyframes.add(0, createNewKeyframe(firstKeyframe, 0));
+                    ++count;
+                }
+            }
+            Keyframe[] keyframeArray = new Keyframe[count];
+            keyframes.toArray(keyframeArray);
+            for (int i = 0; i < count; ++i) {
+                Keyframe keyframe = keyframeArray[i];
+                if (keyframe.getFraction() < 0) {
+                    if (i == 0) {
+                        keyframe.setFraction(0);
+                    } else if (i == count - 1) {
+                        keyframe.setFraction(1);
+                    } else {
+                        // figure out the start/end parameters of the current gap
+                        // in fractions and distribute the gap among those keyframes
+                        int startIndex = i;
+                        int endIndex = i;
+                        for (int j = startIndex + 1; j < count - 1; ++j) {
+                            if (keyframeArray[j].getFraction() >= 0) {
+                                break;
+                            }
+                            endIndex = j;
+                        }
+                        float gap = keyframeArray[endIndex + 1].getFraction() -
+                                keyframeArray[startIndex - 1].getFraction();
+                        distributeKeyframes(keyframeArray, gap, startIndex, endIndex);
+                    }
+                }
+            }
+            value = PropertyValuesHolder.ofKeyframe(propertyName, keyframeArray);
+            if (valueType == VALUE_TYPE_COLOR) {
+                value.setEvaluator(ArgbEvaluator.getInstance());
+            }
+        }
+
+        return value;
+    }
+
+    private static Keyframe createNewKeyframe(Keyframe sampleKeyframe, float fraction) {
+        return sampleKeyframe.getType() == float.class ?
+                            Keyframe.ofFloat(fraction) :
+                            (sampleKeyframe.getType() == int.class) ?
+                                    Keyframe.ofInt(fraction) :
+                                    Keyframe.ofObject(fraction);
+    }
+
+    /**
+     * Utility function to set fractions on keyframes to cover a gap in which the
+     * fractions are not currently set. Keyframe fractions will be distributed evenly
+     * in this gap. For example, a gap of 1 keyframe in the range 0-1 will be at .5, a gap
+     * of .6 spread between two keyframes will be at .2 and .4 beyond the fraction at the
+     * keyframe before startIndex.
+     * Assumptions:
+     * - First and last keyframe fractions (bounding this spread) are already set. So,
+     * for example, if no fractions are set, we will already set first and last keyframe
+     * fraction values to 0 and 1.
+     * - startIndex must be >0 (which follows from first assumption).
+     * - endIndex must be >= startIndex.
+     *
+     * @param keyframes the array of keyframes
+     * @param gap The total gap we need to distribute
+     * @param startIndex The index of the first keyframe whose fraction must be set
+     * @param endIndex The index of the last keyframe whose fraction must be set
+     */
+    private static void distributeKeyframes(Keyframe[] keyframes, float gap,
+            int startIndex, int endIndex) {
+        int count = endIndex - startIndex + 2;
+        float increment = gap / count;
+        for (int i = startIndex; i <= endIndex; ++i) {
+            keyframes[i].setFraction(keyframes[i-1].getFraction() + increment);
+        }
+    }
+
+    private static Keyframe loadKeyframe(Resources res, Theme theme, AttributeSet attrs,
+            int valueType)
+            throws XmlPullParserException, IOException {
+
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.Keyframe, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.Keyframe);
+        }
+
+        Keyframe keyframe = null;
+
+        float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1);
+
+        boolean hasValue = a.peekValue(R.styleable.Keyframe_value) != null;
+
+        if (hasValue) {
+            switch (valueType) {
+                case VALUE_TYPE_FLOAT:
+                    float value = a.getFloat(R.styleable.Keyframe_value, 0);
+                    keyframe = Keyframe.ofFloat(fraction, value);
+                    break;
+                case VALUE_TYPE_COLOR:
+                case VALUE_TYPE_INT:
+                    int intValue = a.getInt(R.styleable.Keyframe_value, 0);
+                    keyframe = Keyframe.ofInt(fraction, intValue);
+                    break;
+            }
+        } else {
+            keyframe = (valueType == VALUE_TYPE_FLOAT) ? Keyframe.ofFloat(fraction) :
+                    Keyframe.ofInt(fraction);
+        }
+
+        a.recycle();
+
+        return keyframe;
     }
 
     private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 92762c3..53d5237 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -972,6 +972,18 @@
         }
     }
 
+    @Override
+    public String toString() {
+        String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
+        boolean prevNeedsSort = mNeedsSort;
+        sortNodes();
+        mNeedsSort = prevNeedsSort;
+        for (Node node : mSortedNodes) {
+            returnVal += "\n    " + node.animation.toString();
+        }
+        return returnVal + "\n}";
+    }
+
     /**
      * Dependency holds information about the node that some other node is
      * dependent upon and the nature of that dependency.
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index abac246..56da940 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -18,7 +18,6 @@
 
 import android.animation.Keyframe.FloatKeyframe;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 0ec5138..12a4bf9 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -18,7 +18,6 @@
 
 import android.animation.Keyframe.IntKeyframe;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 0e99bff..c80e162 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -16,7 +16,6 @@
 
 package android.animation;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
index c921466..c149bed 100644
--- a/core/java/android/animation/Keyframes.java
+++ b/core/java/android/animation/Keyframes.java
@@ -15,7 +15,6 @@
  */
 package android.animation;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 59daaab..3f71d51 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Path;
@@ -24,7 +25,6 @@
 import android.util.Property;
 
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
 
 /**
  * This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
@@ -33,6 +33,27 @@
  * are then determined internally and the animation will call these functions as necessary to
  * animate the property.
  *
+ * <p>Animators can be created from either code or resource files, as shown here:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/anim/object_animator.xml ObjectAnimatorResources}
+ *
+ * <p>When using resource files, it is possible to use {@link PropertyValuesHolder} and
+ * {@link Keyframe} to create more complex animations. Using PropertyValuesHolders
+ * allows animators to animate several properties in parallel, as shown in this sample:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/anim/object_animator_pvh.xml
+ * PropertyValuesHolderResources}
+ *
+ * <p>Using Keyframes allows animations to follow more complex paths from the start
+ * to the end values. Note that you can specify explicit fractional values (from 0 to 1) for
+ * each keyframe to determine when, in the overall duration, the animation should arrive at that
+ * value. Alternatively, you can leave the fractions off and the keyframes will be equally
+ * distributed within the total duration. Also, a keyframe with no value will derive its value
+ * from the target object when the animator starts, just like animators with only one
+ * value specified.</p>
+ *
+ * {@sample development/samples/ApiDemos/res/anim/object_animator_pvh_kf.xml KeyframeResources}
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about animating with {@code ObjectAnimator}, read the
@@ -841,6 +862,7 @@
      *  <p>Overriders of this method should call the superclass method to cause
      *  internal mechanisms to be set up correctly.</p>
      */
+    @CallSuper
     @Override
     void initAnimation() {
         if (!mInitialized) {
@@ -941,6 +963,7 @@
      *
      * @param fraction The elapsed fraction of the animation.
      */
+    @CallSuper
     @Override
     void animateValue(float fraction) {
         final Object target = getTarget();
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index bd7bca0..8928e99 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -25,10 +25,8 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * This class holds information about a property and the values that that property
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 9709555..85dc832 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -16,7 +16,7 @@
 
 package android.animation;
 
-import android.content.res.ConfigurationBoundResourceCache;
+import android.annotation.CallSuper;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -40,6 +40,21 @@
  * out of an animation. This behavior can be changed by calling
  * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
  *
+ * <p>Animators can be created from either code or resource files. Here is an example
+ * of a ValueAnimator resource file:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/anim/animator.xml ValueAnimatorResources}
+ *
+ * <p>It is also possible to use a combination of {@link PropertyValuesHolder} and
+ * {@link Keyframe} resource tags to create a multi-step animation.
+ * Note that you can specify explicit fractional values (from 0 to 1) for
+ * each keyframe to determine when, in the overall duration, the animation should arrive at that
+ * value. Alternatively, you can leave the fractions off and the keyframes will be equally
+ * distributed within the total duration:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/anim/value_animator_pvh_kf.xml
+ * ValueAnimatorKeyframeResources}
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about animating with {@code ValueAnimator}, read the
@@ -492,6 +507,7 @@
      *  <p>Overrides of this method should call the superclass method to ensure
      *  that internal mechanisms for the animation are set up correctly.</p>
      */
+    @CallSuper
     void initAnimation() {
         if (!mInitialized) {
             int numValues = mValues.length;
@@ -1361,6 +1377,7 @@
      *
      * @param fraction The elapsed fraction of the animation.
      */
+    @CallSuper
     void animateValue(float fraction) {
         fraction = mInterpolator.getInterpolation(fraction);
         mCurrentFraction = fraction;
diff --git a/core/java/android/annotation/CallSuper.java b/core/java/android/annotation/CallSuper.java
new file mode 100644
index 0000000..82e2723
--- /dev/null
+++ b/core/java/android/annotation/CallSuper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that any overriding methods should invoke this method as well.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;CallSuper
+ *  public abstract void onFocusLost();
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CallSuper {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/CheckResult.java b/core/java/android/annotation/CheckResult.java
new file mode 100644
index 0000000..787514e
--- /dev/null
+++ b/core/java/android/annotation/CheckResult.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated method returns a result that it typically is
+ * an error to ignore. This is usually used for methods that have no side effect,
+ * so calling it without actually looking at the result usually means the developer
+ * has misunderstood what the method does.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  public &#64;CheckResult String trim(String s) { return s.trim(); }
+ *  ...
+ *  s.trim(); // this is probably an error
+ *  s = s.trim(); // ok
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD})
+public @interface CheckResult {
+    /** Defines the name of the suggested method to use instead, if applicable (using
+     * the same signature format as javadoc.) If there is more than one possibility,
+     * list them all separated by commas.
+     * <p>
+     * For example, ProcessBuilder has a method named {@code redirectErrorStream()}
+     * which sounds like it might redirect the error stream. It does not. It's just
+     * a getter which returns whether the process builder will redirect the error stream,
+     * and to actually set it, you must call {@code redirectErrorStream(boolean)}.
+     * In that case, the method should be defined like this:
+     * <pre>
+     *  &#64;CheckResult(suggest="#redirectErrorStream(boolean)")
+     *  public boolean redirectErrorStream() { ... }
+     * </pre>
+     */
+    String suggest() default "";
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/ColorInt.java b/core/java/android/annotation/ColorInt.java
new file mode 100644
index 0000000..69d196c
--- /dev/null
+++ b/core/java/android/annotation/ColorInt.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element represents a packed color
+ * int, {@code AARRGGBB}. If applied to an int array, every element
+ * in the array represents a color integer.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  public abstract void setTextColor(&#64;ColorInt int color);
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD})
+public @interface ColorInt {
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/FloatRange.java b/core/java/android/annotation/FloatRange.java
new file mode 100644
index 0000000..3a7c150
--- /dev/null
+++ b/core/java/android/annotation/FloatRange.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be a float or double in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;FloatRange(from=0.0,to=1.0)
+ *  public float getAlpha() {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface FloatRange {
+    /** Smallest value. Whether it is inclusive or not is determined
+     * by {@link #fromInclusive} */
+    double from() default Double.NEGATIVE_INFINITY;
+    /** Largest value. Whether it is inclusive or not is determined
+     * by {@link #toInclusive} */
+    double to() default Double.POSITIVE_INFINITY;
+
+    /** Whether the from value is included in the range */
+    boolean fromInclusive() default true;
+
+    /** Whether the to value is included in the range */
+    boolean toInclusive() default true;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java
new file mode 100644
index 0000000..1e3c072
--- /dev/null
+++ b/core/java/android/annotation/IntRange.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should be an int or long in the given range
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  &#64;IntRange(from=0,to=255)
+ *  public int getAlpha() {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+public @interface IntRange {
+    /** Smallest value, inclusive */
+    long from() default Long.MIN_VALUE;
+    /** Largest value, inclusive */
+    long to() default Long.MAX_VALUE;
+}
\ No newline at end of file
diff --git a/core/java/android/annotation/Size.java b/core/java/android/annotation/Size.java
new file mode 100644
index 0000000..389b819
--- /dev/null
+++ b/core/java/android/annotation/Size.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Denotes that the annotated element should have a given size or length.
+ * Note that "-1" means "unset". Typically used with a parameter or
+ * return value of type array or collection.
+ * <p>
+ * Example:
+ * <pre>{@code
+ *  public void getLocationInWindow(&#64;Size(2) int[] location) {
+ *      ...
+ *  }
+ * }</pre>
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD})
+public @interface Size {
+    /** An exact size (or -1 if not specified) */
+    long value() default -1;
+    /** A minimum size, inclusive */
+    long min() default Long.MIN_VALUE;
+    /** A maximum size, inclusive */
+    long max() default Long.MAX_VALUE;
+    /** The size must be a multiple of this factor */
+    long multiple() default 1;
+}
\ No newline at end of file
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 014a7af..94e3b66 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -16,9 +16,12 @@
 
 package android.app;
 
+import android.annotation.DrawableRes;
 import android.annotation.IntDef;
+import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -30,14 +33,10 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
 import android.widget.SpinnerAdapter;
-import android.widget.Toolbar;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Map;
 
 /**
  * A primary toolbar within the activity that may display the activity title, application-level
@@ -256,7 +255,7 @@
      *
      * @see #setDisplayOptions(int, int)
      */
-    public abstract void setCustomView(int resId);
+    public abstract void setCustomView(@LayoutRes int resId);
 
     /**
      * Set the icon to display in the 'home' section of the action bar.
@@ -271,7 +270,7 @@
      * @see #setDisplayUseLogoEnabled(boolean)
      * @see #setDisplayShowHomeEnabled(boolean)
      */
-    public abstract void setIcon(int resId);
+    public abstract void setIcon(@DrawableRes int resId);
 
     /**
      * Set the icon to display in the 'home' section of the action bar.
@@ -301,7 +300,7 @@
      * @see #setDisplayUseLogoEnabled(boolean)
      * @see #setDisplayShowHomeEnabled(boolean)
      */
-    public abstract void setLogo(int resId);
+    public abstract void setLogo(@DrawableRes int resId);
 
     /**
      * Set the logo to display in the 'home' section of the action bar.
@@ -397,7 +396,7 @@
      * @see #setTitle(CharSequence)
      * @see #setDisplayOptions(int, int)
      */
-    public abstract void setTitle(int resId);
+    public abstract void setTitle(@StringRes int resId);
 
     /**
      * Set the action bar's subtitle. This will only be displayed if
@@ -420,7 +419,7 @@
      * @see #setSubtitle(CharSequence)
      * @see #setDisplayOptions(int, int)
      */
-    public abstract void setSubtitle(int resId);
+    public abstract void setSubtitle(@StringRes int resId);
 
     /**
      * Set display options. This changes all display option bits at once. To change
@@ -892,7 +891,7 @@
      * @see #setDisplayHomeAsUpEnabled(boolean)
      * @see #setHomeActionContentDescription(int)
      */
-    public void setHomeAsUpIndicator(int resId) { }
+    public void setHomeAsUpIndicator(@DrawableRes int resId) { }
 
     /**
      * Set an alternate description for the Home/Up action, when enabled.
@@ -931,7 +930,7 @@
      * @see #setHomeAsUpIndicator(int)
      * @see #setHomeAsUpIndicator(android.graphics.drawable.Drawable)
      */
-    public void setHomeActionContentDescription(int resId) { }
+    public void setHomeActionContentDescription(@StringRes int resId) { }
 
     /**
      * Enable hiding the action bar on content scroll.
@@ -1154,7 +1153,7 @@
          * @param resId Resource ID referring to the drawable to use as an icon
          * @return The current instance for call chaining
          */
-        public abstract Tab setIcon(int resId);
+        public abstract Tab setIcon(@DrawableRes int resId);
 
         /**
          * Set the text displayed on this tab. Text may be truncated if there is not
@@ -1172,7 +1171,7 @@
          * @param resId A resource ID referring to the text that should be displayed
          * @return The current instance for call chaining
          */
-        public abstract Tab setText(int resId);
+        public abstract Tab setText(@StringRes int resId);
 
         /**
          * Set a custom view to be used for this tab. This overrides values set by
@@ -1190,7 +1189,7 @@
          * @param layoutResId A layout resource to inflate and use as a custom tab view
          * @return The current instance for call chaining
          */
-        public abstract Tab setCustomView(int layoutResId);
+        public abstract Tab setCustomView(@LayoutRes int layoutResId);
 
         /**
          * Retrieve a previously set custom view for this tab.
@@ -1235,7 +1234,7 @@
          * @see #setContentDescription(CharSequence)
          * @see #getContentDescription()
          */
-        public abstract Tab setContentDescription(int resId);
+        public abstract Tab setContentDescription(@StringRes int resId);
 
         /**
          * Set a description of this tab's content for use in accessibility support.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9568897..7fcbe35 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,7 +16,14 @@
 
 package android.app;
 
+import android.annotation.CallSuper;
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.IntDef;
+import android.annotation.LayoutRes;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.os.PersistableBundle;
 import android.transition.Scene;
 import android.transition.TransitionManager;
@@ -27,10 +34,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.app.ToolbarActionBar;
-import com.android.internal.policy.PolicyManager;
 
-import android.annotation.IntDef;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentCallbacks2;
@@ -84,6 +88,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
@@ -362,7 +367,7 @@
  *
  * <p>Note the "Killable" column in the above table -- for those methods that
  * are marked as being killable, after that method returns the process hosting the
- * activity may killed by the system <em>at any time</em> without another line
+ * activity may be killed by the system <em>at any time</em> without another line
  * of its code being executed.  Because of this, you should use the
  * {@link #onPause} method to write any persistent data (such as user edits)
  * to storage.  In addition, the method
@@ -743,6 +748,7 @@
     final FragmentManagerImpl mFragments = new FragmentManagerImpl();
     final FragmentContainer mContainer = new FragmentContainer() {
         @Override
+        @Nullable
         public View findViewById(int id) {
             return Activity.this.findViewById(id);
         }
@@ -781,6 +787,7 @@
     private boolean mChangeCanvasToTranslucent;
 
     private boolean mTitleReady = false;
+    private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
 
     private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE;
     private SpannableStringBuilder mDefaultKeySsb = null;
@@ -916,6 +923,7 @@
      * @see #onRestoreInstanceState
      * @see #onPostCreate
      */
+    @CallSuper
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
         if (mLastNonConfigurationInstances != null) {
@@ -1117,6 +1125,7 @@
      *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
      * @see #onCreate
      */
+    @CallSuper
     protected void onPostCreate(@Nullable Bundle savedInstanceState) {
         if (!isChild()) {
             mTitleReady = true;
@@ -1154,6 +1163,7 @@
      * @see #onStop
      * @see #onResume
      */
+    @CallSuper
     protected void onStart() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
         mCalled = true;
@@ -1191,6 +1201,7 @@
      * @see #onStart
      * @see #onResume
      */
+    @CallSuper
     protected void onRestart() {
         mCalled = true;
     }
@@ -1215,6 +1226,7 @@
      * @see #onPostResume
      * @see #onPause
      */
+    @CallSuper
     protected void onResume() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
         getApplication().dispatchActivityResumed(this);
@@ -1234,6 +1246,7 @@
      *
      * @see #onResume
      */
+    @CallSuper
     protected void onPostResume() {
         final Window win = getWindow();
         if (win != null) win.makeActive();
@@ -1242,22 +1255,18 @@
     }
 
     /**
-     * @hide
      * Check whether this activity is running as part of a voice interaction with the user.
      * If true, it should perform its interaction with the user through the
      * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
      */
-    @SystemApi
     public boolean isVoiceInteraction() {
         return mVoiceInteractor != null;
     }
 
     /**
-     * @hide
      * Retrieve the active {@link VoiceInteractor} that the user is going through to
      * interact with this activity.
      */
-    @SystemApi
     public VoiceInteractor getVoiceInteractor() {
         return mVoiceInteractor;
     }
@@ -1463,6 +1472,7 @@
      * @see #onSaveInstanceState
      * @see #onStop
      */
+    @CallSuper
     protected void onPause() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
         getApplication().dispatchActivityPaused(this);
@@ -1538,7 +1548,7 @@
      * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
      * application.  You can override this method to place into the bundle anything
      * you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part
-     * of the assist Intent.  The default implementation does nothing.
+     * of the assist Intent.
      *
      * <p>This function will be called after any global assist callbacks that had
      * been registered with {@link Application#registerOnProvideAssistDataListener
@@ -1548,6 +1558,28 @@
     }
 
     /**
+     * This is called when the user is requesting an assist, to provide references
+     * to content related to the current activity.  Before being called, the
+     * {@code outContent} Intent is filled with the base Intent of the activity (the Intent
+     * returned by {@link #getIntent()}).  The Intent's extras are stripped of any types
+     * that are not valid for {@link PersistableBundle} or non-framework Parcelables, and
+     * the flags {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION} and
+     * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} are cleared from the Intent.
+     *
+     * <p>Custom implementation may adjust the content intent to better reflect the top-level
+     * context of the activity, and fill in its ClipData with additional content of
+     * interest that the user is currently viewing.  For example, an image gallery application
+     * that has launched in to an activity allowing the user to swipe through pictures should
+     * modify the intent to reference the current image they are looking it; such an
+     * application when showing a list of pictures should add a ClipData that has
+     * references to all of the pictures currently visible on screen.</p>
+     *
+     * @param outContent The assist content to return.
+     */
+    public void onProvideAssistContent(AssistContent outContent) {
+    }
+
+    /**
      * Called when you are no longer visible to the user.  You will next
      * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
      * depending on later user activity.
@@ -1565,6 +1597,7 @@
      * @see #onSaveInstanceState
      * @see #onDestroy
      */
+    @CallSuper
     protected void onStop() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
@@ -1602,6 +1635,7 @@
      * @see #finish
      * @see #isFinishing
      */
+    @CallSuper
     protected void onDestroy() {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
         mCalled = true;
@@ -2068,7 +2102,8 @@
      *
      * @return The view if found or null otherwise.
      */
-    public View findViewById(int id) {
+    @Nullable
+    public View findViewById(@IdRes int id) {
         return getWindow().findViewById(id);
     }
 
@@ -2141,7 +2176,7 @@
      * @see #setContentView(android.view.View)
      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
      */
-    public void setContentView(int layoutResID) {
+    public void setContentView(@LayoutRes int layoutResID) {
         getWindow().setContentView(layoutResID);
         initWindowDecorActionBar();
     }
@@ -3609,7 +3644,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawableResource}.
      */
-    public final void setFeatureDrawableResource(int featureId, int resId) {
+    public final void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
         getWindow().setFeatureDrawableResource(featureId, resId);
     }
 
@@ -3664,7 +3699,7 @@
     }
 
     @Override
-    protected void onApplyThemeResource(Resources.Theme theme, int resid,
+    protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid,
             boolean first) {
         if (mParent == null) {
             super.onApplyThemeResource(theme, resid, first);
@@ -4619,7 +4654,7 @@
         if (Looper.myLooper() != mMainThread.getLooper()) {
             throw new IllegalStateException("Must be called from main thread");
         }
-        mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
+        mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, null, false);
     }
 
     /**
@@ -5581,6 +5616,7 @@
      * @see #requestVisibleBehind(boolean)
      * @see #onBackgroundVisibleBehindChanged(boolean)
      */
+    @CallSuper
     public void onVisibleBehindCanceled() {
         mCalled = true;
     }
@@ -5664,10 +5700,10 @@
     }
 
     /**
-     * Start an action mode.
+     * Start an action mode of the default type {@link ActionMode#TYPE_PRIMARY}.
      *
-     * @param callback Callback that will manage lifecycle events for this context mode
-     * @return The ContextMode that was started, or null if it was canceled
+     * @param callback Callback that will manage lifecycle events for this action mode
+     * @return The ActionMode that was started, or null if it was canceled
      *
      * @see ActionMode
      */
@@ -5677,6 +5713,20 @@
     }
 
     /**
+     * Start an action mode of the given type.
+     *
+     * @param callback Callback that will manage lifecycle events for this action mode
+     * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}.
+     * @return The ActionMode that was started, or null if it was canceled
+     *
+     * @see ActionMode
+     */
+    @Nullable
+    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
+        return mWindow.getDecorView().startActionMode(callback, type);
+    }
+
+    /**
      * Give the Activity a chance to control the UI for an action mode requested
      * by the system.
      *
@@ -5690,19 +5740,37 @@
     @Nullable
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
-        initWindowDecorActionBar();
-        if (mActionBar != null) {
-            return mActionBar.startActionMode(callback);
+        // Only Primary ActionModes are represented in the ActionBar.
+        if (mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
+            initWindowDecorActionBar();
+            if (mActionBar != null) {
+                return mActionBar.startActionMode(callback);
+            }
         }
         return null;
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Nullable
+    @Override
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+        try {
+            mActionModeTypeStarting = type;
+            return onWindowStartingActionMode(callback);
+        } finally {
+            mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
+        }
+    }
+
+    /**
      * Notifies the Activity that an action mode has been started.
      * Activity subclasses overriding this method should call the superclass implementation.
      *
      * @param mode The new action mode.
      */
+    @CallSuper
     @Override
     public void onActionModeStarted(ActionMode mode) {
     }
@@ -5713,6 +5781,7 @@
      *
      * @param mode The action mode that just finished.
      */
+    @CallSuper
     @Override
     public void onActionModeFinished(ActionMode mode) {
     }
@@ -5929,7 +5998,7 @@
 
         mFragments.attachActivity(this, mContainer, null);
 
-        mWindow = PolicyManager.makeNewWindow(this);
+        mWindow = new PhoneWindow(this);
         mWindow.setCallback(this);
         mWindow.setOnWindowDismissedCallback(this);
         mWindow.getLayoutInflater().setPrivateFactory(this);
@@ -6080,6 +6149,17 @@
                 " did not call through to super.onResume()");
         }
 
+        // invisible activities must be finished before onResume() completes
+        if (!mVisibleFromClient && !mFinished) {
+            Log.w(TAG, "An activity without a UI must call finish() before onResume() completes");
+            if (getApplicationInfo().targetSdkVersion
+                    > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
+                throw new IllegalStateException(
+                        "Activity " + mComponent.toShortString() +
+                        " did not call finish() prior to onResume() completing");
+            }
+        }
+
         // Now really resume, and install the current status bar and menu.
         mCalled = false;
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7a636db..29b024ac 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -256,6 +256,9 @@
     /** @hide User operation call: given user id is the current user, can't be stopped. */
     public static final int USER_OP_IS_CURRENT = -2;
 
+    /** @hide Process does not exist. */
+    public static final int PROCESS_STATE_NONEXISTENT = -1;
+
     /** @hide Process is a persistent system process. */
     public static final int PROCESS_STATE_PERSISTENT = 0;
 
@@ -306,6 +309,27 @@
     /** @hide Process is being cached for later use and is empty. */
     public static final int PROCESS_STATE_CACHED_EMPTY = 13;
 
+    /** @hide requestType for assist context: only basic information. */
+    public static final int ASSIST_CONTEXT_BASIC = 0;
+
+    /** @hide requestType for assist context: generate full AssistStructure. */
+    public static final int ASSIST_CONTEXT_FULL = 1;
+
+    /**
+     * Lock task mode is not active.
+     */
+    public static final int LOCK_TASK_MODE_NONE = 0;
+
+    /**
+     * Full lock task mode is active.
+     */
+    public static final int LOCK_TASK_MODE_LOCKED = 1;
+
+    /**
+     * App pinning mode is active.
+     */
+    public static final int LOCK_TASK_MODE_PINNED = 2;
+
     Point mAppTaskThumbnailSize;
 
     /*package*/ ActivityManager(Context context, Handler handler) {
@@ -2681,12 +2705,25 @@
      * no new tasks can be created or switched to.
      *
      * @see Activity#startLockTask()
+     *
+     * @deprecated Use {@link #getLockTaskModeState} instead.
      */
     public boolean isInLockTaskMode() {
+        return getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+    }
+
+    /**
+     * Return the current state of task locking. The three possible outcomes
+     * are {@link #LOCK_TASK_MODE_NONE}, {@link #LOCK_TASK_MODE_LOCKED}
+     * and {@link #LOCK_TASK_MODE_PINNED}.
+     *
+     * @see Activity#startLockTask()
+     */
+    public int getLockTaskModeState() {
         try {
-            return ActivityManagerNative.getDefault().isInLockTaskMode();
+            return ActivityManagerNative.getDefault().getLockTaskModeState();
         } catch (RemoteException e) {
-            return false;
+            return ActivityManager.LOCK_TASK_MODE_NONE;
         }
     }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e8d08b8..997f69d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -17,7 +17,6 @@
 package android.app;
 
 import android.app.ActivityManager.StackInfo;
-import android.app.ProfilerInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -51,6 +50,7 @@
 import android.util.Log;
 import android.util.Singleton;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -466,8 +466,9 @@
             String resultData = data.readString();
             Bundle resultExtras = data.readBundle();
             boolean resultAbort = data.readInt() != 0;
+            int intentFlags = data.readInt();
             if (who != null) {
-                finishReceiver(who, resultCode, resultData, resultExtras, resultAbort);
+                finishReceiver(who, resultCode, resultData, resultExtras, resultAbort, intentFlags);
             }
             reply.writeNoException();
             return true;
@@ -689,14 +690,6 @@
             return true;
         }
 
-        case MOVE_TASK_TO_BACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int task = data.readInt();
-            moveTaskToBack(task);
-            reply.writeNoException();
-            return true;
-        }
-
         case MOVE_ACTIVITY_TASK_TO_BACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -728,7 +721,6 @@
         case RESIZE_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int stackId = data.readInt();
-            float weight = data.readFloat();
             Rect r = Rect.CREATOR.createFromParcel(data);
             resizeStack(stackId, r);
             reply.writeNoException();
@@ -774,6 +766,14 @@
             return true;
         }
 
+        case GET_FOCUSED_STACK_ID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int focusedStackId = getFocusedStackId();
+            reply.writeNoException();
+            reply.writeInt(focusedStackId);
+            return true;
+        }
+
         case REGISTER_TASK_STACK_LISTENER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2114,6 +2114,15 @@
             return true;
         }
 
+        case REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int requestType = data.readInt();
+            IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder());
+            requestAssistContextExtras(requestType, receiver);
+            reply.writeNoException();
+            return true;
+        }
+
         case REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2183,13 +2192,13 @@
             return true;
         }
 
-        case CREATE_ACTIVITY_CONTAINER_TRANSACTION: {
+        case CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder parentActivityToken = data.readStrongBinder();
             IActivityContainerCallback callback =
                     IActivityContainerCallback.Stub.asInterface(data.readStrongBinder());
             IActivityContainer activityContainer =
-                    createActivityContainer(parentActivityToken, callback);
+                    createVirtualActivityContainer(parentActivityToken, callback);
             reply.writeNoException();
             if (activityContainer != null) {
                 reply.writeInt(1);
@@ -2209,10 +2218,10 @@
             return true;
         }
 
-        case GET_ACTIVITY_CONTAINER_TRANSACTION: {
+        case CREATE_STACK_ON_DISPLAY: {
             data.enforceInterface(IActivityManager.descriptor);
-            IBinder activityToken = data.readStrongBinder();
-            IActivityContainer activityContainer = getEnclosingActivityContainer(activityToken);
+            int displayId = data.readInt();
+            IActivityContainer activityContainer = createStackOnDisplay(displayId);
             reply.writeNoException();
             if (activityContainer != null) {
                 reply.writeInt(1);
@@ -2223,6 +2232,15 @@
             return true;
         }
 
+        case GET_ACTIVITY_DISPLAY_ID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder activityToken = data.readStrongBinder();
+            int displayId = getActivityDisplayId(activityToken);
+            reply.writeNoException();
+            reply.writeInt(displayId);
+            return true;
+        }
+
         case GET_HOME_ACTIVITY_TOKEN_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder homeActivityToken = getHomeActivityToken();
@@ -2276,6 +2294,14 @@
             return true;
         }
 
+        case GET_LOCK_TASK_MODE_STATE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int lockTaskModeState = getLockTaskModeState();
+            reply.writeNoException();
+            reply.writeInt(lockTaskModeState);
+            return true;
+        }
+
         case SET_TASK_DESCRIPTION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2286,6 +2312,24 @@
             return true;
         }
 
+        case SET_TASK_RESIZEABLE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            boolean resizeable = (data.readInt() == 1) ? true : false;
+            setTaskResizeable(taskId, resizeable);
+            reply.writeNoException();
+            return true;
+        }
+
+        case RESIZE_TASK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            Rect r = Rect.CREATOR.createFromParcel(data);
+            resizeTask(taskId, r);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_TASK_DESCRIPTION_ICON_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String filename = data.readString();
@@ -2370,6 +2414,32 @@
             reply.writeNoException();
             return true;
         }
+
+        case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int uid = data.readInt();
+            final byte[] firstPacket = data.createByteArray();
+            notifyCleartextNetwork(uid, firstPacket);
+            reply.writeNoException();
+            return true;
+        }
+
+        case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String procName = data.readString();
+            long maxMemSize = data.readLong();
+            setDumpHeapDebugLimit(procName, maxMemSize);
+            reply.writeNoException();
+            return true;
+        }
+
+        case DUMP_HEAP_FINISHED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String path = data.readString();
+            dumpHeapFinished(path);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -2848,7 +2918,8 @@
         data.recycle();
         reply.recycle();
     }
-    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException
+    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
+            boolean abortBroadcast, int flags) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2858,6 +2929,7 @@
         data.writeString(resultData);
         data.writeBundle(map);
         data.writeInt(abortBroadcast ? 1 : 0);
+        data.writeInt(flags);
         mRemote.transact(FINISH_RECEIVER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
@@ -2988,7 +3060,7 @@
         ArrayList<IAppTask> list = null;
         int N = reply.readInt();
         if (N >= 0) {
-            list = new ArrayList<IAppTask>();
+            list = new ArrayList<>();
             while (N > 0) {
                 IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
                 list.add(task);
@@ -3026,7 +3098,8 @@
         reply.recycle();
         return size;
     }
-    public List getTasks(int maxNum, int flags) throws RemoteException {
+    public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, int flags)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3034,10 +3107,10 @@
         data.writeInt(flags);
         mRemote.transact(GET_TASKS_TRANSACTION, data, reply, 0);
         reply.readException();
-        ArrayList list = null;
+        ArrayList<ActivityManager.RunningTaskInfo> list = null;
         int N = reply.readInt();
         if (N >= 0) {
-            list = new ArrayList();
+            list = new ArrayList<>();
             while (N > 0) {
                 ActivityManager.RunningTaskInfo info =
                         ActivityManager.RunningTaskInfo.CREATOR
@@ -3081,7 +3154,8 @@
         reply.recycle();
         return taskThumbnail;
     }
-    public List getServices(int maxNum, int flags) throws RemoteException {
+    public List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3089,10 +3163,10 @@
         data.writeInt(flags);
         mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0);
         reply.readException();
-        ArrayList list = null;
+        ArrayList<ActivityManager.RunningServiceInfo> list = null;
         int N = reply.readInt();
         if (N >= 0) {
-            list = new ArrayList();
+            list = new ArrayList<>();
             while (N > 0) {
                 ActivityManager.RunningServiceInfo info =
                         ActivityManager.RunningServiceInfo.CREATOR
@@ -3162,17 +3236,6 @@
         data.recycle();
         reply.recycle();
     }
-    public void moveTaskToBack(int task) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(task);
-        mRemote.transact(MOVE_TASK_TO_BACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -3282,6 +3345,18 @@
         reply.recycle();
     }
     @Override
+    public int getFocusedStackId() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_FOCUSED_STACK_ID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int focusedStackId = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return focusedStackId;
+    }
+    @Override
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -5109,6 +5184,19 @@
         return res;
     }
 
+    public void requestAssistContextExtras(int requestType, IResultReceiver receiver)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(requestType);
+        data.writeStrongBinder(receiver.asBinder());
+        mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public void reportAssistContextExtras(IBinder token, Bundle extras)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -5205,14 +5293,14 @@
         reply.recycle();
     }
 
-    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+    public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(parentActivityToken);
         data.writeStrongBinder(callback == null ? null : callback.asBinder());
-        mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        mRemote.transact(CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
         reply.readException();
         final int result = reply.readInt();
         final IActivityContainer res;
@@ -5238,13 +5326,13 @@
         reply.recycle();
     }
 
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException {
+    @Override
+    public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        data.writeInt(displayId);
+        mRemote.transact(CREATE_STACK_ON_DISPLAY, data, reply, 0);
         reply.readException();
         final int result = reply.readInt();
         final IActivityContainer res;
@@ -5258,6 +5346,22 @@
         return res;
     }
 
+    @Override
+    public int getActivityDisplayId(IBinder activityToken)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(activityToken);
+        mRemote.transact(GET_ACTIVITY_DISPLAY_ID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        final int displayId = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return displayId;
+    }
+
+    @Override
     public IBinder getHomeActivityToken() throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -5341,6 +5445,19 @@
     }
 
     @Override
+    public int getLockTaskModeState() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_LOCK_TASK_MODE_STATE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int lockTaskModeState = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return lockTaskModeState;
+    }
+
+    @Override
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -5355,6 +5472,33 @@
     }
 
     @Override
+    public void setTaskResizeable(int taskId, boolean resizeable) throws  RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        data.writeInt(resizeable ? 1 : 0);
+        mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public void resizeTask(int taskId, Rect r) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        r.writeToParcel(data, 0);
+        mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -5476,5 +5620,43 @@
         reply.recycle();
     }
 
+    @Override
+    public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(uid);
+        data.writeByteArray(firstPacket);
+        mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(processName);
+        data.writeLong(maxMemSize);
+        mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public void dumpHeapFinished(String path) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(path);
+        mRemote.transact(DUMP_HEAP_FINISHED_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 39ae65c..8909b28 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -140,6 +140,8 @@
     public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
     /** @hide */
     public static final int ANIM_CUSTOM_IN_PLACE = 10;
+    /** @hide */
+    public static final int ANIM_CLIP_REVEAL = 11;
 
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
@@ -291,6 +293,33 @@
     }
 
     /**
+     * Create an ActivityOptions specifying an animation where the new
+     * activity is revealed from a small originating area of the screen to
+     * its final full representation.
+     *
+     * @param source The View that the new activity is animating from.  This
+     * defines the coordinate space for <var>startX</var> and <var>startY</var>.
+     * @param startX The x starting location of the new activity, relative to <var>source</var>.
+     * @param startY The y starting location of the activity, relative to <var>source</var>.
+     * @param width The initial width of the new activity.
+     * @param height The initial height of the new activity.
+     * @return Returns a new ActivityOptions object that you can use to
+     * supply these options as the options Bundle when starting an activity.
+     */
+    public static ActivityOptions makeClipRevealAnimation(View source,
+            int startX, int startY, int width, int height) {
+        ActivityOptions opts = new ActivityOptions();
+        opts.mAnimationType = ANIM_CLIP_REVEAL;
+        int[] pts = new int[2];
+        source.getLocationOnScreen(pts);
+        opts.mStartX = pts[0] + startX;
+        opts.mStartY = pts[1] + startY;
+        opts.mWidth = width;
+        opts.mHeight = height;
+        return opts;
+    }
+
+    /**
      * Create an ActivityOptions specifying an animation where a thumbnail
      * is scaled from a given position to the new activity window that is
      * being started.
@@ -582,6 +611,7 @@
                 break;
 
             case ANIM_SCALE_UP:
+            case ANIM_CLIP_REVEAL:
                 mStartX = opts.getInt(KEY_ANIM_START_X, 0);
                 mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
                 mWidth = opts.getInt(KEY_ANIM_WIDTH, 0);
@@ -809,6 +839,7 @@
                 b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
                 break;
             case ANIM_SCALE_UP:
+            case ANIM_CLIP_REVEAL:
                 b.putInt(KEY_ANIM_START_X, mStartX);
                 b.putInt(KEY_ANIM_START_Y, mStartY);
                 b.putInt(KEY_ANIM_WIDTH, mWidth);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f2be45c..7b8ec74 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,6 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
-import android.net.LinkProperties;
 import android.net.Network;
 import android.net.Proxy;
 import android.net.ProxyInfo;
@@ -87,8 +86,6 @@
 import android.util.SuperNotCalledException;
 import android.view.Display;
 import android.view.HardwareRenderer;
-import android.view.IWindowManager;
-import android.view.IWindowSessionCallback;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewManager;
@@ -124,7 +121,6 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
-import java.util.regex.Pattern;
 
 import libcore.io.DropBox;
 import libcore.io.EventLogger;
@@ -163,10 +159,9 @@
     private static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
-    private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
-    private static final int LOG_ON_PAUSE_CALLED = 30021;
-    private static final int LOG_ON_RESUME_CALLED = 30022;
+    private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
+    private static final int LOG_AM_ON_RESUME_CALLED = 30022;
 
     /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */
     public static final int SERVICE_DONE_EXECUTING_ANON = 0;
@@ -296,6 +291,9 @@
         boolean hideForNow;
         Configuration newConfig;
         Configuration createdConfig;
+        Configuration overrideConfig;
+        // Used for consolidating configs before sending on to Activity.
+        private Configuration tmpConfig = new Configuration();
         ActivityClientRecord nextIdle;
 
         ProfilerInfo profilerInfo;
@@ -374,7 +372,7 @@
         public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                 boolean ordered, boolean sticky, IBinder token, int sendingUser) {
             super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky,
-                    token, sendingUser);
+                    token, sendingUser, intent.getFlags());
             this.intent = intent;
         }
 
@@ -559,6 +557,15 @@
         int requestType;
     }
 
+    static final class ActivityConfigChangeData {
+        final IBinder activityToken;
+        final Configuration overrideConfig;
+        public ActivityConfigChangeData(IBinder token, Configuration config) {
+            activityToken = token;
+            overrideConfig = config;
+        }
+    }
+
     private native void dumpGraphicsInfo(FileDescriptor fd);
 
     private class ApplicationThread extends ApplicationThreadNative {
@@ -618,12 +625,13 @@
 
         // we use token to identify this activity without having to send the
         // activity itself back to the activity manager. (matters more with ipc)
+        @Override
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-                String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
-                PersistableBundle persistentState, List<ResultInfo> pendingResults,
-                List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
-                ProfilerInfo profilerInfo) {
+                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
+                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
+                int procState, Bundle state, PersistableBundle persistentState,
+                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
 
             updateProcessState(procState, false);
 
@@ -647,16 +655,19 @@
 
             r.profilerInfo = profilerInfo;
 
+            r.overrideConfig = overrideConfig;
             updatePendingConfiguration(curConfig);
 
             sendMessage(H.LAUNCH_ACTIVITY, r);
         }
 
+        @Override
         public final void scheduleRelaunchActivity(IBinder token,
                 List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-                int configChanges, boolean notResumed, Configuration config) {
+                int configChanges, boolean notResumed, Configuration config,
+                Configuration overrideConfig) {
             requestRelaunchActivity(token, pendingResults, pendingNewIntents,
-                    configChanges, notResumed, config, true);
+                    configChanges, notResumed, config, overrideConfig, true);
         }
 
         public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
@@ -886,14 +897,19 @@
                     sticky, sendingUser);
         }
 
+        @Override
         public void scheduleLowMemory() {
             sendMessage(H.LOW_MEMORY, null);
         }
 
-        public void scheduleActivityConfigurationChanged(IBinder token) {
-            sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
+        @Override
+        public void scheduleActivityConfigurationChanged(
+                IBinder token, Configuration overrideConfig) {
+            sendMessage(H.ACTIVITY_CONFIGURATION_CHANGED,
+                    new ActivityConfigChangeData(token, overrideConfig));
         }
 
+        @Override
         public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
             sendMessage(H.PROFILER_CONTROL, profilerInfo, start ? 1 : 0, profileType);
         }
@@ -1083,11 +1099,10 @@
         @Override
         public void dumpGfxInfo(FileDescriptor fd, String[] args) {
             dumpGraphicsInfo(fd);
-            WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
+            WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args);
         }
 
-        @Override
-        public void dumpDbInfo(FileDescriptor fd, String[] args) {
+        private void dumpDatabaseInfo(FileDescriptor fd, String[] args) {
             PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
             PrintWriterPrinter printer = new PrintWriterPrinter(pw);
             SQLiteDebug.dump(printer, args);
@@ -1095,6 +1110,22 @@
         }
 
         @Override
+        public void dumpDbInfo(final FileDescriptor fd, final String[] args) {
+            if (mSystemThread) {
+                // Ensure this invocation is asynchronous to prevent
+                // writer waiting due to buffer cannot be consumed.
+                AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        dumpDatabaseInfo(fd, args);
+                    }
+                });
+            } else {
+                dumpDatabaseInfo(fd, args);
+            }
+        }
+
+        @Override
         public void unstableProviderDied(IBinder provider) {
             sendMessage(H.UNSTABLE_PROVIDER_DIED, provider);
         }
@@ -1178,9 +1209,17 @@
             sendMessage(H.BACKGROUND_VISIBLE_BEHIND_CHANGED, token, visible ? 1 : 0);
         }
 
+        @Override
         public void scheduleEnterAnimationComplete(IBinder token) {
             sendMessage(H.ENTER_ANIMATION_COMPLETE, token);
         }
+
+        @Override
+        public void notifyCleartextNetwork(byte[] firstPacket) {
+            if (StrictMode.vmCleartextNetworkEnabled()) {
+                StrictMode.onCleartextNetworkDetected(firstPacket);
+            }
+        }
     }
 
     private class H extends Handler {
@@ -1430,7 +1469,7 @@
                     break;
                 case ACTIVITY_CONFIGURATION_CHANGED:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
-                    handleActivityConfigurationChanged((IBinder)msg.obj);
+                    handleActivityConfigurationChanged((ActivityConfigChangeData)msg.obj);
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case PROFILER_CONTROL:
@@ -1648,7 +1687,7 @@
             String[] libDirs, int displayId, Configuration overrideConfiguration,
             LoadedApk pkgInfo) {
         return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
-                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
+                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
     }
 
     final Handler getHandler() {
@@ -2331,34 +2370,28 @@
         return activity;
     }
 
-    private Context createBaseContextForActivity(ActivityClientRecord r,
-            final Activity activity) {
-        ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
+    private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
+        int displayId = Display.DEFAULT_DISPLAY;
+        try {
+            displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
+        } catch (RemoteException e) {
+        }
+
+        ContextImpl appContext = ContextImpl.createActivityContext(
+                this, r.packageInfo, displayId, r.overrideConfig);
         appContext.setOuterContext(activity);
         Context baseContext = appContext;
 
         final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
-        try {
-            IActivityContainer container =
-                    ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);
-            final int displayId =
-                    container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();
-            if (displayId > Display.DEFAULT_DISPLAY) {
-                Display display = dm.getRealDisplay(displayId, r.token);
-                baseContext = appContext.createDisplayContext(display);
-            }
-        } catch (RemoteException e) {
-        }
-
         // For debugging purposes, if the activity's package name contains the value of
         // the "debug.use-second-display" system property as a substring, then show
         // its content on a secondary display if there is one.
         String pkgName = SystemProperties.get("debug.second-display.pkg");
         if (pkgName != null && !pkgName.isEmpty()
                 && r.packageInfo.mPackageName.contains(pkgName)) {
-            for (int displayId : dm.getDisplayIds()) {
-                if (displayId != Display.DEFAULT_DISPLAY) {
-                    Display display = dm.getRealDisplay(displayId, r.token);
+            for (int id : dm.getDisplayIds()) {
+                if (id != Display.DEFAULT_DISPLAY) {
+                    Display display = dm.getRealDisplay(id, r.overrideConfig);
                     baseContext = appContext.createDisplayContext(display);
                     break;
                 }
@@ -2486,6 +2519,17 @@
         if (r != null) {
             r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
             r.activity.onProvideAssistData(data);
+            if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL) {
+                data.putParcelable(AssistStructure.ASSIST_KEY, new AssistStructure(r.activity));
+                AssistContent content = new AssistContent();
+                Intent intent = new Intent(r.activity.getIntent());
+                intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+                intent.removeUnsafeExtras();
+                content.setIntent(intent);
+                r.activity.onProvideAssistContent(content);
+                data.putParcelable(AssistContent.ASSIST_KEY, content);
+            }
         }
         if (data.isEmpty()) {
             data = null;
@@ -2977,7 +3021,7 @@
                 }
                 r.activity.performResume();
 
-                EventLog.writeEvent(LOG_ON_RESUME_CALLED,
+                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED,
                         UserHandle.myUserId(), r.activity.getComponentName().getClassName());
 
                 r.paused = false;
@@ -3072,10 +3116,14 @@
             if (!r.activity.mFinished && willBeVisible
                     && r.activity.mDecor != null && !r.hideForNow) {
                 if (r.newConfig != null) {
+                    r.tmpConfig.setTo(r.newConfig);
+                    if (r.overrideConfig != null) {
+                        r.tmpConfig.updateFrom(r.overrideConfig);
+                    }
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
-                            + r.activityInfo.name + " with newConfig " + r.newConfig);
-                    performConfigurationChanged(r.activity, r.newConfig);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+                            + r.activityInfo.name + " with newConfig " + r.tmpConfig);
+                    performConfigurationChanged(r.activity, r.tmpConfig);
+                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
                     r.newConfig = null;
                 }
                 if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
@@ -3247,7 +3295,7 @@
             // Now we are idle.
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
-            EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
+            EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                     r.activity.getComponentName().getClassName());
             if (!r.activity.mCalled) {
                 throw new SuperNotCalledException(
@@ -3404,10 +3452,14 @@
                     }
                 }
                 if (r.newConfig != null) {
+                    r.tmpConfig.setTo(r.newConfig);
+                    if (r.overrideConfig != null) {
+                        r.tmpConfig.updateFrom(r.overrideConfig);
+                    }
                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis "
-                            + r.activityInfo.name + " with new config " + r.newConfig);
-                    performConfigurationChanged(r.activity, r.newConfig);
-                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
+                            + r.activityInfo.name + " with new config " + r.tmpConfig);
+                    performConfigurationChanged(r.activity, r.tmpConfig);
+                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
                     r.newConfig = null;
                 }
             } else {
@@ -3541,7 +3593,7 @@
 
             // request all activities to relaunch for the changes to take place
             for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, false);
+                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false);
             }
         }
     }
@@ -3644,7 +3696,7 @@
                 try {
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
-                    EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
+                    EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                             r.activity.getComponentName().getClassName());
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
@@ -3785,7 +3837,7 @@
     public final void requestRelaunchActivity(IBinder token,
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
             int configChanges, boolean notResumed, Configuration config,
-            boolean fromServer) {
+            Configuration overrideConfig, boolean fromServer) {
         ActivityClientRecord target = null;
 
         synchronized (mResourcesManager) {
@@ -3820,6 +3872,7 @@
                     ActivityClientRecord existing = mActivities.get(token);
                     if (existing != null) {
                         target.startsNotResumed = existing.paused;
+                        target.overrideConfig = existing.overrideConfig;
                     }
                     target.onlyLocalRequest = true;
                 }
@@ -3834,6 +3887,9 @@
             if (config != null) {
                 target.createdConfig = config;
             }
+            if (overrideConfig != null) {
+                target.overrideConfig = overrideConfig;
+            }
             target.pendingConfigChanges |= configChanges;
         }
     }
@@ -3946,6 +4002,7 @@
             }
         }
         r.startsNotResumed = tmp.startsNotResumed;
+        r.overrideConfig = tmp.overrideConfig;
 
         handleLaunchActivity(r, currentIntent);
     }
@@ -4133,16 +4190,21 @@
         }
     }
 
-    final void handleActivityConfigurationChanged(IBinder token) {
-        ActivityClientRecord r = mActivities.get(token);
+    final void handleActivityConfigurationChanged(ActivityConfigChangeData data) {
+        ActivityClientRecord r = mActivities.get(data.activityToken);
         if (r == null || r.activity == null) {
             return;
         }
 
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
                 + r.activityInfo.name);
-        
-        performConfigurationChanged(r.activity, mCompatConfiguration);
+
+        r.tmpConfig.setTo(mCompatConfiguration);
+        if (data.overrideConfig != null) {
+            r.overrideConfig = data.overrideConfig;
+            r.tmpConfig.updateFrom(data.overrideConfig);
+        }
+        performConfigurationChanged(r.activity, r.tmpConfig);
 
         freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));
 
@@ -4194,27 +4256,33 @@
         } else {
             Debug.dumpNativeHeap(dhd.fd.getFileDescriptor());
         }
+        try {
+            ActivityManagerNative.getDefault().dumpHeapFinished(dhd.path);
+        } catch (RemoteException e) {
+        }
     }
 
     final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
         boolean hasPkgInfo = false;
         if (packages != null) {
-            for (int i=packages.length-1; i>=0; i--) {
-                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
-                if (!hasPkgInfo) {
-                    WeakReference<LoadedApk> ref;
-                    ref = mPackages.get(packages[i]);
-                    if (ref != null && ref.get() != null) {
-                        hasPkgInfo = true;
-                    } else {
-                        ref = mResourcePackages.get(packages[i]);
+            synchronized (mResourcesManager) {
+                for (int i=packages.length-1; i>=0; i--) {
+                    //Slog.i(TAG, "Cleaning old package: " + packages[i]);
+                    if (!hasPkgInfo) {
+                        WeakReference<LoadedApk> ref;
+                        ref = mPackages.get(packages[i]);
                         if (ref != null && ref.get() != null) {
                             hasPkgInfo = true;
+                        } else {
+                            ref = mResourcePackages.get(packages[i]);
+                            if (ref != null && ref.get() != null) {
+                                hasPkgInfo = true;
+                            }
                         }
                     }
+                    mPackages.remove(packages[i]);
+                    mResourcePackages.remove(packages[i]);
                 }
-                mPackages.remove(packages[i]);
-                mResourcePackages.remove(packages[i]);
             }
         }
         ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
@@ -4371,10 +4439,16 @@
             if (cacheDir != null) {
                 // Provide a usable directory for temporary files
                 System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-    
-                setupGraphicsSupport(data.info, cacheDir);
             } else {
-                Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
+                Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
+            }
+
+            // Use codeCacheDir to store generated/compiled graphics code
+            final File codeCacheDir = appContext.getCodeCacheDir();
+            if (codeCacheDir != null) {
+                setupGraphicsSupport(data.info, codeCacheDir);
+            } else {
+                Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
             }
         }
 
@@ -4517,6 +4591,10 @@
 
         if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
             dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
+        } else {
+            // Small heap, clamp to the current growth limit and let the heap release
+            // pages after the growth limit to the non growth limit capacity. b/18387825
+            dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
         }
 
         // Allow disk access during application and provider setup. This could
@@ -4921,7 +4999,7 @@
 
     private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
             ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
-        final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
+        final String auths[] = holder.info.authority.split(";");
         final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
 
         final ProviderClientRecord pcr = new ProviderClientRecord(
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e3b27b5..2939322 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -206,7 +206,6 @@
     private ArrayList<GhostViewListeners> mGhostViewListeners =
             new ArrayList<GhostViewListeners>();
     private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
-    final private ArrayList<View> mRootSharedElements = new ArrayList<View>();
     private ArrayList<Matrix> mSharedElementParentMatrices;
 
     public ActivityTransitionCoordinator(Window window,
@@ -253,17 +252,10 @@
                 final String name = sharedElements.keyAt(i);
                 if (isFirstRun && (view == null || !view.isAttachedToWindow() || name == null)) {
                     sharedElements.removeAt(i);
-                } else {
-                    if (!isNested(view, sharedElements)) {
-                        mSharedElementNames.add(name);
-                        mSharedElements.add(view);
-                        sharedElements.removeAt(i);
-                        if (isFirstRun) {
-                            // We need to keep track which shared elements are roots
-                            // and which are nested.
-                            mRootSharedElements.add(view);
-                        }
-                    }
+                } else if (!isNested(view, sharedElements)) {
+                    mSharedElementNames.add(name);
+                    mSharedElements.add(view);
+                    sharedElements.removeAt(i);
                 }
             }
             isFirstRun = false;
@@ -520,24 +512,9 @@
     }
 
     private void getSharedElementParentMatrix(View view, Matrix matrix) {
-        final boolean isNestedInOtherSharedElement = !mRootSharedElements.contains(view);
-        final boolean useParentMatrix;
-        if (isNestedInOtherSharedElement) {
-            useParentMatrix = true;
-        } else {
-            final int index = mSharedElementParentMatrices == null ? -1
-                    : mSharedElements.indexOf(view);
-            if (index < 0) {
-                useParentMatrix = true;
-            } else {
-                // The indices of mSharedElementParentMatrices matches the
-                // mSharedElement matrices.
-                Matrix parentMatrix = mSharedElementParentMatrices.get(index);
-                matrix.set(parentMatrix);
-                useParentMatrix = false;
-            }
-        }
-        if (useParentMatrix) {
+        final int index = mSharedElementParentMatrices == null ? -1
+                : mSharedElements.indexOf(view);
+        if (index < 0) {
             matrix.reset();
             ViewParent viewParent = view.getParent();
             if (viewParent instanceof ViewGroup) {
@@ -545,6 +522,11 @@
                 ViewGroup parent = (ViewGroup) viewParent;
                 parent.transformMatrixToLocal(matrix);
             }
+        } else {
+            // The indices of mSharedElementParentMatrices matches the
+            // mSharedElement matrices.
+            Matrix parentMatrix = mSharedElementParentMatrices.get(index);
+            matrix.set(parentMatrix);
         }
     }
 
@@ -701,7 +683,6 @@
         mResultReceiver = null;
         mPendingTransition = null;
         mListener = null;
-        mRootSharedElements.clear();
         mSharedElementParentMatrices = null;
     }
 
@@ -817,9 +798,12 @@
         ViewGroup decor = getDecor();
         if (decor != null) {
             boolean moveWithParent = moveSharedElementWithParent();
+            Matrix tempMatrix = new Matrix();
             for (int i = 0; i < numSharedElements; i++) {
                 View view = mSharedElements.get(i);
-                GhostView.addGhost(view, decor);
+                tempMatrix.reset();
+                mSharedElementParentMatrices.get(i).invert(tempMatrix);
+                GhostView.addGhost(view, decor, tempMatrix);
                 ViewGroup parent = (ViewGroup) view.getParent();
                 if (moveWithParent && !isInTransitionGroup(parent, decor)) {
                     GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index a2bfa4e..5c6fe46 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -18,7 +18,6 @@
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.transition.Transition;
-import android.util.ArrayMap;
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 94ea2c5..2cb27b0 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.app.ActivityManager.START_CANCELED;
+
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.IIntentSender;
@@ -23,6 +25,7 @@
 import android.content.IntentSender;
 import android.graphics.SurfaceTexture;
 import android.os.IBinder;
+import android.os.OperationCanceledException;
 import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -55,10 +58,6 @@
     private int mLastVisibility;
     private ActivityViewCallback mActivityViewCallback;
 
-    // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
-    IIntentSender mQueuedPendingIntent;
-    Intent mQueuedIntent;
-
     public ActivityView(Context context) {
         this(context, null);
     }
@@ -83,7 +82,7 @@
 
         try {
             mActivityContainer = new ActivityContainerWrapper(
-                    ActivityManagerNative.getDefault().createActivityContainer(
+                    ActivityManagerNative.getDefault().createVirtualActivityContainer(
                             mActivity.getActivityToken(), new ActivityContainerCallback(this)));
         } catch (RemoteException e) {
             throw new RuntimeException("ActivityView: Unable to create ActivityContainer. "
@@ -167,14 +166,13 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
                 (isAttachedToDisplay() ? "" : "not") + " attached");
-        if (mSurface != null) {
-            mActivityContainer.startActivity(intent);
-        } else {
-            mActivityContainer.checkEmbeddedAllowed(intent);
-            mQueuedIntent = intent;
-            mQueuedPendingIntent = null;
+        if (mActivityContainer.startActivity(intent) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -182,15 +180,14 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
                 (isAttachedToDisplay() ? "" : "not") + " attached");
         final IIntentSender iIntentSender = intentSender.getTarget();
-        if (mSurface != null) {
-            mActivityContainer.startActivityIntentSender(iIntentSender);
-        } else {
-            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
-            mQueuedPendingIntent = iIntentSender;
-            mQueuedIntent = null;
+        if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -198,15 +195,14 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
                 + (isAttachedToDisplay() ? "" : "not") + " attached");
         final IIntentSender iIntentSender = pendingIntent.getTarget();
-        if (mSurface != null) {
-            mActivityContainer.startActivityIntentSender(iIntentSender);
-        } else {
-            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
-            mQueuedPendingIntent = iIntentSender;
-            mQueuedIntent = null;
+        if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -243,26 +239,24 @@
             mSurface = null;
             throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
         }
-
-        if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
-                mQueuedPendingIntent != null ? "" : "no") + " queued intent");
-        if (mQueuedIntent != null) {
-            mActivityContainer.startActivity(mQueuedIntent);
-            mQueuedIntent = null;
-        } else if (mQueuedPendingIntent != null) {
-            mActivityContainer.startActivityIntentSender(mQueuedPendingIntent);
-            mQueuedPendingIntent = null;
-        }
     }
 
     /**
      * Set the callback to use to report certain state changes.
-     * @param callback The callback to report events to.
+     *
+     * Note: If the surface has been created prior to this call being made, then
+     * ActivityViewCallback.onSurfaceAvailable will be called from within setCallback.
+     *
+     *  @param callback The callback to report events to.
      *
      * @see ActivityViewCallback
      */
     public void setCallback(ActivityViewCallback callback) {
         mActivityViewCallback = callback;
+
+        if (mSurface != null) {
+            mActivityViewCallback.onSurfaceAvailable(this);
+        }
     }
 
     public static abstract class ActivityViewCallback {
@@ -272,6 +266,16 @@
          * have at most one callback registered.
          */
         public abstract void onAllActivitiesComplete(ActivityView view);
+        /**
+         * Called when the surface is ready to be drawn to. Calling startActivity prior to this
+         * callback will result in an IllegalStateException.
+         */
+        public abstract void onSurfaceAvailable(ActivityView view);
+        /**
+         * Called when the surface has been removed. Calling startActivity after this callback
+         * will result in an IllegalStateException.
+         */
+        public abstract void onSurfaceDestroyed(ActivityView view);
     }
 
     private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@@ -286,6 +290,9 @@
             mWidth = width;
             mHeight = height;
             attachToSurfaceWhenReady();
+            if (mActivityViewCallback != null) {
+                mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
+            }
         }
 
         @Override
@@ -311,6 +318,9 @@
                 throw new RuntimeException(
                         "ActivityView: Unable to set surface of ActivityContainer. " + e);
             }
+            if (mActivityViewCallback != null) {
+                mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
+            }
             return true;
         }
 
@@ -325,7 +335,7 @@
         private final WeakReference<ActivityView> mActivityViewWeakReference;
 
         ActivityContainerCallback(ActivityView activityView) {
-            mActivityViewWeakReference = new WeakReference<ActivityView>(activityView);
+            mActivityViewWeakReference = new WeakReference<>(activityView);
         }
 
         @Override
@@ -391,24 +401,6 @@
             }
         }
 
-        void checkEmbeddedAllowed(Intent intent) {
-            try {
-                mIActivityContainer.checkEmbeddedAllowed(intent);
-            } catch (RemoteException e) {
-                throw new RuntimeException(
-                        "ActivityView: Unable to startActivity from Intent. " + e);
-            }
-        }
-
-        void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
-            try {
-                mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender);
-            } catch (RemoteException e) {
-                throw new RuntimeException(
-                        "ActivityView: Unable to startActivity from IntentSender. " + e);
-            }
-        }
-
         int getDisplayId() {
             try {
                 return mIActivityContainer.getDisplayId();
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 2c596e5..5dd02ae 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -26,7 +26,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.os.Parcelable.Creator;
 
 /**
  * This class provides access to the system alarm services.  These allow you
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 3c6458f..3e545f9 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -18,6 +18,10 @@
 
 import com.android.internal.app.AlertController;
 
+import android.annotation.ArrayRes;
+import android.annotation.AttrRes;
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.database.Cursor;
@@ -34,6 +38,8 @@
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
+import com.android.internal.R;
+
 /**
  * A subclass of Dialog that can display one, two or three buttons. If you only want to
  * display a String in this dialog box, use the setMessage() method.  If you
@@ -44,7 +50,7 @@
  * FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom);
  * fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
  * </pre>
- * 
+ *
  * <p>The AlertDialog class takes care of automatically setting
  * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
  * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
@@ -66,31 +72,46 @@
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the traditional (pre-Holo) alert dialog theme.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_TRADITIONAL = 1;
-    
+
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the holographic alert theme with a dark background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_HOLO_DARK = 2;
-    
+
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the holographic alert theme with a light background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Light_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_HOLO_LIGHT = 3;
 
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the device's default alert theme with a dark background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_DEVICE_DEFAULT_DARK = 4;
 
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the device's default alert theme with a light background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Light_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_DEVICE_DEFAULT_LIGHT = 5;
 
     /**
@@ -104,55 +125,92 @@
      * @hide
      */
     public static final int LAYOUT_HINT_SIDE = 1;
-    
+
+    /**
+     * Creates an alert dialog that uses the default alert dialog theme.
+     * <p>
+     * The default alert dialog theme is defined by
+     * {@link android.R.attr#alertDialogTheme} within the parent
+     * {@code context}'s theme.
+     *
+     * @param context the parent context
+     */
     protected AlertDialog(Context context) {
-        this(context, resolveDialogTheme(context, 0), true);
+        this(context, 0);
     }
 
     /**
-     * Construct an AlertDialog that uses an explicit theme.  The actual style
-     * that an AlertDialog uses is a private implementation, however you can
-     * here supply either the name of an attribute in the theme from which
-     * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
-     * or one of the constants {@link #THEME_TRADITIONAL},
-     * {@link #THEME_HOLO_DARK}, or {@link #THEME_HOLO_LIGHT}.
+     * Creates an alert dialog that uses the default alert dialog theme and a
+     * custom cancel listener.
+     * <p>
+     * This is functionally identical to:
+     * <pre>
+     *     AlertDialog dialog = new AlertDialog(context);
+     *     alertDialog.setCancelable(cancelable);
+     *     alertDialog.setOnCancelListener(cancelListener);
+     * </pre>
+     * <p>
+     * The default alert dialog theme is defined by
+     * {@link android.R.attr#alertDialogTheme} within the parent
+     * {@code context}'s theme.
+     *
+     * @param context the parent context
      */
-    protected AlertDialog(Context context, int theme) {
-        this(context, theme, true);
+    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
+        this(context, 0);
+
+        setCancelable(cancelable);
+        setOnCancelListener(cancelListener);
     }
 
-    AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
-        super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
+    /**
+     * Creates an alert dialog that uses an explicit theme resource.
+     * <p>
+     * The specified theme resource ({@code themeResId}) is applied on top of
+     * the parent {@code context}'s theme. It may be specified as a style
+     * resource containing a fully-populated theme, such as
+     * {@link android.R.style#Theme_Material_Dialog}, to replace all attributes
+     * in the parent {@code context}'s theme including primary and accent
+     * colors.
+     * <p>
+     * To preserve attributes such as primary and accent colors, the
+     * {@code themeResId} may instead be specified as an overlay theme such as
+     * {@link android.R.style#ThemeOverlay_Material_Dialog}. This will override
+     * only the window attributes necessary to style the alert window as a
+     * dialog.
+     * <p>
+     * Alternatively, the {@code themeResId} may be specified as {@code 0} to
+     * use the parent {@code context}'s resolved value for
+     * {@link android.R.attr#alertDialogTheme}.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
+     */
+    protected AlertDialog(Context context, @AttrRes int themeResId) {
+        super(context, resolveDialogTheme(context, themeResId));
 
         mWindow.alwaysReadCloseOnTouchAttr();
         mAlert = new AlertController(getContext(), this, getWindow());
     }
 
-    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
-        super(context, resolveDialogTheme(context, 0));
-        mWindow.alwaysReadCloseOnTouchAttr();
-        setCancelable(cancelable);
-        setOnCancelListener(cancelListener);
-        mAlert = new AlertController(context, this, getWindow());
-    }
-
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == THEME_TRADITIONAL) {
-            return com.android.internal.R.style.Theme_Dialog_Alert;
-        } else if (resid == THEME_HOLO_DARK) {
-            return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
-        } else if (resid == THEME_HOLO_LIGHT) {
-            return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
-        } else if (resid == THEME_DEVICE_DEFAULT_DARK) {
-            return com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert;
-        } else if (resid == THEME_DEVICE_DEFAULT_LIGHT) {
-            return com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
-        } else if (resid >= 0x01000000) {   // start of real resource IDs.
-            return resid;
+    static int resolveDialogTheme(Context context, int themeResId) {
+        if (themeResId == THEME_TRADITIONAL) {
+            return R.style.Theme_Dialog_Alert;
+        } else if (themeResId == THEME_HOLO_DARK) {
+            return R.style.Theme_Holo_Dialog_Alert;
+        } else if (themeResId == THEME_HOLO_LIGHT) {
+            return R.style.Theme_Holo_Light_Dialog_Alert;
+        } else if (themeResId == THEME_DEVICE_DEFAULT_DARK) {
+            return R.style.Theme_DeviceDefault_Dialog_Alert;
+        } else if (themeResId == THEME_DEVICE_DEFAULT_LIGHT) {
+            return R.style.Theme_DeviceDefault_Light_Dialog_Alert;
+        } else if (themeResId >= 0x01000000) {   // start of real resource IDs.
+            return themeResId;
         } else {
-            TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
-                    outValue, true);
+            final TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
             return outValue.resourceId;
         }
     }
@@ -173,13 +231,13 @@
 
     /**
      * Gets the list view used in the dialog.
-     *  
+     *
      * @return The {@link ListView} from the dialog.
      */
     public ListView getListView() {
         return mAlert.getListView();
     }
-    
+
     @Override
     public void setTitle(CharSequence title) {
         super.setTitle(title);
@@ -192,7 +250,7 @@
     public void setCustomTitle(View customTitleView) {
         mAlert.setCustomTitle(customTitleView);
     }
-    
+
     public void setMessage(CharSequence message) {
         mAlert.setMessage(message);
     }
@@ -203,9 +261,9 @@
     public void setView(View view) {
         mAlert.setView(view);
     }
-    
+
     /**
-     * Set the view to display in that dialog, specifying the spacing to appear around that 
+     * Set the view to display in that dialog, specifying the spacing to appear around that
      * view.
      *
      * @param view The view to show in the content area of the dialog
@@ -229,7 +287,7 @@
 
     /**
      * Set a message to be sent when a button is pressed.
-     * 
+     *
      * @param whichButton Which button to set the message for, can be one of
      *            {@link DialogInterface#BUTTON_POSITIVE},
      *            {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -240,10 +298,10 @@
     public void setButton(int whichButton, CharSequence text, Message msg) {
         mAlert.setButton(whichButton, text, null, msg);
     }
-    
+
     /**
      * Set a listener to be invoked when the positive button of the dialog is pressed.
-     * 
+     *
      * @param whichButton Which button to set the listener on, can be one of
      *            {@link DialogInterface#BUTTON_POSITIVE},
      *            {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -263,7 +321,7 @@
     public void setButton(CharSequence text, Message msg) {
         setButton(BUTTON_POSITIVE, text, msg);
     }
-        
+
     /**
      * @deprecated Use {@link #setButton(int, CharSequence, Message)} with
      *             {@link DialogInterface#BUTTON_NEGATIVE}.
@@ -284,7 +342,7 @@
 
     /**
      * Set a listener to be invoked when button 1 of the dialog is pressed.
-     * 
+     *
      * @param text The text to display in button 1.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
      * @deprecated Use
@@ -327,10 +385,10 @@
      * @param resId the resourceId of the drawable to use as the icon or 0
      * if you don't want an icon.
      */
-    public void setIcon(int resId) {
+    public void setIcon(@DrawableRes int resId) {
         mAlert.setIcon(resId);
     }
-    
+
     public void setIcon(Drawable icon) {
         mAlert.setIcon(icon);
     }
@@ -340,7 +398,7 @@
      *
      * @param attrId ID of a theme attribute that points to a drawable resource.
      */
-    public void setIconAttribute(int attrId) {
+    public void setIconAttribute(@AttrRes int attrId) {
         TypedValue out = new TypedValue();
         mContext.getTheme().resolveAttribute(attrId, out, true);
         mAlert.setIcon(out.resourceId);
@@ -349,7 +407,7 @@
     public void setInverseBackgroundForced(boolean forceInverseBackground) {
         mAlert.setInverseBackgroundForced(forceInverseBackground);
     }
-    
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -367,35 +425,57 @@
         if (mAlert.onKeyUp(keyCode, event)) return true;
         return super.onKeyUp(keyCode, event);
     }
-    
+
     public static class Builder {
         private final AlertController.AlertParams P;
-        private int mTheme;
-        
+        private int mThemeResId;
+
         /**
-         * Constructor using a context for this builder and the {@link AlertDialog} it creates.
+         * Creates a builder for an alert dialog that uses the default alert
+         * dialog theme.
+         * <p>
+         * The default alert dialog theme is defined by
+         * {@link android.R.attr#alertDialogTheme} within the parent
+         * {@code context}'s theme.
+         *
+         * @param context the parent context
          */
         public Builder(Context context) {
             this(context, resolveDialogTheme(context, 0));
         }
 
         /**
-         * Constructor using a context and theme for this builder and
-         * the {@link AlertDialog} it creates.  The actual theme
-         * that an AlertDialog uses is a private implementation, however you can
-         * here supply either the name of an attribute in the theme from which
-         * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
-         * or one of the constants
-         * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL},
-         * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or
-         * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}.
+         * Creates a builder for an alert dialog that uses an explicit theme
+         * resource.
+         * <p>
+         * The specified theme resource ({@code themeResId}) is applied on top
+         * of the parent {@code context}'s theme. It may be specified as a
+         * style resource containing a fully-populated theme, such as
+         * {@link android.R.style#Theme_Material_Dialog}, to replace all
+         * attributes in the parent {@code context}'s theme including primary
+         * and accent colors.
+         * <p>
+         * To preserve attributes such as primary and accent colors, the
+         * {@code themeResId} may instead be specified as an overlay theme such
+         * as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will
+         * override only the window attributes necessary to style the alert
+         * window as a dialog.
+         * <p>
+         * Alternatively, the {@code themeResId} may be specified as {@code 0}
+         * to use the parent {@code context}'s resolved value for
+         * {@link android.R.attr#alertDialogTheme}.
+         *
+         * @param context the parent context
+         * @param themeResId the resource ID of the theme against which to inflate
+         *                   this dialog, or {@code 0} to use the parent
+         *                   {@code context}'s default alert dialog theme
          */
-        public Builder(Context context, int theme) {
+        public Builder(Context context, int themeResId) {
             P = new AlertController.AlertParams(new ContextThemeWrapper(
-                    context, resolveDialogTheme(context, theme)));
-            mTheme = theme;
+                    context, resolveDialogTheme(context, themeResId)));
+            mThemeResId = themeResId;
         }
-        
+
         /**
          * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
          * Applications should use this Context for obtaining LayoutInflaters for inflating views
@@ -413,11 +493,11 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setTitle(int titleId) {
+        public Builder setTitle(@StringRes int titleId) {
             P.mTitle = P.mContext.getText(titleId);
             return this;
         }
-        
+
         /**
          * Set the title displayed in the {@link Dialog}.
          *
@@ -427,33 +507,38 @@
             P.mTitle = title;
             return this;
         }
-        
+
         /**
-         * Set the title using the custom view {@code customTitleView}. The
-         * methods {@link #setTitle(int)} and {@link #setIcon(int)} should be
-         * sufficient for most titles, but this is provided if the title needs
-         * more customization. Using this will replace the title and icon set
-         * via the other methods.
-         * 
-         * @param customTitleView The custom view to use as the title.
+         * Set the title using the custom view {@code customTitleView}.
+         * <p>
+         * The methods {@link #setTitle(int)} and {@link #setIcon(int)} should
+         * be sufficient for most titles, but this is provided if the title
+         * needs more customization. Using this will replace the title and icon
+         * set via the other methods.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param customTitleView the custom view to use as the title
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setCustomTitle(View customTitleView) {
             P.mCustomTitleView = customTitleView;
             return this;
         }
-        
+
         /**
          * Set the message to display using the given resource id.
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMessage(int messageId) {
+        public Builder setMessage(@StringRes int messageId) {
             P.mMessage = P.mContext.getText(messageId);
             return this;
         }
-        
+
         /**
          * Set the message to display.
           *
@@ -463,7 +548,7 @@
             P.mMessage = message;
             return this;
         }
-        
+
         /**
          * Set the resource id of the {@link Drawable} to be used in the title.
          * <p>
@@ -471,15 +556,20 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setIcon(int iconId) {
+        public Builder setIcon(@DrawableRes int iconId) {
             P.mIconId = iconId;
             return this;
         }
-        
+
         /**
          * Set the {@link Drawable} to be used in the title.
-          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the drawable
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
+         *
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setIcon(Drawable icon) {
             P.mIcon = icon;
@@ -495,7 +585,7 @@
          *
          * @param attrId ID of a theme attribute that points to a drawable resource.
          */
-        public Builder setIconAttribute(int attrId) {
+        public Builder setIconAttribute(@AttrRes int attrId) {
             TypedValue out = new TypedValue();
             P.mContext.getTheme().resolveAttribute(attrId, out, true);
             P.mIconId = out.resourceId;
@@ -509,12 +599,12 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setPositiveButton(int textId, final OnClickListener listener) {
+        public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
             P.mPositiveButtonText = P.mContext.getText(textId);
             P.mPositiveButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the positive button of the dialog is pressed.
          * @param text The text to display in the positive button
@@ -527,7 +617,7 @@
             P.mPositiveButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param textId The resource id of the text to display in the negative button
@@ -535,12 +625,12 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setNegativeButton(int textId, final OnClickListener listener) {
+        public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
             P.mNegativeButtonText = P.mContext.getText(textId);
             P.mNegativeButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param text The text to display in the negative button
@@ -553,7 +643,7 @@
             P.mNegativeButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param textId The resource id of the text to display in the neutral button
@@ -561,12 +651,12 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setNeutralButton(int textId, final OnClickListener listener) {
+        public Builder setNeutralButton(@StringRes int textId, final OnClickListener listener) {
             P.mNeutralButtonText = P.mContext.getText(textId);
             P.mNeutralButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param text The text to display in the neutral button
@@ -579,7 +669,7 @@
             P.mNeutralButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Sets whether the dialog is cancelable or not.  Default is true.
          *
@@ -589,7 +679,7 @@
             P.mCancelable = cancelable;
             return this;
         }
-        
+
         /**
          * Sets the callback that will be called if the dialog is canceled.
          *
@@ -607,7 +697,7 @@
             P.mOnCancelListener = onCancelListener;
             return this;
         }
-        
+
         /**
          * Sets the callback that will be called when the dialog is dismissed for any reason.
          *
@@ -627,19 +717,19 @@
             P.mOnKeyListener = onKeyListener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener. This should be an array type i.e. R.array.foo
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setItems(int itemsId, final OnClickListener listener) {
+        public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) {
             P.mItems = P.mContext.getResources().getTextArray(itemsId);
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
@@ -651,12 +741,12 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items, which are supplied by the given {@link ListAdapter}, to be
          * displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
-         * 
+         *
          * @param adapter The {@link ListAdapter} to supply the list of items
          * @param listener The listener that will be called when an item is clicked.
          *
@@ -667,12 +757,12 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items, which are supplied by the given {@link Cursor}, to be
          * displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
-         * 
+         *
          * @param cursor The {@link Cursor} to supply the list of items
          * @param listener The listener that will be called when an item is clicked.
          * @param labelColumn The column name on the cursor containing the string to display
@@ -687,7 +777,7 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
@@ -695,7 +785,7 @@
          * a check mark displayed to the right of the text for each checked
          * item. Clicking on an item in the list will not dismiss the dialog.
          * Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param itemsId the resource id of an array i.e. R.array.foo
          * @param checkedItems specifies which items are checked. It should be null in which case no
          *        items are checked. If non null it must be exactly the same length as the array of
@@ -706,7 +796,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, 
+        public Builder setMultiChoiceItems(@ArrayRes int itemsId, boolean[] checkedItems,
                 final OnMultiChoiceClickListener listener) {
             P.mItems = P.mContext.getResources().getTextArray(itemsId);
             P.mOnCheckboxClickListener = listener;
@@ -714,14 +804,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
          * The list will have a check mark displayed to the right of the text
          * for each checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param items the text of the items to be displayed in the list.
          * @param checkedItems specifies which items are checked. It should be null in which case no
          *        items are checked. If non null it must be exactly the same length as the array of
@@ -732,7 +822,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, 
+        public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
                 final OnMultiChoiceClickListener listener) {
             P.mItems = items;
             P.mOnCheckboxClickListener = listener;
@@ -740,14 +830,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
          * The list will have a check mark displayed to the right of the text
          * for each checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param cursor the cursor used to provide the items.
          * @param isCheckedColumn specifies the column name on the cursor to use to determine
          *        whether a checkbox is checked or not. It must return an integer value where 1
@@ -760,7 +850,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, 
+        public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
                 final OnMultiChoiceClickListener listener) {
             P.mCursor = cursor;
             P.mOnCheckboxClickListener = listener;
@@ -769,14 +859,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. This should be an array type i.e.
          * R.array.foo The list will have a check mark displayed to the right of the text for the
          * checked item. Clicking on an item in the list will not dismiss the dialog. Clicking on a
          * button will dismiss the dialog.
-         * 
+         *
          * @param itemsId the resource id of an array i.e. R.array.foo
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -785,7 +875,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setSingleChoiceItems(int itemsId, int checkedItem, 
+        public Builder setSingleChoiceItems(@ArrayRes int itemsId, int checkedItem,
                 final OnClickListener listener) {
             P.mItems = P.mContext.getResources().getTextArray(itemsId);
             P.mOnClickListener = listener;
@@ -793,13 +883,13 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param cursor the cursor to retrieve the items from.
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param labelColumn The column name on the cursor containing the string to display in the
@@ -810,7 +900,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, 
+        public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
                 final OnClickListener listener) {
             P.mCursor = cursor;
             P.mOnClickListener = listener;
@@ -819,13 +909,13 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param items the items to be displayed.
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -840,14 +930,14 @@
             P.mCheckedItem = checkedItem;
             P.mIsSingleChoice = true;
             return this;
-        } 
-        
+        }
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param adapter The {@link ListAdapter} to supply the list of items
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -863,26 +953,25 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Sets a listener to be invoked when an item in the list is selected.
-         * 
-         * @param listener The listener to be invoked.
-         * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param listener the listener to be invoked
+         * @return this Builder object to allow for chaining of calls to set methods
+         * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
          */
         public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
             P.mOnItemSelectedListener = listener;
             return this;
         }
-        
+
         /**
          * Set a custom view resource to be the contents of the Dialog. The
          * resource will be inflated, adding all top-level views to the screen.
          *
          * @param layoutResId Resource ID to be inflated.
-         * @return This Builder object to allow for chaining of calls to set
+         * @return this Builder object to allow for chaining of calls to set
          *         methods
          */
         public Builder setView(int layoutResId) {
@@ -893,12 +982,18 @@
         }
 
         /**
-         * Set a custom view to be the contents of the Dialog. If the supplied view is an instance
-         * of a {@link ListView} the light background will be used.
+         * Sets a custom view to be the contents of the alert dialog.
+         * <p>
+         * When using a pre-Holo theme, if the supplied view is an instance of
+         * a {@link ListView} then the light background will be used.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
          *
-         * @param view The view to use as the contents of the Dialog.
-         * 
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param view the view to use as the contents of the alert dialog
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setView(View view) {
             P.mView = view;
@@ -906,29 +1001,34 @@
             P.mViewSpacingSpecified = false;
             return this;
         }
-        
+
         /**
-         * Set a custom view to be the contents of the Dialog, specifying the
-         * spacing to appear around that view. If the supplied view is an
-         * instance of a {@link ListView} the light background will be used.
-         * 
-         * @param view The view to use as the contents of the Dialog.
-         * @param viewSpacingLeft Spacing between the left edge of the view and
-         *        the dialog frame
-         * @param viewSpacingTop Spacing between the top edge of the view and
-         *        the dialog frame
-         * @param viewSpacingRight Spacing between the right edge of the view
-         *        and the dialog frame
-         * @param viewSpacingBottom Spacing between the bottom edge of the view
-         *        and the dialog frame
-         * @return This Builder object to allow for chaining of calls to set
+         * Sets a custom view to be the contents of the alert dialog and
+         * specifies additional padding around that view.
+         * <p>
+         * When using a pre-Holo theme, if the supplied view is an instance of
+         * a {@link ListView} then the light background will be used.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
+         *
+         * @param view the view to use as the contents of the alert dialog
+         * @param viewSpacingLeft spacing between the left edge of the view and
+         *                        the dialog frame
+         * @param viewSpacingTop spacing between the top edge of the view and
+         *                       the dialog frame
+         * @param viewSpacingRight spacing between the right edge of the view
+         *                         and the dialog frame
+         * @param viewSpacingBottom spacing between the bottom edge of the view
+         *                          and the dialog frame
+         * @return this Builder object to allow for chaining of calls to set
          *         methods
-         *         
-         * 
-         * This is currently hidden because it seems like people should just
-         * be able to put padding around the view.
-         * @hide
+         *
+         * @hide Remove once the framework usages have been replaced.
+         * @deprecated Set the padding on the view itself.
          */
+        @Deprecated
         public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop,
                 int viewSpacingRight, int viewSpacingBottom) {
             P.mView = view;
@@ -940,15 +1040,18 @@
             P.mViewSpacingBottom = viewSpacingBottom;
             return this;
         }
-        
+
         /**
-         * Sets the Dialog to use the inverse background, regardless of what the
-         * contents is.
-         * 
-         * @param useInverseBackground Whether to use the inverse background
-         * 
-         * @return This Builder object to allow for chaining of calls to set methods
+         * Sets the alert dialog to use the inverse background, regardless of
+         * what the contents is.
+         *
+         * @param useInverseBackground whether to use the inverse background
+         * @return this Builder object to allow for chaining of calls to set methods
+         * @deprecated This flag is only used for pre-Material themes. Instead,
+         *             specify the window background using on the alert dialog
+         *             theme.
          */
+        @Deprecated
         public Builder setInverseBackgroundForced(boolean useInverseBackground) {
             P.mForceInverseBackground = useInverseBackground;
             return this;
@@ -964,13 +1067,15 @@
 
 
         /**
-         * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not
-         * {@link Dialog#show()} the dialog. This allows the user to do any extra processing
-         * before displaying the dialog. Use {@link #show()} if you don't have any other processing
-         * to do and want this to be created and displayed.
+         * Creates an {@link AlertDialog} with the arguments supplied to this
+         * builder.
+         * <p>
+         * Calling this method does not display the dialog. If no additional
+         * processing is needed, {@link #show()} may be called instead to both
+         * create and display the dialog.
          */
         public AlertDialog create() {
-            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
+            final AlertDialog dialog = new AlertDialog(P.mContext, mThemeResId);
             P.apply(dialog.mAlert);
             dialog.setCancelable(P.mCancelable);
             if (P.mCancelable) {
@@ -985,14 +1090,20 @@
         }
 
         /**
-         * Creates a {@link AlertDialog} with the arguments supplied to this builder and
-         * {@link Dialog#show()}'s the dialog.
+         * Creates an {@link AlertDialog} with the arguments supplied to this
+         * builder and immediately displays the dialog.
+         * <p>
+         * Calling this method is functionally identical to:
+         * <pre>
+         *     AlertDialog dialog = builder.create();
+         *     dialog.show();
+         * </pre>
          */
         public AlertDialog show() {
-            AlertDialog dialog = create();
+            final AlertDialog dialog = create();
             dialog.show();
             return dialog;
         }
     }
-    
+
 }
diff --git a/core/java/android/app/AppImportanceMonitor.java b/core/java/android/app/AppImportanceMonitor.java
index c760e1e..e0d0d8d 100644
--- a/core/java/android/app/AppImportanceMonitor.java
+++ b/core/java/android/app/AppImportanceMonitor.java
@@ -22,8 +22,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
-
 import java.util.List;
 
 /**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 95870cf..4bd2332 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -206,8 +206,10 @@
     public static final int OP_PROJECT_MEDIA = 46;
     /** @hide Activate a VPN connection without user intervention. */
     public static final int OP_ACTIVATE_VPN = 47;
+    /** @hide Access the WallpaperManagerAPI to write wallpapers. */
+    public static final int OP_WRITE_WALLPAPER = 48;
     /** @hide */
-    public static final int _NUM_OP = 48;
+    public static final int _NUM_OP = 49;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -285,6 +287,7 @@
             OP_TOAST_WINDOW,
             OP_PROJECT_MEDIA,
             OP_ACTIVATE_VPN,
+            OP_WRITE_WALLPAPER,
     };
 
     /**
@@ -340,6 +343,7 @@
             null,
             null,
             OPSTR_ACTIVATE_VPN,
+            null,
     };
 
     /**
@@ -395,6 +399,7 @@
             "TOAST_WINDOW",
             "PROJECT_MEDIA",
             "ACTIVATE_VPN",
+            "WRITE_WALLPAPER",
     };
 
     /**
@@ -450,6 +455,7 @@
             null, // no permission for displaying toasts
             null, // no permission for projecting media
             null, // no permission for activating vpn
+            null, // no permission for supporting wallpaper
     };
 
     /**
@@ -506,6 +512,7 @@
             UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
             null, //PROJECT_MEDIA
             UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
+            UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
     };
 
     /**
@@ -561,6 +568,7 @@
             true, //TOAST_WINDOW
             false, //PROJECT_MEDIA
             false, //ACTIVATE_VPN
+            false, //WALLPAPER
     };
 
     /**
@@ -615,6 +623,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
             AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -673,6 +682,7 @@
             false,
             false,
             false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 967e97e..f35e746 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
+import android.annotation.XmlRes;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Intent;
@@ -63,6 +66,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
+import android.os.SystemProperties;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -287,7 +291,12 @@
         // depending on what the current runtime's instruction set is.
         if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
             final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
-            final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+            // Get the instruction set that the libraries of secondary Abi is supported.
+            // In presence of a native bridge this might be different than the one secondary Abi used.
+            String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+            final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+            secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
 
             // If the runtimeIsa is the same as the primary isa, then we do nothing.
             // Everything will be set up correctly because info.nativeLibraryDir will
@@ -724,7 +733,7 @@
         }
     }
 
-    @Override public Drawable getDrawable(String packageName, int resid,
+    @Override public Drawable getDrawable(String packageName, @DrawableRes int resid,
                                           ApplicationInfo appInfo) {
         ResourceName name = new ResourceName(packageName, resid);
         Drawable dr = getCachedIcon(name);
@@ -1131,7 +1140,7 @@
     }
 
     @Override
-    public CharSequence getText(String packageName, int resid,
+    public CharSequence getText(String packageName, @StringRes int resid,
                                 ApplicationInfo appInfo) {
         ResourceName name = new ResourceName(packageName, resid);
         CharSequence text = getCachedString(name);
@@ -1164,7 +1173,7 @@
     }
 
     @Override
-    public XmlResourceParser getXml(String packageName, int resid,
+    public XmlResourceParser getXml(String packageName, @XmlRes int resid,
                                     ApplicationInfo appInfo) {
         if (appInfo == null) {
             try {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index d1b77b9..b6989ab 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -140,6 +140,10 @@
             int ident = data.readInt();
             ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
             Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
+            Configuration overrideConfig = null;
+            if (data.readInt() != 0) {
+                overrideConfig = Configuration.CREATOR.createFromParcel(data);
+            }
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
             String referrer = data.readString();
             IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
@@ -153,8 +157,8 @@
             boolean isForward = data.readInt() != 0;
             ProfilerInfo profilerInfo = data.readInt() != 0
                     ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
-            scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, referrer,
-                    voiceInteractor, procState, state, persistentState, ri, pi,
+            scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
+                    referrer, voiceInteractor, procState, state, persistentState, ri, pi,
                     notResumed, isForward, profilerInfo);
             return true;
         }
@@ -167,14 +171,15 @@
             List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
             int configChanges = data.readInt();
             boolean notResumed = data.readInt() != 0;
-            Configuration config = null;
+            Configuration config = Configuration.CREATOR.createFromParcel(data);
+            Configuration overrideConfig = null;
             if (data.readInt() != 0) {
-                config = Configuration.CREATOR.createFromParcel(data);
+                overrideConfig = Configuration.CREATOR.createFromParcel(data);
             }
-            scheduleRelaunchActivity(b, ri, pi, configChanges, notResumed, config);
+            scheduleRelaunchActivity(b, ri, pi, configChanges, notResumed, config, overrideConfig);
             return true;
         }
-        
+
         case SCHEDULE_NEW_INTENT_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -404,7 +409,11 @@
         {
             data.enforceInterface(IApplicationThread.descriptor);
             IBinder b = data.readStrongBinder();
-            scheduleActivityConfigurationChanged(b);
+            Configuration overrideConfig = null;
+            if (data.readInt() != 0) {
+                overrideConfig = Configuration.CREATOR.createFromParcel(data);
+            }
+            scheduleActivityConfigurationChanged(b, overrideConfig);
             return true;
         }
 
@@ -670,6 +679,15 @@
             reply.writeNoException();
             return true;
         }
+
+        case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            final byte[] firstPacket = data.createByteArray();
+            notifyCleartextNetwork(firstPacket);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -766,11 +784,11 @@
     }
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
-            PersistableBundle persistentState, List<ResultInfo> pendingResults,
-            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
-            ProfilerInfo profilerInfo) throws RemoteException {
+            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
+            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
+            int procState, Bundle state, PersistableBundle persistentState,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         intent.writeToParcel(data, 0);
@@ -778,6 +796,12 @@
         data.writeInt(ident);
         info.writeToParcel(data, 0);
         curConfig.writeToParcel(data, 0);
+        if (overrideConfig != null) {
+            data.writeInt(1);
+            overrideConfig.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
         compatInfo.writeToParcel(data, 0);
         data.writeString(referrer);
         data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
@@ -801,8 +825,8 @@
 
     public final void scheduleRelaunchActivity(IBinder token,
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, boolean notResumed, Configuration config)
-            throws RemoteException {
+            int configChanges, boolean notResumed, Configuration config,
+            Configuration overrideConfig) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
@@ -810,9 +834,10 @@
         data.writeTypedList(pendingNewIntents);
         data.writeInt(configChanges);
         data.writeInt(notResumed ? 1 : 0);
-        if (config != null) {
+        config.writeToParcel(data, 0);
+        if (overrideConfig != null) {
             data.writeInt(1);
-            config.writeToParcel(data, 0);
+            overrideConfig.writeToParcel(data, 0);
         } else {
             data.writeInt(0);
         }
@@ -1095,6 +1120,7 @@
         data.recycle();
     }
 
+    @Override
     public final void scheduleLowMemory() throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1103,16 +1129,24 @@
         data.recycle();
     }
 
+    @Override
     public final void scheduleActivityConfigurationChanged(
-            IBinder token) throws RemoteException {
+            IBinder token, Configuration overrideConfig) throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeStrongBinder(token);
+        if (overrideConfig != null) {
+            data.writeInt(1);
+            overrideConfig.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
         mRemote.transact(SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
 
+    @Override
     public void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -1350,4 +1384,13 @@
         mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
         data.recycle();
     }
+
+    @Override
+    public void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeByteArray(firstPacket);
+        mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
 }
diff --git a/core/java/android/app/AssistContent.aidl b/core/java/android/app/AssistContent.aidl
new file mode 100644
index 0000000..a6321bf
--- /dev/null
+++ b/core/java/android/app/AssistContent.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable AssistContent;
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
new file mode 100644
index 0000000..ace4af7
--- /dev/null
+++ b/core/java/android/app/AssistContent.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.ClipData;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Holds information about the content an application is viewing, to hand to an
+ * assistant at the user's request.  This is filled in by
+ * {@link Activity#onProvideAssistContent Activity.onProvideAssistContent}.
+ */
+public class AssistContent implements Parcelable {
+    private Intent mIntent;
+    private ClipData mClipData;
+
+    /**
+     * Key name this data structure is stored in the Bundle generated by
+     * {@link Activity#onProvideAssistData}.
+     */
+    public static final String ASSIST_KEY = "android:assist_content";
+
+    /**
+     * Retrieve the framework-generated AssistContent that is stored within
+     * the Bundle filled in by {@link Activity#onProvideAssistContent}.
+     */
+    public static AssistContent getAssistContent(Bundle assistBundle) {
+        return assistBundle.getParcelable(ASSIST_KEY);
+    }
+
+    public AssistContent() {
+    }
+
+    /**
+     * Sets the Intent associated with the content, describing the current top-level context of
+     * the activity.  If this contains a reference to a piece of data related to the activity,
+     * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibilty
+     * service can access it.
+     */
+    public void setIntent(Intent intent) {
+        mIntent = intent;
+    }
+
+    /**
+     * Return the current {@link #setIntent}, which you can modify in-place.
+     */
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /**
+     * Optional additional content items that are involved with
+     * the current UI.  Access to this content will be granted to the assistant as if you
+     * are sending it through an Intent with {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+     */
+    public void setClipData(ClipData clip) {
+        mClipData = clip;
+    }
+
+    /**
+     * Return the current {@link #setClipData}, which you can modify in-place.
+     */
+    public ClipData getClipData() {
+        return mClipData;
+    }
+
+    AssistContent(Parcel in) {
+        if (in.readInt() != 0) {
+            mIntent = Intent.CREATOR.createFromParcel(in);
+        }
+        if (in.readInt() != 0) {
+            mClipData = ClipData.CREATOR.createFromParcel(in);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mIntent != null) {
+            dest.writeInt(1);
+            mIntent.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+        if (mClipData != null) {
+            dest.writeInt(1);
+            mClipData.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    public static final Parcelable.Creator<AssistContent> CREATOR
+            = new Parcelable.Creator<AssistContent>() {
+        public AssistContent createFromParcel(Parcel in) {
+            return new AssistContent(in);
+        }
+
+        public AssistContent[] newArray(int size) {
+            return new AssistContent[size];
+        }
+    };
+}
diff --git a/core/java/android/app/AssistStructure.aidl b/core/java/android/app/AssistStructure.aidl
new file mode 100644
index 0000000..07fb2453
--- /dev/null
+++ b/core/java/android/app/AssistStructure.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable AssistStructure;
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
new file mode 100644
index 0000000..25153fc
--- /dev/null
+++ b/core/java/android/app/AssistStructure.java
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.ComponentName;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PooledStringReader;
+import android.os.PooledStringWriter;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAssistStructure;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+import android.widget.Checkable;
+
+import java.util.ArrayList;
+
+/**
+ * Assist data automatically created by the platform's implementation
+ * of {@link Activity#onProvideAssistData}.  Retrieve it from the assist
+ * data with {@link #getAssistStructure(android.os.Bundle)}.
+ */
+final public class AssistStructure implements Parcelable {
+    static final String TAG = "AssistStructure";
+
+    /**
+     * Key name this data structure is stored in the Bundle generated by
+     * {@link Activity#onProvideAssistData}.
+     */
+    public static final String ASSIST_KEY = "android:assist_structure";
+
+    final ComponentName mActivityComponent;
+
+    final ArrayList<ViewNodeImpl> mRootViews = new ArrayList<>();
+
+    ViewAssistStructureImpl mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
+    Bundle mTmpExtras = new Bundle();
+
+    final static class ViewAssistStructureImpl extends ViewAssistStructure {
+        CharSequence mText;
+        int mTextSelectionStart = -1;
+        int mTextSelectionEnd = -1;
+        int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        float mTextSize = 0;
+        int mTextStyle = 0;
+        CharSequence mHint;
+
+        @Override
+        public void setText(CharSequence text) {
+            mText = text;
+            mTextSelectionStart = mTextSelectionEnd = -1;
+        }
+
+        @Override
+        public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+            mText = text;
+            mTextSelectionStart = selectionStart;
+            mTextSelectionEnd = selectionEnd;
+        }
+
+        @Override
+        public void setTextPaint(TextPaint paint) {
+            mTextColor = paint.getColor();
+            mTextBackgroundColor = paint.bgColor;
+            mTextSize = paint.getTextSize();
+            mTextStyle = 0;
+            Typeface tf = paint.getTypeface();
+            if (tf != null) {
+                if (tf.isBold()) {
+                    mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+                }
+                if (tf.isItalic()) {
+                    mTextStyle |= ViewNode.TEXT_STYLE_ITALIC;
+                }
+            }
+            int pflags = paint.getFlags();
+            if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+                mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+            }
+            if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) {
+                mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE;
+            }
+            if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+                mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU;
+            }
+        }
+
+        @Override
+        public void setHint(CharSequence hint) {
+            mHint = hint;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mText;
+        }
+
+        @Override
+        public int getTextSelectionStart() {
+            return mTextSelectionStart;
+        }
+
+        @Override
+        public int getTextSelectionEnd() {
+            return mTextSelectionEnd;
+        }
+
+        @Override
+        public CharSequence getHint() {
+            return mHint;
+        }
+    }
+
+    final static class ViewNodeTextImpl {
+        final CharSequence mText;
+        final int mTextSelectionStart;
+        final int mTextSelectionEnd;
+        int mTextColor;
+        int mTextBackgroundColor;
+        float mTextSize;
+        int mTextStyle;
+        final String mHint;
+
+        ViewNodeTextImpl(ViewAssistStructureImpl data) {
+            mText = data.mText;
+            mTextSelectionStart = data.mTextSelectionStart;
+            mTextSelectionEnd = data.mTextSelectionEnd;
+            mTextColor = data.mTextColor;
+            mTextBackgroundColor = data.mTextBackgroundColor;
+            mTextSize = data.mTextSize;
+            mTextStyle = data.mTextStyle;
+            mHint = data.mHint != null ? data.mHint.toString() : null;
+        }
+
+        ViewNodeTextImpl(Parcel in) {
+            mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mTextSelectionStart = in.readInt();
+            mTextSelectionEnd = in.readInt();
+            mTextColor = in.readInt();
+            mTextBackgroundColor = in.readInt();
+            mTextSize = in.readFloat();
+            mTextStyle = in.readInt();
+            mHint = in.readString();
+        }
+
+        void writeToParcel(Parcel out) {
+            TextUtils.writeToParcel(mText, out, 0);
+            out.writeInt(mTextSelectionStart);
+            out.writeInt(mTextSelectionEnd);
+            out.writeInt(mTextColor);
+            out.writeInt(mTextBackgroundColor);
+            out.writeFloat(mTextSize);
+            out.writeInt(mTextStyle);
+            out.writeString(mHint);
+        }
+    }
+
+    final static class ViewNodeImpl {
+        final int mX;
+        final int mY;
+        final int mScrollX;
+        final int mScrollY;
+        final int mWidth;
+        final int mHeight;
+
+        static final int FLAGS_DISABLED = 0x00000001;
+        static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
+        static final int FLAGS_FOCUSABLE = 0x00000010;
+        static final int FLAGS_FOCUSED = 0x00000020;
+        static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
+        static final int FLAGS_SELECTED = 0x00000040;
+        static final int FLAGS_ACTIVATED = 0x40000000;
+        static final int FLAGS_CHECKABLE = 0x00000100;
+        static final int FLAGS_CHECKED = 0x00000200;
+        static final int FLAGS_CLICKABLE = 0x00004000;
+        static final int FLAGS_LONG_CLICKABLE = 0x00200000;
+
+        final int mFlags;
+
+        final String mClassName;
+        final String mContentDescription;
+
+        final ViewNodeTextImpl mText;
+        final Bundle mExtras;
+
+        final ViewNodeImpl[] mChildren;
+
+        ViewNodeImpl(AssistStructure assistStructure, View view, int left, int top,
+                CharSequence contentDescription) {
+            mX = left;
+            mY = top;
+            mScrollX = view.getScrollX();
+            mScrollY = view.getScrollY();
+            mWidth = view.getWidth();
+            mHeight = view.getHeight();
+            int flags = view.getVisibility();
+            if (!view.isEnabled()) {
+                flags |= FLAGS_DISABLED;
+            }
+            if (!view.isClickable()) {
+                flags |= FLAGS_CLICKABLE;
+            }
+            if (!view.isFocusable()) {
+                flags |= FLAGS_FOCUSABLE;
+            }
+            if (!view.isFocused()) {
+                flags |= FLAGS_FOCUSED;
+            }
+            if (!view.isAccessibilityFocused()) {
+                flags |= FLAGS_ACCESSIBILITY_FOCUSED;
+            }
+            if (!view.isSelected()) {
+                flags |= FLAGS_SELECTED;
+            }
+            if (!view.isActivated()) {
+                flags |= FLAGS_ACTIVATED;
+            }
+            if (!view.isLongClickable()) {
+                flags |= FLAGS_LONG_CLICKABLE;
+            }
+            if (view instanceof Checkable) {
+                flags |= FLAGS_CHECKABLE;
+                if (((Checkable)view).isChecked()) {
+                    flags |= FLAGS_CHECKED;
+                }
+            }
+            mFlags = flags;
+            mClassName = view.getAccessibilityClassName().toString();
+            mContentDescription = contentDescription != null ? contentDescription.toString() : null;
+            final ViewAssistStructureImpl viewData = assistStructure.mTmpViewAssistStructureImpl;
+            final Bundle extras = assistStructure.mTmpExtras;
+            view.onProvideAssistStructure(viewData, extras);
+            if (viewData.mText != null || viewData.mHint != null) {
+                mText = new ViewNodeTextImpl(viewData);
+                assistStructure.mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
+            } else {
+                mText = null;
+            }
+            if (!extras.isEmpty()) {
+                mExtras = extras;
+                assistStructure.mTmpExtras = new Bundle();
+            } else {
+                mExtras = null;
+            }
+            if (view instanceof ViewGroup) {
+                ViewGroup vg = (ViewGroup)view;
+                final int NCHILDREN = vg.getChildCount();
+                if (NCHILDREN > 0) {
+                    mChildren = new ViewNodeImpl[NCHILDREN];
+                    for (int i=0; i<NCHILDREN; i++) {
+                        mChildren[i] = new ViewNodeImpl(assistStructure, vg.getChildAt(i));
+                    }
+                } else {
+                    mChildren = null;
+                }
+            } else {
+                mChildren = null;
+            }
+        }
+
+        ViewNodeImpl(AssistStructure assistStructure, View view) {
+            this(assistStructure, view, view.getLeft(), view.getTop(), view.getContentDescription());
+        }
+
+        ViewNodeImpl(Parcel in, PooledStringReader preader) {
+            mX = in.readInt();
+            mY = in.readInt();
+            mScrollX = in.readInt();
+            mScrollY = in.readInt();
+            mWidth = in.readInt();
+            mHeight = in.readInt();
+            mFlags = in.readInt();
+            mClassName = preader.readString();
+            mContentDescription = in.readString();
+            if (in.readInt() != 0) {
+                mText = new ViewNodeTextImpl(in);
+            } else {
+                mText = null;
+            }
+            mExtras = in.readBundle();
+            final int NCHILDREN = in.readInt();
+            if (NCHILDREN > 0) {
+                mChildren = new ViewNodeImpl[NCHILDREN];
+                for (int i=0; i<NCHILDREN; i++) {
+                    mChildren[i] = new ViewNodeImpl(in, preader);
+                }
+            } else {
+                mChildren = null;
+            }
+        }
+
+        void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+            out.writeInt(mX);
+            out.writeInt(mY);
+            out.writeInt(mScrollX);
+            out.writeInt(mScrollY);
+            out.writeInt(mWidth);
+            out.writeInt(mHeight);
+            out.writeInt(mFlags);
+            pwriter.writeString(mClassName);
+            out.writeString(mContentDescription);
+            if (mText != null) {
+                out.writeInt(1);
+                mText.writeToParcel(out);
+            } else {
+                out.writeInt(0);
+            }
+            out.writeBundle(mExtras);
+            if (mChildren != null) {
+                final int NCHILDREN = mChildren.length;
+                out.writeInt(NCHILDREN);
+                for (int i=0; i<NCHILDREN; i++) {
+                    mChildren[i].writeToParcel(out, pwriter);
+                }
+            } else {
+                out.writeInt(0);
+            }
+        }
+    }
+
+    /**
+     * Provides access to information about a single view in the assist data.
+     */
+    static public class ViewNode {
+        /**
+         * Magic value for text color that has not been defined, which is very unlikely
+         * to be confused with a real text color.
+         */
+        public static final int TEXT_COLOR_UNDEFINED = 1;
+
+        public static final int TEXT_STYLE_BOLD = 1<<0;
+        public static final int TEXT_STYLE_ITALIC = 1<<1;
+        public static final int TEXT_STYLE_UNDERLINE = 1<<2;
+        public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
+
+        ViewNodeImpl mImpl;
+
+        public ViewNode() {
+        }
+
+        public int getLeft() {
+            return mImpl.mX;
+        }
+
+        public int getTop() {
+            return mImpl.mY;
+        }
+
+        public int getScrollX() {
+            return mImpl.mScrollX;
+        }
+
+        public int getScrollY() {
+            return mImpl.mScrollY;
+        }
+
+        public int getWidth() {
+            return mImpl.mWidth;
+        }
+
+        public int getHeight() {
+            return mImpl.mHeight;
+        }
+
+        public int getVisibility() {
+            return mImpl.mFlags&ViewNodeImpl.FLAGS_VISIBILITY_MASK;
+        }
+
+        public boolean isEnabled() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_DISABLED) == 0;
+        }
+
+        public boolean isClickable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CLICKABLE) != 0;
+        }
+
+        public boolean isFocusable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSABLE) != 0;
+        }
+
+        public boolean isFocused() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSED) != 0;
+        }
+
+        public boolean isAccessibilityFocused() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+        }
+
+        public boolean isCheckable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKABLE) != 0;
+        }
+
+        public boolean isChecked() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKED) != 0;
+        }
+
+        public boolean isSelected() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_SELECTED) != 0;
+        }
+
+        public boolean isActivated() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACTIVATED) != 0;
+        }
+
+        public boolean isLongClickable() {
+            return (mImpl.mFlags&ViewNodeImpl.FLAGS_LONG_CLICKABLE) != 0;
+        }
+
+        public String getClassName() {
+            return mImpl.mClassName;
+        }
+
+        public String getContentDescription() {
+            return mImpl.mContentDescription;
+        }
+
+        public CharSequence getText() {
+            return mImpl.mText != null ? mImpl.mText.mText : null;
+        }
+
+        public int getTextSelectionStart() {
+            return mImpl.mText != null ? mImpl.mText.mTextSelectionStart : -1;
+        }
+
+        public int getTextSelectionEnd() {
+            return mImpl.mText != null ? mImpl.mText.mTextSelectionEnd : -1;
+        }
+
+        public int getTextColor() {
+            return mImpl.mText != null ? mImpl.mText.mTextColor : TEXT_COLOR_UNDEFINED;
+        }
+
+        public int getTextBackgroundColor() {
+            return mImpl.mText != null ? mImpl.mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+        }
+
+        public float getTextSize() {
+            return mImpl.mText != null ? mImpl.mText.mTextSize : 0;
+        }
+
+        public int getTextStyle() {
+            return mImpl.mText != null ? mImpl.mText.mTextStyle : 0;
+        }
+
+        public String getHint() {
+            return mImpl.mText != null ? mImpl.mText.mHint : null;
+        }
+
+        public Bundle getExtras() {
+            return mImpl.mExtras;
+        }
+
+        public int getChildCount() {
+            return mImpl.mChildren != null ? mImpl.mChildren.length : 0;
+        }
+
+        public void getChildAt(int index, ViewNode outNode) {
+            outNode.mImpl = mImpl.mChildren[index];
+        }
+    }
+
+    AssistStructure(Activity activity) {
+        mActivityComponent = activity.getComponentName();
+        ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
+                activity.getActivityToken());
+        for (int i=0; i<views.size(); i++) {
+            ViewRootImpl root = views.get(i);
+            View view = root.getView();
+            Rect rect = new Rect();
+            view.getBoundsOnScreen(rect);
+            CharSequence title = root.getTitle();
+            mRootViews.add(new ViewNodeImpl(this, view, rect.left, rect.top,
+                    title != null ? title : view.getContentDescription()));
+        }
+    }
+
+    AssistStructure(Parcel in) {
+        PooledStringReader preader = new PooledStringReader(in);
+        mActivityComponent = ComponentName.readFromParcel(in);
+        final int N = in.readInt();
+        for (int i=0; i<N; i++) {
+            mRootViews.add(new ViewNodeImpl(in, preader));
+        }
+        //dump();
+    }
+
+    /** @hide */
+    public void dump() {
+        Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+        ViewNode node = new ViewNode();
+        final int N = getWindowCount();
+        for (int i=0; i<N; i++) {
+            Log.i(TAG, "Window #" + i + ":");
+            getWindowAt(i, node);
+            dump("  ", node);
+        }
+    }
+
+    void dump(String prefix, ViewNode node) {
+        Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+                + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
+        int scrollX = node.getScrollX();
+        int scrollY = node.getScrollY();
+        if (scrollX != 0 || scrollY != 0) {
+            Log.i(TAG, prefix + "  Scroll: " + scrollX + "," + scrollY);
+        }
+        String contentDescription = node.getContentDescription();
+        if (contentDescription != null) {
+            Log.i(TAG, prefix + "  Content description: " + contentDescription);
+        }
+        CharSequence text = node.getText();
+        if (text != null) {
+            Log.i(TAG, prefix + "  Text (sel " + node.getTextSelectionStart() + "-"
+                    + node.getTextSelectionEnd() + "): " + text);
+            Log.i(TAG, prefix + "  Text size: " + node.getTextSize() + " , style: #"
+                    + node.getTextStyle());
+            Log.i(TAG, prefix + "  Text color fg: #" + Integer.toHexString(node.getTextColor())
+                    + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+        }
+        String hint = node.getHint();
+        if (hint != null) {
+            Log.i(TAG, prefix + "  Hint: " + hint);
+        }
+        Bundle extras = node.getExtras();
+        if (extras != null) {
+            Log.i(TAG, prefix + "  Extras: " + extras);
+        }
+        final int NCHILDREN = node.getChildCount();
+        if (NCHILDREN > 0) {
+            Log.i(TAG, prefix + "  Children:");
+            String cprefix = prefix + "    ";
+            ViewNode cnode = new ViewNode();
+            for (int i=0; i<NCHILDREN; i++) {
+                node.getChildAt(i, cnode);
+                dump(cprefix, cnode);
+            }
+        }
+    }
+
+    /**
+     * Retrieve the framework-generated AssistStructure that is stored within
+     * the Bundle filled in by {@link Activity#onProvideAssistData}.
+     */
+    public static AssistStructure getAssistStructure(Bundle assistBundle) {
+        return assistBundle.getParcelable(ASSIST_KEY);
+    }
+
+    public ComponentName getActivityComponent() {
+        return mActivityComponent;
+    }
+
+    /**
+     * Return the number of window contents that have been collected in this assist data.
+     */
+    public int getWindowCount() {
+        return mRootViews.size();
+    }
+
+    /**
+     * Return the root view for one of the windows in the assist data.
+     * @param index Which window to retrieve, may be 0 to {@link #getWindowCount()}-1.
+     * @param outNode Node in which to place the window's root view.
+     */
+    public void getWindowAt(int index, ViewNode outNode) {
+        outNode.mImpl = mRootViews.get(index);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        int start = out.dataPosition();
+        PooledStringWriter pwriter = new PooledStringWriter(out);
+        ComponentName.writeToParcel(mActivityComponent, out);
+        final int N = mRootViews.size();
+        out.writeInt(N);
+        for (int i=0; i<N; i++) {
+            mRootViews.get(i).writeToParcel(out, pwriter);
+        }
+        pwriter.finish();
+        Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
+    }
+
+    public static final Parcelable.Creator<AssistStructure> CREATOR
+            = new Parcelable.Creator<AssistStructure>() {
+        public AssistStructure createFromParcel(Parcel in) {
+            return new AssistStructure(in);
+        }
+
+        public AssistStructure[] newArray(int size) {
+            return new AssistStructure[size];
+        }
+    };
+}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 2784d44..83451aa 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -25,7 +25,6 @@
 import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
-import android.transition.TransitionUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.LogWriter;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2ef046d..eb27830 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,18 +16,9 @@
 
 package android.app;
 
-import android.app.usage.IUsageStatsManager;
-import android.app.usage.UsageStatsManager;
-import android.appwidget.AppWidgetManager;
-import android.os.Build;
-import android.service.persistentdata.IPersistentDataBlockService;
-import android.service.persistentdata.PersistentDataBlockManager;
-
-import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.policy.PolicyManager;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
-import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -35,19 +26,15 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.IContentProvider;
+import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IIntentReceiver;
 import android.content.IntentSender;
-import android.content.IRestrictionsManager;
 import android.content.ReceiverCallNotAllowedException;
-import android.content.RestrictionsManager;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ILauncherApps;
 import android.content.pm.IPackageManager;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetManager;
@@ -59,96 +46,28 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.hardware.ConsumerIrManager;
-import android.hardware.ISerialManager;
-import android.hardware.SerialManager;
-import android.hardware.SystemSensorManager;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlService;
-import android.hardware.camera2.CameraManager;
 import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbManager;
-import android.location.CountryDetector;
-import android.location.ICountryDetector;
-import android.location.ILocationManager;
-import android.location.LocationManager;
-import android.media.AudioManager;
-import android.media.MediaRouter;
-import android.media.projection.MediaProjectionManager;
-import android.media.session.MediaSessionManager;
-import android.media.tv.ITvInputManager;
-import android.media.tv.TvInputManager;
-import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
-import android.net.EthernetManager;
-import android.net.IEthernetManager;
-import android.net.INetworkPolicyManager;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkScoreManager;
 import android.net.Uri;
-import android.net.nsd.INsdManager;
-import android.net.nsd.NsdManager;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.IWifiP2pManager;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.IWifiScanner;
-import android.net.wifi.WifiScanner;
-import android.net.wifi.IRttManager;
-import android.net.wifi.RttManager;
-import android.nfc.NfcManager;
-import android.os.BatteryManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
-import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.IUserManager;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.SystemVibrator;
-import android.os.UserManager;
 import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
-import android.print.IPrintManager;
-import android.print.PrintManager;
-import android.service.fingerprint.IFingerprintService;
-import android.service.fingerprint.FingerprintManager;
-import android.telecom.TelecomManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
-import android.view.DisplayAdjustments;
-import android.view.ContextThemeWrapper;
 import android.view.Display;
-import android.view.WindowManagerImpl;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.CaptioningManager;
-import android.view.inputmethod.InputMethodManager;
-import android.view.textservice.TextServicesManager;
-import android.accounts.AccountManager;
-import android.accounts.IAccountManager;
-import android.app.admin.DevicePolicyManager;
-import android.app.job.IJobScheduler;
-import android.app.trust.TrustManager;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.IDropBoxManagerService;
+import android.view.DisplayAdjustments;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -156,8 +75,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
 
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
@@ -231,7 +148,6 @@
     private final Resources mResources;
     private final Display mDisplay; // may be null if default display
     private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
-    private final Configuration mOverrideConfiguration;
 
     private final boolean mRestricted;
 
@@ -267,508 +183,8 @@
 
     private static final String[] EMPTY_FILE_LIST = {};
 
-    /**
-     * Override this class when the system service constructor needs a
-     * ContextImpl.  Else, use StaticServiceFetcher below.
-     */
-    /*package*/ static class ServiceFetcher {
-        int mContextCacheIndex = -1;
-
-        /**
-         * Main entrypoint; only override if you don't need caching.
-         */
-        public Object getService(ContextImpl ctx) {
-            ArrayList<Object> cache = ctx.mServiceCache;
-            Object service;
-            synchronized (cache) {
-                if (cache.size() == 0) {
-                    // Initialize the cache vector on first access.
-                    // At this point sNextPerContextServiceCacheIndex
-                    // is the number of potential services that are
-                    // cached per-Context.
-                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
-                        cache.add(null);
-                    }
-                } else {
-                    service = cache.get(mContextCacheIndex);
-                    if (service != null) {
-                        return service;
-                    }
-                }
-                service = createService(ctx);
-                cache.set(mContextCacheIndex, service);
-                return service;
-            }
-        }
-
-        /**
-         * Override this to create a new per-Context instance of the
-         * service.  getService() will handle locking and caching.
-         */
-        public Object createService(ContextImpl ctx) {
-            throw new RuntimeException("Not implemented");
-        }
-    }
-
-    /**
-     * Override this class for services to be cached process-wide.
-     */
-    abstract static class StaticServiceFetcher extends ServiceFetcher {
-        private Object mCachedInstance;
-
-        @Override
-        public final Object getService(ContextImpl unused) {
-            synchronized (StaticServiceFetcher.this) {
-                Object service = mCachedInstance;
-                if (service != null) {
-                    return service;
-                }
-                return mCachedInstance = createStaticService();
-            }
-        }
-
-        public abstract Object createStaticService();
-    }
-
-    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
-            new HashMap<String, ServiceFetcher>();
-
-    private static int sNextPerContextServiceCacheIndex = 0;
-    private static void registerService(String serviceName, ServiceFetcher fetcher) {
-        if (!(fetcher instanceof StaticServiceFetcher)) {
-            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
-        }
-        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
-    }
-
-    // This one's defined separately and given a variable name so it
-    // can be re-used by getWallpaperManager(), avoiding a HashMap
-    // lookup.
-    private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new WallpaperManager(ctx.getOuterContext(),
-                        ctx.mMainThread.getHandler());
-            }};
-
-    static {
-        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    return AccessibilityManager.getInstance(ctx);
-                }});
-
-        registerService(CAPTIONING_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    return new CaptioningManager(ctx);
-                }});
-
-        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
-                    IAccountManager service = IAccountManager.Stub.asInterface(b);
-                    return new AccountManager(ctx, service);
-                }});
-
-        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
-                }});
-
-        registerService(ALARM_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ALARM_SERVICE);
-                    IAlarmManager service = IAlarmManager.Stub.asInterface(b);
-                    return new AlarmManager(service, ctx);
-                }});
-
-        registerService(AUDIO_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new AudioManager(ctx);
-                }});
-
-        registerService(MEDIA_ROUTER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new MediaRouter(ctx);
-                }});
-
-        registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new BluetoothManager(ctx);
-                }});
-
-        registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE);
-                    return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
-                }});
-
-        registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new ClipboardManager(ctx.getOuterContext(),
-                            ctx.mMainThread.getHandler());
-                }});
-
-        registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
-                    return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
-                }});
-
-        registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
-                    return new CountryDetector(ICountryDetector.Stub.asInterface(b));
-                }});
-
-        registerService(DEVICE_POLICY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
-                }});
-
-        registerService(DOWNLOAD_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
-                }});
-
-        registerService(BATTERY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new BatteryManager();
-                }});
-
-        registerService(NFC_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new NfcManager(ctx);
-                }});
-
-        registerService(DROPBOX_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return createDropBoxManager();
-                }});
-
-        registerService(INPUT_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return InputManager.getInstance();
-                }});
-
-        registerService(DISPLAY_SERVICE, new ServiceFetcher() {
-                @Override
-                public Object createService(ContextImpl ctx) {
-                    return new DisplayManager(ctx.getOuterContext());
-                }});
-
-        registerService(INPUT_METHOD_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return InputMethodManager.getInstance();
-                }});
-
-        registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return TextServicesManager.getInstance();
-                }});
-
-        registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    // TODO: why isn't this caching it?  It wasn't
-                    // before, so I'm preserving the old behavior and
-                    // using getService(), instead of createService()
-                    // which would do the caching.
-                    return new KeyguardManager();
-                }});
-
-        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
-                }});
-
-        registerService(LOCATION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
-                    return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
-                }});
-
-        registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
-            @Override
-            public Object createService(ContextImpl ctx) {
-                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
-                        ServiceManager.getService(NETWORK_POLICY_SERVICE)));
-            }
-        });
-
-        registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    final Context outerContext = ctx.getOuterContext();
-                    return new NotificationManager(
-                        new ContextThemeWrapper(outerContext,
-                                Resources.selectSystemTheme(0,
-                                        outerContext.getApplicationInfo().targetSdkVersion,
-                                        com.android.internal.R.style.Theme_Dialog,
-                                        com.android.internal.R.style.Theme_Holo_Dialog,
-                                        com.android.internal.R.style.Theme_DeviceDefault_Dialog,
-                                        com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
-                        ctx.mMainThread.getHandler());
-                }});
-
-        registerService(NSD_SERVICE, new ServiceFetcher() {
-                @Override
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(NSD_SERVICE);
-                    INsdManager service = INsdManager.Stub.asInterface(b);
-                    return new NsdManager(ctx.getOuterContext(), service);
-                }});
-
-        // Note: this was previously cached in a static variable, but
-        // constructed using mMainThread.getHandler(), so converting
-        // it to be a regular Context-cached service...
-        registerService(POWER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(POWER_SERVICE);
-                    IPowerManager service = IPowerManager.Stub.asInterface(b);
-                    if (service == null) {
-                        Log.wtf(TAG, "Failed to get power manager service.");
-                    }
-                    return new PowerManager(ctx.getOuterContext(),
-                            service, ctx.mMainThread.getHandler());
-                }});
-
-        registerService(SEARCH_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SearchManager(ctx.getOuterContext(),
-                            ctx.mMainThread.getHandler());
-                }});
-
-        registerService(SENSOR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SystemSensorManager(ctx.getOuterContext(),
-                      ctx.mMainThread.getHandler().getLooper());
-                }});
-
-        registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new StatusBarManager(ctx.getOuterContext());
-                }});
-
-        registerService(STORAGE_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    try {
-                        return new StorageManager(
-                                ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
-                    } catch (RemoteException rex) {
-                        Log.e(TAG, "Failed to create StorageManager", rex);
-                        return null;
-                    }
-                }});
-
-        registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new TelephonyManager(ctx.getOuterContext());
-                }});
-
-        registerService(TELEPHONY_SUBSCRIPTION_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new SubscriptionManager(ctx.getOuterContext());
-            }});
-
-        registerService(TELECOM_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new TelecomManager(ctx.getOuterContext());
-                }});
-
-        registerService(UI_MODE_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new UiModeManager();
-                }});
-
-        registerService(USB_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(USB_SERVICE);
-                    return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
-                }});
-
-        registerService(SERIAL_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(SERIAL_SERVICE);
-                    return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
-                }});
-
-        registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SystemVibrator(ctx);
-                }});
-
-        registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
-
-        registerService(WIFI_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_SERVICE);
-                    IWifiManager service = IWifiManager.Stub.asInterface(b);
-                    return new WifiManager(ctx.getOuterContext(), service);
-                }});
-
-        registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
-                    IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
-                    return new WifiP2pManager(service);
-                }});
-
-        registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
-                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
-                return new WifiScanner(ctx.getOuterContext(), service);
-            }});
-
-        registerService(WIFI_RTT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(WIFI_RTT_SERVICE);
-                IRttManager service = IRttManager.Stub.asInterface(b);
-                return new RttManager(ctx.getOuterContext(), service);
-            }});
-
-        registerService(ETHERNET_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ETHERNET_SERVICE);
-                    IEthernetManager service = IEthernetManager.Stub.asInterface(b);
-                    return new EthernetManager(ctx.getOuterContext(), service);
-                }});
-
-        registerService(WINDOW_SERVICE, new ServiceFetcher() {
-                Display mDefaultDisplay;
-                public Object getService(ContextImpl ctx) {
-                    Display display = ctx.mDisplay;
-                    if (display == null) {
-                        if (mDefaultDisplay == null) {
-                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
-                                    getSystemService(Context.DISPLAY_SERVICE);
-                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
-                        }
-                        display = mDefaultDisplay;
-                    }
-                    return new WindowManagerImpl(display);
-                }});
-
-        registerService(USER_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(USER_SERVICE);
-                IUserManager service = IUserManager.Stub.asInterface(b);
-                return new UserManager(ctx, service);
-            }});
-
-        registerService(APP_OPS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(APP_OPS_SERVICE);
-                IAppOpsService service = IAppOpsService.Stub.asInterface(b);
-                return new AppOpsManager(ctx, service);
-            }});
-
-        registerService(CAMERA_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new CameraManager(ctx);
-            }
-        });
-
-        registerService(LAUNCHER_APPS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(LAUNCHER_APPS_SERVICE);
-                ILauncherApps service = ILauncherApps.Stub.asInterface(b);
-                return new LauncherApps(ctx, service);
-            }
-        });
-
-        registerService(RESTRICTIONS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(RESTRICTIONS_SERVICE);
-                IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
-                return new RestrictionsManager(ctx, service);
-            }
-        });
-        registerService(PRINT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
-                IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
-                return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
-                        UserHandle.getAppId(Process.myUid()));
-            }});
-
-        registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new ConsumerIrManager(ctx);
-            }});
-
-        registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new MediaSessionManager(ctx);
-            }
-        });
-
-        registerService(TRUST_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(TRUST_SERVICE);
-                return new TrustManager(b);
-            }
-        });
-
-        registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder binder = ServiceManager.getService(FINGERPRINT_SERVICE);
-                IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
-                return new FingerprintManager(ctx.getOuterContext(), service);
-            }
-        });
-
-        registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
-                ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
-                return new TvInputManager(service, UserHandle.myUserId());
-            }
-        });
-
-        registerService(NETWORK_SCORE_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new NetworkScoreManager(ctx);
-            }
-        });
-
-        registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(USAGE_STATS_SERVICE);
-                IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
-                return new UsageStatsManager(ctx.getOuterContext(), service);
-            }
-        });
-
-        registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
-                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
-        }});
-
-        registerService(PERSISTENT_DATA_BLOCK_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(PERSISTENT_DATA_BLOCK_SERVICE);
-                IPersistentDataBlockService persistentDataBlockService =
-                        IPersistentDataBlockService.Stub.asInterface(b);
-                if (persistentDataBlockService != null) {
-                    return new PersistentDataBlockManager(persistentDataBlockService);
-                } else {
-                    // not supported
-                    return null;
-                }
-            }
-        });
-
-        registerService(MEDIA_PROJECTION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new MediaProjectionManager(ctx);
-                }
-        });
-
-        registerService(APPWIDGET_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(APPWIDGET_SERVICE);
-                return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
-            }});
-    }
+    // The system service cache for the system services that are cached per-ContextImpl.
+    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
 
     static ContextImpl getImpl(Context context) {
         Context nextContext;
@@ -779,11 +195,6 @@
         return (ContextImpl)context;
     }
 
-    // The system service cache for the system services that are
-    // cached per-ContextImpl.  Package-scoped to avoid accessor
-    // methods.
-    final ArrayList<Object> mServiceCache = new ArrayList<Object>();
-
     @Override
     public AssetManager getAssets() {
         return getResources().getAssets();
@@ -898,6 +309,7 @@
         throw new RuntimeException("Not supported in system context");
     }
 
+    @Override
     public File getSharedPrefsFile(String name) {
         return makeFilename(getPreferencesDir(), name + ".xml");
     }
@@ -1185,40 +597,51 @@
     }
 
     @Override
+    @Deprecated
     public Drawable getWallpaper() {
         return getWallpaperManager().getDrawable();
     }
 
     @Override
+    @Deprecated
     public Drawable peekWallpaper() {
         return getWallpaperManager().peekDrawable();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumWidth() {
         return getWallpaperManager().getDesiredMinimumWidth();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumHeight() {
         return getWallpaperManager().getDesiredMinimumHeight();
     }
 
     @Override
-    public void setWallpaper(Bitmap bitmap) throws IOException  {
+    @Deprecated
+    public void setWallpaper(Bitmap bitmap) throws IOException {
         getWallpaperManager().setBitmap(bitmap);
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(InputStream data) throws IOException {
         getWallpaperManager().setStream(data);
     }
 
     @Override
+    @Deprecated
     public void clearWallpaper() throws IOException {
         getWallpaperManager().clear();
     }
 
+    private WallpaperManager getWallpaperManager() {
+        return getSystemService(WallpaperManager.class);
+    }
+
     @Override
     public void startActivity(Intent intent) {
         warnIfCallingFromSystemProcess();
@@ -1490,6 +913,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1504,6 +928,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcast(Intent intent,
             BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -1538,6 +963,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         if (resolvedType != null) {
@@ -1553,6 +979,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
@@ -1565,6 +992,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -1598,6 +1026,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         if (resolvedType != null) {
@@ -1834,25 +1263,12 @@
 
     @Override
     public Object getSystemService(String name) {
-        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
-        return fetcher == null ? null : fetcher.getService(this);
+        return SystemServiceRegistry.getSystemService(this, name);
     }
 
-    private WallpaperManager getWallpaperManager() {
-        return (WallpaperManager) WALLPAPER_FETCHER.getService(this);
-    }
-
-    /* package */ static DropBoxManager createDropBoxManager() {
-        IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
-        IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
-        if (service == null) {
-            // Don't return a DropBoxManager that will NPE upon use.
-            // This also avoids caching a broken DropBoxManager in
-            // getDropBoxManager during early boot, before the
-            // DROPBOX_SERVICE is registered.
-            return null;
-        }
-        return new DropBoxManager(service);
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        return SystemServiceRegistry.getSystemServiceName(serviceClass);
     }
 
     @Override
@@ -1921,6 +1337,7 @@
         }
     }
 
+    @Override
     public void enforcePermission(
             String permission, int pid, int uid, String message) {
         enforce(permission,
@@ -1930,6 +1347,7 @@
                 message);
     }
 
+    @Override
     public void enforceCallingPermission(String permission, String message) {
         enforce(permission,
                 checkCallingPermission(permission),
@@ -1938,6 +1356,7 @@
                 message);
     }
 
+    @Override
     public void enforceCallingOrSelfPermission(
             String permission, String message) {
         enforce(permission,
@@ -2075,6 +1494,7 @@
         }
     }
 
+    @Override
     public void enforceUriPermission(
             Uri uri, int pid, int uid, int modeFlags, String message) {
         enforceForUri(
@@ -2082,6 +1502,7 @@
                 false, uid, uri, message);
     }
 
+    @Override
     public void enforceCallingUriPermission(
             Uri uri, int modeFlags, String message) {
         enforceForUri(
@@ -2090,6 +1511,7 @@
                 Binder.getCallingUid(), uri, message);
     }
 
+    @Override
     public void enforceCallingOrSelfUriPermission(
             Uri uri, int modeFlags, String message) {
         enforceForUri(
@@ -2098,6 +1520,7 @@
                 Binder.getCallingUid(), uri, message);
     }
 
+    @Override
     public void enforceUriPermission(
             Uri uri, String readPermission, String writePermission,
             int pid, int uid, int modeFlags, String message) {
@@ -2132,7 +1555,7 @@
             final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
                     new UserHandle(UserHandle.getUserId(application.uid)), restricted,
-                    mDisplay, mOverrideConfiguration);
+                    mDisplay, null);
             if (c.mResources != null) {
                 return c;
             }
@@ -2155,14 +1578,14 @@
         final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
         if (packageName.equals("system") || packageName.equals("android")) {
             return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                    user, restricted, mDisplay, mOverrideConfiguration);
+                    user, restricted, mDisplay, null);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
-                    user, restricted, mDisplay, mOverrideConfiguration);
+                    user, restricted, mDisplay, null);
             if (c.mResources != null) {
                 return c;
             }
@@ -2190,7 +1613,15 @@
         }
 
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mRestricted, display, mOverrideConfiguration);
+                mUser, mRestricted, display, null);
+    }
+
+    Display getDisplay() {
+        if (mDisplay != null) {
+            return mDisplay;
+        }
+        DisplayManager dm = getSystemService(DisplayManager.class);
+        return dm.getDisplay(Display.DEFAULT_DISPLAY);
     }
 
     private int getDisplayId() {
@@ -2227,6 +1658,7 @@
     }
 
     /** {@hide} */
+    @Override
     public int getUserId() {
         return mUser.getIdentifier();
     }
@@ -2236,7 +1668,7 @@
         ContextImpl context = new ContextImpl(null, mainThread,
                 packageInfo, null, null, false, null, null);
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
-                context.mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
+                context.mResourcesManager.getDisplayMetricsLocked());
         return context;
     }
 
@@ -2247,11 +1679,12 @@
     }
 
     static ContextImpl createActivityContext(ActivityThread mainThread,
-            LoadedApk packageInfo, IBinder activityToken) {
+            LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
-        if (activityToken == null) throw new IllegalArgumentException("activityInfo");
-        return new ContextImpl(null, mainThread,
-                packageInfo, activityToken, null, false, null, null);
+        final Display display = ResourcesManager.getInstance().getAdjustedDisplay(
+                displayId, overrideConfiguration);
+        return new ContextImpl(null, mainThread, packageInfo, null, null, false, display,
+                overrideConfiguration);
     }
 
     private ContextImpl(ContextImpl container, ActivityThread mainThread,
@@ -2271,30 +1704,30 @@
         mPackageInfo = packageInfo;
         mResourcesManager = ResourcesManager.getInstance();
         mDisplay = display;
-        mOverrideConfiguration = overrideConfiguration;
 
         final int displayId = getDisplayId();
         CompatibilityInfo compatInfo = null;
         if (container != null) {
             compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
         }
-        if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) {
-            compatInfo = packageInfo.getCompatibilityInfo();
+        if (compatInfo == null) {
+            compatInfo = (displayId == Display.DEFAULT_DISPLAY)
+                    ? packageInfo.getCompatibilityInfo()
+                    : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
         }
         mDisplayAdjustments.setCompatibilityInfo(compatInfo);
-        mDisplayAdjustments.setActivityToken(activityToken);
+        mDisplayAdjustments.setConfiguration(overrideConfiguration);
 
         Resources resources = packageInfo.getResources(mainThread);
         if (resources != null) {
-            if (activityToken != null
-                    || displayId != Display.DEFAULT_DISPLAY
+            if (displayId != Display.DEFAULT_DISPLAY
                     || overrideConfiguration != null
                     || (compatInfo != null && compatInfo.applicationScale
                             != resources.getCompatibilityInfo().applicationScale)) {
                 resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                         packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                         packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
-                        overrideConfiguration, compatInfo, activityToken);
+                        overrideConfiguration, compatInfo);
             }
         }
         mResources = resources;
@@ -2351,6 +1784,7 @@
         return mActivityToken;
     }
 
+    @SuppressWarnings("deprecation")
     static void setFilePermissionsFromMode(String name, int mode,
             int extraPermissions) {
         int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index f79d32b..3fbbdff 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -131,6 +131,9 @@
         switch (which) {
             case BUTTON_POSITIVE:
                 if (mDateSetListener != null) {
+                    // Clearing focus forces the dialog to commit any pending
+                    // changes, e.g. typed text in a NumberPicker.
+                    mDatePicker.clearFocus();
                     mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(),
                             mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
                 }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 067073a..9defcbe5 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -16,14 +16,19 @@
 
 package android.app;
 
-import android.content.pm.ApplicationInfo;
+import android.annotation.CallSuper;
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
+import android.annotation.StringRes;
 import com.android.internal.app.WindowDecorActionBar;
-import com.android.internal.policy.PolicyManager;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -42,6 +47,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
@@ -115,6 +121,8 @@
 
     private ActionMode mActionMode;
 
+    private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
+
     private final Runnable mDismissAction = new Runnable() {
         public void run() {
             dismissDialog();
@@ -134,14 +142,14 @@
 
     /**
      * Create a Dialog window that uses a custom dialog style.
-     * 
+     *
      * @param context The Context in which the Dialog should run. In particular, it
      *                uses the window manager and theme from this context to
      *                present its UI.
-     * @param theme A style resource describing the theme to use for the 
-     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style 
-     * and Theme Resources</a> for more information about defining and using 
-     * styles.  This theme is applied on top of the current theme in 
+     * @param theme A style resource describing the theme to use for the
+     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
+     * and Theme Resources</a> for more information about defining and using
+     * styles.  This theme is applied on top of the current theme in
      * <var>context</var>.  If 0, the default dialog theme will be used.
      */
     public Dialog(Context context, int theme) {
@@ -162,7 +170,7 @@
         }
 
         mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-        Window w = PolicyManager.makeNewWindow(mContext);
+        Window w = new PhoneWindow(mContext);
         mWindow = w;
         w.setCallback(this);
         w.setOnWindowDismissedCallback(this);
@@ -476,7 +484,8 @@
      * @param id the identifier of the view to find
      * @return The view with the given id or null.
      */
-    public View findViewById(int id) {
+    @Nullable
+    public View findViewById(@IdRes int id) {
         return mWindow.findViewById(id);
     }
 
@@ -486,7 +495,7 @@
      * 
      * @param layoutResID Resource ID to be inflated.
      */
-    public void setContentView(int layoutResID) {
+    public void setContentView(@LayoutRes int layoutResID) {
         mWindow.setContentView(layoutResID);
     }
 
@@ -540,7 +549,7 @@
      *
      * @param titleId the title's text resource identifier
      */
-    public void setTitle(int titleId) {
+    public void setTitle(@StringRes int titleId) {
         setTitle(mContext.getText(titleId));
     }
 
@@ -966,13 +975,13 @@
     public boolean onContextItemSelected(MenuItem item) {
         return false;
     }
-    
+
     /**
      * @see Activity#onContextMenuClosed(Menu)
      */
     public void onContextMenuClosed(Menu menu) {
     }
-    
+
     /**
      * This hook is called when the user signals the desire to start a search.
      */
@@ -991,8 +1000,12 @@
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
-        if (mActionBar != null) {
+        if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) {
             return mActionBar.startActionMode(callback);
         }
         return null;
@@ -1000,10 +1013,24 @@
 
     /**
      * {@inheritDoc}
+     */
+    @Override
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+        try {
+            mActionModeTypeStarting = type;
+            return onWindowStartingActionMode(callback);
+        } finally {
+            mActionModeTypeStarting = ActionMode.TYPE_PRIMARY;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
      *
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeStarted(mode).
      */
+    @CallSuper
     public void onActionModeStarted(ActionMode mode) {
         mActionMode = mode;
     }
@@ -1014,6 +1041,7 @@
      * Note that if you override this method you should always call through
      * to the superclass implementation by calling super.onActionModeFinished(mode).
      */
+    @CallSuper
     public void onActionModeFinished(ActionMode mode) {
         if (mode == mActionMode) {
             mActionMode = null;
@@ -1070,7 +1098,7 @@
      * Convenience for calling
      * {@link android.view.Window#setFeatureDrawableResource}.
      */
-    public final void setFeatureDrawableResource(int featureId, int resId) {
+    public final void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
         getWindow().setFeatureDrawableResource(featureId, resId);
     }
 
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index af45731..bdcc312 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
@@ -219,8 +220,8 @@
  * state of its view hierarchy has been restored.
  * <li> {@link #onStart} makes the fragment visible to the user (based on its
  * containing activity being started).
- * <li> {@link #onResume} makes the fragment interacting with the user (based on its
- * containing activity being resumed).
+ * <li> {@link #onResume} makes the fragment begin interacting with the user
+ * (based on its containing activity being resumed).
  * </ol>
  *
  * <p>As a fragment is no longer being used, it goes through a reverse
@@ -564,7 +565,7 @@
      * and later retrieved by the Fragment with {@link #getArguments}.
      *
      * <p>Applications should generally not implement a constructor.  The
-     * first place application code an run where the fragment is ready to
+     * first place application code can run where the fragment is ready to
      * be used is in {@link #onAttach(Activity)}, the point where the fragment
      * is actually associated with its activity.  Some applications may also
      * want to implement {@link #onInflate} to retrieve attributes from a
@@ -720,8 +721,7 @@
     }
 
     /**
-     * Return the arguments supplied when the fragment was instantiated,
-     * if any.
+     * Return the arguments supplied to {@link #setArguments}, if any.
      */
     final public Bundle getArguments() {
         return mArguments;
@@ -796,7 +796,7 @@
      *
      * @param resId Resource id for the CharSequence text
      */
-    public final CharSequence getText(int resId) {
+    public final CharSequence getText(@StringRes int resId) {
         return getResources().getText(resId);
     }
 
@@ -806,7 +806,7 @@
      *
      * @param resId Resource id for the string
      */
-    public final String getString(int resId) {
+    public final String getString(@StringRes int resId) {
         return getResources().getString(resId);
     }
 
@@ -819,7 +819,7 @@
      * @param formatArgs The format arguments that will be used for substitution.
      */
 
-    public final String getString(int resId, Object... formatArgs) {
+    public final String getString(@StringRes int resId, Object... formatArgs) {
         return getResources().getString(resId, formatArgs);
     }
 
@@ -1244,7 +1244,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
 
@@ -1310,7 +1310,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onActivityCreated(Bundle savedInstanceState) {
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
 
@@ -2009,6 +2009,7 @@
         mChildFragmentManager = new FragmentManagerImpl();
         mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
             @Override
+            @Nullable
             public View findViewById(int id) {
                 if (mView == null) {
                     throw new IllegalStateException("Fragment does not have a view");
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index fc761fe..975b20d 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -19,7 +19,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
 import android.content.Context;
+import android.annotation.IdRes;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.os.Bundle;
@@ -70,7 +72,7 @@
      * with {@link FragmentTransaction#addToBackStack(String)
      * FragmentTransaction.addToBackStack()}.  Entries can later be
      * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
-     * FragmentManager.getBackStackEntry()}.
+     * FragmentManager.getBackStackEntryAt()}.
      *
      * <p>Note that you should never hold on to a BackStackEntry object;
      * the identifier as returned by {@link #getId} is the only thing that
@@ -260,7 +262,7 @@
 
     /**
      * Return the BackStackEntry at index <var>index</var> in the back stack;
-     * entries start index 0 being the bottom of the stack.
+     * where the item on the bottom of the stack has index 0.
      */
     public abstract BackStackEntry getBackStackEntryAt(int index);
 
@@ -394,7 +396,8 @@
  * Callbacks from FragmentManagerImpl to its container.
  */
 interface FragmentContainer {
-    public View findViewById(int id);
+    @Nullable
+    public View findViewById(@IdRes int id);
     public boolean hasView();
 }
 
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 25cd3cc..dc7075c 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -26,7 +26,7 @@
     /**
      * Add a fragment to the activity state.  This fragment may optionally
      * also have its view (if {@link Fragment#onCreateView Fragment.onCreateView}
-     * returns non-null) into a container view of the activity.
+     * returns non-null) inserted into a container view of the activity.
      * 
      * @param containerViewId Optional identifier of the container this fragment is
      * to be placed in.  If 0, it will not be placed in a container.
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 52884f7..170aff3 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -29,9 +29,8 @@
     void setSurface(in Surface surface, int width, int height, int density);
     int startActivity(in Intent intent);
     int startActivityIntentSender(in IIntentSender intentSender);
-    void checkEmbeddedAllowed(in Intent intent);
-    void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
     int getDisplayId();
+    int getStackId();
     boolean injectEvent(in InputEvent event);
     void release();
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e505d69..3dcbdd2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -51,6 +51,7 @@
 import android.os.StrictMode;
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
 
 import java.util.List;
 
@@ -106,7 +107,8 @@
             String resultData, Bundle map, String requiredPermission,
             int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException;
     public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
-    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
+    public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
+            boolean abortBroadcast, int flags) throws RemoteException;
     public void attachApplication(IApplicationThread app) throws RemoteException;
     public void activityResumed(IBinder token) throws RemoteException;
     public void activityIdle(IBinder token, Configuration config,
@@ -130,7 +132,6 @@
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
             throws RemoteException;
     public void moveTaskToFront(int task, int flags, Bundle options) throws RemoteException;
-    public void moveTaskToBack(int task) throws RemoteException;
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
@@ -139,6 +140,7 @@
     public StackInfo getStackInfo(int stackId) throws RemoteException;
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
+    public int getFocusedStackId() throws RemoteException;
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
@@ -418,6 +420,9 @@
 
     public Bundle getAssistContextExtras(int requestType) throws RemoteException;
 
+    public void requestAssistContextExtras(int requestType, IResultReceiver receiver)
+            throws RemoteException;
+
     public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException;
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle)
@@ -433,13 +438,14 @@
 
     public void performIdleMaintenance() throws RemoteException;
 
-    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+    public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException;
 
+    public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException;
+
     public void deleteActivityContainer(IActivityContainer container) throws RemoteException;
 
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException;
+    public int getActivityDisplayId(IBinder activityToken) throws RemoteException;
 
     public IBinder getHomeActivityToken() throws RemoteException;
 
@@ -455,8 +461,12 @@
 
     public boolean isInLockTaskMode() throws RemoteException;
 
+    public int getLockTaskModeState() throws RemoteException;
+
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
+    public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
+    public void resizeTask(int taskId, Rect bounds) throws RemoteException;
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
 
     public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
@@ -470,6 +480,10 @@
     public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
 
     public void systemBackupRestored() throws RemoteException;
+    public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
+
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+    public void dumpHeapFinished(String path) throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -501,7 +515,7 @@
                 dest.writeStrongBinder(null);
             }
             dest.writeStrongBinder(connection);
-            dest.writeInt(noReleaseNeeded ? 1:0);
+            dest.writeInt(noReleaseNeeded ? 1 : 0);
         }
 
         public static final Parcelable.Creator<ContentProviderHolder> CREATOR
@@ -520,7 +534,7 @@
         private ContentProviderHolder(Parcel source) {
             info = ProviderInfo.CREATOR.createFromParcel(source);
             provider = ContentProviderNative.asInterface(
-                source.readStrongBinder());
+                    source.readStrongBinder());
             connection = source.readStrongBinder();
             noReleaseNeeded = source.readInt() != 0;
         }
@@ -597,7 +611,7 @@
     int GET_CALLING_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+21;
     int GET_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+22;
     int MOVE_TASK_TO_FRONT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+23;
-    int MOVE_TASK_TO_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24;
+
     int MOVE_TASK_BACKWARDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
     int GET_TASK_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
 
@@ -737,7 +751,7 @@
     int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
     int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
     int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
-    int CREATE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
+    int CREATE_VIRTUAL_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
     int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
     int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
     int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
@@ -754,7 +768,7 @@
     int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
     int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
     int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
-    int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
+    int GET_ACTIVITY_DISPLAY_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
     int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
 
 
@@ -793,4 +807,15 @@
     int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
     int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
     int SYSTEM_BACKUP_RESTORED = IBinder.FIRST_CALL_TRANSACTION+243;
+
+    // Start of M transactions
+    int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
+    int CREATE_STACK_ON_DISPLAY = IBinder.FIRST_CALL_TRANSACTION+281;
+    int GET_FOCUSED_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+282;
+    int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
+    int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
+    int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
+    int GET_LOCK_TASK_MODE_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+286;
+    int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
+    int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 42acbc6..3fb82f6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -33,7 +33,6 @@
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
-import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
 
@@ -59,14 +58,14 @@
             throws RemoteException;
     void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
-            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
-            PersistableBundle persistentState, List<ResultInfo> pendingResults,
-            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
-            ProfilerInfo profilerInfo) throws RemoteException;
+            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
+            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
+            int procState, Bundle state, PersistableBundle persistentState,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException;
     void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
-            List<ReferrerIntent> pendingNewIntents, int configChanges,
-            boolean notResumed, Configuration config) throws RemoteException;
+            List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
+            Configuration config, Configuration overrideConfig) throws RemoteException;
     void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
     void scheduleDestroyActivity(IBinder token, boolean finished,
             int configChanges) throws RemoteException;
@@ -115,7 +114,8 @@
             int resultCode, String data, Bundle extras, boolean ordered,
             boolean sticky, int sendingUser, int processState) throws RemoteException;
     void scheduleLowMemory() throws RemoteException;
-    void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
+    void scheduleActivityConfigurationChanged(IBinder token, Configuration overrideConfig)
+            throws RemoteException;
     void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType)
             throws RemoteException;
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
@@ -147,6 +147,7 @@
     void scheduleCancelVisibleBehind(IBinder token) throws RemoteException;
     void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled) throws RemoteException;
     void scheduleEnterAnimationComplete(IBinder token) throws RemoteException;
+    void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -204,4 +205,5 @@
     int CANCEL_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52;
     int BACKGROUND_VISIBLE_BEHIND_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53;
     int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54;
+    int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55;
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 88b9080..5d864df 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -75,6 +75,7 @@
 
     ZenModeConfig getZenModeConfig();
     boolean setZenModeConfig(in ZenModeConfig config);
+    oneway void setZenMode(int mode);
     oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
     oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
     oneway void setZenModeCondition(in Condition condition);
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index 03e7ff4..6d27910 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -31,5 +31,5 @@
    ComponentName getGlobalSearchActivity();
    ComponentName getWebSearchActivity();
    ComponentName getAssistIntent(int userHandle);
-   boolean launchAssistAction(int requestType, String hint, int userHandle);
+   boolean launchAssistAction(String hint, int userHandle);
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3b5900b..ccba250 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -29,13 +29,18 @@
     /**
      * Set the wallpaper.
      */
-    ParcelFileDescriptor setWallpaper(String name);
+    ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
     
     /**
      * Set the live wallpaper.
      */
+    void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
+
+    /**
+     * Set the live wallpaper.
+     */
     void setWallpaperComponent(in ComponentName name);
-    
+
     /**
      * Get the wallpaper.
      */
@@ -50,7 +55,7 @@
     /**
      * Clear the wallpaper.
      */
-    void clearWallpaper();
+    void clearWallpaper(in String callingPackage);
 
     /**
      * Return whether there is a wallpaper set with the given name.
@@ -61,7 +66,7 @@
      * Sets the dimension hint for the wallpaper. These hints indicate the desired
      * minimum width and height for the wallpaper.
      */
-    void setDimensionHints(in int width, in int height);
+    void setDimensionHints(in int width, in int height, in String callingPackage);
 
     /**
      * Returns the desired minimum width for the wallpaper.
@@ -76,7 +81,7 @@
     /**
      * Sets extra padding that we would like the wallpaper to have outside of the display.
      */
-    void setDisplayPadding(in Rect padding);
+    void setDisplayPadding(in Rect padding, in String callingPackage);
 
     /**
      * Returns the name of the wallpaper. Private API.
@@ -87,4 +92,9 @@
      * Informs the service that wallpaper settings have been restored. Private API.
      */
     void settingsRestored();
+
+    /**
+     * Check whether wallpapers are supported for the calling user.
+     */
+    boolean isWallpaperSupported(in String callingPackage);
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ad2b61f..5572d30 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1322,7 +1322,10 @@
     
     /*
      * Starts allocation counting. This triggers a gc and resets the counts.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void startAllocCounting() {
         // Before we start trigger a GC and reset the debug counts. Run the 
         // finalizers and another GC before starting and stopping the alloc
@@ -1340,7 +1343,10 @@
     
     /*
      * Stops allocation counting.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public void stopAllocCounting() {
         Runtime.getRuntime().gc();
         Runtime.getRuntime().runFinalization();
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ece2a33..83c6c2b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -45,6 +45,7 @@
 import android.util.SparseArray;
 import android.view.DisplayAdjustments;
 import android.view.Display;
+import android.os.SystemProperties;
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -156,7 +157,12 @@
         // depending on what the current runtime's instruction set is.
         if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
             final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
-            final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+
+            // Get the instruction set that the libraries of secondary Abi is supported.
+            // In presence of a native bridge this might be different than the one secondary Abi used.
+            String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
+            final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
+            secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
 
             // If the runtimeIsa is the same as the primary isa, then we do nothing.
             // Everything will be set up correctly because info.nativeLibraryDir will
@@ -801,7 +807,7 @@
                         if (extras != null) {
                             extras.setAllowFds(false);
                         }
-                        mgr.finishReceiver(this, resultCode, data, extras, false);
+                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                     } catch (RemoteException e) {
                         Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
                     }
@@ -826,8 +832,8 @@
             public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                     boolean ordered, boolean sticky, int sendingUser) {
                 super(resultCode, resultData, resultExtras,
-                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
-                        ordered, sticky, mIIntentReceiver.asBinder(), sendingUser);
+                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
+                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                 mCurIntent = intent;
                 mOrdered = ordered;
             }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 80b57b7..85a6aff 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -165,6 +167,7 @@
      * The resource id of a drawable to use as the icon in the status bar.
      * This is required; notifications with an invalid icon resource will not be shown.
      */
+    @DrawableRes
     public int icon;
 
     /**
@@ -336,6 +339,7 @@
      * @see #FLAG_SHOW_LIGHTS
      * @see #flags
      */
+    @ColorInt
     public int ledARGB;
 
     /**
@@ -413,7 +417,6 @@
      * Bit to be bitwise-ored into the {@link #flags} field that should be
      * set if the notification should be canceled when it is clicked by the
      * user.
-
      */
     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
 
@@ -518,12 +521,14 @@
      * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
      * ignored.
      */
+    @ColorInt
     public int color = COLOR_DEFAULT;
 
     /**
      * Special value of {@link #color} telling the system not to decorate this notification with
      * any special color but instead use default colors when presenting this notification.
      */
+    @ColorInt
     public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
@@ -1736,6 +1741,7 @@
         builder.setSound(this.sound, this.audioStreamType);
         builder.setDefaults(this.defaults);
         builder.setVibrate(this.vibrate);
+        builder.setDeleteIntent(this.deleteIntent);
 
         // now apply the latestEventInfo fields
         if (contentTitle != null) {
@@ -2127,7 +2133,7 @@
          *            A resource ID in the application's package of the drawable to use.
          * @see Notification#icon
          */
-        public Builder setSmallIcon(int icon) {
+        public Builder setSmallIcon(@DrawableRes int icon) {
             mSmallIcon = icon;
             return this;
         }
@@ -2143,7 +2149,7 @@
          * @see Notification#icon
          * @see Notification#iconLevel
          */
-        public Builder setSmallIcon(int icon, int level) {
+        public Builder setSmallIcon(@DrawableRes int icon, int level) {
             mSmallIcon = icon;
             mSmallIconLevel = level;
             return this;
@@ -2385,7 +2391,7 @@
          * @see Notification#ledOnMS
          * @see Notification#ledOffMS
          */
-        public Builder setLights(int argb, int onMs, int offMs) {
+        public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
             mLedArgb = argb;
             mLedOnMs = onMs;
             mLedOffMs = offMs;
@@ -2709,7 +2715,7 @@
          *
          * @return The same Builder.
          */
-        public Builder setColor(int argb) {
+        public Builder setColor(@ColorInt int argb) {
             mColor = argb;
             return this;
         }
@@ -5064,6 +5070,404 @@
     }
 
     /**
+     * <p>Helper class to add Android Auto extensions to notifications. To create a notification
+     * with car extensions:
+     *
+     * <ol>
+     *  <li>Create an {@link Notification.Builder}, setting any desired
+     *  properties.
+     *  <li>Create a {@link CarExtender}.
+     *  <li>Set car-specific properties using the {@code add} and {@code set} methods of
+     *  {@link CarExtender}.
+     *  <li>Call {@link Notification.Builder#extend(Notification.Extender)}
+     *  to apply the extensions to a notification.
+     * </ol>
+     *
+     * <pre class="prettyprint">
+     * Notification notification = new Notification.Builder(context)
+     *         ...
+     *         .extend(new CarExtender()
+     *                 .set*(...))
+     *         .build();
+     * </pre>
+     *
+     * <p>Car extensions can be accessed on an existing notification by using the
+     * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods
+     * to access values.
+     */
+    public static final class CarExtender implements Extender {
+        private static final String TAG = "CarExtender";
+
+        private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
+        private static final String EXTRA_LARGE_ICON = "large_icon";
+        private static final String EXTRA_CONVERSATION = "car_conversation";
+        private static final String EXTRA_COLOR = "app_color";
+
+        private Bitmap mLargeIcon;
+        private UnreadConversation mUnreadConversation;
+        private int mColor = Notification.COLOR_DEFAULT;
+
+        /**
+         * Create a {@link CarExtender} with default options.
+         */
+        public CarExtender() {
+        }
+
+        /**
+         * Create a {@link CarExtender} from the CarExtender options of an existing Notification.
+         *
+         * @param notif The notification from which to copy options.
+         */
+        public CarExtender(Notification notif) {
+            Bundle carBundle = notif.extras == null ?
+                    null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
+            if (carBundle != null) {
+                mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
+                mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
+
+                Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
+                mUnreadConversation = UnreadConversation.getUnreadConversationFromBundle(b);
+            }
+        }
+
+        /**
+         * Apply car extensions to a notification that is being built. This is typically called by
+         * the {@link Notification.Builder#extend(Notification.Extender)}
+         * method of {@link Notification.Builder}.
+         */
+        @Override
+        public Notification.Builder extend(Notification.Builder builder) {
+            Bundle carExtensions = new Bundle();
+
+            if (mLargeIcon != null) {
+                carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
+            }
+            if (mColor != Notification.COLOR_DEFAULT) {
+                carExtensions.putInt(EXTRA_COLOR, mColor);
+            }
+
+            if (mUnreadConversation != null) {
+                Bundle b = mUnreadConversation.getBundleForUnreadConversation();
+                carExtensions.putBundle(EXTRA_CONVERSATION, b);
+            }
+
+            builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions);
+            return builder;
+        }
+
+        /**
+         * Sets the accent color to use when Android Auto presents the notification.
+         *
+         * Android Auto uses the color set with {@link Notification.Builder#setColor(int)}
+         * to accent the displayed notification. However, not all colors are acceptable in an
+         * automotive setting. This method can be used to override the color provided in the
+         * notification in such a situation.
+         */
+        public CarExtender setColor(@ColorInt int color) {
+            mColor = color;
+            return this;
+        }
+
+        /**
+         * Gets the accent color.
+         *
+         * @see setColor
+         */
+        @ColorInt
+        public int getColor() {
+            return mColor;
+        }
+
+        /**
+         * Sets the large icon of the car notification.
+         *
+         * If no large icon is set in the extender, Android Auto will display the icon
+         * specified by {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap)}
+         *
+         * @param largeIcon The large icon to use in the car notification.
+         * @return This object for method chaining.
+         */
+        public CarExtender setLargeIcon(Bitmap largeIcon) {
+            mLargeIcon = largeIcon;
+            return this;
+        }
+
+        /**
+         * Gets the large icon used in this car notification, or null if no icon has been set.
+         *
+         * @return The large icon for the car notification.
+         * @see CarExtender#setLargeIcon
+         */
+        public Bitmap getLargeIcon() {
+            return mLargeIcon;
+        }
+
+        /**
+         * Sets the unread conversation in a message notification.
+         *
+         * @param unreadConversation The unread part of the conversation this notification conveys.
+         * @return This object for method chaining.
+         */
+        public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
+            mUnreadConversation = unreadConversation;
+            return this;
+        }
+
+        /**
+         * Returns the unread conversation conveyed by this notification.
+         * @see #setUnreadConversation(UnreadConversation)
+         */
+        public UnreadConversation getUnreadConversation() {
+            return mUnreadConversation;
+        }
+
+        /**
+         * A class which holds the unread messages from a conversation.
+         */
+        public static class UnreadConversation {
+            private static final String KEY_AUTHOR = "author";
+            private static final String KEY_TEXT = "text";
+            private static final String KEY_MESSAGES = "messages";
+            private static final String KEY_REMOTE_INPUT = "remote_input";
+            private static final String KEY_ON_REPLY = "on_reply";
+            private static final String KEY_ON_READ = "on_read";
+            private static final String KEY_PARTICIPANTS = "participants";
+            private static final String KEY_TIMESTAMP = "timestamp";
+
+            private final String[] mMessages;
+            private final RemoteInput mRemoteInput;
+            private final PendingIntent mReplyPendingIntent;
+            private final PendingIntent mReadPendingIntent;
+            private final String[] mParticipants;
+            private final long mLatestTimestamp;
+
+            UnreadConversation(String[] messages, RemoteInput remoteInput,
+                    PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
+                    String[] participants, long latestTimestamp) {
+                mMessages = messages;
+                mRemoteInput = remoteInput;
+                mReadPendingIntent = readPendingIntent;
+                mReplyPendingIntent = replyPendingIntent;
+                mParticipants = participants;
+                mLatestTimestamp = latestTimestamp;
+            }
+
+            /**
+             * Gets the list of messages conveyed by this notification.
+             */
+            public String[] getMessages() {
+                return mMessages;
+            }
+
+            /**
+             * Gets the remote input that will be used to convey the response to a message list, or
+             * null if no such remote input exists.
+             */
+            public RemoteInput getRemoteInput() {
+                return mRemoteInput;
+            }
+
+            /**
+             * Gets the pending intent that will be triggered when the user replies to this
+             * notification.
+             */
+            public PendingIntent getReplyPendingIntent() {
+                return mReplyPendingIntent;
+            }
+
+            /**
+             * Gets the pending intent that Android Auto will send after it reads aloud all messages
+             * in this object's message list.
+             */
+            public PendingIntent getReadPendingIntent() {
+                return mReadPendingIntent;
+            }
+
+            /**
+             * Gets the participants in the conversation.
+             */
+            public String[] getParticipants() {
+                return mParticipants;
+            }
+
+            /**
+             * Gets the firs participant in the conversation.
+             */
+            public String getParticipant() {
+                return mParticipants.length > 0 ? mParticipants[0] : null;
+            }
+
+            /**
+             * Gets the timestamp of the conversation.
+             */
+            public long getLatestTimestamp() {
+                return mLatestTimestamp;
+            }
+
+            Bundle getBundleForUnreadConversation() {
+                Bundle b = new Bundle();
+                String author = null;
+                if (mParticipants != null && mParticipants.length > 1) {
+                    author = mParticipants[0];
+                }
+                Parcelable[] messages = new Parcelable[mMessages.length];
+                for (int i = 0; i < messages.length; i++) {
+                    Bundle m = new Bundle();
+                    m.putString(KEY_TEXT, mMessages[i]);
+                    m.putString(KEY_AUTHOR, author);
+                    messages[i] = m;
+                }
+                b.putParcelableArray(KEY_MESSAGES, messages);
+                if (mRemoteInput != null) {
+                    b.putParcelable(KEY_REMOTE_INPUT, mRemoteInput);
+                }
+                b.putParcelable(KEY_ON_REPLY, mReplyPendingIntent);
+                b.putParcelable(KEY_ON_READ, mReadPendingIntent);
+                b.putStringArray(KEY_PARTICIPANTS, mParticipants);
+                b.putLong(KEY_TIMESTAMP, mLatestTimestamp);
+                return b;
+            }
+
+            static UnreadConversation getUnreadConversationFromBundle(Bundle b) {
+                if (b == null) {
+                    return null;
+                }
+                Parcelable[] parcelableMessages = b.getParcelableArray(KEY_MESSAGES);
+                String[] messages = null;
+                if (parcelableMessages != null) {
+                    String[] tmp = new String[parcelableMessages.length];
+                    boolean success = true;
+                    for (int i = 0; i < tmp.length; i++) {
+                        if (!(parcelableMessages[i] instanceof Bundle)) {
+                            success = false;
+                            break;
+                        }
+                        tmp[i] = ((Bundle) parcelableMessages[i]).getString(KEY_TEXT);
+                        if (tmp[i] == null) {
+                            success = false;
+                            break;
+                        }
+                    }
+                    if (success) {
+                        messages = tmp;
+                    } else {
+                        return null;
+                    }
+                }
+
+                PendingIntent onRead = b.getParcelable(KEY_ON_READ);
+                PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
+
+                RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
+
+                String[] participants = b.getStringArray(KEY_PARTICIPANTS);
+                if (participants == null || participants.length != 1) {
+                    return null;
+                }
+
+                return new UnreadConversation(messages,
+                        remoteInput,
+                        onReply,
+                        onRead,
+                        participants, b.getLong(KEY_TIMESTAMP));
+            }
+        };
+
+        /**
+         * Builder class for {@link CarExtender.UnreadConversation} objects.
+         */
+        public static class Builder {
+            private final List<String> mMessages = new ArrayList<String>();
+            private final String mParticipant;
+            private RemoteInput mRemoteInput;
+            private PendingIntent mReadPendingIntent;
+            private PendingIntent mReplyPendingIntent;
+            private long mLatestTimestamp;
+
+            /**
+             * Constructs a new builder for {@link CarExtender.UnreadConversation}.
+             *
+             * @param name The name of the other participant in the conversation.
+             */
+            public Builder(String name) {
+                mParticipant = name;
+            }
+
+            /**
+             * Appends a new unread message to the list of messages for this conversation.
+             *
+             * The messages should be added from oldest to newest.
+             *
+             * @param message The text of the new unread message.
+             * @return This object for method chaining.
+             */
+            public Builder addMessage(String message) {
+                mMessages.add(message);
+                return this;
+            }
+
+            /**
+             * Sets the pending intent and remote input which will convey the reply to this
+             * notification.
+             *
+             * @param pendingIntent The pending intent which will be triggered on a reply.
+             * @param remoteInput The remote input parcelable which will carry the reply.
+             * @return This object for method chaining.
+             *
+             * @see CarExtender.UnreadConversation#getRemoteInput
+             * @see CarExtender.UnreadConversation#getReplyPendingIntent
+             */
+            public Builder setReplyAction(
+                    PendingIntent pendingIntent, RemoteInput remoteInput) {
+                mRemoteInput = remoteInput;
+                mReplyPendingIntent = pendingIntent;
+
+                return this;
+            }
+
+            /**
+             * Sets the pending intent that will be sent once the messages in this notification
+             * are read.
+             *
+             * @param pendingIntent The pending intent to use.
+             * @return This object for method chaining.
+             */
+            public Builder setReadPendingIntent(PendingIntent pendingIntent) {
+                mReadPendingIntent = pendingIntent;
+                return this;
+            }
+
+            /**
+             * Sets the timestamp of the most recent message in an unread conversation.
+             *
+             * If a messaging notification has been posted by your application and has not
+             * yet been cancelled, posting a later notification with the same id and tag
+             * but without a newer timestamp may result in Android Auto not displaying a
+             * heads up notification for the later notification.
+             *
+             * @param timestamp The timestamp of the most recent message in the conversation.
+             * @return This object for method chaining.
+             */
+            public Builder setLatestTimestamp(long timestamp) {
+                mLatestTimestamp = timestamp;
+                return this;
+            }
+
+            /**
+             * Builds a new unread conversation object.
+             *
+             * @return The new unread conversation object.
+             */
+            public UnreadConversation build() {
+                String[] messages = mMessages.toArray(new String[mMessages.size()]);
+                String[] participants = { mParticipant };
+                return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent,
+                        mReadPendingIntent, participants, mLatestTimestamp);
+            }
+        }
+    }
+
+    /**
      * Get an array of Notification objects from a parcelable array bundle field.
      * Update the bundle to have a typed array so fetches in the future don't need
      * to do an array copy.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index cf54107..479327d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -27,6 +27,9 @@
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.UserHandle;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.service.notification.ZenModeConfig;
 import android.util.Log;
 
 /**
@@ -276,5 +279,53 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public void setZenMode(int mode) {
+        INotificationManager service = getService();
+        try {
+            service.setZenMode(mode);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void requestZenModeConditions(IConditionListener listener, int relevance) {
+        INotificationManager service = getService();
+        try {
+            service.requestZenModeConditions(listener, relevance);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void setZenModeCondition(Condition exitCondition) {
+        INotificationManager service = getService();
+        try {
+            service.setZenModeCondition(exitCondition);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public Condition getZenModeCondition() {
+        INotificationManager service = getService();
+        try {
+            final ZenModeConfig config = service.getZenModeConfig();
+            if (config != null) {
+                return config.exitCondition;
+            }
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
     private Context mContext;
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 1691d8e..8abe223 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -25,33 +25,28 @@
 import android.content.res.Resources;
 import android.content.res.ResourcesKey;
 import android.hardware.display.DisplayManagerGlobal;
-import android.os.IBinder;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.Display;
-import android.view.DisplayAdjustments;
-
 import java.lang.ref.WeakReference;
 import java.util.Locale;
 
 /** @hide */
 public class ResourcesManager {
     static final String TAG = "ResourcesManager";
-    static final boolean DEBUG_CACHE = false;
-    static final boolean DEBUG_STATS = true;
+    private static final boolean DEBUG = false;
 
     private static ResourcesManager sResourcesManager;
-    final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources
-            = new ArrayMap<ResourcesKey, WeakReference<Resources> >();
-
-    final ArrayMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics
-            = new ArrayMap<DisplayAdjustments, DisplayMetrics>();
+    private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources =
+            new ArrayMap<>();
+    private final ArrayMap<Pair<Integer, Configuration>, WeakReference<Display>> mDisplays =
+            new ArrayMap<>();
 
     CompatibilityInfo mResCompatibilityInfo;
 
     Configuration mResConfiguration;
-    final Configuration mTmpConfig = new Configuration();
 
     public static ResourcesManager getInstance() {
         synchronized (ResourcesManager.class) {
@@ -66,46 +61,18 @@
         return mResConfiguration;
     }
 
-    public void flushDisplayMetricsLocked() {
-        mDefaultDisplayMetrics.clear();
+    DisplayMetrics getDisplayMetricsLocked() {
+        return getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
     }
 
-    public DisplayMetrics getDisplayMetricsLocked(int displayId) {
-        return getDisplayMetricsLocked(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
-    }
-
-    public DisplayMetrics getDisplayMetricsLocked(int displayId, DisplayAdjustments daj) {
-        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-        DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(daj) : null;
-        if (dm != null) {
-            return dm;
-        }
-        dm = new DisplayMetrics();
-
-        DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
-        if (displayManager == null) {
-            // may be null early in system startup
-            dm.setToDefaults();
-            return dm;
-        }
-
-        if (isDefaultDisplay) {
-            mDefaultDisplayMetrics.put(daj, dm);
-        }
-
-        Display d = displayManager.getCompatibleDisplay(displayId, daj);
-        if (d != null) {
-            d.getMetrics(dm);
+    DisplayMetrics getDisplayMetricsLocked(int displayId) {
+        DisplayMetrics dm = new DisplayMetrics();
+        final Display display = getAdjustedDisplay(displayId, Configuration.EMPTY);
+        if (display != null) {
+            display.getMetrics(dm);
         } else {
-            // Display no longer exists
-            // FIXME: This would not be a problem if we kept the Display object around
-            // instead of using the raw display id everywhere.  The Display object caches
-            // its information even after the display has been removed.
             dm.setToDefaults();
         }
-        //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
-        //        + metrics.heightPixels + " den=" + metrics.density
-        //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
         return dm;
     }
 
@@ -141,33 +108,67 @@
     }
 
     /**
+     * Returns an adjusted {@link Display} object based on the inputs or null if display isn't
+     * available.
+     *
+     * @param displayId display Id.
+     * @param overrideConfiguration override configurations.
+     */
+    public Display getAdjustedDisplay(final int displayId, Configuration overrideConfiguration) {
+        final Configuration configCopy = (overrideConfiguration != null)
+                ? new Configuration(overrideConfiguration) : new Configuration();
+        final Pair<Integer, Configuration> key = Pair.create(displayId, configCopy);
+        synchronized (this) {
+            WeakReference<Display> wd = mDisplays.get(key);
+            if (wd != null) {
+                final Display display = wd.get();
+                if (display != null) {
+                    return display;
+                }
+            }
+            final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+            if (dm == null) {
+                // may be null early in system startup
+                return null;
+            }
+            final Display display = dm.getRealDisplay(displayId, key.second);
+            if (display != null) {
+                mDisplays.put(key, new WeakReference<>(display));
+            }
+            return display;
+        }
+    }
+
+    /**
      * Creates the top level Resources for applications with the given compatibility info.
      *
      * @param resDir the resource directory.
+     * @param splitResDirs split resource directories.
      * @param overlayDirs the resource overlay directories.
      * @param libDirs the shared library resource dirs this app references.
-     * @param compatInfo the compability info. Must not be null.
-     * @param token the application token for determining stack bounds.
+     * @param displayId display Id.
+     * @param overrideConfiguration override configurations.
+     * @param compatInfo the compatibility info. Must not be null.
      */
-    public Resources getTopLevelResources(String resDir, String[] splitResDirs,
+    Resources getTopLevelResources(String resDir, String[] splitResDirs,
             String[] overlayDirs, String[] libDirs, int displayId,
-            Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
+            Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
         final float scale = compatInfo.applicationScale;
-        ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
+        Configuration overrideConfigCopy = (overrideConfiguration != null)
+                ? new Configuration(overrideConfiguration) : null;
+        ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
         Resources r;
         synchronized (this) {
             // Resources is app scale dependent.
-            if (false) {
-                Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
-            }
+            if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
+
             WeakReference<Resources> wr = mActiveResources.get(key);
             r = wr != null ? wr.get() : null;
             //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
             if (r != null && r.getAssets().isUpToDate()) {
-                if (false) {
-                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir
-                            + ": appScale=" + r.getCompatibilityInfo().applicationScale);
-                }
+                if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+                        + ": appScale=" + r.getCompatibilityInfo().applicationScale
+                        + " key=" + key + " overrideConfig=" + overrideConfiguration);
                 return r;
             }
         }
@@ -213,7 +214,7 @@
         //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
         DisplayMetrics dm = getDisplayMetricsLocked(displayId);
         Configuration config;
-        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+        final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
         final boolean hasOverrideConfig = key.hasOverrideConfiguration();
         if (!isDefaultDisplay || hasOverrideConfig) {
             config = new Configuration(getConfiguration());
@@ -222,16 +223,14 @@
             }
             if (hasOverrideConfig) {
                 config.updateFrom(key.mOverrideConfiguration);
+                if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);
             }
         } else {
             config = getConfiguration();
         }
-        r = new Resources(assets, dm, config, compatInfo, token);
-        if (false) {
-            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
-                    + r.getConfiguration() + " appScale="
-                    + r.getCompatibilityInfo().applicationScale);
-        }
+        r = new Resources(assets, dm, config, compatInfo);
+        if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+                + r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
 
         synchronized (this) {
             WeakReference<Resources> wr = mActiveResources.get(key);
@@ -244,24 +243,26 @@
             }
 
             // XXX need to remove entries when weak references go away
-            mActiveResources.put(key, new WeakReference<Resources>(r));
+            mActiveResources.put(key, new WeakReference<>(r));
+            if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());
             return r;
         }
     }
 
-    public final boolean applyConfigurationToResourcesLocked(Configuration config,
+    final boolean applyConfigurationToResourcesLocked(Configuration config,
             CompatibilityInfo compat) {
         if (mResConfiguration == null) {
             mResConfiguration = new Configuration();
         }
         if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
-            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+            if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
                     + mResConfiguration.seq + ", newSeq=" + config.seq);
             return false;
         }
         int changes = mResConfiguration.updateFrom(config);
-        flushDisplayMetricsLocked();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+        // Things might have changed in display manager, so clear the cached displays.
+        mDisplays.clear();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked();
 
         if (compat != null && (mResCompatibilityInfo == null ||
                 !mResCompatibilityInfo.equals(compat))) {
@@ -283,11 +284,11 @@
 
         Configuration tmpConfig = null;
 
-        for (int i=mActiveResources.size()-1; i>=0; i--) {
+        for (int i = mActiveResources.size() - 1; i >= 0; i--) {
             ResourcesKey key = mActiveResources.keyAt(i);
             Resources r = mActiveResources.valueAt(i).get();
             if (r != null) {
-                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+                if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                         + r + " config to: " + config);
                 int displayId = key.mDisplayId;
                 boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index af1810b..c719a0e 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -639,6 +639,12 @@
         public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
             return null;
         }
+
+        @Override
+        public ActionMode startActionModeForChild(
+                View child, ActionMode.Callback callback, int type) {
+            return null;
+        }
     }
 
     private boolean isEmpty(AutoCompleteTextView actv) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index a40b29a..fa27631 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -540,11 +540,6 @@
 
     private final Context mContext;
 
-    /**
-     * The package associated with this seach manager.
-     */
-    private String mAssociatedPackage;
-
     // package private since they are used by the inner class SearchManagerCallback
     /* package */ final Handler mHandler;
     /* package */ OnDismissListener mDismissListener = null;
@@ -742,10 +737,6 @@
     public void triggerSearch(String query,
                               ComponentName launchActivity,
                               Bundle appSearchData) {
-        if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
-            throw new IllegalArgumentException("invoking app search on a different package " +
-                    "not associated with this search manager");
-        }
         if (query == null || TextUtils.getTrimmedLength(query) == 0) {
             Log.w(TAG, "triggerSearch called with empty query, ignoring.");
             return;
@@ -978,7 +969,7 @@
             intent.setComponent(comp);
             if (inclContext) {
                 IActivityManager am = ActivityManagerNative.getDefault();
-                Bundle extras = am.getAssistContextExtras(0);
+                Bundle extras = am.getAssistContextExtras(ActivityManager.ASSIST_CONTEXT_BASIC);
                 if (extras != null) {
                     intent.replaceExtras(extras);
                 }
@@ -994,12 +985,12 @@
      * Launch an assist action for the current top activity.
      * @hide
      */
-    public boolean launchAssistAction(int requestType, String hint, int userHandle) {
+    public boolean launchAssistAction(String hint, int userHandle) {
         try {
             if (mService == null) {
                 return false;
             }
-            return mService.launchAssistAction(requestType, hint, userHandle);
+            return mService.launchAssistAction(hint, userHandle);
         } catch (RemoteException re) {
             Log.e(TAG, "launchAssistAction() failed: " + re);
             return false;
diff --git a/core/java/android/app/SearchableInfo.java b/core/java/android/app/SearchableInfo.java
index 922ebdd..c7d2140 100644
--- a/core/java/android/app/SearchableInfo.java
+++ b/core/java/android/app/SearchableInfo.java
@@ -19,6 +19,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.StringRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -682,6 +683,7 @@
      * @return A resource id, or {@code 0} if no language model was specified.
      * @see android.R.styleable#Searchable_voiceLanguageModel
      */
+    @StringRes
     public int getVoiceLanguageModeId() {
         return mVoiceLanguageModeId;
     }
@@ -692,6 +694,7 @@
      * @return A resource id, or {@code 0} if no voice prompt text was specified.
      * @see android.R.styleable#Searchable_voicePromptText
      */
+    @StringRes
     public int getVoicePromptTextId() {
         return mVoicePromptTextId;
     }
@@ -702,6 +705,7 @@
      * @return A resource id, or {@code 0} if no language was specified.
      * @see android.R.styleable#Searchable_voiceLanguage
      */
+    @StringRes
     public int getVoiceLanguageId() {
         return mVoiceLanguageId;
     }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index c8e0031..21a3543 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -498,6 +499,7 @@
      * @return Return an IBinder through which clients can call on to the 
      *         service.
      */
+    @Nullable
     public abstract IBinder onBind(Intent intent);
 
     /**
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 4427ce1..e617553 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.content.SharedPreferences;
 import android.os.FileUtils;
 import android.os.Looper;
@@ -217,7 +218,8 @@
         }
     }
 
-    public String getString(String key, String defValue) {
+    @Nullable
+    public String getString(String key, @Nullable String defValue) {
         synchronized (this) {
             awaitLoadedLocked();
             String v = (String)mMap.get(key);
@@ -225,7 +227,8 @@
         }
     }
 
-    public Set<String> getStringSet(String key, Set<String> defValues) {
+    @Nullable
+    public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
         synchronized (this) {
             awaitLoadedLocked();
             Set<String> v = (Set<String>) mMap.get(key);
@@ -303,13 +306,13 @@
         private final Map<String, Object> mModified = Maps.newHashMap();
         private boolean mClear = false;
 
-        public Editor putString(String key, String value) {
+        public Editor putString(String key, @Nullable String value) {
             synchronized (this) {
                 mModified.put(key, value);
                 return this;
             }
         }
-        public Editor putStringSet(String key, Set<String> values) {
+        public Editor putStringSet(String key, @Nullable Set<String> values) {
             synchronized (this) {
                 mModified.put(key,
                         (values == null) ? null : new HashSet<String>(values));
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
new file mode 100644
index 0000000..993f416
--- /dev/null
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.IDropBoxManagerService;
+
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.job.IJobScheduler;
+import android.app.job.JobScheduler;
+import android.app.trust.TrustManager;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManager;
+import android.appwidget.AppWidgetManager;
+import android.bluetooth.BluetoothManager;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.IRestrictionsManager;
+import android.content.RestrictionsManager;
+import android.content.pm.ILauncherApps;
+import android.content.pm.LauncherApps;
+import android.content.res.Resources;
+import android.hardware.ConsumerIrManager;
+import android.hardware.ISerialManager;
+import android.hardware.SensorManager;
+import android.hardware.SerialManager;
+import android.hardware.SystemSensorManager;
+import android.hardware.camera2.CameraManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlService;
+import android.hardware.input.InputManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbManager;
+import android.location.CountryDetector;
+import android.location.ICountryDetector;
+import android.location.ILocationManager;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.MediaRouter;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiManager;
+import android.media.projection.MediaProjectionManager;
+import android.media.session.MediaSessionManager;
+import android.media.tv.ITvInputManager;
+import android.media.tv.TvInputManager;
+import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IConnectivityManager;
+import android.net.IEthernetManager;
+import android.net.INetworkPolicyManager;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkScoreManager;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
+import android.net.wifi.IRttManager;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.RttManager;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.p2p.IWifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.passpoint.IWifiPasspointManager;
+import android.net.wifi.passpoint.WifiPasspointManager;
+import android.nfc.NfcManager;
+import android.os.BatteryManager;
+import android.os.DropBoxManager;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.IUserManager;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemVibrator;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.os.storage.StorageManager;
+import android.print.IPrintManager;
+import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.IFingerprintService;
+import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.PhoneLayoutInflater;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
+import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
+
+import java.util.HashMap;
+
+/**
+ * Manages all of the system services that can be returned by {@link Context#getSystemService}.
+ * Used by {@link ContextImpl}.
+ */
+final class SystemServiceRegistry {
+    private final static String TAG = "SystemServiceRegistry";
+
+    // Service registry information.
+    // This information is never changed once static initialization has completed.
+    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
+            new HashMap<Class<?>, String>();
+    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
+            new HashMap<String, ServiceFetcher<?>>();
+    private static int sServiceCacheSize;
+
+    // Not instantiable.
+    private SystemServiceRegistry() { }
+
+    static {
+        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
+                new CachedServiceFetcher<AccessibilityManager>() {
+            @Override
+            public AccessibilityManager createService(ContextImpl ctx) {
+                return AccessibilityManager.getInstance(ctx);
+            }});
+
+        registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
+                new CachedServiceFetcher<CaptioningManager>() {
+            @Override
+            public CaptioningManager createService(ContextImpl ctx) {
+                return new CaptioningManager(ctx);
+            }});
+
+        registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
+                new CachedServiceFetcher<AccountManager>() {
+            @Override
+            public AccountManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
+                IAccountManager service = IAccountManager.Stub.asInterface(b);
+                return new AccountManager(ctx, service);
+            }});
+
+        registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
+                new CachedServiceFetcher<ActivityManager>() {
+            @Override
+            public ActivityManager createService(ContextImpl ctx) {
+                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.ALARM_SERVICE, AlarmManager.class,
+                new CachedServiceFetcher<AlarmManager>() {
+            @Override
+            public AlarmManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
+                IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+                return new AlarmManager(service, ctx);
+            }});
+
+        registerService(Context.AUDIO_SERVICE, AudioManager.class,
+                new CachedServiceFetcher<AudioManager>() {
+            @Override
+            public AudioManager createService(ContextImpl ctx) {
+                return new AudioManager(ctx);
+            }});
+
+        registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
+                new CachedServiceFetcher<MediaRouter>() {
+            @Override
+            public MediaRouter createService(ContextImpl ctx) {
+                return new MediaRouter(ctx);
+            }});
+
+        registerService(Context.BLUETOOTH_SERVICE, BluetoothManager.class,
+                new CachedServiceFetcher<BluetoothManager>() {
+            @Override
+            public BluetoothManager createService(ContextImpl ctx) {
+                return new BluetoothManager(ctx);
+            }});
+
+        registerService(Context.HDMI_CONTROL_SERVICE, HdmiControlManager.class,
+                new StaticServiceFetcher<HdmiControlManager>() {
+            @Override
+            public HdmiControlManager createService() {
+                IBinder b = ServiceManager.getService(Context.HDMI_CONTROL_SERVICE);
+                return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
+            }});
+
+        registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
+                new CachedServiceFetcher<ClipboardManager>() {
+            @Override
+            public ClipboardManager createService(ContextImpl ctx) {
+                return new ClipboardManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        // The clipboard service moved to a new package.  If someone asks for the old
+        // interface by class then we want to redirect over to the new interface instead
+        // (which extends it).
+        SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
+
+        registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
+                new StaticServiceFetcher<ConnectivityManager>() {
+            @Override
+            public ConnectivityManager createService() {
+                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+                return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
+                new StaticServiceFetcher<CountryDetector>() {
+            @Override
+            public CountryDetector createService() {
+                IBinder b = ServiceManager.getService(Context.COUNTRY_DETECTOR);
+                return new CountryDetector(ICountryDetector.Stub.asInterface(b));
+            }});
+
+        registerService(Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class,
+                new CachedServiceFetcher<DevicePolicyManager>() {
+            @Override
+            public DevicePolicyManager createService(ContextImpl ctx) {
+                return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class,
+                new CachedServiceFetcher<DownloadManager>() {
+            @Override
+            public DownloadManager createService(ContextImpl ctx) {
+                return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+            }});
+
+        registerService(Context.BATTERY_SERVICE, BatteryManager.class,
+                new StaticServiceFetcher<BatteryManager>() {
+            @Override
+            public BatteryManager createService() {
+                return new BatteryManager();
+            }});
+
+        registerService(Context.NFC_SERVICE, NfcManager.class,
+                new CachedServiceFetcher<NfcManager>() {
+            @Override
+            public NfcManager createService(ContextImpl ctx) {
+                return new NfcManager(ctx);
+            }});
+
+        registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
+                new StaticServiceFetcher<DropBoxManager>() {
+            @Override
+            public DropBoxManager createService() {
+                IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE);
+                IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
+                if (service == null) {
+                    // Don't return a DropBoxManager that will NPE upon use.
+                    // This also avoids caching a broken DropBoxManager in
+                    // getDropBoxManager during early boot, before the
+                    // DROPBOX_SERVICE is registered.
+                    return null;
+                }
+                return new DropBoxManager(service);
+            }});
+
+        registerService(Context.INPUT_SERVICE, InputManager.class,
+                new StaticServiceFetcher<InputManager>() {
+            @Override
+            public InputManager createService() {
+                return InputManager.getInstance();
+            }});
+
+        registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
+                new CachedServiceFetcher<DisplayManager>() {
+            @Override
+            public DisplayManager createService(ContextImpl ctx) {
+                return new DisplayManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
+                new StaticServiceFetcher<InputMethodManager>() {
+            @Override
+            public InputMethodManager createService() {
+                return InputMethodManager.getInstance();
+            }});
+
+        registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
+                new StaticServiceFetcher<TextServicesManager>() {
+            @Override
+            public TextServicesManager createService() {
+                return TextServicesManager.getInstance();
+            }});
+
+        registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class,
+                new StaticServiceFetcher<KeyguardManager>() {
+            @Override
+            public KeyguardManager createService() {
+                return new KeyguardManager();
+            }});
+
+        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
+                new CachedServiceFetcher<LayoutInflater>() {
+            @Override
+            public LayoutInflater createService(ContextImpl ctx) {
+                return new PhoneLayoutInflater(ctx.getOuterContext());
+            }});
+
+        registerService(Context.LOCATION_SERVICE, LocationManager.class,
+                new CachedServiceFetcher<LocationManager>() {
+            @Override
+            public LocationManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+                return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class,
+                new StaticServiceFetcher<NetworkPolicyManager>() {
+            @Override
+            public NetworkPolicyManager createService() {
+                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)));
+            }});
+
+        registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
+                new CachedServiceFetcher<NotificationManager>() {
+            @Override
+            public NotificationManager createService(ContextImpl ctx) {
+                final Context outerContext = ctx.getOuterContext();
+                return new NotificationManager(
+                    new ContextThemeWrapper(outerContext,
+                            Resources.selectSystemTheme(0,
+                                    outerContext.getApplicationInfo().targetSdkVersion,
+                                    com.android.internal.R.style.Theme_Dialog,
+                                    com.android.internal.R.style.Theme_Holo_Dialog,
+                                    com.android.internal.R.style.Theme_DeviceDefault_Dialog,
+                                    com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
+                    ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.NSD_SERVICE, NsdManager.class,
+                new CachedServiceFetcher<NsdManager>() {
+            @Override
+            public NsdManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.NSD_SERVICE);
+                INsdManager service = INsdManager.Stub.asInterface(b);
+                return new NsdManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.POWER_SERVICE, PowerManager.class,
+                new CachedServiceFetcher<PowerManager>() {
+            @Override
+            public PowerManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
+                IPowerManager service = IPowerManager.Stub.asInterface(b);
+                if (service == null) {
+                    Log.wtf(TAG, "Failed to get power manager service.");
+                }
+                return new PowerManager(ctx.getOuterContext(),
+                        service, ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.SEARCH_SERVICE, SearchManager.class,
+                new CachedServiceFetcher<SearchManager>() {
+            @Override
+            public SearchManager createService(ContextImpl ctx) {
+                return new SearchManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.SENSOR_SERVICE, SensorManager.class,
+                new CachedServiceFetcher<SensorManager>() {
+            @Override
+            public SensorManager createService(ContextImpl ctx) {
+                return new SystemSensorManager(ctx.getOuterContext(),
+                  ctx.mMainThread.getHandler().getLooper());
+            }});
+
+        registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
+                new CachedServiceFetcher<StatusBarManager>() {
+            @Override
+            public StatusBarManager createService(ContextImpl ctx) {
+                return new StatusBarManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.STORAGE_SERVICE, StorageManager.class,
+                new CachedServiceFetcher<StorageManager>() {
+            @Override
+            public StorageManager createService(ContextImpl ctx) {
+                try {
+                    return new StorageManager(
+                            ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
+                } catch (RemoteException rex) {
+                    Log.e(TAG, "Failed to create StorageManager", rex);
+                    return null;
+                }
+            }});
+
+        registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
+                new CachedServiceFetcher<TelephonyManager>() {
+            @Override
+            public TelephonyManager createService(ContextImpl ctx) {
+                return new TelephonyManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+                new CachedServiceFetcher<SubscriptionManager>() {
+            @Override
+            public SubscriptionManager createService(ContextImpl ctx) {
+                return new SubscriptionManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.TELECOM_SERVICE, TelecomManager.class,
+                new CachedServiceFetcher<TelecomManager>() {
+            @Override
+            public TelecomManager createService(ContextImpl ctx) {
+                return new TelecomManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
+                new CachedServiceFetcher<UiModeManager>() {
+            @Override
+            public UiModeManager createService(ContextImpl ctx) {
+                return new UiModeManager();
+            }});
+
+        registerService(Context.USB_SERVICE, UsbManager.class,
+                new CachedServiceFetcher<UsbManager>() {
+            @Override
+            public UsbManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+                return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.SERIAL_SERVICE, SerialManager.class,
+                new CachedServiceFetcher<SerialManager>() {
+            @Override
+            public SerialManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.SERIAL_SERVICE);
+                return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
+                new CachedServiceFetcher<Vibrator>() {
+            @Override
+            public Vibrator createService(ContextImpl ctx) {
+                return new SystemVibrator(ctx);
+            }});
+
+        registerService(Context.WALLPAPER_SERVICE, WallpaperManager.class,
+                new CachedServiceFetcher<WallpaperManager>() {
+            @Override
+            public WallpaperManager createService(ContextImpl ctx) {
+                return new WallpaperManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.WIFI_SERVICE, WifiManager.class,
+                new CachedServiceFetcher<WifiManager>() {
+            @Override
+            public WifiManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_SERVICE);
+                IWifiManager service = IWifiManager.Stub.asInterface(b);
+                return new WifiManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
+                new CachedServiceFetcher<WifiPasspointManager>() {
+            @Override
+            public WifiPasspointManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
+                IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
+                return new WifiPasspointManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
+                new StaticServiceFetcher<WifiP2pManager>() {
+            @Override
+            public WifiP2pManager createService() {
+                IBinder b = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
+                IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
+                return new WifiP2pManager(service);
+            }});
+
+        registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
+                new CachedServiceFetcher<WifiScanner>() {
+            @Override
+            public WifiScanner createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
+                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+                return new WifiScanner(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
+                new CachedServiceFetcher<RttManager>() {
+            @Override
+            public RttManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE);
+                IRttManager service = IRttManager.Stub.asInterface(b);
+                return new RttManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
+                new CachedServiceFetcher<EthernetManager>() {
+            @Override
+            public EthernetManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ETHERNET_SERVICE);
+                IEthernetManager service = IEthernetManager.Stub.asInterface(b);
+                return new EthernetManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WINDOW_SERVICE, WindowManager.class,
+                new CachedServiceFetcher<WindowManager>() {
+            @Override
+            public WindowManager createService(ContextImpl ctx) {
+                return new WindowManagerImpl(ctx.getDisplay());
+            }});
+
+        registerService(Context.USER_SERVICE, UserManager.class,
+                new CachedServiceFetcher<UserManager>() {
+            @Override
+            public UserManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.USER_SERVICE);
+                IUserManager service = IUserManager.Stub.asInterface(b);
+                return new UserManager(ctx, service);
+            }});
+
+        registerService(Context.APP_OPS_SERVICE, AppOpsManager.class,
+                new CachedServiceFetcher<AppOpsManager>() {
+            @Override
+            public AppOpsManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+                IAppOpsService service = IAppOpsService.Stub.asInterface(b);
+                return new AppOpsManager(ctx, service);
+            }});
+
+        registerService(Context.CAMERA_SERVICE, CameraManager.class,
+                new CachedServiceFetcher<CameraManager>() {
+            @Override
+            public CameraManager createService(ContextImpl ctx) {
+                return new CameraManager(ctx);
+            }});
+
+        registerService(Context.LAUNCHER_APPS_SERVICE, LauncherApps.class,
+                new CachedServiceFetcher<LauncherApps>() {
+            @Override
+            public LauncherApps createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE);
+                ILauncherApps service = ILauncherApps.Stub.asInterface(b);
+                return new LauncherApps(ctx, service);
+            }});
+
+        registerService(Context.RESTRICTIONS_SERVICE, RestrictionsManager.class,
+                new CachedServiceFetcher<RestrictionsManager>() {
+            @Override
+            public RestrictionsManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.RESTRICTIONS_SERVICE);
+                IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
+                return new RestrictionsManager(ctx, service);
+            }});
+
+        registerService(Context.PRINT_SERVICE, PrintManager.class,
+                new CachedServiceFetcher<PrintManager>() {
+            @Override
+            public PrintManager createService(ContextImpl ctx) {
+                IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
+                IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
+                return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
+                        UserHandle.getAppId(Process.myUid()));
+            }});
+
+        registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
+                new CachedServiceFetcher<ConsumerIrManager>() {
+            @Override
+            public ConsumerIrManager createService(ContextImpl ctx) {
+                return new ConsumerIrManager(ctx);
+            }});
+
+        registerService(Context.MEDIA_SESSION_SERVICE, MediaSessionManager.class,
+                new CachedServiceFetcher<MediaSessionManager>() {
+            @Override
+            public MediaSessionManager createService(ContextImpl ctx) {
+                return new MediaSessionManager(ctx);
+            }});
+
+        registerService(Context.TRUST_SERVICE, TrustManager.class,
+                new StaticServiceFetcher<TrustManager>() {
+            @Override
+            public TrustManager createService() {
+                IBinder b = ServiceManager.getService(Context.TRUST_SERVICE);
+                return new TrustManager(b);
+            }});
+
+        registerService(Context.FINGERPRINT_SERVICE, FingerprintManager.class,
+                new CachedServiceFetcher<FingerprintManager>() {
+            @Override
+            public FingerprintManager createService(ContextImpl ctx) {
+                IBinder binder = ServiceManager.getService(Context.FINGERPRINT_SERVICE);
+                IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
+                return new FingerprintManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
+                new StaticServiceFetcher<TvInputManager>() {
+            @Override
+            public TvInputManager createService() {
+                IBinder iBinder = ServiceManager.getService(Context.TV_INPUT_SERVICE);
+                ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
+                return new TvInputManager(service, UserHandle.myUserId());
+            }});
+
+        registerService(Context.NETWORK_SCORE_SERVICE, NetworkScoreManager.class,
+                new CachedServiceFetcher<NetworkScoreManager>() {
+            @Override
+            public NetworkScoreManager createService(ContextImpl ctx) {
+                return new NetworkScoreManager(ctx);
+            }});
+
+        registerService(Context.USAGE_STATS_SERVICE, UsageStatsManager.class,
+                new CachedServiceFetcher<UsageStatsManager>() {
+            @Override
+            public UsageStatsManager createService(ContextImpl ctx) {
+                IBinder iBinder = ServiceManager.getService(Context.USAGE_STATS_SERVICE);
+                IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
+                return new UsageStatsManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
+                new StaticServiceFetcher<JobScheduler>() {
+            @Override
+            public JobScheduler createService() {
+                IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE);
+                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
+            }});
+
+        registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
+                new StaticServiceFetcher<PersistentDataBlockManager>() {
+            @Override
+            public PersistentDataBlockManager createService() {
+                IBinder b = ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+                IPersistentDataBlockService persistentDataBlockService =
+                        IPersistentDataBlockService.Stub.asInterface(b);
+                if (persistentDataBlockService != null) {
+                    return new PersistentDataBlockManager(persistentDataBlockService);
+                } else {
+                    // not supported
+                    return null;
+                }
+            }});
+
+        registerService(Context.MEDIA_PROJECTION_SERVICE, MediaProjectionManager.class,
+                new CachedServiceFetcher<MediaProjectionManager>() {
+            @Override
+            public MediaProjectionManager createService(ContextImpl ctx) {
+                return new MediaProjectionManager(ctx);
+            }});
+
+        registerService(Context.APPWIDGET_SERVICE, AppWidgetManager.class,
+                new CachedServiceFetcher<AppWidgetManager>() {
+            @Override
+            public AppWidgetManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+                return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
+            }});
+
+        registerService(Context.MIDI_SERVICE, MidiManager.class,
+                new CachedServiceFetcher<MidiManager>() {
+            @Override
+            public MidiManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.MIDI_SERVICE);
+                return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
+            }});
+    }
+
+    /**
+     * Creates an array which is used to cache per-Context service instances.
+     */
+    public static Object[] createServiceCache() {
+        return new Object[sServiceCacheSize];
+    }
+
+    /**
+     * Gets a system service from a given context.
+     */
+    public static Object getSystemService(ContextImpl ctx, String name) {
+        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
+        return fetcher != null ? fetcher.getService(ctx) : null;
+    }
+
+    /**
+     * Gets the name of the system-level service that is represented by the specified class. 
+     */
+    public static String getSystemServiceName(Class<?> serviceClass) {
+        return SYSTEM_SERVICE_NAMES.get(serviceClass);
+    }
+
+    /**
+     * Statically registers a system service with the context.
+     * This method must be called during static initialization only.
+     */
+    private static <T> void registerService(String serviceName, Class<T> serviceClass,
+            ServiceFetcher<T> serviceFetcher) {
+        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
+        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
+    }
+
+    /**
+     * Base interface for classes that fetch services.
+     * These objects must only be created during static initialization.
+     */
+    static abstract interface ServiceFetcher<T> {
+        T getService(ContextImpl ctx);
+    }
+
+    /**
+     * Override this class when the system service constructor needs a
+     * ContextImpl and should be cached and retained by that context.
+     */
+    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
+        private final int mCacheIndex;
+
+        public CachedServiceFetcher() {
+            mCacheIndex = sServiceCacheSize++;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final T getService(ContextImpl ctx) {
+            final Object[] cache = ctx.mServiceCache;
+            synchronized (cache) {
+                // Fetch or create the service.
+                Object service = cache[mCacheIndex];
+                if (service == null) {
+                    service = createService(ctx);
+                    cache[mCacheIndex] = service;
+                }
+                return (T)service;
+            }
+        }
+
+        public abstract T createService(ContextImpl ctx);
+    }
+
+    /**
+     * Override this class when the system service does not need a ContextImpl
+     * and should be cached and retained process-wide.
+     */
+    static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
+        private T mCachedInstance;
+
+        @Override
+        public final T getService(ContextImpl unused) {
+            synchronized (StaticServiceFetcher.this) {
+                if (mCachedInstance == null) {
+                    mCachedInstance = createService();
+                }
+                return mCachedInstance;
+            }
+        }
+
+        public abstract T createService();
+    }
+}
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 3a2c21b..a3b3022 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -31,20 +31,21 @@
 import com.android.internal.R;
 
 /**
- * A dialog that prompts the user for the time of day using a {@link TimePicker}.
+ * A dialog that prompts the user for the time of day using a
+ * {@link TimePicker}.
  *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
  */
 public class TimePickerDialog extends AlertDialog implements OnClickListener,
         OnTimeChangedListener {
-
     private static final String HOUR = "hour";
     private static final String MINUTE = "minute";
     private static final String IS_24_HOUR = "is24hour";
 
     private final TimePicker mTimePicker;
-    private final OnTimeSetListener mTimeSetCallback;
+    private final OnTimeSetListener mTimeSetListener;
 
     private final int mInitialHourOfDay;
     private final int mInitialMinute;
@@ -52,59 +53,70 @@
 
     /**
      * The callback interface used to indicate the user is done filling in
-     * the time (they clicked on the 'Done' button).
+     * the time (e.g. they clicked on the 'OK' button).
      */
     public interface OnTimeSetListener {
-
         /**
-         * @param view The view associated with this listener.
-         * @param hourOfDay The hour that was set.
-         * @param minute The minute that was set.
+         * Called when the user is done setting a new time and the dialog has
+         * closed.
+         *
+         * @param view the view associated with this listener
+         * @param hourOfDay the hour that was set
+         * @param minute the minute that was set
          */
-        void onTimeSet(TimePicker view, int hourOfDay, int minute);
+        public void onTimeSet(TimePicker view, int hourOfDay, int minute);
     }
 
     /**
-     * @param context Parent.
-     * @param callBack How parent is notified.
-     * @param hourOfDay The initial hour.
-     * @param minute The initial minute.
-     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
+     * Creates a new time picker dialog.
+     *
+     * @param context the parent context
+     * @param listener the listener to call when the time is set
+     * @param hourOfDay the initial hour
+     * @param minute the initial minute
+     * @param is24HourView whether this is a 24 hour view or AM/PM
      */
-    public TimePickerDialog(Context context,
-            OnTimeSetListener callBack,
-            int hourOfDay, int minute, boolean is24HourView) {
-        this(context, 0, callBack, hourOfDay, minute, is24HourView);
+    public TimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute,
+            boolean is24HourView) {
+        this(context, 0, listener, hourOfDay, minute, is24HourView);
     }
 
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == 0) {
+    static int resolveDialogTheme(Context context, int resId) {
+        if (resId == 0) {
             final TypedValue outValue = new TypedValue();
             context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
             return outValue.resourceId;
         } else {
-            return resid;
+            return resId;
         }
     }
 
     /**
-     * @param context Parent.
-     * @param theme the theme to apply to this dialog
-     * @param callBack How parent is notified.
-     * @param hourOfDay The initial hour.
-     * @param minute The initial minute.
+     * Creates a new time picker dialog with the specified theme.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme to apply to this dialog
+     * @param listener the listener to call when the time is set
+     * @param hourOfDay the initial hour
+     * @param minute the initial minute
      * @param is24HourView Whether this is a 24 hour view, or AM/PM.
      */
-    public TimePickerDialog(Context context, int theme, OnTimeSetListener callBack, int hourOfDay,
-            int minute, boolean is24HourView) {
-        super(context, resolveDialogTheme(context, theme));
+    public TimePickerDialog(Context context, int themeResId, OnTimeSetListener listener,
+            int hourOfDay, int minute, boolean is24HourView) {
+        super(context, resolveDialogTheme(context, themeResId));
 
-        mTimeSetCallback = callBack;
+        mTimeSetListener = listener;
         mInitialHourOfDay = hourOfDay;
         mInitialMinute = minute;
         mIs24HourView = is24HourView;
 
         final Context themeContext = getContext();
+
+
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
+        final int layoutResId = outValue.resourceId;
+
         final LayoutInflater inflater = LayoutInflater.from(themeContext);
         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
@@ -129,8 +141,8 @@
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
             case BUTTON_POSITIVE:
-                if (mTimeSetCallback != null) {
-                    mTimeSetCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+                if (mTimeSetListener != null) {
+                    mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                             mTimePicker.getCurrentMinute());
                 }
                 break;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0a255f7..0f6ce12 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -219,10 +219,9 @@
     }
 
     /**
-     * Returns the currently configured night mode.
-     *
-     * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or
-     *  {@link #MODE_NIGHT_AUTO}.  When an error occurred -1 is returned.
+     * @return the currently configured night mode. May be one of
+     *         {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
+     *         {@link #MODE_NIGHT_AUTO}, or -1 on error.
      */
     public int getNightMode() {
         if (mService != null) {
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 723cb9b..7b84cb4 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -16,7 +16,6 @@
 
 package android.app;
 
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -34,7 +33,6 @@
 import java.util.ArrayList;
 
 /**
- * @hide
  * Interface for an {@link Activity} to interact with the user through voice.  Use
  * {@link android.app.Activity#getVoiceInteractor() Activity.getVoiceInteractor}
  * to retrieve the interface, if the activity is currently involved in a voice interaction.
@@ -56,7 +54,6 @@
  * request, rather than holding on to the activity instance yourself, either explicitly
  * or implicitly through a non-static inner class.
  */
-@SystemApi
 public class VoiceInteractor {
     static final String TAG = "VoiceInteractor";
     static final boolean DEBUG = true;
@@ -108,9 +105,10 @@
                     request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0);
                     if (DEBUG) Log.d(TAG, "onCommandResult: req="
                             + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
-                            + " result=" + args.arg2);
+                            + " completed=" + msg.arg1 + " result=" + args.arg2);
                     if (request != null) {
-                        ((CommandRequest)request).onCommandResult((Bundle) args.arg2);
+                        ((CommandRequest)request).onCommandResult(msg.arg1 != 0,
+                                (Bundle) args.arg2);
                         if (msg.arg1 != 0) {
                             request.clear();
                         }
@@ -158,8 +156,8 @@
 
         @Override
         public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
-            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
-                    MSG_CANCEL_RESULT, request));
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(
+                    MSG_CANCEL_RESULT, request, null));
         }
     };
 
@@ -321,7 +319,7 @@
          * complete an action (e.g. booking a table might have several possible times that the
          * user could select from or an app might need the user to agree to a terms of service).
          * The result of the confirmation will be returned through an asynchronous call to
-         * either {@link #onCommandResult(android.os.Bundle)} or
+         * either {@link #onCommandResult(boolean, android.os.Bundle)} or
          * {@link #onCancel()}.
          *
          * <p>The command is a string that describes the generic operation to be performed.
@@ -338,7 +336,12 @@
             mArgs = args;
         }
 
-        public void onCommandResult(Bundle result) {
+        /**
+         * Results for CommandRequest can be returned in partial chunks.
+         * The isCompleted is set to true iff all results have been returned, indicating the
+         * CommandRequest has completed.
+         */
+        public void onCommandResult(boolean isCompleted, Bundle result) {
         }
 
         IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8bfe6d3..22e79b6 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.RawRes;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -63,7 +64,10 @@
  * Provides access to the system wallpaper. With WallpaperManager, you can
  * get the current wallpaper, get the desired dimensions for the wallpaper, set
  * the wallpaper, and more. Get an instance of WallpaperManager with
- * {@link #getInstance(android.content.Context) getInstance()}. 
+ * {@link #getInstance(android.content.Context) getInstance()}.
+ *
+ * <p> An app can check whether wallpapers are supported for the current user, by calling
+ * {@link #isWallpaperSupported()}.
  */
 public class WallpaperManager {
     private static String TAG = "WallpaperManager";
@@ -187,7 +191,7 @@
         }
 
         @Override
-        public void setColorFilter(ColorFilter cf) {
+        public void setColorFilter(ColorFilter colorFilter) {
             throw new UnsupportedOperationException("Not supported with this drawable");
         }
 
@@ -248,6 +252,15 @@
 
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
             synchronized (this) {
+                if (mService != null) {
+                    try {
+                        if (!mService.isWallpaperSupported(context.getOpPackageName())) {
+                            return null;
+                        }
+                    } catch (RemoteException e) {
+                        // Ignore
+                    }
+                }
                 if (mWallpaper != null) {
                     return mWallpaper;
                 }
@@ -617,7 +630,9 @@
      * wallpaper will require reloading it again from disk.
      */
     public void forgetLoadedWallpaper() {
-        sGlobals.forgetLoadedWallpaper();
+        if (isWallpaperSupported()) {
+            sGlobals.forgetLoadedWallpaper();
+        }
     }
 
     /**
@@ -707,7 +722,7 @@
      * @throws IOException If an error occurs reverting to the built-in
      * wallpaper.
      */
-    public void setResource(int resid) throws IOException {
+    public void setResource(@RawRes int resid) throws IOException {
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             return;
@@ -716,7 +731,7 @@
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
-                    "res:" + resources.getResourceName(resid));
+                    "res:" + resources.getResourceName(resid), mContext.getOpPackageName());
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -752,7 +767,8 @@
             return;
         }
         try {
-            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+                    mContext.getOpPackageName());
             if (fd == null) {
                 return;
             }
@@ -791,7 +807,8 @@
             return;
         }
         try {
-            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
+            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
+                    mContext.getOpPackageName());
             if (fd == null) {
                 return;
             }
@@ -823,7 +840,7 @@
      * with the given resource ID.  That is, their wallpaper has been
      * set through {@link #setResource(int)} with the same resource id.
      */
-    public boolean hasResourceWallpaper(int resid) {
+    public boolean hasResourceWallpaper(@RawRes int resid) {
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
             return false;
@@ -944,7 +961,8 @@
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
             } else {
-                sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+                sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight,
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             // Ignore
@@ -965,7 +983,7 @@
             if (sGlobals.mService == null) {
                 Log.w(TAG, "WallpaperService not running");
             } else {
-                sGlobals.mService.setDisplayPadding(padding);
+                sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             // Ignore
@@ -994,6 +1012,47 @@
     }
 
     /**
+     * Clear the wallpaper.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void clearWallpaper() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return;
+        }
+        try {
+            sGlobals.mService.clearWallpaper(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Set the live wallpaper.
+     *
+     * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
+     * permission.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean setWallpaperComponent(ComponentName name) {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return false;
+        }
+        try {
+            sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
+            return true;
+        } catch (RemoteException e) {
+            // Ignore
+        }
+        return false;
+    }
+
+    /**
      * Set the position of the current wallpaper within any larger space, when
      * that wallpaper is visible behind the given window.  The X and Y offsets
      * are floating point numbers ranging from 0 to 1, representing where the
@@ -1054,7 +1113,24 @@
             // Ignore.
         }
     }
-    
+
+    /**
+     * Returns whether wallpapers are supported for the calling user. If this function returns
+     * false, any attempts to changing the wallpaper will have no effect.
+     */
+    public boolean isWallpaperSupported() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+        } else {
+            try {
+                return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        return false;
+    }
+
     /**
      * Clear the offsets previously associated with this window through
      * {@link #setWallpaperOffsets(IBinder, float, float)}.  This reverts
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 3074b49..d1e40ae 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -165,15 +165,24 @@
     /** @hide */
     public static class PolicyInfo {
         public final int ident;
-        final public String tag;
-        final public int label;
-        final public int description;
+        public final String tag;
+        public final int label;
+        public final int description;
+        public final int labelForSecondaryUsers;
+        public final int descriptionForSecondaryUsers;
 
-        public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
-            ident = identIn;
-            tag = tagIn;
-            label = labelIn;
-            description = descriptionIn;
+        public PolicyInfo(int ident, String tag, int label, int description) {
+            this(ident, tag, label, description, label, description);
+        }
+
+        public PolicyInfo(int ident, String tag, int label, int description,
+                int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
+            this.ident = ident;
+            this.tag = tag;
+            this.label = label;
+            this.description = description;
+            this.labelForSecondaryUsers = labelForSecondaryUsers;
+            this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
         }
     }
 
@@ -184,7 +193,10 @@
     static {
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
                 com.android.internal.R.string.policylab_wipeData,
-                com.android.internal.R.string.policydesc_wipeData));
+                com.android.internal.R.string.policydesc_wipeData,
+                com.android.internal.R.string.policylab_wipeData_secondaryUser,
+                com.android.internal.R.string.policydesc_wipeData_secondaryUser
+                ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
                 com.android.internal.R.string.policylab_resetPassword,
                 com.android.internal.R.string.policydesc_resetPassword));
@@ -193,7 +205,10 @@
                 com.android.internal.R.string.policydesc_limitPassword));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
                 com.android.internal.R.string.policylab_watchLogin,
-                com.android.internal.R.string.policydesc_watchLogin));
+                com.android.internal.R.string.policydesc_watchLogin,
+                com.android.internal.R.string.policylab_watchLogin,
+                com.android.internal.R.string.policydesc_watchLogin_secondaryUser
+        ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
                 com.android.internal.R.string.policylab_forceLock,
                 com.android.internal.R.string.policydesc_forceLock));
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index c53e749..fe284ce 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.security.KeyChain;
 
 /**
  * Base class for implementing a device administration component.  This
@@ -167,8 +168,8 @@
 
     /**
      * Action sent to a device administrator to notify that the device is entering
-     * lock task mode from an authorized package.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
-     * will describe the authorized package using lock task mode.
+     * lock task mode.  The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
+     * will describe the package using lock task mode.
      *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
@@ -181,7 +182,7 @@
 
     /**
      * Action sent to a device administrator to notify that the device is exiting
-     * lock task mode from an authorized package.
+     * lock task mode.
      *
      * <p>The calling device admin must be the device owner or profile
      * owner to receive this broadcast.
@@ -214,7 +215,8 @@
      * <p>A device admin application which listens to this intent can find out if the device was
      * provisioned for the device owner or profile owner case by calling respectively
      * {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
-     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
+     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle
+     * this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.
      *
      * <p>Input: Nothing.</p>
      * <p>Output: Nothing</p>
@@ -224,6 +226,44 @@
             "android.app.action.PROFILE_PROVISIONING_COMPLETE";
 
     /**
+     * Broadcast Action: This broadcast is sent to indicate that the system is ready for the device
+     * initializer to perform user setup tasks. This is only applicable to devices managed by a
+     * device owner app.
+     *
+     * <p>The broadcast will be limited to the {@link DeviceAdminReceiver} component specified in
+     * the (@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME) field
+     * of the original intent or NFC bump that started the provisioning process. You will generally
+     * handle this in {@link DeviceAdminReceiver#onReadyForUserInitialization}.
+     *
+     * <p>Input: Nothing.</p>
+     * <p>Output: Nothing</p>
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_READY_FOR_USER_INITIALIZATION =
+            "android.app.action.READY_FOR_USER_INITIALIZATION";
+
+    /** @hide */
+    public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID = "android.app.extra.CHOOSE_PRIVATE_KEY_SENDER_UID";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_HOST = "android.app.extra.CHOOSE_PRIVATE_KEY_HOST";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_PORT = "android.app.extra.CHOOSE_PRIVATE_KEY_PORT";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_URL = "android.app.extra.CHOOSE_PRIVATE_KEY_URL";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.extra.CHOOSE_PRIVATE_KEY_ALIAS";
+
+    /** @hide */
+    public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
+
+    /**
      * Name under which a DevicePolicy component publishes information
      * about itself.  This meta-data must reference an XML resource containing
      * a device-admin tag.
@@ -360,20 +400,20 @@
     /**
      * Called when provisioning of a managed profile or managed device has completed successfully.
      *
-     * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
+     * <p> As a prerequisite for the execution of this callback the {@link DeviceAdminReceiver} has
      * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
      * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
      * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
      * managed provisioning.
      *
-     * <p>When provisioning is complete, the managed profile is hidden until the profile owner
-     * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
-     * owner will enable the profile when it has finished any additional setup such as adding an
-     * account by using the {@link AccountManager} and calling apis to bring the profile into the
-     * desired state.
+     * <p>When provisioning of a managed profile is complete, the managed profile is hidden until
+     * the profile owner calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
+     * Typically a profile owner will enable the profile when it has finished any additional setup
+     * such as adding an account by using the {@link AccountManager} and calling apis to bring the
+     * profile into the desired state.
      *
      * <p> Note that provisioning completes without waiting for any server interactions, so the
-     * profile owner needs to wait for data to be available if required (e.g android device ids or
+     * profile owner needs to wait for data to be available if required (e.g. android device ids or
      * other data that is set as a result of server interactions).
      *
      * @param context The running context as per {@link #onReceive}.
@@ -383,8 +423,31 @@
     }
 
     /**
-     * Called when a device is entering lock task mode by a package authorized
-     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     * Called during provisioning of a managed device to allow the device initializer to perform
+     * user setup steps. Only device initializers should override this method.
+     *
+     * <p> Called when the DeviceAdminReceiver receives a
+     * {@link #ACTION_READY_FOR_USER_INITIALIZATION} broadcast. As a prerequisite for the execution
+     * of this callback the {@link DeviceAdminReceiver} has
+     * to declare an intent filter for {@link #ACTION_READY_FOR_USER_INITIALIZATION}. Only the
+     * component specified in the
+     * {@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME} field of the
+     * original intent or NFC bump that started the provisioning process will receive this callback.
+     *
+     * <p>It is not assumed that the device initializer is finished when it returns from
+     * this call, as it may do additional setup asynchronously. The device initializer must call
+     * {DevicePolicyManager#setUserEnabled(ComponentName admin)} when it has finished any additional
+     * setup (such as adding an account by using the {@link AccountManager}) in order for the user
+     * to be functional.
+     *
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     */
+    public void onReadyForUserInitialization(Context context, Intent intent) {
+    }
+
+    /**
+     * Called when a device is entering lock task mode.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -394,8 +457,7 @@
     }
 
     /**
-     * Called when a device is exiting lock task mode by a package authorized
-     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
+     * Called when a device is exiting lock task mode.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -404,6 +466,26 @@
     }
 
     /**
+     * Allows this receiver to select the alias for a private key and certificate pair for
+     * authentication. If this method returns null, the default {@link android.app.Activity} will be
+     * shown that lets the user pick a private key and certificate pair.
+     *
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     * @param uid The uid asking for the private key and certificate pair.
+     * @param host The authentication host, may be null.
+     * @param port The authentication port, or -1.
+     * @param url The URL to authenticate, may be null.
+     * @param alias The alias preselected by the client, or null.
+     * @return The private key alias to return and grant access to.
+     * @see KeyChain#choosePrivateKeyAlias
+     */
+    public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, String host,
+            int port, String url, String alias) {
+        return null;
+    }
+
+    /**
      * Intercept standard device administrator broadcasts.  Implementations
      * should not override this method; it is better to implement the
      * convenience callbacks for each action.
@@ -432,11 +514,22 @@
             onPasswordExpiring(context, intent);
         } else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
             onProfileProvisioningComplete(context, intent);
+        } else if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) {
+            int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1);
+            String host = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_HOST);
+            int port = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_PORT, -1);
+            String url = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_URL);
+            String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS);
+            String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, host, port, url,
+                    alias);
+            setResultData(chosenAlias);
         } else if (ACTION_LOCK_TASK_ENTERING.equals(action)) {
             String pkg = intent.getStringExtra(EXTRA_LOCK_TASK_PACKAGE);
             onLockTaskModeEntering(context, intent, pkg);
         } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
             onLockTaskModeExiting(context, intent);
+        } else if (ACTION_READY_FOR_USER_INITIALIZATION.equals(action)) {
+            onReadyForUserInitialization(context, intent);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a01a96a..245db06 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.Handler;
@@ -41,7 +42,6 @@
 import android.provider.Settings;
 import android.security.Credentials;
 import android.service.restrictions.RestrictionsReceiver;
-import android.service.trust.TrustAgentService;
 import android.util.Log;
 
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -52,11 +52,15 @@
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.security.KeyFactory;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -64,7 +68,7 @@
 /**
  * Public interface for managing policies enforced on a device. Most clients of this class must be
  * registered with the system as a
- * <a href={@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
+ * <a href="{@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
  * a device administrator may be registered as either a profile or device owner. A given method is
  * accessible to all device administrators unless the documentation for that method specifies that
  * it is restricted to either device or profile owners.
@@ -105,11 +109,17 @@
      * Provisioning adds a managed profile and sets the MDM as the profile owner who has full
      * control over the profile.
      *
-     * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the
+     * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain the extra
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported.
      *
-     * <p> When managed provisioning has completed, an intent of the type
-     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcast to the
-     * managed profile.
+     * <p> When managed provisioning has completed, broadcasts are sent to the application specified
+     * in the provisioning intent. The
+     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
+     * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
+     * the primary profile.
      *
      * <p> If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
@@ -144,11 +154,36 @@
      *
      * <p>This package is set as device owner when device owner provisioning is started by an NFC
      * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
+     *
+     * <p> When this extra is set, the application must have exactly one device admin receiver.
+     * This receiver will be set as the profile or device owner and active admin.</p>
+
+     * @see DeviceAdminReceiver
+     * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
+     * supported.
      */
+    @Deprecated
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
 
     /**
+     * A ComponentName extra indicating the device admin receiver of the mobile device management
+     * application that will be set as the profile owner or device owner and active admin.
+     *
+     * <p>If an application starts provisioning directly via an intent with action
+     * {@link #ACTION_PROVISION_MANAGED_PROFILE} the package name of this component has to match the
+     * package name of the application that started provisioning.
+     *
+     * <p>This component is set as device owner and active admin when device owner provisioning is
+     * started by an NFC message containing an NFC record with MIME type
+     * {@link #MIME_TYPE_PROVISIONING_NFC}.
+     *
+     * @see DeviceAdminReceiver
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
+        = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+
+    /**
      * An {@link android.accounts.Account} extra holding the account to migrate during managed
      * profile provisioning. If the account supplied is present in the primary user, it will be
      * copied, along with its credentials to the managed profile and removed from the primary user.
@@ -328,6 +363,76 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
 
     /**
+     * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
+     * has completed successfully.
+     *
+     * <p>The broadcast is limited to the primary profile, to the app specified in the provisioning
+     * intent (@see #ACTION_PROVISION_MANAGED_PROFILE).
+     *
+     * <p>This intent will contain the extra {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} which
+     * corresponds to the account requested to be migrated at provisioning time, if any.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGED_PROFILE_PROVISIONED
+        = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+
+    /**
+     * A boolean extra indicating whether device encryption is required as part of Device Owner
+     * provisioning.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
+             "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+
+    /**
+     * On devices managed by a device owner app, a String representation of a Component name extra
+     * indicating the component of the application that is temporarily granted device owner
+     * privileges during device initialization and profile owner privileges during secondary user
+     * initialization.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     * @see ComponentName#unflattenFromString()
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+
+    /**
+     * A String extra holding an http url that specifies the download location of the device
+     * initializer package. When not provided it is assumed that the device initializer package is
+     * already installed.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
+
+    /**
+     * A String extra holding a http cookie header which should be used in the http request to the
+     * url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+
+    /**
+     * A String extra holding the SHA-1 checksum of the file at download location specified in
+     * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
+     * match the file at the download location an error will be shown to the user and the user will
+     * be asked to factory reset the device.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
+        = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
+
+    /**
      * This MIME type is used for starting the Device Owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -343,7 +448,6 @@
      * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
      * contains the following properties:
      * <ul>
-     * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li>
@@ -357,7 +461,17 @@
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
      * <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
-     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li></ul>
+     * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
+     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
+     *
+     * <p>
+     * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
+     * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain
+     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although
+     * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
+     * This componentName must have been converted to a String via
+     * {@link android.content.ComponentName#flattenToString()}
      *
      * <p> When device owner provisioning has completed, an intent of the type
      * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -690,7 +804,7 @@
     public void setPasswordQuality(ComponentName admin, int quality) {
         if (mService != null) {
             try {
-                mService.setPasswordQuality(admin, quality, UserHandle.myUserId());
+                mService.setPasswordQuality(admin, quality);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -743,7 +857,7 @@
     public void setPasswordMinimumLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLength(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLength(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -797,7 +911,7 @@
     public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumUpperCase(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumUpperCase(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -858,7 +972,7 @@
     public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLowerCase(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLowerCase(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -918,7 +1032,7 @@
     public void setPasswordMinimumLetters(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLetters(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumLetters(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -976,7 +1090,7 @@
     public void setPasswordMinimumNumeric(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNumeric(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumNumeric(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1035,7 +1149,7 @@
     public void setPasswordMinimumSymbols(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumSymbols(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumSymbols(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1093,7 +1207,7 @@
     public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNonLetter(admin, length, UserHandle.myUserId());
+                mService.setPasswordMinimumNonLetter(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1153,7 +1267,7 @@
     public void setPasswordHistoryLength(ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordHistoryLength(admin, length, UserHandle.myUserId());
+                mService.setPasswordHistoryLength(admin, length);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1185,7 +1299,7 @@
     public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
         if (mService != null) {
             try {
-                mService.setPasswordExpirationTimeout(admin, timeout, UserHandle.myUserId());
+                mService.setPasswordExpirationTimeout(admin, timeout);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1330,7 +1444,7 @@
     public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
         if (mService != null) {
             try {
-                mService.setMaximumFailedPasswordsForWipe(admin, num, UserHandle.myUserId());
+                mService.setMaximumFailedPasswordsForWipe(admin, num);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1414,7 +1528,7 @@
     public boolean resetPassword(String password, int flags) {
         if (mService != null) {
             try {
-                return mService.resetPassword(password, flags, UserHandle.myUserId());
+                return mService.resetPassword(password, flags);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1438,7 +1552,7 @@
     public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
-                mService.setMaximumTimeToLock(admin, timeMs, UserHandle.myUserId());
+                mService.setMaximumTimeToLock(admin, timeMs);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1503,8 +1617,8 @@
     public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
 
     /**
-     * Ask the user data be wiped.  This will cause the device to reboot,
-     * erasing all user data while next booting up.
+     * Ask the user data be wiped.  Wiping the primary user will cause the
+     * device to reboot, erasing all user data while next booting up.
      *
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
@@ -1588,7 +1702,7 @@
                             != android.net.Proxy.PROXY_VALID)
                         throw new IllegalArgumentException();
                 }
-                return mService.setGlobalProxy(admin, hostSpec, exclSpec, UserHandle.myUserId());
+                return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1754,7 +1868,7 @@
     public int setStorageEncryption(ComponentName admin, boolean encrypt) {
         if (mService != null) {
             try {
-                return mService.setStorageEncryption(admin, encrypt, UserHandle.myUserId());
+                return mService.setStorageEncryption(admin, encrypt);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -1934,13 +2048,15 @@
             String alias) {
         try {
             final byte[] pemCert = Credentials.convertToPem(cert);
-            return mService.installKeyPair(who, privKey.getEncoded(), pemCert, alias);
-        } catch (CertificateException e) {
-            Log.w(TAG, "Error encoding certificate", e);
-        } catch (IOException e) {
-            Log.w(TAG, "Error writing certificate", e);
+            final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
+                    .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
+            return mService.installKeyPair(who, pkcs8Key, pemCert, alias);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed talking with device policy service", e);
+        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+            Log.w(TAG, "Failed to obtain private key material", e);
+        } catch (CertificateException | IOException e) {
+            Log.w(TAG, "Could not pem-encode certificate", e);
         }
         return false;
     }
@@ -1971,7 +2087,7 @@
     public void setCameraDisabled(ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setCameraDisabled(admin, disabled, UserHandle.myUserId());
+                mService.setCameraDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2015,7 +2131,7 @@
     public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setScreenCaptureDisabled(admin, UserHandle.myUserId(), disabled);
+                mService.setScreenCaptureDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2059,7 +2175,7 @@
     public void setAutoTimeRequired(ComponentName admin, boolean required) {
         if (mService != null) {
             try {
-                mService.setAutoTimeRequired(admin, UserHandle.myUserId(), required);
+                mService.setAutoTimeRequired(admin, required);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2100,7 +2216,7 @@
     public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
         if (mService != null) {
             try {
-                mService.setKeyguardDisabledFeatures(admin, which, UserHandle.myUserId());
+                mService.setKeyguardDisabledFeatures(admin, which);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2350,6 +2466,113 @@
     }
 
     /**
+     * Sets the given component as the device initializer. The package must already be installed and
+     * set as an active device administrator, and there must not be an existing device initializer,
+     * for this call to succeed. This method can only be called by an app holding the
+     * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A
+     * device initializer app is granted device owner privileges during device initialization and
+     * profile owner privileges during secondary user initialization.
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not
+     *        called by the device owner.
+     * @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
+     * @param initializerName The user-visible name of the device initializer.
+     * @return whether the package was successfully registered as the device initializer.
+     * @throws IllegalArgumentException if the package name is null or invalid
+     * @throws IllegalStateException if the caller is not device owner or the device has
+     *         already been provisioned or a device initializer already exists.
+     */
+    public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+            String initializerName) throws IllegalArgumentException, IllegalStateException {
+        if (mService != null) {
+            try {
+                return mService.setDeviceInitializer(who, initializer, initializerName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set device initializer");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package has been registered as the device initializer.
+     *
+     * @param packageName the package name of the app, to compare with the registered device
+     *        initializer app, if any.
+     * @return whether or not the caller is registered as the device initializer app.
+     */
+    public boolean isDeviceInitializerApp(String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isDeviceInitializer(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check device initializer");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the device initializer, so that it will not be invoked on user initialization for any
+     * subsequently created users. This method can be called by either the device owner or device
+     * initializer itself. The caller must be an active administrator.
+     *
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public void clearDeviceInitializerApp(ComponentName who) {
+        if (mService != null) {
+            try {
+                mService.clearDeviceInitializer(who);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to clear device initializer");
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Gets the device initializer of the system.
+     *
+     * @return the package name of the device initializer.
+     */
+    @SystemApi
+    public String getDeviceInitializerApp() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceInitializer();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device initializer");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the enabled state of the user. A user should be enabled only once it is ready to
+     * be used.
+     *
+     * <p>Device initializer must call this method to mark the user as functional.
+     * Only the device initializer agent can call this.
+     *
+     * <p>When the user is enabled, if the device initializer is not also the device owner, the
+     * device initializer will no longer have elevated permissions to call methods in this class.
+     * Additionally, it will be removed as an active administrator and its
+     * {@link DeviceAdminReceiver} will be disabled.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return whether the user is now enabled.
+     */
+    public boolean setUserEnabled(ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.setUserEnabled(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * @hide
      * @deprecated Use #ACTION_SET_PROFILE_OWNER
      * Sets the given component as an active admin and registers the package as the profile
@@ -2417,27 +2640,6 @@
     }
 
     /**
-     * @deprecated Use setProfileOwner(ComponentName ...)
-     * @hide
-     * Sets the given package as the profile owner of the given user profile. The package must
-     * already be installed and there shouldn't be an existing profile owner registered for this
-     * user. Also, this method must be called before the user has been used for the first time.
-     * @param packageName the package name of the application to be registered as profile owner.
-     * @param ownerName the human readable name of the organisation associated with this DPM.
-     * @param userHandle the userId to set the profile owner for.
-     * @return whether the package was successfully registered as the profile owner.
-     * @throws IllegalArgumentException if packageName is null, the package isn't installed, or
-     *         the user has already been set up.
-     */
-    public boolean setProfileOwner(String packageName, String ownerName, int userHandle)
-            throws IllegalArgumentException {
-        if (packageName == null) {
-            throw new NullPointerException("packageName cannot be null");
-        }
-        return setProfileOwner(new ComponentName(packageName, ""), ownerName, userHandle);
-    }
-
-    /**
      * @hide
      * Sets the given component as the profile owner of the given user profile. The package must
      * already be installed and there shouldn't be an existing profile owner registered for this
@@ -2698,14 +2900,12 @@
      * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
      * then it's up to the TrustAgent itself to aggregate the values from all device admins.
      * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
-     * @hide
      */
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
             PersistableBundle configuration) {
         if (mService != null) {
             try {
-                mService.setTrustAgentConfiguration(admin, target, configuration,
-                        UserHandle.myUserId());
+                mService.setTrustAgentConfiguration(admin, target, configuration);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2725,7 +2925,6 @@
      * for this {@param agent} or calls it with a null configuration, null is returned.
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
-     * @hide
      */
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
             ComponentName agent) {
@@ -3109,8 +3308,7 @@
     }
 
     /**
-     * Called by a profile or device owner to set a user restriction specified
-     * by the key.
+     * Called by a profile or device owner to set a user restriction specified by the key.
      * <p>
      * The calling device admin must be a profile or device owner; if it is not,
      * a security exception will be thrown.
@@ -3131,8 +3329,7 @@
     }
 
     /**
-     * Called by a profile or device owner to clear a user restriction specified
-     * by the key.
+     * Called by a profile or device owner to clear a user restriction specified by the key.
      * <p>
      * The calling device admin must be a profile or device owner; if it is not,
      * a security exception will be thrown.
@@ -3153,7 +3350,7 @@
     }
 
     /**
-     * Called by device or profile owner to hide or unhide packages. When a package is hidden it
+     * Called by profile or device owners to hide or unhide packages. When a package is hidden it
      * is unavailable for use, but the data and actual package file remain.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3175,7 +3372,7 @@
     }
 
     /**
-     * Called by device or profile owner to determine if a package is hidden.
+     * Called by profile or device owners to determine if a package is hidden.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to retrieve the hidden status of.
@@ -3193,7 +3390,7 @@
     }
 
     /**
-     * Called by profile or device owner to re-enable a system app that was disabled by default
+     * Called by profile or device owners to re-enable a system app that was disabled by default
      * when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3210,7 +3407,7 @@
     }
 
     /**
-     * Called by profile or device owner to re-enable system apps by intent that were disabled
+     * Called by profile or device owners to re-enable system apps by intent that were disabled
      * by default when the user was initialized.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3296,7 +3493,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      *
      * @see Activity#startLockTask()
-     * @see DeviceAdminReceiver#onLockTaskModeChanged(Context, Intent, boolean, String)
+     * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
+     * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
      * @see UserManager#DISALLOW_CREATE_WINDOWS
      */
     public void setLockTaskPackages(ComponentName admin, String[] packages)
@@ -3351,14 +3549,22 @@
      * <li>{@link Settings.Global#ADB_ENABLED}</li>
      * <li>{@link Settings.Global#AUTO_TIME}</li>
      * <li>{@link Settings.Global#AUTO_TIME_ZONE}</li>
-     * <li>{@link Settings.Global#BLUETOOTH_ON}</li>
+     * <li>{@link Settings.Global#BLUETOOTH_ON}
+     * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+     * {@link android.bluetooth.BluetoothAdapter#enable()} and
+     * {@link android.bluetooth.BluetoothAdapter#disable()} instead.</li>
      * <li>{@link Settings.Global#DATA_ROAMING}</li>
      * <li>{@link Settings.Global#DEVELOPMENT_SETTINGS_ENABLED}</li>
      * <li>{@link Settings.Global#MODE_RINGER}</li>
      * <li>{@link Settings.Global#NETWORK_PREFERENCE}</li>
      * <li>{@link Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
-     * <li>{@link Settings.Global#WIFI_ON}</li>
+     * <li>{@link Settings.Global#WIFI_ON}
+     * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+     * {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
      * <li>{@link Settings.Global#WIFI_SLEEP_POLICY}</li>
+     * <li>{@link Settings.Global#STAY_ON_WHILE_PLUGGED_IN}
+     * This setting is only available from {@link android.os.Build.VERSION_CODES#MNC} onwards
+     * and can only be set if {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
      * </ul>
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3478,9 +3684,14 @@
     /**
      * Check whether the current user has been blocked by device policy from uninstalling a package.
      * Requires the caller to be the profile owner if checking a specific admin's policy.
+     * <p>
+     * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
+     * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code>
+     * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing
+     * <code>null</code> will cause a NullPointerException to be raised.
      *
      * @param admin The name of the admin component whose blocking policy will be checked, or null
-     *        to check if any admin has blocked the uninstallation.
+     *            to check if any admin has blocked the uninstallation.
      * @param packageName package to check.
      * @return true if uninstallation is blocked.
      */
@@ -3575,4 +3786,18 @@
         }
         return Collections.emptyList();
     }
+
+    /**
+     * Called by profile or device owners to set the current user's photo.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param icon the bitmap to set as the photo.
+     */
+    public void setUserIcon(ComponentName admin, Bitmap icon) {
+        try {
+            mService.setUserIcon(admin, icon);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set the user icon ", re);
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0ca60c0..f69cf36 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.PersistableBundle;
@@ -32,34 +33,34 @@
  * {@hide}
  */
 interface IDevicePolicyManager {
-    void setPasswordQuality(in ComponentName who, int quality, int userHandle);
+    void setPasswordQuality(in ComponentName who, int quality);
     int getPasswordQuality(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLength(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLength(in ComponentName who, int length);
     int getPasswordMinimumLength(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumUpperCase(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumUpperCase(in ComponentName who, int length);
     int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLowerCase(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLowerCase(in ComponentName who, int length);
     int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumLetters(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumLetters(in ComponentName who, int length);
     int getPasswordMinimumLetters(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNumeric(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumNumeric(in ComponentName who, int length);
     int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumSymbols(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumSymbols(in ComponentName who, int length);
     int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
 
-    void setPasswordMinimumNonLetter(in ComponentName who, int length, int userHandle);
+    void setPasswordMinimumNonLetter(in ComponentName who, int length);
     int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
 
-    void setPasswordHistoryLength(in ComponentName who, int length, int userHandle);
+    void setPasswordHistoryLength(in ComponentName who, int length);
     int getPasswordHistoryLength(in ComponentName who, int userHandle);
 
-    void setPasswordExpirationTimeout(in ComponentName who, long expiration, int userHandle);
+    void setPasswordExpirationTimeout(in ComponentName who, long expiration);
     long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
 
     long getPasswordExpiration(in ComponentName who, int userHandle);
@@ -68,33 +69,33 @@
     int getCurrentFailedPasswordAttempts(int userHandle);
     int getProfileWithMinimumFailedPasswordsForWipe(int userHandle);
 
-    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle);
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
     int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
 
-    boolean resetPassword(String password, int flags, int userHandle);
+    boolean resetPassword(String password, int flags);
 
-    void setMaximumTimeToLock(in ComponentName who, long timeMs, int userHandle);
+    void setMaximumTimeToLock(in ComponentName who, long timeMs);
     long getMaximumTimeToLock(in ComponentName who, int userHandle);
 
     void lockNow();
 
     void wipeData(int flags, int userHandle);
 
-    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle);
+    ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
     ComponentName getGlobalProxyAdmin(int userHandle);
     void setRecommendedGlobalProxy(in ComponentName admin, in ProxyInfo proxyInfo);
 
-    int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle);
+    int setStorageEncryption(in ComponentName who, boolean encrypt);
     boolean getStorageEncryption(in ComponentName who, int userHandle);
     int getStorageEncryptionStatus(int userHandle);
 
-    void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle);
+    void setCameraDisabled(in ComponentName who, boolean disabled);
     boolean getCameraDisabled(in ComponentName who, int userHandle);
 
-    void setScreenCaptureDisabled(in ComponentName who, int userHandle, boolean disabled);
+    void setScreenCaptureDisabled(in ComponentName who, boolean disabled);
     boolean getScreenCaptureDisabled(in ComponentName who, int userHandle);
 
-    void setKeyguardDisabledFeatures(in ComponentName who, int which, int userHandle);
+    void setKeyguardDisabledFeatures(in ComponentName who, int which);
     int getKeyguardDisabledFeatures(in ComponentName who, int userHandle);
 
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
@@ -129,6 +130,7 @@
     void enforceCanManageCaCerts(in ComponentName admin);
 
     boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias);
+    void choosePrivateKeyAlias(int uid, in String host, int port, in String url, in String alias, IBinder aliasCallback);
 
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
     void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
@@ -186,7 +188,7 @@
     boolean getCrossProfileCallerIdDisabledForUser(int userId);
 
     void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
-            in PersistableBundle args, int userId);
+            in PersistableBundle args);
     List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
             in ComponentName agent, int userId);
 
@@ -194,8 +196,16 @@
     boolean removeCrossProfileWidgetProvider(in ComponentName admin, String packageName);
     List<String> getCrossProfileWidgetProviders(in ComponentName admin);
 
-    void setAutoTimeRequired(in ComponentName who, int userHandle, boolean required);
+    void setAutoTimeRequired(in ComponentName who, boolean required);
     boolean getAutoTimeRequired();
 
     boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
+
+    boolean setUserEnabled(in ComponentName who);
+    boolean isDeviceInitializer(String packageName);
+    void clearDeviceInitializer(in ComponentName who);
+    boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
+    String getDeviceInitializer();
+
+    void setUserIcon(in ComponentName admin, in Bitmap icon);
 }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 87d785a..7f89100 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -105,7 +105,7 @@
  */
 public abstract class BackupAgent extends ContextWrapper {
     private static final String TAG = "BackupAgent";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     /** @hide */
     public static final int TYPE_EOF = 0;
@@ -258,6 +258,7 @@
      *
      * <ul>
      * <li>The contents of the {@link #getCacheDir()} directory</li>
+     * <li>The contents of the {@link #getCodeCacheDir()} directory</li>
      * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
      * <li>The contents of the app's shared library directory</li>
      * </ul>
@@ -285,6 +286,7 @@
         String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
         String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
         String cacheDir = getCacheDir().getCanonicalPath();
+        String codeCacheDir = getCodeCacheDir().getCanonicalPath();
         String libDir = (appInfo.nativeLibraryDir != null)
                 ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
                 : null;
@@ -298,6 +300,7 @@
             filterSet.add(libDir);
         }
         filterSet.add(cacheDir);
+        filterSet.add(codeCacheDir);
         filterSet.add(databaseDir);
         filterSet.add(sharedPrefsDir);
         filterSet.add(filesDir);
@@ -354,6 +357,7 @@
         String dbDir;
         String spDir;
         String cacheDir;
+        String codeCacheDir;
         String libDir;
         String efDir = null;
         String filePath;
@@ -367,6 +371,7 @@
             dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
             spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
             cacheDir = getCacheDir().getCanonicalPath();
+            codeCacheDir = getCodeCacheDir().getCanonicalPath();
             libDir = (appInfo.nativeLibraryDir == null)
                     ? null
                     : new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -380,7 +385,8 @@
             }
 
             // Now figure out which well-defined tree the file is placed in, working from
-            // most to least specific.  We also specifically exclude the lib and cache dirs.
+            // most to least specific.  We also specifically exclude the lib, cache,
+            // and code_cache dirs.
             filePath = file.getCanonicalPath();
         } catch (IOException e) {
             Log.w(TAG, "Unable to obtain canonical paths");
@@ -388,9 +394,10 @@
         }
 
         if (filePath.startsWith(cacheDir)
+                || filePath.startsWith(codeCacheDir)
                 || filePath.startsWith(libDir)
                 || filePath.startsWith(nbFilesDir)) {
-            Log.w(TAG, "lib, cache, and no_backup files are not backed up");
+            Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
             return;
         }
 
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 048a4bb..1fe63e7 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -18,8 +18,6 @@
 
 import android.annotation.SystemApi;
 import android.os.ParcelFileDescriptor;
-import android.os.Process;
-
 import java.io.FileDescriptor;
 import java.io.IOException;
 
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 62734f2..7ee39f5 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -17,7 +17,6 @@
 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;
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 89efeb2..a1c11f3 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -18,8 +18,6 @@
 
 import java.util.List;
 
-import android.content.Context;
-
 /**
  * This is an API for scheduling various types of jobs against the framework that will be executed
  * in your application's own process.
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 3cf3c95..58279d7 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -68,6 +68,11 @@
         public static final int CONFIGURATION_CHANGE = 5;
 
         /**
+         * An event type denoting that a package was interacted with in some way.
+         */
+        public static final int INTERACTION = 6;
+
+        /**
          * {@hide}
          */
         public String mPackage;
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 083a48a..0122069 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -37,6 +37,16 @@
     public abstract void reportEvent(ComponentName component, int userId, int eventType);
 
     /**
+     * Reports an event to the UsageStatsManager.
+     *
+     * @param packageName The package for which this event occurred.
+     * @param userId The user id to which the component belongs to.
+     * @param eventType The event that occurred. Valid values can be found at
+     * {@link UsageEvents}
+     */
+    public abstract void reportEvent(String packageName, int userId, int eventType);
+
+    /**
      * Reports a configuration change to the UsageStatsManager.
      *
      * @param config The new device configuration.
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 8e86824..1af4953 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -16,6 +16,7 @@
 
 package android.appwidget;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -58,18 +59,28 @@
     private DisplayMetrics mDisplayMetrics;
 
     private String mContextOpPackageName;
-    Handler mHandler;
-    int mHostId;
-    Callbacks mCallbacks = new Callbacks();
-    final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
+    private final Handler mHandler;
+    private final int mHostId;
+    private final Callbacks mCallbacks;
+    private final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<>();
     private OnClickHandler mOnClickHandler;
 
-    class Callbacks extends IAppWidgetHost.Stub {
+    static class Callbacks extends IAppWidgetHost.Stub {
+        private final WeakReference<Handler> mWeakHandler;
+
+        public Callbacks(Handler handler) {
+            mWeakHandler = new WeakReference<>(handler);
+        }
+
         public void updateAppWidget(int appWidgetId, RemoteViews views) {
             if (isLocalBinder() && views != null) {
                 views = views.clone();
             }
-            Message msg = mHandler.obtainMessage(HANDLE_UPDATE, appWidgetId, 0, views);
+            Handler handler = mWeakHandler.get();
+            if (handler == null) {
+                return;
+            }
+            Message msg = handler.obtainMessage(HANDLE_UPDATE, appWidgetId, 0, views);
             msg.sendToTarget();
         }
 
@@ -77,20 +88,36 @@
             if (isLocalBinder() && info != null) {
                 info = info.clone();
             }
-            Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED,
+            Handler handler = mWeakHandler.get();
+            if (handler == null) {
+                return;
+            }
+            Message msg = handler.obtainMessage(HANDLE_PROVIDER_CHANGED,
                     appWidgetId, 0, info);
             msg.sendToTarget();
         }
 
         public void providersChanged() {
-            mHandler.obtainMessage(HANDLE_PROVIDERS_CHANGED).sendToTarget();
+            Handler handler = mWeakHandler.get();
+            if (handler == null) {
+                return;
+            }
+            handler.obtainMessage(HANDLE_PROVIDERS_CHANGED).sendToTarget();
         }
 
         public void viewDataChanged(int appWidgetId, int viewId) {
-            Message msg = mHandler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
+            Handler handler = mWeakHandler.get();
+            if (handler == null) {
+                return;
+            }
+            Message msg = handler.obtainMessage(HANDLE_VIEW_DATA_CHANGED,
                     appWidgetId, viewId);
             msg.sendToTarget();
         }
+
+        private static boolean isLocalBinder() {
+            return Process.myPid() == Binder.getCallingPid();
+        }
     }
 
     class UpdateHandler extends Handler {
@@ -132,6 +159,7 @@
         mHostId = hostId;
         mOnClickHandler = handler;
         mHandler = new UpdateHandler(looper);
+        mCallbacks = new Callbacks(mHandler);
         mDisplayMetrics = context.getResources().getDisplayMetrics();
         bindService();
     }
@@ -251,10 +279,6 @@
         }
     }
 
-    private boolean isLocalBinder() {
-        return Process.myPid() == Binder.getCallingPid();
-    }
-
     /**
      * Stop listening to changes for this AppWidget.
      */
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 1ff476e..3219fe7 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -31,9 +31,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Process;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -588,9 +586,10 @@
         return tv;
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setClassName(AppWidgetHostView.class.getName());
     }
 
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 5175490..767f59e 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.media.AudioManager;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -199,7 +200,8 @@
     }
 
     public void finalize() {
-        close();
+        // The empty finalize needs to be kept or the
+        // cts signature tests would fail.
     }
     /**
      * Initiate connection to a profile of the remote bluetooth device.
@@ -414,9 +416,16 @@
     }
 
     /**
-     * Tells remote device to adjust volume. Only if absolute volume is supported.
+     * Tells remote device to adjust volume. Only if absolute volume is
+     * supported. Uses the following values:
+     * <ul>
+     * <li>{@link AudioManager#ADJUST_LOWER}</li>
+     * <li>{@link AudioManager#ADJUST_RAISE}</li>
+     * <li>{@link AudioManager#ADJUST_MUTE}</li>
+     * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
+     * </ul>
      *
-     * @param direction 1 to increase volume, or -1 to decrease volume
+     * @param direction One of the supported adjust values.
      * @hide
      */
     public void adjustAvrcpAbsoluteVolume(int direction) {
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
index ce87329..161c339 100644
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
@@ -26,32 +26,32 @@
  * @hide
  */
 public final class BluetoothActivityEnergyInfo implements Parcelable {
+    private final long mTimestamp;
     private final int mBluetoothStackState;
     private final int mControllerTxTimeMs;
     private final int mControllerRxTimeMs;
     private final int mControllerIdleTimeMs;
     private final int mControllerEnergyUsed;
-    private final long timestamp;
 
     public static final int BT_STACK_STATE_INVALID = 0;
     public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
     public static final int BT_STACK_STATE_STATE_SCANNING = 2;
     public static final int BT_STACK_STATE_STATE_IDLE = 3;
 
-    public BluetoothActivityEnergyInfo(int stackState, int txTime, int rxTime,
-            int idleTime, int energyUsed) {
+    public BluetoothActivityEnergyInfo(long timestamp, int stackState,
+                                       int txTime, int rxTime, int idleTime, int energyUsed) {
+        mTimestamp = timestamp;
         mBluetoothStackState = stackState;
         mControllerTxTimeMs = txTime;
         mControllerRxTimeMs = rxTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
-        timestamp = System.currentTimeMillis();
     }
 
     @Override
     public String toString() {
         return "BluetoothActivityEnergyInfo{"
-            + " timestamp=" + timestamp
+            + " mTimestamp=" + mTimestamp
             + " mBluetoothStackState=" + mBluetoothStackState
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
@@ -63,13 +63,14 @@
     public static final Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
             new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
         public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
+            long timestamp = in.readLong();
             int stackState = in.readInt();
             int txTime = in.readInt();
             int rxTime = in.readInt();
             int idleTime = in.readInt();
             int energyUsed = in.readInt();
-            return new BluetoothActivityEnergyInfo(stackState, txTime, rxTime,
-                    idleTime, energyUsed);
+            return new BluetoothActivityEnergyInfo(timestamp, stackState,
+                    txTime, rxTime, idleTime, energyUsed);
         }
         public BluetoothActivityEnergyInfo[] newArray(int size) {
             return new BluetoothActivityEnergyInfo[size];
@@ -77,6 +78,7 @@
     };
 
     public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mTimestamp);
         out.writeInt(mBluetoothStackState);
         out.writeInt(mControllerTxTimeMs);
         out.writeInt(mControllerRxTimeMs);
@@ -123,11 +125,12 @@
     public int getControllerEnergyUsed() {
         return mControllerEnergyUsed;
     }
+
     /**
-     * @return timestamp(wall clock) of record creation
+     * @return timestamp(real time elapsed in milliseconds since boot) of record creation.
      */
     public long getTimeStamp() {
-        return timestamp;
+        return mTimestamp;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8f4bf8..be26eac 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -26,9 +26,7 @@
 import android.bluetooth.le.ScanResult;
 import android.bluetooth.le.ScanSettings;
 import android.content.Context;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -36,7 +34,6 @@
 import android.util.Pair;
 
 import java.io.IOException;
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index a15bd97..7b5a045 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -61,6 +61,7 @@
      */
     public static final int CALL_STATE_TERMINATED = 7;
 
+    private final BluetoothDevice mDevice;
     private final int mId;
     private int mState;
     private String mNumber;
@@ -70,8 +71,9 @@
     /**
      * Creates BluetoothHeadsetClientCall instance.
      */
-    public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty,
-            boolean outgoing) {
+    public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
+            boolean multiParty, boolean outgoing) {
+        mDevice = device;
         mId = id;
         mState = state;
         mNumber = number != null ? number : "";
@@ -114,6 +116,15 @@
     }
 
     /**
+     * Gets call's device.
+     *
+     * @return call device.
+     */
+    public BluetoothDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
      * Gets call's Id.
      *
      * @return call id.
@@ -161,7 +172,9 @@
     }
 
     public String toString() {
-        StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: ");
+        StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
+        builder.append(mDevice);
+        builder.append(", mId: ");
         builder.append(mId);
         builder.append(", mState: ");
         switch (mState) {
@@ -192,8 +205,9 @@
             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);
+                    return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
+                            in.readInt(), in.readInt(), in.readString(),
+                            in.readInt() == 1, in.readInt() == 1);
                 }
 
                 @Override
@@ -204,6 +218,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(mDevice, 0);
         out.writeInt(mId);
         out.writeInt(mState);
         out.writeString(mNumber);
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
index 6a6b3e3..685b174 100644
--- a/core/java/android/bluetooth/le/TruncatedFilter.java
+++ b/core/java/android/bluetooth/le/TruncatedFilter.java
@@ -17,9 +17,6 @@
 package android.bluetooth.le;
 
 import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
 import java.util.List;
 
 /**
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 9a32fdf..af74e73 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -238,6 +238,7 @@
         final boolean mInitialStickyHint;
         final IBinder mToken;
         final int mSendingUser;
+        final int mFlags;
         
         int mResultCode;
         String mResultData;
@@ -246,8 +247,8 @@
         boolean mFinished;
 
         /** @hide */
-        public PendingResult(int resultCode, String resultData, Bundle resultExtras,
-                int type, boolean ordered, boolean sticky, IBinder token, int userId) {
+        public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type,
+                boolean ordered, boolean sticky, IBinder token, int userId, int flags) {
             mResultCode = resultCode;
             mResultData = resultData;
             mResultExtras = resultExtras;
@@ -256,6 +257,7 @@
             mInitialStickyHint = sticky;
             mToken = token;
             mSendingUser = userId;
+            mFlags = flags;
         }
         
         /**
@@ -417,11 +419,11 @@
                     }
                     if (mOrderedHint) {
                         am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
-                                mAbortBroadcast);
+                                mAbortBroadcast, mFlags);
                     } else {
                         // This broadcast was sent to a component; it is not ordered,
                         // but we still need to tell the activity manager we are done.
-                        am.finishReceiver(mToken, 0, null, null, false);
+                        am.finishReceiver(mToken, 0, null, null, false, mFlags);
                     }
                 } catch (RemoteException ex) {
                 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 0cff4c0..393cf8e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
@@ -364,7 +365,8 @@
         }
 
         @Override
-        public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
+        public Bundle call(
+                String callingPkg, String method, @Nullable String arg, @Nullable Bundle extras) {
             final String original = setCallingPackage(callingPkg);
             try {
                 return ContentProvider.this.call(method, arg, extras);
@@ -1742,7 +1744,7 @@
      * @return provider-defined return value.  May be {@code null}, which is also
      *   the default for providers which don't implement any call methods.
      */
-    public Bundle call(String method, String arg, Bundle extras) {
+    public Bundle call(String method, @Nullable String arg, @Nullable Bundle extras) {
         return null;
     }
 
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 136e54d..49ac062 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -208,6 +208,22 @@
         return mType;
     }
 
+    public boolean isInsert() {
+        return mType == TYPE_INSERT;
+    }
+
+    public boolean isDelete() {
+        return mType == TYPE_DELETE;
+    }
+
+    public boolean isUpdate() {
+        return mType == TYPE_UPDATE;
+    }
+
+    public boolean isAssertQuery() {
+        return mType == TYPE_ASSERT;
+    }
+
     public boolean isWriteOperation() {
         return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
     }
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index ec3d002..4196f27 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -18,7 +18,6 @@
 
 import android.content.ContentProvider;
 import android.net.Uri;
-import android.os.UserHandle;
 import android.os.Parcelable;
 import android.os.Parcel;
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a09fee9..17a8eb7 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.accounts.Account;
+import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
@@ -1357,7 +1358,8 @@
      * @throws NullPointerException if uri or method is null
      * @throws IllegalArgumentException if uri is not known
      */
-    public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
+    public final Bundle call(
+            Uri uri, String method, @Nullable String arg, @Nullable Bundle extras) {
         if (uri == null) {
             throw new NullPointerException("uri == null");
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 26735a6..61cdec3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,14 +16,19 @@
 
 package android.content;
 
+import android.annotation.CheckResult;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.annotation.StringRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
 import android.annotation.SystemApi;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -32,7 +37,6 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.media.MediaScannerConnection.OnScanCompletedListener;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
@@ -146,12 +150,13 @@
     @IntDef(flag = true,
             value = {
                 BIND_AUTO_CREATE,
-                BIND_AUTO_CREATE,
                 BIND_DEBUG_UNBIND,
                 BIND_NOT_FOREGROUND,
                 BIND_ABOVE_CLIENT,
                 BIND_ALLOW_OOM_MANAGEMENT,
-                BIND_WAIVE_PRIORITY
+                BIND_WAIVE_PRIORITY,
+                BIND_IMPORTANT,
+                BIND_ADJUST_WITH_ACTIVITY
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface BindServiceFlags {}
@@ -363,7 +368,7 @@
      *
      * @param resId Resource id for the CharSequence text
      */
-    public final CharSequence getText(int resId) {
+    public final CharSequence getText(@StringRes int resId) {
         return getResources().getText(resId);
     }
 
@@ -373,7 +378,7 @@
      *
      * @param resId Resource id for the string
      */
-    public final String getString(int resId) {
+    public final String getString(@StringRes int resId) {
         return getResources().getString(resId);
     }
 
@@ -386,23 +391,60 @@
      * @param formatArgs The format arguments that will be used for substitution.
      */
 
-    public final String getString(int resId, Object... formatArgs) {
+    public final String getString(@StringRes int resId, Object... formatArgs) {
         return getResources().getString(resId, formatArgs);
     }
 
     /**
-     * Return a drawable object associated with a particular resource ID and
+     * Returns a color associated with a particular resource ID and styled for
+     * the current theme.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @return A single color value in the form 0xAARRGGBB.
+     * @throws android.content.res.Resources.NotFoundException if the given ID
+     *         does not exist.
+     */
+    @Nullable
+    public final int getColor(int id) {
+        return getResources().getColor(id, getTheme());
+    }
+
+    /**
+     * Returns a drawable object associated with a particular resource ID and
      * styled for the current theme.
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return Drawable An object that can be used to draw this resource.
+     * @return An object that can be used to draw this resource, or
+     *         {@code null} if the resource could not be resolved.
+     * @throws android.content.res.Resources.NotFoundException if the given ID
+     *         does not exist.
      */
+    @Nullable
     public final Drawable getDrawable(int id) {
         return getResources().getDrawable(id, getTheme());
     }
 
+    /**
+     * Returns a color state list associated with a particular resource ID and
+     * styled for the current theme.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @return A color state list, or {@code null} if the resource could not be
+     *         resolved.
+     * @throws android.content.res.Resources.NotFoundException if the given ID
+     *         does not exist.
+     */
+    @Nullable
+    public final ColorStateList getColorStateList(int id) {
+        return getResources().getColorStateList(id, getTheme());
+    }
+
      /**
      * Set the base theme for this context.  Note that this should be called
      * before any views are instantiated in the Context (for example before
@@ -411,7 +453,7 @@
      *
      * @param resid The style resource describing the theme.
      */
-    public abstract void setTheme(int resid);
+    public abstract void setTheme(@StyleRes int resid);
 
     /** @hide Needed for some internal implementation...  not public because
      * you can't assume this actually means anything. */
@@ -427,10 +469,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(int[])}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(int[])
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
      */
     public final TypedArray obtainStyledAttributes(
             int[] attrs) {
@@ -439,22 +481,22 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(int, int[])}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(int, int[])
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
      */
     public final TypedArray obtainStyledAttributes(
-            int resid, int[] attrs) throws Resources.NotFoundException {
+            @StyleableRes int resid, int[] attrs) throws Resources.NotFoundException {
         return getTheme().obtainStyledAttributes(resid, attrs);
     }
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
             AttributeSet set, int[] attrs) {
@@ -463,10 +505,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
             AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
@@ -711,7 +753,8 @@
      * are not automatically scanned by the media scanner, you can explicitly
      * add them to the media database with
      * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[],
-     *      OnScanCompletedListener) MediaScannerConnection.scanFile}.
+     *      android.media.MediaScannerConnection.OnScanCompletedListener)
+     *      MediaScannerConnection.scanFile}.
      * Note that this is not the same as
      * {@link android.os.Environment#getExternalStoragePublicDirectory
      * Environment.getExternalStoragePublicDirectory()}, which provides
@@ -1876,7 +1919,7 @@
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
      *
-     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
      * @see #sendBroadcast
      * @see #unregisterReceiver
      */
@@ -2039,7 +2082,9 @@
      * @hide
      */
     @SystemApi
-    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, UserHandle user) {
+    @SuppressWarnings("unused")
+    public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
+            int flags, UserHandle user) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -2110,17 +2155,21 @@
             WIFI_PASSPOINT_SERVICE,
             WIFI_P2P_SERVICE,
             WIFI_SCANNING_SERVICE,
+            //@hide: WIFI_RTT_SERVICE,
             //@hide: ETHERNET_SERVICE,
             WIFI_RTT_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
+            //@hide: FINGERPRINT_SERVICE,
             MEDIA_ROUTER_SERVICE,
             TELEPHONY_SERVICE,
+            TELEPHONY_SUBSCRIPTION_SERVICE,
             TELECOM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
             TEXT_SERVICES_MANAGER_SERVICE,
             APPWIDGET_SERVICE,
+            //@hide: VOICE_INTERACTION_MANAGER_SERVICE,
             //@hide: BACKUP_SERVICE,
             DROPBOX_SERVICE,
             DEVICE_POLICY_SERVICE,
@@ -2132,17 +2181,25 @@
             USB_SERVICE,
             LAUNCHER_APPS_SERVICE,
             //@hide: SERIAL_SERVICE,
+            //@hide: HDMI_CONTROL_SERVICE,
             INPUT_SERVICE,
             DISPLAY_SERVICE,
-            //@hide: SCHEDULING_POLICY_SERVICE,
             USER_SERVICE,
-            //@hide: APP_OPS_SERVICE
+            RESTRICTIONS_SERVICE,
+            APP_OPS_SERVICE,
             CAMERA_SERVICE,
             PRINT_SERVICE,
+            CONSUMER_IR_SERVICE,
+            //@hide: TRUST_SERVICE,
+            TV_INPUT_SERVICE,
+            //@hide: NETWORK_SCORE_SERVICE,
+            USAGE_STATS_SERVICE,
             MEDIA_SESSION_SERVICE,
             BATTERY_SERVICE,
             JOB_SCHEDULER_SERVICE,
+            //@hide: PERSISTENT_DATA_BLOCK_SERVICE,
             MEDIA_PROJECTION_SERVICE,
+            MIDI_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2262,6 +2319,51 @@
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
     /**
+     * Return the handle to a system-level service by class.
+     * <p>
+     * Currently available classes are:
+     * {@link android.view.WindowManager}, {@link android.view.LayoutInflater},
+     * {@link android.app.ActivityManager}, {@link android.os.PowerManager},
+     * {@link android.app.AlarmManager}, {@link android.app.NotificationManager},
+     * {@link android.app.KeyguardManager}, {@link android.location.LocationManager},
+     * {@link android.app.SearchManager}, {@link android.os.Vibrator},
+     * {@link android.net.ConnectivityManager},
+     * {@link android.net.wifi.WifiManager},
+     * {@link android.media.AudioManager}, {@link android.media.MediaRouter},
+     * {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
+     * {@link android.view.inputmethod.InputMethodManager},
+     * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
+     * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}.
+     * </p><p>
+     * Note: System services obtained via this API may be closely associated with
+     * the Context in which they are obtained from.  In general, do not share the
+     * service objects between various different contexts (Activities, Applications,
+     * Services, Providers, etc.)
+     * </p>
+     *
+     * @param serviceClass The class of the desired service.
+     * @return The service or null if the class is not a supported system service.
+     */
+    @SuppressWarnings("unchecked")
+    public final <T> T getSystemService(Class<T> serviceClass) {
+        // Because subclasses may override getSystemService(String) we cannot
+        // perform a lookup by class alone.  We must first map the class to its
+        // service name then invoke the string-based method.
+        String serviceName = getSystemServiceName(serviceClass);
+        return serviceName != null ? (T)getSystemService(serviceName) : null;
+    }
+
+    /**
+     * Gets the name of the system-level service that is represented by the specified class.
+     *
+     * @param serviceClass The class of the desired service.
+     * @return The service name or null if the class is not a supported system service.
+     *
+     * @hide
+     */
+    public abstract String getSystemServiceName(Class<?> serviceClass);
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.os.PowerManager} for controlling power management,
      * including "wake locks," which let you keep the device on while
@@ -2556,7 +2658,7 @@
      * of fingerprints.
      *
      * @see #getSystemService
-     * @see android.app.FingerprintManager
+     * @see android.service.fingerprint.FingerprintManager
      * @hide
      */
     public static final String FINGERPRINT_SERVICE = "fingerprint";
@@ -2612,11 +2714,11 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.text.ClipboardManager} for accessing and modifying
+     * {@link android.content.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
      * @see #getSystemService
-     * @see android.text.ClipboardManager
+     * @see android.content.ClipboardManager
      */
     public static final String CLIPBOARD_SERVICE = "clipboard";
 
@@ -2911,11 +3013,20 @@
      * android.media.projection.MediaProjectionManager} instance for managing
      * media projection sessions.
      * @see #getSystemService
-     * @see android.media.projection.ProjectionManager
+     * @see android.media.projection.MediaProjectionManager
      */
     public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.media.midi.MidiManager} for accessing the MIDI service.
+     *
+     * @see #getSystemService
+     * @hide
+     */
+    public static final String MIDI_SERVICE = "midi";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -2931,6 +3042,7 @@
      * @see PackageManager#checkPermission(String, String)
      * @see #checkCallingPermission
      */
+    @CheckResult(suggest="#enforcePermission(String,int,int,String)")
     @PackageManager.PermissionResult
     public abstract int checkPermission(@NonNull String permission, int pid, int uid);
 
@@ -2960,6 +3072,7 @@
      * @see #checkPermission
      * @see #checkCallingOrSelfPermission
      */
+    @CheckResult(suggest="#enforceCallingPermission(String,String)")
     @PackageManager.PermissionResult
     public abstract int checkCallingPermission(@NonNull String permission);
 
@@ -2979,6 +3092,7 @@
      * @see #checkPermission
      * @see #checkCallingPermission
      */
+    @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)")
     @PackageManager.PermissionResult
     public abstract int checkCallingOrSelfPermission(@NonNull String permission);
 
@@ -3123,6 +3237,7 @@
      *
      * @see #checkCallingUriPermission
      */
+    @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)")
     public abstract int checkUriPermission(Uri uri, int pid, int uid,
             @Intent.AccessUriMode int modeFlags);
 
@@ -3151,6 +3266,7 @@
      *
      * @see #checkUriPermission(Uri, int, int, int)
      */
+    @CheckResult(suggest="#enforceCallingUriPermission(Uri,int,String)")
     public abstract int checkCallingUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags);
 
     /**
@@ -3170,6 +3286,7 @@
      *
      * @see #checkCallingUriPermission
      */
+    @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)")
     public abstract int checkCallingOrSelfUriPermission(Uri uri,
             @Intent.AccessUriMode int modeFlags);
 
@@ -3195,6 +3312,7 @@
      * is allowed to access that uri or holds one of the given permissions, or
      * {@link PackageManager#PERMISSION_DENIED} if it is not.
      */
+    @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)")
     public abstract int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission,
             @Nullable String writePermission, int pid, int uid,
             @Intent.AccessUriMode int modeFlags);
@@ -3338,7 +3456,7 @@
      * are not shared, however they share common state (Resources, ClassLoader,
      * etc) so the Context instance itself is fairly lightweight.
      *
-     * <p>Throws {@link PackageManager.NameNotFoundException} if there is no
+     * <p>Throws {@link android.content.pm.PackageManager.NameNotFoundException} if there is no
      * application with the given package name.
      *
      * <p>Throws {@link java.lang.SecurityException} if the Context requested
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index cfae1cf..6e8b7c1 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -284,36 +284,43 @@
     }
 
     @Override
+    @Deprecated
     public Drawable getWallpaper() {
         return mBase.getWallpaper();
     }
 
     @Override
+    @Deprecated
     public Drawable peekWallpaper() {
         return mBase.peekWallpaper();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumWidth() {
         return mBase.getWallpaperDesiredMinimumWidth();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumHeight() {
         return mBase.getWallpaperDesiredMinimumHeight();
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(Bitmap bitmap) throws IOException {
         mBase.setWallpaper(bitmap);
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(InputStream data) throws IOException {
         mBase.setWallpaper(data);
     }
 
     @Override
+    @Deprecated
     public void clearWallpaper() throws IOException {
         mBase.clearWallpaper();
     }
@@ -445,11 +452,13 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcast(
         Intent intent, BroadcastReceiver resultReceiver,
         Handler scheduler, int initialCode, String initialData,
@@ -460,16 +469,19 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcast(Intent intent) {
         mBase.removeStickyBroadcast(intent);
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         mBase.sendStickyBroadcastAsUser(intent, user);
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -479,6 +491,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
         mBase.removeStickyBroadcastAsUser(intent, user);
     }
@@ -563,6 +576,11 @@
     }
 
     @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        return mBase.getSystemServiceName(serviceClass);
+    }
+
+    @Override
     public int checkPermission(String permission, int pid, int uid) {
         return mBase.checkPermission(permission, pid, uid);
     }
@@ -679,6 +697,7 @@
     }
 
     /** @hide */
+    @Override
     public Context createApplicationContext(ApplicationInfo application,
             int flags) throws PackageManager.NameNotFoundException {
         return mBase.createApplicationContext(application, flags);
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index f858406..4afe38b 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.Nullable;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -56,7 +57,8 @@
     public ContentProviderResult[] applyBatch(String callingPkg,
             ArrayList<ContentProviderOperation> operations)
                     throws RemoteException, OperationApplicationException;
-    public Bundle call(String callingPkg, String method, String arg, Bundle extras)
+    public Bundle call(
+            String callingPkg, String method, @Nullable String arg, @Nullable Bundle extras)
             throws RemoteException;
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2fe727c..2ed8c44 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -23,6 +23,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.AnyRes;
 import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
@@ -762,11 +763,11 @@
          * identifier.
          *
          * @param context The context of the application.
-         * @param resourceId The resource idenfitier for the icon.
+         * @param resourceId The resource identifier for the icon.
          * @return A new ShortcutIconResource with the specified's context package name
-         *         and icon resource idenfitier.
+         *         and icon resource identifier.``
          */
-        public static ShortcutIconResource fromContext(Context context, int resourceId) {
+        public static ShortcutIconResource fromContext(Context context, @AnyRes int resourceId) {
             ShortcutIconResource icon = new ShortcutIconResource();
             icon.packageName = context.getPackageName();
             icon.resourceName = context.getResources().getResourceName(resourceId);
@@ -1238,6 +1239,13 @@
             = "android.intent.extra.ASSIST_PACKAGE";
 
     /**
+     * An optional field on {@link #ACTION_ASSIST} containing the uid of the current foreground
+     * application package at the time the assist was invoked.
+     */
+    public static final String EXTRA_ASSIST_UID
+            = "android.intent.extra.ASSIST_UID";
+
+    /**
      * An optional field on {@link #ACTION_ASSIST} and containing additional contextual
      * information supplied by the current foreground app at the time of the assist request.
      * This is a {@link Bundle} of additional data.
@@ -1760,6 +1768,7 @@
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     /**
@@ -2808,14 +2817,12 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
     /**
-     * @hide
      * Categories for activities that can participate in voice interaction.
      * An activity that supports this category must be prepared to run with
      * no UI shown at all (though in some case it may have a UI shown), and
      * rely on {@link android.app.VoiceInteractor} to interact with the user.
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
-    @SystemApi
     public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
     /**
      * Set if the activity should be considered as an alternative action to
@@ -3254,6 +3261,7 @@
     /**
      * @hide String array of package names.
      */
+    @SystemApi
     public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
 
     /**
@@ -5385,6 +5393,16 @@
     }
 
     /**
+     * Filter extras to only basic types.
+     * @hide
+     */
+    public void removeUnsafeExtras() {
+        if (mExtras != null) {
+            mExtras.filterValues();
+        }
+    }
+
+    /**
      * Retrieve any special flags associated with this intent.  You will
      * normally just set them with {@link #setFlags} and let the system
      * take the appropriate action with them.
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index 5341ea8..6d79626 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.ArrayRes;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -277,7 +278,7 @@
      * @param stringArrayResId the resource id for a string array containing the possible values.
      * @see #setChoiceValues(String[])
      */
-    public void setChoiceValues(Context context, int stringArrayResId) {
+    public void setChoiceValues(Context context, @ArrayRes int stringArrayResId) {
         mChoiceValues = context.getResources().getStringArray(stringArrayResId);
     }
 
@@ -307,7 +308,7 @@
      * @param context the application context, used for retrieving the resources.
      * @param stringArrayResId the resource id of a string array containing the possible entries.
      */
-    public void setChoiceEntries(Context context, int stringArrayResId) {
+    public void setChoiceEntries(Context context, @ArrayRes int stringArrayResId) {
         mChoiceEntries = context.getResources().getStringArray(stringArrayResId);
     }
 
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 46c9234..1d16516 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.annotation.Nullable;
+
 import java.util.Map;
 import java.util.Set;
 
@@ -71,14 +73,12 @@
          * {@link #commit} or {@link #apply} are called.
          * 
          * @param key The name of the preference to modify.
-         * @param value The new value for the preference.  Supplying {@code null}
-         *    as the value is equivalent to calling {@link #remove(String)} with
-         *    this key.
+         * @param value The new value for the preference.
          * 
          * @return Returns a reference to the same Editor object, so you can
          * chain put calls together.
          */
-        Editor putString(String key, String value);
+        Editor putString(String key, @Nullable String value);
         
         /**
          * Set a set of String values in the preferences editor, to be written
@@ -91,7 +91,7 @@
          * @return Returns a reference to the same Editor object, so you can
          * chain put calls together.
          */
-        Editor putStringSet(String key, Set<String> values);
+        Editor putStringSet(String key, @Nullable Set<String> values);
         
         /**
          * Set an int value in the preferences editor, to be written back once
@@ -254,7 +254,8 @@
      * 
      * @throws ClassCastException
      */
-    String getString(String key, String defValue);
+    @Nullable
+    String getString(String key, @Nullable String defValue);
     
     /**
      * Retrieve a set of String values from the preferences.
@@ -272,7 +273,8 @@
      * 
      * @throws ClassCastException
      */
-    Set<String> getStringSet(String key, Set<String> defValues);
+    @Nullable
+    Set<String> getStringSet(String key, @Nullable Set<String> defValues);
     
     /**
      * Retrieve an int value from the preferences.
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
index e9ec5a4..1d5ed8a 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -20,9 +20,9 @@
 import android.os.Parcelable;
 import android.os.ParcelableParcel;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /**
  * Top-level class for managing and interacting with the global undo state for
@@ -54,7 +54,9 @@
  * @hide
  */
 public class UndoManager {
-    private final HashMap<String, UndoOwner> mOwners = new HashMap<String, UndoOwner>();
+    // The common case is a single undo owner (e.g. for a TextView), so default to that capacity.
+    private final ArrayMap<String, UndoOwner> mOwners =
+            new ArrayMap<String, UndoOwner>(1 /* capacity */);
     private final ArrayList<UndoState> mUndos = new ArrayList<UndoState>();
     private final ArrayList<UndoState> mRedos = new ArrayList<UndoState>();
     private int mUpdateCount;
@@ -103,8 +105,7 @@
             return owner;
         }
 
-        owner = new UndoOwner(tag);
-        owner.mManager = this;
+        owner = new UndoOwner(tag, this);
         owner.mData = data;
         mOwners.put(tag, owner);
         return owner;
@@ -114,7 +115,6 @@
         // XXX need to figure out how to prune.
         if (false) {
             mOwners.remove(owner.mTag);
-            owner.mManager = null;
         }
     }
 
@@ -162,6 +162,7 @@
             owner.mSavedIdx = mNextSavedIdx;
             out.writeInt(owner.mSavedIdx);
             out.writeString(owner.mTag);
+            out.writeInt(owner.mOpCount);
             mNextSavedIdx++;
         }
     }
@@ -200,7 +201,9 @@
         UndoOwner owner = mStateOwners[idx];
         if (owner == null) {
             String tag = in.readString();
-            owner = new UndoOwner(tag);
+            int opCount = in.readInt();
+            owner = new UndoOwner(tag, this);
+            owner.mOpCount = opCount;
             mStateOwners[idx] = owner;
             mOwners.put(tag, owner);
         }
diff --git a/core/java/android/content/UndoOwner.java b/core/java/android/content/UndoOwner.java
index d0cdc95..fd257ab 100644
--- a/core/java/android/content/UndoOwner.java
+++ b/core/java/android/content/UndoOwner.java
@@ -23,8 +23,8 @@
  */
 public class UndoOwner {
     final String mTag;
+    final UndoManager mManager;
 
-    UndoManager mManager;
     Object mData;
     int mOpCount;
 
@@ -32,8 +32,15 @@
     int mStateSeq;
     int mSavedIdx;
 
-    UndoOwner(String tag) {
+    UndoOwner(String tag, UndoManager manager) {
+        if (tag == null) {
+            throw new NullPointerException("tag can't be null");
+        }
+        if (manager == null) {
+            throw new NullPointerException("manager can't be null");
+        }
         mTag = tag;
+        mManager = manager;
     }
 
     /**
@@ -54,4 +61,15 @@
     public Object getData() {
         return mData;
     }
+
+    @Override
+    public String toString() {
+        return "UndoOwner:[mTag=" + mTag +
+                " mManager=" + mManager +
+                " mData=" + mData +
+                " mData=" + mData +
+                " mOpCount=" + mOpCount +
+                " mStateSeq=" + mStateSeq +
+                " mSavedIdx=" + mSavedIdx + "]";
+    }
 }
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 8487dae..71a035e 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -20,7 +20,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
 Utility class to aid in matching URIs in content providers.
@@ -171,7 +170,7 @@
             if (path.length() > 0 && path.charAt(0) == '/') {
                 newPath = path.substring(1);
             }
-            tokens = PATH_SPLIT_PATTERN.split(newPath);
+            tokens = newPath.split("/");
         }
 
         int numTokens = tokens != null ? tokens.length : 0;
@@ -207,8 +206,6 @@
         node.mCode = code;
     }
 
-    static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");
-
     /**
      * Try to match against the path in a url.
      *
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 641f843e..4723c0d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -641,6 +641,13 @@
      */
     public String parentActivityName;
 
+    /**
+     * Value indicating if the activity is resizeable to any dimension.
+     * See {@link android.R.attr#resizeableActivity}.
+     * @hide
+     */
+    public boolean resizeable;
+
     public ActivityInfo() {
     }
 
@@ -702,6 +709,7 @@
         if (uiOptions != 0) {
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
+        pw.println(prefix + "resizeable=" + resizeable);
         super.dumpBack(pw, prefix);
     }
     
@@ -730,6 +738,7 @@
         dest.writeString(parentActivityName);
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
+        dest.writeInt(resizeable ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -757,5 +766,6 @@
         parentActivityName = source.readString();
         persistableMode = source.readInt();
         maxRecents = source.readInt();
+        resizeable = (source.readInt() == 1);
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e07edba..e1a2aa9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -334,44 +334,6 @@
     public static final int FLAG_FULL_BACKUP_ONLY = 1<<26;
 
     /**
-     * Value for {@link #flags}: true if the application is hidden via restrictions and for
-     * most purposes is considered as not installed.
-     * {@hide}
-     */
-    public static final int FLAG_HIDDEN = 1<<27;
-
-    /**
-     * Value for {@link #flags}: set to <code>true</code> if the application
-     * has reported that it is heavy-weight, and thus can not participate in
-     * the normal application lifecycle.
-     *
-     * <p>Comes from the
-     * android.R.styleable#AndroidManifestApplication_cantSaveState
-     * attribute of the &lt;application&gt; tag.
-     *
-     * {@hide}
-     */
-    public static final int FLAG_CANT_SAVE_STATE = 1<<28;
-
-    /**
-     * Value for {@link #flags}: Set to true if the application has been
-     * installed using the forward lock option.
-     *
-     * NOTE: DO NOT CHANGE THIS VALUE!  It is saved in packages.xml.
-     * 
-     * {@hide}
-     */
-    public static final int FLAG_FORWARD_LOCK = 1<<29;
-
-    /**
-     * Value for {@link #flags}: set to {@code true} if the application
-     * is permitted to hold privileged permissions.
-     *
-     * {@hide}
-     */
-    public static final int FLAG_PRIVILEGED = 1<<30;
-
-    /**
      * Value for {@link #flags}: true if code from this application will need to be
      * loaded into other applications' processes. On devices that support multiple
      * instruction sets, this implies the code might be loaded into a process that's
@@ -395,11 +357,60 @@
      * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
      * {@link #FLAG_RESIZEABLE_FOR_SCREENS},
      * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
-     * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
+     * {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE},
+     * {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE},
+     * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
+     * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
+     * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
+     * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
      */
     public int flags = 0;
 
     /**
+     * Value for {@link #privateFlags}: true if the application is hidden via restrictions and for
+     * most purposes is considered as not installed.
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_HIDDEN = 1<<0;
+
+    /**
+     * Value for {@link #privateFlags}: set to <code>true</code> if the application
+     * has reported that it is heavy-weight, and thus can not participate in
+     * the normal application lifecycle.
+     *
+     * <p>Comes from the
+     * android.R.styleable#AndroidManifestApplication_cantSaveState
+     * attribute of the &lt;application&gt; tag.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1;
+
+    /**
+     * Value for {@link #privateFlags}: Set to true if the application has been
+     * installed using the forward lock option.
+     *
+     * NOTE: DO NOT CHANGE THIS VALUE!  It is saved in packages.xml.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2;
+
+    /**
+     * Value for {@link #privateFlags}: set to {@code true} if the application
+     * is permitted to hold privileged permissions.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
+
+    /**
+     * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
+     * {@hide}
+     */
+    public int privateFlags;
+
+    /**
      * The required smallest screen width the application can run on.  If 0,
      * nothing has been specified.  Comes from
      * {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
@@ -598,6 +609,7 @@
         pw.println(prefix + "processName=" + processName);
         pw.println(prefix + "taskAffinity=" + taskAffinity);
         pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+                + " privateFlags=0x" + Integer.toHexString(privateFlags)
                 + " theme=0x" + Integer.toHexString(theme));
         pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
                 + " compatibleWidthLimitDp=" + compatibleWidthLimitDp
@@ -680,6 +692,7 @@
         className = orig.className;
         theme = orig.theme;
         flags = orig.flags;
+        privateFlags = orig.privateFlags;
         requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
         compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
         largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -730,6 +743,7 @@
         dest.writeString(className);
         dest.writeInt(theme);
         dest.writeInt(flags);
+        dest.writeInt(privateFlags);
         dest.writeInt(requiresSmallestWidthDp);
         dest.writeInt(compatibleWidthLimitDp);
         dest.writeInt(largestWidthLimitDp);
@@ -779,6 +793,7 @@
         className = source.readString();
         theme = source.readInt();
         flags = source.readInt();
+        privateFlags = source.readInt();
         requiresSmallestWidthDp = source.readInt();
         compatibleWidthLimitDp = source.readInt();
         largestWidthLimitDp = source.readInt();
@@ -866,6 +881,13 @@
     /**
      * @hide
      */
+    public boolean isForwardLocked() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0dc86ad..b518498 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,6 +111,8 @@
 
     int getFlagsForUid(int uid);
 
+    int getPrivateFlagsForUid(int uid);
+
     boolean isUidPrivileged(int uid);
 
     String[] getAppOpPermissionPackages(String permissionName);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index ee23fcd..87b97aa 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -39,6 +39,7 @@
 
     private ActivityInfo mActivityInfo;
     private ComponentName mComponentName;
+    private ResolveInfo mResolveInfo;
     private UserHandle mUser;
     private long mFirstInstallTime;
 
@@ -52,6 +53,7 @@
     LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user,
             long firstInstallTime) {
         this(context);
+        mResolveInfo = info;
         mActivityInfo = info.activityInfo;
         mComponentName = LauncherApps.getComponentName(info);
         mUser = user;
@@ -92,7 +94,7 @@
      * @return The label for the activity.
      */
     public CharSequence getLabel() {
-        return mActivityInfo.loadLabel(mPm);
+        return mResolveInfo.loadLabel(mPm);
     }
 
     /**
@@ -104,8 +106,22 @@
      * @return The drawable associated with the activity
      */
     public Drawable getIcon(int density) {
-        // TODO: Use density
-        return mActivityInfo.loadIcon(mPm);
+        int iconRes = mResolveInfo.getIconResource();
+        Resources resources = null;
+        Drawable icon = null;
+        // Get the preferred density icon from the app's resources
+        if (density != 0 && iconRes != 0) {
+            try {
+                resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+                icon = resources.getDrawableForDensity(iconRes, density);
+            } catch (NameNotFoundException | Resources.NotFoundException exc) {
+            }
+        }
+        // Get the default density icon
+        if (icon == null) {
+            icon = mResolveInfo.loadIcon(mPm);
+        }
+        return icon;
     }
 
     /**
@@ -151,23 +167,7 @@
      * @return A badged icon for the activity.
      */
     public Drawable getBadgedIcon(int density) {
-        int iconRes = mActivityInfo.getIconResource();
-        Resources resources = null;
-        Drawable originalIcon = null;
-        try {
-            resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
-            try {
-                if (density != 0) {
-                    originalIcon = resources.getDrawableForDensity(iconRes, density);
-                }
-            } catch (Resources.NotFoundException e) {
-            }
-        } catch (NameNotFoundException nnfe) {
-        }
-
-        if (originalIcon == null) {
-            originalIcon = mActivityInfo.loadIcon(mPm);
-        }
+        Drawable originalIcon = getIcon(density);
 
         if (originalIcon instanceof BitmapDrawable) {
             return mPm.getUserBadgedIcon(originalIcon, mUser);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index c164340..c81517a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e9f7c50..0365689 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,11 +16,15 @@
 
 package android.content.pm;
 
+import android.annotation.CheckResult;
+import android.annotation.DrawableRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringRes;
 import android.annotation.SystemApi;
+import android.annotation.XmlRes;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyManager;
@@ -2118,6 +2122,7 @@
      * @see #PERMISSION_GRANTED
      * @see #PERMISSION_DENIED
      */
+    @CheckResult
     public abstract int checkPermission(String permName, String pkgName);
 
     /**
@@ -2245,6 +2250,7 @@
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
+    @CheckResult
     public abstract int checkSignatures(String pkg1, String pkg2);
 
     /**
@@ -2267,6 +2273,7 @@
      * @see #SIGNATURE_NO_MATCH
      * @see #SIGNATURE_UNKNOWN_PACKAGE
      */
+    @CheckResult
     public abstract int checkSignatures(int uid1, int uid2);
 
     /**
@@ -2710,7 +2717,7 @@
      * @return Returns a Drawable holding the requested image.  Returns null if
      * an image could not be found for any reason.
      */
-    public abstract Drawable getDrawable(String packageName, int resid,
+    public abstract Drawable getDrawable(String packageName, @DrawableRes int resid,
             ApplicationInfo appInfo);
 
     /**
@@ -3012,7 +3019,7 @@
      * @return Returns a CharSequence holding the requested text.  Returns null
      * if the text could not be found for any reason.
      */
-    public abstract CharSequence getText(String packageName, int resid,
+    public abstract CharSequence getText(String packageName, @StringRes int resid,
             ApplicationInfo appInfo);
 
     /**
@@ -3031,7 +3038,7 @@
      * data.  Returns null if the xml resource could not be found for any
      * reason.
      */
-    public abstract XmlResourceParser getXml(String packageName, int resid,
+    public abstract XmlResourceParser getXml(String packageName, @XmlRes int resid,
             ApplicationInfo appInfo);
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d7d9e8b..1140756 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -799,6 +800,7 @@
                 pkg.splitCodePaths = lite.splitCodePaths;
                 pkg.splitRevisionCodes = lite.splitRevisionCodes;
                 pkg.splitFlags = new int[num];
+                pkg.splitPrivateFlags = new int[num];
 
                 for (int i = 0; i < num; i++) {
                     parseSplitApk(pkg, i, assets, flags);
@@ -1404,7 +1406,7 @@
 
         /* Set the global "forward lock" flag */
         if ((flags & PARSE_FORWARD_LOCK) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
         }
 
         /* Set the global "on SD card" flag */
@@ -2607,7 +2609,7 @@
                 if (sa.getBoolean(
                         com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
                         false)) {
-                    ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE;
+                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
 
                     // A heavy-weight application can not be in a custom process.
                     // We can do direct compare because we intern all strings.
@@ -2759,9 +2761,17 @@
             }
         }
 
+        addSharedLibrariesForBackwardCompatibility(owner);
+
         return true;
     }
 
+    private static void addSharedLibrariesForBackwardCompatibility(Package owner) {
+        if (owner.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+            owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, "org.apache.http.legacy");
+        }
+    }
+
     /**
      * Parse the {@code application} XML tree at the current parse location in a
      * <em>split APK</em> manifest.
@@ -2946,20 +2956,19 @@
             XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
             boolean receiver, boolean hardwareAccelerated)
             throws XmlPullParserException, IOException {
-        TypedArray sa = res.obtainAttributes(attrs,
-                com.android.internal.R.styleable.AndroidManifestActivity);
+        TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestActivity);
 
         if (mParseActivityArgs == null) {
             mParseActivityArgs = new ParseComponentArgs(owner, outError,
-                    com.android.internal.R.styleable.AndroidManifestActivity_name,
-                    com.android.internal.R.styleable.AndroidManifestActivity_label,
-                    com.android.internal.R.styleable.AndroidManifestActivity_icon,
-                    com.android.internal.R.styleable.AndroidManifestActivity_logo,
-                    com.android.internal.R.styleable.AndroidManifestActivity_banner,
+                    R.styleable.AndroidManifestActivity_name,
+                    R.styleable.AndroidManifestActivity_label,
+                    R.styleable.AndroidManifestActivity_icon,
+                    R.styleable.AndroidManifestActivity_logo,
+                    R.styleable.AndroidManifestActivity_banner,
                     mSeparateProcesses,
-                    com.android.internal.R.styleable.AndroidManifestActivity_process,
-                    com.android.internal.R.styleable.AndroidManifestActivity_description,
-                    com.android.internal.R.styleable.AndroidManifestActivity_enabled);
+                    R.styleable.AndroidManifestActivity_process,
+                    R.styleable.AndroidManifestActivity_description,
+                    R.styleable.AndroidManifestActivity_enabled);
         }
         
         mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
@@ -2972,22 +2981,18 @@
             return null;
         }
 
-        boolean setExported = sa.hasValue(
-                com.android.internal.R.styleable.AndroidManifestActivity_exported);
+        boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
         if (setExported) {
-            a.info.exported = sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
+            a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
         }
 
-        a.info.theme = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
+        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
 
-        a.info.uiOptions = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
+        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
                 a.info.applicationInfo.uiOptions);
 
         String parentName = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
+                R.styleable.AndroidManifestActivity_parentActivityName,
                 Configuration.NATIVE_CONFIG_VERSION);
         if (parentName != null) {
             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
@@ -3001,8 +3006,7 @@
         }
 
         String str;
-        str = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
+        str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
         if (str == null) {
             a.info.permission = owner.applicationInfo.permission;
         } else {
@@ -3010,140 +3014,116 @@
         }
 
         str = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
+                R.styleable.AndroidManifestActivity_taskAffinity,
                 Configuration.NATIVE_CONFIG_VERSION);
         a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
                 owner.applicationInfo.taskAffinity, str, outError);
 
         a.info.flags = 0;
         if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
-                false)) {
+                R.styleable.AndroidManifestActivity_multiprocess, false)) {
             a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
             a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
             a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
             a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
             a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
             a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
                 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
             a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)) {
             a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
         }
 
-        if (sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestActivity_immersive,
-                false)) {
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
 
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_primaryUserOnly, false)) {
+            a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
+        }
+
         if (!receiver) {
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
                     hardwareAccelerated)) {
                 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
             }
 
             a.info.launchMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
-                    ActivityInfo.LAUNCH_MULTIPLE);
+                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
             a.info.documentLaunchMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+                    R.styleable.AndroidManifestActivity_documentLaunchMode,
                     ActivityInfo.DOCUMENT_LAUNCH_NONE);
             a.info.maxRecents = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_maxRecents,
+                    R.styleable.AndroidManifestActivity_maxRecents,
                     ActivityManager.getDefaultAppRecentsLimitStatic());
-            a.info.screenOrientation = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
-                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-            a.info.configChanges = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
-                    0);
+            a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
             a.info.softInputMode = sa.getInt(
-                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
-                    0);
+                    R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
 
             a.info.persistableMode = sa.getInteger(
-                    com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
+                    R.styleable.AndroidManifestActivity_persistableMode,
                     ActivityInfo.PERSIST_ROOT_ONLY);
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
                 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
                 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
                 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
             }
 
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_resumeWhilePausing,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
             }
+
+            a.info.resizeable = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_resizeableActivity,
+                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.MNC);
+            if (a.info.resizeable) {
+                // Fixed screen orientation isn't supported with resizeable activities.
+                a.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+            } else {
+                a.info.screenOrientation = sa.getInt(
+                        R.styleable.AndroidManifestActivity_screenOrientation,
+                        ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
-        }
 
-        if (receiver) {
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
-                    false)) {
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
                 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
                 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
                     Slog.w(TAG, "Activity exported request ignored due to singleUser: "
@@ -3153,16 +3133,12 @@
                     setExported = true;
                 }
             }
-            if (sa.getBoolean(
-                    com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
-                    false)) {
-                a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
-            }
         }
 
         sa.recycle();
 
-        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if (receiver && (owner.applicationInfo.privateFlags
+                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
             // A heavy-weight application can not have receives in its main process
             // We can do direct compare because we intern all strings.
             if (a.info.processName == owner.packageName) {
@@ -3515,7 +3491,8 @@
 
         sa.recycle();
 
-        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
             // A heavy-weight application can not have providers in its main process
             // We can do direct compare because we intern all strings.
             if (p.info.processName == owner.packageName) {
@@ -3794,7 +3771,8 @@
 
         sa.recycle();
 
-        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
             // A heavy-weight application can not have services in its main process
             // We can do direct compare because we intern all strings.
             if (s.info.processName == owner.packageName) {
@@ -4212,6 +4190,13 @@
         /** Flags of any split APKs; ordered by parsed splitName */
         public int[] splitFlags;
 
+        /**
+         * Private flags of any split APKs; ordered by parsed splitName.
+         *
+         * {@hide}
+         */
+        public int[] splitPrivateFlags;
+
         public boolean baseHardwareAccelerated;
 
         // For now we only support one application per package.
@@ -4420,6 +4405,13 @@
             return false;
         }
 
+        /**
+         * @hide
+         */
+        public boolean isForwardLocked() {
+            return applicationInfo.isForwardLocked();
+        }
+
         public String toString() {
             return "Package{"
                 + Integer.toHexString(System.identityHashCode(this))
@@ -4647,9 +4639,9 @@
             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
         if (state.hidden) {
-            ai.flags |= ApplicationInfo.FLAG_HIDDEN;
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
         } else {
-            ai.flags &= ~ApplicationInfo.FLAG_HIDDEN;
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
         }
         if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 391ef22..c2d2f65 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -27,6 +27,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.AtomicFile;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -35,6 +36,7 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.google.android.collect.Lists;
@@ -46,9 +48,9 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -56,6 +58,8 @@
 import java.util.List;
 import java.util.Map;
 
+import libcore.io.IoUtils;
+
 /**
  * Cache of registered services. This cache is lazily built by interrogating
  * {@link PackageManager} on a per-user basis. It's updated as packages are
@@ -71,6 +75,7 @@
 public abstract class RegisteredServicesCache<V> {
     private static final String TAG = "PackageManager";
     private static final boolean DEBUG = false;
+    protected static final String REGISTERED_SERVICES_DIR = "registered_services";
 
     public final Context mContext;
     private final String mInterfaceName;
@@ -81,32 +86,54 @@
     private final Object mServicesLock = new Object();
 
     @GuardedBy("mServicesLock")
-    private boolean mPersistentServicesFileDidNotExist;
-    @GuardedBy("mServicesLock")
     private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
 
     private static class UserServices<V> {
         @GuardedBy("mServicesLock")
-        public final Map<V, Integer> persistentServices = Maps.newHashMap();
+        final Map<V, Integer> persistentServices = Maps.newHashMap();
         @GuardedBy("mServicesLock")
-        public Map<V, ServiceInfo<V>> services = null;
+        Map<V, ServiceInfo<V>> services = null;
+        @GuardedBy("mServicesLock")
+        boolean mPersistentServicesFileDidNotExist = true;
     }
 
+    @GuardedBy("mServicesLock")
     private UserServices<V> findOrCreateUserLocked(int userId) {
+        return findOrCreateUserLocked(userId, true);
+    }
+
+    @GuardedBy("mServicesLock")
+    private UserServices<V> findOrCreateUserLocked(int userId, boolean loadFromFileIfNew) {
         UserServices<V> services = mUserServices.get(userId);
         if (services == null) {
             services = new UserServices<V>();
             mUserServices.put(userId, services);
+            if (loadFromFileIfNew && mSerializerAndParser != null) {
+                // Check if user exists and try loading data from file
+                // clear existing data if there was an error during migration
+                UserInfo user = getUser(userId);
+                if (user != null) {
+                    AtomicFile file = createFileForUser(user.id);
+                    if (file.getBaseFile().exists()) {
+                        if (DEBUG) {
+                            Slog.i(TAG, String.format("Loading u%s data from %s", user.id, file));
+                        }
+                        InputStream is = null;
+                        try {
+                            is = file.openRead();
+                            readPersistentServicesLocked(is);
+                        } catch (Exception e) {
+                            Log.w(TAG, "Error reading persistent services for user " + user.id, e);
+                        } finally {
+                            IoUtils.closeQuietly(is);
+                        }
+                    }
+                }
+            }
         }
         return services;
     }
 
-    /**
-     * This file contains the list of known services. We would like to maintain this forever
-     * so we store it as an XML file.
-     */
-    private final AtomicFile mPersistentServicesFile;
-
     // the listener and handler are synchronized on "this" and must be updated together
     private RegisteredServicesCacheListener<V> mListener;
     private Handler mHandler;
@@ -119,13 +146,7 @@
         mAttributesName = attributeName;
         mSerializerAndParser = serializerAndParser;
 
-        File dataDir = Environment.getDataDirectory();
-        File systemDir = new File(dataDir, "system");
-        File syncDir = new File(systemDir, "registered_services");
-        mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml"));
-
-        // Load persisted services from disk
-        readPersistentServicesLocked();
+        migrateIfNecessaryLocked();
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -139,6 +160,11 @@
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mExternalReceiver, sdFilter);
+
+        // Register for user-related events
+        IntentFilter userFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(mUserRemovedReceiver, userFilter);
     }
 
     private final void handlePackageEvent(Intent intent, int userId) {
@@ -190,6 +216,17 @@
         }
     };
 
+    private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            if (DEBUG) {
+                Slog.d(TAG, "u" + userId + " removed - cleaning up");
+            }
+            onUserRemoved(userId);
+        }
+    };
+
     public void invalidateCache(int userId) {
         synchronized (mServicesLock) {
             final UserServices<V> user = findOrCreateUserLocked(userId);
@@ -303,7 +340,8 @@
         }
     }
 
-    private boolean inSystemImage(int callerUid) {
+    @VisibleForTesting
+    protected boolean inSystemImage(int callerUid) {
         String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
         for (String name : packages) {
             try {
@@ -319,6 +357,13 @@
         return false;
     }
 
+    @VisibleForTesting
+    protected List<ResolveInfo> queryIntentServices(int userId) {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.queryIntentServicesAsUser(
+                new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+    }
+
     /**
      * Populate {@link UserServices#services} by scanning installed packages for
      * given {@link UserHandle}.
@@ -331,10 +376,8 @@
             Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
         }
 
-        final PackageManager pm = mContext.getPackageManager();
         final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>();
-        final List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(
-                new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId);
+        final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
         for (ResolveInfo resolveInfo : resolveInfos) {
             try {
                 ServiceInfo<V> info = parseServiceInfo(resolveInfo);
@@ -343,9 +386,7 @@
                     continue;
                 }
                 serviceInfos.add(info);
-            } catch (XmlPullParserException e) {
-                Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
-            } catch (IOException e) {
+            } catch (XmlPullParserException|IOException e) {
                 Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
             }
         }
@@ -377,7 +418,7 @@
                     changed = true;
                     user.services.put(info.type, info);
                     user.persistentServices.put(info.type, info.uid);
-                    if (!(mPersistentServicesFileDidNotExist && firstScan)) {
+                    if (!(user.mPersistentServicesFileDidNotExist && firstScan)) {
                         notifyListener(info.type, userId, false /* removed */);
                     }
                 } else if (previousUid == info.uid) {
@@ -447,7 +488,7 @@
                 }
             }
             if (changed) {
-                writePersistentServicesLocked();
+                writePersistentServicesLocked(user, userId);
             }
         }
     }
@@ -481,7 +522,8 @@
         return false;
     }
 
-    private ServiceInfo<V> parseServiceInfo(ResolveInfo service)
+    @VisibleForTesting
+    protected ServiceInfo<V> parseServiceInfo(ResolveInfo service)
             throws XmlPullParserException, IOException {
         android.content.pm.ServiceInfo si = service.serviceInfo;
         ComponentName componentName = new ComponentName(si.packageName, si.name);
@@ -528,93 +570,156 @@
     /**
      * Read all sync status back in to the initial engine state.
      */
-    private void readPersistentServicesLocked() {
-        mUserServices.clear();
+    private void readPersistentServicesLocked(InputStream is)
+            throws XmlPullParserException, IOException {
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(is, null);
+        int eventType = parser.getEventType();
+        while (eventType != XmlPullParser.START_TAG
+                && eventType != XmlPullParser.END_DOCUMENT) {
+            eventType = parser.next();
+        }
+        String tagName = parser.getName();
+        if ("services".equals(tagName)) {
+            eventType = parser.next();
+            do {
+                if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) {
+                    tagName = parser.getName();
+                    if ("service".equals(tagName)) {
+                        V service = mSerializerAndParser.createFromXml(parser);
+                        if (service == null) {
+                            break;
+                        }
+                        String uidString = parser.getAttributeValue(null, "uid");
+                        final int uid = Integer.parseInt(uidString);
+                        final int userId = UserHandle.getUserId(uid);
+                        final UserServices<V> user = findOrCreateUserLocked(userId,
+                                false /*loadFromFileIfNew*/) ;
+                        user.persistentServices.put(service, uid);
+                    }
+                }
+                eventType = parser.next();
+            } while (eventType != XmlPullParser.END_DOCUMENT);
+        }
+    }
+
+    private void migrateIfNecessaryLocked() {
         if (mSerializerAndParser == null) {
             return;
         }
-        FileInputStream fis = null;
-        try {
-            mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists();
-            if (mPersistentServicesFileDidNotExist) {
-                return;
-            }
-            fis = mPersistentServicesFile.openRead();
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(fis, null);
-            int eventType = parser.getEventType();
-            while (eventType != XmlPullParser.START_TAG
-                    && eventType != XmlPullParser.END_DOCUMENT) {
-                eventType = parser.next();
-            }
-            String tagName = parser.getName();
-            if ("services".equals(tagName)) {
-                eventType = parser.next();
-                do {
-                    if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) {
-                        tagName = parser.getName();
-                        if ("service".equals(tagName)) {
-                            V service = mSerializerAndParser.createFromXml(parser);
-                            if (service == null) {
-                                break;
+        File systemDir = new File(getDataDirectory(), "system");
+        File syncDir = new File(systemDir, REGISTERED_SERVICES_DIR);
+        AtomicFile oldFile = new AtomicFile(new File(syncDir, mInterfaceName + ".xml"));
+        boolean oldFileExists = oldFile.getBaseFile().exists();
+
+        if (oldFileExists) {
+            File marker = new File(syncDir, mInterfaceName + ".xml.migrated");
+            // if not migrated, perform the migration and add a marker
+            if (!marker.exists()) {
+                if (DEBUG) {
+                    Slog.i(TAG, "Marker file " + marker + " does not exist - running migration");
+                }
+                InputStream is = null;
+                try {
+                    is = oldFile.openRead();
+                    mUserServices.clear();
+                    readPersistentServicesLocked(is);
+                } catch (Exception e) {
+                    Log.w(TAG, "Error reading persistent services, starting from scratch", e);
+                } finally {
+                    IoUtils.closeQuietly(is);
+                }
+                try {
+                    for (UserInfo user : getUsers()) {
+                        UserServices<V> userServices = mUserServices.get(user.id);
+                        if (userServices != null) {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Migrating u" + user.id + " services "
+                                        + userServices.persistentServices);
                             }
-                            String uidString = parser.getAttributeValue(null, "uid");
-                            final int uid = Integer.parseInt(uidString);
-                            final int userId = UserHandle.getUserId(uid);
-                            final UserServices<V> user = findOrCreateUserLocked(userId);
-                            user.persistentServices.put(service, uid);
+                            writePersistentServicesLocked(userServices, user.id);
                         }
                     }
-                    eventType = parser.next();
-                } while (eventType != XmlPullParser.END_DOCUMENT);
-            }
-        } catch (Exception e) {
-            Log.w(TAG, "Error reading persistent services, starting from scratch", e);
-        } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (java.io.IOException e1) {
+                    marker.createNewFile();
+                } catch (Exception e) {
+                    Log.w(TAG, "Migration failed", e);
                 }
+                // Migration is complete and we don't need to keep data for all users anymore,
+                // It will be loaded from a new location when requested
+                mUserServices.clear();
             }
         }
     }
 
     /**
-     * Write all sync status to the sync status file.
+     * Writes services of a specified user to the file.
      */
-    private void writePersistentServicesLocked() {
+    private void writePersistentServicesLocked(UserServices<V> user, int userId) {
         if (mSerializerAndParser == null) {
             return;
         }
+        AtomicFile atomicFile = createFileForUser(userId);
         FileOutputStream fos = null;
         try {
-            fos = mPersistentServicesFile.startWrite();
+            fos = atomicFile.startWrite();
             XmlSerializer out = new FastXmlSerializer();
             out.setOutput(fos, "utf-8");
             out.startDocument(null, true);
             out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             out.startTag(null, "services");
-            for (int i = 0; i < mUserServices.size(); i++) {
-                final UserServices<V> user = mUserServices.valueAt(i);
-                for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
-                    out.startTag(null, "service");
-                    out.attribute(null, "uid", Integer.toString(service.getValue()));
-                    mSerializerAndParser.writeAsXml(service.getKey(), out);
-                    out.endTag(null, "service");
-                }
+            for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
+                out.startTag(null, "service");
+                out.attribute(null, "uid", Integer.toString(service.getValue()));
+                mSerializerAndParser.writeAsXml(service.getKey(), out);
+                out.endTag(null, "service");
             }
             out.endTag(null, "services");
             out.endDocument();
-            mPersistentServicesFile.finishWrite(fos);
-        } catch (java.io.IOException e1) {
+            atomicFile.finishWrite(fos);
+        } catch (IOException e1) {
             Log.w(TAG, "Error writing accounts", e1);
             if (fos != null) {
-                mPersistentServicesFile.failWrite(fos);
+                atomicFile.failWrite(fos);
             }
         }
     }
 
+    @VisibleForTesting
+    protected void onUserRemoved(int userId) {
+        mUserServices.remove(userId);
+    }
+
+    @VisibleForTesting
+    protected List<UserInfo> getUsers() {
+        return UserManager.get(mContext).getUsers(true);
+    }
+
+    @VisibleForTesting
+    protected UserInfo getUser(int userId) {
+        return UserManager.get(mContext).getUserInfo(userId);
+    }
+
+    private AtomicFile createFileForUser(int userId) {
+        File userDir = getUserSystemDirectory(userId);
+        File userFile = new File(userDir, REGISTERED_SERVICES_DIR + "/" + mInterfaceName + ".xml");
+        return new AtomicFile(userFile);
+    }
+
+    @VisibleForTesting
+    protected File getUserSystemDirectory(int userId) {
+        return Environment.getUserSystemDirectory(userId);
+    }
+
+    @VisibleForTesting
+    protected File getDataDirectory() {
+        return Environment.getDataDirectory();
+    }
+
+    @VisibleForTesting
+    protected Map<V, Integer> getPersistentServices(int userId) {
+        return findOrCreateUserLocked(userId).persistentServices;
+    }
+
     public abstract V parseServiceAttributes(Resources res,
             String packageName, AttributeSet attrs);
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index ecae52c..a176593 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -627,7 +627,21 @@
      *
      * {@hide}
      */
-    public native final int addOverlayPath(String idmapPath);
+
+    public final int addOverlayPath(String idmapPath) {
+        synchronized (this) {
+            int res = addOverlayPathNative(idmapPath);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    /**
+     * See addOverlayPath.
+     *
+     * {@hide}
+     */
+    public native final int addOverlayPathNative(String idmapPath);
 
     /**
      * Add multiple sets of assets to the asset manager at once.  See
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 68a39d3..841b09d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,8 +16,13 @@
 
 package android.content.res;
 
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
 import android.graphics.Color;
 
+import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
@@ -25,6 +30,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.MathUtils;
 import android.util.SparseArray;
 import android.util.StateSet;
@@ -64,71 +70,128 @@
  * List Resource</a>.</p>
  */
 public class ColorStateList implements Parcelable {
-    private int[][] mStateSpecs; // must be parallel to mColors
-    private int[] mColors;      // must be parallel to mStateSpecs
-    private int mDefaultColor = 0xffff0000;
-
+    private static final String TAG = "ColorStateList";
+    private static final int DEFAULT_COLOR = Color.RED;
     private static final int[][] EMPTY = new int[][] { new int[0] };
     private static final SparseArray<WeakReference<ColorStateList>> sCache =
                             new SparseArray<WeakReference<ColorStateList>>();
 
-    private ColorStateList() { }
+    private int[][] mThemeAttrs;
+    private int mChangingConfigurations;
+
+    private int[][] mStateSpecs;
+    private int[] mColors;
+    private int mDefaultColor;
+    private boolean mIsOpaque;
+
+    private ColorStateList() {
+        // Not publicly instantiable.
+    }
 
     /**
      * Creates a ColorStateList that returns the specified mapping from
      * states to colors.
      */
-    public ColorStateList(int[][] states, int[] colors) {
+    public ColorStateList(int[][] states, @ColorInt int[] colors) {
         mStateSpecs = states;
         mColors = colors;
 
-        if (states.length > 0) {
-            mDefaultColor = colors[0];
-
-            for (int i = 0; i < states.length; i++) {
-                if (states[i].length == 0) {
-                    mDefaultColor = colors[i];
-                }
-            }
-        }
+        onColorsChanged();
     }
 
     /**
-     * Creates or retrieves a ColorStateList that always returns a single color.
+     * @return A ColorStateList containing a single color.
      */
-    public static ColorStateList valueOf(int color) {
-        // TODO: should we collect these eventually?
+    @NonNull
+    public static ColorStateList valueOf(@ColorInt int color) {
         synchronized (sCache) {
-            final WeakReference<ColorStateList> ref = sCache.get(color);
+            final int index = sCache.indexOfKey(color);
+            if (index >= 0) {
+                final ColorStateList cached = sCache.valueAt(index).get();
+                if (cached != null) {
+                    return cached;
+                }
 
-            ColorStateList csl = ref != null ? ref.get() : null;
-            if (csl != null) {
-                return csl;
+                // Prune missing entry.
+                sCache.removeAt(index);
             }
 
-            csl = new ColorStateList(EMPTY, new int[] { color });
+            // Prune the cache before adding new items.
+            final int N = sCache.size();
+            for (int i = N - 1; i >= 0; i--) {
+                if (sCache.valueAt(i).get() == null) {
+                    sCache.removeAt(i);
+                }
+            }
+
+            final ColorStateList csl = new ColorStateList(EMPTY, new int[] { color });
             sCache.put(color, new WeakReference<ColorStateList>(csl));
             return csl;
         }
     }
 
     /**
-     * Create a ColorStateList from an XML document, given a set of {@link Resources}.
+     * Creates a ColorStateList with the same properties as another
+     * ColorStateList.
+     * <p>
+     * The properties of the new ColorStateList can be modified without
+     * affecting the source ColorStateList.
+     *
+     * @param orig the source color state list
      */
+    private ColorStateList(ColorStateList orig) {
+        if (orig != null) {
+            mStateSpecs = orig.mStateSpecs;
+            mDefaultColor = orig.mDefaultColor;
+            mIsOpaque = orig.mIsOpaque;
+
+            // Deep copy, this may change due to theming.
+            mColors = orig.mColors.clone();
+        }
+    }
+
+    /**
+     * Creates a ColorStateList from an XML document.
+     *
+     * @param r Resources against which the ColorStateList should be inflated.
+     * @param parser Parser for the XML document defining the ColorStateList.
+     * @return A new color state list.
+     *
+     * @deprecated Use #createFromXml(Resources, XmlPullParser parser, Theme)
+     */
+    @NonNull
+    @Deprecated
     public static ColorStateList createFromXml(Resources r, XmlPullParser parser)
             throws XmlPullParserException, IOException {
+        return createFromXml(r, parser, null);
+    }
+
+    /**
+     * Creates a ColorStateList from an XML document using given a set of
+     * {@link Resources} and a {@link Theme}.
+     *
+     * @param r Resources against which the ColorStateList should be inflated.
+     * @param parser Parser for the XML document defining the ColorStateList.
+     * @param theme Optional theme to apply to the color state list, may be
+     *              {@code null}.
+     * @return A new color state list.
+     */
+    @NonNull
+    public static ColorStateList createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @Nullable Theme theme) throws XmlPullParserException, IOException {
         final AttributeSet attrs = Xml.asAttributeSet(parser);
 
         int type;
-        while ((type=parser.next()) != XmlPullParser.START_TAG
+        while ((type = parser.next()) != XmlPullParser.START_TAG
                    && type != XmlPullParser.END_DOCUMENT) {
+            // Seek parser to start tag.
         }
 
         if (type != XmlPullParser.START_TAG) {
             throw new XmlPullParserException("No start tag found");
         }
 
-        return createFromXmlInner(r, parser, attrs);
+        return createFromXmlInner(r, parser, attrs, theme);
     }
 
     /**
@@ -136,28 +199,31 @@
      * tag in an XML document, tries to create a ColorStateList from that tag.
      *
      * @throws XmlPullParserException if the current tag is not &lt;selector>
-     * @return A color state list for the current tag.
+     * @return A new color state list for the current tag.
      */
-    private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser,
-            AttributeSet attrs) throws XmlPullParserException, IOException {
-        final ColorStateList colorStateList;
+    @NonNull
+    private static ColorStateList createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
         final String name = parser.getName();
-        if (name.equals("selector")) {
-            colorStateList = new ColorStateList();
-        } else {
+        if (!name.equals("selector")) {
             throw new XmlPullParserException(
-                    parser.getPositionDescription() + ": invalid drawable tag " + name);
+                    parser.getPositionDescription() + ": invalid color state list tag " + name);
         }
 
-        colorStateList.inflate(r, parser, attrs);
+        final ColorStateList colorStateList = new ColorStateList();
+        colorStateList.inflate(r, parser, attrs, theme);
         return colorStateList;
     }
 
     /**
-     * Creates a new ColorStateList that has the same states and
-     * colors as this one but where each color has the specified alpha value
-     * (0-255).
+     * Creates a new ColorStateList that has the same states and colors as this
+     * one but where each color has the specified alpha value (0-255).
+     *
+     * @param alpha The new alpha channel value (0-255).
+     * @return A new color state list.
      */
+    @NonNull
     public ColorStateList withAlpha(int alpha) {
         final int[] colors = new int[mColors.length];
         final int len = colors.length;
@@ -171,88 +237,154 @@
     /**
      * Fill in this object based on the contents of an XML "selector" element.
      */
-    private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+    private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
-        int type;
-
         final int innerDepth = parser.getDepth()+1;
         int depth;
+        int type;
+
+        int changingConfigurations = 0;
+        int defaultColor = DEFAULT_COLOR;
+
+        boolean hasUnresolvedAttrs = false;
 
         int[][] stateSpecList = ArrayUtils.newUnpaddedArray(int[].class, 20);
+        int[][] themeAttrsList = new int[stateSpecList.length][];
         int[] colorList = new int[stateSpecList.length];
         int listSize = 0;
 
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && ((depth=parser.getDepth()) >= innerDepth
-                   || type != XmlPullParser.END_TAG)) {
-            if (type != XmlPullParser.START_TAG) {
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+               && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG || depth > innerDepth
+                    || !parser.getName().equals("item")) {
                 continue;
             }
 
-            if (depth > innerDepth || !parser.getName().equals("item")) {
-                continue;
-            }
+            final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
+                    R.styleable.ColorStateListItem);
+            final int[] themeAttrs = a.extractThemeAttrs();
+            final int baseColor = a.getColor(R.styleable.ColorStateListItem_color, 0);
+            final float alphaMod = a.getFloat(R.styleable.ColorStateListItem_alpha, 1.0f);
 
-            int alphaRes = 0;
-            float alpha = 1.0f;
-            int colorRes = 0;
-            int color = 0xffff0000;
-            boolean haveColor = false;
+            changingConfigurations |= a.getChangingConfigurations();
 
-            int i;
+            a.recycle();
+
+            // Parse all unrecognized attributes as state specifiers.
             int j = 0;
             final int numAttrs = attrs.getAttributeCount();
             int[] stateSpec = new int[numAttrs];
-            for (i = 0; i < numAttrs; i++) {
+            for (int i = 0; i < numAttrs; i++) {
                 final int stateResId = attrs.getAttributeNameResource(i);
-                if (stateResId == 0) break;
-                if (stateResId == com.android.internal.R.attr.alpha) {
-                    alphaRes = attrs.getAttributeResourceValue(i, 0);
-                    if (alphaRes == 0) {
-                        alpha = attrs.getAttributeFloatValue(i, 1.0f);
-                    }
-                } else if (stateResId == com.android.internal.R.attr.color) {
-                    colorRes = attrs.getAttributeResourceValue(i, 0);
-                    if (colorRes == 0) {
-                        color = attrs.getAttributeIntValue(i, color);
-                        haveColor = true;
-                    }
-                } else {
-                    stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
-                            ? stateResId : -stateResId;
+                switch (stateResId) {
+                    case R.attr.color:
+                    case R.attr.alpha:
+                        // Recognized attribute, ignore.
+                        break;
+                    default:
+                        stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
+                                ? stateResId : -stateResId;
                 }
             }
             stateSpec = StateSet.trimStateSet(stateSpec, j);
 
-            if (colorRes != 0) {
-                color = r.getColor(colorRes);
-            } else if (!haveColor) {
-                throw new XmlPullParserException(
-                        parser.getPositionDescription()
-                        + ": <item> tag requires a 'android:color' attribute.");
-            }
-
-            if (alphaRes != 0) {
-                alpha = r.getFloat(alphaRes);
-            }
-
             // Apply alpha modulation.
-            final int alphaMod = MathUtils.constrain((int) (Color.alpha(color) * alpha), 0, 255);
-            color = (color & 0xFFFFFF) | (alphaMod << 24);
-
+            final int color = modulateColorAlpha(baseColor, alphaMod);
             if (listSize == 0 || stateSpec.length == 0) {
-                mDefaultColor = color;
+                defaultColor = color;
+            }
+
+            if (themeAttrs != null) {
+                hasUnresolvedAttrs = true;
             }
 
             colorList = GrowingArrayUtils.append(colorList, listSize, color);
+            themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
             stateSpecList = GrowingArrayUtils.append(stateSpecList, listSize, stateSpec);
             listSize++;
         }
 
+        mChangingConfigurations = changingConfigurations;
+        mDefaultColor = defaultColor;
+
+        if (hasUnresolvedAttrs) {
+            mThemeAttrs = new int[listSize][];
+            System.arraycopy(themeAttrsList, 0, mThemeAttrs, 0, listSize);
+        } else {
+            mThemeAttrs = null;
+        }
+
         mColors = new int[listSize];
         mStateSpecs = new int[listSize][];
         System.arraycopy(colorList, 0, mColors, 0, listSize);
         System.arraycopy(stateSpecList, 0, mStateSpecs, 0, listSize);
+
+        onColorsChanged();
+    }
+
+    /**
+     * Returns whether a theme can be applied to this color state list, which
+     * usually indicates that the color state list has unresolved theme
+     * attributes.
+     *
+     * @return whether a theme can be applied to this color state list
+     */
+    public boolean canApplyTheme() {
+        return mThemeAttrs != null;
+    }
+
+    /**
+     * Applies a theme to this color state list.
+     *
+     * @param t the theme to apply
+     */
+    public void applyTheme(Theme t) {
+        if (mThemeAttrs == null) {
+            return;
+        }
+
+        boolean hasUnresolvedAttrs = false;
+
+        final int[][] themeAttrsList = mThemeAttrs;
+        final int N = themeAttrsList.length;
+        for (int i = 0; i < N; i++) {
+            if (themeAttrsList[i] != null) {
+                final TypedArray a = t.resolveAttributes(themeAttrsList[i],
+                        R.styleable.ColorStateListItem);
+                final int baseColor = a.getColor(
+                        R.styleable.ColorStateListItem_color, mColors[i]);
+                final float alphaMod = a.getFloat(
+                        R.styleable.ColorStateListItem_alpha, 1.0f);
+
+                mColors[i] = modulateColorAlpha(baseColor, alphaMod);
+                mChangingConfigurations |= a.getChangingConfigurations();
+
+                themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
+                if (themeAttrsList[i] != null) {
+                    hasUnresolvedAttrs = true;
+                }
+
+                a.recycle();
+            }
+        }
+
+        if (!hasUnresolvedAttrs) {
+            mThemeAttrs = null;
+        }
+
+        onColorsChanged();
+    }
+
+    private int modulateColorAlpha(int baseColor, float alphaMod) {
+        if (alphaMod == 1.0f) {
+            return baseColor;
+        }
+
+        final int baseAlpha = Color.alpha(baseColor);
+        final int alpha = MathUtils.constrain((int) (baseAlpha * alphaMod + 0.5f), 0, 255);
+        final int color = (baseColor & 0xFFFFFF) | (alpha << 24);
+        return color;
     }
 
     /**
@@ -275,28 +407,24 @@
      * @return True if this color state list is opaque.
      */
     public boolean isOpaque() {
-        final int n = mColors.length;
-        for (int i = 0; i < n; i++) {
-            if (Color.alpha(mColors[i]) != 0xFF) {
-                return false;
-            }
-        }
-        return true;
+        return mIsOpaque;
     }
 
     /**
-     * Return the color associated with the given set of {@link android.view.View} states.
+     * Return the color associated with the given set of
+     * {@link android.view.View} states.
      *
      * @param stateSet an array of {@link android.view.View} states
-     * @param defaultColor the color to return if there's not state spec in this
-     * {@link ColorStateList} that matches the stateSet.
+     * @param defaultColor the color to return if there's no matching state
+     *                     spec in this {@link ColorStateList} that matches the
+     *                     stateSet.
      *
      * @return the color associated with that set of states in this {@link ColorStateList}.
      */
-    public int getColorForState(int[] stateSet, int defaultColor) {
+    public int getColorForState(@Nullable int[] stateSet, int defaultColor) {
         final int setLength = mStateSpecs.length;
         for (int i = 0; i < setLength; i++) {
-            int[] stateSpec = mStateSpecs[i];
+            final int[] stateSpec = mStateSpecs[i];
             if (StateSet.stateSetMatches(stateSpec, stateSet)) {
                 return mColors[i];
             }
@@ -309,12 +437,15 @@
      *
      * @return the default color in this {@link ColorStateList}.
      */
+    @ColorInt
     public int getDefaultColor() {
         return mDefaultColor;
     }
 
     /**
-     * Return the states in this {@link ColorStateList}.
+     * Return the states in this {@link ColorStateList}. The returned array
+     * should not be modified.
+     *
      * @return the states in this {@link ColorStateList}
      * @hide
      */
@@ -323,7 +454,9 @@
     }
 
     /**
-     * Return the colors in this {@link ColorStateList}.
+     * Return the colors in this {@link ColorStateList}. The returned array
+     * should not be modified.
+     *
      * @return the colors in this {@link ColorStateList}
      * @hide
      */
@@ -331,52 +464,82 @@
         return mColors;
     }
 
+    @Override
+    public String toString() {
+        return "ColorStateList{" +
+               "mThemeAttrs=" + Arrays.deepToString(mThemeAttrs) +
+               "mChangingConfigurations=" + mChangingConfigurations +
+               "mStateSpecs=" + Arrays.deepToString(mStateSpecs) +
+               "mColors=" + Arrays.toString(mColors) +
+               "mDefaultColor=" + mDefaultColor + '}';
+    }
+
     /**
-     * If the color state list does not already have an entry matching the
-     * specified state, prepends a state set and color pair to a color state
-     * list.
-     * <p>
-     * This is a workaround used in TimePicker and DatePicker until we can
-     * add support for theme attributes in ColorStateList.
-     *
-     * @param colorStateList the source color state list
-     * @param state the state to prepend
-     * @param color the color to use for the given state
-     * @return a new color state list, or the source color state list if there
-     *         was already a matching state set
-     *
-     * @hide Remove when we can support theme attributes.
+     * Updates the default color and opacity.
      */
-    public static ColorStateList addFirstIfMissing(
-            ColorStateList colorStateList, int state, int color) {
-        final int[][] inputStates = colorStateList.getStates();
-        for (int i = 0; i < inputStates.length; i++) {
-            final int[] inputState = inputStates[i];
-            for (int j = 0; j < inputState.length; j++) {
-                if (inputState[j] == state) {
-                    return colorStateList;
+    private void onColorsChanged() {
+        int defaultColor = DEFAULT_COLOR;
+        boolean isOpaque = true;
+
+        final int[][] states = mStateSpecs;
+        final int[] colors = mColors;
+        final int N = states.length;
+        if (N > 0) {
+            defaultColor = colors[0];
+
+            for (int i = N - 1; i > 0; i--) {
+                if (states[i].length == 0) {
+                    defaultColor = colors[i];
+                    break;
+                }
+            }
+
+            for (int i = 0; i < N; i++) {
+                if (Color.alpha(colors[i]) != 0xFF) {
+                    isOpaque = false;
+                    break;
                 }
             }
         }
 
-        final int[][] outputStates = new int[inputStates.length + 1][];
-        System.arraycopy(inputStates, 0, outputStates, 1, inputStates.length);
-        outputStates[0] = new int[] { state };
-
-        final int[] inputColors = colorStateList.getColors();
-        final int[] outputColors = new int[inputColors.length + 1];
-        System.arraycopy(inputColors, 0, outputColors, 1, inputColors.length);
-        outputColors[0] = color;
-
-        return new ColorStateList(outputStates, outputColors);
+        mDefaultColor = defaultColor;
+        mIsOpaque = isOpaque;
     }
 
-    @Override
-    public String toString() {
-        return "ColorStateList{" +
-               "mStateSpecs=" + Arrays.deepToString(mStateSpecs) +
-               "mColors=" + Arrays.toString(mColors) +
-               "mDefaultColor=" + mDefaultColor + '}';
+    /**
+     * @return A factory that can create new instances of this ColorStateList.
+     */
+    ColorStateListFactory getFactory() {
+        return new ColorStateListFactory(this);
+    }
+
+    static class ColorStateListFactory extends ConstantState<ColorStateList> {
+        final ColorStateList mSrc;
+
+        public ColorStateListFactory(ColorStateList src) {
+            mSrc = src;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mSrc.mChangingConfigurations;
+        }
+
+        @Override
+        public ColorStateList newInstance() {
+            return mSrc;
+        }
+
+        @Override
+        public ColorStateList newInstance(Resources res, Theme theme) {
+            if (theme == null || !mSrc.canApplyTheme()) {
+                return mSrc;
+            }
+
+            final ColorStateList clone = new ColorStateList(mSrc);
+            clone.applyTheme(theme);
+            return clone;
+        }
     }
 
     @Override
@@ -386,6 +549,9 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        if (canApplyTheme()) {
+            Log.w(TAG, "Wrote partially-resolved ColorStateList to parcel!");
+        }
         final int N = mStateSpecs.length;
         dest.writeInt(N);
         for (int i = 0; i < N; i++) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 73913b6..5dc9ef9 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,33 +16,48 @@
 
 package android.content.res;
 
-import android.animation.Animator;
-import android.animation.StateListAnimator;
-import android.annotation.NonNull;
-import android.util.Pools.SynchronizedPool;
-import android.view.ViewDebug;
+import android.annotation.ColorInt;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.animation.Animator;
+import android.animation.StateListAnimator;
+import android.annotation.AnimRes;
+import android.annotation.AnyRes;
+import android.annotation.ArrayRes;
+import android.annotation.BoolRes;
+import android.annotation.ColorRes;
+import android.annotation.DimenRes;
+import android.annotation.DrawableRes;
+import android.annotation.FractionRes;
+import android.annotation.IntegerRes;
+import android.annotation.LayoutRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.PluralsRes;
+import android.annotation.RawRes;
+import android.annotation.StringRes;
+import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
+import android.content.res.ColorStateList.ColorStateListFactory;
 import android.graphics.Movie;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 import android.util.TypedValue;
-import android.util.LongSparseArray;
+import android.view.ViewDebug;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -97,8 +112,8 @@
     private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
     private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
             = new LongSparseArray<ConstantState>();
-    private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
-            = new LongSparseArray<ColorStateList>();
+    private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists
+            = new LongSparseArray<ColorStateListFactory>();
 
     // Pool of TypedArrays targeted to this Resources object.
     final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<TypedArray>(5);
@@ -116,8 +131,8 @@
             new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
     private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
             new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
-    private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
-            new LongSparseArray<WeakReference<ColorStateList>>();
+    private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
+            new ConfigurationBoundResourceCache<ColorStateList>(this);
     private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
             new ConfigurationBoundResourceCache<Animator>(this);
     private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
@@ -140,9 +155,6 @@
 
     private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
 
-    @SuppressWarnings("unused")
-    private WeakReference<IBinder> mToken;
-
     static {
         sPreloadedDrawables = new LongSparseArray[2];
         sPreloadedDrawables[0] = new LongSparseArray<ConstantState>();
@@ -223,46 +235,44 @@
     /**
      * Create a new Resources object on top of an existing set of assets in an
      * AssetManager.
-     * 
-     * @param assets Previously created AssetManager. 
-     * @param metrics Current display metrics to consider when 
+     *
+     * @param assets Previously created AssetManager.
+     * @param metrics Current display metrics to consider when
      *                selecting/computing resource values.
-     * @param config Desired device configuration to consider when 
+     * @param config Desired device configuration to consider when
      *               selecting/computing resource values (optional).
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
-        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
     }
 
     /**
      * Creates a new Resources object with CompatibilityInfo.
-     * 
-     * @param assets Previously created AssetManager. 
-     * @param metrics Current display metrics to consider when 
+     *
+     * @param assets Previously created AssetManager.
+     * @param metrics Current display metrics to consider when
      *                selecting/computing resource values.
-     * @param config Desired device configuration to consider when 
+     * @param config Desired device configuration to consider when
      *               selecting/computing resource values (optional).
      * @param compatInfo this resource's compatibility info. Must not be null.
-     * @param token The Activity token for determining stack affiliation. Usually null.
      * @hide
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
-            CompatibilityInfo compatInfo, IBinder token) {
+            CompatibilityInfo compatInfo) {
         mAssets = assets;
         mMetrics.setToDefaults();
         if (compatInfo != null) {
             mCompatibilityInfo = compatInfo;
         }
-        mToken = new WeakReference<IBinder>(token);
         updateConfiguration(config, metrics);
         assets.ensureStringBlocks();
     }
 
     /**
      * Return a global shared Resources object that provides access to only
-     * system resources (no application resources), and is not configured for 
-     * the current screen (can not use dimension units, does not change based 
-     * on orientation, etc). 
+     * system resources (no application resources), and is not configured for
+     * the current screen (can not use dimension units, does not change based
+     * on orientation, etc).
      */
     public static Resources getSystem() {
         synchronized (sSync) {
@@ -291,7 +301,7 @@
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
-    public CharSequence getText(int id) throws NotFoundException {
+    public CharSequence getText(@StringRes int id) throws NotFoundException {
         CharSequence res = mAssets.getResourceText(id);
         if (res != null) {
             return res;
@@ -320,7 +330,8 @@
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
-    public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
+    public CharSequence getQuantityText(@PluralsRes int id, int quantity)
+            throws NotFoundException {
         NativePluralRules rule = getPluralRule();
         CharSequence res = mAssets.getResourceBagText(id,
                 attrForQuantityCode(rule.quantityForInt(quantity)));
@@ -381,7 +392,7 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getString(int id) throws NotFoundException {
+    public String getString(@StringRes int id) throws NotFoundException {
         CharSequence res = getText(id);
         if (res != null) {
             return res.toString();
@@ -409,7 +420,8 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getString(int id, Object... formatArgs) throws NotFoundException {
+    public String getString(@StringRes int id, Object... formatArgs)
+            throws NotFoundException {
         String raw = getString(id);
         return String.format(mConfiguration.locale, raw, formatArgs);
     }
@@ -439,7 +451,7 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getQuantityString(int id, int quantity, Object... formatArgs)
+    public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
             throws NotFoundException {
         String raw = getQuantityText(id, quantity).toString();
         return String.format(mConfiguration.locale, raw, formatArgs);
@@ -465,7 +477,8 @@
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getQuantityString(int id, int quantity) throws NotFoundException {
+    public String getQuantityString(@PluralsRes int id, int quantity)
+            throws NotFoundException {
         return getQuantityText(id, quantity).toString();
     }
 
@@ -483,7 +496,7 @@
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information, or def if id is 0 or not found.
      */
-    public CharSequence getText(int id, CharSequence def) {
+    public CharSequence getText(@StringRes int id, CharSequence def) {
         CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
         return res != null ? res : def;
     }
@@ -499,7 +512,7 @@
      *
      * @return The styled text array associated with the resource.
      */
-    public CharSequence[] getTextArray(int id) throws NotFoundException {
+    public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
         CharSequence[] res = mAssets.getResourceTextArray(id);
         if (res != null) {
             return res;
@@ -519,7 +532,8 @@
      *
      * @return The string array associated with the resource.
      */
-    public String[] getStringArray(int id) throws NotFoundException {
+    public String[] getStringArray(@ArrayRes int id)
+            throws NotFoundException {
         String[] res = mAssets.getResourceStringArray(id);
         if (res != null) {
             return res;
@@ -539,7 +553,7 @@
      *
      * @return The int array associated with the resource.
      */
-    public int[] getIntArray(int id) throws NotFoundException {
+    public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
         int[] res = mAssets.getArrayIntResource(id);
         if (res != null) {
             return res;
@@ -561,7 +575,8 @@
      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
      * when done with it.
      */
-    public TypedArray obtainTypedArray(int id) throws NotFoundException {
+    public TypedArray obtainTypedArray(@ArrayRes int id)
+            throws NotFoundException {
         int len = mAssets.getArraySize(id);
         if (len < 0) {
             throw new NotFoundException("Array resource ID #0x"
@@ -592,7 +607,7 @@
      * @see #getDimensionPixelOffset
      * @see #getDimensionPixelSize
      */
-    public float getDimension(int id) throws NotFoundException {
+    public float getDimension(@DimenRes int id) throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -627,7 +642,7 @@
      * @see #getDimension
      * @see #getDimensionPixelSize
      */
-    public int getDimensionPixelOffset(int id) throws NotFoundException {
+    public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -664,7 +679,7 @@
      * @see #getDimension
      * @see #getDimensionPixelOffset
      */
-    public int getDimensionPixelSize(int id) throws NotFoundException {
+    public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -698,7 +713,7 @@
      *  
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
-    public float getFraction(int id, int base, int pbase) {
+    public float getFraction(@FractionRes int id, int base, int pbase) {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -748,7 +763,7 @@
      */
     @Deprecated
     @Nullable
-    public Drawable getDrawable(int id) throws NotFoundException {
+    public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
         final Drawable d = getDrawable(id, null);
         if (d != null && d.canApplyTheme()) {
             Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
@@ -773,7 +788,7 @@
      *         not exist.
      */
     @Nullable
-    public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {
+    public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -821,7 +836,7 @@
      */
     @Deprecated
     @Nullable
-    public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
+    public Drawable getDrawableForDensity(@DrawableRes int id, int density) throws NotFoundException {
         return getDrawableForDensity(id, density, null);
     }
 
@@ -840,7 +855,7 @@
      *             not exist.
      */
     @Nullable
-    public Drawable getDrawableForDensity(int id, int density, @Nullable Theme theme) {
+    public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -884,7 +899,7 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      * 
      */
-    public Movie getMovie(int id) throws NotFoundException {
+    public Movie getMovie(@RawRes int id) throws NotFoundException {
         InputStream is = openRawResource(id);
         Movie movie = Movie.decodeStream(is);
         try {
@@ -897,20 +912,43 @@
     }
 
     /**
-     * Return a color integer associated with a particular resource ID.
-     * If the resource holds a complex
-     * {@link android.content.res.ColorStateList}, then the default color from
-     * the set is returned.
+     * Returns a color integer associated with a particular resource ID. If the
+     * resource holds a complex {@link ColorStateList}, then the default color
+     * from the set is returned.
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
      *
-     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
      *
-     * @return Returns a single color value in the form 0xAARRGGBB.
+     * @return A single color value in the form 0xAARRGGBB.
+     * @deprecated Use {@link #getColor(int, Theme)} instead.
      */
-    public int getColor(int id) throws NotFoundException {
+    @ColorInt
+    public int getColor(@ColorRes int id) throws NotFoundException {
+        return getColor(id, null);
+    }
+
+    /**
+     * Returns a themed color integer associated with a particular resource ID.
+     * If the resource holds a complex {@link ColorStateList}, then the default
+     * color from the set is returned.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     *
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     *
+     * @return A single color value in the form 0xAARRGGBB.
+     */
+    @ColorInt
+    public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -919,40 +957,77 @@
             }
             getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
-                && value.type <= TypedValue.TYPE_LAST_INT) {
+                    && value.type <= TypedValue.TYPE_LAST_INT) {
                 mTmpValue = value;
                 return value.data;
             } else if (value.type != TypedValue.TYPE_STRING) {
                 throw new NotFoundException(
-                    "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
-                    + Integer.toHexString(value.type) + " is not valid");
+                        "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+                                + Integer.toHexString(value.type) + " is not valid");
             }
             mTmpValue = null;
         }
-        ColorStateList csl = loadColorStateList(value, id);
+
+        final ColorStateList csl = loadColorStateList(value, id, theme);
         synchronized (mAccessLock) {
             if (mTmpValue == null) {
                 mTmpValue = value;
             }
         }
+
         return csl.getDefaultColor();
     }
 
     /**
-     * Return a color state list associated with a particular resource ID.  The
-     * resource may contain either a single raw color value, or a complex
-     * {@link android.content.res.ColorStateList} holding multiple possible colors.
+     * Returns a color state list associated with a particular resource ID. The
+     * resource may contain either a single raw color value or a complex
+     * {@link ColorStateList} holding multiple possible colors.
      *
      * @param id The desired resource identifier of a {@link ColorStateList},
-     *        as generated by the aapt tool. This integer encodes the package, type, and resource
-     *        entry. The value 0 is an invalid identifier.
+     *           as generated by the aapt tool. This integer encodes the
+     *           package, type, and resource entry. The value 0 is an invalid
+     *           identifier.
      *
-     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
      *
-     * @return Returns a ColorStateList object containing either a single
-     * solid color or multiple colors that can be selected based on a state.
+     * @return A ColorStateList object containing either a single solid color
+     *         or multiple colors that can be selected based on a state.
+     * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
      */
-    public ColorStateList getColorStateList(int id) throws NotFoundException {
+    @Nullable
+    public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
+        final ColorStateList csl = getColorStateList(id, null);
+        if (csl != null && csl.canApplyTheme()) {
+            Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
+                    + "unresolved theme attributes! Consider using "
+                    + "Resources.getColorStateList(int, Theme) or "
+                    + "Context.getColorStateList(int).", new RuntimeException());
+        }
+        return csl;
+    }
+
+    /**
+     * Returns a themed color state list associated with a particular resource
+     * ID. The resource may contain either a single raw color value or a
+     * complex {@link ColorStateList} holding multiple possible colors.
+     *
+     * @param id The desired resource identifier of a {@link ColorStateList},
+     *           as generated by the aapt tool. This integer encodes the
+     *           package, type, and resource entry. The value 0 is an invalid
+     *           identifier.
+     * @param theme The theme used to style the color attributes, may be
+     *              {@code null}.
+     *
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     *
+     * @return A themed ColorStateList object containing either a single solid
+     *         color or multiple colors that can be selected based on a state.
+     */
+    @Nullable
+    public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
+            throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -963,15 +1038,19 @@
             }
             getValue(id, value, true);
         }
-        ColorStateList res = loadColorStateList(value, id);
+
+        final ColorStateList res = loadColorStateList(value, id, theme);
         synchronized (mAccessLock) {
             if (mTmpValue == null) {
                 mTmpValue = value;
             }
         }
+
         return res;
     }
 
+
+
     /**
      * Return a boolean associated with a particular resource ID.  This can be
      * used with any integral resource value, and will return true if it is
@@ -985,7 +1064,7 @@
      *
      * @return Returns the boolean value contained in the resource.
      */
-    public boolean getBoolean(int id) throws NotFoundException {
+    public boolean getBoolean(@BoolRes int id) throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -1013,7 +1092,7 @@
      *
      * @return Returns the integer value contained in the resource.
      */
-    public int getInteger(int id) throws NotFoundException {
+    public int getInteger(@IntegerRes int id) throws NotFoundException {
         synchronized (mAccessLock) {
             TypedValue value = mTmpValue;
             if (value == null) {
@@ -1078,7 +1157,7 @@
      *         
      * @see #getXml
      */
-    public XmlResourceParser getLayout(int id) throws NotFoundException {
+    public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "layout");
     }
 
@@ -1102,7 +1181,7 @@
      *         
      * @see #getXml
      */
-    public XmlResourceParser getAnimation(int id) throws NotFoundException {
+    public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "anim");
     }
 
@@ -1127,7 +1206,7 @@
      *         
      * @see android.util.AttributeSet
      */
-    public XmlResourceParser getXml(int id) throws NotFoundException {
+    public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "xml");
     }
 
@@ -1145,7 +1224,7 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      * 
      */
-    public InputStream openRawResource(int id) throws NotFoundException {
+    public InputStream openRawResource(@RawRes int id) throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -1177,7 +1256,8 @@
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
-    public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
+    public InputStream openRawResource(@RawRes int id, TypedValue value)
+            throws NotFoundException {
         getValue(id, value, true);
 
         try {
@@ -1212,7 +1292,8 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      * 
      */
-    public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
+    public AssetFileDescriptor openRawResourceFd(@RawRes int id)
+            throws NotFoundException {
         TypedValue value;
         synchronized (mAccessLock) {
             value = mTmpValue;
@@ -1257,7 +1338,7 @@
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      *
      */
-    public void getValue(int id, TypedValue outValue, boolean resolveRefs)
+    public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
         boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
         if (found) {
@@ -1280,8 +1361,8 @@
      *             not exist.
      * @see #getValue(String, TypedValue, boolean)
      */
-    public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs)
-            throws NotFoundException {
+    public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+            boolean resolveRefs) throws NotFoundException {
         boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
         if (found) {
             return;
@@ -1640,7 +1721,7 @@
          * @throws NotFoundException Throws NotFoundException if the given ID
          *         does not exist.
          */
-        public Drawable getDrawable(int id) throws NotFoundException {
+        public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
             return Resources.this.getDrawable(id, this);
         }
 
@@ -1843,11 +1924,10 @@
 
             clearDrawableCachesLocked(mDrawableCache, configChanges);
             clearDrawableCachesLocked(mColorDrawableCache, configChanges);
+            mColorStateListCache.onConfigurationChange(configChanges);
             mAnimatorCache.onConfigurationChange(configChanges);
             mStateListAnimatorCache.onConfigurationChange(configChanges);
 
-            mColorStateListCache.clear();
-
             flushLayoutCache();
         }
         synchronized (sSync) {
@@ -2046,7 +2126,7 @@
      *
      * @hide
      */
-    public static boolean resourceHasPackage(int resid) {
+    public static boolean resourceHasPackage(@AnyRes int resid) {
         return (resid >>> 24) != 0;
     }
 
@@ -2064,7 +2144,7 @@
      * @see #getResourceTypeName
      * @see #getResourceEntryName
      */
-    public String getResourceName(int resid) throws NotFoundException {
+    public String getResourceName(@AnyRes int resid) throws NotFoundException {
         String str = mAssets.getResourceName(resid);
         if (str != null) return str;
         throw new NotFoundException("Unable to find resource ID #0x"
@@ -2083,7 +2163,7 @@
      * 
      * @see #getResourceName
      */
-    public String getResourcePackageName(int resid) throws NotFoundException {
+    public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
         String str = mAssets.getResourcePackageName(resid);
         if (str != null) return str;
         throw new NotFoundException("Unable to find resource ID #0x"
@@ -2102,7 +2182,7 @@
      * 
      * @see #getResourceName
      */
-    public String getResourceTypeName(int resid) throws NotFoundException {
+    public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
         String str = mAssets.getResourceTypeName(resid);
         if (str != null) return str;
         throw new NotFoundException("Unable to find resource ID #0x"
@@ -2121,7 +2201,7 @@
      * 
      * @see #getResourceName
      */
-    public String getResourceEntryName(int resid) throws NotFoundException {
+    public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
         String str = mAssets.getResourceEntryName(resid);
         if (str != null) return str;
         throw new NotFoundException("Unable to find resource ID #0x"
@@ -2425,6 +2505,9 @@
                 final String themeKey = theme == null ? "" : theme.mKey;
                 LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
                 if (themedCache == null) {
+                    // Clean out the caches before we add more. This shouldn't
+                    // happen very often.
+                    pruneCaches(caches);
                     themedCache = new LongSparseArray<WeakReference<ConstantState>>(1);
                     caches.put(themeKey, themedCache);
                 }
@@ -2434,12 +2517,46 @@
     }
 
     /**
+     * Prunes empty caches from the cache map.
+     *
+     * @param caches The map of caches to prune.
+     */
+    private void pruneCaches(ArrayMap<String,
+            LongSparseArray<WeakReference<ConstantState>>> caches) {
+        final int N = caches.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final LongSparseArray<WeakReference<ConstantState>> cache = caches.valueAt(i);
+            if (pruneCache(cache)) {
+                caches.removeAt(i);
+            }
+        }
+    }
+
+    /**
+     * Prunes obsolete weak references from a cache, returning {@code true} if
+     * the cache is empty and should be removed.
+     *
+     * @param cache The cache of weak references to prune.
+     * @return {@code true} if the cache is empty and should be removed.
+     */
+    private boolean pruneCache(LongSparseArray<WeakReference<ConstantState>> cache) {
+        final int N = cache.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final WeakReference entry = cache.valueAt(i);
+            if (entry == null || entry.get() == null) {
+                cache.removeAt(i);
+            }
+        }
+        return cache.size() == 0;
+    }
+
+    /**
      * Loads a drawable from XML or resources stream.
      */
     private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
         if (value.string == null) {
             throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
-                    + Integer.toHexString(id) + ")  is not a Drawable (color or path): " + value);
+                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
         }
 
         final String file = value.string.toString();
@@ -2530,7 +2647,8 @@
         return null;
     }
 
-    /*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
+    @Nullable
+    ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
             throws NotFoundException {
         if (TRACE_FOR_PRELOAD) {
             // Log only framework resources
@@ -2544,99 +2662,105 @@
 
         ColorStateList csl;
 
-        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
-                value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-
-            csl = sPreloadedColorStateLists.get(key);
-            if (csl != null) {
-                return csl;
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
+            if (factory != null) {
+                return factory.newInstance();
             }
 
             csl = ColorStateList.valueOf(value.data);
+
             if (mPreloading) {
                 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                         "color")) {
-                    sPreloadedColorStateLists.put(key, csl);
+                    sPreloadedColorStateLists.put(key, csl.getFactory());
                 }
             }
 
             return csl;
         }
 
-        csl = getCachedColorStateList(key);
+        final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
+
+        csl = cache.get(key, theme);
         if (csl != null) {
             return csl;
         }
 
-        csl = sPreloadedColorStateLists.get(key);
-        if (csl != null) {
-            return csl;
+        final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
+        if (factory != null) {
+            csl = factory.newInstance(this, theme);
         }
 
-        if (value.string == null) {
-            throw new NotFoundException(
-                    "Resource is not a ColorStateList (color or path): " + value);
-        }
-        
-        final String file = value.string.toString();
-
-        if (file.endsWith(".xml")) {
-            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
-            try {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "colorstatelist"); 
-                csl = ColorStateList.createFromXml(this, rp);
-                rp.close();
-            } catch (Exception e) {
-                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-                NotFoundException rnf = new NotFoundException(
-                    "File " + file + " from color state list resource ID #0x"
-                    + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-        } else {
-            throw new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x"
-                    + Integer.toHexString(id) + ": .xml extension required");
+        if (csl == null) {
+            csl = loadColorStateListForCookie(value, id, theme);
         }
 
         if (csl != null) {
             if (mPreloading) {
                 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                         "color")) {
-                    sPreloadedColorStateLists.put(key, csl);
+                    sPreloadedColorStateLists.put(key, csl.getFactory());
                 }
             } else {
-                synchronized (mAccessLock) {
-                    //Log.i(TAG, "Saving cached color state list @ #" +
-                    //        Integer.toHexString(key.intValue())
-                    //        + " in " + this + ": " + csl);
-                    mColorStateListCache.put(key, new WeakReference<ColorStateList>(csl));
-                }
+                cache.put(key, theme, csl.getFactory());
             }
         }
 
         return csl;
     }
 
-    private ColorStateList getCachedColorStateList(long key) {
-        synchronized (mAccessLock) {
-            WeakReference<ColorStateList> wr = mColorStateListCache.get(key);
-            if (wr != null) {   // we have the key
-                ColorStateList entry = wr.get();
-                if (entry != null) {
-                    //Log.i(TAG, "Returning cached color state list @ #" +
-                    //        Integer.toHexString(((Integer)key).intValue())
-                    //        + " in " + this + ": " + entry);
-                    return entry;
-                } else {  // our entry has been purged
-                    mColorStateListCache.delete(key);
+    private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
+        if (value.string == null) {
+            throw new UnsupportedOperationException(
+                    "Can't convert to color state list: type=0x" + value.type);
+        }
+
+        final String file = value.string.toString();
+
+        if (TRACE_FOR_MISS_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) {
+                    Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
+                            + ": " + name + " at " + file);
                 }
             }
         }
-        return null;
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
+        }
+
+        final ColorStateList csl;
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        if (file.endsWith(".xml")) {
+            try {
+                final XmlResourceParser rp = loadXmlResourceParser(
+                        file, id, value.assetCookie, "colorstatelist");
+                csl = ColorStateList.createFromXml(this, rp, theme);
+                rp.close();
+            } catch (Exception e) {
+                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from color state list resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+        return csl;
     }
 
     /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
@@ -2715,6 +2839,20 @@
         }
     }
 
+    /**
+     * Obtains styled attributes from the theme, if available, or unstyled
+     * resources if the theme is null.
+     *
+     * @hide
+     */
+    public static TypedArray obtainAttributes(
+            Resources res, Theme theme, AttributeSet set, int[] attrs) {
+        if (theme == null) {
+            return res.obtainAttributes(set, attrs);
+        }
+        return theme.obtainStyledAttributes(set, attrs, 0, 0);
+    }
+
     private Resources() {
         mAssets = AssetManager.getSystem();
         // NOTE: Intentionally leaving this uninitialized (all values set
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 4ae3825..9548d49 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -16,27 +16,23 @@
 
 package android.content.res;
 
-import android.os.IBinder;
+import java.util.Objects;
 
 /** @hide */
 public final class ResourcesKey {
-    final String mResDir;
-    final float mScale;
+    private final String mResDir;
+    private final float mScale;
     private final int mHash;
-    private final IBinder mToken;
 
     public final int mDisplayId;
-    public final Configuration mOverrideConfiguration = new Configuration();
+    public final Configuration mOverrideConfiguration;
 
     public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
-            float scale, IBinder token) {
+            float scale) {
         mResDir = resDir;
         mDisplayId = displayId;
-        if (overrideConfiguration != null) {
-            mOverrideConfiguration.setTo(overrideConfiguration);
-        }
+        mOverrideConfiguration = overrideConfiguration;
         mScale = scale;
-        mToken = token;
 
         int hash = 17;
         hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
@@ -48,7 +44,8 @@
     }
 
     public boolean hasOverrideConfiguration() {
-        return !Configuration.EMPTY.equals(mOverrideConfiguration);
+        return mOverrideConfiguration != null
+                && !Configuration.EMPTY.equals(mOverrideConfiguration);
     }
 
     @Override
@@ -63,17 +60,9 @@
         }
         ResourcesKey peer = (ResourcesKey) obj;
 
-        if ((mResDir == null) && (peer.mResDir != null)) {
+        if (!Objects.equals(mResDir, peer.mResDir)) {
             return false;
         }
-        if ((mResDir != null) && (peer.mResDir == null)) {
-            return false;
-        }
-        if ((mResDir != null) && (peer.mResDir != null)) {
-            if (!mResDir.equals(peer.mResDir)) {
-                return false;
-            }
-        }
         if (mDisplayId != peer.mDisplayId) {
             return false;
         }
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index 77b8a33..9652db7 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -311,13 +311,13 @@
      * the color black is returned instead.
      *
      * @param color The color as a string. Can be a resource reference,
-     *              HTML hexadecimal, octal or a name
+     *              hexadecimal, octal or a name
      * @param foreground True if the color will be used as the foreground color,
      *                   false otherwise
      *
      * @return A CharacterStyle
      *
-     * @see Color#getHtmlColor(String)
+     * @see Color#parseColor(String)
      */
     private static CharacterStyle getColor(String color, boolean foreground) {
         int c = 0xff000000;
@@ -336,7 +336,11 @@
                     }
                 }
             } else {
-                c = Color.getHtmlColor(color);
+                try {
+                    c = Color.parseColor(color);
+                } catch (IllegalArgumentException e) {
+                    c = Color.BLACK;
+                }
             }
         }
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 02602fb..1fca920 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -16,11 +16,13 @@
 
 package android.content.res;
 
+import android.annotation.AnyRes;
+import android.annotation.ColorInt;
 import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
+import android.os.StrictMode;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.util.TypedValue;
 
 import com.android.internal.util.XmlUtils;
@@ -73,7 +75,9 @@
     /*package*/ TypedValue mValue = new TypedValue();
 
     /**
-     * Return the number of values in this array.
+     * Returns the number of values in this array.
+     *
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int length() {
         if (mRecycled) {
@@ -85,6 +89,8 @@
 
     /**
      * Return the number of indices in the array that actually have data.
+     *
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int getIndexCount() {
         if (mRecycled) {
@@ -95,13 +101,14 @@
     }
 
     /**
-     * Return an index in the array that has data.
+     * Returns an index in the array that has data.
      *
      * @param at The index you would like to returned, ranging from 0 to
-     * {@link #getIndexCount()}.
+     *           {@link #getIndexCount()}.
      *
      * @return The index at the given offset, which can be used with
-     * {@link #getValue} and related APIs.
+     *         {@link #getValue} and related APIs.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int getIndex(int at) {
         if (mRecycled) {
@@ -112,7 +119,9 @@
     }
 
     /**
-     * Return the Resources object this array was loaded from.
+     * Returns the Resources object this array was loaded from.
+     *
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public Resources getResources() {
         if (mRecycled) {
@@ -123,12 +132,17 @@
     }
 
     /**
-     * Retrieve the styled string value for the attribute at <var>index</var>.
+     * Retrieves the styled string value for the attribute at <var>index</var>.
+     * <p>
+     * If the attribute is not a string, this method will attempt to coerce
+     * it to a string.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return CharSequence holding string data.  May be styled.  Returns
-     *         null if the attribute is not defined.
+     * @return CharSequence holding string data. May be styled. Returns
+     *         {@code null} if the attribute is not defined or could not be
+     *         coerced to a string.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public CharSequence getText(int index) {
         if (mRecycled) {
@@ -144,23 +158,28 @@
             return loadStringValueAt(index);
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to string: " + v);
+            StrictMode.noteResourceMismatch(v);
             return v.coerceToString();
         }
-        Log.w(Resources.TAG, "getString of bad type: 0x"
-              + Integer.toHexString(type));
-        return null;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getText of bad type: 0x" + Integer.toHexString(type));
     }
 
     /**
-     * Retrieve the string value for the attribute at <var>index</var>.
+     * Retrieves the string value for the attribute at <var>index</var>.
+     * <p>
+     * If the attribute is not a string, this method will attempt to coerce
+     * it to a string.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return String holding string data.  Any styling information is
-     * removed.  Returns null if the attribute is not defined.
+     * @return String holding string data. Any styling information is removed.
+     *         Returns {@code null} if the attribute is not defined or could
+     *         not be coerced to a string.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public String getString(int index) {
         if (mRecycled) {
@@ -176,19 +195,19 @@
             return loadStringValueAt(index).toString();
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to string: " + v);
-            CharSequence cs = v.coerceToString();
+            StrictMode.noteResourceMismatch(v);
+            final CharSequence cs = v.coerceToString();
             return cs != null ? cs.toString() : null;
         }
-        Log.w(Resources.TAG, "getString of bad type: 0x"
-              + Integer.toHexString(type));
-        return null;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getString of bad type: 0x" + Integer.toHexString(type));
     }
 
     /**
-     * Retrieve the string value for the attribute at <var>index</var>, but
+     * Retrieves the string value for the attribute at <var>index</var>, but
      * only if that string comes from an immediate value in an XML file.  That
      * is, this does not allow references to string resources, string
      * attributes, or conversions from other types.  As such, this method
@@ -197,9 +216,10 @@
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return String holding string data.  Any styling information is
-     * removed.  Returns null if the attribute is not defined or is not
-     * an immediate string value.
+     * @return String holding string data. Any styling information is removed.
+     *         Returns {@code null} if the attribute is not defined or is not
+     *         an immediate string value.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public String getNonResourceString(int index) {
         if (mRecycled) {
@@ -220,16 +240,17 @@
     }
 
     /**
-     * @hide
-     * Retrieve the string value for the attribute at <var>index</var> that is
+     * Retrieves the string value for the attribute at <var>index</var> that is
      * not allowed to change with the given configurations.
      *
      * @param index Index of attribute to retrieve.
      * @param allowedChangingConfigs Bit mask of configurations from
-     * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
+     *        {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
      *
-     * @return String holding string data.  Any styling information is
-     * removed.  Returns null if the attribute is not defined.
+     * @return String holding string data. Any styling information is removed.
+     *         Returns {@code null} if the attribute is not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @hide
      */
     public String getNonConfigurationString(int index, int allowedChangingConfigs) {
         if (mRecycled) {
@@ -248,24 +269,33 @@
             return loadStringValueAt(index).toString();
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to string: " + v);
-            CharSequence cs = v.coerceToString();
+            StrictMode.noteResourceMismatch(v);
+            final CharSequence cs = v.coerceToString();
             return cs != null ? cs.toString() : null;
         }
-        Log.w(Resources.TAG, "getString of bad type: 0x"
-              + Integer.toHexString(type));
-        return null;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getNonConfigurationString of bad type: 0x"
+                + Integer.toHexString(type));
     }
 
     /**
      * Retrieve the boolean value for the attribute at <var>index</var>.
+     * <p>
+     * If the attribute is an integer value, this method will return whether
+     * it is equal to zero. If the attribute is not a boolean or integer value,
+     * this method will attempt to coerce it to an integer using
+     * {@link Integer#decode(String)} and return whether it is equal to zero.
      *
      * @param index Index of attribute to retrieve.
-     * @param defValue Value to return if the attribute is not defined.
+     * @param defValue Value to return if the attribute is not defined or
+     *                 cannot be coerced to an integer.
      *
-     * @return Attribute boolean value, or defValue if not defined.
+     * @return Boolean value of the attribute, or defValue if the attribute was
+     *         not defined or could not be coerced to an integer.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public boolean getBoolean(int index, boolean defValue) {
         if (mRecycled) {
@@ -278,28 +308,33 @@
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
-            && type <= TypedValue.TYPE_LAST_INT) {
+                && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA] != 0;
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to boolean: " + v);
-            return XmlUtils.convertValueToBoolean(
-                v.coerceToString(), defValue);
+            StrictMode.noteResourceMismatch(v);
+            return XmlUtils.convertValueToBoolean(v.coerceToString(), defValue);
         }
-        Log.w(Resources.TAG, "getBoolean of bad type: 0x"
-              + Integer.toHexString(type));
-        return defValue;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getBoolean of bad type: 0x" + Integer.toHexString(type));
     }
 
     /**
      * Retrieve the integer value for the attribute at <var>index</var>.
+     * <p>
+     * If the attribute is not an integer, this method will attempt to coerce
+     * it to an integer using {@link Integer#decode(String)}.
      *
      * @param index Index of attribute to retrieve.
-     * @param defValue Value to return if the attribute is not defined.
+     * @param defValue Value to return if the attribute is not defined or
+     *                 cannot be coerced to an integer.
      *
-     * @return Attribute int value, or defValue if not defined.
+     * @return Integer value of the attribute, or defValue if the attribute was
+     *         not defined or could not be coerced to an integer.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int getInt(int index, int defValue) {
         if (mRecycled) {
@@ -312,27 +347,31 @@
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
-            && type <= TypedValue.TYPE_LAST_INT) {
+                && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA];
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to int: " + v);
-            return XmlUtils.convertValueToInt(
-                v.coerceToString(), defValue);
+            StrictMode.noteResourceMismatch(v);
+            return XmlUtils.convertValueToInt(v.coerceToString(), defValue);
         }
-        Log.w(Resources.TAG, "getInt of bad type: 0x"
-              + Integer.toHexString(type));
-        return defValue;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getInt of bad type: 0x" + Integer.toHexString(type));
     }
 
     /**
      * Retrieve the float value for the attribute at <var>index</var>.
+     * <p>
+     * If the attribute is not a float or an integer, this method will attempt
+     * to coerce it to a float using {@link Float#parseFloat(String)}.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return Attribute float value, or defValue if not defined..
+     * @return Attribute float value, or defValue if the attribute was
+     *         not defined or could not be coerced to a float.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public float getFloat(int index, float defValue) {
         if (mRecycled) {
@@ -347,21 +386,21 @@
         } else if (type == TypedValue.TYPE_FLOAT) {
             return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
         } else if (type >= TypedValue.TYPE_FIRST_INT
-            && type <= TypedValue.TYPE_LAST_INT) {
+                && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA];
         }
 
-        TypedValue v = mValue;
+        final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            Log.w(Resources.TAG, "Converting to float: " + v);
-            CharSequence str = v.coerceToString();
+            final CharSequence str = v.coerceToString();
             if (str != null) {
+                StrictMode.noteResourceMismatch(v);
                 return Float.parseFloat(str.toString());
             }
         }
-        Log.w(Resources.TAG, "getFloat of bad type: 0x"
-              + Integer.toHexString(type));
-        return defValue;
+
+        // We already checked for TYPE_NULL. This should never happen.
+        throw new RuntimeException("getFloat of bad type: 0x" + Integer.toHexString(type));
     }
 
     /**
@@ -369,14 +408,21 @@
      * the attribute references a color resource holding a complex
      * {@link android.content.res.ColorStateList}, then the default color from
      * the set is returned.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not an integer color or color state list.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
      *
      * @return Attribute color value, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer color or color state list.
      */
-    public int getColor(int index, int defValue) {
+    @ColorInt
+    public int getColor(int index, @ColorInt int defValue) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
@@ -387,18 +433,21 @@
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
-            && type <= TypedValue.TYPE_LAST_INT) {
+                && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_STRING) {
             final TypedValue value = mValue;
             if (getValueAt(index, value)) {
-                ColorStateList csl = mResources.loadColorStateList(
-                        value, value.resourceId);
+                final ColorStateList csl = mResources.loadColorStateList(
+                        value, value.resourceId, mTheme);
                 return csl.getDefaultColor();
             }
             return defValue;
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to color: type=0x"
@@ -408,12 +457,22 @@
     /**
      * Retrieve the ColorStateList for the attribute at <var>index</var>.
      * The value may be either a single solid color or a reference to
-     * a color or complex {@link android.content.res.ColorStateList} description.
+     * a color or complex {@link android.content.res.ColorStateList}
+     * description.
+     * <p>
+     * This method will return {@code null} if the attribute is not defined or
+     * is not an integer color or color state list.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return ColorStateList for the attribute, or null if not defined.
+     * @return ColorStateList for the attribute, or {@code null} if not
+     *         defined.
+     * @throws RuntimeException if the attribute if the TypedArray has already
+     *         been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer color or color state list.
      */
+    @Nullable
     public ColorStateList getColorStateList(int index) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
@@ -422,21 +481,28 @@
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
-                throw new RuntimeException("Failed to resolve attribute at index " + index);
+                throw new UnsupportedOperationException(
+                        "Failed to resolve attribute at index " + index + ": " + value);
             }
-            return mResources.loadColorStateList(value, value.resourceId);
+            return mResources.loadColorStateList(value, value.resourceId, mTheme);
         }
         return null;
     }
 
     /**
      * Retrieve the integer value for the attribute at <var>index</var>.
+     * <p>
+     * Unlike {@link #getInt(int, int)}, this method will throw an exception if
+     * the attribute is defined but is not an integer.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
      *
      * @return Attribute integer value, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer.
      */
     public int getInteger(int index, int defValue) {
         if (mRecycled) {
@@ -449,10 +515,13 @@
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
-            && type <= TypedValue.TYPE_LAST_INT) {
+                && type <= TypedValue.TYPE_LAST_INT) {
             return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to integer: type=0x"
@@ -460,17 +529,23 @@
     }
 
     /**
-     * Retrieve a dimensional unit attribute at <var>index</var>.  Unit
+     * Retrieve a dimensional unit attribute at <var>index</var>. Unit
      * conversions are based on the current {@link DisplayMetrics}
      * associated with the resources this {@link TypedArray} object
      * came from.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a dimension.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
      *
      * @return Attribute dimension value multiplied by the appropriate
-     * metric, or defValue if not defined.
+     *         metric, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer.
      *
      * @see #getDimensionPixelOffset
      * @see #getDimensionPixelSize
@@ -487,9 +562,12 @@
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
             return TypedValue.complexToDimension(
-                data[index+AssetManager.STYLE_DATA], mMetrics);
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -502,13 +580,19 @@
      * {@link #getDimension}, except the returned value is converted to
      * integer pixels for you.  An offset conversion involves simply
      * truncating the base value to an integer.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a dimension.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
      *
      * @return Attribute dimension value multiplied by the appropriate
-     * metric and truncated to integer pixels, or defValue if not defined.
+     *         metric and truncated to integer pixels, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer.
      *
      * @see #getDimension
      * @see #getDimensionPixelSize
@@ -525,9 +609,12 @@
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
             return TypedValue.complexToDimensionPixelOffset(
-                data[index+AssetManager.STYLE_DATA], mMetrics);
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -541,13 +628,19 @@
      * integer pixels for use as a size.  A size conversion involves
      * rounding the base value, and ensuring that a non-zero base value
      * is at least one pixel in size.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a dimension.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or
      *                 not a resource.
      *
      * @return Attribute dimension value multiplied by the appropriate
-     * metric and truncated to integer pixels, or defValue if not defined.
+     *         metric and truncated to integer pixels, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not a dimension.
      *
      * @see #getDimension
      * @see #getDimensionPixelOffset
@@ -566,7 +659,10 @@
             return TypedValue.complexToDimensionPixelSize(
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
@@ -578,12 +674,18 @@
      * {@link android.view.ViewGroup}'s layout_width and layout_height
      * attributes.  This is only here for performance reasons; applications
      * should use {@link #getDimensionPixelSize}.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a dimension or integer (enum).
      *
      * @param index Index of the attribute to retrieve.
      * @param name Textual name of attribute for error reporting.
      *
      * @return Attribute dimension value multiplied by the appropriate
-     * metric and truncated to integer pixels.
+     *         metric and truncated to integer pixels.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not a dimension or integer (enum).
      */
     public int getLayoutDimension(int index, String name) {
         if (mRecycled) {
@@ -600,10 +702,13 @@
             return TypedValue.complexToDimensionPixelSize(
                 data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
-        throw new RuntimeException(getPositionDescription()
+        throw new UnsupportedOperationException(getPositionDescription()
                 + ": You must supply a " + name + " attribute.");
     }
 
@@ -615,10 +720,11 @@
      *
      * @param index Index of the attribute to retrieve.
      * @param defValue The default value to return if this attribute is not
-     * default or contains the wrong type of data.
+     *                 default or contains the wrong type of data.
      *
      * @return Attribute dimension value multiplied by the appropriate
-     * metric and truncated to integer pixels.
+     *         metric and truncated to integer pixels.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int getLayoutDimension(int index, int defValue) {
         if (mRecycled) {
@@ -633,14 +739,14 @@
             return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_DIMENSION) {
             return TypedValue.complexToDimensionPixelSize(
-                data[index+AssetManager.STYLE_DATA], mMetrics);
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         }
 
         return defValue;
     }
 
     /**
-     * Retrieve a fractional unit attribute at <var>index</var>.
+     * Retrieves a fractional unit attribute at <var>index</var>.
      *
      * @param index Index of attribute to retrieve.
      * @param base The base value of this fraction.  In other words, a
@@ -652,7 +758,10 @@
      *                 not a resource.
      *
      * @return Attribute fractional value multiplied by the appropriate
-     * base value, or defValue if not defined.
+     *         base value, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not a fraction.
      */
     public float getFraction(int index, int base, int pbase, float defValue) {
         if (mRecycled) {
@@ -668,7 +777,10 @@
             return TypedValue.complexToFraction(
                 data[index+AssetManager.STYLE_DATA], base, pbase);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
-            throw new RuntimeException("Failed to resolve attribute at index " + index);
+            final TypedValue value = mValue;
+            getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value);
+            throw new UnsupportedOperationException(
+                    "Failed to resolve attribute at index " + index + ": " + value);
         }
 
         throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
@@ -676,7 +788,7 @@
     }
 
     /**
-     * Retrieve the resource identifier for the attribute at
+     * Retrieves the resource identifier for the attribute at
      * <var>index</var>.  Note that attribute resource as resolved when
      * the overall {@link TypedArray} object is retrieved.  As a
      * result, this function will return the resource identifier of the
@@ -688,7 +800,9 @@
      *                 not a resource.
      *
      * @return Attribute resource identifier, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
+    @AnyRes
     public int getResourceId(int index, int defValue) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
@@ -706,13 +820,15 @@
     }
 
     /**
-     * Retrieve the theme attribute resource identifier for the attribute at
+     * Retrieves the theme attribute resource identifier for the attribute at
      * <var>index</var>.
      *
      * @param index Index of attribute to retrieve.
      * @param defValue Value to return if the attribute is not defined or not a
-     *            resource.
+     *                 resource.
+     *
      * @return Theme attribute resource identifier, or defValue if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      * @hide
      */
     public int getThemeAttributeId(int index, int defValue) {
@@ -730,10 +846,16 @@
 
     /**
      * Retrieve the Drawable for the attribute at <var>index</var>.
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a color or drawable resource.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return Drawable for the attribute, or null if not defined.
+     * @return Drawable for the attribute, or {@code null} if not defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not a color or drawable resource.
      */
     @Nullable
     public Drawable getDrawable(int index) {
@@ -744,7 +866,8 @@
         final TypedValue value = mValue;
         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
-                throw new RuntimeException("Failed to resolve attribute at index " + index);
+                throw new UnsupportedOperationException(
+                        "Failed to resolve attribute at index " + index + ": " + value);
             }
             return mResources.loadDrawable(value, value.resourceId, mTheme);
         }
@@ -756,10 +879,15 @@
      * This gets the resource ID of the selected attribute, and uses
      * {@link Resources#getTextArray Resources.getTextArray} of the owning
      * Resources object to retrieve its String[].
+     * <p>
+     * This method will throw an exception if the attribute is defined but is
+     * not a text array resource.
      *
      * @param index Index of attribute to retrieve.
      *
-     * @return CharSequence[] for the attribute, or null if not defined.
+     * @return CharSequence[] for the attribute, or {@code null} if not
+     *         defined.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public CharSequence[] getTextArray(int index) {
         if (mRecycled) {
@@ -780,7 +908,8 @@
      * @param outValue TypedValue object in which to place the attribute's
      *                 data.
      *
-     * @return Returns true if the value was retrieved, else false.
+     * @return {@code true} if the value was retrieved, false otherwise.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public boolean getValue(int index, TypedValue outValue) {
         if (mRecycled) {
@@ -794,7 +923,9 @@
      * Returns the type of attribute at the specified index.
      *
      * @param index Index of attribute whose type to retrieve.
+     *
      * @return Attribute type.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public int getType(int index) {
         if (mRecycled) {
@@ -814,6 +945,7 @@
      * @param index Index of attribute to retrieve.
      *
      * @return True if the attribute has a value, false otherwise.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public boolean hasValue(int index) {
         if (mRecycled) {
@@ -834,6 +966,7 @@
      * @param index Index of attribute to retrieve.
      *
      * @return True if the attribute has a value or is empty, false otherwise.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public boolean hasValueOrEmpty(int index) {
         if (mRecycled) {
@@ -857,6 +990,7 @@
      * @return Returns a TypedValue object if the attribute is defined,
      *         containing its data; otherwise returns null.  (You will not
      *         receive a TypedValue whose type is TYPE_NULL.)
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public TypedValue peekValue(int index) {
         if (mRecycled) {
@@ -872,6 +1006,9 @@
 
     /**
      * Returns a message about the parser state suitable for printing error messages.
+     *
+     * @return Human-readable description of current parser state.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public String getPositionDescription() {
         if (mRecycled) {
@@ -882,8 +1019,10 @@
     }
 
     /**
-     * Recycle the TypedArray, to be re-used by a later caller. After calling
+     * Recycles the TypedArray, to be re-used by a later caller. After calling
      * this function you must not ever touch the typed array again.
+     *
+     * @throws RuntimeException if the TypedArray has already been recycled.
      */
     public void recycle() {
         if (mRecycled) {
@@ -908,9 +1047,19 @@
      * @return an array of length {@link #getIndexCount()} populated with theme
      *         attributes, or null if there are no theme attributes in the typed
      *         array
+     * @throws RuntimeException if the TypedArray has already been recycled.
      * @hide
      */
+    @Nullable
     public int[] extractThemeAttrs() {
+        return extractThemeAttrs(null);
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public int[] extractThemeAttrs(@Nullable int[] scrap) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
@@ -922,6 +1071,7 @@
         for (int i = 0; i < N; i++) {
             final int index = i * AssetManager.STYLE_NUM_ENTRIES;
             if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+                // Not an attribute, ignore.
                 continue;
             }
 
@@ -930,13 +1080,20 @@
 
             final int attr = data[index + AssetManager.STYLE_DATA];
             if (attr == 0) {
-                // This attribute is useless!
+                // Useless data, ignore.
                 continue;
             }
 
+            // Ensure we have a usable attribute array.
             if (attrs == null) {
-                attrs = new int[N];
+                if (scrap != null && scrap.length == N) {
+                    attrs = scrap;
+                    Arrays.fill(attrs, 0);
+                } else {
+                    attrs = new int[N];
+                }
             }
+
             attrs[i] = attr;
         }
 
@@ -949,9 +1106,14 @@
      *
      * @return Returns a mask of the changing configuration parameters, as
      *         defined by {@link android.content.pm.ActivityInfo}.
+     * @throws RuntimeException if the TypedArray has already been recycled.
      * @see android.content.pm.ActivityInfo
      */
     public int getChangingConfigurations() {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
         int changingConfig = 0;
 
         final int[] data = mData;
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index c125544..e61664c 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -16,8 +16,6 @@
 
 package android.database;
 
-import org.apache.commons.codec.binary.Hex;
-
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.OperationApplicationException;
@@ -416,11 +414,33 @@
      * @return the collation key in hex format
      */
     public static String getHexCollationKey(String name) {
-        byte [] arr = getCollationKeyInBytes(name);
-        char[] keys = Hex.encodeHex(arr);
+        byte[] arr = getCollationKeyInBytes(name);
+        char[] keys = encodeHex(arr);
         return new String(keys, 0, getKeyLen(arr) * 2);
     }
 
+
+    /**
+     * Used building output as Hex
+     */
+    private static final char[] DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7',
+            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    private static char[] encodeHex(byte[] input) {
+        int l = input.length;
+        char[] out = new char[l << 1];
+
+        // two characters form the hex value.
+        for (int i = 0, j = 0; i < l; i++) {
+            out[j++] = DIGITS[(0xF0 & input[i]) >>> 4 ];
+            out[j++] = DIGITS[ 0x0F & input[i] ];
+        }
+
+        return out;
+    }
+
     private static int getKeyLen(byte[] arr) {
         if (arr[arr.length - 1] != 0) {
             return arr.length;
diff --git a/core/java/android/gesture/GestureLibraries.java b/core/java/android/gesture/GestureLibraries.java
index 6d6c156..611d9ab 100644
--- a/core/java/android/gesture/GestureLibraries.java
+++ b/core/java/android/gesture/GestureLibraries.java
@@ -16,6 +16,7 @@
 
 package android.gesture;
 
+import android.annotation.RawRes;
 import android.util.Log;
 import static android.gesture.GestureConstants.*;
 import android.content.Context;
@@ -44,7 +45,7 @@
         return fromFile(context.getFileStreamPath(name));
     }
 
-    public static GestureLibrary fromRawResource(Context context, int resourceId) {
+    public static GestureLibrary fromRawResource(Context context, @RawRes int resourceId) {
         return new ResourceGestureLibrary(context, resourceId);
     }
 
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 6e3a00f..e0d454c 100644
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -16,6 +16,7 @@
 
 package android.gesture;
 
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -204,18 +205,20 @@
         mOrientation = orientation;
     }
 
-    public void setGestureColor(int color) {
+    public void setGestureColor(@ColorInt int color) {
         mCertainGestureColor = color;
     }
 
-    public void setUncertainGestureColor(int color) {
+    public void setUncertainGestureColor(@ColorInt int color) {
         mUncertainGestureColor = color;
     }
 
+    @ColorInt
     public int getUncertainGestureColor() {
         return mUncertainGestureColor;
     }
 
+    @ColorInt
     public int getGestureColor() {
         return mCertainGestureColor;
     }
@@ -640,7 +643,7 @@
             mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
 
             if (mHandleGestureActions && !mIsGesturing) {
-                mTotalLength += (float) Math.sqrt(dx * dx + dy * dy);
+                mTotalLength += (float) Math.hypot(dx, dy);
 
                 if (mTotalLength > mGestureStrokeLengthThreshold) {
                     final OrientedBoundingBox box =
diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java
index 1d0f0fe..4a324f9 100644
--- a/core/java/android/gesture/GestureStroke.java
+++ b/core/java/android/gesture/GestureStroke.java
@@ -69,8 +69,7 @@
                 bx.bottom = p.y;
                 len = 0;
             } else {
-                len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2)
-                        + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2));
+                len += Math.hypot(p.x - tmpPoints[(i - 1) * 2], p.y - tmpPoints[(i -1) * 2 + 1]);
                 bx.union(p.x, p.y);
             }
             index++;
diff --git a/core/java/android/gesture/GestureUtils.java b/core/java/android/gesture/GestureUtils.java
index dd221fc..416279e 100644
--- a/core/java/android/gesture/GestureUtils.java
+++ b/core/java/android/gesture/GestureUtils.java
@@ -293,7 +293,7 @@
             }
             float deltaX = currentPointX - lstPointX;
             float deltaY = currentPointY - lstPointY;
-            float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+            float distance = (float) Math.hypot(deltaX, deltaY);
             if (distanceSoFar + distance >= increment) {
                 float ratio = (increment - distanceSoFar) / distance;
                 float nx = lstPointX + ratio * deltaX;
@@ -379,7 +379,7 @@
         for (int i = 0; i < count; i += 2) {
             float dx = points[i + 2] - points[i];
             float dy = points[i + 3] - points[i + 1];
-            sum += Math.sqrt(dx * dx + dy * dy);
+            sum += Math.hypot(dx, dy);
         }
         return sum;
     }
@@ -388,13 +388,13 @@
         float totalLen = computeTotalLength(points);
         float dx = points[2] - points[0];
         float dy = points[3] - points[1];
-        return (float) Math.sqrt(dx * dx + dy * dy) / totalLen;
+        return (float) Math.hypot(dx, dy) / totalLen;
     }
 
     static float computeStraightness(float[] points, float totalLen) {
         float dx = points[2] - points[0];
         float dy = points[3] - points[1];
-        return (float) Math.sqrt(dx * dx + dy * dy) / totalLen;
+        return (float) Math.hypot(dx, dy) / totalLen;
     }
 
     /**
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 310ab76..49f6513 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -44,7 +44,6 @@
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 
diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java
index ef05732..eb26ee5 100644
--- a/core/java/android/hardware/GeomagneticField.java
+++ b/core/java/android/hardware/GeomagneticField.java
@@ -281,7 +281,7 @@
      * @return  Horizontal component of the field strength in nonoteslas.
      */
     public float getHorizontalStrength() {
-        return (float) Math.sqrt(mX * mX + mY * mY);
+        return (float) Math.hypot(mX, mY);
     }
 
     /**
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 2bc3dd4..9aede01 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -81,4 +81,6 @@
                     int clientUid,
                     // Container for an ICamera object
                     out BinderHolder device);
+
+    int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
 }
diff --git a/core/java/android/hardware/ICameraServiceListener.aidl b/core/java/android/hardware/ICameraServiceListener.aidl
index c5484965..49278b6 100644
--- a/core/java/android/hardware/ICameraServiceListener.aidl
+++ b/core/java/android/hardware/ICameraServiceListener.aidl
@@ -23,4 +23,6 @@
      * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
      */
     void onStatusChanged(int status, int cameraId);
+
+    void onTorchStatusChanged(int status, String cameraId);
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index cf6a779..39f4cca 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -18,6 +18,7 @@
 package android.hardware;
 
 import android.os.Build;
+import android.annotation.SystemApi;
 
 /**
  * Class representing a sensor. Use {@link SensorManager#getSensorList} to get
@@ -511,6 +512,27 @@
      */
     public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture";
 
+     /**
+     * A constant describing a wrist tilt gesture sensor.
+     *
+     * A sensor of this type triggers when the device face is tilted towards the user.
+     * The only allowed return value is 1.0.
+     * This sensor remains active until disabled.
+     *
+     * @hide This sensor is expected to only be used by the system ui
+     */
+    @SystemApi
+    public static final int TYPE_WRIST_TILT_GESTURE = 26;
+
+    /**
+     * A constant string describing a wrist tilt gesture sensor.
+     *
+     * @hide This sensor is expected to only be used by the system ui
+     * @see #TYPE_WRIST_TILT_GESTURE
+     */
+    @SystemApi
+    public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
+
     /**
      * A constant describing all sensor types.
      */
@@ -591,6 +613,7 @@
             1, // SENSOR_TYPE_WAKE_GESTURE
             1, // SENSOR_TYPE_GLANCE_GESTURE
             1, // SENSOR_TYPE_PICK_UP_GESTURE
+            1, // SENSOR_TYPE_WRIST_TILT_GESTURE
     };
 
     /**
@@ -810,4 +833,96 @@
                 + ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
                 + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
     }
+
+    /**
+     * Sets the Type associated with the sensor.
+     * NOTE: to be used only by native bindings in SensorManager.
+     *
+     * This allows interned static strings to be used across all representations of the Sensor. If
+     * a sensor type is not referenced here, it will still be interned by the native SensorManager.
+     *
+     * @return {@code true} if the StringType was successfully set, {@code false} otherwise.
+     */
+    private boolean setType(int value) {
+        mType = value;
+        switch (mType) {
+            case TYPE_ACCELEROMETER:
+                mStringType = STRING_TYPE_ACCELEROMETER;
+                return true;
+            case TYPE_AMBIENT_TEMPERATURE:
+                mStringType = STRING_TYPE_AMBIENT_TEMPERATURE;
+                return true;
+            case TYPE_GAME_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GAME_ROTATION_VECTOR;
+                return true;
+            case TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+                return true;
+            case TYPE_GLANCE_GESTURE:
+                mStringType = STRING_TYPE_GLANCE_GESTURE;
+                return true;
+            case TYPE_GRAVITY:
+                mStringType = STRING_TYPE_GRAVITY;
+                return true;
+            case TYPE_GYROSCOPE:
+                mStringType = STRING_TYPE_GYROSCOPE;
+                return true;
+            case TYPE_GYROSCOPE_UNCALIBRATED:
+                mStringType = STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+                return true;
+            case TYPE_HEART_RATE:
+                mStringType = STRING_TYPE_HEART_RATE;
+                return true;
+            case TYPE_LIGHT:
+                mStringType = STRING_TYPE_LIGHT;
+                return true;
+            case TYPE_LINEAR_ACCELERATION:
+                mStringType = STRING_TYPE_LINEAR_ACCELERATION;
+                return true;
+            case TYPE_MAGNETIC_FIELD:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD;
+                return true;
+            case TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+                return true;
+            case TYPE_PICK_UP_GESTURE:
+                mStringType = STRING_TYPE_PICK_UP_GESTURE;
+                return true;
+            case TYPE_PRESSURE:
+                mStringType = STRING_TYPE_PRESSURE;
+                return true;
+            case TYPE_PROXIMITY:
+                mStringType = STRING_TYPE_PROXIMITY;
+                return true;
+            case TYPE_RELATIVE_HUMIDITY:
+                mStringType = STRING_TYPE_RELATIVE_HUMIDITY;
+                return true;
+            case TYPE_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_ROTATION_VECTOR;
+                return true;
+            case TYPE_SIGNIFICANT_MOTION:
+                mStringType = STRING_TYPE_SIGNIFICANT_MOTION;
+                return true;
+            case TYPE_STEP_COUNTER:
+                mStringType = STRING_TYPE_STEP_COUNTER;
+                return true;
+            case TYPE_STEP_DETECTOR:
+                mStringType = STRING_TYPE_STEP_DETECTOR;
+                return true;
+            case TYPE_TILT_DETECTOR:
+                mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
+                return true;
+            case TYPE_WAKE_GESTURE:
+                mStringType = STRING_TYPE_WAKE_GESTURE;
+                return true;
+            case TYPE_ORIENTATION:
+                mStringType = STRING_TYPE_ORIENTATION;
+                return true;
+            case TYPE_TEMPERATURE:
+                mStringType = STRING_TYPE_TEMPERATURE;
+                return true;
+            default:
+                return false;
+        }
+    }
 }
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index e4e5a8c..34b895b 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -451,7 +451,8 @@
         // non_wake-up version.
         if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
                 type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
-                type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE) {
+                type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
+                type == Sensor.TYPE_WRIST_TILT_GESTURE) {
             wakeUpSensor = true;
         }
 
diff --git a/core/java/android/hardware/camera2/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
index 91ef6ca..84e9912 100644
--- a/core/java/android/hardware/camera2/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -28,16 +28,14 @@
  */
 public class CameraAccessException extends AndroidException {
     /**
-     * The camera device is in use already
-     * @hide
+     * The camera device is in use already.
      */
     public static final int CAMERA_IN_USE = 4;
 
     /**
-     * The system-wide limit for number of open cameras has been reached,
-     * and more camera devices cannot be opened until previous instances are
-     * closed.
-     * @hide
+     * The system-wide limit for number of open cameras or camera resources has
+     * been reached, and more camera devices cannot be opened or torch mode
+     * cannot be turned on until previous instances are closed.
      */
     public static final int MAX_CAMERAS_IN_USE = 5;
 
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7cf8fb0..a0217c2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -638,6 +638,44 @@
             new Key<android.hardware.camera2.params.HighSpeedVideoConfiguration[]>("android.control.availableHighSpeedVideoConfigurations", android.hardware.camera2.params.HighSpeedVideoConfiguration[].class);
 
     /**
+     * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock}</p>
+     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     */
+    @PublicKey
+    public static final Key<Boolean> CONTROL_AE_LOCK_AVAILABLE =
+            new Key<Boolean>("android.control.aeLockAvailable", boolean.class);
+
+    /**
+     * <p>Whether the camera device supports {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}</p>
+     * <p>LIMITED or FULL devices will always list <code>true</code></p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AWB_LOCK
+     */
+    @PublicKey
+    public static final Key<Boolean> CONTROL_AWB_LOCK_AVAILABLE =
+            new Key<Boolean>("android.control.awbLockAvailable", boolean.class);
+
+    /**
+     * <p>List of control modes for {@link CaptureRequest#CONTROL_MODE android.control.mode} that are supported by this camera
+     * device.</p>
+     * <p>This list contains control modes that can be set for the camera device.
+     * LEGACY mode devices will always support AUTO mode. LIMITED and FULL
+     * devices will always support OFF, AUTO modes.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#CONTROL_MODE android.control.mode}</p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_MODE
+     */
+    @PublicKey
+    public static final Key<int[]> CONTROL_AVAILABLE_MODES =
+            new Key<int[]>("android.control.availableModes", int[].class);
+
+    /**
      * <p>List of edge enhancement modes for {@link CaptureRequest#EDGE_MODE android.edge.mode} that are supported by this camera
      * device.</p>
      * <p>Full-capability camera devices must always support OFF; all devices will list FAST.</p>
@@ -889,10 +927,12 @@
      * <ul>
      *   <li>{@link #LENS_FACING_FRONT FRONT}</li>
      *   <li>{@link #LENS_FACING_BACK BACK}</li>
+     *   <li>{@link #LENS_FACING_EXTERNAL EXTERNAL}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      * @see #LENS_FACING_FRONT
      * @see #LENS_FACING_BACK
+     * @see #LENS_FACING_EXTERNAL
      */
     @PublicKey
     public static final Key<Integer> LENS_FACING =
@@ -1069,8 +1109,11 @@
      * android.scaler.availableInputOutputFormatsMap. When using an
      * input stream, there must be at least one output stream
      * configured to to receive the reprocessed images.</p>
+     * <p>When an input stream and some output streams are used in a reprocessing request,
+     * only the input buffer will be used to produce these output stream buffers, and a
+     * new sensor image will not be captured.</p>
      * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
-     * stream image format will be RAW_OPAQUE, the associated output stream image format
+     * stream image format will be OPAQUE, the associated output stream image format
      * should be JPEG.</p>
      * <p><b>Range of valid values:</b><br></p>
      * <p>0 or 1.</p>
@@ -1080,8 +1123,8 @@
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
-     * @hide
      */
+    @PublicKey
     public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
             new Key<Integer>("android.request.maxNumInputStreams", int.class);
 
@@ -1157,8 +1200,10 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR MANUAL_SENSOR}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING MANUAL_POST_PROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING OPAQUE_REPROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -1167,8 +1212,10 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
      * @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_RAW
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS
      * @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING
      */
     @PublicKey
     public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -1345,10 +1392,10 @@
      * <p>The mapping of image formats that are supported by this
      * camera device for input streams, to their corresponding output formats.</p>
      * <p>All camera devices with at least 1
-     * android.request.maxNumInputStreams will have at least one
+     * {@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} will have at least one
      * available input format.</p>
      * <p>The camera device will support the following map of formats,
-     * if its dependent capability is supported:</p>
+     * if its dependent capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}) is supported:</p>
      * <table>
      * <thead>
      * <tr>
@@ -1359,45 +1406,42 @@
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">OPAQUE</td>
      * <td align="left">JPEG</td>
-     * <td align="left">ZSL</td>
+     * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
+     * <td align="left">OPAQUE</td>
      * <td align="left">YUV_420_888</td>
-     * <td align="left">ZSL</td>
+     * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">RAW_OPAQUE</td>
-     * <td align="left">RAW16</td>
-     * <td align="left">RAW</td>
-     * </tr>
-     * <tr>
-     * <td align="left">RAW16</td>
      * <td align="left">YUV_420_888</td>
-     * <td align="left">RAW</td>
-     * </tr>
-     * <tr>
-     * <td align="left">RAW16</td>
      * <td align="left">JPEG</td>
-     * <td align="left">RAW</td>
+     * <td align="left">YUV_REPROCESSING</td>
+     * </tr>
+     * <tr>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">YUV_420_888</td>
+     * <td align="left">YUV_REPROCESSING</td>
      * </tr>
      * </tbody>
      * </table>
-     * <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
+     * <p>OPAQUE refers to a device-internal format that is not directly application-visible.
+     * An OPAQUE input or output surface can be acquired by
+     * OpaqueImageRingBufferQueue#getInputSurface() or
+     * OpaqueImageRingBufferQueue#getOutputSurface().
+     * For a OPAQUE_REPROCESSING-capable camera device, using the OPAQUE format
      * as either input or output will never hurt maximum frame rate (i.e.
-     * StreamConfigurationMap#getOutputStallDuration(int,Size)
-     * for a <code>format =</code> RAW_OPAQUE is always 0).</p>
+     * StreamConfigurationMap#getOutputStallDuration(klass,Size) is always 0),
+     * where klass is android.media.OpaqueImageRingBufferQueue.class.</p>
      * <p>Attempting to configure an input stream with output streams not
      * listed as available in this map is not valid.</p>
      * <p>TODO: typedef to ReprocessFormatMap</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     * <p><b>Full capability</b> -
-     * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
-     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
-     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @hide
      */
     public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
@@ -1899,6 +1943,23 @@
             new Key<Integer>("android.sensor.info.timestampSource", int.class);
 
     /**
+     * <p>Whether the RAW images output from this camera device are subject to
+     * lens shading correction.</p>
+     * <p>If TRUE, all images produced by the camera device in the RAW image formats will
+     * have lens shading correction already applied to it. If FALSE, the images will
+     * not be adjusted for lens shading correction.
+     * See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image formats.</p>
+     * <p>This key will be <code>null</code> for all devices do not report this information.
+     * Devices with RAW capability will always report this information in this key.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+     */
+    @PublicKey
+    public static final Key<Boolean> SENSOR_INFO_LENS_SHADING_APPLIED =
+            new Key<Boolean>("android.sensor.info.lensShadingApplied", boolean.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
@@ -2189,6 +2250,22 @@
             new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
 
     /**
+     * <p>List of lens shading modes for {@link CaptureRequest#SHADING_MODE android.shading.mode} that are supported by this camera device.</p>
+     * <p>This list contains lens shading modes that can be set for the camera device.
+     * Camera devices that support the MANUAL_POST_PROCESSING capability will always
+     * list OFF and FAST mode. This includes all FULL level devices.
+     * LEGACY devices will always only support FAST mode.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#SHADING_MODE android.shading.mode}</p>
+     * <p>This key is available on all devices.</p>
+     *
+     * @see CaptureRequest#SHADING_MODE
+     */
+    @PublicKey
+    public static final Key<int[]> SHADING_AVAILABLE_MODES =
+            new Key<int[]>("android.shading.availableModes", int[].class);
+
+    /**
      * <p>List of face detection modes for {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} that are
      * supported by this camera device.</p>
      * <p>OFF is always supported.</p>
@@ -2232,6 +2309,23 @@
             new Key<boolean[]>("android.statistics.info.availableHotPixelMapModes", boolean[].class);
 
     /**
+     * <p>List of lens shading map output modes for {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode} that
+     * are supported by this camera device.</p>
+     * <p>If no lens shading map output is available for this camera device, this key will
+     * contain only OFF.</p>
+     * <p>ON is always supported on devices with the RAW capability.
+     * LEGACY mode devices will always only support OFF.</p>
+     * <p><b>Range of valid values:</b><br>
+     * Any value listed in {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE android.statistics.lensShadingMapMode}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
+     */
+    @PublicKey
+    public static final Key<byte[]> STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES =
+            new Key<byte[]>("android.statistics.info.availableLensShadingMapModes", byte[].class);
+
+    /**
      * <p>Maximum number of supported points in the
      * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}.</p>
      * <p>If the actual number of points provided by the application (in {@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}*) is
@@ -2255,8 +2349,13 @@
     /**
      * <p>List of tonemapping modes for {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} that are supported by this camera
      * device.</p>
-     * <p>Camera devices that support the MANUAL_POST_PROCESSING capability will always list
-     * CONTRAST_CURVE and FAST. This includes all FULL level devices.</p>
+     * <p>Camera devices that support the MANUAL_POST_PROCESSING capability will always contain
+     * at least one of below mode combinations:</p>
+     * <ul>
+     * <li>CONTRAST_CURVE and FAST</li>
+     * <li>GAMMA_VALUE, PRESET_CURVE, and FAST</li>
+     * </ul>
+     * <p>This includes all FULL level devices.</p>
      * <p><b>Range of valid values:</b><br>
      * Any value listed in {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -2394,6 +2493,83 @@
     public static final Key<Integer> SYNC_MAX_LATENCY =
             new Key<Integer>("android.sync.maxLatency", int.class);
 
+    /**
+     * <p>The available depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>These are output stream configurations for use with
+     * dataSpace HAL_DATASPACE_DEPTH. The configurations are
+     * listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>Only devices that support depth output for at least
+     * the HAL_PIXEL_FORMAT_Y16 dense depth map may include
+     * this entry.</p>
+     * <p>A device that also supports the HAL_PIXEL_FORMAT_BLOB
+     * sparse depth point cloud must report a single entry for
+     * the format in this list as <code>(HAL_PIXEL_FORMAT_BLOB,
+     * android.depth.maxDepthSamples, 1, OUTPUT)</code> in addition to
+     * the entries for HAL_PIXEL_FORMAT_Y16.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfiguration[]> DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.depth.availableDepthStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for depth output formats.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
+     * android.scaler.availableStallDurations for more details about
+     * calculating the max frame rate.</p>
+     * <p>(Keep in sync with
+     * StreamConfigurationMap#getOutputMinFrameDuration)</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * format/size combination for depth streams.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>This functions similarly to
+     * android.scaler.availableStallDurations for depth
+     * streams.</p>
+     * <p>All depth output stream formats may have a nonzero stall
+     * duration.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 482b1f0..fd4cf3c 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -17,7 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.graphics.ImageFormat;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.os.Handler;
 import android.view.Surface;
 
@@ -183,7 +183,7 @@
      *   Then obtain the Surface with
      *   {@link android.renderscript.Allocation#getSurface}.</li>
      *
-     * <li>For access to raw, uncompressed JPEG data in the application: Create an
+     * <li>For access to RAW, uncompressed YUV, or compressed 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
@@ -381,6 +381,20 @@
             throws CameraAccessException;
 
     /**
+     * <p>Create a new camera capture session by providing the target output set of Surfaces and
+     * its corresponding surface configuration to the camera device.</p>
+     *
+     * @see #createCaptureSession
+     * @see OutputConfiguration
+     *
+     * @hide
+     */
+    public abstract void createCaptureSessionByOutputConfiguration(
+            List<OutputConfiguration> outputConfigurations,
+            CameraCaptureSession.StateCallback callback, Handler handler)
+            throws CameraAccessException;
+
+    /**
      * <p>Create a {@link CaptureRequest.Builder} for new capture requests,
      * initialized with template for a target use case. The settings are chosen
      * to be the best options for the specific camera device, so it is not
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index b6bb33b..faa782a 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -27,6 +27,7 @@
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.hardware.camera2.utils.BinderHolder;
 import android.os.IBinder;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -109,8 +110,11 @@
      * of the state of individual CameraManager instances.</p>
      *
      * @param callback the new callback to send camera availability notices to
-     * @param handler The handler on which the callback should be invoked, or
-     * {@code null} to use the current thread's {@link android.os.Looper looper}.
+     * @param handler The handler on which the callback should be invoked, or {@code null} to use
+     *             the current thread's {@link android.os.Looper looper}.
+     *
+     * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
+     *             no looper.
      */
     public void registerAvailabilityCallback(AvailabilityCallback callback, Handler handler) {
         if (handler == null) {
@@ -138,6 +142,52 @@
     }
 
     /**
+     * Register a callback to be notified about torch mode status.
+     *
+     * <p>Registering the same callback again will replace the handler with the
+     * new one provided.</p>
+     *
+     * <p>The first time a callback is registered, it is immediately called
+     * with the torch mode status of all currently known camera devices.</p>
+     *
+     * <p>Since this callback will be registered with the camera service, remember to unregister it
+     * once it is no longer needed; otherwise the callback will continue to receive events
+     * indefinitely and it may prevent other resources from being released. Specifically, the
+     * callbacks will be invoked independently of the general activity lifecycle and independently
+     * of the state of individual CameraManager instances.</p>
+     *
+     * @param callback The new callback to send torch mode status to
+     * @param handler The handler on which the callback should be invoked, or {@code null} to use
+     *             the current thread's {@link android.os.Looper looper}.
+     *
+     * @throws IllegalArgumentException if the handler is {@code null} but the current thread has
+     *             no looper.
+     */
+    public void registerTorchCallback(TorchCallback callback, Handler handler) {
+        if (handler == null) {
+            Looper looper = Looper.myLooper();
+            if (looper == null) {
+                throw new IllegalArgumentException(
+                        "No handler given, and current thread has no looper!");
+            }
+            handler = new Handler(looper);
+        }
+        CameraManagerGlobal.get().registerTorchCallback(callback, handler);
+    }
+
+    /**
+     * Remove a previously-added callback; the callback will no longer receive torch mode status
+     * callbacks.
+     *
+     * <p>Removing a callback that isn't registered has no effect.</p>
+     *
+     * @param callback The callback to remove from the notification list
+     */
+    public void unregisterTorchCallback(TorchCallback callback) {
+        CameraManagerGlobal.get().unregisterTorchCallback(callback);
+    }
+
+    /**
      * <p>Query the capabilities of a camera device. These capabilities are
      * immutable for a given camera.</p>
      *
@@ -384,6 +434,49 @@
     }
 
     /**
+     * Set the flash unit's torch mode of the camera of the given ID without opening the camera
+     * device.
+     *
+     * <p>Use {@link #getCameraIdList} to get the list of available camera devices and use
+     * {@link #getCameraCharacteristics} to check whether the camera device has a flash unit.
+     * Note that even if a camera device has a flash unit, turning on the torch mode may fail
+     * if the camera device or other camera resources needed to turn on the torch mode are in use.
+     * </p>
+     *
+     * <p> If {@link #setTorchMode} is called to turn on or off the torch mode successfully,
+     * {@link CameraManager.TorchCallback#onTorchModeChanged} will be invoked.
+     * However, even if turning on the torch mode is successful, the application does not have the
+     * exclusive ownership of the flash unit or the camera device. The torch mode will be turned
+     * off and becomes unavailable when the camera device that the flash unit belongs to becomes
+     * unavailable or when other camera resources to keep the torch on become unavailable (
+     * {@link CameraManager.TorchCallback#onTorchModeUnavailable} will be invoked). Also,
+     * other applications are free to call {@link #setTorchMode} to turn off the torch mode (
+     * {@link CameraManager.TorchCallback#onTorchModeChanged} will be invoked). If the latest
+     * application that turned on the torch mode exits, the torch mode will be turned off.
+     *
+     * @param cameraId
+     *             The unique identifier of the camera device that the flash unit belongs to.
+     * @param enabled
+     *             The desired state of the torch mode for the target camera device. Set to
+     *             {@code true} to turn on the torch mode. Set to {@code false} to turn off the
+     *             torch mode.
+     *
+     * @throws CameraAccessException if it failed to access the flash unit.
+     *             {@link CameraAccessException#CAMERA_IN_USE} will be thrown if the camera device
+     *             is in use. {@link CameraAccessException#MAX_CAMERAS_IN_USE} will be thrown if
+     *             other camera resources needed to turn on the torch mode are in use.
+     *             {@link CameraAccessException#CAMERA_DISCONNECTED} will be thrown if camera
+     *             service is not available.
+     *
+     * @throws IllegalArgumentException if cameraId was null, cameraId doesn't match any currently
+     *             or previously available camera device, or the camera device doesn't have a
+     *             flash unit.
+     */
+    public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
+        CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
+    }
+
+    /**
      * A callback for camera devices becoming available or
      * unavailable to open.
      *
@@ -428,6 +521,63 @@
     }
 
     /**
+     * A callback for camera flash torch modes becoming unavailable, disabled, or enabled.
+     *
+     * <p>The torch mode becomes unavailable when the camera device it belongs to becomes
+     * unavailable or other camera resouces it needs become busy due to other higher priority
+     * camera activities. The torch mode becomes disabled when it was turned off or when the camera
+     * device it belongs to is no longer in use and other camera resources it needs are no longer
+     * busy. A camera's torch mode is turned off when an application calls {@link #setTorchMode} to
+     * turn off the camera's torch mode, or when an application turns on another camera's torch mode
+     * if keeping multiple torch modes on simultaneously is not supported. The torch mode becomes
+     * enabled when it is turned on via {@link #setTorchMode}.</p>
+     *
+     * <p>The torch mode is available to set via {@link #setTorchMode} only when it's in a disabled
+     * or enabled state.</p>
+     *
+     * <p>Extend this callback and pass an instance of the subclass to
+     * {@link CameraManager#registerTorchCallback} to be notified of such status changes.
+     * </p>
+     *
+     * @see registerTorchCallback
+     */
+    public static abstract class TorchCallback {
+        /**
+         * A camera's torch mode has become unavailable to set via {@link #setTorchMode}.
+         *
+         * <p>If torch mode was previously turned on by calling {@link #setTorchMode}, it will be
+         * turned off before {@link CameraManager.TorchCallback#onTorchModeUnavailable} is
+         * invoked. {@link #setTorchMode} will fail until the torch mode has entered a disabled or
+         * enabled state again.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the camera whose torch mode has become
+         *                 unavailable.
+         */
+        public void onTorchModeUnavailable(String cameraId) {
+            // default empty implementation
+        }
+
+        /**
+         * A camera's torch mode has become enabled or disabled and can be changed via
+         * {@link #setTorchMode}.
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the camera whose torch mode has been changed.
+         *
+         * @param enabled The state that the torch mode of the camera has been changed to.
+         *                {@code true} when the torch mode has become on and available to be turned
+         *                off. {@code false} when the torch mode has becomes off and available to
+         *                be turned on.
+         */
+        public void onTorchModeChanged(String cameraId, boolean enabled) {
+            // default empty implementation
+        }
+    }
+
+    /**
      * Return or create the list of currently connected camera devices.
      *
      * <p>In case of errors connecting to the camera service, will return an empty list.</p>
@@ -583,6 +733,27 @@
         private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
             new ArrayMap<AvailabilityCallback, Handler>();
 
+        // Keep up-to-date with ICameraServiceListener.h
+
+        // torch mode has become not available to set via setTorchMode().
+        public static final int TORCH_STATUS_NOT_AVAILABLE = 0;
+        // torch mode is off and available to be turned on via setTorchMode().
+        public static final int TORCH_STATUS_AVAILABLE_OFF = 1;
+        // torch mode is on and available to be turned off via setTorchMode().
+        public static final int TORCH_STATUS_AVAILABLE_ON = 2;
+
+        // End enums shared with ICameraServiceListener.h
+
+        // torch client binder to set the torch mode with.
+        private Binder mTorchClientBinder = new Binder();
+
+        // Camera ID -> Torch status map
+        private final ArrayMap<String, Integer> mTorchStatus = new ArrayMap<String, Integer>();
+
+        // Registered torch callbacks and their handlers
+        private final ArrayMap<TorchCallback, Handler> mTorchCallbackMap =
+                new ArrayMap<TorchCallback, Handler>();
+
         private final Object mLock = new Object();
 
         // Access only through getCameraService to deal with binder death
@@ -668,15 +839,46 @@
             }
         }
 
+        public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
+            synchronized(mLock) {
+
+                if (cameraId == null) {
+                    throw new IllegalArgumentException("cameraId was null");
+                }
+
+                ICameraService cameraService = getCameraService();
+                if (cameraService == null) {
+                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                        "Camera service is currently unavailable");
+                }
+
+                try {
+                    int status = cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
+                } catch(CameraRuntimeException e) {
+                    int problem = e.getReason();
+                    switch (problem) {
+                        case CameraAccessException.CAMERA_ERROR:
+                            throw new IllegalArgumentException(
+                                    "the camera device doesn't have a flash unit.");
+                        default:
+                            throw e.asChecked();
+                    }
+                } catch (RemoteException e) {
+                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                            "Camera service is currently unavailable");
+                }
+            }
+        }
+
         private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
             int problem = e.getReason();
             switch (problem) {
-            case CameraAccessException.CAMERA_DISCONNECTED:
-                String errorMsg = CameraAccessException.getDefaultMessage(problem);
-                Log.w(TAG, msg + ": " + errorMsg);
-                break;
-            default:
-                throw new IllegalStateException(msg, e.asChecked());
+                case CameraAccessException.CAMERA_DISCONNECTED:
+                    String errorMsg = CameraAccessException.getDefaultMessage(problem);
+                    Log.w(TAG, msg + ": " + errorMsg);
+                    break;
+                default:
+                    throw new IllegalStateException(msg, e.asChecked());
             }
         }
 
@@ -701,6 +903,17 @@
             }
         }
 
+        private boolean validTorchStatus(int status) {
+            switch (status) {
+                case TORCH_STATUS_NOT_AVAILABLE:
+                case TORCH_STATUS_AVAILABLE_ON:
+                case TORCH_STATUS_AVAILABLE_OFF:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
         private void postSingleUpdate(final AvailabilityCallback callback, final Handler handler,
                 final String id, final int status) {
             if (isAvailable(status)) {
@@ -722,6 +935,32 @@
             }
         }
 
+        private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
+                final String id, final int status) {
+            switch(status) {
+                case TORCH_STATUS_AVAILABLE_ON:
+                case TORCH_STATUS_AVAILABLE_OFF:
+                    handler.post(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    callback.onTorchModeChanged(id, status ==
+                                            TORCH_STATUS_AVAILABLE_ON);
+                                }
+                            });
+                    break;
+                default:
+                    handler.post(
+                            new Runnable() {
+                                @Override
+                                public void run() {
+                                    callback.onTorchModeUnavailable(id);
+                                }
+                            });
+                    break;
+            }
+        }
+
         /**
          * Send the state of all known cameras to the provided listener, to initialize
          * the listener's knowledge of camera state.
@@ -791,6 +1030,44 @@
             }
         } // onStatusChangedLocked
 
+        private void updateTorchCallbackLocked(TorchCallback callback, Handler handler) {
+            for (int i = 0; i < mTorchStatus.size(); i++) {
+                String id = mTorchStatus.keyAt(i);
+                Integer status = mTorchStatus.valueAt(i);
+                postSingleTorchUpdate(callback, handler, id, status);
+            }
+        }
+
+        private void onTorchStatusChangedLocked(int status, String id) {
+            if (DEBUG) {
+                Log.v(TAG,
+                        String.format("Camera id %s has torch status changed to 0x%x", id, status));
+            }
+
+            if (!validTorchStatus(status)) {
+                Log.e(TAG, String.format("Ignoring invalid device %s torch status 0x%x", id,
+                                status));
+                return;
+            }
+
+            Integer oldStatus = mTorchStatus.put(id, status);
+            if (oldStatus != null && oldStatus == status) {
+                if (DEBUG) {
+                    Log.v(TAG, String.format(
+                        "Torch status changed to 0x%x, which is what it already was",
+                        status));
+                }
+                return;
+            }
+
+            final int callbackCount = mTorchCallbackMap.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final Handler handler = mTorchCallbackMap.valueAt(i);
+                final TorchCallback callback = mTorchCallbackMap.keyAt(i);
+                postSingleTorchUpdate(callback, handler, id, status);
+            }
+        } // onTorchStatusChangedLocked
+
         /**
          * Register a callback to be notified about camera device availability with the
          * global listener singleton.
@@ -820,6 +1097,22 @@
             }
         }
 
+        public void registerTorchCallback(TorchCallback callback, Handler handler) {
+            synchronized(mLock) {
+                Handler oldHandler = mTorchCallbackMap.put(callback, handler);
+                // For new callbacks, provide initial torch information
+                if (oldHandler == null) {
+                    updateTorchCallbackLocked(callback, handler);
+                }
+            }
+        }
+
+        public void unregisterTorchCallback(TorchCallback callback) {
+            synchronized(mLock) {
+                mTorchCallbackMap.remove(callback);
+            }
+        }
+
         /**
          * Callback from camera service notifying the process about camera availability changes
          */
@@ -830,6 +1123,13 @@
             }
         }
 
+        @Override
+        public void onTorchStatusChanged(int status, String cameraId) throws RemoteException {
+            synchronized (mLock) {
+                onTorchStatusChangedLocked(status, cameraId);
+            }
+        }
+
         /**
          * Listener for camera service death.
          *
@@ -844,9 +1144,9 @@
 
                 mCameraService = null;
 
-                // Tell listeners that the cameras are _available_, because any existing clients
-                // will have gotten disconnected. This is optimistic under the assumption that
-                // the service will be back shortly.
+                // Tell listeners that the cameras and torch modes are _available_, because any
+                // existing clients will have gotten disconnected. This is optimistic under the
+                // assumption that the service will be back shortly.
                 //
                 // Without this, a camera service crash while a camera is open will never signal
                 // to listeners that previously in-use cameras are now available.
@@ -854,6 +1154,11 @@
                     String cameraId = mDeviceStatus.keyAt(i);
                     onStatusChangedLocked(STATUS_PRESENT, cameraId);
                 }
+                for (int i = 0; i < mTorchStatus.size(); i++) {
+                    String cameraId = mTorchStatus.keyAt(i);
+                    onTorchStatusChangedLocked(TORCH_STATUS_AVAILABLE_OFF, cameraId);
+                }
+
             }
         }
 
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1b10858..7f901c8 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -288,6 +288,13 @@
      */
     public static final int LENS_FACING_BACK = 1;
 
+    /**
+     * <p>The camera device is an external camera, and has no fixed facing relative to the
+     * device's screen.</p>
+     * @see CameraCharacteristics#LENS_FACING
+     */
+    public static final int LENS_FACING_EXTERNAL = 2;
+
     //
     // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
     //
@@ -367,13 +374,19 @@
      * The camera device supports basic manual control of the image post-processing
      * stages. This means the following controls are guaranteed to be supported:</p>
      * <ul>
-     * <li>Manual tonemap control<ul>
+     * <li>
+     * <p>Manual tonemap control</p>
+     * <ul>
      * <li>{@link CaptureRequest#TONEMAP_CURVE android.tonemap.curve}</li>
      * <li>{@link CaptureRequest#TONEMAP_MODE android.tonemap.mode}</li>
      * <li>{@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</li>
+     * <li>android.tonemap.gamma</li>
+     * <li>android.tonemap.presetCurve</li>
      * </ul>
      * </li>
-     * <li>Manual white balance control<ul>
+     * <li>
+     * <p>Manual white balance control</p>
+     * <ul>
      * <li>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}</li>
      * <li>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}</li>
      * </ul>
@@ -432,23 +445,40 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_RAW = 3;
 
     /**
-     * <p>The camera device supports the Zero Shutter Lag use case.</p>
+     * <p>The camera device supports the Zero Shutter Lag reprocessing use case.</p>
      * <ul>
-     * <li>At least one input stream can be used.</li>
-     * <li>RAW_OPAQUE is supported as an output/input format</li>
-     * <li>Using RAW_OPAQUE does not cause a frame rate drop
+     * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
+     * <li>OPAQUE is supported as an output/input format, that is,
+     *   StreamConfigurationMap#getOutputSizes(klass) and
+     *   StreamConfigurationMap#getInputSizes(klass) return non empty Size[] and have common
+     *   sizes, where klass is android.media.OpaqueImageRingBufferQueue.class. See
+     *   android.scaler.availableInputOutputFormatsMap for detailed information about
+     *   OPAQUE format.</li>
+     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
+     * <li>Using OPAQUE does not cause a frame rate drop
      *   relative to the sensor's maximum capture rate (at that
-     *   resolution).</li>
-     * <li>RAW_OPAQUE will be reprocessable into both YUV_420_888
+     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
+     * <li>OPAQUE will be reprocessable into both YUV_420_888
      *   and JPEG formats.</li>
-     * <li>The maximum available resolution for RAW_OPAQUE streams
+     * <li>The maximum available resolution for OPAQUE streams
      *   (both input/output) will match the maximum available
      *   resolution of JPEG streams.</li>
+     * <li>Only below controls are effective for reprocessing requests and
+     *   will be present in capture results, other controls in reprocess
+     *   requests will be ignored by the camera device.<ul>
+     * <li>android.jpeg.*</li>
+     * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
+     * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
      * </ul>
+     * </li>
+     * </ul>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
-     * @hide
      */
-    public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING = 4;
 
     /**
      * <p>The camera device supports accurately reporting the sensor settings for many of
@@ -508,6 +538,45 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6;
 
+    /**
+     * <p>The camera device supports the YUV420_888 reprocessing use case, similar as
+     * OPAQUE_REPROCESSING, This capability requires the camera device to support the
+     * following:</p>
+     * <ul>
+     * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
+     * <li>YUV420_888 is supported as a common format for both input and output, that is,
+     *   StreamConfigurationMap#getOutputSizes(YUV420_888) and
+     *   StreamConfigurationMap#getInputSizes(YUV420_888) return non empty Size[] and have
+     *   common sizes.</li>
+     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
+     * <li>Using YUV420_888 does not cause a frame rate drop
+     *   relative to the sensor's maximum capture rate (at that
+     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
+     * <li>YUV420_888 will be reprocessable into both YUV_420_888
+     *   and JPEG formats.</li>
+     * <li>The maximum available resolution for YUV420_888 streams
+     *   (both input/output) will match the maximum available
+     *   resolution of JPEG streams.</li>
+     * <li>Only the below controls are effective for reprocessing requests and will be
+     *   present in capture results. The reprocess requests are from the original capture
+     *   results that are assocaited with the intermidate YUV420_888 output buffers.
+     *   All other controls in the reprocess requests will be ignored by the camera device.<ul>
+     * <li>android.jpeg.*</li>
+     * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
+     * <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
+     * <li>{@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}</li>
+     * </ul>
+     * </li>
+     * </ul>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7;
+
     //
     // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
     //
@@ -966,6 +1035,14 @@
      */
     public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
 
+    /**
+     * <p>The camera device will cancel any currently active or completed
+     * precapture metering sequence, the auto-exposure routine will return to its
+     * initial state.</p>
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     */
+    public static final int CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL = 2;
+
     //
     // Enumeration values for CaptureRequest#CONTROL_AF_MODE
     //
@@ -1823,6 +1900,13 @@
      */
     public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
 
+    /**
+     * <p>MINIMAL 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_MINIMAL = 3;
+
     //
     // Enumeration values for CaptureRequest#SENSOR_TEST_PATTERN_MODE
     //
@@ -2026,6 +2110,43 @@
      */
     public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
 
+    /**
+     * <p>Use the gamma value specified in android.tonemap.gamma to peform
+     * tonemapping.</p>
+     * <p>All color enhancement and tonemapping must be disabled, except
+     * for applying the tonemapping curve specified by android.tonemap.gamma.</p>
+     * <p>Must not slow down frame rate relative to raw sensor output.</p>
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_GAMMA_VALUE = 3;
+
+    /**
+     * <p>Use the preset tonemapping curve specified in
+     * android.tonemap.presetCurve to peform tonemapping.</p>
+     * <p>All color enhancement and tonemapping must be disabled, except
+     * for applying the tonemapping curve specified by
+     * android.tonemap.presetCurve.</p>
+     * <p>Must not slow down frame rate relative to raw sensor output.</p>
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    public static final int TONEMAP_MODE_PRESET_CURVE = 4;
+
+    //
+    // Enumeration values for CaptureRequest#TONEMAP_PRESET_CURVE
+    //
+
+    /**
+     * <p>Tonemapping curve is defined by sRGB</p>
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
+     */
+    public static final int TONEMAP_PRESET_CURVE_SRGB = 0;
+
+    /**
+     * <p>Tonemapping curve is defined by ITU-R BT.709</p>
+     * @see CaptureRequest#TONEMAP_PRESET_CURVE
+     */
+    public static final int TONEMAP_PRESET_CURVE_REC709 = 1;
+
     //
     // Enumeration values for CaptureResult#CONTROL_AE_STATE
     //
@@ -2073,7 +2194,10 @@
      * <p>AE has been asked to do a precapture sequence
      * 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>
+     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START. Currently
+     * active and completed (if it causes camera device internal AE lock) precapture
+     * metering sequence can be canceled through setting
+     * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to CANCEL.</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
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index b417496..7569ea5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -552,6 +552,8 @@
      * in this matrix result metadata. The transform should keep the magnitude
      * of the output color values within <code>[0, 1.0]</code> (assuming input color
      * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
+     * <p>The valid range of each matrix element varies on different devices, but
+     * values within [-1.5, 3.0] are guaranteed not to be clipped.</p>
      * <p><b>Units</b>: Unitless scale factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -575,6 +577,10 @@
      * TRANSFORM_MATRIX.</p>
      * <p>The gains in the result metadata are the gains actually
      * applied by the camera device to the current frame.</p>
+     * <p>The valid range of gains varies on different devices, but gains
+     * between [1.0, 3.0] are guaranteed not to be clipped. Even if a given
+     * device allows gains below 1.0, this is usually not recommended because
+     * this can create color artifacts.</p>
      * <p><b>Units</b>: Unitless gain factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -724,7 +730,14 @@
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
      * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
      * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
-     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.
+     * Similarly, AE precapture trigger CANCEL has no effect when AE is already locked.</p>
+     * <p>When an AE precapture sequence is triggered, AE unlock will not be able to unlock
+     * the AE if AE is locked by the camera device internally during precapture metering
+     * sequence In other words, submitting requests with AE unlock has no effect for an
+     * ongoing precapture metering sequence. Otherwise, the precapture metering sequence
+     * will never succeed in a sequence of preview requests where AE lock is always set
+     * to <code>false</code>.</p>
      * <p>Since the camera device has a pipeline of in-flight requests, the settings that
      * get locked do not necessarily correspond to the settings that were present in the
      * latest capture result received from the camera device, since additional captures
@@ -869,6 +882,11 @@
      * included at all in the request settings. When included and
      * set to START, the camera device will trigger the auto-exposure (AE)
      * precapture metering sequence.</p>
+     * <p>When set to CANCEL, the camera device will cancel any active
+     * precapture metering trigger, and return to its initial AE state.
+     * If a precapture metering sequence is already completed, and the camera
+     * device has implicitly locked the AE for subsequent still capture, the
+     * CANCEL trigger will unlock the AE and return to its initial AE state.</p>
      * <p>The precapture sequence should be triggered before starting a
      * high-quality still capture for final metering decisions to
      * be made, and for firing pre-capture flash pulses to estimate
@@ -884,7 +902,11 @@
      * submitted. To ensure that the AE routine restarts normal scan, the application should
      * submit a request with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == true</code>, followed by a request
      * with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == false</code>, if the application decides not to submit a
-     * still capture request after the precapture sequence completes.</p>
+     * still capture request after the precapture sequence completes. Alternatively, for
+     * API level 23 or newer devices, the CANCEL can be used to unlock the camera device
+     * internally locked AE if the application doesn't submit a still capture request after
+     * the AE precapture trigger. Note that, the CANCEL was added in API level 23, and must not
+     * be used in devices that have earlier API levels.</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
@@ -897,6 +919,7 @@
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
+     *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
@@ -909,6 +932,7 @@
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
      */
     @PublicKey
     public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
@@ -1164,7 +1188,7 @@
      * <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 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 OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR. Other intent values are always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -1249,10 +1273,6 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p>LEGACY mode devices will only support AUTO and USE_SCENE_MODE modes.
-     * LIMITED mode devices will only support OFF and OFF_KEEP_STATE if they
-     * support the MANUAL_SENSOR and MANUAL_POST_PROCSESING capabilities.
-     * FULL mode devices will always support OFF and OFF_KEEP_STATE.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
@@ -1260,9 +1280,12 @@
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_MODES
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
@@ -1382,6 +1405,10 @@
      * camera device will use the highest-quality enhancement algorithms,
      * even if it slows down capture rate. FAST means the camera device will
      * not slow down capture rate when applying edge enhancement.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
+     * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
+     * The camera device may adjust its internal noise reduction parameters for best
+     * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
@@ -1397,6 +1424,7 @@
      *
      * @see CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #EDGE_MODE_OFF
      * @see #EDGE_MODE_FAST
      * @see #EDGE_MODE_HIGH_QUALITY
@@ -1761,18 +1789,28 @@
     /**
      * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>The noise reduction algorithm attempts to improve image quality by removing
-     * excessive noise added by the capture process, especially in dark conditions.
-     * OFF means no noise reduction will be applied by the camera device.</p>
+     * excessive noise added by the capture process, especially in dark conditions.</p>
+     * <p>OFF means no noise reduction will be applied by the camera device, for both raw and
+     * YUV domain.</p>
+     * <p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,to remove
+     * demosaicing or other processing artifacts. For YUV_REPROCESSING, MINIMAL is same as OFF.
+     * This mode is optional, may not be support by all devices. The application should check
+     * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes} before using it.</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 will not
      * slow down capture rate when applying noise filtering.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera device
+     * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
+     * may adjust the noise reduction parameters for best image quality based on the
+     * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
@@ -1783,9 +1821,11 @@
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #NOISE_REDUCTION_MODE_OFF
      * @see #NOISE_REDUCTION_MODE_FAST
      * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     * @see #NOISE_REDUCTION_MODE_MINIMAL
      */
     @PublicKey
     public static final Key<Integer> NOISE_REDUCTION_MODE =
@@ -2078,6 +2118,8 @@
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2086,6 +2128,7 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
      * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
@@ -2148,12 +2191,15 @@
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -2340,6 +2386,8 @@
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
+     *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
@@ -2355,12 +2403,60 @@
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
      * @see #TONEMAP_MODE_HIGH_QUALITY
+     * @see #TONEMAP_MODE_GAMMA_VALUE
+     * @see #TONEMAP_MODE_PRESET_CURVE
      */
     @PublicKey
     public static final Key<Integer> TONEMAP_MODE =
             new Key<Integer>("android.tonemap.mode", int.class);
 
     /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * GAMMA_VALUE</p>
+     * <p>The tonemap curve will be defined the following formula:
+     * * OUT = pow(IN, 1.0 / gamma)
+     * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+     * pow is the power function and gamma is the gamma value specified by this
+     * key.</p>
+     * <p>The same curve will be applied to all color channels. The camera device
+     * may clip the input gamma value to its supported range. The actual applied
+     * value will be returned in capture result.</p>
+     * <p>The valid range of gamma value varies on different devices, but values
+     * within [1.0, 5.0] are guaranteed not to be clipped.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    @PublicKey
+    public static final Key<Float> TONEMAP_GAMMA =
+            new Key<Float>("android.tonemap.gamma", float.class);
+
+    /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * PRESET_CURVE</p>
+     * <p>The tonemap curve will be defined by specified standard.</p>
+     * <p>sRGB (approximated by 16 control points):</p>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p>Rec. 709 (approximated by 16 control points):</p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p>Note that above figures show a 16 control points approximation of preset
+     * curves. Camera devices may apply a different approximation to the curve.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     * @see #TONEMAP_PRESET_CURVE_SRGB
+     * @see #TONEMAP_PRESET_CURVE_REC709
+     */
+    @PublicKey
+    public static final Key<Integer> TONEMAP_PRESET_CURVE =
+            new Key<Integer>("android.tonemap.presetCurve", int.class);
+
+    /**
      * <p>This LED is nominally used to indicate to the user
      * that the camera is powered on and may be streaming images back to the
      * Application Processor. In certain rare circumstances, the OS may
@@ -2426,6 +2522,52 @@
     public static final Key<Boolean> BLACK_LEVEL_LOCK =
             new Key<Boolean>("android.blackLevel.lock", boolean.class);
 
+    /**
+     * <p>The amount of exposure time increase factor applied to the original output
+     * frame by the application processing before sending for reprocessing.</p>
+     * <p>This is optional, and will be supported if the camera device supports YUV_REPROCESSING
+     * capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains YUV_REPROCESSING).</p>
+     * <p>For some YUV reprocessing use cases, the application may choose to filter the original
+     * output frames to effectively reduce the noise to the same level as a frame that was
+     * captured with longer exposure time. To be more specific, assuming the original captured
+     * images were captured with a sensitivity of S and an exposure time of T, the model in
+     * the camera device is that the amount of noise in the image would be approximately what
+     * would be expected if the original capture parameters had been a sensitivity of
+     * S/effectiveExposureFactor and an exposure time of T*effectiveExposureFactor, rather
+     * than S and T respectively. If the captured images were processed by the application
+     * before being sent for reprocessing, then the application may have used image processing
+     * algorithms and/or multi-frame image fusion to reduce the noise in the
+     * application-processed images (input images). By using the effectiveExposureFactor
+     * control, the application can communicate to the camera device the actual noise level
+     * improvement in the application-processed image. With this information, the camera
+     * device can select appropriate noise reduction and edge enhancement parameters to avoid
+     * excessive noise reduction ({@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}) and insufficient edge
+     * enhancement ({@link CaptureRequest#EDGE_MODE android.edge.mode}) being applied to the reprocessed frames.</p>
+     * <p>For example, for multi-frame image fusion use case, the application may fuse
+     * multiple output frames together to a final frame for reprocessing. When N image are
+     * fused into 1 image for reprocessing, the exposure time increase factor could be up to
+     * square root of N (based on a simple photon shot noise model). The camera device will
+     * adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+     * produce the best quality images.</p>
+     * <p>This is relative factor, 1.0 indicates the application hasn't processed the input
+     * buffer in a way that affects its effective exposure time.</p>
+     * <p>This control is only effective for YUV reprocessing capture request. For noise
+     * reduction reprocessing, it is only effective when <code>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} != OFF</code>.
+     * Similarly, for edge enhancement reprocessing, it is only effective when
+     * <code>{@link CaptureRequest#EDGE_MODE android.edge.mode} != OFF</code>.</p>
+     * <p><b>Units</b>: Relative exposure time increase factor.</p>
+     * <p><b>Range of valid values:</b><br>
+     * &gt;= 1.0</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    @PublicKey
+    public static final Key<Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR =
+            new Key<Float>("android.reprocess.effectiveExposureFactor", float.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index f17100d..b84dc2e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -403,6 +403,8 @@
      * in this matrix result metadata. The transform should keep the magnitude
      * of the output color values within <code>[0, 1.0]</code> (assuming input color
      * values is within the normalized range <code>[0, 1.0]</code>), or clipping may occur.</p>
+     * <p>The valid range of each matrix element varies on different devices, but
+     * values within [-1.5, 3.0] are guaranteed not to be clipped.</p>
      * <p><b>Units</b>: Unitless scale factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -426,6 +428,10 @@
      * TRANSFORM_MATRIX.</p>
      * <p>The gains in the result metadata are the gains actually
      * applied by the camera device to the current frame.</p>
+     * <p>The valid range of gains varies on different devices, but gains
+     * between [1.0, 3.0] are guaranteed not to be clipped. Even if a given
+     * device allows gains below 1.0, this is usually not recommended because
+     * this can create color artifacts.</p>
      * <p><b>Units</b>: Unitless gain factors</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
@@ -575,7 +581,14 @@
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
      * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
      * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
-     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
+     * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.
+     * Similarly, AE precapture trigger CANCEL has no effect when AE is already locked.</p>
+     * <p>When an AE precapture sequence is triggered, AE unlock will not be able to unlock
+     * the AE if AE is locked by the camera device internally during precapture metering
+     * sequence In other words, submitting requests with AE unlock has no effect for an
+     * ongoing precapture metering sequence. Otherwise, the precapture metering sequence
+     * will never succeed in a sequence of preview requests where AE lock is always set
+     * to <code>false</code>.</p>
      * <p>Since the camera device has a pipeline of in-flight requests, the settings that
      * get locked do not necessarily correspond to the settings that were present in the
      * latest capture result received from the camera device, since additional captures
@@ -720,6 +733,11 @@
      * included at all in the request settings. When included and
      * set to START, the camera device will trigger the auto-exposure (AE)
      * precapture metering sequence.</p>
+     * <p>When set to CANCEL, the camera device will cancel any active
+     * precapture metering trigger, and return to its initial AE state.
+     * If a precapture metering sequence is already completed, and the camera
+     * device has implicitly locked the AE for subsequent still capture, the
+     * CANCEL trigger will unlock the AE and return to its initial AE state.</p>
      * <p>The precapture sequence should be triggered before starting a
      * high-quality still capture for final metering decisions to
      * be made, and for firing pre-capture flash pulses to estimate
@@ -735,7 +753,11 @@
      * submitted. To ensure that the AE routine restarts normal scan, the application should
      * submit a request with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == true</code>, followed by a request
      * with <code>{@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} == false</code>, if the application decides not to submit a
-     * still capture request after the precapture sequence completes.</p>
+     * still capture request after the precapture sequence completes. Alternatively, for
+     * API level 23 or newer devices, the CANCEL can be used to unlock the camera device
+     * internally locked AE if the application doesn't submit a still capture request after
+     * the AE precapture trigger. Note that, the CANCEL was added in API level 23, and must not
+     * be used in devices that have earlier API levels.</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
@@ -748,6 +770,7 @@
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
+     *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
      * </ul></p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
@@ -760,6 +783,7 @@
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
      * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+     * @see #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL
      */
     @PublicKey
     public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
@@ -892,11 +916,29 @@
      * <td align="center">Ready for high-quality capture</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * </tr>
+     * <tr>
+     * <td align="center">LOCKED</td>
+     * <td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
+     * <td align="center">LOCKED</td>
+     * <td align="center">Precapture trigger is ignored when AE is already locked</td>
+     * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START</td>
      * <td align="center">PRECAPTURE</td>
      * <td align="center">Start AE precapture metering sequence</td>
      * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL</td>
+     * <td align="center">INACTIVE</td>
+     * <td align="center">Currently active precapture metering sequence is canceled</td>
+     * </tr>
      * </tbody>
      * </table>
      * <p>For the above table, the camera device may skip reporting any state changes that happen
@@ -922,18 +964,30 @@
      * <td align="center">Values are already good, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
      * <td align="center">FLASH_REQUIRED</td>
      * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
-     * <td align="center">Any state</td>
+     * <td align="center">Any state (excluding LOCKED)</td>
      * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
      * <td align="center">CONVERGED</td>
      * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td>
      * </tr>
      * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td align="center">FLASH_REQUIRED</td>
+     * <td align="center">Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.</td>
+     * </tr>
+     * <tr>
+     * <td align="center">Any state (excluding LOCKED)</td>
+     * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is CANCEL, converged</td>
+     * <td align="center">CONVERGED</td>
+     * <td align="center">Converged after a precapture sequenceis canceled, transient states are skipped by camera device.</td>
+     * </tr>
+     * <tr>
      * <td align="center">CONVERGED</td>
      * <td align="center">Camera device finished AE scan</td>
      * <td align="center">FLASH_REQUIRED</td>
@@ -1637,7 +1691,7 @@
      * <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 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 OPAQUE_REPROCESSING. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
      * contains MANUAL_SENSOR. Other intent values are always supported.</p>
      * <p><b>Possible values:</b>
      * <ul>
@@ -1865,10 +1919,6 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p>LEGACY mode devices will only support AUTO and USE_SCENE_MODE modes.
-     * LIMITED mode devices will only support OFF and OFF_KEEP_STATE if they
-     * support the MANUAL_SENSOR and MANUAL_POST_PROCSESING capabilities.
-     * FULL mode devices will always support OFF and OFF_KEEP_STATE.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
@@ -1876,9 +1926,12 @@
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CameraCharacteristics#CONTROL_AVAILABLE_MODES
      * @see #CONTROL_MODE_OFF
      * @see #CONTROL_MODE_AUTO
      * @see #CONTROL_MODE_USE_SCENE_MODE
@@ -1998,6 +2051,10 @@
      * camera device will use the highest-quality enhancement algorithms,
      * even if it slows down capture rate. FAST means the camera device will
      * not slow down capture rate when applying edge enhancement.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
+     * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
+     * The camera device may adjust its internal noise reduction parameters for best
+     * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
@@ -2013,6 +2070,7 @@
      *
      * @see CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #EDGE_MODE_OFF
      * @see #EDGE_MODE_FAST
      * @see #EDGE_MODE_HIGH_QUALITY
@@ -2475,18 +2533,28 @@
     /**
      * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>The noise reduction algorithm attempts to improve image quality by removing
-     * excessive noise added by the capture process, especially in dark conditions.
-     * OFF means no noise reduction will be applied by the camera device.</p>
+     * excessive noise added by the capture process, especially in dark conditions.</p>
+     * <p>OFF means no noise reduction will be applied by the camera device, for both raw and
+     * YUV domain.</p>
+     * <p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,to remove
+     * demosaicing or other processing artifacts. For YUV_REPROCESSING, MINIMAL is same as OFF.
+     * This mode is optional, may not be support by all devices. The application should check
+     * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes} before using it.</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 will not
      * slow down capture rate when applying noise filtering.</p>
+     * <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera device
+     * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
+     * may adjust the noise reduction parameters for best image quality based on the
+     * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
@@ -2497,9 +2565,11 @@
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
+     * @see CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
      * @see #NOISE_REDUCTION_MODE_OFF
      * @see #NOISE_REDUCTION_MODE_FAST
      * @see #NOISE_REDUCTION_MODE_HIGH_QUALITY
+     * @see #NOISE_REDUCTION_MODE_MINIMAL
      */
     @PublicKey
     public static final Key<Integer> NOISE_REDUCTION_MODE =
@@ -2984,6 +3054,8 @@
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2992,6 +3064,7 @@
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#SHADING_AVAILABLE_MODES
      * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
      * @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
      * @see #SHADING_MODE_OFF
@@ -3155,7 +3228,7 @@
     /**
      * <p>The shading map is a low-resolution floating-point map
      * that lists the coefficients used to correct for vignetting, for each
-     * Bayer color channel.</p>
+     * Bayer color channel of RAW image data.</p>
      * <p>The least shaded section of the image should have a gain factor
      * of 1; all other sections should have gains above 1.</p>
      * <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
@@ -3191,8 +3264,20 @@
      * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
      * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
      * <p>As a visualization only, inverting the full-color map to recover an
-     * image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
+     * image of a gray wall (using bicubic interpolation for visual quality)
+     * as captured by the sensor gives:</p>
      * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+     * <p>Note that the RAW image data might be subject to lens shading
+     * correction not reported on this map. Query
+     * {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} to see if RAW image data has subject
+     * to lens shading correction. If {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied}
+     * is TRUE, the RAW image data is subject to partial or full lens shading
+     * correction. In the case full lens shading correction is applied to RAW
+     * images, the gain factor map reported in this key will contain all 1.0 gains.
+     * In other words, the map reported in this key is the remaining lens shading
+     * that needs to be applied on the RAW image to get images without lens shading
+     * artifacts. See {@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW android.request.maxNumOutputRaw} for a list of RAW image
+     * formats.</p>
      * <p><b>Range of valid values:</b><br>
      * Each gain factor is &gt;= 1</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3202,6 +3287,8 @@
      *
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_RAW
+     * @see CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED
      * @hide
      */
     public static final Key<float[]> STATISTICS_LENS_SHADING_MAP =
@@ -3339,12 +3426,15 @@
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
      * </ul></p>
+     * <p><b>Available values for this device:</b><br>
+     * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
      * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
      */
@@ -3531,6 +3621,8 @@
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
+     *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
+     *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
      * </ul></p>
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
@@ -3546,12 +3638,60 @@
      * @see #TONEMAP_MODE_CONTRAST_CURVE
      * @see #TONEMAP_MODE_FAST
      * @see #TONEMAP_MODE_HIGH_QUALITY
+     * @see #TONEMAP_MODE_GAMMA_VALUE
+     * @see #TONEMAP_MODE_PRESET_CURVE
      */
     @PublicKey
     public static final Key<Integer> TONEMAP_MODE =
             new Key<Integer>("android.tonemap.mode", int.class);
 
     /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * GAMMA_VALUE</p>
+     * <p>The tonemap curve will be defined the following formula:
+     * * OUT = pow(IN, 1.0 / gamma)
+     * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+     * pow is the power function and gamma is the gamma value specified by this
+     * key.</p>
+     * <p>The same curve will be applied to all color channels. The camera device
+     * may clip the input gamma value to its supported range. The actual applied
+     * value will be returned in capture result.</p>
+     * <p>The valid range of gamma value varies on different devices, but values
+     * within [1.0, 5.0] are guaranteed not to be clipped.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     */
+    @PublicKey
+    public static final Key<Float> TONEMAP_GAMMA =
+            new Key<Float>("android.tonemap.gamma", float.class);
+
+    /**
+     * <p>Tonemapping curve to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
+     * PRESET_CURVE</p>
+     * <p>The tonemap curve will be defined by specified standard.</p>
+     * <p>sRGB (approximated by 16 control points):</p>
+     * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+     * <p>Rec. 709 (approximated by 16 control points):</p>
+     * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+     * <p>Note that above figures show a 16 control points approximation of preset
+     * curves. Camera devices may apply a different approximation to the curve.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
+     *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#TONEMAP_MODE
+     * @see #TONEMAP_PRESET_CURVE_SRGB
+     * @see #TONEMAP_PRESET_CURVE_REC709
+     */
+    @PublicKey
+    public static final Key<Integer> TONEMAP_PRESET_CURVE =
+            new Key<Integer>("android.tonemap.presetCurve", int.class);
+
+    /**
      * <p>This LED is nominally used to indicate to the user
      * that the camera is powered on and may be streaming images back to the
      * Application Processor. In certain rare circumstances, the OS may
@@ -3657,6 +3797,52 @@
     public static final Key<Long> SYNC_FRAME_NUMBER =
             new Key<Long>("android.sync.frameNumber", long.class);
 
+    /**
+     * <p>The amount of exposure time increase factor applied to the original output
+     * frame by the application processing before sending for reprocessing.</p>
+     * <p>This is optional, and will be supported if the camera device supports YUV_REPROCESSING
+     * capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains YUV_REPROCESSING).</p>
+     * <p>For some YUV reprocessing use cases, the application may choose to filter the original
+     * output frames to effectively reduce the noise to the same level as a frame that was
+     * captured with longer exposure time. To be more specific, assuming the original captured
+     * images were captured with a sensitivity of S and an exposure time of T, the model in
+     * the camera device is that the amount of noise in the image would be approximately what
+     * would be expected if the original capture parameters had been a sensitivity of
+     * S/effectiveExposureFactor and an exposure time of T*effectiveExposureFactor, rather
+     * than S and T respectively. If the captured images were processed by the application
+     * before being sent for reprocessing, then the application may have used image processing
+     * algorithms and/or multi-frame image fusion to reduce the noise in the
+     * application-processed images (input images). By using the effectiveExposureFactor
+     * control, the application can communicate to the camera device the actual noise level
+     * improvement in the application-processed image. With this information, the camera
+     * device can select appropriate noise reduction and edge enhancement parameters to avoid
+     * excessive noise reduction ({@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}) and insufficient edge
+     * enhancement ({@link CaptureRequest#EDGE_MODE android.edge.mode}) being applied to the reprocessed frames.</p>
+     * <p>For example, for multi-frame image fusion use case, the application may fuse
+     * multiple output frames together to a final frame for reprocessing. When N image are
+     * fused into 1 image for reprocessing, the exposure time increase factor could be up to
+     * square root of N (based on a simple photon shot noise model). The camera device will
+     * adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
+     * produce the best quality images.</p>
+     * <p>This is relative factor, 1.0 indicates the application hasn't processed the input
+     * buffer in a way that affects its effective exposure time.</p>
+     * <p>This control is only effective for YUV reprocessing capture request. For noise
+     * reduction reprocessing, it is only effective when <code>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} != OFF</code>.
+     * Similarly, for edge enhancement reprocessing, it is only effective when
+     * <code>{@link CaptureRequest#EDGE_MODE android.edge.mode} != OFF</code>.</p>
+     * <p><b>Units</b>: Relative exposure time increase factor.</p>
+     * <p><b>Range of valid values:</b><br>
+     * &gt;= 1.0</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#EDGE_MODE
+     * @see CaptureRequest#NOISE_REDUCTION_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    @PublicKey
+    public static final Key<Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR =
+            new Key<Float>("android.reprocess.effectiveExposureFactor", float.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 50a58ed..d286d38 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -66,7 +66,7 @@
     int deleteStream(int streamId);
 
     // non-negative value is the stream ID. negative value is status_t
-    int createStream(int width, int height, int format, in Surface surface);
+    int createStream(in Surface surface);
 
     int createDefaultRequest(int templateId, out CameraMetadataNative request);
 
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5bc7f71..e87a2f8 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -21,11 +21,9 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.dispatch.ArgumentReplacingDispatcher;
 import android.hardware.camera2.dispatch.BroadcastDispatcher;
-import android.hardware.camera2.dispatch.Dispatchable;
 import android.hardware.camera2.dispatch.DuckTypingDispatcher;
 import android.hardware.camera2.dispatch.HandlerDispatcher;
 import android.hardware.camera2.dispatch.InvokeDispatcher;
-import android.hardware.camera2.dispatch.NullDispatcher;
 import android.hardware.camera2.utils.TaskDrainer;
 import android.hardware.camera2.utils.TaskSingleDrainer;
 import android.os.Handler;
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ec450bd1..c5267cb 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -28,6 +28,7 @@
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.hardware.camera2.utils.LongParcelable;
@@ -373,9 +374,7 @@
 
                 // Add all new streams
                 for (Surface s : addSet) {
-                    // TODO: remove width,height,format since we are ignoring
-                    // it.
-                    int streamId = mRemoteDevice.createStream(0, 0, 0, s);
+                    int streamId = mRemoteDevice.createStream(s);
                     mConfiguredOutputs.put(streamId, s);
                 }
 
@@ -417,6 +416,18 @@
     public void createCaptureSession(List<Surface> outputs,
             CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException {
+        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
+        for (Surface surface : outputs) {
+            outConfigurations.add(new OutputConfiguration(surface));
+        }
+        createCaptureSessionByOutputConfiguration(outConfigurations, callback, handler);
+    }
+
+    @Override
+    public void createCaptureSessionByOutputConfiguration(
+            List<OutputConfiguration> outputConfigurations,
+            CameraCaptureSession.StateCallback callback, Handler handler)
+            throws CameraAccessException {
         synchronized(mInterfaceLock) {
             if (DEBUG) {
                 Log.d(TAG, "createCaptureSession");
@@ -433,8 +444,12 @@
             // TODO: dont block for this
             boolean configureSuccess = true;
             CameraAccessException pendingException = null;
+            List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
+            for (OutputConfiguration config : outputConfigurations) {
+                outSurfaces.add(config.getSurface());
+            }
             try {
-                configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
+                configureSuccess = configureOutputsChecked(outSurfaces); // and then block until IDLE
             } catch (CameraAccessException e) {
                 configureSuccess = false;
                 pendingException = e;
@@ -446,7 +461,7 @@
             // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
             CameraCaptureSessionImpl newSession =
                     new CameraCaptureSessionImpl(mNextSessionId++,
-                            outputs, callback, handler, this, mDeviceHandler,
+                            outSurfaces, callback, handler, this, mDeviceHandler,
                             configureSuccess);
 
             // TODO: wait until current session closes, then create the new session
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
index b9c89f8..e7b3682 100644
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java
@@ -17,10 +17,6 @@
 package android.hardware.camera2.legacy;
 
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.util.Log;
-import android.view.Surface;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index fcf172c..26cd498 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -504,7 +504,7 @@
     }
 
     @Override
-    public int createStream(int width, int height, int format, Surface surface) {
+    public int createStream(Surface surface) {
         if (DEBUG) {
             Log.d(TAG, "createStream called.");
         }
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
index 6215a8f..e576beb 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
@@ -33,7 +33,6 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import static android.hardware.camera2.CaptureRequest.*;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 347db05..8776418 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -42,7 +42,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
 import static com.android.internal.util.Preconditions.*;
@@ -474,6 +473,15 @@
 
             m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step));
         }
+
+        /*
+         * control.aeLockAvailable
+         */
+        {
+            boolean aeLockAvailable = p.isAutoExposureLockSupported();
+
+            m.set(CONTROL_AE_LOCK_AVAILABLE, aeLockAvailable);
+        }
     }
 
 
@@ -571,6 +579,16 @@
                 Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " +
                         ListUtils.listToString(awbAvail));
             }
+
+
+            /*
+             * control.awbLockAvailable
+             */
+            {
+                boolean awbLockAvailable = p.isAutoWhiteBalanceLockSupported();
+
+                m.set(CONTROL_AWB_LOCK_AVAILABLE, awbLockAvailable);
+            }
         }
     }
 
@@ -618,17 +636,44 @@
         /*
          * android.control.availableSceneModes
          */
+        int maxNumDetectedFaces = p.getMaxNumDetectedFaces();
         List<String> sceneModes = p.getSupportedSceneModes();
         List<Integer> supportedSceneModes =
                 ArrayUtils.convertStringListToIntList(sceneModes, sLegacySceneModes, sSceneModes);
-        if (supportedSceneModes == null) { // camera1 doesn't support scene mode settings
-            supportedSceneModes = new ArrayList<Integer>();
-            supportedSceneModes.add(CONTROL_SCENE_MODE_DISABLED); // disabled is always available
+
+        // Special case where the only scene mode listed is AUTO => no scene mode
+        if (sceneModes != null && sceneModes.size() == 1 &&
+                sceneModes.get(0) == Parameters.SCENE_MODE_AUTO) {
+            supportedSceneModes = null;
         }
-        if (p.getMaxNumDetectedFaces() > 0) { // always supports FACE_PRIORITY when face detecting
-            supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
+
+        boolean sceneModeSupported = true;
+        if (supportedSceneModes == null && maxNumDetectedFaces == 0) {
+            sceneModeSupported = false;
         }
-        m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
+
+        if (sceneModeSupported) {
+            if (supportedSceneModes == null) {
+                supportedSceneModes = new ArrayList<Integer>();
+            }
+            if (maxNumDetectedFaces > 0) { // always supports FACE_PRIORITY when face detecting
+                supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
+            }
+            // Remove all DISABLED occurrences
+            if (supportedSceneModes.contains(CONTROL_SCENE_MODE_DISABLED)) {
+                while(supportedSceneModes.remove(new Integer(CONTROL_SCENE_MODE_DISABLED))) {}
+            }
+            m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
+        } else {
+            m.set(CONTROL_AVAILABLE_SCENE_MODES, new int[] {CONTROL_SCENE_MODE_DISABLED});
+        }
+
+        /*
+         * android.control.availableModes
+         */
+        m.set(CONTROL_AVAILABLE_MODES, sceneModeSupported ?
+                new int[] { CONTROL_MODE_AUTO, CONTROL_MODE_USE_SCENE_MODE } :
+                new int[] { CONTROL_MODE_AUTO });
     }
 
     private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 61f7b8b..3688610 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -34,7 +34,6 @@
 import java.util.List;
 import java.util.Objects;
 
-import static com.android.internal.util.Preconditions.*;
 import static android.hardware.camera2.CaptureRequest.*;
 
 /**
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
index 3b10eb5..9e9a6fe 100644
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
@@ -22,8 +22,6 @@
 import android.graphics.RectF;
 import android.hardware.Camera;
 import android.hardware.Camera.Area;
-import android.hardware.camera2.legacy.ParameterUtils.MeteringData;
-import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.ListUtils;
diff --git a/core/java/android/hardware/camera2/legacy/PerfMeasurement.java b/core/java/android/hardware/camera2/legacy/PerfMeasurement.java
index b930ec2..53278c7 100644
--- a/core/java/android/hardware/camera2/legacy/PerfMeasurement.java
+++ b/core/java/android/hardware/camera2/legacy/PerfMeasurement.java
@@ -20,7 +20,6 @@
 import android.util.Log;
 
 import java.io.BufferedWriter;
-import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
diff --git a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
index 0699ffb..e19ebf2 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
@@ -96,15 +96,15 @@
     // Blocks until thread is idling
     public void waitUntilIdle() {
         Handler handler = waitAndGetHandler();
-        Looper looper = handler.getLooper();
-        if (looper.isIdling()) {
+        MessageQueue queue = handler.getLooper().getQueue();
+        if (queue.isIdle()) {
             return;
         }
         mIdle.close();
-        looper.getQueue().addIdleHandler(mIdleHandler);
+        queue.addIdleHandler(mIdleHandler);
         // Ensure that the idle handler gets run even if the looper already went idle
         handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
-        if (looper.isIdling()) {
+        if (queue.isIdle()) {
             return;
         }
         mIdle.block();
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index edd8e4e..9b628fb 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -17,7 +17,6 @@
 package android.hardware.camera2.legacy;
 
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraMetadataNative;
 import android.util.Log;
 import android.view.Surface;
 
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index f1f2f0c..ff74c59 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -16,13 +16,11 @@
 
 package android.hardware.camera2.legacy;
 
-import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.LongParcelable;
 import android.hardware.camera2.utils.SizeAreaComparator;
 import android.hardware.camera2.impl.CameraMetadataNative;
@@ -38,7 +36,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -85,7 +82,7 @@
 
     private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms
     private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2)
-    private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT; // ms (same as JPEG timeout)
+    private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT;
 
     private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
     private boolean mPreviewRunning = false;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
index 22b87ef..d89518b 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
@@ -25,9 +25,6 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 
-import static android.hardware.camera2.impl.CameraMetadataNative.*;
-import static android.hardware.camera2.marshal.MarshalHelpers.*;
-
 /**
  * Marshal any array {@code T}.
  *
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
index 1fd6a1d..0b7a4bf 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
@@ -25,9 +25,6 @@
 import java.lang.reflect.Field;
 import java.nio.ByteBuffer;
 
-import static android.hardware.camera2.impl.CameraMetadataNative.*;
-import static android.hardware.camera2.marshal.MarshalHelpers.*;
-
 /**
  * Marshal any {@code T extends Parcelable} to/from any native type
  *
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
index 189b597..090dd48 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -23,8 +23,6 @@
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static android.hardware.camera2.marshal.MarshalHelpers.*;
-import static com.android.internal.util.Preconditions.*;
-
 import java.nio.ByteBuffer;
 
 /**
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
index 8512804..64763e7 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
@@ -27,9 +27,6 @@
 import java.lang.reflect.Type;
 import java.nio.ByteBuffer;
 
-import static android.hardware.camera2.impl.CameraMetadataNative.*;
-import static android.hardware.camera2.marshal.MarshalHelpers.*;
-
 /**
  * Marshal {@link Range} to/from any native type
  */
diff --git a/core/java/android/hardware/camera2/params/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
index 9bbc33a..d6b84f2 100644
--- a/core/java/android/hardware/camera2/params/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -19,7 +19,6 @@
 import static com.android.internal.util.Preconditions.*;
 import static android.hardware.camera2.params.RggbChannelVector.*;
 
-import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
@@ -238,6 +237,51 @@
         return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
     }
 
+    /**
+     * Return the LensShadingMap as a string representation.
+     *
+     * <p> {@code "LensShadingMap{R:([%f, %f, ... %f], ... [%f, %f, ... %f]), G_even:([%f, %f, ...
+     *  %f], ... [%f, %f, ... %f]), G_odd:([%f, %f, ... %f], ... [%f, %f, ... %f]), B:([%f, %f, ...
+     *  %f], ... [%f, %f, ... %f])}"},
+     * where each {@code %f} represents one gain factor and each {@code [%f, %f, ... %f]} represents
+     * a row of the lens shading map</p>
+     *
+     * @return string representation of {@link LensShadingMap}
+     */
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append("LensShadingMap{");
+
+        final String channelPrefix[] = {"R:(", "G_even:(", "G_odd:(", "B:("};
+
+        for (int ch = 0; ch < COUNT; ch++) {
+            str.append(channelPrefix[ch]);
+
+            for (int r = 0; r < mRows; r++) {
+                str.append("[");
+                for (int c = 0; c < mColumns; c++) {
+                    float gain = getGainFactor(ch, c, r);
+                    str.append(gain);
+                    if (c < mColumns - 1) {
+                        str.append(", ");
+                    }
+                }
+                str.append("]");
+                if (r < mRows - 1) {
+                    str.append(", ");
+                }
+            }
+
+            str.append(")");
+            if (ch < COUNT - 1) {
+                str.append(", ");
+            }
+        }
+
+        str.append("}");
+        return str.toString();
+    }
 
     private final int mRows;
     private final int mColumns;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
new file mode 100644
index 0000000..47c784e
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware.camera2.params;
+
+import android.hardware.camera2.CameraDevice;
+import android.view.Surface;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class for describing camera output, which contains a {@link Surface} and its specific
+ * configuration for creating capture session.
+ *
+ * @see CameraDevice#createCaptureSession
+ *
+ * @hide
+ */
+public final class OutputConfiguration {
+
+    /**
+     * Rotation constant: 0 degree rotation (no rotation)
+     */
+    public static final int ROTATION_0 = 0;
+
+    /**
+     * Rotation constant: 90 degree counterclockwise rotation.
+     */
+    public static final int ROTATION_90 = 1;
+
+    /**
+     * Rotation constant: 180 degree counterclockwise rotation.
+     */
+    public static final int ROTATION_180 = 2;
+
+    /**
+     * Rotation constant: 270 degree counterclockwise rotation.
+     */
+    public static final int ROTATION_270 = 3;
+
+    /**
+     * Create a new immutable SurfaceConfiguration instance.
+     *
+     * @param surface
+     *          A Surface for camera to output to.
+     *
+     * <p>This constructor creates a default configuration</p>
+     *
+     */
+    public OutputConfiguration(Surface surface) {
+        checkNotNull(surface, "Surface must not be null");
+        mSurface = surface;
+        mRotation = ROTATION_0;
+    }
+
+    /**
+     * Create a new immutable SurfaceConfiguration instance.
+     *
+     * <p>This constructor takes an argument for desired camera rotation</p>
+     *
+     * @param surface
+     *          A Surface for camera to output to.
+     * @param rotation
+     *          The desired rotation to be applied on camera output. Value must be one of
+     *          ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degree,
+     *          application should make sure corresponding surface size has width and height
+     *          transposed corresponding to the width and height without rotation. For example,
+     *          if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
+     *          application should set rotation to {@code ROTATION_90} and make sure the
+     *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
+     *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
+     *
+     */
+    public OutputConfiguration(Surface surface, int rotation) {
+        checkNotNull(surface, "Surface must not be null");
+        checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+        mSurface = surface;
+        mRotation = rotation;
+    }
+
+    /**
+     * Get the {@link Surface} associated with this {@link OutputConfiguration}.
+     *
+     * @return the {@link Surface} associated with this {@link OutputConfiguration}.
+     */
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    /**
+     * Get the rotation associated with this {@link OutputConfiguration}.
+     *
+     * @return the rotation associated with this {@link OutputConfiguration}.
+     *         Value will be one of ROTATION_[0, 90, 180, 270]
+     */
+    public int getRotation() {
+        return mRotation;
+    }
+
+    private final Surface mSurface;
+    private final int mRotation;
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 479c842..f5304f8 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -26,7 +26,6 @@
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
 import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
 import android.view.Surface;
-import android.util.Log;
 import android.util.Range;
 import android.util.Size;
 
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 0051ef5..d9f9c1e 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -17,10 +17,10 @@
 package android.hardware.display;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.projection.MediaProjection;
 import android.media.projection.IMediaProjection;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -196,11 +196,11 @@
      * Gets information about a logical display without applying any compatibility metrics.
      *
      * @param displayId The logical display id.
-     * @param IBinder the activity token for this display.
+     * @param configuration the configuration.
      * @return The display object, or null if there is no display with the given id.
      */
-    public Display getRealDisplay(int displayId, IBinder token) {
-        return getCompatibleDisplay(displayId, new DisplayAdjustments(token));
+    public Display getRealDisplay(int displayId, Configuration configuration) {
+        return getCompatibleDisplay(displayId, new DisplayAdjustments(configuration));
     }
 
     public void registerDisplayListener(DisplayListener listener, Handler handler) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index bb162153..adab9be 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -132,6 +132,19 @@
             float requestedRefreshRate, boolean inTraversal);
 
     /**
+     * Applies an offset to the contents of a display, for example to avoid burn-in.
+     * <p>
+     * TODO: Technically this should be associated with a physical rather than logical
+     * display but this is good enough for now.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param x The X offset by which to shift the contents of the display.
+     * @param y The Y offset by which to shift the contents of the display.
+     */
+    public abstract void setDisplayOffsets(int displayId, int x, int y);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 4ddf10f..d354666 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -15,7 +15,6 @@
  */
 package android.hardware.display;
 
-import android.os.IBinder;
 import android.view.Display;
 import android.view.Surface;
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index e5995b0..444f020 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -27,8 +27,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.Vibrator;
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 518a874..cc018e9 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -104,7 +104,7 @@
             try {
                 ai = pm.getApplicationInfo(
                         ri.activityInfo.packageName, PackageManager.GET_META_DATA);
-                if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+                if ((ai.privateFlags & ApplicationInfo.PRIVATE_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");
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 1a8723d..e23a2bb 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -16,13 +16,10 @@
 
 package android.hardware.soundtrigger;
 
-import android.content.Context;
-import android.content.Intent;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import java.lang.ref.WeakReference;
-import java.util.UUID;
 
 /**
  * The SoundTriggerModule provides APIs to control sound models and sound detection
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index d90e06e..1a42319 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -40,6 +40,7 @@
 public class UsbDevice implements Parcelable {
 
     private static final String TAG = "UsbDevice";
+    private static final boolean DEBUG = false;
 
     private final String mName;
     private final String mManufacturerName;
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f64ef87..f283051 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -68,6 +68,8 @@
      * accessory function is enabled
      * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
      * audio source function is enabled
+     * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
+     * MIDI function is enabled
      * </ul>
      *
      * {@hide}
@@ -188,6 +190,14 @@
     public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
 
     /**
+     * Name of the MIDI USB function.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
+     */
+    public static final String USB_FUNCTION_MIDI = "midi";
+
+    /**
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2eb42a7..481fc2f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -19,6 +19,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import android.annotation.DrawableRes;
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.content.Context;
@@ -708,6 +709,7 @@
         mRootView.setSystemUiVisibility(
                 View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mWindow.setContentView(mRootView);
+        mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
         if (Settings.Global.getInt(getContentResolver(),
                 Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
@@ -1177,7 +1179,7 @@
         return isExtractViewShown() ? View.GONE : View.INVISIBLE;
     }
     
-    public void showStatusIcon(int iconResId) {
+    public void showStatusIcon(@DrawableRes int iconResId) {
         mStatusIcon = iconResId;
         mImm.showStatusIcon(mToken, getPackageName(), iconResId);
     }
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index 4fe54c0..45f1889 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -18,6 +18,7 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.XmlRes;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -519,7 +520,8 @@
      * @param width sets width of keyboard
      * @param height sets height of keyboard
      */
-    public Keyboard(Context context, int xmlLayoutResId, int modeId, int width, int height) {
+    public Keyboard(Context context, @XmlRes int xmlLayoutResId, int modeId, int width,
+            int height) {
         mDisplayWidth = width;
         mDisplayHeight = height;
 
@@ -540,7 +542,7 @@
      * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
      * @param modeId keyboard mode identifier
      */
-    public Keyboard(Context context, int xmlLayoutResId, int modeId) {
+    public Keyboard(Context context, @XmlRes int xmlLayoutResId, int modeId) {
         DisplayMetrics dm = context.getResources().getDisplayMetrics();
         mDisplayWidth = dm.widthPixels;
         mDisplayHeight = dm.heightPixels;
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
deleted file mode 100644
index e4e5b1e..0000000
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Messenger;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * Interface to control and observe state of a specific network, hiding
- * network-specific details from {@link ConnectivityManager}. Surfaces events
- * through the registered {@link Handler} to enable {@link ConnectivityManager}
- * to respond to state changes over time.
- *
- * @hide
- */
-public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
-    // TODO: better document threading expectations
-    // TODO: migrate to make NetworkStateTracker abstract class
-
-    public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown";
-    public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi";
-
-    protected Context mContext;
-    private Handler mTarget;
-
-    protected NetworkInfo mNetworkInfo;
-    protected LinkProperties mLinkProperties;
-    protected NetworkCapabilities mNetworkCapabilities;
-    protected Network mNetwork = new Network(ConnectivityManager.NETID_UNSET);
-
-    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
-    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
-    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
-
-    public BaseNetworkStateTracker(int networkType) {
-        mNetworkInfo = new NetworkInfo(
-                networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
-        mLinkProperties = new LinkProperties();
-        mNetworkCapabilities = new NetworkCapabilities();
-    }
-
-    protected BaseNetworkStateTracker() {
-        // By default, let the sub classes construct everything
-    }
-
-    @Deprecated
-    protected Handler getTargetHandler() {
-        return mTarget;
-    }
-
-    protected final void dispatchStateChanged() {
-        // TODO: include snapshot of other fields when sending
-        mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget();
-    }
-
-    protected final void dispatchConfigurationChanged() {
-        // TODO: include snapshot of other fields when sending
-        mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget();
-    }
-
-    @Override
-    public void startMonitoring(Context context, Handler target) {
-        mContext = Preconditions.checkNotNull(context);
-        mTarget = Preconditions.checkNotNull(target);
-        startMonitoringInternal();
-    }
-
-    protected void startMonitoringInternal() {
-
-    }
-
-    @Override
-    public NetworkInfo getNetworkInfo() {
-        return new NetworkInfo(mNetworkInfo);
-    }
-
-    @Override
-    public LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
-    }
-
-    @Override
-    public NetworkCapabilities getNetworkCapabilities() {
-        return new NetworkCapabilities(mNetworkCapabilities);
-    }
-
-    @Override
-    public LinkQualityInfo getLinkQualityInfo() {
-        return null;
-    }
-
-    @Override
-    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
-        // not implemented
-    }
-
-    @Override
-    public boolean setRadio(boolean turnOn) {
-        // Base tracker doesn't handle radios
-        return true;
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return mNetworkInfo.isAvailable();
-    }
-
-    @Override
-    public void setUserDataEnable(boolean enabled) {
-        // Base tracker doesn't handle enabled flags
-    }
-
-    @Override
-    public void setPolicyDataEnable(boolean enabled) {
-        // Base tracker doesn't handle enabled flags
-    }
-
-    @Override
-    public boolean isPrivateDnsRouteSet() {
-        return mPrivateDnsRouteSet.get();
-    }
-
-    @Override
-    public void privateDnsRouteSet(boolean enabled) {
-        mPrivateDnsRouteSet.set(enabled);
-    }
-
-    @Override
-    public boolean isDefaultRouteSet() {
-        return mDefaultRouteSet.get();
-    }
-
-    @Override
-    public void defaultRouteSet(boolean enabled) {
-        mDefaultRouteSet.set(enabled);
-    }
-
-    @Override
-    public boolean isTeardownRequested() {
-        return mTeardownRequested.get();
-    }
-
-    @Override
-    public void setTeardownRequested(boolean isRequested) {
-        mTeardownRequested.set(isRequested);
-    }
-
-    @Override
-    public void setDependencyMet(boolean met) {
-        // Base tracker doesn't handle dependencies
-    }
-
-    @Override
-    public void supplyMessenger(Messenger messenger) {
-        // not supported on this network
-    }
-
-    @Override
-    public String getNetworkInterfaceName() {
-        if (mLinkProperties != null) {
-            return mLinkProperties.getInterfaceName();
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
-        // nothing to do
-    }
-
-    @Override
-    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
-        // nothing to do
-    }
-
-    @Override
-    public void setNetId(int netId) {
-        mNetwork = new Network(netId);
-    }
-
-    @Override
-    public Network getNetwork() {
-        return mNetwork;
-    }
-}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index eb2df0b..34a0727 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -25,7 +25,6 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -38,7 +37,6 @@
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -504,6 +502,8 @@
                 return "MOBILE_EMERGENCY";
             case TYPE_PROXY:
                 return "PROXY";
+            case TYPE_VPN:
+                return "VPN";
             default:
                 return Integer.toString(type);
         }
@@ -1793,25 +1793,6 @@
     }
 
     /**
-     * Sets a secondary requirement bit for the given networkType.
-     * This requirement bit is generally under the control of the carrier
-     * or its agents and is not directly controlled by the user.
-     *
-     * @param networkType The network who's dependence has changed
-     * @param met Boolean - true if network use is OK, false if not
-     *
-     * <p>This method requires the call to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
-     * {@hide}
-     */
-    public void setDataDependency(int networkType, boolean met) {
-        try {
-            mService.setDataDependency(networkType, met);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
      * Returns true if the hardware supports the given network type
      * else it returns false.  This doesn't indicate we have coverage
      * or are authorized onto a network, just whether or not the
@@ -1892,20 +1873,6 @@
     }
 
     /**
-     * Supply the backend messenger for a network tracker
-     *
-     * @param networkType NetworkType to set
-     * @param messenger {@link Messenger}
-     * {@hide}
-     */
-    public void supplyMessenger(int networkType, Messenger messenger) {
-        try {
-            mService.supplyMessenger(networkType, messenger);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
      * Check mobile provisioning.
      *
      * @param suggestedTimeOutMs, timeout in milliseconds
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 6159e1e..87c063f 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import android.net.NetworkUtils;
-import android.os.Parcelable;
 import android.os.Parcel;
 import android.text.TextUtils;
 import android.util.Log;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 46af112..3c09978 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -33,6 +33,7 @@
 
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
 
 /**
@@ -102,8 +103,6 @@
 
     ProxyInfo getDefaultProxy();
 
-    void setDataDependency(int networkType, boolean met);
-
     boolean prepareVpn(String oldPackage, String newPackage);
 
     void setVpnPackageAuthorization(boolean authorized);
@@ -116,12 +115,12 @@
 
     LegacyVpnInfo getLegacyVpnInfo();
 
+    VpnInfo[] getAllVpnInfo();
+
     boolean updateLockdownVpn();
 
     void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal);
 
-    void supplyMessenger(int networkType, in Messenger messenger);
-
     int findConnectionTypeForIface(in String iface);
 
     int checkMobileProvisioning(int suggestedTimeOutMs);
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index 31bc20b..a374a86 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -29,7 +29,7 @@
  */
 public class LocalSocket implements Closeable {
 
-    private LocalSocketImpl impl;
+    private final LocalSocketImpl impl;
     private volatile boolean implCreated;
     private LocalSocketAddress localAddress;
     private boolean isBound;
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
deleted file mode 100644
index abbb7b8..0000000
--- a/core/java/android/net/MobileDataStateTracker.java
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.NetworkInfo.DetailedState;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import com.android.internal.telephony.DctConstants;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.AsyncChannel;
-
-import java.io.CharArrayWriter;
-import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Track the state of mobile data connectivity. This is done by
- * receiving broadcast intents from the Phone process whenever
- * the state of data connectivity changes.
- *
- * {@hide}
- */
-public class MobileDataStateTracker extends BaseNetworkStateTracker {
-
-    private static final String TAG = "MobileDataStateTracker";
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false;
-
-    private PhoneConstants.DataState mMobileDataState;
-    private ITelephony mPhoneService;
-
-    private String mApnType;
-    private NetworkInfo mNetworkInfo;
-    private boolean mTeardownRequested = false;
-    private Handler mTarget;
-    private Context mContext;
-    private LinkProperties mLinkProperties;
-    private boolean mPrivateDnsRouteSet = false;
-    private boolean mDefaultRouteSet = false;
-
-    // NOTE: these are only kept for debugging output; actual values are
-    // maintained in DataConnectionTracker.
-    protected boolean mUserDataEnabled = true;
-    protected boolean mPolicyDataEnabled = true;
-
-    private Handler mHandler;
-    private AsyncChannel mDataConnectionTrackerAc;
-
-    private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false);
-
-    private SignalStrength mSignalStrength;
-
-    private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
-
-    private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT;
-
-    /**
-     * Create a new MobileDataStateTracker
-     * @param netType the ConnectivityManager network type
-     * @param tag the name of this network
-     */
-    public MobileDataStateTracker(int netType, String tag) {
-        mNetworkInfo = new NetworkInfo(netType,
-                TelephonyManager.getDefault().getNetworkType(), tag,
-                TelephonyManager.getDefault().getNetworkTypeName());
-        mApnType = networkTypeToApnType(netType);
-    }
-
-    /**
-     * Begin monitoring data connectivity.
-     *
-     * @param context is the current Android context
-     * @param target is the Hander to which to return the events.
-     */
-    public void startMonitoring(Context context, Handler target) {
-        mTarget = target;
-        mContext = context;
-
-        mHandler = new MdstHandler(target.getLooper(), this);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
-        filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
-        filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
-
-        mContext.registerReceiver(new MobileDataStateReceiver(), filter);
-        mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
-
-        TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
-    }
-
-    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-            mSignalStrength = signalStrength;
-        }
-    };
-
-    static class MdstHandler extends Handler {
-        private MobileDataStateTracker mMdst;
-
-        MdstHandler(Looper looper, MobileDataStateTracker mdst) {
-            super(looper);
-            mMdst = mdst;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        if (VDBG) {
-                            mMdst.log("MdstHandler connected");
-                        }
-                        mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
-                    } else {
-                        if (VDBG) {
-                            mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
-                        }
-                    }
-                    break;
-                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                    if (VDBG) mMdst.log("Disconnected from DataStateTracker");
-                    mMdst.mDataConnectionTrackerAc = null;
-                    break;
-                default: {
-                    if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
-                    break;
-                }
-            }
-        }
-    }
-
-    public boolean isPrivateDnsRouteSet() {
-        return mPrivateDnsRouteSet;
-    }
-
-    public void privateDnsRouteSet(boolean enabled) {
-        mPrivateDnsRouteSet = enabled;
-    }
-
-    public NetworkInfo getNetworkInfo() {
-        return mNetworkInfo;
-    }
-
-    public boolean isDefaultRouteSet() {
-        return mDefaultRouteSet;
-    }
-
-    public void defaultRouteSet(boolean enabled) {
-        mDefaultRouteSet = enabled;
-    }
-
-    /**
-     * This is not implemented.
-     */
-    public void releaseWakeLock() {
-    }
-
-    private void updateLinkProperitesAndCapatilities(Intent intent) {
-        mLinkProperties = intent.getParcelableExtra(
-                PhoneConstants.DATA_LINK_PROPERTIES_KEY);
-        if (mLinkProperties == null) {
-            loge("CONNECTED event did not supply link properties.");
-            mLinkProperties = new LinkProperties();
-        }
-        mLinkProperties.setMtu(mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_mobile_mtu));
-        mNetworkCapabilities = intent.getParcelableExtra(
-                PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY);
-        if (mNetworkCapabilities == null) {
-            loge("CONNECTED event did not supply network capabilities.");
-            mNetworkCapabilities = new NetworkCapabilities();
-        }
-    }
-
-    private class MobileDataStateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(TelephonyIntents.
-                    ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
-                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
-                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
-                if (!TextUtils.equals(mApnType, apnType)) {
-                    return;
-                }
-                if (DBG) {
-                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType
-                            + " apnName=" + apnName);
-                }
-
-                // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
-                mMobileDataState = PhoneConstants.DataState.CONNECTING;
-                updateLinkProperitesAndCapatilities(intent);
-                mNetworkInfo.setIsConnectedToProvisioningNetwork(true);
-
-                // Change state to SUSPENDED so setDetailedState
-                // sends EVENT_STATE_CHANGED to connectivityService
-                setDetailedState(DetailedState.SUSPENDED, "", apnName);
-            } else if (intent.getAction().equals(TelephonyIntents.
-                    ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
-                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
-                if (VDBG) {
-                    log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"
-                        + "mApnType=%s %s received apnType=%s", mApnType,
-                        TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType));
-                }
-                if (!TextUtils.equals(apnType, mApnType)) {
-                    return;
-                }
-                // Assume this isn't a provisioning network.
-                mNetworkInfo.setIsConnectedToProvisioningNetwork(false);
-                if (DBG) {
-                    log("Broadcast received: " + intent.getAction() + " apnType=" + apnType);
-                }
-
-                int oldSubtype = mNetworkInfo.getSubtype();
-                int newSubType = TelephonyManager.getDefault().getNetworkType();
-                String subTypeName = TelephonyManager.getDefault().getNetworkTypeName();
-                mNetworkInfo.setSubtype(newSubType, subTypeName);
-                if (newSubType != oldSubtype && mNetworkInfo.isConnected()) {
-                    Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED,
-                                                        oldSubtype, 0, mNetworkInfo);
-                    msg.sendToTarget();
-                }
-
-                PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class,
-                        intent.getStringExtra(PhoneConstants.STATE_KEY));
-                String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY);
-                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
-                mNetworkInfo.setRoaming(intent.getBooleanExtra(
-                        PhoneConstants.DATA_NETWORK_ROAMING_KEY, false));
-                if (VDBG) {
-                    log(mApnType + " setting isAvailable to " +
-                            intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false));
-                }
-                mNetworkInfo.setIsAvailable(!intent.getBooleanExtra(
-                        PhoneConstants.NETWORK_UNAVAILABLE_KEY, false));
-
-                if (DBG) {
-                    log("Received state=" + state + ", old=" + mMobileDataState +
-                        ", reason=" + (reason == null ? "(unspecified)" : reason));
-                }
-                if (mMobileDataState != state) {
-                    mMobileDataState = state;
-                    switch (state) {
-                        case DISCONNECTED:
-                            if(isTeardownRequested()) {
-                                setTeardownRequested(false);
-                            }
-
-                            setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
-                            // can't do this here - ConnectivityService needs it to clear stuff
-                            // it's ok though - just leave it to be refreshed next time
-                            // we connect.
-                            //if (DBG) log("clearing mInterfaceName for "+ mApnType +
-                            //        " as it DISCONNECTED");
-                            //mInterfaceName = null;
-                            break;
-                        case CONNECTING:
-                            setDetailedState(DetailedState.CONNECTING, reason, apnName);
-                            break;
-                        case SUSPENDED:
-                            setDetailedState(DetailedState.SUSPENDED, reason, apnName);
-                            break;
-                        case CONNECTED:
-                            updateLinkProperitesAndCapatilities(intent);
-                            setDetailedState(DetailedState.CONNECTED, reason, apnName);
-                            break;
-                    }
-
-                    if (VDBG) {
-                        Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
-                        if (mNetworkInfo != null) {
-                            Slog.d(TAG, "NetworkInfo = " + mNetworkInfo);
-                            Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype());
-                            Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
-                        }
-                        if (mLinkProperties != null) {
-                            Slog.d(TAG, "LinkProperties = " + mLinkProperties);
-                        } else {
-                            Slog.d(TAG, "LinkProperties = " );
-                        }
-
-                        if (mNetworkCapabilities != null) {
-                            Slog.d(TAG, mNetworkCapabilities.toString());
-                        } else {
-                            Slog.d(TAG, "NetworkCapabilities = " );
-                        }
-                    }
-
-
-                    /* lets not sample traffic data across state changes */
-                    mSamplingDataTracker.resetSamplingData();
-                } else {
-                    // There was no state change. Check if LinkProperties has been updated.
-                    if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
-                        mLinkProperties = intent.getParcelableExtra(
-                                PhoneConstants.DATA_LINK_PROPERTIES_KEY);
-                        if (mLinkProperties == null) {
-                            loge("No link property in LINK_PROPERTIES change event.");
-                            mLinkProperties = new LinkProperties();
-                        }
-                        // Just update reason field in this NetworkInfo
-                        mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason,
-                                                      mNetworkInfo.getExtraInfo());
-                        Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED,
-                                                            mNetworkInfo);
-                        msg.sendToTarget();
-                    }
-                }
-            } else if (intent.getAction().
-                    equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
-                String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
-                if (!TextUtils.equals(apnType, mApnType)) {
-                    if (DBG) {
-                        log(String.format(
-                                "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " +
-                                "mApnType=%s != received apnType=%s", mApnType, apnType));
-                    }
-                    return;
-                }
-                // Assume this isn't a provisioning network.
-                mNetworkInfo.setIsConnectedToProvisioningNetwork(false);
-                String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
-                String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
-                if (DBG) {
-                    log("Broadcast received: " + intent.getAction() +
-                                " reason=" + reason == null ? "null" : reason);
-                }
-                setDetailedState(DetailedState.FAILED, reason, apnName);
-            } else {
-                if (DBG) log("Broadcast received: ignore " + intent.getAction());
-            }
-        }
-    }
-
-    private void getPhoneService(boolean forceRefresh) {
-        if ((mPhoneService == null) || forceRefresh) {
-            mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
-        }
-    }
-
-    /**
-     * Report whether data connectivity is possible.
-     */
-    public boolean isAvailable() {
-        return mNetworkInfo.isAvailable();
-    }
-
-    /**
-     * Return the system properties name associated with the tcp buffer sizes
-     * for this network.
-     */
-    public String getTcpBufferSizesPropName() {
-        String networkTypeStr = "unknown";
-        TelephonyManager tm = new TelephonyManager(mContext);
-        //TODO We have to edit the parameter for getNetworkType regarding CDMA
-        switch(tm.getNetworkType()) {
-        case TelephonyManager.NETWORK_TYPE_GPRS:
-            networkTypeStr = "gprs";
-            break;
-        case TelephonyManager.NETWORK_TYPE_EDGE:
-            networkTypeStr = "edge";
-            break;
-        case TelephonyManager.NETWORK_TYPE_UMTS:
-            networkTypeStr = "umts";
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSDPA:
-            networkTypeStr = "hsdpa";
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSUPA:
-            networkTypeStr = "hsupa";
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSPA:
-            networkTypeStr = "hspa";
-            break;
-        case TelephonyManager.NETWORK_TYPE_HSPAP:
-            networkTypeStr = "hspap";
-            break;
-        case TelephonyManager.NETWORK_TYPE_CDMA:
-            networkTypeStr = "cdma";
-            break;
-        case TelephonyManager.NETWORK_TYPE_1xRTT:
-            networkTypeStr = "1xrtt";
-            break;
-        case TelephonyManager.NETWORK_TYPE_EVDO_0:
-            networkTypeStr = "evdo";
-            break;
-        case TelephonyManager.NETWORK_TYPE_EVDO_A:
-            networkTypeStr = "evdo";
-            break;
-        case TelephonyManager.NETWORK_TYPE_EVDO_B:
-            networkTypeStr = "evdo";
-            break;
-        case TelephonyManager.NETWORK_TYPE_IDEN:
-            networkTypeStr = "iden";
-            break;
-        case TelephonyManager.NETWORK_TYPE_LTE:
-        case TelephonyManager.NETWORK_TYPE_IWLAN:
-            networkTypeStr = "lte";
-            break;
-        case TelephonyManager.NETWORK_TYPE_EHRPD:
-            networkTypeStr = "ehrpd";
-            break;
-        default:
-            loge("unknown network type: " + tm.getNetworkType());
-        }
-        return "net.tcp.buffersize." + networkTypeStr;
-    }
-
-    /**
-     * Tear down mobile data connectivity, i.e., disable the ability to create
-     * mobile data connections.
-     * TODO - make async and return nothing?
-     */
-    public boolean teardown() {
-        setTeardownRequested(true);
-        return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
-    }
-
-    /**
-     * @return true if this is ready to operate
-     */
-    public boolean isReady() {
-        return mDataConnectionTrackerAc != null;
-    }
-
-    @Override
-    public void captivePortalCheckCompleted(boolean isCaptivePortal) {
-        if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) {
-            // Captive portal change enable/disable failing fast
-            setEnableFailFastMobileData(
-                    isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED);
-        }
-    }
-
-    /**
-     * Record the detailed state of a network, and if it is a
-     * change from the previous state, send a notification to
-     * any listeners.
-     * @param state the new {@code DetailedState}
-     * @param reason a {@code String} indicating a reason for the state change,
-     * if one was supplied. May be {@code null}.
-     * @param extraInfo optional {@code String} providing extra information about the state change
-     */
-    private void setDetailedState(NetworkInfo.DetailedState state, String reason,
-            String extraInfo) {
-        if (DBG) log("setDetailed state, old ="
-                + mNetworkInfo.getDetailedState() + " and new state=" + state);
-        if (state != mNetworkInfo.getDetailedState()) {
-            boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
-            String lastReason = mNetworkInfo.getReason();
-            /*
-             * If a reason was supplied when the CONNECTING state was entered, and no
-             * reason was supplied for entering the CONNECTED state, then retain the
-             * reason that was supplied when going to CONNECTING.
-             */
-            if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null
-                    && lastReason != null)
-                reason = lastReason;
-            mNetworkInfo.setDetailedState(state, reason, extraInfo);
-            Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
-            msg.sendToTarget();
-        }
-    }
-
-    public void setTeardownRequested(boolean isRequested) {
-        mTeardownRequested = isRequested;
-    }
-
-    public boolean isTeardownRequested() {
-        return mTeardownRequested;
-    }
-
-    /**
-     * Re-enable mobile data connectivity after a {@link #teardown()}.
-     * TODO - make async and always get a notification?
-     */
-    public boolean reconnect() {
-        boolean retValue = false; //connected or expect to be?
-        setTeardownRequested(false);
-        switch (setEnableApn(mApnType, true)) {
-            case PhoneConstants.APN_ALREADY_ACTIVE:
-                // need to set self to CONNECTING so the below message is handled.
-                retValue = true;
-                break;
-            case PhoneConstants.APN_REQUEST_STARTED:
-                // set IDLE here , avoid the following second FAILED not sent out
-                mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
-                retValue = true;
-                break;
-            case PhoneConstants.APN_REQUEST_FAILED:
-            case PhoneConstants.APN_TYPE_NOT_AVAILABLE:
-                break;
-            default:
-                loge("Error in reconnect - unexpected response.");
-                break;
-        }
-        return retValue;
-    }
-
-    /**
-     * Turn on or off the mobile radio. No connectivity will be possible while the
-     * radio is off. The operation is a no-op if the radio is already in the desired state.
-     * @param turnOn {@code true} if the radio should be turned on, {@code false} if
-     */
-    public boolean setRadio(boolean turnOn) {
-        getPhoneService(false);
-        /*
-         * If the phone process has crashed in the past, we'll get a
-         * RemoteException and need to re-reference the service.
-         */
-        for (int retry = 0; retry < 2; retry++) {
-            if (mPhoneService == null) {
-                loge("Ignoring mobile radio request because could not acquire PhoneService");
-                break;
-            }
-
-            try {
-                return mPhoneService.setRadio(turnOn);
-            } catch (RemoteException e) {
-                if (retry == 0) getPhoneService(true);
-            }
-        }
-
-        loge("Could not set radio power to " + (turnOn ? "on" : "off"));
-        return false;
-    }
-
-
-    public void setInternalDataEnable(boolean enabled) {
-        if (DBG) log("setInternalDataEnable: E enabled=" + enabled);
-        final AsyncChannel channel = mDataConnectionTrackerAc;
-        if (channel != null) {
-            channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE,
-                    enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
-        }
-        if (VDBG) log("setInternalDataEnable: X enabled=" + enabled);
-    }
-
-    @Override
-    public void setUserDataEnable(boolean enabled) {
-        if (DBG) log("setUserDataEnable: E enabled=" + enabled);
-        final AsyncChannel channel = mDataConnectionTrackerAc;
-        if (channel != null) {
-            channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE,
-                    enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
-            mUserDataEnabled = enabled;
-        }
-        if (VDBG) log("setUserDataEnable: X enabled=" + enabled);
-    }
-
-    @Override
-    public void setPolicyDataEnable(boolean enabled) {
-        if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")");
-        final AsyncChannel channel = mDataConnectionTrackerAc;
-        if (channel != null) {
-            channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE,
-                    enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
-            mPolicyDataEnabled = enabled;
-        }
-    }
-
-    /**
-     * Eanble/disable FailFast
-     *
-     * @param enabled is DctConstants.ENABLED/DISABLED
-     */
-    public void setEnableFailFastMobileData(int enabled) {
-        if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")");
-        final AsyncChannel channel = mDataConnectionTrackerAc;
-        if (channel != null) {
-            channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled);
-        }
-    }
-
-    /**
-     * carrier dependency is met/unmet
-     * @param met
-     */
-    public void setDependencyMet(boolean met) {
-        Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType);
-        try {
-            if (DBG) log("setDependencyMet: E met=" + met);
-            Message msg = Message.obtain();
-            msg.what = DctConstants.CMD_SET_DEPENDENCY_MET;
-            msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED);
-            msg.setData(bundle);
-            mDataConnectionTrackerAc.sendMessage(msg);
-            if (VDBG) log("setDependencyMet: X met=" + met);
-        } catch (NullPointerException e) {
-            loge("setDependencyMet: X mAc was null" + e);
-        }
-    }
-
-    /**
-     *  Inform DCT mobile provisioning has started, it ends when provisioning completes.
-     */
-    public void enableMobileProvisioning(String url) {
-        if (DBG) log("enableMobileProvisioning(url=" + url + ")");
-        final AsyncChannel channel = mDataConnectionTrackerAc;
-        if (channel != null) {
-            Message msg = Message.obtain();
-            msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
-            msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
-            channel.sendMessage(msg);
-        }
-    }
-
-    /**
-     * Return if this network is the provisioning network. Valid only if connected.
-     * @param met
-     */
-    public boolean isProvisioningNetwork() {
-        boolean retVal;
-        try {
-            Message msg = Message.obtain();
-            msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
-            msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
-            Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
-            retVal = result.arg1 == DctConstants.ENABLED;
-        } catch (NullPointerException e) {
-            loge("isProvisioningNetwork: X " + e);
-            retVal = false;
-        }
-        if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
-        return retVal;
-    }
-
-    @Override
-    public String toString() {
-        final CharArrayWriter writer = new CharArrayWriter();
-        final PrintWriter pw = new PrintWriter(writer);
-        pw.print("Mobile data state: "); pw.println(mMobileDataState);
-        pw.print("Data enabled: user="); pw.print(mUserDataEnabled);
-        pw.print(", policy="); pw.println(mPolicyDataEnabled);
-        return writer.toString();
-    }
-
-    /**
-     * Internal method supporting the ENABLE_MMS feature.
-     * @param apnType the type of APN to be enabled or disabled (e.g., mms)
-     * @param enable {@code true} to enable the specified APN type,
-     * {@code false} to disable it.
-     * @return an integer value representing the outcome of the request.
-     */
-    private int setEnableApn(String apnType, boolean enable) {
-        getPhoneService(false);
-        /*
-         * If the phone process has crashed in the past, we'll get a
-         * RemoteException and need to re-reference the service.
-         */
-        for (int retry = 0; retry < 2; retry++) {
-            if (mPhoneService == null) {
-                loge("Ignoring feature request because could not acquire PhoneService");
-                break;
-            }
-
-//            try {
-//                if (enable) {
-//                    return mPhoneService.enableApnType(apnType);
-//                } else {
-//                    return mPhoneService.disableApnType(apnType);
-//                }
-//            } catch (RemoteException e) {
-//                if (retry == 0) getPhoneService(true);
-//            }
-        }
-
-        loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
-        return PhoneConstants.APN_REQUEST_FAILED;
-    }
-
-    public static String networkTypeToApnType(int netType) {
-        switch(netType) {
-            case ConnectivityManager.TYPE_MOBILE:
-                return PhoneConstants.APN_TYPE_DEFAULT;  // TODO - use just one of these
-            case ConnectivityManager.TYPE_MOBILE_MMS:
-                return PhoneConstants.APN_TYPE_MMS;
-            case ConnectivityManager.TYPE_MOBILE_SUPL:
-                return PhoneConstants.APN_TYPE_SUPL;
-            case ConnectivityManager.TYPE_MOBILE_DUN:
-                return PhoneConstants.APN_TYPE_DUN;
-            case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                return PhoneConstants.APN_TYPE_HIPRI;
-            case ConnectivityManager.TYPE_MOBILE_FOTA:
-                return PhoneConstants.APN_TYPE_FOTA;
-            case ConnectivityManager.TYPE_MOBILE_IMS:
-                return PhoneConstants.APN_TYPE_IMS;
-            case ConnectivityManager.TYPE_MOBILE_CBS:
-                return PhoneConstants.APN_TYPE_CBS;
-            case ConnectivityManager.TYPE_MOBILE_IA:
-                return PhoneConstants.APN_TYPE_IA;
-            case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
-                return PhoneConstants.APN_TYPE_EMERGENCY;
-            default:
-                sloge("Error mapping networkType " + netType + " to apnType.");
-                return null;
-        }
-    }
-
-
-    /**
-     * @see android.net.NetworkStateTracker#getLinkProperties()
-     */
-    @Override
-    public LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
-    }
-
-    public void supplyMessenger(Messenger messenger) {
-        if (VDBG) log(mApnType + " got supplyMessenger");
-        AsyncChannel ac = new AsyncChannel();
-        ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger);
-    }
-
-    private void log(String s) {
-        Slog.d(TAG, mApnType + ": " + s);
-    }
-
-    private void loge(String s) {
-        Slog.e(TAG, mApnType + ": " + s);
-    }
-
-    static private void sloge(String s) {
-        Slog.e(TAG, s);
-    }
-
-    @Override
-    public LinkQualityInfo getLinkQualityInfo() {
-        if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) {
-            // no data available yet; just return
-            return null;
-        }
-
-        MobileLinkQualityInfo li = new MobileLinkQualityInfo();
-
-        li.setNetworkType(mNetworkInfo.getType());
-
-        mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
-
-        if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
-            li.setMobileNetworkType(mNetworkInfo.getSubtype());
-
-            NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype());
-            if (entry != null) {
-                li.setTheoreticalRxBandwidth(entry.downloadBandwidth);
-                li.setTheoreticalRxBandwidth(entry.uploadBandwidth);
-                li.setTheoreticalLatency(entry.latency);
-            }
-
-            if (mSignalStrength != null) {
-                li.setNormalizedSignalStrength(getNormalizedSignalStrength(
-                        li.getMobileNetworkType(), mSignalStrength));
-            }
-        }
-
-        SignalStrength ss = mSignalStrength;
-        if (ss != null) {
-
-            li.setRssi(ss.getGsmSignalStrength());
-            li.setGsmErrorRate(ss.getGsmBitErrorRate());
-            li.setCdmaDbm(ss.getCdmaDbm());
-            li.setCdmaEcio(ss.getCdmaEcio());
-            li.setEvdoDbm(ss.getEvdoDbm());
-            li.setEvdoEcio(ss.getEvdoEcio());
-            li.setEvdoSnr(ss.getEvdoSnr());
-            li.setLteSignalStrength(ss.getLteSignalStrength());
-            li.setLteRsrp(ss.getLteRsrp());
-            li.setLteRsrq(ss.getLteRsrq());
-            li.setLteRssnr(ss.getLteRssnr());
-            li.setLteCqi(ss.getLteCqi());
-        }
-
-        if (VDBG) {
-            Slog.d(TAG, "Returning LinkQualityInfo with"
-                    + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType())
-                    + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth())
-                    + " gsm Signal Strength = " + String.valueOf(li.getRssi())
-                    + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm())
-                    + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm())
-                    + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength()));
-        }
-
-        return li;
-    }
-
-    static class NetworkDataEntry {
-        public int networkType;
-        public int downloadBandwidth;               // in kbps
-        public int uploadBandwidth;                 // in kbps
-        public int latency;                         // in millisecond
-
-        NetworkDataEntry(int i1, int i2, int i3, int i4) {
-            networkType = i1;
-            downloadBandwidth = i2;
-            uploadBandwidth = i3;
-            latency = i4;
-        }
-    }
-
-    private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] {
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE,      237,     118, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS,       48,      40, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS,      384,      64, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA,   14400, UNKNOWN, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA,   14400,    5760, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA,    14400,    5760, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP,   21000,    5760, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA,  UNKNOWN, UNKNOWN, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0,   2468,     153, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A,   3072,    1800, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B,  14700,    1800, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN,  UNKNOWN, UNKNOWN, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE,    100000,   50000, UNKNOWN),
-            new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN),
-    };
-
-    private static NetworkDataEntry getNetworkDataEntry(int networkType) {
-        for (NetworkDataEntry entry : mTheoreticalBWTable) {
-            if (entry.networkType == networkType) {
-                return entry;
-            }
-        }
-
-        Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType));
-        return null;
-    }
-
-    private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) {
-
-        int level;
-
-        switch(networkType) {
-            case TelephonyManager.NETWORK_TYPE_EDGE:
-            case TelephonyManager.NETWORK_TYPE_GPRS:
-            case TelephonyManager.NETWORK_TYPE_UMTS:
-            case TelephonyManager.NETWORK_TYPE_HSDPA:
-            case TelephonyManager.NETWORK_TYPE_HSUPA:
-            case TelephonyManager.NETWORK_TYPE_HSPA:
-            case TelephonyManager.NETWORK_TYPE_HSPAP:
-                level = ss.getGsmLevel();
-                break;
-            case TelephonyManager.NETWORK_TYPE_CDMA:
-            case TelephonyManager.NETWORK_TYPE_1xRTT:
-                level = ss.getCdmaLevel();
-                break;
-            case TelephonyManager.NETWORK_TYPE_EVDO_0:
-            case TelephonyManager.NETWORK_TYPE_EVDO_A:
-            case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                level = ss.getEvdoLevel();
-                break;
-            case TelephonyManager.NETWORK_TYPE_LTE:
-                level = ss.getLteLevel();
-                break;
-            case TelephonyManager.NETWORK_TYPE_IDEN:
-            case TelephonyManager.NETWORK_TYPE_EHRPD:
-            default:
-                return UNKNOWN;
-        }
-
-        return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) /
-                SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
-    }
-
-    @Override
-    public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
-        mSamplingDataTracker.startSampling(s);
-    }
-
-    @Override
-    public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
-        mSamplingDataTracker.stopSampling(s);
-    }
-}
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 5c12696..ab57c9b 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.net.NetworkUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.system.ErrnoException;
@@ -27,22 +26,20 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
-import java.net.ProxySelector;
 import java.net.Socket;
 import java.net.SocketAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.net.URL;
 import java.net.URLConnection;
-import java.net.URLStreamHandler;
-import java.util.concurrent.atomic.AtomicReference;
 import javax.net.SocketFactory;
 
 import com.android.okhttp.ConnectionPool;
-import com.android.okhttp.HostResolver;
 import com.android.okhttp.HttpHandler;
 import com.android.okhttp.HttpsHandler;
 import com.android.okhttp.OkHttpClient;
+import com.android.okhttp.OkUrlFactory;
+import com.android.okhttp.internal.Internal;
 
 /**
  * Identifies a {@code Network}.  This is supplied to applications via
@@ -63,10 +60,10 @@
     // Objects used to perform per-network operations such as getSocketFactory
     // and openConnection, and a lock to protect access to them.
     private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
-    // mLock should be used to control write access to mConnectionPool and mHostResolver.
+    // mLock should be used to control write access to mConnectionPool and mNetwork.
     // maybeInitHttpClient() must be called prior to reading either variable.
     private volatile ConnectionPool mConnectionPool = null;
-    private volatile HostResolver mHostResolver = null;
+    private volatile com.android.okhttp.internal.Network mNetwork = null;
     private Object mLock = new Object();
 
     // Default connection pool values. These are evaluated at startup, just
@@ -220,10 +217,10 @@
     // out) ConnectionPools.
     private void maybeInitHttpClient() {
         synchronized (mLock) {
-            if (mHostResolver == null) {
-                mHostResolver = new HostResolver() {
+            if (mNetwork == null) {
+                mNetwork = new com.android.okhttp.internal.Network() {
                     @Override
-                    public InetAddress[] getAllByName(String host) throws UnknownHostException {
+                    public InetAddress[] resolveInetAddresses(String host) throws UnknownHostException {
                         return Network.this.getAllByName(host);
                     }
                 };
@@ -278,22 +275,25 @@
         if (proxy == null) throw new IllegalArgumentException("proxy is null");
         maybeInitHttpClient();
         String protocol = url.getProtocol();
-        OkHttpClient client;
-        // TODO: HttpHandler creates OkHttpClients that share the default ResponseCache.
+        OkUrlFactory okUrlFactory;
+        // TODO: HttpHandler creates OkUrlFactory instances that share the default ResponseCache.
         // Could this cause unexpected behavior?
         if (protocol.equals("http")) {
-            client = HttpHandler.createHttpOkHttpClient(proxy);
+            okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxy);
         } else if (protocol.equals("https")) {
-            client = HttpsHandler.createHttpsOkHttpClient(proxy);
+            okUrlFactory = HttpsHandler.createHttpsOkUrlFactory(proxy);
         } else {
-            // OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
+            // OkHttp only supports HTTP and HTTPS and returns a null URLStreamHandler if
             // passed another protocol.
             throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
         }
-        return client.setSocketFactory(getSocketFactory())
-                .setHostResolver(mHostResolver)
-                .setConnectionPool(mConnectionPool)
-                .open(url);
+        OkHttpClient client = okUrlFactory.client();
+        client.setSocketFactory(getSocketFactory()).setConnectionPool(mConnectionPool);
+
+        // Use internal APIs to change the Network.
+        Internal.instance.setNetwork(client, mNetwork);
+
+        return okUrlFactory.open(url);
     }
 
     /**
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 74d4ac2..24aaf0d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -21,15 +21,12 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.Log;
 
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
 import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * A Utility class for handling for communicating between bearer-specific
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 64d0fcf..e47220b 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -21,12 +21,9 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
 /**
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 5a09b46..7838b47 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -19,8 +19,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
 /**
  * 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
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
deleted file mode 100644
index c80782c..0000000
--- a/core/java/android/net/NetworkStateTracker.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Messenger;
-
-import static com.android.internal.util.Protocol.BASE_NETWORK_STATE_TRACKER;
-
-/**
- * Interface provides the {@link com.android.server.ConnectivityService}
- * with three services. Events to the ConnectivityService when
- * changes occur, an API for controlling the network and storage
- * for network specific information.
- *
- * The Connectivity will call startMonitoring before any other
- * method is called.
- *
- * {@hide}
- */
-public interface NetworkStateTracker {
-
-    /**
-     * -------------------------------------------------------------
-     * Event Interface back to ConnectivityService.
-     *
-     * The events that are to be sent back to the Handler passed
-     * to startMonitoring when the particular event occurs.
-     * -------------------------------------------------------------
-     */
-
-    /**
-     * The network state has changed and the NetworkInfo object
-     * contains the new state.
-     *
-     * msg.what = EVENT_STATE_CHANGED
-     * msg.obj = NetworkInfo object
-     */
-    public static final int EVENT_STATE_CHANGED = BASE_NETWORK_STATE_TRACKER;
-
-    /**
-     * msg.what = EVENT_CONFIGURATION_CHANGED
-     * msg.obj = NetworkInfo object
-     */
-    public static final int EVENT_CONFIGURATION_CHANGED = BASE_NETWORK_STATE_TRACKER + 1;
-
-    /**
-     * msg.what = EVENT_RESTORE_DEFAULT_NETWORK
-     * msg.obj = FeatureUser object
-     */
-    public static final int EVENT_RESTORE_DEFAULT_NETWORK = BASE_NETWORK_STATE_TRACKER + 2;
-
-    /**
-     * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED
-     * msg.obj = NetworkInfo object
-     */
-    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = BASE_NETWORK_STATE_TRACKER + 3;
-
-    /**
-     * msg.what = EVENT_NETWORK_CONNECTED
-     * msg.obj = LinkProperties object
-     */
-    public static final int EVENT_NETWORK_CONNECTED = BASE_NETWORK_STATE_TRACKER + 4;
-
-    /**
-     * msg.what = EVENT_NETWORK_CONNECTION_DISCONNECTED
-     * msg.obj = LinkProperties object, same iface name
-     */
-    public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
-
-    /**
-     * -------------------------------------------------------------
-     * Control Interface
-     * -------------------------------------------------------------
-     */
-    /**
-     * Begin monitoring data connectivity.
-     *
-     * This is the first method called when this interface is used.
-     *
-     * @param context is the current Android context
-     * @param target is the Hander to which to return the events.
-     */
-    public void startMonitoring(Context context, Handler target);
-
-    /**
-     * Fetch NetworkInfo for the network
-     */
-    public NetworkInfo getNetworkInfo();
-
-    /**
-     * Return the LinkProperties for the connection.
-     *
-     * @return a copy of the LinkProperties, is never null.
-     */
-    public LinkProperties getLinkProperties();
-
-    /**
-     * @return a copy of this connections capabilities, may be empty but never null.
-     */
-    public NetworkCapabilities getNetworkCapabilities();
-
-    /**
-     * Get interesting information about this network link
-     * @return a copy of link information, null if not available
-     */
-    public LinkQualityInfo getLinkQualityInfo();
-
-    /**
-     * Return the system properties name associated with the tcp buffer sizes
-     * for this network.
-     */
-    public String getTcpBufferSizesPropName();
-
-    /**
-     * Disable connectivity to a network
-     * @return {@code true} if a teardown occurred, {@code false} if the
-     * teardown did not occur.
-     */
-    public boolean teardown();
-
-    /**
-     * Reenable connectivity to a network after a {@link #teardown()}.
-     * @return {@code true} if we're connected or expect to be connected
-     */
-    public boolean reconnect();
-
-    /**
-     * Captive portal check has completed
-     */
-    public void captivePortalCheckCompleted(boolean isCaptive);
-
-    /**
-     * Turn the wireless radio off for a network.
-     * @param turnOn {@code true} to turn the radio on, {@code false}
-     */
-    public boolean setRadio(boolean turnOn);
-
-    /**
-     * Returns an indication of whether this network is available for
-     * connections. A value of {@code false} means that some quasi-permanent
-     * condition prevents connectivity to this network.
-     *
-     * NOTE that this is broken on multi-connection devices.  Should be fixed in J release
-     * TODO - fix on multi-pdp devices
-     */
-    public boolean isAvailable();
-
-    /**
-     * User control of data connection through this network, typically persisted
-     * internally.
-     */
-    public void setUserDataEnable(boolean enabled);
-
-    /**
-     * Policy control of data connection through this network, typically not
-     * persisted internally. Usually used when {@link NetworkPolicy#limitBytes}
-     * is passed.
-     */
-    public void setPolicyDataEnable(boolean enabled);
-
-    /**
-     * -------------------------------------------------------------
-     * Storage API used by ConnectivityService for saving
-     * Network specific information.
-     * -------------------------------------------------------------
-     */
-
-    /**
-     * Check if private DNS route is set for the network
-     */
-    public boolean isPrivateDnsRouteSet();
-
-    /**
-     * Set a flag indicating private DNS route is set
-     */
-    public void privateDnsRouteSet(boolean enabled);
-
-    /**
-     * Check if default route is set
-     */
-    public boolean isDefaultRouteSet();
-
-    /**
-     * Set a flag indicating default route is set for the network
-     */
-    public void defaultRouteSet(boolean enabled);
-
-    /**
-     * Check if tear down was requested
-     */
-    public boolean isTeardownRequested();
-
-    /**
-     * Indicate tear down requested from connectivity
-     */
-    public void setTeardownRequested(boolean isRequested);
-
-    /**
-     * An external dependency has been met/unmet
-     */
-    public void setDependencyMet(boolean met);
-
-    /*
-     * Called once to setup async channel between this and
-     * the underlying network specific code.
-     */
-    public void supplyMessenger(Messenger messenger);
-
-    /*
-     * Network interface name that we'll lookup for sampling data
-     */
-    public String getNetworkInterfaceName();
-
-    /*
-     * Save the starting sample
-     */
-    public void startSampling(SamplingDataTracker.SamplingSnapshot s);
-
-    /*
-     * Save the ending sample
-     */
-    public void stopSampling(SamplingDataTracker.SamplingSnapshot s);
-
-    /*
-     * Record the current netId
-     */
-    public void setNetId(int netId);
-
-    /*
-     * ?
-     */
-    public Network getNetwork();
-
-}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 2afe578..0766253 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -19,6 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -42,6 +43,7 @@
  * @hide
  */
 public class NetworkStats implements Parcelable {
+    private static final String TAG = "NetworkStats";
     /** {@link #iface} value when interface details unavailable. */
     public static final String IFACE_ALL = null;
     /** {@link #uid} value when UID details unavailable. */
@@ -783,4 +785,162 @@
         public void foundNonMonotonic(
                 NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
     }
+
+    /**
+     * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface.
+     *
+     * This method should only be called on delta NetworkStats. Do not call this method on a
+     * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may
+     * change over time.
+     *
+     * This method performs adjustments for one active VPN package and one VPN iface at a time.
+     *
+     * It is possible for the VPN software to use multiple underlying networks. This method
+     * only migrates traffic for the primary underlying network.
+     *
+     * @param tunUid uid of the VPN application
+     * @param tunIface iface of the vpn tunnel
+     * @param underlyingIface the primary underlying network iface used by the VPN application
+     * @return true if it successfully adjusts the accounting for VPN, false otherwise
+     */
+    public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) {
+        Entry tunIfaceTotal = new Entry();
+        Entry underlyingIfaceTotal = new Entry();
+
+        tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal);
+
+        // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app.
+        // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression.
+        // Negative stats should be avoided.
+        Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal);
+        if (pool.isEmpty()) {
+            return true;
+        }
+        Entry moved = addTrafficToApplications(tunIface,  underlyingIface, tunIfaceTotal, pool);
+        deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
+
+        if (!moved.isEmpty()) {
+            Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved="
+                    + moved);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Initializes the data used by the migrateTun() method.
+     *
+     * This is the first pass iteration which does the following work:
+     * (1) Adds up all the traffic through tun0.
+     * (2) Adds up all the traffic through the tunUid's underlyingIface
+     *     (both foreground and background).
+     */
+    private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
+            Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
+        Entry recycle = new Entry();
+        for (int i = 0; i < size; i++) {
+            getValues(i, recycle);
+            if (recycle.uid == UID_ALL) {
+                throw new IllegalStateException(
+                        "Cannot adjust VPN accounting on an iface aggregated NetworkStats.");
+            }
+
+            if (recycle.uid == tunUid && recycle.tag == TAG_NONE
+                    && Objects.equals(underlyingIface, recycle.iface)) {
+                underlyingIfaceTotal.add(recycle);
+            }
+
+            if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
+                // Add up all tunIface traffic.
+                tunIfaceTotal.add(recycle);
+            }
+        }
+    }
+
+    private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
+        Entry pool = new Entry();
+        pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes);
+        pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets);
+        pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes);
+        pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets);
+        pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations);
+        return pool;
+    }
+
+    private Entry addTrafficToApplications(String tunIface, String underlyingIface,
+            Entry tunIfaceTotal, Entry pool) {
+        Entry moved = new Entry();
+        Entry tmpEntry = new Entry();
+        tmpEntry.iface = underlyingIface;
+        for (int i = 0; i < size; i++) {
+            if (Objects.equals(iface[i], tunIface)) {
+                if (tunIfaceTotal.rxBytes > 0) {
+                    tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
+                } else {
+                    tmpEntry.rxBytes = 0;
+                }
+                if (tunIfaceTotal.rxPackets > 0) {
+                    tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets;
+                } else {
+                    tmpEntry.rxPackets = 0;
+                }
+                if (tunIfaceTotal.txBytes > 0) {
+                    tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes;
+                } else {
+                    tmpEntry.txBytes = 0;
+                }
+                if (tunIfaceTotal.txPackets > 0) {
+                    tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets;
+                } else {
+                    tmpEntry.txPackets = 0;
+                }
+                if (tunIfaceTotal.operations > 0) {
+                    tmpEntry.operations =
+                            pool.operations * operations[i] / tunIfaceTotal.operations;
+                } else {
+                    tmpEntry.operations = 0;
+                }
+                tmpEntry.uid = uid[i];
+                tmpEntry.tag = tag[i];
+                tmpEntry.set = set[i];
+                combineValues(tmpEntry);
+                if (tag[i] == TAG_NONE) {
+                    moved.add(tmpEntry);
+                }
+            }
+        }
+        return moved;
+    }
+
+    private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) {
+        // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
+        // the TAG_NONE traffic.
+        int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE);
+        if (idxVpnBackground != -1) {
+            tunSubtract(idxVpnBackground, this, moved);
+        }
+
+        int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE);
+        if (idxVpnForeground != -1) {
+            tunSubtract(idxVpnForeground, this, moved);
+        }
+    }
+
+    private static void tunSubtract(int i, NetworkStats left, Entry right) {
+        long rxBytes = Math.min(left.rxBytes[i], right.rxBytes);
+        left.rxBytes[i] -= rxBytes;
+        right.rxBytes -= rxBytes;
+
+        long rxPackets = Math.min(left.rxPackets[i], right.rxPackets);
+        left.rxPackets[i] -= rxPackets;
+        right.rxPackets -= rxPackets;
+
+        long txBytes = Math.min(left.txBytes[i], right.txBytes);
+        left.txBytes[i] -= txBytes;
+        right.txBytes -= txBytes;
+
+        long txPackets = Math.min(left.txPackets[i], right.txPackets);
+        left.txPackets[i] -= txPackets;
+        right.txPackets -= txPackets;
+    }
 }
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index 8626d08..9bdf4f6 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
@@ -74,8 +73,8 @@
         }
         try {
             response = mProxyService.resolvePacFile(uri.getHost(), urlString);
-        } catch (RemoteException e) {
-            e.printStackTrace();
+        } catch (Exception e) {
+            Log.e(TAG, "Error resolving PAC File", e);
         }
         if (response == null) {
             return mDefaultList;
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 3477b02..17a84a7 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -22,8 +22,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import org.apache.http.HttpHost;
-
 import java.net.InetSocketAddress;
 import java.net.ProxySelector;
 import java.net.URI;
@@ -37,8 +35,6 @@
  */
 public final class Proxy {
 
-    // Set to true to enable extra debugging.
-    private static final boolean DEBUG = false;
     private static final String TAG = "Proxy";
 
     private static final ProxySelector sDefaultProxySelector;
@@ -192,31 +188,6 @@
         }
     }
 
-    /**
-     * Returns the preferred proxy to be used by clients. This is a wrapper
-     * around {@link android.net.Proxy#getHost()}.
-     *
-     * @param context the context which will be passed to
-     * {@link android.net.Proxy#getHost()}
-     * @param url the target URL for the request
-     * @note Calling this method requires permission
-     * android.permission.ACCESS_NETWORK_STATE
-     * @return The preferred proxy to be used by clients, or null if there
-     * is no proxy.
-     * {@hide}
-     */
-    // TODO: Get rid of this method. It's used only in tests.
-    public static final HttpHost getPreferredHttpHost(Context context,
-            String url) {
-        java.net.Proxy prefProxy = getProxy(context, url);
-        if (prefProxy.equals(java.net.Proxy.NO_PROXY)) {
-            return null;
-        } else {
-            InetSocketAddress sa = (InetSocketAddress)prefProxy.address();
-            return new HttpHost(sa.getHostName(), sa.getPort(), "http");
-        }
-    }
-
     private static final boolean isLocalHost(String host) {
         if (host == null) {
             return false;
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
deleted file mode 100644
index 7d23125..0000000
--- a/core/java/android/net/ProxyDataTracker.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-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.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A data tracker responsible for bringing up and tearing down the system proxy server.
- *
- * {@hide}
- */
-public class ProxyDataTracker extends BaseNetworkStateTracker {
-    private static final String TAG = "ProxyDataTracker";
-    private static final String NETWORK_TYPE = "PROXY";
-
-    // TODO: investigate how to get these DNS addresses from the system.
-    private static final String DNS1 = "8.8.8.8";
-    private static final String DNS2 = "8.8.4.4";
-    private static final String INTERFACE_NAME = "ifb0";
-    private static final String REASON_ENABLED = "enabled";
-    private static final String REASON_DISABLED = "disabled";
-    private static final String REASON_PROXY_DOWN = "proxy_down";
-
-    private static final int MSG_TEAR_DOWN_REQUEST = 1;
-    private static final int MSG_SETUP_REQUEST = 2;
-
-    private static final String PERMISSION_PROXY_STATUS_SENDER =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
-    private static final String ACTION_PROXY_STATUS_CHANGE =
-            "com.android.net.PROXY_STATUS_CHANGE";
-    private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available";
-    private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder";
-    private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE =
-            "reply_to_messenger_binder_bundle";
-
-    private Handler mTarget;
-    private Messenger mProxyStatusService;
-    private AtomicBoolean mReconnectRequested = new AtomicBoolean(false);
-    private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false);
-    private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
-
-    private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) {
-                mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false));
-                if (mIsProxyAvailable.get()) {
-                    Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE);
-                    if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) {
-                        Log.e(TAG, "no messenger binder in the intent to send future requests");
-                        mIsProxyAvailable.set(false);
-                        return;
-                    }
-                    mProxyStatusService =
-                            new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER));
-                    // If there is a pending reconnect request, do it now.
-                    if (mReconnectRequested.get()) {
-                        reconnect();
-                    }
-                } else {
-                    setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
-                            REASON_PROXY_DOWN, null);
-                }
-            } else {
-                Log.d(TAG, "Unrecognized broadcast intent");
-            }
-        }
-    };
-
-    /**
-     * Create a new ProxyDataTracker
-     */
-    public ProxyDataTracker() {
-        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, "");
-        mLinkProperties = new LinkProperties();
-        mNetworkCapabilities = new NetworkCapabilities();
-        mNetworkInfo.setIsAvailable(true);
-        try {
-            mLinkProperties.addDnsServer(InetAddress.getByName(DNS1));
-            mLinkProperties.addDnsServer(InetAddress.getByName(DNS2));
-            mLinkProperties.setInterfaceName(INTERFACE_NAME);
-        } catch (UnknownHostException e) {
-            Log.e(TAG, "Could not add DNS address", e);
-        }
-    }
-
-    @Override
-    public Object clone() throws CloneNotSupportedException {
-        throw new CloneNotSupportedException();
-    }
-
-    @Override
-    public void startMonitoring(Context context, Handler target) {
-        mContext = context;
-        mTarget = target;
-        mContext.registerReceiver(mProxyStatusServiceListener,
-                new IntentFilter(ACTION_PROXY_STATUS_CHANGE),
-                PERMISSION_PROXY_STATUS_SENDER,
-                null);
-    }
-
-    /**
-     * Disable connectivity to the network.
-     */
-    public boolean teardown() {
-        setTeardownRequested(true);
-        mReconnectRequested.set(false);
-        try {
-            if (mIsProxyAvailable.get() && mProxyStatusService != null) {
-                mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST));
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to connect to proxy status service", e);
-            return false;
-        }
-        setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null);
-        return true;
-    }
-
-    /**
-     * Re-enable proxy data connectivity after a {@link #teardown()}.
-     */
-    public boolean reconnect() {
-        mReconnectRequested.set(true);
-        setTeardownRequested(false);
-        if (!mIsProxyAvailable.get()) {
-            Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing.");
-            return false;
-        }
-        setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null);
-
-        try {
-            mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST));
-        } catch (RemoteException e) {
-            Log.e(TAG, "Unable to connect to proxy status service", e);
-            setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null);
-            return false;
-        }
-        // We'll assume proxy is set up successfully. If not, a status change broadcast will be
-        // received afterwards to indicate any failure.
-        setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null);
-        return true;
-    }
-
-    /**
-     * Fetch default gateway address for the network
-     */
-    public int getDefaultGatewayAddr() {
-        return mDefaultGatewayAddr.get();
-    }
-
-    /**
-     * Return the system properties name associated with the tcp buffer sizes
-     * for this network.
-     */
-    public String getTcpBufferSizesPropName() {
-        return "net.tcp.buffersize.wifi";
-    }
-
-    /**
-     * Record the detailed state of a network, and if it is a
-     * change from the previous state, send a notification to
-     * any listeners.
-     * @param state the new @{code DetailedState}
-     * @param reason a {@code String} indicating a reason for the state change,
-     * if one was supplied. May be {@code null}.
-     * @param extraInfo optional {@code String} providing extra information about the state change
-     */
-    private void setDetailedState(NetworkInfo.DetailedState state, String reason,
-            String extraInfo) {
-        mNetworkInfo.setDetailedState(state, reason, extraInfo);
-        Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-        msg.sendToTarget();
-    }
-}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index a3cad77..2c90909 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -21,8 +21,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import org.apache.http.client.HttpClient;
-
 import java.net.InetSocketAddress;
 import java.net.URLConnection;
 import java.util.List;
@@ -31,8 +29,9 @@
 /**
  * Describes a proxy configuration.
  *
- * Proxy configurations are already integrated within the Apache HTTP stack.
- * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ * Proxy configurations are already integrated within the {@code java.net} and
+ * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use
+ * them automatically.
  *
  * Other HTTP stacks will need to obtain the proxy info from
  * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index c15e6e5..27096b1 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -159,6 +159,8 @@
      *     instead. The Apache HTTP client is no longer maintained and may be removed in a future
      *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
      *     for further details.
+     *
+     * @removed
      */
     @Deprecated
     public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
@@ -208,7 +210,7 @@
     private SSLSocketFactory makeSocketFactory(
             KeyManager[] keyManagers, TrustManager[] trustManagers) {
         try {
-            OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
+            OpenSSLContextImpl sslContext = OpenSSLContextImpl.getPreferred();
             sslContext.engineInit(keyManagers, trustManagers, null);
             sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
             return sslContext.engineGetSocketFactory();
diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java
deleted file mode 100644
index acd56f2..0000000
--- a/core/java/android/net/SamplingDataTracker.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-
-import android.os.SystemClock;
-import android.util.Slog;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * @hide
- */
-public class SamplingDataTracker
-{
-    private static final boolean DBG = false;
-    private static final String  TAG = "SamplingDataTracker";
-
-    public static class SamplingSnapshot
-    {
-        public long mTxByteCount;
-        public long mRxByteCount;
-        public long mTxPacketCount;
-        public long mRxPacketCount;
-        public long mTxPacketErrorCount;
-        public long mRxPacketErrorCount;
-        public long mTimestamp;
-    }
-
-    public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) {
-
-        BufferedReader reader = null;
-        try {
-            reader = new BufferedReader(new FileReader("/proc/net/dev"));
-
-            // Skip over the line bearing column titles (there are 2 lines)
-            String line;
-            reader.readLine();
-            reader.readLine();
-
-            while ((line = reader.readLine()) != null) {
-
-                // remove leading whitespace
-                line = line.trim();
-
-                String[] tokens = line.split("[ ]+");
-                if (tokens.length < 17) {
-                    continue;
-                }
-
-                /* column format is
-                 * Interface  (Recv)bytes packets errs drop fifo frame compressed multicast \
-                 *            (Transmit)bytes packets errs drop fifo colls carrier compress
-                */
-
-                String currentIface = tokens[0].split(":")[0];
-                if (DBG) Slog.d(TAG, "Found data for interface " + currentIface);
-                if (mapIfaceToSample.containsKey(currentIface)) {
-
-                    try {
-                        SamplingSnapshot ss = new SamplingSnapshot();
-
-                        ss.mTxByteCount        = Long.parseLong(tokens[1]);
-                        ss.mTxPacketCount      = Long.parseLong(tokens[2]);
-                        ss.mTxPacketErrorCount = Long.parseLong(tokens[3]);
-                        ss.mRxByteCount        = Long.parseLong(tokens[9]);
-                        ss.mRxPacketCount      = Long.parseLong(tokens[10]);
-                        ss.mRxPacketErrorCount = Long.parseLong(tokens[11]);
-
-                        ss.mTimestamp          = SystemClock.elapsedRealtime();
-
-                        if (DBG) {
-                            Slog.d(TAG, "Interface = " + currentIface);
-                            Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount));
-                            Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount));
-                            Slog.d(TAG, "TxPacketErrorCount = "
-                                    + String.valueOf(ss.mTxPacketErrorCount));
-                            Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount));
-                            Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount));
-                            Slog.d(TAG, "RxPacketErrorCount = "
-                                    + String.valueOf(ss.mRxPacketErrorCount));
-                            Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp));
-                            Slog.d(TAG, "---------------------------");
-                        }
-
-                        mapIfaceToSample.put(currentIface, ss);
-
-                    } catch (NumberFormatException e) {
-                        // just ignore this data point
-                    }
-                }
-            }
-
-            if (DBG) {
-                Iterator it = mapIfaceToSample.entrySet().iterator();
-                while (it.hasNext()) {
-                    Map.Entry kvpair = (Map.Entry)it.next();
-                    if (kvpair.getValue() == null) {
-                        Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey());
-                    }
-                }
-            }
-        } catch(FileNotFoundException e) {
-            Slog.e(TAG, "could not find /proc/net/dev");
-        } catch (IOException e) {
-            Slog.e(TAG, "could not read /proc/net/dev");
-        } finally {
-            try {
-                if (reader != null) {
-                    reader.close();
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "could not close /proc/net/dev");
-            }
-        }
-    }
-
-    // Snapshots from previous sampling interval
-    private SamplingSnapshot mBeginningSample;
-    private SamplingSnapshot mEndingSample;
-
-    // Starting snapshot of current interval
-    private SamplingSnapshot mLastSample;
-
-    // Protects sampling data from concurrent access
-    public final Object mSamplingDataLock = new Object();
-
-    // We need long enough time for a good sample
-    private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000;
-
-    // statistics is useless unless we have enough data
-    private final int MINIMUM_SAMPLED_PACKETS   = 30;
-
-    public void startSampling(SamplingSnapshot s) {
-        synchronized(mSamplingDataLock) {
-            mLastSample = s;
-        }
-    }
-
-    public void stopSampling(SamplingSnapshot s) {
-        synchronized(mSamplingDataLock) {
-            if (mLastSample != null) {
-                if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL
-                        && getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) {
-                    mBeginningSample = mLastSample;
-                    mEndingSample = s;
-                    mLastSample = null;
-                } else {
-                    if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small");
-                }
-            }
-        }
-    }
-
-    public void resetSamplingData() {
-        if (DBG) Slog.d(TAG, "Resetting sampled network data");
-        synchronized(mSamplingDataLock) {
-
-            // We could just take another sample here and treat it as an
-            // 'ending sample' effectively shortening sampling interval, but that
-            // requires extra work (specifically, reading the sample needs to be
-            // done asynchronously)
-
-            mLastSample = null;
-        }
-    }
-
-    public long getSampledTxByteCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampledTxPacketCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampledTxPacketErrorCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampledRxByteCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampledRxPacketCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampledPacketCount() {
-        return getSampledPacketCount(mBeginningSample, mEndingSample);
-    }
-
-    public long getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) {
-        if (begin != null && end != null) {
-            long rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount;
-            long txPacketCount = end.mTxPacketCount - begin.mTxPacketCount;
-            return rxPacketCount + txPacketCount;
-        } else {
-            return LinkQualityInfo.UNKNOWN_LONG;
-        }
-    }
-
-    public long getSampledPacketErrorCount() {
-        if (mBeginningSample != null && mEndingSample != null) {
-            long rxPacketErrorCount = getSampledRxPacketErrorCount();
-            long txPacketErrorCount = getSampledTxPacketErrorCount();
-            return rxPacketErrorCount + txPacketErrorCount;
-        } else {
-            return LinkQualityInfo.UNKNOWN_LONG;
-        }
-    }
-
-    public long getSampledRxPacketErrorCount() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public long getSampleTimestamp() {
-        synchronized(mSamplingDataLock) {
-            if (mEndingSample != null) {
-                return mEndingSample.mTimestamp;
-            } else {
-                return LinkQualityInfo.UNKNOWN_LONG;
-            }
-        }
-    }
-
-    public int getSampleDuration() {
-        synchronized(mSamplingDataLock) {
-            if (mBeginningSample != null && mEndingSample != null) {
-                return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp);
-            } else {
-                return LinkQualityInfo.UNKNOWN_INT;
-            }
-        }
-    }
-
-    public void setCommonLinkQualityInfoFields(LinkQualityInfo li) {
-        synchronized(mSamplingDataLock) {
-            li.setLastDataSampleTime(getSampleTimestamp());
-            li.setDataSampleDuration(getSampleDuration());
-            li.setPacketCount(getSampledPacketCount());
-            li.setPacketErrorCount(getSampledPacketErrorCount());
-        }
-    }
-}
-
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 365f2b6..7f1b179 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -21,7 +21,6 @@
 import android.os.Parcel;
 
 import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -188,6 +187,7 @@
         for (InetAddress dnsServer : dnsServers) {
             NetworkUtils.parcelInetAddress(dest, dnsServer, flags);
         }
+        dest.writeString(domains);
     }
 
     protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
@@ -198,5 +198,6 @@
         for (int i = 0; i < size; i++) {
             s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
         }
+        s.domains = in.readString();
     }
 }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 2099c3f..bf3d9aa 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,6 +366,7 @@
     public String toSafeString() {
         String scheme = getScheme();
         String ssp = getSchemeSpecificPart();
+        String authority = null;
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -384,6 +385,9 @@
                     }
                 }
                 return builder.toString();
+            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
+                ssp = null;
+                authority = "//" + getAuthority() + "/...";
             }
         }
         // Not a sensitive scheme, but let's still be conservative about
@@ -397,6 +401,9 @@
         if (ssp != null) {
             builder.append(ssp);
         }
+        if (authority != null) {
+            builder.append(authority);
+        }
         return builder.toString();
     }
 
@@ -1742,7 +1749,7 @@
      *
      * @return normalized Uri (never null)
      * @see {@link android.content.Intent#setData}
-     * @see {@link #setNormalizedData}
+     * @see {@link android.content.Intent#setDataAndNormalize}
      */
     public Uri normalizeScheme() {
         String scheme = getScheme();
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
deleted file mode 100644
index a262076..0000000
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import com.android.internal.http.HttpDateTime;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.RequestWrapper;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.BasicHttpProcessor;
-import org.apache.http.protocol.HttpContext;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.SSLCertificateSocketFactory;
-import android.net.SSLSessionCache;
-import android.os.Looper;
-import android.util.Base64;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-/**
- * Implementation of the Apache {@link DefaultHttpClient} that is configured with
- * reasonable default settings and registered schemes for Android.
- * Don't create this directly, use the {@link #newInstance} factory method.
- *
- * <p>This client processes cookies but does not retain them by default.
- * To retain cookies, simply add a cookie store to the HttpContext:</p>
- *
- * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- *     The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
- */
-@Deprecated
-public final class AndroidHttpClient implements HttpClient {
-
-    // Gzip of data shorter than this probably won't be worthwhile
-    public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
-
-    // Default connection and socket timeout of 60 seconds.  Tweak to taste.
-    private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;
-
-    private static final String TAG = "AndroidHttpClient";
-
-    private static String[] textContentTypes = new String[] {
-            "text/",
-            "application/xml",
-            "application/json"
-    };
-
-    /** Interceptor throws an exception if the executing thread is blocked */
-    private static final HttpRequestInterceptor sThreadCheckInterceptor =
-            new HttpRequestInterceptor() {
-        public void process(HttpRequest request, HttpContext context) {
-            // Prevent the HttpRequest from being sent on the main thread
-            if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) {
-                throw new RuntimeException("This thread forbids HTTP requests");
-            }
-        }
-    };
-
-    /**
-     * Create a new HttpClient with reasonable defaults (which you can update).
-     *
-     * @param userAgent to report in your HTTP requests
-     * @param context to use for caching SSL sessions (may be null for no caching)
-     * @return AndroidHttpClient for you to use for all your requests.
-     *
-     * @deprecated Please use {@link java.net.URLConnection} and friends instead. See
-     *     {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd
-     *     like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)}
-     *     with {@code field} set to {@code User-Agent}.
-     */
-    @Deprecated
-    public static AndroidHttpClient newInstance(String userAgent, Context context) {
-        HttpParams params = new BasicHttpParams();
-
-        // Turn off stale checking.  Our connections break all the time anyway,
-        // and it's not worth it to pay the penalty of checking every time.
-        HttpConnectionParams.setStaleCheckingEnabled(params, false);
-
-        HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
-        HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
-        HttpConnectionParams.setSocketBufferSize(params, 8192);
-
-        // Don't handle redirects -- return them to the caller.  Our code
-        // often wants to re-POST after a redirect, which we must do ourselves.
-        HttpClientParams.setRedirecting(params, false);
-
-        // Use a session cache for SSL sockets
-        SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);
-
-        // Set the specified user agent and register standard protocols.
-        HttpProtocolParams.setUserAgent(params, userAgent);
-        SchemeRegistry schemeRegistry = new SchemeRegistry();
-        schemeRegistry.register(new Scheme("http",
-                PlainSocketFactory.getSocketFactory(), 80));
-        schemeRegistry.register(new Scheme("https",
-                SSLCertificateSocketFactory.getHttpSocketFactory(
-                SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
-
-        ClientConnectionManager manager =
-                new ThreadSafeClientConnManager(params, schemeRegistry);
-
-        // We use a factory method to modify superclass initialization
-        // parameters without the funny call-a-static-method dance.
-        return new AndroidHttpClient(manager, params);
-    }
-
-    /**
-     * Create a new HttpClient with reasonable defaults (which you can update).
-     * @param userAgent to report in your HTTP requests.
-     * @return AndroidHttpClient for you to use for all your requests.
-     *
-     * @deprecated Please use {@link java.net.URLConnection} and friends instead. See
-     *     {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd
-     *     like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)}
-     *     with {@code field} set to {@code User-Agent}.
-     */
-    @Deprecated
-    public static AndroidHttpClient newInstance(String userAgent) {
-        return newInstance(userAgent, null /* session cache */);
-    }
-
-    private final HttpClient delegate;
-
-    private RuntimeException mLeakedException = new IllegalStateException(
-            "AndroidHttpClient created and never closed");
-
-    private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
-        this.delegate = new DefaultHttpClient(ccm, params) {
-            @Override
-            protected BasicHttpProcessor createHttpProcessor() {
-                // Add interceptor to prevent making requests from main thread.
-                BasicHttpProcessor processor = super.createHttpProcessor();
-                processor.addRequestInterceptor(sThreadCheckInterceptor);
-                processor.addRequestInterceptor(new CurlLogger());
-
-                return processor;
-            }
-
-            @Override
-            protected HttpContext createHttpContext() {
-                // Same as DefaultHttpClient.createHttpContext() minus the
-                // cookie store.
-                HttpContext context = new BasicHttpContext();
-                context.setAttribute(
-                        ClientContext.AUTHSCHEME_REGISTRY,
-                        getAuthSchemes());
-                context.setAttribute(
-                        ClientContext.COOKIESPEC_REGISTRY,
-                        getCookieSpecs());
-                context.setAttribute(
-                        ClientContext.CREDS_PROVIDER,
-                        getCredentialsProvider());
-                return context;
-            }
-        };
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        super.finalize();
-        if (mLeakedException != null) {
-            Log.e(TAG, "Leak found", mLeakedException);
-            mLeakedException = null;
-        }
-    }
-
-    /**
-     * Modifies a request to indicate to the server that we would like a
-     * gzipped response.  (Uses the "Accept-Encoding" HTTP header.)
-     * @param request the request to modify
-     * @see #getUngzippedContent
-     */
-    public static void modifyRequestToAcceptGzipResponse(HttpRequest request) {
-        request.addHeader("Accept-Encoding", "gzip");
-    }
-
-    /**
-     * Gets the input stream from a response entity.  If the entity is gzipped
-     * then this will get a stream over the uncompressed data.
-     *
-     * @param entity the entity whose content should be read
-     * @return the input stream to read from
-     * @throws IOException
-     */
-    public static InputStream getUngzippedContent(HttpEntity entity)
-            throws IOException {
-        InputStream responseStream = entity.getContent();
-        if (responseStream == null) return responseStream;
-        Header header = entity.getContentEncoding();
-        if (header == null) return responseStream;
-        String contentEncoding = header.getValue();
-        if (contentEncoding == null) return responseStream;
-        if (contentEncoding.contains("gzip")) responseStream
-                = new GZIPInputStream(responseStream);
-        return responseStream;
-    }
-
-    /**
-     * Release resources associated with this client.  You must call this,
-     * or significant resources (sockets and memory) may be leaked.
-     */
-    public void close() {
-        if (mLeakedException != null) {
-            getConnectionManager().shutdown();
-            mLeakedException = null;
-        }
-    }
-
-    public HttpParams getParams() {
-        return delegate.getParams();
-    }
-
-    public ClientConnectionManager getConnectionManager() {
-        return delegate.getConnectionManager();
-    }
-
-    public HttpResponse execute(HttpUriRequest request) throws IOException {
-        return delegate.execute(request);
-    }
-
-    public HttpResponse execute(HttpUriRequest request, HttpContext context)
-            throws IOException {
-        return delegate.execute(request, context);
-    }
-
-    public HttpResponse execute(HttpHost target, HttpRequest request)
-            throws IOException {
-        return delegate.execute(target, request);
-    }
-
-    public HttpResponse execute(HttpHost target, HttpRequest request,
-            HttpContext context) throws IOException {
-        return delegate.execute(target, request, context);
-    }
-
-    public <T> T execute(HttpUriRequest request,
-            ResponseHandler<? extends T> responseHandler)
-            throws IOException, ClientProtocolException {
-        return delegate.execute(request, responseHandler);
-    }
-
-    public <T> T execute(HttpUriRequest request,
-            ResponseHandler<? extends T> responseHandler, HttpContext context)
-            throws IOException, ClientProtocolException {
-        return delegate.execute(request, responseHandler, context);
-    }
-
-    public <T> T execute(HttpHost target, HttpRequest request,
-            ResponseHandler<? extends T> responseHandler) throws IOException,
-            ClientProtocolException {
-        return delegate.execute(target, request, responseHandler);
-    }
-
-    public <T> T execute(HttpHost target, HttpRequest request,
-            ResponseHandler<? extends T> responseHandler, HttpContext context)
-            throws IOException, ClientProtocolException {
-        return delegate.execute(target, request, responseHandler, context);
-    }
-
-    /**
-     * Compress data to send to server.
-     * Creates a Http Entity holding the gzipped data.
-     * The data will not be compressed if it is too short.
-     * @param data The bytes to compress
-     * @return Entity holding the data
-     */
-    public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver)
-            throws IOException {
-        AbstractHttpEntity entity;
-        if (data.length < getMinGzipSize(resolver)) {
-            entity = new ByteArrayEntity(data);
-        } else {
-            ByteArrayOutputStream arr = new ByteArrayOutputStream();
-            OutputStream zipper = new GZIPOutputStream(arr);
-            zipper.write(data);
-            zipper.close();
-            entity = new ByteArrayEntity(arr.toByteArray());
-            entity.setContentEncoding("gzip");
-        }
-        return entity;
-    }
-
-    /**
-     * Retrieves the minimum size for compressing data.
-     * Shorter data will not be compressed.
-     */
-    public static long getMinGzipSize(ContentResolver resolver) {
-        return DEFAULT_SYNC_MIN_GZIP_BYTES;  // For now, this is just a constant.
-    }
-
-    /* cURL logging support. */
-
-    /**
-     * Logging tag and level.
-     */
-    private static class LoggingConfiguration {
-
-        private final String tag;
-        private final int level;
-
-        private LoggingConfiguration(String tag, int level) {
-            this.tag = tag;
-            this.level = level;
-        }
-
-        /**
-         * Returns true if logging is turned on for this configuration.
-         */
-        private boolean isLoggable() {
-            return Log.isLoggable(tag, level);
-        }
-
-        /**
-         * Prints a message using this configuration.
-         */
-        private void println(String message) {
-            Log.println(level, tag, message);
-        }
-    }
-
-    /** cURL logging configuration. */
-    private volatile LoggingConfiguration curlConfiguration;
-
-    /**
-     * Enables cURL request logging for this client.
-     *
-     * @param name to log messages with
-     * @param level at which to log messages (see {@link android.util.Log})
-     */
-    public void enableCurlLogging(String name, int level) {
-        if (name == null) {
-            throw new NullPointerException("name");
-        }
-        if (level < Log.VERBOSE || level > Log.ASSERT) {
-            throw new IllegalArgumentException("Level is out of range ["
-                + Log.VERBOSE + ".." + Log.ASSERT + "]");
-        }
-
-        curlConfiguration = new LoggingConfiguration(name, level);
-    }
-
-    /**
-     * Disables cURL logging for this client.
-     */
-    public void disableCurlLogging() {
-        curlConfiguration = null;
-    }
-
-    /**
-     * Logs cURL commands equivalent to requests.
-     */
-    private class CurlLogger implements HttpRequestInterceptor {
-        public void process(HttpRequest request, HttpContext context)
-                throws HttpException, IOException {
-            LoggingConfiguration configuration = curlConfiguration;
-            if (configuration != null
-                    && configuration.isLoggable()
-                    && request instanceof HttpUriRequest) {
-                // Never print auth token -- we used to check ro.secure=0 to
-                // enable that, but can't do that in unbundled code.
-                configuration.println(toCurl((HttpUriRequest) request, false));
-            }
-        }
-    }
-
-    /**
-     * Generates a cURL command equivalent to the given request.
-     */
-    private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
-        StringBuilder builder = new StringBuilder();
-
-        builder.append("curl ");
-
-        // add in the method
-        builder.append("-X ");
-        builder.append(request.getMethod());
-        builder.append(" ");
-
-        for (Header header: request.getAllHeaders()) {
-            if (!logAuthToken
-                    && (header.getName().equals("Authorization") ||
-                        header.getName().equals("Cookie"))) {
-                continue;
-            }
-            builder.append("--header \"");
-            builder.append(header.toString().trim());
-            builder.append("\" ");
-        }
-
-        URI uri = request.getURI();
-
-        // If this is a wrapped request, use the URI from the original
-        // request instead. getURI() on the wrapper seems to return a
-        // relative URI. We want an absolute URI.
-        if (request instanceof RequestWrapper) {
-            HttpRequest original = ((RequestWrapper) request).getOriginal();
-            if (original instanceof HttpUriRequest) {
-                uri = ((HttpUriRequest) original).getURI();
-            }
-        }
-
-        builder.append("\"");
-        builder.append(uri);
-        builder.append("\"");
-
-        if (request instanceof HttpEntityEnclosingRequest) {
-            HttpEntityEnclosingRequest entityRequest =
-                    (HttpEntityEnclosingRequest) request;
-            HttpEntity entity = entityRequest.getEntity();
-            if (entity != null && entity.isRepeatable()) {
-                if (entity.getContentLength() < 1024) {
-                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
-                    entity.writeTo(stream);
-
-                    if (isBinaryContent(request)) {
-                        String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP);
-                        builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ");
-                        builder.append(" --data-binary @/tmp/$$.bin");
-                    } else {
-                        String entityString = stream.toString();
-                        builder.append(" --data-ascii \"")
-                                .append(entityString)
-                                .append("\"");
-                    }
-                } else {
-                    builder.append(" [TOO MUCH DATA TO INCLUDE]");
-                }
-            }
-        }
-
-        return builder.toString();
-    }
-
-    private static boolean isBinaryContent(HttpUriRequest request) {
-        Header[] headers;
-        headers = request.getHeaders(Headers.CONTENT_ENCODING);
-        if (headers != null) {
-            for (Header header : headers) {
-                if ("gzip".equalsIgnoreCase(header.getValue())) {
-                    return true;
-                }
-            }
-        }
-
-        headers = request.getHeaders(Headers.CONTENT_TYPE);
-        if (headers != null) {
-            for (Header header : headers) {
-                for (String contentType : textContentTypes) {
-                    if (header.getValue().startsWith(contentType)) {
-                        return false;
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Returns the date of the given HTTP date string. This method can identify
-     * and parse the date formats emitted by common HTTP servers, such as
-     * <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>,
-     * <a href="http://www.ietf.org/rfc/rfc0850.txt">RFC 850</a>,
-     * <a href="http://www.ietf.org/rfc/rfc1036.txt">RFC 1036</a>,
-     * <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a> and
-     * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/asctime.html">ANSI
-     * C's asctime()</a>.
-     *
-     * @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
-     * @throws IllegalArgumentException if {@code dateString} is not a date or
-     *     of an unsupported format.
-     */
-    public static long parseDate(String dateString) {
-        return HttpDateTime.parse(dateString);
-    }
-}
diff --git a/core/java/android/net/http/AndroidHttpClientConnection.java b/core/java/android/net/http/AndroidHttpClientConnection.java
deleted file mode 100644
index 6d48fce..0000000
--- a/core/java/android/net/http/AndroidHttpClientConnection.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import org.apache.http.HttpConnection;
-import org.apache.http.HttpClientConnection;
-import org.apache.http.HttpConnectionMetrics;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpInetConnection;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.NoHttpResponseException;
-import org.apache.http.StatusLine;
-import org.apache.http.entity.BasicHttpEntity;
-import org.apache.http.entity.ContentLengthStrategy;
-import org.apache.http.impl.HttpConnectionMetricsImpl;
-import org.apache.http.impl.entity.EntitySerializer;
-import org.apache.http.impl.entity.StrictContentLengthStrategy;
-import org.apache.http.impl.io.ChunkedInputStream;
-import org.apache.http.impl.io.ContentLengthInputStream;
-import org.apache.http.impl.io.HttpRequestWriter;
-import org.apache.http.impl.io.IdentityInputStream;
-import org.apache.http.impl.io.SocketInputBuffer;
-import org.apache.http.impl.io.SocketOutputBuffer;
-import org.apache.http.io.HttpMessageWriter;
-import org.apache.http.io.SessionInputBuffer;
-import org.apache.http.io.SessionOutputBuffer;
-import org.apache.http.message.BasicLineParser;
-import org.apache.http.message.ParserCursor;
-import org.apache.http.params.CoreConnectionPNames;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.ParseException;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketException;
-
-/**
- * A alternate class for (@link DefaultHttpClientConnection).
- * It has better performance than DefaultHttpClientConnection
- * 
- * {@hide}
- */
-public class AndroidHttpClientConnection
-        implements HttpInetConnection, HttpConnection {
-
-    private SessionInputBuffer inbuffer = null;
-    private SessionOutputBuffer outbuffer = null;
-    private int maxHeaderCount;
-    // store CoreConnectionPNames.MAX_LINE_LENGTH for performance
-    private int maxLineLength;
-
-    private final EntitySerializer entityserializer;
-
-    private HttpMessageWriter requestWriter = null;
-    private HttpConnectionMetricsImpl metrics = null;
-    private volatile boolean open;
-    private Socket socket = null;
-
-    public AndroidHttpClientConnection() {
-        this.entityserializer =  new EntitySerializer(
-                new StrictContentLengthStrategy());
-    }
-
-    /**
-     * Bind socket and set HttpParams to AndroidHttpClientConnection
-     * @param socket outgoing socket
-     * @param params HttpParams
-     * @throws IOException
-      */
-    public void bind(
-            final Socket socket,
-            final HttpParams params) throws IOException {
-        if (socket == null) {
-            throw new IllegalArgumentException("Socket may not be null");
-        }
-        if (params == null) {
-            throw new IllegalArgumentException("HTTP parameters may not be null");
-        }
-        assertNotOpen();
-        socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
-        socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
-
-        int linger = HttpConnectionParams.getLinger(params);
-        if (linger >= 0) {
-            socket.setSoLinger(linger > 0, linger);
-        }
-        this.socket = socket;
-
-        int buffersize = HttpConnectionParams.getSocketBufferSize(params);
-        this.inbuffer = new SocketInputBuffer(socket, buffersize, params);
-        this.outbuffer = new SocketOutputBuffer(socket, buffersize, params);
-
-        maxHeaderCount = params.getIntParameter(
-                CoreConnectionPNames.MAX_HEADER_COUNT, -1);
-        maxLineLength = params.getIntParameter(
-                CoreConnectionPNames.MAX_LINE_LENGTH, -1);
-
-        this.requestWriter = new HttpRequestWriter(outbuffer, null, params);
-
-        this.metrics = new HttpConnectionMetricsImpl(
-                inbuffer.getMetrics(),
-                outbuffer.getMetrics());
-
-        this.open = true;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder buffer = new StringBuilder();
-        buffer.append(getClass().getSimpleName()).append("[");
-        if (isOpen()) {
-            buffer.append(getRemotePort());
-        } else {
-            buffer.append("closed");
-        }
-        buffer.append("]");
-        return buffer.toString();
-    }
-
-
-    private void assertNotOpen() {
-        if (this.open) {
-            throw new IllegalStateException("Connection is already open");
-        }
-    }
-
-    private void assertOpen() {
-        if (!this.open) {
-            throw new IllegalStateException("Connection is not open");
-        }
-    }
-
-    public boolean isOpen() {
-        // to make this method useful, we want to check if the socket is connected
-        return (this.open && this.socket != null && this.socket.isConnected());
-    }
-
-    public InetAddress getLocalAddress() {
-        if (this.socket != null) {
-            return this.socket.getLocalAddress();
-        } else {
-            return null;
-        }
-    }
-
-    public int getLocalPort() {
-        if (this.socket != null) {
-            return this.socket.getLocalPort();
-        } else {
-            return -1;
-        }
-    }
-
-    public InetAddress getRemoteAddress() {
-        if (this.socket != null) {
-            return this.socket.getInetAddress();
-        } else {
-            return null;
-        }
-    }
-
-    public int getRemotePort() {
-        if (this.socket != null) {
-            return this.socket.getPort();
-        } else {
-            return -1;
-        }
-    }
-
-    public void setSocketTimeout(int timeout) {
-        assertOpen();
-        if (this.socket != null) {
-            try {
-                this.socket.setSoTimeout(timeout);
-            } catch (SocketException ignore) {
-                // It is not quite clear from the original documentation if there are any
-                // other legitimate cases for a socket exception to be thrown when setting
-                // SO_TIMEOUT besides the socket being already closed
-            }
-        }
-    }
-
-    public int getSocketTimeout() {
-        if (this.socket != null) {
-            try {
-                return this.socket.getSoTimeout();
-            } catch (SocketException ignore) {
-                return -1;
-            }
-        } else {
-            return -1;
-        }
-    }
-
-    public void shutdown() throws IOException {
-        this.open = false;
-        Socket tmpsocket = this.socket;
-        if (tmpsocket != null) {
-            tmpsocket.close();
-        }
-    }
-
-    public void close() throws IOException {
-        if (!this.open) {
-            return;
-        }
-        this.open = false;
-        doFlush();
-        try {
-            try {
-                this.socket.shutdownOutput();
-            } catch (IOException ignore) {
-            }
-            try {
-                this.socket.shutdownInput();
-            } catch (IOException ignore) {
-            }
-        } catch (UnsupportedOperationException ignore) {
-            // if one isn't supported, the other one isn't either
-        }
-        this.socket.close();
-    }
-
-    /**
-     * Sends the request line and all headers over the connection.
-     * @param request the request whose headers to send.
-     * @throws HttpException
-     * @throws IOException
-     */
-    public void sendRequestHeader(final HttpRequest request)
-            throws HttpException, IOException {
-        if (request == null) {
-            throw new IllegalArgumentException("HTTP request may not be null");
-        }
-        assertOpen();
-        this.requestWriter.write(request);
-        this.metrics.incrementRequestCount();
-    }
-
-    /**
-     * Sends the request entity over the connection.
-     * @param request the request whose entity to send.
-     * @throws HttpException
-     * @throws IOException
-     */
-    public void sendRequestEntity(final HttpEntityEnclosingRequest request)
-            throws HttpException, IOException {
-        if (request == null) {
-            throw new IllegalArgumentException("HTTP request may not be null");
-        }
-        assertOpen();
-        if (request.getEntity() == null) {
-            return;
-        }
-        this.entityserializer.serialize(
-                this.outbuffer,
-                request,
-                request.getEntity());
-    }
-
-    protected void doFlush() throws IOException {
-        this.outbuffer.flush();
-    }
-
-    public void flush() throws IOException {
-        assertOpen();
-        doFlush();
-    }
-
-    /**
-     * Parses the response headers and adds them to the
-     * given {@code headers} object, and returns the response StatusLine
-     * @param headers store parsed header to headers.
-     * @throws IOException
-     * @return StatusLine
-     * @see HttpClientConnection#receiveResponseHeader()
-      */
-    public StatusLine parseResponseHeader(Headers headers)
-            throws IOException, ParseException {
-        assertOpen();
-
-        CharArrayBuffer current = new CharArrayBuffer(64);
-
-        if (inbuffer.readLine(current) == -1) {
-            throw new NoHttpResponseException("The target server failed to respond");
-        }
-
-        // Create the status line from the status string
-        StatusLine statusline = BasicLineParser.DEFAULT.parseStatusLine(
-                current, new ParserCursor(0, current.length()));
-        
-        if (HttpLog.LOGV) HttpLog.v("read: " + statusline);
-        int statusCode = statusline.getStatusCode();
-
-        // Parse header body
-        CharArrayBuffer previous = null;
-        int headerNumber = 0;
-        while(true) {
-            if (current == null) {
-                current = new CharArrayBuffer(64);
-            } else {
-                // This must be he buffer used to parse the status
-                current.clear();
-            }
-            int l = inbuffer.readLine(current);
-            if (l == -1 || current.length() < 1) {
-                break;
-            }
-            // Parse the header name and value
-            // Check for folded headers first
-            // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
-            // discussion on folded headers
-            char first = current.charAt(0);
-            if ((first == ' ' || first == '\t') && previous != null) {
-                // we have continuation folded header
-                // so append value
-                int start = 0;
-                int length = current.length();
-                while (start < length) {
-                    char ch = current.charAt(start);
-                    if (ch != ' ' && ch != '\t') {
-                        break;
-                    }
-                    start++;
-                }
-                if (maxLineLength > 0 &&
-                        previous.length() + 1 + current.length() - start >
-                            maxLineLength) {
-                    throw new IOException("Maximum line length limit exceeded");
-                }
-                previous.append(' ');
-                previous.append(current, start, current.length() - start);
-            } else {
-                if (previous != null) {
-                    headers.parseHeader(previous);
-                }
-                headerNumber++;
-                previous = current;
-                current = null;
-            }
-            if (maxHeaderCount > 0 && headerNumber >= maxHeaderCount) {
-                throw new IOException("Maximum header count exceeded");
-            }
-        }
-
-        if (previous != null) {
-            headers.parseHeader(previous);
-        }
-
-        if (statusCode >= 200) {
-            this.metrics.incrementResponseCount();
-        }
-        return statusline;
-    }
-
-    /**
-     * Return the next response entity.
-     * @param headers contains values for parsing entity
-     * @see HttpClientConnection#receiveResponseEntity(HttpResponse response)
-     */
-    public HttpEntity receiveResponseEntity(final Headers headers) {
-        assertOpen();
-        BasicHttpEntity entity = new BasicHttpEntity();
-
-        long len = determineLength(headers);
-        if (len == ContentLengthStrategy.CHUNKED) {
-            entity.setChunked(true);
-            entity.setContentLength(-1);
-            entity.setContent(new ChunkedInputStream(inbuffer));
-        } else if (len == ContentLengthStrategy.IDENTITY) {
-            entity.setChunked(false);
-            entity.setContentLength(-1);
-            entity.setContent(new IdentityInputStream(inbuffer));
-        } else {
-            entity.setChunked(false);
-            entity.setContentLength(len);
-            entity.setContent(new ContentLengthInputStream(inbuffer, len));
-        }
-
-        String contentTypeHeader = headers.getContentType();
-        if (contentTypeHeader != null) {
-            entity.setContentType(contentTypeHeader);
-        }
-        String contentEncodingHeader = headers.getContentEncoding();
-        if (contentEncodingHeader != null) {
-            entity.setContentEncoding(contentEncodingHeader);
-        }
-
-       return entity;
-    }
-
-    private long determineLength(final Headers headers) {
-        long transferEncoding = headers.getTransferEncoding();
-        // We use Transfer-Encoding if present and ignore Content-Length.
-        // RFC2616, 4.4 item number 3
-        if (transferEncoding < Headers.NO_TRANSFER_ENCODING) {
-            return transferEncoding;
-        } else {
-            long contentlen = headers.getContentLength();
-            if (contentlen > Headers.NO_CONTENT_LENGTH) {
-                return contentlen;
-            } else {
-                return ContentLengthStrategy.IDENTITY;
-            }
-        }
-    }
-
-    /**
-     * Checks whether this connection has gone down.
-     * Network connections may get closed during some time of inactivity
-     * for several reasons. The next time a read is attempted on such a
-     * connection it will throw an IOException.
-     * This method tries to alleviate this inconvenience by trying to
-     * find out if a connection is still usable. Implementations may do
-     * that by attempting a read with a very small timeout. Thus this
-     * method may block for a small amount of time before returning a result.
-     * It is therefore an <i>expensive</i> operation.
-     *
-     * @return  <code>true</code> if attempts to use this connection are
-     *          likely to succeed, or <code>false</code> if they are likely
-     *          to fail and this connection should be closed
-     */
-    public boolean isStale() {
-        assertOpen();
-        try {
-            this.inbuffer.isDataAvailable(1);
-            return false;
-        } catch (IOException ex) {
-            return true;
-        }
-    }
-
-    /**
-     * Returns a collection of connection metrcis
-     * @return HttpConnectionMetrics
-     */
-    public HttpConnectionMetrics getMetrics() {
-        return this.metrics;
-    }
-}
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
deleted file mode 100644
index bf3fe02..0000000
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import com.android.org.conscrypt.SSLParametersImpl;
-import com.android.org.conscrypt.TrustManagerImpl;
-
-import android.util.Slog;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * Class responsible for all server certificate validation functionality
- *
- * {@hide}
- */
-public class CertificateChainValidator {
-    private static final String TAG = "CertificateChainValidator";
-
-    private static class NoPreloadHolder {
-        /**
-         * The singleton instance of the certificate chain validator.
-         */
-        private static final CertificateChainValidator sInstance = new CertificateChainValidator();
-
-        /**
-         * The singleton instance of the hostname verifier.
-         */
-        private static final HostnameVerifier sVerifier = HttpsURLConnection
-                .getDefaultHostnameVerifier();
-    }
-
-    private X509TrustManager mTrustManager;
-
-    /**
-     * @return The singleton instance of the certificates chain validator
-     */
-    public static CertificateChainValidator getInstance() {
-        return NoPreloadHolder.sInstance;
-    }
-
-    /**
-     * Creates a new certificate chain validator. This is a private constructor.
-     * If you need a Certificate chain validator, call getInstance().
-     */
-    private CertificateChainValidator() {
-        try {
-            TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
-            tmf.init((KeyStore) null);
-            for (TrustManager tm : tmf.getTrustManagers()) {
-                if (tm instanceof X509TrustManager) {
-                    mTrustManager = (X509TrustManager) tm;
-                }
-            }
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
-        } catch (KeyStoreException e) {
-            throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
-        }
-
-        if (mTrustManager == null) {
-            throw new RuntimeException(
-                    "None of the X.509 TrustManagers are X509TrustManager");
-        }
-    }
-
-    /**
-     * Performs the handshake and server certificates validation
-     * Notice a new chain will be rebuilt by tracing the issuer and subject
-     * before calling checkServerTrusted().
-     * And if the last traced certificate is self issued and it is expired, it
-     * will be dropped.
-     * @param sslSocket The secure connection socket
-     * @param domain The website domain
-     * @return An SSL error object if there is an error and null otherwise
-     */
-    public SslError doHandshakeAndValidateServerCertificates(
-            HttpsConnection connection, SSLSocket sslSocket, String domain)
-            throws IOException {
-        // get a valid SSLSession, close the socket if we fail
-        SSLSession sslSession = sslSocket.getSession();
-        if (!sslSession.isValid()) {
-            closeSocketThrowException(sslSocket, "failed to perform SSL handshake");
-        }
-
-        // retrieve the chain of the server peer certificates
-        Certificate[] peerCertificates =
-            sslSocket.getSession().getPeerCertificates();
-
-        if (peerCertificates == null || peerCertificates.length == 0) {
-            closeSocketThrowException(
-                sslSocket, "failed to retrieve peer certificates");
-        } else {
-            // update the SSL certificate associated with the connection
-            if (connection != null) {
-                if (peerCertificates[0] != null) {
-                    connection.setCertificate(
-                        new SslCertificate((X509Certificate)peerCertificates[0]));
-                }
-            }
-        }
-
-        return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
-    }
-
-    /**
-     * Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use
-     * by Chromium HTTPS stack to validate the cert chain.
-     * @param certChain The bytes for certificates in ASN.1 DER encoded certificates format.
-     * @param domain The full website hostname and domain
-     * @param authType The authentication type for the cert chain
-     * @return An SSL error object if there is an error and null otherwise
-     */
-    public static SslError verifyServerCertificates(
-        byte[][] certChain, String domain, String authType)
-        throws IOException {
-
-        if (certChain == null || certChain.length == 0) {
-            throw new IllegalArgumentException("bad certificate chain");
-        }
-
-        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
-
-        try {
-            CertificateFactory cf = CertificateFactory.getInstance("X.509");
-            for (int i = 0; i < certChain.length; ++i) {
-                serverCertificates[i] = (X509Certificate) cf.generateCertificate(
-                        new ByteArrayInputStream(certChain[i]));
-            }
-        } catch (CertificateException e) {
-            throw new IOException("can't read certificate", e);
-        }
-
-        return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
-    }
-
-    /**
-     * Handles updates to credential storage.
-     */
-    public static void handleTrustStorageUpdate() {
-        TrustManagerFactory tmf;
-        try {
-            tmf = TrustManagerFactory.getInstance("X.509");
-            tmf.init((KeyStore) null);
-        } catch (NoSuchAlgorithmException e) {
-            Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
-            return;
-        } catch (KeyStoreException e) {
-            Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
-            return;
-        }
-
-        TrustManager[] tms = tmf.getTrustManagers();
-        boolean sentUpdate = false;
-        for (TrustManager tm : tms) {
-            try {
-                Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
-                updateMethod.setAccessible(true);
-                updateMethod.invoke(tm);
-                sentUpdate = true;
-            } catch (Exception e) {
-            }
-        }
-        if (!sentUpdate) {
-            Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
-        }
-    }
-
-    /**
-     * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
-     * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
-     * @param chain the cert chain in X509 cert format.
-     * @param domain The full website hostname and domain
-     * @param authType The authentication type for the cert chain
-     * @return An SSL error object if there is an error and null otherwise
-     */
-    private static SslError verifyServerDomainAndCertificates(
-            X509Certificate[] chain, String domain, String authType)
-            throws IOException {
-        // check if the first certificate in the chain is for this site
-        X509Certificate currCertificate = chain[0];
-        if (currCertificate == null) {
-            throw new IllegalArgumentException("certificate for this site is null");
-        }
-
-        boolean valid = domain != null
-                && !domain.isEmpty()
-                && NoPreloadHolder.sVerifier.verify(domain,
-                        new DelegatingSSLSession.CertificateWrap(currCertificate));
-        if (!valid) {
-            if (HttpLog.LOGV) {
-                HttpLog.v("certificate not for this host: " + domain);
-            }
-            return new SslError(SslError.SSL_IDMISMATCH, currCertificate);
-        }
-
-        try {
-            X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
-            if (x509TrustManager instanceof TrustManagerImpl) {
-                TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
-                trustManager.checkServerTrusted(chain, authType, domain);
-            } else {
-                x509TrustManager.checkServerTrusted(chain, authType);
-            }
-            return null;  // No errors.
-        } catch (GeneralSecurityException e) {
-            if (HttpLog.LOGV) {
-                HttpLog.v("failed to validate the certificate chain, error: " +
-                    e.getMessage());
-            }
-            return new SslError(SslError.SSL_UNTRUSTED, currCertificate);
-        }
-    }
-
-    /**
-     * Returns the platform default {@link X509TrustManager}.
-     */
-    private X509TrustManager getTrustManager() {
-        return mTrustManager;
-    }
-
-    private void closeSocketThrowException(
-            SSLSocket socket, String errorMessage, String defaultErrorMessage)
-            throws IOException {
-        closeSocketThrowException(
-            socket, errorMessage != null ? errorMessage : defaultErrorMessage);
-    }
-
-    private void closeSocketThrowException(SSLSocket socket,
-            String errorMessage) throws IOException {
-        if (HttpLog.LOGV) {
-            HttpLog.v("validation error: " + errorMessage);
-        }
-
-        if (socket != null) {
-            SSLSession session = socket.getSession();
-            if (session != null) {
-                session.invalidate();
-            }
-
-            socket.close();
-        }
-
-        throw new SSLHandshakeException(errorMessage);
-    }
-}
diff --git a/core/java/android/net/http/CharArrayBuffers.java b/core/java/android/net/http/CharArrayBuffers.java
deleted file mode 100644
index 77d45f6..0000000
--- a/core/java/android/net/http/CharArrayBuffers.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import org.apache.http.util.CharArrayBuffer;
-import org.apache.http.protocol.HTTP;
-
-/**
- * Utility methods for working on CharArrayBuffers.
- * 
- * {@hide}
- */
-class CharArrayBuffers {
-
-    static final char uppercaseAddon = 'a' - 'A';
-
-    /**
-     * Returns true if the buffer contains the given string. Ignores leading
-     * whitespace and case.
-     *
-     * @param buffer to search
-     * @param beginIndex index at which we should start
-     * @param str to search for
-     */
-    static boolean containsIgnoreCaseTrimmed(CharArrayBuffer buffer,
-            int beginIndex, final String str) {
-        int len = buffer.length();
-        char[] chars = buffer.buffer();
-        while (beginIndex < len && HTTP.isWhitespace(chars[beginIndex])) {
-            beginIndex++;
-        }
-        int size = str.length();
-        boolean ok = len >= beginIndex + size;
-        for (int j=0; ok && (j<size); j++) {
-            char a = chars[beginIndex+j];
-            char b = str.charAt(j);
-            if (a != b) {
-                a = toLower(a);
-                b = toLower(b);
-                ok = a == b;
-            }
-        }
-        return ok;
-    }
-
-    /**
-     * Returns index of first occurence ch. Lower cases characters leading up
-     * to first occurrence of ch.
-     */
-    static int setLowercaseIndexOf(CharArrayBuffer buffer, final int ch) {
-
-        int beginIndex = 0;
-        int endIndex = buffer.length();
-        char[] chars = buffer.buffer();
-
-        for (int i = beginIndex; i < endIndex; i++) {
-            char current = chars[i];
-            if (current == ch) {
-                return i;
-            } else if (current >= 'A' && current <= 'Z'){
-                // make lower case
-                current += uppercaseAddon;
-                chars[i] = current;
-            }
-        }
-        return -1;
-    }
-
-    private static char toLower(char c) {
-        if (c >= 'A' && c <= 'Z'){
-            c += uppercaseAddon;
-        }
-        return c;
-    }
-}
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
deleted file mode 100644
index 834ad69..0000000
--- a/core/java/android/net/http/Connection.java
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.util.LinkedList;
-
-import javax.net.ssl.SSLHandshakeException;
-
-import org.apache.http.ConnectionReuseStrategy;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpVersion;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.BasicHttpContext;
-
-/**
- * {@hide}
- */
-abstract class Connection {
-
-    /**
-     * Allow a TCP connection 60 idle seconds before erroring out
-     */
-    static final int SOCKET_TIMEOUT = 60000;
-
-    private static final int SEND = 0;
-    private static final int READ = 1;
-    private static final int DRAIN = 2;
-    private static final int DONE = 3;
-    private static final String[] states = {"SEND",  "READ", "DRAIN", "DONE"};
-
-    Context mContext;
-
-    /** The low level connection */
-    protected AndroidHttpClientConnection mHttpClientConnection = null;
-
-    /**
-     * The server SSL certificate associated with this connection
-     * (null if the connection is not secure)
-     * It would be nice to store the whole certificate chain, but
-     * we want to keep things as light-weight as possible
-     */
-    protected SslCertificate mCertificate = null;
-
-    /**
-     * The host this connection is connected to.  If using proxy,
-     * this is set to the proxy address
-     */
-    HttpHost mHost;
-
-    /** true if the connection can be reused for sending more requests */
-    private boolean mCanPersist;
-
-    /** context required by ConnectionReuseStrategy. */
-    private HttpContext mHttpContext;
-
-    /** set when cancelled */
-    private static int STATE_NORMAL = 0;
-    private static int STATE_CANCEL_REQUESTED = 1;
-    private int mActive = STATE_NORMAL;
-
-    /** The number of times to try to re-connect (if connect fails). */
-    private final static int RETRY_REQUEST_LIMIT = 2;
-
-    private static final int MIN_PIPE = 2;
-    private static final int MAX_PIPE = 3;
-
-    /**
-     * Doesn't seem to exist anymore in the new HTTP client, so copied here.
-     */
-    private static final String HTTP_CONNECTION = "http.connection";
-
-    RequestFeeder mRequestFeeder;
-
-    /**
-     * Buffer for feeding response blocks to webkit.  One block per
-     * connection reduces memory churn.
-     */
-    private byte[] mBuf;
-
-    protected Connection(Context context, HttpHost host,
-                         RequestFeeder requestFeeder) {
-        mContext = context;
-        mHost = host;
-        mRequestFeeder = requestFeeder;
-
-        mCanPersist = false;
-        mHttpContext = new BasicHttpContext(null);
-    }
-
-    HttpHost getHost() {
-        return mHost;
-    }
-
-    /**
-     * connection factory: returns an HTTP or HTTPS connection as
-     * necessary
-     */
-    static Connection getConnection(
-            Context context, HttpHost host, HttpHost proxy,
-            RequestFeeder requestFeeder) {
-
-        if (host.getSchemeName().equals("http")) {
-            return new HttpConnection(context, host, requestFeeder);
-        }
-
-        // Otherwise, default to https
-        return new HttpsConnection(context, host, proxy, requestFeeder);
-    }
-
-    /**
-     * @return The server SSL certificate associated with this
-     * connection (null if the connection is not secure)
-     */
-    /* package */ SslCertificate getCertificate() {
-        return mCertificate;
-    }
-
-    /**
-     * Close current network connection
-     * Note: this runs in non-network thread
-     */
-    void cancel() {
-        mActive = STATE_CANCEL_REQUESTED;
-        closeConnection();
-        if (HttpLog.LOGV) HttpLog.v(
-            "Connection.cancel(): connection closed " + mHost);
-    }
-
-    /**
-     * Process requests in queue
-     * pipelines requests
-     */
-    void processRequests(Request firstRequest) {
-        Request req = null;
-        boolean empty;
-        int error = EventHandler.OK;
-        Exception exception = null;
-
-        LinkedList<Request> pipe = new LinkedList<Request>();
-
-        int minPipe = MIN_PIPE, maxPipe = MAX_PIPE;
-        int state = SEND;
-
-        while (state != DONE) {
-            if (HttpLog.LOGV) HttpLog.v(
-                    states[state] + " pipe " + pipe.size());
-
-            /* If a request was cancelled, give other cancel requests
-               some time to go through so we don't uselessly restart
-               connections */
-            if (mActive == STATE_CANCEL_REQUESTED) {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException x) { /* ignore */ }
-                mActive = STATE_NORMAL;
-            }
-
-            switch (state) {
-                case SEND: {
-                    if (pipe.size() == maxPipe) {
-                        state = READ;
-                        break;
-                    }
-                    /* get a request */
-                    if (firstRequest == null) {
-                        req = mRequestFeeder.getRequest(mHost);
-                    } else {
-                        req = firstRequest;
-                        firstRequest = null;
-                    }
-                    if (req == null) {
-                        state = DRAIN;
-                        break;
-                    }
-                    req.setConnection(this);
-
-                    /* Don't work on cancelled requests. */
-                    if (req.mCancelled) {
-                        if (HttpLog.LOGV) HttpLog.v(
-                                "processRequests(): skipping cancelled request "
-                                + req);
-                        req.complete();
-                        break;
-                    }
-
-                    if (mHttpClientConnection == null ||
-                        !mHttpClientConnection.isOpen()) {
-                        /* If this call fails, the address is bad or
-                           the net is down.  Punt for now.
-
-                           FIXME: blow out entire queue here on
-                           connection failure if net up? */
-
-                        if (!openHttpConnection(req)) {
-                            state = DONE;
-                            break;
-                        }
-                    }
-
-                    /* we have a connection, let the event handler
-                     * know of any associated certificate,
-                     * potentially none.
-                     */
-                    req.mEventHandler.certificate(mCertificate);
-
-                    try {
-                        /* FIXME: don't increment failure count if old
-                           connection?  There should not be a penalty for
-                           attempting to reuse an old connection */
-                        req.sendRequest(mHttpClientConnection);
-                    } catch (HttpException e) {
-                        exception = e;
-                        error = EventHandler.ERROR;
-                    } catch (IOException e) {
-                        exception = e;
-                        error = EventHandler.ERROR_IO;
-                    } catch (IllegalStateException e) {
-                        exception = e;
-                        error = EventHandler.ERROR_IO;
-                    }
-                    if (exception != null) {
-                        if (httpFailure(req, error, exception) &&
-                            !req.mCancelled) {
-                            /* retry request if not permanent failure
-                               or cancelled */
-                            pipe.addLast(req);
-                        }
-                        exception = null;
-                        state = clearPipe(pipe) ? DONE : SEND;
-                        minPipe = maxPipe = 1;
-                        break;
-                    }
-
-                    pipe.addLast(req);
-                    if (!mCanPersist) state = READ;
-                    break;
-
-                }
-                case DRAIN:
-                case READ: {
-                    empty = !mRequestFeeder.haveRequest(mHost);
-                    int pipeSize = pipe.size();
-                    if (state != DRAIN && pipeSize < minPipe &&
-                        !empty && mCanPersist) {
-                        state = SEND;
-                        break;
-                    } else if (pipeSize == 0) {
-                        /* Done if no other work to do */
-                        state = empty ? DONE : SEND;
-                        break;
-                    }
-
-                    req = (Request)pipe.removeFirst();
-                    if (HttpLog.LOGV) HttpLog.v(
-                            "processRequests() reading " + req);
-
-                    try {
-                        req.readResponse(mHttpClientConnection);
-                    } catch (ParseException e) {
-                        exception = e;
-                        error = EventHandler.ERROR_IO;
-                    } catch (IOException e) {
-                        exception = e;
-                        error = EventHandler.ERROR_IO;
-                    } catch (IllegalStateException e) {
-                        exception = e;
-                        error = EventHandler.ERROR_IO;
-                    }
-                    if (exception != null) {
-                        if (httpFailure(req, error, exception) &&
-                            !req.mCancelled) {
-                            /* retry request if not permanent failure
-                               or cancelled */
-                            req.reset();
-                            pipe.addFirst(req);
-                        }
-                        exception = null;
-                        mCanPersist = false;
-                    }
-                    if (!mCanPersist) {
-                        if (HttpLog.LOGV) HttpLog.v(
-                                "processRequests(): no persist, closing " +
-                                mHost);
-
-                        closeConnection();
-
-                        mHttpContext.removeAttribute(HTTP_CONNECTION);
-                        clearPipe(pipe);
-                        minPipe = maxPipe = 1;
-                        state = SEND;
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    /**
-     * After a send/receive failure, any pipelined requests must be
-     * cleared back to the mRequest queue
-     * @return true if mRequests is empty after pipe cleared
-     */
-    private boolean clearPipe(LinkedList<Request> pipe) {
-        boolean empty = true;
-        if (HttpLog.LOGV) HttpLog.v(
-                "Connection.clearPipe(): clearing pipe " + pipe.size());
-        synchronized (mRequestFeeder) {
-            Request tReq;
-            while (!pipe.isEmpty()) {
-                tReq = (Request)pipe.removeLast();
-                if (HttpLog.LOGV) HttpLog.v(
-                        "clearPipe() adding back " + mHost + " " + tReq);
-                mRequestFeeder.requeueRequest(tReq);
-                empty = false;
-            }
-            if (empty) empty = !mRequestFeeder.haveRequest(mHost);
-        }
-        return empty;
-    }
-
-    /**
-     * @return true on success
-     */
-    private boolean openHttpConnection(Request req) {
-
-        long now = SystemClock.uptimeMillis();
-        int error = EventHandler.OK;
-        Exception exception = null;
-
-        try {
-            // reset the certificate to null before opening a connection
-            mCertificate = null;
-            mHttpClientConnection = openConnection(req);
-            if (mHttpClientConnection != null) {
-                mHttpClientConnection.setSocketTimeout(SOCKET_TIMEOUT);
-                mHttpContext.setAttribute(HTTP_CONNECTION,
-                                          mHttpClientConnection);
-            } else {
-                // we tried to do SSL tunneling, failed,
-                // and need to drop the request;
-                // we have already informed the handler
-                req.mFailCount = RETRY_REQUEST_LIMIT;
-                return false;
-            }
-        } catch (UnknownHostException e) {
-            if (HttpLog.LOGV) HttpLog.v("Failed to open connection");
-            error = EventHandler.ERROR_LOOKUP;
-            exception = e;
-        } catch (IllegalArgumentException e) {
-            if (HttpLog.LOGV) HttpLog.v("Illegal argument exception");
-            error = EventHandler.ERROR_CONNECT;
-            req.mFailCount = RETRY_REQUEST_LIMIT;
-            exception = e;
-        } catch (SSLConnectionClosedByUserException e) {
-            // hack: if we have an SSL connection failure,
-            // we don't want to reconnect
-            req.mFailCount = RETRY_REQUEST_LIMIT;
-            // no error message
-            return false;
-        } catch (SSLHandshakeException e) {
-            // hack: if we have an SSL connection failure,
-            // we don't want to reconnect
-            req.mFailCount = RETRY_REQUEST_LIMIT;
-            if (HttpLog.LOGV) HttpLog.v(
-                    "SSL exception performing handshake");
-            error = EventHandler.ERROR_FAILED_SSL_HANDSHAKE;
-            exception = e;
-        } catch (IOException e) {
-            error = EventHandler.ERROR_CONNECT;
-            exception = e;
-        }
-
-        if (HttpLog.LOGV) {
-            long now2 = SystemClock.uptimeMillis();
-            HttpLog.v("Connection.openHttpConnection() " +
-                      (now2 - now) + " " + mHost);
-        }
-
-        if (error == EventHandler.OK) {
-            return true;
-        } else {
-            if (req.mFailCount < RETRY_REQUEST_LIMIT) {
-                // requeue
-                mRequestFeeder.requeueRequest(req);
-                req.mFailCount++;
-            } else {
-                httpFailure(req, error, exception);
-            }
-            return error == EventHandler.OK;
-        }
-    }
-
-    /**
-     * Helper.  Calls the mEventHandler's error() method only if
-     * request failed permanently.  Increments mFailcount on failure.
-     *
-     * Increments failcount only if the network is believed to be
-     * connected
-     *
-     * @return true if request can be retried (less than
-     * RETRY_REQUEST_LIMIT failures have occurred).
-     */
-    private boolean httpFailure(Request req, int errorId, Exception e) {
-        boolean ret = true;
-
-        // e.printStackTrace();
-        if (HttpLog.LOGV) HttpLog.v(
-                "httpFailure() ******* " + e + " count " + req.mFailCount +
-                " " + mHost + " " + req.getUri());
-
-        if (++req.mFailCount >= RETRY_REQUEST_LIMIT) {
-            ret = false;
-            String error;
-            if (errorId < 0) {
-                error = ErrorStrings.getString(errorId, mContext);
-            } else {
-                Throwable cause = e.getCause();
-                error = cause != null ? cause.toString() : e.getMessage();
-            }
-            req.mEventHandler.error(errorId, error);
-            req.complete();
-        }
-
-        closeConnection();
-        mHttpContext.removeAttribute(HTTP_CONNECTION);
-
-        return ret;
-    }
-
-    HttpContext getHttpContext() {
-        return mHttpContext;
-    }
-
-    /**
-     * Use same logic as ConnectionReuseStrategy
-     * @see ConnectionReuseStrategy
-     */
-    private boolean keepAlive(HttpEntity entity,
-            ProtocolVersion ver, int connType, final HttpContext context) {
-        org.apache.http.HttpConnection conn = (org.apache.http.HttpConnection)
-            context.getAttribute(ExecutionContext.HTTP_CONNECTION);
-
-        if (conn != null && !conn.isOpen())
-            return false;
-        // do NOT check for stale connection, that is an expensive operation
-
-        if (entity != null) {
-            if (entity.getContentLength() < 0) {
-                if (!entity.isChunked() || ver.lessEquals(HttpVersion.HTTP_1_0)) {
-                    // if the content length is not known and is not chunk
-                    // encoded, the connection cannot be reused
-                    return false;
-                }
-            }
-        }
-        // Check for 'Connection' directive
-        if (connType == Headers.CONN_CLOSE) {
-            return false;
-        } else if (connType == Headers.CONN_KEEP_ALIVE) {
-            return true;
-        }
-        // Resorting to protocol version default close connection policy
-        return !ver.lessEquals(HttpVersion.HTTP_1_0);
-    }
-
-    void setCanPersist(HttpEntity entity, ProtocolVersion ver, int connType) {
-        mCanPersist = keepAlive(entity, ver, connType, mHttpContext);
-    }
-
-    void setCanPersist(boolean canPersist) {
-        mCanPersist = canPersist;
-    }
-
-    boolean getCanPersist() {
-        return mCanPersist;
-    }
-
-    /** typically http or https... set by subclass */
-    abstract String getScheme();
-    abstract void closeConnection();
-    abstract AndroidHttpClientConnection openConnection(Request req) throws IOException;
-
-    /**
-     * Prints request queue to log, for debugging.
-     * returns request count
-     */
-    public synchronized String toString() {
-        return mHost.toString();
-    }
-
-    byte[] getBuf() {
-        if (mBuf == null) mBuf = new byte[8192];
-        return mBuf;
-    }
-
-}
diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
deleted file mode 100644
index d825530..0000000
--- a/core/java/android/net/http/ConnectionThread.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import java.lang.Thread;
-
-/**
- * {@hide}
- */
-class ConnectionThread extends Thread {
-
-    static final int WAIT_TIMEOUT = 5000;
-    static final int WAIT_TICK = 1000;
-
-    // Performance probe
-    long mCurrentThreadTime;
-    long mTotalThreadTime;
-
-    private boolean mWaiting;
-    private volatile boolean mRunning = true;
-    private Context mContext;
-    private RequestQueue.ConnectionManager mConnectionManager;
-    private RequestFeeder mRequestFeeder;
-
-    private int mId;
-    Connection mConnection;
-
-    ConnectionThread(Context context,
-                     int id,
-                     RequestQueue.ConnectionManager connectionManager,
-                     RequestFeeder requestFeeder) {
-        super();
-        mContext = context;
-        setName("http" + id);
-        mId = id;
-        mConnectionManager = connectionManager;
-        mRequestFeeder = requestFeeder;
-    }
-
-    void requestStop() {
-        synchronized (mRequestFeeder) {
-            mRunning = false;
-            mRequestFeeder.notify();
-        }
-    }
-
-    /**
-     * Loop until app shutdown. Runs connections in priority
-     * order.
-     */
-    public void run() {
-        android.os.Process.setThreadPriority(
-                android.os.Process.THREAD_PRIORITY_DEFAULT +
-                android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
-
-        // these are used to get performance data. When it is not in the timing,
-        // mCurrentThreadTime is 0. When it starts timing, mCurrentThreadTime is
-        // first set to -1, it will be set to the current thread time when the
-        // next request starts.
-        mCurrentThreadTime = 0;
-        mTotalThreadTime = 0;
-
-        while (mRunning) {
-            if (mCurrentThreadTime == -1) {
-                mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
-            }
-
-            Request request;
-
-            /* Get a request to process */
-            request = mRequestFeeder.getRequest();
-
-            /* wait for work */
-            if (request == null) {
-                synchronized(mRequestFeeder) {
-                    if (HttpLog.LOGV) HttpLog.v("ConnectionThread: Waiting for work");
-                    mWaiting = true;
-                    try {
-                        mRequestFeeder.wait();
-                    } catch (InterruptedException e) {
-                    }
-                    mWaiting = false;
-                    if (mCurrentThreadTime != 0) {
-                        mCurrentThreadTime = SystemClock
-                                .currentThreadTimeMillis();
-                    }
-                }
-            } else {
-                if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
-                                            request.mHost + " " + request );
-
-                mConnection = mConnectionManager.getConnection(mContext,
-                        request.mHost);
-                mConnection.processRequests(request);
-                if (mConnection.getCanPersist()) {
-                    if (!mConnectionManager.recycleConnection(mConnection)) {
-                        mConnection.closeConnection();
-                    }
-                } else {
-                    mConnection.closeConnection();
-                }
-                mConnection = null;
-
-                if (mCurrentThreadTime > 0) {
-                    long start = mCurrentThreadTime;
-                    mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
-                    mTotalThreadTime += mCurrentThreadTime - start;
-                }
-            }
-
-        }
-    }
-
-    public synchronized String toString() {
-        String con = mConnection == null ? "" : mConnection.toString();
-        String active = mWaiting ? "w" : "a";
-        return "cid " + mId + " " + active + " "  + con;
-    }
-
-}
diff --git a/core/java/android/net/http/DelegatingSSLSession.java b/core/java/android/net/http/DelegatingSSLSession.java
deleted file mode 100644
index 98fbe21..0000000
--- a/core/java/android/net/http/DelegatingSSLSession.java
+++ /dev/null
@@ -1,158 +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.net.http;
-
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * This is only used when a {@code certificate} is available but usage
- * requires a {@link SSLSession}.
- *
- * @hide
- */
-public class DelegatingSSLSession implements SSLSession {
-    protected DelegatingSSLSession() {
-    }
-
-    public static class CertificateWrap extends DelegatingSSLSession {
-        private final Certificate mCertificate;
-
-        public CertificateWrap(Certificate certificate) {
-            mCertificate = certificate;
-        }
-
-        @Override
-        public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-            return new Certificate[] { mCertificate };
-        }
-    }
-
-
-    @Override
-    public int getApplicationBufferSize() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getCipherSuite() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public long getCreationTime() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public byte[] getId() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public long getLastAccessedTime() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Certificate[] getLocalCertificates() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Principal getLocalPrincipal() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getPacketBufferSize() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public javax.security.cert.X509Certificate[] getPeerCertificateChain()
-            throws SSLPeerUnverifiedException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getPeerHost() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getPeerPort() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getProtocol() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public SSLSessionContext getSessionContext() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Object getValue(String name) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String[] getValueNames() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void invalidate() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isValid() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void putValue(String name, Object value) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void removeValue(String name) {
-        throw new UnsupportedOperationException();
-    }
-}
diff --git a/core/java/android/net/http/ErrorStrings.java b/core/java/android/net/http/ErrorStrings.java
deleted file mode 100644
index 8383681..0000000
--- a/core/java/android/net/http/ErrorStrings.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.util.Log;
-
-/**
- * Localized strings for the error codes defined in EventHandler.
- *
- * {@hide}
- */
-public class ErrorStrings {
-    private ErrorStrings() { /* Utility class, don't instantiate. */ }
-
-    private static final String LOGTAG = "Http";
-
-    /**
-     * Get the localized error message resource for the given error code.
-     * If the code is unknown, we'll return a generic error message.
-     */
-    public static String getString(int errorCode, Context context) {
-        return context.getText(getResource(errorCode)).toString();
-    }
-
-    /**
-     * Get the localized error message resource for the given error code.
-     * If the code is unknown, we'll return a generic error message.
-     */
-    public static int getResource(int errorCode) {
-        switch(errorCode) {
-            case EventHandler.OK:
-                return com.android.internal.R.string.httpErrorOk;
-
-            case EventHandler.ERROR:
-                return com.android.internal.R.string.httpError;
-
-            case EventHandler.ERROR_LOOKUP:
-                return com.android.internal.R.string.httpErrorLookup;
-
-            case EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME:
-                return com.android.internal.R.string.httpErrorUnsupportedAuthScheme;
-
-            case EventHandler.ERROR_AUTH:
-                return com.android.internal.R.string.httpErrorAuth;
-
-            case EventHandler.ERROR_PROXYAUTH:
-                return com.android.internal.R.string.httpErrorProxyAuth;
-
-            case EventHandler.ERROR_CONNECT:
-                return com.android.internal.R.string.httpErrorConnect;
-
-            case EventHandler.ERROR_IO:
-                return com.android.internal.R.string.httpErrorIO;
-
-            case EventHandler.ERROR_TIMEOUT:
-                return com.android.internal.R.string.httpErrorTimeout;
-
-            case EventHandler.ERROR_REDIRECT_LOOP:
-                return com.android.internal.R.string.httpErrorRedirectLoop;
-
-            case EventHandler.ERROR_UNSUPPORTED_SCHEME:
-                return com.android.internal.R.string.httpErrorUnsupportedScheme;
-
-            case EventHandler.ERROR_FAILED_SSL_HANDSHAKE:
-                return com.android.internal.R.string.httpErrorFailedSslHandshake;
-
-            case EventHandler.ERROR_BAD_URL:
-                return com.android.internal.R.string.httpErrorBadUrl;
-
-            case EventHandler.FILE_ERROR:
-                return com.android.internal.R.string.httpErrorFile;
-
-            case EventHandler.FILE_NOT_FOUND_ERROR:
-                return com.android.internal.R.string.httpErrorFileNotFound;
-
-            case EventHandler.TOO_MANY_REQUESTS_ERROR:
-                return com.android.internal.R.string.httpErrorTooManyRequests;
-
-            default:
-                Log.w(LOGTAG, "Using generic message for unknown error code: " + errorCode);
-                return com.android.internal.R.string.httpError;
-        }
-    }
-}
diff --git a/core/java/android/net/http/EventHandler.java b/core/java/android/net/http/EventHandler.java
deleted file mode 100644
index 3fd471d..0000000
--- a/core/java/android/net/http/EventHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.http;
-
-
-/**
- * Callbacks in this interface are made as an HTTP request is
- * processed. The normal order of callbacks is status(), headers(),
- * then multiple data() then endData().  handleSslErrorRequest(), if
- * there is an SSL certificate error. error() can occur anywhere
- * in the transaction.
- * 
- * {@hide}
- */
-
-public interface EventHandler {
-
-    /**
-     * Error codes used in the error() callback.  Positive error codes
-     * are reserved for codes sent by http servers.  Negative error
-     * codes are connection/parsing failures, etc.
-     */
-
-    /** Success */
-    public static final int OK = 0;
-    /** Generic error */
-    public static final int ERROR = -1;
-    /** Server or proxy hostname lookup failed */
-    public static final int ERROR_LOOKUP = -2;
-    /** Unsupported authentication scheme (ie, not basic or digest) */
-    public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3;
-    /** User authentication failed on server */
-    public static final int ERROR_AUTH = -4;
-    /** User authentication failed on proxy */
-    public static final int ERROR_PROXYAUTH = -5;
-    /** Could not connect to server */
-    public static final int ERROR_CONNECT = -6;
-    /** Failed to write to or read from server */
-    public static final int ERROR_IO = -7;
-    /** Connection timed out */
-    public static final int ERROR_TIMEOUT = -8;
-    /** Too many redirects */
-    public static final int ERROR_REDIRECT_LOOP = -9;
-    /** Unsupported URI scheme (ie, not http, https, etc) */
-    public static final int ERROR_UNSUPPORTED_SCHEME = -10;
-    /** Failed to perform SSL handshake */
-    public static final int ERROR_FAILED_SSL_HANDSHAKE = -11;
-    /** Bad URL */
-    public static final int ERROR_BAD_URL = -12;
-    /** Generic file error for file:/// loads */
-    public static final int FILE_ERROR = -13;
-    /** File not found error for file:/// loads */
-    public static final int FILE_NOT_FOUND_ERROR = -14;
-    /** Too many requests queued */
-    public static final int TOO_MANY_REQUESTS_ERROR = -15;
-
-    /**
-     * Called after status line has been sucessfully processed.
-     * @param major_version HTTP version advertised by server.  major
-     * is the part before the "."
-     * @param minor_version HTTP version advertised by server.  minor
-     * is the part after the "."
-     * @param code HTTP Status code.  See RFC 2616.
-     * @param reason_phrase Textual explanation sent by server
-     */
-    public void status(int major_version,
-                       int minor_version,
-                       int code,
-                       String reason_phrase);
-
-    /**
-     * Called after all headers are successfully processed.
-     */
-    public void headers(Headers headers);
-
-    /**
-     * An array containing all or part of the http body as read from
-     * the server.
-     * @param data A byte array containing the content
-     * @param len The length of valid content in data
-     *
-     * Note: chunked and compressed encodings are handled within
-     * android.net.http.  Decoded data is passed through this
-     * interface.
-     */
-    public void data(byte[] data, int len);
-
-    /**
-     * Called when the document is completely read.  No more data()
-     * callbacks will be made after this call
-     */
-    public void endData();
-
-    /**
-     * SSL certificate callback called before resource request is
-     * made, which will be null for insecure connection.
-     */
-    public void certificate(SslCertificate certificate);
-
-    /**
-     * There was trouble.
-     * @param id One of the error codes defined below
-     * @param description of error
-     */
-    public void error(int id, String description);
-
-    /**
-     * SSL certificate error callback. Handles SSL error(s) on the way
-     * up to the user. The callback has to make sure that restartConnection() is called,
-     * otherwise the connection will be suspended indefinitely.
-     * @return True if the callback can handle the error, which means it will
-     *              call restartConnection() to unblock the thread later,
-     *              otherwise return false.
-     */
-    public boolean handleSslErrorRequest(SslError error);
-
-}
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
deleted file mode 100644
index 657e071..0000000
--- a/core/java/android/net/http/Headers.java
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.http;
-
-import android.util.Log;
-
-import java.util.ArrayList;
-
-import org.apache.http.HeaderElement;
-import org.apache.http.entity.ContentLengthStrategy;
-import org.apache.http.message.BasicHeaderValueParser;
-import org.apache.http.message.ParserCursor;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.CharArrayBuffer;
-
-/**
- * Manages received headers
- *
- * {@hide}
- */
-public final class Headers {
-    private static final String LOGTAG = "Http";
-
-    // header parsing constant
-    /**
-     * indicate HTTP 1.0 connection close after the response
-     */
-    public final static int CONN_CLOSE = 1;
-    /**
-     * indicate HTTP 1.1 connection keep alive
-     */
-    public final static int CONN_KEEP_ALIVE = 2;
-
-    // initial values.
-    public final static int NO_CONN_TYPE = 0;
-    public final static long NO_TRANSFER_ENCODING = 0;
-    public final static long NO_CONTENT_LENGTH = -1;
-
-    // header strings
-    public final static String TRANSFER_ENCODING = "transfer-encoding";
-    public final static String CONTENT_LEN = "content-length";
-    public final static String CONTENT_TYPE = "content-type";
-    public final static String CONTENT_ENCODING = "content-encoding";
-    public final static String CONN_DIRECTIVE = "connection";
-
-    public final static String LOCATION = "location";
-    public final static String PROXY_CONNECTION = "proxy-connection";
-
-    public final static String WWW_AUTHENTICATE = "www-authenticate";
-    public final static String PROXY_AUTHENTICATE = "proxy-authenticate";
-    public final static String CONTENT_DISPOSITION = "content-disposition";
-    public final static String ACCEPT_RANGES = "accept-ranges";
-    public final static String EXPIRES = "expires";
-    public final static String CACHE_CONTROL = "cache-control";
-    public final static String LAST_MODIFIED = "last-modified";
-    public final static String ETAG = "etag";
-    public final static String SET_COOKIE = "set-cookie";
-    public final static String PRAGMA = "pragma";
-    public final static String REFRESH = "refresh";
-    public final static String X_PERMITTED_CROSS_DOMAIN_POLICIES = "x-permitted-cross-domain-policies";
-
-    // following hash are generated by String.hashCode()
-    private final static int HASH_TRANSFER_ENCODING = 1274458357;
-    private final static int HASH_CONTENT_LEN = -1132779846;
-    private final static int HASH_CONTENT_TYPE = 785670158;
-    private final static int HASH_CONTENT_ENCODING = 2095084583;
-    private final static int HASH_CONN_DIRECTIVE = -775651618;
-    private final static int HASH_LOCATION = 1901043637;
-    private final static int HASH_PROXY_CONNECTION = 285929373;
-    private final static int HASH_WWW_AUTHENTICATE = -243037365;
-    private final static int HASH_PROXY_AUTHENTICATE = -301767724;
-    private final static int HASH_CONTENT_DISPOSITION = -1267267485;
-    private final static int HASH_ACCEPT_RANGES = 1397189435;
-    private final static int HASH_EXPIRES = -1309235404;
-    private final static int HASH_CACHE_CONTROL = -208775662;
-    private final static int HASH_LAST_MODIFIED = 150043680;
-    private final static int HASH_ETAG = 3123477;
-    private final static int HASH_SET_COOKIE = 1237214767;
-    private final static int HASH_PRAGMA = -980228804;
-    private final static int HASH_REFRESH = 1085444827;
-    private final static int HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES = -1345594014;
-
-    // keep any headers that require direct access in a presized
-    // string array
-    private final static int IDX_TRANSFER_ENCODING = 0;
-    private final static int IDX_CONTENT_LEN = 1;
-    private final static int IDX_CONTENT_TYPE = 2;
-    private final static int IDX_CONTENT_ENCODING = 3;
-    private final static int IDX_CONN_DIRECTIVE = 4;
-    private final static int IDX_LOCATION = 5;
-    private final static int IDX_PROXY_CONNECTION = 6;
-    private final static int IDX_WWW_AUTHENTICATE = 7;
-    private final static int IDX_PROXY_AUTHENTICATE = 8;
-    private final static int IDX_CONTENT_DISPOSITION = 9;
-    private final static int IDX_ACCEPT_RANGES = 10;
-    private final static int IDX_EXPIRES = 11;
-    private final static int IDX_CACHE_CONTROL = 12;
-    private final static int IDX_LAST_MODIFIED = 13;
-    private final static int IDX_ETAG = 14;
-    private final static int IDX_SET_COOKIE = 15;
-    private final static int IDX_PRAGMA = 16;
-    private final static int IDX_REFRESH = 17;
-    private final static int IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES = 18;
-
-    private final static int HEADER_COUNT = 19;
-
-    /* parsed values */
-    private long transferEncoding;
-    private long contentLength; // Content length of the incoming data
-    private int connectionType;
-    private ArrayList<String> cookies = new ArrayList<String>(2);
-
-    private String[] mHeaders = new String[HEADER_COUNT];
-    private final static String[] sHeaderNames = {
-        TRANSFER_ENCODING,
-        CONTENT_LEN,
-        CONTENT_TYPE,
-        CONTENT_ENCODING,
-        CONN_DIRECTIVE,
-        LOCATION,
-        PROXY_CONNECTION,
-        WWW_AUTHENTICATE,
-        PROXY_AUTHENTICATE,
-        CONTENT_DISPOSITION,
-        ACCEPT_RANGES,
-        EXPIRES,
-        CACHE_CONTROL,
-        LAST_MODIFIED,
-        ETAG,
-        SET_COOKIE,
-        PRAGMA,
-        REFRESH,
-        X_PERMITTED_CROSS_DOMAIN_POLICIES
-    };
-
-    // Catch-all for headers not explicitly handled
-    private ArrayList<String> mExtraHeaderNames = new ArrayList<String>(4);
-    private ArrayList<String> mExtraHeaderValues = new ArrayList<String>(4);
-
-    public Headers() {
-        transferEncoding = NO_TRANSFER_ENCODING;
-        contentLength = NO_CONTENT_LENGTH;
-        connectionType = NO_CONN_TYPE;
-    }
-
-    public void parseHeader(CharArrayBuffer buffer) {
-        int pos = CharArrayBuffers.setLowercaseIndexOf(buffer, ':');
-        if (pos == -1) {
-            return;
-        }
-        String name = buffer.substringTrimmed(0, pos);
-        if (name.length() == 0) {
-            return;
-        }
-        pos++;
-
-        String val = buffer.substringTrimmed(pos, buffer.length());
-        if (HttpLog.LOGV) {
-            HttpLog.v("hdr " + buffer.length() + " " + buffer);
-        }
-
-        switch (name.hashCode()) {
-        case HASH_TRANSFER_ENCODING:
-            if (name.equals(TRANSFER_ENCODING)) {
-                mHeaders[IDX_TRANSFER_ENCODING] = val;
-                HeaderElement[] encodings = BasicHeaderValueParser.DEFAULT
-                        .parseElements(buffer, new ParserCursor(pos,
-                                buffer.length()));
-                // The chunked encoding must be the last one applied RFC2616,
-                // 14.41
-                int len = encodings.length;
-                if (HTTP.IDENTITY_CODING.equalsIgnoreCase(val)) {
-                    transferEncoding = ContentLengthStrategy.IDENTITY;
-                } else if ((len > 0)
-                        && (HTTP.CHUNK_CODING
-                                .equalsIgnoreCase(encodings[len - 1].getName()))) {
-                    transferEncoding = ContentLengthStrategy.CHUNKED;
-                } else {
-                    transferEncoding = ContentLengthStrategy.IDENTITY;
-                }
-            }
-            break;
-        case HASH_CONTENT_LEN:
-            if (name.equals(CONTENT_LEN)) {
-                mHeaders[IDX_CONTENT_LEN] = val;
-                try {
-                    contentLength = Long.parseLong(val);
-                } catch (NumberFormatException e) {
-                    if (false) {
-                        Log.v(LOGTAG, "Headers.headers(): error parsing"
-                                + " content length: " + buffer.toString());
-                    }
-                }
-            }
-            break;
-        case HASH_CONTENT_TYPE:
-            if (name.equals(CONTENT_TYPE)) {
-                mHeaders[IDX_CONTENT_TYPE] = val;
-            }
-            break;
-        case HASH_CONTENT_ENCODING:
-            if (name.equals(CONTENT_ENCODING)) {
-                mHeaders[IDX_CONTENT_ENCODING] = val;
-            }
-            break;
-        case HASH_CONN_DIRECTIVE:
-            if (name.equals(CONN_DIRECTIVE)) {
-                mHeaders[IDX_CONN_DIRECTIVE] = val;
-                setConnectionType(buffer, pos);
-            }
-            break;
-        case HASH_LOCATION:
-            if (name.equals(LOCATION)) {
-                mHeaders[IDX_LOCATION] = val;
-            }
-            break;
-        case HASH_PROXY_CONNECTION:
-            if (name.equals(PROXY_CONNECTION)) {
-                mHeaders[IDX_PROXY_CONNECTION] = val;
-                setConnectionType(buffer, pos);
-            }
-            break;
-        case HASH_WWW_AUTHENTICATE:
-            if (name.equals(WWW_AUTHENTICATE)) {
-                mHeaders[IDX_WWW_AUTHENTICATE] = val;
-            }
-            break;
-        case HASH_PROXY_AUTHENTICATE:
-            if (name.equals(PROXY_AUTHENTICATE)) {
-                mHeaders[IDX_PROXY_AUTHENTICATE] = val;
-            }
-            break;
-        case HASH_CONTENT_DISPOSITION:
-            if (name.equals(CONTENT_DISPOSITION)) {
-                mHeaders[IDX_CONTENT_DISPOSITION] = val;
-            }
-            break;
-        case HASH_ACCEPT_RANGES:
-            if (name.equals(ACCEPT_RANGES)) {
-                mHeaders[IDX_ACCEPT_RANGES] = val;
-            }
-            break;
-        case HASH_EXPIRES:
-            if (name.equals(EXPIRES)) {
-                mHeaders[IDX_EXPIRES] = val;
-            }
-            break;
-        case HASH_CACHE_CONTROL:
-            if (name.equals(CACHE_CONTROL)) {
-                // In case where we receive more than one header, create a ',' separated list.
-                // This should be ok, according to RFC 2616 chapter 4.2
-                if (mHeaders[IDX_CACHE_CONTROL] != null &&
-                    mHeaders[IDX_CACHE_CONTROL].length() > 0) {
-                    mHeaders[IDX_CACHE_CONTROL] += (',' + val);
-                } else {
-                    mHeaders[IDX_CACHE_CONTROL] = val;
-                }
-            }
-            break;
-        case HASH_LAST_MODIFIED:
-            if (name.equals(LAST_MODIFIED)) {
-                mHeaders[IDX_LAST_MODIFIED] = val;
-            }
-            break;
-        case HASH_ETAG:
-            if (name.equals(ETAG)) {
-                mHeaders[IDX_ETAG] = val;
-            }
-            break;
-        case HASH_SET_COOKIE:
-            if (name.equals(SET_COOKIE)) {
-                mHeaders[IDX_SET_COOKIE] = val;
-                cookies.add(val);
-            }
-            break;
-        case HASH_PRAGMA:
-            if (name.equals(PRAGMA)) {
-                mHeaders[IDX_PRAGMA] = val;
-            }
-            break;
-        case HASH_REFRESH:
-            if (name.equals(REFRESH)) {
-                mHeaders[IDX_REFRESH] = val;
-            }
-            break;
-        case HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES:
-            if (name.equals(X_PERMITTED_CROSS_DOMAIN_POLICIES)) {
-                mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = val;
-            }
-            break;
-        default:
-            mExtraHeaderNames.add(name);
-            mExtraHeaderValues.add(val);
-        }
-    }
-
-    public long getTransferEncoding() {
-        return transferEncoding;
-    }
-
-    public long getContentLength() {
-        return contentLength;
-    }
-
-    public int getConnectionType() {
-        return connectionType;
-    }
-
-    public String getContentType() {
-        return mHeaders[IDX_CONTENT_TYPE];
-    }
-
-    public String getContentEncoding() {
-        return mHeaders[IDX_CONTENT_ENCODING];
-    }
-
-    public String getLocation() {
-        return mHeaders[IDX_LOCATION];
-    }
-
-    public String getWwwAuthenticate() {
-        return mHeaders[IDX_WWW_AUTHENTICATE];
-    }
-
-    public String getProxyAuthenticate() {
-        return mHeaders[IDX_PROXY_AUTHENTICATE];
-    }
-
-    public String getContentDisposition() {
-        return mHeaders[IDX_CONTENT_DISPOSITION];
-    }
-
-    public String getAcceptRanges() {
-        return mHeaders[IDX_ACCEPT_RANGES];
-    }
-
-    public String getExpires() {
-        return mHeaders[IDX_EXPIRES];
-    }
-
-    public String getCacheControl() {
-        return mHeaders[IDX_CACHE_CONTROL];
-    }
-
-    public String getLastModified() {
-        return mHeaders[IDX_LAST_MODIFIED];
-    }
-
-    public String getEtag() {
-        return mHeaders[IDX_ETAG];
-    }
-
-    public ArrayList<String> getSetCookie() {
-        return this.cookies;
-    }
-
-    public String getPragma() {
-        return mHeaders[IDX_PRAGMA];
-    }
-
-    public String getRefresh() {
-        return mHeaders[IDX_REFRESH];
-    }
-
-    public String getXPermittedCrossDomainPolicies() {
-        return mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES];
-    }
-
-    public void setContentLength(long value) {
-        this.contentLength = value;
-    }
-
-    public void setContentType(String value) {
-        mHeaders[IDX_CONTENT_TYPE] = value;
-    }
-
-    public void setContentEncoding(String value) {
-        mHeaders[IDX_CONTENT_ENCODING] = value;
-    }
-
-    public void setLocation(String value) {
-        mHeaders[IDX_LOCATION] = value;
-    }
-
-    public void setWwwAuthenticate(String value) {
-        mHeaders[IDX_WWW_AUTHENTICATE] = value;
-    }
-
-    public void setProxyAuthenticate(String value) {
-        mHeaders[IDX_PROXY_AUTHENTICATE] = value;
-    }
-
-    public void setContentDisposition(String value) {
-        mHeaders[IDX_CONTENT_DISPOSITION] = value;
-    }
-
-    public void setAcceptRanges(String value) {
-        mHeaders[IDX_ACCEPT_RANGES] = value;
-    }
-
-    public void setExpires(String value) {
-        mHeaders[IDX_EXPIRES] = value;
-    }
-
-    public void setCacheControl(String value) {
-        mHeaders[IDX_CACHE_CONTROL] = value;
-    }
-
-    public void setLastModified(String value) {
-        mHeaders[IDX_LAST_MODIFIED] = value;
-    }
-
-    public void setEtag(String value) {
-        mHeaders[IDX_ETAG] = value;
-    }
-
-    public void setXPermittedCrossDomainPolicies(String value) {
-        mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = value;
-    }
-
-    public interface HeaderCallback {
-        public void header(String name, String value);
-    }
-
-    /**
-     * Reports all non-null headers to the callback
-     */
-    public void getHeaders(HeaderCallback hcb) {
-        for (int i = 0; i < HEADER_COUNT; i++) {
-            String h = mHeaders[i];
-            if (h != null) {
-                hcb.header(sHeaderNames[i], h);
-            }
-        }
-        int extraLen = mExtraHeaderNames.size();
-        for (int i = 0; i < extraLen; i++) {
-            if (false) {
-                HttpLog.v("Headers.getHeaders() extra: " + i + " " +
-                          mExtraHeaderNames.get(i) + " " + mExtraHeaderValues.get(i));
-            }
-            hcb.header(mExtraHeaderNames.get(i),
-                       mExtraHeaderValues.get(i));
-        }
-
-    }
-
-    private void setConnectionType(CharArrayBuffer buffer, int pos) {
-        if (CharArrayBuffers.containsIgnoreCaseTrimmed(
-                buffer, pos, HTTP.CONN_CLOSE)) {
-            connectionType = CONN_CLOSE;
-        } else if (CharArrayBuffers.containsIgnoreCaseTrimmed(
-                buffer, pos, HTTP.CONN_KEEP_ALIVE)) {
-            connectionType = CONN_KEEP_ALIVE;
-        }
-    }
-}
diff --git a/core/java/android/net/http/HttpAuthHeader.java b/core/java/android/net/http/HttpAuthHeader.java
deleted file mode 100644
index 3abac23..0000000
--- a/core/java/android/net/http/HttpAuthHeader.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import java.util.Locale;
-
-/**
- * HttpAuthHeader: a class to store HTTP authentication-header parameters.
- * For more information, see: RFC 2617: HTTP Authentication.
- * 
- * {@hide}
- */
-public class HttpAuthHeader {
-    /**
-     * Possible HTTP-authentication header tokens to search for:
-     */
-    public final static String BASIC_TOKEN = "Basic";
-    public final static String DIGEST_TOKEN = "Digest";
-
-    private final static String REALM_TOKEN = "realm";
-    private final static String NONCE_TOKEN = "nonce";
-    private final static String STALE_TOKEN = "stale";
-    private final static String OPAQUE_TOKEN = "opaque";
-    private final static String QOP_TOKEN = "qop";
-    private final static String ALGORITHM_TOKEN = "algorithm";
-
-    /**
-     * An authentication scheme. We currently support two different schemes:
-     * HttpAuthHeader.BASIC  - basic, and
-     * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth").
-     */
-    private int mScheme;
-
-    public static final int UNKNOWN = 0;
-    public static final int BASIC = 1;
-    public static final int DIGEST = 2;
-
-    /**
-     * A flag, indicating that the previous request from the client was
-     * rejected because the nonce value was stale. If stale is TRUE
-     * (case-insensitive), the client may wish to simply retry the request
-     * with a new encrypted response, without reprompting the user for a
-     * new username and password.
-     */
-    private boolean mStale;
-
-    /**
-     * A string to be displayed to users so they know which username and
-     * password to use.
-     */
-    private String mRealm;
-
-    /**
-     * A server-specified data string which should be uniquely generated
-     * each time a 401 response is made.
-     */
-    private String mNonce;
-
-    /**
-     * A string of data, specified by the server, which should be returned
-     *  by the client unchanged in the Authorization header of subsequent
-     * requests with URIs in the same protection space.
-     */
-    private String mOpaque;
-
-    /**
-     * This directive is optional, but is made so only for backward
-     * compatibility with RFC 2069 [6]; it SHOULD be used by all
-     * implementations compliant with this version of the Digest scheme.
-     * If present, it is a quoted string of one or more tokens indicating
-     * the "quality of protection" values supported by the server.  The
-     * value "auth" indicates authentication; the value "auth-int"
-     * indicates authentication with integrity protection.
-     */
-    private String mQop;
-
-    /**
-     * A string indicating a pair of algorithms used to produce the digest
-     * and a checksum. If this is not present it is assumed to be "MD5".
-     */
-    private String mAlgorithm;
-
-    /**
-     * Is this authentication request a proxy authentication request?
-     */
-    private boolean mIsProxy;
-
-    /**
-     * Username string we get from the user.
-     */
-    private String mUsername;
-
-    /**
-     * Password string we get from the user.
-     */
-    private String mPassword;
-
-    /**
-     * Creates a new HTTP-authentication header object from the
-     * input header string.
-     * The header string is assumed to contain parameters of at
-     * most one authentication-scheme (ensured by the caller).
-     */
-    public HttpAuthHeader(String header) {
-        if (header != null) {
-            parseHeader(header);
-        }
-    }
-
-    /**
-     * @return True iff this is a proxy authentication header.
-     */
-    public boolean isProxy() {
-        return mIsProxy;
-    }
-
-    /**
-     * Marks this header as a proxy authentication header.
-     */
-    public void setProxy() {
-        mIsProxy = true;
-    }
-
-    /**
-     * @return The username string.
-     */
-    public String getUsername() {
-        return mUsername;
-    }
-
-    /**
-     * Sets the username string.
-     */
-    public void setUsername(String username) {
-        mUsername = username;
-    }
-
-    /**
-     * @return The password string.
-     */
-    public String getPassword() {
-        return mPassword;
-    }
-
-    /**
-     * Sets the password string.
-     */
-    public void setPassword(String password) {
-        mPassword = password;
-    }
-
-    /**
-     * @return True iff this is the  BASIC-authentication request.
-     */
-    public boolean isBasic () {
-        return mScheme == BASIC;
-    }
-
-    /**
-     * @return True iff this is the DIGEST-authentication request.
-     */
-    public boolean isDigest() {
-        return mScheme == DIGEST;
-    }
-
-    /**
-     * @return The authentication scheme requested. We currently
-     * support two schemes:
-     * HttpAuthHeader.BASIC  - basic, and
-     * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth").
-     */
-    public int getScheme() {
-        return mScheme;
-    }
-
-    /**
-     * @return True if indicating that the previous request from
-     * the client was rejected because the nonce value was stale.
-     */
-    public boolean getStale() {
-        return mStale;
-    }
-
-    /**
-     * @return The realm value or null if there is none.
-     */
-    public String getRealm() {
-        return mRealm;
-    }
-
-    /**
-     * @return The nonce value or null if there is none.
-     */
-    public String getNonce() {
-        return mNonce;
-    }
-
-    /**
-     * @return The opaque value or null if there is none.
-     */
-    public String getOpaque() {
-        return mOpaque;
-    }
-
-    /**
-     * @return The QOP ("quality-of_protection") value or null if
-     * there is none. The QOP value is always lower-case.
-     */
-    public String getQop() {
-        return mQop;
-    }
-
-    /**
-     * @return The name of the algorithm used or null if there is
-     * none. By default, MD5 is used.
-     */
-    public String getAlgorithm() {
-        return mAlgorithm;
-    }
-
-    /**
-     * @return True iff the authentication scheme requested by the
-     * server is supported; currently supported schemes:
-     * BASIC,
-     * DIGEST (only algorithm="md5", no qop or qop="auth).
-     */
-    public boolean isSupportedScheme() {
-        // it is a good idea to enforce non-null realms!
-        if (mRealm != null) {
-            if (mScheme == BASIC) {
-                return true;
-            } else {
-                if (mScheme == DIGEST) {
-                    return
-                        mAlgorithm.equals("md5") &&
-                        (mQop == null || mQop.equals("auth"));
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Parses the header scheme name and then scheme parameters if
-     * the scheme is supported.
-     */
-    private void parseHeader(String header) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("HttpAuthHeader.parseHeader(): header: " + header);
-        }
-
-        if (header != null) {
-            String parameters = parseScheme(header);
-            if (parameters != null) {
-                // if we have a supported scheme
-                if (mScheme != UNKNOWN) {
-                    parseParameters(parameters);
-                }
-            }
-        }
-    }
-
-    /**
-     * Parses the authentication scheme name. If we have a Digest
-     * scheme, sets the algorithm value to the default of MD5.
-     * @return The authentication scheme parameters string to be
-     * parsed later (if the scheme is supported) or null if failed
-     * to parse the scheme (the header value is null?).
-     */
-    private String parseScheme(String header) {
-        if (header != null) {
-            int i = header.indexOf(' ');
-            if (i >= 0) {
-                String scheme = header.substring(0, i).trim();
-                if (scheme.equalsIgnoreCase(DIGEST_TOKEN)) {
-                    mScheme = DIGEST;
-
-                    // md5 is the default algorithm!!!
-                    mAlgorithm = "md5";
-                } else {
-                    if (scheme.equalsIgnoreCase(BASIC_TOKEN)) {
-                        mScheme = BASIC;
-                    }
-                }
-
-                return header.substring(i + 1);
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Parses a comma-separated list of authentification scheme
-     * parameters.
-     */
-    private void parseParameters(String parameters) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("HttpAuthHeader.parseParameters():" +
-                      " parameters: " + parameters);
-        }
-
-        if (parameters != null) {
-            int i;
-            do {
-                i = parameters.indexOf(',');
-                if (i < 0) {
-                    // have only one parameter
-                    parseParameter(parameters);
-                } else {
-                    parseParameter(parameters.substring(0, i));
-                    parameters = parameters.substring(i + 1);
-                }
-            } while (i >= 0);
-        }
-    }
-
-    /**
-     * Parses a single authentication scheme parameter. The parameter
-     * string is expected to follow the format: PARAMETER=VALUE.
-     */
-    private void parseParameter(String parameter) {
-        if (parameter != null) {
-            // here, we are looking for the 1st occurence of '=' only!!!
-            int i = parameter.indexOf('=');
-            if (i >= 0) {
-                String token = parameter.substring(0, i).trim();
-                String value =
-                    trimDoubleQuotesIfAny(parameter.substring(i + 1).trim());
-
-                if (HttpLog.LOGV) {
-                    HttpLog.v("HttpAuthHeader.parseParameter():" +
-                              " token: " + token +
-                              " value: " + value);
-                }
-
-                if (token.equalsIgnoreCase(REALM_TOKEN)) {
-                    mRealm = value;
-                } else {
-                    if (mScheme == DIGEST) {
-                        parseParameter(token, value);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * If the token is a known parameter name, parses and initializes
-     * the token value.
-     */
-    private void parseParameter(String token, String value) {
-        if (token != null && value != null) {
-            if (token.equalsIgnoreCase(NONCE_TOKEN)) {
-                mNonce = value;
-                return;
-            }
-
-            if (token.equalsIgnoreCase(STALE_TOKEN)) {
-                parseStale(value);
-                return;
-            }
-
-            if (token.equalsIgnoreCase(OPAQUE_TOKEN)) {
-                mOpaque = value;
-                return;
-            }
-
-            if (token.equalsIgnoreCase(QOP_TOKEN)) {
-                mQop = value.toLowerCase(Locale.ROOT);
-                return;
-            }
-
-            if (token.equalsIgnoreCase(ALGORITHM_TOKEN)) {
-                mAlgorithm = value.toLowerCase(Locale.ROOT);
-                return;
-            }
-        }
-    }
-
-    /**
-     * Parses and initializes the 'stale' paramer value. Any value
-     * different from case-insensitive "true" is considered "false".
-     */
-    private void parseStale(String value) {
-        if (value != null) {
-            if (value.equalsIgnoreCase("true")) {
-                mStale = true;
-            }
-        }
-    }
-
-    /**
-     * Trims double-quotes around a parameter value if there are any.
-     * @return The string value without the outermost pair of double-
-     * quotes or null if the original value is null.
-     */
-    static private String trimDoubleQuotesIfAny(String value) {
-        if (value != null) {
-            int len = value.length();
-            if (len > 2 &&
-                value.charAt(0) == '\"' && value.charAt(len - 1) == '\"') {
-                return value.substring(1, len - 1);
-            }
-        }
-
-        return value;
-    }
-}
diff --git a/core/java/android/net/http/HttpConnection.java b/core/java/android/net/http/HttpConnection.java
deleted file mode 100644
index edf8fed3..0000000
--- a/core/java/android/net/http/HttpConnection.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-
-import java.net.Socket;
-import java.io.IOException;
-
-import org.apache.http.HttpHost;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-
-/**
- * A requestConnection connecting to a normal (non secure) http server
- * 
- * {@hide}
- */
-class HttpConnection extends Connection {
-
-    HttpConnection(Context context, HttpHost host,
-                   RequestFeeder requestFeeder) {
-        super(context, host, requestFeeder);
-    }
-
-    /**
-     * Opens the connection to a http server
-     *
-     * @return the opened low level connection
-     * @throws IOException if the connection fails for any reason.
-     */
-    @Override
-    AndroidHttpClientConnection openConnection(Request req) throws IOException {
-
-        // Update the certificate info (connection not secure - set to null)
-        EventHandler eventHandler = req.getEventHandler();
-        mCertificate = null;
-        eventHandler.certificate(mCertificate);
-
-        AndroidHttpClientConnection conn = new AndroidHttpClientConnection();
-        BasicHttpParams params = new BasicHttpParams();
-        Socket sock = new Socket(mHost.getHostName(), mHost.getPort());
-        params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192);
-        conn.bind(sock, params);
-        return conn;
-    }
-
-    /**
-     * Closes the low level connection.
-     *
-     * If an exception is thrown then it is assumed that the
-     * connection will have been closed (to the extent possible)
-     * anyway and the caller does not need to take any further action.
-     *
-     */
-    void closeConnection() {
-        try {
-            if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) {
-                mHttpClientConnection.close();
-            }
-        } catch (IOException e) {
-            if (HttpLog.LOGV) HttpLog.v(
-                    "closeConnection(): failed closing connection " +
-                    mHost);
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Restart a secure connection suspended waiting for user interaction.
-     */
-    void restartConnection(boolean abort) {
-        // not required for plain http connections
-    }
-
-    String getScheme() {
-        return "http";
-    }
-}
diff --git a/core/java/android/net/http/HttpLog.java b/core/java/android/net/http/HttpLog.java
deleted file mode 100644
index 0934664..0000000
--- a/core/java/android/net/http/HttpLog.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * package-level logging flag
- */
-
-package android.net.http;
-
-import android.os.SystemClock;
-
-import android.util.Log;
-
-/**
- * {@hide}
- */
-class HttpLog {
-    private final static String LOGTAG = "http";
-
-    private static final boolean DEBUG = false;
-    static final boolean LOGV = false;
-
-    static void v(String logMe) {
-        Log.v(LOGTAG, SystemClock.uptimeMillis() + " " + Thread.currentThread().getName() + " " + logMe);
-    }
-
-    static void e(String logMe) {
-        Log.e(LOGTAG, logMe);
-    }
-}
diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java
index 2785a15..188287f 100644
--- a/core/java/android/net/http/HttpResponseCache.java
+++ b/core/java/android/net/http/HttpResponseCache.java
@@ -16,32 +16,33 @@
 
 package android.net.http;
 
-import android.content.Context;
+import com.android.okhttp.Cache;
+import com.android.okhttp.AndroidShimResponseCache;
+import com.android.okhttp.OkCacheContainer;
+
 import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 import java.net.CacheRequest;
 import java.net.CacheResponse;
-import java.net.HttpURLConnection;
 import java.net.ResponseCache;
 import java.net.URI;
 import java.net.URLConnection;
 import java.util.List;
 import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
-import org.apache.http.impl.client.DefaultHttpClient;
 
 /**
  * Caches HTTP and HTTPS responses to the filesystem so they may be reused,
- * saving time and bandwidth. This class supports {@link HttpURLConnection} and
- * {@link HttpsURLConnection}; there is no platform-provided cache for {@link
- * DefaultHttpClient} or {@link AndroidHttpClient}.
+ * saving time and bandwidth. This class supports {@link
+ * java.net.HttpURLConnection} and {@link javax.net.ssl.HttpsURLConnection};
+ * there is no platform-provided cache for {@code DefaultHttpClient} or
+ * {@code AndroidHttpClient}.
  *
  * <h3>Installing an HTTP response cache</h3>
  * Enable caching of all of your application's HTTP requests by installing the
  * cache at application startup. For example, this code installs a 10 MiB cache
- * in the {@link Context#getCacheDir() application-specific cache directory} of
- * the filesystem}: <pre>   {@code
+ * in the {@link android.content.Context#getCacheDir() application-specific
+ * cache directory} of the filesystem}: <pre>   {@code
  *   protected void onCreate(Bundle savedInstanceState) {
  *       ...
  *
@@ -73,10 +74,10 @@
  * contain private data.</strong> Although it often has more free space,
  * external storage is optional and&#8212;even if available&#8212;can disappear
  * during use. Retrieve the external cache directory using {@link
- * Context#getExternalCacheDir()}. If this method returns null, your application
- * should fall back to either not caching or caching on non-external storage. If
- * the external storage is removed during use, the cache hit rate will drop to
- * zero and ongoing cache reads will fail.
+ * android.content.Context#getExternalCacheDir()}. If this method returns null,
+ * your application should fall back to either not caching or caching on
+ * non-external storage. If the external storage is removed during use, the
+ * cache hit rate will drop to zero and ongoing cache reads will fail.
  *
  * <p>Flushing the cache forces its data to the filesystem. This ensures that
  * all responses written to the cache will be readable the next time the
@@ -147,11 +148,11 @@
  *       } catch (Exception httpResponseCacheNotAvailable) {
  *       }}</pre>
  */
-public final class HttpResponseCache extends ResponseCache implements Closeable {
+public final class HttpResponseCache extends ResponseCache implements Closeable, OkCacheContainer {
 
-    private final com.android.okhttp.HttpResponseCache delegate;
+    private final AndroidShimResponseCache delegate;
 
-    private HttpResponseCache(com.android.okhttp.HttpResponseCache delegate) {
+    private HttpResponseCache(AndroidShimResponseCache delegate) {
         this.delegate = delegate;
     }
 
@@ -161,17 +162,14 @@
      */
     public static HttpResponseCache getInstalled() {
         ResponseCache installed = ResponseCache.getDefault();
-        if (installed instanceof com.android.okhttp.HttpResponseCache) {
-            return new HttpResponseCache(
-                    (com.android.okhttp.HttpResponseCache) installed);
+        if (installed instanceof HttpResponseCache) {
+            return (HttpResponseCache) installed;
         }
-
         return null;
     }
 
     /**
-     * Creates a new HTTP response cache and {@link ResponseCache#setDefault
-     * sets it} as the system default cache.
+     * Creates a new HTTP response cache and sets it as the system default cache.
      *
      * @param directory the directory to hold cache data.
      * @param maxSize the maximum size of the cache in bytes.
@@ -180,26 +178,26 @@
      *     Most applications should respond to this exception by logging a
      *     warning.
      */
-    public static HttpResponseCache install(File directory, long maxSize) throws IOException {
+    public static synchronized HttpResponseCache install(File directory, long maxSize)
+            throws IOException {
         ResponseCache installed = ResponseCache.getDefault();
-        if (installed instanceof com.android.okhttp.HttpResponseCache) {
-            com.android.okhttp.HttpResponseCache installedCache =
-                    (com.android.okhttp.HttpResponseCache) installed;
+        if (installed instanceof HttpResponseCache) {
+            HttpResponseCache installedResponseCache = (HttpResponseCache) installed;
             // don't close and reopen if an equivalent cache is already installed
-            if (installedCache.getDirectory().equals(directory)
-                    && installedCache.getMaxSize() == maxSize
-                    && !installedCache.isClosed()) {
-                return new HttpResponseCache(installedCache);
+            AndroidShimResponseCache trueResponseCache = installedResponseCache.delegate;
+            if (trueResponseCache.isEquivalent(directory, maxSize)) {
+                return installedResponseCache;
             } else {
                 // The HttpResponseCache that owns this object is about to be replaced.
-                installedCache.close();
+                trueResponseCache.close();
             }
         }
 
-        com.android.okhttp.HttpResponseCache responseCache =
-                new com.android.okhttp.HttpResponseCache(directory, maxSize);
-        ResponseCache.setDefault(responseCache);
-        return new HttpResponseCache(responseCache);
+        AndroidShimResponseCache trueResponseCache =
+                AndroidShimResponseCache.create(directory, maxSize);
+        HttpResponseCache newResponseCache = new HttpResponseCache(trueResponseCache);
+        ResponseCache.setDefault(newResponseCache);
+        return newResponseCache;
     }
 
     @Override public CacheResponse get(URI uri, String requestMethod,
@@ -214,10 +212,15 @@
     /**
      * Returns the number of bytes currently being used to store the values in
      * this cache. This may be greater than the {@link #maxSize} if a background
-     * deletion is pending.
+     * deletion is pending. {@code -1} is returned if the size cannot be determined.
      */
     public long size() {
-        return delegate.getSize();
+        try {
+            return delegate.size();
+        } catch (IOException e) {
+            // This can occur if the cache failed to lazily initialize.
+            return -1;
+        }
     }
 
     /**
@@ -225,7 +228,7 @@
      * its data.
      */
     public long maxSize() {
-        return delegate.getMaxSize();
+        return delegate.maxSize();
     }
 
     /**
@@ -271,7 +274,7 @@
      * will remain on the filesystem.
      */
     @Override public void close() throws IOException {
-        if (ResponseCache.getDefault() == this.delegate) {
+        if (ResponseCache.getDefault() == this) {
             ResponseCache.setDefault(null);
         }
         delegate.close();
@@ -281,9 +284,16 @@
      * Uninstalls the cache and deletes all of its stored contents.
      */
     public void delete() throws IOException {
-        if (ResponseCache.getDefault() == this.delegate) {
+        if (ResponseCache.getDefault() == this) {
             ResponseCache.setDefault(null);
         }
         delegate.delete();
     }
+
+    /** @hide Needed for OkHttp integration. */
+    @Override
+    public Cache getCache() {
+        return delegate.getCache();
+    }
+
 }
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
deleted file mode 100644
index 6bf01e2..0000000
--- a/core/java/android/net/http/HttpsConnection.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.util.Log;
-import com.android.org.conscrypt.FileClientSessionCache;
-import com.android.org.conscrypt.OpenSSLContextImpl;
-import com.android.org.conscrypt.SSLClientSessionCache;
-import org.apache.http.Header;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpStatus;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.StatusLine;
-import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.io.File;
-import java.io.IOException;
-import java.net.Socket;
-import java.security.KeyManagementException;
-import java.security.cert.X509Certificate;
-import java.util.Locale;
-
-/**
- * A Connection connecting to a secure http server or tunneling through
- * a http proxy server to a https server.
- *
- * @hide
- */
-public class HttpsConnection extends Connection {
-
-    /**
-     * SSL socket factory
-     */
-    private static SSLSocketFactory mSslSocketFactory = null;
-
-    static {
-        // This initialization happens in the zygote. It triggers some
-        // lazy initialization that can will benefit later invocations of
-        // initializeEngine().
-        initializeEngine(null);
-    }
-
-    /**
-     * @hide
-     *
-     * @param sessionDir directory to cache SSL sessions
-     */
-    public static void initializeEngine(File sessionDir) {
-        try {
-            SSLClientSessionCache cache = null;
-            if (sessionDir != null) {
-                Log.d("HttpsConnection", "Caching SSL sessions in "
-                        + sessionDir + ".");
-                cache = FileClientSessionCache.usingDirectory(sessionDir);
-            }
-
-            OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
-
-            // here, trust managers is a single trust-all manager
-            TrustManager[] trustManagers = new TrustManager[] {
-                new X509TrustManager() {
-                    public X509Certificate[] getAcceptedIssuers() {
-                        return null;
-                    }
-
-                    public void checkClientTrusted(
-                        X509Certificate[] certs, String authType) {
-                    }
-
-                    public void checkServerTrusted(
-                        X509Certificate[] certs, String authType) {
-                    }
-                }
-            };
-
-            sslContext.engineInit(null, trustManagers, null);
-            sslContext.engineGetClientSessionContext().setPersistentCache(cache);
-
-            synchronized (HttpsConnection.class) {
-                mSslSocketFactory = sslContext.engineGetSocketFactory();
-            }
-        } catch (KeyManagementException e) {
-            throw new RuntimeException(e);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private synchronized static SSLSocketFactory getSocketFactory() {
-        return mSslSocketFactory;
-    }
-
-    /**
-     * Object to wait on when suspending the SSL connection
-     */
-    private Object mSuspendLock = new Object();
-
-    /**
-     * True if the connection is suspended pending the result of asking the
-     * user about an error.
-     */
-    private boolean mSuspended = false;
-
-    /**
-     * True if the connection attempt should be aborted due to an ssl
-     * error.
-     */
-    private boolean mAborted = false;
-
-    // Used when connecting through a proxy.
-    private HttpHost mProxyHost;
-
-    /**
-     * Contructor for a https connection.
-     */
-    HttpsConnection(Context context, HttpHost host, HttpHost proxy,
-                    RequestFeeder requestFeeder) {
-        super(context, host, requestFeeder);
-        mProxyHost = proxy;
-    }
-
-    /**
-     * Sets the server SSL certificate associated with this
-     * connection.
-     * @param certificate The SSL certificate
-     */
-    /* package */ void setCertificate(SslCertificate certificate) {
-        mCertificate = certificate;
-    }
-
-    /**
-     * Opens the connection to a http server or proxy.
-     *
-     * @return the opened low level connection
-     * @throws IOException if the connection fails for any reason.
-     */
-    @Override
-    AndroidHttpClientConnection openConnection(Request req) throws IOException {
-        SSLSocket sslSock = null;
-
-        if (mProxyHost != null) {
-            // If we have a proxy set, we first send a CONNECT request
-            // to the proxy; if the proxy returns 200 OK, we negotiate
-            // a secure connection to the target server via the proxy.
-            // If the request fails, we drop it, but provide the event
-            // handler with the response status and headers. The event
-            // handler is then responsible for cancelling the load or
-            // issueing a new request.
-            AndroidHttpClientConnection proxyConnection = null;
-            Socket proxySock = null;
-            try {
-                proxySock = new Socket
-                    (mProxyHost.getHostName(), mProxyHost.getPort());
-
-                proxySock.setSoTimeout(60 * 1000);
-
-                proxyConnection = new AndroidHttpClientConnection();
-                HttpParams params = new BasicHttpParams();
-                HttpConnectionParams.setSocketBufferSize(params, 8192);
-
-                proxyConnection.bind(proxySock, params);
-            } catch(IOException e) {
-                if (proxyConnection != null) {
-                    proxyConnection.close();
-                }
-
-                String errorMessage = e.getMessage();
-                if (errorMessage == null) {
-                    errorMessage =
-                        "failed to establish a connection to the proxy";
-                }
-
-                throw new IOException(errorMessage);
-            }
-
-            StatusLine statusLine = null;
-            int statusCode = 0;
-            Headers headers = new Headers();
-            try {
-                BasicHttpRequest proxyReq = new BasicHttpRequest
-                    ("CONNECT", mHost.toHostString());
-
-                // add all 'proxy' headers from the original request, we also need
-                // to add 'host' header unless we want proxy to answer us with a
-                // 400 Bad Request
-                for (Header h : req.mHttpRequest.getAllHeaders()) {
-                    String headerName = h.getName().toLowerCase(Locale.ROOT);
-                    if (headerName.startsWith("proxy") || headerName.equals("keep-alive")
-                            || headerName.equals("host")) {
-                        proxyReq.addHeader(h);
-                    }
-                }
-
-                proxyConnection.sendRequestHeader(proxyReq);
-                proxyConnection.flush();
-
-                // it is possible to receive informational status
-                // codes prior to receiving actual headers;
-                // all those status codes are smaller than OK 200
-                // a loop is a standard way of dealing with them
-                do {
-                    statusLine = proxyConnection.parseResponseHeader(headers);
-                    statusCode = statusLine.getStatusCode();
-                } while (statusCode < HttpStatus.SC_OK);
-            } catch (ParseException e) {
-                String errorMessage = e.getMessage();
-                if (errorMessage == null) {
-                    errorMessage =
-                        "failed to send a CONNECT request";
-                }
-
-                throw new IOException(errorMessage);
-            } catch (HttpException e) {
-                String errorMessage = e.getMessage();
-                if (errorMessage == null) {
-                    errorMessage =
-                        "failed to send a CONNECT request";
-                }
-
-                throw new IOException(errorMessage);
-            } catch (IOException e) {
-                String errorMessage = e.getMessage();
-                if (errorMessage == null) {
-                    errorMessage =
-                        "failed to send a CONNECT request";
-                }
-
-                throw new IOException(errorMessage);
-            }
-
-            if (statusCode == HttpStatus.SC_OK) {
-                try {
-                    sslSock = (SSLSocket) getSocketFactory().createSocket(
-                            proxySock, mHost.getHostName(), mHost.getPort(), true);
-                } catch(IOException e) {
-                    if (sslSock != null) {
-                        sslSock.close();
-                    }
-
-                    String errorMessage = e.getMessage();
-                    if (errorMessage == null) {
-                        errorMessage =
-                            "failed to create an SSL socket";
-                    }
-                    throw new IOException(errorMessage);
-                }
-            } else {
-                // if the code is not OK, inform the event handler
-                ProtocolVersion version = statusLine.getProtocolVersion();
-
-                req.mEventHandler.status(version.getMajor(),
-                                         version.getMinor(),
-                                         statusCode,
-                                         statusLine.getReasonPhrase());
-                req.mEventHandler.headers(headers);
-                req.mEventHandler.endData();
-
-                proxyConnection.close();
-
-                // here, we return null to indicate that the original
-                // request needs to be dropped
-                return null;
-            }
-        } else {
-            // if we do not have a proxy, we simply connect to the host
-            try {
-                sslSock = (SSLSocket) getSocketFactory().createSocket(
-                        mHost.getHostName(), mHost.getPort());
-                sslSock.setSoTimeout(SOCKET_TIMEOUT);
-            } catch(IOException e) {
-                if (sslSock != null) {
-                    sslSock.close();
-                }
-
-                String errorMessage = e.getMessage();
-                if (errorMessage == null) {
-                    errorMessage = "failed to create an SSL socket";
-                }
-
-                throw new IOException(errorMessage);
-            }
-        }
-
-        // do handshake and validate server certificates
-        SslError error = CertificateChainValidator.getInstance().
-            doHandshakeAndValidateServerCertificates(this, sslSock, mHost.getHostName());
-
-        // Inform the user if there is a problem
-        if (error != null) {
-            // handleSslErrorRequest may immediately unsuspend if it wants to
-            // allow the certificate anyway.
-            // So we mark the connection as suspended, call handleSslErrorRequest
-            // then check if we're still suspended and only wait if we actually
-            // need to.
-            synchronized (mSuspendLock) {
-                mSuspended = true;
-            }
-            // don't hold the lock while calling out to the event handler
-            boolean canHandle = req.getEventHandler().handleSslErrorRequest(error);
-            if(!canHandle) {
-                throw new IOException("failed to handle "+ error);
-            }
-            synchronized (mSuspendLock) {
-                if (mSuspended) {
-                    try {
-                        // Put a limit on how long we are waiting; if the timeout
-                        // expires (which should never happen unless you choose
-                        // to ignore the SSL error dialog for a very long time),
-                        // we wake up the thread and abort the request. This is
-                        // to prevent us from stalling the network if things go
-                        // very bad.
-                        mSuspendLock.wait(10 * 60 * 1000);
-                        if (mSuspended) {
-                            // mSuspended is true if we have not had a chance to
-                            // restart the connection yet (ie, the wait timeout
-                            // has expired)
-                            mSuspended = false;
-                            mAborted = true;
-                            if (HttpLog.LOGV) {
-                                HttpLog.v("HttpsConnection.openConnection():" +
-                                          " SSL timeout expired and request was cancelled!!!");
-                            }
-                        }
-                    } catch (InterruptedException e) {
-                        // ignore
-                    }
-                }
-                if (mAborted) {
-                    // The user decided not to use this unverified connection
-                    // so close it immediately.
-                    sslSock.close();
-                    throw new SSLConnectionClosedByUserException("connection closed by the user");
-                }
-            }
-        }
-
-        // All went well, we have an open, verified connection.
-        AndroidHttpClientConnection conn = new AndroidHttpClientConnection();
-        BasicHttpParams params = new BasicHttpParams();
-        params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192);
-        conn.bind(sslSock, params);
-
-        return conn;
-    }
-
-    /**
-     * Closes the low level connection.
-     *
-     * If an exception is thrown then it is assumed that the connection will
-     * have been closed (to the extent possible) anyway and the caller does not
-     * need to take any further action.
-     *
-     */
-    @Override
-    void closeConnection() {
-        // if the connection has been suspended due to an SSL error
-        if (mSuspended) {
-            // wake up the network thread
-            restartConnection(false);
-        }
-
-        try {
-            if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) {
-                mHttpClientConnection.close();
-            }
-        } catch (IOException e) {
-            if (HttpLog.LOGV)
-                HttpLog.v("HttpsConnection.closeConnection():" +
-                          " failed closing connection " + mHost);
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Restart a secure connection suspended waiting for user interaction.
-     */
-    void restartConnection(boolean proceed) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("HttpsConnection.restartConnection():" +
-                      " proceed: " + proceed);
-        }
-
-        synchronized (mSuspendLock) {
-            if (mSuspended) {
-                mSuspended = false;
-                mAborted = !proceed;
-                mSuspendLock.notify();
-            }
-        }
-    }
-
-    @Override
-    String getScheme() {
-        return "https";
-    }
-}
-
-/**
- * Simple exception we throw if the SSL connection is closed by the user.
- *
- * {@hide}
- */
-class SSLConnectionClosedByUserException extends SSLException {
-
-    public SSLConnectionClosedByUserException(String reason) {
-        super(reason);
-    }
-}
diff --git a/core/java/android/net/http/IdleCache.java b/core/java/android/net/http/IdleCache.java
deleted file mode 100644
index fda6009..0000000
--- a/core/java/android/net/http/IdleCache.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Hangs onto idle live connections for a little while
- */
-
-package android.net.http;
-
-import org.apache.http.HttpHost;
-
-import android.os.SystemClock;
-
-/**
- * {@hide}
- */
-class IdleCache {
-
-    class Entry {
-        HttpHost mHost;
-        Connection mConnection;
-        long mTimeout;
-    };
-
-    private final static int IDLE_CACHE_MAX = 8;
-
-    /* Allow five consecutive empty queue checks before shutdown */
-    private final static int EMPTY_CHECK_MAX = 5;
-
-    /* six second timeout for connections */
-    private final static int TIMEOUT = 6 * 1000;
-    private final static int CHECK_INTERVAL = 2 * 1000;
-    private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
-
-    private int mCount = 0;
-
-    private IdleReaper mThread = null;
-
-    /* stats */
-    private int mCached = 0;
-    private int mReused = 0;
-
-    IdleCache() {
-        for (int i = 0; i < IDLE_CACHE_MAX; i++) {
-            mEntries[i] = new Entry();
-        }
-    }
-
-    /**
-     * Caches connection, if there is room.
-     * @return true if connection cached
-     */
-    synchronized boolean cacheConnection(
-            HttpHost host, Connection connection) {
-
-        boolean ret = false;
-
-        if (HttpLog.LOGV) {
-            HttpLog.v("IdleCache size " + mCount + " host "  + host);
-        }
-
-        if (mCount < IDLE_CACHE_MAX) {
-            long time = SystemClock.uptimeMillis();
-            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
-                Entry entry = mEntries[i];
-                if (entry.mHost == null) {
-                    entry.mHost = host;
-                    entry.mConnection = connection;
-                    entry.mTimeout = time + TIMEOUT;
-                    mCount++;
-                    if (HttpLog.LOGV) mCached++;
-                    ret = true;
-                    if (mThread == null) {
-                        mThread = new IdleReaper();
-                        mThread.start();
-                    }
-                    break;
-                }
-            }
-        }
-        return ret;
-    }
-
-    synchronized Connection getConnection(HttpHost host) {
-        Connection ret = null;
-
-        if (mCount > 0) {
-            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
-                Entry entry = mEntries[i];
-                HttpHost eHost = entry.mHost;
-                if (eHost != null && eHost.equals(host)) {
-                    ret = entry.mConnection;
-                    entry.mHost = null;
-                    entry.mConnection = null;
-                    mCount--;
-                    if (HttpLog.LOGV) mReused++;
-                    break;
-                }
-            }
-        }
-        return ret;
-    }
-
-    synchronized void clear() {
-        for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
-            Entry entry = mEntries[i];
-            if (entry.mHost != null) {
-                entry.mHost = null;
-                entry.mConnection.closeConnection();
-                entry.mConnection = null;
-                mCount--;
-            }
-        }
-    }
-
-    private synchronized void clearIdle() {
-        if (mCount > 0) {
-            long time = SystemClock.uptimeMillis();
-            for (int i = 0; i < IDLE_CACHE_MAX; i++) {
-                Entry entry = mEntries[i];
-                if (entry.mHost != null && time > entry.mTimeout) {
-                    entry.mHost = null;
-                    entry.mConnection.closeConnection();
-                    entry.mConnection = null;
-                    mCount--;
-                }
-            }
-        }
-    }
-
-    private class IdleReaper extends Thread {
-
-        public void run() {
-            int check = 0;
-
-            setName("IdleReaper");
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
-            synchronized (IdleCache.this) {
-                while (check < EMPTY_CHECK_MAX) {
-                    try {
-                        IdleCache.this.wait(CHECK_INTERVAL);
-                    } catch (InterruptedException ex) {
-                    }
-                    if (mCount == 0) {
-                        check++;
-                    } else {
-                        check = 0;
-                        clearIdle();
-                    }
-                }
-                mThread = null;
-            }
-            if (HttpLog.LOGV) {
-                HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
-                          " reused " + mReused);
-                mCached = 0;
-                mReused = 0;
-            }
-        }
-    }
-}
diff --git a/core/java/android/net/http/LoggingEventHandler.java b/core/java/android/net/http/LoggingEventHandler.java
deleted file mode 100644
index bdafa0b..0000000
--- a/core/java/android/net/http/LoggingEventHandler.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * A test EventHandler: Logs everything received
- */
-
-package android.net.http;
-
-import android.net.http.Headers;
-
-/**
- * {@hide}
- */
-public class LoggingEventHandler implements EventHandler {
-
-    public void requestSent() {
-        HttpLog.v("LoggingEventHandler:requestSent()");
-    }
-
-    public void status(int major_version,
-                       int minor_version,
-                       int code, /* Status-Code value */
-                       String reason_phrase) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler:status() major: " + major_version +
-                  " minor: " + minor_version +
-                  " code: " + code +
-                  " reason: " + reason_phrase);
-        }
-    }
-
-    public void headers(Headers headers) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler:headers()");
-            HttpLog.v(headers.toString());
-        }
-    }
-
-    public void locationChanged(String newLocation, boolean permanent) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler: locationChanged() " + newLocation +
-                      " permanent " + permanent);
-        }
-    }
-
-    public void data(byte[] data, int len) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler: data() " + len + " bytes");
-        }
-        // HttpLog.v(new String(data, 0, len));
-    }
-    public void endData() {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler: endData() called");
-        }
-    }
-
-    public void certificate(SslCertificate certificate) {
-         if (HttpLog.LOGV) {
-             HttpLog.v("LoggingEventHandler: certificate(): " + certificate);
-         }
-    }
-
-    public void error(int id, String description) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler: error() called Id:" + id +
-                      " description " + description);
-        }
-    }
-
-    public boolean handleSslErrorRequest(SslError error) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("LoggingEventHandler: handleSslErrorRequest():" + error);
-        }
-        // return false so that the caller thread won't wait forever
-        return false;
-    }
-}
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
deleted file mode 100644
index 76d7bb9..0000000
--- a/core/java/android/net/http/Request.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.http;
-
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.zip.GZIPInputStream;
-
-import org.apache.http.entity.InputStreamEntity;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpStatus;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-
-import org.apache.http.StatusLine;
-import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.message.BasicHttpEntityEnclosingRequest;
-import org.apache.http.protocol.RequestContent;
-
-/**
- * Represents an HTTP request for a given host.
- * 
- * {@hide}
- */
-
-class Request {
-
-    /** The eventhandler to call as the request progresses */
-    EventHandler mEventHandler;
-
-    private Connection mConnection;
-
-    /** The Apache http request */
-    BasicHttpRequest mHttpRequest;
-
-    /** The path component of this request */
-    String mPath;
-
-    /** Host serving this request */
-    HttpHost mHost;
-
-    /** Set if I'm using a proxy server */
-    HttpHost mProxyHost;
-
-    /** True if request has been cancelled */
-    volatile boolean mCancelled = false;
-
-    int mFailCount = 0;
-
-    // This will be used to set the Range field if we retry a connection. This
-    // is http/1.1 feature.
-    private int mReceivedBytes = 0;
-
-    private InputStream mBodyProvider;
-    private int mBodyLength;
-
-    private final static String HOST_HEADER = "Host";
-    private final static String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
-    private final static String CONTENT_LENGTH_HEADER = "content-length";
-
-    /* Used to synchronize waitUntilComplete() requests */
-    private final Object mClientResource = new Object();
-
-    /** True if loading should be paused **/
-    private boolean mLoadingPaused = false;
-
-    /**
-     * Processor used to set content-length and transfer-encoding
-     * headers.
-     */
-    private static RequestContent requestContentProcessor =
-            new RequestContent();
-
-    /**
-     * Instantiates a new Request.
-     * @param method GET/POST/PUT
-     * @param host The server that will handle this request
-     * @param path path part of URI
-     * @param bodyProvider InputStream providing HTTP body, null if none
-     * @param bodyLength length of body, must be 0 if bodyProvider is null
-     * @param eventHandler request will make progress callbacks on
-     * this interface
-     * @param headers reqeust headers
-     */
-    Request(String method, HttpHost host, HttpHost proxyHost, String path,
-            InputStream bodyProvider, int bodyLength,
-            EventHandler eventHandler,
-            Map<String, String> headers) {
-        mEventHandler = eventHandler;
-        mHost = host;
-        mProxyHost = proxyHost;
-        mPath = path;
-        mBodyProvider = bodyProvider;
-        mBodyLength = bodyLength;
-
-        if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
-            mHttpRequest = new BasicHttpRequest(method, getUri());
-        } else {
-            mHttpRequest = new BasicHttpEntityEnclosingRequest(
-                    method, getUri());
-            // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
-            // By using BasicHttpEntityEnclosingRequest, it will set up the
-            // correct content-length, content-type and content-encoding.
-            if (bodyProvider != null) {
-                setBodyProvider(bodyProvider, bodyLength);
-            }
-        }
-        addHeader(HOST_HEADER, getHostPort());
-
-        /* FIXME: if webcore will make the root document a
-           high-priority request, we can ask for gzip encoding only on
-           high priority reqs (saving the trouble for images, etc) */
-        addHeader(ACCEPT_ENCODING_HEADER, "gzip");
-        addHeaders(headers);
-    }
-
-    /**
-     * @param pause True if the load should be paused.
-     */
-    synchronized void setLoadingPaused(boolean pause) {
-        mLoadingPaused = pause;
-
-        // Wake up the paused thread if we're unpausing the load.
-        if (!mLoadingPaused) {
-            notify();
-        }
-    }
-
-    /**
-     * @param connection Request served by this connection
-     */
-    void setConnection(Connection connection) {
-        mConnection = connection;
-    }
-
-    /* package */ EventHandler getEventHandler() {
-        return mEventHandler;
-    }
-
-    /**
-     * Add header represented by given pair to request.  Header will
-     * be formatted in request as "name: value\r\n".
-     * @param name of header
-     * @param value of header
-     */
-    void addHeader(String name, String value) {
-        if (name == null) {
-            String damage = "Null http header name";
-            HttpLog.e(damage);
-            throw new NullPointerException(damage);
-        }
-        if (value == null || value.length() == 0) {
-            String damage = "Null or empty value for header \"" + name + "\"";
-            HttpLog.e(damage);
-            throw new RuntimeException(damage);
-        }
-        mHttpRequest.addHeader(name, value);
-    }
-
-    /**
-     * Add all headers in given map to this request.  This is a helper
-     * method: it calls addHeader for each pair in the map.
-     */
-    void addHeaders(Map<String, String> headers) {
-        if (headers == null) {
-            return;
-        }
-
-        Entry<String, String> entry;
-        Iterator<Entry<String, String>> i = headers.entrySet().iterator();
-        while (i.hasNext()) {
-            entry = i.next();
-            addHeader(entry.getKey(), entry.getValue());
-        }
-    }
-
-    /**
-     * Send the request line and headers
-     */
-    void sendRequest(AndroidHttpClientConnection httpClientConnection)
-            throws HttpException, IOException {
-
-        if (mCancelled) return; // don't send cancelled requests
-
-        if (HttpLog.LOGV) {
-            HttpLog.v("Request.sendRequest() " + mHost.getSchemeName() + "://" + getHostPort());
-            // HttpLog.v(mHttpRequest.getRequestLine().toString());
-            if (false) {
-                Iterator i = mHttpRequest.headerIterator();
-                while (i.hasNext()) {
-                    Header header = (Header)i.next();
-                    HttpLog.v(header.getName() + ": " + header.getValue());
-                }
-            }
-        }
-
-        requestContentProcessor.process(mHttpRequest,
-                                        mConnection.getHttpContext());
-        httpClientConnection.sendRequestHeader(mHttpRequest);
-        if (mHttpRequest instanceof HttpEntityEnclosingRequest) {
-            httpClientConnection.sendRequestEntity(
-                    (HttpEntityEnclosingRequest) mHttpRequest);
-        }
-
-        if (HttpLog.LOGV) {
-            HttpLog.v("Request.requestSent() " + mHost.getSchemeName() + "://" + getHostPort() + mPath);
-        }
-    }
-
-
-    /**
-     * Receive a single http response.
-     *
-     * @param httpClientConnection the request to receive the response for.
-     */
-    void readResponse(AndroidHttpClientConnection httpClientConnection)
-            throws IOException, ParseException {
-
-        if (mCancelled) return; // don't send cancelled requests
-
-        StatusLine statusLine = null;
-        boolean hasBody = false;
-        httpClientConnection.flush();
-        int statusCode = 0;
-
-        Headers header = new Headers();
-        do {
-            statusLine = httpClientConnection.parseResponseHeader(header);
-            statusCode = statusLine.getStatusCode();
-        } while (statusCode < HttpStatus.SC_OK);
-        if (HttpLog.LOGV) HttpLog.v(
-                "Request.readResponseStatus() " +
-                statusLine.toString().length() + " " + statusLine);
-
-        ProtocolVersion v = statusLine.getProtocolVersion();
-        mEventHandler.status(v.getMajor(), v.getMinor(),
-                statusCode, statusLine.getReasonPhrase());
-        mEventHandler.headers(header);
-        HttpEntity entity = null;
-        hasBody = canResponseHaveBody(mHttpRequest, statusCode);
-
-        if (hasBody)
-            entity = httpClientConnection.receiveResponseEntity(header);
-
-        // restrict the range request to the servers claiming that they are
-        // accepting ranges in bytes
-        boolean supportPartialContent = "bytes".equalsIgnoreCase(header
-                .getAcceptRanges());
-
-        if (entity != null) {
-            InputStream is = entity.getContent();
-
-            // process gzip content encoding
-            Header contentEncoding = entity.getContentEncoding();
-            InputStream nis = null;
-            byte[] buf = null;
-            int count = 0;
-            try {
-                if (contentEncoding != null &&
-                    contentEncoding.getValue().equals("gzip")) {
-                    nis = new GZIPInputStream(is);
-                } else {
-                    nis = is;
-                }
-
-                /* accumulate enough data to make it worth pushing it
-                 * up the stack */
-                buf = mConnection.getBuf();
-                int len = 0;
-                int lowWater = buf.length / 2;
-                while (len != -1) {
-                    synchronized(this) {
-                        while (mLoadingPaused) {
-                            // Put this (network loading) thread to sleep if WebCore
-                            // has asked us to. This can happen with plugins for
-                            // example, if we are streaming data but the plugin has
-                            // filled its internal buffers.
-                            try {
-                                wait();
-                            } catch (InterruptedException e) {
-                                HttpLog.e("Interrupted exception whilst "
-                                    + "network thread paused at WebCore's request."
-                                    + " " + e.getMessage());
-                            }
-                        }
-                    }
-
-                    len = nis.read(buf, count, buf.length - count);
-
-                    if (len != -1) {
-                        count += len;
-                        if (supportPartialContent) mReceivedBytes += len;
-                    }
-                    if (len == -1 || count >= lowWater) {
-                        if (HttpLog.LOGV) HttpLog.v("Request.readResponse() " + count);
-                        mEventHandler.data(buf, count);
-                        count = 0;
-                    }
-                }
-            } catch (EOFException e) {
-                /* InflaterInputStream throws an EOFException when the
-                   server truncates gzipped content.  Handle this case
-                   as we do truncated non-gzipped content: no error */
-                if (count > 0) {
-                    // if there is uncommited content, we should commit them
-                    mEventHandler.data(buf, count);
-                }
-                if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
-            } catch(IOException e) {
-                // don't throw if we have a non-OK status code
-                if (statusCode == HttpStatus.SC_OK
-                        || statusCode == HttpStatus.SC_PARTIAL_CONTENT) {
-                    if (supportPartialContent && count > 0) {
-                        // if there is uncommited content, we should commit them
-                        // as we will continue the request
-                        mEventHandler.data(buf, count);
-                    }
-                    throw e;
-                }
-            } finally {
-                if (nis != null) {
-                    nis.close();
-                }
-            }
-        }
-        mConnection.setCanPersist(entity, statusLine.getProtocolVersion(),
-                header.getConnectionType());
-        mEventHandler.endData();
-        complete();
-
-        if (HttpLog.LOGV) HttpLog.v("Request.readResponse(): done " +
-                                    mHost.getSchemeName() + "://" + getHostPort() + mPath);
-    }
-
-    /**
-     * Data will not be sent to or received from server after cancel()
-     * call.  Does not close connection--use close() below for that.
-     *
-     * Called by RequestHandle from non-network thread
-     */
-    synchronized void cancel() {
-        if (HttpLog.LOGV) {
-            HttpLog.v("Request.cancel(): " + getUri());
-        }
-
-        // Ensure that the network thread is not blocked by a hanging request from WebCore to
-        // pause the load.
-        mLoadingPaused = false;
-        notify();
-
-        mCancelled = true;
-        if (mConnection != null) {
-            mConnection.cancel();
-        }
-    }
-
-    String getHostPort() {
-        String myScheme = mHost.getSchemeName();
-        int myPort = mHost.getPort();
-
-        // Only send port when we must... many servers can't deal with it
-        if (myPort != 80 && myScheme.equals("http") ||
-            myPort != 443 && myScheme.equals("https")) {
-            return mHost.toHostString();
-        } else {
-            return mHost.getHostName();
-        }
-    }
-
-    String getUri() {
-        if (mProxyHost == null ||
-            mHost.getSchemeName().equals("https")) {
-            return mPath;
-        }
-        return mHost.getSchemeName() + "://" + getHostPort() + mPath;
-    }
-
-    /**
-     * for debugging
-     */
-    public String toString() {
-        return mPath;
-    }
-
-
-    /**
-     * If this request has been sent once and failed, it must be reset
-     * before it can be sent again.
-     */
-    void reset() {
-        /* clear content-length header */
-        mHttpRequest.removeHeaders(CONTENT_LENGTH_HEADER);
-
-        if (mBodyProvider != null) {
-            try {
-                mBodyProvider.reset();
-            } catch (IOException ex) {
-                if (HttpLog.LOGV) HttpLog.v(
-                        "failed to reset body provider " +
-                        getUri());
-            }
-            setBodyProvider(mBodyProvider, mBodyLength);
-        }
-
-        if (mReceivedBytes > 0) {
-            // reset the fail count as we continue the request
-            mFailCount = 0;
-            // set the "Range" header to indicate that the retry will continue
-            // instead of restarting the request
-            HttpLog.v("*** Request.reset() to range:" + mReceivedBytes);
-            mHttpRequest.setHeader("Range", "bytes=" + mReceivedBytes + "-");
-        }
-    }
-
-    /**
-     * Pause thread request completes.  Used for synchronous requests,
-     * and testing
-     */
-    void waitUntilComplete() {
-        synchronized (mClientResource) {
-            try {
-                if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete()");
-                mClientResource.wait();
-                if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete() done waiting");
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    void complete() {
-        synchronized (mClientResource) {
-            mClientResource.notifyAll();
-        }
-    }
-
-    /**
-     * Decide whether a response comes with an entity.
-     * The implementation in this class is based on RFC 2616.
-     * Unknown methods and response codes are supposed to
-     * indicate responses with an entity.
-     * <br/>
-     * Derived executors can override this method to handle
-     * methods and response codes not specified in RFC 2616.
-     *
-     * @param request   the request, to obtain the executed method
-     * @param response  the response, to obtain the status code
-     */
-
-    private static boolean canResponseHaveBody(final HttpRequest request,
-                                               final int status) {
-
-        if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
-            return false;
-        }
-        return status >= HttpStatus.SC_OK
-            && status != HttpStatus.SC_NO_CONTENT
-            && status != HttpStatus.SC_NOT_MODIFIED;
-    }
-
-    /**
-     * Supply an InputStream that provides the body of a request.  It's
-     * not great that the caller must also provide the length of the data
-     * returned by that InputStream, but the client needs to know up
-     * front, and I'm not sure how to get this out of the InputStream
-     * itself without a costly readthrough.  I'm not sure skip() would
-     * do what we want.  If you know a better way, please let me know.
-     */
-    private void setBodyProvider(InputStream bodyProvider, int bodyLength) {
-        if (!bodyProvider.markSupported()) {
-            throw new IllegalArgumentException(
-                    "bodyProvider must support mark()");
-        }
-        // Mark beginning of stream
-        bodyProvider.mark(Integer.MAX_VALUE);
-
-        ((BasicHttpEntityEnclosingRequest)mHttpRequest).setEntity(
-                new InputStreamEntity(bodyProvider, bodyLength));
-    }
-
-
-    /**
-     * Handles SSL error(s) on the way down from the user (the user
-     * has already provided their feedback).
-     */
-    public void handleSslErrorResponse(boolean proceed) {
-        HttpsConnection connection = (HttpsConnection)(mConnection);
-        if (connection != null) {
-            connection.restartConnection(proceed);
-        }
-    }
-
-    /**
-     * Helper: calls error() on eventhandler with appropriate message
-     * This should not be called before the mConnection is set.
-     */
-    void error(int errorId, int resourceId) {
-        mEventHandler.error(
-                errorId,
-                mConnection.mContext.getText(
-                        resourceId).toString());
-    }
-
-}
diff --git a/core/java/android/net/http/RequestFeeder.java b/core/java/android/net/http/RequestFeeder.java
deleted file mode 100644
index 34ca267..0000000
--- a/core/java/android/net/http/RequestFeeder.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Supplies Requests to a Connection
- */
-
-package android.net.http;
-
-import org.apache.http.HttpHost;
-
-/**
- * {@hide}
- */
-interface RequestFeeder {
-
-    Request getRequest();
-    Request getRequest(HttpHost host);
-
-    /**
-     * @return true if a request for this host is available
-     */
-    boolean haveRequest(HttpHost host);
-
-    /**
-     * Put request back on head of queue
-     */
-    void requeueRequest(Request request);
-}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
deleted file mode 100644
index f23f69c..0000000
--- a/core/java/android/net/http/RequestHandle.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.http;
-
-import android.net.ParseException;
-import android.net.WebAddress;
-import junit.framework.Assert;
-import android.webkit.CookieManager;
-
-import org.apache.commons.codec.binary.Base64;
-
-import java.io.InputStream;
-import java.lang.Math;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-/**
- * RequestHandle: handles a request session that may include multiple
- * redirects, HTTP authentication requests, etc.
- * 
- * {@hide}
- */
-public class RequestHandle {
-
-    private String        mUrl;
-    private WebAddress    mUri;
-    private String        mMethod;
-    private Map<String, String> mHeaders;
-    private RequestQueue  mRequestQueue;
-    private Request       mRequest;
-    private InputStream   mBodyProvider;
-    private int           mBodyLength;
-    private int           mRedirectCount = 0;
-    // Used only with synchronous requests.
-    private Connection    mConnection;
-
-    private final static String AUTHORIZATION_HEADER = "Authorization";
-    private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
-
-    public final static int MAX_REDIRECT_COUNT = 16;
-
-    /**
-     * Creates a new request session.
-     */
-    public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
-            String method, Map<String, String> headers,
-            InputStream bodyProvider, int bodyLength, Request request) {
-
-        if (headers == null) {
-            headers = new HashMap<String, String>();
-        }
-        mHeaders = headers;
-        mBodyProvider = bodyProvider;
-        mBodyLength = bodyLength;
-        mMethod = method == null? "GET" : method;
-
-        mUrl = url;
-        mUri = uri;
-
-        mRequestQueue = requestQueue;
-
-        mRequest = request;
-    }
-
-    /**
-     * Creates a new request session with a given Connection. This connection
-     * is used during a synchronous load to handle this request.
-     */
-    public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
-            String method, Map<String, String> headers,
-            InputStream bodyProvider, int bodyLength, Request request,
-            Connection conn) {
-        this(requestQueue, url, uri, method, headers, bodyProvider, bodyLength,
-                request);
-        mConnection = conn;
-    }
-
-    /**
-     * Cancels this request
-     */
-    public void cancel() {
-        if (mRequest != null) {
-            mRequest.cancel();
-        }
-    }
-
-    /**
-     * Pauses the loading of this request. For example, called from the WebCore thread
-     * when the plugin can take no more data.
-     */
-    public void pauseRequest(boolean pause) {
-        if (mRequest != null) {
-            mRequest.setLoadingPaused(pause);
-        }
-    }
-
-    /**
-     * Handles SSL error(s) on the way down from the user (the user
-     * has already provided their feedback).
-     */
-    public void handleSslErrorResponse(boolean proceed) {
-        if (mRequest != null) {
-            mRequest.handleSslErrorResponse(proceed);
-        }
-    }
-
-    /**
-     * @return true if we've hit the max redirect count
-     */
-    public boolean isRedirectMax() {
-        return mRedirectCount >= MAX_REDIRECT_COUNT;
-    }
-
-    public int getRedirectCount() {
-        return mRedirectCount;
-    }
-
-    public void setRedirectCount(int count) {
-        mRedirectCount = count;
-    }
-
-    /**
-     * Create and queue a redirect request.
-     *
-     * @param redirectTo URL to redirect to
-     * @param statusCode HTTP status code returned from original request
-     * @param cacheHeaders Cache header for redirect URL
-     * @return true if setup succeeds, false otherwise (redirect loop
-     * count exceeded, body provider unable to rewind on 307 redirect)
-     */
-    public boolean setupRedirect(String redirectTo, int statusCode,
-            Map<String, String> cacheHeaders) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("RequestHandle.setupRedirect(): redirectCount " +
-                  mRedirectCount);
-        }
-
-        // be careful and remove authentication headers, if any
-        mHeaders.remove(AUTHORIZATION_HEADER);
-        mHeaders.remove(PROXY_AUTHORIZATION_HEADER);
-
-        if (++mRedirectCount == MAX_REDIRECT_COUNT) {
-            // Way too many redirects -- fail out
-            if (HttpLog.LOGV) HttpLog.v(
-                    "RequestHandle.setupRedirect(): too many redirects " +
-                    mRequest);
-            mRequest.error(EventHandler.ERROR_REDIRECT_LOOP,
-                           com.android.internal.R.string.httpErrorRedirectLoop);
-            return false;
-        }
-
-        if (mUrl.startsWith("https:") && redirectTo.startsWith("http:")) {
-            // implement http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
-            if (HttpLog.LOGV) {
-                HttpLog.v("blowing away the referer on an https -> http redirect");
-            }
-            mHeaders.remove("Referer");
-        }
-
-        mUrl = redirectTo;
-        try {
-            mUri = new WebAddress(mUrl);
-        } catch (ParseException e) {
-            e.printStackTrace();
-        }
-
-        // update the "Cookie" header based on the redirected url
-        mHeaders.remove("Cookie");
-        String cookie = CookieManager.getInstance().getCookie(mUri);
-        if (cookie != null && cookie.length() > 0) {
-            mHeaders.put("Cookie", cookie);
-        }
-
-        if ((statusCode == 302 || statusCode == 303) && mMethod.equals("POST")) {
-            if (HttpLog.LOGV) {
-                HttpLog.v("replacing POST with GET on redirect to " + redirectTo);
-            }
-            mMethod = "GET";
-        }
-        /* Only repost content on a 307.  If 307, reset the body
-           provider so we can replay the body */
-        if (statusCode == 307) {
-            try {
-                if (mBodyProvider != null) mBodyProvider.reset();
-            } catch (java.io.IOException ex) {
-                if (HttpLog.LOGV) {
-                    HttpLog.v("setupRedirect() failed to reset body provider");
-                }
-                return false;
-            }
-
-        } else {
-            mHeaders.remove("Content-Type");
-            mBodyProvider = null;
-        }
-
-        // Update the cache headers for this URL
-        mHeaders.putAll(cacheHeaders);
-
-        createAndQueueNewRequest();
-        return true;
-    }
-
-    /**
-     * Create and queue an HTTP authentication-response (basic) request.
-     */
-    public void setupBasicAuthResponse(boolean isProxy, String username, String password) {
-        String response = computeBasicAuthResponse(username, password);
-        if (HttpLog.LOGV) {
-            HttpLog.v("setupBasicAuthResponse(): response: " + response);
-        }
-        mHeaders.put(authorizationHeader(isProxy), "Basic " + response);
-        setupAuthResponse();
-    }
-
-    /**
-     * Create and queue an HTTP authentication-response (digest) request.
-     */
-    public void setupDigestAuthResponse(boolean isProxy,
-                                        String username,
-                                        String password,
-                                        String realm,
-                                        String nonce,
-                                        String QOP,
-                                        String algorithm,
-                                        String opaque) {
-
-        String response = computeDigestAuthResponse(
-                username, password, realm, nonce, QOP, algorithm, opaque);
-        if (HttpLog.LOGV) {
-            HttpLog.v("setupDigestAuthResponse(): response: " + response);
-        }
-        mHeaders.put(authorizationHeader(isProxy), "Digest " + response);
-        setupAuthResponse();
-    }
-
-    private void setupAuthResponse() {
-        try {
-            if (mBodyProvider != null) mBodyProvider.reset();
-        } catch (java.io.IOException ex) {
-            if (HttpLog.LOGV) {
-                HttpLog.v("setupAuthResponse() failed to reset body provider");
-            }
-        }
-        createAndQueueNewRequest();
-    }
-
-    /**
-     * @return HTTP request method (GET, PUT, etc).
-     */
-    public String getMethod() {
-        return mMethod;
-    }
-
-    /**
-     * @return Basic-scheme authentication response: BASE64(username:password).
-     */
-    public static String computeBasicAuthResponse(String username, String password) {
-        Assert.assertNotNull(username);
-        Assert.assertNotNull(password);
-
-        // encode username:password to base64
-        return new String(Base64.encodeBase64((username + ':' + password).getBytes()));
-    }
-
-    public void waitUntilComplete() {
-        mRequest.waitUntilComplete();
-    }
-
-    public void processRequest() {
-        if (mConnection != null) {
-            mConnection.processRequests(mRequest);
-        }
-    }
-
-    /**
-     * @return Digest-scheme authentication response.
-     */
-    private String computeDigestAuthResponse(String username,
-                                             String password,
-                                             String realm,
-                                             String nonce,
-                                             String QOP,
-                                             String algorithm,
-                                             String opaque) {
-
-        Assert.assertNotNull(username);
-        Assert.assertNotNull(password);
-        Assert.assertNotNull(realm);
-
-        String A1 = username + ":" + realm + ":" + password;
-        String A2 = mMethod  + ":" + mUrl;
-
-        // because we do not preemptively send authorization headers, nc is always 1
-        String nc = "00000001";
-        String cnonce = computeCnonce();
-        String digest = computeDigest(A1, A2, nonce, QOP, nc, cnonce);
-
-        String response = "";
-        response += "username=" + doubleQuote(username) + ", ";
-        response += "realm="    + doubleQuote(realm)    + ", ";
-        response += "nonce="    + doubleQuote(nonce)    + ", ";
-        response += "uri="      + doubleQuote(mUrl)     + ", ";
-        response += "response=" + doubleQuote(digest) ;
-
-        if (opaque     != null) {
-            response += ", opaque=" + doubleQuote(opaque);
-        }
-
-         if (algorithm != null) {
-            response += ", algorithm=" +  algorithm;
-        }
-
-        if (QOP        != null) {
-            response += ", qop=" + QOP + ", nc=" + nc + ", cnonce=" + doubleQuote(cnonce);
-        }
-
-        return response;
-    }
-
-    /**
-     * @return The right authorization header (dependeing on whether it is a proxy or not).
-     */
-    public static String authorizationHeader(boolean isProxy) {
-        if (!isProxy) {
-            return AUTHORIZATION_HEADER;
-        } else {
-            return PROXY_AUTHORIZATION_HEADER;
-        }
-    }
-
-    /**
-     * @return Double-quoted MD5 digest.
-     */
-    private String computeDigest(
-        String A1, String A2, String nonce, String QOP, String nc, String cnonce) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("computeDigest(): QOP: " + QOP);
-        }
-
-        if (QOP == null) {
-            return KD(H(A1), nonce + ":" + H(A2));
-        } else {
-            if (QOP.equalsIgnoreCase("auth")) {
-                return KD(H(A1), nonce + ":" + nc + ":" + cnonce + ":" + QOP + ":" + H(A2));
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * @return MD5 hash of concat(secret, ":", data).
-     */
-    private String KD(String secret, String data) {
-        return H(secret + ":" + data);
-    }
-
-    /**
-     * @return MD5 hash of param.
-     */
-    private String H(String param) {
-        if (param != null) {
-            try {
-                MessageDigest md5 = MessageDigest.getInstance("MD5");
-
-                byte[] d = md5.digest(param.getBytes());
-                if (d != null) {
-                    return bufferToHex(d);
-                }
-            } catch (NoSuchAlgorithmException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * @return HEX buffer representation.
-     */
-    private String bufferToHex(byte[] buffer) {
-        final char hexChars[] =
-            { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
-
-        if (buffer != null) {
-            int length = buffer.length;
-            if (length > 0) {
-                StringBuilder hex = new StringBuilder(2 * length);
-
-                for (int i = 0; i < length; ++i) {
-                    byte l = (byte) (buffer[i] & 0x0F);
-                    byte h = (byte)((buffer[i] & 0xF0) >> 4);
-
-                    hex.append(hexChars[h]);
-                    hex.append(hexChars[l]);
-                }
-
-                return hex.toString();
-            } else {
-                return "";
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Computes a random cnonce value based on the current time.
-     */
-    private String computeCnonce() {
-        Random rand = new Random();
-        int nextInt = rand.nextInt();
-        nextInt = (nextInt == Integer.MIN_VALUE) ?
-                Integer.MAX_VALUE : Math.abs(nextInt);
-        return Integer.toString(nextInt, 16);
-    }
-
-    /**
-     * "Double-quotes" the argument.
-     */
-    private String doubleQuote(String param) {
-        if (param != null) {
-            return "\"" + param + "\"";
-        }
-
-        return null;
-    }
-
-    /**
-     * Creates and queues new request.
-     */
-    private void createAndQueueNewRequest() {
-        // mConnection is non-null if and only if the requests are synchronous.
-        if (mConnection != null) {
-            RequestHandle newHandle = mRequestQueue.queueSynchronousRequest(
-                    mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
-                    mBodyProvider, mBodyLength);
-            mRequest = newHandle.mRequest;
-            mConnection = newHandle.mConnection;
-            newHandle.processRequest();
-            return;
-        }
-        mRequest = mRequestQueue.queueRequest(
-                mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
-                mBodyProvider,
-                mBodyLength).mRequest;
-    }
-}
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
deleted file mode 100644
index 7d2da1b..0000000
--- a/core/java/android/net/http/RequestQueue.java
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * High level HTTP Interface
- * Queues requests as necessary
- */
-
-package android.net.http;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.Proxy;
-import android.net.WebAddress;
-import android.util.Log;
-
-import java.io.InputStream;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Map;
-
-import org.apache.http.HttpHost;
-
-/**
- * {@hide}
- */
-public class RequestQueue implements RequestFeeder {
-
-
-    /**
-     * Requests, indexed by HttpHost (scheme, host, port)
-     */
-    private final LinkedHashMap<HttpHost, LinkedList<Request>> mPending;
-    private final Context mContext;
-    private final ActivePool mActivePool;
-    private final ConnectivityManager mConnectivityManager;
-
-    private HttpHost mProxyHost = null;
-    private BroadcastReceiver mProxyChangeReceiver;
-
-    /* default simultaneous connection count */
-    private static final int CONNECTION_COUNT = 4;
-
-    /**
-     * This class maintains active connection threads
-     */
-    class ActivePool implements ConnectionManager {
-        /** Threads used to process requests */
-        ConnectionThread[] mThreads;
-
-        IdleCache mIdleCache;
-
-        private int mTotalRequest;
-        private int mTotalConnection;
-        private int mConnectionCount;
-
-        ActivePool(int connectionCount) {
-            mIdleCache = new IdleCache();
-            mConnectionCount = connectionCount;
-            mThreads = new ConnectionThread[mConnectionCount];
-
-            for (int i = 0; i < mConnectionCount; i++) {
-                mThreads[i] = new ConnectionThread(
-                        mContext, i, this, RequestQueue.this);
-            }
-        }
-
-        void startup() {
-            for (int i = 0; i < mConnectionCount; i++) {
-                mThreads[i].start();
-            }
-        }
-
-        void shutdown() {
-            for (int i = 0; i < mConnectionCount; i++) {
-                mThreads[i].requestStop();
-            }
-        }
-
-        void startConnectionThread() {
-            synchronized (RequestQueue.this) {
-                RequestQueue.this.notify();
-            }
-        }
-
-        public void startTiming() {
-            for (int i = 0; i < mConnectionCount; i++) {
-                ConnectionThread rt = mThreads[i];
-                rt.mCurrentThreadTime = -1;
-                rt.mTotalThreadTime = 0;
-            }
-            mTotalRequest = 0;
-            mTotalConnection = 0;
-        }
-
-        public void stopTiming() {
-            int totalTime = 0;
-            for (int i = 0; i < mConnectionCount; i++) {
-                ConnectionThread rt = mThreads[i];
-                if (rt.mCurrentThreadTime != -1) {
-                    totalTime += rt.mTotalThreadTime;
-                }
-                rt.mCurrentThreadTime = 0;
-            }
-            Log.d("Http", "Http thread used " + totalTime + " ms " + " for "
-                    + mTotalRequest + " requests and " + mTotalConnection
-                    + " new connections");
-        }
-
-        void logState() {
-            StringBuilder dump = new StringBuilder();
-            for (int i = 0; i < mConnectionCount; i++) {
-                dump.append(mThreads[i] + "\n");
-            }
-            HttpLog.v(dump.toString());
-        }
-
-
-        public HttpHost getProxyHost() {
-            return mProxyHost;
-        }
-
-        /**
-         * Turns off persistence on all live connections
-         */
-        void disablePersistence() {
-            for (int i = 0; i < mConnectionCount; i++) {
-                Connection connection = mThreads[i].mConnection;
-                if (connection != null) connection.setCanPersist(false);
-            }
-            mIdleCache.clear();
-        }
-
-        /* Linear lookup -- okay for small thread counts.  Might use
-           private HashMap<HttpHost, LinkedList<ConnectionThread>> mActiveMap;
-           if this turns out to be a hotspot */
-        ConnectionThread getThread(HttpHost host) {
-            synchronized(RequestQueue.this) {
-                for (int i = 0; i < mThreads.length; i++) {
-                    ConnectionThread ct = mThreads[i];
-                    Connection connection = ct.mConnection;
-                    if (connection != null && connection.mHost.equals(host)) {
-                        return ct;
-                    }
-                }
-            }
-            return null;
-        }
-
-        public Connection getConnection(Context context, HttpHost host) {
-            host = RequestQueue.this.determineHost(host);
-            Connection con = mIdleCache.getConnection(host);
-            if (con == null) {
-                mTotalConnection++;
-                con = Connection.getConnection(mContext, host, mProxyHost,
-                        RequestQueue.this);
-            }
-            return con;
-        }
-        public boolean recycleConnection(Connection connection) {
-            return mIdleCache.cacheConnection(connection.getHost(), connection);
-        }
-
-    }
-
-    /**
-     * A RequestQueue class instance maintains a set of queued
-     * requests.  It orders them, makes the requests against HTTP
-     * servers, and makes callbacks to supplied eventHandlers as data
-     * is read.  It supports request prioritization, connection reuse
-     * and pipelining.
-     *
-     * @param context application context
-     */
-    public RequestQueue(Context context) {
-        this(context, CONNECTION_COUNT);
-    }
-
-    /**
-     * A RequestQueue class instance maintains a set of queued
-     * requests.  It orders them, makes the requests against HTTP
-     * servers, and makes callbacks to supplied eventHandlers as data
-     * is read.  It supports request prioritization, connection reuse
-     * and pipelining.
-     *
-     * @param context application context
-     * @param connectionCount The number of simultaneous connections 
-     */
-    public RequestQueue(Context context, int connectionCount) {
-        mContext = context;
-
-        mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32);
-
-        mActivePool = new ActivePool(connectionCount);
-        mActivePool.startup();
-
-        mConnectivityManager = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-    }
-
-    /**
-     * Enables data state and proxy tracking
-     */
-    public synchronized void enablePlatformNotifications() {
-        if (HttpLog.LOGV) HttpLog.v("RequestQueue.enablePlatformNotifications() network");
-
-        if (mProxyChangeReceiver == null) {
-            mProxyChangeReceiver =
-                    new BroadcastReceiver() {
-                        @Override
-                        public void onReceive(Context ctx, Intent intent) {
-                            setProxyConfig();
-                        }
-                    };
-            mContext.registerReceiver(mProxyChangeReceiver,
-                                      new IntentFilter(Proxy.PROXY_CHANGE_ACTION));
-        }
-        // we need to resample the current proxy setup
-        setProxyConfig();
-    }
-
-    /**
-     * If platform notifications have been enabled, call this method
-     * to disable before destroying RequestQueue
-     */
-    public synchronized void disablePlatformNotifications() {
-        if (HttpLog.LOGV) HttpLog.v("RequestQueue.disablePlatformNotifications() network");
-
-        if (mProxyChangeReceiver != null) {
-            mContext.unregisterReceiver(mProxyChangeReceiver);
-            mProxyChangeReceiver = null;
-        }
-    }
-
-    /**
-     * Because our IntentReceiver can run within a different thread,
-     * synchronize setting the proxy
-     */
-    private synchronized void setProxyConfig() {
-        NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
-        if (info != null && info.getType() == ConnectivityManager.TYPE_WIFI) {
-            mProxyHost = null;
-        } else {
-            String host = Proxy.getHost(mContext);
-            if (HttpLog.LOGV) HttpLog.v("RequestQueue.setProxyConfig " + host);
-            if (host == null) {
-                mProxyHost = null;
-            } else {
-                mActivePool.disablePersistence();
-                mProxyHost = new HttpHost(host, Proxy.getPort(mContext), "http");
-            }
-        }
-    }
-
-    /**
-     * used by webkit
-     * @return proxy host if set, null otherwise
-     */
-    public HttpHost getProxyHost() {
-        return mProxyHost;
-    }
-
-    /**
-     * Queues an HTTP request
-     * @param url The url to load.
-     * @param method "GET" or "POST."
-     * @param headers A hashmap of http headers.
-     * @param eventHandler The event handler for handling returned
-     * data.  Callbacks will be made on the supplied instance.
-     * @param bodyProvider InputStream providing HTTP body, null if none
-     * @param bodyLength length of body, must be 0 if bodyProvider is null
-     */
-    public RequestHandle queueRequest(
-            String url, String method,
-            Map<String, String> headers, EventHandler eventHandler,
-            InputStream bodyProvider, int bodyLength) {
-        WebAddress uri = new WebAddress(url);
-        return queueRequest(url, uri, method, headers, eventHandler,
-                            bodyProvider, bodyLength);
-    }
-
-    /**
-     * Queues an HTTP request
-     * @param url The url to load.
-     * @param uri The uri of the url to load.
-     * @param method "GET" or "POST."
-     * @param headers A hashmap of http headers.
-     * @param eventHandler The event handler for handling returned
-     * data.  Callbacks will be made on the supplied instance.
-     * @param bodyProvider InputStream providing HTTP body, null if none
-     * @param bodyLength length of body, must be 0 if bodyProvider is null
-     */
-    public RequestHandle queueRequest(
-            String url, WebAddress uri, String method, Map<String, String> headers,
-            EventHandler eventHandler,
-            InputStream bodyProvider, int bodyLength) {
-
-        if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri);
-
-        // Ensure there is an eventHandler set
-        if (eventHandler == null) {
-            eventHandler = new LoggingEventHandler();
-        }
-
-        /* Create and queue request */
-        Request req;
-        HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
-
-        // set up request
-        req = new Request(method, httpHost, mProxyHost, uri.getPath(), bodyProvider,
-                          bodyLength, eventHandler, headers);
-
-        queueRequest(req, false);
-
-        mActivePool.mTotalRequest++;
-
-        // dump();
-        mActivePool.startConnectionThread();
-
-        return new RequestHandle(
-                this, url, uri, method, headers, bodyProvider, bodyLength,
-                req);
-    }
-
-    private static class SyncFeeder implements RequestFeeder {
-        // This is used in the case where the request fails and needs to be
-        // requeued into the RequestFeeder.
-        private Request mRequest;
-        SyncFeeder() {
-        }
-        public Request getRequest() {
-            Request r = mRequest;
-            mRequest = null;
-            return r;
-        }
-        public Request getRequest(HttpHost host) {
-            return getRequest();
-        }
-        public boolean haveRequest(HttpHost host) {
-            return mRequest != null;
-        }
-        public void requeueRequest(Request r) {
-            mRequest = r;
-        }
-    }
-
-    public RequestHandle queueSynchronousRequest(String url, WebAddress uri,
-            String method, Map<String, String> headers,
-            EventHandler eventHandler, InputStream bodyProvider,
-            int bodyLength) {
-        if (HttpLog.LOGV) {
-            HttpLog.v("RequestQueue.dispatchSynchronousRequest " + uri);
-        }
-
-        HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
-
-        Request req = new Request(method, host, mProxyHost, uri.getPath(),
-                bodyProvider, bodyLength, eventHandler, headers);
-
-        // Open a new connection that uses our special RequestFeeder
-        // implementation.
-        host = determineHost(host);
-        Connection conn = Connection.getConnection(mContext, host, mProxyHost,
-                new SyncFeeder());
-
-        // TODO: I would like to process the request here but LoadListener
-        // needs a RequestHandle to process some messages.
-        return new RequestHandle(this, url, uri, method, headers, bodyProvider,
-                bodyLength, req, conn);
-
-    }
-
-    // Chooses between the proxy and the request's host.
-    private HttpHost determineHost(HttpHost host) {
-        // There used to be a comment in ConnectionThread about t-mob's proxy
-        // being really bad about https. But, HttpsConnection actually looks
-        // for a proxy and connects through it anyway. I think that this check
-        // is still valid because if a site is https, we will use
-        // HttpsConnection rather than HttpConnection if the proxy address is
-        // not secure.
-        return (mProxyHost == null || "https".equals(host.getSchemeName()))
-                ? host : mProxyHost;
-    }
-
-    /**
-     * @return true iff there are any non-active requests pending
-     */
-    synchronized boolean requestsPending() {
-        return !mPending.isEmpty();
-    }
-
-
-    /**
-     * debug tool: prints request queue to log
-     */
-    synchronized void dump() {
-        HttpLog.v("dump()");
-        StringBuilder dump = new StringBuilder();
-        int count = 0;
-        Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter;
-
-        // mActivePool.log(dump);
-
-        if (!mPending.isEmpty()) {
-            iter = mPending.entrySet().iterator();
-            while (iter.hasNext()) {
-                Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
-                String hostName = entry.getKey().getHostName();
-                StringBuilder line = new StringBuilder("p" + count++ + " " + hostName + " ");
-
-                LinkedList<Request> reqList = entry.getValue();
-                ListIterator reqIter = reqList.listIterator(0);
-                while (iter.hasNext()) {
-                    Request request = (Request)iter.next();
-                    line.append(request + " ");
-                }
-                dump.append(line);
-                dump.append("\n");
-            }
-        }
-        HttpLog.v(dump.toString());
-    }
-
-    /*
-     * RequestFeeder implementation
-     */
-    public synchronized Request getRequest() {
-        Request ret = null;
-
-        if (!mPending.isEmpty()) {
-            ret = removeFirst(mPending);
-        }
-        if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest() => " + ret);
-        return ret;
-    }
-
-    /**
-     * @return a request for given host if possible
-     */
-    public synchronized Request getRequest(HttpHost host) {
-        Request ret = null;
-
-        if (mPending.containsKey(host)) {
-            LinkedList<Request> reqList = mPending.get(host);
-            ret = reqList.removeFirst();
-            if (reqList.isEmpty()) {
-                mPending.remove(host);
-            }
-        }
-        if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest(" + host + ") => " + ret);
-        return ret;
-    }
-
-    /**
-     * @return true if a request for this host is available
-     */
-    public synchronized boolean haveRequest(HttpHost host) {
-        return mPending.containsKey(host);
-    }
-
-    /**
-     * Put request back on head of queue
-     */
-    public void requeueRequest(Request request) {
-        queueRequest(request, true);
-    }
-
-    /**
-     * This must be called to cleanly shutdown RequestQueue
-     */
-    public void shutdown() {
-        mActivePool.shutdown();
-    }
-
-    protected synchronized void queueRequest(Request request, boolean head) {
-        HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost;
-        LinkedList<Request> reqList;
-        if (mPending.containsKey(host)) {
-            reqList = mPending.get(host);
-        } else {
-            reqList = new LinkedList<Request>();
-            mPending.put(host, reqList);
-        }
-        if (head) {
-            reqList.addFirst(request);
-        } else {
-            reqList.add(request);
-        }
-    }
-
-
-    public void startTiming() {
-        mActivePool.startTiming();
-    }
-
-    public void stopTiming() {
-        mActivePool.stopTiming();
-    }
-
-    /* helper */
-    private Request removeFirst(LinkedHashMap<HttpHost, LinkedList<Request>> requestQueue) {
-        Request ret = null;
-        Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = requestQueue.entrySet().iterator();
-        if (iter.hasNext()) {
-            Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
-            LinkedList<Request> reqList = entry.getValue();
-            ret = reqList.removeFirst();
-            if (reqList.isEmpty()) {
-                requestQueue.remove(entry.getKey());
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * This interface is exposed to each connection
-     */
-    interface ConnectionManager {
-        HttpHost getProxyHost();
-        Connection getConnection(Context context, HttpHost host);
-        boolean recycleConnection(Connection connection);
-    }
-}
diff --git a/core/java/android/net/http/Timer.java b/core/java/android/net/http/Timer.java
deleted file mode 100644
index cc15a30..0000000
--- a/core/java/android/net/http/Timer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.http;
-
-import android.os.SystemClock;
-
-/**
- * {@hide}
- * Debugging tool
- */
-class Timer {
-
-    private long mStart;
-    private long mLast;
-
-    public Timer() {
-        mStart = mLast = SystemClock.uptimeMillis();
-    }
-
-    public void mark(String message) {
-        long now = SystemClock.uptimeMillis();
-        if (HttpLog.LOGV) {
-            HttpLog.v(message + " " + (now - mLast) + " total " + (now - mStart));
-        }
-        mLast = now;
-    }
-}
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 6a63a0c..eb4ceda 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -22,8 +22,6 @@
 import java.security.cert.X509Certificate;
 import java.util.List;
 
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLSocket;
 import javax.net.ssl.X509TrustManager;
 
 /**
@@ -36,7 +34,7 @@
  */
 public class X509TrustManagerExtensions {
 
-    TrustManagerImpl mDelegate;
+    final TrustManagerImpl mDelegate;
 
     /**
      * Constructs a new X509TrustManagerExtensions wrapper.
@@ -48,6 +46,7 @@
         if (tm instanceof TrustManagerImpl) {
             mDelegate = (TrustManagerImpl) tm;
         } else {
+            mDelegate = null;
             throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() +
                     " which is not a supported type of X509TrustManager");
         }
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 5852ce4..fdccaae 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -51,7 +51,7 @@
  * {@link Ndef} on NFC Forum Tag Types 1-4, and implement all NDEF operations
  * as defined in this class.
  *
- * <p>Some vendors have there own well defined specifications for storing NDEF data
+ * <p>Some vendors have their own well defined specifications for storing NDEF data
  * on tags that do not fall into the above categories. Android devices with NFC
  * should enumerate and implement {@link Ndef} under these vendor specifications
  * where possible, but it is not mandatory. {@link #getType} returns a String
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 7785f2b..47e8e69 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -301,7 +301,7 @@
                 } catch (InterruptedException e) {
                     android.util.Log.w(LOG_TAG, e);
                 } catch (ExecutionException e) {
-                    throw new RuntimeException("An error occured while executing doInBackground()",
+                    throw new RuntimeException("An error occurred while executing doInBackground()",
                             e.getCause());
                 } catch (CancellationException e) {
                     postResultIfNotInvoked(null);
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 1b02141b9..c373308 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -16,12 +16,12 @@
 
 package android.os;
 
+import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.Log;
 
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -63,7 +63,7 @@
      * inside of the Bundle.
      * @param capacity Initial size of the ArrayMap.
      */
-    BaseBundle(ClassLoader loader, int capacity) {
+    BaseBundle(@Nullable ClassLoader loader, int capacity) {
         mMap = capacity > 0 ?
                 new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
         mClassLoader = loader == null ? getClass().getClassLoader() : loader;
@@ -276,6 +276,7 @@
      * @param key a String key
      * @return an Object, or null
      */
+    @Nullable
     public Object get(String key) {
         unparcel();
         return mMap.get(key);
@@ -307,7 +308,7 @@
      *
      * @param map a Map
      */
-    void putAll(Map map) {
+    void putAll(ArrayMap map) {
         unparcel();
         mMap.putAll(map);
     }
@@ -327,9 +328,9 @@
      * any existing value for the given key.  Either key or value may be null.
      *
      * @param key a String, or null
-     * @param value a Boolean, or null
+     * @param value a boolean
      */
-    public void putBoolean(String key, boolean value) {
+    public void putBoolean(@Nullable String key, boolean value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -341,7 +342,7 @@
      * @param key a String, or null
      * @param value a byte
      */
-    void putByte(String key, byte value) {
+    void putByte(@Nullable String key, byte value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -351,9 +352,9 @@
      * any existing value for the given key.
      *
      * @param key a String, or null
-     * @param value a char, or null
+     * @param value a char
      */
-    void putChar(String key, char value) {
+    void putChar(@Nullable String key, char value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -365,7 +366,7 @@
      * @param key a String, or null
      * @param value a short
      */
-    void putShort(String key, short value) {
+    void putShort(@Nullable String key, short value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -375,9 +376,9 @@
      * any existing value for the given key.
      *
      * @param key a String, or null
-     * @param value an int, or null
+     * @param value an int
      */
-    public void putInt(String key, int value) {
+    public void putInt(@Nullable String key, int value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -389,7 +390,7 @@
      * @param key a String, or null
      * @param value a long
      */
-    public void putLong(String key, long value) {
+    public void putLong(@Nullable String key, long value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -401,7 +402,7 @@
      * @param key a String, or null
      * @param value a float
      */
-    void putFloat(String key, float value) {
+    void putFloat(@Nullable String key, float value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -413,7 +414,7 @@
      * @param key a String, or null
      * @param value a double
      */
-    public void putDouble(String key, double value) {
+    public void putDouble(@Nullable String key, double value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -425,7 +426,7 @@
      * @param key a String, or null
      * @param value a String, or null
      */
-    public void putString(String key, String value) {
+    public void putString(@Nullable String key, @Nullable String value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -437,7 +438,7 @@
      * @param key a String, or null
      * @param value a CharSequence, or null
      */
-    void putCharSequence(String key, CharSequence value) {
+    void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -449,7 +450,7 @@
      * @param key a String, or null
      * @param value an ArrayList<Integer> object, or null
      */
-    void putIntegerArrayList(String key, ArrayList<Integer> value) {
+    void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -461,7 +462,7 @@
      * @param key a String, or null
      * @param value an ArrayList<String> object, or null
      */
-    void putStringArrayList(String key, ArrayList<String> value) {
+    void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -473,7 +474,7 @@
      * @param key a String, or null
      * @param value an ArrayList<CharSequence> object, or null
      */
-    void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
+    void putCharSequenceArrayList(@Nullable String key, @Nullable ArrayList<CharSequence> value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -485,7 +486,7 @@
      * @param key a String, or null
      * @param value a Serializable object, or null
      */
-    void putSerializable(String key, Serializable value) {
+    void putSerializable(@Nullable String key, @Nullable Serializable value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -497,7 +498,7 @@
      * @param key a String, or null
      * @param value a boolean array object, or null
      */
-    public void putBooleanArray(String key, boolean[] value) {
+    public void putBooleanArray(@Nullable String key, @Nullable boolean[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -509,7 +510,7 @@
      * @param key a String, or null
      * @param value a byte array object, or null
      */
-    void putByteArray(String key, byte[] value) {
+    void putByteArray(@Nullable String key, @Nullable byte[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -521,7 +522,7 @@
      * @param key a String, or null
      * @param value a short array object, or null
      */
-    void putShortArray(String key, short[] value) {
+    void putShortArray(@Nullable String key, @Nullable short[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -533,7 +534,7 @@
      * @param key a String, or null
      * @param value a char array object, or null
      */
-    void putCharArray(String key, char[] value) {
+    void putCharArray(@Nullable String key, @Nullable char[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -545,7 +546,7 @@
      * @param key a String, or null
      * @param value an int array object, or null
      */
-    public void putIntArray(String key, int[] value) {
+    public void putIntArray(@Nullable String key, @Nullable int[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -557,7 +558,7 @@
      * @param key a String, or null
      * @param value a long array object, or null
      */
-    public void putLongArray(String key, long[] value) {
+    public void putLongArray(@Nullable String key, @Nullable long[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -569,7 +570,7 @@
      * @param key a String, or null
      * @param value a float array object, or null
      */
-    void putFloatArray(String key, float[] value) {
+    void putFloatArray(@Nullable String key, @Nullable float[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -581,7 +582,7 @@
      * @param key a String, or null
      * @param value a double array object, or null
      */
-    public void putDoubleArray(String key, double[] value) {
+    public void putDoubleArray(@Nullable String key, @Nullable double[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -593,7 +594,7 @@
      * @param key a String, or null
      * @param value a String array object, or null
      */
-    public void putStringArray(String key, String[] value) {
+    public void putStringArray(@Nullable String key, @Nullable String[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -605,7 +606,7 @@
      * @param key a String, or null
      * @param value a CharSequence array object, or null
      */
-    void putCharSequenceArray(String key, CharSequence[] value) {
+    void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -914,7 +915,8 @@
      * @param key a String, or null
      * @return a String value, or null
      */
-    public String getString(String key) {
+    @Nullable
+    public String getString(@Nullable String key) {
         unparcel();
         final Object o = mMap.get(key);
         try {
@@ -936,7 +938,7 @@
      * @return the String value associated with the given key, or defaultValue
      *     if no valid String object is currently mapped to that key.
      */
-    public String getString(String key, String defaultValue) {
+    public String getString(@Nullable String key, String defaultValue) {
         final String s = getString(key);
         return (s == null) ? defaultValue : s;
     }
@@ -949,7 +951,8 @@
      * @param key a String, or null
      * @return a CharSequence value, or null
      */
-    CharSequence getCharSequence(String key) {
+    @Nullable
+    CharSequence getCharSequence(@Nullable String key) {
         unparcel();
         final Object o = mMap.get(key);
         try {
@@ -971,7 +974,7 @@
      * @return the CharSequence value associated with the given key, or defaultValue
      *     if no valid CharSequence object is currently mapped to that key.
      */
-    CharSequence getCharSequence(String key, CharSequence defaultValue) {
+    CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
         final CharSequence cs = getCharSequence(key);
         return (cs == null) ? defaultValue : cs;
     }
@@ -984,7 +987,8 @@
      * @param key a String, or null
      * @return a Serializable value, or null
      */
-    Serializable getSerializable(String key) {
+    @Nullable
+    Serializable getSerializable(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1006,7 +1010,8 @@
      * @param key a String, or null
      * @return an ArrayList<String> value, or null
      */
-    ArrayList<Integer> getIntegerArrayList(String key) {
+    @Nullable
+    ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1028,7 +1033,8 @@
      * @param key a String, or null
      * @return an ArrayList<String> value, or null
      */
-    ArrayList<String> getStringArrayList(String key) {
+    @Nullable
+    ArrayList<String> getStringArrayList(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1050,7 +1056,8 @@
      * @param key a String, or null
      * @return an ArrayList<CharSequence> value, or null
      */
-    ArrayList<CharSequence> getCharSequenceArrayList(String key) {
+    @Nullable
+    ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1072,7 +1079,8 @@
      * @param key a String, or null
      * @return a boolean[] value, or null
      */
-    public boolean[] getBooleanArray(String key) {
+    @Nullable
+    public boolean[] getBooleanArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1094,7 +1102,8 @@
      * @param key a String, or null
      * @return a byte[] value, or null
      */
-    byte[] getByteArray(String key) {
+    @Nullable
+    byte[] getByteArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1116,7 +1125,8 @@
      * @param key a String, or null
      * @return a short[] value, or null
      */
-    short[] getShortArray(String key) {
+    @Nullable
+    short[] getShortArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1138,7 +1148,8 @@
      * @param key a String, or null
      * @return a char[] value, or null
      */
-    char[] getCharArray(String key) {
+    @Nullable
+    char[] getCharArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1160,7 +1171,8 @@
      * @param key a String, or null
      * @return an int[] value, or null
      */
-    public int[] getIntArray(String key) {
+    @Nullable
+    public int[] getIntArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1182,7 +1194,8 @@
      * @param key a String, or null
      * @return a long[] value, or null
      */
-    public long[] getLongArray(String key) {
+    @Nullable
+    public long[] getLongArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1204,7 +1217,8 @@
      * @param key a String, or null
      * @return a float[] value, or null
      */
-    float[] getFloatArray(String key) {
+    @Nullable
+    float[] getFloatArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1226,7 +1240,8 @@
      * @param key a String, or null
      * @return a double[] value, or null
      */
-    public double[] getDoubleArray(String key) {
+    @Nullable
+    public double[] getDoubleArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1248,7 +1263,8 @@
      * @param key a String, or null
      * @return a String[] value, or null
      */
-    public String[] getStringArray(String key) {
+    @Nullable
+    public String[] getStringArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -1270,7 +1286,8 @@
      * @param key a String, or null
      * @return a CharSequence[] value, or null
      */
-    CharSequence[] getCharSequenceArray(String key) {
+    @Nullable
+    CharSequence[] getCharSequenceArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 537e993..bd5a3922 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -162,7 +162,15 @@
      */
     public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
 
-    private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+    private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+
+    /**
+     * @removed Was previously made visible by accident.
+     */
+    public BatteryManager() {
+        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
+                ServiceManager.getService("batteryproperties"));
+    }
 
     /**
      * Query a battery property from the batteryproperties service.
@@ -174,12 +182,7 @@
         long ret;
 
         if (mBatteryPropertiesRegistrar == null) {
-            IBinder b = ServiceManager.getService("batteryproperties");
-            mBatteryPropertiesRegistrar =
-                IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
-            if (mBatteryPropertiesRegistrar == null)
-                return Long.MIN_VALUE;
+            return Long.MIN_VALUE;
         }
 
         try {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cd45cfb..d96a0e9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,7 @@
 import android.telephony.SignalStrength;
 import android.text.format.DateFormat;
 import android.util.Printer;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
@@ -85,10 +86,10 @@
      */
     public static final int WIFI_SCAN = 6;
 
-     /**
-      * A constant indicating a wifi multicast timer
-      */
-     public static final int WIFI_MULTICAST_ENABLED = 7;
+    /**
+     * A constant indicating a wifi multicast timer
+     */
+    public static final int WIFI_MULTICAST_ENABLED = 7;
 
     /**
      * A constant indicating a video turn on timer
@@ -352,7 +353,9 @@
         public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which);
         public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which);
         public abstract long getWifiScanTime(long elapsedRealtimeUs, int which);
+        public abstract int getWifiScanCount(int which);
         public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which);
+        public abstract int getWifiBatchedScanCount(int csphBin, int which);
         public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which);
         public abstract long getAudioTurnedOnTime(long elapsedRealtimeUs, int which);
         public abstract long getVideoTurnedOnTime(long elapsedRealtimeUs, int which);
@@ -438,14 +441,14 @@
             public abstract boolean isActive();
 
             /**
-             * Returns the total time (in 1/100 sec) spent executing in user code.
+             * Returns the total time (in milliseconds) spent executing in user code.
              *
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
             public abstract long getUserTime(int which);
 
             /**
-             * Returns the total time (in 1/100 sec) spent executing in system code.
+             * Returns the total time (in milliseconds) spent executing in system code.
              *
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              */
@@ -473,14 +476,14 @@
             public abstract int getNumAnrs(int which);
 
             /**
-             * Returns the cpu time spent in microseconds while the process was in the foreground.
+             * Returns the cpu time (milliseconds) spent while the process was in the foreground.
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
              * @return foreground cpu time in microseconds
              */
             public abstract long getForegroundTime(int which);
 
             /**
-             * Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
+             * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
              * @param speedStep the index of the CPU speed. This is not the actual speed of the
              * CPU.
              * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
@@ -542,6 +545,297 @@
         }
     }
 
+    public static final class LevelStepTracker {
+        public long mLastStepTime = -1;
+        public int mNumStepDurations;
+        public final long[] mStepDurations;
+
+        public LevelStepTracker(int maxLevelSteps) {
+            mStepDurations = new long[maxLevelSteps];
+        }
+
+        public LevelStepTracker(int numSteps, long[] steps) {
+            mNumStepDurations = numSteps;
+            mStepDurations = new long[numSteps];
+            System.arraycopy(steps, 0, mStepDurations, 0, numSteps);
+        }
+
+        public long getDurationAt(int index) {
+            return mStepDurations[index] & STEP_LEVEL_TIME_MASK;
+        }
+
+        public int getLevelAt(int index) {
+            return (int)((mStepDurations[index] & STEP_LEVEL_LEVEL_MASK)
+                    >> STEP_LEVEL_LEVEL_SHIFT);
+        }
+
+        public int getInitModeAt(int index) {
+            return (int)((mStepDurations[index] & STEP_LEVEL_INITIAL_MODE_MASK)
+                    >> STEP_LEVEL_INITIAL_MODE_SHIFT);
+        }
+
+        public int getModModeAt(int index) {
+            return (int)((mStepDurations[index] & STEP_LEVEL_MODIFIED_MODE_MASK)
+                    >> STEP_LEVEL_MODIFIED_MODE_SHIFT);
+        }
+
+        private void appendHex(long val, int topOffset, StringBuilder out) {
+            boolean hasData = false;
+            while (topOffset >= 0) {
+                int digit = (int)( (val>>topOffset) & 0xf );
+                topOffset -= 4;
+                if (!hasData && digit == 0) {
+                    continue;
+                }
+                hasData = true;
+                if (digit >= 0 && digit <= 9) {
+                    out.append((char)('0' + digit));
+                } else {
+                    out.append((char)('a' + digit - 10));
+                }
+            }
+        }
+
+        public void encodeEntryAt(int index, StringBuilder out) {
+            long item = mStepDurations[index];
+            long duration = item & STEP_LEVEL_TIME_MASK;
+            int level = (int)((item & STEP_LEVEL_LEVEL_MASK)
+                    >> STEP_LEVEL_LEVEL_SHIFT);
+            int initMode = (int)((item & STEP_LEVEL_INITIAL_MODE_MASK)
+                    >> STEP_LEVEL_INITIAL_MODE_SHIFT);
+            int modMode = (int)((item & STEP_LEVEL_MODIFIED_MODE_MASK)
+                    >> STEP_LEVEL_MODIFIED_MODE_SHIFT);
+            switch ((initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+                case Display.STATE_OFF: out.append('f'); break;
+                case Display.STATE_ON: out.append('o'); break;
+                case Display.STATE_DOZE: out.append('d'); break;
+                case Display.STATE_DOZE_SUSPEND: out.append('z'); break;
+            }
+            if ((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
+                out.append('p');
+            }
+            switch ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+                case Display.STATE_OFF: out.append('F'); break;
+                case Display.STATE_ON: out.append('O'); break;
+                case Display.STATE_DOZE: out.append('D'); break;
+                case Display.STATE_DOZE_SUSPEND: out.append('Z'); break;
+            }
+            if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
+                out.append('P');
+            }
+            out.append('-');
+            appendHex(level, 4, out);
+            out.append('-');
+            appendHex(duration, STEP_LEVEL_LEVEL_SHIFT-4, out);
+        }
+
+        public void decodeEntryAt(int index, String value) {
+            final int N = value.length();
+            int i = 0;
+            char c;
+            long out = 0;
+            while (i < N && (c=value.charAt(i)) != '-') {
+                i++;
+                switch (c) {
+                    case 'f': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'o': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'd': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+                            << STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'p': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+                            << STEP_LEVEL_INITIAL_MODE_SHIFT);
+                        break;
+                    case 'F': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'O': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'D': out |= (((long)Display.STATE_DOZE-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'Z': out |= (((long)Display.STATE_DOZE_SUSPEND-1)
+                            << STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                    case 'P': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
+                            << STEP_LEVEL_MODIFIED_MODE_SHIFT);
+                        break;
+                }
+            }
+            i++;
+            long level = 0;
+            while (i < N && (c=value.charAt(i)) != '-') {
+                i++;
+                level <<= 4;
+                if (c >= '0' && c <= '9') {
+                    level += c - '0';
+                } else if (c >= 'a' && c <= 'f') {
+                    level += c - 'a' + 10;
+                } else if (c >= 'A' && c <= 'F') {
+                    level += c - 'A' + 10;
+                }
+            }
+            i++;
+            out |= (level << STEP_LEVEL_LEVEL_SHIFT) & STEP_LEVEL_LEVEL_MASK;
+            long duration = 0;
+            while (i < N && (c=value.charAt(i)) != '-') {
+                i++;
+                duration <<= 4;
+                if (c >= '0' && c <= '9') {
+                    duration += c - '0';
+                } else if (c >= 'a' && c <= 'f') {
+                    duration += c - 'a' + 10;
+                } else if (c >= 'A' && c <= 'F') {
+                    duration += c - 'A' + 10;
+                }
+            }
+            mStepDurations[index] = out | (duration & STEP_LEVEL_TIME_MASK);
+        }
+
+        public void init() {
+            mLastStepTime = -1;
+            mNumStepDurations = 0;
+        }
+
+        public void clearTime() {
+            mLastStepTime = -1;
+        }
+
+        public long computeTimePerLevel() {
+            final long[] steps = mStepDurations;
+            final int numSteps = mNumStepDurations;
+
+            // For now we'll do a simple average across all steps.
+            if (numSteps <= 0) {
+                return -1;
+            }
+            long total = 0;
+            for (int i=0; i<numSteps; i++) {
+                total += steps[i] & STEP_LEVEL_TIME_MASK;
+            }
+            return total / numSteps;
+            /*
+            long[] buckets = new long[numSteps];
+            int numBuckets = 0;
+            int numToAverage = 4;
+            int i = 0;
+            while (i < numSteps) {
+                long totalTime = 0;
+                int num = 0;
+                for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
+                    totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
+                    num++;
+                }
+                buckets[numBuckets] = totalTime / num;
+                numBuckets++;
+                numToAverage *= 2;
+                i += num;
+            }
+            if (numBuckets < 1) {
+                return -1;
+            }
+            long averageTime = buckets[numBuckets-1];
+            for (i=numBuckets-2; i>=0; i--) {
+                averageTime = (averageTime + buckets[i]) / 2;
+            }
+            return averageTime;
+            */
+        }
+
+        public long computeTimeEstimate(long modesOfInterest, long modeValues,
+                int[] outNumOfInterest) {
+            final long[] steps = mStepDurations;
+            final int count = mNumStepDurations;
+            if (count <= 0) {
+                return -1;
+            }
+            long total = 0;
+            int numOfInterest = 0;
+            for (int i=0; i<count; i++) {
+                long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
+                        >> STEP_LEVEL_INITIAL_MODE_SHIFT;
+                long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
+                        >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
+                // If the modes of interest didn't change during this step period...
+                if ((modMode&modesOfInterest) == 0) {
+                    // And the mode values during this period match those we are measuring...
+                    if ((initMode&modesOfInterest) == modeValues) {
+                        // Then this can be used to estimate the total time!
+                        numOfInterest++;
+                        total += steps[i] & STEP_LEVEL_TIME_MASK;
+                    }
+                }
+            }
+            if (numOfInterest <= 0) {
+                return -1;
+            }
+
+            if (outNumOfInterest != null) {
+                outNumOfInterest[0] = numOfInterest;
+            }
+
+            // The estimated time is the average time we spend in each level, multipled
+            // by 100 -- the total number of battery levels
+            return (total / numOfInterest) * 100;
+        }
+
+        public void addLevelSteps(int numStepLevels, long modeBits, long elapsedRealtime) {
+            int stepCount = mNumStepDurations;
+            final long lastStepTime = mLastStepTime;
+            if (lastStepTime >= 0 && numStepLevels > 0) {
+                final long[] steps = mStepDurations;
+                long duration = elapsedRealtime - lastStepTime;
+                for (int i=0; i<numStepLevels; i++) {
+                    System.arraycopy(steps, 0, steps, 1, steps.length-1);
+                    long thisDuration = duration / (numStepLevels-i);
+                    duration -= thisDuration;
+                    if (thisDuration > STEP_LEVEL_TIME_MASK) {
+                        thisDuration = STEP_LEVEL_TIME_MASK;
+                    }
+                    steps[0] = thisDuration | modeBits;
+                }
+                stepCount += numStepLevels;
+                if (stepCount > steps.length) {
+                    stepCount = steps.length;
+                }
+            }
+            mNumStepDurations = stepCount;
+            mLastStepTime = elapsedRealtime;
+        }
+
+        public void readFromParcel(Parcel in) {
+            final int N = in.readInt();
+            mNumStepDurations = N;
+            for (int i=0; i<N; i++) {
+                mStepDurations[i] = in.readLong();
+            }
+        }
+
+        public void writeToParcel(Parcel out) {
+            final int N = mNumStepDurations;
+            out.writeInt(N);
+            for (int i=0; i<N; i++) {
+                out.writeLong(mStepDurations[i]);
+            }
+        }
+    }
+
+    public static final class DailyItem {
+        public long mStartTime;
+        public long mEndTime;
+        public LevelStepTracker mDischargeSteps;
+        public LevelStepTracker mChargeSteps;
+    }
+
+    public abstract DailyItem getDailyItemLocked(int daysAgo);
+
+    public abstract long getCurrentDailyStartTime();
+
+    public abstract long getNextMinDailyDeadline();
+
+    public abstract long getNextMaxDailyDeadline();
+
     public final static class HistoryTag {
         public String string;
         public int uid;
@@ -592,6 +886,86 @@
         }
     }
 
+    /**
+     * Optional detailed information that can go into a history step.  This is typically
+     * generated each time the battery level changes.
+     */
+    public final static class HistoryStepDetails {
+        // Time (in 1/100 second) spent in user space and the kernel since the last step.
+        public int userTime;
+        public int systemTime;
+
+        // Top three apps using CPU in the last step, with times in 1/100 second.
+        public int appCpuUid1;
+        public int appCpuUTime1;
+        public int appCpuSTime1;
+        public int appCpuUid2;
+        public int appCpuUTime2;
+        public int appCpuSTime2;
+        public int appCpuUid3;
+        public int appCpuUTime3;
+        public int appCpuSTime3;
+
+        // Information from /proc/stat
+        public int statUserTime;
+        public int statSystemTime;
+        public int statIOWaitTime;
+        public int statIrqTime;
+        public int statSoftIrqTime;
+        public int statIdlTime;
+
+        public HistoryStepDetails() {
+            clear();
+        }
+
+        public void clear() {
+            userTime = systemTime = 0;
+            appCpuUid1 = appCpuUid2 = appCpuUid3 = -1;
+            appCpuUTime1 = appCpuSTime1 = appCpuUTime2 = appCpuSTime2
+                    = appCpuUTime3 = appCpuSTime3 = 0;
+        }
+
+        public void writeToParcel(Parcel out) {
+            out.writeInt(userTime);
+            out.writeInt(systemTime);
+            out.writeInt(appCpuUid1);
+            out.writeInt(appCpuUTime1);
+            out.writeInt(appCpuSTime1);
+            out.writeInt(appCpuUid2);
+            out.writeInt(appCpuUTime2);
+            out.writeInt(appCpuSTime2);
+            out.writeInt(appCpuUid3);
+            out.writeInt(appCpuUTime3);
+            out.writeInt(appCpuSTime3);
+            out.writeInt(statUserTime);
+            out.writeInt(statSystemTime);
+            out.writeInt(statIOWaitTime);
+            out.writeInt(statIrqTime);
+            out.writeInt(statSoftIrqTime);
+            out.writeInt(statIdlTime);
+        }
+
+        public void readFromParcel(Parcel in) {
+            userTime = in.readInt();
+            systemTime = in.readInt();
+            appCpuUid1 = in.readInt();
+            appCpuUTime1 = in.readInt();
+            appCpuSTime1 = in.readInt();
+            appCpuUid2 = in.readInt();
+            appCpuUTime2 = in.readInt();
+            appCpuSTime2 = in.readInt();
+            appCpuUid3 = in.readInt();
+            appCpuUTime3 = in.readInt();
+            appCpuSTime3 = in.readInt();
+            statUserTime = in.readInt();
+            statSystemTime = in.readInt();
+            statIOWaitTime = in.readInt();
+            statIrqTime = in.readInt();
+            statSoftIrqTime = in.readInt();
+            statIdlTime = in.readInt();
+        }
+    }
+
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
 
@@ -687,6 +1061,9 @@
         // Kernel wakeup reason at this point.
         public HistoryTag wakeReasonTag;
 
+        // Non-null when there is more detailed information at this step.
+        public HistoryStepDetails stepDetails;
+
         public static final int EVENT_FLAG_START = 0x8000;
         public static final int EVENT_FLAG_FINISH = 0x4000;
 
@@ -1481,6 +1858,15 @@
     public abstract long getNetworkActivityBytes(int type, int which);
     public abstract long getNetworkActivityPackets(int type, int which);
 
+    public static final int CONTROLLER_IDLE_TIME = 0;
+    public static final int CONTROLLER_RX_TIME = 1;
+    public static final int CONTROLLER_TX_TIME = 2;
+    public static final int CONTROLLER_ENERGY = 3;
+    public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1;
+
+    public abstract long getBluetoothControllerActivity(int type, int which);
+    public abstract long getWifiControllerActivity(int type, int which);
+
     /**
      * Return the wall clock time when battery stats data collection started.
      */
@@ -1641,15 +2027,15 @@
 
     // Bits in a step duration that are the new battery level we are at.
     public static final long STEP_LEVEL_LEVEL_MASK = 0x0000ff0000000000L;
-    public static final long STEP_LEVEL_LEVEL_SHIFT = 40;
+    public static final int STEP_LEVEL_LEVEL_SHIFT = 40;
 
     // Bits in a step duration that are the initial mode we were in at that step.
     public static final long STEP_LEVEL_INITIAL_MODE_MASK = 0x00ff000000000000L;
-    public static final long STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
+    public static final int STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
 
     // Bits in a step duration that indicate which modes changed during that step.
     public static final long STEP_LEVEL_MODIFIED_MODE_MASK = 0xff00000000000000L;
-    public static final long STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
+    public static final int STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
 
     // Step duration mode: the screen is on, off, dozed, etc; value is Display.STATE_* - 1.
     public static final int STEP_LEVEL_MODE_SCREEN_STATE = 0x03;
@@ -1657,17 +2043,56 @@
     // Step duration mode: power save is on.
     public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04;
 
-    /**
-     * Return the historical number of discharge steps we currently have.
-     */
-    public abstract int getNumDischargeStepDurations();
+    public static final int[] STEP_LEVEL_MODES_OF_INTEREST = new int[] {
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+            STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+    };
+    public static final int[] STEP_LEVEL_MODE_VALUES = new int[] {
+            (Display.STATE_OFF-1),
+            (Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE,
+            (Display.STATE_ON-1),
+            (Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE,
+            (Display.STATE_DOZE-1),
+            (Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE,
+            (Display.STATE_DOZE_SUSPEND-1),
+            (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE,
+    };
+    public static final String[] STEP_LEVEL_MODE_LABELS = new String[] {
+            "screen off",
+            "screen off power save",
+            "screen on",
+            "screen on power save",
+            "screen doze",
+            "screen doze power save",
+            "screen doze-suspend",
+            "screen doze-suspend power save",
+    };
+    public static final String[] STEP_LEVEL_MODE_TAGS = new String[] {
+            "off",
+            "off-save",
+            "on",
+            "on-save",
+            "doze",
+            "doze-save",
+            "susp",
+            "susp-save",
+    };
 
     /**
-     * Return the array of discharge step durations; the number of valid
-     * items in it is returned by {@link #getNumDischargeStepDurations()}.
-     * These values are in milliseconds.
+     * Return the array of discharge step durations.
      */
-    public abstract long[] getDischargeStepDurationsArray();
+    public abstract LevelStepTracker getDischargeLevelStepTracker();
+
+    /**
+     * Return the array of daily discharge step durations.
+     */
+    public abstract LevelStepTracker getDailyDischargeLevelStepTracker();
 
     /**
      * Compute an approximation for how much time (in microseconds) remains until the battery
@@ -1680,16 +2105,14 @@
     public abstract long computeChargeTimeRemaining(long curTime);
 
     /**
-     * Return the historical number of charge steps we currently have.
+     * Return the array of charge step durations.
      */
-    public abstract int getNumChargeStepDurations();
+    public abstract LevelStepTracker getChargeLevelStepTracker();
 
     /**
-     * Return the array of charge step durations; the number of valid
-     * items in it is returned by {@link #getNumChargeStepDurations()}.
-     * These values are in milliseconds.
+     * Return the array of daily charge step durations.
      */
-    public abstract long[] getChargeStepDurationsArray();
+    public abstract LevelStepTracker getDailyChargeLevelStepTracker();
 
     public abstract Map<String, ? extends Timer> getWakeupReasonStats();
 
@@ -1728,13 +2151,6 @@
         }
     }
 
-    public final static void formatTime(StringBuilder sb, long time) {
-        long sec = time / 100;
-        formatTimeRaw(sb, sec);
-        sb.append((time - (sec * 100)) * 10);
-        sb.append("ms ");
-    }
-
     public final static void formatTimeMs(StringBuilder sb, long time) {
         long sec = time / 1000;
         formatTimeRaw(sb, sec);
@@ -2160,6 +2576,7 @@
             long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            int wifiScanCount = u.getWifiScanCount(which);
             long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
@@ -2172,10 +2589,10 @@
                         mobileActiveTime, mobileActiveCount);
             }
 
-            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
+            if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
                     || uidWifiRunningTime != 0) {
                 dumpLine(pw, uid, category, WIFI_DATA,
-                        fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime);
+                        fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount);
             }
 
             if (u.hasUserActivity()) {
@@ -2293,9 +2710,9 @@
                         : processStats.entrySet()) {
                     Uid.Proc ps = ent.getValue();
 
-                    final long userMillis = ps.getUserTime(which) * 10;
-                    final long systemMillis = ps.getSystemTime(which) * 10;
-                    final long foregroundMillis = ps.getForegroundTime(which) * 10;
+                    final long userMillis = ps.getUserTime(which);
+                    final long systemMillis = ps.getSystemTime(which);
+                    final long foregroundMillis = ps.getForegroundTime(which);
                     final int starts = ps.getStarts(which);
                     final int numCrashes = ps.getNumCrashes(which);
                     final int numAnrs = ps.getNumAnrs(which);
@@ -2734,6 +3151,35 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
+        final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
+        final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
+        final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+        final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Rx time:   "); formatTimeMs(sb, wifiRxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  WiFi Tx time:   "); formatTimeMs(sb, wifiTxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
         sb.setLength(0);
         sb.append(prefix);
                 sb.append("  Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
@@ -2761,9 +3207,41 @@
             sb.append(getPhoneDataConnectionCount(i, which));
             sb.append("x");
         }
+
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
+        final long bluetoothIdleTimeMs =
+                getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
+        final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
+        final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+        final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs +
+                bluetoothTxTimeMs;
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Rx time:   "); formatTimeMs(sb, bluetoothRxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  Bluetooth Tx time:   "); formatTimeMs(sb, bluetoothTxTimeMs);
+        sb.append(" (");
+        sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
         pw.println();
 
         if (which == STATS_SINCE_UNPLUGGED) {
@@ -3008,6 +3486,7 @@
             long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
             long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            int wifiScanCount = u.getWifiScanCount(which);
             long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileRxBytes > 0 || mobileTxBytes > 0
@@ -3043,7 +3522,7 @@
                         pw.print(" received, "); pw.print(wifiTxPackets); pw.println(" sent)");
             }
 
-            if (fullWifiLockOnTime != 0 || wifiScanTime != 0
+            if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
                     || uidWifiRunningTime != 0) {
                 sb.setLength(0);
                 sb.append(prefix); sb.append("    Wifi Running: ");
@@ -3057,7 +3536,9 @@
                 sb.append(prefix); sb.append("    Wifi Scan: ");
                         formatTimeMs(sb, wifiScanTime / 1000);
                         sb.append("("); sb.append(formatRatioLocked(wifiScanTime,
-                                whichBatteryRealtime)); sb.append(")");
+                                whichBatteryRealtime)); sb.append(") ");
+                                sb.append(wifiScanCount);
+                                sb.append("x");
                 pw.println(sb.toString());
             }
 
@@ -3316,9 +3797,9 @@
                         sb.append(prefix); sb.append("    Proc ");
                                 sb.append(ent.getKey()); sb.append(":\n");
                         sb.append(prefix); sb.append("      CPU: ");
-                                formatTime(sb, userTime); sb.append("usr + ");
-                                formatTime(sb, systemTime); sb.append("krn ; ");
-                                formatTime(sb, foregroundTime); sb.append("fg");
+                                formatTimeMs(sb, userTime); sb.append("usr + ");
+                                formatTimeMs(sb, systemTime); sb.append("krn ; ");
+                                formatTimeMs(sb, foregroundTime); sb.append("fg");
                         if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
                             sb.append("\n"); sb.append(prefix); sb.append("      ");
                             boolean hasOne = false;
@@ -3692,10 +4173,115 @@
                     }
                 }
                 pw.println();
+                if (rec.stepDetails != null) {
+                    if (!checkin) {
+                        pw.print("                 Details: cpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print("u+");
+                        pw.print(rec.stepDetails.systemTime);
+                        pw.print("s");
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            pw.print(" (");
+                            printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                            pw.print(')');
+                        }
+                        pw.println();
+                        pw.print("                          /proc/stat=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(" usr, ");
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(" sys, ");
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(" io, ");
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(" irq, ");
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(" sirq, ");
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.print(" idle");
+                        int totalRun = rec.stepDetails.statUserTime + rec.stepDetails.statSystemTime
+                                + rec.stepDetails.statIOWaitTime + rec.stepDetails.statIrqTime
+                                + rec.stepDetails.statSoftIrqTime;
+                        int total = totalRun + rec.stepDetails.statIdlTime;
+                        if (total > 0) {
+                            pw.print(" (");
+                            float perc = ((float)totalRun) / ((float)total) * 100;
+                            pw.print(String.format("%.1f%%", perc));
+                            pw.print(" of ");
+                            StringBuilder sb = new StringBuilder(64);
+                            formatTimeMsNoSpace(sb, total*10);
+                            pw.print(sb);
+                            pw.print(")");
+                        }
+                        pw.println();
+                    } else {
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dcpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print(":");
+                        pw.print(rec.stepDetails.systemTime);
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                        }
+                        pw.println();
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dpst=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.println();
+                    }
+                }
                 oldState = rec.states;
                 oldState2 = rec.states2;
             }
         }
+
+        private void printStepCpuUidDetails(PrintWriter pw, int uid, int utime, int stime) {
+            UserHandle.formatUid(pw, uid);
+            pw.print("=");
+            pw.print(utime);
+            pw.print("u+");
+            pw.print(stime);
+            pw.print("s");
+        }
+
+        private void printStepCpuUidCheckinDetails(PrintWriter pw, int uid, int utime, int stime) {
+            pw.print('/');
+            pw.print(uid);
+            pw.print(":");
+            pw.print(utime);
+            pw.print(":");
+            pw.print(stime);
+        }
     }
 
     private void printSizeValue(PrintWriter pw, long size) {
@@ -3725,47 +4311,27 @@
         pw.print(suffix);
     }
 
-    private static boolean dumpTimeEstimate(PrintWriter pw, String label, long[] steps,
-            int count, long modesOfInterest, long modeValues) {
-        if (count <= 0) {
+    private static boolean dumpTimeEstimate(PrintWriter pw, String label1, String label2,
+            String label3, long estimatedTime) {
+        if (estimatedTime < 0) {
             return false;
         }
-        long total = 0;
-        int numOfInterest = 0;
-        for (int i=0; i<count; i++) {
-            long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
-                    >> STEP_LEVEL_INITIAL_MODE_SHIFT;
-            long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
-                    >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
-            // If the modes of interest didn't change during this step period...
-            if ((modMode&modesOfInterest) == 0) {
-                // And the mode values during this period match those we are measuring...
-                if ((initMode&modesOfInterest) == modeValues) {
-                    // Then this can be used to estimate the total time!
-                    numOfInterest++;
-                    total += steps[i] & STEP_LEVEL_TIME_MASK;
-                }
-            }
-        }
-        if (numOfInterest <= 0) {
-            return false;
-        }
-
-        // The estimated time is the average time we spend in each level, multipled
-        // by 100 -- the total number of battery levels
-        long estimatedTime = (total / numOfInterest) * 100;
-
-        pw.print(label);
+        pw.print(label1);
+        pw.print(label2);
+        pw.print(label3);
         StringBuilder sb = new StringBuilder(64);
         formatTimeMs(sb, estimatedTime);
         pw.print(sb);
         pw.println();
-
         return true;
     }
 
-    private static boolean dumpDurationSteps(PrintWriter pw, String header, long[] steps,
-            int count, boolean checkin) {
+    private static boolean dumpDurationSteps(PrintWriter pw, String prefix, String header,
+            LevelStepTracker steps, boolean checkin) {
+        if (steps == null) {
+            return false;
+        }
+        int count = steps.mNumStepDurations;
         if (count <= 0) {
             return false;
         }
@@ -3774,13 +4340,10 @@
         }
         String[] lineArgs = new String[4];
         for (int i=0; i<count; i++) {
-            long duration = steps[i] & STEP_LEVEL_TIME_MASK;
-            int level = (int)((steps[i] & STEP_LEVEL_LEVEL_MASK)
-                    >> STEP_LEVEL_LEVEL_SHIFT);
-            long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
-                    >> STEP_LEVEL_INITIAL_MODE_SHIFT;
-            long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
-                    >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
+            long duration = steps.getDurationAt(i);
+            int level = steps.getLevelAt(i);
+            long initMode = steps.getInitModeAt(i);
+            long modMode = steps.getModModeAt(i);
             if (checkin) {
                 lineArgs[0] = Long.toString(duration);
                 lineArgs[1] = Integer.toString(level);
@@ -3802,7 +4365,8 @@
                 }
                 dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
             } else {
-                pw.print("  #"); pw.print(i); pw.print(": ");
+                pw.print(prefix);
+                pw.print("#"); pw.print(i); pw.print(": ");
                 TimeUtils.formatDuration(duration, pw);
                 pw.print(" to "); pw.print(level);
                 boolean haveModes = false;
@@ -3834,10 +4398,11 @@
 
     public static final int DUMP_UNPLUGGED_ONLY = 1<<0;
     public static final int DUMP_CHARGED_ONLY = 1<<1;
-    public static final int DUMP_HISTORY_ONLY = 1<<2;
-    public static final int DUMP_INCLUDE_HISTORY = 1<<3;
-    public static final int DUMP_VERBOSE = 1<<4;
-    public static final int DUMP_DEVICE_WIFI_ONLY = 1<<5;
+    public static final int DUMP_DAILY_ONLY = 1<<2;
+    public static final int DUMP_HISTORY_ONLY = 1<<3;
+    public static final int DUMP_INCLUDE_HISTORY = 1<<4;
+    public static final int DUMP_VERBOSE = 1<<5;
+    public static final int DUMP_DEVICE_WIFI_ONLY = 1<<6;
 
     private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
         final HistoryPrinter hprinter = new HistoryPrinter();
@@ -3923,6 +4488,36 @@
         }
     }
 
+    private void dumpDailyLevelStepSummary(PrintWriter pw, String prefix, String label,
+            LevelStepTracker steps, StringBuilder tmpSb, int[] tmpOutInt) {
+        if (steps == null) {
+            return;
+        }
+        long timeRemaining = steps.computeTimeEstimate(0, 0, tmpOutInt);
+        if (timeRemaining >= 0) {
+            pw.print(prefix); pw.print(label); pw.print(" total time: ");
+            tmpSb.setLength(0);
+            formatTimeMs(tmpSb, timeRemaining);
+            pw.print(tmpSb);
+            pw.print(" (from "); pw.print(tmpOutInt[0]);
+            pw.println(" steps)");
+        }
+        for (int i=0; i< STEP_LEVEL_MODES_OF_INTEREST.length; i++) {
+            long estimatedTime = steps.computeTimeEstimate(STEP_LEVEL_MODES_OF_INTEREST[i],
+                    STEP_LEVEL_MODE_VALUES[i], tmpOutInt);
+            if (estimatedTime > 0) {
+                pw.print(prefix); pw.print(label); pw.print(" ");
+                pw.print(STEP_LEVEL_MODE_LABELS[i]);
+                pw.print(" time: ");
+                tmpSb.setLength(0);
+                formatTimeMs(tmpSb, estimatedTime);
+                pw.print(tmpSb);
+                pw.print(" (from "); pw.print(tmpOutInt[0]);
+                pw.println(" steps)");
+            }
+        }
+    }
+
     /**
      * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
      *
@@ -3932,8 +4527,8 @@
     public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
         prepareForDumpLocked();
 
-        final boolean filtering =
-                (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
+        final boolean filtering = (flags
+                & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
 
         if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
             final long historyTotalSize = getHistoryTotalSize();
@@ -3977,7 +4572,7 @@
             }
         }
 
-        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) == 0) {
+        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
             return;
         }
 
@@ -4011,50 +4606,24 @@
         }
 
         if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
-            if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(),
-                    getNumDischargeStepDurations(), false)) {
+            if (dumpDurationSteps(pw, "  ", "Discharge step durations:",
+                    getDischargeLevelStepTracker(), false)) {
                 long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
                 if (timeRemaining >= 0) {
                     pw.print("  Estimated discharge time remaining: ");
                     TimeUtils.formatDuration(timeRemaining / 1000, pw);
                     pw.println();
                 }
-                dumpTimeEstimate(pw, "  Estimated screen off time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_OFF-1));
-                dumpTimeEstimate(pw, "  Estimated screen off power save time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE);
-                dumpTimeEstimate(pw, "  Estimated screen on time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_ON-1));
-                dumpTimeEstimate(pw, "  Estimated screen on power save time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE);
-                dumpTimeEstimate(pw, "  Estimated screen doze time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_DOZE-1));
-                dumpTimeEstimate(pw, "  Estimated screen doze power save time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE);
-                dumpTimeEstimate(pw, "  Estimated screen doze suspend time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_DOZE_SUSPEND-1));
-                dumpTimeEstimate(pw, "  Estimated screen doze suspend power save time: ",
-                        getDischargeStepDurationsArray(), getNumDischargeStepDurations(),
-                        STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
-                        (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE);
+                final LevelStepTracker steps = getDischargeLevelStepTracker();
+                for (int i=0; i< STEP_LEVEL_MODES_OF_INTEREST.length; i++) {
+                    dumpTimeEstimate(pw, "  Estimated ", STEP_LEVEL_MODE_LABELS[i], " time: ",
+                            steps.computeTimeEstimate(STEP_LEVEL_MODES_OF_INTEREST[i],
+                                    STEP_LEVEL_MODE_VALUES[i], null));
+                }
                 pw.println();
             }
-            if (dumpDurationSteps(pw, "Charge step durations:", getChargeStepDurationsArray(),
-                    getNumChargeStepDurations(), false)) {
+            if (dumpDurationSteps(pw, "  ", "Charge step durations:",
+                    getChargeLevelStepTracker(), false)) {
                 long timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
                 if (timeRemaining >= 0) {
                     pw.print("  Estimated charge time remaining: ");
@@ -4063,6 +4632,75 @@
                 }
                 pw.println();
             }
+        }
+        if (!filtering || (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0) {
+            pw.println("Daily stats:");
+            pw.print("  Current start time: ");
+            pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                    getCurrentDailyStartTime()).toString());
+            pw.print("  Next min deadline: ");
+            pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                    getNextMinDailyDeadline()).toString());
+            pw.print("  Next max deadline: ");
+            pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                    getNextMaxDailyDeadline()).toString());
+            StringBuilder sb = new StringBuilder(64);
+            int[] outInt = new int[1];
+            LevelStepTracker dsteps = getDailyDischargeLevelStepTracker();
+            LevelStepTracker csteps = getDailyChargeLevelStepTracker();
+            if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0) {
+                if ((flags&DUMP_DAILY_ONLY) != 0) {
+                    if (dumpDurationSteps(pw, "    ", "  Current daily discharge step durations:",
+                            dsteps, false)) {
+                        dumpDailyLevelStepSummary(pw, "      ", "Discharge", dsteps,
+                                sb, outInt);
+                    }
+                    if (dumpDurationSteps(pw, "    ", "  Current daily charge step durations:",
+                            csteps, false)) {
+                        dumpDailyLevelStepSummary(pw, "      ", "Charge", csteps,
+                                sb, outInt);
+                    }
+                } else {
+                    pw.println("  Current daily steps:");
+                    dumpDailyLevelStepSummary(pw, "    ", "Discharge", dsteps,
+                            sb, outInt);
+                    dumpDailyLevelStepSummary(pw, "    ", "Charge", csteps,
+                            sb, outInt);
+                }
+            }
+            DailyItem dit;
+            int curIndex = 0;
+            while ((dit=getDailyItemLocked(curIndex)) != null) {
+                curIndex++;
+                if ((flags&DUMP_DAILY_ONLY) != 0) {
+                    pw.println();
+                }
+                pw.print("  Daily from ");
+                pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mStartTime).toString());
+                pw.print(" to ");
+                pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString());
+                pw.println(":");
+                if ((flags&DUMP_DAILY_ONLY) != 0) {
+                    if (dumpDurationSteps(pw, "      ",
+                            "    Discharge step durations:", dit.mDischargeSteps, false)) {
+                        dumpDailyLevelStepSummary(pw, "        ", "Discharge", dit.mDischargeSteps,
+                                sb, outInt);
+                    }
+                    if (dumpDurationSteps(pw, "      ",
+                            "    Charge step durations:", dit.mChargeSteps, false)) {
+                        dumpDailyLevelStepSummary(pw, "        ", "Charge", dit.mChargeSteps,
+                                sb, outInt);
+                    }
+                } else {
+                    dumpDailyLevelStepSummary(pw, "    ", "Discharge", dit.mDischargeSteps,
+                            sb, outInt);
+                    dumpDailyLevelStepSummary(pw, "    ", "Charge", dit.mChargeSteps,
+                            sb, outInt);
+                }
+            }
+            pw.println();
+        }
+        if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             pw.println("Statistics since last charge:");
             pw.println("  System starts: " + getStartCount()
                     + ", currently on battery: " + getIsOnBattery());
@@ -4087,8 +4725,8 @@
 
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
 
-        final boolean filtering =
-                (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
+        final boolean filtering = (flags &
+                (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
 
         if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
             if (startIteratingHistoryLocked()) {
@@ -4114,7 +4752,7 @@
             }
         }
 
-        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) == 0) {
+        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
             return;
         }
 
@@ -4146,8 +4784,7 @@
             }
         }
         if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
-            dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
-                    getNumDischargeStepDurations(), true);
+            dumpDurationSteps(pw, "", DISCHARGE_STEP_DATA, getDischargeLevelStepTracker(), true);
             String[] lineArgs = new String[1];
             long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
             if (timeRemaining >= 0) {
@@ -4155,8 +4792,7 @@
                 dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA,
                         (Object[])lineArgs);
             }
-            dumpDurationSteps(pw, CHARGE_STEP_DATA, getChargeStepDurationsArray(),
-                    getNumChargeStepDurations(), true);
+            dumpDurationSteps(pw, "", CHARGE_STEP_DATA, getChargeLevelStepTracker(), true);
             timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
             if (timeRemaining >= 0) {
                 lineArgs[0] = Long.toString(timeRemaining);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 4b0cef6..36fc4f9 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -91,7 +91,7 @@
     /** The name of the hardware (from the kernel command line or /proc). */
     public static final String HARDWARE = getString("ro.hardware");
 
-    /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */ 
+    /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */
     public static final String SERIAL = getString("ro.serialno");
 
     /**
@@ -159,7 +159,7 @@
         /**
          * The user-visible SDK version of the framework in its raw String
          * representation; use {@link #SDK_INT} instead.
-         * 
+         *
          * @deprecated Use {@link #SDK_INT} to easily get this as an integer.
          */
         @Deprecated
@@ -207,25 +207,25 @@
          * not yet turned into an official release.
          */
         public static final int CUR_DEVELOPMENT = 10000;
-        
+
         /**
          * October 2008: The original, first, version of Android.  Yay!
          */
         public static final int BASE = 1;
-        
+
         /**
          * February 2009: First Android update, officially called 1.1.
          */
         public static final int BASE_1_1 = 2;
-        
+
         /**
          * May 2009: Android 1.5.
          */
         public static final int CUPCAKE = 3;
-        
+
         /**
          * September 2009: Android 1.6.
-         * 
+         *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
          * <ul>
@@ -247,10 +247,10 @@
          * </ul>
          */
         public static final int DONUT = 4;
-        
+
         /**
          * November 2009: Android 2.0
-         * 
+         *
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
          * <ul>
@@ -267,22 +267,22 @@
          * </ul>
          */
         public static final int ECLAIR = 5;
-        
+
         /**
          * December 2009: Android 2.0.1
          */
         public static final int ECLAIR_0_1 = 6;
-        
+
         /**
          * January 2010: Android 2.1
          */
         public static final int ECLAIR_MR1 = 7;
-        
+
         /**
          * June 2010: Android 2.2
          */
         public static final int FROYO = 8;
-        
+
         /**
          * November 2010: Android 2.3
          *
@@ -294,7 +294,7 @@
          * </ul>
          */
         public static final int GINGERBREAD = 9;
-        
+
         /**
          * February 2011: Android 2.3.3.
          */
@@ -339,12 +339,12 @@
          * </ul>
          */
         public static final int HONEYCOMB = 11;
-        
+
         /**
          * May 2011: Android 3.1.
          */
         public static final int HONEYCOMB_MR1 = 12;
-        
+
         /**
          * June 2011: Android 3.2.
          *
@@ -518,7 +518,8 @@
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
          * <ul>
-         * <li> The default result of {android.preference.PreferenceActivity#isValidFragment
+         * <li> The default result of
+         * {@link android.preference.PreferenceActivity#isValidFragment(String)
          * PreferenceActivity.isValueFragment} becomes false instead of true.</li>
          * <li> In {@link android.webkit.WebView}, apps targeting earlier versions will have
          * JS URLs evaluated directly and any result of the evaluation will not replace
@@ -596,8 +597,13 @@
          * Lollipop with an extra sugar coating on the outside!
          */
         public static final int LOLLIPOP_MR1 = 22;
+
+        /**
+         * M comes after L.
+         */
+        public static final int MNC = CUR_DEVELOPMENT;
     }
-    
+
     /** The type of build, like "user" or "eng". */
     public static final String TYPE = getString("ro.build.type");
 
@@ -644,14 +650,22 @@
     }
 
     /**
-     * Check that device fingerprint is defined and that it matches across
-     * various partitions.
+     * Verifies the the current flash of the device is consistent with what
+     * was expected at build time.
+     * 1) Checks that device fingerprint is defined and that it matches across
+     *    various partitions.
+     * 2) Verifies radio and bootloader partitions are those expected in the build.
      *
      * @hide
      */
-    public static boolean isFingerprintConsistent() {
+    public static boolean isBuildConsistent() {
         final String system = SystemProperties.get("ro.build.fingerprint");
         final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
+        final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
+        final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
+        final String currentBootloader = SystemProperties.get("ro.bootloader");
+        final String requiredRadio = SystemProperties.get("ro.build.expect.baseband");
+        final String currentRadio = SystemProperties.get("gsm.version.baseband");
 
         if (TextUtils.isEmpty(system)) {
             Slog.e(TAG, "Required ro.build.fingerprint is empty!");
@@ -666,6 +680,32 @@
             }
         }
 
+        /* TODO: Figure out issue with checks failing
+        if (!TextUtils.isEmpty(bootimage)) {
+            if (!Objects.equals(system, bootimage)) {
+                Slog.e(TAG, "Mismatched fingerprints; system reported " + system
+                        + " but bootimage reported " + bootimage);
+                return false;
+            }
+        }
+
+        if (!TextUtils.isEmpty(requiredBootloader)) {
+            if (!Objects.equals(currentBootloader, requiredBootloader)) {
+                Slog.e(TAG, "Mismatched bootloader version: build requires " + requiredBootloader
+                        + " but runtime reports " + currentBootloader);
+                return false;
+            }
+        }
+
+        if (!TextUtils.isEmpty(requiredRadio)) {
+            if (!Objects.equals(currentRadio, requiredRadio)) {
+                Slog.e(TAG, "Mismatched radio version: build requires " + requiredRadio
+                        + " but runtime reports " + currentRadio);
+                return false;
+            }
+        }
+        */
+
         return true;
     }
 
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c5c5372..5e9b8c1 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.Size;
 import android.util.SizeF;
@@ -24,7 +25,6 @@
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
  * A mapping from String values to various Parcelable types.
@@ -252,6 +252,29 @@
     }
 
     /**
+     * Filter values in Bundle to only basic types.
+     * @hide
+     */
+    public void filterValues() {
+        unparcel();
+        if (mMap != null) {
+            for (int i = mMap.size() - 1; i >= 0; i--) {
+                Object value = mMap.valueAt(i);
+                if (PersistableBundle.isValidType(value)) {
+                    continue;
+                }
+                if (value instanceof Bundle) {
+                    ((Bundle)value).filterValues();
+                }
+                if (value.getClass().getName().startsWith("android.")) {
+                    continue;
+                }
+                mMap.removeAt(i);
+            }
+        }
+    }
+
+    /**
      * Inserts a byte value into the mapping of this Bundle, replacing
      * any existing value for the given key.
      *
@@ -259,7 +282,7 @@
      * @param value a byte
      */
     @Override
-    public void putByte(String key, byte value) {
+    public void putByte(@Nullable String key, byte value) {
         super.putByte(key, value);
     }
 
@@ -268,10 +291,10 @@
      * any existing value for the given key.
      *
      * @param key a String, or null
-     * @param value a char, or null
+     * @param value a char
      */
     @Override
-    public void putChar(String key, char value) {
+    public void putChar(@Nullable String key, char value) {
         super.putChar(key, value);
     }
 
@@ -283,7 +306,7 @@
      * @param value a short
      */
     @Override
-    public void putShort(String key, short value) {
+    public void putShort(@Nullable String key, short value) {
         super.putShort(key, value);
     }
 
@@ -295,7 +318,7 @@
      * @param value a float
      */
     @Override
-    public void putFloat(String key, float value) {
+    public void putFloat(@Nullable String key, float value) {
         super.putFloat(key, value);
     }
 
@@ -307,7 +330,7 @@
      * @param value a CharSequence, or null
      */
     @Override
-    public void putCharSequence(String key, CharSequence value) {
+    public void putCharSequence(@Nullable String key, @Nullable CharSequence value) {
         super.putCharSequence(key, value);
     }
 
@@ -318,7 +341,7 @@
      * @param key a String, or null
      * @param value a Parcelable object, or null
      */
-    public void putParcelable(String key, Parcelable value) {
+    public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
         unparcel();
         mMap.put(key, value);
         mFdsKnown = false;
@@ -331,7 +354,7 @@
      * @param key a String, or null
      * @param value a Size object, or null
      */
-    public void putSize(String key, Size value) {
+    public void putSize(@Nullable String key, @Nullable Size value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -343,7 +366,7 @@
      * @param key a String, or null
      * @param value a SizeF object, or null
      */
-    public void putSizeF(String key, SizeF value) {
+    public void putSizeF(@Nullable String key, @Nullable SizeF value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -356,7 +379,7 @@
      * @param key a String, or null
      * @param value an array of Parcelable objects, or null
      */
-    public void putParcelableArray(String key, Parcelable[] value) {
+    public void putParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {
         unparcel();
         mMap.put(key, value);
         mFdsKnown = false;
@@ -370,8 +393,8 @@
      * @param key a String, or null
      * @param value an ArrayList of Parcelable objects, or null
      */
-    public void putParcelableArrayList(String key,
-            ArrayList<? extends Parcelable> value) {
+    public void putParcelableArrayList(@Nullable String key,
+            @Nullable ArrayList<? extends Parcelable> value) {
         unparcel();
         mMap.put(key, value);
         mFdsKnown = false;
@@ -392,8 +415,8 @@
      * @param key a String, or null
      * @param value a SparseArray of Parcelable objects, or null
      */
-    public void putSparseParcelableArray(String key,
-            SparseArray<? extends Parcelable> value) {
+    public void putSparseParcelableArray(@Nullable String key,
+            @Nullable SparseArray<? extends Parcelable> value) {
         unparcel();
         mMap.put(key, value);
         mFdsKnown = false;
@@ -407,7 +430,7 @@
      * @param value an ArrayList<Integer> object, or null
      */
     @Override
-    public void putIntegerArrayList(String key, ArrayList<Integer> value) {
+    public void putIntegerArrayList(@Nullable String key, @Nullable ArrayList<Integer> value) {
         super.putIntegerArrayList(key, value);
     }
 
@@ -419,7 +442,7 @@
      * @param value an ArrayList<String> object, or null
      */
     @Override
-    public void putStringArrayList(String key, ArrayList<String> value) {
+    public void putStringArrayList(@Nullable String key, @Nullable ArrayList<String> value) {
         super.putStringArrayList(key, value);
     }
 
@@ -431,7 +454,8 @@
      * @param value an ArrayList<CharSequence> object, or null
      */
     @Override
-    public void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
+    public void putCharSequenceArrayList(@Nullable String key,
+            @Nullable ArrayList<CharSequence> value) {
         super.putCharSequenceArrayList(key, value);
     }
 
@@ -443,7 +467,7 @@
      * @param value a Serializable object, or null
      */
     @Override
-    public void putSerializable(String key, Serializable value) {
+    public void putSerializable(@Nullable String key, @Nullable Serializable value) {
         super.putSerializable(key, value);
     }
 
@@ -455,7 +479,7 @@
      * @param value a byte array object, or null
      */
     @Override
-    public void putByteArray(String key, byte[] value) {
+    public void putByteArray(@Nullable String key, @Nullable byte[] value) {
         super.putByteArray(key, value);
     }
 
@@ -467,7 +491,7 @@
      * @param value a short array object, or null
      */
     @Override
-    public void putShortArray(String key, short[] value) {
+    public void putShortArray(@Nullable String key, @Nullable short[] value) {
         super.putShortArray(key, value);
     }
 
@@ -479,7 +503,7 @@
      * @param value a char array object, or null
      */
     @Override
-    public void putCharArray(String key, char[] value) {
+    public void putCharArray(@Nullable String key, @Nullable char[] value) {
         super.putCharArray(key, value);
     }
 
@@ -491,7 +515,7 @@
      * @param value a float array object, or null
      */
     @Override
-    public void putFloatArray(String key, float[] value) {
+    public void putFloatArray(@Nullable String key, @Nullable float[] value) {
         super.putFloatArray(key, value);
     }
 
@@ -503,7 +527,7 @@
      * @param value a CharSequence array object, or null
      */
     @Override
-    public void putCharSequenceArray(String key, CharSequence[] value) {
+    public void putCharSequenceArray(@Nullable String key, @Nullable CharSequence[] value) {
         super.putCharSequenceArray(key, value);
     }
 
@@ -514,7 +538,7 @@
      * @param key a String, or null
      * @param value a Bundle object, or null
      */
-    public void putBundle(String key, Bundle value) {
+    public void putBundle(@Nullable String key, @Nullable Bundle value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -533,7 +557,7 @@
      * @param key a String, or null
      * @param value an IBinder object, or null
      */
-    public void putBinder(String key, IBinder value) {
+    public void putBinder(@Nullable String key, @Nullable IBinder value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -549,7 +573,7 @@
      * @hide This is the old name of the function.
      */
     @Deprecated
-    public void putIBinder(String key, IBinder value) {
+    public void putIBinder(@Nullable String key, @Nullable IBinder value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -663,7 +687,8 @@
      * @return a CharSequence value, or null
      */
     @Override
-    public CharSequence getCharSequence(String key) {
+    @Nullable
+    public CharSequence getCharSequence(@Nullable String key) {
         return super.getCharSequence(key);
     }
 
@@ -679,7 +704,7 @@
      *     if no valid CharSequence object is currently mapped to that key.
      */
     @Override
-    public CharSequence getCharSequence(String key, CharSequence defaultValue) {
+    public CharSequence getCharSequence(@Nullable String key, CharSequence defaultValue) {
         return super.getCharSequence(key, defaultValue);
     }
 
@@ -691,7 +716,8 @@
      * @param key a String, or null
      * @return a Size value, or null
      */
-    public Size getSize(String key) {
+    @Nullable
+    public Size getSize(@Nullable String key) {
         unparcel();
         final Object o = mMap.get(key);
         try {
@@ -710,7 +736,8 @@
      * @param key a String, or null
      * @return a Size value, or null
      */
-    public SizeF getSizeF(String key) {
+    @Nullable
+    public SizeF getSizeF(@Nullable String key) {
         unparcel();
         final Object o = mMap.get(key);
         try {
@@ -729,7 +756,8 @@
      * @param key a String, or null
      * @return a Bundle value, or null
      */
-    public Bundle getBundle(String key) {
+    @Nullable
+    public Bundle getBundle(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -751,7 +779,8 @@
      * @param key a String, or null
      * @return a Parcelable value, or null
      */
-    public <T extends Parcelable> T getParcelable(String key) {
+    @Nullable
+    public <T extends Parcelable> T getParcelable(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -773,7 +802,8 @@
      * @param key a String, or null
      * @return a Parcelable[] value, or null
      */
-    public Parcelable[] getParcelableArray(String key) {
+    @Nullable
+    public Parcelable[] getParcelableArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -795,7 +825,8 @@
      * @param key a String, or null
      * @return an ArrayList<T> value, or null
      */
-    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) {
+    @Nullable
+    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -818,7 +849,8 @@
      *
      * @return a SparseArray of T values, or null
      */
-    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key) {
+    @Nullable
+    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -841,7 +873,8 @@
      * @return a Serializable value, or null
      */
     @Override
-    public Serializable getSerializable(String key) {
+    @Nullable
+    public Serializable getSerializable(@Nullable String key) {
         return super.getSerializable(key);
     }
 
@@ -854,7 +887,8 @@
      * @return an ArrayList<String> value, or null
      */
     @Override
-    public ArrayList<Integer> getIntegerArrayList(String key) {
+    @Nullable
+    public ArrayList<Integer> getIntegerArrayList(@Nullable String key) {
         return super.getIntegerArrayList(key);
     }
 
@@ -867,7 +901,8 @@
      * @return an ArrayList<String> value, or null
      */
     @Override
-    public ArrayList<String> getStringArrayList(String key) {
+    @Nullable
+    public ArrayList<String> getStringArrayList(@Nullable String key) {
         return super.getStringArrayList(key);
     }
 
@@ -880,7 +915,8 @@
      * @return an ArrayList<CharSequence> value, or null
      */
     @Override
-    public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
+    @Nullable
+    public ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {
         return super.getCharSequenceArrayList(key);
     }
 
@@ -893,7 +929,8 @@
      * @return a byte[] value, or null
      */
     @Override
-    public byte[] getByteArray(String key) {
+    @Nullable
+    public byte[] getByteArray(@Nullable String key) {
         return super.getByteArray(key);
     }
 
@@ -906,7 +943,8 @@
      * @return a short[] value, or null
      */
     @Override
-    public short[] getShortArray(String key) {
+    @Nullable
+    public short[] getShortArray(@Nullable String key) {
         return super.getShortArray(key);
     }
 
@@ -919,7 +957,8 @@
      * @return a char[] value, or null
      */
     @Override
-    public char[] getCharArray(String key) {
+    @Nullable
+    public char[] getCharArray(@Nullable String key) {
         return super.getCharArray(key);
     }
 
@@ -932,7 +971,8 @@
      * @return a float[] value, or null
      */
     @Override
-    public float[] getFloatArray(String key) {
+    @Nullable
+    public float[] getFloatArray(@Nullable String key) {
         return super.getFloatArray(key);
     }
 
@@ -945,7 +985,8 @@
      * @return a CharSequence[] value, or null
      */
     @Override
-    public CharSequence[] getCharSequenceArray(String key) {
+    @Nullable
+    public CharSequence[] getCharSequenceArray(@Nullable String key) {
         return super.getCharSequenceArray(key);
     }
 
@@ -957,7 +998,8 @@
      * @param key a String, or null
      * @return an IBinder value, or null
      */
-    public IBinder getBinder(String key) {
+    @Nullable
+    public IBinder getBinder(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -983,7 +1025,8 @@
      * @hide This is the old name of the function.
      */
     @Deprecated
-    public IBinder getIBinder(String key) {
+    @Nullable
+    public IBinder getIBinder(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
index f83a90b..2ecf317 100644
--- a/core/java/android/os/CommonClock.java
+++ b/core/java/android/os/CommonClock.java
@@ -23,7 +23,6 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import static android.system.OsConstants.*;
 
 /**
  * Used for accessing the android common time service's common clock and receiving notifications
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b8178b4..512e212 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -63,7 +63,10 @@
      *
      * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
      * trace key file.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
 
     /**
@@ -104,7 +107,7 @@
 
     /**
      * This class is used to retrieved various statistics about the memory mappings for this
-     * process. The returns info broken down by dalvik, native, and other. All results are in kB.
+     * process. The returned info is broken down by dalvik, native, and other. All results are in kB.
      */
     public static class MemoryInfo implements Parcelable {
         /** The proportional set size for dalvik heap.  (Doesn't include other Dalvik overhead.) */
@@ -760,7 +763,7 @@
     /**
      * Stop counting the number and aggregate size of memory allocations.
      *
-     * @see #startAllocCounting()
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
     @Deprecated
     public static void stopAllocCounting() {
@@ -770,7 +773,10 @@
     /**
      * Returns the global count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -778,7 +784,10 @@
     /**
      * Clears the global count of objects allocated.
      * @see #getGlobalAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
     }
@@ -786,7 +795,10 @@
     /**
      * Returns the global size, in bytes, of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -794,7 +806,10 @@
     /**
      * Clears the global size of objects allocated.
      * @see #getGlobalAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
     }
@@ -802,7 +817,10 @@
     /**
      * Returns the global count of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -810,7 +828,10 @@
     /**
      * Clears the global count of objects freed.
      * @see #getGlobalFreedCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
     }
@@ -818,7 +839,10 @@
     /**
      * Returns the global size, in bytes, of objects freed by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalFreedSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -826,7 +850,10 @@
     /**
      * Clears the global size of objects freed.
      * @see #getGlobalFreedSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalFreedSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
     }
@@ -834,7 +861,10 @@
     /**
      * Returns the number of non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -842,7 +872,10 @@
     /**
      * Clears the count of non-concurrent GC invocations.
      * @see #getGlobalGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
     }
@@ -851,7 +884,10 @@
      * Returns the number of classes successfully initialized (ie those that executed without
      * throwing an exception) between a {@link #startAllocCounting() start} and
      * {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -859,7 +895,10 @@
     /**
      * Clears the count of classes initialized.
      * @see #getGlobalClassInitCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
     }
@@ -867,7 +906,10 @@
     /**
      * Returns the time spent successfully initializing classes between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getGlobalClassInitTime() {
         /* cumulative elapsed time for class initialization, in usec */
         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
@@ -876,7 +918,10 @@
     /**
      * Clears the count of time spent initializing classes.
      * @see #getGlobalClassInitTime()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetGlobalClassInitTime() {
         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
     }
@@ -948,7 +993,10 @@
     /**
      * Returns the thread-local count of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -956,7 +1004,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
     }
@@ -965,7 +1016,10 @@
      * Returns the thread-local size of objects allocated by the runtime between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
      * @return The allocated size in bytes.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadAllocSize() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -973,7 +1027,10 @@
     /**
      * Clears the thread-local count of objects allocated.
      * @see #getThreadAllocSize()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadAllocSize() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
     }
@@ -1013,7 +1070,10 @@
     /**
      * Returns the number of thread-local non-concurrent GC invocations between a
      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static int getThreadGcInvocationCount() {
         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1021,7 +1081,10 @@
     /**
      * Clears the thread-local count of non-concurrent GC invocations.
      * @see #getThreadGcInvocationCount()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetThreadGcInvocationCount() {
         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
     }
@@ -1029,7 +1092,10 @@
     /**
      * Clears all the global and thread-local memory allocation counters.
      * @see #startAllocCounting()
+     *
+     * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    @Deprecated
     public static void resetAllCounts() {
         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
     }
@@ -1286,7 +1352,10 @@
      *           + icount.globalMethodInvocations());
      *   }
      * </pre>
+     *
+     * @deprecated Instruction counting is no longer supported.
      */
+    @Deprecated
     public static class InstructionCount {
         private static final int NUM_INSTR =
             OpcodeInfo.MAXIMUM_PACKED_VALUE + 1;
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 154a5a5..f93550a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -301,6 +301,8 @@
      */
     void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
 
+    void setUidCleartextNetworkPolicy(int uid, int policy);
+
     /**
      * Return status of bandwidth control module.
      */
diff --git a/core/java/android/os/IProcessInfoService.aidl b/core/java/android/os/IProcessInfoService.aidl
new file mode 100644
index 0000000..c98daa2
--- /dev/null
+++ b/core/java/android/os/IProcessInfoService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IProcessInfoService
+{
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or ActivityManager.PROCESS_STATE_NONEXISTENT
+     * to indicate that no process with the given PID exists.
+     */
+    void getProcessStatesFromPids(in int[] pids, out int[] states);
+}
+
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index b5295fb..236003b 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -21,6 +21,7 @@
 import android.content.pm.UserInfo;
 import android.content.RestrictionEntry;
 import android.graphics.Bitmap;
+import android.os.ParcelFileDescriptor;
 
 /**
  *  {@hide}
@@ -32,7 +33,7 @@
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
     void setUserIcon(int userHandle, in Bitmap icon);
-    Bitmap getUserIcon(int userHandle);
+    ParcelFileDescriptor getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
     UserInfo getProfileParent(int userHandle);
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 6d7c9cf..34c880f 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.util.Log;
 import android.util.Printer;
 
@@ -24,10 +26,10 @@
   * not have a message loop associated with them; to create one, call
   * {@link #prepare} in the thread that is to run the loop, and then
   * {@link #loop} to have it process messages until the loop is stopped.
-  * 
+  *
   * <p>Most interaction with a message loop is through the
   * {@link Handler} class.
-  * 
+  *
   * <p>This is a typical example of the implementation of a Looper thread,
   * using the separation of {@link #prepare} and {@link #loop} to create an
   * initial Handler to communicate with the Looper.
@@ -50,6 +52,16 @@
   *  }</pre>
   */
 public final class Looper {
+    /*
+     * API Implementation Note:
+     *
+     * This class contains the code required to set up and manage an event loop
+     * based on MessageQueue.  APIs that affect the state of the queue should be
+     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
+     * idle handlers and sync barriers are defined on the queue whereas preparing the
+     * thread, looping, and quitting are defined on the looper.
+     */
+
     private static final String TAG = "Looper";
 
     // sThreadLocal.get() will return null unless you've called prepare().
@@ -94,7 +106,8 @@
         }
     }
 
-    /** Returns the application's main looper, which lives in the main thread of the application.
+    /**
+     * Returns the application's main looper, which lives in the main thread of the application.
      */
     public static Looper getMainLooper() {
         synchronized (Looper.class) {
@@ -157,29 +170,16 @@
      * Return the Looper object associated with the current thread.  Returns
      * null if the calling thread is not associated with a Looper.
      */
-    public static Looper myLooper() {
+    public static @Nullable Looper myLooper() {
         return sThreadLocal.get();
     }
 
     /**
-     * Control logging of messages as they are processed by this Looper.  If
-     * enabled, a log message will be written to <var>printer</var> 
-     * at the beginning and ending of each message dispatch, identifying the
-     * target Handler and message contents.
-     * 
-     * @param printer A Printer object that will receive log messages, or
-     * null to disable message logging.
-     */
-    public void setMessageLogging(Printer printer) {
-        mLogging = printer;
-    }
-    
-    /**
      * Return the {@link MessageQueue} object associated with the current
      * thread.  This must be called from a thread running a Looper, or a
      * NullPointerException will be thrown.
      */
-    public static MessageQueue myQueue() {
+    public static @NonNull MessageQueue myQueue() {
         return myLooper().mQueue;
     }
 
@@ -190,13 +190,25 @@
 
     /**
      * Returns true if the current thread is this looper's thread.
-     * @hide
      */
     public boolean isCurrentThread() {
         return Thread.currentThread() == mThread;
     }
 
     /**
+     * Control logging of messages as they are processed by this Looper.  If
+     * enabled, a log message will be written to <var>printer</var>
+     * at the beginning and ending of each message dispatch, identifying the
+     * target Handler and message contents.
+     *
+     * @param printer A Printer object that will receive log messages, or
+     * null to disable message logging.
+     */
+    public void setMessageLogging(@Nullable Printer printer) {
+        mLogging = printer;
+    }
+
+    /**
      * Quits the looper.
      * <p>
      * Causes the {@link #loop} method to terminate without processing any
@@ -233,74 +245,35 @@
     }
 
     /**
-     * Posts a synchronization barrier to the Looper's message queue.
+     * Gets the Thread associated with this Looper.
      *
-     * Message processing occurs as usual until the message queue encounters the
-     * synchronization barrier that has been posted.  When the barrier is encountered,
-     * later synchronous messages in the queue are stalled (prevented from being executed)
-     * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
-     * the token that identifies the synchronization barrier.
-     *
-     * This method is used to immediately postpone execution of all subsequently posted
-     * synchronous messages until a condition is met that releases the barrier.
-     * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
-     * and continue to be processed as usual.
-     *
-     * This call must be always matched by a call to {@link #removeSyncBarrier} with
-     * the same token to ensure that the message queue resumes normal operation.
-     * Otherwise the application will probably hang!
-     *
-     * @return A token that uniquely identifies the barrier.  This token must be
-     * passed to {@link #removeSyncBarrier} to release the barrier.
-     *
-     * @hide
+     * @return The looper's thread.
      */
-    public int postSyncBarrier() {
-        return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
-    }
-
-
-    /**
-     * Removes a synchronization barrier.
-     *
-     * @param token The synchronization barrier token that was returned by
-     * {@link #postSyncBarrier}.
-     *
-     * @throws IllegalStateException if the barrier was not found.
-     *
-     * @hide
-     */
-    public void removeSyncBarrier(int token) {
-        mQueue.removeSyncBarrier(token);
-    }
-
-    /**
-     * Return the Thread associated with this Looper.
-     */
-    public Thread getThread() {
+    public @NonNull Thread getThread() {
         return mThread;
     }
 
-    /** @hide */
-    public MessageQueue getQueue() {
+    /**
+     * Gets this looper's message queue.
+     *
+     * @return The looper's message queue.
+     */
+    public @NonNull MessageQueue getQueue() {
         return mQueue;
     }
 
     /**
-     * Return whether this looper's thread is currently idle, waiting for new work
-     * to do.  This is intrinsically racy, since its state can change before you get
-     * the result back.
-     * @hide
+     * Dumps the state of the looper for debugging purposes.
+     *
+     * @param pw A printer to receive the contents of the dump.
+     * @param prefix A prefix to prepend to each line which is printed.
      */
-    public boolean isIdling() {
-        return mQueue.isIdling();
-    }
-
-    public void dump(Printer pw, String prefix) {
+    public void dump(@NonNull Printer pw, @NonNull String prefix) {
         pw.println(prefix + toString());
         mQueue.dump(pw, prefix + "  ");
     }
 
+    @Override
     public String toString() {
         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
                 + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 01a23ce..7dd4f94 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -16,9 +16,15 @@
 
 package android.os;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.util.Log;
 import android.util.Printer;
+import android.util.SparseArray;
 
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 
 /**
@@ -30,6 +36,9 @@
  * {@link Looper#myQueue() Looper.myQueue()}.
  */
 public final class MessageQueue {
+    private static final String TAG = "MessageQueue";
+    private static final boolean DEBUG = false;
+
     // True if the message queue can be quit.
     private final boolean mQuitAllowed;
 
@@ -38,6 +47,7 @@
 
     Message mMessages;
     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
+    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
     private IdleHandler[] mPendingIdleHandlers;
     private boolean mQuitting;
 
@@ -50,56 +60,10 @@
 
     private native static long nativeInit();
     private native static void nativeDestroy(long ptr);
-    private native static void nativePollOnce(long ptr, int timeoutMillis);
+    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
     private native static void nativeWake(long ptr);
-    private native static boolean nativeIsIdling(long ptr);
-
-    /**
-     * Callback interface for discovering when a thread is going to block
-     * waiting for more messages.
-     */
-    public static interface IdleHandler {
-        /**
-         * Called when the message queue has run out of messages and will now
-         * wait for more.  Return true to keep your idle handler active, false
-         * to have it removed.  This may be called if there are still messages
-         * pending in the queue, but they are all scheduled to be dispatched
-         * after the current time.
-         */
-        boolean queueIdle();
-    }
-
-    /**
-     * Add a new {@link IdleHandler} to this message queue.  This may be
-     * removed automatically for you by returning false from
-     * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
-     * invoked, or explicitly removing it with {@link #removeIdleHandler}.
-     * 
-     * <p>This method is safe to call from any thread.
-     * 
-     * @param handler The IdleHandler to be added.
-     */
-    public void addIdleHandler(IdleHandler handler) {
-        if (handler == null) {
-            throw new NullPointerException("Can't add a null IdleHandler");
-        }
-        synchronized (this) {
-            mIdleHandlers.add(handler);
-        }
-    }
-
-    /**
-     * Remove an {@link IdleHandler} from the queue that was previously added
-     * with {@link #addIdleHandler}.  If the given object is not currently
-     * in the idle list, nothing is done.
-     * 
-     * @param handler The IdleHandler to be removed.
-     */
-    public void removeIdleHandler(IdleHandler handler) {
-        synchronized (this) {
-            mIdleHandlers.remove(handler);
-        }
-    }
+    private native static boolean nativeIsPolling(long ptr);
+    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
 
     MessageQueue(boolean quitAllowed) {
         mQuitAllowed = quitAllowed;
@@ -124,6 +88,222 @@
         }
     }
 
+    /**
+     * Returns true if the looper has no pending messages which are due to be processed.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @return True if the looper is idle.
+     */
+    public boolean isIdle() {
+        synchronized (this) {
+            final long now = SystemClock.uptimeMillis();
+            return mMessages == null || now < mMessages.when;
+        }
+    }
+
+    /**
+     * Add a new {@link IdleHandler} to this message queue.  This may be
+     * removed automatically for you by returning false from
+     * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
+     * invoked, or explicitly removing it with {@link #removeIdleHandler}.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @param handler The IdleHandler to be added.
+     */
+    public void addIdleHandler(@NonNull IdleHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException("Can't add a null IdleHandler");
+        }
+        synchronized (this) {
+            mIdleHandlers.add(handler);
+        }
+    }
+
+    /**
+     * Remove an {@link IdleHandler} from the queue that was previously added
+     * with {@link #addIdleHandler}.  If the given object is not currently
+     * in the idle list, nothing is done.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @param handler The IdleHandler to be removed.
+     */
+    public void removeIdleHandler(@NonNull IdleHandler handler) {
+        synchronized (this) {
+            mIdleHandlers.remove(handler);
+        }
+    }
+
+    /**
+     * Returns whether this looper's thread is currently polling for more work to do.
+     * This is a good signal that the loop is still alive rather than being stuck
+     * handling a callback.  Note that this method is intrinsically racy, since the
+     * state of the loop can change before you get the result back.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @return True if the looper is currently polling for events.
+     * @hide
+     */
+    public boolean isPolling() {
+        synchronized (this) {
+            return isPollingLocked();
+        }
+    }
+
+    private boolean isPollingLocked() {
+        // If the loop is quitting then it must not be idling.
+        // We can assume mPtr != 0 when mQuitting is false.
+        return !mQuitting && nativeIsPolling(mPtr);
+    }
+
+    /**
+     * Registers a file descriptor callback to receive notification when file descriptor
+     * related events occur.
+     * <p>
+     * If the file descriptor has already been registered, the specified events
+     * and callback will replace any that were previously associated with it.
+     * It is not possible to set more than one callback per file descriptor.
+     * </p><p>
+     * It is important to always unregister the callback when the file descriptor
+     * is no longer of use.
+     * </p>
+     *
+     * @param fd The file descriptor for which a callback will be registered.
+     * @param events The set of events to receive: a combination of the
+     * {@link FileDescriptorCallback#EVENT_INPUT},
+     * {@link FileDescriptorCallback#EVENT_OUTPUT}, and
+     * {@link FileDescriptorCallback#EVENT_ERROR} event masks.  If the requested
+     * set of events is zero, then the callback is unregistered.
+     * @param callback The callback to invoke when file descriptor events occur.
+     *
+     * @see FileDescriptorCallback
+     * @see #unregisterFileDescriptorCallback
+     */
+    public void registerFileDescriptorCallback(@NonNull FileDescriptor fd,
+            @FileDescriptorCallback.Events int events,
+            @NonNull FileDescriptorCallback callback) {
+        if (fd == null) {
+            throw new IllegalArgumentException("fd must not be null");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+
+        synchronized (this) {
+            setFileDescriptorCallbackLocked(fd, events, callback);
+        }
+    }
+
+    /**
+     * Unregisters a file descriptor callback.
+     * <p>
+     * This method does nothing if no callback has been registered for the
+     * specified file descriptor.
+     * </p>
+     *
+     * @param fd The file descriptor whose callback will be unregistered.
+     *
+     * @see FileDescriptorCallback
+     * @see #registerFileDescriptorCallback
+     */
+    public void unregisterFileDescriptorCallback(@NonNull FileDescriptor fd) {
+        if (fd == null) {
+            throw new IllegalArgumentException("fd must not be null");
+        }
+
+        synchronized (this) {
+            setFileDescriptorCallbackLocked(fd, 0, null);
+        }
+    }
+
+    private void setFileDescriptorCallbackLocked(FileDescriptor fd, int events,
+            FileDescriptorCallback callback) {
+        final int fdNum = fd.getInt$();
+
+        int index = -1;
+        FileDescriptorRecord record = null;
+        if (mFileDescriptorRecords != null) {
+            index = mFileDescriptorRecords.indexOfKey(fdNum);
+            if (index >= 0) {
+                record = mFileDescriptorRecords.valueAt(index);
+                if (record != null && record.mEvents == events) {
+                    return;
+                }
+            }
+        }
+
+        if (events != 0) {
+            events |= FileDescriptorCallback.EVENT_ERROR;
+            if (record == null) {
+                if (mFileDescriptorRecords == null) {
+                    mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
+                }
+                record = new FileDescriptorRecord(fd, events, callback);
+                mFileDescriptorRecords.put(fdNum, record);
+            } else {
+                record.mCallback = callback;
+                record.mEvents = events;
+                record.mSeq += 1;
+            }
+            nativeSetFileDescriptorEvents(mPtr, fdNum, events);
+        } else if (record != null) {
+            record.mEvents = 0;
+            mFileDescriptorRecords.removeAt(index);
+        }
+    }
+
+    // Called from native code.
+    private int dispatchEvents(int fd, int events) {
+        // Get the file descriptor record and any state that might change.
+        final FileDescriptorRecord record;
+        final int oldWatchedEvents;
+        final FileDescriptorCallback callback;
+        final int seq;
+        synchronized (this) {
+            record = mFileDescriptorRecords.get(fd);
+            if (record == null) {
+                return 0; // spurious, no callback registered
+            }
+
+            oldWatchedEvents = record.mEvents;
+            events &= oldWatchedEvents; // filter events based on current watched set
+            if (events == 0) {
+                return oldWatchedEvents; // spurious, watched events changed
+            }
+
+            callback = record.mCallback;
+            seq = record.mSeq;
+        }
+
+        // Invoke the callback outside of the lock.
+        int newWatchedEvents = callback.onFileDescriptorEvents(
+                record.mDescriptor, events);
+        if (newWatchedEvents != 0) {
+            newWatchedEvents |= FileDescriptorCallback.EVENT_ERROR;
+        }
+
+        // Update the file descriptor record if the callback changed the set of
+        // events to watch and the callback itself hasn't been updated since.
+        if (newWatchedEvents != oldWatchedEvents) {
+            synchronized (this) {
+                int index = mFileDescriptorRecords.indexOfKey(fd);
+                if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
+                        && record.mSeq == seq) {
+                    record.mEvents = newWatchedEvents;
+                    if (newWatchedEvents == 0) {
+                        mFileDescriptorRecords.removeAt(index);
+                    }
+                }
+            }
+        }
+
+        // Return the new set of events to watch for native code to take care of.
+        return newWatchedEvents;
+    }
+
     Message next() {
         // Return here if the message loop has already quit and been disposed.
         // This can happen if the application tries to restart a looper after quit
@@ -167,7 +347,8 @@
                             mMessages = msg.next;
                         }
                         msg.next = null;
-                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
+                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
+                        msg.markInUse();
                         return msg;
                     }
                 } else {
@@ -210,7 +391,7 @@
                 try {
                     keep = idler.queueIdle();
                 } catch (Throwable t) {
-                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
+                    Log.wtf(TAG, "IdleHandler threw exception", t);
                 }
 
                 if (!keep) {
@@ -251,7 +432,34 @@
         }
     }
 
-    int enqueueSyncBarrier(long when) {
+    /**
+     * Posts a synchronization barrier to the Looper's message queue.
+     *
+     * Message processing occurs as usual until the message queue encounters the
+     * synchronization barrier that has been posted.  When the barrier is encountered,
+     * later synchronous messages in the queue are stalled (prevented from being executed)
+     * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
+     * the token that identifies the synchronization barrier.
+     *
+     * This method is used to immediately postpone execution of all subsequently posted
+     * synchronous messages until a condition is met that releases the barrier.
+     * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
+     * and continue to be processed as usual.
+     *
+     * This call must be always matched by a call to {@link #removeSyncBarrier} with
+     * the same token to ensure that the message queue resumes normal operation.
+     * Otherwise the application will probably hang!
+     *
+     * @return A token that uniquely identifies the barrier.  This token must be
+     * passed to {@link #removeSyncBarrier} to release the barrier.
+     *
+     * @hide
+     */
+    public int postSyncBarrier() {
+        return postSyncBarrier(SystemClock.uptimeMillis());
+    }
+
+    private int postSyncBarrier(long when) {
         // Enqueue a new sync barrier token.
         // We don't need to wake the queue because the purpose of a barrier is to stall it.
         synchronized (this) {
@@ -280,7 +488,17 @@
         }
     }
 
-    void removeSyncBarrier(int token) {
+    /**
+     * Removes a synchronization barrier.
+     *
+     * @param token The synchronization barrier token that was returned by
+     * {@link #postSyncBarrier}.
+     *
+     * @throws IllegalStateException if the barrier was not found.
+     *
+     * @hide
+     */
+    public void removeSyncBarrier(int token) {
         // Remove a sync barrier token from the queue.
         // If the queue is no longer stalled by a barrier then wake it.
         synchronized (this) {
@@ -324,7 +542,7 @@
             if (mQuitting) {
                 IllegalStateException e = new IllegalStateException(
                         msg.target + " sending message to a Handler on a dead thread");
-                Log.w("MessageQueue", e.getMessage(), e);
+                Log.w(TAG, e.getMessage(), e);
                 msg.recycle();
                 return false;
             }
@@ -400,18 +618,6 @@
         }
     }
 
-    boolean isIdling() {
-        synchronized (this) {
-            return isIdlingLocked();
-        }
-    }
-
-    private boolean isIdlingLocked() {
-        // If the loop is quitting then it must not be idling.
-        // We can assume mPtr != 0 when mQuitting is false.
-        return !mQuitting && nativeIsIdling(mPtr);
-     }
-
     void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
@@ -559,8 +765,113 @@
                 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
                 n++;
             }
-            pw.println(prefix + "(Total messages: " + n + ", idling=" + isIdlingLocked()
+            pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
                     + ", quitting=" + mQuitting + ")");
         }
     }
+
+    /**
+     * Callback interface for discovering when a thread is going to block
+     * waiting for more messages.
+     */
+    public static interface IdleHandler {
+        /**
+         * Called when the message queue has run out of messages and will now
+         * wait for more.  Return true to keep your idle handler active, false
+         * to have it removed.  This may be called if there are still messages
+         * pending in the queue, but they are all scheduled to be dispatched
+         * after the current time.
+         */
+        boolean queueIdle();
+    }
+
+    /**
+     * A callback which is invoked when file descriptor related events occur.
+     */
+    public static abstract class FileDescriptorCallback {
+        /**
+         * File descriptor event: Indicates that the file descriptor is ready for input
+         * operations, such as reading.
+         * <p>
+         * The callback should read all available data from the file descriptor
+         * then return <code>true</code> to keep the callback active or <code>false</code>
+         * to remove the callback.
+         * </p><p>
+         * In the case of a socket, this event may be generated to indicate
+         * that there is at least one incoming connection that the callback
+         * should accept.
+         * </p><p>
+         * This event will only be generated if the {@link #EVENT_INPUT} event mask was
+         * specified when the callback was added.
+         * </p>
+         */
+        public static final int EVENT_INPUT = 1 << 0;
+
+        /**
+         * File descriptor event: Indicates that the file descriptor is ready for output
+         * operations, such as writing.
+         * <p>
+         * The callback should write as much data as it needs.  If it could not
+         * write everything at once, then it should return <code>true</code> to
+         * keep the callback active.  Otherwise, it should return <code>false</code>
+         * to remove the callback then re-register it later when it needs to write
+         * something else.
+         * </p><p>
+         * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was
+         * specified when the callback was added.
+         * </p>
+         */
+        public static final int EVENT_OUTPUT = 1 << 1;
+
+        /**
+         * File descriptor event: Indicates that the file descriptor encountered a
+         * fatal error.
+         * <p>
+         * File descriptor errors can occur for various reasons.  One common error
+         * is when the remote peer of a socket or pipe closes its end of the connection.
+         * </p><p>
+         * This event may be generated at any time regardless of whether the
+         * {@link #EVENT_ERROR} event mask was specified when the callback was added.
+         * </p>
+         */
+        public static final int EVENT_ERROR = 1 << 2;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag=true, value={EVENT_INPUT, EVENT_OUTPUT, EVENT_ERROR})
+        public @interface Events {}
+
+        /**
+         * Called when a file descriptor receives events.
+         * <p>
+         * The default implementation does nothing and returns 0 to unregister the callback.
+         * </p>
+         *
+         * @param fd The file descriptor.
+         * @param events The set of events that occurred: a combination of the
+         * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks.
+         * @return The new set of events to watch, or 0 to unregister the callback.
+         *
+         * @see #EVENT_INPUT
+         * @see #EVENT_OUTPUT
+         * @see #EVENT_ERROR
+         */
+        public @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events) {
+            return 0;
+        }
+    }
+
+    private static final class FileDescriptorRecord {
+        public final FileDescriptor mDescriptor;
+        public int mEvents;
+        public FileDescriptorCallback mCallback;
+        public int mSeq;
+
+        public FileDescriptorRecord(FileDescriptor descriptor,
+                int events, FileDescriptorCallback callback) {
+            mDescriptor = descriptor;
+            mEvents = events;
+            mCallback = callback;
+        }
+    }
 }
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index c6b2151..5b26304 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -19,11 +19,13 @@
 import static android.system.OsConstants.AF_UNIX;
 import static android.system.OsConstants.SEEK_SET;
 import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SOCK_SEQPACKET;
 import static android.system.OsConstants.S_ISLNK;
 import static android.system.OsConstants.S_ISREG;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
+import android.os.MessageQueue.FileDescriptorCallback;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -31,7 +33,6 @@
 import android.util.Log;
 
 import dalvik.system.CloseGuard;
-
 import libcore.io.IoUtils;
 import libcore.io.Memory;
 
@@ -220,8 +221,8 @@
      *             be opened with the requested mode.
      * @see #parseMode(String)
      */
-    public static ParcelFileDescriptor open(
-            File file, int mode, Handler handler, OnCloseListener listener) throws IOException {
+    public static ParcelFileDescriptor open(File file, int mode, Handler handler,
+            final OnCloseListener listener) throws IOException {
         if (handler == null) {
             throw new IllegalArgumentException("Handler must not be null");
         }
@@ -234,11 +235,27 @@
 
         final FileDescriptor[] comm = createCommSocketPair();
         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
-
-        // Kick off thread to watch for status updates
-        IoUtils.setBlocking(comm[1], true);
-        final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
-        bridge.start();
+        final MessageQueue queue = handler.getLooper().getQueue();
+        queue.registerFileDescriptorCallback(comm[1],
+                FileDescriptorCallback.EVENT_INPUT, new FileDescriptorCallback() {
+            @Override
+            public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+                Status status = null;
+                if ((events & FileDescriptorCallback.EVENT_INPUT) != 0) {
+                    final byte[] buf = new byte[MAX_STATUS];
+                    status = readCommStatus(fd, buf);
+                } else if ((events & FileDescriptorCallback.EVENT_ERROR) != 0) {
+                    status = new Status(Status.DEAD);
+                }
+                if (status != null) {
+                    queue.unregisterFileDescriptorCallback(fd);
+                    IoUtils.closeQuietly(fd);
+                    listener.onClose(status.asIOException());
+                    return 0;
+                }
+                return EVENT_INPUT;
+            }
+        });
 
         return pfd;
     }
@@ -395,10 +412,17 @@
      * connected to each other. The two sockets are indistinguishable.
      */
     public static ParcelFileDescriptor[] createSocketPair() throws IOException {
+        return createSocketPair(SOCK_STREAM);
+    }
+
+    /**
+     * @hide
+     */
+    public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
         try {
             final FileDescriptor fd0 = new FileDescriptor();
             final FileDescriptor fd1 = new FileDescriptor();
-            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
             return new ParcelFileDescriptor[] {
                     new ParcelFileDescriptor(fd0),
                     new ParcelFileDescriptor(fd1) };
@@ -417,11 +441,18 @@
      * This can also be used to detect remote crashes.
      */
     public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
+        return createReliableSocketPair(SOCK_STREAM);
+    }
+
+    /**
+     * @hide
+     */
+    public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
         try {
             final FileDescriptor[] comm = createCommSocketPair();
             final FileDescriptor fd0 = new FileDescriptor();
             final FileDescriptor fd1 = new FileDescriptor();
-            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
             return new ParcelFileDescriptor[] {
                     new ParcelFileDescriptor(fd0, comm[0]),
                     new ParcelFileDescriptor(fd1, comm[1]) };
@@ -432,9 +463,12 @@
 
     private static FileDescriptor[] createCommSocketPair() throws IOException {
         try {
+            // Use SOCK_SEQPACKET so that we have a guarantee that the status
+            // is written and read atomically as one unit and is not split
+            // across multiple IO operations.
             final FileDescriptor comm1 = new FileDescriptor();
             final FileDescriptor comm2 = new FileDescriptor();
-            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
+            Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2);
             IoUtils.setBlocking(comm1, false);
             IoUtils.setBlocking(comm2, false);
             return new FileDescriptor[] { comm1, comm2 };
@@ -695,6 +729,7 @@
                     writePtr += len;
                 }
 
+                // Must write the entire status as a single operation.
                 Os.write(mCommFd, buf, 0, writePtr);
             } catch (ErrnoException e) {
                 // Reporting status is best-effort
@@ -712,6 +747,7 @@
 
     private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
         try {
+            // Must read the entire status as a single operation.
             final int n = Os.read(comm, buf, 0, buf.length);
             if (n == 0) {
                 // EOF means they're dead
@@ -1000,39 +1036,10 @@
                     return new IOException("Unknown status: " + status);
             }
         }
-    }
-
-    /**
-     * Bridge to watch for remote status, and deliver to listener. Currently
-     * requires that communication socket is <em>blocking</em>.
-     */
-    private static final class ListenerBridge extends Thread {
-        // TODO: switch to using Looper to avoid burning a thread
-
-        private FileDescriptor mCommFd;
-        private final Handler mHandler;
-
-        public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) {
-            mCommFd = comm;
-            mHandler = new Handler(looper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    final Status s = (Status) msg.obj;
-                    listener.onClose(s != null ? s.asIOException() : null);
-                }
-            };
-        }
 
         @Override
-        public void run() {
-            try {
-                final byte[] buf = new byte[MAX_STATUS];
-                final Status status = readCommStatus(mCommFd, buf);
-                mHandler.obtainMessage(0, status).sendToTarget();
-            } finally {
-                IoUtils.closeQuietly(mCommFd);
-                mCommFd = null;
-            }
+        public String toString() {
+            return "{" + status + ": " + msg + "}";
         }
     }
 }
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 3a44428..ea180b2 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.Nullable;
 import android.util.ArrayMap;
 import com.android.internal.util.XmlUtils;
 import org.xmlpull.v1.XmlPullParser;
@@ -44,6 +45,16 @@
         EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
     }
 
+    /** @hide */
+    public static boolean isValidType(Object value) {
+        return (value instanceof Integer) || (value instanceof Long) ||
+                (value instanceof Double) || (value instanceof String) ||
+                (value instanceof int[]) || (value instanceof long[]) ||
+                (value instanceof double[]) || (value instanceof String[]) ||
+                (value instanceof PersistableBundle) || (value == null) ||
+                (value instanceof Boolean) || (value instanceof boolean[]);
+    }
+
     /**
      * Constructs a new, empty PersistableBundle.
      */
@@ -77,29 +88,22 @@
      * @param map a Map containing only those items that can be persisted.
      * @throws IllegalArgumentException if any element of #map cannot be persisted.
      */
-    private PersistableBundle(Map<String, Object> map) {
+    private PersistableBundle(ArrayMap<String, Object> map) {
         super();
 
         // First stuff everything in.
         putAll(map);
 
         // Now verify each item throwing an exception if there is a violation.
-        Set<String> keys = map.keySet();
-        Iterator<String> iterator = keys.iterator();
-        while (iterator.hasNext()) {
-            String key = iterator.next();
-            Object value = map.get(key);
-            if (value instanceof Map) {
+        final int N = mMap.size();
+        for (int i=0; i<N; i++) {
+            Object value = mMap.valueAt(i);
+            if (value instanceof ArrayMap) {
                 // Fix up any Maps by replacing them with PersistableBundles.
-                putPersistableBundle(key, new PersistableBundle((Map<String, Object>) value));
-            } else if (!(value instanceof Integer) && !(value instanceof Long) &&
-                    !(value instanceof Double) && !(value instanceof String) &&
-                    !(value instanceof int[]) && !(value instanceof long[]) &&
-                    !(value instanceof double[]) && !(value instanceof String[]) &&
-                    !(value instanceof PersistableBundle) && (value != null) &&
-                    !(value instanceof Boolean) && !(value instanceof boolean[])) {
-                throw new IllegalArgumentException("Bad value in PersistableBundle key=" + key +
-                        " value=" + value);
+                mMap.setValueAt(i, new PersistableBundle((ArrayMap<String, Object>) value));
+            } else if (!isValidType(value)) {
+                throw new IllegalArgumentException("Bad value in PersistableBundle key="
+                        + mMap.keyAt(i) + " value=" + value);
             }
         }
     }
@@ -135,7 +139,7 @@
      * @param key a String, or null
      * @param value a Bundle object, or null
      */
-    public void putPersistableBundle(String key, PersistableBundle value) {
+    public void putPersistableBundle(@Nullable String key, @Nullable PersistableBundle value) {
         unparcel();
         mMap.put(key, value);
     }
@@ -148,7 +152,8 @@
      * @param key a String, or null
      * @return a Bundle value, or null
      */
-    public PersistableBundle getPersistableBundle(String key) {
+    @Nullable
+    public PersistableBundle getPersistableBundle(@Nullable String key) {
         unparcel();
         Object o = mMap.get(key);
         if (o == null) {
@@ -240,8 +245,9 @@
         while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
                 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
             if (event == XmlPullParser.START_TAG) {
-                return new PersistableBundle((Map<String, Object>)
-                        XmlUtils.readThisMapXml(in, startTag, tagName, new MyReadMapCallback()));
+                return new PersistableBundle((ArrayMap<String, Object>)
+                        XmlUtils.readThisArrayMapXml(in, startTag, tagName,
+                        new MyReadMapCallback()));
             }
         }
         return EMPTY;
diff --git a/core/java/android/os/PooledStringReader.java b/core/java/android/os/PooledStringReader.java
new file mode 100644
index 0000000..7795957
--- /dev/null
+++ b/core/java/android/os/PooledStringReader.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Helper class for reading pooling strings from a Parcel.  It must be used
+ * in conjunction with {@link android.os.PooledStringWriter}.  This really needs
+ * to be pushed in to Parcel itself, but doing that is...  complicated.
+ * @hide
+ */
+public class PooledStringReader {
+    private final Parcel mIn;
+
+    /**
+     * The pool of strings we have collected so far.
+     */
+    private final String[] mPool;
+
+    public PooledStringReader(Parcel in) {
+        mIn = in;
+        final int size = in.readInt();
+        mPool = new String[size];
+    }
+
+    public String readString() {
+        int idx = mIn.readInt();
+        if (idx >= 0) {
+            return mPool[idx];
+        } else {
+            idx = (-idx) - 1;
+            String str = mIn.readString();
+            mPool[idx] = str;
+            return str;
+        }
+    }
+}
diff --git a/core/java/android/os/PooledStringWriter.java b/core/java/android/os/PooledStringWriter.java
new file mode 100644
index 0000000..eac297d
--- /dev/null
+++ b/core/java/android/os/PooledStringWriter.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import java.util.HashMap;
+
+/**
+ * Helper class for writing pooled strings into a Parcel.  It must be used
+ * in conjunction with {@link android.os.PooledStringReader}.  This really needs
+ * to be pushed in to Parcel itself, but doing that is...  complicated.
+ * @hide
+ */
+public class PooledStringWriter {
+    private final Parcel mOut;
+
+    /**
+     * Book-keeping for writing pooled string objects, mapping strings we have
+     * written so far to their index in the pool.  We deliberately use HashMap
+     * here since performance is critical, we expect to be doing lots of adds to
+     * it, and it is only a temporary object so its overall memory footprint is
+     * not a signifciant issue.
+     */
+    private final HashMap<String, Integer> mPool;
+
+    /**
+     * Book-keeping for writing pooling string objects, indicating where we
+     * started writing the pool, which is where we need to ultimately store
+     * how many strings are in the pool.
+     */
+    private int mStart;
+
+    /**
+     * Next available index in the pool.
+     */
+    private int mNext;
+
+    public PooledStringWriter(Parcel out) {
+        mOut = out;
+        mPool = new HashMap<>();
+        mStart = out.dataPosition();
+        out.writeInt(0); // reserve space for final pool size.
+    }
+
+    public void writeString(String str) {
+        final Integer cur = mPool.get(str);
+        if (cur != null) {
+            mOut.writeInt(cur);
+        } else {
+            mPool.put(str, mNext);
+            mOut.writeInt(-(mNext+1));
+            mOut.writeString(str);
+            mNext++;
+        }
+    }
+
+    public void finish() {
+        final int pos = mOut.dataPosition();
+        mOut.setDataPosition(mStart);
+        mOut.writeInt(mNext);
+        mOut.setDataPosition(pos);
+    }
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8307d9b..e303f61 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -205,6 +205,20 @@
     public static final int DOZE_WAKE_LOCK = 0x00000040;
 
     /**
+     * Wake lock level: Keep the device awake enough to allow drawing to occur.
+     * <p>
+     * This is used by the window manager to allow applications to draw while the
+     * system is dozing.  It currently has no effect unless the power manager is in
+     * the dozing state.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * {@hide}
+     */
+    public static final int DRAW_WAKE_LOCK = 0x00000080;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -489,6 +503,7 @@
             case FULL_WAKE_LOCK:
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
+            case DRAW_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
@@ -835,6 +850,21 @@
     }
 
     /**
+     * Turn off the device.
+     *
+     * @param confirm If true, shows a shutdown confirmation dialog.
+     * @param wait If true, this call waits for the shutdown to complete and does not return.
+     *
+     * @hide
+     */
+    public void shutdown(boolean confirm, boolean wait) {
+        try {
+            mService.shutdown(confirm, wait);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 21a9904..4834f97 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -614,9 +614,9 @@
         synchronized(Process.class) {
             ArrayList<String> argsForZygote = new ArrayList<String>();
 
-            // --runtime-init, --setuid=, --setgid=,
+            // --runtime-args, --setuid=, --setgid=,
             // and --setgroups= must go first
-            argsForZygote.add("--runtime-init");
+            argsForZygote.add("--runtime-args");
             argsForZygote.add("--setuid=" + uid);
             argsForZygote.add("--setgid=" + gid);
             if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 84aa427..2773da5 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -50,13 +50,6 @@
     public static final native boolean isSELinuxEnforced();
 
     /**
-     * Set whether SELinux is permissive or enforcing.
-     * @param value representing whether to set SELinux to enforcing
-     * @return a boolean representing whether the desired mode was set
-     */
-    public static final native boolean setSELinuxEnforce(boolean value);
-
-    /**
      * Sets the security context for newly created file objects.
      * @param context a security context given as a String.
      * @return a boolean indicating whether the operation succeeded.
@@ -99,27 +92,6 @@
     public static final native String getPidContext(int pid);
 
     /**
-     * Gets a list of the SELinux boolean names.
-     * @return an array of strings containing the SELinux boolean names.
-     */
-    public static final native String[] getBooleanNames();
-
-    /**
-     * Gets the value for the given SELinux boolean name.
-     * @param name The name of the SELinux boolean.
-     * @return a boolean indicating whether the SELinux boolean is set.
-     */
-    public static final native boolean getBooleanValue(String name);
-
-    /**
-     * Sets the value for the given SELinux boolean name.
-     * @param name The name of the SELinux boolean.
-     * @param value The new value of the SELinux boolean.
-     * @return a boolean indicating whether or not the operation succeeded.
-     */
-    public static final native boolean setBooleanValue(String name, boolean value);
-
-    /**
      * Check permissions between two security contexts.
      * @param scon The source or subject security context.
      * @param tcon The target or object security context.
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 6db5f67..0b55998 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -32,14 +32,17 @@
 import android.view.IWindowManager;
 
 import com.android.internal.os.RuntimeInit;
-
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.HexDump;
+
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 import dalvik.system.VMDebug;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -137,6 +140,13 @@
      */
     public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual";
 
+    /**
+     * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK}
+     * in {@link VmPolicy.Builder#detectAll()}. Apps can still always opt-into
+     * detection using {@link VmPolicy.Builder#detectCleartextNetwork()}.
+     */
+    private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
+
     // Only log a duplicate stack trace to the logs every second.
     private static final long MIN_LOG_INTERVAL_MS = 1000;
 
@@ -150,7 +160,7 @@
     // of the Looper.
     private static final int MAX_OFFENSES_PER_LOOP = 10;
 
-    // Thread-policy:
+    // Byte 1: Thread-policy
 
     /**
      * @hide
@@ -174,86 +184,102 @@
      */
     public static final int DETECT_CUSTOM = 0x08;  // for ThreadPolicy
 
+    /**
+     * For StrictMode.noteResourceMismatch()
+     *
+     * @hide
+     */
+    public static final int DETECT_RESOURCE_MISMATCH = 0x10;  // for ThreadPolicy
+
     private static final int ALL_THREAD_DETECT_BITS =
-            DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM;
+            DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM |
+            DETECT_RESOURCE_MISMATCH;
 
-    // Process-policy:
+    // Byte 2: Process-policy
 
     /**
      * Note, a "VM_" bit, not thread.
      * @hide
      */
-    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for VmPolicy
+    public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8;  // for VmPolicy
 
     /**
      * Note, a "VM_" bit, not thread.
      * @hide
      */
-    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400;  // for VmPolicy
+    public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8;  // for VmPolicy
 
     /**
      * Note, a "VM_" bit, not thread.
      * @hide
      */
-    public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800;  // for VmPolicy
+    public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8;  // for VmPolicy
 
     /**
      * @hide
      */
-    private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000;  // for VmPolicy
+    private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8;  // for VmPolicy
 
     /**
      * @hide
      */
-    public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000;  // for VmPolicy
+    public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8;  // for VmPolicy
 
     /**
      * @hide
      */
-    private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000;  // for VmPolicy
+    private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8;  // for VmPolicy
+
+    /**
+     * @hide
+     */
+    private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8;  // for VmPolicy
 
     private static final int ALL_VM_DETECT_BITS =
             DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
             DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
-            DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE;
+            DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE |
+            DETECT_VM_CLEARTEXT_NETWORK;
+
+    // Byte 3: Penalty
 
     /**
      * @hide
      */
-    public static final int PENALTY_LOG = 0x10;  // normal android.util.Log
+    public static final int PENALTY_LOG = 0x01 << 16;  // normal android.util.Log
 
     // Used for both process and thread policy:
 
     /**
      * @hide
      */
-    public static final int PENALTY_DIALOG = 0x20;
+    public static final int PENALTY_DIALOG = 0x02 << 16;
 
     /**
      * Death on any detected violation.
      *
      * @hide
      */
-    public static final int PENALTY_DEATH = 0x40;
+    public static final int PENALTY_DEATH = 0x04 << 16;
 
     /**
      * Death just for detected network usage.
      *
      * @hide
      */
-    public static final int PENALTY_DEATH_ON_NETWORK = 0x200;
+    public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16;
 
     /**
      * Flash the screen during violations.
      *
      * @hide
      */
-    public static final int PENALTY_FLASH = 0x800;
+    public static final int PENALTY_FLASH = 0x10 << 16;
 
     /**
      * @hide
      */
-    public static final int PENALTY_DROPBOX = 0x80;
+    public static final int PENALTY_DROPBOX = 0x20 << 16;
 
     /**
      * Non-public penalty mode which overrides all the other penalty
@@ -266,7 +292,14 @@
      *
      * @hide
      */
-    public static final int PENALTY_GATHER = 0x100;
+    public static final int PENALTY_GATHER = 0x40 << 16;
+
+    /**
+     * Death when cleartext network traffic is detected.
+     *
+     * @hide
+     */
+    public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16;
 
     /**
      * Mask of all the penalty bits valid for thread policies.
@@ -275,13 +308,18 @@
             PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
             PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;
 
-
     /**
      * Mask of all the penalty bits valid for VM policies.
      */
-    private static final int VM_PENALTY_MASK =
-            PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX;
+    private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
+            | PENALTY_DEATH_ON_CLEARTEXT_NETWORK;
 
+    /** {@hide} */
+    public static final int NETWORK_POLICY_ACCEPT = 0;
+    /** {@hide} */
+    public static final int NETWORK_POLICY_LOG = 1;
+    /** {@hide} */
+    public static final int NETWORK_POLICY_REJECT = 2;
 
     // TODO: wrap in some ImmutableHashMap thing.
     // Note: must be before static initialization of sVmPolicy.
@@ -430,6 +468,22 @@
             }
 
             /**
+             * Disable detection of mismatches between defined resource types
+             * and getter calls.
+             */
+            public Builder permitResourceMismatches() {
+                return disable(DETECT_RESOURCE_MISMATCH);
+            }
+
+            /**
+             * Enable detection of mismatches between defined resource types
+             * and getter calls.
+             */
+            public Builder detectResourceMismatches() {
+                return enable(DETECT_RESOURCE_MISMATCH);
+            }
+
+            /**
              * Enable detection of disk writes.
              */
             public Builder detectDiskWrites() {
@@ -636,9 +690,17 @@
              * but will likely expand in future releases.
              */
             public Builder detectAll() {
-                return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
+                int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
                         | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
-                        | DETECT_VM_FILE_URI_EXPOSURE);
+                        | DETECT_VM_FILE_URI_EXPOSURE;
+
+                // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility
+                // for apps to mark sockets that should be ignored
+                if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) {
+                    flags |= DETECT_VM_CLEARTEXT_NETWORK;
+                }
+
+                return enable(flags);
             }
 
             /**
@@ -686,15 +748,46 @@
             }
 
             /**
-             * Crashes the whole process on violation.  This penalty runs at
-             * the end of all enabled penalties so yo you'll still get
-             * your logging or other violations before the process dies.
+             * Detect any network traffic from the calling app which is not
+             * wrapped in SSL/TLS. This can help you detect places that your app
+             * is inadvertently sending cleartext data across the network.
+             * <p>
+             * Using {@link #penaltyDeath()} or
+             * {@link #penaltyDeathOnCleartextNetwork()} will block further
+             * traffic on that socket to prevent accidental data leakage, in
+             * addition to crashing your process.
+             * <p>
+             * Using {@link #penaltyDropBox()} will log the raw contents of the
+             * packet that triggered the violation.
+             * <p>
+             * This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it
+             * may be subject to false positives, such as when STARTTLS
+             * protocols or HTTP proxies are used.
+             */
+            public Builder detectCleartextNetwork() {
+                return enable(DETECT_VM_CLEARTEXT_NETWORK);
+            }
+
+            /**
+             * Crashes the whole process on violation. This penalty runs at the
+             * end of all enabled penalties so you'll still get your logging or
+             * other violations before the process dies.
              */
             public Builder penaltyDeath() {
                 return enable(PENALTY_DEATH);
             }
 
             /**
+             * Crashes the whole process when cleartext network traffic is
+             * detected.
+             *
+             * @see #detectCleartextNetwork()
+             */
+            public Builder penaltyDeathOnCleartextNetwork() {
+                return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK);
+            }
+
+            /**
              * Log detected violations to the system log.
              */
             public Builder penaltyLog() {
@@ -851,6 +944,15 @@
     }
 
     /**
+     * @hide
+     */
+    private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
+        public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
+            super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
+        }
+    }
+
+    /**
      * Returns the bitmask of the current thread's policy.
      *
      * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
@@ -1125,6 +1227,20 @@
             startHandlingViolationException(e);
         }
 
+        // Not part of BlockGuard.Policy; just part of StrictMode:
+        void onResourceMismatch(Object tag) {
+            if ((mPolicyMask & DETECT_RESOURCE_MISMATCH) == 0) {
+                return;
+            }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
+            BlockGuard.BlockGuardPolicyException e =
+                    new StrictModeResourceMismatchViolation(mPolicyMask, tag);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
+        }
+
         // Part of BlockGuard.Policy interface:
         public void onReadFromDisk() {
             if ((mPolicyMask & DETECT_DISK_READ) == 0) {
@@ -1422,7 +1538,7 @@
     }
 
     private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
-        public void report (String message, Throwable allocationSite) {
+        public void report(String message, Throwable allocationSite) {
             onVmPolicyViolation(message, allocationSite);
         }
     }
@@ -1508,6 +1624,27 @@
                     sIsIdlerRegistered = true;
                 }
             }
+
+            int networkPolicy = NETWORK_POLICY_ACCEPT;
+            if ((sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0) {
+                if ((sVmPolicyMask & PENALTY_DEATH) != 0
+                        || (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0) {
+                    networkPolicy = NETWORK_POLICY_REJECT;
+                } else {
+                    networkPolicy = NETWORK_POLICY_LOG;
+                }
+            }
+
+            final INetworkManagementService netd = INetworkManagementService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+            if (netd != null) {
+                try {
+                    netd.setUidCleartextNetworkPolicy(android.os.Process.myUid(), networkPolicy);
+                } catch (RemoteException ignored) {
+                }
+            } else if (networkPolicy != NETWORK_POLICY_ACCEPT) {
+                Log.w(TAG, "Dropping requested network policy due to missing service!");
+            }
         }
     }
 
@@ -1570,6 +1707,13 @@
     /**
      * @hide
      */
+    public static boolean vmCleartextNetworkEnabled() {
+        return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
+    }
+
+    /**
+     * @hide
+     */
     public static void onSqliteObjectLeaked(String message, Throwable originStack) {
         onVmPolicyViolation(message, originStack);
     }
@@ -1600,7 +1744,39 @@
      */
     public static void onFileUriExposed(String location) {
         final String message = "file:// Uri exposed through " + location;
-        onVmPolicyViolation(message, new Throwable(message));
+        onVmPolicyViolation(null, new Throwable(message));
+    }
+
+    /**
+     * @hide
+     */
+    public static void onCleartextNetworkDetected(byte[] firstPacket) {
+        byte[] rawAddr = null;
+        if (firstPacket != null) {
+            if (firstPacket.length >= 20 && (firstPacket[0] & 0xf0) == 0x40) {
+                // IPv4
+                rawAddr = new byte[4];
+                System.arraycopy(firstPacket, 16, rawAddr, 0, 4);
+            } else if (firstPacket.length >= 40 && (firstPacket[0] & 0xf0) == 0x60) {
+                // IPv6
+                rawAddr = new byte[16];
+                System.arraycopy(firstPacket, 24, rawAddr, 0, 16);
+            }
+        }
+
+        final int uid = android.os.Process.myUid();
+        String msg = "Detected cleartext network traffic from UID " + uid;
+        if (rawAddr != null) {
+            try {
+                msg = "Detected cleartext network traffic from UID " + uid + " to "
+                        + InetAddress.getByAddress(rawAddr);
+            } catch (UnknownHostException ignored) {
+            }
+        }
+
+        final boolean forceDeath = (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
+        onVmPolicyViolation(HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg),
+                forceDeath);
     }
 
     // Map from VM violation fingerprint to uptime millis.
@@ -1610,10 +1786,18 @@
      * @hide
      */
     public static void onVmPolicyViolation(String message, Throwable originStack) {
+        onVmPolicyViolation(message, originStack, false);
+    }
+
+    /**
+     * @hide
+     */
+    public static void onVmPolicyViolation(String message, Throwable originStack,
+            boolean forceDeath) {
         final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
-        final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0;
+        final boolean penaltyDeath = ((sVmPolicyMask & PENALTY_DEATH) != 0) || forceDeath;
         final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
-        final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+        final ViolationInfo info = new ViolationInfo(message, originStack, sVmPolicyMask);
 
         // Erase stuff not relevant for process-wide violations
         info.numAnimationsRunning = 0;
@@ -1943,6 +2127,26 @@
     }
 
     /**
+     * For code to note that a resource was obtained using a type other than
+     * its defined type. This is a no-op unless the current thread's
+     * {@link android.os.StrictMode.ThreadPolicy} has
+     * {@link android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()}
+     * enabled.
+     *
+     * @param tag an object for the exception stack trace that's
+     *            built if when this fires.
+     * @hide
+     */
+    public static void noteResourceMismatch(Object tag) {
+        BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+        if (!(policy instanceof AndroidBlockGuardPolicy)) {
+            // StrictMode not enabled.
+            return;
+        }
+        ((AndroidBlockGuardPolicy) policy).onResourceMismatch(tag);
+    }
+
+    /**
      * @hide
      */
     public static void noteDiskRead() {
@@ -2057,6 +2261,8 @@
      * @hide
      */
     public static class ViolationInfo {
+        public String message;
+
         /**
          * Stack and other stuff info.
          */
@@ -2118,10 +2324,15 @@
             policy = 0;
         }
 
+        public ViolationInfo(Throwable tr, int policy) {
+            this(null, tr, policy);
+        }
+
         /**
          * Create an instance of ViolationInfo initialized from an exception.
          */
-        public ViolationInfo(Throwable tr, int policy) {
+        public ViolationInfo(String message, Throwable tr, int policy) {
+            this.message = message;
             crashInfo = new ApplicationErrorReport.CrashInfo(tr);
             violationUptimeMillis = SystemClock.uptimeMillis();
             this.policy = policy;
@@ -2184,6 +2395,7 @@
          *   and the gathering penalty should be removed.
          */
         public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
+            message = in.readString();
             crashInfo = new ApplicationErrorReport.CrashInfo(in);
             int rawPolicy = in.readInt();
             if (unsetGatheringBit) {
@@ -2204,6 +2416,7 @@
          * Save a ViolationInfo instance to a parcel.
          */
         public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(message);
             crashInfo.writeToParcel(dest, flags);
             int start = dest.dataPosition();
             dest.writeInt(policy);
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index 9dbfd50..5c80ca6 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -22,13 +22,13 @@
 import java.util.HashMap;
 
 /**
- * UEventObserver is an abstract class that receives UEvent's from the kernel.<p>
+ * UEventObserver is an abstract class that receives UEvents from the kernel.<p>
  *
  * Subclass UEventObserver, implementing onUEvent(UEvent event), then call
  * startObserving() with a match string. The UEvent thread will then call your
  * onUEvent() method when a UEvent occurs that contains your match string.<p>
  *
- * Call stopObserving() to stop receiving UEvent's.<p>
+ * Call stopObserving() to stop receiving UEvents.<p>
  *
  * There is only one UEvent thread per process, even if that process has
  * multiple UEventObserver subclass instances. The UEvent thread starts when
@@ -78,7 +78,7 @@
     }
 
     /**
-     * Begin observation of UEvent's.<p>
+     * Begin observation of UEvents.<p>
      * This method will cause the UEvent thread to start if this is the first
      * invocation of startObserving in this process.<p>
      * Once called, the UEvent thread will call onUEvent() when an incoming
@@ -103,7 +103,7 @@
     }
 
     /**
-     * End observation of UEvent's.<p>
+     * End observation of UEvents.<p>
      * This process's UEvent thread will never call onUEvent() on this
      * UEventObserver after this call. Repeated calls have no effect.
      */
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 74e064e..6874e77 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -20,7 +20,6 @@
 import android.util.SparseArray;
 
 import java.io.PrintWriter;
-import java.util.HashMap;
 
 /**
  * Representation of a user on the device.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d124a49..706e0d0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -22,6 +22,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.provider.Settings;
@@ -30,6 +31,7 @@
 
 import com.android.internal.R;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -114,6 +116,7 @@
 
     /**
      * Specifies if a user is disallowed from configuring bluetooth.
+     * This does <em>not</em> restrict the user from turning bluetooth on or off.
      * The default value is <code>false</code>.
      * <p/>This restriction has no effect in a managed profile.
      *
@@ -388,6 +391,15 @@
     public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
 
     /**
+     * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
+     * is always set for managed profiles.
+     * @hide
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_WALLPAPER = "no_wallpaper";
+
+    /**
      * Application restriction key that is used to indicate the pending arrival
      * of real restrictions for the app.
      *
@@ -1083,11 +1095,21 @@
      */
     public Bitmap getUserIcon(int userHandle) {
         try {
-            return mService.getUserIcon(userHandle);
+            ParcelFileDescriptor fd = mService.getUserIcon(userHandle);
+            if (fd != null) {
+                try {
+                    return BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
+                } finally {
+                    try {
+                        fd.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
         } catch (RemoteException re) {
             Log.w(TAG, "Could not get the user icon ", re);
-            return null;
         }
+        return null;
     }
 
     /**
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index b65eac7..3d57b4d 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -17,6 +17,9 @@
 package android.preference;
 
 
+import android.annotation.CallSuper;
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
@@ -168,7 +171,7 @@
      * 
      * @param dialogIconRes The icon, as a resource ID.
      */
-    public void setDialogIcon(int dialogIconRes) {
+    public void setDialogIcon(@DrawableRes int dialogIconRes) {
         mDialogIcon = getContext().getDrawable(dialogIconRes);
     }
     
@@ -194,7 +197,7 @@
      * @see #setPositiveButtonText(CharSequence)
      * @param positiveButtonTextResId The positive button text as a resource.
      */
-    public void setPositiveButtonText(int positiveButtonTextResId) {
+    public void setPositiveButtonText(@StringRes int positiveButtonTextResId) {
         setPositiveButtonText(getContext().getString(positiveButtonTextResId));
     }
     
@@ -222,7 +225,7 @@
      * @see #setNegativeButtonText(CharSequence)
      * @param negativeButtonTextResId The negative button text as a resource.
      */
-    public void setNegativeButtonText(int negativeButtonTextResId) {
+    public void setNegativeButtonText(@StringRes int negativeButtonTextResId) {
         setNegativeButtonText(getContext().getString(negativeButtonTextResId));
     }
     
@@ -358,6 +361,7 @@
      * 
      * @param view The content View of the dialog, if it is custom.
      */
+    @CallSuper
     protected void onBindDialogView(View view) {
         View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
         
diff --git a/core/java/android/preference/GenericInflater.java b/core/java/android/preference/GenericInflater.java
index 7de7d1c..918933b 100644
--- a/core/java/android/preference/GenericInflater.java
+++ b/core/java/android/preference/GenericInflater.java
@@ -23,6 +23,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.XmlRes;
 import android.content.Context;
 import android.content.res.XmlResourceParser;
 import android.util.AttributeSet;
@@ -216,7 +217,7 @@
      *         this is the root item; otherwise it is the root of the inflated
      *         XML file.
      */
-    public T inflate(int resource, P root) {
+    public T inflate(@XmlRes int resource, P root) {
         return inflate(resource, root, root != null);
     }
 
@@ -256,7 +257,7 @@
      *         attachToRoot is true, this is root; otherwise it is the root of
      *         the inflated XML file.
      */
-    public T inflate(int resource, P root, boolean attachToRoot) {
+    public T inflate(@XmlRes int resource, P root, boolean attachToRoot) {
         if (DEBUG) System.out.println("INFLATING from resource: " + resource);
         XmlResourceParser parser = getContext().getResources().getXml(resource);
         try {
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 9482a72..2700373 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.ArrayRes;
 import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -91,7 +92,7 @@
      * @see #setEntries(CharSequence[])
      * @param entriesResId The entries array as a resource.
      */
-    public void setEntries(int entriesResId) {
+    public void setEntries(@ArrayRes int entriesResId) {
         setEntries(getContext().getResources().getTextArray(entriesResId));
     }
     
@@ -119,7 +120,7 @@
      * @see #setEntryValues(CharSequence[])
      * @param entryValuesResId The entry values array as a resource.
      */
-    public void setEntryValues(int entryValuesResId) {
+    public void setEntryValues(@ArrayRes int entryValuesResId) {
         setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
     }
     
diff --git a/core/java/android/preference/MultiCheckPreference.java b/core/java/android/preference/MultiCheckPreference.java
index 57c906d..c1260a4 100644
--- a/core/java/android/preference/MultiCheckPreference.java
+++ b/core/java/android/preference/MultiCheckPreference.java
@@ -18,6 +18,7 @@
 
 import java.util.Arrays;
 
+import android.annotation.ArrayRes;
 import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -96,7 +97,7 @@
      * @see #setEntries(CharSequence[])
      * @param entriesResId The entries array as a resource.
      */
-    public void setEntries(int entriesResId) {
+    public void setEntries(@ArrayRes int entriesResId) {
         setEntries(getContext().getResources().getTextArray(entriesResId));
     }
     
@@ -126,7 +127,7 @@
      * @see #setEntryValues(CharSequence[])
      * @param entryValuesResId The entry values array as a resource.
      */
-    public void setEntryValues(int entryValuesResId) {
+    public void setEntryValues(@ArrayRes int entryValuesResId) {
         setEntryValuesCS(getContext().getResources().getTextArray(entryValuesResId));
     }
 
diff --git a/core/java/android/preference/MultiSelectListPreference.java b/core/java/android/preference/MultiSelectListPreference.java
index 6c4c20f..138bd878 100644
--- a/core/java/android/preference/MultiSelectListPreference.java
+++ b/core/java/android/preference/MultiSelectListPreference.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.ArrayRes;
 import android.app.AlertDialog.Builder;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -87,7 +88,7 @@
      * @see #setEntries(CharSequence[])
      * @param entriesResId The entries array as a resource.
      */
-    public void setEntries(int entriesResId) {
+    public void setEntries(@ArrayRes int entriesResId) {
         setEntries(getContext().getResources().getTextArray(entriesResId));
     }
     
@@ -115,7 +116,7 @@
      * @see #setEntryValues(CharSequence[])
      * @param entryValuesResId The entry values array as a resource.
      */
-    public void setEntryValues(int entryValuesResId) {
+    public void setEntryValues(@ArrayRes int entryValuesResId) {
         setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
     }
     
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 0224c73..ccf2cfa 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -16,8 +16,12 @@
 
 package android.preference;
 
+import android.annotation.CallSuper;
 import com.android.internal.util.CharSequences;
 
+import android.annotation.DrawableRes;
+import android.annotation.LayoutRes;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -424,7 +428,7 @@
      *            a {@link View}.
      * @see #setWidgetLayoutResource(int)
      */
-    public void setLayoutResource(int layoutResId) {
+    public void setLayoutResource(@LayoutRes int layoutResId) {
         if (layoutResId != mLayoutResId) {
             // Layout changed
             mCanRecycleLayout = false;
@@ -438,6 +442,7 @@
      * 
      * @return The layout resource ID.
      */
+    @LayoutRes
     public int getLayoutResource() {
         return mLayoutResId;
     }
@@ -452,7 +457,7 @@
      *            main layout.
      * @see #setLayoutResource(int)
      */
-    public void setWidgetLayoutResource(int widgetLayoutResId) {
+    public void setWidgetLayoutResource(@LayoutRes int widgetLayoutResId) {
         if (widgetLayoutResId != mWidgetLayoutResId) {
             // Layout changed
             mCanRecycleLayout = false;
@@ -465,6 +470,7 @@
      * 
      * @return The layout resource ID.
      */
+    @LayoutRes
     public int getWidgetLayoutResource() {
         return mWidgetLayoutResId;
     }
@@ -503,6 +509,7 @@
      * @return The View that displays this Preference.
      * @see #onBindView(View)
      */
+    @CallSuper
     protected View onCreateView(ViewGroup parent) {
         final LayoutInflater layoutInflater =
             (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -532,6 +539,7 @@
      * @param view The View that shows this Preference.
      * @see #onCreateView(ViewGroup)
      */
+    @CallSuper
     protected void onBindView(View view) {
         final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title);
         if (titleView != null) {
@@ -648,7 +656,7 @@
      * @see #setTitle(CharSequence)
      * @param titleResId The title as a resource ID.
      */
-    public void setTitle(int titleResId) {
+    public void setTitle(@StringRes int titleResId) {
         setTitle(mContext.getString(titleResId));
         mTitleRes = titleResId;
     }
@@ -660,6 +668,7 @@
      * @return The title resource.
      * @see #setTitle(int)
      */
+    @StringRes
     public int getTitleRes() {
         return mTitleRes;
     }
@@ -696,7 +705,7 @@
      * @see #setIcon(Drawable)
      * @param iconResId The icon as a resource ID.
      */
-    public void setIcon(int iconResId) {
+    public void setIcon(@DrawableRes int iconResId) {
         mIconResId = iconResId;
         setIcon(mContext.getDrawable(iconResId));
     }
@@ -739,7 +748,7 @@
      * @see #setSummary(CharSequence)
      * @param summaryResId The summary as a resource.
      */
-    public void setSummary(int summaryResId) {
+    public void setSummary(@StringRes int summaryResId) {
         setSummary(mContext.getString(summaryResId));
     }
     
@@ -1350,6 +1359,7 @@
      * should remove any references to this Preference that you know about. Make
      * sure to call through to the superclass implementation.
      */
+    @CallSuper
     protected void onPrepareForRemoval() {
         unregisterDependency();
     }
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 04cd7d5..06666f4 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -16,6 +16,9 @@
 
 package android.preference;
 
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.annotation.XmlRes;
 import android.app.Fragment;
 import android.app.FragmentBreadCrumbs;
 import android.app.FragmentManager;
@@ -337,6 +340,7 @@
          * Resource ID of title of the header that is shown to the user.
          * @attr ref android.R.styleable#PreferenceHeader_title
          */
+        @StringRes
         public int titleRes;
 
         /**
@@ -349,6 +353,7 @@
          * Resource ID of optional summary describing what this header controls.
          * @attr ref android.R.styleable#PreferenceHeader_summary
          */
+        @StringRes
         public int summaryRes;
 
         /**
@@ -361,6 +366,7 @@
          * Resource ID of optional text to show as the title in the bread crumb.
          * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle
          */
+        @StringRes
         public int breadCrumbTitleRes;
 
         /**
@@ -373,6 +379,7 @@
          * Resource ID of optional text to show as the short title in the bread crumb.
          * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle
          */
+        @StringRes
         public int breadCrumbShortTitleRes;
 
         /**
@@ -525,7 +532,7 @@
     }
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         // Theming for the PreferenceActivity layout and for the Preference Header(s) layout
@@ -797,7 +804,7 @@
      * @param resid The XML resource to load and parse.
      * @param target The list in which the parsed headers should be placed.
      */
-    public void loadHeadersFromResource(int resid, List<Header> target) {
+    public void loadHeadersFromResource(@XmlRes int resid, List<Header> target) {
         XmlResourceParser parser = null;
         try {
             parser = getResources().getXml(resid);
@@ -1086,7 +1093,7 @@
      * fragment.
      */
     public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
-            int titleRes, int shortTitleRes) {
+            @StringRes int titleRes, int shortTitleRes) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClass(this, getClass());
         intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
@@ -1124,7 +1131,8 @@
      * this set of preferences.
      */
     public void startWithFragment(String fragmentName, Bundle args,
-            Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
+            Fragment resultTo, int resultRequestCode, @StringRes int titleRes,
+            @StringRes int shortTitleRes) {
         Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
         if (resultTo == null) {
             startActivity(intent);
@@ -1343,9 +1351,9 @@
      * preference panel is done.  The launched panel must use
      * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
      * @param resultRequestCode If resultTo is non-null, this is the caller's
-     * request code to be received with the resut.
+     * request code to be received with the result.
      */
-    public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
+    public void startPreferencePanel(String fragmentClass, Bundle args, @StringRes int titleRes,
             CharSequence titleText, Fragment resultTo, int resultRequestCode) {
         if (mSinglePane) {
             startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index e95e6e2..29f9ca1 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Intent;
@@ -153,15 +154,15 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mPreferenceManager = new PreferenceManager(getActivity(), FIRST_REQUEST_CODE);
         mPreferenceManager.setFragment(this);
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
 
         TypedArray a = getActivity().obtainStyledAttributes(null,
                 com.android.internal.R.styleable.PreferenceFragment,
@@ -177,7 +178,7 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         if (mHavePrefs) {
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 2d35b1b..5e84086 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -19,12 +19,9 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 0a0e625..55ee77a 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.XmlRes;
 import android.app.Activity;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -263,7 +264,7 @@
      *         root).
      * @hide
      */
-    public PreferenceScreen inflateFromResource(Context context, int resId,
+    public PreferenceScreen inflateFromResource(Context context, @XmlRes int resId,
             PreferenceScreen rootPreferences) {
         // Block commits
         setNoCommit(true);
@@ -438,7 +439,7 @@
      *            and clear it followed by a call to this method with this
      *            parameter set to true.
      */
-    public static void setDefaultValues(Context context, int resId, boolean readAgain) {
+    public static void setDefaultValues(Context context, @XmlRes int resId, boolean readAgain) {
         
         // Use the default shared preferences name and mode
         setDefaultValues(context, getDefaultSharedPreferencesName(context),
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index c3dd4ce..30da0e7 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -174,6 +175,11 @@
             }
             if (mRingtone != null) {
                 try {
+                    mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
+                            .getAudioAttributes())
+                            .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
+                                    AudioAttributes.FLAG_BYPASS_MUTE)
+                            .build());
                     mRingtone.play();
                 } catch (Throwable e) {
                     Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java
index 53b5aad..9c3cefc 100644
--- a/core/java/android/preference/SwitchPreference.java
+++ b/core/java/android/preference/SwitchPreference.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
@@ -169,7 +170,7 @@
      *
      * @param resId The text as a string resource ID
      */
-    public void setSwitchTextOn(int resId) {
+    public void setSwitchTextOn(@StringRes int resId) {
         setSwitchTextOn(getContext().getString(resId));
     }
 
@@ -179,7 +180,7 @@
      *
      * @param resId The text as a string resource ID
      */
-    public void setSwitchTextOff(int resId) {
+    public void setSwitchTextOff(@StringRes int resId) {
         setSwitchTextOff(getContext().getString(resId));
     }
 
diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java
index 3823b27..7037aca 100644
--- a/core/java/android/preference/TwoStatePreference.java
+++ b/core/java/android/preference/TwoStatePreference.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.TypedArray;
@@ -116,7 +117,7 @@
      * @see #setSummaryOn(CharSequence)
      * @param summaryResId The summary as a resource.
      */
-    public void setSummaryOn(int summaryResId) {
+    public void setSummaryOn(@StringRes int summaryResId) {
         setSummaryOn(getContext().getString(summaryResId));
     }
 
@@ -144,7 +145,7 @@
      * @see #setSummaryOff(CharSequence)
      * @param summaryResId The summary as a resource.
      */
-    public void setSummaryOff(int summaryResId) {
+    public void setSummaryOff(@StringRes int summaryResId) {
         setSummaryOff(getContext().getString(summaryResId));
     }
 
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 30f0c6a..90d30d6 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -45,11 +45,22 @@
     private static final int VALID_COLOR_MODES =
             COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
 
+    /** Duplex mode: No duplexing. */
+    public static final int DUPLEX_MODE_NONE = 1 << 0;
+    /** Duplex mode: Pages are turned sideways along the long edge - like a book. */
+    public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1;
+    /** Duplex mode: Pages are turned upwards along the short edge - like a notpad. */
+    public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2;
+
+    private static final int VALID_DUPLEX_MODES =
+            DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
+
     private MediaSize mMediaSize;
     private Resolution mResolution;
     private Margins mMinMargins;
 
     private int mColorMode;
+    private int mDuplexMode = DUPLEX_MODE_NONE;
 
     PrintAttributes() {
         /* hide constructor */
@@ -60,6 +71,7 @@
         mResolution = (parcel.readInt() ==  1) ? Resolution.createFromParcel(parcel) : null;
         mMinMargins = (parcel.readInt() ==  1) ? Margins.createFromParcel(parcel) : null;
         mColorMode = parcel.readInt();
+        mDuplexMode = parcel.readInt();
     }
 
     /**
@@ -74,7 +86,7 @@
     /**
      * Sets the media size.
      *
-     * @param The media size.
+     * @param mediaSize The media size.
      *
      * @hide
      */
@@ -94,7 +106,7 @@
     /**
      * Sets the resolution.
      *
-     * @param The resolution.
+     * @param resolution The resolution.
      *
      * @hide
      */
@@ -130,7 +142,7 @@
      * </strong>
      * </p>
      *
-     * @param The margins.
+     * @param margins The margins.
      *
      * @hide
      */
@@ -153,7 +165,7 @@
     /**
      * Sets the color mode.
      *
-     * @param The color mode.
+     * @param colorMode The color mode.
      *
      * @see #COLOR_MODE_MONOCHROME
      * @see #COLOR_MODE_COLOR
@@ -179,6 +191,35 @@
     }
 
     /**
+     * Gets the duplex mode.
+     *
+     * @return The duplex mode.
+     *
+     * @see #DUPLEX_MODE_NONE
+     * @see #DUPLEX_MODE_LONG_EDGE
+     * @see #DUPLEX_MODE_SHORT_EDGE
+     */
+    public int getDuplexMode() {
+        return mDuplexMode;
+    }
+
+    /**
+     * Sets the duplex mode.
+     *
+     * @param duplexMode The duplex mode.
+     *
+     * @see #DUPLEX_MODE_NONE
+     * @see #DUPLEX_MODE_LONG_EDGE
+     * @see #DUPLEX_MODE_SHORT_EDGE
+     *
+     * @hide
+     */
+    public void setDuplexMode(int duplexMode) {
+        enforceValidDuplexMode(duplexMode);
+        mDuplexMode = duplexMode;
+    }
+
+    /**
      * Gets a new print attributes instance which is in portrait orientation,
      * which is the media size is in portrait and all orientation dependent
      * attributes such as resolution and margins are properly adjusted.
@@ -211,6 +252,7 @@
         attributes.setMinMargins(getMinMargins());
 
         attributes.setColorMode(getColorMode());
+        attributes.setDuplexMode(getDuplexMode());
 
         return attributes;
     }
@@ -248,6 +290,7 @@
         attributes.setMinMargins(getMinMargins());
 
         attributes.setColorMode(getColorMode());
+        attributes.setDuplexMode(getDuplexMode());
 
         return attributes;
     }
@@ -273,6 +316,7 @@
             parcel.writeInt(0);
         }
         parcel.writeInt(mColorMode);
+        parcel.writeInt(mDuplexMode);
     }
 
     @Override
@@ -285,6 +329,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + mColorMode;
+        result = prime * result + mDuplexMode;
         result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
         result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
         result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
@@ -306,6 +351,9 @@
         if (mColorMode != other.mColorMode) {
             return false;
         }
+        if (mDuplexMode != other.mDuplexMode) {
+            return false;
+        }
         if (mMinMargins == null) {
             if (other.mMinMargins != null) {
                 return false;
@@ -344,6 +392,7 @@
         builder.append(", resolution: ").append(mResolution);
         builder.append(", minMargins: ").append(mMinMargins);
         builder.append(", colorMode: ").append(colorModeToString(mColorMode));
+        builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
         builder.append("}");
         return builder.toString();
     }
@@ -354,6 +403,7 @@
         mResolution = null;
         mMinMargins = null;
         mColorMode = 0;
+        mDuplexMode = DUPLEX_MODE_NONE;
     }
 
     /**
@@ -364,6 +414,7 @@
         mResolution = other.mResolution;
         mMinMargins = other.mMinMargins;
         mColorMode = other.mColorMode;
+        mDuplexMode = other.mDuplexMode;
     }
 
     /**
@@ -1270,17 +1321,41 @@
             case COLOR_MODE_COLOR: {
                 return "COLOR_MODE_COLOR";
             }
-            default:
+            default: {
                 return "COLOR_MODE_UNKNOWN";
+            }
+        }
+    }
+
+    static String duplexModeToString(int duplexMode) {
+        switch (duplexMode) {
+            case DUPLEX_MODE_NONE: {
+                return "DUPLEX_MODE_NONE";
+            }
+            case DUPLEX_MODE_LONG_EDGE: {
+                return "DUPLEX_MODE_LONG_EDGE";
+            }
+            case DUPLEX_MODE_SHORT_EDGE: {
+                return "DUPLEX_MODE_SHORT_EDGE";
+            }
+            default: {
+                return "DUPLEX_MODE_UNKNOWN";
+            }
         }
     }
 
     static void enforceValidColorMode(int colorMode) {
-        if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
+        if ((colorMode & VALID_COLOR_MODES) == 0 || Integer.bitCount(colorMode) != 1) {
             throw new IllegalArgumentException("invalid color mode: " + colorMode);
         }
     }
 
+    static void enforceValidDuplexMode(int duplexMode) {
+        if ((duplexMode & VALID_DUPLEX_MODES) == 0 || Integer.bitCount(duplexMode) != 1) {
+            throw new IllegalArgumentException("invalid duplex mode: " + duplexMode);
+        }
+    }
+
     /**
      * Builder for creating {@link PrintAttributes}.
      */
@@ -1331,15 +1406,31 @@
          * @see PrintAttributes#COLOR_MODE_COLOR
          */
         public Builder setColorMode(int colorMode) {
-            if (Integer.bitCount(colorMode) > 1) {
-                throw new IllegalArgumentException("can specify at most one colorMode bit.");
-            }
             mAttributes.setColorMode(colorMode);
             return this;
         }
 
         /**
+         * Sets the duplex mode.
+         *
+         * @param duplexMode A valid duplex mode or zero.
+         * @return This builder.
+         *
+         * @see PrintAttributes#DUPLEX_MODE_NONE
+         * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+         * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+         */
+        public Builder setDuplexMode(int duplexMode) {
+            mAttributes.setDuplexMode(duplexMode);
+            return this;
+        }
+
+        /**
          * Creates a new {@link PrintAttributes} instance.
+         * <p>
+         * If you do not specify a duplex mode, the default
+         * {@link #DUPLEX_MODE_NONE} will be used.
+         * </p>
          *
          * @return The new instance.
          */
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 806a89d8..96f3185 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -47,7 +47,8 @@
     private static final int PROPERTY_MEDIA_SIZE = 0;
     private static final int PROPERTY_RESOLUTION = 1;
     private static final int PROPERTY_COLOR_MODE = 2;
-    private static final int PROPERTY_COUNT = 3;
+    private static final int PROPERTY_DUPLEX_MODE = 3;
+    private static final int PROPERTY_COUNT = 4;
 
     private static final Margins DEFAULT_MARGINS = new Margins(0,  0,  0,  0);
 
@@ -56,6 +57,7 @@
     private List<Resolution> mResolutions;
 
     private int mColorModes;
+    private int mDuplexModes;
 
     private final int[] mDefaults = new int[PROPERTY_COUNT];
 
@@ -106,6 +108,7 @@
         }
 
         mColorModes = other.mColorModes;
+        mDuplexModes = other.mDuplexModes;
 
         final int defaultCount = other.mDefaults.length;
         for (int i = 0; i < defaultCount; i++) {
@@ -154,6 +157,19 @@
     }
 
     /**
+     * Gets the bit mask of supported duplex modes.
+     *
+     * @return The bit mask of supported duplex modes.
+     *
+     * @see PrintAttributes#DUPLEX_MODE_NONE
+     * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+     * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+     */
+    public int getDuplexModes() {
+        return mDuplexModes;
+    }
+
+    /**
      * Gets the default print attributes.
      *
      * @return The default attributes.
@@ -178,6 +194,11 @@
             builder.setColorMode(colorMode);
         }
 
+        final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE];
+        if (duplexMode > 0) {
+            builder.setDuplexMode(duplexMode);
+        }
+
         return builder.build();
     }
 
@@ -187,6 +208,7 @@
         readResolutions(parcel);
 
         mColorModes = parcel.readInt();
+        mDuplexModes = parcel.readInt();
 
         readDefaults(parcel);
     }
@@ -203,6 +225,7 @@
         writeResolutions(parcel);
 
         parcel.writeInt(mColorModes);
+        parcel.writeInt(mDuplexModes);
 
         writeDefaults(parcel);
     }
@@ -215,6 +238,7 @@
         result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
         result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
         result = prime * result + mColorModes;
+        result = prime * result + mDuplexModes;
         result = prime * result + Arrays.hashCode(mDefaults);
         return result;
     }
@@ -255,6 +279,9 @@
         if (mColorModes != other.mColorModes) {
             return false;
         }
+        if (mDuplexModes != other.mDuplexModes) {
+            return false;
+        }
         if (!Arrays.equals(mDefaults, other.mDefaults)) {
             return false;
         }
@@ -269,6 +296,7 @@
         builder.append(", mediaSizes=").append(mMediaSizes);
         builder.append(", resolutions=").append(mResolutions);
         builder.append(", colorModes=").append(colorModesToString());
+        builder.append(", duplexModes=").append(duplexModesToString());
         builder.append("\"}");
         return builder.toString();
     }
@@ -289,6 +317,22 @@
         return builder.toString();
     }
 
+    private String duplexModesToString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        int duplexModes = mDuplexModes;
+        while (duplexModes != 0) {
+            final int duplexMode = 1 << Integer.numberOfTrailingZeros(duplexModes);
+            duplexModes &= ~duplexMode;
+            if (builder.length() > 1) {
+                builder.append(", ");
+            }
+            builder.append(PrintAttributes.duplexModeToString(duplexMode));
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
     private void writeMediaSizes(Parcel parcel) {
         if (mMediaSizes == null) {
             parcel.writeInt(0);
@@ -495,19 +539,51 @@
                 currentModes &= ~currentMode;
                 PrintAttributes.enforceValidColorMode(currentMode);
             }
-            if ((colorModes & defaultColorMode) == 0) {
-                throw new IllegalArgumentException("Default color mode not in color modes.");
-            }
-            PrintAttributes.enforceValidColorMode(colorModes);
+            PrintAttributes.enforceValidColorMode(defaultColorMode);
             mPrototype.mColorModes = colorModes;
             mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
             return this;
         }
 
         /**
+         * Sets the duplex modes.
+         * <p>
+         * <strong>Required:</strong> No
+         * </p>
+         *
+         * @param duplexModes The duplex mode bit mask.
+         * @param defaultDuplexMode The default duplex mode.
+         * @return This builder.
+         *
+         * @throws IllegalArgumentException If duplex modes contains an invalid
+         *         mode bit or if the default duplex mode is invalid.
+         *
+         * @see PrintAttributes#DUPLEX_MODE_NONE
+         * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
+         * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
+         */
+        public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
+            int currentModes = duplexModes;
+            while (currentModes > 0) {
+                final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
+                currentModes &= ~currentMode;
+                PrintAttributes.enforceValidDuplexMode(currentMode);
+            }
+            PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
+            mPrototype.mDuplexModes = duplexModes;
+            mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
+            return this;
+        }
+
+        /**
          * Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
          * required properties have been specified. See individual methods
          * in this class for reference about required attributes.
+         * <p>
+         * <strong>Note:</strong> If you do not add supported duplex modes,
+         * {@link android.print.PrintAttributes#DUPLEX_MODE_NONE} will set
+         * as the only supported mode and also as the default duplex mode.
+         * </p>
          *
          * @return A new {@link PrinterCapabilitiesInfo}.
          *
@@ -532,6 +608,10 @@
             if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
                 throw new IllegalStateException("No default color mode specified.");
             }
+            if (mPrototype.mDuplexModes == 0) {
+                setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
+                        PrintAttributes.DUPLEX_MODE_NONE);
+            }
             if (mPrototype.mMinMargins == null) {
                 throw new IllegalArgumentException("margins cannot be null");
             }
@@ -558,4 +638,3 @@
         }
     };
 }
-
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index c5aee7b..527c8ae 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,7 +16,6 @@
 
 package android.printservice;
 
-import android.R;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
@@ -192,7 +191,7 @@
 
     /**
      * If you declared an optional activity with advanced print options via the
-     * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
      * attribute, this extra is used to pass in the currently constructed {@link
      * PrintJobInfo} to your activity allowing you to modify it. After you are
      * done, you must return the modified {@link PrintJobInfo} via the same extra.
@@ -224,7 +223,7 @@
 
     /**
      * If you declared an optional activity with advanced print options via the
-     * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
      * attribute, this extra is used to pass in the currently selected printer's
      * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
      *
@@ -386,7 +385,7 @@
 
             @Override
             public void setClient(IPrintServiceClient client) {
-                mHandler.obtainMessage(ServiceHandler.MSG_SET_CLEINT, client)
+                mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client)
                         .sendToTarget();
             }
 
@@ -414,7 +413,7 @@
         public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
         public static final int MSG_ON_PRINTJOB_QUEUED = 8;
         public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
-        public static final int MSG_SET_CLEINT = 10;
+        public static final int MSG_SET_CLIENT = 10;
 
         public ServiceHandler(Looper looper) {
             super(looper, null, true);
@@ -528,9 +527,9 @@
                     onPrintJobQueued(new PrintJob(printJobInfo, mClient));
                 } break;
 
-                case MSG_SET_CLEINT: {
+                case MSG_SET_CLIENT: {
                     if (DEBUG) {
-                        Log.i(LOG_TAG, "MSG_SET_CLEINT "
+                        Log.i(LOG_TAG, "MSG_SET_CLIENT "
                                 + getPackageName());
                     }
                     mClient = (IPrintServiceClient) message.obj;
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 3853003..69a05c4 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -25,7 +25,6 @@
 import android.database.DatabaseUtils;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
-import android.os.Build;
 import android.provider.BrowserContract.Bookmarks;
 import android.provider.BrowserContract.Combined;
 import android.provider.BrowserContract.History;
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 2df9dbf..ac54da34 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -328,6 +328,14 @@
         public static final String CACHED_PHOTO_ID = "photo_id";
 
         /**
+         * The cached photo URI of the picture associated with the phone number, if it exists.
+         * This value may not be current if the contact information associated with this number
+         * has changed.
+         * <P>Type: TEXT (URI)</P>
+         */
+        public static final String CACHED_PHOTO_URI = "photo_uri";
+
+        /**
          * The cached phone number, formatted with formatting rules based on the country the
          * user was in when the call was made or received.
          * This value is not guaranteed to be present, and may not be current if the contact
@@ -353,6 +361,16 @@
         public static final String PHONE_ACCOUNT_ID = "subscription_id";
 
         /**
+         * Indicates that the entry will be hidden from all queries until the associated
+         * {@link android.telecom.PhoneAccount} is registered with the system.
+         * <P>Type: INTEGER</P>
+         *
+         * @Deprecated
+         * @hide
+         */
+        public static final String PHONE_ACCOUNT_HIDDEN = "phone_account_hidden";
+
+        /**
          * The address associated with the account used to place or receive the call; in string
          * form. For SIM-based calls, this is the user's own phone number.
          * <P>Type: TEXT</P>
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index d4c5cfb..3aa526d 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -2077,12 +2077,12 @@
 
         /**
          * Intents related to the Contacts app UI.
-         * @deprecated see {@link android.provider.ContactsContract}
+         * @deprecated Do not use. This is not supported.
          */
         @Deprecated
         public static final class UI {
             /**
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public UI() {
@@ -2090,76 +2090,77 @@
 
             /**
              * The action for the default contacts list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
-            public static final String LIST_DEFAULT = ContactsContract.Intents.UI.LIST_DEFAULT;
+            public static final String LIST_DEFAULT
+                    = "com.android.contacts.action.LIST_DEFAULT";
 
             /**
              * The action for the contacts list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_GROUP_ACTION =
-                    ContactsContract.Intents.UI.LIST_GROUP_ACTION;
+                    "com.android.contacts.action.LIST_GROUP";
 
             /**
              * When in LIST_GROUP_ACTION mode, this is the group to display.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String GROUP_NAME_EXTRA_KEY =
-                    ContactsContract.Intents.UI.GROUP_NAME_EXTRA_KEY;
+                    "com.android.contacts.extra.GROUP";
             /**
              * The action for the all contacts list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_ALL_CONTACTS_ACTION =
-                    ContactsContract.Intents.UI.LIST_ALL_CONTACTS_ACTION;
+                    "com.android.contacts.action.LIST_ALL_CONTACTS";
 
             /**
              * The action for the contacts with phone numbers list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
-                    ContactsContract.Intents.UI.LIST_CONTACTS_WITH_PHONES_ACTION;
+                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
 
             /**
              * The action for the starred contacts list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_STARRED_ACTION =
-                    ContactsContract.Intents.UI.LIST_STARRED_ACTION;
+                    "com.android.contacts.action.LIST_STARRED";
 
             /**
              * The action for the frequent contacts list tab.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_FREQUENT_ACTION =
-                    ContactsContract.Intents.UI.LIST_FREQUENT_ACTION;
+                    "com.android.contacts.action.LIST_FREQUENT";
 
             /**
              * The action for the "strequent" contacts list tab. It first lists the starred
              * contacts in alphabetical order and then the frequent contacts in descending
              * order of the number of times they have been contacted.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String LIST_STREQUENT_ACTION =
-                    ContactsContract.Intents.UI.LIST_STREQUENT_ACTION;
+                    "com.android.contacts.action.LIST_STREQUENT";
 
             /**
              * A key for to be used as an intent extra to set the activity
              * title to a custom String value.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String TITLE_EXTRA_KEY =
-                    ContactsContract.Intents.UI.TITLE_EXTRA_KEY;
+                    "com.android.contacts.extra.TITLE_EXTRA";
 
             /**
              * Activity Action: Display a filtered list of contacts
@@ -2168,20 +2169,20 @@
              * filtering
              * <p>
              * Output: Nothing.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String FILTER_CONTACTS_ACTION =
-                    ContactsContract.Intents.UI.FILTER_CONTACTS_ACTION;
+                    "com.android.contacts.action.FILTER_CONTACTS";
 
             /**
              * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
              * intents to supply the text on which to filter.
-             * @deprecated see {@link android.provider.ContactsContract}
+             * @deprecated Do not use. This is not supported.
              */
             @Deprecated
             public static final String FILTER_TEXT_EXTRA_KEY =
-                    ContactsContract.Intents.UI.FILTER_TEXT_EXTRA_KEY;
+                    "com.android.contacts.extra.FILTER_TEXT";
         }
 
         /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 18a9eb1..91a19dc 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -197,12 +197,15 @@
      * API for obtaining a pre-authorized version of a URI that normally requires special
      * permission (beyond READ_CONTACTS) to read.  The caller obtaining the pre-authorized URI
      * must already have the necessary permissions to access the URI; otherwise a
-     * {@link SecurityException} will be thrown.
+     * {@link SecurityException} will be thrown. Unlike {@link Context#grantUriPermission},
+     * this can be used to grant permissions that aren't explicitly required for the URI inside
+     * AndroidManifest.xml. For example, permissions that are only required when reading URIs
+     * that refer to the user's profile.
      * </p>
      * <p>
      * The authorized URI returned in the bundle contains an expiring token that allows the
      * caller to execute the query without having the special permissions that would normally
-     * be required.
+     * be required. The token expires in five minutes.
      * </p>
      * <p>
      * This API does not access disk, and should be safe to invoke from the UI thread.
@@ -226,7 +229,6 @@
      * }
      * </pre>
      * </p>
-     * @hide
      */
     public static final class Authorization {
         /**
@@ -1008,7 +1010,8 @@
     /**
      * Types of data used to produce the display name for a contact. In the order
      * of increasing priority: {@link #EMAIL}, {@link #PHONE},
-     * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_NAME}.
+     * {@link #ORGANIZATION}, {@link #NICKNAME}, {@link #STRUCTURED_PHONETIC_NAME},
+     * {@link #STRUCTURED_NAME}.
      */
     public interface DisplayNameSources {
         public static final int UNDEFINED = 0;
@@ -1016,6 +1019,8 @@
         public static final int PHONE = 20;
         public static final int ORGANIZATION = 30;
         public static final int NICKNAME = 35;
+        /** Display name comes from a structured name that only has phonetic components. */
+        public static final int STRUCTURED_PHONETIC_NAME = 37;
         public static final int STRUCTURED_NAME = 40;
     }
 
@@ -1432,9 +1437,9 @@
         * and {@link #CONTENT_MULTI_VCARD_URI} to indicate that the returned
         * vcard should not contain a photo.
         *
-        * @hide
+        * This is useful for obtaining a space efficient vcard.
         */
-        public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "nophoto";
+        public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
 
         /**
          * Base {@link Uri} for referencing multiple {@link Contacts} entry,
@@ -1790,52 +1795,26 @@
             public static final String CONTENT_DIRECTORY = "suggestions";
 
             /**
-             * Used with {@link Builder#addParameter} to specify what kind of data is
-             * supplied for the suggestion query.
+             * Used to specify what kind of data is supplied for the suggestion query.
              *
              * @hide
              */
             public static final String PARAMETER_MATCH_NAME = "name";
 
             /**
-             * Used with {@link Builder#addParameter} to specify what kind of data is
-             * supplied for the suggestion query.
-             *
-             * @hide
-             */
-            public static final String PARAMETER_MATCH_EMAIL = "email";
-
-            /**
-             * Used with {@link Builder#addParameter} to specify what kind of data is
-             * supplied for the suggestion query.
-             *
-             * @hide
-             */
-            public static final String PARAMETER_MATCH_PHONE = "phone";
-
-            /**
-             * Used with {@link Builder#addParameter} to specify what kind of data is
-             * supplied for the suggestion query.
-             *
-             * @hide
-             */
-            public static final String PARAMETER_MATCH_NICKNAME = "nickname";
-
-            /**
              * A convenience builder for aggregation suggestion content URIs.
-             *
-             * TODO: change documentation for this class to use the builder.
-             * @hide
              */
             public static final class Builder {
                 private long mContactId;
-                private ArrayList<String> mKinds = new ArrayList<String>();
-                private ArrayList<String> mValues = new ArrayList<String>();
+                private final ArrayList<String> mValues = new ArrayList<String>();
                 private int mLimit;
 
                 /**
                  * Optional existing contact ID.  If it is not provided, the search
-                 * will be based exclusively on the values supplied with {@link #addParameter}.
+                 * will be based exclusively on the values supplied with {@link #addNameParameter}.
+                 *
+                 * @param contactId contact to find aggregation suggestions for
+                 * @return This Builder object to allow for chaining of calls to builder methods
                  */
                 public Builder setContactId(long contactId) {
                     this.mContactId = contactId;
@@ -1843,28 +1822,31 @@
                 }
 
                 /**
-                 * A value that can be used when searching for an aggregation
-                 * suggestion.
+                 * Add a name to be used when searching for aggregation suggestions.
                  *
-                 * @param kind can be one of
-                 *            {@link AggregationSuggestions#PARAMETER_MATCH_NAME},
-                 *            {@link AggregationSuggestions#PARAMETER_MATCH_EMAIL},
-                 *            {@link AggregationSuggestions#PARAMETER_MATCH_NICKNAME},
-                 *            {@link AggregationSuggestions#PARAMETER_MATCH_PHONE}
+                 * @param name name to find aggregation suggestions for
+                 * @return This Builder object to allow for chaining of calls to builder methods
                  */
-                public Builder addParameter(String kind, String value) {
-                    if (!TextUtils.isEmpty(value)) {
-                        mKinds.add(kind);
-                        mValues.add(value);
-                    }
+                public Builder addNameParameter(String name) {
+                    mValues.add(name);
                     return this;
                 }
 
+                /**
+                 * Sets the Maximum number of suggested aggregations that should be returned.
+                 * @param limit The maximum number of suggested aggregations
+                 *
+                 * @return This Builder object to allow for chaining of calls to builder methods
+                 */
                 public Builder setLimit(int limit) {
                     mLimit = limit;
                     return this;
                 }
 
+                /**
+                 * Combine all of the options that have been set and return a new {@link Uri}
+                 * object for fetching aggregation suggestions.
+                 */
                 public Uri build() {
                     android.net.Uri.Builder builder = Contacts.CONTENT_URI.buildUpon();
                     builder.appendEncodedPath(String.valueOf(mContactId));
@@ -1873,9 +1855,10 @@
                         builder.appendQueryParameter("limit", String.valueOf(mLimit));
                     }
 
-                    int count = mKinds.size();
+                    int count = mValues.size();
                     for (int i = 0; i < count; i++) {
-                        builder.appendQueryParameter("query", mKinds.get(i) + ":" + mValues.get(i));
+                        builder.appendQueryParameter("query", PARAMETER_MATCH_NAME
+                                + ":" + mValues.get(i));
                     }
 
                     return builder.build();
@@ -2214,6 +2197,16 @@
         public static final String CONTACT_ID = "contact_id";
 
         /**
+         * Persistent unique id for each raw_contact within its account.
+         * This id is provided by its own data source, and can be used to backup metadata
+         * to the server.
+         * This should be unique within each set of account_name/account_type/data_set
+         *
+         * @hide
+         */
+        public static final String BACKUP_ID = "backup_id";
+
+        /**
          * The data set within the account that this row belongs to.  This allows
          * multiple sync adapters for the same account type to distinguish between
          * each others' data.
@@ -2258,33 +2251,6 @@
         public static final String DELETED = "deleted";
 
         /**
-         * The "name_verified" flag: "1" means that the name fields on this raw
-         * contact can be trusted and therefore should be used for the entire
-         * aggregated contact.
-         * <p>
-         * If an aggregated contact contains more than one raw contact with a
-         * verified name, one of those verified names is chosen at random.
-         * If an aggregated contact contains no verified names, the
-         * name is chosen randomly from the constituent raw contacts.
-         * </p>
-         * <p>
-         * Updating this flag from "0" to "1" automatically resets it to "0" on
-         * all other raw contacts in the same aggregated contact.
-         * </p>
-         * <p>
-         * Sync adapters should only specify a value for this column when
-         * inserting a raw contact and leave it out when doing an update.
-         * </p>
-         * <p>
-         * The default value is "0"
-         * </p>
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final String NAME_VERIFIED = "name_verified";
-
-        /**
          * The "read-only" flag: "0" by default, "1" if the row cannot be modified or
          * deleted except by a sync adapter.  See {@link ContactsContract#CALLER_IS_SYNCADAPTER}.
          * <P>Type: INTEGER</P>
@@ -2980,7 +2946,6 @@
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
                 DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
-                DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, NAME_VERIFIED);
                 android.content.Entity contact = new android.content.Entity(cv);
 
                 // read data rows until the contact id changes
@@ -4006,6 +3971,13 @@
         public static final String MIMETYPE = "mimetype";
 
         /**
+         * Hash id on the data fields, used for backup and restore.
+         *
+         * @hide
+         */
+        public static final String HASH_ID = "hash_id";
+
+        /**
          * A reference to the {@link RawContacts#_ID}
          * that this data belongs to.
          */
@@ -4628,6 +4600,15 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
 
         /**
+        * The content:// style URI for this table in managed profile, which requests a directory
+        * of data rows matching the selection criteria.
+        *
+        * @hide
+        */
+        static final Uri ENTERPRISE_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "data_enterprise");
+
+        /**
          * A boolean parameter for {@link Data#CONTENT_URI}.
          * This specifies whether or not the returned data items should be filtered to show
          * data items belonging to visible contacts only.
@@ -5779,6 +5760,20 @@
                     "phones");
 
             /**
+            * URI used for getting all contacts from primary and managed profile.
+            *
+            * It supports the same semantics as {@link #CONTENT_URI} and returns the same
+            * columns.  If the device has no corp profile that is linked to the current profile, it
+            * behaves in the exact same way as {@link #CONTENT_URI}.  If there is a corp profile
+            * linked to the current profile, it will merge corp profile and current profile's
+            * results and return
+            *
+            * @hide
+            */
+            public static final Uri ENTERPRISE_CONTENT_URI =
+                    Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
+
+            /**
              * The content:// style URL for phone lookup using a filter. The filter returns
              * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied
              * to display names as well as phone numbers. The filter argument should be passed
@@ -7839,9 +7834,7 @@
     }
 
     /**
-     * Private API for inquiring about the general status of the provider.
-     *
-     * @hide
+     * API for inquiring about the general status of the provider.
      */
     public static final class ProviderStatus {
 
@@ -7854,8 +7847,6 @@
         /**
          * The content:// style URI for this table.  Requests to this URI can be
          * performed on the UI thread because they are always unblocking.
-         *
-         * @hide
          */
         public static final Uri CONTENT_URI =
                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
@@ -7863,64 +7854,35 @@
         /**
          * The MIME-type of {@link #CONTENT_URI} providing a directory of
          * settings.
-         *
-         * @hide
          */
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
 
         /**
          * An integer representing the current status of the provider.
-         *
-         * @hide
          */
         public static final String STATUS = "status";
 
         /**
          * Default status of the provider.
-         *
-         * @hide
          */
         public static final int STATUS_NORMAL = 0;
 
         /**
          * The status used when the provider is in the process of upgrading.  Contacts
          * are temporarily unaccessible.
-         *
-         * @hide
          */
         public static final int STATUS_UPGRADING = 1;
 
         /**
-         * The status used if the provider was in the process of upgrading but ran
-         * out of storage. The DATA1 column will contain the estimated amount of
-         * storage required (in bytes). Update status to STATUS_NORMAL to force
-         * the provider to retry the upgrade.
-         *
-         * @hide
-         */
-        public static final int STATUS_UPGRADE_OUT_OF_MEMORY = 2;
-
-        /**
          * The status used during a locale change.
-         *
-         * @hide
          */
         public static final int STATUS_CHANGING_LOCALE = 3;
 
         /**
          * The status that indicates that there are no accounts and no contacts
          * on the device.
-         *
-         * @hide
          */
         public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4;
-
-        /**
-         * Additional data associated with the status.
-         *
-         * @hide
-         */
-        public static final String DATA1 = "data1";
     }
 
     /**
@@ -8125,12 +8087,22 @@
         public static final String EXTRA_TARGET_RECT = "android.provider.extra.TARGET_RECT";
 
         /**
-         * Extra used to specify size of pivot dialog.
-         * @hide
+         * Extra used to specify size of QuickContacts. Not all implementations of QuickContacts
+         * will respect this extra's value.
+         *
+         * One of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
          */
         public static final String EXTRA_MODE = "android.provider.extra.MODE";
 
         /**
+         * Extra used to specify which mimetype should be prioritized in the QuickContacts UI.
+         * For example, passing the value {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can
+         * cause phone numbers to be displayed more prominently in QuickContacts.
+         */
+        public static final String EXTRA_PRIORITIZED_MIMETYPE
+                = "android.provider.extra.PRIORITIZED_MIMETYPE";
+
+        /**
          * Extra used to indicate a list of specific MIME-types to exclude and not display in the
          * QuickContacts dialog. Stored as a {@link String} array.
          */
@@ -8268,6 +8240,80 @@
             startActivityWithErrorToast(context, intent);
         }
 
+        /**
+         * Trigger a dialog that lists the various methods of interacting with
+         * the requested {@link Contacts} entry. This may be based on available
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
+         *
+         * @param context The parent {@link Context} that may be used as the
+         *            parent for this dialog.
+         * @param target Specific {@link View} from your layout that this dialog
+         *            should be centered around. In particular, if the dialog
+         *            has a "callout" arrow, it will be pointed and centered
+         *            around this {@link View}.
+         * @param lookupUri A
+         *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
+         *            {@link Uri} that describes a specific contact to feature
+         *            in this dialog.
+         * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
+         *            to exclude when showing this dialog. For example, when
+         *            already viewing the contact details card, this can be used
+         *            to omit the details entry from the dialog.
+         * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
+         *             For example, passing the value
+         *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
+         *             displayed more prominently in QuickContacts.
+         */
+        public static void showQuickContact(Context context, View target, Uri lookupUri,
+                String[] excludeMimes, String prioritizedMimeType) {
+            // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
+            // values defined in ContactsContract only affect very old implementations
+            // of QuickContacts.
+            Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+                    excludeMimes);
+            intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
+            startActivityWithErrorToast(context, intent);
+        }
+
+        /**
+         * Trigger a dialog that lists the various methods of interacting with
+         * the requested {@link Contacts} entry. This may be based on available
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
+         *
+         * @param context The parent {@link Context} that may be used as the
+         *            parent for this dialog.
+         * @param target Specific {@link Rect} that this dialog should be
+         *            centered around, in screen coordinates. In particular, if
+         *            the dialog has a "callout" arrow, it will be pointed and
+         *            centered around this {@link Rect}. If you are running at a
+         *            non-native density, you need to manually adjust using
+         *            {@link DisplayMetrics#density} before calling.
+         * @param lookupUri A
+         *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
+         *            {@link Uri} that describes a specific contact to feature
+         *            in this dialog.
+         * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
+         *            to exclude when showing this dialog. For example, when
+         *            already viewing the contact details card, this can be used
+         *            to omit the details entry from the dialog.
+         * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
+         *             For example, passing the value
+         *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
+         *             displayed more prominently in QuickContacts.
+         */
+        public static void showQuickContact(Context context, Rect target, Uri lookupUri,
+                String[] excludeMimes, String prioritizedMimeType) {
+            // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
+            // values defined in ContactsContract only affect very old implementations
+            // of QuickContacts.
+            Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+                    excludeMimes);
+            intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
+            startActivityWithErrorToast(context, intent);
+        }
+
         private static void startActivityWithErrorToast(Context context, Intent intent) {
             try {
               context.startActivity(intent);
@@ -8538,102 +8584,6 @@
         public static final String EXTRA_EXCLUDE_MIMES = "exclude_mimes";
 
         /**
-         * Intents related to the Contacts app UI.
-         *
-         * @hide
-         */
-        public static final class UI {
-            /**
-             * The action for the default contacts list tab.
-             */
-            public static final String LIST_DEFAULT =
-                    "com.android.contacts.action.LIST_DEFAULT";
-
-            /**
-             * The action for the contacts list tab.
-             */
-            public static final String LIST_GROUP_ACTION =
-                    "com.android.contacts.action.LIST_GROUP";
-
-            /**
-             * When in LIST_GROUP_ACTION mode, this is the group to display.
-             */
-            public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
-
-            /**
-             * The action for the all contacts list tab.
-             */
-            public static final String LIST_ALL_CONTACTS_ACTION =
-                    "com.android.contacts.action.LIST_ALL_CONTACTS";
-
-            /**
-             * The action for the contacts with phone numbers list tab.
-             */
-            public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
-                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
-
-            /**
-             * The action for the starred contacts list tab.
-             */
-            public static final String LIST_STARRED_ACTION =
-                    "com.android.contacts.action.LIST_STARRED";
-
-            /**
-             * The action for the frequent contacts list tab.
-             */
-            public static final String LIST_FREQUENT_ACTION =
-                    "com.android.contacts.action.LIST_FREQUENT";
-
-            /**
-             * The action for the "Join Contact" picker.
-             */
-            public static final String PICK_JOIN_CONTACT_ACTION =
-                    "com.android.contacts.action.JOIN_CONTACT";
-
-            /**
-             * The action for the "strequent" contacts list tab. It first lists the starred
-             * contacts in alphabetical order and then the frequent contacts in descending
-             * order of the number of times they have been contacted.
-             */
-            public static final String LIST_STREQUENT_ACTION =
-                    "com.android.contacts.action.LIST_STREQUENT";
-
-            /**
-             * A key for to be used as an intent extra to set the activity
-             * title to a custom String value.
-             */
-            public static final String TITLE_EXTRA_KEY =
-                    "com.android.contacts.extra.TITLE_EXTRA";
-
-            /**
-             * Activity Action: Display a filtered list of contacts
-             * <p>
-             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
-             * filtering
-             * <p>
-             * Output: Nothing.
-             */
-            public static final String FILTER_CONTACTS_ACTION =
-                    "com.android.contacts.action.FILTER_CONTACTS";
-
-            /**
-             * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
-             * intents to supply the text on which to filter.
-             */
-            public static final String FILTER_TEXT_EXTRA_KEY =
-                    "com.android.contacts.extra.FILTER_TEXT";
-
-            /**
-             * Used with JOIN_CONTACT action to set the target for aggregation. This action type
-             * uses contact ids instead of contact uris for the sake of backwards compatibility.
-             * <p>
-             * Type: LONG
-             */
-            public static final String TARGET_CONTACT_ID_EXTRA_KEY
-                    = "com.android.contacts.action.CONTACT_ID";
-        }
-
-        /**
          * Convenience class that contains string constants used
          * to create contact {@link android.content.Intent Intents}.
          */
@@ -8858,10 +8808,8 @@
              * dialog to chose an account
              * <p>
              * Type: {@link Account}
-             *
-             * @hide
              */
-            public static final String ACCOUNT = "com.android.contacts.extra.ACCOUNT";
+            public static final String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
 
             /**
              * Used to specify the data set within the account in which to create the
@@ -8871,10 +8819,8 @@
              * created in the base account, with no data set.
              * <p>
              * Type: String
-             *
-             * @hide
              */
-            public static final String DATA_SET = "com.android.contacts.extra.DATA_SET";
+            public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
         }
     }
 }
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 4135e8b..6979bee 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -28,6 +28,7 @@
 import static android.provider.DocumentsContract.getTreeDocumentId;
 import static android.provider.DocumentsContract.isTreeUri;
 
+import android.annotation.CallSuper;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -355,7 +356,7 @@
     }
 
     /**
-     * Return documents that that match the given query under the requested
+     * Return documents that match the given query under the requested
      * root. The returned documents should be sorted by relevance in descending
      * order. How documents are matched against the query string is an
      * implementation detail left to each provider, but it's suggested that at
@@ -541,6 +542,7 @@
      *
      * @see DocumentsContract#buildDocumentUriUsingTree(Uri, String)
      */
+    @CallSuper
     @Override
     public Uri canonicalize(Uri uri) {
         final Context context = getContext();
@@ -616,6 +618,7 @@
      * call the superclass. If the superclass returns {@code null}, the subclass
      * may implement custom behavior.
      */
+    @CallSuper
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         if (!method.startsWith("android:")) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d773d4a..4c452aa 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -51,14 +51,20 @@
 import android.speech.tts.TextToSpeech;
 import android.text.TextUtils;
 import android.util.AndroidException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 
 import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * The Settings provider contains global system-level device preferences.
@@ -132,7 +138,6 @@
             "android.settings.AIRPLANE_MODE_SETTINGS";
 
     /**
-     * @hide
      * Activity Action: Modify Airplane mode settings using the users voice.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
@@ -154,7 +159,6 @@
      * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    @SystemApi
     public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE =
             "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
 
@@ -308,7 +312,7 @@
 
     /**
      * Activity Action: Show settings to allow configuration of
-     * cast endpoints.
+     * {@link android.media.routing.MediaRouteService media route providers}.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
@@ -991,13 +995,11 @@
     public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
 
     /**
-     * @hide
      * Activity Extra: Enable or disable Airplane Mode.
      * <p>
      * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE}
      * intent as a boolean.
      */
-    @SystemApi
     public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
 
     private static final String JID_RESOURCE_PREFIX = "android";
@@ -1196,6 +1198,11 @@
     public static final class System extends NameValueTable {
         public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
 
+        /** @hide */
+        public static interface Validator {
+            public boolean validate(String value);
+        }
+
         /**
          * The content:// style URL for this table
          */
@@ -1298,13 +1305,53 @@
             MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
         }
 
+        private static final Validator sBooleanValidator =
+                new DiscreteValueValidator(new String[] {"0", "1"});
+
+        private static final Validator sNonNegativeIntegerValidator = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    return Integer.parseInt(value) >= 0;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        };
+
+        private static final Validator sUriValidator = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    Uri.decode(value);
+                    return true;
+                } catch (IllegalArgumentException e) {
+                    return false;
+                }
+            }
+        };
+
+        private static final Validator sLenientIpAddressValidator = new Validator() {
+            private static final int MAX_IPV6_LENGTH = 45;
+
+            @Override
+            public boolean validate(String value) {
+                return value.length() <= MAX_IPV6_LENGTH;
+            }
+        };
+
         /** @hide */
-        public static void getMovedKeys(HashSet<String> outKeySet) {
+        public static void getMovedToGlobalSettings(Set<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
             outKeySet.addAll(MOVED_TO_SECURE_THEN_GLOBAL);
         }
 
         /** @hide */
+        public static void getMovedToSecureSettings(Set<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_SECURE);
+        }
+
+        /** @hide */
         public static void getNonLegacyMovedKeys(HashSet<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
         }
@@ -1727,6 +1774,59 @@
             putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
         }
 
+        private static final class DiscreteValueValidator implements Validator {
+            private final String[] mValues;
+
+            public DiscreteValueValidator(String[] values) {
+                mValues = values;
+            }
+
+            @Override
+            public boolean validate(String value) {
+                return ArrayUtils.contains(mValues, value);
+            }
+        }
+
+        private static final class InclusiveIntegerRangeValidator implements Validator {
+            private final int mMin;
+            private final int mMax;
+
+            public InclusiveIntegerRangeValidator(int min, int max) {
+                mMin = min;
+                mMax = max;
+            }
+
+            @Override
+            public boolean validate(String value) {
+                try {
+                    final int intValue = Integer.parseInt(value);
+                    return intValue >= mMin && intValue <= mMax;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        }
+
+        private static final class InclusiveFloatRangeValidator implements Validator {
+            private final float mMin;
+            private final float mMax;
+
+            public InclusiveFloatRangeValidator(float min, float max) {
+                mMin = min;
+                mMax = max;
+            }
+
+            @Override
+            public boolean validate(String value) {
+                try {
+                    final float floatValue = Float.parseFloat(value);
+                    return floatValue >= mMin && floatValue <= mMax;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        }
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
          */
@@ -1745,6 +1845,9 @@
          */
         public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
 
+        private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * END_BUTTON_BEHAVIOR value for "go home".
          * @hide
@@ -1769,6 +1872,8 @@
          */
         public static final String ADVANCED_SETTINGS = "advanced_settings";
 
+        private static final Validator ADVANCED_SETTINGS_VALIDATOR = sBooleanValidator;
+
         /**
          * ADVANCED_SETTINGS default value.
          * @hide
@@ -1868,6 +1973,8 @@
         @Deprecated
         public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
 
+        private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = sBooleanValidator;
+
         /**
          * The static IP address.
          * <p>
@@ -1878,6 +1985,8 @@
         @Deprecated
         public static final String WIFI_STATIC_IP = "wifi_static_ip";
 
+        private static final Validator WIFI_STATIC_IP_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the gateway's IP address.
          * <p>
@@ -1888,6 +1997,8 @@
         @Deprecated
         public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
 
+        private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the net mask.
          * <p>
@@ -1898,6 +2009,8 @@
         @Deprecated
         public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
 
+        private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the primary DNS's IP address.
          * <p>
@@ -1908,6 +2021,8 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
 
+        private static final Validator WIFI_STATIC_DNS1_VALIDATOR = sLenientIpAddressValidator;
+
         /**
          * If using static IP, the secondary DNS's IP address.
          * <p>
@@ -1918,6 +2033,7 @@
         @Deprecated
         public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
 
+        private static final Validator WIFI_STATIC_DNS2_VALIDATOR = sLenientIpAddressValidator;
 
         /**
          * Determines whether remote devices may discover and/or connect to
@@ -1930,6 +2046,9 @@
         public static final String BLUETOOTH_DISCOVERABILITY =
             "bluetooth_discoverability";
 
+        private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 2);
+
         /**
          * Bluetooth discoverability timeout.  If this value is nonzero, then
          * Bluetooth becomes discoverable for a certain number of seconds,
@@ -1938,6 +2057,9 @@
         public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
             "bluetooth_discoverability_timeout";
 
+        private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
+                sNonNegativeIntegerValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
          * instead
@@ -1961,7 +2083,6 @@
         public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
             "lock_pattern_tactile_feedback_enabled";
 
-
         /**
          * A formatted string of the next alarm that is set, or the empty string
          * if there is no alarm set.
@@ -1971,11 +2092,32 @@
         @Deprecated
         public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
 
+        private static final Validator NEXT_ALARM_FORMATTED_VALIDATOR = new Validator() {
+            private static final int MAX_LENGTH = 1000;
+
+            @Override
+            public boolean validate(String value) {
+                // TODO: No idea what the correct format is.
+                return value == null || value.length() < MAX_LENGTH;
+            }
+        };
+
         /**
          * Scaling factor for fonts, float.
          */
         public static final String FONT_SCALE = "font_scale";
 
+        private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    return Float.parseFloat(value) >= 0;
+                } catch (NumberFormatException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Name of an application package to be debugged.
          *
@@ -2000,6 +2142,8 @@
         @Deprecated
         public static final String DIM_SCREEN = "dim_screen";
 
+        private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;
+
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
          * to dream after a period of inactivity.  This value is also known as the
@@ -2008,16 +2152,23 @@
          */
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
+        private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = sNonNegativeIntegerValidator;
+
         /**
          * The screen backlight brightness between 0 and 255.
          */
         public static final String SCREEN_BRIGHTNESS = "screen_brightness";
 
+        private static final Validator SCREEN_BRIGHTNESS_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 255);
+
         /**
          * Control whether to enable automatic brightness mode.
          */
         public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
 
+        private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = sBooleanValidator;
+
         /**
          * Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
          * or less (<0.0 >-1.0) bright.
@@ -2025,6 +2176,9 @@
          */
         public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
 
+        private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
+                new InclusiveFloatRangeValidator(-1, 1);
+
         /**
          * SCREEN_BRIGHTNESS_MODE value for manual mode.
          */
@@ -2060,12 +2214,18 @@
          */
         public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
 
-         /**
+        private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
+                sNonNegativeIntegerValidator;
+
+        /**
           * Determines which streams are affected by mute. The
           * stream type's bit should be set to 1 if it should be muted when a mute request
           * is received.
           */
-         public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+        public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+
+        private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
+                sNonNegativeIntegerValidator;
 
         /**
          * Whether vibrate is on for different events. This is used internally,
@@ -2073,6 +2233,8 @@
          */
         public static final String VIBRATE_ON = "vibrate_on";
 
+        private static final Validator VIBRATE_ON_VALIDATOR = sBooleanValidator;
+
         /**
          * If 1, redirects the system vibrator to all currently attached input devices
          * that support vibration.  If there are no such input devices, then the system
@@ -2087,50 +2249,67 @@
          */
         public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
 
+        private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = sBooleanValidator;
+
         /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_RING = "volume_ring";
 
         /**
          * System/notifications volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_SYSTEM = "volume_system";
 
         /**
          * Voice call volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_VOICE = "volume_voice";
 
         /**
          * Music/media/gaming volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_MUSIC = "volume_music";
 
         /**
          * Alarm volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_ALARM = "volume_alarm";
 
         /**
          * Notification volume. This is used internally, changing this
          * value will not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_NOTIFICATION = "volume_notification";
 
         /**
          * Bluetooth Headset volume. This is used internally, changing this value will
          * not change the volume. See AudioManager.
+         *
+         * @removed Not used by anything since API 2.
          */
         public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
 
         /**
          * Master volume (float in the range 0.0f to 1.0f).
+         *
          * @hide
          */
         public static final String VOLUME_MASTER = "volume_master";
@@ -2142,6 +2321,8 @@
          */
         public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
 
+        private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
+
         /**
          * Microphone mute (int 1 = mute, 0 = not muted).
          *
@@ -2149,6 +2330,8 @@
          */
         public static final String MICROPHONE_MUTE = "microphone_mute";
 
+        private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the notifications should use the ring volume (value of 1) or
          * a separate notification volume (value of 0). In most cases, users
@@ -2167,6 +2350,8 @@
         public static final String NOTIFICATIONS_USE_RING_VOLUME =
             "notifications_use_ring_volume";
 
+        private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether silent mode should allow vibration feedback. This is used
          * internally in AudioService and the Sound settings activity to
@@ -2181,8 +2366,12 @@
          */
         public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
 
+        private static final Validator VIBRATE_IN_SILENT_VALIDATOR = sBooleanValidator;
+
         /**
          * The mapping of stream type (integer) to its setting.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String[] VOLUME_SETTINGS = {
             VOLUME_VOICE, VOLUME_SYSTEM, VOLUME_RING, VOLUME_MUSIC,
@@ -2193,6 +2382,8 @@
          * Appended to various volume related settings to record the previous
          * values before they the settings were affected by a silent/vibrate
          * ringer mode change.
+         *
+         * @removed  Not used by anything since API 2.
          */
         public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
 
@@ -2207,6 +2398,8 @@
          */
         public static final String RINGTONE = "ringtone";
 
+        private static final Validator RINGTONE_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default ringtone at any
          * given time.
@@ -2225,6 +2418,8 @@
          */
         public static final String NOTIFICATION_SOUND = "notification_sound";
 
+        private static final Validator NOTIFICATION_SOUND_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default notification
          * sound at any given time.
@@ -2241,6 +2436,8 @@
          */
         public static final String ALARM_ALERT = "alarm_alert";
 
+        private static final Validator ALARM_ALERT_VALIDATOR = sUriValidator;
+
         /**
          * A {@link Uri} that will point to the current default alarm alert at
          * any given time.
@@ -2256,30 +2453,52 @@
          */
         public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
 
+        private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    ComponentName.unflattenFromString(value);
+                    return true;
+                } catch (NullPointerException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_REPLACE = "auto_replace";
 
+        private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_CAPS = "auto_caps";
 
+        private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
          * feature converts two spaces to a "." and space.
          */
         public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
 
+        private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = sBooleanValidator;
+
         /**
          * Setting to showing password characters in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_SHOW_PASSWORD = "show_password";
 
+        private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = sBooleanValidator;
+
         public static final String SHOW_GTALK_SERVICE_STATUS =
                 "SHOW_GTALK_SERVICE_STATUS";
 
+        private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = sBooleanValidator;
+
         /**
          * Name of activity to use for wallpaper on the home screen.
          *
@@ -2288,6 +2507,18 @@
         @Deprecated
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
+        private static final Validator WALLPAPER_ACTIVITY_VALIDATOR = new Validator() {
+            private static final int MAX_LENGTH = 1000;
+
+            @Override
+            public boolean validate(String value) {
+                if (value != null && value.length() > MAX_LENGTH) {
+                    return false;
+                }
+                return ComponentName.unflattenFromString(value) != null;
+            }
+        };
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
          * instead
@@ -2309,6 +2540,10 @@
          */
         public static final String TIME_12_24 = "time_12_24";
 
+        /** @hide */
+        public static final Validator TIME_12_24_VALIDATOR =
+                new DiscreteValueValidator(new String[] {"12", "24"});
+
         /**
          * Date format string
          *   mm/dd/yyyy
@@ -2317,6 +2552,19 @@
          */
         public static final String DATE_FORMAT = "date_format";
 
+        /** @hide */
+        public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
+            @Override
+            public boolean validate(String value) {
+                try {
+                    new SimpleDateFormat(value);
+                    return true;
+                } catch (IllegalArgumentException e) {
+                    return false;
+                }
+            }
+        };
+
         /**
          * Whether the setup wizard has been run before (on first boot), or if
          * it still needs to be run.
@@ -2326,6 +2574,9 @@
          */
         public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
 
+        /** @hide */
+        public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = sBooleanValidator;
+
         /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
@@ -2362,6 +2613,9 @@
          */
         public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
 
+        /** @hide */
+        public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = sBooleanValidator;
+
         /**
          * Default screen rotation when no other policy applies.
          * When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
@@ -2372,6 +2626,10 @@
          */
         public static final String USER_ROTATION = "user_rotation";
 
+        /** @hide */
+        public static final Validator USER_ROTATION_VALIDATOR =
+                new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * Control whether the rotation lock toggle in the System UI should be hidden.
          * Typically this is done for accessibility purposes to make it harder for
@@ -2386,6 +2644,10 @@
         public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
                 "hide_rotation_lock_toggle_for_accessibility";
 
+        /** @hide */
+        public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
+                sBooleanValidator;
+
         /**
          * Whether the phone vibrates when it is ringing due to an incoming call. This will
          * be used by Phone and Setting apps; it shouldn't affect other apps.
@@ -2400,12 +2662,18 @@
          */
         public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
 
+        /** @hide */
+        public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the audible DTMF tones are played by the dialer when dialing. The value is
          * boolean (1 or 0).
          */
         public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
 
+        /** @hide */
+        public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
         /**
          * CDMA only settings
          * DTMF tone type played by the dialer when dialing.
@@ -2415,6 +2683,9 @@
          */
         public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
 
+        /** @hide */
+        public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the hearing aid is enabled. The value is
          * boolean (1 or 0).
@@ -2422,6 +2693,9 @@
          */
         public static final String HEARING_AID = "hearing_aid";
 
+        /** @hide */
+        public static final Validator HEARING_AID_VALIDATOR = sBooleanValidator;
+
         /**
          * CDMA only settings
          * TTY Mode
@@ -2433,18 +2707,27 @@
          */
         public static final String TTY_MODE = "tty_mode";
 
+        /** @hide */
+        public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
         /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
 
+        /** @hide */
+        public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the haptic feedback (long presses, ...) are enabled. The value is
          * boolean (1 or 0).
          */
         public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
 
+        /** @hide */
+        public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Each application that shows web suggestions should have its own
          * setting for this.
@@ -2452,6 +2735,9 @@
         @Deprecated
         public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
 
+        /** @hide */
+        public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the notification LED should repeatedly flash when a notification is
          * pending. The value is boolean (1 or 0).
@@ -2459,6 +2745,9 @@
          */
         public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
 
+        /** @hide */
+        public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator;
+
         /**
          * Show pointer location on screen?
          * 0 = no
@@ -2467,6 +2756,9 @@
          */
         public static final String POINTER_LOCATION = "pointer_location";
 
+        /** @hide */
+        public static final Validator POINTER_LOCATION_VALIDATOR = sBooleanValidator;
+
         /**
          * Show touch positions on screen?
          * 0 = no
@@ -2475,9 +2767,12 @@
          */
         public static final String SHOW_TOUCHES = "show_touches";
 
+        /** @hide */
+        public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
+
         /**
          * Log raw orientation data from
-         * {@link com.android.internal.policy.impl.WindowOrientationListener} for use with the
+         * {@link com.android.server.policy.WindowOrientationListener} for use with the
          * orientationplot.py tool.
          * 0 = no
          * 1 = yes
@@ -2486,6 +2781,9 @@
         public static final String WINDOW_ORIENTATION_LISTENER_LOG =
                 "window_orientation_listener_log";
 
+        /** @hide */
+        public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
          * instead
@@ -2508,12 +2806,18 @@
          */
         public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
 
+        /** @hide */
+        public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * Whether the lockscreen should be completely disabled.
          * @hide
          */
         public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
 
+        /** @hide */
+        public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
          * instead
@@ -2578,6 +2882,9 @@
          */
         public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
 
+        /** @hide */
+        public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = sBooleanValidator;
+
         /**
          * Call Preference String.
          * "SIP_ALWAYS" : Always use SIP with network access
@@ -2586,18 +2893,28 @@
          */
         public static final String SIP_CALL_OPTIONS = "sip_call_options";
 
+        /** @hide */
+        public static final Validator SIP_CALL_OPTIONS_VALIDATOR = new DiscreteValueValidator(
+                new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
+
         /**
          * One of the sip call options: Always use SIP with network access.
          * @hide
          */
         public static final String SIP_ALWAYS = "SIP_ALWAYS";
 
+        /** @hide */
+        public static final Validator SIP_ALWAYS_VALIDATOR = sBooleanValidator;
+
         /**
          * One of the sip call options: Only if destination is a SIP address.
          * @hide
          */
         public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
 
+        /** @hide */
+        public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = sBooleanValidator;
+
         /**
          * @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead.  Formerly used to indicate that
          * the user should be prompted each time a call is made whether it should be placed using
@@ -2608,6 +2925,9 @@
         @Deprecated
         public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
 
+        /** @hide */
+        public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = sBooleanValidator;
+
         /**
          * Pointer speed setting.
          * This is an integer value in a range between -7 and +7, so there are 15 possible values.
@@ -2618,12 +2938,19 @@
          */
         public static final String POINTER_SPEED = "pointer_speed";
 
+        /** @hide */
+        public static final Validator POINTER_SPEED_VALIDATOR =
+                new InclusiveFloatRangeValidator(-7, 7);
+
         /**
          * Whether lock-to-app will be triggered by long-press on recents.
          * @hide
          */
         public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
 
+        /** @hide */
+        public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
+
         /**
          * I am the lolrus.
          * <p>
@@ -2633,6 +2960,16 @@
          */
         public static final String EGG_MODE = "egg_mode";
 
+        /** @hide */
+        public static final Validator EGG_MODE_VALIDATOR = sBooleanValidator;
+
+        /**
+         * IMPORTANT: If you add a new public settings you also have to add it to
+         * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
+         * it to PRIVATE_SETTINGS below. Also add a validator that can validate
+         * the setting value. See an example above.
+         */
+
         /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
@@ -2660,20 +2997,6 @@
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             VIBRATE_INPUT_DEVICES,
             MODE_RINGER_STREAMS_AFFECTED,
-            VOLUME_VOICE,
-            VOLUME_SYSTEM,
-            VOLUME_RING,
-            VOLUME_MUSIC,
-            VOLUME_ALARM,
-            VOLUME_NOTIFICATION,
-            VOLUME_BLUETOOTH_SCO,
-            VOLUME_VOICE + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_SYSTEM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_RING + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_MUSIC + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
-            VOLUME_BLUETOOTH_SCO + APPEND_FOR_LAST_AUDIBLE,
             TEXT_AUTO_REPLACE,
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
@@ -2703,17 +3026,199 @@
         };
 
         /**
-         * These entries are considered common between the personal and the managed profile,
-         * since the managed profile doesn't get to change them.
+         * These are all pulbic system settings
+         *
          * @hide
          */
-        public static final String[] CLONE_TO_MANAGED_PROFILE = {
-            DATE_FORMAT,
-            HAPTIC_FEEDBACK_ENABLED,
-            SOUND_EFFECTS_ENABLED,
-            TEXT_SHOW_PASSWORD,
-            TIME_12_24
-        };
+        public static final Set<String> PUBLIC_SETTINGS = new ArraySet<>();
+        static {
+            PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR);
+            PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_IP);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1);
+            PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2);
+            PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY);
+            PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+            PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED);
+            PUBLIC_SETTINGS.add(FONT_SCALE);
+            PUBLIC_SETTINGS.add(DIM_SCREEN);
+            PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT);
+            PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
+            PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE);
+            PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED);
+            PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED);
+            PUBLIC_SETTINGS.add(VIBRATE_ON);
+            PUBLIC_SETTINGS.add(VOLUME_RING);
+            PUBLIC_SETTINGS.add(VOLUME_SYSTEM);
+            PUBLIC_SETTINGS.add(VOLUME_VOICE);
+            PUBLIC_SETTINGS.add(VOLUME_MUSIC);
+            PUBLIC_SETTINGS.add(VOLUME_ALARM);
+            PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION);
+            PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
+            PUBLIC_SETTINGS.add(RINGTONE);
+            PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
+            PUBLIC_SETTINGS.add(ALARM_ALERT);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS);
+            PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+            PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD);
+            PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS);
+            PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY);
+            PUBLIC_SETTINGS.add(TIME_12_24);
+            PUBLIC_SETTINGS.add(DATE_FORMAT);
+            PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN);
+            PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION);
+            PUBLIC_SETTINGS.add(USER_ROTATION);
+            PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING);
+            PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+            PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+            PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+        }
+
+        /**
+         * These are all hidden system settings.
+         *
+         * @hide
+         */
+        public static final Set<String> PRIVATE_SETTINGS = new ArraySet<>();
+        static {
+            PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
+            PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
+            PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
+            PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
+            PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
+            PRIVATE_SETTINGS.add(VOLUME_MASTER);
+            PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
+            PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
+            PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
+            PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
+            PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
+            PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
+            PRIVATE_SETTINGS.add(VIBRATE_WHEN_RINGING);
+            PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING);
+            PRIVATE_SETTINGS.add(HEARING_AID);
+            PRIVATE_SETTINGS.add(TTY_MODE);
+            PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE);
+            PRIVATE_SETTINGS.add(POINTER_LOCATION);
+            PRIVATE_SETTINGS.add(SHOW_TOUCHES);
+            PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG);
+            PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED);
+            PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED);
+            PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND);
+            PRIVATE_SETTINGS.add(DESK_DOCK_SOUND);
+            PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND);
+            PRIVATE_SETTINGS.add(CAR_DOCK_SOUND);
+            PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND);
+            PRIVATE_SETTINGS.add(LOCK_SOUND);
+            PRIVATE_SETTINGS.add(UNLOCK_SOUND);
+            PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS);
+            PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS);
+            PRIVATE_SETTINGS.add(SIP_ALWAYS);
+            PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY);
+            PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
+            PRIVATE_SETTINGS.add(POINTER_SPEED);
+            PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
+            PRIVATE_SETTINGS.add(EGG_MODE);
+        }
+
+        /**
+         * These are all pulbic system settings
+         *
+         * @hide
+         */
+        public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+        static {
+            VALIDATORS.put(END_BUTTON_BEHAVIOR,END_BUTTON_BEHAVIOR_VALIDATOR);
+            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
+            VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+                    BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR);
+            VALIDATORS.put(NEXT_ALARM_FORMATTED, NEXT_ALARM_FORMATTED_VALIDATOR);
+            VALIDATORS.put(FONT_SCALE, FONT_SCALE_VALIDATOR);
+            VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
+            VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
+            VALIDATORS.put(SCREEN_BRIGHTNESS, SCREEN_BRIGHTNESS_VALIDATOR);
+            VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
+            VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
+            VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
+            VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
+            VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
+            VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
+            VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
+            VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
+            VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
+            VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
+            VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
+            VALIDATORS.put(DATE_FORMAT, DATE_FORMAT_VALIDATOR);
+            VALIDATORS.put(SETUP_WIZARD_HAS_RUN, SETUP_WIZARD_HAS_RUN_VALIDATOR);
+            VALIDATORS.put(ACCELEROMETER_ROTATION, ACCELEROMETER_ROTATION_VALIDATOR);
+            VALIDATORS.put(USER_ROTATION, USER_ROTATION_VALIDATOR);
+            VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
+            VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
+            VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
+            VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
+            VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
+            VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
+            VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
+            VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
+            VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
+            VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
+            VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
+            VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
+            VALIDATORS.put(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+                    HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR);
+            VALIDATORS.put(VIBRATE_WHEN_RINGING, VIBRATE_WHEN_RINGING_VALIDATOR);
+            VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
+            VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
+            VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
+            VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
+            VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
+            VALIDATORS.put(WINDOW_ORIENTATION_LISTENER_LOG,
+                    WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR);
+            VALIDATORS.put(LOCKSCREEN_SOUNDS_ENABLED, LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR);
+            VALIDATORS.put(LOCKSCREEN_DISABLED, LOCKSCREEN_DISABLED_VALIDATOR);
+            VALIDATORS.put(SIP_RECEIVE_CALLS, SIP_RECEIVE_CALLS_VALIDATOR);
+            VALIDATORS.put(SIP_CALL_OPTIONS, SIP_CALL_OPTIONS_VALIDATOR);
+            VALIDATORS.put(SIP_ALWAYS, SIP_ALWAYS_VALIDATOR);
+            VALIDATORS.put(SIP_ADDRESS_ONLY, SIP_ADDRESS_ONLY_VALIDATOR);
+            VALIDATORS.put(SIP_ASK_ME_EACH_TIME, SIP_ASK_ME_EACH_TIME_VALIDATOR);
+            VALIDATORS.put(POINTER_SPEED, POINTER_SPEED_VALIDATOR);
+            VALIDATORS.put(LOCK_TO_APP_ENABLED, LOCK_TO_APP_ENABLED_VALIDATOR);
+            VALIDATORS.put(EGG_MODE, EGG_MODE_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_IP, WIFI_STATIC_IP_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_GATEWAY, WIFI_STATIC_GATEWAY_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
+            VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+        }
+
+        /**
+         * These entries are considered common between the personal and the managed profile,
+         * since the managed profile doesn't get to change them.
+         */
+        private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+        static {
+            CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT);
+            CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD);
+            CLONE_TO_MANAGED_PROFILE.add(TIME_12_24);
+        }
+
+        /** @hide */
+        public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+            outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+        }
 
         /**
          * When to use Wi-Fi calling
@@ -3103,7 +3608,7 @@
         }
 
         /** @hide */
-        public static void getMovedKeys(HashSet<String> outKeySet) {
+        public static void getMovedToGlobalSettings(Set<String> outKeySet) {
             outKeySet.addAll(MOVED_TO_GLOBAL);
         }
 
@@ -3657,6 +4162,7 @@
          * A flag containing settings used for biometric weak
          * @hide
          */
+        @Deprecated
         public static final String LOCK_BIOMETRIC_WEAK_FLAGS =
                 "lock_biometric_weak_flags";
 
@@ -3668,7 +4174,11 @@
 
         /**
          * Whether autolock is enabled (0 = false, 1 = true)
+         *
+         * @deprecated Use {@link android.app.KeyguardManager} to determine the state and security
+         *             level of the keyguard.
          */
+        @Deprecated
         public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
 
         /**
@@ -3707,6 +4217,7 @@
          * Ids of the user-selected appwidgets on the lockscreen (comma-delimited).
          * @hide
          */
+        @Deprecated
         public static final String LOCK_SCREEN_APPWIDGET_IDS =
             "lock_screen_appwidget_ids";
 
@@ -3720,6 +4231,7 @@
          * Id of the appwidget shown on the lock screen when appwidgets are disabled.
          * @hide
          */
+        @Deprecated
         public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID =
             "lock_screen_fallback_appwidget_id";
 
@@ -3727,6 +4239,7 @@
          * Index of the lockscreen appwidget to restore, -1 if none.
          * @hide
          */
+        @Deprecated
         public static final String LOCK_SCREEN_STICKY_APPWIDGET =
             "lock_screen_sticky_appwidget";
 
@@ -4758,6 +5271,10 @@
         public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
 
         /** @hide */
+        public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT
+                = "volume_controller_service_component";
+
+        /** @hide */
         public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
 
         /**
@@ -4892,22 +5409,27 @@
         /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
-         * @hide
          */
-        public static final String[] CLONE_TO_MANAGED_PROFILE = {
-            ACCESSIBILITY_ENABLED,
-            ALLOW_MOCK_LOCATION,
-            ALLOWED_GEOLOCATION_ORIGINS,
-            DEFAULT_INPUT_METHOD,
-            ENABLED_ACCESSIBILITY_SERVICES,
-            ENABLED_INPUT_METHODS,
-            LOCATION_MODE,
-            LOCATION_PROVIDERS_ALLOWED,
-            LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
-            SELECTED_INPUT_METHOD_SUBTYPE,
-            SELECTED_SPELL_CHECKER,
-            SELECTED_SPELL_CHECKER_SUBTYPE
-        };
+        private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+        static {
+            CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
+            CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
+            CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
+            CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+            CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
+            CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+            CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
+            CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
+            CLONE_TO_MANAGED_PROFILE.add(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
+            CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
+        }
+
+        /** @hide */
+        public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+            outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+        }
 
         /**
          * Helper method for determining if a location provider is enabled.
@@ -5101,6 +5623,7 @@
          * Whether Theater Mode is on.
          * {@hide}
          */
+        @SystemApi
         public static final String THEATER_MODE_ON = "theater_mode_on";
 
         /**
@@ -6378,14 +6901,7 @@
         public static final String CALL_AUTO_RETRY = "call_auto_retry";
 
         /**
-         * The preferred network mode   7 = Global
-         *                              6 = EvDo only
-         *                              5 = CDMA w/o EvDo
-         *                              4 = CDMA / EvDo auto
-         *                              3 = GSM / WCDMA auto
-         *                              2 = WCDMA only
-         *                              1 = GSM only
-         *                              0 = GSM / WCDMA preferred
+         * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
         public static final String PREFERRED_NETWORK_MODE =
@@ -6547,7 +7063,7 @@
         /**
          * Defines global runtime overrides to window policy.
          *
-         * See {@link com.android.internal.policy.impl.PolicyControl} for value format.
+         * See {@link com.android.server.policy.PolicyControl} for value format.
          *
          * @hide
          */
@@ -6722,6 +7238,11 @@
             MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
         }
 
+        /** @hide */
+        public static void getMovedToSecureSettings(Set<String> outKeySet) {
+            outKeySet.addAll(MOVED_TO_SECURE);
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
new file mode 100644
index 0000000..ac6bbb7
--- /dev/null
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.OperationResult;
+import android.security.KeystoreArguments;
+
+/**
+ * This must be kept manually in sync with system/security/keystore until AIDL
+ * can generate both Java and C++ bindings.
+ *
+ * @hide
+ */
+interface IKeystoreService {
+    int test();
+    byte[] get(String name);
+    int insert(String name, in byte[] item, int uid, int flags);
+    int del(String name, int uid);
+    int exist(String name, int uid);
+    String[] saw(String namePrefix, int uid);
+    int reset();
+    int password(String password);
+    int lock();
+    int unlock(String password);
+    int zero();
+    int generate(String name, int uid, int keyType, int keySize, int flags,
+        in KeystoreArguments args);
+    int import_key(String name, in byte[] data, int uid, int flags);
+    byte[] sign(String name, in byte[] data);
+    int verify(String name, in byte[] data, in byte[] signature);
+    byte[] get_pubkey(String name);
+    int del_key(String name, int uid);
+    int grant(String name, int granteeUid);
+    int ungrant(String name, int granteeUid);
+    long getmtime(String name);
+    int duplicate(String srcKey, int srcUid, String destKey, int destUid);
+    int is_hardware_backed(String string);
+    int clear_uid(long uid);
+    int reset_uid(int uid);
+    int sync_uid(int sourceUid, int targetUid);
+    int password_uid(String password, int uid);
+
+    // Keymaster 0.4 methods
+    int addRngEntropy(in byte[] data);
+    int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags,
+        out KeyCharacteristics characteristics);
+    int getKeyCharacteristics(String alias, in byte[] clientId,
+        in byte[] appId, out KeyCharacteristics characteristics);
+    int importKey(String alias, in KeymasterArguments arguments, int format,
+        in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
+    ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId);
+    OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
+        in KeymasterArguments params, out KeymasterArguments operationParams);
+    OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
+    OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature);
+    int abort(IBinder handle);
+}
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
deleted file mode 100644
index 7e9aba0..0000000
--- a/core/java/android/security/IKeystoreService.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-public interface IKeystoreService extends IInterface {
-    public static abstract class Stub extends Binder implements IKeystoreService {
-        private static class Proxy implements IKeystoreService {
-            private final IBinder mRemote;
-
-            Proxy(IBinder remote) {
-                mRemote = remote;
-            }
-
-            public IBinder asBinder() {
-                return mRemote;
-            }
-
-            public String getInterfaceDescriptor() {
-                return DESCRIPTOR;
-            }
-
-            public int test() throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public byte[] get(String name) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                byte[] _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    mRemote.transact(Stub.TRANSACTION_get, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.createByteArray();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int insert(String name, byte[] item, int uid, int flags) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeByteArray(item);
-                    _data.writeInt(uid);
-                    _data.writeInt(flags);
-                    mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int del(String name, int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_del, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int exist(String name, int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_exist, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public String[] saw(String name, int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                String[] _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_saw, _data, _reply, 0);
-                    _reply.readException();
-                    int size = _reply.readInt();
-                    _result = new String[size];
-                    for (int i = 0; i < size; i++) {
-                        _result[i] = _reply.readString();
-                    }
-                    int _ret = _reply.readInt();
-                    if (_ret != 1) {
-                        return null;
-                    }
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public int reset() throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int password(String password) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(password);
-                    mRemote.transact(Stub.TRANSACTION_password, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int lock() throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    mRemote.transact(Stub.TRANSACTION_lock, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int unlock(String password) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(password);
-                    mRemote.transact(Stub.TRANSACTION_unlock, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public int zero() throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    mRemote.transact(Stub.TRANSACTION_zero, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int generate(String name, int uid, int keyType, int keySize, int flags,
-                    byte[][] args) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(uid);
-                    _data.writeInt(keyType);
-                    _data.writeInt(keySize);
-                    _data.writeInt(flags);
-                    if (args == null) {
-                        _data.writeInt(0);
-                    } else {
-                        _data.writeInt(args.length);
-                        for (int i = 0; i < args.length; i++) {
-                            _data.writeByteArray(args[i]);
-                        }
-                    }
-                    mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int import_key(String name, byte[] data, int uid, int flags)
-                    throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeByteArray(data);
-                    _data.writeInt(uid);
-                    _data.writeInt(flags);
-                    mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public byte[] sign(String name, byte[] data) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                byte[] _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeByteArray(data);
-                    mRemote.transact(Stub.TRANSACTION_sign, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.createByteArray();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int verify(String name, byte[] data, byte[] signature) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeByteArray(data);
-                    _data.writeByteArray(signature);
-                    mRemote.transact(Stub.TRANSACTION_verify, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public byte[] get_pubkey(String name) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                byte[] _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    mRemote.transact(Stub.TRANSACTION_get_pubkey, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.createByteArray();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int del_key(String name, int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_del_key, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int grant(String name, int granteeUid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(granteeUid);
-                    mRemote.transact(Stub.TRANSACTION_grant, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int ungrant(String name, int granteeUid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    _data.writeInt(granteeUid);
-                    mRemote.transact(Stub.TRANSACTION_ungrant, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public long getmtime(String name) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                long _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(name);
-                    mRemote.transact(Stub.TRANSACTION_getmtime, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readLong();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
-                    throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(srcKey);
-                    _data.writeInt(srcUid);
-                    _data.writeString(destKey);
-                    _data.writeInt(destUid);
-                    mRemote.transact(Stub.TRANSACTION_duplicate, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public int is_hardware_backed(String keyType) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(keyType);
-                    mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            @Override
-            public int clear_uid(long uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeLong(uid);
-                    mRemote.transact(Stub.TRANSACTION_clear_uid, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int reset_uid(int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int sync_uid(int srcUid, int dstUid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(srcUid);
-                    _data.writeInt(dstUid);
-                    mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-
-            public int password_uid(String password, int uid) throws RemoteException {
-                Parcel _data = Parcel.obtain();
-                Parcel _reply = Parcel.obtain();
-                int _result;
-                try {
-                    _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeString(password);
-                    _data.writeInt(uid);
-                    mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0);
-                    _reply.readException();
-                    _result = _reply.readInt();
-                } finally {
-                    _reply.recycle();
-                    _data.recycle();
-                }
-                return _result;
-            }
-        }
-
-        private static final String DESCRIPTOR = "android.security.keystore";
-
-        static final int TRANSACTION_test = IBinder.FIRST_CALL_TRANSACTION + 0;
-        static final int TRANSACTION_get = IBinder.FIRST_CALL_TRANSACTION + 1;
-        static final int TRANSACTION_insert = IBinder.FIRST_CALL_TRANSACTION + 2;
-        static final int TRANSACTION_del = IBinder.FIRST_CALL_TRANSACTION + 3;
-        static final int TRANSACTION_exist = IBinder.FIRST_CALL_TRANSACTION + 4;
-        static final int TRANSACTION_saw = IBinder.FIRST_CALL_TRANSACTION + 5;
-        static final int TRANSACTION_reset = IBinder.FIRST_CALL_TRANSACTION + 6;
-        static final int TRANSACTION_password = IBinder.FIRST_CALL_TRANSACTION + 7;
-        static final int TRANSACTION_lock = IBinder.FIRST_CALL_TRANSACTION + 8;
-        static final int TRANSACTION_unlock = IBinder.FIRST_CALL_TRANSACTION + 9;
-        static final int TRANSACTION_zero = IBinder.FIRST_CALL_TRANSACTION + 10;
-        static final int TRANSACTION_generate = IBinder.FIRST_CALL_TRANSACTION + 11;
-        static final int TRANSACTION_import = IBinder.FIRST_CALL_TRANSACTION + 12;
-        static final int TRANSACTION_sign = IBinder.FIRST_CALL_TRANSACTION + 13;
-        static final int TRANSACTION_verify = IBinder.FIRST_CALL_TRANSACTION + 14;
-        static final int TRANSACTION_get_pubkey = IBinder.FIRST_CALL_TRANSACTION + 15;
-        static final int TRANSACTION_del_key = IBinder.FIRST_CALL_TRANSACTION + 16;
-        static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
-        static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
-        static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
-        static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
-        static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
-        static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
-        static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23;
-        static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24;
-        static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25;
-
-        /**
-         * Cast an IBinder object into an IKeystoreService interface, generating
-         * a proxy if needed.
-         */
-        public static IKeystoreService asInterface(IBinder obj) {
-            if (obj == null) {
-                return null;
-            }
-            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
-            if (iin != null && iin instanceof IKeystoreService) {
-                return (IKeystoreService) iin;
-            }
-            return new IKeystoreService.Stub.Proxy(obj);
-        }
-
-        /** Construct the stub at attach it to the interface. */
-        public Stub() {
-            attachInterface(this, DESCRIPTOR);
-        }
-
-        public IBinder asBinder() {
-            return this;
-        }
-
-        @Override
-        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-                throws RemoteException {
-            switch (code) {
-                case INTERFACE_TRANSACTION: {
-                    reply.writeString(DESCRIPTOR);
-                    return true;
-                }
-                case TRANSACTION_test: {
-                    data.enforceInterface(DESCRIPTOR);
-                    int resultCode = test();
-                    reply.writeNoException();
-                    reply.writeInt(resultCode);
-                    return true;
-                }
-            }
-            return super.onTransact(code, data, reply, flags);
-        }
-    }
-
-    public int test() throws RemoteException;
-
-    public byte[] get(String name) throws RemoteException;
-
-    public int insert(String name, byte[] item, int uid, int flags) throws RemoteException;
-
-    public int del(String name, int uid) throws RemoteException;
-
-    public int exist(String name, int uid) throws RemoteException;
-
-    public String[] saw(String name, int uid) throws RemoteException;
-
-    public int reset() throws RemoteException;
-
-    public int password(String password) throws RemoteException;
-
-    public int lock() throws RemoteException;
-
-    public int unlock(String password) throws RemoteException;
-
-    public int zero() throws RemoteException;
-
-    public int generate(String name, int uid, int keyType, int keySize, int flags, byte[][] args)
-            throws RemoteException;
-
-    public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException;
-
-    public byte[] sign(String name, byte[] data) throws RemoteException;
-
-    public int verify(String name, byte[] data, byte[] signature) throws RemoteException;
-
-    public byte[] get_pubkey(String name) throws RemoteException;
-
-    public int del_key(String name, int uid) throws RemoteException;
-
-    public int grant(String name, int granteeUid) throws RemoteException;
-
-    public int ungrant(String name, int granteeUid) throws RemoteException;
-
-    public long getmtime(String name) throws RemoteException;
-
-    public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
-            throws RemoteException;
-
-    public int is_hardware_backed(String string) throws RemoteException;
-
-    public int clear_uid(long uid) throws RemoteException;
-
-    public int reset_uid(int uid) throws RemoteException;
-
-    public int sync_uid(int sourceUid, int targetUid) throws RemoteException;
-
-    public int password_uid(String password, int uid) throws RemoteException;
-}
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
new file mode 100644
index 0000000..d636414
--- /dev/null
+++ b/core/java/android/security/KeystoreArguments.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/* @hide */
+parcelable KeystoreArguments;
diff --git a/core/java/android/security/KeystoreArguments.java b/core/java/android/security/KeystoreArguments.java
new file mode 100644
index 0000000..16054e5
--- /dev/null
+++ b/core/java/android/security/KeystoreArguments.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class for handling the additional arguments to some keystore binder calls.
+ * This must be kept in sync with the deserialization code in system/security/keystore.
+ * @hide
+ */
+public class KeystoreArguments implements Parcelable {
+    public byte[][] args;
+
+    public static final Parcelable.Creator<KeystoreArguments> CREATOR = new
+            Parcelable.Creator<KeystoreArguments>() {
+                public KeystoreArguments createFromParcel(Parcel in) {
+                    return new KeystoreArguments(in);
+                }
+                public KeystoreArguments[] newArray(int size) {
+                    return new KeystoreArguments[size];
+                }
+            };
+
+    public KeystoreArguments() {
+        args = null;
+    }
+
+    public KeystoreArguments(byte[][] args) {
+        this.args = args;
+    }
+
+    private KeystoreArguments(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        if (args == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(args.length);
+            for (byte[] arg : args) {
+                out.writeByteArray(arg);
+            }
+        }
+    }
+
+    private void readFromParcel(Parcel in) {
+        int length = in.readInt();
+        args = new byte[length][];
+        for (int i = 0; i < length; i++) {
+            args[i] = in.createByteArray();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
new file mode 100644
index 0000000..f522355
--- /dev/null
+++ b/core/java/android/security/keymaster/ExportResult.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable ExportResult;
diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java
new file mode 100644
index 0000000..bb44c03
--- /dev/null
+++ b/core/java/android/security/keymaster/ExportResult.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class for handling parceling the return values from keymaster's export operation.
+ * @hide
+ */
+public class ExportResult implements Parcelable {
+    public final int resultCode;
+    public final byte[] exportData;
+
+    public static final Parcelable.Creator<ExportResult> CREATOR = new
+            Parcelable.Creator<ExportResult>() {
+                public ExportResult createFromParcel(Parcel in) {
+                    return new ExportResult(in);
+                }
+
+                public ExportResult[] newArray(int length) {
+                    return new ExportResult[length];
+                }
+            };
+
+    protected ExportResult(Parcel in) {
+        resultCode = in.readInt();
+        exportData = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(resultCode);
+        out.writeByteArray(exportData);
+    }
+};
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
new file mode 100644
index 0000000..15014b1
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable KeyCharacteristics;
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
new file mode 100644
index 0000000..0f1d422
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class KeyCharacteristics implements Parcelable {
+    public KeymasterArguments swEnforced;
+    public KeymasterArguments hwEnforced;
+
+    public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
+            Parcelable.Creator<KeyCharacteristics>() {
+                public KeyCharacteristics createFromParcel(Parcel in) {
+                    return new KeyCharacteristics(in);
+                }
+
+                public KeyCharacteristics[] newArray(int length) {
+                    return new KeyCharacteristics[length];
+                }
+            };
+
+    public KeyCharacteristics() {}
+
+    protected KeyCharacteristics(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        swEnforced.writeToParcel(out, flags);
+        hwEnforced.writeToParcel(out, flags);
+    }
+
+    public void readFromParcel(Parcel in) {
+        swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
+        hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
+    }
+}
+
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
new file mode 100644
index 0000000..9a1c894
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelFormatException;
+
+/**
+ * Base class for the Java side of a Keymaster tagged argument.
+ * <p>
+ * Serialization code for this and subclasses must be kept in sync with system/security/keystore
+ * and with hardware/libhardware/include/hardware/keymaster_defs.h
+ * @hide
+ */
+abstract class KeymasterArgument implements Parcelable {
+    public final int tag;
+
+    public static final Parcelable.Creator<KeymasterArgument> CREATOR = new
+            Parcelable.Creator<KeymasterArgument>() {
+                public KeymasterArgument createFromParcel(Parcel in) {
+                    final int pos = in.dataPosition();
+                    final int tag = in.readInt();
+                    switch (KeymasterDefs.getTagType(tag)) {
+                        case KeymasterDefs.KM_ENUM:
+                        case KeymasterDefs.KM_ENUM_REP:
+                        case KeymasterDefs.KM_INT:
+                        case KeymasterDefs.KM_INT_REP:
+                            return new KeymasterIntArgument(tag, in);
+                        case KeymasterDefs.KM_LONG:
+                            return new KeymasterLongArgument(tag, in);
+                        case KeymasterDefs.KM_DATE:
+                            return new KeymasterDateArgument(tag, in);
+                        case KeymasterDefs.KM_BYTES:
+                        case KeymasterDefs.KM_BIGNUM:
+                            return new KeymasterBlobArgument(tag, in);
+                        case KeymasterDefs.KM_BOOL:
+                            return new KeymasterBooleanArgument(tag, in);
+                        default:
+                            throw new ParcelFormatException("Bad tag: " + tag + " at " + pos);
+                    }
+                }
+                public KeymasterArgument[] newArray(int size) {
+                    return new KeymasterArgument[size];
+                }
+            };
+
+    protected KeymasterArgument(int tag) {
+        this.tag = tag;
+    }
+
+    /**
+     * Writes the value of this argument, if any, to the provided parcel.
+     */
+    public abstract void writeValue(Parcel out);
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(tag);
+        writeValue(out);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
new file mode 100644
index 0000000..7aef5a6
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterArguments.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable KeymasterArguments;
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
new file mode 100644
index 0000000..b5fd4bd
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Utility class for the java side of user specified Keymaster arguments.
+ * <p>
+ * Serialization code for this and subclasses must be kept in sync with system/security/keystore
+ * @hide
+ */
+public class KeymasterArguments implements Parcelable {
+    List<KeymasterArgument> mArguments;
+
+    public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
+            Parcelable.Creator<KeymasterArguments>() {
+                public KeymasterArguments createFromParcel(Parcel in) {
+                    return new KeymasterArguments(in);
+                }
+                public KeymasterArguments[] newArray(int size) {
+                    return new KeymasterArguments[size];
+                }
+            };
+
+    public KeymasterArguments() {
+        mArguments = new ArrayList<KeymasterArgument>();
+    }
+
+    private KeymasterArguments(Parcel in) {
+        mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR);
+    }
+
+    public void addInt(int tag, int value) {
+        mArguments.add(new KeymasterIntArgument(tag, value));
+    }
+
+    public void addBoolean(int tag) {
+        mArguments.add(new KeymasterBooleanArgument(tag));
+    }
+
+    public void addLong(int tag, long value) {
+        mArguments.add(new KeymasterLongArgument(tag, value));
+    }
+
+    public void addBlob(int tag, byte[] value) {
+        mArguments.add(new KeymasterBlobArgument(tag, value));
+    }
+
+    public void addDate(int tag, Date value) {
+        mArguments.add(new KeymasterDateArgument(tag, value));
+    }
+
+    private KeymasterArgument getArgumentByTag(int tag) {
+        for (KeymasterArgument arg : mArguments) {
+            if (arg.tag == tag) {
+                return arg;
+            }
+        }
+        return null;
+    }
+
+    public boolean containsTag(int tag) {
+        return getArgumentByTag(tag) != null;
+    }
+
+    public int getInt(int tag, int defaultValue) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_ENUM:
+            case KeymasterDefs.KM_INT:
+                break; // Accepted types
+            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_ENUM_REP:
+                throw new IllegalArgumentException("Repeatable tags must use getInts: " + tag);
+            default:
+                throw new IllegalArgumentException("Tag is not an int type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterIntArgument) arg).value;
+    }
+
+    public long getLong(int tag, long defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG) {
+            throw new IllegalArgumentException("Tag is not a long type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterLongArgument) arg).value;
+    }
+
+    public Date getDate(int tag, Date defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
+            throw new IllegalArgumentException("Tag is not a date type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterDateArgument) arg).date;
+    }
+
+    public boolean getBoolean(int tag, boolean defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) {
+            throw new IllegalArgumentException("Tag is not a boolean type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return true;
+    }
+
+    public byte[] getBlob(int tag, byte[] defaultValue) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_BYTES:
+            case KeymasterDefs.KM_BIGNUM:
+                break; // Allowed types.
+            default:
+                throw new IllegalArgumentException("Tag is not a blob type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterBlobArgument) arg).blob;
+    }
+
+    public List<Integer> getInts(int tag) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_ENUM_REP:
+                break; // Allowed types.
+            default:
+                throw new IllegalArgumentException("Tag is not a repeating type: " + tag);
+        }
+        List<Integer> values = new ArrayList<Integer>();
+        for (KeymasterArgument arg : mArguments) {
+            if (arg.tag == tag) {
+                values.add(((KeymasterIntArgument) arg).value);
+            }
+        }
+        return values;
+    }
+
+    public int size() {
+        return mArguments.size();
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeTypedList(mArguments);
+    }
+
+    public void readFromParcel(Parcel in) {
+        in.readTypedList(mArguments, KeymasterArgument.CREATOR);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
new file mode 100644
index 0000000..9af4445
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+
+/**
+ * @hide
+ */
+class KeymasterBlobArgument extends KeymasterArgument {
+    public final byte[] blob;
+
+    public KeymasterBlobArgument(int tag, byte[] blob) {
+        super(tag);
+        this.blob = blob;
+    }
+
+    public KeymasterBlobArgument(int tag, Parcel in) {
+        super(tag);
+        blob = in.createByteArray();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeByteArray(blob);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
new file mode 100644
index 0000000..5481e8f
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+
+/**
+ * @hide
+ */
+class KeymasterBooleanArgument extends KeymasterArgument {
+
+    // Boolean arguments are always true if they exist and false if they don't.
+    public final boolean value = true;
+
+    public KeymasterBooleanArgument(int tag) {
+        super(tag);
+    }
+
+    public KeymasterBooleanArgument(int tag, Parcel in) {
+        super(tag);
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        // Do nothing, value is implicit.
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
new file mode 100644
index 0000000..310f546
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import java.util.Date;
+
+/**
+ * @hide
+ */
+class KeymasterDateArgument extends KeymasterArgument {
+    public final Date date;
+
+    public KeymasterDateArgument(int tag, Date date) {
+        super(tag);
+        this.date = date;
+    }
+
+    public KeymasterDateArgument(int tag, Parcel in) {
+        super(tag);
+        date = new Date(in.readLong());
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeLong(date.getTime());
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
new file mode 100644
index 0000000..88cad79
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/**
+ * Class tracking all the keymaster enum values needed for the binder API to keystore.
+ * This must be kept in sync with hardware/libhardware/include/hardware/keymaster_defs.h
+ * See keymaster_defs.h for detailed descriptions of each constant.
+ * @hide
+ */
+public final class KeymasterDefs {
+
+    private KeymasterDefs() {}
+
+    // Tag types.
+    public static final int KM_INVALID = 0 << 28;
+    public static final int KM_ENUM = 1 << 28;
+    public static final int KM_ENUM_REP = 2 << 28;
+    public static final int KM_INT = 3 << 28;
+    public static final int KM_INT_REP = 4 << 28;
+    public static final int KM_LONG = 5 << 28;
+    public static final int KM_DATE = 6 << 28;
+    public static final int KM_BOOL = 7 << 28;
+    public static final int KM_BIGNUM = 8 << 28;
+    public static final int KM_BYTES = 9 << 28;
+
+    // Tag values.
+    public static final int KM_TAG_INVALID = KM_INVALID | 0;
+    public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
+    public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
+    public static final int KM_TAG_KEY_SIZE = KM_INT | 3;
+    public static final int KM_TAG_BLOCK_MODE = KM_ENUM | 4;
+    public static final int KM_TAG_DIGEST = KM_ENUM | 5;
+    public static final int KM_TAG_MAC_LENGTH = KM_INT | 6;
+    public static final int KM_TAG_PADDING = KM_ENUM | 7;
+    public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 8;
+    public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 9;
+
+    public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
+    public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
+    public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
+
+    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200;
+    public static final int KM_TAG_DSA_GENERATOR = KM_BIGNUM | 201;
+    public static final int KM_TAG_DSA_P = KM_BIGNUM | 202;
+    public static final int KM_TAG_DSA_Q = KM_BIGNUM | 203;
+    public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
+    public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
+    public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
+    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_INT | 403;
+    public static final int KM_TAG_MAX_USES_PER_BOOT = KM_INT | 404;
+
+    public static final int KM_TAG_ALL_USERS = KM_BOOL | 500;
+    public static final int KM_TAG_USER_ID = KM_INT | 501;
+    public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 502;
+    public static final int KM_TAG_USER_AUTH_ID = KM_INT_REP | 503;
+    public static final int KM_TAG_AUTH_TIMEOUT = KM_INT | 504;
+
+    public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
+    public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
+
+    public static final int KM_TAG_APPLICATION_DATA = KM_BYTES | 700;
+    public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
+    public static final int KM_TAG_ORIGIN = KM_ENUM | 702;
+    public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
+    public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
+
+    public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
+    public static final int KM_TAG_NONCE = KM_BYTES | 1001;
+    public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002;
+
+    // Algorithm values.
+    public static final int KM_ALGORITHM_RSA = 1;
+    public static final int KM_ALGORITHM_DSA = 2;
+    public static final int KM_ALGORITHM_ECDSA = 3;
+    public static final int KM_ALGORITHM_ECIES = 4;
+    public static final int KM_ALGORITHM_AES = 32;
+    public static final int KM_ALGORITHM_3DES = 33;
+    public static final int KM_ALGORITHM_SKIPJACK = 34;
+    public static final int KM_ALGORITHM_MARS = 48;
+    public static final int KM_ALGORITHM_RC6 = 49;
+    public static final int KM_ALGORITHM_SERPENT = 50;
+    public static final int KM_ALGORITHM_TWOFISH = 51;
+    public static final int KM_ALGORITHM_IDEA = 52;
+    public static final int KM_ALGORITHM_RC5 = 53;
+    public static final int KM_ALGORITHM_CAST5 = 54;
+    public static final int KM_ALGORITHM_BLOWFISH = 55;
+    public static final int KM_ALGORITHM_RC4 = 64;
+    public static final int KM_ALGORITHM_CHACHA20 = 65;
+    public static final int KM_ALGORITHM_HMAC = 128;
+
+    // Block modes.
+    public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1;
+    public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED;
+    public static final int KM_MODE_CBC = 2;
+    public static final int KM_MODE_CBC_CTS = 3;
+    public static final int KM_MODE_CTR = 4;
+    public static final int KM_MODE_OFB = 5;
+    public static final int KM_MODE_CFB = 6;
+    public static final int KM_MODE_XTS = 7;
+    public static final int KM_MODE_FIRST_AUTHENTICATED = 32;
+    public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED;
+    public static final int KM_MODE_OCB = 33;
+    public static final int KM_MODE_CCM = 34;
+    public static final int KM_MODE_FIRST_MAC = 128;
+    public static final int KM_MODE_CMAC = KM_MODE_FIRST_MAC;
+    public static final int KM_MODE_POLY1305 = 129;
+
+    // Padding modes.
+    public static final int KM_PAD_NONE = 1;
+    public static final int KM_PAD_RSA_OAEP = 2;
+    public static final int KM_PAD_RSA_PSS = 3;
+    public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
+    public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
+    public static final int KM_PAD_ANSI_X923 = 32;
+    public static final int KM_PAD_ISO_10126 = 33;
+    public static final int KM_PAD_ZERO = 64;
+    public static final int KM_PAD_PKCS7 = 65;
+    public static final int KM_PAD_ISO_7816_4 = 66;
+
+    // Digest modes.
+    public static final int KM_DIGEST_NONE = 0;
+    public static final int KM_DIGEST_MD5 = 1;
+    public static final int KM_DIGEST_SHA1 = 2;
+    public static final int KM_DIGEST_SHA_2_224 = 3;
+    public static final int KM_DIGEST_SHA_2_256 = 4;
+    public static final int KM_DIGEST_SHA_2_384 = 5;
+    public static final int KM_DIGEST_SHA_2_512 = 6;
+    public static final int KM_DIGEST_SHA_3_256 = 7;
+    public static final int KM_DIGEST_SHA_3_384 = 8;
+    public static final int KM_DIGEST_SHA_3_512 = 9;
+
+    // Key origins.
+    public static final int KM_ORIGIN_HARDWARE = 0;
+    public static final int KM_ORIGIN_SOFTWARE = 1;
+    public static final int KM_ORIGIN_IMPORTED = 2;
+
+    // Key usability requirements.
+    public static final int KM_BLOB_STANDALONE = 0;
+    public static final int KM_BLOB_REQUIRES_FILE_SYSTEM = 1;
+
+    // Operation Purposes.
+    public static final int KM_PURPOSE_ENCRYPT = 0;
+    public static final int KM_PURPOSE_DECRYPT = 1;
+    public static final int KM_PURPOSE_SIGN = 2;
+    public static final int KM_PURPOSE_VERIFY = 3;
+
+    // Key formats.
+    public static final int KM_KEY_FORMAT_X509 = 0;
+    public static final int KM_KEY_FORMAT_PKCS8 = 1;
+    public static final int KM_KEY_FORMAT_PKCS12 = 2;
+    public static final int KM_KEY_FORMAT_RAW = 3;
+
+    // Error codes.
+    public static final int KM_ERROR_OK = 0;
+    public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
+    public static final int KM_ERROR_UNSUPPORTED_PURPOSE = -2;
+    public static final int KM_ERROR_INCOMPATIBLE_PURPOSE = -3;
+    public static final int KM_ERROR_UNSUPPORTED_ALGORITHM = -4;
+    public static final int KM_ERROR_INCOMPATIBLE_ALGORITHM = -5;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
+    public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
+    public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
+    public static final int KM_ERROR_UNSUPPORTED_TAG_LENGTH = -9;
+    public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
+    public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
+    public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
+    public static final int KM_ERROR_INCOMPATIBLE_DIGEST = -13;
+    public static final int KM_ERROR_INVALID_EXPIRATION_TIME = -14;
+    public static final int KM_ERROR_INVALID_USER_ID = -15;
+    public static final int KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT = -16;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_FORMAT = -17;
+    public static final int KM_ERROR_INCOMPATIBLE_KEY_FORMAT = -18;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20;
+    public static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+    public static final int KM_ERROR_KEY_EXPORT_OPTIONS_INVALID = -22;
+    public static final int KM_ERROR_DELEGATION_NOT_ALLOWED = -23;
+    public static final int KM_ERROR_KEY_NOT_YET_VALID = -24;
+    public static final int KM_ERROR_KEY_EXPIRED = -25;
+    public static final int KM_ERROR_KEY_USER_NOT_AUTHENTICATED = -26;
+    public static final int KM_ERROR_OUTPUT_PARAMETER_NULL = -27;
+    public static final int KM_ERROR_INVALID_OPERATION_HANDLE = -28;
+    public static final int KM_ERROR_INSUFFICIENT_BUFFER_SPACE = -29;
+    public static final int KM_ERROR_VERIFICATION_FAILED = -30;
+    public static final int KM_ERROR_TOO_MANY_OPERATIONS = -31;
+    public static final int KM_ERROR_UNEXPECTED_NULL_POINTER = -32;
+    public static final int KM_ERROR_INVALID_KEY_BLOB = -33;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED = -34;
+    public static final int KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED = -35;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_SIGNED = -36;
+    public static final int KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED = -37;
+    public static final int KM_ERROR_INVALID_ARGUMENT = -38;
+    public static final int KM_ERROR_UNSUPPORTED_TAG = -39;
+    public static final int KM_ERROR_INVALID_TAG = -40;
+    public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41;
+    public static final int KM_ERROR_INVALID_RESCOPING = -42;
+    public static final int KM_ERROR_INVALID_DSA_PARAMS = -43;
+    public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44;
+    public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45;
+    public static final int KM_ERROR_OPERATION_CANCELLED = -46;
+    public static final int KM_ERROR_CONCURRENT_ACCESS_CONFLICT = -47;
+    public static final int KM_ERROR_SECURE_HW_BUSY = -48;
+    public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49;
+    public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
+    public static final int KM_ERROR_UNIMPLEMENTED = -100;
+    public static final int KM_ERROR_VERSION_MISMATCH = -101;
+    public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
+
+    public static int getTagType(int tag) {
+        return tag & (0xF << 28);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
new file mode 100644
index 0000000..c3738d7
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+
+/**
+ * @hide
+ */
+class KeymasterIntArgument extends KeymasterArgument {
+    public final int value;
+
+    public KeymasterIntArgument(int tag, int value) {
+        super(tag);
+        this.value = value;
+    }
+
+    public KeymasterIntArgument(int tag, Parcel in) {
+        super(tag);
+        value = in.readInt();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeInt(value);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
new file mode 100644
index 0000000..3c565b8
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+
+/**
+ * @hide
+ */
+class KeymasterLongArgument extends KeymasterArgument {
+    public final long value;
+
+    public KeymasterLongArgument(int tag, long value) {
+        super(tag);
+        this.value = value;
+    }
+
+    public KeymasterLongArgument(int tag, Parcel in) {
+        super(tag);
+        value = in.readLong();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeLong(value);
+    }
+}
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
new file mode 100644
index 0000000..699e8d0
--- /dev/null
+++ b/core/java/android/security/keymaster/OperationResult.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable OperationResult;
diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java
new file mode 100644
index 0000000..4fc9d24
--- /dev/null
+++ b/core/java/android/security/keymaster/OperationResult.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class for handling the parceling of return values from keymaster crypto operations
+ * (begin/update/finish).
+ * @hide
+ */
+public class OperationResult implements Parcelable {
+    public final int resultCode;
+    public final IBinder token;
+    public final int inputConsumed;
+    public final byte[] output;
+
+    public static final Parcelable.Creator<OperationResult> CREATOR = new
+            Parcelable.Creator<OperationResult>() {
+                public OperationResult createFromParcel(Parcel in) {
+                    return new OperationResult(in);
+                }
+
+                public OperationResult[] newArray(int length) {
+                    return new OperationResult[length];
+                }
+            };
+
+    protected OperationResult(Parcel in) {
+        resultCode = in.readInt();
+        token = in.readStrongBinder();
+        inputConsumed = in.readInt();
+        output = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(resultCode);
+        out.writeStrongBinder(token);
+        out.writeInt(inputConsumed);
+        out.writeByteArray(output);
+    }
+}
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index 3d6ebca..0592a84 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -23,11 +23,8 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.RemoteException;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
diff --git a/core/java/android/service/chooser/ChooserTarget.aidl b/core/java/android/service/chooser/ChooserTarget.aidl
new file mode 100644
index 0000000..ca91bc8
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTarget.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+parcelable ChooserTarget;
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
new file mode 100644
index 0000000..7fd1d10
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.service.chooser;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A ChooserTarget represents a deep-link into an application as returned by a
+ * {@link android.service.chooser.ChooserTargetService}.
+ */
+public final class ChooserTarget implements Parcelable {
+    private static final String TAG = "ChooserTarget";
+
+    /**
+     * The title of this target that will be shown to the user. The title may be truncated
+     * if it is too long to display in the space provided.
+     */
+    private CharSequence mTitle;
+
+    /**
+     * The icon that will be shown to the user to represent this target.
+     * The system may resize this icon as appropriate.
+     */
+    private Bitmap mIcon;
+
+    /**
+     * The IntentSender that will be used to deliver the intent to the target.
+     * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
+     * by the real intent sent by the application.
+     */
+    private IntentSender mIntentSender;
+
+    /**
+     * The score given to this item. It can be normalized.
+     */
+    private float mScore;
+
+    /**
+     * Construct a deep link target for presentation by a chooser UI.
+     *
+     * <p>A target is composed of a title and an icon for presentation to the user.
+     * The UI presenting this target may truncate the title if it is too long to be presented
+     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+     *
+     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+     * to the other targets supplied by the same
+     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+     *
+     * <p>Before being sent, the PendingIntent supplied will be
+     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+     * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
+     * that you permit the relevant fields to be filled in using the appropriate flags such as
+     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+     * for {@link Intent#ACTION_SEND} intents.</p>
+     *
+     * <p>Take care not to place custom {@link android.os.Parcelable} types into
+     * the PendingIntent as extras, as the system will not be able to unparcel it to merge
+     * additional extras.</p>
+     *
+     * @param title title of this target that will be shown to a user
+     * @param icon icon to represent this target
+     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+     * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
+     */
+    public ChooserTarget(CharSequence title, Bitmap icon, float score,
+            PendingIntent pendingIntent) {
+        this(title, icon, score, pendingIntent.getIntentSender());
+    }
+
+    /**
+     * Construct a deep link target for presentation by a chooser UI.
+     *
+     * <p>A target is composed of a title and an icon for presentation to the user.
+     * The UI presenting this target may truncate the title if it is too long to be presented
+     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
+     *
+     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
+     * to the other targets supplied by the same
+     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
+     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).</p>
+     *
+     * <p>Before being sent, the IntentSender supplied will be
+     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
+     * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
+     * that you permit the relevant fields to be filled in using the appropriate flags such as
+     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
+     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
+     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
+     * for {@link Intent#ACTION_SEND} intents.</p>
+     *
+     * <p>Take care not to place custom {@link android.os.Parcelable} types into
+     * the IntentSender as extras, as the system will not be able to unparcel it to merge
+     * additional extras.</p>
+     *
+     * @param title title of this target that will be shown to a user
+     * @param icon icon to represent this target
+     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
+     * @param intentSender IntentSender to fill in and send if the user chooses this target
+     */
+    public ChooserTarget(CharSequence title, Bitmap icon, float score, IntentSender intentSender) {
+        mTitle = title;
+        mIcon = icon;
+        if (score > 1.f || score < 0.f) {
+            throw new IllegalArgumentException("Score " + score + " out of range; "
+                    + "must be between 0.0f and 1.0f");
+        }
+        mScore = score;
+        mIntentSender = intentSender;
+    }
+
+    ChooserTarget(Parcel in) {
+        mTitle = in.readCharSequence();
+        if (in.readInt() != 0) {
+            mIcon = Bitmap.CREATOR.createFromParcel(in);
+        } else {
+            mIcon = null;
+        }
+        mScore = in.readFloat();
+        mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+    }
+
+    /**
+     * Returns the title of this target for display to a user. The UI displaying the title
+     * may truncate this title if it is too long to be displayed in full.
+     *
+     * @return the title of this target, intended to be shown to a user
+     */
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Returns the icon representing this target for display to a user. The UI displaying the icon
+     * may crop, resize or overlay this icon.
+     *
+     * @return the icon representing this target, intended to be shown to a user
+     */
+    public Bitmap getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns the ranking score supplied by the creator of this ChooserTarget.
+     * Values are between 0.0f and 1.0f. The UI displaying the target may
+     * take this score into account when sorting and merging targets from multiple sources.
+     *
+     * @return the ranking score for this target between 0.0f and 1.0f, inclusive
+     */
+    public float getScore() {
+        return mScore;
+    }
+
+    /**
+     * Returns the raw IntentSender supplied by the ChooserTarget's creator.
+     *
+     * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+     *
+     * @return the IntentSender supplied by the ChooserTarget's creator
+     */
+    public IntentSender getIntentSender() {
+        return mIntentSender;
+    }
+
+    /**
+     * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
+     *
+     * @param context the sending Context; generally the Activity presenting the chooser UI
+     * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
+     * @return true if sending the Intent was successful
+     */
+    public boolean sendIntent(Context context, Intent fillInIntent) {
+        if (fillInIntent != null) {
+            fillInIntent.migrateExtraStreamToClipData();
+            fillInIntent.prepareToLeaveProcess();
+        }
+        try {
+            mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+            return true;
+        } catch (IntentSender.SendIntentException e) {
+            Log.e(TAG, "sendIntent " + this + " failed", e);
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "ChooserTarget{" + mIntentSender.getCreatorPackage() + "'" + mTitle
+                + "', " + mScore + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mTitle);
+        if (mIcon != null) {
+            dest.writeInt(1);
+            mIcon.writeToParcel(dest, 0);
+        } else {
+            dest.writeInt(0);
+        }
+        dest.writeFloat(mScore);
+        IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
+    }
+
+    public static final Creator<ChooserTarget> CREATOR
+            = new Creator<ChooserTarget>() {
+        @Override
+        public ChooserTarget createFromParcel(Parcel source) {
+            return new ChooserTarget(source);
+        }
+
+        @Override
+        public ChooserTarget[] newArray(int size) {
+            return new ChooserTarget[size];
+        }
+    };
+}
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
new file mode 100644
index 0000000..9188806
--- /dev/null
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.service.chooser;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A service that receives calls from the system when the user is asked to choose
+ * a target for an intent explicitly by another app. The calling app must have invoked
+ * {@link android.content.Intent#ACTION_CHOOSER ACTION_CHOOSER} as handled by the system;
+ * applications do not have the ability to query a ChooserTargetService directly.
+ *
+ * <p>Which ChooserTargetServices are queried depends on a system-level policy decision
+ * made at the moment the chooser is invoked, including but not limited to user time
+ * spent with the app package or associated components in the foreground, recency of usage
+ * or frequency of usage. These will generally correlate with the order that app targets
+ * are shown in the list of intent handlers shown in the system chooser or resolver.</p>
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CHOOSER_TARGET_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ *     &lt;service android:name=".ChooserTargetService"
+ *             android:label="&#64;string/service_name"
+ *             android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
+ *         &lt;intent-filter>
+ *             &lt;action android:name="android.service.chooser.ChooserTargetService" />
+ *         &lt;/intent-filter>
+ *     &lt;/service>
+ * </pre>
+ *
+ * <p>For the system to query your service, you must add a &lt;meta-data> element to the
+ * Activity in your manifest that can handle Intents that you would also like to provide
+ * optional deep links for. For example, a chat app might offer deep links to recent active
+ * conversations instead of invoking a generic picker after the app itself is chosen as a target.
+ * </p>
+ *
+ * <p>The meta-data element should have the name
+ * <code>android.service.chooser.chooser_target_service</code> and a value corresponding to
+ * the component name of your service. Example:</p>
+ * <pre>
+ *     &lt;activity android:name=".MyShareActivity"
+ *             android:label="&#64;string/share_activity_label">
+ *         &lt;intent-filter>
+ *             &lt;action android:name="android.intent.action.SEND" />
+ *         &lt;/intent-filter>
+ *         &lt;meta-data android:name="android.service.chooser.chooser_target_service"
+ *                 android:value=".ChooserTargetService" />
+ *     &lt;/activity>
+ * </pre>
+ */
+public abstract class ChooserTargetService extends Service {
+    // TAG = "ChooserTargetService[MySubclass]";
+    private final String TAG = ChooserTargetService.class.getSimpleName()
+            + '[' + getClass().getSimpleName() + ']';
+
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+
+    private IChooserTargetServiceWrapper mWrapper = null;
+
+    /**
+     * Called by the system to retrieve a set of deep-link {@link ChooserTarget targets} that
+     * can handle an intent.
+     *
+     * <p>The returned list should be sorted such that the most relevant targets appear first.
+     * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared
+     * to have the relevant data fields filled in by the sender. See
+     * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent) ChooserTarget}.</p>
+     *
+     * <p><em>Important:</em> Calls to this method from other applications will occur on
+     * a binder thread, not on your app's main thread. Make sure that access to relevant data
+     * within your app is thread-safe.</p>
+     *
+     * @param targetActivityName the ComponentName of the matched activity that referred the system
+     *                           to this ChooserTargetService
+     * @param matchedFilter the specific IntentFilter on the component that was matched
+     * @return a list of deep-link targets to fulfill the intent match, sorted by relevance
+     */
+    public abstract List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName,
+            IntentFilter matchedFilter);
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            return null;
+        }
+
+        if (mWrapper == null) {
+            mWrapper = new IChooserTargetServiceWrapper();
+        }
+        return mWrapper;
+    }
+
+    private class IChooserTargetServiceWrapper extends IChooserTargetService.Stub {
+        @Override
+        public void getChooserTargets(ComponentName targetComponentName,
+                IntentFilter matchedFilter, IChooserTargetResult result) throws RemoteException {
+            List<ChooserTarget> targets = null;
+            try {
+                targets = onGetChooserTargets(targetComponentName, matchedFilter);
+            } finally {
+                result.sendResult(targets);
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/chooser/IChooserTargetResult.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl
new file mode 100644
index 0000000..dbd7cbd
--- /dev/null
+++ b/core/java/android/service/chooser/IChooserTargetResult.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+import android.service.chooser.ChooserTarget;
+
+/**
+ * @hide
+ */
+interface IChooserTargetResult
+{
+    void sendResult(in List<ChooserTarget> targets);
+}
diff --git a/core/java/android/service/chooser/IChooserTargetService.aidl b/core/java/android/service/chooser/IChooserTargetService.aidl
new file mode 100644
index 0000000..6cfa9a2
--- /dev/null
+++ b/core/java/android/service/chooser/IChooserTargetService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.chooser;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.service.chooser.IChooserTargetResult;
+
+/**
+ * @hide
+ */
+oneway interface IChooserTargetService
+{
+    void getChooserTargets(in ComponentName targetComponentName,
+            in IntentFilter matchedFilter, IChooserTargetResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 38b043971..822bfcc 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,6 +18,9 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.AlarmManager;
@@ -37,6 +40,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -46,7 +50,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.util.MathUtils;
 
-import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.DumpUtils.Dump;
 
@@ -341,6 +344,13 @@
 
     /** {@inheritDoc} */
     @Override
+    public ActionMode onWindowStartingActionMode(
+            android.view.ActionMode.Callback callback, int type) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public void onActionModeStarted(ActionMode mode) {
     }
 
@@ -382,7 +392,7 @@
      * @see #setContentView(android.view.View)
      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
      */
-    public void setContentView(int layoutResID) {
+    public void setContentView(@LayoutRes int layoutResID) {
         getWindow().setContentView(layoutResID);
     }
 
@@ -442,7 +452,8 @@
      *
      * @return The view if found or null otherwise.
      */
-    public View findViewById(int id) {
+    @Nullable
+    public View findViewById(@IdRes int id) {
         return getWindow().findViewById(id);
     }
 
@@ -945,7 +956,7 @@
             throw new IllegalStateException("Only doze dreams can be windowless");
         }
         if (!mWindowless) {
-            mWindow = PolicyManager.makeNewWindow(this);
+            mWindow = new PhoneWindow(this);
             mWindow.setCallback(this);
             mWindow.requestFeature(Window.FEATURE_NO_TITLE);
             mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
@@ -1037,10 +1048,10 @@
     protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
         DumpUtils.dumpAsync(mHandler, new Dump() {
             @Override
-            public void dump(PrintWriter pw) {
+            public void dump(PrintWriter pw, String prefix) {
                 dumpOnHandler(fd, pw, args);
             }
-        }, pw, 1000);
+        }, pw, "", 1000);
     }
 
     /** @hide */
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 178cc8b..6375668 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -17,11 +17,8 @@
 package android.service.fingerprint;
 
 import android.app.ActivityManagerNative;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -31,6 +28,9 @@
 import android.util.Log;
 import android.util.Slog;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A class that coordinates access to the fingerprint hardware.
  * @hide
@@ -97,6 +97,15 @@
         }
     };
 
+    public static final class FingerprintItem {
+        public CharSequence name;
+        public int id;
+        FingerprintItem(CharSequence name, int id) {
+            this.name = name;
+            this.id = id;
+        }
+    }
+
     /**
      * @hide
      */
@@ -248,4 +257,57 @@
     private void sendError(int msg, int arg1, int arg2) {
         mHandler.obtainMessage(msg, arg1, arg2);
     }
+
+    /**
+     * @return list of current fingerprint items
+     * @hide
+     */
+    public List<FingerprintItem> getEnrolledFingerprints() {
+        int[] ids = FingerprintUtils.getFingerprintIdsForUser(mContext.getContentResolver(),
+                getCurrentUserId());
+        List<FingerprintItem> result = new ArrayList<FingerprintItem>();
+        for (int i = 0; i < ids.length; i++) {
+            // TODO: persist names in Settings
+            FingerprintItem item = new FingerprintItem("Finger" + ids[i], ids[i]);
+            result.add(item);
+        }
+        return result;
+    }
+
+    /**
+     * Determine if fingerprint hardware is present and functional.
+     * @return true if hardware is present and functional, false otherwise.
+     * @hide
+     */
+    public boolean isHardwareDetected() {
+        if (mService != null) {
+            try {
+                return mService.isHardwareDetected();
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+            }
+        } else {
+            Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+        }
+        return false;
+    }
+
+    /**
+     * Renames the given fingerprint template
+     * @param fpId the fingerprint id
+     * @param newName the new name
+     * @hide
+     */
+    public void rename(int fpId, String newName) {
+        // Renames the given fpId
+        if (mService != null) {
+            try {
+                mService.rename(fpId, newName);
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in rename(): ", e);
+            }
+        } else {
+            Log.w(TAG, "rename(): Service not connected!");
+        }
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index a4caf8e..cc17b99 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -21,7 +21,11 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Utility class for dealing with fingerprints and fingerprint settings.
@@ -32,34 +36,50 @@
     private static final boolean DEBUG = true;
     private static final String TAG = "FingerprintUtils";
 
+    private static int[] toIntArray(List<Integer> list) {
+        if (list == null) {
+            return null;
+        }
+        int[] arr = new int[list.size()];
+        int i = 0;
+        for (int elem : list) {
+            arr[i] = elem;
+            i++;
+        }
+        return arr;
+    }
+
     public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
         String fingerIdsRaw = Settings.Secure.getStringForUser(res,
                 Settings.Secure.USER_FINGERPRINT_IDS, userId);
-
-        int result[] = {};
+        ArrayList<Integer> tmp = new ArrayList<Integer>();
         if (!TextUtils.isEmpty(fingerIdsRaw)) {
             String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
-            result = new int[fingerStringIds.length];
-            for (int i = 0; i < result.length; i++) {
+            int length = fingerStringIds.length;
+            for (int i = 0; i < length; i++) {
                 try {
-                    result[i] = Integer.decode(fingerStringIds[i]);
+                    tmp.add(Integer.decode(fingerStringIds[i]));
                 } catch (NumberFormatException e) {
-                    if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+                    if (DEBUG) Log.w(TAG, "Error parsing finger id: '" + fingerStringIds[i] + "'");
                 }
             }
         }
-        return result;
+        return toIntArray(tmp);
     }
 
     public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+        // FingerId 0 has special meaning.
+        if (fingerId == 0) {
+            Log.w(TAG, "Tried to add fingerId 0");
+            return;
+        }
+
         int[] fingerIds = getFingerprintIdsForUser(res, userId);
 
-        // FingerId 0 has special meaning.
-        if (fingerId == 0) return;
-
         // Don't allow dups
-        for (int i = 0; i < fingerIds.length; i++) {
-            if (fingerIds[i] == fingerId) return;
+        if (ArrayUtils.contains(fingerIds, fingerId)) {
+            Log.w(TAG, "finger already added " + fingerId);
+            return;
         }
         int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
         newList[fingerIds.length] = fingerId;
@@ -72,19 +92,13 @@
         // FingerId 0 has special meaning. The HAL layer is supposed to remove each finger one
         // at a time and invoke notify() for each fingerId.  If we get called with 0 here, it means
         // something bad has happened.
-        if (fingerId == 0) throw new IllegalStateException("Bad fingerId");
+        if (fingerId == 0) throw new IllegalArgumentException("fingerId can't be 0");
 
-        int[] fingerIds = getFingerprintIdsForUser(res, userId);
-        int[] resultIds = Arrays.copyOf(fingerIds, fingerIds.length);
-        int resultCount = 0;
-        for (int i = 0; i < fingerIds.length; i++) {
-            if (fingerId != fingerIds[i]) {
-                resultIds[resultCount++] = fingerIds[i];
-            }
-        }
-        if (resultCount > 0) {
+        final int[] fingerIds = getFingerprintIdsForUser(res, userId);
+        if (ArrayUtils.contains(fingerIds, fingerId)) {
+            final int[] result = ArrayUtils.removeInt(fingerIds, fingerId);
             Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
-                    Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
+                    Arrays.toString(result), userId);
             return true;
         }
         return false;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index 43d5e9a..9b4750b 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -22,10 +22,10 @@
  * Communication channel from client to the fingerprint service.
  * @hide
  */
-oneway interface IFingerprintService {
+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);
 
@@ -38,4 +38,10 @@
 
     // Stops listening for fingerprints
     void stopListening(IBinder token, int userId);
+
+    // Determine if HAL is loaded and ready
+    boolean isHardwareDetected();
+
+    // Rename the given fingerprint id
+    void rename(int fpId, String name);
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 3d39b18..0860153 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,14 @@
      */
     public static final int INTERRUPTION_FILTER_NONE = 3;
 
+    /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
+     * the value is unavailable for any reason.  For example, before the notification listener
+     * is connected.
+     *
+     * {@see #onListenerConnected()}
+     */
+    public static final int INTERRUPTION_FILTER_UNKNOWN = 0;
+
     /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
      * should disable notification sound, vibrating and other visual or aural effects.
      * This does not change the interruption filter, only the effects. **/
@@ -473,15 +481,16 @@
      * <p>
      * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
      *
-     * @return One of the INTERRUPTION_FILTER_ constants, or 0 on errors.
+     * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
+     * unavailable.
      */
     public final int getCurrentInterruptionFilter() {
-        if (!isBound()) return 0;
+        if (!isBound()) return INTERRUPTION_FILTER_UNKNOWN;
         try {
             return getNotificationInterface().getInterruptionFilterFromListener(mWrapper);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
-            return 0;
+            return INTERRUPTION_FILTER_UNKNOWN;
         }
     }
 
diff --git a/core/java/android/service/restrictions/RestrictionsReceiver.java b/core/java/android/service/restrictions/RestrictionsReceiver.java
index 7c6e1f6..b830cb1 100644
--- a/core/java/android/service/restrictions/RestrictionsReceiver.java
+++ b/core/java/android/service/restrictions/RestrictionsReceiver.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.RestrictionsManager;
-import android.os.IBinder;
 import android.os.PersistableBundle;
 
 /**
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 62fa978..a3178e2 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -25,13 +25,10 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
 
@@ -125,12 +122,14 @@
                 case MSG_CONFIGURE:
                     ConfigurationData data = (ConfigurationData) msg.obj;
                     boolean result = onConfigure(data.options);
-                    try {
-                        synchronized (mLock) {
-                            mCallback.onConfigureCompleted(result, data.token);
+                    if (data.token != null) {
+                        try {
+                            synchronized (mLock) {
+                                mCallback.onConfigureCompleted(result, data.token);
+                            }
+                        } catch (RemoteException e) {
+                            onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                         }
-                    } catch (RemoteException e) {
-                        onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
                     }
                     break;
                 case MSG_TRUST_TIMEOUT:
@@ -206,7 +205,7 @@
      * PersistableBundle)}.
      * <p>Agents that support configuration options should overload this method and return 'true'.
      *
-     * @param options bundle containing all options or null if none.
+     * @param options The aggregated list of options or an empty list if no restrictions apply.
      * @return true if the {@link TrustAgentService} supports configuration options.
      */
     public boolean onConfigure(List<PersistableBundle> options) {
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 9f9c312..797457a 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -17,11 +17,15 @@
 package android.service.voice;
 
 import android.content.Intent;
+import android.os.Bundle;
 
 /**
  * @hide
  */
 oneway interface IVoiceInteractionSession {
+    void show(in Bundle sessionArgs, int flags);
+    void hide();
+    void handleAssist(in Bundle assistData);
     void taskStarted(in Intent intent, int taskId);
     void taskFinished(in Intent intent, int taskId);
     void closeSystemDialogs();
diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
index 2519442..7f8158f 100644
--- a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl
@@ -24,5 +24,5 @@
  * @hide
  */
 oneway interface IVoiceInteractionSessionService {
-    void newSession(IBinder token, in Bundle args);
+    void newSession(IBinder token, in Bundle args, int startFlags);
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 0cde4f2..0c01b25 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -40,15 +40,16 @@
 
 /**
  * Top-level service of the current global voice interactor, which is providing
- * support for hotwording etc.
+ * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
  * The current VoiceInteractionService that has been selected by the user is kept
  * always running by the system, to allow it to do things like listen for hotwords
- * in the background.
+ * in the background to instigate voice interactions.
  *
  * <p>Because this service is always running, it should be kept as lightweight as
  * possible.  Heavy-weight operations (including showing UI) should be implemented
- * in the associated {@link android.service.voice.VoiceInteractionSessionService}
- * that only runs while the operation is active.
+ * in the associated {@link android.service.voice.VoiceInteractionSessionService} when
+ * an actual voice interaction is taking place, and that service should run in a
+ * separate process from this one.
  */
 public class VoiceInteractionService extends Service {
     /**
@@ -69,6 +70,12 @@
      */
     public static final String SERVICE_META_DATA = "android.voice_interaction";
 
+    /**
+     * Flag for use with {@link #showSession: request that the session be started with
+     * assist data from the currently focused activity.
+     */
+    public static final int START_WITH_ASSIST = 1<<0;
+
     IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
         @Override public void ready() {
             mHandler.sendEmptyMessage(MSG_READY);
@@ -132,19 +139,29 @@
     }
 
     /**
-     * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}.
+     * Request that the associated {@link android.service.voice.VoiceInteractionSession} be
+     * shown to the user, starting it if necessary.
      * @param args Arbitrary arguments that will be propagated to the session.
      */
-    public void startSession(Bundle args) {
+    public void showSession(Bundle args, int flags) {
         if (mSystemService == null) {
             throw new IllegalStateException("Not available until onReady() is called");
         }
         try {
-            mSystemService.startSession(mInterface, args);
+            mSystemService.showSession(mInterface, args, flags);
         } catch (RemoteException e) {
         }
     }
 
+    /** @hide */
+    public void startSession(Bundle args, int flags) {
+        showSession(args, flags);
+    }
+    /** @hide */
+    public void startSession(Bundle args) {
+        startSession(args, 0);
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -162,8 +179,8 @@
     /**
      * Called during service initialization to tell you when the system is ready
      * to receive interaction from it. You should generally do initialization here
-     * rather than in {@link #onCreate()}. Methods such as {@link #startSession(Bundle)} and
-     * {@link #createAlwaysOnHotwordDetector(String, Locale, android.service.voice.AlwaysOnHotwordDetector.Callback)}
+     * rather than in {@link #onCreate}. Methods such as {@link #showSession} and
+     * {@link #createAlwaysOnHotwordDetector}
      * will not be operational until this point.
      */
     public void onReady() {
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
index e6e9413..ebc7507 100644
--- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -99,6 +99,10 @@
                 mParseError = "No sessionService specified";
                 return;
             }
+            if (mRecognitionService == null) {
+                mParseError = "No recognitionService specified";
+                return;
+            }
             /* Not yet time
             if (mRecognitionService == null) {
                 mParseError = "No recogitionService specified";
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 749f813..4cf0e4c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,7 +16,6 @@
 
 package android.service.voice;
 
-import android.annotation.SystemApi;
 import android.app.Dialog;
 import android.app.Instrumentation;
 import android.content.Context;
@@ -51,10 +50,16 @@
 import java.lang.ref.WeakReference;
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 /**
- * An active interaction session, started by a {@link VoiceInteractionService}.
+ * An active voice interaction session, providing a facility for the implementation
+ * to interact with the user in the voice interaction layer.  The user interface is
+ * initially shown by default, and can be created be overriding {@link #onCreateContentView()}
+ * in which the UI can be built.
+ *
+ * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
+ * when done.  It can also initiate voice interactions with applications by calling
+ * {@link #startVoiceActivity}</p>.
  */
 public abstract class VoiceInteractionSession implements KeyEvent.Callback {
     static final String TAG = "VoiceInteractionSession";
@@ -84,7 +89,6 @@
     final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
 
     final Insets mTmpInsets = new Insets();
-    final int[] mTmpLocation = new int[2];
 
     final WeakReference<VoiceInteractionSession> mWeakRef
             = new WeakReference<VoiceInteractionSession>(this);
@@ -146,6 +150,23 @@
 
     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
         @Override
+        public void show(Bundle sessionArgs, int flags) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_SHOW,
+                    flags, sessionArgs));
+        }
+
+        @Override
+        public void hide() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
+        }
+
+        @Override
+        public void handleAssist(Bundle assistBundle) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
+                    assistBundle));
+        }
+
+        @Override
         public void taskStarted(Intent intent, int taskId) {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
                     taskId, intent));
@@ -168,10 +189,6 @@
         }
     };
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public static class Request {
         final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
             @Override
@@ -255,10 +272,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public static class Caller {
         final String packageName;
         final int uid;
@@ -280,6 +293,9 @@
     static final int MSG_TASK_FINISHED = 101;
     static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
     static final int MSG_DESTROY = 103;
+    static final int MSG_HANDLE_ASSIST = 104;
+    static final int MSG_SHOW = 105;
+    static final int MSG_HIDE = 106;
 
     class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
         @Override
@@ -320,9 +336,8 @@
                     args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
                     break;
                 case MSG_CANCEL:
-                    args = (SomeArgs)msg.obj;
-                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
-                    onCancel((Request)args.arg1);
+                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
+                    onCancel((Request)msg.obj);
                     break;
                 case MSG_TASK_STARTED:
                     if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
@@ -342,6 +357,19 @@
                     if (DEBUG) Log.d(TAG, "doDestroy");
                     doDestroy();
                     break;
+                case MSG_HANDLE_ASSIST:
+                    if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj);
+                    onHandleAssist((Bundle) msg.obj);
+                    break;
+                case MSG_SHOW:
+                    if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
+                            + " flags=" + msg.arg1);
+                    doShow((Bundle) msg.obj, msg.arg1);
+                    break;
+                case MSG_HIDE:
+                    if (DEBUG) Log.d(TAG, "doHide");
+                    doHide();
+                    break;
             }
         }
 
@@ -354,10 +382,8 @@
     final MyCallbacks mCallbacks = new MyCallbacks();
 
     /**
-     * @hide
      * Information about where interesting parts of the input method UI appear.
      */
-    @SystemApi
     public static final class Insets {
         /**
          * This is the part of the UI that is the main content.  It is
@@ -444,10 +470,50 @@
         }
     }
 
-    void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
+    void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args,
+            int startFlags) {
         mSystemService = service;
         mToken = token;
-        onCreate(args);
+        onCreate(args, startFlags);
+    }
+
+    void doShow(Bundle args, int flags) {
+        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+                + " mWindowVisible=" + mWindowVisible);
+
+        if (mInShowWindow) {
+            Log.w(TAG, "Re-entrance in to showWindow");
+            return;
+        }
+
+        try {
+            mInShowWindow = true;
+            if (!mWindowVisible) {
+                if (!mWindowAdded) {
+                    mWindowAdded = true;
+                    View v = onCreateContentView();
+                    if (v != null) {
+                        setContentView(v);
+                    }
+                }
+            }
+            onShow(args, flags);
+            if (!mWindowVisible) {
+                mWindowVisible = true;
+                mWindow.show();
+            }
+        } finally {
+            mWindowWasVisible = true;
+            mInShowWindow = false;
+        }
+    }
+
+    void doHide() {
+        if (mWindowVisible) {
+            mWindow.hide();
+            mWindowVisible = false;
+            onHide();
+        }
     }
 
     void doDestroy() {
@@ -477,57 +543,34 @@
         mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
-    public void showWindow() {
-        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
-                + " mWindowVisible=" + mWindowVisible);
-
-        if (mInShowWindow) {
-            Log.w(TAG, "Re-entrance in to showWindow");
-            return;
-        }
-
+    public void show() {
         try {
-            mInShowWindow = true;
-            if (!mWindowVisible) {
-                mWindowVisible = true;
-                if (!mWindowAdded) {
-                    mWindowAdded = true;
-                    View v = onCreateContentView();
-                    if (v != null) {
-                        setContentView(v);
-                    }
-                }
-                mWindow.show();
-            }
-        } finally {
-            mWindowWasVisible = true;
-            mInShowWindow = false;
+            mSystemService.showSessionFromSession(mToken, null, 0);
+        } catch (RemoteException e) {
         }
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
+    public void hide() {
+        try {
+            mSystemService.hideSessionFromSession(mToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** TODO: remove */
+    public void showWindow() {
+    }
+
+    /** TODO: remove */
     public void hideWindow() {
-        if (mWindowVisible) {
-            mWindow.hide();
-            mWindowVisible = false;
-        }
     }
 
     /**
-     * @hide
      * You can call this to customize the theme used by your IME's window.
      * This must be set before {@link #onCreate}, so you
      * will typically call it in your constructor with the resource ID
      * of your custom theme.
      */
-    @SystemApi
     public void setTheme(int theme) {
         if (mWindow != null) {
             throw new IllegalStateException("Must be called before onCreate()");
@@ -536,7 +579,6 @@
     }
 
     /**
-     * @hide
      * Ask that a new activity be started for voice interaction.  This will create a
      * new dedicated task in the activity manager for this voice interaction session;
      * this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
@@ -557,7 +599,6 @@
      * always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
      * this is part of a voice interaction.
      */
-    @SystemApi
     public void startVoiceActivity(Intent intent) {
         if (mToken == null) {
             throw new IllegalStateException("Can't call before onCreate()");
@@ -573,19 +614,15 @@
     }
 
     /**
-     * @hide
      * Convenience for inflating views.
      */
-    @SystemApi
     public LayoutInflater getLayoutInflater() {
         return mInflater;
     }
 
     /**
-     * @hide
      * Retrieve the window being used to show the session's UI.
      */
-    @SystemApi
     public Dialog getWindow() {
         return mWindow;
     }
@@ -604,12 +641,7 @@
         }
     }
 
-    /**
-     * Initiatize a new session.
-     *
-     * @param args The arguments that were supplied to
-     * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
-     */
+    /** @hide */
     public void onCreate(Bundle args) {
         mTheme = mTheme != 0 ? mTheme
                 : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
@@ -617,24 +649,52 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
                 mCallbacks, this, mDispatcherState,
-                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.TOP, true);
+                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
         mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
         initViews();
-        mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+        mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
         mWindow.setToken(mToken);
     }
 
     /**
+     * Initiatize a new session.  The given args and showFlags are the initial values
+     * passed to {@link VoiceInteractionService#showSession VoiceInteractionService.showSession},
+     * if possible.  Normally you should handle these in {@link #onShow}.
+     */
+    public void onCreate(Bundle args, int showFlags) {
+        onCreate(args);
+    }
+
+    /**
+     * Called when the session UI is going to be shown.  This is called after
+     * {@link #onCreateContentView} (if the session's content UI needed to be created) and
+     * immediately prior to the window being shown.  This may be called while the window
+     * is already shown, if a show request has come in while it is shown, to allow you to
+     * update the UI to match the new show arguments.
+     *
+     * @param args The arguments that were supplied to
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+     * @param showFlags The show flags originally provided to
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+     */
+    public void onShow(Bundle args, int showFlags) {
+    }
+
+    /**
+     * Called immediately after stopping to show the session UI.
+     */
+    public void onHide() {
+    }
+
+    /**
      * Last callback to the session as it is being finished.
      */
     public void onDestroy() {
     }
 
     /**
-     * @hide
      * Hook in which to create the session's UI.
      */
-    @SystemApi
     public View onCreateContentView() {
         return null;
     }
@@ -643,48 +703,31 @@
         mContentFrame.removeAllViews();
         mContentFrame.addView(view, new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT));
+                ViewGroup.LayoutParams.MATCH_PARENT));
 
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
+    public void onHandleAssist(Bundle assistBundle) {
+    }
+
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         return false;
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public boolean onKeyLongPress(int keyCode, KeyEvent event) {
         return false;
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         return false;
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
         return false;
     }
 
-    /**
-     * @hide
-     */
-    @SystemApi
     public void onBackPressed() {
-        finish();
+        hide();
     }
 
     /**
@@ -693,33 +736,29 @@
      * calls {@link #finish}.
      */
     public void onCloseSystemDialogs() {
-        finish();
+        hide();
     }
 
     /**
-     * @hide
      * Compute the interesting insets into your UI.  The default implementation
-     * uses the entire window frame as the insets.  The default touchable
-     * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
+     * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height
+     * of the window, meaning it should not adjust content underneath.  The default touchable
+     * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}, meaning it consumes all touch
+     * events within its window frame.
      *
      * @param outInsets Fill in with the current UI insets.
      */
-    @SystemApi
     public void onComputeInsets(Insets outInsets) {
-        int[] loc = mTmpLocation;
-        View decor = getWindow().getWindow().getDecorView();
-        decor.getLocationInWindow(loc);
-        outInsets.contentInsets.top = 0;
         outInsets.contentInsets.left = 0;
-        outInsets.contentInsets.right = 0;
         outInsets.contentInsets.bottom = 0;
+        outInsets.contentInsets.right = 0;
+        View decor = getWindow().getWindow().getDecorView();
+        outInsets.contentInsets.top = decor.getHeight();
         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
         outInsets.touchableRegion.setEmpty();
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
      * has actually started.
      *
@@ -731,8 +770,6 @@
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Called when the last activity of a task initiated by
      * {@link #startVoiceActivity(android.content.Intent)} has finished.  The default
      * implementation calls {@link #finish()} on the assumption that this represents
@@ -744,12 +781,10 @@
      * @param taskId Unique ID of the finished task.
      */
     public void onTaskFinished(Intent intent, int taskId) {
-        finish();
+        hide();
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Request to query for what extended commands the session supports.
      *
      * @param caller Who is making the request.
@@ -764,8 +799,6 @@
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Request to confirm with the user before proceeding with an unrecoverable operation,
      * corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
      * VoiceInteractor.ConfirmationRequest}.
@@ -781,8 +814,6 @@
             Bundle extras);
 
     /**
-     * @hide
-     * @SystemApi
      * Request to complete the voice interaction session because the voice activity successfully
      * completed its interaction using voice.  Corresponds to
      * {@link android.app.VoiceInteractor.CompleteVoiceRequest
@@ -804,8 +835,6 @@
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Request to abort the voice interaction session because the voice activity can not
      * complete its interaction using voice.  Corresponds to
      * {@link android.app.VoiceInteractor.AbortVoiceRequest
@@ -824,8 +853,6 @@
     }
 
     /**
-     * @hide
-     * @SystemApi
      * Process an arbitrary extended command from the caller,
      * corresponding to a {@link android.app.VoiceInteractor.CommandRequest
      * VoiceInteractor.CommandRequest}.
@@ -840,8 +867,6 @@
     public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
 
     /**
-     * @hide
-     * @SystemApi
      * Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
      * that was previously delivered to {@link #onConfirm} or {@link #onCommand}.
      *
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index e793849..008d55f 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -40,9 +40,9 @@
     VoiceInteractionSession mSession;
 
     IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() {
-        public void newSession(IBinder token, Bundle args) {
-            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(MSG_NEW_SESSION,
-                    token, args));
+        public void newSession(IBinder token, Bundle args, int startFlags) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_NEW_SESSION,
+                    startFlags, token, args));
 
         }
     };
@@ -54,7 +54,7 @@
             SomeArgs args = (SomeArgs)msg.obj;
             switch (msg.what) {
                 case MSG_NEW_SESSION:
-                    doNewSession((IBinder)args.arg1, (Bundle)args.arg2);
+                    doNewSession((IBinder)args.arg1, (Bundle)args.arg2, args.argi1);
                     break;
             }
         }
@@ -76,7 +76,7 @@
         return mInterface.asBinder();
     }
 
-    void doNewSession(IBinder token, Bundle args) {
+    void doNewSession(IBinder token, Bundle args, int startFlags) {
         if (mSession != null) {
             mSession.doDestroy();
             mSession = null;
@@ -84,7 +84,7 @@
         mSession = onNewSession(args);
         try {
             mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
-            mSession.doCreate(mSystemService, token, args);
+            mSession.doCreate(mSystemService, token, args, startFlags);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 9496b53..4902a71 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -64,8 +64,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-
 /**
  * A wallpaper service is responsible for showing a live wallpaper behind
  * applications that would like to sit on top of it.  This service object
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index b4ac429..d4fea53 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -17,7 +17,6 @@
 
 import android.content.Context;
 import android.media.AudioSystem;
-import android.media.AudioTrack;
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.ConditionVariable;
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index dc4e9d3..9920ea1 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -2,7 +2,6 @@
 
 package android.speech.tts;
 
-import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioTrack;
 import android.speech.tts.TextToSpeechService.AudioOutputParams;
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index 899515f..d785c3f 100644
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -40,7 +40,7 @@
      *
      * @param utteranceId Unique id identifying synthesis request.
      */
-    void onStop(String utteranceId);
+    void onStop(String utteranceId, boolean isStarted);
 
     /**
      * Tells the client that the synthesis has failed.
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c59ca8a..668e028 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts;
 
+import android.annotation.RawRes;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
@@ -37,7 +38,6 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -884,7 +884,7 @@
      *
      * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
-    public int addSpeech(String text, String packagename, int resourceId) {
+    public int addSpeech(String text, String packagename, @RawRes int resourceId) {
         synchronized (mStartLock) {
             mUtterances.put(text, makeResourceUri(packagename, resourceId));
             return SUCCESS;
@@ -993,7 +993,7 @@
      *
      * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
      */
-    public int addEarcon(String earcon, String packagename, int resourceId) {
+    public int addEarcon(String earcon, String packagename, @RawRes int resourceId) {
         synchronized(mStartLock) {
             mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
             return SUCCESS;
@@ -2066,10 +2066,10 @@
         private boolean mEstablished;
 
         private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
-            public void onStop(String utteranceId) throws RemoteException {
+            public void onStop(String utteranceId, boolean isStarted) throws RemoteException {
                 UtteranceProgressListener listener = mUtteranceProgressListener;
                 if (listener != null) {
-                    listener.onDone(utteranceId);
+                    listener.onStop(utteranceId, isStarted);
                 }
             };
 
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 9bb7f02..ba98f27 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -39,11 +39,9 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.Set;
 
@@ -455,10 +453,37 @@
     private class SynthHandler extends Handler {
         private SpeechItem mCurrentSpeechItem = null;
 
+        private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
+        private boolean mFlushAll;
+
         public SynthHandler(Looper looper) {
             super(looper);
         }
 
+        private void startFlushingSpeechItems(Object callerIdentity) {
+            synchronized (mFlushedObjects) {
+                if (callerIdentity == null) {
+                    mFlushAll = true;
+                } else {
+                    mFlushedObjects.add(callerIdentity);
+                }
+            }
+        }
+        private void endFlushingSpeechItems(Object callerIdentity) {
+            synchronized (mFlushedObjects) {
+                if (callerIdentity == null) {
+                    mFlushAll = false;
+                } else {
+                    mFlushedObjects.remove(callerIdentity);
+                }
+            }
+        }
+        private boolean isFlushed(SpeechItem speechItem) {
+            synchronized (mFlushedObjects) {
+                return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
+            }
+        }
+
         private synchronized SpeechItem getCurrentSpeechItem() {
             return mCurrentSpeechItem;
         }
@@ -522,9 +547,13 @@
             Runnable runnable = new Runnable() {
                 @Override
                 public void run() {
-                    setCurrentSpeechItem(speechItem);
-                    speechItem.play();
-                    setCurrentSpeechItem(null);
+                    if (isFlushed(speechItem)) {
+                        speechItem.stop();
+                    } else {
+                        setCurrentSpeechItem(speechItem);
+                        speechItem.play();
+                        setCurrentSpeechItem(null);
+                    }
                 }
             };
             Message msg = Message.obtain(this, runnable);
@@ -552,12 +581,14 @@
          *
          * Called on a service binder thread.
          */
-        public int stopForApp(Object callerIdentity) {
+        public int stopForApp(final Object callerIdentity) {
             if (callerIdentity == null) {
                 return TextToSpeech.ERROR;
             }
 
-            removeCallbacksAndMessages(callerIdentity);
+            // Flush pending messages from callerIdentity
+            startFlushingSpeechItems(callerIdentity);
+
             // This stops writing data to the file / or publishing
             // items to the audio playback handler.
             //
@@ -573,20 +604,39 @@
             // Remove any enqueued audio too.
             mAudioPlaybackHandler.stopForApp(callerIdentity);
 
+            // Stop flushing pending messages
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    endFlushingSpeechItems(callerIdentity);
+                }
+            };
+            sendMessage(Message.obtain(this, runnable));
             return TextToSpeech.SUCCESS;
         }
 
         public int stopAll() {
+            // Order to flush pending messages
+            startFlushingSpeechItems(null);
+
             // Stop the current speech item unconditionally .
             SpeechItem current = setCurrentSpeechItem(null);
             if (current != null) {
                 current.stop();
             }
-            // Remove all other items from the queue.
-            removeCallbacksAndMessages(null);
             // Remove all pending playback as well.
             mAudioPlaybackHandler.stop();
 
+            // Message to stop flushing pending messages
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    endFlushingSpeechItems(null);
+                }
+            };
+            sendMessage(Message.obtain(this, runnable));
+
+
             return TextToSpeech.SUCCESS;
         }
     }
@@ -698,7 +748,6 @@
             return mCallerIdentity;
         }
 
-
         public int getCallerUid() {
             return mCallerUid;
         }
@@ -752,6 +801,10 @@
         protected synchronized boolean isStopped() {
              return mStopped;
         }
+
+        protected synchronized boolean isStarted() {
+            return mStarted;
+       }
     }
 
     /**
@@ -777,7 +830,7 @@
         public void dispatchOnStop() {
             final String utteranceId = getUtteranceId();
             if (utteranceId != null) {
-                mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId);
+                mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId, isStarted());
             }
         }
 
@@ -940,6 +993,8 @@
                 // turn implies that synthesis would not have started.
                 synthesisCallback.stop();
                 TextToSpeechService.this.onStop();
+            } else {
+                dispatchOnStop();
             }
         }
 
@@ -1345,11 +1400,11 @@
             }
         }
 
-        public void dispatchOnStop(Object callerIdentity, String utteranceId) {
+        public void dispatchOnStop(Object callerIdentity, String utteranceId, boolean started) {
             ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
             if (cb == null) return;
             try {
-                cb.onStop(utteranceId);
+                cb.onStop(utteranceId, started);
             } catch (RemoteException e) {
                 Log.e(TAG, "Callback onStop failed: " + e);
             }
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index df6c010..412eba3 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -17,7 +17,6 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 6769794..9eb22ef 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -60,6 +60,20 @@
     }
 
     /**
+     * Called when an utterance has been stopped while in progress or flushed from the
+     * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()}
+     * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in
+     * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
+     *
+     * @param utteranceId the utterance ID of the utterance.
+     * @param isStarted If true, then utterance was interrupted while being synthesized
+     *        and it's output is incomplete. If it's false, then utterance was flushed
+     *        before the synthesis started.
+     */
+    public void onStop(String utteranceId, boolean isStarted) {
+    }
+
+    /**
      * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
      * progress listener.
      *
@@ -83,6 +97,11 @@
                 // Left unimplemented, has no equivalent in the old
                 // API.
             }
+
+            @Override
+            public void onStop(String utteranceId, boolean isStarted) {
+                listener.onUtteranceCompleted(utteranceId);
+            }
         };
     }
 }
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 6f00707..e78cf8f 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -20,7 +20,6 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.text.style.ParagraphStyle;
-import android.util.FloatMath;
 
 /**
  * A BoringLayout is a very simple Layout implementation for text that
@@ -207,7 +206,7 @@
             TextLine line = TextLine.obtain();
             line.set(paint, source, 0, source.length(), Layout.DIR_LEFT_TO_RIGHT,
                     Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
-            mMax = (int) FloatMath.ceil(line.metrics(null));
+            mMax = (int) Math.ceil(line.metrics(null));
             TextLine.recycle(line);
         }
 
@@ -301,7 +300,7 @@
             TextLine line = TextLine.obtain();
             line.set(paint, text, 0, length, Layout.DIR_LEFT_TO_RIGHT,
                     Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
-            fm.width = (int) FloatMath.ceil(line.metrics(fm));
+            fm.width = (int) Math.ceil(line.metrics(fm));
             TextLine.recycle(line);
 
             return fm;
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 77ef1da..1bdaef0 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -270,22 +270,30 @@
         // generate new layout for affected text
 
         StaticLayout reflowed;
+        StaticLayout.Builder b;
 
         synchronized (sLock) {
             reflowed = sStaticLayout;
+            b = sBuilder;
             sStaticLayout = null;
+            sBuilder = null;
         }
 
+        // TODO: make sure reflowed is properly initialized
         if (reflowed == null) {
             reflowed = new StaticLayout(null);
-        } else {
-            reflowed.prepare();
+            b = StaticLayout.Builder.obtain();
         }
 
-        reflowed.generate(text, where, where + after,
-                getPaint(), getWidth(), getTextDirectionHeuristic(), getSpacingMultiplier(),
-                getSpacingAdd(), false,
-                true, mEllipsizedWidth, mEllipsizeAt);
+        b.setText(text, where, where + after)
+                .setPaint(getPaint())
+                .setWidth(getWidth())
+                .setTextDir(getTextDirectionHeuristic())
+                .setSpacingMult(getSpacingMultiplier())
+                .setSpacingAdd(getSpacingAdd())
+                .setEllipsizedWidth(mEllipsizedWidth)
+                .setEllipsize(mEllipsizeAt);
+        reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
 
         // If the new layout has a blank line at the end, but it is not
@@ -359,9 +367,10 @@
 
         updateBlocks(startline, endline - 1, n);
 
+        b.finish();
         synchronized (sLock) {
             sStaticLayout = reflowed;
-            reflowed.finish();
+            sBuilder = b;
         }
     }
 
@@ -720,7 +729,8 @@
 
     private int mTopPadding, mBottomPadding;
 
-    private static StaticLayout sStaticLayout = new StaticLayout(null);
+    private static StaticLayout sStaticLayout = null;
+    private static StaticLayout.Builder sBuilder = null;
 
     private static final Object[] sLock = new Object[0];
 
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 2fcc597..dc93bc2 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -61,7 +61,7 @@
      */
     public static interface ImageGetter {
         /**
-         * This methos is called when the HTML parser encounters an
+         * This method is called when the HTML parser encounters an
          * &lt;img&gt; tag.  The <code>source</code> argument is the
          * string from the "src" attribute; the return value should be
          * a Drawable representation of the image or <code>null</code>
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index b84c3aa..fcf1828 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1564,7 +1564,7 @@
         MeasuredText mt = MeasuredText.obtain();
         TextLine tl = TextLine.obtain();
         try {
-            mt.setPara(text, start, end, TextDirectionHeuristics.LTR);
+            mt.setPara(text, start, end, TextDirectionHeuristics.LTR, null);
             Directions directions;
             int dir;
             if (mt.mEasy) {
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 2415b11..55df206 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -16,7 +16,6 @@
 
 package android.text;
 
-import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.ReplacementSpan;
@@ -40,6 +39,7 @@
 
     private int mPos;
     private TextPaint mWorkPaint;
+    private StaticLayout.Builder mBuilder;
 
     private MeasuredText() {
         mWorkPaint = new TextPaint();
@@ -67,21 +67,29 @@
     }
 
     static MeasuredText recycle(MeasuredText mt) {
-        mt.mText = null;
-        if (mt.mLen < 1000) {
-            synchronized(sLock) {
-                for (int i = 0; i < sCached.length; ++i) {
-                    if (sCached[i] == null) {
-                        sCached[i] = mt;
-                        mt.mText = null;
-                        break;
-                    }
+        mt.finish();
+        synchronized(sLock) {
+            for (int i = 0; i < sCached.length; ++i) {
+                if (sCached[i] == null) {
+                    sCached[i] = mt;
+                    mt.mText = null;
+                    break;
                 }
             }
         }
         return null;
     }
 
+    void finish() {
+        mText = null;
+        mBuilder = null;
+        if (mLen > 1000) {
+            mWidths = null;
+            mChars = null;
+            mLevels = null;
+        }
+    }
+
     void setPos(int pos) {
         mPos = pos - mTextStart;
     }
@@ -89,7 +97,9 @@
     /**
      * Analyzes text for bidirectional runs.  Allocates working buffers.
      */
-    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
+    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir,
+            StaticLayout.Builder builder) {
+        mBuilder = builder;
         mText = text;
         mTextStart = start;
 
@@ -158,9 +168,24 @@
         int p = mPos;
         mPos = p + len;
 
+        // try to do widths measurement in native code, but use Java if paint has been subclassed
+        // FIXME: may want to eliminate special case for subclass
+        float[] widths = null;
+        if (mBuilder == null || paint.getClass() != TextPaint.class) {
+            widths = mWidths;
+        }
         if (mEasy) {
             boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
-            return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
+            float width = 0;
+            if (widths != null) {
+                width = paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, widths, p);
+                if (mBuilder != null) {
+                    mBuilder.addMeasuredRun(p, p + len, widths);
+                }
+            } else {
+                width = mBuilder.addStyleRun(paint, p, p + len, isRtl);
+            }
+            return width;
         }
 
         float totalAdvance = 0;
@@ -168,8 +193,15 @@
         for (int q = p, i = p + 1, e = p + len;; ++i) {
             if (i == e || mLevels[i] != level) {
                 boolean isRtl = (level & 0x1) != 0;
-                totalAdvance +=
-                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
+                if (widths != null) {
+                    totalAdvance +=
+                            paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, widths, q);
+                    if (mBuilder != null) {
+                        mBuilder.addMeasuredRun(q, i, widths);
+                    }
+                } else {
+                    totalAdvance += mBuilder.addStyleRun(paint, q, i, isRtl);
+                }
                 if (i == e) {
                     break;
                 }
@@ -205,10 +237,14 @@
             // Use original text.  Shouldn't matter.
             wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
                     mTextStart + mPos + len, fm);
-            float[] w = mWidths;
-            w[mPos] = wid;
-            for (int i = mPos + 1, e = mPos + len; i < e; i++)
-                w[i] = 0;
+            if (mBuilder == null) {
+                float[] w = mWidths;
+                w[mPos] = wid;
+                for (int i = mPos + 1, e = mPos + len; i < e; i++)
+                    w[i] = 0;
+            } else {
+                mBuilder.addReplacementRun(mPos, mPos + len, wid);
+            }
             mPos += len;
         }
 
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 06df683..7ce44e1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -26,6 +26,7 @@
 import libcore.util.EmptyArray;
 
 import java.lang.reflect.Array;
+import java.util.IdentityHashMap;
 
 /**
  * This is the class for text whose content and markup can both be changed.
@@ -68,6 +69,7 @@
         mSpanStarts = EmptyArray.INT;
         mSpanEnds = EmptyArray.INT;
         mSpanFlags = EmptyArray.INT;
+        mSpanMax = EmptyArray.INT;
 
         if (text instanceof Spanned) {
             Spanned sp = (Spanned) text;
@@ -94,6 +96,7 @@
 
                 setSpan(false, spans[i], st, en, fl);
             }
+            restoreInvariants();
         }
     }
 
@@ -147,9 +150,12 @@
         if (mGapLength < 1)
             new Exception("mGapLength < 1").printStackTrace();
 
-        for (int i = 0; i < mSpanCount; i++) {
-            if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
-            if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+        if (mSpanCount != 0) {
+            for (int i = 0; i < mSpanCount; i++) {
+                if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
+                if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+            }
+            calcMax(treeRoot());
         }
     }
 
@@ -167,35 +173,38 @@
             System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap);
         }
 
-        // XXX be more clever
-        for (int i = 0; i < mSpanCount; i++) {
-            int start = mSpanStarts[i];
-            int end = mSpanEnds[i];
+        // TODO: be more clever (although the win really isn't that big)
+        if (mSpanCount != 0) {
+            for (int i = 0; i < mSpanCount; i++) {
+                int start = mSpanStarts[i];
+                int end = mSpanEnds[i];
 
-            if (start > mGapStart)
-                start -= mGapLength;
-            if (start > where)
-                start += mGapLength;
-            else if (start == where) {
-                int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
-
-                if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                if (start > mGapStart)
+                    start -= mGapLength;
+                if (start > where)
                     start += mGapLength;
-            }
+                else if (start == where) {
+                    int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
 
-            if (end > mGapStart)
-                end -= mGapLength;
-            if (end > where)
-                end += mGapLength;
-            else if (end == where) {
-                int flag = (mSpanFlags[i] & END_MASK);
+                    if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                        start += mGapLength;
+                }
 
-                if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                if (end > mGapStart)
+                    end -= mGapLength;
+                if (end > where)
                     end += mGapLength;
-            }
+                else if (end == where) {
+                    int flag = (mSpanFlags[i] & END_MASK);
 
-            mSpanStarts[i] = start;
-            mSpanEnds[i] = end;
+                    if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                        end += mGapLength;
+                }
+
+                mSpanStarts[i] = start;
+                mSpanEnds[i] = end;
+            }
+            calcMax(treeRoot());
         }
 
         mGapStart = where;
@@ -243,6 +252,9 @@
 
             sendSpanRemoved(what, ostart, oend);
         }
+        if (mIndexOfSpan != null) {
+            mIndexOfSpan.clear();
+        }
     }
 
     // Documentation from interface
@@ -277,12 +289,39 @@
         return append(String.valueOf(text));
     }
 
+    // Returns true if a node was removed (so we can restart search from root)
+    private boolean removeSpansForChange(int start, int end, boolean textIsRemoved, int i) {
+        if ((i & 1) != 0) {
+            // internal tree node
+            if (resolveGap(mSpanMax[i]) >= start &&
+                    removeSpansForChange(start, end, textIsRemoved, leftChild(i))) {
+                return true;
+            }
+        }
+        if (i < mSpanCount) {
+            if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
+                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
+                    mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
+                    mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
+                    // The following condition indicates that the span would become empty
+                    (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
+                mIndexOfSpan.remove(mSpans[i]);
+                removeSpan(i);
+                return true;
+            }
+            return resolveGap(mSpanStarts[i]) <= end && (i & 1) != 0 &&
+                removeSpansForChange(start, end, textIsRemoved, rightChild(i));
+        }
+        return false;
+    }
+
     private void change(int start, int end, CharSequence cs, int csStart, int csEnd) {
         // Can be negative
         final int replacedLength = end - start;
         final int replacementLength = csEnd - csStart;
         final int nbNewChars = replacementLength - replacedLength;
 
+        boolean changed = false;
         for (int i = mSpanCount - 1; i >= 0; i--) {
             int spanStart = mSpanStarts[i];
             if (spanStart > mGapStart)
@@ -309,8 +348,10 @@
                             break;
                 }
 
-                if (spanStart != ost || spanEnd != oen)
+                if (spanStart != ost || spanEnd != oen) {
                     setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i]);
+                    changed = true;
+                }
             }
 
             int flags = 0;
@@ -320,6 +361,9 @@
             else if (spanEnd == end + nbNewChars) flags |= SPAN_END_AT_END;
             mSpanFlags[i] |= flags;
         }
+        if (changed) {
+            restoreInvariants();
+        }
 
         moveGapTo(end);
 
@@ -331,23 +375,10 @@
         // The removal pass needs to be done before the gap is updated in order to broadcast the
         // correct previous positions to the correct intersecting SpanWatchers
         if (replacedLength > 0) { // no need for span fixup on pure insertion
-            // A for loop will not work because the array is being modified
-            // Do not iterate in reverse to keep the SpanWatchers notified in ordering
-            // Also, a removed SpanWatcher should not get notified of removed spans located
-            // further in the span array.
-            int i = 0;
-            while (i < mSpanCount) {
-                if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
-                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
-                        mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
-                        mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
-                        // This condition indicates that the span would become empty
-                        (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
-                    removeSpan(i);
-                    continue; // do not increment i, spans will be shifted left in the array
-                }
-
-                i++;
+            while (mSpanCount > 0 &&
+                    removeSpansForChange(start, end, textIsRemoved, treeRoot())) {
+                // keep deleting spans as needed, and restart from root after every deletion
+                // because deletion can invalidate an index.
             }
         }
 
@@ -360,6 +391,7 @@
         TextUtils.getChars(cs, csStart, csEnd, mText, start);
 
         if (replacedLength > 0) { // no need for span fixup on pure insertion
+            // TODO potential optimization: only update bounds on intersecting spans
             final boolean atEnd = (mGapStart + mGapLength == mText.length);
 
             for (int i = 0; i < mSpanCount; i++) {
@@ -371,10 +403,10 @@
                 mSpanEnds[i] = updatedIntervalBound(mSpanEnds[i], start, nbNewChars, endFlag,
                         atEnd, textIsRemoved);
             }
+            // TODO potential optimization: only fix up invariants when bounds actually changed
+            restoreInvariants();
         }
 
-        mSpanCountBeforeAdd = mSpanCount;
-
         if (cs instanceof Spanned) {
             Spanned sp = (Spanned) cs;
             Object[] spans = sp.getSpans(csStart, csEnd, Object.class);
@@ -389,9 +421,10 @@
                 // Add span only if this object is not yet used as a span in this string
                 if (getSpanStart(spans[i]) < 0) {
                     setSpan(false, spans[i], st - csStart + start, en - csStart + start,
-                            sp.getSpanFlags(spans[i]));
+                            sp.getSpanFlags(spans[i]) | SPAN_ADDED);
                 }
             }
+            restoreInvariants();
         }
     }
 
@@ -427,6 +460,7 @@
         return offset;
     }
 
+    // Note: caller is responsible for removing the mIndexOfSpan entry.
     private void removeSpan(int i) {
         Object object = mSpans[i];
 
@@ -444,8 +478,12 @@
 
         mSpanCount--;
 
+        invalidateIndex(i);
         mSpans[mSpanCount] = null;
 
+        // Invariants must be restored before sending span removed notifications.
+        restoreInvariants();
+
         sendSpanRemoved(object, start, end);
     }
 
@@ -496,10 +534,12 @@
         change(start, end, tb, tbstart, tbend);
 
         if (adjustSelection) {
+            boolean changed = false;
             if (selectionStart > start && selectionStart < end) {
                 final int offset = (selectionStart - start) * newLen / origLen;
                 selectionStart = start + offset;
 
+                changed = true;
                 setSpan(false, Selection.SELECTION_START, selectionStart, selectionStart,
                         Spanned.SPAN_POINT_POINT);
             }
@@ -507,9 +547,13 @@
                 final int offset = (selectionEnd - start) * newLen / origLen;
                 selectionEnd = start + offset;
 
+                changed = true;
                 setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
                         Spanned.SPAN_POINT_POINT);
             }
+            if (changed) {
+                restoreInvariants();
+            }
         }
 
         sendTextChanged(textWatchers, start, origLen, newLen);
@@ -536,12 +580,15 @@
     }
 
     private void sendToSpanWatchers(int replaceStart, int replaceEnd, int nbNewChars) {
-        for (int i = 0; i < mSpanCountBeforeAdd; i++) {
+        for (int i = 0; i < mSpanCount; i++) {
+            int spanFlags = mSpanFlags[i];
+
+            // This loop handles only modified (not added) spans.
+            if ((spanFlags & SPAN_ADDED) != 0) continue;
             int spanStart = mSpanStarts[i];
             int spanEnd = mSpanEnds[i];
             if (spanStart > mGapStart) spanStart -= mGapLength;
             if (spanEnd > mGapStart) spanEnd -= mGapLength;
-            int spanFlags = mSpanFlags[i];
 
             int newReplaceEnd = replaceEnd + nbNewChars;
             boolean spanChanged = false;
@@ -588,13 +635,17 @@
             mSpanFlags[i] &= ~SPAN_START_END_MASK;
         }
 
-        // The spans starting at mIntermediateSpanCount were added from the replacement text
-        for (int i = mSpanCountBeforeAdd; i < mSpanCount; i++) {
-            int spanStart = mSpanStarts[i];
-            int spanEnd = mSpanEnds[i];
-            if (spanStart > mGapStart) spanStart -= mGapLength;
-            if (spanEnd > mGapStart) spanEnd -= mGapLength;
-            sendSpanAdded(mSpans[i], spanStart, spanEnd);
+        // Handle added spans
+        for (int i = 0; i < mSpanCount; i++) {
+            int spanFlags = mSpanFlags[i];
+            if ((spanFlags & SPAN_ADDED) != 0) {
+                mSpanFlags[i] &= ~SPAN_ADDED;
+                int spanStart = mSpanStarts[i];
+                int spanEnd = mSpanEnds[i];
+                if (spanStart > mGapStart) spanStart -= mGapLength;
+                if (spanEnd > mGapStart) spanEnd -= mGapLength;
+                sendSpanAdded(mSpans[i], spanStart, spanEnd);
+            }
         }
     }
 
@@ -607,6 +658,9 @@
         setSpan(true, what, start, end, flags);
     }
 
+    // Note: if send is false, then it is the caller's responsibility to restore
+    // invariants. If send is false and the span already exists, then this method
+    // will not change the index of any spans.
     private void setSpan(boolean send, Object what, int start, int end, int flags) {
         checkRange("setSpan", start, end);
 
@@ -661,8 +715,10 @@
         int count = mSpanCount;
         Object[] spans = mSpans;
 
-        for (int i = 0; i < count; i++) {
-            if (spans[i] == what) {
+        if (mIndexOfSpan != null) {
+            Integer index = mIndexOfSpan.get(what);
+            if (index != null) {
+                int i = index;
                 int ostart = mSpanStarts[i];
                 int oend = mSpanEnds[i];
 
@@ -675,7 +731,10 @@
                 mSpanEnds[i] = end;
                 mSpanFlags[i] = flags;
 
-                if (send) sendSpanChanged(what, ostart, oend, nstart, nend);
+                if (send) {
+                    restoreInvariants();
+                    sendSpanChanged(what, ostart, oend, nstart, nend);
+                }
 
                 return;
             }
@@ -685,43 +744,48 @@
         mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
         mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
         mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
+        invalidateIndex(mSpanCount);
         mSpanCount++;
+        // Make sure there is enough room for empty interior nodes.
+        // This magic formula computes the size of the smallest perfect binary
+        // tree no smaller than mSpanCount.
+        int sizeOfMax = 2 * treeRoot() + 1;
+        if (mSpanMax.length < sizeOfMax) {
+            mSpanMax = new int[sizeOfMax];
+        }
 
-        if (send) sendSpanAdded(what, nstart, nend);
+        if (send) {
+            restoreInvariants();
+            sendSpanAdded(what, nstart, nend);
+        }
     }
 
     /**
      * Remove the specified markup object from the buffer.
      */
     public void removeSpan(Object what) {
-        for (int i = mSpanCount - 1; i >= 0; i--) {
-            if (mSpans[i] == what) {
-                removeSpan(i);
-                return;
-            }
+        if (mIndexOfSpan == null) return;
+        Integer i = mIndexOfSpan.remove(what);
+        if (i != null) {
+            removeSpan(i.intValue());
         }
     }
 
     /**
+     * Return externally visible offset given offset into gapped buffer.
+     */
+    private int resolveGap(int i) {
+        return i > mGapStart ? i - mGapLength : i;
+    }
+
+    /**
      * Return the buffer offset of the beginning of the specified
      * markup object, or -1 if it is not attached to this buffer.
      */
     public int getSpanStart(Object what) {
-        int count = mSpanCount;
-        Object[] spans = mSpans;
-
-        for (int i = count - 1; i >= 0; i--) {
-            if (spans[i] == what) {
-                int where = mSpanStarts[i];
-
-                if (where > mGapStart)
-                    where -= mGapLength;
-
-                return where;
-            }
-        }
-
-        return -1;
+        if (mIndexOfSpan == null) return -1;
+        Integer i = mIndexOfSpan.get(what);
+        return i == null ? -1 : resolveGap(mSpanStarts[i]);
     }
 
     /**
@@ -729,21 +793,9 @@
      * markup object, or -1 if it is not attached to this buffer.
      */
     public int getSpanEnd(Object what) {
-        int count = mSpanCount;
-        Object[] spans = mSpans;
-
-        for (int i = count - 1; i >= 0; i--) {
-            if (spans[i] == what) {
-                int where = mSpanEnds[i];
-
-                if (where > mGapStart)
-                    where -= mGapLength;
-
-                return where;
-            }
-        }
-
-        return -1;
+        if (mIndexOfSpan == null) return -1;
+        Integer i = mIndexOfSpan.get(what);
+        return i == null ? -1 : resolveGap(mSpanEnds[i]);
     }
 
     /**
@@ -751,16 +803,9 @@
      * markup object, or 0 if it is not attached to this buffer.
      */
     public int getSpanFlags(Object what) {
-        int count = mSpanCount;
-        Object[] spans = mSpans;
-
-        for (int i = count - 1; i >= 0; i--) {
-            if (spans[i] == what) {
-                return mSpanFlags[i];
-            }
-        }
-
-        return 0;
+        if (mIndexOfSpan == null) return 0;
+        Integer i = mIndexOfSpan.get(what);
+        return i == null ? 0 : mSpanFlags[i];
     }
 
     /**
@@ -770,59 +815,84 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
-        if (kind == null) return ArrayUtils.emptyArray(kind);
+        if (kind == null || mSpanCount == 0) return ArrayUtils.emptyArray(kind);
+        int count = countSpans(queryStart, queryEnd, kind, treeRoot());
+        if (count == 0) {
+            return ArrayUtils.emptyArray(kind);
+        }
 
-        int spanCount = mSpanCount;
-        Object[] spans = mSpans;
-        int[] starts = mSpanStarts;
-        int[] ends = mSpanEnds;
-        int[] flags = mSpanFlags;
-        int gapstart = mGapStart;
-        int gaplen = mGapLength;
+        // Safe conversion, but requires a suppressWarning
+        T[] ret = (T[]) Array.newInstance(kind, count);
+        getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, 0);
+        return ret;
+    }
 
+    private int countSpans(int queryStart, int queryEnd, Class kind, int i) {
         int count = 0;
-        T[] ret = null;
-        T ret1 = null;
-
-        for (int i = 0; i < spanCount; i++) {
-            int spanStart = starts[i];
-            if (spanStart > gapstart) {
-                spanStart -= gaplen;
+        if ((i & 1) != 0) {
+            // internal tree node
+            int left = leftChild(i);
+            int spanMax = mSpanMax[left];
+            if (spanMax > mGapStart) {
+                spanMax -= mGapLength;
             }
-            if (spanStart > queryEnd) {
-                continue;
+            if (spanMax >= queryStart) {
+                count = countSpans(queryStart, queryEnd, kind, left);
             }
-
-            int spanEnd = ends[i];
-            if (spanEnd > gapstart) {
-                spanEnd -= gaplen;
+        }
+        if (i < mSpanCount) {
+            int spanStart = mSpanStarts[i];
+            if (spanStart > mGapStart) {
+                spanStart -= mGapLength;
             }
-            if (spanEnd < queryStart) {
-                continue;
-            }
-
-            if (spanStart != spanEnd && queryStart != queryEnd) {
-                if (spanStart == queryEnd)
-                    continue;
-                if (spanEnd == queryStart)
-                    continue;
-            }
-
-            // Expensive test, should be performed after the previous tests
-            if (!kind.isInstance(spans[i])) continue;
-
-            if (count == 0) {
-                // Safe conversion thanks to the isInstance test above
-                ret1 = (T) spans[i];
-                count++;
-            } else {
-                if (count == 1) {
-                    // Safe conversion, but requires a suppressWarning
-                    ret = (T[]) Array.newInstance(kind, spanCount - i + 1);
-                    ret[0] = ret1;
+            if (spanStart <= queryEnd) {
+                int spanEnd = mSpanEnds[i];
+                if (spanEnd > mGapStart) {
+                    spanEnd -= mGapLength;
                 }
+                if (spanEnd >= queryStart &&
+                    (spanStart == spanEnd || queryStart == queryEnd ||
+                        (spanStart != queryEnd && spanEnd != queryStart)) &&
+                        kind.isInstance(mSpans[i])) {
+                    count++;
+                }
+                if ((i & 1) != 0) {
+                    count += countSpans(queryStart, queryEnd, kind, rightChild(i));
+                }
+            }
+        }
+        return count;
+    }
 
-                int prio = flags[i] & SPAN_PRIORITY;
+    @SuppressWarnings("unchecked")
+    private <T> int getSpansRec(int queryStart, int queryEnd, Class<T> kind,
+            int i, T[] ret, int count) {
+        if ((i & 1) != 0) {
+            // internal tree node
+            int left = leftChild(i);
+            int spanMax = mSpanMax[left];
+            if (spanMax > mGapStart) {
+                spanMax -= mGapLength;
+            }
+            if (spanMax >= queryStart) {
+                count = getSpansRec(queryStart, queryEnd, kind, left, ret, count);
+            }
+        }
+        if (i >= mSpanCount) return count;
+        int spanStart = mSpanStarts[i];
+        if (spanStart > mGapStart) {
+            spanStart -= mGapLength;
+        }
+        if (spanStart <= queryEnd) {
+            int spanEnd = mSpanEnds[i];
+            if (spanEnd > mGapStart) {
+                spanEnd -= mGapLength;
+            }
+            if (spanEnd >= queryStart &&
+                    (spanStart == spanEnd || queryStart == queryEnd ||
+                        (spanStart != queryEnd && spanEnd != queryStart)) &&
+                        kind.isInstance(mSpans[i])) {
+                int prio = mSpanFlags[i] & SPAN_PRIORITY;
                 if (prio != 0) {
                     int j;
 
@@ -836,32 +906,18 @@
 
                     System.arraycopy(ret, j, ret, j + 1, count - j);
                     // Safe conversion thanks to the isInstance test above
-                    ret[j] = (T) spans[i];
-                    count++;
+                    ret[j] = (T) mSpans[i];
                 } else {
                     // Safe conversion thanks to the isInstance test above
-                    ret[count++] = (T) spans[i];
+                    ret[count] = (T) mSpans[i];
                 }
+                count++;
+            }
+            if (count < ret.length && (i & 1) != 0) {
+                count = getSpansRec(queryStart, queryEnd, kind, rightChild(i), ret, count);
             }
         }
-
-        if (count == 0) {
-            return ArrayUtils.emptyArray(kind);
-        }
-        if (count == 1) {
-            // Safe conversion, but requires a suppressWarning
-            ret = (T[]) Array.newInstance(kind, 1);
-            ret[0] = ret1;
-            return ret;
-        }
-        if (count == ret.length) {
-            return ret;
-        }
-
-        // Safe conversion, but requires a suppressWarning
-        T[] nret = (T[]) Array.newInstance(kind, count);
-        System.arraycopy(ret, 0, nret, 0, count);
-        return nret;
+        return count;
     }
 
     /**
@@ -870,30 +926,31 @@
      * begins or ends.
      */
     public int nextSpanTransition(int start, int limit, Class kind) {
-        int count = mSpanCount;
-        Object[] spans = mSpans;
-        int[] starts = mSpanStarts;
-        int[] ends = mSpanEnds;
-        int gapstart = mGapStart;
-        int gaplen = mGapLength;
-
+        if (mSpanCount == 0) return limit;
         if (kind == null) {
             kind = Object.class;
         }
+        return nextSpanTransitionRec(start, limit, kind, treeRoot());
+    }
 
-        for (int i = 0; i < count; i++) {
-            int st = starts[i];
-            int en = ends[i];
-
-            if (st > gapstart)
-                st -= gaplen;
-            if (en > gapstart)
-                en -= gaplen;
-
-            if (st > start && st < limit && kind.isInstance(spans[i]))
+    private int nextSpanTransitionRec(int start, int limit, Class kind, int i) {
+        if ((i & 1) != 0) {
+            // internal tree node
+            int left = leftChild(i);
+            if (resolveGap(mSpanMax[left]) > start) {
+                limit = nextSpanTransitionRec(start, limit, kind, left);
+            }
+        }
+        if (i < mSpanCount) {
+            int st = resolveGap(mSpanStarts[i]);
+            int en = resolveGap(mSpanEnds[i]);
+            if (st > start && st < limit && kind.isInstance(mSpans[i]))
                 limit = st;
-            if (en > start && en < limit && kind.isInstance(spans[i]))
+            if (en > start && en < limit && kind.isInstance(mSpans[i]))
                 limit = en;
+            if (st < limit && (i & 1) != 0) {
+                limit = nextSpanTransitionRec(start, limit, kind, rightChild(i));
+            }
         }
 
         return limit;
@@ -1339,6 +1396,118 @@
         return hash;
     }
 
+    // Primitives for treating span list as binary tree
+
+    // The spans (along with start and end offsets and flags) are stored in linear arrays sorted
+    // by start offset. For fast searching, there is a binary search structure imposed over these
+    // arrays. This structure is inorder traversal of a perfect binary tree, a slightly unusual
+    // but advantageous approach.
+
+    // The value-containing nodes are indexed 0 <= i < n (where n = mSpanCount), thus preserving
+    // logic that accesses the values as a contiguous array. Other balanced binary tree approaches
+    // (such as a complete binary tree) would require some shuffling of node indices.
+
+    // Basic properties of this structure: For a perfect binary tree of height m:
+    // The tree has 2^(m+1) - 1 total nodes.
+    // The root of the tree has index 2^m - 1.
+    // All leaf nodes have even index, all interior nodes odd.
+    // The height of a node of index i is the number of trailing ones in i's binary representation.
+    // The left child of a node i of height h is i - 2^(h - 1).
+    // The right child of a node i of height h is i + 2^(h - 1).
+
+    // Note that for arbitrary n, interior nodes of this tree may be >= n. Thus, the general
+    // structure of a recursive traversal of node i is:
+    // * traverse left child if i is an interior node
+    // * process i if i < n
+    // * traverse right child if i is an interior node and i < n
+
+    private int treeRoot() {
+        return Integer.highestOneBit(mSpanCount) - 1;
+    }
+
+    // (i+1) & ~i is equal to 2^(the number of trailing ones in i)
+    private static int leftChild(int i) {
+        return i - (((i + 1) & ~i) >> 1);
+    }
+
+    private static int rightChild(int i) {
+        return i + (((i + 1) & ~i) >> 1);
+    }
+
+    // The span arrays are also augmented by an mSpanMax[] array that represents an interval tree
+    // over the binary tree structure described above. For each node, the mSpanMax[] array contains
+    // the maximum value of mSpanEnds of that node and its descendants. Thus, traversals can
+    // easily reject subtrees that contain no spans overlapping the area of interest.
+
+    // Note that mSpanMax[] also has a valid valuefor interior nodes of index >= n, but which have
+    // descendants of index < n. In these cases, it simply represents the maximum span end of its
+    // descendants. This is a consequence of the perfect binary tree structure.
+    private int calcMax(int i) {
+        int max = 0;
+        if ((i & 1) != 0) {
+            // internal tree node
+            max = calcMax(leftChild(i));
+        }
+        if (i < mSpanCount) {
+            max = Math.max(max, mSpanEnds[i]);
+            if ((i & 1) != 0) {
+                max = Math.max(max, calcMax(rightChild(i)));
+            }
+        }
+        mSpanMax[i] = max;
+        return max;
+    }
+
+    // restores binary interval tree invariants after any mutation of span structure
+    private void restoreInvariants() {
+        if (mSpanCount == 0) return;
+
+        // invariant 1: span starts are nondecreasing
+
+        // This is a simple insertion sort because we expect it to be mostly sorted.
+        for (int i = 1; i < mSpanCount; i++) {
+            if (mSpanStarts[i] < mSpanStarts[i - 1]) {
+                Object span = mSpans[i];
+                int start = mSpanStarts[i];
+                int end = mSpanEnds[i];
+                int flags = mSpanFlags[i];
+                int j = i;
+                do {
+                    mSpans[j] = mSpans[j - 1];
+                    mSpanStarts[j] = mSpanStarts[j - 1];
+                    mSpanEnds[j] = mSpanEnds[j - 1];
+                    mSpanFlags[j] = mSpanFlags[j - 1];
+                    j--;
+                } while (j > 0 && start < mSpanStarts[j - 1]);
+                mSpans[j] = span;
+                mSpanStarts[j] = start;
+                mSpanEnds[j] = end;
+                mSpanFlags[j] = flags;
+                invalidateIndex(j);
+            }
+        }
+
+        // invariant 2: max is max span end for each node and its descendants
+        calcMax(treeRoot());
+
+        // invariant 3: mIndexOfSpan maps spans back to indices
+        if (mIndexOfSpan == null) {
+            mIndexOfSpan = new IdentityHashMap<Object, Integer>();
+        }
+        for (int i = mLowWaterMark; i < mSpanCount; i++) {
+            Integer existing = mIndexOfSpan.get(mSpans[i]);
+            if (existing == null || existing != i) {
+                mIndexOfSpan.put(mSpans[i], i);
+            }
+        }
+        mLowWaterMark = Integer.MAX_VALUE;
+    }
+
+    // Call this on any update to mSpans[], so that mIndexOfSpan can be updated
+    private void invalidateIndex(int i) {
+        mLowWaterMark = Math.min(i, mLowWaterMark);
+    }
+
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
     private InputFilter[] mFilters = NO_FILTERS;
 
@@ -1349,9 +1518,11 @@
     private Object[] mSpans;
     private int[] mSpanStarts;
     private int[] mSpanEnds;
+    private int[] mSpanMax;  // see calcMax() for an explanation of what this array stores
     private int[] mSpanFlags;
     private int mSpanCount;
-    private int mSpanCountBeforeAdd;
+    private IdentityHashMap<Object, Integer> mIndexOfSpan;
+    private int mLowWaterMark;  // indices below this have not been touched
 
     // TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
     private static final int MARK = 1;
@@ -1363,6 +1534,7 @@
     private static final int START_SHIFT = 4;
 
     // These bits are not (currently) used by SPANNED flags
+    private static final int SPAN_ADDED = 0x800;
     private static final int SPAN_START_AT_START = 0x1000;
     private static final int SPAN_START_AT_END = 0x2000;
     private static final int SPAN_END_AT_START = 0x4000;
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 07505a9..ee39e27 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,7 +16,6 @@
 
 package android.text;
 
-import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
@@ -28,6 +27,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import java.util.Arrays;
+import java.util.Locale;
+
 /**
  * StaticLayout is a Layout for text that will not be edited after it
  * is laid out.  Use {@link DynamicLayout} for text that may change.
@@ -42,6 +44,209 @@
 
     static final String TAG = "StaticLayout";
 
+    /**
+     * Builder for static layouts. It would be better if this were a public
+     * API (as it would offer much greater flexibility for adding new options)
+     * but for the time being it's just internal.
+     *
+     * @hide
+     */
+    public final static class Builder {
+        private Builder() {
+            mNativePtr = nNewBuilder();
+        }
+
+        static Builder obtain() {
+            Builder b = null;
+            synchronized (sLock) {
+                for (int i = 0; i < sCached.length; i++) {
+                    if (sCached[i] != null) {
+                        b = sCached[i];
+                        sCached[i] = null;
+                        break;
+                    }
+                }
+            }
+            if (b == null) {
+                b = new Builder();
+            }
+
+            // set default initial values
+            b.mWidth = 0;
+            b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
+            b.mSpacingMult = 1.0f;
+            b.mSpacingAdd = 0.0f;
+            b.mIncludePad = true;
+            b.mEllipsizedWidth = 0;
+            b.mEllipsize = null;
+            b.mMaxLines = Integer.MAX_VALUE;
+
+            b.mMeasuredText = MeasuredText.obtain();
+            return b;
+        }
+
+        static void recycle(Builder b) {
+            b.mPaint = null;
+            b.mText = null;
+            MeasuredText.recycle(b.mMeasuredText);
+            synchronized (sLock) {
+                for (int i = 0; i < sCached.length; i++) {
+                    if (sCached[i] == null) {
+                        sCached[i] = b;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // release any expensive state
+        /* package */ void finish() {
+            nFinishBuilder(mNativePtr);
+            mMeasuredText.finish();
+        }
+
+        public Builder setText(CharSequence source) {
+            return setText(source, 0, source.length());
+        }
+
+        public Builder setText(CharSequence source, int start, int end) {
+            mText = source;
+            mStart = start;
+            mEnd = end;
+            return this;
+        }
+
+        public Builder setPaint(TextPaint paint) {
+            mPaint = paint;
+            return this;
+        }
+
+        public Builder setWidth(int width) {
+            mWidth = width;
+            if (mEllipsize == null) {
+                mEllipsizedWidth = width;
+            }
+            return this;
+        }
+
+        public Builder setTextDir(TextDirectionHeuristic textDir) {
+            mTextDir = textDir;
+            return this;
+        }
+
+        // TODO: combine the following, as they're almost always set together?
+        public Builder setSpacingMult(float spacingMult) {
+            mSpacingMult = spacingMult;
+            return this;
+        }
+
+        public Builder setSpacingAdd(float spacingAdd) {
+            mSpacingAdd = spacingAdd;
+            return this;
+        }
+
+        public Builder setIncludePad(boolean includePad) {
+            mIncludePad = includePad;
+            return this;
+        }
+
+        // TODO: combine the following?
+        public Builder setEllipsizedWidth(int ellipsizedWidth) {
+            mEllipsizedWidth = ellipsizedWidth;
+            return this;
+        }
+
+        public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
+            mEllipsize = ellipsize;
+            return this;
+        }
+
+        public Builder setMaxLines(int maxLines) {
+            mMaxLines = maxLines;
+            return this;
+        }
+
+        /**
+         * Measurement and break iteration is done in native code. The protocol for using
+         * the native code is as follows.
+         *
+         * For each paragraph, do a nSetText of the paragraph text. Then, for each run within the
+         * paragraph:
+         *  - setLocale (this must be done at least for the first run, optional afterwards)
+         *  - one of the following, depending on the type of run:
+         *    + addStyleRun (a text run, to be measured in native code)
+         *    + addMeasuredRun (a run already measured in Java, passed into native code)
+         *    + addReplacementRun (a replacement run, width is given)
+         *
+         * After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
+         * Run nComputeLineBreaks() to obtain line breaks for the paragraph.
+         *
+         * After all paragraphs, call finish() to release expensive buffers.
+         */
+
+        private void setLocale(Locale locale) {
+            if (!locale.equals(mLocale)) {
+                nSetLocale(mNativePtr, locale.toLanguageTag());
+                mLocale = locale;
+            }
+        }
+
+        /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
+            return nAddStyleRun(mNativePtr, paint.getNativeInstance(), paint.mNativeTypeface,
+                    start, end, isRtl);
+        }
+
+        /* package */ void addMeasuredRun(int start, int end, float[] widths) {
+            nAddMeasuredRun(mNativePtr, start, end, widths);
+        }
+
+        /* package */ void addReplacementRun(int start, int end, float width) {
+            nAddReplacementRun(mNativePtr, start, end, width);
+        }
+
+        public StaticLayout build() {
+            // TODO: can optimize based on whether ellipsis is needed
+            StaticLayout result = new StaticLayout(mText);
+            result.generate(this, this.mIncludePad, this.mIncludePad);
+            recycle(this);
+            return result;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                nFreeBuilder(mNativePtr);
+            } finally {
+                super.finalize();
+            }
+        }
+
+        /* package */ long mNativePtr;
+
+        CharSequence mText;
+        int mStart;
+        int mEnd;
+        TextPaint mPaint;
+        int mWidth;
+        TextDirectionHeuristic mTextDir;
+        float mSpacingMult;
+        float mSpacingAdd;
+        boolean mIncludePad;
+        int mEllipsizedWidth;
+        TextUtils.TruncateAt mEllipsize;
+        int mMaxLines;
+
+        Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
+
+        // This will go away and be subsumed by native builder code
+        MeasuredText mMeasuredText;
+
+        Locale mLocale;
+
+        private static final Object sLock = new Object();
+        private static final Builder[] sCached = new Builder[3];
+    }
+
     public StaticLayout(CharSequence source, TextPaint paint,
                         int width,
                         Alignment align, float spacingmult, float spacingadd,
@@ -109,6 +314,17 @@
                     : new Ellipsizer(source),
               paint, outerwidth, align, textDir, spacingmult, spacingadd);
 
+        Builder b = Builder.obtain();
+        b.setText(source, bufstart, bufend)
+            .setPaint(paint)
+            .setWidth(outerwidth)
+            .setTextDir(textDir)
+            .setSpacingMult(spacingmult)
+            .setSpacingAdd(spacingadd)
+            .setIncludePad(includepad)
+            .setEllipsizedWidth(ellipsizedWidth)
+            .setEllipsize(ellipsize)
+            .setMaxLines(maxLines);
         /*
          * This is annoying, but we can't refer to the layout until
          * superclass construction is finished, and the superclass
@@ -135,14 +351,9 @@
         mLines = new int[mLineDirections.length];
         mMaximumVisibleLineCount = maxLines;
 
-        mMeasured = MeasuredText.obtain();
+        generate(b, b.mIncludePad, b.mIncludePad);
 
-        generate(source, bufstart, bufend, paint, outerwidth, textDir, spacingmult,
-                 spacingadd, includepad, includepad, ellipsizedWidth,
-                 ellipsize);
-
-        mMeasured = MeasuredText.recycle(mMeasured);
-        mFontMetricsInt = null;
+        Builder.recycle(b);
     }
 
     /* package */ StaticLayout(CharSequence text) {
@@ -151,28 +362,36 @@
         mColumns = COLUMNS_ELLIPSIZE;
         mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
         mLines = new int[mLineDirections.length];
-        // FIXME This is never recycled
-        mMeasured = MeasuredText.obtain();
     }
 
-    /* package */ void generate(CharSequence source, int bufStart, int bufEnd,
-                        TextPaint paint, int outerWidth,
-                        TextDirectionHeuristic textDir, float spacingmult,
-                        float spacingadd, boolean includepad,
-                        boolean trackpad, float ellipsizedWidth,
-                        TextUtils.TruncateAt ellipsize) {
-        int[] breakOpp = null;
-        final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
+    /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
+        CharSequence source = b.mText;
+        int bufStart = b.mStart;
+        int bufEnd = b.mEnd;
+        TextPaint paint = b.mPaint;
+        int outerWidth = b.mWidth;
+        TextDirectionHeuristic textDir = b.mTextDir;
+        float spacingmult = b.mSpacingMult;
+        float spacingadd = b.mSpacingAdd;
+        float ellipsizedWidth = b.mEllipsizedWidth;
+        TextUtils.TruncateAt ellipsize = b.mEllipsize;
+        LineBreaks lineBreaks = new LineBreaks();  // TODO: move to builder to avoid allocation costs
+        // store span end locations
+        int[] spanEndCache = new int[4];
+        // store fontMetrics per span range
+        // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
+        int[] fmCache = new int[4 * 4];
+        b.setLocale(paint.getTextLocale());  // TODO: also respect LocaleSpan within the text
 
         mLineCount = 0;
 
         int v = 0;
         boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
 
-        Paint.FontMetricsInt fm = mFontMetricsInt;
+        Paint.FontMetricsInt fm = b.mFontMetricsInt;
         int[] chooseHtv = null;
 
-        MeasuredText measured = mMeasured;
+        MeasuredText measured = b.mMeasuredText;
 
         Spanned spanned = null;
         if (source instanceof Spanned)
@@ -186,7 +405,7 @@
             else
                 paraEnd++;
 
-            int firstWidthLineLimit = mLineCount + 1;
+            int firstWidthLineCount = 1;
             int firstWidth = outerWidth;
             int restWidth = outerWidth;
 
@@ -204,9 +423,8 @@
                     // leading margin spans, not just this particular one
                     if (lms instanceof LeadingMarginSpan2) {
                         LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
-                        int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
-                        firstWidthLineLimit = Math.max(firstWidthLineLimit,
-                                lmsFirstLine + lms2.getLeadingMarginLineCount());
+                        firstWidthLineCount = Math.max(firstWidthLineCount,
+                                lms2.getLeadingMarginLineCount());
                     }
                 }
 
@@ -235,41 +453,31 @@
                 }
             }
 
-            measured.setPara(source, paraStart, paraEnd, textDir);
+            measured.setPara(source, paraStart, paraEnd, textDir, b);
             char[] chs = measured.mChars;
             float[] widths = measured.mWidths;
             byte[] chdirs = measured.mLevels;
             int dir = measured.mDir;
             boolean easy = measured.mEasy;
+            nSetText(b.mNativePtr, chs, paraEnd - paraStart);
 
-            breakOpp = nLineBreakOpportunities(localeLanguageTag, chs, paraEnd - paraStart, breakOpp);
-            int breakOppIndex = 0;
-
-            int width = firstWidth;
-
-            float w = 0;
-            // here is the offset of the starting character of the line we are currently measuring
-            int here = paraStart;
-
-            // ok is a character offset located after a word separator (space, tab, number...) where
-            // we would prefer to cut the current line. Equals to here when no such break was found.
-            int ok = paraStart;
-            float okWidth = w;
-            int okAscent = 0, okDescent = 0, okTop = 0, okBottom = 0;
-
-            // fit is a character offset such that the [here, fit[ range fits in the allowed width.
-            // We will cut the line there if no ok position is found.
-            int fit = paraStart;
-            float fitWidth = w;
-            int fitAscent = 0, fitDescent = 0, fitTop = 0, fitBottom = 0;
-            // same as fitWidth but not including any trailing whitespace
-            float fitWidthGraphing = w;
-
-            boolean hasTabOrEmoji = false;
-            boolean hasTab = false;
-            TabStops tabStops = null;
-
+            // measurement has to be done before performing line breaking
+            // but we don't want to recompute fontmetrics or span ranges the
+            // second time, so we cache those and then use those stored values
+            int fmCacheCount = 0;
+            int spanEndCacheCount = 0;
             for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+                if (fmCacheCount * 4 >= fmCache.length) {
+                    int[] grow = new int[fmCacheCount * 4 * 2];
+                    System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
+                    fmCache = grow;
+                }
+
+                if (spanEndCacheCount >= spanEndCache.length) {
+                    int[] grow = new int[spanEndCacheCount * 2];
+                    System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
+                    spanEndCache = grow;
+                }
 
                 if (spanned == null) {
                     spanEnd = paraEnd;
@@ -285,201 +493,109 @@
                     measured.addStyleRun(paint, spans, spanLen, fm);
                 }
 
-                int fmTop = fm.top;
-                int fmBottom = fm.bottom;
-                int fmAscent = fm.ascent;
-                int fmDescent = fm.descent;
+                // the order of storage here (top, bottom, ascent, descent) has to match the code below
+                // where these values are retrieved
+                fmCache[fmCacheCount * 4 + 0] = fm.top;
+                fmCache[fmCacheCount * 4 + 1] = fm.bottom;
+                fmCache[fmCacheCount * 4 + 2] = fm.ascent;
+                fmCache[fmCacheCount * 4 + 3] = fm.descent;
+                fmCacheCount++;
 
-                for (int j = spanStart; j < spanEnd; j++) {
-                    char c = chs[j - paraStart];
+                spanEndCache[spanEndCacheCount] = spanEnd;
+                spanEndCacheCount++;
+            }
 
-                    if (c == CHAR_NEW_LINE) {
-                        // intentionally left empty
-                    } else if (c == CHAR_TAB) {
-                        if (hasTab == false) {
-                            hasTab = true;
-                            hasTabOrEmoji = true;
-                            if (spanned != null) {
-                                // First tab this para, check for tabstops
-                                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
-                                        paraEnd, TabStopSpan.class);
-                                if (spans.length > 0) {
-                                    tabStops = new TabStops(TAB_INCREMENT, spans);
-                                }
-                            }
-                        }
-                        if (tabStops != null) {
-                            w = tabStops.nextTab(w);
-                        } else {
-                            w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
-                        }
-                    } else if (c >= CHAR_FIRST_HIGH_SURROGATE && c <= CHAR_LAST_LOW_SURROGATE
-                            && j + 1 < spanEnd) {
-                        int emoji = Character.codePointAt(chs, j - paraStart);
-
-                        if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
-                            Bitmap bm = EMOJI_FACTORY.getBitmapFromAndroidPua(emoji);
-
-                            if (bm != null) {
-                                Paint whichPaint;
-
-                                if (spanned == null) {
-                                    whichPaint = paint;
-                                } else {
-                                    whichPaint = mWorkPaint;
-                                }
-
-                                float wid = bm.getWidth() * -whichPaint.ascent() / bm.getHeight();
-
-                                w += wid;
-                                hasTabOrEmoji = true;
-                                j++;
-                            } else {
-                                w += widths[j - paraStart];
-                            }
-                        } else {
-                            w += widths[j - paraStart];
-                        }
-                    } else {
-                        w += widths[j - paraStart];
+            // tab stop locations
+            int[] variableTabStops = null;
+            if (spanned != null) {
+                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+                        paraEnd, TabStopSpan.class);
+                if (spans.length > 0) {
+                    int[] stops = new int[spans.length];
+                    for (int i = 0; i < spans.length; i++) {
+                        stops[i] = spans[i].getTabStop();
                     }
-
-                    boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB || c == CHAR_ZWSP;
-
-                    if (w <= width || isSpaceOrTab) {
-                        fitWidth = w;
-                        if (!isSpaceOrTab) {
-                            fitWidthGraphing = w;
-                        }
-                        fit = j + 1;
-
-                        if (fmTop < fitTop)
-                            fitTop = fmTop;
-                        if (fmAscent < fitAscent)
-                            fitAscent = fmAscent;
-                        if (fmDescent > fitDescent)
-                            fitDescent = fmDescent;
-                        if (fmBottom > fitBottom)
-                            fitBottom = fmBottom;
-
-                        while (breakOpp[breakOppIndex] != -1
-                                && breakOpp[breakOppIndex] < j - paraStart + 1) {
-                            breakOppIndex++;
-                        }
-                        boolean isLineBreak = breakOppIndex < breakOpp.length &&
-                                breakOpp[breakOppIndex] == j - paraStart + 1;
-
-                        if (isLineBreak) {
-                            okWidth = fitWidthGraphing;
-                            ok = j + 1;
-
-                            if (fitTop < okTop)
-                                okTop = fitTop;
-                            if (fitAscent < okAscent)
-                                okAscent = fitAscent;
-                            if (fitDescent > okDescent)
-                                okDescent = fitDescent;
-                            if (fitBottom > okBottom)
-                                okBottom = fitBottom;
-                        }
-                    } else {
-                        int endPos;
-                        int above, below, top, bottom;
-                        float currentTextWidth;
-
-                        if (ok != here) {
-                            endPos = ok;
-                            above = okAscent;
-                            below = okDescent;
-                            top = okTop;
-                            bottom = okBottom;
-                            currentTextWidth = okWidth;
-                        } else if (fit != here) {
-                            endPos = fit;
-                            above = fitAscent;
-                            below = fitDescent;
-                            top = fitTop;
-                            bottom = fitBottom;
-                            currentTextWidth = fitWidth;
-                        } else {
-                            // must make progress, so take next character
-                            endPos = here + 1;
-                            // but to deal properly with clusters
-                            // take all zero width characters following that
-                            while (endPos < spanEnd && widths[endPos - paraStart] == 0) {
-                                endPos++;
-                            }
-                            above = fmAscent;
-                            below = fmDescent;
-                            top = fmTop;
-                            bottom = fmBottom;
-                            currentTextWidth = widths[here - paraStart];
-                        }
-
-                        int ellipseEnd = endPos;
-                        if (mMaximumVisibleLineCount == 1 && ellipsize == TextUtils.TruncateAt.MIDDLE) {
-                            ellipseEnd = paraEnd;
-                        }
-                        v = out(source, here, ellipseEnd,
-                                above, below, top, bottom,
-                                v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, hasTabOrEmoji,
-                                needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
-                                chs, widths, paraStart, ellipsize, ellipsizedWidth,
-                                currentTextWidth, paint, true);
-
-                        here = endPos;
-                        j = here - 1; // restart j-span loop from here, compensating for the j++
-                        ok = fit = here;
-                        w = 0;
-                        fitWidthGraphing = w;
-                        fitAscent = fitDescent = fitTop = fitBottom = 0;
-                        okAscent = okDescent = okTop = okBottom = 0;
-
-                        if (--firstWidthLineLimit <= 0) {
-                            width = restWidth;
-                        }
-
-                        if (here < spanStart) {
-                            // The text was cut before the beginning of the current span range.
-                            // Exit the span loop, and get spanStart to start over from here.
-                            measured.setPos(here);
-                            spanEnd = here;
-                            break;
-                        }
-
-                        if (mLineCount >= mMaximumVisibleLineCount) {
-                            return;
-                        }
-                    }
+                    Arrays.sort(stops, 0, stops.length);
+                    variableTabStops = stops;
                 }
             }
 
-            if (paraEnd != here && mLineCount < mMaximumVisibleLineCount) {
-                if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) {
-                    paint.getFontMetricsInt(fm);
+            nGetWidths(b.mNativePtr, widths);
+            int breakCount = nComputeLineBreaks(b.mNativePtr, paraEnd - paraStart, firstWidth,
+                    firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
+                    lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
 
-                    fitTop = fm.top;
-                    fitBottom = fm.bottom;
-                    fitAscent = fm.ascent;
-                    fitDescent = fm.descent;
+            int[] breaks = lineBreaks.breaks;
+            float[] lineWidths = lineBreaks.widths;
+            boolean[] flags = lineBreaks.flags;
+
+            // here is the offset of the starting character of the line we are currently measuring
+            int here = paraStart;
+
+            int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
+            int fmCacheIndex = 0;
+            int spanEndCacheIndex = 0;
+            int breakIndex = 0;
+            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+                // retrieve end of span
+                spanEnd = spanEndCache[spanEndCacheIndex++];
+
+                // retrieve cached metrics, order matches above
+                fm.top = fmCache[fmCacheIndex * 4 + 0];
+                fm.bottom = fmCache[fmCacheIndex * 4 + 1];
+                fm.ascent = fmCache[fmCacheIndex * 4 + 2];
+                fm.descent = fmCache[fmCacheIndex * 4 + 3];
+                fmCacheIndex++;
+
+                if (fm.top < fmTop) {
+                    fmTop = fm.top;
+                }
+                if (fm.ascent < fmAscent) {
+                    fmAscent = fm.ascent;
+                }
+                if (fm.descent > fmDescent) {
+                    fmDescent = fm.descent;
+                }
+                if (fm.bottom > fmBottom) {
+                    fmBottom = fm.bottom;
                 }
 
-                // Log.e("text", "output rest " + here + " to " + end);
+                // skip breaks ending before current span range
+                while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
+                    breakIndex++;
+                }
 
-                v = out(source,
-                        here, paraEnd, fitAscent, fitDescent,
-                        fitTop, fitBottom,
-                        v,
-                        spacingmult, spacingadd, chooseHt,
-                        chooseHtv, fm, hasTabOrEmoji,
-                        needMultiply, chdirs, dir, easy, bufEnd,
-                        includepad, trackpad, chs,
-                        widths, paraStart, ellipsize,
-                        ellipsizedWidth, w, paint, paraEnd != bufEnd);
+                while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
+                    int endPos = paraStart + breaks[breakIndex];
+
+                    boolean moreChars = (endPos < bufEnd);
+
+                    v = out(source, here, endPos,
+                            fmAscent, fmDescent, fmTop, fmBottom,
+                            v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex],
+                            needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
+                            chs, widths, paraStart, ellipsize, ellipsizedWidth,
+                            lineWidths[breakIndex], paint, moreChars);
+
+                    if (endPos < spanEnd) {
+                        // preserve metrics for current span
+                        fmTop = fm.top;
+                        fmBottom = fm.bottom;
+                        fmAscent = fm.ascent;
+                        fmDescent = fm.descent;
+                    } else {
+                        fmTop = fmBottom = fmAscent = fmDescent = 0;
+                    }
+
+                    here = endPos;
+                    breakIndex++;
+
+                    if (mLineCount >= mMaximumVisibleLineCount) {
+                        return;
+                    }
+                }
             }
 
-            paraStart = paraEnd;
-
             if (paraEnd == bufEnd)
                 break;
         }
@@ -488,7 +604,7 @@
                 mLineCount < mMaximumVisibleLineCount) {
             // Log.e("text", "output last " + bufEnd);
 
-            measured.setPara(source, bufStart, bufEnd, textDir);
+            measured.setPara(source, bufEnd, bufEnd, textDir, b);
 
             paint.getFontMetricsInt(fm);
 
@@ -845,18 +961,32 @@
         return mEllipsizedWidth;
     }
 
-    void prepare() {
-        mMeasured = MeasuredText.obtain();
-    }
+    private static native long nNewBuilder();
+    private static native void nFreeBuilder(long nativePtr);
+    private static native void nFinishBuilder(long nativePtr);
+    private static native void nSetLocale(long nativePtr, String locale);
 
-    void finish() {
-        mMeasured = MeasuredText.recycle(mMeasured);
-    }
+    private static native void nSetText(long nativePtr, char[] text, int length);
 
-    // returns an array with terminal sentinel value -1 to indicate end
-    // this is so that arrays can be recycled instead of allocating new arrays
-    // every time
-    private static native int[] nLineBreakOpportunities(String locale, char[] text, int length, int[] recycle);
+    private static native float nAddStyleRun(long nativePtr, long nativePaint,
+            long nativeTypeface, int start, int end, boolean isRtl);
+
+    private static native void nAddMeasuredRun(long nativePtr,
+            int start, int end, float[] widths);
+
+    private static native void nAddReplacementRun(long nativePtr, int start, int end, float width);
+
+    private static native void nGetWidths(long nativePtr, float[] widths);
+
+    // populates LineBreaks and returns the number of breaks found
+    //
+    // the arrays inside the LineBreaks objects are passed in as well
+    // to reduce the number of JNI calls in the common case where the
+    // arrays do not have to be resized
+    private static native int nComputeLineBreaks(long nativePtr,
+            int length, float firstWidth, int firstWidthLineCount, float restWidth,
+            int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+            int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
 
     private int mLineCount;
     private int mTopPadding, mBottomPadding;
@@ -884,18 +1014,17 @@
     private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
 
     private static final char CHAR_NEW_LINE = '\n';
-    private static final char CHAR_TAB = '\t';
-    private static final char CHAR_SPACE = ' ';
-    private static final char CHAR_ZWSP = '\u200B';
 
     private static final double EXTRA_ROUNDING = 0.5;
 
-    private static final int CHAR_FIRST_HIGH_SURROGATE = 0xD800;
-    private static final int CHAR_LAST_LOW_SURROGATE = 0xDFFF;
+    // This is used to return three arrays from a single JNI call when
+    // performing line breaking
+    /*package*/ static class LineBreaks {
+        private static final int INITIAL_SIZE = 16;
+        public int[] breaks = new int[INITIAL_SIZE];
+        public float[] widths = new float[INITIAL_SIZE];
+        public boolean[] flags = new boolean[INITIAL_SIZE]; // hasTabOrEmoji
+        // breaks, widths, and flags should all have the same length
+    }
 
-    /*
-     * This is reused across calls to generate()
-     */
-    private MeasuredText mMeasured;
-    private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 }
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index 0447117..4f8cff0 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.ColorInt;
 import android.graphics.Paint;
 
 /**
@@ -25,8 +26,10 @@
 public class TextPaint extends Paint {
 
     // Special value 0 means no background paint
+    @ColorInt
     public int bgColor;
     public int baselineShift;
+    @ColorInt
     public int linkColor;
     public int[] drawableState;
     public float density = 1.0f;
@@ -34,6 +37,7 @@
      * Special value 0 means no custom underline
      * @hide
      */
+    @ColorInt
     public int underlineColor = 0;
     /**
      * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 48bb5dd..676986d 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -457,7 +458,7 @@
      * @param str the string to be examined
      * @return true if str is null or zero length
      */
-    public static boolean isEmpty(CharSequence str) {
+    public static boolean isEmpty(@Nullable CharSequence str) {
         if (str == null || str.length() == 0)
             return true;
         else
@@ -1258,7 +1259,7 @@
                     }
 
                     // XXX this is probably ok, but need to look at it more
-                    tempMt.setPara(format, 0, format.length(), textDir);
+                    tempMt.setPara(format, 0, format.length(), textDir, null);
                     float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
 
                     if (w + moreWid <= avail) {
@@ -1280,7 +1281,7 @@
     private static float setPara(MeasuredText mt, TextPaint paint,
             CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
 
-        mt.setPara(text, start, end, textDir);
+        mt.setPara(text, start, end, textDir, null);
 
         float width;
         Spanned sp = text instanceof Spanned ? (Spanned) text : null;
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 72bbb2b..3ed37b36 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -23,8 +23,6 @@
 import android.text.Spanned;
 import android.text.SpannedString;
 
-import com.android.internal.R;
-
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
@@ -278,73 +276,18 @@
      */
     public static String getTimeFormatString(Context context, int userHandle) {
         LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        return is24HourFormat(context, userHandle) ? d.timeFormat24 : d.timeFormat12;
+        return is24HourFormat(context, userHandle) ? d.timeFormat_Hm : d.timeFormat_hm;
     }
 
     /**
      * Returns a {@link java.text.DateFormat} object that can format the date
-     * in short form (such as 12/31/1999) according
-     * to the current locale and the user's date-order preference.
+     * in short form according to the current locale.
+     *
      * @param context the application context
      * @return the {@link java.text.DateFormat} object that properly formats the date.
      */
     public static java.text.DateFormat getDateFormat(Context context) {
-        String value = Settings.System.getString(context.getContentResolver(),
-                Settings.System.DATE_FORMAT);
-
-        return getDateFormatForSetting(context, value);
-    }
-
-    /**
-     * Returns a {@link java.text.DateFormat} object to format the date
-     * as if the date format setting were set to <code>value</code>,
-     * including null to use the locale's default format.
-     * @param context the application context
-     * @param value the date format setting string to interpret for
-     *              the current locale
-     * @hide
-     */
-    public static java.text.DateFormat getDateFormatForSetting(Context context,
-                                                               String value) {
-        String format = getDateFormatStringForSetting(context, value);
-        return new java.text.SimpleDateFormat(format);
-    }
-
-    private static String getDateFormatStringForSetting(Context context, String value) {
-        if (value != null) {
-            int month = value.indexOf('M');
-            int day = value.indexOf('d');
-            int year = value.indexOf('y');
-
-            if (month >= 0 && day >= 0 && year >= 0) {
-                String template = context.getString(R.string.numeric_date_template);
-                if (year < month && year < day) {
-                    if (month < day) {
-                        value = String.format(template, "yyyy", "MM", "dd");
-                    } else {
-                        value = String.format(template, "yyyy", "dd", "MM");
-                    }
-                } else if (month < day) {
-                    if (day < year) {
-                        value = String.format(template, "MM", "dd", "yyyy");
-                    } else { // unlikely
-                        value = String.format(template, "MM", "yyyy", "dd");
-                    }
-                } else { // day < month
-                    if (month < year) {
-                        value = String.format(template, "dd", "MM", "yyyy");
-                    } else { // unlikely
-                        value = String.format(template, "dd", "yyyy", "MM");
-                    }
-                }
-
-                return value;
-            }
-        }
-
-        // The setting is not set; use the locale's default.
-        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        return d.shortDateFormat4;
+        return java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT);
     }
 
     /**
@@ -377,14 +320,16 @@
      * order returned here.
      */
     public static char[] getDateFormatOrder(Context context) {
-        return ICU.getDateFormatOrder(getDateFormatString(context));
+        return ICU.getDateFormatOrder(getDateFormatString());
     }
 
-    private static String getDateFormatString(Context context) {
-        String value = Settings.System.getString(context.getContentResolver(),
-                Settings.System.DATE_FORMAT);
+    private static String getDateFormatString() {
+        java.text.DateFormat df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT);
+        if (df instanceof SimpleDateFormat) {
+            return ((SimpleDateFormat) df).toPattern();
+        }
 
-        return getDateFormatStringForSetting(context, value);
+        throw new AssertionError("!(df instanceof SimpleDateFormat)");
     }
 
     /**
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index d0ed871..ac98e8a 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -28,9 +28,11 @@
 import java.util.Formatter;
 import java.util.GregorianCalendar;
 import java.util.Locale;
+import java.util.TimeZone;
 
 import libcore.icu.DateIntervalFormat;
 import libcore.icu.LocaleData;
+import libcore.icu.RelativeDateTimeFormatter;
 
 /**
  * This class contains various date-related utilities for creating text for things like
@@ -242,6 +244,8 @@
 
     /**
      * Returns a string describing the elapsed time since startTime.
+     * <p>
+     * The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}.
      * @param startTime some time in the past.
      * @return a String object containing the elapsed time.
      * @see #getRelativeTimeSpanString(long, long, long)
@@ -289,69 +293,8 @@
      */
     public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
             int flags) {
-        Resources r = Resources.getSystem();
-        boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;
-
-        boolean past = (now >= time);
-        long duration = Math.abs(now - time);
-
-        int resId;
-        long count;
-        if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
-            count = duration / SECOND_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_seconds_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_seconds_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_seconds;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_seconds;
-                }
-            }
-        } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
-            count = duration / MINUTE_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_minutes_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_minutes_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_minutes;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_minutes;
-                }
-            }
-        } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
-            count = duration / HOUR_IN_MILLIS;
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_hours_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_hours_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_hours;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_hours;
-                }
-            }
-        } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
-            return getRelativeDayString(r, time, now);
-        } else {
-            // We know that we won't be showing the time, so it is safe to pass
-            // in a null context.
-            return formatDateRange(null, time, time, flags);
-        }
-
-        String format = r.getQuantityString(resId, (int) count);
-        return String.format(format, count);
+        return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(),
+                TimeZone.getDefault(), time, now, minResolution, flags);
     }
 
     /**
@@ -360,8 +303,8 @@
      * <p>
      * Example output strings for the US date format.
      * <ul>
-     * <li>3 mins ago, 10:15 AM</li>
-     * <li>yesterday, 12:20 PM</li>
+     * <li>3 min. ago, 10:15 AM</li>
+     * <li>Yesterday, 12:20 PM</li>
      * <li>Dec 12, 4:12 AM</li>
      * <li>11/14/2007, 8:20 AM</li>
      * </ul>
@@ -374,86 +317,19 @@
      * @param transitionResolution the elapsed time (in milliseconds) at which
      *            to stop reporting relative measurements. Elapsed times greater
      *            than this resolution will default to normal date formatting.
-     *            For example, will transition from "6 days ago" to "Dec 12"
+     *            For example, will transition from "7 days ago" to "Dec 12"
      *            when using {@link #WEEK_IN_MILLIS}.
      */
     public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
             long transitionResolution, int flags) {
-        Resources r = Resources.getSystem();
-
-        long now = System.currentTimeMillis();
-        long duration = Math.abs(now - time);
-
-        // getRelativeTimeSpanString() doesn't correctly format relative dates
-        // above a week or exact dates below a day, so clamp
-        // transitionResolution as needed.
-        if (transitionResolution > WEEK_IN_MILLIS) {
-            transitionResolution = WEEK_IN_MILLIS;
-        } else if (transitionResolution < DAY_IN_MILLIS) {
-            transitionResolution = DAY_IN_MILLIS;
+        // Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format.
+        if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
+            flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR;
         }
 
-        CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);
-
-        String result;
-        if (duration < transitionResolution) {
-            CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
-            result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause);
-        } else {
-            CharSequence dateClause = getRelativeTimeSpanString(c, time, false);
-            result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause);
-        }
-
-        return result;
-    }
-
-    /**
-     * Returns a string describing a day relative to the current day. For example if the day is
-     * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
-     * if the day is in 2 weeks it returns "in 14 days".
-     *
-     * @param r the resources
-     * @param day the relative day to describe in UTC milliseconds
-     * @param today the current time in UTC milliseconds
-     */
-    private static final String getRelativeDayString(Resources r, long day, long today) {
-        Locale locale = r.getConfiguration().locale;
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
-
-        // TODO: use TimeZone.getOffset instead.
-        Time startTime = new Time();
-        startTime.set(day);
-        int startDay = Time.getJulianDay(day, startTime.gmtoff);
-
-        Time currentTime = new Time();
-        currentTime.set(today);
-        int currentDay = Time.getJulianDay(today, currentTime.gmtoff);
-
-        int days = Math.abs(currentDay - startDay);
-        boolean past = (today > day);
-
-        // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
-        if (days == 1) {
-            if (past) {
-                return LocaleData.get(locale).yesterday;
-            } else {
-                return LocaleData.get(locale).tomorrow;
-            }
-        } else if (days == 0) {
-            return LocaleData.get(locale).today;
-        }
-
-        int resId;
-        if (past) {
-            resId = com.android.internal.R.plurals.num_days_ago;
-        } else {
-            resId = com.android.internal.R.plurals.in_num_days;
-        }
-
-        String format = r.getQuantityString(resId, days);
-        return String.format(format, days);
+        return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(),
+                TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution,
+                transitionResolution, flags);
     }
 
     private static void initFormatStrings() {
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 1e04eb4..0c66709 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -215,13 +215,15 @@
      * <p>
      * If "ignoreDst" is true, then this method sets the "isDst" field to -1
      * (the "unknown" value) before normalizing.  It then computes the
-     * correct value for "isDst".
+     * time in milliseconds and sets the correct value for "isDst" if the
+     * fields resolve to a valid date / time.
      *
      * <p>
      * See {@link #toMillis(boolean)} for more information about when to
-     * use <tt>true</tt> or <tt>false</tt> for "ignoreDst".
+     * use <tt>true</tt> or <tt>false</tt> for "ignoreDst" and when {@code -1}
+     * might be returned.
      *
-     * @return the UTC milliseconds since the epoch
+     * @return the UTC milliseconds since the epoch, or {@code -1}
      */
     public long normalize(boolean ignoreDst) {
         calculator.copyFieldsFromTime(this);
@@ -317,6 +319,11 @@
      * a} is less than {@code b}, a positive number if {@code a} is greater than
      * {@code b}, or 0 if they are equal.
      *
+     * <p>
+     * This method can return an incorrect answer when the date / time fields of
+     * either {@code Time} have been set to a local time that contradicts the
+     * available timezone information.
+     *
      * @param a first {@code Time} instance to compare
      * @param b second {@code Time} instance to compare
      * @throws NullPointerException if either argument is {@code null}
@@ -730,6 +737,14 @@
      * <p>
      * You should also use <tt>toMillis(false)</tt> if you want
      * to read back the same milliseconds that you set with {@link #set(long)}
+     *
+     * <p>
+     * This method can return {@code -1} when the date / time fields have been
+     * set to a local time that conflicts with available timezone information.
+     * For example, when daylight savings transitions cause an hour to be
+     * skipped: times within that hour will return {@code -1} if isDst =
+     * {@code -1}.
+     *
      * or {@link #set(Time)} or after parsing a date string.
      */
     public long toMillis(boolean ignoreDst) {
@@ -825,6 +840,10 @@
      * Returns true if the time represented by this Time object occurs before
      * the given time.
      *
+     * <p>
+     * Equivalent to {@code Time.compare(this, that) &lt; 0}. See
+     * {@link #compare(Time, Time)} for details.
+     *
      * @param that a given Time object to compare against
      * @return true if this time is less than the given time
      */
@@ -837,6 +856,10 @@
      * Returns true if the time represented by this Time object occurs after
      * the given time.
      *
+     * <p>
+     * Equivalent to {@code Time.compare(this, that) &gt; 0}. See
+     * {@link #compare(Time, Time)} for details.
+     *
      * @param that a given Time object to compare against
      * @return true if this time is greater than the given time
      */
@@ -917,6 +940,10 @@
      * Returns true if the day of the given time is the epoch on the Julian Calendar
      * (January 1, 1970 on the Gregorian calendar).
      *
+     * <p>
+     * This method can return an incorrect answer when the date / time fields have
+     * been set to a local time that contradicts the available timezone information.
+     *
      * @param time the time to test
      * @return true if epoch.
      */
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index c9e09bd..f167aab 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
@@ -26,7 +27,7 @@
 
     private final int mColor;
 
-    public ForegroundColorSpan(int color) {
+    public ForegroundColorSpan(@ColorInt int color) {
         mColor = color;
     }
 
@@ -46,6 +47,7 @@
         dest.writeInt(mColor);
     }
 
+    @ColorInt
     public int getForegroundColor() {
         return mColor;
     }
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 3d6f8e6..856dd0b 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.DrawableRes;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -110,7 +111,7 @@
         mSource = uri.toString();
     }
 
-    public ImageSpan(Context context, int resourceId) {
+    public ImageSpan(Context context, @DrawableRes int resourceId) {
         this(context, resourceId, ALIGN_BOTTOM);
     }
 
@@ -118,7 +119,7 @@
      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
      * {@link DynamicDrawableSpan#ALIGN_BASELINE}.
      */
-    public ImageSpan(Context context, int resourceId, int verticalAlignment) {
+    public ImageSpan(Context context, @DrawableRes int resourceId, int verticalAlignment) {
         super(verticalAlignment);
         mContext = context;
         mResourceId = resourceId;
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 29dd273..17748ca 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.graphics.Paint;
 import android.graphics.Canvas;
 import android.os.Parcel;
@@ -34,7 +35,7 @@
         mColor = 0xff0000ff;
     }
     
-    public QuoteSpan(int color) {
+    public QuoteSpan(@ColorInt int color) {
         super();
         mColor = color;
     }
@@ -55,6 +56,7 @@
         dest.writeInt(mColor);
     }
 
+    @ColorInt
     public int getColor() {
         return mColor;
     }
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..8e9eb48 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -78,7 +78,10 @@
 
     /**
      *  Bit field indicating that street addresses should be matched in methods that
-     *  take an options mask
+     *  take an options mask. Note that this uses the
+     *  {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+     *  {@link android.webkit.WebView} for finding addresses, which has various
+     *  limitations.
      */
     public static final int MAP_ADDRESSES = 0x08;
 
diff --git a/core/java/android/text/util/Rfc822Token.java b/core/java/android/text/util/Rfc822Token.java
index 0edeeb5..058757a 100644
--- a/core/java/android/text/util/Rfc822Token.java
+++ b/core/java/android/text/util/Rfc822Token.java
@@ -16,18 +16,21 @@
 
 package android.text.util;
 
+import android.annotation.Nullable;
+
 /**
  * This class stores an RFC 822-like name, address, and comment,
  * and provides methods to convert them to quoted strings.
  */
 public class Rfc822Token {
+    @Nullable
     private String mName, mAddress, mComment;
 
     /**
      * Creates a new Rfc822Token with the specified name, address,
      * and comment.
      */
-    public Rfc822Token(String name, String address, String comment) {
+    public Rfc822Token(@Nullable String name, @Nullable String address, @Nullable String comment) {
         mName = name;
         mAddress = address;
         mComment = comment;
@@ -36,6 +39,7 @@
     /**
      * Returns the name part.
      */
+    @Nullable
     public String getName() {
         return mName;
     }
@@ -43,6 +47,7 @@
     /**
      * Returns the address part.
      */
+    @Nullable
     public String getAddress() {
         return mAddress;
     }
@@ -50,6 +55,7 @@
     /**
      * Returns the comment part.
      */
+    @Nullable
     public String getComment() {
         return mComment;
     }
@@ -57,21 +63,21 @@
     /**
      * Changes the name to the specified name.
      */
-    public void setName(String name) {
+    public void setName(@Nullable String name) {
         mName = name;
     }
 
     /**
      * Changes the address to the specified address.
      */
-    public void setAddress(String address) {
+    public void setAddress(@Nullable String address) {
         mAddress = address;
     }
 
     /**
      * Changes the comment to the specified comment.
      */
-    public void setComment(String comment) {
+    public void setComment(@Nullable String comment) {
         mComment = comment;
     }
 
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index f95fb49..70dfe7f 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -21,7 +21,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Path;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 
 /**
  * A PathMotion that generates a curved path along an arc on an imaginary circle containing
@@ -257,7 +256,7 @@
             }
             if (newArcDistance2 != 0) {
                 float ratio2 = newArcDistance2 / arcDist2;
-                float ratio = FloatMath.sqrt(ratio2);
+                float ratio = (float) Math.sqrt(ratio2);
                 ex = dx + (ratio * (ex - dx));
                 ey = dy + (ratio * (ey - dy));
             }
diff --git a/core/java/android/transition/ChangeScroll.java b/core/java/android/transition/ChangeScroll.java
index 39291bf..5a78b94 100644
--- a/core/java/android/transition/ChangeScroll.java
+++ b/core/java/android/transition/ChangeScroll.java
@@ -28,8 +28,6 @@
 /**
  * This transition captures the scroll properties of targets before and after
  * the scene change and animates any changes.
- *
- * @hide
  */
 public class ChangeScroll extends Transition {
 
diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java
index 51beb51..c9faa0f 100644
--- a/core/java/android/transition/CircularPropagation.java
+++ b/core/java/android/transition/CircularPropagation.java
@@ -16,8 +16,6 @@
 package android.transition;
 
 import android.graphics.Rect;
-import android.util.FloatMath;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -87,9 +85,9 @@
             epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2)
                     + sceneRoot.getTranslationY());
         }
-        float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
-        float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
-        float distanceFraction = distance/maxDistance;
+        double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
+        double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
+        double distanceFraction = distance/maxDistance;
 
         long duration = transition.getDuration();
         if (duration < 0) {
@@ -99,9 +97,9 @@
         return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
     }
 
-    private static float distance(float x1, float y1, float x2, float y2) {
-        float x = x2 - x1;
-        float y = y2 - y1;
-        return FloatMath.sqrt((x * x) + (y * y));
+    private static double distance(float x1, float y1, float x2, float y2) {
+        double x = x2 - x1;
+        double y = y2 - y1;
+        return Math.hypot(x, y);
     }
 }
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java
index 0ccdf15..788676a 100644
--- a/core/java/android/transition/Explode.java
+++ b/core/java/android/transition/Explode.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
@@ -143,32 +142,29 @@
 
         int centerX = bounds.centerX();
         int centerY = bounds.centerY();
-        float xVector = centerX - focalX;
-        float yVector = centerY - focalY;
+        double xVector = centerX - focalX;
+        double yVector = centerY - focalY;
 
         if (xVector == 0 && yVector == 0) {
             // Random direction when View is centered on focal View.
-            xVector = (float) (Math.random() * 2) - 1;
-            yVector = (float) (Math.random() * 2) - 1;
+            xVector = (Math.random() * 2) - 1;
+            yVector = (Math.random() * 2) - 1;
         }
-        float vectorSize = calculateDistance(xVector, yVector);
+        double vectorSize = Math.hypot(xVector, yVector);
         xVector /= vectorSize;
         yVector /= vectorSize;
 
-        float maxDistance =
+        double maxDistance =
                 calculateMaxDistance(sceneRoot, focalX - sceneRootX, focalY - sceneRootY);
 
-        outVector[0] = Math.round(maxDistance * xVector);
-        outVector[1] = Math.round(maxDistance * yVector);
+        outVector[0] = (int) Math.round(maxDistance * xVector);
+        outVector[1] = (int) Math.round(maxDistance * yVector);
     }
 
-    private static float calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
+    private static double calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
         int maxX = Math.max(focalX, sceneRoot.getWidth() - focalX);
         int maxY = Math.max(focalY, sceneRoot.getHeight() - focalY);
-        return calculateDistance(maxX, maxY);
+        return Math.hypot(maxX, maxY);
     }
 
-    private static float calculateDistance(float x, float y) {
-        return FloatMath.sqrt((x * x) + (y * y));
-    }
 }
diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java
index a609df6..773c387 100644
--- a/core/java/android/transition/PatternPathMotion.java
+++ b/core/java/android/transition/PatternPathMotion.java
@@ -23,7 +23,6 @@
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.util.PathParser;
 
 /**
@@ -119,7 +118,7 @@
         mTempMatrix.setTranslate(-startX, -startY);
         float dx = endX - startX;
         float dy = endY - startY;
-        float distance = distance(dx, dy);
+        float distance = (float) Math.hypot(dx, dy);
         float scale = 1 / distance;
         mTempMatrix.postScale(scale, scale);
         double angle = Math.atan2(dy, dx);
@@ -130,9 +129,9 @@
 
     @Override
     public Path getPath(float startX, float startY, float endX, float endY) {
-        float dx = endX - startX;
-        float dy = endY - startY;
-        float length = distance(dx, dy);
+        double dx = endX - startX;
+        double dy = endY - startY;
+        float length = (float) Math.hypot(dx, dy);
         double angle = Math.atan2(dy, dx);
 
         mTempMatrix.setScale(length, length);
@@ -143,7 +142,4 @@
         return path;
     }
 
-    private static float distance(float x, float y) {
-        return FloatMath.sqrt((x * x) + (y * y));
-    }
 }
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index ad6c2dd..b10f6a0 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,8 +16,6 @@
 package android.transition;
 
 import android.graphics.Rect;
-import android.util.FloatMath;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2705bcf..c942042 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1762,7 +1762,17 @@
         runAnimators();
     }
 
-    boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+    /**
+     * Returns whether transition values have changed between the start scene and the end scene
+     * (thus determining whether animation is required). The default implementation compares the
+     * property values returned from {@link #getTransitionProperties()}, or all property values if
+     * {@code getTransitionProperties()} returns null. Subclasses may override this method to
+     * provide logic more specific to their transition implementation.
+     *
+     * @param oldValues the first set of values, may be {@code null}
+     * @param newValues the second set of values, may be {@code null}
+     */
+    protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
         boolean valuesChanged = false;
         // if oldValues null, then transition didn't care to stash values,
         // and won't get canceled
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 7bd6287..0b70fdb 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -181,24 +181,27 @@
     private static void changeScene(Scene scene, Transition transition) {
 
         final ViewGroup sceneRoot = scene.getSceneRoot();
+        if (!sPendingTransitions.contains(sceneRoot)) {
+            sPendingTransitions.add(sceneRoot);
 
-        Transition transitionClone = null;
-        if (transition != null) {
-            transitionClone = transition.clone();
-            transitionClone.setSceneRoot(sceneRoot);
+            Transition transitionClone = null;
+            if (transition != null) {
+                transitionClone = transition.clone();
+                transitionClone.setSceneRoot(sceneRoot);
+            }
+
+            Scene oldScene = Scene.getCurrentScene(sceneRoot);
+            if (oldScene != null && transitionClone != null &&
+                    oldScene.isCreatedFromLayoutResource()) {
+                transitionClone.setCanRemoveViews(true);
+            }
+
+            sceneChangeSetup(sceneRoot, transitionClone);
+
+            scene.enter();
+
+            sceneChangeRunTransition(sceneRoot, transitionClone);
         }
-
-        Scene oldScene = Scene.getCurrentScene(sceneRoot);
-        if (oldScene != null && transitionClone != null &&
-                oldScene.isCreatedFromLayoutResource()) {
-            transitionClone.setCanRemoveViews(true);
-        }
-
-        sceneChangeSetup(sceneRoot, transitionClone);
-
-        scene.enter();
-
-        sceneChangeRunTransition(sceneRoot, transitionClone);
     }
 
     private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
@@ -268,7 +271,12 @@
         @Override
         public boolean onPreDraw() {
             removeListeners();
-            sPendingTransitions.remove(mSceneRoot);
+
+            // Don't start the transition if it's no longer pending.
+            if (!sPendingTransitions.remove(mSceneRoot)) {
+                return true;
+            }
+
             // Add to running list, handle end to remove it
             final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
                     getRunningTransitions();
@@ -417,4 +425,24 @@
             sceneChangeRunTransition(sceneRoot, transitionClone);
         }
     }
+
+    /**
+     * Ends all pending and ongoing transitions on the specified scene root.
+     *
+     * @param sceneRoot The root of the View hierarchy to end transitions on.
+     * @hide
+     */
+    public static void endTransitions(final ViewGroup sceneRoot) {
+        sPendingTransitions.remove(sceneRoot);
+
+        final ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
+        if (runningTransitions != null) {
+            final int count = runningTransitions.size();
+            for (int i = 0; i < count; i++) {
+                final Transition transition = runningTransitions.get(i);
+                transition.end();
+            }
+        }
+
+    }
 }
diff --git a/core/java/android/transition/TransitionPropagation.java b/core/java/android/transition/TransitionPropagation.java
index 9a481c2..b831038 100644
--- a/core/java/android/transition/TransitionPropagation.java
+++ b/core/java/android/transition/TransitionPropagation.java
@@ -15,7 +15,6 @@
  */
 package android.transition;
 
-import android.graphics.Rect;
 import android.view.ViewGroup;
 
 /**
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 8779229..cd68fd1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -22,9 +22,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -182,7 +179,7 @@
         return visibility == View.VISIBLE && parent != null;
     }
 
-    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
+    private static VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
             TransitionValues endValues) {
         final VisibilityInfo visInfo = new VisibilityInfo();
         visInfo.visibilityChange = false;
@@ -484,7 +481,7 @@
     }
 
     @Override
-    boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+    protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
         if (oldValues == null && newValues == null) {
             return false;
         }
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 68f725e..7da3941 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -475,6 +475,26 @@
     }
 
     /**
+     * Perform a {@link #remove(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be removed.
+     */
+    public boolean removeAll(ArraySet<? extends E> array) {
+        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+        //       pass, use the property that the sets are sorted by hash to make this linear passes
+        //       (except for hash collisions, which means worst case still n*m), then do one
+        //       collection pass into a new array. This avoids binary searches and excessive memcpy.
+        final int N = array.mSize;
+
+        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+        //       the single results, compare size before and after.
+        final int originalSize = mSize;
+        for (int i = 0; i < N; i++) {
+            remove(array.valueAt(i));
+        }
+        return originalSize != mSize;
+    }
+
+    /**
      * Return the number of items in this array map.
      */
     @Override
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index a6466fc..3aa3447 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -102,7 +102,7 @@
             str = new FileOutputStream(mBaseName);
         } catch (FileNotFoundException e) {
             File parent = mBaseName.getParentFile();
-            if (!parent.mkdir()) {
+            if (!parent.mkdirs()) {
                 throw new IOException("Couldn't create directory " + mBaseName);
             }
             FileUtils.setPermissions(
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 74942ba..eb8c168 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -39,7 +39,7 @@
  * is more useful in conjunction with compiled XML resources:
  * 
  * <pre>
- * XmlPullParser parser = resources.getXml(myResouce);
+ * XmlPullParser parser = resources.getXml(myResource);
  * AttributeSet attributes = Xml.asAttributeSet(parser);</pre>
  * 
  * <p>The implementation returned here, unlike using
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index f607207..84d9ce8 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -16,6 +16,7 @@
 
 package android.util;
 
+import java.io.PrintWriter;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Locale;
@@ -123,4 +124,83 @@
         }
     }
 
+    /** @hide */
+    public static void printSizeValue(PrintWriter pw, long number) {
+        float result = number;
+        String suffix = "";
+        if (result > 900) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            value = String.format("%.1f", result);
+        } else if (result < 100) {
+            value = String.format("%.0f", result);
+        } else {
+            value = String.format("%.0f", result);
+        }
+        pw.print(value);
+        pw.print(suffix);
+    }
+
+    /** @hide */
+    public static String sizeValueToString(long number, StringBuilder outBuilder) {
+        if (outBuilder == null) {
+            outBuilder = new StringBuilder(32);
+        }
+        float result = number;
+        String suffix = "";
+        if (result > 900) {
+            suffix = "KB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "MB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "GB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "TB";
+            result = result / 1024;
+        }
+        if (result > 900) {
+            suffix = "PB";
+            result = result / 1024;
+        }
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            value = String.format("%.1f", result);
+        } else if (result < 100) {
+            value = String.format("%.0f", result);
+        } else {
+            value = String.format("%.0f", result);
+        }
+        outBuilder.append(value);
+        outBuilder.append(suffix);
+        return outBuilder.toString();
+    }
 }
diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java
index bdcf5ca..8f488af 100644
--- a/core/java/android/util/FloatMath.java
+++ b/core/java/android/util/FloatMath.java
@@ -17,10 +17,13 @@
 package android.util;
 
 /**
- * Math routines similar to those found in {@link java.lang.Math}. On
- * versions of Android with a JIT, these are significantly slower than
- * the equivalent {@code Math} functions, which should be used in preference
- * to these.
+ * Math routines similar to those found in {@link java.lang.Math}.
+ *
+ * <p>Historically these methods were faster than the equivalent double-based
+ * {@link java.lang.Math} methods. On versions of Android with a JIT they
+ * became slower and have since been re-implemented to wrap calls to
+ * {@link java.lang.Math}. {@link java.lang.Math} should be used in
+ * preference.
  *
  * @deprecated Use {@link java.lang.Math} instead.
  */
@@ -37,7 +40,9 @@
      * @param value to be converted
      * @return the floor of value
      */
-    public static native float floor(float value);
+    public static float floor(float value) {
+        return (float) Math.floor(value);
+    }
 
     /**
      * Returns the float conversion of the most negative (i.e. closest to
@@ -46,7 +51,9 @@
      * @param value to be converted
      * @return the ceiling of value
      */
-    public static native float ceil(float value);
+    public static float ceil(float value) {
+        return (float) Math.ceil(value);
+    }
 
     /**
      * Returns the closest float approximation of the sine of the argument.
@@ -54,7 +61,9 @@
      * @param angle to compute the cosine of, in radians
      * @return the sine of angle
      */
-    public static native float sin(float angle);
+    public static float sin(float angle) {
+        return (float) Math.sin(angle);
+    }
 
     /**
      * Returns the closest float approximation of the cosine of the argument.
@@ -62,7 +71,9 @@
      * @param angle to compute the cosine of, in radians
      * @return the cosine of angle
      */
-    public static native float cos(float angle);
+    public static float cos(float angle) {
+        return (float) Math.cos(angle);
+    }
 
     /**
      * Returns the closest float approximation of the square root of the
@@ -71,7 +82,9 @@
      * @param value to compute sqrt of
      * @return the square root of value
      */
-    public static native float sqrt(float value);
+    public static float sqrt(float value) {
+        return (float) Math.sqrt(value);
+    }
 
     /**
      * Returns the closest float approximation of the raising "e" to the power
@@ -80,7 +93,9 @@
      * @param value to compute the exponential of
      * @return the exponential of value
      */
-    public static native float exp(float value);
+    public static float exp(float value) {
+        return (float) Math.exp(value);
+    }
 
     /**
      * Returns the closest float approximation of the result of raising {@code
@@ -90,7 +105,9 @@
      * @param y the exponent of the operation.
      * @return {@code x} to the power of {@code y}.
      */
-    public static native float pow(float x, float y);
+    public static float pow(float x, float y) {
+        return (float) Math.pow(x, y);
+    }
 
     /**
      * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
@@ -100,5 +117,7 @@
      * @param y a float number
      * @return the hypotenuse
      */
-    public static native float hypot(float x, float y);
+    public static float hypot(float x, float y) {
+        return (float) Math.hypot(x, y);
+    }
 }
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index e49b8c3..cab5d19 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -16,8 +16,6 @@
 
 package android.util;
 
-import android.text.format.Time;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Calendar;
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 13a692e..36d5b50 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -94,7 +94,7 @@
     public static float dist(float x1, float y1, float x2, float y2) {
         final float x = (x2 - x1);
         final float y = (y2 - y1);
-        return (float) Math.sqrt(x * x + y * y);
+        return (float) Math.hypot(x, y);
     }
 
     public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) {
@@ -105,7 +105,7 @@
     }
 
     public static float mag(float a, float b) {
-        return (float) Math.sqrt(a * a + b * b);
+        return (float) Math.hypot(a, b);
     }
 
     public static float mag(float a, float b, float c) {
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 8ebcacd..ed2d3c6 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -24,6 +24,7 @@
 import android.net.SntpClient;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.text.TextUtils;
 
 /**
  * {@link TrustedTime} that connects with a remote NTP server as its trusted
@@ -79,7 +80,7 @@
 
     @Override
     public boolean forceRefresh() {
-        if (mServer == null) {
+        if (TextUtils.isEmpty(mServer)) {
             // missing server, so no trusted time available
             return false;
         }
diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java
index 41a2e5d..bed3a60 100644
--- a/core/java/android/util/Spline.java
+++ b/core/java/android/util/Spline.java
@@ -165,7 +165,7 @@
                         throw new IllegalArgumentException("The control points must have "
                                 + "monotonic Y values.");
                     }
-                    float h = FloatMath.hypot(a, b);
+                    float h = (float) Math.hypot(a, b);
                     if (h > 9f) {
                         float t = 3f / h;
                         m[i] = t * a * d[i];
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index 2623638..83dfc47 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -36,7 +36,88 @@
  */
 
 public class StateSet {
-    /** @hide */ public StateSet() {}
+    /**
+     * The order here is very important to
+     * {@link android.view.View#getDrawableState()}
+     */
+    private static final int[][] VIEW_STATE_SETS;
+
+    /** @hide */
+    public static final int VIEW_STATE_WINDOW_FOCUSED = 1;
+    /** @hide */
+    public static final int VIEW_STATE_SELECTED = 1 << 1;
+    /** @hide */
+    public static final int VIEW_STATE_FOCUSED = 1 << 2;
+    /** @hide */
+    public static final int VIEW_STATE_ENABLED = 1 << 3;
+    /** @hide */
+    public static final int VIEW_STATE_PRESSED = 1 << 4;
+    /** @hide */
+    public static final int VIEW_STATE_ACTIVATED = 1 << 5;
+    /** @hide */
+    public static final int VIEW_STATE_ACCELERATED = 1 << 6;
+    /** @hide */
+    public static final int VIEW_STATE_HOVERED = 1 << 7;
+    /** @hide */
+    public static final int VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8;
+    /** @hide */
+    public static final int VIEW_STATE_DRAG_HOVERED = 1 << 9;
+
+    static final int[] VIEW_STATE_IDS = new int[] {
+            R.attr.state_window_focused,    VIEW_STATE_WINDOW_FOCUSED,
+            R.attr.state_selected,          VIEW_STATE_SELECTED,
+            R.attr.state_focused,           VIEW_STATE_FOCUSED,
+            R.attr.state_enabled,           VIEW_STATE_ENABLED,
+            R.attr.state_pressed,           VIEW_STATE_PRESSED,
+            R.attr.state_activated,         VIEW_STATE_ACTIVATED,
+            R.attr.state_accelerated,       VIEW_STATE_ACCELERATED,
+            R.attr.state_hovered,           VIEW_STATE_HOVERED,
+            R.attr.state_drag_can_accept,   VIEW_STATE_DRAG_CAN_ACCEPT,
+            R.attr.state_drag_hovered,      VIEW_STATE_DRAG_HOVERED
+    };
+
+    static {
+        if ((VIEW_STATE_IDS.length / 2) != R.styleable.ViewDrawableStates.length) {
+            throw new IllegalStateException(
+                    "VIEW_STATE_IDs array length does not match ViewDrawableStates style array");
+        }
+
+        final int[] orderedIds = new int[VIEW_STATE_IDS.length];
+        for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) {
+            final int viewState = R.styleable.ViewDrawableStates[i];
+            for (int j = 0; j < VIEW_STATE_IDS.length; j += 2) {
+                if (VIEW_STATE_IDS[j] == viewState) {
+                    orderedIds[i * 2] = viewState;
+                    orderedIds[i * 2 + 1] = VIEW_STATE_IDS[j + 1];
+                }
+            }
+        }
+
+        final int NUM_BITS = VIEW_STATE_IDS.length / 2;
+        VIEW_STATE_SETS = new int[1 << NUM_BITS][];
+        for (int i = 0; i < VIEW_STATE_SETS.length; i++) {
+            final int numBits = Integer.bitCount(i);
+            final int[] set = new int[numBits];
+            int pos = 0;
+            for (int j = 0; j < orderedIds.length; j += 2) {
+                if ((i & orderedIds[j + 1]) != 0) {
+                    set[pos++] = orderedIds[j];
+                }
+            }
+            VIEW_STATE_SETS[i] = set;
+        }
+    }
+
+    /** @hide */
+    public static int[] get(int mask) {
+        if (mask >= VIEW_STATE_SETS.length) {
+            throw new IllegalArgumentException("Invalid state set mask");
+        }
+        return VIEW_STATE_SETS[mask];
+    }
+
+    /** @hide */
+    public StateSet() {}
 
     public static final int[] WILD_CARD = new int[0];
     public static final int[] NOTHING = new int[] { 0 };
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 74d4245..98aaa81 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.annotation.AnyRes;
+
 /**
  * Container for a dynamically typed data value.  Primarily used with
  * {@link android.content.res.Resources} for holding resource values.
@@ -178,6 +180,7 @@
     public int assetCookie;
 
     /** If Value came from a resource, this holds the corresponding resource id. */
+    @AnyRes
     public int resourceId;
 
     /** If Value came from a resource, these are the configurations for which
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index a359952..a018138 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -17,6 +17,8 @@
 package android.view;
 
 
+import android.annotation.StringRes;
+
 /**
  * Represents a contextual mode of the user interface. Action modes can be used to provide
  * alternative interaction modes and replace parts of the normal UI until finished.
@@ -29,8 +31,21 @@
  * </div>
  */
 public abstract class ActionMode {
+
+    /**
+     * The action mode is treated as a Primary mode. This is the default.
+     * Use with {@link #setType}.
+     */
+    public static final int TYPE_PRIMARY = 0;
+    /**
+     * The action mode is treated as a Floating Toolbar.
+     * Use with {@link #setType}.
+     */
+    public static final int TYPE_FLOATING = 1;
+
     private Object mTag;
     private boolean mTitleOptionalHint;
+    private int mType = TYPE_PRIMARY;
 
     /**
      * Set a tag object associated with this ActionMode.
@@ -80,7 +95,7 @@
      * @see #setTitle(CharSequence)
      * @see #setCustomView(View)
      */
-    public abstract void setTitle(int resId);
+    public abstract void setTitle(@StringRes int resId);
 
     /**
      * Set the subtitle of the action mode. This method will have no visible effect if
@@ -102,7 +117,7 @@
      * @see #setSubtitle(CharSequence)
      * @see #setCustomView(View)
      */
-    public abstract void setSubtitle(int resId);
+    public abstract void setSubtitle(@StringRes int resId);
 
     /**
      * Set whether or not the title/subtitle display for this action mode
@@ -154,6 +169,25 @@
     public abstract void setCustomView(View view);
 
     /**
+     * Set a type for this action mode. This will affect how the system renders the action mode if
+     * it has to.
+     *
+     * @param type One of {@link #TYPE_PRIMARY} or {@link #TYPE_FLOATING}.
+     */
+    public void setType(int type) {
+        mType = type;
+    }
+
+    /**
+     * Returns the type for this action mode.
+     *
+     * @return One of {@link #TYPE_PRIMARY} or {@link #TYPE_FLOATING}.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
      * Invalidate the action mode and refresh menu content. The mode's
      * {@link ActionMode.Callback} will have its
      * {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called.
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f41afcf..c8149d9 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -141,6 +141,19 @@
     private long mFrameIntervalNanos;
 
     /**
+     * Contains information about the current frame for jank-tracking,
+     * mainly timings of key events along with a bit of metadata about
+     * view tree state
+     *
+     * TODO: Is there a better home for this? Currently Choreographer
+     * is the only one with CALLBACK_ANIMATION start time, hence why this
+     * resides here.
+     *
+     * @hide
+     */
+    FrameInfo mFrameInfo = new FrameInfo();
+
+    /**
      * Callback type: Input callback.  Runs first.
      * @hide
      */
@@ -513,6 +526,7 @@
                 return; // no work to do
             }
 
+            long intendedFrameTimeNanos = frameTimeNanos;
             startNanos = System.nanoTime();
             final long jitterNanos = startNanos - frameTimeNanos;
             if (jitterNanos >= mFrameIntervalNanos) {
@@ -541,12 +555,18 @@
                 return;
             }
 
+            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
             mFrameScheduled = false;
             mLastFrameTimeNanos = frameTimeNanos;
         }
 
+        mFrameInfo.markInputHandlingStart();
         doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+
+        mFrameInfo.markAnimationsStart();
         doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+
+        mFrameInfo.markPerformTraversalsStart();
         doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
 
         if (DEBUG) {
diff --git a/core/java/android/view/ContextMenu.java b/core/java/android/view/ContextMenu.java
index decabcb..85fe421 100644
--- a/core/java/android/view/ContextMenu.java
+++ b/core/java/android/view/ContextMenu.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
 import android.app.Activity;
 import android.graphics.drawable.Drawable;
 import android.widget.AdapterView;
@@ -44,7 +46,7 @@
      * @param titleRes The string resource identifier used for the title.
      * @return This ContextMenu so additional setters can be called.
      */
-    public ContextMenu setHeaderTitle(int titleRes);
+    public ContextMenu setHeaderTitle(@StringRes int titleRes);
 
     /**
      * Sets the context menu header's title to the title given in <var>title</var>.
@@ -61,7 +63,7 @@
      * @param iconRes The resource identifier used for the icon.
      * @return This ContextMenu so additional setters can be called.
      */
-    public ContextMenu setHeaderIcon(int iconRes);
+    public ContextMenu setHeaderIcon(@DrawableRes int iconRes);
 
     /**
      * Sets the context menu header's icon to the icon given in <var>icon</var>
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 0afbde9..d9f6054 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -35,13 +35,19 @@
     public ContextThemeWrapper() {
         super(null);
     }
-    
-    public ContextThemeWrapper(Context base, int themeres) {
+
+    public ContextThemeWrapper(Context base, int themeResId) {
         super(base);
-        mThemeResource = themeres;
+        mThemeResource = themeResId;
     }
 
-    @Override protected void attachBaseContext(Context newBase) {
+    public ContextThemeWrapper(Context base, Resources.Theme theme) {
+        super(base);
+        mTheme = theme;
+    }
+
+    @Override
+    protected void attachBaseContext(Context newBase) {
         super.attachBaseContext(newBase);
     }
 
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index cfb0297..71863b7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -716,7 +716,7 @@
             updateDisplayInfoLocked();
             mDisplayInfo.getLogicalMetrics(outMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
-                    mDisplayAdjustments.getActivityToken());
+                    mDisplayAdjustments.getConfiguration());
         }
     }
 
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index 35fb504..272740f 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.content.res.CompatibilityInfo;
-import android.os.IBinder;
+import android.content.res.Configuration;
 
 import java.util.Objects;
 
@@ -28,22 +28,18 @@
     public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments();
 
     private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-    private volatile IBinder mActivityToken;
+    private Configuration mConfiguration = Configuration.EMPTY;
 
     public DisplayAdjustments() {
     }
 
-    public DisplayAdjustments(IBinder token) {
-        mActivityToken = token;
+    public DisplayAdjustments(Configuration configuration) {
+        mConfiguration = configuration;
     }
 
     public DisplayAdjustments(DisplayAdjustments daj) {
-        this (daj.getCompatibilityInfo(), daj.getActivityToken());
-    }
-
-    public DisplayAdjustments(CompatibilityInfo compatInfo, IBinder token) {
-        setCompatibilityInfo(compatInfo);
-        mActivityToken = token;
+        setCompatibilityInfo(daj.mCompatInfo);
+        mConfiguration = daj.mConfiguration;
     }
 
     public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
@@ -63,16 +59,16 @@
         return mCompatInfo;
     }
 
-    public void setActivityToken(IBinder token) {
+    public void setConfiguration(Configuration configuration) {
         if (this == DEFAULT_DISPLAY_ADJUSTMENTS) {
             throw new IllegalArgumentException(
-                    "setActivityToken: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
+                    "setConfiguration: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
         }
-        mActivityToken = token;
+        mConfiguration = configuration;
     }
 
-    public IBinder getActivityToken() {
-        return mActivityToken;
+    public Configuration getConfiguration() {
+        return mConfiguration;
     }
 
     @Override
@@ -80,7 +76,7 @@
         int hash = 17;
         hash = hash * 31 + mCompatInfo.hashCode();
         if (DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN) {
-            hash = hash * 31 + (mActivityToken == null ? 0 : mActivityToken.hashCode());
+            hash = hash * 31 + (mConfiguration == null ? 0 : mConfiguration.hashCode());
         }
         return hash;
     }
@@ -92,6 +88,6 @@
         }
         DisplayAdjustments daj = (DisplayAdjustments)o;
         return Objects.equals(daj.mCompatInfo, mCompatInfo) &&
-                Objects.equals(daj.mActivityToken, mActivityToken);
+                Objects.equals(daj.mConfiguration, mConfiguration);
     }
 }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 9feb681..ecf45b4 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -17,7 +17,7 @@
 package android.view;
 
 import android.content.res.CompatibilityInfo;
-import android.os.IBinder;
+import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.DisplayMetrics;
@@ -401,16 +401,17 @@
 
     public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
         getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
-                displayAdjustments.getActivityToken(), appWidth, appHeight);
+                displayAdjustments.getConfiguration(), appWidth, appHeight);
     }
 
-    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci, IBinder token) {
-        getMetricsWithSize(outMetrics, ci, token, appWidth, appHeight);
+    public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
+            Configuration configuration) {
+        getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
     }
 
     public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
-            IBinder token) {
-        getMetricsWithSize(outMetrics, compatInfo, token, logicalWidth, logicalHeight);
+            Configuration configuration) {
+        getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
     }
 
     public int getNaturalWidth() {
@@ -431,17 +432,24 @@
     }
 
     private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
-            IBinder token, int width, int height) {
+            Configuration configuration, int width, int height) {
         outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
-        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
-        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
-
         outMetrics.density = outMetrics.noncompatDensity =
                 logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
         outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
         outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
 
+        width = (configuration != null
+                && configuration.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED)
+                ? (int)((configuration.screenWidthDp * outMetrics.density) + 0.5f) : width;
+        height = (configuration != null
+                && configuration.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED)
+                ? (int)((configuration.screenHeightDp * outMetrics.density) + 0.5f) : height;
+
+        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
+        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
+
         if (!compatInfo.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) {
             compatInfo.applyToDisplayMetrics(outMetrics);
         }
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
new file mode 100644
index 0000000..90e1f86
--- /dev/null
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.graphics.Bitmap;
+import android.graphics.CanvasProperty;
+import android.graphics.NinePatch;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Picture;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Pools.SynchronizedPool;
+
+/**
+ * An implementation of a GL canvas that records drawing operations.
+ * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
+ * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
+ * the DisplayList is still holding a native reference to the memory.
+ */
+class DisplayListCanvas extends HardwareCanvas {
+    // The recording canvas pool should be large enough to handle a deeply nested
+    // view hierarchy because display lists are generated recursively.
+    private static final int POOL_LIMIT = 25;
+
+    private static final SynchronizedPool<DisplayListCanvas> sPool =
+            new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT);
+
+    RenderNode mNode;
+    private int mWidth;
+    private int mHeight;
+
+
+    static DisplayListCanvas obtain(@NonNull RenderNode node) {
+        if (node == null) throw new IllegalArgumentException("node cannot be null");
+        DisplayListCanvas canvas = sPool.acquire();
+        if (canvas == null) {
+            canvas = new DisplayListCanvas();
+        }
+        canvas.mNode = node;
+        return canvas;
+    }
+
+    void recycle() {
+        mNode = null;
+        sPool.release(this);
+    }
+
+    long finishRecording() {
+        return nFinishRecording(mNativeCanvasWrapper);
+    }
+
+    @Override
+    public boolean isRecordingFor(Object o) {
+        return o == mNode;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // JNI
+    ///////////////////////////////////////////////////////////////////////////
+
+    private static native boolean nIsAvailable();
+    private static boolean sIsAvailable = nIsAvailable();
+
+    static boolean isAvailable() {
+        return sIsAvailable;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Constructors
+    ///////////////////////////////////////////////////////////////////////////
+
+
+    private DisplayListCanvas() {
+        super(nCreateDisplayListRenderer());
+    }
+
+    private static native long nCreateDisplayListRenderer();
+
+    public static void setProperty(String name, String value) {
+        nSetProperty(name, value);
+    }
+
+    private static native void nSetProperty(String name, String value);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Canvas management
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean isOpaque() {
+        return false;
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public int getMaximumBitmapWidth() {
+        return nGetMaximumTextureWidth();
+    }
+
+    @Override
+    public int getMaximumBitmapHeight() {
+        return nGetMaximumTextureHeight();
+    }
+
+    private static native int nGetMaximumTextureWidth();
+    private static native int nGetMaximumTextureHeight();
+
+    /**
+     * Returns the native OpenGLRenderer object.
+     */
+    long getRenderer() {
+        return mNativeCanvasWrapper;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Setup
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void setViewport(int width, int height) {
+        mWidth = width;
+        mHeight = height;
+
+        nSetViewport(mNativeCanvasWrapper, width, height);
+    }
+
+    private static native void nSetViewport(long renderer,
+            int width, int height);
+
+    @Override
+    public void setHighContrastText(boolean highContrastText) {
+        nSetHighContrastText(mNativeCanvasWrapper, highContrastText);
+    }
+
+    private static native void nSetHighContrastText(long renderer, boolean highContrastText);
+
+    @Override
+    public void insertReorderBarrier() {
+        nInsertReorderBarrier(mNativeCanvasWrapper, true);
+    }
+
+    @Override
+    public void insertInorderBarrier() {
+        nInsertReorderBarrier(mNativeCanvasWrapper, false);
+    }
+
+    private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
+
+    @Override
+    public void onPreDraw(Rect dirty) {
+        if (dirty != null) {
+            nPrepareDirty(mNativeCanvasWrapper, dirty.left, dirty.top, dirty.right, dirty.bottom);
+        } else {
+            nPrepare(mNativeCanvasWrapper);
+        }
+    }
+
+    private static native void nPrepare(long renderer);
+    private static native void nPrepareDirty(long renderer, int left, int top, int right, int bottom);
+
+    @Override
+    public void onPostDraw() {
+        nFinish(mNativeCanvasWrapper);
+    }
+
+    private static native void nFinish(long renderer);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Functor
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void callDrawGLFunction2(long drawGLFunction) {
+        nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction);
+    }
+
+    private static native void nCallDrawGLFunction(long renderer, long drawGLFunction);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Display list
+    ///////////////////////////////////////////////////////////////////////////
+
+    protected static native long nFinishRecording(long renderer);
+
+    @Override
+    public void drawRenderNode(RenderNode renderNode, int flags) {
+        nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList(), flags);
+    }
+
+    private static native void nDrawRenderNode(long renderer, long renderNode,
+            int flags);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Hardware layer
+    ///////////////////////////////////////////////////////////////////////////
+
+    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
+        layer.setLayerPaint(paint);
+        nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y);
+    }
+
+    private static native void nDrawLayer(long renderer, long layer, float x, float y);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Drawing
+    ///////////////////////////////////////////////////////////////////////////
+
+    // TODO: move to Canvas.java
+    @Override
+    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+        Bitmap bitmap = patch.getBitmap();
+        throwIfCannotDraw(bitmap);
+        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+    }
+
+    // TODO: move to Canvas.java
+    @Override
+    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
+        Bitmap bitmap = patch.getBitmap();
+        throwIfCannotDraw(bitmap);
+        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
+        nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+    }
+
+    private static native void nDrawPatch(long renderer, long bitmap, long chunk,
+            float left, float top, float right, float bottom, long paint);
+
+    @Override
+    public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+            CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
+        nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
+                radius.getNativeContainer(), paint.getNativeContainer());
+    }
+
+    private static native void nDrawCircle(long renderer, long propCx,
+            long propCy, long propRadius, long propPaint);
+
+    @Override
+    public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
+            CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
+            CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
+        nDrawRoundRect(mNativeCanvasWrapper, left.getNativeContainer(), top.getNativeContainer(),
+                right.getNativeContainer(), bottom.getNativeContainer(),
+                rx.getNativeContainer(), ry.getNativeContainer(),
+                paint.getNativeContainer());
+    }
+
+    private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
+            long propRight, long propBottom, long propRx, long propRy, long propPaint);
+
+    // TODO: move this optimization to Canvas.java
+    @Override
+    public void drawPath(Path path, Paint paint) {
+        if (path.isSimplePath) {
+            if (path.rects != null) {
+                nDrawRects(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
+            }
+        } else {
+            super.drawPath(path, paint);
+        }
+    }
+
+    private static native void nDrawRects(long renderer, long region, long paint);
+
+    @Override
+    public void drawPicture(Picture picture) {
+        picture.endRecording();
+        // TODO: Implement rendering
+    }
+}
diff --git a/core/java/android/view/FrameInfo.java b/core/java/android/view/FrameInfo.java
new file mode 100644
index 0000000..c79547c
--- /dev/null
+++ b/core/java/android/view/FrameInfo.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that contains all the timing information for the current frame. This
+ * is used in conjunction with the hardware renderer to provide
+ * continous-monitoring jank events
+ *
+ * All times in nanoseconds from CLOCK_MONOTONIC/System.nanoTime()
+ *
+ * To minimize overhead from System.nanoTime() calls we infer durations of
+ * things by knowing the ordering of the events. For example, to know how
+ * long layout & measure took it's displayListRecordStart - performTraversalsStart.
+ *
+ * These constants must be kept in sync with FrameInfo.h in libhwui and are
+ * used for indexing into AttachInfo's mFrameInfo long[], which is intended
+ * to be quick to pass down to native via JNI, hence a pre-packed format
+ *
+ * @hide
+ */
+final class FrameInfo {
+
+    long[] mFrameInfo = new long[9];
+
+    // Various flags set to provide extra metadata about the current frame
+    private static final int FLAGS = 0;
+
+    // Is this the first-draw following a window layout?
+    public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_WINDOW_LAYOUT_CHANGED })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FrameInfoFlags {}
+
+    // The intended vsync time, unadjusted by jitter
+    private static final int INTENDED_VSYNC = 1;
+
+    // Jitter-adjusted vsync time, this is what was used as input into the
+    // animation & drawing system
+    private static final int VSYNC = 2;
+
+    // The time of the oldest input event
+    private static final int OLDEST_INPUT_EVENT = 3;
+
+    // The time of the newest input event
+    private static final int NEWEST_INPUT_EVENT = 4;
+
+    // When input event handling started
+    private static final int HANDLE_INPUT_START = 5;
+
+    // When animation evaluations started
+    private static final int ANIMATION_START = 6;
+
+    // When ViewRootImpl#performTraversals() started
+    private static final int PERFORM_TRAVERSALS_START = 7;
+
+    // When View:draw() started
+    private static final int DRAW_START = 8;
+
+    public void setVsync(long intendedVsync, long usedVsync) {
+        mFrameInfo[INTENDED_VSYNC] = intendedVsync;
+        mFrameInfo[VSYNC] = usedVsync;
+        mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
+        mFrameInfo[NEWEST_INPUT_EVENT] = 0;
+        mFrameInfo[FLAGS] = 0;
+    }
+
+    public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
+        if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
+            mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
+        }
+        if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
+            mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
+        }
+    }
+
+    public void markInputHandlingStart() {
+        mFrameInfo[HANDLE_INPUT_START] = System.nanoTime();
+    }
+
+    public void markAnimationsStart() {
+        mFrameInfo[ANIMATION_START] = System.nanoTime();
+    }
+
+    public void markPerformTraversalsStart() {
+        mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
+    }
+
+    public void markDrawStart() {
+        mFrameInfo[DRAW_START] = System.nanoTime();
+    }
+
+    public void addFlags(@FrameInfoFlags long flags) {
+        mFrameInfo[FLAGS] |= flags;
+    }
+
+}
diff --git a/core/java/android/view/FrameStats.java b/core/java/android/view/FrameStats.java
index b3ac1db..3fbe6fe 100644
--- a/core/java/android/view/FrameStats.java
+++ b/core/java/android/view/FrameStats.java
@@ -16,9 +16,6 @@
 
 package android.view;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-
 /**
  * This is the base class for frame statistics.
  */
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
deleted file mode 100644
index 60a489b..0000000
--- a/core/java/android/view/GLES20Canvas.java
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.CanvasProperty;
-import android.graphics.DrawFilter;
-import android.graphics.Matrix;
-import android.graphics.NinePatch;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Shader;
-import android.graphics.TemporaryBuffer;
-import android.text.GraphicsOperations;
-import android.text.SpannableString;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-/**
- * An implementation of Canvas on top of OpenGL ES 2.0.
- */
-class GLES20Canvas extends HardwareCanvas {
-    private final boolean mOpaque;
-    protected long mRenderer;
-
-    // The native renderer will be destroyed when this object dies.
-    // DO NOT overwrite this reference once it is set.
-    @SuppressWarnings({"unused", "FieldCanBeLocal"})
-    private CanvasFinalizer mFinalizer;
-
-    private int mWidth;
-    private int mHeight;
-
-    private float[] mPoint;
-    private float[] mLine;
-
-    private Rect mClipBounds;
-    private RectF mPathBounds;
-
-    private DrawFilter mFilter;
-
-    ///////////////////////////////////////////////////////////////////////////
-    // JNI
-    ///////////////////////////////////////////////////////////////////////////
-
-    private static native boolean nIsAvailable();
-    private static boolean sIsAvailable = nIsAvailable();
-
-    static boolean isAvailable() {
-        return sIsAvailable;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Constructors
-    ///////////////////////////////////////////////////////////////////////////
-
-    // TODO: Merge with GLES20RecordingCanvas
-    protected GLES20Canvas() {
-        mOpaque = false;
-        mRenderer = nCreateDisplayListRenderer();
-        setupFinalizer();
-    }
-
-    private void setupFinalizer() {
-        if (mRenderer == 0) {
-            throw new IllegalStateException("Could not create GLES20Canvas renderer");
-        } else {
-            mFinalizer = new CanvasFinalizer(mRenderer);
-        }
-    }
-
-    private static native long nCreateDisplayListRenderer();
-    private static native void nResetDisplayListRenderer(long renderer);
-    private static native void nDestroyRenderer(long renderer);
-
-    private static final class CanvasFinalizer {
-        private final long mRenderer;
-
-        public CanvasFinalizer(long renderer) {
-            mRenderer = renderer;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                nDestroyRenderer(mRenderer);
-            } finally {
-                super.finalize();
-            }
-        }
-    }
-
-    public static void setProperty(String name, String value) {
-        nSetProperty(name, value);
-    }
-
-    private static native void nSetProperty(String name, String value);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Canvas management
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public boolean isOpaque() {
-        return mOpaque;
-    }
-
-    @Override
-    public int getWidth() {
-        return mWidth;
-    }
-
-    @Override
-    public int getHeight() {
-        return mHeight;
-    }
-
-    @Override
-    public int getMaximumBitmapWidth() {
-        return nGetMaximumTextureWidth();
-    }
-
-    @Override
-    public int getMaximumBitmapHeight() {
-        return nGetMaximumTextureHeight();
-    }
-
-    private static native int nGetMaximumTextureWidth();
-    private static native int nGetMaximumTextureHeight();
-
-    /**
-     * Returns the native OpenGLRenderer object.
-     */
-    long getRenderer() {
-        return mRenderer;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Setup
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void setViewport(int width, int height) {
-        mWidth = width;
-        mHeight = height;
-
-        nSetViewport(mRenderer, width, height);
-    }
-
-    private static native void nSetViewport(long renderer,
-            int width, int height);
-
-    @Override
-    public void setHighContrastText(boolean highContrastText) {
-        nSetHighContrastText(mRenderer, highContrastText);
-    }
-
-    private static native void nSetHighContrastText(long renderer, boolean highContrastText);
-
-    @Override
-    public void insertReorderBarrier() {
-        nInsertReorderBarrier(mRenderer, true);
-    }
-
-    @Override
-    public void insertInorderBarrier() {
-        nInsertReorderBarrier(mRenderer, false);
-    }
-
-    private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
-
-    @Override
-    public int onPreDraw(Rect dirty) {
-        if (dirty != null) {
-            return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
-                    mOpaque);
-        } else {
-            return nPrepare(mRenderer, mOpaque);
-        }
-    }
-
-    private static native int nPrepare(long renderer, boolean opaque);
-    private static native int nPrepareDirty(long renderer, int left, int top, int right, int bottom,
-            boolean opaque);
-
-    @Override
-    public void onPostDraw() {
-        nFinish(mRenderer);
-    }
-
-    private static native void nFinish(long renderer);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Functor
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public int callDrawGLFunction2(long drawGLFunction) {
-        return nCallDrawGLFunction(mRenderer, drawGLFunction);
-    }
-
-    private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Display list
-    ///////////////////////////////////////////////////////////////////////////
-
-    protected static native long nFinishRecording(long renderer);
-
-    @Override
-    public int drawRenderNode(RenderNode renderNode, Rect dirty, int flags) {
-        return nDrawRenderNode(mRenderer, renderNode.getNativeDisplayList(), dirty, flags);
-    }
-
-    private static native int nDrawRenderNode(long renderer, long renderNode,
-            Rect dirty, int flags);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Hardware layer
-    ///////////////////////////////////////////////////////////////////////////
-
-    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
-        layer.setLayerPaint(paint);
-        nDrawLayer(mRenderer, layer.getLayerHandle(), x, y);
-    }
-
-    private static native void nDrawLayer(long renderer, long layer, float x, float y);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Support
-    ///////////////////////////////////////////////////////////////////////////
-
-    private Rect getInternalClipBounds() {
-        if (mClipBounds == null) mClipBounds = new Rect();
-        return mClipBounds;
-    }
-
-
-    private RectF getPathBounds() {
-        if (mPathBounds == null) mPathBounds = new RectF();
-        return mPathBounds;
-    }
-
-    private float[] getPointStorage() {
-        if (mPoint == null) mPoint = new float[2];
-        return mPoint;
-    }
-
-    private float[] getLineStorage() {
-        if (mLine == null) mLine = new float[4];
-        return mLine;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Clipping
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public boolean clipPath(Path path) {
-        return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt);
-    }
-
-    @Override
-    public boolean clipPath(Path path, Region.Op op) {
-        return nClipPath(mRenderer, path.mNativePath, op.nativeInt);
-    }
-
-    private static native boolean nClipPath(long renderer, long path, int op);
-
-    @Override
-    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);
-
-    @Override
-    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
-        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
-    }
-
-    @Override
-    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);
-    }
-
-    @Override
-    public boolean clipRect(Rect rect, Region.Op op) {
-        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
-    }
-
-    @Override
-    public boolean clipRect(RectF rect) {
-        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
-                Region.Op.INTERSECT.nativeInt);
-    }
-
-    @Override
-    public boolean clipRect(RectF rect, Region.Op op) {
-        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
-    }
-
-    @Override
-    public boolean clipRegion(Region region) {
-        return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt);
-    }
-
-    @Override
-    public boolean clipRegion(Region region, Region.Op op) {
-        return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt);
-    }
-
-    private static native boolean nClipRegion(long renderer, long region, int op);
-
-    @Override
-    public boolean getClipBounds(Rect bounds) {
-        return nGetClipBounds(mRenderer, bounds);
-    }
-
-    private static native boolean nGetClipBounds(long renderer, Rect bounds);
-
-    @Override
-    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);
-
-    @Override
-    public boolean quickReject(Path path, EdgeType type) {
-        RectF pathBounds = getPathBounds();
-        path.computeBounds(pathBounds, true);
-        return nQuickReject(mRenderer, pathBounds.left, pathBounds.top,
-                pathBounds.right, pathBounds.bottom);
-    }
-
-    @Override
-    public boolean quickReject(RectF rect, EdgeType type) {
-        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Transformations
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    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
-    public void skew(float sx, float sy) {
-        nSkew(mRenderer, sx, sy);
-    }
-
-    private static native void nSkew(long renderer, float sx, float sy);
-
-    @Override
-    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) {
-        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")
-    @Override
-    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
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    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) {
-            return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
-        }
-
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        return nSaveLayer(mRenderer, nativePaint, saveFlags);
-    }
-
-    private static native int nSaveLayer(long renderer, long paint, int saveFlags);
-
-    @Override
-    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
-            int saveFlags) {
-        if (left < right && top < bottom) {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
-        }
-        return save(saveFlags);
-    }
-
-    private static native int nSaveLayer(long renderer, float left, float top,
-            float right, float bottom, long paint, int saveFlags);
-
-    @Override
-    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
-        if (bounds != null) {
-            return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
-                    alpha, saveFlags);
-        }
-        return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
-    }
-
-    private static native int nSaveLayerAlpha(long renderer, int alpha, int saveFlags);
-
-    @Override
-    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
-            int saveFlags) {
-        if (left < right && top < bottom) {
-            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
-        }
-        return save(saveFlags);
-    }
-
-    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
-    public void restoreToCount(int saveCount) {
-        nRestoreToCount(mRenderer, saveCount);
-    }
-
-    private static native void nRestoreToCount(long renderer, int saveCount);
-
-    @Override
-    public int getSaveCount() {
-        return nGetSaveCount(mRenderer);
-    }
-
-    private static native int nGetSaveCount(long renderer);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Filtering
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void setDrawFilter(DrawFilter filter) {
-        mFilter = filter;
-        if (filter == null) {
-            nResetPaintFilter(mRenderer);
-        } else if (filter instanceof PaintFlagsDrawFilter) {
-            PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
-            nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
-        }
-    }
-
-    private static native void nResetPaintFilter(long renderer);
-    private static native void nSetupPaintFilter(long renderer, int clearBits, int setBits);
-
-    @Override
-    public DrawFilter getDrawFilter() {
-        return mFilter;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Drawing
-    ///////////////////////////////////////////////////////////////////////////
-
-    @Override
-    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);
-    }
-
-    private static native void nDrawArc(long renderer, float left, float top,
-            float right, float bottom, float startAngle, float sweepAngle,
-            boolean useCenter, long paint);
-
-    @Override
-    public void drawARGB(int a, int r, int g, int b) {
-        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
-    }
-
-    @Override
-    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
-        Bitmap bitmap = patch.getBitmap();
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-    }
-
-    @Override
-    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
-        Bitmap bitmap = patch.getBitmap();
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-    }
-
-    private static native void nDrawPatch(long renderer, long bitmap, long chunk,
-            float left, float top, float right, float bottom, long paint);
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
-    }
-
-    private static native void nDrawBitmap(long renderer, long bitmap, float left,
-            float top, long paint);
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
-    }
-
-    private static native void nDrawBitmap(long renderer, long bitmap,
-            long matrix, long paint);
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-
-        int left, top, right, bottom;
-        if (src == null) {
-            left = top = 0;
-            right = bitmap.getWidth();
-            bottom = bitmap.getHeight();
-        } else {
-            left = src.left;
-            right = src.right;
-            top = src.top;
-            bottom = src.bottom;
-        }
-
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-    }
-
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
-        throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-
-        float left, top, right, bottom;
-        if (src == null) {
-            left = top = 0;
-            right = bitmap.getWidth();
-            bottom = bitmap.getHeight();
-        } else {
-            left = src.left;
-            right = src.right;
-            top = src.top;
-            bottom = src.bottom;
-        }
-
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-    }
-
-    private static native void nDrawBitmap(long renderer, long bitmap,
-            float srcLeft, float srcTop, float srcRight, float srcBottom,
-            float left, float top, float right, float bottom, long paint);
-
-    @Override
-    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
-            int width, int height, boolean hasAlpha, Paint paint) {
-        if (width < 0) {
-            throw new IllegalArgumentException("width must be >= 0");
-        }
-
-        if (height < 0) {
-            throw new IllegalArgumentException("height must be >= 0");
-        }
-
-        if (Math.abs(stride) < width) {
-            throw new IllegalArgumentException("abs(stride) must be >= width");
-        }
-
-        int lastScanline = offset + (height - 1) * stride;
-        int length = colors.length;
-
-        if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
-                (lastScanline + width > length)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, colors, offset, stride, x, y,
-                width, height, hasAlpha, nativePaint);
-    }
-
-    private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride,
-            float x, float y, int width, int height, boolean hasAlpha, long nativePaint);
-
-    @Override
-    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
-            int width, int height, boolean hasAlpha, Paint paint) {
-        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
-    }
-
-    @Override
-    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
-            int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        throwIfCannotDraw(bitmap);
-        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        if (meshWidth == 0 || meshHeight == 0) {
-            return;
-        }
-
-        final int count = (meshWidth + 1) * (meshHeight + 1);
-        checkRange(verts.length, vertOffset, count * 2);
-
-        if (colors != null) {
-            checkRange(colors.length, colorOffset, count);
-        }
-
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, meshWidth, meshHeight,
-                verts, vertOffset, colors, colorOffset, nativePaint);
-    }
-
-    private static native void nDrawBitmapMesh(long renderer, long bitmap,
-            int meshWidth, int meshHeight, float[] verts, int vertOffset,
-            int[] colors, int colorOffset, long paint);
-
-    @Override
-    public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
-    }
-
-    private static native void nDrawCircle(long renderer, float cx, float cy,
-            float radius, long paint);
-
-    @Override
-    public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
-            CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
-        nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(),
-                radius.getNativeContainer(), paint.getNativeContainer());
-    }
-
-    private static native void nDrawCircle(long renderer, long propCx,
-            long propCy, long propRadius, long propPaint);
-
-    @Override
-    public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
-            CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
-            CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
-        nDrawRoundRect(mRenderer, left.getNativeContainer(), top.getNativeContainer(),
-                right.getNativeContainer(), bottom.getNativeContainer(),
-                rx.getNativeContainer(), ry.getNativeContainer(),
-                paint.getNativeContainer());
-    }
-
-    private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
-            long propRight, long propBottom, long propRx, long propRy, long propPaint);
-
-    @Override
-    public void drawColor(int color) {
-        drawColor(color, PorterDuff.Mode.SRC_OVER);
-    }
-
-    @Override
-    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
-    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
-        float[] line = getLineStorage();
-        line[0] = startX;
-        line[1] = startY;
-        line[2] = stopX;
-        line[3] = stopY;
-        drawLines(line, 0, 4, paint);
-    }
-
-    @Override
-    public void drawLines(float[] pts, int offset, int count, Paint paint) {
-        if (count < 4) return;
-
-        if ((offset | count) < 0 || offset + count > pts.length) {
-            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
-        }
-        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
-    }
-
-    private static native void nDrawLines(long renderer, float[] points,
-            int offset, int count, long paint);
-
-    @Override
-    public void drawLines(float[] pts, Paint paint) {
-        drawLines(pts, 0, pts.length, paint);
-    }
-
-    @Override
-    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,
-            float right, float bottom, long paint);
-
-    @Override
-    public void drawPaint(Paint paint) {
-        final Rect r = getInternalClipBounds();
-        nGetClipBounds(mRenderer, r);
-        drawRect(r.left, r.top, r.right, r.bottom, paint);
-    }
-
-    @Override
-    public void drawPath(Path path, Paint paint) {
-        if (path.isSimplePath) {
-            if (path.rects != null) {
-                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
-            }
-        } else {
-            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
-        }
-    }
-
-    private static native void nDrawPath(long renderer, long path, long paint);
-    private static native void nDrawRects(long renderer, long region, long paint);
-
-    @Override
-    public void drawPicture(Picture picture) {
-        picture.endRecording();
-        // TODO: Implement rendering
-    }
-
-    @Override
-    public void drawPoint(float x, float y, Paint paint) {
-        float[] point = getPointStorage();
-        point[0] = x;
-        point[1] = y;
-        drawPoints(point, 0, 2, paint);
-    }
-
-    @Override
-    public void drawPoints(float[] pts, Paint paint) {
-        drawPoints(pts, 0, pts.length, paint);
-    }
-
-    @Override
-    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
-        if (count < 2) return;
-
-        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
-    }
-
-    private static native void nDrawPoints(long renderer, float[] points,
-            int offset, int count, long paint);
-
-    // Note: drawPosText just uses implementation in Canvas
-
-    @Override
-    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
-        if (left == right || top == bottom) return;
-        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
-    }
-
-    private static native void nDrawRect(long renderer, float left, float top,
-            float right, float bottom, long paint);
-
-    @Override
-    public void drawRect(Rect r, Paint paint) {
-        drawRect(r.left, r.top, r.right, r.bottom, paint);
-    }
-
-    @Override
-    public void drawRect(RectF r, Paint paint) {
-        drawRect(r.left, r.top, r.right, r.bottom, paint);
-    }
-
-    @Override
-    public void drawRGB(int r, int g, int b) {
-        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
-    }
-
-    @Override
-    public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
-            Paint paint) {
-        nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
-    }
-
-    private static native void nDrawRoundRect(long renderer, float left, float top,
-            float right, float bottom, float rx, float y, long paint);
-
-    @Override
-    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
-        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        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);
-
-    @Override
-    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        if ((start | end | (end - start) | (text.length() - end)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (text instanceof String || text instanceof SpannedString ||
-                text instanceof SpannableString) {
-            nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
-                    paint.mNativePaint, paint.mNativeTypeface);
-        } else if (text instanceof GraphicsOperations) {
-            ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
-        } else {
-            char[] buf = TemporaryBuffer.obtain(end - start);
-            TextUtils.getChars(text, start, end, buf, 0);
-            nDrawText(mRenderer, buf, 0, end - start, x, y,
-                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-            TemporaryBuffer.recycle(buf);
-        }
-    }
-
-    @Override
-    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
-        if ((start | end | (end - start) | (text.length() - end)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        nDrawText(mRenderer, text, start, end, x, y,
-                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-    }
-
-    private static native void nDrawText(long renderer, String text, int start, int end,
-            float x, float y, int bidiFlags, long paint, long typeface);
-
-    @Override
-    public void drawText(String text, float x, float y, Paint paint) {
-        nDrawText(mRenderer, text, 0, text.length(), x, y,
-                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-    }
-
-    @Override
-    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
-            float vOffset, Paint paint) {
-        if (index < 0 || index + count > text.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-    }
-
-    private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
-            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
-            long typeface);
-
-    @Override
-    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
-        if (text.length() == 0) return;
-
-        nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-    }
-
-    private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
-            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
-            long typeface);
-
-    @Override
-    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, boolean isRtl, Paint paint) {
-        if ((index | count | text.length - index - count) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        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, boolean isRtl, long nativePaint, long nativeTypeface);
-
-    @Override
-    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, boolean isRtl, Paint paint) {
-        if ((start | end | end - start | text.length() - end) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (text instanceof String || text instanceof SpannedString ||
-                text instanceof SpannableString) {
-            nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                    contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
-        } else if (text instanceof GraphicsOperations) {
-            ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    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, 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, boolean isRtl, long nativePaint, long nativeTypeface);
-
-    @Override
-    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
-            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
-            int indexOffset, int indexCount, Paint paint) {
-        // TODO: Implement
-    }
-}
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
deleted file mode 100644
index 5e49d8e..0000000
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.Pools.SynchronizedPool;
-
-/**
- * An implementation of a GL canvas that records drawing operations.
- * This is intended for use with a DisplayList. This class keeps a list of all the Paint and
- * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while
- * the DisplayList is still holding a native reference to the memory.
- */
-class GLES20RecordingCanvas extends GLES20Canvas {
-    // The recording canvas pool should be large enough to handle a deeply nested
-    // view hierarchy because display lists are generated recursively.
-    private static final int POOL_LIMIT = 25;
-
-    private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
-            new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
-
-    RenderNode mNode;
-
-    private GLES20RecordingCanvas() {
-        super();
-    }
-
-    static GLES20RecordingCanvas obtain(@NonNull RenderNode node) {
-        if (node == null) throw new IllegalArgumentException("node cannot be null");
-        GLES20RecordingCanvas canvas = sPool.acquire();
-        if (canvas == null) {
-            canvas = new GLES20RecordingCanvas();
-        }
-        canvas.mNode = node;
-        return canvas;
-    }
-
-    void recycle() {
-        mNode = null;
-        sPool.release(this);
-    }
-
-    long finishRecording() {
-        return nFinishRecording(mRenderer);
-    }
-
-    @Override
-    public boolean isRecordingFor(Object o) {
-        return o == mNode;
-    }
-}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 18accb8..fc2b55b 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -29,6 +29,14 @@
  */
 public abstract class HardwareCanvas extends Canvas {
 
+    /**
+     * Pass a reference to the native renderer to our superclass's
+     * constructor.
+     */
+    protected HardwareCanvas(long renderer) {
+        super(renderer);
+    }
+
     @Override
     public boolean isHardwareAccelerated() {
         return true;
@@ -43,12 +51,10 @@
      * Invoked before any drawing operation is performed in this canvas.
      *
      * @param dirty The dirty rectangle to update, can be null.
-     * @return {@link RenderNode#STATUS_DREW} if anything was drawn (such as a call to clear
-     *         the canvas).
      *
      * @hide
      */
-    public abstract int onPreDraw(Rect dirty);
+    public abstract void onPreDraw(Rect dirty);
 
     /**
      * Invoked after all drawing operation have been performed.
@@ -64,7 +70,7 @@
      * @param renderNode The RenderNode to replay.
      */
     public void drawRenderNode(RenderNode renderNode) {
-        drawRenderNode(renderNode, null, RenderNode.FLAG_CLIP_CHILDREN);
+        drawRenderNode(renderNode, RenderNode.FLAG_CLIP_CHILDREN);
     }
 
     /**
@@ -75,12 +81,9 @@
      * @param flags Optional flags about drawing, see {@link RenderNode} for
      *              the possible flags.
      *
-     * @return One of {@link RenderNode#STATUS_DONE} or {@link RenderNode#STATUS_DREW}
-     *         if anything was drawn.
-     *
      * @hide
      */
-    public abstract int drawRenderNode(RenderNode renderNode, Rect dirty, int flags);
+    public abstract void drawRenderNode(RenderNode renderNode, int flags);
 
     /**
      * Draws the specified layer onto this canvas.
@@ -101,11 +104,11 @@
      *
      * @param drawGLFunction A native function pointer
      *
-     * @return {@link RenderNode#STATUS_DONE}
-     *
      * @hide
      */
-    public abstract int callDrawGLFunction2(long drawGLFunction);
+    public void callDrawGLFunction2(long drawGLFunction) {
+        // Noop - this is done in the display list recorder subclass
+    }
 
     public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
             CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
@@ -116,6 +119,6 @@
             CanvasProperty<Paint> paint);
 
     public static void setProperty(String name, String value) {
-        GLES20Canvas.setProperty(name, value);
+        DisplayListCanvas.setProperty(name, value);
     }
 }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a130bda..65ae8a6 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -52,7 +52,7 @@
      * @see View#setLayerPaint(android.graphics.Paint)
      */
     public void setLayerPaint(Paint paint) {
-        nSetLayerPaint(mFinalizer.get(), paint.mNativePaint);
+        nSetLayerPaint(mFinalizer.get(), paint.getNativeInstance());
         mRenderer.pushLayerUpdate(this);
     }
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c5c3f83..afa7f51 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.util.DisplayMetrics;
 import android.view.Surface.OutOfResourcesException;
 
 import java.io.File;
@@ -206,7 +205,7 @@
      *         false otherwise
      */
     public static boolean isAvailable() {
-        return GLES20Canvas.isAvailable();
+        return DisplayListCanvas.isAvailable();
     }
 
     /**
@@ -278,7 +277,7 @@
     /**
      * Outputs extra debugging information in the specified file descriptor.
      */
-    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd);
+    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args);
 
     /**
      * Loads system properties used by the renderer. This method is invoked
@@ -424,7 +423,7 @@
      */
     static HardwareRenderer create(Context context, boolean translucent) {
         HardwareRenderer renderer = null;
-        if (GLES20Canvas.isAvailable()) {
+        if (DisplayListCanvas.isAvailable()) {
             renderer = new ThreadedRenderer(context, translucent);
         }
         return renderer;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7b20e72..8ac8bc5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -81,7 +81,7 @@
     void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind);
-    void setAppGroupId(IBinder token, int groupId);
+    void setAppTask(IBinder token, int taskId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
@@ -91,6 +91,8 @@
             IRemoteCallback startedCallback);
     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
             int startHeight);
+    void overridePendingAppTransitionClipReveal(int startX, int startY,
+            int startWidth, int startHeight);
     void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
             IRemoteCallback startedCallback, boolean scaleUp);
     void overridePendingAppTransitionAspectScaledThumb(in Bitmap srcThumb, int startX,
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7b13e84..fc0148f 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -188,13 +188,25 @@
 
     void wallpaperCommandComplete(IBinder window, in Bundle result);
 
-    void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
-            float dsdx, float dtdx, float dsdy, float dtdy);
-
     /**
      * Notifies that a rectangle on the screen has been requested.
      */
     void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
 
     IWindowId getWindowId(IBinder window);
+
+    /**
+     * When the system is dozing in a low-power partially suspended state, pokes a short
+     * lived wake lock and ensures that the display is ready to accept the next frame
+     * of content drawn in the window.
+     *
+     * This mechanism is bound to the window rather than to the display manager or the
+     * power manager so that the system can ensure that the window is actually visible
+     * and prevent runaway applications from draining the battery.  This is similar to how
+     * FLAG_KEEP_SCREEN_ON works.
+     *
+     * This method is synchronous because it may need to acquire a wake lock before returning.
+     * The assumption is that this method will be called rather infrequently.
+     */
+    void pokeDrawLock(IBinder window);
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 243a0fc..779560c 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -20,7 +20,6 @@
 import android.os.Parcelable;
 import android.text.method.MetaKeyKeyListener;
 import android.util.Log;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.KeyCharacterMap;
 import android.view.KeyCharacterMap.KeyData;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1546877..1a07aee 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -16,22 +16,26 @@
 
 package android.view;
 
-import android.graphics.Canvas;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Trace;
-import android.widget.FrameLayout;
+import com.android.internal.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.LayoutRes;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.util.Xml;
+import android.widget.FrameLayout;
 
 import java.io.IOException;
 import java.lang.reflect.Constructor;
@@ -64,6 +68,7 @@
  * @see Context#getSystemService
  */
 public abstract class LayoutInflater {
+
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
@@ -90,12 +95,16 @@
     
     private HashMap<String, Boolean> mFilterMap;
 
+    private TypedValue mTempValue;
+
     private static final String TAG_MERGE = "merge";
     private static final String TAG_INCLUDE = "include";
     private static final String TAG_1995 = "blink";
     private static final String TAG_REQUEST_FOCUS = "requestFocus";
     private static final String TAG_TAG = "tag";
 
+    private static final String ATTR_LAYOUT = "layout";
+
     private static final int[] ATTRS_THEME = new int[] {
             com.android.internal.R.attr.theme };
 
@@ -361,7 +370,7 @@
      *         this is the root View; otherwise it is the root of the inflated
      *         XML file.
      */
-    public View inflate(int resource, ViewGroup root) {
+    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
         return inflate(resource, root, root != null);
     }
 
@@ -381,7 +390,7 @@
      *         this is the root View; otherwise it is the root of the inflated
      *         XML file.
      */
-    public View inflate(XmlPullParser parser, ViewGroup root) {
+    public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
         return inflate(parser, root, root != null);
     }
 
@@ -402,7 +411,7 @@
      *         attachToRoot is true, this is root; otherwise it is the root of
      *         the inflated XML file.
      */
-    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
+    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
         final Resources res = getContext().getResources();
         if (DEBUG) {
             Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
@@ -439,7 +448,7 @@
      *         attachToRoot is true, this is root; otherwise it is the root of
      *         the inflated XML file.
      */
-    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
+    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
         synchronized (mConstructorArgs) {
             Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
 
@@ -523,10 +532,10 @@
                 InflateException ex = new InflateException(e.getMessage());
                 ex.initCause(e);
                 throw ex;
-            } catch (IOException e) {
+            } catch (Exception e) {
                 InflateException ex = new InflateException(
                         parser.getPositionDescription()
-                        + ": " + e.getMessage());
+                                + ": " + e.getMessage());
                 ex.initCause(e);
                 throw ex;
             } finally {
@@ -837,7 +846,7 @@
             throws XmlPullParserException, IOException {
         int type;
 
-        final TypedArray ta = mContext.obtainStyledAttributes(
+        final TypedArray ta = view.getContext().obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.ViewTag);
         final int key = ta.getResourceId(com.android.internal.R.styleable.ViewTag_id, 0);
         final CharSequence value = ta.getText(com.android.internal.R.styleable.ViewTag_value);
@@ -856,16 +865,41 @@
         int type;
 
         if (parent instanceof ViewGroup) {
-            final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+            Context context = inheritContext ? parent.getContext() : mContext;
+
+            // Apply a theme wrapper, if requested.
+            final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+            final int themeResId = ta.getResourceId(0, 0);
+            if (themeResId != 0) {
+                context = new ContextThemeWrapper(context, themeResId);
+            }
+            ta.recycle();
+
+            // If the layout is pointing to a theme attribute, we have to
+            // massage the value to get a resource identifier out of it.
+            int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
             if (layout == 0) {
-                final String value = attrs.getAttributeValue(null, "layout");
-                if (value == null) {
-                    throw new InflateException("You must specifiy a layout in the"
+                final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+                if (value == null || value.length() < 1) {
+                    throw new InflateException("You must specify a layout in the"
                             + " include tag: <include layout=\"@layout/layoutID\" />");
-                } else {
-                    throw new InflateException("You must specifiy a valid layout "
-                            + "reference. The layout ID " + value + " is not valid.");
                 }
+
+                layout = context.getResources().getIdentifier(value.substring(1), null, null);
+            }
+
+            // The layout might be referencing a theme attribute.
+            if (mTempValue == null) {
+                mTempValue = new TypedValue();
+            }
+            if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
+                layout = mTempValue.resourceId;
+            }
+
+            if (layout == 0) {
+                final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+                throw new InflateException("You must specify a valid layout "
+                        + "reference. The layout ID " + value + " is not valid.");
             } else {
                 final XmlResourceParser childParser =
                         getContext().getResources().getLayout(layout);
@@ -893,6 +927,14 @@
                                 inheritContext);
                         final ViewGroup group = (ViewGroup) parent;
 
+                        final TypedArray a = context.obtainStyledAttributes(
+                                attrs, R.styleable.Include);
+                        final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                        final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                        final boolean hasWidth = a.hasValue(R.styleable.Include_layout_width);
+                        final boolean hasHeight = a.hasValue(R.styleable.Include_layout_height);
+                        a.recycle();
+
                         // We try to load the layout params set in the <include /> tag. If
                         // they don't exist, we will rely on the layout params set in the
                         // included XML file.
@@ -902,28 +944,21 @@
                         // successfully loaded layout params from the <include /> tag,
                         // false means we need to rely on the included layout params.
                         ViewGroup.LayoutParams params = null;
-                        try {
-                            params = group.generateLayoutParams(attrs);
-                        } catch (RuntimeException e) {
-                            params = group.generateLayoutParams(childAttrs);
-                        } finally {
-                            if (params != null) {
-                                view.setLayoutParams(params);
+                        if (hasWidth && hasHeight) {
+                            try {
+                                params = group.generateLayoutParams(attrs);
+                            } catch (RuntimeException e) {
+                                // Ignore, just fail over to child attrs.
                             }
                         }
+                        if (params == null) {
+                            params = group.generateLayoutParams(childAttrs);
+                        }
+                        view.setLayoutParams(params);
 
                         // Inflate all children.
                         rInflate(childParser, view, childAttrs, true, true);
 
-                        // Attempt to override the included layout's android:id with the
-                        // one set on the <include /> tag itself.
-                        TypedArray a = mContext.obtainStyledAttributes(attrs,
-                            com.android.internal.R.styleable.View, 0, 0);
-                        int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
-                        // While we're at it, let's try to override android:visibility.
-                        int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
-                        a.recycle();
-
                         if (id != View.NO_ID) {
                             view.setId(id);
                         }
diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java
index 7157bc5..0c2e9cf 100644
--- a/core/java/android/view/Menu.java
+++ b/core/java/android/view/Menu.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -148,7 +149,7 @@
      * @param titleRes Resource identifier of title string.
      * @return The newly added menu item.
      */
-    public MenuItem add(int titleRes);
+    public MenuItem add(@StringRes int titleRes);
 
     /**
      * Add a new item to the menu. This item displays the given title for its
@@ -182,7 +183,7 @@
      * @param titleRes Resource identifier of title string.
      * @return The newly added menu item.
      */
-    public MenuItem add(int groupId, int itemId, int order, int titleRes);
+    public MenuItem add(int groupId, int itemId, int order, @StringRes int titleRes);
 
     /**
      * Add a new sub-menu to the menu. This item displays the given title for
@@ -202,7 +203,7 @@
      * @param titleRes Resource identifier of title string.
      * @return The newly added sub-menu
      */
-    SubMenu addSubMenu(final int titleRes);
+    SubMenu addSubMenu(@StringRes final int titleRes);
 
     /**
      * Add a new sub-menu to the menu. This item displays the given
@@ -239,7 +240,7 @@
      * @param titleRes Resource identifier of title string.
      * @return The newly added sub-menu
      */
-    SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes);
+    SubMenu addSubMenu(int groupId, int itemId, int order, @StringRes int titleRes);
 
     /**
      * Add a group of menu items corresponding to actions that can be performed
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 5811c17..b49a59e 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -21,11 +21,15 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.MenuRes;
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -101,7 +105,7 @@
      * @param menu The Menu to inflate into. The items and submenus will be
      *            added to this Menu.
      */
-    public void inflate(int menuRes, Menu menu) {
+    public void inflate(@MenuRes int menuRes, Menu menu) {
         XmlResourceParser parser = null;
         try {
             parser = mContext.getResources().getLayout(menuRes);
@@ -333,6 +337,11 @@
         
         private ActionProvider itemActionProvider;
 
+        private ColorStateList itemIconTintList;
+        private boolean itemIconTintListSet;
+        private PorterDuff.Mode itemIconTintMode;
+        private boolean itemIconTintModeSet;
+
         private static final int defaultGroupId = NO_ID;
         private static final int defaultItemId = NO_ID;
         private static final int defaultItemCategory = 0;
@@ -423,6 +432,23 @@
                 itemActionProvider = null;
             }
 
+            if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTint)) {
+                itemIconTintList = a.getColorStateList(
+                        com.android.internal.R.styleable.MenuItem_iconTint);
+                itemIconTintListSet = true;
+            } else {
+                itemIconTintList = null;
+                itemIconTintListSet = false;
+            }
+            if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
+                itemIconTintMode = Drawable.parseTintMode(
+                        a.getInt(com.android.internal.R.styleable.MenuItem_iconTintMode, -1), null);
+                itemIconTintModeSet = true;
+            } else {
+                itemIconTintMode = null;
+                itemIconTintModeSet = false;
+            }
+
             a.recycle();
 
             itemAdded = false;
@@ -485,6 +511,13 @@
             if (itemActionProvider != null) {
                 item.setActionProvider(itemActionProvider);
             }
+
+            if (itemIconTintListSet) {
+                item.setIconTintList(itemIconTintList);
+            }
+            if (itemIconTintModeSet) {
+                item.setIconTintMode(itemIconTintMode);
+            }
         }
 
         public MenuItem addItem() {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index e706c9c..2948007 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -16,8 +16,13 @@
 
 package android.view;
 
+import android.annotation.DrawableRes;
+import android.annotation.LayoutRes;
+import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View.OnCreateContextMenuListener;
@@ -165,7 +170,7 @@
      * @see #setTitleCondensed(CharSequence)
      */
     
-    public MenuItem setTitle(int title);
+    public MenuItem setTitle(@StringRes int title);
 
     /**
      * Retrieve the current title of the item.
@@ -214,7 +219,7 @@
      * @param iconRes The new icon (as a resource ID) to be displayed.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setIcon(int iconRes);
+    public MenuItem setIcon(@DrawableRes int iconRes);
     
     /**
      * Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
@@ -511,7 +516,7 @@
      *
      * @see #setShowAsAction(int)
      */
-    public MenuItem setActionView(int resId);
+    public MenuItem setActionView(@LayoutRes int resId);
 
     /**
      * Returns the currently set action view for this menu item.
@@ -596,4 +601,26 @@
      * @return This menu item instance for call chaining
      */
     public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
+
+    /**
+     * Applies a tint to the icon drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable)}
+     * will automatically mutate the drawable and apply the specified tint and tint mode.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @return This menu item instance for call chaining
+     */
+    public MenuItem setIconTintList(ColorStateList tint);
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setIconTintList(ColorStateList)} to the icon drawable. The default mode is {@link
+     * PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     * @return This menu item instance for call chaining
+     */
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode);
 }
diff --git a/core/java/android/view/PhoneFallbackEventHandler.java b/core/java/android/view/PhoneFallbackEventHandler.java
new file mode 100644
index 0000000..fbf5732
--- /dev/null
+++ b/core/java/android/view/PhoneFallbackEventHandler.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.app.KeyguardManager;
+import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.media.session.MediaSessionLegacyHelper;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+/**
+ * @hide
+ */
+public class PhoneFallbackEventHandler implements FallbackEventHandler {
+    private static String TAG = "PhoneFallbackEventHandler";
+    private static final boolean DEBUG = false;
+
+    Context mContext;
+    View mView;
+
+    AudioManager mAudioManager;
+    KeyguardManager mKeyguardManager;
+    SearchManager mSearchManager;
+    TelephonyManager mTelephonyManager;
+
+    public PhoneFallbackEventHandler(Context context) {
+        mContext = context;
+    }
+
+    public void setView(View v) {
+        mView = v;
+    }
+
+    public void preDispatchKeyEvent(KeyEvent event) {
+        getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
+    }
+
+    public boolean dispatchKeyEvent(KeyEvent event) {
+
+        final int action = event.getAction();
+        final int keyCode = event.getKeyCode();
+
+        if (action == KeyEvent.ACTION_DOWN) {
+            return onKeyDown(keyCode, event);
+        } else {
+            return onKeyUp(keyCode, event);
+        }
+    }
+
+    boolean onKeyDown(int keyCode, KeyEvent event) {
+        /* ****************************************************************************
+         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
+         * See the comment in PhoneWindow.onKeyDown
+         * ****************************************************************************/
+        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+                return true;
+            }
+
+
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+                 * to avoid music playback */
+                if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+                    return true;  // suppress key event
+                }
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                handleMediaKeyEvent(event);
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_CALL: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                    break;
+                }
+                if (event.getRepeatCount() == 0) {
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+                    dispatcher.performedLongPress(event);
+                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                    // launch the VoiceDialer
+                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    try {
+                        sendCloseSystemWindows();
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        startCallActivity();
+                    }
+                }
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_CAMERA: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                    break;
+                }
+                if (event.getRepeatCount() == 0) {
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+                    dispatcher.performedLongPress(event);
+                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                    sendCloseSystemWindows();
+                    // Broadcast an intent that the Camera button was longpressed
+                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
+                            null, null, null, 0, null, null);
+                }
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_SEARCH: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
+                    break;
+                }
+                if (event.getRepeatCount() == 0) {
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+                    Configuration config = mContext.getResources().getConfiguration();
+                    if (config.keyboard == Configuration.KEYBOARD_NOKEYS
+                            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+                        // launch the search activity
+                        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        try {
+                            mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                            sendCloseSystemWindows();
+                            getSearchManager().stopSearch();
+                            mContext.startActivity(intent);
+                            // Only clear this if we successfully start the
+                            // activity; otherwise we will allow the normal short
+                            // press action to be performed.
+                            dispatcher.performedLongPress(event);
+                            return true;
+                        } catch (ActivityNotFoundException e) {
+                            // Ignore
+                        }
+                    }
+                }
+                break;
+            }
+        }
+        return false;
+    }
+
+    boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (DEBUG) {
+            Slog.d(TAG, "up " + keyCode);
+        }
+        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
+        if (dispatcher != null) {
+            dispatcher.handleUpEvent(event);
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                if (!event.isCanceled()) {
+                    MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+                }
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                handleMediaKeyEvent(event);
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_CAMERA: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                    break;
+                }
+                if (event.isTracking() && !event.isCanceled()) {
+                    // Add short press behavior here if desired
+                }
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_CALL: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                    break;
+                }
+                if (event.isTracking() && !event.isCanceled()) {
+                    startCallActivity();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void startCallActivity() {
+        sendCloseSystemWindows();
+        Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            mContext.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
+        }
+    }
+
+    SearchManager getSearchManager() {
+        if (mSearchManager == null) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        }
+        return mSearchManager;
+    }
+
+    TelephonyManager getTelephonyManager() {
+        if (mTelephonyManager == null) {
+            mTelephonyManager = (TelephonyManager)mContext.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+        }
+        return mTelephonyManager;
+    }
+
+    KeyguardManager getKeyguardManager() {
+        if (mKeyguardManager == null) {
+            mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        }
+        return mKeyguardManager;
+    }
+
+    AudioManager getAudioManager() {
+        if (mAudioManager == null) {
+            mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+        }
+        return mAudioManager;
+    }
+
+    void sendCloseSystemWindows() {
+        PhoneWindow.sendCloseSystemWindows(mContext, null);
+    }
+
+    private void handleMediaKeyEvent(KeyEvent keyEvent) {
+        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+    }
+}
+
diff --git a/core/java/android/view/PhoneLayoutInflater.java b/core/java/android/view/PhoneLayoutInflater.java
new file mode 100644
index 0000000..7d89a0b
--- /dev/null
+++ b/core/java/android/view/PhoneLayoutInflater.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * @hide
+ */
+public class PhoneLayoutInflater extends LayoutInflater {
+    private static final String[] sClassPrefixList = {
+        "android.widget.",
+        "android.webkit.",
+        "android.app."
+    };
+
+    /**
+     * Instead of instantiating directly, you should retrieve an instance
+     * through {@link Context#getSystemService}
+     *
+     * @param context The Context in which in which to find resources and other
+     *                application-specific things.
+     *
+     * @see Context#getSystemService
+     */
+    public PhoneLayoutInflater(Context context) {
+        super(context);
+    }
+
+    protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
+        super(original, newContext);
+    }
+
+    /** Override onCreateView to instantiate names that correspond to the
+        widgets known to the Widget factory. If we don't find a match,
+        call through to our super class.
+    */
+    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
+        for (String prefix : sClassPrefixList) {
+            try {
+                View view = createView(name, prefix, attrs);
+                if (view != null) {
+                    return view;
+                }
+            } catch (ClassNotFoundException e) {
+                // In this case we want to let the base class take a crack
+                // at it.
+            }
+        }
+
+        return super.onCreateView(name, attrs);
+    }
+
+    public LayoutInflater cloneInContext(Context newContext) {
+        return new PhoneLayoutInflater(this, newContext);
+    }
+}
+
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
new file mode 100644
index 0000000..8aef18a
--- /dev/null
+++ b/core/java/android/view/PhoneWindow.java
@@ -0,0 +1,4816 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.getMode;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams.*;
+
+import android.app.ActivityManagerNative;
+import android.app.SearchManager;
+import android.os.UserHandle;
+
+import com.android.internal.R;
+import com.android.internal.view.RootViewSurfaceTaker;
+import com.android.internal.view.StandaloneActionMode;
+import com.android.internal.view.menu.ContextMenuBuilder;
+import com.android.internal.view.menu.IconMenuPresenter;
+import com.android.internal.view.menu.ListMenuPresenter;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
+import com.android.internal.widget.ActionBarContextView;
+import com.android.internal.widget.BackgroundFallback;
+import com.android.internal.widget.DecorContentParent;
+import com.android.internal.widget.SwipeDismissLayout;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionLegacyHelper;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.AndroidRuntimeException;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Android-specific Window.
+ * <p>
+ * todo: need to pull the generic functionality out into a base class
+ * in android.widget.
+ *
+ * @hide
+ */
+public class PhoneWindow extends Window implements MenuBuilder.Callback {
+
+    private final static String TAG = "PhoneWindow";
+
+    private final static boolean SWEEP_OPEN_MENU = false;
+
+    private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
+
+    private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
+            (1 << FEATURE_CUSTOM_TITLE) |
+            (1 << FEATURE_CONTENT_TRANSITIONS) |
+            (1 << FEATURE_ACTIVITY_TRANSITIONS) |
+            (1 << FEATURE_ACTION_MODE_OVERLAY);
+
+    private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
+
+    /**
+     * Simple callback used by the context menu and its submenus. The options
+     * menu submenus do not use this (their behavior is more complex).
+     */
+    final DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU);
+
+    final TypedValue mMinWidthMajor = new TypedValue();
+    final TypedValue mMinWidthMinor = new TypedValue();
+    TypedValue mFixedWidthMajor;
+    TypedValue mFixedWidthMinor;
+    TypedValue mFixedHeightMajor;
+    TypedValue mFixedHeightMinor;
+    TypedValue mOutsetBottom;
+
+    // This is the top-level view of the window, containing the window decor.
+    private DecorView mDecor;
+
+    // This is the view in which the window contents are placed. It is either
+    // mDecor itself, or a child of mDecor where the contents go.
+    private ViewGroup mContentParent;
+
+    private ViewGroup mContentRoot;
+
+    SurfaceHolder.Callback2 mTakeSurfaceCallback;
+
+    InputQueue.Callback mTakeInputQueueCallback;
+
+    private boolean mIsFloating;
+
+    private LayoutInflater mLayoutInflater;
+
+    private TextView mTitleView;
+
+    private DecorContentParent mDecorContentParent;
+    private ActionMenuPresenterCallback mActionMenuPresenterCallback;
+    private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
+
+    private TransitionManager mTransitionManager;
+    private Scene mContentScene;
+
+    // The icon resource has been explicitly set elsewhere
+    // and should not be overwritten with a default.
+    static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
+
+    // The logo resource has been explicitly set elsewhere
+    // and should not be overwritten with a default.
+    static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
+
+    // The icon resource is currently configured to use the system fallback
+    // as no default was previously specified. Anything can override this.
+    static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2;
+
+    int mResourcesSetFlags;
+    int mIconRes;
+    int mLogoRes;
+
+    private DrawableFeatureState[] mDrawables;
+
+    private PanelFeatureState[] mPanels;
+
+    /**
+     * The panel that is prepared or opened (the most recent one if there are
+     * multiple panels). Shortcuts will go to this panel. It gets set in
+     * {@link #preparePanel} and cleared in {@link #closePanel}.
+     */
+    private PanelFeatureState mPreparedPanel;
+
+    /**
+     * The keycode that is currently held down (as a modifier) for chording. If
+     * this is 0, there is no key held down.
+     */
+    private int mPanelChordingKey;
+
+    private ImageView mLeftIconView;
+
+    private ImageView mRightIconView;
+
+    private ProgressBar mCircularProgressBar;
+
+    private ProgressBar mHorizontalProgressBar;
+
+    private int mBackgroundResource = 0;
+    private int mBackgroundFallbackResource = 0;
+
+    private Drawable mBackgroundDrawable;
+
+    private float mElevation;
+
+    /** Whether window content should be clipped to the background outline. */
+    private boolean mClipToOutline;
+
+    private int mFrameResource = 0;
+
+    private int mTextColor = 0;
+    private int mStatusBarColor = 0;
+    private int mNavigationBarColor = 0;
+    private boolean mForcedStatusBarColor = false;
+    private boolean mForcedNavigationBarColor = false;
+
+    private CharSequence mTitle = null;
+
+    private int mTitleColor = 0;
+
+    private boolean mAlwaysReadCloseOnTouchAttr = false;
+
+    private ContextMenuBuilder mContextMenu;
+    private MenuDialogHelper mContextMenuHelper;
+    private boolean mClosingActionMenu;
+
+    private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
+    private MediaController mMediaController;
+
+    private AudioManager mAudioManager;
+    private KeyguardManager mKeyguardManager;
+
+    private int mUiOptions = 0;
+
+    private boolean mInvalidatePanelMenuPosted;
+    private int mInvalidatePanelMenuFeatures;
+    private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
+        @Override public void run() {
+            for (int i = 0; i <= FEATURE_MAX; i++) {
+                if ((mInvalidatePanelMenuFeatures & 1 << i) != 0) {
+                    doInvalidatePanelMenu(i);
+                }
+            }
+            mInvalidatePanelMenuPosted = false;
+            mInvalidatePanelMenuFeatures = 0;
+        }
+    };
+
+    private Transition mEnterTransition = null;
+    private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
+    private Transition mExitTransition = null;
+    private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
+    private Transition mSharedElementEnterTransition = null;
+    private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
+    private Transition mSharedElementExitTransition = null;
+    private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION;
+    private Boolean mAllowReturnTransitionOverlap;
+    private Boolean mAllowEnterTransitionOverlap;
+    private long mBackgroundFadeDurationMillis = -1;
+    private Boolean mSharedElementsUseOverlay;
+
+    private Rect mTempRect;
+
+    static class WindowManagerHolder {
+        static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService("window"));
+    }
+
+    static final RotationWatcher sRotationWatcher = new RotationWatcher();
+
+    public PhoneWindow(Context context) {
+        super(context);
+        mLayoutInflater = LayoutInflater.from(context);
+    }
+
+    @Override
+    public final void setContainer(Window container) {
+        super.setContainer(container);
+    }
+
+    @Override
+    public boolean requestFeature(int featureId) {
+        if (mContentParent != null) {
+            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
+        }
+        final int features = getFeatures();
+        final int newFeatures = features | (1 << featureId);
+        if ((newFeatures & (1 << FEATURE_CUSTOM_TITLE)) != 0 &&
+                (newFeatures & ~CUSTOM_TITLE_COMPATIBLE_FEATURES) != 0) {
+            // Another feature is enabled and the user is trying to enable the custom title feature
+            // or custom title feature is enabled and the user is trying to enable another feature
+            throw new AndroidRuntimeException(
+                    "You cannot combine custom titles with other title features");
+        }
+        if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) {
+            return false; // Ignore. No title dominates.
+        }
+        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) {
+            // Remove the action bar feature if we have no title. No title dominates.
+            removeFeature(FEATURE_ACTION_BAR);
+        }
+
+        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
+            throw new AndroidRuntimeException(
+                    "You cannot combine swipe dismissal and the action bar.");
+        }
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
+            throw new AndroidRuntimeException(
+                    "You cannot combine swipe dismissal and the action bar.");
+        }
+
+        if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
+                getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
+        }
+        return super.requestFeature(featureId);
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions) {
+        mUiOptions = uiOptions;
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions, int mask) {
+        mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
+    }
+
+    @Override
+    public TransitionManager getTransitionManager() {
+        return mTransitionManager;
+    }
+
+    @Override
+    public void setTransitionManager(TransitionManager tm) {
+        mTransitionManager = tm;
+    }
+
+    @Override
+    public Scene getContentScene() {
+        return mContentScene;
+    }
+
+    @Override
+    public void setContentView(int layoutResID) {
+        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
+        // decor, when theme attributes and the like are crystalized. Do not check the feature
+        // before this happens.
+        if (mContentParent == null) {
+            installDecor();
+        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            mContentParent.removeAllViews();
+        }
+
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
+                    getContext());
+            transitionTo(newScene);
+        } else {
+            mLayoutInflater.inflate(layoutResID, mContentParent);
+        }
+        final Callback cb = getCallback();
+        if (cb != null && !isDestroyed()) {
+            cb.onContentChanged();
+        }
+    }
+
+    @Override
+    public void setContentView(View view) {
+        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+    }
+
+    @Override
+    public void setContentView(View view, ViewGroup.LayoutParams params) {
+        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
+        // decor, when theme attributes and the like are crystalized. Do not check the feature
+        // before this happens.
+        if (mContentParent == null) {
+            installDecor();
+        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            mContentParent.removeAllViews();
+        }
+
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            view.setLayoutParams(params);
+            final Scene newScene = new Scene(mContentParent, view);
+            transitionTo(newScene);
+        } else {
+            mContentParent.addView(view, params);
+        }
+        final Callback cb = getCallback();
+        if (cb != null && !isDestroyed()) {
+            cb.onContentChanged();
+        }
+    }
+
+    @Override
+    public void addContentView(View view, ViewGroup.LayoutParams params) {
+        if (mContentParent == null) {
+            installDecor();
+        }
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            // TODO Augment the scenes/transitions API to support this.
+            Log.v(TAG, "addContentView does not support content transitions");
+        }
+        mContentParent.addView(view, params);
+        final Callback cb = getCallback();
+        if (cb != null && !isDestroyed()) {
+            cb.onContentChanged();
+        }
+    }
+
+    private void transitionTo(Scene scene) {
+        if (mContentScene == null) {
+            scene.enter();
+        } else {
+            mTransitionManager.transitionTo(scene);
+        }
+        mContentScene = scene;
+    }
+
+    @Override
+    public View getCurrentFocus() {
+        return mDecor != null ? mDecor.findFocus() : null;
+    }
+
+    @Override
+    public void takeSurface(SurfaceHolder.Callback2 callback) {
+        mTakeSurfaceCallback = callback;
+    }
+
+    public void takeInputQueue(InputQueue.Callback callback) {
+        mTakeInputQueueCallback = callback;
+    }
+
+    @Override
+    public boolean isFloating() {
+        return mIsFloating;
+    }
+
+    /**
+     * Return a LayoutInflater instance that can be used to inflate XML view layout
+     * resources for use in this Window.
+     *
+     * @return LayoutInflater The shared LayoutInflater.
+     */
+    @Override
+    public LayoutInflater getLayoutInflater() {
+        return mLayoutInflater;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (mTitleView != null) {
+            mTitleView.setText(title);
+        } else if (mDecorContentParent != null) {
+            mDecorContentParent.setWindowTitle(title);
+        }
+        mTitle = title;
+    }
+
+    @Override
+    @Deprecated
+    public void setTitleColor(int textColor) {
+        if (mTitleView != null) {
+            mTitleView.setTextColor(textColor);
+        }
+        mTitleColor = textColor;
+    }
+
+    /**
+     * Prepares the panel to either be opened or chorded. This creates the Menu
+     * instance for the panel and populates it via the Activity callbacks.
+     *
+     * @param st The panel state to prepare.
+     * @param event The event that triggered the preparing of the panel.
+     * @return Whether the panel was prepared. If the panel should not be shown,
+     *         returns false.
+     */
+    public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
+        if (isDestroyed()) {
+            return false;
+        }
+
+        // Already prepared (isPrepared will be reset to false later)
+        if (st.isPrepared) {
+            return true;
+        }
+
+        if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
+            // Another Panel is prepared and possibly open, so close it
+            closePanel(mPreparedPanel, false);
+        }
+
+        final Callback cb = getCallback();
+
+        if (cb != null) {
+            st.createdPanelView = cb.onCreatePanelView(st.featureId);
+        }
+
+        final boolean isActionBarMenu =
+                (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
+
+        if (isActionBarMenu && mDecorContentParent != null) {
+            // Enforce ordering guarantees around events so that the action bar never
+            // dispatches menu-related events before the panel is prepared.
+            mDecorContentParent.setMenuPrepared();
+        }
+
+        if (st.createdPanelView == null) {
+            // Init the panel state's menu--return false if init failed
+            if (st.menu == null || st.refreshMenuContent) {
+                if (st.menu == null) {
+                    if (!initializePanelMenu(st) || (st.menu == null)) {
+                        return false;
+                    }
+                }
+
+                if (isActionBarMenu && mDecorContentParent != null) {
+                    if (mActionMenuPresenterCallback == null) {
+                        mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
+                    }
+                    mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
+                }
+
+                // Call callback, and return if it doesn't want to display menu.
+
+                // Creating the panel menu will involve a lot of manipulation;
+                // don't dispatch change events to presenters until we're done.
+                st.menu.stopDispatchingItemsChanged();
+                if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
+                    // Ditch the menu created above
+                    st.setMenu(null);
+
+                    if (isActionBarMenu && mDecorContentParent != null) {
+                        // Don't show it in the action bar either
+                        mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
+                    }
+
+                    return false;
+                }
+
+                st.refreshMenuContent = false;
+            }
+
+            // Callback and return if the callback does not want to show the menu
+
+            // Preparing the panel menu can involve a lot of manipulation;
+            // don't dispatch change events to presenters until we're done.
+            st.menu.stopDispatchingItemsChanged();
+
+            // Restore action view state before we prepare. This gives apps
+            // an opportunity to override frozen/restored state in onPrepare.
+            if (st.frozenActionViewState != null) {
+                st.menu.restoreActionViewStates(st.frozenActionViewState);
+                st.frozenActionViewState = null;
+            }
+
+            if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
+                if (isActionBarMenu && mDecorContentParent != null) {
+                    // The app didn't want to show the menu for now but it still exists.
+                    // Clear it out of the action bar.
+                    mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
+                }
+                st.menu.startDispatchingItemsChanged();
+                return false;
+            }
+
+            // Set the proper keymap
+            KeyCharacterMap kmap = KeyCharacterMap.load(
+                    event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
+            st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
+            st.menu.setQwertyMode(st.qwertyMode);
+            st.menu.startDispatchingItemsChanged();
+        }
+
+        // Set other state
+        st.isPrepared = true;
+        st.isHandled = false;
+        mPreparedPanel = st;
+
+        return true;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // Action bars handle their own menu state
+        if (mDecorContentParent == null) {
+            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+            if ((st != null) && (st.menu != null)) {
+                if (st.isOpen) {
+                    // Freeze state
+                    final Bundle state = new Bundle();
+                    if (st.iconMenuPresenter != null) {
+                        st.iconMenuPresenter.saveHierarchyState(state);
+                    }
+                    if (st.listMenuPresenter != null) {
+                        st.listMenuPresenter.saveHierarchyState(state);
+                    }
+
+                    // Remove the menu views since they need to be recreated
+                    // according to the new configuration
+                    clearMenuViews(st);
+
+                    // Re-open the same menu
+                    reopenMenu(false);
+
+                    // Restore state
+                    if (st.iconMenuPresenter != null) {
+                        st.iconMenuPresenter.restoreHierarchyState(state);
+                    }
+                    if (st.listMenuPresenter != null) {
+                        st.listMenuPresenter.restoreHierarchyState(state);
+                    }
+
+                } else {
+                    // Clear menu views so on next menu opening, it will use
+                    // the proper layout
+                    clearMenuViews(st);
+                }
+            }
+        }
+    }
+
+    private static void clearMenuViews(PanelFeatureState st) {
+        // This can be called on config changes, so we should make sure
+        // the views will be reconstructed based on the new orientation, etc.
+
+        // Allow the callback to create a new panel view
+        st.createdPanelView = null;
+
+        // Causes the decor view to be recreated
+        st.refreshDecorView = true;
+
+        st.clearMenuPresenters();
+    }
+
+    @Override
+    public final void openPanel(int featureId, KeyEvent event) {
+        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                mDecorContentParent.canShowOverflowMenu() &&
+                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
+            mDecorContentParent.showOverflowMenu();
+        } else {
+            openPanel(getPanelState(featureId, true), event);
+        }
+    }
+
+    private void openPanel(final PanelFeatureState st, KeyEvent event) {
+        // System.out.println("Open panel: isOpen=" + st.isOpen);
+
+        // Already open, return
+        if (st.isOpen || isDestroyed()) {
+            return;
+        }
+
+        // Don't open an options panel for honeycomb apps on xlarge devices.
+        // (The app should be using an action bar for menu items.)
+        if (st.featureId == FEATURE_OPTIONS_PANEL) {
+            Context context = getContext();
+            Configuration config = context.getResources().getConfiguration();
+            boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) ==
+                    Configuration.SCREENLAYOUT_SIZE_XLARGE;
+            boolean isHoneycombApp = context.getApplicationInfo().targetSdkVersion >=
+                    android.os.Build.VERSION_CODES.HONEYCOMB;
+
+            if (isXLarge && isHoneycombApp) {
+                return;
+            }
+        }
+
+        Callback cb = getCallback();
+        if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
+            // Callback doesn't want the menu to open, reset any state
+            closePanel(st, true);
+            return;
+        }
+
+        final WindowManager wm = getWindowManager();
+        if (wm == null) {
+            return;
+        }
+
+        // Prepare panel (should have been done before, but just in case)
+        if (!preparePanel(st, event)) {
+            return;
+        }
+
+        int width = WRAP_CONTENT;
+        if (st.decorView == null || st.refreshDecorView) {
+            if (st.decorView == null) {
+                // Initialize the panel decor, this will populate st.decorView
+                if (!initializePanelDecor(st) || (st.decorView == null))
+                    return;
+            } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
+                // Decor needs refreshing, so remove its views
+                st.decorView.removeAllViews();
+            }
+
+            // This will populate st.shownPanelView
+            if (!initializePanelContent(st) || !st.hasPanelItems()) {
+                return;
+            }
+
+            ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
+            if (lp == null) {
+                lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
+            }
+
+            int backgroundResId;
+            if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
+                // If the contents is fill parent for the width, set the
+                // corresponding background
+                backgroundResId = st.fullBackground;
+                width = MATCH_PARENT;
+            } else {
+                // Otherwise, set the normal panel background
+                backgroundResId = st.background;
+            }
+            st.decorView.setWindowBackground(getContext().getDrawable(
+                    backgroundResId));
+
+            ViewParent shownPanelParent = st.shownPanelView.getParent();
+            if (shownPanelParent != null && shownPanelParent instanceof ViewGroup) {
+                ((ViewGroup) shownPanelParent).removeView(st.shownPanelView);
+            }
+            st.decorView.addView(st.shownPanelView, lp);
+
+            /*
+             * Give focus to the view, if it or one of its children does not
+             * already have it.
+             */
+            if (!st.shownPanelView.hasFocus()) {
+                st.shownPanelView.requestFocus();
+            }
+        } else if (!st.isInListMode()) {
+            width = MATCH_PARENT;
+        } else if (st.createdPanelView != null) {
+            // If we already had a panel view, carry width=MATCH_PARENT through
+            // as we did above when it was created.
+            ViewGroup.LayoutParams lp = st.createdPanelView.getLayoutParams();
+            if (lp != null && lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
+                width = MATCH_PARENT;
+            }
+        }
+
+        st.isHandled = false;
+
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                width, WRAP_CONTENT,
+                st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
+                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                st.decorView.mDefaultOpacity);
+
+        if (st.isCompact) {
+            lp.gravity = getOptionsPanelGravity();
+            sRotationWatcher.addWindow(this);
+        } else {
+            lp.gravity = st.gravity;
+        }
+
+        lp.windowAnimations = st.windowAnimations;
+
+        wm.addView(st.decorView, lp);
+        st.isOpen = true;
+        // Log.v(TAG, "Adding main menu to window manager.");
+    }
+
+    @Override
+    public final void closePanel(int featureId) {
+        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                mDecorContentParent.canShowOverflowMenu() &&
+                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
+            mDecorContentParent.hideOverflowMenu();
+        } else if (featureId == FEATURE_CONTEXT_MENU) {
+            closeContextMenu();
+        } else {
+            closePanel(getPanelState(featureId, true), true);
+        }
+    }
+
+    /**
+     * Closes the given panel.
+     *
+     * @param st The panel to be closed.
+     * @param doCallback Whether to notify the callback that the panel was
+     *            closed. If the panel is in the process of re-opening or
+     *            opening another panel (e.g., menu opening a sub menu), the
+     *            callback should not happen and this variable should be false.
+     *            In addition, this method internally will only perform the
+     *            callback if the panel is open.
+     */
+    public final void closePanel(PanelFeatureState st, boolean doCallback) {
+        // System.out.println("Close panel: isOpen=" + st.isOpen);
+        if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
+                mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
+            checkCloseActionMenu(st.menu);
+            return;
+        }
+
+        final ViewManager wm = getWindowManager();
+        if ((wm != null) && st.isOpen) {
+            if (st.decorView != null) {
+                wm.removeView(st.decorView);
+                // Log.v(TAG, "Removing main menu from window manager.");
+                if (st.isCompact) {
+                    sRotationWatcher.removeWindow(this);
+                }
+            }
+
+            if (doCallback) {
+                callOnPanelClosed(st.featureId, st, null);
+            }
+        }
+
+        st.isPrepared = false;
+        st.isHandled = false;
+        st.isOpen = false;
+
+        // This view is no longer shown, so null it out
+        st.shownPanelView = null;
+
+        if (st.isInExpandedMode) {
+            // Next time the menu opens, it should not be in expanded mode, so
+            // force a refresh of the decor
+            st.refreshDecorView = true;
+            st.isInExpandedMode = false;
+        }
+
+        if (mPreparedPanel == st) {
+            mPreparedPanel = null;
+            mPanelChordingKey = 0;
+        }
+    }
+
+    void checkCloseActionMenu(Menu menu) {
+        if (mClosingActionMenu) {
+            return;
+        }
+
+        mClosingActionMenu = true;
+        mDecorContentParent.dismissPopups();
+        Callback cb = getCallback();
+        if (cb != null && !isDestroyed()) {
+            cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+        }
+        mClosingActionMenu = false;
+    }
+
+    @Override
+    public final void togglePanel(int featureId, KeyEvent event) {
+        PanelFeatureState st = getPanelState(featureId, true);
+        if (st.isOpen) {
+            closePanel(st, true);
+        } else {
+            openPanel(st, event);
+        }
+    }
+
+    @Override
+    public void invalidatePanelMenu(int featureId) {
+        mInvalidatePanelMenuFeatures |= 1 << featureId;
+
+        if (!mInvalidatePanelMenuPosted && mDecor != null) {
+            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
+            mInvalidatePanelMenuPosted = true;
+        }
+    }
+
+    void doPendingInvalidatePanelMenu() {
+        if (mInvalidatePanelMenuPosted) {
+            mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
+            mInvalidatePanelMenuRunnable.run();
+        }
+    }
+
+    void doInvalidatePanelMenu(int featureId) {
+        PanelFeatureState st = getPanelState(featureId, false);
+        if (st == null) {
+            return;
+        }
+        Bundle savedActionViewStates = null;
+        if (st.menu != null) {
+            savedActionViewStates = new Bundle();
+            st.menu.saveActionViewStates(savedActionViewStates);
+            if (savedActionViewStates.size() > 0) {
+                st.frozenActionViewState = savedActionViewStates;
+            }
+            // This will be started again when the panel is prepared.
+            st.menu.stopDispatchingItemsChanged();
+            st.menu.clear();
+        }
+        st.refreshMenuContent = true;
+        st.refreshDecorView = true;
+
+        // Prepare the options panel if we have an action bar
+        if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
+                && mDecorContentParent != null) {
+            st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
+            if (st != null) {
+                st.isPrepared = false;
+                preparePanel(st, null);
+            }
+        }
+    }
+
+    /**
+     * Called when the panel key is pushed down.
+     * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
+     * @param event The key event.
+     * @return Whether the key was handled.
+     */
+    public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
+        final int keyCode = event.getKeyCode();
+
+        if (event.getRepeatCount() == 0) {
+            // The panel key was pushed, so set the chording key
+            mPanelChordingKey = keyCode;
+
+            PanelFeatureState st = getPanelState(featureId, false);
+            if (st != null && !st.isOpen) {
+                return preparePanel(st, event);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Called when the panel key is released.
+     * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
+     * @param event The key event.
+     */
+    public final void onKeyUpPanel(int featureId, KeyEvent event) {
+        // The panel key was released, so clear the chording key
+        if (mPanelChordingKey != 0) {
+            mPanelChordingKey = 0;
+
+            final PanelFeatureState st = getPanelState(featureId, false);
+
+            if (event.isCanceled() || (mDecor != null && mDecor.mPrimaryActionMode != null) ||
+                    (st == null)) {
+                return;
+            }
+
+            boolean playSoundEffect = false;
+            if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                    mDecorContentParent.canShowOverflowMenu() &&
+                    !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
+                if (!mDecorContentParent.isOverflowMenuShowing()) {
+                    if (!isDestroyed() && preparePanel(st, event)) {
+                        playSoundEffect = mDecorContentParent.showOverflowMenu();
+                    }
+                } else {
+                    playSoundEffect = mDecorContentParent.hideOverflowMenu();
+                }
+            } else {
+                if (st.isOpen || st.isHandled) {
+
+                    // Play the sound effect if the user closed an open menu (and not if
+                    // they just released a menu shortcut)
+                    playSoundEffect = st.isOpen;
+
+                    // Close menu
+                    closePanel(st, true);
+
+                } else if (st.isPrepared) {
+                    boolean show = true;
+                    if (st.refreshMenuContent) {
+                        // Something may have invalidated the menu since we prepared it.
+                        // Re-prepare it to refresh.
+                        st.isPrepared = false;
+                        show = preparePanel(st, event);
+                    }
+
+                    if (show) {
+                        // Write 'menu opened' to event log
+                        EventLog.writeEvent(50001, 0);
+
+                        // Show menu
+                        openPanel(st, event);
+
+                        playSoundEffect = true;
+                    }
+                }
+            }
+
+            if (playSoundEffect) {
+                AudioManager audioManager = (AudioManager) getContext().getSystemService(
+                        Context.AUDIO_SERVICE);
+                if (audioManager != null) {
+                    audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
+                } else {
+                    Log.w(TAG, "Couldn't get audio manager");
+                }
+            }
+        }
+    }
+
+    @Override
+    public final void closeAllPanels() {
+        final ViewManager wm = getWindowManager();
+        if (wm == null) {
+            return;
+        }
+
+        final PanelFeatureState[] panels = mPanels;
+        final int N = panels != null ? panels.length : 0;
+        for (int i = 0; i < N; i++) {
+            final PanelFeatureState panel = panels[i];
+            if (panel != null) {
+                closePanel(panel, true);
+            }
+        }
+
+        closeContextMenu();
+    }
+
+    /**
+     * Closes the context menu. This notifies the menu logic of the close, along
+     * with dismissing it from the UI.
+     */
+    private synchronized void closeContextMenu() {
+        if (mContextMenu != null) {
+            mContextMenu.close();
+            dismissContextMenu();
+        }
+    }
+
+    /**
+     * Dismisses just the context menu UI. To close the context menu, use
+     * {@link #closeContextMenu()}.
+     */
+    private synchronized void dismissContextMenu() {
+        mContextMenu = null;
+
+        if (mContextMenuHelper != null) {
+            mContextMenuHelper.dismiss();
+            mContextMenuHelper = null;
+        }
+    }
+
+    @Override
+    public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
+        return performPanelShortcut(getPanelState(featureId, false), keyCode, event, flags);
+    }
+
+    private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
+            int flags) {
+        if (event.isSystem() || (st == null)) {
+            return false;
+        }
+
+        boolean handled = false;
+
+        // Only try to perform menu shortcuts if preparePanel returned true (possible false
+        // return value from application not wanting to show the menu).
+        if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
+            // The menu is prepared now, perform the shortcut on it
+            handled = st.menu.performShortcut(keyCode, event, flags);
+        }
+
+        if (handled) {
+            // Mark as handled
+            st.isHandled = true;
+
+            // Only close down the menu if we don't have an action bar keeping it open.
+            if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
+                closePanel(st, true);
+            }
+        }
+
+        return handled;
+    }
+
+    @Override
+    public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
+
+        PanelFeatureState st = getPanelState(featureId, true);
+        if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
+            return false;
+        }
+        if (st.menu == null) {
+            return false;
+        }
+
+        boolean res = st.menu.performIdentifierAction(id, flags);
+
+        // Only close down the menu if we don't have an action bar keeping it open.
+        if (mDecorContentParent == null) {
+            closePanel(st, true);
+        }
+
+        return res;
+    }
+
+    public PanelFeatureState findMenuPanel(Menu menu) {
+        final PanelFeatureState[] panels = mPanels;
+        final int N = panels != null ? panels.length : 0;
+        for (int i = 0; i < N; i++) {
+            final PanelFeatureState panel = panels[i];
+            if (panel != null && panel.menu == menu) {
+                return panel;
+            }
+        }
+        return null;
+    }
+
+    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+        final Callback cb = getCallback();
+        if (cb != null && !isDestroyed()) {
+            final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
+            if (panel != null) {
+                return cb.onMenuItemSelected(panel.featureId, item);
+            }
+        }
+        return false;
+    }
+
+    public void onMenuModeChange(MenuBuilder menu) {
+        reopenMenu(true);
+    }
+
+    private void reopenMenu(boolean toggleMenuMode) {
+        if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
+                (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
+                        mDecorContentParent.isOverflowMenuShowPending())) {
+            final Callback cb = getCallback();
+            if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
+                if (cb != null && !isDestroyed()) {
+                    // If we have a menu invalidation pending, do it now.
+                    if (mInvalidatePanelMenuPosted &&
+                            (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
+                        mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
+                        mInvalidatePanelMenuRunnable.run();
+                    }
+
+                    final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+
+                    // If we don't have a menu or we're waiting for a full content refresh,
+                    // forget it. This is a lingering event that no longer matters.
+                    if (st != null && st.menu != null && !st.refreshMenuContent &&
+                            cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
+                        cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
+                        mDecorContentParent.showOverflowMenu();
+                    }
+                }
+            } else {
+                mDecorContentParent.hideOverflowMenu();
+                final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+                if (st != null && cb != null && !isDestroyed()) {
+                    cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
+                }
+            }
+            return;
+        }
+
+        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+
+        if (st == null) {
+            return;
+        }
+
+        // Save the future expanded mode state since closePanel will reset it
+        boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
+
+        st.refreshDecorView = true;
+        closePanel(st, false);
+
+        // Set the expanded mode state
+        st.isInExpandedMode = newExpandedMode;
+
+        openPanel(st, null);
+    }
+
+    /**
+     * Initializes the menu associated with the given panel feature state. You
+     * must at the very least set PanelFeatureState.menu to the Menu to be
+     * associated with the given panel state. The default implementation creates
+     * a new menu for the panel state.
+     *
+     * @param st The panel whose menu is being initialized.
+     * @return Whether the initialization was successful.
+     */
+    protected boolean initializePanelMenu(final PanelFeatureState st) {
+        Context context = getContext();
+
+        // If we have an action bar, initialize the menu with the right theme.
+        if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
+                mDecorContentParent != null) {
+            final TypedValue outValue = new TypedValue();
+            final Theme baseTheme = context.getTheme();
+            baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
+
+            Theme widgetTheme = null;
+            if (outValue.resourceId != 0) {
+                widgetTheme = context.getResources().newTheme();
+                widgetTheme.setTo(baseTheme);
+                widgetTheme.applyStyle(outValue.resourceId, true);
+                widgetTheme.resolveAttribute(
+                        R.attr.actionBarWidgetTheme, outValue, true);
+            } else {
+                baseTheme.resolveAttribute(
+                        R.attr.actionBarWidgetTheme, outValue, true);
+            }
+
+            if (outValue.resourceId != 0) {
+                if (widgetTheme == null) {
+                    widgetTheme = context.getResources().newTheme();
+                    widgetTheme.setTo(baseTheme);
+                }
+                widgetTheme.applyStyle(outValue.resourceId, true);
+            }
+
+            if (widgetTheme != null) {
+                context = new ContextThemeWrapper(context, 0);
+                context.getTheme().setTo(widgetTheme);
+            }
+        }
+
+        final MenuBuilder menu = new MenuBuilder(context);
+        menu.setCallback(this);
+        st.setMenu(menu);
+
+        return true;
+    }
+
+    /**
+     * Perform initial setup of a panel. This should at the very least set the
+     * style information in the PanelFeatureState and must set
+     * PanelFeatureState.decor to the panel's window decor view.
+     *
+     * @param st The panel being initialized.
+     */
+    protected boolean initializePanelDecor(PanelFeatureState st) {
+        st.decorView = new DecorView(getContext(), st.featureId);
+        st.gravity = Gravity.CENTER | Gravity.BOTTOM;
+        st.setStyle(getContext());
+        TypedArray a = getContext().obtainStyledAttributes(null,
+                R.styleable.Window, 0, st.listPresenterTheme);
+        final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+        if (elevation != 0) {
+            st.decorView.setElevation(elevation);
+        }
+        a.recycle();
+
+        return true;
+    }
+
+    /**
+     * Determine the gravity value for the options panel. This can
+     * differ in compact mode.
+     *
+     * @return gravity value to use for the panel window
+     */
+    private int getOptionsPanelGravity() {
+        try {
+            return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
+            return Gravity.CENTER | Gravity.BOTTOM;
+        }
+    }
+
+    void onOptionsPanelRotationChanged() {
+        final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+        if (st == null) return;
+
+        final WindowManager.LayoutParams lp = st.decorView != null ?
+                (WindowManager.LayoutParams) st.decorView.getLayoutParams() : null;
+        if (lp != null) {
+            lp.gravity = getOptionsPanelGravity();
+            final ViewManager wm = getWindowManager();
+            if (wm != null) {
+                wm.updateViewLayout(st.decorView, lp);
+            }
+        }
+    }
+
+    /**
+     * Initializes the panel associated with the panel feature state. You must
+     * at the very least set PanelFeatureState.panel to the View implementing
+     * its contents. The default implementation gets the panel from the menu.
+     *
+     * @param st The panel state being initialized.
+     * @return Whether the initialization was successful.
+     */
+    protected boolean initializePanelContent(PanelFeatureState st) {
+        if (st.createdPanelView != null) {
+            st.shownPanelView = st.createdPanelView;
+            return true;
+        }
+
+        if (st.menu == null) {
+            return false;
+        }
+
+        if (mPanelMenuPresenterCallback == null) {
+            mPanelMenuPresenterCallback = new PanelMenuPresenterCallback();
+        }
+
+        MenuView menuView = st.isInListMode()
+                ? st.getListMenuView(getContext(), mPanelMenuPresenterCallback)
+                : st.getIconMenuView(getContext(), mPanelMenuPresenterCallback);
+
+        st.shownPanelView = (View) menuView;
+
+        if (st.shownPanelView != null) {
+            // Use the menu View's default animations if it has any
+            final int defaultAnimations = menuView.getWindowAnimations();
+            if (defaultAnimations != 0) {
+                st.windowAnimations = defaultAnimations;
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean performContextMenuIdentifierAction(int id, int flags) {
+        return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
+    }
+
+    @Override
+    public final void setElevation(float elevation) {
+        mElevation = elevation;
+        if (mDecor != null) {
+            mDecor.setElevation(elevation);
+        }
+        dispatchWindowAttributesChanged(getAttributes());
+    }
+
+    @Override
+    public final void setClipToOutline(boolean clipToOutline) {
+        mClipToOutline = clipToOutline;
+        if (mDecor != null) {
+            mDecor.setClipToOutline(clipToOutline);
+        }
+    }
+
+    @Override
+    public final void setBackgroundDrawable(Drawable drawable) {
+        if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
+            mBackgroundResource = 0;
+            mBackgroundDrawable = drawable;
+            if (mDecor != null) {
+                mDecor.setWindowBackground(drawable);
+            }
+            if (mBackgroundFallbackResource != 0) {
+                mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
+            }
+        }
+    }
+
+    @Override
+    public final void setFeatureDrawableResource(int featureId, int resId) {
+        if (resId != 0) {
+            DrawableFeatureState st = getDrawableState(featureId, true);
+            if (st.resid != resId) {
+                st.resid = resId;
+                st.uri = null;
+                st.local = getContext().getDrawable(resId);
+                updateDrawable(featureId, st, false);
+            }
+        } else {
+            setFeatureDrawable(featureId, null);
+        }
+    }
+
+    @Override
+    public final void setFeatureDrawableUri(int featureId, Uri uri) {
+        if (uri != null) {
+            DrawableFeatureState st = getDrawableState(featureId, true);
+            if (st.uri == null || !st.uri.equals(uri)) {
+                st.resid = 0;
+                st.uri = uri;
+                st.local = loadImageURI(uri);
+                updateDrawable(featureId, st, false);
+            }
+        } else {
+            setFeatureDrawable(featureId, null);
+        }
+    }
+
+    @Override
+    public final void setFeatureDrawable(int featureId, Drawable drawable) {
+        DrawableFeatureState st = getDrawableState(featureId, true);
+        st.resid = 0;
+        st.uri = null;
+        if (st.local != drawable) {
+            st.local = drawable;
+            updateDrawable(featureId, st, false);
+        }
+    }
+
+    @Override
+    public void setFeatureDrawableAlpha(int featureId, int alpha) {
+        DrawableFeatureState st = getDrawableState(featureId, true);
+        if (st.alpha != alpha) {
+            st.alpha = alpha;
+            updateDrawable(featureId, st, false);
+        }
+    }
+
+    protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
+        DrawableFeatureState st = getDrawableState(featureId, true);
+        if (st.def != drawable) {
+            st.def = drawable;
+            updateDrawable(featureId, st, false);
+        }
+    }
+
+    @Override
+    public final void setFeatureInt(int featureId, int value) {
+        // XXX Should do more management (as with drawable features) to
+        // deal with interactions between multiple window policies.
+        updateInt(featureId, value, false);
+    }
+
+    /**
+     * Update the state of a drawable feature. This should be called, for every
+     * drawable feature supported, as part of onActive(), to make sure that the
+     * contents of a containing window is properly updated.
+     *
+     * @see #onActive
+     * @param featureId The desired drawable feature to change.
+     * @param fromActive Always true when called from onActive().
+     */
+    protected final void updateDrawable(int featureId, boolean fromActive) {
+        final DrawableFeatureState st = getDrawableState(featureId, false);
+        if (st != null) {
+            updateDrawable(featureId, st, fromActive);
+        }
+    }
+
+    /**
+     * Called when a Drawable feature changes, for the window to update its
+     * graphics.
+     *
+     * @param featureId The feature being changed.
+     * @param drawable The new Drawable to show, or null if none.
+     * @param alpha The new alpha blending of the Drawable.
+     */
+    protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
+        ImageView view;
+        if (featureId == FEATURE_LEFT_ICON) {
+            view = getLeftIconView();
+        } else if (featureId == FEATURE_RIGHT_ICON) {
+            view = getRightIconView();
+        } else {
+            return;
+        }
+
+        if (drawable != null) {
+            drawable.setAlpha(alpha);
+            view.setImageDrawable(drawable);
+            view.setVisibility(View.VISIBLE);
+        } else {
+            view.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Called when an int feature changes, for the window to update its
+     * graphics.
+     *
+     * @param featureId The feature being changed.
+     * @param value The new integer value.
+     */
+    protected void onIntChanged(int featureId, int value) {
+        if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
+            updateProgressBars(value);
+        } else if (featureId == FEATURE_CUSTOM_TITLE) {
+            FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
+            if (titleContainer != null) {
+                mLayoutInflater.inflate(value, titleContainer);
+            }
+        }
+    }
+
+    /**
+     * Updates the progress bars that are shown in the title bar.
+     *
+     * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
+     *            {@link Window#PROGRESS_VISIBILITY_OFF},
+     *            {@link Window#PROGRESS_INDETERMINATE_ON},
+     *            {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
+     *            starting at {@link Window#PROGRESS_START} through
+     *            {@link Window#PROGRESS_END} for setting the default
+     *            progress (if {@link Window#PROGRESS_END} is given,
+     *            the progress bar widgets in the title will be hidden after an
+     *            animation), a value between
+     *            {@link Window#PROGRESS_SECONDARY_START} -
+     *            {@link Window#PROGRESS_SECONDARY_END} for the
+     *            secondary progress (if
+     *            {@link Window#PROGRESS_SECONDARY_END} is given, the
+     *            progress bar widgets will still be shown with the secondary
+     *            progress bar will be completely filled in.)
+     */
+    private void updateProgressBars(int value) {
+        ProgressBar circularProgressBar = getCircularProgressBar(true);
+        ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
+
+        final int features = getLocalFeatures();
+        if (value == PROGRESS_VISIBILITY_ON) {
+            if ((features & (1 << FEATURE_PROGRESS)) != 0) {
+                if (horizontalProgressBar != null) {
+                    int level = horizontalProgressBar.getProgress();
+                    int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
+                            View.VISIBLE : View.INVISIBLE;
+                    horizontalProgressBar.setVisibility(visibility);
+                } else {
+                    Log.e(TAG, "Horizontal progress bar not located in current window decor");
+                }
+            }
+            if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+                if (circularProgressBar != null) {
+                    circularProgressBar.setVisibility(View.VISIBLE);
+                } else {
+                    Log.e(TAG, "Circular progress bar not located in current window decor");
+                }
+            }
+        } else if (value == PROGRESS_VISIBILITY_OFF) {
+            if ((features & (1 << FEATURE_PROGRESS)) != 0) {
+                if (horizontalProgressBar != null) {
+                    horizontalProgressBar.setVisibility(View.GONE);
+                } else {
+                    Log.e(TAG, "Horizontal progress bar not located in current window decor");
+                }
+            }
+            if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+                if (circularProgressBar != null) {
+                    circularProgressBar.setVisibility(View.GONE);
+                } else {
+                    Log.e(TAG, "Circular progress bar not located in current window decor");
+                }
+            }
+        } else if (value == PROGRESS_INDETERMINATE_ON) {
+            if (horizontalProgressBar != null) {
+                horizontalProgressBar.setIndeterminate(true);
+            } else {
+                Log.e(TAG, "Horizontal progress bar not located in current window decor");
+            }
+        } else if (value == PROGRESS_INDETERMINATE_OFF) {
+            if (horizontalProgressBar != null) {
+                horizontalProgressBar.setIndeterminate(false);
+            } else {
+                Log.e(TAG, "Horizontal progress bar not located in current window decor");
+            }
+        } else if (PROGRESS_START <= value && value <= PROGRESS_END) {
+            // We want to set the progress value before testing for visibility
+            // so that when the progress bar becomes visible again, it has the
+            // correct level.
+            if (horizontalProgressBar != null) {
+                horizontalProgressBar.setProgress(value - PROGRESS_START);
+            } else {
+                Log.e(TAG, "Horizontal progress bar not located in current window decor");
+            }
+
+            if (value < PROGRESS_END) {
+                showProgressBars(horizontalProgressBar, circularProgressBar);
+            } else {
+                hideProgressBars(horizontalProgressBar, circularProgressBar);
+            }
+        } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
+            if (horizontalProgressBar != null) {
+                horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
+            } else {
+                Log.e(TAG, "Horizontal progress bar not located in current window decor");
+            }
+
+            showProgressBars(horizontalProgressBar, circularProgressBar);
+        }
+
+    }
+
+    private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
+        final int features = getLocalFeatures();
+        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+                spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.INVISIBLE) {
+            spinnyProgressBar.setVisibility(View.VISIBLE);
+        }
+        // Only show the progress bars if the primary progress is not complete
+        if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
+                horizontalProgressBar.getProgress() < 10000) {
+            horizontalProgressBar.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
+        final int features = getLocalFeatures();
+        Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);
+        anim.setDuration(1000);
+        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+                spinnyProgressBar != null &&
+                spinnyProgressBar.getVisibility() == View.VISIBLE) {
+            spinnyProgressBar.startAnimation(anim);
+            spinnyProgressBar.setVisibility(View.INVISIBLE);
+        }
+        if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
+                horizontalProgressBar.getVisibility() == View.VISIBLE) {
+            horizontalProgressBar.startAnimation(anim);
+            horizontalProgressBar.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        mIconRes = resId;
+        mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
+        mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
+        if (mDecorContentParent != null) {
+            mDecorContentParent.setIcon(resId);
+        }
+    }
+
+    @Override
+    public void setDefaultIcon(int resId) {
+        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
+            return;
+        }
+        mIconRes = resId;
+        if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
+                (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
+            if (resId != 0) {
+                mDecorContentParent.setIcon(resId);
+                mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
+            } else {
+                mDecorContentParent.setIcon(
+                        getContext().getPackageManager().getDefaultActivityIcon());
+                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+            }
+        }
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mLogoRes = resId;
+        mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
+        if (mDecorContentParent != null) {
+            mDecorContentParent.setLogo(resId);
+        }
+    }
+
+    @Override
+    public void setDefaultLogo(int resId) {
+        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
+            return;
+        }
+        mLogoRes = resId;
+        if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
+            mDecorContentParent.setLogo(resId);
+        }
+    }
+
+    @Override
+    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
+        getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
+
+    }
+
+    @Override
+    public void injectInputEvent(InputEvent event) {
+        getViewRootImpl().dispatchInputEvent(event);
+    }
+
+    private ViewRootImpl getViewRootImpl() {
+        if (mDecor != null) {
+            ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
+            if (viewRootImpl != null) {
+                return viewRootImpl;
+            }
+        }
+        throw new IllegalStateException("view not added");
+    }
+
+    /**
+     * Request that key events come to this activity. Use this if your activity
+     * has no views with focus, but the activity still wants a chance to process
+     * key events.
+     */
+    @Override
+    public void takeKeyEvents(boolean get) {
+        mDecor.setFocusable(get);
+    }
+
+    @Override
+    public boolean superDispatchKeyEvent(KeyEvent event) {
+        return mDecor.superDispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
+        return mDecor.superDispatchKeyShortcutEvent(event);
+    }
+
+    @Override
+    public boolean superDispatchTouchEvent(MotionEvent event) {
+        return mDecor.superDispatchTouchEvent(event);
+    }
+
+    @Override
+    public boolean superDispatchTrackballEvent(MotionEvent event) {
+        return mDecor.superDispatchTrackballEvent(event);
+    }
+
+    @Override
+    public boolean superDispatchGenericMotionEvent(MotionEvent event) {
+        return mDecor.superDispatchGenericMotionEvent(event);
+    }
+
+    /**
+     * A key was pressed down and not handled by anything else in the window.
+     *
+     * @see #onKeyUp
+     * @see android.view.KeyEvent
+     */
+    protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
+        /* ****************************************************************************
+         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
+         *
+         * If your key handling must happen before the app gets a crack at the event,
+         * it goes in PhoneWindowManager.
+         *
+         * If your key handling should happen in all windows, and does not depend on
+         * the state of the current application, other than that the current
+         * application can override the behavior by handling the event itself, it
+         * should go in PhoneFallbackEventHandler.
+         *
+         * Only if your handling depends on the window, and the fact that it has
+         * a DecorView, should it go here.
+         * ****************************************************************************/
+
+        final KeyEvent.DispatcherState dispatcher =
+                mDecor != null ? mDecor.getKeyDispatcherState() : null;
+        //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
+        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                int direction = 0;
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_VOLUME_UP:
+                        direction = AudioManager.ADJUST_RAISE;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_DOWN:
+                        direction = AudioManager.ADJUST_LOWER;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_MUTE:
+                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
+                        break;
+                }
+                // If we have a session send it the volume command, otherwise
+                // use the suggested stream.
+                if (mMediaController != null) {
+                    mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
+                } else {
+                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+                            mVolumeControlStreamType, direction,
+                            AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
+                }
+                return true;
+            }
+            // These are all the recognized media key codes in
+            // KeyEvent.isMediaKey()
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if (mMediaController != null) {
+                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            case KeyEvent.KEYCODE_MENU: {
+                onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_BACK: {
+                if (event.getRepeatCount() > 0) break;
+                if (featureId < 0) break;
+                // Currently don't do anything with long press.
+                if (dispatcher != null) {
+                    dispatcher.startTracking(event, this);
+                }
+                return true;
+            }
+
+        }
+
+        return false;
+    }
+
+    private KeyguardManager getKeyguardManager() {
+        if (mKeyguardManager == null) {
+            mKeyguardManager = (KeyguardManager) getContext().getSystemService(
+                    Context.KEYGUARD_SERVICE);
+        }
+        return mKeyguardManager;
+    }
+
+    AudioManager getAudioManager() {
+        if (mAudioManager == null) {
+            mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
+        }
+        return mAudioManager;
+    }
+
+    /**
+     * A key was released and not handled by anything else in the window.
+     *
+     * @see #onKeyDown
+     * @see android.view.KeyEvent
+     */
+    protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
+        final KeyEvent.DispatcherState dispatcher =
+                mDecor != null ? mDecor.getKeyDispatcherState() : null;
+        if (dispatcher != null) {
+            dispatcher.handleUpEvent(event);
+        }
+        //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
+        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN: {
+                // If we have a session send it the volume command, otherwise
+                // use the suggested stream.
+                if (mMediaController != null) {
+                    mMediaController.adjustVolume(0, AudioManager.FLAG_PLAY_SOUND
+                            | AudioManager.FLAG_VIBRATE);
+                } else {
+                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
+                            mVolumeControlStreamType, 0,
+                            AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE);
+                }
+                return true;
+            }
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                // Similar code is in PhoneFallbackEventHandler in case the window
+                // doesn't have one of these.  In this case, we execute it here and
+                // eat the event instead, because we have mVolumeControlStreamType
+                // and they don't.
+                getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
+                return true;
+            }
+            // These are all the recognized media key codes in
+            // KeyEvent.isMediaKey()
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if (mMediaController != null) {
+                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            case KeyEvent.KEYCODE_MENU: {
+                onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
+                        event);
+                return true;
+            }
+
+            case KeyEvent.KEYCODE_BACK: {
+                if (featureId < 0) break;
+                if (event.isTracking() && !event.isCanceled()) {
+                    if (featureId == FEATURE_OPTIONS_PANEL) {
+                        PanelFeatureState st = getPanelState(featureId, false);
+                        if (st != null && st.isInExpandedMode) {
+                            // If the user is in an expanded menu and hits back, it
+                            // should go back to the icon menu
+                            reopenMenu(true);
+                            return true;
+                        }
+                    }
+                    closePanel(featureId);
+                    return true;
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_SEARCH: {
+                /*
+                 * Do this in onKeyUp since the Search key is also used for
+                 * chording quick launch shortcuts.
+                 */
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                    break;
+                }
+                if (event.isTracking() && !event.isCanceled()) {
+                    launchDefaultSearch();
+                }
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected void onActive() {
+    }
+
+    @Override
+    public final View getDecorView() {
+        if (mDecor == null) {
+            installDecor();
+        }
+        return mDecor;
+    }
+
+    @Override
+    public final View peekDecorView() {
+        return mDecor;
+    }
+
+    static private final String FOCUSED_ID_TAG = "android:focusedViewId";
+    static private final String VIEWS_TAG = "android:views";
+    static private final String PANELS_TAG = "android:Panels";
+    static private final String ACTION_BAR_TAG = "android:ActionBar";
+
+    /** {@inheritDoc} */
+    @Override
+    public Bundle saveHierarchyState() {
+        Bundle outState = new Bundle();
+        if (mContentParent == null) {
+            return outState;
+        }
+
+        SparseArray<Parcelable> states = new SparseArray<Parcelable>();
+        mContentParent.saveHierarchyState(states);
+        outState.putSparseParcelableArray(VIEWS_TAG, states);
+
+        // save the focused view id
+        View focusedView = mContentParent.findFocus();
+        if (focusedView != null) {
+            if (focusedView.getId() != View.NO_ID) {
+                outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
+            } else {
+                if (false) {
+                    Log.d(TAG, "couldn't save which view has focus because the focused view "
+                            + focusedView + " has no id.");
+                }
+            }
+        }
+
+        // save the panels
+        SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
+        savePanelState(panelStates);
+        if (panelStates.size() > 0) {
+            outState.putSparseParcelableArray(PANELS_TAG, panelStates);
+        }
+
+        if (mDecorContentParent != null) {
+            SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
+            mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
+            outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
+        }
+
+        return outState;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void restoreHierarchyState(Bundle savedInstanceState) {
+        if (mContentParent == null) {
+            return;
+        }
+
+        SparseArray<Parcelable> savedStates
+                = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
+        if (savedStates != null) {
+            mContentParent.restoreHierarchyState(savedStates);
+        }
+
+        // restore the focused view
+        int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
+        if (focusedViewId != View.NO_ID) {
+            View needsFocus = mContentParent.findViewById(focusedViewId);
+            if (needsFocus != null) {
+                needsFocus.requestFocus();
+            } else {
+                Log.w(TAG,
+                        "Previously focused view reported id " + focusedViewId
+                                + " during save, but can't be found during restore.");
+            }
+        }
+
+        // restore the panels
+        SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
+        if (panelStates != null) {
+            restorePanelState(panelStates);
+        }
+
+        if (mDecorContentParent != null) {
+            SparseArray<Parcelable> actionBarStates =
+                    savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
+            if (actionBarStates != null) {
+                doPendingInvalidatePanelMenu();
+                mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
+            } else {
+                Log.w(TAG, "Missing saved instance states for action bar views! " +
+                        "State will not be restored.");
+            }
+        }
+    }
+
+    /**
+     * Invoked when the panels should freeze their state.
+     *
+     * @param icicles Save state into this. This is usually indexed by the
+     *            featureId. This will be given to {@link #restorePanelState} in the
+     *            future.
+     */
+    private void savePanelState(SparseArray<Parcelable> icicles) {
+        PanelFeatureState[] panels = mPanels;
+        if (panels == null) {
+            return;
+        }
+
+        for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
+            if (panels[curFeatureId] != null) {
+                icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
+            }
+        }
+    }
+
+    /**
+     * Invoked when the panels should thaw their state from a previously frozen state.
+     *
+     * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
+     */
+    private void restorePanelState(SparseArray<Parcelable> icicles) {
+        PanelFeatureState st;
+        int curFeatureId;
+        for (int i = icicles.size() - 1; i >= 0; i--) {
+            curFeatureId = icicles.keyAt(i);
+            st = getPanelState(curFeatureId, false /* required */);
+            if (st == null) {
+                // The panel must not have been required, and is currently not around, skip it
+                continue;
+            }
+
+            st.onRestoreInstanceState(icicles.get(curFeatureId));
+            invalidatePanelMenu(curFeatureId);
+        }
+
+        /*
+         * Implementation note: call openPanelsAfterRestore later to actually open the
+         * restored panels.
+         */
+    }
+
+    /**
+     * Opens the panels that have had their state restored. This should be
+     * called sometime after {@link #restorePanelState} when it is safe to add
+     * to the window manager.
+     */
+    private void openPanelsAfterRestore() {
+        PanelFeatureState[] panels = mPanels;
+
+        if (panels == null) {
+            return;
+        }
+
+        PanelFeatureState st;
+        for (int i = panels.length - 1; i >= 0; i--) {
+            st = panels[i];
+            // We restore the panel if it was last open; we skip it if it
+            // now is open, to avoid a race condition if the user immediately
+            // opens it when we are resuming.
+            if (st != null) {
+                st.applyFrozenState();
+                if (!st.isOpen && st.wasLastOpen) {
+                    st.isInExpandedMode = st.wasLastExpanded;
+                    openPanel(st, null);
+                }
+            }
+        }
+    }
+
+    private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+            final Menu parentMenu = menu.getRootMenu();
+            final boolean isSubMenu = parentMenu != menu;
+            final PanelFeatureState panel = findMenuPanel(isSubMenu ? parentMenu : menu);
+            if (panel != null) {
+                if (isSubMenu) {
+                    callOnPanelClosed(panel.featureId, panel, parentMenu);
+                    closePanel(panel, true);
+                } else {
+                    // Close the panel and only do the callback if the menu is being
+                    // closed completely, not if opening a sub menu
+                    closePanel(panel, allMenusAreClosing);
+                }
+            }
+        }
+
+        @Override
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
+            if (subMenu == null && hasFeature(FEATURE_ACTION_BAR)) {
+                Callback cb = getCallback();
+                if (cb != null && !isDestroyed()) {
+                    cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+                }
+            }
+
+            return true;
+        }
+    }
+
+    private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
+        @Override
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
+            Callback cb = getCallback();
+            if (cb != null) {
+                cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+            checkCloseActionMenu(menu);
+        }
+    }
+
+    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+
+        /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
+
+        /** The feature ID of the panel, or -1 if this is the application's DecorView */
+        private final int mFeatureId;
+
+        private final Rect mDrawingBounds = new Rect();
+
+        private final Rect mBackgroundPadding = new Rect();
+
+        private final Rect mFramePadding = new Rect();
+
+        private final Rect mFrameOffsets = new Rect();
+
+        private boolean mChanging;
+
+        private Drawable mMenuBackground;
+        private boolean mWatchingForMenu;
+        private int mDownY;
+
+        private ActionMode mPrimaryActionMode;
+        private ActionMode mFloatingActionMode;
+        private ActionBarContextView mPrimaryActionModeView;
+        private PopupWindow mPrimaryActionModePopup;
+        private Runnable mShowPrimaryActionModePopup;
+
+        // View added at runtime to draw under the status bar area
+        private View mStatusGuard;
+        // View added at runtime to draw under the navigation bar area
+        private View mNavigationGuard;
+
+        private final ColorViewState mStatusColorViewState = new ColorViewState(
+                SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+                Gravity.TOP,
+                STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+                com.android.internal.R.id.statusBarBackground,
+                FLAG_FULLSCREEN);
+        private final ColorViewState mNavigationColorViewState = new ColorViewState(
+                SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+                Gravity.BOTTOM,
+                NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+                com.android.internal.R.id.navigationBarBackground,
+                0 /* hideWindowFlag */);
+
+        private final Interpolator mShowInterpolator;
+        private final Interpolator mHideInterpolator;
+        private final int mBarEnterExitDuration;
+
+        private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
+
+        private int mLastTopInset = 0;
+        private int mLastBottomInset = 0;
+        private int mLastRightInset = 0;
+        private boolean mLastHasTopStableInset = false;
+        private boolean mLastHasBottomStableInset = false;
+        private int mLastWindowFlags = 0;
+
+        private int mRootScrollY = 0;
+
+        public DecorView(Context context, int featureId) {
+            super(context);
+            mFeatureId = featureId;
+
+            mShowInterpolator = AnimationUtils.loadInterpolator(context,
+                    android.R.interpolator.linear_out_slow_in);
+            mHideInterpolator = AnimationUtils.loadInterpolator(context,
+                    android.R.interpolator.fast_out_linear_in);
+
+            mBarEnterExitDuration = context.getResources().getInteger(
+                    R.integer.dock_enter_exit_duration);
+        }
+
+        public void setBackgroundFallback(int resId) {
+            mBackgroundFallback.setDrawable(resId != 0 ? getContext().getDrawable(resId) : null);
+            setWillNotDraw(getBackground() == null && !mBackgroundFallback.hasFallback());
+        }
+
+        @Override
+        public void onDraw(Canvas c) {
+            super.onDraw(c);
+            mBackgroundFallback.draw(mContentRoot, c, mContentParent);
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            final int keyCode = event.getKeyCode();
+            final int action = event.getAction();
+            final boolean isDown = action == KeyEvent.ACTION_DOWN;
+
+            if (isDown && (event.getRepeatCount() == 0)) {
+                // First handle chording of panel key: if a panel key is held
+                // but not released, try to execute a shortcut in it.
+                if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
+                    boolean handled = dispatchKeyShortcutEvent(event);
+                    if (handled) {
+                        return true;
+                    }
+                }
+
+                // If a panel is open, perform a shortcut on it without the
+                // chorded panel key
+                if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
+                    if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
+                        return true;
+                    }
+                }
+            }
+
+            if (!isDestroyed()) {
+                final Callback cb = getCallback();
+                final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
+                        : super.dispatchKeyEvent(event);
+                if (handled) {
+                    return true;
+                }
+            }
+
+            return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
+                    : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
+        }
+
+        @Override
+        public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
+            // If the panel is already prepared, then perform the shortcut using it.
+            boolean handled;
+            if (mPreparedPanel != null) {
+                handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
+                        Menu.FLAG_PERFORM_NO_CLOSE);
+                if (handled) {
+                    if (mPreparedPanel != null) {
+                        mPreparedPanel.isHandled = true;
+                    }
+                    return true;
+                }
+            }
+
+            // Shortcut not handled by the panel.  Dispatch to the view hierarchy.
+            final Callback cb = getCallback();
+            handled = cb != null && !isDestroyed() && mFeatureId < 0
+                    ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
+            if (handled) {
+                return true;
+            }
+
+            // If the panel is not prepared, then we may be trying to handle a shortcut key
+            // combination such as Control+C.  Temporarily prepare the panel then mark it
+            // unprepared again when finished to ensure that the panel will again be prepared
+            // the next time it is shown for real.
+            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+            if (st != null && mPreparedPanel == null) {
+                preparePanel(st, ev);
+                handled = performPanelShortcut(st, ev.getKeyCode(), ev,
+                        Menu.FLAG_PERFORM_NO_CLOSE);
+                st.isPrepared = false;
+                if (handled) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            final Callback cb = getCallback();
+            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
+                    : super.dispatchTouchEvent(ev);
+        }
+
+        @Override
+        public boolean dispatchTrackballEvent(MotionEvent ev) {
+            final Callback cb = getCallback();
+            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev)
+                    : super.dispatchTrackballEvent(ev);
+        }
+
+        @Override
+        public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+            final Callback cb = getCallback();
+            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchGenericMotionEvent(ev)
+                    : super.dispatchGenericMotionEvent(ev);
+        }
+
+        public boolean superDispatchKeyEvent(KeyEvent event) {
+            // Give priority to closing action modes if applicable.
+            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+                final int action = event.getAction();
+                // Back cancels action modes first.
+                if (mPrimaryActionMode != null) {
+                    if (action == KeyEvent.ACTION_UP) {
+                        mPrimaryActionMode.finish();
+                    }
+                    return true;
+                }
+            }
+
+            return super.dispatchKeyEvent(event);
+        }
+
+        public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
+            return super.dispatchKeyShortcutEvent(event);
+        }
+
+        public boolean superDispatchTouchEvent(MotionEvent event) {
+            return super.dispatchTouchEvent(event);
+        }
+
+        public boolean superDispatchTrackballEvent(MotionEvent event) {
+            return super.dispatchTrackballEvent(event);
+        }
+
+        public boolean superDispatchGenericMotionEvent(MotionEvent event) {
+            return super.dispatchGenericMotionEvent(event);
+        }
+
+        @Override
+        public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+            if (mOutsetBottom != null) {
+                final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+                int bottom = (int) mOutsetBottom.getDimension(metrics);
+                WindowInsets newInsets = insets.replaceSystemWindowInsets(
+                        insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+                        insets.getSystemWindowInsetRight(), bottom);
+                return super.dispatchApplyWindowInsets(newInsets);
+            } else {
+                return super.dispatchApplyWindowInsets(insets);
+            }
+        }
+
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            return onInterceptTouchEvent(event);
+        }
+
+        private boolean isOutOfBounds(int x, int y) {
+            return x < -5 || y < -5 || x > (getWidth() + 5)
+                    || y > (getHeight() + 5);
+        }
+
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent event) {
+            int action = event.getAction();
+            if (mFeatureId >= 0) {
+                if (action == MotionEvent.ACTION_DOWN) {
+                    int x = (int)event.getX();
+                    int y = (int)event.getY();
+                    if (isOutOfBounds(x, y)) {
+                        closePanel(mFeatureId);
+                        return true;
+                    }
+                }
+            }
+
+            if (!SWEEP_OPEN_MENU) {
+                return false;
+            }
+
+            if (mFeatureId >= 0) {
+                if (action == MotionEvent.ACTION_DOWN) {
+                    Log.i(TAG, "Watchiing!");
+                    mWatchingForMenu = true;
+                    mDownY = (int) event.getY();
+                    return false;
+                }
+
+                if (!mWatchingForMenu) {
+                    return false;
+                }
+
+                int y = (int)event.getY();
+                if (action == MotionEvent.ACTION_MOVE) {
+                    if (y > (mDownY+30)) {
+                        Log.i(TAG, "Closing!");
+                        closePanel(mFeatureId);
+                        mWatchingForMenu = false;
+                        return true;
+                    }
+                } else if (action == MotionEvent.ACTION_UP) {
+                    mWatchingForMenu = false;
+                }
+
+                return false;
+            }
+
+            //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
+            //        + " (in " + getHeight() + ")");
+
+            if (action == MotionEvent.ACTION_DOWN) {
+                int y = (int)event.getY();
+                if (y >= (getHeight()-5) && !hasChildren()) {
+                    Log.i(TAG, "Watchiing!");
+                    mWatchingForMenu = true;
+                }
+                return false;
+            }
+
+            if (!mWatchingForMenu) {
+                return false;
+            }
+
+            int y = (int)event.getY();
+            if (action == MotionEvent.ACTION_MOVE) {
+                if (y < (getHeight()-30)) {
+                    Log.i(TAG, "Opening!");
+                    openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
+                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
+                    mWatchingForMenu = false;
+                    return true;
+                }
+            } else if (action == MotionEvent.ACTION_UP) {
+                mWatchingForMenu = false;
+            }
+
+            return false;
+        }
+
+        @Override
+        public void sendAccessibilityEvent(int eventType) {
+            if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+                return;
+            }
+
+            // if we are showing a feature that should be announced and one child
+            // make this child the event source since this is the feature itself
+            // otherwise the callback will take over and announce its client
+            if ((mFeatureId == FEATURE_OPTIONS_PANEL ||
+                    mFeatureId == FEATURE_CONTEXT_MENU ||
+                    mFeatureId == FEATURE_PROGRESS ||
+                    mFeatureId == FEATURE_INDETERMINATE_PROGRESS)
+                    && getChildCount() == 1) {
+                getChildAt(0).sendAccessibilityEvent(eventType);
+            } else {
+                super.sendAccessibilityEvent(eventType);
+            }
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+            final Callback cb = getCallback();
+            if (cb != null && !isDestroyed()) {
+                if (cb.dispatchPopulateAccessibilityEvent(event)) {
+                    return true;
+                }
+            }
+            return super.dispatchPopulateAccessibilityEventInternal(event);
+        }
+
+        @Override
+        protected boolean setFrame(int l, int t, int r, int b) {
+            boolean changed = super.setFrame(l, t, r, b);
+            if (changed) {
+                final Rect drawingBounds = mDrawingBounds;
+                getDrawingRect(drawingBounds);
+
+                Drawable fg = getForeground();
+                if (fg != null) {
+                    final Rect frameOffsets = mFrameOffsets;
+                    drawingBounds.left += frameOffsets.left;
+                    drawingBounds.top += frameOffsets.top;
+                    drawingBounds.right -= frameOffsets.right;
+                    drawingBounds.bottom -= frameOffsets.bottom;
+                    fg.setBounds(drawingBounds);
+                    final Rect framePadding = mFramePadding;
+                    drawingBounds.left += framePadding.left - frameOffsets.left;
+                    drawingBounds.top += framePadding.top - frameOffsets.top;
+                    drawingBounds.right -= framePadding.right - frameOffsets.right;
+                    drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
+                }
+
+                Drawable bg = getBackground();
+                if (bg != null) {
+                    bg.setBounds(drawingBounds);
+                }
+
+                if (SWEEP_OPEN_MENU) {
+                    if (mMenuBackground == null && mFeatureId < 0
+                            && getAttributes().height
+                            == WindowManager.LayoutParams.MATCH_PARENT) {
+                        mMenuBackground = getContext().getDrawable(
+                                R.drawable.menu_background);
+                    }
+                    if (mMenuBackground != null) {
+                        mMenuBackground.setBounds(drawingBounds.left,
+                                drawingBounds.bottom-6, drawingBounds.right,
+                                drawingBounds.bottom+20);
+                    }
+                }
+            }
+            return changed;
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+            final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+
+            final int widthMode = getMode(widthMeasureSpec);
+            final int heightMode = getMode(heightMeasureSpec);
+
+            boolean fixedWidth = false;
+            if (widthMode == AT_MOST) {
+                final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
+                if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
+                    final int w;
+                    if (tvw.type == TypedValue.TYPE_DIMENSION) {
+                        w = (int) tvw.getDimension(metrics);
+                    } else if (tvw.type == TypedValue.TYPE_FRACTION) {
+                        w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
+                    } else {
+                        w = 0;
+                    }
+
+                    if (w > 0) {
+                        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+                        widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                                Math.min(w, widthSize), EXACTLY);
+                        fixedWidth = true;
+                    }
+                }
+            }
+
+            if (heightMode == AT_MOST) {
+                final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
+                if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
+                    final int h;
+                    if (tvh.type == TypedValue.TYPE_DIMENSION) {
+                        h = (int) tvh.getDimension(metrics);
+                    } else if (tvh.type == TypedValue.TYPE_FRACTION) {
+                        h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
+                    } else {
+                        h = 0;
+                    }
+                    if (h > 0) {
+                        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+                        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                                Math.min(h, heightSize), EXACTLY);
+                    }
+                }
+            }
+
+            if (mOutsetBottom != null) {
+                int mode = MeasureSpec.getMode(heightMeasureSpec);
+                if (mode != MeasureSpec.UNSPECIFIED) {
+                    int outset = (int) mOutsetBottom.getDimension(metrics);
+                    int height = MeasureSpec.getSize(heightMeasureSpec);
+                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+                }
+            }
+
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+            int width = getMeasuredWidth();
+            boolean measure = false;
+
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
+
+            if (!fixedWidth && widthMode == AT_MOST) {
+                final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
+                if (tv.type != TypedValue.TYPE_NULL) {
+                    final int min;
+                    if (tv.type == TypedValue.TYPE_DIMENSION) {
+                        min = (int)tv.getDimension(metrics);
+                    } else if (tv.type == TypedValue.TYPE_FRACTION) {
+                        min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
+                    } else {
+                        min = 0;
+                    }
+
+                    if (width < min) {
+                        widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
+                        measure = true;
+                    }
+                }
+            }
+
+            // TODO: Support height?
+
+            if (measure) {
+                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            }
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            super.draw(canvas);
+
+            if (mMenuBackground != null) {
+                mMenuBackground.draw(canvas);
+            }
+        }
+
+
+        @Override
+        public boolean showContextMenuForChild(View originalView) {
+            // Reuse the context menu builder
+            if (mContextMenu == null) {
+                mContextMenu = new ContextMenuBuilder(getContext());
+                mContextMenu.setCallback(mContextMenuCallback);
+            } else {
+                mContextMenu.clearAll();
+            }
+
+            final MenuDialogHelper helper = mContextMenu.show(originalView,
+                    originalView.getWindowToken());
+            if (helper != null) {
+                helper.setPresenterCallback(mContextMenuCallback);
+            } else if (mContextMenuHelper != null) {
+                // No menu to show, but if we have a menu currently showing it just became blank.
+                // Close it.
+                mContextMenuHelper.dismiss();
+            }
+            mContextMenuHelper = helper;
+            return helper != null;
+        }
+
+        @Override
+        public ActionMode startActionModeForChild(View originalView,
+                ActionMode.Callback callback) {
+            // originalView can be used here to be sure that we don't obscure
+            // relevant content with the context mode UI.
+            return startActionMode(callback);
+        }
+
+        @Override
+        public ActionMode startActionModeForChild(
+                View child, ActionMode.Callback callback, int type) {
+            // originalView can be used here to be sure that we don't obscure
+            // relevant content with the context mode UI.
+            return startActionMode(callback, type);
+        }
+
+        @Override
+        public ActionMode startActionMode(ActionMode.Callback callback) {
+            return startActionMode(callback, ActionMode.TYPE_PRIMARY);
+        }
+
+        @Override
+        public ActionMode startActionMode(ActionMode.Callback callback, int type) {
+            ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
+            ActionMode mode = null;
+            if (getCallback() != null && !isDestroyed()) {
+                try {
+                    mode = getCallback().onWindowStartingActionMode(wrappedCallback, type);
+                } catch (AbstractMethodError ame) {
+                    // Older apps might not implement this callback method.
+                }
+            }
+            if (mode != null) {
+                if (mode.getType() == ActionMode.TYPE_PRIMARY) {
+                    cleanupPrimaryActionMode();
+                    mPrimaryActionMode = mode;
+                } else {
+                    mFloatingActionMode = mode;
+                }
+            } else {
+                if (type == ActionMode.TYPE_PRIMARY) {
+                    cleanupPrimaryActionMode();
+                    mode = createStandaloneActionMode(wrappedCallback);
+                    if (mode != null && callback.onCreateActionMode(mode, mode.getMenu())) {
+                        setHandledPrimaryActionMode(mode);
+                    } else {
+                        mode = null;
+                    }
+                }
+            }
+            if (mode != null && getCallback() != null && !isDestroyed()) {
+                try {
+                    getCallback().onActionModeStarted(mode);
+                } catch (AbstractMethodError ame) {
+                    // Older apps might not implement this callback method.
+                }
+            }
+            return mode;
+        }
+
+        private void cleanupPrimaryActionMode() {
+            if (mPrimaryActionMode != null) {
+                mPrimaryActionMode.finish();
+                mPrimaryActionMode = null;
+            }
+            if (mPrimaryActionModeView != null) {
+                mPrimaryActionModeView.killMode();
+            }
+        }
+
+        public void startChanging() {
+            mChanging = true;
+        }
+
+        public void finishChanging() {
+            mChanging = false;
+            drawableChanged();
+        }
+
+        public void setWindowBackground(Drawable drawable) {
+            if (getBackground() != drawable) {
+                setBackgroundDrawable(drawable);
+                if (drawable != null) {
+                    drawable.getPadding(mBackgroundPadding);
+                } else {
+                    mBackgroundPadding.setEmpty();
+                }
+                drawableChanged();
+            }
+        }
+
+        @Override
+        public void setBackgroundDrawable(Drawable d) {
+            super.setBackgroundDrawable(d);
+            if (getWindowToken() != null) {
+                updateWindowResizeState();
+            }
+        }
+
+        public void setWindowFrame(Drawable drawable) {
+            if (getForeground() != drawable) {
+                setForeground(drawable);
+                if (drawable != null) {
+                    drawable.getPadding(mFramePadding);
+                } else {
+                    mFramePadding.setEmpty();
+                }
+                drawableChanged();
+            }
+        }
+
+        @Override
+        public void onWindowSystemUiVisibilityChanged(int visible) {
+            updateColorViews(null /* insets */, true /* animate */);
+        }
+
+        @Override
+        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+            mFrameOffsets.set(insets.getSystemWindowInsets());
+            insets = updateColorViews(insets, true /* animate */);
+            insets = updateStatusGuard(insets);
+            updateNavigationGuard(insets);
+            if (getForeground() != null) {
+                drawableChanged();
+            }
+            return insets;
+        }
+
+        @Override
+        public boolean isTransitionGroup() {
+            return false;
+        }
+
+        private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
+            WindowManager.LayoutParams attrs = getAttributes();
+            int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
+
+            if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+                boolean disallowAnimate = !isLaidOut();
+                disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
+                        & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+                mLastWindowFlags = attrs.flags;
+
+                if (insets != null) {
+                    mLastTopInset = Math.min(insets.getStableInsetTop(),
+                            insets.getSystemWindowInsetTop());
+                    mLastBottomInset = Math.min(insets.getStableInsetBottom(),
+                            insets.getSystemWindowInsetBottom());
+                    mLastRightInset = Math.min(insets.getStableInsetRight(),
+                            insets.getSystemWindowInsetRight());
+
+                    // Don't animate if the presence of stable insets has changed, because that
+                    // indicates that the window was either just added and received them for the
+                    // first time, or the window size or position has changed.
+                    boolean hasTopStableInset = insets.getStableInsetTop() != 0;
+                    disallowAnimate |= (hasTopStableInset != mLastHasTopStableInset);
+                    mLastHasTopStableInset = hasTopStableInset;
+
+                    boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
+                    disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset);
+                    mLastHasBottomStableInset = hasBottomStableInset;
+                }
+
+                updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
+                        mLastTopInset, animate && !disallowAnimate);
+                updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
+                        mLastBottomInset, animate && !disallowAnimate);
+            }
+
+            // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
+            // to ensure that the rest of the view hierarchy doesn't notice it, unless they've
+            // explicitly asked for it.
+
+            boolean consumingNavBar =
+                    (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+                            && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
+                            && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+
+            int consumedRight = consumingNavBar ? mLastRightInset : 0;
+            int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
+
+            if (mContentRoot != null
+                    && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
+                MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
+                if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
+                    lp.rightMargin = consumedRight;
+                    lp.bottomMargin = consumedBottom;
+                    mContentRoot.setLayoutParams(lp);
+
+                    if (insets == null) {
+                        // The insets have changed, but we're not currently in the process
+                        // of dispatching them.
+                        requestApplyInsets();
+                    }
+                }
+                if (insets != null) {
+                    insets = insets.replaceSystemWindowInsets(
+                            insets.getSystemWindowInsetLeft(),
+                            insets.getSystemWindowInsetTop(),
+                            insets.getSystemWindowInsetRight() - consumedRight,
+                            insets.getSystemWindowInsetBottom() - consumedBottom);
+                }
+            }
+
+            if (insets != null) {
+                insets = insets.consumeStableInsets();
+            }
+            return insets;
+        }
+
+        private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
+                int height, boolean animate) {
+            boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0
+                    && (getAttributes().flags & state.hideWindowFlag) == 0
+                    && (getAttributes().flags & state.translucentFlag) == 0
+                    && (color & Color.BLACK) != 0
+                    && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+
+            boolean visibilityChanged = false;
+            View view = state.view;
+
+            if (view == null) {
+                if (show) {
+                    state.view = view = new View(mContext);
+                    view.setBackgroundColor(color);
+                    view.setTransitionName(state.transitionName);
+                    view.setId(state.id);
+                    visibilityChanged = true;
+                    view.setVisibility(INVISIBLE);
+                    state.targetVisibility = VISIBLE;
+
+                    addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
+                            Gravity.START | state.verticalGravity));
+                    updateColorViewTranslations();
+                }
+            } else {
+                int vis = show ? VISIBLE : INVISIBLE;
+                visibilityChanged = state.targetVisibility != vis;
+                state.targetVisibility = vis;
+                if (show) {
+                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                    if (lp.height != height) {
+                        lp.height = height;
+                        view.setLayoutParams(lp);
+                    }
+                    view.setBackgroundColor(color);
+                }
+            }
+            if (visibilityChanged) {
+                view.animate().cancel();
+                if (animate) {
+                    if (show) {
+                        if (view.getVisibility() != VISIBLE) {
+                            view.setVisibility(VISIBLE);
+                            view.setAlpha(0.0f);
+                        }
+                        view.animate().alpha(1.0f).setInterpolator(mShowInterpolator).
+                                setDuration(mBarEnterExitDuration);
+                    } else {
+                        view.animate().alpha(0.0f).setInterpolator(mHideInterpolator)
+                                .setDuration(mBarEnterExitDuration)
+                                .withEndAction(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        state.view.setAlpha(1.0f);
+                                        state.view.setVisibility(INVISIBLE);
+                                    }
+                                });
+                    }
+                } else {
+                    view.setAlpha(1.0f);
+                    view.setVisibility(show ? VISIBLE : INVISIBLE);
+                }
+            }
+        }
+
+        private void updateColorViewTranslations() {
+            // Put the color views back in place when they get moved off the screen
+            // due to the the ViewRootImpl panning.
+            int rootScrollY = mRootScrollY;
+            if (mStatusColorViewState.view != null) {
+                mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
+            }
+            if (mNavigationColorViewState.view != null) {
+                mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
+            }
+        }
+
+        private WindowInsets updateStatusGuard(WindowInsets insets) {
+            boolean showStatusGuard = false;
+            // Show the status guard when the non-overlay contextual action bar is showing
+            if (mPrimaryActionModeView != null) {
+                if (mPrimaryActionModeView.getLayoutParams() instanceof MarginLayoutParams) {
+                    // Insets are magic!
+                    final MarginLayoutParams mlp = (MarginLayoutParams)
+                            mPrimaryActionModeView.getLayoutParams();
+                    boolean mlpChanged = false;
+                    if (mPrimaryActionModeView.isShown()) {
+                        if (mTempRect == null) {
+                            mTempRect = new Rect();
+                        }
+                        final Rect rect = mTempRect;
+
+                        // If the parent doesn't consume the insets, manually
+                        // apply the default system window insets.
+                        mContentParent.computeSystemWindowInsets(insets, rect);
+                        final int newMargin = rect.top == 0 ? insets.getSystemWindowInsetTop() : 0;
+                        if (mlp.topMargin != newMargin) {
+                            mlpChanged = true;
+                            mlp.topMargin = insets.getSystemWindowInsetTop();
+
+                            if (mStatusGuard == null) {
+                                mStatusGuard = new View(mContext);
+                                mStatusGuard.setBackgroundColor(mContext.getResources()
+                                        .getColor(R.color.input_method_navigation_guard));
+                                addView(mStatusGuard, indexOfChild(mStatusColorViewState.view),
+                                        new LayoutParams(LayoutParams.MATCH_PARENT,
+                                                mlp.topMargin, Gravity.START | Gravity.TOP));
+                            } else {
+                                final LayoutParams lp = (LayoutParams)
+                                        mStatusGuard.getLayoutParams();
+                                if (lp.height != mlp.topMargin) {
+                                    lp.height = mlp.topMargin;
+                                    mStatusGuard.setLayoutParams(lp);
+                                }
+                            }
+                        }
+
+                        // The action mode's theme may differ from the app, so
+                        // always show the status guard above it if we have one.
+                        showStatusGuard = mStatusGuard != null;
+
+                        // We only need to consume the insets if the action
+                        // mode is overlaid on the app content (e.g. it's
+                        // sitting in a FrameLayout, see
+                        // screen_simple_overlay_action_mode.xml).
+                        final boolean nonOverlay = (getLocalFeatures()
+                                & (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0;
+                        insets = insets.consumeSystemWindowInsets(
+                                false, nonOverlay && showStatusGuard /* top */, false, false);
+                    } else {
+                        // reset top margin
+                        if (mlp.topMargin != 0) {
+                            mlpChanged = true;
+                            mlp.topMargin = 0;
+                        }
+                    }
+                    if (mlpChanged) {
+                        mPrimaryActionModeView.setLayoutParams(mlp);
+                    }
+                }
+            }
+            if (mStatusGuard != null) {
+                mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE);
+            }
+            return 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
+                if (mContentParent != null) {
+                    if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
+                        MarginLayoutParams mlp =
+                                (MarginLayoutParams) mContentParent.getLayoutParams();
+                        mlp.bottomMargin = insets.getSystemWindowInsetBottom();
+                        mContentParent.setLayoutParams(mlp);
+                    }
+                }
+                // position the navigation guard view, creating it if necessary
+                if (mNavigationGuard == null) {
+                    mNavigationGuard = new View(mContext);
+                    mNavigationGuard.setBackgroundColor(mContext.getResources()
+                            .getColor(R.color.input_method_navigation_guard));
+                    addView(mNavigationGuard, indexOfChild(mNavigationColorViewState.view),
+                            new LayoutParams(LayoutParams.MATCH_PARENT,
+                                    insets.getSystemWindowInsetBottom(),
+                                    Gravity.START | Gravity.BOTTOM));
+                } else {
+                    LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
+                    lp.height = insets.getSystemWindowInsetBottom();
+                    mNavigationGuard.setLayoutParams(lp);
+                }
+            }
+        }
+
+        private void drawableChanged() {
+            if (mChanging) {
+                return;
+            }
+
+            setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
+                    + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
+                    mFramePadding.bottom + mBackgroundPadding.bottom);
+            requestLayout();
+            invalidate();
+
+            int opacity = PixelFormat.OPAQUE;
+            // Note: if there is no background, we will assume opaque. The
+            // common case seems to be that an application sets there to be
+            // no background so it can draw everything itself. For that,
+            // we would like to assume OPAQUE and let the app force it to
+            // the slower TRANSLUCENT mode if that is really what it wants.
+            Drawable bg = getBackground();
+            Drawable fg = getForeground();
+            if (bg != null) {
+                if (fg == null) {
+                    opacity = bg.getOpacity();
+                } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
+                        && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
+                    // If the frame padding is zero, then we can be opaque
+                    // if either the frame -or- the background is opaque.
+                    int fop = fg.getOpacity();
+                    int bop = bg.getOpacity();
+                    if (false)
+                        Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
+                    if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
+                        opacity = PixelFormat.OPAQUE;
+                    } else if (fop == PixelFormat.UNKNOWN) {
+                        opacity = bop;
+                    } else if (bop == PixelFormat.UNKNOWN) {
+                        opacity = fop;
+                    } else {
+                        opacity = Drawable.resolveOpacity(fop, bop);
+                    }
+                } else {
+                    // For now we have to assume translucent if there is a
+                    // frame with padding... there is no way to tell if the
+                    // frame and background together will draw all pixels.
+                    if (false)
+                        Log.v(TAG, "Padding: " + mFramePadding);
+                    opacity = PixelFormat.TRANSLUCENT;
+                }
+            }
+
+            if (false)
+                Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
+            if (false)
+                Log.v(TAG, "Selected default opacity: " + opacity);
+
+            mDefaultOpacity = opacity;
+            if (mFeatureId < 0) {
+                setDefaultWindowFormat(opacity);
+            }
+        }
+
+        @Override
+        public void onWindowFocusChanged(boolean hasWindowFocus) {
+            super.onWindowFocusChanged(hasWindowFocus);
+
+            // If the user is chording a menu shortcut, release the chord since
+            // this window lost focus
+            if (hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus && mPanelChordingKey != 0) {
+                closePanel(FEATURE_OPTIONS_PANEL);
+            }
+
+            final Callback cb = getCallback();
+            if (cb != null && !isDestroyed() && mFeatureId < 0) {
+                cb.onWindowFocusChanged(hasWindowFocus);
+            }
+        }
+
+        void updateWindowResizeState() {
+            Drawable bg = getBackground();
+            hackTurnOffWindowResizeAnim(bg == null || bg.getOpacity()
+                    != PixelFormat.OPAQUE);
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+
+            updateWindowResizeState();
+
+            final Callback cb = getCallback();
+            if (cb != null && !isDestroyed() && mFeatureId < 0) {
+                cb.onAttachedToWindow();
+            }
+
+            if (mFeatureId == -1) {
+                /*
+                 * The main window has been attached, try to restore any panels
+                 * that may have been open before. This is called in cases where
+                 * an activity is being killed for configuration change and the
+                 * menu was open. When the activity is recreated, the menu
+                 * should be shown again.
+                 */
+                openPanelsAfterRestore();
+            }
+        }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+
+            final Callback cb = getCallback();
+            if (cb != null && mFeatureId < 0) {
+                cb.onDetachedFromWindow();
+            }
+
+            if (mDecorContentParent != null) {
+                mDecorContentParent.dismissPopups();
+            }
+
+            if (mPrimaryActionModePopup != null) {
+                removeCallbacks(mShowPrimaryActionModePopup);
+                if (mPrimaryActionModePopup.isShowing()) {
+                    mPrimaryActionModePopup.dismiss();
+                }
+                mPrimaryActionModePopup = null;
+            }
+
+            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+            if (st != null && st.menu != null && mFeatureId < 0) {
+                st.menu.close();
+            }
+        }
+
+        @Override
+        public void onCloseSystemDialogs(String reason) {
+            if (mFeatureId >= 0) {
+                closeAllPanels();
+            }
+        }
+
+        public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
+            return mFeatureId < 0 ? mTakeSurfaceCallback : null;
+        }
+
+        public InputQueue.Callback willYouTakeTheInputQueue() {
+            return mFeatureId < 0 ? mTakeInputQueueCallback : null;
+        }
+
+        public void setSurfaceType(int type) {
+            PhoneWindow.this.setType(type);
+        }
+
+        public void setSurfaceFormat(int format) {
+            PhoneWindow.this.setFormat(format);
+        }
+
+        public void setSurfaceKeepScreenOn(boolean keepOn) {
+            if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        }
+
+        @Override
+        public void onRootViewScrollYChanged(int rootScrollY) {
+            mRootScrollY = rootScrollY;
+            updateColorViewTranslations();
+        }
+
+        private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
+            if (mPrimaryActionModeView == null) {
+                if (isFloating()) {
+                    // Use the action bar theme.
+                    final TypedValue outValue = new TypedValue();
+                    final Theme baseTheme = mContext.getTheme();
+                    baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
+
+                    final Context actionBarContext;
+                    if (outValue.resourceId != 0) {
+                        final Theme actionBarTheme = mContext.getResources().newTheme();
+                        actionBarTheme.setTo(baseTheme);
+                        actionBarTheme.applyStyle(outValue.resourceId, true);
+
+                        actionBarContext = new ContextThemeWrapper(mContext, 0);
+                        actionBarContext.getTheme().setTo(actionBarTheme);
+                    } else {
+                        actionBarContext = mContext;
+                    }
+
+                    mPrimaryActionModeView = new ActionBarContextView(actionBarContext);
+                    mPrimaryActionModePopup = new PopupWindow(actionBarContext, null,
+                            R.attr.actionModePopupWindowStyle);
+                    mPrimaryActionModePopup.setWindowLayoutType(
+                            WindowManager.LayoutParams.TYPE_APPLICATION);
+                    mPrimaryActionModePopup.setContentView(mPrimaryActionModeView);
+                    mPrimaryActionModePopup.setWidth(MATCH_PARENT);
+
+                    actionBarContext.getTheme().resolveAttribute(
+                            R.attr.actionBarSize, outValue, true);
+                    final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
+                            actionBarContext.getResources().getDisplayMetrics());
+                    mPrimaryActionModeView.setContentHeight(height);
+                    mPrimaryActionModePopup.setHeight(WRAP_CONTENT);
+                    mShowPrimaryActionModePopup = new Runnable() {
+                        public void run() {
+                            mPrimaryActionModePopup.showAtLocation(
+                                    mPrimaryActionModeView.getApplicationWindowToken(),
+                                    Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
+                        }
+                    };
+                } else {
+                    ViewStub stub = (ViewStub) findViewById(
+                            R.id.action_mode_bar_stub);
+                    if (stub != null) {
+                        mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
+                    }
+                }
+            }
+            if (mPrimaryActionModeView != null) {
+                mPrimaryActionModeView.killMode();
+                ActionMode mode = new StandaloneActionMode(
+                        mPrimaryActionModeView.getContext(), mPrimaryActionModeView,
+                        callback, mPrimaryActionModePopup == null);
+                return mode;
+            }
+            return null;
+        }
+
+        private void setHandledPrimaryActionMode(ActionMode mode) {
+            mPrimaryActionMode = mode;
+            mPrimaryActionMode.invalidate();
+            mPrimaryActionModeView.initForMode(mPrimaryActionMode);
+            mPrimaryActionModeView.setVisibility(View.VISIBLE);
+            if (mPrimaryActionModePopup != null) {
+                post(mShowPrimaryActionModePopup);
+            }
+            mPrimaryActionModeView.sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        }
+
+        /**
+         * Clears out internal reference when the action mode is destroyed.
+         */
+        private class ActionModeCallbackWrapper implements ActionMode.Callback {
+            private ActionMode.Callback mWrapped;
+
+            public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
+                mWrapped = wrapped;
+            }
+
+            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+                return mWrapped.onCreateActionMode(mode, menu);
+            }
+
+            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+                requestFitSystemWindows();
+                return mWrapped.onPrepareActionMode(mode, menu);
+            }
+
+            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+                return mWrapped.onActionItemClicked(mode, item);
+            }
+
+            public void onDestroyActionMode(ActionMode mode) {
+                mWrapped.onDestroyActionMode(mode);
+                if (mode == mPrimaryActionMode) {
+                    if (mPrimaryActionModePopup != null) {
+                        removeCallbacks(mShowPrimaryActionModePopup);
+                        mPrimaryActionModePopup.dismiss();
+                    } else if (mPrimaryActionModeView != null) {
+                        mPrimaryActionModeView.setVisibility(GONE);
+                    }
+                    if (mPrimaryActionModeView != null) {
+                        mPrimaryActionModeView.removeAllViews();
+                    }
+                    mPrimaryActionMode = null;
+                } else if (mode == mFloatingActionMode) {
+                    mFloatingActionMode = null;
+                }
+                if (getCallback() != null && !isDestroyed()) {
+                    try {
+                        getCallback().onActionModeFinished(mode);
+                    } catch (AbstractMethodError ame) {
+                        // Older apps might not implement this callback method.
+                    }
+                }
+                requestFitSystemWindows();
+            }
+        }
+    }
+
+    protected DecorView generateDecor() {
+        return new DecorView(getContext(), -1);
+    }
+
+    protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
+            int drawableAttr, int alphaAttr) {
+        Drawable d = attrs.getDrawable(drawableAttr);
+        if (d != null) {
+            requestFeature(featureId);
+            setFeatureDefaultDrawable(featureId, d);
+        }
+        if ((getFeatures() & (1 << featureId)) != 0) {
+            int alpha = attrs.getInt(alphaAttr, -1);
+            if (alpha >= 0) {
+                setFeatureDrawableAlpha(featureId, alpha);
+            }
+        }
+    }
+
+    protected ViewGroup generateLayout(DecorView decor) {
+        // Apply data from current theme.
+
+        TypedArray a = getWindowStyle();
+
+        if (false) {
+            System.out.println("From style:");
+            String s = "Attrs:";
+            for (int i = 0; i < R.styleable.Window.length; i++) {
+                s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
+                        + a.getString(i);
+            }
+            System.out.println(s);
+        }
+
+        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
+        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
+                & (~getForcedWindowFlags());
+        if (mIsFloating) {
+            setLayout(WRAP_CONTENT, WRAP_CONTENT);
+            setFlags(0, flagsToUpdate);
+        } else {
+            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
+            requestFeature(FEATURE_NO_TITLE);
+        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
+            // Don't allow an action bar if there is no title.
+            requestFeature(FEATURE_ACTION_BAR);
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
+            requestFeature(FEATURE_ACTION_BAR_OVERLAY);
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
+            requestFeature(FEATURE_ACTION_MODE_OVERLAY);
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
+            requestFeature(FEATURE_SWIPE_TO_DISMISS);
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
+            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
+                false)) {
+            setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
+                    & (~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
+                false)) {
+            setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
+                    & (~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
+            setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
+            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
+        }
+
+        if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
+                getContext().getApplicationInfo().targetSdkVersion
+                        >= android.os.Build.VERSION_CODES.HONEYCOMB)) {
+            setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
+        }
+
+        a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
+        a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+        if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
+            if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
+            a.getValue(R.styleable.Window_windowFixedWidthMajor,
+                    mFixedWidthMajor);
+        }
+        if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
+            if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
+            a.getValue(R.styleable.Window_windowFixedWidthMinor,
+                    mFixedWidthMinor);
+        }
+        if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
+            if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
+            a.getValue(R.styleable.Window_windowFixedHeightMajor,
+                    mFixedHeightMajor);
+        }
+        if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
+            if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
+            a.getValue(R.styleable.Window_windowFixedHeightMinor,
+                    mFixedHeightMinor);
+        }
+        if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
+            requestFeature(FEATURE_CONTENT_TRANSITIONS);
+        }
+        if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
+            requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
+        }
+
+        final WindowManager windowService = (WindowManager) getContext().getSystemService(
+                Context.WINDOW_SERVICE);
+        if (windowService != null) {
+            final Display display = windowService.getDefaultDisplay();
+            final boolean shouldUseBottomOutset =
+                    display.getDisplayId() == Display.DEFAULT_DISPLAY
+                            || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0;
+            if (shouldUseBottomOutset && a.hasValue(R.styleable.Window_windowOutsetBottom)) {
+                if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+                a.getValue(R.styleable.Window_windowOutsetBottom,
+                        mOutsetBottom);
+            }
+        }
+
+        final Context context = getContext();
+        final int targetSdk = context.getApplicationInfo().targetSdkVersion;
+        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
+        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
+        final boolean targetHcNeedsOptions = context.getResources().getBoolean(
+                R.bool.target_honeycomb_needs_options_menu);
+        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
+
+        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
+        } else {
+            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
+        }
+
+        // Non-floating windows on high end devices must put up decor beneath the system bars and
+        // therefore must know about visibility changes of those.
+        if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+            if (!targetPreL && a.getBoolean(
+                    R.styleable.Window_windowDrawsSystemBarBackgrounds,
+                    false)) {
+                setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                        FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
+            }
+        }
+        if (!mForcedStatusBarColor) {
+            mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+        }
+        if (!mForcedNavigationBarColor) {
+            mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+        }
+        if (a.getBoolean(R.styleable.Window_windowHasLightStatusBar, false)) {
+            decor.setSystemUiVisibility(
+                    decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+        }
+
+        if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
+                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            if (a.getBoolean(
+                    R.styleable.Window_windowCloseOnTouchOutside,
+                    false)) {
+                setCloseOnTouchOutsideIfNotSet(true);
+            }
+        }
+
+        WindowManager.LayoutParams params = getAttributes();
+
+        if (!hasSoftInputMode()) {
+            params.softInputMode = a.getInt(
+                    R.styleable.Window_windowSoftInputMode,
+                    params.softInputMode);
+        }
+
+        if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
+                mIsFloating)) {
+            /* All dialogs should have the window dimmed */
+            if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
+                params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            }
+            if (!haveDimAmount()) {
+                params.dimAmount = a.getFloat(
+                        android.R.styleable.Window_backgroundDimAmount, 0.5f);
+            }
+        }
+
+        if (params.windowAnimations == 0) {
+            params.windowAnimations = a.getResourceId(
+                    R.styleable.Window_windowAnimationStyle, 0);
+        }
+
+        // The rest are only done if this window is not embedded; otherwise,
+        // the values are inherited from our container.
+        if (getContainer() == null) {
+            if (mBackgroundDrawable == null) {
+                if (mBackgroundResource == 0) {
+                    mBackgroundResource = a.getResourceId(
+                            R.styleable.Window_windowBackground, 0);
+                }
+                if (mFrameResource == 0) {
+                    mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
+                }
+                mBackgroundFallbackResource = a.getResourceId(
+                        R.styleable.Window_windowBackgroundFallback, 0);
+                if (false) {
+                    System.out.println("Background: "
+                            + Integer.toHexString(mBackgroundResource) + " Frame: "
+                            + Integer.toHexString(mFrameResource));
+                }
+            }
+            mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+            mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
+            mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
+        }
+
+        // Inflate the window decor.
+
+        int layoutResource;
+        int features = getLocalFeatures();
+        // System.out.println("Features: 0x" + Integer.toHexString(features));
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+            layoutResource = R.layout.screen_swipe_dismiss;
+        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
+            if (mIsFloating) {
+                TypedValue res = new TypedValue();
+                getContext().getTheme().resolveAttribute(
+                        R.attr.dialogTitleIconsDecorLayout, res, true);
+                layoutResource = res.resourceId;
+            } else {
+                layoutResource = R.layout.screen_title_icons;
+            }
+            // XXX Remove this once action bar supports these features.
+            removeFeature(FEATURE_ACTION_BAR);
+            // System.out.println("Title Icons!");
+        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
+                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
+            // Special case for a window with only a progress bar (and title).
+            // XXX Need to have a no-title version of embedded windows.
+            layoutResource = R.layout.screen_progress;
+            // System.out.println("Progress!");
+        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
+            // Special case for a window with a custom title.
+            // If the window is floating, we need a dialog layout
+            if (mIsFloating) {
+                TypedValue res = new TypedValue();
+                getContext().getTheme().resolveAttribute(
+                        R.attr.dialogCustomTitleDecorLayout, res, true);
+                layoutResource = res.resourceId;
+            } else {
+                layoutResource = R.layout.screen_custom_title;
+            }
+            // XXX Remove this once action bar supports these features.
+            removeFeature(FEATURE_ACTION_BAR);
+        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
+            // If no other features and not embedded, only need a title.
+            // If the window is floating, we need a dialog layout
+            if (mIsFloating) {
+                TypedValue res = new TypedValue();
+                getContext().getTheme().resolveAttribute(
+                        R.attr.dialogTitleDecorLayout, res, true);
+                layoutResource = res.resourceId;
+            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
+                layoutResource = a.getResourceId(
+                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
+                        R.layout.screen_action_bar);
+            } else {
+                layoutResource = R.layout.screen_title;
+            }
+            // System.out.println("Title!");
+        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
+            layoutResource = R.layout.screen_simple_overlay_action_mode;
+        } else {
+            // Embedded, so no decoration is needed.
+            layoutResource = R.layout.screen_simple;
+            // System.out.println("Simple!");
+        }
+
+        mDecor.startChanging();
+
+        View in = mLayoutInflater.inflate(layoutResource, null);
+        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        mContentRoot = (ViewGroup) in;
+
+        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
+        if (contentParent == null) {
+            throw new RuntimeException("Window couldn't find content container view");
+        }
+
+        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+            ProgressBar progress = getCircularProgressBar(false);
+            if (progress != null) {
+                progress.setIndeterminate(true);
+            }
+        }
+
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+            registerSwipeCallbacks();
+        }
+
+        // Remaining setup -- of background and title -- that only applies
+        // to top-level windows.
+        if (getContainer() == null) {
+            final Drawable background;
+            if (mBackgroundResource != 0) {
+                background = getContext().getDrawable(mBackgroundResource);
+            } else {
+                background = mBackgroundDrawable;
+            }
+            mDecor.setWindowBackground(background);
+
+            final Drawable frame;
+            if (mFrameResource != 0) {
+                frame = getContext().getDrawable(mFrameResource);
+            } else {
+                frame = null;
+            }
+            mDecor.setWindowFrame(frame);
+
+            mDecor.setElevation(mElevation);
+            mDecor.setClipToOutline(mClipToOutline);
+
+            if (mTitle != null) {
+                setTitle(mTitle);
+            }
+
+            if (mTitleColor == 0) {
+                mTitleColor = mTextColor;
+            }
+            setTitleColor(mTitleColor);
+        }
+
+        mDecor.finishChanging();
+
+        return contentParent;
+    }
+
+    /** @hide */
+    public void alwaysReadCloseOnTouchAttr() {
+        mAlwaysReadCloseOnTouchAttr = true;
+    }
+
+    private void installDecor() {
+        if (mDecor == null) {
+            mDecor = generateDecor();
+            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+            mDecor.setIsRootNamespace(true);
+            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
+                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
+            }
+        }
+        if (mContentParent == null) {
+            mContentParent = generateLayout(mDecor);
+
+            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
+            mDecor.makeOptionalFitsSystemWindows();
+
+            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
+                    R.id.decor_content_parent);
+
+            if (decorContentParent != null) {
+                mDecorContentParent = decorContentParent;
+                mDecorContentParent.setWindowCallback(getCallback());
+                if (mDecorContentParent.getTitle() == null) {
+                    mDecorContentParent.setWindowTitle(mTitle);
+                }
+
+                final int localFeatures = getLocalFeatures();
+                for (int i = 0; i < FEATURE_MAX; i++) {
+                    if ((localFeatures & (1 << i)) != 0) {
+                        mDecorContentParent.initFeature(i);
+                    }
+                }
+
+                mDecorContentParent.setUiOptions(mUiOptions);
+
+                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
+                        (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
+                    mDecorContentParent.setIcon(mIconRes);
+                } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
+                        mIconRes == 0 && !mDecorContentParent.hasIcon()) {
+                    mDecorContentParent.setIcon(
+                            getContext().getPackageManager().getDefaultActivityIcon());
+                    mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+                }
+                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
+                        (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
+                    mDecorContentParent.setLogo(mLogoRes);
+                }
+
+                // Invalidate if the panel menu hasn't been created before this.
+                // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
+                // being called in the middle of onCreate or similar.
+                // A pending invalidation will typically be resolved before the posted message
+                // would run normally in order to satisfy instance state restoration.
+                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+                if (!isDestroyed() && (st == null || st.menu == null)) {
+                    invalidatePanelMenu(FEATURE_ACTION_BAR);
+                }
+            } else {
+                mTitleView = (TextView)findViewById(R.id.title);
+                if (mTitleView != null) {
+                    mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
+                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
+                        View titleContainer = findViewById(
+                                R.id.title_container);
+                        if (titleContainer != null) {
+                            titleContainer.setVisibility(View.GONE);
+                        } else {
+                            mTitleView.setVisibility(View.GONE);
+                        }
+                        if (mContentParent instanceof FrameLayout) {
+                            ((FrameLayout)mContentParent).setForeground(null);
+                        }
+                    } else {
+                        mTitleView.setText(mTitle);
+                    }
+                }
+            }
+
+            if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
+                mDecor.setBackgroundFallback(mBackgroundFallbackResource);
+            }
+
+            // Only inflate or create a new TransitionManager if the caller hasn't
+            // already set a custom one.
+            if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
+                if (mTransitionManager == null) {
+                    final int transitionRes = getWindowStyle().getResourceId(
+                            R.styleable.Window_windowContentTransitionManager,
+                            0);
+                    if (transitionRes != 0) {
+                        final TransitionInflater inflater = TransitionInflater.from(getContext());
+                        mTransitionManager = inflater.inflateTransitionManager(transitionRes,
+                                mContentParent);
+                    } else {
+                        mTransitionManager = new TransitionManager();
+                    }
+                }
+
+                mEnterTransition = getTransition(mEnterTransition, null,
+                        R.styleable.Window_windowEnterTransition);
+                mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
+                        R.styleable.Window_windowReturnTransition);
+                mExitTransition = getTransition(mExitTransition, null,
+                        R.styleable.Window_windowExitTransition);
+                mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
+                        R.styleable.Window_windowReenterTransition);
+                mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
+                        R.styleable.Window_windowSharedElementEnterTransition);
+                mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
+                        USE_DEFAULT_TRANSITION,
+                        R.styleable.Window_windowSharedElementReturnTransition);
+                mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
+                        R.styleable.Window_windowSharedElementExitTransition);
+                mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
+                        USE_DEFAULT_TRANSITION,
+                        R.styleable.Window_windowSharedElementReenterTransition);
+                if (mAllowEnterTransitionOverlap == null) {
+                    mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
+                            R.styleable.Window_windowAllowEnterTransitionOverlap, true);
+                }
+                if (mAllowReturnTransitionOverlap == null) {
+                    mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
+                            R.styleable.Window_windowAllowReturnTransitionOverlap, true);
+                }
+                if (mBackgroundFadeDurationMillis < 0) {
+                    mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
+                            R.styleable.Window_windowTransitionBackgroundFadeDuration,
+                            DEFAULT_BACKGROUND_FADE_DURATION_MS);
+                }
+                if (mSharedElementsUseOverlay == null) {
+                    mSharedElementsUseOverlay = getWindowStyle().getBoolean(
+                            R.styleable.Window_windowSharedElementsUseOverlay, true);
+                }
+            }
+        }
+    }
+
+    private Transition getTransition(Transition currentValue, Transition defaultValue, int id) {
+        if (currentValue != defaultValue) {
+            return currentValue;
+        }
+        int transitionId = getWindowStyle().getResourceId(id, -1);
+        Transition transition = defaultValue;
+        if (transitionId != -1 && transitionId != R.transition.no_transition) {
+            TransitionInflater inflater = TransitionInflater.from(getContext());
+            transition = inflater.inflateTransition(transitionId);
+            if (transition instanceof TransitionSet &&
+                    ((TransitionSet)transition).getTransitionCount() == 0) {
+                transition = null;
+            }
+        }
+        return transition;
+    }
+
+    private Drawable loadImageURI(Uri uri) {
+        try {
+            return Drawable.createFromStream(
+                    getContext().getContentResolver().openInputStream(uri), null);
+        } catch (Exception e) {
+            Log.w(TAG, "Unable to open content: " + uri);
+        }
+        return null;
+    }
+
+    private DrawableFeatureState getDrawableState(int featureId, boolean required) {
+        if ((getFeatures() & (1 << featureId)) == 0) {
+            if (!required) {
+                return null;
+            }
+            throw new RuntimeException("The feature has not been requested");
+        }
+
+        DrawableFeatureState[] ar;
+        if ((ar = mDrawables) == null || ar.length <= featureId) {
+            DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
+            if (ar != null) {
+                System.arraycopy(ar, 0, nar, 0, ar.length);
+            }
+            mDrawables = ar = nar;
+        }
+
+        DrawableFeatureState st = ar[featureId];
+        if (st == null) {
+            ar[featureId] = st = new DrawableFeatureState(featureId);
+        }
+        return st;
+    }
+
+    /**
+     * Gets a panel's state based on its feature ID.
+     *
+     * @param featureId The feature ID of the panel.
+     * @param required Whether the panel is required (if it is required and it
+     *            isn't in our features, this throws an exception).
+     * @return The panel state.
+     */
+    private PanelFeatureState getPanelState(int featureId, boolean required) {
+        return getPanelState(featureId, required, null);
+    }
+
+    /**
+     * Gets a panel's state based on its feature ID.
+     *
+     * @param featureId The feature ID of the panel.
+     * @param required Whether the panel is required (if it is required and it
+     *            isn't in our features, this throws an exception).
+     * @param convertPanelState Optional: If the panel state does not exist, use
+     *            this as the panel state.
+     * @return The panel state.
+     */
+    private PanelFeatureState getPanelState(int featureId, boolean required,
+            PanelFeatureState convertPanelState) {
+        if ((getFeatures() & (1 << featureId)) == 0) {
+            if (!required) {
+                return null;
+            }
+            throw new RuntimeException("The feature has not been requested");
+        }
+
+        PanelFeatureState[] ar;
+        if ((ar = mPanels) == null || ar.length <= featureId) {
+            PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
+            if (ar != null) {
+                System.arraycopy(ar, 0, nar, 0, ar.length);
+            }
+            mPanels = ar = nar;
+        }
+
+        PanelFeatureState st = ar[featureId];
+        if (st == null) {
+            ar[featureId] = st = (convertPanelState != null)
+                    ? convertPanelState
+                    : new PanelFeatureState(featureId);
+        }
+        return st;
+    }
+
+    @Override
+    public final void setChildDrawable(int featureId, Drawable drawable) {
+        DrawableFeatureState st = getDrawableState(featureId, true);
+        st.child = drawable;
+        updateDrawable(featureId, st, false);
+    }
+
+    @Override
+    public final void setChildInt(int featureId, int value) {
+        updateInt(featureId, value, false);
+    }
+
+    @Override
+    public boolean isShortcutKey(int keyCode, KeyEvent event) {
+        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+        return st != null && st.menu != null && st.menu.isShortcutKey(keyCode, event);
+    }
+
+    private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) {
+        // Do nothing if the decor is not yet installed... an update will
+        // need to be forced when we eventually become active.
+        if (mContentParent == null) {
+            return;
+        }
+
+        final int featureMask = 1 << featureId;
+
+        if ((getFeatures() & featureMask) == 0 && !fromResume) {
+            return;
+        }
+
+        Drawable drawable = null;
+        if (st != null) {
+            drawable = st.child;
+            if (drawable == null)
+                drawable = st.local;
+            if (drawable == null)
+                drawable = st.def;
+        }
+        if ((getLocalFeatures() & featureMask) == 0) {
+            if (getContainer() != null) {
+                if (isActive() || fromResume) {
+                    getContainer().setChildDrawable(featureId, drawable);
+                }
+            }
+        } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
+            // System.out.println("Drawable changed: old=" + st.cur
+            // + ", new=" + drawable);
+            st.cur = drawable;
+            st.curAlpha = st.alpha;
+            onDrawableChanged(featureId, drawable, st.alpha);
+        }
+    }
+
+    private void updateInt(int featureId, int value, boolean fromResume) {
+
+        // Do nothing if the decor is not yet installed... an update will
+        // need to be forced when we eventually become active.
+        if (mContentParent == null) {
+            return;
+        }
+
+        final int featureMask = 1 << featureId;
+
+        if ((getFeatures() & featureMask) == 0 && !fromResume) {
+            return;
+        }
+
+        if ((getLocalFeatures() & featureMask) == 0) {
+            if (getContainer() != null) {
+                getContainer().setChildInt(featureId, value);
+            }
+        } else {
+            onIntChanged(featureId, value);
+        }
+    }
+
+    private ImageView getLeftIconView() {
+        if (mLeftIconView != null) {
+            return mLeftIconView;
+        }
+        if (mContentParent == null) {
+            installDecor();
+        }
+        return (mLeftIconView = (ImageView)findViewById(R.id.left_icon));
+    }
+
+    @Override
+    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
+        super.dispatchWindowAttributesChanged(attrs);
+        if (mDecor != null) {
+            mDecor.updateColorViews(null /* insets */, true /* animate */);
+        }
+    }
+
+    private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
+        if (mCircularProgressBar != null) {
+            return mCircularProgressBar;
+        }
+        if (mContentParent == null && shouldInstallDecor) {
+            installDecor();
+        }
+        mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
+        if (mCircularProgressBar != null) {
+            mCircularProgressBar.setVisibility(View.INVISIBLE);
+        }
+        return mCircularProgressBar;
+    }
+
+    private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
+        if (mHorizontalProgressBar != null) {
+            return mHorizontalProgressBar;
+        }
+        if (mContentParent == null && shouldInstallDecor) {
+            installDecor();
+        }
+        mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
+        if (mHorizontalProgressBar != null) {
+            mHorizontalProgressBar.setVisibility(View.INVISIBLE);
+        }
+        return mHorizontalProgressBar;
+    }
+
+    private ImageView getRightIconView() {
+        if (mRightIconView != null) {
+            return mRightIconView;
+        }
+        if (mContentParent == null) {
+            installDecor();
+        }
+        return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
+    }
+
+    private void registerSwipeCallbacks() {
+        SwipeDismissLayout swipeDismiss =
+                (SwipeDismissLayout) findViewById(R.id.content);
+        swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
+            @Override
+            public void onDismissed(SwipeDismissLayout layout) {
+                dispatchOnWindowDismissed();
+            }
+        });
+        swipeDismiss.setOnSwipeProgressChangedListener(
+                new SwipeDismissLayout.OnSwipeProgressChangedListener() {
+                    private static final float ALPHA_DECREASE = 0.5f;
+                    private boolean mIsTranslucent = false;
+                    @Override
+                    public void onSwipeProgressChanged(
+                            SwipeDismissLayout layout, float progress, float translate) {
+                        WindowManager.LayoutParams newParams = getAttributes();
+                        newParams.x = (int) translate;
+                        newParams.alpha = 1 - (progress * ALPHA_DECREASE);
+                        setAttributes(newParams);
+
+                        int flags = 0;
+                        if (newParams.x == 0) {
+                            flags = FLAG_FULLSCREEN;
+                        } else {
+                            flags = FLAG_LAYOUT_NO_LIMITS;
+                        }
+                        setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+                    }
+
+                    @Override
+                    public void onSwipeCancelled(SwipeDismissLayout layout) {
+                        WindowManager.LayoutParams newParams = getAttributes();
+                        newParams.x = 0;
+                        newParams.alpha = 1;
+                        setAttributes(newParams);
+                        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+                    }
+                });
+    }
+
+    /**
+     * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
+     * callback. This method will grab whatever extra state is needed for the
+     * callback that isn't given in the parameters. If the panel is not open,
+     * this will not perform the callback.
+     *
+     * @param featureId Feature ID of the panel that was closed. Must be given.
+     * @param panel Panel that was closed. Optional but useful if there is no
+     *            menu given.
+     * @param menu The menu that was closed. Optional, but give if you have.
+     */
+    private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
+        final Callback cb = getCallback();
+        if (cb == null)
+            return;
+
+        // Try to get a menu
+        if (menu == null) {
+            // Need a panel to grab the menu, so try to get that
+            if (panel == null) {
+                if ((featureId >= 0) && (featureId < mPanels.length)) {
+                    panel = mPanels[featureId];
+                }
+            }
+
+            if (panel != null) {
+                // menu still may be null, which is okay--we tried our best
+                menu = panel.menu;
+            }
+        }
+
+        // If the panel is not open, do not callback
+        if ((panel != null) && (!panel.isOpen))
+            return;
+
+        if (!isDestroyed()) {
+            cb.onPanelClosed(featureId, menu);
+        }
+    }
+
+    /**
+     * Helper method for adding launch-search to most applications. Opens the
+     * search window using default settings.
+     *
+     * @return true if search window opened
+     */
+    private boolean launchDefaultSearch() {
+        boolean result;
+        final Callback cb = getCallback();
+        if (cb == null || isDestroyed()) {
+            result = false;
+        } else {
+            sendCloseSystemWindows("search");
+            result = cb.onSearchRequested();
+        }
+        if (!result && (getContext().getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
+            // On TVs, if the app doesn't implement search, we want to launch assist.
+            return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE))
+                    .launchAssistAction(null, UserHandle.myUserId());
+        }
+        return result;
+    }
+
+    @Override
+    public void setVolumeControlStream(int streamType) {
+        mVolumeControlStreamType = streamType;
+    }
+
+    @Override
+    public int getVolumeControlStream() {
+        return mVolumeControlStreamType;
+    }
+
+    @Override
+    public void setMediaController(MediaController controller) {
+        mMediaController = controller;
+    }
+
+    @Override
+    public MediaController getMediaController() {
+        return mMediaController;
+    }
+
+    @Override
+    public void setEnterTransition(Transition enterTransition) {
+        mEnterTransition = enterTransition;
+    }
+
+    @Override
+    public void setReturnTransition(Transition transition) {
+        mReturnTransition = transition;
+    }
+
+    @Override
+    public void setExitTransition(Transition exitTransition) {
+        mExitTransition = exitTransition;
+    }
+
+    @Override
+    public void setReenterTransition(Transition transition) {
+        mReenterTransition = transition;
+    }
+
+    @Override
+    public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
+        mSharedElementEnterTransition = sharedElementEnterTransition;
+    }
+
+    @Override
+    public void setSharedElementReturnTransition(Transition transition) {
+        mSharedElementReturnTransition = transition;
+    }
+
+    @Override
+    public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
+        mSharedElementExitTransition = sharedElementExitTransition;
+    }
+
+    @Override
+    public void setSharedElementReenterTransition(Transition transition) {
+        mSharedElementReenterTransition = transition;
+    }
+
+    @Override
+    public Transition getEnterTransition() {
+        return mEnterTransition;
+    }
+
+    @Override
+    public Transition getReturnTransition() {
+        return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
+                : mReturnTransition;
+    }
+
+    @Override
+    public Transition getExitTransition() {
+        return mExitTransition;
+    }
+
+    @Override
+    public Transition getReenterTransition() {
+        return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
+                : mReenterTransition;
+    }
+
+    @Override
+    public Transition getSharedElementEnterTransition() {
+        return mSharedElementEnterTransition;
+    }
+
+    @Override
+    public Transition getSharedElementReturnTransition() {
+        return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION
+                ? getSharedElementEnterTransition() : mSharedElementReturnTransition;
+    }
+
+    @Override
+    public Transition getSharedElementExitTransition() {
+        return mSharedElementExitTransition;
+    }
+
+    @Override
+    public Transition getSharedElementReenterTransition() {
+        return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION
+                ? getSharedElementExitTransition() : mSharedElementReenterTransition;
+    }
+
+    @Override
+    public void setAllowEnterTransitionOverlap(boolean allow) {
+        mAllowEnterTransitionOverlap = allow;
+    }
+
+    @Override
+    public boolean getAllowEnterTransitionOverlap() {
+        return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
+    }
+
+    @Override
+    public void setAllowReturnTransitionOverlap(boolean allowExitTransitionOverlap) {
+        mAllowReturnTransitionOverlap = allowExitTransitionOverlap;
+    }
+
+    @Override
+    public boolean getAllowReturnTransitionOverlap() {
+        return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
+    }
+
+    @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;
+    }
+
+    @Override
+    public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
+        mSharedElementsUseOverlay = sharedElementsUseOverlay;
+    }
+
+    @Override
+    public boolean getSharedElementsUseOverlay() {
+        return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
+    }
+
+    private static final class DrawableFeatureState {
+        DrawableFeatureState(int _featureId) {
+            featureId = _featureId;
+        }
+
+        final int featureId;
+
+        int resid;
+
+        Uri uri;
+
+        Drawable local;
+
+        Drawable child;
+
+        Drawable def;
+
+        Drawable cur;
+
+        int alpha = 255;
+
+        int curAlpha = 255;
+    }
+
+    private static final class PanelFeatureState {
+
+        /** Feature ID for this panel. */
+        int featureId;
+
+        // Information pulled from the style for this panel.
+
+        int background;
+
+        /** The background when the panel spans the entire available width. */
+        int fullBackground;
+
+        int gravity;
+
+        int x;
+
+        int y;
+
+        int windowAnimations;
+
+        /** Dynamic state of the panel. */
+        DecorView decorView;
+
+        /** The panel that was returned by onCreatePanelView(). */
+        View createdPanelView;
+
+        /** The panel that we are actually showing. */
+        View shownPanelView;
+
+        /** Use {@link #setMenu} to set this. */
+        MenuBuilder menu;
+
+        IconMenuPresenter iconMenuPresenter;
+        ListMenuPresenter listMenuPresenter;
+
+        /** true if this menu will show in single-list compact mode */
+        boolean isCompact;
+
+        /** Theme resource ID for list elements of the panel menu */
+        int listPresenterTheme;
+
+        /**
+         * Whether the panel has been prepared (see
+         * {@link PhoneWindow#preparePanel}).
+         */
+        boolean isPrepared;
+
+        /**
+         * Whether an item's action has been performed. This happens in obvious
+         * scenarios (user clicks on menu item), but can also happen with
+         * chording menu+(shortcut key).
+         */
+        boolean isHandled;
+
+        boolean isOpen;
+
+        /**
+         * True if the menu is in expanded mode, false if the menu is in icon
+         * mode
+         */
+        boolean isInExpandedMode;
+
+        public boolean qwertyMode;
+
+        boolean refreshDecorView;
+
+        boolean refreshMenuContent;
+
+        boolean wasLastOpen;
+
+        boolean wasLastExpanded;
+
+        /**
+         * Contains the state of the menu when told to freeze.
+         */
+        Bundle frozenMenuState;
+
+        /**
+         * Contains the state of associated action views when told to freeze.
+         * These are saved across invalidations.
+         */
+        Bundle frozenActionViewState;
+
+        PanelFeatureState(int featureId) {
+            this.featureId = featureId;
+
+            refreshDecorView = false;
+        }
+
+        public boolean isInListMode() {
+            return isInExpandedMode || isCompact;
+        }
+
+        public boolean hasPanelItems() {
+            if (shownPanelView == null) return false;
+            if (createdPanelView != null) return true;
+
+            if (isCompact || isInExpandedMode) {
+                return listMenuPresenter.getAdapter().getCount() > 0;
+            } else {
+                return ((ViewGroup) shownPanelView).getChildCount() > 0;
+            }
+        }
+
+        /**
+         * Unregister and free attached MenuPresenters. They will be recreated as needed.
+         */
+        public void clearMenuPresenters() {
+            if (menu != null) {
+                menu.removeMenuPresenter(iconMenuPresenter);
+                menu.removeMenuPresenter(listMenuPresenter);
+            }
+            iconMenuPresenter = null;
+            listMenuPresenter = null;
+        }
+
+        void setStyle(Context context) {
+            TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
+            background = a.getResourceId(
+                    R.styleable.Theme_panelBackground, 0);
+            fullBackground = a.getResourceId(
+                    R.styleable.Theme_panelFullBackground, 0);
+            windowAnimations = a.getResourceId(
+                    R.styleable.Theme_windowAnimationStyle, 0);
+            isCompact = a.getBoolean(
+                    R.styleable.Theme_panelMenuIsCompact, false);
+            listPresenterTheme = a.getResourceId(
+                    R.styleable.Theme_panelMenuListTheme,
+                    R.style.Theme_ExpandedMenu);
+            a.recycle();
+        }
+
+        void setMenu(MenuBuilder menu) {
+            if (menu == this.menu) return;
+
+            if (this.menu != null) {
+                this.menu.removeMenuPresenter(iconMenuPresenter);
+                this.menu.removeMenuPresenter(listMenuPresenter);
+            }
+            this.menu = menu;
+            if (menu != null) {
+                if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
+                if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
+            }
+        }
+
+        MenuView getListMenuView(Context context, MenuPresenter.Callback cb) {
+            if (menu == null) return null;
+
+            if (!isCompact) {
+                getIconMenuView(context, cb); // Need this initialized to know where our offset goes
+            }
+
+            if (listMenuPresenter == null) {
+                listMenuPresenter = new ListMenuPresenter(
+                        R.layout.list_menu_item_layout, listPresenterTheme);
+                listMenuPresenter.setCallback(cb);
+                listMenuPresenter.setId(R.id.list_menu_presenter);
+                menu.addMenuPresenter(listMenuPresenter);
+            }
+
+            if (iconMenuPresenter != null) {
+                listMenuPresenter.setItemIndexOffset(
+                        iconMenuPresenter.getNumActualItemsShown());
+            }
+            MenuView result = listMenuPresenter.getMenuView(decorView);
+
+            return result;
+        }
+
+        MenuView getIconMenuView(Context context, MenuPresenter.Callback cb) {
+            if (menu == null) return null;
+
+            if (iconMenuPresenter == null) {
+                iconMenuPresenter = new IconMenuPresenter(context);
+                iconMenuPresenter.setCallback(cb);
+                iconMenuPresenter.setId(R.id.icon_menu_presenter);
+                menu.addMenuPresenter(iconMenuPresenter);
+            }
+
+            MenuView result = iconMenuPresenter.getMenuView(decorView);
+
+            return result;
+        }
+
+        Parcelable onSaveInstanceState() {
+            SavedState savedState = new SavedState();
+            savedState.featureId = featureId;
+            savedState.isOpen = isOpen;
+            savedState.isInExpandedMode = isInExpandedMode;
+
+            if (menu != null) {
+                savedState.menuState = new Bundle();
+                menu.savePresenterStates(savedState.menuState);
+            }
+
+            return savedState;
+        }
+
+        void onRestoreInstanceState(Parcelable state) {
+            SavedState savedState = (SavedState) state;
+            featureId = savedState.featureId;
+            wasLastOpen = savedState.isOpen;
+            wasLastExpanded = savedState.isInExpandedMode;
+            frozenMenuState = savedState.menuState;
+
+            /*
+             * A LocalActivityManager keeps the same instance of this class around.
+             * The first time the menu is being shown after restoring, the
+             * Activity.onCreateOptionsMenu should be called. But, if it is the
+             * same instance then menu != null and we won't call that method.
+             * We clear any cached views here. The caller should invalidatePanelMenu.
+             */
+            createdPanelView = null;
+            shownPanelView = null;
+            decorView = null;
+        }
+
+        void applyFrozenState() {
+            if (menu != null && frozenMenuState != null) {
+                menu.restorePresenterStates(frozenMenuState);
+                frozenMenuState = null;
+            }
+        }
+
+        private static class SavedState implements Parcelable {
+            int featureId;
+            boolean isOpen;
+            boolean isInExpandedMode;
+            Bundle menuState;
+
+            public int describeContents() {
+                return 0;
+            }
+
+            public void writeToParcel(Parcel dest, int flags) {
+                dest.writeInt(featureId);
+                dest.writeInt(isOpen ? 1 : 0);
+                dest.writeInt(isInExpandedMode ? 1 : 0);
+
+                if (isOpen) {
+                    dest.writeBundle(menuState);
+                }
+            }
+
+            private static SavedState readFromParcel(Parcel source) {
+                SavedState savedState = new SavedState();
+                savedState.featureId = source.readInt();
+                savedState.isOpen = source.readInt() == 1;
+                savedState.isInExpandedMode = source.readInt() == 1;
+
+                if (savedState.isOpen) {
+                    savedState.menuState = source.readBundle();
+                }
+
+                return savedState;
+            }
+
+            public static final Parcelable.Creator<SavedState> CREATOR
+                    = new Parcelable.Creator<SavedState>() {
+                public SavedState createFromParcel(Parcel in) {
+                    return readFromParcel(in);
+                }
+
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
+        }
+
+    }
+
+    static class RotationWatcher extends IRotationWatcher.Stub {
+        private Handler mHandler;
+        private final Runnable mRotationChanged = new Runnable() {
+            public void run() {
+                dispatchRotationChanged();
+            }
+        };
+        private final ArrayList<WeakReference<PhoneWindow>> mWindows =
+                new ArrayList<WeakReference<PhoneWindow>>();
+        private boolean mIsWatching;
+
+        @Override
+        public void onRotationChanged(int rotation) throws RemoteException {
+            mHandler.post(mRotationChanged);
+        }
+
+        public void addWindow(PhoneWindow phoneWindow) {
+            synchronized (mWindows) {
+                if (!mIsWatching) {
+                    try {
+                        WindowManagerHolder.sWindowManager.watchRotation(this);
+                        mHandler = new Handler();
+                        mIsWatching = true;
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Couldn't start watching for device rotation", ex);
+                    }
+                }
+                mWindows.add(new WeakReference<PhoneWindow>(phoneWindow));
+            }
+        }
+
+        public void removeWindow(PhoneWindow phoneWindow) {
+            synchronized (mWindows) {
+                int i = 0;
+                while (i < mWindows.size()) {
+                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
+                    final PhoneWindow win = ref.get();
+                    if (win == null || win == phoneWindow) {
+                        mWindows.remove(i);
+                    } else {
+                        i++;
+                    }
+                }
+            }
+        }
+
+        void dispatchRotationChanged() {
+            synchronized (mWindows) {
+                int i = 0;
+                while (i < mWindows.size()) {
+                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
+                    final PhoneWindow win = ref.get();
+                    if (win != null) {
+                        win.onOptionsPanelRotationChanged();
+                        i++;
+                    } else {
+                        mWindows.remove(i);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Simple implementation of MenuBuilder.Callback that:
+     * <li> Opens a submenu when selected.
+     * <li> Calls back to the callback's onMenuItemSelected when an item is
+     * selected.
+     */
+    private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
+        private int mFeatureId;
+        private MenuDialogHelper mSubMenuHelper;
+
+        public DialogMenuCallback(int featureId) {
+            mFeatureId = featureId;
+        }
+
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+            if (menu.getRootMenu() != menu) {
+                onCloseSubMenu(menu);
+            }
+
+            if (allMenusAreClosing) {
+                Callback callback = getCallback();
+                if (callback != null && !isDestroyed()) {
+                    callback.onPanelClosed(mFeatureId, menu);
+                }
+
+                if (menu == mContextMenu) {
+                    dismissContextMenu();
+                }
+
+                // Dismiss the submenu, if it is showing
+                if (mSubMenuHelper != null) {
+                    mSubMenuHelper.dismiss();
+                    mSubMenuHelper = null;
+                }
+            }
+        }
+
+        public void onCloseSubMenu(MenuBuilder menu) {
+            Callback callback = getCallback();
+            if (callback != null && !isDestroyed()) {
+                callback.onPanelClosed(mFeatureId, menu.getRootMenu());
+            }
+        }
+
+        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+            Callback callback = getCallback();
+            return (callback != null && !isDestroyed())
+                    && callback.onMenuItemSelected(mFeatureId, item);
+        }
+
+        public void onMenuModeChange(MenuBuilder menu) {
+        }
+
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
+            if (subMenu == null) return false;
+
+            // Set a simple callback for the submenu
+            subMenu.setCallback(this);
+
+            // The window manager will give us a valid window token
+            mSubMenuHelper = new MenuDialogHelper(subMenu);
+            mSubMenuHelper.show(null);
+
+            return true;
+        }
+    }
+
+    private static class ColorViewState {
+        View view = null;
+        int targetVisibility = View.INVISIBLE;
+
+        final int id;
+        final int systemUiHideFlag;
+        final int translucentFlag;
+        final int verticalGravity;
+        final String transitionName;
+        final int hideWindowFlag;
+
+        ColorViewState(int systemUiHideFlag,
+                int translucentFlag, int verticalGravity,
+                String transitionName, int id, int hideWindowFlag) {
+            this.id = id;
+            this.systemUiHideFlag = systemUiHideFlag;
+            this.translucentFlag = translucentFlag;
+            this.verticalGravity = verticalGravity;
+            this.transitionName = transitionName;
+            this.hideWindowFlag = hideWindowFlag;
+        }
+    }
+
+    void sendCloseSystemWindows() {
+        sendCloseSystemWindows(getContext(), null);
+    }
+
+    void sendCloseSystemWindows(String reason) {
+        sendCloseSystemWindows(getContext(), reason);
+    }
+
+    public static void sendCloseSystemWindows(Context context, String reason) {
+        if (ActivityManagerNative.isSystemReady()) {
+            try {
+                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    @Override
+    public int getStatusBarColor() {
+        return mStatusBarColor;
+    }
+
+    @Override
+    public void setStatusBarColor(int color) {
+        mStatusBarColor = color;
+        mForcedStatusBarColor = true;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null, false /* animate */);
+        }
+    }
+
+    @Override
+    public int getNavigationBarColor() {
+        return mNavigationBarColor;
+    }
+
+    @Override
+    public void setNavigationBarColor(int color) {
+        mNavigationBarColor = color;
+        mForcedNavigationBarColor = true;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null, false /* animate */);
+        }
+    }
+}
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7dcad68..cf35ce5 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.util.XmlUtils;
 
+import android.annotation.XmlRes;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -192,7 +193,7 @@
      * @throws Resources.NotFoundException if the resource was not found or the drawable
      * linked in the resource was not found.
      */
-    public static PointerIcon loadCustomIcon(Resources resources, int resourceId) {
+    public static PointerIcon loadCustomIcon(Resources resources, @XmlRes int resourceId) {
         if (resources == null) {
             throw new IllegalArgumentException("resources must not be null");
         }
@@ -373,7 +374,7 @@
         return true;
     }
 
-    private void loadResource(Context context, Resources resources, int resourceId) {
+    private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
         final XmlResourceParser parser = resources.getXml(resourceId);
         final int bitmapRes;
         final float hotSpotX;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 47f72a8..38867a8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -225,7 +225,7 @@
      * @see #isValid()
      */
     public HardwareCanvas start(int width, int height) {
-        HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this);
+        HardwareCanvas canvas = DisplayListCanvas.obtain(this);
         canvas.setViewport(width, height);
         // The dirty rect should always be null for a display list
         canvas.onPreDraw(null);
@@ -241,11 +241,11 @@
      * @see #isValid()
      */
     public void end(HardwareCanvas endCanvas) {
-        if (!(endCanvas instanceof GLES20RecordingCanvas)) {
+        if (!(endCanvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Passed an invalid canvas to end!");
         }
 
-        GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas;
+        DisplayListCanvas canvas = (DisplayListCanvas) endCanvas;
         canvas.onPostDraw();
         long renderNodeData = canvas.finishRecording();
         nSetDisplayListData(mNativeRenderNode, renderNodeData);
@@ -305,7 +305,7 @@
     }
 
     public boolean setLayerPaint(Paint paint) {
-        return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
+        return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
     }
 
     public boolean setClipBounds(@Nullable Rect rect) {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7b35a3b..379796d 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -283,10 +283,10 @@
     }
 
     public void setTarget(Canvas canvas) {
-        if (!(canvas instanceof GLES20RecordingCanvas)) {
+        if (!(canvas instanceof DisplayListCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        final DisplayListCanvas recordingCanvas = (DisplayListCanvas) canvas;
         setTarget(recordingCanvas.mNode);
     }
 
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 42a58a8..6508cca 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -21,7 +21,6 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.util.FloatMath;
 
 /**
  * Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
@@ -394,7 +393,7 @@
         if (inDoubleTapMode()) {
             span = spanY;
         } else {
-            span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+            span = (float) Math.hypot(spanX, spanY);
         }
 
         // Dispatch begin/end events as needed.
diff --git a/core/java/android/view/SubMenu.java b/core/java/android/view/SubMenu.java
index 196a183..38662b0 100644
--- a/core/java/android/view/SubMenu.java
+++ b/core/java/android/view/SubMenu.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.DrawableRes;
+import android.annotation.StringRes;
 import android.graphics.drawable.Drawable;
 
 /**
@@ -38,7 +40,7 @@
      * @param titleRes The string resource identifier used for the title.
      * @return This SubMenu so additional setters can be called.
      */
-    public SubMenu setHeaderTitle(int titleRes);
+    public SubMenu setHeaderTitle(@StringRes int titleRes);
 
     /**
      * Sets the submenu header's title to the title given in <var>title</var>.
@@ -55,7 +57,7 @@
      * @param iconRes The resource identifier used for the icon.
      * @return This SubMenu so additional setters can be called.
      */
-    public SubMenu setHeaderIcon(int iconRes);
+    public SubMenu setHeaderIcon(@DrawableRes int iconRes);
 
     /**
      * Sets the submenu header's icon to the icon given in <var>icon</var>
@@ -88,7 +90,7 @@
      * @param iconRes The new icon (as a resource ID) to be displayed.
      * @return This SubMenu so additional setters can be called.
      */
-    public SubMenu setIcon(int iconRes);
+    public SubMenu setIcon(@DrawableRes int iconRes);
     
     /**
      * Change the icon associated with this submenu's item in its parent menu.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 33ce517..83b8100 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -322,7 +322,6 @@
      * @return A canvas for drawing into the surface.
      *
      * @throws IllegalStateException If the canvas cannot be locked.
-     * @hide
      */
     public Canvas lockHardwareCanvas() {
         synchronized (mLock) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ad4a048..51fefe9 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,8 +16,7 @@
 
 package android.view;
 
-import com.android.internal.R;
-
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -27,16 +26,18 @@
 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 com.android.internal.R;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -74,6 +75,14 @@
         PROFILE_PROPERTY_VISUALIZE_BARS,
     };
 
+    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
+    private static final int FLAG_DUMP_RESET        = 1 << 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DumpFlags {}
+
     // Size of the rendered content.
     private int mWidth, mHeight;
 
@@ -98,7 +107,6 @@
     private boolean mInitialized = false;
     private RenderNode mRootNode;
     private Choreographer mChoreographer;
-    private boolean mProfilingEnabled;
     private boolean mRootNodeNeedsUpdate;
 
     ThreadedRenderer(Context context, boolean translucent) {
@@ -118,10 +126,6 @@
 
         AtlasInitializer.sInstance.init(context, mNativeProxy);
 
-        // Setup timing
-        mChoreographer = Choreographer.getInstance();
-        nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
-
         loadSystemProperties();
     }
 
@@ -233,32 +237,25 @@
     }
 
     @Override
-    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
+    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
         pw.flush();
-        nDumpProfileInfo(mNativeProxy, fd);
-    }
-
-    private static int search(String[] values, String value) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i].equals(value)) return i;
+        int flags = 0;
+        for (int i = 0; i < args.length; i++) {
+            switch (args[i]) {
+                case "framestats":
+                    flags |= FLAG_DUMP_FRAMESTATS;
+                    break;
+                case "reset":
+                    flags |= FLAG_DUMP_RESET;
+                    break;
+            }
         }
-        return -1;
-    }
-
-    private static boolean checkIfProfilingRequested() {
-        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
-        int graphType = search(VISUALIZERS, profiling);
-        return (graphType >= 0) || Boolean.parseBoolean(profiling);
+        nDumpProfileInfo(mNativeProxy, fd, flags);
     }
 
     @Override
     boolean loadSystemProperties() {
         boolean changed = nLoadSystemProperties(mNativeProxy);
-        boolean wantProfiling = checkIfProfilingRequested();
-        if (wantProfiling != mProfilingEnabled) {
-            mProfilingEnabled = wantProfiling;
-            changed = true;
-        }
         if (changed) {
             invalidateRoot();
         }
@@ -307,20 +304,12 @@
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
         attachInfo.mIgnoreDirtyState = true;
-        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
-        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
 
-        long recordDuration = 0;
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime();
-        }
+        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
+        choreographer.mFrameInfo.markDrawStart();
 
         updateRootDisplayList(view, callbacks);
 
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime() - recordDuration;
-        }
-
         attachInfo.mIgnoreDirtyState = false;
 
         // register animating rendernodes which started animating prior to renderer
@@ -337,8 +326,8 @@
             attachInfo.mPendingAnimatingRenderNodes = null;
         }
 
-        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
-                recordDuration, view.getResources().getDisplayMetrics().density);
+        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
             setEnabled(false);
             attachInfo.mViewRootImpl.mSurface.release();
@@ -369,7 +358,7 @@
     @Override
     boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
         return nCopyLayerInto(mNativeProxy,
-                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+                layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
     }
 
     @Override
@@ -384,6 +373,7 @@
 
     @Override
     void setName(String name) {
+        nSetName(mNativeProxy, name);
     }
 
     @Override
@@ -470,7 +460,7 @@
             for (int i = 0; i < count; i++) {
                 drawables.valueAt(i).addAtlasableBitmaps(tmpList);
                 for (int j = 0; j < tmpList.size(); j++) {
-                    preloadedPointers.add(tmpList.get(j).mNativeBitmap);
+                    preloadedPointers.add(tmpList.get(j).getSkBitmap());
                 }
                 tmpList.clear();
             }
@@ -492,8 +482,8 @@
     private static native long nCreateProxy(boolean translucent, long rootRenderNode);
     private static native void nDeleteProxy(long nativeProxy);
 
-    private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
     private static native boolean nLoadSystemProperties(long nativeProxy);
+    private static native void nSetName(long nativeProxy, String name);
 
     private static native boolean nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
@@ -502,8 +492,7 @@
             float lightX, float lightY, float lightZ, float lightRadius,
             int ambientShadowAlpha, int spotShadowAlpha);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native int nSyncAndDrawFrame(long nativeProxy,
-            long frameTimeNanos, long recordDuration, float density);
+    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
     private static native void nDestroy(long nativeProxy);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
@@ -523,5 +512,6 @@
     private static native void nStopDrawing(long nativeProxy);
     private static native void nNotifyFramePending(long nativeProxy);
 
-    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
+    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
+            @DumpFlags int dumpFlags);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3c05872..3927096 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,9 +18,15 @@
 
 import android.animation.AnimatorInflater;
 import android.animation.StateListAnimator;
+import android.annotation.CallSuper;
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
+import android.annotation.IdRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -35,8 +41,6 @@
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
@@ -66,6 +70,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.Property;
 import android.util.SparseArray;
+import android.util.StateSet;
 import android.util.SuperNotCalledException;
 import android.util.TypedValue;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -439,7 +444,7 @@
  * </p>
  *
  * <p>
- * To intiate a layout, call {@link #requestLayout}. This method is typically
+ * To initiate a layout, call {@link #requestLayout}. This method is typically
  * called by a view on itself when it believes that is can no longer fit within
  * its current bounds.
  * </p>
@@ -1438,140 +1443,87 @@
      */
     protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
 
-    /**
-     * The order here is very important to {@link #getDrawableState()}
-     */
-    private static final int[][] VIEW_STATE_SETS;
-
-    static final int VIEW_STATE_WINDOW_FOCUSED = 1;
-    static final int VIEW_STATE_SELECTED = 1 << 1;
-    static final int VIEW_STATE_FOCUSED = 1 << 2;
-    static final int VIEW_STATE_ENABLED = 1 << 3;
-    static final int VIEW_STATE_PRESSED = 1 << 4;
-    static final int VIEW_STATE_ACTIVATED = 1 << 5;
-    static final int VIEW_STATE_ACCELERATED = 1 << 6;
-    static final int VIEW_STATE_HOVERED = 1 << 7;
-    static final int VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8;
-    static final int VIEW_STATE_DRAG_HOVERED = 1 << 9;
-
-    static final int[] VIEW_STATE_IDS = new int[] {
-        R.attr.state_window_focused,    VIEW_STATE_WINDOW_FOCUSED,
-        R.attr.state_selected,          VIEW_STATE_SELECTED,
-        R.attr.state_focused,           VIEW_STATE_FOCUSED,
-        R.attr.state_enabled,           VIEW_STATE_ENABLED,
-        R.attr.state_pressed,           VIEW_STATE_PRESSED,
-        R.attr.state_activated,         VIEW_STATE_ACTIVATED,
-        R.attr.state_accelerated,       VIEW_STATE_ACCELERATED,
-        R.attr.state_hovered,           VIEW_STATE_HOVERED,
-        R.attr.state_drag_can_accept,   VIEW_STATE_DRAG_CAN_ACCEPT,
-        R.attr.state_drag_hovered,      VIEW_STATE_DRAG_HOVERED
-    };
-
     static {
-        if ((VIEW_STATE_IDS.length/2) != R.styleable.ViewDrawableStates.length) {
-            throw new IllegalStateException(
-                    "VIEW_STATE_IDs array length does not match ViewDrawableStates style array");
-        }
-        int[] orderedIds = new int[VIEW_STATE_IDS.length];
-        for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) {
-            int viewState = R.styleable.ViewDrawableStates[i];
-            for (int j = 0; j<VIEW_STATE_IDS.length; j += 2) {
-                if (VIEW_STATE_IDS[j] == viewState) {
-                    orderedIds[i * 2] = viewState;
-                    orderedIds[i * 2 + 1] = VIEW_STATE_IDS[j + 1];
-                }
-            }
-        }
-        final int NUM_BITS = VIEW_STATE_IDS.length / 2;
-        VIEW_STATE_SETS = new int[1 << NUM_BITS][];
-        for (int i = 0; i < VIEW_STATE_SETS.length; i++) {
-            int numBits = Integer.bitCount(i);
-            int[] set = new int[numBits];
-            int pos = 0;
-            for (int j = 0; j < orderedIds.length; j += 2) {
-                if ((i & orderedIds[j+1]) != 0) {
-                    set[pos++] = orderedIds[j];
-                }
-            }
-            VIEW_STATE_SETS[i] = set;
-        }
+        EMPTY_STATE_SET = StateSet.get(0);
 
-        EMPTY_STATE_SET = VIEW_STATE_SETS[0];
-        WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_WINDOW_FOCUSED];
-        SELECTED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_SELECTED];
-        SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED];
-        FOCUSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_FOCUSED];
-        FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED];
-        FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED];
-        FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_FOCUSED];
-        ENABLED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_ENABLED];
-        ENABLED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_ENABLED];
-        ENABLED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_ENABLED];
-        ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_ENABLED];
-        ENABLED_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_FOCUSED | VIEW_STATE_ENABLED];
-        ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_ENABLED];
-        ENABLED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_ENABLED];
-        ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_FOCUSED| VIEW_STATE_ENABLED];
+        WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED);
 
-        PRESSED_STATE_SET = VIEW_STATE_SETS[VIEW_STATE_PRESSED];
-        PRESSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_PRESSED];
-        PRESSED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_PRESSED];
-        PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_PRESSED];
-        PRESSED_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_FOCUSED | VIEW_STATE_PRESSED];
-        PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_PRESSED];
-        PRESSED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_PRESSED];
-        PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_FOCUSED | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_ENABLED | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_ENABLED
-                | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_ENABLED
-                | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_FOCUSED | VIEW_STATE_ENABLED
-                | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_SELECTED | VIEW_STATE_FOCUSED
-                | VIEW_STATE_ENABLED | VIEW_STATE_PRESSED];
-        PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = VIEW_STATE_SETS[
-                VIEW_STATE_WINDOW_FOCUSED | VIEW_STATE_SELECTED
-                | VIEW_STATE_FOCUSED| VIEW_STATE_ENABLED
-                | VIEW_STATE_PRESSED];
+        SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED);
+        SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED);
+
+        FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED);
+        FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED);
+        FOCUSED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED);
+        FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_FOCUSED);
+
+        ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED);
+        ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_ENABLED);
+        ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED);
+
+        PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED);
+        PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED
+                        | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED
+                        | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED);
+        PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get(
+                StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED
+                        | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED
+                        | StateSet.VIEW_STATE_PRESSED);
     }
 
     /**
@@ -1645,6 +1597,7 @@
      * @see #setId(int)
      * @see #getId()
      */
+    @IdRes
     @ViewDebug.ExportedProperty(resolveId = true)
     int mID = NO_ID;
 
@@ -1977,7 +1930,7 @@
     static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR;
 
     /**
-     * Text direction is inherited thru {@link ViewGroup}
+     * Text direction is inherited through {@link ViewGroup}
      */
     public static final int TEXT_DIRECTION_INHERIT = 0;
 
@@ -2545,7 +2498,7 @@
 
     /**
      * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
-     * to be layed out as if it has requested
+     * to be laid out as if it has requested
      * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't.  This
      * allows it to avoid artifacts when switching in and out of that mode, at
      * the expense that some of its user interface may be covered by screen
@@ -2557,7 +2510,7 @@
 
     /**
      * Flag for {@link #setSystemUiVisibility(int)}: View would like its window
-     * to be layed out as if it has requested
+     * to be laid out as if it has requested
      * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't.  This
      * allows it to avoid artifacts when switching in and out of that mode, at
      * the expense that some of its user interface may be covered by screen
@@ -2596,6 +2549,20 @@
     public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000;
 
     /**
+     * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that
+     * is compatible with light status bar backgrounds.
+     *
+     * <p>For this to take effect, the window must request
+     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
+     *         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
+     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS
+     *         FLAG_TRANSLUCENT_STATUS}.
+     *
+     * @see android.R.attr#windowHasLightStatusBar
+     */
+    public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
+
+    /**
      * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
      */
     public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE;
@@ -3620,7 +3587,7 @@
      * @param attrs The attributes of the XML tag that is inflating the view.
      * @see #View(Context, AttributeSet, int)
      */
-    public View(Context context, AttributeSet attrs) {
+    public View(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
@@ -3641,7 +3608,7 @@
      *        the view. Can be 0 to not look for defaults.
      * @see #View(Context, AttributeSet)
      */
-    public View(Context context, AttributeSet attrs, int defStyleAttr) {
+    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -3678,7 +3645,7 @@
      *        to not look for defaults.
      * @see #View(Context, AttributeSet, int)
      */
-    public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         this(context);
 
         final TypedArray a = context.obtainStyledAttributes(
@@ -4508,6 +4475,8 @@
 
         if (scrollabilityCache.scrollBar == null) {
             scrollabilityCache.scrollBar = new ScrollBarDrawable();
+            scrollabilityCache.scrollBar.setCallback(this);
+            scrollabilityCache.scrollBar.setState(getDrawableState());
         }
 
         final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
@@ -4619,11 +4588,18 @@
     }
 
     /**
-     * Register a callback to be invoked when the scroll position of this view
-     * changed.
+     * Register a callback to be invoked when the scroll X or Y positions of
+     * this view change.
+     * <p>
+     * <b>Note:</b> Some views handle scrolling independently from View and may
+     * have their own separate listeners for scroll-type events. For example,
+     * {@link android.widget.ListView ListView} allows clients to register an
+     * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener}
+     * to listen for changes in list scroll position.
      *
-     * @param l The callback that will run.
-     * @hide Only used internally.
+     * @param l The listener to notify when the scroll X or Y position changes.
+     * @see android.view.View#getScrollX()
+     * @see android.view.View#getScrollY()
      */
     public void setOnScrollChangeListener(OnScrollChangeListener l) {
         getListenerInfo().mOnScrollChangeListener = l;
@@ -4719,7 +4695,7 @@
      *
      * @see #setClickable(boolean)
      */
-    public void setOnClickListener(OnClickListener l) {
+    public void setOnClickListener(@Nullable OnClickListener l) {
         if (!isClickable()) {
             setClickable(true);
         }
@@ -4743,7 +4719,7 @@
      *
      * @see #setLongClickable(boolean)
      */
-    public void setOnLongClickListener(OnLongClickListener l) {
+    public void setOnLongClickListener(@Nullable OnLongClickListener l) {
         if (!isLongClickable()) {
             setLongClickable(true);
         }
@@ -4868,17 +4844,36 @@
     }
 
     /**
-     * Start an action mode.
+     * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}.
      *
      * @param callback Callback that will control the lifecycle of the action mode
      * @return The new action mode if it is started, null otherwise
      *
      * @see ActionMode
+     * @see #startActionMode(android.view.ActionMode.Callback, int)
      */
     public ActionMode startActionMode(ActionMode.Callback callback) {
+        return startActionMode(callback, ActionMode.TYPE_PRIMARY);
+    }
+
+    /**
+     * Start an action mode with the given type.
+     *
+     * @param callback Callback that will control the lifecycle of the action mode
+     * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}.
+     * @return The new action mode if it is started, null otherwise
+     *
+     * @see ActionMode
+     */
+    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
         ViewParent parent = getParent();
         if (parent == null) return null;
-        return parent.startActionModeForChild(this, callback);
+        try {
+            return parent.startActionModeForChild(this, callback, type);
+        } catch (AbstractMethodError ame) {
+            // Older implementations of custom views might not implement this.
+            return parent.startActionModeForChild(this, callback);
+        }
     }
 
     /**
@@ -5123,7 +5118,7 @@
     }
 
     /**
-     * Returns true if this view has focus iteself, or is the ancestor of the
+     * Returns true if this view has focus itself, or is the ancestor of the
      * view that has focus.
      *
      * @return True if this view has or contains focus, false otherwise.
@@ -5176,6 +5171,7 @@
      *        passed in as finer grained information about where the focus is coming
      *        from (in addition to direction).  Will be <code>null</code> otherwise.
      */
+    @CallSuper
     protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
             @Nullable Rect previouslyFocusedRect) {
         if (gainFocus) {
@@ -5220,7 +5216,7 @@
      * populate the text content of the event source including its descendants,
      * and last calls
      * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
-     * on its parent to resuest sending of the event to interested parties.
+     * on its parent to request sending of the event to interested parties.
      * <p>
      * If an {@link AccessibilityDelegate} has been specified via calling
      * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
@@ -5270,8 +5266,10 @@
      * @see #sendAccessibilityEvent(int)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    void sendAccessibilityEventInternal(int eventType) {
+    public void sendAccessibilityEventInternal(int eventType) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
         }
@@ -5304,8 +5302,10 @@
      * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
+    public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
         if (!isShown()) {
             return;
         }
@@ -5355,8 +5355,10 @@
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         onPopulateAccessibilityEvent(event);
         return false;
     }
@@ -5392,6 +5394,7 @@
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
+    @CallSuper
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
@@ -5404,8 +5407,10 @@
      * @see #onPopulateAccessibilityEvent(AccessibilityEvent)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
     }
 
     /**
@@ -5434,6 +5439,7 @@
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
+    @CallSuper
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
@@ -5446,10 +5452,12 @@
      * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         event.setSource(this);
-        event.setClassName(View.class.getName());
+        event.setClassName(getAccessibilityClassName());
         event.setPackageName(getContext().getPackageName());
         event.setEnabled(isEnabled());
         event.setContentDescription(mContentDescription);
@@ -5502,8 +5510,10 @@
 
     /**
      * @see #createAccessibilityNodeInfo()
+     *
+     * @hide
      */
-    AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
+    public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             return provider.createAccessibilityNodeInfo(View.NO_ID);
@@ -5544,6 +5554,7 @@
      *
      * @param info The instance to initialize.
      */
+    @CallSuper
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         if (mAccessibilityDelegate != null) {
             mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
@@ -5617,11 +5628,33 @@
     }
 
     /**
+     * Return the class name of this object to be used for accessibility purposes.
+     * Subclasses should only override this if they are implementing something that
+     * should be seen as a completely new class of view when used by accessibility,
+     * unrelated to the class it is deriving from.  This is used to fill in
+     * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}.
+     */
+    public CharSequence getAccessibilityClassName() {
+        return View.class.getName();
+    }
+
+    /**
+     * Called when assist structure is being retrieved from a view as part of
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * @param structure Additional standard structured view structure to supply.
+     * @param extras Non-standard extensions.
+     */
+    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
+    }
+
+    /**
      * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
      *
      * Note: Called from the default {@link AccessibilityDelegate}.
+     *
+     * @hide
      */
-    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         Rect bounds = mAttachInfo.mTmpInvalRect;
 
         getDrawingRect(bounds);
@@ -5696,7 +5729,7 @@
         info.setVisibleToUser(isVisibleToUser());
 
         info.setPackageName(mContext.getPackageName());
-        info.setClassName(View.class.getName());
+        info.setClassName(getAccessibilityClassName());
         info.setContentDescription(getContentDescription());
 
         info.setEnabled(isEnabled());
@@ -5843,7 +5876,7 @@
      *
      * @see AccessibilityDelegate
      */
-    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+    public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
         mAccessibilityDelegate = delegate;
     }
 
@@ -6057,7 +6090,7 @@
      * @param id The labeled view id.
      */
     @RemotableViewMethod
-    public void setLabelFor(int id) {
+    public void setLabelFor(@IdRes int id) {
         if (mLabelForId == id) {
             return;
         }
@@ -6083,6 +6116,7 @@
      *
      * @hide pending API council approval
      */
+    @CallSuper
     protected void onFocusLost() {
         resetPressedState();
     }
@@ -6549,6 +6583,19 @@
     }
 
     /**
+     * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are
+     * only available if the view is attached.
+     *
+     * @return WindowInsets from the top of the view hierarchy or null if View is detached
+     */
+    public WindowInsets getRootWindowInsets() {
+        if (mAttachInfo != null) {
+            return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */);
+        }
+        return null;
+    }
+
+    /**
      * @hide Compute the insets that should be consumed by this view and the ones
      * that should propagate to those under it.
      */
@@ -6691,7 +6738,6 @@
     @RemotableViewMethod
     public void setVisibility(@Visibility int visibility) {
         setFlags(visibility, VISIBILITY_MASK);
-        if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
     }
 
     /**
@@ -7394,8 +7440,8 @@
      * including this view if it is focusable itself) to views. This method
      * adds all focusable views regardless if we are in touch mode or
      * only views focusable in touch mode if we are in touch mode or
-     * only views that can take accessibility focus if accessibility is enabeld
-     * depending on the focusable mode paramater.
+     * only views that can take accessibility focus if accessibility is enabled
+     * depending on the focusable mode parameter.
      *
      * @param views Focusable views found so far or null if all we are interested is
      *        the number of focusables.
@@ -7681,7 +7727,7 @@
 
     /**
      * Call this to try to give focus to a specific view or to one of its descendants. This is a
-     * special variant of {@link #requestFocus() } that will allow views that are not focuable in
+     * special variant of {@link #requestFocus() } that will allow views that are not focusable in
      * touch mode to request focus when they are touched.
      *
      * @return Whether this view or one of its descendants actually took focus.
@@ -8083,7 +8129,7 @@
     *
     * Note: Called from the default {@link AccessibilityDelegate}.
     *
-    * @hide Until we've refactored all accessibility delegation methods.
+    * @hide
     */
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         if (isNestedScrollingEnabled()
@@ -8732,20 +8778,28 @@
     }
 
     /**
-     * Called when the visibility of the view or an ancestor of the view is changed.
-     * @param changedView The view whose visibility changed. Could be 'this' or
-     * an ancestor view.
-     * @param visibility The new visibility of changedView: {@link #VISIBLE},
-     * {@link #INVISIBLE} or {@link #GONE}.
+     * Called when the visibility of the view or an ancestor of the view has
+     * changed.
+     *
+     * @param changedView The view whose visibility changed. May be
+     *                    {@code this} or an ancestor view.
+     * @param visibility The new visibility, one of {@link #VISIBLE},
+     *                   {@link #INVISIBLE} or {@link #GONE}.
      */
     protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
-        if (visibility == VISIBLE) {
+        final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
+        if (visible) {
             if (mAttachInfo != null) {
                 initialAwakenScrollBars();
             } else {
                 mPrivateFlags |= PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH;
             }
         }
+
+        final Drawable dr = mBackground;
+        if (dr != null && visible != dr.isVisible()) {
+            dr.setVisible(visible, false);
+        }
     }
 
     /**
@@ -8868,7 +8922,7 @@
      * Called when the current configuration of the resources being used
      * by the application have changed.  You can use this to decide when
      * to reload resources that can changed based on orientation and other
-     * configuration characterstics.  You only need to use this if you are
+     * configuration characteristics.  You only need to use this if you are
      * not relying on the normal {@link android.app.Activity} mechanism of
      * recreating the activity instance upon a configuration change.
      *
@@ -9875,9 +9929,15 @@
 
     /**
      * Interface definition for a callback to be invoked when the scroll
-     * position of a view changes.
+     * X or Y positions of a view change.
+     * <p>
+     * <b>Note:</b> Some views handle scrolling independently from View and may
+     * have their own separate listeners for scroll-type events. For example,
+     * {@link android.widget.ListView ListView} allows clients to register an
+     * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener}
+     * to listen for changes in list scroll position.
      *
-     * @hide Only used internally.
+     * @see #setOnScrollChangeListener(View.OnScrollChangeListener)
      */
     public interface OnScrollChangeListener {
         /**
@@ -10046,6 +10106,10 @@
      *
      * @return The measured width of this view as a bit mask.
      */
+    @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
+            @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
+                    name = "MEASURED_STATE_TOO_SMALL"),
+    })
     public final int getMeasuredWidthAndState() {
         return mMeasuredWidth;
     }
@@ -10070,6 +10134,10 @@
      *
      * @return The measured width of this view as a bit mask.
      */
+    @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
+            @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
+                    name = "MEASURED_STATE_TOO_SMALL"),
+    })
     public final int getMeasuredHeightAndState() {
         return mMeasuredHeight;
     }
@@ -10537,7 +10605,7 @@
      * <p>Note that if the view is backed by a
      * {@link #setLayerType(int, android.graphics.Paint) layer} and is associated with a
      * {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an alpha value less than
-     * 1.0 will supercede the alpha of the layer paint.</p>
+     * 1.0 will supersede the alpha of the layer paint.</p>
      *
      * @param alpha The opacity of the view.
      *
@@ -10546,7 +10614,7 @@
      *
      * @attr ref android.R.styleable#View_alpha
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         ensureTransformationInfo();
         if (mTransformationInfo.mAlpha != alpha) {
             mTransformationInfo.mAlpha = alpha;
@@ -11585,7 +11653,7 @@
      * </p>
      *
      * <p>
-     * This method should be invoked everytime a subclass directly updates the
+     * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
      * </p>
      *
@@ -11624,7 +11692,7 @@
      * </p>
      *
      * <p>
-     * This method should be invoked everytime a subclass directly updates the
+     * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
      * </p>
      *
@@ -11632,7 +11700,7 @@
      *        should start; when the delay is 0, the animation starts
      *        immediately
      *
-     * @param invalidate Wheter this method should call invalidate
+     * @param invalidate Whether this method should call invalidate
      *
      * @return true if the animation is played, false otherwise
      *
@@ -11652,6 +11720,8 @@
 
         if (scrollCache.scrollBar == null) {
             scrollCache.scrollBar = new ScrollBarDrawable();
+            scrollCache.scrollBar.setCallback(this);
+            scrollCache.scrollBar.setState(getDrawableState());
         }
 
         if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
@@ -12537,7 +12607,7 @@
     /**
      * Define whether scrollbars will fade when the view is not scrolling.
      *
-     * @param fadeScrollbars wheter to enable fading
+     * @param fadeScrollbars whether to enable fading
      *
      * @attr ref android.R.styleable#View_fadeScrollbars
      */
@@ -13051,6 +13121,7 @@
      *
      * @see #onDetachedFromWindow()
      */
+    @CallSuper
     protected void onAttachedToWindow() {
         if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
             mParent.requestTransparentRegion(this);
@@ -13072,7 +13143,9 @@
 
         if (isFocused()) {
             InputMethodManager imm = InputMethodManager.peekInstance();
-            imm.focusIn(this);
+            if (imm != null) {
+                imm.focusIn(this);
+            }
         }
     }
 
@@ -13381,6 +13454,7 @@
      *
      * @see #onAttachedToWindow()
      */
+    @CallSuper
     protected void onDetachedFromWindow() {
     }
 
@@ -13389,11 +13463,12 @@
      * after onDetachedFromWindow().
      *
      * If you override this you *MUST* call super.onDetachedFromWindowInternal()!
-     * The super method should be called at the end of the overriden method to ensure
+     * The super method should be called at the end of the overridden method to ensure
      * subclasses are destroyed first
      *
      * @hide
      */
+    @CallSuper
     protected void onDetachedFromWindowInternal() {
         mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
         mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
@@ -13700,6 +13775,7 @@
      * @see #dispatchSaveInstanceState(android.util.SparseArray)
      * @see #setSaveEnabled(boolean)
      */
+    @CallSuper
     protected Parcelable onSaveInstanceState() {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         return BaseSavedState.EMPTY_STATE;
@@ -13758,6 +13834,7 @@
      * @see #restoreHierarchyState(android.util.SparseArray)
      * @see #dispatchRestoreInstanceState(android.util.SparseArray)
      */
+    @CallSuper
     protected void onRestoreInstanceState(Parcelable state) {
         mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (state != BaseSavedState.EMPTY_STATE && state != null) {
@@ -13790,7 +13867,7 @@
      * <p>Note: if this view's parent addStateFromChildren property is enabled and this
      * property is enabled, an exception will be thrown.</p>
      *
-     * <p>Note: if the child view uses and updates additionnal states which are unknown to the
+     * <p>Note: if the child view uses and updates additional states which are unknown to the
      * parent, these states should not be affected by this method.</p>
      *
      * @param enabled True to enable duplication of the parent's drawable state, false
@@ -13831,7 +13908,7 @@
      * </ul>
      *
      * <p>If this view has an alpha value set to < 1.0 by calling
-     * {@link #setAlpha(float)}, the alpha value of the layer's paint is superceded
+     * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded
      * by this view's alpha value.</p>
      *
      * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE},
@@ -13899,7 +13976,7 @@
      * </ul>
      *
      * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the
-     * alpha value of the layer's paint is superceded by this view's alpha value.</p>
+     * alpha value of the layer's paint is superseded by this view's alpha value.</p>
      *
      * @param paint The paint used to compose the layer. This argument is optional
      *        and can be null. It is ignored when the layer type is
@@ -14008,6 +14085,7 @@
      *
      * @hide
      */
+    @CallSuper
     protected void destroyHardwareResources() {
         // Although the Layer will be destroyed by RenderNode, we want to release
         // the staging display list, which is also a signal to RenderNode that it's
@@ -14280,7 +14358,7 @@
      * @see #buildDrawingCache()
      * @see #getDrawingCache()
      */
-    public void setDrawingCacheBackgroundColor(int color) {
+    public void setDrawingCacheBackgroundColor(@ColorInt int color) {
         if (color != mDrawingCacheBackgroundColor) {
             mDrawingCacheBackgroundColor = color;
             mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
@@ -14292,6 +14370,7 @@
      *
      * @return The background color to used for the drawing cache's bitmap
      */
+    @ColorInt
     public int getDrawingCacheBackgroundColor() {
         return mDrawingCacheBackgroundColor;
     }
@@ -14803,10 +14882,9 @@
     void setDisplayListProperties(RenderNode renderNode) {
         if (renderNode != null) {
             renderNode.setHasOverlappingRendering(hasOverlappingRendering());
-            if (mParent instanceof ViewGroup) {
-                renderNode.setClipToBounds(
-                        (((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
-            }
+            renderNode.setClipToBounds(mParent instanceof ViewGroup
+                    && ((ViewGroup) mParent).getClipChildren());
+
             float alpha = 1;
             if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
                     ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -15141,7 +15219,7 @@
                     }
                 } else {
                     mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
+                    ((HardwareCanvas) canvas).drawRenderNode(renderNode, flags);
                 }
             }
         } else if (cache != null) {
@@ -15197,6 +15275,7 @@
      *
      * @param canvas The Canvas to which the View is rendered.
      */
+    @CallSuper
     public void draw(Canvas canvas) {
         final int privateFlags = mPrivateFlags;
         final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
@@ -15506,6 +15585,7 @@
      * @return The known solid color background for this view, or 0 if the color may vary
      */
     @ViewDebug.ExportedProperty(category = "drawing")
+    @ColorInt
     public int getSolidColor() {
         return 0;
     }
@@ -15798,6 +15878,7 @@
      * <p>Even if the subclass overrides onFinishInflate, they should always be
      * sure to call the super method, so that we get called.
      */
+    @CallSuper
     protected void onFinishInflate() {
     }
 
@@ -15963,8 +16044,9 @@
      * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
      * @see #drawableStateChanged()
      */
+    @CallSuper
     protected boolean verifyDrawable(Drawable who) {
-        return who == mBackground;
+        return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who);
     }
 
     /**
@@ -15978,14 +16060,24 @@
      *
      * @see Drawable#setState(int[])
      */
+    @CallSuper
     protected void drawableStateChanged() {
+        final int[] state = getDrawableState();
+
         final Drawable d = mBackground;
         if (d != null && d.isStateful()) {
-            d.setState(getDrawableState());
+            d.setState(state);
+        }
+
+        if (mScrollCache != null) {
+            final Drawable scrollBar = mScrollCache.scrollBar;
+            if (scrollBar != null && scrollBar.isStateful()) {
+                scrollBar.setState(state);
+            }
         }
 
         if (mStateListAnimator != null) {
-            mStateListAnimator.setState(getDrawableState());
+            mStateListAnimator.setState(state);
         }
     }
 
@@ -16001,6 +16093,7 @@
      * @param x hotspot x coordinate
      * @param y hotspot y coordinate
      */
+    @CallSuper
     public void drawableHotspotChanged(float x, float y) {
         if (mBackground != null) {
             mBackground.setHotspot(x, y);
@@ -16083,26 +16176,30 @@
         int privateFlags = mPrivateFlags;
 
         int viewStateIndex = 0;
-        if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED;
-        if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= VIEW_STATE_ENABLED;
-        if (isFocused()) viewStateIndex |= VIEW_STATE_FOCUSED;
-        if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED;
-        if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED;
-        if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED;
+        if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED;
+        if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED;
+        if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED;
+        if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED;
+        if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED;
+        if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED;
         if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested &&
                 HardwareRenderer.isAvailable()) {
             // This is set if HW acceleration is requested, even if the current
             // process doesn't allow it.  This is just to allow app preview
             // windows to better match their app.
-            viewStateIndex |= VIEW_STATE_ACCELERATED;
+            viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED;
         }
-        if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED;
+        if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED;
 
         final int privateFlags2 = mPrivateFlags2;
-        if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) viewStateIndex |= VIEW_STATE_DRAG_CAN_ACCEPT;
-        if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_DRAG_HOVERED;
+        if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) {
+            viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT;
+        }
+        if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) {
+            viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED;
+        }
 
-        drawableState = VIEW_STATE_SETS[viewStateIndex];
+        drawableState = StateSet.get(viewStateIndex);
 
         //noinspection ConstantIfStatement
         if (false) {
@@ -16179,7 +16276,7 @@
      * @param color the color of the background
      */
     @RemotableViewMethod
-    public void setBackgroundColor(int color) {
+    public void setBackgroundColor(@ColorInt int color) {
         if (mBackground instanceof ColorDrawable) {
             ((ColorDrawable) mBackground.mutate()).setColor(color);
             computeOpaqueFlags();
@@ -16190,6 +16287,20 @@
     }
 
     /**
+     * If the view has a ColorDrawable background, returns the color of that
+     * drawable.
+     *
+     * @return The color of the ColorDrawable background, if set, otherwise 0.
+     */
+    @ColorInt
+    public int getBackgroundColor() {
+        if (mBackground instanceof ColorDrawable) {
+            return ((ColorDrawable) mBackground).getColor();
+        }
+        return 0;
+    }
+
+    /**
      * Set the background to a given resource. The resource should refer to
      * a Drawable object or 0 to remove the background.
      * @param resid The identifier of the resource.
@@ -16197,7 +16308,7 @@
      * @attr ref android.R.styleable#View_background
      */
     @RemotableViewMethod
-    public void setBackgroundResource(int resid) {
+    public void setBackgroundResource(@DrawableRes int resid) {
         if (resid != 0 && resid == mBackgroundResource) {
             return;
         }
@@ -16652,8 +16763,8 @@
     }
 
     /**
-     * Return if the padding as been set thru relative values
-     * {@link #setPaddingRelative(int, int, int, int)} or thru
+     * Return if the padding has been set through relative values
+     * {@link #setPaddingRelative(int, int, int, int)} or through
      * @attr ref android.R.styleable#View_paddingStart or
      * @attr ref android.R.styleable#View_paddingEnd
      *
@@ -16955,7 +17066,7 @@
      *
      * @param location an array of two integers in which to hold the coordinates
      */
-    public void getLocationOnScreen(int[] location) {
+    public void getLocationOnScreen(@Size(2) int[] location) {
         getLocationInWindow(location);
 
         final AttachInfo info = mAttachInfo;
@@ -16972,7 +17083,7 @@
      *
      * @param location an array of two integers in which to hold the coordinates
      */
-    public void getLocationInWindow(int[] location) {
+    public void getLocationInWindow(@Size(2) int[] location) {
         if (location == null || location.length < 2) {
             throw new IllegalArgumentException("location must be an array of two integers");
         }
@@ -17025,7 +17136,7 @@
      * @param id the id of the view to be found
      * @return the view of the specified id, null if cannot be found
      */
-    protected View findViewTraversal(int id) {
+    protected View findViewTraversal(@IdRes int id) {
         if (id == mID) {
             return this;
         }
@@ -17064,7 +17175,8 @@
      * @param id The id to search for.
      * @return The view that has the given id in the hierarchy or null
      */
-    public final View findViewById(int id) {
+    @Nullable
+    public final View findViewById(@IdRes int id) {
         if (id < 0) {
             return null;
         }
@@ -17179,7 +17291,7 @@
      *
      * @attr ref android.R.styleable#View_id
      */
-    public void setId(int id) {
+    public void setId(@IdRes int id) {
         mID = id;
         if (mID == View.NO_ID && mLabelForId != View.NO_ID) {
             mID = generateViewId();
@@ -17219,6 +17331,7 @@
      * @see #findViewById(int)
      * @attr ref android.R.styleable#View_id
      */
+    @IdRes
     @ViewDebug.CapturedViewProperty
     public int getId() {
         return mID;
@@ -17277,7 +17390,7 @@
      *
      * The specified key should be an id declared in the resources of the
      * application to ensure it is unique (see the <a
-     * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
+     * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
      * Keys identified as belonging to
      * the Android framework or not associated with any package will cause
      * an {@link IllegalArgumentException} to be thrown.
@@ -17454,6 +17567,7 @@
      * <p>Subclasses which override this method should call the superclass method to
      * handle possible request-during-layout errors correctly.</p>
      */
+    @CallSuper
     public void requestLayout() {
         if (mMeasureCache != null) mMeasureCache.clear();
 
@@ -17575,7 +17689,7 @@
      * <p>
      * Measure the view and its content to determine the measured width and the
      * measured height. This method is invoked by {@link #measure(int, int)} and
-     * should be overriden by subclasses to provide accurate and efficient
+     * should be overridden by subclasses to provide accurate and efficient
      * measurement of their contents.
      * </p>
      *
@@ -17688,37 +17802,40 @@
 
     /**
      * Utility to reconcile a desired size and state, with constraints imposed
-     * by a MeasureSpec.  Will take the desired size, unless a different size
-     * is imposed by the constraints.  The returned value is a compound integer,
+     * by a MeasureSpec. Will take the desired size, unless a different size
+     * is imposed by the constraints. The returned value is a compound integer,
      * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
-     * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
-     * size is smaller than the size the view wants to be.
+     * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the
+     * resulting size is smaller than the size the view wants to be.
      *
-     * @param size How big the view wants to be
-     * @param measureSpec Constraints imposed by the parent
+     * @param size How big the view wants to be.
+     * @param measureSpec Constraints imposed by the parent.
+     * @param childMeasuredState Size information bit mask for the view's
+     *                           children.
      * @return Size information bit mask as defined by
-     * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
+     *         {@link #MEASURED_SIZE_MASK} and
+     *         {@link #MEASURED_STATE_TOO_SMALL}.
      */
     public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
-        int result = size;
-        int specMode = MeasureSpec.getMode(measureSpec);
-        int specSize =  MeasureSpec.getSize(measureSpec);
+        final int specMode = MeasureSpec.getMode(measureSpec);
+        final int specSize = MeasureSpec.getSize(measureSpec);
+        final int result;
         switch (specMode) {
-        case MeasureSpec.UNSPECIFIED:
-            result = size;
-            break;
-        case MeasureSpec.AT_MOST:
-            if (specSize < size) {
-                result = specSize | MEASURED_STATE_TOO_SMALL;
-            } else {
+            case MeasureSpec.AT_MOST:
+                if (specSize < size) {
+                    result = specSize | MEASURED_STATE_TOO_SMALL;
+                } else {
+                    result = size;
+                }
+                break;
+            case MeasureSpec.EXACTLY:
+                result = specSize;
+                break;
+            case MeasureSpec.UNSPECIFIED:
+            default:
                 result = size;
-            }
-            break;
-        case MeasureSpec.EXACTLY:
-            result = specSize;
-            break;
         }
-        return result | (childMeasuredState&MEASURED_STATE_MASK);
+        return result | (childMeasuredState & MEASURED_STATE_MASK);
     }
 
     /**
@@ -17906,6 +18023,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationStart() {
         mPrivateFlags |= PFLAG_ANIMATION_STARTED;
     }
@@ -17918,6 +18036,7 @@
      * @see #setAnimation(android.view.animation.Animation)
      * @see #getAnimation()
      */
+    @CallSuper
     protected void onAnimationEnd() {
         mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
     }
@@ -18181,7 +18300,7 @@
      * appearance as the given View. The default also positions the center of the drag shadow
      * directly under the touch point. If no View is provided (the constructor with no parameters
      * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and
-     * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overriden, then the
+     * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the
      * default is an invisible drag shadow.
      * <p>
      * You are not required to use the View you provide to the constructor as the basis of the
@@ -18810,7 +18929,7 @@
      * @see #dispatchNestedPreScroll(int, int, int[], int[])
      */
     public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+            int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
             if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
                 int startX = 0;
@@ -18858,7 +18977,8 @@
      * @return true if the parent consumed some or all of the scroll delta
      * @see #dispatchNestedScroll(int, int, int, int, int[])
      */
-    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+    public boolean dispatchNestedPreScroll(int dx, int dy,
+            @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) {
         if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
             if (dx != 0 || dy != 0) {
                 int startX = 0;
diff --git a/core/java/android/view/ViewAssistStructure.java b/core/java/android/view/ViewAssistStructure.java
new file mode 100644
index 0000000..5132bb9
--- /dev/null
+++ b/core/java/android/view/ViewAssistStructure.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.text.TextPaint;
+
+/**
+ * Container for storing additional per-view data generated by {@link View#onProvideAssistStructure
+ * View.onProvideAssistStructure}.
+ */
+public abstract class ViewAssistStructure {
+    public abstract void setText(CharSequence text);
+    public abstract void setText(CharSequence text, int selectionStart, int selectionEnd);
+    public abstract void setTextPaint(TextPaint paint);
+    public abstract void setHint(CharSequence hint);
+
+    public abstract CharSequence getText();
+    public abstract int getTextSelectionStart();
+    public abstract int getTextSelectionEnd();
+    public abstract CharSequence getHint();
+}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c4b689f..87f3e94 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.animation.LayoutTransition;
+import android.annotation.IdRes;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
@@ -52,11 +53,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
-
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
 /**
@@ -371,6 +369,26 @@
     static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
 
     /**
+     * When true, indicates that a call to startActionModeForChild was made with the type parameter
+     * and should not be ignored. This helps in backwards compatibility with the existing method
+     * without a type.
+     *
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
+     */
+    private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
+
+    /**
+     * When true, indicates that a call to startActionModeForChild was made without the type
+     * parameter. This helps in backwards compatibility with the existing method
+     * without a type.
+     *
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
+     */
+    private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
+
+    /**
      * Indicates which types of drawing caches are to be kept in memory.
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -481,6 +499,60 @@
      */
     private int mNestedScrollAxes;
 
+    /**
+     * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
+     *
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
+     */
+    private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
+        @Override
+        public void setTitle(CharSequence title) {}
+
+        @Override
+        public void setTitle(int resId) {}
+
+        @Override
+        public void setSubtitle(CharSequence subtitle) {}
+
+        @Override
+        public void setSubtitle(int resId) {}
+
+        @Override
+        public void setCustomView(View view) {}
+
+        @Override
+        public void invalidate() {}
+
+        @Override
+        public void finish() {}
+
+        @Override
+        public Menu getMenu() {
+            return null;
+        }
+
+        @Override
+        public CharSequence getTitle() {
+            return null;
+        }
+
+        @Override
+        public CharSequence getSubtitle() {
+            return null;
+        }
+
+        @Override
+        public View getCustomView() {
+            return null;
+        }
+
+        @Override
+        public MenuInflater getMenuInflater() {
+            return null;
+        }
+    };
+
     public ViewGroup(Context context) {
         this(context, null);
     }
@@ -696,8 +768,49 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
-        return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
+        if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
+            // This is the original call.
+            try {
+                mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
+                return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
+            } finally {
+                mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
+            }
+        } else {
+            // We are being called from the new method with type.
+            return SENTINEL_ACTION_MODE;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ActionMode startActionModeForChild(
+            View originalView, ActionMode.Callback callback, int type) {
+        if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0) {
+            ActionMode mode;
+            try {
+                mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
+                mode = startActionModeForChild(originalView, callback);
+            } finally {
+                mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
+            }
+            if (mode != SENTINEL_ACTION_MODE) {
+                return mode;
+            }
+        }
+        if (mParent != null) {
+            try {
+                return mParent.startActionModeForChild(originalView, callback, type);
+            } catch (AbstractMethodError ame) {
+                // Custom view parents might not implement this method.
+                return mParent.startActionModeForChild(originalView, callback);
+            }
+        }
+        return null;
     }
 
     /**
@@ -771,8 +884,10 @@
      * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
      *
      * Note: Called from the default {@link View.AccessibilityDelegate}.
+     *
+     * @hide
      */
-    boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
+    public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
         return true;
     }
 
@@ -1206,7 +1321,7 @@
      * {@inheritDoc}
      */
     public void bringChildToFront(View child) {
-        int index = indexOfChild(child);
+        final int index = indexOfChild(child);
         if (index >= 0) {
             removeFromArray(index);
             addInArray(child, mChildrenCount);
@@ -2708,8 +2823,9 @@
         }
     }
 
+    /** @hide */
     @Override
-    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         boolean handled = false;
         if (includeForAccessibility()) {
             handled = super.dispatchPopulateAccessibilityEventInternal(event);
@@ -2736,8 +2852,9 @@
         return false;
     }
 
+    /** @hide */
     @Override
-    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
         if (getAccessibilityNodeProvider() != null) {
             return;
@@ -2755,8 +2872,9 @@
         }
     }
 
+    /** @hide */
     @Override
-    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
         event.setClassName(ViewGroup.class.getName());
     }
@@ -3607,7 +3725,7 @@
      * {@hide}
      */
     @Override
-    protected View findViewTraversal(int id) {
+    protected View findViewTraversal(@IdRes int id) {
         if (id == mID) {
             return this;
         }
@@ -3766,7 +3884,7 @@
      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
-     * @param index the position at which to add the child
+     * @param index the position at which to add the child or -1 to add last
      * @param params the layout parameters to set on the child
      */
     public void addView(View child, int index, LayoutParams params) {
@@ -3882,7 +4000,7 @@
      * If index is negative, it means put it at the end of the list.
      *
      * @param child the view to add to the group
-     * @param index the index at which the child must be added
+     * @param index the index at which the child must be added or -1 to add last
      * @param params the layout parameters to associate with the child
      * @return true if the child was added, false otherwise
      */
@@ -3897,7 +4015,7 @@
      * If index is negative, it means put it at the end of the list.
      *
      * @param child the view to add to the group
-     * @param index the index at which the child must be added
+     * @param index the index at which the child must be added or -1 to add last
      * @param params the layout parameters to associate with the child
      * @param preventRequestLayout if true, calling this method will not trigger a
      *        layout request on child
@@ -6377,8 +6495,8 @@
 
         /**
          * Information about how wide the view wants to be. Can be one of the
-         * constants FILL_PARENT (replaced by MATCH_PARENT ,
-         * in API Level 8) or WRAP_CONTENT. or an exact size.
+         * constants FILL_PARENT (replaced by MATCH_PARENT
+         * in API Level 8) or WRAP_CONTENT, or an exact size.
          */
         @ViewDebug.ExportedProperty(category = "layout", mapping = {
             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
@@ -6388,8 +6506,8 @@
 
         /**
          * Information about how tall the view wants to be. Can be one of the
-         * constants FILL_PARENT (replaced by MATCH_PARENT ,
-         * in API Level 8) or WRAP_CONTENT. or an exact size.
+         * constants FILL_PARENT (replaced by MATCH_PARENT
+         * in API Level 8) or WRAP_CONTENT, or an exact size.
          */
         @ViewDebug.ExportedProperty(category = "layout", mapping = {
             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 035871d..15b86d1 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -190,7 +190,8 @@
     public void createContextMenu(ContextMenu menu);
 
     /**
-     * Start an action mode for the specified view.
+     * Start an action mode for the specified view with the default type
+     * {@link ActionMode#TYPE_PRIMARY}.
      *
      * <p>In most cases, a subclass does not need to override this. However, if the
      * subclass is added directly to the window manager (for example,
@@ -200,17 +201,35 @@
      * @param originalView The source view where the action mode was first invoked
      * @param callback The callback that will handle lifecycle events for the action mode
      * @return The new action mode if it was started, null otherwise
+     *
+     * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
      */
     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback);
 
     /**
+     * Start an action mode of a specific type for the specified view.
+     *
+     * <p>In most cases, a subclass does not need to override this. However, if the
+     * subclass is added directly to the window manager (for example,
+     * {@link ViewManager#addView(View, android.view.ViewGroup.LayoutParams)})
+     * then it should override this and start the action mode.</p>
+     *
+     * @param originalView The source view where the action mode was first invoked
+     * @param callback The callback that will handle lifecycle events for the action mode
+     * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}.
+     * @return The new action mode if it was started, null otherwise
+     */
+    public ActionMode startActionModeForChild(
+            View originalView, ActionMode.Callback callback, int type);
+
+    /**
      * This method is called on the parent when a child's drawable state
      * has changed.
      *
      * @param child The child whose drawable state has changed.
      */
     public void childDrawableStateChanged(View child);
-    
+
     /**
      * Called when a child does not want this parent and its ancestors to
      * intercept touch events with
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index b73b9fa..f18b7ac 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -19,8 +19,6 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.animation.TimeInterpolator;
-import android.os.Build;
-
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Set;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e4d82b1..1473806 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -56,6 +56,7 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
@@ -76,7 +77,6 @@
 
 import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PolicyManager;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
 
@@ -265,6 +265,8 @@
     final Rect mDispatchContentInsets = new Rect();
     final Rect mDispatchStableInsets = new Rect();
 
+    private WindowInsets mLastWindowInsets;
+
     final Configuration mLastConfiguration = new Configuration();
     final Configuration mPendingConfiguration = new Configuration();
 
@@ -386,7 +388,7 @@
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
-        mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
+        mFallbackEventHandler = new PhoneFallbackEventHandler(context);
         mChoreographer = Choreographer.getInstance();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
@@ -472,12 +474,13 @@
 
                 // Compute surface insets required to draw at specified Z value.
                 // TODO: Use real shadow insets for a constant max Z.
-                final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
-                attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                if (!attrs.hasManualSurfaceInsets) {
+                    final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+                    attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                }
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
                 mTranslator = compatibilityInfo.getTranslator();
-                mDisplayAdjustments.setActivityToken(attrs.token);
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
@@ -549,6 +552,11 @@
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
+                try {
+                    relayoutWindow(attrs, getHostVisibility(), false);
+                } catch (RemoteException e) {
+                    if (DEBUG_LAYOUT) Log.e(TAG, "failed to relayoutWindow", e);
+                }
                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                     mAttachInfo.mRootView = null;
@@ -649,6 +657,10 @@
         return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
     }
 
+    public CharSequence getTitle() {
+        return mWindowAttributes.getTitle();
+    }
+
     void destroyHardwareResources() {
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
@@ -760,6 +772,7 @@
             final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
             final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
             final int oldSoftInputMode = mWindowAttributes.softInputMode;
+            final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;
 
             // Keep track of the actual window flags supplied by the client.
             mClientWindowLayoutFlags = attrs.flags;
@@ -786,6 +799,7 @@
             // Restore old surface insets.
             mWindowAttributes.surfaceInsets.set(
                     oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+            mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
 
             applyKeepScreenOnFlag(mWindowAttributes);
 
@@ -831,6 +845,7 @@
                 final int newDisplayState = mDisplay.getState();
                 if (oldDisplayState != newDisplayState) {
                     mAttachInfo.mDisplayState = newDisplayState;
+                    pokeDrawLockIfNeeded();
                     if (oldDisplayState != Display.STATE_UNKNOWN) {
                         final int oldScreenState = toViewScreenState(oldDisplayState);
                         final int newScreenState = toViewScreenState(newDisplayState);
@@ -861,6 +876,19 @@
         }
     };
 
+    void pokeDrawLockIfNeeded() {
+        final int displayState = mAttachInfo.mDisplayState;
+        if (mView != null && mAdded && mTraversalScheduled
+                && (displayState == Display.STATE_DOZE
+                        || displayState == Display.STATE_DOZE_SUSPEND)) {
+            try {
+                mWindowSession.pokeDrawLock(mWindow);
+            } catch (RemoteException ex) {
+                // System server died, oh well.
+            }
+        }
+    }
+
     @Override
     public void requestFitSystemWindows() {
         checkThread();
@@ -1028,20 +1056,21 @@
     void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
-            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
+            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
             if (!mUnbufferedInputDispatch) {
                 scheduleConsumeBatchedInput();
             }
             notifyRendererOfFramePending();
+            pokeDrawLockIfNeeded();
         }
     }
 
     void unscheduleTraversals() {
         if (mTraversalScheduled) {
             mTraversalScheduled = false;
-            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
+            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
         }
@@ -1050,7 +1079,7 @@
     void doTraversal() {
         if (mTraversalScheduled) {
             mTraversalScheduled = false;
-            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
+            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
 
             if (mProfile) {
                 Debug.startMethodTracing("ViewAncestor");
@@ -1205,13 +1234,29 @@
         m.postTranslate(-mAttachInfo.mWindowLeft, -mAttachInfo.mWindowTop);
     }
 
+    /* package */ WindowInsets getWindowInsets(boolean forceConstruct) {
+        if (mLastWindowInsets == null || forceConstruct) {
+            mDispatchContentInsets.set(mAttachInfo.mContentInsets);
+            mDispatchStableInsets.set(mAttachInfo.mStableInsets);
+            Rect contentInsets = mDispatchContentInsets;
+            Rect stableInsets = mDispatchStableInsets;
+            // For dispatch we preserve old logic, but for direct requests from Views we allow to
+            // immediately use pending insets.
+            if (!forceConstruct
+                    && (!mPendingContentInsets.equals(contentInsets) ||
+                        !mPendingStableInsets.equals(stableInsets))) {
+                contentInsets = mPendingContentInsets;
+                stableInsets = mPendingStableInsets;
+            }
+            final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound;
+            mLastWindowInsets = new WindowInsets(contentInsets,
+                    null /* windowDecorInsets */, stableInsets, isRound);
+        }
+        return mLastWindowInsets;
+    }
+
     void dispatchApplyInsets(View host) {
-        mDispatchContentInsets.set(mAttachInfo.mContentInsets);
-        mDispatchStableInsets.set(mAttachInfo.mStableInsets);
-        final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound;
-        host.dispatchApplyWindowInsets(new WindowInsets(
-                mDispatchContentInsets, null /* windowDecorInsets */,
-                mDispatchStableInsets, isRound));
+        host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
     }
 
     private void performTraversals() {
@@ -1326,12 +1371,17 @@
             }
         }
 
+        // Non-visible windows can't hold accessibility focus.
+        if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
+            host.clearAccessibilityFocus();
+        }
+
         // Execute enqueued actions on every traversal in case a detached view enqueued an action
         getRunQueue().executeActions(mAttachInfo.mHandler);
 
         boolean insetsChanged = false;
 
-        boolean layoutRequested = mLayoutRequested && !mStopped;
+        boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
         if (layoutRequested) {
 
             final Resources res = mView.getContext().getResources();
@@ -1502,6 +1552,7 @@
                         // to resume them
                         mDirty.set(0, 0, mWidth, mHeight);
                     }
+                    mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
                 }
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
@@ -1763,7 +1814,7 @@
                 }
             }
 
-            if (!mStopped) {
+            if (!mStopped || mReportNextDraw) {
                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                         (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
@@ -1836,7 +1887,7 @@
             }
         }
 
-        final boolean didLayout = layoutRequested && !mStopped;
+        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
         boolean triggerGlobalLayoutListener = didLayout
                 || mAttachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
@@ -2505,6 +2556,9 @@
             }
         }
 
+        mAttachInfo.mDrawingTime =
+                mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
+
         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                 // If accessibility focus moved, always invalidate the root.
@@ -2624,7 +2678,6 @@
 
             dirty.setEmpty();
             mIsAnimating = false;
-            attachInfo.mDrawingTime = SystemClock.uptimeMillis();
             mView.mPrivateFlags |= View.PFLAG_DRAWN;
 
             if (DEBUG_DRAW) {
@@ -3069,17 +3122,6 @@
         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
     }
 
-    private static void forceLayout(View view) {
-        view.forceLayout();
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            final int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                forceLayout(group.getChildAt(i));
-            }
-        }
-    }
-
     private final static int MSG_INVALIDATE = 1;
     private final static int MSG_INVALIDATE_RECT = 2;
     private final static int MSG_DIE = 3;
@@ -3213,10 +3255,6 @@
                         mReportNextDraw = true;
                     }
 
-                    if (mView != null) {
-                        forceLayout(mView);
-                    }
-
                     requestLayout();
                 }
                 break;
@@ -3231,9 +3269,6 @@
                     mWinFrame.top = t;
                     mWinFrame.bottom = t + h;
 
-                    if (mView != null) {
-                        forceLayout(mView);
-                    }
                     requestLayout();
                 }
                 break;
@@ -5778,6 +5813,16 @@
             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                     mPendingInputEventCount);
 
+            long eventTime = q.mEvent.getEventTimeNano();
+            long oldestEventTime = eventTime;
+            if (q.mEvent instanceof MotionEvent) {
+                MotionEvent me = (MotionEvent)q.mEvent;
+                if (me.getHistorySize() > 0) {
+                    oldestEventTime = me.getHistoricalEventTimeNano(0);
+                }
+            }
+            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
+
             deliverInputEvent(q);
         }
 
@@ -6182,6 +6227,12 @@
     }
 
     @Override
+    public ActionMode startActionModeForChild(
+            View originalView, ActionMode.Callback callback, int type) {
+        return null;
+    }
+
+    @Override
     public void createContextMenu(ContextMenu menu) {
     }
 
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index d68a860..ec852e8 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -69,8 +71,8 @@
  */
 @RemoteView
 public final class ViewStub extends View {
-    private int mLayoutResource = 0;
     private int mInflatedId;
+    private int mLayoutResource;
 
     private WeakReference<View> mInflatedViewRef;
 
@@ -78,7 +80,7 @@
     private OnInflateListener mInflateListener;
 
     public ViewStub(Context context) {
-        initialize(context);
+        this(context, 0);
     }
 
     /**
@@ -87,39 +89,30 @@
      * @param context The application's environment.
      * @param layoutResource The reference to a layout resource that will be inflated.
      */
-    public ViewStub(Context context, int layoutResource) {
+    public ViewStub(Context context, @LayoutRes int layoutResource) {
+        this(context, null);
+
         mLayoutResource = layoutResource;
-        initialize(context);
     }
 
     public ViewStub(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    @SuppressWarnings({"UnusedDeclaration"})
     public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
     public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.ViewStub, defStyleAttr, defStyleRes);
+        super(context);
 
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.ViewStub, defStyleAttr, defStyleRes);
         mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
         mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
-
+        mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
         a.recycle();
 
-        a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
-        mID = a.getResourceId(R.styleable.View_id, NO_ID);
-        a.recycle();
-
-        initialize(context);
-    }
-
-    private void initialize(Context context) {
-        mContext = context;
         setVisibility(GONE);
         setWillNotDraw(true);
     }
@@ -134,6 +127,7 @@
      * @see #setInflatedId(int)
      * @attr ref android.R.styleable#ViewStub_inflatedId
      */
+    @IdRes
     public int getInflatedId() {
         return mInflatedId;
     }
@@ -149,7 +143,7 @@
      * @attr ref android.R.styleable#ViewStub_inflatedId
      */
     @android.view.RemotableViewMethod
-    public void setInflatedId(int inflatedId) {
+    public void setInflatedId(@IdRes int inflatedId) {
         mInflatedId = inflatedId;
     }
 
@@ -165,6 +159,7 @@
      * @see #inflate()
      * @attr ref android.R.styleable#ViewStub_layout
      */
+    @LayoutRes
     public int getLayoutResource() {
         return mLayoutResource;
     }
@@ -182,7 +177,7 @@
      * @attr ref android.R.styleable#ViewStub_layout
      */
     @android.view.RemotableViewMethod
-    public void setLayoutResource(int layoutResource) {
+    public void setLayoutResource(@LayoutRes int layoutResource) {
         mLayoutResource = layoutResource;
     }
 
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 8704356..f36fd5a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,10 @@
 
 package android.view;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -42,10 +46,8 @@
  * area, default key processing, etc.
  *
  * <p>The only existing implementation of this abstract class is
- * android.policy.PhoneWindow, which you should instantiate when needing a
- * Window.  Eventually that class will be refactored and a factory method
- * added for creating Window instances without knowing about a particular
- * implementation.
+ * android.view.PhoneWindow, which you should instantiate when needing a
+ * Window.
  */
 public abstract class Window {
     /** Flag for the "options panel" feature.  This is enabled by default. */
@@ -414,7 +416,9 @@
          * Called when an action mode is being started for this window. Gives the
          * callback an opportunity to handle the action mode in its own unique and
          * beautiful way. If this method returns null the system can choose a way
-         * to present the mode or choose not to start the mode at all.
+         * to present the mode or choose not to start the mode at all. This is equivalent
+         * to {@link #onWindowStartingActionMode(android.view.ActionMode.Callback, int)}
+         * with type {@link ActionMode#TYPE_PRIMARY}.
          *
          * @param callback Callback to control the lifecycle of this action mode
          * @return The ActionMode that was started, or null if the system should present it
@@ -423,6 +427,19 @@
         public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);
 
         /**
+         * Called when an action mode is being started for this window. Gives the
+         * callback an opportunity to handle the action mode in its own unique and
+         * beautiful way. If this method returns null the system can choose a way
+         * to present the mode or choose not to start the mode at all.
+         *
+         * @param callback Callback to control the lifecycle of this action mode
+         * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}.
+         * @return The ActionMode that was started, or null if the system should present it
+         */
+        @Nullable
+        public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type);
+
+        /**
          * Called when an action mode has been started. The appropriate mode callback
          * method will have already been invoked.
          *
@@ -986,7 +1003,8 @@
      *
      * @return The view if found or null otherwise.
      */
-    public View findViewById(int id) {
+    @Nullable
+    public View findViewById(@IdRes int id) {
         return getDecorView().findViewById(id);
     }
 
@@ -999,7 +1017,7 @@
      * @param layoutResID Resource ID to be inflated.
      * @see #setContentView(View, android.view.ViewGroup.LayoutParams)
      */
-    public abstract void setContentView(int layoutResID);
+    public abstract void setContentView(@LayoutRes int layoutResID);
 
     /**
      * Convenience for
@@ -1067,7 +1085,7 @@
     public abstract void setTitle(CharSequence title);
 
     @Deprecated
-    public abstract void setTitleColor(int textColor);
+    public abstract void setTitleColor(@ColorInt int textColor);
 
     public abstract void openPanel(int featureId, KeyEvent event);
 
@@ -1129,7 +1147,7 @@
      * @param resId The resource identifier of a drawable resource which will
      *              be installed as the new background.
      */
-    public void setBackgroundDrawableResource(int resId) {
+    public void setBackgroundDrawableResource(@DrawableRes int resId) {
         setBackgroundDrawable(mContext.getDrawable(resId));
     }
 
@@ -1145,7 +1163,7 @@
 
     /**
      * Set the value for a drawable feature of this window, from a resource
-     * identifier.  You must have called requestFeauture(featureId) before
+     * identifier.  You must have called requestFeature(featureId) before
      * calling this function.
      *
      * @see android.content.res.Resources#getDrawable(int)
@@ -1154,7 +1172,7 @@
      * constant by Window.
      * @param resId Resource identifier of the desired image.
      */
-    public abstract void setFeatureDrawableResource(int featureId, int resId);
+    public abstract void setFeatureDrawableResource(int featureId, @DrawableRes int resId);
 
     /**
      * Set the value for a drawable feature of this window, from a URI. You
@@ -1424,7 +1442,7 @@
      *
      * @param resId resource ID of a drawable to set
      */
-    public void setIcon(int resId) { }
+    public void setIcon(@DrawableRes int resId) { }
 
     /**
      * Set the default icon for this window.
@@ -1433,7 +1451,7 @@
      *
      * @hide
      */
-    public void setDefaultIcon(int resId) { }
+    public void setDefaultIcon(@DrawableRes int resId) { }
 
     /**
      * Set the logo for this window. A logo is often shown in place of an
@@ -1442,7 +1460,7 @@
      *
      * @param resId resource ID of a drawable to set
      */
-    public void setLogo(int resId) { }
+    public void setLogo(@DrawableRes int resId) { }
 
     /**
      * Set the default logo for this window.
@@ -1451,7 +1469,7 @@
      *
      * @hide
      */
-    public void setDefaultLogo(int resId) { }
+    public void setDefaultLogo(@DrawableRes int resId) { }
 
     /**
      * Set focus locally. The window should have the
@@ -1833,6 +1851,7 @@
     /**
      * @return the color of the status bar.
      */
+    @ColorInt
     public abstract int getStatusBarColor();
 
     /**
@@ -1850,11 +1869,12 @@
      * The transitionName for the view background will be "android:status:background".
      * </p>
      */
-    public abstract void setStatusBarColor(int color);
+    public abstract void setStatusBarColor(@ColorInt int color);
 
     /**
      * @return the color of the navigation bar.
      */
+    @ColorInt
     public abstract int getNavigationBarColor();
 
     /**
@@ -1872,7 +1892,7 @@
      * The transitionName for the view background will be "android:navigation:background".
      * </p>
      */
-    public abstract void setNavigationBarColor(int color);
+    public abstract void setNavigationBarColor(@ColorInt int color);
 
 
 }
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 35a6a76..979ee95 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -132,6 +132,11 @@
     }
 
     @Override
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+        return mWrapped.onWindowStartingActionMode(callback, type);
+    }
+
+    @Override
     public void onActionModeStarted(ActionMode mode) {
         mWrapped.onActionModeStarted(mode);
     }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 094a8a1..905d6d7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.SystemApi;
 import android.app.Presentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -501,13 +502,6 @@
         public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
 
         /**
-         * Window type: Behind the universe of the real windows.
-         * In multiuser systems shows on all users' windows.
-         * @hide
-         */
-        public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
-
-        /**
          * Window type: Display overlay window.  Used to simulate secondary display devices.
          * In multiuser systems shows on all users' windows.
          * @hide
@@ -1332,6 +1326,16 @@
          * @hide
          */
         public final Rect surfaceInsets = new Rect();
+
+        /**
+         * Whether the surface insets have been manually set. When set to
+         * {@code false}, the view root will automatically determine the
+         * appropriate surface insets.
+         *
+         * @see #surfaceInsets
+         * @hide
+         */
+        public boolean hasManualSurfaceInsets;
     
         /**
          * The desired bitmap format.  May be one of the constants in
@@ -1590,7 +1594,19 @@
         public final CharSequence getTitle() {
             return mTitle;
         }
-    
+
+        /** @hide */
+        @SystemApi
+        public final void setUserActivityTimeout(long timeout) {
+            userActivityTimeout = timeout;
+        }
+
+        /** @hide */
+        @SystemApi
+        public final long getUserActivityTimeout() {
+            return userActivityTimeout;
+        }
+
         public int describeContents() {
             return 0;
         }
@@ -1628,6 +1644,7 @@
             out.writeInt(surfaceInsets.top);
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
+            out.writeInt(hasManualSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
         }
 
@@ -1676,6 +1693,7 @@
             surfaceInsets.top = in.readInt();
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
+            hasManualSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
         }
 
@@ -1858,6 +1876,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (hasManualSurfaceInsets != o.hasManualSurfaceInsets) {
+                hasManualSurfaceInsets = o.hasManualSurfaceInsets;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (needsMenuKey != o.needsMenuKey) {
                 needsMenuKey = o.needsMenuKey;
                 changes |= NEEDS_MENU_KEY_CHANGED;
@@ -1966,8 +1989,11 @@
             if (userActivityTimeout >= 0) {
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
             }
-            if (!surfaceInsets.equals(Insets.NONE)) {
+            if (!surfaceInsets.equals(Insets.NONE) || hasManualSurfaceInsets) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
+                if (hasManualSurfaceInsets) {
+                    sb.append(" (manual)");
+                }
             }
             if (needsMenuKey != NEEDS_MENU_UNSET) {
                 sb.append(" needsMenuKey=");
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index a14c766..1cebe3f 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -190,6 +190,39 @@
         }
     }
 
+    public ArrayList<ViewRootImpl> getRootViews(IBinder token) {
+        ArrayList<ViewRootImpl> views = new ArrayList<>();
+        synchronized (mLock) {
+            final int numRoots = mRoots.size();
+            for (int i = 0; i < numRoots; ++i) {
+                WindowManager.LayoutParams params = mParams.get(i);
+                if (params.token == null) {
+                    continue;
+                }
+                if (params.token != token) {
+                    boolean isChild = false;
+                    if (params.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
+                            && params.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        for (int j = 0 ; j < numRoots; ++j) {
+                            View viewj = mViews.get(j);
+                            WindowManager.LayoutParams paramsj = mParams.get(j);
+                            if (params.token == viewj.getWindowToken()
+                                    && paramsj.token == token) {
+                                isChild = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (!isChild) {
+                        continue;
+                    }
+                }
+                views.add(mRoots.get(i));
+            }
+        }
+        return views;
+    }
+
     public View getRootView(String name) {
         synchronized (mLock) {
             for (int i = mRoots.size() - 1; i >= 0; --i) {
@@ -213,15 +246,15 @@
             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
         }
 
-        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
+        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
         if (parentWindow != null) {
             parentWindow.adjustLayoutParamsForSubWindow(wparams);
-        } else {
+        } else if (ActivityManager.isHighEndGfx()) {
             // If there's no parent and we're running on L or above (or in the
             // system context), assume we want hardware acceleration.
             final Context context = view.getContext();
-            if (context != null
-                    && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
+            if (context != null && context.getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.LOLLIPOP) {
                 wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
             }
         }
@@ -459,7 +492,7 @@
         }
     }
 
-    public void dumpGfxInfo(FileDescriptor fd) {
+    public void dumpGfxInfo(FileDescriptor fd, String[] args) {
         FileOutputStream fout = new FileOutputStream(fd);
         PrintWriter pw = new FastPrintWriter(fout);
         try {
@@ -476,7 +509,7 @@
                     HardwareRenderer renderer =
                             root.getView().mAttachInfo.mHardwareRenderer;
                     if (renderer != null) {
-                        renderer.dumpGfxInfo(pw, fd);
+                        renderer.dumpGfxInfo(pw, fd, args);
                     }
                 }
 
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index f557b97..7b4640b 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -20,7 +20,7 @@
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.IBinder;
-import android.os.IRemoteCallback;
+import android.view.animation.Animation;
 
 import java.util.List;
 
@@ -85,6 +85,41 @@
     }
 
     /**
+     * Abstract class to be notified about {@link com.android.server.wm.AppTransition} events. Held
+     * as an abstract class so a listener only needs to implement the methods of its interest.
+     */
+    public static abstract class AppTransitionListener {
+
+        /**
+         * Called when an app transition is being setup and about to be executed.
+         */
+        public void onAppTransitionPendingLocked() {}
+
+        /**
+         * Called when a pending app transition gets cancelled.
+         */
+        public void onAppTransitionCancelledLocked() {}
+
+        /**
+         * Called when an app transition gets started
+         *
+         * @param openToken the token for the opening app
+         * @param closeToken the token for the closing app
+         * @param openAnimation the animation for the opening app
+         * @param closeAnimation the animation for the closing app
+         */
+        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
+                Animation openAnimation, Animation closeAnimation) {}
+
+        /**
+         * Called when an app transition is finished running.
+         *
+         * @param token the token for app whose transition has finished
+         */
+        public void onAppTransitionFinishedLocked(IBinder token) {}
+    }
+
+    /**
      * Request that the window manager call
      * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
      * within a surface transaction at a later time.
@@ -189,4 +224,11 @@
      * @param removeWindows Whether to also remove the windows associated with the token.
      */
     public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows);
+
+    /**
+     * Registers a listener to be notified about app transition events.
+     *
+     * @param listener The listener to register.
+     */
+    public abstract void registerAppTransitionListener(AppTransitionListener listener);
 }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 94f3e7aa..9199af1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.CompatibilityInfo;
@@ -105,6 +106,13 @@
     public final static String EXTRA_HDMI_PLUGGED_STATE = "state";
 
     /**
+     * Set to {@code true} when intent was invoked from pressing the home key.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY";
+
+    /**
      * Pass this event to the user / app.  To be returned from
      * {@link #interceptKeyBeforeQueueing}.
      */
@@ -357,6 +365,11 @@
          * @return true if window is on default display.
          */
         public boolean isDefaultDisplay();
+
+        /**
+         * Check whether the window is currently dimming.
+         */
+        public boolean isDimming();
     }
 
     /**
@@ -579,13 +592,6 @@
     public int getMaxWallpaperLayer();
 
     /**
-     * Return the window layer at which windows appear above the normal
-     * universe (that is no longer impacted by the universe background
-     * transform).
-     */
-    public int getAboveUniverseLayer();
-
-    /**
      * Return the display width available after excluding any screen
      * decorations that can never be removed.  That is, system bar or
      * button bar.
@@ -901,13 +907,12 @@
 
     /**
      * Called following layout of all window to apply policy to each window.
-     *
+     * 
      * @param win The window being positioned.
-     * @param attrs The LayoutParams of the window.
-     * @param attached For sub-windows, the window it is attached to. Otherwise null.
+     * @param attrs The LayoutParams of the window. 
      */
     public void applyPostLayoutPolicyLw(WindowState win,
-            WindowManager.LayoutParams attrs, WindowState attached);
+            WindowManager.LayoutParams attrs);
 
     /**
      * Called following layout of all windows and after policy has been applied
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index cefd34d..db78ec5 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -17,7 +17,6 @@
 package android.view.accessibility;
 
 import android.accessibilityservice.IAccessibilityServiceConnection;
-import android.graphics.Point;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index b5afdf7..6096d7d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -721,7 +721,7 @@
      * @return Whether the refresh succeeded.
      */
     public boolean refresh() {
-        return refresh(false);
+        return refresh(true);
     }
 
     /**
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 85d77cb..a5524d8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -16,6 +16,7 @@
 
 package android.view.animation;
 
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
@@ -622,7 +623,7 @@
      * @param bg The background color.  If 0, no background.  Currently must
      * be black, with any desired alpha level.
      */
-    public void setBackgroundColor(int bg) {
+    public void setBackgroundColor(@ColorInt int bg) {
         mBackgroundColor = bg;
     }
 
@@ -753,6 +754,7 @@
     /**
      * Returns the background color behind the animation.
      */
+    @ColorInt
     public int getBackgroundColor() {
         return mBackgroundColor;
     }
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 606c83e..4d1209a 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -19,6 +19,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.AnimRes;
+import android.annotation.InterpolatorRes;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -65,7 +67,7 @@
      * @return The animation object reference by the specified id
      * @throws NotFoundException when the animation cannot be loaded
      */
-    public static Animation loadAnimation(Context context, int id)
+    public static Animation loadAnimation(Context context, @AnimRes int id)
             throws NotFoundException {
 
         XmlResourceParser parser = null;
@@ -143,7 +145,7 @@
      * @return The animation object reference by the specified id
      * @throws NotFoundException when the layout animation controller cannot be loaded
      */
-    public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
+    public static LayoutAnimationController loadLayoutAnimation(Context context, @AnimRes int id)
             throws NotFoundException {
 
         XmlResourceParser parser = null;
@@ -266,7 +268,8 @@
      * @return The animation object reference by the specified id
      * @throws NotFoundException
      */
-    public static Interpolator loadInterpolator(Context context, int id) throws NotFoundException {
+    public static Interpolator loadInterpolator(Context context, @InterpolatorRes int id)
+            throws NotFoundException {
         XmlResourceParser parser = null;
         try {
             parser = context.getResources().getAnimation(id);
diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java
index 2361501..e194927 100644
--- a/core/java/android/view/animation/ClipRectAnimation.java
+++ b/core/java/android/view/animation/ClipRectAnimation.java
@@ -26,8 +26,8 @@
  * @hide
  */
 public class ClipRectAnimation extends Animation {
-    private Rect mFromRect = new Rect();
-    private Rect mToRect = new Rect();
+    protected Rect mFromRect = new Rect();
+    protected Rect mToRect = new Rect();
 
     /**
      * Constructor to use when building a ClipRectAnimation from code
@@ -43,6 +43,15 @@
         mToRect.set(toClip);
     }
 
+    /**
+     * Constructor to use when building a ClipRectAnimation from code
+     */
+    public ClipRectAnimation(int fromL, int fromT, int fromR, int fromB,
+            int toL, int toT, int toR, int toB) {
+        mFromRect.set(fromL, fromT, fromR, fromB);
+        mToRect.set(toL, toT, toR, toB);
+    }
+
     @Override
     protected void applyTransformation(float it, Transformation tr) {
         int l = mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it);
diff --git a/core/java/android/view/animation/ClipRectLRAnimation.java b/core/java/android/view/animation/ClipRectLRAnimation.java
new file mode 100644
index 0000000..8993cd3
--- /dev/null
+++ b/core/java/android/view/animation/ClipRectLRAnimation.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+import android.graphics.Rect;
+
+/**
+ * Special case of ClipRectAnimation that animates only the left/right
+ * dimensions of the clip, picking up the other dimensions from whatever is
+ * set on the transform already.
+ *
+ * @hide
+ */
+public class ClipRectLRAnimation extends ClipRectAnimation {
+
+    /**
+     * Constructor. Passes in 0 for Top/Bottom parameters of ClipRectAnimation
+     */
+    public ClipRectLRAnimation(int fromL, int fromR, int toL, int toR) {
+        super(fromL, 0, fromR, 0, toL, 0, toR, 0);
+    }
+
+    /**
+     * Calculates and sets clip rect on given transformation. It uses existing values
+     * on the Transformation for Top/Bottom clip parameters.
+     */
+    @Override
+    protected void applyTransformation(float it, Transformation tr) {
+        Rect oldClipRect = tr.getClipRect();
+        tr.setClipRect(mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it),
+                oldClipRect.top,
+                mFromRect.right + (int) ((mToRect.right - mFromRect.right) * it),
+                oldClipRect.bottom);
+    }
+}
diff --git a/core/java/android/view/animation/ClipRectTBAnimation.java b/core/java/android/view/animation/ClipRectTBAnimation.java
new file mode 100644
index 0000000..06f86ce
--- /dev/null
+++ b/core/java/android/view/animation/ClipRectTBAnimation.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+import android.graphics.Rect;
+
+/**
+ * Special case of ClipRectAnimation that animates only the top/bottom
+ * dimensions of the clip, picking up the other dimensions from whatever is
+ * set on the transform already.
+ *
+ * @hide
+ */
+public class ClipRectTBAnimation extends ClipRectAnimation {
+
+    /**
+     * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation
+     */
+    public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB) {
+        super(0, fromT, 0, fromB, 0, toT, 0, toB);
+    }
+
+    /**
+     * Calculates and sets clip rect on given transformation. It uses existing values
+     * on the Transformation for Left/Right clip parameters.
+     */
+    @Override
+    protected void applyTransformation(float it, Transformation tr) {
+        Rect oldClipRect = tr.getClipRect();
+        tr.setClipRect(oldClipRect.left, mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it),
+                oldClipRect.right,
+                mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it));
+    }
+
+}
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index 2f4fe73..8eb5b5c 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -16,6 +16,7 @@
 
 package android.view.animation;
 
+import android.annotation.FloatRange;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 
@@ -122,7 +123,13 @@
         mAlpha *= t.getAlpha();
         mMatrix.preConcat(t.getMatrix());
         if (t.mHasClipRect) {
-            setClipRect(t.getClipRect());
+            Rect bounds = t.getClipRect();
+            if (mHasClipRect) {
+                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
+                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
+            } else {
+                setClipRect(bounds);
+            }
         }
     }
     
@@ -135,7 +142,13 @@
         mAlpha *= t.getAlpha();
         mMatrix.postConcat(t.getMatrix());
         if (t.mHasClipRect) {
-            setClipRect(t.getClipRect());
+            Rect bounds = t.getClipRect();
+            if (mHasClipRect) {
+                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
+                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
+            } else {
+                setClipRect(bounds);
+            }
         }
     }
 
@@ -151,7 +164,7 @@
      * Sets the degree of transparency
      * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         mAlpha = alpha;
     }
 
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index d2ff754..216022b 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -24,7 +24,7 @@
  * An animation that controls the position of an object. See the
  * {@link android.view.animation full package} description for details and
  * sample code.
- * 
+ *
  */
 public class TranslateAnimation extends Animation {
     private int mFromXType = ABSOLUTE;
@@ -33,20 +33,28 @@
     private int mFromYType = ABSOLUTE;
     private int mToYType = ABSOLUTE;
 
-    private float mFromXValue = 0.0f;
-    private float mToXValue = 0.0f;
+    /** @hide */
+    protected float mFromXValue = 0.0f;
+    /** @hide */
+    protected float mToXValue = 0.0f;
 
-    private float mFromYValue = 0.0f;
-    private float mToYValue = 0.0f;
+    /** @hide */
+    protected float mFromYValue = 0.0f;
+    /** @hide */
+    protected float mToYValue = 0.0f;
 
-    private float mFromXDelta;
-    private float mToXDelta;
-    private float mFromYDelta;
-    private float mToYDelta;
+    /** @hide */
+    protected float mFromXDelta;
+    /** @hide */
+    protected float mToXDelta;
+    /** @hide */
+    protected float mFromYDelta;
+    /** @hide */
+    protected float mToYDelta;
 
     /**
      * Constructor used when a TranslateAnimation is loaded from a resource.
-     * 
+     *
      * @param context Application context to use
      * @param attrs Attribute set from which to read values
      */
@@ -81,7 +89,7 @@
 
     /**
      * Constructor to use when building a TranslateAnimation from code
-     * 
+     *
      * @param fromXDelta Change in X coordinate to apply at the start of the
      *        animation
      * @param toXDelta Change in X coordinate to apply at the end of the
diff --git a/core/java/android/view/animation/TranslateXAnimation.java b/core/java/android/view/animation/TranslateXAnimation.java
new file mode 100644
index 0000000..d75323f
--- /dev/null
+++ b/core/java/android/view/animation/TranslateXAnimation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+import android.graphics.Matrix;
+
+/**
+ * Special case of TranslateAnimation that translates only horizontally, picking up the
+ * vertical values from whatever is set on the Transformation already. When used in
+ * conjunction with a TranslateYAnimation, allows independent animation of x and y
+ * position.
+ * @hide
+ */
+public class TranslateXAnimation extends TranslateAnimation {
+    float[] mTmpValues = new float[9];
+
+    /**
+     * Constructor. Passes in 0 for the y parameters of TranslateAnimation
+     */
+    public TranslateXAnimation(float fromXDelta, float toXDelta) {
+        super(fromXDelta, toXDelta, 0, 0);
+    }
+
+    /**
+     * Constructor. Passes in 0 for the y parameters of TranslateAnimation
+     */
+    public TranslateXAnimation(int fromXType, float fromXValue, int toXType, float toXValue) {
+        super(fromXType, fromXValue, toXType, toXValue, ABSOLUTE, 0, ABSOLUTE, 0);
+    }
+
+    /**
+     * Calculates and sets x translation values on given transformation.
+     */
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        Matrix m = t.getMatrix();
+        m.getValues(mTmpValues);
+        float dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
+        t.getMatrix().setTranslate(dx, mTmpValues[Matrix.MTRANS_Y]);
+    }
+}
diff --git a/core/java/android/view/animation/TranslateYAnimation.java b/core/java/android/view/animation/TranslateYAnimation.java
new file mode 100644
index 0000000..714558d
--- /dev/null
+++ b/core/java/android/view/animation/TranslateYAnimation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.animation;
+
+import android.graphics.Matrix;
+
+/**
+ * Special case of TranslateAnimation that translates only vertically, picking up the
+ * horizontal values from whatever is set on the Transformation already. When used in
+ * conjunction with a TranslateXAnimation, allows independent animation of x and y
+ * position.
+ * @hide
+ */
+public class TranslateYAnimation extends TranslateAnimation {
+    float[] mTmpValues = new float[9];
+
+    /**
+     * Constructor. Passes in 0 for the x parameters of TranslateAnimation
+     */
+    public TranslateYAnimation(float fromYDelta, float toYDelta) {
+        super(0, 0, fromYDelta, toYDelta);
+    }
+
+    /**
+     * Constructor. Passes in 0 for the x parameters of TranslateAnimation
+     */
+    public TranslateYAnimation(int fromYType, float fromYValue, int toYType, float toYValue) {
+        super(ABSOLUTE, 0, ABSOLUTE, 0, fromYType, fromYValue, toYType, toYValue);
+    }
+
+    /**
+     * Calculates and sets y translation values on given transformation.
+     */
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        Matrix m = t.getMatrix();
+        m.getValues(mTmpValues);
+        float dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
+        t.getMatrix().setTranslate(mTmpValues[Matrix.MTRANS_X], dy);
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b56378f..0996810 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -27,7 +27,6 @@
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -494,19 +493,17 @@
                                 mIInputContext.finishComposingText();
                             } catch (RemoteException e) {
                             }
-                            // Check focus again in case that "onWindowFocus" is called before
-                            // handling this message.
-                            if (mServedView != null && mServedView.hasWindowFocus()) {
-                                // "finishComposingText" has been already called above. So we
-                                // should not call mServedInputConnection.finishComposingText here.
-                                // Also, please note that this handler thread could be different
-                                // from a thread that created mServedView. That could happen
-                                // the current activity is running in the system process.
-                                // In that case, we really should not call
-                                // mServedInputConnection.finishComposingText.
-                                if (checkFocusNoStartInput(mHasBeenInactive, false)) {
-                                    startInputInner(null, 0, 0, 0);
-                                }
+                        }
+                        // Check focus again in case that "onWindowFocus" is called before
+                        // handling this message.
+                        if (mServedView != null && mServedView.hasWindowFocus()) {
+                            // Please note that this handler thread could be different
+                            // from a thread that created mServedView. That could happen
+                            // the current activity is running in the system process.
+                            // In that case, we really should not call
+                            // mServedInputConnection.finishComposingText.
+                            if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+                                startInputInner(null, 0, 0, 0);
                             }
                         }
                     }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 1671faa..c2f3777 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.inputmethod.InputMethodUtils;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -379,7 +381,7 @@
      */
     public CharSequence getDisplayName(
             Context context, String packageName, ApplicationInfo appInfo) {
-        final Locale locale = constructLocaleFromString(mSubtypeLocale);
+        final Locale locale = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
         final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
         if (mSubtypeNameResId == 0) {
             return localeStr;
@@ -503,22 +505,6 @@
         }
     };
 
-    private static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr))
-            return null;
-        String[] localeParams = localeStr.split("_", 3);
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
     private static int hashCodeInternal(String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
             boolean isAsciiCapable) {
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index 5bef71f..6a748ce 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -17,15 +17,10 @@
 package android.view.inputmethod;
 
 import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AndroidRuntimeException;
 import android.util.Slog;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.List;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
@@ -203,43 +198,20 @@
     }
 
     private static byte[] compress(final byte[] data) {
-        ByteArrayOutputStream resultStream = null;
-        GZIPOutputStream zipper = null;
-        try {
-            resultStream = new ByteArrayOutputStream();
-            zipper = new GZIPOutputStream(resultStream);
+        try (final ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
+                final GZIPOutputStream zipper = new GZIPOutputStream(resultStream)) {
             zipper.write(data);
-        } catch(IOException e) {
+            zipper.finish();
+            return resultStream.toByteArray();
+        } catch(Exception e) {
+            Slog.e(TAG, "Failed to compress the data.", e);
             return null;
-        } finally {
-            try {
-                if (zipper != null) {
-                    zipper.close();
-                }
-            } catch (IOException e) {
-                zipper = null;
-                Slog.e(TAG, "Failed to close the stream.", e);
-                // swallowed, not propagated back to the caller
-            }
-            try {
-                if (resultStream != null) {
-                    resultStream.close();
-                }
-            } catch (IOException e) {
-                resultStream = null;
-                Slog.e(TAG, "Failed to close the stream.", e);
-                // swallowed, not propagated back to the caller
-            }
         }
-        return resultStream != null ? resultStream.toByteArray() : null;
     }
 
     private static byte[] decompress(final byte[] data, final int expectedSize) {
-        ByteArrayInputStream inputStream = null;
-        GZIPInputStream unzipper = null;
-        try {
-            inputStream = new ByteArrayInputStream(data);
-            unzipper = new GZIPInputStream(inputStream);
+        try (final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+                final GZIPInputStream unzipper = new GZIPInputStream(inputStream)) {
             final byte [] result = new byte[expectedSize];
             int totalReadBytes = 0;
             while (totalReadBytes < result.length) {
@@ -254,25 +226,9 @@
                 return null;
             }
             return result;
-        } catch(IOException e) {
+        } catch(Exception e) {
+            Slog.e(TAG, "Failed to decompress the data.", e);
             return null;
-        } finally {
-            try {
-                if (unzipper != null) {
-                    unzipper.close();
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to close the stream.", e);
-                // swallowed, not propagated back to the caller
-            }
-            try {
-                if (inputStream != null) {
-                  inputStream.close();
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to close the stream.", e);
-                // swallowed, not propagated back to the caller
-            }
         }
     }
 }
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index eca96f9..6d5fac1 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -31,10 +31,7 @@
     }
 
     /**
-     * Gets the singleton CookieManager instance. If this method is used
-     * before the application instantiates a {@link WebView} instance,
-     * {@link CookieSyncManager#createInstance CookieSyncManager.createInstance(Context)}
-     * must be called first.
+     * Gets the singleton CookieManager instance.
      *
      * @return the singleton CookieManager instance
      */
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index d9546ca..eda8d36 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -17,7 +17,6 @@
 package android.webkit;
 
 import android.content.Context;
-import android.util.Log;
 
 
 /**
diff --git a/core/java/android/webkit/LegacyErrorStrings.java b/core/java/android/webkit/LegacyErrorStrings.java
new file mode 100644
index 0000000..60a6ee1
--- /dev/null
+++ b/core/java/android/webkit/LegacyErrorStrings.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Localized strings for the error codes defined in EventHandler.
+ *
+ * {@hide}
+ */
+class LegacyErrorStrings {
+    private LegacyErrorStrings() { /* Utility class, don't instantiate. */ }
+
+    private static final String LOGTAG = "Http";
+
+    /**
+     * Get the localized error message resource for the given error code.
+     * If the code is unknown, we'll return a generic error message.
+     */
+    static String getString(int errorCode, Context context) {
+        return context.getText(getResource(errorCode)).toString();
+    }
+
+    /**
+     * Get the localized error message resource for the given error code.
+     * If the code is unknown, we'll return a generic error message.
+     */
+    private static int getResource(int errorCode) {
+        switch(errorCode) {
+            case 0: /* EventHandler.OK: */
+                return com.android.internal.R.string.httpErrorOk;
+
+            case -1: /* EventHandler.ERROR: */
+                return com.android.internal.R.string.httpError;
+
+            case -2: /* EventHandler.ERROR_LOOKUP: */
+                return com.android.internal.R.string.httpErrorLookup;
+
+            case -3: /* EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME: */
+                return com.android.internal.R.string.httpErrorUnsupportedAuthScheme;
+
+            case -4: /* EventHandler.ERROR_AUTH: */
+                return com.android.internal.R.string.httpErrorAuth;
+
+            case -5: /* EventHandler.ERROR_PROXYAUTH: */
+                return com.android.internal.R.string.httpErrorProxyAuth;
+
+            case -6: /* EventHandler.ERROR_CONNECT: */
+                return com.android.internal.R.string.httpErrorConnect;
+
+            case -7: /* EventHandler.ERROR_IO: */
+                return com.android.internal.R.string.httpErrorIO;
+
+            case -8: /* EventHandler.ERROR_TIMEOUT: */
+                return com.android.internal.R.string.httpErrorTimeout;
+
+            case -9: /* EventHandler.ERROR_REDIRECT_LOOP: */
+                return com.android.internal.R.string.httpErrorRedirectLoop;
+
+            case -10: /* EventHandler.ERROR_UNSUPPORTED_SCHEME: */
+                return com.android.internal.R.string.httpErrorUnsupportedScheme;
+
+            case -11: /* EventHandler.ERROR_FAILED_SSL_HANDSHAKE: */
+                return com.android.internal.R.string.httpErrorFailedSslHandshake;
+
+            case -12: /* EventHandler.ERROR_BAD_URL: */
+                return com.android.internal.R.string.httpErrorBadUrl;
+
+            case -13: /* EventHandler.FILE_ERROR: */
+                return com.android.internal.R.string.httpErrorFile;
+
+            case -14: /* EventHandler.FILE_NOT_FOUND_ERROR: */
+                return com.android.internal.R.string.httpErrorFileNotFound;
+
+            case -15: /* EventHandler.TOO_MANY_REQUESTS_ERROR: */
+                return com.android.internal.R.string.httpErrorTooManyRequests;
+
+            default:
+                Log.w(LOGTAG, "Using generic message for unknown error code: " + errorCode);
+                return com.android.internal.R.string.httpError;
+        }
+    }
+}
diff --git a/core/java/android/webkit/WebBackForwardList.java b/core/java/android/webkit/WebBackForwardList.java
index e671376..6f763dc 100644
--- a/core/java/android/webkit/WebBackForwardList.java
+++ b/core/java/android/webkit/WebBackForwardList.java
@@ -16,7 +16,6 @@
 
 package android.webkit;
 
-import android.annotation.SystemApi;
 import java.io.Serializable;
 
 /**
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 768dc9f..4737e9b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -70,13 +70,14 @@
     }
 
     /**
-     * Notify the host application that the current page would
-     * like to show a custom View.  This is used for Fullscreen
-     * video playback; see "HTML5 Video support" documentation on
+     * Notify the host application that the current page has entered full
+     * screen mode. The host application must show the custom View which
+     * contains the web contents &mdash; video or other HTML content &mdash;
+     * in full screen mode. Also see "Full screen support" documentation on
      * {@link WebView}.
      * @param view is the View object to be shown.
-     * @param callback is the callback to be invoked if and when the view
-     * is dismissed.
+     * @param callback invoke this callback to request the page to exit
+     * full screen mode.
      */
     public void onShowCustomView(View view, CustomViewCallback callback) {};
 
@@ -96,8 +97,10 @@
             CustomViewCallback callback) {};
 
     /**
-     * Notify the host application that the current page would
-     * like to hide its custom view.
+     * Notify the host application that the current page has exited full
+     * screen mode. The host application must hide the custom View, ie. the
+     * View passed to {@link #onShowCustomView} when the content entered fullscreen.
+     * Also see "Full screen support" documentation on {@link WebView}.
      */
     public void onHideCustomView() {}
 
@@ -377,10 +380,9 @@
     }
 
     /**
-     * When the user starts to playback a video element, it may take time for enough
-     * data to be buffered before the first frames can be rendered. While this buffering
-     * is taking place, the ChromeClient can use this function to provide a View to be
-     * displayed. For example, the ChromeClient could show a spinner animation.
+     * Obtains a View to be displayed while buffering of full screen video is taking
+     * place. The host application can override this method to provide a View
+     * containing a spinner or similar.
      *
      * @return View The View to be displayed whilst the video is loading.
      */
diff --git a/core/java/android/webkit/WebMessage.java b/core/java/android/webkit/WebMessage.java
new file mode 100644
index 0000000..7683a40
--- /dev/null
+++ b/core/java/android/webkit/WebMessage.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * The Java representation of the HTML5 PostMessage event. See
+ * https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces
+ * for definition of a MessageEvent in HTML5.
+ *
+ */
+public class WebMessage {
+
+    private String mData;
+    private WebMessagePort[] mPorts;
+
+    /**
+     * Creates a WebMessage.
+     * @param data  the data of the message.
+     */
+    public WebMessage(String data) {
+        mData = data;
+    }
+
+    /**
+     * Creates a WebMessage.
+     * @param data  the data of the message.
+     * @param ports  the ports that are sent with the message.
+     */
+    public WebMessage(String data, WebMessagePort[] ports) {
+        mData = data;
+        mPorts = ports;
+    }
+
+    /**
+     * Returns the data of the message.
+     */
+    public String getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the ports that are sent with the message, or null if no port
+     * is sent.
+     */
+    public WebMessagePort[] getPorts() {
+        return mPorts;
+    }
+}
diff --git a/core/java/android/webkit/WebMessagePort.java b/core/java/android/webkit/WebMessagePort.java
new file mode 100644
index 0000000..eab27bd
--- /dev/null
+++ b/core/java/android/webkit/WebMessagePort.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.os.Handler;
+
+/**
+ * The Java representation of the HTML5 Message Port. See
+ * https://html.spec.whatwg.org/multipage/comms.html#messageport
+ * for definition of MessagePort in HTML5.
+ *
+ * A Message port represents one endpoint of a Message Channel. In Android
+ * webview, there is no separate Message Channel object. When a message channel
+ * is created, both ports are tangled to each other and started, and then
+ * returned in a MessagePort array, see {@link WebView#createWebMessageChannel}
+ * for creating a message channel.
+ *
+ * When a message port is first created or received via transfer, it does not
+ * have a WebMessageCallback to receive web messages. The messages are queued until
+ * a WebMessageCallback is set.
+ */
+public abstract class WebMessagePort {
+
+    /**
+     * The listener for handling MessagePort events. The message callback
+     * methods are called on the main thread. If the embedder application
+     * wants to receive the messages on a different thread, it can do this
+     * by passing a Handler in
+     *  {@link WebMessagePort#setWebMessageCallback(WebMessageCallback, Handler)}.
+     * In the latter case, the application should be extra careful for thread safety
+     * since WebMessagePort methods should be called on main thread.
+     */
+    public static abstract class WebMessageCallback {
+        /**
+         * Message callback for receiving onMessage events.
+         *
+         * @param port  the WebMessagePort that the message is destined for
+         * @param message  the message from the entangled port.
+         */
+        public void onMessage(WebMessagePort port, WebMessage message) { }
+    }
+
+    /**
+     * Post a WebMessage to the entangled port.
+     *
+     * @param message  the message from Java to JS.
+     *
+     * @throws IllegalStateException If message port is already transferred or closed.
+     */
+    public abstract void postMessage(WebMessage message);
+
+    /**
+     * Close the message port and free any resources associated with it.
+     */
+    public abstract void close();
+
+    /**
+     * Sets a callback to receive message events on the main thread.
+     *
+     * @param callback  the message callback.
+     */
+    public abstract void setWebMessageCallback(WebMessageCallback callback);
+
+    /**
+     * Sets a callback to receive message events on the handler that is provided
+     * by the application.
+     *
+     * @param callback  the message callback.
+     * @param handler   the handler to receive the message messages.
+     */
+    public abstract void setWebMessageCallback(WebMessageCallback callback, Handler handler);
+}
diff --git a/core/java/android/webkit/WebResourceError.java b/core/java/android/webkit/WebResourceError.java
new file mode 100644
index 0000000..080d174
--- /dev/null
+++ b/core/java/android/webkit/WebResourceError.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * Encapsulates information about errors occured during loading of web resources. See
+ * {@link WebViewClient#onReceivedError(WebView, WebResourceRequest, WebResourceError) WebViewClient.onReceivedError(WebView, WebResourceRequest, WebResourceError)}
+ */
+public abstract class WebResourceError {
+    /**
+     * Gets the error code of the error. The code corresponds to one
+     * of the ERROR_* constants in {@link WebViewClient}.
+     *
+     * @return The error code of the error
+     */
+    public abstract int getErrorCode();
+
+    /**
+     * Gets the string describing the error. Descriptions are localized,
+     * and thus can be used for communicating the problem to the user.
+     *
+     * @return The description of the error
+     */
+    public abstract String getDescription();
+}
diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java
index 2185658de3..0760d2b 100644
--- a/core/java/android/webkit/WebResourceRequest.java
+++ b/core/java/android/webkit/WebResourceRequest.java
@@ -18,7 +18,6 @@
 
 import android.net.Uri;
 
-import java.io.InputStream;
 import java.util.Map;
 
 /**
@@ -42,6 +41,8 @@
 
     /**
      * Gets whether a gesture (such as a click) was associated with the request.
+     * For security reasons in certain situations this method may return false even though the
+     * sequence of events which caused the request to be created was initiated by a user gesture.
      *
      * @return whether a gesture was associated with the request.
      */
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index ad6e9aa..a42aaa7 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import java.io.InputStream;
+import java.io.StringBufferInputStream;
 import java.util.Map;
 
 /**
@@ -24,7 +25,7 @@
  * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
  * response when the WebView requests a particular resource.
  */
-public class WebResourceResponse {
+public class WebResourceResponse extends WebResourceResponseBase {
     private String mMimeType;
     private String mEncoding;
     private int mStatusCode;
@@ -40,13 +41,14 @@
      *
      * @param mimeType the resource response's MIME type, for example text/html
      * @param encoding the resource response's encoding
-     * @param data the input stream that provides the resource response's data
+     * @param data the input stream that provides the resource response's data. Must not be a
+     *             StringBufferInputStream.
      */
     public WebResourceResponse(String mimeType, String encoding,
             InputStream data) {
         mMimeType = mimeType;
         mEncoding = encoding;
-        mInputStream = data;
+        setData(data);
     }
 
     /**
@@ -62,7 +64,8 @@
      *                     and not empty.
      * @param responseHeaders the resource response's headers represented as a mapping of header
      *                        name -> header value.
-     * @param data the input stream that provides the resource response's data
+     * @param data the input stream that provides the resource response's data. Must not be a
+     *             StringBufferInputStream.
      */
     public WebResourceResponse(String mimeType, String encoding, int statusCode,
             String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
@@ -72,38 +75,36 @@
     }
 
     /**
-     * Sets the resource response's MIME type, for example text/html.
+     * Sets the resource response's MIME type, for example &quot;text/html&quot;.
      *
-     * @param mimeType the resource response's MIME type
+     * @param mimeType The resource response's MIME type
      */
     public void setMimeType(String mimeType) {
         mMimeType = mimeType;
     }
 
     /**
-     * Gets the resource response's MIME type.
-     *
-     * @return the resource response's MIME type
+     * {@inheritDoc}
      */
+    @Override
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Sets the resource response's encoding, for example UTF-8. This is used
+     * Sets the resource response's encoding, for example &quot;UTF-8&quot;. This is used
      * to decode the data from the input stream.
      *
-     * @param encoding the resource response's encoding
+     * @param encoding The resource response's encoding
      */
     public void setEncoding(String encoding) {
         mEncoding = encoding;
     }
 
     /**
-     * Gets the resource response's encoding.
-     *
-     * @return the resource response's encoding
+     * {@inheritDoc}
      */
+    @Override
     public String getEncoding() {
         return mEncoding;
     }
@@ -139,19 +140,17 @@
     }
 
     /**
-     * Gets the resource response's status code.
-     *
-     * @return the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public int getStatusCode() {
         return mStatusCode;
     }
 
     /**
-     * Gets the description of the resource response's status code.
-     *
-     * @return the description of the resource response's status code.
+     * {@inheritDoc}
      */
+    @Override
     public String getReasonPhrase() {
         return mReasonPhrase;
     }
@@ -159,17 +158,16 @@
     /**
      * Sets the headers for the resource response.
      *
-     * @param headers mapping of header name -> header value.
+     * @param headers Mapping of header name -> header value.
      */
     public void setResponseHeaders(Map<String, String> headers) {
         mResponseHeaders = headers;
     }
 
     /**
-     * Gets the headers for the resource response.
-     *
-     * @return the headers for the resource response.
+     * {@inheritDoc}
      */
+    @Override
     public Map<String, String> getResponseHeaders() {
         return mResponseHeaders;
     }
@@ -178,17 +176,22 @@
      * Sets the input stream that provides the resource response's data. Callers
      * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
      *
-     * @param data the input stream that provides the resource response's data
+     * @param data the input stream that provides the resource response's data. Must not be a
+     *             StringBufferInputStream.
      */
     public void setData(InputStream data) {
+        // If data is (or is a subclass of) StringBufferInputStream
+        if (data != null && StringBufferInputStream.class.isAssignableFrom(data.getClass())) {
+            throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
+                "not be passed to a WebResourceResponse");
+        }
         mInputStream = data;
     }
 
     /**
-     * Gets the input stream that provides the resource response's data.
-     *
-     * @return the input stream that provides the resource response's data
+     * {@inheritDoc}
      */
+    @Override
     public InputStream getData() {
         return mInputStream;
     }
diff --git a/core/java/android/webkit/WebResourceResponseBase.java b/core/java/android/webkit/WebResourceResponseBase.java
new file mode 100644
index 0000000..cffde82
--- /dev/null
+++ b/core/java/android/webkit/WebResourceResponseBase.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Encapsulates a resource response received from the server.
+ * This is an abstract class used by WebView callbacks.
+ */
+public abstract class WebResourceResponseBase {
+    /**
+     * Gets the resource response's MIME type.
+     *
+     * @return The resource response's MIME type
+     */
+    public abstract String getMimeType();
+
+    /**
+     * Gets the resource response's encoding.
+     *
+     * @return The resource response's encoding
+     */
+    public abstract String getEncoding();
+
+    /**
+     * Gets the resource response's status code.
+     *
+     * @return The resource response's status code.
+     */
+    public abstract int getStatusCode();
+
+    /**
+     * Gets the description of the resource response's status code.
+     *
+     * @return The description of the resource response's status code.
+     */
+    public abstract String getReasonPhrase();
+
+    /**
+     * Gets the headers for the resource response.
+     *
+     * @return The headers for the resource response.
+     */
+    public abstract Map<String, String> getResponseHeaders();
+
+    /**
+     * Gets the input stream that provides the resource response's data.
+     *
+     * @return The input stream that provides the resource response's data
+     */
+    public abstract InputStream getData();
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 1d2c311..943beb0 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1285,7 +1285,7 @@
      * strongly discouraged.
      *
      * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract void setMixedContentMode(int mode);
 
@@ -1293,7 +1293,7 @@
      * Gets the current behavior of the WebView with regard to loading insecure content from a
      * secure origin.
      * @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW},
-     *     {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+     *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
      */
     public abstract int getMixedContentMode();
 
@@ -1330,4 +1330,25 @@
      */
     @SystemApi
     public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
+
+    /**
+     * Sets whether this WebView should raster tiles when it is
+     * offscreen but attached to a window. Turning this on can avoid
+     * rendering artifacts when animating an offscreen WebView on-screen.
+     * Offscreen WebViews in this mode use more memory. The default value is
+     * false.
+     * Please follow these guidelines to limit memory usage:
+     * - WebView size should be not be larger than the device screen size.
+     * - Limit use of this mode to a small number of WebViews. Use it for
+     *   visible WebViews and WebViews about to be animated to visible.
+     */
+    public abstract void setOffscreenPreRaster(boolean enabled);
+
+    /**
+     * Gets whether this WebView should raster tiles when it is
+     * offscreen but attached to a window.
+     * @return true if this WebView will raster tiles when it is
+     * offscreen but attached to a window.
+     */
+    public abstract boolean getOffscreenPreRaster();
 }
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index 402394f..801be12 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -17,11 +17,6 @@
 package android.webkit;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.util.Log;
 
 /*
  * @deprecated The WebSyncManager no longer does anything.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 48712bb..67ad642 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -27,6 +27,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.http.SslCertificate;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Looper;
@@ -233,12 +234,48 @@
  *
  * <h3>HTML5 Video support</h3>
  *
- * <p>In order to support inline HTML5 video in your application, you need to have hardware
- * acceleration turned on, and set a {@link android.webkit.WebChromeClient}. For full screen support,
- * implementations of {@link WebChromeClient#onShowCustomView(View, WebChromeClient.CustomViewCallback)}
- * and {@link WebChromeClient#onHideCustomView()} are required,
- * {@link WebChromeClient#getVideoLoadingProgressView()} is optional.
+ * <p>In order to support inline HTML5 video in your application you need to have hardware
+ * acceleration turned on.
  * </p>
+ *
+ * <h3>Full screen support</h3>
+ *
+ * <p>In order to support full screen &mdash; for video or other HTML content &mdash; you need to set a
+ * {@link android.webkit.WebChromeClient} and implement both
+ * {@link WebChromeClient#onShowCustomView(View, WebChromeClient.CustomViewCallback)}
+ * and {@link WebChromeClient#onHideCustomView()}. If the implementation of either of these two methods is
+ * missing then the web contents will not be allowed to enter full screen. Optionally you can implement
+ * {@link WebChromeClient#getVideoLoadingProgressView()} to customize the View displayed whilst a video
+ * is loading.
+ * </p>
+ *
+ * <h3>Layout size</h3>
+ * <p>
+ * It is recommended to set the WebView layout height to a fixed value or to
+ * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} instead of using
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}.
+ * When using {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}
+ * for the height none of the WebView's parents should use a
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} layout height since that could result in
+ * incorrect sizing of the views.
+ * </p>
+ *
+ * <p>Setting the WebView's height to {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
+ * enables the following behaviors:
+ * <ul>
+ * <li>The HTML body layout height is set to a fixed value. This means that elements with a height
+ * relative to the HTML body may not be sized correctly. </li>
+ * <li>For applications targetting {@link android.os.Build.VERSION_CODES#KITKAT} and earlier SDKs the
+ * HTML viewport meta tag will be ignored in order to preserve backwards compatibility. </li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Using a layout width of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} is not
+ * supported. If such a width is used the WebView will attempt to use the width of the parent
+ * instead.
+ * </p>
+ *
  */
 // Implementation notes.
 // The WebView is a thin API class that delegates its public API to a backend WebViewProvider
@@ -1789,6 +1826,37 @@
     }
 
     /**
+     * Creates a message channel to communicate with JS and returns the message
+     * ports that represent the endpoints of this message channel. The HTML5 message
+     * channel functionality is described here:
+     * https://html.spec.whatwg.org/multipage/comms.html#messagechannel
+     *
+     * The returned message channels are entangled and already in started state.
+     *
+     * @return the two message ports that form the message channel.
+     */
+    public WebMessagePort[] createWebMessageChannel() {
+        checkThread();
+        if (TRACE) Log.d(LOGTAG, "createWebMessageChannel");
+        return mProvider.createWebMessageChannel();
+    }
+
+    /**
+     * Post a message to main frame. The embedded application can restrict the
+     * messages to a certain target origin. See
+     *    https://html.spec.whatwg.org/multipage/comms.html#posting-messages
+     * for how target origin can be used.
+     *
+     * @param message the WebMessage
+     * @param targetOrigin the target origin.
+     */
+    public void postMessageToMainFrame(WebMessage message, Uri targetOrigin) {
+        checkThread();
+        if (TRACE) Log.d(LOGTAG, "postMessageToMainFrame. TargetOrigin=" + targetOrigin);
+        mProvider.postMessageToMainFrame(message, targetOrigin);
+    }
+
+    /**
      * Gets the WebSettings object used to control the settings for this
      * WebView.
      *
@@ -2043,7 +2111,7 @@
         }
 
         public boolean super_performAccessibilityAction(int action, Bundle arguments) {
-            return WebView.super.performAccessibilityAction(action, arguments);
+            return WebView.super.performAccessibilityActionInternal(action, arguments);
         }
 
         public boolean super_performLongClick() {
@@ -2152,7 +2220,7 @@
     /**
      * In addition to the FindListener that the user may set via the WebView.setFindListener
      * API, FindActionModeCallback will register it's own FindListener. We keep them separate
-     * via this class so that that the two FindListeners can potentially exist at once.
+     * via this class so that the two FindListeners can potentially exist at once.
      */
     private class FindListenerDistributor implements FindListener {
         private FindListener mFindDialogFindListener;
@@ -2351,22 +2419,27 @@
         return mProvider.getViewDelegate().shouldDelayChildPressedState();
     }
 
+    public CharSequence getAccessibilityClassName() {
+        return WebView.class.getName();
+    }
+
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(WebView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         mProvider.getViewDelegate().onInitializeAccessibilityNodeInfo(info);
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(WebView.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         mProvider.getViewDelegate().onInitializeAccessibilityEvent(event);
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         return mProvider.getViewDelegate().performAccessibilityAction(action, arguments);
     }
 
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index d52dd60..34b8cf6 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -23,8 +23,6 @@
 import android.view.KeyEvent;
 import android.view.ViewRootImpl;
 
-import java.security.Principal;
-
 public class WebViewClient {
 
     /**
@@ -50,7 +48,9 @@
      * is called once for each main frame load so a page with iframes or
      * framesets will call onPageStarted one time for the main frame. This also
      * means that onPageStarted will not be called when the contents of an
-     * embedded frame changes, i.e. clicking a link whose target is an iframe.
+     * embedded frame changes, i.e. clicking a link whose target is an iframe,
+     * it will also not be called for fragment navigations (navigations to
+     * #fragment_id).
      *
      * @param view The WebView that is initiating the callback.
      * @param url The url to be loaded.
@@ -174,6 +174,8 @@
     public static final int ERROR_FILE_NOT_FOUND = -14;
     /** Too many requests during this load */
     public static final int ERROR_TOO_MANY_REQUESTS = -15;
+    /** Request blocked by the browser */
+    public static final int ERROR_BLOCKED = -16;
 
     /**
      * Report an error to the host application. These errors are unrecoverable
@@ -183,12 +185,45 @@
      * @param errorCode The error code corresponding to an ERROR_* value.
      * @param description A String describing the error.
      * @param failingUrl The url that failed to load.
+     * @deprecated Use {@link #onReceivedError(WebView, WebResourceRequest, WebResourceError)
+     *             onReceivedError(WebView, WebResourceRequest, WebResourceError)} instead.
      */
+    @Deprecated
     public void onReceivedError(WebView view, int errorCode,
             String description, String failingUrl) {
     }
 
     /**
+     * Report web resource loading error to the host application. These errors usually indicate
+     * inability to connect to the server. Note that unlike the deprecated version of the callback,
+     * the new version will be called for any resource (iframe, image, etc), not just for the main
+     * page. Thus, it is recommended to perform minimum required work in this callback.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param error Information about the error occured.
+     */
+    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+        if (request.isForMainFrame()) {
+            onReceivedError(view,
+                    error.getErrorCode(), error.getDescription(), request.getUrl().toString());
+        }
+    }
+
+    /**
+     * Notify the host application that an HTTP error has been received from the server while
+     * loading a resource.  HTTP errors have status codes &gt;= 400.  This callback will be called
+     * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to
+     * perform minimum required work in this callback. Note that the content of the server
+     * response may not be provided within the <b>errorResponse</b> parameter.
+     * @param view The WebView that is initiating the callback.
+     * @param request The originating request.
+     * @param errorResponse Information about the error occured.
+     */
+    public void onReceivedHttpError(
+            WebView view, WebResourceRequest request, WebResourceResponseBase errorResponse) {
+    }
+
+    /**
      * As the host application if the browser should resend data as the
      * requested page was a result of a POST. The default is to not resend the
      * data.
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index bfea481..cdff416 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -16,7 +16,6 @@
 
 package android.webkit;
 
-import android.annotation.SystemApi;
 import android.content.Context;
 
 /**
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index e03445e..ac360fa 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.net.http.ErrorStrings;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.SparseArray;
@@ -150,7 +149,7 @@
      * Returns the error string for the given {@code errorCode}.
      */
     public String getErrorString(Context context, int errorCode) {
-        return ErrorStrings.getString(errorCode, context);
+        return LegacyErrorStrings.getString(errorCode, context);
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 474ef42..cafe053 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -117,12 +117,8 @@
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
                 try {
-                    try {
-                        sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
-                                .newInstance(new WebViewDelegate());
-                    } catch (Exception e) {
-                        sProviderInstance = providerClass.newInstance();
-                    }
+                    sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
+                            .newInstance(new WebViewDelegate());
                     if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                     return sProviderInstance;
                 } catch (Exception e) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 2aee57b..0cdb875 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -24,8 +24,8 @@
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.net.http.SslCertificate;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
 import android.print.PrintDocumentAdapter;
@@ -228,6 +228,10 @@
 
     public void removeJavascriptInterface(String interfaceName);
 
+    public WebMessagePort[] createWebMessageChannel();
+
+    public void postMessageToMainFrame(WebMessage message, Uri targetOrigin);
+
     public WebSettings getSettings();
 
     public void setMapTrackballToArrowKeys(boolean setMap);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 523f970..168066a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -16,11 +16,12 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.TransitionDrawable;
@@ -578,6 +579,12 @@
     private boolean mIsChildViewEnabled;
 
     /**
+     * The cached drawable state for the selector. Accounts for child enabled
+     * state, but otherwise identical to the view's own drawable state.
+     */
+    private int[] mSelectorState;
+
+    /**
      * The last scroll state reported to clients through {@link OnScrollListener}.
      */
     private int mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE;
@@ -1466,8 +1473,9 @@
         onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
     }
 
+    /** @hide */
     @Override
-    public void sendAccessibilityEvent(int eventType) {
+    public void sendAccessibilityEventInternal(int eventType) {
         // Since this class calls onScrollChanged even if the mFirstPosition and the
         // child count have not changed we will avoid sending duplicate accessibility
         // events.
@@ -1482,19 +1490,18 @@
                 mLastAccessibilityScrollEventToIndex = lastVisiblePosition;
             }
         }
-        super.sendAccessibilityEvent(eventType);
+        super.sendAccessibilityEventInternal(eventType);
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AbsListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsListView.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AbsListView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         if (isEnabled()) {
             if (canScrollUp()) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
@@ -1522,9 +1529,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         switch (action) {
@@ -2395,7 +2403,9 @@
             lp.itemId = mAdapter.getItemId(position);
         }
         lp.viewType = mAdapter.getItemViewType(position);
-        child.setLayoutParams(lp);
+        if (lp != vlp) {
+          child.setLayoutParams(lp);
+        }
     }
 
     class ListItemAccessibilityDelegate extends AccessibilityDelegate {
@@ -2703,7 +2713,7 @@
      *
      * @attr ref android.R.styleable#AbsListView_listSelector
      */
-    public void setSelector(int resID) {
+    public void setSelector(@DrawableRes int resID) {
         setSelector(getContext().getDrawable(resID));
     }
 
@@ -2783,7 +2793,7 @@
     void updateSelectorState() {
         if (mSelector != null) {
             if (shouldShowSelector()) {
-                mSelector.setState(getDrawableState());
+                mSelector.setState(getDrawableStateForSelector());
             } else {
                 mSelector.setState(StateSet.NOTHING);
             }
@@ -2796,12 +2806,11 @@
         updateSelectorState();
     }
 
-    @Override
-    protected int[] onCreateDrawableState(int extraSpace) {
+    private int[] getDrawableStateForSelector() {
         // If the child view is enabled then do the default behavior.
         if (mIsChildViewEnabled) {
             // Common case
-            return super.onCreateDrawableState(extraSpace);
+            return super.getDrawableState();
         }
 
         // The selector uses this View's drawable state. The selected child view
@@ -2809,10 +2818,12 @@
         // states.
         final int enabledState = ENABLED_STATE_SET[0];
 
-        // If we don't have any extra space, it will return one of the static state arrays,
-        // and clearing the enabled state on those arrays is a bad thing!  If we specify
-        // we need extra space, it will create+copy into a new array that safely mutable.
-        int[] state = super.onCreateDrawableState(extraSpace + 1);
+        // If we don't have any extra space, it will return one of the static
+        // state arrays, and clearing the enabled state on those arrays is a
+        // bad thing! If we specify we need extra space, it will create+copy
+        // into a new array that is safely mutable.
+        final int[] state = onCreateDrawableState(1);
+
         int enabledPos = -1;
         for (int i = state.length - 1; i >= 0; i--) {
             if (state[i] == enabledState) {
@@ -5972,7 +5983,7 @@
      *
      * @param color The background color
      */
-    public void setCacheColorHint(int color) {
+    public void setCacheColorHint(@ColorInt int color) {
         if (color != mCacheColorHint) {
             mCacheColorHint = color;
             int count = getChildCount();
@@ -5990,6 +6001,7 @@
      * @return The cache color hint
      */
     @ViewDebug.ExportedProperty(category = "drawing")
+    @ColorInt
     public int getCacheColorHint() {
         return mCacheColorHint;
     }
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 4800c7f..d6f9f78 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -31,7 +31,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.internal.R;
@@ -381,8 +380,8 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         final Drawable thumb = mThumb;
         if (thumb != null) {
@@ -403,28 +402,31 @@
     }
 
     private void updateThumbAndTrackPos(int w, int h) {
+        final int paddedHeight = h - mPaddingTop - mPaddingBottom;
         final Drawable track = getCurrentDrawable();
         final Drawable thumb = mThumb;
 
         // The max height does not incorporate padding, whereas the height
         // parameter does.
-        final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
+        final int trackHeight = Math.min(mMaxHeight, paddedHeight);
         final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
 
         // Apply offset to whichever item is taller.
         final int trackOffset;
         final int thumbOffset;
         if (thumbHeight > trackHeight) {
-            trackOffset = (thumbHeight - trackHeight) / 2;
-            thumbOffset = 0;
+            final int offsetHeight = (paddedHeight - thumbHeight) / 2;
+            trackOffset = offsetHeight + (thumbHeight - trackHeight) / 2;
+            thumbOffset = offsetHeight + 0;
         } else {
-            trackOffset = 0;
-            thumbOffset = (trackHeight - thumbHeight) / 2;
+            final int offsetHeight = (paddedHeight - trackHeight) / 2;
+            trackOffset = offsetHeight + 0;
+            thumbOffset = offsetHeight + (trackHeight - thumbHeight) / 2;
         }
 
         if (track != null) {
-            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
-                    h - mPaddingBottom - trackOffset - mPaddingTop);
+            final int trackWidth = w - mPaddingRight - mPaddingLeft;
+            track.setBounds(0, trackOffset, trackWidth, trackOffset + trackHeight);
         }
 
         if (thumb != null) {
@@ -472,7 +474,6 @@
 
         final Drawable background = getBackground();
         if (background != null) {
-            final Rect bounds = thumb.getBounds();
             final int offsetX = mPaddingLeft - mThumbOffset;
             final int offsetY = mPaddingTop;
             background.setHotspotBounds(left + offsetX, top + offsetY,
@@ -695,19 +696,20 @@
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (isEnabled()) {
-            int progress = getProgress();
+            int increment = mKeyProgressIncrement;
             switch (keyCode) {
                 case KeyEvent.KEYCODE_DPAD_LEFT:
-                    if (progress <= 0) break;
-                    setProgress(progress - mKeyProgressIncrement, true);
-                    onKeyChange();
-                    return true;
-
+                    increment = -increment;
+                    // fallthrough
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
-                    if (progress >= getMax()) break;
-                    setProgress(progress + mKeyProgressIncrement, true);
-                    onKeyChange();
-                    return true;
+                    increment = isLayoutRtl() ? -increment : increment;
+                    int progress = getProgress() + increment;
+                    if (progress > 0 && progress < getMax()) {
+                        setProgress(progress, true);
+                        onKeyChange();
+                        return true;
+                    }
+                    break;
             }
         }
 
@@ -715,15 +717,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AbsSeekBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsSeekBar.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AbsSeekBar.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
         if (isEnabled()) {
             final int progress = getProgress();
@@ -736,9 +737,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         if (!isEnabled()) {
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 6a4ad75..1cb7f2a 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -28,8 +28,6 @@
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * An abstract base class for spinner widgets. SDK users will probably not
@@ -73,13 +71,12 @@
         initAbsSpinner();
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.AbsSpinner, defStyleAttr, defStyleRes);
+                attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes);
 
-        CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
+        final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
         if (entries != null) {
-            ArrayAdapter<CharSequence> adapter =
-                    new ArrayAdapter<CharSequence>(context,
-                            R.layout.simple_spinner_item, entries);
+            final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
+                    context, R.layout.simple_spinner_item, entries);
             adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
             setAdapter(adapter);
         }
@@ -472,14 +469,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AbsSpinner.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AbsSpinner.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AbsSpinner.class.getName();
     }
 }
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 18f15a0..4fadc19 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -17,10 +17,10 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Matrix;
-import android.graphics.Rect;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -55,7 +55,7 @@
         implements ActionProvider.SubUiVisibilityListener {
     private static final String TAG = "ActionMenuPresenter";
 
-    private View mOverflowButton;
+    private OverflowMenuButton mOverflowButton;
     private boolean mReserveOverflow;
     private boolean mReserveOverflowSet;
     private int mWidthLimit;
@@ -79,6 +79,8 @@
     private OpenOverflowRunnable mPostedOpenRunnable;
     private ActionMenuPopupCallback mPopupCallback;
 
+    private TintInfo mOverflowTintInfo;
+
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
@@ -113,6 +115,7 @@
                 mOverflowButton = new OverflowMenuButton(mSystemContext);
                 final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                 mOverflowButton.measure(spec, spec);
+                applyOverflowTint();
             }
             width -= mOverflowButton.getMeasuredWidth();
         } else {
@@ -236,6 +239,7 @@
         if (hasOverflow) {
             if (mOverflowButton == null) {
                 mOverflowButton = new OverflowMenuButton(mSystemContext);
+                applyOverflowTint();
             }
             ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
             if (parent != mMenuView) {
@@ -550,6 +554,40 @@
         menuView.initialize(mMenu);
     }
 
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mOverflowTintInfo == null) {
+            mOverflowTintInfo = new TintInfo();
+        }
+        mOverflowTintInfo.mTintList = tint;
+        mOverflowTintInfo.mHasTintList = true;
+
+        applyOverflowTint();
+    }
+
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mOverflowTintInfo == null) {
+            mOverflowTintInfo = new TintInfo();
+        }
+        mOverflowTintInfo.mTintMode = tintMode;
+        mOverflowTintInfo.mHasTintMode = true;
+
+        applyOverflowTint();
+    }
+
+    private void applyOverflowTint() {
+        final TintInfo tintInfo = mOverflowTintInfo;
+        if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
+            if (mOverflowButton != null) {
+                if (tintInfo.mHasTintList) {
+                    mOverflowButton.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mOverflowButton.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
     private static class SavedState implements Parcelable {
         public int openSubMenuId;
 
@@ -645,9 +683,10 @@
             return false;
         }
 
+    /** @hide */
         @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
+        public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfoInternal(info);
             info.setCanOpenPopup(true);
         }
 
@@ -773,4 +812,11 @@
             return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
         }
     }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 0a8a01f..9d3a5dc 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -16,7 +16,9 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.graphics.PorterDuff;
 import android.util.AttributeSet;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
@@ -116,11 +118,14 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mPresenter.updateMenuView(false);
 
-        if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
-            mPresenter.hideOverflowMenu();
-            mPresenter.showOverflowMenu();
+        if (mPresenter != null) {
+            mPresenter.updateMenuView(false);
+
+            if (mPresenter.isOverflowMenuShowing()) {
+                mPresenter.hideOverflowMenu();
+                mPresenter.showOverflowMenu();
+            }
         }
     }
 
@@ -543,6 +548,31 @@
         mReserveOverflow = reserveOverflow;
     }
 
+    /**
+     * Applies a tint to the overflow drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mPresenter != null) {
+            mPresenter.setOverflowTintList(tint);
+        }
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setOverflowTintList(ColorStateList)} to the overflow drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     */
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mPresenter != null) {
+            mPresenter.setOverflowTintMode(tintMode);
+        }
+    }
+
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
@@ -700,7 +730,8 @@
         return result;
     }
 
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    /** @hide */
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         return false;
     }
 
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f9af2f9..f34ad71 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -334,7 +335,7 @@
      *
      * @param resourceId The content description resource id.
      */
-    public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
+    public void setExpandActivityOverflowButtonContentDescription(@StringRes int resourceId) {
         CharSequence contentDescription = mContext.getString(resourceId);
         mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
     }
@@ -514,7 +515,7 @@
      *
      * @param resourceId The resource id.
      */
-    public void setDefaultActionButtonContentDescription(int resourceId) {
+    public void setDefaultActionButtonContentDescription(@StringRes int resourceId) {
         mDefaultActionButtonContentDescription = resourceId;
     }
 
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 5e2394c..72cb0b5 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.os.Parcelable;
@@ -276,7 +277,7 @@
      *
      * @param listener The callback that will be invoked.
      */
-    public void setOnItemClickListener(OnItemClickListener listener) {
+    public void setOnItemClickListener(@Nullable OnItemClickListener listener) {
         mOnItemClickListener = listener;
     }
 
@@ -284,6 +285,7 @@
      * @return The callback to be invoked with an item in this AdapterView has
      *         been clicked, or null id no callback has been set.
      */
+    @Nullable
     public final OnItemClickListener getOnItemClickListener() {
         return mOnItemClickListener;
     }
@@ -394,10 +396,11 @@
      *
      * @param listener The callback that will run
      */
-    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
         mOnItemSelectedListener = listener;
     }
 
+    @Nullable
     public final OnItemSelectedListener getOnItemSelectedListener() {
         return mOnItemSelectedListener;
     }
@@ -929,8 +932,9 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         View selectedView = getSelectedView();
         if (selectedView != null && selectedView.getVisibility() == VISIBLE
                 && selectedView.dispatchPopulateAccessibilityEvent(event)) {
@@ -939,9 +943,10 @@
         return false;
     }
 
+    /** @hide */
     @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (super.onRequestSendAccessibilityEvent(child, event)) {
+    public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEventInternal(child, event)) {
             // Add a record for ourselves as well.
             AccessibilityEvent record = AccessibilityEvent.obtain();
             onInitializeAccessibilityEvent(record);
@@ -954,9 +959,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AdapterView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AdapterView.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setScrollable(isScrollableForAccessibility());
         View selectedView = getSelectedView();
         if (selectedView != null) {
@@ -964,10 +974,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AdapterView.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setScrollable(isScrollableForAccessibility());
         View selectedView = getSelectedView();
         if (selectedView != null) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 1bc2f4b..932b354 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -29,8 +29,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.OnClickHandler;
 
 import java.util.ArrayList;
@@ -1085,14 +1083,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AdapterViewAnimator.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AdapterViewAnimator.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AdapterViewAnimator.class.getName();
     }
 }
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 285dee8..a105b40 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -26,8 +26,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.RemotableViewMethod;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 /**
@@ -305,14 +303,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(AdapterViewFlipper.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(AdapterViewFlipper.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return AdapterViewFlipper.class.getName();
     }
 }
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 97926a7..89e508f 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -16,8 +16,13 @@
 
 package android.widget;
 
+import android.annotation.ArrayRes;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -44,7 +49,8 @@
  * or to have some of data besides toString() results fill the views,
  * override {@link #getView(int, View, ViewGroup)} to return the type of view you want.
  */
-public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
+public class ArrayAdapter<T> extends BaseAdapter implements Filterable,
+        Spinner.ThemedSpinnerAdapter {
     /**
      * Contains the list of objects that represent the data of this ArrayAdapter.
      * The content of this list is referred to as "the array" in the documentation.
@@ -93,6 +99,9 @@
 
     private LayoutInflater mInflater;
 
+    /** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */
+    private LayoutInflater mDropDownInflater;
+
     /**
      * Constructor
      *
@@ -100,8 +109,8 @@
      * @param resource The resource ID for a layout file containing a TextView to use when
      *                 instantiating views.
      */
-    public ArrayAdapter(Context context, int resource) {
-        init(context, resource, 0, new ArrayList<T>());
+    public ArrayAdapter(Context context, @LayoutRes int resource) {
+        this(context, resource, 0, new ArrayList<T>());
     }
 
     /**
@@ -112,8 +121,8 @@
      *                 instantiating views.
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      */
-    public ArrayAdapter(Context context, int resource, int textViewResourceId) {
-        init(context, resource, textViewResourceId, new ArrayList<T>());
+    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {
+        this(context, resource, textViewResourceId, new ArrayList<T>());
     }
 
     /**
@@ -124,8 +133,8 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, int resource, T[] objects) {
-        init(context, resource, 0, Arrays.asList(objects));
+    public ArrayAdapter(Context context, @LayoutRes int resource, T[] objects) {
+        this(context, resource, 0, Arrays.asList(objects));
     }
 
     /**
@@ -137,8 +146,8 @@
      * @param textViewResourceId The id of the TextView within the layout resource to be populated
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) {
-        init(context, resource, textViewResourceId, Arrays.asList(objects));
+    public ArrayAdapter(Context context, @LayoutRes int resource, @IdRes int textViewResourceId, T[] objects) {
+        this(context, resource, textViewResourceId, Arrays.asList(objects));
     }
 
     /**
@@ -149,8 +158,8 @@
      *                 instantiating views.
      * @param objects The objects to represent in the ListView.
      */
-    public ArrayAdapter(Context context, int resource, List<T> objects) {
-        init(context, resource, 0, objects);
+    public ArrayAdapter(Context context, @LayoutRes int resource, List<T> objects) {
+        this(context, resource, 0, objects);
     }
 
     /**
@@ -163,7 +172,11 @@
      * @param objects The objects to represent in the ListView.
      */
     public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects) {
-        init(context, resource, textViewResourceId, objects);
+        mContext = context;
+        mInflater = LayoutInflater.from(context);
+        mResource = mDropDownResource = resource;
+        mObjects = objects;
+        mFieldId = textViewResourceId;
     }
 
     /**
@@ -305,14 +318,6 @@
         mNotifyOnChange = notifyOnChange;
     }
 
-    private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
-        mContext = context;
-        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mResource = mDropDownResource = resource;
-        mObjects = objects;
-        mFieldId = textViewResourceId;
-    }
-
     /**
      * Returns the context associated with this array adapter. The context is used
      * to create views from the resource passed to the constructor.
@@ -359,16 +364,16 @@
      * {@inheritDoc}
      */
     public View getView(int position, View convertView, ViewGroup parent) {
-        return createViewFromResource(position, convertView, parent, mResource);
+        return createViewFromResource(mInflater, position, convertView, parent, mResource);
     }
 
-    private View createViewFromResource(int position, View convertView, ViewGroup parent,
-            int resource) {
+    private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
+            ViewGroup parent, int resource) {
         View view;
         TextView text;
 
         if (convertView == null) {
-            view = mInflater.inflate(resource, parent, false);
+            view = inflater.inflate(resource, parent, false);
         } else {
             view = convertView;
         }
@@ -403,16 +408,45 @@
      * @param resource the layout resource defining the drop down views
      * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
      */
-    public void setDropDownViewResource(int resource) {
+    public void setDropDownViewResource(@LayoutRes int resource) {
         this.mDropDownResource = resource;
     }
 
     /**
+     * Sets the {@link Resources.Theme} against which drop-down views are
+     * inflated.
+     * <p>
+     * By default, drop-down views are inflated against the theme of the
+     * {@link Context} passed to the adapter's constructor.
+     *
+     * @param theme the theme against which to inflate drop-down views or
+     *              {@code null} to use the theme from the adapter's context
+     * @see #getDropDownView(int, View, ViewGroup)
+     */
+    @Override
+    public void setDropDownViewTheme(Resources.Theme theme) {
+        if (theme == null) {
+            mDropDownInflater = null;
+        } else if (theme == mInflater.getContext().getTheme()) {
+            mDropDownInflater = mInflater;
+        } else {
+            final Context context = new ContextThemeWrapper(mContext, theme);
+            mDropDownInflater = LayoutInflater.from(context);
+        }
+    }
+
+    @Override
+    public Resources.Theme getDropDownViewTheme() {
+        return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
-        return createViewFromResource(position, convertView, parent, mDropDownResource);
+        final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
+        return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
     }
 
     /**
@@ -426,7 +460,7 @@
      * @return An ArrayAdapter<CharSequence>.
      */
     public static ArrayAdapter<CharSequence> createFromResource(Context context,
-            int textArrayResId, int textViewResId) {
+            @ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
         CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
         return new ArrayAdapter<CharSequence>(context, textViewResId, strings);
     }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index e6392b9..01767d5 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.DrawableRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
@@ -356,7 +357,7 @@
      * 
      * @attr ref android.R.styleable#PopupWindow_popupBackground
      */
-    public void setDropDownBackgroundResource(int id) {
+    public void setDropDownBackgroundResource(@DrawableRes int id) {
         mPopup.setBackgroundDrawable(getContext().getDrawable(id));
     }
     
diff --git a/core/java/android/widget/Button.java b/core/java/android/widget/Button.java
index 1663620..154cc33 100644
--- a/core/java/android/widget/Button.java
+++ b/core/java/android/widget/Button.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 
@@ -112,14 +110,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(Button.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(Button.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Button.class.getName();
     }
 }
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index ed59ea6..5bc16cb 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -23,9 +25,6 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import com.android.internal.R;
 
 import java.text.DateFormat;
@@ -142,7 +141,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
      */
-    public void setSelectedWeekBackgroundColor(int color) {
+    public void setSelectedWeekBackgroundColor(@ColorInt int color) {
         mDelegate.setSelectedWeekBackgroundColor(color);
     }
 
@@ -153,6 +152,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
      */
+    @ColorInt
     public int getSelectedWeekBackgroundColor() {
         return mDelegate.getSelectedWeekBackgroundColor();
     }
@@ -164,7 +164,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
      */
-    public void setFocusedMonthDateColor(int color) {
+    public void setFocusedMonthDateColor(@ColorInt int color) {
         mDelegate.setFocusedMonthDateColor(color);
     }
 
@@ -175,6 +175,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
      */
+    @ColorInt
     public int getFocusedMonthDateColor() {
         return mDelegate.getFocusedMonthDateColor();
     }
@@ -186,7 +187,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
      */
-    public void setUnfocusedMonthDateColor(int color) {
+    public void setUnfocusedMonthDateColor(@ColorInt int color) {
         mDelegate.setUnfocusedMonthDateColor(color);
     }
 
@@ -197,6 +198,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
      */
+    @ColorInt
     public int getUnfocusedMonthDateColor() {
         return mDelegate.getUnfocusedMonthDateColor();
     }
@@ -208,7 +210,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekNumberColor
      */
-    public void setWeekNumberColor(int color) {
+    public void setWeekNumberColor(@ColorInt int color) {
         mDelegate.setWeekNumberColor(color);
     }
 
@@ -219,6 +221,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekNumberColor
      */
+    @ColorInt
     public int getWeekNumberColor() {
         return mDelegate.getWeekNumberColor();
     }
@@ -230,7 +233,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
      */
-    public void setWeekSeparatorLineColor(int color) {
+    public void setWeekSeparatorLineColor(@ColorInt int color) {
         mDelegate.setWeekSeparatorLineColor(color);
     }
 
@@ -241,6 +244,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
      */
+    @ColorInt
     public int getWeekSeparatorLineColor() {
         return mDelegate.getWeekSeparatorLineColor();
     }
@@ -253,7 +257,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
      */
-    public void setSelectedDateVerticalBar(int resourceId) {
+    public void setSelectedDateVerticalBar(@DrawableRes int resourceId) {
         mDelegate.setSelectedDateVerticalBar(resourceId);
     }
 
@@ -502,13 +506,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(CalendarView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(CalendarView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CalendarView.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index 71438c9..15bbdd2 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -73,14 +71,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(CheckBox.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(CheckBox.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CheckBox.class.getName();
     }
 }
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 69969a9..22e079c 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -32,12 +33,14 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-
 /**
- * An extension to TextView that supports the {@link android.widget.Checkable} interface.
- * This is useful when used in a {@link android.widget.ListView ListView} where the it's 
- * {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has been set to
- * something other than {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
+ * An extension to {@link TextView} that supports the {@link Checkable}
+ * interface and displays.
+ * <p>
+ * This is useful when used in a {@link android.widget.ListView ListView} where
+ * the {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has
+ * been set to something other than
+ * {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
  *
  * @attr ref android.R.styleable#CheckedTextView_checked
  * @attr ref android.R.styleable#CheckedTextView_checkMark
@@ -116,9 +119,10 @@
     }
 
     /**
-     * <p>Changes the checked state of this text view.</p>
+     * Sets the checked state of this view.
      *
-     * @param checked true to check the text, false to uncheck it
+     * @param checked {@code true} set the state to checked, {@code false} to
+     *                uncheck
      */
     public void setChecked(boolean checked) {
         if (mChecked != checked) {
@@ -129,24 +133,24 @@
         }
     }
 
-
     /**
-     * Set the checkmark to a given Drawable, identified by its resourece id. This will be drawn
-     * when {@link #isChecked()} is true.
+     * Sets the check mark to the drawable with the specified resource ID.
+     * <p>
+     * When this view is checked, the drawable's state set will include
+     * {@link android.R.attr#state_checked}.
      *
-     * @param resid The Drawable to use for the checkmark.
-     *
+     * @param resId the resource identifier of drawable to use as the check
+     *              mark
+     * @attr ref android.R.styleable#CheckedTextView_checkMark
      * @see #setCheckMarkDrawable(Drawable)
      * @see #getCheckMarkDrawable()
-     *
-     * @attr ref android.R.styleable#CheckedTextView_checkMark
      */
-    public void setCheckMarkDrawable(int resid) {
-        if (resid != 0 && resid == mCheckMarkResource) {
+    public void setCheckMarkDrawable(@DrawableRes int resId) {
+        if (resId != 0 && resId == mCheckMarkResource) {
             return;
         }
 
-        mCheckMarkResource = resid;
+        mCheckMarkResource = resId;
 
         Drawable d = null;
         if (mCheckMarkResource != 0) {
@@ -156,14 +160,15 @@
     }
 
     /**
-     * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true.
+     * Set the check mark to the specified drawable.
+     * <p>
+     * When this view is checked, the drawable's state set will include
+     * {@link android.R.attr#state_checked}.
      *
-     * @param d The Drawable to use for the checkmark.
-     *
+     * @param d the drawable to use for the check mark
+     * @attr ref android.R.styleable#CheckedTextView_checkMark
      * @see #setCheckMarkDrawable(int)
      * @see #getCheckMarkDrawable()
-     *
-     * @attr ref android.R.styleable#CheckedTextView_checkMark
      */
     public void setCheckMarkDrawable(Drawable d) {
         if (mCheckMarkDrawable != null) {
@@ -436,16 +441,21 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(CheckedTextView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CheckedTextView.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setChecked(mChecked);
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(CheckedTextView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setCheckable(true);
         info.setChecked(mChecked);
     }
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index f94789d..a15080e 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -24,8 +24,6 @@
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import java.util.Formatter;
@@ -282,14 +280,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(Chronometer.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(Chronometer.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Chronometer.class.getName();
     }
 }
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 447ccc2..f2afeeb 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.graphics.PorterDuff;
 import com.android.internal.R;
@@ -50,7 +51,6 @@
  */
 public abstract class CompoundButton extends Button implements Checkable {
     private boolean mChecked;
-    private int mButtonResource;
     private boolean mBroadcasting;
 
     private Drawable mButtonDrawable;
@@ -197,54 +197,62 @@
     }
 
     /**
-     * Set the button graphic to a given Drawable, identified by its resource
-     * id.
+     * Sets a drawable as the compound button image given its resource
+     * identifier.
      *
-     * @param resid the resource id of the drawable to use as the button
-     *        graphic
+     * @param resId the resource identifier of the drawable
+     * @attr ref android.R.styleable#CompoundButton_button
      */
-    public void setButtonDrawable(int resid) {
-        if (resid != 0 && resid == mButtonResource) {
-            return;
-        }
-
-        mButtonResource = resid;
-
-        Drawable d = null;
-        if (mButtonResource != 0) {
-            d = getContext().getDrawable(mButtonResource);
+    public void setButtonDrawable(@DrawableRes int resId) {
+        final Drawable d;
+        if (resId != 0) {
+            d = getContext().getDrawable(resId);
+        } else {
+            d = null;
         }
         setButtonDrawable(d);
     }
 
     /**
-     * Set the button graphic to a given Drawable
+     * Sets a drawable as the compound button image.
      *
-     * @param d The Drawable to use as the button graphic
+     * @param drawable the drawable to set
+     * @attr ref android.R.styleable#CompoundButton_button
      */
-    public void setButtonDrawable(Drawable d) {
-        if (mButtonDrawable != d) {
+    @Nullable
+    public void setButtonDrawable(@Nullable Drawable drawable) {
+        if (mButtonDrawable != drawable) {
             if (mButtonDrawable != null) {
                 mButtonDrawable.setCallback(null);
                 unscheduleDrawable(mButtonDrawable);
             }
 
-            mButtonDrawable = d;
+            mButtonDrawable = drawable;
 
-            if (d != null) {
-                d.setCallback(this);
-                d.setLayoutDirection(getLayoutDirection());
-                if (d.isStateful()) {
-                    d.setState(getDrawableState());
+            if (drawable != null) {
+                drawable.setCallback(this);
+                drawable.setLayoutDirection(getLayoutDirection());
+                if (drawable.isStateful()) {
+                    drawable.setState(getDrawableState());
                 }
-                d.setVisible(getVisibility() == VISIBLE, false);
-                setMinHeight(d.getIntrinsicHeight());
+                drawable.setVisible(getVisibility() == VISIBLE, false);
+                setMinHeight(drawable.getIntrinsicHeight());
                 applyButtonTint();
             }
         }
     }
 
     /**
+     * @return the drawable used as the compound button image
+     * @see #setButtonDrawable(Drawable)
+     * @see #setButtonDrawable(int)
+     */
+    @Nullable
+    public Drawable getButtonDrawable() {
+        return mButtonDrawable;
+    }
+
+    /**
      * Applies a tint to the button drawable. Does not modify the current tint
      * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
      * <p>
@@ -325,16 +333,21 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(CompoundButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return CompoundButton.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setChecked(mChecked);
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(CompoundButton.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setCheckable(true);
         info.setChecked(mChecked);
     }
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index d4c5be0..30c74c0 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -17,11 +17,13 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.DataSetObserver;
 import android.os.Handler;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -35,7 +37,7 @@
  * columns.
  */
 public abstract class CursorAdapter extends BaseAdapter implements Filterable,
-        CursorFilter.CursorFilterClient {
+        CursorFilter.CursorFilterClient, Spinner.ThemedSpinnerAdapter {
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -57,6 +59,11 @@
      */
     protected Context mContext;
     /**
+     * Context used for {@link #getDropDownView(int, View, ViewGroup)}.
+     * {@hide}
+     */
+    protected Context mDropDownContext;
+    /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
      */
@@ -185,6 +192,33 @@
     }
 
     /**
+     * Sets the {@link Resources.Theme} against which drop-down views are
+     * inflated.
+     * <p>
+     * By default, drop-down views are inflated against the theme of the
+     * {@link Context} passed to the adapter's constructor.
+     *
+     * @param theme the theme against which to inflate drop-down views or
+     *              {@code null} to use the theme from the adapter's context
+     * @see #newDropDownView(Context, Cursor, ViewGroup)
+     */
+    @Override
+    public void setDropDownViewTheme(Resources.Theme theme) {
+        if (theme == null) {
+            mDropDownContext = null;
+        } else if (theme == mContext.getTheme()) {
+            mDropDownContext = mContext;
+        } else {
+            mDropDownContext = new ContextThemeWrapper(mContext, theme);
+        }
+    }
+
+    @Override
+    public Resources.Theme getDropDownViewTheme() {
+        return mDropDownContext == null ? null : mDropDownContext.getTheme();
+    }
+
+    /**
      * Returns the cursor.
      * @return the cursor.
      */
@@ -258,20 +292,21 @@
     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         if (mDataValid) {
+            final Context context = mDropDownContext == null ? mContext : mDropDownContext;
             mCursor.moveToPosition(position);
-            View v;
+            final View v;
             if (convertView == null) {
-                v = newDropDownView(mContext, mCursor, parent);
+                v = newDropDownView(context, mCursor, parent);
             } else {
                 v = convertView;
             }
-            bindView(v, mContext, mCursor);
+            bindView(v, context, mCursor);
             return v;
         } else {
             return null;
         }
     }
-    
+
     /**
      * Makes a new view to hold the data pointed to by cursor.
      * @param context Interface to application's global information
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 0ca08e1..45998f7 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -33,7 +33,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.NumberPicker.OnValueChangeListener;
@@ -283,27 +282,22 @@
         return mDelegate.isEnabled();
     }
 
+    /** @hide */
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         return mDelegate.dispatchPopulateAccessibilityEvent(event);
     }
 
+    /** @hide */
     @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEventInternal(event);
         mDelegate.onPopulateAccessibilityEvent(event);
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        mDelegate.onInitializeAccessibilityEvent(event);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        mDelegate.onInitializeAccessibilityNodeInfo(info);
+    public CharSequence getAccessibilityClassName() {
+        return DatePicker.class.getName();
     }
 
     @Override
@@ -472,8 +466,6 @@
 
         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
         void onPopulateAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
     }
 
     /**
@@ -888,16 +880,6 @@
             event.getText().add(selectedDateUtterance);
         }
 
-        @Override
-        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-            event.setClassName(DatePicker.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            info.setClassName(DatePicker.class.getName());
-        }
-
         /**
          * Sets the current locale.
          *
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
old mode 100644
new mode 100755
index 61547f6..0e3ec7f
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -30,7 +30,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 
@@ -112,8 +111,8 @@
         mTempDate = getCalendarForLocale(mMaxDate, locale);
         mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
 
-        mMinDate.set(DEFAULT_START_YEAR, 1, 1);
-        mMaxDate.set(DEFAULT_END_YEAR, 12, 31);
+        mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
+        mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
 
         final Resources res = mDelegator.getResources();
         final TypedArray a = mContext.obtainStyledAttributes(attrs,
@@ -145,8 +144,8 @@
 
         // Use Theme attributes if possible
         final int dayOfWeekTextAppearanceResId = a.getResourceId(
-                R.styleable.DatePicker_dayOfWeekTextAppearance, -1);
-        if (dayOfWeekTextAppearanceResId != -1) {
+                R.styleable.DatePicker_dayOfWeekTextAppearance, 0);
+        if (dayOfWeekTextAppearanceResId != 0) {
             mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId);
         }
 
@@ -154,34 +153,23 @@
 
         dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
 
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor);
         final int monthTextAppearanceResId = a.getResourceId(
-                R.styleable.DatePicker_headerMonthTextAppearance, -1);
-        if (monthTextAppearanceResId != -1) {
+                R.styleable.DatePicker_headerMonthTextAppearance, 0);
+        if (monthTextAppearanceResId != 0) {
             mHeaderMonthTextView.setTextAppearance(context, monthTextAppearanceResId);
         }
-        mHeaderMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderMonthTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
         final int dayOfMonthTextAppearanceResId = a.getResourceId(
-                R.styleable.DatePicker_headerDayOfMonthTextAppearance, -1);
-        if (dayOfMonthTextAppearanceResId != -1) {
+                R.styleable.DatePicker_headerDayOfMonthTextAppearance, 0);
+        if (dayOfMonthTextAppearanceResId != 0) {
             mHeaderDayOfMonthTextView.setTextAppearance(context, dayOfMonthTextAppearanceResId);
         }
-        mHeaderDayOfMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderDayOfMonthTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
-        final int yearTextAppearanceResId = a.getResourceId(
-                R.styleable.DatePicker_headerYearTextAppearance, -1);
-        if (yearTextAppearanceResId != -1) {
-            mHeaderYearTextView.setTextAppearance(context, yearTextAppearanceResId);
+        final int headerYearTextAppearanceResId = a.getResourceId(
+                R.styleable.DatePicker_headerYearTextAppearance, 0);
+        if (headerYearTextAppearanceResId != 0) {
+            mHeaderYearTextView.setTextAppearance(context, headerYearTextAppearanceResId);
         }
-        mHeaderYearTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderYearTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
         mDayPickerView = new DayPickerView(mContext);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
@@ -194,16 +182,23 @@
         mYearPickerView.init(this);
         mYearPickerView.setRange(mMinDate, mMaxDate);
 
-        final int yearSelectedCircleColor = a.getColor(R.styleable.DatePicker_yearListSelectorColor,
-                defaultHighlightColor);
-        mYearPickerView.setYearSelectedCircleColor(yearSelectedCircleColor);
+        final ColorStateList yearBackgroundColor = a.getColorStateList(
+                R.styleable.DatePicker_yearListSelectorColor);
+        mYearPickerView.setYearBackgroundColor(yearBackgroundColor);
+
+        final int yearTextAppearanceResId = a.getResourceId(
+                R.styleable.DatePicker_yearListItemTextAppearance, 0);
+        if (yearTextAppearanceResId != 0) {
+            mYearPickerView.setYearTextAppearance(yearTextAppearanceResId);
+        }
 
         final ColorStateList calendarTextColor = a.getColorStateList(
                 R.styleable.DatePicker_calendarTextColor);
-        final int calendarSelectedTextColor = a.getColor(
-                R.styleable.DatePicker_calendarSelectedTextColor, defaultHighlightColor);
-        mDayPickerView.setCalendarTextColor(ColorStateList.addFirstIfMissing(
-                calendarTextColor, R.attr.state_selected, calendarSelectedTextColor));
+        mDayPickerView.setCalendarTextColor(calendarTextColor);
+
+        final ColorStateList calendarDayBackgroundColor = a.getColorStateList(
+                R.styleable.DatePicker_calendarDayBackgroundColor);
+        mDayPickerView.setCalendarDayBackgroundColor(calendarDayBackgroundColor);
 
         mDayPickerDescription = res.getString(R.string.day_picker_description);
         mSelectDay = res.getString(R.string.select_day);
@@ -578,14 +573,8 @@
         event.getText().add(mCurrentDate.getTime().toString());
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(DatePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(DatePicker.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return DatePicker.class.getName();
     }
 
     @Override
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 443884a..0b5824a 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -21,17 +21,14 @@
 import android.content.IntentFilter;
 import android.content.BroadcastReceiver;
 import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Handler;
 import android.text.format.Time;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.provider.Settings;
 import android.widget.TextView;
 import android.widget.RemoteViews.RemoteView;
 
 import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 
@@ -156,7 +153,7 @@
                     format = getTimeFormat();
                     break;
                 case SHOW_MONTH_DAY_YEAR:
-                    format = getDateFormat();
+                    format = DateFormat.getDateInstance(DateFormat.SHORT);
                     break;
                 default:
                     throw new RuntimeException("unknown display value: " + display);
@@ -196,21 +193,6 @@
         return android.text.format.DateFormat.getTimeFormat(getContext());
     }
 
-    private DateFormat getDateFormat() {
-        String format = Settings.System.getString(getContext().getContentResolver(),
-                Settings.System.DATE_FORMAT);
-        if (format == null || "".equals(format)) {
-            return DateFormat.getDateInstance(DateFormat.SHORT);
-        } else {
-            try {
-                return new SimpleDateFormat(format);
-            } catch (IllegalArgumentException e) {
-                // If we tried to use a bad format string, fall back to a default.
-                return DateFormat.getDateInstance(DateFormat.SHORT);
-            }
-        }
-    }
-
     void clearFormatAndUpdate() {
         mLastFormat = null;
         update();
@@ -283,14 +265,10 @@
             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
             context.registerReceiver(mReceiver, filter);
-
-            final Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
-            context.getContentResolver().registerContentObserver(uri, true, mObserver);
         }
 
         void unregister(Context context) {
             context.unregisterReceiver(mReceiver);
-            context.getContentResolver().unregisterContentObserver(mObserver);
         }
     }
 }
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 7db3fb9..65af45d 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -305,6 +305,10 @@
         mAdapter.setCalendarTextColor(colors);
     }
 
+    void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) {
+        mAdapter.setCalendarDayBackgroundColor(dayBackgroundColor);
+    }
+
     void setCalendarTextAppearance(int resId) {
         mAdapter.setCalendarTextAppearance(resId);
     }
@@ -459,9 +463,10 @@
         mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setItemCount(-1);
     }
 
@@ -476,22 +481,26 @@
     /**
      * Necessary for accessibility, to ensure we support "scrolling" forward and backward
      * in the month list.
+     *
+     * @hide
      */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
         info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
     }
 
     /**
      * When scroll forward/backward events are received, announce the newly scrolled-to month.
+     *
+     * @hide
      */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD &&
                 action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
-            return super.performAccessibilityAction(action, arguments);
+            return super.performAccessibilityActionInternal(action, arguments);
         }
 
         // Figure out what month is showing.
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index b6c1e5b..9e442f9 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -23,9 +23,6 @@
 import android.provider.Settings;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import java.util.Calendar;
 
 /**
@@ -116,16 +113,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
+    public CharSequence getAccessibilityClassName() {
         //noinspection deprecation
-        event.setClassName(DigitalClock.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        //noinspection deprecation
-        info.setClassName(DigitalClock.class.getName());
+        return DigitalClock.class.getName();
     }
 }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 6925756..9019f31 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.content.res.TypedArray;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -24,7 +25,6 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.util.FloatMath;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -220,8 +220,8 @@
         if (mPullDistance == 0) {
             mGlowScaleY = mGlowScaleYStart = 0;
         } else {
-            final float scale = Math.max(0, 1 - 1 /
-                    FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+            final float scale = (float) (Math.max(0, 1 - 1 /
+                    Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
 
             mGlowScaleY = mGlowScaleYStart = scale;
         }
@@ -293,7 +293,7 @@
      *
      * @param color Color in argb
      */
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
         mPaint.setColor(color);
     }
 
@@ -301,6 +301,7 @@
      * Return the color of this edge effect in argb.
      * @return The color of this edge effect in argb
      */
+    @ColorInt
     public int getColor() {
         return mPaint.getColor();
     }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index a8ff562..d21a5f7 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -25,7 +25,6 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 
@@ -123,19 +122,13 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(EditText.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return EditText.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(EditText.class.getName());
-    }
-
-    @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SET_TEXT: {
                 CharSequence text = (arguments != null) ? arguments.getCharSequence(
@@ -147,7 +140,7 @@
                 return true;
             }
             default: {
-                return super.performAccessibilityAction(action, arguments);
+                return super.performAccessibilityActionInternal(action, arguments);
             }
         }
     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 936da32..d93b212 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -23,8 +23,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputFilter;
-import android.text.SpannableString;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.view.menu.MenuBuilder;
@@ -50,6 +48,7 @@
 import android.inputmethodservice.ExtractEditText;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.DynamicLayout;
@@ -118,15 +117,19 @@
  */
 public class Editor {
     private static final String TAG = "Editor";
-    static final boolean DEBUG_UNDO = false;
+    private static final boolean DEBUG_UNDO = false;
 
     static final int BLINK = 500;
     private static final float[] TEMP_POSITION = new float[2];
     private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
+    // Tag used when the Editor maintains its own separate UndoManager.
+    private static final String UNDO_OWNER_TAG = "Editor";
 
-    UndoManager mUndoManager;
-    UndoOwner mUndoOwner;
-    InputFilter mUndoInputFilter;
+    // Each Editor manages its own undo stack.
+    private final UndoManager mUndoManager = new UndoManager();
+    private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
+    boolean mAllowUndo = true;
 
     // Cursor Controllers.
     InsertionPointCursorController mInsertionPointCursorController;
@@ -214,6 +217,12 @@
     WordIterator mWordIterator;
     SpellChecker mSpellChecker;
 
+    // This word iterator is set with text and used to determine word boundaries
+    // when a user is selecting text.
+    private WordIterator mWordIteratorWithText;
+    // Indicate that the text in the word iterator needs to be updated.
+    private boolean mUpdateWordIteratorText;
+
     private Rect mTempRect;
 
     private TextView mTextView;
@@ -222,6 +231,54 @@
 
     Editor(TextView textView) {
         mTextView = textView;
+        // Synchronize the filter list, which places the undo input filter at the end.
+        mTextView.setFilters(mTextView.getFilters());
+    }
+
+    ParcelableParcel saveInstanceState() {
+        // For now there is only undo state.
+        return (ParcelableParcel) mUndoManager.saveInstanceState();
+    }
+
+    void restoreInstanceState(ParcelableParcel state) {
+        mUndoManager.restoreInstanceState(state);
+        // Re-associate this object as the owner of undo state.
+        mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    }
+
+    /**
+     * Forgets all undo and redo operations for this Editor.
+     */
+    void forgetUndoRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.forgetUndos(owners, -1 /* all */);
+        mUndoManager.forgetRedos(owners, -1 /* all */);
+    }
+
+    boolean canUndo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mAllowUndo && mUndoManager.countUndos(owners) > 0;
+    }
+
+    boolean canRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mAllowUndo && mUndoManager.countRedos(owners) > 0;
+    }
+
+    void undo() {
+        if (!mAllowUndo) {
+            return;
+        }
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.undo(owners, 1);  // Undo 1 action.
+    }
+
+    void redo() {
+        if (!mAllowUndo) {
+            return;
+        }
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.redo(owners, 1);  // Redo 1 action.
     }
 
     void onAttachedToWindow() {
@@ -647,9 +704,52 @@
         return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
     }
 
+    private int getWordStart(int offset) {
+        // FIXME - For this and similar methods we're not doing anything to check if there's
+        // a LocaleSpan in the text, this may be something we should try handling or checking for.
+        int retOffset = getWordIteratorWithText().getBeginning(offset);
+        if (retOffset == BreakIterator.DONE) retOffset = offset;
+        return retOffset;
+    }
+
+    private int getWordEnd(int offset, boolean includePunctuation) {
+        int retOffset = getWordIteratorWithText().getEnd(offset);
+        if (retOffset == BreakIterator.DONE) {
+            retOffset = offset;
+        } else if (includePunctuation) {
+            retOffset = handlePunctuation(retOffset);
+        }
+        return retOffset;
+    }
+
+    private boolean isEndBoundary(int offset) {
+        int thisEnd = getWordEnd(offset, false);
+        return offset == thisEnd;
+    }
+
+    private boolean isStartBoundary(int offset) {
+        int thisStart = getWordStart(offset);
+        return thisStart == offset;
+    }
+
+    private int handlePunctuation(int offset) {
+        // FIXME - Check with UX how repeated ending punctuation should be handled.
+        // FIXME - Check with UX if / how we would handle non sentence ending characters.
+        // FIXME - Consider punctuation in different languages.
+        CharSequence text = mTextView.getText();
+        if (offset < text.length()) {
+            int c = Character.codePointAt(text, offset);
+            if (c == 0x002e /* period */|| c == 0x003f /* question mark */
+                    || c == 0x0021 /* exclamation mark */) {
+                offset = Character.offsetByCodePoints(text, offset, 1);
+            }
+        }
+        return offset;
+    }
+
     /**
-     * Adjusts selection to the word under last touch offset.
-     * Return true if the operation was successfully performed.
+     * Adjusts selection to the word under last touch offset. Return true if the operation was
+     * successfully performed.
      */
     private boolean selectCurrentWord() {
         if (!canSelectText()) {
@@ -696,6 +796,8 @@
             selectionStart = ((Spanned) mTextView.getText()).getSpanStart(urlSpan);
             selectionEnd = ((Spanned) mTextView.getText()).getSpanEnd(urlSpan);
         } else {
+            // FIXME - We should check if there's a LocaleSpan in the text, this may be
+            // something we should try handling or checking for.
             final WordIterator wordIterator = getWordIterator();
             wordIterator.setCharSequence(mTextView.getText(), minOffset, maxOffset);
 
@@ -718,6 +820,7 @@
     void onLocaleChanged() {
         // Will be re-created on demand in getWordIterator with the proper new locale
         mWordIterator = null;
+        mWordIteratorWithText = null;
     }
 
     /**
@@ -730,6 +833,23 @@
         return mWordIterator;
     }
 
+    private WordIterator getWordIteratorWithText() {
+        if (mWordIteratorWithText == null) {
+            mWordIteratorWithText = new WordIterator(mTextView.getTextServicesLocale());
+            mUpdateWordIteratorText = true;
+        }
+        if (mUpdateWordIteratorText) {
+            // FIXME - Shouldn't copy all of the text as only the area of the text relevant
+            // to the user's selection is needed. A possible solution would be to
+            // copy some number N of characters near the selection and then when the
+            // user approaches N then we'd do another copy of the next N characters.
+            CharSequence text = mTextView.getText();
+            mWordIteratorWithText.setCharSequence(text, 0, text.length());
+            mUpdateWordIteratorText = false;
+        }
+        return mWordIteratorWithText;
+    }
+
     private long getCharRange(int offset) {
         final int textLength = mTextView.getText().length();
         if (offset + 1 < textLength) {
@@ -878,9 +998,8 @@
                 mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
                 stopSelectionActionMode();
             } else {
-                getSelectionController().hide();
-                selectCurrentWord();
-                getSelectionController().show();
+                stopSelectionActionMode();
+                startSelectionActionMode();
             }
             handled = true;
         }
@@ -1016,6 +1135,9 @@
     void sendOnTextChanged(int start, int after) {
         updateSpellCheckSpans(start, start + after, false);
 
+        // Flip flag to indicate the word iterator needs to have the text reset.
+        mUpdateWordIteratorText = true;
+
         // Hide the controllers as soon as text is modified (typing, procedural...)
         // We do not hide the span controllers, since they can be added when a new text is
         // inserted into the text view (voice IME).
@@ -1101,6 +1223,7 @@
                     ims.mChangedEnd = EXTRACT_UNKNOWN;
                     ims.mContentChanged = false;
                 }
+                mUndoInputFilter.beginBatchEdit();
                 mTextView.onBeginBatchEdit();
             }
         }
@@ -1127,6 +1250,7 @@
 
     void finishBatchEdit(final InputMethodState ims) {
         mTextView.onEndBatchEdit();
+        mUndoInputFilter.endBatchEdit();
 
         if (ims.mContentChanged || ims.mSelectionModeChanged) {
             mTextView.updateAfterEdit();
@@ -1352,6 +1476,9 @@
                             searchStartIndex);
                     // Note how dynamic layout's internal block indices get updated from Editor
                     blockIndices[i] = blockIndex;
+                    if (mTextDisplayLists[blockIndex] != null) {
+                        mTextDisplayLists[blockIndex].isDirty = true;
+                    }
                     searchStartIndex = blockIndex + 1;
                 }
 
@@ -1388,6 +1515,7 @@
                             // brings this range of text back to the top left corner of the viewport
                             hardwareCanvas.translate(-left, -top);
                             layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
+                            mTextDisplayLists[blockIndex].isDirty = false;
                             // No need to untranslate, previous context is popped after
                             // drawDisplayList
                         } finally {
@@ -1402,7 +1530,7 @@
                     blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
                 }
 
-                ((HardwareCanvas) canvas).drawRenderNode(blockDisplayList, null,
+                ((HardwareCanvas) canvas).drawRenderNode(blockDisplayList,
                         0 /* no child clipping, our TextView parent enforces it */);
 
                 endOfPreviousBlock = blockEndLine;
@@ -1567,6 +1695,9 @@
             }
         }
 
+        if (selectionStarted) {
+            getSelectionController().enterDrag();
+        }
         return selectionStarted;
     }
 
@@ -1702,7 +1833,7 @@
 
     /**
      * Called by the framework in response to a text auto-correction (such as fixing a typo using a
-     * a dictionnary) from the current input method, provided by it calling
+     * a dictionary) from the current input method, provided by it calling
      * {@link InputConnection#commitCorrection} InputConnection.commitCorrection()}. The default
      * implementation flashes the background of the corrected word to provide feedback to the user.
      *
@@ -2838,6 +2969,12 @@
                                 MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
             }
 
+            if (mTextView.isSuggestionsEnabled() && isCursorInsideSuggestionSpan()) {
+                menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace).
+                        setShowAsAction(
+                                MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+            }
+
             styledAttributes.recycle();
 
             if (mCustomSelectionActionModeCallback != null) {
@@ -2848,7 +2985,6 @@
             }
 
             if (menu.hasVisibleItems() || mode.getCustomView() != null) {
-                getSelectionController().show();
                 mTextView.setHasTransientState(true);
                 return true;
             } else {
@@ -2870,6 +3006,10 @@
                  mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) {
                 return true;
             }
+            if (item.getItemId() == TextView.ID_REPLACE) {
+                onReplace();
+                return true;
+            }
             return mTextView.onTextContextMenuItem(item.getItemId());
         }
 
@@ -2898,6 +3038,13 @@
         }
     }
 
+    private void onReplace() {
+        int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
+        stopSelectionActionMode();
+        Selection.setSelection((Spannable) mTextView.getText(), middle);
+        showSuggestions();
+    }
+
     private class ActionPopupWindow extends PinnedPopupWindow implements OnClickListener {
         private static final int POPUP_TEXT_LAYOUT =
                 com.android.internal.R.layout.text_edit_action_popup_text;
@@ -2956,10 +3103,7 @@
                 mTextView.onTextContextMenuItem(TextView.ID_PASTE);
                 hide();
             } else if (view == mReplaceTextView) {
-                int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
-                stopSelectionActionMode();
-                Selection.setSelection((Spannable) mTextView.getText(), middle);
-                showSuggestions();
+                onReplace();
             }
         }
 
@@ -3186,6 +3330,8 @@
         private Runnable mActionPopupShower;
         // Minimum touch target size for handles
         private int mMinSize;
+        // Indicates the line of text that the handle is on.
+        protected int mLine = -1;
 
         public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(mTextView.getContext());
@@ -3194,6 +3340,8 @@
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
             mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+            mContainer.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+            mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
             mContainer.setContentView(this);
 
             mDrawableLtr = drawableLtr;
@@ -3361,6 +3509,7 @@
                     addPositionToTouchUpFilter(offset);
                 }
                 final int line = layout.getLineForOffset(offset);
+                mLine = line;
 
                 mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
                         getHorizontalOffset() + getCursorOffset());
@@ -3410,6 +3559,30 @@
             }
         }
 
+        public void showAtLocation(int offset) {
+            // TODO - investigate if there's a better way to show the handles
+            // after the drag accelerator has occured.
+            int[] tmpCords = new int[2];
+            mTextView.getLocationInWindow(tmpCords);
+
+            Layout layout = mTextView.getLayout();
+            int posX = tmpCords[0];
+            int posY = tmpCords[1];
+
+            final int line = layout.getLineForOffset(offset);
+
+            int startX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f
+                    - mHotspotX - getHorizontalOffset() + getCursorOffset());
+            int startY = layout.getLineBottom(line);
+
+            // Take TextView's padding and scroll into account.
+            startX += mTextView.viewportToContentHorizontalOffset();
+            startY += mTextView.viewportToContentVerticalOffset();
+
+            mContainer.showAtLocation(mTextView, Gravity.NO_GRAVITY,
+                    startX + posX, startY + posY);
+        }
+
         @Override
         protected void onDraw(Canvas c) {
             final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -3648,6 +3821,12 @@
     }
 
     private class SelectionStartHandleView extends HandleView {
+        // The previous offset this handle was at.
+        private int mPrevOffset;
+        // Indicates whether the cursor is making adjustments within a word.
+        private boolean mInWord = false;
+        // Offset to track difference between touch and word boundary.
+        protected int mTouchWordOffset;
 
         public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -3655,11 +3834,7 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            if (isRtlRun) {
-                return drawable.getIntrinsicWidth() / 4;
-            } else {
-                return (drawable.getIntrinsicWidth() * 3) / 4;
-            }
+            return isRtlRun ? 0 : drawable.getIntrinsicWidth();
         }
 
         @Override
@@ -3681,21 +3856,81 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            int offset = mTextView.getOffsetForPosition(x, y);
+            final int trueOffset = mTextView.getOffsetForPosition(x, y);
+            final int currLine = mTextView.getLineAtCoordinate(y);
+            int offset = trueOffset;
+            boolean positionCursor = false;
 
-            // Handles can not cross and selection is at least one character
-            final int selectionEnd = mTextView.getSelectionEnd();
-            if (offset >= selectionEnd) offset = Math.max(0, selectionEnd - 1);
+            int end = getWordEnd(offset, true);
+            int start = getWordStart(offset);
 
-            positionAtCursorOffset(offset, false);
+            if (offset < mPrevOffset) {
+                // User is increasing the selection.
+                if (!mInWord || currLine < mLine) {
+                    // We're not in a word, or we're on a different line so we'll expand by
+                    // word. First ensure the user has at least entered the next word.
+                    int offsetToWord = Math.min((end - start) / 2, 2);
+                    if (offset <= end - offsetToWord || currLine < mLine) {
+                        offset = start;
+                    } else {
+                        offset = mPrevOffset;
+                    }
+                }
+                mPrevOffset = offset;
+                mTouchWordOffset = Math.max(trueOffset - offset, 0);
+                mInWord = !isStartBoundary(offset);
+                positionCursor = true;
+            } else if (offset - mTouchWordOffset > mPrevOffset) {
+                // User is shrinking the selection.
+                if (currLine > mLine) {
+                    // We're on a different line, so we'll snap to word boundaries.
+                    offset = end;
+                }
+                offset -= mTouchWordOffset;
+                mPrevOffset = offset;
+                mInWord = !isEndBoundary(offset);
+                positionCursor = true;
+            }
+
+            // Handles can not cross and selection is at least one character.
+            if (positionCursor) {
+                final int selectionEnd = mTextView.getSelectionEnd();
+                if (offset >= selectionEnd) {
+                    // We can't cross the handles so let's just constrain the Y value.
+                    int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+                    if (alteredOffset >= selectionEnd) {
+                        // Can't pass the other drag handle.
+                        offset = Math.max(0, selectionEnd - 1);
+                    } else {
+                        offset = alteredOffset;
+                    }
+                }
+                positionAtCursorOffset(offset, false);
+            }
         }
 
         public ActionPopupWindow getActionPopupWindow() {
             return mActionPopupWindow;
         }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            boolean superResult = super.onTouchEvent(event);
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                // Reset the touch word offset when the user has lifted their finger.
+                mTouchWordOffset = 0;
+            }
+            return superResult;
+        }
     }
 
     private class SelectionEndHandleView extends HandleView {
+        // The previous offset this handle was at.
+        private int mPrevOffset;
+        // Indicates whether the cursor is making adjustments within a word.
+        private boolean mInWord = false;
+        // Offset to track difference between touch and word boundary.
+        protected int mTouchWordOffset;
 
         public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
             super(drawableLtr, drawableRtl);
@@ -3703,11 +3938,7 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            if (isRtlRun) {
-                return (drawable.getIntrinsicWidth() * 3) / 4;
-            } else {
-                return drawable.getIntrinsicWidth() / 4;
-            }
+            return isRtlRun ? drawable.getIntrinsicWidth() : 0;
         }
 
         @Override
@@ -3729,20 +3960,72 @@
 
         @Override
         public void updatePosition(float x, float y) {
-            int offset = mTextView.getOffsetForPosition(x, y);
+            final int trueOffset = mTextView.getOffsetForPosition(x, y);
+            final int currLine = mTextView.getLineAtCoordinate(y);
+            int offset = trueOffset;
+            boolean positionCursor = false;
 
-            // Handles can not cross and selection is at least one character
-            final int selectionStart = mTextView.getSelectionStart();
-            if (offset <= selectionStart) {
-                offset = Math.min(selectionStart + 1, mTextView.getText().length());
+            int end = getWordEnd(offset, true);
+            int start = getWordStart(offset);
+
+            if (offset > mPrevOffset) {
+                // User is increasing the selection.
+                if (!mInWord || currLine > mLine) {
+                    // We're not in a word, or we're on a different line so we'll expand by
+                    // word. First ensure the user has at least entered the next word.
+                    int midPoint = Math.min((end - start) / 2, 2);
+                    if (offset >= start + midPoint || currLine > mLine) {
+                        offset = end;
+                    } else {
+                        offset = mPrevOffset;
+                    }
+                }
+                mPrevOffset = offset;
+                mTouchWordOffset = Math.max(offset - trueOffset, 0);
+                mInWord = !isEndBoundary(offset);
+                positionCursor = true;
+            } else if (offset + mTouchWordOffset < mPrevOffset) {
+                // User is shrinking the selection.
+                if (currLine > mLine) {
+                    // We're on a different line, so we'll snap to word boundaries.
+                    offset = getWordStart(offset);
+                }
+                offset += mTouchWordOffset;
+                mPrevOffset = offset;
+                positionCursor = true;
+                mInWord = !isStartBoundary(offset);
             }
 
-            positionAtCursorOffset(offset, false);
+            if (positionCursor) {
+                final int selectionStart = mTextView.getSelectionStart();
+                if (offset <= selectionStart) {
+                    // We can't cross the handles so let's just constrain the Y value.
+                    int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+                    int length = mTextView.getText().length();
+                    if (alteredOffset <= selectionStart) {
+                        // Can't pass the other drag handle.
+                        offset = Math.min(selectionStart + 1, length);
+                    } else {
+                        offset = Math.min(alteredOffset, length);
+                    }
+                }
+                positionAtCursorOffset(offset, false);
+            }
         }
 
         public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
             mActionPopupWindow = actionPopupWindow;
         }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            boolean superResult = super.onTouchEvent(event);
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                // Reset the touch word offset when the user has lifted their finger.
+                mTouchWordOffset = 0;
+            }
+            return superResult;
+        }
     }
 
     /**
@@ -3825,6 +4108,11 @@
         private float mDownPositionX, mDownPositionY;
         private boolean mGestureStayedInTapRegion;
 
+        // Where the user first starts the drag motion.
+        private int mStartOffset = -1;
+        // Indicates whether the user is selecting text and using the drag accelerator.
+        private boolean mDragAcceleratorActive;
+
         SelectionModifierCursorController() {
             resetTouchOffsets();
         }
@@ -3874,6 +4162,22 @@
             if (mEndHandle != null) mEndHandle.hide();
         }
 
+        public void enterDrag() {
+            // Just need to init the handles / hide insertion cursor.
+            show();
+            mDragAcceleratorActive = true;
+            // Start location of selection.
+            mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
+                    mLastDownPositionY);
+            // Don't show the handles until user has lifted finger.
+            hide();
+
+            // This stops scrolling parents from intercepting the touch event, allowing
+            // the user to continue dragging across the screen to select text; TextView will
+            // scroll as necessary.
+            mTextView.getParent().requestDisallowInterceptTouchEvent(true);
+        }
+
         public void onTouchEvent(MotionEvent event) {
             // This is done even when the View does not have focus, so that long presses can start
             // selection and tap can move cursor from this tap position.
@@ -3882,7 +4186,7 @@
                     final float x = event.getX();
                     final float y = event.getY();
 
-                    // Remember finger down position, to be able to start selection from there
+                    // Remember finger down position, to be able to start selection from there.
                     mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y);
 
                     // Double tap detection
@@ -3921,23 +4225,112 @@
                     break;
 
                 case MotionEvent.ACTION_MOVE:
+                    final ViewConfiguration viewConfiguration = ViewConfiguration.get(
+                            mTextView.getContext());
+
                     if (mGestureStayedInTapRegion) {
                         final float deltaX = event.getX() - mDownPositionX;
                         final float deltaY = event.getY() - mDownPositionY;
                         final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
-                        final ViewConfiguration viewConfiguration = ViewConfiguration.get(
-                                mTextView.getContext());
                         int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop();
 
                         if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) {
                             mGestureStayedInTapRegion = false;
                         }
                     }
+
+                    if (mStartHandle != null && mStartHandle.isShowing()) {
+                        // Don't do the drag if the handles are showing already.
+                        break;
+                    }
+
+                    if (mStartOffset != -1) {
+                        final int rawOffset = mTextView.getOffsetForPosition(event.getX(),
+                                event.getY());
+                        int offset = rawOffset;
+
+                        // We don't start "dragging" until the user is past the initial word that
+                        // gets selected on long press.
+                        int firstWordStart = getWordStart(mStartOffset);
+                        int firstWordEnd = getWordEnd(mStartOffset, false);
+                        if (offset > firstWordEnd || offset < firstWordStart) {
+
+                            // Basically the goal in the below code is to have the highlight be
+                            // offset so that your finger isn't covering the end point.
+                            int fingerOffset = viewConfiguration.getScaledTouchSlop();
+                            float mx = event.getX();
+                            float my = event.getY();
+                            if (mx > fingerOffset) mx -= fingerOffset;
+                            if (my > fingerOffset) my -= fingerOffset;
+                            offset = mTextView.getOffsetForPosition(mx, my);
+
+                            // Perform the check for closeness at edge of view, if we're very close
+                            // don't adjust the offset to be in front of the finger - otherwise the
+                            // user can't select words at the edge.
+                            if (mTextView.getWidth() - fingerOffset > mx) {
+                                // We're going by word, so we need to make sure that the offset
+                                // that we get is within this, so we'll get the previous boundary.
+                                final WordIterator wordIterator = getWordIteratorWithText();
+
+                                final int precedingOffset = wordIterator.preceding(offset);
+                                if (mStartOffset < offset) {
+                                    // Expanding with bottom handle, in this case the selection end
+                                    // is before the finger.
+                                    offset = Math.max(precedingOffset - 1, 0);
+                                } else {
+                                    // Expand with the start handle, in this case the selection
+                                    // start is before the finger.
+                                    if (precedingOffset == WordIterator.DONE) {
+                                        offset = 0;
+                                    } else {
+                                        offset = wordIterator.preceding(precedingOffset);
+                                    }
+                                }
+                            }
+                            if (offset == WordIterator.DONE)
+                                offset = rawOffset;
+
+                            // Need to adjust start offset based on direction of movement.
+                            int newStart = mStartOffset < offset ? getWordStart(mStartOffset)
+                                    : getWordEnd(mStartOffset, true);
+                            Selection.setSelection((Spannable) mTextView.getText(), newStart,
+                                    offset);
+                        }
+                    }
                     break;
 
                 case MotionEvent.ACTION_UP:
                     mPreviousTapUpTime = SystemClock.uptimeMillis();
+                    if (mDragAcceleratorActive) {
+                        // No longer dragging to select text, let the parent intercept events.
+                        mTextView.getParent().requestDisallowInterceptTouchEvent(false);
+
+                        show();
+                        int startOffset = mTextView.getSelectionStart();
+                        int endOffset = mTextView.getSelectionEnd();
+
+                        // Since we don't let drag handles pass once they're visible, we need to
+                        // make sure the start / end locations are correct because the user *can*
+                        // switch directions during the initial drag.
+                        if (endOffset < startOffset) {
+                            int tmp = endOffset;
+                            endOffset = startOffset;
+                            startOffset = tmp;
+
+                            // Also update the selection with the right offsets in this case.
+                            Selection.setSelection((Spannable) mTextView.getText(),
+                                    startOffset, endOffset);
+                        }
+
+                        // Need to do this to display the handles.
+                        mStartHandle.showAtLocation(startOffset);
+                        mEndHandle.showAtLocation(endOffset);
+
+                        // No longer the first dragging motion, reset.
+                        mDragAcceleratorActive = false;
+                        mStartOffset = -1;
+                    }
                     break;
             }
         }
@@ -3964,6 +4357,8 @@
 
         public void resetTouchOffsets() {
             mMinTouchOffset = mMaxTouchOffset = -1;
+            mStartOffset = -1;
+            mDragAcceleratorActive = false;
         }
 
         /**
@@ -3973,6 +4368,13 @@
             return mStartHandle != null && mStartHandle.isDragging();
         }
 
+        /**
+         * @return true if the user is selecting text using the drag accelerator.
+         */
+        public boolean isDragAcceleratorActive() {
+            return mDragAcceleratorActive;
+        }
+
         public void onTouchModeChanged(boolean isInTouchMode) {
             if (!isInTouchMode) {
                 hide();
@@ -4157,103 +4559,208 @@
         int mChangedStart, mChangedEnd, mChangedDelta;
     }
 
+    /**
+     * @return True iff (start, end) is a valid range within the text.
+     */
+    private static boolean isValidRange(CharSequence text, int start, int end) {
+        return 0 <= start && start <= end && end <= text.length();
+    }
+
+    /**
+     * An InputFilter that monitors text input to maintain undo history. It does not modify the
+     * text being typed (and hence always returns null from the filter() method).
+     */
     public static class UndoInputFilter implements InputFilter {
-        final Editor mEditor;
+        private final Editor mEditor;
+
+        // Whether the current filter pass is directly caused by an end-user text edit.
+        private boolean mIsUserEdit;
+
+        // Whether this is the first pass through the filter for a given end-user text edit.
+        private boolean mFirstFilterPass;
 
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
         }
 
+        /**
+         * Signals that a user-triggered edit is starting.
+         */
+        public void beginBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "beginBatchEdit");
+            mIsUserEdit = true;
+            mFirstFilterPass = true;
+        }
+
+        public void endBatchEdit() {
+            if (DEBUG_UNDO) Log.d(TAG, "endBatchEdit");
+            mIsUserEdit = false;
+        }
+
         @Override
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
             if (DEBUG_UNDO) {
-                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ")");
-                Log.d(TAG, "filter: dest=" + dest + " (" + dstart + "-" + dend + ")");
+                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ") " +
+                        "dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
-            final UndoManager um = mEditor.mUndoManager;
-            if (um.isInUndo()) {
-                if (DEBUG_UNDO) Log.d(TAG, "*** skipping, currently performing undo/redo");
+
+            // Check to see if this edit should be tracked for undo.
+            if (!canUndoEdit(source, start, end, dest, dstart, dend)) {
                 return null;
             }
 
+            // An application may install a TextWatcher to provide additional modifications after
+            // the initial input filters run (e.g. a credit card formatter that adds spaces to a
+            // string). This results in multiple filter() calls for what the user considers to be
+            // a single operation. Always undo the whole set of changes in one step.
+            final boolean forceMerge = !mFirstFilterPass;
+            mFirstFilterPass = false;
+
+            // Build a new operation with all the information from this edit.
+            EditOperation edit = new EditOperation(mEditor, forceMerge,
+                    source, start, end, dest, dstart, dend);
+
+            // Fetch the last edit operation and attempt to merge in the new edit.
+            final UndoManager um = mEditor.mUndoManager;
             um.beginUpdate("Edit text");
-            TextModifyOperation op = um.getLastOperation(
-                    TextModifyOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
-            if (op != null) {
-                if (DEBUG_UNDO) Log.d(TAG, "Last op: range=(" + op.mRangeStart + "-" + op.mRangeEnd
-                        + "), oldText=" + op.mOldText);
-                // See if we can continue modifying this operation.
-                if (op.mOldText == null) {
-                    // The current operation is an add...  are we adding more?  We are adding
-                    // more if we are either appending new text to the end of the last edit or
-                    // completely replacing some or all of the last edit.
-                    if (start < end && ((dstart >= op.mRangeStart && dend <= op.mRangeEnd)
-                            || (dstart == op.mRangeEnd && dend == op.mRangeEnd))) {
-                        op.mRangeEnd = dstart + (end-start);
-                        um.endUpdate();
-                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, mRangeEnd="
-                                + op.mRangeEnd);
-                        return null;
-                    }
-                } else {
-                    // The current operation is a delete...  can we delete more?
-                    if (start == end && dend == op.mRangeStart-1) {
-                        SpannableStringBuilder str;
-                        if (op.mOldText instanceof SpannableString) {
-                            str = (SpannableStringBuilder)op.mOldText;
-                        } else {
-                            str = new SpannableStringBuilder(op.mOldText);
-                        }
-                        str.insert(0, dest, dstart, dend);
-                        op.mRangeStart = dstart;
-                        op.mOldText = str;
-                        um.endUpdate();
-                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, range=("
-                                + op.mRangeStart + "-" + op.mRangeEnd
-                                + "), oldText=" + op.mOldText);
-                        return null;
-                    }
-                }
-
-                // Couldn't add to the current undo operation, need to start a new
-                // undo state for a new undo operation.
-                um.commitState(null);
-                um.setUndoLabel("Edit text");
-            }
-
-            // Create a new undo state reflecting the operation being performed.
-            op = new TextModifyOperation(mEditor.mUndoOwner);
-            op.mRangeStart = dstart;
-            if (start < end) {
-                op.mRangeEnd = dstart + (end-start);
+            EditOperation lastEdit = um.getLastOperation(
+                  EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
+            if (lastEdit == null) {
+                // Add this as the first edit.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            } else if (!mIsUserEdit) {
+                // An application directly modified the Editable outside of a text edit. Treat this
+                // as a new change and don't attempt to merge.
+                if (DEBUG_UNDO) Log.d(TAG, "non-user edit, new op " + edit);
+                um.commitState(mEditor.mUndoOwner);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            } else if (lastEdit.mergeWith(edit)) {
+                // Merge succeeded, nothing else to do.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
             } else {
-                op.mRangeEnd = dstart;
+                // Could not merge with the last edit, so commit the last edit and add this edit.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: merge failed, adding " + edit);
+                um.commitState(mEditor.mUndoOwner);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
             }
-            if (dstart < dend) {
-                op.mOldText = dest.subSequence(dstart, dend);
-            }
-            if (DEBUG_UNDO) Log.d(TAG, "*** adding new op, range=(" + op.mRangeStart
-                    + "-" + op.mRangeEnd + "), oldText=" + op.mOldText);
-            um.addOperation(op, UndoManager.MERGE_MODE_NONE);
             um.endUpdate();
-            return null;
+            return null;  // Text not changed.
+        }
+
+        private boolean canUndoEdit(CharSequence source, int start, int end,
+                Spanned dest, int dstart, int dend) {
+            if (!mEditor.mAllowUndo) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: undo is disabled");
+                return false;
+            }
+
+            if (mEditor.mUndoManager.isInUndo()) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+                return false;
+            }
+
+            // Text filters run before input operations are applied. However, some input operations
+            // are invalid and will throw exceptions when applied. This is common in tests. Don't
+            // attempt to undo invalid operations.
+            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
+                return false;
+            }
+
+            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
+            // on an input field. Skip no-op changes.
+            if (start == end && dstart == dend) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
+                return false;
+            }
+
+            return true;
         }
     }
 
-    public static class TextModifyOperation extends UndoOperation<TextView> {
-        int mRangeStart, mRangeEnd;
-        CharSequence mOldText;
+    /**
+     * An operation to undo a single "edit" to a text view.
+     */
+    public static class EditOperation extends UndoOperation<Editor> {
+        private static final int TYPE_INSERT = 0;
+        private static final int TYPE_DELETE = 1;
+        private static final int TYPE_REPLACE = 2;
 
-        public TextModifyOperation(UndoOwner owner) {
-            super(owner);
+        private int mType;
+        private boolean mForceMerge;
+        private String mOldText;
+        private int mOldTextStart;
+        private String mNewText;
+        private int mNewTextStart;
+
+        private int mOldCursorPos;
+        private int mNewCursorPos;
+
+        /**
+         * Constructs an edit operation from a text input operation that replaces the range
+         * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
+         * If forceMerge is true then always forcibly merge this operation with any previous one.
+         */
+        public EditOperation(Editor editor, boolean forceMerge,
+                CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+            super(editor.mUndoOwner);
+            mForceMerge = forceMerge;
+
+            mOldText = dest.subSequence(dstart, dend).toString();
+            mNewText = source.subSequence(start, end).toString();
+
+            // Determine the type of the edit and store where it occurred. Avoid storing
+            // irrevelant data (e.g. mNewTextStart for a delete) because that makes the
+            // merging logic more complex (e.g. merging deletes could lead to mNewTextStart being
+            // outside the bounds of the final text).
+            if (mNewText.length() > 0 && mOldText.length() == 0) {
+                mType = TYPE_INSERT;
+                mNewTextStart = dstart;
+            } else if (mNewText.length() == 0 && mOldText.length() > 0) {
+                mType = TYPE_DELETE;
+                mOldTextStart = dstart;
+            } else {
+                mType = TYPE_REPLACE;
+                mOldTextStart = mNewTextStart = dstart;
+            }
+
+            // Store cursor data.
+            mOldCursorPos = editor.mTextView.getSelectionStart();
+            mNewCursorPos = dstart + (end - start);
         }
 
-        public TextModifyOperation(Parcel src, ClassLoader loader) {
+        public EditOperation(Parcel src, ClassLoader loader) {
             super(src, loader);
-            mRangeStart = src.readInt();
-            mRangeEnd = src.readInt();
-            mOldText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+            mType = src.readInt();
+            mForceMerge = src.readInt() != 0;
+            mOldText = src.readString();
+            mOldTextStart = src.readInt();
+            mNewText = src.readString();
+            mNewTextStart = src.readInt();
+            mOldCursorPos = src.readInt();
+            mNewCursorPos = src.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mType);
+            dest.writeInt(mForceMerge ? 1 : 0);
+            dest.writeString(mOldText);
+            dest.writeInt(mOldTextStart);
+            dest.writeString(mNewText);
+            dest.writeInt(mNewTextStart);
+            dest.writeInt(mOldCursorPos);
+            dest.writeInt(mNewCursorPos);
+        }
+
+        private int getNewTextEnd() {
+            return mNewTextStart + mNewText.length();
+        }
+
+        private int getOldTextEnd() {
+            return mOldTextStart + mOldText.length();
         }
 
         @Override
@@ -4262,59 +4769,185 @@
 
         @Override
         public void undo() {
-            swapText();
+            if (DEBUG_UNDO) Log.d(TAG, "undo");
+            // Remove the new text and insert the old.
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
         }
 
         @Override
         public void redo() {
-            swapText();
+            if (DEBUG_UNDO) Log.d(TAG, "redo");
+            // Remove the old text and insert the new.
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            modifyText(text, mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart,
+                    mNewCursorPos);
         }
 
-        private void swapText() {
-            // Both undo and redo involves swapping the contents of the range
-            // in the text view with our local text.
-            TextView tv = getOwnerData();
-            Editable editable = (Editable)tv.getText();
-            CharSequence curText;
-            if (mRangeStart >= mRangeEnd) {
-                curText = null;
-            } else {
-                curText = editable.subSequence(mRangeStart, mRangeEnd);
-            }
+        /**
+         * Attempts to merge this existing operation with a new edit.
+         * @param edit The new edit operation.
+         * @return If the merge succeeded, returns true. Otherwise returns false and leaves this
+         * object unchanged.
+         */
+        private boolean mergeWith(EditOperation edit) {
             if (DEBUG_UNDO) {
-                Log.d(TAG, "Swap: range=(" + mRangeStart + "-" + mRangeEnd
-                        + "), oldText=" + mOldText);
-                Log.d(TAG, "Swap: curText=" + curText);
+                Log.d(TAG, "mergeWith old " + this);
+                Log.d(TAG, "mergeWith new " + edit);
             }
-            if (mOldText == null) {
-                editable.delete(mRangeStart, mRangeEnd);
-                mRangeEnd = mRangeStart;
-            } else {
-                editable.replace(mRangeStart, mRangeEnd, mOldText);
-                mRangeEnd = mRangeStart + mOldText.length();
+            if (edit.mForceMerge) {
+                forceMergeWith(edit);
+                return true;
             }
-            mOldText = curText;
+            switch (mType) {
+                case TYPE_INSERT:
+                    return mergeInsertWith(edit);
+                case TYPE_DELETE:
+                    return mergeDeleteWith(edit);
+                case TYPE_REPLACE:
+                    return mergeReplaceWith(edit);
+                default:
+                    return false;
+            }
+        }
+
+        private boolean mergeInsertWith(EditOperation edit) {
+            // Only merge continuous insertions.
+            if (edit.mType != TYPE_INSERT) {
+                return false;
+            }
+            // Only merge insertions that are contiguous.
+            if (getNewTextEnd() != edit.mNewTextStart) {
+                return false;
+            }
+            mNewText += edit.mNewText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        // TODO: Support forward delete.
+        private boolean mergeDeleteWith(EditOperation edit) {
+            // Only merge continuous deletes.
+            if (edit.mType != TYPE_DELETE) {
+                return false;
+            }
+            // Only merge deletions that are contiguous.
+            if (mOldTextStart != edit.getOldTextEnd()) {
+                return false;
+            }
+            mOldTextStart = edit.mOldTextStart;
+            mOldText = edit.mOldText + mOldText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        private boolean mergeReplaceWith(EditOperation edit) {
+            // Replacements can merge only with adjacent inserts.
+            if (edit.mType != TYPE_INSERT || getNewTextEnd() != edit.mNewTextStart) {
+                return false;
+            }
+            mOldText += edit.mOldText;
+            mNewText += edit.mNewText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        /**
+         * Forcibly creates a single merged edit operation by simulating the entire text
+         * contents being replaced.
+         */
+        private void forceMergeWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
+            Editor editor = getOwnerData();
+
+            // Copy the text of the current field.
+            // NOTE: Using StringBuilder instead of SpannableStringBuilder would be somewhat faster,
+            // but would require two parallel implementations of modifyText() because Editable and
+            // StringBuilder do not share an interface for replace/delete/insert.
+            Editable editable = (Editable) editor.mTextView.getText();
+            Editable originalText = new SpannableStringBuilder(editable.toString());
+
+            // Roll back the last operation.
+            modifyText(originalText, mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart,
+                    mOldCursorPos);
+
+            // Clone the text again and apply the new operation.
+            Editable finalText = new SpannableStringBuilder(editable.toString());
+            modifyText(finalText, edit.mOldTextStart, edit.getOldTextEnd(), edit.mNewText,
+                    edit.mNewTextStart, edit.mNewCursorPos);
+
+            // Convert this operation into a non-mergeable replacement of the entire string.
+            mType = TYPE_REPLACE;
+            mNewText = finalText.toString();
+            mNewTextStart = 0;
+            mOldText = originalText.toString();
+            mOldTextStart = 0;
+            mNewCursorPos = edit.mNewCursorPos;
+            // mOldCursorPos is unchanged.
+        }
+
+        private static void modifyText(Editable text, int deleteFrom, int deleteTo,
+                CharSequence newText, int newTextInsertAt, int newCursorPos) {
+            // Apply the edit if it is still valid.
+            if (isValidRange(text, deleteFrom, deleteTo) &&
+                    newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
+                if (deleteFrom != deleteTo) {
+                    text.delete(deleteFrom, deleteTo);
+                }
+                if (newText.length() != 0) {
+                    text.insert(newTextInsertAt, newText);
+                }
+            }
+            // Restore the cursor position. If there wasn't an old cursor (newCursorPos == -1) then
+            // don't explicitly set it and rely on SpannableStringBuilder to position it.
+            // TODO: Select all the text that was undone.
+            if (0 <= newCursorPos && newCursorPos <= text.length()) {
+                Selection.setSelection(text, newCursorPos);
+            }
+        }
+
+        private String getTypeString() {
+            switch (mType) {
+                case TYPE_INSERT:
+                    return "insert";
+                case TYPE_DELETE:
+                    return "delete";
+                case TYPE_REPLACE:
+                    return "replace";
+                default:
+                    return "";
+            }
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mRangeStart);
-            dest.writeInt(mRangeEnd);
-            TextUtils.writeToParcel(mOldText, dest, flags);
+        public String toString() {
+            return "[mType=" + getTypeString() + ", " +
+                    "mOldText=" + mOldText + ", " +
+                    "mOldTextStart=" + mOldTextStart + ", " +
+                    "mNewText=" + mNewText + ", " +
+                    "mNewTextStart=" + mNewTextStart + ", " +
+                    "mOldCursorPos=" + mOldCursorPos + ", " +
+                    "mNewCursorPos=" + mNewCursorPos + "]";
         }
 
-        public static final Parcelable.ClassLoaderCreator<TextModifyOperation> CREATOR
-                = new Parcelable.ClassLoaderCreator<TextModifyOperation>() {
-            public TextModifyOperation createFromParcel(Parcel in) {
-                return new TextModifyOperation(in, null);
+        public static final Parcelable.ClassLoaderCreator<EditOperation> CREATOR
+                = new Parcelable.ClassLoaderCreator<EditOperation>() {
+            @Override
+            public EditOperation createFromParcel(Parcel in) {
+                return new EditOperation(in, null);
             }
 
-            public TextModifyOperation createFromParcel(Parcel in, ClassLoader loader) {
-                return new TextModifyOperation(in, loader);
+            @Override
+            public EditOperation createFromParcel(Parcel in, ClassLoader loader) {
+                return new EditOperation(in, loader);
             }
 
-            public TextModifyOperation[] newArray(int size) {
-                return new TextModifyOperation[size];
+            @Override
+            public EditOperation[] newArray(int size) {
+                return new EditOperation[size];
             }
         };
     }
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 70089e0..fac36c5 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -30,8 +30,6 @@
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ExpandableListConnector.PositionMetadata;
 
 import java.util.ArrayList;
@@ -1342,14 +1340,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ExpandableListView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ExpandableListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ExpandableListView.class.getName();
     }
 }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index d974c29..f6d198b 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -29,12 +30,9 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.Gravity;
-import android.view.RemotableViewMethod;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
@@ -103,15 +101,16 @@
         super(context);
     }
     
-    public FrameLayout(Context context, AttributeSet attrs) {
+    public FrameLayout(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    public FrameLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public FrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public FrameLayout(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
@@ -203,11 +202,15 @@
     }
 
     @Override
-    @RemotableViewMethod
-    public void setVisibility(@Visibility int visibility) {
-        super.setVisibility(visibility);
-        if (mForeground != null) {
-            mForeground.setVisible(visibility == VISIBLE, false);
+    protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        final Drawable dr = mForeground;
+        if (dr != null) {
+            final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
+            if (visible != dr.isVisible()) {
+                dr.setVisible(visible, false);
+            }
         }
     }
 
@@ -703,17 +706,9 @@
         return new LayoutParams(p);
     }
 
-
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(FrameLayout.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(FrameLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return FrameLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index f7c839f..af5a8bf 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -33,7 +33,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Transformation;
 
@@ -1374,15 +1373,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(Gallery.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Gallery.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(Gallery.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setScrollable(mItemCount > 1);
         if (isEnabled()) {
             if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
@@ -1394,9 +1392,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         switch (action) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 161ae7e..6cc4bda 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -31,8 +31,6 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 import com.android.internal.R;
 
@@ -143,7 +141,9 @@
  * view was alone in a column, that column would itself collapse to zero width if and only if
  * no gravity was defined on the view. If gravity was defined, then the gone-marked
  * view has no effect on the layout and the container should be laid out as if the view
- * had never been added to it.
+ * had never been added to it. GONE views are taken to have zero weight during excess space
+ * distribution.
+ * <p>
  * These statements apply equally to rows as well as columns, and to groups of rows or columns.
  *
  * <p>
@@ -1012,12 +1012,10 @@
             LayoutParams lp = getLayoutParams(c);
             if (firstPass) {
                 measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
-                mHorizontalAxis.recordOriginalMeasurement(i);
-                mVerticalAxis.recordOriginalMeasurement(i);
             } else {
                 boolean horizontal = (mOrientation == HORIZONTAL);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                if (spec.alignment == FILL) {
+                if (spec.getAbsoluteAlignment(horizontal) == FILL) {
                     Interval span = spec.span;
                     Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
                     int[] locations = axis.getLocations();
@@ -1093,11 +1091,6 @@
         invalidateValues();
     }
 
-    final Alignment getAlignment(Alignment alignment, boolean horizontal) {
-        return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
-                (horizontal ? START : BASELINE);
-    }
-
     // Layout container
 
     /**
@@ -1152,8 +1145,8 @@
             int pWidth = getMeasurement(c, true);
             int pHeight = getMeasurement(c, false);
 
-            Alignment hAlign = getAlignment(columnSpec.alignment, true);
-            Alignment vAlign = getAlignment(rowSpec.alignment, false);
+            Alignment hAlign = columnSpec.getAbsoluteAlignment(true);
+            Alignment vAlign = rowSpec.getAbsoluteAlignment(false);
 
             Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
             Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
@@ -1191,15 +1184,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(GridLayout.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(GridLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return GridLayout.class.getName();
     }
 
     // Inner classes
@@ -1243,7 +1229,6 @@
 
         public boolean hasWeights;
         public boolean hasWeightsValid = false;
-        public int[] originalMeasurements;
         public int[] deltas;
 
         boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
@@ -1306,7 +1291,7 @@
                 // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                Bounds bounds = getAlignment(spec.alignment, horizontal).getBounds();
+                Bounds bounds = spec.getAbsoluteAlignment(horizontal).getBounds();
                 assoc.put(spec, bounds);
             }
             return assoc.pack();
@@ -1322,9 +1307,8 @@
                 // we must include views that are GONE here, see introductory javadoc
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
-                int size = (spec.weight == 0) ?
-                        getMeasurementIncludingMargin(c, horizontal) :
-                        getOriginalMeasurements()[i] + getDeltas()[i];
+                int size = getMeasurementIncludingMargin(c, horizontal) +
+                        ((spec.weight == 0) ? 0 : getDeltas()[i]);
                 groupBounds.getValue(i).include(GridLayout.this, c, spec, this, size);
             }
         }
@@ -1712,7 +1696,11 @@
 
         private boolean computeHasWeights() {
             for (int i = 0, N = getChildCount(); i < N; i++) {
-                LayoutParams lp = getLayoutParams(getChildAt(i));
+                final View child = getChildAt(i);
+                if (child.getVisibility() == View.GONE) {
+                    continue;
+                }
+                LayoutParams lp = getLayoutParams(child);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 if (spec.weight != 0) {
                     return true;
@@ -1729,19 +1717,6 @@
             return hasWeights;
         }
 
-        public int[] getOriginalMeasurements() {
-            if (originalMeasurements == null) {
-                originalMeasurements = new int[getChildCount()];
-            }
-            return originalMeasurements;
-        }
-
-        private void recordOriginalMeasurement(int i) {
-            if (hasWeights()) {
-                getOriginalMeasurements()[i] = getMeasurementIncludingMargin(getChildAt(i), horizontal);
-            }
-        }
-
         public int[] getDeltas() {
             if (deltas == null) {
                 deltas = new int[getChildCount()];
@@ -1752,7 +1727,10 @@
         private void shareOutDelta(int totalDelta, float totalWeight) {
             Arrays.fill(deltas, 0);
             for (int i = 0, N = getChildCount(); i < N; i++) {
-                View c = getChildAt(i);
+                final View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) {
+                    continue;
+                }
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 float weight = spec.weight;
@@ -1805,6 +1783,9 @@
             float totalWeight = 0f;
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
+                if (c.getVisibility() == View.GONE) {
+                    continue;
+                }
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 totalWeight += spec.weight;
@@ -1900,7 +1881,6 @@
 
             locations = null;
 
-            originalMeasurements = null;
             deltas = null;
             hasWeightsValid = false;
 
@@ -2020,7 +2000,6 @@
                 R.styleable.ViewGroup_MarginLayout_layout_marginRight;
         private static final int BOTTOM_MARGIN =
                 R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
-
         private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
         private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
         private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
@@ -2414,7 +2393,7 @@
         protected final void include(GridLayout gl, View c, Spec spec, Axis axis, int size) {
             this.flexibility &= spec.getFlexibility();
             boolean horizontal = axis.horizontal;
-            Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
+            Alignment alignment = spec.getAbsoluteAlignment(axis.horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
             int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
             include(before, size - before);
@@ -2565,6 +2544,16 @@
             this(startDefined, new Interval(start, start + size), alignment, weight);
         }
 
+        private Alignment getAbsoluteAlignment(boolean horizontal) {
+            if (alignment != UNDEFINED_ALIGNMENT) {
+                return alignment;
+            }
+            if (weight == 0f) {
+                return horizontal ? START : BASELINE;
+            }
+            return FILL;
+        }
+
         final Spec copyWriteSpan(Interval span) {
             return new Spec(startDefined, span, alignment, weight);
         }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index efd6fc0..c6e3dc8 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -31,7 +31,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
@@ -2342,15 +2341,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(GridView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return GridView.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(GridView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
         final int columnsCount = getNumColumns();
         final int rowsCount = getCount() / columnsCount;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1b93b97..324c2aa 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -762,9 +761,10 @@
         awakenScrollBars();
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         switch (action) {
@@ -795,9 +795,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(HorizontalScrollView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return HorizontalScrollView.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         final int scrollRange = getScrollRange();
         if (scrollRange > 0) {
             info.setScrollable(true);
@@ -810,10 +815,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(HorizontalScrollView.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setScrollable(getScrollRange() > 0);
         event.setScrollX(mScrollX);
         event.setScrollY(mScrollY);
diff --git a/core/java/android/widget/ImageButton.java b/core/java/android/widget/ImageButton.java
index 3a20628..332b158 100644
--- a/core/java/android/widget/ImageButton.java
+++ b/core/java/android/widget/ImageButton.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 /**
@@ -93,14 +91,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ImageButton.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ImageButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/ImageSwitcher.java b/core/java/android/widget/ImageSwitcher.java
index c048970..08f21a2 100644
--- a/core/java/android/widget/ImageSwitcher.java
+++ b/core/java/android/widget/ImageSwitcher.java
@@ -16,13 +16,11 @@
 
 package android.widget;
 
+import android.annotation.DrawableRes;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 
 public class ImageSwitcher extends ViewSwitcher
 {
@@ -35,7 +33,7 @@
         super(context, attrs);
     }
 
-    public void setImageResource(int resid)
+    public void setImageResource(@DrawableRes int resid)
     {
         ImageView image = (ImageView)this.getNextView();
         image.setImageResource(resid);
@@ -57,14 +55,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ImageSwitcher.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ImageSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageSwitcher.class.getName();
     }
 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index c68bfca..041796b 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -43,7 +44,6 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
@@ -127,15 +127,16 @@
         initImageView();
     }
 
-    public ImageView(Context context, AttributeSet attrs) {
+    public ImageView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public ImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         initImageView();
@@ -239,9 +240,10 @@
         return (getBackground() != null && getBackground().getCurrent() != null);
     }
 
+    /** @hide */
     @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEventInternal(event);
         CharSequence contentDescription = getContentDescription();
         if (!TextUtils.isEmpty(contentDescription)) {
             event.getText().add(contentDescription);
@@ -385,7 +387,7 @@
      * @attr ref android.R.styleable#ImageView_src
      */
     @android.view.RemotableViewMethod
-    public void setImageResource(int resId) {
+    public void setImageResource(@DrawableRes int resId) {
         // The resource configuration may have changed, so we should always
         // try to load the resource even if the resId hasn't changed.
         final int oldWidth = mDrawableWidth;
@@ -1419,14 +1421,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ImageView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ImageView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ImageView.class.getName();
     }
 }
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 6476cdc..da15302 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
@@ -28,8 +29,6 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import java.lang.annotation.Retention;
@@ -188,11 +187,11 @@
         this(context, null);
     }
 
-    public LinearLayout(Context context, AttributeSet attrs) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
     
-    public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+    public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -1807,15 +1806,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(LinearLayout.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(LinearLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return LinearLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2e9858c..ee2c055 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -21,6 +21,7 @@
 import com.android.internal.util.Predicate;
 import com.google.android.collect.Lists;
 
+import android.annotation.IdRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -40,7 +41,6 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
@@ -2420,10 +2420,15 @@
                         (ViewGroup) selectedView, currentFocus, direction);
                 if (nextFocus != null) {
                     // do the math to get interesting rect in next focus' coordinates
-                    currentFocus.getFocusedRect(mTempRect);
-                    offsetDescendantRectToMyCoords(currentFocus, mTempRect);
-                    offsetRectIntoDescendantCoords(nextFocus, mTempRect);
-                    if (nextFocus.requestFocus(direction, mTempRect)) {
+                    Rect focusedRect = mTempRect;
+                    if (currentFocus != null) {
+                        currentFocus.getFocusedRect(focusedRect);
+                        offsetDescendantRectToMyCoords(currentFocus, focusedRect);
+                        offsetRectIntoDescendantCoords(nextFocus, focusedRect);
+                    } else {
+                        focusedRect = null;
+                    }
+                    if (nextFocus.requestFocus(direction, focusedRect)) {
                         return true;
                     }
                 }
@@ -2556,8 +2561,10 @@
         if (mItemsCanFocus && (focusResult == null)
                 && selectedView != null && selectedView.hasFocus()) {
             final View focused = selectedView.findFocus();
-            if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) {
-                focused.clearFocus();
+            if (focused != null) {
+                if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) {
+                    focused.clearFocus();
+                }
             }
         }
 
@@ -3623,7 +3630,7 @@
      * First look in our children, then in any header and footer views that may be scrolled off.
      */
     @Override
-    protected View findViewTraversal(int id) {
+    protected View findViewTraversal(@IdRes int id) {
         View v;
         v = super.findViewTraversal(id);
         if (v == null) {
@@ -3872,15 +3879,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ListView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ListView.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ListView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
         final int rowsCount = getCount();
         final int selectionMode = getSelectionModeForAccessibility();
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index f1aaa4d..2375089 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -28,16 +28,13 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.PhoneWindow;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
-import com.android.internal.policy.PolicyManager;
-
 import java.util.Formatter;
 import java.util.Locale;
 
@@ -128,7 +125,7 @@
 
     private void initFloatingWindow() {
         mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        mWindow = PolicyManager.makeNewWindow(mContext);
+        mWindow = new PhoneWindow(mContext);
         mWindow.setWindowManager(mWindowManager, null, null);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mDecor = mWindow.getDecorView();
@@ -626,15 +623,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(MediaController.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(MediaController.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return MediaController.class.getName();
     }
 
     private View.OnClickListener mRewListener = new View.OnClickListener() {
diff --git a/core/java/android/widget/MultiAutoCompleteTextView.java b/core/java/android/widget/MultiAutoCompleteTextView.java
index cbd01b0..2152e43 100644
--- a/core/java/android/widget/MultiAutoCompleteTextView.java
+++ b/core/java/android/widget/MultiAutoCompleteTextView.java
@@ -23,8 +23,6 @@
 import android.text.TextUtils;
 import android.text.method.QwertyKeyListener;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * An editable text view, extending {@link AutoCompleteTextView}, that
@@ -203,15 +201,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(MultiAutoCompleteTextView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(MultiAutoCompleteTextView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return MultiAutoCompleteTextView.class.getName();
     }
 
     public static interface Tokenizer {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index ee17b78..16dc26d 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1558,9 +1558,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setClassName(NumberPicker.class.getName());
         event.setScrollable(true);
         event.setScrollY((mMinValue + mValue) * mSelectorElementHeight);
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index a40d4f8..451e493 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.hardware.SensorManager;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
@@ -181,9 +180,7 @@
      * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
      */
     public float getCurrVelocity() {
-        float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity;
-        squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity;
-        return FloatMath.sqrt(squaredNorm);
+        return (float) Math.hypot(mScrollerX.mCurrVelocity, mScrollerY.mCurrVelocity);
     }
 
     /**
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 2708398..1507dfb 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -22,6 +22,7 @@
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.SubMenuBuilder;
 
+import android.annotation.MenuRes;
 import android.content.Context;
 import android.view.Gravity;
 import android.view.Menu;
@@ -115,6 +116,29 @@
     }
 
     /**
+     * Sets the gravity used to align the popup window to its anchor view.
+     * <p>
+     * If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown.
+     *
+     * @param gravity the gravity used to align the popup window
+     *
+     * @see #getGravity()
+     */
+    public void setGravity(int gravity) {
+        mPopup.setGravity(gravity);
+    }
+
+    /**
+     * @return the gravity used to align the popup window to its anchor view
+     *
+     * @see #setGravity(int)
+     */
+    public int getGravity() {
+        return mPopup.getGravity();
+    }
+
+    /**
      * Returns an {@link OnTouchListener} that can be added to the anchor view
      * to implement drag-to-open behavior.
      * <p>
@@ -182,7 +206,7 @@
      * popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
      * @param menuRes Menu resource to inflate
      */
-    public void inflate(int menuRes) {
+    public void inflate(@MenuRes int menuRes) {
         getMenuInflater().inflate(menuRes, mMenu);
     }
 
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 396c0b9..f676254 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,17 +18,22 @@
 
 import com.android.internal.R;
 
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.os.IBinder;
+import android.transition.Transition;
+import android.transition.Transition.EpicenterCallback;
+import android.transition.Transition.TransitionListener;
+import android.transition.Transition.TransitionListenerAdapter;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -36,7 +41,9 @@
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.ViewTreeObserver.OnScrollChangedListener;
 import android.view.WindowManager;
 
@@ -46,7 +53,7 @@
  * <p>A popup window that can be used to display an arbitrary view. The popup
  * window is a floating container that appears on top of the current
  * activity.</p>
- * 
+ *
  * @see android.widget.AutoCompleteTextView
  * @see android.widget.Spinner
  */
@@ -58,7 +65,7 @@
      * it doesn't.
      */
     public static final int INPUT_METHOD_FROM_FOCUSABLE = 0;
-    
+
     /**
      * Mode for {@link #setInputMethodMode(int)}: this popup always needs to
      * work with an input method, regardless of whether it is focusable.  This
@@ -66,7 +73,7 @@
      * the input method while it is shown.
      */
     public static final int INPUT_METHOD_NEEDED = 1;
-    
+
     /**
      * Mode for {@link #setInputMethodMode(int)}: this popup never needs to
      * work with an input method, regardless of whether it is focusable.  This
@@ -77,14 +84,30 @@
 
     private static final int DEFAULT_ANCHORED_GRAVITY = Gravity.TOP | Gravity.START;
 
+    /**
+     * Default animation style indicating that separate animations should be
+     * used for top/bottom anchoring states.
+     */
+    private static final int ANIMATION_STYLE_DEFAULT = -1;
+
+    private final int[] mDrawingLocation = new int[2];
+    private final int[] mScreenLocation = new int[2];
+    private final Rect mTempRect = new Rect();
+    private final Rect mAnchorBounds = new Rect();
+
     private Context mContext;
     private WindowManager mWindowManager;
-    
+
     private boolean mIsShowing;
+    private boolean mIsTransitioningToDismiss;
     private boolean mIsDropdown;
 
+    /** View that handles event dispatch and content transitions. */
+    private PopupDecorView mDecorView;
+
+    /** The contents of the popup. */
     private View mContentView;
-    private View mPopupView;
+
     private boolean mFocusable;
     private int mInputMethodMode = INPUT_METHOD_FROM_FOCUSABLE;
     private int mSoftInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
@@ -114,49 +137,67 @@
 
     private float mElevation;
 
-    private int[] mDrawingLocation = new int[2];
-    private int[] mScreenLocation = new int[2];
-    private Rect mTempRect = new Rect();
-    
     private Drawable mBackground;
     private Drawable mAboveAnchorBackgroundDrawable;
     private Drawable mBelowAnchorBackgroundDrawable;
 
-    // Temporary animation centers. Should be moved into window params?
-    private int mAnchorRelativeX;
-    private int mAnchorRelativeY;
+    private Transition mEnterTransition;
+    private Transition mExitTransition;
 
     private boolean mAboveAnchor;
     private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-    
+
     private OnDismissListener mOnDismissListener;
     private boolean mIgnoreCheekPress = false;
 
-    private int mAnimationStyle = -1;
-    
+    private int mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+
     private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
         com.android.internal.R.attr.state_above_anchor
     };
 
     private WeakReference<View> mAnchor;
 
-    private final OnScrollChangedListener mOnScrollChangedListener =
-        new OnScrollChangedListener() {
-            @Override
-            public void onScrollChanged() {
-                final View anchor = mAnchor != null ? mAnchor.get() : null;
-                if (anchor != null && mPopupView != null) {
-                    final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                            mPopupView.getLayoutParams();
-
-                    updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
-                            mAnchoredGravity));
-                    update(p.x, p.y, -1, -1, true);
-                }
+    private final EpicenterCallback mEpicenterCallback = new EpicenterCallback() {
+        @Override
+        public Rect onGetEpicenter(Transition transition) {
+            final View anchor = mAnchor != null ? mAnchor.get() : null;
+            final View decor = mDecorView;
+            if (anchor == null || decor == null) {
+                return null;
             }
-        };
 
-    private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
+            final Rect anchorBounds = mAnchorBounds;
+            final int[] anchorLocation = anchor.getLocationOnScreen();
+            final int[] popupLocation = mDecorView.getLocationOnScreen();
+
+            // Compute the position of the anchor relative to the popup.
+            anchorBounds.set(0, 0, anchor.getWidth(), anchor.getHeight());
+            anchorBounds.offset(anchorLocation[0] - popupLocation[0],
+                    anchorLocation[1] - popupLocation[1]);
+
+            return anchorBounds;
+        }
+    };
+
+    private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() {
+        @Override
+        public void onScrollChanged() {
+            final View anchor = mAnchor != null ? mAnchor.get() : null;
+            if (anchor != null && mDecorView != null) {
+                final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                        mDecorView.getLayoutParams();
+
+                updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+                        mAnchoredGravity));
+                update(p.x, p.y, -1, -1, true);
+            }
+        }
+    };
+
+    private int mAnchorXoff;
+    private int mAnchorYoff;
+    private int mAnchoredGravity;
     private boolean mOverlapAnchor;
 
     private boolean mPopupViewInitialLayoutDirectionInherited;
@@ -187,15 +228,15 @@
     public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
-    
+
     /**
      * <p>Create a new, empty, non focusable popup window of dimension (0,0).</p>
-     * 
+     *
      * <p>The popup does not provide a background.</p>
      */
     public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mContext = context;
-        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.PopupWindow, defStyleAttr, defStyleRes);
@@ -203,11 +244,34 @@
         mElevation = a.getDimension(R.styleable.PopupWindow_popupElevation, 0);
         mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
 
-        final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
-        mAnimationStyle = animStyle == R.style.Animation_PopupWindow ? -1 : animStyle;
+        // Preserve default behavior from Gingerbread. If the animation is
+        // undefined or explicitly specifies the Gingerbread animation style,
+        // use a sentinel value.
+        if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupAnimationStyle)) {
+            final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, 0);
+            if (animStyle == R.style.Animation_PopupWindow) {
+                mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+            } else {
+                mAnimationStyle = animStyle;
+            }
+        } else {
+            mAnimationStyle = ANIMATION_STYLE_DEFAULT;
+        }
+
+        final Transition enterTransition = getTransition(a.getResourceId(
+                R.styleable.PopupWindow_popupEnterTransition, 0));
+        final Transition exitTransition;
+        if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupExitTransition)) {
+            exitTransition = getTransition(a.getResourceId(
+                    R.styleable.PopupWindow_popupExitTransition, 0));
+        } else {
+            exitTransition = enterTransition == null ? null : enterTransition.clone();
+        }
 
         a.recycle();
 
+        setEnterTransition(enterTransition);
+        setExitTransition(exitTransition);
         setBackgroundDrawable(bg);
     }
 
@@ -288,6 +352,37 @@
         setFocusable(focusable);
     }
 
+    public void setEnterTransition(Transition enterTransition) {
+        mEnterTransition = enterTransition;
+
+        if (mEnterTransition != null) {
+            mEnterTransition.setEpicenterCallback(mEpicenterCallback);
+        }
+    }
+
+    public void setExitTransition(Transition exitTransition) {
+        mExitTransition = exitTransition;
+
+        if (mExitTransition != null) {
+            mExitTransition.setEpicenterCallback(mEpicenterCallback);
+        }
+    }
+
+    private Transition getTransition(int resId) {
+        if (resId != 0 && resId != R.transition.no_transition) {
+            final TransitionInflater inflater = TransitionInflater.from(mContext);
+            final Transition transition = inflater.inflateTransition(resId);
+            if (transition != null) {
+                final boolean isEmpty = transition instanceof TransitionSet
+                        && ((TransitionSet) transition).getTransitionCount() == 0;
+                if (!isEmpty) {
+                    return transition;
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      * Return the drawable used as the popup window's background.
      *
@@ -378,9 +473,9 @@
     }
 
     /**
-     * Set the flag on popup to ignore cheek press event; by default this flag
+     * Set the flag on popup to ignore cheek press events; by default this flag
      * is set to false
-     * which means the pop wont ignore cheek press dispatch events.
+     * which means the popup will not ignore cheek press dispatch events.
      *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
@@ -391,7 +486,7 @@
     public void setIgnoreCheekPress() {
         mIgnoreCheekPress = true;
     }
-    
+
 
     /**
      * <p>Change the animation style resource for this popup.</p>
@@ -403,13 +498,13 @@
      * @param animationStyle animation style to use when the popup appears
      *      and disappears.  Set to -1 for the default animation, 0 for no
      *      animation, or a resource identifier for an explicit animation.
-     *      
+     *
      * @see #update()
      */
     public void setAnimationStyle(int animationStyle) {
         mAnimationStyle = animationStyle;
     }
-    
+
     /**
      * <p>Return the view used as the content of the popup window.</p>
      *
@@ -493,7 +588,7 @@
      * @param focusable true if the popup should grab focus, false otherwise.
      *
      * @see #isFocusable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setFocusable(boolean focusable) {
@@ -502,23 +597,23 @@
 
     /**
      * Return the current value in {@link #setInputMethodMode(int)}.
-     * 
+     *
      * @see #setInputMethodMode(int)
      */
     public int getInputMethodMode() {
         return mInputMethodMode;
-        
+
     }
-    
+
     /**
      * Control how the popup operates with an input method: one of
      * {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
      * or {@link #INPUT_METHOD_NOT_NEEDED}.
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
-     * 
+     *
      * @see #getInputMethodMode()
      * @see #update()
      */
@@ -549,12 +644,12 @@
     public int getSoftInputMode() {
         return mSoftInputMode;
     }
-    
+
     /**
      * <p>Indicates whether the popup window receives touch events.</p>
-     * 
+     *
      * @return true if the popup is touchable, false otherwise
-     * 
+     *
      * @see #setTouchable(boolean)
      */
     public boolean isTouchable() {
@@ -573,7 +668,7 @@
      * @param touchable true if the popup should receive touch events, false otherwise
      *
      * @see #isTouchable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setTouchable(boolean touchable) {
@@ -583,9 +678,9 @@
     /**
      * <p>Indicates whether the popup window will be informed of touch events
      * outside of its window.</p>
-     * 
+     *
      * @return true if the popup is outside touchable, false otherwise
-     * 
+     *
      * @see #setOutsideTouchable(boolean)
      */
     public boolean isOutsideTouchable() {
@@ -606,7 +701,7 @@
      * touch events, false otherwise
      *
      * @see #isOutsideTouchable()
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #update()
      */
     public void setOutsideTouchable(boolean touchable) {
@@ -615,9 +710,9 @@
 
     /**
      * <p>Indicates whether clipping of the popup window is enabled.</p>
-     * 
+     *
      * @return true if the clipping is enabled, false otherwise
-     * 
+     *
      * @see #setClippingEnabled(boolean)
      */
     public boolean isClippingEnabled() {
@@ -628,13 +723,13 @@
      * <p>Allows the popup window to extend beyond the bounds of the screen. By default the
      * window is clipped to the screen boundaries. Setting this to false will allow windows to be
      * accurately positioned.</p>
-     * 
+     *
      * <p>If the popup is showing, calling this method will take effect only
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
      *
      * @param enabled false if the window should be allowed to extend outside of the screen
-     * @see #isShowing() 
+     * @see #isShowing()
      * @see #isClippingEnabled()
      * @see #update()
      */
@@ -662,12 +757,12 @@
     void setAllowScrollingAnchorParent(boolean enabled) {
         mAllowScrollingAnchorParent = enabled;
     }
-    
+
     /**
      * <p>Indicates whether the popup window supports splitting touches.</p>
-     * 
+     *
      * @return true if the touch splitting is enabled, false otherwise
-     * 
+     *
      * @see #setSplitTouchEnabled(boolean)
      */
     public boolean isSplitTouchEnabled() {
@@ -796,7 +891,7 @@
      * window manager by the popup.  By default these are 0, meaning that
      * the current width or height is requested as an explicit size from
      * the window manager.  You can supply
-     * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or 
+     * {@link ViewGroup.LayoutParams#WRAP_CONTENT} or
      * {@link ViewGroup.LayoutParams#MATCH_PARENT} to have that measure
      * spec supplied instead, replacing the absolute width and height that
      * has been set in the popup.</p>
@@ -817,7 +912,7 @@
         mWidthMode = widthSpec;
         mHeightMode = heightSpec;
     }
-    
+
     /**
      * <p>Return this popup's height MeasureSpec</p>
      *
@@ -838,7 +933,7 @@
      * @param height the height MeasureSpec of the popup
      *
      * @see #getHeight()
-     * @see #isShowing() 
+     * @see #isShowing()
      */
     public void setHeight(int height) {
         mHeight = height;
@@ -849,7 +944,7 @@
      *
      * @return the width MeasureSpec of the popup
      *
-     * @see #setWidth(int) 
+     * @see #setWidth(int)
      */
     public int getWidth() {
         return mWidth;
@@ -871,6 +966,34 @@
     }
 
     /**
+     * Sets whether the popup window should overlap its anchor view when
+     * displayed as a drop-down.
+     * <p>
+     * If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown.
+     *
+     * @param overlapAnchor Whether the popup should overlap its anchor.
+     *
+     * @see #getOverlapAnchor()
+     * @see #isShowing()
+     */
+    public void setOverlapAnchor(boolean overlapAnchor) {
+        mOverlapAnchor = overlapAnchor;
+    }
+
+    /**
+     * Returns whether the popup window should overlap its anchor view when
+     * displayed as a drop-down.
+     *
+     * @return Whether the popup should overlap its anchor.
+     *
+     * @see #setOverlapAnchor(boolean)
+     */
+    public boolean getOverlapAnchor() {
+        return mOverlapAnchor;
+    }
+
+    /**
      * <p>Indicate whether this popup window is showing on screen.</p>
      *
      * @return true if the popup is showing, false otherwise
@@ -887,7 +1010,7 @@
      * a gravity of {@link android.view.Gravity#NO_GRAVITY} is similar to specifying
      * <code>Gravity.LEFT | Gravity.TOP</code>.
      * </p>
-     * 
+     *
      * @param parent a parent view to get the {@link android.view.View#getWindowToken()} token from
      * @param gravity the gravity which controls the placement of the popup window
      * @param x the popup's x location offset
@@ -913,32 +1036,34 @@
             return;
         }
 
+        TransitionManager.endTransitions(mDecorView);
+
         unregisterForScrollChanged();
 
         mIsShowing = true;
         mIsDropdown = false;
 
-        WindowManager.LayoutParams p = createPopupLayout(token);
-        p.windowAnimations = computeAnimationResource();
-       
+        final WindowManager.LayoutParams p = createPopupLayoutParams(token);
         preparePopup(p);
-        if (gravity == Gravity.NO_GRAVITY) {
-            gravity = Gravity.TOP | Gravity.START;
+
+        // Only override the default if some gravity was specified.
+        if (gravity != Gravity.NO_GRAVITY) {
+            p.gravity = gravity;
         }
-        p.gravity = gravity;
+
         p.x = x;
         p.y = y;
-        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
-        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
+
         invokePopup(p);
     }
 
     /**
-     * <p>Display the content view in a popup window anchored to the bottom-left
+     * Display the content view in a popup window anchored to the bottom-left
      * corner of the anchor view. If there is not enough room on screen to show
      * the popup in its entirety, this method tries to find a parent scroll
-     * view to scroll. If no parent scroll view can be scrolled, the bottom-left
-     * corner of the popup is pinned at the top left corner of the anchor view.</p>
+     * view to scroll. If no parent scroll view can be scrolled, the
+     * bottom-left corner of the popup is pinned at the top left corner of the
+     * anchor view.
      *
      * @param anchor the view on which to pin the popup window
      *
@@ -949,14 +1074,15 @@
     }
 
     /**
-     * <p>Display the content view in a popup window anchored to the bottom-left
+     * Display the content view in a popup window anchored to the bottom-left
      * corner of the anchor view offset by the specified x and y coordinates.
-     * If there is not enough room on screen to show
-     * the popup in its entirety, this method tries to find a parent scroll
-     * view to scroll. If no parent scroll view can be scrolled, the bottom-left
-     * corner of the popup is pinned at the top left corner of the anchor view.</p>
-     * <p>If the view later scrolls to move <code>anchor</code> to a different
-     * location, the popup will be moved correspondingly.</p>
+     * If there is not enough room on screen to show the popup in its entirety,
+     * this method tries to find a parent scroll view to scroll. If no parent
+     * scroll view can be scrolled, the bottom-left corner of the popup is
+     * pinned at the top left corner of the anchor view.
+     * <p>
+     * If the view later scrolls to move <code>anchor</code> to a different
+     * location, the popup will be moved correspondingly.
      *
      * @param anchor the view on which to pin the popup window
      * @param xoff A horizontal offset from the anchor in pixels
@@ -969,14 +1095,17 @@
     }
 
     /**
-     * <p>Display the content view in a popup window anchored to the bottom-left
-     * corner of the anchor view offset by the specified x and y coordinates.
-     * If there is not enough room on screen to show
-     * the popup in its entirety, this method tries to find a parent scroll
-     * view to scroll. If no parent scroll view can be scrolled, the bottom-left
-     * corner of the popup is pinned at the top left corner of the anchor view.</p>
-     * <p>If the view later scrolls to move <code>anchor</code> to a different
-     * location, the popup will be moved correspondingly.</p>
+     * Displays the content view in a popup window anchored to the corner of
+     * another view. The window is positioned according to the specified
+     * gravity and offset by the specified x and y coordinates.
+     * <p>
+     * If there is not enough room on screen to show the popup in its entirety,
+     * this method tries to find a parent scroll view to scroll. If no parent
+     * view can be scrolled, the specified vertical gravity will be ignored and
+     * the popup will anchor itself such that it is visible.
+     * <p>
+     * If the view later scrolls to move <code>anchor</code> to a different
+     * location, the popup will be moved correspondingly.
      *
      * @param anchor the view on which to pin the popup window
      * @param xoff A horizontal offset from the anchor in pixels
@@ -990,20 +1119,18 @@
             return;
         }
 
+        TransitionManager.endTransitions(mDecorView);
+
         registerForScrollChanged(anchor, xoff, yoff, gravity);
 
         mIsShowing = true;
         mIsDropdown = true;
 
-        WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
+        final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
         preparePopup(p);
 
-        updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
-
-        if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
-        if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
-
-        p.windowAnimations = computeAnimationResource();
+        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity);
+        updateAboveAnchor(aboveAnchor);
 
         invokePopup(p);
     }
@@ -1018,12 +1145,12 @@
                 // do the job.
                 if (mAboveAnchorBackgroundDrawable != null) {
                     if (mAboveAnchor) {
-                        mPopupView.setBackground(mAboveAnchorBackgroundDrawable);
+                        mDecorView.setBackground(mAboveAnchorBackgroundDrawable);
                     } else {
-                        mPopupView.setBackground(mBelowAnchorBackgroundDrawable);
+                        mDecorView.setBackground(mBelowAnchorBackgroundDrawable);
                     }
                 } else {
-                    mPopupView.refreshDrawableState();
+                    mDecorView.refreshDrawableState();
                 }
             }
         }
@@ -1045,10 +1172,9 @@
     }
 
     /**
-     * <p>Prepare the popup by embedding in into a new ViewGroup if the
-     * background drawable is not null. If embedding is required, the layout
-     * parameters' height is modified to take into account the background's
-     * padding.</p>
+     * Prepare the popup by embedding it into a new ViewGroup if the background
+     * drawable is not null. If embedding is required, the layout parameters'
+     * height is modified to take into account the background's padding.
      *
      * @param p the layout parameters of the popup's content view
      */
@@ -1058,36 +1184,86 @@
                     + "calling setContentView() before attempting to show the popup.");
         }
 
-        if (mBackground != null) {
-            final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
-            int height = ViewGroup.LayoutParams.MATCH_PARENT;
-            if (layoutParams != null &&
-                    layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
-                height = ViewGroup.LayoutParams.WRAP_CONTENT;
-            }
-
-            // when a background is available, we embed the content view
-            // within another view that owns the background drawable
-            PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
-            PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, height
-            );
-            popupViewContainer.setBackground(mBackground);
-            popupViewContainer.addView(mContentView, listParams);
-
-            mPopupView = popupViewContainer;
-        } else {
-            mPopupView = mContentView;
+        // The old decor view may be transitioning out. Make sure it finishes
+        // and cleans up before we try to create another one.
+        if (mDecorView != null) {
+            mDecorView.cancelTransitions();
         }
 
-        mPopupView.setElevation(mElevation);
+        // When a background is available, we embed the content view within
+        // another view that owns the background drawable.
+        final View backgroundView;
+        if (mBackground != null) {
+            backgroundView = createBackgroundView(mContentView);
+            backgroundView.setBackground(mBackground);
+        } else {
+            backgroundView = mContentView;
+        }
+
+        mDecorView = createDecorView(backgroundView);
+
+        // The background owner should be elevated so that it casts a shadow.
+        backgroundView.setElevation(mElevation);
+
+        // We may wrap that in another view, so we'll need to manually specify
+        // the surface insets.
+        final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2);
+        p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+        p.hasManualSurfaceInsets = true;
+
         mPopupViewInitialLayoutDirectionInherited =
-                (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
+                (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
         mPopupWidth = p.width;
         mPopupHeight = p.height;
     }
 
     /**
+     * Wraps a content view in a PopupViewContainer.
+     *
+     * @param contentView the content view to wrap
+     * @return a PopupViewContainer that wraps the content view
+     */
+    private PopupBackgroundView createBackgroundView(View contentView) {
+        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
+        final int height;
+        if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            height = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
+
+        final PopupBackgroundView backgroundView = new PopupBackgroundView(mContext);
+        final PopupBackgroundView.LayoutParams listParams = new PopupBackgroundView.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, height);
+        backgroundView.addView(contentView, listParams);
+
+        return backgroundView;
+    }
+
+    /**
+     * Wraps a content view in a FrameLayout.
+     *
+     * @param contentView the content view to wrap
+     * @return a FrameLayout that wraps the content view
+     */
+    private PopupDecorView createDecorView(View contentView) {
+        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
+        final int height;
+        if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            height = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
+
+        final PopupDecorView decorView = new PopupDecorView(mContext);
+        decorView.addView(contentView, ViewGroup.LayoutParams.MATCH_PARENT, height);
+        decorView.setClipChildren(false);
+        decorView.setClipToPadding(false);
+
+        return decorView;
+    }
+
+    /**
      * <p>Invoke the popup window by adding the content view to the window
      * manager.</p>
      *
@@ -1099,16 +1275,21 @@
         if (mContext != null) {
             p.packageName = mContext.getPackageName();
         }
-        mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
+
+        final PopupDecorView decorView = mDecorView;
+        decorView.setFitsSystemWindows(mLayoutInsetDecor);
+        decorView.requestEnterTransition(mEnterTransition);
+
         setLayoutDirectionFromAnchor();
-        mWindowManager.addView(mPopupView, p);
+
+        mWindowManager.addView(decorView, p);
     }
 
     private void setLayoutDirectionFromAnchor() {
         if (mAnchor != null) {
             View anchor = mAnchor.get();
             if (anchor != null && mPopupViewInitialLayoutDirectionInherited) {
-                mPopupView.setLayoutDirection(anchor.getLayoutDirection());
+                mDecorView.setLayoutDirection(anchor.getLayoutDirection());
             }
         }
     }
@@ -1120,26 +1301,39 @@
      *
      * @return the layout parameters to pass to the window manager
      */
-    private WindowManager.LayoutParams createPopupLayout(IBinder token) {
-        // generates the layout parameters for the drop down
-        // we want a fixed size view located at the bottom left of the anchor
-        WindowManager.LayoutParams p = new WindowManager.LayoutParams();
-        // these gravity settings put the view at the top left corner of the
-        // screen. The view is then positioned to the appropriate location
-        // by setting the x and y offsets to match the anchor's bottom
-        // left corner
+    private WindowManager.LayoutParams createPopupLayoutParams(IBinder token) {
+        final WindowManager.LayoutParams p = new WindowManager.LayoutParams();
+
+        // These gravity settings put the view at the top left corner of the
+        // screen. The view is then positioned to the appropriate location by
+        // setting the x and y offsets to match the anchor's bottom-left
+        // corner.
         p.gravity = Gravity.START | Gravity.TOP;
-        p.width = mLastWidth = mWidth;
-        p.height = mLastHeight = mHeight;
+        p.flags = computeFlags(p.flags);
+        p.type = mWindowLayoutType;
+        p.token = token;
+        p.softInputMode = mSoftInputMode;
+        p.windowAnimations = computeAnimationResource();
+
         if (mBackground != null) {
             p.format = mBackground.getOpacity();
         } else {
             p.format = PixelFormat.TRANSLUCENT;
         }
-        p.flags = computeFlags(p.flags);
-        p.type = mWindowLayoutType;
-        p.token = token;
-        p.softInputMode = mSoftInputMode;
+
+        if (mHeightMode < 0) {
+            p.height = mLastHeight = mHeightMode;
+        } else {
+            p.height = mLastHeight = mHeight;
+        }
+
+        if (mWidthMode < 0) {
+            p.width = mLastWidth = mWidthMode;
+        } else {
+            p.width = mLastWidth = mWidth;
+        }
+
+        // Used for debugging.
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
 
         return p;
@@ -1193,7 +1387,7 @@
     }
 
     private int computeAnimationResource() {
-        if (mAnimationStyle == -1) {
+        if (mAnimationStyle == ANIMATION_STYLE_DEFAULT) {
             if (mIsDropdown) {
                 return mAboveAnchor
                         ? com.android.internal.R.style.Animation_DropDownUp
@@ -1212,7 +1406,7 @@
      * <p>
      * The height must have been set on the layout parameters prior to calling
      * this method.
-     * 
+     *
      * @param anchor the view on which the popup window must be anchored
      * @param p the layout parameters used to display the drop down
      * @param xoff horizontal offset used to adjust for background padding
@@ -1310,19 +1504,15 @@
 
         p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
 
-        // Compute the position of the anchor relative to the popup.
-        mAnchorRelativeX = mDrawingLocation[0] - p.x + anchorHeight / 2;
-        mAnchorRelativeY = mDrawingLocation[1] - p.y + anchorWidth / 2;
-
         return onTop;
     }
-    
+
     /**
      * Returns the maximum height that is available for the popup to be
      * completely shown. It is recommended that this height be the maximum for
      * the popup's height, otherwise it is possible that the popup will be
      * clipped.
-     * 
+     *
      * @param anchor The view on which the popup window must be anchored.
      * @return The maximum available height for the popup to be completely
      *         shown.
@@ -1345,14 +1535,14 @@
     public int getMaxAvailableHeight(View anchor, int yOffset) {
         return getMaxAvailableHeight(anchor, yOffset, false);
     }
-    
+
     /**
      * Returns the maximum height that is available for the popup to be
      * completely shown, optionally ignoring any bottom decorations such as
      * the input method. It is recommended that this height be the maximum for
      * the popup's height, otherwise it is possible that the popup will be
      * clipped.
-     * 
+     *
      * @param anchor The view on which the popup window must be anchored.
      * @param yOffset y offset from the view's bottom edge
      * @param ignoreBottomDecorations if true, the height returned will be
@@ -1360,7 +1550,7 @@
      *        bottom decorations
      * @return The maximum available height for the popup to be completely
      *         shown.
-     *         
+     *
      * @hide Pending API council approval.
      */
     public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
@@ -1369,7 +1559,7 @@
 
         final int[] anchorPos = mDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
-        
+
         int bottomEdge = displayFrame.bottom;
         if (ignoreBottomDecorations) {
             Resources res = anchor.getContext().getResources();
@@ -1382,49 +1572,90 @@
         int returnedHeight = Math.max(distanceToBottom, distanceToTop);
         if (mBackground != null) {
             mBackground.getPadding(mTempRect);
-            returnedHeight -= mTempRect.top + mTempRect.bottom; 
+            returnedHeight -= mTempRect.top + mTempRect.bottom;
         }
-        
+
         return returnedHeight;
     }
-    
+
     /**
-     * <p>Dispose of the popup window. This method can be invoked only after
-     * {@link #showAsDropDown(android.view.View)} has been executed. Failing that, calling
-     * this method will have no effect.</p>
+     * Disposes of the popup window. This method can be invoked only after
+     * {@link #showAsDropDown(android.view.View)} has been executed. Failing
+     * that, calling this method will have no effect.
      *
-     * @see #showAsDropDown(android.view.View) 
+     * @see #showAsDropDown(android.view.View)
      */
     public void dismiss() {
-        if (isShowing() && mPopupView != null) {
-            mIsShowing = false;
-
-            unregisterForScrollChanged();
-
-            try {
-                mWindowManager.removeViewImmediate(mPopupView);
-            } finally {
-                if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
-                    ((ViewGroup) mPopupView).removeView(mContentView);
-                }
-                mPopupView = null;
-
-                if (mOnDismissListener != null) {
-                    mOnDismissListener.onDismiss();
-                }
-            }
+        if (!isShowing() || mIsTransitioningToDismiss) {
+            return;
         }
+
+        final PopupDecorView decorView = mDecorView;
+        final View contentView = mContentView;
+
+        final ViewGroup contentHolder;
+        final ViewParent contentParent = contentView.getParent();
+        if (contentParent instanceof ViewGroup) {
+            contentHolder = ((ViewGroup) contentParent);
+        } else {
+            contentHolder = null;
+        }
+
+        // Ensure any ongoing or pending transitions are canceled.
+        decorView.cancelTransitions();
+
+        unregisterForScrollChanged();
+
+        mIsShowing = false;
+        mIsTransitioningToDismiss = true;
+
+        if (mExitTransition != null && decorView.isLaidOut()) {
+            decorView.startExitTransition(mExitTransition, new TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    dismissImmediate(decorView, contentHolder, contentView);
+                }
+            });
+        } else {
+            dismissImmediate(decorView, contentHolder, contentView);
+        }
+
+        if (mOnDismissListener != null) {
+            mOnDismissListener.onDismiss();
+        }
+    }
+
+    /**
+     * Removes the popup from the window manager and tears down the supporting
+     * view hierarchy, if necessary.
+     */
+    private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) {
+        // If this method gets called and the decor view doesn't have a parent,
+        // then it was either never added or was already removed. That should
+        // never happen, but it's worth checking to avoid potential crashes.
+        if (decorView.getParent() != null) {
+            mWindowManager.removeViewImmediate(decorView);
+        }
+
+        if (contentHolder != null) {
+            contentHolder.removeView(contentView);
+        }
+
+        // This needs to stay until after all transitions have ended since we
+        // need the reference to cancel transitions in preparePopup().
+        mDecorView = null;
+        mIsTransitioningToDismiss = false;
     }
 
     /**
      * Sets the listener to be called when the window is dismissed.
-     * 
+     *
      * @param onDismissListener The listener.
      */
     public void setOnDismissListener(OnDismissListener onDismissListener) {
         mOnDismissListener = onDismissListener;
     }
-    
+
     /**
      * Updates the state of the popup window, if it is currently being displayed,
      * from the currently set state.  This includes:
@@ -1436,12 +1667,12 @@
         if (!isShowing() || mContentView == null) {
             return;
         }
-        
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
-        
+
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
+
         boolean update = false;
-        
+
         final int newAnim = computeAnimationResource();
         if (newAnim != p.windowAnimations) {
             p.windowAnimations = newAnim;
@@ -1456,7 +1687,7 @@
 
         if (update) {
             setLayoutDirectionFromAnchor();
-            mWindowManager.updateViewLayout(mPopupView, p);
+            mWindowManager.updateViewLayout(mDecorView, p);
         }
     }
 
@@ -1469,11 +1700,11 @@
      * @param height the new height
      */
     public void update(int width, int height) {
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
-                mPopupView.getLayoutParams();
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
         update(p.x, p.y, width, height, false);
     }
-    
+
     /**
      * <p>Updates the position and the dimension of the popup window. Width and
      * height can be set to -1 to update location only.  Calling this function
@@ -1517,7 +1748,8 @@
             return;
         }
 
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
 
         boolean update = force;
 
@@ -1557,7 +1789,7 @@
 
         if (update) {
             setLayoutDirectionFromAnchor();
-            mWindowManager.updateViewLayout(mPopupView, p);
+            mWindowManager.updateViewLayout(mDecorView, p);
         }
     }
 
@@ -1571,7 +1803,7 @@
      * @param height the new height, can be -1 to ignore
      */
     public void update(View anchor, int width, int height) {
-        update(anchor, false, 0, 0, true, width, height, mAnchoredGravity);
+        update(anchor, false, 0, 0, true, width, height);
     }
 
     /**
@@ -1590,30 +1822,26 @@
      * @param height the new height, can be -1 to ignore
      */
     public void update(View anchor, int xoff, int yoff, int width, int height) {
-        update(anchor, true, xoff, yoff, true, width, height, mAnchoredGravity);
+        update(anchor, true, xoff, yoff, true, width, height);
     }
 
     private void update(View anchor, boolean updateLocation, int xoff, int yoff,
-            boolean updateDimension, int width, int height, int gravity) {
+            boolean updateDimension, int width, int height) {
 
         if (!isShowing() || mContentView == null) {
             return;
         }
 
-        WeakReference<View> oldAnchor = mAnchor;
-        final boolean needsUpdate = updateLocation
-                && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+        final WeakReference<View> oldAnchor = mAnchor;
+        final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
         if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
-            registerForScrollChanged(anchor, xoff, yoff, gravity);
+            registerForScrollChanged(anchor, xoff, yoff, mAnchoredGravity);
         } else if (needsUpdate) {
             // No need to register again if this is a DropDown, showAsDropDown already did.
             mAnchorXoff = xoff;
             mAnchorYoff = yoff;
-            mAnchoredGravity = gravity;
         }
 
-        WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
-
         if (updateDimension) {
             if (width == -1) {
                 width = mPopupWidth;
@@ -1627,11 +1855,12 @@
             }
         }
 
-        int x = p.x;
-        int y = p.y;
-
+        final WindowManager.LayoutParams p =
+                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
+        final int x = p.x;
+        final int y = p.y;
         if (updateLocation) {
-            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
+            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, mAnchoredGravity));
         } else {
             updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                     mAnchoredGravity));
@@ -1651,23 +1880,22 @@
     }
 
     private void unregisterForScrollChanged() {
-        WeakReference<View> anchorRef = mAnchor;
-        View anchor = null;
-        if (anchorRef != null) {
-            anchor = anchorRef.get();
-        }
+        final WeakReference<View> anchorRef = mAnchor;
+        final View anchor = anchorRef == null ? null : anchorRef.get();
         if (anchor != null) {
-            ViewTreeObserver vto = anchor.getViewTreeObserver();
+            final ViewTreeObserver vto = anchor.getViewTreeObserver();
             vto.removeOnScrollChangedListener(mOnScrollChangedListener);
         }
+
         mAnchor = null;
     }
 
     private void registerForScrollChanged(View anchor, int xoff, int yoff, int gravity) {
         unregisterForScrollChanged();
 
-        mAnchor = new WeakReference<View>(anchor);
-        ViewTreeObserver vto = anchor.getViewTreeObserver();
+        mAnchor = new WeakReference<>(anchor);
+
+        final ViewTreeObserver vto = anchor.getViewTreeObserver();
         if (vto != null) {
             vto.addOnScrollChangedListener(mOnScrollChangedListener);
         }
@@ -1677,41 +1905,28 @@
         mAnchoredGravity = gravity;
     }
 
-    private class PopupViewContainer extends FrameLayout {
-        private static final String TAG = "PopupWindow.PopupViewContainer";
+    private class PopupDecorView extends FrameLayout {
+        private TransitionListenerAdapter mPendingExitListener;
 
-        public PopupViewContainer(Context context) {
+        public PopupDecorView(Context context) {
             super(context);
         }
 
         @Override
-        protected int[] onCreateDrawableState(int extraSpace) {
-            if (mAboveAnchor) {
-                // 1 more needed for the above anchor state
-                final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-                View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET);
-                return drawableState;
-            } else {
-                return super.onCreateDrawableState(extraSpace);
-            }
-        }
-
-        @Override
         public boolean dispatchKeyEvent(KeyEvent event) {
             if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                 if (getKeyDispatcherState() == null) {
                     return super.dispatchKeyEvent(event);
                 }
 
-                if (event.getAction() == KeyEvent.ACTION_DOWN
-                        && event.getRepeatCount() == 0) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                     if (state != null) {
                         state.startTracking(event, this);
                     }
                     return true;
                 } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                    final KeyEvent.DispatcherState state = getKeyDispatcherState();
                     if (state != null && state.isTracking(event) && !event.isCanceled()) {
                         dismiss();
                         return true;
@@ -1735,7 +1950,7 @@
         public boolean onTouchEvent(MotionEvent event) {
             final int x = (int) event.getX();
             final int y = (int) event.getY();
-            
+
             if ((event.getAction() == MotionEvent.ACTION_DOWN)
                     && ((x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight()))) {
                 dismiss();
@@ -1748,15 +1963,115 @@
             }
         }
 
-        @Override
-        public void sendAccessibilityEvent(int eventType) {
-            // clinets are interested in the content not the container, make it event source
-            if (mContentView != null) {
-                mContentView.sendAccessibilityEvent(eventType);
-            } else {
-                super.sendAccessibilityEvent(eventType);
+        /**
+         * Requests that an enter transition run after the next layout pass.
+         */
+        public void requestEnterTransition(Transition transition) {
+            final ViewTreeObserver observer = getViewTreeObserver();
+            if (observer != null && transition != null) {
+                final Transition enterTransition = transition.clone();
+
+                // Postpone the enter transition after the first layout pass.
+                observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        final ViewTreeObserver observer = getViewTreeObserver();
+                        if (observer != null) {
+                            observer.removeOnGlobalLayoutListener(this);
+                        }
+
+                        startEnterTransition(enterTransition);
+                    }
+                });
+            }
+        }
+
+        /**
+         * Starts the pending enter transition, if one is set.
+         */
+        private void startEnterTransition(Transition enterTransition) {
+            final int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                final View child = getChildAt(i);
+                enterTransition.addTarget(child);
+                child.setVisibility(View.INVISIBLE);
+            }
+
+            TransitionManager.beginDelayedTransition(this, enterTransition);
+
+            for (int i = 0; i < count; i++) {
+                final View child = getChildAt(i);
+                child.setVisibility(View.VISIBLE);
+            }
+        }
+
+        /**
+         * Starts an exit transition immediately.
+         * <p>
+         * <strong>Note:</strong> The transition listener is guaranteed to have
+         * its {@code onTransitionEnd} method called even if the transition
+         * never starts; however, it may be called with a {@code null} argument.
+         */
+        public void startExitTransition(Transition transition, final TransitionListener listener) {
+            if (transition == null) {
+                return;
+            }
+
+            // The exit listener MUST be called for cleanup, even if the
+            // transition never starts or ends. Stash it for later.
+            mPendingExitListener = new TransitionListenerAdapter() {
+                @Override
+                public void onTransitionEnd(Transition transition) {
+                    listener.onTransitionEnd(transition);
+
+                    // The listener was called. Our job here is done.
+                    mPendingExitListener = null;
+                }
+            };
+
+            final Transition exitTransition = transition.clone();
+            exitTransition.addListener(mPendingExitListener);
+
+            final int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                final View child = getChildAt(i);
+                exitTransition.addTarget(child);
+            }
+
+            TransitionManager.beginDelayedTransition(this, exitTransition);
+
+            for (int i = 0; i < count; i++) {
+                final View child = getChildAt(i);
+                child.setVisibility(View.INVISIBLE);
+            }
+        }
+
+        /**
+         * Cancels all pending or current transitions.
+         */
+        public void cancelTransitions() {
+            TransitionManager.endTransitions(this);
+
+            if (mPendingExitListener != null) {
+                mPendingExitListener.onTransitionEnd(null);
             }
         }
     }
-    
+
+    private class PopupBackgroundView extends FrameLayout {
+        public PopupBackgroundView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected int[] onCreateDrawableState(int extraSpace) {
+            if (mAboveAnchor) {
+                final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+                View.mergeDrawableStates(drawableState, ABOVE_ANCHOR_STATE_SET);
+                return drawableState;
+            } else {
+                return super.onCreateDrawableState(extraSpace);
+            }
+        }
+    }
 }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index de1bbc7..50d701a 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -18,15 +18,16 @@
 
 import android.annotation.Nullable;
 import android.graphics.PorterDuff;
+
 import com.android.internal.R;
 
+import android.annotation.InterpolatorRes;
 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;
@@ -49,7 +50,6 @@
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -64,8 +64,8 @@
 /**
  * <p>
  * Visual indicator of progress in some operation.  Displays a bar to the user
- * representing how far the operation has progressed; the application can 
- * change the amount of progress (modifying the length of the bar) as it moves 
+ * representing how far the operation has progressed; the application can
+ * change the amount of progress (modifying the length of the bar) as it moves
  * forward.  There is also a secondary progress displayable on a progress bar
  * which is useful for displaying intermediate progress, such as the buffer
  * level during a streaming playback progress bar.
@@ -81,7 +81,7 @@
  * <p>The following code example shows how a progress bar can be used from
  * a worker thread to update the user interface to notify the user of progress:
  * </p>
- * 
+ *
  * <pre>
  * public class MyActivity extends Activity {
  *     private static final int PROGRESS = 0x1;
@@ -169,13 +169,13 @@
  * </ul>
  * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
  * if your application uses a light colored theme (a white background).</p>
- *  
- * <p><strong>XML attributes</b></strong> 
- * <p> 
- * See {@link android.R.styleable#ProgressBar ProgressBar Attributes}, 
+ *
+ * <p><strong>XML attributes</b></strong>
+ * <p>
+ * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
  * {@link android.R.styleable#View View Attributes}
  * </p>
- * 
+ *
  * @attr ref android.R.styleable#ProgressBar_animationResolution
  * @attr ref android.R.styleable#ProgressBar_indeterminate
  * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
@@ -244,7 +244,7 @@
     public ProgressBar(Context context) {
         this(context, null);
     }
-    
+
     public ProgressBar(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.progressBarStyle);
     }
@@ -261,9 +261,9 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
-        
+
         mNoInvalidate = true;
-        
+
         final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
         if (progressDrawable != null) {
             // Calling this method can set mMaxHeight, make sure the corresponding
@@ -282,11 +282,11 @@
         mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
 
         final int resID = a.getResourceId(
-                com.android.internal.R.styleable.ProgressBar_interpolator, 
+                com.android.internal.R.styleable.ProgressBar_interpolator,
                 android.R.anim.linear_interpolator); // default to linear interpolator
         if (resID > 0) {
             setInterpolator(context, resID);
-        } 
+        }
 
         setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
 
@@ -399,36 +399,49 @@
      * traverse layer and state list drawables.
      */
     private Drawable tileify(Drawable drawable, boolean clip) {
-        
+        // TODO: This is a terrible idea that potentially destroys any drawable
+        // that extends any of these classes. We *really* need to remove this.
+
         if (drawable instanceof LayerDrawable) {
-            LayerDrawable background = (LayerDrawable) drawable;
-            final int N = background.getNumberOfLayers();
-            Drawable[] outDrawables = new Drawable[N];
-            
+            final LayerDrawable orig = (LayerDrawable) drawable;
+            final int N = orig.getNumberOfLayers();
+            final Drawable[] outDrawables = new Drawable[N];
+
             for (int i = 0; i < N; i++) {
-                int id = background.getId(i);
-                outDrawables[i] = tileify(background.getDrawable(i),
+                final int id = orig.getId(i);
+                outDrawables[i] = tileify(orig.getDrawable(i),
                         (id == R.id.progress || id == R.id.secondaryProgress));
             }
 
-            LayerDrawable newBg = new LayerDrawable(outDrawables);
-            
+            final LayerDrawable clone = new LayerDrawable(outDrawables);
             for (int i = 0; i < N; i++) {
-                newBg.setId(i, background.getId(i));
+                clone.setId(i, orig.getId(i));
+                clone.setLayerGravity(i, orig.getLayerGravity(i));
+                clone.setLayerWidth(i, orig.getLayerWidth(i));
+                clone.setLayerHeight(i, orig.getLayerHeight(i));
+                clone.setLayerInsetLeft(i, orig.getLayerInsetLeft(i));
+                clone.setLayerInsetRight(i, orig.getLayerInsetRight(i));
+                clone.setLayerInsetTop(i, orig.getLayerInsetTop(i));
+                clone.setLayerInsetBottom(i, orig.getLayerInsetBottom(i));
+                clone.setLayerInsetStart(i, orig.getLayerInsetStart(i));
+                clone.setLayerInsetEnd(i, orig.getLayerInsetEnd(i));
             }
-            
-            return newBg;
-            
-        } else if (drawable instanceof StateListDrawable) {
-            StateListDrawable in = (StateListDrawable) drawable;
-            StateListDrawable out = new StateListDrawable();
-            int numStates = in.getStateCount();
-            for (int i = 0; i < numStates; i++) {
+
+            return clone;
+        }
+
+        if (drawable instanceof StateListDrawable) {
+            final StateListDrawable in = (StateListDrawable) drawable;
+            final StateListDrawable out = new StateListDrawable();
+            final int N = in.getStateCount();
+            for (int i = 0; i < N; i++) {
                 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
             }
+
             return out;
-            
-        } else if (drawable instanceof BitmapDrawable) {
+        }
+
+        if (drawable instanceof BitmapDrawable) {
             final BitmapDrawable bitmap = (BitmapDrawable) drawable;
             final Bitmap tileBitmap = bitmap.getBitmap();
             if (mSampleTile == null) {
@@ -448,7 +461,7 @@
             return clip ? new ClipDrawable(
                     shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
         }
-        
+
         return drawable;
     }
 
@@ -456,7 +469,7 @@
         final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
         return new RoundRectShape(roundedCorners, null, null);
     }
-    
+
     /**
      * Convert a AnimationDrawable for use as a barberpole animation.
      * Each frame of the animation is wrapped in a ClipDrawable and
@@ -468,7 +481,7 @@
             final int N = background.getNumberOfFrames();
             AnimationDrawable newBg = new AnimationDrawable();
             newBg.setOneShot(background.isOneShot());
-            
+
             for (int i = 0; i < N; i++) {
                 Drawable frame = tileify(background.getFrame(i), true);
                 frame.setLevel(10000);
@@ -479,7 +492,7 @@
         }
         return drawable;
     }
-    
+
     /**
      * <p>
      * Initialize the progress bar's default values:
@@ -520,7 +533,7 @@
      * <p>Change the indeterminate mode for this progress bar. In indeterminate
      * mode, the progress is ignored and the progress bar shows an infinite
      * animation instead.</p>
-     * 
+     *
      * If this progress bar's style only supports indeterminate mode (such as the circular
      * progress bars), then this will be ignored.
      *
@@ -699,7 +712,7 @@
 
         setIndeterminateDrawable(d);
     }
-    
+
     /**
      * <p>Get the drawable used to draw the progress bar in
      * progress mode.</p>
@@ -1135,7 +1148,7 @@
 
         setProgressDrawable(d);
     }
-    
+
     /**
      * @return The drawable currently used to draw the progress bar
      */
@@ -1214,30 +1227,12 @@
             rd.fromUser = fromUser;
             return rd;
         }
-        
+
         public void recycle() {
             sPool.release(this);
         }
     }
 
-    private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
-        Drawable layer = null;
-
-        // We expect a layer drawable, so try to find the target ID.
-        final Drawable d = mCurrentDrawable;
-        if (d instanceof LayerDrawable) {
-            layer = ((LayerDrawable) d).findDrawableByLayerId(id);
-        }
-
-        if (fallback && layer == null) {
-            layer = d;
-        }
-
-        layer.mutate();
-        layer.setTintList(tint);
-        layer.setTintMode(tintMode);
-    }
-
     private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
             boolean callBackToApp) {
         float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
@@ -1257,13 +1252,13 @@
         } else {
             invalidate();
         }
-        
+
         if (callBackToApp && id == R.id.progress) {
-            onProgressRefresh(scale, fromUser);
+            onProgressRefresh(scale, fromUser, progress);
         }
     }
 
-    void onProgressRefresh(float scale, boolean fromUser) {
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             scheduleAccessibilityEventSender();
         }
@@ -1285,7 +1280,7 @@
             }
         }
     }
-    
+
     /**
      * <p>Set the current progress to the specified value. Does not do anything
      * if the progress bar is in indeterminate mode.</p>
@@ -1295,13 +1290,13 @@
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
      * @see #getProgress()
-     * @see #incrementProgressBy(int) 
+     * @see #incrementProgressBy(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setProgress(int progress) {
         setProgress(progress, false);
     }
-    
+
     @android.view.RemotableViewMethod
     synchronized void setProgress(int progress, boolean fromUser) {
         if (mIndeterminate) {
@@ -1327,7 +1322,7 @@
      * Set the current secondary progress to the specified value. Does not do
      * anything if the progress bar is in indeterminate mode.
      * </p>
-     * 
+     *
      * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
      * @see #setIndeterminate(boolean)
      * @see #isIndeterminate()
@@ -1408,8 +1403,8 @@
      * @param max the upper range of this progress bar
      *
      * @see #getMax()
-     * @see #setProgress(int) 
-     * @see #setSecondaryProgress(int) 
+     * @see #setProgress(int)
+     * @see #setSecondaryProgress(int)
      */
     @android.view.RemotableViewMethod
     public synchronized void setMax(int max) {
@@ -1426,13 +1421,13 @@
             refreshProgress(R.id.progress, mProgress, false);
         }
     }
-    
+
     /**
      * <p>Increase the progress bar's progress by the specified amount.</p>
      *
      * @param diff the amount by which the progress must be increased
      *
-     * @see #setProgress(int) 
+     * @see #setProgress(int)
      */
     public synchronized final void incrementProgressBy(int diff) {
         setProgress(mProgress + diff);
@@ -1443,7 +1438,7 @@
      *
      * @param diff the amount by which the secondary progress must be increased
      *
-     * @see #setSecondaryProgress(int) 
+     * @see #setSecondaryProgress(int)
      */
     public synchronized final void incrementSecondaryProgressBy(int diff) {
         setSecondaryProgress(mSecondaryProgress + diff);
@@ -1466,13 +1461,13 @@
             if (mInterpolator == null) {
                 mInterpolator = new LinearInterpolator();
             }
-    
+
             if (mTransformation == null) {
                 mTransformation = new Transformation();
             } else {
                 mTransformation.clear();
             }
-            
+
             if (mAnimation == null) {
                 mAnimation = new AlphaAnimation(0.0f, 1.0f);
             } else {
@@ -1507,7 +1502,7 @@
      * @param context The application environment
      * @param resID The resource identifier of the interpolator to load
      */
-    public void setInterpolator(Context context, int resID) {
+    public void setInterpolator(Context context, @InterpolatorRes int resID) {
         setInterpolator(AnimationUtils.loadInterpolator(context, resID));
     }
 
@@ -1623,7 +1618,7 @@
             }
             mIndeterminateDrawable.setBounds(left, top, right, bottom);
         }
-        
+
         if (mProgressDrawable != null) {
             mProgressDrawable.setBounds(0, 0, right, bottom);
         }
@@ -1646,7 +1641,7 @@
             // rotates properly in its animation
             final int saveCount = canvas.save();
 
-            if(isLayoutRtl() && mMirrorForRtl) {
+            if (isLayoutRtl() && mMirrorForRtl) {
                 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
                 canvas.scale(-1.0f, 1.0f);
             } else {
@@ -1678,35 +1673,38 @@
 
     @Override
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        Drawable d = mCurrentDrawable;
-
         int dw = 0;
         int dh = 0;
+
+        final Drawable d = mCurrentDrawable;
         if (d != null) {
             dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
             dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
         }
+
         updateDrawableState();
+
         dw += mPaddingLeft + mPaddingRight;
         dh += mPaddingTop + mPaddingBottom;
 
-        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
-                resolveSizeAndState(dh, heightMeasureSpec, 0));
+        final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0);
+        final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0);
+        setMeasuredDimension(measuredWidth, measuredHeight);
     }
-    
+
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
         updateDrawableState();
     }
-        
+
     private void updateDrawableState() {
-        int[] state = getDrawableState();
-        
+        final int[] state = getDrawableState();
+
         if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
             mProgressDrawable.setState(state);
         }
-        
+
         if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
             mIndeterminateDrawable.setState(state);
         }
@@ -1728,14 +1726,14 @@
     static class SavedState extends BaseSavedState {
         int progress;
         int secondaryProgress;
-        
+
         /**
          * Constructor called from {@link ProgressBar#onSaveInstanceState()}
          */
         SavedState(Parcelable superState) {
             super(superState);
         }
-        
+
         /**
          * Constructor called from {@link #CREATOR}
          */
@@ -1769,10 +1767,10 @@
         // Force our ancestor class to save its state
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        
+
         ss.progress = mProgress;
         ss.secondaryProgress = mSecondaryProgress;
-        
+
         return ss;
     }
 
@@ -1780,7 +1778,7 @@
     public void onRestoreInstanceState(Parcelable state) {
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        
+
         setProgress(ss.progress);
         setSecondaryProgress(ss.secondaryProgress);
     }
@@ -1826,17 +1824,16 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ProgressBar.class.getName());
-        event.setItemCount(mMax);
-        event.setCurrentItemIndex(mProgress);
+    public CharSequence getAccessibilityClassName() {
+        return ProgressBar.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ProgressBar.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
+        event.setItemCount(mMax);
+        event.setCurrentItemIndex(mProgress);
     }
 
     /**
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 23fa402..25b301f 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -37,8 +37,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * Widget used to show an image with the standard QuickContact badge
@@ -52,6 +50,7 @@
     private QueryHandler mQueryHandler;
     private Drawable mDefaultAvatar;
     private Bundle mExtras = null;
+    private String mPrioritizedMimeType;
 
     protected String[] mExcludeMimes = null;
 
@@ -126,6 +125,15 @@
     public void setMode(int size) {
     }
 
+    /**
+     * Set which mimetype should be prioritized in the QuickContacts UI. For example, passing the
+     * value {@link Email#CONTENT_ITEM_TYPE} can cause emails to be displayed more prominently in
+     * QuickContacts.
+     */
+    public void setPrioritizedMimeType(String prioritizedMimeType) {
+        mPrioritizedMimeType = prioritizedMimeType;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
@@ -287,7 +295,7 @@
         final Bundle extras = (mExtras == null) ? new Bundle() : mExtras;
         if (mContactUri != null) {
             QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
-                    QuickContact.MODE_LARGE, mExcludeMimes);
+                    mExcludeMimes, mPrioritizedMimeType);
         } else if (mContactEmail != null && mQueryHandler != null) {
             extras.putString(EXTRA_URI_CONTENT, mContactEmail);
             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
@@ -305,15 +313,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(QuickContactBadge.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(QuickContactBadge.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return QuickContactBadge.class.getName();
     }
 
     /**
@@ -377,10 +378,10 @@
             mContactUri = lookupUri;
             onContactUriChanged();
 
-            if (trigger && lookupUri != null) {
+            if (trigger && mContactUri != null) {
                 // Found contact, so trigger QuickContact
-                QuickContact.showQuickContact(getContext(), QuickContactBadge.this, lookupUri,
-                        QuickContact.MODE_LARGE, mExcludeMimes);
+                QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
+                        mExcludeMimes, mPrioritizedMimeType);
             } else if (createUri != null) {
                 // Prompt user to add this person to contacts
                 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 11fda2c..28b4db2 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -23,23 +23,26 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.graphics.Typeface;
 import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.MathUtils;
+import android.util.StateSet;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -56,14 +59,8 @@
  *
  * @hide
  */
-public class RadialTimePickerView extends View implements View.OnTouchListener {
-    private static final String TAG = "ClockView";
-
-    private static final boolean DEBUG = false;
-
-    private static final int DEBUG_COLOR = 0x20FF0000;
-    private static final int DEBUG_TEXT_COLOR = 0x60FF0000;
-    private static final int DEBUG_STROKE_WIDTH = 2;
+public class RadialTimePickerView extends View {
+    private static final String TAG = "RadialTimePickerView";
 
     private static final int HOURS = 0;
     private static final int MINUTES = 1;
@@ -82,12 +79,6 @@
     // Transparent alpha level
     private static final int ALPHA_TRANSPARENT = 0;
 
-    // Alpha level of color for selector.
-    private static final int ALPHA_SELECTOR = 60; // was 51
-
-    private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f;
-    private static final float SINE_30_DEGREES = 0.5f;
-
     private static final int DEGREES_FOR_ONE_HOUR = 30;
     private static final int DEGREES_FOR_ONE_MINUTE = 6;
 
@@ -95,9 +86,27 @@
     private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
     private static final int[] MINUTES_NUMBERS = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55};
 
-    private static final int CENTER_RADIUS = 2;
+    private static final int FADE_OUT_DURATION = 500;
+    private static final int FADE_IN_DURATION = 500;
 
-    private static int[] sSnapPrefer30sMap = new int[361];
+    private static final int[] SNAP_PREFER_30S_MAP = new int[361];
+
+    private static final int NUM_POSITIONS = 12;
+    private static final float[] COS_30 = new float[NUM_POSITIONS];
+    private static final float[] SIN_30 = new float[NUM_POSITIONS];
+
+    static {
+        // Prepare mapping to snap touchable degrees to selectable degrees.
+        preparePrefer30sMap();
+
+        final double increment = 2.0 * Math.PI / NUM_POSITIONS;
+        double angle = Math.PI / 2.0;
+        for (int i = 0; i < NUM_POSITIONS; i++) {
+            COS_30[i] = (float) Math.cos(angle);
+            SIN_30[i] = (float) Math.sin(angle);
+            angle += increment;
+        }
+    }
 
     private final InvalidateUpdateListener mInvalidateUpdateListener =
             new InvalidateUpdateListener();
@@ -108,7 +117,6 @@
     private final String[] mMinutesTexts = new String[12];
 
     private final Paint[] mPaint = new Paint[2];
-    private final int[] mColor = new int[2];
     private final IntHolder[] mAlpha = new IntHolder[2];
 
     private final Paint mPaintCenter = new Paint();
@@ -118,42 +126,27 @@
     private final IntHolder[][] mAlphaSelector = new IntHolder[2][3];
 
     private final Paint mPaintBackground = new Paint();
-    private final Paint mPaintDebug = new Paint();
 
     private final Typeface mTypeface;
 
-    private final float[] mCircleRadius = new float[3];
+    private final ColorStateList[] mTextColor = new ColorStateList[3];
+    private final int[] mTextSize = new int[3];
+    private final int[] mTextInset = new int[3];
 
-    private final float[] mTextSize = new float[2];
+    private final float[][] mOuterTextX = new float[2][12];
+    private final float[][] mOuterTextY = new float[2][12];
 
-    private final float[][] mTextGridHeights = new float[2][7];
-    private final float[][] mTextGridWidths = new float[2][7];
-
-    private final float[] mInnerTextGridHeights = new float[7];
-    private final float[] mInnerTextGridWidths = new float[7];
-
-    private final float[] mCircleRadiusMultiplier = new float[2];
-    private final float[] mNumbersRadiusMultiplier = new float[3];
-
-    private final float[] mTextSizeMultiplier = new float[3];
-
-    private final float[] mAnimationRadiusMultiplier = new float[3];
-
-    private final float mTransitionMidRadiusMultiplier;
-    private final float mTransitionEndRadiusMultiplier;
+    private final float[] mInnerTextX = new float[12];
+    private final float[] mInnerTextY = new float[12];
 
     private final int[] mLineLength = new int[3];
-    private final int[] mSelectionRadius = new int[3];
-    private final float mSelectionRadiusMultiplier;
     private final int[] mSelectionDegrees = new int[3];
 
-    private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<Animator>();
-    private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<Animator>();
+    private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<>();
+    private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<>();
 
     private final RadialPickerTouchHelper mTouchHelper;
 
-    private float mInnerTextSize;
-
     private boolean mIs24HourMode;
     private boolean mShowHours;
 
@@ -163,8 +156,14 @@
      */
     private boolean mIsOnInnerCircle;
 
+    private int mSelectorRadius;
+    private int mSelectorStroke;
+    private int mSelectorDotRadius;
+    private int mCenterDotRadius;
+
     private int mXCenter;
     private int mYCenter;
+    private int mCircleRadius;
 
     private int mMinHypotenuseForInnerNumber;
     private int mMaxHypotenuseForOuterNumber;
@@ -176,7 +175,8 @@
     private AnimatorSet mTransition;
 
     private int mAmOrPm;
-    private int mDisabledAlpha;
+
+    private float mDisabledAlpha;
 
     private OnValueSelectedListener mListener;
 
@@ -186,11 +186,6 @@
         void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance);
     }
 
-    static {
-        // Prepare mapping to snap touchable degrees to selectable degrees.
-        preparePrefer30sMap();
-    }
-
     /**
      * Split up the 360 degrees of the circle among the 60 selectable values. Assigns a larger
      * selectable area to each of the 12 visible values, such that the ratio of space apportioned
@@ -225,7 +220,7 @@
         // Iterate through the input.
         for (int degrees = 0; degrees < 361; degrees++) {
             // Save the input-output mapping.
-            sSnapPrefer30sMap[degrees] = snappedOutputDegrees;
+            SNAP_PREFER_30S_MAP[degrees] = snappedOutputDegrees;
             // If this is the last input for the specified output, calculate the next output and
             // the next expected count.
             if (count == expectedCount) {
@@ -252,10 +247,10 @@
      * mapping.
      */
     private static int snapPrefer30s(int degrees) {
-        if (sSnapPrefer30sMap == null) {
+        if (SNAP_PREFER_30S_MAP == null) {
             return -1;
         }
-        return sSnapPrefer30sMap[degrees];
+        return SNAP_PREFER_30S_MAP[degrees];
     }
 
     /**
@@ -308,7 +303,7 @@
         // Pull disabled alpha from theme.
         final TypedValue outValue = new TypedValue();
         context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
-        mDisabledAlpha = (int) (outValue.getFloat() * 255 + 0.5f);
+        mDisabledAlpha = outValue.getFloat();
 
         // process style attributes
         final Resources res = getResources();
@@ -327,72 +322,73 @@
             }
         }
 
-        final int numbersTextColor = a.getColor(R.styleable.TimePicker_numbersTextColor,
-                res.getColor(R.color.timepicker_default_text_color_material));
+        mTextColor[HOURS] = a.getColorStateList(R.styleable.TimePicker_numbersTextColor);
+        mTextColor[HOURS_INNER] = a.getColorStateList(R.styleable.TimePicker_numbersInnerTextColor);
+        mTextColor[MINUTES] = mTextColor[HOURS];
 
         mPaint[HOURS] = new Paint();
         mPaint[HOURS].setAntiAlias(true);
         mPaint[HOURS].setTextAlign(Paint.Align.CENTER);
-        mColor[HOURS] = numbersTextColor;
 
         mPaint[MINUTES] = new Paint();
         mPaint[MINUTES].setAntiAlias(true);
         mPaint[MINUTES].setTextAlign(Paint.Align.CENTER);
-        mColor[MINUTES] = numbersTextColor;
 
-        mPaintCenter.setColor(numbersTextColor);
+        final ColorStateList selectorColors = a.getColorStateList(
+                R.styleable.TimePicker_numbersSelectorColor);
+        final int selectorActivatedColor = selectorColors.getColorForState(
+                StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
+
+        mPaintCenter.setColor(selectorActivatedColor);
         mPaintCenter.setAntiAlias(true);
-        mPaintCenter.setTextAlign(Paint.Align.CENTER);
+
+        final int[] activatedStateSet = StateSet.get(
+                StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED);
 
         mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint();
         mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true);
-        mColorSelector[HOURS][SELECTOR_CIRCLE] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[HOURS][SELECTOR_CIRCLE] = selectorActivatedColor;
 
         mPaintSelector[HOURS][SELECTOR_DOT] = new Paint();
         mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true);
-        mColorSelector[HOURS][SELECTOR_DOT] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[HOURS][SELECTOR_DOT] =
+                mTextColor[HOURS].getColorForState(activatedStateSet, 0);
 
         mPaintSelector[HOURS][SELECTOR_LINE] = new Paint();
         mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true);
         mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2);
-        mColorSelector[HOURS][SELECTOR_LINE] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[HOURS][SELECTOR_LINE] = selectorActivatedColor;
 
         mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint();
         mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true);
-        mColorSelector[MINUTES][SELECTOR_CIRCLE] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[MINUTES][SELECTOR_CIRCLE] = selectorActivatedColor;
 
         mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint();
         mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true);
-        mColorSelector[MINUTES][SELECTOR_DOT] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[MINUTES][SELECTOR_DOT] =
+                mTextColor[MINUTES].getColorForState(activatedStateSet, 0);
 
         mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint();
         mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true);
         mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2);
-        mColorSelector[MINUTES][SELECTOR_LINE] = a.getColor(
-                R.styleable.TimePicker_numbersSelectorColor,
-                R.color.timepicker_default_selector_color_material);
+        mColorSelector[MINUTES][SELECTOR_LINE] = selectorActivatedColor;
 
         mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
-                res.getColor(R.color.timepicker_default_numbers_background_color_material)));
+                context.getColor(R.color.timepicker_default_numbers_background_color_material)));
         mPaintBackground.setAntiAlias(true);
 
-        if (DEBUG) {
-            mPaintDebug.setColor(DEBUG_COLOR);
-            mPaintDebug.setAntiAlias(true);
-            mPaintDebug.setStrokeWidth(DEBUG_STROKE_WIDTH);
-            mPaintDebug.setStyle(Paint.Style.STROKE);
-            mPaintDebug.setTextAlign(Paint.Align.CENTER);
-        }
+        mSelectorRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_radius);
+        mSelectorStroke = res.getDimensionPixelSize(R.dimen.timepicker_selector_stroke);
+        mSelectorDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_dot_radius);
+        mCenterDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_center_dot_radius);
+
+        mTextSize[HOURS] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_normal);
+        mTextSize[MINUTES] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_normal);
+        mTextSize[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_inner);
+
+        mTextInset[HOURS] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_normal);
+        mTextInset[MINUTES] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_normal);
+        mTextInset[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_inner);
 
         mShowHours = true;
         mIs24HourMode = false;
@@ -409,22 +405,8 @@
         initHoursAndMinutesText();
         initData();
 
-        mTransitionMidRadiusMultiplier =  Float.parseFloat(
-                res.getString(R.string.timepicker_transition_mid_radius_multiplier));
-        mTransitionEndRadiusMultiplier = Float.parseFloat(
-                res.getString(R.string.timepicker_transition_end_radius_multiplier));
-
-        mTextGridHeights[HOURS] = new float[7];
-        mTextGridHeights[MINUTES] = new float[7];
-
-        mSelectionRadiusMultiplier = Float.parseFloat(
-                res.getString(R.string.timepicker_selection_radius_multiplier));
-
         a.recycle();
 
-        setOnTouchListener(this);
-        setClickable(true);
-
         // Initial values
         final Calendar calendar = Calendar.getInstance(Locale.getDefault());
         final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
@@ -436,21 +418,6 @@
         setHapticFeedbackEnabled(true);
     }
 
-    /**
-     * Measure the view to end up as a square, based on the minimum of the height and width.
-     */
-    @Override
-    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int minDimension = Math.min(measuredWidth, measuredHeight);
-
-        super.onMeasure(MeasureSpec.makeMeasureSpec(minDimension, widthMode),
-                MeasureSpec.makeMeasureSpec(minDimension, heightMode));
-    }
-
     public void initialize(int hour, int minute, boolean is24HourMode) {
         if (mIs24HourMode != is24HourMode) {
             mIs24HourMode = is24HourMode;
@@ -512,7 +479,6 @@
             mIsOnInnerCircle = isOnInnerCircle;
 
             initData();
-            updateLayoutData();
             mTouchHelper.invalidateRoot();
         }
 
@@ -601,24 +567,32 @@
     }
 
     public void showHours(boolean animate) {
-        if (mShowHours) return;
+        if (mShowHours) {
+            return;
+        }
+
         mShowHours = true;
+
         if (animate) {
             startMinutesToHoursAnimation();
         }
+
         initData();
-        updateLayoutData();
         invalidate();
     }
 
     public void showMinutes(boolean animate) {
-        if (!mShowHours) return;
+        if (!mShowHours) {
+            return;
+        }
+
         mShowHours = false;
+
         if (animate) {
             startHoursToMinutesAnimation();
         }
+
         initData();
-        updateLayoutData();
         invalidate();
     }
 
@@ -643,162 +617,117 @@
 
         mOuterTextMinutes = mMinutesTexts;
 
-        final Resources res = getResources();
+        final int hoursAlpha = mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT;
+        mAlpha[HOURS].setValue(hoursAlpha);
+        mAlphaSelector[HOURS][SELECTOR_CIRCLE].setValue(hoursAlpha);
+        mAlphaSelector[HOURS][SELECTOR_DOT].setValue(hoursAlpha);
+        mAlphaSelector[HOURS][SELECTOR_LINE].setValue(hoursAlpha);
 
-        if (mShowHours) {
-            if (mIs24HourMode) {
-                mCircleRadiusMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_circle_radius_multiplier_24HourMode));
-                mNumbersRadiusMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_numbers_radius_multiplier_outer));
-                mTextSizeMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_text_size_multiplier_outer));
-
-                mNumbersRadiusMultiplier[HOURS_INNER] = Float.parseFloat(
-                        res.getString(R.string.timepicker_numbers_radius_multiplier_inner));
-                mTextSizeMultiplier[HOURS_INNER] = Float.parseFloat(
-                        res.getString(R.string.timepicker_text_size_multiplier_inner));
-            } else {
-                mCircleRadiusMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_circle_radius_multiplier));
-                mNumbersRadiusMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_numbers_radius_multiplier_normal));
-                mTextSizeMultiplier[HOURS] = Float.parseFloat(
-                        res.getString(R.string.timepicker_text_size_multiplier_normal));
-            }
-        } else {
-            mCircleRadiusMultiplier[MINUTES] = Float.parseFloat(
-                    res.getString(R.string.timepicker_circle_radius_multiplier));
-            mNumbersRadiusMultiplier[MINUTES] = Float.parseFloat(
-                    res.getString(R.string.timepicker_numbers_radius_multiplier_normal));
-            mTextSizeMultiplier[MINUTES] = Float.parseFloat(
-                    res.getString(R.string.timepicker_text_size_multiplier_normal));
-        }
-
-        mAnimationRadiusMultiplier[HOURS] = 1;
-        mAnimationRadiusMultiplier[HOURS_INNER] = 1;
-        mAnimationRadiusMultiplier[MINUTES] = 1;
-
-        mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT);
-        mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE);
-
-        mAlphaSelector[HOURS][SELECTOR_CIRCLE].setValue(
-                mShowHours ? ALPHA_SELECTOR : ALPHA_TRANSPARENT);
-        mAlphaSelector[HOURS][SELECTOR_DOT].setValue(
-                mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT);
-        mAlphaSelector[HOURS][SELECTOR_LINE].setValue(
-                mShowHours ? ALPHA_SELECTOR : ALPHA_TRANSPARENT);
-
-        mAlphaSelector[MINUTES][SELECTOR_CIRCLE].setValue(
-                mShowHours ? ALPHA_TRANSPARENT : ALPHA_SELECTOR);
-        mAlphaSelector[MINUTES][SELECTOR_DOT].setValue(
-                mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE);
-        mAlphaSelector[MINUTES][SELECTOR_LINE].setValue(
-                mShowHours ? ALPHA_TRANSPARENT : ALPHA_SELECTOR);
+        final int minutesAlpha = mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE;
+        mAlpha[MINUTES].setValue(minutesAlpha);
+        mAlphaSelector[MINUTES][SELECTOR_CIRCLE].setValue(minutesAlpha);
+        mAlphaSelector[MINUTES][SELECTOR_DOT].setValue(minutesAlpha);
+        mAlphaSelector[MINUTES][SELECTOR_LINE].setValue(minutesAlpha);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        updateLayoutData();
-    }
-
-    private void updateLayoutData() {
-        mXCenter = getWidth() / 2;
-        mYCenter = getHeight() / 2;
-
-        final int min = Math.min(mXCenter, mYCenter);
-
-        mCircleRadius[HOURS] = min * mCircleRadiusMultiplier[HOURS];
-        mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS];
-        mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES];
-
-        mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS]
-                * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS];
-        mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS]
-                * mNumbersRadiusMultiplier[HOURS]) + mSelectionRadius[HOURS];
-        mHalfwayHypotenusePoint = (int) (mCircleRadius[HOURS]
-                * ((mNumbersRadiusMultiplier[HOURS] + mNumbersRadiusMultiplier[HOURS_INNER]) / 2));
-
-        mTextSize[HOURS] = mCircleRadius[HOURS] * mTextSizeMultiplier[HOURS];
-        mTextSize[MINUTES] = mCircleRadius[MINUTES] * mTextSizeMultiplier[MINUTES];
-
-        if (mIs24HourMode) {
-            mInnerTextSize = mCircleRadius[HOURS] * mTextSizeMultiplier[HOURS_INNER];
+        if (!changed) {
+            return;
         }
 
-        calculateGridSizesHours();
-        calculateGridSizesMinutes();
+        mXCenter = getWidth() / 2;
+        mYCenter = getHeight() / 2;
+        mCircleRadius = Math.min(mXCenter, mYCenter);
 
-        mSelectionRadius[HOURS] = (int) (mCircleRadius[HOURS] * mSelectionRadiusMultiplier);
-        mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS];
-        mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier);
+        mMinHypotenuseForInnerNumber = mCircleRadius - mTextInset[HOURS_INNER] - mSelectorRadius;
+        mMaxHypotenuseForOuterNumber = mCircleRadius - mTextInset[HOURS] - mSelectorRadius;
+        mHalfwayHypotenusePoint = mCircleRadius - (mTextInset[HOURS] + mTextInset[HOURS_INNER]) / 2;
+
+        calculatePositionsHours();
+        calculatePositionsMinutes();
 
         mTouchHelper.invalidateRoot();
     }
 
     @Override
     public void onDraw(Canvas canvas) {
-        if (!mInputEnabled) {
-            canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), mDisabledAlpha);
-        } else {
-            canvas.save();
-        }
-
-        calculateGridSizesHours();
-        calculateGridSizesMinutes();
+        final float alphaMod = mInputEnabled ? 1 : mDisabledAlpha;
 
         drawCircleBackground(canvas);
-        drawSelector(canvas);
-
-        drawTextElements(canvas, mTextSize[HOURS], mTypeface, mOuterTextHours,
-                mTextGridWidths[HOURS], mTextGridHeights[HOURS], mPaint[HOURS],
-                mColor[HOURS], mAlpha[HOURS].getValue());
-
-        if (mIs24HourMode && mInnerTextHours != null) {
-            drawTextElements(canvas, mInnerTextSize, mTypeface, mInnerTextHours,
-                    mInnerTextGridWidths, mInnerTextGridHeights, mPaint[HOURS],
-                    mColor[HOURS], mAlpha[HOURS].getValue());
-        }
-
-        drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mOuterTextMinutes,
-                mTextGridWidths[MINUTES], mTextGridHeights[MINUTES], mPaint[MINUTES],
-                mColor[MINUTES], mAlpha[MINUTES].getValue());
-
-        drawCenter(canvas);
-
-        if (DEBUG) {
-            drawDebug(canvas);
-        }
-
-        canvas.restore();
+        drawHours(canvas, alphaMod);
+        drawMinutes(canvas, alphaMod);
+        drawCenter(canvas, alphaMod);
     }
 
     private void drawCircleBackground(Canvas canvas) {
-        canvas.drawCircle(mXCenter, mYCenter, mCircleRadius[HOURS], mPaintBackground);
+        canvas.drawCircle(mXCenter, mYCenter, mCircleRadius, mPaintBackground);
     }
 
-    private void drawCenter(Canvas canvas) {
-        canvas.drawCircle(mXCenter, mYCenter, CENTER_RADIUS, mPaintCenter);
+    private void drawHours(Canvas canvas, float alphaMod) {
+        final int hoursAlpha = (int) (mAlpha[HOURS].getValue() * alphaMod + 0.5f);
+        if (hoursAlpha > 0) {
+            // Draw the hour selector under the elements.
+            drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS, null, alphaMod);
+
+            // Draw outer hours.
+            drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS],
+                    mOuterTextHours, mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS],
+                    hoursAlpha, !mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
+
+            // Draw inner hours (12-23) for 24-hour time.
+            if (mIs24HourMode && mInnerTextHours != null) {
+                drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER],
+                        mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha,
+                        mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
+            }
+        }
     }
 
-    private void drawSelector(Canvas canvas) {
-        drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS);
-        drawSelector(canvas, MINUTES);
+    private void drawMinutes(Canvas canvas, float alphaMod) {
+        final int minutesAlpha = (int) (mAlpha[MINUTES].getValue() * alphaMod + 0.5f);
+        if (minutesAlpha > 0) {
+            drawSelector(canvas, MINUTES, mSelectorPath, alphaMod);
+
+            // Exclude the selector region, then draw minutes with no
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE);
+            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
+                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    minutesAlpha, false, 0, false);
+            canvas.restore();
+
+            // Intersect the selector region, then draw minutes with only
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(mSelectorPath, Region.Op.INTERSECT);
+            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
+                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    minutesAlpha, true, mSelectionDegrees[MINUTES], true);
+            canvas.restore();
+        }
+    }
+
+    private void drawCenter(Canvas canvas, float alphaMod) {
+        mPaintCenter.setAlpha((int) (255 * alphaMod + 0.5f));
+        canvas.drawCircle(mXCenter, mYCenter, mCenterDotRadius, mPaintCenter);
     }
 
     private int getMultipliedAlpha(int argb, int alpha) {
         return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5);
     }
 
-    private void drawSelector(Canvas canvas, int index) {
+    private final Path mSelectorPath = new Path();
+
+    private void drawSelector(Canvas canvas, int index, Path selectorPath, float alphaMod) {
         // Calculate the current radius at which to place the selection circle.
-        mLineLength[index] = (int) (mCircleRadius[index]
-                * mNumbersRadiusMultiplier[index] * mAnimationRadiusMultiplier[index]);
+        mLineLength[index] = mCircleRadius - mTextInset[index];
 
-        double selectionRadians = Math.toRadians(mSelectionDegrees[index]);
+        final double selectionRadians = Math.toRadians(mSelectionDegrees[index]);
 
-        int pointX = mXCenter + (int) (mLineLength[index] * Math.sin(selectionRadians));
-        int pointY = mYCenter - (int) (mLineLength[index] * Math.cos(selectionRadians));
+        float pointX = mXCenter + (int) (mLineLength[index] * Math.sin(selectionRadians));
+        float pointY = mYCenter - (int) (mLineLength[index] * Math.cos(selectionRadians));
 
         int color;
         int alpha;
@@ -806,267 +735,146 @@
 
         // Draw the selection circle
         color = mColorSelector[index % 2][SELECTOR_CIRCLE];
-        alpha = mAlphaSelector[index % 2][SELECTOR_CIRCLE].getValue();
+        alpha = (int) (mAlphaSelector[index % 2][SELECTOR_CIRCLE].getValue() * alphaMod + 0.5f);
         paint = mPaintSelector[index % 2][SELECTOR_CIRCLE];
         paint.setColor(color);
         paint.setAlpha(getMultipliedAlpha(color, alpha));
-        canvas.drawCircle(pointX, pointY, mSelectionRadius[index], paint);
+        canvas.drawCircle(pointX, pointY, mSelectorRadius, paint);
 
-        // Draw the dot if needed
-        if (mSelectionDegrees[index] % 30 != 0) {
+        // If needed, set up the clip path for later.
+        if (selectorPath != null) {
+            mSelectorPath.reset();
+            mSelectorPath.addCircle(pointX, pointY, mSelectorRadius, Path.Direction.CCW);
+        }
+
+        // Draw the dot if needed.
+        final boolean shouldDrawDot = mSelectionDegrees[index] % 30 != 0;
+        if (shouldDrawDot) {
             // We're not on a direct tick
             color = mColorSelector[index % 2][SELECTOR_DOT];
-            alpha = mAlphaSelector[index % 2][SELECTOR_DOT].getValue();
+            alpha = (int) (mAlphaSelector[index % 2][SELECTOR_DOT].getValue() * alphaMod + 0.5f);
             paint = mPaintSelector[index % 2][SELECTOR_DOT];
             paint.setColor(color);
             paint.setAlpha(getMultipliedAlpha(color, alpha));
-            canvas.drawCircle(pointX, pointY, (mSelectionRadius[index] * 2 / 7), paint);
-        } else {
-            // We're not drawing the dot, so shorten the line to only go as far as the edge of the
-            // selection circle
-            int lineLength = mLineLength[index] - mSelectionRadius[index];
-            pointX = mXCenter + (int) (lineLength * Math.sin(selectionRadians));
-            pointY = mYCenter - (int) (lineLength * Math.cos(selectionRadians));
+            canvas.drawCircle(pointX, pointY, mSelectorDotRadius, paint);
         }
 
+        // Shorten the line to only go from the edge of the center dot to the
+        // edge of the selection circle.
+        final double sin = Math.sin(selectionRadians);
+        final double cos = Math.cos(selectionRadians);
+        final int lineLength = mLineLength[index] - mSelectorRadius;
+        final int centerX = mXCenter + (int) (mCenterDotRadius * sin);
+        final int centerY = mYCenter - (int) (mCenterDotRadius * cos);
+        pointX = centerX + (int) (lineLength * sin);
+        pointY = centerY - (int) (lineLength * cos);
+
         // Draw the line
         color = mColorSelector[index % 2][SELECTOR_LINE];
-        alpha = mAlphaSelector[index % 2][SELECTOR_LINE].getValue();
+        alpha = (int) (mAlphaSelector[index % 2][SELECTOR_LINE].getValue() * alphaMod + 0.5f);
         paint = mPaintSelector[index % 2][SELECTOR_LINE];
         paint.setColor(color);
+        paint.setStrokeWidth(mSelectorStroke);
         paint.setAlpha(getMultipliedAlpha(color, alpha));
         canvas.drawLine(mXCenter, mYCenter, pointX, pointY, paint);
     }
 
-    private void drawDebug(Canvas canvas) {
-        // Draw outer numbers circle
-        final float outerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS];
-        canvas.drawCircle(mXCenter, mYCenter, outerRadius, mPaintDebug);
-
-        // Draw inner numbers circle
-        final float innerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS_INNER];
-        canvas.drawCircle(mXCenter, mYCenter, innerRadius, mPaintDebug);
-
-        // Draw outer background circle
-        canvas.drawCircle(mXCenter, mYCenter, mCircleRadius[HOURS], mPaintDebug);
-
-        // Draw outer rectangle for circles
-        float left = mXCenter - outerRadius;
-        float top = mYCenter - outerRadius;
-        float right = mXCenter + outerRadius;
-        float bottom = mYCenter + outerRadius;
-        canvas.drawRect(left, top, right, bottom, mPaintDebug);
-
-        // Draw outer rectangle for background
-        left = mXCenter - mCircleRadius[HOURS];
-        top = mYCenter - mCircleRadius[HOURS];
-        right = mXCenter + mCircleRadius[HOURS];
-        bottom = mYCenter + mCircleRadius[HOURS];
-        canvas.drawRect(left, top, right, bottom, mPaintDebug);
-
-        // Draw outer view rectangle
-        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaintDebug);
-
-        // Draw selected time
-        final String selected = String.format("%02d:%02d", getCurrentHour(), getCurrentMinute());
-
-        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-        TextView tv = new TextView(getContext());
-        tv.setLayoutParams(lp);
-        tv.setText(selected);
-        tv.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-        Paint paint = tv.getPaint();
-        paint.setColor(DEBUG_TEXT_COLOR);
-
-        final int width = tv.getMeasuredWidth();
-
-        float height = paint.descent() - paint.ascent();
-        float x = mXCenter - width / 2;
-        float y = mYCenter + 1.5f * height;
-
-        canvas.drawText(selected, x, y, paint);
-    }
-
-    private void calculateGridSizesHours() {
+    private void calculatePositionsHours() {
         // Calculate the text positions
-        float numbersRadius = mCircleRadius[HOURS]
-                * mNumbersRadiusMultiplier[HOURS] * mAnimationRadiusMultiplier[HOURS];
+        final float numbersRadius = mCircleRadius - mTextInset[HOURS];
 
         // Calculate the positions for the 12 numbers in the main circle.
-        calculateGridSizes(mPaint[HOURS], numbersRadius, mXCenter, mYCenter,
-                mTextSize[HOURS], mTextGridHeights[HOURS], mTextGridWidths[HOURS]);
+        calculatePositions(mPaint[HOURS], numbersRadius, mXCenter, mYCenter,
+                mTextSize[HOURS], mOuterTextX[HOURS], mOuterTextY[HOURS]);
 
         // If we have an inner circle, calculate those positions too.
         if (mIs24HourMode) {
-            float innerNumbersRadius = mCircleRadius[HOURS_INNER]
-                    * mNumbersRadiusMultiplier[HOURS_INNER]
-                    * mAnimationRadiusMultiplier[HOURS_INNER];
-
-            calculateGridSizes(mPaint[HOURS], innerNumbersRadius, mXCenter, mYCenter,
-                    mInnerTextSize, mInnerTextGridHeights, mInnerTextGridWidths);
+            final int innerNumbersRadius = mCircleRadius - mTextInset[HOURS_INNER];
+            calculatePositions(mPaint[HOURS], innerNumbersRadius, mXCenter, mYCenter,
+                    mTextSize[HOURS_INNER], mInnerTextX, mInnerTextY);
         }
     }
 
-    private void calculateGridSizesMinutes() {
+    private void calculatePositionsMinutes() {
         // Calculate the text positions
-        float numbersRadius = mCircleRadius[MINUTES]
-                * mNumbersRadiusMultiplier[MINUTES] * mAnimationRadiusMultiplier[MINUTES];
+        final float numbersRadius = mCircleRadius - mTextInset[MINUTES];
 
         // Calculate the positions for the 12 numbers in the main circle.
-        calculateGridSizes(mPaint[MINUTES], numbersRadius, mXCenter, mYCenter,
-                mTextSize[MINUTES], mTextGridHeights[MINUTES], mTextGridWidths[MINUTES]);
+        calculatePositions(mPaint[MINUTES], numbersRadius, mXCenter, mYCenter,
+                mTextSize[MINUTES], mOuterTextX[MINUTES], mOuterTextY[MINUTES]);
     }
 
-
     /**
      * Using the trigonometric Unit Circle, calculate the positions that the text will need to be
      * drawn at based on the specified circle radius. Place the values in the textGridHeights and
      * textGridWidths parameters.
      */
-    private static void calculateGridSizes(Paint paint, float numbersRadius, float xCenter,
-            float yCenter, float textSize, float[] textGridHeights, float[] textGridWidths) {
-        /*
-         * The numbers need to be drawn in a 7x7 grid, representing the points on the Unit Circle.
-         */
-        final float offset1 = numbersRadius;
-        // cos(30) = a / r => r * cos(30)
-        final float offset2 = numbersRadius * COSINE_30_DEGREES;
-        // sin(30) = o / r => r * sin(30)
-        final float offset3 = numbersRadius * SINE_30_DEGREES;
-
+    private static void calculatePositions(Paint paint, float radius, float xCenter, float yCenter,
+            float textSize, float[] x, float[] y) {
+        // Adjust yCenter to account for the text's baseline.
         paint.setTextSize(textSize);
-        // We'll need yTextBase to be slightly lower to account for the text's baseline.
         yCenter -= (paint.descent() + paint.ascent()) / 2;
 
-        textGridHeights[0] = yCenter - offset1;
-        textGridWidths[0] = xCenter - offset1;
-        textGridHeights[1] = yCenter - offset2;
-        textGridWidths[1] = xCenter - offset2;
-        textGridHeights[2] = yCenter - offset3;
-        textGridWidths[2] = xCenter - offset3;
-        textGridHeights[3] = yCenter;
-        textGridWidths[3] = xCenter;
-        textGridHeights[4] = yCenter + offset3;
-        textGridWidths[4] = xCenter + offset3;
-        textGridHeights[5] = yCenter + offset2;
-        textGridWidths[5] = xCenter + offset2;
-        textGridHeights[6] = yCenter + offset1;
-        textGridWidths[6] = xCenter + offset1;
+        for (int i = 0; i < NUM_POSITIONS; i++) {
+            x[i] = xCenter - radius * COS_30[i];
+            y[i] = yCenter - radius * SIN_30[i];
+        }
     }
 
     /**
      * Draw the 12 text values at the positions specified by the textGrid parameters.
      */
-    private void drawTextElements(Canvas canvas, float textSize, Typeface typeface, String[] texts,
-            float[] textGridWidths, float[] textGridHeights, Paint paint, int color, int alpha) {
+    private void drawTextElements(Canvas canvas, float textSize, Typeface typeface,
+            ColorStateList textColor, String[] texts, float[] textX, float[] textY, Paint paint,
+            int alpha, boolean showActivated, int activatedDegrees, boolean activatedOnly) {
         paint.setTextSize(textSize);
         paint.setTypeface(typeface);
-        paint.setColor(color);
-        paint.setAlpha(getMultipliedAlpha(color, alpha));
-        canvas.drawText(texts[0], textGridWidths[3], textGridHeights[0], paint);
-        canvas.drawText(texts[1], textGridWidths[4], textGridHeights[1], paint);
-        canvas.drawText(texts[2], textGridWidths[5], textGridHeights[2], paint);
-        canvas.drawText(texts[3], textGridWidths[6], textGridHeights[3], paint);
-        canvas.drawText(texts[4], textGridWidths[5], textGridHeights[4], paint);
-        canvas.drawText(texts[5], textGridWidths[4], textGridHeights[5], paint);
-        canvas.drawText(texts[6], textGridWidths[3], textGridHeights[6], paint);
-        canvas.drawText(texts[7], textGridWidths[2], textGridHeights[5], paint);
-        canvas.drawText(texts[8], textGridWidths[1], textGridHeights[4], paint);
-        canvas.drawText(texts[9], textGridWidths[0], textGridHeights[3], paint);
-        canvas.drawText(texts[10], textGridWidths[1], textGridHeights[2], paint);
-        canvas.drawText(texts[11], textGridWidths[2], textGridHeights[1], paint);
-    }
 
-    // Used for animating the hours by changing their radius
-    @SuppressWarnings("unused")
-    private void setAnimationRadiusMultiplierHours(float animationRadiusMultiplier) {
-        mAnimationRadiusMultiplier[HOURS] = animationRadiusMultiplier;
-        mAnimationRadiusMultiplier[HOURS_INNER] = animationRadiusMultiplier;
-    }
+        // The activated index can touch a range of elements.
+        final float activatedIndex = activatedDegrees / (360.0f / NUM_POSITIONS);
+        final int activatedFloor = (int) activatedIndex;
+        final int activatedCeil = ((int) Math.ceil(activatedIndex)) % NUM_POSITIONS;
 
-    // Used for animating the minutes by changing their radius
-    @SuppressWarnings("unused")
-    private void setAnimationRadiusMultiplierMinutes(float animationRadiusMultiplier) {
-        mAnimationRadiusMultiplier[MINUTES] = animationRadiusMultiplier;
-    }
+        for (int i = 0; i < 12; i++) {
+            final boolean activated = (activatedFloor == i || activatedCeil == i);
+            if (activatedOnly && !activated) {
+                continue;
+            }
 
-    private static ObjectAnimator getRadiusDisappearAnimator(Object target,
-            String radiusPropertyName, InvalidateUpdateListener updateListener,
-            float midRadiusMultiplier, float endRadiusMultiplier) {
-        Keyframe kf0, kf1, kf2;
-        float midwayPoint = 0.2f;
-        int duration = 500;
+            final int stateMask = StateSet.VIEW_STATE_ENABLED
+                    | (showActivated && activated ? StateSet.VIEW_STATE_ACTIVATED : 0);
+            final int color = textColor.getColorForState(StateSet.get(stateMask), 0);
+            paint.setColor(color);
+            paint.setAlpha(getMultipliedAlpha(color, alpha));
 
-        kf0 = Keyframe.ofFloat(0f, 1);
-        kf1 = Keyframe.ofFloat(midwayPoint, midRadiusMultiplier);
-        kf2 = Keyframe.ofFloat(1f, endRadiusMultiplier);
-        PropertyValuesHolder radiusDisappear = PropertyValuesHolder.ofKeyframe(
-                radiusPropertyName, kf0, kf1, kf2);
-
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(
-                target, radiusDisappear).setDuration(duration);
-        animator.addUpdateListener(updateListener);
-        return animator;
-    }
-
-    private static ObjectAnimator getRadiusReappearAnimator(Object target,
-            String radiusPropertyName, InvalidateUpdateListener updateListener,
-            float midRadiusMultiplier, float endRadiusMultiplier) {
-        Keyframe kf0, kf1, kf2, kf3;
-        float midwayPoint = 0.2f;
-        int duration = 500;
-
-        // Set up animator for reappearing.
-        float delayMultiplier = 0.25f;
-        float transitionDurationMultiplier = 1f;
-        float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
-        int totalDuration = (int) (duration * totalDurationMultiplier);
-        float delayPoint = (delayMultiplier * duration) / totalDuration;
-        midwayPoint = 1 - (midwayPoint * (1 - delayPoint));
-
-        kf0 = Keyframe.ofFloat(0f, endRadiusMultiplier);
-        kf1 = Keyframe.ofFloat(delayPoint, endRadiusMultiplier);
-        kf2 = Keyframe.ofFloat(midwayPoint, midRadiusMultiplier);
-        kf3 = Keyframe.ofFloat(1f, 1);
-        PropertyValuesHolder radiusReappear = PropertyValuesHolder.ofKeyframe(
-                radiusPropertyName, kf0, kf1, kf2, kf3);
-
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(
-                target, radiusReappear).setDuration(totalDuration);
-        animator.addUpdateListener(updateListener);
-        return animator;
+            canvas.drawText(texts[i], textX[i], textY[i], paint);
+        }
     }
 
     private static ObjectAnimator getFadeOutAnimator(IntHolder target, int startAlpha, int endAlpha,
                 InvalidateUpdateListener updateListener) {
-        int duration = 500;
-        ObjectAnimator animator = ObjectAnimator.ofInt(target, "value", startAlpha, endAlpha);
-        animator.setDuration(duration);
+        final ObjectAnimator animator = ObjectAnimator.ofInt(target, "value", startAlpha, endAlpha);
+        animator.setDuration(FADE_OUT_DURATION);
         animator.addUpdateListener(updateListener);
-
         return animator;
     }
 
     private static ObjectAnimator getFadeInAnimator(IntHolder target, int startAlpha, int endAlpha,
                 InvalidateUpdateListener updateListener) {
-        Keyframe kf0, kf1, kf2;
-        int duration = 500;
+        final float delayMultiplier = 0.25f;
+        final float transitionDurationMultiplier = 1f;
+        final float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
+        final int totalDuration = (int) (FADE_IN_DURATION * totalDurationMultiplier);
+        final float delayPoint = (delayMultiplier * FADE_IN_DURATION) / totalDuration;
 
-        // Set up animator for reappearing.
-        float delayMultiplier = 0.25f;
-        float transitionDurationMultiplier = 1f;
-        float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
-        int totalDuration = (int) (duration * totalDurationMultiplier);
-        float delayPoint = (delayMultiplier * duration) / totalDuration;
-
+        final Keyframe kf0, kf1, kf2;
         kf0 = Keyframe.ofInt(0f, startAlpha);
         kf1 = Keyframe.ofInt(delayPoint, startAlpha);
         kf2 = Keyframe.ofInt(1f, endAlpha);
-        PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("value", kf0, kf1, kf2);
+        final PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("value", kf0, kf1, kf2);
 
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(
-                target, fadeIn).setDuration(totalDuration);
+        final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, fadeIn);
+        animator.setDuration(totalDuration);
         animator.addUpdateListener(updateListener);
         return animator;
     }
@@ -1080,29 +888,23 @@
 
     private void startHoursToMinutesAnimation() {
         if (mHoursToMinutesAnims.size() == 0) {
-            mHoursToMinutesAnims.add(getRadiusDisappearAnimator(this,
-                    "animationRadiusMultiplierHours", mInvalidateUpdateListener,
-                    mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier));
             mHoursToMinutesAnims.add(getFadeOutAnimator(mAlpha[HOURS],
                     ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_CIRCLE],
-                    ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
+                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_DOT],
                     ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_LINE],
-                    ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
+                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
 
-            mHoursToMinutesAnims.add(getRadiusReappearAnimator(this,
-                    "animationRadiusMultiplierMinutes", mInvalidateUpdateListener,
-                    mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier));
             mHoursToMinutesAnims.add(getFadeInAnimator(mAlpha[MINUTES],
                     ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_CIRCLE],
-                    ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener));
+                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_DOT],
                     ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_LINE],
-                    ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener));
+                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
         }
 
         if (mTransition != null && mTransition.isRunning()) {
@@ -1115,29 +917,23 @@
 
     private void startMinutesToHoursAnimation() {
         if (mMinuteToHoursAnims.size() == 0) {
-            mMinuteToHoursAnims.add(getRadiusDisappearAnimator(this,
-                    "animationRadiusMultiplierMinutes", mInvalidateUpdateListener,
-                    mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier));
             mMinuteToHoursAnims.add(getFadeOutAnimator(mAlpha[MINUTES],
                     ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_CIRCLE],
-                    ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
+                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_DOT],
                     ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_LINE],
-                    ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
+                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
 
-            mMinuteToHoursAnims.add(getRadiusReappearAnimator(this,
-                    "animationRadiusMultiplierHours", mInvalidateUpdateListener,
-                    mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier));
             mMinuteToHoursAnims.add(getFadeInAnimator(mAlpha[HOURS],
                     ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_CIRCLE],
-                    ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener));
+                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_DOT],
                     ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
             mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_LINE],
-                    ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener));
+                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
         }
 
         if (mTransition != null && mTransition.isRunning()) {
@@ -1148,20 +944,21 @@
         mTransition.start();
     }
 
-    private int getDegreesFromXY(float x, float y) {
+    private int getDegreesFromXY(float x, float y, boolean constrainOutside) {
         final double hypotenuse = Math.sqrt(
                 (y - mYCenter) * (y - mYCenter) + (x - mXCenter) * (x - mXCenter));
 
         // Basic check if we're outside the range of the disk
-        if (hypotenuse > mCircleRadius[HOURS]) {
+        if (constrainOutside && hypotenuse > mCircleRadius) {
             return -1;
         }
+
         // Check
         if (mIs24HourMode && mShowHours) {
             if (hypotenuse >= mMinHypotenuseForInnerNumber
                     && hypotenuse <= mHalfwayHypotenusePoint) {
                 mIsOnInnerCircle = true;
-            } else if (hypotenuse <= mMaxHypotenuseForOuterNumber
+            } else if ((hypotenuse <= mMaxHypotenuseForOuterNumber || !constrainOutside)
                     && hypotenuse >= mHalfwayHypotenusePoint) {
                 mIsOnInnerCircle = false;
             } else {
@@ -1169,11 +966,11 @@
             }
         } else {
             final int index =  (mShowHours) ? HOURS : MINUTES;
-            final float length = (mCircleRadius[index] * mNumbersRadiusMultiplier[index]);
-            final int distanceToNumber = (int) Math.abs(hypotenuse - length);
-            final int maxAllowedDistance =
-                    (int) (mCircleRadius[index] * (1 - mNumbersRadiusMultiplier[index]));
-            if (distanceToNumber > maxAllowedDistance) {
+            final float length = (mCircleRadius - mTextInset[index]);
+            final int distanceToNumber = (int) (hypotenuse - length);
+            final int maxAllowedDistance = mTextInset[index];
+            if (distanceToNumber < -maxAllowedDistance
+                    || (constrainOutside && distanceToNumber > maxAllowedDistance)) {
                 return -1;
             }
         }
@@ -1203,7 +1000,7 @@
     boolean mChangedDuringTouch = false;
 
     @Override
-    public boolean onTouch(View v, MotionEvent event) {
+    public boolean onTouchEvent(MotionEvent event) {
         if (!mInputEnabled) {
             return true;
         }
@@ -1240,7 +1037,7 @@
         // Calling getDegreesFromXY has side effects, so cache
         // whether we used to be on the inner circle.
         final boolean wasOnInnerCircle = mIsOnInnerCircle;
-        final int degrees = getDegreesFromXY(x, y);
+        final int degrees = getDegreesFromXY(x, y, false);
         if (degrees == -1) {
             return false;
         }
@@ -1385,7 +1182,7 @@
             // Calling getDegreesXY() has side-effects, so we need to cache the
             // current inner circle value and restore after the call.
             final boolean wasOnInnerCircle = mIsOnInnerCircle;
-            final int degrees = getDegreesFromXY(x, y);
+            final int degrees = getDegreesFromXY(x, y, true);
             final boolean isOnInnerCircle = mIsOnInnerCircle;
             mIsOnInnerCircle = wasOnInnerCircle;
 
@@ -1541,18 +1338,18 @@
             if (type == TYPE_HOUR) {
                 final boolean innerCircle = mIs24HourMode && value > 0 && value <= 12;
                 if (innerCircle) {
-                    centerRadius = mCircleRadius[HOURS_INNER] * mNumbersRadiusMultiplier[HOURS_INNER];
-                    radius = mSelectionRadius[HOURS_INNER];
+                    centerRadius = mCircleRadius - mTextInset[HOURS_INNER];
+                    radius = mSelectorRadius;
                 } else {
-                    centerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS];
-                    radius = mSelectionRadius[HOURS];
+                    centerRadius = mCircleRadius - mTextInset[HOURS];
+                    radius = mSelectorRadius;
                 }
 
                 degrees = getDegreesForHour(value);
             } else if (type == TYPE_MINUTE) {
-                centerRadius = mCircleRadius[MINUTES] * mNumbersRadiusMultiplier[MINUTES];
+                centerRadius = mCircleRadius - mTextInset[MINUTES];
                 degrees = getDegreesForMinute(value);
-                radius = mSelectionRadius[MINUTES];
+                radius = mSelectorRadius;
             } else {
                 // This should never happen.
                 centerRadius = 0;
diff --git a/core/java/android/widget/RadioButton.java b/core/java/android/widget/RadioButton.java
index afc4830..d44fbd7 100644
--- a/core/java/android/widget/RadioButton.java
+++ b/core/java/android/widget/RadioButton.java
@@ -18,8 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -80,14 +78,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(RadioButton.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(RadioButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RadioButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 78d05b0..065feb8 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -18,13 +18,12 @@
 
 import com.android.internal.R;
 
+import android.annotation.IdRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -151,7 +150,7 @@
      * @see #getCheckedRadioButtonId()
      * @see #clearCheck()
      */
-    public void check(int id) {
+    public void check(@IdRes int id) {
         // don't even bother
         if (id != -1 && (id == mCheckedId)) {
             return;
@@ -168,7 +167,7 @@
         setCheckedId(id);
     }
 
-    private void setCheckedId(int id) {
+    private void setCheckedId(@IdRes int id) {
         mCheckedId = id;
         if (mOnCheckedChangeListener != null) {
             mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
@@ -193,6 +192,7 @@
      *
      * @attr ref android.R.styleable#RadioGroup_checkedButton
      */
+    @IdRes
     public int getCheckedRadioButtonId() {
         return mCheckedId;
     }
@@ -241,15 +241,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(RadioGroup.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(RadioGroup.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RadioGroup.class.getName();
     }
 
     /**
@@ -338,7 +331,7 @@
          * @param group the group in which the checked radio button has changed
          * @param checkedId the unique identifier of the newly checked radio button
          */
-        public void onCheckedChanged(RadioGroup group, int checkedId);
+        public void onCheckedChanged(RadioGroup group, @IdRes int checkedId);
     }
 
     private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 82b490e..b538334 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -21,9 +21,6 @@
 import android.graphics.drawable.shapes.RectShape;
 import android.graphics.drawable.shapes.Shape;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import com.android.internal.R;
 
 /**
@@ -43,7 +40,7 @@
  * <p>
  * The secondary progress should not be modified by the client as it is used
  * internally as the background for a fractionally filled star.
- * 
+ *
  * @attr ref android.R.styleable#RatingBar_numStars
  * @attr ref android.R.styleable#RatingBar_rating
  * @attr ref android.R.styleable#RatingBar_stepSize
@@ -58,14 +55,14 @@
      * programmatically.
      */
     public interface OnRatingBarChangeListener {
-        
+
         /**
          * Notification that the rating has changed. Clients can use the
          * fromUser parameter to distinguish user-initiated changes from those
          * that occurred programmatically. This will not be called continuously
          * while the user is dragging, only when the user finalizes a rating by
          * lifting the touch.
-         * 
+         *
          * @param ratingBar The RatingBar whose rating has changed.
          * @param rating The current rating. This will be in the range
          *            0..numStars.
@@ -79,9 +76,9 @@
     private int mNumStars = 5;
 
     private int mProgressOnStartTracking;
-    
+
     private OnRatingBarChangeListener mOnRatingBarChangeListener;
-    
+
     public RatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
@@ -98,19 +95,19 @@
         a.recycle();
 
         if (numStars > 0 && numStars != mNumStars) {
-            setNumStars(numStars);            
+            setNumStars(numStars);
         }
-        
+
         if (stepSize >= 0) {
             setStepSize(stepSize);
         } else {
             setStepSize(0.5f);
         }
-        
+
         if (rating >= 0) {
             setRating(rating);
         }
-        
+
         // A touch inside a star fill up to that fractional area (slightly more
         // than 1 so boundaries round up).
         mTouchProgressOffset = 1.1f;
@@ -123,16 +120,16 @@
     public RatingBar(Context context) {
         this(context, null);
     }
-    
+
     /**
      * Sets the listener to be called when the rating changes.
-     * 
+     *
      * @param listener The listener.
      */
     public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
         mOnRatingBarChangeListener = listener;
     }
-    
+
     /**
      * @return The listener (may be null) that is listening for rating change
      *         events.
@@ -144,7 +141,7 @@
     /**
      * Whether this rating bar should only be an indicator (thus non-changeable
      * by the user).
-     * 
+     *
      * @param isIndicator Whether it should be an indicator.
      *
      * @attr ref android.R.styleable#RatingBar_isIndicator
@@ -153,7 +150,7 @@
         mIsUserSeekable = !isIndicator;
         setFocusable(!isIndicator);
     }
-    
+
     /**
      * @return Whether this rating bar is only an indicator.
      *
@@ -162,21 +159,21 @@
     public boolean isIndicator() {
         return !mIsUserSeekable;
     }
-    
+
     /**
      * Sets the number of stars to show. In order for these to be shown
      * properly, it is recommended the layout width of this widget be wrap
      * content.
-     * 
+     *
      * @param numStars The number of stars.
      */
     public void setNumStars(final int numStars) {
         if (numStars <= 0) {
             return;
         }
-        
+
         mNumStars = numStars;
-        
+
         // This causes the width to change, so re-layout
         requestLayout();
     }
@@ -188,10 +185,10 @@
     public int getNumStars() {
         return mNumStars;
     }
-    
+
     /**
      * Sets the rating (the number of stars filled).
-     * 
+     *
      * @param rating The rating to set.
      */
     public void setRating(float rating) {
@@ -200,16 +197,16 @@
 
     /**
      * Gets the current rating (number of stars filled).
-     * 
+     *
      * @return The current rating.
      */
     public float getRating() {
-        return getProgress() / getProgressPerStar();        
+        return getProgress() / getProgressPerStar();
     }
 
     /**
      * Sets the step size (granularity) of this rating bar.
-     * 
+     *
      * @param stepSize The step size of this rating bar. For example, if
      *            half-star granularity is wanted, this would be 0.5.
      */
@@ -217,7 +214,7 @@
         if (stepSize <= 0) {
             return;
         }
-        
+
         final float newMax = mNumStars / stepSize;
         final int newProgress = (int) (newMax / getMax() * getProgress());
         setMax((int) newMax);
@@ -226,13 +223,13 @@
 
     /**
      * Gets the step size of this rating bar.
-     * 
+     *
      * @return The step size.
      */
     public float getStepSize() {
         return (float) getNumStars() / getMax();
     }
-    
+
     /**
      * @return The amount of progress that fits into a star
      */
@@ -251,12 +248,12 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         // Keep secondary progress in sync with primary
-        updateSecondaryProgress(getProgress());
-        
+        updateSecondaryProgress(progress);
+
         if (!fromUser) {
             // Callback for non-user rating changes
             dispatchRatingChange(false);
@@ -267,7 +264,7 @@
      * The secondary progress is used to differentiate the background of a
      * partially filled star. This method keeps the secondary progress in sync
      * with the progress.
-     * 
+     *
      * @param progress The primary progress level.
      */
     private void updateSecondaryProgress(int progress) {
@@ -278,11 +275,11 @@
             setSecondaryProgress(secondaryProgress);
         }
     }
-    
+
     @Override
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        
+
         if (mSampleTile != null) {
             // TODO: Once ProgressBar's TODOs are gone, this can be done more
             // cleanly than mSampleTile
@@ -295,7 +292,7 @@
     @Override
     void onStartTrackingTouch() {
         mProgressOnStartTracking = getProgress();
-        
+
         super.onStartTrackingTouch();
     }
 
@@ -327,19 +324,12 @@
         if (max <= 0) {
             return;
         }
-        
+
         super.setMax(max);
     }
-    
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(RatingBar.class.getName());
-    }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(RatingBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RatingBar.class.getName();
     }
 }
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 5b604cd..d12739f 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -37,7 +37,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
@@ -201,7 +200,6 @@
     private static final int VALUE_NOT_SET = Integer.MIN_VALUE;
 
     private View mBaselineView = null;
-    private boolean mHasBaselineAlignedChild;
 
     private int mGravity = Gravity.START | Gravity.TOP;
     private final Rect mContentBounds = new Rect();
@@ -417,8 +415,6 @@
             height = myHeight;
         }
 
-        mHasBaselineAlignedChild = false;
-
         View ignore = null;
         int gravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
         final boolean horizontalGravity = gravity != Gravity.START && gravity != 0;
@@ -473,11 +469,11 @@
         final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
 
         for (int i = 0; i < count; i++) {
-            View child = views[i];
+            final View child = views[i];
             if (child.getVisibility() != GONE) {
-                LayoutParams params = (LayoutParams) child.getLayoutParams();
-                
-                applyVerticalSizeRules(params, myHeight);
+                final LayoutParams params = (LayoutParams) child.getLayoutParams();
+
+                applyVerticalSizeRules(params, myHeight, child.getBaseline());
                 measureChild(child, params, myWidth, myHeight);
                 if (positionChildVertical(child, params, myHeight, isWrapContentHeight)) {
                     offsetVerticalAxis = true;
@@ -519,25 +515,22 @@
             }
         }
 
-        if (mHasBaselineAlignedChild) {
-            for (int i = 0; i < count; i++) {
-                View child = getChildAt(i);
-                if (child.getVisibility() != GONE) {
-                    LayoutParams params = (LayoutParams) child.getLayoutParams();
-                    alignBaseline(child, params);
-
-                    if (child != ignore || verticalGravity) {
-                        left = Math.min(left, params.mLeft - params.leftMargin);
-                        top = Math.min(top, params.mTop - params.topMargin);
-                    }
-
-                    if (child != ignore || horizontalGravity) {
-                        right = Math.max(right, params.mRight + params.rightMargin);
-                        bottom = Math.max(bottom, params.mBottom + params.bottomMargin);
-                    }
+        // Use the top-start-most laid out view as the baseline. RTL offsets are
+        // applied later, so we can use the left-most edge as the starting edge.
+        View baselineView = null;
+        LayoutParams baselineParams = null;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams childParams = (LayoutParams) child.getLayoutParams();
+                if (baselineView == null || baselineParams == null
+                        || compareLayoutPosition(childParams, baselineParams) < 0) {
+                    baselineView = child;
+                    baselineParams = childParams;
                 }
             }
         }
+        mBaselineView = baselineView;
 
         if (isWrapContentWidth) {
             // Width already has left padding in it since it was calculated by looking at
@@ -638,39 +631,23 @@
                     params.mRight -= offsetWidth;
                 }
             }
-
         }
 
         setMeasuredDimension(width, height);
     }
 
-    private void alignBaseline(View child, LayoutParams params) {
-        final int layoutDirection = getLayoutDirection();
-        int[] rules = params.getRules(layoutDirection);
-        int anchorBaseline = getRelatedViewBaseline(rules, ALIGN_BASELINE);
-
-        if (anchorBaseline != -1) {
-            LayoutParams anchorParams = getRelatedViewParams(rules, ALIGN_BASELINE);
-            if (anchorParams != null) {
-                int offset = anchorParams.mTop + anchorBaseline;
-                int baseline = child.getBaseline();
-                if (baseline != -1) {
-                    offset -= baseline;
-                }
-                int height = params.mBottom - params.mTop;
-                params.mTop = offset;
-                params.mBottom = params.mTop + height;
-            }
+    /**
+     * @return a negative number if the top of {@code p1} is above the top of
+     *         {@code p2} or if they have identical top values and the left of
+     *         {@code p1} is to the left of {@code p2}, or a positive number
+     *         otherwise
+     */
+    private int compareLayoutPosition(LayoutParams p1, LayoutParams p2) {
+        final int topDiff = p1.mTop - p2.mTop;
+        if (topDiff != 0) {
+            return topDiff;
         }
-
-        if (mBaselineView == null) {
-            mBaselineView = child;
-        } else {
-            LayoutParams lp = (LayoutParams) mBaselineView.getLayoutParams();
-            if (params.mTop < lp.mTop || (params.mTop == lp.mTop && params.mLeft < lp.mLeft)) {
-                mBaselineView = child;
-            }
-        }
+        return p1.mLeft - p2.mLeft;
     }
 
     /**
@@ -950,8 +927,20 @@
         }
     }
 
-    private void applyVerticalSizeRules(LayoutParams childParams, int myHeight) {
-        int[] rules = childParams.getRules();
+    private void applyVerticalSizeRules(LayoutParams childParams, int myHeight, int myBaseline) {
+        final int[] rules = childParams.getRules();
+
+        // Baseline alignment overrides any explicitly specified top or bottom.
+        int baselineOffset = getRelatedViewBaselineOffset(rules);
+        if (baselineOffset != -1) {
+            if (myBaseline != -1) {
+                baselineOffset -= myBaseline;
+            }
+            childParams.mTop = baselineOffset;
+            childParams.mBottom = VALUE_NOT_SET;
+            return;
+        }
+
         RelativeLayout.LayoutParams anchorParams;
 
         childParams.mTop = VALUE_NOT_SET;
@@ -1000,10 +989,6 @@
                 childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
             }
         }
-
-        if (rules[ALIGN_BASELINE] != 0) {
-            mHasBaselineAlignedChild = true;
-        }
     }
 
     private View getRelatedView(int[] rules, int relation) {
@@ -1038,10 +1023,17 @@
         return null;
     }
 
-    private int getRelatedViewBaseline(int[] rules, int relation) {
-        View v = getRelatedView(rules, relation);
+    private int getRelatedViewBaselineOffset(int[] rules) {
+        final View v = getRelatedView(rules, ALIGN_BASELINE);
         if (v != null) {
-            return v.getBaseline();
+            final int baseline = v.getBaseline();
+            if (baseline != -1) {
+                final ViewGroup.LayoutParams params = v.getLayoutParams();
+                if (params instanceof LayoutParams) {
+                    final LayoutParams anchorParams = (LayoutParams) v.getLayoutParams();
+                    return anchorParams.mTop + baseline;
+                }
+            }
         }
         return -1;
     }
@@ -1104,8 +1096,9 @@
         return new LayoutParams(p);
     }
 
+    /** @hide */
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         if (mTopToBottomLeftToRightSet == null) {
             mTopToBottomLeftToRightSet = new TreeSet<View>(new TopToBottomLeftToRightComparator());
         }
@@ -1128,15 +1121,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(RelativeLayout.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(RelativeLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return RelativeLayout.class.getName();
     }
 
     /**
@@ -1387,6 +1373,7 @@
          *        {@link android.widget.RelativeLayout RelativeLayout}, such as
          *        ALIGN_WITH_PARENT_LEFT.
          * @see #addRule(int, int)
+         * @see #getRule(int)
          */
         public void addRule(int verb) {
             mRules[verb] = TRUE;
@@ -1407,6 +1394,7 @@
          *        for true or 0 for false).  For verbs that don't refer to another sibling
          *        (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
          * @see #addRule(int)
+         * @see #getRule(int)
          */
         public void addRule(int verb, int anchor) {
             mRules[verb] = anchor;
@@ -1422,6 +1410,7 @@
          *         ALIGN_WITH_PARENT_LEFT.
          * @see #addRule(int)
          * @see #addRule(int, int)
+         * @see #getRule(int)
          */
         public void removeRule(int verb) {
             mRules[verb] = 0;
@@ -1429,6 +1418,22 @@
             mRulesChanged = true;
         }
 
+        /**
+         * Returns the layout rule associated with a specific verb.
+         *
+         * @param verb one of the verbs defined by {@link RelativeLayout}, such
+         *             as ALIGN_WITH_PARENT_LEFT
+         * @return the id of another view to use as an anchor, a boolean value
+         *         (represented as {@link RelativeLayout#TRUE} for true
+         *         or 0 for false), or -1 for verbs that don't refer to another
+         *         sibling (for example, ALIGN_WITH_PARENT_BOTTOM)
+         * @see #addRule(int)
+         * @see #addRule(int, int)
+         */
+        public int getRule(int verb) {
+            return mRules[verb];
+        }
+
         private boolean hasRelativeRules() {
             return (mInitialRules[START_OF] != 0 || mInitialRules[END_OF] != 0 ||
                     mInitialRules[ALIGN_START] != 0 || mInitialRules[ALIGN_END] != 0 ||
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dd7fa18..a10be11 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
 import android.app.Application;
@@ -2263,7 +2264,7 @@
      * @param color Sets the text color for all the states (normal, selected,
      *            focused) to be this color.
      */
-    public void setTextColor(int viewId, int color) {
+    public void setTextColor(int viewId, @ColorInt int color) {
         setInt(viewId, "setTextColor", color);
     }
 
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 56bdb9b..349f3f0 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -26,14 +26,12 @@
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
diff --git a/core/java/android/widget/ResourceCursorAdapter.java b/core/java/android/widget/ResourceCursorAdapter.java
index 7341c2c..100f919 100644
--- a/core/java/android/widget/ResourceCursorAdapter.java
+++ b/core/java/android/widget/ResourceCursorAdapter.java
@@ -17,7 +17,9 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.Cursor;
+import android.view.ContextThemeWrapper;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
@@ -31,9 +33,10 @@
     private int mLayout;
 
     private int mDropDownLayout;
-    
+
     private LayoutInflater mInflater;
-    
+    private LayoutInflater mDropDownInflater;
+
     /**
      * Constructor the enables auto-requery.
      *
@@ -52,8 +55,9 @@
         super(context, c);
         mLayout = mDropDownLayout = layout;
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mDropDownInflater = mInflater;
     }
-    
+
     /**
      * Constructor with default behavior as per
      * {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended
@@ -74,6 +78,7 @@
         super(context, c, autoRequery);
         mLayout = mDropDownLayout = layout;
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mDropDownInflater = mInflater;
     }
 
     /**
@@ -91,11 +96,37 @@
         super(context, c, flags);
         mLayout = mDropDownLayout = layout;
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mDropDownInflater = mInflater;
+    }
+
+    /**
+     * Sets the {@link android.content.res.Resources.Theme} against which drop-down views are
+     * inflated.
+     * <p>
+     * By default, drop-down views are inflated against the theme of the
+     * {@link Context} passed to the adapter's constructor.
+     *
+     * @param theme the theme against which to inflate drop-down views or
+     *              {@code null} to use the theme from the adapter's context
+     * @see #newDropDownView(Context, Cursor, ViewGroup)
+     */
+    @Override
+    public void setDropDownViewTheme(Resources.Theme theme) {
+        super.setDropDownViewTheme(theme);
+
+        if (theme == null) {
+            mDropDownInflater = null;
+        } else if (theme == mInflater.getContext().getTheme()) {
+            mDropDownInflater = mInflater;
+        } else {
+            final Context context = new ContextThemeWrapper(mContext, theme);
+            mDropDownInflater = LayoutInflater.from(context);
+        }
     }
 
     /**
      * Inflates view(s) from the specified XML file.
-     * 
+     *
      * @see android.widget.CursorAdapter#newView(android.content.Context,
      *      android.database.Cursor, ViewGroup)
      */
@@ -106,7 +137,7 @@
 
     @Override
     public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
-        return mInflater.inflate(mDropDownLayout, parent, false);
+        return mDropDownInflater.inflate(mDropDownLayout, parent, false);
     }
 
     /**
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 8eff1aa..91d6232 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -23,63 +23,74 @@
 import android.graphics.drawable.Drawable;
 
 /**
- * This is only used by View for displaying its scroll bars.  It should probably
+ * This is only used by View for displaying its scroll bars. It should probably
  * be moved in to the view package since it is used in that lower-level layer.
  * For now, we'll hide it so it can be cleaned up later.
+ *
  * {@hide}
  */
-public class ScrollBarDrawable extends Drawable {
-    private static final int[] STATE_ENABLED = new int[] { android.R.attr.state_enabled };
-
+public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
     private Drawable mVerticalTrack;
     private Drawable mHorizontalTrack;
     private Drawable mVerticalThumb;
     private Drawable mHorizontalThumb;
+
     private int mRange;
     private int mOffset;
     private int mExtent;
+
     private boolean mVertical;
-    private boolean mChanged;
+    private boolean mBoundsChanged;
     private boolean mRangeChanged;
-    private final Rect mTempBounds = new Rect();
     private boolean mAlwaysDrawHorizontalTrack;
     private boolean mAlwaysDrawVerticalTrack;
     private boolean mMutated;
 
-    public ScrollBarDrawable() {
-    }
+    private int mAlpha = 255;
+    private boolean mHasSetAlpha;
+
+    private ColorFilter mColorFilter;
+    private boolean mHasSetColorFilter;
 
     /**
-     * Indicate whether the horizontal scrollbar track should always be drawn regardless of the
-     * extent. Defaults to false.
+     * Indicate whether the horizontal scrollbar track should always be drawn
+     * regardless of the extent. Defaults to false.
      *
-     * @param alwaysDrawTrack Set to true if the track should always be drawn
+     * @param alwaysDrawTrack Whether the track should always be drawn
+     *
+     * @see #getAlwaysDrawHorizontalTrack()
      */
     public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) {
         mAlwaysDrawHorizontalTrack = alwaysDrawTrack;
     }
 
     /**
-     * Indicate whether the vertical scrollbar track should always be drawn regardless of the
-     * extent. Defaults to false.
+     * Indicate whether the vertical scrollbar track should always be drawn
+     * regardless of the extent. Defaults to false.
      *
-     * @param alwaysDrawTrack Set to true if the track should always be drawn
+     * @param alwaysDrawTrack Whether the track should always be drawn
+     *
+     * @see #getAlwaysDrawVerticalTrack()
      */
     public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) {
         mAlwaysDrawVerticalTrack = alwaysDrawTrack;
     }
 
     /**
-     * Indicates whether the vertical scrollbar track should always be drawn regardless of the
-     * extent.
+     * @return whether the vertical scrollbar track should always be drawn
+     *         regardless of the extent.
+     *
+     * @see #setAlwaysDrawVerticalTrack(boolean)
      */
     public boolean getAlwaysDrawVerticalTrack() {
         return mAlwaysDrawVerticalTrack;
     }
 
     /**
-     * Indicates whether the horizontal scrollbar track should always be drawn regardless of the
-     * extent.
+     * @return whether the horizontal scrollbar track should always be drawn
+     *         regardless of the extent.
+     *
+     * @see #setAlwaysDrawHorizontalTrack(boolean)
      */
     public boolean getAlwaysDrawHorizontalTrack() {
         return mAlwaysDrawHorizontalTrack;
@@ -87,17 +98,18 @@
 
     public void setParameters(int range, int offset, int extent, boolean vertical) {
         if (mVertical != vertical) {
-            mChanged = true;
+            mVertical = vertical;
+
+            mBoundsChanged = true;
         }
 
         if (mRange != range || mOffset != offset || mExtent != extent) {
+            mRange = range;
+            mOffset = offset;
+            mExtent = extent;
+
             mRangeChanged = true;
         }
-
-        mRange = range;
-        mOffset = offset;
-        mExtent = extent;
-        mVertical = vertical;
     }
 
     @Override
@@ -113,27 +125,29 @@
             drawThumb = false;
         }
 
-        Rect r = getBounds();
+        final Rect r = getBounds();
         if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) {
             return;
         }
+
         if (drawTrack) {
             drawTrack(canvas, r, vertical);
         }
 
         if (drawThumb) {
-            int size = vertical ? r.height() : r.width();
-            int thickness = vertical ? r.width() : r.height();
-            int length = Math.round((float) size * extent / range);
-            int offset = Math.round((float) (size - length) * mOffset / (range - extent));
+            final int size = vertical ? r.height() : r.width();
+            final int thickness = vertical ? r.width() : r.height();
+            final int minLength = thickness * 2;
 
-            // avoid the tiny thumb
-            int minLength = thickness * 2;
+            // Avoid the tiny thumb.
+            int length = Math.round((float) size * extent / range);
             if (length < minLength) {
                 length = minLength;
             }
-            // avoid the too-big thumb
-            if (offset + length > size) {
+
+            // Avoid the too-big thumb.
+            int offset = Math.round((float) (size - length) * mOffset / (range - extent));
+            if (offset > size - length) {
                 offset = size - length;
             }
 
@@ -144,92 +158,132 @@
     @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
-        mChanged = true;
+        mBoundsChanged = true;
     }
 
-    protected void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
-        Drawable track;
+    @Override
+    public boolean isStateful() {
+        return (mVerticalTrack != null && mVerticalTrack.isStateful())
+                || (mVerticalThumb != null && mVerticalThumb.isStateful())
+                || (mHorizontalTrack != null && mHorizontalTrack.isStateful())
+                || (mHorizontalThumb != null && mHorizontalThumb.isStateful())
+                || super.isStateful();
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        boolean changed = super.onStateChange(state);
+        if (mVerticalTrack != null) {
+            changed |= mVerticalTrack.setState(state);
+        }
+        if (mVerticalThumb != null) {
+            changed |= mVerticalThumb.setState(state);
+        }
+        if (mHorizontalTrack != null) {
+            changed |= mHorizontalTrack.setState(state);
+        }
+        if (mHorizontalThumb != null) {
+            changed |= mHorizontalThumb.setState(state);
+        }
+        return changed;
+    }
+
+    private void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
+        final Drawable track;
         if (vertical) {
             track = mVerticalTrack;
         } else {
             track = mHorizontalTrack;
         }
+
         if (track != null) {
-            if (mChanged) {
+            if (mBoundsChanged) {
                 track.setBounds(bounds);
             }
             track.draw(canvas);
         }
     }
 
-    protected void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
-        final Rect thumbRect = mTempBounds;
-        final boolean changed = mRangeChanged || mChanged;
-        if (changed) {
-            if (vertical) {
-                thumbRect.set(bounds.left,  bounds.top + offset,
-                        bounds.right, bounds.top + offset + length);
-            } else {
-                thumbRect.set(bounds.left + offset, bounds.top,
-                        bounds.left + offset + length, bounds.bottom);
-            }
-        }
-
+    private void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
+        final boolean changed = mRangeChanged || mBoundsChanged;
         if (vertical) {
             if (mVerticalThumb != null) {
                 final Drawable thumb = mVerticalThumb;
-                if (changed) thumb.setBounds(thumbRect);
+                if (changed) {
+                    thumb.setBounds(bounds.left, bounds.top + offset,
+                            bounds.right, bounds.top + offset + length);
+                }
+
                 thumb.draw(canvas);
             }
         } else {
             if (mHorizontalThumb != null) {
                 final Drawable thumb = mHorizontalThumb;
-                if (changed) thumb.setBounds(thumbRect);
+                if (changed) {
+                    thumb.setBounds(bounds.left + offset, bounds.top,
+                            bounds.left + offset + length, bounds.bottom);
+                }
+
                 thumb.draw(canvas);
             }
         }
     }
 
     public void setVerticalThumbDrawable(Drawable thumb) {
-        if (thumb != null) {
-            if (mMutated) {
-                thumb.mutate();
-            }
-            thumb.setState(STATE_ENABLED);
-            mVerticalThumb = thumb;
+        if (mVerticalThumb != null) {
+            mVerticalThumb.setCallback(null);
         }
+
+        propagateCurrentState(thumb);
+        mVerticalThumb = thumb;
     }
 
     public void setVerticalTrackDrawable(Drawable track) {
-        if (track != null) {
-            if (mMutated) {
-                track.mutate();
-            }
-            track.setState(STATE_ENABLED);
+        if (mVerticalTrack != null) {
+            mVerticalTrack.setCallback(null);
         }
+
+        propagateCurrentState(track);
         mVerticalTrack = track;
     }
 
     public void setHorizontalThumbDrawable(Drawable thumb) {
-        if (thumb != null) {
-            if (mMutated) {
-                thumb.mutate();
-            }
-            thumb.setState(STATE_ENABLED);
-            mHorizontalThumb = thumb;
+        if (mHorizontalThumb != null) {
+            mHorizontalThumb.setCallback(null);
         }
+
+        propagateCurrentState(thumb);
+        mHorizontalThumb = thumb;
     }
 
     public void setHorizontalTrackDrawable(Drawable track) {
-        if (track != null) {
-            if (mMutated) {
-                track.mutate();
-            }
-            track.setState(STATE_ENABLED);
+        if (mHorizontalTrack != null) {
+            mHorizontalTrack.setCallback(null);
         }
+
+        propagateCurrentState(track);
         mHorizontalTrack = track;
     }
 
+    private void propagateCurrentState(Drawable d) {
+        if (d != null) {
+            if (mMutated) {
+                d.mutate();
+            }
+
+            d.setState(getState());
+            d.setCallback(this);
+
+            if (mHasSetAlpha) {
+                d.setAlpha(mAlpha);
+            }
+
+            if (mHasSetColorFilter) {
+                d.setColorFilter(mColorFilter);
+            }
+        }
+    }
+
     public int getSize(boolean vertical) {
         if (vertical) {
             return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() :
@@ -262,6 +316,9 @@
 
     @Override
     public void setAlpha(int alpha) {
+        mAlpha = alpha;
+        mHasSetAlpha = true;
+
         if (mVerticalTrack != null) {
             mVerticalTrack.setAlpha(alpha);
         }
@@ -278,32 +335,54 @@
 
     @Override
     public int getAlpha() {
-        // All elements should have same alpha, just return one of them
-        return mVerticalThumb.getAlpha();
+        return mAlpha;
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
+    public void setColorFilter(ColorFilter colorFilter) {
+        mColorFilter = colorFilter;
+        mHasSetColorFilter = true;
+
         if (mVerticalTrack != null) {
-            mVerticalTrack.setColorFilter(cf);
+            mVerticalTrack.setColorFilter(colorFilter);
         }
         if (mVerticalThumb != null) {
-            mVerticalThumb.setColorFilter(cf);
+            mVerticalThumb.setColorFilter(colorFilter);
         }
         if (mHorizontalTrack != null) {
-            mHorizontalTrack.setColorFilter(cf);
+            mHorizontalTrack.setColorFilter(colorFilter);
         }
         if (mHorizontalThumb != null) {
-            mHorizontalThumb.setColorFilter(cf);
+            mHorizontalThumb.setColorFilter(colorFilter);
         }
     }
 
     @Override
+    public ColorFilter getColorFilter() {
+        return mColorFilter;
+    }
+
+    @Override
     public int getOpacity() {
         return PixelFormat.TRANSLUCENT;
     }
 
     @Override
+    public void invalidateDrawable(Drawable who) {
+        invalidateSelf();
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        scheduleSelf(what, when);
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        unscheduleSelf(what);
+    }
+
+    @Override
     public String toString() {
         return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset +
                " extent=" + mExtent + (mVertical ? " V" : " H");
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a90b392..b95c27d 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -809,9 +809,10 @@
         awakenScrollBars();
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         if (!isEnabled()) {
@@ -839,9 +840,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ScrollView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ScrollView.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         if (isEnabled()) {
             final int scrollRange = getScrollRange();
             if (scrollRange > 0) {
@@ -856,10 +862,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ScrollView.class.getName());
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         final boolean scrollable = getScrollRange() > 0;
         event.setScrollable(scrollable);
         event.setScrollX(mScrollX);
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 5e88a96..357c9c3 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.os.Build;
-import android.util.FloatMath;
 import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -425,7 +424,7 @@
 
             float dx = (float) (mFinalX - mStartX);
             float dy = (float) (mFinalY - mStartY);
-            float hyp = FloatMath.sqrt(dx * dx + dy * dy);
+            float hyp = (float) Math.hypot(dx, dy);
 
             float ndx = dx / hyp;
             float ndy = dy / hyp;
@@ -442,7 +441,7 @@
         mMode = FLING_MODE;
         mFinished = false;
 
-        float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
+        float velocity = (float) Math.hypot(velocityX, velocityY);
      
         mVelocity = velocity;
         mDuration = getSplineFlingDuration(velocity);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 4ee6418..bbf120a 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -49,8 +49,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView.OnItemClickListener;
@@ -1326,15 +1324,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(SearchView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(SearchView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SearchView.class.getName();
     }
 
     private void adjustDropDownSizeAndPosition() {
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index dc7c04c..d010122 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -18,15 +18,13 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 
 
 /**
  * A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch
  * the thumb and drag left or right to set the current progress level or use the arrow keys.
- * Placing focusable widgets to the left or right of a SeekBar is discouraged. 
+ * Placing focusable widgets to the left or right of a SeekBar is discouraged.
  * <p>
  * Clients of the SeekBar can attach a {@link SeekBar.OnSeekBarChangeListener} to
  * be notified of the user's actions.
@@ -42,39 +40,39 @@
      * programmatically.
      */
     public interface OnSeekBarChangeListener {
-        
+
         /**
          * Notification that the progress level has changed. Clients can use the fromUser parameter
          * to distinguish user-initiated changes from those that occurred programmatically.
-         * 
+         *
          * @param seekBar The SeekBar whose progress has changed
          * @param progress The current progress level. This will be in the range 0..max where max
          *        was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)
          * @param fromUser True if the progress change was initiated by the user.
          */
         void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);
-    
+
         /**
          * Notification that the user has started a touch gesture. Clients may want to use this
-         * to disable advancing the seekbar. 
+         * to disable advancing the seekbar.
          * @param seekBar The SeekBar in which the touch gesture began
          */
         void onStartTrackingTouch(SeekBar seekBar);
-        
+
         /**
          * Notification that the user has finished a touch gesture. Clients may want to use this
-         * to re-enable advancing the seekbar. 
+         * to re-enable advancing the seekbar.
          * @param seekBar The SeekBar in which the touch gesture began
          */
         void onStopTrackingTouch(SeekBar seekBar);
     }
 
     private OnSeekBarChangeListener mOnSeekBarChangeListener;
-    
+
     public SeekBar(Context context) {
         this(context, null);
     }
-    
+
     public SeekBar(Context context, AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.seekBarStyle);
     }
@@ -88,26 +86,26 @@
     }
 
     @Override
-    void onProgressRefresh(float scale, boolean fromUser) {
-        super.onProgressRefresh(scale, fromUser);
+    void onProgressRefresh(float scale, boolean fromUser, int progress) {
+        super.onProgressRefresh(scale, fromUser, progress);
 
         if (mOnSeekBarChangeListener != null) {
-            mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
+            mOnSeekBarChangeListener.onProgressChanged(this, progress, fromUser);
         }
     }
 
     /**
      * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
      * provides notifications of when the user starts and stops a touch gesture within the SeekBar.
-     * 
+     *
      * @param l The seek bar notification listener
-     * 
+     *
      * @see SeekBar.OnSeekBarChangeListener
      */
     public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
         mOnSeekBarChangeListener = l;
     }
-    
+
     @Override
     void onStartTrackingTouch() {
         super.onStartTrackingTouch();
@@ -115,7 +113,7 @@
             mOnSeekBarChangeListener.onStartTrackingTouch(this);
         }
     }
-    
+
     @Override
     void onStopTrackingTouch() {
         super.onStopTrackingTouch();
@@ -125,14 +123,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(SeekBar.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(SeekBar.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SeekBar.class.getName();
     }
 }
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 98bcfff..a656712 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -17,6 +17,8 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.view.ContextThemeWrapper;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
@@ -40,14 +42,14 @@
  * If the returned value is false, the following views are then tried in order:
  * <ul>
  * <li> A view that implements Checkable (e.g. CheckBox).  The expected bind value is a boolean.
- * <li> TextView.  The expected bind value is a string and {@link #setViewText(TextView, String)} 
+ * <li> TextView.  The expected bind value is a string and {@link #setViewText(TextView, String)}
  * is invoked.
- * <li> ImageView. The expected bind value is a resource id or a string and 
- * {@link #setViewImage(ImageView, int)} or {@link #setViewImage(ImageView, String)} is invoked. 
+ * <li> ImageView. The expected bind value is a resource id or a string and
+ * {@link #setViewImage(ImageView, int)} or {@link #setViewImage(ImageView, String)} is invoked.
  * </ul>
  * If no appropriate binding can be found, an {@link IllegalStateException} is thrown.
  */
-public class SimpleAdapter extends BaseAdapter implements Filterable {
+public class SimpleAdapter extends BaseAdapter implements Filterable, Spinner.ThemedSpinnerAdapter {
     private int[] mTo;
     private String[] mFrom;
     private ViewBinder mViewBinder;
@@ -58,12 +60,15 @@
     private int mDropDownResource;
     private LayoutInflater mInflater;
 
+    /** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */
+    private LayoutInflater mDropDownInflater;
+
     private SimpleFilter mFilter;
     private ArrayList<Map<String, ?>> mUnfilteredData;
 
     /**
      * Constructor
-     * 
+     *
      * @param context The context where the View associated with this SimpleAdapter is running
      * @param data A List of Maps. Each entry in the List corresponds to one row in the list. The
      *        Maps contain the data for each row, and should include all the entries specified in
@@ -85,7 +90,6 @@
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     }
 
-    
     /**
      * @see android.widget.Adapter#getCount()
      */
@@ -111,14 +115,14 @@
      * @see android.widget.Adapter#getView(int, View, ViewGroup)
      */
     public View getView(int position, View convertView, ViewGroup parent) {
-        return createViewFromResource(position, convertView, parent, mResource);
+        return createViewFromResource(mInflater, position, convertView, parent, mResource);
     }
 
-    private View createViewFromResource(int position, View convertView,
+    private View createViewFromResource(LayoutInflater inflater, int position, View convertView,
             ViewGroup parent, int resource) {
         View v;
         if (convertView == null) {
-            v = mInflater.inflate(resource, parent, false);
+            v = inflater.inflate(resource, parent, false);
         } else {
             v = convertView;
         }
@@ -135,12 +139,41 @@
      * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
      */
     public void setDropDownViewResource(int resource) {
-        this.mDropDownResource = resource;
+        mDropDownResource = resource;
+    }
+
+    /**
+     * Sets the {@link android.content.res.Resources.Theme} against which drop-down views are
+     * inflated.
+     * <p>
+     * By default, drop-down views are inflated against the theme of the
+     * {@link Context} passed to the adapter's constructor.
+     *
+     * @param theme the theme against which to inflate drop-down views or
+     *              {@code null} to use the theme from the adapter's context
+     * @see #getDropDownView(int, View, ViewGroup)
+     */
+    @Override
+    public void setDropDownViewTheme(Resources.Theme theme) {
+        if (theme == null) {
+            mDropDownInflater = null;
+        } else if (theme == mInflater.getContext().getTheme()) {
+            mDropDownInflater = mInflater;
+        } else {
+            final Context context = new ContextThemeWrapper(mInflater.getContext(), theme);
+            mDropDownInflater = LayoutInflater.from(context);
+        }
+    }
+
+    @Override
+    public Resources.Theme getDropDownViewTheme() {
+        return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
     }
 
     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
-        return createViewFromResource(position, convertView, parent, mDropDownResource);
+        return createViewFromResource(
+                mDropDownInflater, position, convertView, parent, mDropDownResource);
     }
 
     private void bindView(int position, View view) {
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
index 24ebb2c..c807d56 100644
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ b/core/java/android/widget/SimpleMonthAdapter.java
@@ -39,6 +39,7 @@
 
     private Calendar mSelectedDay = Calendar.getInstance();
     private ColorStateList mCalendarTextColors = ColorStateList.valueOf(Color.BLACK);
+    private ColorStateList mCalendarDayBackgroundColor = ColorStateList.valueOf(Color.MAGENTA);
     private OnDaySelectedListener mOnDaySelectedListener;
 
     private int mFirstDayOfWeek;
@@ -88,6 +89,10 @@
         mCalendarTextColors = colors;
     }
 
+    void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) {
+        mCalendarDayBackgroundColor = dayBackgroundColor;
+    }
+
     /**
      * Sets the text color, size, style, hint color, and highlight color from
      * the specified TextAppearance resource. This is mostly copied from
@@ -144,9 +149,11 @@
             v.setClickable(true);
             v.setOnDayClickListener(mOnDayClickListener);
 
-            if (mCalendarTextColors != null) {
-                v.setTextColor(mCalendarTextColors);
-            }
+            v.setMonthTextColor(mCalendarTextColors);
+            v.setDayOfWeekTextColor(mCalendarTextColors);
+            v.setDayTextColor(mCalendarTextColors);
+
+            v.setDayBackgroundColor(mCalendarDayBackgroundColor);
         }
 
         final int minMonth = mMinDate.get(Calendar.MONTH);
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index d2a37ac..58ad515 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -27,12 +27,13 @@
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.os.Bundle;
+import android.text.TextPaint;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.AttributeSet;
 import android.util.IntArray;
-import android.util.MathUtils;
+import android.util.StateSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -44,7 +45,6 @@
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Formatter;
-import java.util.List;
 import java.util.Locale;
 
 /**
@@ -52,8 +52,7 @@
  * within the specified month.
  */
 class SimpleMonthView extends View {
-    private static final int DEFAULT_HEIGHT = 32;
-    private static final int MIN_HEIGHT = 10;
+    private static final int MIN_ROW_HEIGHT = 10;
 
     private static final int DEFAULT_SELECTED_DAY = -1;
     private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
@@ -61,18 +60,21 @@
     private static final int DEFAULT_NUM_ROWS = 6;
     private static final int MAX_NUM_ROWS = 6;
 
-    private static final int SELECTED_CIRCLE_ALPHA = 60;
-
-    private static final int DAY_SEPARATOR_WIDTH = 1;
-
     private final Formatter mFormatter;
     private final StringBuilder mStringBuilder;
 
-    private final int mMiniDayNumberTextSize;
-    private final int mMonthLabelTextSize;
-    private final int mMonthDayLabelTextSize;
-    private final int mMonthHeaderSize;
-    private final int mDaySelectedCircleSize;
+    private final int mMonthTextSize;
+    private final int mDayOfWeekTextSize;
+    private final int mDayTextSize;
+
+    /** Height of the header containing the month and day of week labels. */
+    private final int mMonthHeaderHeight;
+
+    private final TextPaint mMonthPaint = new TextPaint();
+    private final TextPaint mDayOfWeekPaint = new TextPaint();
+    private final TextPaint mDayPaint = new TextPaint();
+
+    private final Paint mDayBackgroundPaint = new Paint();
 
     /** Single-letter (when available) formatter for the day of week label. */
     private SimpleDateFormat mDayFormatter = new SimpleDateFormat("EEEEE", Locale.getDefault());
@@ -81,14 +83,7 @@
     private int mPadding = 0;
 
     private String mDayOfWeekTypeface;
-    private String mMonthTitleTypeface;
-
-    private Paint mDayNumberPaint;
-    private Paint mDayNumberDisabledPaint;
-    private Paint mDayNumberSelectedPaint;
-
-    private Paint mMonthTitlePaint;
-    private Paint mMonthDayLabelPaint;
+    private String mMonthTypeface;
 
     private int mMonth;
     private int mYear;
@@ -97,13 +92,13 @@
     private int mWidth;
 
     // The height this view should draw at in pixels, set by height param
-    private int mRowHeight = DEFAULT_HEIGHT;
+    private final int mRowHeight;
 
     // If this view contains the today
     private boolean mHasToday = false;
 
     // Which day is selected [0-6] or -1 if no day is selected
-    private int mSelectedDay = -1;
+    private int mActivatedDay = -1;
 
     // Which day is today [0-6] or -1 if no day is today
     private int mToday = DEFAULT_SELECTED_DAY;
@@ -142,6 +137,8 @@
     private int mDisabledTextColor;
     private int mSelectedDayColor;
 
+    private ColorStateList mDayTextColor;
+
     public SimpleMonthView(Context context) {
         this(context, null);
     }
@@ -159,22 +156,21 @@
 
         final Resources res = context.getResources();
         mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface);
-        mMonthTitleTypeface = res.getString(R.string.sans_serif);
+        mMonthTypeface = res.getString(R.string.sans_serif);
 
         mStringBuilder = new StringBuilder(50);
         mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
 
-        mMiniDayNumberTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size);
-        mMonthLabelTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size);
-        mMonthDayLabelTextSize = res.getDimensionPixelSize(
+        mDayTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size);
+        mMonthTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size);
+        mDayOfWeekTextSize = res.getDimensionPixelSize(
                 R.dimen.datepicker_month_day_label_text_size);
-        mMonthHeaderSize = res.getDimensionPixelOffset(
+        mMonthHeaderHeight = res.getDimensionPixelOffset(
                 R.dimen.datepicker_month_list_item_header_height);
-        mDaySelectedCircleSize = res.getDimensionPixelSize(
-                R.dimen.datepicker_day_number_select_circle_radius);
 
-        mRowHeight = (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height)
-                - mMonthHeaderSize) / MAX_NUM_ROWS;
+        mRowHeight = Math.max(MIN_ROW_HEIGHT,
+                (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height)
+                        - mMonthHeaderHeight) / MAX_NUM_ROWS);
 
         // Set up accessibility components.
         mTouchHelper = new MonthViewTouchHelper(this);
@@ -182,8 +178,32 @@
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         mLockAccessibilityDelegate = true;
 
-        // Sets up any standard paints that will be used
-        initView();
+        initPaints();
+    }
+
+    /**
+     * Sets up the text and style properties for painting.
+     */
+    private void initPaints() {
+        mMonthPaint.setAntiAlias(true);
+        mMonthPaint.setTextSize(mMonthTextSize);
+        mMonthPaint.setTypeface(Typeface.create(mMonthTypeface, Typeface.BOLD));
+        mMonthPaint.setTextAlign(Align.CENTER);
+        mMonthPaint.setStyle(Style.FILL);
+
+        mDayOfWeekPaint.setAntiAlias(true);
+        mDayOfWeekPaint.setTextSize(mDayOfWeekTextSize);
+        mDayOfWeekPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.BOLD));
+        mDayOfWeekPaint.setTextAlign(Align.CENTER);
+        mDayOfWeekPaint.setStyle(Style.FILL);
+
+        mDayBackgroundPaint.setAntiAlias(true);
+        mDayBackgroundPaint.setStyle(Style.FILL);
+
+        mDayPaint.setAntiAlias(true);
+        mDayPaint.setTextSize(mDayTextSize);
+        mDayPaint.setTextAlign(Align.CENTER);
+        mDayPaint.setStyle(Style.FILL);
     }
 
     @Override
@@ -193,22 +213,28 @@
         mDayFormatter = new SimpleDateFormat("EEEEE", newConfig.locale);
     }
 
-    void setTextColor(ColorStateList colors) {
-        final Resources res = getContext().getResources();
+    void setMonthTextColor(ColorStateList monthTextColor) {
+        final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0);
+        mMonthPaint.setColor(enabledColor);
+        invalidate();
+    }
 
-        mNormalTextColor = colors.getColorForState(ENABLED_STATE_SET,
-                res.getColor(R.color.datepicker_default_normal_text_color_holo_light));
-        mMonthTitlePaint.setColor(mNormalTextColor);
-        mMonthDayLabelPaint.setColor(mNormalTextColor);
+    void setDayOfWeekTextColor(ColorStateList dayOfWeekTextColor) {
+        final int enabledColor = dayOfWeekTextColor.getColorForState(ENABLED_STATE_SET, 0);
+        mDayOfWeekPaint.setColor(enabledColor);
+        invalidate();
+    }
 
-        mDisabledTextColor = colors.getColorForState(EMPTY_STATE_SET,
-                res.getColor(R.color.datepicker_default_disabled_text_color_holo_light));
-        mDayNumberDisabledPaint.setColor(mDisabledTextColor);
+    void setDayTextColor(ColorStateList dayTextColor) {
+        mDayTextColor = dayTextColor;
+        invalidate();
+    }
 
-        mSelectedDayColor = colors.getColorForState(ENABLED_SELECTED_STATE_SET,
-                res.getColor(R.color.holo_blue_light));
-        mDayNumberSelectedPaint.setColor(mSelectedDayColor);
-        mDayNumberSelectedPaint.setAlpha(SELECTED_CIRCLE_ALPHA);
+    void setDayBackgroundColor(ColorStateList dayBackgroundColor) {
+        final int activatedColor = dayBackgroundColor.getColorForState(
+                StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
+        mDayBackgroundPaint.setColor(activatedColor);
+        invalidate();
     }
 
     @Override
@@ -246,52 +272,6 @@
         return true;
     }
 
-    /**
-     * Sets up the text and style properties for painting.
-     */
-    private void initView() {
-        mMonthTitlePaint = new Paint();
-        mMonthTitlePaint.setAntiAlias(true);
-        mMonthTitlePaint.setColor(mNormalTextColor);
-        mMonthTitlePaint.setTextSize(mMonthLabelTextSize);
-        mMonthTitlePaint.setTypeface(Typeface.create(mMonthTitleTypeface, Typeface.BOLD));
-        mMonthTitlePaint.setTextAlign(Align.CENTER);
-        mMonthTitlePaint.setStyle(Style.FILL);
-        mMonthTitlePaint.setFakeBoldText(true);
-
-        mMonthDayLabelPaint = new Paint();
-        mMonthDayLabelPaint.setAntiAlias(true);
-        mMonthDayLabelPaint.setColor(mNormalTextColor);
-        mMonthDayLabelPaint.setTextSize(mMonthDayLabelTextSize);
-        mMonthDayLabelPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.NORMAL));
-        mMonthDayLabelPaint.setTextAlign(Align.CENTER);
-        mMonthDayLabelPaint.setStyle(Style.FILL);
-        mMonthDayLabelPaint.setFakeBoldText(true);
-
-        mDayNumberSelectedPaint = new Paint();
-        mDayNumberSelectedPaint.setAntiAlias(true);
-        mDayNumberSelectedPaint.setColor(mSelectedDayColor);
-        mDayNumberSelectedPaint.setAlpha(SELECTED_CIRCLE_ALPHA);
-        mDayNumberSelectedPaint.setTextAlign(Align.CENTER);
-        mDayNumberSelectedPaint.setStyle(Style.FILL);
-        mDayNumberSelectedPaint.setFakeBoldText(true);
-
-        mDayNumberPaint = new Paint();
-        mDayNumberPaint.setAntiAlias(true);
-        mDayNumberPaint.setTextSize(mMiniDayNumberTextSize);
-        mDayNumberPaint.setTextAlign(Align.CENTER);
-        mDayNumberPaint.setStyle(Style.FILL);
-        mDayNumberPaint.setFakeBoldText(false);
-
-        mDayNumberDisabledPaint = new Paint();
-        mDayNumberDisabledPaint.setAntiAlias(true);
-        mDayNumberDisabledPaint.setColor(mDisabledTextColor);
-        mDayNumberDisabledPaint.setTextSize(mMiniDayNumberTextSize);
-        mDayNumberDisabledPaint.setTextAlign(Align.CENTER);
-        mDayNumberDisabledPaint.setStyle(Style.FILL);
-        mDayNumberDisabledPaint.setFakeBoldText(false);
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         drawMonthTitle(canvas);
@@ -323,11 +303,7 @@
      */
     void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
             int enabledDayEnd) {
-        if (mRowHeight < MIN_HEIGHT) {
-            mRowHeight = MIN_HEIGHT;
-        }
-
-        mSelectedDay = selectedDay;
+        mActivatedDay = selectedDay;
 
         if (isValidMonth(month)) {
             mMonth = month;
@@ -415,7 +391,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
-                + mMonthHeaderSize);
+                + mMonthHeaderHeight);
     }
 
     @Override
@@ -437,21 +413,28 @@
 
     private void drawMonthTitle(Canvas canvas) {
         final float x = (mWidth + 2 * mPadding) / 2f;
-        final float y = (mMonthHeaderSize - mMonthDayLabelTextSize) / 2f;
-        canvas.drawText(getMonthAndYearString(), x, y, mMonthTitlePaint);
+
+        // Centered on the upper half of the month header.
+        final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent();
+        final float y = mMonthHeaderHeight * 0.25f - lineHeight / 2f;
+
+        canvas.drawText(getMonthAndYearString(), x, y, mMonthPaint);
     }
 
     private void drawWeekDayLabels(Canvas canvas) {
-        final int y = mMonthHeaderSize - (mMonthDayLabelTextSize / 2);
-        final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
+        final float dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
+
+        // Centered on the lower half of the month header.
+        final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
+        final float y = mMonthHeaderHeight * 0.75f - lineHeight / 2f;
 
         for (int i = 0; i < mNumDays; i++) {
             final int calendarDay = (i + mWeekStart) % mNumDays;
             mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
 
             final String dayLabel = mDayFormatter.format(mDayLabelCalendar.getTime());
-            final int x = (2 * i + 1) * dayWidthHalf + mPadding;
-            canvas.drawText(dayLabel, x, y, mMonthDayLabelPaint);
+            final float x = (2 * i + 1) * dayWidthHalf + mPadding;
+            canvas.drawText(dayLabel, x, y, mDayOfWeekPaint);
         }
     }
 
@@ -459,26 +442,40 @@
      * Draws the month days.
      */
     private void drawDays(Canvas canvas) {
-        int y = (((mRowHeight + mMiniDayNumberTextSize) / 2) - DAY_SEPARATOR_WIDTH)
-                + mMonthHeaderSize;
-        int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
-        int j = findDayOffset();
-        for (int day = 1; day <= mNumCells; day++) {
-            int x = (2 * j + 1) * dayWidthHalf + mPadding;
-            if (mSelectedDay == day) {
-                canvas.drawCircle(x, y - (mMiniDayNumberTextSize / 3), mDaySelectedCircleSize,
-                        mDayNumberSelectedPaint);
+        final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
+
+        // Centered within the row.
+        final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
+        float y = mMonthHeaderHeight + (mRowHeight - lineHeight) / 2f;
+
+        for (int day = 1, j = findDayOffset(); day <= mNumCells; day++) {
+            final int x = (2 * j + 1) * dayWidthHalf + mPadding;
+            int stateMask = 0;
+
+            if (day >= mEnabledDayStart && day <= mEnabledDayEnd) {
+                stateMask |= StateSet.VIEW_STATE_ENABLED;
             }
 
-            if (mHasToday && mToday == day) {
-                mDayNumberPaint.setColor(mSelectedDayColor);
-            } else {
-                mDayNumberPaint.setColor(mNormalTextColor);
+            if (mActivatedDay == day) {
+                stateMask |= StateSet.VIEW_STATE_ACTIVATED;
+
+                // Adjust the circle to be centered the row.
+                final float rowCenterY = y + lineHeight / 2;
+                canvas.drawCircle(x, rowCenterY, mRowHeight / 2,
+                        mDayBackgroundPaint);
             }
-            final Paint paint = (day < mEnabledDayStart || day > mEnabledDayEnd) ?
-                    mDayNumberDisabledPaint : mDayNumberPaint;
-            canvas.drawText(String.format("%d", day), x, y, paint);
+
+            final int[] stateSet = StateSet.get(stateMask);
+            final int dayTextColor = mDayTextColor.getColorForState(stateSet, 0);
+            mDayPaint.setColor(dayTextColor);
+
+            final boolean isDayToday = mHasToday && mToday == day;
+            mDayPaint.setFakeBoldText(isDayToday);
+
+            canvas.drawText(String.format("%d", day), x, y, mDayPaint);
+
             j++;
+
             if (j == mNumDays) {
                 j = 0;
                 y += mRowHeight;
@@ -504,7 +501,7 @@
             return -1;
         }
         // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
-        int row = (int) (y - mMonthHeaderSize) / mRowHeight;
+        int row = (int) (y - mMonthHeaderHeight) / mRowHeight;
         int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
 
         int day = column - findDayOffset() + 1;
@@ -628,7 +625,7 @@
             node.setBoundsInParent(mTempRect);
             node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
 
-            if (virtualViewId == mSelectedDay) {
+            if (virtualViewId == mActivatedDay) {
                 node.setSelected(true);
             }
 
@@ -654,7 +651,7 @@
          */
         private void getItemBounds(int day, Rect rect) {
             final int offsetX = mPadding;
-            final int offsetY = mMonthHeaderSize;
+            final int offsetY = mMonthHeaderHeight;
             final int cellHeight = mRowHeight;
             final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays);
             final int index = ((day - 1) + findDayOffset());
@@ -679,7 +676,7 @@
             final CharSequence date = DateFormat.format(DATE_FORMAT,
                     mTempCalendar.getTimeInMillis());
 
-            if (day == mSelectedDay) {
+            if (day == mActivatedDay) {
                 return getContext().getString(R.string.item_is_selected, date);
             }
 
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index ec06c02..9c44236 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -32,7 +32,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * SlidingDrawer hides content out of the screen and allows the user to drag a handle
@@ -838,15 +837,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(SlidingDrawer.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(SlidingDrawer.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return SlidingDrawer.class.getName();
     }
 
     private void closeDrawer() {
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 3592687..e7031fe 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -727,14 +727,10 @@
                 }
             }
 
-            if (scheduleOtherSpellCheck && wordStart <= end) {
+            if (scheduleOtherSpellCheck && wordStart != BreakIterator.DONE && wordStart <= end) {
                 // Update range span: start new spell check from last wordStart
                 setRangeSpan(editable, wordStart, end);
             } else {
-                if (DBG && scheduleOtherSpellCheck) {
-                    Log.w(TAG, "Trying to schedule spellcheck for invalid region, from "
-                            + wordStart + " to " + end);
-                }
                 removeRangeSpan(editable);
             }
 
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 0d76239..3746ec6 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -16,11 +16,16 @@
 
 package android.widget;
 
+import com.android.internal.R;
+
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.annotation.Widget;
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
@@ -30,18 +35,17 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ListPopupWindow.ForwardingListener;
 import android.widget.PopupWindow.OnDismissListener;
 
-
 /**
  * A view that displays one child at a time and lets the user pick among them.
  * The items in the Spinner come from the {@link Adapter} associated with
@@ -74,17 +78,22 @@
      * Use a dropdown anchored to the Spinner for selecting spinner options.
      */
     public static final int MODE_DROPDOWN = 1;
-    
+
     /**
      * Use the theme-supplied value to select the dropdown mode.
      */
     private static final int MODE_THEME = -1;
 
+    /** Context used to inflate the popup window or dialog. */
+    private Context mPopupContext;
+
     /** Forwarding listener used to implement drag-to-open. */
     private ForwardingListener mForwardingListener;
 
+    /** Temporary holder for setAdapter() calls from the super constructor. */
+    private SpinnerAdapter mTempAdapter;
+
     private SpinnerPopup mPopup;
-    private DropDownAdapter mTempAdapter;
     int mDropDownWidth;
 
     private int mGravity;
@@ -184,69 +193,120 @@
      * @see #MODE_DIALOG
      * @see #MODE_DROPDOWN
      */
-    public Spinner(
-            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode) {
+    public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
+            int mode) {
+        this(context, attrs, defStyleAttr, defStyleRes, mode, null);
+    }
+
+    /**
+     * Constructs a new spinner with the given context's theme, the supplied
+     * attribute set, default styles, popup mode (one of {@link #MODE_DIALOG}
+     * or {@link #MODE_DROPDOWN}), and the context against which the popup
+     * should be inflated.
+     *
+     * @param context The context against which the view is inflated, which
+     *                provides access to the current theme, resources, etc.
+     * @param attrs The attributes of the XML tag that is inflating the view.
+     * @param defStyleAttr An attribute in the current theme that contains a
+     *                     reference to a style resource that supplies default
+     *                     values for the view. Can be 0 to not look for
+     *                     defaults.
+     * @param defStyleRes A resource identifier of a style resource that
+     *                    supplies default values for the view, used only if
+     *                    defStyleAttr is 0 or can not be found in the theme.
+     *                    Can be 0 to not look for defaults.
+     * @param mode Constant describing how the user will select choices from
+     *             the spinner.
+     * @param popupContext The context against which the dialog or dropdown
+     *                     popup will be inflated. Can be null to use the view
+     *                     context. If set, this will override any value
+     *                     specified by
+     *                     {@link android.R.styleable#Spinner_popupTheme}.
+     *
+     * @see #MODE_DIALOG
+     * @see #MODE_DROPDOWN
+     */
+    public Spinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, int mode,
+            Context popupContext) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.Spinner, defStyleAttr, defStyleRes);
+                attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
+
+        if (popupContext != null) {
+            mPopupContext = popupContext;
+        } else {
+            final int popupThemeResId = a.getResourceId(R.styleable.Spinner_popupTheme, 0);
+            if (popupThemeResId != 0) {
+                mPopupContext = new ContextThemeWrapper(context, popupThemeResId);
+            } else {
+                mPopupContext = context;
+            }
+        }
 
         if (mode == MODE_THEME) {
-            mode = a.getInt(com.android.internal.R.styleable.Spinner_spinnerMode, MODE_DIALOG);
+            mode = a.getInt(R.styleable.Spinner_spinnerMode, MODE_DIALOG);
         }
-        
+
         switch (mode) {
-        case MODE_DIALOG: {
-            mPopup = new DialogPopup();
-            break;
-        }
+            case MODE_DIALOG: {
+                mPopup = new DialogPopup();
+                mPopup.setPromptText(a.getString(R.styleable.Spinner_prompt));
+                break;
+            }
 
-        case MODE_DROPDOWN: {
-            final DropdownPopup popup = new DropdownPopup(context, attrs, defStyleAttr, defStyleRes);
+            case MODE_DROPDOWN: {
+                final DropdownPopup popup = new DropdownPopup(
+                        mPopupContext, attrs, defStyleAttr, defStyleRes);
+                final TypedArray pa = mPopupContext.obtainStyledAttributes(
+                        attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
+                mDropDownWidth = pa.getLayoutDimension(R.styleable.Spinner_dropDownWidth,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+                popup.setBackgroundDrawable(pa.getDrawable(R.styleable.Spinner_popupBackground));
+                popup.setPromptText(a.getString(R.styleable.Spinner_prompt));
+                pa.recycle();
 
-            mDropDownWidth = a.getLayoutDimension(
-                    com.android.internal.R.styleable.Spinner_dropDownWidth,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-            popup.setBackgroundDrawable(a.getDrawable(
-                    com.android.internal.R.styleable.Spinner_popupBackground));
-
-            mPopup = popup;
-            mForwardingListener = new ForwardingListener(this) {
-                @Override
-                public ListPopupWindow getPopup() {
-                    return popup;
-                }
-
-                @Override
-                public boolean onForwardingStarted() {
-                    if (!mPopup.isShowing()) {
-                        mPopup.show(getTextDirection(), getTextAlignment());
+                mPopup = popup;
+                mForwardingListener = new ForwardingListener(this) {
+                    @Override
+                    public ListPopupWindow getPopup() {
+                        return popup;
                     }
-                    return true;
-                }
-            };
-            break;
-        }
+
+                    @Override
+                    public boolean onForwardingStarted() {
+                        if (!mPopup.isShowing()) {
+                            mPopup.show(getTextDirection(), getTextAlignment());
+                        }
+                        return true;
+                    }
+                };
+                break;
+            }
         }
 
-        mGravity = a.getInt(com.android.internal.R.styleable.Spinner_gravity, Gravity.CENTER);
-
-        mPopup.setPromptText(a.getString(com.android.internal.R.styleable.Spinner_prompt));
-
+        mGravity = a.getInt(R.styleable.Spinner_gravity, Gravity.CENTER);
         mDisableChildrenWhenDisabled = a.getBoolean(
-                com.android.internal.R.styleable.Spinner_disableChildrenWhenDisabled, false);
+                R.styleable.Spinner_disableChildrenWhenDisabled, false);
 
         a.recycle();
 
         // Base constructor can call setAdapter before we initialize mPopup.
         // Finish setting things up if this happened.
         if (mTempAdapter != null) {
-            mPopup.setAdapter(mTempAdapter);
+            setAdapter(mTempAdapter);
             mTempAdapter = null;
         }
     }
 
     /**
+     * @return the context used to inflate the Spinner's popup or dialog window
+     */
+    public Context getPopupContext() {
+        return mPopupContext;
+    }
+
+    /**
      * Set the background drawable for the spinner's popup window of choices.
      * Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.
      *
@@ -259,7 +319,7 @@
             Log.e(TAG, "setPopupBackgroundDrawable: incompatible spinner mode; ignoring...");
             return;
         }
-        ((DropdownPopup) mPopup).setBackgroundDrawable(background);
+        mPopup.setBackgroundDrawable(background);
     }
 
     /**
@@ -270,8 +330,8 @@
      *
      * @attr ref android.R.styleable#Spinner_popupBackground
      */
-    public void setPopupBackgroundResource(int resId) {
-        setPopupBackgroundDrawable(getContext().getDrawable(resId));
+    public void setPopupBackgroundResource(@DrawableRes int resId) {
+        setPopupBackgroundDrawable(getPopupContext().getDrawable(resId));
     }
 
     /**
@@ -410,9 +470,17 @@
     }
 
     /**
-     * Sets the Adapter used to provide the data which backs this Spinner.
+     * Sets the {@link SpinnerAdapter} used to provide the data which backs
+     * this Spinner.
      * <p>
-     * Note that Spinner overrides {@link Adapter#getViewTypeCount()} on the
+     * If this Spinner has a popup theme set in XML via the
+     * {@link android.R.styleable#Spinner_popupTheme popupTheme} attribute, the
+     * adapter should inflate drop-down views using the same theme. The easiest
+     * way to achieve this is by using {@link #getPopupContext()} to obtain a
+     * layout inflater for use in
+     * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}.
+     * <p>
+     * Spinner overrides {@link Adapter#getViewTypeCount()} on the
      * Adapter associated with this view. Calling
      * {@link Adapter#getItemViewType(int) getItemViewType(int)} on the object
      * returned from {@link #getAdapter()} will always return 0. Calling
@@ -429,6 +497,13 @@
      */
     @Override
     public void setAdapter(SpinnerAdapter adapter) {
+        // The super constructor may call setAdapter before we're prepared.
+        // Postpone doing anything until we've finished construction.
+        if (mPopup == null) {
+            mTempAdapter = adapter;
+            return;
+        }
+
         super.setAdapter(adapter);
 
         mRecycler.clear();
@@ -439,11 +514,8 @@
             throw new IllegalArgumentException("Spinner adapter view type count must be 1");
         }
 
-        if (mPopup != null) {
-            mPopup.setAdapter(new DropDownAdapter(adapter));
-        } else {
-            mTempAdapter = new DropDownAdapter(adapter);
-        }
+        final Context popupContext = mPopupContext == null ? mContext : mPopupContext;
+        mPopup.setAdapter(new DropDownAdapter(adapter, popupContext.getTheme()));
     }
 
     @Override
@@ -693,15 +765,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(Spinner.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Spinner.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(Spinner.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
         if (mAdapter != null) {
             info.setCanOpenPopup(true);
@@ -847,14 +918,26 @@
         private ListAdapter mListAdapter;
 
         /**
-         * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
+         * Creates a new ListAdapter wrapper for the specified adapter.
          *
-         * @param adapter the Adapter to transform into a ListAdapter
+         * @param adapter the SpinnerAdapter to transform into a ListAdapter
+         * @param dropDownTheme the theme against which to inflate drop-down
+         *                      views, may be {@null} to use default theme
          */
-        public DropDownAdapter(SpinnerAdapter adapter) {
-            this.mAdapter = adapter;
+        public DropDownAdapter(@Nullable SpinnerAdapter adapter,
+                @Nullable Resources.Theme dropDownTheme) {
+            mAdapter = adapter;
+
             if (adapter instanceof ListAdapter) {
-                this.mListAdapter = (ListAdapter) adapter;
+                mListAdapter = (ListAdapter) adapter;
+            }
+
+            if (dropDownTheme != null && adapter instanceof Spinner.ThemedSpinnerAdapter) {
+                final Spinner.ThemedSpinnerAdapter themedAdapter =
+                        (Spinner.ThemedSpinnerAdapter) adapter;
+                if (themedAdapter.getDropDownViewTheme() == null) {
+                    themedAdapter.setDropDownViewTheme(dropDownTheme);
+                }
             }
         }
 
@@ -970,7 +1053,7 @@
         public int getVerticalOffset();
         public int getHorizontalOffset();
     }
-    
+
     private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
         private AlertDialog mPopup;
         private ListAdapter mListAdapter;
@@ -994,7 +1077,7 @@
         public void setPromptText(CharSequence hintText) {
             mPrompt = hintText;
         }
-        
+
         public CharSequence getHintText() {
             return mPrompt;
         }
@@ -1003,7 +1086,7 @@
             if (mListAdapter == null) {
                 return;
             }
-            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+            AlertDialog.Builder builder = new AlertDialog.Builder(getPopupContext());
             if (mPrompt != null) {
                 builder.setTitle(mPrompt);
             }
@@ -1179,4 +1262,21 @@
             }
         }
     }
+
+    public interface ThemedSpinnerAdapter {
+        /**
+         * Sets the {@link Resources.Theme} against which drop-down views are
+         * inflated.
+         *
+         * @param theme the context against which to inflate drop-down views
+         * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup)
+         */
+        public void setDropDownViewTheme(Resources.Theme theme);
+
+        /**
+         * @return The {@link Resources.Theme} against which drop-down views are
+         *         inflated.
+         */
+        public Resources.Theme getDropDownViewTheme();
+    }
 }
diff --git a/core/java/android/widget/SpinnerAdapter.java b/core/java/android/widget/SpinnerAdapter.java
index 91504cf..f99f45b 100644
--- a/core/java/android/widget/SpinnerAdapter.java
+++ b/core/java/android/widget/SpinnerAdapter.java
@@ -22,16 +22,17 @@
 /**
  * Extended {@link Adapter} that is the bridge between a
  * {@link android.widget.Spinner} and its data. A spinner adapter allows to
- * define two different views: one that shows the data in the spinner itself and
- * one that shows the data in the drop down list when the spinner is pressed.</p>
+ * define two different views: one that shows the data in the spinner itself
+ * and one that shows the data in the drop down list when the spinner is
+ * pressed.
  */
 public interface SpinnerAdapter extends Adapter {
     /**
-     * <p>Get a {@link android.view.View} that displays in the drop down popup
-     * the data at the specified position in the data set.</p>
+     * Gets a {@link android.view.View} that displays in the drop down popup
+     * the data at the specified position in the data set.
      *
-     * @param position      index of the item whose view we want.
-     * @param convertView   the old view to reuse, if possible. Note: You should
+     * @param position index of the item whose view we want.
+     * @param convertView the old view to reuse, if possible. Note: You should
      *        check that this view is non-null and of an appropriate type before
      *        using. If it is not possible to convert this view to display the
      *        correct data, this method can create a new view.
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index d2e718c..2bd3143 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -41,7 +41,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.LinearInterpolator;
 import android.widget.RemoteViews.RemoteView;
@@ -1050,10 +1049,8 @@
             if (mView != null) {
                 final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
 
-                float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset, 2) +
-                        Math.pow(viewLp.verticalOffset, 2));
-                float maxd = (float) Math.sqrt(Math.pow(mSlideAmount, 2) +
-                        Math.pow(0.4f * mSlideAmount, 2));
+                float d = (float) Math.hypot(viewLp.horizontalOffset, viewLp.verticalOffset);
+                float maxd = (float) Math.hypot(mSlideAmount, 0.4f * mSlideAmount);
 
                 if (velocity == 0) {
                     return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION;
@@ -1227,15 +1224,14 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(StackView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return StackView.class.getName();
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(StackView.class.getName());
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         info.setScrollable(getChildCount() > 1);
         if (isEnabled()) {
             if (getDisplayedChild() < getChildCount() - 1) {
@@ -1247,9 +1243,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
             return true;
         }
         if (!isEnabled()) {
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index 6349347..4323851 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -145,8 +145,9 @@
      * copied to the query text field.
      * <p>
      *
-     * @param refine which queries to refine. Possible values are {@link #REFINE_NONE},
-     * {@link #REFINE_BY_ENTRY}, and {@link #REFINE_ALL}.
+     * @param refineWhat which queries to refine. Possible values are
+     *                   {@link #REFINE_NONE}, {@link #REFINE_BY_ENTRY}, and
+     *                   {@link #REFINE_ALL}.
      */
     public void setQueryRefinement(int refineWhat) {
         mQueryRefinement = refineWhat;
@@ -327,7 +328,7 @@
             // First check TEXT_2_URL
             CharSequence text2 = getStringOrNull(cursor, mText2UrlCol);
             if (text2 != null) {
-                text2 = formatUrl(text2);
+                text2 = formatUrl(context, text2);
             } else {
                 text2 = getStringOrNull(cursor, mText2Col);
             }
@@ -372,12 +373,12 @@
         }
     }
 
-    private CharSequence formatUrl(CharSequence url) {
+    private CharSequence formatUrl(Context context, CharSequence url) {
         if (mUrlColor == null) {
             // Lazily get the URL color from the current theme.
             TypedValue colorValue = new TypedValue();
-            mContext.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true);
-            mUrlColor = mContext.getResources().getColorStateList(colorValue.resourceId);
+            context.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true);
+            mUrlColor = context.getResources().getColorStateList(colorValue.resourceId);
         }
 
         SpannableString text = new SpannableString(url);
@@ -502,6 +503,30 @@
     }
 
     /**
+     * This method is overridden purely to provide a bit of protection against
+     * flaky content providers.
+     *
+     * @see android.widget.CursorAdapter#getDropDownView(int, View, ViewGroup)
+     */
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+        try {
+            return super.getDropDownView(position, convertView, parent);
+        } catch (RuntimeException e) {
+            Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e);
+            // Put exception string in item title
+            final Context context = mDropDownContext == null ? mContext : mDropDownContext;
+            final View v = newDropDownView(context, mCursor, parent);
+            if (v != null) {
+                final ChildViewCache views = (ChildViewCache) v.getTag();
+                final TextView tv = views.mText1;
+                tv.setText(e.toString());
+            }
+            return v;
+        }
+    }
+
+    /**
      * Gets a drawable given a value provided by a suggestion provider.
      *
      * This value could be just the string value of a resource id
@@ -570,7 +595,7 @@
                 OpenResourceIdResult r =
                     mProviderContext.getContentResolver().getResourceId(uri);
                 try {
-                    return r.r.getDrawable(r.id, mContext.getTheme());
+                    return r.r.getDrawable(r.id, mProviderContext.getTheme());
                 } catch (Resources.NotFoundException ex) {
                     throw new FileNotFoundException("Resource does not exist: " + uri);
                 }
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 7a22224..bb290e7 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -17,6 +17,9 @@
 package android.widget;
 
 import android.animation.ObjectAnimator;
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -24,10 +27,12 @@
 import android.graphics.Canvas;
 import android.graphics.Insets;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -41,6 +46,7 @@
 import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
 import android.view.VelocityTracker;
+import android.view.ViewAssistStructure;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -84,7 +90,17 @@
     private static final int MONOSPACE = 3;
 
     private Drawable mThumbDrawable;
+    private ColorStateList mThumbTintList = null;
+    private PorterDuff.Mode mThumbTintMode = null;
+    private boolean mHasThumbTint = false;
+    private boolean mHasThumbTintMode = false;
+
     private Drawable mTrackDrawable;
+    private ColorStateList mTrackTintList = null;
+    private PorterDuff.Mode mTrackTintMode = null;
+    private boolean mHasTrackTint = false;
+    private boolean mHasTrackTintMode = false;
+
     private int mThumbTextPadding;
     private int mSwitchMinWidth;
     private int mSwitchPadding;
@@ -249,7 +265,7 @@
      *
      * @attr ref android.R.styleable#Switch_switchTextAppearance
      */
-    public void setSwitchTextAppearance(Context context, int resid) {
+    public void setSwitchTextAppearance(Context context, @StyleRes int resid) {
         TypedArray appearance =
                 context.obtainStyledAttributes(resid,
                         com.android.internal.R.styleable.TextAppearance);
@@ -457,7 +473,7 @@
      *
      * @attr ref android.R.styleable#Switch_track
      */
-    public void setTrackResource(int resId) {
+    public void setTrackResource(@DrawableRes int resId) {
         setTrackDrawable(getContext().getDrawable(resId));
     }
 
@@ -473,6 +489,86 @@
     }
 
     /**
+     * Applies a tint to the track drawable. Does not modify the current
+     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setTrackDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Switch_trackTint
+     * @see #getTrackTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setTrackTintList(@Nullable ColorStateList tint) {
+        mTrackTintList = tint;
+        mHasTrackTint = true;
+
+        applyTrackTint();
+    }
+
+    /**
+     * @return the tint applied to the track drawable
+     * @attr ref android.R.styleable#Switch_trackTint
+     * @see #setTrackTintList(ColorStateList)
+     */
+    @Nullable
+    public ColorStateList getTrackTintList() {
+        return mTrackTintList;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setTrackTintList(ColorStateList)}} to the track drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#Switch_trackTintMode
+     * @see #getTrackTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setTrackTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mTrackTintMode = tintMode;
+        mHasTrackTintMode = true;
+
+        applyTrackTint();
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the track
+     *         drawable
+     * @attr ref android.R.styleable#Switch_trackTintMode
+     * @see #setTrackTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getTrackTintMode() {
+        return mTrackTintMode;
+    }
+
+    private void applyTrackTint() {
+        if (mTrackDrawable != null && (mHasTrackTint || mHasTrackTintMode)) {
+            mTrackDrawable = mTrackDrawable.mutate();
+
+            if (mHasTrackTint) {
+                mTrackDrawable.setTintList(mTrackTintList);
+            }
+
+            if (mHasTrackTintMode) {
+                mTrackDrawable.setTintMode(mTrackTintMode);
+            }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mTrackDrawable.isStateful()) {
+                mTrackDrawable.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Set the drawable used for the switch "thumb" - the piece that the user
      * can physically touch and drag along the track.
      *
@@ -499,7 +595,7 @@
      *
      * @attr ref android.R.styleable#Switch_thumb
      */
-    public void setThumbResource(int resId) {
+    public void setThumbResource(@DrawableRes int resId) {
         setThumbDrawable(getContext().getDrawable(resId));
     }
 
@@ -516,6 +612,86 @@
     }
 
     /**
+     * Applies a tint to the thumb drawable. Does not modify the current
+     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setThumbDrawable(Drawable)} will
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Switch_thumbTint
+     * @see #getThumbTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setThumbTintList(@Nullable ColorStateList tint) {
+        mThumbTintList = tint;
+        mHasThumbTint = true;
+
+        applyThumbTint();
+    }
+
+    /**
+     * @return the tint applied to the thumb drawable
+     * @attr ref android.R.styleable#Switch_thumbTint
+     * @see #setThumbTintList(ColorStateList)
+     */
+    @Nullable
+    public ColorStateList getThumbTintList() {
+        return mThumbTintList;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setThumbTintList(ColorStateList)}} to the thumb drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#Switch_thumbTintMode
+     * @see #getThumbTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mThumbTintMode = tintMode;
+        mHasThumbTintMode = true;
+
+        applyThumbTint();
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the thumb
+     *         drawable
+     * @attr ref android.R.styleable#Switch_thumbTintMode
+     * @see #setThumbTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getThumbTintMode() {
+        return mThumbTintMode;
+    }
+
+    private void applyThumbTint() {
+        if (mThumbDrawable != null && (mHasThumbTint || mHasThumbTintMode)) {
+            mThumbDrawable = mThumbDrawable.mutate();
+
+            if (mHasThumbTint) {
+                mThumbDrawable.setTintList(mThumbTintList);
+            }
+
+            if (mHasThumbTintMode) {
+                mThumbDrawable.setTintMode(mThumbTintMode);
+            }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mThumbDrawable.isStateful()) {
+                mThumbDrawable.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Specifies whether the track should be split by the thumb. When true,
      * the thumb's optical bounds will be clipped out of the track drawable,
      * then the thumb will be drawn into the resulting gap.
@@ -665,9 +841,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEventInternal(event);
 
         final CharSequence text = isChecked() ? mTextOn : mTextOff;
         if (text != null) {
@@ -1181,15 +1358,31 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(Switch.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return Switch.class.getName();
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(Switch.class.getName());
+    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
+        super.onProvideAssistStructure(structure, extras);
+        CharSequence switchText = isChecked() ? mTextOn : mTextOff;
+        if (!TextUtils.isEmpty(switchText)) {
+            CharSequence oldText = structure.getText();
+            if (TextUtils.isEmpty(oldText)) {
+                structure.setText(switchText);
+            } else {
+                StringBuilder newText = new StringBuilder();
+                newText.append(oldText).append(' ').append(switchText);
+                structure.setText(newText);
+            }
+            structure.setTextPaint(mTextPaint);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = info.getText();
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 89df51a..110d79b0 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -33,9 +33,6 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.Window;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -173,8 +170,9 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void sendAccessibilityEvent(int eventType) {
+    public void sendAccessibilityEventInternal(int eventType) {
         /* avoid super class behavior - TabWidget sends the right events */
     }
 
@@ -384,15 +382,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TabHost.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TabHost.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TabHost.class.getName();
     }
 
     public void setCurrentTab(int index) {
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 47a5449..9496e62 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -17,8 +17,8 @@
 package android.widget;
 
 import android.R;
+import android.annotation.DrawableRes;
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -29,7 +29,6 @@
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  *
@@ -244,7 +243,7 @@
      * @param resId the resource identifier of the drawable to use as a
      * divider.
      */
-    public void setDividerDrawable(int resId) {
+    public void setDividerDrawable(@DrawableRes int resId) {
         setDividerDrawable(mContext.getDrawable(resId));
     }
     
@@ -265,7 +264,7 @@
      * @param resId the resource identifier of the drawable to use as the
      * left strip drawable
      */
-    public void setLeftStripDrawable(int resId) {
+    public void setLeftStripDrawable(@DrawableRes int resId) {
         setLeftStripDrawable(mContext.getDrawable(resId));
     }
 
@@ -286,7 +285,7 @@
      * @param resId the resource identifier of the drawable to use as the
      * right strip drawable
      */
-    public void setRightStripDrawable(int resId) {
+    public void setRightStripDrawable(@DrawableRes int resId) {
         setRightStripDrawable(mContext.getDrawable(resId));
     }
 
@@ -401,8 +400,9 @@
         }
     }
 
+    /** @hide */
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         onPopulateAccessibilityEvent(event);
         // Dispatch only to the selected tab.
         if (mSelectedTab != -1) {
@@ -415,28 +415,28 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TabWidget.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TabWidget.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
         event.setItemCount(getTabCount());
         event.setCurrentItemIndex(mSelectedTab);
     }
 
 
+    /** @hide */
     @Override
-    public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+    public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
         // this class fires events only when tabs are focused or selected
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
             event.recycle();
             return;
         }
-        super.sendAccessibilityEventUnchecked(event);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TabWidget.class.getName());
+        super.sendAccessibilityEventUncheckedInternal(event);
     }
 
     /**
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index f4b2ce0..093bdcf 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -24,9 +24,6 @@
 import android.util.SparseBooleanArray;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import java.util.regex.Pattern;
 
 /**
@@ -667,15 +664,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TableLayout.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TableLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TableLayout.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index fe3631a..faf5b84 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -24,8 +24,6 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -380,15 +378,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TableRow.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TableRow.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TableRow.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index a98d272..e2acaac 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -230,10 +230,10 @@
         if (mFormat12 == null || mFormat24 == null) {
             LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
             if (mFormat12 == null) {
-                mFormat12 = ld.timeFormat12;
+                mFormat12 = ld.timeFormat_hm;
             }
             if (mFormat24 == null) {
-                mFormat24 = ld.timeFormat24;
+                mFormat24 = ld.timeFormat_Hm;
             }
         }
 
@@ -457,9 +457,9 @@
         LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
 
         if (format24Requested) {
-            mFormat = abc(mFormat24, mFormat12, ld.timeFormat24);
+            mFormat = abc(mFormat24, mFormat12, ld.timeFormat_Hm);
         } else {
-            mFormat = abc(mFormat12, mFormat24, ld.timeFormat12);
+            mFormat = abc(mFormat12, mFormat24, ld.timeFormat_hm);
         }
 
         boolean hadSeconds = mHasSeconds;
diff --git a/core/java/android/widget/TextSwitcher.java b/core/java/android/widget/TextSwitcher.java
index 1aefd2b..ecd9a8c 100644
--- a/core/java/android/widget/TextSwitcher.java
+++ b/core/java/android/widget/TextSwitcher.java
@@ -21,8 +21,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * Specialized {@link android.widget.ViewSwitcher} that contains
@@ -92,14 +90,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TextSwitcher.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TextSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TextSwitcher.class.getName();
     }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7dc64bd..447e9ac 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,14 +17,20 @@
 package android.widget;
 
 import android.R;
+import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.annotation.StyleRes;
+import android.annotation.XmlRes;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.UndoManager;
 import android.content.res.ColorStateList;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -32,6 +38,7 @@
 import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Typeface;
@@ -41,6 +48,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -93,7 +101,6 @@
 import android.text.style.UpdateAppearance;
 import android.text.util.Linkify;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -108,6 +115,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewAssistStructure;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
 import android.view.ViewGroup.LayoutParams;
@@ -215,6 +223,8 @@
  * @attr ref android.R.styleable#TextView_drawableStart
  * @attr ref android.R.styleable#TextView_drawableEnd
  * @attr ref android.R.styleable#TextView_drawablePadding
+ * @attr ref android.R.styleable#TextView_drawableTint
+ * @attr ref android.R.styleable#TextView_drawableTintMode
  * @attr ref android.R.styleable#TextView_lineSpacingExtra
  * @attr ref android.R.styleable#TextView_lineSpacingMultiplier
  * @attr ref android.R.styleable#TextView_marqueeRepeatLimit
@@ -299,7 +309,6 @@
     private float mShadowRadius, mShadowDx, mShadowDy;
     private int mShadowColor;
 
-
     private boolean mPreDrawRegistered;
     private boolean mPreDrawListenerDetached;
 
@@ -313,16 +322,27 @@
     private TextUtils.TruncateAt mEllipsize;
 
     static class Drawables {
-        final static int DRAWABLE_NONE = -1;
-        final static int DRAWABLE_RIGHT = 0;
-        final static int DRAWABLE_LEFT = 1;
+        static final int LEFT = 0;
+        static final int TOP = 1;
+        static final int RIGHT = 2;
+        static final int BOTTOM = 3;
+
+        static final int DRAWABLE_NONE = -1;
+        static final int DRAWABLE_RIGHT = 0;
+        static final int DRAWABLE_LEFT = 1;
 
         final Rect mCompoundRect = new Rect();
 
-        Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
-                mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp;
+        final Drawable[] mShowing = new Drawable[4];
 
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTint;
+        boolean mHasTintMode;
+
+        Drawable mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp;
         Drawable mDrawableLeftInitial, mDrawableRightInitial;
+
         boolean mIsRtlCompatibilityMode;
         boolean mOverride;
 
@@ -345,19 +365,19 @@
 
         public void resolveWithLayoutDirection(int layoutDirection) {
             // First reset "left" and "right" drawables to their initial values
-            mDrawableLeft = mDrawableLeftInitial;
-            mDrawableRight = mDrawableRightInitial;
+            mShowing[Drawables.LEFT] = mDrawableLeftInitial;
+            mShowing[Drawables.RIGHT] = mDrawableRightInitial;
 
             if (mIsRtlCompatibilityMode) {
                 // Use "start" drawable as "left" drawable if the "left" drawable was not defined
-                if (mDrawableStart != null && mDrawableLeft == null) {
-                    mDrawableLeft = mDrawableStart;
+                if (mDrawableStart != null && mShowing[Drawables.LEFT] == null) {
+                    mShowing[Drawables.LEFT] = mDrawableStart;
                     mDrawableSizeLeft = mDrawableSizeStart;
                     mDrawableHeightLeft = mDrawableHeightStart;
                 }
                 // Use "end" drawable as "right" drawable if the "right" drawable was not defined
-                if (mDrawableEnd != null && mDrawableRight == null) {
-                    mDrawableRight = mDrawableEnd;
+                if (mDrawableEnd != null && mShowing[Drawables.RIGHT] == null) {
+                    mShowing[Drawables.RIGHT] = mDrawableEnd;
                     mDrawableSizeRight = mDrawableSizeEnd;
                     mDrawableHeightRight = mDrawableHeightEnd;
                 }
@@ -367,11 +387,11 @@
                 switch(layoutDirection) {
                     case LAYOUT_DIRECTION_RTL:
                         if (mOverride) {
-                            mDrawableRight = mDrawableStart;
+                            mShowing[Drawables.RIGHT] = mDrawableStart;
                             mDrawableSizeRight = mDrawableSizeStart;
                             mDrawableHeightRight = mDrawableHeightStart;
 
-                            mDrawableLeft = mDrawableEnd;
+                            mShowing[Drawables.LEFT] = mDrawableEnd;
                             mDrawableSizeLeft = mDrawableSizeEnd;
                             mDrawableHeightLeft = mDrawableHeightEnd;
                         }
@@ -380,11 +400,11 @@
                     case LAYOUT_DIRECTION_LTR:
                     default:
                         if (mOverride) {
-                            mDrawableLeft = mDrawableStart;
+                            mShowing[Drawables.LEFT] = mDrawableStart;
                             mDrawableSizeLeft = mDrawableSizeStart;
                             mDrawableHeightLeft = mDrawableHeightStart;
 
-                            mDrawableRight = mDrawableEnd;
+                            mShowing[Drawables.RIGHT] = mDrawableEnd;
                             mDrawableSizeRight = mDrawableSizeEnd;
                             mDrawableHeightRight = mDrawableHeightEnd;
                         }
@@ -396,17 +416,10 @@
         }
 
         private void updateDrawablesLayoutDirection(int layoutDirection) {
-            if (mDrawableLeft != null) {
-                mDrawableLeft.setLayoutDirection(layoutDirection);
-            }
-            if (mDrawableRight != null) {
-                mDrawableRight.setLayoutDirection(layoutDirection);
-            }
-            if (mDrawableTop != null) {
-                mDrawableTop.setLayoutDirection(layoutDirection);
-            }
-            if (mDrawableBottom != null) {
-                mDrawableBottom.setLayoutDirection(layoutDirection);
+            for (Drawable dr : mShowing) {
+                if (dr != null) {
+                    dr.setLayoutDirection(layoutDirection);
+                }
             }
         }
 
@@ -416,10 +429,10 @@
             }
             mDrawableError = dr;
 
-            final Rect compoundRect = mCompoundRect;
-            int[] state = tv.getDrawableState();
-
             if (mDrawableError != null) {
+                final Rect compoundRect = mCompoundRect;
+                final int[] state = tv.getDrawableState();
+
                 mDrawableError.setState(state);
                 mDrawableError.copyBounds(compoundRect);
                 mDrawableError.setCallback(tv);
@@ -434,12 +447,12 @@
             // first restore the initial state if needed
             switch (mDrawableSaved) {
                 case DRAWABLE_LEFT:
-                    mDrawableLeft = mDrawableTemp;
+                    mShowing[Drawables.LEFT] = mDrawableTemp;
                     mDrawableSizeLeft = mDrawableSizeTemp;
                     mDrawableHeightLeft = mDrawableHeightTemp;
                     break;
                 case DRAWABLE_RIGHT:
-                    mDrawableRight = mDrawableTemp;
+                    mShowing[Drawables.RIGHT] = mDrawableTemp;
                     mDrawableSizeRight = mDrawableSizeTemp;
                     mDrawableHeightRight = mDrawableHeightTemp;
                     break;
@@ -452,11 +465,11 @@
                     case LAYOUT_DIRECTION_RTL:
                         mDrawableSaved = DRAWABLE_LEFT;
 
-                        mDrawableTemp = mDrawableLeft;
+                        mDrawableTemp = mShowing[Drawables.LEFT];
                         mDrawableSizeTemp = mDrawableSizeLeft;
                         mDrawableHeightTemp = mDrawableHeightLeft;
 
-                        mDrawableLeft = mDrawableError;
+                        mShowing[Drawables.LEFT] = mDrawableError;
                         mDrawableSizeLeft = mDrawableSizeError;
                         mDrawableHeightLeft = mDrawableHeightError;
                         break;
@@ -464,11 +477,11 @@
                     default:
                         mDrawableSaved = DRAWABLE_RIGHT;
 
-                        mDrawableTemp = mDrawableRight;
+                        mDrawableTemp = mShowing[Drawables.RIGHT];
                         mDrawableSizeTemp = mDrawableSizeRight;
                         mDrawableHeightTemp = mDrawableHeightRight;
 
-                        mDrawableRight = mDrawableError;
+                        mShowing[Drawables.RIGHT] = mDrawableError;
                         mDrawableSizeRight = mDrawableSizeError;
                         mDrawableHeightRight = mDrawableHeightError;
                         break;
@@ -521,6 +534,7 @@
     private final TextPaint mTextPaint;
     private boolean mUserSetTextScaleX;
     private Layout mLayout;
+    private boolean mLocaleChanged = false;
 
     private int mGravity = Gravity.TOP | Gravity.START;
     private boolean mHorizontallyScrolling;
@@ -624,16 +638,17 @@
         this(context, null);
     }
 
-    public TextView(Context context, AttributeSet attrs) {
+    public TextView(Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.textViewStyle);
     }
 
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
     @SuppressWarnings("deprecation")
-    public TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public TextView(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         mText = "";
@@ -772,6 +787,8 @@
         boolean selectallonfocus = false;
         Drawable drawableLeft = null, drawableTop = null, drawableRight = null,
             drawableBottom = null, drawableStart = null, drawableEnd = null;
+        ColorStateList drawableTint = null;
+        PorterDuff.Mode drawableTintMode = null;
         int drawablePadding = 0;
         int ellipsize = -1;
         boolean singleLine = false;
@@ -857,6 +874,14 @@
                 drawableEnd = a.getDrawable(attr);
                 break;
 
+            case com.android.internal.R.styleable.TextView_drawableTint:
+                drawableTint = a.getColorStateList(attr);
+                break;
+
+            case com.android.internal.R.styleable.TextView_drawableTintMode:
+                drawableTintMode = Drawable.parseTintMode(a.getInt(attr, -1), drawableTintMode);
+                break;
+
             case com.android.internal.R.styleable.TextView_drawablePadding:
                 drawablePadding = a.getDimensionPixelSize(attr, drawablePadding);
                 break;
@@ -1032,6 +1057,11 @@
                 inputType = a.getInt(attr, EditorInfo.TYPE_NULL);
                 break;
 
+            case com.android.internal.R.styleable.TextView_allowUndo:
+                createEditorIfNeeded();
+                mEditor.mAllowUndo = a.getBoolean(attr, true);
+                break;
+
             case com.android.internal.R.styleable.TextView_imeOptions:
                 createEditorIfNeeded();
                 mEditor.createInputContentTypeIfNeeded();
@@ -1241,6 +1271,22 @@
                 bufferType = BufferType.SPANNABLE;
         }
 
+        // Set up the tint (if needed) before setting the drawables so that it
+        // gets applied correctly.
+        if (drawableTint != null || drawableTintMode != null) {
+            if (mDrawables == null) {
+                mDrawables = new Drawables(context);
+            }
+            if (drawableTint != null) {
+                mDrawables.mTintList = drawableTint;
+                mDrawables.mHasTint = true;
+            }
+            if (drawableTintMode != null) {
+                mDrawables.mTintMode = drawableTintMode;
+                mDrawables.mHasTintMode = true;
+            }
+        }
+
         // This call will save the initial left/right drawables
         setCompoundDrawablesWithIntrinsicBounds(
             drawableLeft, drawableTop, drawableRight, drawableBottom);
@@ -1426,6 +1472,7 @@
             }
             resetResolvedDrawables();
             resolveDrawables();
+            applyCompoundDrawableTint();
         }
     }
 
@@ -1573,7 +1620,8 @@
      * @hide
      */
     public final UndoManager getUndoManager() {
-        return mEditor == null ? null : mEditor.mUndoManager;
+        // TODO: Consider supporting a global undo manager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -1591,22 +1639,12 @@
      * @hide
      */
     public final void setUndoManager(UndoManager undoManager, String tag) {
-        if (undoManager != null) {
-            createEditorIfNeeded();
-            mEditor.mUndoManager = undoManager;
-            mEditor.mUndoOwner = undoManager.getOwner(tag, this);
-            mEditor.mUndoInputFilter = new Editor.UndoInputFilter(mEditor);
-            if (!(mText instanceof Editable)) {
-                setText(mText, BufferType.EDITABLE);
-            }
-
-            setFilters((Editable) mText, mFilters);
-        } else if (mEditor != null) {
-            // XXX need to destroy all associated state.
-            mEditor.mUndoManager = null;
-            mEditor.mUndoOwner = null;
-            mEditor.mUndoInputFilter = null;
-        }
+        // TODO: Consider supporting a global undo manager. An implementation will need to:
+        // * createEditorIfNeeded()
+        // * Promote to BufferType.EDITABLE if needed.
+        // * Update the UndoManager and UndoOwner.
+        // Likewise it will need to be able to restore the default UndoManager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -1784,7 +1822,7 @@
      */
     public int getCompoundPaddingTop() {
         final Drawables dr = mDrawables;
-        if (dr == null || dr.mDrawableTop == null) {
+        if (dr == null || dr.mShowing[Drawables.TOP] == null) {
             return mPaddingTop;
         } else {
             return mPaddingTop + dr.mDrawablePadding + dr.mDrawableSizeTop;
@@ -1797,7 +1835,7 @@
      */
     public int getCompoundPaddingBottom() {
         final Drawables dr = mDrawables;
-        if (dr == null || dr.mDrawableBottom == null) {
+        if (dr == null || dr.mShowing[Drawables.BOTTOM] == null) {
             return mPaddingBottom;
         } else {
             return mPaddingBottom + dr.mDrawablePadding + dr.mDrawableSizeBottom;
@@ -1810,7 +1848,7 @@
      */
     public int getCompoundPaddingLeft() {
         final Drawables dr = mDrawables;
-        if (dr == null || dr.mDrawableLeft == null) {
+        if (dr == null || dr.mShowing[Drawables.LEFT] == null) {
             return mPaddingLeft;
         } else {
             return mPaddingLeft + dr.mDrawablePadding + dr.mDrawableSizeLeft;
@@ -1823,7 +1861,7 @@
      */
     public int getCompoundPaddingRight() {
         final Drawables dr = mDrawables;
-        if (dr == null || dr.mDrawableRight == null) {
+        if (dr == null || dr.mShowing[Drawables.RIGHT] == null) {
             return mPaddingRight;
         } else {
             return mPaddingRight + dr.mDrawablePadding + dr.mDrawableSizeRight;
@@ -2021,14 +2059,12 @@
                 } else {
                     // We need to retain the last set padding, so just clear
                     // out all of the fields in the existing structure.
-                    if (dr.mDrawableLeft != null) dr.mDrawableLeft.setCallback(null);
-                    dr.mDrawableLeft = null;
-                    if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
-                    dr.mDrawableTop = null;
-                    if (dr.mDrawableRight != null) dr.mDrawableRight.setCallback(null);
-                    dr.mDrawableRight = null;
-                    if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
-                    dr.mDrawableBottom = null;
+                    for (int i = dr.mShowing.length - 1; i >= 0; i--) {
+                        if (dr.mShowing[i] != null) {
+                            dr.mShowing[i].setCallback(null);
+                        }
+                        dr.mShowing[i] = null;
+                    }
                     dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
                     dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
                     dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
@@ -2042,25 +2078,25 @@
 
             mDrawables.mOverride = false;
 
-            if (dr.mDrawableLeft != left && dr.mDrawableLeft != null) {
-                dr.mDrawableLeft.setCallback(null);
+            if (dr.mShowing[Drawables.LEFT] != left && dr.mShowing[Drawables.LEFT] != null) {
+                dr.mShowing[Drawables.LEFT].setCallback(null);
             }
-            dr.mDrawableLeft = left;
+            dr.mShowing[Drawables.LEFT] = left;
 
-            if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
-                dr.mDrawableTop.setCallback(null);
+            if (dr.mShowing[Drawables.TOP] != top && dr.mShowing[Drawables.TOP] != null) {
+                dr.mShowing[Drawables.TOP].setCallback(null);
             }
-            dr.mDrawableTop = top;
+            dr.mShowing[Drawables.TOP] = top;
 
-            if (dr.mDrawableRight != right && dr.mDrawableRight != null) {
-                dr.mDrawableRight.setCallback(null);
+            if (dr.mShowing[Drawables.RIGHT] != right && dr.mShowing[Drawables.RIGHT] != null) {
+                dr.mShowing[Drawables.RIGHT].setCallback(null);
             }
-            dr.mDrawableRight = right;
+            dr.mShowing[Drawables.RIGHT] = right;
 
-            if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
-                dr.mDrawableBottom.setCallback(null);
+            if (dr.mShowing[Drawables.BOTTOM] != bottom && dr.mShowing[Drawables.BOTTOM] != null) {
+                dr.mShowing[Drawables.BOTTOM].setCallback(null);
             }
-            dr.mDrawableBottom = bottom;
+            dr.mShowing[Drawables.BOTTOM] = bottom;
 
             final Rect compoundRect = dr.mCompoundRect;
             int[] state;
@@ -2116,6 +2152,7 @@
 
         resetResolvedDrawables();
         resolveDrawables();
+        applyCompoundDrawableTint();
         invalidate();
         requestLayout();
     }
@@ -2139,7 +2176,8 @@
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
     @android.view.RemotableViewMethod
-    public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
+    public void setCompoundDrawablesWithIntrinsicBounds(@DrawableRes int left,
+            @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
         final Context context = getContext();
         setCompoundDrawablesWithIntrinsicBounds(left != 0 ? context.getDrawable(left) : null,
                 top != 0 ? context.getDrawable(top) : null,
@@ -2199,10 +2237,14 @@
 
         // We're switching to relative, discard absolute.
         if (dr != null) {
-            if (dr.mDrawableLeft != null) dr.mDrawableLeft.setCallback(null);
-            dr.mDrawableLeft = dr.mDrawableLeftInitial = null;
-            if (dr.mDrawableRight != null) dr.mDrawableRight.setCallback(null);
-            dr.mDrawableRight = dr.mDrawableRightInitial = null;
+            if (dr.mShowing[Drawables.LEFT] != null) {
+                dr.mShowing[Drawables.LEFT].setCallback(null);
+            }
+            dr.mShowing[Drawables.LEFT] = dr.mDrawableLeftInitial = null;
+            if (dr.mShowing[Drawables.RIGHT] != null) {
+                dr.mShowing[Drawables.RIGHT].setCallback(null);
+            }
+            dr.mShowing[Drawables.RIGHT] = dr.mDrawableRightInitial = null;
             dr.mDrawableSizeLeft = dr.mDrawableHeightLeft = 0;
             dr.mDrawableSizeRight = dr.mDrawableHeightRight = 0;
         }
@@ -2220,12 +2262,18 @@
                     // out all of the fields in the existing structure.
                     if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
                     dr.mDrawableStart = null;
-                    if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
-                    dr.mDrawableTop = null;
-                    if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+                    if (dr.mShowing[Drawables.TOP] != null) {
+                        dr.mShowing[Drawables.TOP].setCallback(null);
+                    }
+                    dr.mShowing[Drawables.TOP] = null;
+                    if (dr.mDrawableEnd != null) {
+                        dr.mDrawableEnd.setCallback(null);
+                    }
                     dr.mDrawableEnd = null;
-                    if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
-                    dr.mDrawableBottom = null;
+                    if (dr.mShowing[Drawables.BOTTOM] != null) {
+                        dr.mShowing[Drawables.BOTTOM].setCallback(null);
+                    }
+                    dr.mShowing[Drawables.BOTTOM] = null;
                     dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
                     dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
                     dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
@@ -2244,20 +2292,20 @@
             }
             dr.mDrawableStart = start;
 
-            if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
-                dr.mDrawableTop.setCallback(null);
+            if (dr.mShowing[Drawables.TOP] != top && dr.mShowing[Drawables.TOP] != null) {
+                dr.mShowing[Drawables.TOP].setCallback(null);
             }
-            dr.mDrawableTop = top;
+            dr.mShowing[Drawables.TOP] = top;
 
             if (dr.mDrawableEnd != end && dr.mDrawableEnd != null) {
                 dr.mDrawableEnd.setCallback(null);
             }
             dr.mDrawableEnd = end;
 
-            if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
-                dr.mDrawableBottom.setCallback(null);
+            if (dr.mShowing[Drawables.BOTTOM] != bottom && dr.mShowing[Drawables.BOTTOM] != null) {
+                dr.mShowing[Drawables.BOTTOM].setCallback(null);
             }
-            dr.mDrawableBottom = bottom;
+            dr.mShowing[Drawables.BOTTOM] = bottom;
 
             final Rect compoundRect = dr.mCompoundRect;
             int[] state;
@@ -2330,8 +2378,8 @@
      * @attr ref android.R.styleable#TextView_drawableBottom
      */
     @android.view.RemotableViewMethod
-    public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
-            int bottom) {
+    public void setCompoundDrawablesRelativeWithIntrinsicBounds(@DrawableRes int start,
+            @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
         final Context context = getContext();
         setCompoundDrawablesRelativeWithIntrinsicBounds(
                 start != 0 ? context.getDrawable(start) : null,
@@ -2383,9 +2431,7 @@
     public Drawable[] getCompoundDrawables() {
         final Drawables dr = mDrawables;
         if (dr != null) {
-            return new Drawable[] {
-                dr.mDrawableLeft, dr.mDrawableTop, dr.mDrawableRight, dr.mDrawableBottom
-            };
+            return dr.mShowing.clone();
         } else {
             return new Drawable[] { null, null, null, null };
         }
@@ -2404,7 +2450,8 @@
         final Drawables dr = mDrawables;
         if (dr != null) {
             return new Drawable[] {
-                dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom
+                dr.mDrawableStart, dr.mShowing[Drawables.TOP],
+                dr.mDrawableEnd, dr.mShowing[Drawables.BOTTOM]
             };
         } else {
             return new Drawable[] { null, null, null, null };
@@ -2445,6 +2492,118 @@
         return dr != null ? dr.mDrawablePadding : 0;
     }
 
+    /**
+     * Applies a tint to the compound drawables. Does not modify the
+     * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to
+     * {@link #setCompoundDrawables(Drawable, Drawable, Drawable, Drawable)}
+     * and related methods will automatically mutate the drawables and apply
+     * the specified tint and tint mode using
+     * {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#TextView_drawableTint
+     * @see #getCompoundDrawableTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setCompoundDrawableTintList(@Nullable ColorStateList tint) {
+        if (mDrawables == null) {
+            mDrawables = new Drawables(getContext());
+        }
+        mDrawables.mTintList = tint;
+        mDrawables.mHasTint = true;
+
+        applyCompoundDrawableTint();
+    }
+
+    /**
+     * @return the tint applied to the compound drawables
+     * @attr ref android.R.styleable#TextView_drawableTint
+     * @see #setCompoundDrawableTintList(ColorStateList)
+     */
+    public ColorStateList getCompoundDrawableTintList() {
+        return mDrawables != null ? mDrawables.mTintList : null;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setCompoundDrawableTintList(ColorStateList)} to the compound
+     * drawables. The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#TextView_drawableTintMode
+     * @see #setCompoundDrawableTintList(ColorStateList)
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setCompoundDrawableTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mDrawables == null) {
+            mDrawables = new Drawables(getContext());
+        }
+        mDrawables.mTintMode = tintMode;
+        mDrawables.mHasTintMode = true;
+
+        applyCompoundDrawableTint();
+    }
+
+    /**
+     * Returns the blending mode used to apply the tint to the compound
+     * drawables, if specified.
+     *
+     * @return the blending mode used to apply the tint to the compound
+     *         drawables
+     * @attr ref android.R.styleable#TextView_drawableTintMode
+     * @see #setCompoundDrawableTintMode(PorterDuff.Mode)
+     */
+    public PorterDuff.Mode getCompoundDrawableTintMode() {
+        return mDrawables != null ? mDrawables.mTintMode : null;
+    }
+
+    private void applyCompoundDrawableTint() {
+        if (mDrawables == null) {
+            return;
+        }
+
+        if (mDrawables.mHasTint || mDrawables.mHasTintMode) {
+            final ColorStateList tintList = mDrawables.mTintList;
+            final PorterDuff.Mode tintMode = mDrawables.mTintMode;
+            final boolean hasTint = mDrawables.mHasTint;
+            final boolean hasTintMode = mDrawables.mHasTintMode;
+            final int[] state = getDrawableState();
+
+            for (Drawable dr : mDrawables.mShowing) {
+                if (dr == null) {
+                    continue;
+                }
+
+                if (dr == mDrawables.mDrawableError) {
+                    // From a developer's perspective, the error drawable isn't
+                    // a compound drawable. Don't apply the generic compound
+                    // drawable tint to it.
+                    continue;
+                }
+
+                dr.mutate();
+
+                if (hasTint) {
+                    dr.setTintList(tintList);
+                }
+
+                if (hasTintMode) {
+                    dr.setTintMode(tintMode);
+                }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (dr.isStateful()) {
+                    dr.setState(state);
+                }
+            }
+        }
+    }
+
     @Override
     public void setPadding(int left, int top, int right, int bottom) {
         if (left != mPaddingLeft ||
@@ -2488,7 +2647,7 @@
      * Sets the text color, size, style, hint color, and highlight color
      * from the specified TextAppearance resource.
      */
-    public void setTextAppearance(Context context, int resid) {
+    public void setTextAppearance(Context context, @StyleRes int resid) {
         TypedArray appearance =
             context.obtainStyledAttributes(resid,
                                            com.android.internal.R.styleable.TextAppearance);
@@ -2593,9 +2752,18 @@
      * @see Paint#setTextLocale
      */
     public void setTextLocale(Locale locale) {
+        mLocaleChanged = true;
         mTextPaint.setTextLocale(locale);
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (!mLocaleChanged) {
+            mTextPaint.setTextLocale(Locale.getDefault());
+        }
+    }
+
     /**
      * @return the size (in pixels) of the default text size in this TextView.
      */
@@ -2830,7 +2998,7 @@
      * @attr ref android.R.styleable#TextView_textColor
      */
     @android.view.RemotableViewMethod
-    public void setTextColor(int color) {
+    public void setTextColor(@ColorInt int color) {
         mTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -2871,6 +3039,7 @@
      *
      * @return Returns the current text color.
      */
+    @ColorInt
     public final int getCurrentTextColor() {
         return mCurTextColor;
     }
@@ -2881,7 +3050,7 @@
      * @attr ref android.R.styleable#TextView_textColorHighlight
      */
     @android.view.RemotableViewMethod
-    public void setHighlightColor(int color) {
+    public void setHighlightColor(@ColorInt int color) {
         if (mHighlightColor != color) {
             mHighlightColor = color;
             invalidate();
@@ -2895,6 +3064,7 @@
      *
      * @attr ref android.R.styleable#TextView_textColorHighlight
      */
+    @ColorInt
     public int getHighlightColor() {
         return mHighlightColor;
     }
@@ -2989,6 +3159,7 @@
      *
      * @attr ref android.R.styleable#TextView_shadowColor
      */
+    @ColorInt
     public int getShadowColor() {
         return mShadowColor;
     }
@@ -3064,7 +3235,7 @@
      * @attr ref android.R.styleable#TextView_textColorHint
      */
     @android.view.RemotableViewMethod
-    public final void setHintTextColor(int color) {
+    public final void setHintTextColor(@ColorInt int color) {
         mHintTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -3103,6 +3274,7 @@
      *
      * @return Returns the current hint text color.
      */
+    @ColorInt
     public final int getCurrentHintTextColor() {
         return mHintTextColor != null ? mCurHintTextColor : mCurTextColor;
     }
@@ -3116,7 +3288,7 @@
      * @attr ref android.R.styleable#TextView_textColorLink
      */
     @android.view.RemotableViewMethod
-    public final void setLinkTextColor(int color) {
+    public final void setLinkTextColor(@ColorInt int color) {
         mLinkTextColor = ColorStateList.valueOf(color);
         updateTextColors();
     }
@@ -3663,26 +3835,12 @@
             updateTextColors();
         }
 
-        final Drawables dr = mDrawables;
-        if (dr != null) {
-            int[] state = getDrawableState();
-            if (dr.mDrawableTop != null && dr.mDrawableTop.isStateful()) {
-                dr.mDrawableTop.setState(state);
-            }
-            if (dr.mDrawableBottom != null && dr.mDrawableBottom.isStateful()) {
-                dr.mDrawableBottom.setState(state);
-            }
-            if (dr.mDrawableLeft != null && dr.mDrawableLeft.isStateful()) {
-                dr.mDrawableLeft.setState(state);
-            }
-            if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
-                dr.mDrawableRight.setState(state);
-            }
-            if (dr.mDrawableStart != null && dr.mDrawableStart.isStateful()) {
-                dr.mDrawableStart.setState(state);
-            }
-            if (dr.mDrawableEnd != null && dr.mDrawableEnd.isStateful()) {
-                dr.mDrawableEnd.setState(state);
+        if (mDrawables != null) {
+            final int[] state = getDrawableState();
+            for (Drawable dr : mDrawables.mShowing) {
+                if (dr != null && dr.isStateful()) {
+                    dr.setState(state);
+                }
             }
         }
     }
@@ -3691,25 +3849,12 @@
     public void drawableHotspotChanged(float x, float y) {
         super.drawableHotspotChanged(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);
+        if (mDrawables != null) {
+            final int[] state = getDrawableState();
+            for (Drawable dr : mDrawables.mShowing) {
+                if (dr != null && dr.isStateful()) {
+                    dr.setHotspot(x, y);
+                }
             }
         }
     }
@@ -3757,6 +3902,9 @@
 
             ss.error = getError();
 
+            if (mEditor != null) {
+                ss.editorState = mEditor.saveInstanceState();
+            }
             return ss;
         }
 
@@ -3820,10 +3968,17 @@
             // Display the error later, after the first layout pass
             post(new Runnable() {
                 public void run() {
-                    setError(error);
+                    if (mEditor == null || !mEditor.mErrorWasChanged) {
+                        setError(error);
+                    }
                 }
             });
         }
+
+        if (ss.editorState != null) {
+            createEditorIfNeeded();
+            mEditor.restoreInstanceState(ss.editorState);
+        }
     }
 
     /**
@@ -3970,6 +4125,7 @@
         if (type == BufferType.EDITABLE || getKeyListener() != null ||
                 needEditableForNotification) {
             createEditorIfNeeded();
+            mEditor.forgetUndoRedo();
             Editable t = mEditableFactory.newEditable(text);
             text = t;
             setFilters(t, mFilters);
@@ -4128,11 +4284,11 @@
     }
 
     @android.view.RemotableViewMethod
-    public final void setText(int resid) {
+    public final void setText(@StringRes int resid) {
         setText(getContext().getResources().getText(resid));
     }
 
-    public final void setText(int resid, BufferType type) {
+    public final void setText(@StringRes int resid, BufferType type) {
         setText(getContext().getResources().getText(resid), type);
     }
 
@@ -4168,7 +4324,7 @@
      * @attr ref android.R.styleable#TextView_hint
      */
     @android.view.RemotableViewMethod
-    public final void setHint(int resid) {
+    public final void setHint(@StringRes int resid) {
         setHint(getContext().getResources().getText(resid));
     }
 
@@ -4572,7 +4728,7 @@
      * @see EditorInfo#extras
      * @attr ref android.R.styleable#TextView_editorExtras
      */
-    public void setInputExtras(int xmlResId) throws XmlPullParserException, IOException {
+    public void setInputExtras(@XmlRes int xmlResId) throws XmlPullParserException, IOException {
         createEditorIfNeeded();
         XmlResourceParser parser = getResources().getXml(xmlResId);
         mEditor.createInputContentTypeIfNeeded();
@@ -4800,7 +4956,7 @@
                      * make sure the entire cursor gets invalidated instead of
                      * sometimes missing half a pixel.
                      */
-                    float thick = FloatMath.ceil(mTextPaint.getStrokeWidth());
+                    float thick = (float) Math.ceil(mTextPaint.getStrokeWidth());
                     if (thick < 1.0f) {
                         thick = 1.0f;
                     }
@@ -4810,10 +4966,10 @@
                     // mHighlightPath is guaranteed to be non null at that point.
                     mHighlightPath.computeBounds(TEMP_RECTF, false);
 
-                    invalidate((int) FloatMath.floor(horizontalPadding + TEMP_RECTF.left - thick),
-                            (int) FloatMath.floor(verticalPadding + TEMP_RECTF.top - thick),
-                            (int) FloatMath.ceil(horizontalPadding + TEMP_RECTF.right + thick),
-                            (int) FloatMath.ceil(verticalPadding + TEMP_RECTF.bottom + thick));
+                    invalidate((int) Math.floor(horizontalPadding + TEMP_RECTF.left - thick),
+                            (int) Math.floor(verticalPadding + TEMP_RECTF.top - thick),
+                            (int) Math.ceil(horizontalPadding + TEMP_RECTF.right + thick),
+                            (int) Math.ceil(verticalPadding + TEMP_RECTF.bottom + thick));
                 }
             } else {
                 for (int i = 0; i < mEditor.mCursorCount; i++) {
@@ -5038,9 +5194,11 @@
     protected boolean verifyDrawable(Drawable who) {
         final boolean verified = super.verifyDrawable(who);
         if (!verified && mDrawables != null) {
-            return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
-                    who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom ||
-                    who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd;
+            for (Drawable dr : mDrawables.mShowing) {
+                if (who == dr) {
+                    return true;
+                }
+            }
         }
         return verified;
     }
@@ -5049,23 +5207,10 @@
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
         if (mDrawables != null) {
-            if (mDrawables.mDrawableLeft != null) {
-                mDrawables.mDrawableLeft.jumpToCurrentState();
-            }
-            if (mDrawables.mDrawableTop != null) {
-                mDrawables.mDrawableTop.jumpToCurrentState();
-            }
-            if (mDrawables.mDrawableRight != null) {
-                mDrawables.mDrawableRight.jumpToCurrentState();
-            }
-            if (mDrawables.mDrawableBottom != null) {
-                mDrawables.mDrawableBottom.jumpToCurrentState();
-            }
-            if (mDrawables.mDrawableStart != null) {
-                mDrawables.mDrawableStart.jumpToCurrentState();
-            }
-            if (mDrawables.mDrawableEnd != null) {
-                mDrawables.mDrawableEnd.jumpToCurrentState();
+            for (Drawable dr : mDrawables.mShowing) {
+                if (dr != null) {
+                    dr.jumpToCurrentState();
+                }
             }
         }
     }
@@ -5084,7 +5229,7 @@
             // accordingly.
             final TextView.Drawables drawables = mDrawables;
             if (drawables != null) {
-                if (drawable == drawables.mDrawableLeft) {
+                if (drawable == drawables.mShowing[Drawables.LEFT]) {
                     final int compoundPaddingTop = getCompoundPaddingTop();
                     final int compoundPaddingBottom = getCompoundPaddingBottom();
                     final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
@@ -5092,7 +5237,7 @@
                     scrollX += mPaddingLeft;
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightLeft) / 2;
                     handled = true;
-                } else if (drawable == drawables.mDrawableRight) {
+                } else if (drawable == drawables.mShowing[Drawables.RIGHT]) {
                     final int compoundPaddingTop = getCompoundPaddingTop();
                     final int compoundPaddingBottom = getCompoundPaddingBottom();
                     final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
@@ -5100,7 +5245,7 @@
                     scrollX += (mRight - mLeft - mPaddingRight - drawables.mDrawableSizeRight);
                     scrollY += compoundPaddingTop + (vspace - drawables.mDrawableHeightRight) / 2;
                     handled = true;
-                } else if (drawable == drawables.mDrawableTop) {
+                } else if (drawable == drawables.mShowing[Drawables.TOP]) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
                     final int hspace = mRight - mLeft - compoundPaddingRight - compoundPaddingLeft;
@@ -5108,7 +5253,7 @@
                     scrollX += compoundPaddingLeft + (hspace - drawables.mDrawableWidthTop) / 2;
                     scrollY += mPaddingTop;
                     handled = true;
-                } else if (drawable == drawables.mDrawableBottom) {
+                } else if (drawable == drawables.mShowing[Drawables.BOTTOM]) {
                     final int compoundPaddingLeft = getCompoundPaddingLeft();
                     final int compoundPaddingRight = getCompoundPaddingRight();
                     final int hspace = mRight - mLeft - compoundPaddingRight - compoundPaddingLeft;
@@ -5312,44 +5457,44 @@
 
             // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
             // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mDrawableLeft != null) {
+            if (dr.mShowing[Drawables.LEFT] != null) {
                 canvas.save();
                 canvas.translate(scrollX + mPaddingLeft + leftOffset,
                                  scrollY + compoundPaddingTop +
                                  (vspace - dr.mDrawableHeightLeft) / 2);
-                dr.mDrawableLeft.draw(canvas);
+                dr.mShowing[Drawables.LEFT].draw(canvas);
                 canvas.restore();
             }
 
             // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
             // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mDrawableRight != null) {
+            if (dr.mShowing[Drawables.RIGHT] != null) {
                 canvas.save();
                 canvas.translate(scrollX + right - left - mPaddingRight
                         - dr.mDrawableSizeRight - rightOffset,
                          scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2);
-                dr.mDrawableRight.draw(canvas);
+                dr.mShowing[Drawables.RIGHT].draw(canvas);
                 canvas.restore();
             }
 
             // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
             // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mDrawableTop != null) {
+            if (dr.mShowing[Drawables.TOP] != null) {
                 canvas.save();
                 canvas.translate(scrollX + compoundPaddingLeft +
                         (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop);
-                dr.mDrawableTop.draw(canvas);
+                dr.mShowing[Drawables.TOP].draw(canvas);
                 canvas.restore();
             }
 
             // IMPORTANT: The coordinates computed are also used in invalidateDrawable()
             // Make sure to update invalidateDrawable() when changing this code.
-            if (dr.mDrawableBottom != null) {
+            if (dr.mShowing[Drawables.BOTTOM] != null) {
                 canvas.save();
                 canvas.translate(scrollX + compoundPaddingLeft +
                         (hspace - dr.mDrawableWidthBottom) / 2,
                          scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom);
-                dr.mDrawableBottom.draw(canvas);
+                dr.mShowing[Drawables.BOTTOM].draw(canvas);
                 canvas.restore();
             }
         }
@@ -6507,7 +6652,7 @@
             max = Math.max(max, layout.getLineWidth(i));
         }
 
-        return (int) FloatMath.ceil(max);
+        return (int) Math.ceil(max);
     }
 
     /**
@@ -6584,7 +6729,7 @@
 
             if (boring == null || boring == UNKNOWN_BORING) {
                 if (des < 0) {
-                    des = (int) FloatMath.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint));
+                    des = (int) Math.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint));
                 }
                 width = des;
             } else {
@@ -6614,7 +6759,7 @@
 
                 if (hintBoring == null || hintBoring == UNKNOWN_BORING) {
                     if (hintDes < 0) {
-                        hintDes = (int) FloatMath.ceil(Layout.getDesiredWidth(mHint, mTextPaint));
+                        hintDes = (int) Math.ceil(Layout.getDesiredWidth(mHint, mTextPaint));
                     }
                     hintWidth = hintDes;
                 } else {
@@ -6920,8 +7065,8 @@
              * keep leading edge in view.
              */
 
-            int left = (int) FloatMath.floor(layout.getLineLeft(line));
-            int right = (int) FloatMath.ceil(layout.getLineRight(line));
+            int left = (int) Math.floor(layout.getLineLeft(line));
+            int right = (int) Math.ceil(layout.getLineRight(line));
 
             if (right - left < hspace) {
                 scrollx = (right + left) / 2 - hspace / 2;
@@ -6933,10 +7078,10 @@
                 }
             }
         } else if (a == Layout.Alignment.ALIGN_RIGHT) {
-            int right = (int) FloatMath.ceil(layout.getLineRight(line));
+            int right = (int) Math.ceil(layout.getLineRight(line));
             scrollx = right - hspace;
         } else { // a == Layout.Alignment.ALIGN_LEFT (will also be the default)
-            scrollx = (int) FloatMath.floor(layout.getLineLeft(line));
+            scrollx = (int) Math.floor(layout.getLineLeft(line));
         }
 
         if (ht < vspace) {
@@ -7011,8 +7156,8 @@
         final int top = layout.getLineTop(line);
         final int bottom = layout.getLineTop(line + 1);
 
-        int left = (int) FloatMath.floor(layout.getLineLeft(line));
-        int right = (int) FloatMath.ceil(layout.getLineRight(line));
+        int left = (int) Math.floor(layout.getLineLeft(line));
+        int right = (int) Math.ceil(layout.getLineRight(line));
         int ht = layout.getHeight();
 
         int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
@@ -7960,7 +8105,14 @@
     public boolean onTouchEvent(MotionEvent event) {
         final int action = event.getActionMasked();
 
-        if (mEditor != null) mEditor.onTouchEvent(event);
+        if (mEditor != null) {
+            mEditor.onTouchEvent(event);
+
+            if (mEditor.mSelectionModifierCursorController != null &&
+                    mEditor.mSelectionModifierCursorController.isDragAcceleratorActive()) {
+                return true;
+            }
+        }
 
         final boolean superResult = super.onTouchEvent(event);
 
@@ -8242,14 +8394,19 @@
 
     @Override
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
-        final int filteredMetaState = event.getMetaState() & ~KeyEvent.META_CTRL_MASK;
-        if (KeyEvent.metaStateHasNoModifiers(filteredMetaState)) {
+        if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
+            // Handle Ctrl-only shortcuts.
             switch (keyCode) {
             case KeyEvent.KEYCODE_A:
                 if (canSelectText()) {
                     return onTextContextMenuItem(ID_SELECT_ALL);
                 }
                 break;
+            case KeyEvent.KEYCODE_Z:
+                if (canUndo()) {
+                    return onTextContextMenuItem(ID_UNDO);
+                }
+                break;
             case KeyEvent.KEYCODE_X:
                 if (canCut()) {
                     return onTextContextMenuItem(ID_CUT);
@@ -8266,6 +8423,19 @@
                 }
                 break;
             }
+        } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
+            // Handle Ctrl-Shift shortcuts.
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_Z:
+                    if (canRedo()) {
+                        return onTextContextMenuItem(ID_REDO);
+                    }
+                    break;
+                case KeyEvent.KEYCODE_V:
+                    if (canPaste()) {
+                        return onTextContextMenuItem(ID_PASTE_AS_PLAIN_TEXT);
+                    }
+            }
         }
         return super.onKeyShortcut(keyCode, event);
     }
@@ -8380,9 +8550,10 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEventInternal(event);
 
         final boolean isPassword = hasPasswordTransformationMethod();
         if (!isPassword || shouldSpeakPasswordsForAccessibility()) {
@@ -8404,10 +8575,26 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
+    public CharSequence getAccessibilityClassName() {
+        return TextView.class.getName();
+    }
 
-        event.setClassName(TextView.class.getName());
+    @Override
+    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
+        super.onProvideAssistStructure(structure, extras);
+        final boolean isPassword = hasPasswordTransformationMethod();
+        if (!isPassword) {
+            structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+            structure.setTextPaint(mTextPaint);
+        }
+        structure.setHint(getHint());
+    }
+
+    /** @hide */
+    @Override
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
+
         final boolean isPassword = hasPasswordTransformationMethod();
         event.setPassword(isPassword);
 
@@ -8418,11 +8605,11 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
-        info.setClassName(TextView.class.getName());
         final boolean isPassword = hasPasswordTransformationMethod();
         info.setPassword(isPassword);
 
@@ -8578,15 +8765,16 @@
         }
     }
 
+    /** @hide */
     @Override
-    public void sendAccessibilityEvent(int eventType) {
+    public void sendAccessibilityEventInternal(int eventType) {
         // Do not send scroll events since first they are not interesting for
         // accessibility and second such events a generated too frequently.
         // For details see the implementation of bringTextIntoView().
         if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
             return;
         }
-        super.sendAccessibilityEvent(eventType);
+        super.sendAccessibilityEventInternal(eventType);
     }
 
     /**
@@ -8625,9 +8813,13 @@
     }
 
     static final int ID_SELECT_ALL = android.R.id.selectAll;
+    static final int ID_UNDO = android.R.id.undo;
+    static final int ID_REDO = android.R.id.redo;
     static final int ID_CUT = android.R.id.cut;
     static final int ID_COPY = android.R.id.copy;
     static final int ID_PASTE = android.R.id.paste;
+    static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
+    static final int ID_REPLACE = android.R.id.replaceText;
 
     /**
      * Called when a context menu option for the text view is selected.  Currently
@@ -8655,8 +8847,24 @@
                 selectAllText();
                 return true;
 
+            case ID_UNDO:
+                if (mEditor != null) {
+                    mEditor.undo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
+            case ID_REDO:
+                if (mEditor != null) {
+                    mEditor.redo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
             case ID_PASTE:
-                paste(min, max);
+                paste(min, max, true /* withFormatting */);
+                return true;
+
+            case ID_PASTE_AS_PLAIN_TEXT:
+                paste(min, max, false /* withFormatting */);
                 return true;
 
             case ID_CUT:
@@ -8784,7 +8992,17 @@
      * @hide
      */
     protected void stopSelectionActionMode() {
-        mEditor.stopSelectionActionMode();
+        if (mEditor != null) {
+            mEditor.stopSelectionActionMode();
+        }
+    }
+
+    boolean canUndo() {
+        return mEditor != null && mEditor.canUndo();
+    }
+
+    boolean canRedo() {
+        return mEditor != null && mEditor.canRedo();
     }
 
     boolean canCut() {
@@ -8830,14 +9048,21 @@
     /**
      * Paste clipboard content between min and max positions.
      */
-    private void paste(int min, int max) {
+    private void paste(int min, int max, boolean withFormatting) {
         ClipboardManager clipboard =
             (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
         ClipData clip = clipboard.getPrimaryClip();
         if (clip != null) {
             boolean didFirst = false;
             for (int i=0; i<clip.getItemCount(); i++) {
-                CharSequence paste = clip.getItemAt(i).coerceToStyledText(getContext());
+                final CharSequence paste;
+                if (withFormatting) {
+                    paste = clip.getItemAt(i).coerceToStyledText(getContext());
+                } else {
+                    // Get an item as text and remove all spans by toString().
+                    final CharSequence text = clip.getItemAt(i).coerceToText(getContext());
+                    paste = (text instanceof Spanned) ? text.toString() : text;
+                }
                 if (paste != null) {
                     if (!didFirst) {
                         Selection.setSelection((Spannable) mText, max);
@@ -8895,7 +9120,7 @@
         return getLayout().getLineForVertical((int) y);
     }
 
-    private int getOffsetAtCoordinate(int line, float x) {
+    int getOffsetAtCoordinate(int line, float x) {
         x = convertToLocalHorizontalCoordinate(x);
         return getLayout().getOffsetForHorizontal(line, x);
     }
@@ -9154,6 +9379,7 @@
         CharSequence text;
         boolean frozenWithFocus;
         CharSequence error;
+        ParcelableParcel editorState;  // Optional state from Editor.
 
         SavedState(Parcelable superState) {
             super(superState);
@@ -9173,6 +9399,13 @@
                 out.writeInt(1);
                 TextUtils.writeToParcel(error, out, flags);
             }
+
+            if (editorState == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                editorState.writeToParcel(out, flags);
+            }
         }
 
         @Override
@@ -9208,6 +9441,10 @@
             if (in.readInt() != 0) {
                 error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             }
+
+            if (in.readInt() != 0) {
+                editorState = ParcelableParcel.CREATOR.createFromParcel(in);
+            }
         }
     }
 
diff --git a/core/java/android/widget/TextViewWithCircularIndicator.java b/core/java/android/widget/TextViewWithCircularIndicator.java
index 43c0843..d3c786c 100644
--- a/core/java/android/widget/TextViewWithCircularIndicator.java
+++ b/core/java/android/widget/TextViewWithCircularIndicator.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Typeface;
@@ -27,14 +26,8 @@
 import com.android.internal.R;
 
 class TextViewWithCircularIndicator extends TextView {
-
-    private static final int SELECTED_CIRCLE_ALPHA = 60;
-
     private final Paint mCirclePaint = new Paint();
-
     private final String mItemIsSelectedText;
-    private int mCircleColor;
-    private boolean mDrawIndicator;
 
     public TextViewWithCircularIndicator(Context context) {
         this(context, null);
@@ -50,22 +43,11 @@
 
     public TextViewWithCircularIndicator(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
-        super(context, attrs);
-
-
-        // Use Theme attributes if possible
-        final TypedArray a = mContext.obtainStyledAttributes(attrs,
-                R.styleable.DatePicker, defStyleAttr, defStyleRes);
-        final int resId = a.getResourceId(R.styleable.DatePicker_yearListItemTextAppearance, -1);
-        if (resId != -1) {
-            setTextAppearance(context, resId);
-        }
+        super(context, attrs, defStyleAttr, defStyleRes);
 
         final Resources res = context.getResources();
         mItemIsSelectedText = res.getString(R.string.item_is_selected);
 
-        a.recycle();
-
         init();
     }
 
@@ -77,33 +59,26 @@
     }
 
     public void setCircleColor(int color) {
-        if (color != mCircleColor) {
-            mCircleColor = color;
-            mCirclePaint.setColor(mCircleColor);
-            mCirclePaint.setAlpha(SELECTED_CIRCLE_ALPHA);
-            requestLayout();
-        }
-    }
-
-    public void setDrawIndicator(boolean drawIndicator) {
-        mDrawIndicator = drawIndicator;
+        mCirclePaint.setColor(color);
+        invalidate();
     }
 
     @Override
     public void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        if (mDrawIndicator) {
+        if (isActivated()) {
             final int width = getWidth();
             final int height = getHeight();
-            int radius = Math.min(width, height) / 2;
+            final int radius = Math.min(width, height) / 2;
             canvas.drawCircle(width / 2, height / 2, radius, mCirclePaint);
         }
+
+        super.onDraw(canvas);
     }
 
     @Override
     public CharSequence getContentDescription() {
-        CharSequence itemText = getText();
-        if (mDrawIndicator) {
+        final CharSequence itemText = getText();
+        if (isActivated()) {
             return String.format(mItemIsSelectedText, itemText);
         } else {
             return itemText;
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 26e02f8..944b491 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -24,8 +24,6 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-
 import com.android.internal.R;
 
 import java.util.Locale;
@@ -196,28 +194,16 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public CharSequence getAccessibilityClassName() {
+        return TimePicker.class.getName();
+    }
+
+    /** @hide */
+    @Override
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         return mDelegate.dispatchPopulateAccessibilityEvent(event);
     }
 
-    @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
-        mDelegate.onPopulateAccessibilityEvent(event);
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        mDelegate.onInitializeAccessibilityEvent(event);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        mDelegate.onInitializeAccessibilityNodeInfo(info);
-    }
-
     /**
      * A delegate interface that defined the public API of the TimePicker. Allows different
      * TimePicker implementations. This would need to be implemented by the TimePicker delegates
@@ -248,8 +234,6 @@
 
         boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
         void onPopulateAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityEvent(AccessibilityEvent event);
-        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
     }
 
     /**
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 1534429..9fdd718 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -17,7 +17,6 @@
 package android.widget;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -34,7 +33,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -91,6 +89,7 @@
     private int mInitialHourOfDay;
     private int mInitialMinute;
     private boolean mIs24HourView;
+    private boolean mIsAmPmAtStart;
 
     // For hardware IME input.
     private char mPlaceholderText;
@@ -131,19 +130,19 @@
         mPmText = amPmStrings[1];
 
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
-                R.layout.time_picker_holo);
+                R.layout.time_picker_material);
         final View mainView = inflater.inflate(layoutResourceId, delegator);
 
         mHeaderView = mainView.findViewById(R.id.time_header);
         mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
 
         // Set up hour/minute labels.
-        mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
+        mHourView = (TextView) mainView.findViewById(R.id.hours);
         mHourView.setOnClickListener(mClickListener);
         mHourView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_hours));
-        mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
-        mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
+        mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
+        mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
         mMinuteView.setOnClickListener(mClickListener);
         mMinuteView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_minutes));
@@ -161,17 +160,8 @@
         mHourView.setMinWidth(computeStableWidth(mHourView, 24));
         mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
 
-        // TODO: This can be removed once we support themed color state lists.
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.TimePicker_headerSelectedTextColor,
-                res.getColor(R.color.timepicker_default_selector_color_material));
-        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-
         // Set up AM/PM labels.
-        mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
+        mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
         mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
         mAmLabel.setText(amPmStrings[0]);
         mAmLabel.setOnClickListener(mClickListener);
@@ -284,24 +274,40 @@
     }
 
     private void updateHeaderAmPm() {
+
         if (mIs24HourView) {
             mAmPmLayout.setVisibility(View.GONE);
         } else {
             // Ensure that AM/PM layout is in the correct position.
             final String dateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, "hm");
-            final boolean amPmAtStart = dateTimePattern.startsWith("a");
-            final ViewGroup parent = (ViewGroup) mAmPmLayout.getParent();
-            final int targetIndex = amPmAtStart ? 0 : parent.getChildCount() - 1;
-            final int currentIndex = parent.indexOfChild(mAmPmLayout);
-            if (targetIndex != currentIndex) {
-                parent.removeView(mAmPmLayout);
-                parent.addView(mAmPmLayout, targetIndex);
-            }
+            final boolean isAmPmAtStart = dateTimePattern.startsWith("a");
+            setAmPmAtStart(isAmPmAtStart);
 
             updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
         }
     }
 
+    private void setAmPmAtStart(boolean isAmPmAtStart) {
+        if (mIsAmPmAtStart != isAmPmAtStart) {
+            mIsAmPmAtStart = isAmPmAtStart;
+
+            final RelativeLayout.LayoutParams params =
+                    (RelativeLayout.LayoutParams) mAmPmLayout.getLayoutParams();
+            if (params.getRule(RelativeLayout.RIGHT_OF) != 0 ||
+                    params.getRule(RelativeLayout.LEFT_OF) != 0) {
+                if (isAmPmAtStart) {
+                    params.removeRule(RelativeLayout.RIGHT_OF);
+                    params.addRule(RelativeLayout.LEFT_OF, mHourView.getId());
+                } else {
+                    params.removeRule(RelativeLayout.LEFT_OF);
+                    params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId());
+                }
+            }
+
+            mAmPmLayout.setLayoutParams(params);
+        }
+    }
+
     /**
      * Set the current hour.
      */
@@ -466,16 +472,6 @@
         event.getText().add(selectedDate);
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(TimePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(TimePicker.class.getName());
-    }
-
     /**
      * Set whether in keyboard mode or not.
      *
@@ -609,11 +605,11 @@
     private void updateAmPmLabelStates(int amOrPm) {
         final boolean isAm = amOrPm == AM;
         mAmLabel.setChecked(isAm);
-        mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
+        mAmLabel.setSelected(isAm);
 
         final boolean isPm = amOrPm == PM;
         mPmLabel.setChecked(isPm);
-        mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
+        mPmLabel.setSelected(isPm);
     }
 
     /**
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index e162f4a..513c55b 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -28,12 +28,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
 import java.util.Calendar;
 import java.util.Locale;
 
@@ -427,16 +425,6 @@
         event.getText().add(selectedDateUtterance);
     }
 
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        event.setClassName(TimePicker.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        info.setClassName(TimePicker.class.getName());
-    }
-
     private void updateInputState() {
         // Make sure that if the user changes the value and the IME is active
         // for one of the inputs if this widget, the IME is closed. If the user
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index be4cdc1..207f675 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.IntDef;
+import android.annotation.StringRes;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
 import android.content.Context;
@@ -280,7 +281,7 @@
      *
      * @throws Resources.NotFoundException if the resource can't be found.
      */
-    public static Toast makeText(Context context, int resId, @Duration int duration)
+    public static Toast makeText(Context context, @StringRes int resId, @Duration int duration)
                                 throws Resources.NotFoundException {
         return makeText(context, context.getResources().getText(resId), duration);
     }
@@ -289,7 +290,7 @@
      * Update the text in a Toast that was previously created using one of the makeText() methods.
      * @param resId The new text for the Toast.
      */
-    public void setText(int resId) {
+    public void setText(@StringRes int resId) {
         setText(mContext.getText(resId));
     }
     
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index 28519d1..6a8449e 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -21,8 +21,6 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * Displays checked/unchecked states as a button
@@ -154,14 +152,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ToggleButton.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ToggleButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ToggleButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index c5325c4..d2430bc 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -16,12 +16,14 @@
 
 package android.widget;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.RectF;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,6 +106,9 @@
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
+    private TintInfo mOverflowTintInfo;
+    private TintInfo mNavTintInfo;
+
     private Drawable mCollapseIcon;
     private CharSequence mCollapseDescription;
     private ImageButton mCollapseButtonView;
@@ -266,6 +271,21 @@
         if (!TextUtils.isEmpty(navDesc)) {
             setNavigationContentDescription(navDesc);
         }
+
+        if (a.hasValue(R.styleable.Toolbar_overflowTint)) {
+            setOverflowTintList(a.getColorStateList(R.styleable.Toolbar_overflowTint));
+        }
+        if (a.hasValue(R.styleable.Toolbar_overflowTintMode)) {
+            setOverflowTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.Toolbar_overflowTintMode, -1), null));
+        }
+        if (a.hasValue(R.styleable.Toolbar_navigationTint)) {
+            setNavigationTintList(a.getColorStateList(R.styleable.Toolbar_navigationTint));
+        }
+        if (a.hasValue(R.styleable.Toolbar_navigationTintMode)) {
+            setNavigationTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.Toolbar_navigationTintMode, -1), null));
+        }
         a.recycle();
     }
 
@@ -666,7 +686,7 @@
      *
      * @param color The new text color in 0xAARRGGBB format
      */
-    public void setTitleTextColor(int color) {
+    public void setTitleTextColor(@ColorInt int color) {
         mTitleTextColor = color;
         if (mTitleTextView != null) {
             mTitleTextView.setTextColor(color);
@@ -678,7 +698,7 @@
      *
      * @param color The new text color in 0xAARRGGBB format
      */
-    public void setSubtitleTextColor(int color) {
+    public void setSubtitleTextColor(@ColorInt int color) {
         mSubtitleTextColor = color;
         if (mSubtitleTextView != null) {
             mSubtitleTextView.setTextColor(color);
@@ -806,6 +826,91 @@
     }
 
     /**
+     * Applies a tint to the icon drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setNavigationIcon(Drawable)} will automatically mutate
+     * the drawable and apply the specified tint and tint mode.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationTint
+     */
+    public void setNavigationTintList(ColorStateList tint) {
+        if (mNavTintInfo == null) {
+            mNavTintInfo = new TintInfo();
+        }
+        mNavTintInfo.mTintList = tint;
+        mNavTintInfo.mHasTintList = true;
+
+        applyNavigationTint();
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setNavigationTintList(ColorStateList)} to the navigation drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationTintMode
+     */
+    public void setNavigationTintMode(PorterDuff.Mode tintMode) {
+        if (mNavTintInfo == null) {
+            mNavTintInfo = new TintInfo();
+        }
+        mNavTintInfo.mTintMode = tintMode;
+        mNavTintInfo.mHasTintMode = true;
+
+        applyNavigationTint();
+    }
+
+    /**
+     * Applies a tint to the overflow drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_overflowTint
+     */
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mMenuView != null) {
+            // If the menu view is available, directly set the tint
+            mMenuView.setOverflowTintList(tint);
+        } else {
+            // Otherwise we will record the value
+            if (mOverflowTintInfo == null) {
+                mOverflowTintInfo = new TintInfo();
+            }
+            mOverflowTintInfo.mTintList = tint;
+            mOverflowTintInfo.mHasTintList = true;
+        }
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setOverflowTintList(ColorStateList)} to the overflow drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_overflowTintMode
+     */
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mMenuView != null) {
+            // If the menu view is available, directly set the tint mode
+            mMenuView.setOverflowTintMode(tintMode);
+        } else {
+            // Otherwise we will record the value
+            if (mOverflowTintInfo == null) {
+                mOverflowTintInfo = new TintInfo();
+            }
+            mOverflowTintInfo.mTintMode = tintMode;
+            mOverflowTintInfo.mHasTintMode = true;
+        }
+    }
+
+    /**
      * Return the Menu shown in the toolbar.
      *
      * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -841,6 +946,17 @@
             lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             mMenuView.setLayoutParams(lp);
             addSystemView(mMenuView);
+
+            if (mOverflowTintInfo != null) {
+                // If we have tint info for the overflow, set it on the menu view now
+                if (mOverflowTintInfo.mHasTintList) {
+                    mMenuView.setOverflowTintList(mOverflowTintInfo.mTintList);
+                }
+                if (mOverflowTintInfo.mHasTintMode) {
+                    mMenuView.setOverflowTintMode(mOverflowTintInfo.mTintMode);
+                }
+                mOverflowTintInfo = null;
+            }
         }
     }
 
@@ -994,6 +1110,7 @@
             final LayoutParams lp = generateDefaultLayoutParams();
             lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             mNavButtonView.setLayoutParams(lp);
+            applyNavigationTint();
         }
     }
 
@@ -1012,6 +1129,7 @@
                     collapseActionView();
                 }
             });
+            applyNavigationTint();
         }
     }
 
@@ -1763,6 +1881,30 @@
         return mPopupContext;
     }
 
+    private void applyNavigationTint() {
+        final TintInfo tintInfo = mNavTintInfo;
+        if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
+            if (mNavButtonView != null) {
+                if (tintInfo.mHasTintList) {
+                    mNavButtonView.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mNavButtonView.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+
+            if (mCollapseButtonView != null) {
+                // We will use the same tint for the collapse button
+                if (tintInfo.mHasTintList) {
+                    mCollapseButtonView.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mCollapseButtonView.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
     /**
      * Interface responsible for receiving menu item click events if the items themselves
      * do not have individual item click listeners.
@@ -1990,4 +2132,11 @@
         public void onRestoreInstanceState(Parcelable state) {
         }
     }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java
index 5606c60..69ff488 100644
--- a/core/java/android/widget/TwoLineListItem.java
+++ b/core/java/android/widget/TwoLineListItem.java
@@ -20,8 +20,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RelativeLayout;
 
 /**
@@ -94,14 +92,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TwoLineListItem.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TwoLineListItem.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return TwoLineListItem.class.getName();
     }
 }
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 572cca2..2671739 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -43,8 +43,6 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.MediaController.MediaPlayerControl;
 
 import java.io.IOException;
@@ -202,15 +200,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(VideoView.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(VideoView.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return VideoView.class.getName();
     }
 
     public int resolveAdjustedSize(int desiredSize, int measureSpec) {
@@ -311,6 +302,8 @@
             mMediaPlayer = null;
             mCurrentState = STATE_IDLE;
             mTargetState  = STATE_IDLE;
+            AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+            am.abandonAudioFocus(null);
         }
     }
 
@@ -319,12 +312,13 @@
             // not ready for playback just yet, will try again later
             return;
         }
-        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
-
         // we shouldn't clear the target state, because somebody might have
         // called start() previously
         release(false);
+
+        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+
         try {
             mMediaPlayer = new MediaPlayer();
             // TODO: create SubtitleController in MediaPlayer, but we need
@@ -650,6 +644,8 @@
             if (cleartargetstate) {
                 mTargetState  = STATE_IDLE;
             }
+            AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+            am.abandonAudioFocus(null);
         }
     }
 
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index eee914e..f30fdd8 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -22,8 +22,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
@@ -358,14 +356,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ViewAnimator.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ViewAnimator.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewAnimator.class.getName();
     }
 }
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index cf1f554..94e7ba1 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -24,8 +24,6 @@
 import android.os.*;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
 /**
@@ -150,15 +148,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ViewFlipper.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ViewFlipper.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewFlipper.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/ViewSwitcher.java b/core/java/android/widget/ViewSwitcher.java
index 0376918..0d5627e 100644
--- a/core/java/android/widget/ViewSwitcher.java
+++ b/core/java/android/widget/ViewSwitcher.java
@@ -20,8 +20,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * {@link ViewAnimator} that switches between two views, and has a factory
@@ -69,15 +67,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ViewSwitcher.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ViewSwitcher.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ViewSwitcher.class.getName();
     }
 
     /**
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index 24ed7ce..6f0465f 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -17,8 +17,10 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.util.AttributeSet;
+import android.util.StateSet;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -42,7 +44,7 @@
     private DatePickerController mController;
 
     private int mSelectedPosition = -1;
-    private int mYearSelectedCircleColor;
+    private int mYearActivatedColor;
 
     public YearPickerView(Context context) {
         this(context, null);
@@ -97,15 +99,14 @@
         onDateChanged();
     }
 
-    public void setYearSelectedCircleColor(int color) {
-        if (color != mYearSelectedCircleColor) {
-            mYearSelectedCircleColor = color;
-        }
-        requestLayout();
+    public void setYearBackgroundColor(ColorStateList yearBackgroundColor) {
+        mYearActivatedColor = yearBackgroundColor.getColorForState(
+                StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
+        invalidate();
     }
 
-    public int getYearSelectedCircleColor()  {
-        return mYearSelectedCircleColor;
+    public void setYearTextAppearance(int resId) {
+        mAdapter.setItemTextAppearance(resId);
     }
 
     private void updateAdapterData() {
@@ -127,12 +128,8 @@
         mController.onYearSelected(mAdapter.getItem(position));
     }
 
-    void setItemTextAppearance(int resId) {
-        mAdapter.setItemTextAppearance(resId);
-    }
-
     private class YearAdapter extends ArrayAdapter<Integer> {
-        int mItemTextAppearanceResId;
+        private int mItemTextAppearanceResId;
 
         public YearAdapter(Context context, int resource) {
             super(context, resource);
@@ -140,16 +137,15 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            TextViewWithCircularIndicator v = (TextViewWithCircularIndicator)
+            final TextViewWithCircularIndicator v = (TextViewWithCircularIndicator)
                     super.getView(position, convertView, parent);
-            v.setTextAppearance(getContext(), mItemTextAppearanceResId);
-            v.requestLayout();
-            int year = getItem(position);
-            boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year;
-            v.setDrawIndicator(selected);
-            if (selected) {
-                v.setCircleColor(mYearSelectedCircleColor);
-            }
+            v.setTextAppearance(v.getContext(), mItemTextAppearanceResId);
+            v.setCircleColor(mYearActivatedColor);
+
+            final int year = getItem(position);
+            final boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year;
+            v.setActivated(selected);
+
             return v;
         }
 
@@ -189,9 +185,10 @@
                 mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
     }
 
+    /** @hide */
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEventInternal(event);
 
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
             event.setFromIndex(0);
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index 715e868..0255bdb 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -23,8 +23,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLongClickListener;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 public class ZoomButton extends ImageButton implements OnLongClickListener {
 
@@ -104,14 +102,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ZoomButton.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ZoomButton.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ZoomButton.class.getName();
     }
 }
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index 8897875..66c052b 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -22,8 +22,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AlphaAnimation;
 
 import com.android.internal.R;
@@ -110,14 +108,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ZoomControls.class.getName());
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ZoomControls.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ZoomControls.class.getName();
     }
 }
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
new file mode 100644
index 0000000..5c0a888
--- /dev/null
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.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.internal.alsa;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * @hide Retrieves information from an ALSA "cards" file.
+ */
+public class AlsaCardsParser {
+    private static final String TAG = "AlsaCardsParser";
+    protected static final boolean DEBUG = true;
+
+    private static final String kCardsFilePath = "/proc/asound/cards";
+
+    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]");
+
+    private ArrayList<AlsaCardRecord> mCardRecords = new ArrayList<AlsaCardRecord>();
+
+    public class AlsaCardRecord {
+        private static final String TAG = "AlsaCardRecord";
+        private static final String kUsbCardKeyStr = "at usb-";
+
+        public int mCardNum = -1;
+        public String mField1 = "";
+        public String mCardName = "";
+        public String mCardDescription = "";
+        public boolean mIsUsb = false;
+
+        public AlsaCardRecord() {}
+
+        public boolean parse(String line, int lineIndex) {
+            int tokenIndex = 0;
+            int delimIndex = 0;
+
+            if (lineIndex == 0) {
+                // line # (skip)
+                tokenIndex = mTokenizer.nextToken(line, tokenIndex);
+                delimIndex = mTokenizer.nextDelimiter(line, tokenIndex);
+
+                try {
+                    // mCardNum
+                    mCardNum = Integer.parseInt(line.substring(tokenIndex, delimIndex));
+                } catch (NumberFormatException e) {
+                    Slog.e(TAG, "Failed to parse line " + lineIndex + " of " + kCardsFilePath
+                        + ": " + line.substring(tokenIndex, delimIndex));
+                    return false;
+                }
+
+                // mField1
+                tokenIndex = mTokenizer.nextToken(line, delimIndex);
+                delimIndex = mTokenizer.nextDelimiter(line, tokenIndex);
+                mField1 = line.substring(tokenIndex, delimIndex);
+
+                // mCardName
+                tokenIndex = mTokenizer.nextToken(line, delimIndex);
+                mCardName = line.substring(tokenIndex);
+
+                // done
+              } else if (lineIndex == 1) {
+                  tokenIndex = mTokenizer.nextToken(line, 0);
+                  if (tokenIndex != -1) {
+                      int keyIndex = line.indexOf(kUsbCardKeyStr);
+                      mIsUsb = keyIndex != -1;
+                      if (mIsUsb) {
+                          mCardDescription = line.substring(tokenIndex, keyIndex - 1);
+                      }
+                  }
+            }
+
+            return true;
+        }
+
+        public String textFormat() {
+          return mCardName + " : " + mCardDescription;
+        }
+    }
+
+    public AlsaCardsParser() {}
+
+    public void scan() {
+        if (DEBUG) {
+            Slog.i(TAG, "AlsaCardsParser.scan()");
+        }
+        mCardRecords = new ArrayList<AlsaCardRecord>();
+
+        File cardsFile = new File(kCardsFilePath);
+        try {
+            FileReader reader = new FileReader(cardsFile);
+            BufferedReader bufferedReader = new BufferedReader(reader);
+            String line = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                AlsaCardRecord cardRecord = new AlsaCardRecord();
+                if (DEBUG) {
+                    Slog.i(TAG, "  " + line);
+                }
+                cardRecord.parse(line, 0);
+
+                line = bufferedReader.readLine();
+                if (line == null) {
+                    break;
+                }
+                if (DEBUG) {
+                    Slog.i(TAG, "  " + line);
+                }
+                cardRecord.parse(line, 1);
+
+                mCardRecords.add(cardRecord);
+            }
+            reader.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public ArrayList<AlsaCardRecord> getScanRecords() {
+        return mCardRecords;
+    }
+
+    public AlsaCardRecord getCardRecordAt(int index) {
+        return mCardRecords.get(index);
+    }
+
+    public AlsaCardRecord getCardRecordFor(int cardNum) {
+        for (AlsaCardRecord rec : mCardRecords) {
+            if (rec.mCardNum == cardNum) {
+                return rec;
+            }
+        }
+
+        return null;
+    }
+
+    public int getNumCardRecords() {
+        return mCardRecords.size();
+    }
+
+    public boolean isCardUsb(int cardNum) {
+        for (AlsaCardRecord rec : mCardRecords) {
+            if (rec.mCardNum == cardNum) {
+                return rec.mIsUsb;
+            }
+        }
+
+        return false;
+    }
+
+    // return -1 if none found
+    public int getDefaultUsbCard() {
+        // Choose the most-recently added EXTERNAL card
+        // or return the first added EXTERNAL card?
+        for (AlsaCardRecord rec : mCardRecords) {
+            if (rec.mIsUsb) {
+                return rec.mCardNum;
+            }
+        }
+
+        return -1;
+    }
+
+    public int getDefaultCard() {
+        // return an external card if possible
+        int card = getDefaultUsbCard();
+
+        if (card < 0 && getNumCardRecords() > 0) {
+            // otherwise return the (internal) card with the highest number
+            card = getCardRecordAt(getNumCardRecords() - 1).mCardNum;
+        }
+        return card;
+    }
+
+    static public boolean hasCardNumber(ArrayList<AlsaCardRecord> recs, int cardNum) {
+        for (AlsaCardRecord cardRec : recs) {
+            if (cardRec.mCardNum == cardNum) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public ArrayList<AlsaCardRecord> getNewCardRecords(ArrayList<AlsaCardRecord> prevScanRecs) {
+        ArrayList<AlsaCardRecord> newRecs = new ArrayList<AlsaCardRecord>();
+        for (AlsaCardRecord rec : mCardRecords) {
+            // now scan to see if this card number is in the previous scan list
+            if (!hasCardNumber(prevScanRecs, rec.mCardNum)) {
+                newRecs.add(rec);
+            }
+        }
+        return newRecs;
+    }
+
+    //
+    // Logging
+    //
+    public void Log(String heading) {
+        if (DEBUG) {
+            Slog.i(TAG, heading);
+            for (AlsaCardRecord cardRec : mCardRecords) {
+                Slog.i(TAG, cardRec.textFormat());
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
new file mode 100644
index 0000000..81b7943
--- /dev/null
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.alsa;
+
+import android.util.Slog;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * Retrieves information from an ALSA "devices" file.
+ */
+public class AlsaDevicesParser {
+    private static final String TAG = "AlsaDevicesParser";
+    protected static final boolean DEBUG = false;
+
+    private static final String kDevicesFilePath = "/proc/asound/devices";
+
+    private static final int kIndex_CardDeviceField = 5;
+    private static final int kStartIndex_CardNum = 6;
+    private static final int kEndIndex_CardNum = 8; // one past
+    private static final int kStartIndex_DeviceNum = 9;
+    private static final int kEndIndex_DeviceNum = 11; // one past
+    private static final int kStartIndex_Type = 14;
+
+    private static LineTokenizer mTokenizer = new LineTokenizer(" :[]-");
+
+    private boolean mHasCaptureDevices = false;
+    private boolean mHasPlaybackDevices = false;
+    private boolean mHasMIDIDevices = false;
+
+    public class AlsaDeviceRecord {
+        public static final int kDeviceType_Unknown = -1;
+        public static final int kDeviceType_Audio = 0;
+        public static final int kDeviceType_Control = 1;
+        public static final int kDeviceType_MIDI = 2;
+
+        public static final int kDeviceDir_Unknown = -1;
+        public static final int kDeviceDir_Capture = 0;
+        public static final int kDeviceDir_Playback = 1;
+
+        int mCardNum = -1;
+        int mDeviceNum = -1;
+        int mDeviceType = kDeviceType_Unknown;
+        int mDeviceDir = kDeviceDir_Unknown;
+
+        public AlsaDeviceRecord() {}
+
+        public boolean parse(String line) {
+            // "0123456789012345678901234567890"
+            // "  2: [ 0-31]: digital audio playback"
+            // "  3: [ 0-30]: digital audio capture"
+            // " 35: [ 1]   : control"
+            // " 36: [ 2- 0]: raw midi"
+
+            final int kToken_LineNum = 0;
+            final int kToken_CardNum = 1;
+            final int kToken_DeviceNum = 2;
+            final int kToken_Type0 = 3; // "digital", "control", "raw"
+            final int kToken_Type1 = 4; // "audio", "midi"
+            final int kToken_Type2 = 5; // "capture", "playback"
+
+            int tokenOffset = 0;
+            int delimOffset = 0;
+            int tokenIndex = kToken_LineNum;
+            while (true) {
+                tokenOffset = mTokenizer.nextToken(line, delimOffset);
+                if (tokenOffset == LineTokenizer.kTokenNotFound) {
+                    break; // bail
+                }
+                delimOffset = mTokenizer.nextDelimiter(line, tokenOffset);
+                if (delimOffset == LineTokenizer.kTokenNotFound) {
+                    delimOffset = line.length();
+                }
+                String token = line.substring(tokenOffset, delimOffset);
+
+                try {
+                    switch (tokenIndex) {
+                    case kToken_LineNum:
+                        // ignore
+                        break;
+
+                    case kToken_CardNum:
+                        mCardNum = Integer.parseInt(token);
+                        if (line.charAt(delimOffset) != '-') {
+                            tokenIndex++; // no device # in the token stream
+                        }
+                        break;
+
+                    case kToken_DeviceNum:
+                        mDeviceNum = Integer.parseInt(token);
+                        break;
+
+                    case kToken_Type0:
+                        if (token.equals("digital")) {
+                            // NOP
+                        } else if (token.equals("control")) {
+                            mDeviceType = kDeviceType_Control;
+                        } else if (token.equals("raw")) {
+                            // NOP
+                        }
+                        break;
+
+                    case kToken_Type1:
+                        if (token.equals("audio")) {
+                            mDeviceType = kDeviceType_Audio;
+                        } else if (token.equals("midi")) {
+                            mDeviceType = kDeviceType_MIDI;
+                            mHasMIDIDevices = true;
+                        }
+                        break;
+
+                    case kToken_Type2:
+                        if (token.equals("capture")) {
+                            mDeviceDir = kDeviceDir_Capture;
+                            mHasCaptureDevices = true;
+                        } else if (token.equals("playback")) {
+                            mDeviceDir = kDeviceDir_Playback;
+                            mHasPlaybackDevices = true;
+                        }
+                        break;
+                    } // switch (tokenIndex)
+                } catch (NumberFormatException e) {
+                    Slog.e(TAG, "Failed to parse token " + tokenIndex + " of " + kDevicesFilePath
+                        + " token: " + token);
+                    return false;
+                }
+
+                tokenIndex++;
+            } // while (true)
+
+            return true;
+        } // parse()
+
+        public String textFormat() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[" + mCardNum + ":" + mDeviceNum + "]");
+
+            switch (mDeviceType) {
+            case kDeviceType_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceType_Audio:
+                sb.append(" Audio");
+                break;
+            case kDeviceType_Control:
+                sb.append(" Control");
+                break;
+            case kDeviceType_MIDI:
+                sb.append(" MIDI");
+                break;
+            }
+
+            switch (mDeviceDir) {
+            case kDeviceDir_Unknown:
+                sb.append(" N/A");
+                break;
+            case kDeviceDir_Capture:
+                sb.append(" Capture");
+                break;
+            case kDeviceDir_Playback:
+                sb.append(" Playback");
+                break;
+            }
+
+            return sb.toString();
+        }
+    }
+
+    private ArrayList<AlsaDeviceRecord> mDeviceRecords = new ArrayList<AlsaDeviceRecord>();
+
+    public AlsaDevicesParser() {}
+
+    //
+    // Access
+    //
+    public int getDefaultDeviceNum(int card) {
+        // TODO - This (obviously) isn't sufficient. Revisit.
+        return 0;
+    }
+
+    //
+    // Predicates
+    //
+   public boolean hasPlaybackDevices() {
+        return mHasPlaybackDevices;
+    }
+
+    public boolean hasPlaybackDevices(int card) {
+        for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Playback) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasCaptureDevices() {
+        return mHasCaptureDevices;
+    }
+
+    public boolean hasCaptureDevices(int card) {
+        for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_Audio &&
+                deviceRecord.mDeviceDir == AlsaDeviceRecord.kDeviceDir_Capture) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasMIDIDevices() {
+        return mHasMIDIDevices;
+    }
+
+    public boolean hasMIDIDevices(int card) {
+        for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+            if (deviceRecord.mCardNum == card &&
+                deviceRecord.mDeviceType == AlsaDeviceRecord.kDeviceType_MIDI) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    //
+    // Process
+    //
+    private boolean isLineDeviceRecord(String line) {
+        return line.charAt(kIndex_CardDeviceField) == '[';
+    }
+
+    public void scan() {
+        mDeviceRecords.clear();
+
+        File devicesFile = new File(kDevicesFilePath);
+        try {
+            FileReader reader = new FileReader(devicesFile);
+            BufferedReader bufferedReader = new BufferedReader(reader);
+            String line = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                if (isLineDeviceRecord(line)) {
+                    AlsaDeviceRecord deviceRecord = new AlsaDeviceRecord();
+                    deviceRecord.parse(line);
+                    mDeviceRecords.add(deviceRecord);
+                }
+            }
+            reader.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    //
+    // Loging
+    //
+    public void Log(String heading) {
+        if (DEBUG) {
+            Slog.i(TAG, heading);
+            for (AlsaDeviceRecord deviceRecord : mDeviceRecords) {
+                Slog.i(TAG, deviceRecord.textFormat());
+            }
+        }
+    }
+} // class AlsaDevicesParser
+
diff --git a/core/java/com/android/internal/alsa/LineTokenizer.java b/core/java/com/android/internal/alsa/LineTokenizer.java
new file mode 100644
index 0000000..43047a9
--- /dev/null
+++ b/core/java/com/android/internal/alsa/LineTokenizer.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.alsa;
+
+/**
+ * @hide
+ * Breaks lines in an ALSA "cards" or "devices" file into tokens.
+ * TODO(pmclean) Look into replacing this with String.split().
+ */
+public class LineTokenizer {
+    public static final int kTokenNotFound = -1;
+
+    private String mDelimiters = "";
+
+    public LineTokenizer(String delimiters) {
+        mDelimiters = delimiters;
+    }
+
+    int nextToken(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) == -1) {
+                // past a delimiter
+                break;
+            }
+      }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+
+    int nextDelimiter(String line, int startIndex) {
+        int len = line.length();
+        int offset = startIndex;
+        for (; offset < len; offset++) {
+            if (mDelimiters.indexOf(line.charAt(offset)) != -1) {
+                // past a delimiter
+                break;
+            }
+        }
+
+      return offset < len ? offset : kTokenNotFound;
+    }
+}
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 5566aa6..ed48b0d 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -17,11 +17,9 @@
 package com.android.internal.app;
 
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.view.KeyEvent;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 20d209f..9dabb4e 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -20,6 +20,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.Nullable;
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -38,7 +39,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
-import android.view.ViewTreeObserver;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -450,27 +451,107 @@
         }
     }
 
+    /**
+     * Resolves whether a custom or default panel should be used. Removes the
+     * default panel if a custom panel should be used. If the resolved panel is
+     * a view stub, inflates before returning.
+     *
+     * @param customPanel the custom panel
+     * @param defaultPanel the default panel
+     * @return the panel to use
+     */
+    @Nullable
+    private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
+        if (customPanel == null) {
+            // Inflate the default panel, if needed.
+            if (defaultPanel instanceof ViewStub) {
+                defaultPanel = ((ViewStub) defaultPanel).inflate();
+            }
+
+            return (ViewGroup) defaultPanel;
+        }
+
+        // Remove the default panel entirely.
+        if (defaultPanel != null) {
+            final ViewParent parent = defaultPanel.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(defaultPanel);
+            }
+        }
+
+        // Inflate the custom panel, if needed.
+        if (customPanel instanceof ViewStub) {
+            customPanel = ((ViewStub) customPanel).inflate();
+        }
+
+        return (ViewGroup) customPanel;
+    }
+
     private void setupView() {
-        final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
+        final View parentPanel = mWindow.findViewById(R.id.parentPanel);
+        final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
+        final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
+        final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
+
+        // Install custom content before setting up the title or buttons so
+        // that we can handle panel overrides.
+        final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
+        setupCustomContent(customPanel);
+
+        final View customTopPanel = customPanel.findViewById(R.id.topPanel);
+        final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
+        final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
+
+        // Resolve the correct panels and remove the defaults, if needed.
+        final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
+        final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
+        final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
+
         setupContent(contentPanel);
-        final boolean hasButtons = setupButtons();
+        setupButtons(buttonPanel);
+        setupTitle(topPanel);
 
-        final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
-        final TypedArray a = mContext.obtainStyledAttributes(
-                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
-        final boolean hasTitle = setupTitle(topPanel);
+        final boolean hasCustomPanel = customPanel != null
+                && customPanel.getVisibility() != View.GONE;
+        final boolean hasTopPanel = topPanel != null
+                && topPanel.getVisibility() != View.GONE;
+        final boolean hasButtonPanel = buttonPanel != null
+                && buttonPanel.getVisibility() != View.GONE;
 
-        final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
-        if (!hasButtons) {
-            buttonPanel.setVisibility(View.GONE);
-            final View spacer = mWindow.findViewById(R.id.textSpacerNoButtons);
-            if (spacer != null) {
-                spacer.setVisibility(View.VISIBLE);
+        // Only display the text spacer if we don't have buttons.
+        if (!hasButtonPanel) {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
             }
             mWindow.setCloseOnTouchOutsideIfNotSet(true);
         }
 
-        final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
+        // Only display the divider if we have a title and a custom view or a
+        // message.
+        if (hasTopPanel) {
+            final View divider;
+            if (mMessage != null || hasCustomPanel || mListView != null) {
+                divider = topPanel.findViewById(R.id.titleDivider);
+            } else {
+                divider = topPanel.findViewById(R.id.titleDividerTop);
+            }
+
+            if (divider != null) {
+                divider.setVisibility(View.VISIBLE);
+            }
+        }
+
+        final TypedArray a = mContext.obtainStyledAttributes(
+                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+        setBackground(a, topPanel, contentPanel, customPanel, buttonPanel,
+                hasTopPanel, hasCustomPanel, hasButtonPanel);
+        a.recycle();
+    }
+
+    private void setupCustomContent(ViewGroup customPanel) {
         final View customView;
         if (mView != null) {
             customView = mView;
@@ -502,30 +583,9 @@
         } else {
             customPanel.setVisibility(View.GONE);
         }
-
-        // Only display the divider if we have a title and a custom view or a
-        // message.
-        if (hasTitle) {
-            final View divider;
-            if (mMessage != null || customView != null || mListView != null) {
-                divider = mWindow.findViewById(R.id.titleDivider);
-            } else {
-                divider = mWindow.findViewById(R.id.titleDividerTop);
-            }
-
-            if (divider != null) {
-                divider.setVisibility(View.VISIBLE);
-            }
-        }
-
-        setBackground(a, topPanel, contentPanel, customPanel, buttonPanel, hasTitle, hasCustomView,
-                hasButtons);
-        a.recycle();
     }
 
-    private boolean setupTitle(ViewGroup topPanel) {
-        boolean hasTitle = true;
-
+    private void setupTitle(ViewGroup topPanel) {
         if (mCustomTitleView != null) {
             // Add the custom title view directly to the topPanel layout
             LayoutParams lp = new LayoutParams(
@@ -567,18 +627,16 @@
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
                 topPanel.setVisibility(View.GONE);
-                hasTitle = false;
             }
         }
-        return hasTitle;
     }
 
     private void setupContent(ViewGroup contentPanel) {
-        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+        mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
 
         // Special case for users that only want to display a String
-        mMessageView = (TextView) mWindow.findViewById(R.id.message);
+        mMessageView = (TextView) contentPanel.findViewById(R.id.message);
         if (mMessageView == null) {
             return;
         }
@@ -601,8 +659,8 @@
         }
 
         // Set up scroll indicators (if present).
-        final View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
-        final View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+        final View indicatorUp = contentPanel.findViewById(R.id.scrollIndicatorUp);
+        final View indicatorDown = contentPanel.findViewById(R.id.scrollIndicatorDown);
         if (indicatorUp != null || indicatorDown != null) {
             if (mMessage != null) {
                 // We're just showing the ScrollView, set up listener.
@@ -663,12 +721,12 @@
         }
     }
 
-    private boolean setupButtons() {
+    private void setupButtons(ViewGroup buttonPanel) {
         int BIT_BUTTON_POSITIVE = 1;
         int BIT_BUTTON_NEGATIVE = 2;
         int BIT_BUTTON_NEUTRAL = 4;
         int whichButtons = 0;
-        mButtonPositive = (Button) mWindow.findViewById(R.id.button1);
+        mButtonPositive = (Button) buttonPanel.findViewById(R.id.button1);
         mButtonPositive.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonPositiveText)) {
@@ -679,7 +737,7 @@
             whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
         }
 
-        mButtonNegative = (Button) mWindow.findViewById(R.id.button2);
+        mButtonNegative = (Button) buttonPanel.findViewById(R.id.button2);
         mButtonNegative.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNegativeText)) {
@@ -691,7 +749,7 @@
             whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
         }
 
-        mButtonNeutral = (Button) mWindow.findViewById(R.id.button3);
+        mButtonNeutral = (Button) buttonPanel.findViewById(R.id.button3);
         mButtonNeutral.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNeutralText)) {
@@ -717,7 +775,10 @@
             }
         }
 
-        return whichButtons != 0;
+        final boolean hasButtons = whichButtons != 0;
+        if (!hasButtons) {
+            buttonPanel.setVisibility(View.GONE);
+        }
     }
 
     private void centerButton(Button button) {
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
new file mode 100644
index 0000000..7e70b0c
--- /dev/null
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ClipData;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.DebugUtils;
+
+/**
+ * This activity is displayed when the system has collected a heap dump from
+ * a large process and the user has selected to share it.
+ */
+public class DumpHeapActivity extends Activity {
+    /** The process we are reporting */
+    public static final String KEY_PROCESS = "process";
+    /** The size limit the process reached */
+    public static final String KEY_SIZE = "size";
+
+    // Broadcast action to determine when to delete the current dump heap data.
+    public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
+
+    // Extra for above: delay delete of data, since the user is in the process of sharing it.
+    public static final String EXTRA_DELAY_DELETE = "delay_delete";
+
+    static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java");
+
+    String mProcess;
+    long mSize;
+    AlertDialog mDialog;
+    boolean mHandled = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mProcess = getIntent().getStringExtra(KEY_PROCESS);
+        mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+        AlertDialog.Builder b = new AlertDialog.Builder(this,
+                android.R.style.Theme_Material_Light_Dialog_Alert);
+        b.setTitle(com.android.internal.R.string.dump_heap_title);
+        b.setMessage(getString(com.android.internal.R.string.dump_heap_text,
+                mProcess, DebugUtils.sizeValueToString(mSize, null)));
+        b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mHandled = true;
+                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+                finish();
+            }
+        });
+        b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mHandled = true;
+                Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
+                broadcast.putExtra(EXTRA_DELAY_DELETE, true);
+                sendBroadcast(broadcast);
+                Intent intent = new Intent(Intent.ACTION_SEND);
+                ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
+                intent.setClipData(clip);
+                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                intent.setType(clip.getDescription().getMimeType(0));
+                intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
+                startActivity(Intent.createChooser(intent,
+                        getText(com.android.internal.R.string.dump_heap_title)));
+                finish();
+        }
+        });
+        mDialog = b.show();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (!isChangingConfigurations()) {
+            if (!mHandled) {
+                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDialog.dismiss();
+    }
+}
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
index 6ed3bdc..fc213c5 100644
--- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -25,6 +25,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.storage.StorageVolume;
 import android.util.Log;
 
 /**
@@ -94,6 +95,10 @@
         if (which == POSITIVE_BUTTON) {
             Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
             intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+            // Transfer the storage volume to the new intent
+            final StorageVolume storageVolume = getIntent().getParcelableExtra(
+                    StorageVolume.EXTRA_STORAGE_VOLUME);
+            intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, storageVolume);
             startService(intent);
         }
 
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 5a10524..8f549a6 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,9 +26,11 @@
 import android.service.voice.IVoiceInteractionSession;
 
 interface IVoiceInteractionManagerService {
-    void startSession(IVoiceInteractionService service, in Bundle sessionArgs);
+    void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
     boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
             IVoiceInteractor interactor);
+    boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
+    boolean hideSessionFromSession(IBinder token);
     int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
     void finish(IBinder token);
 
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 7c1308f..f598828 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -28,7 +28,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.UserInfo;
 import android.os.Bundle;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 70fb510..75beee9 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -24,6 +24,7 @@
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -897,17 +898,17 @@
                         pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
                         pw.print(count);
                         pw.print(" samples ");
-                        printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
                         pw.print(" / ");
-                        printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
                         pw.print(" ");
-                        printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
+                        DebugUtils.printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
                         pw.println();
                     }
                 }
@@ -924,9 +925,9 @@
         if (proc.mNumCachedKill != 0) {
             pw.print(prefix); pw.print("Killed from cached state: ");
                     pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
-                    printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
-                    printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
-                    printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
+                    DebugUtils.printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
+                    DebugUtils.printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
         }
     }
 
@@ -939,11 +940,11 @@
             int bucket, int index) {
         pw.print(prefix); pw.print(label);
         pw.print(": ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index) * 1024);
         pw.print(" min, ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index + 1) * 1024);
         pw.print(" avg, ");
-        printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
+        DebugUtils.printSizeValue(pw, getSysMemUsageValue(bucket, index+2) * 1024);
         pw.println(" max");
     }
 
@@ -1150,43 +1151,6 @@
         pw.print("%");
     }
 
-    static void printSizeValue(PrintWriter pw, long number) {
-        float result = number;
-        String suffix = "";
-        if (result > 900) {
-            suffix = "KB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "MB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "GB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "TB";
-            result = result / 1024;
-        }
-        if (result > 900) {
-            suffix = "PB";
-            result = result / 1024;
-        }
-        String value;
-        if (result < 1) {
-            value = String.format("%.2f", result);
-        } else if (result < 10) {
-            value = String.format("%.1f", result);
-        } else if (result < 100) {
-            value = String.format("%.0f", result);
-        } else {
-            value = String.format("%.0f", result);
-        }
-        pw.print(value);
-        pw.print(suffix);
-    }
-
     public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
             boolean sepProcStates, int[] procStates, long now) {
@@ -2437,7 +2401,7 @@
             pw.print(prefix);
             pw.print(label);
             pw.print(": ");
-            printSizeValue(pw, mem);
+            DebugUtils.printSizeValue(pw, mem);
             pw.print(" (");
             pw.print(samples);
             pw.print(" samples)");
@@ -2475,7 +2439,7 @@
         totalPss = printMemoryCategory(pw, "  ", "Z-Ram  ", totalMem.sysMemZRamWeight,
                 totalMem.totalTime, totalPss, totalMem.sysMemSamples);
         pw.print("  TOTAL  : ");
-        printSizeValue(pw, totalPss);
+        DebugUtils.printSizeValue(pw, totalPss);
         pw.println();
         printMemoryCategory(pw, "  ", STATE_NAMES[STATE_SERVICE_RESTARTING],
                 totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss,
@@ -3781,17 +3745,17 @@
             printPercent(pw, (double) totalTime / (double) overallTime);
             if (numPss > 0) {
                 pw.print(" (");
-                printSizeValue(pw, minPss * 1024);
+                DebugUtils.printSizeValue(pw, minPss * 1024);
                 pw.print("-");
-                printSizeValue(pw, avgPss * 1024);
+                DebugUtils.printSizeValue(pw, avgPss * 1024);
                 pw.print("-");
-                printSizeValue(pw, maxPss * 1024);
+                DebugUtils.printSizeValue(pw, maxPss * 1024);
                 pw.print("/");
-                printSizeValue(pw, minUss * 1024);
+                DebugUtils.printSizeValue(pw, minUss * 1024);
                 pw.print("-");
-                printSizeValue(pw, avgUss * 1024);
+                DebugUtils.printSizeValue(pw, avgUss * 1024);
                 pw.print("-");
-                printSizeValue(pw, maxUss * 1024);
+                DebugUtils.printSizeValue(pw, maxUss * 1024);
                 if (full) {
                     pw.print(" over ");
                     pw.print(numPss);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 649a59f..3ceea9d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -342,6 +342,9 @@
                         return;
                     }
 
+                    // Do not show the profile switch message anymore.
+                    mProfileSwitchMessageId = -1;
+
                     final Intent intent = intentForDisplayResolveInfo(dri);
                     onIntentSelected(dri.ri, intent, false);
                     finish();
@@ -505,15 +508,6 @@
             // Header views don't count.
             return;
         }
-        ResolveInfo resolveInfo = mAdapter.resolveInfoForPosition(position, true);
-        if (mResolvingHome && hasManagedProfile()
-                && !supportsManagedProfiles(resolveInfo)) {
-            Toast.makeText(this, String.format(getResources().getString(
-                    com.android.internal.R.string.activity_resolver_work_profiles_support),
-                    resolveInfo.activityInfo.loadLabel(getPackageManager()).toString()),
-                    Toast.LENGTH_LONG).show();
-            return;
-        }
         final int checkedPos = mListView.getCheckedItemPosition();
         final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
         if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
@@ -579,7 +573,6 @@
                 mListView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
                 id == R.id.button_always,
                 mAlwaysUseOption);
-        dismiss();
     }
 
     void startSelected(int which, boolean always, boolean filtered) {
@@ -587,6 +580,14 @@
             return;
         }
         ResolveInfo ri = mAdapter.resolveInfoForPosition(which, filtered);
+        if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
+            Toast.makeText(this, String.format(getResources().getString(
+                    com.android.internal.R.string.activity_resolver_work_profiles_support),
+                    ri.activityInfo.loadLabel(getPackageManager()).toString()),
+                    Toast.LENGTH_LONG).show();
+            return;
+        }
+
         Intent intent = mAdapter.intentForPosition(which, filtered);
         onIntentSelected(ri, intent, always);
         finish();
@@ -841,6 +842,8 @@
                 Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
             }
 
+            // Clear the value of mOtherProfile from previous call.
+            mOtherProfile = null;
             mList.clear();
             if (mBaseResolveList != null) {
                 currentResolveList = mOrigResolveList = mBaseResolveList;
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 061b535..2bf02f1 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -20,8 +20,10 @@
 import android.content.res.TypedArray;
 import android.view.ViewParent;
 import android.widget.Toolbar;
+
 import com.android.internal.R;
 import com.android.internal.view.ActionBarPolicy;
+import com.android.internal.view.ActionModeWrapper;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.SubMenuBuilder;
@@ -46,6 +48,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.TypedValue;
 import android.view.ActionMode;
+import android.view.ActionMode.Callback;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -88,20 +91,20 @@
 
     private TabImpl mSelectedTab;
     private int mSavedTabPosition = INVALID_POSITION;
-    
+
     private boolean mDisplayHomeAsUpSet;
 
-    ActionModeImpl mActionMode;
+    ActionMode mActionMode;
     ActionMode mDeferredDestroyActionMode;
     ActionMode.Callback mDeferredModeDestroyCallback;
-    
+
     private boolean mLastMenuVisibility;
     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
             new ArrayList<OnMenuVisibilityListener>();
 
     private static final int CONTEXT_DISPLAY_NORMAL = 0;
     private static final int CONTEXT_DISPLAY_SPLIT = 1;
-    
+
     private static final int INVALID_POSITION = -1;
 
     private int mContextDisplayMode;
@@ -942,11 +945,12 @@
         private ActionMode.Callback mCallback;
         private WeakReference<View> mCustomView;
 
-        public ActionModeImpl(Context context, ActionMode.Callback callback) {
+        public ActionModeImpl(
+                Context context, ActionMode.Callback callback) {
             mActionModeContext = context;
             mCallback = callback;
             mMenu = new MenuBuilder(context)
-                    .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+                        .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
             mMenu.setCallback(this);
         }
 
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 044383e..e32a3a2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -44,11 +44,8 @@
 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.*;
 
 /**
@@ -87,7 +84,6 @@
     private File mRestoreSetDir;
     private File mRestoreSetIncrementalDir;
     private File mRestoreSetFullDir;
-    private long mRestoreToken;
 
     // Additional bookkeeping for full backup
     private String mFullTargetPackage;
@@ -96,20 +92,22 @@
     private BufferedOutputStream mFullBackupOutputStream;
     private byte[] mFullBackupBuffer;
 
-    private File mFullRestoreSetDir;
-    private HashSet<String> mFullRestorePackages;
     private FileInputStream mCurFullRestoreStream;
     private FileOutputStream mFullRestoreSocketStream;
     private byte[] mFullRestoreBuffer;
 
-    public LocalTransport(Context context) {
-        mContext = context;
+    private void makeDataDirs() {
         mCurrentSetDir.mkdirs();
-        mCurrentSetFullDir.mkdir();
-        mCurrentSetIncrementalDir.mkdir();
         if (!SELinux.restorecon(mCurrentSetDir)) {
             Log.e(TAG, "SELinux restorecon failed for " + mCurrentSetDir);
         }
+        mCurrentSetFullDir.mkdir();
+        mCurrentSetIncrementalDir.mkdir();
+    }
+
+    public LocalTransport(Context context) {
+        mContext = context;
+        makeDataDirs();
     }
 
     @Override
@@ -154,6 +152,7 @@
     public int initializeDevice() {
         if (DEBUG) Log.v(TAG, "wiping all data");
         deleteContents(mCurrentSetDir);
+        makeDataDirs();
         return TRANSPORT_OK;
     }
 
@@ -372,6 +371,9 @@
                 return TRANSPORT_ERROR;
             }
         }
+        if (DEBUG) {
+            Log.v(TAG, "   stored " + numBytes + " of data");
+        }
         return TRANSPORT_OK;
     }
 
@@ -425,7 +427,6 @@
                 + " matching packages");
         mRestorePackages = packages;
         mRestorePackage = -1;
-        mRestoreToken = token;
         mRestoreSetDir = new File(mDataDir, Long.toString(token));
         mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR);
         mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR);
@@ -434,6 +435,10 @@
 
     @Override
     public RestoreDescription nextRestorePackage() {
+        if (DEBUG) {
+            Log.v(TAG, "nextRestorePackage() : mRestorePackage=" + mRestorePackage
+                    + " length=" + mRestorePackages.length);
+        }
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
 
         boolean found = false;
@@ -444,7 +449,10 @@
             // skip packages where we have a data dir but no actual contents
             String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
             if (contents != null && contents.length > 0) {
-                if (DEBUG) Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+                if (DEBUG) {
+                    Log.v(TAG, "  nextRestorePackage(TYPE_KEY_VALUE) @ "
+                        + mRestorePackage + " = " + name);
+                }
                 mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
                 found = true;
             }
@@ -453,7 +461,10 @@
                 // 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);
+                    if (DEBUG) {
+                        Log.v(TAG, "  nextRestorePackage(TYPE_FULL_STREAM) @ "
+                                + mRestorePackage + " = " + name);
+                    }
                     mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
                     mCurFullRestoreStream = null;   // ensure starting from the ground state
                     found = true;
@@ -463,6 +474,11 @@
             if (found) {
                 return new RestoreDescription(name, mRestoreType);
             }
+
+            if (DEBUG) {
+                Log.v(TAG, "  ... package @ " + mRestorePackage + " = " + name
+                        + " has no data; skipping");
+            }
         }
 
         if (DEBUG) Log.v(TAG, "  no more packages to restore");
diff --git a/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java b/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java
deleted file mode 100644
index faaac7f..0000000
--- a/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/ByteArrayPartSource.java,v 1.7 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-/**
- * A PartSource that reads from a byte array.  This class should be used when
- * the data to post is already loaded into memory.
- * 
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- *   
- * @since 2.0 
- */
-public class ByteArrayPartSource implements PartSource {
-
-    /** Name of the source file. */
-    private String fileName;
-
-    /** Byte array of the source file. */
-    private byte[] bytes;
-
-    /**
-     * Constructor for ByteArrayPartSource.
-     * 
-     * @param fileName the name of the file these bytes represent
-     * @param bytes the content of this part
-     */
-    public ByteArrayPartSource(String fileName, byte[] bytes) {
-
-        this.fileName = fileName;
-        this.bytes = bytes;
-
-    }
-
-    /**
-     * @see PartSource#getLength()
-     */
-    public long getLength() {
-        return bytes.length;
-    }
-
-    /**
-     * @see PartSource#getFileName()
-     */
-    public String getFileName() {
-        return fileName;
-    }
-
-    /**
-     * @see PartSource#createInputStream()
-     */
-    public InputStream createInputStream() {
-        return new ByteArrayInputStream(bytes);
-    }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/FilePart.java b/core/java/com/android/internal/http/multipart/FilePart.java
deleted file mode 100644
index 45e4be6..0000000
--- a/core/java/com/android/internal/http/multipart/FilePart.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class implements a part of a Multipart post object that
- * consists of a file.  
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *   
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- *     The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
- */
-@Deprecated
-public class FilePart extends PartBase {
-
-    /** Default content encoding of file attachments. */
-    public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
-
-    /** Default charset of file attachments. */
-    public static final String DEFAULT_CHARSET = "ISO-8859-1";
-
-    /** Default transfer encoding of file attachments. */
-    public static final String DEFAULT_TRANSFER_ENCODING = "binary";
-
-    /** Log object for this class. */
-    private static final Log LOG = LogFactory.getLog(FilePart.class);
-
-    /** Attachment's file name */
-    protected static final String FILE_NAME = "; filename=";
-
-    /** Attachment's file name as a byte array */
-    private static final byte[] FILE_NAME_BYTES = 
-        EncodingUtils.getAsciiBytes(FILE_NAME);
-
-    /** Source of the file part. */
-    private PartSource source;
-
-    /**
-     * FilePart Constructor.
-     *
-     * @param name the name for this part
-     * @param partSource the source for this part
-     * @param contentType the content type for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CONTENT_TYPE default} is used
-     * @param charset the charset encoding for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CHARSET default} is used
-     */
-    public FilePart(String name, PartSource partSource, String contentType, String charset) {
-        
-        super(
-            name, 
-            contentType == null ? DEFAULT_CONTENT_TYPE : contentType, 
-            charset == null ? "ISO-8859-1" : charset, 
-            DEFAULT_TRANSFER_ENCODING
-        );
-
-        if (partSource == null) {
-            throw new IllegalArgumentException("Source may not be null");
-        }
-        this.source = partSource;
-    }
-        
-    /**
-     * FilePart Constructor.
-     *
-     * @param name the name for this part
-     * @param partSource the source for this part
-     */
-    public FilePart(String name, PartSource partSource) {
-        this(name, partSource, null, null);
-    }
-
-    /**
-     * FilePart Constructor.
-     *
-     * @param name the name of the file part
-     * @param file the file to post
-     *
-     * @throws FileNotFoundException if the <i>file</i> is not a normal
-     * file or if it is not readable.
-     */
-    public FilePart(String name, File file) 
-    throws FileNotFoundException {
-        this(name, new FilePartSource(file), null, null);
-    }
-
-    /**
-     * FilePart Constructor.
-     *
-     * @param name the name of the file part
-     * @param file the file to post
-     * @param contentType the content type for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CONTENT_TYPE default} is used
-     * @param charset the charset encoding for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CHARSET default} is used
-     *
-     * @throws FileNotFoundException if the <i>file</i> is not a normal
-     * file or if it is not readable.
-     */
-    public FilePart(String name, File file, String contentType, String charset) 
-    throws FileNotFoundException {
-        this(name, new FilePartSource(file), contentType, charset);
-    }
-
-     /**
-     * FilePart Constructor.
-     *
-     * @param name the name of the file part
-     * @param fileName the file name 
-     * @param file the file to post
-     *
-     * @throws FileNotFoundException if the <i>file</i> is not a normal
-     * file or if it is not readable.
-     */
-    public FilePart(String name, String fileName, File file) 
-    throws FileNotFoundException {
-        this(name, new FilePartSource(fileName, file), null, null);
-    }
-    
-     /**
-     * FilePart Constructor.
-     *
-     * @param name the name of the file part
-     * @param fileName the file name 
-     * @param file the file to post
-     * @param contentType the content type for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CONTENT_TYPE default} is used
-     * @param charset the charset encoding for this part, if <code>null</code> the 
-     * {@link #DEFAULT_CHARSET default} is used
-     *
-     * @throws FileNotFoundException if the <i>file</i> is not a normal
-     * file or if it is not readable.
-     */
-    public FilePart(String name, String fileName, File file, String contentType, String charset) 
-    throws FileNotFoundException {
-        this(name, new FilePartSource(fileName, file), contentType, charset);
-    }
-    
-    /**
-     * Write the disposition header to the output stream
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs
-     * @see Part#sendDispositionHeader(OutputStream)
-     */
-    @Override
-    protected void sendDispositionHeader(OutputStream out) 
-    throws IOException {
-        LOG.trace("enter sendDispositionHeader(OutputStream out)");
-        super.sendDispositionHeader(out);
-        String filename = this.source.getFileName();
-        if (filename != null) {
-            out.write(FILE_NAME_BYTES);
-            out.write(QUOTE_BYTES);
-            out.write(EncodingUtils.getAsciiBytes(filename));
-            out.write(QUOTE_BYTES);
-        }
-    }
-    
-    /**
-     * Write the data in "source" to the specified stream.
-     * @param out The output stream.
-     * @throws IOException if an IO problem occurs.
-     * @see Part#sendData(OutputStream)
-     */
-    @Override
-    protected void sendData(OutputStream out) throws IOException {
-        LOG.trace("enter sendData(OutputStream out)");
-        if (lengthOfData() == 0) {
-            
-            // this file contains no data, so there is nothing to send.
-            // we don't want to create a zero length buffer as this will
-            // cause an infinite loop when reading.
-            LOG.debug("No data to send.");
-            return;
-        }
-        
-        byte[] tmp = new byte[4096];
-        InputStream instream = source.createInputStream();
-        try {
-            int len;
-            while ((len = instream.read(tmp)) >= 0) {
-                out.write(tmp, 0, len);
-            }
-        } finally {
-            // we're done with the stream, close it
-            instream.close();
-        }
-    }
-
-    /** 
-     * Returns the source of the file part.
-     *  
-     * @return The source.
-     */
-    protected PartSource getSource() {
-        LOG.trace("enter getSource()");
-        return this.source;
-    }
-
-    /**
-     * Return the length of the data.
-     * @return The length.
-     * @see Part#lengthOfData()
-     */    
-    @Override
-    protected long lengthOfData() {
-        LOG.trace("enter lengthOfData()");
-        return source.getLength();
-    }    
-
-}
diff --git a/core/java/com/android/internal/http/multipart/FilePartSource.java b/core/java/com/android/internal/http/multipart/FilePartSource.java
deleted file mode 100644
index eb5cc0f..0000000
--- a/core/java/com/android/internal/http/multipart/FilePartSource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePartSource.java,v 1.10 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A PartSource that reads from a File.
- * 
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- *   
- * @since 2.0 
- */
-public class FilePartSource implements PartSource {
-
-    /** File part file. */
-    private File file = null;
-
-    /** File part file name. */
-    private String fileName = null;
-    
-    /**
-     * Constructor for FilePartSource.
-     * 
-     * @param file the FilePart source File. 
-     *
-     * @throws FileNotFoundException if the file does not exist or 
-     * cannot be read
-     */
-    public FilePartSource(File file) throws FileNotFoundException {
-        this.file = file;
-        if (file != null) {
-            if (!file.isFile()) {
-                throw new FileNotFoundException("File is not a normal file.");
-            }
-            if (!file.canRead()) {
-                throw new FileNotFoundException("File is not readable.");
-            }
-            this.fileName = file.getName();       
-        }
-    }
-
-    /**
-     * Constructor for FilePartSource.
-     * 
-     * @param fileName the file name of the FilePart
-     * @param file the source File for the FilePart
-     *
-     * @throws FileNotFoundException if the file does not exist or 
-     * cannot be read
-     */
-    public FilePartSource(String fileName, File file) 
-      throws FileNotFoundException {
-        this(file);
-        if (fileName != null) {
-            this.fileName = fileName;
-        }
-    }
-    
-    /**
-     * Return the length of the file
-     * @return the length of the file.
-     * @see PartSource#getLength()
-     */
-    public long getLength() {
-        if (this.file != null) {
-            return this.file.length();
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Return the current filename
-     * @return the filename.
-     * @see PartSource#getFileName()
-     */
-    public String getFileName() {
-        return (fileName == null) ? "noname" : fileName;
-    }
-
-    /**
-     * Return a new {@link FileInputStream} for the current filename.
-     * @return the new input stream.
-     * @throws IOException If an IO problem occurs.
-     * @see PartSource#createInputStream()
-     */
-    public InputStream createInputStream() throws IOException {
-        if (this.file != null) {
-            return new FileInputStream(this.file);
-        } else {
-            return new ByteArrayInputStream(new byte[] {});
-        }
-    }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/MultipartEntity.java b/core/java/com/android/internal/http/multipart/MultipartEntity.java
deleted file mode 100644
index 5319251..0000000
--- a/core/java/com/android/internal/http/multipart/MultipartEntity.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/MultipartRequestEntity.java,v 1.1 2004/10/06 03:39:59 mbecke Exp $
- * $Revision: 502647 $
- * $Date: 2007-02-02 17:22:54 +0100 (Fri, 02 Feb 2007) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Random;
-
-import org.apache.http.Header;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Implements a request entity suitable for an HTTP multipart POST method.
- * <p>
- * The HTTP multipart POST method is defined in section 3.3 of
- * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC1867</a>:
- * <blockquote>
- * The media-type multipart/form-data follows the rules of all multipart
- * MIME data streams as outlined in RFC 1521. The multipart/form-data contains 
- * a series of parts. Each part is expected to contain a content-disposition 
- * header where the value is "form-data" and a name attribute specifies 
- * the field name within the form, e.g., 'content-disposition: form-data; 
- * name="xxxxx"', where xxxxx is the field name corresponding to that field.
- * Field names originally in non-ASCII character sets may be encoded using 
- * the method outlined in RFC 1522.
- * </blockquote>
- * </p>
- * <p>This entity is designed to be used in conjunction with the 
- * {@link org.apache.http.HttpRequest} to provide
- * multipart posts.  Example usage:</p>
- * <pre>
- *  File f = new File("/path/fileToUpload.txt");
- *  HttpRequest request = new HttpRequest("http://host/some_path");
- *  Part[] parts = {
- *      new StringPart("param_name", "value"),
- *      new FilePart(f.getName(), f)
- *  };
- *  filePost.setEntity(
- *      new MultipartRequestEntity(parts, filePost.getParams())
- *      );
- *  HttpClient client = new HttpClient();
- *  int status = client.executeMethod(filePost);
- * </pre>
- * 
- * @since 3.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- *     The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
- */
-@Deprecated
-public class MultipartEntity extends AbstractHttpEntity {
-
-    private static final Log log = LogFactory.getLog(MultipartEntity.class);
-    
-    /** The Content-Type for multipart/form-data. */
-    private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
-    
-    /**
-     * Sets the value to use as the multipart boundary.
-     * <p>
-     * This parameter expects a value if type {@link String}.
-     * </p>
-     */
-    public static final String MULTIPART_BOUNDARY = "http.method.multipart.boundary";
-    
-    /**
-     * The pool of ASCII chars to be used for generating a multipart boundary.
-     */
-    private static byte[] MULTIPART_CHARS = EncodingUtils.getAsciiBytes(
-        "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
-    
-    /**
-     * Generates a random multipart boundary string.
-    */
-    private static byte[] generateMultipartBoundary() {
-        Random rand = new Random();
-        byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
-        for (int i = 0; i < bytes.length; i++) {
-            bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
-        }
-        return bytes;
-    }
-    
-    /** The MIME parts as set by the constructor */
-    protected Part[] parts;
-    
-    private byte[] multipartBoundary;
-    
-    private HttpParams params;
-    
-    private boolean contentConsumed = false;
-    
-    /**
-     * Creates a new multipart entity containing the given parts.
-     * @param parts The parts to include.
-     * @param params The params of the HttpMethod using this entity.
-     */
-    public MultipartEntity(Part[] parts, HttpParams params) {      
-      if (parts == null) {
-          throw new IllegalArgumentException("parts cannot be null");
-      }
-      if (params == null) {
-          throw new IllegalArgumentException("params cannot be null");
-      }
-      this.parts = parts;
-      this.params = params;
-    }
-    
-    public MultipartEntity(Part[] parts) {
-      setContentType(MULTIPART_FORM_CONTENT_TYPE);
-      if (parts == null) {
-          throw new IllegalArgumentException("parts cannot be null");
-      }
-      this.parts = parts;
-      this.params = null;
-    }
-    
-    /**
-     * Returns the MIME boundary string that is used to demarcate boundaries of
-     * this part. The first call to this method will implicitly create a new
-     * boundary string. To create a boundary string first the 
-     * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise 
-     * a random one is generated.
-     * 
-     * @return The boundary string of this entity in ASCII encoding.
-     */
-    protected byte[] getMultipartBoundary() {
-        if (multipartBoundary == null) {
-            String temp = null;
-            if (params != null) {
-              temp = (String) params.getParameter(MULTIPART_BOUNDARY);
-            }
-            if (temp != null) {
-                multipartBoundary = EncodingUtils.getAsciiBytes(temp);
-            } else {
-                multipartBoundary = generateMultipartBoundary();
-            }
-        }
-        return multipartBoundary;
-    }
-
-    /**
-     * Returns <code>true</code> if all parts are repeatable, <code>false</code> otherwise.
-     */
-    public boolean isRepeatable() {
-        for (int i = 0; i < parts.length; i++) {
-            if (!parts[i].isRepeatable()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /* (non-Javadoc)
-     */
-    public void writeTo(OutputStream out) throws IOException {
-        Part.sendParts(out, parts, getMultipartBoundary());
-    }
-    /* (non-Javadoc)
-     * @see org.apache.commons.http.AbstractHttpEntity.#getContentType()
-     */
-    @Override
-    public Header getContentType() {
-      StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
-      buffer.append("; boundary=");
-      buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
-      return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
-
-    }
-
-    /* (non-Javadoc)
-     */
-    public long getContentLength() {
-        try {
-            return Part.getLengthOfParts(parts, getMultipartBoundary());            
-        } catch (Exception e) {
-            log.error("An exception occurred while getting the length of the parts", e);
-            return 0;
-        }
-    }    
- 
-    public InputStream getContent() throws IOException, IllegalStateException {
-          if(!isRepeatable() && this.contentConsumed ) {
-              throw new IllegalStateException("Content has been consumed");
-          }
-          this.contentConsumed = true;
-          
-          ByteArrayOutputStream baos = new ByteArrayOutputStream();
-          Part.sendParts(baos, this.parts, this.multipartBoundary);
-          ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-          return bais;
-    }
-  
-    public boolean isStreaming() {
-        return false;
-    }
-}
diff --git a/core/java/com/android/internal/http/multipart/Part.java b/core/java/com/android/internal/http/multipart/Part.java
deleted file mode 100644
index 1d66dc67..0000000
--- a/core/java/com/android/internal/http/multipart/Part.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v 1.16 2005/01/14 21:16:40 olegk Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Abstract class for one Part of a multipart post object.
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- *     The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
- */
-@Deprecated
-public abstract class Part {
-
-    /** Log object for this class. */
-    private static final Log LOG = LogFactory.getLog(Part.class);
-
-    /** 
-     * The boundary 
-     * @deprecated use {@link org.apache.http.client.methods.multipart#MULTIPART_BOUNDARY}
-     */
-    protected static final String BOUNDARY = "----------------314159265358979323846";
-    
-    /** 
-     * The boundary as a byte array.
-     * @deprecated
-     */
-    protected static final byte[] BOUNDARY_BYTES = EncodingUtils.getAsciiBytes(BOUNDARY);
-
-    /**
-     * The default boundary to be used if {@link #setPartBoundary(byte[])} has not
-     * been called.
-     */
-    private static final byte[] DEFAULT_BOUNDARY_BYTES = BOUNDARY_BYTES;    
-    
-    /** Carriage return/linefeed */
-    protected static final String CRLF = "\r\n";
-    
-    /** Carriage return/linefeed as a byte array */
-    protected static final byte[] CRLF_BYTES = EncodingUtils.getAsciiBytes(CRLF);
-    
-    /** Content dispostion characters */
-    protected static final String QUOTE = "\"";
-    
-    /** Content dispostion as a byte array */
-    protected static final byte[] QUOTE_BYTES = 
-      EncodingUtils.getAsciiBytes(QUOTE);
-
-    /** Extra characters */
-    protected static final String EXTRA = "--";
-    
-    /** Extra characters as a byte array */
-    protected static final byte[] EXTRA_BYTES = 
-      EncodingUtils.getAsciiBytes(EXTRA);
-    
-    /** Content dispostion characters */
-    protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name=";
-    
-    /** Content dispostion as a byte array */
-    protected static final byte[] CONTENT_DISPOSITION_BYTES = 
-      EncodingUtils.getAsciiBytes(CONTENT_DISPOSITION);
-
-    /** Content type header */
-    protected static final String CONTENT_TYPE = "Content-Type: ";
-
-    /** Content type header as a byte array */
-    protected static final byte[] CONTENT_TYPE_BYTES = 
-      EncodingUtils.getAsciiBytes(CONTENT_TYPE);
-
-    /** Content charset */
-    protected static final String CHARSET = "; charset=";
-
-    /** Content charset as a byte array */
-    protected static final byte[] CHARSET_BYTES = 
-      EncodingUtils.getAsciiBytes(CHARSET);
-
-    /** Content type header */
-    protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: ";
-
-    /** Content type header as a byte array */
-    protected static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = 
-      EncodingUtils.getAsciiBytes(CONTENT_TRANSFER_ENCODING);
-
-    /**
-     * Return the boundary string.
-     * @return the boundary string
-     * @deprecated uses a constant string. Rather use {@link #getPartBoundary}
-     */
-    public static String getBoundary() {
-        return BOUNDARY;
-    }
-
-    /**
-     * The ASCII bytes to use as the multipart boundary.
-     */
-    private byte[] boundaryBytes;
-    
-    /**
-     * Return the name of this part.
-     * @return The name.
-     */
-    public abstract String getName();
-    
-    /**
-     * Returns the content type of this part.
-     * @return the content type, or <code>null</code> to exclude the content type header
-     */
-    public abstract String getContentType();
-
-    /**
-     * Return the character encoding of this part.
-     * @return the character encoding, or <code>null</code> to exclude the character 
-     * encoding header
-     */
-    public abstract String getCharSet();
-
-    /**
-     * Return the transfer encoding of this part.
-     * @return the transfer encoding, or <code>null</code> to exclude the transfer encoding header
-     */
-    public abstract String getTransferEncoding();
-
-    /**
-     * Gets the part boundary to be used.
-     * @return the part boundary as an array of bytes.
-     * 
-     * @since 3.0
-     */
-    protected byte[] getPartBoundary() {
-        if (boundaryBytes == null) {
-            // custom boundary bytes have not been set, use the default.
-            return DEFAULT_BOUNDARY_BYTES;
-        } else {
-            return boundaryBytes;            
-        }
-    }
-    
-    /**
-     * Sets the part boundary.  Only meant to be used by 
-     * {@link Part#sendParts(OutputStream, Part[], byte[])}
-     * and {@link Part#getLengthOfParts(Part[], byte[])}
-     * @param boundaryBytes An array of ASCII bytes.
-     * @since 3.0
-     */
-    void setPartBoundary(byte[] boundaryBytes) {
-        this.boundaryBytes = boundaryBytes;
-    }
-    
-    /**
-     * Tests if this part can be sent more than once.
-     * @return <code>true</code> if {@link #sendData(OutputStream)} can be successfully called 
-     * more than once.
-     * @since 3.0
-     */
-    public boolean isRepeatable() {
-        return true;
-    }
-    
-    /**
-     * Write the start to the specified output stream
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    protected void sendStart(OutputStream out) throws IOException {
-        LOG.trace("enter sendStart(OutputStream out)");
-        out.write(EXTRA_BYTES);
-        out.write(getPartBoundary());
-        out.write(CRLF_BYTES);
-    }
-    
-    /**
-     * Write the content disposition header to the specified output stream
-     * 
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    protected void sendDispositionHeader(OutputStream out) throws IOException {
-        LOG.trace("enter sendDispositionHeader(OutputStream out)");
-        out.write(CONTENT_DISPOSITION_BYTES);
-        out.write(QUOTE_BYTES);
-        out.write(EncodingUtils.getAsciiBytes(getName()));
-        out.write(QUOTE_BYTES);
-    }
-    
-    /**
-     * Write the content type header to the specified output stream
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-     protected void sendContentTypeHeader(OutputStream out) throws IOException {
-        LOG.trace("enter sendContentTypeHeader(OutputStream out)");
-        String contentType = getContentType();
-        if (contentType != null) {
-            out.write(CRLF_BYTES);
-            out.write(CONTENT_TYPE_BYTES);
-            out.write(EncodingUtils.getAsciiBytes(contentType));
-            String charSet = getCharSet();
-            if (charSet != null) {
-                out.write(CHARSET_BYTES);
-                out.write(EncodingUtils.getAsciiBytes(charSet));
-            }
-        }
-    }
-
-    /**
-     * Write the content transfer encoding header to the specified 
-     * output stream
-     * 
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-     protected void sendTransferEncodingHeader(OutputStream out) throws IOException {
-        LOG.trace("enter sendTransferEncodingHeader(OutputStream out)");
-        String transferEncoding = getTransferEncoding();
-        if (transferEncoding != null) {
-            out.write(CRLF_BYTES);
-            out.write(CONTENT_TRANSFER_ENCODING_BYTES);
-            out.write(EncodingUtils.getAsciiBytes(transferEncoding));
-        }
-    }
-
-    /**
-     * Write the end of the header to the output stream
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    protected void sendEndOfHeader(OutputStream out) throws IOException {
-        LOG.trace("enter sendEndOfHeader(OutputStream out)");
-        out.write(CRLF_BYTES);
-        out.write(CRLF_BYTES);
-    }
-    
-    /**
-     * Write the data to the specified output stream
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    protected abstract void sendData(OutputStream out) throws IOException;
-    
-    /**
-     * Return the length of the main content
-     * 
-     * @return long The length.
-     * @throws IOException If an IO problem occurs
-     */
-    protected abstract long lengthOfData() throws IOException;
-    
-    /**
-     * Write the end data to the output stream.
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    protected void sendEnd(OutputStream out) throws IOException {
-        LOG.trace("enter sendEnd(OutputStream out)");
-        out.write(CRLF_BYTES);
-    }
-    
-    /**
-     * Write all the data to the output stream.
-     * If you override this method make sure to override 
-     * #length() as well
-     * 
-     * @param out The output stream
-     * @throws IOException If an IO problem occurs.
-     */
-    public void send(OutputStream out) throws IOException {
-        LOG.trace("enter send(OutputStream out)");
-        sendStart(out);
-        sendDispositionHeader(out);
-        sendContentTypeHeader(out);
-        sendTransferEncodingHeader(out);
-        sendEndOfHeader(out);
-        sendData(out);
-        sendEnd(out);
-    }
-
-
-    /**
-     * Return the full length of all the data.
-     * If you override this method make sure to override 
-     * #send(OutputStream) as well
-     * 
-     * @return long The length.
-     * @throws IOException If an IO problem occurs
-     */
-    public long length() throws IOException {
-        LOG.trace("enter length()");
-        if (lengthOfData() < 0) {
-            return -1;
-        }
-        ByteArrayOutputStream overhead = new ByteArrayOutputStream();
-        sendStart(overhead);
-        sendDispositionHeader(overhead);
-        sendContentTypeHeader(overhead);
-        sendTransferEncodingHeader(overhead);
-        sendEndOfHeader(overhead);
-        sendEnd(overhead);
-        return overhead.size() + lengthOfData();
-    }
-
-    /**
-     * Return a string representation of this object.
-     * @return A string representation of this object.
-     * @see java.lang.Object#toString()
-     */    
-    @Override
-    public String toString() {
-        return this.getName();
-    }
-
-    /**
-     * Write all parts and the last boundary to the specified output stream.
-     * 
-     * @param out The stream to write to.
-     * @param parts The parts to write.
-     * 
-     * @throws IOException If an I/O error occurs while writing the parts.
-     */
-    public static void sendParts(OutputStream out, final Part[] parts)
-        throws IOException {
-        sendParts(out, parts, DEFAULT_BOUNDARY_BYTES);
-    }
-
-    /**
-     * Write all parts and the last boundary to the specified output stream.
-     * 
-     * @param out The stream to write to.
-     * @param parts The parts to write.
-     * @param partBoundary The ASCII bytes to use as the part boundary.
-     * 
-     * @throws IOException If an I/O error occurs while writing the parts.
-     * 
-     * @since 3.0
-     */
-    public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary)
-        throws IOException {
-        
-        if (parts == null) {
-            throw new IllegalArgumentException("Parts may not be null"); 
-        }
-        if (partBoundary == null || partBoundary.length == 0) {
-            throw new IllegalArgumentException("partBoundary may not be empty");
-        }
-        for (int i = 0; i < parts.length; i++) {
-            // set the part boundary before the part is sent
-            parts[i].setPartBoundary(partBoundary);
-            parts[i].send(out);
-        }
-        out.write(EXTRA_BYTES);
-        out.write(partBoundary);
-        out.write(EXTRA_BYTES);
-        out.write(CRLF_BYTES);
-    }
-    
-    /**
-     * Return the total sum of all parts and that of the last boundary
-     * 
-     * @param parts The parts.
-     * @return The total length
-     * 
-     * @throws IOException If an I/O error occurs while writing the parts.
-     */
-    public static long getLengthOfParts(Part[] parts)
-    throws IOException {
-        return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES);
-    }
-    
-    /**
-     * Gets the length of the multipart message including the given parts.
-     * 
-     * @param parts The parts.
-     * @param partBoundary The ASCII bytes to use as the part boundary.
-     * @return The total length
-     * 
-     * @throws IOException If an I/O error occurs while writing the parts.
-     * 
-     * @since 3.0
-     */
-    public static long getLengthOfParts(Part[] parts, byte[] partBoundary) throws IOException {
-        LOG.trace("getLengthOfParts(Parts[])");
-        if (parts == null) {
-            throw new IllegalArgumentException("Parts may not be null"); 
-        }
-        long total = 0;
-        for (int i = 0; i < parts.length; i++) {
-            // set the part boundary before we calculate the part's length
-            parts[i].setPartBoundary(partBoundary);
-            long l = parts[i].length();
-            if (l < 0) {
-                return -1;
-            }
-            total += l;
-        }
-        total += EXTRA_BYTES.length;
-        total += partBoundary.length;
-        total += EXTRA_BYTES.length;
-        total += CRLF_BYTES.length;
-        return total;
-    }        
-}
diff --git a/core/java/com/android/internal/http/multipart/PartBase.java b/core/java/com/android/internal/http/multipart/PartBase.java
deleted file mode 100644
index 876d15d..0000000
--- a/core/java/com/android/internal/http/multipart/PartBase.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartBase.java,v 1.5 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-
-/**
- * Provides setters and getters for the basic Part properties.
- * 
- * @author Michael Becke
- */
-public abstract class PartBase extends Part {
-
-    /** Name of the file part. */
-    private String name;
-        
-    /** Content type of the file part. */
-    private String contentType;
-
-    /** Content encoding of the file part. */
-    private String charSet;
-    
-    /** The transfer encoding. */
-    private String transferEncoding;
-
-    /**
-     * Constructor.
-     * 
-     * @param name The name of the part
-     * @param contentType The content type, or <code>null</code>
-     * @param charSet The character encoding, or <code>null</code> 
-     * @param transferEncoding The transfer encoding, or <code>null</code>
-     */
-    public PartBase(String name, String contentType, String charSet, String transferEncoding) {
-
-        if (name == null) {
-            throw new IllegalArgumentException("Name must not be null");
-        }
-        this.name = name;
-        this.contentType = contentType;
-        this.charSet = charSet;
-        this.transferEncoding = transferEncoding;
-    }
-
-    /**
-     * Returns the name.
-     * @return The name.
-     * @see Part#getName()
-     */
-    @Override
-    public String getName() { 
-        return this.name; 
-    }
-
-    /**
-     * Returns the content type of this part.
-     * @return String The name.
-     */
-    @Override
-    public String getContentType() {
-        return this.contentType;
-    }
-
-    /**
-     * Return the character encoding of this part.
-     * @return String The name.
-     */
-    @Override
-    public String getCharSet() {
-        return this.charSet;
-    }
-
-    /**
-     * Returns the transfer encoding of this part.
-     * @return String The name.
-     */
-    @Override
-    public String getTransferEncoding() {
-        return transferEncoding;
-    }
-
-    /**
-     * Sets the character encoding.
-     * 
-     * @param charSet the character encoding, or <code>null</code> to exclude the character 
-     * encoding header
-     */
-    public void setCharSet(String charSet) {
-        this.charSet = charSet;
-    }
-
-    /**
-     * Sets the content type.
-     * 
-     * @param contentType the content type, or <code>null</code> to exclude the content type header
-     */
-    public void setContentType(String contentType) {
-        this.contentType = contentType;
-    }
-
-    /**
-     * Sets the part name.
-     * 
-     * @param name
-     */
-    public void setName(String name) {
-        if (name == null) {
-            throw new IllegalArgumentException("Name must not be null");
-        }
-        this.name = name;
-    }
-
-    /**
-     * Sets the transfer encoding.
-     * 
-     * @param transferEncoding the transfer encoding, or <code>null</code> to exclude the 
-     * transfer encoding header
-     */
-    public void setTransferEncoding(String transferEncoding) {
-        this.transferEncoding = transferEncoding;
-    }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/PartSource.java b/core/java/com/android/internal/http/multipart/PartSource.java
deleted file mode 100644
index 3740696..0000000
--- a/core/java/com/android/internal/http/multipart/PartSource.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartSource.java,v 1.6 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * An interface for providing access to data when posting MultiPart messages.
- * 
- * @see FilePart
- * 
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- *   
- * @since 2.0 
- */
-public interface PartSource {
-
-    /**
-     * Gets the number of bytes contained in this source.
-     * 
-     * @return a value >= 0
-     */
-    long getLength();
-    
-    /**
-     * Gets the name of the file this source represents.
-     * 
-     * @return the fileName used for posting a MultiPart file part
-     */
-    String getFileName();
-    
-    /**
-     * Gets a new InputStream for reading this source.  This method can be 
-     * called more than once and should therefore return a new stream every
-     * time.
-     * 
-     * @return a new InputStream
-     * 
-     * @throws IOException if an error occurs when creating the InputStream
-     */
-    InputStream createInputStream() throws IOException;
-
-}
diff --git a/core/java/com/android/internal/http/multipart/StringPart.java b/core/java/com/android/internal/http/multipart/StringPart.java
deleted file mode 100644
index 73d0f90..0000000
--- a/core/java/com/android/internal/http/multipart/StringPart.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v 1.11 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT 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 software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.OutputStream;
-import java.io.IOException;
-
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Simple string parameter for a multipart post
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- *     The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
- */
-@Deprecated
-public class StringPart extends PartBase {
-
-    /** Log object for this class. */
-    private static final Log LOG = LogFactory.getLog(StringPart.class);
-
-    /** Default content encoding of string parameters. */
-    public static final String DEFAULT_CONTENT_TYPE = "text/plain";
-
-    /** Default charset of string parameters*/
-    public static final String DEFAULT_CHARSET = "US-ASCII";
-
-    /** Default transfer encoding of string parameters*/
-    public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
-
-    /** Contents of this StringPart. */
-    private byte[] content;
-    
-    /** The String value of this part. */
-    private String value;
-
-    /**
-     * Constructor.
-     *
-     * @param name The name of the part
-     * @param value the string to post
-     * @param charset the charset to be used to encode the string, if <code>null</code> 
-     * the {@link #DEFAULT_CHARSET default} is used
-     */
-    public StringPart(String name, String value, String charset) {
-        
-        super(
-            name,
-            DEFAULT_CONTENT_TYPE,
-            charset == null ? DEFAULT_CHARSET : charset,
-            DEFAULT_TRANSFER_ENCODING
-        );
-        if (value == null) {
-            throw new IllegalArgumentException("Value may not be null");
-        }
-        if (value.indexOf(0) != -1) {
-            // See RFC 2048, 2.8. "8bit Data"
-            throw new IllegalArgumentException("NULs may not be present in string parts");
-        }
-        this.value = value;
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param name The name of the part
-     * @param value the string to post
-     */
-    public StringPart(String name, String value) {
-        this(name, value, null);
-    }
-    
-    /**
-     * Gets the content in bytes.  Bytes are lazily created to allow the charset to be changed
-     * after the part is created.
-     * 
-     * @return the content in bytes
-     */
-    private byte[] getContent() {
-        if (content == null) {
-            content = EncodingUtils.getBytes(value, getCharSet());
-        }
-        return content;
-    }
-    
-    /**
-     * Writes the data to the given OutputStream.
-     * @param out the OutputStream to write to
-     * @throws IOException if there is a write error
-     */
-    @Override
-    protected void sendData(OutputStream out) throws IOException {
-        LOG.trace("enter sendData(OutputStream)");
-        out.write(getContent());
-    }
-    
-    /**
-     * Return the length of the data.
-     * @return The length of the data.
-     * @see Part#lengthOfData()
-     */
-    @Override
-    protected long lengthOfData() {
-        LOG.trace("enter lengthOfData()");
-        return getContent().length;
-    }
-    
-    /* (non-Javadoc)
-     * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String)
-     */
-    @Override
-    public void setCharSet(String charSet) {
-        super.setCharSet(charSet);
-        this.content = null;
-    }
-
-}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 183527c..29326d3a 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -35,6 +35,8 @@
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.TextServicesManager;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -130,7 +132,7 @@
         return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
     }
 
-    private static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
+    public static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
             final Context context, final boolean checkDefaultAttribute,
             @Nullable final Locale requiredLocale, final boolean checkCountry,
             final String requiredSubtypeMode) {
@@ -409,6 +411,24 @@
         return false;
     }
 
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+
     public static boolean containsSubtypeOf(final InputMethodInfo imi,
             @Nullable final Locale locale, final boolean checkCountry, final String mode) {
         if (locale == null) {
@@ -418,15 +438,16 @@
         for (int i = 0; i < N; ++i) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(i);
             if (checkCountry) {
-                // TODO: Use {@link Locale#toLanguageTag()} and
-                // {@link Locale#forLanguageTag(languageTag)} instead.
-                if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
+                final Locale subtypeLocale = constructLocaleFromString(subtype.getLocale());
+                if (subtypeLocale == null ||
+                        !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) ||
+                        !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) {
                     continue;
                 }
             } else {
                 final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
                         subtype.getLocale()));
-                if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
+                if (!TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage())) {
                     continue;
                 }
             }
@@ -518,7 +539,8 @@
         return NOT_A_SUBTYPE_ID;
     }
 
-    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+    @VisibleForTesting
+    public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
             Resources res, InputMethodInfo imi) {
         final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
         final String systemLocale = res.getConfiguration().locale.toString();
diff --git a/core/java/com/android/internal/net/VpnInfo.aidl b/core/java/com/android/internal/net/VpnInfo.aidl
new file mode 100644
index 0000000..6fc97be
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+parcelable VpnInfo;
diff --git a/core/java/com/android/internal/net/VpnInfo.java b/core/java/com/android/internal/net/VpnInfo.java
new file mode 100644
index 0000000..a676dac
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A lightweight container used to carry information of the ongoing VPN.
+ * Internal use only..
+ *
+ * @hide
+ */
+public class VpnInfo implements Parcelable {
+    public int ownerUid;
+    public String vpnIface;
+    public String primaryUnderlyingIface;
+
+    @Override
+    public String toString() {
+        return "VpnInfo{" +
+                "ownerUid=" + ownerUid +
+                ", vpnIface='" + vpnIface + '\'' +
+                ", primaryUnderlyingIface='" + primaryUnderlyingIface + '\'' +
+                '}';
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(ownerUid);
+        dest.writeString(vpnIface);
+        dest.writeString(primaryUnderlyingIface);
+    }
+
+    public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() {
+        @Override
+        public VpnInfo createFromParcel(Parcel source) {
+            VpnInfo info = new VpnInfo();
+            info.ownerUid = source.readInt();
+            info.vpnIface = source.readString();
+            info.primaryUnderlyingIface = source.readString();
+            return info;
+        }
+
+        @Override
+        public VpnInfo[] newArray(int size) {
+            return new VpnInfo[size];
+        }
+    };
+}
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index cfeca08..4cd959f 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -26,12 +26,15 @@
     public double value;
     public double[] values;
     public DrainType drainType;
+
+    // Measured in milliseconds.
     public long usageTime;
     public long cpuTime;
     public long gpsTime;
     public long wifiRunningTime;
     public long cpuFgTime;
     public long wakeLockTime;
+
     public long mobileRxPackets;
     public long mobileTxPackets;
     public long mobileActive;
@@ -48,6 +51,14 @@
     public String[] mPackages;
     public String packageWithHighestDrain;
 
+    // Measured in mAh (milli-ampere per hour).
+    public double wifiPower;
+    public double cpuPower;
+    public double wakeLockPower;
+    public double mobileRadioPower;
+    public double gpsPower;
+    public double sensorPower;
+
     public enum DrainType {
         IDLE,
         CELL,
@@ -107,4 +118,31 @@
         }
         return uidObj.getUid();
     }
+
+    /**
+     * Add stats from other to this BatterySipper.
+     */
+    public void add(BatterySipper other) {
+        cpuTime += other.cpuTime;
+        gpsTime += other.gpsTime;
+        wifiRunningTime += other.wifiRunningTime;
+        cpuFgTime += other.cpuFgTime;
+        wakeLockTime += other.wakeLockTime;
+        mobileRxPackets += other.mobileRxPackets;
+        mobileTxPackets += other.mobileTxPackets;
+        mobileActive += other.mobileActive;
+        mobileActiveCount += other.mobileActiveCount;
+        wifiRxPackets += other.wifiRxPackets;
+        wifiTxPackets += other.wifiTxPackets;
+        mobileRxBytes += other.mobileRxBytes;
+        mobileTxBytes += other.mobileTxBytes;
+        wifiRxBytes += other.wifiRxBytes;
+        wifiTxBytes += other.wifiTxBytes;
+        wifiPower += other.wifiPower;
+        gpsPower += other.gpsPower;
+        cpuPower += other.cpuPower;
+        sensorPower += other.sensorPower;
+        mobileRadioPower += other.mobileRadioPower;
+        wakeLockPower += other.wakeLockPower;
+    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index eae4427..d3611bf 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -344,6 +344,7 @@
                 mMobilemsppList.add(bs);
             }
         }
+
         for (int i=0; i<mUserSippers.size(); i++) {
             List<BatterySipper> user = mUserSippers.valueAt(i);
             for (int j=0; j<user.size(); j++) {
@@ -389,8 +390,8 @@
 
     private void processAppUsage(SparseArray<UserHandle> asUsers) {
         final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        SensorManager sensorManager = (SensorManager) mContext.getSystemService(
-                Context.SENSOR_SERVICE);
+        final SensorManager sensorManager =
+                (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
         final int which = mStatsType;
         final int speedSteps = mPowerProfile.getNumSpeedSteps();
         final double[] powerCpuNormal = new double[speedSteps];
@@ -401,238 +402,317 @@
         final double mobilePowerPerPacket = getMobilePowerPerPacket();
         final double mobilePowerPerMs = getMobilePowerPerMs();
         final double wifiPowerPerPacket = getWifiPowerPerPacket();
-        long appWakelockTimeUs = 0;
+        long totalAppWakelockTimeUs = 0;
         BatterySipper osApp = null;
         mStatsPeriod = mTypeBatteryRealtime;
-        SparseArray<? extends Uid> uidStats = mStats.getUidStats();
+
+        final ArrayList<BatterySipper> appList = new ArrayList<>();
+
+        // Max values used to normalize later.
+        double maxWifiPower = 0;
+        double maxCpuPower = 0;
+        double maxWakeLockPower = 0;
+        double maxMobileRadioPower = 0;
+        double maxGpsPower = 0;
+        double maxSensorPower = 0;
+
+        final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
         final int NU = uidStats.size();
         for (int iu = 0; iu < NU; iu++) {
-            Uid u = uidStats.valueAt(iu);
-            double p; // in mAs
-            double power = 0; // in mAs
-            double highestDrain = 0;
-            String packageWithHighestDrain = null;
-            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
-            long cpuTime = 0;
-            long cpuFgTime = 0;
-            long wakelockTime = 0;
-            long gpsTime = 0;
+            final Uid u = uidStats.valueAt(iu);
+            final BatterySipper app = new BatterySipper(
+                    BatterySipper.DrainType.APP, u, new double[]{0});
+
+            final Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
             if (processStats.size() > 0) {
-                // Process CPU time
+                // Process CPU time.
+
+                // Keep track of the package with highest drain.
+                double highestDrain = 0;
+
                 for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
                         : processStats.entrySet()) {
                     Uid.Proc ps = ent.getValue();
-                    final long userTime = ps.getUserTime(which);
-                    final long systemTime = ps.getSystemTime(which);
-                    final long foregroundTime = ps.getForegroundTime(which);
-                    cpuFgTime += foregroundTime * 10; // convert to millis
-                    final long tmpCpuTime = (userTime + systemTime) * 10; // convert to millis
-                    int totalTimeAtSpeeds = 0;
-                    // Get the total first
+                    app.cpuFgTime += ps.getForegroundTime(which);
+                    final long totalCpuTime = ps.getUserTime(which) + ps.getSystemTime(which);
+                    app.cpuTime += totalCpuTime;
+
+                    // Calculate the total CPU time spent at the various speed steps.
+                    long totalTimeAtSpeeds = 0;
                     for (int step = 0; step < speedSteps; step++) {
                         cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which);
                         totalTimeAtSpeeds += cpuSpeedStepTimes[step];
                     }
-                    if (totalTimeAtSpeeds == 0) totalTimeAtSpeeds = 1;
-                    // Then compute the ratio of time spent at each speed
-                    double processPower = 0;
+                    totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
+
+                    // Then compute the ratio of time spent at each speed and figure out
+                    // the total power consumption.
+                    double cpuPower = 0;
                     for (int step = 0; step < speedSteps; step++) {
-                        double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
-                        if (DEBUG && ratio != 0) Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
-                                + step + " ratio=" + makemAh(ratio) + " power="
-                                + makemAh(ratio*tmpCpuTime*powerCpuNormal[step] / (60*60*1000)));
-                        processPower += ratio * tmpCpuTime * powerCpuNormal[step];
+                        final double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
+                        final double cpuSpeedStepPower =
+                                ratio * totalCpuTime * powerCpuNormal[step];
+                        if (DEBUG && ratio != 0) {
+                            Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
+                                    + step + " ratio=" + makemAh(ratio) + " power="
+                                    + makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+                        }
+                        cpuPower += cpuSpeedStepPower;
                     }
-                    cpuTime += tmpCpuTime;
-                    if (DEBUG && processPower != 0) {
+
+                    if (DEBUG && cpuPower != 0) {
                         Log.d(TAG, String.format("process %s, cpu power=%s",
-                                ent.getKey(), makemAh(processPower / (60*60*1000))));
+                                ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000))));
                     }
-                    power += processPower;
-                    if (packageWithHighestDrain == null
-                            || packageWithHighestDrain.startsWith("*")) {
-                        highestDrain = processPower;
-                        packageWithHighestDrain = ent.getKey();
-                    } else if (highestDrain < processPower
-                            && !ent.getKey().startsWith("*")) {
-                        highestDrain = processPower;
-                        packageWithHighestDrain = ent.getKey();
+                    app.cpuPower += cpuPower;
+
+                    // Each App can have multiple packages and with multiple running processes.
+                    // Keep track of the package who's process has the highest drain.
+                    if (app.packageWithHighestDrain == null ||
+                            app.packageWithHighestDrain.startsWith("*")) {
+                        highestDrain = cpuPower;
+                        app.packageWithHighestDrain = ent.getKey();
+                    } else if (highestDrain < cpuPower && !ent.getKey().startsWith("*")) {
+                        highestDrain = cpuPower;
+                        app.packageWithHighestDrain = ent.getKey();
                     }
                 }
             }
-            if (cpuFgTime > cpuTime) {
-                if (DEBUG && cpuFgTime > cpuTime + 10000) {
+
+            // Ensure that the CPU times make sense.
+            if (app.cpuFgTime > app.cpuTime) {
+                if (DEBUG && app.cpuFgTime > app.cpuTime + 10000) {
                     Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
                 }
-                cpuTime = cpuFgTime; // Statistics may not have been gathered yet.
+
+                // Statistics may not have been gathered yet.
+                app.cpuTime = app.cpuFgTime;
             }
-            power /= (60*60*1000);
+
+            // Convert the CPU power to mAh
+            app.cpuPower /= (60 * 60 * 1000);
+            maxCpuPower = Math.max(maxCpuPower, app.cpuPower);
 
             // Process wake lock usage
-            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats();
+            final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
+                    u.getWakelockStats();
+            long wakeLockTimeUs = 0;
             for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry
                     : wakelockStats.entrySet()) {
-                Uid.Wakelock wakelock = wakelockEntry.getValue();
+                final Uid.Wakelock wakelock = wakelockEntry.getValue();
+
                 // Only care about partial wake locks since full wake locks
                 // are canceled when the user turns the screen off.
                 BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
                 if (timer != null) {
-                    wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which);
+                    wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which);
                 }
             }
-            appWakelockTimeUs += wakelockTime;
-            wakelockTime /= 1000; // convert to millis
+            app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis
+            totalAppWakelockTimeUs += wakeLockTimeUs;
 
-            // Add cost of holding a wake lock
-            p = (wakelockTime
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000);
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wake "
-                    + wakelockTime + " power=" + makemAh(p));
-            power += p;
+            // Add cost of holding a wake lock.
+            app.wakeLockPower = (app.wakeLockTime *
+                    mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60 * 60 * 1000);
+            if (DEBUG && app.wakeLockPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wake "
+                        + app.wakeLockTime + " power=" + makemAh(app.wakeLockPower));
+            }
+            maxWakeLockPower = Math.max(maxWakeLockPower, app.wakeLockPower);
 
-            // Add cost of mobile traffic
-            final long mobileRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
-            final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
-            final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
-            final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
+            // Add cost of mobile traffic.
             final long mobileActive = u.getMobileRadioActiveTime(mStatsType);
+            app.mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
+            app.mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
+            app.mobileActive = mobileActive / 1000;
+            app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
+            app.mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
+            app.mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
+
             if (mobileActive > 0) {
                 // We are tracking when the radio is up, so can use the active time to
                 // determine power use.
                 mAppMobileActive += mobileActive;
-                p = (mobilePowerPerMs * mobileActive) / 1000;
+                app.mobileRadioPower = (mobilePowerPerMs * mobileActive) / 1000;
             } else {
                 // We are not tracking when the radio is up, so must approximate power use
                 // based on the number of packets.
-                p = (mobileRx + mobileTx) * mobilePowerPerPacket;
+                app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets)
+                        * mobilePowerPerPacket;
             }
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
-                    + (mobileRx+mobileTx) + " active time " + mobileActive
-                    + " power=" + makemAh(p));
-            power += p;
+            if (DEBUG && app.mobileRadioPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
+                        + (app.mobileRxPackets + app.mobileTxPackets)
+                        + " active time " + mobileActive
+                        + " power=" + makemAh(app.mobileRadioPower));
+            }
+            maxMobileRadioPower = Math.max(maxMobileRadioPower, app.mobileRadioPower);
 
             // Add cost of wifi traffic
-            final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
-            final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
-            final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
-            final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
-            p = (wifiRx + wifiTx) * wifiPowerPerPacket;
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
-                    + (mobileRx+mobileTx) + " power=" + makemAh(p));
-            power += p;
+            app.wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
+            app.wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
+            app.wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
+            app.wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
 
-            // Add cost of keeping WIFI running.
-            long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000;
-            mAppWifiRunning += wifiRunningTimeMs;
-            p = (wifiRunningTimeMs
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
-            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi running "
-                    + wifiRunningTimeMs + " power=" + makemAh(p));
-            power += p;
-
-            // Add cost of WIFI scans
-            long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
-            p = (wifiScanTimeMs
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000);
-            if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
-                    + " power=" + makemAh(p));
-            power += p;
-            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
-                long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
-                p = ((batchScanTimeMs
-                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
-                    ) / (60*60*1000);
-                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
-                        + " time=" + batchScanTimeMs + " power=" + makemAh(p));
-                power += p;
+            final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
+                    * wifiPowerPerPacket;
+            if (DEBUG && wifiPacketPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
+                        + (app.wifiRxPackets + app.wifiTxPackets)
+                        + " power=" + makemAh(wifiPacketPower));
             }
 
+            // Add cost of keeping WIFI running.
+            app.wifiRunningTime = u.getWifiRunningTime(mRawRealtime, which) / 1000;
+            mAppWifiRunning += app.wifiRunningTime;
+
+            final double wifiLockPower = (app.wifiRunningTime
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60 * 60 * 1000);
+            if (DEBUG && wifiLockPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi running "
+                        + app.wifiRunningTime + " power=" + makemAh(wifiLockPower));
+            }
+
+            // Add cost of WIFI scans
+            final long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
+            final double wifiScanPower = (wifiScanTimeMs
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN))
+                    /  (60 * 60 * 1000);
+            if (DEBUG && wifiScanPower != 0) {
+                Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
+                        + " power=" + makemAh(wifiScanPower));
+            }
+
+            // Add cost of WIFI batch scans.
+            double wifiBatchScanPower = 0;
+            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
+                final long batchScanTimeMs =
+                        u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
+                final double batchScanPower = ((batchScanTimeMs
+                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
+                ) / (60 * 60 * 1000);
+                if (DEBUG && batchScanPower != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
+                            + " time=" + batchScanTimeMs + " power=" + makemAh(batchScanPower));
+                }
+                wifiBatchScanPower += batchScanPower;
+            }
+
+            // Add up all the WiFi costs.
+            app.wifiPower = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
+            maxWifiPower = Math.max(maxWifiPower, app.wifiPower);
+
             // Process Sensor usage
-            SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
-            int NSE = sensorStats.size();
-            for (int ise=0; ise<NSE; ise++) {
-                Uid.Sensor sensor = sensorStats.valueAt(ise);
-                int sensorHandle = sensorStats.keyAt(ise);
-                BatteryStats.Timer timer = sensor.getSensorTime();
-                long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
-                double multiplier = 0;
+            final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+            final int NSE = sensorStats.size();
+            for (int ise = 0; ise < NSE; ise++) {
+                final Uid.Sensor sensor = sensorStats.valueAt(ise);
+                final int sensorHandle = sensorStats.keyAt(ise);
+                final BatteryStats.Timer timer = sensor.getSensorTime();
+                final long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
+                double sensorPower = 0;
                 switch (sensorHandle) {
                     case Uid.Sensor.GPS:
-                        multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON);
-                        gpsTime = sensorTime;
+                        app.gpsTime = sensorTime;
+                        app.gpsPower = (app.gpsTime
+                                * mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON))
+                                / (60 * 60 * 1000);
+                        sensorPower = app.gpsPower;
+                        maxGpsPower = Math.max(maxGpsPower, app.gpsPower);
                         break;
                     default:
                         List<Sensor> sensorList = sensorManager.getSensorList(
                                 android.hardware.Sensor.TYPE_ALL);
                         for (android.hardware.Sensor s : sensorList) {
                             if (s.getHandle() == sensorHandle) {
-                                multiplier = s.getPower();
+                                sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000);
+                                app.sensorPower += sensorPower;
                                 break;
                             }
                         }
                 }
-                p = (multiplier * sensorTime) / (60*60*1000);
-                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
-                        + " time=" + sensorTime + " power=" + makemAh(p));
-                power += p;
+                if (DEBUG && sensorPower != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
+                            + " time=" + sensorTime + " power=" + makemAh(sensorPower));
+                }
+            }
+            maxSensorPower = Math.max(maxSensorPower, app.sensorPower);
+
+            final double totalUnnormalizedPower = app.cpuPower + app.wifiPower + app.wakeLockPower
+                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
+            if (DEBUG && totalUnnormalizedPower != 0) {
+                Log.d(TAG, String.format("UID %d: total power=%s",
+                        u.getUid(), makemAh(totalUnnormalizedPower)));
             }
 
-            if (DEBUG && power != 0) Log.d(TAG, String.format("UID %d: total power=%s",
-                    u.getUid(), makemAh(power)));
+            // Add the app to the list if it is consuming power.
+            if (totalUnnormalizedPower != 0 || u.getUid() == 0) {
+                appList.add(app);
+            }
+        }
 
-            // Add the app to the list if it is consuming power
-            final int userId = UserHandle.getUserId(u.getUid());
-            if (power != 0 || u.getUid() == 0) {
-                BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u,
-                        new double[] {power});
-                app.cpuTime = cpuTime;
-                app.gpsTime = gpsTime;
-                app.wifiRunningTime = wifiRunningTimeMs;
-                app.cpuFgTime = cpuFgTime;
-                app.wakeLockTime = wakelockTime;
-                app.mobileRxPackets = mobileRx;
-                app.mobileTxPackets = mobileTx;
-                app.mobileActive = mobileActive / 1000;
-                app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
-                app.wifiRxPackets = wifiRx;
-                app.wifiTxPackets = wifiTx;
-                app.mobileRxBytes = mobileRxB;
-                app.mobileTxBytes = mobileTxB;
-                app.wifiRxBytes = wifiRxB;
-                app.wifiTxBytes = wifiTxB;
-                app.packageWithHighestDrain = packageWithHighestDrain;
-                if (u.getUid() == Process.WIFI_UID) {
-                    mWifiSippers.add(app);
-                    mWifiPower += power;
-                } else if (u.getUid() == Process.BLUETOOTH_UID) {
-                    mBluetoothSippers.add(app);
-                    mBluetoothPower += power;
-                } else if (!forAllUsers && asUsers.get(userId) == null
-                        && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) {
-                    List<BatterySipper> list = mUserSippers.get(userId);
-                    if (list == null) {
-                        list = new ArrayList<BatterySipper>();
-                        mUserSippers.put(userId, list);
-                    }
-                    list.add(app);
-                    if (power != 0) {
-                        Double userPower = mUserPower.get(userId);
-                        if (userPower == null) {
-                            userPower = power;
-                        } else {
-                            userPower += power;
-                        }
-                        mUserPower.put(userId, userPower);
-                    }
+        // Fetch real power consumption from hardware.
+        double actualTotalWifiPower = 0.0;
+        if (mStats.getWifiControllerActivity(BatteryStats.CONTROLLER_ENERGY, mStatsType) != 0) {
+            final double kDefaultVoltage = 3.36;
+            final long energy = mStats.getWifiControllerActivity(
+                    BatteryStats.CONTROLLER_ENERGY, mStatsType);
+            final double voltage = mPowerProfile.getAveragePowerOrDefault(
+                    PowerProfile.OPERATING_VOLTAGE_WIFI, kDefaultVoltage);
+            actualTotalWifiPower = energy / (voltage * 1000*60*60);
+        }
+
+        final int appCount = appList.size();
+        for (int i = 0; i < appCount; i++) {
+            // Normalize power where possible.
+            final BatterySipper app = appList.get(i);
+            if (actualTotalWifiPower != 0) {
+                app.wifiPower = (app.wifiPower / maxWifiPower) * actualTotalWifiPower;
+            }
+
+            // Assign the final power consumption here.
+            final double power = app.wifiPower + app.cpuPower + app.wakeLockPower
+                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
+            app.values[0] = app.value = power;
+
+            //
+            // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
+            //
+
+            final int uid = app.getUid();
+            final int userId = UserHandle.getUserId(uid);
+            if (uid == Process.WIFI_UID) {
+                mWifiSippers.add(app);
+                mWifiPower += power;
+            } else if (uid == Process.BLUETOOTH_UID) {
+                mBluetoothSippers.add(app);
+                mBluetoothPower += power;
+            } else if (!forAllUsers && asUsers.get(userId) == null
+                    && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
+                // We are told to just report this user's apps as one large entry.
+                List<BatterySipper> list = mUserSippers.get(userId);
+                if (list == null) {
+                    list = new ArrayList<>();
+                    mUserSippers.put(userId, list);
+                }
+                list.add(app);
+
+                Double userPower = mUserPower.get(userId);
+                if (userPower == null) {
+                    userPower = power;
                 } else {
-                    mUsageList.add(app);
-                    if (power > mMaxPower) mMaxPower = power;
-                    if (power > mMaxRealPower) mMaxRealPower = power;
-                    mComputedPower += power;
+                    userPower += power;
                 }
-                if (u.getUid() == 0) {
-                    osApp = app;
-                }
+                mUserPower.put(userId, userPower);
+            } else {
+                mUsageList.add(app);
+                if (power > mMaxPower) mMaxPower = power;
+                if (power > mMaxRealPower) mMaxRealPower = power;
+                mComputedPower += power;
+            }
+
+            if (uid == 0) {
+                osApp = app;
             }
         }
 
@@ -641,7 +721,7 @@
         // this remainder to the OS, if possible.
         if (osApp != null) {
             long wakeTimeMillis = mBatteryUptime / 1000;
-            wakeTimeMillis -= (appWakelockTimeUs / 1000)
+            wakeTimeMillis -= (totalAppWakelockTimeUs / 1000)
                     + (mStats.getScreenOnTime(mRawRealtime, which) / 1000);
             if (wakeTimeMillis > 0) {
                 double power = (wakeTimeMillis
@@ -741,46 +821,11 @@
         for (int i=0; i<from.size(); i++) {
             BatterySipper wbs = from.get(i);
             if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
-            bs.cpuTime += wbs.cpuTime;
-            bs.gpsTime += wbs.gpsTime;
-            bs.wifiRunningTime += wbs.wifiRunningTime;
-            bs.cpuFgTime += wbs.cpuFgTime;
-            bs.wakeLockTime += wbs.wakeLockTime;
-            bs.mobileRxPackets += wbs.mobileRxPackets;
-            bs.mobileTxPackets += wbs.mobileTxPackets;
-            bs.mobileActive += wbs.mobileActive;
-            bs.mobileActiveCount += wbs.mobileActiveCount;
-            bs.wifiRxPackets += wbs.wifiRxPackets;
-            bs.wifiTxPackets += wbs.wifiTxPackets;
-            bs.mobileRxBytes += wbs.mobileRxBytes;
-            bs.mobileTxBytes += wbs.mobileTxBytes;
-            bs.wifiRxBytes += wbs.wifiRxBytes;
-            bs.wifiTxBytes += wbs.wifiTxBytes;
+            bs.add(wbs);
         }
         bs.computeMobilemspp();
     }
 
-    private void addWiFiUsage() {
-        long onTimeMs = mStats.getWifiOnTime(mRawRealtime, mStatsType) / 1000;
-        long runningTimeMs = mStats.getGlobalWifiRunningTime(mRawRealtime, mStatsType) / 1000;
-        if (DEBUG) Log.d(TAG, "WIFI runningTime=" + runningTimeMs
-                + " app runningTime=" + mAppWifiRunning);
-        runningTimeMs -= mAppWifiRunning;
-        if (runningTimeMs < 0) runningTimeMs = 0;
-        double wifiPower = (onTimeMs * 0 /* TODO */
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)
-                + runningTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON))
-                / (60*60*1000);
-        if (DEBUG && wifiPower != 0) {
-            Log.d(TAG, "Wifi: time=" + runningTimeMs + " power=" + makemAh(wifiPower));
-        }
-        if ((wifiPower+mWifiPower) != 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, runningTimeMs,
-                    wifiPower + mWifiPower);
-            aggregateSippers(bs, mWifiSippers, "WIFI");
-        }
-    }
-
     private void addIdleUsage() {
         long idleTimeMs = (mTypeBatteryRealtime
                 - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
@@ -794,24 +839,81 @@
         }
     }
 
+    /**
+     * We do per-app blaming of WiFi activity. If energy info is reported from the controller,
+     * then only the WiFi process gets blamed here since we normalize power calculations and
+     * assign all the power drain to apps. If energy info is not reported, we attribute the
+     * difference between total running time of WiFi for all apps and the actual running time
+     * of WiFi to the WiFi subsystem.
+     */
+    private void addWiFiUsage() {
+        final long idleTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
+        final long txTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
+        final long rxTimeMs = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
+        final long energy = mStats.getWifiControllerActivity(
+                BatteryStats.CONTROLLER_ENERGY, mStatsType);
+        final long totalTimeRunning = idleTimeMs + txTimeMs + rxTimeMs;
+
+        double powerDrain = 0;
+        if (energy == 0 && totalTimeRunning > 0) {
+            // Energy is not reported, which means we may have left over power drain not attributed
+            // to any app. Assign this power to the WiFi app.
+            // TODO(adamlesinski): This mimics the old behavior. However, mAppWifiRunningTime
+            // is the accumulation of the time each app kept the WiFi chip on. Multiple apps
+            // can do this at the same time, so these times do not add up to the total time
+            // the WiFi chip was on. Consider normalizing the time spent running and calculating
+            // power from that? Normalizing the times will assign a weight to each app which
+            // should better represent power usage.
+            powerDrain = ((totalTimeRunning - mAppWifiRunning)
+                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
+        }
+
+        if (DEBUG && powerDrain != 0) {
+            Log.d(TAG, "Wifi active: time=" + (txTimeMs + rxTimeMs)
+                    + " power=" + makemAh(powerDrain));
+        }
+
+        // TODO(adamlesinski): mWifiPower is already added as a BatterySipper...
+        // Are we double counting here?
+        final double power = mWifiPower + powerDrain;
+        if (power > 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, totalTimeRunning, power);
+            aggregateSippers(bs, mWifiSippers, "WIFI");
+        }
+    }
+
+    /**
+     * Bluetooth usage is not attributed to any apps yet, so the entire blame goes to the
+     * Bluetooth Category.
+     */
     private void addBluetoothUsage() {
-        long btOnTimeMs = mStats.getBluetoothOnTime(mRawRealtime, mStatsType) / 1000;
-        double btPower = btOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON)
-                / (60*60*1000);
-        if (DEBUG && btPower != 0) {
-            Log.d(TAG, "Bluetooth: time=" + btOnTimeMs + " power=" + makemAh(btPower));
+        final double kDefaultVoltage = 3.36;
+        final long idleTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
+        final long txTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
+        final long rxTimeMs = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
+        final long energy = mStats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_ENERGY, mStatsType);
+        final double voltage = mPowerProfile.getAveragePowerOrDefault(
+                PowerProfile.OPERATING_VOLTAGE_BLUETOOTH, kDefaultVoltage);
+
+        // energy is measured in mA * V * ms, and we are interested in mAh
+        final double powerDrain = energy / (voltage * 60*60*1000);
+
+        if (DEBUG && powerDrain != 0) {
+            Log.d(TAG, "Bluetooth active: time=" + (txTimeMs + rxTimeMs)
+                    + " power=" + makemAh(powerDrain));
         }
-        int btPingCount = mStats.getBluetoothPingCount();
-        double pingPower = (btPingCount
-                * mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD))
-                / (60*60*1000);
-        if (DEBUG && pingPower != 0) {
-            Log.d(TAG, "Bluetooth ping: count=" + btPingCount + " power=" + makemAh(pingPower));
-        }
-        btPower += pingPower;
-        if ((btPower+mBluetoothPower) != 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, btOnTimeMs,
-                    btPower + mBluetoothPower);
+
+        final long totalTime = idleTimeMs + txTimeMs + rxTimeMs;
+        final double power = mBluetoothPower + powerDrain;
+        if (power > 0) {
+            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, totalTime, power);
             aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 20bb95e..f9b1ca1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -20,11 +20,15 @@
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.app.ActivityManager;
+import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiManager;
 import android.os.BadParcelableException;
 import android.os.BatteryManager;
@@ -38,6 +42,8 @@
 import android.os.ParcelFormatException;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.WorkSource;
@@ -56,20 +62,29 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
+import android.util.Xml;
 import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
 
+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.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -94,7 +109,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 119 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -111,6 +126,7 @@
 
     private final JournaledFile mFile;
     public final AtomicFile mCheckinFile;
+    public final AtomicFile mDailyFile;
 
     static final int MSG_UPDATE_WAKELOCKS = 1;
     static final int MSG_REPORT_POWER_CHANGE = 2;
@@ -208,7 +224,7 @@
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
     final HistoryItem mHistoryAddTmp = new HistoryItem();
-    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap();
     String[] mReadHistoryStrings;
     int[] mReadHistoryUids;
     int mReadHistoryChars;
@@ -227,6 +243,38 @@
     HistoryItem mHistoryLastEnd;
     HistoryItem mHistoryCache;
 
+    // Used by computeHistoryStepDetails
+    HistoryStepDetails mLastHistoryStepDetails = null;
+    byte mLastHistoryStepLevel = 0;
+    final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails();
+    /**
+     * Total time (in 1/100 sec) spent executing in user code.
+     */
+    long mLastStepCpuUserTime;
+    long mCurStepCpuUserTime;
+    /**
+     * Total time (in 1/100 sec) spent executing in kernel code.
+     */
+    long mLastStepCpuSystemTime;
+    long mCurStepCpuSystemTime;
+    /**
+     * Times from /proc/stat
+     */
+    long mLastStepStatUserTime;
+    long mLastStepStatSystemTime;
+    long mLastStepStatIOWaitTime;
+    long mLastStepStatIrqTime;
+    long mLastStepStatSoftIrqTime;
+    long mLastStepStatIdleTime;
+    long mCurStepStatUserTime;
+    long mCurStepStatSystemTime;
+    long mCurStepStatIOWaitTime;
+    long mCurStepStatIrqTime;
+    long mCurStepStatSoftIrqTime;
+    long mCurStepStatIdleTime;
+
     private HistoryItem mHistoryIterator;
     private boolean mReadOverflow;
     private boolean mIteratingHistory;
@@ -290,6 +338,12 @@
     final LongSamplingCounter[] mNetworkPacketActivityCounters =
             new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
 
+    final LongSamplingCounter[] mBluetoothActivityCounters =
+            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
+    final LongSamplingCounter[] mWifiActivityCounters =
+            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
     boolean mWifiOn;
     StopwatchTimer mWifiOnTimer;
 
@@ -354,16 +408,22 @@
     int mModStepMode = 0;
 
     int mLastDischargeStepLevel;
-    long mLastDischargeStepTime;
     int mMinDischargeStepLevel;
-    int mNumDischargeStepDurations;
-    final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS];
+    final LevelStepTracker mDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
+    final LevelStepTracker mDailyDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
 
     int mLastChargeStepLevel;
-    long mLastChargeStepTime;
     int mMaxChargeStepLevel;
-    int mNumChargeStepDurations;
-    final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS];
+    final LevelStepTracker mChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
+    final LevelStepTracker mDailyChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
+
+    static final int MAX_DAILY_ITEMS = 10;
+
+    long mDailyStartTime = 0;
+    long mNextMinDailyDeadline = 0;
+    long mNextMaxDailyDeadline = 0;
+
+    final ArrayList<DailyItem> mDailyItems = new ArrayList<>();
 
     long mLastWriteTime = 0; // Milliseconds
 
@@ -446,6 +506,7 @@
     public BatteryStatsImpl() {
         mFile = null;
         mCheckinFile = null;
+        mDailyFile = null;
         mHandler = null;
         clearHistoryLocked();
     }
@@ -1938,6 +1999,10 @@
     static final int STATE_BATTERY_PLUG_MASK    = 0x00000003;
     static final int STATE_BATTERY_PLUG_SHIFT   = 24;
 
+    // We use the low bit of the battery state int to indicate that we have full details
+    // from a battery level change.
+    static final int BATTERY_DELTA_LEVEL_FLAG   = 0x00000001;
+
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
@@ -1958,7 +2023,11 @@
             deltaTimeToken = (int)deltaTime;
         }
         int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
-        final int batteryLevelInt = buildBatteryLevelInt(cur);
+        final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel
+                ? BATTERY_DELTA_LEVEL_FLAG : 0;
+        final boolean computeStepDetails = includeStepDetails != 0
+                || mLastHistoryStepDetails == null;
+        final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails;
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
             firstToken |= DELTA_BATTERY_LEVEL_FLAG;
@@ -2040,12 +2109,26 @@
                     + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
                     + cur.eventTag.string);
         }
+        if (computeStepDetails) {
+            computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
+            if (includeStepDetails != 0) {
+                mCurHistoryStepDetails.writeToParcel(dest);
+            }
+            cur.stepDetails = mCurHistoryStepDetails;
+            mLastHistoryStepDetails = mCurHistoryStepDetails;
+        } else {
+            cur.stepDetails = null;
+        }
+        if (mLastHistoryStepLevel < cur.batteryLevel) {
+            mLastHistoryStepDetails = null;
+        }
+        mLastHistoryStepLevel = cur.batteryLevel;
     }
 
     private int buildBatteryLevelInt(HistoryItem h) {
         return ((((int)h.batteryLevel)<<25)&0xfe000000)
-                | ((((int)h.batteryTemperature)<<14)&0x01ffc000)
-                | (((int)h.batteryVoltage)&0x00003fff);
+                | ((((int)h.batteryTemperature)<<14)&0x01ff8000)
+                | ((((int)h.batteryVoltage)<<1)&0x00007fff);
     }
 
     private int buildStateInt(HistoryItem h) {
@@ -2063,6 +2146,98 @@
                 | (h.states&(~DELTA_STATE_MASK));
     }
 
+    private void computeHistoryStepDetails(final HistoryStepDetails out,
+            final HistoryStepDetails last) {
+        final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out;
+
+        // Perform a CPU update right after we do this collection, so we have started
+        // collecting good data for the next step.
+        requestImmediateCpuUpdate();
+
+        if (last == null) {
+            // We are not generating a delta, so all we need to do is reset the stats
+            // we will later be doing a delta from.
+            final int NU = mUidStats.size();
+            for (int i=0; i<NU; i++) {
+                final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+                uid.mLastStepUserTime = uid.mCurStepUserTime;
+                uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            }
+            mLastStepCpuUserTime = mCurStepCpuUserTime;
+            mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+            mLastStepStatUserTime = mCurStepStatUserTime;
+            mLastStepStatSystemTime = mCurStepStatSystemTime;
+            mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+            mLastStepStatIrqTime = mCurStepStatIrqTime;
+            mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+            mLastStepStatIdleTime = mCurStepStatIdleTime;
+            tmp.clear();
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTime + " sys="
+                    + mLastStepStatSystemTime + " io=" + mLastStepStatIOWaitTime
+                    + " irq=" + mLastStepStatIrqTime + " sirq="
+                    + mLastStepStatSoftIrqTime + " idle=" + mLastStepStatIdleTime);
+            Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTime + " sys="
+                    + mCurStepStatSystemTime + " io=" + mCurStepStatIOWaitTime
+                    + " irq=" + mCurStepStatIrqTime + " sirq="
+                    + mCurStepStatSoftIrqTime + " idle=" + mCurStepStatIdleTime);
+        }
+        out.userTime = (int)(mCurStepCpuUserTime - mLastStepCpuUserTime);
+        out.systemTime = (int)(mCurStepCpuSystemTime - mLastStepCpuSystemTime);
+        out.statUserTime = (int)(mCurStepStatUserTime - mLastStepStatUserTime);
+        out.statSystemTime = (int)(mCurStepStatSystemTime - mLastStepStatSystemTime);
+        out.statIOWaitTime = (int)(mCurStepStatIOWaitTime - mLastStepStatIOWaitTime);
+        out.statIrqTime = (int)(mCurStepStatIrqTime - mLastStepStatIrqTime);
+        out.statSoftIrqTime = (int)(mCurStepStatSoftIrqTime - mLastStepStatSoftIrqTime);
+        out.statIdlTime = (int)(mCurStepStatIdleTime - mLastStepStatIdleTime);
+        out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1;
+        out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0;
+        out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0;
+        final int NU = mUidStats.size();
+        for (int i=0; i<NU; i++) {
+            final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+            final int totalUTime = (int)(uid.mCurStepUserTime - uid.mLastStepUserTime);
+            final int totalSTime = (int)(uid.mCurStepSystemTime - uid.mLastStepSystemTime);
+            final int totalTime = totalUTime + totalSTime;
+            uid.mLastStepUserTime = uid.mCurStepUserTime;
+            uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            if (totalTime <= (out.appCpuUTime3+out.appCpuSTime3)) {
+                continue;
+            }
+            if (totalTime <= (out.appCpuUTime2+out.appCpuSTime2)) {
+                out.appCpuUid3 = uid.mUid;
+                out.appCpuUTime3 = totalUTime;
+                out.appCpuSTime3 = totalSTime;
+            } else {
+                out.appCpuUid3 = out.appCpuUid2;
+                out.appCpuUTime3 = out.appCpuUTime2;
+                out.appCpuSTime3 = out.appCpuSTime2;
+                if (totalTime <= (out.appCpuUTime1+out.appCpuSTime1)) {
+                    out.appCpuUid2 = uid.mUid;
+                    out.appCpuUTime2 = totalUTime;
+                    out.appCpuSTime2 = totalSTime;
+                } else {
+                    out.appCpuUid2 = out.appCpuUid1;
+                    out.appCpuUTime2 = out.appCpuUTime1;
+                    out.appCpuSTime2 = out.appCpuSTime1;
+                    out.appCpuUid1 = uid.mUid;
+                    out.appCpuUTime1 = totalUTime;
+                    out.appCpuSTime1 = totalSTime;
+                }
+            }
+        }
+        mLastStepCpuUserTime = mCurStepCpuUserTime;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+        mLastStepStatUserTime = mCurStepStatUserTime;
+        mLastStepStatSystemTime = mCurStepStatSystemTime;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+        mLastStepStatIrqTime = mCurStepStatIrqTime;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+        mLastStepStatIdleTime = mCurStepStatIdleTime;
+    }
+
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
@@ -2091,8 +2266,9 @@
             cur.numReadInts += 2;
         }
 
+        final int batteryLevelInt;
         if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
-            int batteryLevelInt = src.readInt();
+            batteryLevelInt = src.readInt();
             cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
             cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
             cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
@@ -2102,6 +2278,8 @@
                     + " batteryLevel=" + cur.batteryLevel
                     + " batteryTemp=" + cur.batteryTemperature
                     + " batteryVolt=" + (int)cur.batteryVoltage);
+        } else {
+            batteryLevelInt = 0;
         }
 
         if ((firstToken&DELTA_STATE_FLAG) != 0) {
@@ -2180,6 +2358,13 @@
         } else {
             cur.eventCode = HistoryItem.EVENT_NONE;
         }
+
+        if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
+            cur.stepDetails = mReadHistoryStepDetails;
+            cur.stepDetails.readFromParcel(src);
+        } else {
+            cur.stepDetails = null;
+        }
     }
 
     @Override
@@ -2207,6 +2392,7 @@
                 && (diffStates2&lastDiffStates2) == 0
                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
+                && mHistoryLastWritten.stepDetails == null
                 && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
                         || cur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == cur.batteryLevel
@@ -2632,6 +2818,11 @@
         }
     }
 
+    private void requestImmediateCpuUpdate() {
+        mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+        mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+    }
+
     public void setRecordAllHistoryLocked(boolean enabled) {
         mRecordAllHistory = enabled;
         if (!enabled) {
@@ -2823,6 +3014,10 @@
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
+        if (!mOnBatteryInternal) {
+            return -1;
+        }
+
         final int N = mPartialTimers.size();
         if (N == 0) {
             mLastPartialTimers.clear();
@@ -2853,7 +3048,23 @@
         return 0;
     }
 
-    public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
+    public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime,
+            int totalUTime, int totalSTime, int statUserTime, int statSystemTime,
+            int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime,
+            long[] cpuSpeedTimes) {
+        if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
+                + " user=" + statUserTime + " sys=" + statSystemTime
+                + " io=" + statIOWaitTime + " irq=" + statIrqTime
+                + " sirq=" + statSoftIrqTime + " idle=" + statIdleTime);
+        mCurStepCpuUserTime += totalUTime;
+        mCurStepCpuSystemTime += totalSTime;
+        mCurStepStatUserTime += statUserTime;
+        mCurStepStatSystemTime += statSystemTime;
+        mCurStepStatIOWaitTime += statIOWaitTime;
+        mCurStepStatIrqTime += statIrqTime;
+        mCurStepStatSoftIrqTime += statSoftIrqTime;
+        mCurStepStatIdleTime += statIdleTime;
+
         final int N = mPartialTimers.size();
         if (perc != 0) {
             int num = 0;
@@ -2874,26 +3085,24 @@
                     if (st.mInList) {
                         Uid uid = st.mUid;
                         if (uid != null && uid.mUid != Process.SYSTEM_UID) {
-                            int myUTime = utime/num;
-                            int mySTime = stime/num;
-                            utime -= myUTime;
-                            stime -= mySTime;
+                            int myUTime = remainUTime/num;
+                            int mySTime = remainSTtime/num;
+                            remainUTime -= myUTime;
+                            remainSTtime -= mySTime;
                             num--;
                             Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
-                            proc.addCpuTimeLocked(myUTime, mySTime);
-                            proc.addSpeedStepTimes(cpuSpeedTimes);
+                            proc.addCpuTimeLocked(myUTime, mySTime, cpuSpeedTimes);
                         }
                     }
                 }
             }
 
             // Just in case, collect any lost CPU time.
-            if (utime != 0 || stime != 0) {
+            if (remainUTime != 0 || remainSTtime != 0) {
                 Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
                 if (uid != null) {
                     Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
-                    proc.addCpuTimeLocked(utime, stime);
-                    proc.addSpeedStepTimes(cpuSpeedTimes);
+                    proc.addCpuTimeLocked(remainUTime, remainSTtime, cpuSpeedTimes);
                 }
             }
         }
@@ -3019,6 +3228,7 @@
 
     public void noteScreenStateLocked(int state) {
         if (mScreenState != state) {
+            recordDailyStatsIfNeededLocked(true);
             final int oldState = mScreenState;
             mScreenState = state;
             if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
@@ -4109,6 +4319,20 @@
         return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
     }
 
+    @Override public long getBluetoothControllerActivity(int type, int which) {
+        if (type >= 0 && type < mBluetoothActivityCounters.length) {
+            return mBluetoothActivityCounters[type].getCountLocked(which);
+        }
+        return 0;
+    }
+
+    @Override public long getWifiControllerActivity(int type, int which) {
+        if (type >= 0 && type < mWifiActivityCounters.length) {
+            return mWifiActivityCounters[type].getCountLocked(which);
+        }
+        return 0;
+    }
+
     @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) {
         return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -4214,6 +4438,14 @@
         LongSamplingCounter mMobileRadioActiveCount;
 
         /**
+         * The CPU times we had at the last history details update.
+         */
+        long mLastStepUserTime;
+        long mLastStepSystemTime;
+        long mCurStepUserTime;
+        long mCurStepSystemTime;
+
+        /**
          * The statistics we have collected for this uid's wake locks.
          */
         final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
@@ -4543,6 +4775,14 @@
         }
 
         @Override
+        public int getWifiScanCount(int which) {
+            if (mWifiScanTimer == null) {
+                return 0;
+            }
+            return mWifiScanTimer.getCountLocked(which);
+        }
+
+        @Override
         public long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which) {
             if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
             if (mWifiBatchedScanTimer[csphBin] == null) {
@@ -4552,6 +4792,15 @@
         }
 
         @Override
+        public int getWifiBatchedScanCount(int csphBin, int which) {
+            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
+            if (mWifiBatchedScanTimer[csphBin] == null) {
+                return 0;
+            }
+            return mWifiBatchedScanTimer[csphBin].getCountLocked(which);
+        }
+
+        @Override
         public long getWifiMulticastTime(long elapsedRealtimeUs, int which) {
             if (mWifiMulticastTimer == null) {
                 return 0;
@@ -4876,6 +5125,9 @@
                 mPackageStats.clear();
             }
 
+            mLastStepUserTime = mLastStepSystemTime = 0;
+            mCurStepUserTime = mCurStepSystemTime = 0;
+
             if (!active) {
                 if (mWifiRunningTimer != null) {
                     mWifiRunningTimer.detach();
@@ -5392,17 +5644,17 @@
             boolean mActive = true;
 
             /**
-             * Total time (in 1/100 sec) spent executing in user code.
+             * Total time (in ms) spent executing in user code.
              */
             long mUserTime;
 
             /**
-             * Total time (in 1/100 sec) spent executing in kernel code.
+             * Total time (in ms) spent executing in kernel code.
              */
             long mSystemTime;
 
             /**
-             * Amount of time the process was running in the foreground.
+             * Amount of time (in ms) the process was running in the foreground.
              */
             long mForegroundTime;
 
@@ -5678,9 +5930,22 @@
                 return BatteryStatsImpl.this;
             }
 
-            public void addCpuTimeLocked(int utime, int stime) {
+            public void addCpuTimeLocked(int utime, int stime, long[] speedStepBins) {
                 mUserTime += utime;
+                mCurStepUserTime += utime;
                 mSystemTime += stime;
+                mCurStepSystemTime += stime;
+
+                for (int i = 0; i < mSpeedBins.length && i < speedStepBins.length; i++) {
+                    long amt = speedStepBins[i];
+                    if (amt != 0) {
+                        SamplingCounter c = mSpeedBins[i];
+                        if (c == null) {
+                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
+                        }
+                        c.addCountAtomic(speedStepBins[i]);
+                    }
+                }
             }
 
             public void addForegroundTimeLocked(long ttime) {
@@ -5770,20 +6035,6 @@
                 return val;
             }
 
-            /* Called by ActivityManagerService when CPU times are updated. */
-            public void addSpeedStepTimes(long[] values) {
-                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
-                    long amt = values[i];
-                    if (amt != 0) {
-                        SamplingCounter c = mSpeedBins[i];
-                        if (c == null) {
-                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
-                        }
-                        c.addCountAtomic(values[i]);
-                    }
-                }
-            }
-
             @Override
             public long getTimeAtCpuSpeedStep(int speedStep, int which) {
                 if (speedStep < mSpeedBins.length) {
@@ -6404,6 +6655,7 @@
             mFile = null;
         }
         mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
+        mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
         mHandler = new MyHandler(handler.getLooper());
         mStartCount++;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6426,6 +6678,10 @@
             mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
         }
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+        }
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
         mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -6462,11 +6718,13 @@
         mCurrentBatteryLevel = 0;
         initDischarge();
         clearHistoryLocked();
+        updateDailyDeadlineLocked();
     }
 
     public BatteryStatsImpl(Parcel p) {
         mFile = null;
         mCheckinFile = null;
+        mDailyFile = null;
         mHandler = null;
         clearHistoryLocked();
         readFromParcel(p);
@@ -6486,6 +6744,286 @@
         }
     }
 
+    public void updateDailyDeadlineLocked() {
+        // Get the current time.
+        long currentTime = mDailyStartTime = System.currentTimeMillis();
+        Calendar calDeadline = Calendar.getInstance();
+        calDeadline.setTimeInMillis(currentTime);
+
+        // Move time up to the next day, ranging from 1am to 3pm.
+        calDeadline.set(Calendar.DAY_OF_YEAR, calDeadline.get(Calendar.DAY_OF_YEAR) + 1);
+        calDeadline.set(Calendar.MILLISECOND, 0);
+        calDeadline.set(Calendar.SECOND, 0);
+        calDeadline.set(Calendar.MINUTE, 0);
+        calDeadline.set(Calendar.HOUR_OF_DAY, 1);
+        mNextMinDailyDeadline = calDeadline.getTimeInMillis();
+        calDeadline.set(Calendar.HOUR_OF_DAY, 3);
+        mNextMaxDailyDeadline = calDeadline.getTimeInMillis();
+    }
+
+    public void recordDailyStatsIfNeededLocked(boolean settled) {
+        long currentTime = System.currentTimeMillis();
+        if (currentTime >= mNextMaxDailyDeadline) {
+            recordDailyStatsLocked();
+        } else if (settled && currentTime >= mNextMinDailyDeadline) {
+            recordDailyStatsLocked();
+        } else if (currentTime < (mDailyStartTime-(1000*60*60*24))) {
+            recordDailyStatsLocked();
+        }
+    }
+
+    public void recordDailyStatsLocked() {
+        DailyItem item = new DailyItem();
+        item.mStartTime = mDailyStartTime;
+        item.mEndTime = System.currentTimeMillis();
+        boolean hasData = false;
+        if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
+            hasData = true;
+            item.mDischargeSteps = new LevelStepTracker(
+                    mDailyDischargeStepTracker.mNumStepDurations,
+                    mDailyDischargeStepTracker.mStepDurations);
+        }
+        if (mDailyChargeStepTracker.mNumStepDurations > 0) {
+            hasData = true;
+            item.mChargeSteps = new LevelStepTracker(
+                    mDailyChargeStepTracker.mNumStepDurations,
+                    mDailyChargeStepTracker.mStepDurations);
+        }
+        mDailyDischargeStepTracker.init();
+        mDailyChargeStepTracker.init();
+        updateDailyDeadlineLocked();
+
+        if (hasData) {
+            mDailyItems.add(item);
+            while (mDailyItems.size() > MAX_DAILY_ITEMS) {
+                mDailyItems.remove(0);
+            }
+            final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
+            try {
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(memStream, "utf-8");
+                writeDailyItemsLocked(out);
+                BackgroundThread.getHandler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        synchronized (mCheckinFile) {
+                            FileOutputStream stream = null;
+                            try {
+                                stream = mDailyFile.startWrite();
+                                memStream.writeTo(stream);
+                                stream.flush();
+                                FileUtils.sync(stream);
+                                stream.close();
+                                mDailyFile.finishWrite(stream);
+                            } catch (IOException e) {
+                                Slog.w("BatteryStats",
+                                        "Error writing battery daily items", e);
+                                mDailyFile.failWrite(stream);
+                            }
+                        }
+                    }
+                });
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
+        StringBuilder sb = new StringBuilder(64);
+        out.startDocument(null, true);
+        out.startTag(null, "daily-items");
+        for (int i=0; i<mDailyItems.size(); i++) {
+            final DailyItem dit = mDailyItems.get(i);
+            out.startTag(null, "item");
+            out.attribute(null, "start", Long.toString(dit.mStartTime));
+            out.attribute(null, "end", Long.toString(dit.mEndTime));
+            writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
+            writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
+            out.endTag(null, "item");
+        }
+        out.endTag(null, "daily-items");
+        out.endDocument();
+    }
+
+    private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
+            StringBuilder tmpBuilder) throws IOException {
+        if (steps != null) {
+            out.startTag(null, tag);
+            out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
+            for (int i=0; i<steps.mNumStepDurations; i++) {
+                out.startTag(null, "s");
+                tmpBuilder.setLength(0);
+                steps.encodeEntryAt(i, tmpBuilder);
+                out.attribute(null, "v", tmpBuilder.toString());
+                out.endTag(null, "s");
+            }
+            out.endTag(null, tag);
+        }
+    }
+
+    public void readDailyStatsLocked() {
+        Slog.d(TAG, "Reading daily items from " + mDailyFile.getBaseFile());
+        mDailyItems.clear();
+        FileInputStream stream;
+        try {
+            stream = mDailyFile.openRead();
+        } catch (FileNotFoundException e) {
+            return;
+        }
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+            readDailyItemsLocked(parser);
+        } catch (XmlPullParserException e) {
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    private void readDailyItemsLocked(XmlPullParser parser) {
+        try {
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("item")) {
+                    readDailyItemTagLocked(parser);
+                } else {
+                    Slog.w(TAG, "Unknown element under <daily-items>: "
+                            + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+
+        } catch (IllegalStateException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "Failed parsing daily " + e);
+        }
+    }
+
+    void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        DailyItem dit = new DailyItem();
+        String attr = parser.getAttributeValue(null, "start");
+        if (attr != null) {
+            dit.mStartTime = Long.parseLong(attr);
+        }
+        attr = parser.getAttributeValue(null, "end");
+        if (attr != null) {
+            dit.mEndTime = Long.parseLong(attr);
+        }
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("dis")) {
+                readDailyItemTagDetailsLocked(parser, dit, false, "dis");
+            } else if (tagName.equals("chg")) {
+                readDailyItemTagDetailsLocked(parser, dit, true, "chg");
+            } else {
+                Slog.w(TAG, "Unknown element under <item>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+        mDailyItems.add(dit);
+    }
+
+    void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
+            String tag)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        final String numAttr = parser.getAttributeValue(null, "n");
+        if (numAttr == null) {
+            Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
+            XmlUtils.skipCurrentTag(parser);
+            return;
+        }
+        final int num = Integer.parseInt(numAttr);
+        LevelStepTracker steps = new LevelStepTracker(num);
+        if (isCharge) {
+            dit.mChargeSteps = steps;
+        } else {
+            dit.mDischargeSteps = steps;
+        }
+        int i = 0;
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if ("s".equals(tagName)) {
+                if (i < num) {
+                    String valueAttr = parser.getAttributeValue(null, "v");
+                    if (valueAttr != null) {
+                        steps.decodeEntryAt(i, valueAttr);
+                        i++;
+                    }
+                }
+            } else {
+                Slog.w(TAG, "Unknown element under <" + tag + ">: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+        steps.mNumStepDurations = i;
+    }
+
+    @Override
+    public DailyItem getDailyItemLocked(int daysAgo) {
+        int index = mDailyItems.size()-1-daysAgo;
+        return index >= 0 ? mDailyItems.get(index) : null;
+    }
+
+    @Override
+    public long getCurrentDailyStartTime() {
+        return mDailyStartTime;
+    }
+
+    @Override
+    public long getNextMinDailyDeadline() {
+        return mNextMinDailyDeadline;
+    }
+
+    @Override
+    public long getNextMaxDailyDeadline() {
+        return mNextMaxDailyDeadline;
+    }
+
     @Override
     public boolean startIteratingOldHistoryLocked() {
         if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
@@ -6656,10 +7194,8 @@
         mDischargeAmountScreenOnSinceCharge = 0;
         mDischargeAmountScreenOff = 0;
         mDischargeAmountScreenOffSinceCharge = 0;
-        mLastDischargeStepTime = -1;
-        mNumDischargeStepDurations = 0;
-        mLastChargeStepTime = -1;
-        mNumChargeStepDurations = 0;
+        mDischargeStepTracker.init();
+        mChargeStepTracker.init();
     }
 
     public void resetAllStatsCmdLocked() {
@@ -6733,6 +7269,10 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].reset(false);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].reset(false);
+            mWifiActivityCounters[i].reset(false);
+        }
         mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
@@ -6756,6 +7296,18 @@
             mWakeupReasonStats.clear();
         }
 
+        mLastHistoryStepDetails = null;
+        mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
+        mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
+        mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
+        mLastStepStatUserTime = mCurStepStatUserTime = 0;
+        mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
+        mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
+        mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
+
         initDischarge();
 
         clearHistoryLocked();
@@ -6807,6 +7359,9 @@
     public void pullPendingStateUpdatesLocked() {
         updateKernelWakelocksLocked();
         updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
+        // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786
+        // updateBluetoothControllerActivityLocked();
+        updateWifiControllerActivityLocked();
         if (mOnBatteryInternal) {
             final boolean screenOn = mScreenState == Display.STATE_ON;
             updateDischargeScreenLevelsLocked(screenOn, screenOn);
@@ -6870,12 +7425,13 @@
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
                 reset = true;
-                mNumDischargeStepDurations = 0;
+                mDischargeStepTracker.init();
             }
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = true;
             mLastDischargeStepLevel = level;
             mMinDischargeStepLevel = level;
-            mLastDischargeStepTime = -1;
+            mDischargeStepTracker.clearTime();
+            mDailyDischargeStepTracker.clearTime();
             mInitStepMode = mCurStepMode;
             mModStepMode = 0;
             pullPendingStateUpdatesLocked();
@@ -6900,7 +7456,7 @@
             mDischargeAmountScreenOff = 0;
             updateTimeBasesLocked(true, !screenOn, uptime, realtime);
         } else {
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = false;
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
@@ -6914,10 +7470,9 @@
             }
             updateDischargeScreenLevelsLocked(screenOn, screenOn);
             updateTimeBasesLocked(false, !screenOn, uptime, realtime);
-            mNumChargeStepDurations = 0;
+            mChargeStepTracker.init();
             mLastChargeStepLevel = level;
             mMaxChargeStepLevel = level;
-            mLastChargeStepTime = -1;
             mInitStepMode = mCurStepMode;
             mModStepMode = 0;
         }
@@ -6969,34 +7524,12 @@
     // This should probably be exposed in the API, though it's not critical
     private static final int BATTERY_PLUGGED_NONE = 0;
 
-    private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
-            int numStepLevels, long modeBits, long elapsedRealtime) {
-        if (lastStepTime >= 0 && numStepLevels > 0) {
-            long duration = elapsedRealtime - lastStepTime;
-            for (int i=0; i<numStepLevels; i++) {
-                System.arraycopy(steps, 0, steps, 1, steps.length-1);
-                long thisDuration = duration / (numStepLevels-i);
-                duration -= thisDuration;
-                if (thisDuration > STEP_LEVEL_TIME_MASK) {
-                    thisDuration = STEP_LEVEL_TIME_MASK;
-                }
-                steps[0] = thisDuration | modeBits;
-            }
-            stepCount += numStepLevels;
-            if (stepCount > steps.length) {
-                stepCount = steps.length;
-            }
-        }
-        return stepCount;
-    }
-
     public void setBatteryState(int status, int health, int plugType, int level,
             int temp, int volt) {
         synchronized(this) {
             final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
             final long uptime = SystemClock.uptimeMillis();
             final long elapsedRealtime = SystemClock.elapsedRealtime();
-            int oldStatus = mHistoryCur.batteryStatus;
             if (!mHaveBatteryLevel) {
                 mHaveBatteryLevel = true;
                 // We start out assuming that the device is plugged in (not
@@ -7010,8 +7543,14 @@
                         mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
                     }
                 }
-                oldStatus = status;
+                mHistoryCur.batteryStatus = (byte)status;
+                mHistoryCur.batteryLevel = (byte)level;
+                mMaxChargeStepLevel = mMinDischargeStepLevel =
+                        mLastChargeStepLevel = mLastDischargeStepLevel = level;
+            } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
+                recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
             }
+            int oldStatus = mHistoryCur.batteryStatus;
             if (onBattery) {
                 mDischargeCurrentLevel = level;
                 if (!mRecordingHistory) {
@@ -7072,23 +7611,23 @@
                         | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
                 if (onBattery) {
                     if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
-                        mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
-                                mNumDischargeStepDurations, mLastDischargeStepTime,
-                                mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
+                        mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+                                modeBits, elapsedRealtime);
+                        mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+                                modeBits, elapsedRealtime);
                         mLastDischargeStepLevel = level;
                         mMinDischargeStepLevel = level;
-                        mLastDischargeStepTime = elapsedRealtime;
                         mInitStepMode = mCurStepMode;
                         mModStepMode = 0;
                     }
                 } else {
                     if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
-                        mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
-                                mNumChargeStepDurations, mLastChargeStepTime,
-                                level - mLastChargeStepLevel, modeBits, elapsedRealtime);
+                        mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+                                modeBits, elapsedRealtime);
+                        mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+                                modeBits, elapsedRealtime);
                         mLastChargeStepLevel = level;
                         mMaxChargeStepLevel = level;
-                        mLastChargeStepTime = elapsedRealtime;
                         mInitStepMode = mCurStepMode;
                         mModStepMode = 0;
                     }
@@ -7259,6 +7798,65 @@
         }
     }
 
+    private void updateBluetoothControllerActivityLocked() {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter == null) {
+            return;
+        }
+
+        // We read the data even if we are not on battery. Each read clears
+        // the previous data, so we must always read to make sure the
+        // data is for the current interval.
+        BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
+                BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
+        if (info == null || !info.isValid() || !mOnBatteryInternal) {
+            // Bad info or we are not on battery.
+            return;
+        }
+
+        mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+                info.getControllerRxTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+                info.getControllerTxTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+                info.getControllerIdleTimeMillis());
+        mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+                info.getControllerEnergyUsed());
+    }
+
+    private void updateWifiControllerActivityLocked() {
+        IWifiManager wifiManager = IWifiManager.Stub.asInterface(
+                ServiceManager.getService(Context.WIFI_SERVICE));
+        if (wifiManager == null) {
+            return;
+        }
+
+        WifiActivityEnergyInfo info;
+        try {
+            // We read the data even if we are not on battery. Each read clears
+            // the previous data, so we must always read to make sure the
+            // data is for the current interval.
+            info = wifiManager.reportActivityInfo();
+        } catch (RemoteException e) {
+            // Nothing to report, WiFi is dead.
+            return;
+        }
+
+        if (info == null || !info.isValid() || !mOnBatteryInternal) {
+            // Bad info or we are not on battery.
+            return;
+        }
+
+        mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+                info.getControllerRxTimeMillis());
+        mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+                info.getControllerTxTimeMillis());
+        mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+                info.getControllerIdleTimeMillis());
+        mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+                info.getControllerEnergyUsed());
+    }
+
     public long getAwakeTimeBattery() {
         return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
     }
@@ -7363,22 +7961,24 @@
         long usPerLevel = duration/discharge;
         return usPerLevel * mCurrentBatteryLevel;
         */
-        if (mNumDischargeStepDurations < 1) {
+        if (mDischargeStepTracker.mNumStepDurations < 1) {
             return -1;
         }
-        long msPerLevel = computeTimePerLevel(mDischargeStepDurations, mNumDischargeStepDurations);
+        long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
         if (msPerLevel <= 0) {
             return -1;
         }
         return (msPerLevel * mCurrentBatteryLevel) * 1000;
     }
 
-    public int getNumDischargeStepDurations() {
-        return mNumDischargeStepDurations;
+    @Override
+    public LevelStepTracker getDischargeLevelStepTracker() {
+        return mDischargeStepTracker;
     }
 
-    public long[] getDischargeStepDurationsArray() {
-        return mDischargeStepDurations;
+    @Override
+    public LevelStepTracker getDailyDischargeLevelStepTracker() {
+        return mDailyDischargeStepTracker;
     }
 
     @Override
@@ -7400,22 +8000,24 @@
         long usPerLevel = duration/(curLevel-plugLevel);
         return usPerLevel * (100-curLevel);
         */
-        if (mNumChargeStepDurations < 1) {
+        if (mChargeStepTracker.mNumStepDurations < 1) {
             return -1;
         }
-        long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);
+        long msPerLevel = mChargeStepTracker.computeTimePerLevel();
         if (msPerLevel <= 0) {
             return -1;
         }
         return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
     }
 
-    public int getNumChargeStepDurations() {
-        return mNumChargeStepDurations;
+    @Override
+    public LevelStepTracker getChargeLevelStepTracker() {
+        return mChargeStepTracker;
     }
 
-    public long[] getChargeStepDurationsArray() {
-        return mChargeStepDurations;
+    @Override
+    public LevelStepTracker getDailyChargeLevelStepTracker() {
+        return mDailyChargeStepTracker;
     }
 
     long getBatteryUptimeLocked() {
@@ -7713,6 +8315,10 @@
     }
 
     public void readLocked() {
+        if (mDailyFile != null) {
+            readDailyStatsLocked();
+        }
+
         if (mFile == null) {
             Slog.w("BatteryStats", "readLocked: no file associated with this instance");
             return;
@@ -7750,6 +8356,8 @@
             addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
             startRecordingHistory(elapsedRealtime, uptime, false);
         }
+
+        recordDailyStatsIfNeededLocked(false);
     }
 
     public int describeContents() {
@@ -7908,10 +8516,13 @@
         mHighDischargeAmountSinceCharge = in.readInt();
         mDischargeAmountScreenOnSinceCharge = in.readInt();
         mDischargeAmountScreenOffSinceCharge = in.readInt();
-        mNumDischargeStepDurations = in.readInt();
-        in.readLongArray(mDischargeStepDurations);
-        mNumChargeStepDurations = in.readInt();
-        in.readLongArray(mChargeStepDurations);
+        mDischargeStepTracker.readFromParcel(in);
+        mChargeStepTracker.readFromParcel(in);
+        mDailyDischargeStepTracker.readFromParcel(in);
+        mDailyChargeStepTracker.readFromParcel(in);
+        mDailyStartTime = in.readLong();
+        mNextMinDailyDeadline = in.readLong();
+        mNextMaxDailyDeadline = in.readLong();
 
         mStartCount++;
 
@@ -7960,6 +8571,15 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
         }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
+        }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
+        }
+
         mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
         mFlashlightOn = false;
         mFlashlightOnTimer.readSummaryFromParcelLocked(in);
@@ -8202,10 +8822,13 @@
         out.writeInt(getHighDischargeAmountSinceCharge());
         out.writeInt(getDischargeAmountScreenOnSinceCharge());
         out.writeInt(getDischargeAmountScreenOffSinceCharge());
-        out.writeInt(mNumDischargeStepDurations);
-        out.writeLongArray(mDischargeStepDurations);
-        out.writeInt(mNumChargeStepDurations);
-        out.writeLongArray(mChargeStepDurations);
+        mDischargeStepTracker.writeToParcel(out);
+        mChargeStepTracker.writeToParcel(out);
+        mDailyDischargeStepTracker.writeToParcel(out);
+        mDailyChargeStepTracker.writeToParcel(out);
+        out.writeLong(mDailyStartTime);
+        out.writeLong(mNextMinDailyDeadline);
+        out.writeLong(mNextMaxDailyDeadline);
 
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -8245,6 +8868,12 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
+        }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
+        }
         out.writeInt(mNumConnectivityChange);
         mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
 
@@ -8549,6 +9178,15 @@
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mOnBatteryTimeBase, in);
         }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        }
+
+        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        }
+
         mNumConnectivityChange = in.readInt();
         mLoadedNumConnectivityChange = in.readInt();
         mUnpluggedNumConnectivityChange = in.readInt();
@@ -8568,10 +9206,8 @@
         mDischargeAmountScreenOnSinceCharge = in.readInt();
         mDischargeAmountScreenOff = in.readInt();
         mDischargeAmountScreenOffSinceCharge = in.readInt();
-        mNumDischargeStepDurations = in.readInt();
-        in.readLongArray(mDischargeStepDurations);
-        mNumChargeStepDurations = in.readInt();
-        in.readLongArray(mChargeStepDurations);
+        mDischargeStepTracker.readFromParcel(in);
+        mChargeStepTracker.readFromParcel(in);
         mLastWriteTime = in.readLong();
 
         mBluetoothPingCount = in.readInt();
@@ -8696,6 +9332,12 @@
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
         }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mBluetoothActivityCounters[i].writeToParcel(out);
+        }
+        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+            mWifiActivityCounters[i].writeToParcel(out);
+        }
         out.writeInt(mNumConnectivityChange);
         out.writeInt(mLoadedNumConnectivityChange);
         out.writeInt(mUnpluggedNumConnectivityChange);
@@ -8710,10 +9352,8 @@
         out.writeInt(mDischargeAmountScreenOnSinceCharge);
         out.writeInt(mDischargeAmountScreenOff);
         out.writeInt(mDischargeAmountScreenOffSinceCharge);
-        out.writeInt(mNumDischargeStepDurations);
-        out.writeLongArray(mDischargeStepDurations);
-        out.writeInt(mNumChargeStepDurations);
-        out.writeLongArray(mChargeStepDurations);
+        mDischargeStepTracker.writeToParcel(out);
+        mChargeStepTracker.writeToParcel(out);
         out.writeLong(mLastWriteTime);
 
         out.writeInt(getBluetoothPingCount());
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 2f30ebc..433a54b 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -91,11 +91,11 @@
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false);
+        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false);
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode) {
+            String instructionSet, boolean vmSafeMode, boolean debuggable) {
         StringBuilder builder = new StringBuilder("dexopt");
         builder.append(' ');
         builder.append(apkPath);
@@ -106,8 +106,8 @@
         builder.append(pkgName);
         builder.append(' ');
         builder.append(instructionSet);
-        builder.append(' ');
         builder.append(vmSafeMode ? " 1" : " 0");
+        builder.append(debuggable ? " 1" : " 0");
         return execute(builder.toString());
     }
 
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index b3bafa1..944eb5a 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -76,6 +76,11 @@
     public static final String POWER_WIFI_ACTIVE = "wifi.active";
 
     /**
+     * Operating voltage of the WiFi controller.
+     */
+    public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage";
+
+    /**
      * Power consumption when GPS is on.
      */
     public static final String POWER_GPS_ON = "gps.on";
@@ -96,6 +101,11 @@
     public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
 
     /**
+     * Operating voltage of the Bluetooth controller.
+     */
+    public static final String OPERATING_VOLTAGE_BLUETOOTH = "bluetooth.voltage";
+
+    /**
      * Power consumption when screen is on, not including the backlight power.
      */
     public static final String POWER_SCREEN_ON = "screen.on";
@@ -224,11 +234,13 @@
     }
 
     /**
-     * Returns the average current in mA consumed by the subsystem 
+     * Returns the average current in mA consumed by the subsystem, or the given
+     * default value if the subsystem has no recorded value.
      * @param type the subsystem type
+     * @param defaultValue the value to return if the subsystem has no recorded value.
      * @return the average current in milliAmps.
      */
-    public double getAveragePower(String type) {
+    public double getAveragePowerOrDefault(String type, double defaultValue) {
         if (sPowerMap.containsKey(type)) {
             Object data = sPowerMap.get(type);
             if (data instanceof Double[]) {
@@ -237,9 +249,18 @@
                 return (Double) sPowerMap.get(type);
             }
         } else {
-            return 0;
+            return defaultValue;
         }
     }
+
+    /**
+     * Returns the average current in mA consumed by the subsystem
+     * @param type the subsystem type
+     * @return the average current in milliAmps.
+     */
+    public double getAveragePower(String type) {
+        return getAveragePowerOrDefault(type, 0);
+    }
     
     /**
      * Returns the average current in mA consumed by the subsystem for the given level.
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index b5338df..2983047 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -22,11 +22,13 @@
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.system.OsConstants;
 import android.util.Slog;
 
 import com.android.internal.util.FastPrintWriter;
 
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -130,6 +132,9 @@
 
     private final boolean mIncludeThreads;
 
+    // How long a CPU jiffy is in milliseconds.
+    private final long mJiffyMillis;
+
     private float mLoad1 = 0;
     private float mLoad5 = 0;
     private float mLoad15 = 0;
@@ -152,6 +157,7 @@
     private int mRelIrqTime;
     private int mRelSoftIrqTime;
     private int mRelIdleTime;
+    private boolean mRelStatsAreGood;
 
     private int[] mCurPids;
     private int[] mCurThreadPids;
@@ -268,6 +274,8 @@
 
     public ProcessCpuTracker(boolean includeThreads) {
         mIncludeThreads = includeThreads;
+        long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+        mJiffyMillis = 1000/jiffyHz;
     }
 
     public void onLoadChanged(float load1, float load5, float load15) {
@@ -285,49 +293,72 @@
 
     public void update() {
         if (DEBUG) Slog.v(TAG, "Update: " + this);
-        mLastSampleTime = mCurrentSampleTime;
-        mCurrentSampleTime = SystemClock.uptimeMillis();
-        mLastSampleRealTime = mCurrentSampleRealTime;
-        mCurrentSampleRealTime = SystemClock.elapsedRealtime();
+
+        final long nowUptime = SystemClock.uptimeMillis();
+        final long nowRealtime = SystemClock.elapsedRealtime();
 
         final long[] sysCpu = mSystemCpuData;
         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
                 null, sysCpu, null)) {
             // Total user time is user + nice time.
-            final long usertime = sysCpu[0]+sysCpu[1];
+            final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis;
             // Total system time is simply system time.
-            final long systemtime = sysCpu[2];
+            final long systemtime = sysCpu[2] * mJiffyMillis;
             // Total idle time is simply idle time.
-            final long idletime = sysCpu[3];
+            final long idletime = sysCpu[3] * mJiffyMillis;
             // Total irq time is iowait + irq + softirq time.
-            final long iowaittime = sysCpu[4];
-            final long irqtime = sysCpu[5];
-            final long softirqtime = sysCpu[6];
+            final long iowaittime = sysCpu[4] * mJiffyMillis;
+            final long irqtime = sysCpu[5] * mJiffyMillis;
+            final long softirqtime = sysCpu[6] * mJiffyMillis;
 
-            mRelUserTime = (int)(usertime - mBaseUserTime);
-            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
-            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
-            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
-            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
-            mRelIdleTime = (int)(idletime - mBaseIdleTime);
+            // This code is trying to avoid issues with idle time going backwards,
+            // but currently it gets into situations where it triggers most of the time. :(
+            if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime
+                    && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime
+                    && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) {
+                mRelUserTime = (int)(usertime - mBaseUserTime);
+                mRelSystemTime = (int)(systemtime - mBaseSystemTime);
+                mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
+                mRelIrqTime = (int)(irqtime - mBaseIrqTime);
+                mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
+                mRelIdleTime = (int)(idletime - mBaseIdleTime);
+                mRelStatsAreGood = true;
 
-            if (DEBUG) {
-                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
-                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
-                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
-                      + " O:" + sysCpu[6]);
-                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
-                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                if (DEBUG) {
+                    Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis)
+                          + " N:" + (sysCpu[1]*mJiffyMillis)
+                          + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis)
+                          + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis)
+                          + " O:" + (sysCpu[6]*mJiffyMillis));
+                    Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
+                          + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                }
+
+                mBaseUserTime = usertime;
+                mBaseSystemTime = systemtime;
+                mBaseIoWaitTime = iowaittime;
+                mBaseIrqTime = irqtime;
+                mBaseSoftIrqTime = softirqtime;
+                mBaseIdleTime = idletime;
+
+            } else {
+                mRelUserTime = 0;
+                mRelSystemTime = 0;
+                mRelIoWaitTime = 0;
+                mRelIrqTime = 0;
+                mRelSoftIrqTime = 0;
+                mRelIdleTime = 0;
+                mRelStatsAreGood = false;
+                Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
+                return;
             }
-
-            mBaseUserTime = usertime;
-            mBaseSystemTime = systemtime;
-            mBaseIoWaitTime = iowaittime;
-            mBaseIrqTime = irqtime;
-            mBaseSoftIrqTime = softirqtime;
-            mBaseIdleTime = idletime;
         }
 
+        mLastSampleTime = mCurrentSampleTime;
+        mCurrentSampleTime = nowUptime;
+        mLastSampleRealTime = mCurrentSampleRealTime;
+        mCurrentSampleRealTime = nowRealtime;
+
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
             mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
@@ -391,8 +422,8 @@
 
                     final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
                     final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
-                    final long utime = procStats[PROCESS_STAT_UTIME];
-                    final long stime = procStats[PROCESS_STAT_STIME];
+                    final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis;
+                    final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis;
 
                     if (utime == st.base_utime && stime == st.base_stime) {
                         st.rel_utime = 0;
@@ -466,8 +497,8 @@
                         st.baseName = procStatsString[0];
                         st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
                         st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
-                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
-                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
+                        st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis;
+                        st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis;
                     } else {
                         Slog.i(TAG, "Skipping kernel process pid " + pid
                                 + " name " + procStatsString[0]);
@@ -553,7 +584,7 @@
                     null, statsData, null)) {
                 long time = statsData[PROCESS_STAT_UTIME]
                         + statsData[PROCESS_STAT_STIME];
-                return time;
+                return time * mJiffyMillis;
             }
             return 0;
         }
@@ -647,6 +678,10 @@
         return mRelIdleTime;
     }
 
+    final public boolean hasGoodLastStats() {
+        return mRelStatsAreGood;
+    }
+
     final public float getTotalCpuPercent() {
         int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
         if (denom <= 0) {
@@ -750,7 +785,7 @@
         for (int i=0; i<N; i++) {
             Stats st = mWorkingProcs.get(i);
             printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
-                    st.pid, st.name, (int)(st.rel_uptime+5)/10,
+                    st.pid, st.name, (int)st.rel_uptime,
                     st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
             if (!st.removed && st.workingThreads != null) {
                 int M = st.workingThreads.size();
@@ -758,7 +793,7 @@
                     Stats tst = st.workingThreads.get(j);
                     printProcessCPU(pw,
                             tst.added ? "   +" : (tst.removed ? "   -": "    "),
-                            tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
+                            tst.pid, tst.name, (int)st.rel_uptime,
                             tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
                 }
             }
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 29ccb6a..2539a35 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -233,6 +233,7 @@
     }
 
     public static final void main(String[] argv) {
+        enableDdms();
         if (argv.length == 2 && argv[1].equals("application")) {
             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
             redirectLogStreams();
@@ -365,9 +366,9 @@
     }
 
     /**
-     * Enable debugging features.
+     * Enable DDMS.
      */
-    static {
+    static final void enableDdms() {
         // Register handlers for DDM messages.
         android.ddm.DdmRegister.registerHandlers();
     }
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 3301cbe..34ae58a 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -19,6 +19,7 @@
 import android.os.Process;
 import android.util.Slog;
 
+import dalvik.system.VMRuntime;
 import java.io.DataOutputStream;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -62,7 +63,8 @@
             // wrapper that it directly forked).
             if (fdNum != 0) {
                 try {
-                    FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum);
+                    FileDescriptor fd = new FileDescriptor();
+                    fd.setInt$(fdNum);
                     DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
                     os.writeInt(Process.myPid());
                     os.close();
@@ -95,9 +97,20 @@
      * @param args Arguments for {@link RuntimeInit#main}.
      */
     public static void execApplication(String invokeWith, String niceName,
-            int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
+            int targetSdkVersion, String instructionSet, FileDescriptor pipeFd,
+            String[] args) {
         StringBuilder command = new StringBuilder(invokeWith);
-        command.append(" /system/bin/app_process /system/bin --application");
+
+        final String appProcess;
+        if (VMRuntime.is64BitInstructionSet(instructionSet)) {
+            appProcess = "/system/bin/app_process64";
+        } else {
+            appProcess = "/system/bin/app_process32";
+        }
+        command.append(' ');
+        command.append(appProcess);
+
+        command.append(" /system/bin --application");
         if (niceName != null) {
             command.append(" '--nice-name=").append(niceName).append("'");
         }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index cca340c..fced092 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -20,12 +20,9 @@
 import dalvik.system.ZygoteHooks;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.os.SystemClock;
-import android.util.Slog;
 
 /** @hide */
 public final class Zygote {
-    private static final String TAG = "Zygote";
     /*
     * Bit values for "debugFlags" argument.  The definitions are duplicated
     * in the native code.
@@ -87,15 +84,11 @@
     public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
           int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
           String instructionSet, String appDataDir) {
-        long startTime = SystemClock.elapsedRealtime();
         VM_HOOKS.preFork();
-        checkTime(startTime, "Zygote.preFork");
         int pid = nativeForkAndSpecialize(
                   uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                   instructionSet, appDataDir);
-        checkTime(startTime, "Zygote.nativeForkAndSpecialize");
         VM_HOOKS.postForkCommon();
-        checkTime(startTime, "Zygote.postForkCommon");
         return pid;
     }
 
@@ -104,18 +97,6 @@
           String instructionSet, String appDataDir);
 
     /**
-     * Temporary hack: check time since start time and log if over a fixed threshold.
-     *
-     */
-    private static void checkTime(long startTime, String where) {
-        long now = SystemClock.elapsedRealtime();
-        if ((now-startTime) > 1000) {
-            // If we are taking more than a second, log about it.
-            Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
-        }
-    }
-
-    /**
      * Special method to start the system server process. In addition to the
      * common actions performed in forkAndSpecialize, the pid of the child
      * process is recorded such that the death of the child process will cause
@@ -151,9 +132,7 @@
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
     private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
-        long startTime = SystemClock.elapsedRealtime();
         VM_HOOKS.postForkChild(debugFlags, instructionSet);
-        checkTime(startTime, "Zygote.callPostForkChildHooks");
     }
 
 
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4548221..7acd8f5 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -16,6 +16,12 @@
 
 package com.android.internal.os;
 
+import static android.system.OsConstants.F_SETFD;
+import static android.system.OsConstants.O_CLOEXEC;
+import static android.system.OsConstants.STDERR_FILENO;
+import static android.system.OsConstants.STDIN_FILENO;
+import static android.system.OsConstants.STDOUT_FILENO;
+
 import android.net.Credentials;
 import android.net.LocalSocket;
 import android.os.Process;
@@ -24,7 +30,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Log;
-import dalvik.system.PathClassLoader;
+import dalvik.system.VMRuntime;
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -37,8 +43,6 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import libcore.io.IoUtils;
-import android.os.SystemClock;
-import android.util.Slog;
 
 /**
  * A connection that can make spawn requests.
@@ -72,7 +76,6 @@
     private final DataOutputStream mSocketOutStream;
     private final BufferedReader mSocketReader;
     private final Credentials peer;
-    private final String peerSecurityContext;
     private final String abiList;
 
     /**
@@ -100,20 +103,6 @@
             Log.e(TAG, "Cannot read peer credentials", ex);
             throw ex;
         }
-
-        peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
-    }
-
-    /**
-     * Temporary hack: check time since start time and log if over a fixed threshold.
-     *
-     */
-    private void checkTime(long startTime, String where) {
-        long now = SystemClock.elapsedRealtime();
-        if ((now-startTime) > 1000) {
-            // If we are taking more than a second, log about it.
-            Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
-        }
     }
 
     /**
@@ -121,7 +110,7 @@
      *
      * @return null-ok; file descriptor
      */
-    FileDescriptor getFileDescriptor() {
+    FileDescriptor getFileDesciptor() {
         return mSocket.getFileDescriptor();
     }
 
@@ -145,8 +134,6 @@
         Arguments parsedArgs = null;
         FileDescriptor[] descriptors;
 
-        long startTime = SystemClock.elapsedRealtime();
-
         try {
             args = readArgumentList();
             descriptors = mSocket.getAncillaryFileDescriptors();
@@ -156,7 +143,6 @@
             return true;
         }
 
-        checkTime(startTime, "zygoteConnection.runOnce: readArgumentList");
         if (args == null) {
             // EOF reached.
             closeSocket();
@@ -188,30 +174,23 @@
                         ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
             }
 
-
-            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-
-            checkTime(startTime, "zygoteConnection.runOnce: apply security policies");
+            applyUidSecurityPolicy(parsedArgs, peer);
+            applyInvokeWithSecurityPolicy(parsedArgs, peer);
 
             applyDebuggerSystemProperty(parsedArgs);
             applyInvokeWithSystemProperty(parsedArgs);
 
-            checkTime(startTime, "zygoteConnection.runOnce: apply security policies");
-
             int[][] rlimits = null;
 
             if (parsedArgs.rlimits != null) {
                 rlimits = parsedArgs.rlimits.toArray(intArray2d);
             }
 
-            if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
-                FileDescriptor[] pipeFds = Os.pipe();
+            if (parsedArgs.invokeWith != null) {
+                FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                 childPipeFd = pipeFds[1];
                 serverPipeFd = pipeFds[0];
-                ZygoteInit.setCloseOnExec(serverPipeFd, true);
+                Os.fcntlInt(childPipeFd, F_SETFD, 0);
             }
 
             /**
@@ -242,14 +221,10 @@
 
             fd = null;
 
-            checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize");
             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                     parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                     parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                     parsedArgs.appDataDir);
-            checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize");
-        } catch (IOException ex) {
-            logAndPrintError(newStderr, "Exception creating pipe", ex);
         } catch (ErrnoException ex) {
             logAndPrintError(newStderr, "Exception creating pipe", ex);
         } catch (IllegalArgumentException ex) {
@@ -323,20 +298,13 @@
      *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
      *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
      *    are the settings for current and max value.</i>
-     *   <li> --classpath=<i>colon-separated classpath</i> indicates
-     * that the specified class (which must b first non-flag argument) should
-     * be loaded from jar files in the specified classpath. Incompatible with
-     * --runtime-init
-     *   <li> --runtime-init indicates that the remaining arg list should
-     * be handed off to com.android.internal.os.RuntimeInit, rather than
-     * processed directly
-     * Android runtime startup (eg, Binder initialization) is also eschewed.
-     *   <li> --nice-name=<i>nice name to appear in ps</i>
-     *   <li> If <code>--runtime-init</code> is present:
-     *      [--] &lt;args for RuntimeInit &gt;
-     *   <li> If <code>--runtime-init</code> is absent:
-     *      [--] &lt;classname&gt; [args...]
      *   <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
+     *   <li> --nice-name=<i>nice name to appear in ps</i>
+     *   <li> --runtime-args indicates that the remaining arg list should
+     * be handed off to com.android.internal.os.RuntimeInit, rather than
+     * processed directly.
+     * Android runtime startup (eg, Binder initialization) is also eschewed.
+     *   <li> [--] &lt;args for RuntimeInit &gt;
      * </ul>
      */
     static class Arguments {
@@ -364,12 +332,6 @@
         int targetSdkVersion;
         boolean targetSdkVersionSpecified;
 
-        /** from --classpath */
-        String classpath;
-
-        /** from --runtime-init */
-        boolean runtimeInit;
-
         /** from --nice-name */
         String niceName;
 
@@ -431,6 +393,8 @@
                 throws IllegalArgumentException {
             int curArg = 0;
 
+            boolean seenRuntimeArgs = false;
+
             for ( /* curArg */ ; curArg < args.length; curArg++) {
                 String arg = args[curArg];
 
@@ -471,8 +435,8 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
                 } else if (arg.equals("--enable-assert")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
-                } else if (arg.equals("--runtime-init")) {
-                    runtimeInit = true;
+                } else if (arg.equals("--runtime-args")) {
+                    seenRuntimeArgs = true;
                 } else if (arg.startsWith("--seinfo=")) {
                     if (seInfoSpecified) {
                         throw new IllegalArgumentException(
@@ -517,17 +481,6 @@
                     }
 
                     rlimits.add(rlimitTuple);
-                } else if (arg.equals("-classpath")) {
-                    if (classpath != null) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    try {
-                        classpath = args[++curArg];
-                    } catch (IndexOutOfBoundsException ex) {
-                        throw new IllegalArgumentException(
-                                "-classpath requires argument");
-                    }
                 } else if (arg.startsWith("--setgroups=")) {
                     if (gids != null) {
                         throw new IllegalArgumentException(
@@ -574,15 +527,18 @@
                 }
             }
 
-            if (runtimeInit && classpath != null) {
-                throw new IllegalArgumentException(
-                        "--runtime-init and -classpath are incompatible");
+            if (abiListQuery) {
+                if (args.length - curArg > 0) {
+                    throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
+                }
+            } else {
+                if (!seenRuntimeArgs) {
+                    throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+                }
+
+                remainingArgs = new String[args.length - curArg];
+                System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
             }
-
-            remainingArgs = new String[args.length - curArg];
-
-            System.arraycopy(args, curArg, remainingArgs, 0,
-                    remainingArgs.length);
         }
     }
 
@@ -637,63 +593,30 @@
     }
 
     /**
-     * Applies zygote security policy per bugs #875058 and #1082165.
-     * Based on the credentials of the process issuing a zygote command:
-     * <ol>
-     * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
-     * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
+     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
      * operation. It may also specify any gid and setgroups() list it chooses.
      * In factory test mode, it may specify any UID.
-     * <li> Any other uid may not specify any uid, gid, or setgroups list. The
-     * uid and gid will be inherited from the requesting process.
-     * </ul>
      *
      * @param args non-null; zygote spawner arguments
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
 
-        int peerUid = peer.getUid();
-
-        if (peerUid == 0) {
-            // Root can do what it wants
-        } else if (peerUid == Process.SYSTEM_UID ) {
-            // System UID is restricted, except in factory test mode
+        if (peer.getUid() == Process.SYSTEM_UID) {
             String factoryTest = SystemProperties.get("ro.factorytest");
             boolean uidRestricted;
 
             /* In normal operation, SYSTEM_UID can only specify a restricted
              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
              */
-            uidRestricted
-                 = !(factoryTest.equals("1") || factoryTest.equals("2"));
+            uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2"));
 
-            if (uidRestricted
-                    && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
+            if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
                 throw new ZygoteSecurityException(
                         "System UID may not launch process with UID < "
-                                + Process.SYSTEM_UID);
-            }
-        } else {
-            // Everything else
-            if (args.uidSpecified || args.gidSpecified
-                || args.gids != null) {
-                throw new ZygoteSecurityException(
-                        "App UIDs may not specify uid's or gid's");
-            }
-        }
-
-        if (args.uidSpecified || args.gidSpecified || args.gids != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyids");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify uid's or gid's");
+                        + Process.SYSTEM_UID);
             }
         }
 
@@ -708,7 +631,6 @@
         }
     }
 
-
     /**
      * Applies debugger system properties to the zygote arguments.
      *
@@ -725,44 +647,6 @@
     }
 
     /**
-     * Applies zygote security policy per bug #1042973. Based on the credentials
-     * of the process issuing a zygote command:
-     * <ol>
-     * <li> peers of  uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
-     * may specify any rlimits.
-     * <li> All other uids may not specify rlimits.
-     * </ul>
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyRlimitSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-
-        int peerUid = peer.getUid();
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            if (args.rlimits != null) {
-                throw new ZygoteSecurityException(
-                        "This UID may not specify rlimits.");
-            }
-        }
-
-        if (args.rlimits != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyrlimits");
-            if (!allowed) {
-                throw new ZygoteSecurityException(
-                        "Peer may not specify rlimits");
-            }
-         }
-    }
-
-    /**
      * Applies zygote security policy.
      * Based on the credentials of the process issuing a zygote command:
      * <ol>
@@ -775,8 +659,7 @@
      * @param peer non-null; peer credentials
      * @throws ZygoteSecurityException
      */
-    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
-            String peerSecurityContext)
+    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
             throws ZygoteSecurityException {
         int peerUid = peer.getUid();
 
@@ -784,52 +667,6 @@
             throw new ZygoteSecurityException("Peer is not permitted to specify "
                     + "an explicit invoke-with wrapper command");
         }
-
-        if (args.invokeWith != null) {
-            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                         peerSecurityContext,
-                                                         "zygote",
-                                                         "specifyinvokewith");
-            if (!allowed) {
-                throw new ZygoteSecurityException("Peer is not permitted to specify "
-                    + "an explicit invoke-with wrapper command");
-            }
-        }
-    }
-
-    /**
-     * Applies zygote security policy for SELinux information.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyseInfoSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-        int peerUid = peer.getUid();
-
-        if (args.seInfo == null) {
-            // nothing to check
-            return;
-        }
-
-        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
-            // All peers with UID other than root or SYSTEM_UID
-            throw new ZygoteSecurityException(
-                    "This UID may not specify SELinux info.");
-        }
-
-        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                     peerSecurityContext,
-                                                     "zygote",
-                                                     "specifyseinfo");
-        if (!allowed) {
-            throw new ZygoteSecurityException(
-                    "Peer may not specify SELinux info");
-        }
-
-        return;
     }
 
     /**
@@ -839,20 +676,18 @@
      */
     public static void applyInvokeWithSystemProperty(Arguments args) {
         if (args.invokeWith == null && args.niceName != null) {
-            if (args.niceName != null) {
-                String property = "wrap." + args.niceName;
-                if (property.length() > 31) {
-                    // Avoid creating an illegal property name when truncating.
-                    if (property.charAt(30) != '.') {
-                        property = property.substring(0, 31);
-                    } else {
-                        property = property.substring(0, 30);
-                    }
+            String property = "wrap." + args.niceName;
+            if (property.length() > 31) {
+                // Properties with a trailing "." are illegal.
+                if (property.charAt(30) != '.') {
+                    property = property.substring(0, 31);
+                } else {
+                    property = property.substring(0, 30);
                 }
-                args.invokeWith = SystemProperties.get(property);
-                if (args.invokeWith != null && args.invokeWith.length() == 0) {
-                    args.invokeWith = null;
-                }
+            }
+            args.invokeWith = SystemProperties.get(property);
+            if (args.invokeWith != null && args.invokeWith.length() == 0) {
+                args.invokeWith = null;
             }
         }
     }
@@ -886,14 +721,15 @@
 
         if (descriptors != null) {
             try {
-                ZygoteInit.reopenStdio(descriptors[0],
-                        descriptors[1], descriptors[2]);
+                Os.dup2(descriptors[0], STDIN_FILENO);
+                Os.dup2(descriptors[1], STDOUT_FILENO);
+                Os.dup2(descriptors[2], STDERR_FILENO);
 
                 for (FileDescriptor fd: descriptors) {
                     IoUtils.closeQuietly(fd);
                 }
                 newStderr = System.err;
-            } catch (IOException ex) {
+            } catch (ErrnoException ex) {
                 Log.e(TAG, "Error reopening stdio", ex);
             }
         }
@@ -902,47 +738,14 @@
             Process.setArgV0(parsedArgs.niceName);
         }
 
-        if (parsedArgs.runtimeInit) {
-            if (parsedArgs.invokeWith != null) {
-                WrapperInit.execApplication(parsedArgs.invokeWith,
-                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
-                        pipeFd, parsedArgs.remainingArgs);
-            } else {
-                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
-                        parsedArgs.remainingArgs, null /* classLoader */);
-            }
+        if (parsedArgs.invokeWith != null) {
+            WrapperInit.execApplication(parsedArgs.invokeWith,
+                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
+                    VMRuntime.getCurrentInstructionSet(),
+                    pipeFd, parsedArgs.remainingArgs);
         } else {
-            String className;
-            try {
-                className = parsedArgs.remainingArgs[0];
-            } catch (ArrayIndexOutOfBoundsException ex) {
-                logAndPrintError(newStderr,
-                        "Missing required class name argument", null);
-                return;
-            }
-
-            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
-            System.arraycopy(parsedArgs.remainingArgs, 1,
-                    mainArgs, 0, mainArgs.length);
-
-            if (parsedArgs.invokeWith != null) {
-                WrapperInit.execStandalone(parsedArgs.invokeWith,
-                        parsedArgs.classpath, className, mainArgs);
-            } else {
-                ClassLoader cloader;
-                if (parsedArgs.classpath != null) {
-                    cloader = new PathClassLoader(parsedArgs.classpath,
-                            ClassLoader.getSystemClassLoader());
-                } else {
-                    cloader = ClassLoader.getSystemClassLoader();
-                }
-
-                try {
-                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
-                } catch (RuntimeException ex) {
-                    logAndPrintError(newStderr, "Error starting.", ex);
-                }
-            }
+            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
+                    parsedArgs.remainingArgs, null /* classLoader */);
         }
     }
 
@@ -1019,8 +822,8 @@
     private void setChildPgid(int pid) {
         // Try to move the new child into the peer's process group.
         try {
-            ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));
-        } catch (IOException ex) {
+            Os.setpgid(pid, Os.getpgid(peer.getPid()));
+        } catch (ErrnoException ex) {
             // This exception is expected in the case where
             // the peer is not in our session
             // TODO get rid of this log message in the case where
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index d95cf71..49d565d 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.os;
 
+import static android.system.OsConstants.POLLIN;
 import static android.system.OsConstants.S_IRWXG;
 import static android.system.OsConstants.S_IRWXO;
 
@@ -23,8 +24,6 @@
 import android.content.res.TypedArray;
 import android.net.LocalServerSocket;
 import android.opengl.EGL14;
-import android.os.Build;
-import android.os.Debug;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -32,9 +31,9 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.system.StructPollfd;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.Slog;
 import android.webkit.WebViewFactory;
 
 import dalvik.system.DexFile;
@@ -52,7 +51,6 @@
 import java.io.InputStreamReader;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 
 /**
@@ -93,12 +91,6 @@
     private static Resources mResources;
 
     /**
-     * The number of times that the main Zygote loop
-     * should run before calling gc() again.
-     */
-    static final int GC_LOOP_COUNT = 10;
-
-    /**
      * The path of a file that contains classes to preload.
      */
     private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
@@ -107,54 +99,6 @@
     private static final boolean PRELOAD_RESOURCES = true;
 
     /**
-     * Invokes a static "main(argv[]) method on class "className".
-     * Converts various failing exceptions into RuntimeExceptions, with
-     * the assumption that they will then cause the VM instance to exit.
-     *
-     * @param loader class loader to use
-     * @param className Fully-qualified class name
-     * @param argv Argument vector for main()
-     */
-    static void invokeStaticMain(ClassLoader loader,
-            String className, String[] argv)
-            throws ZygoteInit.MethodAndArgsCaller {
-        Class<?> cl;
-
-        try {
-            cl = loader.loadClass(className);
-        } catch (ClassNotFoundException ex) {
-            throw new RuntimeException(
-                    "Missing class when invoking static main " + className,
-                    ex);
-        }
-
-        Method m;
-        try {
-            m = cl.getMethod("main", new Class[] { String[].class });
-        } catch (NoSuchMethodException ex) {
-            throw new RuntimeException(
-                    "Missing static main on " + className, ex);
-        } catch (SecurityException ex) {
-            throw new RuntimeException(
-                    "Problem getting static main on " + className, ex);
-        }
-
-        int modifiers = m.getModifiers();
-        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
-            throw new RuntimeException(
-                    "Main method is not public and static on " + className);
-        }
-
-        /*
-         * This throw gets caught in ZygoteInit.main(), which responds
-         * by invoking the exception's run() method. This arrangement
-         * clears up all the stack frames that were required in setting
-         * up the process.
-         */
-        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
-    }
-
-    /**
      * Registers a server socket for zygote command connections
      *
      * @throws RuntimeException when open fails
@@ -171,8 +115,9 @@
             }
 
             try {
-                sServerSocket = new LocalServerSocket(
-                        createFileDescriptor(fileDesc));
+                FileDescriptor fd = new FileDescriptor();
+                fd.setInt$(fileDesc);
+                sServerSocket = new LocalServerSocket(fd);
             } catch (IOException ex) {
                 throw new RuntimeException(
                         "Error binding to local socket '" + fileDesc + "'", ex);
@@ -231,26 +176,6 @@
     private static final int ROOT_UID = 0;
     private static final int ROOT_GID = 0;
 
-    /**
-     * Sets effective user ID.
-     */
-    private static void setEffectiveUser(int uid) {
-        int errno = setreuid(ROOT_UID, uid);
-        if (errno != 0) {
-            Log.e(TAG, "setreuid() failed. errno: " + errno);
-        }
-    }
-
-    /**
-     * Sets effective group ID.
-     */
-    private static void setEffectiveGroup(int gid) {
-        int errno = setregid(ROOT_GID, gid);
-        if (errno != 0) {
-            Log.e(TAG, "setregid() failed. errno: " + errno);
-        }
-    }
-
     static void preload() {
         Log.d(TAG, "begin preload");
         preloadClasses();
@@ -298,19 +223,29 @@
         long startTime = SystemClock.uptimeMillis();
 
         // Drop root perms while running static initializers.
-        setEffectiveGroup(UNPRIVILEGED_GID);
-        setEffectiveUser(UNPRIVILEGED_UID);
+        final int reuid = Os.getuid();
+        final int regid = Os.getgid();
+
+        // We need to drop root perms only if we're already root. In the case of "wrapped"
+        // processes (see WrapperInit), this function is called from an unprivileged uid
+        // and gid.
+        boolean droppedPriviliges = false;
+        if (reuid == ROOT_UID && regid == ROOT_GID) {
+            try {
+                Os.setregid(ROOT_GID, UNPRIVILEGED_GID);
+                Os.setreuid(ROOT_UID, UNPRIVILEGED_UID);
+            } catch (ErrnoException ex) {
+                throw new RuntimeException("Failed to drop root", ex);
+            }
+
+            droppedPriviliges = true;
+        }
 
         // Alter the target heap utilization.  With explicit GCs this
         // is not likely to have any effect.
         float defaultUtilization = runtime.getTargetHeapUtilization();
         runtime.setTargetHeapUtilization(0.8f);
 
-        // Start with a clean slate.
-        System.gc();
-        runtime.runFinalizationSync();
-        Debug.startAllocCounting();
-
         try {
             BufferedReader br
                 = new BufferedReader(new InputStreamReader(is), 256);
@@ -329,15 +264,6 @@
                         Log.v(TAG, "Preloading " + line + "...");
                     }
                     Class.forName(line);
-                    if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
-                        if (false) {
-                            Log.v(TAG,
-                                " GC at " + Debug.getGlobalAllocSize());
-                        }
-                        System.gc();
-                        runtime.runFinalizationSync();
-                        Debug.resetGlobalAllocSize();
-                    }
                     count++;
                 } catch (ClassNotFoundException e) {
                     Log.w(TAG, "Class not found for preloading: " + line);
@@ -367,11 +293,15 @@
             // Fill in dex caches with classes, fields, and methods brought in by preloading.
             runtime.preloadDexCaches();
 
-            Debug.stopAllocCounting();
-
-            // Bring back root. We'll need it later.
-            setEffectiveUser(ROOT_UID);
-            setEffectiveGroup(ROOT_GID);
+            // Bring back root. We'll need it later if we're in the zygote.
+            if (droppedPriviliges) {
+                try {
+                    Os.setreuid(ROOT_UID, ROOT_UID);
+                    Os.setregid(ROOT_GID, ROOT_GID);
+                } catch (ErrnoException ex) {
+                    throw new RuntimeException("Failed to restore root", ex);
+                }
+            }
         }
     }
 
@@ -385,10 +315,7 @@
     private static void preloadResources() {
         final VMRuntime runtime = VMRuntime.getRuntime();
 
-        Debug.startAllocCounting();
         try {
-            System.gc();
-            runtime.runFinalizationSync();
             mResources = Resources.getSystem();
             mResources.startPreloading();
             if (PRELOAD_RESOURCES) {
@@ -413,28 +340,18 @@
             mResources.finishPreloading();
         } catch (RuntimeException e) {
             Log.w(TAG, "Failure preloading resources", e);
-        } finally {
-            Debug.stopAllocCounting();
         }
     }
 
     private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
         int N = ar.length();
         for (int i=0; i<N; i++) {
-            if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
-                if (false) {
-                    Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
-                }
-                System.gc();
-                runtime.runFinalizationSync();
-                Debug.resetGlobalAllocSize();
-            }
             int id = ar.getResourceId(i, 0);
             if (false) {
                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
             }
             if (id != 0) {
-                if (mResources.getColorStateList(id) == null) {
+                if (mResources.getColorStateList(id, null) == null) {
                     throw new IllegalArgumentException(
                             "Unable to find preloaded color resource #0x"
                             + Integer.toHexString(id)
@@ -449,14 +366,6 @@
     private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
         int N = ar.length();
         for (int i=0; i<N; i++) {
-            if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
-                if (false) {
-                    Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
-                }
-                System.gc();
-                runtime.runFinalizationSync();
-                Debug.resetGlobalAllocSize();
-            }
             int id = ar.getResourceId(i, 0);
             if (false) {
                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
@@ -478,7 +387,7 @@
      * softly- and final-reachable objects, along with any other garbage.
      * This is only useful just before a fork().
      */
-    /*package*/ static void gc() {
+    /*package*/ static void gcAndFinalize() {
         final VMRuntime runtime = VMRuntime.getRuntime();
 
         /* runFinalizationSync() lets finalizers be called in Zygote,
@@ -487,9 +396,6 @@
         System.gc();
         runtime.runFinalizationSync();
         System.gc();
-        runtime.runFinalizationSync();
-        System.gc();
-        runtime.runFinalizationSync();
     }
 
     /**
@@ -527,7 +433,7 @@
 
             WrapperInit.execApplication(parsedArgs.invokeWith,
                     parsedArgs.niceName, parsedArgs.targetSdkVersion,
-                    null, args);
+                    VMRuntime.getCurrentInstructionSet(), null, args);
         } else {
             ClassLoader cl = null;
             if (systemServerClasspath != null) {
@@ -594,8 +500,8 @@
             "--setgid=1000",
             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
             "--capabilities=" + capabilities + "," + capabilities,
-            "--runtime-init",
             "--nice-name=system_server",
+            "--runtime-args",
             "com.android.server.SystemServer",
         };
         ZygoteConnection.Arguments parsedArgs = null;
@@ -647,6 +553,7 @@
 
     public static void main(String argv[]) {
         try {
+            RuntimeInit.enableDdms();
             // Start profiling the zygote initialization.
             SamplingProfilerIntegration.start();
 
@@ -680,7 +587,7 @@
             SamplingProfilerIntegration.writeZygoteSnapshot();
 
             // Do an initial gc to clean up after startup
-            gc();
+            gcAndFinalize();
 
             // Disable tracing so that forked processes do not inherit stale tracing tags from
             // Zygote.
@@ -744,137 +651,42 @@
     private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
         ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
         ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
-        FileDescriptor[] fdArray = new FileDescriptor[4];
 
         fds.add(sServerSocket.getFileDescriptor());
         peers.add(null);
 
-        int loopCount = GC_LOOP_COUNT;
         while (true) {
-            int index;
-
-            /*
-             * Call gc() before we block in select().
-             * It's work that has to be done anyway, and it's better
-             * to avoid making every child do it.  It will also
-             * madvise() any free memory as a side-effect.
-             *
-             * Don't call it every time, because walking the entire
-             * heap is a lot of overhead to free a few hundred bytes.
-             */
-            if (loopCount <= 0) {
-                gc();
-                loopCount = GC_LOOP_COUNT;
-            } else {
-                loopCount--;
+            StructPollfd[] pollFds = new StructPollfd[fds.size()];
+            for (int i = 0; i < pollFds.length; ++i) {
+                pollFds[i] = new StructPollfd();
+                pollFds[i].fd = fds.get(i);
+                pollFds[i].events = (short) POLLIN;
             }
-
-
             try {
-                fdArray = fds.toArray(fdArray);
-                index = selectReadable(fdArray);
-            } catch (IOException ex) {
-                throw new RuntimeException("Error in select()", ex);
+                Os.poll(pollFds, -1);
+            } catch (ErrnoException ex) {
+                throw new RuntimeException("poll failed", ex);
             }
-
-            if (index < 0) {
-                throw new RuntimeException("Error in select()");
-            } else if (index == 0) {
-                ZygoteConnection newPeer = acceptCommandPeer(abiList);
-                peers.add(newPeer);
-                fds.add(newPeer.getFileDescriptor());
-            } else {
-                boolean done;
-                done = peers.get(index).runOnce();
-
-                if (done) {
-                    peers.remove(index);
-                    fds.remove(index);
+            for (int i = pollFds.length - 1; i >= 0; --i) {
+                if ((pollFds[i].revents & POLLIN) == 0) {
+                    continue;
+                }
+                if (i == 0) {
+                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
+                    peers.add(newPeer);
+                    fds.add(newPeer.getFileDesciptor());
+                } else {
+                    boolean done = peers.get(i).runOnce();
+                    if (done) {
+                        peers.remove(i);
+                        fds.remove(i);
+                    }
                 }
             }
         }
     }
 
     /**
-     * The Linux syscall "setreuid()"
-     * @param ruid real uid
-     * @param euid effective uid
-     * @return 0 on success, non-zero errno on fail
-     */
-    static native int setreuid(int ruid, int euid);
-
-    /**
-     * The Linux syscall "setregid()"
-     * @param rgid real gid
-     * @param egid effective gid
-     * @return 0 on success, non-zero errno on fail
-     */
-    static native int setregid(int rgid, int egid);
-
-    /**
-     * Invokes the linux syscall "setpgid"
-     *
-     * @param pid pid to change
-     * @param pgid new process group of pid
-     * @return 0 on success or non-zero errno on fail
-     */
-    static native int setpgid(int pid, int pgid);
-
-    /**
-     * Invokes the linux syscall "getpgid"
-     *
-     * @param pid pid to query
-     * @return pgid of pid in question
-     * @throws IOException on error
-     */
-    static native int getpgid(int pid) throws IOException;
-
-    /**
-     * Invokes the syscall dup2() to copy the specified descriptors into
-     * stdin, stdout, and stderr. The existing stdio descriptors will be
-     * closed and errors during close will be ignored. The specified
-     * descriptors will also remain open at their original descriptor numbers,
-     * so the caller may want to close the original descriptors.
-     *
-     * @param in new stdin
-     * @param out new stdout
-     * @param err new stderr
-     * @throws IOException
-     */
-    static native void reopenStdio(FileDescriptor in,
-            FileDescriptor out, FileDescriptor err) throws IOException;
-
-    /**
-     * Toggles the close-on-exec flag for the specified file descriptor.
-     *
-     * @param fd non-null; file descriptor
-     * @param flag desired close-on-exec flag state
-     * @throws IOException
-     */
-    static native void setCloseOnExec(FileDescriptor fd, boolean flag)
-            throws IOException;
-
-    /**
-     * Invokes select() on the provider array of file descriptors (selecting
-     * for readability only). Array elements of null are ignored.
-     *
-     * @param fds non-null; array of readable file descriptors
-     * @return index of descriptor that is now readable or -1 for empty array.
-     * @throws IOException if an error occurs
-     */
-    static native int selectReadable(FileDescriptor[] fds) throws IOException;
-
-    /**
-     * Creates a file descriptor from an int fd.
-     *
-     * @param fd integer OS file descriptor
-     * @return non-null; FileDescriptor instance
-     * @throws IOException if fd is invalid
-     */
-    static native FileDescriptor createFileDescriptor(int fd)
-            throws IOException;
-
-    /**
      * Class not instantiable.
      */
     private ZygoteInit() {
diff --git a/core/java/com/android/internal/policy/IPolicy.java b/core/java/com/android/internal/policy/IPolicy.java
deleted file mode 100644
index d08b3b4..0000000
--- a/core/java/com/android/internal/policy/IPolicy.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-/* The implementation of this interface must be called Policy and contained
- * within the com.android.internal.policy.impl package */
-public interface IPolicy {
-    public Window makeNewWindow(Context context);
-
-    public LayoutInflater makeNewLayoutInflater(Context context);
-
-    public WindowManagerPolicy makeNewWindowManager();
-
-    public FallbackEventHandler makeNewFallbackEventHandler(Context context);
-}
diff --git a/core/java/com/android/internal/policy/PolicyManager.java b/core/java/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 462b3a9..0000000
--- a/core/java/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import android.content.Context;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * {@hide}
- */
-
-public final class PolicyManager {
-    private static final String POLICY_IMPL_CLASS_NAME =
-        "com.android.internal.policy.impl.Policy";
-
-    private static final IPolicy sPolicy;
-
-    static {
-        // Pull in the actual implementation of the policy at run-time
-        try {
-            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
-            sPolicy = (IPolicy)policyClass.newInstance();
-        } catch (ClassNotFoundException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);
-        } catch (InstantiationException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
-        } catch (IllegalAccessException ex) {
-            throw new RuntimeException(
-                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);
-        }
-    }
-
-    // Cannot instantiate this class
-    private PolicyManager() {}
-
-    // The static methods to spawn new policy-specific objects
-    public static Window makeNewWindow(Context context) {
-        return sPolicy.makeNewWindow(context);
-    }
-
-    public static LayoutInflater makeNewLayoutInflater(Context context) {
-        return sPolicy.makeNewLayoutInflater(context);
-    }
-
-    public static WindowManagerPolicy makeNewWindowManager() {
-        return sPolicy.makeNewWindowManager();
-    }
-
-    public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return sPolicy.makeNewFallbackEventHandler(context);
-    }
-}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index a3c0db4..2b0d244 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -1,19 +1,19 @@
 /**
  * Copyright (c) 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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.
  */
- 
+
 package com.android.internal.statusbar;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -43,5 +43,26 @@
     void preloadRecentApps();
     void cancelPreloadRecentApps();
     void showScreenPinningRequest();
+
+    /**
+     * Notifies the status bar that an app transition is pending to delay applying some flags with
+     * visual impact until {@link #appTransitionReady} is called.
+     */
+    void appTransitionPending();
+
+    /**
+     * Notifies the status bar that a pending app transition has been cancelled.
+     */
+    void appTransitionCancelled();
+
+    /**
+     * Notifies the status bar that an app transition is now being executed.
+     *
+     * @param statusBarAnimationsStartTime the desired start time for all visual animations in the
+     *        status bar caused by this app transition in uptime millis
+     * @param statusBarAnimationsDuration the duration for all visual animations in the status
+     *        bar caused by this app transition in millis
+     */
+    void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 40c009f..6cb839e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -1,16 +1,16 @@
 /**
  * Copyright (c) 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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.
  */
 
@@ -61,4 +61,25 @@
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
+
+    /**
+     * Notifies the status bar that an app transition is pending to delay applying some flags with
+     * visual impact until {@link #appTransitionReady} is called.
+     */
+    void appTransitionPending();
+
+    /**
+     * Notifies the status bar that a pending app transition has been cancelled.
+     */
+    void appTransitionCancelled();
+
+    /**
+     * Notifies the status bar that an app transition is now being executed.
+     *
+     * @param statusBarAnimationsStartTime the desired start time for all visual animations in the
+     *        status bar caused by this app transition in uptime millis
+     * @param statusBarAnimationsDuration the duration for all visual animations in the status
+     *        bar caused by this app transition in millis
+     */
+    void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
 }
diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java
new file mode 100644
index 0000000..abb50c1
--- /dev/null
+++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * EpicenterClipReveal captures the {@link View#getClipBounds()} before and
+ * after the scene change and animates between those and the epicenter bounds
+ * during a visibility transition.
+ */
+public class EpicenterClipReveal extends Visibility {
+    private static final String PROPNAME_CLIP = "android:epicenterReveal:clip";
+    private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds";
+
+    public EpicenterClipReveal() {}
+
+    public EpicenterClipReveal(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        super.captureStartValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        super.captureEndValues(transitionValues);
+        captureValues(transitionValues);
+    }
+
+    private void captureValues(TransitionValues values) {
+        final View view = values.view;
+        if (view.getVisibility() == View.GONE) {
+            return;
+        }
+
+        final Rect clip = view.getClipBounds();
+        values.values.put(PROPNAME_CLIP, clip);
+
+        if (clip == null) {
+            final Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+            values.values.put(PROPNAME_BOUNDS, bounds);
+        }
+    }
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, View view,
+            TransitionValues startValues, TransitionValues endValues) {
+        if (endValues == null) {
+            return null;
+        }
+
+        final Rect end = getBestRect(endValues);
+        final Rect start = getEpicenterOrCenter(end);
+
+        // Prepare the view.
+        view.setClipBounds(start);
+
+        return createRectAnimator(view, start, end, endValues);
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, View view,
+            TransitionValues startValues, TransitionValues endValues) {
+        if (startValues == null) {
+            return null;
+        }
+
+        final Rect start = getBestRect(startValues);
+        final Rect end = getEpicenterOrCenter(start);
+
+        // Prepare the view.
+        view.setClipBounds(start);
+
+        return createRectAnimator(view, start, end, endValues);
+    }
+
+    private Rect getEpicenterOrCenter(Rect bestRect) {
+        final Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            return epicenter;
+        }
+
+        int centerX = bestRect.centerX();
+        int centerY = bestRect.centerY();
+        return new Rect(centerX, centerY, centerX, centerY);
+    }
+
+    private Rect getBestRect(TransitionValues values) {
+        final Rect clipRect = (Rect) values.values.get(PROPNAME_CLIP);
+        if (clipRect == null) {
+            return (Rect) values.values.get(PROPNAME_BOUNDS);
+        }
+        return clipRect;
+    }
+
+    private Animator createRectAnimator(final View view, Rect start, Rect end,
+            TransitionValues endValues) {
+        final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP);
+        final RectEvaluator evaluator = new RectEvaluator(new Rect());
+        ObjectAnimator anim = ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                view.setClipBounds(terminalClip);
+            }
+        });
+        return anim;
+    }
+}
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
index 65b56ec..64e1d10 100644
--- a/core/java/com/android/internal/util/DumpUtils.java
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -35,13 +35,14 @@
      * trying to acquire, we use a short timeout to avoid deadlocks.  The process
      * is inelegant but this function is only used for debugging purposes.
      */
-    public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw, long timeout) {
+    public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw,
+            final String prefix, long timeout) {
         final StringWriter sw = new StringWriter();
         if (handler.runWithScissors(new Runnable() {
             @Override
             public void run() {
                 PrintWriter lpw = new FastPrintWriter(sw);
-                dump.dump(lpw);
+                dump.dump(lpw, prefix);
                 lpw.close();
             }
         }, timeout)) {
@@ -52,6 +53,6 @@
     }
 
     public interface Dump {
-        void dump(PrintWriter pw);
+        void dump(PrintWriter pw, String prefix);
     }
 }
diff --git a/core/java/com/android/internal/util/UserIcons.java b/core/java/com/android/internal/util/UserIcons.java
index e1e9d5e..c69d14f 100644
--- a/core/java/com/android/internal/util/UserIcons.java
+++ b/core/java/com/android/internal/util/UserIcons.java
@@ -48,9 +48,12 @@
         if (icon == null) {
             return null;
         }
-        Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(),
-                Bitmap.Config.ARGB_8888);
-        icon.draw(new Canvas(bitmap));
+        final int width = icon.getIntrinsicWidth();
+        final int height = icon.getIntrinsicHeight();
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        icon.setBounds(0, 0, width, height);
+        icon.draw(canvas);
         return bitmap;
     }
 
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 2bd607c..0350d61 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -20,6 +20,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Bitmap.CompressFormat;
 import android.net.Uri;
+import android.util.ArrayMap;
 import android.util.Base64;
 import android.util.Xml;
 
@@ -822,7 +823,36 @@
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name, callback);
+                Object val = readThisValueXml(parser, name, callback, false);
+                map.put(name[0], val);
+            } else if (eventType == parser.END_TAG) {
+                if (parser.getName().equals(endTag)) {
+                    return map;
+                }
+                throw new XmlPullParserException(
+                    "Expected " + endTag + " end tag at: " + parser.getName());
+            }
+            eventType = parser.next();
+        } while (eventType != parser.END_DOCUMENT);
+
+        throw new XmlPullParserException(
+            "Document ended before " + endTag + " end tag");
+    }
+
+    /**
+     * Like {@link #readThisMapXml}, but returns an ArrayMap instead of HashMap.
+     * @hide
+     */
+    public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag,
+            String[] name, ReadMapCallback callback)
+            throws XmlPullParserException, java.io.IOException
+    {
+        ArrayMap<String, Object> map = new ArrayMap<>();
+
+        int eventType = parser.getEventType();
+        do {
+            if (eventType == parser.START_TAG) {
+                Object val = readThisValueXml(parser, name, callback, true);
                 map.put(name[0], val);
             } else if (eventType == parser.END_TAG) {
                 if (parser.getName().equals(endTag)) {
@@ -854,7 +884,7 @@
      */
     public static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
             String[] name) throws XmlPullParserException, java.io.IOException {
-        return readThisListXml(parser, endTag, name, null);
+        return readThisListXml(parser, endTag, name, null, false);
     }
 
     /**
@@ -872,14 +902,14 @@
      * @see #readListXml
      */
     private static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
-            String[] name, ReadMapCallback callback)
+            String[] name, ReadMapCallback callback, boolean arrayMap)
             throws XmlPullParserException, java.io.IOException {
         ArrayList list = new ArrayList();
 
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name, callback);
+                Object val = readThisValueXml(parser, name, callback, arrayMap);
                 list.add(val);
                 //System.out.println("Adding to list: " + val);
             } else if (eventType == parser.END_TAG) {
@@ -915,7 +945,7 @@
      */
     public static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name)
             throws XmlPullParserException, java.io.IOException {
-        return readThisSetXml(parser, endTag, name, null);
+        return readThisSetXml(parser, endTag, name, null, false);
     }
 
     /**
@@ -937,13 +967,14 @@
      * @hide
      */
     private static final HashSet readThisSetXml(XmlPullParser parser, String endTag, String[] name,
-            ReadMapCallback callback) throws XmlPullParserException, java.io.IOException {
+            ReadMapCallback callback, boolean arrayMap)
+            throws XmlPullParserException, java.io.IOException {
         HashSet set = new HashSet();
         
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                Object val = readThisValueXml(parser, name, callback);
+                Object val = readThisValueXml(parser, name, callback, arrayMap);
                 set.add(val);
                 //System.out.println("Adding to set: " + val);
             } else if (eventType == parser.END_TAG) {
@@ -1292,7 +1323,7 @@
         int eventType = parser.getEventType();
         do {
             if (eventType == parser.START_TAG) {
-                return readThisValueXml(parser, name, null);
+                return readThisValueXml(parser, name, null, false);
             } else if (eventType == parser.END_TAG) {
                 throw new XmlPullParserException(
                     "Unexpected end tag at: " + parser.getName());
@@ -1308,7 +1339,8 @@
     }
 
     private static final Object readThisValueXml(XmlPullParser parser, String[] name,
-            ReadMapCallback callback)  throws XmlPullParserException, java.io.IOException {
+            ReadMapCallback callback, boolean arrayMap)
+            throws XmlPullParserException, java.io.IOException {
         final String valueName = parser.getAttributeValue(null, "name");
         final String tagName = parser.getName();
 
@@ -1368,19 +1400,21 @@
             return res;
         } else if (tagName.equals("map")) {
             parser.next();
-            res = readThisMapXml(parser, "map", name);
+            res = arrayMap
+                    ? readThisArrayMapXml(parser, "map", name, callback)
+                    : readThisMapXml(parser, "map", name, callback);
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
         } else if (tagName.equals("list")) {
             parser.next();
-            res = readThisListXml(parser, "list", name);
+            res = readThisListXml(parser, "list", name, callback, arrayMap);
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
         } else if (tagName.equals("set")) {
             parser.next();
-            res = readThisSetXml(parser, "set", name);
+            res = readThisSetXml(parser, "set", name, callback, arrayMap);
             name[0] = valueName;
             //System.out.println("Returning value for " + valueName + ": " + res);
             return res;
diff --git a/core/java/com/android/internal/view/ActionModeWrapper.java b/core/java/com/android/internal/view/ActionModeWrapper.java
new file mode 100644
index 0000000..d98617d
--- /dev/null
+++ b/core/java/com/android/internal/view/ActionModeWrapper.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.internal.view.menu.MenuBuilder;
+
+/**
+ * ActionMode implementation that wraps several actions modes and creates them on the fly depending
+ * on the ActionMode type chosen by the client.
+ */
+public class ActionModeWrapper extends ActionMode {
+
+    /**
+     * Interface to defer the ActionMode creation until the type is chosen.
+     */
+    public interface ActionModeProvider {
+        /**
+         * Create the desired ActionMode, that will immediately be used as the current active mode
+         * in the decorator.
+         *
+         * @param callback The {@link ActionMode.Callback} to be used.
+         * @param menuBuilder The {@link MenuBuilder} that should be used by the created
+         *      {@link ActionMode}. This will already have been populated.
+         * @return A new {@link ActionMode} ready to be used that uses menuBuilder as its menu.
+         */
+        ActionMode createActionMode(ActionMode.Callback callback, MenuBuilder menuBuilder);
+    }
+
+    private ActionMode mActionMode;
+    private final Context mContext;
+    private MenuBuilder mMenu;
+    private final ActionMode.Callback mCallback;
+    private boolean mTypeLocked = false;
+
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+    private View mCustomView;
+    
+    private final ActionModeProvider mActionModeProvider;
+
+    public ActionModeWrapper(
+            Context context, ActionMode.Callback callback, ActionModeProvider actionModeProvider) {
+        mContext = context;
+        mMenu = new MenuBuilder(context).setDefaultShowAsAction(
+                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mCallback = callback;
+        mActionModeProvider = actionModeProvider;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(title);
+        } else {
+            mTitle = title;
+        }
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(resId);
+        } else {
+            mTitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(subtitle);
+        } else {
+            mSubtitle = subtitle;
+        }
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(resId);
+        } else {
+            mSubtitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        if (mActionMode != null) {
+            mActionMode.setCustomView(view);
+        } else {
+            mCustomView = view;
+        }
+    }
+
+    public ActionMode getWrappedActionMode() {
+        return mActionMode;
+    }
+
+    /**
+     * Set the current type as final and create the necessary ActionMode. After this call, any
+     * changes to the ActionMode type will be ignored.
+     */
+    public void lockType() {
+        mTypeLocked = true;
+        switch (getType()) {
+            case ActionMode.TYPE_PRIMARY:
+            default:
+                mActionMode = mActionModeProvider.createActionMode(mCallback, mMenu);
+                break;
+            case ActionMode.TYPE_FLOATING:
+                // Not implemented yet.
+                break;
+        }
+
+        if (mActionMode == null) {
+            return;
+        }
+
+        mActionMode.setTitle(mTitle);
+        mActionMode.setSubtitle(mSubtitle);
+        if (mCustomView != null) {
+            mActionMode.setCustomView(mCustomView);
+        }
+
+        mTitle = null;
+        mSubtitle = null;
+        mCustomView = null;
+    }
+
+    @Override
+    public void setType(int type) {
+        if (!mTypeLocked) {
+            super.setType(type);
+        } else {
+            throw new IllegalStateException(
+                    "You can't change the ActionMode's type after onCreateActionMode.");
+        }
+    }
+
+    @Override
+    public void invalidate() {
+        if (mActionMode != null) {
+            mActionMode.invalidate();
+        }
+    }
+
+    @Override
+    public void finish() {
+        if (mActionMode != null) {
+            mActionMode.finish();
+        } else {
+            mCallback.onDestroyActionMode(this);
+        }
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        if (mActionMode != null) {
+            return mActionMode.getTitle();
+        }
+        return mTitle;
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        if (mActionMode != null) {
+            return mActionMode.getSubtitle();
+        }
+        return mSubtitle;
+    }
+
+    @Override
+    public View getCustomView() {
+        if (mActionMode != null) {
+            return mActionMode.getCustomView();
+        }
+        return mCustomView;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return new MenuInflater(mContext);
+    }
+
+}
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index d5d3602..e6d911c 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -47,7 +47,7 @@
         mCallback = callback;
 
         mMenu = new MenuBuilder(view.getContext()).setDefaultShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+                        MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mMenu.setCallback(this);
         mFocusable = isFocusable;
     }
@@ -64,12 +64,12 @@
 
     @Override
     public void setTitle(int resId) {
-        setTitle(mContext.getString(resId));
+        setTitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
     public void setSubtitle(int resId) {
-        setSubtitle(mContext.getString(resId));
+        setSubtitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index ed676bb..00af401 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -42,6 +44,7 @@
     
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
+    private TintInfo mIconTintInfo;
     
     private Context mContext;
     
@@ -158,12 +161,14 @@
     public MenuItem setIcon(Drawable icon) {
         mIconDrawable = icon;
         mIconResId = NO_ICON;
+        applyIconTint();
         return this;
     }
 
     public MenuItem setIcon(int iconRes) {
         mIconResId = iconRes;
         mIconDrawable = mContext.getDrawable(iconRes);
+        applyIconTint();
         return this;
     }
 
@@ -274,4 +279,48 @@
         // No need to save the listener; ActionMenuItem does not support collapsing items.
         return this;
     }
+
+    @Override
+    public MenuItem setIconTintList(ColorStateList tintList) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintList = tintList;
+        mIconTintInfo.mHasTintList = true;
+        applyIconTint();
+        return this;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintMode = tintMode;
+        mIconTintInfo.mHasTintMode = true;
+        applyIconTint();
+        return this;
+    }
+
+    private void applyIconTint() {
+        final TintInfo tintInfo = mIconTintInfo;
+        if (mIconDrawable != null && tintInfo != null) {
+            if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
+                mIconDrawable = mIconDrawable.mutate();
+                if (tintInfo.mHasTintList) {
+                    mIconDrawable.setTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mIconDrawable.setTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 7eec392..f75b139 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -217,14 +217,14 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         onPopulateAccessibilityEvent(event);
         return true;
     }
 
     @Override
-    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.onPopulateAccessibilityEvent(event);
+    public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEventInternal(event);
         final CharSequence cdesc = getContentDescription();
         if (!TextUtils.isEmpty(cdesc)) {
             event.getText().add(cdesc);
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 692bdac..29ac3f3 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -276,8 +276,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
 
         if (mItemData != null && mItemData.hasSubMenu()) {
             info.setCanOpenPopup(true);
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 3b1f20d..ef4e546 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -21,6 +21,8 @@
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 import android.view.ActionProvider;
@@ -60,6 +62,11 @@
      * needed).
      */ 
     private int mIconResId = NO_ICON;
+
+    /**
+     * Tint info for the icon
+     */
+    private TintInfo mIconTintInfo;
     
     /** The menu to which this item belongs */
     private MenuBuilder mMenu;
@@ -385,10 +392,10 @@
         }
 
         if (mIconResId != NO_ICON) {
-            Drawable icon =  mMenu.getContext().getDrawable(mIconResId);
+            mIconDrawable = mMenu.getContext().getDrawable(mIconResId);
             mIconResId = NO_ICON;
-            mIconDrawable = icon;
-            return icon;
+            applyIconTint();
+            return mIconDrawable;
         }
         
         return null;
@@ -397,6 +404,7 @@
     public MenuItem setIcon(Drawable icon) {
         mIconResId = NO_ICON;
         mIconDrawable = icon;
+        applyIconTint();
         mMenu.onItemsChanged(false);
         
         return this;
@@ -670,4 +678,48 @@
     public boolean isActionViewExpanded() {
         return mIsActionViewExpanded;
     }
+
+    @Override
+    public MenuItem setIconTintList(ColorStateList tintList) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintList = tintList;
+        mIconTintInfo.mHasTintList = true;
+        applyIconTint();
+        return this;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintMode = tintMode;
+        mIconTintInfo.mHasTintMode = true;
+        applyIconTint();
+        return this;
+    }
+
+    private void applyIconTint() {
+        final TintInfo tintInfo = mIconTintInfo;
+        if (mIconDrawable != null && tintInfo != null) {
+            if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
+                mIconDrawable = mIconDrawable.mutate();
+                if (tintInfo.mHasTintList) {
+                    mIconDrawable.setTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mIconDrawable.setTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 99bb1ac..7d45071 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -43,8 +43,6 @@
 public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
         ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
         View.OnAttachStateChangeListener, MenuPresenter {
-    private static final String TAG = "MenuPopupHelper";
-
     static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
 
     private final Context mContext;
@@ -118,6 +116,10 @@
         mDropDownGravity = gravity;
     }
 
+    public int getGravity() {
+        return mDropDownGravity;
+    }
+
     public void show() {
         if (!tryShow()) {
             throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
@@ -128,14 +130,25 @@
         return mPopup;
     }
 
+    /**
+     * Attempts to show the popup anchored to the view specified by
+     * {@link #setAnchorView(View)}.
+     *
+     * @return {@code true} if the popup was shown or was already showing prior
+     *         to calling this method, {@code false} otherwise
+     */
     public boolean tryShow() {
+        if (isShowing()) {
+            return true;
+        }
+
         mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
         mPopup.setOnDismissListener(this);
         mPopup.setOnItemClickListener(this);
         mPopup.setAdapter(mAdapter);
         mPopup.setModal(true);
 
-        View anchor = mAnchorView;
+        final View anchor = mAnchorView;
         if (anchor != null) {
             final boolean addGlobalListener = mTreeObserver == null;
             mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
@@ -165,6 +178,7 @@
         }
     }
 
+    @Override
     public void onDismiss() {
         mPopup = null;
         mMenu.close();
@@ -186,6 +200,7 @@
         adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
     }
 
+    @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
             dismiss();
diff --git a/core/java/com/android/internal/widget/AccessibleDateAnimator.java b/core/java/com/android/internal/widget/AccessibleDateAnimator.java
index e91a55c..f97a5d1 100644
--- a/core/java/com/android/internal/widget/AccessibleDateAnimator.java
+++ b/core/java/com/android/internal/widget/AccessibleDateAnimator.java
@@ -40,7 +40,7 @@
      * Announce the currently-selected date when launched.
      */
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
             // Clear the event's current text so that only the current date will be spoken.
             event.getText().clear();
@@ -51,6 +51,6 @@
             event.getText().add(dateString);
             return true;
         }
-        return super.dispatchPopulateAccessibilityEvent(event);
+        return super.dispatchPopulateAccessibilityEventInternal(event);
     }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 7937a95..a5efa82 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -23,7 +23,6 @@
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.ActionMode;
@@ -32,8 +31,6 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import java.util.List;
-
 /**
  * This class acts as a container for the action bar view and action mode context views.
  * It applies special styles as needed to help handle animated transitions between them.
@@ -259,6 +256,15 @@
         return null;
     }
 
+    @Override
+    public ActionMode startActionModeForChild(
+            View child, ActionMode.Callback callback, int type) {
+        if (type != ActionMode.TYPE_PRIMARY) {
+            return super.startActionModeForChild(child, callback, type);
+        }
+        return null;
+    }
+
     private static boolean isCollapsed(View view) {
         return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0;
     }
@@ -387,7 +393,7 @@
         }
 
         @Override
-        public void setColorFilter(ColorFilter cf) {
+        public void setColorFilter(ColorFilter colorFilter) {
         }
 
         @Override
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 7c671e8..42d875d 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -17,8 +17,6 @@
 
 import com.android.internal.R;
 
-import android.util.TypedValue;
-import android.view.ContextThemeWrapper;
 import android.widget.ActionMenuPresenter;
 import android.widget.ActionMenuView;
 import com.android.internal.view.menu.MenuBuilder;
@@ -158,7 +156,7 @@
             removeView(mCustomView);
         }
         mCustomView = view;
-        if (mTitleLayout != null) {
+        if (view != null && mTitleLayout != null) {
             removeView(mTitleLayout);
             mTitleLayout = null;
         }
@@ -529,7 +527,7 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+    public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
             // Action mode started
             event.setSource(this);
@@ -537,7 +535,7 @@
             event.setPackageName(getContext().getPackageName());
             event.setContentDescription(mTitle);
         } else {
-            super.onInitializeAccessibilityEvent(event);
+            super.onInitializeAccessibilityEventInternal(event);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index cca48d3..c3a7460 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -32,7 +32,6 @@
 import android.util.Log;
 import android.util.Property;
 import android.util.SparseArray;
-import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 654d08b..88436f8 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1463,14 +1463,14 @@
         }
 
         @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
             onPopulateAccessibilityEvent(event);
             return true;
         }
 
         @Override
-        public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-            super.onPopulateAccessibilityEvent(event);
+        public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+            super.onPopulateAccessibilityEventInternal(event);
             final CharSequence cdesc = getContentDescription();
             if (!TextUtils.isEmpty(cdesc)) {
                 event.getText().add(cdesc);
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..64e6c69
--- /dev/null
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+    /** Spacer used in horizontal orientation. */
+    private final View mSpacer;
+
+    /** Whether the current configuration allows stacking. */
+    private final boolean mAllowStacked;
+
+    /** Whether the layout is currently stacked. */
+    private boolean mStacked;
+
+    public ButtonBarLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mAllowStacked = context.getResources().getBoolean(R.bool.allow_stacked_button_bar);
+        mSpacer = findViewById(R.id.spacer);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Maybe we can fit the content now?
+        if (w > oldw && mStacked) {
+            setStacked(false);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        if (mAllowStacked && getOrientation() == LinearLayout.HORIZONTAL) {
+            final int measuredWidth = getMeasuredWidthAndState();
+            final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+            if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+                setStacked(true);
+
+                // Measure again in the new orientation.
+                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            }
+        }
+    }
+
+    private void setStacked(boolean stacked) {
+        setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+        setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+        if (mSpacer != null) {
+            mSpacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+        }
+
+        // Reverse the child order. This is specific to the Material button
+        // bar's layout XML and will probably not generalize.
+        final int childCount = getChildCount();
+        for (int i = childCount - 2; i >= 0; i--) {
+            bringChildToFront(getChildAt(i));
+        }
+
+        mStacked = stacked;
+    }
+}
diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
index 0e046cb..bdf17fc 100644
--- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java
+++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
@@ -567,7 +567,15 @@
         }
         // TODO: Check virtual view visibility.
         if (!isAccessibilityFocused(virtualViewId)) {
+            // Clear focus from the previously focused view, if applicable.
+            if (mFocusedVirtualViewId != INVALID_ID) {
+                sendEventForVirtualView(mFocusedVirtualViewId,
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+            }
+
+            // Set focus on the new view.
             mFocusedVirtualViewId = virtualViewId;
+
             // TODO: Only invalidate virtual view bounds.
             mView.invalidate();
             sendEventForVirtualView(virtualViewId,
diff --git a/core/java/com/android/internal/widget/FaceUnlockView.java b/core/java/com/android/internal/widget/FaceUnlockView.java
deleted file mode 100644
index 121e601..0000000
--- a/core/java/com/android/internal/widget/FaceUnlockView.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.RelativeLayout;
-
-public class FaceUnlockView extends RelativeLayout {
-    private static final String TAG = "FaceUnlockView";
-
-    public FaceUnlockView(Context context) {
-        this(context, null);
-    }
-
-    public FaceUnlockView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    private int resolveMeasured(int measureSpec, int desired)
-    {
-        int result = 0;
-        int specSize = MeasureSpec.getSize(measureSpec);
-        switch (MeasureSpec.getMode(measureSpec)) {
-            case MeasureSpec.UNSPECIFIED:
-                result = desired;
-                break;
-            case MeasureSpec.AT_MOST:
-                result = Math.max(specSize, desired);
-                break;
-            case MeasureSpec.EXACTLY:
-            default:
-                result = specSize;
-        }
-        return result;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int minimumWidth = getSuggestedMinimumWidth();
-        final int minimumHeight = getSuggestedMinimumHeight();
-        int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
-        int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
-        final int chosenSize = Math.min(viewWidth, viewHeight);
-        final int newWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
-        final int newHeightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
-
-        super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
-    }
-}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 9501f92..0cb1f38 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -31,5 +31,4 @@
     boolean checkVoldPassword(int userId);
     boolean havePattern(int userId);
     boolean havePassword(int userId);
-    void removeUser(int userId);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f6c42af..90821dc 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -18,14 +18,11 @@
 
 import android.Manifest;
 import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
-import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.AsyncTask;
@@ -39,16 +36,12 @@
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
-import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.IWindowManager;
-import android.view.View;
-import android.widget.Button;
 
-import com.android.internal.R;
 import com.google.android.collect.Lists;
 
+import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
@@ -56,6 +49,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import libcore.util.HexEncoding;
+
 /**
  * Utilities for the lock pattern and its settings.
  */
@@ -100,52 +95,36 @@
     public static final int MIN_LOCK_PATTERN_SIZE = 4;
 
     /**
+     * The minimum size of a valid password.
+     */
+    public static final int MIN_LOCK_PASSWORD_SIZE = 4;
+
+    /**
      * The minimum number of dots the user must include in a wrong pattern
      * attempt for it to be counted against the counts that affect
      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
      */
     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
 
-    /**
-     * Tells the keyguard to show the user switcher when the keyguard is created.
-     */
-    public static final String KEYGUARD_SHOW_USER_SWITCHER = "showuserswitcher";
-
-    /**
-     * Tells the keyguard to show the security challenge when the keyguard is created.
-     */
-    public static final String KEYGUARD_SHOW_SECURITY_CHALLENGE = "showsecuritychallenge";
-
-    /**
-     * Tells the keyguard to show the widget with the specified id when the keyguard is created.
-     */
-    public static final String KEYGUARD_SHOW_APPWIDGET = "showappwidget";
-
-    /**
-     * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
-     * be used
-     */
-    public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
-
-    /**
-     * Pseudo-appwidget id we use to represent the default clock status widget
-     */
-    public static final int ID_DEFAULT_STATUS_WIDGET = -2;
-
+    @Deprecated
     public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
     public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
     public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
     public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
-    public static final String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
+    @Deprecated
+    public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
     public final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
     public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
     public final static String LOCKSCREEN_OPTIONS = "lockscreen.options";
+    @Deprecated
     public final static String LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK
             = "lockscreen.biometric_weak_fallback";
+    @Deprecated
     public final static String BIOMETRIC_WEAK_EVER_CHOSEN_KEY
             = "lockscreen.biometricweakeverchosen";
     public final static String LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS
             = "lockscreen.power_button_instantly_locks";
+    @Deprecated
     public final static String LOCKSCREEN_WIDGETS_ENABLED = "lockscreen.widgets_enabled";
 
     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
@@ -224,7 +203,11 @@
     }
 
     public int getRequestedPasswordHistoryLength() {
-        return getDevicePolicyManager().getPasswordHistoryLength(null, getCurrentOrCallingUserId());
+        return getRequestedPasswordHistoryLength(getCurrentOrCallingUserId());
+    }
+
+    private int getRequestedPasswordHistoryLength(int userId) {
+        return getDevicePolicyManager().getPasswordHistoryLength(null, userId);
     }
 
     public int getRequestedPasswordMinimumLetters() {
@@ -286,14 +269,6 @@
         }
     }
 
-    public void removeUser(int userId) {
-        try {
-            getLockSettings().removeUser(userId);
-        } catch (RemoteException re) {
-            Log.e(TAG, "Couldn't remove lock settings for user " + userId);
-        }
-    }
-
     private int getCurrentOrCallingUserId() {
         if (mMultiUserMode) {
             // TODO: This is a little inefficient. See if all users of this are able to
@@ -356,9 +331,10 @@
      * @return Whether the password matches any in the history.
      */
     public boolean checkPasswordHistory(String password) {
+        int userId = getCurrentOrCallingUserId();
         String passwordHashString = new String(
-                passwordToHash(password, getCurrentOrCallingUserId()));
-        String passwordHistory = getString(PASSWORD_HISTORY_KEY);
+                passwordToHash(password, userId), StandardCharsets.UTF_8);
+        String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId);
         if (passwordHistory == null) {
             return false;
         }
@@ -380,15 +356,7 @@
      * Check to see if the user has stored a lock pattern.
      * @return Whether a saved pattern exists.
      */
-    public boolean savedPatternExists() {
-        return savedPatternExists(getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Check to see if the user has stored a lock pattern.
-     * @return Whether a saved pattern exists.
-     */
-    public boolean savedPatternExists(int userId) {
+    private boolean savedPatternExists(int userId) {
         try {
             return getLockSettings().havePattern(userId);
         } catch (RemoteException re) {
@@ -400,15 +368,7 @@
      * Check to see if the user has stored a lock pattern.
      * @return Whether a saved pattern exists.
      */
-    public boolean savedPasswordExists() {
-        return savedPasswordExists(getCurrentOrCallingUserId());
-    }
-
-     /**
-     * Check to see if the user has stored a lock pattern.
-     * @return Whether a saved pattern exists.
-     */
-    public boolean savedPasswordExists(int userId) {
+    private boolean savedPasswordExists(int userId) {
         try {
             return getLockSettings().havePassword(userId);
         } catch (RemoteException re) {
@@ -423,17 +383,7 @@
      * @return True if the user has ever chosen a pattern.
      */
     public boolean isPatternEverChosen() {
-        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false);
-    }
-
-    /**
-     * Return true if the user has ever chosen biometric weak.  This is true even if biometric
-     * weak is not current set.
-     *
-     * @return True if the user has ever chosen biometric weak.
-     */
-    public boolean isBiometricWeakEverChosen() {
-        return getBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, false);
+        return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, getCurrentOrCallingUserId());
     }
 
     /**
@@ -441,68 +391,54 @@
      * information it has.
      */
     public int getActivePasswordQuality() {
-        int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-        // Note we don't want to use getKeyguardStoredPasswordQuality() because we want this to
-        // return biometric_weak if that is being used instead of the backup
-        int quality =
-                (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
-        switch (quality) {
-            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-                if (isLockPatternEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
-                if (isBiometricWeakInstalled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                if (isLockPasswordEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
-                if (isLockPasswordEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-                if (isLockPasswordEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                if (isLockPasswordEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-                }
-                break;
-            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
-                if (isLockPasswordEnabled()) {
-                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-                }
-                break;
-        }
-
-        return activePasswordQuality;
+        return getActivePasswordQuality(getCurrentOrCallingUserId());
     }
 
-    public void clearLock(boolean isFallback) {
-        clearLock(isFallback, getCurrentOrCallingUserId());
+    /**
+     * Used by device policy manager to validate the current password
+     * information it has.
+     */
+    public int getActivePasswordQuality(int userId) {
+        int quality = getKeyguardStoredPasswordQuality(userId);
+
+        if (isLockPasswordEnabled(quality, userId)) {
+            // Quality is a password and a password exists. Return the quality.
+            return quality;
+        }
+
+        if (isLockPatternEnabled(quality, userId)) {
+            // Quality is a pattern and a pattern exists. Return the quality.
+            return quality;
+        }
+
+        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+    }
+
+    public void clearLock() {
+        clearLock(getCurrentOrCallingUserId());
     }
 
     /**
      * Clear any lock pattern or password.
      */
-    public void clearLock(boolean isFallback, int userHandle) {
-        if(!isFallback) deleteGallery(userHandle);
-        saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, isFallback,
-                userHandle);
-        setLockPatternEnabled(false, userHandle);
-        saveLockPattern(null, isFallback, userHandle);
+    public void clearLock(int userHandle) {
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
-        setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                userHandle);
+
+        try {
+            getLockSettings().setLockPassword(null, userHandle);
+            getLockSettings().setLockPattern(null, userHandle);
+        } catch (RemoteException e) {
+            // well, we tried...
+        }
+
+        if (userHandle == UserHandle.USER_OWNER) {
+            // Set the encryption password to default.
+            updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+        }
+
+        getDevicePolicyManager().setActivePasswordState(
+                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
+
         onAfterChangingPassword(userHandle);
     }
 
@@ -513,7 +449,7 @@
      * @param disable Disables lock screen when true
      */
     public void setLockScreenDisabled(boolean disable) {
-        setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
+        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, getCurrentOrCallingUserId());
     }
 
     /**
@@ -523,7 +459,7 @@
      * @return true if lock screen is can be disabled
      */
     public boolean isLockScreenDisabled() {
-        if (!isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0) {
+        if (!isSecure() && getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId())) {
             // Check if the number of switchable users forces the lockscreen.
             final List<UserInfo> users = UserManager.get(mContext).getUsers(true);
             final int userCount = users.size();
@@ -539,96 +475,57 @@
     }
 
     /**
-     * Calls back SetupFaceLock to delete the temporary gallery file
-     */
-    public void deleteTempGallery() {
-        Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
-        intent.putExtra("deleteTempGallery", true);
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Calls back SetupFaceLock to delete the gallery file when the lock type is changed
-    */
-    void deleteGallery(int userId) {
-        if(usingBiometricWeak(userId)) {
-            Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
-            intent.putExtra("deleteGallery", true);
-            mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
-        }
-    }
-
-    /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern) {
-        this.saveLockPattern(pattern, false);
+        this.saveLockPattern(pattern, getCurrentOrCallingUserId());
     }
 
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
-     */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
-        this.saveLockPattern(pattern, isFallback, getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Save a lock pattern.
-     * @param pattern The new pattern to save.
-     * @param isFallback Specifies if this is a fallback to biometric weak
      * @param userId the user whose pattern is to be saved.
      */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback,
-            int userId) {
+    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
         try {
+            if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
+                throw new IllegalArgumentException("pattern must not be null and at least "
+                        + MIN_LOCK_PATTERN_SIZE + " dots long.");
+            }
+
             getLockSettings().setLockPattern(patternToString(pattern), userId);
             DevicePolicyManager dpm = getDevicePolicyManager();
-            if (pattern != null) {
-                // Update the device encryption password.
-                if (userId == UserHandle.USER_OWNER
-                        && LockPatternUtils.isDeviceEncryptionEnabled()) {
-                    final boolean required = isCredentialRequiredToDecrypt(true);
-                    if (!required) {
-                        clearEncryptionPassword();
-                    } else {
-                        String stringPattern = patternToString(pattern);
-                        updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
-                    }
-                }
 
-                setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
-                if (!isFallback) {
-                    deleteGallery(userId);
-                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
-                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
-                            pattern.size(), 0, 0, 0, 0, 0, 0, userId);
+            // Update the device encryption password.
+            if (userId == UserHandle.USER_OWNER
+                    && LockPatternUtils.isDeviceEncryptionEnabled()) {
+                final boolean required = isCredentialRequiredToDecrypt(true);
+                if (!required) {
+                    clearEncryptionPassword();
                 } else {
-                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, userId);
-                    setLong(PASSWORD_TYPE_ALTERNATE_KEY,
-                            DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
-                    finishBiometricWeak(userId);
-                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            0, 0, 0, 0, 0, 0, 0, userId);
+                    String stringPattern = patternToString(pattern);
+                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
                 }
-            } else {
-                dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
-                        0, 0, 0, 0, 0, userId);
             }
+
+            setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
+
+            setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
+            dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
+                    pattern.size(), 0, 0, 0, 0, 0, 0, userId);
             onAfterChangingPassword(userId);
         } catch (RemoteException re) {
             Log.e(TAG, "Couldn't save lock pattern " + re);
         }
     }
 
-    private void updateCryptoUserInfo() {
-        int userId = getCurrentOrCallingUserId();
+    private void updateCryptoUserInfo(int userId) {
         if (userId != UserHandle.USER_OWNER) {
             return;
         }
 
-        final String ownerInfo = isOwnerInfoEnabled() ? getOwnerInfo(userId) : "";
+        final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
 
         IBinder service = ServiceManager.getService("mount");
         if (service == null) {
@@ -647,20 +544,25 @@
 
     public void setOwnerInfo(String info, int userId) {
         setString(LOCK_SCREEN_OWNER_INFO, info, userId);
-        updateCryptoUserInfo();
+        updateCryptoUserInfo(userId);
     }
 
     public void setOwnerInfoEnabled(boolean enabled) {
-        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
-        updateCryptoUserInfo();
+        int userId = getCurrentOrCallingUserId();
+        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
+        updateCryptoUserInfo(userId);
     }
 
     public String getOwnerInfo(int userId) {
-        return getString(LOCK_SCREEN_OWNER_INFO);
+        return getString(LOCK_SCREEN_OWNER_INFO, userId);
     }
 
     public boolean isOwnerInfoEnabled() {
-        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
+        return isOwnerInfoEnabled(getCurrentOrCallingUserId());
+    }
+
+    private boolean isOwnerInfoEnabled(int userId) {
+        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false, userId);
     }
 
     /**
@@ -786,7 +688,7 @@
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      */
     public void saveLockPassword(String password, int quality) {
-        this.saveLockPassword(password, quality, false, getCurrentOrCallingUserId());
+        saveLockPassword(password, quality, getCurrentOrCallingUserId());
     }
 
     /**
@@ -795,120 +697,88 @@
      * pattern.
      * @param password The password to save
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
-     * @param isFallback Specifies if this is a fallback to biometric weak
-     */
-    public void saveLockPassword(String password, int quality, boolean isFallback) {
-        saveLockPassword(password, quality, isFallback, getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Save a lock password.  Does not ensure that the password is as good
-     * as the requested mode, but will adjust the mode to be as good as the
-     * pattern.
-     * @param password The password to save
-     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
-     * @param isFallback Specifies if this is a fallback to biometric weak
      * @param userHandle The userId of the user to change the password for
      */
-    public void saveLockPassword(String password, int quality, boolean isFallback, int userHandle) {
+    public void saveLockPassword(String password, int quality, int userHandle) {
         try {
             DevicePolicyManager dpm = getDevicePolicyManager();
-            if (!TextUtils.isEmpty(password)) {
-                getLockSettings().setLockPassword(password, userHandle);
-                int computedQuality = computePasswordQuality(password);
-
-                // Update the device encryption password.
-                if (userHandle == UserHandle.USER_OWNER
-                        && LockPatternUtils.isDeviceEncryptionEnabled()) {
-                    if (!isCredentialRequiredToDecrypt(true)) {
-                        clearEncryptionPassword();
-                    } else {
-                        boolean numeric = computedQuality
-                                == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-                        boolean numericComplex = computedQuality
-                                == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
-                        int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
-                                : StorageManager.CRYPT_TYPE_PASSWORD;
-                        updateEncryptionPassword(type, password);
-                    }
-                }
-
-                if (!isFallback) {
-                    deleteGallery(userHandle);
-                    setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
-                    if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                        int letters = 0;
-                        int uppercase = 0;
-                        int lowercase = 0;
-                        int numbers = 0;
-                        int symbols = 0;
-                        int nonletter = 0;
-                        for (int i = 0; i < password.length(); i++) {
-                            char c = password.charAt(i);
-                            if (c >= 'A' && c <= 'Z') {
-                                letters++;
-                                uppercase++;
-                            } else if (c >= 'a' && c <= 'z') {
-                                letters++;
-                                lowercase++;
-                            } else if (c >= '0' && c <= '9') {
-                                numbers++;
-                                nonletter++;
-                            } else {
-                                symbols++;
-                                nonletter++;
-                            }
-                        }
-                        dpm.setActivePasswordState(Math.max(quality, computedQuality),
-                                password.length(), letters, uppercase, lowercase,
-                                numbers, symbols, nonletter, userHandle);
-                    } else {
-                        // The password is not anything.
-                        dpm.setActivePasswordState(
-                                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                                0, 0, 0, 0, 0, 0, 0, userHandle);
-                    }
-                } else {
-                    // Case where it's a fallback for biometric weak
-                    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            userHandle);
-                    setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
-                            userHandle);
-                    finishBiometricWeak(userHandle);
-                    dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
-                            0, 0, 0, 0, 0, 0, 0, userHandle);
-                }
-                // Add the password to the password history. We assume all
-                // password hashes have the same length for simplicity of implementation.
-                String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
-                if (passwordHistory == null) {
-                    passwordHistory = "";
-                }
-                int passwordHistoryLength = getRequestedPasswordHistoryLength();
-                if (passwordHistoryLength == 0) {
-                    passwordHistory = "";
-                } else {
-                    byte[] hash = passwordToHash(password, userHandle);
-                    passwordHistory = new String(hash) + "," + passwordHistory;
-                    // Cut it to contain passwordHistoryLength hashes
-                    // and passwordHistoryLength -1 commas.
-                    passwordHistory = passwordHistory.substring(0, Math.min(hash.length
-                            * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
-                            .length()));
-                }
-                setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
-            } else {
-                // Empty password
-                getLockSettings().setLockPassword(null, userHandle);
-                if (userHandle == UserHandle.USER_OWNER) {
-                    // Set the encryption password to default.
-                    updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
-                }
-
-                dpm.setActivePasswordState(
-                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
-                        userHandle);
+            if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
+                throw new IllegalArgumentException("password must not be null and at least "
+                        + "of length " + MIN_LOCK_PASSWORD_SIZE);
             }
+
+            getLockSettings().setLockPassword(password, userHandle);
+            int computedQuality = computePasswordQuality(password);
+
+            // Update the device encryption password.
+            if (userHandle == UserHandle.USER_OWNER
+                    && LockPatternUtils.isDeviceEncryptionEnabled()) {
+                if (!isCredentialRequiredToDecrypt(true)) {
+                    clearEncryptionPassword();
+                } else {
+                    boolean numeric = computedQuality
+                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+                    boolean numericComplex = computedQuality
+                            == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+                    int type = numeric || numericComplex ? StorageManager.CRYPT_TYPE_PIN
+                            : StorageManager.CRYPT_TYPE_PASSWORD;
+                    updateEncryptionPassword(type, password);
+                }
+            }
+
+            setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
+            if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                int letters = 0;
+                int uppercase = 0;
+                int lowercase = 0;
+                int numbers = 0;
+                int symbols = 0;
+                int nonletter = 0;
+                for (int i = 0; i < password.length(); i++) {
+                    char c = password.charAt(i);
+                    if (c >= 'A' && c <= 'Z') {
+                        letters++;
+                        uppercase++;
+                    } else if (c >= 'a' && c <= 'z') {
+                        letters++;
+                        lowercase++;
+                    } else if (c >= '0' && c <= '9') {
+                        numbers++;
+                        nonletter++;
+                    } else {
+                        symbols++;
+                        nonletter++;
+                    }
+                }
+                dpm.setActivePasswordState(Math.max(quality, computedQuality),
+                        password.length(), letters, uppercase, lowercase,
+                        numbers, symbols, nonletter, userHandle);
+            } else {
+                // The password is not anything.
+                dpm.setActivePasswordState(
+                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                        0, 0, 0, 0, 0, 0, 0, userHandle);
+            }
+
+            // Add the password to the password history. We assume all
+            // password hashes have the same length for simplicity of implementation.
+            String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
+            if (passwordHistory == null) {
+                passwordHistory = "";
+            }
+            int passwordHistoryLength = getRequestedPasswordHistoryLength(userHandle);
+            if (passwordHistoryLength == 0) {
+                passwordHistory = "";
+            } else {
+                byte[] hash = passwordToHash(password, userHandle);
+                passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory;
+                // Cut it to contain passwordHistoryLength hashes
+                // and passwordHistoryLength -1 commas.
+                passwordHistory = passwordHistory.substring(0, Math.min(hash.length
+                        * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory
+                        .length()));
+            }
+            setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
             onAfterChangingPassword(userHandle);
         } catch (RemoteException re) {
             // Cant do much
@@ -968,31 +838,8 @@
      * @return stored password quality
      */
     public int getKeyguardStoredPasswordQuality(int userHandle) {
-        int quality = (int) getLong(PASSWORD_TYPE_KEY,
+        return (int) getLong(PASSWORD_TYPE_KEY,
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
-        // If the user has chosen to use weak biometric sensor, then return the backup locking
-        // method and treat biometric as a special case.
-        if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
-            quality = (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
-                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
-        }
-        return quality;
-    }
-
-    /**
-     * @return true if the lockscreen method is set to biometric weak
-     */
-    public boolean usingBiometricWeak() {
-        return usingBiometricWeak(getCurrentOrCallingUserId());
-    }
-
-    /**
-     * @return true if the lockscreen method is set to biometric weak
-     */
-    public boolean usingBiometricWeak(int userId) {
-        int quality = (int) getLong(
-                PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
-        return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
     }
 
     /**
@@ -1001,6 +848,10 @@
      * @return The pattern.
      */
     public static List<LockPatternView.Cell> stringToPattern(String string) {
+        if (string == null) {
+            return null;
+        }
+
         List<LockPatternView.Cell> result = Lists.newArrayList();
 
         final byte[] bytes = string.getBytes();
@@ -1076,157 +927,100 @@
      * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash.
      * Not the most secure, but it is at least a second level of protection. First level is that
      * the file is in a location only readable by the system process.
+     *
      * @param password the gesture pattern.
+     *
      * @return the hash of the pattern in a byte array.
      */
     public byte[] passwordToHash(String password, int userId) {
         if (password == null) {
             return null;
         }
-        String algo = null;
-        byte[] hashed = null;
+
         try {
             byte[] saltedPassword = (password + getSalt(userId)).getBytes();
-            byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword);
-            byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword);
-            hashed = (toHex(sha1) + toHex(md5)).getBytes();
-        } catch (NoSuchAlgorithmException e) {
-            Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo);
-        }
-        return hashed;
-    }
+            byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
+            byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
 
-    private static String toHex(byte[] ary) {
-        final String hex = "0123456789ABCDEF";
-        String ret = "";
-        for (int i = 0; i < ary.length; i++) {
-            ret += hex.charAt((ary[i] >> 4) & 0xf);
-            ret += hex.charAt(ary[i] & 0xf);
+            byte[] combined = new byte[sha1.length + md5.length];
+            System.arraycopy(sha1, 0, combined, 0, sha1.length);
+            System.arraycopy(md5, 0, combined, sha1.length, md5.length);
+
+            final char[] hexEncoded = HexEncoding.encode(combined);
+            return new String(hexEncoded).getBytes(StandardCharsets.UTF_8);
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError("Missing digest algorithm: ", e);
         }
-        return ret;
     }
 
     /**
-     * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
+     * @return Whether the lock screen is secured.
+     */
+    public boolean isSecure() {
+        return isSecure(getCurrentOrCallingUserId());
+    }
+
+    /**
+     * @param userId the user for which to report the value
+     * @return Whether the lock screen is secured.
+     */
+    public boolean isSecure(int userId) {
+        int mode = getKeyguardStoredPasswordQuality(userId);
+        return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
+    }
+
+    /**
+     * @return Whether the lock password is enabled
      */
     public boolean isLockPasswordEnabled() {
-        long mode = getLong(PASSWORD_TYPE_KEY, 0);
-        long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
+        return isLockPasswordEnabled(getCurrentOrCallingUserId());
+    }
+
+    public boolean isLockPasswordEnabled(int userId) {
+        return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
+    }
+
+    private boolean isLockPasswordEnabled(int mode, int userId) {
         final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
                 || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-        final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
-                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
-                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
-                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-
-        return savedPasswordExists() && (passwordEnabled ||
-                (usingBiometricWeak() && backupEnabled));
+        return passwordEnabled && savedPasswordExists(userId);
     }
 
     /**
-     * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
+     * @return Whether the lock pattern is enabled
      */
     public boolean isLockPatternEnabled() {
         return isLockPatternEnabled(getCurrentOrCallingUserId());
     }
 
-    /**
-     * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
-     */
     public boolean isLockPatternEnabled(int userId) {
-        final boolean backupEnabled =
-                getLong(PASSWORD_TYPE_ALTERNATE_KEY,
-                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId)
-                                == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-
-        return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false, userId)
-                && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
-                        userId) == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
-                        || (usingBiometricWeak(userId) && backupEnabled));
+        return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
     }
 
-    /**
-     * @return Whether biometric weak lock is installed and that the front facing camera exists
-     */
-    public boolean isBiometricWeakInstalled() {
-        // Check that it's installed
-        PackageManager pm = mContext.getPackageManager();
-        try {
-            pm.getPackageInfo("com.android.facelock", PackageManager.GET_ACTIVITIES);
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-
-        // Check that the camera is enabled
-        if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
-            return false;
-        }
-        if (getDevicePolicyManager().getCameraDisabled(null, getCurrentOrCallingUserId())) {
-            return false;
-        }
-
-        // TODO: If we decide not to proceed with Face Unlock as a trustlet, this must be changed
-        // back to returning true.  If we become certain that Face Unlock will be a trustlet, this
-        // entire function and a lot of other code can be removed.
-        if (DEBUG) Log.d(TAG, "Forcing isBiometricWeakInstalled() to return false to disable it");
-        return false;
-    }
-
-    /**
-     * Set whether biometric weak liveliness is enabled.
-     */
-    public void setBiometricWeakLivelinessEnabled(boolean enabled) {
-        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
-        long newFlag;
-        if (enabled) {
-            newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
-        } else {
-            newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
-        }
-        setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
-    }
-
-    /**
-     * @return Whether the biometric weak liveliness is enabled.
-     */
-    public boolean isBiometricWeakLivelinessEnabled() {
-        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
-        return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
-    }
-
-    /**
-     * Set whether the lock pattern is enabled.
-     */
-    public void setLockPatternEnabled(boolean enabled) {
-        setLockPatternEnabled(enabled, getCurrentOrCallingUserId());
-    }
-
-    /**
-     * Set whether the lock pattern is enabled.
-     */
-    public void setLockPatternEnabled(boolean enabled, int userHandle) {
-        setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled, userHandle);
+    private boolean isLockPatternEnabled(int mode, int userId) {
+        return mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
+                && savedPatternExists(userId);
     }
 
     /**
      * @return Whether the visible pattern is enabled.
      */
     public boolean isVisiblePatternEnabled() {
-        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false);
+        return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, getCurrentOrCallingUserId());
     }
 
     /**
      * Set whether the visible pattern is enabled.
      */
     public void setVisiblePatternEnabled(boolean enabled) {
-        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
+        int userId = getCurrentOrCallingUserId();
+
+        setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
 
         // Update for crypto if owner
-        int userId = getCurrentOrCallingUserId();
         if (userId != UserHandle.USER_OWNER) {
             return;
         }
@@ -1260,7 +1054,7 @@
      */
     public long setLockoutAttemptDeadline() {
         final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
-        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
+        setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, getCurrentOrCallingUserId());
         return deadline;
     }
 
@@ -1270,7 +1064,7 @@
      *   enter a pattern.
      */
     public long getLockoutAttemptDeadline() {
-        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
+        final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, getCurrentOrCallingUserId());
         final long now = SystemClock.elapsedRealtime();
         if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
             return 0L;
@@ -1278,51 +1072,6 @@
         return deadline;
     }
 
-    /**
-     * @return Whether the user is permanently locked out until they verify their
-     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
-     *   attempts.
-     */
-    public boolean isPermanentlyLocked() {
-        return getBoolean(LOCKOUT_PERMANENT_KEY, false);
-    }
-
-    /**
-     * Set the state of whether the device is permanently locked, meaning the user
-     * must authenticate via other means.
-     *
-     * @param locked Whether the user is permanently locked out until they verify their
-     *   credentials.  Occurs after {@link #FAILED_ATTEMPTS_BEFORE_RESET} failed
-     *   attempts.
-     */
-    public void setPermanentlyLocked(boolean locked) {
-        setBoolean(LOCKOUT_PERMANENT_KEY, locked);
-    }
-
-    public boolean isEmergencyCallCapable() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable);
-    }
-
-    public boolean isPukUnlockScreenEnable() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enable_puk_unlock_screen);
-    }
-
-    public boolean isEmergencyCallEnabledWhileSimLocked() {
-        return mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
-    }
-
-    /**
-     * @return A formatted string of the next alarm (for showing on the lock screen),
-     *   or null if there is no next alarm.
-     */
-    public AlarmManager.AlarmClockInfo getNextAlarm() {
-        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        return alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
-    }
-
     private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
         try {
             return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
@@ -1331,10 +1080,6 @@
         }
     }
 
-    private boolean getBoolean(String secureSettingKey, boolean defaultValue) {
-        return getBoolean(secureSettingKey, defaultValue, getCurrentOrCallingUserId());
-    }
-
     private void setBoolean(String secureSettingKey, boolean enabled, int userId) {
         try {
             getLockSettings().setBoolean(secureSettingKey, enabled, userId);
@@ -1344,144 +1089,6 @@
         }
     }
 
-    private void setBoolean(String secureSettingKey, boolean enabled) {
-        setBoolean(secureSettingKey, enabled, getCurrentOrCallingUserId());
-    }
-
-    public int[] getAppWidgets() {
-        return getAppWidgets(UserHandle.USER_CURRENT);
-    }
-
-    private int[] getAppWidgets(int userId) {
-        String appWidgetIdString = Settings.Secure.getStringForUser(
-                mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, userId);
-        String delims = ",";
-        if (appWidgetIdString != null && appWidgetIdString.length() > 0) {
-            String[] appWidgetStringIds = appWidgetIdString.split(delims);
-            int[] appWidgetIds = new int[appWidgetStringIds.length];
-            for (int i = 0; i < appWidgetStringIds.length; i++) {
-                String appWidget = appWidgetStringIds[i];
-                try {
-                    appWidgetIds[i] = Integer.decode(appWidget);
-                } catch (NumberFormatException e) {
-                    Log.d(TAG, "Error when parsing widget id " + appWidget);
-                    return null;
-                }
-            }
-            return appWidgetIds;
-        }
-        return new int[0];
-    }
-
-    private static String combineStrings(int[] list, String separator) {
-        int listLength = list.length;
-
-        switch (listLength) {
-            case 0: {
-                return "";
-            }
-            case 1: {
-                return Integer.toString(list[0]);
-            }
-        }
-
-        int strLength = 0;
-        int separatorLength = separator.length();
-
-        String[] stringList = new String[list.length];
-        for (int i = 0; i < listLength; i++) {
-            stringList[i] = Integer.toString(list[i]);
-            strLength += stringList[i].length();
-            if (i < listLength - 1) {
-                strLength += separatorLength;
-            }
-        }
-
-        StringBuilder sb = new StringBuilder(strLength);
-
-        for (int i = 0; i < listLength; i++) {
-            sb.append(list[i]);
-            if (i < listLength - 1) {
-                sb.append(separator);
-            }
-        }
-
-        return sb.toString();
-    }
-
-    // appwidget used when appwidgets are disabled (we make an exception for
-    // default clock widget)
-    public void writeFallbackAppWidgetId(int appWidgetId) {
-        Settings.Secure.putIntForUser(mContentResolver,
-                Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
-                appWidgetId,
-                UserHandle.USER_CURRENT);
-    }
-
-    // appwidget used when appwidgets are disabled (we make an exception for
-    // default clock widget)
-    public int getFallbackAppWidgetId() {
-        return Settings.Secure.getIntForUser(
-                mContentResolver,
-                Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID,
-                AppWidgetManager.INVALID_APPWIDGET_ID,
-                UserHandle.USER_CURRENT);
-    }
-
-    private void writeAppWidgets(int[] appWidgetIds) {
-        Settings.Secure.putStringForUser(mContentResolver,
-                        Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS,
-                        combineStrings(appWidgetIds, ","),
-                        UserHandle.USER_CURRENT);
-    }
-
-    // TODO: log an error if this returns false
-    public boolean addAppWidget(int widgetId, int index) {
-        int[] widgets = getAppWidgets();
-        if (widgets == null) {
-            return false;
-        }
-        if (index < 0 || index > widgets.length) {
-            return false;
-        }
-        int[] newWidgets = new int[widgets.length + 1];
-        for (int i = 0, j = 0; i < newWidgets.length; i++) {
-            if (index == i) {
-                newWidgets[i] = widgetId;
-                i++;
-            }
-            if (i < newWidgets.length) {
-                newWidgets[i] = widgets[j];
-                j++;
-            }
-        }
-        writeAppWidgets(newWidgets);
-        return true;
-    }
-
-    public boolean removeAppWidget(int widgetId) {
-        int[] widgets = getAppWidgets();
-
-        if (widgets.length == 0) {
-            return false;
-        }
-
-        int[] newWidgets = new int[widgets.length - 1];
-        for (int i = 0, j = 0; i < widgets.length; i++) {
-            if (widgets[i] == widgetId) {
-                // continue...
-            } else if (j >= newWidgets.length) {
-                // we couldn't find the widget
-                return false;
-            } else {
-                newWidgets[j] = widgets[i];
-                j++;
-            }
-        }
-        writeAppWidgets(newWidgets);
-        return true;
-    }
-
     private long getLong(String secureSettingKey, long defaultValue, int userHandle) {
         try {
             return getLockSettings().getLong(secureSettingKey, defaultValue, userHandle);
@@ -1490,19 +1097,6 @@
         }
     }
 
-    private long getLong(String secureSettingKey, long defaultValue) {
-        try {
-            return getLockSettings().getLong(secureSettingKey, defaultValue,
-                    getCurrentOrCallingUserId());
-        } catch (RemoteException re) {
-            return defaultValue;
-        }
-    }
-
-    private void setLong(String secureSettingKey, long value) {
-        setLong(secureSettingKey, value, getCurrentOrCallingUserId());
-    }
-
     private void setLong(String secureSettingKey, long value, int userHandle) {
         try {
             getLockSettings().setLong(secureSettingKey, value, userHandle);
@@ -1512,10 +1106,6 @@
         }
     }
 
-    private String getString(String secureSettingKey) {
-        return getString(secureSettingKey, getCurrentOrCallingUserId());
-    }
-
     private String getString(String secureSettingKey, int userHandle) {
         try {
             return getLockSettings().getString(secureSettingKey, null, userHandle);
@@ -1533,134 +1123,13 @@
         }
     }
 
-    public boolean isSecure() {
-        return isSecure(getCurrentOrCallingUserId());
-    }
-
-    public boolean isSecure(int userId) {
-        long mode = getKeyguardStoredPasswordQuality(userId);
-        final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-        final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
-                || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-        final boolean secure =
-                isPattern && isLockPatternEnabled(userId) && savedPatternExists(userId)
-                || isPassword && savedPasswordExists(userId);
-        return secure;
-    }
-
-    /**
-     * Sets the emergency button visibility based on isEmergencyCallCapable().
-     *
-     * If the emergency button is visible, sets the text on the emergency button
-     * to indicate what action will be taken.
-     *
-     * If there's currently a call in progress, the button will take them to the call
-     * @param button The button to update
-     * @param shown Indicates whether the given screen wants the emergency button to show at all
-     * @param showIcon Indicates whether to show a phone icon for the button.
-     */
-    public void updateEmergencyCallButtonState(Button button, boolean shown, boolean showIcon) {
-        if (isEmergencyCallCapable() && shown) {
-            button.setVisibility(View.VISIBLE);
-        } else {
-            button.setVisibility(View.GONE);
-            return;
-        }
-
-        int textId;
-        if (isInCall()) {
-            // show "return to call" text and show phone icon
-            textId = R.string.lockscreen_return_to_call;
-            int phoneCallIcon = showIcon ? R.drawable.stat_sys_phone_call : 0;
-            button.setCompoundDrawablesWithIntrinsicBounds(phoneCallIcon, 0, 0, 0);
-        } else {
-            textId = R.string.lockscreen_emergency_call;
-            int emergencyIcon = showIcon ? R.drawable.ic_emergency : 0;
-            button.setCompoundDrawablesWithIntrinsicBounds(emergencyIcon, 0, 0, 0);
-        }
-        button.setText(textId);
-    }
-
-    /**
-     * Resumes a call in progress. Typically launched from the EmergencyCall button
-     * on various lockscreens.
-     */
-    public void resumeCall() {
-        getTelecommManager().showInCallScreen(false);
-    }
-
-    /**
-     * @return {@code true} if there is a call currently in progress, {@code false} otherwise.
-     */
-    public boolean isInCall() {
-        return getTelecommManager().isInCall();
-    }
-
-    private TelecomManager getTelecommManager() {
-        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-    }
-
-    private void finishBiometricWeak(int userId) {
-        setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true, userId);
-
-        // Launch intent to show final screen, this also
-        // moves the temporary gallery to the actual gallery
-        Intent intent = new Intent();
-        intent.setClassName("com.android.facelock",
-                "com.android.facelock.SetupEndScreen");
-        mContext.startActivityAsUser(intent, new UserHandle(userId));
-    }
-
     public void setPowerButtonInstantlyLocks(boolean enabled) {
-        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled);
+        setBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, enabled, getCurrentOrCallingUserId());
     }
 
     public boolean getPowerButtonInstantlyLocks() {
-        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true);
-    }
-
-    public static boolean isSafeModeEnabled() {
-        try {
-            return IWindowManager.Stub.asInterface(
-                    ServiceManager.getService("window")).isSafeModeEnabled();
-        } catch (RemoteException e) {
-            // Shouldn't happen!
-        }
-        return false;
-    }
-
-    /**
-     * Determine whether the user has selected any non-system widgets in keyguard
-     *
-     * @return true if widgets have been selected
-     */
-    public boolean hasWidgetsEnabledInKeyguard(int userid) {
-        int widgets[] = getAppWidgets(userid);
-        for (int i = 0; i < widgets.length; i++) {
-            if (widgets[i] > 0) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean getWidgetsEnabled() {
-        return getWidgetsEnabled(getCurrentOrCallingUserId());
-    }
-
-    public boolean getWidgetsEnabled(int userId) {
-        return getBoolean(LOCKSCREEN_WIDGETS_ENABLED, false, userId);
-    }
-
-    public void setWidgetsEnabled(boolean enabled) {
-        setWidgetsEnabled(enabled, getCurrentOrCallingUserId());
-    }
-
-    public void setWidgetsEnabled(boolean enabled, int userId) {
-        setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
+        return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true,
+                getCurrentOrCallingUserId());
     }
 
     public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 9fa6882..52bbabf 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -65,8 +65,8 @@
 
     private boolean mDrawingProfilingStarted = false;
 
-    private Paint mPaint = new Paint();
-    private Paint mPathPaint = new Paint();
+    private final Paint mPaint = new Paint();
+    private final Paint mPathPaint = new Paint();
 
     /**
      * How many milliseconds we spend animating each circle of a lock pattern
@@ -82,7 +82,7 @@
     private static final float DRAG_THRESHHOLD = 0.0f;
 
     private OnPatternListener mOnPatternListener;
-    private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
+    private final ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
 
     /**
      * Lookup table for the circles of the pattern we are currently drawing.
@@ -90,7 +90,7 @@
      * in which case we use this to hold the cells we are drawing for the in
      * progress animation.
      */
-    private boolean[][] mPatternDrawLookup = new boolean[3][3];
+    private final boolean[][] mPatternDrawLookup = new boolean[3][3];
 
     /**
      * the in progress point:
@@ -122,24 +122,27 @@
     private int mErrorColor;
     private int mSuccessColor;
 
-    private Interpolator mFastOutSlowInInterpolator;
-    private Interpolator mLinearOutSlowInInterpolator;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private final Interpolator mLinearOutSlowInInterpolator;
 
     /**
      * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
      */
-    public static class Cell {
-        int row;
-        int column;
+    public static final class Cell {
+        final int row;
+        final int column;
 
         // keep # objects limited to 9
-        static Cell[][] sCells = new Cell[3][3];
-        static {
+        private static final Cell[][] sCells = createCells();
+
+        private static Cell[][] createCells() {
+            Cell[][] res = new Cell[3][3];
             for (int i = 0; i < 3; i++) {
                 for (int j = 0; j < 3; j++) {
-                    sCells[i][j] = new Cell(i, j);
+                    res[i][j] = new Cell(i, j);
                 }
             }
+            return res;
         }
 
         /**
@@ -160,11 +163,7 @@
             return column;
         }
 
-        /**
-         * @param row The row of the cell.
-         * @param column The column of the cell.
-         */
-        public static synchronized Cell of(int row, int column) {
+        public static Cell of(int row, int column) {
             checkRange(row, column);
             return sCells[row][column];
         }
@@ -178,6 +177,7 @@
             }
         }
 
+        @Override
         public String toString() {
             return "(row=" + row + ",clmn=" + column + ")";
         }
@@ -722,7 +722,7 @@
                 handleActionDown(event);
                 return true;
             case MotionEvent.ACTION_UP:
-                handleActionUp(event);
+                handleActionUp();
                 return true;
             case MotionEvent.ACTION_MOVE:
                 handleActionMove(event);
@@ -812,7 +812,7 @@
         announceForAccessibility(mContext.getString(resId));
     }
 
-    private void handleActionUp(MotionEvent event) {
+    private void handleActionUp() {
         // report pattern detected
         if (!mPattern.isEmpty()) {
             mPatternInProgress = false;
@@ -1119,12 +1119,15 @@
             dest.writeValue(mTactileFeedbackEnabled);
         }
 
+        @SuppressWarnings({ "unused", "hiding" }) // Found using reflection
         public static final Parcelable.Creator<SavedState> CREATOR =
                 new Creator<SavedState>() {
+                    @Override
                     public SavedState createFromParcel(Parcel in) {
                         return new SavedState(in);
                     }
 
+                    @Override
                     public SavedState[] newArray(int size) {
                         return new SavedState[size];
                     }
diff --git a/core/java/com/android/internal/widget/PagerAdapter.java b/core/java/com/android/internal/widget/PagerAdapter.java
new file mode 100644
index 0000000..910a720
--- /dev/null
+++ b/core/java/com/android/internal/widget/PagerAdapter.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.database.DataSetObservable;
+import android.database.DataSetObserver;
+import android.os.Parcelable;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Base class providing the adapter to populate pages inside of
+ * a {@link android.support.v4.view.ViewPager}.  You will most likely want to use a more
+ * specific implementation of this, such as
+ * {@link android.support.v4.app.FragmentPagerAdapter} or
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}.
+ *
+ * <p>When you implement a PagerAdapter, you must override the following methods
+ * at minimum:</p>
+ * <ul>
+ * <li>{@link #instantiateItem(android.view.ViewGroup, int)}</li>
+ * <li>{@link #destroyItem(android.view.ViewGroup, int, Object)}</li>
+ * <li>{@link #getCount()}</li>
+ * <li>{@link #isViewFromObject(android.view.View, Object)}</li>
+ * </ul>
+ *
+ * <p>PagerAdapter is more general than the adapters used for
+ * {@link android.widget.AdapterView AdapterViews}. Instead of providing a
+ * View recycling mechanism directly ViewPager uses callbacks to indicate the
+ * steps taken during an update. A PagerAdapter may implement a form of View
+ * recycling if desired or use a more sophisticated method of managing page
+ * Views such as Fragment transactions where each page is represented by its
+ * own Fragment.</p>
+ *
+ * <p>ViewPager associates each page with a key Object instead of working with
+ * Views directly. This key is used to track and uniquely identify a given page
+ * independent of its position in the adapter. A call to the PagerAdapter method
+ * {@link #startUpdate(android.view.ViewGroup)} indicates that the contents of the ViewPager
+ * are about to change. One or more calls to {@link #instantiateItem(android.view.ViewGroup, int)}
+ * and/or {@link #destroyItem(android.view.ViewGroup, int, Object)} will follow, and the end
+ * of an update will be signaled by a call to {@link #finishUpdate(android.view.ViewGroup)}.
+ * By the time {@link #finishUpdate(android.view.ViewGroup) finishUpdate} returns the views
+ * associated with the key objects returned by
+ * {@link #instantiateItem(android.view.ViewGroup, int) instantiateItem} should be added to
+ * the parent ViewGroup passed to these methods and the views associated with
+ * the keys passed to {@link #destroyItem(android.view.ViewGroup, int, Object) destroyItem}
+ * should be removed. The method {@link #isViewFromObject(android.view.View, Object)} identifies
+ * whether a page View is associated with a given key object.</p>
+ *
+ * <p>A very simple PagerAdapter may choose to use the page Views themselves
+ * as key objects, returning them from {@link #instantiateItem(android.view.ViewGroup, int)}
+ * after creation and adding them to the parent ViewGroup. A matching
+ * {@link #destroyItem(android.view.ViewGroup, int, Object)} implementation would remove the
+ * View from the parent ViewGroup and {@link #isViewFromObject(android.view.View, Object)}
+ * could be implemented as <code>return view == object;</code>.</p>
+ *
+ * <p>PagerAdapter supports data set changes. Data set changes must occur on the
+ * main thread and must end with a call to {@link #notifyDataSetChanged()} similar
+ * to AdapterView adapters derived from {@link android.widget.BaseAdapter}. A data
+ * set change may involve pages being added, removed, or changing position. The
+ * ViewPager will keep the current page active provided the adapter implements
+ * the method {@link #getItemPosition(Object)}.</p>
+ */
+public abstract class PagerAdapter {
+    private DataSetObservable mObservable = new DataSetObservable();
+
+    public static final int POSITION_UNCHANGED = -1;
+    public static final int POSITION_NONE = -2;
+
+    /**
+     * Return the number of views available.
+     */
+    public abstract int getCount();
+
+    /**
+     * Called when a change in the shown pages is going to start being made.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     */
+    public void startUpdate(ViewGroup container) {
+        startUpdate((View) container);
+    }
+
+    /**
+     * Create the page for the given position.  The adapter is responsible
+     * for adding the view to the container given here, although it only
+     * must ensure this is done by the time it returns from
+     * {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View in which the page will be shown.
+     * @param position The page position to be instantiated.
+     * @return Returns an Object representing the new page.  This does not
+     * need to be a View, but can be some other container of the page.
+     */
+    public Object instantiateItem(ViewGroup container, int position) {
+        return instantiateItem((View) container, position);
+    }
+
+    /**
+     * Remove a page for the given position.  The adapter is responsible
+     * for removing the view from its container, although it only must ensure
+     * this is done by the time it returns from {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position to be removed.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     */
+    public void destroyItem(ViewGroup container, int position, Object object) {
+        destroyItem((View) container, position, object);
+    }
+
+    /**
+     * Called to inform the adapter of which item is currently considered to
+     * be the "primary", that is the one show to the user as the current page.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position that is now the primary.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     */
+    public void setPrimaryItem(ViewGroup container, int position, Object object) {
+        setPrimaryItem((View) container, position, object);
+    }
+
+    /**
+     * Called when the a change in the shown pages has been completed.  At this
+     * point you must ensure that all of the pages have actually been added or
+     * removed from the container as appropriate.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     */
+    public void finishUpdate(ViewGroup container) {
+        finishUpdate((View) container);
+    }
+
+    /**
+     * Called when a change in the shown pages is going to start being made.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     *
+     * @deprecated Use {@link #startUpdate(android.view.ViewGroup)}
+     */
+    public void startUpdate(View container) {
+    }
+
+    /**
+     * Create the page for the given position.  The adapter is responsible
+     * for adding the view to the container given here, although it only
+     * must ensure this is done by the time it returns from
+     * {@link #finishUpdate(android.view.ViewGroup)}.
+     *
+     * @param container The containing View in which the page will be shown.
+     * @param position The page position to be instantiated.
+     * @return Returns an Object representing the new page.  This does not
+     * need to be a View, but can be some other container of the page.
+     *
+     * @deprecated Use {@link #instantiateItem(android.view.ViewGroup, int)}
+     */
+    public Object instantiateItem(View container, int position) {
+        throw new UnsupportedOperationException(
+                "Required method instantiateItem was not overridden");
+    }
+
+    /**
+     * Remove a page for the given position.  The adapter is responsible
+     * for removing the view from its container, although it only must ensure
+     * this is done by the time it returns from {@link #finishUpdate(android.view.View)}.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position to be removed.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     *
+     * @deprecated Use {@link #destroyItem(android.view.ViewGroup, int, Object)}
+     */
+    public void destroyItem(View container, int position, Object object) {
+        throw new UnsupportedOperationException("Required method destroyItem was not overridden");
+    }
+
+    /**
+     * Called to inform the adapter of which item is currently considered to
+     * be the "primary", that is the one show to the user as the current page.
+     *
+     * @param container The containing View from which the page will be removed.
+     * @param position The page position that is now the primary.
+     * @param object The same object that was returned by
+     * {@link #instantiateItem(android.view.View, int)}.
+     *
+     * @deprecated Use {@link #setPrimaryItem(android.view.ViewGroup, int, Object)}
+     */
+    public void setPrimaryItem(View container, int position, Object object) {
+    }
+
+    /**
+     * Called when the a change in the shown pages has been completed.  At this
+     * point you must ensure that all of the pages have actually been added or
+     * removed from the container as appropriate.
+     * @param container The containing View which is displaying this adapter's
+     * page views.
+     *
+     * @deprecated Use {@link #finishUpdate(android.view.ViewGroup)}
+     */
+    public void finishUpdate(View container) {
+    }
+
+    /**
+     * Determines whether a page View is associated with a specific key object
+     * as returned by {@link #instantiateItem(android.view.ViewGroup, int)}. This method is
+     * required for a PagerAdapter to function properly.
+     *
+     * @param view Page View to check for association with <code>object</code>
+     * @param object Object to check for association with <code>view</code>
+     * @return true if <code>view</code> is associated with the key object <code>object</code>
+     */
+    public abstract boolean isViewFromObject(View view, Object object);
+
+    /**
+     * Save any instance state associated with this adapter and its pages that should be
+     * restored if the current UI state needs to be reconstructed.
+     *
+     * @return Saved state for this adapter
+     */
+    public Parcelable saveState() {
+        return null;
+    }
+
+    /**
+     * Restore any instance state associated with this adapter and its pages
+     * that was previously saved by {@link #saveState()}.
+     *
+     * @param state State previously saved by a call to {@link #saveState()}
+     * @param loader A ClassLoader that should be used to instantiate any restored objects
+     */
+    public void restoreState(Parcelable state, ClassLoader loader) {
+    }
+
+    /**
+     * Called when the host view is attempting to determine if an item's position
+     * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given
+     * item has not changed or {@link #POSITION_NONE} if the item is no longer present
+     * in the adapter.
+     *
+     * <p>The default implementation assumes that items will never
+     * change position and always returns {@link #POSITION_UNCHANGED}.
+     *
+     * @param object Object representing an item, previously returned by a call to
+     *               {@link #instantiateItem(android.view.View, int)}.
+     * @return object's new position index from [0, {@link #getCount()}),
+     *         {@link #POSITION_UNCHANGED} if the object's position has not changed,
+     *         or {@link #POSITION_NONE} if the item is no longer present.
+     */
+    public int getItemPosition(Object object) {
+        return POSITION_UNCHANGED;
+    }
+
+    /**
+     * This method should be called by the application if the data backing this adapter has changed
+     * and associated views should update.
+     */
+    public void notifyDataSetChanged() {
+        mObservable.notifyChanged();
+    }
+
+    /**
+     * Register an observer to receive callbacks related to the adapter's data changing.
+     *
+     * @param observer The {@link android.database.DataSetObserver} which will receive callbacks.
+     */
+    public void registerDataSetObserver(DataSetObserver observer) {
+        mObservable.registerObserver(observer);
+    }
+
+    /**
+     * Unregister an observer from callbacks related to the adapter's data changing.
+     *
+     * @param observer The {@link android.database.DataSetObserver} which will be unregistered.
+     */
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        mObservable.unregisterObserver(observer);
+    }
+
+    /**
+     * This method may be called by the ViewPager to obtain a title string
+     * to describe the specified page. This method may return null
+     * indicating no title for this page. The default implementation returns
+     * null.
+     *
+     * @param position The position of the title requested
+     * @return A title for the requested page
+     */
+    public CharSequence getPageTitle(int position) {
+        return null;
+    }
+
+    /**
+     * Returns the proportional width of a given page as a percentage of the
+     * ViewPager's measured width from (0.f-1.f]
+     *
+     * @param position The position of the page requested
+     * @return Proportional width for the given page position
+     */
+    public float getPageWidth(int position) {
+        return 1.f;
+    }
+}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 4e48454..01e835b 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -593,15 +593,13 @@
     }
 
     @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(ResolverDrawerLayout.class.getName());
+    public CharSequence getAccessibilityClassName() {
+        return ResolverDrawerLayout.class.getName();
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(ResolverDrawerLayout.class.getName());
         if (isEnabled()) {
             if (mCollapseOffset != 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index d6bd1d6f..ffd9b24 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -31,7 +31,6 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
@@ -150,7 +149,9 @@
         addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
         if (mTabSpinner.getAdapter() == null) {
-            mTabSpinner.setAdapter(new TabAdapter());
+            final TabAdapter adapter = new TabAdapter(mContext);
+            adapter.setDropDownViewContext(mTabSpinner.getPopupContext());
+            mTabSpinner.setAdapter(adapter);
         }
         if (mTabSelector != null) {
             removeCallbacks(mTabSelector);
@@ -276,8 +277,8 @@
         }
     }
 
-    private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
-        final TabView tabView = new TabView(getContext(), tab, forAdapter);
+    private TabView createTabView(Context context, ActionBar.Tab tab, boolean forAdapter) {
+        final TabView tabView = new TabView(context, tab, forAdapter);
         if (forAdapter) {
             tabView.setBackgroundDrawable(null);
             tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
@@ -294,7 +295,7 @@
     }
 
     public void addTab(ActionBar.Tab tab, boolean setSelected) {
-        TabView tabView = createTabView(tab, false);
+        TabView tabView = createTabView(mContext, tab, false);
         mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0,
                 LayoutParams.MATCH_PARENT, 1));
         if (mTabSpinner != null) {
@@ -309,7 +310,7 @@
     }
 
     public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
-        final TabView tabView = createTabView(tab, false);
+        final TabView tabView = createTabView(mContext, tab, false);
         mTabLayout.addView(tabView, position, new LinearLayout.LayoutParams(
                 0, LayoutParams.MATCH_PARENT, 1));
         if (mTabSpinner != null) {
@@ -391,17 +392,9 @@
         }
 
         @Override
-        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(event);
+        public CharSequence getAccessibilityClassName() {
             // This view masquerades as an action bar tab.
-            event.setClassName(ActionBar.Tab.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
-            // This view masquerades as an action bar tab.
-            info.setClassName(ActionBar.Tab.class.getName());
+            return ActionBar.Tab.class.getName();
         }
 
         @Override
@@ -514,6 +507,16 @@
     }
 
     private class TabAdapter extends BaseAdapter {
+        private Context mDropDownContext;
+
+        public TabAdapter(Context context) {
+            setDropDownViewContext(context);
+        }
+
+        public void setDropDownViewContext(Context context) {
+            mDropDownContext = context;
+        }
+
         @Override
         public int getCount() {
             return mTabLayout.getChildCount();
@@ -532,7 +535,18 @@
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             if (convertView == null) {
-                convertView = createTabView((ActionBar.Tab) getItem(position), true);
+                convertView = createTabView(mContext, (ActionBar.Tab) getItem(position), true);
+            } else {
+                ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
+            }
+            return convertView;
+        }
+
+        @Override
+        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = createTabView(mDropDownContext,
+                        (ActionBar.Tab) getItem(position), true);
             } else {
                 ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
             }
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
deleted file mode 100644
index 5f3c5f9..0000000
--- a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import java.lang.Math;
-
-import com.android.internal.R;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.StateSet;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.widget.RemoteViews.RemoteView;
-
-/**
- * A layout that switches between its children based on the requested layout height.
- * Each child specifies its minimum and maximum valid height.  Results are undefined
- * if children specify overlapping ranges.  A child may specify the maximum height
- * as 'unbounded' to indicate that it is willing to be displayed arbitrarily tall.
- *
- * <p>
- * See {@link SizeAdaptiveLayout.LayoutParams} for a full description of the
- * layout parameters used by SizeAdaptiveLayout.
- */
-@RemoteView
-public class SizeAdaptiveLayout extends ViewGroup {
-
-    private static final String TAG = "SizeAdaptiveLayout";
-    private static final boolean DEBUG = false;
-    private static final boolean REPORT_BAD_BOUNDS = true;
-    private static final long CROSSFADE_TIME = 250;
-
-    // TypedArray indices
-    private static final int MIN_VALID_HEIGHT =
-            R.styleable.SizeAdaptiveLayout_Layout_layout_minHeight;
-    private static final int MAX_VALID_HEIGHT =
-            R.styleable.SizeAdaptiveLayout_Layout_layout_maxHeight;
-
-    // view state
-    private View mActiveChild;
-    private View mLastActive;
-
-    // animation state
-    private AnimatorSet mTransitionAnimation;
-    private AnimatorListener mAnimatorListener;
-    private ObjectAnimator mFadePanel;
-    private ObjectAnimator mFadeView;
-    private int mCanceledAnimationCount;
-    private View mEnteringView;
-    private View mLeavingView;
-    // View used to hide larger views under smaller ones to create a uniform crossfade
-    private View mModestyPanel;
-    private int mModestyPanelTop;
-
-    public SizeAdaptiveLayout(Context context) {
-        this(context, null);
-    }
-
-    public SizeAdaptiveLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SizeAdaptiveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public SizeAdaptiveLayout(
-            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        initialize();
-    }
-
-    private void initialize() {
-        mModestyPanel = new View(getContext());
-        // If the SizeAdaptiveLayout has a solid background, use it as a transition hint.
-        Drawable background = getBackground();
-        if (background instanceof StateListDrawable) {
-            StateListDrawable sld = (StateListDrawable) background;
-            sld.setState(StateSet.WILD_CARD);
-            background = sld.getCurrent();
-        }
-        if (background instanceof ColorDrawable) {
-            mModestyPanel.setBackgroundDrawable(background);
-        }
-        SizeAdaptiveLayout.LayoutParams layout =
-                new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                                    ViewGroup.LayoutParams.MATCH_PARENT);
-        mModestyPanel.setLayoutParams(layout);
-        addView(mModestyPanel);
-        mFadePanel = ObjectAnimator.ofFloat(mModestyPanel, "alpha", 0f);
-        mFadeView = ObjectAnimator.ofFloat(null, "alpha", 0f);
-        mAnimatorListener = new BringToFrontOnEnd();
-        mTransitionAnimation = new AnimatorSet();
-        mTransitionAnimation.play(mFadeView).with(mFadePanel);
-        mTransitionAnimation.setDuration(CROSSFADE_TIME);
-        mTransitionAnimation.addListener(mAnimatorListener);
-    }
-
-    /**
-     * Visible for testing
-     * @hide
-     */
-    public Animator getTransitionAnimation() {
-        return mTransitionAnimation;
-    }
-
-    /**
-     * Visible for testing
-     * @hide
-     */
-    public View getModestyPanel() {
-        return mModestyPanel;
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        mLastActive = null;
-        // make sure all views start off invisible.
-        for (int i = 0; i < getChildCount(); i++) {
-            getChildAt(i).setVisibility(View.GONE);
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (DEBUG) Log.d(TAG, this + " measure spec: " +
-                         MeasureSpec.toString(heightMeasureSpec));
-        View model = selectActiveChild(heightMeasureSpec);
-        if (model == null) {
-            setMeasuredDimension(0, 0);
-            return;
-        }
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) model.getLayoutParams();
-        if (DEBUG) Log.d(TAG, "active min: " + lp.minHeight + " max: " + lp.maxHeight);
-        measureChild(model, widthMeasureSpec, heightMeasureSpec);
-        int childHeight = model.getMeasuredHeight();
-        int childWidth = model.getMeasuredHeight();
-        int childState = combineMeasuredStates(0, model.getMeasuredState());
-        if (DEBUG) Log.d(TAG, "measured child at: " + childHeight);
-        int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState);
-        int resolvedHeight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
-        if (DEBUG) Log.d(TAG, "resolved to: " + resolvedHeight);
-        int boundedHeight = clampSizeToBounds(resolvedHeight, model);
-        if (DEBUG) Log.d(TAG, "bounded to: " + boundedHeight);
-        setMeasuredDimension(resolvedWidth, boundedHeight);
-    }
-
-    private int clampSizeToBounds(int measuredHeight, View child) {
-        SizeAdaptiveLayout.LayoutParams lp =
-                (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
-        int heightIn = View.MEASURED_SIZE_MASK & measuredHeight;
-        int height = Math.max(heightIn, lp.minHeight);
-        if (lp.maxHeight != SizeAdaptiveLayout.LayoutParams.UNBOUNDED) {
-            height = Math.min(height, lp.maxHeight);
-        }
-
-        if (REPORT_BAD_BOUNDS && heightIn != height) {
-            Log.d(TAG, this + "child view " + child + " " +
-                  "measured out of bounds at " + heightIn +"px " +
-                  "clamped to " + height + "px");
-        }
-
-        return height;
-    }
-
-    //TODO extend to width and height
-    private View selectActiveChild(int heightMeasureSpec) {
-        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        View unboundedView = null;
-        View tallestView = null;
-        int tallestViewSize = 0;
-        View smallestView = null;
-        int smallestViewSize = Integer.MAX_VALUE;
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child != mModestyPanel) {
-                SizeAdaptiveLayout.LayoutParams lp =
-                    (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
-                if (DEBUG) Log.d(TAG, "looking at " + i +
-                                 " with min: " + lp.minHeight +
-                                 " max: " +  lp.maxHeight);
-                if (lp.maxHeight == SizeAdaptiveLayout.LayoutParams.UNBOUNDED &&
-                    unboundedView == null) {
-                    unboundedView = child;
-                }
-                if (lp.maxHeight > tallestViewSize) {
-                    tallestViewSize = lp.maxHeight;
-                    tallestView = child;
-                }
-                if (lp.minHeight < smallestViewSize) {
-                    smallestViewSize = lp.minHeight;
-                    smallestView = child;
-                }
-                if (heightMode != MeasureSpec.UNSPECIFIED &&
-                    heightSize >= lp.minHeight && heightSize <= lp.maxHeight) {
-                    if (DEBUG) Log.d(TAG, "  found exact match, finishing early");
-                    return child;
-                }
-            }
-        }
-        if (unboundedView != null) {
-            tallestView = unboundedView;
-        }
-        if (heightMode == MeasureSpec.UNSPECIFIED || heightSize > tallestViewSize) {
-            return tallestView;
-        } else {
-            return smallestView;
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top));
-        mLastActive = mActiveChild;
-        int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top,
-                                                           View.MeasureSpec.EXACTLY);
-        mActiveChild = selectActiveChild(measureSpec);
-        if (mActiveChild == null) return;
-
-        mActiveChild.setVisibility(View.VISIBLE);
-
-        if (mLastActive != mActiveChild && mLastActive != null) {
-            if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive +
-                    " to: " + mActiveChild);
-
-            mEnteringView = mActiveChild;
-            mLeavingView = mLastActive;
-
-            mEnteringView.setAlpha(1f);
-
-            mModestyPanel.setAlpha(1f);
-            mModestyPanel.bringToFront();
-            mModestyPanelTop = mLeavingView.getHeight();
-            mModestyPanel.setVisibility(View.VISIBLE);
-            // TODO: mModestyPanel background should be compatible with mLeavingView
-
-            mLeavingView.bringToFront();
-
-            if (mTransitionAnimation.isRunning()) {
-                mTransitionAnimation.cancel();
-            }
-            mFadeView.setTarget(mLeavingView);
-            mFadeView.setFloatValues(0f);
-            mFadePanel.setFloatValues(0f);
-            mTransitionAnimation.setupStartValues();
-            mTransitionAnimation.start();
-        }
-        final int childWidth = mActiveChild.getMeasuredWidth();
-        final int childHeight = mActiveChild.getMeasuredHeight();
-        // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive
-        mActiveChild.layout(0, 0, childWidth, childHeight);
-
-        if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop);
-        mModestyPanel.layout(0, mModestyPanelTop, childWidth, mModestyPanelTop + childHeight);
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        if (DEBUG) Log.d(TAG, "generate layout from attrs");
-        return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        if (DEBUG) Log.d(TAG, "generate default layout from viewgroup");
-        return new SizeAdaptiveLayout.LayoutParams(p);
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        if (DEBUG) Log.d(TAG, "generate default layout from null");
-        return new SizeAdaptiveLayout.LayoutParams();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof SizeAdaptiveLayout.LayoutParams;
-    }
-
-    /**
-     * Per-child layout information associated with ViewSizeAdaptiveLayout.
-     *
-     * TODO extend to width and height
-     *
-     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight
-     * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight
-     */
-    public static class LayoutParams extends ViewGroup.LayoutParams {
-
-        /**
-         * Indicates the minimum valid height for the child.
-         */
-        @ViewDebug.ExportedProperty(category = "layout")
-        public int minHeight;
-
-        /**
-         * Indicates the maximum valid height for the child.
-         */
-        @ViewDebug.ExportedProperty(category = "layout")
-        public int maxHeight;
-
-        /**
-         * Constant value for maxHeight that indicates there is not maximum height.
-         */
-        public static final int UNBOUNDED = -1;
-
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-            if (DEBUG) {
-                Log.d(TAG, "construct layout from attrs");
-                for (int i = 0; i < attrs.getAttributeCount(); i++) {
-                    Log.d(TAG, " " + attrs.getAttributeName(i) + " = " +
-                          attrs.getAttributeValue(i));
-                }
-            }
-            TypedArray a =
-                    c.obtainStyledAttributes(attrs,
-                            R.styleable.SizeAdaptiveLayout_Layout);
-
-            minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0);
-            if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight);
-
-            try {
-                maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED);
-                if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight);
-            } catch (Exception e) {
-                if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e);
-            }
-
-            a.recycle();
-        }
-
-        /**
-         * Creates a new set of layout parameters with the specified width, height
-         * and valid height bounds.
-         *
-         * @param width the width, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
-         * @param height the height, either {@link #MATCH_PARENT},
-         *        {@link #WRAP_CONTENT} or a fixed size in pixels
-         * @param minHeight the minimum height of this child
-         * @param maxHeight the maximum height of this child
-         *        or {@link #UNBOUNDED} if the child can grow forever
-         */
-        public LayoutParams(int width, int height, int minHeight, int maxHeight) {
-            super(width, height);
-            this.minHeight = minHeight;
-            this.maxHeight = maxHeight;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(int width, int height) {
-            this(width, height, UNBOUNDED, UNBOUNDED);
-        }
-
-        /**
-         * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
-         */
-        public LayoutParams() {
-            this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public LayoutParams(ViewGroup.LayoutParams p) {
-            super(p);
-            minHeight = UNBOUNDED;
-            maxHeight = UNBOUNDED;
-        }
-
-        public String debug(String output) {
-            return output + "SizeAdaptiveLayout.LayoutParams={" +
-                    ", max=" + maxHeight +
-                    ", max=" + minHeight + "}";
-        }
-    }
-
-    class BringToFrontOnEnd implements AnimatorListener {
-        @Override
-            public void onAnimationEnd(Animator animation) {
-            if (mCanceledAnimationCount == 0) {
-                mLeavingView.setVisibility(View.GONE);
-                mModestyPanel.setVisibility(View.GONE);
-                mEnteringView.bringToFront();
-                mEnteringView = null;
-                mLeavingView = null;
-            } else {
-                mCanceledAnimationCount--;
-            }
-        }
-
-        @Override
-            public void onAnimationCancel(Animator animation) {
-            mCanceledAnimationCount++;
-        }
-
-        @Override
-            public void onAnimationRepeat(Animator animation) {
-            if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen.");
-            assert(false);
-        }
-
-        @Override
-            public void onAnimationStart(Animator animation) {
-        }
-    }
-}
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index a206e7f..8c395ec 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -31,7 +31,6 @@
 import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.view.View;
 import android.view.accessibility.CaptioningManager.CaptionStyle;
 
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d617c05..89990c2 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -19,6 +19,7 @@
 import android.animation.TimeInterpolator;
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -38,6 +39,7 @@
     private static final String TAG = "SwipeDismissLayout";
 
     private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+    private boolean mUseDynamicTranslucency = true;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -85,7 +87,7 @@
                     // and temporarily disables translucency when it is fully visible.
                     // As soon as the user starts swiping, we will re-enable
                     // translucency.
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertFromTranslucent();
                     }
                 }
@@ -117,6 +119,11 @@
                 android.R.integer.config_shortAnimTime);
         mCancelInterpolator = new DecelerateInterpolator(1.5f);
         mDismissInterpolator = new AccelerateInterpolator(1.5f);
+        TypedArray a = context.getTheme().obtainStyledAttributes(
+                com.android.internal.R.styleable.Theme);
+        mUseDynamicTranslucency = !a.hasValue(
+                com.android.internal.R.styleable.Window_windowIsTranslucent);
+        a.recycle();
     }
 
     public void setOnDismissedListener(OnDismissedListener listener) {
@@ -230,7 +237,7 @@
                 mLastX = ev.getRawX();
                 updateSwiping(ev);
                 if (mSwiping) {
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertToTranslucent(null, null);
                     }
                     setProgress(ev.getRawX() - mDownX);
@@ -254,7 +261,7 @@
     }
 
     protected void cancel() {
-        if (getContext() instanceof Activity) {
+        if (mUseDynamicTranslucency && getContext() instanceof Activity) {
             ((Activity) getContext()).convertFromTranslucent();
         }
         if (mProgressListener != null) {
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index 8d1f73a..54df87b 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -27,8 +27,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
new file mode 100644
index 0000000..f916e6f
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -0,0 +1,2866 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.DrawableRes;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.FocusFinder;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityRecord;
+import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
+import android.widget.Scroller;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Layout manager that allows the user to flip left and right
+ * through pages of data.  You supply an implementation of a
+ * {@link android.support.v4.view.PagerAdapter} to generate the pages that the view shows.
+ *
+ * <p>Note this class is currently under early design and
+ * development.  The API will likely change in later updates of
+ * the compatibility library, requiring changes to the source code
+ * of apps when they are compiled against the newer version.</p>
+ *
+ * <p>ViewPager is most often used in conjunction with {@link android.app.Fragment},
+ * which is a convenient way to supply and manage the lifecycle of each page.
+ * There are standard adapters implemented for using fragments with the ViewPager,
+ * which cover the most common use cases.  These are
+ * {@link android.support.v4.app.FragmentPagerAdapter} and
+ * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
+ * classes have simple code showing how to build a full user interface
+ * with them.
+ *
+ * <p>For more information about how to use ViewPager, read <a
+ * href="{@docRoot}training/implementing-navigation/lateral.html">Creating Swipe Views with
+ * Tabs</a>.</p>
+ *
+ * <p>Below is a more complicated example of ViewPager, using it in conjunction
+ * with {@link android.app.ActionBar} tabs.  You can find other examples of using
+ * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code.
+ *
+ * {@sample development/samples/Support13Demos/src/com/example/android/supportv13/app/ActionBarTabsPager.java
+ *      complete}
+ */
+public class ViewPager extends ViewGroup {
+    private static final String TAG = "ViewPager";
+    private static final boolean DEBUG = false;
+
+    private static final boolean USE_CACHE = false;
+
+    private static final int DEFAULT_OFFSCREEN_PAGES = 1;
+    private static final int MAX_SETTLE_DURATION = 600; // ms
+    private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
+
+    private static final int DEFAULT_GUTTER_SIZE = 16; // dips
+
+    private static final int MIN_FLING_VELOCITY = 400; // dips
+
+    private static final int[] LAYOUT_ATTRS = new int[] {
+        com.android.internal.R.attr.layout_gravity
+    };
+
+    /**
+     * Used to track what the expected number of items in the adapter should be.
+     * If the app changes this when we don't expect it, we'll throw a big obnoxious exception.
+     */
+    private int mExpectedAdapterCount;
+
+    static class ItemInfo {
+        Object object;
+        int position;
+        boolean scrolling;
+        float widthFactor;
+        float offset;
+    }
+
+    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>(){
+        @Override
+        public int compare(ItemInfo lhs, ItemInfo rhs) {
+            return lhs.position - rhs.position;
+        }
+    };
+
+    private static final Interpolator sInterpolator = new Interpolator() {
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
+    private final ItemInfo mTempItem = new ItemInfo();
+
+    private final Rect mTempRect = new Rect();
+
+    private PagerAdapter mAdapter;
+    private int mCurItem;   // Index of currently displayed page.
+    private int mRestoredCurItem = -1;
+    private Parcelable mRestoredAdapterState = null;
+    private ClassLoader mRestoredClassLoader = null;
+    private Scroller mScroller;
+    private PagerObserver mObserver;
+
+    private int mPageMargin;
+    private Drawable mMarginDrawable;
+    private int mTopPageBounds;
+    private int mBottomPageBounds;
+
+    // Offsets of the first and last items, if known.
+    // Set during population, used to determine if we are at the beginning
+    // or end of the pager data set during touch scrolling.
+    private float mFirstOffset = -Float.MAX_VALUE;
+    private float mLastOffset = Float.MAX_VALUE;
+
+    private int mChildWidthMeasureSpec;
+    private int mChildHeightMeasureSpec;
+    private boolean mInLayout;
+
+    private boolean mScrollingCacheEnabled;
+
+    private boolean mPopulatePending;
+    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;
+
+    private boolean mIsBeingDragged;
+    private boolean mIsUnableToDrag;
+    private int mDefaultGutterSize;
+    private int mGutterSize;
+    private int mTouchSlop;
+    /**
+     * Position of the last motion event.
+     */
+    private float mLastMotionX;
+    private float mLastMotionY;
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+    /**
+     * ID of the active pointer. This is used to retain consistency during
+     * drags/flings if multiple pointers are used.
+     */
+    private int mActivePointerId = INVALID_POINTER;
+    /**
+     * Sentinel value for no current active pointer.
+     * Used by {@link #mActivePointerId}.
+     */
+    private static final int INVALID_POINTER = -1;
+
+    /**
+     * Determines speed during touch scrolling
+     */
+    private VelocityTracker mVelocityTracker;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
+    private int mFlingDistance;
+    private int mCloseEnough;
+
+    // If the pager is at least this close to its final position, complete the scroll
+    // on touch down and let the user interact with the content inside instead of
+    // "catching" the flinging pager.
+    private static final int CLOSE_ENOUGH = 2; // dp
+
+    private boolean mFakeDragging;
+    private long mFakeDragBeginTime;
+
+    private EdgeEffect mLeftEdge;
+    private EdgeEffect mRightEdge;
+
+    private boolean mFirstLayout = true;
+    private boolean mNeedCalculatePageOffsets = false;
+    private boolean mCalledSuper;
+    private int mDecorChildCount;
+
+    private OnPageChangeListener mOnPageChangeListener;
+    private OnPageChangeListener mInternalPageChangeListener;
+    private OnAdapterChangeListener mAdapterChangeListener;
+    private PageTransformer mPageTransformer;
+
+    private static final int DRAW_ORDER_DEFAULT = 0;
+    private static final int DRAW_ORDER_FORWARD = 1;
+    private static final int DRAW_ORDER_REVERSE = 2;
+    private int mDrawingOrder;
+    private ArrayList<View> mDrawingOrderedChildren;
+    private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();
+
+    /**
+     * Indicates that the pager is in an idle, settled state. The current page
+     * is fully in view and no animation is in progress.
+     */
+    public static final int SCROLL_STATE_IDLE = 0;
+
+    /**
+     * Indicates that the pager is currently being dragged by the user.
+     */
+    public static final int SCROLL_STATE_DRAGGING = 1;
+
+    /**
+     * Indicates that the pager is in the process of settling to a final position.
+     */
+    public static final int SCROLL_STATE_SETTLING = 2;
+
+    private final Runnable mEndScrollRunnable = new Runnable() {
+        public void run() {
+            setScrollState(SCROLL_STATE_IDLE);
+            populate();
+        }
+    };
+
+    private int mScrollState = SCROLL_STATE_IDLE;
+
+    /**
+     * Callback interface for responding to changing state of the selected page.
+     */
+    public interface OnPageChangeListener {
+
+        /**
+         * This method will be invoked when the current page is scrolled, either as part
+         * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+         *
+         * @param position Position index of the first page currently being displayed.
+         *                 Page position+1 will be visible if positionOffset is nonzero.
+         * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
+         * @param positionOffsetPixels Value in pixels indicating the offset from position.
+         */
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
+
+        /**
+         * This method will be invoked when a new page becomes selected. Animation is not
+         * necessarily complete.
+         *
+         * @param position Position index of the new selected page.
+         */
+        public void onPageSelected(int position);
+
+        /**
+         * Called when the scroll state changes. Useful for discovering when the user
+         * begins dragging, when the pager is automatically settling to the current page,
+         * or when it is fully stopped/idle.
+         *
+         * @param state The new scroll state.
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_IDLE
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_DRAGGING
+         * @see com.android.internal.widget.ViewPager#SCROLL_STATE_SETTLING
+         */
+        public void onPageScrollStateChanged(int state);
+    }
+
+    /**
+     * Simple implementation of the {@link OnPageChangeListener} interface with stub
+     * implementations of each method. Extend this if you do not intend to override
+     * every method of {@link OnPageChangeListener}.
+     */
+    public static class SimpleOnPageChangeListener implements OnPageChangeListener {
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            // This space for rent
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            // This space for rent
+        }
+    }
+
+    /**
+     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
+     * This offers an opportunity for the application to apply a custom transformation
+     * to the page views using animation properties.
+     *
+     * <p>As property animation is only supported as of Android 3.0 and forward,
+     * setting a PageTransformer on a ViewPager on earlier platform versions will
+     * be ignored.</p>
+     */
+    public interface PageTransformer {
+        /**
+         * Apply a property transformation to the given page.
+         *
+         * @param page Apply the transformation to this page
+         * @param position Position of page relative to the current front-and-center
+         *                 position of the pager. 0 is front and center. 1 is one full
+         *                 page position to the right, and -1 is one page position to the left.
+         */
+        public void transformPage(View page, float position);
+    }
+
+    /**
+     * Used internally to monitor when adapters are switched.
+     */
+    interface OnAdapterChangeListener {
+        public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter);
+    }
+
+    /**
+     * Used internally to tag special types of child views that should be added as
+     * pager decorations by default.
+     */
+    interface Decor {}
+
+    public ViewPager(Context context) {
+        super(context);
+        initViewPager();
+    }
+
+    public ViewPager(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initViewPager();
+    }
+
+    void initViewPager() {
+        setWillNotDraw(false);
+        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+        setFocusable(true);
+        final Context context = getContext();
+        mScroller = new Scroller(context, sInterpolator);
+        final ViewConfiguration configuration = ViewConfiguration.get(context);
+        final float density = context.getResources().getDisplayMetrics().density;
+
+        mTouchSlop = configuration.getScaledPagingTouchSlop();
+        mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density);
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+        mLeftEdge = new EdgeEffect(context);
+        mRightEdge = new EdgeEffect(context);
+
+        mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
+        mCloseEnough = (int) (CLOSE_ENOUGH * density);
+        mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
+
+        setAccessibilityDelegate(new MyAccessibilityDelegate());
+
+        if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        removeCallbacks(mEndScrollRunnable);
+        super.onDetachedFromWindow();
+    }
+
+    private void setScrollState(int newState) {
+        if (mScrollState == newState) {
+            return;
+        }
+
+        mScrollState = newState;
+        if (mPageTransformer != null) {
+            // PageTransformers can do complex things that benefit from hardware layers.
+            enableLayers(newState != SCROLL_STATE_IDLE);
+        }
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrollStateChanged(newState);
+        }
+    }
+
+    /**
+     * Set a PagerAdapter that will supply views for this pager as needed.
+     *
+     * @param adapter Adapter to use
+     */
+    public void setAdapter(PagerAdapter adapter) {
+        if (mAdapter != null) {
+            mAdapter.unregisterDataSetObserver(mObserver);
+            mAdapter.startUpdate(this);
+            for (int i = 0; i < mItems.size(); i++) {
+                final ItemInfo ii = mItems.get(i);
+                mAdapter.destroyItem(this, ii.position, ii.object);
+            }
+            mAdapter.finishUpdate(this);
+            mItems.clear();
+            removeNonDecorViews();
+            mCurItem = 0;
+            scrollTo(0, 0);
+        }
+
+        final PagerAdapter oldAdapter = mAdapter;
+        mAdapter = adapter;
+        mExpectedAdapterCount = 0;
+
+        if (mAdapter != null) {
+            if (mObserver == null) {
+                mObserver = new PagerObserver();
+            }
+            mAdapter.registerDataSetObserver(mObserver);
+            mPopulatePending = false;
+            final boolean wasFirstLayout = mFirstLayout;
+            mFirstLayout = true;
+            mExpectedAdapterCount = mAdapter.getCount();
+            if (mRestoredCurItem >= 0) {
+                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
+                setCurrentItemInternal(mRestoredCurItem, false, true);
+                mRestoredCurItem = -1;
+                mRestoredAdapterState = null;
+                mRestoredClassLoader = null;
+            } else if (!wasFirstLayout) {
+                populate();
+            } else {
+                requestLayout();
+            }
+        }
+
+        if (mAdapterChangeListener != null && oldAdapter != adapter) {
+            mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
+        }
+    }
+
+    private void removeNonDecorViews() {
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (!lp.isDecor) {
+                removeViewAt(i);
+                i--;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the current adapter supplying pages.
+     *
+     * @return The currently registered PagerAdapter
+     */
+    public PagerAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    void setOnAdapterChangeListener(OnAdapterChangeListener listener) {
+        mAdapterChangeListener = listener;
+    }
+
+    private int getClientWidth() {
+        return getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
+    }
+
+    /**
+     * Set the currently selected page. If the ViewPager has already been through its first
+     * layout with its current adapter there will be a smooth animated transition between
+     * the current item and the specified item.
+     *
+     * @param item Item index to select
+     */
+    public void setCurrentItem(int item) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, !mFirstLayout, false);
+    }
+
+    /**
+     * Set the currently selected page.
+     *
+     * @param item Item index to select
+     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
+     */
+    public void setCurrentItem(int item, boolean smoothScroll) {
+        mPopulatePending = false;
+        setCurrentItemInternal(item, smoothScroll, false);
+    }
+
+    public int getCurrentItem() {
+        return mCurItem;
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
+        setCurrentItemInternal(item, smoothScroll, always, 0);
+    }
+
+    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
+        if (mAdapter == null || mAdapter.getCount() <= 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+        if (!always && mCurItem == item && mItems.size() != 0) {
+            setScrollingCacheEnabled(false);
+            return;
+        }
+
+        if (item < 0) {
+            item = 0;
+        } else if (item >= mAdapter.getCount()) {
+            item = mAdapter.getCount() - 1;
+        }
+        final int pageLimit = mOffscreenPageLimit;
+        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
+            // We are doing a jump by more than one page.  To avoid
+            // glitches, we want to keep all current pages in the view
+            // until the scroll ends.
+            for (int i=0; i<mItems.size(); i++) {
+                mItems.get(i).scrolling = true;
+            }
+        }
+        final boolean dispatchSelected = mCurItem != item;
+
+        if (mFirstLayout) {
+            // We don't have any idea how big we are yet and shouldn't have any pages either.
+            // Just set things up and let the pending layout handle things.
+            mCurItem = item;
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+            requestLayout();
+        } else {
+            populate(item);
+            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
+        }
+    }
+
+    private void scrollToItem(int item, boolean smoothScroll, int velocity,
+            boolean dispatchSelected) {
+        final ItemInfo curInfo = infoForPosition(item);
+        int destX = 0;
+        if (curInfo != null) {
+            final int width = getClientWidth();
+            destX = (int) (width * Math.max(mFirstOffset,
+                    Math.min(curInfo.offset, mLastOffset)));
+        }
+        if (smoothScroll) {
+            smoothScrollTo(destX, 0, velocity);
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+        } else {
+            if (dispatchSelected && mOnPageChangeListener != null) {
+                mOnPageChangeListener.onPageSelected(item);
+            }
+            if (dispatchSelected && mInternalPageChangeListener != null) {
+                mInternalPageChangeListener.onPageSelected(item);
+            }
+            completeScroll(false);
+            scrollTo(destX, 0);
+            pageScrolled(destX);
+        }
+    }
+
+    /**
+     * Set a listener that will be invoked whenever the page changes or is incrementally
+     * scrolled. See {@link OnPageChangeListener}.
+     *
+     * @param listener Listener to set
+     */
+    public void setOnPageChangeListener(OnPageChangeListener listener) {
+        mOnPageChangeListener = listener;
+    }
+
+    /**
+     * Set a {@link PageTransformer} that will be called for each attached page whenever
+     * the scroll position is changed. This allows the application to apply custom property
+     * transformations to each page, overriding the default sliding look and feel.
+     *
+     * <p><em>Note:</em> Prior to Android 3.0 the property animation APIs did not exist.
+     * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.</p>
+     *
+     * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+     *                            to be drawn from last to first instead of first to last.
+     * @param transformer PageTransformer that will modify each page's animation properties
+     */
+    public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
+        final boolean hasTransformer = transformer != null;
+        final boolean needsPopulate = hasTransformer != (mPageTransformer != null);
+        mPageTransformer = transformer;
+        setChildrenDrawingOrderEnabled(hasTransformer);
+        if (hasTransformer) {
+            mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;
+        } else {
+            mDrawingOrder = DRAW_ORDER_DEFAULT;
+        }
+        if (needsPopulate) populate();
+    }
+
+    @Override
+    protected int getChildDrawingOrder(int childCount, int i) {
+        final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i;
+        final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex;
+        return result;
+    }
+
+    /**
+     * Set a separate OnPageChangeListener for internal use by the support library.
+     *
+     * @param listener Listener to set
+     * @return The old listener that was set, if any.
+     */
+    OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {
+        OnPageChangeListener oldListener = mInternalPageChangeListener;
+        mInternalPageChangeListener = listener;
+        return oldListener;
+    }
+
+    /**
+     * Returns the number of pages that will be retained to either side of the
+     * current page in the view hierarchy in an idle state. Defaults to 1.
+     *
+     * @return How many pages will be kept offscreen on either side
+     * @see #setOffscreenPageLimit(int)
+     */
+    public int getOffscreenPageLimit() {
+        return mOffscreenPageLimit;
+    }
+
+    /**
+     * Set the number of pages that should be retained to either side of the
+     * current page in the view hierarchy in an idle state. Pages beyond this
+     * limit will be recreated from the adapter when needed.
+     *
+     * <p>This is offered as an optimization. If you know in advance the number
+     * of pages you will need to support or have lazy-loading mechanisms in place
+     * on your pages, tweaking this setting can have benefits in perceived smoothness
+     * of paging animations and interaction. If you have a small number of pages (3-4)
+     * that you can keep active all at once, less time will be spent in layout for
+     * newly created view subtrees as the user pages back and forth.</p>
+     *
+     * <p>You should keep this limit low, especially if your pages have complex layouts.
+     * This setting defaults to 1.</p>
+     *
+     * @param limit How many pages will be kept offscreen in an idle state.
+     */
+    public void setOffscreenPageLimit(int limit) {
+        if (limit < DEFAULT_OFFSCREEN_PAGES) {
+            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
+                    DEFAULT_OFFSCREEN_PAGES);
+            limit = DEFAULT_OFFSCREEN_PAGES;
+        }
+        if (limit != mOffscreenPageLimit) {
+            mOffscreenPageLimit = limit;
+            populate();
+        }
+    }
+
+    /**
+     * Set the margin between pages.
+     *
+     * @param marginPixels Distance between adjacent pages in pixels
+     * @see #getPageMargin()
+     * @see #setPageMarginDrawable(android.graphics.drawable.Drawable)
+     * @see #setPageMarginDrawable(int)
+     */
+    public void setPageMargin(int marginPixels) {
+        final int oldMargin = mPageMargin;
+        mPageMargin = marginPixels;
+
+        final int width = getWidth();
+        recomputeScrollPosition(width, width, marginPixels, oldMargin);
+
+        requestLayout();
+    }
+
+    /**
+     * Return the margin between pages.
+     *
+     * @return The size of the margin in pixels
+     */
+    public int getPageMargin() {
+        return mPageMargin;
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param d Drawable to display between pages
+     */
+    public void setPageMarginDrawable(Drawable d) {
+        mMarginDrawable = d;
+        if (d != null) refreshDrawableState();
+        setWillNotDraw(d == null);
+        invalidate();
+    }
+
+    /**
+     * Set a drawable that will be used to fill the margin between pages.
+     *
+     * @param resId Resource ID of a drawable to display between pages
+     */
+    public void setPageMarginDrawable(@DrawableRes int resId) {
+        setPageMarginDrawable(getContext().getDrawable(resId));
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mMarginDrawable;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        final Drawable d = mMarginDrawable;
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+    }
+
+    // We want the duration of the page snap animation to be influenced by the distance that
+    // the screen has to travel, however, we don't want this duration to be effected in a
+    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+    // of travel has on the overall snap duration.
+    float distanceInfluenceForSnapDuration(float f) {
+        f -= 0.5f; // center the values about 0.
+        f *= 0.3f * Math.PI / 2.0f;
+        return (float) Math.sin(f);
+    }
+
+    /**
+     * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     */
+    void smoothScrollTo(int x, int y) {
+        smoothScrollTo(x, y, 0);
+    }
+
+    /**
+     * Like {@link android.view.View#scrollBy}, but scroll smoothly instead of immediately.
+     *
+     * @param x the number of pixels to scroll by on the X axis
+     * @param y the number of pixels to scroll by on the Y axis
+     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
+     */
+    void smoothScrollTo(int x, int y, int velocity) {
+        if (getChildCount() == 0) {
+            // Nothing to do.
+            setScrollingCacheEnabled(false);
+            return;
+        }
+        int sx = getScrollX();
+        int sy = getScrollY();
+        int dx = x - sx;
+        int dy = y - sy;
+        if (dx == 0 && dy == 0) {
+            completeScroll(false);
+            populate();
+            setScrollState(SCROLL_STATE_IDLE);
+            return;
+        }
+
+        setScrollingCacheEnabled(true);
+        setScrollState(SCROLL_STATE_SETTLING);
+
+        final int width = getClientWidth();
+        final int halfWidth = width / 2;
+        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
+        final float distance = halfWidth + halfWidth *
+                distanceInfluenceForSnapDuration(distanceRatio);
+
+        int duration = 0;
+        velocity = Math.abs(velocity);
+        if (velocity > 0) {
+            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+        } else {
+            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
+            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
+            duration = (int) ((pageDelta + 1) * 100);
+        }
+        duration = Math.min(duration, MAX_SETTLE_DURATION);
+
+        mScroller.startScroll(sx, sy, dx, dy, duration);
+        postInvalidateOnAnimation();
+    }
+
+    ItemInfo addNewItem(int position, int index) {
+        ItemInfo ii = new ItemInfo();
+        ii.position = position;
+        ii.object = mAdapter.instantiateItem(this, position);
+        ii.widthFactor = mAdapter.getPageWidth(position);
+        if (index < 0 || index >= mItems.size()) {
+            mItems.add(ii);
+        } else {
+            mItems.add(index, ii);
+        }
+        return ii;
+    }
+
+    void dataSetChanged() {
+        // This method only gets called if our observer is attached, so mAdapter is non-null.
+
+        final int adapterCount = mAdapter.getCount();
+        mExpectedAdapterCount = adapterCount;
+        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 &&
+                mItems.size() < adapterCount;
+        int newCurrItem = mCurItem;
+
+        boolean isUpdating = false;
+        for (int i = 0; i < mItems.size(); i++) {
+            final ItemInfo ii = mItems.get(i);
+            final int newPos = mAdapter.getItemPosition(ii.object);
+
+            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
+                continue;
+            }
+
+            if (newPos == PagerAdapter.POSITION_NONE) {
+                mItems.remove(i);
+                i--;
+
+                if (!isUpdating) {
+                    mAdapter.startUpdate(this);
+                    isUpdating = true;
+                }
+
+                mAdapter.destroyItem(this, ii.position, ii.object);
+                needPopulate = true;
+
+                if (mCurItem == ii.position) {
+                    // Keep the current item in the valid range
+                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
+                    needPopulate = true;
+                }
+                continue;
+            }
+
+            if (ii.position != newPos) {
+                if (ii.position == mCurItem) {
+                    // Our current item changed position. Follow it.
+                    newCurrItem = newPos;
+                }
+
+                ii.position = newPos;
+                needPopulate = true;
+            }
+        }
+
+        if (isUpdating) {
+            mAdapter.finishUpdate(this);
+        }
+
+        Collections.sort(mItems, COMPARATOR);
+
+        if (needPopulate) {
+            // Reset our known page widths; populate will recompute them.
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) {
+                    lp.widthFactor = 0.f;
+                }
+            }
+
+            setCurrentItemInternal(newCurrItem, false, true);
+            requestLayout();
+        }
+    }
+
+    void populate() {
+        populate(mCurItem);
+    }
+
+    void populate(int newCurrentItem) {
+        ItemInfo oldCurInfo = null;
+        int focusDirection = View.FOCUS_FORWARD;
+        if (mCurItem != newCurrentItem) {
+            focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+            oldCurInfo = infoForPosition(mCurItem);
+            mCurItem = newCurrentItem;
+        }
+
+        if (mAdapter == null) {
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Bail now if we are waiting to populate.  This is to hold off
+        // on creating views from the time the user releases their finger to
+        // fling to a new position until we have finished the scroll to
+        // that position, avoiding glitches from happening at that point.
+        if (mPopulatePending) {
+            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
+            sortChildDrawingOrder();
+            return;
+        }
+
+        // Also, don't populate until we are attached to a window.  This is to
+        // avoid trying to populate before we have restored our view hierarchy
+        // state and conflicting with what is restored.
+        if (getWindowToken() == null) {
+            return;
+        }
+
+        mAdapter.startUpdate(this);
+
+        final int pageLimit = mOffscreenPageLimit;
+        final int startPos = Math.max(0, mCurItem - pageLimit);
+        final int N = mAdapter.getCount();
+        final int endPos = Math.min(N-1, mCurItem + pageLimit);
+
+        if (N != mExpectedAdapterCount) {
+            String resName;
+            try {
+                resName = getResources().getResourceName(getId());
+            } catch (Resources.NotFoundException e) {
+                resName = Integer.toHexString(getId());
+            }
+            throw new IllegalStateException("The application's PagerAdapter changed the adapter's" +
+                    " contents without calling PagerAdapter#notifyDataSetChanged!" +
+                    " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N +
+                    " Pager id: " + resName +
+                    " Pager class: " + getClass() +
+                    " Problematic adapter: " + mAdapter.getClass());
+        }
+
+        // Locate the currently focused item or add it if needed.
+        int curIndex = -1;
+        ItemInfo curItem = null;
+        for (curIndex = 0; curIndex < mItems.size(); curIndex++) {
+            final ItemInfo ii = mItems.get(curIndex);
+            if (ii.position >= mCurItem) {
+                if (ii.position == mCurItem) curItem = ii;
+                break;
+            }
+        }
+
+        if (curItem == null && N > 0) {
+            curItem = addNewItem(mCurItem, curIndex);
+        }
+
+        // Fill 3x the available width or up to the number of offscreen
+        // pages requested to either side, whichever is larger.
+        // If we have no current item we have no work to do.
+        if (curItem != null) {
+            float extraWidthLeft = 0.f;
+            int itemIndex = curIndex - 1;
+            ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+            final int clientWidth = getClientWidth();
+            final float leftWidthNeeded = clientWidth <= 0 ? 0 :
+                    2.f - curItem.widthFactor + (float) getPaddingLeft() / (float) clientWidth;
+            for (int pos = mCurItem - 1; pos >= 0; pos--) {
+                if (extraWidthLeft >= leftWidthNeeded && pos < startPos) {
+                    if (ii == null) {
+                        break;
+                    }
+                    if (pos == ii.position && !ii.scrolling) {
+                        mItems.remove(itemIndex);
+                        mAdapter.destroyItem(this, pos, ii.object);
+                        if (DEBUG) {
+                            Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
+                                    " view: " + ((View) ii.object));
+                        }
+                        itemIndex--;
+                        curIndex--;
+                        ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                    }
+                } else if (ii != null && pos == ii.position) {
+                    extraWidthLeft += ii.widthFactor;
+                    itemIndex--;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                } else {
+                    ii = addNewItem(pos, itemIndex + 1);
+                    extraWidthLeft += ii.widthFactor;
+                    curIndex++;
+                    ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;
+                }
+            }
+
+            float extraWidthRight = curItem.widthFactor;
+            itemIndex = curIndex + 1;
+            if (extraWidthRight < 2.f) {
+                ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                final float rightWidthNeeded = clientWidth <= 0 ? 0 :
+                        (float) getPaddingRight() / (float) clientWidth + 2.f;
+                for (int pos = mCurItem + 1; pos < N; pos++) {
+                    if (extraWidthRight >= rightWidthNeeded && pos > endPos) {
+                        if (ii == null) {
+                            break;
+                        }
+                        if (pos == ii.position && !ii.scrolling) {
+                            mItems.remove(itemIndex);
+                            mAdapter.destroyItem(this, pos, ii.object);
+                            if (DEBUG) {
+                                Log.i(TAG, "populate() - destroyItem() with pos: " + pos +
+                                        " view: " + ((View) ii.object));
+                            }
+                            ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                        }
+                    } else if (ii != null && pos == ii.position) {
+                        extraWidthRight += ii.widthFactor;
+                        itemIndex++;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    } else {
+                        ii = addNewItem(pos, itemIndex);
+                        itemIndex++;
+                        extraWidthRight += ii.widthFactor;
+                        ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;
+                    }
+                }
+            }
+
+            calculatePageOffsets(curItem, curIndex, oldCurInfo);
+        }
+
+        if (DEBUG) {
+            Log.i(TAG, "Current page list:");
+            for (int i=0; i<mItems.size(); i++) {
+                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);
+            }
+        }
+
+        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
+
+        mAdapter.finishUpdate(this);
+
+        // Check width measurement of current pages and drawing sort order.
+        // Update LayoutParams as needed.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.childIndex = i;
+            if (!lp.isDecor && lp.widthFactor == 0.f) {
+                // 0 means requery the adapter for this, it doesn't have a valid width.
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null) {
+                    lp.widthFactor = ii.widthFactor;
+                    lp.position = ii.position;
+                }
+            }
+        }
+        sortChildDrawingOrder();
+
+        if (hasFocus()) {
+            View currentFocused = findFocus();
+            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;
+            if (ii == null || ii.position != mCurItem) {
+                for (int i=0; i<getChildCount(); i++) {
+                    View child = getChildAt(i);
+                    ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        if (child.requestFocus(focusDirection)) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void sortChildDrawingOrder() {
+        if (mDrawingOrder != DRAW_ORDER_DEFAULT) {
+            if (mDrawingOrderedChildren == null) {
+                mDrawingOrderedChildren = new ArrayList<View>();
+            } else {
+                mDrawingOrderedChildren.clear();
+            }
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                mDrawingOrderedChildren.add(child);
+            }
+            Collections.sort(mDrawingOrderedChildren, sPositionComparator);
+        }
+    }
+
+    private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) {
+        final int N = mAdapter.getCount();
+        final int width = getClientWidth();
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        // Fix up offsets for later layout.
+        if (oldCurInfo != null) {
+            final int oldCurPosition = oldCurInfo.position;
+            // Base offsets off of oldCurInfo.
+            if (oldCurPosition < curItem.position) {
+                int itemIndex = 0;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset + oldCurInfo.widthFactor + marginOffset;
+                for (int pos = oldCurPosition + 1;
+                        pos <= curItem.position && itemIndex < mItems.size(); pos++) {
+                    ii = mItems.get(itemIndex);
+                    while (pos > ii.position && itemIndex < mItems.size() - 1) {
+                        itemIndex++;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos < ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset += mAdapter.getPageWidth(pos) + marginOffset;
+                        pos++;
+                    }
+                    ii.offset = offset;
+                    offset += ii.widthFactor + marginOffset;
+                }
+            } else if (oldCurPosition > curItem.position) {
+                int itemIndex = mItems.size() - 1;
+                ItemInfo ii = null;
+                float offset = oldCurInfo.offset;
+                for (int pos = oldCurPosition - 1;
+                        pos >= curItem.position && itemIndex >= 0; pos--) {
+                    ii = mItems.get(itemIndex);
+                    while (pos < ii.position && itemIndex > 0) {
+                        itemIndex--;
+                        ii = mItems.get(itemIndex);
+                    }
+                    while (pos > ii.position) {
+                        // We don't have an item populated for this,
+                        // ask the adapter for an offset.
+                        offset -= mAdapter.getPageWidth(pos) + marginOffset;
+                        pos--;
+                    }
+                    offset -= ii.widthFactor + marginOffset;
+                    ii.offset = offset;
+                }
+            }
+        }
+
+        // Base all offsets off of curItem.
+        final int itemCount = mItems.size();
+        float offset = curItem.offset;
+        int pos = curItem.position - 1;
+        mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE;
+        mLastOffset = curItem.position == N - 1 ?
+                curItem.offset + curItem.widthFactor - 1 : Float.MAX_VALUE;
+        // Previous pages
+        for (int i = curIndex - 1; i >= 0; i--, pos--) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos > ii.position) {
+                offset -= mAdapter.getPageWidth(pos--) + marginOffset;
+            }
+            offset -= ii.widthFactor + marginOffset;
+            ii.offset = offset;
+            if (ii.position == 0) mFirstOffset = offset;
+        }
+        offset = curItem.offset + curItem.widthFactor + marginOffset;
+        pos = curItem.position + 1;
+        // Next pages
+        for (int i = curIndex + 1; i < itemCount; i++, pos++) {
+            final ItemInfo ii = mItems.get(i);
+            while (pos < ii.position) {
+                offset += mAdapter.getPageWidth(pos++) + marginOffset;
+            }
+            if (ii.position == N - 1) {
+                mLastOffset = offset + ii.widthFactor - 1;
+            }
+            ii.offset = offset;
+            offset += ii.widthFactor + marginOffset;
+        }
+
+        mNeedCalculatePageOffsets = false;
+    }
+
+    /**
+     * This is the persistent state that is saved by ViewPager.  Only needed
+     * if you are creating a sublass of ViewPager that must save its own
+     * state, in which case it should implement a subclass of this which
+     * contains that state.
+     */
+    public static class SavedState extends BaseSavedState {
+        int position;
+        Parcelable adapterState;
+        ClassLoader loader;
+
+        public SavedState(Parcel source) {
+            super(source);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(position);
+            out.writeParcelable(adapterState, flags);
+        }
+
+        @Override
+        public String toString() {
+            return "FragmentPager.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " position=" + position + "}";
+        }
+
+        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+
+        SavedState(Parcel in, ClassLoader loader) {
+            super(in);
+            if (loader == null) {
+                loader = getClass().getClassLoader();
+            }
+            position = in.readInt();
+            adapterState = in.readParcelable(loader);
+            this.loader = loader;
+        }
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.position = mCurItem;
+        if (mAdapter != null) {
+            ss.adapterState = mAdapter.saveState();
+        }
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState ss = (SavedState)state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (mAdapter != null) {
+            mAdapter.restoreState(ss.adapterState, ss.loader);
+            setCurrentItemInternal(ss.position, false, true);
+        } else {
+            mRestoredCurItem = ss.position;
+            mRestoredAdapterState = ss.adapterState;
+            mRestoredClassLoader = ss.loader;
+        }
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        if (!checkLayoutParams(params)) {
+            params = generateLayoutParams(params);
+        }
+        final LayoutParams lp = (LayoutParams) params;
+        lp.isDecor |= child instanceof Decor;
+        if (mInLayout) {
+            if (lp != null && lp.isDecor) {
+                throw new IllegalStateException("Cannot add pager decor view during layout");
+            }
+            lp.needsMeasure = true;
+            addViewInLayout(child, index, params);
+        } else {
+            super.addView(child, index, params);
+        }
+
+        if (USE_CACHE) {
+            if (child.getVisibility() != GONE) {
+                child.setDrawingCacheEnabled(mScrollingCacheEnabled);
+            } else {
+                child.setDrawingCacheEnabled(false);
+            }
+        }
+    }
+
+    @Override
+    public void removeView(View view) {
+        if (mInLayout) {
+            removeViewInLayout(view);
+        } else {
+            super.removeView(view);
+        }
+    }
+
+    ItemInfo infoForChild(View child) {
+        for (int i=0; i<mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (mAdapter.isViewFromObject(child, ii.object)) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    ItemInfo infoForAnyChild(View child) {
+        ViewParent parent;
+        while ((parent=child.getParent()) != this) {
+            if (parent == null || !(parent instanceof View)) {
+                return null;
+            }
+            child = (View)parent;
+        }
+        return infoForChild(child);
+    }
+
+    ItemInfo infoForPosition(int position) {
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.position == position) {
+                return ii;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // For simple implementation, our internal size is always 0.
+        // We depend on the container to specify the layout size of
+        // our view.  We can't really know what it is since we will be
+        // adding and removing different arbitrary views and do not
+        // want the layout to change as this happens.
+        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),
+                getDefaultSize(0, heightMeasureSpec));
+
+        final int measuredWidth = getMeasuredWidth();
+        final int maxGutterSize = measuredWidth / 10;
+        mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);
+
+        // Children are just made to fill our space.
+        int childWidthSize = measuredWidth - getPaddingLeft() - getPaddingRight();
+        int childHeightSize = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
+
+        /*
+         * Make sure all children have been properly measured. Decor views first.
+         * Right now we cheat and make this less complicated by assuming decor
+         * views won't intersect. We will pin to edges based on gravity.
+         */
+        int size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp != null && lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    int widthMode = MeasureSpec.AT_MOST;
+                    int heightMode = MeasureSpec.AT_MOST;
+                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
+                    boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT;
+
+                    if (consumeVertical) {
+                        widthMode = MeasureSpec.EXACTLY;
+                    } else if (consumeHorizontal) {
+                        heightMode = MeasureSpec.EXACTLY;
+                    }
+
+                    int widthSize = childWidthSize;
+                    int heightSize = childHeightSize;
+                    if (lp.width != LayoutParams.WRAP_CONTENT) {
+                        widthMode = MeasureSpec.EXACTLY;
+                        if (lp.width != LayoutParams.FILL_PARENT) {
+                            widthSize = lp.width;
+                        }
+                    }
+                    if (lp.height != LayoutParams.WRAP_CONTENT) {
+                        heightMode = MeasureSpec.EXACTLY;
+                        if (lp.height != LayoutParams.FILL_PARENT) {
+                            heightSize = lp.height;
+                        }
+                    }
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);
+                    final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
+                    child.measure(widthSpec, heightSpec);
+
+                    if (consumeVertical) {
+                        childHeightSize -= child.getMeasuredHeight();
+                    } else if (consumeHorizontal) {
+                        childWidthSize -= child.getMeasuredWidth();
+                    }
+                }
+            }
+        }
+
+        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
+        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY);
+
+        // Make sure we have created all fragments that we need to have shown.
+        mInLayout = true;
+        populate();
+        mInLayout = false;
+
+        // Page views next.
+        size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child
+                        + ": " + mChildWidthMeasureSpec);
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp == null || !lp.isDecor) {
+                    final int widthSpec = MeasureSpec.makeMeasureSpec(
+                            (int) (childWidthSize * lp.widthFactor), MeasureSpec.EXACTLY);
+                    child.measure(widthSpec, mChildHeightMeasureSpec);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Make sure scroll position is set correctly.
+        if (w != oldw) {
+            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);
+        }
+    }
+
+    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {
+        if (oldWidth > 0 && !mItems.isEmpty()) {
+            final int widthWithMargin = width - getPaddingLeft() - getPaddingRight() + margin;
+            final int oldWidthWithMargin = oldWidth - getPaddingLeft() - getPaddingRight()
+                                           + oldMargin;
+            final int xpos = getScrollX();
+            final float pageOffset = (float) xpos / oldWidthWithMargin;
+            final int newOffsetPixels = (int) (pageOffset * widthWithMargin);
+
+            scrollTo(newOffsetPixels, getScrollY());
+            if (!mScroller.isFinished()) {
+                // We now return to your regularly scheduled scroll, already in progress.
+                final int newDuration = mScroller.getDuration() - mScroller.timePassed();
+                ItemInfo targetInfo = infoForPosition(mCurItem);
+                mScroller.startScroll(newOffsetPixels, 0,
+                        (int) (targetInfo.offset * width), 0, newDuration);
+            }
+        } else {
+            final ItemInfo ii = infoForPosition(mCurItem);
+            final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0;
+            final int scrollPos = (int) (scrollOffset *
+                                         (width - getPaddingLeft() - getPaddingRight()));
+            if (scrollPos != getScrollX()) {
+                completeScroll(false);
+                scrollTo(scrollPos, getScrollY());
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = getChildCount();
+        int width = r - l;
+        int height = b - t;
+        int paddingLeft = getPaddingLeft();
+        int paddingTop = getPaddingTop();
+        int paddingRight = getPaddingRight();
+        int paddingBottom = getPaddingBottom();
+        final int scrollX = getScrollX();
+
+        int decorCount = 0;
+
+        // First pass - decor views. We need to do this in two passes so that
+        // we have the proper offsets for non-decor views later.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                int childLeft = 0;
+                int childTop = 0;
+                if (lp.isDecor) {
+                    final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                    final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+                    switch (hgrav) {
+                        default:
+                            childLeft = paddingLeft;
+                            break;
+                        case Gravity.LEFT:
+                            childLeft = paddingLeft;
+                            paddingLeft += child.getMeasuredWidth();
+                            break;
+                        case Gravity.CENTER_HORIZONTAL:
+                            childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                    paddingLeft);
+                            break;
+                        case Gravity.RIGHT:
+                            childLeft = width - paddingRight - child.getMeasuredWidth();
+                            paddingRight += child.getMeasuredWidth();
+                            break;
+                    }
+                    switch (vgrav) {
+                        default:
+                            childTop = paddingTop;
+                            break;
+                        case Gravity.TOP:
+                            childTop = paddingTop;
+                            paddingTop += child.getMeasuredHeight();
+                            break;
+                        case Gravity.CENTER_VERTICAL:
+                            childTop = Math.max((height - child.getMeasuredHeight()) / 2,
+                                    paddingTop);
+                            break;
+                        case Gravity.BOTTOM:
+                            childTop = height - paddingBottom - child.getMeasuredHeight();
+                            paddingBottom += child.getMeasuredHeight();
+                            break;
+                    }
+                    childLeft += scrollX;
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                    decorCount++;
+                }
+            }
+        }
+
+        final int childWidth = width - paddingLeft - paddingRight;
+        // Page views. Do this once we have the right padding offsets from above.
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                ItemInfo ii;
+                if (!lp.isDecor && (ii = infoForChild(child)) != null) {
+                    int loff = (int) (childWidth * ii.offset);
+                    int childLeft = paddingLeft + loff;
+                    int childTop = paddingTop;
+                    if (lp.needsMeasure) {
+                        // This was added during layout and needs measurement.
+                        // Do it now that we know what we're working with.
+                        lp.needsMeasure = false;
+                        final int widthSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (childWidth * lp.widthFactor),
+                                MeasureSpec.EXACTLY);
+                        final int heightSpec = MeasureSpec.makeMeasureSpec(
+                                (int) (height - paddingTop - paddingBottom),
+                                MeasureSpec.EXACTLY);
+                        child.measure(widthSpec, heightSpec);
+                    }
+                    if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object
+                            + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()
+                            + "x" + child.getMeasuredHeight());
+                    child.layout(childLeft, childTop,
+                            childLeft + child.getMeasuredWidth(),
+                            childTop + child.getMeasuredHeight());
+                }
+            }
+        }
+        mTopPageBounds = paddingTop;
+        mBottomPageBounds = height - paddingBottom;
+        mDecorChildCount = decorCount;
+
+        if (mFirstLayout) {
+            scrollToItem(mCurItem, false, 0, false);
+        }
+        mFirstLayout = false;
+    }
+
+    @Override
+    public void computeScroll() {
+        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
+            int oldX = getScrollX();
+            int oldY = getScrollY();
+            int x = mScroller.getCurrX();
+            int y = mScroller.getCurrY();
+
+            if (oldX != x || oldY != y) {
+                scrollTo(x, y);
+                if (!pageScrolled(x)) {
+                    mScroller.abortAnimation();
+                    scrollTo(0, y);
+                }
+            }
+
+            // Keep on drawing until the animation has finished.
+            postInvalidateOnAnimation();
+            return;
+        }
+
+        // Done with scroll, clean up state.
+        completeScroll(true);
+    }
+
+    private boolean pageScrolled(int xpos) {
+        if (mItems.size() == 0) {
+            mCalledSuper = false;
+            onPageScrolled(0, 0, 0);
+            if (!mCalledSuper) {
+                throw new IllegalStateException(
+                        "onPageScrolled did not call superclass implementation");
+            }
+            return false;
+        }
+        final ItemInfo ii = infoForCurrentScrollPosition();
+        final int width = getClientWidth();
+        final int widthWithMargin = width + mPageMargin;
+        final float marginOffset = (float) mPageMargin / width;
+        final int currentPage = ii.position;
+        final float pageOffset = (((float) xpos / width) - ii.offset) /
+                (ii.widthFactor + marginOffset);
+        final int offsetPixels = (int) (pageOffset * widthWithMargin);
+
+        mCalledSuper = false;
+        onPageScrolled(currentPage, pageOffset, offsetPixels);
+        if (!mCalledSuper) {
+            throw new IllegalStateException(
+                    "onPageScrolled did not call superclass implementation");
+        }
+        return true;
+    }
+
+    /**
+     * This method will be invoked when the current page is scrolled, either as part
+     * of a programmatically initiated smooth scroll or a user initiated touch scroll.
+     * If you override this method you must call through to the superclass implementation
+     * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
+     * returns.
+     *
+     * @param position Position index of the first page currently being displayed.
+     *                 Page position+1 will be visible if positionOffset is nonzero.
+     * @param offset Value from [0, 1) indicating the offset from the page at position.
+     * @param offsetPixels Value in pixels indicating the offset from position.
+     */
+    protected void onPageScrolled(int position, float offset, int offsetPixels) {
+        // Offset any decor views if needed - keep them on-screen at all times.
+        if (mDecorChildCount > 0) {
+            final int scrollX = getScrollX();
+            int paddingLeft = getPaddingLeft();
+            int paddingRight = getPaddingRight();
+            final int width = getWidth();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (!lp.isDecor) continue;
+
+                final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+                int childLeft = 0;
+                switch (hgrav) {
+                    default:
+                        childLeft = paddingLeft;
+                        break;
+                    case Gravity.LEFT:
+                        childLeft = paddingLeft;
+                        paddingLeft += child.getWidth();
+                        break;
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = Math.max((width - child.getMeasuredWidth()) / 2,
+                                paddingLeft);
+                        break;
+                    case Gravity.RIGHT:
+                        childLeft = width - paddingRight - child.getMeasuredWidth();
+                        paddingRight += child.getMeasuredWidth();
+                        break;
+                }
+                childLeft += scrollX;
+
+                final int childOffset = childLeft - child.getLeft();
+                if (childOffset != 0) {
+                    child.offsetLeftAndRight(childOffset);
+                }
+            }
+        }
+
+        if (mOnPageChangeListener != null) {
+            mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+        if (mInternalPageChangeListener != null) {
+            mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);
+        }
+
+        if (mPageTransformer != null) {
+            final int scrollX = getScrollX();
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                if (lp.isDecor) continue;
+
+                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
+                mPageTransformer.transformPage(child, transformPos);
+            }
+        }
+
+        mCalledSuper = true;
+    }
+
+    private void completeScroll(boolean postEvents) {
+        boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
+        if (needPopulate) {
+            // Done with scroll, no longer want to cache view drawing.
+            setScrollingCacheEnabled(false);
+            mScroller.abortAnimation();
+            int oldX = getScrollX();
+            int oldY = getScrollY();
+            int x = mScroller.getCurrX();
+            int y = mScroller.getCurrY();
+            if (oldX != x || oldY != y) {
+                scrollTo(x, y);
+            }
+        }
+        mPopulatePending = false;
+        for (int i=0; i<mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            if (ii.scrolling) {
+                needPopulate = true;
+                ii.scrolling = false;
+            }
+        }
+        if (needPopulate) {
+            if (postEvents) {
+                postOnAnimation(mEndScrollRunnable);
+            } else {
+                mEndScrollRunnable.run();
+            }
+        }
+    }
+
+    private boolean isGutterDrag(float x, float dx) {
+        return (x < mGutterSize && dx > 0) || (x > getWidth() - mGutterSize && dx < 0);
+    }
+
+    private void enableLayers(boolean enable) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final int layerType = enable ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE;
+            getChildAt(i).setLayerType(layerType, null);
+        }
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        /*
+         * This method JUST determines whether we want to intercept the motion.
+         * If we return true, onMotionEvent will be called and we do the actual
+         * scrolling there.
+         */
+
+        final int action = ev.getAction() & MotionEvent.ACTION_MASK;
+
+        // Always take care of the touch gesture being complete.
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+            // Release the drag.
+            if (DEBUG) Log.v(TAG, "Intercept done!");
+            mIsBeingDragged = false;
+            mIsUnableToDrag = false;
+            mActivePointerId = INVALID_POINTER;
+            if (mVelocityTracker != null) {
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
+            }
+            return false;
+        }
+
+        // Nothing more to do here if we have decided whether or not we
+        // are dragging.
+        if (action != MotionEvent.ACTION_DOWN) {
+            if (mIsBeingDragged) {
+                if (DEBUG) Log.v(TAG, "Intercept returning true!");
+                return true;
+            }
+            if (mIsUnableToDrag) {
+                if (DEBUG) Log.v(TAG, "Intercept returning false!");
+                return false;
+            }
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE: {
+                /*
+                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+                 * whether the user has moved far enough from his original down touch.
+                 */
+
+                /*
+                * Locally do absolute value. mLastMotionY is set to the y value
+                * of the down event.
+                */
+                final int activePointerId = mActivePointerId;
+                if (activePointerId == INVALID_POINTER) {
+                    // If we don't have a valid id, the touch down wasn't on content.
+                    break;
+                }
+
+                final int pointerIndex = ev.findPointerIndex(activePointerId);
+                final float x = ev.getX(pointerIndex);
+                final float dx = x - mLastMotionX;
+                final float xDiff = Math.abs(dx);
+                final float y = ev.getY(pointerIndex);
+                final float yDiff = Math.abs(y - mInitialMotionY);
+                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+
+                if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
+                        canScroll(this, false, (int) dx, (int) x, (int) y)) {
+                    // Nested view has scrollable area under this point. Let it be handled there.
+                    mLastMotionX = x;
+                    mLastMotionY = y;
+                    mIsUnableToDrag = true;
+                    return false;
+                }
+                if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
+                    if (DEBUG) Log.v(TAG, "Starting drag!");
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                    mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
+                            mInitialMotionX - mTouchSlop;
+                    mLastMotionY = y;
+                    setScrollingCacheEnabled(true);
+                } else if (yDiff > mTouchSlop) {
+                    // The finger has moved enough in the vertical
+                    // direction to be counted as a drag...  abort
+                    // any attempt to drag horizontally, to work correctly
+                    // with children that have scrolling containers.
+                    if (DEBUG) Log.v(TAG, "Starting unable to drag!");
+                    mIsUnableToDrag = true;
+                }
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    if (performDrag(x)) {
+                        postInvalidateOnAnimation();
+                    }
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_DOWN: {
+                /*
+                 * Remember location of down touch.
+                 * ACTION_DOWN always refers to pointer index 0.
+                 */
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                mIsUnableToDrag = false;
+
+                mScroller.computeScrollOffset();
+                if (mScrollState == SCROLL_STATE_SETTLING &&
+                        Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
+                    // Let the user 'catch' the pager as it animates.
+                    mScroller.abortAnimation();
+                    mPopulatePending = false;
+                    populate();
+                    mIsBeingDragged = true;
+                    requestParentDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                } else {
+                    completeScroll(false);
+                    mIsBeingDragged = false;
+                }
+
+                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
+                        + " mIsBeingDragged=" + mIsBeingDragged
+                        + "mIsUnableToDrag=" + mIsUnableToDrag);
+                break;
+            }
+
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                break;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        /*
+         * The only time we want to intercept motion events is if we are in the
+         * drag mode.
+         */
+        return mIsBeingDragged;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mFakeDragging) {
+            // A fake drag is in progress already, ignore this real one
+            // but still eat the touch events.
+            // (It is likely that the user is multi-touching the screen.)
+            return true;
+        }
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
+            // Don't handle edge touches immediately -- they may actually belong to one of our
+            // descendants.
+            return false;
+        }
+
+        if (mAdapter == null || mAdapter.getCount() == 0) {
+            // Nothing to present or scroll; nothing to touch.
+            return false;
+        }
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(ev);
+
+        final int action = ev.getAction();
+        boolean needsInvalidate = false;
+
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                mScroller.abortAnimation();
+                mPopulatePending = false;
+                populate();
+
+                // Remember where the motion event started
+                mLastMotionX = mInitialMotionX = ev.getX();
+                mLastMotionY = mInitialMotionY = ev.getY();
+                mActivePointerId = ev.getPointerId(0);
+                break;
+            }
+            case MotionEvent.ACTION_MOVE:
+                if (!mIsBeingDragged) {
+                    final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(pointerIndex);
+                    final float xDiff = Math.abs(x - mLastMotionX);
+                    final float y = ev.getY(pointerIndex);
+                    final float yDiff = Math.abs(y - mLastMotionY);
+                    if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
+                    if (xDiff > mTouchSlop && xDiff > yDiff) {
+                        if (DEBUG) Log.v(TAG, "Starting drag!");
+                        mIsBeingDragged = true;
+                        requestParentDisallowInterceptTouchEvent(true);
+                        mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
+                                mInitialMotionX - mTouchSlop;
+                        mLastMotionY = y;
+                        setScrollState(SCROLL_STATE_DRAGGING);
+                        setScrollingCacheEnabled(true);
+
+                        // Disallow Parent Intercept, just in case
+                        ViewParent parent = getParent();
+                        if (parent != null) {
+                            parent.requestDisallowInterceptTouchEvent(true);
+                        }
+                    }
+                }
+                // Not else! Note that mIsBeingDragged can be set above.
+                if (mIsBeingDragged) {
+                    // Scroll to follow the motion event
+                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    needsInvalidate |= performDrag(x);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mIsBeingDragged) {
+                    final VelocityTracker velocityTracker = mVelocityTracker;
+                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                    int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+                    mPopulatePending = true;
+                    final int width = getClientWidth();
+                    final int scrollX = getScrollX();
+                    final ItemInfo ii = infoForCurrentScrollPosition();
+                    final int currentPage = ii.position;
+                    final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
+                    final int activePointerIndex =
+                            ev.findPointerIndex(mActivePointerId);
+                    final float x = ev.getX(activePointerIndex);
+                    final int totalDelta = (int) (x - mInitialMotionX);
+                    int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                            totalDelta);
+                    setCurrentItemInternal(nextPage, true, true, initialVelocity);
+
+                    mActivePointerId = INVALID_POINTER;
+                    endDrag();
+                    mLeftEdge.onRelease();
+                    mRightEdge.onRelease();
+                    needsInvalidate = true;
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                if (mIsBeingDragged) {
+                    scrollToItem(mCurItem, true, 0, false);
+                    mActivePointerId = INVALID_POINTER;
+                    endDrag();
+                    mLeftEdge.onRelease();
+                    mRightEdge.onRelease();
+                    needsInvalidate = true;
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                final int index = ev.getActionIndex();
+                final float x = ev.getX(index);
+                mLastMotionX = x;
+                mActivePointerId = ev.getPointerId(index);
+                break;
+            }
+            case MotionEvent.ACTION_POINTER_UP:
+                onSecondaryPointerUp(ev);
+                mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
+                break;
+        }
+        if (needsInvalidate) {
+            postInvalidateOnAnimation();
+        }
+        return true;
+    }
+
+    private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+    }
+
+    private boolean performDrag(float x) {
+        boolean needsInvalidate = false;
+
+        final float deltaX = mLastMotionX - x;
+        mLastMotionX = x;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX + deltaX;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+        boolean leftAbsolute = true;
+        boolean rightAbsolute = true;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftAbsolute = false;
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightAbsolute = false;
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            if (leftAbsolute) {
+                float over = leftBound - scrollX;
+                mLeftEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            if (rightAbsolute) {
+                float over = scrollX - rightBound;
+                mRightEdge.onPull(Math.abs(over) / width);
+                needsInvalidate = true;
+            }
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        return needsInvalidate;
+    }
+
+    /**
+     * @return Info about the page at the current scroll position.
+     *         This can be synthetic for a missing middle page; the 'object' field can be null.
+     */
+    private ItemInfo infoForCurrentScrollPosition() {
+        final int width = getClientWidth();
+        final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
+        final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
+        int lastPos = -1;
+        float lastOffset = 0.f;
+        float lastWidth = 0.f;
+        boolean first = true;
+
+        ItemInfo lastItem = null;
+        for (int i = 0; i < mItems.size(); i++) {
+            ItemInfo ii = mItems.get(i);
+            float offset;
+            if (!first && ii.position != lastPos + 1) {
+                // Create a synthetic item for a missing page.
+                ii = mTempItem;
+                ii.offset = lastOffset + lastWidth + marginOffset;
+                ii.position = lastPos + 1;
+                ii.widthFactor = mAdapter.getPageWidth(ii.position);
+                i--;
+            }
+            offset = ii.offset;
+
+            final float leftBound = offset;
+            final float rightBound = offset + ii.widthFactor + marginOffset;
+            if (first || scrollOffset >= leftBound) {
+                if (scrollOffset < rightBound || i == mItems.size() - 1) {
+                    return ii;
+                }
+            } else {
+                return lastItem;
+            }
+            first = false;
+            lastPos = ii.position;
+            lastOffset = offset;
+            lastWidth = ii.widthFactor;
+            lastItem = ii;
+        }
+
+        return lastItem;
+    }
+
+    private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
+        int targetPage;
+        if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {
+            targetPage = velocity > 0 ? currentPage : currentPage + 1;
+        } else {
+            final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f;
+            targetPage = (int) (currentPage + pageOffset + truncator);
+        }
+
+        if (mItems.size() > 0) {
+            final ItemInfo firstItem = mItems.get(0);
+            final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+
+            // Only let the user target pages we have items for
+            targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
+        }
+
+        return targetPage;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        boolean needsInvalidate = false;
+
+        final int overScrollMode = getOverScrollMode();
+        if (overScrollMode == View.OVER_SCROLL_ALWAYS ||
+                (overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS &&
+                        mAdapter != null && mAdapter.getCount() > 1)) {
+            if (!mLeftEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+                final int width = getWidth();
+
+                canvas.rotate(270);
+                canvas.translate(-height + getPaddingTop(), mFirstOffset * width);
+                mLeftEdge.setSize(height, width);
+                needsInvalidate |= mLeftEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+            if (!mRightEdge.isFinished()) {
+                final int restoreCount = canvas.save();
+                final int width = getWidth();
+                final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+
+                canvas.rotate(90);
+                canvas.translate(-getPaddingTop(), -(mLastOffset + 1) * width);
+                mRightEdge.setSize(height, width);
+                needsInvalidate |= mRightEdge.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            }
+        } else {
+            mLeftEdge.finish();
+            mRightEdge.finish();
+        }
+
+        if (needsInvalidate) {
+            // Keep animating
+            postInvalidateOnAnimation();
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // Draw the margin drawable between pages if needed.
+        if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) {
+            final int scrollX = getScrollX();
+            final int width = getWidth();
+
+            final float marginOffset = (float) mPageMargin / width;
+            int itemIndex = 0;
+            ItemInfo ii = mItems.get(0);
+            float offset = ii.offset;
+            final int itemCount = mItems.size();
+            final int firstPos = ii.position;
+            final int lastPos = mItems.get(itemCount - 1).position;
+            for (int pos = firstPos; pos < lastPos; pos++) {
+                while (pos > ii.position && itemIndex < itemCount) {
+                    ii = mItems.get(++itemIndex);
+                }
+
+                float drawAt;
+                if (pos == ii.position) {
+                    drawAt = (ii.offset + ii.widthFactor) * width;
+                    offset = ii.offset + ii.widthFactor + marginOffset;
+                } else {
+                    float widthFactor = mAdapter.getPageWidth(pos);
+                    drawAt = (offset + widthFactor) * width;
+                    offset += widthFactor + marginOffset;
+                }
+
+                if (drawAt + mPageMargin > scrollX) {
+                    mMarginDrawable.setBounds((int) drawAt, mTopPageBounds,
+                            (int) (drawAt + mPageMargin + 0.5f), mBottomPageBounds);
+                    mMarginDrawable.draw(canvas);
+                }
+
+                if (drawAt > scrollX + width) {
+                    break; // No more visible, no sense in continuing
+                }
+            }
+        }
+    }
+
+    /**
+     * Start a fake drag of the pager.
+     *
+     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager
+     * with the touch scrolling of another view, while still letting the ViewPager
+     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)
+     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call
+     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.
+     *
+     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag
+     * is already in progress, this method will return false.
+     *
+     * @return true if the fake drag began successfully, false if it could not be started.
+     *
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean beginFakeDrag() {
+        if (mIsBeingDragged) {
+            return false;
+        }
+        mFakeDragging = true;
+        setScrollState(SCROLL_STATE_DRAGGING);
+        mInitialMotionX = mLastMotionX = 0;
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        } else {
+            mVelocityTracker.clear();
+        }
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+        mFakeDragBeginTime = time;
+        return true;
+    }
+
+    /**
+     * End a fake drag of the pager.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     */
+    public void endFakeDrag() {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        final VelocityTracker velocityTracker = mVelocityTracker;
+        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+        int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
+        mPopulatePending = true;
+        final int width = getClientWidth();
+        final int scrollX = getScrollX();
+        final ItemInfo ii = infoForCurrentScrollPosition();
+        final int currentPage = ii.position;
+        final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
+        final int totalDelta = (int) (mLastMotionX - mInitialMotionX);
+        int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
+                totalDelta);
+        setCurrentItemInternal(nextPage, true, true, initialVelocity);
+        endDrag();
+
+        mFakeDragging = false;
+    }
+
+    /**
+     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.
+     *
+     * @param xOffset Offset in pixels to drag by.
+     * @see #beginFakeDrag()
+     * @see #endFakeDrag()
+     */
+    public void fakeDragBy(float xOffset) {
+        if (!mFakeDragging) {
+            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");
+        }
+
+        mLastMotionX += xOffset;
+
+        float oldScrollX = getScrollX();
+        float scrollX = oldScrollX - xOffset;
+        final int width = getClientWidth();
+
+        float leftBound = width * mFirstOffset;
+        float rightBound = width * mLastOffset;
+
+        final ItemInfo firstItem = mItems.get(0);
+        final ItemInfo lastItem = mItems.get(mItems.size() - 1);
+        if (firstItem.position != 0) {
+            leftBound = firstItem.offset * width;
+        }
+        if (lastItem.position != mAdapter.getCount() - 1) {
+            rightBound = lastItem.offset * width;
+        }
+
+        if (scrollX < leftBound) {
+            scrollX = leftBound;
+        } else if (scrollX > rightBound) {
+            scrollX = rightBound;
+        }
+        // Don't lose the rounded component
+        mLastMotionX += scrollX - (int) scrollX;
+        scrollTo((int) scrollX, getScrollY());
+        pageScrolled((int) scrollX);
+
+        // Synthesize an event for the VelocityTracker.
+        final long time = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,
+                mLastMotionX, 0, 0);
+        mVelocityTracker.addMovement(ev);
+        ev.recycle();
+    }
+
+    /**
+     * Returns true if a fake drag is in progress.
+     *
+     * @return true if currently in a fake drag, false otherwise.
+     *
+     * @see #beginFakeDrag()
+     * @see #fakeDragBy(float)
+     * @see #endFakeDrag()
+     */
+    public boolean isFakeDragging() {
+        return mFakeDragging;
+    }
+
+    private void onSecondaryPointerUp(MotionEvent ev) {
+        final int pointerIndex = ev.getActionIndex();
+        final int pointerId = ev.getPointerId(pointerIndex);
+        if (pointerId == mActivePointerId) {
+            // This was our active pointer going up. Choose a new
+            // active pointer and adjust accordingly.
+            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+            mLastMotionX = ev.getX(newPointerIndex);
+            mActivePointerId = ev.getPointerId(newPointerIndex);
+            if (mVelocityTracker != null) {
+                mVelocityTracker.clear();
+            }
+        }
+    }
+
+    private void endDrag() {
+        mIsBeingDragged = false;
+        mIsUnableToDrag = false;
+
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private void setScrollingCacheEnabled(boolean enabled) {
+        if (mScrollingCacheEnabled != enabled) {
+            mScrollingCacheEnabled = enabled;
+            if (USE_CACHE) {
+                final int size = getChildCount();
+                for (int i = 0; i < size; ++i) {
+                    final View child = getChildAt(i);
+                    if (child.getVisibility() != GONE) {
+                        child.setDrawingCacheEnabled(enabled);
+                    }
+                }
+            }
+        }
+    }
+
+    public boolean canScrollHorizontally(int direction) {
+        if (mAdapter == null) {
+            return false;
+        }
+
+        final int width = getClientWidth();
+        final int scrollX = getScrollX();
+        if (direction < 0) {
+            return (scrollX > (int) (width * mFirstOffset));
+        } else if (direction > 0) {
+            return (scrollX < (int) (width * mLastOffset));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v given a delta of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            // Count backwards - let topmost views consume scroll distance first.
+            for (int i = count - 1; i >= 0; i--) {
+                // TODO: Add versioned support here for transformed views.
+                // This will not work for transformed views in Honeycomb+
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
+                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
+                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && v.canScrollHorizontally(-dx);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // Let the focused view and/or our descendants get the key first
+        return super.dispatchKeyEvent(event) || executeKeyEvent(event);
+    }
+
+    /**
+     * You can call this function yourself to have the scroll view perform
+     * scrolling from a key event, just as if the event had been dispatched to
+     * it by the view hierarchy.
+     *
+     * @param event The key event to execute.
+     * @return Return true if the event was handled, else false.
+     */
+    public boolean executeKeyEvent(KeyEvent event) {
+        boolean handled = false;
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    handled = arrowScroll(FOCUS_LEFT);
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    handled = arrowScroll(FOCUS_RIGHT);
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        handled = arrowScroll(FOCUS_FORWARD);
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        handled = arrowScroll(FOCUS_BACKWARD);
+                    }
+                    break;
+            }
+        }
+        return handled;
+    }
+
+    public boolean arrowScroll(int direction) {
+        View currentFocused = findFocus();
+        if (currentFocused == this) {
+            currentFocused = null;
+        } else if (currentFocused != null) {
+            boolean isChild = false;
+            for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                    parent = parent.getParent()) {
+                if (parent == this) {
+                    isChild = true;
+                    break;
+                }
+            }
+            if (!isChild) {
+                // This would cause the focus search down below to fail in fun ways.
+                final StringBuilder sb = new StringBuilder();
+                sb.append(currentFocused.getClass().getSimpleName());
+                for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup;
+                        parent = parent.getParent()) {
+                    sb.append(" => ").append(parent.getClass().getSimpleName());
+                }
+                Log.e(TAG, "arrowScroll tried to find focus based on non-child " +
+                        "current focused view " + sb.toString());
+                currentFocused = null;
+            }
+        }
+
+        boolean handled = false;
+
+        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,
+                direction);
+        if (nextFocused != null && nextFocused != currentFocused) {
+            if (direction == View.FOCUS_LEFT) {
+                // If there is nothing to the left, or this is causing us to
+                // jump to the right, then what we really want to do is page left.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft >= currLeft) {
+                    handled = pageLeft();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            } else if (direction == View.FOCUS_RIGHT) {
+                // If there is nothing to the right, or this is causing us to
+                // jump to the left, then what we really want to do is page right.
+                final int nextLeft = getChildRectInPagerCoordinates(mTempRect, nextFocused).left;
+                final int currLeft = getChildRectInPagerCoordinates(mTempRect, currentFocused).left;
+                if (currentFocused != null && nextLeft <= currLeft) {
+                    handled = pageRight();
+                } else {
+                    handled = nextFocused.requestFocus();
+                }
+            }
+        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {
+            // Trying to move left and nothing there; try to page.
+            handled = pageLeft();
+        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {
+            // Trying to move right and nothing there; try to page.
+            handled = pageRight();
+        }
+        if (handled) {
+            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
+        }
+        return handled;
+    }
+
+    private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {
+        if (outRect == null) {
+            outRect = new Rect();
+        }
+        if (child == null) {
+            outRect.set(0, 0, 0, 0);
+            return outRect;
+        }
+        outRect.left = child.getLeft();
+        outRect.right = child.getRight();
+        outRect.top = child.getTop();
+        outRect.bottom = child.getBottom();
+
+        ViewParent parent = child.getParent();
+        while (parent instanceof ViewGroup && parent != this) {
+            final ViewGroup group = (ViewGroup) parent;
+            outRect.left += group.getLeft();
+            outRect.right += group.getRight();
+            outRect.top += group.getTop();
+            outRect.bottom += group.getBottom();
+
+            parent = group.getParent();
+        }
+        return outRect;
+    }
+
+    boolean pageLeft() {
+        if (mCurItem > 0) {
+            setCurrentItem(mCurItem-1, true);
+            return true;
+        }
+        return false;
+    }
+
+    boolean pageRight() {
+        if (mAdapter != null && mCurItem < (mAdapter.getCount()-1)) {
+            setCurrentItem(mCurItem+1, true);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        final int focusableCount = views.size();
+
+        final int descendantFocusability = getDescendantFocusability();
+
+        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
+            for (int i = 0; i < getChildCount(); i++) {
+                final View child = getChildAt(i);
+                if (child.getVisibility() == VISIBLE) {
+                    ItemInfo ii = infoForChild(child);
+                    if (ii != null && ii.position == mCurItem) {
+                        child.addFocusables(views, direction, focusableMode);
+                    }
+                }
+            }
+        }
+
+        // we add ourselves (if focusable) in all cases except for when we are
+        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
+        // to avoid the focus search finding layouts when a more precise search
+        // among the focusable children would be more interesting.
+        if (
+            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
+                // No focusable descendants
+                (focusableCount == views.size())) {
+            // Note that we can't call the superclass here, because it will
+            // add all views in.  So we need to do the same thing View does.
+            if (!isFocusable()) {
+                return;
+            }
+            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&
+                    isInTouchMode() && !isFocusableInTouchMode()) {
+                return;
+            }
+            if (views != null) {
+                views.add(this);
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be touchable.
+     */
+    @Override
+    public void addTouchables(ArrayList<View> views) {
+        // Note that we don't call super.addTouchables(), which means that
+        // we don't call View.addTouchables().  This is okay because a ViewPager
+        // is itself not touchable.
+        for (int i = 0; i < getChildCount(); i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    child.addTouchables(views);
+                }
+            }
+        }
+    }
+
+    /**
+     * We only want the current page that is being shown to be focusable.
+     */
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction,
+            Rect previouslyFocusedRect) {
+        int index;
+        int increment;
+        int end;
+        int count = getChildCount();
+        if ((direction & FOCUS_FORWARD) != 0) {
+            index = 0;
+            increment = 1;
+            end = count;
+        } else {
+            index = count - 1;
+            increment = -1;
+            end = -1;
+        }
+        for (int i = index; i != end; i += increment) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem) {
+                    if (child.requestFocus(direction, previouslyFocusedRect)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        // Dispatch scroll events from this ViewPager.
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        // Dispatch all other accessibility events from the current page.
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == VISIBLE) {
+                final ItemInfo ii = infoForChild(child);
+                if (ii != null && ii.position == mCurItem &&
+                        child.dispatchPopulateAccessibilityEvent(event)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return generateDefaultLayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && super.checkLayoutParams(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    class MyAccessibilityDelegate extends AccessibilityDelegate {
+
+        @Override
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(host, event);
+            event.setClassName(ViewPager.class.getName());
+            final AccessibilityRecord record = AccessibilityRecord.obtain();
+            record.setScrollable(canScroll());
+            if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED
+                    && mAdapter != null) {
+                record.setItemCount(mAdapter.getCount());
+                record.setFromIndex(mCurItem);
+                record.setToIndex(mCurItem);
+            }
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            info.setClassName(ViewPager.class.getName());
+            info.setScrollable(canScroll());
+            if (canScrollHorizontally(1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
+            if (canScrollHorizontally(-1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            }
+        }
+
+        @Override
+        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+            if (super.performAccessibilityAction(host, action, args)) {
+                return true;
+            }
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                    if (canScrollHorizontally(1)) {
+                        setCurrentItem(mCurItem + 1);
+                        return true;
+                    }
+                } return false;
+                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                    if (canScrollHorizontally(-1)) {
+                        setCurrentItem(mCurItem - 1);
+                        return true;
+                    }
+                } return false;
+            }
+            return false;
+        }
+
+        private boolean canScroll() {
+            return (mAdapter != null) && (mAdapter.getCount() > 1);
+        }
+    }
+
+    private class PagerObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            dataSetChanged();
+        }
+        @Override
+        public void onInvalidated() {
+            dataSetChanged();
+        }
+    }
+
+    /**
+     * Layout parameters that should be supplied for views added to a
+     * ViewPager.
+     */
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+        /**
+         * true if this view is a decoration on the pager itself and not
+         * a view supplied by the adapter.
+         */
+        public boolean isDecor;
+
+        /**
+         * Gravity setting for use on decor views only:
+         * Where to position the view page within the overall ViewPager
+         * container; constants are defined in {@link android.view.Gravity}.
+         */
+        public int gravity;
+
+        /**
+         * Width as a 0-1 multiplier of the measured pager width
+         */
+        float widthFactor = 0.f;
+
+        /**
+         * true if this view was added during layout and needs to be measured
+         * before being positioned.
+         */
+        boolean needsMeasure;
+
+        /**
+         * Adapter position this view is for if !isDecor
+         */
+        int position;
+
+        /**
+         * Current child index within the ViewPager that this view occupies
+         */
+        int childIndex;
+
+        public LayoutParams() {
+            super(FILL_PARENT, FILL_PARENT);
+        }
+
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
+            gravity = a.getInteger(0, Gravity.TOP);
+            a.recycle();
+        }
+    }
+
+    static class ViewPositionComparator implements Comparator<View> {
+        @Override
+        public int compare(View lhs, View rhs) {
+            final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();
+            final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();
+            if (llp.isDecor != rlp.isDecor) {
+                return llp.isDecor ? 1 : -1;
+            }
+            return llp.position - rlp.position;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
deleted file mode 100644
index 9e7a649..0000000
--- a/core/java/com/android/internal/widget/WaveView.java
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import java.util.ArrayList;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.media.AudioAttributes;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.R;
-
-/**
- * A special widget containing a center and outer ring. Moving the center ring to the outer ring
- * causes an event that can be caught by implementing OnTriggerListener.
- */
-public class WaveView extends View implements ValueAnimator.AnimatorUpdateListener {
-    private static final String TAG = "WaveView";
-    private static final boolean DBG = false;
-    private static final int WAVE_COUNT = 20; // default wave count
-    private static final long VIBRATE_SHORT = 20;  // msec
-    private static final long VIBRATE_LONG = 20;  // msec
-
-    // Lock state machine states
-    private static final int STATE_RESET_LOCK = 0;
-    private static final int STATE_READY = 1;
-    private static final int STATE_START_ATTEMPT = 2;
-    private static final int STATE_ATTEMPTING = 3;
-    private static final int STATE_UNLOCK_ATTEMPT = 4;
-    private static final int STATE_UNLOCK_SUCCESS = 5;
-
-    // Animation properties.
-    private static final long DURATION = 300; // duration of transitional animations
-    private static final long FINAL_DURATION = 200; // duration of final animations when unlocking
-    private static final long RING_DELAY = 1300; // when to start fading animated rings
-    private static final long FINAL_DELAY = 200; // delay for unlock success animation
-    private static final long SHORT_DELAY = 100; // for starting one animation after another.
-    private static final long WAVE_DURATION = 2000; // amount of time for way to expand/decay
-    private static final long RESET_TIMEOUT = 3000; // elapsed time of inactivity before we reset
-    private static final long DELAY_INCREMENT = 15; // increment per wave while tracking motion
-    private static final long DELAY_INCREMENT2 = 12; // increment per wave while not tracking
-    private static final long WAVE_DELAY = WAVE_DURATION / WAVE_COUNT; // initial propagation delay
-
-    /**
-     * The scale by which to multiply the unlock handle width to compute the radius
-     * in which it can be grabbed when accessibility is disabled.
-     */
-    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED = 0.5f;
-
-    /**
-     * The scale by which to multiply the unlock handle width to compute the radius
-     * in which it can be grabbed when accessibility is enabled (more generous).
-     */
-    private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.0f;
-
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
-    private Vibrator mVibrator;
-    private OnTriggerListener mOnTriggerListener;
-    private ArrayList<DrawableHolder> mDrawables = new ArrayList<DrawableHolder>(3);
-    private ArrayList<DrawableHolder> mLightWaves = new ArrayList<DrawableHolder>(WAVE_COUNT);
-    private boolean mFingerDown = false;
-    private float mRingRadius = 182.0f; // Radius of bitmap ring. Used to snap halo to it
-    private int mSnapRadius = 136; // minimum threshold for drag unlock
-    private int mWaveCount = WAVE_COUNT;  // number of waves
-    private long mWaveTimerDelay = WAVE_DELAY;
-    private int mCurrentWave = 0;
-    private float mLockCenterX; // center of widget as dictated by widget size
-    private float mLockCenterY;
-    private float mMouseX; // current mouse position as of last touch event
-    private float mMouseY;
-    private DrawableHolder mUnlockRing;
-    private DrawableHolder mUnlockDefault;
-    private DrawableHolder mUnlockHalo;
-    private int mLockState = STATE_RESET_LOCK;
-    private int mGrabbedState = OnTriggerListener.NO_HANDLE;
-    private boolean mWavesRunning;
-    private boolean mFinishWaves;
-
-    public WaveView(Context context) {
-        this(context, null);
-    }
-
-    public WaveView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView);
-        // mOrientation = a.getInt(R.styleable.WaveView_orientation, HORIZONTAL);
-        // a.recycle();
-
-        initDrawables();
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        mLockCenterX = 0.5f * w;
-        mLockCenterY = 0.5f * h;
-        super.onSizeChanged(w, h, oldw, oldh);
-    }
-
-    @Override
-    protected int getSuggestedMinimumWidth() {
-        // View should be large enough to contain the unlock ring + halo
-        return mUnlockRing.getWidth() + mUnlockHalo.getWidth();
-    }
-
-    @Override
-    protected int getSuggestedMinimumHeight() {
-        // View should be large enough to contain the unlock ring + halo
-        return mUnlockRing.getHeight() + mUnlockHalo.getHeight();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
-        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-        int widthSpecSize =  MeasureSpec.getSize(widthMeasureSpec);
-        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
-        int width;
-        int height;
-
-        if (widthSpecMode == MeasureSpec.AT_MOST) {
-            width = Math.min(widthSpecSize, getSuggestedMinimumWidth());
-        } else if (widthSpecMode == MeasureSpec.EXACTLY) {
-            width = widthSpecSize;
-        } else {
-            width = getSuggestedMinimumWidth();
-        }
-
-        if (heightSpecMode == MeasureSpec.AT_MOST) {
-            height = Math.min(heightSpecSize, getSuggestedMinimumWidth());
-        } else if (heightSpecMode == MeasureSpec.EXACTLY) {
-            height = heightSpecSize;
-        } else {
-            height = getSuggestedMinimumHeight();
-        }
-
-        setMeasuredDimension(width, height);
-    }
-
-    private void initDrawables() {
-        mUnlockRing = new DrawableHolder(createDrawable(R.drawable.unlock_ring));
-        mUnlockRing.setX(mLockCenterX);
-        mUnlockRing.setY(mLockCenterY);
-        mUnlockRing.setScaleX(0.1f);
-        mUnlockRing.setScaleY(0.1f);
-        mUnlockRing.setAlpha(0.0f);
-        mDrawables.add(mUnlockRing);
-
-        mUnlockDefault = new DrawableHolder(createDrawable(R.drawable.unlock_default));
-        mUnlockDefault.setX(mLockCenterX);
-        mUnlockDefault.setY(mLockCenterY);
-        mUnlockDefault.setScaleX(0.1f);
-        mUnlockDefault.setScaleY(0.1f);
-        mUnlockDefault.setAlpha(0.0f);
-        mDrawables.add(mUnlockDefault);
-
-        mUnlockHalo = new DrawableHolder(createDrawable(R.drawable.unlock_halo));
-        mUnlockHalo.setX(mLockCenterX);
-        mUnlockHalo.setY(mLockCenterY);
-        mUnlockHalo.setScaleX(0.1f);
-        mUnlockHalo.setScaleY(0.1f);
-        mUnlockHalo.setAlpha(0.0f);
-        mDrawables.add(mUnlockHalo);
-
-        BitmapDrawable wave = createDrawable(R.drawable.unlock_wave);
-        for (int i = 0; i < mWaveCount; i++) {
-            DrawableHolder holder = new DrawableHolder(wave);
-            mLightWaves.add(holder);
-            holder.setAlpha(0.0f);
-        }
-    }
-
-    private void waveUpdateFrame(float mouseX, float mouseY, boolean fingerDown) {
-        double distX = mouseX - mLockCenterX;
-        double distY = mouseY - mLockCenterY;
-        int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
-        double touchA = Math.atan2(distX, distY);
-        float ringX = (float) (mLockCenterX + mRingRadius * Math.sin(touchA));
-        float ringY = (float) (mLockCenterY + mRingRadius * Math.cos(touchA));
-
-        switch (mLockState) {
-            case STATE_RESET_LOCK:
-                if (DBG) Log.v(TAG, "State RESET_LOCK");
-                mWaveTimerDelay = WAVE_DELAY;
-                for (int i = 0; i < mLightWaves.size(); i++) {
-                    DrawableHolder holder = mLightWaves.get(i);
-                    holder.addAnimTo(300, 0, "alpha", 0.0f, false);
-                }
-                for (int i = 0; i < mLightWaves.size(); i++) {
-                    mLightWaves.get(i).startAnimations(this);
-                }
-
-                mUnlockRing.addAnimTo(DURATION, 0, "x", mLockCenterX, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "y", mLockCenterY, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 0.1f, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 0.1f, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 0.0f, true);
-
-                mUnlockDefault.removeAnimationFor("x");
-                mUnlockDefault.removeAnimationFor("y");
-                mUnlockDefault.removeAnimationFor("scaleX");
-                mUnlockDefault.removeAnimationFor("scaleY");
-                mUnlockDefault.removeAnimationFor("alpha");
-                mUnlockDefault.setX(mLockCenterX);
-                mUnlockDefault.setY(mLockCenterY);
-                mUnlockDefault.setScaleX(0.1f);
-                mUnlockDefault.setScaleY(0.1f);
-                mUnlockDefault.setAlpha(0.0f);
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
-
-                mUnlockHalo.removeAnimationFor("x");
-                mUnlockHalo.removeAnimationFor("y");
-                mUnlockHalo.removeAnimationFor("scaleX");
-                mUnlockHalo.removeAnimationFor("scaleY");
-                mUnlockHalo.removeAnimationFor("alpha");
-                mUnlockHalo.setX(mLockCenterX);
-                mUnlockHalo.setY(mLockCenterY);
-                mUnlockHalo.setScaleX(0.1f);
-                mUnlockHalo.setScaleY(0.1f);
-                mUnlockHalo.setAlpha(0.0f);
-                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "x", mLockCenterX, true);
-                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "y", mLockCenterY, true);
-                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, true);
-                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, true);
-                mUnlockHalo.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, true);
-
-                removeCallbacks(mLockTimerActions);
-
-                mLockState = STATE_READY;
-                break;
-
-            case STATE_READY:
-                if (DBG) Log.v(TAG, "State READY");
-                mWaveTimerDelay = WAVE_DELAY;
-                break;
-
-            case STATE_START_ATTEMPT:
-                if (DBG) Log.v(TAG, "State START_ATTEMPT");
-                mUnlockDefault.removeAnimationFor("x");
-                mUnlockDefault.removeAnimationFor("y");
-                mUnlockDefault.removeAnimationFor("scaleX");
-                mUnlockDefault.removeAnimationFor("scaleY");
-                mUnlockDefault.removeAnimationFor("alpha");
-                mUnlockDefault.setX(mLockCenterX + 182);
-                mUnlockDefault.setY(mLockCenterY);
-                mUnlockDefault.setScaleX(0.1f);
-                mUnlockDefault.setScaleY(0.1f);
-                mUnlockDefault.setAlpha(0.0f);
-
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleX", 1.0f, false);
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "scaleY", 1.0f, false);
-                mUnlockDefault.addAnimTo(DURATION, SHORT_DELAY, "alpha", 1.0f, false);
-
-                mUnlockRing.addAnimTo(DURATION, 0, "scaleX", 1.0f, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "scaleY", 1.0f, true);
-                mUnlockRing.addAnimTo(DURATION, 0, "alpha", 1.0f, true);
-
-                mLockState = STATE_ATTEMPTING;
-                break;
-
-            case STATE_ATTEMPTING:
-                if (DBG) Log.v(TAG, "State ATTEMPTING (fingerDown = " + fingerDown + ")");
-                if (dragDistance > mSnapRadius) {
-                    mFinishWaves = true; // don't start any more waves.
-                    if (fingerDown) {
-                        mUnlockHalo.addAnimTo(0, 0, "x", ringX, true);
-                        mUnlockHalo.addAnimTo(0, 0, "y", ringY, true);
-                        mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
-                        mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
-                        mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
-                    }  else {
-                        if (DBG) Log.v(TAG, "up detected, moving to STATE_UNLOCK_ATTEMPT");
-                        mLockState = STATE_UNLOCK_ATTEMPT;
-                    }
-                } else {
-                    // If waves have stopped, we need to kick them off again...
-                    if (!mWavesRunning) {
-                        mWavesRunning = true;
-                        mFinishWaves = false;
-                        // mWaveTimerDelay = WAVE_DELAY;
-                        postDelayed(mAddWaveAction, mWaveTimerDelay);
-                    }
-                    mUnlockHalo.addAnimTo(0, 0, "x", mouseX, true);
-                    mUnlockHalo.addAnimTo(0, 0, "y", mouseY, true);
-                    mUnlockHalo.addAnimTo(0, 0, "scaleX", 1.0f, true);
-                    mUnlockHalo.addAnimTo(0, 0, "scaleY", 1.0f, true);
-                    mUnlockHalo.addAnimTo(0, 0, "alpha", 1.0f, true);
-                }
-                break;
-
-            case STATE_UNLOCK_ATTEMPT:
-                if (DBG) Log.v(TAG, "State UNLOCK_ATTEMPT");
-                if (dragDistance > mSnapRadius) {
-                    for (int n = 0; n < mLightWaves.size(); n++) {
-                        DrawableHolder wave = mLightWaves.get(n);
-                        long delay = 1000L*(6 + n - mCurrentWave)/10L;
-                        wave.addAnimTo(FINAL_DURATION, delay, "x", ringX, true);
-                        wave.addAnimTo(FINAL_DURATION, delay, "y", ringY, true);
-                        wave.addAnimTo(FINAL_DURATION, delay, "scaleX", 0.1f, true);
-                        wave.addAnimTo(FINAL_DURATION, delay, "scaleY", 0.1f, true);
-                        wave.addAnimTo(FINAL_DURATION, delay, "alpha", 0.0f, true);
-                    }
-                    for (int i = 0; i < mLightWaves.size(); i++) {
-                        mLightWaves.get(i).startAnimations(this);
-                    }
-
-                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
-                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
-                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleX", 0.1f, false);
-                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "scaleY", 0.1f, false);
-                    mUnlockRing.addAnimTo(FINAL_DURATION, 0, "alpha", 0.0f, false);
-
-                    mUnlockRing.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
-
-                    mUnlockDefault.removeAnimationFor("x");
-                    mUnlockDefault.removeAnimationFor("y");
-                    mUnlockDefault.removeAnimationFor("scaleX");
-                    mUnlockDefault.removeAnimationFor("scaleY");
-                    mUnlockDefault.removeAnimationFor("alpha");
-                    mUnlockDefault.setX(ringX);
-                    mUnlockDefault.setY(ringY);
-                    mUnlockDefault.setScaleX(0.1f);
-                    mUnlockDefault.setScaleY(0.1f);
-                    mUnlockDefault.setAlpha(0.0f);
-
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "x", ringX, true);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "y", ringY, true);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleX", 1.0f, true);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "scaleY", 1.0f, true);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, 0, "alpha", 1.0f, true);
-
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
-                    mUnlockDefault.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
-
-                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "x", ringX, false);
-                    mUnlockHalo.addAnimTo(FINAL_DURATION, 0, "y", ringY, false);
-
-                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleX", 3.0f, false);
-                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "scaleY", 3.0f, false);
-                    mUnlockHalo.addAnimTo(FINAL_DURATION, FINAL_DELAY, "alpha", 0.0f, false);
-
-                    removeCallbacks(mLockTimerActions);
-
-                    postDelayed(mLockTimerActions, RESET_TIMEOUT);
-
-                    dispatchTriggerEvent(OnTriggerListener.CENTER_HANDLE);
-                    mLockState = STATE_UNLOCK_SUCCESS;
-                } else {
-                    mLockState = STATE_RESET_LOCK;
-                }
-                break;
-
-            case STATE_UNLOCK_SUCCESS:
-                if (DBG) Log.v(TAG, "State UNLOCK_SUCCESS");
-                removeCallbacks(mAddWaveAction);
-                break;
-
-            default:
-                if (DBG) Log.v(TAG, "Unknown state " + mLockState);
-                break;
-        }
-        mUnlockDefault.startAnimations(this);
-        mUnlockHalo.startAnimations(this);
-        mUnlockRing.startAnimations(this);
-    }
-
-    BitmapDrawable createDrawable(int resId) {
-        Resources res = getResources();
-        Bitmap bitmap = BitmapFactory.decodeResource(res, resId);
-        return new BitmapDrawable(res, bitmap);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
-        for (int i = 0; i < mDrawables.size(); ++i) {
-            mDrawables.get(i).draw(canvas);
-        }
-        for (int i = 0; i < mLightWaves.size(); ++i) {
-            mLightWaves.get(i).draw(canvas);
-        }
-    }
-
-    private final Runnable mLockTimerActions = new Runnable() {
-        public void run() {
-            if (DBG) Log.v(TAG, "LockTimerActions");
-            // reset lock after inactivity
-            if (mLockState == STATE_ATTEMPTING) {
-                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK");
-                mLockState = STATE_RESET_LOCK;
-            }
-            // for prototype, reset after successful unlock
-            if (mLockState == STATE_UNLOCK_SUCCESS) {
-                if (DBG) Log.v(TAG, "Timer resets to STATE_RESET_LOCK after success");
-                mLockState = STATE_RESET_LOCK;
-            }
-            invalidate();
-        }
-    };
-
-    private final Runnable mAddWaveAction = new Runnable() {
-        public void run() {
-            double distX = mMouseX - mLockCenterX;
-            double distY = mMouseY - mLockCenterY;
-            int dragDistance = (int) Math.ceil(Math.hypot(distX, distY));
-            if (mLockState == STATE_ATTEMPTING && dragDistance < mSnapRadius
-                    && mWaveTimerDelay >= WAVE_DELAY) {
-                mWaveTimerDelay = Math.min(WAVE_DURATION, mWaveTimerDelay + DELAY_INCREMENT);
-
-                DrawableHolder wave = mLightWaves.get(mCurrentWave);
-                wave.setAlpha(0.0f);
-                wave.setScaleX(0.2f);
-                wave.setScaleY(0.2f);
-                wave.setX(mMouseX);
-                wave.setY(mMouseY);
-
-                wave.addAnimTo(WAVE_DURATION, 0, "x", mLockCenterX, true);
-                wave.addAnimTo(WAVE_DURATION, 0, "y", mLockCenterY, true);
-                wave.addAnimTo(WAVE_DURATION*2/3, 0, "alpha", 1.0f, true);
-                wave.addAnimTo(WAVE_DURATION, 0, "scaleX", 1.0f, true);
-                wave.addAnimTo(WAVE_DURATION, 0, "scaleY", 1.0f, true);
-
-                wave.addAnimTo(1000, RING_DELAY, "alpha", 0.0f, false);
-                wave.startAnimations(WaveView.this);
-
-                mCurrentWave = (mCurrentWave+1) % mWaveCount;
-                if (DBG) Log.v(TAG, "WaveTimerDelay: start new wave in " + mWaveTimerDelay);
-            } else {
-                mWaveTimerDelay += DELAY_INCREMENT2;
-            }
-            if (mFinishWaves) {
-                // sentinel used to restart the waves after they've stopped
-                mWavesRunning = false;
-            } else {
-                postDelayed(mAddWaveAction, mWaveTimerDelay);
-            }
-        }
-    };
-
-    @Override
-    public boolean onHoverEvent(MotionEvent event) {
-        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
-            final int action = event.getAction();
-            switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    event.setAction(MotionEvent.ACTION_DOWN);
-                    break;
-                case MotionEvent.ACTION_HOVER_MOVE:
-                    event.setAction(MotionEvent.ACTION_MOVE);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    event.setAction(MotionEvent.ACTION_UP);
-                    break;
-            }
-            onTouchEvent(event);
-            event.setAction(action);
-        }
-        return super.onHoverEvent(event);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        final int action = event.getAction();
-        mMouseX = event.getX();
-        mMouseY = event.getY();
-        boolean handled = false;
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                removeCallbacks(mLockTimerActions);
-                mFingerDown = true;
-                tryTransitionToStartAttemptState(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                tryTransitionToStartAttemptState(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_UP:
-                if (DBG) Log.v(TAG, "ACTION_UP");
-                mFingerDown = false;
-                postDelayed(mLockTimerActions, RESET_TIMEOUT);
-                setGrabbedState(OnTriggerListener.NO_HANDLE);
-                // Normally the state machine is driven by user interaction causing redraws.
-                // However, when there's no more user interaction and no running animations,
-                // the state machine stops advancing because onDraw() never gets called.
-                // The following ensures we advance to the next state in this case,
-                // either STATE_UNLOCK_ATTEMPT or STATE_RESET_LOCK.
-                waveUpdateFrame(mMouseX, mMouseY, mFingerDown);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                mFingerDown = false;
-                handled = true;
-                break;
-        }
-        invalidate();
-        return handled ? true : super.onTouchEvent(event);
-    }
-
-    /**
-     * Tries to transition to start attempt state.
-     *
-     * @param event A motion event.
-     */
-    private void tryTransitionToStartAttemptState(MotionEvent event) {
-        final float dx = event.getX() - mUnlockHalo.getX();
-        final float dy = event.getY() - mUnlockHalo.getY();
-        float dist = (float) Math.hypot(dx, dy);
-        if (dist <= getScaledGrabHandleRadius()) {
-            setGrabbedState(OnTriggerListener.CENTER_HANDLE);
-            if (mLockState == STATE_READY) {
-                mLockState = STATE_START_ATTEMPT;
-                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                    announceUnlockHandle();
-                }
-            }
-        }
-    }
-
-    /**
-     * @return The radius in which the handle is grabbed scaled based on
-     *     whether accessibility is enabled.
-     */
-    private float getScaledGrabHandleRadius() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mUnlockHalo.getWidth();
-        } else {
-            return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED * mUnlockHalo.getWidth();
-        }
-    }
-
-    /**
-     * Announces the unlock handle if accessibility is enabled.
-     */
-    private void announceUnlockHandle() {
-        setContentDescription(mContext.getString(R.string.description_target_unlock_tablet));
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-        setContentDescription(null);
-    }
-
-    /**
-     * Triggers haptic feedback.
-     */
-    private synchronized void vibrate(long duration) {
-        final boolean hapticEnabled = Settings.System.getIntForUser(
-                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1,
-                UserHandle.USER_CURRENT) != 0;
-        if (hapticEnabled) {
-            if (mVibrator == null) {
-                mVibrator = (android.os.Vibrator) getContext()
-                        .getSystemService(Context.VIBRATOR_SERVICE);
-            }
-            mVibrator.vibrate(duration, VIBRATION_ATTRIBUTES);
-        }
-    }
-
-    /**
-     * Registers a callback to be invoked when the user triggers an event.
-     *
-     * @param listener the OnDialTriggerListener to attach to this view
-     */
-    public void setOnTriggerListener(OnTriggerListener listener) {
-        mOnTriggerListener = listener;
-    }
-
-    /**
-     * Dispatches a trigger event to listener. Ignored if a listener is not set.
-     * @param whichHandle the handle that triggered the event.
-     */
-    private void dispatchTriggerEvent(int whichHandle) {
-        vibrate(VIBRATE_LONG);
-        if (mOnTriggerListener != null) {
-            mOnTriggerListener.onTrigger(this, whichHandle);
-        }
-    }
-
-    /**
-     * Sets the current grabbed state, and dispatches a grabbed state change
-     * event to our listener.
-     */
-    private void setGrabbedState(int newState) {
-        if (newState != mGrabbedState) {
-            mGrabbedState = newState;
-            if (mOnTriggerListener != null) {
-                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
-            }
-        }
-    }
-
-    public interface OnTriggerListener {
-        /**
-         * Sent when the user releases the handle.
-         */
-        public static final int NO_HANDLE = 0;
-
-        /**
-         * Sent when the user grabs the center handle
-         */
-        public static final int CENTER_HANDLE = 10;
-
-        /**
-         * Called when the user drags the center ring beyond a threshold.
-         */
-        void onTrigger(View v, int whichHandle);
-
-        /**
-         * Called when the "grabbed state" changes (i.e. when the user either grabs or releases
-         * one of the handles.)
-         *
-         * @param v the view that was triggered
-         * @param grabbedState the new state: {@link #NO_HANDLE}, {@link #CENTER_HANDLE},
-         */
-        void onGrabbedStateChange(View v, int grabbedState);
-    }
-
-    public void onAnimationUpdate(ValueAnimator animation) {
-        invalidate();
-    }
-
-    public void reset() {
-        if (DBG) Log.v(TAG, "reset() : resets state to STATE_RESET_LOCK");
-        mLockState = STATE_RESET_LOCK;
-        invalidate();
-    }
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/Ease.java b/core/java/com/android/internal/widget/multiwaveview/Ease.java
deleted file mode 100644
index 7f90c44..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/Ease.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import android.animation.TimeInterpolator;
-
-class Ease {
-    private static final float DOMAIN = 1.0f;
-    private static final float DURATION = 1.0f;
-    private static final float START = 0.0f;
-
-    static class Linear {
-        public static final TimeInterpolator easeNone = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return input;
-            }
-        };
-    }
-
-    static class Cubic {
-        public static final TimeInterpolator easeIn = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN*(input/=DURATION)*input*input + START;
-            }
-        };
-        public static final TimeInterpolator easeOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START;
-            }
-        };
-        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return ((input/=DURATION/2) < 1.0f) ?
-                        (DOMAIN/2*input*input*input + START)
-                            : (DOMAIN/2*((input-=2)*input*input + 2) + START);
-            }
-        };
-    }
-
-    static class Quad {
-        public static final TimeInterpolator easeIn = new TimeInterpolator() {
-            public float getInterpolation (float input) {
-                return DOMAIN*(input/=DURATION)*input + START;
-            }
-        };
-        public static final TimeInterpolator easeOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return -DOMAIN *(input/=DURATION)*(input-2) + START;
-            }
-        };
-        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return ((input/=DURATION/2) < 1) ?
-                        (DOMAIN/2*input*input + START)
-                            : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START);
-            }
-        };
-    }
-
-    static class Quart {
-        public static final TimeInterpolator easeIn = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN*(input/=DURATION)*input*input*input + START;
-            }
-        };
-        public static final TimeInterpolator easeOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START;
-            }
-        };
-        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return ((input/=DURATION/2) < 1) ?
-                        (DOMAIN/2*input*input*input*input + START)
-                            : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START);
-            }
-        };
-    }
-
-    static class Quint {
-        public static final TimeInterpolator easeIn = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN*(input/=DURATION)*input*input*input*input + START;
-            }
-        };
-        public static final TimeInterpolator easeOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START;
-            }
-        };
-        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return ((input/=DURATION/2) < 1) ?
-                        (DOMAIN/2*input*input*input*input*input + START)
-                            : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START);
-            }
-        };
-    }
-
-    static class Sine {
-        public static final TimeInterpolator easeIn = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START;
-            }
-        };
-        public static final TimeInterpolator easeOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START;
-            }
-        };
-        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
-            public float getInterpolation(float input) {
-                return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START;
-            }
-        };
-    }
-
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
deleted file mode 100644
index b680fab..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ /dev/null
@@ -1,1383 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.media.AudioAttributes;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-
-/**
- * A re-usable widget containing a center, outer ring and wave animation.
- */
-public class GlowPadView extends View {
-    private static final String TAG = "GlowPadView";
-    private static final boolean DEBUG = false;
-
-    // Wave state machine
-    private static final int STATE_IDLE = 0;
-    private static final int STATE_START = 1;
-    private static final int STATE_FIRST_TOUCH = 2;
-    private static final int STATE_TRACKING = 3;
-    private static final int STATE_SNAP = 4;
-    private static final int STATE_FINISH = 5;
-
-    // Animation properties.
-    private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it
-
-    public interface OnTriggerListener {
-        int NO_HANDLE = 0;
-        int CENTER_HANDLE = 1;
-        public void onGrabbed(View v, int handle);
-        public void onReleased(View v, int handle);
-        public void onTrigger(View v, int target);
-        public void onGrabbedStateChange(View v, int handle);
-        public void onFinishFinalAnimation();
-    }
-
-    // Tuneable parameters for animation
-    private static final int WAVE_ANIMATION_DURATION = 1000;
-    private static final int RETURN_TO_HOME_DELAY = 1200;
-    private static final int RETURN_TO_HOME_DURATION = 200;
-    private static final int HIDE_ANIMATION_DELAY = 200;
-    private static final int HIDE_ANIMATION_DURATION = 200;
-    private static final int SHOW_ANIMATION_DURATION = 200;
-    private static final int SHOW_ANIMATION_DELAY = 50;
-    private static final int INITIAL_SHOW_HANDLE_DURATION = 200;
-    private static final int REVEAL_GLOW_DELAY = 0;
-    private static final int REVEAL_GLOW_DURATION = 0;
-
-    private static final float TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.3f;
-    private static final float TARGET_SCALE_EXPANDED = 1.0f;
-    private static final float TARGET_SCALE_COLLAPSED = 0.8f;
-    private static final float RING_SCALE_EXPANDED = 1.0f;
-    private static final float RING_SCALE_COLLAPSED = 0.5f;
-
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
-    private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
-    private AnimationBundle mWaveAnimations = new AnimationBundle();
-    private AnimationBundle mTargetAnimations = new AnimationBundle();
-    private AnimationBundle mGlowAnimations = new AnimationBundle();
-    private ArrayList<String> mTargetDescriptions;
-    private ArrayList<String> mDirectionDescriptions;
-    private OnTriggerListener mOnTriggerListener;
-    private TargetDrawable mHandleDrawable;
-    private TargetDrawable mOuterRing;
-    private Vibrator mVibrator;
-
-    private int mFeedbackCount = 3;
-    private int mVibrationDuration = 0;
-    private int mGrabbedState;
-    private int mActiveTarget = -1;
-    private float mGlowRadius;
-    private float mWaveCenterX;
-    private float mWaveCenterY;
-    private int mMaxTargetHeight;
-    private int mMaxTargetWidth;
-    private float mRingScaleFactor = 1f;
-    private boolean mAllowScaling;
-
-    private float mOuterRadius = 0.0f;
-    private float mSnapMargin = 0.0f;
-    private float mFirstItemOffset = 0.0f;
-    private boolean mMagneticTargets = false;
-    private boolean mDragging;
-    private int mNewTargetResources;
-
-    private class AnimationBundle extends ArrayList<Tweener> {
-        private static final long serialVersionUID = 0xA84D78726F127468L;
-        private boolean mSuspended;
-
-        public void start() {
-            if (mSuspended) return; // ignore attempts to start animations
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.start();
-            }
-        }
-
-        public void cancel() {
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.cancel();
-            }
-            clear();
-        }
-
-        public void stop() {
-            final int count = size();
-            for (int i = 0; i < count; i++) {
-                Tweener anim = get(i);
-                anim.animator.end();
-            }
-            clear();
-        }
-
-        public void setSuspended(boolean suspend) {
-            mSuspended = suspend;
-        }
-    };
-
-    private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
-            dispatchOnFinishFinalAnimation();
-        }
-    };
-
-    private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            ping();
-            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
-            dispatchOnFinishFinalAnimation();
-        }
-    };
-
-    private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
-        public void onAnimationUpdate(ValueAnimator animation) {
-            invalidate();
-        }
-    };
-
-    private boolean mAnimatingTargets;
-    private AnimatorListener mTargetUpdateListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animator) {
-            if (mNewTargetResources != 0) {
-                internalSetTargetResources(mNewTargetResources);
-                mNewTargetResources = 0;
-                hideTargets(false, false);
-            }
-            mAnimatingTargets = false;
-        }
-    };
-    private int mTargetResourceId;
-    private int mTargetDescriptionsResourceId;
-    private int mDirectionDescriptionsResourceId;
-    private boolean mAlwaysTrackFinger;
-    private int mHorizontalInset;
-    private int mVerticalInset;
-    private int mGravity = Gravity.TOP;
-    private boolean mInitialLayout = true;
-    private Tweener mBackgroundAnimator;
-    private PointCloud mPointCloud;
-    private float mInnerRadius;
-    private int mPointerId;
-
-    public GlowPadView(Context context) {
-        this(context, null);
-    }
-
-    public GlowPadView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        Resources res = context.getResources();
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GlowPadView);
-        mInnerRadius = a.getDimension(R.styleable.GlowPadView_innerRadius, mInnerRadius);
-        mOuterRadius = a.getDimension(R.styleable.GlowPadView_outerRadius, mOuterRadius);
-        mSnapMargin = a.getDimension(R.styleable.GlowPadView_snapMargin, mSnapMargin);
-        mFirstItemOffset = (float) Math.toRadians(
-                a.getFloat(R.styleable.GlowPadView_firstItemOffset,
-                        (float) Math.toDegrees(mFirstItemOffset)));
-        mVibrationDuration = a.getInt(R.styleable.GlowPadView_vibrationDuration,
-                mVibrationDuration);
-        mFeedbackCount = a.getInt(R.styleable.GlowPadView_feedbackCount,
-                mFeedbackCount);
-        mAllowScaling = a.getBoolean(R.styleable.GlowPadView_allowScaling, false);
-        TypedValue handle = a.peekValue(R.styleable.GlowPadView_handleDrawable);
-        mHandleDrawable = new TargetDrawable(res, handle != null ? handle.resourceId : 0);
-        mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
-        mOuterRing = new TargetDrawable(res,
-                getResourceId(a, R.styleable.GlowPadView_outerRingDrawable));
-
-        mAlwaysTrackFinger = a.getBoolean(R.styleable.GlowPadView_alwaysTrackFinger, false);
-        mMagneticTargets = a.getBoolean(R.styleable.GlowPadView_magneticTargets, mMagneticTargets);
-
-        int pointId = getResourceId(a, R.styleable.GlowPadView_pointDrawable);
-        Drawable pointDrawable = pointId != 0 ? context.getDrawable(pointId) : null;
-        mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
-
-        mPointCloud = new PointCloud(pointDrawable);
-        mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
-        mPointCloud.glowManager.setRadius(mGlowRadius);
-
-        TypedValue outValue = new TypedValue();
-
-        // Read array of target drawables
-        if (a.getValue(R.styleable.GlowPadView_targetDrawables, outValue)) {
-            internalSetTargetResources(outValue.resourceId);
-        }
-        if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
-            throw new IllegalStateException("Must specify at least one target drawable");
-        }
-
-        // Read array of target descriptions
-        if (a.getValue(R.styleable.GlowPadView_targetDescriptions, outValue)) {
-            final int resourceId = outValue.resourceId;
-            if (resourceId == 0) {
-                throw new IllegalStateException("Must specify target descriptions");
-            }
-            setTargetDescriptionsResourceId(resourceId);
-        }
-
-        // Read array of direction descriptions
-        if (a.getValue(R.styleable.GlowPadView_directionDescriptions, outValue)) {
-            final int resourceId = outValue.resourceId;
-            if (resourceId == 0) {
-                throw new IllegalStateException("Must specify direction descriptions");
-            }
-            setDirectionDescriptionsResourceId(resourceId);
-        }
-
-        mGravity = a.getInt(R.styleable.GlowPadView_gravity, Gravity.TOP);
-
-        a.recycle();
-
-        setVibrateEnabled(mVibrationDuration > 0);
-
-        assignDefaultsIfNeeded();
-    }
-
-    private int getResourceId(TypedArray a, int id) {
-        TypedValue tv = a.peekValue(id);
-        return tv == null ? 0 : tv.resourceId;
-    }
-
-    private void dump() {
-        Log.v(TAG, "Outer Radius = " + mOuterRadius);
-        Log.v(TAG, "SnapMargin = " + mSnapMargin);
-        Log.v(TAG, "FeedbackCount = " + mFeedbackCount);
-        Log.v(TAG, "VibrationDuration = " + mVibrationDuration);
-        Log.v(TAG, "GlowRadius = " + mGlowRadius);
-        Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
-        Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
-    }
-
-    public void suspendAnimations() {
-        mWaveAnimations.setSuspended(true);
-        mTargetAnimations.setSuspended(true);
-        mGlowAnimations.setSuspended(true);
-    }
-
-    public void resumeAnimations() {
-        mWaveAnimations.setSuspended(false);
-        mTargetAnimations.setSuspended(false);
-        mGlowAnimations.setSuspended(false);
-        mWaveAnimations.start();
-        mTargetAnimations.start();
-        mGlowAnimations.start();
-    }
-
-    @Override
-    protected int getSuggestedMinimumWidth() {
-        // View should be large enough to contain the background + handle and
-        // target drawable on either edge.
-        return (int) (Math.max(mOuterRing.getWidth(), 2 * mOuterRadius) + mMaxTargetWidth);
-    }
-
-    @Override
-    protected int getSuggestedMinimumHeight() {
-        // View should be large enough to contain the unlock ring + target and
-        // target drawable on either edge
-        return (int) (Math.max(mOuterRing.getHeight(), 2 * mOuterRadius) + mMaxTargetHeight);
-    }
-
-    /**
-     * This gets the suggested width accounting for the ring's scale factor.
-     */
-    protected int getScaledSuggestedMinimumWidth() {
-        return (int) (mRingScaleFactor * Math.max(mOuterRing.getWidth(), 2 * mOuterRadius)
-                + mMaxTargetWidth);
-    }
-
-    /**
-     * This gets the suggested height accounting for the ring's scale factor.
-     */
-    protected int getScaledSuggestedMinimumHeight() {
-        return (int) (mRingScaleFactor * Math.max(mOuterRing.getHeight(), 2 * mOuterRadius)
-                + mMaxTargetHeight);
-    }
-
-    private int resolveMeasured(int measureSpec, int desired)
-    {
-        int result = 0;
-        int specSize = MeasureSpec.getSize(measureSpec);
-        switch (MeasureSpec.getMode(measureSpec)) {
-            case MeasureSpec.UNSPECIFIED:
-                result = desired;
-                break;
-            case MeasureSpec.AT_MOST:
-                result = Math.min(specSize, desired);
-                break;
-            case MeasureSpec.EXACTLY:
-            default:
-                result = specSize;
-        }
-        return result;
-    }
-
-    private void switchToState(int state, float x, float y) {
-        switch (state) {
-            case STATE_IDLE:
-                deactivateTargets();
-                hideGlow(0, 0, 0.0f, null);
-                startBackgroundAnimation(0, 0.0f);
-                mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
-                mHandleDrawable.setAlpha(1.0f);
-                break;
-
-            case STATE_START:
-                startBackgroundAnimation(0, 0.0f);
-                break;
-
-            case STATE_FIRST_TOUCH:
-                mHandleDrawable.setAlpha(0.0f);
-                deactivateTargets();
-                showTargets(true);
-                startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f);
-                setGrabbedState(OnTriggerListener.CENTER_HANDLE);
-                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                    announceTargets();
-                }
-                break;
-
-            case STATE_TRACKING:
-                mHandleDrawable.setAlpha(0.0f);
-                showGlow(REVEAL_GLOW_DURATION , REVEAL_GLOW_DELAY, 1.0f, null);
-                break;
-
-            case STATE_SNAP:
-                // TODO: Add transition states (see list_selector_background_transition.xml)
-                mHandleDrawable.setAlpha(0.0f);
-                showGlow(REVEAL_GLOW_DURATION , REVEAL_GLOW_DELAY, 0.0f, null);
-                break;
-
-            case STATE_FINISH:
-                doFinish();
-                break;
-        }
-    }
-
-    private void showGlow(int duration, int delay, float finalAlpha,
-            AnimatorListener finishListener) {
-        mGlowAnimations.cancel();
-        mGlowAnimations.add(Tweener.to(mPointCloud.glowManager, duration,
-                "ease", Ease.Cubic.easeIn,
-                "delay", delay,
-                "alpha", finalAlpha,
-                "onUpdate", mUpdateListener,
-                "onComplete", finishListener));
-        mGlowAnimations.start();
-    }
-
-    private void hideGlow(int duration, int delay, float finalAlpha,
-            AnimatorListener finishListener) {
-        mGlowAnimations.cancel();
-        mGlowAnimations.add(Tweener.to(mPointCloud.glowManager, duration,
-                "ease", Ease.Quart.easeOut,
-                "delay", delay,
-                "alpha", finalAlpha,
-                "x", 0.0f,
-                "y", 0.0f,
-                "onUpdate", mUpdateListener,
-                "onComplete", finishListener));
-        mGlowAnimations.start();
-    }
-
-    private void deactivateTargets() {
-        final int count = mTargetDrawables.size();
-        for (int i = 0; i < count; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-        }
-        mActiveTarget = -1;
-    }
-
-    /**
-     * Dispatches a trigger event to listener. Ignored if a listener is not set.
-     * @param whichTarget the target that was triggered.
-     */
-    private void dispatchTriggerEvent(int whichTarget) {
-        vibrate();
-        if (mOnTriggerListener != null) {
-            mOnTriggerListener.onTrigger(this, whichTarget);
-        }
-    }
-
-    private void dispatchOnFinishFinalAnimation() {
-        if (mOnTriggerListener != null) {
-            mOnTriggerListener.onFinishFinalAnimation();
-        }
-    }
-
-    private void doFinish() {
-        final int activeTarget = mActiveTarget;
-        final boolean targetHit =  activeTarget != -1;
-
-        if (targetHit) {
-            if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
-
-            highlightSelected(activeTarget);
-
-            // Inform listener of any active targets.  Typically only one will be active.
-            hideGlow(RETURN_TO_HOME_DURATION, RETURN_TO_HOME_DELAY, 0.0f, mResetListener);
-            dispatchTriggerEvent(activeTarget);
-            if (!mAlwaysTrackFinger) {
-                // Force ring and targets to finish animation to final expanded state
-                mTargetAnimations.stop();
-            }
-        } else {
-            // Animate handle back to the center based on current state.
-            hideGlow(HIDE_ANIMATION_DURATION, 0, 0.0f, mResetListenerWithPing);
-            hideTargets(true, false);
-        }
-
-        setGrabbedState(OnTriggerListener.NO_HANDLE);
-    }
-
-    private void highlightSelected(int activeTarget) {
-        // Highlight the given target and fade others
-        mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
-        hideUnselected(activeTarget);
-    }
-
-    private void hideUnselected(int active) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            if (i != active) {
-                mTargetDrawables.get(i).setAlpha(0.0f);
-            }
-        }
-    }
-
-    private void hideTargets(boolean animate, boolean expanded) {
-        mTargetAnimations.cancel();
-        // Note: these animations should complete at the same time so that we can swap out
-        // the target assets asynchronously from the setTargetResources() call.
-        mAnimatingTargets = animate;
-        final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
-        final int delay = animate ? HIDE_ANIMATION_DELAY : 0;
-
-        final float targetScale = expanded ?
-                TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED;
-        final int length = mTargetDrawables.size();
-        final TimeInterpolator interpolator = Ease.Cubic.easeOut;
-        for (int i = 0; i < length; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-            mTargetAnimations.add(Tweener.to(target, duration,
-                    "ease", interpolator,
-                    "alpha", 0.0f,
-                    "scaleX", targetScale,
-                    "scaleY", targetScale,
-                    "delay", delay,
-                    "onUpdate", mUpdateListener));
-        }
-
-        float ringScaleTarget = expanded ?
-                RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED;
-        ringScaleTarget *= mRingScaleFactor;
-        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
-                "ease", interpolator,
-                "alpha", 0.0f,
-                "scaleX", ringScaleTarget,
-                "scaleY", ringScaleTarget,
-                "delay", delay,
-                "onUpdate", mUpdateListener,
-                "onComplete", mTargetUpdateListener));
-
-        mTargetAnimations.start();
-    }
-
-    private void showTargets(boolean animate) {
-        mTargetAnimations.stop();
-        mAnimatingTargets = animate;
-        final int delay = animate ? SHOW_ANIMATION_DELAY : 0;
-        final int duration = animate ? SHOW_ANIMATION_DURATION : 0;
-        final int length = mTargetDrawables.size();
-        for (int i = 0; i < length; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            target.setState(TargetDrawable.STATE_INACTIVE);
-            mTargetAnimations.add(Tweener.to(target, duration,
-                    "ease", Ease.Cubic.easeOut,
-                    "alpha", 1.0f,
-                    "scaleX", 1.0f,
-                    "scaleY", 1.0f,
-                    "delay", delay,
-                    "onUpdate", mUpdateListener));
-        }
-
-        float ringScale = mRingScaleFactor * RING_SCALE_EXPANDED;
-        mTargetAnimations.add(Tweener.to(mOuterRing, duration,
-                "ease", Ease.Cubic.easeOut,
-                "alpha", 1.0f,
-                "scaleX", ringScale,
-                "scaleY", ringScale,
-                "delay", delay,
-                "onUpdate", mUpdateListener,
-                "onComplete", mTargetUpdateListener));
-
-        mTargetAnimations.start();
-    }
-
-    private void vibrate() {
-        final boolean hapticEnabled = Settings.System.getIntForUser(
-                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 1,
-                UserHandle.USER_CURRENT) != 0;
-        if (mVibrator != null && hapticEnabled) {
-            mVibrator.vibrate(mVibrationDuration, VIBRATION_ATTRIBUTES);
-        }
-    }
-
-    private ArrayList<TargetDrawable> loadDrawableArray(int resourceId) {
-        Resources res = getContext().getResources();
-        TypedArray array = res.obtainTypedArray(resourceId);
-        final int count = array.length();
-        ArrayList<TargetDrawable> drawables = new ArrayList<TargetDrawable>(count);
-        for (int i = 0; i < count; i++) {
-            TypedValue value = array.peekValue(i);
-            TargetDrawable target = new TargetDrawable(res, value != null ? value.resourceId : 0);
-            drawables.add(target);
-        }
-        array.recycle();
-        return drawables;
-    }
-
-    private void internalSetTargetResources(int resourceId) {
-        final ArrayList<TargetDrawable> targets = loadDrawableArray(resourceId);
-        mTargetDrawables = targets;
-        mTargetResourceId = resourceId;
-
-        int maxWidth = mHandleDrawable.getWidth();
-        int maxHeight = mHandleDrawable.getHeight();
-        final int count = targets.size();
-        for (int i = 0; i < count; i++) {
-            TargetDrawable target = targets.get(i);
-            maxWidth = Math.max(maxWidth, target.getWidth());
-            maxHeight = Math.max(maxHeight, target.getHeight());
-        }
-        if (mMaxTargetWidth != maxWidth || mMaxTargetHeight != maxHeight) {
-            mMaxTargetWidth = maxWidth;
-            mMaxTargetHeight = maxHeight;
-            requestLayout(); // required to resize layout and call updateTargetPositions()
-        } else {
-            updateTargetPositions(mWaveCenterX, mWaveCenterY);
-            updatePointCloudPosition(mWaveCenterX, mWaveCenterY);
-        }
-    }
-
-    /**
-     * Loads an array of drawables from the given resourceId.
-     *
-     * @param resourceId
-     */
-    public void setTargetResources(int resourceId) {
-        if (mAnimatingTargets) {
-            // postpone this change until we return to the initial state
-            mNewTargetResources = resourceId;
-        } else {
-            internalSetTargetResources(resourceId);
-        }
-    }
-
-    public int getTargetResourceId() {
-        return mTargetResourceId;
-    }
-
-    /**
-     * Sets the resource id specifying the target descriptions for accessibility.
-     *
-     * @param resourceId The resource id.
-     */
-    public void setTargetDescriptionsResourceId(int resourceId) {
-        mTargetDescriptionsResourceId = resourceId;
-        if (mTargetDescriptions != null) {
-            mTargetDescriptions.clear();
-        }
-    }
-
-    /**
-     * Gets the resource id specifying the target descriptions for accessibility.
-     *
-     * @return The resource id.
-     */
-    public int getTargetDescriptionsResourceId() {
-        return mTargetDescriptionsResourceId;
-    }
-
-    /**
-     * Sets the resource id specifying the target direction descriptions for accessibility.
-     *
-     * @param resourceId The resource id.
-     */
-    public void setDirectionDescriptionsResourceId(int resourceId) {
-        mDirectionDescriptionsResourceId = resourceId;
-        if (mDirectionDescriptions != null) {
-            mDirectionDescriptions.clear();
-        }
-    }
-
-    /**
-     * Gets the resource id specifying the target direction descriptions.
-     *
-     * @return The resource id.
-     */
-    public int getDirectionDescriptionsResourceId() {
-        return mDirectionDescriptionsResourceId;
-    }
-
-    /**
-     * Enable or disable vibrate on touch.
-     *
-     * @param enabled
-     */
-    public void setVibrateEnabled(boolean enabled) {
-        if (enabled && mVibrator == null) {
-            mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
-        } else {
-            mVibrator = null;
-        }
-    }
-
-    /**
-     * Starts wave animation.
-     *
-     */
-    public void ping() {
-        if (mFeedbackCount > 0) {
-            boolean doWaveAnimation = true;
-            final AnimationBundle waveAnimations = mWaveAnimations;
-
-            // Don't do a wave if there's already one in progress
-            if (waveAnimations.size() > 0 && waveAnimations.get(0).animator.isRunning()) {
-                long t = waveAnimations.get(0).animator.getCurrentPlayTime();
-                if (t < WAVE_ANIMATION_DURATION/2) {
-                    doWaveAnimation = false;
-                }
-            }
-
-            if (doWaveAnimation) {
-                startWaveAnimation();
-            }
-        }
-    }
-
-    private void stopAndHideWaveAnimation() {
-        mWaveAnimations.cancel();
-        mPointCloud.waveManager.setAlpha(0.0f);
-    }
-
-    private void startWaveAnimation() {
-        mWaveAnimations.cancel();
-        mPointCloud.waveManager.setAlpha(1.0f);
-        mPointCloud.waveManager.setRadius(mHandleDrawable.getWidth()/2.0f);
-        mWaveAnimations.add(Tweener.to(mPointCloud.waveManager, WAVE_ANIMATION_DURATION,
-                "ease", Ease.Quad.easeOut,
-                "delay", 0,
-                "radius", 2.0f * mOuterRadius,
-                "onUpdate", mUpdateListener,
-                "onComplete",
-                new AnimatorListenerAdapter() {
-                    public void onAnimationEnd(Animator animator) {
-                        mPointCloud.waveManager.setRadius(0.0f);
-                        mPointCloud.waveManager.setAlpha(0.0f);
-                    }
-                }));
-        mWaveAnimations.start();
-    }
-
-    /**
-     * Resets the widget to default state and cancels all animation. If animate is 'true', will
-     * animate objects into place. Otherwise, objects will snap back to place.
-     *
-     * @param animate
-     */
-    public void reset(boolean animate) {
-        mGlowAnimations.stop();
-        mTargetAnimations.stop();
-        startBackgroundAnimation(0, 0.0f);
-        stopAndHideWaveAnimation();
-        hideTargets(animate, false);
-        hideGlow(0, 0, 0.0f, null);
-        Tweener.reset();
-    }
-
-    private void startBackgroundAnimation(int duration, float alpha) {
-        final Drawable background = getBackground();
-        if (mAlwaysTrackFinger && background != null) {
-            if (mBackgroundAnimator != null) {
-                mBackgroundAnimator.animator.cancel();
-            }
-            mBackgroundAnimator = Tweener.to(background, duration,
-                    "ease", Ease.Cubic.easeIn,
-                    "alpha", (int)(255.0f * alpha),
-                    "delay", SHOW_ANIMATION_DELAY);
-            mBackgroundAnimator.animator.start();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        final int action = event.getActionMasked();
-        boolean handled = false;
-        switch (action) {
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_DOWN:
-                if (DEBUG) Log.v(TAG, "*** DOWN ***");
-                handleDown(event);
-                handleMove(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (DEBUG) Log.v(TAG, "*** MOVE ***");
-                handleMove(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_UP:
-                if (DEBUG) Log.v(TAG, "*** UP ***");
-                handleMove(event);
-                handleUp(event);
-                handled = true;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                if (DEBUG) Log.v(TAG, "*** CANCEL ***");
-                handleMove(event);
-                handleCancel(event);
-                handled = true;
-                break;
-
-        }
-        invalidate();
-        return handled ? true : super.onTouchEvent(event);
-    }
-
-    private void updateGlowPosition(float x, float y) {
-        float dx = x - mOuterRing.getX();
-        float dy = y - mOuterRing.getY();
-        dx *= 1f / mRingScaleFactor;
-        dy *= 1f / mRingScaleFactor;
-        mPointCloud.glowManager.setX(mOuterRing.getX() + dx);
-        mPointCloud.glowManager.setY(mOuterRing.getY() + dy);
-    }
-
-    private void handleDown(MotionEvent event) {
-        int actionIndex = event.getActionIndex();
-        float eventX = event.getX(actionIndex);
-        float eventY = event.getY(actionIndex);
-        switchToState(STATE_START, eventX, eventY);
-        if (!trySwitchToFirstTouchState(eventX, eventY)) {
-            mDragging = false;
-        } else {
-            mPointerId = event.getPointerId(actionIndex);
-            updateGlowPosition(eventX, eventY);
-        }
-    }
-
-    private void handleUp(MotionEvent event) {
-        if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
-        int actionIndex = event.getActionIndex();
-        if (event.getPointerId(actionIndex) == mPointerId) {
-            switchToState(STATE_FINISH, event.getX(actionIndex), event.getY(actionIndex));
-        }
-    }
-
-    private void handleCancel(MotionEvent event) {
-        if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
-
-        // Drop the active target if canceled.
-        mActiveTarget = -1; 
-
-        int actionIndex = event.findPointerIndex(mPointerId);
-        actionIndex = actionIndex == -1 ? 0 : actionIndex;
-        switchToState(STATE_FINISH, event.getX(actionIndex), event.getY(actionIndex));
-    }
-
-    private void handleMove(MotionEvent event) {
-        int activeTarget = -1;
-        final int historySize = event.getHistorySize();
-        ArrayList<TargetDrawable> targets = mTargetDrawables;
-        int ntargets = targets.size();
-        float x = 0.0f;
-        float y = 0.0f;
-        float activeAngle = 0.0f;
-        int actionIndex = event.findPointerIndex(mPointerId);
-
-        if (actionIndex == -1) {
-            return;  // no data for this pointer
-        }
-
-        for (int k = 0; k < historySize + 1; k++) {
-            float eventX = k < historySize ? event.getHistoricalX(actionIndex, k)
-                    : event.getX(actionIndex);
-            float eventY = k < historySize ? event.getHistoricalY(actionIndex, k)
-                    : event.getY(actionIndex);
-            // tx and ty are relative to wave center
-            float tx = eventX - mWaveCenterX;
-            float ty = eventY - mWaveCenterY;
-            float touchRadius = (float) Math.sqrt(dist2(tx, ty));
-            final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
-            float limitX = tx * scale;
-            float limitY = ty * scale;
-            double angleRad = Math.atan2(-ty, tx);
-
-            if (!mDragging) {
-                trySwitchToFirstTouchState(eventX, eventY);
-            }
-
-            if (mDragging) {
-                // For multiple targets, snap to the one that matches
-                final float snapRadius = mRingScaleFactor * mOuterRadius - mSnapMargin;
-                final float snapDistance2 = snapRadius * snapRadius;
-                // Find first target in range
-                for (int i = 0; i < ntargets; i++) {
-                    TargetDrawable target = targets.get(i);
-
-                    double targetMinRad = mFirstItemOffset + (i - 0.5) * 2 * Math.PI / ntargets;
-                    double targetMaxRad = mFirstItemOffset + (i + 0.5) * 2 * Math.PI / ntargets;
-                    if (target.isEnabled()) {
-                        boolean angleMatches =
-                            (angleRad > targetMinRad && angleRad <= targetMaxRad) ||
-                            (angleRad + 2 * Math.PI > targetMinRad &&
-                             angleRad + 2 * Math.PI <= targetMaxRad) ||
-                            (angleRad - 2 * Math.PI > targetMinRad &&
-                             angleRad - 2 * Math.PI <= targetMaxRad);
-                        if (angleMatches && (dist2(tx, ty) > snapDistance2)) {
-                            activeTarget = i;
-                            activeAngle = (float) -angleRad;
-                        }
-                    }
-                }
-            }
-            x = limitX;
-            y = limitY;
-        }
-
-        if (!mDragging) {
-            return;
-        }
-
-        if (activeTarget != -1) {
-            switchToState(STATE_SNAP, x,y);
-            updateGlowPosition(x, y);
-        } else {
-            switchToState(STATE_TRACKING, x, y);
-            updateGlowPosition(x, y);
-        }
-
-        if (mActiveTarget != activeTarget) {
-            // Defocus the old target
-            if (mActiveTarget != -1) {
-                TargetDrawable target = targets.get(mActiveTarget);
-                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
-                    target.setState(TargetDrawable.STATE_INACTIVE);
-                }
-                if (mMagneticTargets) {
-                    updateTargetPosition(mActiveTarget, mWaveCenterX, mWaveCenterY);
-                }
-            }
-            // Focus the new target
-            if (activeTarget != -1) {
-                TargetDrawable target = targets.get(activeTarget);
-                if (target.hasState(TargetDrawable.STATE_FOCUSED)) {
-                    target.setState(TargetDrawable.STATE_FOCUSED);
-                }
-                if (mMagneticTargets) {
-                    updateTargetPosition(activeTarget, mWaveCenterX, mWaveCenterY, activeAngle);
-                }
-                if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                    String targetContentDescription = getTargetDescription(activeTarget);
-                    announceForAccessibility(targetContentDescription);
-                }
-            }
-        }
-        mActiveTarget = activeTarget;
-    }
-
-    @Override
-    public boolean onHoverEvent(MotionEvent event) {
-        if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
-            final int action = event.getAction();
-            switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    event.setAction(MotionEvent.ACTION_DOWN);
-                    break;
-                case MotionEvent.ACTION_HOVER_MOVE:
-                    event.setAction(MotionEvent.ACTION_MOVE);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    event.setAction(MotionEvent.ACTION_UP);
-                    break;
-            }
-            onTouchEvent(event);
-            event.setAction(action);
-        }
-        super.onHoverEvent(event);
-        return true;
-    }
-
-    /**
-     * Sets the current grabbed state, and dispatches a grabbed state change
-     * event to our listener.
-     */
-    private void setGrabbedState(int newState) {
-        if (newState != mGrabbedState) {
-            if (newState != OnTriggerListener.NO_HANDLE) {
-                vibrate();
-            }
-            mGrabbedState = newState;
-            if (mOnTriggerListener != null) {
-                if (newState == OnTriggerListener.NO_HANDLE) {
-                    mOnTriggerListener.onReleased(this, OnTriggerListener.CENTER_HANDLE);
-                } else {
-                    mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE);
-                }
-                mOnTriggerListener.onGrabbedStateChange(this, newState);
-            }
-        }
-    }
-
-    private boolean trySwitchToFirstTouchState(float x, float y) {
-        final float tx = x - mWaveCenterX;
-        final float ty = y - mWaveCenterY;
-        if (mAlwaysTrackFinger || dist2(tx,ty) <= getScaledGlowRadiusSquared()) {
-            if (DEBUG) Log.v(TAG, "** Handle HIT");
-            switchToState(STATE_FIRST_TOUCH, x, y);
-            updateGlowPosition(tx, ty);
-            mDragging = true;
-            return true;
-        }
-        return false;
-    }
-
-    private void assignDefaultsIfNeeded() {
-        if (mOuterRadius == 0.0f) {
-            mOuterRadius = Math.max(mOuterRing.getWidth(), mOuterRing.getHeight())/2.0f;
-        }
-        if (mSnapMargin == 0.0f) {
-            mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
-        }
-        if (mInnerRadius == 0.0f) {
-            mInnerRadius = mHandleDrawable.getWidth() / 10.0f;
-        }
-    }
-
-    private void computeInsets(int dx, int dy) {
-        final int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.LEFT:
-                mHorizontalInset = 0;
-                break;
-            case Gravity.RIGHT:
-                mHorizontalInset = dx;
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-            default:
-                mHorizontalInset = dx / 2;
-                break;
-        }
-        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.TOP:
-                mVerticalInset = 0;
-                break;
-            case Gravity.BOTTOM:
-                mVerticalInset = dy;
-                break;
-            case Gravity.CENTER_VERTICAL:
-            default:
-                mVerticalInset = dy / 2;
-                break;
-        }
-    }
-
-    /**
-     * Given the desired width and height of the ring and the allocated width and height, compute
-     * how much we need to scale the ring.
-     */
-    private float computeScaleFactor(int desiredWidth, int desiredHeight,
-            int actualWidth, int actualHeight) {
-
-        // Return unity if scaling is not allowed.
-        if (!mAllowScaling) return 1f;
-
-        final int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-
-        float scaleX = 1f;
-        float scaleY = 1f;
-
-        // We use the gravity as a cue for whether we want to scale on a particular axis.
-        // We only scale to fit horizontally if we're not pinned to the left or right. Likewise,
-        // we only scale to fit vertically if we're not pinned to the top or bottom. In these
-        // cases, we want the ring to hang off the side or top/bottom, respectively.
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.LEFT:
-            case Gravity.RIGHT:
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-            default:
-                if (desiredWidth > actualWidth) {
-                    scaleX = (1f * actualWidth - mMaxTargetWidth) /
-                            (desiredWidth - mMaxTargetWidth);
-                }
-                break;
-        }
-        switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.TOP:
-            case Gravity.BOTTOM:
-                break;
-            case Gravity.CENTER_VERTICAL:
-            default:
-                if (desiredHeight > actualHeight) {
-                    scaleY = (1f * actualHeight - mMaxTargetHeight) /
-                            (desiredHeight - mMaxTargetHeight);
-                }
-                break;
-        }
-        return Math.min(scaleX, scaleY);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int minimumWidth = getSuggestedMinimumWidth();
-        final int minimumHeight = getSuggestedMinimumHeight();
-        int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
-        int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
-
-        mRingScaleFactor = computeScaleFactor(minimumWidth, minimumHeight,
-                computedWidth, computedHeight);
-
-        int scaledWidth = getScaledSuggestedMinimumWidth();
-        int scaledHeight = getScaledSuggestedMinimumHeight();
-
-        computeInsets(computedWidth - scaledWidth, computedHeight - scaledHeight);
-        setMeasuredDimension(computedWidth, computedHeight);
-    }
-
-    private float getRingWidth() {
-        return mRingScaleFactor * Math.max(mOuterRing.getWidth(), 2 * mOuterRadius);
-    }
-
-    private float getRingHeight() {
-        return mRingScaleFactor * Math.max(mOuterRing.getHeight(), 2 * mOuterRadius);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        final int width = right - left;
-        final int height = bottom - top;
-
-        // Target placement width/height. This puts the targets on the greater of the ring
-        // width or the specified outer radius.
-        final float placementWidth = getRingWidth();
-        final float placementHeight = getRingHeight();
-        float newWaveCenterX = mHorizontalInset
-                + Math.max(width, mMaxTargetWidth + placementWidth) / 2;
-        float newWaveCenterY = mVerticalInset
-                + Math.max(height, + mMaxTargetHeight + placementHeight) / 2;
-
-        if (mInitialLayout) {
-            stopAndHideWaveAnimation();
-            hideTargets(false, false);
-            mInitialLayout = false;
-        }
-
-        mOuterRing.setPositionX(newWaveCenterX);
-        mOuterRing.setPositionY(newWaveCenterY);
-
-        mPointCloud.setScale(mRingScaleFactor);
-
-        mHandleDrawable.setPositionX(newWaveCenterX);
-        mHandleDrawable.setPositionY(newWaveCenterY);
-
-        updateTargetPositions(newWaveCenterX, newWaveCenterY);
-        updatePointCloudPosition(newWaveCenterX, newWaveCenterY);
-        updateGlowPosition(newWaveCenterX, newWaveCenterY);
-
-        mWaveCenterX = newWaveCenterX;
-        mWaveCenterY = newWaveCenterY;
-
-        if (DEBUG) dump();
-    }
-
-    private void updateTargetPosition(int i, float centerX, float centerY) {
-        final float angle = getAngle(getSliceAngle(), i);
-        updateTargetPosition(i, centerX, centerY, angle);
-    }
-
-    private void updateTargetPosition(int i, float centerX, float centerY, float angle) {
-        final float placementRadiusX = getRingWidth() / 2;
-        final float placementRadiusY = getRingHeight() / 2;
-        if (i >= 0) {
-            ArrayList<TargetDrawable> targets = mTargetDrawables;
-            final TargetDrawable targetIcon = targets.get(i);
-            targetIcon.setPositionX(centerX);
-            targetIcon.setPositionY(centerY);
-            targetIcon.setX(placementRadiusX * (float) Math.cos(angle));
-            targetIcon.setY(placementRadiusY * (float) Math.sin(angle));
-        }
-    }
-
-    private void updateTargetPositions(float centerX, float centerY) {
-        updateTargetPositions(centerX, centerY, false);
-    }
-
-    private void updateTargetPositions(float centerX, float centerY, boolean skipActive) {
-        final int size = mTargetDrawables.size();
-        final float alpha = getSliceAngle();
-        // Reposition the target drawables if the view changed.
-        for (int i = 0; i < size; i++) {
-            if (!skipActive || i != mActiveTarget) {
-                updateTargetPosition(i, centerX, centerY, getAngle(alpha, i));
-            }
-        }
-    }
-
-    private float getAngle(float alpha, int i) {
-        return mFirstItemOffset + alpha * i;
-    }
-
-    private float getSliceAngle() {
-        return (float) (-2.0f * Math.PI / mTargetDrawables.size());
-    }
-
-    private void updatePointCloudPosition(float centerX, float centerY) {
-        mPointCloud.setCenter(centerX, centerY);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        mPointCloud.draw(canvas);
-        mOuterRing.draw(canvas);
-        final int ntargets = mTargetDrawables.size();
-        for (int i = 0; i < ntargets; i++) {
-            TargetDrawable target = mTargetDrawables.get(i);
-            if (target != null) {
-                target.draw(canvas);
-            }
-        }
-        mHandleDrawable.draw(canvas);
-    }
-
-    public void setOnTriggerListener(OnTriggerListener listener) {
-        mOnTriggerListener = listener;
-    }
-
-    private float square(float d) {
-        return d * d;
-    }
-
-    private float dist2(float dx, float dy) {
-        return dx*dx + dy*dy;
-    }
-
-    private float getScaledGlowRadiusSquared() {
-        final float scaledTapRadius;
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            scaledTapRadius = TAP_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mGlowRadius;
-        } else {
-            scaledTapRadius = mGlowRadius;
-        }
-        return square(scaledTapRadius);
-    }
-
-    private void announceTargets() {
-        StringBuilder utterance = new StringBuilder();
-        final int targetCount = mTargetDrawables.size();
-        for (int i = 0; i < targetCount; i++) {
-            String targetDescription = getTargetDescription(i);
-            String directionDescription = getDirectionDescription(i);
-            if (!TextUtils.isEmpty(targetDescription)
-                    && !TextUtils.isEmpty(directionDescription)) {
-                String text = String.format(directionDescription, targetDescription);
-                utterance.append(text);
-            }
-        }
-        if (utterance.length() > 0) {
-            announceForAccessibility(utterance.toString());
-        }
-    }
-
-    private String getTargetDescription(int index) {
-        if (mTargetDescriptions == null || mTargetDescriptions.isEmpty()) {
-            mTargetDescriptions = loadDescriptions(mTargetDescriptionsResourceId);
-            if (mTargetDrawables.size() != mTargetDescriptions.size()) {
-                Log.w(TAG, "The number of target drawables must be"
-                        + " equal to the number of target descriptions.");
-                return null;
-            }
-        }
-        return mTargetDescriptions.get(index);
-    }
-
-    private String getDirectionDescription(int index) {
-        if (mDirectionDescriptions == null || mDirectionDescriptions.isEmpty()) {
-            mDirectionDescriptions = loadDescriptions(mDirectionDescriptionsResourceId);
-            if (mTargetDrawables.size() != mDirectionDescriptions.size()) {
-                Log.w(TAG, "The number of target drawables must be"
-                        + " equal to the number of direction descriptions.");
-                return null;
-            }
-        }
-        return mDirectionDescriptions.get(index);
-    }
-
-    private ArrayList<String> loadDescriptions(int resourceId) {
-        TypedArray array = getContext().getResources().obtainTypedArray(resourceId);
-        final int count = array.length();
-        ArrayList<String> targetContentDescriptions = new ArrayList<String>(count);
-        for (int i = 0; i < count; i++) {
-            String contentDescription = array.getString(i);
-            targetContentDescriptions.add(contentDescription);
-        }
-        array.recycle();
-        return targetContentDescriptions;
-    }
-
-    public int getResourceIdForTarget(int index) {
-        final TargetDrawable drawable = mTargetDrawables.get(index);
-        return drawable == null ? 0 : drawable.getResourceId();
-    }
-
-    public void setEnableTarget(int resourceId, boolean enabled) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            final TargetDrawable target = mTargetDrawables.get(i);
-            if (target.getResourceId() == resourceId) {
-                target.setEnabled(enabled);
-                break; // should never be more than one match
-            }
-        }
-    }
-
-    /**
-     * Gets the position of a target in the array that matches the given resource.
-     * @param resourceId
-     * @return the index or -1 if not found
-     */
-    public int getTargetPosition(int resourceId) {
-        for (int i = 0; i < mTargetDrawables.size(); i++) {
-            final TargetDrawable target = mTargetDrawables.get(i);
-            if (target.getResourceId() == resourceId) {
-                return i; // should never be more than one match
-            }
-        }
-        return -1;
-    }
-
-    private boolean replaceTargetDrawables(Resources res, int existingResourceId,
-            int newResourceId) {
-        if (existingResourceId == 0 || newResourceId == 0) {
-            return false;
-        }
-
-        boolean result = false;
-        final ArrayList<TargetDrawable> drawables = mTargetDrawables;
-        final int size = drawables.size();
-        for (int i = 0; i < size; i++) {
-            final TargetDrawable target = drawables.get(i);
-            if (target != null && target.getResourceId() == existingResourceId) {
-                target.setDrawable(res, newResourceId);
-                result = true;
-            }
-        }
-
-        if (result) {
-            requestLayout(); // in case any given drawable's size changes
-        }
-
-        return result;
-    }
-
-    /**
-     * Searches the given package for a resource to use to replace the Drawable on the
-     * target with the given resource id
-     * @param component of the .apk that contains the resource
-     * @param name of the metadata in the .apk
-     * @param existingResId the resource id of the target to search for
-     * @return true if found in the given package and replaced at least one target Drawables
-     */
-    public boolean replaceTargetDrawablesIfPresent(ComponentName component, String name,
-                int existingResId) {
-        if (existingResId == 0) return false;
-
-        boolean replaced = false;
-        if (component != null) {
-            try {
-                PackageManager packageManager = mContext.getPackageManager();
-                // Look for the search icon specified in the activity meta-data
-                Bundle metaData = packageManager.getActivityInfo(
-                        component, PackageManager.GET_META_DATA).metaData;
-                if (metaData != null) {
-                    int iconResId = metaData.getInt(name);
-                    if (iconResId != 0) {
-                        Resources res = packageManager.getResourcesForActivity(component);
-                        replaced = replaceTargetDrawables(res, existingResId, iconResId);
-                    }
-                }
-            } catch (NameNotFoundException e) {
-                Log.w(TAG, "Failed to swap drawable; "
-                        + component.flattenToShortString() + " not found", e);
-            } catch (Resources.NotFoundException nfe) {
-                Log.w(TAG, "Failed to swap drawable from "
-                        + component.flattenToShortString(), nfe);
-            }
-        }
-        if (!replaced) {
-            // Restore the original drawable
-            replaceTargetDrawables(mContext.getResources(), existingResId, existingResId);
-        }
-        return replaced;
-    }
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
deleted file mode 100644
index f299935..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import java.util.ArrayList;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.util.FloatMath;
-import android.util.Log;
-
-public class PointCloud {
-    private static final float MIN_POINT_SIZE = 2.0f;
-    private static final float MAX_POINT_SIZE = 4.0f;
-    private static final int INNER_POINTS = 8;
-    private static final String TAG = "PointCloud";
-    private ArrayList<Point> mPointCloud = new ArrayList<Point>();
-    private Drawable mDrawable;
-    private float mCenterX;
-    private float mCenterY;
-    private Paint mPaint;
-    private float mScale = 1.0f;
-    private static final float PI = (float) Math.PI;
-
-    // These allow us to have multiple concurrent animations.
-    WaveManager waveManager = new WaveManager();
-    GlowManager glowManager = new GlowManager();
-    private float mOuterRadius;
-
-    public class WaveManager {
-        private float radius = 50;
-        private float alpha = 0.0f;
-
-        public void setRadius(float r) {
-            radius = r;
-        }
-
-        public float getRadius() {
-            return radius;
-        }
-
-        public void setAlpha(float a) {
-            alpha = a;
-        }
-
-        public float getAlpha() {
-            return alpha;
-        }
-    };
-
-    public class GlowManager {
-        private float x;
-        private float y;
-        private float radius = 0.0f;
-        private float alpha = 0.0f;
-
-        public void setX(float x1) {
-            x = x1;
-        }
-
-        public float getX() {
-            return x;
-        }
-
-        public void setY(float y1) {
-            y = y1;
-        }
-
-        public float getY() {
-            return y;
-        }
-
-        public void setAlpha(float a) {
-            alpha = a;
-        }
-
-        public float getAlpha() {
-            return alpha;
-        }
-
-        public void setRadius(float r) {
-            radius = r;
-        }
-
-        public float getRadius() {
-            return radius;
-        }
-    }
-
-    class Point {
-        float x;
-        float y;
-        float radius;
-
-        public Point(float x2, float y2, float r) {
-            x = (float) x2;
-            y = (float) y2;
-            radius = r;
-        }
-    }
-
-    public PointCloud(Drawable drawable) {
-        mPaint = new Paint();
-        mPaint.setFilterBitmap(true);
-        mPaint.setColor(Color.rgb(255, 255, 255)); // TODO: make configurable
-        mPaint.setAntiAlias(true);
-        mPaint.setDither(true);
-
-        mDrawable = drawable;
-        if (mDrawable != null) {
-            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
-        }
-    }
-
-    public void setCenter(float x, float y) {
-        mCenterX = x;
-        mCenterY = y;
-    }
-
-    public void makePointCloud(float innerRadius, float outerRadius) {
-        if (innerRadius == 0) {
-            Log.w(TAG, "Must specify an inner radius");
-            return;
-        }
-        mOuterRadius = outerRadius;
-        mPointCloud.clear();
-        final float pointAreaRadius =  (outerRadius - innerRadius);
-        final float ds = (2.0f * PI * innerRadius / INNER_POINTS);
-        final int bands = (int) Math.round(pointAreaRadius / ds);
-        final float dr = pointAreaRadius / bands;
-        float r = innerRadius;
-        for (int b = 0; b <= bands; b++, r += dr) {
-            float circumference = 2.0f * PI * r;
-            final int pointsInBand = (int) (circumference / ds);
-            float eta = PI/2.0f;
-            float dEta = 2.0f * PI / pointsInBand;
-            for (int i = 0; i < pointsInBand; i++) {
-                float x = r * FloatMath.cos(eta);
-                float y = r * FloatMath.sin(eta);
-                eta += dEta;
-                mPointCloud.add(new Point(x, y, r));
-            }
-        }
-    }
-
-    public void setScale(float scale) {
-        mScale  = scale;
-    }
-
-    public float getScale() {
-        return mScale;
-    }
-
-    private static float hypot(float x, float y) {
-        return FloatMath.sqrt(x*x + y*y);
-    }
-
-    private static float max(float a, float b) {
-        return a > b ? a : b;
-    }
-
-    public int getAlphaForPoint(Point point) {
-        // Contribution from positional glow
-        float glowDistance = hypot(glowManager.x - point.x, glowManager.y - point.y);
-        float glowAlpha = 0.0f;
-        if (glowDistance < glowManager.radius) {
-            float cosf = FloatMath.cos(PI * 0.25f * glowDistance / glowManager.radius);
-            glowAlpha = glowManager.alpha * max(0.0f, (float) Math.pow(cosf, 10.0f));
-        }
-
-        // Compute contribution from Wave
-        float radius = hypot(point.x, point.y);
-        float waveAlpha = 0.0f;
-        if (radius < waveManager.radius * 2) {
-            float distanceToWaveRing = (radius - waveManager.radius);
-            float cosf = FloatMath.cos(PI * 0.5f * distanceToWaveRing / waveManager.radius);
-            waveAlpha = waveManager.alpha * max(0.0f, (float) Math.pow(cosf, 6.0f));
-        }
-        return (int) (max(glowAlpha, waveAlpha) * 255);
-    }
-
-    private float interp(float min, float max, float f) {
-        return min + (max - min) * f;
-    }
-
-    public void draw(Canvas canvas) {
-        ArrayList<Point> points = mPointCloud;
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        canvas.scale(mScale, mScale, mCenterX, mCenterY);
-        for (int i = 0; i < points.size(); i++) {
-            Point point = points.get(i);
-            final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE,
-                    point.radius / mOuterRadius);
-            final float px = point.x + mCenterX;
-            final float py = point.y + mCenterY;
-            int alpha = getAlphaForPoint(point);
-
-            if (alpha == 0) continue;
-
-            if (mDrawable != null) {
-                canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                final float cx = mDrawable.getIntrinsicWidth() * 0.5f;
-                final float cy = mDrawable.getIntrinsicHeight() * 0.5f;
-                final float s = pointSize / MAX_POINT_SIZE;
-                canvas.scale(s, s, px, py);
-                canvas.translate(px - cx, py - cy);
-                mDrawable.setAlpha(alpha);
-                mDrawable.draw(canvas);
-                canvas.restore();
-            } else {
-                mPaint.setAlpha(alpha);
-                canvas.drawCircle(px, py, pointSize, mPaint);
-            }
-        }
-        canvas.restore();
-    }
-
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
deleted file mode 100644
index 5a4c441..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.util.Log;
-
-public class TargetDrawable {
-    private static final String TAG = "TargetDrawable";
-    private static final boolean DEBUG = false;
-
-    public static final int[] STATE_ACTIVE =
-            { android.R.attr.state_enabled, android.R.attr.state_active };
-    public static final int[] STATE_INACTIVE =
-            { android.R.attr.state_enabled, -android.R.attr.state_active };
-    public static final int[] STATE_FOCUSED =
-            { android.R.attr.state_enabled, -android.R.attr.state_active,
-                android.R.attr.state_focused };
-
-    private float mTranslationX = 0.0f;
-    private float mTranslationY = 0.0f;
-    private float mPositionX = 0.0f;
-    private float mPositionY = 0.0f;
-    private float mScaleX = 1.0f;
-    private float mScaleY = 1.0f;
-    private float mAlpha = 1.0f;
-    private Drawable mDrawable;
-    private boolean mEnabled = true;
-    private final int mResourceId;
-
-    public TargetDrawable(Resources res, int resId) {
-        mResourceId = resId;
-        setDrawable(res, resId);
-    }
-
-    public void setDrawable(Resources res, int resId) {
-        // Note we explicitly don't set mResourceId to resId since we allow the drawable to be
-        // swapped at runtime and want to re-use the existing resource id for identification.
-        Drawable drawable = resId == 0 ? null : res.getDrawable(resId);
-        // Mutate the drawable so we can animate shared drawable properties.
-        mDrawable = drawable != null ? drawable.mutate() : null;
-        resizeDrawables();
-        setState(STATE_INACTIVE);
-    }
-
-    public TargetDrawable(TargetDrawable other) {
-        mResourceId = other.mResourceId;
-        // Mutate the drawable so we can animate shared drawable properties.
-        mDrawable = other.mDrawable != null ? other.mDrawable.mutate() : null;
-        resizeDrawables();
-        setState(STATE_INACTIVE);
-    }
-
-    public void setState(int [] state) {
-        if (mDrawable instanceof StateListDrawable) {
-            StateListDrawable d = (StateListDrawable) mDrawable;
-            d.setState(state);
-        }
-    }
-
-    public boolean hasState(int [] state) {
-        if (mDrawable instanceof StateListDrawable) {
-            StateListDrawable d = (StateListDrawable) mDrawable;
-            // TODO: this doesn't seem to work
-            return d.getStateDrawableIndex(state) != -1;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the drawable is a StateListDrawable and is in the focused state.
-     *
-     * @return
-     */
-    public boolean isActive() {
-        if (mDrawable instanceof StateListDrawable) {
-            StateListDrawable d = (StateListDrawable) mDrawable;
-            int[] states = d.getState();
-            for (int i = 0; i < states.length; i++) {
-                if (states[i] == android.R.attr.state_focused) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if this target is enabled. Typically an enabled target contains a valid
-     * drawable in a valid state. Currently all targets with valid drawables are valid.
-     *
-     * @return
-     */
-    public boolean isEnabled() {
-        return mDrawable != null && mEnabled;
-    }
-
-    /**
-     * Makes drawables in a StateListDrawable all the same dimensions.
-     * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
-     * drawable.
-     */
-    private void resizeDrawables() {
-        if (mDrawable instanceof StateListDrawable) {
-            StateListDrawable d = (StateListDrawable) mDrawable;
-            int maxWidth = 0;
-            int maxHeight = 0;
-            for (int i = 0; i < d.getStateCount(); i++) {
-                Drawable childDrawable = d.getStateDrawable(i);
-                maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
-                maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
-            }
-            if (DEBUG) Log.v(TAG, "union of childDrawable rects " + d + " to: "
-                        + maxWidth + "x" + maxHeight);
-            d.setBounds(0, 0, maxWidth, maxHeight);
-            for (int i = 0; i < d.getStateCount(); i++) {
-                Drawable childDrawable = d.getStateDrawable(i);
-                if (DEBUG) Log.v(TAG, "sizing drawable " + childDrawable + " to: "
-                            + maxWidth + "x" + maxHeight);
-                childDrawable.setBounds(0, 0, maxWidth, maxHeight);
-            }
-        } else if (mDrawable != null) {
-            mDrawable.setBounds(0, 0,
-                    mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
-        }
-    }
-
-    public void setX(float x) {
-        mTranslationX = x;
-    }
-
-    public void setY(float y) {
-        mTranslationY = y;
-    }
-
-    public void setScaleX(float x) {
-        mScaleX = x;
-    }
-
-    public void setScaleY(float y) {
-        mScaleY = y;
-    }
-
-    public void setAlpha(float alpha) {
-        mAlpha = alpha;
-    }
-
-    public float getX() {
-        return mTranslationX;
-    }
-
-    public float getY() {
-        return mTranslationY;
-    }
-
-    public float getScaleX() {
-        return mScaleX;
-    }
-
-    public float getScaleY() {
-        return mScaleY;
-    }
-
-    public float getAlpha() {
-        return mAlpha;
-    }
-
-    public void setPositionX(float x) {
-        mPositionX = x;
-    }
-
-    public void setPositionY(float y) {
-        mPositionY = y;
-    }
-
-    public float getPositionX() {
-        return mPositionX;
-    }
-
-    public float getPositionY() {
-        return mPositionY;
-    }
-
-    public int getWidth() {
-        return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
-    }
-
-    public int getHeight() {
-        return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
-    }
-
-    public void draw(Canvas canvas) {
-        if (mDrawable == null || !mEnabled) {
-            return;
-        }
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        canvas.scale(mScaleX, mScaleY, mPositionX, mPositionY);
-        canvas.translate(mTranslationX + mPositionX, mTranslationY + mPositionY);
-        canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
-        mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
-        mDrawable.draw(canvas);
-        canvas.restore();
-    }
-
-    public void setEnabled(boolean enabled) {
-        mEnabled  = enabled;
-    }
-
-    public int getResourceId() {
-        return mResourceId;
-    }
-}
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
deleted file mode 100644
index d559d9d..0000000
--- a/core/java/com/android/internal/widget/multiwaveview/Tweener.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget.multiwaveview;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map.Entry;
-
-import android.animation.Animator.AnimatorListener;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.util.Log;
-
-class Tweener {
-    private static final String TAG = "Tweener";
-    private static final boolean DEBUG = false;
-
-    ObjectAnimator animator;
-    private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
-
-    public Tweener(ObjectAnimator anim) {
-        animator = anim;
-    }
-
-    private static void remove(Animator animator) {
-        Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
-        while (iter.hasNext()) {
-            Entry<Object, Tweener> entry = iter.next();
-            if (entry.getValue().animator == animator) {
-                if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
-                        + " sTweens.size() = " + sTweens.size());
-                iter.remove();
-                break; // an animator can only be attached to one object
-            }
-        }
-    }
-
-    public static Tweener to(Object object, long duration, Object... vars) {
-        long delay = 0;
-        AnimatorUpdateListener updateListener = null;
-        AnimatorListener listener = null;
-        TimeInterpolator interpolator = null;
-
-        // Iterate through arguments and discover properties to animate
-        ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
-        for (int i = 0; i < vars.length; i+=2) {
-            if (!(vars[i] instanceof String)) {
-                throw new IllegalArgumentException("Key must be a string: " + vars[i]);
-            }
-            String key = (String) vars[i];
-            Object value = vars[i+1];
-            if ("simultaneousTween".equals(key)) {
-                // TODO
-            } else if ("ease".equals(key)) {
-                interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
-            } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
-                updateListener = (AnimatorUpdateListener) value;
-            } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
-                listener = (AnimatorListener) value;
-            } else if ("delay".equals(key)) {
-                delay = ((Number) value).longValue();
-            } else if ("syncWith".equals(key)) {
-                // TODO
-            } else if (value instanceof float[]) {
-                props.add(PropertyValuesHolder.ofFloat(key,
-                        ((float[])value)[0], ((float[])value)[1]));
-            } else if (value instanceof int[]) {
-                props.add(PropertyValuesHolder.ofInt(key,
-                        ((int[])value)[0], ((int[])value)[1]));
-            } else if (value instanceof Number) {
-                float floatValue = ((Number)value).floatValue();
-                props.add(PropertyValuesHolder.ofFloat(key, floatValue));
-            } else {
-                throw new IllegalArgumentException(
-                        "Bad argument for key \"" + key + "\" with value " + value.getClass());
-            }
-        }
-
-        // Re-use existing tween, if present
-        Tweener tween = sTweens.get(object);
-        ObjectAnimator anim = null;
-        if (tween == null) {
-            anim = ObjectAnimator.ofPropertyValuesHolder(object,
-                    props.toArray(new PropertyValuesHolder[props.size()]));
-            tween = new Tweener(anim);
-            sTweens.put(object, tween);
-            if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
-        } else {
-            anim = sTweens.get(object).animator;
-            replace(props, object); // Cancel all animators for given object
-        }
-
-        if (interpolator != null) {
-            anim.setInterpolator(interpolator);
-        }
-
-        // Update animation with properties discovered in loop above
-        anim.setStartDelay(delay);
-        anim.setDuration(duration);
-        if (updateListener != null) {
-            anim.removeAllUpdateListeners(); // There should be only one
-            anim.addUpdateListener(updateListener);
-        }
-        if (listener != null) {
-            anim.removeAllListeners(); // There should be only one.
-            anim.addListener(listener);
-        }
-        anim.addListener(mCleanupListener);
-
-        return tween;
-    }
-
-    Tweener from(Object object, long duration, Object... vars) {
-        // TODO:  for v of vars
-        //            toVars[v] = object[v]
-        //            object[v] = vars[v]
-        return Tweener.to(object, duration, vars);
-    }
-
-    // Listener to watch for completed animations and remove them.
-    private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            remove(animation);
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            remove(animation);
-        }
-    };
-
-    public static void reset() {
-        if (DEBUG) {
-            Log.v(TAG, "Reset()");
-            if (sTweens.size() > 0) {
-                Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
-            }
-        }
-        sTweens.clear();
-    }
-
-    private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
-        for (final Object killobject : args) {
-            Tweener tween = sTweens.get(killobject);
-            if (tween != null) {
-                tween.animator.cancel();
-                if (props != null) {
-                    tween.animator.setValues(
-                            props.toArray(new PropertyValuesHolder[props.size()]));
-                } else {
-                    sTweens.remove(tween);
-                }
-            }
-        }
-    }
-}
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
new file mode 100644
index 0000000..3f4b980
--- /dev/null
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -0,0 +1,380 @@
+/*
+ * 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.backup;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SyncAdapterType;
+import android.content.SyncStatusObserver;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper for backing up account sync settings (whether or not a service should be synced). The
+ * sync settings are backed up as a JSON object containing all the necessary information for
+ * restoring the sync settings later.
+ */
+public class AccountSyncSettingsBackupHelper implements BackupHelper {
+
+    private static final String TAG = "AccountSyncSettingsBackupHelper";
+    private static final boolean DEBUG = false;
+
+    private static final int STATE_VERSION = 1;
+    private static final int MD5_BYTE_SIZE = 16;
+    private static final int SYNC_REQUEST_LATCH_TIMEOUT_SECONDS = 1;
+
+    private static final String JSON_FORMAT_HEADER_KEY = "account_data";
+    private static final String JSON_FORMAT_ENCODING = "UTF-8";
+    private static final int JSON_FORMAT_VERSION = 1;
+
+    private static final String KEY_VERSION = "version";
+    private static final String KEY_MASTER_SYNC_ENABLED = "masterSyncEnabled";
+    private static final String KEY_ACCOUNTS = "accounts";
+    private static final String KEY_ACCOUNT_NAME = "name";
+    private static final String KEY_ACCOUNT_TYPE = "type";
+    private static final String KEY_ACCOUNT_AUTHORITIES = "authorities";
+    private static final String KEY_AUTHORITY_NAME = "name";
+    private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
+    private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
+
+    private Context mContext;
+    private AccountManager mAccountManager;
+
+    public AccountSyncSettingsBackupHelper(Context context) {
+        mContext = context;
+        mAccountManager = AccountManager.get(mContext);
+    }
+
+    /**
+     * Take a snapshot of the current account sync settings and write them to the given output.
+     */
+    @Override
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput output,
+            ParcelFileDescriptor newState) {
+        try {
+            JSONObject dataJSON = serializeAccountSyncSettingsToJSON();
+
+            if (DEBUG) {
+                Log.d(TAG, "Account sync settings JSON: " + dataJSON);
+            }
+
+            // Encode JSON data to bytes.
+            byte[] dataBytes = dataJSON.toString().getBytes(JSON_FORMAT_ENCODING);
+            byte[] oldMd5Checksum = readOldMd5Checksum(oldState);
+            byte[] newMd5Checksum = generateMd5Checksum(dataBytes);
+            if (!Arrays.equals(oldMd5Checksum, newMd5Checksum)) {
+                int dataSize = dataBytes.length;
+                output.writeEntityHeader(JSON_FORMAT_HEADER_KEY, dataSize);
+                output.writeEntityData(dataBytes, dataSize);
+
+                Log.i(TAG, "Backup successful.");
+            } else {
+                Log.i(TAG, "Old and new MD5 checksums match. Skipping backup.");
+            }
+
+            writeNewMd5Checksum(newState, newMd5Checksum);
+        } catch (JSONException | IOException | NoSuchAlgorithmException e) {
+            Log.e(TAG, "Couldn't backup account sync settings\n" + e);
+        }
+    }
+
+    /**
+     * Fetch and serialize Account and authority information as a JSON Array.
+     */
+    private JSONObject serializeAccountSyncSettingsToJSON() throws JSONException {
+        Account[] accounts = mAccountManager.getAccounts();
+        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
+                mContext.getUserId());
+
+        // Create a map of Account types to authorities. Later this will make it easier for us to
+        // generate our JSON.
+        HashMap<String, List<String>> accountTypeToAuthorities = new HashMap<String,
+                List<String>>();
+        for (SyncAdapterType syncAdapter : syncAdapters) {
+            // Skip adapters that aren’t visible to the user.
+            if (!syncAdapter.isUserVisible()) {
+                continue;
+            }
+            if (!accountTypeToAuthorities.containsKey(syncAdapter.accountType)) {
+                accountTypeToAuthorities.put(syncAdapter.accountType, new ArrayList<String>());
+            }
+            accountTypeToAuthorities.get(syncAdapter.accountType).add(syncAdapter.authority);
+        }
+
+        // Generate JSON.
+        JSONObject backupJSON = new JSONObject();
+        backupJSON.put(KEY_VERSION, JSON_FORMAT_VERSION);
+        backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomatically());
+
+        JSONArray accountJSONArray = new JSONArray();
+        for (Account account : accounts) {
+            List<String> authorities = accountTypeToAuthorities.get(account.type);
+
+            // We ignore Accounts that don't have any authorities because there would be no sync
+            // settings for us to restore.
+            if (authorities == null || authorities.isEmpty()) {
+                continue;
+            }
+
+            JSONObject accountJSON = new JSONObject();
+            accountJSON.put(KEY_ACCOUNT_NAME, account.name);
+            accountJSON.put(KEY_ACCOUNT_TYPE, account.type);
+
+            // Add authorities for this Account type and check whether or not sync is enabled.
+            JSONArray authoritiesJSONArray = new JSONArray();
+            for (String authority : authorities) {
+                int syncState = ContentResolver.getIsSyncable(account, authority);
+                boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority);
+
+                JSONObject authorityJSON = new JSONObject();
+                authorityJSON.put(KEY_AUTHORITY_NAME, authority);
+                authorityJSON.put(KEY_AUTHORITY_SYNC_STATE, syncState);
+                authorityJSON.put(KEY_AUTHORITY_SYNC_ENABLED, syncEnabled);
+                authoritiesJSONArray.put(authorityJSON);
+            }
+            accountJSON.put(KEY_ACCOUNT_AUTHORITIES, authoritiesJSONArray);
+
+            accountJSONArray.put(accountJSON);
+        }
+        backupJSON.put(KEY_ACCOUNTS, accountJSONArray);
+
+        return backupJSON;
+    }
+
+    /**
+     * Read the MD5 checksum from the old state.
+     *
+     * @return the old MD5 checksum
+     */
+    private byte[] readOldMd5Checksum(ParcelFileDescriptor oldState) throws IOException {
+        DataInputStream dataInput = new DataInputStream(
+                new FileInputStream(oldState.getFileDescriptor()));
+
+        byte[] oldMd5Checksum = new byte[MD5_BYTE_SIZE];
+        try {
+            int stateVersion = dataInput.readInt();
+            if (stateVersion <= STATE_VERSION) {
+                // If the state version is a version we can understand then read the MD5 sum,
+                // otherwise we return an empty byte array for the MD5 sum which will force a
+                // backup.
+                for (int i = 0; i < MD5_BYTE_SIZE; i++) {
+                    oldMd5Checksum[i] = dataInput.readByte();
+                }
+            } else {
+                Log.i(TAG, "Backup state version is: " + stateVersion
+                        + " (support only up to version " + STATE_VERSION + ")");
+            }
+        } catch (EOFException eof) {
+            // Initial state may be empty.
+        } finally {
+            dataInput.close();
+        }
+        return oldMd5Checksum;
+    }
+
+    /**
+     * Write the given checksum to the file descriptor.
+     */
+    private void writeNewMd5Checksum(ParcelFileDescriptor newState, byte[] md5Checksum)
+            throws IOException {
+        DataOutputStream dataOutput = new DataOutputStream(
+                new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
+
+        dataOutput.writeInt(STATE_VERSION);
+        dataOutput.write(md5Checksum);
+        dataOutput.close();
+    }
+
+    private byte[] generateMd5Checksum(byte[] data) throws NoSuchAlgorithmException {
+        if (data == null) {
+            return null;
+        }
+
+        MessageDigest md5 = MessageDigest.getInstance("MD5");
+        return md5.digest(data);
+    }
+
+    /**
+     * Restore account sync settings from the given data input stream.
+     */
+    @Override
+    public void restoreEntity(BackupDataInputStream data) {
+        byte[] dataBytes = new byte[data.size()];
+        try {
+            // Read the data and convert it to a String.
+            data.read(dataBytes);
+            String dataString = new String(dataBytes, JSON_FORMAT_ENCODING);
+
+            // Convert data to a JSON object.
+            JSONObject dataJSON = new JSONObject(dataString);
+            boolean masterSyncEnabled = dataJSON.getBoolean(KEY_MASTER_SYNC_ENABLED);
+            JSONArray accountJSONArray = dataJSON.getJSONArray(KEY_ACCOUNTS);
+
+            boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomatically();
+            if (currentMasterSyncEnabled) {
+                // Disable master sync to prevent any syncs from running.
+                ContentResolver.setMasterSyncAutomatically(false);
+            }
+
+            try {
+                HashSet<Account> currentAccounts = getAccountsHashSet();
+                for (int i = 0; i < accountJSONArray.length(); i++) {
+                    JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
+                    String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
+                    String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+
+                    Account account = new Account(accountName, accountType);
+
+                    // Check if the account already exists. Accounts that don't exist on the device
+                    // yet won't be restored.
+                    if (currentAccounts.contains(account)) {
+                        restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+                    }
+                }
+            } finally {
+                // Set the master sync preference to the value from the backup set.
+                ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
+            }
+
+            Log.i(TAG, "Restore successful.");
+        } catch (IOException | JSONException e) {
+            Log.e(TAG, "Couldn't restore account sync settings\n" + e);
+        }
+    }
+
+    /**
+     * Helper method - fetch accounts and return them as a HashSet.
+     *
+     * @return Accounts in a HashSet.
+     */
+    private HashSet<Account> getAccountsHashSet() {
+        Account[] accounts = mAccountManager.getAccounts();
+        HashSet<Account> accountHashSet = new HashSet<Account>();
+        for (Account account : accounts) {
+            accountHashSet.add(account);
+        }
+        return accountHashSet;
+    }
+
+    /**
+     * Restore account sync settings using the given JSON. This function won't work if the account
+     * doesn't exist yet.
+     */
+    private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON)
+            throws JSONException {
+        // Restore authorities.
+        JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES);
+        String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
+        String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
+        final Account account = new Account(accountName, accountType);
+        for (int i = 0; i < authorities.length(); i++) {
+            JSONObject authority = (JSONObject) authorities.get(i);
+            final String authorityName = authority.getString(KEY_AUTHORITY_NAME);
+            boolean syncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED);
+
+            // Cancel any active syncs.
+            if (ContentResolver.isSyncActive(account, authorityName)) {
+                ContentResolver.cancelSync(account, authorityName);
+            }
+
+            boolean overwriteSync = true;
+            Bundle initializationExtras = createSyncInitializationBundle();
+            int currentSyncState = ContentResolver.getIsSyncable(account, authorityName);
+            if (currentSyncState < 0) {
+                // Requesting a sync is an asynchronous operation, so we setup a countdown latch to
+                // wait for it to finish. Initialization syncs are generally very brief and
+                // shouldn't take too much time to finish.
+                final CountDownLatch latch = new CountDownLatch(1);
+                Object syncStatusObserverHandle = ContentResolver.addStatusChangeListener(
+                        ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, new SyncStatusObserver() {
+                            @Override
+                            public void onStatusChanged(int which) {
+                                if (!ContentResolver.isSyncActive(account, authorityName)) {
+                                    latch.countDown();
+                                }
+                            }
+                        });
+
+                // If we set sync settings for a sync that hasn't been initialized yet, we run the
+                // risk of having our changes overwritten later on when the sync gets initialized.
+                // To prevent this from happening we will manually initiate the sync adapter. We
+                // also explicitly pass in a Bundle with SYNC_EXTRAS_INITIALIZE to prevent a data
+                // sync from running after the initialization sync. Two syncs will be scheduled, but
+                // the second one (data sync) will override the first one (initialization sync) and
+                // still behave as an initialization sync because of the Bundle.
+                ContentResolver.requestSync(account, authorityName, initializationExtras);
+
+                boolean done = false;
+                try {
+                    done = latch.await(SYNC_REQUEST_LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "CountDownLatch interrupted\n" + e);
+                    done = false;
+                }
+                if (!done) {
+                    overwriteSync = false;
+                    Log.i(TAG, "CountDownLatch timed out, skipping '" + authorityName
+                            + "' authority.");
+                }
+                ContentResolver.removeStatusChangeListener(syncStatusObserverHandle);
+            }
+
+            if (overwriteSync) {
+                ContentResolver.setSyncAutomatically(account, authorityName, syncEnabled);
+                Log.i(TAG, "Set sync automatically for '" + authorityName + "': " + syncEnabled);
+            }
+        }
+    }
+
+    private Bundle createSyncInitializationBundle() {
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+        return extras;
+    }
+
+    @Override
+    public void writeNewStateDescription(ParcelFileDescriptor newState) {
+
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 35a1a5a..b5f2f37 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -86,6 +86,8 @@
         }
         addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
         addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
+        addHelper("account_sync_settings",
+                new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
 
         super.onBackup(oldState, data, newState);
     }
@@ -118,6 +120,8 @@
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
         addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
+        addHelper("account_sync_settings",
+                new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
index 0dde465..d45982e 100644
--- a/core/java/com/android/server/net/NetlinkTracker.java
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -24,11 +24,9 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Objects;
 import java.util.Set;
 
 /**
diff --git a/core/java/org/apache/http/conn/ConnectTimeoutException.java b/core/java/org/apache/http/conn/ConnectTimeoutException.java
new file mode 100644
index 0000000..6cc6922
--- /dev/null
+++ b/core/java/org/apache/http/conn/ConnectTimeoutException.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ConnectTimeoutException.java $
+ * $Revision: 617645 $
+ * $Date: 2008-02-01 13:05:31 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InterruptedIOException;
+
+/**
+ * A timeout while connecting to an HTTP server or waiting for an
+ * available connection from an HttpConnectionManager.
+ * 
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ * 
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public class ConnectTimeoutException extends InterruptedIOException {
+
+    private static final long serialVersionUID = -4816682903149535989L;
+
+    /**
+     * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+     */
+    public ConnectTimeoutException() {
+        super();
+    }
+
+    /**
+     * Creates a ConnectTimeoutException with the specified detail message.
+     * 
+     * @param message The exception detail message 
+     */
+    public ConnectTimeoutException(final String message) {
+        super(message);
+    }
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/HostNameResolver.java b/core/java/org/apache/http/conn/scheme/HostNameResolver.java
new file mode 100644
index 0000000..30ef298
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/HostNameResolver.java
@@ -0,0 +1,47 @@
+/*
+ * $HeadURL:$
+ * $Revision:$
+ * $Date:$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface HostNameResolver {
+
+    InetAddress resolve (String hostname) throws IOException;
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java b/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java
new file mode 100644
index 0000000..b9f53489
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java
@@ -0,0 +1,77 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * A {@link SocketFactory SocketFactory} for layered sockets (SSL/TLS).
+ * See there for things to consider when implementing a socket factory.
+ * 
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface LayeredSocketFactory extends SocketFactory {
+
+    /**
+     * Returns a socket connected to the given host that is layered over an
+     * existing socket.  Used primarily for creating secure sockets through
+     * proxies.
+     * 
+     * @param socket the existing socket 
+     * @param host the host name/IP
+     * @param port the port on the host
+     * @param autoClose a flag for closing the underling socket when the created
+     * socket is closed
+     * 
+     * @return Socket a new socket
+     * 
+     * @throws IOException if an I/O error occurs while creating the socket
+     * @throws UnknownHostException if the IP address of the host cannot be
+     * determined
+     */
+    Socket createSocket(
+        Socket socket, 
+        String host, 
+        int port, 
+        boolean autoClose
+    ) throws IOException, UnknownHostException;              
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/SocketFactory.java b/core/java/org/apache/http/conn/scheme/SocketFactory.java
new file mode 100644
index 0000000..c6bc03c7
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/SocketFactory.java
@@ -0,0 +1,143 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/SocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.params.HttpParams;
+
+/**
+ * A factory for creating and connecting sockets.
+ * The factory encapsulates the logic for establishing a socket connection.
+ * <br/>
+ * Both {@link java.lang.Object#equals(java.lang.Object) Object.equals()}
+ * and {@link java.lang.Object#hashCode() Object.hashCode()}
+ * must be overridden for the correct operation of some connection managers.
+ * 
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface SocketFactory {
+
+    /**
+     * Creates a new, unconnected socket.
+     * The socket should subsequently be passed to
+     * {@link #connectSocket connectSocket}.
+     *
+     * @return  a new socket
+     * 
+     * @throws IOException if an I/O error occurs while creating the socket
+     */
+    Socket createSocket()
+        throws IOException
+        ;
+
+
+    /**
+     * Connects a socket to the given host.
+     * 
+     * @param sock      the socket to connect, as obtained from
+     *                  {@link #createSocket createSocket}.
+     *                  <code>null</code> indicates that a new socket
+     *                  should be created and connected.
+     * @param host      the host to connect to
+     * @param port      the port to connect to on the host
+     * @param localAddress the local address to bind the socket to, or
+     *                  <code>null</code> for any
+     * @param localPort the port on the local machine,
+     *                  0 or a negative number for any
+     * @param params    additional {@link HttpParams parameters} for connecting
+     * 
+     * @return  the connected socket. The returned object may be different
+     *          from the <code>sock</code> argument if this factory supports
+     *          a layered protocol.
+     * 
+     * @throws IOException if an I/O error occurs
+     * @throws UnknownHostException if the IP address of the target host
+     *          can not be determined
+     * @throws ConnectTimeoutException if the socket cannot be connected
+     *          within the time limit defined in the <code>params</code>
+     */
+    Socket connectSocket(
+        Socket sock,
+        String host, 
+        int port, 
+        InetAddress localAddress, 
+        int localPort,
+        HttpParams params
+    ) throws IOException, UnknownHostException, ConnectTimeoutException;
+
+
+    /**
+     * Checks whether a socket provides a secure connection.
+     * The socket must be {@link #connectSocket connected}
+     * by this factory.
+     * The factory will <i>not</i> perform I/O operations
+     * in this method.
+     * <br/>
+     * As a rule of thumb, plain sockets are not secure and
+     * TLS/SSL sockets are secure. However, there may be
+     * application specific deviations. For example, a plain
+     * socket to a host in the same intranet ("trusted zone")
+     * could be considered secure. On the other hand, a
+     * TLS/SSL socket could be considered insecure based on
+     * the cypher suite chosen for the connection.
+     *
+     * @param sock      the connected socket to check
+     *
+     * @return  <code>true</code> if the connection of the socket
+     *          should be considered secure, or
+     *          <code>false</code> if it should not
+     *
+     * @throws IllegalArgumentException
+     *  if the argument is invalid, for example because it is
+     *  not a connected socket or was created by a different
+     *  socket factory.
+     *  Note that socket factories are <i>not</i> required to
+     *  check these conditions, they may simply return a default
+     *  value when called with an invalid socket argument.
+     */
+    boolean isSecure(Socket sock)
+        throws IllegalArgumentException
+        ;
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
new file mode 100644
index 0000000..e264f1c4
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -0,0 +1,288 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.util.regex.Pattern;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import javax.net.ssl.DistinguishedNameParser;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * Abstract base class for all standard {@link X509HostnameVerifier} 
+ * implementations.
+ * 
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public abstract class AbstractVerifier implements X509HostnameVerifier {
+
+    private static final Pattern IPV4_PATTERN = Pattern.compile(
+            "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
+
+    /**
+     * This contains a list of 2nd-level domains that aren't allowed to
+     * have wildcards when combined with country-codes.
+     * For example: [*.co.uk].
+     * <p/>
+     * The [*.co.uk] problem is an interesting one.  Should we just hope
+     * that CA's would never foolishly allow such a certificate to happen?
+     * Looks like we're the only implementation guarding against this.
+     * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+     */
+    private final static String[] BAD_COUNTRY_2LDS =
+          { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+            "lg", "ne", "net", "or", "org" };
+
+    static {
+        // Just in case developer forgot to manually sort the array.  :-)
+        Arrays.sort(BAD_COUNTRY_2LDS);
+    }
+
+    public AbstractVerifier() {
+        super();
+    }
+
+    public final void verify(String host, SSLSocket ssl)
+          throws IOException {
+        if(host == null) {
+            throw new NullPointerException("host to verify is null");
+        }
+
+        SSLSession session = ssl.getSession();
+        Certificate[] certs = session.getPeerCertificates();
+        X509Certificate x509 = (X509Certificate) certs[0];
+        verify(host, x509);
+    }
+
+    public final boolean verify(String host, SSLSession session) {
+        try {
+            Certificate[] certs = session.getPeerCertificates();
+            X509Certificate x509 = (X509Certificate) certs[0];
+            verify(host, x509);
+            return true;
+        }
+        catch(SSLException e) {
+            return false;
+        }
+    }
+
+    public final void verify(String host, X509Certificate cert)
+          throws SSLException {
+        String[] cns = getCNs(cert);
+        String[] subjectAlts = getDNSSubjectAlts(cert);
+        verify(host, cns, subjectAlts);
+    }
+
+    public final void verify(final String host, final String[] cns,
+                             final String[] subjectAlts,
+                             final boolean strictWithSubDomains)
+          throws SSLException {
+
+        // Build the list of names we're going to check.  Our DEFAULT and
+        // STRICT implementations of the HostnameVerifier only use the
+        // first CN provided.  All other CNs are ignored.
+        // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+        LinkedList<String> names = new LinkedList<String>();
+        if(cns != null && cns.length > 0 && cns[0] != null) {
+            names.add(cns[0]);
+        }
+        if(subjectAlts != null) {
+            for (String subjectAlt : subjectAlts) {
+                if (subjectAlt != null) {
+                    names.add(subjectAlt);
+                }
+            }
+        }
+
+        if(names.isEmpty()) {
+            String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
+            throw new SSLException(msg);
+        }
+
+        // StringBuffer for building the error message.
+        StringBuffer buf = new StringBuffer();
+
+        // We're can be case-insensitive when comparing the host we used to
+        // establish the socket to the hostname in the certificate.
+        String hostName = host.trim().toLowerCase(Locale.ENGLISH);
+        boolean match = false;
+        for(Iterator<String> it = names.iterator(); it.hasNext();) {
+            // Don't trim the CN, though!
+            String cn = it.next();
+            cn = cn.toLowerCase(Locale.ENGLISH);
+            // Store CN in StringBuffer in case we need to report an error.
+            buf.append(" <");
+            buf.append(cn);
+            buf.append('>');
+            if(it.hasNext()) {
+                buf.append(" OR");
+            }
+
+            // The CN better have at least two dots if it wants wildcard
+            // action.  It also can't be [*.co.uk] or [*.co.jp] or
+            // [*.org.uk], etc...
+            boolean doWildcard = cn.startsWith("*.") &&
+                                 cn.indexOf('.', 2) != -1 &&
+                                 acceptableCountryWildcard(cn) &&
+                                 !isIPv4Address(host);
+
+            if(doWildcard) {
+                match = hostName.endsWith(cn.substring(1));
+                if(match && strictWithSubDomains) {
+                    // If we're in strict mode, then [*.foo.com] is not
+                    // allowed to match [a.b.foo.com]
+                    match = countDots(hostName) == countDots(cn);
+                }
+            } else {
+                match = hostName.equals(cn);
+            }
+            if(match) {
+                break;
+            }
+        }
+        if(!match) {
+            throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
+        }
+    }
+
+    public static boolean acceptableCountryWildcard(String cn) {
+        int cnLen = cn.length();
+        if(cnLen >= 7 && cnLen <= 9) {
+            // Look for the '.' in the 3rd-last position:
+            if(cn.charAt(cnLen - 3) == '.') {
+                // Trim off the [*.] and the [.XX].
+                String s = cn.substring(2, cnLen - 3);
+                // And test against the sorted array of bad 2lds:
+                int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+                return x < 0;
+            }
+        }
+        return true;
+    }
+
+    public static String[] getCNs(X509Certificate cert) {
+        DistinguishedNameParser dnParser =
+                new DistinguishedNameParser(cert.getSubjectX500Principal());
+        List<String> cnList = dnParser.getAllMostSpecificFirst("cn");
+
+        if(!cnList.isEmpty()) {
+            String[] cns = new String[cnList.size()];
+            cnList.toArray(cns);
+            return cns;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+     * Returns null if there aren't any.
+     * <p/>
+     * Note:  Java doesn't appear able to extract international characters
+     * from the SubjectAlts.  It can only extract international characters
+     * from the CN field.
+     * <p/>
+     * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+     * international characters correctly in the SubjectAlts?).
+     *
+     * @param cert X509Certificate
+     * @return Array of SubjectALT DNS names stored in the certificate.
+     */
+    public static String[] getDNSSubjectAlts(X509Certificate cert) {
+        LinkedList<String> subjectAltList = new LinkedList<String>();
+        Collection<List<?>> c = null;
+        try {
+            c = cert.getSubjectAlternativeNames();
+        }
+        catch(CertificateParsingException cpe) {
+            Logger.getLogger(AbstractVerifier.class.getName())
+                    .log(Level.FINE, "Error parsing certificate.", cpe);
+        }
+        if(c != null) {
+            for (List<?> aC : c) {
+                List<?> list = aC;
+                int type = ((Integer) list.get(0)).intValue();
+                // If type is 2, then we've got a dNSName
+                if (type == 2) {
+                    String s = (String) list.get(1);
+                    subjectAltList.add(s);
+                }
+            }
+        }
+        if(!subjectAltList.isEmpty()) {
+            String[] subjectAlts = new String[subjectAltList.size()];
+            subjectAltList.toArray(subjectAlts);
+            return subjectAlts;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Counts the number of dots "." in a string.
+     * @param s  string to count dots from
+     * @return  number of dots
+     */
+    public static int countDots(final String s) {
+        int count = 0;
+        for(int i = 0; i < s.length(); i++) {
+            if(s.charAt(i) == '.') {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private static boolean isIPv4Address(final String input) {
+        return IPV4_PATTERN.matcher(input).matches();
+    }
+}
diff --git a/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
new file mode 100644
index 0000000..c2bf4c4
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+/**
+ * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * off. This implementation is a no-op, and never throws the SSLException.
+ * 
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public class AllowAllHostnameVerifier extends AbstractVerifier {
+
+    public final void verify(
+            final String host, 
+            final String[] cns,
+            final String[] subjectAlts) {
+        // Allow everything - so never blowup.
+    }
+
+    @Override
+    public final String toString() { 
+        return "ALLOW_ALL"; 
+    }
+    
+}
diff --git a/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
new file mode 100644
index 0000000..48a7bf9
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The HostnameVerifier that works the same way as Curl and Firefox.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.
+ * <p/>
+ * The only difference between BROWSER_COMPATIBLE and STRICT is that a wildcard 
+ * (such as "*.foo.com") with BROWSER_COMPATIBLE matches all subdomains, 
+ * including "a.b.foo.com".
+ * 
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public class BrowserCompatHostnameVerifier extends AbstractVerifier {
+
+    public final void verify(
+            final String host, 
+            final String[] cns,
+            final String[] subjectAlts) throws SSLException {
+        verify(host, cns, subjectAlts, false);
+    }
+
+    @Override
+    public final String toString() { 
+        return "BROWSER_COMPATIBLE"; 
+    }
+    
+}
diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
new file mode 100644
index 0000000..4d53d40
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -0,0 +1,408 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java $
+ * $Revision: 659194 $
+ * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import org.apache.http.conn.scheme.HostNameResolver;
+import org.apache.http.conn.scheme.LayeredSocketFactory;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * Layered socket factory for TLS/SSL connections, based on JSSE.
+ *.
+ * <p>
+ * SSLSocketFactory can be used to validate the identity of the HTTPS 
+ * server against a list of trusted certificates and to authenticate to
+ * the HTTPS server using a private key. 
+ * </p>
+ * 
+ * <p>
+ * SSLSocketFactory will enable server authentication when supplied with
+ * a {@link KeyStore truststore} file containg one or several trusted
+ * certificates. The client secure socket will reject the connection during
+ * the SSL session handshake if the target HTTPS server attempts to
+ * authenticate itself with a non-trusted certificate.
+ * </p>
+ * 
+ * <p>
+ * Use JDK keytool utility to import a trusted certificate and generate a truststore file:    
+ *    <pre>
+ *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ *    </pre>
+ * </p>
+ * 
+ * <p>
+ * SSLSocketFactory will enable client authentication when supplied with
+ * a {@link KeyStore keystore} file containg a private key/public certificate
+ * pair. The client secure socket will use the private key to authenticate
+ * itself to the target HTTPS server during the SSL session handshake if
+ * requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented
+ * by the client in order to establish client's authenticity
+ * </p>
+ * 
+ * <p>
+ * Use the following sequence of actions to generate a keystore file
+ * </p>
+ *   <ul>
+ *     <li>
+ *      <p>
+ *      Use JDK keytool utility to generate a new key
+ *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ *      For simplicity use the same password for the key as that of the keystore
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Issue a certificate signing request (CSR)
+ *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
+ *     </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Send the certificate request to the trusted Certificate Authority for signature. 
+ *      One may choose to act as her own CA and sign the certificate request using a PKI 
+ *      tool, such as OpenSSL.
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the trusted CA root certificate
+ *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre> 
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the PKCS#7 file containg the complete certificate chain
+ *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre> 
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Verify the content the resultant keystore file
+ *       <pre>keytool -list -v -keystore my.keystore</pre> 
+ *      </p>
+ *     </li>
+ *   </ul>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public class SSLSocketFactory implements LayeredSocketFactory {
+
+    public static final String TLS   = "TLS";
+    public static final String SSL   = "SSL";
+    public static final String SSLV2 = "SSLv2";
+    
+    public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER 
+        = new AllowAllHostnameVerifier();
+    
+    public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER 
+        = new BrowserCompatHostnameVerifier();
+    
+    public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER 
+        = new StrictHostnameVerifier();
+
+    /*
+     * Put defaults into holder class to avoid class preloading creating an
+     * instance of the classes referenced.
+     */
+    private static class NoPreloadHolder {
+        /**
+         * The factory using the default JVM settings for secure connections.
+         */
+        private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory();
+    }
+
+    /**
+     * Gets an singleton instance of the SSLProtocolSocketFactory.
+     * @return a SSLProtocolSocketFactory
+     */
+    public static SSLSocketFactory getSocketFactory() {
+        return NoPreloadHolder.DEFAULT_FACTORY;
+    }
+
+    private final SSLContext sslcontext;
+    private final javax.net.ssl.SSLSocketFactory socketfactory;
+    private final HostNameResolver nameResolver;
+    private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+
+    public SSLSocketFactory(
+        String algorithm, 
+        final KeyStore keystore, 
+        final String keystorePassword, 
+        final KeyStore truststore,
+        final SecureRandom random,
+        final HostNameResolver nameResolver) 
+        throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+    {
+        super();
+        if (algorithm == null) {
+            algorithm = TLS;
+        }
+        KeyManager[] keymanagers = null;
+        if (keystore != null) {
+            keymanagers = createKeyManagers(keystore, keystorePassword);
+        }
+        TrustManager[] trustmanagers = null;
+        if (truststore != null) {
+            trustmanagers = createTrustManagers(truststore);
+        }
+        this.sslcontext = SSLContext.getInstance(algorithm);
+        this.sslcontext.init(keymanagers, trustmanagers, random);
+        this.socketfactory = this.sslcontext.getSocketFactory();
+        this.nameResolver = nameResolver;
+    }
+
+    public SSLSocketFactory(
+            final KeyStore keystore, 
+            final String keystorePassword, 
+            final KeyStore truststore) 
+            throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+    {
+        this(TLS, keystore, keystorePassword, truststore, null, null);
+    }
+
+    public SSLSocketFactory(final KeyStore keystore, final String keystorePassword) 
+            throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+    {
+        this(TLS, keystore, keystorePassword, null, null, null);
+    }
+
+    public SSLSocketFactory(final KeyStore truststore) 
+            throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+    {
+        this(TLS, null, null, truststore, null, null);
+    }
+
+    /**
+     * Constructs an HttpClient SSLSocketFactory backed by the given JSSE
+     * SSLSocketFactory.
+     *
+     * @hide
+     */
+    public SSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory) {
+        super();
+        this.sslcontext = null;
+        this.socketfactory = socketfactory;
+        this.nameResolver = null;
+    }
+
+    /**
+     * Creates the default SSL socket factory.
+     * This constructor is used exclusively to instantiate the factory for
+     * {@link #getSocketFactory getSocketFactory}.
+     */
+    private SSLSocketFactory() {
+        super();
+        this.sslcontext = null;
+        this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+        this.nameResolver = null;
+    }
+
+    private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
+        throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+        if (keystore == null) {
+            throw new IllegalArgumentException("Keystore may not be null");
+        }
+        KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
+            KeyManagerFactory.getDefaultAlgorithm());
+        kmfactory.init(keystore, password != null ? password.toCharArray(): null);
+        return kmfactory.getKeyManagers(); 
+    }
+
+    private static TrustManager[] createTrustManagers(final KeyStore keystore)
+        throws KeyStoreException, NoSuchAlgorithmException { 
+        if (keystore == null) {
+            throw new IllegalArgumentException("Keystore may not be null");
+        }
+        TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
+            TrustManagerFactory.getDefaultAlgorithm());
+        tmfactory.init(keystore);
+        return tmfactory.getTrustManagers();
+    }
+
+
+    // non-javadoc, see interface org.apache.http.conn.SocketFactory
+    public Socket createSocket()
+        throws IOException {
+
+        // the cast makes sure that the factory is working as expected
+        return (SSLSocket) this.socketfactory.createSocket();
+    }
+
+
+    // non-javadoc, see interface org.apache.http.conn.SocketFactory
+    public Socket connectSocket(
+        final Socket sock,
+        final String host,
+        final int port,
+        final InetAddress localAddress,
+        int localPort,
+        final HttpParams params
+    ) throws IOException {
+
+        if (host == null) {
+            throw new IllegalArgumentException("Target host may not be null.");
+        }
+        if (params == null) {
+            throw new IllegalArgumentException("Parameters may not be null.");
+        }
+
+        SSLSocket sslsock = (SSLSocket)
+            ((sock != null) ? sock : createSocket());
+
+        if ((localAddress != null) || (localPort > 0)) {
+
+            // we need to bind explicitly
+            if (localPort < 0)
+                localPort = 0; // indicates "any"
+
+            InetSocketAddress isa =
+                new InetSocketAddress(localAddress, localPort);
+            sslsock.bind(isa);
+        }
+
+        int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
+        int soTimeout = HttpConnectionParams.getSoTimeout(params);
+
+        InetSocketAddress remoteAddress;
+        if (this.nameResolver != null) {
+            remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port); 
+        } else {
+            remoteAddress = new InetSocketAddress(host, port);            
+        }
+        
+        sslsock.connect(remoteAddress, connTimeout);
+
+        sslsock.setSoTimeout(soTimeout);
+        try {
+            hostnameVerifier.verify(host, sslsock);
+            // verifyHostName() didn't blowup - good!
+        } catch (IOException iox) {
+            // close the socket before re-throwing the exception
+            try { sslsock.close(); } catch (Exception x) { /*ignore*/ }
+            throw iox;
+        }
+
+        return sslsock;
+    }
+
+
+    /**
+     * Checks whether a socket connection is secure.
+     * This factory creates TLS/SSL socket connections
+     * which, by default, are considered secure.
+     * <br/>
+     * Derived classes may override this method to perform
+     * runtime checks, for example based on the cypher suite.
+     *
+     * @param sock      the connected socket
+     *
+     * @return  <code>true</code>
+     *
+     * @throws IllegalArgumentException if the argument is invalid
+     */
+    public boolean isSecure(Socket sock)
+        throws IllegalArgumentException {
+
+        if (sock == null) {
+            throw new IllegalArgumentException("Socket may not be null.");
+        }
+        // This instanceof check is in line with createSocket() above.
+        if (!(sock instanceof SSLSocket)) {
+            throw new IllegalArgumentException
+                ("Socket not created by this factory.");
+        }
+        // This check is performed last since it calls the argument object.
+        if (sock.isClosed()) {
+            throw new IllegalArgumentException("Socket is closed.");
+        }
+
+        return true;
+
+    } // isSecure
+
+
+    // non-javadoc, see interface LayeredSocketFactory
+    public Socket createSocket(
+        final Socket socket,
+        final String host,
+        final int port,
+        final boolean autoClose
+    ) throws IOException, UnknownHostException {
+        SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
+              socket,
+              host,
+              port,
+              autoClose
+        );
+        hostnameVerifier.verify(host, sslSocket);
+        // verifyHostName() didn't blowup - good!
+        return sslSocket;
+    }
+
+    public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
+        if ( hostnameVerifier == null ) {
+            throw new IllegalArgumentException("Hostname verifier may not be null");
+        }
+        this.hostnameVerifier = hostnameVerifier;
+    }
+
+    public X509HostnameVerifier getHostnameVerifier() {
+        return hostnameVerifier;
+    }
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
new file mode 100644
index 0000000..bd9e70d
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
@@ -0,0 +1,74 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The Strict HostnameVerifier works the same way as Sun Java 1.4, Sun
+ * Java 5, Sun Java 6-rc.  It's also pretty close to IE6.  This
+ * implementation appears to be compliant with RFC 2818 for dealing with
+ * wildcards.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.  The
+ * one divergence from IE6 is how we only check the first CN.  IE6 allows
+ * a match against any of the CNs present.  We decided to follow in
+ * Sun Java 1.4's footsteps and only check the first CN.  (If you need
+ * to check all the CN's, feel free to write your own implementation!).
+ * <p/>
+ * A wildcard such as "*.foo.com" matches only subdomains in the same
+ * level, for example "a.foo.com".  It does not match deeper subdomains
+ * such as "a.b.foo.com".
+ * 
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public class StrictHostnameVerifier extends AbstractVerifier {
+
+    public final void verify(
+            final String host, 
+            final String[] cns,
+            final String[] subjectAlts) throws SSLException {
+        verify(host, cns, subjectAlts, true);
+    }
+
+    @Override
+    public final String toString() { 
+        return "STRICT"; 
+    }
+    
+}
diff --git a/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java b/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
new file mode 100644
index 0000000..e38db5f
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
@@ -0,0 +1,91 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java $
+ * $Revision: 618365 $
+ * $Date: 2008-02-04 10:20:08 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate.  Implements javax.net.ssl.HostnameVerifier, but
+ * we don't actually use that interface.  Instead we added some methods that
+ * take String parameters (instead of javax.net.ssl.HostnameVerifier's
+ * SSLSession).  JUnit is a lot easier this way!  :-)
+ * <p/>
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations.  But feel free to define
+ * your own implementation!
+ * <p/>
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author <a href="mailto:hauer@psicode.com">Sebastian Hauer</a>
+ *
+ * @since 4.0 (8-Dec-2006)
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface X509HostnameVerifier extends HostnameVerifier {
+
+    boolean verify(String host, SSLSession session);
+
+    void verify(String host, SSLSocket ssl) throws IOException;
+
+    void verify(String host, X509Certificate cert) throws SSLException;
+
+    /**
+     * Checks to see if the supplied hostname matches any of the supplied CNs
+     * or "DNS" Subject-Alts.  Most implementations only look at the first CN,
+     * and ignore any additional CNs.  Most implementations do look at all of
+     * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+     * according to RFC 2818.
+     *
+     * @param cns         CN fields, in order, as extracted from the X.509
+     *                    certificate.
+     * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+     *                    from the X.509 certificate.
+     * @param host        The hostname to verify.
+     * @throws SSLException If verification failed.
+     */
+    void verify(String host, String[] cns, String[] subjectAlts)
+          throws SSLException;
+
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/package.html b/core/java/org/apache/http/conn/ssl/package.html
new file mode 100644
index 0000000..a5c737f
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+TLS/SSL specific parts of the <i>HttpConn</i> API.
+
+</body>
+</html>
diff --git a/core/java/org/apache/http/params/CoreConnectionPNames.java b/core/java/org/apache/http/params/CoreConnectionPNames.java
new file mode 100644
index 0000000..9479db1
--- /dev/null
+++ b/core/java/org/apache/http/params/CoreConnectionPNames.java
@@ -0,0 +1,136 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/CoreConnectionPNames.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+
+/**
+ * Defines parameter names for connections in HttpCore.
+ * 
+ * @version $Revision: 576077 $
+ * 
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface CoreConnectionPNames {
+
+    /**
+     * Defines the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the 
+     * timeout for waiting for data. A timeout value of zero is interpreted as an infinite 
+     * timeout. This value is used when no socket timeout is set in the 
+     * method parameters. 
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     * @see java.net.SocketOptions#SO_TIMEOUT
+     */
+    public static final String SO_TIMEOUT = "http.socket.timeout"; 
+
+    /**
+     * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm 
+     * tries to conserve bandwidth by minimizing the number of segments that are 
+     * sent. When applications wish to decrease network latency and increase 
+     * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). 
+     * Data will be sent earlier, at the cost of an increase in bandwidth consumption. 
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     * @see java.net.SocketOptions#TCP_NODELAY
+     */
+    public static final String TCP_NODELAY = "http.tcp.nodelay"; 
+
+    /**
+     * Determines the size of the internal socket buffer used to buffer data
+     * while receiving / transmitting HTTP messages.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    public static final String SOCKET_BUFFER_SIZE = "http.socket.buffer-size"; 
+
+    /**
+     * Sets SO_LINGER with the specified linger time in seconds. The maximum timeout 
+     * value is platform specific. Value <tt>0</tt> implies that the option is disabled.
+     * Value <tt>-1</tt> implies that the JRE default is used. The setting only affects 
+     * socket close.  
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     * @see java.net.SocketOptions#SO_LINGER
+     */
+    public static final String SO_LINGER = "http.socket.linger"; 
+
+    /**
+     * Determines the timeout until a connection is etablished. A value of zero 
+     * means the timeout is not used. The default value is zero.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    public static final String CONNECTION_TIMEOUT = "http.connection.timeout"; 
+
+    /**
+     * Determines whether stale connection check is to be used. Disabling 
+     * stale connection check may result in slight performance improvement 
+     * at the risk of getting an I/O error when executing a request over a
+     * connection that has been closed at the server side. 
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     */
+    public static final String STALE_CONNECTION_CHECK = "http.connection.stalecheck"; 
+
+    /**
+     * Determines the maximum line length limit. If set to a positive value, any HTTP 
+     * line exceeding this limit will cause an IOException. A negative or zero value
+     * will effectively disable the check.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    public static final String MAX_LINE_LENGTH = "http.connection.max-line-length";
+    
+    /**
+     * Determines the maximum HTTP header count allowed. If set to a positive value, 
+     * the number of HTTP headers received from the data stream exceeding this limit 
+     * will cause an IOException. A negative or zero value will effectively disable 
+     * the check. 
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    public static final String MAX_HEADER_COUNT = "http.connection.max-header-count";
+
+}
diff --git a/core/java/org/apache/http/params/HttpConnectionParams.java b/core/java/org/apache/http/params/HttpConnectionParams.java
new file mode 100644
index 0000000..a7b31fc
--- /dev/null
+++ b/core/java/org/apache/http/params/HttpConnectionParams.java
@@ -0,0 +1,229 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpConnectionParams.java $
+ * $Revision: 576089 $
+ * $Date: 2007-09-16 05:39:56 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * An adaptor for accessing connection parameters in {@link HttpParams}.
+ * <br/>
+ * Note that the <i>implements</i> relation to {@link CoreConnectionPNames}
+ * is for compatibility with existing application code only. References to
+ * the parameter names should use the interface, not this class.
+ * 
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * 
+ * @version $Revision: 576089 $
+ * 
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public final class HttpConnectionParams implements CoreConnectionPNames {
+
+    /**
+     */
+    private HttpConnectionParams() {
+        super();
+    }
+
+    /**
+     * Returns the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the 
+     * timeout for waiting for data. A timeout value of zero is interpreted as an infinite 
+     * timeout. This value is used when no socket timeout is set in the 
+     * method parameters. 
+     *
+     * @return timeout in milliseconds
+     */
+    public static int getSoTimeout(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getIntParameter(CoreConnectionPNames.SO_TIMEOUT, 0);
+    }
+
+    /**
+     * Sets the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the 
+     * timeout for waiting for data. A timeout value of zero is interpreted as an infinite 
+     * timeout. This value is used when no socket timeout is set in the 
+     * method parameters. 
+     *
+     * @param timeout Timeout in milliseconds
+     */
+    public static void setSoTimeout(final HttpParams params, int timeout) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
+        
+    }
+
+    /**
+     * Tests if Nagle's algorithm is to be used.  
+     *
+     * @return <tt>true</tt> if the Nagle's algorithm is to NOT be used
+     *   (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+     */
+    public static boolean getTcpNoDelay(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getBooleanParameter
+            (CoreConnectionPNames.TCP_NODELAY, true);
+    }
+
+    /**
+     * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm 
+     * tries to conserve bandwidth by minimizing the number of segments that are 
+     * sent. When applications wish to decrease network latency and increase 
+     * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). 
+     * Data will be sent earlier, at the cost of an increase in bandwidth consumption. 
+     *
+     * @param value <tt>true</tt> if the Nagle's algorithm is to NOT be used
+     *   (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+     */
+    public static void setTcpNoDelay(final HttpParams params, boolean value) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, value);
+    }
+
+    public static int getSocketBufferSize(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getIntParameter
+            (CoreConnectionPNames.SOCKET_BUFFER_SIZE, -1);
+    }
+    
+    public static void setSocketBufferSize(final HttpParams params, int size) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, size);
+    }
+
+    /**
+     * Returns linger-on-close timeout. Value <tt>0</tt> implies that the option is 
+     * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+     * 
+     * @return the linger-on-close timeout
+     */
+    public static int getLinger(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getIntParameter(CoreConnectionPNames.SO_LINGER, -1);
+    }
+
+    /**
+     * Returns linger-on-close timeout. This option disables/enables immediate return 
+     * from a close() of a TCP Socket. Enabling this option with a non-zero Integer 
+     * timeout means that a close() will block pending the transmission and 
+     * acknowledgement of all data written to the peer, at which point the socket is 
+     * closed gracefully. Value <tt>0</tt> implies that the option is 
+     * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+     *
+     * @param value the linger-on-close timeout
+     */
+    public static void setLinger(final HttpParams params, int value) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setIntParameter(CoreConnectionPNames.SO_LINGER, value);
+    }
+
+    /**
+     * Returns the timeout until a connection is etablished. A value of zero 
+     * means the timeout is not used. The default value is zero.
+     * 
+     * @return timeout in milliseconds.
+     */
+    public static int getConnectionTimeout(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getIntParameter
+            (CoreConnectionPNames.CONNECTION_TIMEOUT, 0);
+    }
+
+    /**
+     * Sets the timeout until a connection is etablished. A value of zero 
+     * means the timeout is not used. The default value is zero.
+     * 
+     * @param timeout Timeout in milliseconds.
+     */
+    public static void setConnectionTimeout(final HttpParams params, int timeout) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setIntParameter
+            (CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
+    }
+    
+    /**
+     * Tests whether stale connection check is to be used. Disabling 
+     * stale connection check may result in slight performance improvement 
+     * at the risk of getting an I/O error when executing a request over a
+     * connection that has been closed at the server side. 
+     * 
+     * @return <tt>true</tt> if stale connection check is to be used, 
+     *   <tt>false</tt> otherwise.
+     */
+    public static boolean isStaleCheckingEnabled(final HttpParams params) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        return params.getBooleanParameter
+            (CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
+    }
+
+    /**
+     * Defines whether stale connection check is to be used. Disabling 
+     * stale connection check may result in slight performance improvement 
+     * at the risk of getting an I/O error when executing a request over a
+     * connection that has been closed at the server side. 
+     * 
+     * @param value <tt>true</tt> if stale connection check is to be used, 
+     *   <tt>false</tt> otherwise.
+     */
+    public static void setStaleCheckingEnabled(final HttpParams params, boolean value) {
+        if (params == null) {
+            throw new IllegalArgumentException("HTTP parameters may not be null");
+        }
+        params.setBooleanParameter
+            (CoreConnectionPNames.STALE_CONNECTION_CHECK, value);
+    }
+    
+}
diff --git a/core/java/org/apache/http/params/HttpParams.java b/core/java/org/apache/http/params/HttpParams.java
new file mode 100644
index 0000000..9562e54
--- /dev/null
+++ b/core/java/org/apache/http/params/HttpParams.java
@@ -0,0 +1,192 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpParams.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * Represents a collection of HTTP protocol and framework parameters.
+ *   
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * 
+ * @version $Revision: 610763 $
+ *
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ *     for further details.
+ */
+@Deprecated
+public interface HttpParams {
+
+    /** 
+     * Obtains the value of the given parameter.
+     * 
+     * @param name the parent name.
+     * 
+     * @return  an object that represents the value of the parameter,
+     *          <code>null</code> if the parameter is not set or if it
+     *          is explicitly set to <code>null</code>
+     * 
+     * @see #setParameter(String, Object)
+     */
+    Object getParameter(String name);
+
+    /**
+     * Assigns the value to the parameter with the given name.
+     *
+     * @param name parameter name
+     * @param value parameter value
+     */
+    HttpParams setParameter(String name, Object value);
+
+    /**
+     * Creates a copy of these parameters.
+     *
+     * @return  a new set of parameters holding the same values as this one
+     */
+    HttpParams copy();
+    
+    /**
+     * Removes the parameter with the specified name.
+     * 
+     * @param name parameter name
+     * 
+     * @return true if the parameter existed and has been removed, false else.
+     */
+    boolean removeParameter(String name);
+
+    /** 
+     * Returns a {@link Long} parameter value with the given name. 
+     * If the parameter is not explicitly set, the default value is returned.  
+     * 
+     * @param name the parent name.
+     * @param defaultValue the default value.
+     * 
+     * @return a {@link Long} that represents the value of the parameter.
+     * 
+     * @see #setLongParameter(String, long)
+     */
+    long getLongParameter(String name, long defaultValue);
+
+    /**
+     * Assigns a {@link Long} to the parameter with the given name
+     * 
+     * @param name parameter name
+     * @param value parameter value
+     */ 
+    HttpParams setLongParameter(String name, long value);
+
+    /** 
+     * Returns an {@link Integer} parameter value with the given name. 
+     * If the parameter is not explicitly set, the default value is returned.  
+     * 
+     * @param name the parent name.
+     * @param defaultValue the default value.
+     * 
+     * @return a {@link Integer} that represents the value of the parameter.
+     * 
+     * @see #setIntParameter(String, int)
+     */
+    int getIntParameter(String name, int defaultValue);
+
+    /**
+     * Assigns an {@link Integer} to the parameter with the given name
+     * 
+     * @param name parameter name
+     * @param value parameter value
+     */ 
+    HttpParams setIntParameter(String name, int value);
+
+    /** 
+     * Returns a {@link Double} parameter value with the given name. 
+     * If the parameter is not explicitly set, the default value is returned.  
+     *
+     * @param name the parent name.
+     * @param defaultValue the default value.
+     * 
+     * @return a {@link Double} that represents the value of the parameter.
+     * 
+     * @see #setDoubleParameter(String, double)
+     */
+    double getDoubleParameter(String name, double defaultValue);
+
+    /**
+     * Assigns a {@link Double} to the parameter with the given name
+     * 
+     * @param name parameter name
+     * @param value parameter value
+     */ 
+    HttpParams setDoubleParameter(String name, double value);
+
+    /** 
+     * Returns a {@link Boolean} parameter value with the given name. 
+     * If the parameter is not explicitly set, the default value is returned.  
+     * 
+     * @param name the parent name.
+     * @param defaultValue the default value.
+     * 
+     * @return a {@link Boolean} that represents the value of the parameter.
+     * 
+     * @see #setBooleanParameter(String, boolean)
+     */
+    boolean getBooleanParameter(String name, boolean defaultValue);
+
+    /**
+     * Assigns a {@link Boolean} to the parameter with the given name
+     * 
+     * @param name parameter name
+     * @param value parameter value
+     */ 
+    HttpParams setBooleanParameter(String name, boolean value);
+
+    /**
+     * Checks if a boolean parameter is set to <code>true</code>.
+     * 
+     * @param name parameter name
+     * 
+     * @return <tt>true</tt> if the parameter is set to value <tt>true</tt>,
+     *         <tt>false</tt> if it is not set or set to <code>false</code>
+     */
+    boolean isParameterTrue(String name);
+
+    /**
+     * Checks if a boolean parameter is not set or <code>false</code>.
+     * 
+     * @param name parameter name
+     * 
+     * @return <tt>true</tt> if the parameter is either not set or
+     *         set to value <tt>false</tt>,
+     *         <tt>false</tt> if it is set to <code>true</code>
+     */
+    boolean isParameterFalse(String name);
+
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index dbaa4b8..30a7e68 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -1,271 +1,264 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
 LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
 LOCAL_CPPFLAGS += -Wno-conversion-null
 
 ifeq ($(TARGET_ARCH), arm)
-	LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
+    LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
 else
-	LOCAL_CFLAGS += -DPACKED=""
-endif
-
-ifeq ($(USE_OPENGL_RENDERER),true)
-	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+    LOCAL_CFLAGS += -DPACKED=""
 endif
 
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
+
 LOCAL_SRC_FILES:= \
-	AndroidRuntime.cpp \
-	com_android_internal_content_NativeLibraryHelper.cpp \
-	com_google_android_gles_jni_EGLImpl.cpp \
-	com_google_android_gles_jni_GLImpl.cpp.arm \
-	android_app_NativeActivity.cpp \
-	android_opengl_EGL14.cpp \
-	android_opengl_EGLExt.cpp \
-	android_opengl_GLES10.cpp \
-	android_opengl_GLES10Ext.cpp \
-	android_opengl_GLES11.cpp \
-	android_opengl_GLES11Ext.cpp \
-	android_opengl_GLES20.cpp \
-	android_opengl_GLES30.cpp \
-	android_opengl_GLES31.cpp \
-	android_opengl_GLES31Ext.cpp \
-	android_database_CursorWindow.cpp \
-	android_database_SQLiteCommon.cpp \
-	android_database_SQLiteConnection.cpp \
-	android_database_SQLiteGlobal.cpp \
-	android_database_SQLiteDebug.cpp \
-	android_emoji_EmojiFactory.cpp \
-	android_view_DisplayEventReceiver.cpp \
-	android_view_Surface.cpp \
-	android_view_SurfaceControl.cpp \
-	android_view_SurfaceSession.cpp \
-	android_view_TextureView.cpp \
-	android_view_InputChannel.cpp \
-	android_view_InputDevice.cpp \
-	android_view_InputEventReceiver.cpp \
-	android_view_InputEventSender.cpp \
-	android_view_InputQueue.cpp \
-	android_view_KeyEvent.cpp \
-	android_view_KeyCharacterMap.cpp \
-	android_view_GraphicBuffer.cpp \
-	android_view_GLES20Canvas.cpp \
-	android_view_HardwareLayer.cpp \
-	android_view_ThreadedRenderer.cpp \
-	android_view_MotionEvent.cpp \
-	android_view_PointerIcon.cpp \
-	android_view_RenderNode.cpp \
-	android_view_RenderNodeAnimator.cpp \
-	android_view_VelocityTracker.cpp \
-	android_text_AndroidCharacter.cpp \
-	android_text_AndroidBidi.cpp \
-	android_text_StaticLayout.cpp \
-	android_os_Debug.cpp \
-	android_os_MemoryFile.cpp \
-	android_os_MessageQueue.cpp \
-	android_os_Parcel.cpp \
-	android_os_SELinux.cpp \
-	android_os_SystemClock.cpp \
-	android_os_SystemProperties.cpp \
-	android_os_Trace.cpp \
-	android_os_UEventObserver.cpp \
-	android_net_LocalSocketImpl.cpp \
-	android_net_NetUtils.cpp \
-	android_net_TrafficStats.cpp \
-	android_nio_utils.cpp \
-	android_util_AssetManager.cpp \
-	android_util_Binder.cpp \
-	android_util_EventLog.cpp \
-	android_util_Log.cpp \
-	android_util_FloatMath.cpp \
-	android_util_Process.cpp \
-	android_util_StringBlock.cpp \
-	android_util_XmlBlock.cpp \
-	android_graphics_Canvas.cpp \
-	android_graphics_Picture.cpp \
-	android/graphics/AutoDecodeCancel.cpp \
-	android/graphics/Bitmap.cpp \
-	android/graphics/BitmapFactory.cpp \
-	android/graphics/Camera.cpp \
-	android/graphics/CanvasProperty.cpp \
-	android/graphics/ColorFilter.cpp \
-	android/graphics/DrawFilter.cpp \
-	android/graphics/FontFamily.cpp \
-	android/graphics/CreateJavaOutputStreamAdaptor.cpp \
-	android/graphics/Graphics.cpp \
-	android/graphics/HarfBuzzNGFaceSkia.cpp \
-	android/graphics/Interpolator.cpp \
-	android/graphics/MaskFilter.cpp \
-	android/graphics/Matrix.cpp \
-	android/graphics/MinikinSkia.cpp \
-	android/graphics/MinikinUtils.cpp \
-	android/graphics/Movie.cpp \
-	android/graphics/NinePatch.cpp \
-	android/graphics/NinePatchImpl.cpp \
-	android/graphics/NinePatchPeeker.cpp \
-	android/graphics/Paint.cpp \
-	android/graphics/PaintImpl.cpp \
-	android/graphics/Path.cpp \
-	android/graphics/PathMeasure.cpp \
-	android/graphics/PathEffect.cpp \
-	android/graphics/Picture.cpp \
-	android/graphics/PorterDuff.cpp \
-	android/graphics/BitmapRegionDecoder.cpp \
-	android/graphics/Rasterizer.cpp \
-	android/graphics/Region.cpp \
-	android/graphics/Shader.cpp \
-	android/graphics/SkiaCanvas.cpp \
-	android/graphics/SurfaceTexture.cpp \
-	android/graphics/Typeface.cpp \
-	android/graphics/TypefaceImpl.cpp \
-	android/graphics/Utils.cpp \
-	android/graphics/Xfermode.cpp \
-	android/graphics/YuvToJpegEncoder.cpp \
-	android/graphics/pdf/PdfDocument.cpp \
-	android/graphics/pdf/PdfEditor.cpp \
-	android/graphics/pdf/PdfRenderer.cpp \
-	android_media_AudioRecord.cpp \
-	android_media_AudioSystem.cpp \
-	android_media_AudioTrack.cpp \
-	android_media_JetPlayer.cpp \
-	android_media_RemoteDisplay.cpp \
-	android_media_ToneGenerator.cpp \
-	android_hardware_Camera.cpp \
-	android_hardware_camera2_CameraMetadata.cpp \
-	android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
-	android_hardware_camera2_legacy_PerfMeasurement.cpp \
-	android_hardware_camera2_DngCreator.cpp \
-	android_hardware_SensorManager.cpp \
-	android_hardware_SerialPort.cpp \
-	android_hardware_SoundTrigger.cpp \
-	android_hardware_UsbDevice.cpp \
-	android_hardware_UsbDeviceConnection.cpp \
-	android_hardware_UsbRequest.cpp \
-	android_hardware_location_ActivityRecognitionHardware.cpp \
-	android_util_FileObserver.cpp \
-	android/opengl/poly_clip.cpp.arm \
-	android/opengl/util.cpp.arm \
-	android_server_FingerprintManager.cpp \
-	android_server_NetworkManagementSocketTagger.cpp \
-	android_server_Watchdog.cpp \
-	android_ddm_DdmHandleNativeHeap.cpp \
-	com_android_internal_os_ZygoteInit.cpp \
-	android_backup_BackupDataInput.cpp \
-	android_backup_BackupDataOutput.cpp \
-	android_backup_FileBackupHelperBase.cpp \
-	android_backup_BackupHelperDispatcher.cpp \
-	android_app_backup_FullBackup.cpp \
-	android_content_res_ObbScanner.cpp \
-	android_content_res_Configuration.cpp \
-	android_animation_PropertyValuesHolder.cpp \
-	com_android_internal_net_NetworkStatsFactory.cpp \
-	com_android_internal_os_Zygote.cpp \
-	com_android_internal_util_VirtualRefBasePtr.cpp \
-	com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+    AndroidRuntime.cpp \
+    com_android_internal_content_NativeLibraryHelper.cpp \
+    com_google_android_gles_jni_EGLImpl.cpp \
+    com_google_android_gles_jni_GLImpl.cpp.arm \
+    android_app_NativeActivity.cpp \
+    android_opengl_EGL14.cpp \
+    android_opengl_EGLExt.cpp \
+    android_opengl_GLES10.cpp \
+    android_opengl_GLES10Ext.cpp \
+    android_opengl_GLES11.cpp \
+    android_opengl_GLES11Ext.cpp \
+    android_opengl_GLES20.cpp \
+    android_opengl_GLES30.cpp \
+    android_opengl_GLES31.cpp \
+    android_opengl_GLES31Ext.cpp \
+    android_database_CursorWindow.cpp \
+    android_database_SQLiteCommon.cpp \
+    android_database_SQLiteConnection.cpp \
+    android_database_SQLiteGlobal.cpp \
+    android_database_SQLiteDebug.cpp \
+    android_emoji_EmojiFactory.cpp \
+    android_view_DisplayEventReceiver.cpp \
+    android_view_DisplayListCanvas.cpp \
+    android_view_GraphicBuffer.cpp \
+    android_view_HardwareLayer.cpp \
+    android_view_InputChannel.cpp \
+    android_view_InputDevice.cpp \
+    android_view_InputEventReceiver.cpp \
+    android_view_InputEventSender.cpp \
+    android_view_InputQueue.cpp \
+    android_view_KeyCharacterMap.cpp \
+    android_view_KeyEvent.cpp \
+    android_view_MotionEvent.cpp \
+    android_view_PointerIcon.cpp \
+    android_view_RenderNode.cpp \
+    android_view_RenderNodeAnimator.cpp \
+    android_view_Surface.cpp \
+    android_view_SurfaceControl.cpp \
+    android_view_SurfaceSession.cpp \
+    android_view_TextureView.cpp \
+    android_view_ThreadedRenderer.cpp \
+    android_view_VelocityTracker.cpp \
+    android_text_AndroidCharacter.cpp \
+    android_text_AndroidBidi.cpp \
+    android_text_StaticLayout.cpp \
+    android_os_Debug.cpp \
+    android_os_MemoryFile.cpp \
+    android_os_MessageQueue.cpp \
+    android_os_Parcel.cpp \
+    android_os_SELinux.cpp \
+    android_os_SystemClock.cpp \
+    android_os_SystemProperties.cpp \
+    android_os_Trace.cpp \
+    android_os_UEventObserver.cpp \
+    android_net_LocalSocketImpl.cpp \
+    android_net_NetUtils.cpp \
+    android_net_TrafficStats.cpp \
+    android_nio_utils.cpp \
+    android_util_AssetManager.cpp \
+    android_util_Binder.cpp \
+    android_util_EventLog.cpp \
+    android_util_Log.cpp \
+    android_util_Process.cpp \
+    android_util_StringBlock.cpp \
+    android_util_XmlBlock.cpp \
+    android_graphics_Canvas.cpp \
+    android_graphics_Picture.cpp \
+    android/graphics/AutoDecodeCancel.cpp \
+    android/graphics/AvoidXfermode.cpp \
+    android/graphics/Bitmap.cpp \
+    android/graphics/BitmapFactory.cpp \
+    android/graphics/Camera.cpp \
+    android/graphics/CanvasProperty.cpp \
+    android/graphics/ColorFilter.cpp \
+    android/graphics/DrawFilter.cpp \
+    android/graphics/FontFamily.cpp \
+    android/graphics/CreateJavaOutputStreamAdaptor.cpp \
+    android/graphics/Graphics.cpp \
+    android/graphics/HarfBuzzNGFaceSkia.cpp \
+    android/graphics/Interpolator.cpp \
+    android/graphics/MaskFilter.cpp \
+    android/graphics/Matrix.cpp \
+    android/graphics/MinikinSkia.cpp \
+    android/graphics/MinikinUtils.cpp \
+    android/graphics/Movie.cpp \
+    android/graphics/NinePatch.cpp \
+    android/graphics/NinePatchImpl.cpp \
+    android/graphics/NinePatchPeeker.cpp \
+    android/graphics/Paint.cpp \
+    android/graphics/PaintImpl.cpp \
+    android/graphics/Path.cpp \
+    android/graphics/PathMeasure.cpp \
+    android/graphics/PathEffect.cpp \
+    android/graphics/Picture.cpp \
+    android/graphics/PorterDuff.cpp \
+    android/graphics/BitmapRegionDecoder.cpp \
+    android/graphics/Rasterizer.cpp \
+    android/graphics/Region.cpp \
+    android/graphics/Shader.cpp \
+    android/graphics/SurfaceTexture.cpp \
+    android/graphics/Typeface.cpp \
+    android/graphics/TypefaceImpl.cpp \
+    android/graphics/Utils.cpp \
+    android/graphics/Xfermode.cpp \
+    android/graphics/YuvToJpegEncoder.cpp \
+    android/graphics/pdf/PdfDocument.cpp \
+    android/graphics/pdf/PdfEditor.cpp \
+    android/graphics/pdf/PdfRenderer.cpp \
+    android_media_AudioRecord.cpp \
+    android_media_AudioSystem.cpp \
+    android_media_AudioTrack.cpp \
+    android_media_JetPlayer.cpp \
+    android_media_RemoteDisplay.cpp \
+    android_media_ToneGenerator.cpp \
+    android_hardware_Camera.cpp \
+    android_hardware_camera2_CameraMetadata.cpp \
+    android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
+    android_hardware_camera2_legacy_PerfMeasurement.cpp \
+    android_hardware_camera2_DngCreator.cpp \
+    android_hardware_SensorManager.cpp \
+    android_hardware_SerialPort.cpp \
+    android_hardware_SoundTrigger.cpp \
+    android_hardware_UsbDevice.cpp \
+    android_hardware_UsbDeviceConnection.cpp \
+    android_hardware_UsbRequest.cpp \
+    android_hardware_location_ActivityRecognitionHardware.cpp \
+    android_util_FileObserver.cpp \
+    android/opengl/poly_clip.cpp.arm \
+    android/opengl/util.cpp \
+    android_server_FingerprintManager.cpp \
+    android_server_NetworkManagementSocketTagger.cpp \
+    android_server_Watchdog.cpp \
+    android_ddm_DdmHandleNativeHeap.cpp \
+    android_backup_BackupDataInput.cpp \
+    android_backup_BackupDataOutput.cpp \
+    android_backup_FileBackupHelperBase.cpp \
+    android_backup_BackupHelperDispatcher.cpp \
+    android_app_backup_FullBackup.cpp \
+    android_content_res_ObbScanner.cpp \
+    android_content_res_Configuration.cpp \
+    android_animation_PropertyValuesHolder.cpp \
+    com_android_internal_net_NetworkStatsFactory.cpp \
+    com_android_internal_os_Zygote.cpp \
+    com_android_internal_util_VirtualRefBasePtr.cpp \
+    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
 
 LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	$(LOCAL_PATH)/android/graphics \
-	$(LOCAL_PATH)/../../libs/hwui \
-	$(LOCAL_PATH)/../../../native/opengl/libs \
-	$(call include-path-for, bluedroid) \
-	$(call include-path-for, libhardware)/hardware \
-	$(call include-path-for, libhardware_legacy)/hardware_legacy \
-	$(TOP)/bionic/libc/dns/include \
-	$(TOP)/frameworks/av/include \
-	$(TOP)/system/media/camera/include \
-	$(TOP)/system/netd/include \
-	external/icu/icu4c/source/common \
-	external/pdfium/core/include/fpdfapi \
-	external/pdfium/core/include/fpdfdoc \
-	external/pdfium/fpdfsdk/include \
-	external/skia/src/core \
-	external/skia/src/effects \
-	external/skia/src/images \
-	external/sqlite/dist \
-	external/sqlite/android \
-	external/expat/lib \
-	external/openssl/include \
-	external/tremor/Tremor \
-	external/jpeg \
-	external/harfbuzz_ng/src \
-	external/zlib \
-	frameworks/opt/emoji \
-	libcore/include \
-	$(call include-path-for, audio-utils) \
-	frameworks/minikin/include \
-	external/freetype/include
+    $(JNI_H_INCLUDE) \
+    $(LOCAL_PATH)/android/graphics \
+    $(LOCAL_PATH)/../../libs/hwui \
+    $(LOCAL_PATH)/../../../native/opengl/libs \
+    $(call include-path-for, bluedroid) \
+    $(call include-path-for, libhardware)/hardware \
+    $(call include-path-for, libhardware_legacy)/hardware_legacy \
+    $(TOP)/frameworks/av/include \
+    $(TOP)/system/media/camera/include \
+    $(TOP)/system/netd/include \
+    external/pdfium/core/include/fpdfapi \
+    external/pdfium/core/include/fpdfdoc \
+    external/pdfium/fpdfsdk/include \
+    external/skia/src/core \
+    external/skia/src/effects \
+    external/skia/src/images \
+    external/sqlite/dist \
+    external/sqlite/android \
+    external/expat/lib \
+    external/tremor/Tremor \
+    external/jpeg \
+    external/harfbuzz_ng/src \
+    frameworks/opt/emoji \
+    libcore/include \
+    $(call include-path-for, audio-utils) \
+    frameworks/minikin/include \
+    external/freetype/include
 # TODO: clean up Minikin so it doesn't need the freetype include
 
 LOCAL_SHARED_LIBRARIES := \
-	libmemtrack \
-	libandroidfw \
-	libexpat \
-	libnativehelper \
-	liblog \
-	libcutils \
-	libutils \
-	libbinder \
-	libnetutils \
-	libui \
-	libgui \
-	libinput \
-	libinputflinger \
-	libcamera_client \
-	libcamera_metadata \
-	libskia \
-	libsqlite \
-	libEGL \
-	libGLESv1_CM \
-	libGLESv2 \
-	libETC1 \
-	libhardware \
-	libhardware_legacy \
-	libselinux \
-	libsonivox \
-	libcrypto \
-	libssl \
-	libicuuc \
-	libicui18n \
-	libmedia \
-	libjpeg \
-	libusbhost \
-	libharfbuzz_ng \
-	libz \
-	libaudioutils \
-	libpdfium \
-	libimg_utils \
-	libnetd_client \
-	libsoundtrigger \
-	libminikin \
-	libstlport \
-	libprocessgroup \
-	libnativebridge \
-
-ifeq ($(USE_OPENGL_RENDERER),true)
-	LOCAL_SHARED_LIBRARIES += libhwui
-endif
+    libmemtrack \
+    libandroidfw \
+    libexpat \
+    libnativehelper \
+    liblog \
+    libcutils \
+    libutils \
+    libbinder \
+    libnetutils \
+    libui \
+    libgui \
+    libinput \
+    libinputflinger \
+    libcamera_client \
+    libcamera_metadata \
+    libskia \
+    libsqlite \
+    libEGL \
+    libGLESv1_CM \
+    libGLESv2 \
+    libETC1 \
+    libhardware \
+    libhardware_legacy \
+    libselinux \
+    libsonivox \
+    libcrypto \
+    libssl \
+    libicuuc \
+    libicui18n \
+    libmedia \
+    libjpeg \
+    libusbhost \
+    libharfbuzz_ng \
+    libz \
+    libaudioutils \
+    libpdfium \
+    libimg_utils \
+    libnetd_client \
+    libsoundtrigger \
+    libminikin \
+    libprocessgroup \
+    libnativebridge
 
 LOCAL_SHARED_LIBRARIES += \
-	libdl
+    libhwui \
+    libdl
+
 # we need to access the private Bionic header
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
-LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
-	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
+LOCAL_C_INCLUDES += bionic/libc/private
 
 LOCAL_MODULE:= libandroid_runtime
 
-include external/stlport/libstlport.mk
+# -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn
+#                       off a GCC warning that Clang doesn't know.
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-unknown-pragmas
+
+# -Wno-c++11-extensions: Clang warns about Skia using the C++11 override keyword, but this project
+#                        is not being compiled with that level. Remove once this has changed.
+LOCAL_CFLAGS += -Wno-c++11-extensions
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1fbd4a1..ad52e3f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -95,8 +95,6 @@
 extern int register_android_media_JetPlayer(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
 
-extern int register_android_util_FloatMath(JNIEnv* env);
-
 namespace android {
 
 /*
@@ -129,16 +127,16 @@
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_GraphicBuffer(JNIEnv* env);
+extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
-extern int register_android_view_GraphicBuffer(JNIEnv* env);
-extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_HardwareLayer(JNIEnv* env);
-extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
@@ -164,7 +162,6 @@
 extern int register_android_opengl_classes(JNIEnv *env);
 extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
 extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
-extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
 extern int register_android_backup_BackupDataInput(JNIEnv *env);
 extern int register_android_backup_BackupDataOutput(JNIEnv *env);
 extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
@@ -193,12 +190,6 @@
 
 static AndroidRuntime* gCurRuntime = NULL;
 
-static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
-{
-    if (jniThrowException(env, exc, msg) != 0)
-        assert(false);
-}
-
 /*
  * Code written in the Java Programming Language calls here from main().
  */
@@ -246,8 +237,8 @@
         mArgBlockLength(argBlockLength)
 {
     SkGraphics::Init();
-    // There is also a global font cache, but its budget is specified in code
-    // see SkFontHost_android.cpp
+    // There is also a global font cache, but its budget is specified by
+    // SK_DEFAULT_FONT_CACHE_COUNT_LIMIT and SK_DEFAULT_FONT_CACHE_LIMIT.
 
     // Pre-allocate enough space to hold a fair number of options.
     mOptions.setCapacity(20);
@@ -366,22 +357,37 @@
 }
 
 /*
- * Read the persistent locale.
+ * Read the persistent locale. Attempts to read to persist.sys.locale
+ * and falls back to the default locale (ro.product.locale) if
+ * persist.sys.locale is empty.
  */
-static void readLocale(char* language, char* region)
+static void readLocale(char* locale)
 {
-    char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
+    // Allocate 4 extra bytes because we might read a property into
+    // this array at offset 4.
+    char propLocale[PROPERTY_VALUE_MAX + 4];
 
-    property_get("persist.sys.language", propLang, "");
-    property_get("persist.sys.country", propRegn, "");
-    if (*propLang == 0 && *propRegn == 0) {
-        /* Set to ro properties, default is en_US */
-        property_get("ro.product.locale.language", propLang, "en");
-        property_get("ro.product.locale.region", propRegn, "US");
+    property_get("persist.sys.locale", propLocale, "");
+    if (propLocale[0] == 0) {
+        property_get("ro.product.locale", propLocale, "");
+
+        if (propLocale[0] == 0) {
+            // If persist.sys.locale and ro.product.locale are missing,
+            // construct a locale value from the individual locale components.
+            property_get("ro.product.locale.language", propLocale, "en");
+
+            // The language code is either two or three chars in length. If it
+            // isn't 2 chars long, assume three. Anything else is an error
+            // anyway.
+            const int offset = (propLocale[2] == 0) ? 2 : 3;
+            propLocale[offset] = '-';
+
+            property_get("ro.product.locale.region", propLocale + offset + 1, "US");
+        }
     }
-    strncat(language, propLang, 3);
-    strncat(region, propRegn, 3);
-    //ALOGD("language=%s region=%s\n", language, region);
+
+    strncat(locale, propLocale, PROPERTY_VALUE_MAX);
+    // ALOGD("[DEBUG] locale=%s", locale);
 }
 
 void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
@@ -534,19 +540,18 @@
     JavaVMInitArgs initArgs;
     char propBuf[PROPERTY_VALUE_MAX];
     char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
-    char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
-    char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
     char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
     char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
     char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
     char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
+    char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
+    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
+    char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
-    char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
-    char dalvikVmLibBuf[PROPERTY_VALUE_MAX];
     char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
@@ -572,11 +577,8 @@
                                     PROPERTY_VALUE_MAX];
     char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX];
     char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX];
-    char langOption[sizeof("-Duser.language=") + 3];
-    char regionOption[sizeof("-Duser.region=") + 3];
+    char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
     char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
-    char jitOpBuf[sizeof("-Xjitop:")-1 + PROPERTY_VALUE_MAX];
-    char jitMethodBuf[sizeof("-Xjitmethod:")-1 + PROPERTY_VALUE_MAX];
     char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
 
     bool checkJni = false;
@@ -595,9 +597,6 @@
         /* extended JNI checking */
         addOption("-Xcheck:jni");
 
-        /* set a cap on JNI global references */
-        addOption("-Xjnigreflimit:2000");
-
         /* with -Xcheck:jni, this provides a JNI function call trace */
         //addOption("-verbose:jni");
     }
@@ -613,30 +612,6 @@
 
     parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
 
-    property_get("dalvik.vm.check-dex-sum", propBuf, "");
-    if (strcmp(propBuf, "true") == 0) {
-        /* perform additional DEX checksum tests */
-        addOption("-Xcheckdexsum");
-    }
-
-    property_get("log.redirect-stdio", propBuf, "");
-    if (strcmp(propBuf, "true") == 0) {
-        /* convert stdout/stderr to log messages */
-        addOption("-Xlog-stdio");
-    }
-
-    strcpy(enableAssertBuf, "-ea:");
-    property_get("dalvik.vm.enableassertions", enableAssertBuf+sizeof("-ea:")-1, "");
-    if (enableAssertBuf[sizeof("-ea:")-1] != '\0') {
-        /* accept "all" to mean "all classes and packages" */
-        if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0)
-            enableAssertBuf[3] = '\0'; // truncate to "-ea"
-        ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
-        addOption(enableAssertBuf);
-    } else {
-        ALOGV("Assertions disabled\n");
-    }
-
     strcpy(jniOptsBuf, "-Xjniopts:");
     if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
         ALOGI("JNI options: '%s'\n", jniOptsBuf);
@@ -663,14 +638,6 @@
     parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
     parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
 
-    // Increase the main thread's interpreter stack size for bug 6315322.
-    addOption("-XX:mainThreadStackSize=24K");
-
-    // Set the max jit code cache size.  Note: size of 0 will disable the JIT.
-    parseRuntimeOption("dalvik.vm.jit.codecachesize",
-                       jitcodecachesizeOptsBuf,
-                       "-Xjitcodecachesize:");
-
     parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
     parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
     parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
@@ -678,6 +645,13 @@
                        heaptargetutilizationOptsBuf,
                        "-XX:HeapTargetUtilization=");
 
+    /*
+     * JIT related options.
+     */
+    parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
+    parseRuntimeOption("dalvik.vm.jitcodecachesize", jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
+    parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
+
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
       addOption("-XX:LowMemoryMode");
@@ -686,53 +660,6 @@
     parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
     parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");
 
-    /*
-     * Enable or disable dexopt features, such as bytecode verification and
-     * calculation of register maps for precise GC.
-     */
-    property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, "");
-    if (dexoptFlagsBuf[0] != '\0') {
-        const char* opc;
-        const char* val;
-
-        opc = strstr(dexoptFlagsBuf, "v=");     /* verification */
-        if (opc != NULL) {
-            switch (*(opc+2)) {
-            case 'n':   val = "-Xverify:none";      break;
-            case 'r':   val = "-Xverify:remote";    break;
-            case 'a':   val = "-Xverify:all";       break;
-            default:    val = NULL;                 break;
-            }
-
-            if (val != NULL) {
-                addOption(val);
-            }
-        }
-
-        opc = strstr(dexoptFlagsBuf, "o=");     /* optimization */
-        if (opc != NULL) {
-            switch (*(opc+2)) {
-            case 'n':   val = "-Xdexopt:none";      break;
-            case 'v':   val = "-Xdexopt:verified";  break;
-            case 'a':   val = "-Xdexopt:all";       break;
-            case 'f':   val = "-Xdexopt:full";      break;
-            default:    val = NULL;                 break;
-            }
-
-            if (val != NULL) {
-                addOption(val);
-            }
-        }
-
-        opc = strstr(dexoptFlagsBuf, "m=y");    /* register map */
-        if (opc != NULL) {
-            addOption("-Xgenregmap");
-
-            /* turn on precise GC while we're at it */
-            addOption("-Xgc:precise");
-        }
-    }
-
     /* enable debugging; set suspend=y to pause during VM init */
     /* use android ADB transport */
     addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
@@ -741,12 +668,6 @@
                        lockProfThresholdBuf,
                        "-Xlockprofthreshold:");
 
-    /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
-    parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:");
-
-    /* Force interpreter-only mode for selected methods */
-    parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");
-
     if (executionMode == kEMIntPortable) {
         addOption("-Xint:portable");
     } else if (executionMode == kEMIntFast) {
@@ -755,141 +676,138 @@
         addOption("-Xint:jit");
     }
 
-    // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
-    property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
-    bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
+    // If we are booting without the real /data, don't spend time compiling.
+    property_get("vold.decrypt", voldDecryptBuf, "");
+    bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
+                             (strcmp(voldDecryptBuf, "1") == 0));
 
-    if (libart) {
-        // If we booting without the real /data, don't spend time compiling.
-        property_get("vold.decrypt", voldDecryptBuf, "");
-        bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
-                                 (strcmp(voldDecryptBuf, "1") == 0));
-
-        // Extra options for boot.art/boot.oat image generation.
-        parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
-                                   "-Xms", "-Ximage-compiler-option");
-        parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
-                                   "-Xmx", "-Ximage-compiler-option");
-        if (skip_compilation) {
-            addOption("-Ximage-compiler-option");
-            addOption("--compiler-filter=verify-none");
-        } else {
-            parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
-                                "--compiler-filter=", "-Ximage-compiler-option");
-        }
-
-        // Make sure there is a preloaded-classes file.
-        if (!hasFile("/system/etc/preloaded-classes")) {
-            ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
-                  strerror(errno));
-            goto bail;
-        }
+    // Extra options for boot.art/boot.oat image generation.
+    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
+                               "-Xms", "-Ximage-compiler-option");
+    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
+                               "-Xmx", "-Ximage-compiler-option");
+    if (skip_compilation) {
         addOption("-Ximage-compiler-option");
-        addOption("--image-classes=/system/etc/preloaded-classes");
-
-        // If there is a compiled-classes file, push it.
-        if (hasFile("/system/etc/compiled-classes")) {
-            addOption("-Ximage-compiler-option");
-            addOption("--compiled-classes=/system/etc/compiled-classes");
-        }
-
-        property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
-        parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
-
-        // Extra options for DexClassLoader.
-        parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
-                                   "-Xms", "-Xcompiler-option");
-        parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
-                                   "-Xmx", "-Xcompiler-option");
-        if (skip_compilation) {
-            addOption("-Xcompiler-option");
-            addOption("--compiler-filter=verify-none");
-        } else {
-            parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
-                                "--compiler-filter=", "-Xcompiler-option");
-        }
-        property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
-        parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
-
+        addOption("--compiler-filter=verify-none");
+    } else {
+        parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
+                            "--compiler-filter=", "-Ximage-compiler-option");
     }
 
+    // Make sure there is a preloaded-classes file.
+    if (!hasFile("/system/etc/preloaded-classes")) {
+        ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
+              strerror(errno));
+        goto bail;
+    }
+    addOption("-Ximage-compiler-option");
+    addOption("--image-classes=/system/etc/preloaded-classes");
+
+    // If there is a compiled-classes file, push it.
+    if (hasFile("/system/etc/compiled-classes")) {
+        addOption("-Ximage-compiler-option");
+        addOption("--compiled-classes=/system/etc/compiled-classes");
+    }
+
+    property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
+    parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
+
+    // Extra options for DexClassLoader.
+    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
+                               "-Xms", "-Xcompiler-option");
+    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
+                               "-Xmx", "-Xcompiler-option");
+    if (skip_compilation) {
+        addOption("-Xcompiler-option");
+        addOption("--compiler-filter=verify-none");
+
+        // We skip compilation when a minimal runtime is brought up for decryption. In that case
+        // /data is temporarily backed by a tmpfs, which is usually small.
+        // If the system image contains prebuilts, they will be relocated into the tmpfs. In this
+        // specific situation it is acceptable to *not* relocate and run out of the prebuilts
+        // directly instead.
+        addOption("--runtime-arg");
+        addOption("-Xnorelocate");
+    } else {
+        parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
+                            "--compiler-filter=", "-Xcompiler-option");
+    }
+    property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
+    parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
+
     /* extra options; parse this late so it overrides others */
     property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
     parseExtraOpts(extraOptsBuf, NULL);
 
     /* Set the properties for locale */
     {
-        strcpy(langOption, "-Duser.language=");
-        strcpy(regionOption, "-Duser.region=");
-        readLocale(langOption, regionOption);
-        addOption(langOption);
-        addOption(regionOption);
+        strcpy(localeOption, "-Duser.locale=");
+        readLocale(localeOption);
+        addOption(localeOption);
     }
 
     /*
      * Set profiler options
      */
-    if (libart) {
-        // Whether or not the profiler should be enabled.
-        property_get("dalvik.vm.profiler", propBuf, "0");
-        if (propBuf[0] == '1') {
-            addOption("-Xenable-profiler");
-        }
+    // Whether or not the profiler should be enabled.
+    property_get("dalvik.vm.profiler", propBuf, "0");
+    if (propBuf[0] == '1') {
+        addOption("-Xenable-profiler");
+    }
 
-        // 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') {
-            addOption("-Xprofile-start-immediately");
-        }
+    // 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') {
+        addOption("-Xprofile-start-immediately");
+    }
 
-        // Number of seconds during profile runs.
-        parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:");
+    // Number of seconds during profile runs.
+    parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:");
 
-        // Length of each profile run (seconds).
-        parseRuntimeOption("dalvik.vm.profile.duration-secs",
-                           profileDuration,
-                           "-Xprofile-duration:");
+    // Length of each profile run (seconds).
+    parseRuntimeOption("dalvik.vm.profile.duration-secs",
+                       profileDuration,
+                       "-Xprofile-duration:");
 
-        // Polling interval during profile run (microseconds).
-        parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:");
+    // Polling interval during profile run (microseconds).
+    parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:");
 
-        // Coefficient for period backoff.  The the period is multiplied
-        // by this value after each profile run.
-        parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:");
+    // Coefficient for period backoff.  The the period is multiplied
+    // by this value after each profile run.
+    parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:");
 
-        // Top K% of samples that are considered relevant when
-        // deciding if the app should be recompiled.
-        parseRuntimeOption("dalvik.vm.profile.top-k-thr",
-                           profileTopKThreshold,
-                           "-Xprofile-top-k-threshold:");
+    // Top K% of samples that are considered relevant when
+    // deciding if the app should be recompiled.
+    parseRuntimeOption("dalvik.vm.profile.top-k-thr",
+                       profileTopKThreshold,
+                       "-Xprofile-top-k-threshold:");
 
-        // The threshold after which a change in the structure of the
-        // top K% profiled samples becomes significant and triggers
-        // recompilation. A change in profile is considered
-        // significant if X% (top-k-change-threshold) of the top K%
-        // (top-k-threshold property) samples has changed.
-        parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr",
-                           profileTopKChangeThreshold,
-                           "-Xprofile-top-k-change-threshold:");
+    // The threshold after which a change in the structure of the
+    // top K% profiled samples becomes significant and triggers
+    // recompilation. A change in profile is considered
+    // significant if X% (top-k-change-threshold) of the top K%
+    // (top-k-threshold property) samples has changed.
+    parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr",
+                       profileTopKChangeThreshold,
+                       "-Xprofile-top-k-change-threshold:");
 
-        // Type of profile data.
-        parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:");
+    // Type of profile data.
+    parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:");
 
-        // Depth of bounded stack data
-        parseRuntimeOption("dalvik.vm.profile.stack-depth",
-                           profileMaxStackDepth,
-                           "-Xprofile-max-stack-depth:");
+    // Depth of bounded stack data
+    parseRuntimeOption("dalvik.vm.profile.stack-depth",
+                       profileMaxStackDepth,
+                       "-Xprofile-max-stack-depth:");
 
-        // Native bridge library. "0" means that native bridge is disabled.
-        property_get("ro.dalvik.vm.native.bridge", propBuf, "");
-        if (propBuf[0] == '\0') {
-            ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
-        } else if (strcmp(propBuf, "0") != 0) {
-            snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
-                     "-XX:NativeBridge=%s", propBuf);
-            addOption(nativeBridgeLibrary);
-        }
+    // Native bridge library. "0" means that native bridge is disabled.
+    property_get("ro.dalvik.vm.native.bridge", propBuf, "");
+    if (propBuf[0] == '\0') {
+        ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
+    } else if (strcmp(propBuf, "0") != 0) {
+        snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
+                 "-XX:NativeBridge=%s", propBuf);
+        addOption(nativeBridgeLibrary);
     }
 
     initArgs.version = JNI_VERSION_1_4;
@@ -1237,19 +1155,11 @@
     return 0;
 }
 
-static void register_jam_procs(const RegJAMProc array[], size_t count)
-{
-    for (size_t i = 0; i < count; i++) {
-        array[i]();
-    }
-}
-
 static const RegJNIRec gRegJNI[] = {
     REG_JNI(register_com_android_internal_os_RuntimeInit),
     REG_JNI(register_android_os_SystemClock),
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
-    REG_JNI(register_android_util_FloatMath),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
@@ -1269,7 +1179,7 @@
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
     REG_JNI(register_android_view_GraphicBuffer),
-    REG_JNI(register_android_view_GLES20Canvas),
+    REG_JNI(register_android_view_DisplayListCanvas),
     REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
@@ -1337,7 +1247,6 @@
     REG_JNI(register_android_net_NetworkUtils),
     REG_JNI(register_android_net_TrafficStats),
     REG_JNI(register_android_os_MemoryFile),
-    REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_com_android_internal_os_Zygote),
     REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
     REG_JNI(register_android_hardware_Camera),
diff --git a/core/jni/android/graphics/AutoDecodeCancel.cpp b/core/jni/android/graphics/AutoDecodeCancel.cpp
index f0739ea..0641b96 100644
--- a/core/jni/android/graphics/AutoDecodeCancel.cpp
+++ b/core/jni/android/graphics/AutoDecodeCancel.cpp
@@ -1,6 +1,7 @@
 #include "AutoDecodeCancel.h"
+#include "SkMutex.h"
 
-static SkMutex  gAutoDecoderCancelMutex;
+SK_DECLARE_STATIC_MUTEX(gAutoDecoderCancelMutex);
 static AutoDecoderCancel* gAutoDecoderCancel;
 #ifdef SK_DEBUG
 static int gAutoDecoderCancelCount;
diff --git a/core/jni/android/graphics/AutoDecodeCancel.h b/core/jni/android/graphics/AutoDecodeCancel.h
index 37b86f9..dd6a0d4 100644
--- a/core/jni/android/graphics/AutoDecodeCancel.h
+++ b/core/jni/android/graphics/AutoDecodeCancel.h
@@ -1,5 +1,5 @@
-#ifndef AutoDecodeCancel_DEFINED
-#define AutoDecodeCancel_DEFINED
+#ifndef _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
+#define _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
 
 #include <jni.h>
 #include "SkImageDecoder.h"
@@ -24,4 +24,4 @@
 #endif
 };
 
-#endif
+#endif  // _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
diff --git a/core/jni/android/graphics/AvoidXfermode.cpp b/core/jni/android/graphics/AvoidXfermode.cpp
new file mode 100644
index 0000000..9ca1f26
--- /dev/null
+++ b/core/jni/android/graphics/AvoidXfermode.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "AvoidXfermode.h"
+#include "SkColorPriv.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+#include "SkString.h"
+
+AvoidXfermode::AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode) {
+    if (tolerance > 255) {
+        tolerance = 255;
+    }
+    fTolerance = SkToU8(tolerance);
+    fOpColor = opColor;
+    fDistMul = (256 << 14) / (tolerance + 1);
+    fMode = mode;
+}
+
+SkFlattenable* AvoidXfermode::CreateProc(SkReadBuffer& buffer) {
+    const SkColor color = buffer.readColor();
+    const unsigned tolerance = buffer.readUInt();
+    const unsigned mode = buffer.readUInt();
+    return Create(color, tolerance, (Mode)mode);
+}
+
+void AvoidXfermode::flatten(SkWriteBuffer& buffer) const {
+    buffer.writeColor(fOpColor);
+    buffer.writeUInt(fTolerance);
+    buffer.writeUInt(fMode);
+}
+
+// returns 0..31
+static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b) {
+    SkASSERT(r <= SK_R16_MASK);
+    SkASSERT(g <= SK_G16_MASK);
+    SkASSERT(b <= SK_B16_MASK);
+
+    unsigned dr = SkAbs32(SkGetPackedR16(c) - r);
+    unsigned dg = SkAbs32(SkGetPackedG16(c) - g) >> (SK_G16_BITS - SK_R16_BITS);
+    unsigned db = SkAbs32(SkGetPackedB16(c) - b);
+
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+// returns 0..255
+static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b) {
+    SkASSERT(r <= 0xFF);
+    SkASSERT(g <= 0xFF);
+    SkASSERT(b <= 0xFF);
+
+    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
+    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
+    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
+
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static int scale_dist_14(int dist, uint32_t mul, uint32_t sub) {
+    int tmp = dist * mul - sub;
+    int result = (tmp + (1 << 13)) >> 14;
+
+    return result;
+}
+
+static inline unsigned Accurate255To256(unsigned x) {
+    return x + (x >> 7);
+}
+
+void AvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
+                             const SkAlpha aa[]) const {
+    unsigned    opR = SkColorGetR(fOpColor);
+    unsigned    opG = SkColorGetG(fOpColor);
+    unsigned    opB = SkColorGetB(fOpColor);
+    uint32_t    mul = fDistMul;
+    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
+
+    int MAX, mask;
+
+    if (kTargetColor_Mode == fMode) {
+        mask = -1;
+        MAX = 255;
+    } else {
+        mask = 0;
+        MAX = 0;
+    }
+
+    for (int i = 0; i < count; i++) {
+        int d = color_dist32(dst[i], opR, opG, opB);
+        // now reverse d if we need to
+        d = MAX + (d ^ mask) - mask;
+        SkASSERT((unsigned)d <= 255);
+        d = Accurate255To256(d);
+
+        d = scale_dist_14(d, mul, sub);
+        SkASSERT(d <= 256);
+
+        if (d > 0) {
+            if (aa) {
+                d = SkAlphaMul(d, Accurate255To256(*aa++));
+                if (0 == d) {
+                    continue;
+                }
+            }
+            dst[i] = SkFourByteInterp256(src[i], dst[i], d);
+        }
+    }
+}
+
+static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale) {
+    SkASSERT(scale <= 32);
+    scale <<= 3;
+
+    return SkPackRGB16( SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
+                        SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
+                        SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
+}
+
+void AvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
+                             const SkAlpha aa[]) const {
+    unsigned    opR = SkColorGetR(fOpColor) >> (8 - SK_R16_BITS);
+    unsigned    opG = SkColorGetG(fOpColor) >> (8 - SK_G16_BITS);
+    unsigned    opB = SkColorGetB(fOpColor) >> (8 - SK_R16_BITS);
+    uint32_t    mul = fDistMul;
+    uint32_t    sub = (fDistMul - (1 << 14)) << SK_R16_BITS;
+
+    int MAX, mask;
+
+    if (kTargetColor_Mode == fMode) {
+        mask = -1;
+        MAX = 31;
+    } else {
+        mask = 0;
+        MAX = 0;
+    }
+
+    for (int i = 0; i < count; i++) {
+        int d = color_dist16(dst[i], opR, opG, opB);
+        // now reverse d if we need to
+        d = MAX + (d ^ mask) - mask;
+        SkASSERT((unsigned)d <= 31);
+        // convert from 0..31 to 0..32
+        d += d >> 4;
+        d = scale_dist_14(d, mul, sub);
+        SkASSERT(d <= 32);
+
+        if (d > 0) {
+            if (aa) {
+                d = SkAlphaMul(d, Accurate255To256(*aa++));
+                if (0 == d) {
+                    continue;
+                }
+            }
+            dst[i] = SkBlend3216(src[i], dst[i], d);
+        }
+    }
+}
+
+void AvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
+        const SkAlpha aa[]) const {
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void AvoidXfermode::toString(SkString* str) const {
+    str->append("AvoidXfermode: opColor: ");
+    str->appendHex(fOpColor);
+    str->appendf("distMul: %d ", fDistMul);
+
+    static const char* gModeStrings[] = { "Avoid", "Target" };
+
+    str->appendf("mode: %s", gModeStrings[fMode]);
+}
+#endif
diff --git a/core/jni/android/graphics/AvoidXfermode.h b/core/jni/android/graphics/AvoidXfermode.h
new file mode 100644
index 0000000..318d7be
--- /dev/null
+++ b/core/jni/android/graphics/AvoidXfermode.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef AvoidXfermode_DEFINED
+#define AvoidXfermode_DEFINED
+
+#include "SkColor.h"
+#include "SkTypes.h"
+#include "SkXfermode.h"
+
+/** \class AvoidXfermode
+
+    This xfermode will draw the src everywhere except on top of the specified
+    color.
+*/
+class AvoidXfermode : public SkXfermode {
+public:
+    enum Mode {
+        kAvoidColor_Mode,   //!< draw everywhere except on the opColor
+        kTargetColor_Mode   //!< draw only on top of the opColor
+    };
+
+    /** This xfermode draws, or doesn't draw, based on the destination's
+        distance from an op-color.
+
+        There are two modes, and each mode interprets a tolerance value.
+
+        Avoid: In this mode, drawing is allowed only on destination pixels that
+               are different from the op-color.
+               Tolerance near 0: avoid any colors even remotely similar to the op-color
+               Tolerance near 255: avoid only colors nearly identical to the op-color
+
+        Target: In this mode, drawing only occurs on destination pixels that
+                are similar to the op-color
+                Tolerance near 0: draw only on colors that are nearly identical to the op-color
+                Tolerance near 255: draw on any colors even remotely similar to the op-color
+     */
+    static AvoidXfermode* Create(SkColor opColor, U8CPU tolerance, Mode mode) {
+        return SkNEW_ARGS(AvoidXfermode, (opColor, tolerance, mode));
+    }
+
+    // overrides from SkXfermode
+    void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+    void xfer16(uint16_t dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+    void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
+            const SkAlpha aa[]) const override;
+
+    SK_TO_STRING_OVERRIDE()
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(AvoidXfermode)
+
+protected:
+    AvoidXfermode(SkColor opColor, U8CPU tolerance, Mode mode);
+    void flatten(SkWriteBuffer&) const override;
+
+private:
+    SkColor     fOpColor;
+    uint32_t    fDistMul;   // x.14 cached from fTolerance
+    uint8_t     fTolerance;
+    Mode        fMode;
+
+    typedef SkXfermode INHERITED;
+};
+
+#endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index d7eef6e..7a934bd 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -15,16 +15,10 @@
 #include "android_nio_utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 
+#include "core_jni_helpers.h"
+
 #include <jni.h>
 
-#include <ResourceCache.h>
-
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
-
 ///////////////////////////////////////////////////////////////////////////////
 // Conversions to/from SkColor, for get/setPixels, and the create method, which
 // is basically like setPixels
@@ -43,8 +37,11 @@
 
 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
                           int, int) {
+    // Needed to thwart the unreachable code detection from clang.
+    static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
+
     // SkColor's ordering may be different from SkPMColor
-    if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
+    if (sk_color_ne_zero) {
         memcpy(dst, src, width * sizeof(SkColor));
         return;
     }
@@ -225,37 +222,34 @@
                               SkColorTable* ctable) {
     SkASSERT(width > 0);
     const uint8_t* s = (const uint8_t*)src;
-    const SkPMColor* colors = ctable->lockColors();
+    const SkPMColor* colors = ctable->readColors();
     do {
         *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
     } while (--width != 0);
-    ctable->unlockColors();
 }
 
 static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
                               SkColorTable* ctable) {
     SkASSERT(width > 0);
     const uint8_t* s = (const uint8_t*)src;
-    const SkPMColor* colors = ctable->lockColors();
+    const SkPMColor* colors = ctable->readColors();
     do {
         SkPMColor c = colors[*s++];
         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
                                 SkGetPackedG32(c), SkGetPackedB32(c));
     } while (--width != 0);
-    ctable->unlockColors();
 }
 
 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
                                SkColorTable* ctable) {
     SkASSERT(width > 0);
     const uint8_t* s = (const uint8_t*)src;
-    const SkPMColor* colors = ctable->lockColors();
+    const SkPMColor* colors = ctable->readColors();
     do {
         SkPMColor c = colors[*s++];
         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
                                SkGetPackedB32(c));
     } while (--width != 0);
-    ctable->unlockColors();
 }
 
 // can return NULL
@@ -364,24 +358,11 @@
 
 static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
-    if (android::uirenderer::ResourceCache::hasInstance()) {
-        android::uirenderer::ResourceCache::getInstance().destructor(bitmap);
-        return;
-    }
-#endif // USE_OPENGL_RENDERER
     delete bitmap;
 }
 
 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
-    if (android::uirenderer::ResourceCache::hasInstance()) {
-        bool result;
-        result = android::uirenderer::ResourceCache::getInstance().recycle(bitmap);
-        return result ? JNI_TRUE : JNI_FALSE;
-    }
-#endif // USE_OPENGL_RENDERER
     bitmap->setPixels(NULL, NULL);
     return JNI_TRUE;
 }
@@ -575,24 +556,33 @@
         return NULL;
     }
 
-    SkBitmap* bitmap = new SkBitmap;
+    std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
 
-    bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes);
+    if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) {
+        return NULL;
+    }
 
     SkColorTable* ctable = NULL;
     if (colorType == kIndex_8_SkColorType) {
         int count = p->readInt32();
+        if (count < 0 || count > 256) {
+            // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
+            // inclusive.
+            return NULL;
+        }
         if (count > 0) {
             size_t size = count * sizeof(SkPMColor);
             const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
+            if (src == NULL) {
+                return NULL;
+            }
             ctable = new SkColorTable(src, count);
         }
     }
 
-    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
+    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable);
     if (NULL == buffer) {
         SkSafeUnref(ctable);
-        delete bitmap;
         return NULL;
     }
 
@@ -604,7 +594,6 @@
     android::status_t status = p->readBlob(size, &blob);
     if (status) {
         doThrowRE(env, "Could not read bitmap from parcel blob.");
-        delete bitmap;
         return NULL;
     }
 
@@ -614,8 +603,8 @@
 
     blob.release();
 
-    return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
-            NULL, NULL, density);
+    return GraphicsJNI::createBitmap(env, bitmap.release(), buffer,
+            getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
 }
 
 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
@@ -644,8 +633,7 @@
             int count = ctable->count();
             p->writeInt32(count);
             memcpy(p->writeInplace(count * sizeof(SkPMColor)),
-                   ctable->lockColors(), count * sizeof(SkPMColor));
-            ctable->unlockColors();
+                   ctable->readColors(), count * sizeof(SkPMColor));
         } else {
             p->writeInt32(0);   // indicate no ctable
         }
@@ -832,10 +820,8 @@
             return JNI_FALSE;
         }
 
-        SkAutoLockColors alc0(ct0);
-        SkAutoLockColors alc1(ct1);
         const size_t size = ct0->count() * sizeof(SkPMColor);
-        if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
+        if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
             return JNI_FALSE;
         }
     }
@@ -873,8 +859,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gBitmapMethods[] = {
     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_creator },
@@ -914,10 +898,8 @@
     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
 };
 
-#define kClassPathName  "android/graphics/Bitmap"
-
 int register_android_graphics_Bitmap(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
+                                         NELEM(gBitmapMethods));
 }
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 49577cf..47090fb 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -15,7 +15,7 @@
 #include "JNIHelp.h"
 #include "GraphicsJNI.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <androidfw/Asset.h>
 #include <androidfw/ResourceTypes.h>
 #include <cutils/compiler.h>
@@ -41,7 +41,6 @@
 jfieldID gOptions_mCancelID;
 jfieldID gOptions_bitmapFieldID;
 
-jfieldID gBitmap_nativeBitmapFieldID;
 jfieldID gBitmap_ninePatchInsetsFieldID;
 
 jclass gInsetStruct_class;
@@ -49,12 +48,6 @@
 
 using namespace android;
 
-static inline int32_t validOrNeg1(bool isValid, int32_t value) {
-//    return isValid ? value : -1;
-    SkASSERT((int)isValid == 0 || (int)isValid == 1);
-    return ((int32_t)isValid - 1) | value;
-}
-
 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
     static const struct {
         SkImageDecoder::Format fFormat;
@@ -69,7 +62,7 @@
         { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
     };
 
-    const char* cstr = NULL;
+    const char* cstr = nullptr;
     for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
         if (gMimeTypes[i].fFormat == format) {
             cstr = gMimeTypes[i].fMimeType;
@@ -77,10 +70,10 @@
         }
     }
 
-    jstring jstr = NULL;
-    if (cstr != NULL) {
+    jstring jstr = nullptr;
+    if (cstr != nullptr) {
         // NOTE: Caller should env->ExceptionCheck() for OOM
-        // (can't check for NULL as it's a valid return value)
+        // (can't check for nullptr as it's a valid return value)
         jstr = env->NewStringUTF(cstr);
     }
     return jstr;
@@ -187,8 +180,8 @@
 
         const size_t size = sk_64_asS32(size64);
         if (size > mSize) {
-            ALOGW("bitmap marked for reuse (%d bytes) can't fit new bitmap (%d bytes)",
-                    mSize, size);
+            ALOGW("bitmap marked for reuse (%u bytes) can't fit new bitmap "
+                  "(%zu bytes)", mSize, size);
             return false;
         }
 
@@ -268,7 +261,7 @@
     SkBitmap* outputBitmap = NULL;
     unsigned int existingBufferSize = 0;
     if (javaBitmap != NULL) {
-        outputBitmap = (SkBitmap*) env->GetLongField(javaBitmap, gBitmap_nativeBitmapFieldID);
+        outputBitmap = GraphicsJNI::getSkBitmap(env, javaBitmap);
         if (outputBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
             javaBitmap = NULL;
@@ -397,7 +390,7 @@
         // to/from unpremultiplied bitmaps.
         outputBitmap->setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,
                 colorType, decodingBitmap.alphaType()));
-        if (!outputBitmap->allocPixels(outputAllocator, NULL)) {
+        if (!outputBitmap->tryAllocPixels(outputAllocator, NULL)) {
             return nullObjectReturn("allocation failed for scaled bitmap");
         }
 
@@ -468,11 +461,11 @@
         jobject padding, jobject options) {
 
     jobject bitmap = NULL;
-    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
+    SkAutoTDelete<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
     if (stream.get()) {
-        SkAutoTUnref<SkStreamRewindable> bufferedStream(
-                SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER));
+        SkAutoTDelete<SkStreamRewindable> bufferedStream(
+                SkFrontBufferedStream::Create(stream.detach(), BYTES_TO_BUFFER));
         SkASSERT(bufferedStream.get() != NULL);
         bitmap = doDecode(env, bufferedStream, padding, options);
     }
@@ -511,13 +504,13 @@
         return nullObjectReturn("Could not open file");
     }
 
-    SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
-                         SkFILEStream::kCallerPasses_Ownership));
+    SkAutoTDelete<SkFILEStream> fileStream(new SkFILEStream(file,
+            SkFILEStream::kCallerPasses_Ownership));
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
     // current position of the file descriptor.
-    SkAutoTUnref<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream,
+    SkAutoTDelete<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.detach(),
             BYTES_TO_BUFFER));
 
     return doDecode(env, stream, padding, bitmapFactoryOptions);
@@ -529,8 +522,7 @@
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     // since we know we'll be done with the asset when we return, we can
     // just use a simple wrapper
-    SkAutoTUnref<SkStreamRewindable> stream(new AssetStreamAdaptor(asset,
-            AssetStreamAdaptor::kNo_OwnAsset, AssetStreamAdaptor::kNo_HasMemoryBase));
+    SkAutoTDelete<SkStreamRewindable> stream(new AssetStreamAdaptor(asset));
     return doDecode(env, stream, padding, options);
 }
 
@@ -538,8 +530,7 @@
         jint offset, jint length, jobject options) {
 
     AutoJavaByteArray ar(env, byteArray);
-    SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
-    SkAutoUnref aur(stream);
+    SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false));
     return doDecode(env, stream, NULL, options);
 }
 
@@ -585,52 +576,39 @@
     {   "requestCancel", "()V", (void*)nativeRequestCancel }
 };
 
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[]) {
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(id);
-    return id;
-}
-
 int register_android_graphics_BitmapFactory(JNIEnv* env) {
-    jclass options_class = env->FindClass("android/graphics/BitmapFactory$Options");
-    SkASSERT(options_class);
-    gOptions_bitmapFieldID = getFieldIDCheck(env, options_class, "inBitmap",
+    jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
+    gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
             "Landroid/graphics/Bitmap;");
-    gOptions_justBoundsFieldID = getFieldIDCheck(env, options_class, "inJustDecodeBounds", "Z");
-    gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I");
-    gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig",
+    gOptions_justBoundsFieldID = GetFieldIDOrDie(env, options_class, "inJustDecodeBounds", "Z");
+    gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I");
+    gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig",
             "Landroid/graphics/Bitmap$Config;");
-    gOptions_premultipliedFieldID = getFieldIDCheck(env, options_class, "inPremultiplied", "Z");
-    gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z");
-    gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z");
-    gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class,
+    gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z");
+    gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z");
+    gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z");
+    gOptions_preferQualityOverSpeedFieldID = GetFieldIDOrDie(env, options_class,
             "inPreferQualityOverSpeed", "Z");
-    gOptions_scaledFieldID = getFieldIDCheck(env, options_class, "inScaled", "Z");
-    gOptions_densityFieldID = getFieldIDCheck(env, options_class, "inDensity", "I");
-    gOptions_screenDensityFieldID = getFieldIDCheck(env, options_class, "inScreenDensity", "I");
-    gOptions_targetDensityFieldID = getFieldIDCheck(env, options_class, "inTargetDensity", "I");
-    gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I");
-    gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I");
-    gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;");
-    gOptions_mCancelID = getFieldIDCheck(env, options_class, "mCancel", "Z");
+    gOptions_scaledFieldID = GetFieldIDOrDie(env, options_class, "inScaled", "Z");
+    gOptions_densityFieldID = GetFieldIDOrDie(env, options_class, "inDensity", "I");
+    gOptions_screenDensityFieldID = GetFieldIDOrDie(env, options_class, "inScreenDensity", "I");
+    gOptions_targetDensityFieldID = GetFieldIDOrDie(env, options_class, "inTargetDensity", "I");
+    gOptions_widthFieldID = GetFieldIDOrDie(env, options_class, "outWidth", "I");
+    gOptions_heightFieldID = GetFieldIDOrDie(env, options_class, "outHeight", "I");
+    gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;");
+    gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z");
 
-    jclass bitmap_class = env->FindClass("android/graphics/Bitmap");
-    SkASSERT(bitmap_class);
-    gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, bitmap_class, "mNativeBitmap", "J");
-    gBitmap_ninePatchInsetsFieldID = getFieldIDCheck(env, bitmap_class, "mNinePatchInsets",
+    jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap");
+    gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets",
             "Landroid/graphics/NinePatch$InsetStruct;");
 
-    gInsetStruct_class = (jclass) env->NewGlobalRef(env->FindClass("android/graphics/NinePatch$InsetStruct"));
-    gInsetStruct_constructorMethodID = env->GetMethodID(gInsetStruct_class, "<init>", "(IIIIIIIIFIF)V");
+    gInsetStruct_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
+        "android/graphics/NinePatch$InsetStruct"));
+    gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
+                                                        "(IIIIIIIIFIF)V");
 
-    int ret = AndroidRuntime::registerNativeMethods(env,
-                                    "android/graphics/BitmapFactory$Options",
-                                    gOptionsMethods,
-                                    SK_ARRAY_COUNT(gOptionsMethods));
-    if (ret) {
-        return ret;
-    }
-    return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/BitmapFactory",
-                                         gMethods, SK_ARRAY_COUNT(gMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory$Options",
+                                  gOptionsMethods, NELEM(gOptionsMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
+                                         gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index 97dcc6d..a54da43 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -1,5 +1,5 @@
-#ifndef BitmapFactory_DEFINE
-#define BitmapFactory_DEFINE
+#ifndef _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
+#define _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
 
 #include "GraphicsJNI.h"
 
@@ -21,4 +21,4 @@
 
 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format);
 
-#endif
+#endif  // _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 6633261..3525d07 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -30,7 +30,7 @@
 #include "Utils.h"
 #include "JNIHelp.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include "android_util_Binder.h"
 #include "android_nio_utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
@@ -40,12 +40,6 @@
 #include <androidfw/Asset.h>
 #include <sys/stat.h>
 
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
-
 using namespace android;
 
 class SkBitmapRegionDecoder {
@@ -75,10 +69,13 @@
     int fHeight;
 };
 
+// Takes ownership of the SkStreamRewindable. For consistency, deletes stream even
+// when returning null.
 static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) {
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
     int width, height;
     if (NULL == decoder) {
+        SkDELETE(stream);
         doThrowIOE(env, "Image format not supported");
         return nullObjectReturn("SkImageDecoder::Factory returned null");
     }
@@ -87,6 +84,7 @@
     decoder->setAllocator(javaAllocator);
     javaAllocator->unref();
 
+    // This call passes ownership of stream to the decoder, or deletes on failure.
     if (!decoder->buildTileIndex(stream, &width, &height)) {
         char msg[100];
         snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
@@ -109,8 +107,8 @@
     AutoJavaByteArray ar(env, byteArray);
     SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
 
+    // the decoder owns the stream.
     jobject brd = createBitmapRegionDecoder(env, stream);
-    SkSafeUnref(stream); // the decoder now holds a reference
     return brd;
 }
 
@@ -129,8 +127,8 @@
     SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor));
     SkMemoryStream* stream = new SkMemoryStream(data);
 
+    // the decoder owns the stream.
     jobject brd = createBitmapRegionDecoder(env, stream);
-    SkSafeUnref(stream); // the decoder now holds a reference
     return brd;
 }
 
@@ -143,8 +141,8 @@
     SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage);
 
     if (stream) {
+        // the decoder owns the stream.
         brd = createBitmapRegionDecoder(env, stream);
-        stream->unref(); // the decoder now holds a reference
     }
     return brd;
 }
@@ -153,13 +151,13 @@
                                  jlong native_asset, // Asset
                                  jboolean isShareable) {
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
-    SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset));
-    if (NULL == stream.get()) {
+    SkMemoryStream* stream = CopyAssetToStream(asset);
+    if (NULL == stream) {
         return NULL;
     }
 
-    jobject brd = createBitmapRegionDecoder(env, stream.get());
-    // The decoder now holds a reference to stream.
+    // the decoder owns the stream.
+    jobject brd = createBitmapRegionDecoder(env, stream);
     return brd;
 }
 
@@ -219,7 +217,7 @@
 
     if (tileBitmap != NULL) {
         // Re-use bitmap.
-        bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap);
+        bitmap = GraphicsJNI::getSkBitmap(env, tileBitmap);
     }
     if (bitmap == NULL) {
         bitmap = new SkBitmap;
@@ -274,8 +272,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gBitmapRegionDecoderMethods[] = {
     {   "nativeDecodeRegion",
         "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
@@ -308,10 +304,8 @@
     },
 };
 
-#define kClassPathName  "android/graphics/BitmapRegionDecoder"
-
 int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-            gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/BitmapRegionDecoder",
+            gBitmapRegionDecoderMethods, NELEM(gBitmapRegionDecoderMethods));
 }
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 9f832b0..036ece1 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -1,5 +1,5 @@
 #include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "SkCamera.h"
 
@@ -96,7 +96,7 @@
 }
 
 static void Camera_applyToCanvas(JNIEnv* env, jobject obj, jlong canvasHandle) {
-    SkCanvas* canvas = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas();
+    SkCanvas* canvas = reinterpret_cast<android::Canvas*>(canvasHandle)->asSkCanvas();
     jlong viewHandle = env->GetLongField(obj, gNativeInstanceFieldID);
     Sk3DView* v = reinterpret_cast<Sk3DView*>(viewHandle);
     v->applyToCanvas(canvas);
@@ -137,16 +137,8 @@
 };
 
 int register_android_graphics_Camera(JNIEnv* env) {
-    jclass clazz = env->FindClass("android/graphics/Camera");
-    if (clazz == 0) {
-        return -1;
-    }
-    gNativeInstanceFieldID = env->GetFieldID(clazz, "native_instance", "J");
-    if (gNativeInstanceFieldID == 0) {
-        return -1;
-    }
-    return android::AndroidRuntime::registerNativeMethods(env,
-                                               "android/graphics/Camera",
-                                               gCameraMethods,
-                                               SK_ARRAY_COUNT(gCameraMethods));
+    jclass clazz = android::FindClassOrDie(env, "android/graphics/Camera");
+    gNativeInstanceFieldID = android::GetFieldIDOrDie(env, clazz, "native_instance", "J");
+    return android::RegisterMethodsOrDie(env, "android/graphics/Camera", gCameraMethods,
+                                         NELEM(gCameraMethods));
 }
diff --git a/core/jni/android/graphics/Canvas.h b/core/jni/android/graphics/Canvas.h
deleted file mode 100644
index 2577a90..0000000
--- a/core/jni/android/graphics/Canvas.h
+++ /dev/null
@@ -1,19 +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.
- */
-
-// This header is shared with other libraries and as such is located in a
-// separate directory.
-#include <private/graphics/Canvas.h>
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index e63c5fa..deb4971 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -17,7 +17,7 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include "Paint.h"
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 
 #include <utils/RefBase.h>
 #include <CanvasProperty.h>
@@ -26,8 +26,6 @@
 
 using namespace uirenderer;
 
-#ifdef USE_OPENGL_RENDERER
-
 static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) {
     return reinterpret_cast<jlong>(new CanvasPropertyPrimitive(initialValue));
 }
@@ -37,23 +35,18 @@
     return reinterpret_cast<jlong>(new CanvasPropertyPaint(*paint));
 }
 
-#endif
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/graphics/CanvasProperty";
-
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
     { "nCreateFloat", "(F)J", (void*) createFloat },
     { "nCreatePaint", "(J)J", (void*) createPaint },
-#endif
 };
 
 int register_android_graphics_CanvasProperty(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/CanvasProperty", gMethods,
+                                NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index c66c844..d03bcf0 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -17,11 +17,11 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "SkColorFilter.h"
 #include "SkColorMatrixFilter.h"
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
 
 #include <Caches.h>
 
@@ -36,10 +36,9 @@
         if (filter) SkSafeUnref(filter);
     }
 
-    static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
-            jint modeHandle) {
-        SkPorterDuff::Mode mode = (SkPorterDuff::Mode) modeHandle;
-        return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode)));
+    static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(SkColorFilter::CreateModeFilter(srcColor, mode));
     }
 
     static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
@@ -74,18 +73,15 @@
     { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
 };
 
-#define REG(env, name, array) \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
-                                                    SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
 int register_android_graphics_ColorFilter(JNIEnv* env) {
-    int result;
-    
-    REG(env, "android/graphics/ColorFilter", colorfilter_methods);
-    REG(env, "android/graphics/PorterDuffColorFilter", porterduff_methods);
-    REG(env, "android/graphics/LightingColorFilter", lighting_methods);
-    REG(env, "android/graphics/ColorMatrixColorFilter", colormatrix_methods);
+    android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods,
+                                  NELEM(colorfilter_methods));
+    android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", porterduff_methods,
+                                  NELEM(porterduff_methods));
+    android::RegisterMethodsOrDie(env, "android/graphics/LightingColorFilter", lighting_methods,
+                                  NELEM(lighting_methods));
+    android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter",
+                                  colormatrix_methods, NELEM(colormatrix_methods));
     
     return 0;
 }
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index a67740c..26523f8 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -24,7 +24,6 @@
     }
 
     virtual size_t read(void* buffer, size_t size) {
-        JNIEnv* env = fEnv;
         if (NULL == buffer) {
             if (0 == size) {
                 return 0;
@@ -165,7 +164,7 @@
 
 SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
                                         jbyteArray storage) {
-    SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
+    SkAutoTDelete<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
     if (NULL == adaptor.get()) {
         return NULL;
     }
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index ecd270f..56cba51 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -1,5 +1,5 @@
-#ifndef CreateJavaOutputStream_DEFINED
-#define CreateJavaOutputStream_DEFINED
+#ifndef _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
+#define _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
 
 //#include <android_runtime/AndroidRuntime.h>
 #include "jni.h"
@@ -38,4 +38,5 @@
 
 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
                                          jbyteArray storage);
-#endif
+
+#endif  // _ANDROID_GRAPHICS_CREATE_JAVA_OUTPUT_STREAM_ADAPTOR_H_
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index 3275875..bac124f 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -24,6 +24,8 @@
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
 
+#include "core_jni_helpers.h"
+
 #include "SkDrawFilter.h"
 #include "SkPaintFlagsDrawFilter.h"
 #include "SkPaint.h"
@@ -103,16 +105,11 @@
     {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF}
 };
 
-#define REG(env, name, array)                                                                       \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
-
 int register_android_graphics_DrawFilter(JNIEnv* env) {
-    int result;
-    
-    REG(env, "android/graphics/DrawFilter", drawfilter_methods);
-    REG(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods);
+    int result = RegisterMethodsOrDie(env, "android/graphics/DrawFilter", drawfilter_methods,
+                                      NELEM(drawfilter_methods));
+    result |= RegisterMethodsOrDie(env, "android/graphics/PaintFlagsDrawFilter", paintflags_methods,
+                                   NELEM(paintflags_methods));
     
     return 0;
 }
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index bfb30b7..d28669a 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -17,8 +17,10 @@
 #define LOG_TAG "Minikin"
 
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 
+#include "SkData.h"
+#include "SkRefCnt.h"
 #include "SkTypeface.h"
 #include "GraphicsJNI.h"
 #include <ScopedPrimitiveArray.h>
@@ -82,6 +84,10 @@
     return true;
 }
 
+static void releaseAsset(const void* ptr, size_t length, void* context) {
+    delete static_cast<Asset*>(context);
+}
+
 static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr,
         jobject jassetMgr, jstring jpath) {
     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
@@ -98,12 +104,16 @@
         return false;
     }
 
-    SkStream* stream = new AssetStreamAdaptor(asset,
-                                              AssetStreamAdaptor::kYes_OwnAsset,
-                                              AssetStreamAdaptor::kYes_HasMemoryBase);
+    const void* buf = asset->getBuffer(false);
+    if (NULL == buf) {
+        delete asset;
+        return false;
+    }
+
+    SkAutoTUnref<SkData> data(SkData::NewWithProc(buf, asset->getLength(), releaseAsset, asset));
+    SkMemoryStream* stream = new SkMemoryStream(data);
+    // CreateFromStream takes ownership of stream.
     SkTypeface* face = SkTypeface::CreateFromStream(stream);
-    // Note: SkTypeface::CreateFromStream holds its own reference to the stream
-    stream->unref();
     if (face == NULL) {
         ALOGE("addFontFromAsset failed to create font %s", str.c_str());
         return false;
@@ -125,9 +135,8 @@
 
 int register_android_graphics_FontFamily(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env,
-        "android/graphics/FontFamily",
-        gFontFamilyMethods, NELEM(gFontFamilyMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
+                                NELEM(gFontFamilyMethods));
 }
 
 }
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index a51af40..0747969 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -8,10 +8,12 @@
 #include "SkCanvas.h"
 #include "SkDevice.h"
 #include "SkMath.h"
-#include "SkPicture.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
 
+#include <Caches.h>
+#include <TextureCache.h>
+
 void doThrowNPE(JNIEnv* env) {
     jniThrowNullPointerException(env, NULL);
 }
@@ -152,7 +154,7 @@
 static jfieldID gPointF_yFieldID;
 
 static jclass   gBitmap_class;
-static jfieldID gBitmap_nativeInstanceID;
+static jfieldID gBitmap_skBitmapPtr;
 static jmethodID gBitmap_constructorMethodID;
 static jmethodID gBitmap_reinitMethodID;
 static jmethodID gBitmap_getAllocationByteCountMethodID;
@@ -166,10 +168,6 @@
 static jclass   gCanvas_class;
 static jfieldID gCanvas_nativeInstanceID;
 
-static jclass   gPaint_class;
-static jfieldID gPaint_nativeInstanceID;
-static jfieldID gPaint_nativeTypefaceID;
-
 static jclass   gPicture_class;
 static jfieldID gPicture_nativeInstanceID;
 
@@ -340,11 +338,11 @@
     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
 }
 
-SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
+SkBitmap* GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap) {
     SkASSERT(env);
     SkASSERT(bitmap);
     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
-    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativeInstanceID);
+    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_skBitmapPtr);
     SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkASSERT(b);
     return b;
@@ -368,30 +366,11 @@
     if (!canvasHandle) {
         return NULL;
     }
-    SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas();
+    SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->asSkCanvas();
     SkASSERT(c);
     return c;
 }
 
-android::Paint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
-    SkASSERT(env);
-    SkASSERT(paint);
-    SkASSERT(env->IsInstanceOf(paint, gPaint_class));
-    jlong paintHandle = env->GetLongField(paint, gPaint_nativeInstanceID);
-    android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
-    SkASSERT(p);
-    return p;
-}
-
-android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint) {
-    SkASSERT(env);
-    SkASSERT(paint);
-    SkASSERT(env->IsInstanceOf(paint, gPaint_class));
-    jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
-    android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
-    return p;
-}
-
 SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
 {
     SkASSERT(env);
@@ -524,10 +503,25 @@
         JNIEnv* env = vm2env(fVM);
         env->DeleteGlobalRef(fStorageObj);
     }
+
+    if (android::uirenderer::Caches::hasInstance()) {
+        android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
+static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) {
+    int32_t rowBytes32 = SkToS32(bitmap.rowBytes());
+    int64_t bigSize = (int64_t)bitmap.height() * rowBytes32;
+    if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
+        return false; // allocation will be too large
+    }
+
+    *size = sk_64_asS32(bigSize);
+    return true;
+}
+
 jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                              SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
@@ -536,7 +530,15 @@
         return NULL;
     }
 
-    const size_t size = bitmap->getSize();
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
+        return NULL;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
     jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
                                                              gVMRuntime_newNonMovableArray,
                                                              gByte_class, size);
@@ -549,8 +551,7 @@
         return NULL;
     }
     SkASSERT(addr);
-    SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr,
-            bitmap->rowBytes(), arrayObj, ctable);
+    SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr, rowBytes, arrayObj, ctable);
     bitmap->setPixelRef(pr)->unref();
     // since we're already allocated, we lockPixels right away
     // HeapAllocator behaves this way too
@@ -559,6 +560,60 @@
     return arrayObj;
 }
 
+struct AndroidPixelRefContext {
+    int32_t stableID;
+};
+
+static void allocatePixelsReleaseProc(void* ptr, void* ctx) {
+    AndroidPixelRefContext* context = (AndroidPixelRefContext*)ctx;
+    if (android::uirenderer::Caches::hasInstance()) {
+         android::uirenderer::Caches::getInstance().textureCache.releaseTexture(context->stableID);
+    }
+
+    sk_free(ptr);
+    delete context;
+}
+
+bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) {
+    const SkImageInfo& info = bitmap->info();
+    if (info.fColorType == kUnknown_SkColorType) {
+        doThrowIAE(env, "unknown bitmap configuration");
+        return NULL;
+    }
+
+    size_t size;
+    if (!computeAllocationSize(*bitmap, &size)) {
+        return false;
+    }
+
+    // we must respect the rowBytes value already set on the bitmap instead of
+    // attempting to compute our own.
+    const size_t rowBytes = bitmap->rowBytes();
+
+    void* addr = sk_malloc_flags(size, 0);
+    if (NULL == addr) {
+        return false;
+    }
+
+    AndroidPixelRefContext* context = new AndroidPixelRefContext;
+    SkMallocPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rowBytes, ctable, addr,
+                                                         &allocatePixelsReleaseProc, context);
+    if (!pr) {
+        delete context;
+        return false;
+    }
+
+    // set the stableID in the context so that it can be used later in
+    // allocatePixelsReleaseProc to remove the texture from the cache.
+    context->stableID = pr->getStableID();
+
+    bitmap->setPixelRef(pr)->unref();
+    // since we're already allocated, we can lockPixels right away
+    bitmap->lockPixels();
+
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env)
@@ -621,7 +676,7 @@
     gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
 
     gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
-    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "J");
+    gBitmap_skBitmapPtr = getFieldIDCheck(env, gBitmap_class, "mSkBitmapPtr", "J");
     gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
     gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
     gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
@@ -635,10 +690,6 @@
     gCanvas_class = make_globalref(env, "android/graphics/Canvas");
     gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J");
 
-    gPaint_class = make_globalref(env, "android/graphics/Paint");
-    gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "J");
-    gPaint_nativeTypefaceID = getFieldIDCheck(env, gPaint_class, "mNativeTypeface", "J");
-
     gPicture_class = make_globalref(env, "android/graphics/Picture");
     gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J");
 
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 42973ba..422d3f1 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -1,5 +1,5 @@
-#ifndef GraphicsJNI_DEFINED
-#define GraphicsJNI_DEFINED
+#ifndef _ANDROID_GRAPHICS_GRAPHICS_JNI_H_
+#define _ANDROID_GRAPHICS_GRAPHICS_JNI_H_
 
 #include "SkBitmap.h"
 #include "SkDevice.h"
@@ -15,7 +15,7 @@
 
 namespace android {
 class Paint;
-class TypefaceImpl;
+struct TypefaceImpl;
 }
 
 class GraphicsJNI {
@@ -48,9 +48,7 @@
     static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
 
     static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
-    static android::Paint*  getNativePaint(JNIEnv*, jobject paint);
-    static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
-    static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
+    static SkBitmap* getSkBitmap(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     // Given the 'native' long held by the Rasterizer.java object, return a
@@ -97,6 +95,14 @@
     static jbyteArray allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
             SkColorTable* ctable);
 
+    /**
+     * Given a bitmap we natively allocate a memory block to store the contents
+     * of that bitmap.  The memory is then attached to the bitmap via an
+     * SkPixelRef, which ensures that upon deletion the appropriate caches
+     * are notified.
+     */
+    static bool allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable);
+
     /** Copy the colors in colors[] to the bitmap, convert to the correct
         format along the way.
         Whether to use premultiplied pixels is determined by dstBitmap's alphaType.
@@ -160,7 +166,6 @@
 
 private:
     JavaVM* fVM;
-    bool fAllocateInJavaHeap;
     jbyteArray fStorageObj;
     int fAllocCount;
 };
@@ -248,4 +253,4 @@
 #define NPE_CHECK_RETURN_VOID(env, object)    \
     do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0)
 
-#endif
+#endif  // _ANDROID_GRAPHICS_GRAPHICS_JNI_H_
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index a75efcf..e537942 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -33,17 +33,19 @@
 #include "HarfBuzzNGFaceSkia.h"
 
 #include <cutils/log.h>
-#include <SkFontHost.h>
 #include <SkPaint.h>
 #include <SkPath.h>
 #include <SkPoint.h>
 #include <SkRect.h>
+#include <SkTypeface.h>
 #include <SkUtils.h>
 
 #include <hb.h>
 
 namespace android {
 
+static const bool kDebugGlyphs = false;
+
 // Our implementation of the callbacks which Harfbuzz requires by using Skia
 // calls. See the Harfbuzz source for references about what these callbacks do.
 
@@ -62,9 +64,9 @@
     uint16_t glyph = codepoint;
 
     paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds);
-#if DEBUG_GLYPHS
-    ALOGD("returned glyph for %i: width = %f", codepoint, skWidth);
-#endif
+    if (kDebugGlyphs) {
+        ALOGD("returned glyph for %i: width = %f", codepoint, skWidth);
+    }
     if (width)
         *width = SkScalarToHBFixed(skWidth);
     if (extents) {
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
index 7b71ecc..3308d5d 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
@@ -24,8 +24,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef HarfBuzzNGFaceSkia_h
-#define HarfBuzzNGFaceSkia_h
+#ifndef _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
+#define _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
 
 #include <SkScalar.h>
 #include <SkPaint.h>
@@ -56,4 +56,4 @@
 
 }  // namespace android
 
-#endif
+#endif  // _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index 455f867..f7f3511 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -1,5 +1,5 @@
 #include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "GraphicsJNI.h"
 #include "SkInterpolator.h"
@@ -83,8 +83,6 @@
 
 int register_android_graphics_Interpolator(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env,
-                                                       "android/graphics/Interpolator",
-                                                       gInterpolatorMethods,
-                                                       SK_ARRAY_COUNT(gInterpolatorMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/Interpolator",
+                                         gInterpolatorMethods, NELEM(gInterpolatorMethods));
 }
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index b394905..d658643 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -4,6 +4,8 @@
 #include "SkBlurMaskFilter.h"
 #include "SkTableMaskFilter.h"
 
+#include "core_jni_helpers.h"
+
 #include <jni.h>
 
 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
@@ -77,20 +79,16 @@
     { "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable    }
 };
 
-#include <android_runtime/AndroidRuntime.h>
-
-#define REG(env, name, array)                                                                       \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
 int register_android_graphics_MaskFilter(JNIEnv* env)
 {
-    int result;
-
-    REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
-    REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
-    REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
-    REG(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods);
+    android::RegisterMethodsOrDie(env, "android/graphics/MaskFilter", gMaskFilterMethods,
+                                  NELEM(gMaskFilterMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods,
+                                  NELEM(gBlurMaskFilterMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/EmbossMaskFilter",
+                                  gEmbossMaskFilterMethods, NELEM(gEmbossMaskFilterMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods,
+                                  NELEM(gTableMaskFilterMethods));
 
     return 0;
 }
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 01ab699..0ff7c78 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -17,7 +17,7 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 
 #include "SkMatrix.h"
 #include "SkTemplates.h"
@@ -354,11 +354,10 @@
 static jfieldID sNativeInstanceField;
 
 int register_android_graphics_Matrix(JNIEnv* env) {
-    int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Matrix", methods,
-        sizeof(methods) / sizeof(methods[0]));
+    int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods));
 
-    jclass clazz = env->FindClass("android/graphics/Matrix");
-    sNativeInstanceField = env->GetFieldID(clazz, "native_instance", "J");
+    jclass clazz = FindClassOrDie(env, "android/graphics/Matrix");
+    sNativeInstanceField = GetFieldIDOrDie(env, clazz, "native_instance", "J");
 
     return result;
 }
diff --git a/core/jni/android/graphics/Matrix.h b/core/jni/android/graphics/Matrix.h
index 31edf88..11c9e72 100644
--- a/core/jni/android/graphics/Matrix.h
+++ b/core/jni/android/graphics/Matrix.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _ANDROID_GRAPHICS_MATRIX_H
-#define _ANDROID_GRAPHICS_MATRIX_H
+#ifndef _ANDROID_GRAPHICS_MATRIX_H_
+#define _ANDROID_GRAPHICS_MATRIX_H_
 
 #include "jni.h"
 #include "SkMatrix.h"
@@ -27,4 +27,4 @@
 
 } // namespace android
 
-#endif // _ANDROID_GRAPHICS_MATRIX_H
+#endif // _ANDROID_GRAPHICS_MATRIX_H_
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
index 255617e..a06428d 100644
--- a/core/jni/android/graphics/MinikinSkia.h
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MINIKIN_SKIA_H
-#define ANDROID_MINIKIN_SKIA_H
+#ifndef _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
+#define _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
 
 #include <minikin/MinikinFont.h>
 
@@ -54,4 +54,4 @@
 
 }  // namespace android
 
-#endif  // ANDROID_MINIKIN_SKIA_H
\ No newline at end of file
+#endif  // _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
\ No newline at end of file
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index f64ad7d..8139c24 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -26,18 +26,6 @@
 
 namespace android {
 
-// Do an sprintf starting at offset n, abort on overflow
-static int snprintfcat(char* buf, int off, int size, const char* format, ...)
-        __attribute__((__format__(__printf__, 4, 5)));
-static int snprintfcat(char* buf, int off, int size, const char* format, ...) {
-    va_list args;
-    va_start(args, format);
-    int n = vsnprintf(buf + off, size - off, format, args);
-    LOG_ALWAYS_FATAL_IF(n >= size - off, "String overflow in setting layout properties");
-    va_end(args);
-    return off + n;
-}
-
 void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
         const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
     TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
@@ -59,6 +47,7 @@
     minikinPaint.letterSpacing = paint->getLetterSpacing();
     minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
     minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
+    minikinPaint.hyphenEdit = HyphenEdit(paint->getHyphenEdit());
 
     layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
 }
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 3646c1a..236f1fd 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -21,8 +21,8 @@
 
  // TODO: does this really need to be separate from MinikinSkia?
 
-#ifndef ANDROID_MINIKIN_UTILS_H
-#define ANDROID_MINIKIN_UTILS_H
+#ifndef _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
+#define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
 
 #include <minikin/Layout.h>
 #include "Paint.h"
@@ -81,4 +81,4 @@
 
 }  // namespace android
 
-#endif  // ANDROID_MINIKIN_UTILS_H
+#endif  // _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 226f83e..5c7acf8 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,3 +1,4 @@
+#include "Canvas.h"
 #include "ScopedLocalRef.h"
 #include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
@@ -13,11 +14,7 @@
 #include <androidfw/ResourceTypes.h>
 #include <netinet/in.h>
 
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
+#include "core_jni_helpers.h"
 
 static jclass       gMovie_class;
 static jmethodID    gMovie_constructorMethodID;
@@ -67,16 +64,19 @@
     return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
 }
 
-static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
-                       jfloat fx, jfloat fy, jobject jpaint) {
+static void movie_draw(JNIEnv* env, jobject movie, jlong canvasHandle,
+                       jfloat fx, jfloat fy, jlong paintHandle) {
     NPE_CHECK_RETURN_VOID(env, movie);
-    NPE_CHECK_RETURN_VOID(env, canvas);
-    // its OK for paint to be null
+
+    android::Canvas* c = reinterpret_cast<android::Canvas*>(canvasHandle);
+    const android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
+
+    // Canvas should never be NULL. However paint is an optional parameter and
+    // therefore may be NULL.
+    SkASSERT(c != NULL);
 
     SkMovie* m = J2Movie(env, movie);
-    SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
     const SkBitmap& b = m->bitmap();
-    const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;
 
     c->drawBitmap(b, fx, fy, p);
 }
@@ -84,9 +84,7 @@
 static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
     android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
     if (asset == NULL) return NULL;
-    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset,
-            android::AssetStreamAdaptor::kNo_OwnAsset,
-            android::AssetStreamAdaptor::kNo_HasMemoryBase));
+    SkAutoTDelete<SkStreamRewindable> stream(new android::AssetStreamAdaptor(asset));
     SkMovie* moov = SkMovie::DecodeStream(stream.get());
     return create_jmovie(env, moov);
 }
@@ -106,11 +104,11 @@
     // trying to determine the stream's format. The only decoder for movies is GIF, which
     // will only read 6.
     // FIXME: Get this number from SkImageDecoder
-    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    // bufferedStream takes ownership of strm
+    SkAutoTDelete<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
     SkASSERT(bufferedStream.get() != NULL);
 
     SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
-    strm->unref();
     return create_jmovie(env, moov);
 }
 
@@ -138,15 +136,13 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gMethods[] = {
     {   "width",    "()I",  (void*)movie_width  },
     {   "height",   "()I",  (void*)movie_height  },
     {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
     {   "duration", "()I",  (void*)movie_duration  },
     {   "setTime",  "(I)Z", (void*)movie_setTime  },
-    {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
+    {   "nDraw",    "(JFFJ)V",
                             (void*)movie_draw  },
     { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
                             (void*)movie_decodeAsset },
@@ -157,22 +153,14 @@
                             (void*)movie_decodeByteArray },
 };
 
-#define kClassPathName  "android/graphics/Movie"
-
-#define RETURN_ERR_IF_NULL(value)   do { if (!(value)) { assert(0); return -1; } } while (false)
-
 int register_android_graphics_Movie(JNIEnv* env)
 {
-    gMovie_class = env->FindClass(kClassPathName);
-    RETURN_ERR_IF_NULL(gMovie_class);
-    gMovie_class = (jclass)env->NewGlobalRef(gMovie_class);
+    gMovie_class = android::FindClassOrDie(env, "android/graphics/Movie");
+    gMovie_class = android::MakeGlobalRefOrDie(env, gMovie_class);
 
-    gMovie_constructorMethodID = env->GetMethodID(gMovie_class, "<init>", "(J)V");
-    RETURN_ERR_IF_NULL(gMovie_constructorMethodID);
+    gMovie_constructorMethodID = android::GetMethodIDOrDie(env, gMovie_class, "<init>", "(J)V");
 
-    gMovie_nativeInstanceID = env->GetFieldID(gMovie_class, "mNativeMovie", "J");
-    RETURN_ERR_IF_NULL(gMovie_nativeInstanceID);
+    gMovie_nativeInstanceID = android::GetFieldIDOrDie(env, gMovie_class, "mNativeMovie", "J");
 
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-                                                       gMethods, SK_ARRAY_COUNT(gMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/Movie", gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index be62fdd..3f8bfe2 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -30,6 +30,7 @@
 #include "GraphicsJNI.h"
 
 #include "JNIHelp.h"
+#include "core_jni_helpers.h"
 
 extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
         const android::Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);
@@ -79,14 +80,12 @@
 
     static void finalize(JNIEnv* env, jobject, jlong patchHandle) {
         int8_t* patch = reinterpret_cast<int8_t*>(patchHandle);
-#ifdef USE_OPENGL_RENDERER
         if (android::uirenderer::ResourceCache::hasInstance()) {
             Res_png_9patch* p = (Res_png_9patch*) patch;
             android::uirenderer::ResourceCache::getInstance().destructor(p);
-            return;
+        } else {
+            delete[] patch;
         }
-#endif // USE_OPENGL_RENDERER
-        delete[] patch;
     }
 
     static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, const SkBitmap* bitmap,
@@ -121,7 +120,7 @@
     static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF,
             jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
-        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas();
+        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
         const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
@@ -140,7 +139,7 @@
     static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect,
             jlong bitmapHandle, jlong chunkHandle, jlong paintHandle,
             jint destDensity, jint srcDensity) {
-        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->getSkCanvas();
+        SkCanvas* canvas       = reinterpret_cast<Canvas*>(canvasHandle)->asSkCanvas();
         const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
         Res_png_9patch* chunk  = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         const Paint* paint     = reinterpret_cast<Paint*>(paintHandle);
@@ -176,8 +175,6 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gNinePatchMethods[] = {
     { "isNinePatchChunk", "([B)Z",                        (void*) SkNinePatchGlue::isNinePatchChunk },
     { "validateNinePatchChunk", "(J[B)J",                 (void*) SkNinePatchGlue::validateNinePatchChunk },
@@ -189,6 +186,6 @@
 };
 
 int register_android_graphics_NinePatch(JNIEnv* env) {
-    return android::AndroidRuntime::registerNativeMethods(env,
-            "android/graphics/NinePatch", gNinePatchMethods, SK_ARRAY_COUNT(gNinePatchMethods));
+    return android::RegisterMethodsOrDie(env,
+            "android/graphics/NinePatch", gNinePatchMethods, NELEM(gNinePatchMethods));
 }
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index c162c48..26ce967 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -23,20 +23,16 @@
 
 #include "SkBitmap.h"
 #include "SkCanvas.h"
+#include "SkColorPriv.h"
 #include "SkNinePatch.h"
 #include "SkPaint.h"
 #include "SkUnPreMultiply.h"
 
-#define USE_TRACE
-
-#ifdef USE_TRACE
-    static bool gTrace;
-#endif
-
-#include "SkColorPriv.h"
-
 #include <utils/Log.h>
 
+static const bool kUseTrace = true;
+static bool gTrace = false;
+
 static bool getColor(const SkBitmap& bitmap, int x, int y, SkColor* c) {
     switch (bitmap.colorType()) {
         case kN32_SkColorType:
@@ -120,7 +116,7 @@
     const int32_t* yDivs = chunk.getYDivs();
     // if our SkCanvas were back by GL we should enable this and draw this as
     // a mesh, which will be faster in most cases.
-    if (false) {
+    if ((false)) {
         SkNinePatch::DrawMesh(canvas, bounds, bitmap,
                               xDivs, chunk.numXDivs,
                               yDivs, chunk.numYDivs,
@@ -128,37 +124,34 @@
         return;
     }
 
-#ifdef USE_TRACE
-    gTrace = true;
-#endif
+    if (kUseTrace) {
+        gTrace = true;
+    }
 
     SkASSERT(canvas || outRegion);
 
-#ifdef USE_TRACE
-    if (canvas) {
-        const SkMatrix& m = canvas->getTotalMatrix();
-        ALOGV("ninepatch [%g %g %g] [%g %g %g]\n",
-                 SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
-                 SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
-    }
-#endif
+    if (kUseTrace) {
+        if (canvas) {
+            const SkMatrix& m = canvas->getTotalMatrix();
+            ALOGV("ninepatch [%g %g %g] [%g %g %g]\n",
+                    SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
+                    SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
+        }
 
-#ifdef USE_TRACE
-    if (gTrace) {
-        ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()));
+        ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()),
+                SkScalarToFloat(bounds.height()));
         ALOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
         ALOGV("======== ninepatch xDivs [%d,%d]\n", xDivs[0], xDivs[1]);
         ALOGV("======== ninepatch yDivs [%d,%d]\n", yDivs[0], yDivs[1]);
     }
-#endif
 
     if (bounds.isEmpty() ||
         bitmap.width() == 0 || bitmap.height() == 0 ||
         (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
     {
-#ifdef USE_TRACE
-        if (gTrace) ALOGV("======== abort ninepatch draw\n");
-#endif
+        if (kUseTrace) {
+            ALOGV("======== abort ninepatch draw\n");
+        }
         return;
     }
     
@@ -202,18 +195,18 @@
     }
     int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
 
-#ifdef USE_TRACE
-    ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
-             bitmap.width(), bitmap.height(),
-             SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
-             SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
-             numXDivs, numYDivs);
-#endif
+    if (kUseTrace) {
+        ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
+                bitmap.width(), bitmap.height(),
+                SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+                SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
+                numXDivs, numYDivs);
+    }
 
     src.fTop = 0;
     dst.fTop = bounds.fTop;
     // The first row always starts with the top being at y=0 and the bottom
-    // being either yDivs[1] (if yDivs[0]=0) of yDivs[0].  In the former case
+    // being either yDivs[1] (if yDivs[0]=0) or yDivs[0].  In the former case
     // the first row is stretchable along the Y axis, otherwise it is fixed.
     // The last row always ends with the bottom being bitmap.height and the top
     // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
@@ -307,15 +300,15 @@
                 goto nextDiv;
             }
             if (canvas) {
-#ifdef USE_TRACE
-                ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
-                         src.fLeft, src.fTop, src.width(), src.height(),
-                         SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
-                         SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
-                if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
-                    ALOGV("--- skip patch\n");
+                if (kUseTrace) {
+                    ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
+                            src.fLeft, src.fTop, src.width(), src.height(),
+                            SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
+                            SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
+                    if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
+                        ALOGV("--- skip patch\n");
+                    }
                 }
-#endif
                 drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
                                   color, hasXfer);
             }
diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp
index d99ddeb..6c32a21 100644
--- a/core/jni/android/graphics/NinePatchPeeker.cpp
+++ b/core/jni/android/graphics/NinePatchPeeker.cpp
@@ -39,14 +39,7 @@
         // now update our host to force index or 32bit config
         // 'cause we don't want 565 predithered, since as a 9patch, we know
         // we will be stretched, and therefore we want to dither afterwards.
-        SkImageDecoder::PrefConfigTable table;
-        table.fPrefFor_8Index_NoAlpha_src   = SkBitmap::kIndex8_Config;
-        table.fPrefFor_8Index_YesAlpha_src  = SkBitmap::kIndex8_Config;
-        table.fPrefFor_8Gray_src            = SkBitmap::kARGB_8888_Config;
-        table.fPrefFor_8bpc_NoAlpha_src     = SkBitmap::kARGB_8888_Config;
-        table.fPrefFor_8bpc_YesAlpha_src    = SkBitmap::kARGB_8888_Config;
-
-        mHost->setPrefConfigTable(table);
+        mHost->setPreserveSrcDepth(true);
     } else if (!strcmp("npLb", tag) && length == sizeof(int32_t) * 4) {
         mHasInsets = true;
         memcpy(&mOpticalInsets, data, sizeof(int32_t) * 4);
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h
index 7c18b2d..2d49b38 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/core/jni/android/graphics/NinePatchPeeker.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef NinePatchPeeker_h
-#define NinePatchPeeker_h
+#ifndef _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_
+#define _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_
 
 #include "SkImageDecoder.h"
 #include <androidfw/ResourceTypes.h>
@@ -53,4 +53,4 @@
     uint8_t mOutlineAlpha;
 };
 
-#endif // NinePatchPeeker_h
+#endif  // _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 6b02326..a92a9ac 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -21,7 +21,7 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <ScopedUtfChars.h>
 
 #include "SkBlurDrawLooper.h"
@@ -61,6 +61,10 @@
 static jclass   gFontMetricsInt_class;
 static JMetricsID gFontMetricsInt_fieldID;
 
+static jclass   gPaint_class;
+static jfieldID gPaint_nativeInstanceID;
+static jfieldID gPaint_nativeTypefaceID;
+
 static void defaultSettingsForAndroid(Paint* paint) {
     // GlyphID encoding is required because we are using Harfbuzz shaping
     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
@@ -72,6 +76,25 @@
         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
     };
 
+    static Paint* getNativePaint(JNIEnv* env, jobject paint) {
+        SkASSERT(env);
+        SkASSERT(paint);
+        SkASSERT(env->IsInstanceOf(paint, gPaint_class));
+        jlong paintHandle = env->GetLongField(paint, gPaint_nativeInstanceID);
+        android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
+        SkASSERT(p);
+        return p;
+    }
+
+    static TypefaceImpl* getNativeTypeface(JNIEnv* env, jobject paint) {
+        SkASSERT(env);
+        SkASSERT(paint);
+        SkASSERT(env->IsInstanceOf(paint, gPaint_class));
+        jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
+        android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
+        return p;
+    }
+
     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         delete obj;
@@ -106,7 +129,7 @@
 
     static jint getFlags(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
+        Paint* nativePaint = getNativePaint(env, paint);
         uint32_t result = nativePaint->getFlags();
         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
         if (nativePaint->getFilterLevel() != Paint::kNone_FilterLevel) {
@@ -117,7 +140,7 @@
 
     static void setFlags(JNIEnv* env, jobject paint, jint flags) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        Paint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
+        Paint* nativePaint = getNativePaint(env, paint);
         // Instead of modifying 0x02, change the filter level.
         nativePaint->setFilterLevel(flags & sFilterBitmapFlag
                 ? Paint::kLow_FilterLevel
@@ -132,55 +155,55 @@
 
     static jint getHinting(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return GraphicsJNI::getNativePaint(env, paint)->getHinting()
+        return getNativePaint(env, paint)->getHinting()
                 == Paint::kNo_Hinting ? 0 : 1;
     }
 
     static void setHinting(JNIEnv* env, jobject paint, jint mode) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setHinting(
+        getNativePaint(env, paint)->setHinting(
                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
     }
 
     static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setAntiAlias(aa);
+        getNativePaint(env, paint)->setAntiAlias(aa);
     }
 
     static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setLinearText(linearText);
+        getNativePaint(env, paint)->setLinearText(linearText);
     }
 
     static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setSubpixelText(subpixelText);
+        getNativePaint(env, paint)->setSubpixelText(subpixelText);
     }
 
     static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setUnderlineText(underlineText);
+        getNativePaint(env, paint)->setUnderlineText(underlineText);
     }
 
     static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
+        getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
     }
 
     static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
+        getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
     }
 
     static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setFilterLevel(
+        getNativePaint(env, paint)->setFilterLevel(
                 filterBitmap ? Paint::kLow_FilterLevel : Paint::kNone_FilterLevel);
     }
 
     static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setDither(dither);
+        getNativePaint(env, paint)->setDither(dither);
     }
 
     static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
@@ -197,45 +220,45 @@
     static jint getColor(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         int color;
-        color = GraphicsJNI::getNativePaint(env, paint)->getColor();
+        color = getNativePaint(env, paint)->getColor();
         return static_cast<jint>(color);
     }
 
     static jint getAlpha(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         int alpha;
-        alpha = GraphicsJNI::getNativePaint(env, paint)->getAlpha();
+        alpha = getNativePaint(env, paint)->getAlpha();
         return static_cast<jint>(alpha);
     }
 
     static void setColor(JNIEnv* env, jobject paint, jint color) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setColor(color);
+        getNativePaint(env, paint)->setColor(color);
     }
 
     static void setAlpha(JNIEnv* env, jobject paint, jint a) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setAlpha(a);
+        getNativePaint(env, paint)->setAlpha(a);
     }
 
     static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeWidth());
+        return SkScalarToFloat(getNativePaint(env, paint)->getStrokeWidth());
     }
 
     static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setStrokeWidth(width);
+        getNativePaint(env, paint)->setStrokeWidth(width);
     }
 
     static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getStrokeMiter());
+        return SkScalarToFloat(getNativePaint(env, paint)->getStrokeMiter());
     }
 
     static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setStrokeMiter(miter);
+        getNativePaint(env, paint)->setStrokeMiter(miter);
     }
 
     static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
@@ -370,44 +393,44 @@
 
     static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        Paint* obj = GraphicsJNI::getNativePaint(env, paint);
+        Paint* obj = getNativePaint(env, paint);
         return obj->getFontVariant() == VARIANT_ELEGANT;
     }
 
     static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        Paint* obj = GraphicsJNI::getNativePaint(env, paint);
+        Paint* obj = getNativePaint(env, paint);
         obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
     }
 
     static jfloat getTextSize(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSize());
+        return SkScalarToFloat(getNativePaint(env, paint)->getTextSize());
     }
 
     static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setTextSize(textSize);
+        getNativePaint(env, paint)->setTextSize(textSize);
     }
 
     static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextScaleX());
+        return SkScalarToFloat(getNativePaint(env, paint)->getTextScaleX());
     }
 
     static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setTextScaleX(scaleX);
+        getNativePaint(env, paint)->setTextScaleX(scaleX);
     }
 
     static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
         NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(GraphicsJNI::getNativePaint(env, paint)->getTextSkewX());
+        return SkScalarToFloat(getNativePaint(env, paint)->getTextSkewX());
     }
 
     static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
         NPE_CHECK_RETURN_VOID(env, paint);
-        GraphicsJNI::getNativePaint(env, paint)->setTextSkewX(skewX);
+        getNativePaint(env, paint)->setTextSkewX(skewX);
     }
 
     static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
@@ -430,14 +453,24 @@
         }
     }
 
+    static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        return paint->getHyphenEdit();
+    }
+
+    static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        paint->setHyphenEdit((uint32_t)hyphen);
+    }
+
     static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
         const int kElegantTop = 2500;
         const int kElegantBottom = -1000;
         const int kElegantAscent = 1900;
         const int kElegantDescent = -500;
         const int kElegantLeading = 0;
-        Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
-        TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+        Paint* paint = getNativePaint(env, jpaint);
+        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
         typeface = TypefaceImpl_resolveDefault(typeface);
         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
         float saveSkewX = paint->getTextSkewX();
@@ -525,12 +558,12 @@
             return 0;
         }
 
-        Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+        Paint* paint = getNativePaint(env, jpaint);
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = 0;
 
         Layout layout;
-        TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
         result = layout.getAdvance();
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
@@ -553,11 +586,11 @@
         }
 
         const jchar* textArray = env->GetStringChars(text, NULL);
-        Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+        Paint* paint = getNativePaint(env, jpaint);
         jfloat width = 0;
 
         Layout layout;
-        TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, start, count, textLength);
         width = layout.getAdvance();
 
@@ -575,11 +608,11 @@
         }
 
         const jchar* textArray = env->GetStringChars(text, NULL);
-        Paint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+        Paint* paint = getNativePaint(env, jpaint);
         jfloat width = 0;
 
         Layout layout;
-        TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
         MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
         width = layout.getAdvance();
 
@@ -818,7 +851,7 @@
 
     static int breakText(JNIEnv* env, const Paint& paint, TypefaceImpl* typeface, const jchar text[],
                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
-                         Paint::TextBufferDirection textBufferDirection) {
+                         const bool forwardScan) {
         size_t measuredCount = 0;
         float measured = 0;
 
@@ -826,7 +859,7 @@
         MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
         float* advances = new float[count];
         layout.getAdvances(advances);
-        const bool forwardScan = (textBufferDirection == Paint::kForward_TextBufferDirection);
+
         for (int i = 0; i < count; i++) {
             // traverse in the given direction
             int index = forwardScan ? i : (count - i - 1);
@@ -857,13 +890,13 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
 
-        Paint::TextBufferDirection tbd;
+        bool forwardTextDirection;
         if (count < 0) {
-            tbd = Paint::kBackward_TextBufferDirection;
+            forwardTextDirection = false;
             count = -count;
         }
         else {
-            tbd = Paint::kForward_TextBufferDirection;
+            forwardTextDirection = true;
         }
 
         if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
@@ -873,7 +906,7 @@
 
         const jchar* text = env->GetCharArrayElements(jtext, NULL);
         count = breakText(env, *paint, typeface, text + index, count, maxWidth,
-                          bidiFlags, jmeasuredWidth, tbd);
+                          bidiFlags, jmeasuredWidth, forwardTextDirection);
         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
                                       JNI_ABORT);
         return count;
@@ -886,13 +919,9 @@
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
 
-        Paint::TextBufferDirection tbd = forwards ?
-                                        Paint::kForward_TextBufferDirection :
-                                        Paint::kBackward_TextBufferDirection;
-
         int count = env->GetStringLength(jtext);
         const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
+        count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
         env->ReleaseStringChars(jtext, text);
         return count;
     }
@@ -990,6 +1019,8 @@
     {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
     {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
     {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings},
+    {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
+    {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
     {"ascent","!()F", (void*) PaintGlue::ascent},
     {"descent","!()F", (void*) PaintGlue::descent},
 
@@ -1021,35 +1052,30 @@
     {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
 };
 
-static jfieldID req_fieldID(jfieldID id) {
-    SkASSERT(id);
-    return id;
-}
-
 int register_android_graphics_Paint(JNIEnv* env) {
-    gFontMetrics_class = env->FindClass("android/graphics/Paint$FontMetrics");
-    SkASSERT(gFontMetrics_class);
-    gFontMetrics_class = (jclass)env->NewGlobalRef(gFontMetrics_class);
+    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
+    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
 
-    gFontMetrics_fieldID.top = req_fieldID(env->GetFieldID(gFontMetrics_class, "top", "F"));
-    gFontMetrics_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetrics_class, "ascent", "F"));
-    gFontMetrics_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetrics_class, "descent", "F"));
-    gFontMetrics_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetrics_class, "bottom", "F"));
-    gFontMetrics_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetrics_class, "leading", "F"));
+    gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
+    gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
+    gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
+    gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
+    gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
 
-    gFontMetricsInt_class = env->FindClass("android/graphics/Paint$FontMetricsInt");
-    SkASSERT(gFontMetricsInt_class);
-    gFontMetricsInt_class = (jclass)env->NewGlobalRef(gFontMetricsInt_class);
+    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
+    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
 
-    gFontMetricsInt_fieldID.top = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "top", "I"));
-    gFontMetricsInt_fieldID.ascent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "ascent", "I"));
-    gFontMetricsInt_fieldID.descent = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "descent", "I"));
-    gFontMetricsInt_fieldID.bottom = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "bottom", "I"));
-    gFontMetricsInt_fieldID.leading = req_fieldID(env->GetFieldID(gFontMetricsInt_class, "leading", "I"));
+    gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
+    gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
+    gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
+    gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
+    gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
 
-    int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Paint", methods,
-        sizeof(methods) / sizeof(methods[0]));
-    return result;
+    gPaint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Paint"));
+    gPaint_nativeInstanceID = GetFieldIDOrDie(env, gPaint_class, "mNativePaint", "J");
+    gPaint_nativeTypefaceID = GetFieldIDOrDie(env, gPaint_class, "mNativeTypeface", "J");
+
+    return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
 }
 
 }
diff --git a/core/jni/android/graphics/Paint.h b/core/jni/android/graphics/Paint.h
index a20bb4b..1f82836 100644
--- a/core/jni/android/graphics/Paint.h
+++ b/core/jni/android/graphics/Paint.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GRAPHICS_PAINT_H
-#define ANDROID_GRAPHICS_PAINT_H
+#ifndef ANDROID_GRAPHICS_PAINT_H_
+#define ANDROID_GRAPHICS_PAINT_H_
 
 #include <SkPaint.h>
 #include <string>
@@ -69,13 +69,22 @@
         return mFontVariant;
     }
 
+    void setHyphenEdit(uint32_t hyphen) {
+        mHyphenEdit = hyphen;
+    }
+
+    uint32_t getHyphenEdit() const {
+        return mHyphenEdit;
+    }
+
 private:
-    float mLetterSpacing;
+    float mLetterSpacing = 0;
     std::string mFontFeatureSettings;
     std::string mTextLocale;
     FontVariant mFontVariant;
+    uint32_t mHyphenEdit = 0;
 };
 
 }  // namespace android
 
-#endif // ANDROID_GRAPHICS_PAINT_H
+#endif // ANDROID_GRAPHICS_PAINT_H_
diff --git a/core/jni/android/graphics/PaintImpl.cpp b/core/jni/android/graphics/PaintImpl.cpp
index fac669b..da85018 100644
--- a/core/jni/android/graphics/PaintImpl.cpp
+++ b/core/jni/android/graphics/PaintImpl.cpp
@@ -28,7 +28,8 @@
 
 Paint::Paint(const Paint& paint) : SkPaint(paint),
         mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings),
-        mTextLocale(paint.mTextLocale), mFontVariant(paint.mFontVariant) {
+        mTextLocale(paint.mTextLocale), mFontVariant(paint.mFontVariant),
+        mHyphenEdit(paint.mHyphenEdit) {
 }
 
 Paint::~Paint() {
@@ -40,6 +41,7 @@
     mFontFeatureSettings = other.mFontFeatureSettings;
     mTextLocale = other.mTextLocale;
     mFontVariant = other.mFontVariant;
+    mHyphenEdit = other.mHyphenEdit;
     return *this;
 }
 
@@ -48,7 +50,8 @@
             && a.mLetterSpacing == b.mLetterSpacing
             && a.mFontFeatureSettings == b.mFontFeatureSettings
             && a.mTextLocale == b.mTextLocale
-            && a.mFontVariant == b.mFontVariant;
+            && a.mFontVariant == b.mFontVariant
+            && a.mHyphenEdit == b.mHyphenEdit;
 }
 
 }
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 30ce58d..f7b5dc2 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -22,12 +22,12 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "SkPath.h"
 #include "SkPathOps.h"
 
-#include <ResourceCache.h>
+#include <Caches.h>
 #include <vector>
 #include <map>
 
@@ -38,12 +38,10 @@
 
     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-#ifdef USE_OPENGL_RENDERER
-        if (android::uirenderer::ResourceCache::hasInstance()) {
-            android::uirenderer::ResourceCache::getInstance().destructor(obj);
-            return;
+        // Purge entries from the HWUI path cache if this path's data is unique
+        if (obj->unique() && android::uirenderer::Caches::hasInstance()) {
+            android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
         }
-#endif
         delete obj;
     }
 
@@ -520,9 +518,7 @@
 };
 
 int register_android_graphics_Path(JNIEnv* env) {
-    int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Path", methods,
-        sizeof(methods) / sizeof(methods[0]));
-    return result;
+    return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
 }
 
 }
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index 28d881d..9d0f0ad 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -1,6 +1,8 @@
 #include <jni.h>
 #include "GraphicsJNI.h"
 
+#include "core_jni_helpers.h"
+
 #include "SkPathEffect.h"
 #include "SkCornerPathEffect.h"
 #include "SkDashPathEffect.h"
@@ -97,24 +99,22 @@
     { "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor }
 };
 
-#include <android_runtime/AndroidRuntime.h>
-
-#define REG(env, name, array)                                              \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
-                                                  SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
 int register_android_graphics_PathEffect(JNIEnv* env)
 {
-    int result;
-
-    REG(env, "android/graphics/PathEffect", gPathEffectMethods);
-    REG(env, "android/graphics/ComposePathEffect", gComposePathEffectMethods);
-    REG(env, "android/graphics/SumPathEffect", gSumPathEffectMethods);
-    REG(env, "android/graphics/DashPathEffect", gDashPathEffectMethods);
-    REG(env, "android/graphics/PathDashPathEffect", gPathDashPathEffectMethods);
-    REG(env, "android/graphics/CornerPathEffect", gCornerPathEffectMethods);
-    REG(env, "android/graphics/DiscretePathEffect", gDiscretePathEffectMethods);
+    android::RegisterMethodsOrDie(env, "android/graphics/PathEffect", gPathEffectMethods,
+                         NELEM(gPathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/ComposePathEffect",
+                                  gComposePathEffectMethods, NELEM(gComposePathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/SumPathEffect", gSumPathEffectMethods,
+                                  NELEM(gSumPathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/DashPathEffect", gDashPathEffectMethods,
+                                  NELEM(gDashPathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/PathDashPathEffect",
+                                  gPathDashPathEffectMethods, NELEM(gPathDashPathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/CornerPathEffect",
+                                  gCornerPathEffectMethods, NELEM(gCornerPathEffectMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/DiscretePathEffect",
+                                  gDiscretePathEffectMethods, NELEM(gDiscretePathEffectMethods));
 
     return 0;
 }
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp
index 13f68a9..fec5d9d 100644
--- a/core/jni/android/graphics/PathMeasure.cpp
+++ b/core/jni/android/graphics/PathMeasure.cpp
@@ -17,7 +17,7 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 
 #include "SkPathMeasure.h"
 
@@ -156,9 +156,7 @@
 };
 
 int register_android_graphics_PathMeasure(JNIEnv* env) {
-    int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/PathMeasure", methods,
-        sizeof(methods) / sizeof(methods[0]));
-    return result;
+    return RegisterMethodsOrDie(env, "android/graphics/PathMeasure", methods, NELEM(methods));
 }
 
 }
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index 630999c..12bfaa2 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -27,9 +27,10 @@
         mHeight = src->height();
         if (NULL != src->mPicture.get()) {
             mPicture.reset(SkRef(src->mPicture.get()));
-        } if (NULL != src->mRecorder.get()) {
+        } else if (NULL != src->mRecorder.get()) {
             mPicture.reset(src->makePartialCopy());
         }
+        validate();
     } else {
         mWidth = 0;
         mHeight = 0;
@@ -42,45 +43,37 @@
     mWidth = width;
     mHeight = height;
     SkCanvas* canvas = mRecorder->beginRecording(width, height, NULL, 0);
-    // the java side will wrap this guy in a Canvas.java, which will call
-    // unref in its finalizer, so we have to ref it here, so that both that
-    // Canvas.java and our picture can both be owners
-    canvas->ref();
     return Canvas::create_canvas(canvas);
 }
 
 void Picture::endRecording() {
     if (NULL != mRecorder.get()) {
         mPicture.reset(mRecorder->endRecording());
+        validate();
         mRecorder.reset(NULL);
     }
 }
 
 int Picture::width() const {
-    if (NULL != mPicture.get()) {
-        SkASSERT(mPicture->width() == mWidth);
-        SkASSERT(mPicture->height() == mHeight);
-    }
-
+    validate();
     return mWidth;
 }
 
 int Picture::height() const {
-    if (NULL != mPicture.get()) {
-        SkASSERT(mPicture->width() == mWidth);
-        SkASSERT(mPicture->height() == mHeight);
-    }
-
+    validate();
     return mHeight;
 }
 
 Picture* Picture::CreateFromStream(SkStream* stream) {
     Picture* newPict = new Picture;
 
-    newPict->mPicture.reset(SkPicture::CreateFromStream(stream));
-    if (NULL != newPict->mPicture.get()) {
-        newPict->mWidth = newPict->mPicture->width();
-        newPict->mHeight = newPict->mPicture->height();
+    SkPicture* skPicture = SkPicture::CreateFromStream(stream);
+    if (NULL != skPicture) {
+        newPict->mPicture.reset(skPicture);
+
+        const SkIRect cullRect = skPicture->cullRect().roundOut();
+        newPict->mWidth = cullRect.width();
+        newPict->mHeight = cullRect.height();
     }
 
     return newPict;
@@ -91,10 +84,13 @@
         SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy());
         tempPict->serialize(stream);
     } else if (NULL != mPicture.get()) {
+        validate();
         mPicture->serialize(stream);
     } else {
-        SkPicture empty;
-        empty.serialize(stream);
+        SkPictureRecorder recorder;
+        recorder.beginRecording(0, 0);
+        SkAutoTUnref<SkPicture> empty(recorder.endRecording());
+        empty->serialize(stream);
     }
 }
 
@@ -103,9 +99,9 @@
         this->endRecording();
         SkASSERT(NULL != mPicture.get());
     }
+    validate();
     if (NULL != mPicture.get()) {
-        // TODO: remove this const_cast once pictures are immutable
-        const_cast<SkPicture*>(mPicture.get())->draw(canvas->getSkCanvas());
+        mPicture.get()->playback(canvas->asSkCanvas());
     }
 }
 
@@ -119,4 +115,14 @@
     return reRecorder.endRecording();
 }
 
+void Picture::validate() const {
+#ifdef SK_DEBUG
+    if (NULL != mPicture.get()) {
+        SkRect cullRect = mPicture->cullRect();
+        SkRect myRect = SkRect::MakeWH(SkIntToScalar(mWidth), SkIntToScalar(mHeight));
+        SkASSERT(cullRect == myRect);
+    }
+#endif
+}
+
 }; // namespace android
diff --git a/core/jni/android/graphics/Picture.h b/core/jni/android/graphics/Picture.h
index a2e5d4a..a9db648 100644
--- a/core/jni/android/graphics/Picture.h
+++ b/core/jni/android/graphics/Picture.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_GRAPHICS_PICTURE_H
-#define ANDROID_GRAPHICS_PICTURE_H
+#ifndef ANDROID_GRAPHICS_PICTURE_H_
+#define ANDROID_GRAPHICS_PICTURE_H_
 
 #include "SkPicture.h"
 #include "SkPictureRecorder.h"
@@ -60,7 +60,9 @@
     // 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;
+
+    void validate() const;
 };
 
 }; // namespace android
-#endif // ANDROID_GRAPHICS_PICTURE_H
+#endif // ANDROID_GRAPHICS_PICTURE_H_
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index 8a49eb5..d65864d 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -22,9 +22,9 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
-#include "SkPorterDuff.h"
+#include "SkXfermode.h"
 
 namespace android {
 
@@ -32,8 +32,28 @@
 public:
 
     static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) {
-        SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(SkPorterDuff::CreateXfermode(mode));
+        // validate that the Java enum values match our expectations
+        SK_COMPILE_ASSERT(0  == SkXfermode::kClear_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(1  == SkXfermode::kSrc_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(2  == SkXfermode::kDst_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(3  == SkXfermode::kSrcOver_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(4  == SkXfermode::kDstOver_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(5  == SkXfermode::kSrcIn_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(6  == SkXfermode::kDstIn_Mode,    xfermode_mismatch);
+        SK_COMPILE_ASSERT(7  == SkXfermode::kSrcOut_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(8  == SkXfermode::kDstOut_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(9  == SkXfermode::kSrcATop_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(10 == SkXfermode::kDstATop_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(11 == SkXfermode::kXor_Mode,      xfermode_mismatch);
+        SK_COMPILE_ASSERT(16 == SkXfermode::kDarken_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(17 == SkXfermode::kLighten_Mode,  xfermode_mismatch);
+        SK_COMPILE_ASSERT(13 == SkXfermode::kModulate_Mode, xfermode_mismatch);
+        SK_COMPILE_ASSERT(14 == SkXfermode::kScreen_Mode,   xfermode_mismatch);
+        SK_COMPILE_ASSERT(12 == SkXfermode::kPlus_Mode,     xfermode_mismatch);
+        SK_COMPILE_ASSERT(15 == SkXfermode::kOverlay_Mode,  xfermode_mismatch);
+        
+        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(SkXfermode::Create(mode));
     }
  
 };
@@ -43,10 +63,7 @@
 };
 
 int register_android_graphics_PorterDuff(JNIEnv* env) {
-    int result = AndroidRuntime::registerNativeMethods(env,
-                                "android/graphics/PorterDuffXfermode", methods,
-                                        sizeof(methods) / sizeof(methods[0]));
-    return result;
+    return RegisterMethodsOrDie(env, "android/graphics/PorterDuffXfermode", methods, NELEM(methods));
 }
 
 }
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index 2b1aca1..cfc23ac8 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -24,7 +24,7 @@
 #include "GraphicsJNI.h"
 #include "Paint.h"
 #include "SkLayerRasterizer.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 // Rasterizer.java holds a pointer (jlong) to this guy
 class NativeRasterizer {
@@ -59,7 +59,6 @@
     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
         delete reinterpret_cast<NativeRasterizer *>(objHandle);
     }
- 
 };
 
 static JNINativeMethod gRasterizerMethods[] = {
@@ -67,9 +66,8 @@
 };
 
 int register_android_graphics_Rasterizer(JNIEnv* env) {
-    int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Rasterizer", gRasterizerMethods,
-        sizeof(gRasterizerMethods) / sizeof(gRasterizerMethods[0]));
-    return result;
+    return RegisterMethodsOrDie(env, "android/graphics/Rasterizer", gRasterizerMethods,
+                                NELEM(gRasterizerMethods));
 }
 
 class SkLayerRasterizerGlue {
@@ -94,10 +92,8 @@
 
 int register_android_graphics_LayerRasterizer(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env,
-                                                       "android/graphics/LayerRasterizer",
-                                                       gLayerRasterizerMethods,
-                                                       SK_ARRAY_COUNT(gLayerRasterizerMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/LayerRasterizer",
+                                gLayerRasterizerMethods, NELEM(gLayerRasterizerMethods));
 }
 
 }
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 912968a..90a020e 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -23,7 +23,7 @@
 #include "android_util_Binder.h"
 
 #include <jni.h>
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 
 namespace android {
 
@@ -325,19 +325,13 @@
 
 int register_android_graphics_Region(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/graphics/Region");
-    SkASSERT(clazz);
+    jclass clazz = FindClassOrDie(env, "android/graphics/Region");
 
-    gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "J");
-    SkASSERT(gRegion_nativeInstanceFieldID);
+    gRegion_nativeInstanceFieldID = GetFieldIDOrDie(env, clazz, "mNativeRegion", "J");
 
-    int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
-                                                             gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
-    if (result < 0)
-        return result;
-
-    return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
-                                                       gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
+    RegisterMethodsOrDie(env, "android/graphics/Region", gRegionMethods, NELEM(gRegionMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/RegionIterator", gRegionIterMethods,
+                                NELEM(gRegionIterMethods));
 }
 
 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
diff --git a/core/jni/android/graphics/Region.h b/core/jni/android/graphics/Region.h
index c15f06e..2e8e109 100644
--- a/core/jni/android/graphics/Region.h
+++ b/core/jni/android/graphics/Region.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _ANDROID_GRAPHICS_REGION_H
-#define _ANDROID_GRAPHICS_REGION_H
+#ifndef _ANDROID_GRAPHICS_REGION_H_
+#define _ANDROID_GRAPHICS_REGION_H_
 
 #include "jni.h"
 #include "SkRegion.h"
@@ -27,4 +27,4 @@
 
 } // namespace android
 
-#endif // _ANDROID_GRAPHICS_REGION_H
+#endif // _ANDROID_GRAPHICS_REGION_H_
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index d43745f..907dd59 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_RTL_PROPERTIES_H
-#define ANDROID_RTL_PROPERTIES_H
+#ifndef _ANDROID_GRAPHICS_RTL_PROPERTIES_H_
+#define _ANDROID_GRAPHICS_RTL_PROPERTIES_H_
 
 #include <cutils/properties.h>
 #include <stdlib.h>
@@ -45,11 +45,5 @@
     return kRtlDebugDisabled;
 }
 
-// Define if we want (1) to have Advances debug values or not (0)
-#define DEBUG_ADVANCES 0
-
-// Define if we want (1) to have Glyphs debug values or not (0)
-#define DEBUG_GLYPHS 0
-
 } // namespace android
-#endif // ANDROID_RTL_PROPERTIES_H
+#endif // _ANDROID_GRAPHICS_RTL_PROPERTIES_H_
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 6146fff..6591d29 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -3,20 +3,15 @@
 
 #include "SkShader.h"
 #include "SkGradientShader.h"
-#include "SkPorterDuff.h"
 #include "SkComposeShader.h"
 #include "SkTemplates.h"
 #include "SkXfermode.h"
 
-#include <SkiaShader.h>
 #include <Caches.h>
 
-using namespace android::uirenderer;
+#include "core_jni_helpers.h"
 
-static struct {
-    jclass clazz;
-    jfieldID shader;
-} gShaderClassInfo;
+using namespace android::uirenderer;
 
 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     if (NULL == ptr) {
@@ -56,18 +51,31 @@
     SkSafeUnref(shader);
 }
 
-static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
+static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle, jlong matrixHandle)
 {
-    SkShader* shader       = reinterpret_cast<SkShader*>(shaderHandle);
+    // ensure we have a valid matrix to use
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
-    if (shader) {
-        if (matrix) {
-            shader->setLocalMatrix(*matrix);
-        } else {
-            shader->resetLocalMatrix();
-        }
-        shader->setGenerationID(shader->getGenerationID() + 1);
+    if (NULL == matrix) {
+        matrix = &SkMatrix::I();
     }
+
+    // The current shader will no longer need a direct reference owned by Shader.java
+    // as all the data needed is contained within the newly created LocalMatrixShader.
+    SkASSERT(shaderHandle);
+    SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
+
+    SkMatrix currentMatrix;
+    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
+    if (baseShader.get()) {
+        // if the matrices are same then there is no need to allocate a new
+        // shader that is identical to the existing one.
+        if (currentMatrix == *matrix) {
+            return reinterpret_cast<jlong>(currentShader.detach());
+        }
+        return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
+    }
+
+    return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -218,14 +226,13 @@
 }
 
 static jlong ComposeShader_create2(JNIEnv* env, jobject o,
-        jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle)
+        jlong shaderAHandle, jlong shaderBHandle, jint xfermodeHandle)
 {
     SkShader* shaderA = reinterpret_cast<SkShader *>(shaderAHandle);
     SkShader* shaderB = reinterpret_cast<SkShader *>(shaderBHandle);
-    SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
-    SkAutoUnref au(SkPorterDuff::CreateXfermode(porterDuffMode));
-    SkXfermode* mode = (SkXfermode*) au.get();
-    SkShader* shader = new SkComposeShader(shaderA, shaderB, mode);
+    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+    SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
+    SkShader* shader = new SkComposeShader(shaderA, shaderB, xfermode.get());
     return reinterpret_cast<jlong>(shader);
 }
 
@@ -238,7 +245,7 @@
 
 static JNINativeMethod gShaderMethods[] = {
     { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
-    { "nativeSetLocalMatrix",    "(JJ)V",   (void*)Shader_setLocalMatrix    }
+    { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
 };
 
 static JNINativeMethod gBitmapShaderMethods[] = {
@@ -265,23 +272,22 @@
     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
 };
 
-#include <android_runtime/AndroidRuntime.h>
-
-#define REG(env, name, array)                                                                       \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
 int register_android_graphics_Shader(JNIEnv* env)
 {
-    int result;
+    android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
+                                  NELEM(gColorMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
+                                  NELEM(gShaderMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
+                                  NELEM(gBitmapShaderMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/LinearGradient", gLinearGradientMethods,
+                                  NELEM(gLinearGradientMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/RadialGradient", gRadialGradientMethods,
+                                  NELEM(gRadialGradientMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/SweepGradient", gSweepGradientMethods,
+                                  NELEM(gSweepGradientMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
+                                  NELEM(gComposeShaderMethods));
 
-    REG(env, "android/graphics/Color", gColorMethods);
-    REG(env, "android/graphics/Shader", gShaderMethods);
-    REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
-    REG(env, "android/graphics/LinearGradient", gLinearGradientMethods);
-    REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
-    REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
-    REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
-
-    return result;
+    return 0;
 }
diff --git a/core/jni/android/graphics/SkiaCanvas.cpp b/core/jni/android/graphics/SkiaCanvas.cpp
deleted file mode 100644
index c7255a1..0000000
--- a/core/jni/android/graphics/SkiaCanvas.cpp
+++ /dev/null
@@ -1,711 +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.
- */
-
-#include "jni.h"
-#include "Canvas.h"
-#include "GraphicsJNI.h"
-#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"
-
-#include "MinikinUtils.h"
-
-#include "TypefaceImpl.h"
-
-#include "unicode/ubidi.h"
-#include "unicode/ushape.h"
-
-#include <utils/Log.h>
-
-namespace android {
-
-// Holds an SkCanvas reference plus additional native data.
-class SkiaCanvas : public Canvas {
-public:
-    SkiaCanvas(SkBitmap* bitmap);
-
-    SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {
-        SkASSERT(canvas);
-    }
-
-    virtual SkCanvas* getSkCanvas() {
-        return mCanvas.get();
-    }
-
-    virtual void setBitmap(SkBitmap* bitmap, bool copyState);
-
-    virtual bool isOpaque();
-    virtual int width();
-    virtual int height();
-
-    virtual int getSaveCount() const;
-    virtual int save(SkCanvas::SaveFlags flags);
-    virtual void restore();
-    virtual void restoreToCount(int saveCount);
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-                const SkPaint* paint, SkCanvas::SaveFlags flags);
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags);
-
-    virtual void getMatrix(SkMatrix* outMatrix) const;
-    virtual void setMatrix(const SkMatrix& matrix);
-    virtual void concat(const SkMatrix& matrix);
-    virtual void rotate(float degrees);
-    virtual void scale(float sx, float sy);
-    virtual void skew(float sx, float sy);
-    virtual void translate(float dx, float dy);
-
-    virtual bool getClipBounds(SkRect* outRect) const;
-    virtual bool quickRejectRect(float left, float top, float right, float bottom) const;
-    virtual bool quickRejectPath(const SkPath& path) const;
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
-
-    virtual SkDrawFilter* getDrawFilter();
-    virtual void setDrawFilter(SkDrawFilter* drawFilter);
-
-    virtual void drawColor(int color, SkXfermode::Mode mode);
-    virtual void drawPaint(const SkPaint& paint);
-
-    virtual void drawPoint(float x, float y, const SkPaint& paint);
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint);
-    virtual void drawLine(float startX, float startY, float stopX, float stopY,
-            const SkPaint& paint);
-    virtual void drawLines(const float* points, int count, const SkPaint& paint);
-    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint);
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint& paint);
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint);
-    virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint);
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint);
-    virtual void drawPath(const SkPath& path, const SkPaint& paint);
-    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
-            const float* verts, const float* tex, const int* colors,
-            const uint16_t* indices, int indexCount, const SkPaint& paint);
-
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint);
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint);
-    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
-    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint);
-
-    virtual void drawText(const uint16_t* text, const float* positions, int count,
-            const SkPaint& paint, float x, float y,
-            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom);
-    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
-            int posCount, const SkPaint& paint);
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint);
-
-    virtual bool drawTextAbsolutePos() const { return true; }
-
-private:
-    struct SaveRec {
-        int                 saveCount;
-        SkCanvas::SaveFlags saveFlags;
-    };
-
-    void recordPartialSave(SkCanvas::SaveFlags flags);
-    void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
-    void applyClips(const SkTArray<SkClipStack::Element>& clips);
-
-    void drawPoints(const float* points, int count, const SkPaint& paint,
-                    SkCanvas::PointMode mode);
-    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
-
-    SkAutoTUnref<SkCanvas> mCanvas;
-    SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
-};
-
-// Construct an SkCanvas from the bitmap.
-static SkCanvas* createCanvas(SkBitmap* bitmap) {
-    if (bitmap) {
-        return SkNEW_ARGS(SkCanvas, (*bitmap));
-    }
-
-    // Create an empty bitmap device to prevent callers from crashing
-    // if they attempt to draw into this canvas.
-    SkBitmap emptyBitmap;
-    return new SkCanvas(emptyBitmap);
-}
-
-Canvas* Canvas::create_canvas(SkBitmap* bitmap) {
-    return new SkiaCanvas(bitmap);
-}
-
-Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
-    return new SkiaCanvas(skiaCanvas);
-}
-
-SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) {
-    mCanvas.reset(createCanvas(bitmap));
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations: Replace Bitmap
-// ----------------------------------------------------------------------------
-
-class ClipCopier : public SkCanvas::ClipVisitor {
-public:
-    ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
-
-    virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
-        m_dstCanvas->clipRect(rect, op, antialias);
-    }
-    virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
-        m_dstCanvas->clipRRect(rrect, op, antialias);
-    }
-    virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
-        m_dstCanvas->clipPath(path, op, antialias);
-    }
-
-private:
-    SkCanvas* m_dstCanvas;
-};
-
-void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) {
-    SkCanvas* newCanvas = createCanvas(bitmap);
-    SkASSERT(newCanvas);
-
-    if (copyState) {
-        // Copy the canvas matrix & clip state.
-        newCanvas->setMatrix(mCanvas->getTotalMatrix());
-        if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
-            ClipCopier copier(newCanvas);
-            mCanvas->replayClips(&copier);
-        }
-    }
-
-    // unrefs the existing canvas
-    mCanvas.reset(newCanvas);
-
-    // clean up the old save stack
-    mSaveStack.reset(NULL);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-
-bool SkiaCanvas::isOpaque() {
-    return mCanvas->getDevice()->accessBitmap(false).isOpaque();
-}
-
-int SkiaCanvas::width() {
-    return mCanvas->getBaseLayerSize().width();
-}
-
-int SkiaCanvas::height() {
-    return mCanvas->getBaseLayerSize().height();
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations: Save (layer)
-// ----------------------------------------------------------------------------
-
-int SkiaCanvas::getSaveCount() const {
-    return mCanvas->getSaveCount();
-}
-
-int SkiaCanvas::save(SkCanvas::SaveFlags flags) {
-    int count = mCanvas->save();
-    recordPartialSave(flags);
-    return count;
-}
-
-void SkiaCanvas::restore() {
-    const SaveRec* rec = (NULL == mSaveStack.get())
-            ? 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();
-}
-
-void SkiaCanvas::restoreToCount(int restoreCount) {
-    while (mCanvas->getSaveCount() > restoreCount) {
-        this->restore();
-    }
-}
-
-int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, SkCanvas::SaveFlags flags) {
-    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
-    recordPartialSave(flags);
-    return count;
-}
-
-int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
-        int alpha, SkCanvas::SaveFlags flags) {
-    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag);
-    recordPartialSave(flags);
-    return count;
-}
-
-// ----------------------------------------------------------------------------
-// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::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.get()) {
-        mSaveStack.reset(SkNEW_ARGS(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 SkiaCanvas::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 SkiaCanvas::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);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations: Matrix
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
-    *outMatrix = mCanvas->getTotalMatrix();
-}
-
-void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
-    mCanvas->setMatrix(matrix);
-}
-
-void SkiaCanvas::concat(const SkMatrix& matrix) {
-    mCanvas->concat(matrix);
-}
-
-void SkiaCanvas::rotate(float degrees) {
-    mCanvas->rotate(degrees);
-}
-
-void SkiaCanvas::scale(float sx, float sy) {
-    mCanvas->scale(sx, sy);
-}
-
-void SkiaCanvas::skew(float sx, float sy) {
-    mCanvas->skew(sx, sy);
-}
-
-void SkiaCanvas::translate(float dx, float dy) {
-    mCanvas->translate(dx, dy);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations: Clips
-// ----------------------------------------------------------------------------
-
-// This function is a mirror of SkCanvas::getClipBounds except that it does
-// not outset the edge of the clip to account for anti-aliasing. There is
-// a skia bug to investigate pushing this logic into back into skia.
-// (see https://code.google.com/p/skia/issues/detail?id=1303)
-bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
-    SkIRect ibounds;
-    if (!mCanvas->getClipDeviceBounds(&ibounds)) {
-        return false;
-    }
-
-    SkMatrix inverse;
-    // if we can't invert the CTM, we can't return local clip bounds
-    if (!mCanvas->getTotalMatrix().invert(&inverse)) {
-        if (outRect) {
-            outRect->setEmpty();
-        }
-        return false;
-    }
-
-    if (NULL != outRect) {
-        SkRect r = SkRect::Make(ibounds);
-        inverse.mapRect(outRect, r);
-    }
-    return true;
-}
-
-bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
-    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    return mCanvas->quickReject(bounds);
-}
-
-bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
-    return mCanvas->quickReject(path);
-}
-
-bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
-    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->clipRect(rect, op);
-    return mCanvas->isClipEmpty();
-}
-
-bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
-    mCanvas->clipPath(*path, op);
-    return mCanvas->isClipEmpty();
-}
-
-bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
-    SkPath rgnPath;
-    if (region->getBoundaryPath(&rgnPath)) {
-        // The region is specified in device space.
-        SkMatrix savedMatrix = mCanvas->getTotalMatrix();
-        mCanvas->resetMatrix();
-        mCanvas->clipPath(rgnPath, op);
-        mCanvas->setMatrix(savedMatrix);
-    } else {
-        mCanvas->clipRect(SkRect::MakeEmpty(), op);
-    }
-    return mCanvas->isClipEmpty();
-}
-
-// ----------------------------------------------------------------------------
-// Canvas state operations: Filters
-// ----------------------------------------------------------------------------
-
-SkDrawFilter* SkiaCanvas::getDrawFilter() {
-    return mCanvas->getDrawFilter();
-}
-
-void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
-    mCanvas->setDrawFilter(drawFilter);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) {
-    mCanvas->drawColor(color, mode);
-}
-
-void SkiaCanvas::drawPaint(const SkPaint& paint) {
-    mCanvas->drawPaint(paint);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations: Geometry
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
-                            SkCanvas::PointMode mode) {
-    // convert the floats into SkPoints
-    count >>= 1;    // now it is the number of points
-    SkAutoSTMalloc<32, SkPoint> storage(count);
-    SkPoint* pts = storage.get();
-    for (int i = 0; i < count; i++) {
-        pts[i].set(points[0], points[1]);
-        points += 2;
-    }
-    mCanvas->drawPoints(mode, count, pts, paint);
-}
-
-
-void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
-    mCanvas->drawPoint(x, y, paint);
-}
-
-void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
-    this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
-}
-
-void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
-                          const SkPaint& paint) {
-    mCanvas->drawLine(startX, startY, stopX, stopY, paint);
-}
-
-void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
-    this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
-}
-
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
-        const SkPaint& paint) {
-    mCanvas->drawRectCoords(left, top, right, bottom, paint);
-
-}
-
-void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, const SkPaint& paint) {
-    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawRoundRect(rect, rx, ry, paint);
-}
-
-void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
-    mCanvas->drawCircle(x, y, radius, paint);
-}
-
-void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
-    SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawOval(oval, paint);
-}
-
-void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
-    SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
-    mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
-}
-
-void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
-    mCanvas->drawPath(path, paint);
-}
-
-void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
-                              const float* verts, const float* texs, const int* colors,
-                              const uint16_t* indices, int indexCount, const SkPaint& paint) {
-#ifndef SK_SCALAR_IS_FLOAT
-    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
-#endif
-    const int ptCount = vertexCount >> 1;
-    mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
-                          (SkColor*)colors, NULL, indices, indexCount, paint);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations: Bitmaps
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
-    mCanvas->drawBitmap(bitmap, left, top, paint);
-}
-
-void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
-    mCanvas->drawBitmapMatrix(bitmap, matrix, paint);
-}
-
-void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
-                            float srcRight, float srcBottom, float dstLeft, float dstTop,
-                            float dstRight, float dstBottom, const SkPaint* paint) {
-    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
-    SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
-}
-
-void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-        const float* vertices, const int* colors, const SkPaint* paint) {
-
-    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
-    const int indexCount = meshWidth * meshHeight * 6;
-
-    /*  Our temp storage holds 2 or 3 arrays.
-        texture points [ptCount * sizeof(SkPoint)]
-        optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
-            copy to convert from float to fixed
-        indices [ptCount * sizeof(uint16_t)]
-    */
-    ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
-    storageSize += indexCount * sizeof(uint16_t);  // indices[]
-
-
-#ifndef SK_SCALAR_IS_FLOAT
-    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
-#endif
-    SkAutoMalloc storage(storageSize);
-    SkPoint* texs = (SkPoint*)storage.get();
-    uint16_t* indices = (uint16_t*)(texs + ptCount);
-
-    // cons up texture coordinates and indices
-    {
-        const SkScalar w = SkIntToScalar(bitmap.width());
-        const SkScalar h = SkIntToScalar(bitmap.height());
-        const SkScalar dx = w / meshWidth;
-        const SkScalar dy = h / meshHeight;
-
-        SkPoint* texsPtr = texs;
-        SkScalar y = 0;
-        for (int i = 0; i <= meshHeight; i++) {
-            if (i == meshHeight) {
-                y = h;  // to ensure numerically we hit h exactly
-            }
-            SkScalar x = 0;
-            for (int j = 0; j < meshWidth; j++) {
-                texsPtr->set(x, y);
-                texsPtr += 1;
-                x += dx;
-            }
-            texsPtr->set(w, y);
-            texsPtr += 1;
-            y += dy;
-        }
-        SkASSERT(texsPtr - texs == ptCount);
-    }
-
-    // cons up indices
-    {
-        uint16_t* indexPtr = indices;
-        int index = 0;
-        for (int i = 0; i < meshHeight; i++) {
-            for (int j = 0; j < meshWidth; j++) {
-                // lower-left triangle
-                *indexPtr++ = index;
-                *indexPtr++ = index + meshWidth + 1;
-                *indexPtr++ = index + meshWidth + 2;
-                // upper-right triangle
-                *indexPtr++ = index;
-                *indexPtr++ = index + meshWidth + 2;
-                *indexPtr++ = index + 1;
-                // bump to the next cell
-                index += 1;
-            }
-            // bump to the next row
-            index += 1;
-        }
-        SkASSERT(indexPtr - indices == indexCount);
-        SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
-    }
-
-    // double-check that we have legal indices
-#ifdef SK_DEBUG
-    {
-        for (int i = 0; i < indexCount; i++) {
-            SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
-        }
-    }
-#endif
-
-    // cons-up a shader for the bitmap
-    SkPaint tmpPaint;
-    if (paint) {
-        tmpPaint = *paint;
-    }
-    SkShader* shader = SkShader::CreateBitmapShader(bitmap,
-                                                    SkShader::kClamp_TileMode,
-                                                    SkShader::kClamp_TileMode);
-    SkSafeUnref(tmpPaint.setShader(shader));
-
-    mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
-                         texs, (const SkColor*)colors, NULL, indices,
-                         indexCount, tmpPaint);
-}
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations: Text
-// ----------------------------------------------------------------------------
-
-void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
-        const SkPaint& paint, float x, float y,
-        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) {
-    // Set align to left for drawing, as we don't want individual
-    // glyphs centered or right-aligned; the offset above takes
-    // care of all alignment.
-    SkPaint paintCopy(paint);
-    paintCopy.setTextAlign(SkPaint::kLeft_Align);
-
-    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
-    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
-}
-
-void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount,
-        const SkPaint& paint) {
-    SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
-    int indx;
-    for (indx = 0; indx < posCount; indx++) {
-        posPtr[indx].fX = positions[indx << 1];
-        posPtr[indx].fY = positions[(indx << 1) + 1];
-    }
-
-    SkPaint paintCopy(paint);
-    paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding);
-    mCanvas->drawPosText(text, count, posPtr, paintCopy);
-
-    delete[] posPtr;
-}
-
-void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-        float hOffset, float vOffset, const SkPaint& paint) {
-    mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
-}
-
-} // namespace android
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index eaca6d2..35d69fe 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -24,7 +24,7 @@
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <utils/Log.h>
 #include <utils/misc.h>
@@ -359,10 +359,8 @@
 
 int register_android_graphics_SurfaceTexture(JNIEnv* env)
 {
-    int err = 0;
-    err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
-            gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
-    return err;
+    return RegisterMethodsOrDie(env, kSurfaceTextureClassPathName, gSurfaceTextureMethods,
+                                NELEM(gSurfaceTextureMethods));
 }
 
 } // namespace android
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 2029658..b092e44 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -15,11 +15,10 @@
  */
 
 #include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "GraphicsJNI.h"
 #include <ScopedPrimitiveArray.h>
-#include "SkStream.h"
 #include "SkTypeface.h"
 #include "TypefaceImpl.h"
 #include <android_runtime/android_util_AssetManager.h>
@@ -81,8 +80,6 @@
 
 int register_android_graphics_Typeface(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env,
-                                                       "android/graphics/Typeface",
-                                                       gTypefaceMethods,
-                                                       SK_ARRAY_COUNT(gTypefaceMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/Typeface", gTypefaceMethods,
+                                NELEM(gTypefaceMethods));
 }
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
index 7afbeb2..da56290 100644
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -24,7 +24,6 @@
 
 #include "jni.h"  // for jlong, remove when being passed proper type
 
-#include "SkStream.h"
 #include "SkTypeface.h"
 
 #include <vector>
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index d129f621..d36f83a 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -15,8 +15,8 @@
  */
 
 
-#ifndef ANDROID_TYPEFACE_IMPL_H
-#define ANDROID_TYPEFACE_IMPL_H
+#ifndef _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
+#define _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
 
 #include "jni.h"  // for jlong, eventually remove
 #include "SkTypeface.h"
@@ -62,4 +62,4 @@
 
 }
 
-#endif  // ANDROID_TYPEFACE_IMPL_H
\ No newline at end of file
+#endif  // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
\ No newline at end of file
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index a134d4b..4f9ce8b 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -16,24 +16,15 @@
 
 #include "Utils.h"
 #include "SkUtils.h"
+#include "SkData.h"
 
 using namespace android;
 
-AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset, OwnAsset ownAsset,
-                                       HasMemoryBase hasMemoryBase)
+AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset)
     : fAsset(asset)
-    , fMemoryBase(kYes_HasMemoryBase == hasMemoryBase ?
-                  asset->getBuffer(false) : NULL)
-    , fOwnAsset(ownAsset)
 {
 }
 
-AssetStreamAdaptor::~AssetStreamAdaptor() {
-    if (kYes_OwnAsset == fOwnAsset) {
-        delete fAsset;
-    }
-}
-
 bool AssetStreamAdaptor::rewind() {
     off64_t pos = fAsset->seek(0, SEEK_SET);
     if (pos == (off64_t)-1) {
@@ -97,27 +88,26 @@
         return NULL;
     }
 
-    off64_t size = asset->seek(0, SEEK_SET);
-    if ((off64_t)-1 == size) {
+    const off64_t seekReturnVal = asset->seek(0, SEEK_SET);
+    if ((off64_t)-1 == seekReturnVal) {
         SkDebugf("---- copyAsset: asset rewind failed\n");
         return NULL;
     }
 
-    size = asset->getLength();
+    const off64_t size = asset->getLength();
     if (size <= 0) {
         SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
         return NULL;
     }
 
-    SkMemoryStream* stream = new SkMemoryStream(size);
-    void* data = const_cast<void*>(stream->getMemoryBase());
-    off64_t len = asset->read(data, size);
+    SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
+    const off64_t len = asset->read(data->writable_data(), size);
     if (len != size) {
         SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
-        delete stream;
-        stream = NULL;
+        return NULL;
     }
-    return stream;
+
+    return new SkMemoryStream(data);
 }
 
 jobject android::nullObjectReturn(const char msg[]) {
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index b90593c..c0b9410 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef UTILS_DEFINED
-#define UTILS_DEFINED
+#ifndef _ANDROID_GRAPHICS_UTILS_H_
+#define _ANDROID_GRAPHICS_UTILS_H_
 
 #include "SkStream.h"
 
@@ -28,22 +28,7 @@
 
 class AssetStreamAdaptor : public SkStreamRewindable {
 public:
-    // Enum passed to constructor. If set to kYes_OwnAsset,
-    // the passed in Asset will be deleted upon destruction.
-    enum OwnAsset {
-        kYes_OwnAsset,
-        kNo_OwnAsset,
-    };
-
-    // Enum passed to constructor. If set to kYes_HasMemoryBase,
-    // getMemoryBase will return the Asset's buffer.
-    enum HasMemoryBase {
-        kYes_HasMemoryBase,
-        kNo_HasMemoryBase,
-    };
-
-    AssetStreamAdaptor(Asset*, OwnAsset, HasMemoryBase);
-    ~AssetStreamAdaptor();
+    AssetStreamAdaptor(Asset*);
 
     virtual bool rewind();
     virtual size_t read(void* buffer, size_t size);
@@ -51,13 +36,9 @@
     virtual size_t getLength() const;
     virtual bool isAtEnd() const;
 
-    virtual const void* getMemoryBase() { return fMemoryBase; }
-
     virtual SkStreamRewindable* duplicate() const;
 private:
-    Asset*              fAsset;
-    const void* const   fMemoryBase;
-    const OwnAsset      fOwnAsset;
+    Asset* fAsset;
 };
 
 /**
@@ -89,4 +70,4 @@
 
 }; // namespace android
 
-#endif
+#endif  // _ANDROID_GRAPHICS_UTILS_H_
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 6bf6f8a..4a424ae 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -16,9 +16,9 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
-#include "SkAvoidXfermode.h"
+#include "AvoidXfermode.h"
 #include "SkPixelXorXfermode.h"
 
 namespace android {
@@ -35,8 +35,8 @@
     static jlong avoid_create(JNIEnv* env, jobject, jint opColor,
                                 jint tolerance, jint modeHandle)
     {
-        SkAvoidXfermode::Mode mode = static_cast<SkAvoidXfermode::Mode>(modeHandle);
-        return reinterpret_cast<jlong>(SkAvoidXfermode::Create(opColor, tolerance, mode));
+        AvoidXfermode::Mode mode = static_cast<AvoidXfermode::Mode>(modeHandle);
+        return reinterpret_cast<jlong>(AvoidXfermode::Create(opColor, tolerance, mode));
     }
 
     static jlong pixelxor_create(JNIEnv* env, jobject, jint opColor)
@@ -59,19 +59,15 @@
     {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create}
 };
 
-#include <android_runtime/AndroidRuntime.h>
-
-#define REG(env, name, array)                                              \
-    result = android::AndroidRuntime::registerNativeMethods(env, name, array, \
-                                                  SK_ARRAY_COUNT(array));  \
-    if (result < 0) return result
-
 int register_android_graphics_Xfermode(JNIEnv* env) {
-    int result;
-    
-    REG(env, "android/graphics/Xfermode", gXfermodeMethods);
-    REG(env, "android/graphics/AvoidXfermode", gAvoidMethods);
-    REG(env, "android/graphics/PixelXorXfermode", gPixelXorMethods);
+    android::RegisterMethodsOrDie(env, "android/graphics/Xfermode", gXfermodeMethods,
+                                  NELEM(gXfermodeMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/Xfermode", gXfermodeMethods,
+                                  NELEM(gXfermodeMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/AvoidXfermode", gAvoidMethods,
+                                  NELEM(gAvoidMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/PixelXorXfermode", gPixelXorMethods,
+                                  NELEM(gPixelXorMethods));
 
     return 0;
 }
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 6591d60..5eede2a 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -4,6 +4,8 @@
 #include <ui/PixelFormat.h>
 #include <hardware/hardware.h>
 
+#include "core_jni_helpers.h"
+
 #include <jni.h>
 
 YuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
@@ -236,21 +238,18 @@
     env->ReleaseByteArrayElements(inYuv, yuv, 0);
     env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
     env->ReleaseIntArrayElements(strides, imgStrides, 0);
+    delete strm;
     return result;
 }
 ///////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gYuvImageMethods[] = {
     {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
         (void*)YuvImage_compressToJpeg }
 };
 
-#define kClassPathName  "android/graphics/YuvImage"
-
 int register_android_graphics_YuvImage(JNIEnv* env)
 {
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-            gYuvImageMethods, SK_ARRAY_COUNT(gYuvImageMethods));
+    return android::RegisterMethodsOrDie(env, "android/graphics/YuvImage", gYuvImageMethods,
+                                         NELEM(gYuvImageMethods));
 }
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.h b/core/jni/android/graphics/YuvToJpegEncoder.h
index 0d418ed..1ea844a 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.h
+++ b/core/jni/android/graphics/YuvToJpegEncoder.h
@@ -1,5 +1,5 @@
-#ifndef YuvToJpegEncoder_DEFINED
-#define YuvToJpegEncoder_DEFINED
+#ifndef _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
+#define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
 
 #include "SkTypes.h"
 #include "SkStream.h"
@@ -47,16 +47,16 @@
 
 class Yuv420SpToJpegEncoder : public YuvToJpegEncoder {
 public:
-     Yuv420SpToJpegEncoder(int* strides);
-     virtual ~Yuv420SpToJpegEncoder() {}
+    Yuv420SpToJpegEncoder(int* strides);
+    virtual ~Yuv420SpToJpegEncoder() {}
 
 private:
-     void configSamplingFactors(jpeg_compress_struct* cinfo);
-     void deinterleaveYuv(uint8_t* yuv, int width, int height,
+    void configSamplingFactors(jpeg_compress_struct* cinfo);
+    void deinterleaveYuv(uint8_t* yuv, int width, int height,
             uint8_t*& yPlanar, uint8_t*& uPlanar, uint8_t*& vPlanar);
-     void deinterleave(uint8_t* vuPlanar, uint8_t* uRows, uint8_t* vRows,
-             int rowIndex, int width, int height);
-     void compress(jpeg_compress_struct* cinfo, uint8_t* yuv, int* offsets);
+    void deinterleave(uint8_t* vuPlanar, uint8_t* uRows, uint8_t* vRows,
+            int rowIndex, int width, int height);
+    void compress(jpeg_compress_struct* cinfo, uint8_t* yuv, int* offsets);
 };
 
 class Yuv422IToJpegEncoder : public YuvToJpegEncoder {
@@ -71,4 +71,4 @@
             uint8_t* vRows, int rowIndex, int width, int height);
 };
 
-#endif
+#endif  // _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index 9436a47..a91b15b 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -16,7 +16,7 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <vector>
 
 #include "Canvas.h"
@@ -71,12 +71,7 @@
         mCurrentPage = page;
 
         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
-        // is destroyed, so we have to bump up the reference count.
-        canvas->ref();
+                SkRect::MakeWH(contentRect.width(), contentRect.height()));
 
         return canvas;
     }
@@ -164,10 +159,9 @@
 };
 
 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
-    int result = android::AndroidRuntime::registerNativeMethods(
+    return RegisterMethodsOrDie(
             env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
             NELEM(gPdfDocument_Methods));
-    return result;
 }
 
 };
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index ed6f1d6..84434ae 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -16,14 +16,19 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
 #include "fpdfview.h"
 #include "fpdfedit.h"
 #include "fpdfsave.h"
 #include "fsdk_rendercontext.h"
 #include "fpdf_transformpage.h"
+#pragma GCC diagnostic pop
+
 #include "SkMatrix.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 #include <vector>
 #include <utils/Log.h>
 #include <unistd.h>
@@ -92,12 +97,12 @@
         switch (error) {
             case FPDF_ERR_PASSWORD:
             case FPDF_ERR_SECURITY: {
-                jniThrowException(env, "java/lang/SecurityException",
-                        "cannot create document. Error:" + error);
+                jniThrowExceptionFmt(env, "java/lang/SecurityException",
+                        "cannot create document. Error: %ld", error);
             } break;
             default: {
-                jniThrowException(env, "java/io/IOException",
-                        "cannot create document. Error:" + error);
+                jniThrowExceptionFmt(env, "java/io/IOException",
+                        "cannot create document. Error: %ld", error);
             } break;
         }
         destroyLibraryIfNeeded();
@@ -150,7 +155,7 @@
 static int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) {
     const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner);
     const bool success = writeAllBytes(writer->dstFd, buffer, size);
-    if (success < 0) {
+    if (!success) {
         ALOGE("Cannot write to file descriptor. Error:%d", errno);
         return 0;
     }
@@ -164,8 +169,8 @@
     writer.WriteBlock = &writeBlock;
     const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL);
     if (!success) {
-        jniThrowException(env, "java/io/IOException",
-                "cannot write to fd. Error:" + errno);
+        jniThrowExceptionFmt(env, "java/io/IOException",
+                "cannot write to fd. Error: %d", errno);
         destroyLibraryIfNeeded();
     }
 }
@@ -196,7 +201,11 @@
     SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
 
     SkScalar transformValues[6];
-    skTransform->asAffine(transformValues);
+    if (!skTransform->asAffine(transformValues)) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                "transform matrix has perspective. Only affine matrices are allowed.");
+        return;
+    }
 
     // PDF's coordinate system origin is left-bottom while in graphics it
     // is the top-left. So, translate the PDF coordinates to ours.
@@ -350,19 +359,19 @@
 };
 
 int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
-    const int result = android::AndroidRuntime::registerNativeMethods(
+    const int result = RegisterMethodsOrDie(
             env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
             NELEM(gPdfEditor_Methods));
 
-    jclass pointClass = env->FindClass("android/graphics/Point");
-    gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I");
-    gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I");
+    jclass pointClass = FindClassOrDie(env, "android/graphics/Point");
+    gPointClassInfo.x = GetFieldIDOrDie(env, pointClass, "x", "I");
+    gPointClassInfo.y = GetFieldIDOrDie(env, pointClass, "y", "I");
 
-    jclass rectClass = env->FindClass("android/graphics/Rect");
-    gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I");
-    gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I");
-    gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I");
-    gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I");
+    jclass rectClass = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.left = GetFieldIDOrDie(env, rectClass, "left", "I");
+    gRectClassInfo.top = GetFieldIDOrDie(env, rectClass, "top", "I");
+    gRectClassInfo.right = GetFieldIDOrDie(env, rectClass, "right", "I");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClass, "bottom", "I");
 
     return result;
 };
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 357d3c0..fc98cf9 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -20,9 +20,13 @@
 #include "SkBitmap.h"
 #include "SkMatrix.h"
 #include "fpdfview.h"
-#include "fsdk_rendercontext.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+#include "fsdk_rendercontext.h"
+#pragma GCC diagnostic pop
+
+#include "core_jni_helpers.h"
 #include <vector>
 #include <utils/Log.h>
 #include <unistd.h>
@@ -85,12 +89,12 @@
         switch (error) {
             case FPDF_ERR_PASSWORD:
             case FPDF_ERR_SECURITY: {
-                jniThrowException(env, "java/lang/SecurityException",
-                        "cannot create document. Error:" + error);
+                jniThrowExceptionFmt(env, "java/lang/SecurityException",
+                        "cannot create document. Error: %ld", error);
             } break;
             default: {
-                jniThrowException(env, "java/io/IOException",
-                        "cannot create document. Error:" + error);
+                jniThrowExceptionFmt(env, "java/io/IOException",
+                        "cannot create document. Error: %ld", error);
             } break;
         }
         destroyLibraryIfNeeded();
@@ -215,11 +219,16 @@
         matrix.Set(1, 0, 0, -1, 0, pPage->GetPageHeight());
 
         SkScalar transformValues[6];
-        transform->asAffine(transformValues);
+        if (transform->asAffine(transformValues)) {
+            matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+                    transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+                    transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
+        } else {
+            // Already checked for a return value of false in the caller, so this should never
+            // happen.
+            ALOGE("Error rendering page!");
+        }
 
-        matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
-                transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
-                transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
     }
     pageContext->AppendObjectList(pPage, &matrix);
 
@@ -237,7 +246,6 @@
         jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
         jlong matrixPtr, jint renderMode) {
 
-    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
     SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
     SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
@@ -261,6 +269,12 @@
         renderFlags |= FPDF_PRINTING;
     }
 
+    if (skMatrix && !skMatrix->asAffine(NULL)) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                "transform matrix has perspective. Only affine matrices are allowed.");
+        return;
+    }
+
     renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
             destBottom, skMatrix, renderFlags);
 
@@ -279,13 +293,13 @@
 };
 
 int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
-    int result = android::AndroidRuntime::registerNativeMethods(
+    int result = RegisterMethodsOrDie(
             env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
             NELEM(gPdfRenderer_Methods));
 
-    jclass clazz = env->FindClass("android/graphics/Point");
-    gPointClassInfo.x = env->GetFieldID(clazz, "x", "I");
-    gPointClassInfo.y = env->GetFieldID(clazz, "y", "I");
+    jclass clazz = FindClassOrDie(env, "android/graphics/Point");
+    gPointClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "I");
+    gPointClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "I");
 
     return result;
 };
diff --git a/core/jni/android/opengl/poly_clip.cpp b/core/jni/android/opengl/poly_clip.cpp
index 04e4b17..5c65220 100644
--- a/core/jni/android/opengl/poly_clip.cpp
+++ b/core/jni/android/opengl/poly_clip.cpp
@@ -58,7 +58,6 @@
 
 void poly_clip_to_halfspace(Poly* p, Poly* q, int index, float sign, float k)
 {
-    unsigned long m;
     float *up, *vp, *wp;
     Poly_vert *v;
     int i;
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 89baef8..5c2d0d0 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -16,6 +16,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "GraphicsJNI.h"
 
 #include <math.h>
 #include <stdio.h>
@@ -29,7 +30,7 @@
 
 #include <SkBitmap.h>
 
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #undef LOG_TAG
 #define LOG_TAG "OpenGLUtil"
@@ -149,10 +150,6 @@
     return result;
 }
 
-static void doThrowIAE(JNIEnv* env, const char* msg) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", msg);
-}
-
 template<class JArray, class T>
 class ArrayHelper {
 public:
@@ -471,13 +468,13 @@
 void multiplyMM(float* r, const float* lhs, const float* rhs)
 {
     for (int i=0 ; i<4 ; i++) {
-        register const float rhs_i0 = rhs[ I(i,0) ];
-        register float ri0 = lhs[ I(0,0) ] * rhs_i0;
-        register float ri1 = lhs[ I(0,1) ] * rhs_i0;
-        register float ri2 = lhs[ I(0,2) ] * rhs_i0;
-        register float ri3 = lhs[ I(0,3) ] * rhs_i0;
+        const float rhs_i0 = rhs[ I(i,0) ];
+        float ri0 = lhs[ I(0,0) ] * rhs_i0;
+        float ri1 = lhs[ I(0,1) ] * rhs_i0;
+        float ri2 = lhs[ I(0,2) ] * rhs_i0;
+        float ri3 = lhs[ I(0,3) ] * rhs_i0;
         for (int j=1 ; j<4 ; j++) {
-            register const float rhs_ij = rhs[ I(i,j) ];
+            const float rhs_ij = rhs[ I(i,j) ];
             ri0 += lhs[ I(j,0) ] * rhs_ij;
             ri1 += lhs[ I(j,1) ] * rhs_ij;
             ri2 += lhs[ I(j,2) ] * rhs_ij;
@@ -548,14 +545,6 @@
 
 // ---------------------------------------------------------------------------
 
-static jfieldID nativeBitmapID = 0;
-
-void nativeUtilsClassInit(JNIEnv *env, jclass clazz)
-{
-    jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
-    nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
-}
-
 extern void setGLDebugLevel(int level);
 void setTracingLevel(JNIEnv *env, jclass clazz, jint level)
 {
@@ -629,16 +618,14 @@
 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     return getInternalFormat(nativeBitmap->colorType());
 }
 
 static jint util_getType(JNIEnv *env, jclass clazz,
         jobject jbitmap)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     return getType(nativeBitmap->colorType());
 }
 
@@ -646,8 +633,7 @@
         jint target, jint level, jint internalformat,
         jobject jbitmap, jint type, jint border)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
@@ -675,9 +661,8 @@
         if (data) {
             void* const pixels = (char*)data + palette_size;
             SkColorTable* ctable = bitmap.getColorTable();
-            memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
+            memcpy(data, ctable->readColors(), ctable->count() * sizeof(SkPMColor));
             memcpy(pixels, p, size);
-            ctable->unlockColors();
             glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
             free(data);
         } else {
@@ -695,8 +680,7 @@
         jint target, jint level, jint xoffset, jint yoffset,
         jobject jbitmap, jint format, jint type)
 {
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     SkColorType colorType = bitmap.colorType();
     if (format < 0) {
@@ -732,24 +716,22 @@
 /* Cache method IDs each time the class is loaded. */
 
 static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInitBuffer(JNIEnv *env)
 {
-    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
-    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
-
-    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
-    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
-
-    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+    jclass nioAccessClassLocal = FindClassOrDie(env, "java/nio/NIOAccess");
+    nioAccessClass = MakeGlobalRefOrDie(env, nioAccessClassLocal);
+    getBasePointerID = GetStaticMethodIDOrDie(env, nioAccessClass,
             "getBasePointer", "(Ljava/nio/Buffer;)J");
-    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+    getBaseArrayID = GetStaticMethodIDOrDie(env, nioAccessClass,
             "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
-    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+    getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, nioAccessClass,
             "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
-    positionID = _env->GetFieldID(bufferClass, "position", "I");
-    limitID = _env->GetFieldID(bufferClass, "limit", "I");
-    elementSizeShiftID =
-        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+
+    jclass bufferClassLocal = FindClassOrDie(env, "java/nio/Buffer");
+    bufferClass = MakeGlobalRefOrDie(env, bufferClassLocal);
+    positionID = GetFieldIDOrDie(env, bufferClass, "position", "I");
+    limitID = GetFieldIDOrDie(env, bufferClass, "limit", "I");
+    elementSizeShiftID = GetFieldIDOrDie(env, bufferClass, "_elementSizeShift", "I");
 }
 
 static void *
@@ -759,8 +741,6 @@
     jint limit;
     jint elementSizeShift;
     jlong pointer;
-    jint offset;
-    void *data;
 
     position = _env->GetIntField(buffer, positionID);
     limit = _env->GetIntField(buffer, limitID);
@@ -900,10 +880,8 @@
         } else if (outB.remaining() < encodedImageSize) {
             doThrowIAE(env, "out's remaining data < encoded image size");
         } else {
-            int result = etc1_encode_image((etc1_byte*) inB.getData(),
-                    width, height, pixelSize,
-                    stride,
-                    (etc1_byte*) outB.getData());
+            etc1_encode_image((etc1_byte*) inB.getData(), width, height, pixelSize, stride,
+                              (etc1_byte*) outB.getData());
         }
     }
 }
@@ -933,10 +911,8 @@
         } else if (outB.remaining() < imageSize) {
             doThrowIAE(env, "out's remaining data < image size");
         } else {
-            int result = etc1_decode_image((etc1_byte*) inB.getData(),
-                    (etc1_byte*) outB.getData(),
-                    width, height, pixelSize,
-                    stride);
+            etc1_decode_image((etc1_byte*) inB.getData(), (etc1_byte*) outB.getData(),
+                              width, height, pixelSize, stride);
         }
     }
 }
@@ -1023,7 +999,6 @@
 };
 
 static JNINativeMethod gUtilsMethods[] = {
-    {"nativeClassInit", "()V",                          (void*)nativeUtilsClassInit },
     { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
@@ -1062,12 +1037,7 @@
     int result = 0;
     for (int i = 0; i < NELEM(gClasses); i++) {
         ClassRegistrationInfo* cri = &gClasses[i];
-        result = AndroidRuntime::registerNativeMethods(env,
-                cri->classPath, cri->methods, cri->methodCount);
-        if (result < 0) {
-            ALOGE("Failed to register %s: %d", cri->classPath, result);
-            break;
-        }
+        result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
     }
     return result;
 }
diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp
index ef1c4ed..d117741 100644
--- a/core/jni/android_animation_PropertyValuesHolder.cpp
+++ b/core/jni/android_animation_PropertyValuesHolder.cpp
@@ -18,7 +18,7 @@
 #include <assert.h>
 
 #include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <utils/misc.h>
 
 // ----------------------------------------------------------------------------
@@ -168,8 +168,7 @@
 
 int register_android_animation_PropertyValuesHolder(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env,
-            kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 633a207..95be3f2 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -40,12 +40,17 @@
 
 #include "nativebridge/native_bridge.h"
 
+#include "core_jni_helpers.h"
+
+
 #define LOG_TRACE(...)
 //#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 
 namespace android
 {
 
+static const bool kLogTrace = false;
+
 static struct {
     jmethodID finish;
     jmethodID setWindowFlags;
@@ -75,8 +80,10 @@
     work.cmd = cmd;
     work.arg1 = arg1;
     work.arg2 = arg2;
-    
-    LOG_TRACE("write_work: cmd=%d", cmd);
+
+    if (kLogTrace) {
+        ALOGD("write_work: cmd=%d", cmd);
+    }
 
 restart:
     int res = write(fd, &work, sizeof(work));
@@ -206,7 +213,9 @@
         return 1;
     }
 
-    LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
+    if (kLogTrace) {
+        ALOGD("mainWorkCallback: cmd=%d", work.cmd);
+    }
 
     switch (work.cmd) {
         case CMD_FINISH: {
@@ -249,7 +258,9 @@
         jstring externalDataDir, jint sdkVersion,
         jobject jAssetMgr, jbyteArray savedState)
 {
-    LOG_TRACE("loadNativeCode_native");
+    if (kLogTrace) {
+        ALOGD("loadNativeCode_native");
+    }
 
     const char* pathStr = env->GetStringUTFChars(path, NULL);
     NativeCode* code = NULL;
@@ -358,7 +369,9 @@
 static void
 unloadNativeCode_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("unloadNativeCode_native");
+    if (kLogTrace) {
+        ALOGD("unloadNativeCode_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         delete code;
@@ -368,7 +381,9 @@
 static void
 onStart_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onStart_native");
+    if (kLogTrace) {
+        ALOGD("onStart_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStart != NULL) {
@@ -380,7 +395,9 @@
 static void
 onResume_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onResume_native");
+    if (kLogTrace) {
+        ALOGD("onResume_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onResume != NULL) {
@@ -392,7 +409,9 @@
 static jbyteArray
 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onSaveInstanceState_native");
+    if (kLogTrace) {
+        ALOGD("onSaveInstanceState_native");
+    }
 
     jbyteArray array = NULL;
 
@@ -419,7 +438,9 @@
 static void
 onPause_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onPause_native");
+    if (kLogTrace) {
+        ALOGD("onPause_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onPause != NULL) {
@@ -431,7 +452,9 @@
 static void
 onStop_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onStop_native");
+    if (kLogTrace) {
+        ALOGD("onStop_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStop != NULL) {
@@ -443,7 +466,9 @@
 static void
 onConfigurationChanged_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onConfigurationChanged_native");
+    if (kLogTrace) {
+        ALOGD("onConfigurationChanged_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onConfigurationChanged != NULL) {
@@ -455,7 +480,9 @@
 static void
 onLowMemory_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onLowMemory_native");
+    if (kLogTrace) {
+        ALOGD("onLowMemory_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onLowMemory != NULL) {
@@ -467,7 +494,9 @@
 static void
 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jlong handle, jboolean focused)
 {
-    LOG_TRACE("onWindowFocusChanged_native");
+    if (kLogTrace) {
+        ALOGD("onWindowFocusChanged_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onWindowFocusChanged != NULL) {
@@ -479,7 +508,9 @@
 static void
 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface)
 {
-    LOG_TRACE("onSurfaceCreated_native");
+    if (kLogTrace) {
+        ALOGD("onSurfaceCreated_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
@@ -500,7 +531,9 @@
 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface,
         jint format, jint width, jint height)
 {
-    LOG_TRACE("onSurfaceChanged_native");
+    if (kLogTrace) {
+        ALOGD("onSurfaceChanged_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
@@ -540,7 +573,9 @@
 static void
 onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jlong handle)
 {
-    LOG_TRACE("onSurfaceRedrawNeeded_native");
+    if (kLogTrace) {
+        ALOGD("onSurfaceRedrawNeeded_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
@@ -552,7 +587,9 @@
 static void
 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jlong handle, jobject surface)
 {
-    LOG_TRACE("onSurfaceDestroyed_native");
+    if (kLogTrace) {
+        ALOGD("onSurfaceDestroyed_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
@@ -566,7 +603,9 @@
 static void
 onInputQueueCreated_native(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)
 {
-    LOG_TRACE("onInputChannelCreated_native");
+    if (kLogTrace) {
+        ALOGD("onInputChannelCreated_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onInputQueueCreated != NULL) {
@@ -579,7 +618,9 @@
 static void
 onInputQueueDestroyed_native(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)
 {
-    LOG_TRACE("onInputChannelDestroyed_native");
+    if (kLogTrace) {
+        ALOGD("onInputChannelDestroyed_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onInputQueueDestroyed != NULL) {
@@ -593,7 +634,9 @@
 onContentRectChanged_native(JNIEnv* env, jobject clazz, jlong handle,
         jint x, jint y, jint w, jint h)
 {
-    LOG_TRACE("onContentRectChanged_native");
+    if (kLogTrace) {
+        ALOGD("onContentRectChanged_native");
+    }
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onContentRectChanged != NULL) {
@@ -632,39 +675,20 @@
 
 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class %s", className);
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName);
-        
 int register_android_app_NativeActivity(JNIEnv* env)
 {
     //ALOGD("register_android_app_NativeActivity");
-    jclass clazz;
-    FIND_CLASS(clazz, kNativeActivityPathName);
+    jclass clazz = FindClassOrDie(env, kNativeActivityPathName);
 
-    GET_METHOD_ID(gNativeActivityClassInfo.finish,
-            clazz,
-            "finish", "()V");
-    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags,
-            clazz,
-            "setWindowFlags", "(II)V");
-    GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
-            clazz,
-            "setWindowFormat", "(I)V");
-    GET_METHOD_ID(gNativeActivityClassInfo.showIme,
-            clazz,
-            "showIme", "(I)V");
-    GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
-            clazz,
-            "hideIme", "(I)V");
+    gNativeActivityClassInfo.finish = GetMethodIDOrDie(env, clazz, "finish", "()V");
+    gNativeActivityClassInfo.setWindowFlags = GetMethodIDOrDie(env, clazz, "setWindowFlags",
+                                                               "(II)V");
+    gNativeActivityClassInfo.setWindowFormat = GetMethodIDOrDie(env, clazz, "setWindowFormat",
+                                                                "(I)V");
+    gNativeActivityClassInfo.showIme = GetMethodIDOrDie(env, clazz, "showIme", "(I)V");
+    gNativeActivityClassInfo.hideIme = GetMethodIDOrDie(env, clazz, "hideIme", "(I)V");
 
-    return AndroidRuntime::registerNativeMethods(
-        env, kNativeActivityPathName,
-        g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, kNativeActivityPathName, g_methods, NELEM(g_methods));
 }
 
 } // namespace android
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index 3cfaa82..2c02b37 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -23,6 +23,8 @@
 
 #include <androidfw/BackupHelpers.h>
 
+#include "core_jni_helpers.h"
+
 #include <string.h>
 
 namespace android
@@ -73,8 +75,6 @@
 static jint backupToTar(JNIEnv* env, jobject clazz, jstring packageNameObj,
         jstring domainObj, jstring linkdomain,
         jstring rootpathObj, jstring pathObj, jobject dataOutputObj) {
-    int ret;
-
     // Extract the various strings, allowing for null object pointers
     const char* packagenamechars = (packageNameObj) ? env->GetStringUTFChars(packageNameObj, NULL) : NULL;
     const char* rootchars = (rootpathObj) ? env->GetStringUTFChars(rootpathObj, NULL) : NULL;
@@ -118,15 +118,11 @@
 
 int register_android_app_backup_FullBackup(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/app/backup/BackupDataOutput");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataOutput");
+    jclass clazz = FindClassOrDie(env, "android/app/backup/BackupDataOutput");
 
-    sBackupDataOutput.mBackupWriter = env->GetFieldID(clazz, "mBackupWriter", "J");
-    LOG_FATAL_IF(sBackupDataOutput.mBackupwriter == NULL,
-            "Unable to find mBackupWriter field in android.app.backup.BackupDataOutput");
+    sBackupDataOutput.mBackupWriter = GetFieldIDOrDie(env, clazz, "mBackupWriter", "J");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FullBackup",
-            g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "android/app/backup/FullBackup", g_methods, NELEM(g_methods));
 }
 
 }
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 90763b0..096a784 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -22,6 +22,8 @@
 
 #include <androidfw/BackupHelpers.h>
 
+#include "core_jni_helpers.h"
+
 namespace android
 {
 
@@ -135,17 +137,12 @@
 {
     //ALOGD("register_android_backup_BackupDataInput");
 
-    jclass clazz = env->FindClass("android/app/backup/BackupDataInput$EntityHeader");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataInput.EntityHeader");
-    s_keyField = env->GetFieldID(clazz, "key", "Ljava/lang/String;");
-    LOG_FATAL_IF(s_keyField == NULL,
-            "Unable to find key field in android.app.backup.BackupDataInput.EntityHeader");
-    s_dataSizeField = env->GetFieldID(clazz, "dataSize", "I");
-    LOG_FATAL_IF(s_dataSizeField == NULL,
-            "Unable to find dataSize field in android.app.backup.BackupDataInput.EntityHeader");
+    jclass clazz = FindClassOrDie(env, "android/app/backup/BackupDataInput$EntityHeader");
+    s_keyField = GetFieldIDOrDie(env, clazz, "key", "Ljava/lang/String;");
+    s_dataSizeField = GetFieldIDOrDie(env, clazz, "dataSize", "I");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupDataInput",
-            g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "android/app/backup/BackupDataInput", g_methods,
+                                NELEM(g_methods));
 }
 
 }
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index 8244e1b..a7894f4 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -18,7 +18,7 @@
 #include <utils/Log.h>
 
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <androidfw/BackupHelpers.h>
 
@@ -85,7 +85,6 @@
 static void
 setKeyPrefix_native(JNIEnv* env, jobject clazz, jlong w, jstring keyPrefixObj)
 {
-    int err;
     BackupDataWriter* writer = (BackupDataWriter*)w;
 
     const char* keyPrefixUTF = env->GetStringUTFChars(keyPrefixObj, NULL);
@@ -107,7 +106,7 @@
 int register_android_backup_BackupDataOutput(JNIEnv* env)
 {
     //ALOGD("register_android_backup_BackupDataOutput");
-    return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupDataOutput",
+    return RegisterMethodsOrDie(env, "android/app/backup/BackupDataOutput",
             g_methods, NELEM(g_methods));
 }
 
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
index a8b7d44..80bdaf8 100644
--- a/core/jni/android_backup_BackupHelperDispatcher.cpp
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -24,6 +24,7 @@
 #include <sys/uio.h>
 #include <unistd.h>
 
+#include "core_jni_helpers.h"
 
 #define VERSION_1_HEADER 0x01706c48  // 'Hlp'1 little endian
 
@@ -227,18 +228,12 @@
 
 int register_android_backup_BackupHelperDispatcher(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header");
-    LOG_FATAL_IF(clazz == NULL,
-            "Unable to find class android.app.backup.BackupHelperDispatcher.Header");
-    s_chunkSizeField = env->GetFieldID(clazz, "chunkSize", "I");
-    LOG_FATAL_IF(s_chunkSizeField == NULL,
-            "Unable to find chunkSize field in android.app.backup.BackupHelperDispatcher.Header");
-    s_keyPrefixField = env->GetFieldID(clazz, "keyPrefix", "Ljava/lang/String;");
-    LOG_FATAL_IF(s_keyPrefixField == NULL,
-            "Unable to find keyPrefix field in android.app.backup.BackupHelperDispatcher.Header");
+    jclass clazz = FindClassOrDie(env, "android/app/backup/BackupHelperDispatcher$Header");
+    s_chunkSizeField = GetFieldIDOrDie(env, clazz, "chunkSize", "I");
+    s_keyPrefixField = GetFieldIDOrDie(env, clazz, "keyPrefix", "Ljava/lang/String;");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupHelperDispatcher",
-            g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "android/app/backup/BackupHelperDispatcher", g_methods,
+                                NELEM(g_methods));
 }
 
 }
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 66e3e9d..6d6ac1b 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -18,7 +18,7 @@
 #include <utils/Log.h>
 
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <androidfw/BackupHelpers.h>
 
@@ -118,7 +118,7 @@
 
 int register_android_backup_FileBackupHelperBase(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FileBackupHelperBase",
+    return RegisterMethodsOrDie(env, "android/app/backup/FileBackupHelperBase",
             g_methods, NELEM(g_methods));
 }
 
diff --git a/core/jni/android_content_res_Configuration.cpp b/core/jni/android_content_res_Configuration.cpp
index 201ffe8..3b45e72 100644
--- a/core/jni/android_content_res_Configuration.cpp
+++ b/core/jni/android_content_res_Configuration.cpp
@@ -23,6 +23,8 @@
 #include <android_runtime/android_content_res_Configuration.h>
 #include "android_runtime/AndroidRuntime.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -70,49 +72,27 @@
             gConfigurationClassInfo.smallestScreenWidthDp);
 }
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_content_res_Configuration(JNIEnv* env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/content/res/Configuration");
+    jclass clazz = FindClassOrDie(env, "android/content/res/Configuration");
 
-    GET_FIELD_ID(gConfigurationClassInfo.mcc, clazz,
-            "mcc", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.mnc, clazz,
-            "mnc", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.locale, clazz,
-            "locale", "Ljava/util/Locale;");
-    GET_FIELD_ID(gConfigurationClassInfo.screenLayout, clazz,
-            "screenLayout", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz,
-            "touchscreen", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz,
-            "keyboard", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, clazz,
-            "keyboardHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, clazz,
-            "hardKeyboardHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz,
-            "navigation", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, clazz,
-            "navigationHidden", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.orientation, clazz,
-            "orientation", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.uiMode, clazz,
-            "uiMode", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.screenWidthDp, clazz,
-            "screenWidthDp", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.screenHeightDp, clazz,
-            "screenHeightDp", "I");
-    GET_FIELD_ID(gConfigurationClassInfo.smallestScreenWidthDp, clazz,
-            "smallestScreenWidthDp", "I");
+    gConfigurationClassInfo.mcc = GetFieldIDOrDie(env, clazz, "mcc", "I");
+    gConfigurationClassInfo.mnc = GetFieldIDOrDie(env, clazz, "mnc", "I");
+    gConfigurationClassInfo.locale = GetFieldIDOrDie(env, clazz, "locale", "Ljava/util/Locale;");
+    gConfigurationClassInfo.screenLayout = GetFieldIDOrDie(env, clazz, "screenLayout", "I");
+    gConfigurationClassInfo.touchscreen = GetFieldIDOrDie(env, clazz, "touchscreen", "I");
+    gConfigurationClassInfo.keyboard = GetFieldIDOrDie(env, clazz, "keyboard", "I");
+    gConfigurationClassInfo.keyboardHidden = GetFieldIDOrDie(env, clazz, "keyboardHidden", "I");
+    gConfigurationClassInfo.hardKeyboardHidden = GetFieldIDOrDie(env, clazz, "hardKeyboardHidden",
+                                                                 "I");
+    gConfigurationClassInfo.navigation = GetFieldIDOrDie(env, clazz, "navigation", "I");
+    gConfigurationClassInfo.navigationHidden = GetFieldIDOrDie(env, clazz, "navigationHidden", "I");
+    gConfigurationClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "I");
+    gConfigurationClassInfo.uiMode = GetFieldIDOrDie(env, clazz, "uiMode", "I");
+    gConfigurationClassInfo.screenWidthDp = GetFieldIDOrDie(env, clazz, "screenWidthDp", "I");
+    gConfigurationClassInfo.screenHeightDp = GetFieldIDOrDie(env, clazz, "screenHeightDp", "I");
+    gConfigurationClassInfo.smallestScreenWidthDp = GetFieldIDOrDie(env, clazz,
+                                                                    "smallestScreenWidthDp", "I");
 
     return 0;
 }
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 5d51ee2..ef17db6 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -25,6 +25,8 @@
 #include "utils/misc.h"
 #include "android_runtime/AndroidRuntime.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -80,30 +82,17 @@
             (void*) android_content_res_ObbScanner_getObbInfo },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_content_res_ObbScanner(JNIEnv* env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/content/res/ObbInfo");
+    jclass clazz = FindClassOrDie(env, "android/content/res/ObbInfo");
 
-    GET_FIELD_ID(gObbInfoClassInfo.packageName, clazz,
-            "packageName", "Ljava/lang/String;");
-    GET_FIELD_ID(gObbInfoClassInfo.version, clazz,
-            "version", "I");
-    GET_FIELD_ID(gObbInfoClassInfo.flags, clazz,
-            "flags", "I");
-    GET_FIELD_ID(gObbInfoClassInfo.salt, clazz,
-            "salt", "[B");
+    gObbInfoClassInfo.packageName = GetFieldIDOrDie(env, clazz, "packageName",
+                                                    "Ljava/lang/String;");
+    gObbInfoClassInfo.version = GetFieldIDOrDie(env, clazz, "version", "I");
+    gObbInfoClassInfo.flags = GetFieldIDOrDie(env, clazz, "flags", "I");
+    gObbInfoClassInfo.salt = GetFieldIDOrDie(env, clazz, "salt", "[B");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/content/res/ObbScanner", gMethods,
-            NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/content/res/ObbScanner", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index af6cc72..580ac02 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -36,6 +36,8 @@
 #include "android_util_Binder.h"
 #include "android_database_SQLiteCommon.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -522,29 +524,16 @@
             (void*)nativePutNull },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
-int register_android_database_CursorWindow(JNIEnv * env)
+int register_android_database_CursorWindow(JNIEnv* env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/database/CharArrayBuffer");
+    jclass clazz = FindClassOrDie(env, "android/database/CharArrayBuffer");
 
-    GET_FIELD_ID(gCharArrayBufferClassInfo.data, clazz,
-            "data", "[C");
-    GET_FIELD_ID(gCharArrayBufferClassInfo.sizeCopied, clazz,
-            "sizeCopied", "I");
+    gCharArrayBufferClassInfo.data = GetFieldIDOrDie(env, clazz, "data", "[C");
+    gCharArrayBufferClassInfo.sizeCopied = GetFieldIDOrDie(env, clazz, "sizeCopied", "I");
 
-    gEmptyString = jstring(env->NewGlobalRef(env->NewStringUTF("")));
-    LOG_FATAL_IF(!gEmptyString, "Unable to create empty string");
+    gEmptyString = MakeGlobalRefOrDie(env, env->NewStringUTF(""));
 
-    return AndroidRuntime::registerNativeMethods(env, "android/database/CursorWindow",
-            sMethods, NELEM(sMethods));
+    return RegisterMethodsOrDie(env, "android/database/CursorWindow", sMethods, NELEM(sMethods));
 }
 
 } // namespace android
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index ae56432..7a3cdf6 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -37,6 +37,8 @@
 
 #include "android_database_SQLiteCommon.h"
 
+#include "core_jni_helpers.h"
+
 // Set to 1 to use UTF16 storage for localized indexes.
 #define UTF16_STORAGE 0
 
@@ -325,7 +327,6 @@
 
 static jint nativeGetParameterCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
         jlong statementPtr) {
-    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
 
     return sqlite3_bind_parameter_count(statement);
@@ -333,7 +334,6 @@
 
 static jboolean nativeIsReadOnly(JNIEnv* env, jclass clazz, jlong connectionPtr,
         jlong statementPtr) {
-    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
 
     return sqlite3_stmt_readonly(statement) != 0;
@@ -341,7 +341,6 @@
 
 static jint nativeGetColumnCount(JNIEnv* env, jclass clazz, jlong connectionPtr,
         jlong statementPtr) {
-    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
 
     return sqlite3_column_count(statement);
@@ -349,7 +348,6 @@
 
 static jstring nativeGetColumnName(JNIEnv* env, jclass clazz, jlong connectionPtr,
         jlong statementPtr, jint index) {
-    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
     sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
 
     const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(statement, index));
@@ -845,35 +843,20 @@
             (void*)nativeResetCancel },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_database_SQLiteConnection(JNIEnv *env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/database/sqlite/SQLiteCustomFunction");
+    jclass clazz = FindClassOrDie(env, "android/database/sqlite/SQLiteCustomFunction");
 
-    GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.name, clazz,
-            "name", "Ljava/lang/String;");
-    GET_FIELD_ID(gSQLiteCustomFunctionClassInfo.numArgs, clazz,
-            "numArgs", "I");
-    GET_METHOD_ID(gSQLiteCustomFunctionClassInfo.dispatchCallback,
-            clazz, "dispatchCallback", "([Ljava/lang/String;)V");
+    gSQLiteCustomFunctionClassInfo.name = GetFieldIDOrDie(env, clazz, "name", "Ljava/lang/String;");
+    gSQLiteCustomFunctionClassInfo.numArgs = GetFieldIDOrDie(env, clazz, "numArgs", "I");
+    gSQLiteCustomFunctionClassInfo.dispatchCallback = GetMethodIDOrDie(env, clazz,
+            "dispatchCallback", "([Ljava/lang/String;)V");
 
-    FIND_CLASS(clazz, "java/lang/String");
-    gStringClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
+    clazz = FindClassOrDie(env, "java/lang/String");
+    gStringClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteConnection",
-            sMethods, NELEM(sMethods));
+    return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteConnection", sMethods,
+                                NELEM(sMethods));
 }
 
 } // namespace android
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
index c1e7305..26e13cf 100644
--- a/core/jni/android_database_SQLiteDebug.cpp
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -28,6 +28,8 @@
 
 #include <sqlite3.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -62,27 +64,17 @@
             (void*) nativeGetPagerStats },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_database_SQLiteDebug(JNIEnv *env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/database/sqlite/SQLiteDebug$PagerStats");
+    jclass clazz = FindClassOrDie(env, "android/database/sqlite/SQLiteDebug$PagerStats");
 
-    GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.memoryUsed, clazz,
-            "memoryUsed", "I");
-    GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.largestMemAlloc, clazz,
+    gSQLiteDebugPagerStatsClassInfo.memoryUsed = GetFieldIDOrDie(env, clazz, "memoryUsed", "I");
+    gSQLiteDebugPagerStatsClassInfo.largestMemAlloc = GetFieldIDOrDie(env, clazz,
             "largestMemAlloc", "I");
-    GET_FIELD_ID(gSQLiteDebugPagerStatsClassInfo.pageCacheOverflow, clazz,
+    gSQLiteDebugPagerStatsClassInfo.pageCacheOverflow = GetFieldIDOrDie(env, clazz,
             "pageCacheOverflow", "I");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDebug",
+    return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteDebug",
             gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index 89d64fa..d0c592e 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -18,7 +18,7 @@
 
 #include <jni.h>
 #include <JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <sqlite3.h>
 #include <sqlite3_android.h>
@@ -74,15 +74,14 @@
 static JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
-    { "nativeReleaseMemory", "()I",
-            (void*)nativeReleaseMemory },
+    { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory },
 };
 
 int register_android_database_SQLiteGlobal(JNIEnv *env)
 {
     sqliteInitialize();
 
-    return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteGlobal",
+    return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteGlobal",
             sMethods, NELEM(sMethods));
 }
 
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index 9b96320..ae96936 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -20,7 +20,7 @@
 
 #include <JNIHelp.h>
 #include <jni.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -82,7 +82,7 @@
     get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize,
                          &header.totalMemory, &header.backtraceSize);
 
-    ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d",
+    ALOGD("*** mapSize: %zu allocSize: %zu allocInfoSize: %zu totalMemory: %zu",
           header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
 
 #if defined(__LP64__)
@@ -110,7 +110,8 @@
 };
 
 int register_android_ddm_DdmHandleNativeHeap(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table));
+    return RegisterMethodsOrDie(env, "android/ddm/DdmHandleNativeHeap", method_table,
+                                NELEM(method_table));
 }
 
 };
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index f127d29..655b400 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -265,14 +265,6 @@
     return (jclass)env->NewGlobalRef(c);
 }
 
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[])
-{
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(id);
-    return id;
-}
-
 int register_android_emoji_EmojiFactory(JNIEnv* env) {
   gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
   gEmojiFactory_constructorMethodID = env->GetMethodID(
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 96607d2..c337a9f 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -16,12 +16,11 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
-#include "Canvas.h"
+#include <Canvas.h>
 #include "SkDrawFilter.h"
 #include "SkGraphics.h"
-#include "SkPorterDuff.h"
 #include "Paint.h"
 #include "TypefaceImpl.h"
 
@@ -186,8 +185,8 @@
 }
 
 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
-     SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-     get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
+    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
+    get_canvas(canvasHandle)->drawColor(color, mode);
 }
 
 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
@@ -383,7 +382,8 @@
                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
                            kPremul_SkAlphaType);
     SkBitmap bitmap;
-    if (!bitmap.allocPixels(info)) {
+    bitmap.setInfo(info);
+    if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
         return;
     }
 
@@ -411,9 +411,10 @@
 class DrawTextFunctor {
 public:
     DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
-                    const SkPaint& paint, float x, float y, MinikinRect& bounds)
+                    const SkPaint& paint, float x, float y, MinikinRect& bounds,
+                    float totalAdvance)
             : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
-              x(x), y(y), bounds(bounds) { }
+              x(x), y(y), bounds(bounds), totalAdvance(totalAdvance) { }
 
     void operator()(size_t start, size_t end) {
         if (canvas->drawTextAbsolutePos()) {
@@ -432,7 +433,8 @@
 
         size_t glyphCount = end - start;
         canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
-                         bounds.mLeft , bounds.mTop , bounds.mRight , bounds.mBottom);
+                         bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom,
+                         totalAdvance);
     }
 private:
     const Layout& layout;
@@ -443,6 +445,7 @@
     float x;
     float y;
     MinikinRect& bounds;
+    float totalAdvance;
 };
 
 // Same values used by Skia
@@ -494,8 +497,11 @@
 
     MinikinRect bounds;
     layout.getBounds(&bounds);
+    if (!canvas->drawTextAbsolutePos()) {
+        bounds.offset(x, y);
+    }
 
-    DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds);
+    DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds, layout.getAdvance());
     MinikinUtils::forFontRun(layout, &paint, f);
 
     drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
@@ -556,42 +562,6 @@
     env->ReleaseStringChars(text, jchars);
 }
 
-static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
-                             jint index, jint count, jfloatArray pos, jlong paintHandle) {
-    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL;
-    float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
-    int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
-
-    get_canvas(canvasHandle)->drawPosText(jchars + index, posArray, count << 1, posCount, *paint);
-
-    if (text) {
-        env->ReleaseCharArrayElements(text, jchars, 0);
-    }
-    if (pos) {
-        env->ReleaseFloatArrayElements(pos, posArray, 0);
-    }
-}
-
-
-static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
-                              jfloatArray pos, jlong paintHandle) {
-    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL;
-    int byteLength = text ? env->GetStringLength(text) : 0;
-    float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
-    int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
-
-    get_canvas(canvasHandle)->drawPosText(jchars , posArray, byteLength << 1, posCount, *paint);
-
-    if (text) {
-        env->ReleaseStringChars(text, jchars);
-    }
-    if (pos) {
-        env->ReleaseFloatArrayElements(pos, posArray, 0);
-    }
-}
-
 class DrawTextOnPathFunctor {
 public:
     DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
@@ -736,7 +706,7 @@
 };
 
 int register_android_graphics_Canvas(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp
index eb8f6dd..308ee20 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/core/jni/android_graphics_Picture.cpp
@@ -16,7 +16,7 @@
 
 #include "jni.h"
 #include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "Picture.h"
 
@@ -106,7 +106,7 @@
 };
 
 int register_android_graphics_Picture(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, "android/graphics/Picture", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/Picture", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 69f46d3..169fb60 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -21,7 +21,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <android_runtime/android_view_Surface.h>
 
@@ -222,7 +222,7 @@
 
     // Vector access should be protected by lock in postData()
     if (!buffers->isEmpty()) {
-        ALOGV("Using callback buffer from queue of length %d", buffers->size());
+        ALOGV("Using callback buffer from queue of length %zu", buffers->size());
         jbyteArray globalBuffer = buffers->itemAt(0);
         buffers->removeAt(0);
 
@@ -232,7 +232,7 @@
         if (obj != NULL) {
             jsize bufferLength = env->GetArrayLength(obj);
             if ((int)bufferLength < (int)bufferSize) {
-                ALOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!",
+                ALOGE("Callback buffer was too small! Expected %zu bytes, but got %d bytes!",
                     bufferSize, bufferLength);
                 env->DeleteLocalRef(obj);
                 return NULL;
@@ -445,7 +445,7 @@
                 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
                 mCallbackBuffers.push(callbackBuffer);
 
-                ALOGV("Adding callback buffer to queue, %d total",
+                ALOGV("Adding callback buffer to queue, %zu total",
                         mCallbackBuffers.size());
 
                 // We want to make sure the camera knows we're ready for the
@@ -481,7 +481,7 @@
 }
 
 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) {
-    ALOGV("Clearing callback buffers, %d remained", buffers->size());
+    ALOGV("Clearing callback buffers, %zu remained", buffers->size());
     while (!buffers->isEmpty()) {
         env->DeleteGlobalRef(buffers->top());
         buffers->pop();
@@ -517,10 +517,12 @@
     jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
 {
     // Convert jstring to String16
-    const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
+    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
+        env->GetStringChars(clientPackageName, NULL));
     jsize rawClientNameLen = env->GetStringLength(clientPackageName);
     String16 clientName(rawClientName, rawClientNameLen);
-    env->ReleaseStringChars(clientPackageName, rawClientName);
+    env->ReleaseStringChars(clientPackageName,
+                            reinterpret_cast<const jchar*>(rawClientName));
 
     sp<Camera> camera;
     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
@@ -783,7 +785,8 @@
     const jchar* str = env->GetStringCritical(params, 0);
     String8 params8;
     if (params) {
-        params8 = String8(str, env->GetStringLength(params));
+        params8 = String8(reinterpret_cast<const char16_t*>(str),
+                          env->GetStringLength(params));
         env->ReleaseStringCritical(params, str);
     }
     if (camera->setParameters(params8) != NO_ERROR) {
@@ -1031,26 +1034,14 @@
     jfieldID   *jfield;
 };
 
-static int find_fields(JNIEnv *env, field *fields, int count)
+static void find_fields(JNIEnv *env, field *fields, int count)
 {
     for (int i = 0; i < count; i++) {
         field *f = &fields[i];
-        jclass clazz = env->FindClass(f->class_name);
-        if (clazz == NULL) {
-            ALOGE("Can't find %s", f->class_name);
-            return -1;
-        }
-
-        jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
-        if (field == NULL) {
-            ALOGE("Can't find %s.%s", f->class_name, f->field_name);
-            return -1;
-        }
-
+        jclass clazz = FindClassOrDie(env, f->class_name);
+        jfieldID field = GetFieldIDOrDie(env, clazz, f->field_name, f->field_type);
         *(f->jfield) = field;
     }
-
-    return 0;
 }
 
 // Get all the required offsets in java class and register native functions
@@ -1076,30 +1067,17 @@
         { "android/graphics/Point", "y", "I", &fields.point_y},
     };
 
-    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
-        return -1;
+    find_fields(env, fields_to_find, NELEM(fields_to_find));
 
-    jclass clazz = env->FindClass("android/hardware/Camera");
-    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+    jclass clazz = FindClassOrDie(env, "android/hardware/Camera");
+    fields.post_event = GetStaticMethodIDOrDie(env, clazz, "postEventFromNative",
                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-    if (fields.post_event == NULL) {
-        ALOGE("Can't find android/hardware/Camera.postEventFromNative");
-        return -1;
-    }
 
-    clazz = env->FindClass("android/graphics/Rect");
-    fields.rect_constructor = env->GetMethodID(clazz, "<init>", "()V");
-    if (fields.rect_constructor == NULL) {
-        ALOGE("Can't find android/graphics/Rect.Rect()");
-        return -1;
-    }
+    clazz = FindClassOrDie(env, "android/graphics/Rect");
+    fields.rect_constructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
 
-    clazz = env->FindClass("android/hardware/Camera$Face");
-    fields.face_constructor = env->GetMethodID(clazz, "<init>", "()V");
-    if (fields.face_constructor == NULL) {
-        ALOGE("Can't find android/hardware/Camera$Face.Face()");
-        return -1;
-    }
+    clazz = FindClassOrDie(env, "android/hardware/Camera$Face");
+    fields.face_constructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
 
     clazz = env->FindClass("android/graphics/Point");
     fields.point_constructor = env->GetMethodID(clazz, "<init>", "()V");
@@ -1109,6 +1087,5 @@
     }
 
     // Register native functions
-    return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
-                                              camMethods, NELEM(camMethods));
+    return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));
 }
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index ec2bd84..0b737a7 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "SensorManager"
 
+#include <map>
+
 #include <utils/Log.h>
 #include <utils/Looper.h>
 
@@ -28,6 +30,8 @@
 #include "android_os_MessageQueue.h"
 #include <android_runtime/AndroidRuntime.h>
 
+#include "core_jni_helpers.h"
+
 static struct {
     jclass clazz;
     jmethodID dispatchSensorEvent;
@@ -42,7 +46,6 @@
     jfieldID    vendor;
     jfieldID    version;
     jfieldID    handle;
-    jfieldID    type;
     jfieldID    range;
     jfieldID    resolution;
     jfieldID    power;
@@ -53,6 +56,7 @@
     jfieldID    requiredPermission;
     jfieldID    maxDelay;
     jfieldID    flags;
+    jmethodID   setType;
 } gSensorOffsets;
 
 
@@ -69,7 +73,6 @@
     sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
     sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
     sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
-    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
     sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
     sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
     sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
@@ -82,6 +85,47 @@
                                                         "Ljava/lang/String;");
     sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
     sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
+    sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+}
+
+/**
+ * A key comparator predicate.
+ * It is used to intern strings associated with Sensor data.
+ * It defines a 'Strict weak ordering' for the interned strings.
+ */
+class InternedStringCompare {
+public:
+    bool operator()(const String8* string1, const String8* string2) const {
+        if (string1 == NULL) {
+            return string2 != NULL;
+        }
+        return string1->compare(*string2) < 0;
+    }
+};
+
+/**
+ * A localized interning mechanism for Sensor strings.
+ * We implement our own interning to avoid the overhead of using java.lang.String#intern().
+ * It is common that Vendor, StringType, and RequirePermission data is common between many of the
+ * Sensors, by interning the memory usage to represent Sensors is optimized.
+ */
+static jstring
+getInternedString(JNIEnv *env, const String8* string) {
+    static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
+
+    jstring internedString;
+    std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
+    if (iterator != internedStrings.end()) {
+        internedString = iterator->second;
+    } else {
+        jstring localString = env->NewStringUTF(string->string());
+        // we are implementing our own interning so expect these strings to be backed by global refs
+        internedString = (jstring) env->NewGlobalRef(localString);
+        internedStrings.insert(std::make_pair(string, internedString));
+        env->DeleteLocalRef(localString);
+    }
+
+    return internedString;
 }
 
 static jint
@@ -91,20 +135,19 @@
 
     Sensor const* const* sensorList;
     size_t count = mgr.getSensorList(&sensorList);
-    if (size_t(next) >= count)
+    if (size_t(next) >= count) {
         return -1;
+    }
 
     Sensor const* const list = sensorList[next];
     const SensorOffsets& sensorOffsets(gSensorOffsets);
-    jstring name = env->NewStringUTF(list->getName().string());
-    jstring vendor = env->NewStringUTF(list->getVendor().string());
-    jstring stringType = env->NewStringUTF(list->getStringType().string());
-    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
+    jstring name = getInternedString(env, &list->getName());
+    jstring vendor = getInternedString(env, &list->getVendor());
+    jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
     env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
-    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
     env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
     env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
     env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
@@ -113,11 +156,14 @@
                      list->getFifoReservedEventCount());
     env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
                      list->getFifoMaxEventCount());
-    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
     env->SetObjectField(sensor, sensorOffsets.requiredPermission,
                         requiredPermission);
     env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
     env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
+    if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
+        jstring stringType = getInternedString(env, &list->getStringType());
+        env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    }
     next++;
     return size_t(next) < count ? next : 0;
 }
@@ -294,32 +340,22 @@
 
 using namespace android;
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_hardware_SensorManager(JNIEnv *env)
 {
-    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
+    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
             gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
 
-    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
+    RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
             gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
 
-    FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
+    gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
+            "android/hardware/SystemSensorManager$BaseEventQueue");
 
-    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
-            gBaseEventQueueClassInfo.clazz,
-            "dispatchSensorEvent", "(I[FIJ)V");
+    gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
+            gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
 
-    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
-                  gBaseEventQueueClassInfo.clazz,
-                  "dispatchFlushCompleteEvent", "(I)V");
+    gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
+            gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
 
     return 0;
 }
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 7f40a5c..2d2ff4d 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -260,17 +260,9 @@
 
 int register_android_hardware_SerialPort(JNIEnv *env)
 {
-    jclass clazz = env->FindClass("android/hardware/SerialPort");
-    if (clazz == NULL) {
-        ALOGE("Can't find android/hardware/SerialPort");
-        return -1;
-    }
-    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
-    if (field_context == NULL) {
-        ALOGE("Can't find SerialPort.mNativeContext");
-        return -1;
-    }
+    jclass clazz = FindClassOrDie(env, "android/hardware/SerialPort");
+    field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "I");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort",
+    return RegisterMethodsOrDie(env, "android/hardware/SerialPort",
             method_table, NELEM(method_table));
 }
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 2a8e6d6..28e5030 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -21,7 +21,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include <system/sound_trigger.h>
 #include <soundtrigger/SoundTriggerCallback.h>
 #include <soundtrigger/SoundTrigger.h>
@@ -801,112 +801,102 @@
 
 int register_android_hardware_SoundTrigger(JNIEnv *env)
 {
-    jclass arrayListClass = env->FindClass("java/util/ArrayList");
-    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
-    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
+    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
+    gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
 
-    jclass uuidClass = env->FindClass("java/util/UUID");
-    gUUIDClass = (jclass) env->NewGlobalRef(uuidClass);
-    gUUIDMethods.toString = env->GetMethodID(uuidClass, "toString", "()Ljava/lang/String;");
+    jclass uuidClass = FindClassOrDie(env, "java/util/UUID");
+    gUUIDClass = MakeGlobalRefOrDie(env, uuidClass);
+    gUUIDMethods.toString = GetMethodIDOrDie(env, uuidClass, "toString", "()Ljava/lang/String;");
 
-    jclass lClass = env->FindClass(kSoundTriggerClassPathName);
-    gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
+    jclass lClass = FindClassOrDie(env, kSoundTriggerClassPathName);
+    gSoundTriggerClass = MakeGlobalRefOrDie(env, lClass);
 
-    jclass moduleClass = env->FindClass(kModuleClassPathName);
-    gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
-    gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
-                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-    gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
-    gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
+    jclass moduleClass = FindClassOrDie(env, kModuleClassPathName);
+    gModuleClass = MakeGlobalRefOrDie(env, moduleClass);
+    gPostEventFromNative = GetStaticMethodIDOrDie(env, moduleClass, "postEventFromNative",
+                                                  "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    gModuleFields.mNativeContext = GetFieldIDOrDie(env, moduleClass, "mNativeContext", "J");
+    gModuleFields.mId = GetFieldIDOrDie(env, moduleClass, "mId", "I");
 
+    jclass modulePropertiesClass = FindClassOrDie(env, kModulePropertiesClassPathName);
+    gModulePropertiesClass = MakeGlobalRefOrDie(env, modulePropertiesClass);
+    gModulePropertiesCstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
+            "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V");
 
-    jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
-    gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
-    gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
-                              "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V");
+    jclass soundModelClass = FindClassOrDie(env, kSoundModelClassPathName);
+    gSoundModelClass = MakeGlobalRefOrDie(env, soundModelClass);
+    gSoundModelFields.uuid = GetFieldIDOrDie(env, soundModelClass, "uuid", "Ljava/util/UUID;");
+    gSoundModelFields.vendorUuid = GetFieldIDOrDie(env, soundModelClass, "vendorUuid",
+                                                   "Ljava/util/UUID;");
+    gSoundModelFields.data = GetFieldIDOrDie(env, soundModelClass, "data", "[B");
 
-    jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
-    gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
-    gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;");
-    gSoundModelFields.vendorUuid = env->GetFieldID(soundModelClass, "vendorUuid", "Ljava/util/UUID;");
-    gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
+    jclass keyphraseClass = FindClassOrDie(env, kKeyphraseClassPathName);
+    gKeyphraseClass = MakeGlobalRefOrDie(env, keyphraseClass);
+    gKeyphraseFields.id = GetFieldIDOrDie(env, keyphraseClass, "id", "I");
+    gKeyphraseFields.recognitionModes = GetFieldIDOrDie(env, keyphraseClass, "recognitionModes",
+                                                        "I");
+    gKeyphraseFields.locale = GetFieldIDOrDie(env, keyphraseClass, "locale", "Ljava/lang/String;");
+    gKeyphraseFields.text = GetFieldIDOrDie(env, keyphraseClass, "text", "Ljava/lang/String;");
+    gKeyphraseFields.users = GetFieldIDOrDie(env, keyphraseClass, "users", "[I");
 
-    jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName);
-    gKeyphraseClass = (jclass) env->NewGlobalRef(keyphraseClass);
-    gKeyphraseFields.id = env->GetFieldID(keyphraseClass, "id", "I");
-    gKeyphraseFields.recognitionModes = env->GetFieldID(keyphraseClass, "recognitionModes", "I");
-    gKeyphraseFields.locale = env->GetFieldID(keyphraseClass, "locale", "Ljava/lang/String;");
-    gKeyphraseFields.text = env->GetFieldID(keyphraseClass, "text", "Ljava/lang/String;");
-    gKeyphraseFields.users = env->GetFieldID(keyphraseClass, "users", "[I");
-
-    jclass keyphraseSoundModelClass = env->FindClass(kKeyphraseSoundModelClassPathName);
-    gKeyphraseSoundModelClass = (jclass) env->NewGlobalRef(keyphraseSoundModelClass);
-    gKeyphraseSoundModelFields.keyphrases = env->GetFieldID(keyphraseSoundModelClass,
+    jclass keyphraseSoundModelClass = FindClassOrDie(env, kKeyphraseSoundModelClassPathName);
+    gKeyphraseSoundModelClass = MakeGlobalRefOrDie(env, keyphraseSoundModelClass);
+    gKeyphraseSoundModelFields.keyphrases = GetFieldIDOrDie(env, keyphraseSoundModelClass,
                                          "keyphrases",
                                          "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;");
 
-
-    jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
-    gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
-    gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
+    jclass recognitionEventClass = FindClassOrDie(env, kRecognitionEventClassPathName);
+    gRecognitionEventClass = MakeGlobalRefOrDie(env, recognitionEventClass);
+    gRecognitionEventCstor = GetMethodIDOrDie(env, recognitionEventClass, "<init>",
                                               "(IIZIIIZLandroid/media/AudioFormat;[B)V");
 
-    jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName);
-    gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass);
-    gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>",
+    jclass keyphraseRecognitionEventClass = FindClassOrDie(env,
+                                                           kKeyphraseRecognitionEventClassPathName);
+    gKeyphraseRecognitionEventClass = MakeGlobalRefOrDie(env, keyphraseRecognitionEventClass);
+    gKeyphraseRecognitionEventCstor = GetMethodIDOrDie(env, keyphraseRecognitionEventClass, "<init>",
               "(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V");
 
 
-    jclass keyRecognitionConfigClass = env->FindClass(kRecognitionConfigClassPathName);
-    gRecognitionConfigClass = (jclass) env->NewGlobalRef(keyRecognitionConfigClass);
-    gRecognitionConfigFields.captureRequested = env->GetFieldID(keyRecognitionConfigClass,
-                                                              "captureRequested",
-                                                              "Z");
-    gRecognitionConfigFields.keyphrases = env->GetFieldID(keyRecognitionConfigClass,
-                        "keyphrases",
-                        "[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;");
-    gRecognitionConfigFields.data = env->GetFieldID(keyRecognitionConfigClass,
-                                                              "data",
-                                                              "[B");
+    jclass keyRecognitionConfigClass = FindClassOrDie(env, kRecognitionConfigClassPathName);
+    gRecognitionConfigClass = MakeGlobalRefOrDie(env, keyRecognitionConfigClass);
+    gRecognitionConfigFields.captureRequested = GetFieldIDOrDie(env, keyRecognitionConfigClass,
+                                                                "captureRequested", "Z");
+    gRecognitionConfigFields.keyphrases = GetFieldIDOrDie(env, keyRecognitionConfigClass,
+           "keyphrases", "[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;");
+    gRecognitionConfigFields.data = GetFieldIDOrDie(env, keyRecognitionConfigClass, "data", "[B");
 
-    jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName);
-    gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass);
-    gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>",
-                           "(III[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V");
-    gKeyphraseRecognitionExtraFields.id = env->GetFieldID(gKeyphraseRecognitionExtraClass, "id", "I");
-    gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass,
-                                                                        "recognitionModes", "I");
-    gKeyphraseRecognitionExtraFields.coarseConfidenceLevel = env->GetFieldID(gKeyphraseRecognitionExtraClass,
-                                                                        "coarseConfidenceLevel", "I");
-    gKeyphraseRecognitionExtraFields.confidenceLevels = env->GetFieldID(gKeyphraseRecognitionExtraClass,
-                                             "confidenceLevels",
-                                             "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;");
+    jclass keyphraseRecognitionExtraClass = FindClassOrDie(env,
+                                                           kKeyphraseRecognitionExtraClassPathName);
+    gKeyphraseRecognitionExtraClass = MakeGlobalRefOrDie(env, keyphraseRecognitionExtraClass);
+    gKeyphraseRecognitionExtraCstor = GetMethodIDOrDie(env, keyphraseRecognitionExtraClass,
+            "<init>", "(III[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V");
+    gKeyphraseRecognitionExtraFields.id = GetFieldIDOrDie(env, gKeyphraseRecognitionExtraClass,
+                                                          "id", "I");
+    gKeyphraseRecognitionExtraFields.recognitionModes = GetFieldIDOrDie(env,
+            gKeyphraseRecognitionExtraClass, "recognitionModes", "I");
+    gKeyphraseRecognitionExtraFields.coarseConfidenceLevel = GetFieldIDOrDie(env,
+            gKeyphraseRecognitionExtraClass, "coarseConfidenceLevel", "I");
+    gKeyphraseRecognitionExtraFields.confidenceLevels = GetFieldIDOrDie(env,
+            gKeyphraseRecognitionExtraClass, "confidenceLevels",
+            "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;");
 
-    jclass confidenceLevelClass = env->FindClass(kConfidenceLevelClassPathName);
-    gConfidenceLevelClass = (jclass) env->NewGlobalRef(confidenceLevelClass);
-    gConfidenceLevelCstor = env->GetMethodID(confidenceLevelClass, "<init>", "(II)V");
-    gConfidenceLevelFields.userId = env->GetFieldID(confidenceLevelClass, "userId", "I");
-    gConfidenceLevelFields.confidenceLevel = env->GetFieldID(confidenceLevelClass,
+    jclass confidenceLevelClass = FindClassOrDie(env, kConfidenceLevelClassPathName);
+    gConfidenceLevelClass = MakeGlobalRefOrDie(env, confidenceLevelClass);
+    gConfidenceLevelCstor = GetMethodIDOrDie(env, confidenceLevelClass, "<init>", "(II)V");
+    gConfidenceLevelFields.userId = GetFieldIDOrDie(env, confidenceLevelClass, "userId", "I");
+    gConfidenceLevelFields.confidenceLevel = GetFieldIDOrDie(env, confidenceLevelClass,
                                                              "confidenceLevel", "I");
 
-    jclass audioFormatClass = env->FindClass(kAudioFormatClassPathName);
-    gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass);
-    gAudioFormatCstor = env->GetMethodID(audioFormatClass, "<init>", "(III)V");
+    jclass audioFormatClass = FindClassOrDie(env, kAudioFormatClassPathName);
+    gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
+    gAudioFormatCstor = GetMethodIDOrDie(env, audioFormatClass, "<init>", "(III)V");
 
-    jclass soundModelEventClass = env->FindClass(kSoundModelEventClassPathName);
-    gSoundModelEventClass = (jclass) env->NewGlobalRef(soundModelEventClass);
-    gSoundModelEventCstor = env->GetMethodID(soundModelEventClass, "<init>",
-                                              "(II[B)V");
+    jclass soundModelEventClass = FindClassOrDie(env, kSoundModelEventClassPathName);
+    gSoundModelEventClass = MakeGlobalRefOrDie(env, soundModelEventClass);
+    gSoundModelEventCstor = GetMethodIDOrDie(env, soundModelEventClass, "<init>", "(II[B)V");
 
 
-    int status = AndroidRuntime::registerNativeMethods(env,
-                kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
-
-    if (status == 0) {
-        status = AndroidRuntime::registerNativeMethods(env,
-                kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
-    }
-
-
-    return status;
+    RegisterMethodsOrDie(env, kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
 }
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index 25f901b..ef3b646 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <usbhost/usbhost.h>
 
@@ -54,6 +54,6 @@
 
 int register_android_hardware_UsbDevice(JNIEnv *env)
 {
-    return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
+    return RegisterMethodsOrDie(env, "android/hardware/usb/UsbDevice",
             method_table, NELEM(method_table));
 }
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 467a9a1..e0cae6f 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <usbhost/usbhost.h>
 
@@ -268,17 +268,9 @@
 
 int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
 {
-    jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection");
-    if (clazz == NULL) {
-        ALOGE("Can't find android/hardware/usb/UsbDeviceConnection");
-        return -1;
-    }
-    field_context = env->GetFieldID(clazz, "mNativeContext", "J");
-    if (field_context == NULL) {
-        ALOGE("Can't find UsbDeviceConnection.mNativeContext");
-        return -1;
-    }
+    jclass clazz = FindClassOrDie(env, "android/hardware/usb/UsbDeviceConnection");
+    field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
 
-    return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection",
+    return RegisterMethodsOrDie(env, "android/hardware/usb/UsbDeviceConnection",
             method_table, NELEM(method_table));
 }
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index a3c7b0a..ce99e15 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <usbhost/usbhost.h>
 
@@ -215,7 +215,7 @@
         return -1;
     }
 
-    return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbRequest",
+    return RegisterMethodsOrDie(env, "android/hardware/usb/UsbRequest",
             method_table, NELEM(method_table));
 }
 
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 7935329..7c8769d 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -16,7 +16,6 @@
 */
 
 // #define LOG_NDEBUG 0
-// #define LOG_NNDEBUG 0
 #define LOG_TAG "CameraMetadata-JNI"
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -29,7 +28,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_os_Parcel.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
 
 #include <binder/IServiceManager.h>
@@ -42,13 +41,7 @@
 #include <sys/types.h> // for socketpair
 #include <sys/socket.h> // for socketpair
 
-#if defined(LOG_NNDEBUG)
-#if !LOG_NNDEBUG
-#define ALOGVV ALOGV
-#endif
-#else
-#define ALOGVV(...)
-#endif
+static const bool kIsDebug = false;
 
 // fully-qualified class name
 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
@@ -111,8 +104,8 @@
         size_t typeSize = getTypeSize(type);
 
         if (dataBytes % typeSize != 0) {
-            ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize "
-                  "(%ud)", __FUNCTION__, dataBytes, typeSize);
+            ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
+                  "(%zu)", __FUNCTION__, dataBytes, typeSize);
             return BAD_VALUE;
         }
 
@@ -219,7 +212,7 @@
 
     jboolean empty = metadata->isEmpty();
 
-    ALOGV("%s: Empty returned %d, entry count was %d",
+    ALOGV("%s: Empty returned %d, entry count was %zu",
           __FUNCTION__, empty, metadata->entryCount());
 
     return empty;
@@ -315,7 +308,6 @@
                              "Tag (%d) did not have a type", tag);
         return;
     }
-    size_t tagSize = Helpers::getTypeSize(tagType);
 
     status_t res;
 
@@ -597,7 +589,7 @@
 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
 {
     // Register native functions
-    return AndroidRuntime::registerNativeMethods(env,
+    return RegisterMethodsOrDie(env,
             CAMERA_METADATA_CLASS_NAME,
             gCameraMetadataMethods,
             NELEM(gCameraMetadataMethods));
@@ -617,7 +609,7 @@
     if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
         return;
 
-    jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME);
+    env->FindClass(CAMERA_METADATA_CLASS_NAME);
 }
 
 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
@@ -651,12 +643,15 @@
 
         const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
                 vendorSections[i - ANDROID_SECTION_COUNT].string();
-        ALOGVV("%s: Trying to match against section '%s'",
-               __FUNCTION__, str);
+        if (kIsDebug) {
+            ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+        }
         if (strstr(key, str) == key) { // key begins with the section name
             size_t strLength = strlen(str);
 
-            ALOGVV("%s: Key begins with section name", __FUNCTION__);
+            if (kIsDebug) {
+                ALOGV("%s: Key begins with section name", __FUNCTION__);
+            }
 
             // section name is the longest we've found so far
             if (section == NULL || sectionLength < strLength) {
@@ -664,7 +659,9 @@
                 sectionIndex = i;
                 sectionLength = strLength;
 
-                ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
+                if (kIsDebug) {
+                    ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+                }
             }
         }
     }
@@ -676,7 +673,7 @@
                              "Could not find section name for key '%s')", key);
         return 0;
     } else {
-        ALOGV("%s: Found matched section '%s' (%d)",
+        ALOGV("%s: Found matched section '%s' (%zu)",
               __FUNCTION__, section, sectionIndex);
     }
 
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 7361858..5548476 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -16,6 +16,15 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "DngCreator_JNI"
+#include <inttypes.h>
+#include <string.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <cutils/properties.h>
 
 #include <system/camera_metadata.h>
 #include <camera/CameraMetadata.h>
@@ -27,6 +36,7 @@
 #include <img_utils/Input.h>
 #include <img_utils/StripSource.h>
 
+#include "core_jni_helpers.h"
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
@@ -431,7 +441,6 @@
 InputStripSource::~InputStripSource() {}
 
 status_t InputStripSource::writeToStream(Output& stream, uint32_t count) {
-    status_t err = OK;
     uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel;
     jlong offset = mOffset;
 
@@ -765,7 +774,8 @@
             }
         }
         if (uninitialized) {
-            ALOGE("%s: No valid NoiseProfile coefficients for color plane %u", __FUNCTION__, p);
+            ALOGE("%s: No valid NoiseProfile coefficients for color plane %zu",
+                  __FUNCTION__, p);
             return BAD_VALUE;
         }
     }
@@ -809,29 +819,20 @@
 static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
     ALOGV("%s:", __FUNCTION__);
 
-    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
-            ANDROID_DNGCREATOR_CTX_JNI_ID, "J");
-    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
-            "can't find android/hardware/camera2/DngCreator.%s",
-            ANDROID_DNGCREATOR_CTX_JNI_ID);
+    gDngCreatorClassInfo.mNativeContext = GetFieldIDOrDie(env,
+            clazz, ANDROID_DNGCREATOR_CTX_JNI_ID, "J");
 
-    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
-    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
-    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
-    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
+    jclass outputStreamClazz = FindClassOrDie(env, "java/io/OutputStream");
+    gOutputStreamClassInfo.mWriteMethod = GetMethodIDOrDie(env,
+            outputStreamClazz, "write", "([BII)V");
 
-    jclass inputStreamClazz = env->FindClass("java/io/InputStream");
-    LOG_ALWAYS_FATAL_IF(inputStreamClazz == NULL, "Can't find java/io/InputStream class");
-    gInputStreamClassInfo.mReadMethod = env->GetMethodID(inputStreamClazz, "read", "([BII)I");
-    LOG_ALWAYS_FATAL_IF(gInputStreamClassInfo.mReadMethod == NULL, "Can't find read method");
-    gInputStreamClassInfo.mSkipMethod = env->GetMethodID(inputStreamClazz, "skip", "(J)J");
-    LOG_ALWAYS_FATAL_IF(gInputStreamClassInfo.mSkipMethod == NULL, "Can't find skip method");
+    jclass inputStreamClazz = FindClassOrDie(env, "java/io/InputStream");
+    gInputStreamClassInfo.mReadMethod = GetMethodIDOrDie(env, inputStreamClazz, "read", "([BII)I");
+    gInputStreamClassInfo.mSkipMethod = GetMethodIDOrDie(env, inputStreamClazz, "skip", "(J)J");
 
-    jclass inputBufferClazz = env->FindClass("java/nio/ByteBuffer");
-    LOG_ALWAYS_FATAL_IF(inputBufferClazz == NULL, "Can't find java/nio/ByteBuffer class");
-    gInputByteBufferClassInfo.mGetMethod = env->GetMethodID(inputBufferClazz, "get",
-            "([BII)Ljava/nio/ByteBuffer;");
-    LOG_ALWAYS_FATAL_IF(gInputByteBufferClassInfo.mGetMethod == NULL, "Can't find get method");
+    jclass inputBufferClazz = FindClassOrDie(env, "java/nio/ByteBuffer");
+    gInputByteBufferClassInfo.mGetMethod = GetMethodIDOrDie(env,
+            inputBufferClazz, "get", "([BII)Ljava/nio/ByteBuffer;");
 }
 
 static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
@@ -859,7 +860,6 @@
 
     const uint32_t samplesPerPixel = 1;
     const uint32_t bitsPerSample = BITS_PER_SAMPLE;
-    const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
     uint32_t imageWidth = 0;
     uint32_t imageHeight = 0;
 
@@ -1407,8 +1407,9 @@
 
         if (entry.count > 0) {
             if (entry.count != numCfaChannels * 2) {
-                ALOGW("%s: Invalid entry count %u for noise profile returned in characteristics,"
-                        " no noise profile tag written...", __FUNCTION__, entry.count);
+                ALOGW("%s: Invalid entry count %zu for noise profile returned "
+                      "in characteristics, no noise profile tag written...",
+                      __FUNCTION__, entry.count);
             } else {
                 if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels,
                         cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) {
@@ -1643,7 +1644,7 @@
 
     size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
     jlong capacity = env->GetDirectBufferCapacity(buffer);
-    if (capacity != fullSize) {
+    if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
         jniThrowExceptionFmt(env, "java/lang/AssertionError",
                 "Invalid size %d for thumbnail, expected size was %d",
                 capacity, fullSize);
@@ -1803,8 +1804,9 @@
         jint height, jobject inBuffer, jint rowStride, jint pixStride, jlong offset,
         jboolean isDirect) {
     ALOGV("%s:", __FUNCTION__);
-    ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, rowStride=%d, pixStride=%d,"
-              " offset=%lld", __FUNCTION__, width, height, rowStride, pixStride, offset);
+    ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, "
+          "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width,
+          height, rowStride, pixStride, offset);
     uint32_t rStride = static_cast<uint32_t>(rowStride);
     uint32_t pStride = static_cast<uint32_t>(pixStride);
     uint32_t uWidth = static_cast<uint32_t>(width);
@@ -1911,12 +1913,12 @@
     uint32_t uHeight = static_cast<uint32_t>(height);
     uint64_t uOffset = static_cast<uint32_t>(offset);
 
-    ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, rowStride=%u,"
-              "pixStride=%u, offset=%lld", __FUNCTION__, width, height, rowStride, pixStride,
-              offset);
+    ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, "
+          "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width,
+          height, rowStride, pixStride, offset);
 
     sp<JniOutputStream> out = new JniOutputStream(env, outStream);
-    if(env->ExceptionCheck()) {
+    if (env->ExceptionCheck()) {
         ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
         return;
     }
@@ -1990,7 +1992,6 @@
 };
 
 int register_android_hardware_camera2_DngCreator(JNIEnv *env) {
-    return AndroidRuntime::registerNativeMethods(env,
-                   "android/hardware/camera2/DngCreator", gDngCreatorMethods,
-                   NELEM(gDngCreatorMethods));
+    return RegisterMethodsOrDie(env,
+            "android/hardware/camera2/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods));
 }
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 0a6fb9d..87896df 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -23,7 +23,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "android_runtime/android_view_Surface.h"
 #include "android_runtime/android_graphics_SurfaceTexture.h"
 
@@ -52,12 +52,12 @@
  * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
  */
 static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
-        uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
+        uint8_t* crPlane, uint8_t* cbPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
     uint8_t R, G, B;
     size_t index = 0;
     for (size_t j = 0; j < height; j++) {
-        uint8_t* u = uPlane;
-        uint8_t* v = vPlane;
+        uint8_t* cr = crPlane;
+        uint8_t* cb = cbPlane;
         uint8_t* y = yPlane;
         bool jEven = (j & 1) == 0;
         for (size_t i = 0; i < width; i++) {
@@ -66,18 +66,18 @@
             B = rgbBuf[index++];
             *y++ = (77 * R + 150 * G +  29 * B) >> 8;
             if (jEven && (i & 1) == 0) {
-                *v = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
-                *u = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
-                u += chromaStep;
-                v += chromaStep;
+                *cb = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
+                *cr = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
+                cr += chromaStep;
+                cb += chromaStep;
             }
             // Skip alpha
             index++;
         }
         yPlane += yStride;
         if (jEven) {
-            uPlane += chromaStride;
-            vPlane += chromaStride;
+            crPlane += chromaStride;
+            cbPlane += chromaStride;
         }
     }
 }
@@ -315,8 +315,8 @@
         case HAL_PIXEL_FORMAT_BLOB: {
             int8_t* img = NULL;
             struct camera3_jpeg_blob footer = {
-                jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
-                jpeg_size: (uint32_t)bufferLength
+                .jpeg_blob_id = CAMERA3_JPEG_BLOB_ID,
+                .jpeg_size = (uint32_t)bufferLength
             };
 
             size_t totalJpegSize = bufferLength + sizeof(footer);
@@ -622,7 +622,7 @@
         ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
         return 0;
     }
-    sp<IBinder> b = gbp->asBinder();
+    sp<IBinder> b = IInterface::asBinder(gbp);
     if (b == NULL) {
         ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
         return 0;
@@ -740,7 +740,7 @@
 int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
 {
     // Register native functions
-    return AndroidRuntime::registerNativeMethods(env,
+    return RegisterMethodsOrDie(env,
             CAMERA_DEVICE_CLASS_NAME,
             gCameraDeviceMethods,
             NELEM(gCameraDeviceMethods));
diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
index 93473a5..7257597 100644
--- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
+++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
@@ -22,7 +22,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <ui/GraphicBuffer.h>
 #include <system/window.h>
@@ -328,7 +328,7 @@
 int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv* env)
 {
     // Register native functions
-    return AndroidRuntime::registerNativeMethods(env,
+    return RegisterMethodsOrDie(env,
             PERF_MEASUREMENT_CLASS_NAME,
             gPerfMeasurementMethods,
             NELEM(gPerfMeasurementMethods));
diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
index b8fa04c..470c5ba 100644
--- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
+++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
@@ -123,7 +123,7 @@
     detach_thread();
 }
 
-activity_recognition_callback_procs_t sCallbacks {
+activity_recognition_callback_procs_t sCallbacks = {
     activity_callback,
 };
 
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 2b2bee9..df9f893 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -21,7 +21,7 @@
 #include <inttypes.h>
 #include <jni.h>
 #include <JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <utils/Log.h>
 #include <media/AudioRecord.h>
@@ -606,59 +606,28 @@
 
 
     // Get the AudioRecord class
-    jclass audioRecordClass = env->FindClass(kClassPathName);
-    if (audioRecordClass == NULL) {
-        ALOGE("Can't find %s", kClassPathName);
-        return -1;
-    }
+    jclass audioRecordClass = FindClassOrDie(env, kClassPathName);
     // Get the postEvent method
-    javaAudioRecordFields.postNativeEventInJava = env->GetStaticMethodID(
-            audioRecordClass,
-            JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-    if (javaAudioRecordFields.postNativeEventInJava == NULL) {
-        ALOGE("Can't find AudioRecord.%s", JAVA_POSTEVENT_CALLBACK_NAME);
-        return -1;
-    }
+    javaAudioRecordFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
+            audioRecordClass, JAVA_POSTEVENT_CALLBACK_NAME,
+            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
 
     // Get the variables
     //    mNativeRecorderInJavaObj
-    javaAudioRecordFields.nativeRecorderInJavaObj =
-        env->GetFieldID(audioRecordClass,
-                        JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
-    if (javaAudioRecordFields.nativeRecorderInJavaObj == NULL) {
-        ALOGE("Can't find AudioRecord.%s", JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME);
-        return -1;
-    }
+    javaAudioRecordFields.nativeRecorderInJavaObj = GetFieldIDOrDie(env,
+            audioRecordClass, JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME, "J");
     //     mNativeCallbackCookie
-    javaAudioRecordFields.nativeCallbackCookie = env->GetFieldID(
-            audioRecordClass,
-            JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
-    if (javaAudioRecordFields.nativeCallbackCookie == NULL) {
-        ALOGE("Can't find AudioRecord.%s", JAVA_NATIVECALLBACKINFO_FIELD_NAME);
-        return -1;
-    }
+    javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
+            audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");
 
     // Get the AudioAttributes class and fields
-    jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName);
-    if (audioAttrClass == NULL) {
-        ALOGE("Can't find %s", kAudioAttributesClassPathName);
-        return -1;
-    }
-    jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass);
-    javaAudioAttrFields.fieldRecSource = env->GetFieldID(audioAttributesClassRef, "mSource", "I");
-    javaAudioAttrFields.fieldFlags = env->GetFieldID(audioAttributesClassRef, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags =
-            env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;");
-    env->DeleteGlobalRef(audioAttributesClassRef);
-    if (javaAudioAttrFields.fieldRecSource == NULL
-            || javaAudioAttrFields.fieldFlags == NULL
-            || javaAudioAttrFields.fieldFormattedTags == NULL) {
-        ALOGE("Can't initialize AudioAttributes fields");
-        return -1;
-    }
+    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
+    javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
+    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
+    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
+            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
 
-    return AndroidRuntime::registerNativeMethods(env,
-            kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index fee1ead..4a98f27 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -22,7 +22,7 @@
 
 #include <jni.h>
 #include <JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
@@ -298,7 +298,9 @@
     const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
     String8 c_keyValuePairs8;
     if (keyValuePairs) {
-        c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
+        c_keyValuePairs8 = String8(
+            reinterpret_cast<const char16_t*>(c_keyValuePairs),
+            env->GetStringLength(keyValuePairs));
         env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
     }
     int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
@@ -311,7 +313,8 @@
     const jchar* c_keys = env->GetStringCritical(keys, 0);
     String8 c_keys8;
     if (keys) {
-        c_keys8 = String8(c_keys, env->GetStringLength(keys));
+        c_keys8 = String8(reinterpret_cast<const char16_t*>(c_keys),
+                          env->GetStringLength(keys));
         env->ReleaseStringCritical(keys, c_keys);
     }
     return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
@@ -335,13 +338,15 @@
 }
 
 static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
+    const char *c_name = env->GetStringUTFChars(device_name, NULL);
     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                           static_cast <audio_policy_dev_state_t>(state),
-                                          c_address));
+                                          c_address, c_name));
     env->ReleaseStringUTFChars(device_address, c_address);
+    env->ReleaseStringUTFChars(device_name, c_name);
     return (jint) status;
 }
 
@@ -628,6 +633,7 @@
                                            NULL,
                                            NULL,
                                            NULL,
+                                           NULL,
                                            NULL);
         env->DeleteLocalRef(jHandle);
         if (jAudioPort == NULL) {
@@ -785,10 +791,11 @@
     jintArray jFormats = NULL;
     jobjectArray jGains = NULL;
     jobject jHandle = NULL;
+    jstring jDeviceName = NULL;
     bool useInMask;
 
-    ALOGV("convertAudioPortFromNative id %d role %d type %d",
-                                  nAudioPort->id, nAudioPort->role, nAudioPort->type);
+    ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
+        nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
 
     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
     if (jSamplingRates == NULL) {
@@ -868,17 +875,21 @@
         goto exit;
     }
 
+    jDeviceName = env->NewStringUTF(nAudioPort->name);
+
     if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
-                                     jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
+                                     jHandle, jDeviceName,
+                                     jSamplingRates, jChannelMasks, jFormats, jGains,
                                      nAudioPort->ext.device.type, jAddress);
         env->DeleteLocalRef(jAddress);
     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
         ALOGV("convertAudioPortFromNative is a mix");
         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
-                                     jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
+                                     jHandle, nAudioPort->role, jDeviceName,
+                                     jSamplingRates, jChannelMasks,
                                      jFormats, jGains);
     } else {
         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
@@ -902,6 +913,9 @@
     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
 
 exit:
+    if (jDeviceName != NULL) {
+        env->DeleteLocalRef(jDeviceName);
+    }
     if (jSamplingRates != NULL) {
         env->DeleteLocalRef(jSamplingRates);
     }
@@ -1120,7 +1134,7 @@
     return jStatus;
 }
 
-static int
+static jint
 android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
                                                jobject jPatch)
 {
@@ -1142,7 +1156,7 @@
     status_t status = AudioSystem::releaseAudioPatch(handle);
     ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
     jint jStatus = nativeToJavaStatus(status);
-    return status;
+    return jStatus;
 }
 
 static jint
@@ -1222,7 +1236,7 @@
             jStatus = AUDIO_JAVA_ERROR;
             goto exit;
         }
-        ALOGV("listAudioPatches patch %d num_sources %d num_sinks %d",
+        ALOGV("listAudioPatches patch %zu num_sources %d num_sinks %d",
               i, nPatches[i].num_sources, nPatches[i].num_sinks);
 
         env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
@@ -1246,7 +1260,7 @@
             env->SetObjectArrayElement(jSources, j, jSource);
             env->DeleteLocalRef(jSource);
             jSource = NULL;
-            ALOGV("listAudioPatches patch %d source %d is a %s handle %d",
+            ALOGV("listAudioPatches patch %zu source %zu is a %s handle %d",
                   i, j,
                   nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
                   nPatches[i].sources[j].id);
@@ -1271,7 +1285,7 @@
             env->SetObjectArrayElement(jSinks, j, jSink);
             env->DeleteLocalRef(jSink);
             jSink = NULL;
-            ALOGV("listAudioPatches patch %d sink %d is a %s handle %d",
+            ALOGV("listAudioPatches patch %zu sink %zu is a %s handle %d",
                   i, j,
                   nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
                   nPatches[i].sinks[j].id);
@@ -1493,7 +1507,7 @@
     {"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},
+    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/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},
     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
@@ -1540,135 +1554,130 @@
 
 int register_android_media_AudioSystem(JNIEnv *env)
 {
+    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
+    gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
+    gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;");
 
-    jclass arrayListClass = env->FindClass("java/util/ArrayList");
-    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
-    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
-    gArrayListMethods.toArray = env->GetMethodID(arrayListClass, "toArray", "()[Ljava/lang/Object;");
+    jclass audioHandleClass = FindClassOrDie(env, "android/media/AudioHandle");
+    gAudioHandleClass = MakeGlobalRefOrDie(env, audioHandleClass);
+    gAudioHandleCstor = GetMethodIDOrDie(env, audioHandleClass, "<init>", "(I)V");
+    gAudioHandleFields.mId = GetFieldIDOrDie(env, audioHandleClass, "mId", "I");
 
-    jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
-    gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
-    gAudioHandleCstor = env->GetMethodID(audioHandleClass, "<init>", "(I)V");
-    gAudioHandleFields.mId = env->GetFieldID(audioHandleClass, "mId", "I");
-
-    jclass audioPortClass = env->FindClass("android/media/AudioPort");
-    gAudioPortClass = (jclass) env->NewGlobalRef(audioPortClass);
-    gAudioPortCstor = env->GetMethodID(audioPortClass, "<init>",
-                               "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
-    gAudioPortFields.mHandle = env->GetFieldID(audioPortClass, "mHandle",
+    jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
+    gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
+    gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
+    gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
                                                "Landroid/media/AudioHandle;");
-    gAudioPortFields.mRole = env->GetFieldID(audioPortClass, "mRole", "I");
-    gAudioPortFields.mGains = env->GetFieldID(audioPortClass, "mGains",
+    gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
+    gAudioPortFields.mGains = GetFieldIDOrDie(env, audioPortClass, "mGains",
                                               "[Landroid/media/AudioGain;");
-    gAudioPortFields.mActiveConfig = env->GetFieldID(audioPortClass, "mActiveConfig",
-                                              "Landroid/media/AudioPortConfig;");
+    gAudioPortFields.mActiveConfig = GetFieldIDOrDie(env, audioPortClass, "mActiveConfig",
+                                                     "Landroid/media/AudioPortConfig;");
 
-    jclass audioPortConfigClass = env->FindClass("android/media/AudioPortConfig");
-    gAudioPortConfigClass = (jclass) env->NewGlobalRef(audioPortConfigClass);
-    gAudioPortConfigCstor = env->GetMethodID(audioPortConfigClass, "<init>",
-                                 "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
-    gAudioPortConfigFields.mPort = env->GetFieldID(audioPortConfigClass, "mPort",
+    jclass audioPortConfigClass = FindClassOrDie(env, "android/media/AudioPortConfig");
+    gAudioPortConfigClass = MakeGlobalRefOrDie(env, audioPortConfigClass);
+    gAudioPortConfigCstor = GetMethodIDOrDie(env, audioPortConfigClass, "<init>",
+            "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
+    gAudioPortConfigFields.mPort = GetFieldIDOrDie(env, audioPortConfigClass, "mPort",
                                                    "Landroid/media/AudioPort;");
-    gAudioPortConfigFields.mSamplingRate = env->GetFieldID(audioPortConfigClass,
+    gAudioPortConfigFields.mSamplingRate = GetFieldIDOrDie(env, audioPortConfigClass,
                                                            "mSamplingRate", "I");
-    gAudioPortConfigFields.mChannelMask = env->GetFieldID(audioPortConfigClass,
+    gAudioPortConfigFields.mChannelMask = GetFieldIDOrDie(env, audioPortConfigClass,
                                                           "mChannelMask", "I");
-    gAudioPortConfigFields.mFormat = env->GetFieldID(audioPortConfigClass, "mFormat", "I");
-    gAudioPortConfigFields.mGain = env->GetFieldID(audioPortConfigClass, "mGain",
+    gAudioPortConfigFields.mFormat = GetFieldIDOrDie(env, audioPortConfigClass, "mFormat", "I");
+    gAudioPortConfigFields.mGain = GetFieldIDOrDie(env, audioPortConfigClass, "mGain",
                                                    "Landroid/media/AudioGainConfig;");
-    gAudioPortConfigFields.mConfigMask = env->GetFieldID(audioPortConfigClass, "mConfigMask", "I");
+    gAudioPortConfigFields.mConfigMask = GetFieldIDOrDie(env, audioPortConfigClass, "mConfigMask",
+                                                         "I");
 
-    jclass audioDevicePortConfigClass = env->FindClass("android/media/AudioDevicePortConfig");
-    gAudioDevicePortConfigClass = (jclass) env->NewGlobalRef(audioDevicePortConfigClass);
-    gAudioDevicePortConfigCstor = env->GetMethodID(audioDevicePortConfigClass, "<init>",
-                         "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
+    jclass audioDevicePortConfigClass = FindClassOrDie(env, "android/media/AudioDevicePortConfig");
+    gAudioDevicePortConfigClass = MakeGlobalRefOrDie(env, audioDevicePortConfigClass);
+    gAudioDevicePortConfigCstor = GetMethodIDOrDie(env, audioDevicePortConfigClass, "<init>",
+            "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
 
-    jclass audioMixPortConfigClass = env->FindClass("android/media/AudioMixPortConfig");
-    gAudioMixPortConfigClass = (jclass) env->NewGlobalRef(audioMixPortConfigClass);
-    gAudioMixPortConfigCstor = env->GetMethodID(audioMixPortConfigClass, "<init>",
-                         "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
+    jclass audioMixPortConfigClass = FindClassOrDie(env, "android/media/AudioMixPortConfig");
+    gAudioMixPortConfigClass = MakeGlobalRefOrDie(env, audioMixPortConfigClass);
+    gAudioMixPortConfigCstor = GetMethodIDOrDie(env, audioMixPortConfigClass, "<init>",
+            "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
 
-    jclass audioDevicePortClass = env->FindClass("android/media/AudioDevicePort");
-    gAudioDevicePortClass = (jclass) env->NewGlobalRef(audioDevicePortClass);
-    gAudioDevicePortCstor = env->GetMethodID(audioDevicePortClass, "<init>",
-             "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
+    jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
+    gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
+    gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
+            "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
 
-    jclass audioMixPortClass = env->FindClass("android/media/AudioMixPort");
-    gAudioMixPortClass = (jclass) env->NewGlobalRef(audioMixPortClass);
-    gAudioMixPortCstor = env->GetMethodID(audioMixPortClass, "<init>",
-                              "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
+    jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
+    gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
+    gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
+            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
 
-    jclass audioGainClass = env->FindClass("android/media/AudioGain");
-    gAudioGainClass = (jclass) env->NewGlobalRef(audioGainClass);
-    gAudioGainCstor = env->GetMethodID(audioGainClass, "<init>", "(IIIIIIIII)V");
+    jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
+    gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
+    gAudioGainCstor = GetMethodIDOrDie(env, audioGainClass, "<init>", "(IIIIIIIII)V");
 
-    jclass audioGainConfigClass = env->FindClass("android/media/AudioGainConfig");
-    gAudioGainConfigClass = (jclass) env->NewGlobalRef(audioGainConfigClass);
-    gAudioGainConfigCstor = env->GetMethodID(audioGainConfigClass, "<init>",
+    jclass audioGainConfigClass = FindClassOrDie(env, "android/media/AudioGainConfig");
+    gAudioGainConfigClass = MakeGlobalRefOrDie(env, audioGainConfigClass);
+    gAudioGainConfigCstor = GetMethodIDOrDie(env, audioGainConfigClass, "<init>",
                                              "(ILandroid/media/AudioGain;II[II)V");
-    gAudioGainConfigFields.mIndex = env->GetFieldID(gAudioGainConfigClass, "mIndex", "I");
-    gAudioGainConfigFields.mMode = env->GetFieldID(audioGainConfigClass, "mMode", "I");
-    gAudioGainConfigFields.mChannelMask = env->GetFieldID(audioGainConfigClass, "mChannelMask",
+    gAudioGainConfigFields.mIndex = GetFieldIDOrDie(env, gAudioGainConfigClass, "mIndex", "I");
+    gAudioGainConfigFields.mMode = GetFieldIDOrDie(env, audioGainConfigClass, "mMode", "I");
+    gAudioGainConfigFields.mChannelMask = GetFieldIDOrDie(env, audioGainConfigClass, "mChannelMask",
                                                           "I");
-    gAudioGainConfigFields.mValues = env->GetFieldID(audioGainConfigClass, "mValues", "[I");
-    gAudioGainConfigFields.mRampDurationMs = env->GetFieldID(audioGainConfigClass,
+    gAudioGainConfigFields.mValues = GetFieldIDOrDie(env, audioGainConfigClass, "mValues", "[I");
+    gAudioGainConfigFields.mRampDurationMs = GetFieldIDOrDie(env, audioGainConfigClass,
                                                              "mRampDurationMs", "I");
 
-    jclass audioPatchClass = env->FindClass("android/media/AudioPatch");
-    gAudioPatchClass = (jclass) env->NewGlobalRef(audioPatchClass);
-    gAudioPatchCstor = env->GetMethodID(audioPatchClass, "<init>",
+    jclass audioPatchClass = FindClassOrDie(env, "android/media/AudioPatch");
+    gAudioPatchClass = MakeGlobalRefOrDie(env, audioPatchClass);
+    gAudioPatchCstor = GetMethodIDOrDie(env, audioPatchClass, "<init>",
 "(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
-    gAudioPatchFields.mHandle = env->GetFieldID(audioPatchClass, "mHandle",
+    gAudioPatchFields.mHandle = GetFieldIDOrDie(env, audioPatchClass, "mHandle",
                                                 "Landroid/media/AudioHandle;");
 
-    jclass eventHandlerClass = env->FindClass(kEventHandlerClassPathName);
-    gPostEventFromNative = env->GetStaticMethodID(eventHandlerClass, "postEventFromNative",
-                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
+    gPostEventFromNative = GetStaticMethodIDOrDie(env, eventHandlerClass, "postEventFromNative",
+                                                  "(Ljava/lang/Object;IIILjava/lang/Object;)V");
 
 
-    jclass audioMixClass = env->FindClass("android/media/audiopolicy/AudioMix");
-    gAudioMixClass = (jclass) env->NewGlobalRef(audioMixClass);
-    gAudioMixFields.mRule = env->GetFieldID(audioMixClass, "mRule",
+    jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
+    gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
+    gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
                                                 "Landroid/media/audiopolicy/AudioMixingRule;");
-    gAudioMixFields.mFormat = env->GetFieldID(audioMixClass, "mFormat",
+    gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
                                                 "Landroid/media/AudioFormat;");
-    gAudioMixFields.mRouteFlags = env->GetFieldID(audioMixClass, "mRouteFlags", "I");
-    gAudioMixFields.mRegistrationId = env->GetFieldID(audioMixClass, "mRegistrationId",
+    gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
+    gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
                                                       "Ljava/lang/String;");
-    gAudioMixFields.mMixType = env->GetFieldID(audioMixClass, "mMixType", "I");
+    gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
 
-    jclass audioFormatClass = env->FindClass("android/media/AudioFormat");
-    gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass);
-    gAudioFormatFields.mEncoding = env->GetFieldID(audioFormatClass, "mEncoding", "I");
-    gAudioFormatFields.mSampleRate = env->GetFieldID(audioFormatClass, "mSampleRate", "I");
-    gAudioFormatFields.mChannelMask = env->GetFieldID(audioFormatClass, "mChannelMask", "I");
+    jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
+    gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
+    gAudioFormatFields.mEncoding = GetFieldIDOrDie(env, audioFormatClass, "mEncoding", "I");
+    gAudioFormatFields.mSampleRate = GetFieldIDOrDie(env, audioFormatClass, "mSampleRate", "I");
+    gAudioFormatFields.mChannelMask = GetFieldIDOrDie(env, audioFormatClass, "mChannelMask", "I");
 
-    jclass audioMixingRuleClass = env->FindClass("android/media/audiopolicy/AudioMixingRule");
-    gAudioMixingRuleClass = (jclass) env->NewGlobalRef(audioMixingRuleClass);
-    gAudioMixingRuleFields.mCriteria = env->GetFieldID(audioMixingRuleClass, "mCriteria",
+    jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
+    gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
+    gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
                                                        "Ljava/util/ArrayList;");
 
     jclass attributeMatchCriterionClass =
-                env->FindClass("android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion");
-    gAttributeMatchCriterionClass = (jclass) env->NewGlobalRef(attributeMatchCriterionClass);
-    gAttributeMatchCriterionFields.mAttr = env->GetFieldID(attributeMatchCriterionClass, "mAttr",
+                FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion");
+    gAttributeMatchCriterionClass = MakeGlobalRefOrDie(env, attributeMatchCriterionClass);
+    gAttributeMatchCriterionFields.mAttr = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mAttr",
                                                        "Landroid/media/AudioAttributes;");
-    gAttributeMatchCriterionFields.mRule = env->GetFieldID(attributeMatchCriterionClass, "mRule",
+    gAttributeMatchCriterionFields.mRule = GetFieldIDOrDie(env, attributeMatchCriterionClass, "mRule",
                                                        "I");
 
-    jclass audioAttributesClass = env->FindClass("android/media/AudioAttributes");
-    gAudioAttributesClass = (jclass) env->NewGlobalRef(audioAttributesClass);
-    gAudioAttributesFields.mUsage = env->GetFieldID(audioAttributesClass, "mUsage", "I");
-    gAudioAttributesFields.mSource = env->GetFieldID(audioAttributesClass, "mSource", "I");
+    jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
+    gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
+    gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
+    gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
 
     AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
 
-    int status = AndroidRuntime::registerNativeMethods(env,
-                kClassPathName, gMethods, NELEM(gMethods));
-
-    if (status == 0) {
-        status = AndroidRuntime::registerNativeMethods(env,
-                kEventHandlerClassPathName, gEventHandlerMethods, NELEM(gEventHandlerMethods));
-    }
-    return status;
+    RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kEventHandlerClassPathName, gEventHandlerMethods,
+                                NELEM(gEventHandlerMethods));
 }
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index ab38864..a7a925f 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -19,7 +19,7 @@
 
 #include <JNIHelp.h>
 #include <JniConstants.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "ScopedBytes.h"
 
@@ -215,19 +215,6 @@
         return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
     }
 
-    // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
-    // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
-    // in android_media_AudioTrack_native_write_byte()
-    if ((format == AUDIO_FORMAT_PCM_8_BIT)
-        && (memoryMode == MODE_STATIC)) {
-        ALOGV("android_media_AudioTrack_setup(): requesting MODE_STATIC for 8bit \
-            buff size of %dbytes, switching to 16bit, buff size of %dbytes",
-            buffSizeInBytes, 2*buffSizeInBytes);
-        format = AUDIO_FORMAT_PCM_16_BIT;
-        // we will need twice the memory to store the data
-        buffSizeInBytes *= 2;
-    }
-
     // compute the frame count
     size_t frameCount;
     if (audio_is_linear_pcm(format)) {
@@ -523,41 +510,14 @@
             written = 0;
         }
     } else {
-        const audio_format_t format = audioFormatToNative(audioFormat);
-        switch (format) {
-
-        default:
-        case AUDIO_FORMAT_PCM_FLOAT:
-        case AUDIO_FORMAT_PCM_16_BIT: {
-            // writing to shared memory, check for capacity
-            if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
-                sizeInBytes = track->sharedBuffer()->size();
-            }
-            memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
-            written = sizeInBytes;
-            } break;
-
-        case AUDIO_FORMAT_PCM_8_BIT: {
-            // data contains 8bit data we need to expand to 16bit before copying
-            // to the shared memory
-            // writing to shared memory, check for capacity,
-            // note that input data will occupy 2X the input space due to 8 to 16bit conversion
-            if (((size_t)sizeInBytes)*2 > track->sharedBuffer()->size()) {
-                sizeInBytes = track->sharedBuffer()->size() / 2;
-            }
-            int count = sizeInBytes;
-            int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
-            const uint8_t *src = (const uint8_t *)(data + offsetInBytes);
-            memcpy_to_i16_from_u8(dst, src, count);
-            // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
-            // the 8bit mixer restriction from the user of this function
-            written = sizeInBytes;
-            } break;
-
+        // writing to shared memory, check for capacity
+        if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
+            sizeInBytes = track->sharedBuffer()->size();
         }
+        memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
+        written = sizeInBytes;
     }
     return written;
-
 }
 
 // ----------------------------------------------------------------------------
@@ -1062,68 +1022,34 @@
     javaAudioTrackFields.postNativeEventInJava = NULL;
 
     // Get the AudioTrack class
-    jclass audioTrackClass = env->FindClass(kClassPathName);
-    if (audioTrackClass == NULL) {
-        ALOGE("Can't find %s", kClassPathName);
-        return -1;
-    }
+    jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
 
     // Get the postEvent method
-    javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
-            audioTrackClass,
-            JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-    if (javaAudioTrackFields.postNativeEventInJava == NULL) {
-        ALOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
-        return -1;
-    }
+    javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
+            audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
+            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
 
     // Get the variables fields
     //      nativeTrackInJavaObj
-    javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
-            audioTrackClass,
-            JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
-    if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
-        ALOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
-        return -1;
-    }
+    javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
+            audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
     //      jniData
-    javaAudioTrackFields.jniData = env->GetFieldID(
-            audioTrackClass,
-            JAVA_JNIDATA_FIELD_NAME, "J");
-    if (javaAudioTrackFields.jniData == NULL) {
-        ALOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
-        return -1;
-    }
+    javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
+            audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
     //      fieldStreamType
-    javaAudioTrackFields.fieldStreamType = env->GetFieldID(audioTrackClass,
-            JAVA_STREAMTYPE_FIELD_NAME, "I");
-    if (javaAudioTrackFields.fieldStreamType == NULL) {
-        ALOGE("Can't find AudioTrack.%s", JAVA_STREAMTYPE_FIELD_NAME);
-        return -1;
-    }
+    javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
+            audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
 
     // Get the AudioAttributes class and fields
-    jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName);
-    if (audioAttrClass == NULL) {
-        ALOGE("Can't find %s", kAudioAttributesClassPathName);
-        return -1;
-    }
-    jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass);
-    javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I");
-    javaAudioAttrFields.fieldContentType
-                                   = env->GetFieldID(audioAttributesClassRef, "mContentType", "I");
-    javaAudioAttrFields.fieldFlags = env->GetFieldID(audioAttributesClassRef, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags =
-            env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;");
-    env->DeleteGlobalRef(audioAttributesClassRef);
-    if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL
-            || javaAudioAttrFields.fieldFlags == NULL
-            || javaAudioAttrFields.fieldFormattedTags == NULL) {
-        ALOGE("Can't initialize AudioAttributes fields");
-        return -1;
-    }
+    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
+    javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
+    javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
+            audioAttrClass, "mContentType", "I");
+    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
+    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
+            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
 
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index 69f5711..d441f10 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -24,7 +24,7 @@
 
 #include <jni.h>
 #include <JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <utils/Log.h>
 #include <media/JetPlayer.h>
@@ -517,36 +517,22 @@
 
 int register_android_media_JetPlayer(JNIEnv *env)
 {
-    jclass jetPlayerClass = NULL;
     javaJetPlayerFields.jetClass = NULL;
     javaJetPlayerFields.postNativeEventInJava = NULL;
     javaJetPlayerFields.nativePlayerInJavaObj = NULL;
 
     // Get the JetPlayer java class
-    jetPlayerClass = env->FindClass(kClassPathName);
-    if (jetPlayerClass == NULL) {
-        ALOGE("Can't find %s", kClassPathName);
-        return -1;
-    }
-    javaJetPlayerFields.jetClass = (jclass)env->NewGlobalRef(jetPlayerClass);
+    jclass jetPlayerClass = FindClassOrDie(env, kClassPathName);
+    javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass);
 
     // Get the mNativePlayerInJavaObj variable field
-    javaJetPlayerFields.nativePlayerInJavaObj = env->GetFieldID(
-            jetPlayerClass,
-            JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
-    if (javaJetPlayerFields.nativePlayerInJavaObj == NULL) {
-        ALOGE("Can't find JetPlayer.%s", JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME);
-        return -1;
-    }
+    javaJetPlayerFields.nativePlayerInJavaObj = GetFieldIDOrDie(env,
+            jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
 
     // Get the callback to post events from this native code to Java
-    javaJetPlayerFields.postNativeEventInJava = env->GetStaticMethodID(javaJetPlayerFields.jetClass,
-            JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;III)V");
-    if (javaJetPlayerFields.postNativeEventInJava == NULL) {
-        ALOGE("Can't find Jet.%s", JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME);
-        return -1;
-    }
+    javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
+            javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME,
+            "(Ljava/lang/Object;III)V");
 
-    return AndroidRuntime::registerNativeMethods(env,
-            kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 1cd3fbb..e2bba30 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -22,7 +22,7 @@
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/Log.h>
 
@@ -188,17 +188,15 @@
 
 int register_android_media_RemoteDisplay(JNIEnv* env)
 {
-    int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
-            gMethods, NELEM(gMethods));
+    int err = RegisterMethodsOrDie(env, "android/media/RemoteDisplay", gMethods, NELEM(gMethods));
 
-    jclass clazz = env->FindClass("android/media/RemoteDisplay");
-    gRemoteDisplayClassInfo.notifyDisplayConnected =
-            env->GetMethodID(clazz, "notifyDisplayConnected",
-                    "(Landroid/view/Surface;IIII)V");
-    gRemoteDisplayClassInfo.notifyDisplayDisconnected =
-            env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
-    gRemoteDisplayClassInfo.notifyDisplayError =
-            env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
+    jclass clazz = FindClassOrDie(env, "android/media/RemoteDisplay");
+    gRemoteDisplayClassInfo.notifyDisplayConnected = GetMethodIDOrDie(env,
+            clazz, "notifyDisplayConnected", "(Landroid/view/Surface;IIII)V");
+    gRemoteDisplayClassInfo.notifyDisplayDisconnected = GetMethodIDOrDie(env,
+            clazz, "notifyDisplayDisconnected", "()V");
+    gRemoteDisplayClassInfo.notifyDisplayError = GetMethodIDOrDie(env,
+            clazz, "notifyDisplayError", "(I)V");
     return err;
 }
 
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index ca00709..243f040 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -23,7 +23,7 @@
 
 #include <jni.h>
 #include <JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <utils/Log.h>
 #include <media/AudioSystem.h>
@@ -134,21 +134,10 @@
 
 
 int register_android_media_ToneGenerator(JNIEnv *env) {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, "android/media/ToneGenerator");
 
-    clazz = env->FindClass("android/media/ToneGenerator");
-    if (clazz == NULL) {
-        ALOGE("Can't find %s", "android/media/ToneGenerator");
-        return -1;
-    }
-
-    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
-    if (fields.context == NULL) {
-        ALOGE("Can't find ToneGenerator.mNativeContext");
-        return -1;
-    }
+    fields.context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
     ALOGV("register_android_media_ToneGenerator ToneGenerator fields.context: %p", fields.context);
 
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/media/ToneGenerator", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/media/ToneGenerator", gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 98f4bed..97abe6b 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -39,6 +39,9 @@
 
 namespace android {
 
+template <typename T>
+void UNUSED(T t) {}
+
 static jfieldID field_inboundFileDescriptors;
 static jfieldID field_outboundFileDescriptors;
 static jclass class_Credentials;
@@ -57,7 +60,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -95,7 +98,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -118,7 +121,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -154,7 +157,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return NULL;
     }
 
@@ -184,7 +187,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -246,7 +249,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return 0;
     }
 
@@ -293,7 +296,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -353,7 +356,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return (jint)-1;
     }
 
@@ -378,7 +381,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return (jint)-1;
     }
 
@@ -459,20 +462,20 @@
                 jobject fdObject
                         = jniCreateFileDescriptor(env, pDescriptors[i]);
 
-                if (env->ExceptionOccurred() != NULL) {
+                if (env->ExceptionCheck()) {
                     return -1;
                 }
 
                 env->SetObjectArrayElement(fdArray, i, fdObject);
 
-                if (env->ExceptionOccurred() != NULL) {
+                if (env->ExceptionCheck()) {
                     return -1;
                 }
             }
 
             env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
 
-            if (env->ExceptionOccurred() != NULL) {
+            if (env->ExceptionCheck()) {
                 return -1;
             }
         }
@@ -492,7 +495,6 @@
         void *buffer, size_t len)
 {
     ssize_t ret;
-    ssize_t bytesread = 0;
     struct msghdr msg;
     struct iovec iv;
     unsigned char *buf = (unsigned char *)buffer;
@@ -558,7 +560,7 @@
             = (jobjectArray)env->GetObjectField(
                 object, field_outboundFileDescriptors);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return -1;
     }
 
@@ -570,18 +572,18 @@
     // Add any pending outbound file descriptors to the message
     if (outboundFds != NULL) {
 
-        if (env->ExceptionOccurred() != NULL) {
+        if (env->ExceptionCheck()) {
             return -1;
         }
 
         for (int i = 0; i < countFds; i++) {
             jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
-            if (env->ExceptionOccurred() != NULL) {
+            if (env->ExceptionCheck()) {
                 return -1;
             }
 
             fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
-            if (env->ExceptionOccurred() != NULL) {
+            if (env->ExceptionCheck()) {
                 return -1;
             }
         }
@@ -638,7 +640,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return (jint)0;
     }
 
@@ -683,7 +685,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return (jint)-1;
     }
 
@@ -717,12 +719,12 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
     err = socket_write_all(env, object, fd, &b, 1);
-
+    UNUSED(err);
     // A return of -1 above means an exception is pending
 }
 
@@ -745,7 +747,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return;
     }
 
@@ -758,7 +760,7 @@
 
     err = socket_write_all(env, object, fd,
             byteBuffer + off, len);
-
+    UNUSED(err);
     // A return of -1 above means an exception is pending
 
     env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT);
@@ -777,7 +779,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return NULL;
     }
 
@@ -816,7 +818,7 @@
 
     fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         return NULL;
     }
 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index e64f1de..f283675 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -19,13 +19,14 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "NetdClient.h"
-#include "resolv_netid.h"
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 #include <arpa/inet.h>
 #include <cutils/properties.h>
 
+#include "core_jni_helpers.h"
+
 extern "C" {
 int ifc_enable(const char *ifname);
 int ifc_disable(const char *ifname);
@@ -265,27 +266,26 @@
 
 int register_android_net_NetworkUtils(JNIEnv* env)
 {
-    jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults");
-    LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
-    dhcpResultsFieldIds.clear =
-            env->GetMethodID(dhcpResultsClass, "clear", "()V");
-    dhcpResultsFieldIds.setIpAddress =
-            env->GetMethodID(dhcpResultsClass, "setIpAddress", "(Ljava/lang/String;I)Z");
-    dhcpResultsFieldIds.setGateway =
-            env->GetMethodID(dhcpResultsClass, "setGateway", "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.addDns =
-            env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.setDomains =
-            env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V");
-    dhcpResultsFieldIds.setServerAddress =
-            env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.setLeaseDuration =
-            env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V");
-    dhcpResultsFieldIds.setVendorInfo =
-            env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V");
+    jclass dhcpResultsClass = FindClassOrDie(env, "android/net/DhcpResults");
 
-    return AndroidRuntime::registerNativeMethods(env,
-            NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
+    dhcpResultsFieldIds.clear = GetMethodIDOrDie(env, dhcpResultsClass, "clear", "()V");
+    dhcpResultsFieldIds.setIpAddress =GetMethodIDOrDie(env, dhcpResultsClass, "setIpAddress",
+            "(Ljava/lang/String;I)Z");
+    dhcpResultsFieldIds.setGateway = GetMethodIDOrDie(env, dhcpResultsClass, "setGateway",
+            "(Ljava/lang/String;)Z");
+    dhcpResultsFieldIds.addDns = GetMethodIDOrDie(env, dhcpResultsClass, "addDns",
+            "(Ljava/lang/String;)Z");
+    dhcpResultsFieldIds.setDomains = GetMethodIDOrDie(env, dhcpResultsClass, "setDomains",
+            "(Ljava/lang/String;)V");
+    dhcpResultsFieldIds.setServerAddress = GetMethodIDOrDie(env, dhcpResultsClass,
+            "setServerAddress", "(Ljava/lang/String;)Z");
+    dhcpResultsFieldIds.setLeaseDuration = GetMethodIDOrDie(env, dhcpResultsClass,
+            "setLeaseDuration", "(I)V");
+    dhcpResultsFieldIds.setVendorInfo = GetMethodIDOrDie(env, dhcpResultsClass, "setVendorInfo",
+            "(Ljava/lang/String;)V");
+
+    return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
+                                NELEM(gNetworkUtilMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 031637f..7354417 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -23,7 +23,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <jni.h>
 #include <ScopedUtfChars.h>
 #include <utils/misc.h>
@@ -192,8 +192,7 @@
 };
 
 int register_android_net_TrafficStats(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, "android/net/TrafficStats",
-            gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/net/TrafficStats", gMethods, NELEM(gMethods));
 }
 
 }
diff --git a/core/jni/android_nfc.h b/core/jni/android_nfc.h
deleted file mode 100644
index 36346e3..0000000
--- a/core/jni/android_nfc.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Contains the bare minimum header so that framework NFC jni can link
- * against NFC native library
- */
-
-#ifndef __ANDROID_NFC_H__
-#define __ANDROID_NFC_H__
-
-#define LOG_TAG "NdefMessage"
-#include <utils/Log.h>
-
-extern "C" {
-
-#if 0
-  #define TRACE(...) ALOG(LOG_DEBUG, "NdefMessage", __VA_ARGS__)
-#else
-  #define TRACE(...)
-#endif
-
-typedef struct phFriNfc_NdefRecord {
-    uint8_t                 Flags;
-    uint8_t                 Tnf;
-    uint8_t                 TypeLength;
-    uint8_t                *Type;
-    uint8_t                 IdLength;
-    uint8_t                *Id;
-    uint32_t                PayloadLength;
-    uint8_t                *PayloadData;
-} phFriNfc_NdefRecord_t;
-
-uint16_t phFriNfc_NdefRecord_GetRecords(uint8_t*      pBuffer,
-                                        uint32_t      BufferLength,
-                                        uint8_t*      pRawRecords[ ],
-                                        uint8_t       IsChunked[ ],
-                                        uint32_t*     pNumberOfRawRecords
-                                        );
-uint16_t phFriNfc_NdefRecord_Parse(phFriNfc_NdefRecord_t* pRecord,
-                                   uint8_t*               pRawRecord);
-
-uint16_t phFriNfc_NdefRecord_Generate(phFriNfc_NdefRecord_t*  pRecord,
-                                      uint8_t*                pBuffer,
-                                      uint32_t                MaxBufferSize,
-                                      uint32_t*               pBytesWritten
-                                      );
-}
-
-#endif
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index 59d6e41..ed8c603 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -16,6 +16,8 @@
 
 #include "android_nio_utils.h"
 
+#include "core_jni_helpers.h"
+
 struct NioJNIData {
     jclass nioAccessClass;
 
@@ -73,39 +75,19 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static jclass findClass(JNIEnv* env, const char name[]) {
-    jclass c = env->FindClass(name);
-    LOG_FATAL_IF(!c, "Unable to find class %s", name);
-    return c;
-}
-
-static jmethodID findStaticMethod(JNIEnv* env, jclass c, const char method[],
-                                  const char params[]) {
-    jmethodID m = env->GetStaticMethodID(c, method, params);
-    LOG_FATAL_IF(!m, "Unable to find method %s", method);
-    return m;
-}
-
-static jfieldID getFieldID(JNIEnv* env, jclass c, const char name[],
-                           const char type[]) {
-    jfieldID f = env->GetFieldID(c, name, type);
-    LOG_FATAL_IF(!f, "Unable to find field %s", name);
-    return f;
-}
-
 namespace android {
 
 int register_android_nio_utils(JNIEnv* env) {
-    jclass localClass = findClass(env, "java/nio/NIOAccess");
-    gNioJNI.getBasePointerID = findStaticMethod(env, localClass,
-                                    "getBasePointer", "(Ljava/nio/Buffer;)J");
-    gNioJNI.getBaseArrayID = findStaticMethod(env, localClass,
-                    "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
-    gNioJNI.getBaseArrayOffsetID = findStaticMethod(env, localClass,
-                                "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+    jclass localClass = FindClassOrDie(env, "java/nio/NIOAccess");
+    gNioJNI.getBasePointerID = GetStaticMethodIDOrDie(env, localClass, "getBasePointer",
+                                                      "(Ljava/nio/Buffer;)J");
+    gNioJNI.getBaseArrayID = GetStaticMethodIDOrDie(env, localClass, "getBaseArray",
+                                                    "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    gNioJNI.getBaseArrayOffsetID = GetStaticMethodIDOrDie(env, localClass, "getBaseArrayOffset",
+                                                          "(Ljava/nio/Buffer;)I");
 
     // now record a permanent version of the class ID
-    gNioJNI.nioAccessClass = (jclass) env->NewGlobalRef(localClass);
+    gNioJNI.nioAccessClass = MakeGlobalRefOrDie(env, localClass);
 
     return 0;
 }
diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h
index 69c360c..c634cb91 100644
--- a/core/jni/android_nio_utils.h
+++ b/core/jni/android_nio_utils.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef android_nio_utils_DEFINED
-#define android_nio_utils_DEFINED
+#ifndef _ANDROID_NIO_UTILS_H_
+#define _ANDROID_NIO_UTILS_H_
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -58,17 +58,16 @@
 public:
     AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit);
     ~AutoBufferPointer();
-    
+
     void* pointer() const { return fPointer; }
-    
+
 private:
     JNIEnv* fEnv;
     void*   fPointer;
     jarray  fArray;
-    jint    fRemaining;
     jboolean fCommit;
 };
 
 }   /* namespace android */
 
-#endif
+#endif  // _ANDROID_NIO_UTILS_H_
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 19e4d99..36f7963 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -16,6 +16,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -156,7 +160,8 @@
 android_eglGetDisplayInt
   (JNIEnv *_env, jobject _this, jint display_id) {
 
-    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+    if (static_cast<uintptr_t>(display_id) !=
+        reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
         jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
         return 0;
     }
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 15899f5..60a3bf6 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -16,6 +16,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -81,23 +85,19 @@
     eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
     eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
 
-    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
-    eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
-    eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
-    eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
-
 
     jclass eglClass = _env->FindClass("android/opengl/EGL14");
     jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
-    _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
+    jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID);
+    eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
 
     jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
-    _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
+    jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID);
+    eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
 
     jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
-    _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
+    jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID);
+    eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
 }
 
 static void *
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 0a39a8e..c9b68bf 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 83d9bda..4f1eaa5 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index a292cf2..08c4740 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 4ee5f15..21e5670f 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index 60ab37b..cd0c135 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index ba324b0..226162d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES3/gl3.h>
 #include <GLES3/gl3ext.h>
 
@@ -1931,7 +1935,11 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        // The cast below is incorrect. The driver will end up writing to the
+        // address specified by name, which will always crash the process since
+        // it is guaranteed to be in low memory. The additional static_cast
+        // suppresses the warning for now. http://b/19478262
+        (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3639,7 +3647,7 @@
         (GLenum)mode,
         (GLsizei)count,
         (GLenum)type,
-        (GLvoid *)indicesOffset,
+        (GLvoid *)static_cast<uintptr_t>(indicesOffset),
         (GLsizei)instanceCount
     );
 }
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index bc9fc5d..e5ea950 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -16,6 +16,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <stdint.h>
 #include <GLES3/gl31.h>
 #include <jni.h>
@@ -351,7 +355,7 @@
     // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer.
     // GL checks for too-large values. Here we only need to check for successful signed 64-bit
     // to unsigned 32-bit conversion.
-    if (sizeof(void*) != sizeof(jlong) && indirect > UINTPTR_MAX) {
+    if (sizeof(void*) != sizeof(jlong) && indirect > static_cast<jlong>(UINT32_MAX)) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large");
         return;
     }
@@ -363,7 +367,7 @@
     // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer.
     // GL checks for too-large values. Here we only need to check for successful signed 64-bit
     // to unsigned 32-bit conversion.
-    if (sizeof(void*) != sizeof(jlong) && indirect > UINTPTR_MAX) {
+    if (sizeof(void*) != sizeof(jlong) && indirect > static_cast<jlong>(UINT32_MAX)) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large");
         return;
     }
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index d76c166..7317e9f 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -16,6 +16,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include <GLES3/gl31.h>
 #include <GLES2/gl2ext.h>
 
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d9e64c7..773d42e 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -227,13 +227,12 @@
     int len, nameLen;
     bool skip, done = false;
 
-    unsigned size = 0, resident = 0, pss = 0, swappable_pss = 0;
+    unsigned pss = 0, swappable_pss = 0;
     float sharing_proportion = 0.0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
     unsigned swapped_out = 0;
     bool is_swappable = false;
-    unsigned referenced = 0;
     unsigned temp;
 
     uint64_t start;
@@ -362,9 +361,9 @@
             }
 
             if (line[0] == 'S' && sscanf(line, "Size: %d kB", &temp) == 1) {
-                size = temp;
+                /* size = temp; */
             } else if (line[0] == 'R' && sscanf(line, "Rss: %d kB", &temp) == 1) {
-                resident = temp;
+                /* resident = temp; */
             } else if (line[0] == 'P' && sscanf(line, "Pss: %d kB", &temp) == 1) {
                 pss = temp;
             } else if (line[0] == 'S' && sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
@@ -376,7 +375,7 @@
             } else if (line[0] == 'P' && sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
                 private_dirty = temp;
             } else if (line[0] == 'R' && sscanf(line, "Referenced: %d kB", &temp) == 1) {
-                referenced = temp;
+                /* referenced = temp; */
             } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
                 swapped_out = temp;
             } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
@@ -502,7 +501,6 @@
     jlong pss = 0;
     jlong uss = 0;
     jlong memtrack = 0;
-    unsigned temp;
 
     char tmp[128];
     FILE *fp;
@@ -939,7 +937,8 @@
     const jchar* str = env->GetStringCritical(fileName, 0);
     String8 fileName8;
     if (str) {
-        fileName8 = String8(str, env->GetStringLength(fileName));
+        fileName8 = String8(reinterpret_cast<const char16_t*>(str),
+                            env->GetStringLength(fileName));
         env->ReleaseStringCritical(fileName, str);
     }
 
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index 27b29bc..c198a73 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -18,7 +18,7 @@
 #include <utils/Log.h>
 
 #include <cutils/ashmem.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include "JNIHelp.h"
 #include <unistd.h>
 #include <sys/mman.h>
@@ -151,9 +151,7 @@
 
 int register_android_os_MemoryFile(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(
-        env, "android/os/MemoryFile",
-        methods, NELEM(methods));
+    return RegisterMethodsOrDie(env, "android/os/MemoryFile", methods, NELEM(methods));
 }
 
 }
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index a8ed895..d2db3c9 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -23,26 +23,37 @@
 #include <utils/Log.h>
 #include "android_os_MessageQueue.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
     jfieldID mPtr;   // native object attached to the DVM MessageQueue
+    jmethodID dispatchEvents;
 } gMessageQueueClassInfo;
 
+// Must be kept in sync with the constants in Looper.FileDescriptorCallback
+static const int CALLBACK_EVENT_INPUT = 1 << 0;
+static const int CALLBACK_EVENT_OUTPUT = 1 << 1;
+static const int CALLBACK_EVENT_ERROR = 1 << 2;
 
-class NativeMessageQueue : public MessageQueue {
+
+class NativeMessageQueue : public MessageQueue, public LooperCallback {
 public:
     NativeMessageQueue();
     virtual ~NativeMessageQueue();
 
     virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
 
-    void pollOnce(JNIEnv* env, int timeoutMillis);
-
+    void pollOnce(JNIEnv* env, jobject obj, int timeoutMillis);
     void wake();
+    void setFileDescriptorEvents(int fd, int events);
+
+    virtual int handleEvent(int fd, int events, void* data);
 
 private:
-    bool mInCallback;
+    JNIEnv* mPollEnv;
+    jobject mPollObj;
     jthrowable mExceptionObj;
 };
 
@@ -54,8 +65,8 @@
 }
 
 bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
-    jthrowable exceptionObj = env->ExceptionOccurred();
-    if (exceptionObj) {
+    if (env->ExceptionCheck()) {
+        jthrowable exceptionObj = env->ExceptionOccurred();
         env->ExceptionClear();
         raiseException(env, msg, exceptionObj);
         env->DeleteLocalRef(exceptionObj);
@@ -64,7 +75,8 @@
     return false;
 }
 
-NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {
+NativeMessageQueue::NativeMessageQueue() :
+        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
     mLooper = Looper::getForThread();
     if (mLooper == NULL) {
         mLooper = new Looper(false);
@@ -77,7 +89,7 @@
 
 void NativeMessageQueue::raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) {
     if (exceptionObj) {
-        if (mInCallback) {
+        if (mPollEnv == env) {
             if (mExceptionObj) {
                 env->DeleteLocalRef(mExceptionObj);
             }
@@ -92,10 +104,13 @@
     }
 }
 
-void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
-    mInCallback = true;
+void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
+    mPollEnv = env;
+    mPollObj = pollObj;
     mLooper->pollOnce(timeoutMillis);
-    mInCallback = false;
+    mPollObj = NULL;
+    mPollEnv = NULL;
+
     if (mExceptionObj) {
         env->Throw(mExceptionObj);
         env->DeleteLocalRef(mExceptionObj);
@@ -107,6 +122,46 @@
     mLooper->wake();
 }
 
+void NativeMessageQueue::setFileDescriptorEvents(int fd, int events) {
+    if (events) {
+        int looperEvents = 0;
+        if (events & CALLBACK_EVENT_INPUT) {
+            looperEvents |= Looper::EVENT_INPUT;
+        }
+        if (events & CALLBACK_EVENT_OUTPUT) {
+            looperEvents |= Looper::EVENT_OUTPUT;
+        }
+        mLooper->addFd(fd, Looper::POLL_CALLBACK, looperEvents, this,
+                reinterpret_cast<void*>(events));
+    } else {
+        mLooper->removeFd(fd);
+    }
+}
+
+int NativeMessageQueue::handleEvent(int fd, int looperEvents, void* data) {
+    int events = 0;
+    if (looperEvents & Looper::EVENT_INPUT) {
+        events |= CALLBACK_EVENT_INPUT;
+    }
+    if (looperEvents & Looper::EVENT_OUTPUT) {
+        events |= CALLBACK_EVENT_OUTPUT;
+    }
+    if (looperEvents & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP | Looper::EVENT_INVALID)) {
+        events |= CALLBACK_EVENT_ERROR;
+    }
+    int oldWatchedEvents = reinterpret_cast<intptr_t>(data);
+    int newWatchedEvents = mPollEnv->CallIntMethod(mPollObj,
+            gMessageQueueClassInfo.dispatchEvents, fd, events);
+    if (!newWatchedEvents) {
+        return 0; // unregister the fd
+    }
+    if (newWatchedEvents != oldWatchedEvents) {
+        setFileDescriptorEvents(fd, newWatchedEvents);
+    }
+    return 1;
+}
+
+
 // ----------------------------------------------------------------------------
 
 sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
@@ -130,20 +185,26 @@
     nativeMessageQueue->decStrong(env);
 }
 
-static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jclass clazz,
+static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
         jlong ptr, jint timeoutMillis) {
     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
-    nativeMessageQueue->pollOnce(env, timeoutMillis);
+    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
 }
 
 static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
-    return nativeMessageQueue->wake();
+    nativeMessageQueue->wake();
 }
 
-static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jlong ptr) {
+static jboolean android_os_MessageQueue_nativeIsPolling(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
-    return nativeMessageQueue->getLooper()->isIdling();
+    return nativeMessageQueue->getLooper()->isPolling();
+}
+
+static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, jclass clazz,
+        jlong ptr, jint fd, jint events) {
+    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
+    nativeMessageQueue->setFileDescriptorEvents(fd, events);
 }
 
 // ----------------------------------------------------------------------------
@@ -154,29 +215,21 @@
     { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
     { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
     { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
-    { "nativeIsIdling", "(J)Z", (void*)android_os_MessageQueue_nativeIsIdling }
+    { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
+    { "nativeSetFileDescriptorEvents", "(JII)V",
+            (void*)android_os_MessageQueue_nativeSetFileDescriptorEvents },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_os_MessageQueue(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/os/MessageQueue",
-            gMessageQueueMethods, NELEM(gMessageQueueMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/os/MessageQueue", gMessageQueueMethods,
+                                   NELEM(gMessageQueueMethods));
 
-    jclass clazz;
-    FIND_CLASS(clazz, "android/os/MessageQueue");
+    jclass clazz = FindClassOrDie(env, "android/os/MessageQueue");
+    gMessageQueueClassInfo.mPtr = GetFieldIDOrDie(env, clazz, "mPtr", "J");
+    gMessageQueueClassInfo.dispatchEvents = GetMethodIDOrDie(env, clazz,
+            "dispatchEvents", "(II)I");
 
-    GET_FIELD_ID(gMessageQueueClassInfo.mPtr, clazz,
-            "mPtr", "J");
-    
-    return 0;
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h
index 49d2aa0..1e49b5f 100644
--- a/core/jni/android_os_MessageQueue.h
+++ b/core/jni/android_os_MessageQueue.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class MessageQueue : public RefBase {
+class MessageQueue : public virtual RefBase {
 public:
     /* Gets the message queue's looper. */
     inline sp<Looper> getLooper() const {
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 960acc0..4f29c50 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -46,6 +46,8 @@
 
 #include <android_runtime/AndroidRuntime.h>
 
+#include "core_jni_helpers.h"
+
 //#undef ALOGV
 //#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
 
@@ -275,7 +277,9 @@
         if (val) {
             const jchar* str = env->GetStringCritical(val, 0);
             if (str) {
-                err = parcel->writeString16(str, env->GetStringLength(val));
+                err = parcel->writeString16(
+                    reinterpret_cast<const char16_t*>(str),
+                    env->GetStringLength(val));
                 env->ReleaseStringCritical(val, str);
             }
         } else {
@@ -409,7 +413,7 @@
         size_t len;
         const char16_t* str = parcel->readString16Inplace(&len);
         if (str) {
-            return env->NewString(str, len);
+            return env->NewString(reinterpret_cast<const jchar*>(str), len);
         }
         return NULL;
     }
@@ -451,7 +455,8 @@
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return NULL;
     }
-    String8 name8(str, env->GetStringLength(name));
+    String8 name8(reinterpret_cast<const char16_t*>(str),
+                  env->GetStringLength(name));
     env->ReleaseStringCritical(name, str);
     int flags=0;
     switch (mode&0x30000000) {
@@ -646,7 +651,9 @@
         // the caller expects to be invoking
         const jchar* str = env->GetStringCritical(name, 0);
         if (str != NULL) {
-            parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
+            parcel->writeInterfaceToken(String16(
+                  reinterpret_cast<const char16_t*>(str),
+                  env->GetStringLength(name)));
             env->ReleaseStringCritical(name, str);
         }
     }
@@ -654,8 +661,6 @@
 
 static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name)
 {
-    jboolean ret = JNI_FALSE;
-
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     if (parcel != NULL) {
         const jchar* str = env->GetStringCritical(name, 0);
@@ -663,7 +668,8 @@
             IPCThreadState* threadState = IPCThreadState::self();
             const int32_t oldPolicy = threadState->getStrictModePolicy();
             const bool isValid = parcel->enforceInterface(
-                String16(str, env->GetStringLength(name)),
+                String16(reinterpret_cast<const char16_t*>(str),
+                         env->GetStringLength(name)),
                 threadState);
             env->ReleaseStringCritical(name, str);
             if (isValid) {
@@ -756,20 +762,14 @@
 
 int register_android_os_Parcel(JNIEnv* env)
 {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, kParcelPathName);
 
-    clazz = env->FindClass(kParcelPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
+    gParcelOffsets.clazz = MakeGlobalRefOrDie(env, clazz);
+    gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, clazz, "mNativePtr", "J");
+    gParcelOffsets.obtain = GetStaticMethodIDOrDie(env, clazz, "obtain", "()Landroid/os/Parcel;");
+    gParcelOffsets.recycle = GetMethodIDOrDie(env, clazz, "recycle", "()V");
 
-    gParcelOffsets.clazz = (jclass) env->NewGlobalRef(clazz);
-    gParcelOffsets.mNativePtr = env->GetFieldID(clazz, "mNativePtr", "J");
-    gParcelOffsets.obtain = env->GetStaticMethodID(clazz, "obtain",
-                                                   "()Landroid/os/Parcel;");
-    gParcelOffsets.recycle = env->GetMethodID(clazz, "recycle", "()V");
-
-    return AndroidRuntime::registerNativeMethods(
-        env, kParcelPathName,
-        gParcelMethods, NELEM(gParcelMethods));
+    return RegisterMethodsOrDie(env, kParcelPathName, gParcelMethods, NELEM(gParcelMethods));
 }
 
 };
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index ffa569e..762b88f 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -19,7 +19,7 @@
 
 #include "JNIHelp.h"
 #include "jni.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "selinux/selinux.h"
 #include "selinux/android.h"
 #include <errno.h>
@@ -61,23 +61,6 @@
 }
 
 /*
- * Function: setSELinuxEnforce
- * Purpose: set the SE Linux enforcing mode
- * Parameters: true (enforcing) or false (permissive)
- * Return value: true (success) or false (fail)
- * Exceptions: none
- */
-static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
-    if (isSELinuxDisabled) {
-        return false;
-    }
-
-    int enforce = value ? 1 : 0;
-
-    return (security_setenforce(enforce) != -1) ? true : false;
-}
-
-/*
  * Function: getPeerCon
  * Purpose: retrieves security context of peer socket
  * Parameters:
@@ -97,7 +80,7 @@
     }
 
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    if (env->ExceptionOccurred() != NULL) {
+    if (env->ExceptionCheck()) {
         ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
         return NULL;
     }
@@ -265,92 +248,6 @@
 }
 
 /*
- * Function: getBooleanNames
- * Purpose: Gets a list of the SELinux boolean names.
- * Parameters: None
- * Returns: an array of strings  containing the SELinux boolean names.
- *          returns NULL string on error
- * Exceptions: None
- */
-static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
-    if (isSELinuxDisabled) {
-        return NULL;
-    }
-
-    char **list;
-    int len;
-    if (security_get_boolean_names(&list, &len) == -1) {
-        return NULL;
-    }
-
-    jclass stringClass = env->FindClass("java/lang/String");
-    jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
-    for (int i = 0; i < len; i++) {
-        ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
-        env->SetObjectArrayElement(stringArray, i, obj.get());
-        free(list[i]);
-    }
-    free(list);
-
-    return stringArray;
-}
-
-/*
- * Function: getBooleanValue
- * Purpose: Gets the value for the given SELinux boolean name.
- * Parameters:
- *            String: The name of the SELinux boolean.
- * Returns: a boolean: (true) boolean is set or (false) it is not.
- * Exceptions: None
- */
-static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
-    if (isSELinuxDisabled) {
-        return false;
-    }
-
-    if (nameStr == NULL) {
-        return false;
-    }
-
-    ScopedUtfChars name(env, nameStr);
-    int ret = security_get_boolean_active(name.c_str());
-
-    ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
-    return (ret == 1) ? true : false;
-}
-
-/*
- * Function: setBooleanNames
- * Purpose: Sets the value for the given SELinux boolean name.
- * Parameters:
- *            String: The name of the SELinux boolean.
- *            Boolean: The new value of the SELinux boolean.
- * Returns: a boolean indicating whether or not the operation succeeded.
- * Exceptions: None
- */
-static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
-    if (isSELinuxDisabled) {
-        return false;
-    }
-
-    if (nameStr == NULL) {
-        return false;
-    }
-
-    ScopedUtfChars name(env, nameStr);
-    int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
-    if (ret) {
-        return false;
-    }
-
-    if (security_commit_booleans() == -1) {
-        return false;
-    }
-
-    return true;
-}
-
-/*
  * Function: checkSELinuxAccess
  * Purpose: Check permissions between two security contexts.
  * Parameters: subjectContextStr: subject security context as a string
@@ -426,8 +323,6 @@
 static JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
-    { "getBooleanNames"          , "()[Ljava/lang/String;"                        , (void*)getBooleanNames  },
-    { "getBooleanValue"          , "(Ljava/lang/String;)Z"                        , (void*)getBooleanValue  },
     { "getContext"               , "()Ljava/lang/String;"                         , (void*)getCon           },
     { "getFileContext"           , "(Ljava/lang/String;)Ljava/lang/String;"       , (void*)getFileCon       },
     { "getPeerContext"           , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getPeerCon       },
@@ -435,10 +330,8 @@
     { "isSELinuxEnforced"        , "()Z"                                          , (void*)isSELinuxEnforced},
     { "isSELinuxEnabled"         , "()Z"                                          , (void*)isSELinuxEnabled },
     { "native_restorecon"        , "(Ljava/lang/String;I)Z"                       , (void*)native_restorecon},
-    { "setBooleanValue"          , "(Ljava/lang/String;Z)Z"                       , (void*)setBooleanValue  },
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
-    { "setSELinuxEnforce"        , "(Z)Z"                                         , (void*)setSELinuxEnforce},
 };
 
 static int log_callback(int type, const char *fmt, ...) {
@@ -469,8 +362,7 @@
 
     isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
 
-    return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
-            NELEM(method_table));
+    return RegisterMethodsOrDie(env, "android/os/SELinux", method_table, NELEM(method_table));
 }
 
 }
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index 6247844..dfe024e 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -27,7 +27,7 @@
 
 #include "JNIHelp.h"
 #include "jni.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <sys/time.h>
 #include <time.h>
@@ -60,18 +60,11 @@
 static jlong android_os_SystemClock_currentThreadTimeMillis(JNIEnv* env,
         jobject clazz)
 {
-#if defined(HAVE_POSIX_CLOCKS)
     struct timespec tm;
 
     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
 
     return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
-#else
-    struct timeval tv;
-
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
-#endif
 }
 
 /*
@@ -80,18 +73,11 @@
 static jlong android_os_SystemClock_currentThreadTimeMicro(JNIEnv* env,
         jobject clazz)
 {
-#if defined(HAVE_POSIX_CLOCKS)
     struct timespec tm;
 
     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
 
     return tm.tv_sec * 1000000LL + tm.tv_nsec / 1000;
-#else
-    struct timeval tv;
-
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000000LL + tv.tv_nsec / 1000;
-#endif
 }
 
 /*
@@ -135,8 +121,7 @@
 };
 int register_android_os_SystemClock(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/os/SystemClock", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/os/SystemClock", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 677396d1..554d304 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -21,7 +21,7 @@
 #include "utils/misc.h"
 #include <utils/Log.h>
 #include "jni.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include <nativehelper/JNIHelp.h>
 
 namespace android
@@ -239,9 +239,8 @@
 
 int register_android_os_SystemProperties(JNIEnv *env)
 {
-    return AndroidRuntime::registerNativeMethods(
-        env, "android/os/SystemProperties",
-        method_table, NELEM(method_table));
+    return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
+                                NELEM(method_table));
 }
 
 };
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index b11c5bb..52fd111 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "Trace"
 // #define LOG_NDEBUG 0
 
+#include <inttypes.h>
+
 #include <JNIHelp.h>
 #include <ScopedUtfChars.h>
 #include <ScopedStringChars.h>
@@ -48,47 +50,44 @@
         jlong tag, jstring nameStr, jint value) {
     ScopedUtfChars name(env, nameStr);
 
-    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, name.c_str(), value);
+    ALOGV("%s: %" PRId64 " %s %d", __FUNCTION__, tag, name.c_str(), value);
     atrace_int(tag, name.c_str(), value);
 }
 
 static void android_os_Trace_nativeTraceBegin(JNIEnv* env, jclass clazz,
         jlong tag, jstring nameStr) {
-    const size_t MAX_SECTION_NAME_LEN = 127;
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
 
-    ALOGV("%s: %lld %s", __FUNCTION__, tag, utf8Chars.string());
+    ALOGV("%s: %" PRId64 " %s", __FUNCTION__, tag, utf8Chars.string());
     atrace_begin(tag, utf8Chars.string());
 }
 
 static void android_os_Trace_nativeTraceEnd(JNIEnv* env, jclass clazz,
         jlong tag) {
 
-    ALOGV("%s: %lld", __FUNCTION__, tag);
+    ALOGV("%s: %" PRId64, __FUNCTION__, tag);
     atrace_end(tag);
 }
 
 static void android_os_Trace_nativeAsyncTraceBegin(JNIEnv* env, jclass clazz,
         jlong tag, jstring nameStr, jint cookie) {
-    const size_t MAX_SECTION_NAME_LEN = 127;
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
 
-    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
+    ALOGV("%s: %" PRId64 " %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
     atrace_async_begin(tag, utf8Chars.string(), cookie);
 }
 
 static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass clazz,
         jlong tag, jstring nameStr, jint cookie) {
-    const size_t MAX_SECTION_NAME_LEN = 127;
     ScopedStringChars jchars(env, nameStr);
     String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
     sanitizeString(utf8Chars);
 
-    ALOGV("%s: %lld %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
+    ALOGV("%s: %" PRId64 " %s %d", __FUNCTION__, tag, utf8Chars.string(), cookie);
     atrace_async_end(tag, utf8Chars.string(), cookie);
 }
 
@@ -137,7 +136,7 @@
 int register_android_os_Trace(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "android/os/Trace",
             gTraceMethods, NELEM(gTraceMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
 
     return 0;
 }
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index 3f7c7d2..eb36f85 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -22,7 +22,7 @@
 #include "hardware_legacy/uevent.h"
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <utils/Mutex.h>
 #include <utils/Vector.h>
@@ -117,16 +117,9 @@
 
 int register_android_os_UEventObserver(JNIEnv *env)
 {
-    jclass clazz;
+    FindClassOrDie(env, "android/os/UEventObserver");
 
-    clazz = env->FindClass("android/os/UEventObserver");
-    if (clazz == NULL) {
-        ALOGE("Can't find android/os/UEventObserver");
-        return -1;
-    }
-
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/os/UEventObserver", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/os/UEventObserver", gMethods, NELEM(gMethods));
 }
 
 }   // namespace android
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index b174d1b..853425c 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -20,36 +20,21 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
+#include <android_os_MessageQueue.h>
 #include <hardware/hardware.h>
 #include <hardware/fingerprint.h>
 #include <utils/Log.h>
-
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+#include <utils/Looper.h>
+#include "core_jni_helpers.h"
 
 namespace android {
 
-static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 0);
 
 static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
 static struct {
     jclass clazz;
     jmethodID notify;
-    jobject callbackObject;
 } gFingerprintServiceClassInfo;
 
 static struct {
@@ -57,11 +42,26 @@
     fingerprint_device_t *device;
 } gContext;
 
+static sp<Looper> gLooper;
+static jobject gCallback;
+
+class CallbackHandler : public MessageHandler {
+    int type;
+    int arg1, arg2;
+public:
+    CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { }
+
+    virtual void handleMessage(const Message& message) {
+        //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2);
+    }
+};
+
 // 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
     switch (msg.type) {
         case FINGERPRINT_ERROR:
             arg1 = msg.data.error;
@@ -70,48 +70,34 @@
             arg1 = msg.data.acquired.acquired_info;
             break;
         case FINGERPRINT_PROCESSED:
-            arg1 = msg.data.processed.id;
+            arg1 = msg.data.processed.finger.fid;
             break;
         case FINGERPRINT_TEMPLATE_ENROLLING:
-            arg1 = msg.data.enroll.id;
+            arg1 = msg.data.enroll.finger.fid;
             arg2 = msg.data.enroll.samples_remaining;
-            arg3 = msg.data.enroll.data_collected_bmp;
             break;
         case FINGERPRINT_TEMPLATE_REMOVED:
-            arg1 = msg.data.removed.id;
+            arg1 = msg.data.removed.finger.fid;
             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);
+    // This call potentially comes in on a thread not owned by us. Hand it off to our
+    // looper so it runs on our thread when calling back to FingerprintService.
+    // CallbackHandler object is reference-counted, so no cleanup necessary.
+    gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message());
 }
 
-static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
+static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, 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);
+    gCallback = MakeGlobalRefOrDie(env, callbackObj);
+    gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
 }
 
 static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
     ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
-    int ret = gContext.device->enroll(gContext.device, timeout);
+    int ret = gContext.device->enroll(gContext.device, 0, timeout);
     return reinterpret_cast<jint>(ret);
 }
 
@@ -123,7 +109,10 @@
 
 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);
+    fingerprint_finger_id_t finger;
+    finger.gid = 0;
+    finger.fid = fingerprintId;
+    int ret = gContext.device->remove(gContext.device, finger);
     return reinterpret_cast<jint>(ret);
 }
 
@@ -184,19 +173,20 @@
 // TODO: clean up void methods
 static const JNINativeMethod g_methods[] = {
     { "nativeEnroll", "(I)I", (void*)nativeEnroll },
-    { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
+    { "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel },
     { "nativeRemove", "(I)I", (void*)nativeRemove },
     { "nativeOpenHal", "()I", (void*)nativeOpenHal },
     { "nativeCloseHal", "()I", (void*)nativeCloseHal },
-    { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
+    { "nativeInit","(Landroid/os/MessageQueue;"
+            "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));
+    jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE);
+    gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gFingerprintServiceClassInfo.notify =
+            GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V");
+    int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
     ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
     return result;
 }
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index 7e12b1e..ca21fd7 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -35,7 +35,7 @@
                                 jint tagNum, jint uid) {
   int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-  if (env->ExceptionOccurred() != NULL) {
+  if (env->ExceptionCheck()) {
     ALOGE("Can't get FileDescriptor num");
     return (jint)-1;
   }
@@ -51,7 +51,7 @@
                                   jobject fileDescriptor) {
   int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
-  if (env->ExceptionOccurred() != NULL) {
+  if (env->ExceptionCheck()) {
     ALOGE("Can't get FileDescriptor num");
     return (jint)-1;
   }
diff --git a/core/jni/android_server_Watchdog.cpp b/core/jni/android_server_Watchdog.cpp
index 6726c14..d1f9434 100644
--- a/core/jni/android_server_Watchdog.cpp
+++ b/core/jni/android_server_Watchdog.cpp
@@ -26,7 +26,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 static void dumpOneStack(int tid, int outFd) {
     char buf[64];
@@ -106,8 +106,7 @@
 };
 
 int register_android_server_Watchdog(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, "com/android/server/Watchdog",
-                                                 g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "com/android/server/Watchdog", g_methods, NELEM(g_methods));
 }
 
 }
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 6f7ee49..3285429 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "AndroidUnicode"
 
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include "utils/misc.h"
 #include "utils/Log.h"
 #include "unicode/ubidi.h"
@@ -57,14 +57,12 @@
 }
 
 static JNINativeMethod gMethods[] = {
-        { "runBidi", "(I[C[BIZ)I",
-        (void*) runBidi }
+        { "runBidi", "(I[C[BIZ)I", (void*) runBidi }
 };
 
 int register_android_text_AndroidBidi(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidBidi",
-            gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/text/AndroidBidi", gMethods, NELEM(gMethods));
 }
 
 }
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 94bd40f..9258248 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -19,7 +19,7 @@
 
 #include "JNIHelp.h"
 #include "ScopedPrimitiveArray.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include "utils/misc.h"
 #include "utils/Log.h"
 #include "unicode/uchar.h"
@@ -193,8 +193,7 @@
 
 int register_android_text_AndroidCharacter(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter",
-            gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/text/AndroidCharacter", gMethods, NELEM(gMethods));
 }
 
 }
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 9e20d18..8800f0b 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -23,88 +23,686 @@
 #include "utils/Log.h"
 #include "ScopedPrimitiveArray.h"
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
+#include <cstdint>
 #include <vector>
+#include <list>
+#include <algorithm>
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "MinikinSkia.h"
+#include "MinikinUtils.h"
+#include "Paint.h"
 
 namespace android {
 
-class ScopedBreakIterator {
-    public:
-        ScopedBreakIterator(JNIEnv* env, BreakIterator* breakIterator, jcharArray inputText,
-                            jint length) : mBreakIterator(breakIterator), mChars(env, inputText) {
-            UErrorCode status = U_ZERO_ERROR;
-            mUText = utext_openUChars(NULL, mChars.get(), length, &status);
-            if (mUText == NULL) {
-                return;
-            }
+struct JLineBreaksID {
+    jfieldID breaks;
+    jfieldID widths;
+    jfieldID flags;
+};
 
-            mBreakIterator->setText(mUText, status);
+static jclass gLineBreaks_class;
+static JLineBreaksID gLineBreaks_fieldID;
+
+class Builder {
+    public:
+        ~Builder() {
+            utext_close(&mUText);
+            delete mBreakIterator;
         }
 
-        inline BreakIterator* operator->() {
+        void setLocale(const icu::Locale& locale) {
+            delete mBreakIterator;
+            UErrorCode status = U_ZERO_ERROR;
+            mBreakIterator = icu::BreakIterator::createLineInstance(locale, status);
+            // TODO: check status
+        }
+
+        void resize(size_t size) {
+            mTextBuf.resize(size);
+            mWidthBuf.resize(size);
+        }
+
+        size_t size() const {
+            return mTextBuf.size();
+        }
+
+        uint16_t* buffer() {
+            return mTextBuf.data();
+        }
+
+        float* widths() {
+            return mWidthBuf.data();
+        }
+
+        // set text to current contents of buffer
+        void setText() {
+            UErrorCode status = U_ZERO_ERROR;
+            utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
+            mBreakIterator->setText(&mUText, status);
+        }
+
+        void finish() {
+            if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
+                mTextBuf.clear();
+                mTextBuf.shrink_to_fit();
+                mWidthBuf.clear();
+                mWidthBuf.shrink_to_fit();
+            }
+        }
+
+        icu::BreakIterator* breakIterator() const {
             return mBreakIterator;
         }
 
-        ~ScopedBreakIterator() {
-            utext_close(mUText);
-            delete mBreakIterator;
-        }
-    private:
-        BreakIterator* mBreakIterator;
-        ScopedCharArrayRO mChars;
-        UText* mUText;
+        float measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
+                bool isRtl);
 
-        // disable copying and assignment
-        ScopedBreakIterator(const ScopedBreakIterator&);
-        void operator=(const ScopedBreakIterator&);
+        void addReplacement(size_t start, size_t end, float width);
+
+    private:
+        const size_t MAX_TEXT_BUF_RETAIN = 32678;
+        icu::BreakIterator* mBreakIterator = nullptr;
+        UText mUText = UTEXT_INITIALIZER;
+        std::vector<uint16_t>mTextBuf;
+        std::vector<float>mWidthBuf;
 };
 
-static jintArray nLineBreakOpportunities(JNIEnv* env, jclass, jstring javaLocaleName,
-                                        jcharArray inputText, jint length,
-                                        jintArray recycle) {
-    jintArray ret;
-    std::vector<jint> breaks;
+static const int CHAR_SPACE = 0x20;
+static const int CHAR_TAB = 0x09;
+static const int CHAR_NEWLINE = 0x0a;
+static const int CHAR_ZWSP = 0x200b;
 
-    ScopedIcuLocale icuLocale(env, javaLocaleName);
-    if (icuLocale.valid()) {
-        UErrorCode status = U_ZERO_ERROR;
-        BreakIterator* it = BreakIterator::createLineInstance(icuLocale.locale(), status);
-        if (!U_SUCCESS(status) || it == NULL) {
-            if (it) {
-                delete it;
+class TabStops {
+    public:
+        // specified stops must be a sorted array (allowed to be null)
+        TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
+            mStops(env), mTabWidth(defaultTabWidth) {
+                if (stops != nullptr) {
+                    mStops.reset(stops);
+                    mNumStops = mStops.size();
+                } else {
+                    mNumStops = 0;
+                }
             }
-        } else {
-            ScopedBreakIterator breakIterator(env, it, inputText, length);
-            for (int loc = breakIterator->first(); loc != BreakIterator::DONE;
-                    loc = breakIterator->next()) {
-                breaks.push_back(loc);
+        float width(float widthSoFar) const {
+            const jint* mStopsArray = mStops.get();
+            for (int i = 0; i < mNumStops; i++) {
+                if (mStopsArray[i] > widthSoFar) {
+                    return mStopsArray[i];
+                }
+            }
+            // find the next tabstop after widthSoFar
+            return static_cast<int>((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
+        }
+    private:
+        ScopedIntArrayRO mStops;
+        const int mTabWidth;
+        int mNumStops;
+
+        // disable copying and assignment
+        TabStops(const TabStops&);
+        void operator=(const TabStops&);
+};
+
+enum PrimitiveType {
+    kPrimitiveType_Box,
+    kPrimitiveType_Glue,
+    kPrimitiveType_Penalty,
+    kPrimitiveType_Variable,
+    kPrimitiveType_Wordbreak
+};
+
+static const float PENALTY_INFINITY = 1e7; // forced non-break, negative infinity is forced break
+
+struct Primitive {
+    PrimitiveType type;
+    int location;
+    // 'Box' has width
+    // 'Glue' has width
+    // 'Penalty' has width and penalty
+    // 'Variable' has tabStop
+    // 'Wordbreak' has penalty
+    union {
+        struct {
+            float width;
+            float penalty;
+        };
+        const TabStops* tabStop;
+    };
+};
+
+class LineWidth {
+    public:
+        LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) :
+                mFirstWidth(firstWidth), mFirstWidthLineCount(firstWidthLineCount),
+                mRestWidth(restWidth) {}
+        float getLineWidth(int line) const {
+            return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
+        }
+    private:
+        const float mFirstWidth;
+        const int mFirstWidthLineCount;
+        const float mRestWidth;
+};
+
+class LineBreaker {
+    public:
+        LineBreaker(const std::vector<Primitive>& primitives,
+                    const LineWidth& lineWidth) :
+                mPrimitives(primitives), mLineWidth(lineWidth) {}
+        virtual ~LineBreaker() {}
+        virtual void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
+                                   std::vector<unsigned char>* flags) const = 0;
+    protected:
+        const std::vector<Primitive>& mPrimitives;
+        const LineWidth& mLineWidth;
+};
+
+class OptimizingLineBreaker : public LineBreaker {
+    public:
+        OptimizingLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
+                LineBreaker(primitives, lineWidth) {}
+        void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
+                           std::vector<unsigned char>* flags) const {
+            int numBreaks = mPrimitives.size();
+            Node* opt = new Node[numBreaks];
+            opt[0].prev = -1;
+            opt[0].prevCount = 0;
+            opt[0].width = 0;
+            opt[0].demerits = 0;
+            opt[0].flags = false;
+            opt[numBreaks - 1].prev = -1;
+            opt[numBreaks - 1].prevCount = 0;
+
+            std::list<int> active;
+            active.push_back(0);
+            int lastBreak = 0;
+            for (int i = 0; i < numBreaks; i++) {
+                const Primitive& p = mPrimitives[i];
+                if (p.type == kPrimitiveType_Penalty) {
+                    const bool finalBreak = (i + 1 == numBreaks);
+                    bool breakFound = false;
+                    Node bestBreak;
+                    for (std::list<int>::iterator it = active.begin(); it != active.end(); /* incrementing done in loop */) {
+                        const int pos = *it;
+                        bool flags;
+                        float width, printedWidth;
+                        const int lines = opt[pos].prevCount;
+                        const float maxWidth = mLineWidth.getLineWidth(lines);
+                        // we have to compute metrics every time --
+                        // we can't really precompute this stuff and just deal with breaks
+                        // because of the way tab characters work, this makes it computationally
+                        // harder, but this way, we can still optimize while treating tab characters
+                        // correctly
+                        computeMetrics(pos, i, &width, &printedWidth, &flags);
+                        if (printedWidth <= maxWidth) {
+                            float demerits = computeDemerits(maxWidth, printedWidth,
+                                    finalBreak, p.penalty) + opt[pos].demerits;
+                            if (!breakFound || demerits < bestBreak.demerits) {
+                                bestBreak.prev = pos;
+                                bestBreak.prevCount = opt[pos].prevCount + 1;
+                                bestBreak.demerits = demerits;
+                                bestBreak.width = printedWidth;
+                                bestBreak.flags = flags;
+                                breakFound = true;
+                            }
+                            ++it;
+                        } else {
+                            active.erase(it++); // safe to delete like this
+                        }
+                    }
+                    if (p.penalty == -PENALTY_INFINITY) {
+                        active.clear();
+                    }
+                    if (breakFound) {
+                        opt[i] = bestBreak;
+                        active.push_back(i);
+                        lastBreak = i;
+                    }
+                    if (active.empty()) {
+                        // we can't give up!
+                        float width, printedWidth;
+                        bool flags;
+                        const int lines = opt[lastBreak].prevCount;
+                        const float maxWidth = mLineWidth.getLineWidth(lines);
+                        const int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, &width, &printedWidth, &flags);
+
+                        opt[breakIndex].prev = lastBreak;
+                        opt[breakIndex].prevCount = lines + 1;
+                        opt[breakIndex].demerits = 0; // doesn't matter, it's the only one
+                        opt[breakIndex].width = width;
+                        opt[breakIndex].flags = flags;
+
+                        active.push_back(breakIndex);
+                        lastBreak = breakIndex;
+                        i = breakIndex; // incremented by i++
+                    }
+                }
+            }
+
+            int idx = numBreaks - 1;
+            int count = opt[idx].prevCount;
+            breaks->resize(count);
+            widths->resize(count);
+            flags->resize(count);
+            while (opt[idx].prev != -1) {
+                --count;
+
+                (*breaks)[count] = mPrimitives[idx].location;
+                (*widths)[count] = opt[idx].width;
+                (*flags)[count] = opt[idx].flags;
+
+                idx = opt[idx].prev;
+            }
+            delete[] opt;
+        }
+    private:
+        inline void computeMetrics(int start, int end, float* width, float* printedWidth, bool* flags) const {
+            bool f = false;
+            float w = 0, pw = 0;
+            for (int i = start; i < end; i++) {
+                const Primitive& p = mPrimitives[i];
+                if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
+                    w += p.width;
+                    if (p.type == kPrimitiveType_Box) {
+                        pw = w;
+                    }
+                } else if (p.type == kPrimitiveType_Variable) {
+                    w = p.tabStop->width(w);
+                    f = true;
+                }
+            }
+            *width = w;
+            *printedWidth = pw;
+            *flags = f;
+        }
+
+        inline float computeDemerits(float maxWidth, float width, bool finalBreak, float penalty) const {
+            float deviation = finalBreak ? 0 : maxWidth - width;
+            return (deviation * deviation) + penalty;
+        }
+
+        // returns end pos (chosen break), -1 if fail
+        inline int desperateBreak(int start, int limit, float maxWidth, float* width, float* printedWidth, bool* flags) const {
+            float w = 0, pw = 0;
+            bool breakFound = false;
+            int breakIndex = 0, firstTabIndex = INT_MAX;
+            for (int i = start; i < limit; i++) {
+                const Primitive& p = mPrimitives[i];
+
+                if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
+                    w += p.width;
+                    if (p.type == kPrimitiveType_Box) {
+                        pw = w;
+                    }
+                } else if (p.type == kPrimitiveType_Variable) {
+                    w = p.tabStop->width(w);
+                    firstTabIndex = std::min(firstTabIndex, i);
+                }
+
+                if (pw > maxWidth) {
+                    if (breakFound) {
+                        break;
+                    } else {
+                        // no choice, keep going
+                    }
+                }
+
+                // must make progress
+                if (i > start && (p.type == kPrimitiveType_Penalty || p.type == kPrimitiveType_Wordbreak)) {
+                    breakFound = true;
+                    breakIndex = i;
+                }
+            }
+
+            if (breakFound) {
+                *width = w;
+                *printedWidth = pw;
+                *flags = (start <= firstTabIndex && firstTabIndex < breakIndex);
+                return breakIndex;
+            } else {
+                return -1;
             }
         }
+
+        struct Node {
+            int prev; // set to sentinel value (-1) for initial node
+            int prevCount; // number of breaks so far
+            float demerits;
+            float width;
+            bool flags;
+        };
+};
+
+class GreedyLineBreaker : public LineBreaker {
+    public:
+        GreedyLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
+            LineBreaker(primitives, lineWidth) {}
+        void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
+                           std::vector<unsigned char>* flags) const {
+            int lineNum = 0;
+            float width = 0, printedWidth = 0;
+            bool breakFound = false, goodBreakFound = false;
+            int breakIndex = 0, goodBreakIndex = 0;
+            float breakWidth = 0, goodBreakWidth = 0;
+            int firstTabIndex = INT_MAX;
+
+            float maxWidth = mLineWidth.getLineWidth(lineNum);
+
+            const int numPrimitives = mPrimitives.size();
+            // greedily fit as many characters as possible on each line
+            // loop over all primitives, and choose the best break point
+            // (if possible, a break point without splitting a word)
+            // after going over the maximum length
+            for (int i = 0; i < numPrimitives; i++) {
+                const Primitive& p = mPrimitives[i];
+
+                // update the current line width
+                if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
+                    width += p.width;
+                    if (p.type == kPrimitiveType_Box) {
+                        printedWidth = width;
+                    }
+                } else if (p.type == kPrimitiveType_Variable) {
+                    width = p.tabStop->width(width);
+                    // keep track of first tab character in the region we are examining
+                    // so we can determine whether or not a line contains a tab
+                    firstTabIndex = std::min(firstTabIndex, i);
+                }
+
+                // find the best break point for the characters examined so far
+                if (printedWidth > maxWidth) {
+                    if (breakFound || goodBreakFound) {
+                        if (goodBreakFound) {
+                            // a true line break opportunity existed in the characters examined so far,
+                            // so there is no need to split a word
+                            i = goodBreakIndex; // no +1 because of i++
+                            lineNum++;
+                            maxWidth = mLineWidth.getLineWidth(lineNum);
+                            breaks->push_back(mPrimitives[goodBreakIndex].location);
+                            widths->push_back(goodBreakWidth);
+                            flags->push_back(firstTabIndex < goodBreakIndex);
+                            firstTabIndex = INT_MAX;
+                        } else {
+                            // must split a word because there is no other option
+                            i = breakIndex; // no +1 because of i++
+                            lineNum++;
+                            maxWidth = mLineWidth.getLineWidth(lineNum);
+                            breaks->push_back(mPrimitives[breakIndex].location);
+                            widths->push_back(breakWidth);
+                            flags->push_back(firstTabIndex < breakIndex);
+                            firstTabIndex = INT_MAX;
+                        }
+                        printedWidth = width = 0;
+                        goodBreakFound = breakFound = false;
+                        goodBreakWidth = breakWidth = 0;
+                        continue;
+                    } else {
+                        // no choice, keep going... must make progress by putting at least one
+                        // character on a line, even if part of that character is cut off --
+                        // there is no other option
+                    }
+                }
+
+                // update possible break points
+                if (p.type == kPrimitiveType_Penalty && p.penalty < PENALTY_INFINITY) {
+                    // this does not handle penalties with width
+
+                    // handle forced line break
+                    if (p.penalty == -PENALTY_INFINITY) {
+                        lineNum++;
+                        maxWidth = mLineWidth.getLineWidth(lineNum);
+                        breaks->push_back(p.location);
+                        widths->push_back(printedWidth);
+                        flags->push_back(firstTabIndex < i);
+                        firstTabIndex = INT_MAX;
+                        printedWidth = width = 0;
+                        goodBreakFound = breakFound = false;
+                        goodBreakWidth = breakWidth = 0;
+                        continue;
+                    }
+                    if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
+                        breakFound = true;
+                        breakIndex = i;
+                        breakWidth = printedWidth;
+                    }
+                    if (i > goodBreakIndex && printedWidth <= maxWidth) {
+                        goodBreakFound = true;
+                        goodBreakIndex = i;
+                        goodBreakWidth = printedWidth;
+                    }
+                } else if (p.type == kPrimitiveType_Wordbreak) {
+                    // only do this if necessary -- we don't want to break words
+                    // when possible, but sometimes it is unavoidable
+                    if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
+                        breakFound = true;
+                        breakIndex = i;
+                        breakWidth = printedWidth;
+                    }
+                }
+            }
+
+            if (breakFound || goodBreakFound) {
+                // output last break if there are more characters to output
+                if (goodBreakFound) {
+                    breaks->push_back(mPrimitives[goodBreakIndex].location);
+                    widths->push_back(goodBreakWidth);
+                    flags->push_back(firstTabIndex < goodBreakIndex);
+                } else {
+                    breaks->push_back(mPrimitives[breakIndex].location);
+                    widths->push_back(breakWidth);
+                    flags->push_back(firstTabIndex < breakIndex);
+                }
+            }
+        }
+};
+
+static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
+                        jfloatArray recycleWidths, jbooleanArray recycleFlags,
+                        jint recycleLength, const std::vector<jint>& breaks,
+                        const std::vector<jfloat>& widths, const std::vector<jboolean>& flags) {
+    int bufferLength = breaks.size();
+    if (recycleLength < bufferLength) {
+        // have to reallocate buffers
+        recycleBreaks = env->NewIntArray(bufferLength);
+        recycleWidths = env->NewFloatArray(bufferLength);
+        recycleFlags = env->NewBooleanArray(bufferLength);
+
+        env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
+        env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
+        env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
+    }
+    // copy data
+    env->SetIntArrayRegion(recycleBreaks, 0, breaks.size(), &breaks.front());
+    env->SetFloatArrayRegion(recycleWidths, 0, widths.size(), &widths.front());
+    env->SetBooleanArrayRegion(recycleFlags, 0, flags.size(), &flags.front());
+
+    return bufferLength;
+}
+
+void computePrimitives(const jchar* textArr, const jfloat* widthsArr, jint length, const std::vector<int>& breaks,
+                       const TabStops& tabStopCalculator, std::vector<Primitive>* primitives) {
+    int breaksSize = breaks.size();
+    int breakIndex = 0;
+    Primitive p;
+    for (int i = 0; i < length; i++) {
+        p.location = i;
+        jchar c = textArr[i];
+        if (c == CHAR_SPACE || c == CHAR_ZWSP) {
+            p.type = kPrimitiveType_Glue;
+            p.width = widthsArr[i];
+            primitives->push_back(p);
+        } else if (c == CHAR_TAB) {
+            p.type = kPrimitiveType_Variable;
+            p.tabStop = &tabStopCalculator; // shared between all variable primitives
+            primitives->push_back(p);
+        } else if (c != CHAR_NEWLINE) {
+            while (breakIndex < breaksSize && breaks[breakIndex] < i) breakIndex++;
+            p.width = 0;
+            if (breakIndex < breaksSize && breaks[breakIndex] == i) {
+                p.type = kPrimitiveType_Penalty;
+                p.penalty = 0;
+            } else {
+                p.type = kPrimitiveType_Wordbreak;
+            }
+            if (widthsArr[i] != 0) {
+                primitives->push_back(p);
+            }
+
+            p.type = kPrimitiveType_Box;
+            p.width = widthsArr[i];
+            primitives->push_back(p);
+        }
+    }
+    // final break at end of everything
+    p.location = length;
+    p.type = kPrimitiveType_Penalty;
+    p.width = 0;
+    p.penalty = -PENALTY_INFINITY;
+    primitives->push_back(p);
+}
+
+// sets the text on the builder
+static void nSetText(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, int length) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    b->resize(length);
+    env->GetCharArrayRegion(text, 0, length, b->buffer());
+    b->setText();
+}
+
+static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
+                               jint length,
+                               jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
+                               jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
+                               jobject recycle, jintArray recycleBreaks,
+                               jfloatArray recycleWidths, jbooleanArray recycleFlags,
+                               jint recycleLength) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+
+    std::vector<int> breaks;
+
+    icu::BreakIterator* breakIterator = b->breakIterator();
+    int loc = breakIterator->first();
+    while ((loc = breakIterator->next()) != icu::BreakIterator::DONE) {
+        breaks.push_back(loc);
     }
 
-    breaks.push_back(-1); // sentinel terminal value
+    // TODO: all these allocations can be moved into the builder
+    std::vector<Primitive> primitives;
+    TabStops tabStops(env, variableTabStops, defaultTabStop);
+    computePrimitives(b->buffer(), b->widths(), length, breaks, tabStops, &primitives);
 
-    if (recycle != NULL && static_cast<size_t>(env->GetArrayLength(recycle)) >= breaks.size()) {
-        ret = recycle;
+    LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
+    std::vector<int> computedBreaks;
+    std::vector<float> computedWidths;
+    std::vector<unsigned char> computedFlags;
+
+    if (optimize) {
+        OptimizingLineBreaker breaker(primitives, lineWidth);
+        breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
     } else {
-        ret = env->NewIntArray(breaks.size());
+        GreedyLineBreaker breaker(primitives, lineWidth);
+        breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
     }
+    b->finish();
 
-    if (ret != NULL) {
-        env->SetIntArrayRegion(ret, 0, breaks.size(), &breaks.front());
+    return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
+            computedBreaks, computedWidths, computedFlags);
+}
+
+static jlong nNewBuilder(JNIEnv*, jclass) {
+    return reinterpret_cast<jlong>(new Builder);
+}
+
+static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
+    delete reinterpret_cast<Builder*>(nativePtr);
+}
+
+static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    b->finish();
+}
+
+static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
+    ScopedIcuLocale icuLocale(env, javaLocaleName);
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+
+    if (icuLocale.valid()) {
+        b->setLocale(icuLocale.locale());
     }
+}
 
-    return ret;
+float Builder::measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
+        bool isRtl) {
+    Layout layout;
+    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
+    // TODO: should we provide more context?
+    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, mTextBuf.data() + start, 0,
+            end - start, end - start);
+    layout.getAdvances(mWidthBuf.data() + start);
+    return layout.getAdvance();
+}
+
+void Builder::addReplacement(size_t start, size_t end, float width) {
+    mWidthBuf[start] = width;
+    std::fill(&mWidthBuf[start + 1], &mWidthBuf[end], 0.0f);
+}
+
+// Basically similar to Paint.getTextRunAdvances but with C++ interface
+static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr,
+        jlong nativePaint, jlong nativeTypeface, jint start, jint end, jboolean isRtl) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    Paint* paint = reinterpret_cast<Paint*>(nativePaint);
+    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(nativeTypeface);
+    return b->measureStyleRun(paint, typeface, start, end, isRtl);
+}
+
+// Accept width measurements for the run, passed in from Java
+static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr,
+        jint start, jint end, jfloatArray widths) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    env->GetFloatArrayRegion(widths, start, end - start, b->widths() + start);
+}
+
+static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
+        jint start, jint end, jfloat width) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    b->addReplacement(start, end, width);
+}
+
+static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) {
+    Builder* b = reinterpret_cast<Builder*>(nativePtr);
+    env->SetFloatArrayRegion(widths, 0, b->size(), b->widths());
 }
 
 static JNINativeMethod gMethods[] = {
-    {"nLineBreakOpportunities", "(Ljava/lang/String;[CI[I)[I", (void*) nLineBreakOpportunities}
+    // TODO performance: many of these are candidates for fast jni, awaiting guidance
+    {"nNewBuilder", "()J", (void*) nNewBuilder},
+    {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+    {"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
+    {"nSetLocale", "(JLjava/lang/String;)V", (void*) nSetLocale},
+    {"nSetText", "(J[CI)V", (void*) nSetText},
+    {"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
+    {"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
+    {"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
+    {"nGetWidths", "(J[F)V", (void*) nGetWidths},
+    {"nComputeLineBreaks", "(JIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+        (void*) nComputeLineBreaks}
 };
 
 int register_android_text_StaticLayout(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env, "android/text/StaticLayout",
-            gMethods, NELEM(gMethods));
+    gLineBreaks_class = MakeGlobalRefOrDie(env,
+            FindClassOrDie(env, "android/text/StaticLayout$LineBreaks"));
+
+    gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I");
+    gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F");
+    gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[Z");
+
+    return RegisterMethodsOrDie(env, "android/text/StaticLayout", gMethods, NELEM(gMethods));
 }
 
 }
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index fba7255..daf5a61 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -17,38 +17,39 @@
 
 #define LOG_TAG "asset"
 
-#define DEBUG_STYLES(x) //x
-#define THROW_ON_BAD_ID 0
-
 #include <android_runtime/android_util_AssetManager.h>
 
-#include "jni.h"
-#include "JNIHelp.h"
-#include "ScopedStringChars.h"
-#include "ScopedUtfChars.h"
-#include "android_util_Binder.h"
-#include <utils/misc.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/Log.h>
-
-#include <androidfw/Asset.h>
-#include <androidfw/AssetManager.h>
-#include <androidfw/AttributeFinder.h>
-#include <androidfw/ResourceTypes.h>
-
-#include <private/android_filesystem_config.h> // for AID_SYSTEM
-
+#include <inttypes.h>
+#include <linux/capability.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
-#include <linux/capability.h>
+#include <private/android_filesystem_config.h> // for AID_SYSTEM
+
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AttributeFinder.h"
+#include "androidfw/ResourceTypes.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "JNIHelp.h"
+#include "ScopedStringChars.h"
+#include "ScopedUtfChars.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
 
 
 namespace android {
 
+static const bool kThrowOnBadId = false;
+static const bool kDebugStyles = false;
+
 // ----------------------------------------------------------------------------
 
 static struct typedvalue_offsets_t
@@ -651,23 +652,29 @@
         return 0;
     }
 
-    const char16_t* defType16 = defType
-        ? env->GetStringChars(defType, NULL) : NULL;
+    const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
+        : NULL;
     jsize defTypeLen = defType
         ? env->GetStringLength(defType) : 0;
-    const char16_t* defPackage16 = defPackage
-        ? env->GetStringChars(defPackage, NULL) : NULL;
+    const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
+                                                                NULL))
+        : NULL;
     jsize defPackageLen = defPackage
         ? env->GetStringLength(defPackage) : 0;
 
     jint ident = am->getResources().identifierForName(
-        name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
+        reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
+        defType16, defTypeLen, defPackage16, defPackageLen);
 
     if (defPackage16) {
-        env->ReleaseStringChars(defPackage, defPackage16);
+        env->ReleaseStringChars(defPackage,
+                                reinterpret_cast<const jchar*>(defPackage16));
     }
     if (defType16) {
-        env->ReleaseStringChars(defType, defType16);
+        env->ReleaseStringChars(defType,
+                                reinterpret_cast<const jchar*>(defType16));
     }
 
     return ident;
@@ -804,21 +811,21 @@
     ResTable_config config;
     uint32_t typeSpecFlags;
     ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
-#if THROW_ON_BAD_ID
-    if (block == BAD_INDEX) {
-        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-        return 0;
-    }
-#endif
-    uint32_t ref = ident;
-    if (resolve) {
-        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
-#if THROW_ON_BAD_ID
+    if (kThrowOnBadId) {
         if (block == BAD_INDEX) {
             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
             return 0;
         }
-#endif
+    }
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
     }
     if (block >= 0) {
         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
@@ -864,12 +871,12 @@
     uint32_t ref = ident;
     if (resolve) {
         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
-#if THROW_ON_BAD_ID
-        if (block == BAD_INDEX) {
-            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-            return 0;
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
         }
-#endif
     }
     if (block >= 0) {
         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
@@ -927,8 +934,11 @@
     const size_t N = res.getBasePackageCount();
     for (size_t i = 0; i < N; i++) {
         const String16 name = res.getBasePackageName(i);
-        env->CallVoidMethod(sparseArray, gSparseArrayOffsets.put, (jint) res.getBasePackageId(i),
-                env->NewString(name, name.size()));
+        env->CallVoidMethod(
+            sparseArray, gSparseArrayOffsets.put,
+            static_cast<jint>(res.getBasePackageId(i)),
+            env->NewString(reinterpret_cast<const jchar*>(name.string()),
+                           name.size()));
     }
     return sparseArray;
 }
@@ -979,12 +989,12 @@
     uint32_t ref = 0;
     if (resolve) {
         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
-#if THROW_ON_BAD_ID
-        if (block == BAD_INDEX) {
-            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-            return 0;
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
         }
-#endif
     }
     return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
 }
@@ -995,6 +1005,7 @@
 {
     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
     const ResTable& res(theme->getResTable());
+    (void)res;
 
     // XXX Need to use params.
     theme->dumpToLog();
@@ -1046,8 +1057,10 @@
         return JNI_FALSE;
     }
 
-    DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
-        themeToken, defStyleAttr, defStyleRes));
+    if (kDebugStyles) {
+        ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
+              "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
+    }
 
     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
     const ResTable& res = theme->getResTable();
@@ -1114,7 +1127,9 @@
     for (jsize ii=0; ii<NI; ii++) {
         const uint32_t curIdent = (uint32_t)src[ii];
 
-        DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
+        if (kDebugStyles) {
+            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
+        }
 
         // Try to find a value for this attribute...  we prioritize values
         // coming from, first XML attributes, then XML style, then default
@@ -1129,8 +1144,9 @@
             block = -1;
             value.dataType = Res_value::TYPE_ATTRIBUTE;
             value.data = srcValues[ii];
-            DEBUG_STYLES(ALOGI("-> From values: type=0x%x, data=0x%08x",
-                    value.dataType, value.data));
+            if (kDebugStyles) {
+                ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+            }
         }
 
         if (value.dataType == Res_value::TYPE_NULL) {
@@ -1139,8 +1155,9 @@
                 block = defStyleEntry->stringBlock;
                 typeSetFlags = defStyleTypeSetFlags;
                 value = defStyleEntry->map.value;
-                DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
             }
         }
 
@@ -1150,39 +1167,46 @@
             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
                     &resid, &typeSetFlags, &config);
             if (newBlock >= 0) block = newBlock;
-            DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
-                    value.dataType, value.data));
+            if (kDebugStyles) {
+                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+            }
         } else {
             // If we still don't have a value for this attribute, try to find
             // it in the theme!
             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
             if (newBlock >= 0) {
-                DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
                 newBlock = res.resolveReference(&value, block, &resid,
                         &typeSetFlags, &config);
-#if THROW_ON_BAD_ID
-                if (newBlock == BAD_INDEX) {
-                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                    return JNI_FALSE;
+                if (kThrowOnBadId) {
+                    if (newBlock == BAD_INDEX) {
+                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                        return JNI_FALSE;
+                    }
                 }
-#endif
                 if (newBlock >= 0) block = newBlock;
-                DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
             }
         }
 
         // Deal with the special @null value -- it turns back to TYPE_NULL.
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
-            DEBUG_STYLES(ALOGI("-> Setting to @null!"));
+            if (kDebugStyles) {
+                ALOGI("-> Setting to @null!");
+            }
             value.dataType = Res_value::TYPE_NULL;
             value.data = Res_value::DATA_NULL_UNDEFINED;
             block = -1;
         }
 
-        DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
-                curIdent, value.dataType, value.data));
+        if (kDebugStyles) {
+            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
+                  value.data);
+        }
 
         // Write the final value back to Java.
         dest[STYLE_TYPE] = value.dataType;
@@ -1236,8 +1260,11 @@
         return JNI_FALSE;
     }
 
-    DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
-        themeToken, defStyleAttr, defStyleRes, xmlParserToken));
+    if (kDebugStyles) {
+    ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
+          "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
+          xmlParserToken);
+    }
 
     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
     const ResTable& res = theme->getResTable();
@@ -1332,7 +1359,9 @@
     for (jsize ii = 0; ii < NI; ii++) {
         const uint32_t curIdent = (uint32_t)src[ii];
 
-        DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
+        if (kDebugStyles) {
+            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
+        }
 
         // Try to find a value for this attribute...  we prioritize values
         // coming from, first XML attributes, then XML style, then default
@@ -1348,8 +1377,9 @@
             // We found the attribute we were looking for.
             block = kXmlBlock;
             xmlParser->getAttributeValue(xmlAttrIdx, &value);
-            DEBUG_STYLES(ALOGI("-> From XML: type=0x%x, data=0x%08x",
-                    value.dataType, value.data));
+            if (kDebugStyles) {
+                ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
+            }
         }
 
         if (value.dataType == Res_value::TYPE_NULL) {
@@ -1360,8 +1390,9 @@
                 block = styleAttrEntry->stringBlock;
                 typeSetFlags = styleTypeSetFlags;
                 value = styleAttrEntry->map.value;
-                DEBUG_STYLES(ALOGI("-> From style: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
             }
         }
 
@@ -1373,8 +1404,9 @@
                 block = defStyleAttrEntry->stringBlock;
                 typeSetFlags = styleTypeSetFlags;
                 value = defStyleAttrEntry->map.value;
-                DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
             }
         }
 
@@ -1386,41 +1418,50 @@
             if (newBlock >= 0) {
                 block = newBlock;
             }
-            DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
-                    value.dataType, value.data));
+
+            if (kDebugStyles) {
+                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+            }
         } else {
             // If we still don't have a value for this attribute, try to find
             // it in the theme!
             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
             if (newBlock >= 0) {
-                DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+                if (kDebugStyles) {
+                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
                 newBlock = res.resolveReference(&value, block, &resid,
                         &typeSetFlags, &config);
-#if THROW_ON_BAD_ID
-                if (newBlock == BAD_INDEX) {
-                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                    return JNI_FALSE;
+                if (kThrowOnBadId) {
+                    if (newBlock == BAD_INDEX) {
+                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                        return JNI_FALSE;
+                    }
                 }
-#endif
+
                 if (newBlock >= 0) {
                     block = newBlock;
                 }
-                DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
-                        value.dataType, value.data));
+
+                if (kDebugStyles) {
+                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+                }
             }
         }
 
         // Deal with the special @null value -- it turns back to TYPE_NULL.
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
-            DEBUG_STYLES(ALOGI("-> Setting to @null!"));
+            if (kDebugStyles) {
+                ALOGI("-> Setting to @null!");
+            }
             value.dataType = Res_value::TYPE_NULL;
             value.data = Res_value::DATA_NULL_UNDEFINED;
             block = kXmlBlock;
         }
 
-        DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
-                curIdent, value.dataType, value.data));
+        if (kDebugStyles) {
+            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
+        }
 
         // Write the final value back to Java.
         dest[STYLE_TYPE] = value.dataType;
@@ -1549,12 +1590,12 @@
             //printf("Resolving attribute reference\n");
             ssize_t newBlock = res.resolveReference(&value, block, &resid,
                     &typeSetFlags, &config);
-#if THROW_ON_BAD_ID
-            if (newBlock == BAD_INDEX) {
-                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                return JNI_FALSE;
+            if (kThrowOnBadId) {
+                if (newBlock == BAD_INDEX) {
+                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                    return JNI_FALSE;
+                }
             }
-#endif
             if (newBlock >= 0) block = newBlock;
         }
 
@@ -1663,12 +1704,12 @@
             //printf("Resolving attribute reference\n");
             ssize_t newBlock = res.resolveReference(&value, block, &resid,
                     &typeSetFlags, &config);
-#if THROW_ON_BAD_ID
-            if (newBlock == BAD_INDEX) {
-                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                return JNI_FALSE;
+            if (kThrowOnBadId) {
+                if (newBlock == BAD_INDEX) {
+                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                    return JNI_FALSE;
+                }
             }
-#endif
             if (newBlock >= 0) block = newBlock;
         }
 
@@ -1776,12 +1817,12 @@
             stringIndex = value.data;
         }
 
-#if THROW_ON_BAD_ID
-        if (stringBlock == BAD_INDEX) {
-            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-            return array;
+        if (kThrowOnBadId) {
+            if (stringBlock == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
         }
-#endif
 
         //todo: It might be faster to allocate a C array to contain
         //      the blocknums and indices, put them in there and then
@@ -1824,12 +1865,12 @@
 
         // Take care of resolving the found resource to its final value.
         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
-#if THROW_ON_BAD_ID
-        if (block == BAD_INDEX) {
-            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-            return array;
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
         }
-#endif
         if (value.dataType == Res_value::TYPE_STRING) {
             const ResStringPool* pool = res.getTableStringBlock(block);
             const char* str8 = pool->string8At(value.data, &strLen);
@@ -1837,7 +1878,8 @@
                 str = env->NewStringUTF(str8);
             } else {
                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
-                str = env->NewString(str16, strLen);
+                str = env->NewString(reinterpret_cast<const jchar*>(str16),
+                                     strLen);
             }
 
             // If one of our NewString{UTF} calls failed due to memory, an
@@ -1887,12 +1929,12 @@
 
         // Take care of resolving the found resource to its final value.
         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
-#if THROW_ON_BAD_ID
-        if (block == BAD_INDEX) {
-            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-            return array;
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
         }
-#endif
         if (value.dataType >= Res_value::TYPE_FIRST_INT
                 && value.dataType <= Res_value::TYPE_LAST_INT) {
             int intVal = value.data;
@@ -1924,7 +1966,6 @@
         return NULL;
     }
 
-    Res_value value;
     const ResTable::bag_entry* bag = startOfBag;
     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
         int resourceId = bag->map.name.ident;
@@ -2016,7 +2057,7 @@
         (void*) android_content_AssetManager_getAssetRemainingLength },
     { "addAssetPathNative", "(Ljava/lang/String;)I",
         (void*) android_content_AssetManager_addAssetPath },
-    { "addOverlayPath",   "(Ljava/lang/String;)I",
+    { "addOverlayPathNative",   "(Ljava/lang/String;)I",
         (void*) android_content_AssetManager_addOverlayPath },
     { "isUpToDate",     "()Z",
         (void*) android_content_AssetManager_isUpToDate },
@@ -2099,69 +2140,43 @@
     { "getAssetAllocations", "()Ljava/lang/String;",
         (void*) android_content_AssetManager_getAssetAllocations },
     { "getGlobalAssetManagerCount", "()I",
-        (void*) android_content_AssetManager_getGlobalAssetCount },
+        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
 };
 
 int register_android_content_AssetManager(JNIEnv* env)
 {
-    jclass typedValue = env->FindClass("android/util/TypedValue");
-    LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
-    gTypedValueOffsets.mType
-        = env->GetFieldID(typedValue, "type", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
-    gTypedValueOffsets.mData
-        = env->GetFieldID(typedValue, "data", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
-    gTypedValueOffsets.mString
-        = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
-    LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
-    gTypedValueOffsets.mAssetCookie
-        = env->GetFieldID(typedValue, "assetCookie", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
-    gTypedValueOffsets.mResourceId
-        = env->GetFieldID(typedValue, "resourceId", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
-    gTypedValueOffsets.mChangingConfigurations
-        = env->GetFieldID(typedValue, "changingConfigurations", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
-    gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
-    LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
+    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
+                                                 "Ljava/lang/CharSequence;");
+    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
+                                                                 "changingConfigurations", "I");
+    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
 
-    jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
-    LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
-    gAssetFileDescriptorOffsets.mFd
-        = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
-    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
-    gAssetFileDescriptorOffsets.mStartOffset
-        = env->GetFieldID(assetFd, "mStartOffset", "J");
-    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
-    gAssetFileDescriptorOffsets.mLength
-        = env->GetFieldID(assetFd, "mLength", "J");
-    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
+    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
+                                                      "Landroid/os/ParcelFileDescriptor;");
+    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
 
-    jclass assetManager = env->FindClass("android/content/res/AssetManager");
-    LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
-    gAssetManagerOffsets.mObject
-        = env->GetFieldID(assetManager, "mObject", "J");
-    LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
+    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
 
-    jclass stringClass = env->FindClass("java/lang/String");
-    LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
-    g_stringClass = (jclass)env->NewGlobalRef(stringClass);
-    LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
+    jclass stringClass = FindClassOrDie(env, "java/lang/String");
+    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
 
-    jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
-    LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
-    gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
-    gSparseArrayOffsets.constructor =
-            env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
-    LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
-    gSparseArrayOffsets.put =
-            env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
-    LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
+    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
+                                                       "<init>", "()V");
+    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
+                                               "(ILjava/lang/Object;)V");
 
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
+    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+                                NELEM(gAssetManagerMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index e400698..5f42c3d 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -46,7 +46,7 @@
 #include <ScopedUtfChars.h>
 #include <ScopedLocalRef.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 //#undef ALOGV
 //#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
@@ -85,15 +85,6 @@
 
 // ----------------------------------------------------------------------------
 
-static struct debug_offsets_t
-{
-    // Class state.
-    jclass mClass;
-
-} gDebugOffsets;
-
-// ----------------------------------------------------------------------------
-
 static struct error_offsets_t
 {
     jclass mClass;
@@ -215,7 +206,6 @@
         sleep(60);
         ALOGE("Forcefully exiting");
         exit(1);
-        *((int *) 1) = 1;
     }
 
 bail:
@@ -271,9 +261,9 @@
         //printf("\n");
         jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
             code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
-        jthrowable excep = env->ExceptionOccurred();
 
-        if (excep) {
+        if (env->ExceptionCheck()) {
+            jthrowable excep = env->ExceptionOccurred();
             report_exception(env, excep,
                 "*** Uncaught remote exception!  "
                 "(Exceptions are not yet supported across processes.)");
@@ -291,12 +281,12 @@
             set_dalvik_blockguard_policy(env, strict_policy_before);
         }
 
-        jthrowable excep2 = env->ExceptionOccurred();
-        if (excep2) {
-            report_exception(env, excep2,
+        if (env->ExceptionCheck()) {
+            jthrowable excep = env->ExceptionOccurred();
+            report_exception(env, excep,
                 "*** Uncaught exception in onBinderStrictModePolicyChange");
             /* clean up JNI local ref -- we don't return to Java code */
-            env->DeleteLocalRef(excep2);
+            env->DeleteLocalRef(excep);
         }
 
         // Need to always call through the native implementation of
@@ -398,8 +388,8 @@
 
             env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
                     gBinderProxyOffsets.mSendDeathNotice, mObject);
-            jthrowable excep = env->ExceptionOccurred();
-            if (excep) {
+            if (env->ExceptionCheck()) {
+                jthrowable excep = env->ExceptionOccurred();
                 report_exception(env, excep,
                         "*** Uncaught exception returned from death notification!");
             }
@@ -836,21 +826,13 @@
 
 static int int_register_android_os_Binder(JNIEnv* env)
 {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, kBinderPathName);
 
-    clazz = env->FindClass(kBinderPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Binder");
+    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
+    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
 
-    gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gBinderOffsets.mExecTransact
-        = env->GetMethodID(clazz, "execTransact", "(IJJI)Z");
-    assert(gBinderOffsets.mExecTransact);
-
-    gBinderOffsets.mObject
-        = env->GetFieldID(clazz, "mObject", "J");
-    assert(gBinderOffsets.mObject);
-
-    return AndroidRuntime::registerNativeMethods(
+    return RegisterMethodsOrDie(
         env, kBinderPathName,
         gBinderMethods, NELEM(gBinderMethods));
 }
@@ -920,17 +902,12 @@
 
 static int int_register_android_os_BinderInternal(JNIEnv* env)
 {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, kBinderInternalPathName);
 
-    clazz = env->FindClass(kBinderInternalPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class com.android.internal.os.BinderInternal");
+    gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
 
-    gBinderInternalOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gBinderInternalOffsets.mForceGc
-        = env->GetStaticMethodID(clazz, "forceBinderGc", "()V");
-    assert(gBinderInternalOffsets.mForceGc);
-
-    return AndroidRuntime::registerNativeMethods(
+    return RegisterMethodsOrDie(
         env, kBinderInternalPathName,
         gBinderInternalMethods, NELEM(gBinderInternalMethods));
 }
@@ -955,7 +932,8 @@
     IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
     if (target != NULL) {
         const String16& desc = target->getInterfaceDescriptor();
-        return env->NewString(desc.string(), desc.size());
+        return env->NewString(reinterpret_cast<const jchar*>(desc.string()),
+                              desc.size());
     }
     jniThrowException(env, "java/lang/RuntimeException",
             "No binder found for object");
@@ -1024,7 +1002,9 @@
 }
 
 // From frameworks/base/core/java/android/content/EventLogTags.logtags:
-#define ENABLE_BINDER_SAMPLE 0
+
+static const bool kEnableBinderSample = false;
+
 #define LOGTAG_BINDER_OPERATION 52004
 
 static void conditionally_log_binder_call(int64_t start_millis,
@@ -1063,16 +1043,9 @@
 }
 
 // We only measure binder call durations to potentially log them if
-// we're on the main thread.  Unfortunately sim-eng doesn't seem to
-// have gettid, so we just ignore this and don't log if we can't
-// get the thread id.
+// we're on the main thread.
 static bool should_time_binder_calls() {
-#ifdef HAVE_GETTID
-  return (getpid() == androidGetTid());
-#else
-#warning no gettid(), so not logging Binder calls...
-  return false;
-#endif
+  return (getpid() == gettid());
 }
 
 static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
@@ -1102,24 +1075,28 @@
     ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
             target, obj, code);
 
-#if ENABLE_BINDER_SAMPLE
-    // Only log the binder call duration for things on the Java-level main thread.
-    // But if we don't
-    const bool time_binder_calls = should_time_binder_calls();
 
+    bool time_binder_calls;
     int64_t start_millis;
-    if (time_binder_calls) {
-        start_millis = uptimeMillis();
+    if (kEnableBinderSample) {
+        // Only log the binder call duration for things on the Java-level main thread.
+        // But if we don't
+        time_binder_calls = should_time_binder_calls();
+
+        if (time_binder_calls) {
+            start_millis = uptimeMillis();
+        }
     }
-#endif
+
     //printf("Transact from Java code to %p sending: ", target); data->print();
     status_t err = target->transact(code, *data, reply, flags);
     //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
-#if ENABLE_BINDER_SAMPLE
-    if (time_binder_calls) {
-        conditionally_log_binder_call(start_millis, target, code);
+
+    if (kEnableBinderSample) {
+        if (time_binder_calls) {
+            conditionally_log_binder_call(start_millis, target, code);
+        }
     }
-#endif
 
     if (err == NO_ERROR) {
         return JNI_TRUE;
@@ -1244,39 +1221,24 @@
 
 static int int_register_android_os_BinderProxy(JNIEnv* env)
 {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, "java/lang/Error");
+    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
 
-    clazz = env->FindClass("java/lang/Error");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.Error");
-    gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+    clazz = FindClassOrDie(env, kBinderProxyPathName);
+    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
+    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
+            "(Landroid/os/IBinder$DeathRecipient;)V");
 
-    clazz = env->FindClass(kBinderProxyPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.BinderProxy");
+    gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
+    gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf",
+                                                "Ljava/lang/ref/WeakReference;");
+    gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J");
 
-    gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gBinderProxyOffsets.mConstructor
-        = env->GetMethodID(clazz, "<init>", "()V");
-    assert(gBinderProxyOffsets.mConstructor);
-    gBinderProxyOffsets.mSendDeathNotice
-        = env->GetStaticMethodID(clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V");
-    assert(gBinderProxyOffsets.mSendDeathNotice);
+    clazz = FindClassOrDie(env, "java/lang/Class");
+    gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
 
-    gBinderProxyOffsets.mObject
-        = env->GetFieldID(clazz, "mObject", "J");
-    assert(gBinderProxyOffsets.mObject);
-    gBinderProxyOffsets.mSelf
-        = env->GetFieldID(clazz, "mSelf", "Ljava/lang/ref/WeakReference;");
-    assert(gBinderProxyOffsets.mSelf);
-    gBinderProxyOffsets.mOrgue
-        = env->GetFieldID(clazz, "mOrgue", "J");
-    assert(gBinderProxyOffsets.mOrgue);
-
-    clazz = env->FindClass("java/lang/Class");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find java.lang.Class");
-    gClassOffsets.mGetName = env->GetMethodID(clazz, "getName", "()Ljava/lang/String;");
-    assert(gClassOffsets.mGetName);
-
-    return AndroidRuntime::registerNativeMethods(
+    return RegisterMethodsOrDie(
         env, kBinderProxyPathName,
         gBinderProxyMethods, NELEM(gBinderProxyMethods));
 }
@@ -1294,28 +1256,20 @@
     if (int_register_android_os_BinderProxy(env) < 0)
         return -1;
 
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, "android/util/Log");
+    gLogOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gLogOffsets.mLogE = GetStaticMethodIDOrDie(env, clazz, "e",
+            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
 
-    clazz = env->FindClass("android/util/Log");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.util.Log");
-    gLogOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gLogOffsets.mLogE = env->GetStaticMethodID(
-        clazz, "e", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
-    assert(gLogOffsets.mLogE);
+    clazz = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
+    gParcelFileDescriptorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gParcelFileDescriptorOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>",
+                                                                 "(Ljava/io/FileDescriptor;)V");
 
-    clazz = env->FindClass("android/os/ParcelFileDescriptor");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
-    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gParcelFileDescriptorOffsets.mConstructor
-        = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
-
-    clazz = env->FindClass("android/os/StrictMode");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.StrictMode");
-    gStrictModeCallbackOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gStrictModeCallbackOffsets.mCallback = env->GetStaticMethodID(
-        clazz, "onBinderStrictModePolicyChange", "(I)V");
-    LOG_FATAL_IF(gStrictModeCallbackOffsets.mCallback == NULL,
-                 "Unable to find strict mode callback.");
+    clazz = FindClassOrDie(env, "android/os/StrictMode");
+    gStrictModeCallbackOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
+            "onBinderStrictModePolicyChange", "(I)V");
 
     return 0;
 }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 8a0eaa2..5cb8b2e 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -17,7 +17,7 @@
 #include <fcntl.h>
 
 #include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "jni.h"
 #include "log/logger.h"
 
@@ -159,7 +159,7 @@
     }
 
     struct logger_list *logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NONBLOCK, 0, 0);
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
 
     if (!logger_list) {
         jniThrowIOException(env, errno);
@@ -188,6 +188,10 @@
             break;
         }
 
+        if (log_msg.id() != LOG_ID_EVENTS) {
+            continue;
+        }
+
         int32_t tag = * (int32_t *) log_msg.msg();
 
         int found = 0;
@@ -263,33 +267,21 @@
 
 int register_android_util_EventLog(JNIEnv* env) {
     for (int i = 0; i < NELEM(gClasses); ++i) {
-        jclass clazz = env->FindClass(gClasses[i].name);
-        if (clazz == NULL) {
-            ALOGE("Can't find class: %s\n", gClasses[i].name);
-            return -1;
-        }
-        *gClasses[i].clazz = (jclass) env->NewGlobalRef(clazz);
+        jclass clazz = FindClassOrDie(env, gClasses[i].name);
+        *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
     }
 
     for (int i = 0; i < NELEM(gFields); ++i) {
-        *gFields[i].id = env->GetFieldID(
+        *gFields[i].id = GetFieldIDOrDie(env,
                 *gFields[i].c, gFields[i].name, gFields[i].ft);
-        if (*gFields[i].id == NULL) {
-            ALOGE("Can't find field: %s\n", gFields[i].name);
-            return -1;
-        }
     }
 
     for (int i = 0; i < NELEM(gMethods); ++i) {
-        *gMethods[i].id = env->GetMethodID(
+        *gMethods[i].id = GetMethodIDOrDie(env,
                 *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
-        if (*gMethods[i].id == NULL) {
-            ALOGE("Can't find method: %s\n", gMethods[i].name);
-            return -1;
-        }
     }
 
-    return AndroidRuntime::registerNativeMethods(
+    return RegisterMethodsOrDie(
             env,
             "android/util/EventLog",
             gRegisterMethods, NELEM(gRegisterMethods));
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 0327d8c..067d298 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -19,7 +19,7 @@
 #include "jni.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,7 +29,7 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#ifdef HAVE_INOTIFY
+#if defined(__linux__)
 #include <sys/inotify.h>
 #endif
 
@@ -39,29 +39,25 @@
 
 static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
 {
-#ifdef HAVE_INOTIFY
-
-    return (jint)inotify_init();    
-
-#else // HAVE_INOTIFY
-
+#if defined(__linux__)
+    return (jint)inotify_init();
+#else
     return -1;
-
-#endif // HAVE_INOTIFY
+#endif
 }
 
 static void android_os_fileobserver_observe(JNIEnv* env, jobject object, jint fd)
 {
-#ifdef HAVE_INOTIFY
- 
+#if defined(__linux__)
+
     char event_buf[512];
     struct inotify_event* event;
-         
+
     while (1)
     {
         int event_pos = 0;
         int num_bytes = read(fd, event_buf, sizeof(event_buf));
-        
+
         if (num_bytes < (int)sizeof(*event))
         {
             if (errno == EINTR)
@@ -70,14 +66,14 @@
             ALOGE("***** ERROR! android_os_fileobserver_observe() got a short event!");
             return;
         }
-        
+
         while (num_bytes >= (int)sizeof(*event))
         {
             int event_size;
             event = (struct inotify_event *)(event_buf + event_pos);
 
             jstring path = NULL;
-            
+
             if (event->len > 0)
             {
                 path = env->NewStringUTF(event->name);
@@ -98,37 +94,37 @@
             event_pos += event_size;
         }
     }
-    
-#endif // HAVE_INOTIFY
+
+#endif
 }
 
 static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
 {
     int res = -1;
-    
-#ifdef HAVE_INOTIFY
-   
+
+#if defined(__linux__)
+
     if (fd >= 0)
     {
         const char* path = env->GetStringUTFChars(pathString, NULL);
-        
+
         res = inotify_add_watch(fd, path, mask);
-        
+
         env->ReleaseStringUTFChars(pathString, path);
     }
 
-#endif // HAVE_INOTIFY
-    
+#endif
+
     return res;
 }
 
 static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
 {
-#ifdef HAVE_INOTIFY
+#if defined(__linux__)
 
     inotify_rm_watch((int)fd, (uint32_t)wfd);
 
-#endif // HAVE_INOTIFY
+#endif
 }
 
 static JNINativeMethod sMethods[] = {
@@ -137,29 +133,17 @@
     { "observe", "(I)V", (void*)android_os_fileobserver_observe },
     { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
     { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
-    
+
 };
 
 int register_android_os_FileObserver(JNIEnv* env)
 {
-    jclass clazz;
+    jclass clazz = FindClassOrDie(env, "android/os/FileObserver$ObserverThread");
 
-    clazz = env->FindClass("android/os/FileObserver$ObserverThread");
+    method_onEvent = GetMethodIDOrDie(env, clazz, "onEvent", "(IILjava/lang/String;)V");
 
-    if (clazz == NULL)
-	{
-        ALOGE("Can't find android/os/FileObserver$ObserverThread");
-        return -1;
-    }
-
-    method_onEvent = env->GetMethodID(clazz, "onEvent", "(IILjava/lang/String;)V");
-    if (method_onEvent == NULL)
-    {
-        ALOGE("Can't find FileObserver.onEvent(int, int, String)");
-        return -1;
-    }
-
-    return AndroidRuntime::registerNativeMethods(env, "android/os/FileObserver$ObserverThread", sMethods, NELEM(sMethods));
+    return RegisterMethodsOrDie(env, "android/os/FileObserver$ObserverThread", sMethods,
+                                NELEM(sMethods));
 }
 
 } /* namespace android */
diff --git a/core/jni/android_util_FloatMath.cpp b/core/jni/android_util_FloatMath.cpp
deleted file mode 100644
index 73b7a6f..0000000
--- a/core/jni/android_util_FloatMath.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-#include <math.h>
-#include <float.h>
-#include "SkTypes.h"
-
-class MathUtilsGlue {
-public:
-    static float FloorF(JNIEnv* env, jobject clazz, float x) {
-        return floorf(x);
-    }
-    
-    static float CeilF(JNIEnv* env, jobject clazz, float x) {
-        return ceilf(x);
-    }
-    
-    static float SinF(JNIEnv* env, jobject clazz, float x) {
-        return sinf(x);
-    }
-    
-    static float CosF(JNIEnv* env, jobject clazz, float x) {
-        return cosf(x);
-    }
-    
-    static float SqrtF(JNIEnv* env, jobject clazz, float x) {
-        return sqrtf(x);
-    }
-
-    static float ExpF(JNIEnv* env, jobject clazz, float x) {
-        return expf(x);
-    }
-
-    static float PowF(JNIEnv* env, jobject clazz, float x, float y) {
-        return powf(x, y);
-    }
-
-    static float HypotF(JNIEnv* env, jobject clazz, float x, float y) {
-        return hypotf(x, y);
-    }
-};
-
-static JNINativeMethod gMathUtilsMethods[] = {
-    {"floor", "(F)F", (void*) MathUtilsGlue::FloorF},
-    {"ceil", "(F)F", (void*) MathUtilsGlue::CeilF},
-    {"sin", "(F)F", (void*) MathUtilsGlue::SinF},
-    {"cos", "(F)F", (void*) MathUtilsGlue::CosF},
-    {"sqrt", "(F)F", (void*) MathUtilsGlue::SqrtF},
-    {"exp", "(F)F", (void*) MathUtilsGlue::ExpF},
-    {"pow", "(FF)F", (void*) MathUtilsGlue::PowF},
-    {"hypot", "(FF)F", (void*) MathUtilsGlue::HypotF},
-};
-
-int register_android_util_FloatMath(JNIEnv* env)
-{
-    int result = android::AndroidRuntime::registerNativeMethods(env,
-                                            "android/util/FloatMath",
-                                            gMathUtilsMethods,
-                                            SK_ARRAY_COUNT(gMathUtilsMethods));
-    return result;
-}
-
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 93dcbef..9a80f1d 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -26,11 +26,9 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "android_util_Log.h"
 
-#define MIN(a,b) ((a<b)?a:b)
-
 namespace android {
 
 struct levels_t {
@@ -145,21 +143,16 @@
 
 int register_android_util_Log(JNIEnv* env)
 {
-    jclass clazz = env->FindClass("android/util/Log");
+    jclass clazz = FindClassOrDie(env, "android/util/Log");
 
-    if (clazz == NULL) {
-        ALOGE("Can't find android/util/Log");
-        return -1;
-    }
+    levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
+    levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
+    levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
+    levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
+    levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
+    levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));
 
-    levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
-    levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
-    levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
-    levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
-    levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
-    levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
-
-    return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index aaa680f..2830724 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -26,7 +26,7 @@
 #include <utils/Vector.h>
 #include <processgroup/processgroup.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include "android_util_Binder.h"
 #include "JNIHelp.h"
@@ -43,13 +43,13 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#define POLICY_DEBUG 0
 #define GUARD_THREAD_PRIORITY 0
 
-#define DEBUG_PROC(x) //x
-
 using namespace android;
 
+static const bool kDebugPolicy = false;
+static const bool kDebugProc = false;
+
 #if GUARD_THREAD_PRIORITY
 Mutex gKeyCreateMutex;
 static pthread_key_t gBgKey = -1;
@@ -109,7 +109,8 @@
     const jchar* str16 = env->GetStringCritical(name, 0);
     String8 name8;
     if (str16) {
-        name8 = String8(str16, env->GetStringLength(name));
+        name8 = String8(reinterpret_cast<const char16_t*>(str16),
+                        env->GetStringLength(name));
         env->ReleaseStringCritical(name, str16);
     }
 
@@ -140,7 +141,8 @@
     const jchar* str16 = env->GetStringCritical(name, 0);
     String8 name8;
     if (str16) {
-        name8 = String8(str16, env->GetStringLength(name));
+        name8 = String8(reinterpret_cast<const char16_t*>(str16),
+                        env->GetStringLength(name));
         env->ReleaseStringCritical(name, str16);
     }
 
@@ -175,7 +177,6 @@
 {
     ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
     DIR *d;
-    FILE *fp;
     char proc_path[255];
     struct dirent *de;
 
@@ -191,26 +192,27 @@
     }
     SchedPolicy sp = (SchedPolicy) grp;
 
-#if POLICY_DEBUG
-    char cmdline[32];
-    int fd;
+    if (kDebugPolicy) {
+        char cmdline[32];
+        int fd;
 
-    strcpy(cmdline, "unknown");
+        strcpy(cmdline, "unknown");
 
-    sprintf(proc_path, "/proc/%d/cmdline", pid);
-    fd = open(proc_path, O_RDONLY);
-    if (fd >= 0) {
-        int rc = read(fd, cmdline, sizeof(cmdline)-1);
-        cmdline[rc] = 0;
-        close(fd);
+        sprintf(proc_path, "/proc/%d/cmdline", pid);
+        fd = open(proc_path, O_RDONLY);
+        if (fd >= 0) {
+            int rc = read(fd, cmdline, sizeof(cmdline)-1);
+            cmdline[rc] = 0;
+            close(fd);
+        }
+
+        if (sp == SP_BACKGROUND) {
+            ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
+        } else {
+            ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
+        }
     }
 
-    if (sp == SP_BACKGROUND) {
-        ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
-    } else {
-        ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
-    }
-#endif
     sprintf(proc_path, "/proc/%d/task", pid);
     if (!(d = opendir(proc_path))) {
         // If the process exited on us, don't generate an exception
@@ -271,7 +273,7 @@
     // Establishes the calling thread as illegal to put into the background.
     // Typically used only for the system process's main looper.
 #if GUARD_THREAD_PRIORITY
-    ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, androidGetTid());
+    ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid());
     {
         Mutex::Autolock _l(gKeyCreateMutex);
         if (gBgKey == -1) {
@@ -287,7 +289,8 @@
 void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz,
                                               jint tid, jint policy, jint pri)
 {
-#ifdef HAVE_SCHED_SETSCHEDULER
+// linux has sched_setscheduler(), others don't.
+#if defined(__linux__)
     struct sched_param param;
     param.sched_priority = pri;
     int rc = sched_setscheduler(tid, policy, &param);
@@ -306,7 +309,7 @@
     // if we're putting the current thread into the background, check the TLS
     // to make sure this thread isn't guarded.  If it is, raise an exception.
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        if (pid == androidGetTid()) {
+        if (pid == gettid()) {
             void* bgOk = pthread_getspecific(gBgKey);
             if (bgOk == ((void*)0xbaad)) {
                 ALOGE("Thread marked fg-only put self in background!");
@@ -333,7 +336,7 @@
 void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
                                                         jint pri)
 {
-    android_os_Process_setThreadPriority(env, clazz, androidGetTid(), pri);
+    android_os_Process_setThreadPriority(env, clazz, gettid(), pri);
 }
 
 jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
@@ -384,7 +387,8 @@
     const jchar* str = env->GetStringCritical(name, 0);
     String8 name8;
     if (str) {
-        name8 = String8(str, env->GetStringLength(name));
+        name8 = String8(reinterpret_cast<const char16_t*>(str),
+                        env->GetStringLength(name));
         env->ReleaseStringCritical(name, str);
     }
 
@@ -718,7 +722,7 @@
         jint mode = formatData[fi];
         if ((mode&PROC_PARENS) != 0) {
             i++;
-        } else if ((mode&PROC_QUOTES != 0)) {
+        } else if ((mode&PROC_QUOTES) != 0) {
             if (buffer[i] == '"') {
                 i++;
             } else {
@@ -728,7 +732,9 @@
         const char term = (char)(mode&PROC_TERM_MASK);
         const jsize start = i;
         if (i >= endIndex) {
-            DEBUG_PROC(ALOGW("Ran off end of data @%d", i));
+            if (kDebugProc) {
+                ALOGW("Ran off end of data @%d", i);
+            }
             res = JNI_FALSE;
             break;
         }
@@ -828,7 +834,9 @@
     int fd = open(file8, O_RDONLY);
 
     if (fd < 0) {
-        DEBUG_PROC(ALOGW("Unable to open process file: %s\n", file8));
+        if (kDebugProc) {
+            ALOGW("Unable to open process file: %s\n", file8);
+        }
         env->ReleaseStringUTFChars(file, file8);
         return JNI_FALSE;
     }
@@ -839,7 +847,9 @@
     close(fd);
 
     if (len < 0) {
-        DEBUG_PROC(ALOGW("Unable to open process file: %s fd=%d\n", file8, fd));
+        if (kDebugProc) {
+            ALOGW("Unable to open process file: %s fd=%d\n", file8, fd);
+        }
         return JNI_FALSE;
     }
     buffer[len] = 0;
@@ -1044,11 +1054,7 @@
     {"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
 };
 
-const char* const kProcessPathName = "android/os/Process";
-
 int register_android_os_Process(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(
-        env, kProcessPathName,
-        methods, NELEM(methods));
+    return RegisterMethodsOrDie(env, "android/os/Process", methods, NELEM(methods));
 }
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index f29250f..f83eaec 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -20,7 +20,7 @@
 #include "jni.h"
 #include "JNIHelp.h"
 #include <utils/misc.h>
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 #include <utils/Log.h>
 
 #include <androidfw/ResourceTypes.h>
@@ -171,7 +171,7 @@
 
 int register_android_content_StringBlock(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env,
+    return RegisterMethodsOrDie(env,
             "android/content/res/StringBlock", gStringBlockMethods, NELEM(gStringBlockMethods));
 }
 
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 2cccb83..375710e 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
@@ -267,19 +267,20 @@
     const char16_t* ns16 = NULL;
     jsize nsLen = 0;
     if (ns) {
-        ns16 = env->GetStringChars(ns, NULL);
+        ns16 = reinterpret_cast<const char16_t*>(env->GetStringChars(ns, NULL));
         nsLen = env->GetStringLength(ns);
     }
 
-    const char16_t* name16 = env->GetStringChars(name, NULL);
+    const char16_t* name16 = reinterpret_cast<const char16_t*>(
+        env->GetStringChars(name, NULL));
     jsize nameLen = env->GetStringLength(name);
 
     jint idx = static_cast<jint>(st->indexOfAttribute(ns16, nsLen, name16, nameLen));
 
     if (ns) {
-        env->ReleaseStringChars(ns, ns16);
+        env->ReleaseStringChars(ns, reinterpret_cast<const jchar*>(ns16));
     }
-    env->ReleaseStringChars(name, name16);
+    env->ReleaseStringChars(name, reinterpret_cast<const jchar*>(name16));
 
     return idx;
 }
@@ -411,7 +412,7 @@
 
 int register_android_content_XmlBlock(JNIEnv* env)
 {
-    return AndroidRuntime::registerNativeMethods(env,
+    return RegisterMethodsOrDie(env,
             "android/content/res/XmlBlock", gXmlBlockMethods, NELEM(gXmlBlockMethods));
 }
 
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index d4cc159..0d54953 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -18,9 +18,10 @@
 
 //#define LOG_NDEBUG 0
 
-
 #include "JNIHelp.h"
 
+#include <inttypes.h>
+
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 #include <utils/Looper.h>
@@ -28,6 +29,8 @@
 #include <gui/DisplayEventReceiver.h>
 #include "android_os_MessageQueue.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // Number of events to read at a time from the DisplayEventReceiver pipe.
@@ -142,7 +145,7 @@
     int32_t vsyncDisplayId;
     uint32_t vsyncCount;
     if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
-        ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
+        ALOGV("receiver %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
                 this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
         mWaitingForVsync = false;
         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
@@ -260,29 +263,19 @@
             (void*)nativeScheduleVsync }
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_view_DisplayEventReceiver(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/DisplayEventReceiver",
-            gMethods, NELEM(gMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/view/DisplayEventReceiver", gMethods,
+                                   NELEM(gMethods));
 
-    FIND_CLASS(gDisplayEventReceiverClassInfo.clazz, "android/view/DisplayEventReceiver");
+    jclass clazz = FindClassOrDie(env, "android/view/DisplayEventReceiver");
+    gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
-            gDisplayEventReceiverClassInfo.clazz,
-            "dispatchVsync", "(JII)V");
-    GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
-            gDisplayEventReceiverClassInfo.clazz,
-            "dispatchHotplug", "(JIZ)V");
-    return 0;
+    gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
+            gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
+    gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
+            gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V");
+
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
new file mode 100644
index 0000000..f2e6c4b
--- /dev/null
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <androidfw/ResourceTypes.h>
+
+#include <cutils/properties.h>
+
+#include <SkBitmap.h>
+#include <SkRegion.h>
+
+#include <DisplayListRenderer.h>
+#include <Rect.h>
+#include <RenderNode.h>
+#include <CanvasProperty.h>
+#include <Paint.h>
+#include <renderthread/RenderProxy.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using namespace uirenderer;
+
+static struct {
+    jmethodID set;
+} gRectClassInfo;
+
+// ----------------------------------------------------------------------------
+// Setup
+// ----------------------------------------------------------------------------
+
+static void android_view_DisplayListCanvas_setViewport(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jint width, jint height) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->setViewport(width, height);
+}
+
+static void android_view_DisplayListCanvas_setHighContrastText(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jboolean highContrastText) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->setHighContrastText(highContrastText);
+}
+
+static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jboolean reorderEnable) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->insertReorderBarrier(reorderEnable);
+}
+
+static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz,
+        jlong rendererPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->prepare();
+}
+
+static void android_view_DisplayListCanvas_prepareDirty(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jint left, jint top, jint right, jint bottom) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->prepareDirty(left, top, right, bottom);
+}
+
+static void android_view_DisplayListCanvas_finish(JNIEnv* env, jobject clazz,
+        jlong rendererPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->finish();
+}
+
+static void android_view_DisplayListCanvas_setProperty(JNIEnv* env,
+        jobject clazz, jstring name, jstring value) {
+    if (!Caches::hasInstance()) {
+        ALOGW("can't set property, no Caches instance");
+        return;
+    }
+
+    if (name == NULL || value == NULL) {
+        ALOGW("can't set prop, null passed");
+    }
+
+    const char* nameCharArray = env->GetStringUTFChars(name, NULL);
+    const char* valueCharArray = env->GetStringUTFChars(value, NULL);
+    Caches::getInstance().setTempProperty(nameCharArray, valueCharArray);
+    env->ReleaseStringUTFChars(name, nameCharArray);
+    env->ReleaseStringUTFChars(name, valueCharArray);
+}
+
+// ----------------------------------------------------------------------------
+// Functor
+// ----------------------------------------------------------------------------
+
+static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong functorPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
+    android::uirenderer::Rect dirty;
+    renderer->callDrawGLFunction(functor, dirty);
+}
+
+// ----------------------------------------------------------------------------
+// Misc
+// ----------------------------------------------------------------------------
+
+static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
+    return Caches::getInstance().maxTextureSize;
+}
+
+static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
+    return Caches::getInstance().maxTextureSize;
+}
+
+// ----------------------------------------------------------------------------
+// Drawing
+// ----------------------------------------------------------------------------
+
+static void android_view_DisplayListCanvas_drawPatch(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
+        float left, float top, float right, float bottom, jlong paintPtr) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
+    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
+    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
+}
+
+static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
+        jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
+    CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
+    CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
+    CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
+    CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
+    CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
+    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
+    renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
+}
+
+static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
+    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
+    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
+    renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
+}
+
+static void android_view_DisplayListCanvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
+    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
+    if (paint->getStyle() != Paint::kFill_Style ||
+            (paint->isAntiAlias() && !renderer->isCurrentTransformSimple())) {
+        SkRegion::Iterator it(*region);
+        while (!it.done()) {
+            const SkIRect& r = it.rect();
+            renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, *paint);
+            it.next();
+        }
+    } else {
+        int count = 0;
+        Vector<float> rects;
+        SkRegion::Iterator it(*region);
+        while (!it.done()) {
+            const SkIRect& r = it.rect();
+            rects.push(r.fLeft);
+            rects.push(r.fTop);
+            rects.push(r.fRight);
+            rects.push(r.fBottom);
+            count += 4;
+            it.next();
+        }
+        renderer->drawRects(rects.array(), count, paint);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// Display lists
+// ----------------------------------------------------------------------------
+
+static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
+        jobject clazz, jlong rendererPtr) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    return reinterpret_cast<jlong>(renderer->finishRecording());
+}
+
+static jlong android_view_DisplayListCanvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
+    return reinterpret_cast<jlong>(new DisplayListRenderer);
+}
+
+static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
+        jobject clazz, jlong rendererPtr, jlong renderNodePtr,
+        jint flags) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    android::uirenderer::Rect bounds;
+    renderer->drawRenderNode(renderNode, bounds, flags);
+}
+
+// ----------------------------------------------------------------------------
+// Layers
+// ----------------------------------------------------------------------------
+
+static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    renderer->drawLayer(layer, x, y);
+}
+
+// ----------------------------------------------------------------------------
+// Common
+// ----------------------------------------------------------------------------
+
+static jboolean android_view_DisplayListCanvas_isAvailable(JNIEnv* env, jobject clazz) {
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
+        // not in the emulator
+        return JNI_TRUE;
+    }
+    // In the emulator this property will be set to 1 when hardware GLES is
+    // enabled, 0 otherwise. On old emulator versions it will be undefined.
+    property_get("ro.kernel.qemu.gles", prop, "0");
+    return atoi(prop) == 1 ? JNI_TRUE : JNI_FALSE;
+}
+
+// ----------------------------------------------------------------------------
+// Logging
+// ----------------------------------------------------------------------------
+
+static void
+android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/DisplayListCanvas";
+
+static JNINativeMethod gMethods[] = {
+    { "nIsAvailable",       "()Z",             (void*) android_view_DisplayListCanvas_isAvailable },
+    { "nSetViewport",       "(JII)V",          (void*) android_view_DisplayListCanvas_setViewport },
+    { "nSetHighContrastText","(JZ)V",          (void*) android_view_DisplayListCanvas_setHighContrastText },
+    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+    { "nPrepare",           "(J)V",            (void*) android_view_DisplayListCanvas_prepare },
+    { "nPrepareDirty",      "(JIIII)V",        (void*) android_view_DisplayListCanvas_prepareDirty },
+    { "nFinish",            "(J)V",            (void*) android_view_DisplayListCanvas_finish },
+    { "nSetProperty",       "(Ljava/lang/String;Ljava/lang/String;)V",
+            (void*) android_view_DisplayListCanvas_setProperty },
+
+    { "nCallDrawGLFunction", "(JJ)V",          (void*) android_view_DisplayListCanvas_callDrawGLFunction },
+
+    { "nDrawPatch",         "(JJJFFFFJ)V",     (void*) android_view_DisplayListCanvas_drawPatch },
+
+    { "nDrawRects",         "(JJJ)V",          (void*) android_view_DisplayListCanvas_drawRegionAsRects },
+    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_DisplayListCanvas_drawRoundRectProps },
+    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_DisplayListCanvas_drawCircleProps },
+
+    { "nFinishRecording",   "(J)J",            (void*) android_view_DisplayListCanvas_finishRecording },
+    { "nDrawRenderNode",    "(JJI)V",          (void*) android_view_DisplayListCanvas_drawRenderNode },
+
+    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_DisplayListCanvas_createDisplayListRenderer },
+
+    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_DisplayListCanvas_drawLayer },
+
+    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
+    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
+};
+
+static JNINativeMethod gActivityThreadMethods[] = {
+    { "dumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
+                                               (void*) android_app_ActivityThread_dumpGraphics }
+};
+
+int register_android_view_DisplayListCanvas(JNIEnv* env) {
+    jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
+
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+int register_android_app_ActivityThread(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/app/ActivityThread",
+            gActivityThreadMethods, NELEM(gActivityThreadMethods));
+}
+
+};
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
deleted file mode 100644
index 9bbd4fc..0000000
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ /dev/null
@@ -1,991 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include "jni.h"
-#include "GraphicsJNI.h"
-#include <nativehelper/JNIHelp.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include <androidfw/ResourceTypes.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
-#include <cutils/properties.h>
-
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkImageInfo.h>
-#include <SkMatrix.h>
-#include <SkPorterDuff.h>
-#include <SkRegion.h>
-#include <SkScalerContext.h>
-#include <SkTemplates.h>
-#include <SkXfermode.h>
-
-#include <DisplayListRenderer.h>
-#include <Rect.h>
-#include <RenderNode.h>
-#include <CanvasProperty.h>
-#include <Paint.h>
-#include <renderthread/RenderProxy.h>
-
-#include "MinikinUtils.h"
-
-namespace android {
-
-using namespace uirenderer;
-
-/**
- * Note: DisplayListRenderer JNI layer is generated and compiled only on supported
- *       devices. This means all the logic must be compiled only when the
- *       preprocessor variable USE_OPENGL_RENDERER is defined.
- */
-#ifdef USE_OPENGL_RENDERER
-
-// ----------------------------------------------------------------------------
-// Defines
-// ----------------------------------------------------------------------------
-
-// Debug
-#define DEBUG_RENDERER 0
-
-// Debug
-#if DEBUG_RENDERER
-    #define RENDERER_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-    #define RENDERER_LOGD(...)
-#endif
-
-// ----------------------------------------------------------------------------
-
-static struct {
-    jmethodID set;
-} gRectClassInfo;
-
-// ----------------------------------------------------------------------------
-// Constructors
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    RENDERER_LOGD("Destroy DisplayListRenderer");
-    delete renderer;
-}
-
-// ----------------------------------------------------------------------------
-// Setup
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint width, jint height) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->setViewport(width, height);
-}
-
-static void android_view_GLES20Canvas_setHighContrastText(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jboolean highContrastText) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->setHighContrastText(highContrastText);
-}
-
-static void android_view_GLES20Canvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jboolean reorderEnable) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->insertReorderBarrier(reorderEnable);
-}
-
-static int android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jboolean opaque) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return renderer->prepare(opaque);
-}
-
-static int android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint left, jint top, jint right, jint bottom,
-        jboolean opaque) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return renderer->prepareDirty(left, top, right, bottom, opaque);
-}
-
-static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->finish();
-}
-
-static void android_view_GLES20Canvas_setProperty(JNIEnv* env,
-        jobject clazz, jstring name, jstring value) {
-    if (!Caches::hasInstance()) {
-        ALOGW("can't set property, no Caches instance");
-        return;
-    }
-
-    if (name == NULL || value == NULL) {
-        ALOGW("can't set prop, null passed");
-    }
-
-    const char* nameCharArray = env->GetStringUTFChars(name, NULL);
-    const char* valueCharArray = env->GetStringUTFChars(value, NULL);
-    Caches::getInstance().setTempProperty(nameCharArray, valueCharArray);
-    env->ReleaseStringUTFChars(name, nameCharArray);
-    env->ReleaseStringUTFChars(name, valueCharArray);
-}
-
-// ----------------------------------------------------------------------------
-// Functor
-// ----------------------------------------------------------------------------
-
-static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong functorPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    android::uirenderer::Rect dirty;
-    return renderer->callDrawGLFunction(functor, dirty);
-}
-
-// ----------------------------------------------------------------------------
-// Misc
-// ----------------------------------------------------------------------------
-
-static jint android_view_GLES20Canvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
-    return Caches::getInstance().maxTextureSize;
-}
-
-static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
-    return Caches::getInstance().maxTextureSize;
-}
-
-// ----------------------------------------------------------------------------
-// State
-// ----------------------------------------------------------------------------
-
-static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject clazz, jlong rendererPtr,
-        jint flags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return renderer->save(flags);
-}
-
-static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return renderer->getSaveCount();
-}
-
-static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->restore();
-}
-
-static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint saveCount) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->restoreToCount(saveCount);
-}
-
-// ----------------------------------------------------------------------------
-// Layers
-// ----------------------------------------------------------------------------
-
-static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jlong paintPtr, jint saveFlags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    return renderer->saveLayer(left, top, right, bottom, paint, saveFlags);
-}
-
-static jint android_view_GLES20Canvas_saveLayerClip(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong paintPtr, jint saveFlags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
-    return renderer->saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
-            paint, saveFlags);
-}
-
-static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jint alpha, jint saveFlags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
-}
-
-static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint alpha, jint saveFlags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
-    return renderer->saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
-            alpha, saveFlags);
-}
-
-// ----------------------------------------------------------------------------
-// Clipping
-// ----------------------------------------------------------------------------
-
-static jboolean android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const bool result = renderer->quickRejectConservative(left, top, right, bottom);
-    return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jint op) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const bool result = renderer->clipRect(left, top, right, bottom,
-                                           static_cast<SkRegion::Op>(op));
-    return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint left, jint top, jint right, jint bottom,
-        jint op) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const bool result = renderer->clipRect(float(left), float(top), float(right),
-                                           float(bottom),
-                                           static_cast<SkRegion::Op>(op));
-    return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_view_GLES20Canvas_clipPath(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong pathPtr, jint op) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
-    const bool result = renderer->clipPath(path, static_cast<SkRegion::Op>(op));
-    return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_view_GLES20Canvas_clipRegion(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong regionPtr, jint op) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
-    const bool result = renderer->clipRegion(region, static_cast<SkRegion::Op>(op));
-    return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jobject rect) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
-
-    env->CallVoidMethod(rect, gRectClassInfo.set,
-            int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
-
-    return !bounds.isEmpty() ? JNI_TRUE : JNI_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-// Transforms
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat dx, jfloat dy) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->translate(dx, dy);
-}
-
-static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat degrees) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->rotate(degrees);
-}
-
-static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat sx, jfloat sy) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->scale(sx, sy);
-}
-
-static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat sx, jfloat sy) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->skew(sx, sy);
-}
-
-static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong matrixPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    renderer->setMatrix(matrix ? *matrix : SkMatrix::I());
-}
-
-static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong matrixPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    renderer->getMatrix(matrix);
-}
-
-static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong matrixPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    renderer->concatMatrix(*matrix);
-}
-
-// ----------------------------------------------------------------------------
-// Drawing
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong bitmapPtr, jfloat left, jfloat top, jlong paintPtr) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-
-    // apply transform directly to canvas, so it affects shaders correctly
-    renderer->save(SkCanvas::kMatrix_SaveFlag);
-    renderer->translate(left, top);
-    renderer->drawBitmap(bitmap, paint);
-    renderer->restore();
-}
-
-static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong bitmapPtr,
-        float srcLeft, float srcTop, float srcRight, float srcBottom,
-        float dstLeft, float dstTop, float dstRight, float dstBottom, jlong paintPtr) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
-            dstLeft, dstTop, dstRight, dstBottom, paint);
-}
-
-static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong bitmapPtr, jlong matrixPtr, jlong paintPtr) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-
-    // apply transform directly to canvas, so it affects shaders correctly
-    renderer->save(SkCanvas::kMatrix_SaveFlag);
-    renderer->concatMatrix(*matrix);
-    renderer->drawBitmap(bitmap, paint);
-    renderer->restore();
-}
-
-static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jintArray colors, jint offset, jint stride,
-        jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, jlong paintPtr) {
-    // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
-    // correct the alphaType to kOpaque_SkAlphaType.
-    const SkImageInfo info = SkImageInfo::Make(width, height,
-                               hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
-                               kPremul_SkAlphaType);
-    SkBitmap* bitmap = new SkBitmap;
-    if (!bitmap->allocPixels(info)) {
-        delete bitmap;
-        return;
-    }
-
-    if (!GraphicsJNI::SetPixels(env, colors, offset, stride, 0, 0, width, height, *bitmap)) {
-        delete bitmap;
-        return;
-    }
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-
-    // apply transform directly to canvas, so it affects shaders correctly
-    renderer->save(SkCanvas::kMatrix_SaveFlag);
-    renderer->translate(left, top);
-    renderer->drawBitmapData(bitmap, paint);
-    renderer->restore();
-
-    // Note - bitmap isn't deleted as DisplayListRenderer owns it now
-}
-
-static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong bitmapPtr, jint meshWidth, jint meshHeight,
-        jfloatArray vertices, jint offset, jintArray colors, jint colorOffset, jlong paintPtr) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-
-    jfloat* verticesArray = vertices ? env->GetFloatArrayElements(vertices, NULL) + offset : NULL;
-    jint* colorsArray = colors ? env->GetIntArrayElements(colors, NULL) + colorOffset : NULL;
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawBitmapMesh(bitmap, meshWidth, meshHeight, verticesArray, colorsArray, paint);
-
-    if (vertices) env->ReleaseFloatArrayElements(vertices, verticesArray, 0);
-    if (colors) env->ReleaseIntArrayElements(colors, colorsArray, 0);
-}
-
-static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong bitmapPtr, jlong patchPtr,
-        float left, float top, float right, float bottom, jlong paintPtr) {
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
-
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
-}
-
-static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint color, jint modeHandle) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
-    renderer->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
-}
-
-static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawRect(left, top, right, bottom, paint);
-}
-
-static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jfloat rx, jfloat ry, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawRoundRect(left, top, right, bottom, rx, ry, paint);
-}
-
-static void android_view_GLES20Canvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
-        jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
-    CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
-    CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
-    CanvasPropertyPrimitive* bottomProp = reinterpret_cast<CanvasPropertyPrimitive*>(bottomPropPtr);
-    CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
-    CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
-    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
-    renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
-}
-
-static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat x, jfloat y, jfloat radius, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawCircle(x, y, radius, paint);
-}
-
-static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
-    CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
-    CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
-    CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
-    renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
-}
-
-static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawOval(left, top, right, bottom, paint);
-}
-
-static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jfloat startAngle, jfloat sweepAngle, jboolean useCenter, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
-}
-
-static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    if (paint->getStyle() != Paint::kFill_Style ||
-            (paint->isAntiAlias() && !renderer->isCurrentTransformSimple())) {
-        SkRegion::Iterator it(*region);
-        while (!it.done()) {
-            const SkIRect& r = it.rect();
-            renderer->drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
-            it.next();
-        }
-    } else {
-        int count = 0;
-        Vector<float> rects;
-        SkRegion::Iterator it(*region);
-        while (!it.done()) {
-            const SkIRect& r = it.rect();
-            rects.push(r.fLeft);
-            rects.push(r.fTop);
-            rects.push(r.fRight);
-            rects.push(r.fBottom);
-            count += 4;
-            it.next();
-        }
-        renderer->drawRects(rects.array(), count, paint);
-    }
-}
-
-static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    jfloat* storage = env->GetFloatArrayElements(points, NULL);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawPoints(storage + offset, count, paint);
-    env->ReleaseFloatArrayElements(points, storage, 0);
-}
-
-static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong pathPtr, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawPath(path, paint);
-}
-
-static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    jfloat* storage = env->GetFloatArrayElements(points, NULL);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    renderer->drawLines(storage + offset, count, paint);
-    env->ReleaseFloatArrayElements(points, storage, 0);
-}
-
-// ----------------------------------------------------------------------------
-// Draw filters
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_setupPaintFilter(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint clearBits, jint setBits) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->setupPaintFilter(clearBits, setBits);
-}
-
-static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject clazz,
-        jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    renderer->resetPaintFilter();
-}
-
-// ----------------------------------------------------------------------------
-// Text
-// ----------------------------------------------------------------------------
-
-class RenderTextFunctor {
-public:
-    RenderTextFunctor(const Layout& layout, DisplayListRenderer* renderer, jfloat x, jfloat y,
-                Paint* paint, uint16_t* glyphs, float* pos, float totalAdvance,
-                uirenderer::Rect& bounds)
-            : layout(layout), renderer(renderer), x(x), y(y), paint(paint), glyphs(glyphs),
-            pos(pos), totalAdvance(totalAdvance), bounds(bounds) { }
-    void operator()(size_t start, size_t end) {
-        for (size_t i = start; i < end; i++) {
-            glyphs[i] = layout.getGlyphId(i);
-            pos[2 * i] = layout.getX(i);
-            pos[2 * i + 1] = layout.getY(i);
-        }
-        size_t glyphsCount = end - start;
-        int bytesCount = glyphsCount * sizeof(jchar);
-        renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
-            x, y, pos + 2 * start, paint, totalAdvance, bounds);
-    }
-private:
-    const Layout& layout;
-    DisplayListRenderer* renderer;
-    jfloat x;
-    jfloat y;
-    Paint* paint;
-    uint16_t* glyphs;
-    float* pos;
-    float totalAdvance;
-    uirenderer::Rect& bounds;
-};
-
-static void renderTextLayout(DisplayListRenderer* renderer, Layout* layout,
-    jfloat x, jfloat y, Paint* paint) {
-    size_t nGlyphs = layout->nGlyphs();
-    float* pos = new float[nGlyphs * 2];
-    uint16_t* glyphs = new uint16_t[nGlyphs];
-    MinikinRect b;
-    layout->getBounds(&b);
-    android::uirenderer::Rect bounds(b.mLeft, b.mTop, b.mRight, b.mBottom);
-    bounds.translate(x, y);
-    float totalAdvance = layout->getAdvance();
-
-    RenderTextFunctor f(*layout, renderer, x, y, paint, glyphs, pos, totalAdvance, bounds);
-    MinikinUtils::forFontRun(*layout, paint, f);
-    delete[] glyphs;
-    delete[] pos;
-}
-
-static void renderText(DisplayListRenderer* renderer, const jchar* text, int count,
-        jfloat x, jfloat y, int bidiFlags, Paint* paint, TypefaceImpl* typeface) {
-    Layout layout;
-    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
-    x += MinikinUtils::xOffsetForTextAlign(paint, layout);
-    renderTextLayout(renderer, &layout, x, y, paint);
-}
-
-class RenderTextOnPathFunctor {
-public:
-    RenderTextOnPathFunctor(const Layout& layout, DisplayListRenderer* renderer, float hOffset,
-                float vOffset, Paint* paint, SkPath* path)
-            : layout(layout), renderer(renderer), hOffset(hOffset), vOffset(vOffset),
-                paint(paint), path(path) {
-    }
-    void operator()(size_t start, size_t end) {
-        uint16_t glyphs[1];
-        for (size_t i = start; i < end; i++) {
-            glyphs[0] = layout.getGlyphId(i);
-            float x = hOffset + layout.getX(i);
-            float y = vOffset + layout.getY(i);
-            renderer->drawTextOnPath((const char*) glyphs, sizeof(glyphs), 1, path, x, y, paint);
-        }
-    }
-private:
-    const Layout& layout;
-    DisplayListRenderer* renderer;
-    float hOffset;
-    float vOffset;
-    Paint* paint;
-    SkPath* path;
-};
-
-static void renderTextOnPath(DisplayListRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, Paint* paint,
-        TypefaceImpl* typeface) {
-    Layout layout;
-    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
-    hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
-    Paint::Align align = paint->getTextAlign();
-    paint->setTextAlign(Paint::kLeft_Align);
-
-    RenderTextOnPathFunctor f(layout, renderer, hOffset, vOffset, paint, path);
-    MinikinUtils::forFontRun(layout, paint, f);
-    paint->setTextAlign(align);
-}
-
-static void renderTextRun(DisplayListRenderer* renderer, const jchar* text,
-        jint start, jint count, jint contextCount, jfloat x, jfloat y,
-        int bidiFlags, Paint* paint, TypefaceImpl* typeface) {
-    Layout layout;
-    MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
-    x += MinikinUtils::xOffsetForTextAlign(paint, layout);
-    renderTextLayout(renderer, &layout, x, y, paint);
-}
-
-static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jcharArray text, jint index, jint count,
-        jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    jchar* textArray = env->GetCharArrayElements(text, NULL);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
-
-    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 bidiFlags, jlong paintPtr, jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const jchar* textArray = env->GetStringChars(text, NULL);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
-
-    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 bidiFlags, jlong paintPtr,
-        jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    jchar* textArray = env->GetCharArrayElements(text, NULL);
-    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
-
-    renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, bidiFlags, paint, typeface);
-    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 bidiFlags, jlong paintPtr,
-        jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const jchar* textArray = env->GetStringChars(text, NULL);
-    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
-    Paint* paint = reinterpret_cast<Paint*>(paintPtr);
-    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
-
-    renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, bidiFlags, paint, typeface);
-    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, jboolean isRtl,
-        jlong paintPtr, jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    jchar* textArray = env->GetCharArrayElements(text, NULL);
-    Paint* paint = reinterpret_cast<Paint*>(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, 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, jboolean isRtl,
-        jlong paintPtr, jlong typefacePtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    const jchar* textArray = env->GetStringChars(text, NULL);
-    jint count = end - start;
-    jint contextCount = contextEnd - contextStart;
-    Paint* paint = reinterpret_cast<Paint*>(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, bidiFlags, paint, typeface);
-    env->ReleaseStringChars(text, textArray);
-}
-
-// ----------------------------------------------------------------------------
-// Display lists
-// ----------------------------------------------------------------------------
-
-static jlong android_view_GLES20Canvas_finishRecording(JNIEnv* env,
-        jobject clazz, jlong rendererPtr) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    return reinterpret_cast<jlong>(renderer->finishRecording());
-}
-
-static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
-    return reinterpret_cast<jlong>(new DisplayListRenderer);
-}
-
-static jint android_view_GLES20Canvas_drawRenderNode(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong renderNodePtr,
-        jobject dirty, jint flags) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    android::uirenderer::Rect bounds;
-    status_t status = renderer->drawRenderNode(renderNode, bounds, flags);
-    if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
-        env->CallVoidMethod(dirty, gRectClassInfo.set,
-                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
-    }
-    return status;
-}
-
-// ----------------------------------------------------------------------------
-// Layers
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
-    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    renderer->drawLayer(layer, x, y);
-}
-
-#endif // USE_OPENGL_RENDERER
-
-// ----------------------------------------------------------------------------
-// Common
-// ----------------------------------------------------------------------------
-
-static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) {
-#ifdef USE_OPENGL_RENDERER
-    char prop[PROPERTY_VALUE_MAX];
-    if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
-        // not in the emulator
-        return JNI_TRUE;
-    }
-    // In the emulator this property will be set to 1 when hardware GLES is
-    // enabled, 0 otherwise. On old emulator versions it will be undefined.
-    property_get("ro.kernel.qemu.gles", prop, "0");
-    return atoi(prop) == 1 ? JNI_TRUE : JNI_FALSE;
-#else
-    return JNI_FALSE;
-#endif
-}
-
-// ----------------------------------------------------------------------------
-// Logging
-// ----------------------------------------------------------------------------
-
-static void
-android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
-#ifdef USE_OPENGL_RENDERER
-    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::renderthread::RenderProxy::outputLogBuffer(fd);
-#endif // USE_OPENGL_RENDERER
-}
-
-// ----------------------------------------------------------------------------
-// JNI Glue
-// ----------------------------------------------------------------------------
-
-const char* const kClassPathName = "android/view/GLES20Canvas";
-
-static JNINativeMethod gMethods[] = {
-    { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
-
-#ifdef USE_OPENGL_RENDERER
-
-    { "nDestroyRenderer",   "(J)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
-    { "nSetViewport",       "(JII)V",          (void*) android_view_GLES20Canvas_setViewport },
-    { "nSetHighContrastText","(JZ)V",          (void*) android_view_GLES20Canvas_setHighContrastText },
-    { "nInsertReorderBarrier","(JZ)V",         (void*) android_view_GLES20Canvas_insertReorderBarrier },
-    { "nPrepare",           "(JZ)I",           (void*) android_view_GLES20Canvas_prepare },
-    { "nPrepareDirty",      "(JIIIIZ)I",       (void*) android_view_GLES20Canvas_prepareDirty },
-    { "nFinish",            "(J)V",            (void*) android_view_GLES20Canvas_finish },
-    { "nSetProperty",           "(Ljava/lang/String;Ljava/lang/String;)V",
-            (void*) android_view_GLES20Canvas_setProperty },
-
-    { "nCallDrawGLFunction", "(JJ)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
-
-    { "nSave",              "(JI)I",           (void*) android_view_GLES20Canvas_save },
-    { "nRestore",           "(J)V",            (void*) android_view_GLES20Canvas_restore },
-    { "nRestoreToCount",    "(JI)V",           (void*) android_view_GLES20Canvas_restoreToCount },
-    { "nGetSaveCount",      "(J)I",            (void*) android_view_GLES20Canvas_getSaveCount },
-
-    { "nSaveLayer",         "(JFFFFJI)I",      (void*) android_view_GLES20Canvas_saveLayer },
-    { "nSaveLayer",         "(JJI)I",          (void*) android_view_GLES20Canvas_saveLayerClip },
-    { "nSaveLayerAlpha",    "(JFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
-    { "nSaveLayerAlpha",    "(JII)I",          (void*) android_view_GLES20Canvas_saveLayerAlphaClip },
-
-    { "nQuickReject",       "(JFFFF)Z",        (void*) android_view_GLES20Canvas_quickReject },
-    { "nClipRect",          "(JFFFFI)Z",       (void*) android_view_GLES20Canvas_clipRectF },
-    { "nClipRect",          "(JIIIII)Z",       (void*) android_view_GLES20Canvas_clipRect },
-    { "nClipPath",          "(JJI)Z",          (void*) android_view_GLES20Canvas_clipPath },
-    { "nClipRegion",        "(JJI)Z",          (void*) android_view_GLES20Canvas_clipRegion },
-
-    { "nTranslate",         "(JFF)V",          (void*) android_view_GLES20Canvas_translate },
-    { "nRotate",            "(JF)V",           (void*) android_view_GLES20Canvas_rotate },
-    { "nScale",             "(JFF)V",          (void*) android_view_GLES20Canvas_scale },
-    { "nSkew",              "(JFF)V",          (void*) android_view_GLES20Canvas_skew },
-
-    { "nSetMatrix",         "(JJ)V",           (void*) android_view_GLES20Canvas_setMatrix },
-    { "nGetMatrix",         "(JJ)V",           (void*) android_view_GLES20Canvas_getMatrix },
-    { "nConcatMatrix",      "(JJ)V",           (void*) android_view_GLES20Canvas_concatMatrix },
-
-    { "nDrawBitmap",        "(JJFFJ)V",      (void*) android_view_GLES20Canvas_drawBitmap },
-    { "nDrawBitmap",        "(JJFFFFFFFFJ)V",(void*) android_view_GLES20Canvas_drawBitmapRect },
-    { "nDrawBitmap",        "(JJJJ)V",       (void*) android_view_GLES20Canvas_drawBitmapMatrix },
-    { "nDrawBitmap",        "(J[IIIFFIIZJ)V",  (void*) android_view_GLES20Canvas_drawBitmapData },
-
-    { "nDrawBitmapMesh",    "(JJII[FI[IIJ)V",(void*) android_view_GLES20Canvas_drawBitmapMesh },
-
-    { "nDrawPatch",         "(JJJFFFFJ)V",   (void*) android_view_GLES20Canvas_drawPatch },
-
-    { "nDrawColor",         "(JII)V",          (void*) android_view_GLES20Canvas_drawColor },
-    { "nDrawRect",          "(JFFFFJ)V",       (void*) android_view_GLES20Canvas_drawRect },
-    { "nDrawRects",         "(JJJ)V",          (void*) android_view_GLES20Canvas_drawRegionAsRects },
-    { "nDrawRoundRect",     "(JFFFFFFJ)V",     (void*) android_view_GLES20Canvas_drawRoundRect },
-    { "nDrawRoundRect",     "(JJJJJJJJ)V",     (void*) android_view_GLES20Canvas_drawRoundRectProps },
-    { "nDrawCircle",        "(JFFFJ)V",        (void*) android_view_GLES20Canvas_drawCircle },
-    { "nDrawCircle",        "(JJJJJ)V",        (void*) android_view_GLES20Canvas_drawCircleProps },
-    { "nDrawOval",          "(JFFFFJ)V",       (void*) android_view_GLES20Canvas_drawOval },
-    { "nDrawArc",           "(JFFFFFFZJ)V",    (void*) android_view_GLES20Canvas_drawArc },
-    { "nDrawPoints",        "(J[FIIJ)V",       (void*) android_view_GLES20Canvas_drawPoints },
-
-    { "nDrawPath",          "(JJJ)V",          (void*) android_view_GLES20Canvas_drawPath },
-    { "nDrawLines",         "(J[FIIJ)V",       (void*) android_view_GLES20Canvas_drawLines },
-
-    { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
-    { "nResetPaintFilter",  "(J)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
-
-    { "nDrawText",          "(J[CIIFFIJJ)V",   (void*) android_view_GLES20Canvas_drawTextArray },
-    { "nDrawText",          "(JLjava/lang/String;IIFFIJJ)V",
-            (void*) android_view_GLES20Canvas_drawText },
-
-    { "nDrawTextOnPath",    "(J[CIIJFFIJJ)V",  (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
-    { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJJ)V",
-            (void*) android_view_GLES20Canvas_drawTextOnPath },
-
-    { "nDrawTextRun",       "(J[CIIIIFFZJJ)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
-    { "nDrawTextRun",       "(JLjava/lang/String;IIIIFFZJJ)V",
-            (void*) android_view_GLES20Canvas_drawTextRun },
-
-    { "nGetClipBounds",     "(JLandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds },
-
-    { "nFinishRecording",   "(J)J",      (void*) android_view_GLES20Canvas_finishRecording },
-    { "nDrawRenderNode",    "(JJLandroid/graphics/Rect;I)I", (void*) android_view_GLES20Canvas_drawRenderNode },
-
-    { "nCreateDisplayListRenderer", "()J",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
-
-    { "nDrawLayer",              "(JJFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
-
-    { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
-    { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
-
-#endif
-};
-
-static JNINativeMethod gActivityThreadMethods[] = {
-    { "dumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
-                                               (void*) android_app_ActivityThread_dumpGraphics }
-};
-
-
-#ifdef USE_OPENGL_RENDERER
-    #define FIND_CLASS(var, className) \
-            var = env->FindClass(className); \
-            LOG_FATAL_IF(! var, "Unable to find class " className);
-
-    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-            var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-            LOG_FATAL_IF(! var, "Unable to find method " methodName);
-#else
-    #define FIND_CLASS(var, className)
-    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor)
-#endif
-
-int register_android_view_GLES20Canvas(JNIEnv* env) {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/graphics/Rect");
-    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
-
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-const char* const kActivityThreadPathName = "android/app/ActivityThread";
-
-int register_android_app_ActivityThread(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kActivityThreadPathName,
-            gActivityThreadMethods, NELEM(gActivityThreadMethods));
-}
-
-};
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 5ebed9c..a12629f 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -38,6 +38,8 @@
 
 #include <private/gui/ComposerService.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -45,16 +47,7 @@
 // ----------------------------------------------------------------------------
 
 // Debug
-#define DEBUG_GRAPHIC_BUFFER 0
-
-// Debug
-#if DEBUG_GRAPHIC_BUFFER
-    #define GB_LOGD(...) ALOGD(__VA_ARGS__)
-    #define GB_LOGW(...) ALOGW(__VA_ARGS__)
-#else
-    #define GB_LOGD(...)
-    #define GB_LOGW(...)
-#endif
+static const bool kDebugGraphicBuffer = false;
 
 #define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN
 
@@ -116,14 +109,18 @@
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
     if (alloc == NULL) {
-        GB_LOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
+        if (kDebugGraphicBuffer) {
+            ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
+        }
         return NULL;
     }
 
     status_t error;
     sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
     if (buffer == NULL) {
-        GB_LOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
+        if (kDebugGraphicBuffer) {
+            ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
+        }
         return NULL;
     }
 
@@ -277,18 +274,6 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(!var, "Unable to find method " methodName);
-
 const char* const kClassPathName = "android/view/GraphicBuffer";
 
 static JNINativeMethod gMethods[] = {
@@ -307,22 +292,21 @@
 };
 
 int register_android_view_GraphicBuffer(JNIEnv* env) {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/view/GraphicBuffer");
-    GET_FIELD_ID(gGraphicBufferClassInfo.mNativeObject, clazz, "mNativeObject", "J");
+    jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer");
+    gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J");
 
-    FIND_CLASS(clazz, "android/graphics/Rect");
-    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
-    GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
-    GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
-    GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
-    GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+    clazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
+    gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
+    gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
+    gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
-    FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-    GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V");
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
 
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 1ffff03..9e49afb 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -20,7 +20,7 @@
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
 #include <gui/GLConsumer.h>
@@ -41,8 +41,6 @@
 
 using namespace uirenderer;
 
-#ifdef USE_OPENGL_RENDERER
-
 static jboolean android_view_HardwareLayer_prepare(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr, jint width, jint height, jboolean isOpaque) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -84,11 +82,9 @@
 static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return layer->backingLayer()->getTexture();
+    return layer->backingLayer()->getTextureId();
 }
 
-#endif // USE_OPENGL_RENDERER
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -96,8 +92,6 @@
 const char* const kClassPathName = "android/view/HardwareLayer";
 
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
-
     { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
     { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_HardwareLayer_setLayerPaint },
     { "nSetTransform",           "(JJ)V",      (void*) android_view_HardwareLayer_setTransform },
@@ -106,11 +100,10 @@
     { "nUpdateSurfaceTexture",   "(J)V",       (void*) android_view_HardwareLayer_updateSurfaceTexture },
 
     { "nGetTexName",             "(J)I",       (void*) android_view_HardwareLayer_getTexName },
-#endif
 };
 
 int register_android_view_HardwareLayer(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index d667920..4b42ab5 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -26,6 +26,8 @@
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -275,33 +277,19 @@
             (void*)android_view_InputChannel_nativeDup },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_InputChannel(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/InputChannel",
-            gInputChannelMethods, NELEM(gInputChannelMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/view/InputChannel", gInputChannelMethods,
+                                   NELEM(gInputChannelMethods));
 
-    FIND_CLASS(gInputChannelClassInfo.clazz, "android/view/InputChannel");
+    jclass clazz = FindClassOrDie(env, "android/view/InputChannel");
+    gInputChannelClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_FIELD_ID(gInputChannelClassInfo.mPtr, gInputChannelClassInfo.clazz,
-            "mPtr", "J");
-    
-    GET_METHOD_ID(gInputChannelClassInfo.ctor, gInputChannelClassInfo.clazz,
-            "<init>", "()V");
+    gInputChannelClassInfo.mPtr = GetFieldIDOrDie(env, gInputChannelClassInfo.clazz, "mPtr", "J");
 
-    return 0;
+    gInputChannelClassInfo.ctor = GetMethodIDOrDie(env, gInputChannelClassInfo.clazz, "<init>",
+                                                   "()V");
+
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index bef0f84..2323f43 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -25,6 +25,8 @@
 #include "android_view_InputDevice.h"
 #include "android_view_KeyCharacterMap.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -77,24 +79,15 @@
 }
 
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_view_InputDevice(JNIEnv* env)
 {
-    FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
-    gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
+    gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice");
+    gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
 
-    GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
-            "<init>",
+    gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
             "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
 
-    GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
+    gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
 
     return 0;
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index f36bf31..43b8471 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -18,10 +18,6 @@
 
 //#define LOG_NDEBUG 0
 
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-
 #include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
@@ -37,8 +33,12 @@
 
 #include <ScopedLocalRef.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
+static const bool kDebugDispatchCycle = false;
+
 static struct {
     jclass clazz;
 
@@ -92,9 +92,9 @@
         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mInputConsumer(inputChannel), mMessageQueue(messageQueue),
         mBatchedInputEventPending(false), mFdEvents(0) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
+    }
 }
 
 NativeInputEventReceiver::~NativeInputEventReceiver() {
@@ -108,25 +108,25 @@
 }
 
 void NativeInputEventReceiver::dispose() {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
+    }
 
     setFdEvents(0);
 }
 
 status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+    }
 
     status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
     if (status) {
         if (status == WOULD_BLOCK) {
-#if DEBUG_DISPATCH_CYCLE
-            ALOGD("channel '%s' ~ Could not send finished signal immediately.  "
-                    "Enqueued for later.", getInputChannelName());
-#endif
+            if (kDebugDispatchCycle) {
+                ALOGD("channel '%s' ~ Could not send finished signal immediately.  "
+                        "Enqueued for later.", getInputChannelName());
+            }
             Finish finish;
             finish.seq = seq;
             finish.handled = handled;
@@ -156,13 +156,13 @@
 
 int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
-#if DEBUG_DISPATCH_CYCLE
         // This error typically occurs when the publisher has closed the input channel
         // as part of removing a window or finishing an IME session, in which case
         // the consumer will soon be disposed as well.
-        ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
-                "events=0x%x", getInputChannelName(), events);
-#endif
+        if (kDebugDispatchCycle) {
+            ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
+                    "events=0x%x", getInputChannelName(), events);
+        }
         return 0; // remove the callback
     }
 
@@ -181,10 +181,10 @@
                 mFinishQueue.removeItemsAt(0, i);
 
                 if (status == WOULD_BLOCK) {
-#if DEBUG_DISPATCH_CYCLE
-                    ALOGD("channel '%s' ~ Sent %u queued finish events; %u left.",
-                            getInputChannelName(), i, mFinishQueue.size());
-#endif
+                    if (kDebugDispatchCycle) {
+                        ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
+                                getInputChannelName(), i, mFinishQueue.size());
+                    }
                     return 1; // keep the callback, try again later
                 }
 
@@ -200,10 +200,10 @@
                 return 0; // remove the callback
             }
         }
-#if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ Sent %u queued finish events; none left.",
-                getInputChannelName(), mFinishQueue.size());
-#endif
+        if (kDebugDispatchCycle) {
+            ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
+                    getInputChannelName(), mFinishQueue.size());
+        }
         mFinishQueue.clear();
         setFdEvents(ALOOPER_EVENT_INPUT);
         return 1;
@@ -216,10 +216,10 @@
 
 status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
         bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
-            getInputChannelName(), consumeBatches ? "true" : "false", frameTime);
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
+                getInputChannelName(), consumeBatches ? "true" : "false", (long long)frameTime);
+    }
 
     if (consumeBatches) {
         mBatchedInputEventPending = false;
@@ -250,10 +250,10 @@
                     }
 
                     mBatchedInputEventPending = true;
-#if DEBUG_DISPATCH_CYCLE
-                    ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
-                            getInputChannelName());
-#endif
+                    if (kDebugDispatchCycle) {
+                        ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
+                                getInputChannelName());
+                    }
                     env->CallVoidMethod(receiverObj.get(),
                             gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
                     if (env->ExceptionCheck()) {
@@ -282,17 +282,17 @@
             jobject inputEventObj;
             switch (inputEvent->getType()) {
             case AINPUT_EVENT_TYPE_KEY:
-#if DEBUG_DISPATCH_CYCLE
-                ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
-#endif
+                if (kDebugDispatchCycle) {
+                    ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
+                }
                 inputEventObj = android_view_KeyEvent_fromNative(env,
                         static_cast<KeyEvent*>(inputEvent));
                 break;
 
             case AINPUT_EVENT_TYPE_MOTION: {
-#if DEBUG_DISPATCH_CYCLE
-                ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
-#endif
+                if (kDebugDispatchCycle) {
+                    ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
+                }
                 MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
                 if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
                     *outConsumedBatch = true;
@@ -307,9 +307,9 @@
             }
 
             if (inputEventObj) {
-#if DEBUG_DISPATCH_CYCLE
-                ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
-#endif
+                if (kDebugDispatchCycle) {
+                    ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
+                }
                 env->CallVoidMethod(receiverObj.get(),
                         gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                 if (env->ExceptionCheck()) {
@@ -408,29 +408,20 @@
             (void*)nativeConsumeBatchedInputEvents },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_view_InputEventReceiver(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/InputEventReceiver",
+    int res = RegisterMethodsOrDie(env, "android/view/InputEventReceiver",
             gMethods, NELEM(gMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
-    FIND_CLASS(gInputEventReceiverClassInfo.clazz, "android/view/InputEventReceiver");
+    jclass clazz = FindClassOrDie(env, "android/view/InputEventReceiver");
+    gInputEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
+    gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env,
             gInputEventReceiverClassInfo.clazz,
             "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
-    GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
-            gInputEventReceiverClassInfo.clazz,
-            "dispatchBatchedInputEventPending", "()V");
-    return 0;
+    gInputEventReceiverClassInfo.dispatchBatchedInputEventPending = GetMethodIDOrDie(env,
+            gInputEventReceiverClassInfo.clazz, "dispatchBatchedInputEventPending", "()V");
+
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index f156b9a..265daeb 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -18,10 +18,6 @@
 
 //#define LOG_NDEBUG 0
 
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-
 #include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
@@ -37,8 +33,13 @@
 
 #include <ScopedLocalRef.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
+// Log debug messages about the dispatch cycle.
+static const bool kDebugDispatchCycle = false;
+
 static struct {
     jclass clazz;
 
@@ -82,9 +83,9 @@
         mSenderWeakGlobal(env->NewGlobalRef(senderWeak)),
         mInputPublisher(inputChannel), mMessageQueue(messageQueue),
         mNextPublishedSeq(1) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName());
+    }
 }
 
 NativeInputEventSender::~NativeInputEventSender() {
@@ -99,17 +100,17 @@
 }
 
 void NativeInputEventSender::dispose() {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Disposing input event sender.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Disposing input event sender.", getInputChannelName());
+    }
 
     mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd());
 }
 
 status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName(), seq);
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName(), seq);
+    }
 
     uint32_t publishedSeq = mNextPublishedSeq++;
     status_t status = mInputPublisher.publishKeyEvent(publishedSeq,
@@ -126,9 +127,9 @@
 }
 
 status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent* event) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName(), seq);
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName(), seq);
+    }
 
     uint32_t publishedSeq;
     for (size_t i = 0; i <= event->getHistorySize(); i++) {
@@ -153,13 +154,14 @@
 
 int NativeInputEventSender::handleEvent(int receiveFd, int events, void* data) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
-#if DEBUG_DISPATCH_CYCLE
         // This error typically occurs when the consumer has closed the input channel
         // as part of finishing an IME session, in which case the publisher will
         // soon be disposed as well.
-        ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred.  "
-                "events=0x%x", getInputChannelName(), events);
-#endif
+        if (kDebugDispatchCycle) {
+            ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred.  "
+                    "events=0x%x", getInputChannelName(), events);
+        }
+
         return 0; // remove the callback
     }
 
@@ -176,9 +178,9 @@
 }
 
 status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName());
-#endif
+    if (kDebugDispatchCycle) {
+        ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName());
+    }
 
     ScopedLocalRef<jobject> senderObj(env, NULL);
     bool skipCallbacks = false;
@@ -200,12 +202,12 @@
             uint32_t seq = mPublishedSeqMap.valueAt(index);
             mPublishedSeqMap.removeItemsAt(index);
 
-#if DEBUG_DISPATCH_CYCLE
-            ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
-                    "pendingEvents=%u.",
-                    getInputChannelName(), seq, handled ? "true" : "false",
-                    mPublishedSeqMap.size());
-#endif
+            if (kDebugDispatchCycle) {
+                ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
+                        "pendingEvents=%zu.",
+                        getInputChannelName(), seq, handled ? "true" : "false",
+                        mPublishedSeqMap.size());
+            }
 
             if (!skipCallbacks) {
                 if (!senderObj.get()) {
@@ -299,26 +301,16 @@
             (void*)nativeSendMotionEvent },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_view_InputEventSender(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/InputEventSender",
-            gMethods, NELEM(gMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/view/InputEventSender", gMethods, NELEM(gMethods));
 
-    FIND_CLASS(gInputEventSenderClassInfo.clazz, "android/view/InputEventSender");
+    jclass clazz = FindClassOrDie(env, "android/view/InputEventSender");
+    gInputEventSenderClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_METHOD_ID(gInputEventSenderClassInfo.dispatchInputEventFinished,
-            gInputEventSenderClassInfo.clazz,
-            "dispatchInputEventFinished", "(IZ)V");
-    return 0;
+    gInputEventSenderClassInfo.dispatchInputEventFinished = GetMethodIDOrDie(
+            env, gInputEventSenderClassInfo.clazz, "dispatchInputEventFinished", "(IZ)V");
+
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 21b73b1..96ccdee 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -33,6 +33,8 @@
 #include "android_view_KeyEvent.h"
 #include "android_view_MotionEvent.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -256,27 +258,13 @@
 
 static const char* const kInputQueuePathName = "android/view/InputQueue";
 
-#define FIND_CLASS(var, className) \
-        do { \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class %s", className); \
-        } while(0)
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        do { \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName); \
-        } while(0)
-
 int register_android_view_InputQueue(JNIEnv* env)
 {
-    jclass clazz;
-    FIND_CLASS(clazz, kInputQueuePathName);
-    GET_METHOD_ID(gInputQueueClassInfo.finishInputEvent, clazz, "finishInputEvent", "(JZ)V");
+    jclass clazz = FindClassOrDie(env, kInputQueuePathName);
+    gInputQueueClassInfo.finishInputEvent = GetMethodIDOrDie(env, clazz, "finishInputEvent",
+                                                             "(JZ)V");
 
-    return AndroidRuntime::registerNativeMethods(
-        env, kInputQueuePathName,
-        g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, kInputQueuePathName, g_methods, NELEM(g_methods));
 }
 
 } // namespace android
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 62d5129..7653f58 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -26,6 +26,8 @@
 #include "android_os_Parcel.h"
 #include "android_view_KeyEvent.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -148,7 +150,9 @@
         return 0;
     }
 
-    char16_t result = map->getMap()->getMatch(keyCode, chars, size_t(numChars), metaState);
+    char16_t result = map->getMap()->getMatch(
+        keyCode, reinterpret_cast<char16_t*>(chars), size_t(numChars),
+        metaState);
 
     env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
     return result;
@@ -176,7 +180,9 @@
 
     Vector<KeyEvent> events;
     jobjectArray result = NULL;
-    if (map->getMap()->getEvents(map->getDeviceId(), chars, size_t(numChars), events)) {
+    if (map->getMap()->getEvents(map->getDeviceId(),
+                                 reinterpret_cast<char16_t*>(chars),
+                                 size_t(numChars), events)) {
         result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
         if (result) {
             for (size_t i = 0; i < events.size(); i++) {
@@ -221,40 +227,23 @@
             (void*)nativeGetEvents },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_KeyCharacterMap(JNIEnv* env)
 {
-    FIND_CLASS(gKeyCharacterMapClassInfo.clazz, "android/view/KeyCharacterMap");
-    gKeyCharacterMapClassInfo.clazz = jclass(env->NewGlobalRef(gKeyCharacterMapClassInfo.clazz));
+    gKeyCharacterMapClassInfo.clazz = FindClassOrDie(env, "android/view/KeyCharacterMap");
+    gKeyCharacterMapClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyCharacterMapClassInfo.clazz);
 
-    GET_METHOD_ID(gKeyCharacterMapClassInfo.ctor, gKeyCharacterMapClassInfo.clazz,
+    gKeyCharacterMapClassInfo.ctor = GetMethodIDOrDie(env, gKeyCharacterMapClassInfo.clazz,
             "<init>", "(J)V");
 
-    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
-    gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
+    gKeyEventClassInfo.clazz = FindClassOrDie(env, "android/view/KeyEvent");
+    gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, gKeyEventClassInfo.clazz);
 
-    jclass clazz;
-    FIND_CLASS(clazz, "android/view/KeyCharacterMap$FallbackAction");
+    jclass clazz = FindClassOrDie(env, "android/view/KeyCharacterMap$FallbackAction");
 
-    GET_FIELD_ID(gFallbackActionClassInfo.keyCode, clazz,
-            "keyCode", "I");
+    gFallbackActionClassInfo.keyCode = GetFieldIDOrDie(env, clazz, "keyCode", "I");
+    gFallbackActionClassInfo.metaState = GetFieldIDOrDie(env, clazz, "metaState", "I");
 
-    GET_FIELD_ID(gFallbackActionClassInfo.metaState, clazz,
-            "metaState", "I");
-
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/view/KeyCharacterMap", g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "android/view/KeyCharacterMap", g_methods, NELEM(g_methods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 7ae21a7..216e6f6 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -25,6 +25,8 @@
 #include <ScopedUtfChars.h>
 #include "android_view_KeyEvent.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -124,56 +126,32 @@
         (void*)android_view_KeyEvent_nativeKeyCodeFromString},
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_KeyEvent(JNIEnv* env) {
-    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+    jclass clazz = FindClassOrDie(env, "android/view/KeyEvent");
+    gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_STATIC_METHOD_ID(gKeyEventClassInfo.obtain, gKeyEventClassInfo.clazz,
+    gKeyEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz,
             "obtain", "(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;");
-    GET_METHOD_ID(gKeyEventClassInfo.recycle, gKeyEventClassInfo.clazz,
+    gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz,
             "recycle", "()V");
 
-    GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
-            "mDeviceId", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mSource, gKeyEventClassInfo.clazz,
-            "mSource", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mMetaState, gKeyEventClassInfo.clazz,
-            "mMetaState", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mAction, gKeyEventClassInfo.clazz,
-            "mAction", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mKeyCode, gKeyEventClassInfo.clazz,
-            "mKeyCode", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mScanCode, gKeyEventClassInfo.clazz,
-            "mScanCode", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mRepeatCount, gKeyEventClassInfo.clazz,
-            "mRepeatCount", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mFlags, gKeyEventClassInfo.clazz,
-            "mFlags", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mDownTime, gKeyEventClassInfo.clazz,
-            "mDownTime", "J");
-    GET_FIELD_ID(gKeyEventClassInfo.mEventTime, gKeyEventClassInfo.clazz,
-            "mEventTime", "J");
-    GET_FIELD_ID(gKeyEventClassInfo.mCharacters, gKeyEventClassInfo.clazz,
-            "mCharacters", "Ljava/lang/String;");
+    gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I");
+    gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I");
+    gKeyEventClassInfo.mMetaState = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mMetaState",
+                                                    "I");
+    gKeyEventClassInfo.mAction = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mAction", "I");
+    gKeyEventClassInfo.mKeyCode = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mKeyCode", "I");
+    gKeyEventClassInfo.mScanCode = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mScanCode", "I");
+    gKeyEventClassInfo.mRepeatCount = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mRepeatCount",
+                                                      "I");
+    gKeyEventClassInfo.mFlags = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mFlags", "I");
+    gKeyEventClassInfo.mDownTime = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDownTime", "J");
+    gKeyEventClassInfo.mEventTime = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mEventTime",
+                                                    "J");
+    gKeyEventClassInfo.mCharacters = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mCharacters",
+                                                     "Ljava/lang/String;");
 
-    return AndroidRuntime::registerNativeMethods(
-        env, "android/view/KeyEvent", g_methods, NELEM(g_methods));
+    return RegisterMethodsOrDie(env, "android/view/KeyEvent", g_methods, NELEM(g_methods));
 }
 
 } // namespace android
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index a590dbf..e622768 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -29,6 +29,8 @@
 #include "android_util_Binder.h"
 #include "android/graphics/Matrix.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -296,7 +298,6 @@
         jfloat* outValues = static_cast<jfloat*>(env->GetPrimitiveArrayCritical(
                 outValuesArray, NULL));
 
-        const float* values = rawPointerCoords->values;
         uint32_t index = 0;
         do {
             uint32_t axis = bits.clearFirstMarkedBit();
@@ -853,71 +854,41 @@
             (void*)android_view_MotionEvent_nativeAxisFromString },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
-
-#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
-        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method" methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_MotionEvent(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
-            gMotionEventMethods, NELEM(gMotionEventMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/view/MotionEvent", gMotionEventMethods,
+                                   NELEM(gMotionEventMethods));
 
-    FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
-    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
+    gMotionEventClassInfo.clazz = FindClassOrDie(env, "android/view/MotionEvent");
+    gMotionEventClassInfo.clazz = MakeGlobalRefOrDie(env, gMotionEventClassInfo.clazz);
 
-    GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
+    gMotionEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gMotionEventClassInfo.clazz,
             "obtain", "()Landroid/view/MotionEvent;");
-    GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
+    gMotionEventClassInfo.recycle = GetMethodIDOrDie(env, gMotionEventClassInfo.clazz,
             "recycle", "()V");
-    GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
+    gMotionEventClassInfo.mNativePtr = GetFieldIDOrDie(env, gMotionEventClassInfo.clazz,
             "mNativePtr", "J");
 
-    jclass clazz;
-    FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
+    jclass clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerCoords");
 
-    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
-            "mPackedAxisBits", "J");
-    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
-            "mPackedAxisValues", "[F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
-            "x", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
-            "y", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
-            "pressure", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
-            "size", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
-            "touchMajor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
-            "touchMinor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
-            "toolMajor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
-            "toolMinor", "F");
-    GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
-            "orientation", "F");
+    gPointerCoordsClassInfo.mPackedAxisBits = GetFieldIDOrDie(env, clazz, "mPackedAxisBits", "J");
+    gPointerCoordsClassInfo.mPackedAxisValues = GetFieldIDOrDie(env, clazz, "mPackedAxisValues",
+                                                                "[F");
+    gPointerCoordsClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "F");
+    gPointerCoordsClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "F");
+    gPointerCoordsClassInfo.pressure = GetFieldIDOrDie(env, clazz, "pressure", "F");
+    gPointerCoordsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "F");
+    gPointerCoordsClassInfo.touchMajor = GetFieldIDOrDie(env, clazz, "touchMajor", "F");
+    gPointerCoordsClassInfo.touchMinor = GetFieldIDOrDie(env, clazz, "touchMinor", "F");
+    gPointerCoordsClassInfo.toolMajor = GetFieldIDOrDie(env, clazz, "toolMajor", "F");
+    gPointerCoordsClassInfo.toolMinor = GetFieldIDOrDie(env, clazz, "toolMinor", "F");
+    gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F");
 
-    FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
+    clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties");
 
-    GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
-            "id", "I");
-    GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
-            "toolType", "I");
+    gPointerPropertiesClassInfo.id = GetFieldIDOrDie(env, clazz, "id", "I");
+    gPointerPropertiesClassInfo.toolType = GetFieldIDOrDie(env, clazz, "toolType", "I");
 
-    return 0;
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 5e29213..f6d9a1a 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -25,6 +25,8 @@
 #include <utils/Log.h>
 #include <android/graphics/GraphicsJNI.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 static struct {
@@ -78,7 +80,7 @@
 
     jobject bitmapObj = env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmap);
     if (bitmapObj) {
-        SkBitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj);
+        SkBitmap* bitmap = GraphicsJNI::getSkBitmap(env, bitmapObj);
         if (bitmap) {
             outPointerIcon->bitmap = *bitmap; // use a shared pixel ref
         }
@@ -106,42 +108,26 @@
 
 // --- JNI Registration ---
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
-        var = jclass(env->NewGlobalRef(var));
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_PointerIcon(JNIEnv* env) {
-    FIND_CLASS(gPointerIconClassInfo.clazz, "android/view/PointerIcon");
+    jclass clazz = FindClassOrDie(env, "android/view/PointerIcon");
+    gPointerIconClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
-    GET_FIELD_ID(gPointerIconClassInfo.mBitmap, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.mBitmap = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
             "mBitmap", "Landroid/graphics/Bitmap;");
 
-    GET_FIELD_ID(gPointerIconClassInfo.mStyle, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.mStyle = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
             "mStyle", "I");
 
-    GET_FIELD_ID(gPointerIconClassInfo.mHotSpotX, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.mHotSpotX = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
             "mHotSpotX", "F");
 
-    GET_FIELD_ID(gPointerIconClassInfo.mHotSpotY, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.mHotSpotY = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
             "mHotSpotY", "F");
 
-    GET_STATIC_METHOD_ID(gPointerIconClassInfo.getSystemIcon, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.getSystemIcon = GetStaticMethodIDOrDie(env, gPointerIconClassInfo.clazz,
             "getSystemIcon", "(Landroid/content/Context;I)Landroid/view/PointerIcon;");
 
-    GET_METHOD_ID(gPointerIconClassInfo.load, gPointerIconClassInfo.clazz,
+    gPointerIconClassInfo.load = GetMethodIDOrDie(env, gPointerIconClassInfo.clazz,
             "load", "(Landroid/content/Context;)Landroid/view/PointerIcon;");
 
     return 0;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 621df72..2b5a961 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -28,17 +28,12 @@
 #include <RenderNode.h>
 #include <Paint.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 using namespace uirenderer;
 
-/**
- * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
- *       devices. This means all the logic must be compiled only when the
- *       preprocessor variable USE_OPENGL_RENDERER is defined.
- */
-#ifdef USE_OPENGL_RENDERER
-
 #define SET_AND_DIRTY(prop, val, dirtyFlag) \
     (reinterpret_cast<RenderNode*>(renderNodePtr)->mutateStagingProperties().prop(val) \
         ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
@@ -467,8 +462,6 @@
     renderNode->animators().endAllStagingAnimators();
 }
 
-#endif // USE_OPENGL_RENDERER
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -476,7 +469,6 @@
 const char* const kClassPathName = "android/view/RenderNode";
 
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
     { "nCreate",               "(Ljava/lang/String;)J",    (void*) android_view_RenderNode_create },
     { "nDestroyRenderNode",   "(J)V",   (void*) android_view_RenderNode_destroyRenderNode },
     { "nSetDisplayListData",   "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
@@ -548,24 +540,10 @@
 
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
     { "nEndAllAnimators",          "(J)V", (void*) android_view_RenderNode_endAllAnimators },
-#endif
 };
 
-#ifdef USE_OPENGL_RENDERER
-    #define FIND_CLASS(var, className) \
-            var = env->FindClass(className); \
-            LOG_FATAL_IF(! var, "Unable to find class " className);
-
-    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-            var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-            LOG_FATAL_IF(! var, "Unable to find method " methodName);
-#else
-    #define FIND_CLASS(var, className)
-    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor)
-#endif
-
 int register_android_view_RenderNode(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index eb56639..4177ee2 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -25,6 +25,8 @@
 #include <Interpolator.h>
 #include <RenderProperties.h>
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 using namespace uirenderer;
@@ -35,8 +37,6 @@
     jmethodID callOnFinished;
 } gRenderNodeAnimatorClassInfo;
 
-#ifdef USE_OPENGL_RENDERER
-
 static JNIEnv* getEnv(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -161,11 +161,6 @@
     animator->setStartDelay(startDelay);
 }
 
-static jlong getStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr) {
-    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
-    return static_cast<jlong>(animator->startDelay());
-}
-
 static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
@@ -192,8 +187,6 @@
     animator->end();
 }
 
-#endif
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -201,7 +194,6 @@
 const char* const kClassPathName = "android/view/RenderNodeAnimator";
 
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
     { "nCreateAnimator", "(IF)J", (void*) createAnimator },
     { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator },
@@ -215,28 +207,19 @@
     { "nSetListener", "(JLandroid/view/RenderNodeAnimator;)V", (void*) setListener},
     { "nStart", "(J)V", (void*) start},
     { "nEnd", "(J)V", (void*) end },
-#endif
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
 int register_android_view_RenderNodeAnimator(JNIEnv* env) {
-#ifdef USE_OPENGL_RENDERER
     sLifecycleChecker.incStrong(0);
-#endif
-    FIND_CLASS(gRenderNodeAnimatorClassInfo.clazz, kClassPathName);
-    gRenderNodeAnimatorClassInfo.clazz = jclass(env->NewGlobalRef(gRenderNodeAnimatorClassInfo.clazz));
+    gRenderNodeAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName);
+    gRenderNodeAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env,
+                                                            gRenderNodeAnimatorClassInfo.clazz);
 
-    GET_STATIC_METHOD_ID(gRenderNodeAnimatorClassInfo.callOnFinished, gRenderNodeAnimatorClassInfo.clazz,
-            "callOnFinished", "(Landroid/view/RenderNodeAnimator;)V");
+    gRenderNodeAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
+            env, gRenderNodeAnimatorClassInfo.clazz, "callOnFinished",
+            "(Landroid/view/RenderNodeAnimator;)V");
 
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index a39ff8e..fff8604 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -23,7 +23,7 @@
 #include "android_os_Parcel.h"
 #include "android/graphics/GraphicsJNI.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <android_runtime/Log.h>
@@ -49,6 +49,7 @@
 
 #include <AnimationContext.h>
 #include <DisplayListRenderer.h>
+#include <FrameInfo.h>
 #include <RenderNode.h>
 #include <renderthread/RenderProxy.h>
 
@@ -129,6 +130,100 @@
     return surfaceObj;
 }
 
+int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f) {
+
+    switch(f) {
+        case PublicFormat::JPEG:
+        case PublicFormat::DEPTH_POINT_CLOUD:
+            return HAL_PIXEL_FORMAT_BLOB;
+        case PublicFormat::DEPTH16:
+            return HAL_PIXEL_FORMAT_Y16;
+        case PublicFormat::RAW_SENSOR:
+            return HAL_PIXEL_FORMAT_RAW16;
+        default:
+            // Most formats map 1:1
+            return static_cast<int>(f);
+    }
+}
+
+android_dataspace android_view_Surface_mapPublicFormatToHalDataspace(
+        PublicFormat f) {
+    switch(f) {
+        case PublicFormat::JPEG:
+            return HAL_DATASPACE_JFIF;
+        case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH16:
+            return HAL_DATASPACE_DEPTH;
+        case PublicFormat::RAW_SENSOR:
+        case PublicFormat::RAW10:
+            return HAL_DATASPACE_ARBITRARY;
+        case PublicFormat::YUV_420_888:
+        case PublicFormat::NV21:
+        case PublicFormat::YV12:
+            return HAL_DATASPACE_JFIF;
+        default:
+            // Most formats map to UNKNOWN
+            return HAL_DATASPACE_UNKNOWN;
+    }
+}
+
+PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+        int format, android_dataspace dataSpace) {
+    switch(format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+        case HAL_PIXEL_FORMAT_Y8:
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+        case HAL_PIXEL_FORMAT_YV12:
+            // Enums overlap in both name and value
+            return static_cast<PublicFormat>(format);
+        case HAL_PIXEL_FORMAT_RAW16:
+            // Name differs, though value is the same
+            return PublicFormat::RAW_SENSOR;
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV16;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            // Name differs, though the value is the same
+            return PublicFormat::NV21;
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+            // Name differs, though the value is the same
+            return PublicFormat::YUY2;
+        case HAL_PIXEL_FORMAT_Y16:
+            // Dataspace-dependent
+            switch (dataSpace) {
+                case HAL_DATASPACE_DEPTH:
+                    return PublicFormat::DEPTH16;
+                default:
+                    // Assume non-depth Y16 is just Y16.
+                    return PublicFormat::Y16;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Dataspace-dependent
+            switch (dataSpace) {
+                case HAL_DATASPACE_DEPTH:
+                    return PublicFormat::DEPTH_POINT_CLOUD;
+                case HAL_DATASPACE_JFIF:
+                    return PublicFormat::JPEG;
+                default:
+                    // Assume otherwise-marked blobs are also JPEG
+                    return PublicFormat::JPEG;
+            }
+            break;
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+            // Not defined in public API
+            return PublicFormat::UNKNOWN;
+
+        default:
+            return PublicFormat::UNKNOWN;
+    }
+}
 // ----------------------------------------------------------------------------
 
 static inline bool isSurfaceValid(const sp<Surface>& sur) {
@@ -324,7 +419,7 @@
     // update the Surface only if the underlying IGraphicBufferProducer
     // has changed.
     if (self != NULL
-            && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
+            && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
         // same IGraphicBufferProducer, return ourselves
         return jlong(self.get());
     }
@@ -354,7 +449,7 @@
         return;
     }
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
+    parcel->writeStrongBinder( self != 0 ? IInterface::asBinder(self->getIGraphicBufferProducer()) : NULL);
 }
 
 static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -406,8 +501,11 @@
 
 static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-    proxy->syncAndDrawFrame(frameTimeNs, 0, 1.0f);
+    nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
+    UiFrameInfoBuilder(proxy->frameInfo())
+            .setVsync(vsync, vsync)
+            .addFlag(FrameInfoFlags::kSurfaceCanvas);
+    proxy->syncAndDrawFrame();
 }
 
 static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
@@ -454,26 +552,26 @@
 
 int register_android_view_Surface(JNIEnv* env)
 {
-    int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
+    int err = RegisterMethodsOrDie(env, "android/view/Surface",
             gSurfaceMethods, NELEM(gSurfaceMethods));
 
-    jclass clazz = env->FindClass("android/view/Surface");
-    gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
-    gSurfaceClassInfo.mNativeObject =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "J");
-    gSurfaceClassInfo.mLock =
-            env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
-    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
+    jclass clazz = FindClassOrDie(env, "android/view/Surface");
+    gSurfaceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gSurfaceClassInfo.mNativeObject = GetFieldIDOrDie(env,
+            gSurfaceClassInfo.clazz, "mNativeObject", "J");
+    gSurfaceClassInfo.mLock = GetFieldIDOrDie(env,
+            gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
+    gSurfaceClassInfo.ctor = GetMethodIDOrDie(env, gSurfaceClassInfo.clazz, "<init>", "(J)V");
 
-    clazz = env->FindClass("android/graphics/Canvas");
-    gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
-    gCanvasClassInfo.setNativeBitmap = env->GetMethodID(clazz, "setNativeBitmap", "(J)V");
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
 
-    clazz = env->FindClass("android/graphics/Rect");
-    gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
-    gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
-    gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
-    gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
+    clazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
+    gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
+    gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
     return err;
 }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 06c22ae..a8355c2 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -26,7 +26,7 @@
 #include "android/graphics/GraphicsJNI.h"
 #include "android/graphics/Region.h"
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_view_SurfaceSession.h>
 
@@ -134,7 +134,7 @@
     status_t res;
     if (allLayers) {
         minLayer = 0;
-        maxLayer = -1UL;
+        maxLayer = -1;
     }
 
     res = screenshot->update(displayToken, sourceCrop, width, height,
@@ -150,7 +150,7 @@
     switch (screenshot->getFormat()) {
         case PIXEL_FORMAT_RGBX_8888: {
             screenshotInfo.fColorType = kRGBA_8888_SkColorType;
-            screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
             break;
         }
         case PIXEL_FORMAT_RGBA_8888: {
@@ -160,7 +160,7 @@
         }
         case PIXEL_FORMAT_RGB_565: {
             screenshotInfo.fColorType = kRGB_565_SkColorType;
-            screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
             break;
         }
         default: {
@@ -647,41 +647,44 @@
 
 int register_android_view_SurfaceControl(JNIEnv* env)
 {
-    int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
+    int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
 
-    jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
-    gPhysicalDisplayInfoClassInfo.clazz = static_cast<jclass>(env->NewGlobalRef(clazz));
-    gPhysicalDisplayInfoClassInfo.ctor = env->GetMethodID(gPhysicalDisplayInfoClassInfo.clazz,
-            "<init>", "()V");
-    gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
-    gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
-    gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
-    gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
-    gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
-    gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
-    gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
-    gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = env->GetFieldID(clazz,
-            "appVsyncOffsetNanos", "J");
-    gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = env->GetFieldID(clazz,
-            "presentationDeadlineNanos", "J");
+    jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
+    gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
+            gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
+    gPhysicalDisplayInfoClassInfo.width =       GetFieldIDOrDie(env, clazz, "width", "I");
+    gPhysicalDisplayInfoClassInfo.height =      GetFieldIDOrDie(env, clazz, "height", "I");
+    gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
+    gPhysicalDisplayInfoClassInfo.density =     GetFieldIDOrDie(env, clazz, "density", "F");
+    gPhysicalDisplayInfoClassInfo.xDpi =        GetFieldIDOrDie(env, clazz, "xDpi", "F");
+    gPhysicalDisplayInfoClassInfo.yDpi =        GetFieldIDOrDie(env, clazz, "yDpi", "F");
+    gPhysicalDisplayInfoClassInfo.secure =      GetFieldIDOrDie(env, clazz, "secure", "Z");
+    gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
+            clazz, "appVsyncOffsetNanos", "J");
+    gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
+            clazz, "presentationDeadlineNanos", "J");
 
-    jclass rectClazz = env->FindClass("android/graphics/Rect");
-    gRectClassInfo.bottom = env->GetFieldID(rectClazz, "bottom", "I");
-    gRectClassInfo.left = env->GetFieldID(rectClazz, "left", "I");
-    gRectClassInfo.right = env->GetFieldID(rectClazz, "right", "I");
-    gRectClassInfo.top = env->GetFieldID(rectClazz, "top", "I");
+    jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
+    gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
+    gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
+    gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
 
-    jclass frameStatsClazz = env->FindClass("android/view/FrameStats");
-    jfieldID undefined_time_nano_field =  env->GetStaticFieldID(frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
+    jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
+    jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
+            frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
     nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
 
-    jclass contFrameStatsClazz = env->FindClass("android/view/WindowContentFrameStats");
-    gWindowContentFrameStatsClassInfo.init =  env->GetMethodID(contFrameStatsClazz, "init", "(J[J[J[J)V");
+    jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
+    gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
+            contFrameStatsClazz, "init", "(J[J[J[J)V");
     gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
 
-    jclass animFrameStatsClazz = env->FindClass("android/view/WindowAnimationFrameStats");
-    gWindowAnimationFrameStatsClassInfo.init =  env->GetMethodID(animFrameStatsClazz, "init", "(J[J)V");
+    jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
+    gWindowAnimationFrameStatsClassInfo.init =  GetMethodIDOrDie(env,
+            animFrameStatsClazz, "init", "(J[J)V");
     gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
 
     return err;
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 5c04a78..c2bd0b3c4 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -31,6 +31,8 @@
 
 #include "android/graphics/GraphicsJNI.h"
 
+#include "core_jni_helpers.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -86,12 +88,15 @@
         case WINDOW_FORMAT_RGBX_8888:
             info.fColorType = kN32_SkColorType;
             info.fAlphaType = kOpaque_SkAlphaType;
+            break;
         case WINDOW_FORMAT_RGB_565:
             info.fColorType = kRGB_565_SkColorType;
             info.fAlphaType = kOpaque_SkAlphaType;
+            break;
         default:
             info.fColorType = kUnknown_SkColorType;
-            info.fAlphaType = kIgnore_SkAlphaType;
+            // switch to kUnknown_SkAlphaType when its in skia
+            info.fAlphaType = kOpaque_SkAlphaType;
             break;
     }
     return info;
@@ -212,35 +217,22 @@
             (void*) android_view_TextureView_unlockCanvasAndPost },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(!var, "Unable to find class " className);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
-        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
-        LOG_FATAL_IF(!var, "Unable to find method " methodName);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(!var, "Unable to find field" fieldName);
-
 int register_android_view_TextureView(JNIEnv* env) {
-    jclass clazz;
-    FIND_CLASS(clazz, "android/graphics/Rect");
-    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
-    GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
-    GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
-    GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
-    GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+    jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
+    gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
+    gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
+    gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
+    gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
+    gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
 
-    FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-    GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V");
+    clazz = FindClassOrDie(env, "android/graphics/Canvas");
+    gCanvasClassInfo.mSurfaceFormat = GetFieldIDOrDie(env, clazz, "mSurfaceFormat", "I");
+    gCanvasClassInfo.setNativeBitmap = GetMethodIDOrDie(env, clazz, "setNativeBitmap", "(J)V");
 
-    FIND_CLASS(clazz, "android/view/TextureView");
-    GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J");
+    clazz = FindClassOrDie(env, "android/view/TextureView");
+    gTextureViewClassInfo.nativeWindow = GetFieldIDOrDie(env, clazz, "mNativeWindow", "J");
 
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index b9d849c..3d9a9ed 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -44,8 +44,6 @@
 
 namespace android {
 
-#ifdef USE_OPENGL_RENDERER
-
 using namespace android::uirenderer;
 using namespace android::uirenderer::renderthread;
 
@@ -241,18 +239,20 @@
     delete proxy;
 }
 
-static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong frameIntervalNanos) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->setFrameInterval(frameIntervalNanos);
-}
-
 static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     return proxy->loadSystemProperties();
 }
 
+static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jstring jname) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    const char* name = env->GetStringUTFChars(jname, NULL);
+    proxy->setName(name);
+    env->ReleaseStringUTFChars(jname, name);
+}
+
 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -283,7 +283,7 @@
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
         jint width, jint height,
         jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius,
-        jint ambientShadowAlpha, jint spotShadowAlpha) {
+        jint ambientShadowAlpha, jint spotShadowAlpha, jfloat density) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
             ambientShadowAlpha, spotShadowAlpha);
@@ -296,9 +296,13 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
+        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
+            "Mismatched size expectations, given %d expected %d",
+            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
+    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
+    return proxy->syncAndDrawFrame();
 }
 
 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -393,14 +397,12 @@
 }
 
 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jobject javaFileDescriptor) {
+        jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    proxy->dumpProfileInfo(fd);
+    proxy->dumpProfileInfo(fd, dumpFlags);
 }
 
-#endif
-
 // ----------------------------------------------------------------------------
 // Shaders
 // ----------------------------------------------------------------------------
@@ -420,19 +422,18 @@
 const char* const kClassPathName = "android/view/ThreadedRenderer";
 
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
     { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
-    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
+    { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
-    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
@@ -447,14 +448,13 @@
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
     { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
-    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
-#endif
+    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
 };
 
 int register_android_view_ThreadedRenderer(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 1e36932..ddd5fc8 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -26,6 +26,7 @@
 
 #include <ScopedUtfChars.h>
 
+#include "core_jni_helpers.h"
 
 namespace android {
 
@@ -242,31 +243,18 @@
             (void*)android_view_VelocityTracker_nativeGetEstimator },
 };
 
-#define FIND_CLASS(var, className) \
-        var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
 int register_android_view_VelocityTracker(JNIEnv* env) {
-    int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker",
-            gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods));
-    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    int res = RegisterMethodsOrDie(env, "android/view/VelocityTracker", gVelocityTrackerMethods,
+                                   NELEM(gVelocityTrackerMethods));
 
-    jclass clazz;
-    FIND_CLASS(clazz, "android/view/VelocityTracker$Estimator");
+    jclass clazz = FindClassOrDie(env, "android/view/VelocityTracker$Estimator");
 
-    GET_FIELD_ID(gEstimatorClassInfo.xCoeff, clazz,
-            "xCoeff", "[F");
-    GET_FIELD_ID(gEstimatorClassInfo.yCoeff, clazz,
-            "yCoeff", "[F");
-    GET_FIELD_ID(gEstimatorClassInfo.degree, clazz,
-            "degree", "I");
-    GET_FIELD_ID(gEstimatorClassInfo.confidence, clazz,
-            "confidence", "F");
-    return 0;
+    gEstimatorClassInfo.xCoeff = GetFieldIDOrDie(env, clazz, "xCoeff", "[F");
+    gEstimatorClassInfo.yCoeff = GetFieldIDOrDie(env, clazz, "yCoeff", "[F");
+    gEstimatorClassInfo.degree = GetFieldIDOrDie(env, clazz, "degree", "I");
+    gEstimatorClassInfo.confidence = GetFieldIDOrDie(env, clazz, "confidence", "F");
+
+    return res;
 }
 
 } // namespace android
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 226b764..3c1993e 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "NativeLibraryHelper"
 //#define LOG_NDEBUG 0
 
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <ScopedUtfChars.h>
 #include <UniquePtr.h>
@@ -117,7 +117,7 @@
         return true;
     }
 
-    if (st->st_size != fileSize) {
+    if (static_cast<uint64_t>(st->st_size) != static_cast<uint64_t>(fileSize)) {
         return true;
     }
 
@@ -430,7 +430,6 @@
     }
 
     ZipEntryRO entry = NULL;
-    char fileName[PATH_MAX];
     int status = NO_NATIVE_LIBRARIES;
     while ((entry = it->next()) != NULL) {
         // We're currently in the lib/ directory of the APK, so it does have some native
@@ -564,8 +563,8 @@
 
 int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env)
 {
-    return AndroidRuntime::registerNativeMethods(env,
-                "com/android/internal/content/NativeLibraryHelper", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env,
+            "com/android/internal/content/NativeLibraryHelper", gMethods, NELEM(gMethods));
 }
 
 };
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 2e2d0c7..6c0b756 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -17,10 +17,11 @@
 #define LOG_TAG "NetworkStats"
 
 #include <errno.h>
+#include <inttypes.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <android_runtime/AndroidRuntime.h>
+#include <core_jni_helpers.h>
 #include <jni.h>
 
 #include <ScopedUtfChars.h>
@@ -187,7 +188,7 @@
         if (endPos - pos == 3) {
             rawTag = 0;
         } else {
-            if (sscanf(pos, "%llx", &rawTag) != 1) {
+            if (sscanf(pos, "%" PRIx64, &rawTag) != 1) {
                 ALOGE("bad tag: %s", pos);
                 fclose(fp);
                 return -1;
@@ -204,7 +205,7 @@
         while (*pos == ' ') pos++;
 
         // Parse remaining fields.
-        if (sscanf(pos, "%u %u %llu %llu %llu %llu",
+        if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64,
                 &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
                 &s.txBytes, &s.txPackets) == 6) {
             if (limitUid != -1 && limitUid != s.uid) {
@@ -283,16 +284,6 @@
     return 0;
 }
 
-static jclass findClass(JNIEnv* env, const char* name) {
-    ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
-    jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
-    if (result == NULL) {
-        ALOGE("failed to find class '%s'", name);
-        abort();
-    }
-    return result;
-}
-
 static JNINativeMethod gMethods[] = {
         { "nativeReadNetworkStatsDetail",
                 "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
@@ -300,24 +291,25 @@
 };
 
 int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
-    int err = AndroidRuntime::registerNativeMethods(env,
+    int err = RegisterMethodsOrDie(env,
             "com/android/internal/net/NetworkStatsFactory", gMethods,
             NELEM(gMethods));
 
-    gStringClass = findClass(env, "java/lang/String");
+    gStringClass = FindClassOrDie(env, "java/lang/String");
+    gStringClass = MakeGlobalRefOrDie(env, gStringClass);
 
-    jclass clazz = env->FindClass("android/net/NetworkStats");
-    gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
-    gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I");
-    gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
-    gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
-    gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
-    gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I");
-    gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J");
-    gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J");
-    gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J");
-    gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J");
-    gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J");
+    jclass clazz = FindClassOrDie(env, "android/net/NetworkStats");
+    gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I");
+    gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I");
+    gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;");
+    gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I");
+    gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I");
+    gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
+    gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
+    gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
+    gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J");
+    gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J");
+    gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J");
 
     return err;
 }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4f5e08b..2bfeadb 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -20,12 +20,12 @@
 #include <sys/mount.h>
 #include <linux/fs.h>
 
-#include <grp.h>
 #include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/capability.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
@@ -34,7 +34,7 @@
 #include <sys/types.h>
 #include <sys/utsname.h>
 #include <sys/wait.h>
-
+#include <unistd.h>
 
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
@@ -43,9 +43,8 @@
 #include <utils/String8.h>
 #include <selinux/android.h>
 #include <processgroup/processgroup.h>
-#include <inttypes.h>
 
-#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 #include "JNIHelp.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
@@ -105,7 +104,7 @@
     // so that it is restarted by init and system server will be restarted
     // from there.
     if (pid == gSystemServerPid) {
-      ALOGE("Exit zygote because system server (%d) has terminated");
+      ALOGE("Exit zygote because system server (%d) has terminated", pid);
       kill(getpid(), SIGKILL);
     }
   }
@@ -131,7 +130,7 @@
 
   int err = sigaction(SIGCHLD, &sa, NULL);
   if (err < 0) {
-    ALOGW("Error setting SIGCHLD handler: %d", errno);
+    ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
   }
 }
 
@@ -143,7 +142,7 @@
 
   int err = sigaction(SIGCHLD, &sa, NULL);
   if (err < 0) {
-    ALOGW("Error unsetting SIGCHLD handler: %d", errno);
+    ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
   }
 }
 
@@ -190,7 +189,8 @@
 
     int rc = setrlimit(javaRlimit[0], &rlim);
     if (rc == -1) {
-      ALOGE("setrlimit(%d, {%d, %d}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max);
+      ALOGE("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
+            rlim.rlim_max);
       RuntimeAbort(env);
     }
   }
@@ -236,7 +236,7 @@
   capdata[1].permitted = permitted >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    ALOGE("capset(%lld, %lld) failed", permitted, effective);
+    ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective);
     RuntimeAbort(env);
   }
 }
@@ -258,7 +258,7 @@
 
   // Create a second private mount namespace for our process
   if (unshare(CLONE_NEWNS) == -1) {
-      ALOGW("Failed to unshare(): %d", errno);
+      ALOGW("Failed to unshare(): %s", strerror(errno));
       return false;
   }
 
@@ -295,14 +295,15 @@
     if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
       // Mount entire external storage tree for all users
       if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
-        ALOGW("Failed to mount %s to %s :%d", source, target, errno);
+        ALOGW("Failed to mount %s to %s: %s", source, target, strerror(errno));
         return false;
       }
     } else {
       // Only mount user-specific external storage
-      if (TEMP_FAILURE_RETRY(
-              mount(source_user.string(), target_user.string(), NULL, MS_BIND, NULL)) == -1) {
-        ALOGW("Failed to mount %s to %s: %d", source_user.string(), target_user.string(), errno);
+      if (TEMP_FAILURE_RETRY(mount(source_user.string(), target_user.string(), NULL,
+                                   MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to %s: %s", source_user.string(), target_user.string(),
+              strerror(errno));
         return false;
       }
     }
@@ -314,7 +315,7 @@
     // Finally, mount user-specific path into place for legacy users
     if (TEMP_FAILURE_RETRY(
             mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
-      ALOGW("Failed to mount %s to %s: %d", target_user.string(), legacy, errno);
+      ALOGW("Failed to mount %s to %s: %s", target_user.string(), legacy, strerror(errno));
       return false;
     }
   } else {
@@ -365,13 +366,13 @@
   for (i = 0; i < count; i++) {
     devnull = open("/dev/null", O_RDWR);
     if (devnull < 0) {
-      ALOGE("Failed to open /dev/null");
+      ALOGE("Failed to open /dev/null: %s", strerror(errno));
       RuntimeAbort(env);
       continue;
     }
-    ALOGV("Switching descriptor %d to /dev/null: %d", ar[i], errno);
+    ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno));
     if (dup2(devnull, ar[i]) < 0) {
-      ALOGE("Failed dup2() on descriptor %d", ar[i]);
+      ALOGE("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
       RuntimeAbort(env);
     }
     close(devnull);
@@ -401,23 +402,7 @@
   strlcpy(buf, s, sizeof(buf)-1);
   errno = pthread_setname_np(pthread_self(), buf);
   if (errno != 0) {
-    ALOGW("Unable to set the name of current thread to '%s'", buf);
-  }
-}
-
-  // Temporary timing check.
-uint64_t MsTime() {
-  timespec now;
-  clock_gettime(CLOCK_MONOTONIC, &now);
-  return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000);
-}
-
-
-void ckTime(uint64_t start, const char* where) {
-  uint64_t now = MsTime();
-  if ((now-start) > 1000) {
-    // If we are taking more than a second, log about it.
-    ALOGW("Slow operation: %"PRIu64" ms in %s", (uint64_t)(now-start), where);
+    ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
   }
 }
 
@@ -429,9 +414,7 @@
                                      jstring java_se_info, jstring java_se_name,
                                      bool is_system_server, jintArray fdsToClose,
                                      jstring instructionSet, jstring dataDir) {
-  uint64_t start = MsTime();
   SetSigChldHandler();
-  ckTime(start, "ForkAndSpecializeCommon:SetSigChldHandler");
 
   pid_t pid = fork();
 
@@ -439,12 +422,9 @@
     // The child process.
     gMallocLeakZygoteChild = 1;
 
-
     // Clean up any descriptors which must be closed immediately
     DetachDescriptors(env, fdsToClose);
 
-    ckTime(start, "ForkAndSpecializeCommon:Fork and detach");
-
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
       EnableKeepCapabilities(env);
@@ -504,13 +484,13 @@
 
     int rc = setresgid(gid, gid, gid);
     if (rc == -1) {
-      ALOGE("setresgid(%d) failed", gid);
+      ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
       RuntimeAbort(env);
     }
 
     rc = setresuid(uid, uid, uid);
     if (rc == -1) {
-      ALOGE("setresuid(%d) failed", uid);
+      ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
       RuntimeAbort(env);
     }
 
@@ -519,7 +499,7 @@
         int old_personality = personality(0xffffffff);
         int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
         if (new_personality == -1) {
-            ALOGW("personality(%d) failed", new_personality);
+            ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
         }
     }
 
@@ -568,11 +548,8 @@
 
     UnsetSigChldHandler();
 
-    ckTime(start, "ForkAndSpecializeCommon:child process setup");
-
     env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                               is_system_server ? NULL : instructionSet);
-    ckTime(start, "ForkAndSpecializeCommon:PostForkChildHooks returns");
     if (env->ExceptionCheck()) {
       ALOGE("Error calling post fork hooks.");
       RuntimeAbort(env);
@@ -636,15 +613,11 @@
 };
 
 int register_com_android_internal_os_Zygote(JNIEnv* env) {
-  gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
-  if (gZygoteClass == NULL) {
-    RuntimeAbort(env);
-  }
-  gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks",
+  gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName));
+  gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
                                                    "(ILjava/lang/String;)V");
 
-  return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
-      gMethods, NELEM(gMethods));
+  return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
 }
 }  // namespace android
 
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
deleted file mode 100644
index 2233ee3..0000000
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "Zygote"
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utils/misc.h>
-#include <errno.h>
-#include <sys/select.h>
-
-#include "jni.h"
-#include <JNIHelp.h>
-#include "android_runtime/AndroidRuntime.h"
-
-#include <sys/capability.h>
-#include <sys/prctl.h>
-
-namespace android {
-
-/*
- * In class com.android.internal.os.ZygoteInit:
- * private static native boolean setreuid(int ruid, int euid)
- */
-static jint com_android_internal_os_ZygoteInit_setreuid(
-    JNIEnv* env, jobject clazz, jint ruid, jint euid)
-{
-    if (setreuid(ruid, euid) < 0) {
-        return errno;
-    }
-    return 0;
-}
-
-/*
- * In class com.android.internal.os.ZygoteInit:
- * private static native int setregid(int rgid, int egid)
- */
-static jint com_android_internal_os_ZygoteInit_setregid(
-    JNIEnv* env, jobject clazz, jint rgid, jint egid)
-{
-    if (setregid(rgid, egid) < 0) {
-        return errno;
-    }
-    return 0;
-}
-
-/*
- * In class com.android.internal.os.ZygoteInit:
- * private static native int setpgid(int rgid, int egid)
- */
-static jint com_android_internal_os_ZygoteInit_setpgid(
-    JNIEnv* env, jobject clazz, jint pid, jint pgid)
-{
-    if (setpgid(pid, pgid) < 0) {
-        return errno;
-    }
-    return 0;
-}
-
-/*
- * In class com.android.internal.os.ZygoteInit:
- * private static native int getpgid(int pid)
- */
-static jint com_android_internal_os_ZygoteInit_getpgid(
-    JNIEnv* env, jobject clazz, jint pid)
-{
-    pid_t ret;
-    ret = getpgid(pid);
-
-    if (ret < 0) {
-        jniThrowIOException(env, errno);
-    }
-
-    return ret;
-}
-
-static void com_android_internal_os_ZygoteInit_reopenStdio(JNIEnv* env,
-        jobject clazz, jobject in, jobject out, jobject errfd)
-{
-    int fd;
-    int err;
-
-    fd = jniGetFDFromFileDescriptor(env, in);
-
-    if  (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-
-    do {
-        err = dup2(fd, STDIN_FILENO);
-    } while (err < 0 && errno == EINTR);
-
-    fd = jniGetFDFromFileDescriptor(env, out);
-
-    if  (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-
-    do {
-        err = dup2(fd, STDOUT_FILENO);
-    } while (err < 0 && errno == EINTR);
-
-    fd = jniGetFDFromFileDescriptor(env, errfd);
-
-    if  (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-
-    do {
-        err = dup2(fd, STDERR_FILENO);
-    } while (err < 0 && errno == EINTR);
-}
-
-static void com_android_internal_os_ZygoteInit_setCloseOnExec (JNIEnv *env,
-    jobject clazz, jobject descriptor, jboolean flag)
-{
-    int fd;
-    int err;
-    int fdFlags;
-
-    fd = jniGetFDFromFileDescriptor(env, descriptor);
-
-    if  (env->ExceptionOccurred() != NULL) {
-        return;
-    }
-
-    fdFlags = fcntl(fd, F_GETFD);
-
-    if (fdFlags < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-
-    if (flag) {
-        fdFlags |= FD_CLOEXEC;
-    } else {
-        fdFlags &= ~FD_CLOEXEC;
-    }
-
-    err = fcntl(fd, F_SETFD, fdFlags);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return;
-    }
-}
-
-static jint com_android_internal_os_ZygoteInit_selectReadable (
-        JNIEnv *env, jobject clazz, jobjectArray fds)
-{
-    if (fds == NULL) {
-        jniThrowNullPointerException(env, "fds == null");
-        return -1;
-    }
-
-    jsize length = env->GetArrayLength(fds);
-    fd_set fdset;
-
-    if (env->ExceptionOccurred() != NULL) {
-        return -1;
-    }
-
-    FD_ZERO(&fdset);
-
-    int nfds = 0;
-    for (jsize i = 0; i < length; i++) {
-        jobject fdObj = env->GetObjectArrayElement(fds, i);
-        if  (env->ExceptionOccurred() != NULL) {
-            return -1;
-        }
-        if (fdObj == NULL) {
-            continue;
-        }
-        int fd = jniGetFDFromFileDescriptor(env, fdObj);
-        if  (env->ExceptionOccurred() != NULL) {
-            return -1;
-        }
-
-        FD_SET(fd, &fdset);
-
-        if (fd >= nfds) {
-            nfds = fd + 1;
-        }
-    }
-
-    int err;
-    do {
-        err = select (nfds, &fdset, NULL, NULL, NULL);
-    } while (err < 0 && errno == EINTR);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return -1;
-    }
-
-    for (jsize i = 0; i < length; i++) {
-        jobject fdObj = env->GetObjectArrayElement(fds, i);
-        if  (env->ExceptionOccurred() != NULL) {
-            return -1;
-        }
-        if (fdObj == NULL) {
-            continue;
-        }
-        int fd = jniGetFDFromFileDescriptor(env, fdObj);
-        if  (env->ExceptionOccurred() != NULL) {
-            return -1;
-        }
-        if (FD_ISSET(fd, &fdset)) {
-            return (jint)i;
-        }
-    }
-    return -1;
-}
-
-static jobject com_android_internal_os_ZygoteInit_createFileDescriptor (
-        JNIEnv *env, jobject clazz, jint fd)
-{
-    return jniCreateFileDescriptor(env, fd);
-}
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "setreuid", "(II)I",
-      (void*) com_android_internal_os_ZygoteInit_setreuid },
-    { "setregid", "(II)I",
-      (void*) com_android_internal_os_ZygoteInit_setregid },
-    { "setpgid", "(II)I",
-      (void *) com_android_internal_os_ZygoteInit_setpgid },
-    { "getpgid", "(I)I",
-      (void *) com_android_internal_os_ZygoteInit_getpgid },
-    { "reopenStdio",
-        "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;"
-        "Ljava/io/FileDescriptor;)V",
-            (void *) com_android_internal_os_ZygoteInit_reopenStdio},
-    { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
-        (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
-    { "selectReadable", "([Ljava/io/FileDescriptor;)I",
-        (void *) com_android_internal_os_ZygoteInit_selectReadable },
-    { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
-        (void *) com_android_internal_os_ZygoteInit_createFileDescriptor }
-};
-int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
-{
-    return AndroidRuntime::registerNativeMethods(env,
-            "com/android/internal/os/ZygoteInit", gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
index ce6f207..7a18c2d 100644
--- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -16,7 +16,7 @@
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 namespace android {
 
@@ -42,7 +42,7 @@
 };
 
 int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 704e1be..2c65d62 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -18,7 +18,7 @@
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
+#include "core_jni_helpers.h"
 
 #include <Interpolator.h>
 
@@ -26,8 +26,6 @@
 
 using namespace uirenderer;
 
-#ifdef USE_OPENGL_RENDERER
-
 static jlong createAccelerateDecelerateInterpolator(JNIEnv* env, jobject clazz) {
     return reinterpret_cast<jlong>(new AccelerateDecelerateInterpolator());
 }
@@ -74,8 +72,6 @@
     return reinterpret_cast<jlong>(new LUTInterpolator(lut, len));
 }
 
-#endif
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -83,7 +79,6 @@
 const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
 
 static JNINativeMethod gMethods[] = {
-#ifdef USE_OPENGL_RENDERER
     { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
     { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator },
     { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator },
@@ -94,11 +89,10 @@
     { "createLinearInterpolator", "()J", (void*) createLinearInterpolator },
     { "createOvershootInterpolator", "(F)J", (void*) createOvershootInterpolator },
     { "createLutInterpolator", "([F)J", (void*) createLutInterpolator },
-#endif
 };
 
 int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv* env) {
-    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
 
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 6c21bab..7080e2a 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -30,6 +30,7 @@
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
+#include <GraphicsJNI.h>
 #include <SkBitmap.h>
 #include <SkPixelRef.h>
 
@@ -46,7 +47,6 @@
 static jfieldID gSurface_EGLSurfaceFieldID;
 static jfieldID gSurface_NativePixelRefFieldID;
 static jfieldID gConfig_EGLConfigFieldID;
-static jfieldID gBitmap_NativeBitmapFieldID;
 
 static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
     if (!o) return EGL_NO_DISPLAY;
@@ -85,9 +85,6 @@
     jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
     gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "J");
     gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "J");
-
-    jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
-    gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "J");
 }
 
 static const jint gNull_attrib_base[] = {EGL_NONE};
@@ -280,9 +277,7 @@
     EGLConfig  cnf = getConfig(_env, config);
     jint* base = 0;
 
-    SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(native_pixmap,
-                    gBitmap_NativeBitmapFieldID);
+    SkBitmap const * nativeBitmap = GraphicsJNI::getSkBitmap(_env, native_pixmap);
     SkPixelRef* ref = nativeBitmap ? nativeBitmap->pixelRef() : 0;
     if (ref == NULL) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index 7975987..c5f330e 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -17,6 +17,10 @@
 
 // This source file is automatically generated
 
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
new file mode 100644
index 0000000..3f169c3
--- /dev/null
+++ b/core/jni/core_jni_helpers.h
@@ -0,0 +1,77 @@
+/*
+ * 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 CORE_JNI_HELPERS
+#define CORE_JNI_HELPERS
+
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+// Defines some helpful functions.
+
+static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
+    jclass clazz = env->FindClass(class_name);
+    LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
+    return clazz;
+}
+
+static inline jfieldID GetFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
+                                       const char* field_signature) {
+    jfieldID res = env->GetFieldID(clazz, field_name, field_signature);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+    return res;
+}
+
+static inline jmethodID GetMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
+                                         const char* method_signature) {
+    jmethodID res = env->GetMethodID(clazz, method_name, method_signature);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find method %s", method_name);
+    return res;
+}
+
+static inline jfieldID GetStaticFieldIDOrDie(JNIEnv* env, jclass clazz, const char* field_name,
+                                             const char* field_signature) {
+    jfieldID res = env->GetStaticFieldID(clazz, field_name, field_signature);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static field %s", field_name);
+    return res;
+}
+
+static inline jmethodID GetStaticMethodIDOrDie(JNIEnv* env, jclass clazz, const char* method_name,
+                                               const char* method_signature) {
+    jmethodID res = env->GetStaticMethodID(clazz, method_name, method_signature);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to find static method %s", method_name);
+    return res;
+}
+
+template <typename T>
+static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
+    jobject res = env->NewGlobalRef(in);
+    LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference.");
+    return static_cast<T>(res);
+}
+
+static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
+                                       const JNINativeMethod* gMethods, int numMethods) {
+    int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods);
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+    return res;
+}
+
+}  // namespace android
+
+#endif  // CORE_JNI_HELPERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ccdb5db..ed4776b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -182,11 +182,7 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
     <protected-broadcast android:name="android.intent.action.HEADSET_PLUG" />
-    <protected-broadcast android:name="android.media.action.ANALOG_AUDIO_DOCK_PLUG" />
-    <protected-broadcast android:name="android.media.action.DIGITAL_AUDIO_DOCK_PLUG" />
     <protected-broadcast android:name="android.media.action.HDMI_AUDIO_PLUG" />
-    <protected-broadcast android:name="android.media.action.USB_AUDIO_ACCESSORY_PLUG" />
-    <protected-broadcast android:name="android.media.action.USB_AUDIO_DEVICE_PLUG" />
 
     <protected-broadcast android:name="android.media.AUDIO_BECOMING_NOISY" />
     <protected-broadcast android:name="android.media.RINGER_MODE_CHANGED" />
@@ -236,6 +232,7 @@
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -303,6 +300,8 @@
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
 
+    <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
@@ -833,6 +832,21 @@
         android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
+    <!-- @SystemApi @hide Allow system apps to receive broadcast
+         when a wifi network credential is changed.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
+        android:permissionGroup="android.permission-group.NETWORK"
+        android:protectionLevel="signature|system" />
+
+    <!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
+	 by another application. Once reconfigured the original creator canot make any further
+	 modifications.
+	 <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
+	android:permissionGroup="android.permission-group.NETWORK"
+	android:protectionLevel="signature|system" />
+
     <!-- @hide -->
     <permission android:name="android.permission.ACCESS_WIMAX_STATE"
         android:permissionGroup="android.permission-group.NETWORK"
@@ -2285,6 +2299,14 @@
         android:description="@string/permdesc_modifyParentalControls"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by a {@link android.media.routing.MediaRouteService}
+         to ensure that only the system can interact with it.
+         @hide -->
+    <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
+        android:label="@string/permlab_bindRouteProvider"
+        android:description="@string/permdesc_bindRouteProvider"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
@@ -2813,6 +2835,18 @@
         android:label="@string/permlab_access_keyguard_secure_storage"
         android:description="@string/permdesc_access_keyguard_secure_storage" />
 
+    <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
+    <permission android:name="android.permission.MANAGE_FINGERPRINT"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_manageFingerprint"
+        android:description="@string/permdesc_manageFingerprint" />
+
+    <!-- Allows an app to use fingerprint hardware. -->
+    <permission android:name="android.permission.USE_FINGERPRINT"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_useFingerprint"
+        android:description="@string/permdesc_useFingerprint" />
+
     <!-- Allows an application to control keyguard.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.CONTROL_KEYGUARD"
@@ -2858,6 +2892,14 @@
         android:description="@string/permdesc_bindNotificationListenerService"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link
+         android.service.chooser.ChooserTargetService}, to ensure that
+         only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
+        android:label="@string/permlab_bindChooserTargetService"
+        android:description="@string/permdesc_bindChooserTargetService"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
@@ -2867,6 +2909,13 @@
         android:description="@string/permdesc_bindConditionProviderService"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.media.routing.MediaRouteService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_MEDIA_ROUTE_SERVICE"
+        android:label="@string/permlab_bindMediaRouteService"
+        android:description="@string/permdesc_bindMediaRouteService"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by an {@link android.service.dreams.DreamService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_DREAM_SERVICE"
@@ -2984,6 +3033,19 @@
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
+        <activity android:name="com.android.internal.app.DumpHeapActivity"
+                android:theme="@style/Theme.Translucent.NoTitleBar"
+                android:label="@string/dump_heap_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:noHistory="true"
+                android:excludeFromRecents="true"
+                android:process=":ui">
+        </activity>
+        <provider android:name="com.android.server.am.DumpHeapProvider"
+                android:authorities="com.android.server.heapdump"
+                android:grantUriPermissions="true"
+                android:multiprocess="false"
+                android:singleUser="true" />
 
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
@@ -3147,6 +3209,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.backup.KeyValueBackupJob"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service
             android:name="com.android.server.pm.BackgroundDexOptService"
             android:exported="true"
diff --git a/core/res/res/anim/disabled_anim_material.xml b/core/res/res/anim/disabled_anim_material.xml
deleted file mode 100644
index 6a7731e..0000000
--- a/core/res/res/anim/disabled_anim_material.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false">
-        <set>
-            <objectAnimator android:propertyName="alpha"
-                android:duration="@integer/disabled_alpha_animation_duration"
-                android:valueTo="?attr/disabledAlpha"
-                android:valueType="floatType"/>
-        </set>
-    </item>
-    <item>
-        <set>
-            <objectAnimator android:propertyName="alpha"
-                android:duration="@integer/disabled_alpha_animation_duration"
-                android:valueTo="1"
-                android:valueType="floatType"/>
-        </set>
-    </item>
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_material.xml
new file mode 100644
index 0000000..b45f824
--- /dev/null
+++ b/core/res/res/color/btn_colored_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/colorButtonNormal" />
+    <item android:color="?attr/colorAccent" />
+</selector>
diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml
new file mode 100644
index 0000000..950d04a
--- /dev/null
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/textColorSecondary" />
+    <item android:color="?attr/colorAccent"/>
+</selector>
diff --git a/core/res/res/color/btn_default_material_dark.xml b/core/res/res/color/btn_default_material_dark.xml
index 9be1417..e77af37 100644
--- a/core/res/res/color/btn_default_material_dark.xml
+++ b/core/res/res/color/btn_default_material_dark.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:alpha="@dimen/disabled_alpha_material_dark"
+          android:alpha="?attr/disabledAlpha"
           android:color="@color/button_material_dark"/>
     <item android:color="@color/button_material_dark"/>
 </selector>
diff --git a/core/res/res/color/btn_default_material_light.xml b/core/res/res/color/btn_default_material_light.xml
index af5afe6..9fe5766 100644
--- a/core/res/res/color/btn_default_material_light.xml
+++ b/core/res/res/color/btn_default_material_light.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
-          android:alpha="@dimen/disabled_alpha_material_light"
+          android:alpha="?attr/disabledAlpha"
           android:color="@color/button_material_light"/>
     <item android:color="@color/button_material_light"/>
 </selector>
diff --git a/core/res/res/color/control_checkable_material.xml b/core/res/res/color/control_checkable_material.xml
new file mode 100644
index 0000000..c8ef909
--- /dev/null
+++ b/core/res/res/color/control_checkable_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/colorControlNormal" />
+    <item android:state_checked="true"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorControlNormal" />
+</selector>
diff --git a/core/res/res/color/control_default_material.xml b/core/res/res/color/control_default_material.xml
new file mode 100644
index 0000000..901c680
--- /dev/null
+++ b/core/res/res/color/control_default_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?attr/disabledAlpha"
+          android:color="?attr/colorControlNormal" />
+    <item android:color="?attr/colorControlActivated" />
+</selector>
diff --git a/core/res/res/color/control_highlight_material.xml b/core/res/res/color/control_highlight_material.xml
new file mode 100644
index 0000000..2492a4d
--- /dev/null
+++ b/core/res/res/color/control_highlight_material.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="true"
+          android:state_enabled="true"
+          android:alpha="@dimen/highlight_alpha_material_colored"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorControlHighlight" />
+</selector>
diff --git a/core/res/res/color/date_picker_calendar_holo_dark.xml b/core/res/res/color/date_picker_calendar_holo_dark.xml
deleted file mode 100644
index d29486f..0000000
--- a/core/res/res/color/date_picker_calendar_holo_dark.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_enabled="true" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_dark"/>
-    <item android:state_enabled="true" android:state_selected="true"
-          android:color="@color/holo_blue_light"/>
-    <item android:state_enabled="false"
-          android:color="@color/datepicker_default_disabled_text_color_holo_dark"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_calendar_holo_light.xml b/core/res/res/color/date_picker_calendar_holo_light.xml
deleted file mode 100644
index 776f39b..0000000
--- a/core/res/res/color/date_picker_calendar_holo_light.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_enabled="true" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_light"/>
-    <item android:state_enabled="true" android:state_selected="true"
-          android:color="@color/holo_blue_light"/>
-    <item android:state_enabled="false"
-          android:color="@color/datepicker_default_disabled_text_color_holo_light"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_header_text_material.xml b/core/res/res/color/date_picker_header_text_material.xml
new file mode 100644
index 0000000..cda894b
--- /dev/null
+++ b/core/res/res/color/date_picker_header_text_material.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_selected="true"
+        android:color="?attr/textColorPrimaryInverse" />
+    <item
+        android:color="?attr/textColorSecondaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_holo_dark.xml b/core/res/res/color/date_picker_selector_holo_dark.xml
deleted file mode 100644
index 9e5a5bd..0000000
--- a/core/res/res/color/date_picker_selector_holo_dark.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="true"
-          android:color="@color/datepicker_default_selected_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_dark"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_holo_light.xml b/core/res/res/color/date_picker_selector_holo_light.xml
deleted file mode 100644
index bf8667c..0000000
--- a/core/res/res/color/date_picker_selector_holo_light.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="true"
-          android:color="@color/datepicker_default_selected_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_light"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_holo_dark.xml b/core/res/res/color/date_picker_year_selector_holo_dark.xml
deleted file mode 100644
index ce519b2..0000000
--- a/core/res/res/color/date_picker_year_selector_holo_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_dark"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_holo_light.xml b/core/res/res/color/date_picker_year_selector_holo_light.xml
deleted file mode 100644
index c228711..0000000
--- a/core/res/res/color/date_picker_year_selector_holo_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_light"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/highlighted_text_material.xml b/core/res/res/color/highlighted_text_material.xml
new file mode 100644
index 0000000..fee277a
--- /dev/null
+++ b/core/res/res/color/highlighted_text_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="0.4"
+          android:color="?attr/colorAccent" />
+</selector>
diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml
new file mode 100644
index 0000000..77883d9
--- /dev/null
+++ b/core/res/res/color/hint_foreground_material_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/hint_alpha_material_dark"
+          android:color="@color/foreground_material_dark" />
+</selector>
diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml
new file mode 100644
index 0000000..99168fd
--- /dev/null
+++ b/core/res/res/color/hint_foreground_material_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/hint_alpha_material_light"
+          android:color="@color/foreground_material_light" />
+</selector>
diff --git a/core/res/res/color/list_highlight_material.xml b/core/res/res/color/list_highlight_material.xml
new file mode 100644
index 0000000..116ab29
--- /dev/null
+++ b/core/res/res/color/list_highlight_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true"
+          android:alpha="@dimen/highlight_alpha_material_colored"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorControlHighlight" />
+</selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_dark.xml b/core/res/res/color/primary_text_disable_only_material_dark.xml
index a6296c96..8bfefa7 100644
--- a/core/res/res/color/primary_text_disable_only_material_dark.xml
+++ b/core/res/res/color/primary_text_disable_only_material_dark.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="@dimen/disabled_alpha_material_dark"
-          android:color="@color/bright_foreground_material_dark"/>
-    <item android:color="@color/bright_foreground_material_dark"/>
+          android:color="@color/foreground_material_dark"/>
+    <item android:color="@color/foreground_material_dark"/>
 </selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_light.xml b/core/res/res/color/primary_text_disable_only_material_light.xml
index b781844..0cc09fc 100644
--- a/core/res/res/color/primary_text_disable_only_material_light.xml
+++ b/core/res/res/color/primary_text_disable_only_material_light.xml
@@ -17,6 +17,6 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="@dimen/disabled_alpha_material_light"
-          android:color="@color/bright_foreground_material_light"/>
-    <item android:color="@color/bright_foreground_material_light"/>
+          android:color="@color/foreground_material_light"/>
+    <item android:color="@color/foreground_material_light"/>
 </selector>
diff --git a/core/res/res/color/ripple_material_dark.xml b/core/res/res/color/ripple_material_dark.xml
new file mode 100644
index 0000000..940e5da
--- /dev/null
+++ b/core/res/res/color/ripple_material_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/highlight_alpha_material_dark"
+          android:color="@color/foreground_material_dark" />
+</selector>
diff --git a/core/res/res/color/ripple_material_light.xml b/core/res/res/color/ripple_material_light.xml
new file mode 100644
index 0000000..406a133
--- /dev/null
+++ b/core/res/res/color/ripple_material_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/highlight_alpha_material_light"
+          android:color="@color/foreground_material_light" />
+</selector>
diff --git a/core/res/res/color/switch_track_material.xml b/core/res/res/color/switch_track_material.xml
new file mode 100644
index 0000000..0c8caa9
--- /dev/null
+++ b/core/res/res/color/switch_track_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:color="?attr/colorForeground"
+          android:alpha="?attr/disabledAlpha" />
+    <item android:state_checked="true"
+          android:color="?attr/colorControlActivated" />
+    <item android:color="?attr/colorForeground" />
+</selector>
diff --git a/core/res/res/color/tab_highlight_material.xml b/core/res/res/color/tab_highlight_material.xml
new file mode 100644
index 0000000..7b2922bd
--- /dev/null
+++ b/core/res/res/color/tab_highlight_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/highlight_alpha_material_colored"
+          android:color="?attr/colorControlActivated" />
+</selector>
diff --git a/core/res/res/color/tab_indicator_material.xml b/core/res/res/color/tab_indicator_material.xml
new file mode 100644
index 0000000..9602e92
--- /dev/null
+++ b/core/res/res/color/tab_indicator_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:color="@color/white" />
+    <item android:color="@color/transparent" />
+</selector>
diff --git a/core/res/res/color/tab_indicator_text_material.xml b/core/res/res/color/tab_indicator_text_material.xml
new file mode 100644
index 0000000..019fa67
--- /dev/null
+++ b/core/res/res/color/tab_indicator_text_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_selected="true"
+          android:color="?attr/textColorPrimary" />
+    <item android:color="?attr/textColorSecondary" />
+</selector>
diff --git a/core/res/res/color/time_picker_header_text_material.xml b/core/res/res/color/time_picker_header_text_material.xml
new file mode 100644
index 0000000..cda894b
--- /dev/null
+++ b/core/res/res/color/time_picker_header_text_material.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_selected="true"
+        android:color="?attr/textColorPrimaryInverse" />
+    <item
+        android:color="?attr/textColorSecondaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color/white_disabled_material.xml b/core/res/res/color/white_disabled_material.xml
new file mode 100644
index 0000000..c61f900
--- /dev/null
+++ b/core/res/res/color/white_disabled_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/white"
+          android:alpha="?attr/disabledAlpha" />
+</selector>
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 992a8ff..0000000
--- a/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 68e17ad..0000000
--- a/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index fbb2e0c..0000000
--- a/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index de7ac29..0000000
--- a/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-hdpi/stat_notify_call_mute.png
deleted file mode 100644
index f8f9503..0000000
--- a/core/res/res/drawable-hdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
deleted file mode 100644
index d5bb37f..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 9415bc0..0000000
--- a/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
index 9cdc25b..1550b44 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
index 276d480..b309dfd 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_notify_call_mute.png b/core/res/res/drawable-ldpi/stat_notify_call_mute.png
deleted file mode 100644
index 353ecf2..0000000
--- a/core/res/res/drawable-ldpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png b/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
deleted file mode 100644
index 22ecd30..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index 5903856..0000000
--- a/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index e5bface..0000000
--- a/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index 92d4b05..0000000
--- a/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index bbf5928..0000000
--- a/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-mdpi/stat_notify_call_mute.png
deleted file mode 100644
index 79683c7..0000000
--- a/core/res/res/drawable-mdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
deleted file mode 100644
index df0597f..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 4918d33..0000000
--- a/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
index 95c0168..b36a413 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
index 569332a..afd0bd2 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
deleted file mode 100644
index 996aadc..0000000
--- a/core/res/res/drawable-sw600dp-hdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
deleted file mode 100644
index e440805..0000000
--- a/core/res/res/drawable-sw600dp-hdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
deleted file mode 100644
index 5ebf23a..0000000
--- a/core/res/res/drawable-sw600dp-mdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
deleted file mode 100644
index 0228134..0000000
--- a/core/res/res/drawable-sw600dp-mdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
deleted file mode 100644
index 142080a..0000000
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
deleted file mode 100644
index f9563b2..0000000
--- a/core/res/res/drawable-sw600dp-xhdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
deleted file mode 100644
index dd1b5be..0000000
--- a/core/res/res/drawable-sw600dp-xxhdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
deleted file mode 100644
index df9bff1..0000000
--- a/core/res/res/drawable-sw600dp-xxhdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index d0d0b1e..0000000
--- a/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index dff391f..0000000
--- a/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index e3c4eeb..0000000
--- a/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index d4bd169..0000000
--- a/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_notify_call_mute.png b/core/res/res/drawable-xhdpi/stat_notify_call_mute.png
deleted file mode 100644
index e143366..0000000
--- a/core/res/res/drawable-xhdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png
deleted file mode 100644
index f7f7871..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index fd47f15..0000000
--- a/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
index a01ac10..58f8c43 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
index d3602d9..42a893d 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
deleted file mode 100644
index e1c55ad..0000000
--- a/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100644
index 0d6a39a..0000000
--- a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index 452f45c..0000000
--- a/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 2e7bc12..0000000
--- a/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png b/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png
deleted file mode 100644
index 8c6176c..0000000
--- a/core/res/res/drawable-xxhdpi/stat_notify_call_mute.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png b/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png
deleted file mode 100644
index a53913f..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_speakerphone.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 3e3174d..0000000
--- a/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
index 75085ce..d0f274a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
index e2eb5be..f1f637a 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
deleted file mode 100755
index c06740b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
deleted file mode 100644
index 1086e9d..0000000
--- a/core/res/res/drawable-xxxhdpi/spinner_mtrl_am_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
deleted file mode 100644
index 1e4a74c..0000000
--- a/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
new file mode 100644
index 0000000..643168f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
new file mode 100644
index 0000000..e8f3aad
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/action_bar_item_background_material.xml b/core/res/res/drawable/action_bar_item_background_material.xml
new file mode 100644
index 0000000..8228e3f
--- /dev/null
+++ b/core/res/res/drawable/action_bar_item_background_material.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="?attr/colorControlHighlight"
+        android:radius="20dp" />
diff --git a/core/res/res/drawable/btn_cab_done_material.xml b/core/res/res/drawable/btn_cab_done_material.xml
deleted file mode 100644
index 36cc196..0000000
--- a/core/res/res/drawable/btn_cab_done_material.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:state_pressed="true">
-        <color android:color="?attr/colorControlHighlight" />
-    </item>
-    <item android:state_focused="true" android:state_enabled="true">
-        <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
-            android:tint="?attr/colorControlHighlight" />
-    </item>
-    <item android:state_enabled="true">
-        <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
-            android:tint="?attr/colorButtonNormal" />
-    </item>
-</selector>
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 1e05e84..24df879 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -16,118 +16,156 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:state_checked="true">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal" />
     </item>
     <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_001"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_002"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_003"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_004"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_005"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_006"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_007"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_008"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_009"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_010"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_011"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_012"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_013"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_014"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
+                        android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
     <transition android:fromId="@+id/on" android:toId="@+id/off">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_000"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_001"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_002"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_003"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_004"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_005"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_006"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_007"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_008"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_009"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_010"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_011"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_012"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_013"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_014"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_check_to_off_mtrl_015"
+                        android:tint="?attr/colorControlNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml
index 121e544..bce579e 100644
--- a/core/res/res/drawable/btn_radio_material_anim.xml
+++ b/core/res/res/drawable/btn_radio_material_anim.xml
@@ -16,128 +16,156 @@
 
 <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:state_checked="true">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_015"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_enabled="false">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_000"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal"
+                android:alpha="?attr/disabledAlpha" />
     </item>
     <item android:state_checked="true" android:id="@+id/on">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_015"
-            android:tint="?attr/colorControlActivated" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                android:tint="?attr/colorControlActivated" />
     </item>
     <item android:id="@+id/off">
-        <bitmap
-            android:src="@drawable/btn_radio_to_on_mtrl_000"
-            android:tint="?attr/colorControlNormal" />
+        <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                android:tint="?attr/colorControlNormal" />
     </item>
     <transition android:fromId="@+id/off" android:toId="@+id/on">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_000"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_on_mtrl_015"
+                        android:tint="?attr/colorControlActivated" />
             </item>
         </animation-list>
     </transition>
     <transition android:fromId="@+id/on" android:toId="@+id/off">
         <animation-list>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_000"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007"
+                        android:tint="?attr/colorControlActivated" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014"
+                        android:tint="?attr/colorControlNormal" />
             </item>
             <item android:duration="15">
-                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlNormal" />
+                <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015"
+                        android:tint="?attr/colorControlNormal" />
             </item>
         </animation-list>
     </transition>
diff --git a/core/res/res/drawable/btn_star_material.xml b/core/res/res/drawable/btn_star_material.xml
index 29862d2..cbea471 100644
--- a/core/res/res/drawable/btn_star_material.xml
+++ b/core/res/res/drawable/btn_star_material.xml
@@ -14,17 +14,6 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true">
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item>
-        <bitmap android:src="@drawable/btn_star_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-</selector>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/btn_star_mtrl_alpha"
+        android:tint="@color/control_checkable_material" />
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index f91d4cc..8b19e4a 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -23,11 +23,11 @@
         <item>
             <ripple android:color="?attr/colorControlHighlight">
                 <item>
-                    <shape xmlns:android="http://schemas.android.com/apk/res/android"
-                           android:shape="rectangle">
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorButtonNormal">
                         <corners android:topLeftRadius="@dimen/control_corner_material"
                                  android:topRightRadius="@dimen/control_corner_material"/>
-                        <solid android:color="?attr/colorButtonNormal" />
+                        <solid android:color="@color/white" />
                         <padding android:left="@dimen/button_padding_horizontal_material"
                                  android:top="@dimen/button_padding_vertical_material"
                                  android:right="@dimen/button_padding_horizontal_material"
@@ -36,17 +36,11 @@
                 </item>
             </ripple>
         </item>
-        <item>
-            <selector xmlns:android="http://schemas.android.com/apk/res/android">
-                <item android:state_checked="false">
-                    <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-                <item android:state_checked="true">
-                    <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-            </selector>
+        <item android:gravity="bottom|fill_horizontal">
+            <shape android:shape="rectangle">
+                <size android:height="2dp" />
+                <solid android:color="@color/control_checkable_material" />
+            </shape>
         </item>
     </layer-list>
 </inset>
diff --git a/core/res/res/drawable/control_background_material.xml b/core/res/res/drawable/control_background_material.xml
new file mode 100644
index 0000000..7b78349
--- /dev/null
+++ b/core/res/res/drawable/control_background_material.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/control_highlight_material"
+        android:radius="20dp" />
diff --git a/core/res/res/drawable/ic_expand_more_48dp.xml b/core/res/res/drawable/ic_expand_more_48dp.xml
new file mode 100644
index 0000000..11323e3
--- /dev/null
+++ b/core/res/res/drawable/ic_expand_more_48dp.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
+    <path
+        android:pathData="M0 0h48v48H0z"
+        android:fillColor="#00000000"/>
+</vector>
diff --git a/core/res/res/drawable/immersive_cling_bg_circ.xml b/core/res/res/drawable/immersive_cling_bg_circ.xml
new file mode 100644
index 0000000..4731bbd
--- /dev/null
+++ b/core/res/res/drawable/immersive_cling_bg_circ.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval" >
+
+    <solid android:color="@color/white" />
+
+    <size
+        android:height="56dp"
+        android:width="56dp" />
+
+</shape>
diff --git a/core/res/res/drawable/immersive_cling_light_bg_circ.xml b/core/res/res/drawable/immersive_cling_light_bg_circ.xml
new file mode 100644
index 0000000..df5d5ad
--- /dev/null
+++ b/core/res/res/drawable/immersive_cling_light_bg_circ.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval" >
+
+    <solid android:color="#80ffffff" />
+
+    <size
+        android:height="76dp"
+        android:width="76dp" />
+
+</shape>
diff --git a/core/res/res/drawable/list_highlight_material.xml b/core/res/res/drawable/list_highlight_material.xml
new file mode 100644
index 0000000..5a930c4
--- /dev/null
+++ b/core/res/res/drawable/list_highlight_material.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/list_highlight_material">
+    <item android:id="@id/mask">
+        <color android:color="@color/white" />
+    </item>
+</ripple>
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index 6b64337..c1795640 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -15,22 +15,32 @@
 -->
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@id/background">
-        <nine-patch android:src="@drawable/progress_mtrl_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+    <item android:id="@id/background"
+          android:gravity="center_vertical|fill_horizontal">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlNormal">
+            <size android:height="@dimen/progress_bar_height_material" />
+            <solid android:color="@color/white_disabled_material" />
+        </shape>
     </item>
-    <item android:id="@id/secondaryProgress">
+    <item android:id="@id/secondaryProgress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
-            <nine-patch android:src="@drawable/progress_mtrl_alpha"
-                android:tint="?attr/colorControlActivated"
-                android:alpha="?attr/disabledAlpha" />
+            <shape android:shape="rectangle"
+                   android:tint="?attr/colorControlActivated">
+                <size android:height="@dimen/progress_bar_height_material" />
+                <solid android:color="@color/white_disabled_material" />
+            </shape>
         </scale>
     </item>
-    <item android:id="@id/progress">
+    <item android:id="@id/progress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
-            <nine-patch android:src="@drawable/progress_mtrl_alpha"
-                android:tint="?attr/colorControlActivated" />
+            <shape android:shape="rectangle"
+                   android:tint="?attr/colorControlActivated">
+                <size android:height="@dimen/progress_bar_height_material" />
+                <solid android:color="@color/white" />
+            </shape>
         </scale>
     </item>
 </layer-list>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_material.xml b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
index 89a1787..86a85c3 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_material.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
@@ -15,32 +15,42 @@
 -->
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@id/background">
-        <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha"
-                    android:tint="?attr/colorControlNormal" />
+    <item android:id="@id/background"
+          android:gravity="center_vertical|fill_horizontal">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlNormal">
+            <size android:height="@dimen/scrubber_track_height_material" />
+            <solid android:color="@color/white_disabled_material" />
+        </shape>
     </item>
-    <item android:id="@id/secondaryProgress">
+    <item android:id="@id/secondaryProgress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
             <selector>
-                <item android:state_enabled="false">
-                    <color android:color="@color/transparent" />
-                </item>
+                <item android:state_enabled="false"
+                      android:drawable="@color/transparent" />
                 <item>
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                                android:tint="?attr/colorControlNormal" />
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorControlActivated">
+                        <size android:height="@dimen/scrubber_track_height_material" />
+                        <solid android:color="@color/white_disabled_material" />
+                    </shape>
                 </item>
             </selector>
         </scale>
     </item>
-    <item android:id="@id/progress">
+    <item android:id="@id/progress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
             <selector>
-                <item android:state_enabled="false">
-                    <color android:color="@color/transparent" />
-                </item>
+                <item android:state_enabled="false"
+                      android:drawable="@color/transparent" />
                 <item>
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                                android:tint="?attr/colorControlActivated" />
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorControlActivated">
+                        <size android:height="@dimen/progress_bar_height_material" />
+                        <solid android:color="@color/white" />
+                    </shape>
                 </item>
             </selector>
         </scale>
diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml
index d99e367..d5b509f 100644
--- a/core/res/res/drawable/spinner_background_material.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -14,19 +14,22 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:autoMirrored="true">
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack">
+    <item android:drawable="@drawable/item_background_borderless_material"
+          android:gravity="end|center_vertical"
+          android:width="24dp"
+          android:height="24dp" />
+    <item android:gravity="end|center_vertical">
+        <vector android:width="24dp"
+                android:height="24dp"
+                android:viewportWidth="24.0"
+                android:viewportHeight="24.0"
+                android:tint="?attr/colorControlNormal">
+            <path android:pathData="M7,10l5,5,5-5z"
+                  android:fillColor="@color/white"/>
+        </vector>
     </item>
-    <item android:state_pressed="false" android:state_focused="false">
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-</selector>
+    <item android:end="48dp"
+          android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index fab3dc9..69c2f30 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,46 +14,8 @@
      limitations under the License.
 -->
 
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:inset="@dimen/control_inset_material">
-    <selector android:autoMirrored="true">
-        <item android:state_enabled="false">
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated"
-                        android:alpha="?attr/disabledAlpha" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlActivated"
-                        android:alpha="?attr/disabledAlpha" />
-                </item>
-            </layer-list>
-        </item>
-        <item android:state_pressed="false" android:state_focused="false">
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlNormal" />
-                </item>
-            </layer-list>
-        </item>
-        <item>
-            <layer-list android:paddingMode="stack">
-                <item>
-                    <nine-patch android:src="@drawable/textfield_activated_mtrl_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-                <item>
-                    <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
-                        android:tint="?attr/colorControlActivated" />
-                </item>
-            </layer-list>
-        </item>
-    </selector>
-</inset>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack">
+    <item android:drawable="@drawable/edit_text_material" />
+    <item android:drawable="@drawable/spinner_background_material" />
+</layer-list>
diff --git a/core/res/res/drawable/stat_notify_call_mute.xml b/core/res/res/drawable/stat_notify_call_mute.xml
new file mode 100644
index 0000000..4baf5cf
--- /dev/null
+++ b/core/res/res/drawable/stat_notify_call_mute.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18.0dp"
+        android:height="18.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="m19.0,11.0l-1.7,0.0c0.0,0.74 -0.16,1.43 -0.43,2.05l1.23,1.23c0.56,-0.98 0.9,-2.09 0.9,-3.28zm-4.02,0.17c0.0,-0.06 0.02,-0.11 0.02,-0.17l0.0,-6.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0s-3.0,1.34 -3.0,3.0l0.0,0.18l5.98,5.99zm-10.71,-8.17l-1.27,1.27l6.01,6.01l0.0,0.72c0.0,1.66 1.33,3.0 2.99,3.0c0.22,0.0 0.44,-0.03 0.65,-0.08l1.66,1.66c-0.71,0.33 -1.5,0.52 -2.31,0.52c-2.76,0.0 -5.3,-2.1 -5.3,-5.1l-1.7,0.0c0.0,3.41 2.72,6.23 6.0,6.72l0.0,3.28l2.0,0.0l0.0,-3.28c0.91,-0.13 1.77,-0.45 2.54,-0.9l4.19,4.18l1.27,-1.27l-16.73,-16.73z"/>
+</vector>
diff --git a/core/res/res/drawable/stat_sys_speakerphone.xml b/core/res/res/drawable/stat_sys_speakerphone.xml
new file mode 100644
index 0000000..4f30657
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_speakerphone.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="18.0dp"
+        android:height="18.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M20.0,15.5c-1.25,0.0 -2.45,-0.2 -3.57,-0.57 -0.35,-0.11 -0.74,-0.03 -1.02,0.24l-2.2,2.2c-2.83,-1.44 -5.15,-3.75 -6.59,-6.59l2.2,-2.21c0.28,-0.26 0.36,-0.65 0.25,-1.0C8.7,6.45 8.5,5.25 8.5,4.0c0.0,-0.55 -0.45,-1.0 -1.0,-1.0L4.0,3.0c-0.55,0.0 -1.0,0.45 -1.0,1.0 0.0,9.39 7.61,17.0 17.0,17.0 0.55,0.0 1.0,-0.45 1.0,-1.0l0.0,-3.5c0.0,-0.55 -0.45,-1.0 -1.0,-1.0zM19.0,12.0l2.0,0.0c0.0,-4.97 -4.03,-9.0 -9.0,-9.0l0.0,2.0c3.87,0.0 7.0,3.13 7.0,7.0zm-4.0,0.0l2.0,0.0c0.0,-2.76 -2.24,-5.0 -5.0,-5.0l0.0,2.0c1.66,0.0 3.0,1.34 3.0,3.0z"/>
+</vector>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 1ec2f88..8b028d3 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,20 +14,15 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorForeground"
-            android:alpha="0.1" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="center_vertical|fill_horizontal"
+          android:start="4dp"
+          android:end="4dp">
+        <shape android:shape="rectangle"
+               android:tint="@color/switch_track_material">
+            <corners android:radius="7dp" />
+            <solid android:color="@color/white_disabled_material" />
+            <size android:height="14dp" />
+        </shape>
     </item>
-    <item android:state_checked="true">
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorControlActivated"
-            android:alpha="0.3" />
-    </item>
-    <item>
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorForeground"
-            android:alpha="0.3" />
-    </item>
-</selector>
+</layer-list>
diff --git a/core/res/res/drawable/tab_indicator_material.xml b/core/res/res/drawable/tab_indicator_material.xml
index 16362c0..958f57f 100644
--- a/core/res/res/drawable/tab_indicator_material.xml
+++ b/core/res/res/drawable/tab_indicator_material.xml
@@ -14,10 +14,22 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true">
-        <nine-patch android:src="@drawable/tab_indicator_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="nest">
+    <item>
+        <ripple android:color="@color/tab_highlight_material">
+            <item android:id="@id/mask">
+                <color android:color="@color/white" />
+            </item>
+        </ripple>
     </item>
-    <item android:drawable="@color/transparent" />
-</selector>
+    <item android:gravity="bottom">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlActivated">
+            <size android:height="2dp" />
+            <solid android:color="@color/tab_indicator_material" />
+        </shape>
+    </item>
+    <item android:bottom="2dp"
+          android:drawable="@color/transparent" />
+</layer-list>
diff --git a/core/res/res/drawable/textfield_search_material.xml b/core/res/res/drawable/textfield_search_material.xml
index 1c0f5eb..fcd0579 100644
--- a/core/res/res/drawable/textfield_search_material.xml
+++ b/core/res/res/drawable/textfield_search_material.xml
@@ -15,28 +15,20 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item android:state_window_focused="false" android:state_enabled="false">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
-    </item>
-    <item android:state_enabled="true" android:state_focused="true">
+    <item android:state_window_focused="true"
+          android:state_enabled="true"
+          android:state_focused="true">
         <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
+                    android:tint="?attr/colorControlActivated" />
     </item>
-    <item android:state_enabled="true" android:state_activated="true">
+    <item android:state_window_focused="true"
+          android:state_enabled="true"
+          android:state_activated="true">
         <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:state_enabled="true">
-        <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
+                    android:tint="?attr/colorControlActivated" />
     </item>
     <item>
         <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
-            android:tint="?attr/colorControlNormal" />
+                    android:tint="?attr/colorControlNormal" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/time_picker_header_material.xml b/core/res/res/drawable/time_picker_header_material.xml
index cdb92b6..ef2068a 100644
--- a/core/res/res/drawable/time_picker_header_material.xml
+++ b/core/res/res/drawable/time_picker_header_material.xml
@@ -15,8 +15,6 @@
 -->
 
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?attr/colorControlHighlight">
-    <item>
-        <color android:color="?attr/colorAccent" />
-    </item>
+        android:color="?attr/colorControlHighlight">
+    <item android:drawable="?attr/colorAccent" />
 </ripple>
diff --git a/core/res/res/layout-land/time_picker_holo.xml b/core/res/res/layout-land/time_picker_holo.xml
deleted file mode 100644
index f6923ee..0000000
--- a/core/res/res/layout-land/time_picker_holo.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-    <FrameLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:minWidth="@dimen/timepicker_left_side_width"
-        android:orientation="vertical">
-        <include
-            layout="@layout/time_header_label"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center" />
-    </FrameLayout>
-    <android.widget.RadialTimePickerView
-        android:id="@+id/radial_picker"
-        android:layout_width="@dimen/timepicker_radial_picker_dimen"
-        android:layout_height="match_parent"
-        android:layout_gravity="center" />
-</LinearLayout>
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
new file mode 100644
index 0000000..1b85e8f
--- /dev/null
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:tools="http://schemas.android.com/tools"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/time_header"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_column="0"
+        android:layout_row="0"
+        android:layout_rowSpan="3"
+        android:layout_gravity="center|fill"
+        tools:background="@color/accent_material_light" />
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="0"
+        android:layout_row="1"
+        android:layout_gravity="center|fill"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding">
+
+        <LinearLayout
+            android:id="@+id/time_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_centerInParent="true"
+            android:paddingTop="@dimen/timepicker_radial_picker_top_margin">
+
+            <!-- The hour should always be to the left of the separator,
+                 regardless of the current locale's layout direction. -->
+            <TextView
+                android:id="@+id/hours"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="none"
+                android:gravity="right"
+                tools:text="23"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+
+            <TextView
+                android:id="@+id/separator"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:importantForAccessibility="no"
+                tools:text=":"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+
+            <!-- The minutes should always be to the right of the separator,
+                 regardless of the current locale's layout direction. -->
+            <TextView
+                android:id="@+id/minutes"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="none"
+                android:gravity="left"
+                tools:text="59"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+        </LinearLayout>
+
+        <!-- The layout alignment of this view will switch between toRightOf
+             @id/minutes and toLeftOf @id/hours depending on the locale. -->
+        <LinearLayout
+            android:id="@+id/ampm_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/time_layout"
+            android:layout_centerHorizontal="true"
+            android:orientation="vertical">
+
+            <CheckedTextView
+                android:id="@+id/am_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_am_top_padding"
+                android:lines="1"
+                android:ellipsize="none"
+                android:includeFontPadding="false"
+                tools:text="AM"
+                tools:textSize="@dimen/timepicker_ampm_label_size"
+                tools:textColor="@color/white" />
+
+            <CheckedTextView
+                android:id="@+id/pm_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_pm_top_padding"
+                android:lines="1"
+                android:ellipsize="none"
+                android:includeFontPadding="false"
+                tools:text="PM"
+                tools:textSize="@dimen/timepicker_ampm_label_size"
+                tools:textColor="@color/white" />
+        </LinearLayout>
+    </RelativeLayout>
+
+    <ViewStub
+        android:id="@id/topPanel"
+        android:layout="@layout/alert_dialog_title_material"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="1"
+        android:layout_row="0"
+        android:layout_gravity="top|fill_horizontal" />
+
+    <android.widget.RadialTimePickerView
+        android:id="@+id/radial_picker"
+        android:layout_width="@dimen/timepicker_radial_picker_dimen"
+        android:layout_height="@dimen/timepicker_radial_picker_dimen"
+        android:layout_column="1"
+        android:layout_row="1"
+        android:layout_rowWeight="1"
+        android:layout_gravity="center|fill"
+        android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+        android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+        android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
+
+    <ViewStub
+        android:id="@id/buttonPanel"
+        android:layout="@layout/alert_dialog_button_bar_material"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="1"
+        android:layout_row="2"
+        android:layout_gravity="bottom|fill_horizontal" />
+</GridLayout>
diff --git a/core/res/res/layout-television/user_switching_dialog.xml b/core/res/res/layout-television/user_switching_dialog.xml
new file mode 100644
index 0000000..72150e3
--- /dev/null
+++ b/core/res/res/layout-television/user_switching_dialog.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/message"
+        style="?attr/textAppearanceListItem"
+        android:layout_width="match_parent"
+        android:background="@color/background_leanback_dark"
+        android:textColor="@color/primary_text_leanback_dark"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:paddingTop="24dp"
+        android:paddingBottom="24dp" />
diff --git a/core/res/res/layout/alert_dialog_button_bar_material.xml b/core/res/res/layout/alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..891bcd5
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_button_bar_material.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+
+<com.android.internal.widget.ButtonBarLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/buttonPanel"
+    style="?attr/buttonBarStyle"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layoutDirection="locale"
+    android:orientation="horizontal"
+    android:paddingStart="12dp"
+    android:paddingEnd="12dp"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="bottom">
+
+    <Button
+        android:id="@+id/button3"
+        style="?attr/buttonBarNeutralButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Space
+        android:id="@+id/spacer"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:visibility="invisible" />
+
+    <Button
+        android:id="@+id/button2"
+        style="?attr/buttonBarNegativeButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/button1"
+        style="?attr/buttonBarPositiveButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+</com.android.internal.widget.ButtonBarLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 29bfaa7..bf1e383 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -22,34 +22,7 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
-    <LinearLayout android:id="@+id/topPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-        <LinearLayout android:id="@+id/title_template"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:gravity="center_vertical|start"
-            android:paddingStart="?attr/dialogPreferredPadding"
-            android:paddingEnd="?attr/dialogPreferredPadding"
-            android:paddingTop="@dimen/dialog_padding_top_material">
-            <ImageView android:id="@+id/icon"
-                android:layout_width="32dip"
-                android:layout_height="32dip"
-                android:layout_marginEnd="8dip"
-                android:scaleType="fitCenter"
-                android:src="@null" />
-            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?attr/windowTitleStyle"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textAlignment="viewStart" />
-        </LinearLayout>
-        <!-- If the client uses a customTitle, it will be added here. -->
-    </LinearLayout>
+    <include layout="@layout/alert_dialog_title_material" />
 
     <FrameLayout android:id="@+id/contentPanel"
         android:layout_width="match_parent"
@@ -101,33 +74,5 @@
             android:layout_height="wrap_content" />
     </FrameLayout>
 
-    <LinearLayout android:id="@+id/buttonPanel"
-        style="?attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layoutDirection="locale"
-        android:orientation="horizontal"
-        android:paddingStart="12dp"
-        android:paddingEnd="12dp"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
-        android:gravity="bottom">
-        <Button android:id="@+id/button3"
-            style="?attr/buttonBarNeutralButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:visibility="invisible" />
-        <Button android:id="@+id/button2"
-            style="?attr/buttonBarNegativeButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-        <Button android:id="@+id/button1"
-            style="?attr/buttonBarPositiveButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-    </LinearLayout>
+    <include layout="@layout/alert_dialog_button_bar_material" />
 </LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
new file mode 100644
index 0000000..f61b90b
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/topPanel"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/title_template"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center_vertical|start"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:paddingTop="@dimen/dialog_padding_top_material">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="32dip"
+            android:layout_height="32dip"
+            android:layout_marginEnd="8dip"
+            android:scaleType="fitCenter"
+            android:src="@null" />
+
+        <com.android.internal.widget.DialogTitle
+            android:id="@+id/alertTitle"
+            style="?attr/windowTitleStyle"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewStart" />
+    </LinearLayout>
+
+    <!-- If the client uses a customTitle, it will be added here. -->
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index c0cd93d..28fbea5 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -13,55 +13,80 @@
      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:orientation="vertical"
-    android:padding="12dp"
-    >
-    <LinearLayout
-        android:id="@+id/text"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_marginTop="4dp"
-        android:padding="1dp"
-        >
+        android:background="#ff009688"
+        android:gravity="center_vertical"
+        android:paddingBottom="24dp">
+
+    <FrameLayout
+            android:id="@+id/immersive_cling_chevron"
+            android:layout_width="76dp"
+            android:layout_height="76dp"
+            android:layout_marginTop="-24dp"
+            android:layout_centerHorizontal="true">
+
         <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:src="@drawable/cling_arrow_up"
-            />
-        <FrameLayout
+                android:id="@+id/immersive_cling_back_bg_light"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="center"
+                android:src="@drawable/immersive_cling_light_bg_circ" />
+
+        <ImageView
+                android:id="@+id/immersive_cling_back_bg"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="center"
+                android:src="@drawable/immersive_cling_bg_circ" />
+
+        <ImageView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingTop="8dp"
+                android:scaleType="center"
+                android:src="@drawable/ic_expand_more_48dp"
+                android:tint="#ff009688"/>
+    </FrameLayout>
+
+    <TextView
+            android:id="@+id/immersive_cling_title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:background="@drawable/cling_bg"
-            android:paddingStart="14dp"
-            android:paddingEnd="14dp"
-            android:paddingTop="24dp"
-            android:paddingBottom="24dp">
-            <TextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:text="@string/immersive_mode_confirmation"
-                android:textColor="#80000000"
-                android:textSize="16sp"
-                />
-        </FrameLayout>
-    </LinearLayout>
+            android:layout_below="@id/immersive_cling_chevron"
+            android:paddingEnd="48dp"
+            android:paddingStart="48dp"
+            android:paddingTop="40dp"
+            android:text="@string/immersive_cling_title"
+            android:textColor="@color/primary_text_default_material_light"
+            android:textSize="24sp" />
+
+    <TextView
+            android:id="@+id/immersive_cling_description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/immersive_cling_title"
+            android:paddingEnd="48dp"
+            android:paddingStart="48dp"
+            android:paddingTop="12.6dp"
+            android:text="@string/immersive_cling_description"
+            android:textColor="@color/primary_text_default_material_light"
+            android:textSize="16sp" />
 
     <Button
-        android:id="@+id/ok"
-        android:layout_width="160sp"
-        android:layout_height="wrap_content"
-        android:layout_gravity="right"
-        android:layout_marginTop="18dp"
-        android:gravity="center"
-        android:text="@string/ok"
-        android:background="@drawable/cling_button"
-        />
+            android:id="@+id/ok"
+            style="@style/Widget.Material.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_below="@+id/immersive_cling_description"
+            android:layout_marginEnd="40dp"
+            android:layout_marginTop="18dp"
+            android:paddingEnd="8dp"
+            android:paddingStart="8dp"
+            android:text="@string/immersive_cling_positive"
+            android:textColor="@android:color/white"
+            android:textSize="14sp" />
 
-</LinearLayout>
-
-
+</RelativeLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 3fdcaf7..ea22b15 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -16,12 +16,9 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="64dp"
-    internal:layout_minHeight="64dp"
-    internal:layout_maxHeight="64dp"
     >
     <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
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 935424a..2a3ee90 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -16,12 +16,9 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
     >
     <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 302e651..f1a9549 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -16,12 +16,9 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
     >
     <ImageView
         android:id="@+id/big_picture"
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 d0c10b2..f657f04 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -16,12 +16,9 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
     >
     <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index ac448ee..d292d4e 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -16,12 +16,9 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
     >
     <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 69020a4..0292d28 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -16,14 +16,11 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="64dp"
     android:orientation="horizontal"
     android:background="#00000000"
-    internal:layout_minHeight="64dp"
-    internal:layout_maxHeight="64dp"
     >
     <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml
deleted file mode 100644
index 07d1766..0000000
--- a/core/res/res/layout/time_header_label.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/time_header"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:padding="@dimen/timepicker_separator_padding"
-    android:gravity="center">
-
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="bottom"
-        android:orientation="horizontal"
-        android:layoutDirection="ltr">
-
-        <TextView
-            android:id="@+id/hours"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="end"
-            android:layoutDirection="locale" />
-
-        <TextView
-            android:id="@+id/separator"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/timepicker_separator_padding"
-            android:layout_marginRight="@dimen/timepicker_separator_padding"
-            android:importantForAccessibility="no"
-            android:layoutDirection="locale" />
-
-        <TextView
-            android:id="@+id/minutes"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="start"
-            android:layoutDirection="locale" />
-
-        <LinearLayout
-            android:id="@+id/ampm_layout"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:baselineAlignedChildIndex="1"
-            android:layoutDirection="locale">
-            <CheckedTextView
-                android:id="@+id/am_label"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingTop="@dimen/timepicker_ampm_vertical_padding"
-                android:lines="1"
-                android:ellipsize="none" />
-            <CheckedTextView
-                android:id="@+id/pm_label"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingTop="@dimen/timepicker_pm_top_padding"
-                android:lines="1"
-                android:ellipsize="none" />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
new file mode 100644
index 0000000..0ef404d
--- /dev/null
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:tools="http://schemas.android.com/tools"
+                android:id="@+id/time_header"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="horizontal"
+                android:padding="@dimen/timepicker_separator_padding"
+                tools:background="@color/accent_material_light">
+
+    <!-- The hour should always be to the left of the separator,
+         regardless of the current locale's layout direction. -->
+    <TextView
+        android:id="@+id/hours"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toLeftOf="@+id/separator"
+        android:layout_alignBaseline="@+id/separator"
+        android:singleLine="true"
+        android:ellipsize="none"
+        android:gravity="right"
+        tools:text="23"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
+
+    <TextView
+        android:id="@+id/separator"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/timepicker_separator_padding"
+        android:layout_marginRight="@dimen/timepicker_separator_padding"
+        android:layout_centerInParent="true"
+        android:importantForAccessibility="no"
+        tools:text=":"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
+
+    <!-- The minutes should always be to the left of the separator,
+         regardless of the current locale's layout direction. -->
+    <TextView
+        android:id="@+id/minutes"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@+id/separator"
+        android:layout_alignBaseline="@+id/separator"
+        android:singleLine="true"
+        android:ellipsize="none"
+        android:gravity="left"
+        tools:text="59"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
+
+    <!-- The layout alignment of this view will switch between toRightOf
+         @id/minutes and toLeftOf @id/hours depending on the locale. -->
+    <LinearLayout
+        android:id="@+id/ampm_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@+id/minutes"
+        android:layout_alignBaseline="@+id/minutes"
+        android:orientation="vertical"
+        android:baselineAlignedChildIndex="1">
+        <CheckedTextView
+            android:id="@+id/am_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingTop="@dimen/timepicker_am_top_padding"
+            android:lines="1"
+            android:ellipsize="none"
+            tools:text="AM"
+            tools:textSize="@dimen/timepicker_ampm_label_size"
+            tools:textColor="@color/white" />
+        <CheckedTextView
+            android:id="@+id/pm_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingTop="@dimen/timepicker_pm_top_padding"
+            android:lines="1"
+            android:ellipsize="none"
+            tools:text="PM"
+            tools:textSize="@dimen/timepicker_ampm_label_size"
+            tools:textColor="@color/white" />
+    </LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
deleted file mode 100644
index d04fbb6..0000000
--- a/core/res/res/layout/time_picker_holo.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-    <include
-        layout="@layout/time_header_label"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/timepicker_header_height"
-        android:layout_gravity="center" />
-    <android.widget.RadialTimePickerView
-        android:id="@+id/radial_picker"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/timepicker_radial_picker_dimen"
-        android:layout_gravity="center" />
-</LinearLayout>
diff --git a/core/res/res/layout/time_picker_legacy_holo.xml b/core/res/res/layout/time_picker_legacy_material.xml
similarity index 100%
rename from core/res/res/layout/time_picker_legacy_holo.xml
rename to core/res/res/layout/time_picker_legacy_material.xml
diff --git a/core/res/res/layout/time_picker_material.xml b/core/res/res/layout/time_picker_material.xml
new file mode 100644
index 0000000..37a7384
--- /dev/null
+++ b/core/res/res/layout/time_picker_material.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <include
+        layout="@layout/time_picker_header_material"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/timepicker_header_height"
+        android:layout_gravity="center" />
+    <android.widget.RadialTimePickerView
+        android:id="@+id/radial_picker"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/timepicker_radial_picker_dimen"
+        android:layout_gravity="center"
+        android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+        android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+        android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
+</LinearLayout>
diff --git a/core/res/res/transition/popup_window_enter.xml b/core/res/res/transition/popup_window_enter.xml
new file mode 100644
index 0000000..92d4c1e
--- /dev/null
+++ b/core/res/res/transition/popup_window_enter.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
+               android:transitionOrdering="together">
+     <transition class="com.android.internal.transition.EpicenterClipReveal"
+         android:interpolator="@android:interpolator/accelerate_cubic"
+         android:startDelay="50"
+         android:duration="300" />
+     <fade
+         android:interpolator="@android:interpolator/linear"
+         android:duration="100" />
+</transitionSet>
diff --git a/core/res/res/transition/popup_window_exit.xml b/core/res/res/transition/popup_window_exit.xml
new file mode 100644
index 0000000..5cb9f0b
--- /dev/null
+++ b/core/res/res/transition/popup_window_exit.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<fade xmlns:android="http://schemas.android.com/apk/res/android"
+      android:interpolator="@android:interpolator/linear" />
diff --git a/core/res/res/values-af/donottranslate-cldr.xml b/core/res/res/values-af/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-af/donottranslate-cldr.xml
+++ b/core/res/res/values-af/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index edadfc4..5a12efb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekondes"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekonde"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Titelloos&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen foonnommer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Onbekend"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Stemboodskap"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Jou SIM-kaart is PUK-gesluit. Voer die PUK-kode in om dit te ontsluit."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Sleutel PUK2 in om SIM-kaart oop te sluit."</string>
     <string name="enablePin" msgid="209412020907207950">"Onsuksesvol, aktiveer SIM-/RUIM-slot."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende poging voordat SIM gesluit word."</item>
-    <item quantity="other" msgid="7530597808358774740">"Jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende pogings voordat SIM gesluit word."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor voordat SIM gesluit word.</item>
+      <item quantity="one">Jy het <xliff:g id="NUMBER_0">%d</xliff:g> poging oor voordat SIM gesluit word.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Inkomender beller-ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is AF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Stembystand"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind aan \'n roeteverskafferdiens"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Laat die houer toe om aan enige geregistreerde roeteverskaffers te bind. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind aan \'n TV-invoer"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Laat die program toe om met kortveldkommunikasie- (NFC) merkers, kaarte en lesers te kommunikeer."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktiveer jou skermslot"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Laat die program toe om die sleutelslot en enige verwante wagwoordsekuriteit te deaktiveer. Byvoorbeeld, die foon deaktiveer die sleutelslot wanneer ’n oproep inkom, en atkiveer dit dan weer wanneer die oproep eindig."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"bestuur vingerafdrukhardeware"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Laat die program toe om metodes te benut om vingerafdruksjablone vir gebruik by te voeg en uit te vee."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"gebruik vingerafdrukhardeware"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Laat die program toe om vingerafdrukhardeware vir stawing te gebruik"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lees sinkroniseer-instellings"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Laat die program toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-program met \'n rekening gesinkroniseer is."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"wissel tussen sinkronisasie aan en af"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind aan \'n kieserteikendiens"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Laat die houer toe om aan die top-koppelvlak van \'n kieserteikendiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"verbind met \'n toestandverskafferdiens"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Laat die houer toe om met die topvlak-koppelvlak van \'n toestandverskafferdiens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind aan \'n mediaroetediens"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Laat die houer toe om aan die topvlakkoppelvlak van \'n mediaroetediens te bind. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"bind aan \'n droomdiens"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Laat die houer toe om aan die topvlak-koppelvlak van \'n droomdiens te bind. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die diensverskaffer voorsien is"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind aan \'n diensverskaffer-boodskapdiens"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dit laat die houer toe om aan die top-koppelvlak van \'n diensverskaffer-boodskapdiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Beheer die lengte en die karakters wat in skermslotwagwoorde en -PIN\'e toegelaat word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitor die aantal keer wat \'n verkeerde wagwoorde ingevoer is wanneer die skerm ontsluit word. Sluit die tablet of vee al die data uit as die wagwoord te veel keer verkeerd ingevoer word."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitor die aantal verkeerde wagwoorde wat ingevoer word wanneer die skerm ontsluit word, en sluit die TV of vee al die TV se data uit as te veel verkeerde wagwoorde ingevoer word."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitor die aantal keer wat \'n verkeerde wagwoorde ingevoer is wanneer die skerm ontsluit word. Sluit die foon of vee al die data uit as die wagwoord te veel keer verkeerd ingevoer word."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Wysig die wagwoord wat die skerm ontsluit"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Verander die skermontsluit-wagwoord."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitor die aantal verkeerde wagwoorde wat ingevoer word wanneer die skerm ontsluit word, en sluit die tablet of vee al hierdie gebruiker se data uit as te veel verkeerde wagwoorde ingevoer word."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitor die aantal verkeerde wagwoorde wat ingevoer word wanneer die skerm ontsluit word, en sluit die TV of vee al hierdie gebruiker se data uit as te veel verkeerde wagwoorde ingevoer word."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitor die aantal verkeerde wagwoorde wat ingevoer word wanneer die skerm ontsluit word, en sluit die foon of vee al hierdie gebruiker se data uit as te veel verkeerde wagwoorde ingevoer word."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Verander die skermslot"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Verander die skermslot."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Sluit die skerm"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Beheer hoe en wanneer die skerm sluit."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Vee alle data uit"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Vee die tablet se data uit sonder waarskuwing, deur \'n fabrieksterugstelling uit te voer."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Vee die TV se data sonder waarskuwing uit deur \'n fabriekterugstelling te doen."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Vee die foon se data uit sonder waarskuwing, deur \'n fabrieksterugstelling uit te voer."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Vee gebruikerdata uit"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Vee hierdie gebruiker se data in hierdie tablet sonder waarskuwing uit."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Vee hierdie gebruiker se data in hierdie TV sonder waarskuwing uit."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Vee hierdie gebruiker se data in hierdie foon sonder waarskuwing uit."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Stel die toestel se globale instaan"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel die toestel se globale instaan wat gebruik moet word terwyl die beleid geaktiveer is. Net die eerste toesteladministrateur stel die effektiewe globale instaan op."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Stel skermslotwagwoord se vervaldatum"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Beheer hoe gereeld die skermslot-wagwoord verander moet word."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Stel die toestel se globale instaanbediener wat gebruik moet word terwyl die beleid geaktiveer is. Net die toesteladministrateur kan die globale instaanbediener stel."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Stel skermslotwagw. se verval"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Verander hoe gereeld die skermslotwagwoord, -PIN of -patroon verander moet word."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Stel bergingsenkripsie"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vereis dat gestoorde programdata geënkripteer word."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiveer kameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Voorkom die gebruik van alle toestelkameras."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Deaktiveer kenmerke in \'keyguard\'"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Voorkom die gebruik van \'n paar kenmerke in \'keyguard\'."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Deaktiveer skermslotkenmerke"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Voorkom die gebruik van sommige kenmerke van skermslot."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Tuis"</item>
     <item msgid="869923650527136615">"Mobiel"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil Verken-met-raak aktiveer. Wanneer Verken-met-raak aangeskakel is, kan jy beskrywings van wat onder jou vinger is hoor of sien, of jy kan gebare uitvoer om interaksie met die foon te hê ."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand gelede"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Voor 1 maand gelede"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekonde gelede"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekondes gelede"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuut gelede"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minute gelede"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 uur gelede"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Afgelope <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Afgelope <xliff:g id="COUNT_1">%d</xliff:g> dae</item>
+      <item quantity="one">Afgelope <xliff:g id="COUNT_0">%d</xliff:g> dag</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Verlede maand"</string>
     <string name="older" msgid="5211975022815554840">"Ouer"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gister"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"oor 1 sekonde"</item>
-    <item quantity="other" msgid="1241926116443974687">"oor <xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"oor 1 minuut"</item>
-    <item quantity="other" msgid="3330713936399448749">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"oor 1 uur"</item>
-    <item quantity="other" msgid="547290677353727389">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"môre"</item>
-    <item quantity="other" msgid="5109449375100953247">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sek. gelede"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min. gelede"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min. gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 uur gelede"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gister"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"oor 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"oor <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"oor 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"oor 1 uur"</item>
-    <item quantity="other" msgid="3705373766798013406">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"môre"</item>
-    <item quantity="other" msgid="2973062968038355991">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"by <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"weke"</string>
     <string name="year" msgid="4001118221013892076">"jaar"</string>
     <string name="years" msgid="6881577717993213522">"jaar"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekonde"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minute"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 uur"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ure"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekondes</item>
+      <item quantity="one">1 sekonde</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="one">1 minuut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> uur</item>
+      <item quantity="one">1 uur</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hierdie video is nie geldig vir stroming na hierdie toestel nie."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan nie hierdie video speel nie."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android begin tans …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimeer tans berging."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimeer program <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Berei tans <xliff:g id="APPNAME">%1$s</xliff:g> voor."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Begin programme."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Voltooi herlaai."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> loop"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Moenie die nuwe program begin nie."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Begin <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop die ou program sonder om te stoor."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Kies \'n handeling vir teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Luiervolume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Luitone"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende luitoon"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netwerk beskikbaar"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi-netwerke beskikbaar"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Oop Wi-Fi-netwerke beskikbaar"</item>
-    <item quantity="other" msgid="7915895323644292768">"Oop Wi-Fi-netwerke beskikbaar"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi netwerke beskikbaar</item>
+      <item quantity="one">Wi-Fi-netwerk beskikbaar</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Oop Wi-Fi-netwerke beskikbaar</item>
+      <item quantity="one">Oop Wi-Fi-netwerk beskikbaar</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Meld aan by Wi-Fi-netwerk"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Meld aan by netwerk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Program %1$s wil aan Wi-Fi-netwerk %2$s koppel"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"\'n Program"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kon nie Wi-Fi Direct begin nie."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Gekoppel as \'n mediatoestel"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Gekoppel as \'n kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Gekoppel as \'n MIDI-toestel"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Gekoppel as \'n installeerder"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Gekoppel aan \'n USB-toebehoorsel"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Raak vir ander USB-opsies."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Slaan oor"</string>
     <string name="no_matches" msgid="8129421908915840737">"Geen passings nie"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Vind op bladsy"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 passing"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> van <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> van <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 passing</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Klaar"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Ontheg tans USB-geheue..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Ontheg tans SD-kaart..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skep \'n PIN vir wysigingbeperkings"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'e kom nie ooreen nie. Probeer weer."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is te kort. Moet ten minste 4 syfers wees."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Probeer weer oor 1 sekonde"</item>
-    <item quantity="other" msgid="4730868920742952817">"Probeer weer oor <xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Probeer weer oor <xliff:g id="COUNT">%d</xliff:g> sekondes</item>
+      <item quantity="one">Probeer weer oor 1 sekonde</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer later weer"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swiep van bo af na onder om volskerm te verlaat."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Bekyk tans volskerm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Swiep van bo na onder as jy wil uitgaan."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Het dit"</string>
     <string name="done_label" msgid="2093726099505892398">"Klaar"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ure se sirkelglyer"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minute se sirkelglyer"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om hierdie skerm te ontspeld, raak en hou tegelyk Terug en Oorsig."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om hierdie skerm te ontspeld, raak en hou Oorsig."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skerm is vasgespeld. Jou organisasie laat nie toe dat dit ontspeld word nie."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skerm ontspeld"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Totdat jou ontspantyd om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> eindig"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tot jou aftyd verby is"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Vir een minuut (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Vir %1$d minute (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Vir een uur (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Vir %1$d ure (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d minute lank"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Een uur lank"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d uur lank"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d minute lank (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Een minuut lank (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d uur lank (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Een uur lank (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d minute lank</item>
+      <item quantity="one">Een minuut lank</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d uur lank</item>
+      <item quantity="one">Een uur lank</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Onbepaalde tyd"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Vou in"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Tot die volgende wekker om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Tot die volgende wekker"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-versoek is gewysig tot DIAL-versoek."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-versoek is gewysig tot USSD-versoek."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-versoek is gewysig tot nuwe SS-versoek."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-randpoort"</string>
 </resources>
diff --git a/core/res/res/values-am/donottranslate-cldr.xml b/core/res/res/values-am/donottranslate-cldr.xml
index ea1975c..6afe07f 100755
--- a/core/res/res/values-am/donottranslate-cldr.xml
+++ b/core/res/res/values-am/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %b %-e %Y</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ac46b66..1741851 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ሴ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ሴ"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ርዕስ አልባ&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ምንም ስልክ ቁጥር የለም)"</string>
     <string name="unknownName" msgid="6867811765370350269">"አይታወቅም"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"የድምፅ መልዕክት"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM ካርድዎ PUK-የተቆለፈ ነው።የPUK ኮዱን በመተየብ ይክፈቱት።"</string>
     <string name="needPuk2" msgid="4526033371987193070">" SIM ለመክፈት PUK2 ተይብ።"</string>
     <string name="enablePin" msgid="209412020907207950">"አልተሳካም፣ የሲም/RUIM ቁልፍን አንቃ።"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"ሲምዎ ከመቆለፉ በፊት <xliff:g id="NUMBER">%d</xliff:g> ሙከራ ይቀርዎታል።"</item>
-    <item quantity="other" msgid="7530597808358774740">"ሲምዎ ከመቆለፉ በፊት <xliff:g id="NUMBER">%d</xliff:g> ሙከራዎች ይቀሩዎታል።"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">ሲምዎ ከመቆለፉ በፊት <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀሩዎታል።</item>
+      <item quantity="other">ሲምዎ ከመቆለፉ በፊት <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀሩዎታል።</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"የገቢ ደዋይID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ቅንብሮች"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ  ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ከመንገድ አቅራቢዎች አገልግሎት ጋር ያስተሳስሩ"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"አቃፊው ከማናቸውም የተመዘገቡ የመንገድ አቅራቢዎች ጋር እንዲተሳሰር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ከአንድ የቴሌቪዥን ግብዓት ጋር እሰር"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ከቅርብ ግኑኙነት መስክ (NFC) መለያዎች፣ ካርዶች እና አንባቢ ጋር ለማገናኘት ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"የማያ ገጽዎን መቆለፊያ ያሰናክሉ"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"መተግበሪያው መቆለፊያውና ማንኛውም የተጎዳኘ የይለፍ ቃል ደህንነት እንዲያሰናክል ይፈቅድለታል። ለምሳሌ ስልኩ ገቢ የስልክ ጥሪ በሚቀበልበት ጊዜ መቆለፊያውን ያሰናክልና ከዚያም ጥሪው ሲጠናቀቅ መቆለፊያውን በድጋሚ ያነቃዋል።"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"የጣት አሻራ ሃርድዌርን አስተዳድር"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"መተግበሪያው ጥቅም ላይ እንዲውሉ የጣት አሻራ ቅንብር ደንቦችን ለማከል እና ለመሰረዝ የሚያስችሉ ስልቶችን እንዲያስጀምር ያስችለዋል።"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"የጣት አሻራ ሃርድዌርን ተጠቀም"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"መተግበሪያው የጣት አሻራ ሃርድዌር ለማረጋገጥ ስራ እንዲጠቀም ያስችለዋል"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"የሥምሪያ ቅንብሮች አንብብ"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"መተግበሪያው የአንድ መለያ የማመሳሰል ቅንብሮችን እንዲያነብ ይፈቅድለታል። ለምሳሌ ይህ የሰዎች መተግበሪያ ከመለያ ጋር መመሳሰሉን አለመመሳሰሉን ሊወስን ይችላል።"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ማመሳሰያ በማብራትና በማጥፋት መካከል ቀያይር"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ከመራጭ ዒላማ አገልግሎት ጋር ይሰሩ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ያዢው የመራጩን ዒላማ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጽ ጋር እንዲያስር ይፈቅዳል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ከአንድ የሁኔታ አቅራቢ አገልግሎት ጋር ይሰሩ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ያዢው የአንድ የሁኔታ አቅራቢ አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ከአንድ ማህደረመረጃ ማዞር አገልግሎት ጋር ያስተሳስራል"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"ያዢው የአንድ ማህደረመረጃ ማዞር አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ከህልም አገልግሎት ጋር ጠርዝ"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ያዢው የህልም አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅዳል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ወደሞባይል አገልግሎት ሰጪ የመልዕክት አገልግሎት አያይዝ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ያዢው በሞባይል አገልግሎት ሰጪ የመልዕክት አላላክ አገልግሎት ላይ ከፍተኛውን ደረጃ በይነ ገጽ እንዲይዝ ይፈቅድለታል። ለመደበኛ መተግበሪያ በጭራሽ አያስፈልግም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"በማያ ገጽ መቆለፊያ የይለፍ ቃሎች እና ፒኖች ውስጥ የሚፈቀዱ ቁምፊዎችን እና ርዝመታቸውን ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ማሳያውን በምትከፍትበት ጊዜ በስህተት የተተየቡ የይለፍ ቃሎችን ቁጥር ተቆጣጠር፤ እና ጡባዊ ተኮውን ቆልፍ  ወይም በጣም ብዙ የተሳሳቱ የይለፍ ቃሎች ከተተየቡ የጡባዊ ተኮን ውሂብ አጥፋ፡፡"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ማያ ገጹን ሲያስከፍቱ በትክክል ያልተተየቡ የይለፍ ቃላት ብዛት ተከታተል፣ እና በጣም ብዙ ትክክል ያልሆኑ የይለፍ ቃላት ከተተየቡ ቴሌዚዥኑን ቆልፍ ወይም ሁሉንም የቴሌቪዥን ውሂብ ደምስስ።"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"የተተየቡ ልክ ያልሆኑ የይለፍ ቃሎችን ቁጥር ተቆጣጠር፡፡ማሳያውን በምትከፍትበት ጊዜ፤ እና በጣም ብዙ ልክ ያልሆኑ የይለፍ ቃሎች ከተተየቡ ስልኩን ቆልፈው ወይም ሁሉንም የስልኩን ውሂብ ደምስሰው፡፡"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"የማያ-መክፈቻ ይለፍ ቃል ለውጥ"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"የማያ-መክፈቻ የይለፍ ቃል ለውጥ።"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ማያ ገጹን ሲያስከፍቱ በትክክል ያልተተየቡ የይለፍ ቃላት ብዛት ተከታተል፣ እና በጣም ብዙ ትክክል ያልሆኑ የይለፍ ቃላት ከተተየቡ ጡባዊውን ቆልፍ ወይም ሁሉንም የዚህን ተጠቃሚ ውሂብ ደምስስ።."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ማያ ገጹን ሲያስከፍቱ በትክክል ያልተተየቡ የይለፍ ቃላት ብዛት ተከታተል፣ እና በጣም ብዙ ትክክል ያልሆኑ የይለፍ ቃላት ከተተየቡ ቴሌቪዥኑን ቆልፍ ወይም ሁሉንም የዚህን ተጠቃሚ ውሂብ ደምስስ።"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ማያ ገጹን ሲያስከፍቱ በትክክል ያልተተየቡ የይለፍ ቃላት ብዛት ተከታተል፣ እና በጣም ብዙ ትክክል ያልሆኑ የይለፍ ቃላት ከተተየቡ ስልኩን ቆልፍ ወይም ሁሉንም የዚህን ተጠቃሚ ውሂብ ደምስስ።"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"የማያ ገጹን መቆለፊያ ለውጥ"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"የማያ ገጽ መቆለፊያውን ለውጥ።"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ማያ ቆልፍ"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"ማያው እንዴት እና መቼ እንደሚቆልፍ ተቆጣጠር።"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ሁሉንም ውሂብ ሰርዝ"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"የፋብሪካው ውሂብ ዳግም አስጀምርን በማከናወን፣ያለ ማስጠንቀቂያ የጡባዊውን ውሂብ አጥፋ።"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"የፋብሪካ ውሂብ ዳግም ማስጀመር በማከናወን ያለማስጠንቀቂያ የቴሌቪዥኑን ውሂብ ይደምስሱ።"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"የፋብሪካ ውሂብ ድጋሚ አስጀምር በማከናወን ያለ ማሰጠንቀቂያ የስልኩን ውሂብ ደምስስ።"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"የተጠቃሚ ውሂብ ደምስስ"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ያለምንም ማስጠንቀቂያ የዚህን ጡባዊ የተጠቃሚ ውሂብ ደምስስ።"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ያለምንም ማስጠንቀቂያ የዚህን ቴቪ የተጠቃሚ ውሂብ ደምስስ።"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ያለምንም ማስጠንቀቂያ የዚህን ስልክ የተጠቃሚ ውሂብ ደምስስ።"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"የመሣሪያውን ሁሉንም ፕሮክሲ አዘጋጅ"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"መመሪያ እስኪነቃ ድረስ ለመጠቀም የመሣሪያውን ሁሉንም ፕሮክሲ አዘጋጅ። የመጀመሪያው የመሣሪያ አስተዳደር ብቻ የሁሉንም ፕሮክሲ ያዘጋጃል።"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"የማያቆልፍ ይለፍ ቃል ማብቂያ ጊዜ አዘጋጅ"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"የማያ ቆልፍ ይለፍ ቃል በምን ያህል ጊዜ ተደጋግሞ መለወጥ እንዳለበት ተቆጣጠር።"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"መመሪያ ነቅቶ እያለ ጥቅም ላይ ሊውል የሚችለውን የመሣሪያውን ሁሉንተናዊ ተኪ አዘጋጅ። የመሣሪያ ባለቤት ብቻ የሁሉንተናዊ ተኪውን ማዘጋጀት ይችላል።"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"የማያ ገጽ መቆለፊያ የአገልግሎት ማብቂያ ጊዜን አዘጋጅ"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"የማያ ገጽ መቆለፊያ የይለፍ ቃል፣ ፒን፣ ወይም ስርዓተ ጥለት በምን ያህል ጊዜ ተደጋግሞ መለወጥ እንዳለበት ለውጥ።"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ማከማቻ ማመስጠር አዘጋጅ"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"የተከማቸ ትግበራ ውሂብ የተመሰጠረ እንዲሆን ጠይቅ።"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ካሜራዎችን አቦዝን"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"የሁሉንም መሣሪያ ካሜራዎች መጠቀም ከልክል።"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"በቁልፍ ጠባቂ ውስጥ ባህሪያትን ያሰናክሉ"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"በቁልፍ ጠባቂ ውስጥ የአንዳንድ ባህሪያትን መጠቀም ያግዱ።"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"የማያ ገጽ መቆለፊያ የተሰናከሉ ባህሪዎች"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"የማያ ገጽ መቆለፊያ ላይ ያሉ አንዳንድ ባህሪዎችን መጠቀምን ተከላከል።"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"መነሻ"</item>
     <item msgid="869923650527136615">"ተንቀሳቃሽ"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>  ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"ከ 1 ደቂቃ በፊት"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"ከ1 ሰዓት በፊት"</item>
-    <item quantity="other" msgid="2467273239587587569">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ቀኖች <xliff:g id="COUNT">%d</xliff:g> ያልቃል"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">የመጨረሻዎቹ <xliff:g id="COUNT_1">%d</xliff:g> ቀኖች</item>
+      <item quantity="other">የመጨረሻዎቹ <xliff:g id="COUNT_1">%d</xliff:g> ቀኖች</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">" ያለፈው ወር"</string>
     <string name="older" msgid="5211975022815554840">"የድሮ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ትላንትና"</item>
-    <item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
-    <item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"በ1 ደቂቃ ውስጥ"</item>
-    <item quantity="other" msgid="3330713936399448749">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"በ  1 ሰዓት"</item>
-    <item quantity="other" msgid="547290677353727389">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ነገ"</item>
-    <item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"ከ 1 ደቂቃ በፊት"</item>
-    <item quantity="other" msgid="851164968597150710">"ከ <xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"ከ1 ሰዓት በፊት"</item>
-    <item quantity="other" msgid="6889970745748538901">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ትላንትና"</item>
-    <item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
-    <item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"በ1 ደቂቃ ውስጥ"</item>
-    <item quantity="other" msgid="4216113292706568726">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"በ  1 ሰዓት"</item>
-    <item quantity="other" msgid="3705373766798013406">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ነገ"</item>
-    <item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"በ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"በ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ውስጥ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"ሳምንቶች"</string>
     <string name="year" msgid="4001118221013892076">"ዓመት"</string>
     <string name="years" msgid="6881577717993213522">"ዓመታት"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 ሴኮንድ"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 ደቂቃ"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ሰዓት"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ሰከንዶች</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ሰከንዶች</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ሰዓቶች</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ሰዓቶች</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"የቪዲዮ ችግር"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ይቅርታ፣ ይህ ቪዲዮ በዚህ መሣሪያ ለመልቀቅ ትክክል አይደለም።"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ይሄን ቪዲዮ ማጫወት አልተቻለም።"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android በመጀመር ላይ ነው…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ማከማቻን በማመቻቸት ላይ።"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"መተግበሪያዎች በአግባቡ በመጠቀም ላይ <xliff:g id="NUMBER_0">%1$d</xliff:g> ከ <xliff:g id="NUMBER_1">%2$d</xliff:g> ፡፡"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ን ማዘጋጀት።"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"መተግበሪያዎችን በማስጀመር ላይ፡፡"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"አጨራረስ ማስነሻ፡፡"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"አዲሱን መተግበሪያ አትጀምር።"</string>
     <string name="new_app_action" msgid="5472756926945440706">"ጀምር <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"የድሮውን ትግበራ ሳታስቀምጥ አቁም።"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ለፅሁፍ ድርጊት ምረጥ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"የስልክ ጥሪ ድምፅ"</string>
     <string name="volume_music" msgid="5421651157138628171">" ማህደረ መረጃ  ክፍልፍል"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ምንም"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ጥሪ ድምፆች"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ያልታወቀ የስልክ ጥሪ ድምፅ"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"የWi-Fi አውታረ መረብ አለ"</item>
-    <item quantity="other" msgid="4192424489168397386">"የWi-Fi አውታረ መረቦች አሉ"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"አውታረ መረብ ሲኖር Wi-Fi ክፈት"</item>
-    <item quantity="other" msgid="7915895323644292768">"አውታረ መረቦች ሲኖሩ Wi-Fi ክፈት"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">የWi-Fi አውታረ መረቦች አሉ</item>
+      <item quantity="other">የWi-Fi አውታረ መረቦች አሉ</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
+      <item quantity="other">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ወደ አውታረ መረብ ይግቡ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"መተግበሪያ %1$s ወደ Wifi Network %2$s መገናኘት ይፈልጋል"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"አንድ መተግበሪያ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ  ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ  ያጠፋል።"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"በቀጥታ Wi-Fi ማስጀመር አልተቻለም።"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"እሺ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"እንደ ማህደረ መረጃ መሣሪያ ተያይዟል"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"እንደካሜራ ተያይዟል"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"እንደ MIDI መሣሪያ ተገናኝቷል"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"እንደ ጫኝ ተያይዟል"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ለUSB ተቀጥላ ተያይዟል"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"ለሌላ የUSB አማራጮች ንካ።"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ዝለል"</string>
     <string name="no_matches" msgid="8129421908915840737">"ምንም ተመሳሳይ የለም።"</string>
     <string name="find_on_page" msgid="1946799233822820384">"በገፅ ላይ አግኝ"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 ጨዋታ"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ከ <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> ከ<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> ከ<xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"ተከናውኗል"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"የUSB ማከማቻ በመንቀል ላይ...."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"የSD ካርድ በመንቀል ላይ...."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"ገደቦችን ለመቀየር ፒን ይፍጠሩ"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ፒኖች አይዛመዱም። እንደገና ይሞክሩ።"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ፒን በጣም አጭር ነው። ቢያንስ 4 አኃዝ መሆን አለበት።"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"በ1 ሰከንድ ውስጥ እንደገና ይሞክሩ"</item>
-    <item quantity="other" msgid="4730868920742952817">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ</item>
+      <item quantity="other">በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ቆይተው እንደገና ይሞክሩ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ከሙሉ ገጽ ማያ ለመውጣት ጣትዎን ከላይ ወደታች ያንሸራትቱ።"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ሙሉ ገጽ በማሳየት ላይ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ገባኝ"</string>
     <string name="done_label" msgid="2093726099505892398">"ተከናውኗል"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"የሰዓታት ክብ ተንሸራታች"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"የደቂቃዎች ክብ ተንሸራታች"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ይህን ማያ ገጽ ለመንቀል ተመለስን እና አጠቃላይ እይታን በተመሳሳይ ይንኳቸውና ይያዟቸው።"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ይህን ማያ ገጽ ለመንቀል አጠቃላይ እይታን ይንኩትና ይያዙት።"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ማያ ገጽ ተሰክቷል። መንቀል በድርጅትዎ አይፈቀድም።"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"የባትሪ ዕድሜን ለማሻሻል ማገዝ እንዲቻል፣ ኢሜይል፣ መልዕክት አላላክ እና ሌሎች በማመሳሰል ላይ የሚመረኮዙ መተግበሪያዎች እርስዎ ካልከፈቱዋቸው በቀር አይዘምኑም።\n\nየባትሪ ኃይል ቆጣቢ የእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ በራስ-ሰር ይጠፋል።"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"የጥገና ጊዜዎ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ላይ እስኪያበቃ ድረስ"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"የእርስዎ የማይገኙበት ጊዜ እስከሚያበቃ ድረስ"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ለአንድ ደቂቃ (እስከ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ድረስ)"</item>
-    <item quantity="other" msgid="2787867221129368935">"ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ድረስ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ለአንድ ሰዓት (እስከ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ድረስ)"</item>
-    <item quantity="other" msgid="2827214920627669898">"ለ%1$d ሰዓቶች (እስከ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ድረስ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item>
-    <item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ለአንድ ሰዓት"</item>
-    <item quantity="other" msgid="5408537517529822157">"ለ%d ሰዓቶች"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
+      <item quantity="other">ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">ለ%1$d ሰዓቶች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
+      <item quantity="other">ለ%1$d ሰዓቶች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">ለ%d ደቂቃዎች</item>
+      <item quantity="other">ለ%d ደቂቃዎች</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">ለ%d ሰዓቶች</item>
+      <item quantity="other">ለ%d ሰዓቶች</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ድረስ"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"ያለገደብ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ይህን እስኪያጠፉት ድረስ"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ሰብስብ"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"በ<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ላይ እስከሚቀጥለው ማንቂያ ድረስ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"እስከሚቀጥለው ማንቂያ ድረስ"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ጥያቄ ወደ ደውል ጥያቄ ተሻሽሎዋል።"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ጥያቄ ወደ USSD ጥያቄ ተሻሽሎዋል።"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ጥያቄ ወደ አዲስ SS ጥያቄ ተሻሽሎዋል።"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral ወደብ"</string>
 </resources>
diff --git a/core/res/res/values-ar-rEG/donottranslate-cldr.xml b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar-rEG/donottranslate-cldr.xml
+++ b/core/res/res/values-ar-rEG/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s‏/%s‏/%s"</string>
     <string name="month_day_year">%-e %B، %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d‏/%m‏/%Y</string>
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
index d625752..1be9ed8 100755
--- a/core/res/res/values-ar/donottranslate-cldr.xml
+++ b/core/res/res/values-ar/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s‏/%s‏/%s"</string>
     <string name="month_day_year">%-e %B، %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d‏/%m‏/%Y</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 838a424..1d1fe54 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانية"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانية"</string>
     <string name="untitled" msgid="4638956954852782576">"‏&lt;بلا عنوان&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ليس هناك رقم هاتف)"</string>
     <string name="unknownName" msgid="6867811765370350269">"غير معروف"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"البريد الصوتي"</string>
@@ -60,13 +58,17 @@
     <string name="mismatchPin" msgid="609379054496863419">"أرقام التعريف الشخصية التي كتبتها غير مطابقة."</string>
     <string name="invalidPin" msgid="3850018445187475377">"اكتب رقم تعريف شخصيًا مكونًا من 4 إلى ثمانية أعداد."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"‏اكتب رمز PUK مكونًا من 8 أرقام أو أكثر."</string>
-    <string name="needPuk" msgid="919668385956251611">"‏بطاقة SIM مؤمّنة بكود PUK. اكتب كود PUK لإلغاء تأمينها."</string>
-    <string name="needPuk2" msgid="4526033371987193070">"‏اكتب PUK2 لإلغاء تأمين بطاقة SIM."</string>
+    <string name="needPuk" msgid="919668385956251611">"‏شريحة SIM مؤمّنة بكود PUK. اكتب كود PUK لإلغاء تأمينها."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"‏اكتب PUK2 لإلغاء تأمين شريحة SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"‏محاولة غير ناجحة، مكّن قفل SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"‏يتبقى لديك محاولة واحدة (<xliff:g id="NUMBER">%d</xliff:g>) يتم بعدها قفل بطاقة SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"‏يتبقى لديك <xliff:g id="NUMBER">%d</xliff:g> من المحاولات يتم بعدها قفل بطاقة SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="zero">‏لم يتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item>
+      <item quantity="two">‏يتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) يتم بعدهما قفل شريحة SIM.</item>
+      <item quantity="few">‏يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات يتم بعدها قفل شريحة SIM.</item>
+      <item quantity="many">‏يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة يتم بعدها قفل شريحة SIM.</item>
+      <item quantity="other">‏يتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات يتم بعدها قفل شريحة SIM.</item>
+      <item quantity="one">‏يتبقى لديك محاولة واحدة (<xliff:g id="NUMBER_0">%d</xliff:g>) يتم بعدها قفل شريحة SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"معرف المتصل الوارد"</string>
@@ -202,6 +204,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"وضع الطائرة قيد التشغيل"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"وضع الطائرة متوقف"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"الإعدادات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"المساعد الصوتي"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
@@ -304,13 +307,13 @@
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"إرسال أحداث يتم الرد عليها عبر رسالة"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"السماح للتطبيق بإرسال طلبات إلى تطبيقات المراسلة الأخرى للتعامل مع الأحداث التي يتم الرد عليها عبر الرسائل في المكالمات الواردة."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"‏قراءة الرسائل النصية (الرسائل القصيرة SMS أو رسائل الوسائط المتعددة)"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"‏للسماح للتطبيق بقراءة الرسائل القصيرة SMS المخزنة على الجهاز اللوحي أو على بطاقة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة SMS، بغض النظر عن المحتوى أو مدى السرية."</string>
-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"‏يتيح للتطبيق قراءة الرسائل القصيرة SMS المخزنة في التلفزيون أو في بطاقة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة، بغض النظر عن المحتوى ومدى السرية."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"‏للسماح للتطبيق بقراءة الرسائل القصيرة SMS المخزنة على هاتفك أو على بطاقة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة SMS، بغض النظر عن المحتوى أو مدى السرية."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"‏للسماح للتطبيق بقراءة الرسائل القصيرة SMS المخزنة على الجهاز اللوحي أو على شريحة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة SMS، بغض النظر عن المحتوى أو مدى السرية."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"‏يتيح للتطبيق قراءة الرسائل القصيرة SMS المخزنة في التلفزيون أو في شريحة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة، بغض النظر عن المحتوى ومدى السرية."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"‏للسماح للتطبيق بقراءة الرسائل القصيرة SMS المخزنة على هاتفك أو على شريحة SIM. ويتيح هذا للتطبيق قراءة جميع الرسائل القصيرة SMS، بغض النظر عن المحتوى أو مدى السرية."</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"‏تعديل الرسائل النصية (الرسائل القصيرة SMS أو رسائل الوسائط المتعددة)"</string>
-    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"‏للسماح للتطبيق بالكتابة إلى الرسائل القصيرة SMS المخزّنة على الجهاز اللوحي أو بطاقة SIM. قد تحذف التطبيقات الضارة رسائلك."</string>
-    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"‏يتيح للتطبيق كتابة رسائل قصيرة SMS مخزنة على التلفزيون أو بطاقة SIM. وقد تؤدي التطبيقات الضارة إلى حذف رسائلك."</string>
-    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"‏للسماح للتطبيق بالكتابة إلى الرسائل القصيرة SMS المخزّنة على الهاتف أو بطاقة SIM. قد تحذف التطبيقات الضارة رسائلك."</string>
+    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"‏للسماح للتطبيق بالكتابة إلى الرسائل القصيرة SMS المخزّنة على الجهاز اللوحي أو شريحة SIM. قد تحذف التطبيقات الضارة رسائلك."</string>
+    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"‏يتيح للتطبيق كتابة رسائل قصيرة SMS مخزنة على التلفزيون أو شريحة SIM. وقد تؤدي التطبيقات الضارة إلى حذف رسائلك."</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"‏للسماح للتطبيق بالكتابة إلى الرسائل القصيرة SMS المخزّنة على الهاتف أو شريحة SIM. قد تحذف التطبيقات الضارة رسائلك."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"‏تلقي رسائل نصية (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"‏للسماح للتطبيق بتلقي رسائل WAP ومعالجتها. ويتضمن هذا الإذن إمكانية مراقبة الرسائل التي يتم إرسالها إليك أو حذفها بدون عرضها لك."</string>
     <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"‏تلقي رسائل بلوتوث (MAP)"</string>
@@ -431,6 +434,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"الربط مع خدمة مزود طريق"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"للسماح لحامل البطاقة الربط مع أي مزود طريق مسجل. لا يجب استخدامه على الإطلاق مع التطبيقات العادية."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"الالتزام بإدخال التلفزيون"</string>
@@ -574,7 +579,7 @@
     <string name="permlab_recordAudio" msgid="3876049771427466323">"تسجيل الصوت"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"للسماح للتطبيق بتسجيل الصوت باستخدام الميكروفون. ويتيح هذا الإذن للتطبيق تسجيل الصوت في أي وقت وبدون موافقة منك."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"‏اتصالات SIM"</string>
-    <string name="permdesc_sim_communication" msgid="5725159654279639498">"‏السماح للتطبيق بإرسال أوامر إلى بطاقة SIM. وهذا أمر بالغ الخطورة."</string>
+    <string name="permdesc_sim_communication" msgid="5725159654279639498">"‏السماح للتطبيق بإرسال أوامر إلى شريحة SIM. وهذا أمر بالغ الخطورة."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"التقاط صور ومقاطع فيديو"</string>
     <string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"‏تعطيل مؤشر LED للإرسال عندما تكون الكاميرا قيد الاستخدام"</string>
@@ -737,6 +742,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"‏للسماح للتطبيق بالاتصال بعلامات الاتصال قريب المدى (NFC)، والبطاقات وبرامج القراءة."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"تعطيل قفل الشاشة"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"للسماح للتطبيق بتعطيل تأمين المفاتيح وأي أمان لكلمة مرور مرتبطة. على سبيل المثال، يعطل الهاتف تأمين المفاتيح عند استقبال مكالمة هاتفية واردة، ثم يعيد تمكين تأمين المفاتيح عند انتهاء المكالمة."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"لإدارة أجهزة بصمة الإصبع"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"للسماح للتطبيق باستدعاء طرق لإضافة نماذج من بصمات الأصابع وحذفها."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"لاستخدام أجهزة بصمة الإصبع"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"للسماح للتطبيق باستخدام أجهزة بصمة الإصبع للمصادقة"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"قراءة إعدادات المزامنة"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"التبديل بين تشغيل المزامنة وإيقافها"</string>
@@ -791,8 +800,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"الربط بخدمة اختيار الهدف"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة اختيار الهدف. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"الربط بخدمة موفر الحالة"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة موفر الحالة. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"الربط بخدمة توجيه الوسائط"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة توجيه الوسائط. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"‏الالتزام بخدمة dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"‏للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة dream. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string>
@@ -810,29 +823,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"الالتزام بخدمة المراسلة التابعة لمشغل شبكة الجوّال"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"يسمح لحامله بالالتزام بواجهة المستوى العالي لخدمة المراسلة التابعة لمشغل شبكة الجوَّال. ومن المفترض عدم الحاجة إليه مع التطبيقات العادية."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"للتحكم في الطول والأحرف المسموح بها في كلمات المرور وأرقام التعريف الشخصي في قفل الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"لمراقبة عدد مرات كتابة كلمات المرور غير الصحيحة عند إلغاء تأمين الشاشة وتأمين الجهاز اللوحي أو مسح جميع بياناته في حالة كتابة الكثير من كلمات المرور غير الصحيحة."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"مراقبة عدد كلمات المرور غير الصحيحة التي تتم كتابتها عند إلغاء قفل الشاشة، وقفل التلفزيون أو محو جميع بيانات التلفزيون إذا تمت كتابة عدد كبير من كلمات المرور غير الصحيحة."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"مراقبة عدد كلمات المرور غير الصحيحة التي تمت كتابتها عند إلغاء تأمين الشاشة، وتأمين الهاتف ومحو جميع بياناته إذا تمت كتابة عدد أكبر من اللازم من كلمات المرور غير الصحيحة."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"تغيير كلمة مرور إلغاء قفل الشاشة"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"يمكنك تغيير كلمة مرور إلغاء تأمين الشاشة."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"يمكنك مراقبة عدد كلمات المرور غير الصحيحة التي تمت كتابتها عند إلغاء تأمين الشاشة، وتأمين الجهاز اللوحي ومحو جميع بيانات هذا المستخدم إذا تمت كتابة عدد أكبر من اللازم من كلمات المرور غير الصحيحة."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"يمكنك مراقبة عدد كلمات المرور غير الصحيحة التي تمت كتابتها عند إلغاء تأمين الشاشة، وتأمين التلفزيون ومحو جميع بيانات هذا المستخدم إذا تمت كتابة عدد أكبر من اللازم من كلمات المرور غير الصحيحة."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"يمكنك مراقبة عدد كلمات المرور غير الصحيحة التي تمت كتابتها عند إلغاء تأمين الشاشة، وتأمين الهاتف ومحو جميع بيانات هذا المستخدم إذا تمت كتابة عدد أكبر من اللازم من كلمات المرور غير الصحيحة."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"تغيير قفل الشاشة"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"لتغيير قفل الشاشة."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"تأمين الشاشة"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"يمكنك التحكم في كيفية ووقت تأمين الشاشة."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"مسح جميع البيانات"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"يمكنك محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"محو بيانات التلفزيون بدون تحذير من خلال إجراء إعادة ضبط البيانات على إعدادات المصنع."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"يمكنك محو بيانات الهاتف بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"محو بيانات المستخدم"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"لمحو بيانات هذا المستخدم على هذا الجهاز اللوحي بدون تحذير."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"لمحو بيانات هذا المستخدم على هذا التلفزيون بدون تحذير."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"لمحو بيانات هذا المستخدم على هذا الهاتف بدون تحذير."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تعيين الخادم الوكيل العمومي للجهاز"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"تعيين الخادم الوكيل العمومي للجهاز لكي يتم استخدامه أثناء تمكين السياسة. يعين مشرف الجهاز الأول فقط الخادم الوكيل العمومي الفعال."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ضبط انتهاء كلمة مرور تأمين شاشة"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"يمكنك التحكم في عدد مرات تغيير كلمة مرور تأمين الشاشة."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"لضبط الخادم الوكيل العام في الجهاز على الاستخدام أثناء تمكين السياسة. ولن يمكن لأحد سوى مالك الجهاز ضبط الخادم الوكيل العام."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"تعيين مدة انتهاء صلاحية كلمة مرور قفل الشاشة"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"لتغيير عدد مرات تغيير كلمة المرور ورقم التعريف الشخصي والنمط في قفل الشاشة."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تعيين تشفير التخزين"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"يمكنك طلب تشفير بيانات التطبيق المخزنة."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"تعطيل الكاميرات"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"يمكنك منح استخدام جميع كاميرات الجهاز."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"تعطيل الميزات في وضع حماية المفاتيح"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"يمكنك منع استخدام بعض الميزات في وضع حماية المفاتيح."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"تعطيل ميزات قفل الشاشة"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"لمنع استخدام بعض ميزات قفل الشاشة."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"المنزل"</item>
     <item msgid="869923650527136615">"الجوال"</item>
@@ -968,14 +988,14 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"أعد المحاولة"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"أعد المحاولة"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"تم تجاوز الحد الأقصى لعدد محاولات تأمين الجهاز بالوجه"</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"‏ليست هناك بطاقة SIM"</string>
-    <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"‏ليس هناك بطاقة SIM في الجهاز اللوحي."</string>
-    <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"‏لا تتوفر بطاقة SIM في التلفزيون."</string>
-    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"‏ليس هناك بطاقة SIM في الهاتف."</string>
-    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"‏أدخل بطاقة SIM."</string>
-    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"‏بطاقة SIM مفقودة أو غير قابلة للقراءة. أدخل بطاقة SIM."</string>
-    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"‏بطاقة SIM غير قابلة للاستخدام."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"‏تم تعطيل بطاقة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على بطاقة SIM أخرى."</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"‏ليست هناك شريحة SIM"</string>
+    <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"‏ليس هناك شريحة SIM في الجهاز اللوحي."</string>
+    <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"‏لا تتوفر شريحة SIM في التلفزيون."</string>
+    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"‏ليس هناك شريحة SIM في الهاتف."</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"‏أدخل شريحة SIM."</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"‏شريحة SIM مفقودة أو غير قابلة للقراءة. أدخل شريحة SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"‏شريحة SIM غير قابلة للاستخدام."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"‏تم تعطيل شريحة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على شريحة SIM أخرى."</string>
     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"المقطع الصوتي السابق"</string>
     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"المقطع الصوتي التالي"</string>
     <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"إيقاف مؤقت"</string>
@@ -985,10 +1005,10 @@
     <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"تقديم سريع"</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"مكالمات طوارئ فقط"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"الشبكة مؤمّنة"</string>
-    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"‏بطاقة SIM مؤمّنة بكود PUK."</string>
+    <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"‏شريحة SIM مؤمّنة بكود PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"راجع دليل المستخدم أو اتصل بخدمة العملاء."</string>
-    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"‏بطاقة SIM مؤمّنة."</string>
-    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"‏جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"‏شريحة SIM مؤمّنة."</string>
+    <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"‏جارٍ إلغاء تأمين شريحة SIM…"</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة.\n\nالرجاء إعادة المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"لقد كتبت كلمة المرور <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"‏لقد كتبت رمز PIN <xliff:g id="NUMBER_0">%d</xliff:g> مرة بشكل غير صحيح. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
@@ -1128,75 +1148,16 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"‏يريد <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> تمكين ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"قبل شهر واحد"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل شهر واحد"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"قبل ثانية واحدة"</item>
-    <item quantity="other" msgid="3903706804349556379">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"قبل دقيقة واحدة"</item>
-    <item quantity="other" msgid="2176942008915455116">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"قبل ساعة واحدة"</item>
-    <item quantity="other" msgid="2467273239587587569">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعات"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"آخر <xliff:g id="COUNT">%d</xliff:g> من الأيام"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="zero">آخر <xliff:g id="COUNT_1">%d</xliff:g> من الأيام</item>
+      <item quantity="two">آخر يومين (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
+      <item quantity="few">آخر <xliff:g id="COUNT_1">%d</xliff:g> أيام</item>
+      <item quantity="many">آخر <xliff:g id="COUNT_1">%d</xliff:g> يومًا</item>
+      <item quantity="other">آخر <xliff:g id="COUNT_1">%d</xliff:g> من الأيام</item>
+      <item quantity="one">آخر <xliff:g id="COUNT_0">%d</xliff:g> يوم</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"الشهر الماضي"</string>
     <string name="older" msgid="5211975022815554840">"أقدم"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"أمس"</item>
-    <item quantity="other" msgid="2479586466153314633">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"في ثانية واحدة"</item>
-    <item quantity="other" msgid="1241926116443974687">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"في دقيقة واحدة"</item>
-    <item quantity="other" msgid="3330713936399448749">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"في ساعة واحدة"</item>
-    <item quantity="other" msgid="547290677353727389">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"غدًا"</item>
-    <item quantity="other" msgid="5109449375100953247">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"قبل ثانية واحدة"</item>
-    <item quantity="other" msgid="3699169366650930415">"قبل <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"قبل دقيقة واحدة"</item>
-    <item quantity="other" msgid="851164968597150710">"قبل <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"قبل ساعة واحدة"</item>
-    <item quantity="other" msgid="6889970745748538901">"قبل <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"أمس"</item>
-    <item quantity="other" msgid="3453342639616481191">"قبل <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"في ثانية واحدة"</item>
-    <item quantity="other" msgid="5495880108825805108">"في <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"في دقيقة واحدة"</item>
-    <item quantity="other" msgid="4216113292706568726">"في <xliff:g id="COUNT">%d</xliff:g> دقيقة"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"في ساعة واحدة"</item>
-    <item quantity="other" msgid="3705373766798013406">"في <xliff:g id="COUNT">%d</xliff:g> ساعة"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"غدًا"</item>
-    <item quantity="other" msgid="2973062968038355991">"في <xliff:g id="COUNT">%d</xliff:g> يوم"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"في <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"في الساعة <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"في <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1173,30 @@
     <string name="weeks" msgid="6509623834583944518">"أسابيع"</string>
     <string name="year" msgid="4001118221013892076">"سنة"</string>
     <string name="years" msgid="6881577717993213522">"أعوام"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"ثانية واحدة"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> من الثواني"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"دقيقة واحدة"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> من الدقائق"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"ساعة واحدة"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> من الساعات"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="zero">أقل من ثانية (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="two">ثانيتان (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> ثوانٍ</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> ثانية</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> من الثواني</item>
+      <item quantity="one">ثانية واحدة</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="zero">أقل من دقيقة (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="two">دقيقتان (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> دقائق</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> دقيقة</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> من الدقائق</item>
+      <item quantity="one">دقيقة واحدة</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="zero">أقل من ساعة (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="two">ساعتان (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> ساعات</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> ساعة</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> من الساعات</item>
+      <item quantity="one">ساعة واحدة</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"مشكلة في الفيديو"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"عذرًا، هذا الفيديو غير صالح للبث على هذا الجهاز."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"لا يمكنك تشغيل هذا الفيديو."</string>
@@ -1301,6 +1274,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏جارٍ تشغيل Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"جارٍ تحسين السعة التخزينية."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"جارٍ تحسين التطبيق <xliff:g id="NUMBER_0">%1$d</xliff:g> من <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"جارٍ تحضير <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"بدء التطبيقات."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"جارٍ إعادة التشغيل."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> يعمل"</string>
@@ -1311,6 +1285,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"عدم بدء التطبيق الجديد."</string>
     <string name="new_app_action" msgid="5472756926945440706">"بدء <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"إيقاف التطبيق القديم بدون الحفظ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"اختيار إجراء للنص"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"مستوى صوت الرنين"</string>
     <string name="volume_music" msgid="5421651157138628171">"مستوى صوت الوسائط"</string>
@@ -1331,20 +1313,31 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"لا شيء"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"نغمات الرنين"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"نغمة رنين غير معروفة"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"‏شبكة Wi-Fi متاحة"</item>
-    <item quantity="other" msgid="4192424489168397386">"‏شبكات Wi-Fi متاحة"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"‏هناك شبكة Wi-Fi مفتوحة متاحة"</item>
-    <item quantity="other" msgid="7915895323644292768">"‏هناك شبكات Wi-Fi مفتوحة متاحة"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="zero">‏لا تتوفر أية شبكات Wi-Fi</item>
+      <item quantity="two">‏تتوفر شبكتا Wi-Fi</item>
+      <item quantity="few">‏تتوفر شبكات Wi-Fi</item>
+      <item quantity="many">‏تتوفر شبكات Wi-Fi</item>
+      <item quantity="other">‏تتوفر شبكات Wi-Fi</item>
+      <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="zero">‏لا تتوفر أية شبكات Wi-Fi مفتوحة</item>
+      <item quantity="two">‏تتوفر شبكتا Wi-Fi مفتوحتان</item>
+      <item quantity="few">‏تتوفر شبكات Wi-Fi مفتوحة</item>
+      <item quantity="many">‏تتوفر شبكات Wi-Fi مفتوحة</item>
+      <item quantity="other">‏تتوفر شبكات Wi-Fi مفتوحة</item>
+      <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة مفتوحة</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"‏تسجيل الدخول إلى شبكة Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"تسجيل الدخول إلى الشبكة"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏يريد تطبيق %1$s الاتصال بشبكة Wifi ‏%2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"تطبيق"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏اتصال Wi-Fi مباشر"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏تعذر بدء Wi-Fi Direct."</string>
@@ -1375,10 +1368,10 @@
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"‏يمكنك تغيير ذلك لاحقًا من إعدادات &gt; تطبيقات"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"السماح دومًا"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"عدم السماح مطلقًا"</string>
-    <string name="sim_removed_title" msgid="6227712319223226185">"‏تمت إزالة بطاقة SIM"</string>
-    <string name="sim_removed_message" msgid="5450336489923274918">"‏لن تكون شبكة الجوّال متوفرة إلى أن تعيد تشغيل الهاتف مع إدخال بطاقة SIM صالحة."</string>
+    <string name="sim_removed_title" msgid="6227712319223226185">"‏تمت إزالة شريحة SIM"</string>
+    <string name="sim_removed_message" msgid="5450336489923274918">"‏لن تكون شبكة الجوّال متوفرة إلى أن تعيد تشغيل الهاتف مع إدخال شريحة SIM صالحة."</string>
     <string name="sim_done_button" msgid="827949989369963775">"تم"</string>
-    <string name="sim_added_title" msgid="3719670512889674693">"‏تمت إضافة بطاقة SIM"</string>
+    <string name="sim_added_title" msgid="3719670512889674693">"‏تمت إضافة شريحة SIM"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"أعد تشغيل جهازك للدخول إلى شبكة الجوّال."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"إعادة التشغيل"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"تعيين الوقت"</string>
@@ -1411,6 +1404,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"التوصيل كجهاز وسائط"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"التوصيل ككاميرا"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"‏تم التوصيل كجهاز MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"التوصيل كأداة تثبيت"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏الاتصال بجهاز USB ملحق"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"‏المس للاطلاع على خيارات USB الأخرى."</string>
@@ -1526,10 +1520,14 @@
     <string name="skip_button_label" msgid="1275362299471631819">"تخطٍ"</string>
     <string name="no_matches" msgid="8129421908915840737">"ليس هناك أية مطابقات"</string>
     <string name="find_on_page" msgid="1946799233822820384">"بحث في الصفحة"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"مطابقة واحدة"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="zero"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="two"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> من <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">مباراة واحدة</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"تم"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"‏جارٍ إلغاء تحميل وحدة تخزين USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"‏جارٍ إلغاء تحميل بطاقة SD..."</string>
@@ -1675,14 +1673,14 @@
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"‏أدخل رمز PIN لبطاقة SIM"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"‏أدخل رمز PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"أدخل كلمة المرور"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"‏بطاقة SIM معطلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوال للاطلاع على التفاصيل."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"‏شريحة SIM معطلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوال للاطلاع على التفاصيل."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"‏إدخال رمز رمز PIN المراد"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"‏تأكيد رمز رمز PIN المراد"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏جارٍ إلغاء تأمين شريحة SIM…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"‏رمز PIN غير صحيح."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"‏اكتب رمز PIN المكون من 4 إلى 8 أرقام."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"‏يجب أن يتكون رمز PUK من 8 أرقام."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل بطاقة SIM نهائيًا."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل شريحة SIM نهائيًا."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏لا يتطابق رمزا رمز PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
     <string name="kg_login_instructions" msgid="1100551261265506448">"‏لإلغاء التأمين، سجّل الدخول بحسابك في Google."</string>
@@ -1815,12 +1813,18 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"إنشاء رقم تعريف شخصي لتعديل القيود"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"أرقام التعريف الشخصية لا تتطابق، أعد المحاولة."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"‏رمز PIN أقصر مما يلزم، يجب ألا يقل عن 4 أرقام. "</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"أعد المحاولة خلال ثانية واحدة."</item>
-    <item quantity="other" msgid="4730868920742952817">"أعد المحاولة خلال <xliff:g id="COUNT">%d</xliff:g> ثانية"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="zero">حاول مرة أخرى خلال أقل من ثانية <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="two">حاول مرة أخرى خلال ثانيتين (<xliff:g id="COUNT">%d</xliff:g>)</item>
+      <item quantity="few">حاول مرة أخرى خلال <xliff:g id="COUNT">%d</xliff:g> ثوانٍ</item>
+      <item quantity="many">حاول مرة أخرى خلال <xliff:g id="COUNT">%d</xliff:g> ثانية</item>
+      <item quantity="other">حاول مرة أخرى خلال <xliff:g id="COUNT">%d</xliff:g> من الثواني</item>
+      <item quantity="one">حاول مرة أخرى خلال ثانية واحدة</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"أعد المحاولة لاحقًا"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مرر بسرعة من أعلى لأسفل للخروج من وضع ملء الشاشة."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"جارٍ العرض بملء الشاشة"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"حسنًا"</string>
     <string name="done_label" msgid="2093726099505892398">"تم"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"شريط التمرير الدائري للساعات"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"شريط التمرير الدائري للدقائق"</string>
@@ -1835,7 +1839,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"رجوع\" و\"نظرة عامة\" في آن واحد مع الاستمرار."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"نظرة عامة\" مع الاستمرار."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"الشاشة مثبتة. لا تسمح منظمتك بإلغاء التثبيت."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"تم تثبيت الشاشة"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"تم إلغاء تثبيت الشاشة"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string>
@@ -1844,24 +1849,40 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"للمساعدة في تحسين عمر البطارية، يساعد موفر البطارية في تقليل أداء الجهاز ويفرض قيدًا على الاهتزاز وخدمات الموقع ومعظم بيانات الخلفية. قد لا يتم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم تفتحها.\n\nيتم إيقاف موفر البطارية تلقائيًا أثناء شحن الجهاز."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"إلى أن ينتهي وقت التوقف عن العمل في <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"حتى انتهاء وقت التعطل"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"لمدة دقيقة واحدة (حتى <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"‏لمدة %1$d من الدقائق (حتى <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"لمدة ساعة واحدة (حتى <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"‏لمدة %1$d من الساعات (حتى <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item>
-    <item quantity="other" msgid="6924190729213550991">"‏لمدة %d من الدقائق"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"لمدة ساعة واحدة"</item>
-    <item quantity="other" msgid="5408537517529822157">"‏لمدة %d من الساعات"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="zero">‏لمدة أقل من دقيقة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="two">‏لمدة دقيقتين (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">‏لمدة %1$d دقائق (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">‏لمدة %1$d دقيقة (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏لمدة %1$d من الدقائق (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">لمدة دقيقة واحدة (حتى <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="zero">‏لمدة أقل من ساعة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="two">‏لمدة ساعتين (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">‏لمدة %1$d ساعات (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">‏لمدة %1$d ساعة (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏لمدة %1$d من الساعات (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">لمدة ساعة واحدة (حتى <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="zero">‏لمدة أقل من دقيقة (%d)</item>
+      <item quantity="two">‏لمدة دقيقتين (%d)</item>
+      <item quantity="few">‏لمدة %d دقائق</item>
+      <item quantity="many">‏لمدة %d دقيقة</item>
+      <item quantity="other">‏لمدة %d من الدقائق</item>
+      <item quantity="one">لمدة دقيقة واحدة</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="zero">‏لمدة أقل من ساعة (%d)</item>
+      <item quantity="two">‏لمدة ساعتين (%d)</item>
+      <item quantity="few">‏لمدة %d ساعات</item>
+      <item quantity="many">‏لمدة %d ساعة</item>
+      <item quantity="other">‏لمدة %d من الساعات</item>
+      <item quantity="one">لمدة ساعة واحدة</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"إلى أجل غير مسمى"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"تصغير"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"حتى التنبيه التالي في <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"حتى التنبيه التالي"</string>
@@ -1874,4 +1895,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏يتم تعديل الطلب SS لطلب الاتصال."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏يتم تعديل طلب SS إلى طلب USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏يتم تعديل طلب SS إلى طلب SS الجديد."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏منفذ الأجهزة الطرفية المزودة بكابل USB"</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 479cfcf..b22eb7a 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -967,75 +967,11 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Toxunaraq Kəşf Et rejimini aktivləşdirmək istəyir. Toxunaraq Kəşf Et açıldığı zaman, barmağınızın altında nə olduğu haqda olan təsvirləri eşidə və ya görə bilərsiniz və ya telefonda insanlarla əlaqəyə keçmək üçün jestlər həyata keçirə bilərsiniz"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay öncə"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay əvvəl"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saniyə əvvəl"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniyə əvvəl"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 dəqiqə əvvəl"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 saat əvvəl"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
-  </plurals>
   <plurals name="last_num_days">
     <item quantity="other" msgid="3069992808164318268">"Son <xliff:g id="COUNT">%d</xliff:g> gün"</item>
   </plurals>
     <string name="last_month" msgid="3959346739979055432">"Keçən ay"</string>
     <string name="older" msgid="5211975022815554840">"Köhnə"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"dünən"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 saniyə ərzində"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniyə içində"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 dəqiqə içində"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə ərzində"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 saata"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"sabah"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün ərzində"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saniyə əvvəl"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> san əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 dəqiqə əvvəl"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dəqiqə əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 saat əvvəl"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"dünən"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün əvvəl"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 san ərzində"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> san ərzində"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 dəq ərzində"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dəqiqəyə"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 saat ərzində"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saata"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"sabah"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> günə"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarixində"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"saat <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ilində"</string>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
index 1943517..7c5ba7c 100755
--- a/core/res/res/values-bg/donottranslate-cldr.xml
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 4828b48..0ca9f51 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без заглавие&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Няма телефонен номер)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Неизвестно"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Гласова поща"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM картата ви е заключена с PUK. Въведете PUK кода, за да я отключите."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Въведете PUK2, за да отблокирате SIM картата."</string>
     <string name="enablePin" msgid="209412020907207950">"Неуспешно – активирайте заключването на SIM/RUIM картата."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Остава ви <xliff:g id="NUMBER">%d</xliff:g> опит, преди SIM картата да бъде заключена."</item>
-    <item quantity="other" msgid="7530597808358774740">"Остават ви <xliff:g id="NUMBER">%d</xliff:g> опита, преди SIM картата да бъде заключена."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита, преди SIM картата да бъде заключена.</item>
+      <item quantity="one">Остава ви <xliff:g id="NUMBER_0">%d</xliff:g> опит, преди SIM картата да бъде заключена.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Идентификация на вх. обаждания"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"свързване с услуга за предоставяне на маршрути"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Разрешава на собственика да се свързва с всички регистрирани доставчици на маршрути. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"свързване към вход на телевизор"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Разрешава на приложението да комуникира с маркери, карти и четци, ползващи комуникация в близкото поле (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"деактивиране на заключването на екрана ви"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Разрешава на приложението да деактивира заключването на клавиатурата и свързаната защита с парола. Например телефонът деактивира заключването при получаване на входящо обаждане и после го активира отново, когато обаждането завърши."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управление на хардуера за отпечатъци"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Разрешава на приложението да извиква начини за добавяне и изтриване на шаблони за отпечатъци, които да се използват."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"използване на хардуера за отпечатъци"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Разрешава на приложението да използва хардуера за отпечатъци с цел удостоверяване"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"четене на настройките за синхронизиране"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Разрешава на приложението да чете настройките за синхронизиране на профил. Например това може да определи дали приложението Хора е синхронизирано с даден профил."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"включване и изключване на синхронизирането"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"свързване с целева услуга в инструмент за избор"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на целева услуга в инструмент за избор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"свързване с услуга за предоставяне на условия"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за предоставяне на условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"свързване с услуга за маршрутизиране на мултимедия"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за маршрутизиране на мултимедия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"свързване с услуга за „мечти“"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за „мечти“. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"извикване на предоставеното от оператора приложение за конфигуриране"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"свързване с услуга за съобщения от оператор"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Разрешава на притежателя да се свърже към интерфейса от най-високото ниво на услуга за съобщения от оператор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролира дължината и разрешените знаци за паролите и ПИН кодовете за заключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Наблюдава броя въведени неправилни пароли при отключването на екрана и заключва таблета или изтрива всички данни от него, ако неправилните пароли са твърде много."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Наблюдаване на броя на неправилно въведените пароли при отключване на екрана и заключване на телевизора или изтриване на всички данни от него, ако неуспешните опити са твърде много."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Наблюдава броя въведени неправилни пароли при отключването на екрана и заключва телефона или изтрива всички данни от него, ако неправилните пароли са твърде много."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Промяна на паролата за отключване на екрана"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Промяна на паролата за отключване на екрана."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Наблюдава броя на неправилно въведените пароли при отключване на екрана и заключва таблета или изтрива всички данни на този потребител, ако неуспешните опити са твърде много."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Наблюдава броя на неправилно въведените пароли при отключване на екрана и заключва телевизора или изтрива всички данни на този потребител, ако неуспешните опити са твърде много."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Наблюдава броя на неправилно въведените пароли при отключване на екрана и заключва телефона или изтрива всички данни на този потребител, ако неуспешните опити са твърде много."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Промяна на заключването на екрана"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Променя заключването на екрана."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Заключване на екрана"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Контролирайте как и кога екранът се заключва."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Изтриване на всички данни"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Изтриване на данните в таблета без предупреждение чрез възстановяване на фабричните настройки."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Изтриване на данните от телевизора без предупреждение чрез възстановяване на фабричните настройки."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Изтриване на данните в телефона без предупреждение чрез възстановяване на фабричните настройки."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Изтриване на потребителските данни"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Изтрива данните на този потребител от таблета без предупреждение."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Изтрива данните на този потребител от телевизора без предупреждение."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Изтрива данните на този потребител от телефона без предупреждение."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Задаване на глобален прокси сървър за устройството"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Задаване на глобалния прокси сървър, който да се използва, когато правилото е активирано. Само първият администратор на устройството задава действителния глобален прокси сървър."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Изтичане на паролата"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Контролирайте колко често трябва да се променя паролата за заключен екран."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Задава глобалния прокси сървър за устройството, който да се използва, когато правилото е активирано. Само собственикът на устройството може да задава такъв сървър."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Задав. на валидност на паролата на закл. на екрана"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Променя колко често трябва да се сменят паролата, ПИН кодът или фигурата за заключване на екрана."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Шифроване за хранилището"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Изисква съхраняваните данни за приложенията да бъдат шифровани."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Деактивиране на камерите"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Предотвратява употребата на камерите на всички устройства."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Функции при защита на клавишите: Деакт."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Предотвратява използването на някои функции при защита на клавишите."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Функции на закл. на екрана: Деакт."</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Предотвратява използването на някои функции на заключването на екрана."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашен"</item>
     <item msgid="869923650527136615">"Мобилен"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> иска да активира изследването чрез докосване. Когато услугата е включена, можете да чувате или да виждате описания на това, което е под пръста ви, или да изпълнявате жестове, за да взаимодействате с телефона."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Преди 1 месец"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Преди повече от месец"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Преди 1 секунда"</item>
-    <item quantity="other" msgid="3903706804349556379">"Преди <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Преди 1 минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"Преди <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Преди 1 час"</item>
-    <item quantity="other" msgid="2467273239587587569">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последните <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Последните <xliff:g id="COUNT_1">%d</xliff:g> дни</item>
+      <item quantity="one">Последният <xliff:g id="COUNT_0">%d</xliff:g> ден</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Последният месец"</string>
     <string name="older" msgid="5211975022815554840">"По-стари"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"след 1 секунда"</item>
-    <item quantity="other" msgid="1241926116443974687">"след <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"след 1 минута"</item>
-    <item quantity="other" msgid="3330713936399448749">"след <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"след 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"утре"</item>
-    <item quantity="other" msgid="5109449375100953247">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Преди 1 сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"Преди <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Преди 1 мин"</item>
-    <item quantity="other" msgid="851164968597150710">"Преди <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Преди 1 час"</item>
-    <item quantity="other" msgid="6889970745748538901">"Преди <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"Преди <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"след 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"след <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"след 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"след <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"след 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"след <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"утре"</item>
-    <item quantity="other" msgid="2973062968038355991">"след <xliff:g id="COUNT">%d</xliff:g> дни"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"през <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"седмици"</string>
     <string name="year" msgid="4001118221013892076">"година"</string>
     <string name="years" msgid="6881577717993213522">"години"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 минута"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 час"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунди</item>
+      <item quantity="one">1 секунда</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минути</item>
+      <item quantity="one">1 минута</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> часа</item>
+      <item quantity="one">1 час</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Проблем с видеоклипа"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Този видеоклип не е валиден за поточно предаване към това устройство."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Този видеоклип не може да се пусне."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android се стартира…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Хранилището се оптимизира."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизира се приложение <xliff:g id="NUMBER_0">%1$d</xliff:g> от <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> се подготвя."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Приложенията се стартират."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Зареждането завършва."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> се изпълнява"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Новото приложение да не се стартира."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Стартиране на <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Спиране на старото приложение без запазване."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Избиране на действие за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Сила на звука при звънене"</string>
     <string name="volume_music" msgid="5421651157138628171">"Сила на звука"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестна мелодия"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Има достъпна Wi-Fi мрежа"</item>
-    <item quantity="other" msgid="4192424489168397386">"Има достъпни Wi-Fi мрежи"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Има достъпна отворена Wi-Fi мрежа"</item>
-    <item quantity="other" msgid="7915895323644292768">"Има достъпни отворени Wi-Fi мрежи"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Има достъпни Wi-Fi мрежи</item>
+      <item quantity="one">Има достъпна Wi-Fi мрежа</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Има достъпни отворени Wi-Fi мрежи</item>
+      <item quantity="one">Има достъпна отворена Wi-Fi мрежа</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Влизане в Wi-Fi мрежа"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Влезте в мрежата"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложението %1$s иска да се свърже с Wi-Fi мрежата „%2$s“"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct не можа да се стартира."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Свързан като медийно устройство"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Свързан като камера"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Свързано като MIDI устройство"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Свързан като инсталационна програма"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Установена е връзка с аксесоар за USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Докоснете за други опции за USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Пропускане"</string>
     <string name="no_matches" msgid="8129421908915840737">"Няма съответствия"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Намиране в страницата"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 съответствие"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> от <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> от <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 игра</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Готово"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB хранилището се спира..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD картата се спира..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Създаване на ПИН код за промяна на ограниченията"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ПИН кодовете не са идентични. Опитайте отново."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ПИН кодът е твърде кратък. Трябва да е поне 4 цифри."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Опитайте отново след 1 секунда"</item>
-    <item quantity="other" msgid="4730868920742952817">"Опитайте отново след <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Опитайте отново след <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+      <item quantity="one">Опитайте отново след 1 секунда</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Опитайте отново по-късно"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"За изход от цял екран прекарайте пръст отгоре надолу."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Изглед на цял екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"За изход прекарайте пръст надолу от горната част."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрах"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Кръгов плъзгач за часовете"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Кръгов плъзгач за минутите"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да освободите екрана, докоснете и задръжте едновременно бутона за връщане назад и този за общ преглед."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да освободите този екран, докоснете и задръжте бутона „Общ преглед“."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранът е фиксиран. Освобождаването не е разрешено от организацията ви."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранът е освободен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"До приключване на неактивността в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До приключването на почивката ви"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"За една минута (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"За %1$d минути (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"За един час (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"За %1$d часа (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
-    <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"За един час"</item>
-    <item quantity="other" msgid="5408537517529822157">"За %d часа"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">За една минута (до <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">За %1$d часа (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">За един час (до <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">За %d минути</item>
+      <item quantity="one">За една минута</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">За %d часа</item>
+      <item quantity="one">За един час</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"За неопределено време"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Свиване"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следващия будилник в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следващия будилник"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS заявката е променена на DIAL заявка."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS заявката е променена на USSD заявка."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS заявката е променена на нова SS заявка."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Периферен USB порт"</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index fc090ff..8a60320 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> সেকেন্ড"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> সেকেন্ড"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;শিরোনামহীন&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(কোনো ফোন নম্বর নেই)"</string>
     <string name="unknownName" msgid="6867811765370350269">"অজানা"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ভয়েসমেল"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"আপনার সিম কার্ডটি PUK-কোড দিয়ে লক করা রয়েছে৷ এটিকে আনলক করতে PUK কোডটি লিখুন৷"</string>
     <string name="needPuk2" msgid="4526033371987193070">"সিম কার্ড অবরোধ মুক্ত করতে PUK2 লিখুন৷"</string>
     <string name="enablePin" msgid="209412020907207950">"অসফল, সিম/RUIM লক সক্ষম করুন৷"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷"</item>
-    <item quantity="other" msgid="7530597808358774740">"আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম লক হয়ে যাবে৷"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
+      <item quantity="other">আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM লক হয়ে যাবে৷</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"আগত কলার ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"বিমান মোড চালু করা আছে"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"বিমান মোড বন্ধ করা আছে"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"সেটিংস"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
     <string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ধারককে, একটি দূরবর্তী প্রদর্শনের উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়। সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"একটি উইজেট পরিষেবাতে সংলগ্ন করে"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ধারককে, একটি উইজেট পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"একটি রুট প্রদানকারীর পরিষেবা বাঁধাই করে"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ধারককে, কোনো নিবন্ধিত রুট প্রদানকারীকে বাঁধাই করার অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"একটি ডিভাইস প্রশাসকের সাথে ইন্টারঅ্যাক্ট করে"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ধারককে, একটি ডিভাইস প্রশাসকে ইন্টেন্টগুলি পাঠানোর অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"টিভি ইনপুট বাঁধাই করে"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"অ্যাপ্লিকেশানকে নিয়ার ফিল্ড কমিউনিকেশন (NFC) ট্যাগ, কার্ড এবং রিডারগুলির সাথে যোগাযোগ করতে দেয়৷"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"আপনার স্ক্রীন লক অক্ষম করুন"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"কী-লক এবং যেকোনো সংশ্লিষ্ট পাসওয়ার্ড সুরক্ষা অক্ষম করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ উদাহরণস্বরূপ, একটি ইনকামিং ফোন কল গ্রহণ করার সময়ে ফোনটি কী-লক অক্ষম করে, তারপরে কল শেষ হয়ে গেলে কী-লকটিকে পুনরায় সক্ষম করে৷"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার পরিচালনা করুন"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ব্যবহার করার জন্য আঙ্গুলের ছাপের টেম্প্লেটগুলি যোগ করা এবং মোছার পদ্ধতিগুলি গ্রহন করতে অ্যাপ্লিকেশানটিতে অমুমতি দেয়৷"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার ব্যবহার করুন"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"অনুমোদনের জন্য আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার ব্যবহার করতে অ্যাপ্লিকেশানটিতে অনুমতি দেয়"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"সিঙ্ক সেটিংস পড়ে"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"অ্যাপ্লিকেশানটিকে একটি অ্যাকাউন্টের জন্য সিঙ্ক সেটিংস পড়ার অনুমতি দেয়৷ উদাহরণস্বরূপ, \'পিপল\' অ্যাপ্লিকেশানটি কোনো অ্যাকাউন্টের সাথে সিঙ্ক করা আছে কিনা তা নির্ধারণ করতে পারে৷"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"সমন্বয় চালু এবং বন্ধ করা টগল করুন"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"অ্যাপ্লিকেশানটিকে অন্যান্য অ্যাপ্লিকেশান যেগুলি পোস্ট করে সেগুলি সমেত, বিজ্ঞপ্তিগুলি পুনরুদ্ধার করতে, পরীক্ষা করতে এবং সাফ করার অনুমতি দেয়৷"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"একটি বিজ্ঞপ্তি শ্রোতা পরিষেবাতে সংলগ্ন করে"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ধারককে, একটি বিজ্ঞপ্তি শ্রোতা পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"একটি লক্ষ চয়নকারী পরিষেবাতে আবদ্ধ করুন"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ধারককে, একটি লক্ষ্য চয়নকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"একটি শর্ত প্রদানকারীর পরিষেবা বাঁধাই করে"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ধারককে, একটি শর্ত প্রদানকারী পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"একটি মিডিয়া রুট পরিষেবায় জুড়ুন"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"ধারককে একটি মিডিয়া রুট পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়। সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনোই প্রয়োজন হয় না।"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"একটি স্বপ্নের পরিষেবার সাথে যুক্ত হন"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ধারককে, একটি স্বপ্নের পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ক্যারিয়ারের প্রদেয় কনফিগারেশন অ্যাপ্লিকেশানকে দিয়ে কাজ করায়"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"একটি ক্যারিয়ার বার্তাপ্রেরণ পরিষেবা আবদ্ধ করতে"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ধারককে, একটি ক্যারিয়ার বার্তাপ্রেরণ পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"পাসওয়ার্ড নিয়মগুলি সেট করে"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"স্ক্রীন আনলক করার পাসওয়ার্ডগুলিতে অনুমতিপ্রাপ্ত অক্ষর এবং দৈর্ঘ্য নিয়ন্ত্রণ করে৷"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"স্ক্রীন লক করার পাসওয়ার্ডগুলিতে অনুমতিপ্রাপ্ত অক্ষর এবং দৈর্ঘ্য নিয়ন্ত্রণ করে৷"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"স্ক্রীণ আনলক করার প্রচেষ্টাগুলি নিরীক্ষণ করে"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"স্ক্রীণ আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং ট্যাবলেট লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে ট্যাবলেটের ডেটা মুছে ফেলে৷"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"স্ক্রীন আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং টিভি লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে টিভির ডেটা মুছে ফেলে৷"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"স্ক্রীণ আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং ফোন লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে ফোনের ডেটা মুছে ফেলে৷"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"স্ক্রীণ আনলক করার পাসওয়ার্ড পরিবর্তন করে"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"স্ক্রীন আনলক করার পাসওয়ার্ড পরিবর্তন করে৷"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"স্ক্রীন আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং ট্যাবলেট লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে ব্যবহারকারীর ডেটা মুছে ফেলে৷"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"স্ক্রীন আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং টিভি লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে ব্যবহারকারীর ডেটা মুছে ফেলে৷"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"স্ক্রীন আনলক করার সময় ভুলভাবে লেখা পাসওয়ার্ড প্রবেশের সংখ্যা মনিটার করে, এবং ফোন লক করে এবং অনেক বার পাসওয়ার্ড ভুল ভাবে লেখা হলে ব্যবহারকারীর ডেটা মুছে ফেলে৷"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"স্ক্রীন লক পরিবর্তন করুন"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"স্ক্রীন লক পরিবর্তন করুন৷"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"স্ক্রীণটি লক করে"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"স্ক্রীন কখন কিভাবে লক হবে তা নিয়ন্ত্রণ করে৷"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"সমস্ত ডেটা মুছে দেয়"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ফ্যাক্টরি ডেটা পুনরায় সেট কার্য সম্পাদনার দ্বারা কোনো রকম সতর্কতা ছাড়াই ট্যাবলেটের ডেটা মোছে৷"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"সতর্কীকরণ ছাড়াই একটি ফ্যাক্টরি ডেটা পুনরায় সেট করার দ্বারা টিভির ডেটা মুছে ফেলে৷"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ফ্যাক্টরি ডেটা পুনরায় সেট কার্য সম্পাদনার দ্বারা কোনো রকম সতর্কতা ছাড়াই ফোনের ডেটা মোছে৷"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ব্যবহারকারীর ডেটা মুছুন"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"সতর্কীকরণ ছাড়াই এই ট্যাবলেটে থাকা ব্যাবহারকার্রী ডেটা মুছে ফেলে৷"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"সতর্কীকরণ ছাড়াই এই টিভিতে থাকা ব্যাবহারকার্রী ডেটা মুছে ফেলে৷"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"সতর্কীকরণ ছাড়াই এই ফোনে থাকা ব্যাবহারকার্রী ডেটা মুছে ফেলে৷"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ডিভাইসের বৈশ্বিক প্রক্সী সেট করে"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"যখন নীতি সক্ষম করা হয় তখন ডিভাইসের বৈশ্বিক প্রক্সী ব্যবহার করা হবে সেই হিসাবে সেট করে৷ শুধুমাত্র প্রথম ডিভাইস প্রশাসক কার্যকর বৈশ্বিক প্রক্সী সেট করে৷"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"লক-স্ক্রীণ পাসওয়ার্ডের মেয়াদ শেষ হওয়ার সময়কাল সেট করে"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"স্ক্রীন লক করার পাসওয়ার্ড কত ঘন ঘন পরিবর্তন করা আবশ্যক তা নিয়ন্ত্রণ করে৷"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"নীতিযখন নীতি সক্ষম করা হয় তখন ডিভাইসের বৈশ্বিক প্রক্সী ব্যবহার করা হবে সেই হিসাবে সেট করে৷ শুধুমাত্র ডিভাইসের মালিক বৈশ্বিক প্রক্সী সেট করতে পারেন৷"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"স্ক্রীন লক করার জন্য পাসওয়ার্ডের মেয়াদ শেষ হওয়ার সময় সেট করে"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"স্ক্রীন লক করার পাসওয়ার্ড কত ঘন ঘন পরিবর্তন করা আবশ্যক তা পরিবর্তন করুন৷"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"সঞ্চয়স্থানের এনক্রিপশান সেট করে"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"এই সঞ্চিত অ্যাপ্লিকেশান ডেটা এনক্রিপ্ট করা দরকার৷"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ক্যামেরাগুলি অক্ষম করে"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"সমস্ত ডিভাইসের ক্যামেরার ব্যবহার আটকায়৷"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"কীগার্ডে বৈশিষ্ট্যগুলি নিষ্ক্রিয় করুন"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"কীগার্ডে কিছু বৈশিষ্ট্যের ব্যবহার আটকায়৷"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"স্ক্রীন লকের বৈশিষ্ট্য নিষ্ক্রিয় করুন"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"স্ক্রীন লকের কিছু বৈশিষ্ট্যের ব্যবহার আটকায়৷"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"হোম"</item>
     <item msgid="869923650527136615">"মোবাইল"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' সক্ষম করতে চাইছে৷ যখন \'স্পর্শের মাধ্যমে অন্বেষণ করুন\' চালু করা হবে তখন আপনার আঙ্গুলের নিয়ন্ত্রণে থাকা জিনিসের বর্ণনাগুলি শুনতে অথবা দেখতে পাবেন অথবা ফোনের সাথে ইন্টারঅ্যাক্ট করার জন্য অঙ্গভঙ্গির সাহায্য নিতে পারবেন৷"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"১ মাস আগে"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"১ মাস আগে"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"১ সেকেন্ড আগে"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"১ মিনিট আগে"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"১ ঘন্টা আগে"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"গত <xliff:g id="COUNT">%d</xliff:g> দিনে"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">বিগত <xliff:g id="COUNT_1">%d</xliff:g> দিন</item>
+      <item quantity="other">বিগত <xliff:g id="COUNT_1">%d</xliff:g> দিন</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"গত মাস"</string>
     <string name="older" msgid="5211975022815554840">"পুরোনো"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"গতকাল"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"১ সেকেন্ডের মধ্যে"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"১ মিনিটের মধ্যে"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"১ ঘন্টার মধ্যে"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"আগামীকাল"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"১ সেকেন্ড আগে"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"১ মিনিট আগে"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> মিনিট আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"১ ঘন্টা আগে"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা আগে"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"গতকাল"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> দিন আগে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"১ সেকেন্ডের মধ্যে"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"১ মিনিটের মধ্যে"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> মিনিটের মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"১ ঘন্টার মধ্যে"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টার মধ্যে"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"আগামীকাল"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> দিনের মধ্যে"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> এ"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> এ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> এ"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"সপ্তাহ"</string>
     <string name="year" msgid="4001118221013892076">"বছর"</string>
     <string name="years" msgid="6881577717993213522">"বছর"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"১ সেকেন্ড"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ড"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"১ মিনিট"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> মিনিট"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"১ ঘন্টা"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ঘন্টা"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ড</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ড</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> মিনিট</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> মিনিট</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ঘন্টা</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ঘন্টা</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ভিডিও সমস্যা"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"এই ভিডিওটি এই ডিভাইসে স্ট্রিমিং করার জন্য বৈধ নয়৷"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"এই ভিডিওটি চালানো যাবে না৷"</string>
@@ -1257,7 +1210,7 @@
     <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
     <string name="yes" msgid="5362982303337969312">"ঠিক আছে"</string>
     <string name="no" msgid="5141531044935541497">"বাতিল করুন"</string>
-    <string name="dialog_alert_title" msgid="2049658708609043103">"মনোযোগ"</string>
+    <string name="dialog_alert_title" msgid="2049658708609043103">"খেয়াল করুন"</string>
     <string name="loading" msgid="7933681260296021180">"লোড হচ্ছে..."</string>
     <string name="capital_on" msgid="1544682755514494298">"চালু করুন"</string>
     <string name="capital_off" msgid="6815870386972805832">"বন্ধ করুন"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android চালু হচ্ছে…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"সঞ্চয়স্থান অপ্টিমাইজ করা হচ্ছে৷"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>টির মধ্যে <xliff:g id="NUMBER_0">%1$d</xliff:g>টি অ্যাপ্লিকেশান অপ্টিমাইজ করা হচ্ছে৷"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> প্রস্তুত করা হচ্ছে৷"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"অ্যাপ্লিকেশানগুলি শুরু করা হচ্ছে৷"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"চালু করা সম্পূর্ণ হচ্ছে৷"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> চলছে"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"নতুন অ্যাপ্লিকেশান চালু করবেন না৷"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> শুরু করুন"</string>
     <string name="new_app_description" msgid="1932143598371537340">"সংরক্ষণ না করেই পুরোনো অ্যাপ্লিকেশানটি বন্ধ করুন৷"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"পাঠ্যের জন্য একটি কাজ বেছে নিন"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"রিং ভলিউম"</string>
     <string name="volume_music" msgid="5421651157138628171">"মিডিয়ার ভলিউম"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"কোনো কিছুই নয়"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"রিংটোনগুলি"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"অজানা রিংটোন"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi নেটওয়ার্ক উপলব্ধ রয়েছে"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi নেটওয়ার্ক উপলব্ধ রয়েছে"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"খোলা Wi-Fi নেটওয়ার্ক উপলব্ধ রয়েছে"</item>
-    <item quantity="other" msgid="7915895323644292768">"খোলা Wi-Fi নেটওয়ার্ক উপলব্ধ রয়েছে"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Wi-Fi নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+      <item quantity="other">Wi-Fi নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">খোলা Wi-Fi নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+      <item quantity="other">খোলা Wi-Fi নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi নেটওয়ার্কে সাইন ইন করুন"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"নেটওয়ার্কে সাইন ইন করুন"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi এর সাথে সংযোগ করা যায়নি"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" একটি দুর্বল ইন্টারনেট সংযোগ রয়েছে৷"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের মঞ্জুরি দেবেন?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"অ্যাপ্লিকেশান %1$s Wifi নেটওয়ার্ক %2$s এর সাথে সংযোগ করতে চায়"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"একটি অ্যাপ্লিকেশান"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ডাইরেক্ট"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ডাইরেক্ট আরম্ভ করুন৷ এটি Wi-Fi client/hotspot কে বন্ধ করবে৷"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi ডাইরেক্ট শুরু করা যায়নি৷"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ঠিক আছে"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"একটি মিডিয়া ডিভাইস হিসাবে সংযুক্ত হয়েছে"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"একটি ক্যামেরা হিসাবে সংযুক্ত"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"একটি MIDI ডিভাইস হিসাবে সংযুক্ত করা হয়েছে"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"একটি ইনস্টলার হিসাবে সংযুক্ত হয়েছে"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"একটি USB যন্ত্রাংশতে সংযুক্ত হয়েছে"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"অন্যন্য USB বিকল্পের জন্য স্পর্শ করুন৷"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"এড়িয়ে যান"</string>
     <string name="no_matches" msgid="8129421908915840737">"কোনো মিল নেই"</string>
     <string name="find_on_page" msgid="1946799233822820384">"পৃষ্ঠায় খুঁজুন"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"১টি সমরূপ"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>টির মধ্যে <xliff:g id="INDEX">%d</xliff:g> নম্বর"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g>টির <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>টির <xliff:g id="INDEX">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"সম্পন্ন হয়েছে"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB সংগ্রহস্থল আনমাউন্ট করা হচ্ছে…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD কার্ড আনমাউন্ট করা হচ্ছে…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"নিষেধাজ্ঞাগুলি পরিবর্তন করার জন্য একটি PIN তৈরি করুন"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINগুলি মেলেনি৷ আবার চেষ্টা করুন৷"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN খুবই ছোট৷ এটিকে কমপক্ষে ৪ সংখ্যার হতে হবে৷"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"১ সেকেন্ডের মধ্যে আবার চেষ্টা করুন"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"পরে আবার চেষ্টা করুন"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"পূর্ণস্ক্রীণ থেকে প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন৷"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"পূর্ণ স্ক্রীণে দেখা হচ্ছে"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"প্রস্থান করতে উপর থেকে নীচের দিকে সোয়াইপ করুন"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"বুঝেছি"</string>
     <string name="done_label" msgid="2093726099505892398">"সম্পন্ন হয়েছে"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"বৃত্তাকার ঘন্টা নির্বাচকের স্লাইডার"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' এবং \'এক নজরে\' একসাথে স্পর্শ করুন এবং ধরে রাখুন৷"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"এই স্ক্রীনটিকে আনপিন করতে, \'এক নজরে\' স্পর্শ করুন এবং ধরে রাখুন৷"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"স্ক্রীন পিন করা আছে। আপনার প্রতিষ্ঠান এটিকে পিনমুক্ত করার অনুমতি দেয়নি।"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"স্ক্রীন পিন করা হয়েছে"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"পিন না করা স্ক্রীন"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে PIN চান"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ব্যাটরির লাইফ উন্নত করতে সহায়তা করতে, ব্যাটারি সাশ্রয়কারী আপনার ডিভাইসের কার্যসম্পাদনা হ্রাস করে এবং কম্পন, অবস্থান পরিষেবাসমূহ এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে৷ ইমেল, বার্তাপ্রেরণ এবং অন্যান্য অ্যাপ্লিকেশানগুলিকে যেগুলি সিঙ্কের উপর নির্ভর করে সেগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে৷\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সাশ্রয়কারী স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়৷"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>টার সময়ে আপনার ডাউনটাইম শেষ হওয়া পর্যন্ত"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"আপনার ডাউনটাইম শেষ না হওয়া পর্যন্ত"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"এক মিনিটের জন্য (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> পর্যন্ত)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> পর্যন্ত)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"এক ঘন্টার জন্য (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> পর্যন্ত)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d ঘন্টার জন্য (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> পর্যন্ত)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"এক মিনিটের জন্য"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d মিনিটের জন্য"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"এক ঘন্টার জন্য"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d ঘন্টার জন্য"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
+      <item quantity="other">%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d ঘন্টার জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
+      <item quantity="other">%1$d ঘন্টার জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d মিনিটের জন্য</item>
+      <item quantity="other">%d মিনিটের জন্য</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d ঘন্টার জন্য</item>
+      <item quantity="other">%d ঘন্টার জন্য</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পর্যন্ত"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"অনির্দিষ্টভাবে"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"আপনার দ্বারা এটি বন্ধ করা পর্যন্ত"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"সঙ্কুচিত করুন"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> এ পরবর্তী অ্যালার্ম পর্যন্ত"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"পরবর্তী অ্যালার্ম পর্যন্ত"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS অনুরোধটিকে ডায়াল অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS অনুরোধটিকে নতুন USSD অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS অনুরোধটিকে নতুন SS অনুরোধে রুপান্তরিত করা হয়েছে৷"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB পেরিফেরাল পোর্ট"</string>
 </resources>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
index 13f623b..db2d1ec 100755
--- a/core/res/res/values-ca/donottranslate-cldr.xml
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B de %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 30ce0d7..8884cae 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sense títol&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Sense número de telèfon)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Desconegut"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correu de veu"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"La targeta SIM està bloquejada pel PUK. Escriviu el codi PUK per desbloquejar-la."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Escriviu el PUK2 per desbloquejar la targeta SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"No és correcte; activa el bloqueig de RUIM/SIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Et queda <xliff:g id="NUMBER">%d</xliff:g> intent; si no l\'encertes, la SIM es bloquejarà."</item>
-    <item quantity="other" msgid="7530597808358774740">"Et queden <xliff:g id="NUMBER">%d</xliff:g> intents; si no l\'encertes, la SIM es bloquejarà."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM es bloquejarà.</item>
+      <item quantity="one">Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM es bloquejarà.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Identificació de trucada entrant"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode d\'avió activat"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode d\'avió desactivat"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuració"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. per veu"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"establir vincles amb un servei d\'aprovisionament de rutes"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet que el titular estableixi vincles amb els proveïdors de rutes registrats. No hauria de ser mai necessari per a les aplicacions normals."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"Vinculació a una entrada de televisor"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet que l\'aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivació del bloqueig de pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada telefònica entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gestionar el maquinari d\'empremtes digitals"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet que l\'aplicació invoqui mètodes per afegir i suprimir plantilles d\'empremtes digitals que es puguin fer servir."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilitzar el maquinari d\'empremtes digitals"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet que l\'aplicació faci servir maquinari d\'empremtes digitals per a l\'autenticació"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"llegir la configuració de sincronització"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Persones estigui sincronitzada amb un compte."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar o desactivar la sincronització"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei oient de notificacions"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei oient de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular-se a un servei de destí de selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet que el propietari la pugui vincular a la interfície principal d\'un servei de destí de selector. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enllaçar amb el servei de proveïdor de condicions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet enllaçar amb la interfície de nivell superior d\'un servei de proveïdor de condicions. No ha de ser mai necessari per a aplicacions normals."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular-se amb un servei de rutes multimèdia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permet que el titular es vinculi amb la interfície de nivell superior d\'un servei de rutes multimèdia. No ha de ser mai necessari per a aplicacions normals."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"enllaçar amb un servei en repòs"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permet enllaçar amb la interfície de nivell superior d\'un servei en repòs. No hauria de ser mai necessari per a aplicacions normals."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular-la al servei de missatgeria d\'un operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet que el propietari la pugui vincular a la interfície principal del servei de missatgeria d\'un operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Permet controlar la longitud i el nombre de caràcters permesos a les contrasenyes i als PIN del bloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar els intents de desbloqueig de pantalla"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Supervisa el nombre de contrasenyes incorrectes introduïdes per desbloquejar la pantalla i bloqueja la tauleta o n\'esborra totes les dades si s\'introdueixen massa contrasenyes incorrectes."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja el televisor o n\'esborra totes les dades si s\'escriuen massa contrasenyes incorrectes."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Supervisa el nombre de contrasenyes incorrectes introduïdes en desbloquejar la pantalla, i bloqueja el telèfon o esborra totes les dades del telèfon si s\'introdueixen massa contrasenyes incorrectes."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Canvia la contrasenya de desbloqueig de pantalla"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Canvia la contrasenya de desbloqueig de pantalla."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja la tauleta o n\'esborra totes les dades de l\'usuari si s\'escriuen massa contrasenyes incorrectes."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja el televisor o n\'esborra totes les dades de l\'usuari si s\'escriuen massa contrasenyes incorrectes."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Fa un seguiment del nombre de contrasenyes incorrectes que s\'han escrit en intentar desbloquejar la pantalla i bloqueja el telèfon o n\'esborra totes les dades de l\'usuari si s\'escriuen massa contrasenyes incorrectes."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Canviar el bloqueig de pantalla"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Permet canviar el bloqueig de pantalla."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloqueig de pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controla com i quan es bloqueja la pantalla."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Esborrar totes les dades"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Esborra les dades de la tauleta sense advertiment mitjançant un restabliment de les dades de fàbrica."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Esborra les dades del televisor sense advertiment mitjançant un restabliment de les dades de fàbrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Esborra les dades del telèfon sense avisar, restablint les dades de fàbrica."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Esborrar les dades de l\'usuari"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Esborra les dades de l\'usuari desades a la tauleta sense avisar-ne."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Esborra les dades de l\'usuari desades al televisor sense avisar-ne."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Esborra les dades de l\'usuari desades al telèfon sense avisar-ne."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor intermediari global del dispositiu"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Defineix el servidor intermediari global del dispositiu que cal utilitzar mentre la política estigui activada. Només el primer administrador del dispositiu pot definir el servidor intermediari global efectiu."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducitat de bloqueig de pantalla"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controla la freqüència amb què cal canviar la contrasenya de bloqueig de pantalla."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Si la política s\'activa, s\'utilitza el servidor intermediari global del dispositiu. Només el propietari del dispositiu el pot establir."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Definir caducitat bloqueig"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Permet canviar la freqüència amb què cal canviar la contrasenya, el PIN o el patró del bloqueig de pantalla."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptació d’emmagatzematge"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desactivar les càmeres"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedeix l\'ús de les càmeres del dispositiu."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Desactivar les funcions en bloqueig"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Impedeix l\'ús d\'algunes funcions en bloqueig de tecles."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desactivar funcions bloqueig"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Impedeix l\'ús d\'algunes funcions del bloqueig de pantalla."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Mòbil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vol activar l\'exploració tàctil. Quan l\'exploració per tàctil està activada, pots escoltar o veure les descripcions del contingut seleccionat o utilitzar gestos per interactuar amb el telèfon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Fa 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fa més d\'1 mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Fa 1 segon"</item>
-    <item quantity="other" msgid="3903706804349556379">"Fa <xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Fa 1 minut"</item>
-    <item quantity="other" msgid="2176942008915455116">"Fa <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Fa 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Els darrers <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Darrers <xliff:g id="COUNT_1">%d</xliff:g> dies</item>
+      <item quantity="one">Darrer dia (<xliff:g id="COUNT_0">%d</xliff:g>)</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"El mes passat"</string>
     <string name="older" msgid="5211975022815554840">"Més antigues"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Ahir"</item>
-    <item quantity="other" msgid="2479586466153314633">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"d\'aquí a 1 segon"</item>
-    <item quantity="other" msgid="1241926116443974687">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"d\'aquí a 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"d\'aquí a 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demà"</item>
-    <item quantity="other" msgid="5109449375100953247">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Fa 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"Fa <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"fa 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Fa <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Fa 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"Fa <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ahir"</item>
-    <item quantity="other" msgid="3453342639616481191">"Fa <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"d\'aquí a 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"d\'aquí a 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"d\'aquí a 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demà"</item>
-    <item quantity="other" msgid="2973062968038355991">"d\'aquí a <xliff:g id="COUNT">%d</xliff:g> dies"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a les <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"el <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"setmanes"</string>
     <string name="year" msgid="4001118221013892076">"any"</string>
     <string name="years" msgid="6881577717993213522">"anys"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segon"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuts"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hores"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segons</item>
+      <item quantity="one">1 segon</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuts</item>
+      <item quantity="one">1 minut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> hores</item>
+      <item quantity="one">1 hora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problema amb el vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Aquest vídeo no és vàlid per a la reproducció en aquest dispositiu."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No es pot reproduir aquest vídeo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"S\'està iniciant Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"S\'està optimitzant l\'emmagatzematge."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"S\'està optimitzant l\'aplicació <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"S\'està preparant <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"S\'estan iniciant les aplicacions."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"S\'està finalitzant l\'actualització."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciïs l\'aplicació nova."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Inicia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Atura l\'aplicació antiga sense desar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Tria una acció per al text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Cap"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sons"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"To desconegut"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Xarxa Wi-fi disponible"</item>
-    <item quantity="other" msgid="4192424489168397386">"Xarxes Wi-fi disponibles"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Xarxa Wi-fi oberta disponible"</item>
-    <item quantity="other" msgid="7915895323644292768">"Xarxes Wi-fi obertes disponibles"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Xarxes Wi-Fi disponibles</item>
+      <item quantity="one">Xarxa Wi-Fi disponible</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Xarxes Wi-Fi obertes disponibles</item>
+      <item quantity="one">Xarxa Wi-Fi oberta disponible</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Inicia la sessió a la xarxa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Inicia la sessió a la xarxa"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'aplicació %1$s vol connectar-se a la xarxa Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicació"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/la zona Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No s\'ha pogut iniciar Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connectat com a disp. multimèdia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connectat com a càmera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connectat com a dispositiu MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connectat com a instal·lador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connectat a un accessori USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toca per accedir a altres opcions d\'USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Omet"</string>
     <string name="no_matches" msgid="8129421908915840737">"Cap coincidència"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Troba-ho a la pàgina"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 coincidència"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 partida</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Fet"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"S\'està desactivant l\'emmagatzematge USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"S\'està desactivant la targeta SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un pin per modificar les restriccions"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Els PIN no coincideixen. Torna-ho a provar."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN és massa curt. Ha de tenir quatre dígits com a mínim."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Torna-ho a provar d\'aquí a 1 segon"</item>
-    <item quantity="other" msgid="4730868920742952817">"Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Torna-ho a provar d\'aquí a <xliff:g id="COUNT">%d</xliff:g> segons</item>
+      <item quantity="one">Torna-ho a provar d\'aquí a 1 segon</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Torna-ho a provar més tard"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Fes lliscar el dit cap avall per sortir de la pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualització en pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Per sortir, fes lliscar el dit cap avall des de la part superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"D\'acord"</string>
     <string name="done_label" msgid="2093726099505892398">"Fet"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control circular de les hores"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control circular dels minuts"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per anul·lar la fixació d\'aquesta pantalla, mantén premudes les opcions Enrere i Visió general alhora."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per anul·lar la fixació d\'aquesta pantalla, mantén premuda l\'opció Visió general."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"S\'ha fixat la pantalla. La teva organització no permet anul·lar-ne la fixació."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixació de la pantalla anul·lada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demana el codi PIN abans d\'anul·lar la fixació"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Per allargar la durada de la bateria, l\'estalvi de bateria redueix el rendiment del dispositiu i limita l\'ús de la vibració, dels serveis d\'ubicació i de la majoria de les dades en segon pla. És possible que el correu electrònic, la missatgeria i altres aplicacions que depenen de la sincronització no s\'actualitzin fins que els obris.\n\nL\'estalvi de bateria es desactiva de manera automàtica quan el dispositiu es posa a carregar."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Fins que no finalitzi la inactivitat a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>."</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Fins que finalitzi el temps d\'inactivitat"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Durant 1 minut (fins a les <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Durant 1 hora (fins a les <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Durant %1$d hores (fins a les <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Durant un minut"</item>
-    <item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Durant una hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Durant %d hores"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durant 1 minut (fins a les <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Durant %1$d hores (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durant 1 hora (fins a les <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Durant %d minuts</item>
+      <item quantity="one">Durant un minut</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Durant %d hores</item>
+      <item quantity="one">Durant 1 hora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidament"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Replega"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fins que soni l\'alarma següent a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fins que soni l\'alarma següent"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La sol·licitud SS s\'ha transformat en una sol·licitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La sol·licitud SS s\'ha transformat en una sol·licitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La sol·licitud SS s\'ha transformat en una sol·licitud SS nova."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port perifèric USB"</string>
 </resources>
diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-cs/donottranslate-cldr.xml
+++ b/core/res/res/values-cs/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 94a23a8..1a023578 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Bez názvu&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(žádné telefonní číslo)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Není známo"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Hlasová schránka"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"SIM karta je blokována pomocí kódu PUK. Odblokujete ji zadáním kódu PUK."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Chcete-li odblokovat SIM kartu, zadejte kód PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"Operace nebyla úspěšná, povolte zámek SIM/RUIM karty."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Máte ještě <xliff:g id="NUMBER">%d</xliff:g> pokus. Poté bude SIM karta uzamčena."</item>
-    <item quantity="other" msgid="7530597808358774740">"Počet zbývajících pokusů, po jejichž vyčerpání bude SIM karta uzamčena: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="few">Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy. Poté bude SIM karta uzamčena.</item>
+      <item quantity="many">Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusu. Poté bude SIM karta uzamčena.</item>
+      <item quantity="other">Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusů. Poté bude SIM karta uzamčena.</item>
+      <item quantity="one">Máte ještě <xliff:g id="NUMBER_0">%d</xliff:g> pokus. Poté bude SIM karta uzamčena.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Příchozí identifikace volajícího"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim Letadlo je ZAPNUTÝ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim Letadlo je VYPNUTÝ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
@@ -431,6 +432,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"navázání na službu poskytovatele tras"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteli navázat se na libovolného poskytovatele registrovaných tras. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"navázání na televizní vstup"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikaci komunikovat se štítky, kartami a čtečkami s podporou technologie NFC."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"vypnutí zámku obrazovky"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Umožňuje aplikaci vypnout zámek kláves a související zabezpečení heslem. Telefon například vypne zámek klávesnice při příchozím hovoru a po skončení hovoru jej zase zapne."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"správa hardwaru na čtení otisků prstů"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Umožňuje aplikaci volat metody k přidání a smazání šablon otisků prstů, které budou použity."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"použití hardwaru na čtení otisků prstů"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Umožňuje aplikaci použít k ověření hardware na čtení otisků prstů"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čtení nastavení synchronizace"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikaci číst nastavení synchronizace v účtu. Může například určit, zda je s účtem synchronizována aplikace Lidé."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"vypnutí nebo zapnutí synchronizace"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"navázat se na cílovou službu nástroje pro výběr"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteli navázat se na rozhraní nejvyšší úrovně cílové služby nástroje pro výběr. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"navázání na službu poskytovatele podmínky"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby poskytovatele podmínky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"navázání na službu směrování médií"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby směrování médií. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"navázat se na službu spořiče"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Umožňuje navázání na nejvyšší úroveň služby spořiče. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"navázat se na nejvyšší úroveň rozhraní služby zasílání zpráv prostřednictvím operátora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby zasílání zpráv prostřednictvím operátora. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ovládání délky a znaků povolených v heslech a kódech PIN zámku obrazovky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout tablet nebo vymazat z tabletu všechna data, pokud bylo zadáno příliš mnoho nesprávných hesel."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Umožňuje monitorovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout televizi nebo vymazat veškerá data v televizi, pokud je zadáno příliš mnoho nesprávných hesel."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout telefon nebo vymazat z telefonu všechna data, pokud bylo zadáno příliš mnoho nesprávných hesel."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Změnit heslo pro odemknutí obrazovky"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Změnit heslo pro odemknutí obrazovky."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout tablet nebo vymazat veškerá data uživatele."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout televizi nebo vymazat veškerá data uživatele."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout telefon nebo vymazat veškerá data uživatele."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Změnit zámek obrazovky"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Změnit zámek obrazovky."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Uzamknout obrazovku"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Řídit, jak a kdy se obrazovka uzamkne."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Vymazat všechna data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Bez upozornění smazat všechna data tabletu obnovením továrních dat."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Umožňuje provést obnovení továrních dat a bez varování tím vymazat data v televizi."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Bez upozornění smazat všechna data telefonu obnovením továrních dat."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Vymazat data uživatele"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Vymazat data tohoto uživatele v tomto tabletu bez upozornění."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Vymazat data tohoto uživatele v této televizi bez upozornění."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Vymazat data tohoto uživatele v tomto telefonu bez upozornění."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavit globální proxy server zařízení"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit vypršení hesla zámku"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Určuje, jak často je třeba měnit heslo pro uzamčení obrazovky."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Nastaví globální proxy server, který bude používán, když je zásada zapnuta. Globální proxy server může nastavit pouze vlastník zařízení."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Nastavit vypršení hesla zámku obrazovky"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Mění, jak často je potřeba měnit heslo, PIN nebo gesto zámku obrazovky."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavit šifrování úložiště"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Požadovat šifrování uložených dat aplikací."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Vypnout fotoaparáty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zakázat používání všech fotoaparátů zařízení."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Zakázat funkce v zámku zařízení"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Zabránit používání některých funkcí v zámku zařízení."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Zakázat funkce zámku obrazovky"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Zabránit použití některých funkcí zámku obrazovky."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domů"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolení funkce Prozkoumání dotykem. Pokud je funkce Prozkoumání dotykem zapnuta, můžete slyšet nebo vidět popisy objektů pod vaším prstem nebo ovládat telefon gesty."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"před 1 měsícem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Déle než před 1 měsícem"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"před 1 sekundou"</item>
-    <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"před 1 min"</item>
-    <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"před 1 h"</item>
-    <item quantity="other" msgid="2467273239587587569">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posledních <xliff:g id="COUNT">%d</xliff:g> dnů"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="few">Poslední <xliff:g id="COUNT_1">%d</xliff:g> dny</item>
+      <item quantity="many">Posledních <xliff:g id="COUNT_1">%d</xliff:g> dne</item>
+      <item quantity="other">Posledních <xliff:g id="COUNT_1">%d</xliff:g> dnů</item>
+      <item quantity="one">Poslední <xliff:g id="COUNT_0">%d</xliff:g> den</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Poslední měsíc"</string>
     <string name="older" msgid="5211975022815554840">"Starší"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včera"</item>
-    <item quantity="other" msgid="2479586466153314633">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
-    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za 1 hodinu"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"zítra"</item>
-    <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"před 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"před 1 h"</item>
-    <item quantity="other" msgid="6889970745748538901">"před <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včera"</item>
-    <item quantity="other" msgid="3453342639616481191">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za 1 hodinu"</item>
-    <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"zítra"</item>
-    <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dne <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"v <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"roku <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"týd."</string>
     <string name="year" msgid="4001118221013892076">"rokem"</string>
     <string name="years" msgid="6881577717993213522">"lety"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekunda"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuta"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hodina"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekund</item>
+      <item quantity="one">1 sekunda</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minuty</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> minuty</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minut</item>
+      <item quantity="one">1 minuta</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="few">[<xliff:g id="COUNT">%d</xliff:g>] hodiny</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> hodiny</item>
+      <item quantity="other">[<xliff:g id="COUNT">%d</xliff:g>] hodin</item>
+      <item quantity="one">1 hodina</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Potíže s videem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Toto video nelze přenášet datovým proudem do tohoto zařízení."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nelze přehrát."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Spouštění systému Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Probíhá optimalizace úložiště."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimalizování aplikace <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Příprava aplikace <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Spouštění aplikací."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončování inicializace."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nespouštět novou aplikaci."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Spustit aplikaci <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zastavit starou aplikaci bez uložení."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Vyberte akci pro text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitost vyzvánění"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hlasitost médií"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Žádné"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámý vyzváněcí tón"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"K dispozici je síť Wi-Fi."</item>
-    <item quantity="other" msgid="4192424489168397386">"Jsou k dispozici sítě Wi-Fi."</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"K dispozici je veřejná síť Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"Jsou k dispozici veřejné sítě Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="few">K dispozici jsou sítě Wi-Fi</item>
+      <item quantity="many">K dispozici jsou sítě Wi-Fi</item>
+      <item quantity="other">K dispozici jsou sítě Wi-Fi</item>
+      <item quantity="one">K dispozici je síť Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="few">K dispozici jsou veřejné sítě Wi-Fi</item>
+      <item quantity="many">K dispozici jsou veřejné sítě Wi-Fi</item>
+      <item quantity="other">K dispozici jsou veřejné sítě Wi-Fi</item>
+      <item quantity="one">K dispozici je veřejná síť Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Přihlásit se k síti Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Přihlášení k síti"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikace %1$s se chce připojit k síti Wi-Fi %2$s."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikace"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit přímé připojení sítě Wi-Fi. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Přímé připojení sítě Wi-Fi se nepodařilo spustit."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Připojeno jako mediální zařízení"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Připojeno jako fotoaparát"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Připojeno jako zařízení MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Připojeno jako instalátor"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Připojeno k perifernímu zařízení USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Dotykem zobrazíte další možnosti rozhraní USB."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Přeskočit"</string>
     <string name="no_matches" msgid="8129421908915840737">"Žádné shody"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Hledat na stránce"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 shoda"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> ze <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 shoda</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Hotovo"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Odpojování úložiště USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Odpojování karty SD..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvořit kód PIN pro úpravy omezení"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN se neshodují. Zkuste to znovu."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je příliš krátký. Musí mít alespoň čtyři číslice."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Zkuste to znovu za 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="few">Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many">Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="other">Zkuste to znovu za <xliff:g id="COUNT">%d</xliff:g> sekund</item>
+      <item quantity="one">Zkuste to znovu za 1 sekundu</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Zkuste to znovu později"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celé obrazovky ukončíte přejetím dolů."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazení celé obrazovky"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Režim ukončíte přejetím prstem shora dolů."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumím"</string>
     <string name="done_label" msgid="2093726099505892398">"Hotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posuvník hodin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posuvník minut"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Chcete-li tuto obrazovku uvolnit, klepněte současně na možnosti Zpět a Přehled a podržte je."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Chcete-li tuto obrazovku uvolnit, klepněte na možnost Přehled a podržte ji."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je připnuta. Vaše organizace uvolnění zakázala."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka uvolněna"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o kód PIN"</string>
@@ -1843,25 +1830,33 @@
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Před uvolněním požádat o heslo"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dokud v <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> neskončí pozastavení"</string>
-    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Dokud neskončí výpadek"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Jednu minutu (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d min (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Jednu hodinu (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d h (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item>
-    <item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Na 1 h"</item>
-    <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
-  </plurals>
+    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Dokud neskončí pozastavení"</string>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="few">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Jednu minutu (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="few">%1$d hodiny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d hodiny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d hodin (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Jednu hodinu (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="few">%d minuty</item>
+      <item quantity="many">%d minuty</item>
+      <item quantity="other">%d minut</item>
+      <item quantity="one">Jednu minutu</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="few">%d hodiny</item>
+      <item quantity="many">%d hodiny</item>
+      <item quantity="other">%d hodin</item>
+      <item quantity="one">Jednu hodinu</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Na dobu neurčitou"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sbalit"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do dalšího budíku v <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do příštího budíku"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Požadavek SS byl změněn na požadavek DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Požadavek SS byl změněn na požadavek USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Požadavek SS byl změněn na nový požadavek SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB pro periferní zařízení"</string>
 </resources>
diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml
index 4c7a781..af35257 100755
--- a/core/res/res/values-da/donottranslate-cldr.xml
+++ b/core/res/res/values-da/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a320cd4..07a588a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Uden titel&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Intet telefonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Ukendt"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Telefonsvarer"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
     <string name="enablePin" msgid="209412020907207950">"Mislykkedes. Aktivér SIM-/RUIM-lås."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver låst."</item>
-    <item quantity="other" msgid="7530597808358774740">"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver låst."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver låst.</item>
+      <item quantity="other">Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver låst.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI-nummer"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Indgående opkalds-id"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"oprette tilknytning til en ruteudbydertjeneste"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillader, at indehaveren opretter tilknytninger til registrerede ruteudbydere. Dette bør aldrig være nødvendigt for normale apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"knyt til en tv-indgang"</string>
@@ -703,7 +704,7 @@
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Tillader, at appen kan læse oplysninger om Wi-Fi-netværk, f.eks. hvorvidt Wi-Fi er aktiveret og navnet på forbundne Wi-Fi-enheder."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"oprette og afbryde Wi-Fi-forbindelse"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Tillader, at appen kan oprette og afbryde forbindelsen fra Wi-Fi-adgangspunkter og foretage ændringer i enhedskonfigurationen for Wi-Fi-netværk."</string>
-    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillad Wi-Fi-multicastmodtagelse"</string>
+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillade Wi-Fi-multicastmodtagelse"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Tillader, at appen kan modtage pakker, der sendes til alle enheder på et Wi-Fi-netværk ved hjælp af multicastadresser, ikke kun din tablet. Den bruger mere strøm end tilstanden, der ikke anvender multicast."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Giver appen lov til at modtage pakker, der sendes til alle enheder og ikke bare dit tv på et Wi-Fi-netværk ved hjælp af multicast-adresser. Dette bruger mere strøm end tilstanden uden multicast."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Tillader, at appen kan modtage pakker, der sendes til alle enheder på et Wi-Fi-netværk ved hjælp af multicastadresser, ikke kun din telefon. Den bruger mere strøm end tilstanden, der ikke anvender multicast."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Tillader, at appen kan kommunikere med NFC-tags (Near Field Communication), -kort og -læsere."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivere din skærmlås"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Tillader, at appen kan deaktivere tastaturlåsen og anden form for tilknyttet adgangskodesikkerhed. Telefonen deaktiverer f.eks. tastaturlåsen ved indgående telefonopkald og aktiverer tastaturlåsen igen, når opkaldet er afsluttet."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"administrer fingeraftrykhardware"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Tillader, at appen kan køre metoder til at tilføje og slette fingeraftryksskabeloner"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"brug fingeraftrykhardware"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Tillader, at appen kan bruge fingeraftrykhardware til godkendelse"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"læse indstillinger for synkronisering"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Tillader, at appen kan læse synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. fastslå, om appen Personer er synkroniseret med en konto."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"slå synkronisering til og fra"</string>
@@ -781,7 +786,7 @@
     <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Tillader, at appen kan interagere med telefonitjenester for at foretage/modtage opkald."</string>
     <string name="permlab_control_incall_experience" msgid="9061024437607777619">"leverer brugeroplevelsen under opkald"</string>
     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Tillader, at appen leverer brugeroplevelsen under opkald."</string>
-    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse oversigt over netværksbrug"</string>
+    <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"læse historisk netværksbrug"</string>
     <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Tillader, at appen kan læse historisk netværksbrug for specifikke netværk og apps."</string>
     <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"administrer netværkspolitik"</string>
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"knytte sig til en tjeneste til valg af mål"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Tillader, at appen kan knytte sig til det øverste grænsefladeniveau for en tjeneste til valg af mål. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"opret binding til en medierutetjeneste"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en medierutetjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"fastlås til en drømmetjeneste"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Tillader, at indehaveren fastlåser det øverste niveau af brugergrænsefladen for en drømmetjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"knytte til et mobilselskabs beskedtjeneste"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dette giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for et mobilselskabs beskedtjeneste. Dette bør ikke være nødvendigt i normale apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Overvåg antallet af forkert indtastede adgangskoder, når du låser skærmen op, og lås din tablet, eller slet alle data i den, hvis der er indtastet for mange forkerte adgangskoder."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Overvåg antallet af forkert indtastede adgangskoder ved oplåsning af skærmen, og lås tv\'et eller slet alle dets data, hvis der indtastes for mange forkerte adgangskoder."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Overvåg antallet af forkerte adgangskoder ved oplåsning af skærmen, og lås telefonen eller slet alle data på telefonen, hvis der er indtastet for mange forkerte adgangskoder."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Skifte adgangskode til oplåsning af skærm"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Skifter adgangskode til oplåsning af skærmen."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Registrer antallet af forkerte adgangskoder, der indtastes ved oplåsning af skærmen, og lås din tablet, eller slet alle brugerens data, hvis adgangskoden tastes forkert for mange gange."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Registrer antallet af forkerte adgangskoder, der indtastes ved oplåsning af skærmen, og lås tv-adgangen, eller slet alle brugerens data, hvis adgangskoden tastes forkert for mange gange."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Registrer antallet af forkerte adgangskoder, der indtastes ved oplåsning af skærmen, og lås telefonen, eller slet alle brugerens data, hvis adgangskoden tastes forkert for mange gange."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Skift skærmlås"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Skift skærmlås."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Låse skærmen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrollerer, hvordan og hvornår skærmen låses."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Slette alle data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Slet din tablets data uden varsel ved at gendanne fabriksindstillingerne."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Slet tv\'ets data uden varsel ved at nulstille til fabrinksindstillingerne."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Sletter telefonens data uden varsel ved at gendanne fabriksindstillingerne."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Slet brugerdata"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Slet denne brugers data på denne tablet uden varsel."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Slet denne brugers data på dette tv uden varsel."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Slet denne brugers data på denne telefon uden varsel."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angiv enhedens globale proxy"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for skærmlåskoden"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontroller, hvor ofte skærmlåsens adgangskode skal skiftes."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Indstil den globale proxy for enheden, der skal bruges, mens politikken er aktiveret. Det er kun enhedens ejer, der kan indstille den globale proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Angiv udløbsdato for adgangskoden til skærmlås"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Rediger, hvor ofte skærmlåsens adgangskode, pinkode eller adgangsmønster skal skiftes."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angiv kryptering af lager"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Kræver, at gemte appdata krypteres."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiver kameraer"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Bloker brug af alle kameraer på enheden."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Deaktiver tastaturlåsfunktioner"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Forbyd brugen af ​​visse tastaturlåsfunktioner."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Deaktiver skærmlåsfunktioner"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Undgå brugen af visse skærmlåsfunktioner."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ønsker at aktivere Udforsk ved berøring. Når Udforsk ved berøring er aktiveret, kan du høre eller se beskrivelser af, hvad der er under din finger, eller udføre bevægelser for at interagere med telefonen."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"for 1 måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Før for 1 måned siden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"for 1 sekund siden"</item>
-    <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"for 1 minut siden"</item>
-    <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"for 1 time siden"</item>
-    <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Seneste <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Inden for de seneste <xliff:g id="COUNT_1">%d</xliff:g> dage</item>
+      <item quantity="other">Inden for de seneste <xliff:g id="COUNT_1">%d</xliff:g> dage</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Seneste måned"</string>
     <string name="older" msgid="5211975022815554840">"Ældre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"i går"</item>
-    <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om 1 time"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"for 1 sek. siden"</item>
-    <item quantity="other" msgid="3699169366650930415">"for <xliff:g id="COUNT">%d</xliff:g> sek. siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"for 1 min. siden"</item>
-    <item quantity="other" msgid="851164968597150710">"for <xliff:g id="COUNT">%d</xliff:g> min. siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"for 1 time siden"</item>
-    <item quantity="other" msgid="6889970745748538901">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"i går"</item>
-    <item quantity="other" msgid="3453342639616481191">"for <xliff:g id="COUNT">%d</xliff:g> dage siden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 time"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dage"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"uger"</string>
     <string name="year" msgid="4001118221013892076">"år"</string>
     <string name="years" msgid="6881577717993213522">"år"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"Ét sekund"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"Ét minut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"Én time"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minutter</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutter</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> timer</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> timer</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne video kan ikke streames på denne enhed."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videoen kan ikke afspilles."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android starter..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Lageret optimeres."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimerer app <xliff:g id="NUMBER_0">%1$d</xliff:g> ud af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Åbner dine apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Gennemfører start."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Åbn ikke den nye app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop den gamle app uden at gemme."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Vælg en handling for teksten"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Lydstyrke for opkald"</string>
     <string name="volume_music" msgid="5421651157138628171">"Lydstyrke for medier"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ukendt ringetone"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi-netværk tilgængeligt"</item>
-    <item quantity="other" msgid="4192424489168397386">"Tilgængelige Wi-Fi-netværk"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Åbent Wi-Fi-netværk tilgængeligt"</item>
-    <item quantity="other" msgid="7915895323644292768">"Der er åbne Wi-Fi-netværk tilgængelige"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
+      <item quantity="other">Tilgængelige Wi-Fi-netværk</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Åbne Wi-Fi-netværk er tilgængelige</item>
+      <item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Log ind på Wi-Fi-netværket"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Log ind på netværk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Applikationen %1$s vil gerne have forbindelse til Wi-Fi-netværk %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En applikation"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct kunne ikke startes."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tilsluttet som en medieenhed"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tilsluttet som et kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Forbundet til en MIDI-enhed"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tilsluttet som et installationsprogram"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tilsluttet et USB-ekstraudstyr"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Tryk for at se andre valgmuligheder for USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Spring over"</string>
     <string name="no_matches" msgid="8129421908915840737">"Der er ingen matches"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Find på siden"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 match"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Udfør"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Demonterer USB-lageret..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Demonterer SD-kortet..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Opret en pinkode til ændring af begrænsninger"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderne stemmer ikke overens. Prøv igen."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden er for kort. Den skal være på mindst 4 tal."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Prøv igen om 1 sekund"</item>
-    <item quantity="other" msgid="4730868920742952817">"Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="other">Prøv igen om <xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv igen senere"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Stryg ned fra toppen for at afslutte fuld skærm"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fuld skærm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Stryg ned fra toppen for at afslutte."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK, det er forstået"</string>
     <string name="done_label" msgid="2093726099505892398">"Udfør"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Cirkulær timevælger"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Cirkulær minutvælger"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og Oversigt på samme tid og holde fingeren nede."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Oversigt og holde fingeren nede."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skærmen er fastgjort. Frigørelse er ikke tilladt af din organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skærmen blev frigjort"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Indtil din nedetid slutter kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Indtil nedetiden ophører"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"I ét minut (indtil <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"I én time (indtil <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"I %1$d timer (indtil <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"I ét minut"</item>
-    <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"I én time"</item>
-    <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">I %1$d timer (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">I %1$d timer (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">I %d minutter</item>
+      <item quantity="other">I %d minutter</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">I %d timer</item>
+      <item quantity="other">I %d timer</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Uendeligt"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skjul"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Indtil næste alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Indtil næste alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-anmodningen er ændret til en DIAL-anmodning."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-anmodningen er ændret til en USSD-anmodning."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-anmodningen er ændret til en ny SS-anmodning."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Ydre USB-port"</string>
 </resources>
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index 1fa067f..d641e10e 100755
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d.%m.%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8a54d54..72eff6f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> Sek."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> Sek."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Unbenannt&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Keine Telefonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Unbekannt"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mailbox"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
     <string name="enablePin" msgid="209412020907207950">"Fehler. SIM-/RUIM-Sperre aktivieren."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuch, bevor Ihre SIM-Karte gesperrt wird."</item>
-    <item quantity="other" msgid="7530597808358774740">"Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuche, bevor Ihre SIM-Karte gesperrt wird."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor Ihre SIM-Karte gesperrt wird.</item>
+      <item quantity="one">Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Ihre SIM-Karte gesperrt wird.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Anrufer-ID für eingehenden Anruf"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"An Routenanbieterdienst binden"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ermöglicht dem Inhaber die Bindung an registrierte Routenanbieter. Sollte für normale Apps nicht erforderlich sein"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"An eine TV-Eingabe binden"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Displaysperre deaktivieren"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ermöglicht der App, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. Das Telefon deaktiviert die Tastensperre beispielsweise, wenn ein Anruf eingeht, und aktiviert sie wieder, nachdem das Gespräch beendet wurde."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Fingerabdruckhardware verwalten"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erlaubt der App, Methoden zum Hinzufügen und Löschen zu verwendender Fingerabdruckvorlagen aufzurufen"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Fingerabdruckhardware verwenden"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Erlaubt der App, Fingerabdruckhardware zur Authentifizierung zu verwenden"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Synchronisierung aktivieren oder deaktivieren"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"An einen Zielauswahldienst binden"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Zielauswahldienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsproviderdienst binden"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"An Mediarouting-Dienst binden"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Ermöglicht dem Inhaber die Bindung an die Oberfläche eines Mediarouting-Dienstes auf oberster Ebene. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"An Dream-Dienst binden"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Ermöglicht der App, sich an die Oberfläche eines Dream-Dienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"An einen Mobilfunkanbieter-SMS/MMS-Dienst binden"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ermöglicht dem Inhaber die Bindung an die Oberfläche eines Mobilfunkanbieter-SMS/MMS-Dienstes auf oberster Ebene. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Zulässige Länge und Zeichen für Passwörter für die Displaysperre festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Tablet sperren oder alle Daten auf dem Tablet löschen, wenn zu häufig ein falsches Passwort eingegeben wird."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Bildschirms überwachen und Fernseher sperren oder alle Daten auf dem Fernseher löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Bildschirms überwachen und Telefon sperren oder alle Daten auf dem Telefon löschen, wenn zu häufig ein falsches Passwort eingegeben wird."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Bildschirms ändern"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ändern Sie das Passwort zum Entsperren des Bildschirms."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Tablet sperren oder alle Daten dieses Nutzers löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Fernseher sperren oder alle Daten dieses Nutzers löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Smartphone sperren oder alle Daten dieses Nutzers löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Displaysperre ändern"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Displaysperre ändern"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm sperren"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Legen Sie fest, wie und wann der Bildschirm gesperrt wird."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Fernseher ohne Warnung löschen"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Nutzerdaten löschen"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Daten dieses Nutzers auf diesem Tablet ohne vorherige Warnung löschen"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Daten dieses Nutzers auf diesem Fernseher ohne vorherige Warnung löschen"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Daten dieses Nutzers auf diesem Smartphone ohne vorherige Warnung löschen"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Legen Sie fest, wie häufig das Passwort zum Sperren des Bildschirms geändert werden muss."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Bei aktivierter Richtlinie zu verwendenden globalen Geräteproxy festlegen. Nur der Eigentümer des Geräts kann den globalen Proxy festlegen."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Passwortablauf für Sperre festlegen"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Häufigkeit ändern, mit der das Passwort, die PIN oder das Muster für die Displaysperre geändert werden muss"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Speicherverschlüsselung"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Anforderung, dass gespeicherte App-Daten verschlüsselt werden"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameras deaktivieren"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Nutzung sämtlicher Gerätekameras unterbinden"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Funktionen in Keyguard deaktivieren"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Verhindert in Keyguard die Verwendung einiger Funktionen"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Sperrfunktionen deaktivieren"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Verhindert die Verwendung einiger Funktionen der Displaysperre"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\". Wenn \"Tippen &amp; Entdecken\" aktiviert ist, können Sie Beschreibungen dessen hören oder sehen, was sich unter ihren Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"vor 1 Sekunde"</item>
-    <item quantity="other" msgid="3903706804349556379">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"vor 1 Minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"vor 1 Stunde"</item>
-    <item quantity="other" msgid="2467273239587587569">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Letzte <xliff:g id="COUNT">%d</xliff:g> Tage"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Letzte <xliff:g id="COUNT_1">%d</xliff:g> Tage</item>
+      <item quantity="one">Gestern (<xliff:g id="COUNT_0">%d</xliff:g> Tag)</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Letzter Monat"</string>
     <string name="older" msgid="5211975022815554840">"Älter"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gestern"</item>
-    <item quantity="other" msgid="2479586466153314633">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 Sekunde"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 Minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 Stunde"</item>
-    <item quantity="other" msgid="547290677353727389">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"vor 1 Sekunde"</item>
-    <item quantity="other" msgid="3699169366650930415">"vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"vor 1 Minute"</item>
-    <item quantity="other" msgid="851164968597150710">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"vor 1 Stunde"</item>
-    <item quantity="other" msgid="6889970745748538901">"vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gestern"</item>
-    <item quantity="other" msgid="3453342639616481191">"vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 Sekunde"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 Minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 Stunde"</item>
-    <item quantity="other" msgid="3705373766798013406">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"am <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"um <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"im Jahr <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"Wochen"</string>
     <string name="year" msgid="4001118221013892076">"Jahr"</string>
     <string name="years" msgid="6881577717993213522">"Jahre"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 Sekunde"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 Minute"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 Stunde"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> Sekunden</item>
+      <item quantity="one">1 Sekunde</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> Minuten</item>
+      <item quantity="one">1 Minute</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> Stunden</item>
+      <item quantity="one">1 Stunde</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobleme"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Dieses Video ist nicht für Streaming auf diesem Gerät gültig."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Video kann nicht wiedergegeben werden."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android wird gestartet…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Speicher wird optimiert"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> von <xliff:g id="NUMBER_1">%2$d</xliff:g> wird optimiert..."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> wird vorbereitet"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps werden gestartet..."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Start wird abgeschlossen..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Neue App nicht starten"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Alte App beenden, ohne zu speichern"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Aktion für Text auswählen"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Keine"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Klingeltöne"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Unbekannter Klingelton"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"WLAN-Netzwerk verfügbar"</item>
-    <item quantity="other" msgid="4192424489168397386">"WLAN-Netzwerke verfügbar"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Verfügbares WLAN-Netzwerk öffnen"</item>
-    <item quantity="other" msgid="7915895323644292768">"Verfügbare WLAN-Netzwerke öffnen"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">WLAN-Netzwerke verfügbar</item>
+      <item quantity="one">WLAN-Netzwerk verfügbar</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Verfügbare WLAN-Netzwerke öffnen</item>
+      <item quantity="one">Verfügbares WLAN-Netzwerk öffnen</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Im WLAN-Netzwerk anmelden"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Im Netzwerk anmelden"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN-Netzwerk %2$s herstellen."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Eine App"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Starten von Wi-Fi Direct nicht möglich"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Als Mediengerät angeschlossen"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Als Kamera angeschlossen"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Als MIDI-Gerät verbunden"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Als Installationsprogramm angeschlossen"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Mit USB-Zubehör verbunden"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Für mehr USB-Optionen berühren"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Überspringen"</string>
     <string name="no_matches" msgid="8129421908915840737">"Keine Treffer"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Auf Seite suchen"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 Treffer"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> von <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> von <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 Treffer</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Fertig"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB-Speicher wird getrennt..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-Karte wird getrennt..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuchen Sie es erneut."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens 4 Ziffern umfassen."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"In 1 Sek. wiederholen"</item>
-    <item quantity="other" msgid="4730868920742952817">"In <xliff:g id="COUNT">%d</xliff:g> Sek. wiederholen"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">In <xliff:g id="COUNT">%d</xliff:g> Sek. wiederholen</item>
+      <item quantity="one">In 1 Sek. wiederholen</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Später erneut versuchen"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Zum Schließen des Vollbilds von oben nach unten wischen"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vollbildmodus wird aktiviert"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Zum Beenden von oben nach unten wischen"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Fertig"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kreisförmiger Schieberegler für Stunden"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kreisförmiger Schieberegler für Minuten"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie \"Übersicht\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Der Bildschirm ist fixiert. Sie sind nicht berechtigt, diese Einstellung zu beenden."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Bildschirm gelöst"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf Ihrem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn Ihr Gerät aufgeladen wird."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Bis zum Ende der Downtime um <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Bis zum Ende der Inaktivität"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1 Minute (bis <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d Minuten (bis <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1 Stunde (bis <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d Stunden (bis <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Für eine Stunde"</item>
-    <item quantity="other" msgid="5408537517529822157">"Für %d Stunden"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d Minuten (bis <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">1 Minute (bis <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d Stunden (bis <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">1 Stunde (bis <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Für %d Minuten</item>
+      <item quantity="one">Für 1 Minute</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Für %d Stunden</item>
+      <item quantity="one">Für eine Stunde</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Bis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Unbegrenzt"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Minimieren"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Bis zum nächsten Weckruf um <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Bis zum nächsten Weckruf"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-Anfrage wird in DIAL-Anfrage geändert."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-Anfrage wird in USSD-Anfrage geändert."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-Anfrage wird in neue SS-Anfrage geändert."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-Port für Peripheriegeräte"</string>
 </resources>
diff --git a/core/res/res/values-el/donottranslate-cldr.xml b/core/res/res/values-el/donottranslate-cldr.xml
index 7da5a72..c7f41b4 100755
--- a/core/res/res/values-el/donottranslate-cldr.xml
+++ b/core/res/res/values-el/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d %b %Y</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ea06473..caa3408 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -40,14 +40,12 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> δευτ."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> δευτ."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Χωρίς τίτλο&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Δεν υπάρχει τηλεφωνικός αριθμός)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Άγνωστο"</string>
-    <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτόματος τηλεφωνητής"</string>
+    <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Αυτ/τος τηλεφωνητής"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
     <string name="mmiError" msgid="5154499457739052907">"Πρόβλημα σύνδεσης ή μη έγκυρος κώδικας MMI."</string>
-    <string name="mmiFdnError" msgid="5224398216385316471">"Η λειτουργία περιορίζεται μόνο σε καθορισμένους αριθμούς κλήσης."</string>
+    <string name="mmiFdnError" msgid="5224398216385316471">"Η λειτουργία περιορίζεται μόνο σε προκαθορισμένους αριθμούς κλήσης."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Η υπηρεσία ενεργοποιήθηκε."</string>
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Η υπηρεσία ενεργοποιήθηκε για:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Η υπηρεσία έχει απενεργοποιηθεί."</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Η κάρτα SIM έχει κλειδωθεί με κωδικό PUK. Πληκτρολογήστε τον κωδικό PUK για να την ξεκλειδώσετε."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Πληκτρολογήστε τον κωδικό PUK2 για την κατάργηση αποκλεισμού της κάρτας SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Ανεπιτυχής προσπάθεια. Ενεργοποιήστε το Κλείδωμα SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια προτού η κάρτα SIM κλειδωθεί."</item>
-    <item quantity="other" msgid="7530597808358774740">"Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες προτού η κάρτα SIM κλειδωθεί."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες προτού κλειδωθεί η κάρτα SIM.</item>
+      <item quantity="one">Απομένει άλλη <xliff:g id="NUMBER_0">%d</xliff:g> προσπάθεια προτού κλειδωθεί η κάρτα SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Εισερχόμενη αναγνώριση κλήσης"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Λειτ. πτήσης είναι ανενεργή"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ρυθμίσεις"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Φων.υποβοηθ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"σύνδεση σε μια υπηρεσία παρόχου δρομολογητή"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Δίνει στον κάτοχο τη δυνατότητα σύνδεσης με οποιονδήποτε εγγεγραμμένο πάροχο δρομολογητή. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"σύνδεση σε μία είσοδο τηλεόρασης"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Επιτρέπει στην εφαρμογή την επικοινωνία με ετικέτες, κάρτες και αναγνώστες της Επικοινωνίας κοντινού πεδίου (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"απενεργοποίηση κλειδώματος οθόνης"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Επιτρέπει στην εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, το κλείδωμα πληκτρολογίου στο τηλέφωνο απενεργοποιείται όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και ενεργοποιείται ξανά όταν η κλήση τερματιστεί."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"διαχείριση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους για την προσθήκη και τη διαγραφή προτύπων μοναδικού χαρακτηριστικού για χρήση."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"χρήση εξοπλισμού μοναδικού χαρακτηριστικού"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί εξοπλισμό μοναδικού χαρακτηριστικού για έλεγχο ταυτότητας"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"εναλλαγή ενεργοποίησης και απενεργοποίησης συγχρονισμού"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"δέσμευση σε υπηρεσία επιλογής στόχευσης"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας επιλογής στόχευσης. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"σύνδεση σε μια υπηρεσία δρομολόγησης μέσων"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας δρομολόγησης μέσων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"δέσμευση σε υπηρεσία dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας dream. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Παρακολούθηση του αριθμού λανθασμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλείδωμα του tablet ή διαγραφή όλων των δεδομένων του σε περίπτωση πληκτρολόγησης πάρα πολλών εσφαλμένων κωδικών πρόσβασης."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Παρακολούθηση του αριθμού των εσφαλμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλείδωμα της τηλεόρασης ή διαγραφή όλων των δεδομένων της τηλεόρασης, αν έχουν πληκτρολογηθεί πάρα πολλοί εσφαλμένοι κωδικοί πρόσβασης."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Παρακολούθηση του αριθμού λανθασμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλείδωμα του τηλεφώνου ή διαγραφή όλων των δεδομένων του σε περίπτωση πληκτρολόγησης πάρα πολλών εσφαλμένων κωδικών πρόσβασης."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Αλλαγή κωδικού πρόσβασης ξεκλειδώματος οθόνης"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Αλλαγή του κωδικού πρόσβασης ξεκλειδώματος οθόνης."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Παρακολουθήστε τον αριθμό των εσφαλμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλειδώστε το tablet ή διαγράψτε όλα τα δεδομένα του χρήστη, σε περίπτωση εισαγωγής πάρα πολλών εσφαλμένων κωδικών πρόσβασης."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Παρακολουθήστε τον αριθμό των εσφαλμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλειδώστε την τηλεόραση ή διαγράψτε όλα τα δεδομένα του χρήστη, σε περίπτωση εισαγωγής πάρα πολλών εσφαλμένων κωδικών πρόσβασης."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Παρακολουθήστε τον αριθμό των εσφαλμένων κωδικών πρόσβασης που πληκτρολογούνται κατά το ξεκλείδωμα της οθόνης και κλειδώστε το τηλέφωνο ή διαγράψτε όλα τα δεδομένα του χρήστη, σε περίπτωση εισαγωγής πάρα πολλών εσφαλμένων κωδικών πρόσβασης."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Αλλαγή του κλειδώματος οθόνης"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Αλλαγή του κλειδώματος οθόνης"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Κλείδωμα οθόνης"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Έλεγχος του τρόπου και του χρόνου κλειδώματος της οθόνης."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Διαγραφή όλων των δεδομένων"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Διαγραφή των δεδομένων του tablet χωρίς προειδοποίηση με επαναφορά των εργοστασιακών ρυθμίσεων."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Διαγραφή των δεδομένων της τηλεόρασης χωρίς προειδοποίηση με εκτέλεση επαναφοράς εργοστασιακών ρυθμίσεων."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Διαγραφή των δεδομένων του τηλεφώνου χωρίς προειδοποίηση με επαναφορά των εργοστασιακών ρυθμίσεων."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Διαγραφή δεδομένων χρήστη"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Διαγραφή των δεδομένων αυτού του χρήστη σε αυτό το tablet χωρίς προειδοποίηση."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Διαγραφή των δεδομένων αυτού του χρήστη σε αυτήν την τηλεόραση χωρίς προειδοποίηση."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Διαγραφή των δεδομένων αυτού του χρήστη σε αυτό το τηλέφωνο χωρίς προειδοποίηση."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ρύθμιση του γενικού διακομιστή μεσολάβησης της συσκευής"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδ. κλειδ. οθ."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Έλεγχος της συχνότητας αλλαγής του κωδικού πρόσβασης κλειδώματος οθόνης."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Ρυθμίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής, ενώ η πολιτική είναι ενεργοποιημένη. Μόνο ο κάτοχος της συσκευής μπορεί να ρυθμίσει τον γενικό διακομιστής μεσολάβησης."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ορίστε λήξη κωδ.πρόσ.κλειδ.οθ."</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Αλλάξτε τη συχνότητας αλλαγής του κωδικού πρόσβασης κλειδώματος οθόνης, του PIN ή του μοτίβου."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ορισμός κρυπτογρ. αποθ. χώρου"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Να απαιτείται η κρυπτογράφηση των αποθηκευμένων δεδομένων εφαρμογής"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Απενεργοποίηση φωτογρ. μηχανών"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Να αποτρέπεται η χρήση των φωτογραφικών μηχανών της συσκευής."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Απενεργοποίηση λειτουργιών στο κλείδωμα πληκτρολογίου"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Αποφυγή της χρήσης ορισμένων λειτουργιών στο κλείδωμα πληκτρολογίου."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Απεν. λειτ.κλειδώματος οθόνης"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Αποφυγή της χρήσης ορισμένων λειτουργιών στο κλείδωμα οθόνης."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Οικία"</item>
     <item msgid="869923650527136615">"Κινητό"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Η υπηρεσία <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> απαιτεί ενεργοποίηση της Εξερεύνησης μέσω αφής. Όταν είναι ενεργοποιημένη η Εξερεύνηση μέσω αφής, μπορείτε να δείτε ή να ακούσετε περιγραφές για τις επιλογές που βρίσκονται κάτω από το δάχτυλό σας ή να κάνετε κινήσεις αλληλεπίδρασης με το τηλέφωνό σας."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"πριν από 1 μήνα"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Παλαιότερα από 1 μήνα"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"πριν από 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="3903706804349556379">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"πριν από 1 λεπτό"</item>
-    <item quantity="other" msgid="2176942008915455116">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"πριν από 1 ώρα"</item>
-    <item quantity="other" msgid="2467273239587587569">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Τελευταίες <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Τελευταίες <xliff:g id="COUNT_1">%d</xliff:g> ημέρες</item>
+      <item quantity="one">Τελευταία <xliff:g id="COUNT_0">%d</xliff:g> ημέρα</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Τελευταίος μήνας"</string>
     <string name="older" msgid="5211975022815554840">"Παλαιότερα"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"χθες"</item>
-    <item quantity="other" msgid="2479586466153314633">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"σε 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="1241926116443974687">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"σε 1 λεπτό"</item>
-    <item quantity="other" msgid="3330713936399448749">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"σε 1 ώρα"</item>
-    <item quantity="other" msgid="547290677353727389">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"αύριο"</item>
-    <item quantity="other" msgid="5109449375100953247">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"πριν από 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="3699169366650930415">"πριν από <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"πριν από 1 λεπτό"</item>
-    <item quantity="other" msgid="851164968597150710">"πριν από <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"πριν από 1 ώρα"</item>
-    <item quantity="other" msgid="6889970745748538901">"πριν από <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"χθες"</item>
-    <item quantity="other" msgid="3453342639616481191">"πριν από <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"σε 1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="5495880108825805108">"σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"σε 1 λεπτό"</item>
-    <item quantity="other" msgid="4216113292706568726">"σε <xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"σε 1 ώρα"</item>
-    <item quantity="other" msgid="3705373766798013406">"σε <xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"αύριο"</item>
-    <item quantity="other" msgid="2973062968038355991">"σε <xliff:g id="COUNT">%d</xliff:g> ημέρες"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"στις <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"στις <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"το <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"εβδομάδες"</string>
     <string name="year" msgid="4001118221013892076">"έτος"</string>
     <string name="years" msgid="6881577717993213522">"έτη"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 δευτερόλεπτο"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 λεπτό"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> λεπτά"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ώρα"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ώρες"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα</item>
+      <item quantity="one">1 δευτερόλεπτο</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> λεπτά</item>
+      <item quantity="one">1 λεπτό</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ώρες</item>
+      <item quantity="one">1 ώρα</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Πρόβλημα με το βίντεο"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Αυτό το βίντεο δεν είναι έγκυρο για ροή σε αυτή τη συσκευή."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Δεν μπορείτε να αναπαράγετε αυτό το βίντεο."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Εκκίνηση Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Βελτιστοποίηση αποθηκευτικού χώρου."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Βελτιστοποίηση της εφαρμογής <xliff:g id="NUMBER_0">%1$d</xliff:g> από <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Προετοιμασία <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Έναρξη εφαρμογών."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Ολοκλήρωση εκκίνησης."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Μην εκκινήσετε τη νέα εφαρμογή."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Εκκίνηση της εφαρμογής <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Διακοπή της παλιάς εφαρμογής χωρίς αποθήκευση."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Επιλέξτε μια ενέργεια για το κείμενο"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ένταση ήχου ειδοποίησης"</string>
     <string name="volume_music" msgid="5421651157138628171">"Ένταση ήχου πολυμέσων"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Κανένας"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ήχοι κλήσης"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Άγνωστος ήχος κλήσης"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Υπάρχει διαθέσιμο δίκτυο Wi-Fi"</item>
-    <item quantity="other" msgid="4192424489168397386">"Υπάρχουν διαθέσιμα δίκτυα Wi-Fi"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Υπάρχουν διαθέσιμα δίκτυα Wi-Fi</item>
+      <item quantity="one">Υπάρχει διαθέσιμο δίκτυο Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi</item>
+      <item quantity="one">Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Σύνδεση στο δίκτυο Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Σύνδεση σε δίκτυο"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Η εφαρμογή %1$s θα ήθελε να συνδεθεί με το δίκτυο WiFi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Μια εφαρμογή"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Δεν ήταν δυνατή η εκκίνηση του Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ΟΚ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Συνδεδεμένο ως συσκευή πολυμέσων"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Συνδεδεμένο ως φωτογραφική μηχανή"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Συνδεθήκατε ως συσκευή MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Συνδεδεμένο ως πρόγραμμα εγκατάστασης"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Σύνδεση σε αξεσουάρ USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Αγγίξτε για άλλες επιλογές USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Παράλειψη"</string>
     <string name="no_matches" msgid="8129421908915840737">"Δεν υπάρχουν αποτελέσματα"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Εύρεση στη σελίδα"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 αποτέλεσμα"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> από <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> από <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 αντιστοιχία</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Τέλος"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Αποσύνδεση του χώρου αποθήκευσης USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Αφαίρεση κάρτας SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Δημιουργία PIN για τροποποίηση περιορισμών"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Τα PIN δεν συμφωνούν. Προσπαθήστε ξανά."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Το PIN είναι υπερβολικά μικρό. Πρέπει να έχει μέγεθος τουλάχιστον 4 χαρακτήρων."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Επανάληψη σε 1 δευτ."</item>
-    <item quantity="other" msgid="4730868920742952817">"Επανάληψη σε <xliff:g id="COUNT">%d</xliff:g> δευτ."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Δοκιμάστε ξανά σε <xliff:g id="COUNT">%d</xliff:g> δευτερόλεπτα</item>
+      <item quantity="one">Δοκιμάστε ξανά σε 1 δευτερόλεπτο</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Δοκιμάστε ξανά αργότερα"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Σάρωση προς τα κάτω για έξοδο από πλήρη οθόνη"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Προβολή σε πλήρη οθόνη"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Το κατάλαβα"</string>
     <string name="done_label" msgid="2093726099505892398">"Τέλος"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Κυκλικό ρυθμιστικό ωρών"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Κυκλικό ρυθμιστικό λεπτών"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, πατήστε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα \"Επισκόπηση\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Η οθόνη καρφιστώθηκε. Το ξεκαρφίτσωμα δεν επιτρέπεται από τον οργανισμό σας."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Η οθόνη ξεκαρφιτσώθηκε"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στο συγχρονισμό ενδέχεται να μην ενημερώνονται έως ότου τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα όταν η συσκευή σας φορτίζει."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Έως τη λήξη του νεκρού χρόνου σας στις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Έως τη λήξη του νεκρού χρόνου σας"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Για ένα λεπτό (έως τις <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Για %1$d λεπτά (έως τις <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Για μία ώρα (έως τις <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Για %1$d ώρες (έως τις <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item>
-    <item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Για μία ώρα"</item>
-    <item quantity="other" msgid="5408537517529822157">"Για %d ώρες"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Για %1$d λεπτά (έως τις <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Για ένα λεπτό (έως τις <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Για %1$d ώρες (έως τις <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Για μία ώρα (έως τις <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Για %d λεπτά</item>
+      <item quantity="one">Για ένα λεπτό</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Για %d ώρες</item>
+      <item quantity="one">Για μία ώρα</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Έως τις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Επ\' αόριστον"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Σύμπτυξη"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Έως την επόμενη ειδοποίηση στις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Έως την επόμενη ειδοποίηση"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Το αίτημα SS τροποποιήθηκε σε αίτημα DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Το αίτημα SS τροποποιήθηκε σε αίτημα USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Το αίτημα SS τροποποιήθηκε σε νέο αίτημα SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Περιφερειακή θύρα USB"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/donottranslate-cldr.xml b/core/res/res/values-en-rAU/donottranslate-cldr.xml
index a7c07d3..69c3aea 100755
--- a/core/res/res/values-en-rAU/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rAU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rCA/donottranslate-cldr.xml b/core/res/res/values-en-rCA/donottranslate-cldr.xml
index b632f81..57b80df 100755
--- a/core/res/res/values-en-rCA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rCA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%Y-%m-%d, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rGB/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ef6f18d7..e75df385 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secs"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Untitled&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(No phone number)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Unknown"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Your SIM card is PUK-locked. Type the PUK code to unlock it."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Type PUK2 to unblock SIM card."</string>
     <string name="enablePin" msgid="209412020907207950">"Unsuccessful, enable SIM/RUIM Lock."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM is locked."</item>
-    <item quantity="other" msgid="7530597808358774740">"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM is locked."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
+      <item quantity="one">You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before SIM is locked.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Incoming Caller ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Allows the app to communicate with Near Field Communication (NFC) tags, cards and readers."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disable your screen lock"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Allows the app to disable the keylock and any associated password security. For example, the phone disables the keylock when receiving an incoming phone call, then re-enables the keylock when the call is finished."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"manage fingerprint hardware"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Allows the app to invoke methods to add and delete fingerprint templates for use."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"use fingerprint hardware"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Allows the app to use fingerprint hardware for authentication"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Allows the holder to bind to the top-level interface of a media route service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"bind to a dream service"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind to a carrier messaging service"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitor the number of incorrect passwords typed when unlocking the screen and lock the tablet or erase all the tablet\'s data if too many incorrect passwords are typed."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the TV or erase all the TV\'s data if too many incorrect passwords are typed."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitor the number of incorrect passwords typed when unlocking the screen and lock the phone or erase all the phone\'s data if too many incorrect passwords are typed."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Change the screen-unlock password"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Change the screen-unlock password."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the tablet or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the TV or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the phone or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Change the screen lock"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Change the screen lock."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Lock the screen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Control how and when the screen locks."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Erase all data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Erase the tablet\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Erase the TV\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Erase the phone\'s data without warning by performing a factory data reset."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Erase user data"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Erase this user\'s data on this tablet without warning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Erase this user\'s data on this TV without warning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Erase this user\'s data on this phone without warning."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Set the device global proxy"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Set lock-screen password expiry"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Control how frequently the lock-screen password must be changed."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Set the device global proxy to be used while policy is enabled. Only the device owner can set the global proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Set screen lock password expiry"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Change how frequently the screen lock password, PIN or pattern must be changed."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Set storage encryption"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Require that stored app data be encrypted."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Disable cameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Prevent use of all device cameras."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Disable features in keyguard"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Prevent use of some features in keyguard."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Disable features of screen lock"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Prevent use of some features of screen lock."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Last <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Last <xliff:g id="COUNT_1">%d</xliff:g> days</item>
+      <item quantity="one">Last <xliff:g id="COUNT_0">%d</xliff:g> day</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Last month"</string>
     <string name="older" msgid="5211975022815554840">"Older"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"yesterday"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
-    <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
-    <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"weeks"</string>
     <string name="year" msgid="4001118221013892076">"year"</string>
     <string name="years" msgid="6881577717993213522">"years"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 second"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hour"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> seconds</item>
+      <item quantity="one">1 second</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutes</item>
+      <item quantity="one">1 minute</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> hours</item>
+      <item quantity="one">1 hour</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video problem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"This video isn\'t valid for streaming to this device."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Can\'t play this video."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android is starting…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimising storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimising app <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparing <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media volume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi network available"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi networks available"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Open available Wi-Fi network"</item>
-    <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi networks available"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi networks available</item>
+      <item quantity="one">Wi-Fi network available</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Open Wi-Fi networks available</item>
+      <item quantity="one">Open Wi-Fi network available</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Sign in to Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connected as a media device"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connected as a camera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connected as a MIDI device"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connected as an installer"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connected to a USB accessory"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Touch for other USB options."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Skip"</string>
     <string name="no_matches" msgid="8129421908915840737">"No matches"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Find on page"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 Match"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> of <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> of <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 match</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Done"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Unmounting USB storage…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Unmounting SD card…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Create a PIN for modifying restrictions"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINs don\'t match. Try again."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is too short. Must be at least 4 digits."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Try again in 1 second"</item>
-    <item quantity="other" msgid="4730868920742952817">"Try again in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Try again in <xliff:g id="COUNT">%d</xliff:g> seconds</item>
+      <item quantity="one">Try again in 1 second</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string>
     <string name="done_label" msgid="2093726099505892398">"Done"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Until your downtime ends at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Until your downtime ends"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"For one minute (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"For %1$d minutes (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"For one hour (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"For %1$d hours (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
-    <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
-    <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">For %1$d hours (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">For one hour (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">For %d minutes</item>
+      <item quantity="one">For one minute</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">For %d hours</item>
+      <item quantity="one">For one hour</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinitely"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Collapse"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Until next alarm at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Until next alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-en-rIE/donottranslate-cldr.xml b/core/res/res/values-en-rIE/donottranslate-cldr.xml
index d099376..db438f2 100755
--- a/core/res/res/values-en-rIE/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIE/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y, %H:%M:%S</string>
diff --git a/core/res/res/values-en-rIN/donottranslate-cldr.xml b/core/res/res/values-en-rIN/donottranslate-cldr.xml
index 1d9470c..84157fe 100755
--- a/core/res/res/values-en-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d-%b-%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ef6f18d7..e75df385 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secs"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Untitled&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(No phone number)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Unknown"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Your SIM card is PUK-locked. Type the PUK code to unlock it."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Type PUK2 to unblock SIM card."</string>
     <string name="enablePin" msgid="209412020907207950">"Unsuccessful, enable SIM/RUIM Lock."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM is locked."</item>
-    <item quantity="other" msgid="7530597808358774740">"You have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM is locked."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM is locked.</item>
+      <item quantity="one">You have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before SIM is locked.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Incoming Caller ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Allows the app to communicate with Near Field Communication (NFC) tags, cards and readers."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disable your screen lock"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Allows the app to disable the keylock and any associated password security. For example, the phone disables the keylock when receiving an incoming phone call, then re-enables the keylock when the call is finished."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"manage fingerprint hardware"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Allows the app to invoke methods to add and delete fingerprint templates for use."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"use fingerprint hardware"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Allows the app to use fingerprint hardware for authentication"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"toggle sync on and off"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bind to a chooser target service"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bind to a media route service"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Allows the holder to bind to the top-level interface of a media route service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"bind to a dream service"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind to a carrier messaging service"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitor the number of incorrect passwords typed when unlocking the screen and lock the tablet or erase all the tablet\'s data if too many incorrect passwords are typed."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the TV or erase all the TV\'s data if too many incorrect passwords are typed."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitor the number of incorrect passwords typed when unlocking the screen and lock the phone or erase all the phone\'s data if too many incorrect passwords are typed."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Change the screen-unlock password"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Change the screen-unlock password."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the tablet or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the TV or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitor the number of incorrect passwords typed when unlocking the screen, and lock the phone or erase all this user\'s data if too many incorrect passwords are typed."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Change the screen lock"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Change the screen lock."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Lock the screen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Control how and when the screen locks."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Erase all data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Erase the tablet\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Erase the TV\'s data without warning by performing a factory data reset."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Erase the phone\'s data without warning by performing a factory data reset."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Erase user data"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Erase this user\'s data on this tablet without warning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Erase this user\'s data on this TV without warning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Erase this user\'s data on this phone without warning."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Set the device global proxy"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Set lock-screen password expiry"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Control how frequently the lock-screen password must be changed."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Set the device global proxy to be used while policy is enabled. Only the device owner can set the global proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Set screen lock password expiry"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Change how frequently the screen lock password, PIN or pattern must be changed."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Set storage encryption"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Require that stored app data be encrypted."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Disable cameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Prevent use of all device cameras."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Disable features in keyguard"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Prevent use of some features in keyguard."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Disable features of screen lock"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Prevent use of some features of screen lock."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wants to enable Explore by Touch. When Explore by Touch is turned on, you can hear or see descriptions of what\'s under your finger or perform gestures to interact with the phone."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 month ago"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Before 1 month ago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 second ago"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconds ago"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minute ago"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutes ago"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hour ago"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Last <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Last <xliff:g id="COUNT_1">%d</xliff:g> days</item>
+      <item quantity="one">Last <xliff:g id="COUNT_0">%d</xliff:g> day</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Last month"</string>
     <string name="older" msgid="5211975022815554840">"Older"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"yesterday"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"in 1 second"</item>
-    <item quantity="other" msgid="1241926116443974687">"in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"in 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"in <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"in 1 hour"</item>
-    <item quantity="other" msgid="547290677353727389">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"tomorrow"</item>
-    <item quantity="other" msgid="5109449375100953247">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec ago"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> secs ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min ago"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> mins ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hour ago"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> hours ago"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"yesterday"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> days ago"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"in 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"in <xliff:g id="COUNT">%d</xliff:g> secs"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"in 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"in <xliff:g id="COUNT">%d</xliff:g> mins"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"in 1 hour"</item>
-    <item quantity="other" msgid="3705373766798013406">"in <xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"tomorrow"</item>
-    <item quantity="other" msgid="2973062968038355991">"in <xliff:g id="COUNT">%d</xliff:g> days"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"on <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"at <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"weeks"</string>
     <string name="year" msgid="4001118221013892076">"year"</string>
     <string name="years" msgid="6881577717993213522">"years"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 second"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hour"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hours"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> seconds</item>
+      <item quantity="one">1 second</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutes</item>
+      <item quantity="one">1 minute</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> hours</item>
+      <item quantity="one">1 hour</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video problem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"This video isn\'t valid for streaming to this device."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Can\'t play this video."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android is starting…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimising storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimising app <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparing <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starting apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finishing boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> running"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Don\'t start the new app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stop the old app without saving."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Choose an action for text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringer volume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media volume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Unknown ringtone"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi network available"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi networks available"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Open available Wi-Fi network"</item>
-    <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi networks available"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi networks available</item>
+      <item quantity="one">Wi-Fi network available</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Open Wi-Fi networks available</item>
+      <item quantity="one">Open Wi-Fi network available</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Sign in to Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connected as a media device"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connected as a camera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connected as a MIDI device"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connected as an installer"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connected to a USB accessory"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Touch for other USB options."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Skip"</string>
     <string name="no_matches" msgid="8129421908915840737">"No matches"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Find on page"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 Match"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> of <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> of <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 match</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Done"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Unmounting USB storage…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Unmounting SD card…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Create a PIN for modifying restrictions"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINs don\'t match. Try again."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN is too short. Must be at least 4 digits."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Try again in 1 second"</item>
-    <item quantity="other" msgid="4730868920742952817">"Try again in <xliff:g id="COUNT">%d</xliff:g> seconds"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Try again in <xliff:g id="COUNT">%d</xliff:g> seconds</item>
+      <item quantity="one">Try again in 1 second</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Try again later"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swipe down from the top to exit full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Viewing full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"To exit, swipe down from the top."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Got it"</string>
     <string name="done_label" msgid="2093726099505892398">"Done"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Hours circular slider"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"To unpin this screen, touch and hold Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Screen is pinned. Unpinning isn\'t allowed by your organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Screen unpinned"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Until your downtime ends at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Until your downtime ends"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"For one minute (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"For %1$d minutes (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"For one hour (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"For %1$d hours (until <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"For one minute"</item>
-    <item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"For one hour"</item>
-    <item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">For %1$d hours (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">For one hour (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">For %d minutes</item>
+      <item quantity="one">For one minute</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">For %d hours</item>
+      <item quantity="one">For one hour</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinitely"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Collapse"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Until next alarm at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Until next alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS request is modified to DIAL request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS request is modified to USSD request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS request is modified to new SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-en-rNZ/donottranslate-cldr.xml b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
index a4ff357..4e9bec6 100755
--- a/core/res/res/values-en-rNZ/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rNZ/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-e/%m/%Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rSG/strings.xml b/core/res/res/values-en-rSG/strings.xml
index 09a8490..5ba1082b 100644
--- a/core/res/res/values-en-rSG/strings.xml
+++ b/core/res/res/values-en-rSG/strings.xml
@@ -776,22 +776,6 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
     <!-- no translation found for preposition_for_date (2689847983632851560) -->
     <skip />
     <!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-en-rUS/donottranslate-cldr.xml b/core/res/res/values-en-rUS/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values-en-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-en-rUS/strings.xml b/core/res/res/values-en-rUS/strings.xml
index fdc0d69..adae7f4 100644
--- a/core/res/res/values-en-rUS/strings.xml
+++ b/core/res/res/values-en-rUS/strings.xml
@@ -777,22 +777,6 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
-    <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
-    <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
-    <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
-    <!-- no translation found for num_hours_ago:one (853404611989669641) -->
-    <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
-    <!-- no translation found for num_days_ago:one (4222479980812128212) -->
-    <!-- no translation found for num_days_ago:other (5445701370433601703) -->
-    <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
-    <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
-    <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
-    <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
-    <!-- no translation found for in_num_hours:one (6501470863235186391) -->
-    <!-- no translation found for in_num_hours:other (4415358752953289251) -->
-    <!-- no translation found for in_num_days:one (5608475533104443893) -->
-    <!-- no translation found for in_num_days:other (3827193006163842267) -->
     <!-- no translation found for preposition_for_date (2689847983632851560) -->
     <skip />
     <!-- no translation found for preposition_for_time (2613388053493148013) -->
diff --git a/core/res/res/values-en-rZA/donottranslate-cldr.xml b/core/res/res/values-en-rZA/donottranslate-cldr.xml
index 7c27604..a4a5308 100755
--- a/core/res/res/values-en-rZA/donottranslate-cldr.xml
+++ b/core/res/res/values-en-rZA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%d %b %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml
index 878b48f..8adac31 100755
--- a/core/res/res/values-es-rUS/donottranslate-cldr.xml
+++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %b %-e, %Y</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 45ee7a3..84718dd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sin título&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(No hay número de teléfono)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Desconocido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Tu tarjeta SIM está bloqueada con PUK. Escribe el código PUK para desbloquearla."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Escribir PUK2 para desbloquear la tarjeta SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Error; habilita el bloqueo de SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Te queda <xliff:g id="NUMBER">%d</xliff:g> intento antes de que se bloquee la tarjeta SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que se bloquee la tarjeta SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que se bloquee la tarjeta SIM.</item>
+      <item quantity="one">Tienes <xliff:g id="NUMBER_0">%d</xliff:g> un intento más antes de que se bloquee la tarjeta SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Identificador de llamadas entrantes"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular con un servicio de proveedor de rutas"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite al propietario vincular con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a una entrada de TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivar el bloqueo de pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación desactive el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el dispositivo puede desactivar el bloqueo del teclado cuando recibe una llamada telefónica y volver a activarlo cuando finaliza la llamada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Administrar el hardware de huellas digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación emplee métodos para agregar y eliminar plantillas de huellas digitales para su uso."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utilizar hardware de huellas digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincularse a un servicio de destino selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de destino. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servicio de enrutamiento de contenido multimedia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite vincular con la interfaz de nivel superior de un servicio de enrutamiento de contenido multimedia. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"vincularse a un servicio de protector de pantalla interactivo"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de protector de pantalla interactivo. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular al servicio de mensajería del proveedor"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de mensajería del proveedor. Las aplicaciones regulares no lo necesitan."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Permite controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Controla la cantidad de contraseñas incorrectas ingresadas al desbloquear la pantalla y bloquea la tablet o borra todos los datos de la tablet si se ingresaron demasiadas contraseñas incorrectas."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y permite bloquear la TV o borrar todos los datos de la TV si se escriben demasiadas contraseñas incorrectas."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla y bloquea el dispositivo o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Cambiar la contraseña para desbloquear la pantalla"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Cambiar la contraseña para desbloquear la pantalla"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear la tablet, o borrar todos los datos del usuario, si se ingresan demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear la televisión, o borrar todos los datos del usuario, si se ingresan demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear el teléfono, o borrar todos los datos del usuario, si se ingresan demasiadas contraseñas incorrectas."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Cambiar el bloqueo de pantalla"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Permite cambiar el bloqueo de pantalla."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear la pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar cómo y cuándo se bloquea la pantalla"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Eliminar todos los datos"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Eliminar los datos de la tablet sin avisar y restablecer la configuración de fábrica"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Permite borrar los datos de la TV sin previo aviso mediante el restablecimiento de la configuración de fábrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Eliminar los datos del dispositivo sin avisar y restablecer la configuración de fábrica"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Borrar los datos del usuario"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Permite borrar los datos del usuario en esta tablet sin previo aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Permite borrar los datos del usuario en esta televisión sin previo aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Permite borrar los datos del usuario en este teléfono sin previo aviso."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad del bloqueo de pantalla"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controlar la frecuencia con la que se debe cambiar la contraseña de bloqueo de pantalla"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Configura el proxy global de dispositivo que se usará mientras se habilita la política. Solo el propietario del dispositivo puede configurar el proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Config. vencimiento contraseña"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Permite modificar la frecuencia con que se cambia la contraseña, el PIN o el patrón de bloqueo de pantalla."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Establecer la encriptación del almacenamiento"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exige que se encripten los datos de la aplicación almacenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desactivar cámaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evita el uso de todas las cámaras del dispositivo."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Desactiv. funciones en bloqueo"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Evita el uso de algunas funciones con el bloqueo del teclado."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Inhabilitar funciones bloqueo"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Permite evitar el uso de algunas funciones de bloqueo de pantalla."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Móvil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> desea activar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el dispositivo."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace 1 mes."</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Anterior a 1 mes atrás"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto."</item>
-    <item quantity="other" msgid="2176942008915455116">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hace 1 hora."</item>
-    <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas."</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Quedan <xliff:g id="COUNT_1">%d</xliff:g> días.</item>
+      <item quantity="one">Queda <xliff:g id="COUNT_0">%d</xliff:g> día.</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Último mes"</string>
     <string name="older" msgid="5211975022815554840">"Antiguos"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ayer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días."</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"en 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"en 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañana"</item>
-    <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hace 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Hace 1 hora."</item>
-    <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ayer"</item>
-    <item quantity="other" msgid="3453342639616481191">"Hace <xliff:g id="COUNT">%d</xliff:g> días."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"en 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"en 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañana"</item>
-    <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semanas"</string>
     <string name="year" msgid="4001118221013892076">"año"</string>
     <string name="years" msgid="6881577717993213522">"años"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">1 segundo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+      <item quantity="one">1 minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+      <item quantity="one">1 hora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problemas de video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"No es posible transmitir este video al dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el video."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Iniciando Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamiento"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando la aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando el inicio"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Inicio <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Interrumpe la aplicación anterior sin guardar los cambios."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Seleccionar una acción para el texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volumen de los medios"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tono de llamada desconocido"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Red disponible de Wi-Fi"</item>
-    <item quantity="other" msgid="4192424489168397386">"redes disponibles de Wi-Fi"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Abrir red disponible de Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"Abrir redes disponibles de Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">redes de Wi-Fi disponibles</item>
+      <item quantity="one">red de Wi-Fi disponible</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Abrir redes de Wi-Fi disponibles</item>
+      <item quantity="one">Abrir red de Wi-Fi disponible</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Accede a una red Wi-Fi."</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Acceder a la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere conectarse a la red Wi-Fi %2$s."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se pudo iniciar Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como un dispositivo de medios"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Conectado como dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como un instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toca para acceder a otras opciones de USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Omitir"</string>
     <string name="no_matches" msgid="8129421908915840737">"Sin coincidencias"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Buscar en la página"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 coincidencia"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 coincidencia</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Listo"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Desactivando almacenamiento USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Desactivando tarjeta SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los PIN no coinciden. Vuelve a intentarlo."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Intentar en 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Intentar en <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Vuelve a intentarlo en <xliff:g id="COUNT">%d</xliff:g> segundos.</item>
+      <item quantity="one">Vuelve a intentarlo en 1 segundo.</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vuelve a intentar más tarde."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualización en pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string>
     <string name="done_label" msgid="2093726099505892398">"Listo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para dejar de fijar esta pantalla, mantén presionados los botones para volver y Recientes al mismo tiempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para dejar de fijar esta pantalla, mantén presionado el botón Recientes."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La pantalla está fija. La organización no permite dejar de fijar la pantalla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla no fija"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización no puedan actualizarse, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hasta que termine el tiempo de inactividad a la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hasta que finalice el tiempo de inactividad"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Durante 1 minuto; hasta la(s) <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>"</item>
-    <item quantity="other" msgid="2787867221129368935">"Durante %1$d minutos; hasta la(s) <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Durante 1 hora; hasta la(s) <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>"</item>
-    <item quantity="other" msgid="2827214920627669898">"Durante %1$d horas; hasta la(s) <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Durante %1$d minutos hasta la(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g></item>
+      <item quantity="one">Durante 1 minuto; hasta la(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g></item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Durante %1$d horas, hasta la(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g></item>
+      <item quantity="one">Durante 1 hora; hasta la(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g></item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Durante %d minutos</item>
+      <item quantity="one">Durante un minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Durante %d horas</item>
+      <item quantity="one">Durante 1 hora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hasta la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidamente"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Contraer"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hasta la próxima alarma a la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hasta la próxima alarma"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS cambió por una solicitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS cambió por una solicitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS cambió por una nueva solicitud SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Puerto USB de periféricos"</string>
 </resources>
diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml
index d73a715..ca16aa0 100755
--- a/core/res/res/values-es/donottranslate-cldr.xml
+++ b/core/res/res/values-es/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d/%m/%Y, %H:%M:%S</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cb8549c..df148a0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sin título&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Sin número de teléfono)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Desconocido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Buzón de voz"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"La tarjeta SIM está bloqueada con el código PUK. Introduce el código PUK para desbloquearla."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Introduce el código PUK2 para desbloquear la tarjeta SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Error, habilitar bloqueo de SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Te queda <xliff:g id="NUMBER">%d</xliff:g> intento para bloquear la tarjeta SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"Quedan <xliff:g id="NUMBER">%d</xliff:g> intentos para bloquear la tarjeta SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para bloquear la tarjeta SIM.</item>
+      <item quantity="one">Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para bloquear la tarjeta SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID de emisor de llamada entrante"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión activado. Desactivar"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ajustes"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt; 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"enlazar con un servicio de proveedor de rutas"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite enlazar con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"enlazar a una entrada de TV"</string>
@@ -541,9 +542,9 @@
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite que la aplicación acceda a otros comandos del proveedor de ubicación. De esta forma, la aplicación podrá interferir en el funcionamiento del GPS o de otras fuentes de ubicación."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"permiso para instalar un proveedor de ubicación"</string>
     <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Permite crear fuentes de ubicación simuladas para hacer pruebas o instalar un nuevo proveedor de ubicación. Este permiso autoriza a la aplicación a sobrescribir la ubicación o el estado proporcionados por otras fuentes de ubicación, como los proveedores de ubicación o GPS."</string>
-    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"ubicación precisa (basada en red y GPS)"</string>
+    <string name="permlab_accessFineLocation" msgid="1191898061965273372">"ubicación precisa (basada en redes y GPS)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite que la aplicación obtenga tu ubicación precisa mediante el Sistema de posicionamiento global (GPS) o fuentes de ubicación de red, como torres de telefonía y redes Wi-Fi. Estos servicios de ubicación deben estar activados y disponibles para que la aplicación pueda utilizarlos. Las aplicaciones pueden utilizar este permiso para determinar tu ubicación y es posible que el dispositivo consuma más batería."</string>
-    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"ubicación aproximada (basada en red)"</string>
+    <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"ubicación aproximada (basada en redes)"</string>
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite que la aplicación obtenga tu ubicación aproximada. Esta ubicación se deriva de los servicios de ubicación que utilizan fuentes de ubicación de red, como torres de telefonía y redes Wi-Fi. Estos servicios de ubicación deben estar activados y disponibles para que la aplicación pueda utilizarlos. Las aplicaciones pueden utilizar este permiso para determinar tu ubicación de forma aproximada."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación use funciones de SurfaceFlinger de nivel inferior."</string>
@@ -689,7 +690,7 @@
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"Permite que la aplicación solicite tokens de autenticación."</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"ver conexiones de red"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Permite que la aplicación vea información sobre conexiones de red (por ejemplo, qué redes existen y están conectadas)."</string>
-    <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"acceso completo a red"</string>
+    <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"acceso completo a la red"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permite que la aplicación cree sockets de red y utilice protocolos de red personalizados. El navegador y otras aplicaciones proporcionan los medios necesarios para el envío de datos a Internet, por lo que no hace falta utilizar este permiso para eso."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"cambiar/interceptar el tráfico y la configuración de red"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Permite que la aplicación modifique los ajustes de red y que intercepte e inspeccione todo el tráfico de red para, por ejemplo, cambiar el proxy y el puerto de cualquier APN. Las aplicaciones malintencionadas pueden controlar, redirigir o modificar los paquetes de red sin el consentimiento del usuario."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"inhabilitar el bloqueo de pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Por ejemplo, el teléfono puede inhabilitar el bloqueo del teclado cuando se recibe una llamada telefónica y volver a habilitarlo cuando finaliza la llamada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"administrar hardware de huellas digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que la aplicación invoque métodos para añadir y eliminar plantillas de huellas digitales y utilizarlas."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizar hardware de huellas digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar y desactivar la sincronización"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"enlazar con un servicio de destino selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que el titular enlace con la interfaz de nivel superior de un servicio de destino selector. Las aplicaciones normales no deberían necesitar nunca este permiso."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"enlazar a un servicio de rutas multimedia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite enlazar con la interfaz de nivel superior de un servicio de rutas multimedia. No debe ser necesario para las aplicaciones normales."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"enlazar con un servicio de salvapantallas"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite enlazar con la interfaz de nivel superior de un servicio de salvapantallas. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"enlazar con el servicio de mensajería de un operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite enlazar con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla la longitud y los caracteres permitidos en los PIN y en las contraseñas de bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Controla el número de contraseñas incorrectas introducidas al desbloquear la pantalla y bloquea el tablet o elimina todos sus datos si se introducen demasiadas contraseñas incorrectas."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Controla el número de contraseñas incorrectas introducidas al desbloquear la pantalla y bloquea la TV o borra todos los datos de la TV si se introducen demasiadas contraseñas incorrectas."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla el número de contraseñas incorrectas introducidas al desbloquear la pantalla y bloquea el teléfono o elimina todos sus datos si se introducen demasiadas contraseñas incorrectas."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Modificación de contraseña de bloqueo de pantalla"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Modificar la contraseña de bloqueo de pantalla"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Controla el número de contraseñas incorrectas introducidas para desbloquear la pantalla y bloquea el tablet o borra todos los datos del usuario si se introducen demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Controla el número de contraseñas incorrectas introducidas para desbloquear la pantalla y bloquea la TV o borra todos los datos del usuario si se introducen demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Controla el número de contraseñas incorrectas introducidas para desbloquear la pantalla y bloquea el teléfono o borra todos los datos del usuario si se introducen demasiadas contraseñas incorrectas."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Cambiar el bloqueo de pantalla"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Cambia el bloqueo de pantalla."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloqueo de pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar cómo y cuándo se bloquea la pantalla"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos los datos"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar los datos del tablet sin avisar restableciendo datos de fábrica"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Borra los datos de la TV sin advertencia previa restableciendo la TV a los valores predeterminados de fábrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Borrar datos del usuario"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Borra los datos del usuario en este tablet sin avisar."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Borra los datos del usuario en esta TV sin avisar."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Borra los datos del usuario en este teléfono sin avisar."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor proxy global"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad bloqueo pantalla"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controlar la frecuencia con la que se debe cambiar el bloqueo de la pantalla"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el propietario del dispositivo puede definir el proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Definir caducidad contraseña"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Cambia la frecuencia con la que se debe cambiar el patrón, el PIN o la contraseña del bloqueo de pantalla."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Cifrado del almacenamiento"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exige que se cifren los datos de la aplicación almacenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Inhabilitar cámaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evitar el uso de las cámaras del dispositivo"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Inhabilitar funciones en bloqueo"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Evita el uso de algunas funciones durante el bloqueo."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desactivar funciones bloqueo"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Evita el uso de algunas funciones del bloqueo de pantalla."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Móvil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quiere habilitar la exploración táctil. Cuando esta función esté activada, podrás escuchar o ver descripciones del contenido seleccionado o usar gestos para interactuar con el teléfono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hace un mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hace más de un mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Hace 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"Hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Hace 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hace 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g> últimos días</item>
+      <item quantity="one">Último día (<xliff:g id="COUNT_0">%d</xliff:g>)</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"El mes pasado"</string>
     <string name="older" msgid="5211975022815554840">"Anterior"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Ayer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dentro de 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dentro de 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dentro de 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"dentro de <xliff:g id="COUNT">%d</xliff:g>  horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañana"</item>
-    <item quantity="other" msgid="5109449375100953247">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hace 1 segundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hace 1 minuto"</item>
-    <item quantity="other" msgid="851164968597150710">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"hace 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"Ayer"</item>
-    <item quantity="other" msgid="3453342639616481191">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dentro de 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dentro de 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dentro de 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañana"</item>
-    <item quantity="other" msgid="2973062968038355991">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"el <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semanas"</string>
     <string name="year" msgid="4001118221013892076">"año"</string>
     <string name="years" msgid="6881577717993213522">"años"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">1 segundo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+      <item quantity="one">1 minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+      <item quantity="one">1 hora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Incidencias con el vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo no se puede transmitir al dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"No se puede reproducir el vídeo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android se está iniciando…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamiento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>..."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalizando inicio..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"No iniciar la nueva aplicación"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Detener la aplicación anterior sin guardar"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Selecciona una acción para el texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volumen del timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volumen multimedia"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tono desconocido"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Red Wi-Fi disponible"</item>
-    <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponibles"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Red Wi-Fi abierta disponible"</item>
-    <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abiertas disponibles"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Redes Wi-Fi disponibles</item>
+      <item quantity="one">Red Wi-Fi disponible</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Redes Wi-Fi abiertas disponibles</item>
+      <item quantity="one">Red Wi-Fi abierta disponible</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Iniciar sesión en red Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Iniciar sesión en la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere establecer conexión con la red Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se ha podido iniciar Wi-Fi Direct."</string>
@@ -1388,7 +1353,7 @@
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NUEVO:"</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"Proporcionado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
-    <string name="perm_costs_money" msgid="4902470324142151116">"es posible que se cobre por usar la aplicación."</string>
+    <string name="perm_costs_money" msgid="4902470324142151116">"es posible que esto te cueste dinero"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"Almacenamiento USB masivo"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"Conexión por USB"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Has conectado el dispositivo al ordenador por USB. Toca el siguiente botón si quieres transferir archivos entre el ordenador y el almacenamiento USB del dispositivo."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como dispositivo multimedia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Conectado como dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toca para acceder a otras opciones de USB"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Saltar"</string>
     <string name="no_matches" msgid="8129421908915840737">"No hay coincidencias."</string>
     <string name="find_on_page" msgid="1946799233822820384">"Buscar en la página"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Una coincidencia"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 coincidencia</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Listo"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Desactivando almacenamiento USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Desactivando tarjeta SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crear PIN para modificar restricciones"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Los números PIN no coinciden. Inténtalo de nuevo."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"El PIN es demasiado corto. Debe tener al menos 4 dígitos."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Inténtalo en 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Inténtalo en <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Vuelve a intentarlo en <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">Vuelve a intentarlo en 1 segundo</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Volver a intentar más tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Desliza el dedo hacia abajo para salir de la pantalla completa"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Mostrando pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para salir, desliza el dedo hacia abajo desde la parte superior de la pantalla."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendido"</string>
     <string name="done_label" msgid="2093726099505892398">"Listo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control deslizante circular de horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para desactivar esta pantalla, mantén pulsados los botones de retroceso y Visión general al mismo tiempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para desactivar esta pantalla, mantén pulsado Visión general."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Se ha activado la pantalla. Tu organización no puede desactivarla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fijada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"La pantalla ya no está fija"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hasta que el tiempo de inactividad finalice el <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hasta que finalice el tiempo de inactividad"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Durante un minuto (hasta las <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Durante %1$d minutos (hasta las <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Durante una hora (hasta las <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Durante %1$d horas (hasta las <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Durante 1 hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Durante %1$d minutos (hasta las <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante un minuto (hasta las <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Durante %1$d horas (hasta las <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante una hora (hasta las <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Durante %d minutos</item>
+      <item quantity="one">Durante un minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Durante %d horas</item>
+      <item quantity="one">Durante una hora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidamente"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Contraer"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hasta la próxima alarma a las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hasta la próxima alarma"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La solicitud SS se ha modificado para la solicitud DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La solicitud SS se ha modificado para la solicitud USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La solicitud SS se ha modificado para la nueva solicitud SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Puerto periférico USB"</string>
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 36d8b89..a428496 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Pealkirjata&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefoninumbrit pole)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Teadmata"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Kõnepost"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-kaart on PUK-lukustatud. Avamiseks sisestage PUK-kood."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Sisestage SIM-kaardi blokeeringu tühistamiseks PUK2-kood."</string>
     <string name="enablePin" msgid="209412020907207950">"Ebaõnnestus, SIM-i/RUIM-i lukustuse lubamine."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Teil on enne SIM-i lukustumist jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katse."</item>
-    <item quantity="other" msgid="7530597808358774740">"Teil on enne SIM-i lukustumist jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katset."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Teil on enne SIM-kaardi lukustumist jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
+      <item quantity="one">Teil on enne SIM-kaardi lukustumist jäänud veel <xliff:g id="NUMBER_0">%d</xliff:g> katse.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Sissetuleva kõne helistaja ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"sidumine marsruudi pakkumisteenusega"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Lubab õiguste omajal luua seosed kõikide registreeritud marsruutide pakkujatega. Pole kunagi vajalik tavaliste rakenduste korral."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"sidumine TV-sisendiga"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Võimaldab rakendusel suhelda lähiväljaside (NFC) märgendite, kaartide ja lugeritega."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"keelake ekraanilukk"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Võimaldab rakendusel keelata klahviluku ja muu seotud parooli turvalisuse. Näiteks keelab telefon klahviluku sissetuleva kõne vastuvõtmisel ja lubab klahviluku uuesti, kui kõne on lõpetatud."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"sõrmejälje riistvara haldamine"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Võimaldab rakendusel tühistada meetodid kasutatavate sõrmejäljemallide lisamiseks ja kustutamiseks."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"sõrmejälje riistvara kasutamine"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Võimaldab rakendusel autentimiseks kasutada sõrmejälje riistvara"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"loe sünkroonimisseadeid"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Võimaldab rakendusel lugeda konto sünkroonimisseadeid. Näiteks võib see määrata, kas rakendus Inimesed on kontoga sünkroonitud."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"lülitage sünkroonimine sisse ja välja"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"valija sihtteenusega sidumine"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Võimaldab omanikul siduda valija sihtteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"seo tingimuse pakkuja teenusega"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lubab omanikul siduda tingimuse pakkuja teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"meediumi marsruutimise teenusega sidumine"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Lubab omanikul siduda meediumi marsruutimise teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"sidumine uneteenusega"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Lubab omanikul siduda uneteenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operaatoripoolse konfiguratsioonirakenduse aktiveerimine"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"seose loomine operaatori sõnumisideteenusega"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Lubab omanikul luua seose operaatori sõnumisideteenuse ülataseme liidesega. Pole kunagi vajalik tavalise rakenduse puhul."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Juhitakse ekraaniluku paroolide ja PIN-koodide pikkusi ning lubatud tähemärkide seadeid."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab tahvelarvuti või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Ekraani avamiseks valesti sisestatud paroolide arvu jälgimine ja teleri lukustamine või teleri andmete kustutamine, kui parool sisestatakse liiga mitu korda valesti."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab telefoni või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekraaniluku parooli muutmine"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekraaniluku parooli muutmine."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Jälgitakse ekraani avamisel sisestatud valede paroolide arvu ja lukustatakse tahvelarvuti või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Jälgitakse ekraani avamisel sisestatud valede paroolide arvu ja lukustatakse teler või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Jälgitakse ekraani avamisel sisestatud valede paroolide arvu ja lukustatakse telefon või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Ekraaniluku muutmine"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Muudetakse ekraanilukku."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Ekraani lukustamine"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Määrake, kuidas ja millal ekraan lukustub."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Kõikide andmete kustutamine"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Kustutage tahvelarvuti andmed hoiatamata, lähtestades arvuti tehaseandmetele."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Teleri andmete hoiatamata kustutamine tehase andmetele lähtestamise abil."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Kustuta telefoniandmed hoiatuseta, lähtestades telefoni tehaseandmetele."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Kasutaja andmete kustutamine"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Kustutatakse selle kasutaja andmed sellest tahvelarvutist ilma hoiatamata."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Kustutatakse selle kasutaja andmed sellest telerist ilma hoiatamata."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Kustutatakse selle kasutaja andmed sellest telefonist ilma hoiatamata."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Määra seadme globaalne puhverserver"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Eeskirjade lubamise ajal kasutatava seadme globaalse puhverserveri määramine. Ainult esimese seadme administraator määrab tõhusa globaalse puhverserveri."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekraaniluku parooli aegumise määramine"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Määrake ekraaniluku parooli muutmissagedus."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Määratakse kasutatava seadme üldine puhverserver, kui reegel on lubatud. Üldise puhverserveri saab määrata ainult seadme omanik."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ekraaniluku parooli aegum. määram."</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Muudetakse ekraaniluku parooli, PIN-koodi või mustri kohustusliku muutmise sagedust."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Salvestamise krüpt. määramine"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Nõua salvestatud rakenduse andmete krüpteerimist."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Keela kaamerad"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vältige seadme kõigi kaamerate kasutamist."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Klahviluku funkts. keelamine"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Takistage klahviluku mõne funktsiooni kasutamist."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Ekraaniluku funkts. keelamine"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Takistatakse ekraaniluku mõne funktsiooni kasutamist."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Kodu"</item>
     <item msgid="869923650527136615">"Mobiil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> soovib lubada puudutusega uurimise. Kui puudutusega uurimine on sisse lülitatud, kuulete või näete kirjeldusi asjade kohta, mis on teie sõrme all, või saate suhelda telefoniga liigutuste abil."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 kuu tagasi"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Varem kui 1 kuu tagasi"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekund tagasi"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minut tagasi"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 tund tagasi"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Viimased <xliff:g id="COUNT">%d</xliff:g> päeva"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Viimased <xliff:g id="COUNT_1">%d</xliff:g> päeva</item>
+      <item quantity="one">Viimane <xliff:g id="COUNT_0">%d</xliff:g> päev</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Eelmisel kuul"</string>
     <string name="older" msgid="5211975022815554840">"Vanem"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"eile"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 sekundi pärast"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 minuti pärast"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 tunni pärast"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"homme"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 s tagasi"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sekundit tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minut tagasi"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutit tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 tund tagasi"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tundi tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"eile"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päeva tagasi"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 sekundi pärast"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 minuti pärast"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minuti pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 tunni pärast"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunni pärast"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"homme"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päeva pärast"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"kuupäeval <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kell <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"aastal <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"nädalat"</string>
     <string name="year" msgid="4001118221013892076">"aasta"</string>
     <string name="years" msgid="6881577717993213522">"aastat"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekund"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekundit"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutit"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 tund"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> tundi"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundit</item>
+      <item quantity="one">1 sekund</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutit</item>
+      <item quantity="one">1 minut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tundi</item>
+      <item quantity="one">1 tund</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem videoga"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"See video ei sobi voogesituseks selles seadmes."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videot ei saa esitada."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android käivitub ..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Salvestusruumi optimeerimine."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>. rakenduse <xliff:g id="NUMBER_1">%2$d</xliff:g>-st optimeerimine."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Rakenduse <xliff:g id="APPNAME">%1$s</xliff:g> ettevalmistamine."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Rakenduste käivitamine."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Käivitamise lõpuleviimine."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> töötab"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Valige teksti jaoks toiming"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Helina helitugevus"</string>
     <string name="volume_music" msgid="5421651157138628171">"Meediumi helitugevus"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Puudub"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Helinad"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tundmatu helin"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"WiFi-võrk on saadaval"</item>
-    <item quantity="other" msgid="4192424489168397386">"WiFi-võrgud saadaval"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Avatud WiFi võrk on saadaval"</item>
-    <item quantity="other" msgid="7915895323644292768">"Avatud WiFi-võrgud on saadaval"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">WiFi-võrgud on saadaval</item>
+      <item quantity="one">WiFi-võrk on saadaval</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Avatud WiFi-võrgud on saadaval</item>
+      <item quantity="one">Avatud WiFi-võrk on saadaval</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Logige sisse WiFi-võrku"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Logige võrku"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Rakendus %1$s soovib luua ühenduse WiFi-võrguga %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Rakendus"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ühendatud meediumiseadmena"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ühendatud kaamerana"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Ühendatud MIDI-seadmena"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ühendatud installijana"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ühendatud USB-lisaseadmega"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Puudutage teisi USB valikuid."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Jäta vahele"</string>
     <string name="no_matches" msgid="8129421908915840737">"Vasted puuduvad"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Otsige lehelt"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 vaste"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> vastet <xliff:g id="TOTAL">%d</xliff:g>-st</item>
+      <item quantity="one">1 vaste</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Valmis"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB-salvestusruumi eemaldamine ..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-kaardi eemaldamine ..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Looge PIN-kood piirangute muutmiseks"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kood ei sobi. Proovige uuesti."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-kood on liiga lühike. Peab olema vähemalt 4-kohaline."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Proovige uuesti 1 sekundi pärast"</item>
-    <item quantity="other" msgid="4730868920742952817">"Proovige uuesti <xliff:g id="COUNT">%d</xliff:g> sekundi pärast"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Proovige uuesti <xliff:g id="COUNT">%d</xliff:g> sekundi pärast</item>
+      <item quantity="one">Proovige uuesti 1 sekundi pärast</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Proovige hiljem uuesti"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Täisekraanilt väljumiseks pühkige ülevalt alla."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Kuvamine täisekraanil"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Väljumiseks pühkige ülevalt alla."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Selge"</string>
     <string name="done_label" msgid="2093726099505892398">"Valmis"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ringikujuline tunniliugur"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Ringikujuline minutiliugur"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ekraanikuva vabastamiseks puudutage pikalt samal ajal nuppe Tagasi ja Ülevaade."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ekraanikuva vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekraan on kinnitatud. Teie organisatsioon ei luba vabastamist."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekraan on vabastatud"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kuni seisakuaja lõppemiseni kell <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kuni puhkeaja lõpuni"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Üheks minutiks (kuni <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d minutiks (kuni <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Üheks tunniks (kuni <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d tunniks (kuni <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d minutiks"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Üheks tunniks"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d tunniks"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d minutiks (kuni <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Üheks minutiks (kuni <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d tunniks (kuni <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Üheks tunniks (kuni <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d minutiks</item>
+      <item quantity="one">Üheks minutiks</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d tunniks</item>
+      <item quantity="one">Üheks tunniks</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Määramata ajaks"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Ahendamine"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Kuni järgmise alarmini <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Kuni järgmise alarmini"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-päring muudeti DIAL-päringuks."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-päring muudeti USSD-päringuks."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-päring muudeti uueks SS-päringuks."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Väline USB-port"</string>
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 00e15e3..953a5fa 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Izengabea&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ez dago telefono-zenbakirik)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Ezezaguna"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Erantzungailua"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM txartela PUK bidez blokeatuta duzu. Desblokeatzeko, idatzi PUK kodea."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM txartela desblokeatzeko, idatzi PUK2 kodea."</string>
     <string name="enablePin" msgid="209412020907207950">"Ezin izan da aldatu. Gaitu SIM edo RUIM txartelaren blokeoa."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"<xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizu SIM txartela blokeatu aurretik."</item>
-    <item quantity="other" msgid="7530597808358774740">"<xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela blokeatu aurretik."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela blokeatu aurretik.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela blokeatu aurretik.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Sarrerako deien identifikazio-zerbitzua"</string>
@@ -192,9 +190,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoaren aukerak"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Pantailaren blokeoa"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
-    <string name="global_action_bug_report" msgid="7934010578922304799">"Programa-akatsen txostena"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"Sortu programa-akatsen txostena"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira programa-akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
+    <string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Isilik modua"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Soinua DESAKTIBATUTA dago"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Soinua AKTIBATUTA dago"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hegaldi modua AKTIBATUTA dago"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hegaldi modua DESAKTIBATUTA dago"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ezarpenak"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ahots-laguntza"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
@@ -426,11 +425,13 @@
     <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Lotu ahots bidezko elkarrekintzako zerbitzuei"</string>
     <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ahots bidezko elkarrekintzako zerbitzu baten goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"kudeatu ahozko gako-esaldiak"</string>
-    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ahoz esandako gako-hitzak hautemateko gako-esaldiak kudeatzea baimentzen die aplikazioei. Aplikazio normalek ez lukete behar."</string>
+    <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ahozko pasahitzak hautemateko gako-esaldiak kudeatzea baimentzen die aplikazioei. Aplikazio normalek ez lukete behar."</string>
     <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Lotu urruneko pantaila batera"</string>
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Urruneko pantaila baten goi-mailako interfazera lotzeko aukera ematen dio titularrari. Aplikazio normalek ez dute baimen hau behar."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"lotu widget-zerbitzu batekin"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Widget-zerbitzu baten goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Lotu ibilbide-hornitzaileen zerbitzuei"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Erregistratutako ibilbide-hornitzaileei lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"aritu elkarlanean gailu baten administratzailearekin"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Gailu-administratzaileei xedeak bidaltzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"Lotu telebista-sarrerei"</string>
@@ -559,7 +560,7 @@
     <string name="permdesc_controlVpn" msgid="762852603315861214">"Sare pribatu birtualen behe-mailako eginbideak kontrolatzea baimentzen die aplikazioei."</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"Grabatu audio-irteera"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Audio-irteera grabatzeko eta birbideratzeko aukera ematen die aplikazioei."</string>
-    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hauteman Hotword"</string>
+    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hauteman ahozko pasahitza"</string>
     <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Hotword bidez hauteman daitekeen audioa grabatzeko aukera ematen die aplikazioei. Atzeko planoan grabatzeak ez du bestelako audio-grabazioak (adibidez, bideokamera bidezkoak) egitea eragozten."</string>
     <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audio-bideratzea"</string>
     <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Audio-bideratzea zuzenean kontrolatzea eta audio-gidalerroei gainjartzea baimentzen die aplikazioei."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Near Field Communication (NFC) etiketekin, txartelekin eta irakurgailuekin komunikatzea baimentzen die aplikazioei."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"pantailaren blokeoa desgaitzea"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Teklen blokeoa eta erlazionatutako pasahitz-segurtasuna desgaitzeko baimena ematen die aplikazioei. Adibidez, telefonoak teklen blokeoa desgaitzen du telefono-deiak jasotzen dituenean, eta berriro gaitzen du deiak amaitzean."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Kudeatu hatz-marka digitalen hardwarea"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Hatz-marka digitalen txantiloiak gehitzeko eta ezabatzeko metodoei dei egitea baimentzen die aplikazioei."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Erabili hatz-marka digitalen hardwarea"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autentifikatzeko hatz-marka digitalen hardwarea erabiltzea baimentzen die aplikazioei."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Irakurri sinkronizazio-ezarpenak"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen die aplikazioei. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"sinkronizazioa aktibatzea eta desaktibatzea"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Jakinarazpenak berreskuratu, aztertu eta garbitzeko aukera ematen die aplikazioei, beste aplikazioek argitaratutako jakinarazpenak barne."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Lotu jakinarazpenak hautemateko zerbitzu batera"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Jakinarazpenak hautemateko zerbitzu baten goi-mailako interfazera lotzeko aukera ematen dio titularrari. Aplikazio normalek ez dute baimen hau behar."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Lotu hautatzailearen zerbitzu jakin batera"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Zerbitzu jakin baten goi-mailako interfazera lotzea baimentzen die titularrei. Aplikazio normalek ez dute baimen hau behar."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Lotu baldintza-hornitzaileen zerbitzuei"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Baldintza-hornitzaileen zerbitzuen goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"lotetsi multimedia-irteerako zerbitzu bati"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Multimedia-irteerako zerbitzu baten goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"lotu dream zerbitzuei"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Dream zerbitzu baten goi-mailako interfazeari lotzea baimentzen die titularrei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Deitu operadorearen konfigurazio-aplikazioari"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"lotu operadorearen mezularitza-zerbitzuari"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Operadore baten mezularitza-zerbitzuaren goi-mailako interfazeari lotzea baimentzen die erabiltzaileei. Aplikazio normalek ez lukete inoiz beharko."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolatu pantaila desblokeatzeko pasahitzen luzera eta onartutako karaktereak."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolatu pantaila blokeoaren pasahitzen eta PINen luzera eta onartutako karaktereak."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Kontrolatu pantaila desblokeatzeko saiakerak"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu tableta edo ezabatu bere datuak pasahitza gehiegitan oker idazten bada."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu telebista edo ezabatu haren datuak pasahitza gehiegitan oker idazten bada."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu telefonoa edo ezabatu bere datuak pasahitza gehiegitan oker idazten bada."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Aldatu pantaila desblokeatzeko pasahitza"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Aldatu pantaila desblokeatzeko pasahitza."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu tableta edo ezabatu erabiltzailearen datuak pasahitza gehiegitan oker idazten bada."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu telebista edo ezabatu erabiltzailearen datuak pasahitza gehiegitan oker idazten bada."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Kontrolatu pantaila desblokeatzen saiatzean idatzitako pasahitz oker kopurua, eta blokeatu telefonoa edo ezabatu erabiltzailearen datuak pasahitza gehiegitan oker idazten bada."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Aldatu pantailaren blokeoa"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Aldatu pantailaren blokeoa."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Blokeatu pantaila"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolatu pantaila nola eta noiz blokeatzen den."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Ezabatu datu guztiak"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ezabatu tabletaren datuak abisatu gabe, jatorrizko datuak berrezarrita."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Ezabatu telebistaren datuak abisatu gabe, jatorrizko datuak berrezarrita."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ezabatu telefonoaren datuak abisatu gabe, jatorrizko datuak berrezarrita."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Ezabatu erabiltzailearen datuak"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ezabatu erabiltzaileak tabletan dituen datuak abisatu gabe."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ezabatu erabiltzaileak telebistan dituen datuak abisatu gabe."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Ezabatu erabiltzaileak telefonoan dituen datuak abisatu gabe."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ezarri gailuaren proxy orokorra"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ezarri gailuaren proxy orokorra gidalerroak gaituta dauden bitartean erabiltzeko. Gailuaren lehen administratzaileak soilik ezartzen du proxy orokor eraginkorra."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ezarri blokeatzeko pasahitzaren iraungitzea"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontrolatu pantaila blokeatuko pasahitza aldatu beharreko maiztasuna."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Ezarri gailuaren proxy orokorra gidalerroak gaituta dauden bitartean erabiltzeko. Gailuaren jabeak soilik ezar dezake proxy orokorra."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ezarri pasahitzaren iraungitzea"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Aldatu pantaila blokeatuko pasahitza, PINa edo eredua aldatu beharreko maiztasuna."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ezarri memoria-enkriptatzea"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Eskatu gordetako aplikazio-datuak enkriptatzea."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desgaitu kamerak"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Eragotzi gailuaren kamerak erabiltzea."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Teklen blokeoko eginbideak desgaitzea"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Eragotzi teklen blokeoko eginbide batzuk erabiltzea."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desgaitu blokeoko eginbideak"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Eragotzi pantailaren blokeoko eginbide batzuk erabiltzea."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Etxekoa"</item>
     <item msgid="869923650527136615">"Mugikorra"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> zerbitzuak \"Arakatu ukituta\" eginbidea gaitu nahi du. Eginbide hori aktibatuta dagoenean, hatzaren azpian duzunaren azalpena ikus edo entzun dezakezu, edo telefonoarekin elkarrekintzan aritzeko keinuak egin ditzakezu."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Duela hilabete"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Duela hilabete baino gutxiago"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"duela segundo bat"</item>
-    <item quantity="other" msgid="3903706804349556379">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"duela minutu bat"</item>
-    <item quantity="other" msgid="2176942008915455116">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Duela ordubete"</item>
-    <item quantity="other" msgid="2467273239587587569">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"azken <xliff:g id="COUNT">%d</xliff:g> egunak"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Azken <xliff:g id="COUNT_1">%d</xliff:g> egunetan</item>
+      <item quantity="one">Azken <xliff:g id="COUNT_0">%d</xliff:g> egunean</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Azken hilabetea"</string>
     <string name="older" msgid="5211975022815554840">"Zaharragoa"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"atzo"</item>
-    <item quantity="other" msgid="2479586466153314633">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"segundo bat barru"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"Minutu bat barru"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"Ordubete barru"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"bihar"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"duela segundo bat"</item>
-    <item quantity="other" msgid="3699169366650930415">"duela <xliff:g id="COUNT">%d</xliff:g> segundo"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"duela minutu bat"</item>
-    <item quantity="other" msgid="851164968597150710">"duela <xliff:g id="COUNT">%d</xliff:g> minutu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"duela ordubete"</item>
-    <item quantity="other" msgid="6889970745748538901">"duela <xliff:g id="COUNT">%d</xliff:g> ordu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"atzo"</item>
-    <item quantity="other" msgid="3453342639616481191">"Duela <xliff:g id="COUNT">%d</xliff:g> egun"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"segundo bat barru"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> segundo barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"minutu bat barru"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> minutu barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ordubete barru"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ordu barru"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"bihar"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> egun barru"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"data: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"urtea: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"aste"</string>
     <string name="year" msgid="4001118221013892076">"urte"</string>
     <string name="years" msgid="6881577717993213522">"urte"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundo"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minutu"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutu"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ordu"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ordu"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundo</item>
+      <item quantity="one">Segundo bat</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutu</item>
+      <item quantity="one">Minutu bat</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ordu</item>
+      <item quantity="one">Ordubete</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Bideoak arazoren bat du"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Bideo hau ezin da gailuan zuzenean erreproduzitu."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ezin da bideoa erreproduzitu."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android abiarazten ari da…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Memoria optimizatzen."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> aplikazio optimizatzen."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> prestatzen."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikazioak abiarazten."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Bertsio-berritzea amaitzen."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ez abiarazi aplikazio berria."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Hasi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Gelditu aplikazio zaharra ezer gorde gabe."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Aukeratu testurako ekintza"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Tonu-jotzailearen bolumena"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multimedia-edukiaren bolumena"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Bat ere ez"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuak"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tonu ezezaguna"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi sarea erabilgarri"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi sareak erabilgarri"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Wi-Fi sare irekia erabilgarri"</item>
-    <item quantity="other" msgid="7915895323644292768">"Wi-Fi sare irekiak erabilgarri"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi sareak erabilgarri</item>
+      <item quantity="one">Wi-Fi sarea erabilgarri</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Wi-Fi sare irekiak erabilgarri</item>
+      <item quantity="one">Wi-Fi sare irekia erabilgarri</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Hasi saioa Wi-Fi sarean"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Hasi saioa sarean"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Interneteko konexio txarra du."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzea baimendu nahi diozu?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s aplikazioak %2$s Wi-Fi sarera konektatu nahi du"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikazio bat"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Hasi Wi-Fi Direct. Wi-Fi bezeroa edo sare publikoa desaktibatuko da."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Ezin izan da Wi-Fi Direct hasi."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Ados"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Multimedia-gailu gisa konektatua"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kamera gisa konektatua"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI gailu gisa konektatu da"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Instalatzaile gisa konektatua"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB osagarri batera konektatuta"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Ukitu beste USB aukera batzuk ikusteko."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Saltatu"</string>
     <string name="no_matches" msgid="8129421908915840737">"Ez dago emaitzarik"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Aurkitu orri honetan"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Emaitza bat"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">Emaitza bat</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Eginda"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB memoria desmuntatzen…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD txartela desmuntatzen…"</string>
@@ -1660,7 +1626,7 @@
     <string name="media_route_status_available" msgid="6983258067194649391">"Erabilgarri"</string>
     <string name="media_route_status_not_available" msgid="6739899962681886401">"Ez dago erabilgarri"</string>
     <string name="media_route_status_in_use" msgid="4533786031090198063">"Abian"</string>
-    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantaila barneratua"</string>
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantaila integratua"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI pantaila"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>. gainjartzea"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Konfiguratu debekuak aldatu ahal izateko idatzi beharko den PIN kodea"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINak ez datoz bat. Saiatu berriro."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PINa laburregia da. 4 digitu izan behar ditu gutxienez."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Saiatu berriro segundo bat igarotakoan"</item>
-    <item quantity="other" msgid="4730868920742952817">"Saiatu berriro <xliff:g id="COUNT">%d</xliff:g> segundo igarotakoan"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Saiatu berriro <xliff:g id="COUNT">%d</xliff:g> segundo igarotakoan</item>
+      <item quantity="one">Saiatu berriro segundo bat igarotakoan</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Saiatu berriro geroago"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pantaila osotik irteteko, pasatu hatza goitik behera."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Pantaila osoan ikusten"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Irteteko, pasatu hatza goitik behera."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ados"</string>
     <string name="done_label" msgid="2093726099505892398">"Eginda"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ordua aukeratzeko ikuspegi zirkularra"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minutuak aukeratzeko ikuspegi zirkularra"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aingura kentzeko, eduki ukituta Atzera eta Ikuspegi orokorra botoiak aldi berean."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aingura kentzeko, eduki ukituta Ikuspegi orokorra botoia."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Pantaila ainguratu da. Erakundeak ez du aingura kentzea onartzen."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Aingura kendu zaio pantailari"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren funtzionamendua, dardara,  kokapen-zerbitzuak eta atzeko planoko datuen erabilera gehiena mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzen ezarri orduko desaktibatzen da bateria-aurrezlea."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte iraungo du jarduerarik gabeko aldiak"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jarduerarik gabeko denbora amaitu arte"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Minutu batez (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> arte)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d minutuz (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> arte)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Ordubetez (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> arte)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d orduz (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> arte)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Minutu batez"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d minutuz"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Ordubetez"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d orduz"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d minutuz (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> arte)</item>
+      <item quantity="one">Minutu batez (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> arte)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d orduz (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> arte)</item>
+      <item quantity="one">Ordubetez (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> arte)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d minutuz</item>
+      <item quantity="one">Minutu batez</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d orduz</item>
+      <item quantity="one">Ordubetez</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Mugagabea"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Zuk desaktibatu arte"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Tolestu"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hurrengo alarmara arte (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hurrengo alarmara arte"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS eskaera DIAL eskaerara aldatu da."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS eskaera USSD eskaerara aldatu da."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS eskaera SS eskaera berrira aldatu da."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ataka periferikoa"</string>
 </resources>
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
index bb77b31..2821cd5 100755
--- a/core/res/res/values-fa/donottranslate-cldr.xml
+++ b/core/res/res/values-fa/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S،‏ %Y/%-m/%-e</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index bfead99..7419f5b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانیه"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانیه"</string>
     <string name="untitled" msgid="4638956954852782576">"‏&lt;بدون عنوان&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(بدون شماره تلفن)"</string>
     <string name="unknownName" msgid="6867811765370350269">"نامشخص"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"پست صوتی"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"‏سیم کارت شما با PUK قفل شده است. کد PUK را برای بازگشایی آن بنویسید."</string>
     <string name="needPuk2" msgid="4526033371987193070">"‏PUK2 را برای بازگشایی قفل سیم کارت بنویسید."</string>
     <string name="enablePin" msgid="209412020907207950">"‏ناموفق بود، قفل سیم/RUIM را فعال کنید."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"<xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم کارت قفل می‌شود."</item>
-    <item quantity="other" msgid="7530597808358774740">"<xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم کارت قفل می‌شود."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم‌کارت قفل می‌شود.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم‌کارت قفل می‌شود.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"شناسه تماس گیرنده ورودی"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"تنظیمات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده ام‍ک‍ان می‌دهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامه‌های عادی لازم باشد."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"اتصال به یک سرویس ارائه‌دهنده مسیر"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"به دارنده امکان می‌دهد به هر ارائه‌دهنده مسیر ثبت شده‌ای متصل شود. هرگز برای برنامه‌های عادی مورد نیاز نیست."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"‏به دارنده اجازه می‎دهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامه‎های معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"اتصال به ورودی تلویزیون"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"‏به برنامه اجازه می‎دهد تا با تگهای ارتباط میدان نزدیک (NFC)، کارتها و فایل خوان ارتباط برقرار کند."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"غیرفعال کردن قفل صفحه شما"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"به برنامه امکان می‌دهد قفل کلید و هر گونه امنیت گذرواژه مرتبط را غیرفعال کند. به‌عنوان مثال تلفن هنگام دریافت یک تماس تلفنی ورودی قفل کلید را غیرفعال می‌کند و بعد از پایان تماس، قفل کلید را دوباره فعال می‌کند."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"مدیریت سخت‌افزار اثر انگشت"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"به برنامه امکان می‌دهد روش‌هایی را برای افزودن و حذف الگوهای اثر انگشت جهت استفاده، فعال کند."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"استفاده از سخت‌افزار اثر انگشت"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"به برنامه امکان می‌دهد از سخت‌افزار اثر انگشت برای احراز هویت استفاده کند"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگام‌سازی"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"به برنامه اجازه می‌دهد تنظیمات را برای یک حساب بخواند. به‌عنوان مثال، این ویژگی می‌تواند تعیین کند آیا حساب «افراد» شما با یک حساب همگام‌سازی شده است."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"تغییر وضعیت همگام‌سازی بین فعال و غیرفعال"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"اتصال به یک سرویس هدف‌یابی انتخابگر"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"به دارنده اجازه می‌دهد به رابط سطح بالای یک سرویس هدف‌یابی انتخابگر متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"مقید بودن به سرویس ارائه‌دهنده وضعیت"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"به دارنده امکان می‌دهد تا به واسط سطح بالای سرویس ارائه‌دهنده وضعیت مقید باشد. برای برنامه‌های عادی هرگز نباید لازم باشد."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"اتصال به یک سرویس مسیر رسانه‌ای"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"به دارنده امکان می‌دهد به واسط کاربر سطح بالای سرویس مسیر رسانه‌ای متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"اتصال به سرویس مورد نظر"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"به برنامه اجازه می‌دهد که به رابط سطح بالای سرویس مورد نظر متصل شود. هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"لغو برنامه پیکربندی ارائه شده توسط شرکت مخابراتی"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"مقید به سرویس پیام‌رسانی شرکت مخابراتی"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"به کنترل‌کننده اجازه می‌دهد که به سطح بالای رابط کاربر سرویس پیام‌رسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامه‌های عادی مورد نیاز شود."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"‏طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"کنترل طول و نوع نویسه‌هایی که در گذرواژه و پین قفل صفحه مجاز است."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"‏تعداد گذرواژه‎های نادرست تایپ شده را هنگام بازکردن قفل صفحه کنترل می‌کند، و اگر دفعات زیادی گذرواژه نادرست وارد شود رایانهٔ لوحی را قفل می‌کند و همه داده‎های رایانهٔ لوحی را پاک می‌کند."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"بر تعداد گذرواژه‌های نادرست تایپ‌شده در زمان باز کردن قفل صفحه نظارت کنید و اگر تعدا زیادی گذرواژه‌های اشتباه تایپ شده است، تلویزیون را قفل کنید یا همه داده‌های تلویزیون را پاک کنید."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"‏تعداد گذرواژه‎های نادرست تایپ شده را هنگام بازکردن قفل صفحه کنترل می‎کند. اگر دفعات زیادی گذرواژه نادرست وارد شود، تلفن را قفل می‌کند یا همه داده‎های تلفن را پاک می‌کند."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"تغییر رمز ورود قفل گشایی صفحه"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"گذرواژه بازگشایی قفل صفحه را تغییر دهید."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"بر تعداد گذرواژه‌های نادرستی که هنگام باز کردن قفل صفحه تایپ شده، نظارت می‌کند، و اگر تعداد گذرواژه‌های تایپ شده نادرست بیش از حد بود، رایانه لوحی را قفل می‌کند یا کلیه داده‌های کاربر را پاک می‌کند."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"بر تعداد گذرواژه‌های نادرستی که هنگام باز کردن قفل صفحه تایپ شده، نظارت می‌کند، و اگر تعداد گذرواژه‌های تایپ شده نادرست بیش از حد بود، تلویزیون را قفل می‌کند یا کلیه داده‌های کاربر را پاک می‌کند."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"بر تعداد گذرواژه‌های نادرستی که هنگام باز کردن قفل صفحه تایپ شده، نظارت می‌کند، و اگر تعداد گذرواژه‌های تایپ شده نادرست بیش از حد بود، تلفن را قفل می‌کند یا کلیه داده‌های کاربر را پاک می‌کند."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"تغییر قفل صفحه"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"تغییر قفل صفحه."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"قفل کردن صفحه"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"نحوه و زمان قفل شدن صفحه را کنترل کنید."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"پاک کردن تمام داده‌ها"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"با انجام بازنشانی به داده‌های کارخانه، داده‌های رایانهٔ لوحی بدون هشدار پاک می‌شود."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"داده‌های تلویزیون را بدون هشدار با انجام بازنشانی به داده کارخانه پاک کنید."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"با انجام بازنشانی به داده‌های کارخانه، داده‌های تلفن بدون هشدار پاک می‌شود."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"پاک کردن داده‌های کاربر"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"داده‌های این کاربر را در این رایانه لوحی بدون هشدار پاک می‌کند."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"داده‌های این کاربر را در این تلویزیون بدون هشدار پاک می‌کند."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"داده‌های این کاربر را در این تلفن بدون هشدار پاک می‌کند."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تنظیم پروکسی جهانی دستگاه"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می‌کند."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یک بار باید گذرواژه صفحه قفل عوض شود."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"پروکسی کلی دستگاه را برای استفاده هنگام فعال بودن این خط‌مشی تنظیم می‌کند. تنها مالک دستگاه می‌تواند پروکسی کلی را تنظیم کند."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"تنظیم تاریخ انقضای گذرواژه قفل صفحه"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"تغییر تعداد دفعاتی که گذرواژه، پین یا الگوی قفل صفحه باید تغییر کند."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"اطلاعات ذخیره شده برنامه باید رمزگذاری شود."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"جلوگیری از استفاده از همه دوربین‌های دستگاه."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"غیرفعال کردن ویژگی‌‌ها در محافظ کلید"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"از استفاده از برخی ویژگی‌ها در محافظ کلید جلوگیری شود."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"غیرفعال کردن ویژگی‌های قفل صفحه"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"از استفاده از بعضی ویژگی‌های قفل صفحه جلوگیری می‌کند."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"خانه"</item>
     <item msgid="869923650527136615">"تلفن همراه"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> می‌خواهد «کاوش با لمس» را فعال کند. وقتی «کاوش با لمس» فعال است، می‌توانید توضیحاتی را برای آنچه که زیر انگشت شما است مشاهده کرده یا بشنوید یا برای استفاده از تلفن خود از حرکات استفاده کنید."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"۱ ماه قبل"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"قبل از ۱ ماه گذشته"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"۱ ثانیه قبل"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"۱ دقیقه قبل"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"۱ ساعت قبل"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> روز گذشته"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> روز قبل</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> روز قبل</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"ماه گذشته"</string>
     <string name="older" msgid="5211975022815554840">"قدیمی تر"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ديروز"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"در ۱ ثانیه"</item>
-    <item quantity="other" msgid="1241926116443974687">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"در ۱ دقیقه"</item>
-    <item quantity="other" msgid="3330713936399448749">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"در ۱ ساعت"</item>
-    <item quantity="other" msgid="547290677353727389">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"فردا"</item>
-    <item quantity="other" msgid="5109449375100953247">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"۱ ثانیه قبل"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ثانیه قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"۱ دقیقه قبل"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> دقیقه قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"۱ ساعت قبل"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ساعت قبل"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ديروز"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> روز قبل"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"در ۱ ثانیه"</item>
-    <item quantity="other" msgid="5495880108825805108">"در <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"در ۱ دقیقه"</item>
-    <item quantity="other" msgid="4216113292706568726">"در <xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"در ۱ ساعت"</item>
-    <item quantity="other" msgid="3705373766798013406">"در <xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"فردا"</item>
-    <item quantity="other" msgid="2973062968038355991">"در <xliff:g id="COUNT">%d</xliff:g> روز"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"در <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"در <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"در <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"هفته"</string>
     <string name="year" msgid="4001118221013892076">"سال"</string>
     <string name="years" msgid="6881577717993213522">"سال"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"۱ ثانیه"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"۱ دقیقه"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> دقیقه"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"۱ ساعت"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ساعت"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ثانیه</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ثانیه</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> دقیقه</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> دقیقه</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ساعت</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ساعت</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدئو ممکن نیست."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏Android در حال راه‌اندازی است..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"بهینه‌سازی فضای ذخیره‌سازی."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"در حال بهینه‌سازی برنامهٔ <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"آماده‌سازی <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"در حال آغاز برنامه‌ها."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"در حال اتمام راه‌اندازی."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string>
     <string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"برنامه قدیمی را بدون ذخیره متوقف کنید."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"انتخاب یک عملکرد برای نوشتار"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"میزان صدای زنگ"</string>
     <string name="volume_music" msgid="5421651157138628171">"میزان صدای رسانه"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"هیچکدام"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"آهنگ‌های زنگ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"آهنگ زنگ ناشناس"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"‏شبکه Wi-Fi موجود است"</item>
-    <item quantity="other" msgid="4192424489168397386">"‏شبکه‌های Wi-Fi موجود هستند"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"‏شبکه Wi-Fi موجود را باز کنید"</item>
-    <item quantity="other" msgid="7915895323644292768">"‏شبکه‌های Wi-Fi موجود را باز کنید"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">‏شبکه Wi-Fi در دسترس</item>
+      <item quantity="other">‏شبکه‌ Wi-Fi در دسترس</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">‏شبکه Wi-Fi باز در دسترس</item>
+      <item quantity="other">‏شبکه‌ Wi-Fi باز در دسترس</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"‏ورود به شبکه Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ورود به شبکه"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال اجازه داده شود؟"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏برنامه %1$s می‌خواهد به شبکه Wifi ‏%2$s وصل شود"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"برنامه"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏Wi-Fi Direct شروع نشد."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به‌عنوان دستگاه رسانه‌ای"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"متصل شده به‌عنوان دوربین"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"‏به عنوان یک دستگاه MIDI متصل شد"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"متصل شده به‌عنوان نصب کننده"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏به یک وسیله جانبی USB وصل شده است"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"‏برای سایر گزینه‌های USB لمس کنید."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"پرش"</string>
     <string name="no_matches" msgid="8129421908915840737">"مورد منطبقی موجود نیست"</string>
     <string name="find_on_page" msgid="1946799233822820384">"یافتن در صفحه"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 مورد منطبق"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"انجام شد"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"‏در حال لغو نصب حافظهٔ USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"‏در حال لغو نصب کارت SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"یک پین برای تغییر محدودیت‌ها ایجاد کنید"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"پین‌ها مطابقت ندارند. دوباره امتحان کنید."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"پین بیش از حد کوتاه است. باید حداقل ۴ رقم باشد."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"امتحان پس از ۱ ثانیه"</item>
-    <item quantity="other" msgid="4730868920742952817">"امتحان پس از <xliff:g id="COUNT">%d</xliff:g> ثانیه"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ثانیه دیگر دوباره امتحان کنید</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ثانیه دیگر دوباره امتحان کنید</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"بعداً دوباره امتحان کنید"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"برای خروج از حالت تمام صفحه، انگشت خود را به تندی از بالای صفحه به پایین بکشید."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string>
     <string name="done_label" msgid="2093726099505892398">"انجام شد"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایره‌ای ساعت"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایره‌ای دقیقه"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"برای برداشتن پین این صفحه، هم‌زمان «بازگشت» و «نمای کلی» را لمس کنید و نگه دارید."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"برای برداشتن پین این صفحه، «نمای کلی» را لمس کنید و نگه دارید."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"صفحه پین شده است. سازمان شما برداشتن پین را غیرمجاز کرده است."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"پین صفحه برداشته شد"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود ماندگاری باتری، ابزار صرفه‌جویی در مصرف باتری عملکرد دستگاهتان را کاهش می‌دهد و لرزش، سرویس‌های مبتنی بر مکان، و دسترسی به اکثر داده‌ها در پس‌زمینه را محدود می‌کند. ایمیل، پیام‌رسانی و برنامه‌های دیگری که به همگام‌سازی متکی هستند، تا زمانی که آن‌ها را باز نکنید نمی‌توانند به‌روز شوند.\n\nابزار صرفه‌جویی در مصرف باتری به صورت خودکار در هنگام شارژ شدن دستگاه خاموش می‌شود."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"تا زمانی که زمان استراحت در <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> به پایان برسد"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"تا زمان اتمام فرویش"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"به مدت یک دقیقه (تا <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"به مدت یک ساعت (تا <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"‏به مدت %1$d ساعت (تا <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item>
-    <item quantity="other" msgid="6924190729213550991">"‏برای %d دقیقه"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"برای یک ساعت"</item>
-    <item quantity="other" msgid="5408537517529822157">"‏برای %d ساعت"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">‏به مدت %1$d ساعت (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏به مدت %1$d ساعت (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">‏به مدت %d دقیقه</item>
+      <item quantity="other">‏به مدت %d دقیقه</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">‏به مدت %d ساعت</item>
+      <item quantity="other">‏به مدت %d ساعت</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"نامحدود"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"کوچک کردن"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"تا هشدار بعدی در <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"تا هشدار بعدی"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏درخواست SS به درخواست DIAL اصلاح می‌شود."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏درخواست SS به درخواست USSD اصلاح می‌شود."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏درخواست SS به درخواست SS جدید اصلاح می‌شود."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏درگاه جانبی USB"</string>
 </resources>
diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml
+++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k.%M.%S</string>
     <string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
index 8e8c640..eab4957 100755
--- a/core/res/res/values-fi/donottranslate-cldr.xml
+++ b/core/res/res/values-fi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k.%M.%S</string>
     <string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 6faab43..9eed4a1 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Nimetön&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ei puhelinnumeroa)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Tuntematon"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Vastaaja"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-korttisi on PUK-lukittu. Poista lukitus antamalla PUK-koodi."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Pura SIM-kortin esto antamalla PUK2-koodi."</string>
     <string name="enablePin" msgid="209412020907207950">"Epäonnistui, ota SIM-/RUIM-lukitus käyttöön."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti lukitaan."</item>
-    <item quantity="other" msgid="7530597808358774740">"Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti lukitaan."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti lukitaan.</item>
+      <item quantity="one">Sinulla on <xliff:g id="NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti lukitaan.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI-koodi"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Soittajan tunnus"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"reitin tarjoajan palveluun sitominen"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Antaa sovelluksen luoda sidoksen mihin tahansa rekisteröityyn reitin tarjoajaan. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"sido TV-tuloon"</string>
@@ -579,13 +580,13 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"poista lähetyksen merkkivalo käytöstä, kun kameraa käytetään"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Antaa valmiiksi asennetun järjestelmäsovelluksen poistaa käytöstä kameran käytössäolon merkkivalon."</string>
-    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"poista tablet-laite käytöstä lopullisesti"</string>
+    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"poista tabletti käytöstä lopullisesti"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"Poista televisio pysyvästi käytöstä"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"poista puhelin käytöstä pysyvästi"</string>
     <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Antaa sovelluksen poistaa koko tablet-laitteen käytöstä lopullisesti. Tämä on hyvin vaarallista."</string>
     <string name="permdesc_brick" product="tv" msgid="7070924544316356349">"Antaa sovelluksen poistaa koko television pysyvästi käytöstä. Tämä on hyvin vaarallista."</string>
     <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Antaa sovelluksen poistaa koko puhelimen käytöstä lopullisesti. Tämä on hyvin vaarallista."</string>
-    <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"pakota tablet-laite käynnistymään uudelleen"</string>
+    <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"pakota tabletti käynnistymään uudelleen"</string>
     <string name="permlab_reboot" product="tv" msgid="2112102119558886236">"Pakota television uudelleenkäynnistys"</string>
     <string name="permlab_reboot" product="default" msgid="2898560872462638242">"pakota puhelin käynnistymään uudelleen"</string>
     <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Antaa sovelluksen pakottaa tablet-laitteen käynnistymään uudelleen."</string>
@@ -649,7 +650,7 @@
     <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Antaa sovelluksen käyttää tablet-laitteen infrapunalähetintä."</string>
     <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Antaa sovelluksen käyttää television infrapunalähetintä."</string>
     <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Antaa sovelluksen käyttää puhelimen infrapunalähetintä."</string>
-    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"käynnistä tai sammuta tablet-laite"</string>
+    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"käynnistä tai sammuta tabletti"</string>
     <string name="permlab_devicePower" product="tv" msgid="7579718349658943416">"Sammuta ja käynnistä televisio"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"sammutta tai käynnistä puhelin"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Antaa sovelluksen sammuttaa tai käynnistää tablet-laitteen."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Antaa sovelluksen kommunikoida NFC (Near Field Communication) -tagien, -korttien ja -lukijoiden kanssa."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"poista ruudun lukitus käytöstä"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Antaa sovelluksen ottaa näppäinlukon ja siihen liittyvän salasanasuojauksen pois käytöstä. Esimerkki: puhelin poistaa näppäinlukon käytöstä puhelun saapuessa ja asettaa lukon takaisin käyttöön puhelun päättyessä."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"sormenjälkilaitteiston hallinnointi"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Sallii sovelluksen käyttää menetelmiä, joilla voidaan lisätä tai poistaa sormenjälkimalleja."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"sormenjälkilaitteiston käyttö"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Sallii sovelluksen käyttää sormenjälkilaitteistoa todennukseen."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lue synkronointiasetuksia"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Antaa sovelluksen lukea tilien synkronointiasetuksia. Sovellus voi esimerkiksi määrittää, onko Henkilöt-sovellus synkronoitu tilin kanssa."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ota synkronointi käyttöön tai poista se käytöstä"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"luo sidos valitsimen kohdepalveluun"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Antaa sovelluksen luoda sidoksen valitsimen kohdepalvelun ylemmän tason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ehtojen toimituspalveluun sitominen"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Antaa sovelluksen luoda sidoksen ehtojen toimituspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"median reitityspalveluun sitoutuminen"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Antaa sovelluksen sitoutua median reitityspalvelun ylätason liittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"sitoudu Unelma-palveluun"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Antaa sovelluksen sitoutua Unelma-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Palveluntarjoajan määrityssovelluksen käynnistäminen"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Operaattorin viestipalveluun sitoutuminen"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Antaa sovelluksen sitoutua operaattorin viestipalvelun ylätason liittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Hallinnoi ruudun ruudun lukituksen salasanoissa ja PIN-koodeissa sallittuja merkkejä ja niiden pituutta."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Valvoo väärien salasanojen lukumäärää näytön lukituksen poistossa sekä lukitsee tablet-laitteen tai poistaa sen tiedot, jos salasana syötetään väärin liian monta kertaa."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Valvo väärien salasanojen määrää poistettaessa näytön lukitusta ja lukitse televisio tai poista television kaikki tiedot, jos salasana kirjoitetaan väärin liian monta kertaa."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Valvoo väärien salasanojen lukumäärää näytön lukituksen poistossa ja lukitsee puhelimen tai poistaa sen kaikki tiedot, jos väärä salasana syötetään liian monta kertaa."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Vaihda ruudunlukituksen poiston salasanaa"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Vaihda ruudunlukituksen poiston salasanaa."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Valvo väärien salasanojen määrää ruudun lukitusta avattaessa ja lukitse tabletti tai poista kaikki tämän käyttäjän tiedot, jos salasana kirjoitetaan väärin liian monta kertaa."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Valvo väärien salasanojen määrää ruudun lukitusta avattaessa ja lukitse televisio tai poista kaikki tämän käyttäjän tiedot, jos salasana kirjoitetaan väärin liian monta kertaa."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Valvo väärien salasanojen määrää ruudun lukitusta avattaessa ja lukitse puhelin tai poista kaikki tämän käyttäjän tiedot, jos salasana kirjoitetaan väärin liian monta kertaa."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Muuta ruudun lukitus"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Muuta ruudun lukitus."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Lukitse ruutu"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Hallinnoi, milloin ja miten ruutu lukittuu."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Pyyhi kaikki tiedot"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Tyhjennä tablet-laitteen tiedot varoituksetta palauttamalla tehdasasetukset."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Palauta tehdasasetukset ja poista television tiedot ilman varoitusta."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Tyhjennä puhelimen tiedot varoituksetta palauttamalla tehdasasetukset."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Pyyhi käyttäjän tiedot"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Pyyhi tämän käyttäjän tiedot tabletista ilman varoitusta."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Pyyhi tämän käyttäjän tiedot televisiosta ilman varoitusta."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Pyyhi tämän käyttäjän tiedot puhelimesta ilman varoitusta."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Aseta laitteen yleinen välityspalvelin"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain ensimmäinen laitteen järjestelmänhallitsija voi asettaa käytettävän yleisen välityspalvelimen."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta ruudunlukituksen salasanan voimassaoloaika"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Määritä, miten usein ruudunlukituksen salasana tulee vaihtaa."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain laitteen omistaja voi asettaa yleisen välityspalvelimen."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Määritä ruudun lukituksen salasanan viimeinen voimassaolopäivä"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Muuta sitä, miten usein ruudun lukituksen salasana, PIN-koodi tai kuvio tulee vaihtaa."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Aseta tallennustilan salaus"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Pakota tallennettujen sovellustietojen salaus."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Poista kamerat käytöstä"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Estä laitteen kaikkien kameroiden käyttö."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Poista omin. käyt. näppäinluk."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Estä joidenkin ominaisuuksien käyttö näppäinlukolla."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Poista ruudun lukituksen ominaisuudet"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Estä joidenkin ruudun lukituksen ominaisuuksien käyttö."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Puhelinnumero (koti)"</item>
     <item msgid="869923650527136615">"Mobiili"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> haluaa ottaa Tutustu koskettamalla -ominaisuuden käyttöön. Kun Tutustu koskettamalla on käytössä, näet tai kuulet kuvauksen sormen alla olevista kohteista ja voit käyttää puhelinta sormieleiden avulla."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 sekunti sitten"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekuntia sitten"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuutti sitten"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuuttia sitten"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 tunti sitten"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Viimeisen <xliff:g id="COUNT">%d</xliff:g> päivän aikana"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Edellisten <xliff:g id="COUNT_1">%d</xliff:g> päivän aikana</item>
+      <item quantity="one">Edellisen <xliff:g id="COUNT_0">%d</xliff:g> päivän aikana</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Viime kuussa"</string>
     <string name="older" msgid="5211975022815554840">"Vanhemmat"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"eilen"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 sekunnin kuluttua"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 minuutin kuluttua"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> minuutin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 tunnin kuluttua"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"huomenna"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 s sitten"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min sitten"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 tunti sitten"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> tuntia sitten"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"eilen"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> päivää sitten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 s kuluttua"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 min kuluttua"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> min kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 tunnin kuluttua"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> tunnin kuluttua"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"huomenna"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> päivän kuluttua"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"päivä: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"klo <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"vuonna <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"viikkoa"</string>
     <string name="year" msgid="4001118221013892076">"vuosi"</string>
     <string name="years" msgid="6881577717993213522">"vuotta"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekunti"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekuntia"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuutti"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuuttia"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 tunti"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> tuntia"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekuntia</item>
+      <item quantity="one">1 sekunti</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuuttia</item>
+      <item quantity="one">1 minuutti</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tuntia</item>
+      <item quantity="one">1 tunti</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video-ongelma"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Tätä videota ei voi suoratoistaa tällä laitteella."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videota ei voida toistaa."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android käynnistyy…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimoidaan tallennustilaa."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimoidaan sovellusta <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Valmistellaan: <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Käynnistetään sovelluksia."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Viimeistellään päivitystä."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> käynnissä"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Älä käynnistä uutta sovellusta."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Käynnistä <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Pysäytä vanha sovellus tallentamatta."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Valitse tekstille toiminto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Soittoäänen voimakkuus"</string>
     <string name="volume_music" msgid="5421651157138628171">"Median äänenvoimakkuus"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ei mitään"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Tuntematon soittoääni"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi-verkko käytettävissä"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi-verkkoja käytettävissä"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Avoin Wi-Fi-verkko käytettävissä"</item>
-    <item quantity="other" msgid="7915895323644292768">"Avoimia Wi-Fi-verkkoja käytettävissä"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi-verkkoja käytettävissä</item>
+      <item quantity="one">Wi-Fi-verkko käytettävissä</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Avoimia Wi-Fi-verkkoja käytettävissä</item>
+      <item quantity="one">Avoin Wi-Fi-verkko käytettävissä</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Kirjaudu Wi-Fi-verkkoon"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Kirjaudu verkkoon"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Sovellus %1$s yrittää yhdistää Wi-Fi-verkkoon %2$s."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Sovellus"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora Wi-Fi-yhteys"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora Wi-Fi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran Wi-Fi-yhteyden käynnistäminen epäonnistui."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Kytketty medialaitteena"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kytketty kamerana"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Yhdistetty MIDI-laitteeseen"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Kytketty asennusohjelmana"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Liitetty USB-laitteeseen"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Käytä muita USB-vaihtoehtoja koskettamalla."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ohita"</string>
     <string name="no_matches" msgid="8129421908915840737">"Ei tuloksia"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Etsi sivulta"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 tulos"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 tulos</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Valmis"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Poistetaan USB-tallennustilaa käytöstä..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Poistetaan SD-korttia käytöstä..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Luo uusi PIN-koodi rajoitusten muokkaamista varten"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-koodit eivät vastaa toisiaan. Yritä uudelleen."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koodi on liian lyhyt. Vähimmäispituus on neljä merkkiä."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Yritä uud. 1 s kul."</item>
-    <item quantity="other" msgid="4730868920742952817">"Yritä uud. <xliff:g id="COUNT">%d</xliff:g> s kul."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Yritä uudelleen <xliff:g id="COUNT">%d</xliff:g> sekunnin kuluttua</item>
+      <item quantity="one">Yritä uudelleen 1 sekunnin kuluttua</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Yritä myöhemmin uudelleen"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Poistu koko näytön tilasta pyyhkäisemällä alas."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Koko ruudun tilassa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Selvä"</string>
     <string name="done_label" msgid="2093726099505892398">"Valmis"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Tuntien ympyränmuotoinen liukusäädin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minuuttien ympyränmuotoinen liukusäädin"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Poista näytön kiinnitys painamalla Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Poista näytön kiinnitys painamalla Viimeisimmät-kohtaa pitkään."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Näyttö on kiinnitetty. Irrottaminen ei ole sallittu organisaatiossasi."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Näyttö irrotettu"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN-koodi ennen irrotusta"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Käyttökatkos päättyy klo <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Vapaa-aikasi päättymiseen saakka"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Yksi minuutti (kunnes kello on <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d minuuttia (kunnes kello on <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Yksi tunti (kunnes kello on <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d tuntia (kunnes kello on <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Tunniksi"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d tunniksi"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Yhdeksi minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d tunniksi (kunnes kello on <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Yhdeksi tunniksi (kunnes kello on <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d minuutiksi</item>
+      <item quantity="one">Minuutiksi</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d tunniksi</item>
+      <item quantity="one">Tunniksi</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kunnes kello on <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Toistaiseksi"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Kutista"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Seuraavaan herätykseen saakka (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Seuraavaan herätykseen saakka"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-pyyntö muutettiin DIAL-pyynnöksi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-pyyntö muutettiin USSD-pyynnöksi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-pyyntö muutettiin uudeksi SS-pyynnöksi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-oheislaiteportti"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b8a8257..8002744 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sans_titre&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Aucun numéro de téléphone)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Inconnu"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Messagerie vocale"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Opération infructueuse. Activez le verrouillage SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative avant que votre carte SIM soit verrouillée."</item>
-    <item quantity="other" msgid="7530597808358774740">"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative(s) avant que votre carte SIM soit verrouillée."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM soit verrouillée.</item>
+      <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM soit verrouillée.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"Code IIEM"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Numéro de l\'appelant (entrant)"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"associer à un fournisseur d\'itinéraires enregistré"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet à l\'application autorisée de s\'associer à des fournisseurs d\'itinéraires enregistrés. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée de téléviseur"</string>
@@ -571,7 +572,7 @@
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"Permet à l\'application de contrôler la lecture des contenus multimédias et d\'accéder aux données associées (titre, auteur...)."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifier vos paramètres audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer fichier audio"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"enregistrer des fichiers audio"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permet à l\'application d\'enregistrer des contenus audio à l\'aide du microphone. Cette autorisation lui donne la possibilité d\'enregistrer du contenu audio à tout moment sans votre consentement."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"Communication avec la carte SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des bornes, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité par mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gérer le matériel d\'empreinte digitale"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permet à l\'application de faire appel à des méthodes d\'ajout et de suppression de modèles d\'empreinte digitale que vous pouvez utiliser."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utiliser le matériel d\'empreinte digitale"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permet à l\'application d\'utiliser du matériel d\'empreinte digitale pour l\'authentification"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer ou désactiver la synchronisation"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se lier à un service cible de sélecteur"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet au propriétaire de se lier à l\'interface de haut niveau d\'un service cible de sélecteur. Ne devrait jamais être nécessaire pour les applications normales."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires multimédias"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'itinéraires multimédias. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"associer à un service de rêve"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de rêve. Les applications standard ne devraient pas avoir recours à cette fonctionnalité."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration du fournisseur de services"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"s\'associer à un service de messagerie d\'un fournisseur"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de messagerie d\'un fournisseur. Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les NIP de verrouillage de l\'écran."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Contrôler le nombre de mots de passe incorrects saisis pour le déverrouillage de l\'écran, puis verrouiller la tablette ou effacer toutes ses données si le nombre maximal de tentatives de saisie du mot de passe est atteint"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Surveille le nombre de mots de passe incorrects entrés lors du déverrouillage de l\'écran et verrouille le téléviseur ou efface toutes ses données en cas d\'un nombre trop élevé de tentatives."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Contrôler le nombre de mots de passe incorrects saisis pour le déverrouillage de l\'écran, puis verrouille le téléphone ou efface toutes ses données si le nombre maximal de tentatives de saisie du mot de passe est atteint."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Surveille le nombre de mots de passe incorrects entrés lors du déverrouillage de l\'écran et verrouille la tablette ou efface toutes les données de l\'utilisateur en cas d\'un nombre trop élevé de tentatives."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Surveille le nombre de mots de passe incorrects entrés lors du déverrouillage de l\'écran et verrouille le téléviseur ou efface toutes les données de l\'utilisateur en cas d\'un nombre trop élevé de tentatives."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Surveille le nombre de mots de passe incorrects entrés lors du déverrouillage de l\'écran et verrouille le téléphone ou efface toutes les données de l\'utilisateur en cas d\'un nombre trop élevé de tentatives."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Modifier le verrouillage de l\'écran"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Modifier le verrouillage de l\'écran"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Verrouiller l\'écran"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Gérer le mode et les conditions de verrouillage de l\'écran"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Effacer toutes les données"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Effacer les données de la tablette sans avertissement, en rétablissant la configuration d\'usine"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Effacer les données du téléviseur sans avertissement en effectuant une réinitialisation des paramètres d\'usine."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Effacer les données du téléphone sans avertissement, en rétablissant la configuration d\'usine"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Effacer les données de l\'utilisateur"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Effacer les données de l\'utilisateur sur cette tablette sans avertissement."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Effacer les données de l\'utilisateur sur ce téléviseur sans avertissement."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Effacer les données de l\'utilisateur sur ce téléphone sans avertissement."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le serveur mandataire global du mobile"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le serveur mandataire global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le serveur mandataire global utilisé."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Indiquer le mandataire global à utiliser pour l\'appareil lorsque la politique est activée. Seul le propriétaire de l\'appareil peut définir le mandataire global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Déf. expir. m. passe verr. écr."</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Modifier la fréquence de modification du mot de passe, du NIP ou du motif de verrouillage de l\'écran."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exiger le chiffrement des données d\'application stockées"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Désactiver les appareils photo"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Empêcher l\'utilisation de tous les appareils photos"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Désact. fonct. si protec. clav."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Empêcher l\'utilisation de certaines fonctionnalités lorsque la protection du clavier est activée"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Désact. fonctions verr. écran"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domicile"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Il y a 1 heure"</item>
-    <item quantity="other" msgid="2467273239587587569">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Les <xliff:g id="COUNT">%d</xliff:g> derniers jours"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Le dernier <xliff:g id="COUNT_1">%d</xliff:g> jour</item>
+      <item quantity="other">Le dernier <xliff:g id="COUNT_1">%d</xliff:g> jours</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
     <string name="older" msgid="5211975022815554840">"Précédent"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hier"</item>
-    <item quantity="other" msgid="2479586466153314633">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
-    <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demain"</item>
-    <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"il y a 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Il y a 1 h"</item>
-    <item quantity="other" msgid="6889970745748538901">"il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hier"</item>
-    <item quantity="other" msgid="3453342639616481191">"il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
-    <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demain"</item>
-    <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semaines"</string>
     <string name="year" msgid="4001118221013892076">"an"</string>
     <string name="years" msgid="6881577717993213522">"ans"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 seconde"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g>minutes"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 heure"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> seconde</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> secondes</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutes</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> heure</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> heures</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problème vidéo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Impossible de lire cette vidéo en continu sur cet appareil."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossible de lire la vidéo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android en cours de démarrage..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimisation du stockage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimisation de l\'application <xliff:g id="NUMBER_0">%1$d</xliff:g> sur <xliff:g id="NUMBER_1">%2$d</xliff:g>…"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Aucune"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Réseau Wi-Fi disponible"</item>
-    <item quantity="other" msgid="4192424489168397386">"Réseaux Wi-Fi disponibles"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Réseau Wi-Fi ouvert disponible"</item>
-    <item quantity="other" msgid="7915895323644292768">"Réseaux Wi-Fi ouverts disponibles"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Réseau Wi-Fi à proximité</item>
+      <item quantity="other">Réseaux Wi-Fi à proximité</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Réseau Wi-Fi ouvert à proximité</item>
+      <item quantity="other">Réseaux Wi-Fi ouverts à proximité</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Se connecter au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'app. multimédia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connecté en tant qu\'appareil photo"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connecté en tant qu\'appareil MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connecté en tant que programme d\'installation"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez pour accéder aux autres options USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Passer"</string>
     <string name="no_matches" msgid="8129421908915840737">"Aucune partie"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Rechercher sur la page"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 correspondance"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Terminé"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Désinstallation de la mémoire de stockage USB en cours…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Désinstallation de la carte SD en cours…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Créez un NIP pour modifier les restrictions"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les NIP ne correspondent pas. Essayez à nouveau."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le NIP est trop court. Il doit comporter au moins 4 chiffres."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> seconde</item>
+      <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Réessayez plus tard"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Balayez vers le bas pour quitter le mode plein écran"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage plein écran"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez vers le bas à partir du haut."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Terminé"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage de cet écran, appuyez de manière prolongée sur Retour et Aperçu simultanément."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur Aperçu."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. Votre organisation n\'autorise pas l\'annulation d\'épinglage."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\n L\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Jusqu\'à ce que le temps d\'arrêt se termine à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jusqu\'à la fin du temps d\'arrêt"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Pendant une minute (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Pendant une heure (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Pendant %1$d heures (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
-    <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
-    <item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Pendant %1$d heure (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Pendant %1$d heures (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Pendant %d minute</item>
+      <item quantity="other">Pendant %d minutes</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Pendant %d heure</item>
+      <item quantity="other">Pendant %d heures</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indéfiniment"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Réduire"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Jusqu\'à la prochaine alarme, à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Jusqu\'à la prochaine alarme"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La demande SS a été modifiée et est maintenant une demande DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La demande SS a été modifiée et est maintenant une demande USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La demande SS a été modifiée et est maintenant une nouvelle demande SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB"</string>
 </resources>
diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml
index 5fc3539..2d6a109 100755
--- a/core/res/res/values-fr/donottranslate-cldr.xml
+++ b/core/res/res/values-fr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y à %H:%M:%S</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 9fb2e9f..c1fe962 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sans nom&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Aucun numéro de téléphone)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Inconnu"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Messagerie vocale"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Votre carte SIM est verrouillée par clé PUK. Saisissez la clé PUK pour la déverrouiller."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Saisissez la clé PUK2 pour débloquer la carte SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Échec de l\'opération. Veuillez activer le verrouillage de la carte SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative avant que votre carte SIM ne soit verrouillée."</item>
-    <item quantity="other" msgid="7530597808358774740">"Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne soit verrouillée.</item>
+      <item quantity="other">Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne soit verrouillée.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"Code IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"Code MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Numéro de l\'appelant (entrant)"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assistance vocale"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"s\'associer à un fournisseur d\'itinéraires"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permettre à l\'application autorisée de s\'associer à n\'importe quel fournisseur d\'itinéraires. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée TV"</string>
@@ -619,7 +620,7 @@
     <string name="permdesc_hardware_test" msgid="6597964191208016605">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
     <string name="permlab_fm" msgid="8749504526866832">"accéder aux radios FM"</string>
     <string name="permdesc_fm" msgid="4145699441237962818">"Permet à l\'application d\'accéder aux radios FM afin d\'écouter des programmes."</string>
-    <string name="permlab_callPhone" msgid="3925836347681847954">"Appeler directement les numéros de téléphone"</string>
+    <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"Appel direct de tout numéro de téléphone"</string>
     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permet à l\'application d\'appeler n\'importe quel numéro de téléphone, y compris les numéros d\'urgence, sans votre intervention. Des applications malveillantes peuvent passer des appels inutiles et interdits aux services d\'urgence."</string>
@@ -693,7 +694,7 @@
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Permet à l\'application de créer des sockets réseau et d\'utiliser des protocoles réseau personnalisés. Le navigateur et d\'autres applications permettent d\'envoyer des données sur Internet. Cette autorisation n\'est donc pas nécessaire pour envoyer des données sur Internet."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"changer/intercepter les paramètres et le trafic du réseau"</string>
     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Permet à l\'application de modifier les paramètres réseau, ainsi que d\'intercepter et de surveiller tout le trafic réseau ayant pour but de modifier le proxy et le port d\'un APN, par exemple. Des applications malveillantes peuvent exploiter cette fonctionnalité pour surveiller, rediriger ou modifier les paquets réseau à votre insu."</string>
-    <string name="permlab_changeNetworkState" msgid="958884291454327309">"Modification de la connectivité du réseau"</string>
+    <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifier la connectivité réseau"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permet à l\'application de modifier l\'état de la connectivité du réseau."</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"changer la connectivité du partage de connexion"</string>
     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permet à l\'application de modifier l\'état de la connectivité du partage de connexion."</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permet à l\'application de communiquer avec des tags, des cartes et des lecteurs compatibles avec la technologie NFC (communication en champ proche)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"désactiver le verrouillage de l\'écran"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet à l\'application de désactiver le verrouillage des touches et toute mesure de sécurité via mot de passe associée. Par exemple, votre téléphone désactive le verrouillage des touches lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"Gérer le matériel d\'empreintes digitales"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Autoriser l\'application à invoquer des méthodes pour ajouter et supprimer des modèles d\'empreintes digitales"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"Utiliser le matériel d\'empreintes digitales"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Autoriser l\'application à utiliser le matériel d\'empreintes digitales pour l\'authentification"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lire les paramètres de synchronisation"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activer/désactiver la synchronisation"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"S\'associer à un service de cible d\'un sélecteur"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permet à l\'application autorisée de s\'associer à l\'interface de niveau supérieur du service de cible d\'un sélecteur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"s\'associer à un service d\'itinéraires médias"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'itinéraires médias. Ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"associer à un service d\'écran de veille interactif"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service d\'écran de veille interactif. Cette autorisation ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration fournie par l\'opérateur"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"s\'associer au service SMS/MMS d\'un opérateur"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permettre à l\'application de s\'associer à l\'interface de niveau supérieur du service SMS/MMS d\'un opérateur. Ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les codes d\'accès de verrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Contrôler le nombre de mots de passe incorrects saisis pour le déverrouillage de l\'écran, puis verrouiller la tablette ou effacer toutes ses données si le nombre maximal de tentatives de saisie du mot de passe est atteint"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Contrôlez le nombre de fois qu\'un mot de passe incorrect est saisi lors du déverrouillage de l\'écran, et verrouillez le téléviseur ou effacez-en les données en cas de dépassement du nombre maximal de mots de passe incorrects autorisés."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Contrôler le nombre de mots de passe incorrects saisis pour le déverrouillage de l\'écran, puis verrouiller le téléphone ou effacer toutes ses données si le nombre maximal de tentatives de saisie du mot de passe est atteint"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Contrôlez le nombre de fois qu\'un mot de passe incorrect est saisi lors du déverrouillage de l\'écran, et verrouillez la tablette ou effacez toutes les informations sur l\'utilisateur si le nombre maximal de mots de passe incorrects autorisés est dépassé."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Contrôlez le nombre de fois qu\'un mot de passe incorrect est saisi lors du déverrouillage de l\'écran, et verrouillez le téléviseur ou effacez toutes les informations sur l\'utilisateur si le nombre maximal de mots de passe incorrects autorisés est dépassé."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Contrôlez le nombre de fois qu\'un mot de passe incorrect est saisi lors du déverrouillage de l\'écran, et verrouillez le téléphone ou effacez toutes les informations sur l\'utilisateur si le nombre maximal de mots de passe incorrects autorisés est dépassé."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Modifier le verrouillage de l\'écran"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Modifier le verrouillage de l\'écran"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Verrouiller l\'écran"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Gérer le mode et les conditions de verrouillage de l\'écran"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Effacer toutes les données"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Effacer les données de la tablette sans avertissement, en rétablissant la configuration d\'usine"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Effacez les données du téléviseur sans préavis via le rétablissement de sa configuration d\'usine."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Effacer les données du téléphone sans avertissement, en rétablissant la configuration d\'usine"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Effacer les informations sur l\'utilisateur"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Effacer les informations sur cet utilisateur de cette tablette sans avertissement"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Effacer les informations sur cet utilisateur de ce téléviseur sans avertissement"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Effacer les informations sur cet utilisateur de ce téléphone sans avertissement"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Indiquer le proxy global à utiliser pour l\'appareil lorsque la règle est activée. Seul le propriétaire de l\'appareil peut définir le proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Config. expir. mot passe verr. écran"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Modifier la fréquence de modification du mot de passe, du code d\'accès ou du motif de verrouillage de l\'écran"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir chiffrement du stockage"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exiger le chiffrement des données d\'application stockées"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Désactiver les appareils photo"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Empêcher l\'utilisation de tous les appareils photos"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Désact. fonct. si protec. clav."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Empêcher l\'utilisation de certaines fonctionnalités lorsque la protection du clavier est activée"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Désact. fonctions verr. écran"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domicile"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Il y a 1 mois"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Il y a plus d\'un mois"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Il y a 1 seconde"</item>
-    <item quantity="other" msgid="3903706804349556379">"Il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Il y a 1 minute"</item>
-    <item quantity="other" msgid="2176942008915455116">"Il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"il y a 1 heure"</item>
-    <item quantity="other" msgid="2467273239587587569">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Les <xliff:g id="COUNT">%d</xliff:g> derniers jours"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Le dernier jour (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
+      <item quantity="other">Les <xliff:g id="COUNT_1">%d</xliff:g> derniers jours</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Le mois dernier"</string>
     <string name="older" msgid="5211975022815554840">"Préc."</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hier"</item>
-    <item quantity="other" msgid="2479586466153314633">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dans 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dans 1 minute"</item>
-    <item quantity="other" msgid="3330713936399448749">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dans 1 heure"</item>
-    <item quantity="other" msgid="547290677353727389">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"demain"</item>
-    <item quantity="other" msgid="5109449375100953247">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"il y a 1 seconde"</item>
-    <item quantity="other" msgid="3699169366650930415">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"il y a 1 minute"</item>
-    <item quantity="other" msgid="851164968597150710">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"il y a 1 heure"</item>
-    <item quantity="other" msgid="6889970745748538901">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hier"</item>
-    <item quantity="other" msgid="3453342639616481191">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dans 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dans 1 minute"</item>
-    <item quantity="other" msgid="4216113292706568726">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dans 1 heure"</item>
-    <item quantity="other" msgid="3705373766798013406">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"demain"</item>
-    <item quantity="other" msgid="2973062968038355991">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"le <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semaines"</string>
     <string name="year" msgid="4001118221013892076">"année"</string>
     <string name="years" msgid="6881577717993213522">"années"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 seconde"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> secondes"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minute"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutes"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 heure"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> heures"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> seconde</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> secondes</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutes</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> heure</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> heures</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problème vidéo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Impossible de lire cette vidéo en streaming sur cet appareil."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossible de lire la vidéo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Démarrage d\'Android en cours"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimisation du stockage en cours…"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimisation de l\'application <xliff:g id="NUMBER_0">%1$d</xliff:g> sur <xliff:g id="NUMBER_1">%2$d</xliff:g>…"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Lancement des applications…"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Finalisation de la mise à jour."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pas lancer la nouvelle application"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Démarrer <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Arrêtez l\'ancienne application sans enregistrer."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Sélectionner une action pour le texte"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume de la sonnerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Aucun"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Sonneries"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Sonnerie inconnue"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Réseau Wi-Fi disponible"</item>
-    <item quantity="other" msgid="4192424489168397386">"Réseaux Wi-Fi disponibles"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Réseau Wi-Fi ouvert disponible"</item>
-    <item quantity="other" msgid="7915895323644292768">"Réseaux Wi-Fi ouverts disponibles"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Réseau Wi-Fi disponible</item>
+      <item quantity="other">Réseaux Wi-Fi disponibles</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Réseau Wi-Fi ouvert disponible</item>
+      <item quantity="other">Réseaux Wi-Fi ouverts disponibles</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Se connecter au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'appareil multimédia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connecté en tant qu\'appareil photo"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connecté en tant qu\'appareil MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connecté en tant que programme d\'installation"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez ici pour accéder aux autres options USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ignorer"</string>
     <string name="no_matches" msgid="8129421908915840737">"Aucune correspondance"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Rechercher sur la page"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 correspondance"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> sur <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"OK"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Désinstallation de la mémoire de stockage USB en cours…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Désinstallation de la carte SD en cours…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Créer un code PIN pour modifier les restrictions"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Les codes PIN ne correspondent pas. Veuillez réessayer."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Le code PIN est trop court. Il doit comporter au moins 4 chiffres."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Réessayer dans 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Réessayer dans <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> seconde</item>
+      <item quantity="other">Réessayer dans <xliff:g id="COUNT">%d</xliff:g> secondes</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Veuillez réessayer ultérieurement."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Faites glisser le doigt vers le bas pour quitter le mode plein écran."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Affichage en plein écran"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pour quitter, balayez l\'écran du haut vers le bas."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"OK"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Curseur circulaire des heures"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage, appuyez de manière prolongée et simultanée sur \"Retour\" et \"Aperçu\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Aperçu\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"L\'écran est épinglé. L\'annulation de l\'épinglage n\'est pas autorisée par votre organisation."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé."</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances de votre appareil, et il désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. La messagerie électronique, les SMS/MMS et les autres applications basées sur la synchronisation ne sont mises à jour que si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque votre appareil est en charge."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Jusqu\'à ce que le temps d\'arrêt se termine à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jusqu\'à la fin du temps d\'arrêt"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Pendant une minute (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Pendant une heure (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Pendant %1$d heures (jusqu\'à <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
-    <item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
-    <item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Pendant %1$d heure (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Pendant %1$d heures (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Pendant %d minute</item>
+      <item quantity="other">Pendant %d minutes</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Pendant %d heure</item>
+      <item quantity="other">Pendant %d heures</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indéfiniment"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Réduire"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Jusqu\'à la prochaine alarme à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Jusqu\'à la prochaine alarme"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La requête SS a été remplacée par une requête DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La requête SS a été remplacée par une requête USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La requête SS a été remplacée par une autre requête SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port du périphérique USB"</string>
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index bafdda8..8df4d62 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> segundos"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> segundo"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sen título&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"…"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Sen número de teléfono)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Descoñecido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"A tarxeta SIM está bloqueada con código PUK. Escribe o código PUK para desbloqueala."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Escribe o código PUK2 para desbloquear a tarxeta SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Non é correcto. Activa o bloqueo da SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Quédache <xliff:g id="NUMBER">%d</xliff:g> intento antes de que se bloquee a SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"Quédanche <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que se bloquee a SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos antes de que se bloquee a SIM.</item>
+      <item quantity="one">Quédache <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que se bloquee a SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID de chamada entrante"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo avión está activado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo avión está desactivado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao propietario vincularse á interface de nivel superior dunha pantalla remota. Non debería ser nunca necesario para as aplicacións normais."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servizo de widgets"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite ao propietario vincularse á interface de nivel superior dun servizo de widget. As aplicacións normais non deberían necesitar este permiso."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular a un servizo de provedor de rutas"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite ao propietario vincularse a calquera provedor de ruta rexistrado. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar cun administrador de dispositivos"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao propietario enviar intentos a un administrador de dispositivos. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a unha entrada de televisión"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite á aplicación comunicarse con etiquetas, tarxetas e lectores Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivar o bloqueo da pantalla"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite á aplicación desactivar o bloqueo do teclado e calquera seguridade dos contrasinais asociada. Por exemplo, o teléfono desactiva o bloqueo do teclado ao recibir unha chamada telefónica entrante e, a continuación, volve activar o bloqueo do teclado unha vez finalizada a chamada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"xestionar hardware de identificación dixital"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que a aplicación invoque métodos para engadir e eliminar modelos de uso de identificación dixital."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"usar hardware de identificación dixital"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que a aplicación utilice hardware de identificación dixital para a autenticación"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler a configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite á aplicación ler a configuración de sincronización dunha conta. Por exemplo, esta acción pode determinar se a aplicación Contactos se sincroniza cunha conta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar e desactivar a sincronización"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite á aplicación recuperar, examinar e borrar notificacións, incluídas as publicadas por outras aplicacións."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a un servizo de axente de escoita de notificacións"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite ao propietario vincularse á interface de nivel superior dun servizo axente de escoita de notificacións.  Non debería ser nunca necesario para as aplicacións normais."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a un servizo de destino de selector"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao propietario vincularse á interface de nivel superior dun servizo de destino de selector. Non se debería necesitar para as aplicacións normais."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a un servizo de provedor de condicións"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite ao propietario vincularse á interface de nivel superior dun servizo provedor de condicións. As aplicacións normais non deberían necesitar este permiso."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a un servizo de ruta de medios"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite ao propietario vincularse á interface de nivel superior dun servizo de ruta de medio. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"vincular a un servizo de soños"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite ao propietario vincularse á interface de nivel superior dun servizo de soños. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicación de configuración fornecida polo operador"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a un servizo de mensaxería"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao propietario vincularse á interface de nivel superior dun servizo de mensaxería. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer as normas de contrasinal"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar a lonxitude e os caracteres permitidos nos contrasinais de desbloqueo da pantalla."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla a lonxitude e os caracteres permitidos nos contrasinais e nos PIN de bloqueo da pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisar os intentos de desbloqueo da pantalla"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Supervisa o número de contrasinais incorrectos escritos ao desbloquear a pantalla e bloquea o tablet ou borra todos os datos do tablet se se escriben demasiados contrasinais incorrectos."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Controla o número de contrasinais incorrectos introducidos ao desbloquear a pantalla e bloquea a televisión ou borra todos os seus datos se se introducen demasiados contrasinais incorrectos."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Supervisa o número de contrasinais incorrectos escritos ao desbloquear a pantalla e bloquea o teléfono ou borra todos os datos do teléfono se se escriben demasiados contrasinais incorrectos."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Cambiar o contrasinal de desbloqueo da pantalla"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Cambiar o contrasinal de desbloqueo da pantalla."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Supervisar o número de contrasinais incorrectos escritos ao desbloquear a pantalla e bloquear o tablet ou borrar todos os datos do usuario se se escriben demasiados contrasinais incorrectos."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Supervisar o número de contrasinais incorrectos escritos ao desbloquear a pantalla e bloquear a televisión ou borrar todos os datos do usuario se se escriben demasiados contrasinais incorrectos."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Supervisar o número de contrasinais incorrectos escritos ao desbloquear a pantalla e bloquear o teléfono ou borrar todos os datos do usuario se se escriben demasiados contrasinais incorrectos."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Cambiar o bloqueo da pantalla"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Cambia o bloqueo da pantalla."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear a pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar como e cando se bloquea a pantalla."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos os datos"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar os datos do tablet sen previo aviso mediante a realización dun restablecemento dos datos de fábrica."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Borra os datos da televisión sen previo aviso a través do restablecemento dos valores de fábrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar os datos do teléfono sen previo aviso mediante a realización dun restablecemento dos datos de fábrica."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Borrar os datos do usuario"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Borra os datos deste usuario neste tablet sen previo aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Borra os datos deste usuario nesta televisión sen previo aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Borra os datos deste usuario neste teléfono sen previo aviso."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Establecer o proxy global do dispositivo"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Establecer o proxy global do dispositivo que se debe usar mentres a política estea activada. Só o primeiro administrador do dispositivo establece o proxy global que se usará."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidade bloqueo pantalla"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controlar a frecuencia coa que se debe cambiar o contrasinal da pantalla de bloqueo."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Configura o proxy global do dispositivo que se debe usar cando a política está activada. Só o propietario do dispositivo pode configurar o proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Establecer a caducidade do contrasinal de bloqueo da pantalla"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Cambia a frecuencia coa que se debe modificar o contrasinal, o PIN ou o padrón do bloqueo da pantalla."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptación de almacenamento"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Esixir que os datos da aplicación almacenados estean encriptados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desactivar cámaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evitar o uso de todas as cámaras do dispositivo."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Desactivar as funcións de bloqueo do teclado"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Evitar o uso dalgunhas funcións de bloqueo do teclado."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desactivar as funcións de bloqueo da pantalla"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Evita o uso dalgunhas funcións de bloqueo da pantalla."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Particular"</item>
     <item msgid="869923650527136615">"Móbil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quere activar a exploración táctil. Cando a exploración táctil estea activada, poderás escoitar ou ver descricións do contido seleccionado ou realizar xestos para interactuar co teléfono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Hai 1 mes"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Hai máis de 1 mes"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"hai 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"hai <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"hai 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"hai <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Hai 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> días</item>
+      <item quantity="one">Último <xliff:g id="COUNT_0">%d</xliff:g> día</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"O mes pasado"</string>
     <string name="older" msgid="5211975022815554840">"Antes"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"onte"</item>
-    <item quantity="other" msgid="2479586466153314633">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"en 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"en <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"En 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"en <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"En 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"En <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mañá"</item>
-    <item quantity="other" msgid="5109449375100953247">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"hai 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"hai <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"hai 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"hai <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"hai 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"hai <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"onte"</item>
-    <item quantity="other" msgid="3453342639616481191">"Hai <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"en 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"en <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"en 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"en <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"en 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"en <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mañá"</item>
-    <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"o <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ás <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"no <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semanas"</string>
     <string name="year" msgid="4001118221013892076">"ano"</string>
     <string name="years" msgid="6881577717993213522">"anos"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">Un segundo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+      <item quantity="one">Un minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+      <item quantity="one">Unha hora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Hai un problema co vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo non se pode transmitir no dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Non se pode reproducir este vídeo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Estase iniciando Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizando almacenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizando aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando aplicacións."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Está finalizando o arranque"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> está en execución"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Non inicies a aplicación nova."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Deter a aplicación antiga sen gardar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Seleccionar unha acción para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume do timbre"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume dos elementos multimedia"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ningún"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tons de chamada"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ton de chamada descoñecido"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi dispoñible"</item>
-    <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi dispoñibles"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Abrir a rede Wi-Fi dispoñible"</item>
-    <item quantity="other" msgid="7915895323644292768">"Abrir as redes Wi-Fi dispoñibles"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Redes wifi dispoñibles</item>
+      <item quantity="one">Rede wifi dispoñible</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Abrir redes wifi dispoñibles</item>
+      <item quantity="one">Abrir rede wifi dispoñible</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Inicia sesión na rede wifi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Inicia sesión na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar coa rede Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ten unha conexión a Internet deficiente."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicación %1$s quere conectarse á rede wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Unha aplicación"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Esta acción desactivará o cliente e a zona interactiva da wifi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Non se puido iniciar Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como dispositivo multimedia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como unha cámara"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Conectado como dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toca para acceder a outras opcións de USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Omitir"</string>
     <string name="no_matches" msgid="8129421908915840737">"Non hai coincidencias"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Buscar na páxina"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 coincidencia"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">Unha coincidencia</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Feito"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Desactivando o almacenamento USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Desactivando a tarxeta SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un PIN para modificar as restricións"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PIN non coinciden. Téntao de novo."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado curto. Debe conter polo menos 4 díxitos."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Téntao de novo dentro de 1 segundo"</item>
-    <item quantity="other" msgid="4730868920742952817">"Téntao de novo dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Téntao de novo en <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">Téntao de novo dentro nun segundo</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Téntao de novo máis tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Pasa o dedo cara abaixo desde a parte superior para saír da pantalla completa."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vendo pantalla completa"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para saír, pasa o dedo cara abaixo desde arriba."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"De acordo"</string>
     <string name="done_label" msgid="2093726099505892398">"Feito"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Control de desprazamento circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Control de desprazamento circular dos minutos"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar a pantalla, mantén premido Atrás e Visión xeral ao mesmo tempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar a pantalla, mantén premido Visión xeral."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A pantalla está fixada. A túa organización non permite desactivar a pantalla."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla desactivada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función aforro de batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función aforro de batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Ata que remate o tempo de inactividade ás <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Ata que remate o tempo de inactividade"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Durante un minuto (ata as <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Durante %1$d minutos (ata as <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Durante unha hora (ata as <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Durante %1$d horas (ata as <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Durante unha hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Durante %1$d minutos (ata as <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante un minuto (ata as <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Durante %1$d horas (ata as <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante unha hora (ata as <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Durante %d minutos</item>
+      <item quantity="one">Durante un minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Durante %d horas</item>
+      <item quantity="one">Durante unha hora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Ata as <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidamente"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Ata que desactives isto"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Contraer"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Ata que soe a seguinte alarma ás <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Ata que soe a seguinte alarma"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitude SS transformouse nunha solicitude DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitude SS transformouse nunha solicitude USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitude SS transformouse nunha nova solicitude SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porto periférico USB"</string>
 </resources>
diff --git a/core/res/res/values-h320dp/bools.xml b/core/res/res/values-h320dp/bools.xml
new file mode 100644
index 0000000..3bbfe96
--- /dev/null
+++ b/core/res/res/values-h320dp/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <bool name="allow_stacked_button_bar">true</bool>
+</resources>
diff --git a/core/res/res/values-h320dp/dimens.xml b/core/res/res/values-h320dp/dimens.xml
new file mode 100644
index 0000000..d0de6a1
--- /dev/null
+++ b/core/res/res/values-h320dp/dimens.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_text_inset_inner">58dp</dimen>
+    <dimen name="timepicker_radial_picker_dimen">224dp</dimen>
+    <integer name="timepicker_title_visibility">2</integer>
+
+    <dimen name="floating_window_margin_left">16dp</dimen>
+    <dimen name="floating_window_margin_top">8dp</dimen>
+    <dimen name="floating_window_margin_right">16dp</dimen>
+    <dimen name="floating_window_margin_bottom">32dp</dimen>
+</resources>
diff --git a/core/res/res/values-hi-rIN/donottranslate-cldr.xml b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi-rIN/donottranslate-cldr.xml
+++ b/core/res/res/values-hi-rIN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hi/donottranslate-cldr.xml b/core/res/res/values-hi/donottranslate-cldr.xml
index 8f30750..b1dc879 100755
--- a/core/res/res/values-hi/donottranslate-cldr.xml
+++ b/core/res/res/values-hi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %d-%m-%Y</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4e63de0..f063560 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंड"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंड"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;शीर्षक-रहित&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(कोई फ़ोन नंबर नहीं)"</string>
     <string name="unknownName" msgid="6867811765370350269">"अज्ञात"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"वॉयस मेल"</string>
@@ -63,17 +61,17 @@
     <string name="needPuk" msgid="919668385956251611">"आपका सिम कार्ड PUK लॉक किया गया है. इसे अनलॉक करने के लिए PUK कोड लिखें."</string>
     <string name="needPuk2" msgid="4526033371987193070">"सिम कार्ड अनब्‍लॉक करने के लिए PUK2 लिखें."</string>
     <string name="enablePin" msgid="209412020907207950">"असफल, सिम//RUIM लॉक सक्षम करें."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"सिम के लॉक हो जाने से पहले आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष है."</item>
-    <item quantity="other" msgid="7530597808358774740">"सिम के लॉक हो जाने से पहले आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष हैं."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">सिम के लॉक हो जाने से पहले आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+      <item quantity="other">सिम के लॉक हो जाने से पहले आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"इनकमिंग कॉलर ID"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"आउटगोइंग कॉलर ID"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"कनेक्ट किया गया लाइन आईडी"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"कनेक्ट किया गया लाइन आईडी प्रतिबंध"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"कॉल अग्रेषण"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"कॉल आगे भेजना"</string>
     <string name="CwMmi" msgid="9129678056795016867">"कॉल प्रतीक्षा"</string>
     <string name="BaMmi" msgid="455193067926770581">"कॉल बाधित करना"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"पासवर्ड बदलें"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाई जहाज मोड चालू है"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाई जहाज मोड बंद है"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"वॉइस सहायक"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्‍तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"किसी रूट प्रदाता सेवा से आबद्ध हों"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"धारक को किसी भी पंजीकृत रूट प्रदाता से आबद्ध रहने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी डिवाइस नियंत्रक के साथ सहभागिता करें"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी डिवाइस नियंत्रक को उद्देश्य भेजने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"टीवी इनपुट से आबद्ध करें"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ऐप्स  को नियर फ़ील्ड कम्यूनिकेशन (NFC) टैग, कार्ड, और रीडर के साथ संचार करने देता है."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"अपना स्‍क्रीन लॉक अक्षम करें"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ऐप्स को कीलॉक और कोई भी संबद्ध पासवर्ड सुरक्षा अक्षम करने देता है. उदाहरण के लिए, इनकमिंग फ़ोन कॉल प्राप्त करते समय फ़ोन, कीलॉक को अक्षम कर देता है, फिर कॉल समाप्त होने पर कीलॉक को पुन: सक्षम कर देता है."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"अंगुली की छाप के लिए हार्डवेयर को प्रबंधित करें"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अंगुली की छाप वाले टेम्पलेट का उपयोग करने के लिए जोड़ने और हटाने हेतु ऐप को विधियां प्रारंभ करने देती है."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"अंगुली की छाप के लिए हार्डवेयर का उपयोग करें"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ऐप के प्रमाणीकरण के लिए अंगुली की छाप हार्डवेयर का उपयोग करने देती है"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"समन्वयन सेटिंग पढ़ें"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ऐप्स  को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह निर्धारित किया जा सकता है कि लोग ऐप्स  किसी खाते के साथ समन्‍वयित है या नहीं."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"समन्‍वयन बंद या चालू टॉगल करें"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स  को नोटिफिकेशन को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स  के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"नोटिफिकेशन श्रवणकर्ता सेवा से जुड़ें"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को नोटिफिकेशन श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स  के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"किसी चयनकर्ता लक्ष्य सेवा से आबद्ध हों"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारक को किसी चयनकर्ता लक्ष्य सेवा के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्‍स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया रूट सेवा से आबद्ध हों"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"धारक को मीडिया रूट सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"भावी सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"धारक को किसी भावी सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स  प्रारंभ करें"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"किसी वाहक संदेश सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"धारक को किसी वाहक संदेश सेवा के शीर्ष-स्‍तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्‍स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्‍क्रीन लॉक पासवर्ड तथा पिन की लंबाई और उसमें अनुमत वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"स्‍क्रीन को अनलॉक करते समय गलत लिखे गए पासवर्ड की संख्‍या पर निगरानी करें, और बहुत अधिक बार गलत पासवर्ड लिखे जाने पर टेबलेट लॉक करें या टेबलेट का संपूर्ण डेटा मिटाएं."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें और यदि बहुत अधिक गलत पासवर्ड लिखे जाते हैं तो टीवी को लॉक करें या टीवी का सभी डेटा मिटा दें."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"गलत लिखे गए पासवर्ड की संख्‍या पर निगरानी करें. स्क्रीन अनलॉक करते समय, बहुत अधिक बार गलत पासवर्ड लिखे जाने पर फ़ोन लॉक करें या फ़ोन का संपूर्ण डेटा मिटाएं."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"स्‍क्रीन-अनलॉक पासवर्ड बदलें"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"स्‍क्रीन-अनलॉक पासवर्ड बदलें."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें और यदि बार बार अधिक पासवर्ड लिखे जाते हैं तो टैबलेट को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें यदि बार बार गलत पासवर्ड लिखे जाने पर टीवी को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"स्‍क्रीन को अनलॉक करते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें और यदि बार बार गलत पासवर्ड लिखे जाते हैं तो फ़ोन को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"स्‍क्रीन लॉक बदलें"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"स्‍क्रीन लॉक को बदलें."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"स्‍क्रीन लॉक करें"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"नियंत्रित करें कि स्‍क्रीन कैसे और कब लॉक हो."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"सभी डेटा मिटाएं"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"फ़ैक्टरी डेटा रीसेट करके, बिना चेतावनी के टेबलेट का डेटा मिटाएं."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"फ़ैक्‍टरी डेटा रीसेट करके चेतावनी दिए बिना टीवी का डेटा मिटा दें."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"फ़ैक्‍टरी डेटा रीसेट करके, बिना चेतावनी के फ़ोन का डेटा मिटाएं."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"उपयोगकर्ता डेटा मिटाएं"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"इस टैबलेट पर मौजूद इस उपयोगकर्ता का डेटा बिना चेतावनी के मिटा दें."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"इस टीवी पर मौजूद इस उपयोगकर्ता का डेटा बिना चेतावनी के मिटा दें."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"इस फ़ोन पर मौजूद इस उपयोगकर्ता का डेटा बिना चेतावनी के मिटा दें."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"डिवाइस वैश्विक प्रॉक्‍सी सेट करें"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"नीति सक्षम होने के दौरान डिवाइस वैश्विक प्रॉक्‍सी सेट करें. केवल पहला डिवाइस नियंत्रक, प्रभावी वैश्विक प्रॉक्‍सी सेट करता है."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"स्‍क्रीन लॉक करें पासवर्ड समाप्ति सेट करें"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"नियंत्रित करें कि कितने समय में लॉक-स्‍क्रीन पासवर्ड बदला जाना चाहिए."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"नीति सक्षम होने के दौरान डिवाइस वैश्विक प्रॉक्‍सी सेट करें. केवल डिवाइस स्‍वामी ही वैश्‍विक प्रॉक्‍सी सेट कर सकता है."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"स्‍क्रीन लॉक पासवर्ड समाप्‍ति सेट करें"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"यह बदलें कि स्‍क्रीन लॉक पासवर्ड, पिन या पैटर्न को कितने समय में बदला जाना चाहिए."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"मेमोरी एन्‍क्रिप्‍शन सेट करें"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत ऐप्स डेटा को एन्क्रिप्ट किया जाना आवश्‍यक है."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"कैमरों को अक्षम करें"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"सभी डिवाइस कैमरों का उपयोग रोकें."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"कीगार्ड में सुविधाएं अक्षम करें"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"कीगार्ड में कुछ सुविधाओं का उपयोग रोकें."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"स्‍क्रीन लॉक सुविधाएं अक्षम करें"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"स्‍क्रीन लॉक की कुछ सुविधाओं का उपयोग रोकें."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"घर"</item>
     <item msgid="869923650527136615">"मोबाइल"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्‍पर्श के द्वारा अन्‍वेषण करें सक्षम करना चाहती है. स्‍पर्श के द्वारा अन्‍वेष करें चालू होने पर, आप अपनी अंगुली के नीचे क्या है उसका विवरण सुन सकते हैं या देख सकते हैं या फ़ोन से डॉयलॉग करने के लिए जेस्‍चर निष्‍पादित कर सकते हैं."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 माह पहले"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 माह से पहले"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 सेकंड पहले"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 मिनट पहले"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 घंटे पहले"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अंतिम <xliff:g id="COUNT">%d</xliff:g> दिन"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">पिछले <xliff:g id="COUNT_1">%d</xliff:g> दिनों में</item>
+      <item quantity="other">पिछले <xliff:g id="COUNT_1">%d</xliff:g> दिनों में</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"पिछला माह"</string>
     <string name="older" msgid="5211975022815554840">"इससे पुराना"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"बीता कल"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 सेकंड में"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 मिनट में"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 घंटे में"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"आने वाला कल"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 सेकंड पहले"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंड पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 मिनट पहले"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनट पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 घंटे पहले"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घंटे पहले"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"बीता कल"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन पहले"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 सेकंड में"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 मिनट में"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनट में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 घंटे में"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घंटे में"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"आने वाला कल"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिन में"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> को"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> पर"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> में"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"सप्ताह"</string>
     <string name="year" msgid="4001118221013892076">"वर्ष"</string>
     <string name="years" msgid="6881577717993213522">"वर्ष"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 सेकंड"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> सेकंड"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 मिनट"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> मिनट"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 घंटा"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> घंटे"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंड</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> मिनट</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> मिनट</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> घंटे</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> घंटे</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"वीडियो समस्‍याएं"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"यह वीडियो इस डिवाइस पर स्ट्रीमिंग के लिए मान्‍य नहीं है."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"यह वीडियो नहीं चलाया जा सकता."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android प्रारंभ हो रहा है…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"मेमोरी ऑप्‍टिमाइज़ हो रही है."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> ऐप्स  अनुकूलित हो रहा है."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तैयार हो रहा है."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ऐप्स  प्रारंभ होने वाले हैं"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्‍त हो रहा है."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चल रही है"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नया ऐप्स प्रारंभ न करें."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string>
     <string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"लेख के लिए किसी क्रिया को चुनें"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर वॉल्‍यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया वॉल्‍यूम"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"कोई नहीं"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिंगटोन"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"वाई-फ़ाई  नेटवर्क उपलब्‍ध"</item>
-    <item quantity="other" msgid="4192424489168397386">"वाई-फ़ाई  नेटवर्क उपलब्‍ध"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"उपलब्‍ध वाई-फ़ाई  नेटवर्क खोलें"</item>
-    <item quantity="other" msgid="7915895323644292768">"खुले वाई-फ़ाई  नेटवर्क उपलब्‍ध है"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
+      <item quantity="other">वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
+      <item quantity="other">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"वाई-फ़ाई  नेटवर्क में प्रवेश करें"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"नेटवर्क में प्रवेश करें"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ऐप्‍लिकेशन %2$s वाई-फ़ाई नेटवर्क से कनेक्‍ट करना चाहता है"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ऐप्लिकेशन"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाई-फ़ाई डायरेक्ट"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाई-फ़ाई  डायरेक्ट प्रारंभ करें. इससे वाई-फ़ाई  क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाई-फ़ाई  डायरेक्ट प्रारंभ नहीं किया जा सका."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक है"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"किसी मीडिया डिवाइस के रूप में कनेक्‍ट किया गया"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"कैमरे के रूप में कनेक्‍ट करें"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI डिवाइस के रूप में कनेक्‍ट है"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"किसी इंस्‍टॉलर के रूप में कनेक्‍ट किया गया"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB सहायक सामग्री से कनेक्‍ट कि‍या गया"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"अन्‍य USB विकल्‍पों के लिए स्पर्श करें."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"अभी नहीं"</string>
     <string name="no_matches" msgid="8129421908915840737">"कोई मिलान नहीं"</string>
     <string name="find_on_page" msgid="1946799233822820384">"पृष्ठ पर ढूंढें"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 मिलान"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> में से <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g> में से <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> में से <xliff:g id="INDEX">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"पूर्ण"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB मेमोरी अनमाउंट हो रहा है…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD कार्ड अनमाउंट किया जा रहा है…"</string>
@@ -1752,8 +1718,8 @@
     <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
     <string name="mediasize_na_letter" msgid="2841414839888344296">"लेटर"</string>
     <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"गवर्नमेंट लेटर"</string>
-    <string name="mediasize_na_legal" msgid="8621364037680465666">"लीगल"</string>
-    <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"जूनियर लीगल"</string>
+    <string name="mediasize_na_legal" msgid="8621364037680465666">"वैधानिक"</string>
+    <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"जूनियर वैधानिक"</string>
     <string name="mediasize_na_ledger" msgid="5567030340509075333">"लेजर"</string>
     <string name="mediasize_na_tabloid" msgid="4571735038501661757">"टेबलॉइड"</string>
     <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"इंडेक्स कार्ड 3x5"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबंधों को बदलने के लिए PIN बनाएं"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN मिलान नहीं करते हैं. फिर से प्रयास करें."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN बहुत छोटा है. कम से कम 4 अंकों का होना चाहिए."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 सेकंड में पुन: प्रयास करें"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंड में पुन: प्रयास करें</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"बाद में फिर से प्रयास करें"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीन से बाहर आने के लिए ऊपर से नीचे स्वाइप करें."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन में देखें"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहर निकलने के लिए, ऊपर से नीचे स्वा‍इप करें."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"समझ लिया"</string>
     <string name="done_label" msgid="2093726099505892398">"पूर्ण"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"घंटो का चक्राकार स्लाइडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनटों का चक्राकार स्लाइडर"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"इस स्क्रीन को अनपिन करने के लिए, एक ही समय में वापस जाएं और अवलोकन को स्पर्श करके रखें."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"इस स्क्रीन को अनपिन करने के लिए, अवलोकन को स्पर्श करके रखें."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्‍क्रीन पिन की गई है. आपके संगठन के द्वारा अनपिन करने की अनुमति नहीं है."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्‍क्रीन पिन की गई"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्‍क्रीन अनपिन की गई"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी जीवन काल को बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन, स्‍थान सेवाओं और अधिकांश पृष्‍ठभूमि डेटा को सीमित कर देता है. हो सकता है कि ईमेल, संदेश सेवा तथा समन्‍वयन पर आधारित अन्‍य ऐप्‍स तब तक ना खुलें जब तक कि आप उन्‍हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"जब तक कि <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> बजे आपका डाउनटाइम समाप्‍त न हो"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"आपका बंद रहने का समय समाप्‍त होने तक"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"एक मिनट के लिए (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> तक)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> तक)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"एक घंटे के लिए (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> तक)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d घंटो के लिए (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> तक)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"एक घंटे के लिए"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d घंटे के लिए"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
+      <item quantity="other">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d घंटे के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
+      <item quantity="other">%1$d घंटे के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d मिनट के लिए</item>
+      <item quantity="other">%d मिनट के लिए</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d घंटे के लिए</item>
+      <item quantity="other">%d घंटे के लिए</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> तक"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"अनिश्चित समय तक"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"संक्षिप्त करें"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर अगले अलार्म तक"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"अगले अलार्म तक"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध को DIAL अनुरोध में बदल दिया गया है."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध को USSD अनुरोध में बदल दिया गया है."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध को नए SS अनुरोध में बदल दिया गया है."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB पेरिफ़ेरल पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-hr-rHR/donottranslate-cldr.xml b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr-rHR/donottranslate-cldr.xml
+++ b/core/res/res/values-hr-rHR/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%-e. %B %Y.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
index 2eb6d87..ca21a47 100755
--- a/core/res/res/values-hr/donottranslate-cldr.xml
+++ b/core/res/res/values-hr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%-e. %B %Y.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1da6527..59893da2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Bez naslova&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nema telefonskog broja)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Nepoznato"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Govorna pošta"</string>
@@ -63,10 +61,11 @@
     <string name="needPuk" msgid="919668385956251611">"Vaša je SIM kartica zaključana PUK-om. Unesite PUK kôd da biste je otključali."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Unesite PUK2 da biste odblokirali SIM karticu."</string>
     <string name="enablePin" msgid="209412020907207950">"Neuspješno; omogući zaključavanje SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Imate još <xliff:g id="NUMBER">%d</xliff:g> pokušaj prije zaključavanja SIM kartice."</item>
-    <item quantity="other" msgid="7530597808358774740">"Imate još nekoliko preostalih pokušaja (<xliff:g id="NUMBER">%d</xliff:g>) prije zaključavanja SIM kartice."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj prije zaključavanja SIM kartice.</item>
+      <item quantity="few">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije zaključavanja SIM kartice.</item>
+      <item quantity="other">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije zaključavanja SIM kartice.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID dolaznog pozivatelja"</string>
@@ -202,6 +201,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Postavke"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
@@ -431,6 +431,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"povezivanje s davateljem usluge usmjeravanja poziva"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nositelju omogućuje povezivanje s registriranim davateljem usluga usmjeravanja poziva. Nije potrebno za normalne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"povezivanje s TV ulazom"</string>
@@ -737,6 +739,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Aplikaciji omogućuje komunikaciju s oznakama, karticama i čitačima komunikacije kratkog dometa (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"onemogućavanje zaključavanja zaslona"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Aplikaciji omogućuje onemogućavanje zaključavanja tipkovnice i svih pripadajućih sigurnosnih zaporki. Na primjer, telefon onemogućuje zaključavanje tipkovnice kod primanja dolaznog telefonskog poziva, nakon kojeg se zaključavanje tipkovnice ponovo omogućuje."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"upravljanje hardverom za čitanje otisaka prstiju"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Aplikaciji omogućuje pozivanje načina za dodavanje i brisanje predložaka otisaka prstiju koji će se upotrijebiti."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"upotreba hardvera za čitanje otisaka prstiju"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Aplikaciji omogućuje upotrebu hardvera za čitanje otisaka prstiju radi autentifikacije."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje postavki sinkronizacije"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Aplikaciji omogućuje čitanje postavki sinkronizacije za račun. Time se, primjerice, može utvrditi je li aplikacija Osobe sinkronizirana s računom."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"uključivanje/isključivanje sinkronizacije"</string>
@@ -791,8 +797,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezivanje s uslugom biranja cilja"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Omogućuje nositelju povezivanje sa sučeljem najviše razine usluge biranja cilja. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezivanje s uslugom davatelja uvjeta"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge davatelja uvjeta. Nije potrebno za normalne aplikacije."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezivanje s uslugom za usmjeravanje medija"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Korisniku omogućuje vezanje uz sučelje najviše razine usluge za usmjeravanje medija. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"vezanje na Dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine za Dream. Ne bi trebalo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pozovi operaterovu aplikaciju za konfiguraciju"</string>
@@ -810,29 +820,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"povezivanje s uslugom mobilnog operatera za slanje poruka"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Omogućuje nositelju povezivanje sa sučeljem najviše razine usluge mobilnog operatera za slanje poruka. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Upravlja duljinom i znakovima koji su dopušteni u zaporkama i PIN-ovima zaključavanja zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Nadziri broj netočnih zaporki unesenih pri otključavanju zaslona i zaključaj tabletno računalo ili izbriši sve podatke na njemu ako je uneseno previše netočnih zaporki."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Prati broj netočnih zaporki unesenih prilikom otključavanja zaslona i zaključava televizor ili briše sve njegove podatke ako se unese previše netočnih zaporki."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Nadzire broj netočno unesenih zaporki pri otključavanju zaslona i zaključava telefon ili briše sve podatke na telefonu ako je uneseno previše netočnih zaporki."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Promijeni zaporku za otključavanje zaslona"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Promijenite zaporku za otključavanje zaslona."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Prati broj netočnih zaporki unesenih prilikom otključavanja zaslona i zaključava tablet ili briše sve podatke korisnika ako se unese previše netočnih zaporki."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Prati broj netočnih zaporki unesenih prilikom otključavanja zaslona i zaključava televizor ili briše sve podatke korisnika ako se unese previše netočnih zaporki."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Prati broj netočnih zaporki unesenih prilikom otključavanja zaslona i zaključava telefon ili briše sve podatke korisnika ako se unese previše netočnih zaporki."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Promijeni zaključavanje zaslona"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Mijenja zaključavanje zaslona."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Zaključaj zaslon"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Upravljanje načinom i vremenom zaključavanja zaslona"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Izbriši sve podatke"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Vraćanjem u tvorničko stanje izbriši podatke tabletnog računala bez upozorenja."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Briše podatke televizora bez upozorenja vraćanjem na tvorničko stanje."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Vraćanjem na tvorničko stanje izbrišite podatke telefona bez upozorenja."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Izbriši podatke korisnika"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Briše podatke korisnika na ovom tabletu bez upozorenja."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Briše podatke korisnika na ovom televizoru bez upozorenja."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Briše podatke korisnika na ovom telefonu bez upozorenja."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"postavi globalni proxy uređaja"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Postavi globalni proxy uređaja za upotrebu dok su pravila omogućena. Samo prvi administrator uređaja postavlja djelotvoran globalni proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Post. istek zap. zaklj. zasl."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Upravljajte učestalošću promjena zaporke za zaključavanje zaslona."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Postavlja globalni proxy za uređaj koji će se upotrebljavati dok je pravilo omogućeno. Samo vlasnik uređaja može postaviti globalni proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Postavi rok zaporke zaklj. zaslona"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Mijenja učestalost obaveznog mijenjanja zaporke, PIN-a ili uzorka zaključavanja zaslona."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Postavi enkripciju za pohranu"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zahtijevajte da pohranjeni podaci aplikacije budu šifrirani."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Onemogući fotoaparate"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Spriječite upotrebu svih kamera uređaja."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Onemogući zaštitu tipkovnice"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Sprječava se upotreba nekih značajki u zaštitnom zaključavanju tipkovnice."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Onemogući znač. zaklj. zaslona"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Sprječava upotrebu nekih značajki zaključavanja zaslona."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Početna"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -1128,75 +1145,13 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Usluga <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogućiti značajku Istraživanje dodirom. Kad je značajka Istraživanje dodirom uključena, možete čuti ili vidjeti opise onoga što je pod vašim prstom ili izvršiti pokrete za interakciju s telefonom."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prije 1 mjesec"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prije 1 mjesec"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Prije 1 sekundu"</item>
-    <item quantity="other" msgid="3903706804349556379">"prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"prije 1 minutu"</item>
-    <item quantity="other" msgid="2176942008915455116">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Prije 1 sata"</item>
-    <item quantity="other" msgid="2467273239587587569">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posljednjih ovoliko dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Posljednjih <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
+      <item quantity="few">Posljednja <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+      <item quantity="other">Posljednjih <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Prošli mjesec"</string>
     <string name="older" msgid="5211975022815554840">"Starije"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"jučer"</item>
-    <item quantity="other" msgid="2479586466153314633">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za 1 minutu"</item>
-    <item quantity="other" msgid="3330713936399448749">"za sljedeći broj minuta: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za 1 sat"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"sutra"</item>
-    <item quantity="other" msgid="5109449375100953247">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Prije 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"Prije <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Prije 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Prije <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Prije 1 sat"</item>
-    <item quantity="other" msgid="6889970745748538901">"Prije <xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"jučer"</item>
-    <item quantity="other" msgid="3453342639616481191">"Prije <xliff:g id="COUNT">%d</xliff:g> dana"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za 1 sat"</item>
-    <item quantity="other" msgid="3705373766798013406">"za sljedeći broj sati: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"sutra"</item>
-    <item quantity="other" msgid="2973062968038355991">"za sljedeći broj dana: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dana <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"u <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>."</string>
@@ -1212,18 +1167,21 @@
     <string name="weeks" msgid="6509623834583944518">"tjedna"</string>
     <string name="year" msgid="4001118221013892076">"godina"</string>
     <string name="years" msgid="6881577717993213522">"godina"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 s"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 min"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 sat"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekunda</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sat</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sata</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sati</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problem s videozapisom"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ovaj videozapis nije valjan za streaming na ovaj uređaj."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ovaj videozapis nije moguće reproducirati."</string>
@@ -1301,6 +1259,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Pokretanje Androida..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje pohrane."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiziranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripremanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Završetak inicijalizacije."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne pokreći novu aplikaciju."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zaustavi staru aplikaciju bez spremanja."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izaberite radnju za tekst"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Glasnoća zvona"</string>
     <string name="volume_music" msgid="5421651157138628171">"Glasnoća medija"</string>
@@ -1331,20 +1298,25 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nijedan"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznata melodija zvona"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Dostupna je Wi-Fi mreža"</item>
-    <item quantity="other" msgid="4192424489168397386">"Dostupne su Wi-Fi mreže"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Omogućavanje otvaranja Wi-Fi mreže"</item>
-    <item quantity="other" msgid="7915895323644292768">"Omogućavanje otvaranja Wi-Fi mreža"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Dostupne su Wi-Fi mreže</item>
+      <item quantity="few">Dostupne su Wi-Fi mreže</item>
+      <item quantity="other">Dostupne su Wi-Fi mreže</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Dostupne su otvorene Wi-Fi mreže</item>
+      <item quantity="few">Dostupne su otvorene Wi-Fi mreže</item>
+      <item quantity="other">Dostupne su otvorene Wi-Fi mreže</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Prijavite se na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Prijavite se na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s traži povezivanje s Wi-Fi mrežom %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Pokretanje izravne Wi-Fi veze nije moguće."</string>
@@ -1411,6 +1383,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"U redu"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Spojen kao medijski uređaj"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Spojen kao fotoaparat"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Povezan kao MIDI uređaj"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Spojen kao instalacijski program"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Spojen na USB pribor"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Dodirnite za ostale opcije USB uređaja"</string>
@@ -1526,10 +1499,11 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nema rezultata"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Pronađi na stranici"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 podudaranje"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Gotovo"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Isključivanje USB pohrane..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Isključivanje SD kartice..."</string>
@@ -1815,12 +1789,15 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izradite PIN za izmjenu ograničenja"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora imati barem 4 znamenke."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Ponovite za 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Ponovite za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
+      <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+      <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Prijeđite prstom s vrha prema dolje za izlaz iz cijelog zaslona."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Gledanje preko cijelog zaslona"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Za izlaz prijeđite prstom prema od vrha prema dolje."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Shvaćam"</string>
     <string name="done_label" msgid="2093726099505892398">"Gotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kružni klizač sati"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač minuta"</string>
@@ -1835,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkvačili ovaj zaslon, istovremeno dodirnite i zadržite Natrag i Pregled."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Pregled."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pričvršćen. Vaša organizacija ne dopušta otkvačivanje."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je otkvačen"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
@@ -1844,24 +1822,28 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dok razdoblje zastoja ne završi u <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do završetka prekida rada"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Jednu minutu (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d min (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Jedan sat (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d h (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d min"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Jedan sat"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d h"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d minutu (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d sat (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d sata (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d sati (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d minutu</item>
+      <item quantity="few">%d minute</item>
+      <item quantity="other">%d minuta</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d sat</item>
+      <item quantity="few">%d sata</item>
+      <item quantity="other">%d sati</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Neodređeno"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sažmi"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do sljedećeg alarma u <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do sljedećeg alarma"</string>
@@ -1874,4 +1856,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtjev izmijenjen je u DIAL zahtjev."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev izmijenjen je u USSD zahtjev."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev izmijenjen je u novi SS zahtjev."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB priključak za periferne uređaje"</string>
 </resources>
diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
index 81e3b12..fd2fe92 100755
--- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml
+++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%Y. %B %-e.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%Y.%m.%d., %-k:%M:%S</string>
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
index bafa25e..3f60be7 100755
--- a/core/res/res/values-hu/donottranslate-cldr.xml
+++ b/core/res/res/values-hu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%Y. %B %-e.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %Y.%m.%d.</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8d959ff..12a0fb7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> másodperc"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> másodperc"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Névtelen&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nincs telefonszám)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Ismeretlen"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Hangposta"</string>
@@ -58,15 +56,15 @@
     <string name="badPin" msgid="9015277645546710014">"A megadott régi PIN kód helytelen."</string>
     <string name="badPuk" msgid="5487257647081132201">"A megadott PUK kód helytelen."</string>
     <string name="mismatchPin" msgid="609379054496863419">"A beírt PIN kódok nem egyeznek."</string>
-    <string name="invalidPin" msgid="3850018445187475377">"Írjon be egy 4-8 számjegyű PIN-kódot."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Írjon be egy 4-8 számjegyű PIN kódot."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 számjegyű vagy hosszabb PUK kódot írjon be."</string>
     <string name="needPuk" msgid="919668385956251611">"A SIM kártya le van zárva a PUK kóddal. A feloldáshoz adja meg a PUK kódot."</string>
     <string name="needPuk2" msgid="4526033371987193070">"A SIM kártya feloldásához adja meg a PUK2 kódot."</string>
     <string name="enablePin" msgid="209412020907207950">"Sikertelen, engedélyezze a SIM-/RUIM-zárolást."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van, mielőtt zároljuk a SIM kártyát."</item>
-    <item quantity="other" msgid="7530597808358774740">"Még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van, mielőtt zároljuk a SIM kártyát."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Még <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása van a SIM kártya zárolásáig.</item>
+      <item quantity="one">Még <xliff:g id="NUMBER_0">%d</xliff:g> próbálkozása van a SIM kártya zárolásáig.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Beérkező hívóazonosító"</string>
@@ -77,7 +75,7 @@
     <string name="CwMmi" msgid="9129678056795016867">"Hívásvárakoztatás"</string>
     <string name="BaMmi" msgid="455193067926770581">"Hívásletiltás"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Jelszómódosítás"</string>
-    <string name="PinMmi" msgid="3113117780361190304">"PIN-kód módosítása"</string>
+    <string name="PinMmi" msgid="3113117780361190304">"PIN kód módosítása"</string>
     <string name="CnipMmi" msgid="3110534680557857162">"Szám hívása"</string>
     <string name="CnirMmi" msgid="3062102121430548731">"Hívószám korlátozva"</string>
     <string name="ThreeWCMmi" msgid="9051047170321190368">"Háromutas hívás"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Repülőgép üzemmód bekapcsolva"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Repülőgép üzemmód kikapcsolva"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Beállítások"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hangsegéd"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"csatlakozás egy útvonal-szolgáltatóhoz"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Az eszköz kezelője csatlakozhat bármely regisztrált útvonal-szolgáltatóhoz. A normál alkalmazások esetében erre nincs szükség."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"csatlakozás tévébemenethez"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Lehetővé teszi az alkalmazás számára, hogy NFC (Near Field Communication - kis hatósugarú vezeték nélküli kommunikáció) technológiát használó címkékkel, kártyákkal és leolvasókkal kommunikáljon."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"képernyőzár kikapcsolása"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Lehetővé teszi az alkalmazás számára a billentyűzár és bármely kapcsolódó jelszavas védelem kikapcsolását. Például a telefon feloldja a billentyűzárat bejövő hívás esetén, majd újra bekapcsolja azt a hívás végeztével."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ujjlenyomat-olvasó hardver kezelése"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Lehetővé teszi az alkalmazás számára a használni kívánt ujjlenyomatsablonok hozzáadására és törlésére szolgáló metódusok indítását."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ujjlenyomat-olvasó hardver használata"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Lehetővé teszi az alkalmazás számára az ujjlenyomat-olvasó hardver hitelesítésre való használatát"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"szinkronizálási beállítások olvasása"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Lehetővé teszi az alkalmazás számára egy fiók szinkronizálási beállításainak beolvasását. Például ellenőrizheti, hogy a Személyek alkalmazás szinkronizálva van-e egy fiókkal."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"szinkronizálás be-és kikapcsolása"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"csatlakozás célválasztó szolgáltatáshoz"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lehetővé teszi a használó számára, hogy csatlakozzon egy célválasztó 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_bindConditionProviderService" msgid="1180107672332704641">"csatlakozás egy feltételbiztosító szolgáltatáshoz"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lehetővé teszi a használó számára, hogy csatlakozzon egy feltételbiztosító 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_bindMediaRouteService" msgid="6637740382272686835">"csatlakozás egy médiaútvonal-szolgáltatáshoz"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Lehetővé teszi a használó számára, hogy csatlakozzon egy médiaútvonal-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_bindDreamService" msgid="4153646965978563462">"csatlakozás egy képernyővédő szolgáltatáshoz"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Lehetővé teszi a használó számára, hogy csatlakozzon egy képernyővédő 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_invokeCarrierSetup" msgid="3699600833975117478">"a szolgáltatói konfigurációs alkalmazás hívása"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"kapcsolódás egy üzenetszolgáltatáshoz"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy üzenetszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"A képernyőzár jelszavaiban és PIN kódjaiban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Megfigyeli a képernyő feloldásakor helytelenül beírt jelszavak számát, és túl sok hibásan beírt jelszó esetén lezárja a táblagépet, vagy törli a táblagép összes adatát."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"A képernyőzárolás során megadott helytelen jelszavak számának figyelése, és a tévé zárolása vagy a tévé összes adatának törlése abban az esetben, ha túl sokszor adtak meg helytelen jelszót."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Megfigyeli a képernyő feloldásakor helytelenül beírt jelszavak számát, és túl sok hibásan beírt jelszó esetén lezárja a telefont, vagy törli a telefon összes adatát."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"A képernyőzárat feloldó jelszó módosítása"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"A képernyőzárat feloldó jelszó módosítása."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"A képernyőzárolás során megadott helytelen jelszavak számának figyelése, és a táblagép zárolása vagy a felhasználó összes adatának törlése abban az esetben, ha túl sokszor adtak meg helytelen jelszót."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"A képernyőzárolás során megadott helytelen jelszavak számának figyelése, és a tévé zárolása vagy a felhasználó összes adatának törlése abban az esetben, ha túl sokszor adtak meg helytelen jelszót."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"A képernyőzárolás során megadott helytelen jelszavak számának figyelése, és a telefon zárolása vagy a felhasználó összes adatának törlése abban az esetben, ha túl sokszor adtak meg helytelen jelszót."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"A képernyőzár módosítása"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"A képernyőzár módosítása."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"A képernyő zárolása"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"A képernyőzárolás módjának és idejének vezérlése."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Minden adat törlése"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Figyelmeztetés nélkül törli a táblagép adatait, visszaállítva a gyári adatokat."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"A tévé adatainak törlése a gyári alapbeállítások visszaállításával anélkül, hogy figyelmeztetés jelenne meg erről."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Figyelmeztetés nélkül törli a telefon összes adatát, visszaállítva a gyári adatokat."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"A felhasználói adatok törlése"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"A felhasználó összes adatának törlése erről a táblagépről figyelmeztetés nélkül."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"A felhasználó összes adatának törlése erről a tévéről figyelmeztetés nélkül."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"A felhasználó összes adatának törlése erről a telefonról figyelmeztetés nélkül."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Az eszköz globális proxyjának beállítása"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Az eszköz globális proxyja lesz használatban, amíg az irányelv engedélyezve van. Csak az eszköz első rendszergazdája állíthatja be a tényleges globális proxyt."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Képernyőjelszó érvényessége"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Azt vezérli, hogy milyen gyakran kell módosítani a képernyőzár jelszavát."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Az eszköz globális proxyja lesz használatban, amíg a házirend engedélyezve van. A globális proxyt csak az eszköz tulajdonosa állíthatja be."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Zárolási jelszó lejárati ideje"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Annak módosítása, hogy a képernyőzár jelszavát, PIN kódját vagy mintáját milyen gyakran kell megváltoztatni."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Tárhelytitkosítás beállítása"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Megköveteli a tárolt alkalmazásadatok titkosítását."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kamerák letiltása"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Az összes eszközkamera használatának megakadályozása."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Funkciók letiltása billentyűzár esetén."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Bizonyos funkciók használatának megakadályozása billentyűzár esetén."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Képernyőzár-funkciók letiltása"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Egyes képernyőzár-funkciók használatának megakadályozása."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Otthoni"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> aktiválni szeretné a Felfedezés érintéssel funkciót. Amikor be van kapcsolva a Felfedezés érintéssel, akkor hallhatja vagy láthatja annak leírását, ami az ujja alatt van, illetve végrehajthat kézmozdulatokat a telefon kezeléséhez."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 hónapja"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Több mint 1 hónapja"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 másodperce"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 perce"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 órája"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Elmúlt <xliff:g id="COUNT">%d</xliff:g> napban"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">A legutóbbi <xliff:g id="COUNT_1">%d</xliff:g> nap</item>
+      <item quantity="one">A legutóbbi <xliff:g id="COUNT_0">%d</xliff:g> nap</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Múlt hónapban"</string>
     <string name="older" msgid="5211975022815554840">"Régebbi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"tegnap"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 másodperc múlva"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 perc múlva"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 óra múlva"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"holnap"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 másodperce"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> másodperce"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 perce"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> perce"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 órája"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> órája"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"tegnap"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> napja"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 másodperc múlva"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 perc múlva"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> perc múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 óra múlva"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> óra múlva"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"holnap"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> nap múlva"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"e napon: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"év: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"hét"</string>
     <string name="year" msgid="4001118221013892076">"év"</string>
     <string name="years" msgid="6881577717993213522">"év"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 másodperc"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> másodperc"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 perc"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> perc"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 óra"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> óra"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> másodperc</item>
+      <item quantity="one">1 másodperc</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> perc</item>
+      <item quantity="one">1 perc</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> óra</item>
+      <item quantity="one">1 óra</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoprobléma"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ezt a videót nem lehet megjeleníteni ezen az eszközön."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nem lehet lejátszani ezt a videót."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Az Android indítása…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Tárhely-optimalizálás."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Alkalmazás optimalizálása: <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> előkészítése."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Kezdő alkalmazások."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Rendszerindítás befejezése."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> fut"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne indítsa el az új alkalmazást."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> indítása"</string>
     <string name="new_app_description" msgid="1932143598371537340">"A régi alkalmazás leállítása mentés nélkül."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Válasszon ki egy műveletet a szöveghez"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Csengetés hangereje"</string>
     <string name="volume_music" msgid="5421651157138628171">"Média hangereje"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Egyik sem"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Csengőhangok"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ismeretlen csengőhang"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi hálózat elérhető"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi hálózatok elérhetők"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Nyílt Wi-Fi hálózat elérhető"</item>
-    <item quantity="other" msgid="7915895323644292768">"Nyílt Wi-Fi hálózatok elérhetők"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi hálózatok érhetők el</item>
+      <item quantity="one">Van elérhető Wi-Fi hálózat</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Nyílt Wi-Fi hálózatok érhetők el</item>
+      <item quantity="one">Nyílt Wi-Fi hálózat érhető el</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Bejelentkezés Wi-Fi hálózatba"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Bejelentkezés a hálózatba"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A(z) %1$s alkalmazás szeretne csatlakozni a következő Wi-Fi hálózathoz: %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Egy alkalmazás"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nem sikerült elindítani a Wi-Fi Direct kapcsolatot."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Csatlakoztatva médiaeszközként"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Csatlakoztatva kameraként"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Csatlakoztatva MIDI-eszközként"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Csatlakoztatva telepítőként"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Csatlakoztatva egy USB-kiegészítőhöz"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Érintse meg a további USB-opciókért."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Kihagyás"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nincs találat"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Keresés az oldalon"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 találat"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>/<xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 találat</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Kész"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Az USB-tár leválasztása..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-kártya leválasztása..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN kód létrehozása a korlátozások módosításához"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"A PIN kódok nem egyeznek. Próbálja újra."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"A PIN kód túl rövid. Legalább 4 számjegyből kell állnia."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Próbálja újra 1 másodperc múlva"</item>
-    <item quantity="other" msgid="4730868920742952817">"Próbálja újra <xliff:g id="COUNT">%d</xliff:g> másodperc múlva"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Próbálja újra <xliff:g id="COUNT">%d</xliff:g> másodperc múlva</item>
+      <item quantity="one">Próbálja újra 1 másodperc múlva</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Próbálkozzon később"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"A teljes képernyős nézetből való kilépéshez húzza ujját a képernyő tetejétől lefelé."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Megtekintése teljes képernyőn"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Kilépéshez csúsztassa ujját fentről lefelé."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Értem"</string>
     <string name="done_label" msgid="2093726099505892398">"Kész"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Óra kör alakú csúszkája"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Perc kör alakú csúszkája"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés lehetőséget egyszerre."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"A képernyő rögzítésének feloldásához tartsa lenyomva az Áttekintés lehetőséget."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A képernyő rögzítve van. Szervezete nem engedélyezi a rögzítés feloldását."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Képernyő rögzítése feloldva"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN kód kérése a rögzítés feloldásához"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Amíg az állásidő véget nem ér ekkor: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Amíg az inaktivitás véget nem ér"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Egy percre (eddig: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d percre (eddig: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Egy órára (eddig: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d órára (eddig: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Egy percen át"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d percen át"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Egy órán át"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d órán át"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d percen át (eddig: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Egy percen át (eddig: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d órán át (eddig: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Egy órán át (eddig: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d percen át</item>
+      <item quantity="one">Egy percen át</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d órán át</item>
+      <item quantity="one">Egy órán át</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Határozatlan ideig"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Összecsukás"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"A következő ébresztésig ekkor: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"A következő ébresztésig"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Az SS-kérés módosítva DIAL-kérésre."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Az SS-kérés módosítva USSD-kérésre."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Az SS-kérés módosítva új SS-kérésre."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-perifériaport"</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 6de4b8e..29510b3 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -21,9 +21,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"Բ"</string>
-    <string name="kilobyteShort" msgid="5973789783504771878">"Կբ"</string>
-    <string name="megabyteShort" msgid="6355851576770428922">"Մբ"</string>
-    <string name="gigabyteShort" msgid="3259882455212193214">"Գբ"</string>
+    <string name="kilobyteShort" msgid="5973789783504771878">"ԿԲ"</string>
+    <string name="megabyteShort" msgid="6355851576770428922">"ՄԲ"</string>
+    <string name="gigabyteShort" msgid="3259882455212193214">"ԳԲ"</string>
     <string name="terabyteShort" msgid="231613018159186962">"Տբ"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"Պբ"</string>
     <string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> վ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> վ"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Անանուն&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Հեռախոսահամար չկա)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Անհայտ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Ձայնային փոստ"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Ձեր SIM քարտը PUK-ով կողպված է: Մուտքագրեք PUK կոդը այն ապակողպելու համար:"</string>
     <string name="needPuk2" msgid="4526033371987193070">"Մուտքագրեք PUK2-ը` SIM քարտն արգելաբացելու համար:"</string>
     <string name="enablePin" msgid="209412020907207950">"Ձախողվեց: Միացրեք SIM/RUIM կողպումը:"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ՝ մինչև SIM-ի արգելափակումը:"</item>
-    <item quantity="other" msgid="7530597808358774740">"Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ՝ մինչև SIM-ի արգելափակումը:"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն արգելափակվելու է:</item>
+      <item quantity="other">Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն արգելափակվելու է:</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Մուտքային զանգողի ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"կապվել երթուղու մատակարարի ծառայությանը"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Թույլ է տալիս տիրոջը կապվել երթուղու մատակարարներից ցանկացածին: Սովորական ծրագրերի համար երբեք անհրաժեշտ չէ:"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Թույլ է տալիս սեփականատիրոջը ուղարկել մտադրություններ սարքի կառավարչին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"միանալ հեռուստացույցի մուտքին"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Թույլ է տալիս հավելվածին հաղորդակցվել Մոտ տարածությամբ հաղորդակցման (NFC) պիտակների, քարտերի և ընթերցիչների հետ:"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"անջատել ձեր էկրանի կողպեքը"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Թույլ է տալիս հավելվածին անջատել ստեղնաշարի կողպումը և ցանկացած համակցված գաղտնաբառի պաշտպանվածությունը: Սրա ճիշտ օրինակն է, երբ հեռախոսը անջատում է ստեղնաշարի կողպումը մուտքային զանգ ստանալիս, հետո այն կրկին միացնում է, երբ զանգը ավարտվում է:"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"կառավարել մատնահետքերի գրանցման սարքը"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Հավելվածին թույլ է տալիս կատարել այնպիսի գործառույթներ, որոնց միջոցով կարելի է օգտագործման համար ավելացնել և հեռացնել մատնահետքերի նմուշներ:"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"օգտագործել մատնահետքերի գրանցման սարքը"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Հավելվածին թույլ է տալիս նույնականացման համար օգտագործել մատնահետքերի գրանցման սարքը"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամեցման կարգավորումները"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամեցման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամեցված է հաշվի հետ:"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամեցումը փոխարկել միացվածի և անջատվածի"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"միանալ ընտրողի թիրախային ծառայությանը"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Թույլ է տալիս միանալ ընտրողի թիրախային ծառայության վերին մակարդակի միջերեսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"կապվել պայմանների մատակարարի ծառայությանը"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Թույլ է տալիս սեփականատիրոջը միանալ պայմանների մատակարարների բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"կապվել մեդիա երթուղու ծառայությանը"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Թույլ է տալիս սեփականատիրոջը միանալ մեդիա երթուղու ծառայության բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"Միացում էկրանապահների ծառայությանը"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Թույլ է տալիս սեփականատիրոջը միանալ էկրանապահների ծառայության վերին մակարդակի միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Կապակցում օպերատորի հաղորդագրությունների ծառայության հետ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Թույլ է տալիս տիրոջը կապվել օպերատորի հաղորդագրությունների ծառայության վերին մակարդակի միջերեսի հետ: Սա երբեք չի պահանջվում սովորական հավելվածների համար:"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Վերահսկել սխալ գաղտնաբառերի թիվը, որոնք մուտքագրվել են էկրանն ապակողպելիս, և կողպել գրասալիկը կամ ջնջել գրասալիկի բոլոր տվյալները, եթե մուտքագրվել են չափից շատ սխալ գաղտնաբառեր:"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Վերահսկել սխալ գաղտնաբառերի թիվը, որոնք մուտքագրվել են էկրանը ապակողպելիս, և կողպել հեռուստացույցը կամ ջնջել բոլոր տվյալները, եթե չափից ավելի սխալ գաղտնաբառեր են մուտքագրվել:"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Վերահսկել սխալ գաղտնաբառերի թիվը, որոնք մուտքագրվել են էկրանն ապակողպելիս, և կողպել հեռախոսը կամ ջնջել հեռախոսի բոլոր տվյալները, եթե մուտքագրվել են չափից շատ սխալ գաղտնաբառեր:"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Փոխել էկրանի ապակողպման գաղտնաբառը"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Փոխել էկրանի ապակողպման գաղտնաբառը:"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Կառավարել էկրանն ապակողպելիս մուտքագրվող սխալ գաղտնաբառերի թիվը և կողպել գրասալիկը կամ ջնջել այս օգտվողի բոլոր տվյալները չափից ավելի սխալ գաղտնաբառեր մուտքագրելու դեպքում:"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Կառավարել էկրանն ապակողպելիս մուտքագրվող սխալ գաղտնաբառերի թիվը և կողպել հեռուստացույցը կամ ջնջել այս օգտվողի բոլոր տվյալները չափից ավելի սխալ գաղտնաբառեր մուտքագրելու դեպքում:"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Կառավարել էկրանն ապակողպելիս մուտքագրվող սխալ գաղտնաբառերի թիվը և կողպել հեռախոսը կամ ջնջել այս օգտվողի բոլոր տվյալները չափից ավելի սխալ գաղտնաբառեր մուտքագրելու դեպքում:"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Փոխել էկրանի կողպման գաղտնաբառը"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Փոխել էկրանի կողպման գաղտնաբառը:"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Կողպել էկրանը"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Վերահսկել` ինչպես և երբ է էկրանը կողպվում:"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Ջնջել բոլոր տվյալները"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ջնջել գրասալիկի տվյալներն առանց նախազգուշացման` կատարելով գործարանային տվյալների վերակայում:"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Ջնջել հեռուստացույցի տվյալները առանց զգուշացման՝ վերականգնելով գործարանային կարգավորումները:"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ջնջել հեռախոսի տվյալներն առանց նախազգուշացման` կատարելով գործարանային տվյալների վերակայում:"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Ջնջել օգտվողի տվյալները"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ջնջել այս օգտվողի տվյալներն այս գրասալիկում առանց նախազգուշացման:"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ջնջել այս օգտվողի տվյալներն այս հեռուստացույցում առանց նախազգուշացման:"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Ջնջել այս օգտվողի տվյալներն այս հեռախոսում առանց նախազգուշացման:"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Կարգավորել սարքի համաշխարհային պրոքսին"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Սարքը կարգավորել, որ համաշխարհային պրոքսին օգտագործվի, երբ քաղաքականությունը միացված է: Միայն առաջին սարքի կառավարիչն է կարգավորում գործող համաշխարհային պրոքսին:"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Սահմանել էկրանի կողպման գաղտնաբառի սպառման ժամկետը"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Վերահսկել` ինչ հաճախականությամբ պետք է էկրանի կողպման գաղտնաբառը փոխվի:"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Կարգավորել, որ սարքի համընդհանուր պրոքսի-սերվերն օգտագործվի, երբ քաղաքականությունը միացված է: Միայն սարքի սեփականատերը կարող է կարգավորել համընդհանուր պրոքսի-սերվերը:"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Նշել էկր կողպ գաղտնաբ սպառումը"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Փոխել էկրանի կողպման գաղտնաբառի, PIN-ի կամ նախշի փոփոխման հաճախականությունը:"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Կարգավորել պահոցի կոդավորումը"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Պահանջել, որ պահվող հավելվածների տվյալները լինեն կոդավորված:"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Կասեցնել տեսախցիկները"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Կանխել բոլոր սարքերի ֆոտոխցիկների օգտագործումը:"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Անջատել ստեղնակողպեքի գործառույթները"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Կանխել ստեղնակողպեքի որոշ գործառույթների օգտագործումը:"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Անջ. էկր. կողպ. գործառույթները"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Կանխել էկրանի կողպման որոշ գործառույթների օգտագործումը:"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Տնային"</item>
     <item msgid="869923650527136615">"Բջջային"</item>
@@ -1055,7 +1071,7 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Վերաբեռնել"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"«<xliff:g id="TITLE">%s</xliff:g>»-ի էջում ասվում է`"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Հաստատել կողմնորոշումը"</string>
+    <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Գործողության հաստատում"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Լքել այս էջը"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Մնալ այս էջում"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nՎստա՞հ եք, որ ցանկանում եք հեռանալ այս էջից:"</string>
@@ -1094,7 +1110,7 @@
     <string name="permlab_readVoicemail" msgid="8415201752589140137">"կարդալ ձայնային փոստը"</string>
     <string name="permdesc_readVoicemail" msgid="8926534735321616550">"Ծրագրին թույլ է տալիս կարդալ ձեր ձայնային փոստը"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"փոփոխել դիտարկչի աշխարհագրական տեղանքի թույլտվությունները"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել զննարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Թույլ է տալիս հավելվածին փոփոխել դիտարկչի աշխարհագրական դիրքի թույլտվությունները: Վնասարար հավելվածները կարող են օգտագործել սա` թույլատրելու ուղարկել տեղադրության վերաբերյալ տեղեկությունները կամայական վեբ կայքերին:"</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"հաստատել փաթեթները"</string>
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Թույլ է տալիս հավելվածին հաստատել, որ փաթեթը տեղադրելի է:"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"միանալ փաթեթի ստուգիչին"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ը ցանկանում է միացնել «Հետազոտում հպման միջոցով» ռեժիմը: Երբ միացված է «Հետազոտում հպման միջոցով» ռեժիմը, դուք կարող եք լսել կամ տեսնել նկարագրությունը, թե ինչ է ձեր մատի տակ, կամ կատարել ժեստեր`  հեռախոսի հետ փոխգործակցելու համար:"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ամիս առաջ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ավելի շուտ քան 1 ամիս"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 վայրկյան առաջ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> վայրկյան առաջ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 րոպե առաջ"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ժամ առաջ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Վերջին <xliff:g id="COUNT">%d</xliff:g> օրերին"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Վերջին <xliff:g id="COUNT_1">%d</xliff:g> օրում</item>
+      <item quantity="other">Վերջին <xliff:g id="COUNT_1">%d</xliff:g> օրում</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Անցյալ ամիս"</string>
     <string name="older" msgid="5211975022815554840">"Ավելի հին"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"երեկ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 վայրկյանից"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> վայրկյանից"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 րոպեից"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 ժամից"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"վաղը"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 վրկ առաջ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> վրկ. առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 րոպե առաջ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> րոպե առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ժամ առաջ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ժամ առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"երեկ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> օր առաջ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 վրկ-ից"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> վրկ-ից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 րոպեից"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> րոպեից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 ժամից"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ժամից"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"վաղը"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> օրից"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ին"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ժամը <xliff:g id="TIME">%s</xliff:g>-ին"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> թվականին"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"շաբաթ"</string>
     <string name="year" msgid="4001118221013892076">"տարի"</string>
     <string name="years" msgid="6881577717993213522">"տարի"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 վայրկյան"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> վայրկյան"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 րոպե"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> րոպե"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ժամ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ժամ"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> վայրկյան</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> վայրկյան</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> րոպե</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> րոպե</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ժամ</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ժամ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Տեսանյութի խնդիր"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Այս տեսանյութը հեռարձակման ենթակա չէ այս սարքով:"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Այս տեսանյութը հնարավոր չէ նվագարկել:"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android-ը մեկնարկում է…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Պահեստի օպտիմալացում:"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Օպտիմալացվում է հավելված <xliff:g id="NUMBER_0">%1$d</xliff:g>-ը <xliff:g id="NUMBER_1">%2$d</xliff:g>-ից:"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը պատրաստվում է:"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Հավելվածները մեկնարկում են:"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Բեռնումն ավարտվում է:"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>-ն աշխատում է"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Չսկսել նոր հավելված:"</string>
     <string name="new_app_action" msgid="5472756926945440706">"Սկիզբ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Դադարեցնել նախկին ծրագիրն առանց պահպանման:"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Ընտրեք գործողություն տեքստի համար"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Զանգակի ձայնի ուժգնությունը"</string>
     <string name="volume_music" msgid="5421651157138628171">"Մեդիա ձայնի բարձրություն"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ոչ մեկը"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Զանգերանգներ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Անհայտ զանգերանգ"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi ցանցը հասանելի է"</item>
-    <item quantity="other" msgid="4192424489168397386">"հասանելի են Wi-Fi ցանցեր"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Բաց Wi-Fi ցանցը հասանելի է"</item>
-    <item quantity="other" msgid="7915895323644292768">"Հասանելի են բաց Wi-Fi ցանցեր"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Հասանելի են Wi-Fi ցանցեր</item>
+      <item quantity="other">Հասանելի են Wi-Fi ցանցեր</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
+      <item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Մուտք գործեք Wi-Fi ցանց"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Մուտք գործել ցանց"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ունի թույլ ինտերնետ կապ:"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s հավելվածը ցանկանում է միանալ %2$s Wifi ցանցին"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Հավելված"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ուղիղ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Մեկնարկել Wi-Fi ուղին: Այն կանջատի Wi-Fi հաճախորդ/թեժ կետ գործողությունը:"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Չհաջողվեց մեկնարկել Wi-Fi ուղին:"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Լավ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Կապակցված է որպես մեդիա սարք"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Միացված է որպես ֆոտոխցիկ"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Կապակցված է որպես MIDI սարք"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Միացված է որպես տեղադրիչ"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Կապակցված է USB լրասարքի"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Հպեք` այլ USB ընտրանքների համար:"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Բաց թողնել"</string>
     <string name="no_matches" msgid="8129421908915840737">"Համընկնում չկա"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Գտեք էջում"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 համընկնում"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>-ից <xliff:g id="INDEX">%d</xliff:g>-ը"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g>՝ <xliff:g id="TOTAL">%d</xliff:g>-ից</item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>՝ <xliff:g id="TOTAL">%d</xliff:g>-ից</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Կատարված է"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Անջատվում է USB կրիչը..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Անջատում է SD քարտը..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Ստեղծել PIN՝ սահմանափակումները փոփոխելու համար"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-երը չեն համընկնում: Փորձեք կրկին:"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-ը չափազանց կարճ է: Պետք է ունենա առնվազն 4 թվանիշ:"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Կրկին փորձեք 1 վայրկյանից"</item>
-    <item quantity="other" msgid="4730868920742952817">"Կրկին փորձեք <xliff:g id="COUNT">%d</xliff:g> վայրկյանից"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Կրկին փորձեք <xliff:g id="COUNT">%d</xliff:g> վայրկյանից</item>
+      <item quantity="other">Կրկին փորձեք <xliff:g id="COUNT">%d</xliff:g> վայրկյանից</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Կրկին փորձեք մի փոքր ուշ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Սահահարվածեք վերից վար՝ ամբողջական էկրանից դուրս գալու համար:"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Լիաէկրան դիտում"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Պարզ է"</string>
     <string name="done_label" msgid="2093726099505892398">"Պատրաստ է"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ժամերի ընտրություն թվատախտակից"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Րոպեների ընտրություն թվատախտակից"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Այս էկրան ապամրացնելու համար միաժամանակ հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Համատեսքի կոճակը:"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Էկրանն ամրացված է: Ապամրացումը չի թույլատրվում ձեր կազմակերպության կողմից:"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Էկրանն ապամրացված է"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու նպատակով, մարտկոցի էներգիայի խնայման գործառույթը սահմանափակում է սարքի աշխատանքը, թրթռոցը, տեղադրության ծառայությունները և հետնաշերտում աշխատող շատ գործընթացներ: Էլփոստը, հաղորդագրությունների փոխանակումը և տվյալների համաժամեցումից կախված այլ հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\nԵրբ ձեր սարքը լիցքավորվում է, մարտկոցի էներգիայի խնայման գործառույթն ինքնաշխատորեն անջատվում է:"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Մինչև ձեր ժամանակն ավարտվի ժամը <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Մինչև անգործունության ժամանակն ավարտվի"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Մեկ րոպե (մինչև <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Մեկ ժամ (մինչև <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d ժամ (մինչև <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d րոպե"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Մեկ ժամ"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d ժամ"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d ժամ (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d ժամ (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d րոպե</item>
+      <item quantity="other">%d րոպե</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d ժամ</item>
+      <item quantity="other">%d ժամ</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Մինչև <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Անորոշ ժամանակով"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Թաքցնել"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Մինչև հաջորդ զարթուցիչը՝ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Մինչև հաջորդ զարթուցիչը"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS հարցումը փոխվել է DIAL հարցման:"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS հարցումը փոխվել է USSD հարցման:"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS հարցումը փոխվել է նոր SS հարցման:"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB արտաքին միացք"</string>
 </resources>
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
index 1f8e542..823b41f 100755
--- a/core/res/res/values-in-rID/donottranslate-cldr.xml
+++ b/core/res/res/values-in-rID/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
     <string name="date_time">%2$s %1$s</string>
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
index b57823a..35a84eb 100755
--- a/core/res/res/values-in/donottranslate-cldr.xml
+++ b/core/res/res/values-in/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ffabeda..502f318 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> dtk"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> dtk"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Tanpa judul&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Tidak ada nomor telepon)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Tidak diketahui"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Kotak Pesan"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Kartu SIM Anda dikunci PUK. Ketikkan kode PUK untuk membukanya."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Ketikkan PUK2 untuk membuka kartu SIM"</string>
     <string name="enablePin" msgid="209412020907207950">"Gagal, aktifkan Kunci SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan sebelum SIM terkunci."</item>
-    <item quantity="other" msgid="7530597808358774740">"Sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan sebelum SIM terkunci."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan sebelum SIM terkunci.</item>
+      <item quantity="one">Sisa <xliff:g id="NUMBER_0">%d</xliff:g> percobaan sebelum SIM terkunci.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Nomor Penelepon Masuk"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Setelan"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Bantuan"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mengikat ke layanan penyedia rute"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Memungkinkan pemegang mengikat ke penyedia rute terdaftar mana pun. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"mengikat ke masukan TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Mengizinkan apl berkomunikasi dengan tag, kartu, dan alat pembaca Komunikasi Nirkabel Jarak Dekat (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"nonaktifkan kunci layar Anda"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Memungkinkan aplikasi menonaktifkan kunci tombol dan keamanan sandi apa pun yang terkait. Misalnya, ponsel menonaktifkan kunci tombol saat menerima panggilan telepon masuk, kemudian mengaktifkan kembali kunci tombol ketika panggilan selesai."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"kelola perangkat keras sidik jari"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Mengizinkan aplikasi memanggil metode untuk menambahkan dan menghapus template sidik jari untuk digunakan."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan perangkat keras sidik jari"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Mengizinkan aplikasi untuk menggunakan perangkat keras sidik jari untuk otentikasi"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"baca setelan sinkron"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Memungkinkan aplikasi membaca setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat menentukan apakah aplikasi Orang disinkronkan dengan sebuah akun."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"nyalakan dan matikan sinkronisasi"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mengikat ke layanan sasaran pemilik"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"mengikat ke layanan penyedia ketentuan"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan penyedia ketentuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mengikat ke layanan rute media"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan rute media. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"mengikat ke layanan lamunan"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan lamunan. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"memanggil aplikasi konfigurasi yang disediakan operator"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ikat ke layanan perpesanan operator"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Mengizinkan operator untuk mengikat ke antarmuka tingkat tinggi dari suatu layanan perpesanan operator. Fitur ini seharusnya tidak diperlukan oleh aplikasi normal."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengontrol panjang dan karakter yang diizinkan dalam sandi dan PIN kunci layar."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Memantau jumlah sandi yang salah ketik saat membuka kunci layar, dan mengunci tablet atau menghapus semua data tablet jika sandi yang salah ketik terlalu banyak."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Memantau banyaknya sandi salah yang diketikkan saat membuka kunci layar, dan mengunci TV atau menghapus semua data TV jika terlalu banyak sandi salah diketikkan."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Memantau jumlah sandi salah ketik saat membuka kunci layar, dan mengunci ponsel atau menghapus semua data ponsel jika sandi yang salah ketik terlalu banyak."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ubah sandi pembuka kunci layar"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ubah sandi pembuka kunci layar."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Memantau banyaknya sandi salah yang diketikkan saat membuka kunci layar, dan mengunci tablet atau menghapus semua data pengguna ini jika terlalu banyak sandi salah diketikkan."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Memantau banyaknya sandi salah yang diketikkan saat membuka kunci layar, dan mengunci TV atau menghapus semua data pengguna ini jika terlalu banyak sandi salah diketikkan."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Memantau banyaknya sandi salah yang diketikkan saat membuka kunci layar, dan mengunci ponsel atau menghapus semua data pengguna ini jika terlalu banyak sandi salah diketikkan."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Mengubah kunci layar"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Mengubah kunci layar."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Kunci layar"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrol cara dan kapan layar mengunci."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Hapus semua data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Hapus data tablet tanpa peringatan dengan menyetel ulang data pabrik."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Menghapus data TV tanpa peringatan dengan mengembalikan ke setelan pabrik."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Hapus data ponsel tanpa peringatan dengan menyetel ulang data pabrik."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Menghapus data pengguna"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Menghapus data pengguna ini di tablet ini tanpa peringatan."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Menghapus data pengguna ini di TV ini tanpa peringatan."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Menghapus data pengguna ini di ponsel ini tanpa peringatan."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setel proxy global perangkat"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setel proxy global perangkat yang akandigunakan ketika kebijakan diaktifkan. Hanya admin perangkat pertama yang menyetel procy global yang berlaku."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Setel kedaluwarsa sandi pengunci layar"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontrol seberapa sering sandi pengunci layar harus diganti."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Menyetel proxy global perangkat yang akan digunakan jika kebijakan diaktifkan. Hanya pemilik perangkat yang dapat menyetel proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Menyetel berakhirnya sandi kunci layar"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Mengubah seberapa sering sandi, PIN, atau pola kunci layar harus diubah."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setel enkripsi penyimpanan"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Mengharuskan data apl yang disimpan untuk dienkripsi."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Nonaktifkan kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Mencegah penggunaan semua kamera perangkat."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Nonaktifkan fitur di pengaman"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Mencegah penggunaan beberapa fitur dalam pengaman."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Menonaktifkan fitur kunci layar"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Mencegah penggunaan beberapa fitur kunci layar."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Rumah"</item>
     <item msgid="869923650527136615">"Seluler"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mengaktifkan Menjelajah dengan Sentuhan. Saat Menjelajah dengan Sentuhan diaktifkan, Anda dapat mendengar atau melihat deskripsi dari apa yang ada di bawah jari Anda atau melakukan gerakan untuk berinteraksi dengan ponsel."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 detik lalu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 menit yang lalu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> hari terakhir"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g> hari terakhir</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g> hari terakhir</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Bulan lalu"</string>
     <string name="older" msgid="5211975022815554840">"Lawas"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kemarin"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dalam 1 detik"</item>
-    <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dalam 1 menit"</item>
-    <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
-    <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"besok"</item>
-    <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 detik yang lalu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> detik yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 menit yang lalu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> menit yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kemarin"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dalam 1 detik"</item>
-    <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> detik"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dalam 1 menit"</item>
-    <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> menit"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
-    <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"besok"</item>
-    <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"minggu"</string>
     <string name="year" msgid="4001118221013892076">"tahun"</string>
     <string name="years" msgid="6881577717993213522">"tahun"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 detik"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> detik"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 menit"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> menit"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 jam"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> detik</item>
+      <item quantity="one">1 detik</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> menit</item>
+      <item quantity="one">1 menit</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> jam</item>
+      <item quantity="one">1 jam</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video ini tidak valid untuk pengaliran ke perangkat ini."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat memutar video ini."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Memulai Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Mengoptimalkan penyimpanan."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimalkan aplikasi <xliff:g id="NUMBER_0">%1$d</xliff:g> dari <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Menyiapkan <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulai aplikasi."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Menyelesaikan boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Mulai <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume dering"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume media"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Tidak Ada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak dikenal"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Jaringan Wi-Fi tersedia"</item>
-    <item quantity="other" msgid="4192424489168397386">"Jaringan Wi-Fi"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Jaringan Wi-Fi terbuka tersedia"</item>
-    <item quantity="other" msgid="7915895323644292768">"Jaringan Wi-Fi terbuka tersedia"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Jaringan Wi-Fi tersedia</item>
+      <item quantity="one">Jaringan Wi-Fi tersedia</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Jaringan Wi-Fi terbuka tersedia</item>
+      <item quantity="one">Jaringan Wi-Fi terbuka tersedia</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Masuk ke jaringan Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Masuk ke jaringan"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin tersambung ke Jaringan Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikasi"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Direct. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulai Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Oke"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tersambung sebagai perangkat media"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tersambung sebagai kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Terhubung sebagai perangkat MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tersambung sebagai pemasang"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tersambung ke aksesori USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Sentuh untuk opsi USB lainnya."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Lewati"</string>
     <string name="no_matches" msgid="8129421908915840737">"Tidak ada kecocokan"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Temukan pada laman"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 kecocokan"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> dari <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> dari <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 kecocokan</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Selesai"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Melepas penyimpanan USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Melepas kartu SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Buat PIN untuk mengubah batasan"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak cocok. Coba lagi."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Minimal 4 digit."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Coba 1 dtk lagi"</item>
-    <item quantity="other" msgid="4730868920742952817">"Coba <xliff:g id="COUNT">%d</xliff:g> detik lagi"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Coba <xliff:g id="COUNT">%d</xliff:g> detik lagi</item>
+      <item quantity="one">Coba 1 detik lagi</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Coba lagi nanti"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Gesek dari atas ke bawah untuk keluar dari layar penuh."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat layar penuh"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, gesek ke bawah dari atas."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Mengerti"</string>
     <string name="done_label" msgid="2093726099505892398">"Selesai"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Penggeser putar jam"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Penggeser putar menit"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk melepas pin layar ini, sentuh lama tombol Kembali dan Ringkasan secara bersamaan."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk melepas pin layar ini, sentuh lama tombol Ringkasan."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Layar disematkan. Pelepasan sematan tidak diizinkan oleh organisasi Anda."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Layar disematkan"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Layar dicopot sematannya"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hingga waktu perbaikan Anda berakhir pukul <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hingga waktu non-operasional berakhir"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Selama semenit (hingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Selama %1$d menit (hingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Selama sejam (hingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Selama %1$d jam (hingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
-    <item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
-    <item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Selama %1$d menit (hingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Selama satu menit (hingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Selama %1$d jam (hingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Selama satu jam (hingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Selama %d menit</item>
+      <item quantity="one">Selama satu menit</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Selama %d jam</item>
+      <item quantity="one">Selama satu jam</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Tidak ditentukan"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Ciutkan"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Sampai alarm berikutnya pukul <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Sampai alarm berikutnya"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah menjadi permintaan DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah menjadi permintaan USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah menjadi permintaan SS baru."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port Periferal USB"</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 9ca0f58..11b4d98 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Ónefnt&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ekkert símanúmer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Óþekkt"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Talhólf"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-kortið er PUK-læst. Sláðu inn PUK-númerið til að taka það úr lás."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Sláðu inn PUK2-númer að taka SIM-kortið úr lás."</string>
     <string name="enablePin" msgid="209412020907207950">"Tókst ekki. Kveiktu á SIM-/RUIM-lás."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraun eftir áður en SIM-kortinu verður læst."</item>
-    <item quantity="other" msgid="7530597808358774740">"Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraunir eftir áður en SIM-kortinu verður læst."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir áður en SIM-kortinu verður læst.</item>
+      <item quantity="other">Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraunir eftir áður en SIM-kortinu verður læst.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Númerabirting innhringinga"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"KVEIKT er á flugstillingu"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"SLÖKKT er á flugstillingu"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Stillingar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Raddaðstoð"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leyfir forriti að bindast efsta viðmótslagi fjartengds skjás. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bindast græjuþjónustu"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leyfir handhafa að bindast efsta viðmótslagi græjuþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bindast þjónustu leiðaveitu"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Leyfir handhafa að bindast öllum veitum skráðra leiða. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"samskipti við stjórnanda tækis"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leyfir handhafa að senda tilgang til stjórnanda tækis. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bindast sjónvarpsinntaki"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Leyfir forriti að eiga samskipti við NFC-merki, -spjöld og -lesara (nándarsamskipti)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"slökkva á skjálásnum"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Leyfir forriti að slökkva á símalásnum og öðrum öryggisaðgerðum tengdum aðgangsorði. Til dæmis gerir síminn lásinn óvirkan þegar símtal berst og læsist svo aftur að símtali loknu."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"stjórna fingrafarabúnaði"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Gerir forritinu kleift að beita aðferðum til að bæta við og eyða fingrafarasniðmátum til notkunar."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"nota fingrafarabúnað"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Leyfir forritinu að nota fingrafarabúnað til auðkenningar"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lesa samstillingar"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Leyfir forriti að lesa kosti samstillingar fyrir reikning. Þetta er til dæmis hægt að nota til að komast að því hvort forritið Fólk er samstillt við reikning."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kveikja og slökkva á samstillingu"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Leyfir forriti að sækja, skoða og hreinsa tilkynningar, þ. á m. þær sem önnur forrit birta."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bindast hlustunarþjónustu tilkynninga"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leyfir forriti að bindast efsta viðmótslagi hlustunarþjónustu tilkynninga. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bindast valþjónustu fyrir markmið"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Leyfir handhafa að bindast efsta viðmótslagi valþjónustu fyrir markmið. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bindast þjónustu skilyrðaveitu"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Leyfir handhafa að bindast efsta viðmótslagi skilyrðaveitu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bindast beiningarþjónustu fyrir margmiðlun"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Leyfir handhafa að bindast efsta viðmótslagi beiningarþjónustu fyrir margmiðlun. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"bindast skjávaraþjónustu"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Leyfir handhafa að bindast efsta viðmótslagi skjávaraþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ræsa grunnstillingarforrit frá símafyrirtæki"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bindast skilaboðaþjónustu símafyrirtækis"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Leyfir forriti að bindast efsta viðmótslagi skilaboðaþjónustu símafyrirtækis. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setja reglur um aðgangsorð"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stjórna lengd aðgangsorða til að taka skjáinn úr lás og leyfðum stöfum."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stjórna lengd og fjölda stafa í aðgangsorðum og PIN-númerum skjáláss."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Fylgjast með tilraunum til að taka skjáinn úr lás"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa spjaldtölvunni eða eyða öllum gögnum hennar ef rangt aðgangsorð er fært inn of oft."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa sjónvarpinu eða eyða öllum gögnum þess ef rangt aðgangsorð er fært inn of oft."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa símanum eða eyða öllum gögnum hans ef rangt aðgangsorð er fært inn of oft."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Breyta aðgangsorði skjáláss"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Breyta aðgangsorðinu til að taka skjáinn úr lás."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa spjaldtölvunni eða eyða öllum gögnum viðkomandi notanda ef rangt aðgangsorð er fært inn of oft."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa sjónvarpinu eða eyða öllum gögnum viðkomandi notanda ef rangt aðgangsorð er fært inn of oft."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Fylgjast með fjölda rangra innskráningartilrauna með aðgangsorði þegar skjárinn er tekinn úr lás og læsa símanum eða eyða öllum gögnum viðkomandi notanda ef rangt aðgangsorð er fært inn of oft."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Breyta skjálásnum"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Breyta skjálásnum."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Læsa skjánum"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Stjórna hvernig og hvenær skjárinn læsist."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Eyða öllum gögnum"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Eyða gögnum spjaldtölvunnar fyrirvaralaust með núllstillingu."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Eyða gögnum sjónvarpsins fyrirvaralaust með núllstillingu."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Eyða gögnum símans fyrirvaralaust með núllstillingu."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Eyða gögnum notanda"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Eyða gögnum viðkomandi notanda í þessari spjaldtölvu án viðvörunar."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Eyða gögnum viðkomandi notanda í þessu sjónvarpi án viðvörunar."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Eyða gögnum viðkomandi notanda í þessum síma án viðvörunar."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Stilla altækan proxy-þjón fyrir tækið"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stilla altækan proxy-þjón tækisins sem nota á þegar stefnan er virk. Aðeins fyrsti stjórnandi tækisins stillir virkan altækan proxy-þjón."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Stilla fyrningu aðgangsorðs"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Stjórna hversu oft þarf að skipta um aðgangsorð til að taka skjáinn úr lás."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Velja altækan proxy-þjón tækisins sem nota á þegar stefnan er virk. Aðeins eigandi tækisins getur valið altækan proxy-þjón."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Velja gildistíma aðgangsorðs"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Breyta því hversu oft þarf að skipta um aðgangsorð, PIN-númer eða mynstur skjáláss."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Velja dulkóðun geymslu"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Krefjast þess að geymd forritsgögn séu dulkóðuð."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Slökkva á myndavélum"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Koma í veg fyrir notkun allra myndavéla tækisins."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Óvirkja eiginleika lyklavörslu"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Koma í veg fyrir notkun sumra eiginleika lyklavörslu."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Slökkva á eiginleikum skjáláss"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Koma í veg fyrir notkun sumra eiginleika skjáláss."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Heima"</item>
     <item msgid="869923650527136615">"Farsími"</item>
@@ -902,7 +918,7 @@
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Brúðkaupsafmæli"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Annað"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Sérsniðið"</string>
-    <string name="emailTypeHome" msgid="449227236140433919">"Heim"</string>
+    <string name="emailTypeHome" msgid="449227236140433919">"Heima"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Vinna"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Annað"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Farsími"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill kveikja á snertikönnun. Þegar kveikt er á snertikönnun geturðu heyrt eða séð lýsingu á því sem er á skjánum undir fingrinum hverju sinni eða notað bendingar til að stjórna símanum."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Fyrir mánuði"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Fyrir meira en mánuði"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"fyrir sekúndu"</item>
-    <item quantity="other" msgid="3903706804349556379">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"fyrir mínútu"</item>
-    <item quantity="other" msgid="2176942008915455116">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"fyrir klukkustund"</item>
-    <item quantity="other" msgid="2467273239587587569">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Síðustu <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Undanfarinn <xliff:g id="COUNT_1">%d</xliff:g> dag</item>
+      <item quantity="other">Undanfarna <xliff:g id="COUNT_1">%d</xliff:g> daga</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Í síðasta mánuði"</string>
     <string name="older" msgid="5211975022815554840">"Eldra"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"í gær"</item>
-    <item quantity="other" msgid="2479586466153314633">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"eftir sekúndu"</item>
-    <item quantity="other" msgid="1241926116443974687">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"eftir mínútu"</item>
-    <item quantity="other" msgid="3330713936399448749">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"eftir klukkustund"</item>
-    <item quantity="other" msgid="547290677353727389">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"á morgun"</item>
-    <item quantity="other" msgid="5109449375100953247">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"fyrir sekúndu"</item>
-    <item quantity="other" msgid="3699169366650930415">"fyrir <xliff:g id="COUNT">%d</xliff:g> sekúndum"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"fyrir mínútu"</item>
-    <item quantity="other" msgid="851164968597150710">"fyrir <xliff:g id="COUNT">%d</xliff:g> mínútum"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"fyrir klukkustund"</item>
-    <item quantity="other" msgid="6889970745748538901">"fyrir <xliff:g id="COUNT">%d</xliff:g> klukkustundum"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"í gær"</item>
-    <item quantity="other" msgid="3453342639616481191">"fyrir <xliff:g id="COUNT">%d</xliff:g> dögum"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"eftir sekúndu"</item>
-    <item quantity="other" msgid="5495880108825805108">"eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"eftir mínútu"</item>
-    <item quantity="other" msgid="4216113292706568726">"eftir <xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"eftir klukkustund"</item>
-    <item quantity="other" msgid="3705373766798013406">"eftir <xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"á morgun"</item>
-    <item quantity="other" msgid="2973062968038355991">"eftir <xliff:g id="COUNT">%d</xliff:g> daga"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"vikur"</string>
     <string name="year" msgid="4001118221013892076">"ár"</string>
     <string name="years" msgid="6881577717993213522">"ár"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekúnda"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 mínúta"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> mínútur"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 klukkustund"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> klukkustundir"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekúnda</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekúndur</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> mínúta</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> mínútur</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> klukkustund</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> klukkustundir</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Vandamál með myndskeið"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Þetta myndskeið er ekki gjaldgengt fyrir straumspilun í þessu tæki."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ekki er hægt að spila þetta myndskeið."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android er að ræsast…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Fínstillir geymslu."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Fínstillir forrit <xliff:g id="NUMBER_0">%1$d</xliff:g> af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Undirbýr <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ræsir forrit."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Lýkur ræsingu."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ekki ræsa nýja forritið."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Ræsa <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stöðva gamla forritið án þess að vista."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Veldu aðgerð fyrir texta"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hljóðstyrkur hringingar"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hljóðstyrkur efnisspilunar"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Enginn"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Hringitónar"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Óþekktur hringitónn"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi net í boði"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi net í boði"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Opið Wi-Fi net í boði"</item>
-    <item quantity="other" msgid="7915895323644292768">"Opin Wi-Fi net í boði"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Wi-Fi net í boði</item>
+      <item quantity="other">Wi-Fi net í boði</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Opin Wi-Fi net í boði</item>
+      <item quantity="other">Opin Wi-Fi net í boði</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Skrá inn á Wi-Fi net"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Skrá inn á net"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" er með lélegt netsamband."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Forritið %1$s vill tengjast Wi-Fi netinu %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Forrit"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ræsa Wi-Fi Direct. Þetta mun slökkva á Wi-Fi biðlara/aðgangsstað."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Ekki var hægt að ræsa Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Í lagi"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tengt sem geymslumiðill"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tengt sem myndavél"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Tengt sem MIDI-tæki"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tengt sem uppsetningarforrit"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tengt við USB-aukabúnað"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Snertu til að sjá aðra USB-valkosti."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Sleppa"</string>
     <string name="no_matches" msgid="8129421908915840737">"Engar samsvaranir"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Finna á síðu"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Ein samsvörun"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> af <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Lokið"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Aftengir USB-geymslu…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Aftengir SD-kort…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Búðu til PIN-númer til að breyta takmörkunum"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-númerin stemma ekki. Reyndu aftur."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-númerið er of stutt. Það verður að vera a.m.k. 4 tölustafir."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Reyndu aftur eftir sekúndu"</item>
-    <item quantity="other" msgid="4730868920742952817">"Reyndu aftur eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Reyndu aftur eftir <xliff:g id="COUNT">%d</xliff:g> sekúndu</item>
+      <item quantity="other">Reyndu aftur eftir <xliff:g id="COUNT">%d</xliff:g> sekúndur</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Reyndu aftur síðar"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Strjúktu niður frá efri brún til að hætta að nota allan skjáinn."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Notar allan skjáinn"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Strjúktu niður frá efri brún til að hætta."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ég skil"</string>
     <string name="done_label" msgid="2093726099505892398">"Lokið"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Valskífa fyrir klukkustundir"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Valskífa fyrir mínútur"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Til að taka lásinn af þessari skjámynd skaltu halda inni Til baka og Yfirliti samtímis."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Til að taka lásinn af þessari skjámynd skaltu halda inni Yfirliti."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjárinn er festur. Póstskipanin þín leyfir ekki að hann sé losaður."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjár opnaður"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Þangað til niðritíma lýkur, <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Þar til niðritíma lýkur"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Í eina mínútu (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Í %1$d mín. (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Í eina klukkustund (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Í %1$d klst. (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Í eina mínútu"</item>
-    <item quantity="other" msgid="6924190729213550991">"Í %d mínútur"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Í eina klukkustund"</item>
-    <item quantity="other" msgid="5408537517529822157">"Í %d klukkustundir"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Í %1$d mínútu (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Í %1$d mínútur (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Í %1$d klukkustund (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Í %1$d klukkustundir (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Í %d mínútu</item>
+      <item quantity="other">Í %d mínútur</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Í %d klukkustund</item>
+      <item quantity="other">Í %d klukkustundir</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Án tímatakmarkana"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Þar til þú slekkur á þessu"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Minnka"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fram að næsta vekjara kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fram að næsta vekjara"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-beiðni er breytt í DIAL-beiðni."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-beiðni er breytt í USSD-beiðni."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-beiðni er breytt í nýja SS-beiðni."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB-tengi fyrir jaðartæki"</string>
 </resources>
diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml
index 2aea9510..95ba6dc 100755
--- a/core/res/res/values-it/donottranslate-cldr.xml
+++ b/core/res/res/values-it/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d/%b/%Y</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d781042..2ab192f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secondi"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> secondo"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Senza nome&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nessun numero di telefono)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Sconosciuto"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Segreteria"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"La SIM è bloccata tramite PUK. Digita il codice PUK per sbloccarla."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Digita il PUK2 per sbloccare la SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Operazione non riuscita; attiva blocco SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata."</item>
-    <item quantity="other" msgid="7530597808358774740">"Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata.</item>
+      <item quantity="one">Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID chiamante in entrata"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Impostazioni"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"collegamento a un servizio provider di routing"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Consente al titolare di collegarsi a qualsiasi provider di routing registrato. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"collegamento a ingresso TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Consente all\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disattivazione blocco schermo"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Consente all\'applicazione di disattivare il blocco tastiera ed eventuali protezioni tramite password associate. Ad esempio, il telefono disattiva il blocco tastiera quando riceve una telefonata in arrivo e lo riattiva al termine della chiamata."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestisci hardware per il riconoscimento delle impronte digitali"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Consente all\'app di richiamare metodi per aggiungere e rimuovere modelli di impronte digitali da utilizzare."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizza hardware per il riconoscimento delle impronte digitali"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Consente all\'app di utilizzare l\'hardware per il riconoscimento delle impronte digitali per eseguire l\'autenticazione"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"attivazione e disattivazione della sincronizzazione"</string>
@@ -755,7 +760,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"lettura contenuti scheda SD"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"L\'app può leggere i contenuti dell\'archivio USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Consente all\'applicazione di leggere i contenuti della scheda SD."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"Modifica/eliminazione contenuti USB"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifica/eliminazione contenuti USB"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifica o eliminazione dei contenuti della scheda SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Consente all\'applicazione di scrivere nell\'archivio USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Consente all\'applicazione di scrivere sulla scheda SD."</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"collegamento al servizio di destinazione di un utente"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Consente al titolare di collegarsi all\'interfaccia di primo livello del servizio di destinazione di un utente. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"associa a servizio di routing multimediale"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Consente di eseguire l\'associazione all\'interfaccia di primo livello di un servizio di routing multimediale. Generalmente non necessario per le normali app."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"associa a servizio dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Consente all\'utente di associare l\'interfaccia di primo livello di un servizio dream. Questa impostazione non è mai necessaria per le app normali."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"associazione a un servizio di messaggi dell\'operatore"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Consente l\'associazione di un servizio di messaggi dell\'operatore all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Impostazione regole password"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlla la lunghezza e i caratteri ammessi nelle password e nei PIN del blocco schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Controllo tentativi di sblocco dello schermo"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitora il numero di password errate digitate durante lo sblocco dello schermo e blocca il tablet o cancella tutti i dati del tablet se vengono digitate troppe password errate."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Consente di monitorare il numero di password sbagliate inserite per sbloccare lo schermo, nonché di bloccare la TV e cancellarne tutti i dati se vengono digitate troppe password errate."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitora il numero di password errate digitate durante lo sblocco dello schermo e blocca il telefono o cancella tutti i dati del telefono se vengono digitate troppe password errate."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Cambia la password di sblocco dello schermo"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Cambia la password di sblocco dello schermo."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitora il numero di password errate digitate durante lo sblocco dello schermo e blocca il tablet o resetta tutti i dati dell\'utente se è stato raggiunto il limite massimo consentito."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitora il numero di password errate digitate durante lo sblocco dello schermo e blocca la TV o resetta tutti i dati dell\'utente se è stato raggiunto il limite massimo consentito."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitora il numero di password errate digitate durante lo sblocco dello schermo e blocca il telefono o resetta tutti i dati dell\'utente se è stato raggiunto il limite massimo consentito."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Modifica blocco schermo"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Modifica il blocco schermo."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Blocco dello schermo"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlla come e quando si blocca lo schermo."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Cancellazione di tutti i dati"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Cancella i dati del tablet senza preavviso eseguendo un ripristino dati di fabbrica."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Consente di cancellare i dati della TV senza preavviso eseguendo un ripristino dei dati di fabbrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Cancella i dati del telefono senza preavviso eseguendo un ripristino dati di fabbrica."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Resetta i dati dell\'utente"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Resetta i dati dell\'utente sul tablet senza preavviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Resetta i dati dell\'utente sulla TV senza preavviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Resetta i dati dell\'utente sul telefono senza preavviso."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Imposta il proxy globale del dispositivo"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Impostazione scadenza password blocco schermo"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Stabilisci la frequenza di modifica della password di blocco dello schermo."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale può essere impostato solo dal proprietario del dispositivo."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Imposta scadenza password blocco schermo"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Cambia la frequenza di modifica di password, PIN o sequenza del blocco schermo."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Impostazione crittografia archivio"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Richiede la crittografia dei dati applicazione memorizzati."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Disattivazione fotocamere"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedisci l\'utilizzo di tutte le fotocamere del dispositivo."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Disattiva le funzioni con il blocco tastiera"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Impedisce l\'utilizzo di alcune funzioni con il blocco tastiera."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Disattiva funzioni blocco schermo"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Impedisce l\'utilizzo di alcune funzioni del blocco schermo."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Cellulare"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vuole attivare la funzione Esplora al tocco. Quando la funzione Esplora al tocco è attiva, puoi ascoltare o visualizzare le descrizioni di ciò che stai toccando oppure interagire con il telefono tramite gesti."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mese fa"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Oltre 1 mese fa"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 secondo fa"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> secondi fa"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto fa"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuti fa"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ora fa"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ultimi <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Ultimi <xliff:g id="COUNT_1">%d</xliff:g> giorni</item>
+      <item quantity="one">Ultimo giorno (<xliff:g id="COUNT_0">%d</xliff:g>)</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Ultimo mese"</string>
     <string name="older" msgid="5211975022815554840">"Precedente"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ieri"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"tra 1 secondo"</item>
-    <item quantity="other" msgid="1241926116443974687">"tra <xliff:g id="COUNT">%d</xliff:g> secondi"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"tra 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"tra <xliff:g id="COUNT">%d</xliff:g> minuti"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"tra 1 ora"</item>
-    <item quantity="other" msgid="547290677353727389">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"domani"</item>
-    <item quantity="other" msgid="5109449375100953247">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sec fa"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min fa"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ora fa"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ieri"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"tra 1 sec"</item>
-    <item quantity="other" msgid="5495880108825805108">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"tra 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"tra 1 ora"</item>
-    <item quantity="other" msgid="3705373766798013406">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"domani"</item>
-    <item quantity="other" msgid="2973062968038355991">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"in data <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"alle ore <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"nel <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"settimane"</string>
     <string name="year" msgid="4001118221013892076">"anno"</string>
     <string name="years" msgid="6881577717993213522">"anni"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 secondo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> secondi"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuti"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ore"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> secondi</item>
+      <item quantity="one">1 secondo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuti</item>
+      <item quantity="one">1 minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ore</item>
+      <item quantity="one">1 ora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problemi video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Questo video non è valido per lo streaming su questo dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Impossibile riprodurre il video."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Avvio di Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ottimizzazione archiviazione."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ottimizzazione applicazione <xliff:g id="NUMBER_0">%1$d</xliff:g> di <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> in preparazione."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Avvio applicazioni."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Conclusione dell\'avvio."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Non avviare la nuova applicazione."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Avvia <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Interrompi la vecchia applicazione senza salvare."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Scegli un\'azione per il testo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume suoneria"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume contenuti multimediali"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nessuna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Suoneria sconosciuta"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Rete Wi-Fi disponibile"</item>
-    <item quantity="other" msgid="4192424489168397386">"Reti Wi-Fi disponibili"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Rete Wi-Fi aperta disponibile"</item>
-    <item quantity="other" msgid="7915895323644292768">"Reti Wi-Fi aperte disponibili"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Reti Wi-Fi disponibili</item>
+      <item quantity="one">Rete Wi-Fi disponibile</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Apri reti Wi-Fi disponibili</item>
+      <item quantity="one">Apri rete Wi-Fi disponibile</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Accedi a rete Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Accedi alla rete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'applicazione %1$s vorrebbe connettersi alla rete Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Un\'applicazione"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Avvio di Wi-Fi Direct non riuscito."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Collegato come dispositivo multimediale"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Collegato come fotocamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Connesso come un dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Collegato come installer"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Collegato a un accessorio USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Tocca per altre opzioni USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ignora"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nessuna corrispondenza"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Trova nella pagina"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 corrispondenza"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> di <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> di <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 partita</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Fine"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Smontaggio dell\'archivio USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Smontaggio scheda SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crea un PIN per la modifica delle limitazioni"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"I PIN non corrispondono. Riprova."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Il PIN è troppo corto. Deve avere almeno quattro cifre."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Riprova fra 1 s."</item>
-    <item quantity="other" msgid="4730868920742952817">"Riprova tra <xliff:g id="COUNT">%d</xliff:g> s."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Riprova tra <xliff:g id="COUNT">%d</xliff:g> secondi</item>
+      <item quantity="one">Riprova tra 1 secondo</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Riprova più tardi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Scorri dall\'alto verso il basso per uscire dalla modalità schermo intero."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualizzazione a schermo intero"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Per uscire, scorri dall\'alto verso il basso."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Fine"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Dispositivo di scorrimento circolare per le ore"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Dispositivo di scorrimento circolare per i minuti"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per sbloccare questa schermata, tocca e tieni premute contemporaneamente le opzioni Indietro e Panoramica."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Per sbloccare questa schermata, tocca e tieni premuta l\'opzione Panoramica."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"La schermata è bloccata. La tua organizzazione non ne consente lo sblocco."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Schermata sbloccata"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN prima di sbloccare"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di localizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Fino al termine del periodo di inattività previsto per le <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Fino al termine del periodo di inattività"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Per un minuto (fino alle ore <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Per un\'ora (fino alle ore <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Per %1$d ore (fino alle ore <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Per un minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Per un\'ora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Per %d ore"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Per un minuto (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Per %1$d ore (fino alla ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Per un\'ora (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Per %d minuti</item>
+      <item quantity="one">Per un minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Per %d ore</item>
+      <item quantity="one">Per un\'ora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Sempre"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Comprimi"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Fino alla prossima sveglia alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Fino alla prossima sveglia"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"La richiesta SS è stata modificata in richiesta DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"La richiesta SS è stata modificata in richiesta USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La richiesta SS è stata modificata in nuova richiesta SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta periferica USB"</string>
 </resources>
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
index cf05c9d..a9015d0 100755
--- a/core/res/res/values-iw/donottranslate-cldr.xml
+++ b/core/res/res/values-iw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e ב%B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ac8d2a5..15c1b35 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> שניות"</string>
     <string name="durationSecond" msgid="985669622276420331">"שנייה <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
     <string name="untitled" msgid="4638956954852782576">"‏&gt;ללא כותרת&lt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(אין מספר טלפון)"</string>
     <string name="unknownName" msgid="6867811765370350269">"לא ידוע"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"דואר קולי"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"‏כרטיס ה-SIM נעול באמצעות PUK. הקלד את קוד PUK כדי לבטל את נעילתו."</string>
     <string name="needPuk2" msgid="4526033371987193070">"‏הקלד PUK2 כדי לבטל את חסימת כרטיס ה-SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"‏לא הצלחת. הפעל נעילת SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"‏נותר לך ניסיון <xliff:g id="NUMBER">%d</xliff:g> לפני נעילת כרטיס ה-SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"‏נותרו לך <xliff:g id="NUMBER">%d</xliff:g> ניסיונות לפני נעילת כרטיס ה-SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="two">‏נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני נעילת כרטיס ה-SIM.</item>
+      <item quantity="many">‏נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני נעילת כרטיס ה-SIM.</item>
+      <item quantity="other">‏נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני נעילת כרטיס ה-SIM.</item>
+      <item quantity="one">‏נותר לך ניסיון <xliff:g id="NUMBER_0">%d</xliff:g> לפני נעילת כרטיס ה-SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"זיהוי מתקשר של שיחה נכנסת"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"מצב טיסה מופעל"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"מצב טיסה כבוי"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
@@ -431,6 +432,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"‏הכפפה לשירות Widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"‏מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"איגוד לשירות של ספק ניתוב"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"מאפשרת לבעלים לאגד לספקי ניתוב רשומים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"איגוד לקלט טלוויזיה"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"מאפשר לאפליקציה נהל תקשורת עם תגים, כרטיסים וקוראים מסוג \'תקשורת מטווח קצר\'."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ביטול נעילת המסך שלך"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"מאפשר לאפליקציה להשבית את נעילת המקשים וכל אמצעי אבטחה משויך המבוסס על סיסמה. לדוגמה, הטלפון משבית את נעילת המקשים בעת קבלה של שיחת טלפון נכנסת, ולאחר מכן מפעיל מחדש את נעילת המקשים עם סיום השיחה."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ניהול חומרה של טביעות אצבעות"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"מאפשר לאפליקציה להפעיל שיטות להוספה ומחיקה של תבניות טביעות אצבעות שבהן ייעשה שימוש."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"שימוש בחומרה של טביעות אצבעות"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"מאפשר לאפליקציה להשתמש בחומרה של טביעות אצבעות לצורך אימות"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"קרא את הגדרות הסינכרון"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"מאפשר לאפליקציה לקרוא את הגדרות הסנכרון של חשבון. לדוגמה, ניתן לגלות כך האם האפליקציה \'אנשים\' מסונכרן עם חשבון כלשהו."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"הפעלת וכיבוי סנכרון"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"‏איגוד אל שירות Chooser Target"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"‏מאפשר לבעלים לאגד לממשק ברמה העליונה של שירות Chooser Target. לעולם לא אמור להיות נחוץ עבור אפליקציות רגילות."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"איגוד לשירות ספק תנאי"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות ספק תנאי. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"איגוד לשירות ניתוב מדיה"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"מאפשרת לבעלים לאגוד לממשק ברמה העליונה של שירות ניתוב מדיה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"‏איגוד לשירות Dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"‏מאפשרת לבעלים לבצע איגוד לממשק הרמה העליונה של שירות Dream. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילות."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"איגוד לשירות העברת הודעות של ספק"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות העברת הודעות של ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"‏קביעת האורך הנדרש והתווים המותרים בסיסמאות ובקודי PIN של מסך הנעילה."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ניהול מעקב אחר מספר הסיסמאות השגויות שמוקלדות בעת ביטול נעילת המסך, וביצוע נעילה של הטאבלט, או מחיקה של כל נתוני הטאבלט, אם מוקלדות יותר מדי סיסמאות שגויות."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"מעקב אחר מספר הסיסמאות השגויות שהוזנו בעת נעילת המסך, ונעילת הטלוויזיה או מחיקה של כל נתוני הטלוויזיה אם הוזנו סיסמאות שגויות רבות מדי."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ניהול מעקב אחר מספר הסיסמאות השגויות שהוקלדו בעת ביטול נעילה המסך, וביצוע נעילה של הטלפון או מחיקה של כל נתוני הטלפון אם הוקלדו יותר מדי סיסמאות שגויות."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"שנה את הסיסמה לביטול נעילת המסך"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"שנה את הסיסמה לביטול נעילת המסך."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"מעקב אחר מספר הסיסמאות השגויות שהוזנו בעת ביטול נעילת המסך, כמו גם נעילת הטאבלט או מחיקה של כל נתוני המשתמש הזה אם הוזנו יותר מדי סיסמאות שגויות."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"מעקב אחר מספר הסיסמאות השגויות שהוזנו בעת ביטול נעילת המסך, כמו גם נעילת הטלוויזיה או מחיקה של כל נתוני המשתמש הזה אם הוזנו יותר מדי סיסמאות שגויות."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"מעקב אחר מספר הסיסמאות השגויות שהוזנו בעת ביטול נעילת המסך, כמו גם נעילת הטלפון או מחיקה של כל נתוני המשתמש הזה אם הוזנו יותר מדי סיסמאות שגויות."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"שינוי נעילת המסך"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"שינוי של נעילת המסך."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"נעל את המסך"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"שלוט באופן ובתזמון של נעילת המסך"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"מחק את כל הנתונים"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"מחק את נתוני הטאבלט ללא אזהרה על ידי ביצוע איפוס נתוני יצרן."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"מחיקה של נתוני הטלוויזיה ללא אזהרה, על ידי ביצוע איפוס לנתוני היצרן."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"מחק את נתוני הטלפון ללא אזהרה על ידי ביצוע איפוס נתוני יצרן."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"מחיקת נתוני משתמש"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"מחיקה ללא אזהרה של נתוני המשתמש הזה בטאבלט הזה."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"מחיקה ללא אזהרה של נתוני המשתמש הזה בטלוויזיה הזו."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"מחיקה ללא אזהרה של נתוני המשתמש הזה בטלפון הזה."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"‏הגדר את שרת ה-Proxy הכללי של המכשיר"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"‏הגדר שימוש בשרת ה-Proxy הגלובלי של המכשיר כאשר המדיניות מופעלת. רק מנהל המכשיר הראשון מגדיר את שרת ה-Proxy הגלובלי הפעיל."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תאריך תפוגה לסיסמה של נעילת המסך"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"שלוט בתדירות שבה יש לשנות את הסיסמה של נעילת המסך."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"‏הגדרה של שרת ה-proxy הגלובלי שבו ייעשה שימוש כשהמדיניות פועלת. רק הבעלים של המכשיר יכול להגדיר את שרת ה-proxy הגלובלי."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"הגדרת תפוגה לסיסמת מסך הנעילה"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"‏שינוי התדירות לדרישת השינוי של הסיסמה, ה-PIN או קו ביטול הנעילה של מסך הנעילה."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"הגדר הצפנת אחסון"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"דרוש שנתוני אפליקציות מאוחסנות יהיו מוצפנים."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"השבת מצלמות"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"מנע שימוש בכל המצלמות שבמכשיר."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"‏השבת תכונות ב-Keyguard"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"‏מנע שימוש בתכונות מסוימות ב-Keyguard."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"השבתת תכונות של נעילת המסך"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"מניעת השימוש בתכונות מסוימות של מסך הנעילה."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"בית"</item>
     <item msgid="869923650527136615">"נייד"</item>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> רוצה להפעיל את התכונה \'חקור על ידי מגע\'. כאשר התכונה \'חקור על ידי מגע\' מופעלת, אתה יכול לשמוע או לראות תיאורים של הפריטים שעליהם אצבעך מונחת או לקיים אינטראקציה עם הטלפון באמצעות תנועות אצבע."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"לפני חודש אחד"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"לפני חודש אחד"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"לפני שנייה אחת"</item>
-    <item quantity="other" msgid="3903706804349556379">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"לפני דקה אחת"</item>
-    <item quantity="other" msgid="2176942008915455116">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"לפני שעה"</item>
-    <item quantity="other" msgid="2467273239587587569">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> הימים האחרונים"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="two"><xliff:g id="COUNT_1">%d</xliff:g> הימים האחרונים</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> הימים האחרונים</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> הימים האחרונים</item>
+      <item quantity="one">יום <xliff:g id="COUNT_0">%d</xliff:g> אחרון</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"בחודש שעבר"</string>
     <string name="older" msgid="5211975022815554840">"ישן יותר"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"אתמול"</item>
-    <item quantity="other" msgid="2479586466153314633">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"בעוד שנייה אחת"</item>
-    <item quantity="other" msgid="1241926116443974687">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"בעוד דקה אחת"</item>
-    <item quantity="other" msgid="3330713936399448749">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"תוך שעה אחת"</item>
-    <item quantity="other" msgid="547290677353727389">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"מחר"</item>
-    <item quantity="other" msgid="5109449375100953247">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"לפני שנייה אחת"</item>
-    <item quantity="other" msgid="3699169366650930415">"לפני <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"לפני דקה"</item>
-    <item quantity="other" msgid="851164968597150710">"לפני <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"לפני שעה"</item>
-    <item quantity="other" msgid="6889970745748538901">"לפני <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"אתמול"</item>
-    <item quantity="other" msgid="3453342639616481191">"לפני <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"תוך שנייה אחת"</item>
-    <item quantity="other" msgid="5495880108825805108">"תוך <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"תוך דקה אחת"</item>
-    <item quantity="other" msgid="4216113292706568726">"תוך <xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"תוך שעה אחת"</item>
-    <item quantity="other" msgid="3705373766798013406">"תוך <xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"מחר"</item>
-    <item quantity="other" msgid="2973062968038355991">"בעוד <xliff:g id="COUNT">%d</xliff:g> ימים"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"בתאריך <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"בשנת <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"שבועות"</string>
     <string name="year" msgid="4001118221013892076">"שנה"</string>
     <string name="years" msgid="6881577717993213522">"שנים"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"שנייה אחת"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"דקה אחת"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> דקות"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"שעה אחת"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> שעות"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="one">שנייה אחת</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> דקות</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> דקות</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> דקות</item>
+      <item quantity="one">דקה אחת</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> שעות</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> שעות</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> שעות</item>
+      <item quantity="one">שעה אחת</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"בעיה בווידאו"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"סרטון זה אינו חוקי להעברה כמדיה זורמת למכשיר זה."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"לא ניתן להפעיל סרטון זה."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏הפעלת Android מתחילה…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"מתבצעת אופטימיזציה של האחסון."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"מבצע אופטימיזציה של אפליקציה <xliff:g id="NUMBER_0">%1$d</xliff:g> מתוך <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"מכין את <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"מפעיל אפליקציות."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"מסיים אתחול."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> פועל"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"אל תפעיל את האפליקציה החדש."</string>
     <string name="new_app_action" msgid="5472756926945440706">"הפעל את <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"עצור את האפליקציה הישן ללא שמירה."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"בחירת פעולה לביצוע עם טקסט"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"עוצמת קול של צלצול"</string>
     <string name="volume_music" msgid="5421651157138628171">"עוצמת קול של מדיה"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ללא"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"רינגטונים"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"רינגטון לא ידוע"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"‏רשת Wi-Fi זמינה"</item>
-    <item quantity="other" msgid="4192424489168397386">"‏רשתות Wi-Fi זמינות"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"‏רשת Wi-Fi פתוחה זמינה"</item>
-    <item quantity="other" msgid="7915895323644292768">"‏רשתות Wi-Fi פתוחות זמינות"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="two">‏יש רשתות Wi-Fi זמינות</item>
+      <item quantity="many">‏יש רשתות Wi-Fi זמינות</item>
+      <item quantity="other">‏יש רשתות Wi-Fi זמינות</item>
+      <item quantity="one">‏יש רשת Wi-Fi זמינה</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="two">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
+      <item quantity="many">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
+      <item quantity="other">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
+      <item quantity="one">‏יש רשת Wi-Fi פתוחה וזמינה</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"‏כניסה לרשת Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"היכנס לרשת"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏האפליקציה %1$s מנסה להתחבר אל רשת ה-Wi-Fi ‏%2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"אפליקציה"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ישיר"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏הפעל Wi-Fi ישיר. פעולה זו תכבה את הנקודה לשיתוף אינטרנט ב-Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏לא ניתן להפעיל Wi-Fi ישיר"</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"אישור"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"מחובר כמכשיר מדיה"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"מחובר כמצלמה"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"‏מחובר כהתקן MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"מחובר כמתקין"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏מחובר לאביזר USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"‏גע לקבלת אפשרויות USB נוספות."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"דלג"</string>
     <string name="no_matches" msgid="8129421908915840737">"אין התאמות"</string>
     <string name="find_on_page" msgid="1946799233822820384">"חפש בדף"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"התאמה אחת"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> מתוך <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="two"><xliff:g id="INDEX">%d</xliff:g> מתוך <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> מתוך <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> מתוך <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">התאמה אחת</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"סיום"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"‏מבטל טעינה של אחסון USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"‏מבטל טעינה של כרטיס SD..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"‏צור מספר PIN לשינוי הגבלות"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"‏מספרי ה-PIN לא תואמים. נסה שוב."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"‏מספר ה-PIN קצר מדי. חייב להיות באורך 4 ספרות לפחות."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"נסה שוב בעוד שנייה"</item>
-    <item quantity="other" msgid="4730868920742952817">"נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="two">נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="many">נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="other">נסה שוב בעוד <xliff:g id="COUNT">%d</xliff:g> שניות</item>
+      <item quantity="one">נסה שוב בעוד שנייה אחת</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"נסה שוב מאוחר יותר"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"החלק מטה מהחלק העליון כדי לצאת ממסך מלא."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"צפייה במסך מלא"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"כדי לצאת, החלק מלמעלה למטה."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"הבנתי"</string>
     <string name="done_label" msgid="2093726099505892398">"בוצע"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"מחוון שעות מעגלי"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"מחוון דקות מעגלי"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"כדי לבטל את הקפאת המסך הזה, גע בו-זמנית נגיעה ממושכת ב\'הקודם\' ו\'סקירה\'."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"כדי לבטל את הקפאת המסך הזה, גע נגיעה ממושכת ב\'סקירה\'."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"המסך מוצמד. הארגון אוסר לבטל את הצמדתו."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"המסך מוצמד"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"הצמדת המסך בוטלה"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"בקש קוד אימות לפני ביטול הצמדה"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם תפתח אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"עד לסיום ההשבתה בשעה <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"עד לסיום זמן ההשבתה"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"למשך דקה אחת (עד <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"‏למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"למשך שעה אחת (עד <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"‏למשך %1$d שעות (עד <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item>
-    <item quantity="other" msgid="6924190729213550991">"‏למשך %d דקות"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"למשך שעה אחת"</item>
-    <item quantity="other" msgid="5408537517529822157">"‏למשך %d שעות"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="two">‏למשך %d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">‏למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">למשך דקה אחת (עד <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="two">‏למשך %d שעות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">‏למשך %d שעות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">‏למשך %d שעות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">למשך שעה אחת (עד <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="two">‏למשך %d דקות</item>
+      <item quantity="many">‏למשך %d דקות</item>
+      <item quantity="other">‏למשך %d דקות</item>
+      <item quantity="one">למשך דקה אחת</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="two">‏למשך %d שעות</item>
+      <item quantity="many">‏למשך %d שעות</item>
+      <item quantity="other">‏למשך %d שעות</item>
+      <item quantity="one">למשך שעה אחת</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"ללא הגבלה"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"כווץ"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"עד ההתראה הבאה ב-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"עד ההתראה הבאה"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏בקשת SS שונתה לבקשת DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏בקשת SS שונתה לבקשת USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏בקשת SS שונתה לבקשת SS חדשה."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏יציאת USB בציוד היקפי"</string>
 </resources>
diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml
index 21aa0e6..a3c1f64 100755
--- a/core/res/res/values-ja/donottranslate-cldr.xml
+++ b/core/res/res/values-ja/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y年%-m月%-e日</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%Y/%m/%d %-k:%M:%S</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 640e8b2..c4849b2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;新規&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(電話番号なし)"</string>
     <string name="unknownName" msgid="6867811765370350269">"不明"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ボイスメール"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIMカードはPUKでロックされています。ロックを解除するにはPUKコードを入力してください。"</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIMカードのロック解除のためPUK2を入力します。"</string>
     <string name="enablePin" msgid="209412020907207950">"SIM/RUIMロックを有効にしてください。"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。この回数を超えるとSIMがロックされます。"</item>
-    <item quantity="other" msgid="7530597808358774740">"入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。この回数を超えるとSIMがロックされます。"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">入力できるのはあと<xliff:g id="NUMBER_1">%d</xliff:g>回です。この回数を超えるとSIMがロックされます。</item>
+      <item quantity="one">入力できるのはあと<xliff:g id="NUMBER_0">%d</xliff:g>回です。この回数を超えるとSIMがロックされます。</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"着信時の発信者番号"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ルートプロバイダサービスへのバインド"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"登録済みのルートプロバイダにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"テレビの入力へのバインド"</string>
@@ -527,7 +528,7 @@
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"あなたや友だちのソーシャル更新情報へのアクセスと同期をアプリに許可します。情報の共有は慎重に行ってください。これを許可すると、あなたと友だちがソーシャルネットワークで行ったやり取りを、機密性に関係なくアプリから読み取ることができるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ソーシャルストリームに書く"</string>
     <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"友だちのソーシャル更新情報の表示をアプリに許可します。情報の共有は慎重に行ってください。これによりアプリは、友だちから発信されたかのようなメッセージを作成できるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
-    <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報を読み取る"</string>
+    <string name="permlab_readCalendar" msgid="5972727560257612398">"カレンダーの予定と機密情報の読み取り"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"タブレットに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"テレビに保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"携帯端末に保存されているカレンダーの予定(友だちや同僚の予定も含めすべて)を読み取ることをアプリに許可します。これにより、アプリがカレンダーのデータを機密性に関係なく共有または保存できるようになる可能性があります。"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"NFCタグ、カード、リーダーとの通信をアプリに許可します。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"画面ロックの無効化"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"キーロックとキーロックに関連付けられたパスワードのセキュリティを無効にすることをアプリに許可します。たとえば、かかってきた電話を受ける際にキーロックを無効にし、通話が終了したらキーロックを再度有効にする場合などに使用します。"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"指紋ハードウェアの管理"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"使用する指紋テンプレートの追加や削除を行う方法の呼び出しをアプリに許可します。"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"指紋ハードウェアの使用"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"指紋ハードウェアを認証に使用することをアプリに許可します"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"同期のON/OFFの切り替え"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"選択した対象サービスへのバインド"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"選択した対象サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"コンディションプロバイダサービスへのバインド"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"コンディションプロバイダサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"メディアルートサービスへのバインド"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"メディアルートサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ドリームサービスにバインド"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ドリームサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"携帯通信会社が提供する設定アプリの呼び出し"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"携帯通信会社のSMSサービスへのバインド"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"携帯通信会社のSMSサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合はタブレットをロックするかタブレットのデータをすべて消去します。"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"画面のロック解除に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合はテレビをロックするかテレビのデータをすべて消去します。"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合は携帯端末をロックするか携帯端末のデータをすべて消去します。"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"画面ロック解除パスワードの変更"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"画面ロック解除パスワードを変更します。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"画面のロック解除の際に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合はタブレットをロックするかこのユーザーのデータをすべて消去します。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"画面のロック解除の際に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合はテレビをロックするかこのユーザーのデータをすべて消去します。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"画面のロック解除の際に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合はスマートフォンをロックするかこのユーザーのデータをすべて消去します。"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"画面ロックの変更"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"画面ロックを変更します。"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"画面のロック"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"画面をロックする方法とタイミングを制御します。"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"すべてのデータを消去"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"警告せずにデータの初期化を実行してタブレット内のデータを消去します。"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"警告せずにデータの初期化を実行してテレビ内のデータを消去します。"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"警告せずにデータの初期化を実行して端末内のデータを消去します。"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ユーザーデータの消去"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"このタブレットのこのユーザーのデータを警告なく消去します。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"このテレビのこのユーザーのデータを警告なく消去します。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"このスマートフォンのこのユーザーのデータを警告なく消去します。"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"端末のグローバルプロキシを設定"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"解除パスワードの有効期限の設定"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ロック解除パスワードの変更が必要になる頻度を指定します。"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。グローバルプロキシを設定できるのは端末の所有者だけです。"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"画面ロックのパスワード有効期限の設定"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"画面ロックのパスワード、PIN、パターンの変更が必要になる頻度を変更します。"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ストレージ暗号化の設定"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"保存したアプリデータが暗号化されるようにします。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"カメラを無効にする"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"すべての端末カメラを使用できないようにします。"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"キーガードの機能を無効にする"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"キーガードの一部の機能の使用を禁止します。"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"画面ロック機能の無効化"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"画面ロックの一部の機能の使用を禁止します。"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"自宅"</item>
     <item msgid="869923650527136615">"携帯"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>がタッチガイドをONにしようとしています。タッチガイドをONにすると、指の位置にあるアイテムの説明を読み上げたり表示したりできます。また、携帯端末を通常とは違うジェスチャーで操作できます。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1か月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1か月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1分前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1時間前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"過去<xliff:g id="COUNT">%d</xliff:g>日間"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">過去<xliff:g id="COUNT_1">%d</xliff:g>日間</item>
+      <item quantity="one">過去<xliff:g id="COUNT_0">%d</xliff:g>日間</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"先月"</string>
     <string name="older" msgid="5211975022815554840">"もっと前"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨日"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1秒後"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1分後"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1時間後"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明日"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1分前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1時間前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨日"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1秒後"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1分後"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1時間後"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明日"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>年"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"週間"</string>
     <string name="year" msgid="4001118221013892076">"年"</string>
     <string name="years" msgid="6881577717993213522">"年"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1秒"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g>秒"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1分"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g>分"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1時間"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g>時間"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>秒</item>
+      <item quantity="one">1秒</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>分</item>
+      <item quantity="one">1分</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>時間</item>
+      <item quantity="one">1時間</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"動画の問題"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"この動画はこの端末にストリーミングできません。"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"この動画を再生できません。"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Androidの起動中…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ストレージを最適化しています。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>個中<xliff:g id="NUMBER_0">%1$d</xliff:g>個のアプリを最適化しています。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>をペア設定しています。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"アプリを起動しています。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ブートを終了しています。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"新しいアプリを起動しません。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>を起動"</string>
     <string name="new_app_description" msgid="1932143598371537340">"古いアプリを保存せずに停止します。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"アプリケーションを選択"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"着信音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"メディアの音量"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"なし"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"着信音"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"不明な着信音"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fiを利用できます"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fiを利用できます"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Wi-Fiオープンネットワークが利用できます"</item>
-    <item quantity="other" msgid="7915895323644292768">"Wi-Fiオープンネットワークが利用できます"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">複数のWi-Fiネットワークが利用できます</item>
+      <item quantity="one">Wi-Fiネットワークが利用できます</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">複数のWi-Fiオープンネットワークが利用できます</item>
+      <item quantity="one">Wi-Fiオープンネットワークが利用できます</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fiネットワークにログイン"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ネットワークにログイン"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"アプリ%1$sがWi-Fiネットワーク%2$sへの接続を希望しています"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"アプリ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directを開始できませんでした。"</string>
@@ -1411,9 +1376,10 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"メディアデバイスとして接続"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"カメラとして接続"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDIデバイスとして接続"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"インストーラとして接続"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USBアクセサリを接続しました"</string>
-    <string name="usb_notification_message" msgid="2290859399983720271">"他のUSBオプションをタップしてください。"</string>
+    <string name="usb_notification_message" msgid="2290859399983720271">"USB接続方法を変更するにはタップしてください。"</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"USBストレージをフォーマットしますか?"</string>
     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"SDカードをフォーマットしますか?"</string>
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"USBストレージに保存されているファイルはすべて消去されます。この操作は元に戻せません。"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"スキップ"</string>
     <string name="no_matches" msgid="8129421908915840737">"該当なし"</string>
     <string name="find_on_page" msgid="1946799233822820384">"ページ内を検索"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1件一致"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>件"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>件(<xliff:g id="TOTAL">%d</xliff:g>件中)</item>
+      <item quantity="one">1件一致</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"完了"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USBストレージのマウント解除中..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SDカードのマウント解除中..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"制限を変更するためのPINを作成してください"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINが一致しません。もう一度お試しください。"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PINが短すぎます。4桁以上にしてください。"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1秒後に再試行"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g>秒後に再試行"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>秒後にもう一度お試しください</item>
+      <item quantity="one">1秒後にもう一度お試しください</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"しばらくしてから再試行"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"全画面表示を終了するには、上から下にスワイプ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"全画面表示"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"終了するには、上部から下にスワイプします。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"完了"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"円形スライダー(時)"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"円形スライダー(分)"</string>
@@ -1835,33 +1803,34 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"この画面の固定を解除するには[戻る]と[最近]を同時に押し続けます。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"この画面の固定を解除するには[最近]を押し続けます。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"画面が固定されています。会社/組織により解除は許可されていません。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"画面固定を解除しました"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"オフライン再生を解除する前にパスワードの入力を求める"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>にダウンロードが終わるまで"</string>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>にダウンタイムが終わるまで"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ダウンタイム終了まで"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1分間(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>まで)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d分間(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>まで)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1時間(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>まで)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d時間(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>まで)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1分"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d分"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1時間"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d時間"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d分間(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>まで)</item>
+      <item quantity="one">1分間(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>まで)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d時間(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>まで)</item>
+      <item quantity="one">1時間(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>まで)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d分</item>
+      <item quantity="one">1分</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d時間</item>
+      <item quantity="one">1時間</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"制限なし"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"折りたたむ"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"次のアラーム(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)まで"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"次のアラームまで"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SSリクエストはDIALリクエストに変更されました。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SSリクエストはUSSDリクエストに変更されました。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SSリクエストは新しいSSリクエストに変更されました。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB周辺機器ポート"</string>
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index fe65d3d..f0b3f31 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> წმ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> წმ"</string>
     <string name="untitled" msgid="4638956954852782576">"უსათაურო"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ტელეფონის ნომრის გარეშე)"</string>
     <string name="unknownName" msgid="6867811765370350269">"უცნობი"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ხმოვანი ფოსტა"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"თქვენი SIM ბარათი დაბლოკილია PUK კოდით. განბლოკვისთვის შეიყვანეთ PUK კოდი."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM ბარათის განსაბლოკად აკრიფეთ PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"წარუმატებელი მცდელობა. ჩართეთ SIM/RUIM ჩაკეტვა."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ SIM დაიბლოკებოდეს."</item>
-    <item quantity="other" msgid="7530597808358774740">"თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ SIM დაიბლოკებოდეს."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM დაიბლოკება.</item>
+      <item quantity="one">თქვენ დაგრჩათ <xliff:g id="NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM დაიბლოკება.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"შემომავალი ზარის აბონენტის ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"პარამეტრები"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"მარშრუტის სერვისის პროვაიდერთან შეკავშირება"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"საშუალებას აძლევს მფლობელს შეკავშირდეს მარშრუტების ნებისმიერ პროვაიდერთან. ჩვეულებრივ აპებს უმეტეს შემთხვევაში არ დაჭირდება."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"აპს შეეძლება მოწყობილობის ადმინისტრატორისთვის intent ობიექტების გაგზავნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV შეყვანასთან მიბმა"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"აპს შეეძლება ახლო მოქმედების რადიოკავშირის (NFC) მეშვეობით ტეგების, ბარათებისა და წამკითხველების შემცველი მონაცემების მიმოცვლა."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"თქვენი ეკრანის ბლოკის გათიშვა"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"შეეძლება კლავიატურის დაბლოკვისა და პაროლით უზრუნველყოფილი ნებისმიერი უსაფრთხოების ფუნქციის დეაქტივაცია. მაგალითად, ტელეფონი შემომავალი ზარის დროს აუქმებს კლავიატურის დაბლოკვას და კვლავ ააქტიურებს მას, როგორც კი ზარი დასრულდება."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"თითის ანაბეჭდის აპარატის მართვა"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"საშუალებას აძლევს აპლიკაციას დაამატოს ან ამოშალოს გამოსაყენებელი თითის ანაბეჭდის ნიმუშები,"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"თითის ანაბეჭდის აპარატის გამოყენება"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"საშუალებას აძლევს აპლიკაციას გამოიყენოს ავტენთიფიკაციისათვის თითის ანაბეჭდის აპარატი"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"სინქრონიზაციის პარამეტრების წაკითხვა"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"აპს შეეძლება, წაიკითხოს ანგარიშის სინქრონიზაციის პარამეტრები. მაგალითად, მას შეეძლება განსაზღვროს, არის თუ არა People აპი სინქრონიზებული ანგარიშთან."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"სინქრონიზაციის ჩართვა და გამორთვა"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"აკავშირებს შერჩეულ სამიზნე მომსახურებასთან"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"საშუალებას აძლევს მფლობელს, დააკავშიროს ზედა დონის ინტერფეისი შერჩეულ სამიზნე მომსახურებასთან. არასდროს უნდა იყოს საჭირო ნორმალურ აპლიკაციებში."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"მდგომარეობის პროვაიდერის სერვისებთან შეკავშირება"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"მფლობელს შეეძლება შეკავშირდეს მდგომარეობის პროვაიდერის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"მედიის მარშრუტის სერვისთან შეკავშირება"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"მფლობელს შეეძლება შეკავშირდეს მედიის მარშრუტიზაციის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"dream სერვისთან მიბმა"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"მფლობელს შეეძლება მიებას dream სერვისის ზედა დონის ინტერფეისი. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ოპერატორის მიერ მოწოდებული კოფიგურაციის აპის გამოხმობა"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"აკავშირებს შეტყობინების გაცვლის მომსახურებას"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"საშუალებას აძლევს მფლობელს შექმნას შეტყობინების გაცვლის მომსახურების უმახლესი დონის ინტერფეისი. არასდროს იქნება საჭირო ნორმალური აპლიკაციებისათვის."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"აკონტროლეთ ეკრანის ბლოკირების პაროლებისა და PIN-ების სიმბოლოების სიგრძე."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ეკრანის განბლოკვისთვის არასწორად აკრეფილი პაროლების რაოდენობის მონიტორინგი. ტაბლეტის დაბლოკვა ან მასზე არსებული ყველა მონაცემის წაშლა ძალიან ბევრჯერ არასწორი პაროლის შეყვანის შემთხვევაში."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ეკრანის განბლოკვის დროს, გააკონტროლეთ არასწორად შეყვანილი პაროლების რაოდენობა და ჩაკეტეთ ტელევიზორი ან წაშალეთ ტელვიზორის ყველა მონაცემები, იმ შემთხვევაში, თუ პაროლის მრავალჯერად, არასწორად შეყვანას ექნება ადგილი."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ეკრანის განბლოკვისთვის არასწორად აკრეფილი პაროლების რაოდენობის მონიტორინგი. ტელეფონის დაბლოკვა ან მასზე არსებული ყველა მონაცემის წაშლა ძალიან ბევრჯერ არასწორი პაროლის შეყვანის შემთხვევაში."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"ეკრანის განბლოკვის პაროლის შეცვლა"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"შეცვალეთ ეკრანის განბლოკვის პაროლი."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ეკრანის განბლოკვისას არასწორი პაროლების შეყვანილი რაოდენობის მონიტორინგი და ტაბლეტის დაბლოკვა ან მრავლალჯერ არასწორი პაროლის შეყვანის შემთხვევაში ამ მომხმარებლის მთელი ინფორმაციის წაშლა."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ეკრანის განბლოკვისას არასწორი პაროლების შეყვანილი რაოდენობის მონიტორინგი და ტელევიზორის დაბლოკვა ან მრავლალჯერ არასწორი პაროლის შეყვანის შემთხვევაში ამ მომხმარებლის მთელი ინფორმაციის წაშლა."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ეკრანის განბლოკვისას არასწორი პაროლების შეყვანილი რაოდენობის მონიტორინგი და ტელეფონის დაბლოკვა ან მრავლალჯერ არასწორი პაროლის შეყვანის შემთხვევაში ამ მომხმარებლის მთელი ინფორმაციის წაშლა."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"ეკრანის დაბლოკვის შეცვლა"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"ეკრანის დაბლოკვის შეცვლა"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ეკრანის დაბლოკვა"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"გააკონტროლეთ, როგორ და როდის დაიბლოკოს ეკრანი."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ყველა მონაცემის წაშლა"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ტაბლეტის მონაცემების გაუფრთხილებლად წაშლა, ქარხნული მონაცემების აღდგენით"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ტელევიზორის მონაცემები წაშლილია, ქარხნულ მონაცემებზე დაბრუნების გაფრთხილების გარეშე."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ტელეფონის მონაცემების გაუფრთხილებლად წაშლა, ქარხნული მონაცემების აღდგენით"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"მომხმარებლის მონაცემების წაშლა"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ამ მომხმარებლის მონაცემების გაუფრთხილებელი წაშლა ამ ტაბლეტზე."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ამ მომხმარებლის მონაცემების გაუფრთხილებელი წაშლა ამ ტელევიზორში."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ამ მომხმარებლის მონაცემების გაუფრთხილებელი წაშლა ამ ტელეფონზე."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"მოწყობილობის გლობალური პროქსის დაყენება"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"დააყენეთ მოწყობილობა გლობალურ პროქსის სერვერის გამოსაყენებლად, როდესაც დებულება გააქტიურებულია. მხოლოდ მოწყობილობის პირველი ადმინი აყენებს ეფექტურ გლობალურ პროქსი სერვერს."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ეკრანის პაროლის ვადის დაყენება"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"გააკონტროლეთ, თუ რამდენად ხშირად უნდა შეიცვალოს ეკრანის დაბლოკვის პაროლი."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ჩართული პოლიტიკის დროს მოწყობილობის გლობალური პროქსის დაყენება. მხოლოდ მოწყობილობის მფლობელს შეუძლია გლობალური პროქსის დაყენება."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"მითითებული ეკრანის დაბლოკვის პაროლის ვადა"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"შეცვალეთ ეკრანის ბლოკირების პაროლების, PIN-ებისა და მონახაზების შეცვლის სიხშირე."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"მეხსიერების დაშიფრვის დაყენება"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"საჭიროა შენახული აპის მონაცემების დაშიფრვა."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"კამერების გათიშვა"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"მოწყობილობის კამერების გამოყენების აღკვეთა."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"დაბლოკვის ფუნქციების გათიშვა"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"დაბლოკვისას ზოგიერთი ფუნქციის გამოყენების თავიდან აცილება."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"ეკრანის დაბლოკვის მახასიათებლების გამორთვა"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"დაიცავით ეკრანის ბლოკირება გარკვეული მახასიათებლებისაგან."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"სახლი"</item>
     <item msgid="869923650527136615">"მობილური"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>-ს სურს „შეხებით შესწავლის“ რეჟიმის ჩრთვა. ეს ტელეფონის ჟესტებით მართვისა და იმ ელემენტების აღწერის მოსმენის შესაძლებლობას მოგცემთ, რომელსაც შეეხებით."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"ერთი თვის წინ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"უფრო ადრე, ვიდრე ერთი თვის წინ"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 წამის წინ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 წუთის უკან"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 საათის წინ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ბოლო <xliff:g id="COUNT">%d</xliff:g> დღე"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> ბოლო <xliff:g id="COUNT_1">%d</xliff:g> დღეს</item>
+      <item quantity="one"> ბოლო <xliff:g id="COUNT_0">%d</xliff:g> დღეს</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"გასული თვე"</string>
     <string name="older" msgid="5211975022815554840">"უფრო ძველი"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"გუშინ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 წამში"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> წამში"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 წუთში"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 საათში"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ხვალ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 წმ. წინ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 წუთის წინ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> წუთის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 საათის წინ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> საათის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"გუშინ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> დღის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 წამში"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> წამის წინ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 წუთში"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> წუთში"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 საათში"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ხვალ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> დღეში"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"თარიღი: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ზე"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> წელს"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"კვირა"</string>
     <string name="year" msgid="4001118221013892076">"წელი"</string>
     <string name="years" msgid="6881577717993213522">"წელი"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 წამი"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> წამი"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 წუთი"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> წუთი"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 საათი"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> საათში"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> წამი</item>
+      <item quantity="one">1 წამი</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> წუთი</item>
+      <item quantity="one">1 წუთი</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> საათი</item>
+      <item quantity="one">1 საათი</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"პრობლემები ვიდეოსთან"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ეს ვიდეო არ გამოდგება ამ მოწყობილობაზე სტრიმინგისთვის."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ვიდეოს დაკვრა არ არის შესაძლებელი."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android იწყება…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"მეხსიერების ოპტიმიზირება."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"მიმდინარეობს აპლიკაციების ოპტიმიზაცია. დასრულებულია <xliff:g id="NUMBER_0">%1$d</xliff:g>, სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"ემზადება <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"აპების ჩართვა"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ჩატვირთვის დასასრული."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"არ ჩართოთ ახალი აპი."</string>
     <string name="new_app_action" msgid="5472756926945440706">"დასაწყისი <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"შეაჩერე ძველი აპი ცვლილებების შენახვის გარეშე."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"შეარჩიეთ ქმედება ტექსტისთვის."</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"მრეკავის ხმა"</string>
     <string name="volume_music" msgid="5421651157138628171">"მედიის ხმა"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"არც ერთი"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ზარები"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"უცნობი ზარი"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi ქსელი ხელმისაწვდომია"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi ქსელები ხელმისაწვდომია."</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"ხელმისაწვდომი Wi-Fi ქსელების გახსნა"</item>
-    <item quantity="other" msgid="7915895323644292768">"ხელმისაწვდომი Wi-Fi ქსელების გახსნა"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">ხელმისაწვდომია Wi-Fi ქსელები</item>
+      <item quantity="one">ხელმისაწვდომია Wi-Fi ქსელი</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">ხელმისაწვდომია ღია Wi-Fi ქსელები</item>
+      <item quantity="one">ხელმისაწვდომია ღია Wi-Fi ქსელი</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi ქსელთან დაკავშირება"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ქსელში შესვლა"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" აქვს ცუდი ინტერნეტ კავშირი."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"განაცხადს %1$s სურს დაუკავშირდეს Wifi ქსელს %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"აპლიკაცია"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ჩართეთ Wi-Fi Direct. ეს გამოიწვევს Wi-Fi კლიენტისა/უსადენო ქსელის გამორთვას."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ვერ მოხერხდა Wi-Fi Direct-ის გაშვება."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"დაკავშირებულია როგორც მედია მოწყობილობა"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"დაკავშირებულია როგორც კამერა"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"დაკავშირებული როგორც MIDI მოწყობილობა"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"დაკავშირებულია როგორც დამყენებელი"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"დაკავშირებულია USB აქსესუართან"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"შეეხეთ USB-ის სხვა პარამეტრების სანახავად."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"გამოტოვება"</string>
     <string name="no_matches" msgid="8129421908915840737">"შესატყვისები არ არის."</string>
     <string name="find_on_page" msgid="1946799233822820384">"გვერდზე ძებნა"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 დამთხვევა"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> <xliff:g id="TOTAL">%d</xliff:g>-დან"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>, სულ: <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 დამთხვევა</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"დასრულდა"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB მეხსიერების გათიშვა…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"მიმდინარეობს SD ბარათის მოხსნა…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"შექმენით PIN შეზღუდვების ცვლილებებისათვის"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ები არ ემთხვევა. სცადეთ ხელახლა."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ძალიან მოკლეა. უნდა შედგებოდეს სულ ცოტა 4 ციფრისგან."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"კიდევ ერთხელ სცადეთ 1 წამში"</item>
-    <item quantity="other" msgid="4730868920742952817">"კიდევ ერთხელ სცადეთ <xliff:g id="COUNT">%d</xliff:g> წამში"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">ხელახლა სცადეთ <xliff:g id="COUNT">%d</xliff:g> წამში</item>
+      <item quantity="one">ხელახლა სცადეთ 1 წამში</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"სცადეთ მოგვიანებით"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ჩამოასრიალეთ ზევიდან სრული ეკრანის დასახურად."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"სრულ ეკრანზე ნახვა"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"გამოსვლისათვის, გაასრიალეთ ზემოდან ქვემოთ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"გასაგებია"</string>
     <string name="done_label" msgid="2093726099505892398">"დასრულდა"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"საათების წრიული სლაიდერი"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"წუთების წრიული სლაიდერი"</string>
@@ -1833,9 +1801,10 @@
     <string name="item_is_selected" msgid="949687401682476608">"არჩეულია <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> წაიშალა"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „გადახედვა“."</string>
-    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ამ ეკრანისთვის მიმაგრების გასაუქმებლად შეეხეთ და არ აუშვათ ღილაკებს „გადახედვა“."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ეკრანი დაფიქსირებული. ფიქსაციის მოხსნა თქვენო ორგანიზაციის მიერ ნებადართული არ არის."</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „მიმოხილვა“."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ამ ეკრანისთვის მიმაგრების გასაუქმებლად, შეეხეთ და არ აუშვათ „მიმოხილვა“-ს."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ეკრანს ფიქსაცია მოეხსნა"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ელემენტის მოქმედების ვადის გაუმჯობესებისათვის, ელემენტის დამზოგი ამცირებს თქვენი მოწყობილობის შესრულებას და ზღუდავს ვიბრაციას, ადგილმდებარეობის მომსახურებებს და ძირითად ფონურ მონაცემებს. ელ-ფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დაყრდნობილი აპლიკაციების განახლება არ მოხდება მათ გახსნეამდე. \n\n ელემენტის დამზოგველი ავტომატურად გამოირთვება, როდესაც თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"დანამ თქვენი კავშირგარეშე დრო დასრულდებოდეს <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ზე"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"სანამ ავარიული პაუზა დასრულდებოდეს"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ერთი წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>-მდე)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>-მდე)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ერთი საათის განმავლობაში (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>-მდე)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d საათის განმავლობაში (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>-მდე)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d წუთით"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ერთი საათით"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d საათით"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>-მდე)</item>
+      <item quantity="one">ერთი წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>-მდე)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d საათის განმავლობაში (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>-მდე)</item>
+      <item quantity="one">ერთი საათის განმავლობაში (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>-მდე)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d წუთის განმავლობაში</item>
+      <item quantity="one">ერთი წუთის განმავლობაში</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d საათის განმავლობაში</item>
+      <item quantity="one">ერთი საათის განმავლობაში</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"სამუდამოდ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"აკეცვა"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"შემდეგ მაღვიძარამდე <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ში"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"შემდეგ მაღვიძარამდე"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS მოთხოვნა შეიცვალა DIAL მოთხოვნით."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS მოთხოვნა შეიცვალა USSD მოთხოვნით."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS მოთხოვნა შეიცვალა ახალი SS მოთხოვნით."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"პერიფერიული USB პორტი"</string>
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index c57e2cb..3d52607 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Атаусыз&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Телефон нөмірі жоқ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Белгісіз"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Дауыс-хабар"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM картаңыз PUK арқылы бекітілген. Ашу үшін PUK кодын теріңіз."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM картасын ашу үшін PUK2 кодын теріңіз."</string>
     <string name="enablePin" msgid="209412020907207950">"Сәтсіз, SIM/RUIM бекітпесін қосыңыз."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"<xliff:g id="NUMBER">%d</xliff:g> әрекеттен кейін SIM бекітіледі."</item>
-    <item quantity="other" msgid="7530597808358774740">"<xliff:g id="NUMBER">%d</xliff:g> әрекеттен кейін SIM бекітіледі."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">SIM картасының бекітілуіне <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
+      <item quantity="one">SIM картасының бекітілуіне <xliff:g id="NUMBER_0">%d</xliff:g> әрекет қалды.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI (Халықаралық мобильдік құрылғы анықтағышы)"</string>
     <string name="meid" msgid="4841221237681254195">"MEID (ұялы құрылғы анықтағыш)"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Келген қоңырау шалушының жеке анықтағышы"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ұшақ режимі ҚОСУЛЫ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ұшақ режимі ӨШІРУЛІ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Параметрлер"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Пайдаланушыға қашықтан басқарылатын дисплейдің жоғары деңгейлі интерфейсіне жалғану мүмкіндігін ұсынады. Қалыпты қолданбаны ешқашан қажет етпеуі тиіс."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет қызметіне байланыстыру"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Пайдаланушыға виджет қызметінің жоғары деңгейлі интерфейсіне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"маршрут провайдері қызметіне байластыру"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Пайдаланушыға кез келген тіркелген маршрут провайдерлеріне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"құрал әкімшісімен қатынасу"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Иесіне ниеттерді құрылғы әкімшісіне жіберуге рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ТД кірісіне байластыру"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Қолданбаға NFC белгілерімен, карталармен және оқу құралдарымен байланысуға рұқсат береді."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"экран бекітпесін істен шығару"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Қолданбаларға кілтперне және басқа кілтсөзге қатысты қауіпсіздік шараларын өшіру мүмкіндігін береді. Мысалы, телефон кіріс қоңырауларын алғанда кілтпернені өшіреді және қоңырау аяқталғанда қайта қосады."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"саусақ ізі жабдығын басқару"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Қолданбаға пайдаланатын саусақ ізі үлгілерін қосу және жою әдістерін шақыруға мүмкіндік береді."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"саусақ ізі жабдығын пайдалану"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Қолданбаға аутентификацияалу үшін саусақ ізі жабдығын пайдалануға мүмкіндік береді"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"синх параметрлерін оқу"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Қолданбаға есептік жазба синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының есептік жазбамен сихрондалғаны анықталуы мүмкін."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синх қосу және өшіру арасында ауысу"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Қолданбаға хабарларды алу, тексеру және тазалау мүмкіндігін береді, басқа қолданбалар арқылы қойылған хабарларды қоса."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"хабар тыңдау қызметіне қосылу"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Пайдаланушыға хабар есту қызметінің жоғары деңгейлі интерфейсіне жалғану мүмкіндігін ұсынады. Қалыпты қолданбаны ешқашан қажет етпеуі тиіс."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"таңдау мақсатты қызметіне байластыру"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Иесіне таңдау мақсатты қызметінің жоғарғы деңгейлі интерфейсіне байластыруға мүмкіндік береді. Қалыпты қолданбаларға үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарттар провайдері қызметіне байластыру"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Пайдаланушыға шарт провайдері қызметінің жоғары деңгейлі интерфейсіне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медианы бағыттау қызметіне байластыру"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Иесіне медиа бағыттау қызметінің жоғарғы деңгейлі интерфейсіне байластыруға рұқсат етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"dream қызметіне байластыру"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Иесіне dream қызметінің жоғарғы деңгейлі интерфейсіне байластыруға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"жабдықтаушы ұсынатын жасақтамалық қолданбаны қосу"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"оператордың хабар алмасу қызметіне байластыру"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Иесіне оператордың хабар алмасу қызметінің жоғарғы деңгейлі интерфейсіне байластыруға рұқсат етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Кілтсөз ережелерін тағайындау"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Экранды ашу кілтсөздерінің ұзындығы мен қолдануға болатын таңбаларды басқару."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран бекітпесінің құпия сөздерінің және PIN кодтарының ұзындығын және оларда рұқсат етілген таңбаларды басқару."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Экранды ашу әркеттерін бақылау"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Экран бекітпесін ашқан кезде терілген қате құпия сөздердің санын бақылау және планшетті бекіту немесе тым көп қате құпия сөздер терілген болса, планшеттің бүкіл деректерін өшіру."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Экран бекітпесін ашу кезінде терілген дұрыс емес құпия сөздердің санын бақылау және тым көп дұрыс емес құпия сөз терілсе, ТД бекіту немесе бүкіл ТД деректерін өшіру."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Экран бекітпесін ашқан кезде терілген қате құпия сөздердің санын бақылау және телефонды бекіту немесе тым көп қате құпия сөздер терілген болса, телефонның бүкіл деректерін өшіру."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Экранды ашу кілтсөзін өзгерту"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Экранды ашу кілтсөзін өзгерту."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Экран бекітпесін ашқанда терілген қате құпия сөздердің санын бақылау және тым көп қате құпия сөздер терілсе, планшетті бекіту немесе осы пайдаланушының барлық деректерін өшіру."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Экран бекітпесін ашқанда терілген қате құпия сөздердің санын бақылау және тым көп қате құпия сөздер терілсе, теледидарды бекіту немесе осы пайдаланушының барлық деректерін өшіру."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Экран бекітпесін ашқанда терілген қате құпия сөздердің санын бақылау және тым көп қате құпия сөздер терілсе, телефонды бекіту немесе осы пайдаланушының барлық деректерін өшіру."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Экран бекітпесін өзгерту"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Экран бекітпесін өзгерту."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Экранды бекіту"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Экранның қашан және қалай бекітілетінін басқару."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Барлық деректерді өшіру"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Планшет дерекқорын ескертусіз, зауыттық дерекқорын қайта реттеу арқылы өшіру."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Зауыттық деректерді қалпына келтіруді орындау арқылы ТД деректерін ескертусіз өшіру."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Телефон дерекқорын ескертусіз, зауыттық дерекқорын қайта реттеу арқылы өшіру."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Пайдаланушы деректерін өшіру"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Осы пайдаланушының осы планшеттегі деректерін ескертусіз өшіру."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Осы пайдаланушының осы теледидардағы деректерін ескертусіз өшіру."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Осы пайдаланушының осы телефондағы деректерін ескертусіз өшіру."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Құрылғы жаһандық прокси қызметін орнату"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Саясат қосылғанда қолдану үшін құрылғы жаһандық прокси қызметін орнату. Бірінші құрылғы әкімшісі ғана қолданыстағы жаһандық проксиді орнатады."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Экранды бекіту кілт сөзінің жарамдылық мерзімін тағайындау"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Экранды бекіту кілтсөзін өзгерту жиілігін басқару."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Саясат қосулы болғанда пайдаланылатын құрылғының ғаламдық прокси-серверін орнатыңыз. Ғаламдық прокси-серверді тек құрылғы иесі орната алады."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Экран бекітпесі құпия сөзінің мерзімін орнату"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Экран бекітпесінің құпия сөзін, PIN кодын немесе өрнегін өзгерту жиілігін өзгерту."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Жад қорының шрифтін тағайындау"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Сақталған қолданба деректерінің кодталуын қажет етеді."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Камераларды өшіру"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Құрылғыдағы барлық камералар қолданысын бөгеу."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Кілтпернедегі функциялары өшіру"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Кілтпернедегі кейбір функцияларды қолдануды бөгеу."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Экран бекітпесінің мүмкіндіктерін өшіру"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Экран бекітпесінің кейбір мүмкіндіктерін пайдалануды болдырмау."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Үй"</item>
     <item msgid="869923650527136615">"Ұялы тел."</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> Сенсор арқылы шолу функциясын іске қосуды қалайды. Сенсор арқылы шолу функциясы қосылғанда саусақ астындағы нысан сипаттарын естуге немесе көруге болады немесе телефонмен қатынасу қимылдарын орындауға болады."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ай бұрын"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Осыған дейін 1 ай бұрын"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секунд бұрын"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минут бұрын"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 сағат бұрын"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Соңғы <xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Соңғы <xliff:g id="COUNT_1">%d</xliff:g> күн</item>
+      <item quantity="one">Соңғы <xliff:g id="COUNT_0">%d</xliff:g> күн</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Соңғы ай"</string>
     <string name="older" msgid="5211975022815554840">"Ескілеу"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"кеше"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 секундта"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 минутта"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 сағатта"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ертең"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 секунд бұрын"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> секунд бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 минут бұрын"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минут бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 сағат бұрын"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> сағат бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"кеше"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 секундта"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> секундта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 минутта"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 сағатта"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> сағатта"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ертең"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> күнде"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> күні"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> уақытында"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> жылда"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"апталар"</string>
     <string name="year" msgid="4001118221013892076">"жыл"</string>
     <string name="years" msgid="6881577717993213522">"жылдар"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунд"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунд"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 минут"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минут"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 сағат"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> сағат"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="one">1 секунд</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минут</item>
+      <item quantity="one">1 минут</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> сағат</item>
+      <item quantity="one">1 сағат</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Бейне ақаулығы"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Бұл бейне осы құрылғыға ағынын жіберуге жарамсыз."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Бұл бейне таспаны ойната алмайды."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android іске қосылуда…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Қойманы оңтайландыру."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ішінен <xliff:g id="NUMBER_0">%1$d</xliff:g> қолданба оңтайландырылуда."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> дайындалуда."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Қолданбалар іске қосылуда."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Қосуды аяқтауда."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> қосылған"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Жаңа қолданбаны іске қоспау."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> қолданбасын қосу"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ескі қолданбаны сақтаусыз тоқтату."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Мәтін үшін әрекет таңдау"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Қоңырау шырылының қаттылығы"</string>
     <string name="volume_music" msgid="5421651157138628171">"Meдиа дыбысының қаттылығы"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ешқандай"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Бастапқы қоңырау әуендері"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Белгісіз қоңырау әуені"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi желісі қол жетімді"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi желілері қол жетімді"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Ашық Wi-Fi желісі қол жетімді"</item>
-    <item quantity="other" msgid="7915895323644292768">"Ашық Wi-Fi желілері қол жетімді"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi желілері қол жетімді</item>
+      <item quantity="one">Wi-Fi желісі қол жетімді</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Ашық Wi-Fi желілері қол жетімді</item>
+      <item quantity="one">Ашық Wi-Fi желісі қол жетімді</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi желісіне кіру"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Желіге кіру"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет байланысы нашар."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s қолданбасы %2$s Wi-Fi желісіне қосылғысы келеді"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Қолданба"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi тікелей"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Тікелей байланысын бастау. Бұл Wi-Fi клиент/хот-спотты өшіреді."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Тікелей байланысын қоса алмады."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Жарайды"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Медиа құралы ретінде қосылған"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Камера ретінде жалғанған"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI құрылғысы ретінде қосылу орындалды"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Орнату құрылғысына жалғанған"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB жабдығына қосылған"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Басқа USB oпцияларын түрту."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Аттап өту"</string>
     <string name="no_matches" msgid="8129421908915840737">"Сәйкес табылмады"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Беттен табу"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 сәйкестік"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>, барлығы <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> ішінен <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="one">1 сәйкестік</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Орындалды"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB жадын шығаруда…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD картасын шығаруда…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Шектеулерді өзгертуге арналған PIN жасақтау"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN кодтар сәйкес емес. Қайта әрекеттеніңіз."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN тым қысқа. Кем дегенде 4 бірлік болуы тиіс."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 секундтан кейін қайта әрекеттеніңіз"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Әрекетті <xliff:g id="COUNT">%d</xliff:g> секундтан кейін қайталаңыз</item>
+      <item quantity="one">Әрекетті 1 секундтан кейін қайталаңыз</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Кейінірек қайта әрекеттеніңіз."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толық экраннан шығу үшін саусағыңызды жоғарыдан төмен қарай жылжытыңыз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Толық экранда көру"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Шығу үшін жоғарыдан төмен қарай жанап өтіңіз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Түсіндім"</string>
     <string name="done_label" msgid="2093726099505892398">"Орындалды"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Сағаттар айналымының қозғалтқышы"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Минут айналымын қозғалтқыш"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Осы экранды босату үшін «Кері» және «Шолу» пәрмендерін бір уақытта түртіп, ұстап тұрыңыз."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Осы экранды босату үшін «Шолу» пәрменін түртіп, ұстап тұрыңыз."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран түйрелген. Босатуға ұйымыңыз рұқсат етпейді."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран босатылды"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареяның қызмет көрсету мерзімін жақсарту үшін батарея үнемдегіш құрылғының өнімділігін төмендетеді және дірілді, орынды анықтау қызметтерін және фондық деректердің көпшілігін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nБатарея үнемдегіш құрылғы зарядталып жатқанда автоматты түрде өшеді."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> уақытында әрекетсіздік аяқталғанша"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Бос тұру уақыты аяқталғанша"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Бір минут бойы (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> дейін)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d минут бойы (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> дейін)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Бір сағат бойы (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> дейін)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d сағат бойы (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> дейін)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Бір минут бойы"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d минут бойы"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Бір сағат бойы"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d сағат бойы"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d минут бойы (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> дейін)</item>
+      <item quantity="one">Бір минут бойы (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> дейін)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d сағат бойы (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> дейін)</item>
+      <item quantity="one">Бір сағат бойы (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> дейін)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d минут бойы</item>
+      <item quantity="one">Бір минут бойы</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d сағат бойы</item>
+      <item quantity="one">Бір сағат бойы</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Белгісіз уақыт бойы"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Сіз осыны өшіргенше"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Тасалау"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> уақытындағы келесі дабылға дейін"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Келесі дабылға дейін"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сұрауы DIAL сұрауына өзгертілді."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сұрауы USSD сұрауына өзгертілді."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сұрауы жаңа SS сұрауына өзгертілді."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB перифериялық порты"</string>
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 542ba8e..f429f59 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> វិនាទី"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> វិនាទី"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;គ្មាន​ចំណង​ជើង&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(គ្មាន​លេខ​ទូរស័ព្ទ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"មិន​ស្គាល់"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"សារ​ជា​សំឡេង"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ស៊ីមកាត​​របស់​អ្នក​ជាប់​កូដ PUK ។ បញ្ចូល​កូដ PUK ដើម្បី​ដោះ​សោ។"</string>
     <string name="needPuk2" msgid="4526033371987193070">"បញ្ចូល​កូដ PUK2 ដើម្បី​ដោះ​សោ​ស៊ីម​កាត។"</string>
     <string name="enablePin" msgid="209412020907207950">"បរាជ័យ, បើក​ការ​ចាក់សោ​ស៊ី​ម / RUIM ។"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅសល់​មុន​ពេល​ស៊ី​ម​ត្រូវ​បាន​ចាក់សោ​។"</item>
-    <item quantity="other" msgid="7530597808358774740">"អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅសល់​មុន​ពេល​ស៊ី​ម​ត្រូវ​បាន​ចាក់សោ​។"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត មុនពេលស៊ីមត្រូវចាក់សោ។</item>
+      <item quantity="one">អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_0">%d</xliff:g> ដងទៀត មុនពេលស៊ីមត្រូវចាក់សោ។</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"លេខ​សម្គាល់​អ្នក​ហៅ​​ចូល​"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បាន​បើក​របៀប​ពេល​ជិះ​យន្ត​ហោះ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បាន​បិទ​របៀបពេលជិះ​យន្តហោះ​"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ការ​កំណត់"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ជំនួយសម្លេង"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោ​ឥឡូវនេះ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​ការ​បង្ហាញ​ពី​ចម្ងាយ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក​"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ភ្ជាប់​ទៅ​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​ច្រក"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ក្រុមហ៊ុន​ផ្ដល់​​ច្រក​ដែល​បាន​ចុះ​ឈ្មោះ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទង​ជា​មួយ​អ្នកគ្រប់គ្រង​ឧបករណ៍"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យ​ម្ចាស់​ផ្ញើ​គោលបំណង​​ទៅ​អ្នក​គ្រប់គ្រង​ឧបករណ៍។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់​ទៅ​ការ​បញ្ចូល​ទូរទស្សន៍"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ឲ្យ​កម្មវិធី​ទាក់ទង​ជា​មួយ​ស្លាក (NFC) កាត និង​កម្មវិធី​អាន។"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"បិទ​ការ​ចាក់​សោ​អេក្រង់​របស់​អ្នក"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ឲ្យ​កម្មវិធី​បិទ​ការ​ចាក់សោ​សុវត្ថិភាព​ពាក្យ​សម្ងាត់​ដែល​បាន​ភ្ជាប់​ណា​មួយ។ ​ឧទាហរណ៍​ត្រឹមត្រូវ​​​នៃ​ការ​បិទ​ទូរស័ព្ទ​ពេល​ទទួលការ​ហៅ​ចូល បន្ទាប់​ម​បើក​សោ​ពេល​ការ​ហៅ​បាន​បញ្ចប់។"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"គ្រប់គ្រងផ្នែករឹងស្នាមម្រាមដៃ"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"អនុញ្ញាតឲ្យកម្មវិធីប្រើវិធីសាស្ត្របន្ថែម និងលុបពុម្ពម្រាមដៃសម្រាប់ប្រើប្រាស់។"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ប្រើផ្នែករឹងស្នាមម្រាមដៃ"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"អនុញ្ញាតឲ្យកម្មវិធីប្រើផ្នែករឹងស្នាមម្រាមដៃសម្រាប់ការផ្ទៀងផ្ទាត់"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"អាន​ការ​កំណត់​ធ្វើ​សម​កាល​កម្ម"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ឲ្យ​កម្មវិធី​អាន​ការ​កំណត់​ធ្វើ​សម​កាល​កម្ម​សម្រាប់​គណនី។ ឧទាហរណ៍ វា​អាច​កំណត់​ថា​តើ​​​កម្មវិធី​ត្រូវ​បាន​បើក​ជា​មួយ​គណនី​ដែរ​ឬទេ។"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"បិទ/បើក​ការ​ធ្វើ​សម​កាល​កម្ម"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យ​កម្មវិធី​ទៅ​យក ពិនិត្យ និង​សម្អាត​ការ​ជូន​ដំណឹង រួមមាន​​ប្រកាស​ដោយ​កម្មវិធី​ផ្សេងៗ។"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចង​ទៅ​សេវាកម្ម​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​​ទេ។"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ចងភ្ជាប់ទៅសេវាកម្មគោលដៅជ្រើសរើស"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"អនុញ្ញាតឲ្យអ្នកប្រើចងភ្ជាប់ទៅអ៊ីនធឺហ្វេសកម្រិតខ្ពស់នៃសេវាកម្មគោលដៅជ្រើសរើស។ អាចនឹងមិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ភ្ជាប់​ទៅ​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​​របស់​សេវាកម្ម​ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ភ្ជាប់​​ទៅ​សេវា​ផ្លូវ​មេឌៀ"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​ពេញ​និយម​នៃ​សេវាកម្ម​ផ្លូវ​មេឌៀ​។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ​។"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ភ្ជាប់​ទៅ​សេវាកម្ម​ស្រមោល​ស្រមៃ"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ស្រមើ​ស្រមៃ។ មិន​គួរ​ចាំបាច់​​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ដកហូត​កម្មវិធី​កំណត់​រចនាសម្ព័ន្ធ​ដែល​បាន​ផ្ដល់​ដោយ​ក្រុមហ៊ុន​បញ្ជូន"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ភ្ជាប់ទៅសេវាកម្មសារអ្នកផ្តល់សេវាកម្មទូរស័ព្ទ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"អនុញ្ញាតឲ្យអ្នកប្រើភ្ជាប់ទៅអ៊ីនធឺហ្វេសកម្រិតខ្ពស់នៃសេវាកម្មសារអ្នកផ្តល់សេវាកម្មទូរស័ព្ទ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់​ក្បួន​ពាក្យ​សម្ងាត់"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"ពិនិត្យ​ប្រវែង និង​តួអក្សរ​ដែល​បាន​អនុញ្ញាត​ក្នុង​ពាក្យ​សម្ងាត់​ចាក់​សោ​អេក្រង់។"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"គ្រប់គ្រងប្រវែង និងតួអក្សរដែលអនុញ្ញាតឲ្យប្រើក្នុងពាក្យសម្ងាត់ និងលេខសម្ងាត់ចាក់សោអេក្រង់។"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ពិនិត្យ​ការ​ព្យាយាម​ដោះ​សោ​អេក្រង់"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ពិនិត្យ​ចំនួន​​បញ្ចូល​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។ ពេល​ដោះ​សោ​អេក្រង់ និង​ចាក់​សោ​ទូរស័ព្ទ ឬ​លុប​ទិន្នន័យ​ទូរស័ព្ទ​ទាំងអស់​ ប្រសិន​បើ​មាន​ពាក្យ​សម្ងាត់​បញ្ចូល​មិន​ត្រឹមត្រូវ​ច្រើន​ដង​ពេក។"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ត្រួតពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោទូរទស្សន៍ ឬលុបទិន្នន័យទូរទស្សន៍ទាំង ប្រសិនបើមានការវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ពិនិត្យ​ចំនួន​​បញ្ចូល​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។ ពេល​ដោះ​សោ​អេក្រង់ និង​ចាក់​សោ​ទូរស័ព្ទ ឬ​លុប​ទិន្នន័យ​ទូរស័ព្ទ​ទាំងអស់​ ប្រសិន​បើ​មាន​ពាក្យ​សម្ងាត់​បញ្ចូល​មិន​ត្រឹមត្រូវ​ច្រើន​ដង​ពេក។"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"ប្ដូរ​ពាក្យ​សម្ងាត់​ដោះ​សោ​អេក្រង់"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"ប្ដូរ​ពាក្យ​សម្ងាត់​​ដោះ​សោ​អេក្រង់។"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ត្រួតពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោថេប្លេត ឬលុបទិន្នន័យអ្នកប្រើនេះទាំងអស់ ប្រសិនបើមានការវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ត្រួតពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោទូរទស្សន៍ ឬលុបទិន្នន័យអ្នកប្រើនេះទាំងអស់ ប្រសិនបើមានការវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ត្រួតពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោទូរស័ព្ទ ឬលុបទិន្នន័យអ្នកប្រើនេះទាំងអស់ ប្រសិនបើមានការវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"ប្តូរការចាក់សោអេក្រង់"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"ប្តូរការចាក់សោអេក្រង់។"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ចាក់សោ​អេក្រង់"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"ពិនិត្យ​វិធី និង​ពេលវេលា​ចាក់សោ​អេក្រង់។"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"លុប​ទិន្នន័យ​ទាំង​អស់"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"លុប​ទិន្នន័យ​កុំព្យូទ័រ​បន្ទះ​ដោយ​មិន​​ព្រមាន​ដោយ​អនុវត្ត​ការ​កំណត់​ទិន្នន័យ​ដូច​ចេញ​ពី​រោងចក្រ។"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"លុបទិន្នន័យរបស់ទូរទស្សន៍ដោយមិនចាំបាច់ព្រមានដោយការប្រតិបត្តិការកំណត់ឡើងវិញទាំងស្រុង។"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"លុប​ទិន្នន័យ​ទូរស័ព្ទ​ដោយ​មិន​ព្រមាន ដោយ​អនុវត្ត​ការ​កំណត់​ទិន្នន័យ​ដូច​ចេញ​ពី​រោងចក្រ ។"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"លុបទិន្នន័យរបស់អ្នកប្រើ"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"លុបទិន្នន័យរបស់អ្នកប្រើនេះនៅលើថេប្លេតនេះដោយគ្មានការព្រមាន។"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"លុបទិន្នន័យរបស់អ្នកប្រើនេះនៅលើទូរទស្សន៍នេះដោយគ្មានការព្រមាន។"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"លុបទិន្នន័យរបស់អ្នកប្រើនេះនៅលើទូរស័ព្ទនេះដោយគ្មានការព្រមាន។"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"កំណត់​ប្រូកស៊ី​សកល​របស់​ឧបករណ៍"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"កំណត់​ប្រូកស៊ី​សកល​របស់​ឧបករណ៍​ត្រូវ​ប្រើ​ពេល​បាន​បើក​គោលនយោបាយ។ មាន​តែ​អ្នក​គ្រប់គ្រង​ឧបករណ៍​ដំបូង​ប៉ុណ្ណោះ​កំណត់​ប្រូកស៊ី​សកល​ត្រឹមត្រូវ។"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"កំណត់​សុពលភាព​ពាក្យ​សម្ងាត់​ចាក់សោ​អេក្រង់"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ពិនិត្យ​វិធី​ដែល​ប្ដូរ​ពាក្យ​សម្ងាត់​ចាក់​សោ​អេក្រង់​ញឹកញាប់។"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"កំណត់ប្រូកស៊ីសកលឧបករណ៍ដើម្បីប្រើប្រាស់ ខណៈពេលដែលគោលការណ៍បើកដំណើរការ។ មានតែឧបករណ៍ម្ចាស់ប៉ុណ្ណោះអាចកំណត់ប្រូកស៊ីសកលនេះបាន។"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"កំណត់ពេលផុតកំណត់ពាក្យសម្ងាត់ចាក់សោអេក្រង់"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"ប្តូរពីភាពញឹកញាប់ដែលពាក្យសម្ងាត់ លេខសម្ងាត់ និងគំរូចាក់សោអេក្រង់ត្រូវផ្លាស់ប្តូរ។"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"កំណត់​ការ​ដាក់លេខ​កូដ​ការ​ផ្ទុក"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"តម្រូវ​ឲ្យ​ដាក់​លេខ​កូដ​ទិន្នន័យ​កម្មវិធី​បាន​រក្សាទុក។"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"បិទ​ម៉ាស៊ីន​ថត"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"ការពារ​ការ​ប្រើ​ម៉ាស៊ីន​ថត​ឧបករណ៍​ទាំងអស់។"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"បិទ​លក្ខណៈ​ក្នុង​ការ​ចាក់សោ"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"ការ​ពារ​មិន​ឲ្យ​ប្រើ​លក្ខណៈ​មួយ​ចំនួន​ក្នុង​ការ​ចាក់សោ។"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"បិទលក្ខណៈពិសេសចាក់សោអេក្រង់"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"រារាំងអ្នកប្រើពីការប្រើលក្ខណៈពិសេសនៃការចាក់សោអេក្រង់មួយចំនួន។"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"ផ្ទះ"</item>
     <item msgid="869923650527136615">"​ចល័ត"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ចង់​បើក​ការ​រុករ​ក​ដោយ​ប៉ះ។ ពេល​រុករក​ដោយ​ប៉ះ​ត្រូវ​បាន​បើក​​ អ្នក​អាច​ស្ដាប់​ឮ​ ឬ​ឃើញ​ការ​ពណ៌នា​អ្វី​ដែល​នៅ​ក្រោម​ម្រាមដៃ​របស់​អ្នក​​ ឬ​អនុវត្ត​កាយវិការ​ដើម្បី​មាន​អន្តរកម្ម​ជា​មួយ​ទូរស័ព្ទ។"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ខែ​មុន"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"មុន​ពេល ១ ខែ​មុន"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"១ វិនាទី​មុន"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី​មុន"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"១ នាទី​មុន"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> នាទី​​មុន"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"១ ម៉ោង​មុន"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោង​មុន"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​ចុងក្រោយ"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g> ថ្ងៃចុងក្រោយ</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g> ថ្ងៃចុងក្រោយ</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"ខែ​មុន"</string>
     <string name="older" msgid="5211975022815554840">"ចាស់​ជាង"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ម្សិលមិញ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​មុន"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ក្នុង​រយៈ​ពេល ១ វិនាទី"</item>
-    <item quantity="other" msgid="1241926116443974687">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ក្នុង​រយៈពេល ១ នាទី"</item>
-    <item quantity="other" msgid="3330713936399448749">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"រយៈពេល ១ ម៉ោង"</item>
-    <item quantity="other" msgid="547290677353727389">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ថ្ងៃស្អែក"</item>
-    <item quantity="other" msgid="5109449375100953247">"រយៈពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"១ វិនាទី​មុន"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"១ នាទី​មុន"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> នាទី​​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"១ ម៉ោង​មុន"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោង​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ម្សិលមិញ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ​​មុន"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ក្នុង​ពេល​ 1 វិនាទី"</item>
-    <item quantity="other" msgid="5495880108825805108">"ក្នុង​ពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ក្នុង​ពេល 1 នាទី"</item>
-    <item quantity="other" msgid="4216113292706568726">"នៅ​រយៈពេល <xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ក្នុង​រយៈ​ពេល ១ ម៉ោង"</item>
-    <item quantity="other" msgid="3705373766798013406">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ថ្ងៃស្អែក"</item>
-    <item quantity="other" msgid="2973062968038355991">"ក្នុង​រយៈ​ពេល <xliff:g id="COUNT">%d</xliff:g> ថ្ងៃ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"នៅ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"នៅ​ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ក្នុង​ឆ្នាំ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍​"</string>
     <string name="year" msgid="4001118221013892076">"ឆ្នាំ​"</string>
     <string name="years" msgid="6881577717993213522">"ឆ្នាំ​"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 វិនាទី"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"១ នាទី"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> នាទី"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"១ ម៉ោង"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ម៉ោង"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> វិនាទី</item>
+      <item quantity="one">1 វិនាទី</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> នាទី</item>
+      <item quantity="one">1 នាទី</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ម៉ោង</item>
+      <item quantity="one">1 ម៉ោង</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"បញ្ហា​វីដេអូ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"វីដេអូ​នេះ​មិន​ត្រឹមត្រូវ​សម្រាប់​​ចរន្ត​ចូល​ឧបករណ៍​នេះ។"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"មិន​អាច​ចាក់​វីដេអូ​នេះ។"</string>
@@ -1303,6 +1256,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android កំពុង​ចាប់ផ្ដើម…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"កំពុងធ្វើឲ្យឧបករណ៍ផ្ទុកមានប្រសិទ្ធភាព។"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ធ្វើ​ឲ្យ​កម្មវិធី​ប្រសើរ​ឡើង <xliff:g id="NUMBER_0">%1$d</xliff:g> នៃ <xliff:g id="NUMBER_1">%2$d</xliff:g> ។"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"កំពុងរៀបចំ <xliff:g id="APPNAME">%1$s</xliff:g>។"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ចាប់ផ្ដើម​កម្មវិធី។"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"បញ្ចប់​ការ​ចាប់ផ្ដើម។"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
@@ -1313,6 +1267,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"កុំ​ចាប់ផ្ដើម​កម្មវិធី​ថ្មី។"</string>
     <string name="new_app_action" msgid="5472756926945440706">"ចាប់ផ្ដើម <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"បញ្ឈប់​កម្មវិធី​ចាស់​ដោយ​មិន​រក្សាទុក"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ជ្រើស​សកម្មភាព​សម្រាប់​អត្ថបទ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"កម្រិត​សំឡេង​រោទ៍"</string>
     <string name="volume_music" msgid="5421651157138628171">"កម្រិត​សំឡេង​មេឌៀ"</string>
@@ -1333,20 +1295,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"គ្មាន"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"សំឡេង​រោទ៍"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"សំឡេង​រោទ៍​មិន​ស្គាល់"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"មាន​បណ្ដាញ​វ៉ាយហ្វាយ"</item>
-    <item quantity="other" msgid="4192424489168397386">"មាន​បណ្ដាញ​វ៉ាយហ្វាយ"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"បើក​បណ្ដាញ​វ៉ាយហ្វាយ​​ដែល​មាន"</item>
-    <item quantity="other" msgid="7915895323644292768">"មាន​បណ្ដាញ​វ៉ាយហ្វាយ​បើក"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">មានបណ្តាញ Wi-Fi</item>
+      <item quantity="one">មានបណ្តាញ Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
+      <item quantity="one">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"ចូល​បណ្ដាញ​វ៉ាយហ្វាយ"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ចូល​ក្នុង​បណ្ដាញ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មិន​ល្អ។"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"កម្មវិធី %1$s ចង់ភ្ជាប់ទៅបណ្តាញ Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"កម្មវិធី"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"វ៉ាយហ្វាយ​ផ្ទាល់"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើម​វ៉ាយហ្វាយ​ផ្ទាល់។ វា​នឹង​បិទ​វ៉ាយហ្វាយ​ហតស្ពត។"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"មិន​អាច​ចាប់ផ្ដើម​វ៉ាយហ្វា​ដោយ​ផ្ទាល់។"</string>
@@ -1413,6 +1378,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"យល់ព្រម"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"បាន​តភ្ជាប់​ជា​ឧបករណ៍​​ផ្ទុក"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"បាន​ភ្ជាប់​ជា​ម៉ាស៊ីន​ថត"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"បានភ្ជាប់ជាឧបករណ៍មីឌី"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"បាន​ភ្ជាប់​ជា​កម្មវិធី​ដំឡើង"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"បាន​ភ្ជាប់​ឧបករណ៍​យូអេសប៊ី"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"ប៉ះ ដើម្បី​មើល​ជម្រើស​យូអេសប៊ី​ផ្សេង។"</string>
@@ -1528,10 +1494,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"រំលង"</string>
     <string name="no_matches" msgid="8129421908915840737">"គ្មាន​ការ​ផ្គូផ្គង"</string>
     <string name="find_on_page" msgid="1946799233822820384">"រក​ក្នុង​ទំព័រ"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"១ ប្រកួត"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> នៃ <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> នៃ <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">ការប្រកួត 1</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"រួចរាល់"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"កំពុង​ផ្ដាច់​ឧបករណ៍​យូអេសប៊ី..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"កំពុង​ផ្ដាច់​កាត​អេសឌី..."</string>
@@ -1817,12 +1783,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"បង្កើត​កូដ PIN សម្រាប់​កែ​ការ​ដាក់​កម្រិត"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"កូដ PIN មិន​ដូច​គ្នា។ ព្យាយាម​ម្ដង​ទៀត។"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"កូដ​ PIN ខ្លី​ពេក។ ត្រូវ​តែ​មាន​យ៉ាង​ហោច​ណាស់ ៤ តួ។"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល​ ១​វិនាទី។"</item>
-    <item quantity="other" msgid="4730868920742952817">"សូម​ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">ព្យាយាមម្តងទៀតក្នុងរយៈពេល <xliff:g id="COUNT">%d</xliff:g> វិនាទី</item>
+      <item quantity="one">ព្យាយាមម្តងទៀតក្នុងរយៈពេល 1 វិនាទី</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"សូម​ព្យាយាម​ម្ដងទៀត​នៅ​ពេល​ក្រោយ។"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"អូស​​​​ពីលើ​ចុះក្រោម ដើម្បី​ចេញ​ពី​ការ​បង្ហាញ​ពេញ​អេក្រង់។"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"កំពុងមើលពេញអេក្រង់"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"យល់ហើយ"</string>
     <string name="done_label" msgid="2093726099505892398">"រួចរាល់"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"គ្រាប់​រំកិល​រង្វង់​ម៉ោង"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"គ្រាប់​រំកិល​រង្វង់​នាទី"</string>
@@ -1837,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែង​ធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ដើម្បី​មិន​ភ្ជាប់​អេក្រង់​នេះ ប៉ះ ហើយ​សង្កត់​ថយក្រោយ និង​ទិដ្ឋភាព​នៅ​ពេល​តែ​មួយ។"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ដើម្បី​មិន​ភ្ជាប់​អេក្រង់​នេះ ប៉ះ ហើយ​សង្កត់​ទិដ្ឋភាព។"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"អេក្រង់​ត្រូវ​បាន​ភ្ជាប់។ ការ​ផ្ដាច់​មិន​​ត្រូវ​បាន​អនុញ្ញាត​ដោយ​ស្ថាប័ន​របស់​អ្នក។"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"បាន​ភ្ជាប់​អេក្រង់"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"មិន​បាន​ភ្ជាប់​អេក្រង់"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួរ​រក​កូដ PIN មុន​ពេល​ផ្ដាច់"</string>
@@ -1846,24 +1815,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ដើម្បីជួយឲ្យថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំសំចៃថាមពលថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតភាពញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយស្ទើរតែទាំងអស់។ ការផ្ញើសារអ៊ីម៉ែល និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មអាចនឹងមិនធ្វើបច្ចុប្បន្នភាពទេ លុះត្រាតែអ្នកបើកពួកវា។\n\nកម្មវិធីសន្សំសំចៃបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"រហូត​ដល់ម៉ោង​សម្រាក ឬរវល់​របស់​អ្នក​បញ្ចប់​នៅ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"រហូត​ដល់​ម៉ោង​រាប់​ថយក្រោយ​ចប់"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"សម្រាប់​មួយ​នាទី (រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"សម្រាប់ %1$d នាទី​ (រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"សម្រាប់​មួយ​ម៉ោង (រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"សម្រាប់ %1$d ម៉ោង (រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"សម្រាប់​មួយ​នាទី"</item>
-    <item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"សម្រាប់​មួយ​ម៉ោង"</item>
-    <item quantity="other" msgid="5408537517529822157">"សម្រាប់ %d ម៉ោង"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">រយៈពេល %1$d នាទី (រហូតដល់ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">រយៈពេលមួយនាទី (រហូតដល់ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">រយៈពេល %1$d ម៉ោង (រហូតដល់ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">រយៈពេលមួយម៉ោង (រហូតដល់ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">រយៈពេល %d នាទី</item>
+      <item quantity="one">រយៈពេលមួយនាទី</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">រយៈពេល %d ម៉ោង</item>
+      <item quantity="one">រយៈពេលមួយម៉ោង</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"គ្មាន​​កំណត់"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"រហូត​ដល់ពេល​​អ្នក​បិទ​វា"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"បង្រួម"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"រហូត​ដល់​ការ​ជូន​ដំណឹង​បន្ទាប់​នៅ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"រហូត​ការ​ជូន​ដំណឹង​បន្ទាប់"</string>
@@ -1876,4 +1845,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរការហៅទូរស័ព្ទ។"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ USSD។"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"សំណើរ SS ត្រូវបានកែសម្រួលទៅតាមសំណើរ SS ថ្មី។"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"ឧបករណ៍រន្ធ USB បន្ថែម"</string>
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 6d1730e..a834721 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ಸೆಕೆಂಡುಗಳು"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ಸೆಕೆಂಡುಗಳು"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ಶೀರ್ಷಿಕೆ ರಹಿತ&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ಯಾವುದೇ ಫೋನ್ ಸಂಖ್ಯೆಯಿಲ್ಲ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"ಅಪರಿಚಿತ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ಧ್ವನಿಮೇಲ್"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ನಿಮ್ಮ ಸಿಮ್‌ ಕಾರ್ಡ್ PUK-ಲಾಕ್ ಆಗಿದೆ. ಅದನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು PUK ಕೋಡ್ ಟೈಪ್ ಮಾಡಿ."</string>
     <string name="needPuk2" msgid="4526033371987193070">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು PUK2 ಟೈಪ್ ಮಾಡಿ."</string>
     <string name="enablePin" msgid="209412020907207950">"ಯಶಸ್ವಿಯಾಗಿಲ್ಲ, ಸಿಮ್‌/RUIM ಲಾಕ್ ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"ಸಿಮ್‌ ಲಾಕ್ ಆಗುವುದಕ್ಕಿಂತ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನ ಬಾಕಿ ಉಳಿದಿದೆ."</item>
-    <item quantity="other" msgid="7530597808358774740">"ಸಿಮ್‌ ಲಾಕ್ ಆಗುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one"> ಸಿಮ್‌ ಲಾಕ್‌ ಆಗುವುದಕ್ಕಿಂತ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+      <item quantity="other"> ಸಿಮ್‌ ಲಾಕ್‌ ಆಗುವುದಕ್ಕಿಂತ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ಒಳಬರುವ ಕರೆಮಾಡುವವರ ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ಎರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆನ್ ಆಗಿದೆ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ಎರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ರಿಮೋಟ್ ಪ್ರದರ್ಶನದ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ವಿಜೆಟ್ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ವಿಜೆಟ್‌‌ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ಮಾರ್ಗ ಪೂರೈಕೆದಾರರ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ಯಾವುದೇ ನೋಂದಾಯಿತ ಪೂರೈಕೆದಾರರನ್ನು ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ಸಾಧನ ನಿರ್ವಾಹಕರ ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಿ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ಸಾಧನ ನಿರ್ವಾಹಕರಿಗೆ ಉದ್ದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV ಇನ್‌ಪುಟ್‌‌ ಅನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ಸಮೀಪದ ಕ್ಷೇತ್ರ ಸಂವಹನ (NFC) ಟ್ಯಾಗ್‌ಗಳು, ಕಾರ್ಡ್‌ಗಳು, ಮತ್ತು ಓದುಗರನ್ನು ಅಪ್ಲಿಕೇಶನ್‌ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ನಿಮ್ಮ ಪರದೆ ಲಾಕ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ಕೀಲಾಕ್ ಮತ್ತು ಯಾವುದೇ ಸಂಬಂಧಿತ ಭದ್ರತಾ ಪಾಸ್‍‍ವರ್ಡ್ ಭದ್ರತೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಒಳಬರುವ ಕರೆಯನ್ನು ಸ್ವೀಕರಿಸುವಾಗ ಕೀಲಾಕ್ ಅನ್ನು ಫೋನ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ, ನಂತರ ಕರೆಯು ಅಂತ್ಯಗೊಂಡಾಗ ಕೀಲಾಕ್ ಅನ್ನು ಮರು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಹಾರ್ಡ್‌ವೇರ್ ನಿರ್ವಹಿಸಿ"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ಬಳಕೆಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಟೆಂಪ್ಲೇಟ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಮತ್ತು ಅಳಿಸಲು ವಿಧಾನಗಳನ್ನು ಮನವಿ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಹಾರ್ಡ್‌ವೇರ್ ಬಳಸಿ"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಹಾರ್ಡ್‌ವೇರ್ ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ರೀಡ್‌ ಮಾಡು"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ಒಂದು ಖಾತೆಯ ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್‍‍ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಖಾತೆಯೊಂದಿಗೆ ಜನರ ಅಪ್ಲಿಕೇಶನ್ ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಇದು ನಿರ್ಧರಿಸಬಹುದು."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ಸಿಂಕ್ ಆನ್ ಮತ್ತು ಸಿಂಕ್ ಆಫ್ ಟಾಗಲ್ ಮಾಡಿ"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಮೂಲಕ ಪೋಸ್ಟ್ ಮಾಡಿರುವ ಅಧಿಸೂಚನೆಗಳೂ ಸೇರಿದಂತೆ, ಅಂತಹ ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಿಂಪಡೆದುಕೊಳ್ಳಲು, ಪರೀಕ್ಷಿಸಲು ಮತ್ತು ತೆರವುಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ಅಧಿಸೂಚನೆ ಕೇಳುಗರ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ಆಯ್ಕೆಮಾಡುವವರ ಗುರಿ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ಕಂಡೀಶನ್‌‌ ಪೂರೈಕೆದಾರರ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ಕಂಡೀಶನ್‌ ಪೂರೈಕೆದಾರರ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"ಮಾಧ್ಯಮ ಮಾರ್ಗ ಸೇವೆಯನ್ನು ಪ್ರತಿಬಂಧಿಸು"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"ಮಾಧ್ಯಮ ವರ್ಗ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ಕನಸಿನ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ಕನಸಿನ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ವಾಹಕ-ಒದಗಿಸಿರುವ ಕಾನ್ಫಿಗರೇಶನ್ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ವಿನಂತಿಸಿಕೊಳ್ಳಿ"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ವಾಹಕ ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ವಾಹಕ ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ಪಾಸ್‌ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"ಪರದೆ-ಅನ್‍‍ಲಾಕ್ ಪಾಸ್‍‍ವರ್ಡ್‌ಗಳಲ್ಲಿ ಅನುಮತಿಸಿರುವ ಅಳತೆ ಮತ್ತು ಅಕ್ಷರಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"ಪರದೆ ಲಾಕ್‌ನಲ್ಲಿನ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಿನ್‌ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ಪರದೆಯ-ಅನ್‌ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮಾನಿಟರ್ ಮಾಡಿ"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ಪರದೆಯನ್ನು ಅನ್‌ಲಾಕ್‌ ಮಾಡುವಾಗ ತಪ್ಪಾಗಿ ಟೈಪ್‌ ಮಾಡಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ, ಮತ್ತು ಟ್ಯಾಬ್ಲೆಟ್‌ ಅನ್ನು ಲಾಕ್‌ ಮಾಡಿ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್‌ ಮಾಡಿದ್ದರೆ ಟ್ಯಾಬ್ಲೆಟ್‌ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ಪರದೆ ಅನ್‌ಲಾಕ್ ಮಾಡುವಾಗ ಟೈಪ್ ಮಾಡಿದ ತಪ್ಪು ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ ಮತ್ತು ಒಂದು ವೇಳೆ ಹಲವಾರು ತಪ್ಪು ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್ ಮಾಡಿದ್ದರೆ ಟಿವಿಯನ್ನು ಲಾಕ್ ಮಾಡಿ ಅಥವಾ  ಟಿವಿಯ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ಪರದೆಯನ್ನು ಅನ್‌ಲಾಕ್‌ ಮಾಡಿದಾಗ ತಪ್ಪಾಗಿ ಟೈಪ್‌ ಮಾಡಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ, ಮತ್ತು ಫೋನ್‌‌ ಅನ್ನು ಲಾಕ್‌ ಮಾಡಿ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್‌ ಮಾಡಿದ್ದರೆ ಫೋನ್‌‌ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"ಸ್ಕ್ರೀನ್‌-ಅನ್‌ಲಾಕ್ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"ಪರದೆಯ-ಅನ್‍‍ಲಾಕ್ ಪಾಸ್‍ವರ್ಡ್ ಬದಲಾಯಿಸಿ."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ಪರದೆಯನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡುವಾಗ ಟೈಪ್ ಮಾಡಲಾದ ತಪ್ಪಾಗಿರುವ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಟ್ಯಾಬ್ಲೆಟ್ ಲಾಕ್ ಮಾಡಿ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್ ಮಾಡಲಾಗಿದ್ದರೆ ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ಪರದೆಯನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡುವಾಗ ಟೈಪ್ ಮಾಡಲಾದ ತಪ್ಪಾಗಿರುವ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಟಿವಿಯನ್ನು ಲಾಕ್ ಮಾಡಿ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್ ಮಾಡಲಾಗಿದ್ದರೆ ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ಪರದೆಯನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡುವಾಗ ಟೈಪ್ ಮಾಡಲಾದ ತಪ್ಪಾಗಿರುವ ಪಾಸ್‌ವರ್ಡ್‌ಗಳ ಸಂಖ್ಯೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಫೋನ್ ಲಾಕ್ ಮಾಡಿ ಅಥವಾ ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಟೈಪ್ ಮಾಡಲಾಗಿದ್ದರೆ ಈ ಬಳಕೆದಾರರ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"ಪರದೆ ಲಾಕ್ ಬದಲಾಯಿಸಿ"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"ಪರದೆ ಲಾಕ್ ಬದಲಾಯಿಸಿ."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ಪರದೆ ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"ಪರದೆಯು ಯಾವಾಗ ಮತ್ತು ಹೇಗೆ ಲಾಕ್ ಆಗಬೇಕೆಂಬುದನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿ"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾ ಮರುಹೊಂದಿಕೆಯನ್ನು ನಿರ್ವಹಿಸುವ ಮೂಲಕ ಎಚ್ಚರಿಕೆಯನ್ನು ನೀಡದೆಯೇ ಟ್ಯಾಬ್ಲೆಟ್ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ಒಂದು ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾವನ್ನು ಮರುಹೊಂದಿಸುವ ಮೂಲಕ ಎಚ್ಚರಿಕೆ ನೀಡದೆಯೆ ಟಿವಿ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ಫ್ಯಾಕ್ಟರಿ ಡೇಟಾ ಮರುಹೊಂದಿಕೆಯನ್ನು ನಿರ್ವಹಿಸುವ ಮೂಲಕ ಎಚ್ಚರಿಕೆಯನ್ನು ನೀಡದೆಯೇ ಫೋನ್ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ಬಳಕೆದಾರ ಡೇಟಾ ಅಳಿಸಿ"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ಯಾವುದೇ ಸೂಚನೆ ಇಲ್ಲದೆ ಈ ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಈ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ಯಾವುದೇ ಸೂಚನೆ ಇಲ್ಲದೆ ಈ ಟಿವಿಯಲ್ಲಿ ಈ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ಯಾವುದೇ ಸೂಚನೆ ಇಲ್ಲದೆ ಈ ಫೋನ್‌ನಲ್ಲಿ ಈ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ಸಾಧನವನ್ನು ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಗೆ ಹೊಂದಿಸಿ"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ನೀತಿಯು ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಬಳಸಲು ಸಾಧನವನ್ನು ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಗೆ ಹೊಂದಿಸಿ. ಮೊದಲ ಸಾಧನ ನಿರ್ವಾಹಕರು ಮಾತ್ರ ಪರಿಣಾಮಕಾರಿ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಗೆ ಹೊಂದಿಸುತ್ತಾರೆ."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ಲಾಕ್-ಪರದೆ ಪಾಸ್‌ವರ್ಡ್ ಮುಕ್ತಾಯ ಅವಧಿಯನ್ನು ಹೊಂದಿಸಿ"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ಲಾಕ್-ಪರದೆ ಪಾಸ್‍‍ವರ್ಡ್ ಅನ್ನು ಎಷ್ಟು ಬಾರಿ ಬದಲಿಸಬೇಕು ಎಂಬುದನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ನೀತಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ ಬಳಸಬೇಕಾದ ಸಾಧನದ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಿ. ಸಾಧನದ ಮಾಲೀಕರು ಮಾತ್ರ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಬಹುದಾಗಿರುತ್ತದೆ."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"ಪರದೆ ಲಾಕ್ ಪಾಸ್‌ವರ್ಡ್ ಮುಕ್ತಾಯವನ್ನು ಹೊಂದಿಸಿ"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"ಪರದೆ ಲಾಕ್ ಪಾಸ್‌ವರ್ಡ್, ಪಿನ್, ಅಥವಾ ನಮೂನೆಯನ್ನು ಹೆಚ್ಚು ಪದೆ ಪದೇ ಬದಲಾಯಿಸಬೇಕಾಗಿರುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಿ."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ಸಂಗ್ರಹಣೆ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಹೊಂದಿಸಿ"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ಸಂಗ್ರಹಿಸಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಬೇಕಾದ ಅಗತ್ಯವಿದೆ."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ಕ್ಯಾಮರಾಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"ಎಲ್ಲಾ ಸಾಧನ ಕ್ಯಾಮರಾಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"ಕೀಗಾರ್ಡ್ ವೈಶಿಷ್ಟ್ಯ ನಿಷ್ಕ್ರಿಯ"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"ಕೀಗಾರ್ಡ್‌ನಲ್ಲಿ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"ಪರದೆ ಲಾಕ್‌ನ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"ಪರದೆ ಲಾಕ್‌ನ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"ನಿವಾಸ"</item>
     <item msgid="869923650527136615">"ಮೊಬೈಲ್"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಸಕ್ರಿಯಗೊಳಿಸಲು <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ಬಯಸುತ್ತದೆ. ಸ್ಪರ್ಶದ ಮೂಲಕ ಎಕ್ಸ್‌ಪ್ಲೋರ್ ಆನ್ ಮಾಡಿದಾಗ, ಫೋನ್‌ ಜೊತೆ ಸಂವಹನ ನಡೆಸಲು ನಿಮ್ಮ ಬೆರಳಿನ ಅಡಿಯಲ್ಲಿರುವ ವಿವರಣೆಗಳನ್ನು ನೀವು ಆಲಿಸಬಹುದು ಅಥವಾ ವೀಕ್ಷಿಸಬಹುದು ಇಲ್ಲವೇ ಗೆಶ್ಚರ್‌‌ ಮಾಡಬಹುದು."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ತಿಂಗಳ ಹಿಂದೆ"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ತಿಂಗಳ ಹಿಂದಕ್ಕೂ ಮೊದಲು"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ಕಳೆದ <xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">ಕಳೆದ <xliff:g id="COUNT_1">%d</xliff:g> ದಿನಗಳು</item>
+      <item quantity="other">ಕಳೆದ <xliff:g id="COUNT_1">%d</xliff:g> ದಿನಗಳು</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"ಕಳೆದ ತಿಂಗಳು"</string>
     <string name="older" msgid="5211975022815554840">"ಹಳೆಯದು"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ನಿನ್ನೆ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ನಾಳೆ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ಸೆಕೆಂಡಿನ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 ನಿಮಿಷದ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ಗಂಟೆ ಹಿಂದೆ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ನಿನ್ನೆ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 ನಿಮಿಷದಲ್ಲಿ"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 ಗಂಟೆಯಲ್ಲಿ"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳಲ್ಲಿ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ನಾಳೆ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ದಿನಗಳಲ್ಲಿ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> ರಂದು"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ರಲ್ಲಿ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> ರಲ್ಲಿ"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"ವಾರಗಳು"</string>
     <string name="year" msgid="4001118221013892076">"ವರ್ಷ"</string>
     <string name="years" msgid="6881577717993213522">"ವರ್ಷಗಳು"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 ಸೆಕೆಂಡು"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳು"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 ನಿಮಿಷ"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳು"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ಗಂಟೆ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳು"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳು</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳು</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳು</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ನಿಮಿಷಗಳು</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳು</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಗಂಟೆಗಳು</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ವೀಡಿಯೊ ಸಮಸ್ಯೆ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ಈ ಸಾಧನಲ್ಲಿ ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಈ ವೀಡಿಯೊ ಮಾನ್ಯವಾಗಿಲ್ಲ."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ಈ ವೀಡಿಯೊ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ಸಂಗ್ರಹಣೆಯನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="NUMBER_0">%1$d</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ಬೂಟ್ ಪೂರ್ಣಗೊಳಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ರನ್ ಆಗುತ್ತಿದೆ"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್‌ ಪ್ರಾರಂಭಿಸಬೇಡಿ."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="new_app_description" msgid="1932143598371537340">"ಉಳಿಸದೇ ಹಳೆಯ ಅಪ್ಲಿಕೇಶನ್ ನಿಲ್ಲಿಸಿ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ಪಠ್ಯಕ್ಕೆ ಕ್ರಿಯೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ರಿಂಗರ್ ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_music" msgid="5421651157138628171">"ಮೀಡಿಯಾ ವಾಲ್ಯೂಮ್"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ಯಾವುದೂ ಇಲ್ಲ"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ರಿಂಗ್‌ಟೋನ್‌ಗಳು"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ಅಜ್ಞಾತ ರಿಂಗ್‌ಟೋನ್"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿದೆ"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"ಮುಕ್ತ Wi-Fi ನೆಟ್‌ವರ್ಕ್ ಲಭ್ಯವಿದೆ"</item>
-    <item quantity="other" msgid="7915895323644292768">"ಮುಕ್ತ Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
+      <item quantity="other">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
+      <item quantity="other">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi ನೆಟ್‍ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ನೆಟ್‍ವರ್ಕ್‌ಗೆ ಸೈನ್ ಮಾಡಿ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ಕಳಪೆ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿದೆ."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s ವೈಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು %1$s ಅಪ್ಲಿಕೇಶನ್‌ ಬಯಸುತ್ತದೆ"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ಅಪ್ಲಿಕೇಶನ್"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ಡೈರೆಕ್ಟ್"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ಡೈರೆಕ್ಟ್ ಪ್ರಾರಂಭಿಸಿ. ಇದು Wi-Fi ಕ್ಲೈಂಟ್‌/ಹಾಟ್‌ಸ್ಪಾಟ್ ಅನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi ಡೈರೆಕ್ಟ್ ಪ್ರಾರಂಭಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ಸರಿ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"ಮಾಧ್ಯಮ ಸಾಧನದ ರೂಪದಲ್ಲಿ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"ಕ್ಯಾಮರಾದಂತೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI ಸಾಧನದಂತೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ಸ್ಥಾಪಕದಂತೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ಪರಿಕರಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"ಇತರ USB ಆಯ್ಕೆಗಳಿಗಾಗಿ ಸ್ಪರ್ಶಿಸಿ."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ಸ್ಕಿಪ್‌ ಮಾಡು"</string>
     <string name="no_matches" msgid="8129421908915840737">"ಯಾವುದೇ ಹೊಂದಿಕೆಗಳಿಲ್ಲ"</string>
     <string name="find_on_page" msgid="1946799233822820384">"ಪುಟದಲ್ಲಿ ಹುಡುಕಿ"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 ಹೊಂದಾಣಿಕೆ"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> ರಲ್ಲಿ <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g> ರಲ್ಲಿ <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> ರಲ್ಲಿ <xliff:g id="INDEX">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"ಮುಗಿದಿದೆ"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB ಸಂಗ್ರಹಣೆಯ ಅಳವಡಿಕೆ ತೆಗೆಯಲಾಗುತ್ತಿದೆ…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD ಕಾರ್ಡ್ ಅಳವಡಿಕೆ ತೆಗೆಯಲಾಗುತ್ತಿದೆ…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"ನಿರ್ಬಂಧಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಪಿನ್‌ ರಚಿಸಿ"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ಪಿನ್‌ ಗಳು ಹೊಂದಿಕೆಯಾಗುತ್ತಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ಪಿನ್‌ ತುಂಬಾ ಚಿಕ್ಕದಾಗಿದೆ. ಕನಿಷ್ಟ ಪಕ್ಷ 4 ಅಂಕಿಗಳಾಗಿರಬೇಕು."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 ಸೆಕೆಂಡಿನಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ನಿರ್ಗಮಿಸಲು ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ತಿಳಿಯಿತು"</string>
     <string name="done_label" msgid="2093726099505892398">"ಮುಗಿದಿದೆ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ಗಂಟೆಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ‘ಹಿಂದೆ’ ಮತ್ತು ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ಪರದೆ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ. ಅನ್‌ಪಿನ್‌ ಮಾಡಲು ನಿಮ್ಮ ಸಂಸ್ಥೆ ಅವಕಾಶ ಮಾಡಿಕೊಟ್ಟಿಲ್ಲ."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ಸ್ಕ್ರೀನ್‌ ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ಸ್ಕ್ರೀನ್‌ ಅನ್‌ಪಿನ್‌ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್‌ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಪಿನ್‌ ಕೇಳಿ"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ನಿಮ್ಮ ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವುದನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ, ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ನವೀಕರಣಗೊಳ್ಳುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ನಿಮ್ಮ ಅಲಭ್ಯತೆ ಕೊನೆಗೊಳ್ಳುವವರೆಗೆ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ನಿಮ್ಮ ಸ್ಥಗಿತಕಾಲ ಕೊನೆಗೊಳ್ಳುವವರೆಗೆ"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ಒಂದು ನಿಮಿಷದವರೆಗೆ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ವರೆಗೆ)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ವರೆಗೆ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ಒಂದು ಗಂಟೆಯವರೆಗೆ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ವರೆಗೆ)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d ಗಂಟೆಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> ವರೆಗೆ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ಒಂದು ನಿಮಿಷದವರೆಗೆ"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d ನಿಮಿಷಗಳವರೆಗೆ"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ಒಂದು ಗಂಟೆಯವರೆಗೆ"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d ಗಂಟೆಗಳವರೆಗೆ"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
+      <item quantity="other">%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d ಗಂಟೆಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
+      <item quantity="other">%1$d ಗಂಟೆಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d ನಿಮಿಷಗಳವರೆಗೆ</item>
+      <item quantity="other">%d ನಿಮಿಷಗಳವರೆಗೆ</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d ಗಂಟೆಗಳವರೆಗೆ</item>
+      <item quantity="other">%d ಗಂಟೆಗಳವರೆಗೆ</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"ಅನಿರ್ದಿಷ್ಟವಾಗಿ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ನೀವಿದನ್ನು ಆಫ್‌ ಮಾಡುವವರೆಗೆ"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ಸಂಕುಚಿಸು"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"ಮುಂದಿನ ಅಲಾರಮ್ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"ಮುಂದಿನ ಅಲಾರಮ್‌ವರೆಗೆ"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ವಿನಂತಿಯನ್ನು DIAL ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ವಿನಂತಿಯನ್ನು USSD ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ವಿನಂತಿಯನ್ನು ಹೊಸ SS ವಿನಂತಿಗೆ ಮಾರ್ಪಡಿಸಲಾಗಿದೆ."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ಹೊರಭಾಗದ ಪೋರ್ಟ್"</string>
 </resources>
diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml
index 083b176..626a480 100755
--- a/core/res/res/values-ko/donottranslate-cldr.xml
+++ b/core/res/res/values-ko/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s. %s. %s."</string>
     <string name="month_day_year">%Y년 %-m월 %-e일</string>
     <string name="time_of_day">%p %-l:%M:%S</string>
     <string name="date_and_time">%Y년 %-m월 %-e일 %p %-l:%M:%S</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ce316df..c263ce9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>초"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>초"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;제목 없음&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(전화번호 없음)"</string>
     <string name="unknownName" msgid="6867811765370350269">"알 수 없음"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"음성메일"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM 카드의 PUK가 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM 카드 잠금을 해제하려면 PUK2를 입력하세요."</string>
     <string name="enablePin" msgid="209412020907207950">"실패했습니다. SIM/RUIM 잠금을 사용 설정하세요."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"<xliff:g id="NUMBER">%d</xliff:g>회 이상 실패할 경우 SIM이 잠깁니다."</item>
-    <item quantity="other" msgid="7530597808358774740">"<xliff:g id="NUMBER">%d</xliff:g>회 이상 실패할 경우 SIM이 잠깁니다."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 SIM이 잠깁니다.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g>번 더 실패하면 SIM이 잠깁니다.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"발신자 번호"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"설정"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"경로 제공업체 서비스 사용"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"권한을 가진 프로그램이 등록된 경로 제공업체를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV 입력 사용"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"앱이 NFC(근거리 무선 통신) 태그, 카드 및 리더와 통신할 수 있도록 허용합니다."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"화면 잠금 사용 중지"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"앱이 키 잠금 및 관련 비밀번호 보안을 사용중지할 수 있도록 허용합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"지문 하드웨어 관리"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"동기화 사용 및 사용 중지 전환"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"선택기 타겟 서비스 사용"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"권한을 가진 프로그램이 선택기 타겟 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"조건 제공자 서비스 사용"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"권한을 가진 프로그램이 조건 제공자 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"미디어 경로 서비스 사용"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"권한을 가진 프로그램이 미디어 경로 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"드림 서비스에 연결"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"권한을 가진 프로그램이 드림 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"이동통신사에서 제공한 구성 앱 호출"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"이동통신사 메시지 서비스에 고정"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"보유자가 이동통신사 메시지 서비스의 최상위 인터페이스에 고정할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"화면 잠금 비밀번호와 PIN에 허용되는 길이와 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"화면 잠금해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고, 잘못된 비밀번호 입력 횟수가 너무 많은 경우 태블릿을 잠그거나 태블릿에 있는 데이터를 모두 지웁니다."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"화면을 잠금 해제할 때 잘못된 비밀번호를 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많을 때 TV를 잠그거나 TV의 데이터를 모두 삭제합니다."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"화면 잠금해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고, 잘못된 비밀번호 입력 횟수가 너무 많은 경우 휴대전화를 잠그거나 휴대전화에 있는 데이터를 모두 지웁니다."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"화면 잠금해제 비밀번호 변경"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"화면 잠금해제 비밀번호를 변경합니다."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 태블릿을 잠그거나 이 사용자의 데이터를 모두 삭제합니다."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 TV를 잠그거나 이 사용자의 데이터를 모두 삭제합니다."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 휴대전화를 잠그거나 이 사용자의 데이터를 모두 삭제합니다."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"화면 잠금 변경"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"화면 잠금을 변경합니다."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"화면 잠금"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"화면을 잠그는 방법과 시기를 제어합니다."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"모든 데이터 삭제"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"초기화를 수행하여 경고 없이 태블릿 데이터를 지웁니다."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"초기화를 수행해서 TV의 데이터를 경고 없이 삭제합니다."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"초기화를 수행하여 경고 없이 휴대전화 데이터를 지웁니다."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"사용자 데이터 삭제"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"이 태블릿에서 사용자의 데이터를 경고 없이 삭제합니다."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"이 TV에서 사용자의 데이터를 경고 없이 삭제합니다."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"이 휴대전화에서 사용자의 데이터를 경고 없이 삭제합니다."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"화면 잠금 비밀번호 만료 설정"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"화면 잠금 비밀번호 변경 빈도를 설정합니다."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 기기 소유자만 전체 프록시를 설정할 수 있습니다."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"화면 잠금 비밀번호 만료 설정"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"화면 잠금 비밀번호, PIN 또는 패턴의 변경 빈도를 변경합니다."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"카메라 사용 안함"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"모든 기기 카메라의 사용 차단"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"키가드에서 기능 사용중지"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"키가드에서 일부 기능의 사용을 차단합니다."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"화면 잠금 기능 사용 중지"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"일부 화면 잠금 기능의 사용을 차단합니다."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"집"</item>
     <item msgid="869923650527136615">"모바일"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>을(를) 사용하려면 \'터치하여 탐색\' 기능을 사용하도록 설정해야 합니다. \'터치하여 탐색\'을 사용하도록 설정하면, 화면을 터치하여 손가락 아래에 표시된 항목에 대한 설명을 듣고 보거나 휴대전화로 상호작용하기 위한 동작을 수행할 수 있습니다."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"한 달 전"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"한 달 전"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1초 전"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1분 전"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1시간 전"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"지난 <xliff:g id="COUNT">%d</xliff:g>일"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">지난 <xliff:g id="COUNT_1">%d</xliff:g>일</item>
+      <item quantity="one">지난 <xliff:g id="COUNT_0">%d</xliff:g>일</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"지난 달"</string>
     <string name="older" msgid="5211975022815554840">"이전"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"어제"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1초 내"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1분 후"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1시간 후"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"내일"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1초 전"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1분 전"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1시간 전"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"어제"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1초 후"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1분 후"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1시간 후"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"내일"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>년"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"주"</string>
     <string name="year" msgid="4001118221013892076">"년"</string>
     <string name="years" msgid="6881577717993213522">"년"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1초"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g>초"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1분"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g>분"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1시간"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g>시간"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>초</item>
+      <item quantity="one">1초</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>분</item>
+      <item quantity="one">1분</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>시간</item>
+      <item quantity="one">1시간</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"영상 문제"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"이 기기로 스트리밍하기에 적합하지 않은 동영상입니다."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"동영상을 재생할 수 없습니다."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android가 시작되는 중…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"저장소 최적화 중"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"앱 <xliff:g id="NUMBER_1">%2$d</xliff:g>개 중 <xliff:g id="NUMBER_0">%1$d</xliff:g>개 최적화 중"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> 준비 중..."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"앱을 시작하는 중입니다."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"부팅 완료"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"새 앱을 시작하지 마세요."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> 시작"</string>
     <string name="new_app_description" msgid="1932143598371537340">"저장하지 않고 이전 앱을 중단합니다."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"텍스트에 대한 작업 선택"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"벨소리 볼륨"</string>
     <string name="volume_music" msgid="5421651157138628171">"미디어 볼륨"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"없음"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"벨소리"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"알 수 없는 벨소리"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi 네트워크 사용 가능"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi 네트워크 사용 가능"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"개방형 Wi-Fi 네트워크 사용 가능"</item>
-    <item quantity="other" msgid="7915895323644292768">"개방형 Wi-Fi 네트워크 사용 가능"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi 네트워크 사용 가능</item>
+      <item quantity="one">Wi-Fi 네트워크 사용 가능</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">개방형 Wi-Fi 네트워크 사용 가능</item>
+      <item quantity="one">개방형 Wi-Fi 네트워크 사용 가능</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi 네트워크에 로그인"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"네트워크에 로그인"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s 애플리케이션에서 %2$s Wi-Fi 네트워크에 연결하려고 합니다."</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"앱"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct를 시작하지 못했습니다."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"미디어 기기로 연결됨"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"카메라로 연결됨"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI 기기로 연결됨"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"설치 프로그램으로 연결됨"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB 액세서리에 연결됨"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"다른 USB 옵션을 보려면 터치하세요."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"건너뛰기"</string>
     <string name="no_matches" msgid="8129421908915840737">"검색결과 없음"</string>
     <string name="find_on_page" msgid="1946799233822820384">"페이지에서 찾기"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"검색결과 1개"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other">검색결과 <xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">검색결과 1개</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"완료"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB 저장소 마운트 해제 중..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD 카드 마운트 해제 중..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"제한사항 수정을 위한 PIN 생성"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN이 일치하지 않습니다. 다시 시도하세요."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN이 너무 짧습니다. 최소 4자 이상이어야 합니다."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1초 후에 다시 시도하세요."</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g>초 후에 다시 시도하세요."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g>초 후에 다시 시도하세요.</item>
+      <item quantity="one">1초 후에 다시 시도하세요.</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"나중에 다시 시도"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"전체화면을 종료하려면 위에서 아래로 스와이프하세요."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"전체 화면 보기"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"종료하려면 위에서 아래로 스와이프합니다."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"확인"</string>
     <string name="done_label" msgid="2093726099505892398">"완료"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"시간 원형 슬라이더"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"분 원형 슬라이더"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"화면 고정을 해제하려면 \'개요\'를 길게 터치합니다."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"화면이 고정되었습니다. 소속된 조직에서 고정 해제를 허용하지 않습니다."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"화면 고정 해제됨"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"배터리 수명 개선을 위해, 배터리 세이버는 기기의 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기를 충전 중일 때는 자동으로 사용 중지됩니다."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>에 정지가 종료될 때까지"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"다운타임이 끝날 때까지"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1분(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>까지)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d분(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>까지)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1시간(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>까지)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d시간(<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>까지)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1시간 동안"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d시간 동안"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d분 동안(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>까지)</item>
+      <item quantity="one">1분 동안(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>까지)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d시간 동안(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>까지)</item>
+      <item quantity="one">1시간 동안(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>까지)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d분 동안</item>
+      <item quantity="one">1분 동안</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d시간 동안</item>
+      <item quantity="one">1시간 동안</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>까지"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"무제한"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"접기"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"다음 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 알람까지"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"다음 알람까지"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 요청이 DIAL 요청으로 수정됩니다."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 요청이 USSD 요청으로 수정됩니다."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 요청이 새로운 SS 요청으로 수정됩니다."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 주변기기 포트"</string>
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index e160e67..f8a1e48 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -46,9 +46,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Баш аты жок&gt;"</string>
-    <!-- no translation found for ellipsis (7899829516048813237) -->
-    <skip />
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <!-- no translation found for emptyPhoneNumber (7694063042079676517) -->
     <skip />
     <string name="unknownName" msgid="6867811765370350269">"Белгисиз"</string>
@@ -86,10 +83,10 @@
     <!-- no translation found for needPuk2 (4526033371987193070) -->
     <skip />
     <string name="enablePin" msgid="209412020907207950">"Оңунан чыкпады, SIM/RUIM бөгөттөөсүн жандырыңыз."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Сизде SIM бөгөттөлгөнгө чейин <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-    <item quantity="other" msgid="7530597808358774740">"Сизде SIM бөгөттөлгөнгө чейин <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Сизде SIM кулпуланганга чейин <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
+      <item quantity="one">Сизде SIM кулпуланганга чейин <xliff:g id="NUMBER_0">%d</xliff:g> аракет калды.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <!-- no translation found for ClipMmi (6952821216480289285) -->
@@ -308,6 +305,7 @@
     <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
     <skip />
     <string name="global_action_settings" msgid="1756531602592545966">"Жөндөөлөр"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
     <!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
     <skip />
@@ -581,6 +579,8 @@
     <!-- no translation found for permlab_bindRemoteViews (5697987759897367099) -->
     <skip />
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Кармоочуга виджет кызматынын жогорку деңгээлдеги интерфейсине жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"багыт берүүчү кызматка жалгаштыруу"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Кармоочуга катталган багыт берүүчүлөргө жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <!-- no translation found for permlab_bindDeviceAdmin (8704986163711455010) -->
     <skip />
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Кармоочуга түзмөк администраторуна ниетин билдирүү мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
@@ -940,6 +940,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Колдонмого Жакынкы аралыкта байланышуу (NFC) белгилери, карталары жана окугучтары менен байланышуу мүмкүнчүлүгүн берет."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"экранды бөгөттөөнү өчүрүү"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Колдонмого экрандын бөгөттөөчү жана ага байланыштуу сырсөз коргоосун өчүрүү уруксатын берет. Мисалы, чалуу келгенде экрандын бөгөтүн алып салат, чалуу бүткөндө кайрадан орнотот."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"манжа изинин аппараттык камсыздоосун башкаруу"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Колдонмого пайдалануу үчүн манжа изинин үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"манжа изинин аппараттык камсыздоосун колдонуу"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Колдонмого аныктыгын текшерүү үчүн манжа изинин аппараттык камсыздоосун пайдалануу мүмкүндүгүн берет"</string>
     <!-- no translation found for permlab_readSyncSettings (6201810008230503052) -->
     <skip />
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string>
@@ -1003,8 +1007,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Колдонмого (башка колдонмолор жайгаштырган дагы) эскертүүлөрдү алуу, изилдөө, жана аларды тазалоо мүмкүнчүлүгүн берет."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"эскертүү тыңшагыч кызматына байланыштыруу"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ээсине эскертүү тыңшагыч кызматтын жогорку деңгээл интерфейсине туташуу мүмкүнчүлүгүн берет. Жөнөкөй колдонмолордо эч качан керектелбейт."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"тандоочунун каалоосу кызматына туташуу"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Кармоочуга тандоочунун каалоосу кызматынын жогорку деңгээл интерфейсин жалгаштырууга мүмкүндүк берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"шарт түзүүчү кызматына жалгаштыруу"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Кармоочуга шарт түзүүчү кызматтын жогорку деңгээлдеги интерфейсине жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа жол кызматына жалгаштыруу"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Кармоочуга медиа жол кызматынын жогорку деңгээл интерфейсин жалгаштырууга мүмкүндүк берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"dream кызматына жалгаштыруу"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Кармоочуга dream кызматынын жогорку деңгээлдеги интерфейсине жалгашуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"оператордун конфигурациялык колдонмосун чакыруу"</string>
@@ -1023,15 +1031,17 @@
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Кармоочуга оператордун билдирүү кызматынын жогорку деңгээлдеги интерфейсине байланышуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбашы мүмкүн."</string>
     <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
     <skip />
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Экранды бөгөттөн чыгаруу сырсөзүнүн узундугун жана уруксат берилген белгилерди башкаруу."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран кулпусунун сырсөздөрү менен PIN\'дерине уруксат берилген узундук менен белгилерди көзөмөлдөө."</string>
     <!-- no translation found for policylab_watchLogin (914130646942199503) -->
     <skip />
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Экрандын кулпусу ачылып жатканда туура эмес терилген сырсөздөрдүн санын текшерип, эгер алардын саны өтө эле көп болсо, планшетти кулпулаңыз же планшеттеги бардык дайындарды тазалап салыңыз."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, сыналгыны кулпулап же бардык сыналгы дайындарын тазалап салуу."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Экрандын кулпусу ачылып жатканда туура эмес терилген сырсөздөрдүн санын текшерип, эгер алардын саны өтө эле көп болсо, телефонду кулпулаңыз же телефондогу бардык дайындарды тазалап салыңыз."</string>
-    <!-- no translation found for policylab_resetPassword (2620077191242688955) -->
-    <skip />
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Экранды бөгөттөн чыгаруу сырсөзүн алмаштыруу."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, планшетти кулпулап же бул колдонуучунун бардык дайындарын тазалап салуу."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, сыналгыны кулпулап же бул колдонуучунун бардык дайындарын тазалап салуу."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Экрандын кулпусун ачуу учурунда туура эмес терилген сырсөздөрдү тескөө жана сырсөз өтө көп жолу туура эмес терилген болсо, телефонду кулпулап же бул колдонуучунун бардык дайындарын тазалап салуу."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Экран кулпусун өзгөртүү"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Экран кулпусун өзгөртүү."</string>
     <!-- no translation found for policylab_forceLock (2274085384704248431) -->
     <skip />
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Экран качан жана кантип бөгөттөлөөрүн башкаруу."</string>
@@ -1040,21 +1050,23 @@
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Баштапкы абалга кайтарууну колдонуп, планшеттин бардык берилиштерин эскертүүсүз тазалоо."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Сыналгынын дайындарын баштапкы абалга кайтарып, алдын-ала эскертпестен өчүрүп салуу."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Баштапкы абалга кайтарууну колдонуп, телефондун бардык берилиштерин эскертүүсүз тазалоо."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Колдонуучунун дайындарын тазалоо"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Бул колдонуучунун ушул планшеттеги дайындарын эскертүүсүз тазалоо."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Бул колдонуучунун ушул сыналгыдагы дайындарын эскертүүсүз тазалоо."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Бул колдонуучунун ушул телефондогу дайындарын эскертүүсүз тазалоо."</string>
     <!-- no translation found for policylab_setGlobalProxy (2784828293747791446) -->
     <skip />
-    <!-- no translation found for policydesc_setGlobalProxy (6387497466660154931) -->
-    <skip />
-    <!-- no translation found for policylab_expirePassword (885279151847254056) -->
-    <skip />
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Бөгөттөөчү көшөгөнүн сырсөзүнүн алмаштырылыш тартибин башкаруу."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Саясат иштетилгенде түзмөктүн глобалдык проксиси колдонулгудай кылып коюңуз. Түзмөк ээси гана глобалдык проксини коё алат."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Экран кулпснн сырсөзнн мөөнөтү"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Экран кулпусунун сырсөзү, PIN же үлгүсү канча убакыт аралыгында өзгөртүлүшү керектигин өзгөртүү."</string>
     <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
     <skip />
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Колдонмонун сакталган берилиштери шифрленишин талап кылуу."</string>
     <!-- no translation found for policylab_disableCamera (6395301023152297826) -->
     <skip />
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Түзмөктүн бардык камераларын колдонууга тыюу салуу."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Тергич бөгөттөөсүнүн мүмкүнчүлүктөрүн өчүрүү"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Тергич бөгөттөөсүнүн кээ бир мүмкүнчүлүктөрүн колдонууга тыюу салуу."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Экран кулпснн өзгчлктрн өчүрүү"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Экран кулпусунун айрым өзгөчөлүктөрүн колдонуунун алдын алуу."</string>
     <!-- no translation found for phoneTypes:0 (8901098336658710359) -->
     <!-- no translation found for phoneTypes:1 (869923650527136615) -->
     <!-- no translation found for phoneTypes:2 (7897544654242874543) -->
@@ -1472,43 +1484,14 @@
     <skip />
     <!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
     <skip />
-    <!-- no translation found for num_seconds_ago:one (4869870056547896011) -->
-    <!-- no translation found for num_seconds_ago:other (3903706804349556379) -->
-    <!-- no translation found for num_minutes_ago:one (3306787433088810191) -->
-    <!-- no translation found for num_minutes_ago:other (2176942008915455116) -->
-    <!-- no translation found for num_hours_ago:one (9150797944610821849) -->
-    <!-- no translation found for num_hours_ago:other (2467273239587587569) -->
-    <!-- no translation found for last_num_days:other (3069992808164318268) -->
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Акыркы <xliff:g id="COUNT_1">%d</xliff:g> күн</item>
+      <item quantity="one">Акыркы <xliff:g id="COUNT_0">%d</xliff:g> күн</item>
+    </plurals>
     <!-- no translation found for last_month (3959346739979055432) -->
     <skip />
     <!-- no translation found for older (5211975022815554840) -->
     <skip />
-    <!-- no translation found for num_days_ago:one (861358534398115820) -->
-    <!-- no translation found for num_days_ago:other (2479586466153314633) -->
-    <!-- no translation found for in_num_seconds:one (2729745560954905102) -->
-    <!-- no translation found for in_num_seconds:other (1241926116443974687) -->
-    <!-- no translation found for in_num_minutes:one (8793095251325200395) -->
-    <!-- no translation found for in_num_minutes:other (3330713936399448749) -->
-    <!-- no translation found for in_num_hours:one (7164353342477769999) -->
-    <!-- no translation found for in_num_hours:other (547290677353727389) -->
-    <!-- no translation found for in_num_days:one (5413088743009839518) -->
-    <!-- no translation found for in_num_days:other (5109449375100953247) -->
-    <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
-    <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
-    <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
-    <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
-    <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
-    <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
-    <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
-    <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
-    <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
-    <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
-    <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
-    <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
-    <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
-    <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
-    <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
-    <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
     <!-- no translation found for preposition_for_date (9093949757757445117) -->
     <skip />
     <!-- no translation found for preposition_for_time (5506831244263083793) -->
@@ -1539,18 +1522,18 @@
     <skip />
     <!-- no translation found for years (6881577717993213522) -->
     <skip />
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунда"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 мүнөт"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> мүнөт"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 саат"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> саат"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="one">1 секунд</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> мүнөт</item>
+      <item quantity="one">1 мүнөт</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> саат</item>
+      <item quantity="one">1 саат</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Видео маселеси"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Бул видеону ушул түзмөктө агылтып көрсөтүү мүмкүн эмес."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Бул видеону ойнотуу мүмкүн эмес."</string>
@@ -1660,6 +1643,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android жүргүзүлүүдө…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Сактагыч ыңгайлаштырылууда."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колдонмо ыңгайлаштырылууда."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> даярдалууда."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Колдонмолорду иштетип баштоо"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Жүктөө аякталууда."</string>
     <!-- no translation found for heavy_weight_notification (9087063985776626166) -->
@@ -1673,6 +1657,14 @@
     <!-- no translation found for new_app_action (5472756926945440706) -->
     <skip />
     <string name="new_app_description" msgid="1932143598371537340">"Эски колдонмону сактабастан токтотуу."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Текст үчүн аракет тандаңыз"</string>
     <!-- no translation found for volume_ringtone (6885421406845734650) -->
     <skip />
@@ -1705,16 +1697,23 @@
     <skip />
     <!-- no translation found for ringtone_unknown (5477919988701784788) -->
     <skip />
-    <!-- no translation found for wifi_available:one (6654123987418168693) -->
-    <!-- no translation found for wifi_available:other (4192424489168397386) -->
-    <!-- no translation found for wifi_available_detailed:one (1634101450343277345) -->
-    <!-- no translation found for wifi_available_detailed:other (7915895323644292768) -->
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi тармагы жеткиликтүү</item>
+      <item quantity="one">Wi-Fi тармагы жеткиликтүү</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Ачык Wi-Fi тармагы жеткиликтүү</item>
+      <item quantity="one">Ачык Wi-Fi тармагы жеткиликтүү</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi түйүнүнө кирүү"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"түйүнгө кирүү"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" хотспотунун интернет байланышы начар."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s колдонмосу %2$s Wifi тармагына туташкысы келет"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Колдонмо"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Дайректи иштетүү. Бул Wi-Fi клиентти/хотспотту өчүрөт."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Дайрект иштетилбеди."</string>
@@ -1801,6 +1800,7 @@
     <skip />
     <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
     <skip />
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI түзмөк катары туташкан"</string>
     <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
     <skip />
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB аксессуарга байланышты"</string>
@@ -1971,8 +1971,10 @@
     <skip />
     <!-- no translation found for find_on_page (1946799233822820384) -->
     <skip />
-    <!-- no translation found for matches_found:one (8167147081136579439) -->
-    <!-- no translation found for matches_found:other (4641872797067609177) -->
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> ичинен <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="one">1 дал келүү</item>
+    </plurals>
     <!-- no translation found for action_mode_done (7217581640461922289) -->
     <skip />
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB сактагыч чыгарылууда…"</string>
@@ -2294,12 +2296,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Чектөөлөрдү өзгөртүү үчүн PIN түзүңүз"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINдер туура келген жок. Кайталаңыз."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN өтө кыска. Аз дегенде 4 сандан турушу керек."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 секундадан кийин кайталаңыз"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> секундадан кийин кайталаңыз"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунддан кийин кайталаңыз</item>
+      <item quantity="one">1 секунддан кийин кайталаңыз</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Кийинчерээк кайталаңыз"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Толук экран абалынан чыгуу үчүн жогорудан төмөн сүрүңүз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Толук экранды көрүүдө"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Чыгуу үчүн, жогурдан төмөн сүрүңүз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Түшүндүм"</string>
     <string name="done_label" msgid="2093726099505892398">"Даяр"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Саат жебеси"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Мүнөт жебеси"</string>
@@ -2314,7 +2318,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Бул экранды бошотуу үчүн Артка жана Көз жүгүртүүнү чогуу басып, кармап туруңуз."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Бул экранды бошотуу үчүн Көз жүгүртүүнү басып, кармап туруңуз."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Экран кадалды. Уюмуңуздун уруксатысыз бошото албайсыз."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Экран бошотулду"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
@@ -2323,24 +2328,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареянын өмүрүн узартуу үчүн, батареяны үнөмдөгүч түзмөгүңүздүн ишинин майнаптуулугун азайтып, дирилдөө, жайгашкан жерди аныктоо кызматтары жана фондук дайындардын көпчүлүгүн чектеп коёт. Электрондук почта, билдирүү жазышуу жана башка шайкештештирүүгө байланыштуу колдонмолор ачылмайынча жаңыртылбай калышы мүмкүн.\n\nБатарея үнөмдөгүч түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Иштебей турган абал <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> аяктамайынча"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Аракетсиз убакытыңыз бүткүчө"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Бир мүнөткө (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> чейин)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d мүнөткө (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> чейин)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Бир саатка (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> чейин)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d саатка (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> чейин)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Бир мүнөткө"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d мүнөткө"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Бир саатка"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d саатка"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d мүнөткө (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> чейин)</item>
+      <item quantity="one">Бир мүнөткө (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> чейин)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d саатка (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> чейин)</item>
+      <item quantity="one">Бир саатка (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> чейин)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d мүнөткө</item>
+      <item quantity="one">Бир мүнөткө</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d саатка</item>
+      <item quantity="one">Бир саатка</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Белгисиз"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Бул өчүрүлгөнгө чейин"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Жыйнап коюу"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Саат <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> боло турган кийинки айгайга чейин"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Кийинки айгайга чейин"</string>
@@ -2353,4 +2358,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS сурамы DIAL сурамына өзгөртүлдү."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS сурамы USSD сурамына өзгөртүлдү."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS сурамы жаңы SS сурамына өзгөртүлдү."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Сырткы оюкча"</string>
 </resources>
diff --git a/core/res/res/values-land/dimens_material.xml b/core/res/res/values-land/dimens_material.xml
index 77719a6..379ccf6 100644
--- a/core/res/res/values-land/dimens_material.xml
+++ b/core/res/res/values-land/dimens_material.xml
@@ -24,4 +24,28 @@
     <!-- Default text size for action bar subtitle.-->
     <dimen name="text_size_subtitle_material_toolbar">12dp</dimen>
 
+    <!-- Floating window margins are small until we hit sw380dp-land. -->
+    <dimen name="floating_window_margin_left">16dp</dimen>
+    <dimen name="floating_window_margin_top">4dp</dimen>
+    <dimen name="floating_window_margin_right">16dp</dimen>
+    <dimen name="floating_window_margin_bottom">16dp</dimen>
+
+    <!-- Material time picker dimensions. -->
+    <!-- Text size for the time picker header HH:MM label. This value is large
+         enough that we don't need to use scaled pixels, dp is fine. -->
+    <dimen name="timepicker_time_label_size">48dp</dimen>
+    <dimen name="timepicker_ampm_label_size">16sp</dimen>
+    <dimen name="timepicker_am_top_padding">8dp</dimen>
+    <dimen name="timepicker_pm_top_padding">3dp</dimen>
+    <!-- Radial picker is small until we hit sw380dp-land. -->
+    <dimen name="timepicker_radial_picker_dimen">180dp</dimen>
+    <dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
+    <dimen name="timepicker_radial_picker_horizontal_margin">24dp</dimen>
+
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_text_inset_normal">22dp</dimen>
+    <!-- Landscape inset is small until we hit sw380dp-land. -->
+    <dimen name="timepicker_text_inset_inner">46dp</dimen>
+    <dimen name="timepicker_text_size_normal">14sp</dimen>
+    <dimen name="timepicker_text_size_inner">12sp</dimen>
 </resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index c866e3b..70d8c65 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ວິ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ວິ"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ບໍ່ມີຊື່&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ບໍ່ມີເບີໂທລະສັບ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"​ບໍ່​ຮູ້​ຈັກ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ຂໍ້ຄວາມສຽງ"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ຊິມກາດຂອງທ່ານຖືກລັອກດ້ວຍລະຫັດ PUK. ໃຫ້ພິມລະຫັດ PUK ເພື່ອປົດລັອກມັນ."</string>
     <string name="needPuk2" msgid="4526033371987193070">"ພິມ PUK2 ເພື່ອປົດລັອກ SIM card."</string>
     <string name="enablePin" msgid="209412020907207950">"ບໍ່ສຳເລັດ, ເປີດນໍາໃຊ້ການລັອກຂອງ SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະຖືກລັອກ."</item>
-    <item quantity="other" msgid="7530597808358774740">"ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະຖືກລັອກ."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະຖືກລັອກ.</item>
+      <item quantity="one">ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະຖືກລັອກ.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ໝາຍເລກຜູ່ໂທເຂົ້າ"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"​ການ​ຕັ້ງ​ຄ່າ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ຊ່ວຍ​ເຫຼືອ​ທາງ​ສຽງ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກ​ດຽວ​ນີ້"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ເຊື່ອມ​ໂຍງ​ກັບ​ການ​ບໍ​ລິ​ການ​ຂອງ​ຜູ່​ໃຫ້​ບໍ​ລິ​ການ​ເສັ້ນ​ທາງ"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ອະ​ນຸ​ຍາດ​ໃຫ້​ເຈົ້າ​ຂອງ​ສາ​ມາດ​ເຊື່ອມ​ໂຍງກັບ​ທຸກໆ​ຜູ່​ໃຫ້​ບໍ​ລິ​ການເສັ້ນ​ທາງ​ທີ່​ລົງ​ທະ​ບຽນ. ບໍ່​ຄວນ​ຈະ​ໄດ້​ໃຊ້​ໃນ​ແອັບຯ​ທົ່ວ​ໄປ."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ຜູກ​ກັບ​ການ​ປ້ອນ​ຂໍ້​ມູນ​ເຂົ້າ​ໂທ​ລະ​ທັດ"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ອະນຸຍາດໃຫ້ແອັບຯຕິດຕໍ່ສື່ສານກັບປ້າຍກຳກັບ, ບັດ ແລະໂຕອ່ານຂອງການສື່ສານໄລຍະສັ້ນ (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ປິດການລັອກໜ້າຈໍ"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ອະນຸຍາດໃຫ້ແອັບຯປິດການເຮັດວຽກຂອງປຸ່ມລັອກ ແລະລະບົບຄວາມປອດໄພຂອງລະຫັດຜ່ານທີ່ເຊື່ອມໂຍງກັນ. ໂຕຢ່າງ: ໂທລະສັບຈະປິດການເຮັດວຽກຂອງປຸ່ມລັອກເມື່ອມີສາຍໂທເຂົ້າ ຈາກນັ້ນຈຶ່ງເປີດໃຊ້ໄດ້ອີກເມື່ອວາງສາຍແລ້ວ."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ຈັດ​ການ​ຮາດ​ແວ​ລາຍ​ນີ້ວ​ມື"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ເຮັດ​ໃຫ້​ວິ​ທີ​ການ​ຕ່າງໆ​ເພີ່ມ ແລະ​ລຶບ​ແມ່​ແບບ​ລາຍ​ນີ້ວ​ມື​ສຳ​ລັບ​ການ​ໃຊ້."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ໃຊ້​ຮາດ​ແວ​ລາຍ​ນີ້ວ​ມື"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ນຳ​ໃຊ້​ຮາດ​ແວ​ລາຍ​ນີ້ວ​ມື​ສຳ​ລັບ​ການ​ຮັບ​ຮອງ"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ອ່ານການຕັ້ງຄ່າຊິ້ງຂໍ້ມູນ"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການຕັ້ງຄ່າການຊິ້ງຂໍ້ມູນຂອງບັນຊີໄດ້. ຕົວຢ່າງເຊັ່ນ: ມັນຈະສາມາດກວດສອບໄດ້ແອັບຯ People ຖືກຊິ້ງຂໍ້ມູນກັບບັນຊີໃດນຶ່ງແລ້ວຫຼືຍັງ."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ສະລັບການເປີດ ແລະປິດການຊິ້ງຂໍ້ມູນ"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ຜູກ​ພັນ​ກັບ​ເປົ້າ​ໝາຍ​ການ​ບໍ​ລິ​ການ​ຜູ້​ເລືອກ"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກ​ພັນ​ກັບຕົວ​ປະ​ສານລະດັບສູງສຸດຂອງການບໍລິການເປົ້າ​ໝາຍ​ຜູ້​ເລືອກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ຜູ່​ສະ​ໜອງ​ເງື່ອນ​ໄຂ"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ອະນຸຍາດ​ໃຫ້​ເຈົ້າຂອງ​ເຊື່ອມໂຍງ​ສ່ວນຕິດຕໍ່​ລະດັບ​ສູງສຸດ​ຂອງ​ບໍ​ລິ​ການ​ສະ​ໜອງ​ເງື່ອນ​ໄຂ. ບໍ່ຈຳເປັນ​ສຳລັບ​ແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"​ເຊື່ອມ​ໂຍງ​ກັບ​ບໍ​ລິ​ການ​ເສັ້ນ​ທາງ​ມີ​ເດຍ"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"​ອະ​ນຸ​ຍາດ​ໃຫ້​ຜູ່​ໃຊ້​ເຊື່ອມ​ໂຍງ​ກັບ​ສ່ວນ​ຕິດ​ຕໍ່​ຜູ່​ໃຊ້​ລະ​ດັບ​ສູງ​ສຸດ​ຂອງ​ບໍ​ລິ​ການ​ເສັ້ນ​ທາງ​ມີ​ເດຍ. ແອັບຯ​ທົ່ວ​ໄປ​ບໍ່​ຄວນ​ຕ້ອງໃຊ້."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ຜູກ​ກັບ​ບໍ​ລິ​ການ dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ອະນຸຍາດ​ໃຫ້ຜູ່ຖື​ຜູກກັບ​ສ່ວນຕິດຕໍ່​ລະດັບ​ສູງສຸດ ຂອງ​ບໍລິການ dream. ບໍ່ຈຳເປັນ​ສຳລັບ​ແອັບຯ​ທົ່ວໄປ."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ຜູກ​ພັນ​ກັບ​ການ​ບໍ​ລິ​ການ​ສົ່ງ​ຂໍ້​ຄວາມ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກ​ພັນ​ກັບຕົວ​ປະ​ສານລະດັບສູງສຸດຂອງບໍລິການສົ່ງ​ຂໍ້​ຄວາມ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"ຄວບຄຸມຄວາມຍາວ ແລະຕົວອັກສອນທີ່ອະ​ນຸ​ຍາດ​ໃຫ້​ຢູ່​ໃນລະ​ຫັດລັອກໜ້າຈໍ ແລະ PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ຕິດຕາມເບິ່ງຈຳນວນການພິມລະຫັດຜ່ານທີ່ບໍ່ຖືກຕ້ອງ ໃນເວລາປົດລັອກໜ້າຈໍ ແລະລັອກແທັບເລັດ ຫຼືລຶບຂໍ້ມູນທັງໝົດຂອງແທັບເລັດ ຖ້າມີການພິມລະຫັດຜ່ານບໍ່ຖືກຕ້ອງຫຼາຍເທື່ອເກີນໄປ."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ຕິດ​ຕາມ​ຈຳ​ນວນ​ຂອງ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ທີ່​ພິມ​ໄປ​ແລ້ວ ເມື່ອ​ປົດ​ລັອກ​ໜ້າ​ຈໍ, ແລະ​ລັອກໂທລະພາບຫຼື​ລຶບ​ທຸກ​ຂໍ້​ມູນ​ຂອງໂທລະພາບຖ້າ​ໄດ້​ພິມ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ເຂົ້າ​ໄປ​ຫຼາຍ​ອັນ​ເກີນ​ໄປ."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ຕິດຕາມເບິ່ງຈຳນວນການພິມລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ ໃນເວລາປົດລັອກໜ້າຈໍ ແລະລັອກໂທລະສັບ ຫຼືລຶບຂໍ້ມູນທັງໝົດຂອງໂປລະສັບ ຖ້າມີການພິມລະຫັດຜ່ານບໍ່ຖືກຕ້ອງຫຼາຍເທື່ອເກີນໄປ."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"ປ່ຽນລະຫັດລັອກໜ້າຈໍ"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"ປ່ຽນລະຫັດປົດລັອກໜ້າຈໍ"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ຕິດ​ຕາມ​ຈຳ​ນວນ​ຂອງ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ທີ່​ພິມ​ໄປ​ແລ້ວ ເມື່ອ​ປົດ​ລັອກ​ໜ້າ​ຈໍ, ແລະ​ລັອກແທັບ​ເລັດ ຫຼື​ລຶບ​ທຸກ​ຂໍ້​ມູນຜູ້​ໃຊ້​ນີ້ ຖ້າ​ໄດ້​ພິມ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ເຂົ້າ​ໄປ​ຫຼາຍ​ອັນ​ເກີນ​ໄປ."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ຕິດ​ຕາມ​ຈຳ​ນວນ​ຂອງ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ທີ່​ພິມ​ໄປ​ແລ້ວ ເມື່ອ​ປົດ​ລັອກ​ໜ້າ​ຈໍ, ແລະ​ລັອກໂທລະພາບ ຫຼື​ລຶບ​ທຸກ​ຂໍ້​ມູນຜູ້​ໃຊ້​ນີ້ ຖ້າ​ໄດ້​ພິມ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ເຂົ້າ​ໄປ​ຫຼາຍ​ອັນ​ເກີນ​ໄປ."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ຕິດ​ຕາມ​ຈຳ​ນວນ​ຂອງ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ທີ່​ພິມ​ໄປ​ແລ້ວ ເມື່ອ​ປົດ​ລັອກ​ໜ້າ​ຈໍ, ແລະ​ລັອກໂທລະສັບ ຫຼື​ລຶບ​ທຸກ​ຂໍ້​ມູນຜູ້​ໃຊ້​ນີ້ ຖ້າ​ໄດ້​ພິມ​ລະ​ຫັດ​ຜ່ານ​ບໍ່​ຖືກ​ຕ້ອງ​ເຂົ້າ​ໄປ​ຫຼາຍ​ອັນ​ເກີນ​ໄປ."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"ປ່ຽນ​ລັອກ​ໜ້າ​ຈໍ"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"ປ່ຽນ​ລັອກ​ໜ້າ​ຈໍ."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ລັອກໜ້າຈໍ"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"ຄວບຄຸມວ່າໜ້າຈໍຄວນຈະຖືກລັອກເມື່ອໃດ ແລະແນວໃດ"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ລຶບຂໍ້ມູນທັງໝົດ"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ລຶບຂໍ້ມູນຂອງແທັບເລັດໂດຍບໍ່ມີການເຕືອນ ໂດຍການຣີເຊັດກັບຄືນໃຫ້ເປັນແບບທີ່ມາຈາກໂຮງງານ."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ລຶບ​ຂໍ້​ມູນ​ຂອງໂທລະພາບໂດຍ​ບໍ່​ມີ​ການ​ເຕືອນ ດ້ວຍ​ການ​ເຮັດ​ການ​ຕັ້ງ​ຄ່າ​ຂໍ້​ມູນ​ໂຮງ​ງານ​ຄືນ​ໃໝ່."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ລຶບຂໍ້ມູນຂອງໂທລະສັບໂດຍບໍ່ມີການເຕືອນ ໂດຍການຣີເຊັດກັບຄືນໃຫ້ເປັນແບບທີ່ມາຈາກໂຮງງານ."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ລຶບ​ຂໍ້​ມູນ​ຜູ້​ໃຊ້"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ລຶບ​ຂໍ້​ມູນ​ຂອງ​ຜູ້​ໃຊ້​ນີ້​ຢູ່​ໃນ​ໂທ​ລະ​ທັດ​ນີ້​ໂດຍ​ບໍ່​ມີ​ການ​ເຕືອນ."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ລຶບ​ອຸ​ປະ​ກອນ​ຜູ້​ໃຊ້​ນີ້​ຢູ່​ໃນ​ໂທ​ລະ​ທັດ​ນີ້​ໂດຍ​ບໍ່​ມີ​ການ​ເຕືອນ."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ລຶບ​ຂໍ້​ມູນ​ຂອງ​ຜູ້​ໃຊ້​ນີ້​ຢູ່​ໃນ​ໂທ​ລະ​ສັບ​ນີ້​ໂດຍ​ບໍ່​ມີ​ການ​ເຕືອນ."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ປ່ຽນ proxy ຮວມຂອງອຸປະກອນ"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ຕັ້ງໃຫ້ພຣັອກຊີສ່ວນກາງຂອງອຸປະກອນ ທີ່ຈະໃຊ້ໃນຂະນະທີ່ເປີດນຳໃຊ້ນະໂຍບາຍ. ສະເເພາະຜູ່ເບິ່ງແຍງອຸປະກອນຄົນທຳອິດເທົ່ານັ້ນ ທີ່ຈະຕັ້ງຄ່າພຣັອກຊີສ່ວນກາງທີ່ມີຜົນນຳໃຊ້ໄດ້."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ຕັ້ງວັນໝົດກຳນົດຂອງລະຫັດລັອກໜ້າຈໍ"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ຄວບຄຸມຄວາມຖີ່ໃນການປ່ຽນລະຫັດໜ້າຈໍລັອກ."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ຕັ້ງໃຫ້ພຣັອກຊີສ່ວນກາງຂອງອຸປະກອນ ທີ່ຈະໃຊ້ໃນຂະນະທີ່ເປີດນຳໃຊ້ນະໂຍບາຍ. ພຽງ​ແຕ່​ເຈົ້າ​ຂອງ​ອຸ​ປະ​ກອນ​ເທົ່າ​ນັ້ນ​ສາ​ມາດ​ຕັ້ງ​ພ​ຣັອກ​ຊີ​ທົ່ວ​ໄປ​ໄດ້."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"ຕັ້ງ​ຄ່າ​ການ​ໝົດ​ອາ​ຍຸ​ລະ​ຫັດ​ຜ່ານ​ລັອກ​ໜ້າ​ຈໍ"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"ປ່ຽນ​ວ່າ​ຈະ​ໃຫ້ລະ​ຫັດ​ຜ່ານ​ລັອກ​ໜ້າ​ຈໍ, PIN, ຫຼື​ຮູບ​ແບບ​ຕ້ອງ​ມີ​ການ​ປ່ຽນ​ແປງ​ເລື້ອຍ​ປານ​ໃດ."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ຕັ້ງຄ່າການເຂົ້າລະຫັດທີ່ເກັບຂໍ້ມູນ"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ຮຽກຮ້ອງໃຫ້ມີການເຂົ້າລະຫັດຂໍ້ມູນທີ່ຈັດເກັບໃນແອັບຯ"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ປິດການໃຊ້ກ້ອງ"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"ຫ້າມການໃຊ້ກ້ອງຈາກທຸກອຸປະກອນ."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"ປິດການນຳໃຊ້ການລັອກປຸ່ມ"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"ປ້ອງກັນການໃຊ້ຄວາມສາມາດບາງສ່ວນໃນການລັອກປຸ່ມ."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"ປິດ​ໃຊ້​ງານ​ຄຸນ​ສົມ​ບັດ​ຂອງ​ລັອກ​ໜ້າ​ຈໍ"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"ປ້ອງກັນການໃຊ້ຄຸນ​ສົມ​ບັດບາງສ່ວນຂອງ​ລັອກ​ໜ້າ​ຈໍ."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"ເຮືອນ"</item>
     <item msgid="869923650527136615">"ມືຖື"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ຕ້ອງການເປີດນຳໃຊ້ \"ການສຳຫຼວດໂດຍສຳພັດ\". ເມື່ອເປີດ \"ການສຳຫຼວດໂດຍສຳພັດ\" ແລ້ວ ທ່ານຈະສາມາດໄດ້ຍິນ ຫຼືເຫັນຄຳບັນຍາຍວ່າມີຫຍັງຢູ່ກ້ອງນິ້ວມືຂອງທ່ານ ຫຼືໃຊ້ຮູບແບບການເຄື່ອນໄຫວເພື່ອໂຕ້ຕອບກັບໂທລະສັບ."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ເດືອນກ່ອນຫນ້ານີ້"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ຫຼາຍກວ່າ 1 ເດືອນກ່ອນ"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 ວິນາທີກ່ອນ"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ວິນາທີກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 ນາທີກ່ອນໜ້ານີ້"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ນາ​ທີ​ທີ່ຜ່ານມາ"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງທີ່ຜ່ານມາ"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ມື້ທີ່ຜ່ານມາ"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ວັນ​ສຸດ​ທ້າຍ</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ວັນ​ສຸດ​ທ້າຍ</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"ເດືອນແລ້ວ"</string>
     <string name="older" msgid="5211975022815554840">"ເກົ່າກວ່າ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ມື້​ວານ​ນີ້"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ມື້​ກ່ອນ"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ໃນອີກ 1 ວິນາທີ"</item>
-    <item quantity="other" msgid="1241926116443974687">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິ​ນາ​ທີ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ໃນ 1 ນາທີ"</item>
-    <item quantity="other" msgid="3330713936399448749">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນາທີ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ໃນ 1 ຊົ່ວໂມງ"</item>
-    <item quantity="other" msgid="547290677353727389">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ມື້ອື່ນ"</item>
-    <item quantity="other" msgid="5109449375100953247">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 ວິນາທີກ່ອນ"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ວິ ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 ນທ ກ່ອນ"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> ນທ ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ຊົ່ວໂມງກ່ອນ"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ມື້ວານນີ້"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ມື້ກ່ອນໜ້ານີ້"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ໃນ 1 ວິ"</item>
-    <item quantity="other" msgid="5495880108825805108">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ວິ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ໃນ 1 ນາທີ"</item>
-    <item quantity="other" msgid="4216113292706568726">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ນທ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ໃນ 1 ຊົ່ວໂມງ"</item>
-    <item quantity="other" msgid="3705373766798013406">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ມື້ອື່ນ"</item>
-    <item quantity="other" msgid="2973062968038355991">"ໃນ <xliff:g id="COUNT">%d</xliff:g> ມື້"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ວັນທີ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ໃນ <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"ອາທິດ"</string>
     <string name="year" msgid="4001118221013892076">"ປີ"</string>
     <string name="years" msgid="6881577717993213522">"ປິ"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 ວິນາທີ"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> ວິນາທີ"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 ນາ​ທີ"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> ນາທີ"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ຊົ່ວ​ໂມງ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ວິ​ນາ​ທີ</item>
+      <item quantity="one">1ວິ​ນາ​ທີ</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ນາທີ</item>
+      <item quantity="one">1 ນາທີ</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ຊົ່ວໂມງ</item>
+      <item quantity="one">1 ຊົ່ວໂມງ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ບັນຫາວິດີໂອ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ວິດີໂອນີ້ບໍ່ຖືກຕ້ອງສຳລັບການສະແດງໃນອຸປະກອນນີ້."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ບໍ່ສາມາດຫຼິ້ນວິດີໂອນີ້ໄດ້."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"ກຳ​ລັງ​ເລີ່ມລະ​ບົບ​ Android …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ການ​ປັບ​ບ່ອນ​ເກັບ​ຂໍ້​ມູນ​ໃຫ້​ເໝາະ​ສົມ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ກຳລັງ​ປັບປຸງ​ປະສິດທິພາບ​ແອັບຯ​ທີ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຈາກ​ທັງ​ໝົດ <xliff:g id="NUMBER_1">%2$d</xliff:g> ແອັບຯ."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"ກຳ​ລັງ​ກຽມ <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ກຳລັງເປີດແອັບຯ."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ກຳລັງສຳເລັດການເປີດລະບົບ."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກ"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"ຫ້າມເປີດແອັບຯໃໝ່."</string>
     <string name="new_app_action" msgid="5472756926945440706">"ເລີ່ມຕົ້ນ <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"ຢຸດແອັບຯເກົ່າໂດຍບໍ່ຕ້ອງບັນທຶກ."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"ເລືອກການເຮັດວຽກຂອງຂໍ້ຄວາມ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ລະດັບສຽງເອີ້ນເຂົ້າ"</string>
     <string name="volume_music" msgid="5421651157138628171">"ລະດັບສຽງຂອງສື່"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ບໍ່ມີ"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ຣິງໂທນ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ຣິງໂທນທີ່ບໍ່ຮູ້ຈັກ"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"ເຄືອຂ່າຍ Wi-Fi ທີ່ພົບ"</item>
-    <item quantity="other" msgid="4192424489168397386">"ມີເຄືອຂ່າຍ Wi​-Fi ໃຫ້ໃຊ້"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"ເປີດ Wi-Fi ເຄືອຂ່າຍທີ່ມີ"</item>
-    <item quantity="other" msgid="7915895323644292768">"ເຄືອຂ່າຍ Wi-Fi ແບບເປີດທີ່ພົບ"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+      <item quantity="one">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
+      <item quantity="one">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ມີສັນຍານອິນເຕີເນັດທີ່ບໍ່ດີ."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ %1$s ຢາກ​ຈະ​ເຊື່ອມ​ຕໍ່​ກັບ​ເຄືອ​ຂ່າຍ Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"​ແອັບ​ພລິ​ເຄ​ຊັນ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ເລີ່ມ Wi-Fi Direct. ນີ້ຈະເປັນການປິດ Wi-Fi client/hotspot."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ບໍ່ສາມາດເລີ່ມ Wi-Fi Direct ໄດ້."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ຕົກລົງ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"ເຊື່ອມຕໍ່ເປັນອຸປະກອນສື່"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"ເຊື່ອມຕໍ່ເປັນກ້ອງຖ່າຍຮູບແລ້ວ"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"​ເຊື່ອມ​ຕໍ່​ເປັນ​ອຸ​ປະ​ກອນ​ MIDI ແລ້ວ"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ເຊື່ອມຕໍ່ໃນນາມຕົວຕິດຕັ້ງ"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ເຊື່ອມຕໍ່ກັບອຸປະກອນເສີມ USB ແລ້ວ"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"ແຕະເພື່ອເບິ່ງໂຕເລືອກເລືອກ USB ອື່ນໆ."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ຂ້າມ"</string>
     <string name="no_matches" msgid="8129421908915840737">"ບໍ່ພົບຜົນການຊອກຫາ"</string>
     <string name="find_on_page" msgid="1946799233822820384">"ຊອກໃນໜ້າ"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 ກົງກັນ"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ຈາກທັງໝົດ <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> ໃນ <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 ກົງກັນ</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"ແລ້ວໆ"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"ກຳລັງຖອນການເຊື່ອມຕໍ່ບ່ອນຈັດເກັບຂໍ້ມູນ USB …"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"ຖອນການເຊື່ອມຕໍ່ SD card..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາ​ລັບ​ການ​ປັບ​ປຸງ​ຂໍ້ຈໍາ​ກັດ​"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN ບໍ່​ກົງກັນ. ລອງໃໝ່ອີກຄັ້ງ​."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ​ສັ້ນ​ເກີນ​ໄປ​. ຕ້ອງມີຢ່າງໜ້ອຍ 4 ຫຼັກ​."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"ລອງໃໝ່ໃນອີກ 1 ວິນາທີ"</item>
-    <item quantity="other" msgid="4730868920742952817">"ລອງໃໝ່ໃນອີກ <xliff:g id="COUNT">%d</xliff:g> ວິນາທີ"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">ລອງໃໝ່ໃນອີກ <xliff:g id="COUNT">%d</xliff:g> ລອງໃໝ່ໃນອີກ 1 ວິນາທີ</item>
+      <item quantity="one">ລອງໃໝ່ໃນອີກ 1 ວິນາທີ</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ລອງໃໝ່ອີກຄັ້ງໃນພາຍຫລັງ."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"ປັດລົງມາຈາກທາງເທິງເພື່ອອອກຈາກໂໝດເຕັມໜ້າຈໍ."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"ການ​ເບິ່ງ​ເຕັມ​ໜ້າ​ຈໍ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ເພື່ອ​ອອກ, ຮູດ​ລົງ​ລຸ່ມ​ຈາກ​ດ້ານ​ເທິງ."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ໄດ້​ແລ້ວ"</string>
     <string name="done_label" msgid="2093726099505892398">"ແລ້ວໆ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ໂຕໝຸນປັບຊົ່ວໂມງ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ໂຕໝຸນປັບນາທີ"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"​ບ່ອນ​ເຮັດ​ວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ເພື່ອ​ຖອດ​ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ນີ້, ສຳ​ຜັດປຸ່ມ ​ກັບ​ຄືນ ແລະ ພາບ​ຮວມ ຄ້າງ​ໄວ້​ພ້ອມ​ກັນ."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ເພື່ອ​ຖອດ​ການ​ປັກ​ໝຸດໜ້າ​ຈໍ​ນີ້, ສຳ​ຜັດ​ປຸ່ມ ພາບ​ຮວມ ຄ້າງ​ໄວ້."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ໜ້າ​ຈໍ​ຖືກ​ປັກ​ໝຸດ​ໄວ້. ​ອົງ​ກອນ​ຂອງ​ທ່ານບໍ່​​ອະ​ນຸ​ຍາດ​ໃຫ້​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ​ໄດ້."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ຍົກ​ເລີກ​ການ​ປັກ​ໝຸນ​​ຫນ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ເພື່ອ​ຊ່ວຍ​ເພີ່ມ​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ, ຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີ​ຫຼຸດ​ປະ​ສິດ​ທິ​ພາບ​ການ​ເຮັດ​ວຽກ​ຂອງ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ລົງ ແລະ​ຈຳ​ກັດ​ການ​ສັ່ນ, ການ​ບໍ​ລິ​ການ​ຫາທີ່ຕັ້ງ, ແລະ​ຂໍ້​ມູນ​ພື້ນ​ຫຼັງ​ເກືອບ​ທັງ​ໝົດ. ອີ​ເມວ, ການ​ສົ່ງ​ຂໍ້​ຄວາມ, ແລະ​ແອັບອື່ນໆ​ທີ່ອາ​ໄສການ​ຊິງ​ຄ໌​ອາດ​ຈະ​ບໍ່​ອັບ​ເດດ ນອກ​ຈາກວ່າ​ທ່ານ​ເປີດ​ມັນ.\n\nຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີຈະ​ປິດ​ອັດ​ຕະ​ໂນ​ມັດ ເມື່ອ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ກຳ​ລັງ​ສາກຢູ່."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ຈົນ​ກວ່າ​ດາວ​ທາມ​ຂອງ​ທ່ານ​ຈະ​ສິ້ນ​ສຸດ​ທີ່ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"​ຈົນ​ກວ່າ​ເວ​ລາ​ປິດ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ​ສິ້ນ​ສຸດ​ລົງ"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"​ເປັນ​ເວ​ລາ 1 ນາ​ທີ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"​ເປັນ​ເວ​ລາ %1$d ​ນາ​ທີ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"​ເປັນ​ເວ​ລາ 1 ຊົ່ວ​ໂມງ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"​ເປັນ​ເວ​ລາ %1$d ​ຊົ່ວ​ໂມງ (​ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ເປັນ​ເວລາ​ນຶ່ງ​ນາ​ທີ"</item>
-    <item quantity="other" msgid="6924190729213550991">"ເປັນ​ເວລາ %d ນາ​ທີ"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ເປັນ​ເວລາ​ນຶ່ງ​ຊົ່ວ​ໂມງ"</item>
-    <item quantity="other" msgid="5408537517529822157">"ເປັນ​ເວລາ %d ຊົ່ວ​ໂມງ"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">ເປັນ​ເວ​ລາ %1$d ນາ​ທີ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">​ເປັນ​ເວ​ລາ 1 ນາ​ທີ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">ເປັນ​ເວ​ລາ %1$d ຊົ່ວ​ໂມງ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">ເປັນ​ເວ​ລາ 1 ຊົ່ວ​ໂມງ (ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">ເປັນ​ເວ​ລາ %d ນາ​ທີ</item>
+      <item quantity="one">ເປັນ​ເວລາໜຶ່ງ​ນາ​ທີ</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">ເປັນ​ເວລາ​ %d ຊົ່ວ​ໂມງ</item>
+      <item quantity="one">ເປັນ​ເວລາໜຶ່ງ​ຊົ່ວ​ໂມງ</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"ຢ່າງ​ບໍ່​ມີ​ກຳນົດ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າ​ທ່ານ​ຈະ​ປິດ​"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ຫຍໍ້"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"​ຈົນ​ກວ່າ​ໂມງ​ປຸກ​ຄັ້ງ​ຕໍ່​ໄປ​ໃນ​ເວ​ລາ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"​ຈົນ​ກວ່າ​ໂມງ​ປຸກ​ຄັ້ງຕໍ່​ໄປ"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ DIAL ແລ້ວ."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ USSD ແລ້ວ."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"ການ​ຂໍ SS ຖືກ​ດັດ​ແປງ​ເປັນ​ການ​ຂໍ SS ໃໝ່​ແລ້ວ."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"ຊ່ອງ​ຮອບນອກ USB"</string>
 </resources>
diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
index 8a50344..ba4a326 100755
--- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml
+++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y m. %B %-e d.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %Y-%m-%d</string>
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
index b2368dc..cdca7b6 100755
--- a/core/res/res/values-lt/donottranslate-cldr.xml
+++ b/core/res/res/values-lt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y m. %B %-e d.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y.%m.%d</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8f4a82f..6eda58a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Be pavadinimo&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nėra telefono numerio)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Nežinoma"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Balso paštas"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"Jūsų SIM kortelė yra užrakinta PUK kodu. Jei norite ją atrakinti, įveskite PUK kodą."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Įveskite PUK2 kodą, kad panaikintumėte SIM kortelės blokavimą."</string>
     <string name="enablePin" msgid="209412020907207950">"Nepavyko. Įgalinti SIM / RUIM užraktą."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Liko <xliff:g id="NUMBER">%d</xliff:g> band. Paskui SIM kortelė bus užrakinta."</item>
-    <item quantity="other" msgid="7530597808358774740">"Liko <xliff:g id="NUMBER">%d</xliff:g> band. Paskui SIM kortelė bus užrakinta."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas. Tada SIM kortelė bus užrakinta.</item>
+      <item quantity="few">Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymai. Tada SIM kortelė bus užrakinta.</item>
+      <item quantity="many">Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymo. Tada SIM kortelė bus užrakinta.</item>
+      <item quantity="other">Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymų. Tada SIM kortelė bus užrakinta.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Įeinančio skambintojo ID"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ĮJUNGTAS lėktuvo režimas"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"lėktuvo režimas IŠJUNGTAS"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nustatymai"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
@@ -431,6 +432,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"susisaistyti su maršruto parinkimo paslauga"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Savininkui leidžiama susisaistyti su bet kokiomis registruotomis maršrutų parinkimo paslaugomis. To niekada neturėtų prireikti naudojant įprastas programas."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"susisaistyti su TV įvestimi"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Leidžiama programai perduoti artimojo lauko ryšių technologijos (ALR) žymas, korteles ir skaitymo programas."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"išjungti ekrano užraktą"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Leidžiama programai neleisti klavišo užrakto ir visos susijusios slaptažodžio apsaugos. Pvz., telefonas neleidžia klavišo užrakto priimant gaunamąjį skambutį ir pakartotinai jį įgalina, kai skambutis baigiamas."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"tvarkyti kontrolinio kodo aparatinę įrangą"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Leidžiama programai aktyvinti metodus, norint pridėti ir ištrinti naudojamus kontrolinių kodų šablonus."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"naudoti kontrolinio kodo aparatinę įrangą"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Leidžiama programai naudoti kontrolinio kodo aparatinę įrangą tapatybei nustatyti"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"skaityti sinchronizavimo nustatymus"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Leidžiama programai skaityti ir sinchronizuoti paskyros nustatymus. Pvz., taip gali būti nustatoma, ar su paskyra sinchronizuota Žmonių programa."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"įjungti arba išjungti sinchronizavimą"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"susaistyti programą su tikslo pasirinkimo paslauga"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Savininkui leidžiama susaistyti programą su tikslo pasirinkimo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"susaistyti su sąlygos teikėjo paslauga"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Turėtojui leidžiama susaistyti programą su sąlygos teikėjo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"susaistyti su medijos maršruto paslauga"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Leidžiama savininką susaistyti su aukščiausio lygio medijos maršruto paslaugos sąsaja. Niekada neturėtų būti reikalinga įprastoms programoms."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"susisaistyti su mėgstama paslauga"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Savininkui leidžiama susisaistyti su mėgstamos paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"iškviesti operatoriaus pateiktą konfigūravimo programą"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"susaistyti su operatoriaus susirašinėjimo žinutėmis paslauga"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Leidžiama savininkui susisaistyti su aukščiausio lygio operatoriaus susirašinėjimo žinutėmis paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Valdykite, kokio ilgio ekrano užrakto slaptažodžius ir PIN kodus galima naudoti."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Stebimas neteisingai įvestų slaptažodžių skaičius atrakinant ekraną ir užrakinti planšetinį kompiuterį arba ištrinti visus jame esančius duomenis, jei įvedama per daug neteisingų slaptažodžių."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Stebėti atrakinant ekraną įvestų netinkamų slaptažodžių skaičių ir užrakinti TV arba ištrinti visus TV duomenis, jei per daug kartų įvedamas netinkamas slaptažodis."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Atrakindami ekraną stebėkite neteisingai įvestų slaptažodžių skaičių ir užrakinkite telefoną ar ištrinkite visus telefono duomenis, jei įvedama per daug neteisingų slaptažodžių."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Pakeisti ekrano užrakinimo slaptažodį"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Pakeisti ekrano atrakinimo slaptažodį."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Stebėkite atrakinant ekraną įvestų netinkamų slaptažodžių skaičių ir užrakinkite planšetinį kompiuterį arba ištrinkite visus šio naudotojo duomenis, jei per daug kartų įvedamas netinkamas slaptažodis."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Stebėkite atrakinant ekraną įvestų netinkamų slaptažodžių skaičių ir užrakinkite TV arba ištrinkite visus šio naudotojo duomenis, jei per daug kartų įvedamas netinkamas slaptažodis."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Stebėkite atrakinant ekraną įvestų netinkamų slaptažodžių skaičių ir užrakinkite telefoną arba ištrinkite visus šio naudotojo duomenis, jei per daug kartų įvedamas netinkamas slaptažodis."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Ekrano užrakto pakeitimas"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Pakeiskite ekrano užraktą."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Užrakinti ekraną"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Valdyti, kaip ir kada užrakinamas ekranas."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Trinti visus duomenis"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Be įspėjimo ištrinti planšetinio kompiuterio duomenis atkuriant gamyklinius duomenis."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Ištrinti TV duomenis be įspėjimo atliekant gamyklinių duomenų atkūrimą."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Be įspėjimo ištrinti telefono duomenis atkuriant gamyklinius duomenis."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Naudotojo duomenų ištrynimas"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ištrinkite šio naudotojo duomenis šiame planšetiniame kompiuteryje be įspėjimo."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ištrinkite šio naudotojo duomenis šiame TV be įspėjimo."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Ištrinkite šio naudotojo duomenis šiame telefone be įspėjimo."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nustatyti įrenginio bendrąjį tarpinį serverį"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nustatyti įrenginio bendrąjį tarpinį serverį, kad būtų naudojamas, kol įgalinta politika. Tik pirmasis įrenginio administratorius nustato efektyvų bendrąjį tarpinį serverį."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Nust. ekr. užr. slapt. gal. pab."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Valdykite, kaip dažnai reikia keisti ekrano užrakinimo slaptažodį."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Nustatykite įrenginio visuotinį tarpinį serverį, kuris bus naudojamas, kai politika įgalinta. Tik įrenginio savininkas gali nustatyti visuotinį tarpinį serverį."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ekr. užr. slaptaž. gal. l. n."</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Pakeiskite, kaip dažnai reikia keisti ekrano užrakto slaptažodį, PIN kodą arba atrakinimo piešinį."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nustatyti atmintinės šifruotę"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Reikalauti, kad saugomos programos duomenys būtų šifruoti."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Neleisti fotoaparatų"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Neleisti naudoti visų įrenginio fotoaparatų."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Funkcijų išjung. klaviat. aps."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Naudojant klaviatūros apsaugos funkciją, neleisti naudoti kai kurių funkcijų."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Ekrano užrakto funkc. išjung."</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Neleiskite naudoti tam tikrų ekrano užrakto funkcijų."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Pagrindinis"</item>
     <item msgid="869923650527136615">"Mobilusis"</item>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"„<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>“ nori įgalinti naršymą liečiant. Kai naršymas liečiant bus įjungtas, galėsite išgirsti ar peržiūrėti pirštu liečiamų elementų aprašus arba atlikdami gestus naudoti telefoną."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Prieš 1 mėn."</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Prieš maždaug 1 mėnesį"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Prieš 1 sek."</item>
-    <item quantity="other" msgid="3903706804349556379">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Prieš 1 minutę"</item>
-    <item quantity="other" msgid="2176942008915455116">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Prieš 1 valandą"</item>
-    <item quantity="other" msgid="2467273239587587569">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Paskutinės <xliff:g id="COUNT">%d</xliff:g> dienos (-ų)"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> pastaroji diena</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> pastarosios dienos</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> pastarosios dienos</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> pastarųjų dienų</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Paskutinį mėnesį"</string>
     <string name="older" msgid="5211975022815554840">"Senesni"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"vakar"</item>
-    <item quantity="other" msgid="2479586466153314633">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"po 1 sek."</item>
-    <item quantity="other" msgid="1241926116443974687">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"po 1 min."</item>
-    <item quantity="other" msgid="3330713936399448749">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"po 1 val."</item>
-    <item quantity="other" msgid="547290677353727389">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"rytoj"</item>
-    <item quantity="other" msgid="5109449375100953247">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Prieš 1 sek."</item>
-    <item quantity="other" msgid="3699169366650930415">"Prieš <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Prieš 1 min."</item>
-    <item quantity="other" msgid="851164968597150710">"Prieš <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Prieš 1 valandą"</item>
-    <item quantity="other" msgid="6889970745748538901">"Prieš <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"vakar"</item>
-    <item quantity="other" msgid="3453342639616481191">"Prieš <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"po 1 sek."</item>
-    <item quantity="other" msgid="5495880108825805108">"po <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"po 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"po <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"po 1 val."</item>
-    <item quantity="other" msgid="3705373766798013406">"po <xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"rytoj"</item>
-    <item quantity="other" msgid="2973062968038355991">"po <xliff:g id="COUNT">%d</xliff:g> d."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> m."</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"sav."</string>
     <string name="year" msgid="4001118221013892076">"metai"</string>
     <string name="years" msgid="6881577717993213522">"metai"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sek."</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 min."</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 val."</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> val."</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekundė</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekundės</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> sekundės</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundžių</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minutė</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minutės</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> minutės</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minučių</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> valanda</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> valandos</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> valandos</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> valandų</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Vaizdo įrašo problema"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis vaizdo įrašas netinkamas srautiniu būdu perduoti į šį įrenginį."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Negalima paleisti šio vaizdo įrašo."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Paleidžiama „Android“…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimizuojama saugykla."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizuojama <xliff:g id="NUMBER_0">%1$d</xliff:g> progr. iš <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ruošiama „<xliff:g id="APPNAME">%1$s</xliff:g>“."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Paleidžiamos programos."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Užbaigiamas paleidimas."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nepaleiskite naujos programos."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Paleisti „<xliff:g id="OLD_APP">%1$s</xliff:g>“"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Sustabdyti seną programą jos neišsaugant."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pasirinkite teksto veiksmą"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Skambučio garsumas"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medijos garsumas"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nėra"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Skambėjimo tonai"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nežinomas skambėjimo tonas"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Galimas „Wi-Fi“ tinklas"</item>
-    <item quantity="other" msgid="4192424489168397386">"galimi „Wi-Fi“ tinklai"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Atidaryti galimą „Wi-Fi“ tinklą"</item>
-    <item quantity="other" msgid="7915895323644292768">"Atidaryti galimus „Wi-Fi“ tinklus"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Pasiekiami „Wi-Fi“ tinklai</item>
+      <item quantity="few">Pasiekiami „Wi-Fi“ tinklai</item>
+      <item quantity="many">Pasiekiami „Wi-Fi“ tinklai</item>
+      <item quantity="other">Pasiekiami „Wi-Fi“ tinklai</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+      <item quantity="few">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+      <item quantity="many">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+      <item quantity="other">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Prisijungti prie „Wi-Fi“ ryšio tinklo"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Prisijungti prie tinklo"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programa „%1$s“ nori prisijungti prie „Wi-Fi“ tinklo „%2$s“"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programa"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nepavyko paleisti „Wi-Fi Direct“."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Gerai"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Prij. kaip medijos įrenginys"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Prij. kaip fotoap."</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Prijungtas kaip MIDI įrenginys"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Prij. kaip diegimo programa"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Prijungta prie USB priedo"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Jei norite matyti kitas USB parinktis, palieskite."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Praleisti"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nėra atitikčių"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Ieškoti puslapyje"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 atitiktis"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> iš <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> iš <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> iš <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> iš <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> iš <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Atlikta"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Pašalinama USB atmintis..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Pašalinama SD kortelė..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Sukurti modifikavimo apribojimų PIN kodą"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN kodas neatitinka. Bandykite dar kartą."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN kodas per trumpas. Jis turi būti bent 4 skaitmenų."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Band. dar po 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Band. dar po <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundės</item>
+      <item quantity="few">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundžių</item>
+      <item quantity="many">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundės</item>
+      <item quantity="other">Bandykite dar kartą po <xliff:g id="COUNT">%d</xliff:g> sekundžių</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vėliau bandykite dar kartą"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Perbraukite nuo viršaus žemyn, kad išeitumėte iš viso ekrano režimo"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Peržiūrima viso ekrano režimu"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Supratau"</string>
     <string name="done_label" msgid="2093726099505892398">"Atlikta"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Apskritas valandų slankiklis"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Apskritas minučių slankiklis"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Jei norite atsegti šį ekraną, vienu metu palieskite ir palaikykite „Atgal“ ir „Apžvalga“."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Jei norite atsegti šį ekraną, palieskite ir palaikykite „Apžvalga“."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekranas yra prisegtas. Jūsų organizacija neleidžia jo atsegti."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekranas atsegtas"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo žinutėmis ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kol jūsų prastova baigsis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kol baigsis prastova"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Vieną minutę (iki <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d min. (iki <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Vieną valandą (iki <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d val. (iki <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 min."</item>
-    <item quantity="other" msgid="6924190729213550991">"%d min."</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 val."</item>
-    <item quantity="other" msgid="5408537517529822157">"%d val."</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d minutę (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d minutes (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d minutės (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d minučių (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d valandą (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d valandas (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d valandos (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d valandų (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d minutę</item>
+      <item quantity="few">%d minutes</item>
+      <item quantity="many">%d minutės</item>
+      <item quantity="other">%d minučių</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d valandą</item>
+      <item quantity="few">%d valandas</item>
+      <item quantity="many">%d valandos</item>
+      <item quantity="other">%d valandų</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Neapibrėžta"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sutraukti"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Iki kito įspėjimo <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Iki kito įspėjimo"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS užklausa pakeista į DIAL užklausą."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS užklausa pakeista į USSD užklausą."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS užklausa pakeista į naują SS užklausą."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB išorinis prievadas"</string>
 </resources>
diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
index f565157..3bed6cd 100755
--- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml
+++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%Y. gada %-e. %B</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%Y. gada %-e. %b, %H:%M:%S</string>
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
index c21481a..7ecdc31 100755
--- a/core/res/res/values-lv/donottranslate-cldr.xml
+++ b/core/res/res/values-lv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%Y. gada %-e. %B</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y. gada %-e. %b</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 620ba06..6360a42 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Bez nosaukuma&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nav tālruņa numura)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Nezināms"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Balss pasts"</string>
@@ -63,10 +61,11 @@
     <string name="needPuk" msgid="919668385956251611">"SIM karte ir bloķēta ar PUK kodu. Ierakstiet PUK kodu, lai to atbloķētu."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Ierakstiet PUK2 kodu, lai atbloķētu SIM karti."</string>
     <string name="enablePin" msgid="209412020907207950">"Neizdevās. Iespējojiet SIM/RUIM bloķēšanu."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi, pirms SIM karte tiks bloķēta."</item>
-    <item quantity="other" msgid="7530597808358774740">"Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi(-es), pirms SIM karte tiks bloķēta."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="zero">Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes. Pēdējā mēģinājuma kļūdas gadījumā SIM karte tiks bloķēta.</item>
+      <item quantity="one">Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizi. Pēdējā mēģinājuma kļūdas gadījumā SIM karte tiks bloķēta.</item>
+      <item quantity="other">Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes. Pēdējā mēģinājuma kļūdas gadījumā SIM karte tiks bloķēta.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Ienākošā zvana zvanītāja ID"</string>
@@ -202,6 +201,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lidojuma režīms ir IESLĒGTS."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lidojuma režīms ir IZSLĒGTS."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
@@ -431,6 +431,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Saistīšana ar maršruta nodrošinātāja pakalpojumu"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ļauj īpašniekam saistīt jebkādus reģistrētus maršrutēšanas nodrošinātājus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"Izveidot saiti ar TV ieeju"</string>
@@ -737,6 +739,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ļauj lietotnei sazināties ar tuva darbības lauka sakaru (Near Field Communication — NFC) atzīmēm, kartēm un lasītājiem."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"atspējot ekrāna bloķēšanu"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ļauj lietotnei atspējot taustiņslēgu un visu saistīto paroļu drošību. Piemēram, tālrunis atspējo taustiņslēgu, saņemot ienākošu zvanu, un pēc zvana pabeigšanas atkārtoti iespējo taustiņslēgu."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"pārvaldīt pirkstu nospiedumu aparatūru"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Atļauj lietotnei izsaukt metodes izmantojamo pirkstu nospiedumu veidņu pievienošanai un dzēšanai."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"lietot pirkstu nospiedumu aparatūru"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Atļauj lietotnei izmantot pirkstu nospiedumu aparatūru autentificēšanai."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lasīt sinhronizācijas iestatījumus"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ļauj lietotnei lasīt konta sinhronizācijas iestatījumus. Piemēram, šādi var noteikt, vai lietotne Personas ir sinhronizēta ar kontu."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ieslēgt un izslēgt sinhronizāciju"</string>
@@ -791,8 +797,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"izveidot savienojumu ar atlasītāja mērķa pakalpojumu"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ļauj atļaujas īpašniekam izveidot savienojumu ar atlasītāja mērķa pakalpojuma augstākā līmeņa saskarni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Saistīšana ar nosacījumu sniedzēja pakalpojumu"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ļauj īpašniekam izveidot savienojumu ar drukas nosacījumu sniedzēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Saistīšana ar multivides datu maršrutēšanas pakalpojumu"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Ļauj īpašniekam izveidot saiti ar multivides datu maršrutēšanas pakalpojuma augstākā līmeņa saskarni. Nekad nav nepieciešama parastām lietotnēm."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"piesaistīt ekrānsaudzētāja pakalpojumu"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Ļauj īpašniekam piesaistīt ekrānsaudzētāja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Operatora nodrošinātas konfigurācijas lietotnes izsaukšana"</string>
@@ -810,29 +820,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Savienojuma izveide ar mobilo sakaru operatora ziņojumapmaiņas pakalpojumu"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ļauj īpašniekam izveidot savienojumu ar mobilo sakaru operatora ziņojumapmaiņas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolēt ekrāna bloķēšanas paroļu un PIN garumu un tajos atļautās rakstzīmes."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Pārrauga nepareizi ievadīto paroļu skaitu, atbloķējot ekrānu, un bloķē planšetdatoru vai dzēš visus planšetdatora datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Pārraudzīt nepareizi ievadīto ekrāna atbloķēšanas paroļu skaitu un bloķēt televizoru vai dzēst televizora datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Pārrauga nepareizi ievadīto paroļu skaitu, atbloķējot ekrānu, un bloķē tālruni vai dzēš visus tālruņa datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekrāna atbloķēšanas paroles maiņa"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Maina ekrāna atbloķēšanas paroli."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Pārraudzīt nepareizi ievadīto ekrāna atbloķēšanas paroļu skaitu un bloķēt planšetdatoru vai dzēst visus šī lietotāja datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Pārraudzīt nepareizi ievadīto ekrāna atbloķēšanas paroļu skaitu un bloķēt televizoru vai dzēst visus šī lietotāja datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Pārraudzīt nepareizi ievadīto ekrāna atbloķēšanas paroļu skaitu un bloķēt tālruni vai dzēst visus šī lietotāja datus, ja tiek ievadīts pārāk daudz nepareizu paroļu."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Mainīt ekrāna bloķēšanas iestatījumus"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Mainīt ekrāna bloķēšanas iestatījumu."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Ekrāna bloķēšana"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolē, kā un kad ekrāns tiek bloķēts."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Dzēst visus datus"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Dzēš planšetdatora datus bez brīdinājuma, veicot rūpnīcas datu atiestatīšanu."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Bez brīdinājuma dzēst televizora datus, veicot rūpnīcas datu atiestatīšanu."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Dzēš tālruņa datus bez brīdinājuma, veicot rūpnīcas datu atiestatīšanu."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Dzēst lietotāja datus"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Bez brīdinājuma dzēst šī lietotāja datus no planšetdatora."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Bez brīdinājuma dzēst šī lietotāja datus no televizora."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Bez brīdinājuma dzēst šī lietotāja datus no tālruņa."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Iestatīt ierīces globālo starpniekserveri"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Iestatiet izmantojamo ierīces globālo starpniekserveri, kad ir iespējota politika. Spēkā esošo globālo starpniekserveri iestata tikai pirmās ierīces administrators."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekrāna bloķ., paroles termiņa iestat."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontrolē, cik bieži ir jāmaina ekrāna bloķēšanas parole."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Iestatīt ierīces globālo starpniekserveri, kas jāizmanto, kad politika ir iespējota. Globālo starpniekserveri var iestatīt tikai ierīces īpašnieks."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Iestatīt paroles derīgumu"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Norādīt, cik bieži jāmaina ekrāna bloķēšanas parole, PIN vai grafiskā atslēga."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Skatīt atmiņas šifrējumu"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Pieprasa, lai saglabātie lietotnes dati tiktu šifrēti."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Atspējot kameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Neļauj izmantot nevienu ierīces kameru."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Bloķēšanas funkcijas atspējošana"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Atspējot noteiktas funkcijas taustiņslēgā."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Atspējot bloķēšanas funkcijas"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Novērst dažu ekrāna bloķēšanas funkciju darbību."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Mājas"</item>
     <item msgid="869923650527136615">"Mobilais"</item>
@@ -1128,75 +1145,13 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vēlas iespējot funkciju “Atklāt pieskaroties”. Kad ir ieslēgta funkcija “Atklāt pieskaroties”, var dzirdēt vai redzēt tā vienuma aprakstu, virs kura atrodas pirksts, vai veikt žestus, lai mijiedarbotos ar tālruni."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pirms 1 mēneša"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vairāk nekā pirms 1 mēneša"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Pirms 1 sekundes"</item>
-    <item quantity="other" msgid="3903706804349556379">"Pirms <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Pirms 1 minūtes"</item>
-    <item quantity="other" msgid="2176942008915455116">"Pirms <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Pirms 1 stundas"</item>
-    <item quantity="other" msgid="2467273239587587569">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Pēdējās <xliff:g id="COUNT">%d</xliff:g> dienās"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="zero">Pēdējās <xliff:g id="COUNT_1">%d</xliff:g> dienās</item>
+      <item quantity="one">Pēdējā <xliff:g id="COUNT_1">%d</xliff:g> dienā</item>
+      <item quantity="other">Pēdējās <xliff:g id="COUNT_1">%d</xliff:g> dienās</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Iepriekšējā mēnesī"</string>
     <string name="older" msgid="5211975022815554840">"Vecāks"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"vakar"</item>
-    <item quantity="other" msgid="2479586466153314633">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"pēc 1 sekundes"</item>
-    <item quantity="other" msgid="1241926116443974687">"pēc <xliff:g id="COUNT">%d</xliff:g> sekundes(-ēm)"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"pēc 1 minūtes"</item>
-    <item quantity="other" msgid="3330713936399448749">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"pēc 1 stundas"</item>
-    <item quantity="other" msgid="547290677353727389">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"rītdien"</item>
-    <item quantity="other" msgid="5109449375100953247">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Pirms 1 sekundes"</item>
-    <item quantity="other" msgid="3699169366650930415">"Pirms <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Pirms 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Pirms <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Pirms 1 stundas"</item>
-    <item quantity="other" msgid="6889970745748538901">"Pirms <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"vakar"</item>
-    <item quantity="other" msgid="3453342639616481191">"Pirms <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"pēc 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"pēc <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"pēc 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"pēc <xliff:g id="COUNT">%d</xliff:g> minūtes(-ēm)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"pēc 1 stundas"</item>
-    <item quantity="other" msgid="3705373766798013406">"pēc <xliff:g id="COUNT">%d</xliff:g> stundas(-ām)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"rītdien"</item>
-    <item quantity="other" msgid="2973062968038355991">"pēc <xliff:g id="COUNT">%d</xliff:g> dienas(-ām)"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"šādā datumā: <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"šādā gadā: <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1167,21 @@
     <string name="weeks" msgid="6509623834583944518">"nedēļas"</string>
     <string name="year" msgid="4001118221013892076">"gads"</string>
     <string name="years" msgid="6881577717993213522">"gadi"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 s"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 min"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 stunda"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="zero"><xliff:g id="COUNT">%d</xliff:g> sekunžu</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekundes</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundes</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="zero"><xliff:g id="COUNT">%d</xliff:g> minūšu</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minūte</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minūtes</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="zero"><xliff:g id="COUNT">%d</xliff:g> stundu</item>
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> stunda</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> stundas</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video problēma"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Šis video nav derīgs straumēšanai uz šo ierīci."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nevar atskaņot šo video."</string>
@@ -1301,6 +1259,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Notiek Android palaišana…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Notiek krātuves optimizēšana."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Tiek optimizēta <xliff:g id="NUMBER_0">%1$d</xliff:g>. lietotne no <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Notiek lietotnes <xliff:g id="APPNAME">%1$s</xliff:g> sagatavošana."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Notiek lietotņu palaišana."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Tiek pabeigta sāknēšana."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> darbojas"</string>
@@ -1311,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nestartējiet jauno lietotni."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Startēt: <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Aptur vecās lietotnes darbību, neko nesaglabājot."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izvēlieties darbību tekstam"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Zvanītāja skaļums"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multivides skaļums"</string>
@@ -1331,20 +1298,25 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nav"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvana signāli"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nezināms zvana signāls"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi tīkls ir pieejams."</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi tīkli ir pieejami"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Ir pieejams atvērts Wi-Fi tīkls"</item>
-    <item quantity="other" msgid="7915895323644292768">"Ir pieejami atvērti Wi-Fi tīkli."</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="zero">Pieejami Wi-Fi tīkli</item>
+      <item quantity="one">Pieejami Wi-Fi tīkli</item>
+      <item quantity="other">Pieejami Wi-Fi tīkli</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="zero">Ir pieejami atvērti Wi-Fi tīkli</item>
+      <item quantity="one">Ir pieejami atvērti Wi-Fi tīkli</item>
+      <item quantity="other">Ir pieejami atvērti Wi-Fi tīkli</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Pierakstieties Wi-Fi tīklā."</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Pierakstīšanās tīklā"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Lietotne %1$s vēlas izveidot savienojumu ar Wi-Fi tīklu %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Lietojumprogramma"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nevarēja palaist programmu Wi-Fi Direct."</string>
@@ -1411,6 +1383,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Labi"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Pievienots kā multivides ierīce"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Pievienots kā kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Ierīce tika pievienota kā MIDI ierīce."</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Pievienots kā instalēšanas programma"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ir izveidots savienojums ar USB piederumu."</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Pieskarieties, lai skatītu citas USB opcijas."</string>
@@ -1526,10 +1499,11 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Izlaist"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nav atbilstību"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Atrast lapā"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 atbilstība"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> no <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="zero"><xliff:g id="INDEX">%d</xliff:g>. no <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g>. no <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>. no <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Gatavs"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Notiek USB atmiņas atvienošana..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Notiek SD kartes atvienošana..."</string>
@@ -1815,12 +1789,15 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Izveidojiet PIN, lai mainītu ierobežojumus."</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ievadītie PIN neatbilst. Mēģiniet vēlreiz."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ir pārāk īss. Tam ir jābūt vismaz 4 ciparus garam."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Mēģ. vēl pēc 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Mēģ. vēl pēc <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="zero">Mēģiniet vēlreiz pēc <xliff:g id="COUNT">%d</xliff:g> sekundēm</item>
+      <item quantity="one">Mēģiniet vēlreiz pēc <xliff:g id="COUNT">%d</xliff:g> sekundes</item>
+      <item quantity="other">Mēģiniet vēlreiz pēc <xliff:g id="COUNT">%d</xliff:g> sekundēm</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Vēlāk mēģiniet vēlreiz."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Lai izietu no pilnekrāna režīma, velciet no augšas uz leju."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Skatīšanās pilnekrāna režīmā"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Lai izietu, no augšdaļas velciet lejup."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Labi"</string>
     <string name="done_label" msgid="2093726099505892398">"Gatavs"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Stundu apļveida slīdnis"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Minūšu apļveida slīdnis"</string>
@@ -1835,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Lai atspraustu šo ekrānu, vienlaicīgi pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Lai atspraustu šo ekrānu, pieskarieties pogai “Pārskats” un turiet to."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekrāns ir piesprausts. Jūsu organizācija nav atļāvusi atspraušanu."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekrāns ir atsprausts"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pirms atspraušanas pieprasīt PIN"</string>
@@ -1844,24 +1822,28 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Līdz beigsies dīkstāve (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Līdz beidzas dīkstāve"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Vienu minūti (līdz <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d minūtes (līdz <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Vienu stundu (līdz <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d stundas (līdz <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d min"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Vienu stundu"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d h"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="zero">%1$d minūtes (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">%1$d minūti (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d minūtes (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="zero">%1$d stundas (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">%1$d stundu (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d stundas (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="zero">%d minūtes</item>
+      <item quantity="one">%d minūti</item>
+      <item quantity="other">%d minūtes</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="zero">%d stundas</item>
+      <item quantity="one">%d stundu</item>
+      <item quantity="other">%d stundas</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Līdz <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Uz nenoteiktu laiku"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sakļaut"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Līdz nākamajam signālam: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Līdz nākamajam signālam"</string>
@@ -1874,4 +1856,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS pieprasījums ir mainīts uz DIAL pieprasījumu."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS pieprasījums ir mainīts uz USSD pieprasījumu."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS pieprasījums ir mainīts uz jaunu SS pieprasījumu."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB perifērijas ports"</string>
 </resources>
diff --git a/core/res/res/values-mcc259-mnc05/config.xml b/core/res/res/values-mcc259-mnc05/config.xml
new file mode 100644
index 0000000..065668c
--- /dev/null
+++ b/core/res/res/values-mcc259-mnc05/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The list of ril radio technologies (see ServiceState.java) which only support
+         a single data connection at one time.  This may change by carrier via
+         overlays (some don't support multiple pdp on UMTS).  All unlisted radio
+         tech types support unlimited types (practically only 2-4 used). -->
+    <integer-array name="config_onlySingleDcAllowed">
+        <item>1</item>  <!-- GPRS -->
+        <item>2</item>  <!-- EDGE -->
+        <item>3</item>  <!-- UMTS -->
+        <item>9</item>  <!-- HSDPA -->
+        <item>10</item> <!-- HSUPA -->
+        <item>11</item> <!-- HSPA -->
+        <item>14</item> <!-- LTE -->
+        <item>15</item> <!-- HSPAP -->
+    </integer-array>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 87131de..86e31e5 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без наслов&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Нема телефонски број)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Непознато"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Говорна пошта"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Вашата СИМ картичка е заклучена со ПУК код. Внесете го ПУК кодот за да се отклучи."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Внесете го ПУК2 кодот за да се одблокира СИМ картичката."</string>
     <string name="enablePin" msgid="209412020907207950">"Неуспешно, овозможи заклучување на SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Ви преостанува уште <xliff:g id="NUMBER">%d</xliff:g> обид, а потоа СИМ картичката ќе се заклучи."</item>
-    <item quantity="other" msgid="7530597808358774740">"Ви преостануваат уште <xliff:g id="NUMBER">%d</xliff:g> обиди, а потоа СИМ картичката ќе се заклучи."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обид пред СИМ-картичката да се заклучи.</item>
+      <item quantity="other">Ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обиди пред СИМ-картичката да се заклучи.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ИД на дојдовен повикувач"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режимот на работа во авион е вклучен"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режимот на работа во авион е исклучен"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Поставки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Овозможува сопственикот да се поврзе со интерфејс од највисоко ниво на приказ од далечина. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"врзи се со услуга за виџет"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволува сопственикот да се поврзе со интерфејс од највисоко ниво на услугата за додатоци. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"поврзување со услуга за давател на маршрута"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозволува сопственикот да се поврзе со сите регистрирани даватели на маршрути. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"комуницирај со администратор на уред"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволува сопственикот да испраќа намери до администратор за уреди. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"поврзување со ТВ-влез"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Дозволува апликацијата да комуницира со ознаки, картички и читачи за Комуникација при непосредна близина (НФЦ)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"оневозможи заклучување на екран"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Овозможува апликацијата да го оневозможи заклучувањето и каква било безбедност поврзана со лозинка. На пример, телефонот го оневозможува заклучувањето при прием на телефонски повик, а потоа повторно го овозможува заклучувањето кога повикот ќе заврши."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управувај хардвер за отпечатоци"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозволува апликацијата да повика начини за додавање и бришење шаблони на отпечатоци за користење."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отпечатоци"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозволува апликацијата да користи хардвер за отпечатоци за проверка"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"прочитај синхронизирани подесувања"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Овозможува апликацијата да ги чита подесувањата за синхронизирање на сметка. На пример, така може да се утврди дали апликацијата „Луѓе“ е синхронизирана со сметка."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"вклучи и исклучи синхронизација"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Овозможува апликацијата да враќа, проверува и брише известувања, вклучувајќи ги и оние објавени од други апликации."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"поврзи се со услугата слушател на известувања"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Овозможува сопственикот да се поврзе со интерфејс од највисоко ниво на услугата слушател на известувања. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"сврзи се со услугата избирач на цел"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозволува сопственикот да се сврзе со интерфејс од највисоко ниво на услугата избирач на цел. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"поврзување со услуга за давател на услов"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозволува сопственикот да се поврзе со интерфејс од највисоко ниво на давател на услуги за услов. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"врзува со услуга за насочување медиуми"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Овозможува носителот да се врзува со интерфејс на највисоко ниво на услуга за насочување медиуми. Не би требало да е потребно за стандардни апликации."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"поврзи се со услугата мечтаење"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Дозволува сопственикот да се поврзе со интерфејс од највисоко ниво на услугата мечтаење. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"повикај конфигурација на апликацијата обезбедена од давателот"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"сврзување со давателот на услугата за пораки"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Дозволува сопственикот да се сврзе со интерфејсот од највисоко ниво на давателот на услугата за пораки. Не треба да се користи за стандардни апликации."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подеси правила за лозинката"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирај ги должината и знаците што се дозволени за лозинки за отклучување екран."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролирај ги должината и знаците што се дозволени за лозинки и ПИН-броеви за отклучување екран."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Следи ги обидите за отклучување на екранот"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Посматрај го бројот на неточни лозинки што се напишани за да се отклучи екранот и заклучи го таблетот или избриши ги сите податоци од него ако бидат напишани премногу неточни лозинки."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го телевизорот или избриши ги сите негови податоци доколку се внесени премногу погрешни лозинки."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Посматрај го бројот на неточни лозинки што се напишани за да се отклучи екранот и заклучи го телефонот или избриши ги сите податоци од него ако бидат напишани премногу неточни лозинки."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Промени ја лозинката за отклучување на екранот"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Промени ја лозинката за отклучување екран."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го таблетот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го телевизорот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го телефонот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Промени го заклучувањето на екранот."</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Промени го заклучувањето на екранот."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Заклучи го екранот"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Контролирај како и кога се заклучува екранот."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Избриши ги сите податоци"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Избриши ги податоците во таблетот без предупредување со вршење на фабричко ресетирање на податоци."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Избриши ги податоците на телевизорот без предупредување со изведување ресетирање на фабрички податоци."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Избриши ги податоците во телефонот без предупредување со вршење на фабричко ресетирање на податоци."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Избриши ги податоците на корисникот"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Избриши ги податоците на овој корисник на таблетот без предупредување."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Избриши ги податоците на овој корисник на телевизорот без предупредување."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Избриши ги податоците на овој корисник на телефонот без предупредување."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подеси го глобалниот прокси на уредот"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесете употреба на глобалниот прокси на уредот додека политиката е овозможена. Само првиот администратор на уредот може да подеси важечки глобален прокси."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Подеси период на важност на лозинката за заклучување на екранот"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Контролирај колку често мора да се менува лозинката за заклучување екран."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Поставете го глобалниот прокси на уредот да се користи додека политиката е овозможена. Само сопственикот на уредот може да го поставува глобалниот прокси."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Рок на лозинка за закл. екран"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Измени колку често мора да се менува лозинката, ПИН-бројот или шемата за заклучување екран."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Подеси шифрирање на меморија"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Барај зачуваните податоци за апликација да се шифрирани."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Оневозможи фотоапарати"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Спречи употреба на сите камери на уредот."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Оневозможи функции во заклучувањето"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Спречи употреба на некои функции во заклучувањето."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Исклучи функции на закл. екран"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Спречи употреба на некои функции од заклучување на екранот."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Дома"</item>
     <item msgid="869923650527136615">"Мобилен"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со телефонот."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Пред 1 месец"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пред повеќе од 1 месец"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"пред 1 секунда"</item>
-    <item quantity="other" msgid="3903706804349556379">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"пред 1 минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Пред 1 час"</item>
-    <item quantity="other" msgid="2467273239587587569">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последните <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Последните <xliff:g id="COUNT_1">%d</xliff:g> ден</item>
+      <item quantity="other">Последните <xliff:g id="COUNT_1">%d</xliff:g> дена</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Минатиот месец"</string>
     <string name="older" msgid="5211975022815554840">"Постари"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"за 1 секунда"</item>
-    <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"за 1 минута"</item>
-    <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"за 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"утре"</item>
-    <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"пред 1 сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"пред <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"пред 1 мин"</item>
-    <item quantity="other" msgid="851164968597150710">"пред <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"пред 1 час"</item>
-    <item quantity="other" msgid="6889970745748538901">"пред <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"Пред <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"за 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"утре"</item>
-    <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дена"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"на <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"во <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"во <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"седмици"</string>
     <string name="year" msgid="4001118221013892076">"година"</string>
     <string name="years" msgid="6881577717993213522">"години"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 минута"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минути"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 час"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> часа"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> минута</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минути</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> час</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> часа</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Проблем со видео"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Видеово не е важечко за постојан тек до уредов."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ова видео не може да се пушти."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android стартува…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимизирање на складирањето."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Се оптимизира апликација <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Се подготвува <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Се стартуваат апликациите."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Подигањето завршува."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> работи"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не стартувајте ја новата апликација."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Вклучи <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Запрете ја старата апликација без зачувување."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Избери дејство за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Јачина на звук на ѕвонче"</string>
     <string name="volume_music" msgid="5421651157138628171">"Јачина на звук на медиуми"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ниедна"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Непозната мелодија"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi мрежа е достапна"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi мрежи се достапни"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Отворена Wi-Fi мрежа е достапна"</item>
-    <item quantity="other" msgid="7915895323644292768">"Отворени Wi-Fi мрежи се достапни"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Wi-Fi мрежи се достапни</item>
+      <item quantity="other">Wi-Fi мрежи се достапни</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Отворени Wi-Fi мрежи се достапни</item>
+      <item quantity="other">Отворени Wi-Fi мрежи се достапни</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Пријави се на Wi-Fi мрежа"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Пријави се на мрежа"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има слаба конекција на интернет."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликацијата %1$s сака да се поврзе со Wifi-мрежата %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Започни Wi-Fi Direct. Ова ќе го исклучи Wi-Fi клиентот/хточката на пристап."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не можеше да се стартува Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Во ред"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Поврзан како уред за медиуми"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Поврзан како фотоапарат"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Поврзан како уред со MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Поврзан како инсталатор"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Поврзан со УСБ додаток"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Допри за други опции на УСБ."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Прескокни"</string>
     <string name="no_matches" msgid="8129421908915840737">"Нема совпаѓања"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Пронајди на страница"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 совпаѓање"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Готово"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Одмонтирање УСБ меморија..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Одмонтирање СД картичка..."</string>
@@ -1817,12 +1783,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Создади ПИН за измена на ограничувањата"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ПИН кодовите не се совпаѓаат. Обиди се повторно."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ПИН кодот е премногу краток. Мора да има најмалку 4 цифри."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Обидете се повторно за 1 секунда"</item>
-    <item quantity="other" msgid="4730868920742952817">"Обидете се повторно за <xliff:g id="COUNT">%d</xliff:g> секунди"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Обидете се повторно по <xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="other">Обидете се повторно по <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Обиди се повторно подоцна"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Помини со прстот одозгора надолу да излезе од режим на цел екран."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Се прикажува на цел екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"За да излезете, повлечете одозгора надолу."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Разбрав"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Приказ на часови во кружно движење"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Приказ на минути во кружно движење"</string>
@@ -1837,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да го откачите екранот, допрете и задржете Назад и Краток преглед во исто време."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"За да го откачите екранот, допрете и задржете Краток преглед."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екранот е закачен. Откачување не е дозволено од вашата организација."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екранот е откачен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string>
@@ -1846,24 +1815,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и го ограничува вибрирањето, услугите за локација и повеќето податоци од заднина. Е-поштата, испраќањето пораки и другите апликации кои се потпираат на синхронизација можеби нема да се ажурираат доколку не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Додека не заврши паузата во <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Додека да заврши паузата"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Една минута (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d минути (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Еден час (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d часа (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"За една минута"</item>
-    <item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"За еден час"</item>
-    <item quantity="other" msgid="5408537517529822157">"За %d часа"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">За %1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">За %1$d час (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">За %1$d часа (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">За %d минута</item>
+      <item quantity="other">За %d минути</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">За % d час</item>
+      <item quantity="other">За % d часа</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Неодредено време"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Додека не го исклучите"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Собери"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следниот аларм во <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следниот аларм"</string>
@@ -1876,4 +1845,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Барањето SS е изменето во барање DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Барањето SS е изменето во барање USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Барањето SS е изменето во ново барање SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Надворешна порта на УСБ"</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index fb866d7..959d0a7 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> സെക്കൻഡ്"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> സെക്കൻഡ്"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ശീർഷകമില്ലാത്ത&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ഫോൺ നമ്പറില്ല)"</string>
     <string name="unknownName" msgid="6867811765370350269">"അജ്ഞാതം"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"വോയ്സ് മെയില്‍"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"നിങ്ങളുടെ സിം കാർഡ് PUK ലോക്ക് ചെയ്‌തതാണ്. ഇത് അൺലോക്ക് ചെയ്യാൻ PUK കോഡ് ടൈപ്പുചെയ്യുക."</string>
     <string name="needPuk2" msgid="4526033371987193070">"സിം കാർഡ് തടഞ്ഞത് മാറ്റാൻ PUK2 ടൈപ്പുചെയ്യുക."</string>
     <string name="enablePin" msgid="209412020907207950">"വിജയകരമല്ല, സിം/RUIM ലോക്ക് പ്രവർത്തനക്ഷമമാക്കുക."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"സിം ലോക്കാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമം കൂടി ബാക്കിയുണ്ട്."</item>
-    <item quantity="other" msgid="7530597808358774740">"സിം ലോക്കാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ബാക്കിയുണ്ട്."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">SIM ലോക്കാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
+      <item quantity="one">SIM ലോക്കാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ഇൻകമിംഗ് കോളർ ഐഡി"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ഫ്ലൈറ്റ് മോഡ് ഓണാണ്"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ഫ്ലൈറ്റ് മോഡ് ഓഫാണ്"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ക്രമീകരണങ്ങൾ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്‌സ് സഹായം"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ഒരു വിദൂര ഡിസ്‌പ്ലേയുടെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ഒരു വിജറ്റ് സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ഒരു വിജറ്റ് സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"റൂട്ട് പ്രൊവൈഡർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ഏതെങ്കിലും രജിസ്‌റ്റർചെയ്‌ത റൂട്ട് ദാതാക്കളുമായി ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ഒരു ഉപകരണ അഡ്‌മിനുമായി സംവദിക്കുക"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ഒരു ഉപകരണ അഡ്മിനിസ്‌ട്രേറ്ററിലേക്ക് ഇന്റന്റുകൾ അയയ്ക്കുന്നതിന് ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV ഇൻപുട്ടുമായി ബന്ധിപ്പിക്കുക"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"നിയർ ഫീൽഡ് കമ്മ്യൂണിക്കേഷൻ (NFC) ടാഗുകളുമായും കാർഡുകളുമായും റീഡറുകളുമായുള്ള ആശയവിനിമയത്തിന് അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"നിങ്ങളുടെ സ്‌ക്രീൻ ലോക്ക് പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"കീലോക്കും ഏതെങ്കിലും അനുബന്ധ പാസ്‌വേഡ് സുരക്ഷയും പ്രവർത്തനരഹിതമാക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു ഇൻകമിംഗ് കോൾ സ്വീകരിക്കുമ്പോൾ ഫോൺ കീലോക്ക് പ്രവർത്തനരഹിതമാക്കുന്നു, കോൾ അവസാനിക്കുമ്പോൾ കീലോക്ക് വീണ്ടും പ്രവർത്തനക്ഷമമാകുന്നു."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ നിയന്ത്രിക്കുക"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ഉപയോഗിക്കാനായി വിരലടയാള ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ഫിംഗർപ്രിന്റ് ഹാർഡ്‌വെയർ ഉപയോഗിക്കുക"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"പ്രാമാണീകരണത്തിനായി വിരലടയാളം ഉപയോഗിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"സമന്വയം ഓണാക്കുക, ഓഫാക്കുക ടോഗിൾചെയ്യുക"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"മറ്റ് അപ്ലിക്കേഷനുകൾ പോസ്റ്റുചെയ്‌തവയുൾപ്പെടെയുള്ള, അറിയിപ്പുകൾ വീണ്ടെടുക്കാനും പരിശോധിക്കാനും മായ്‌ക്കാനും അപ്ലിക്കേഷനുകളെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ഒരു അറിയിപ്പ് ലിസണർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ഒരു അറിയിപ്പ് ലിസണർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ഒരു ചൂസർ ടാർഗെറ്റ് സേവനത്തിന്റെ ഉയർന്ന ലെവൽ ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"കണ്ടീഷൻ പ്രൊവൈഡർ സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ഒരു കണ്ടീഷൻ പ്രൊവൈഡർ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"മീഡിയ റൂട്ട് സേവനവുമായി ബന്ധിപ്പിക്കുക"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"ഒരു മീഡിയ റൂട്ട് സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"സ്വപ്‌നതുല്യമായ ഒരു സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"സ്വപ്‌നതുല്യമായ ഒരു സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"കാരിയർ നൽകിയ കോൺഫിഗറേഷൻ അപ്ലിക്കേഷൻ റദ്ദാക്കുക"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"കാരിയർ സന്ദേശമയയ്‌ക്കൽ സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ഒരു കാരിയർ സന്ദേശമയയ്‌ക്കൽ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"പാസ്‌വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"സ്‌ക്രീൻ-അൺലോക്ക് പാസ്‌വേഡുകളിൽ അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"സ്‌ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക, വളരെയധികം തെറ്റായ പാസ്‌വ്ഡുകൾ ടൈപ്പുചെയ്‌തിട്ടുണ്ടെങ്കിൽ ടാബ്‌ലെറ്റ് ലോക്കുചെയ്യുകയോ ടാബ്‌ലെറ്റിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോ ചെയ്യുക."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"സ്‌ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്‌വേഡ് തെറ്റായി നൽകിയിട്ടുണ്ടെങ്കിൽ ടിവി ലോക്കുചെയ്യുകയോ ടിവിയുടെ എല്ലാ വിവരവും മായ്‌ക്കുകയോ ചെയ്യുക."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക, വളരെയധികം തെറ്റായ പാസ്‌വ്ഡുകൾ ടൈപ്പുചെയ്‌തിട്ടുണ്ടെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഫോണിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോചെയ്യുക."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"സ്‌ക്രീൻ അൺലോക്ക് പാസ്‌വേഡ് മാറ്റുക"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"സ്‌ക്രീൻ അൺലോക്ക് പാസ്‌വേഡ് മാറ്റുക."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"സ്‌ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്‌വേഡ് ടൈപ്പുചെയ്‌തെങ്കിൽ ടാബ്‌ലെറ്റ് ലോക്കുചെയ്യുകയോ ഈ എല്ലാ ഉപയോക്തൃവിവരവും മായ്‌ക്കുകയോ ചെയ്യുക."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"സ്‌ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്‌വേഡ് ടൈപ്പുചെയ്‌തെങ്കിൽ ടിവി ലോക്കുചെയ്യുകയോ ഈ എല്ലാ ഉപയോക്തൃവിവരവും മായ്‌ക്കുകയോ ചെയ്യുക."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"സ്‌ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്‌ത പാസ്‌വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്‌വേഡ് ടൈപ്പുചെയ്‌തെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഈ എല്ലാ ഉപയോക്തൃവിവരവും മായ്‌ക്കുകയോ ചെയ്യുക."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"സ്‌ക്രീൻ ലോക്ക് മാറ്റുക"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"സ്‌ക്രീൻ ലോക്ക് മാറ്റുക."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"സ്‌ക്രീൻ ലോക്കുചെയ്യുക"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"സ്‌ക്രീൻ ലോക്കുകൾ എങ്ങനെ വേണമെന്നും എപ്പോൾ വേണമെന്നും എന്നത് നിയന്ത്രിക്കുക"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"എല്ലാ ഡാറ്റയും മായ്ക്കുക"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ഒരു ഫാക്‌ടറി ഡാറ്റ പുനഃസജ്ജീകരണം നടപ്പിലാക്കുന്നതിലൂടെ ടാബ്‌ലെറ്റിന്റെ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്‌ക്കുക."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ഒരു ഫാക്‌ടറി വിവരം പുനഃസജ്ജീകരിച്ചുകൊണ്ട് മുന്നറിയിപ്പുകളില്ലാതെ ടിവിയുടെ വിവരം മായ്ക്കുക."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ഒരു ഫാക്‌ടറി ഡാറ്റ പുനഃസജ്ജീകരണം നടപ്പിലാക്കുന്നതിലൂടെ ഫോണിന്റെ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്‌ക്കുക."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ഉപയോക്തൃ ഡാറ്റ മായ്‌ക്കുക"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"മുന്നറിയിപ്പൊന്നും നൽകാതെ ഈ ടാബ്‌ലെറ്റിലെ ഈ ഉപയോക്താവിന്റെ ഡാറ്റ മായ്‌ക്കുക."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"മുന്നറിയിപ്പൊന്നും നൽകാതെ ഈ ടിവിയിലെ ഈ ഉപയോക്താവിന്റെ ഡാറ്റ മായ്‌ക്കുക."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"മുന്നറിയിപ്പൊന്നും നൽകാതെ ഈ ഫോണിലെ ഈ ഉപയോക്താവിന്റെ ഡാറ്റ മായ്‌ക്കുക."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ഉപകരണ ഗ്ലോബൽ പ്രോക്‌സി സജ്ജീകരിക്കുക"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"നയം പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുമ്പോൾ ഉപകരണ ഗ്ലോബൽ പ്രോക്സി ഉപയോഗിക്കുന്നത് സജ്ജമാക്കുക. ആദ്യ ഉപകരണ അഡ്‌മിൻ മാത്രമേ ഫലപ്രദമായ ഗ്ലോബൽ പ്രോക്സി സജ്ജമാക്കൂ."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ലോക്ക്-സ്‌ക്രീൻ പാസ്‌വേഡ് കാലഹരണപ്പെടൽ സജ്ജീകരിക്കുക"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ലോക്ക്-സ്‌ക്രീൻ പാസ്‌വേഡുകൾ എത്ര ഇടവേളകളിൽ മാറ്റണമെന്ന് നിയന്ത്രിക്കുക"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"നയം പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുമ്പോൾ ഉപകരണ ഗ്ലോബൽ പ്രോക്‌സി ഉപയോഗിക്കുന്നത് സജ്ജമാക്കുക. ഉപകരണ ഉടമയ്‌ക്ക് മാത്രമേ ഗ്ലോബൽ പ്രോക്‌സി സജ്ജമാക്കാനാകൂ."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡ് കാലഹരണപ്പെടൽ സജ്ജമാക്കുക"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡ്, PIN അല്ലെങ്കിൽ പാറ്റേൺ എപ്പോഴൊക്കെ മാറ്റണമെന്നത് നിയന്ത്രിക്കുക."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"സംഭരണ എൻക്രിപ്‌ഷൻ സജ്ജീകരിക്കുക"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"സംഭരിച്ച അപ്ലിക്കേഷൻ ഡാറ്റ എൻക്രിപ്റ്റുചെയ്യേണ്ടതുണ്ട്."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ക്യാമറകൾ പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"എല്ലാ ഉപകരണ ക്യാമറകളുടേയും ഉപയോഗം തടയുക."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"കീഗാർഡിലെ സവിശേഷതകൾ പ്രവർത്തനരഹിതമാക്കുക"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"കീഗാർഡിലെ ചില സവിശേഷതകളുടെ ഉപയോഗം തടയുക."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"സ്‌ക്രീൻ ലോക്കിന്റെ ഫീച്ചറുകൾ പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"സ്‌ക്രീൻ ലോക്കിലെ ചില ഫീച്ചറുകളുടെ ഉപയോഗം തടയുക."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"വീട്ടിലെ ഫോൺ"</item>
     <item msgid="869923650527136615">"മൊബൈൽ"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കാൻ <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു. ടച്ച് വഴി പര്യവേക്ഷണം ചെയ്യൽ ഓൺ ചെയ്യുമ്പോൾ, നിങ്ങളുടെ വിരലിനടിയിലുള്ളവയുടെ വിവരണം കേൾക്കാനോ കാണാനോ അല്ലെങ്കിൽ ഫോണുമായി സംവദിക്കുന്ന ജെസ്റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 മാസം മുമ്പുള്ളത്"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ഒരു മാസം മുമ്പ്"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 നിമിഷം മുമ്പ്"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 മിനിറ്റ് മുമ്പ്"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 മണിക്കൂര്‍ മുമ്പ്"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"കഴിഞ്ഞ <xliff:g id="COUNT">%d</xliff:g> ദിവസം"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">അവസാന <xliff:g id="COUNT_1">%d</xliff:g> ദിവസം</item>
+      <item quantity="one">അവസാന <xliff:g id="COUNT_0">%d</xliff:g> ദിവസം</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"കഴിഞ്ഞ മാസം"</string>
     <string name="older" msgid="5211975022815554840">"പഴയത്"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ഇന്നലെ"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ഒരു മിനിറ്റിൽ"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"നാളെ"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"ഒരു നിമിഷം മുമ്പ്"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"ഒരു മിനിറ്റ് മുമ്പ്"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ് മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 മണിക്കൂര്‍ മുമ്പ്"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ഇന്നലെ"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ദിവസം മുമ്പ്"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ഒരു നിമിഷത്തിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> നിമിഷത്തിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ഒരു മിനിറ്റിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ഒരു മണിക്കൂറിനുള്ളിൽ"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂറിനുള്ളിൽ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"നാളെ"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> ദിവസത്തിനുള്ളിൽ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>-ന്"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>-ൽ"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"ആഴ്‌ച"</string>
     <string name="year" msgid="4001118221013892076">"വര്‍ഷം"</string>
     <string name="years" msgid="6881577717993213522">"വർഷം"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 സെക്കൻഡ്"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> സെക്കൻഡ്"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"ഒരു മിനിറ്റ്"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ്"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"ഒരു മണിക്കൂർ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> സെക്കൻഡ്</item>
+      <item quantity="one">ഒരു സെക്കൻഡ്</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> മിനിറ്റ്</item>
+      <item quantity="one">ഒരു മിനിറ്റ്</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> മണിക്കൂർ</item>
+      <item quantity="one">ഒരു മണിക്കൂർ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"വീഡിയോ പ്രശ്‌നം"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ഈ വീഡിയോ ഈ ഉപകരണത്തിൽ സ്ട്രീം ചെയ്യുന്നതിന് സാധുവായതല്ല."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ഈ വീഡിയോ പ്ലേ ചെയ്യാനായില്ല."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ആരംഭിക്കുന്നു…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"സംഭരണം ഒപ്‌റ്റിമൈസ് ചെയ്യുന്നു."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> അപ്ലിക്കേഷൻ ഓപ്റ്റിമൈസ് ചെയ്യുന്നു."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> തയ്യാറാക്കുന്നു."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"അപ്ലിക്കേഷനുകൾ ആരംഭിക്കുന്നു."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ബൂട്ട് ചെയ്യൽ പൂർത്തിയാകുന്നു."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> പ്രവർത്തിക്കുന്നു"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"പുതിയ അപ്ലിക്കേഷൻ ആരംഭിക്കരുത്."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ആരംഭിക്കുക"</string>
     <string name="new_app_description" msgid="1932143598371537340">"സംരക്ഷിക്കാതെ തന്നെ പഴയ അപ്ലിക്കേഷൻ നിർത്തുക."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"വാചകസന്ദേശത്തിനായി ഒരു പ്രവർത്തനം തിരഞ്ഞെടുക്കുക"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"റിംഗർ വോളിയം"</string>
     <string name="volume_music" msgid="5421651157138628171">"മീഡിയ വോളിയം"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ഒന്നുമില്ല"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"റിംഗ്ടോണുകൾ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"അജ്ഞാത റിംഗ്‌ടോൺ"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi നെറ്റ്‌വർക്ക് ലഭ്യമാണ്"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi നെറ്റ്‌വർക്കുകൾ ലഭ്യമാണ്"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"ലഭ്യമായ Wi-Fi നെറ്റ്‌വർക്ക് തുറക്കുക"</item>
-    <item quantity="other" msgid="7915895323644292768">"ലഭ്യമായ Wi-Fi നെറ്റ്‌വർക്കുകൾ തുറക്കുക"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi നെറ്റ്‌വർക്കുകൾ ലഭ്യമാണ്</item>
+      <item quantity="one">Wi-Fi നെറ്റ്‌വർക്ക് ലഭ്യമാണ്</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">ലഭ്യമായ Wi-Fi നെറ്റ്‌വർക്കുകൾ തുറക്കുക</item>
+      <item quantity="one">ലഭ്യമായ Wi-Fi നെറ്റ്‌വർക്ക് തുറക്കുക</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"നെറ്റ്‌വർക്കിൽ സൈൻ ഇൻ ചെയ്യുക"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" മോശം ഇന്റർനെറ്റ് കണക്ഷനാണുള്ളത്."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"അപ്ലിക്കേഷൻ %1$s Wifi നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റുചെയ്യാൻ താൽപ്പര്യപ്പെടുന്നു %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ഒരു അപ്ലിക്കേഷൻ"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ഡയറക്‌ട്"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ഡയറക്റ്റ് ആരംഭിക്കുക. ഇത് Wi-Fi ക്ലയന്റ്/ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കും."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi ഡയറക്റ്റ് ആരംഭിക്കാനായില്ല."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ശരി"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"മീഡിയ ഉപകരണമായി കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"ഒരു ക്യാമറയായി കണക്‌റ്റുചെയ്‌തു"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI ഉപകരണമായി കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ഇൻസ്‌റ്റാളറായി കണക്‌റ്റുചെയ്തു"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ഒരു USB ആക്‌സസ്സറി കണക്റ്റുചെയ്‌തു"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"മറ്റ് USB ഓപ്‌ഷനുകൾക്കായി സ്പർശിക്കുക."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ഒഴിവാക്കുക"</string>
     <string name="no_matches" msgid="8129421908915840737">"പൊരുത്തപ്പെടലുകൾ ഒന്നുമില്ല"</string>
     <string name="find_on_page" msgid="1946799233822820384">"പേജിൽ കണ്ടെത്തുക"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"ഒരു പൊരുത്തം"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> / <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> / <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">ഒരു പൊരുത്തം</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"പൂർത്തിയായി"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB കാർഡ് അൺമൗണ്ടുചെയ്യുന്നു…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD കാർഡ് അൺമൗണ്ടുചെയ്യുന്നു…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"നിയന്ത്രണങ്ങൾ പരിഷ്‌ക്കരിക്കാൻ ഒരു പിൻ സൃഷ്‌ടിക്കുക"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"പിൻ നമ്പറുകൾ പൊരുത്തപ്പെടുന്നില്ല. വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"പിൻ തീരെ ചെറുതാണ്. 4 അക്കമെങ്കിലും ഉണ്ടായിരിക്കണം."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"ഒരു സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക</item>
+      <item quantity="one">ഒരു സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"പൂർണ്ണസ്‌ക്രീനിൽനിന്നും പുറത്തുകടക്കുന്നതിന് മുകളിൽ നിന്നും താഴേക്ക് സ്വൈപ്പുചെയ്യുക."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"പൂർണ്ണ സ്‌ക്രീനിൽ കാണുന്നു"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"അവസാനിപ്പിക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പുചെയ്യുക."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"മനസ്സിലായി"</string>
     <string name="done_label" msgid="2093726099505892398">"പൂർത്തിയാക്കി"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ചാക്രികമായി മണിക്കൂറുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'കാഴ്ച\' എന്നിവ ഒരേ സമയം സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ, കാഴ്ച സ്‌പർശിച്ച് പിടിക്കുക."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"സ്ക്രീൻ പിൻ ചെയ്തിരിക്കുന്നു. നിങ്ങളുടെ ഓർഗനൈസേഷൻ അൺപിൻ ചെയ്യൽ അനുവദിക്കുന്നില്ല."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"സ്ക്രീൻ പിൻ ചെയ്തു"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"സ്ക്രീൻ അൺപിൻ ചെയ്തു"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പിൻ ആവശ്യപ്പെടുക"</string>
@@ -1844,22 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി സേവർ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്‌ക്കുകയും വൈബ്രേഷനെയും മിക്ക പശ്ചാത്തല വിവരത്തെയും പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. ഇമെയിൽ, സന്ദേശമയയ്‌ക്കൽ, സമന്വയിപ്പിക്കലിനെ ആശ്രയിച്ചുള്ള മറ്റ് അപ്ലിക്കേഷനുകൾ എന്നിവ നിങ്ങൾ തുറക്കുന്നതുവരെ അപ്‌ഡേറ്റുചെയ്യാനിടയില്ല.\n\nനിങ്ങളുടെ ഉപകരണം ചാർജ്ജുചെയ്യുമ്പോൾ ബാറ്ററി സേവർ സ്വയം ഓഫാകും."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ന് നിങ്ങളുടെ കാലാവധി അവസാനിക്കുന്നതുവരെ"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"പ്രവർത്തനരഹിതമായിരിക്കുന്ന സമയം അവസാനിക്കുന്നതുവരെ"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for zen_mode_duration_minutes_summary:other (2787867221129368935) -->
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ഒരു മണിക്കൂർ സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> വരെ)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d മണിക്കൂർ സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> വരെ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ഒരു മിനിറ്റ് ദൈർഘ്യം"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d മിനിറ്റ് ദൈർഘ്യം"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ഒരു മണിക്കൂർ ദൈർഘ്യം"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d മണിക്കൂർ ദൈർഘ്യം"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d മിനിറ്റ് സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> വരെ)</item>
+      <item quantity="one">ഒരു മിനിറ്റ് സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> വരെ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d മണിക്കൂർ സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> വരെ)</item>
+      <item quantity="one">ഒരു മണിക്കൂർ സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> വരെ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d മിനിറ്റ് സമയത്തേക്ക്</item>
+      <item quantity="one">ഒരു മിനിറ്റ് സമയത്തേക്ക്</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d മണിക്കൂർ സമയത്തേക്ക്</item>
+      <item quantity="one">ഒരു മണിക്കൂർ സമയത്തേക്ക്</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"അവ്യക്തം"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"നിങ്ങൾ ഇത് ഓ‌ഫാക്കും വരെ"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ചുരുക്കുക"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-നുള്ള അടുത്ത അലാറം വരെ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"അടുത്ത അലാറം വരെ"</string>
@@ -1872,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS അഭ്യർത്ഥന, DIAL അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS അഭ്യർത്ഥന, USSD അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS അഭ്യർത്ഥന, പുതിയ SS അഭ്യർത്ഥനയായി പരിഷ്‌ക്കരിച്ചു."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB പെരിഫറൽ പോർട്ട്"</string>
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 2094239..ba53123 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Гарчиггүй&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Утасны дугаар байхгүй)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Тодорхойгүй"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"дуут шуудан"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM картны PUK-түгжигдсэн. Тайлах бол PUK кодыг бичнэ үү."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM картын хаалтыг болиулах бол PUK2-г бичнэ үү."</string>
     <string name="enablePin" msgid="209412020907207950">"Амжилтгүй боллоо, СИМ/РҮИМ түгжээг идэвхжүүлнэ үү."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Таны СИМ түгжигдэхээс өмнө танд <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдлээ."</item>
-    <item quantity="other" msgid="7530597808358774740">"СИМ түгжигдэхээс өмнө танд <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдлээ."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Таны СИМ түгжигдэхээс өмнө танд <xliff:g id="NUMBER_1">%d</xliff:g> оролдлого хийх боломж үлдлээ. </item>
+      <item quantity="one">Таны СИМ түгжигдэхээс өмнө танд <xliff:g id="NUMBER_0">%d</xliff:g> оролдлого хийх боломж үлдлээ. </item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Дуудлага хийгчийн ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Нислэгийн горим асав"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Нислэгийн горим унтарсан"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Тохиргоо"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Дуут туслах"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"маршрут нийлүүлэгчийн үйлчилгээтэй холбогдох"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Эзэмшигчид бүртгэгдсэн маршрут нийлүүлэгчтэй холбогдох  боломж олгоно. Энгийн апп-уудад хэзээ ч шаардагдахгүй."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ТВ оролт холбох"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Апп нь Ойролцоо Талбарын Холболт(NFC) таг, карт, болон уншигчтай холбогдох боломжтой."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"дэлгэцний түгжээг идэвхгүй болгох"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Апп нь түгжээ болон бусад холбоотой нууц үгийн аюулгүй байдлыг идэвхгүй болгох боломжтой. Жишээ нь бол утас нь дуудлага ирэх үед түгжээг идэвхгүй болгох ба дуудлага дуусахад буцаан идэвхтэй болгодог."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"хурууны хээний програм хангамжийг удирдах"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Хурууны хээний загварыг нэмэх эсвэл усгтах үйлдлийг хийх зөвшөөрлийг програмд олгодог."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"хурууны хээний програм хангамжийг ашиглах"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Баталгаажуулалт хийх зорилгоор хурууны хээний програм хамгамжийг ашиглах зөвшөөрлийг програмд олгодог"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"синк тохиргоог унших"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь акаунтын синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп акаунттай синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синкийг унтрааж асаах тохиргоо"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Сонгогчийн зорилтот үйлчилгээнд холбогдох"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Эзэмшигчид сонгогчийн зорилтот үйлчилгээний дээд түвшний интерфэйс рүү холбогдох боломжийг олгоно. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"нөхцөл нийлүүлэгч үйлчилгээнд холбох"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Эзэмшигчид нөхцөл нийлүүлэгч үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"медиа маршрут үйлчилгээтэй холбох"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Эзэмшигчид медиа маршрут үйлчилгээний дээр түвшний интерфэйст холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"дрийм үйлчилгээнд холбох"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Эзэмшигч нь дрийм үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"үүрэн компанийн нийлүүлсэн тохируулгын апп-г өдөөх"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"зөөгч зурвасын үйлчилгээнд холбох"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Эзэмшигчид зөөгч зурвасын үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Дэлгэц түгжих нууц үг болон ПИН кодны урт болон нийт тэмдэгтийн уртыг хянах."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Дэлгэц түгжигдсэн үед нууц үг буруу оруулалтын тоог хянах ба хэрэв хэт олон удаа нууц үгийг буруу оруулбал таблетыг түгжих болон таблетын бүх датаг арилгана"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Дэлгэцийн түгжээг тайлахад оруулсан буруу нууц үгийн давтамжийг хянаад телевиз-г түгж эсвэл буруу нууц үг хэт олон удаа орсон тохиолдолд телевиз-ийн бүх датаг устга."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Дэлгэц түгжигдсэн үед нууц үг буруу оруулалтын тоог хянах, ба хэрэв хэт олон удаа нууц үгийг буруу оруулбал утсыг түгжих болон утасны бүх датаг арилгана"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Дэлгэц түгжих нууц үгийг солих"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Дэлгэц түгжих нууц үгийг солих"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Дэлгэцийн түгжээг тайлахад оруулсан буруу нууц үгийн давтамжийг хянаж таблетыг түгжих эсвэл буруу нууц үгийг хэт олон удаа оруулсан тохиолдолд энэ хэрэглэгчийн мэдээллийг устгах."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Дэлгэцийн түгжээг тайлахад оруулсан буруу нууц үгийн давтамжийг хянаж телевизийг түгжих эсвэл буруу нууц үгийг хэт олон удаа оруулсан тохиолдолд энэ хэрэглэгчийн мэдээллийг устгах."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Дэлгэцийн түгжээг тайлахад оруулсан буруу нууц үгийн давтамжийг хянаж гар утсыг түгжих эсвэл буруу нууц үгийг хэт олон удаа оруулсан тохиолдолд энэ хэрэглэгчийн мэдээллийг устгах."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Дэлгэцийн түгжээг өөрчлөх"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Дэлгэцийн түгжээг өөрчлөх."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Дэлгэц түгжих"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Дэлгэц хэзээ яаж түгжихийг удирдах"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Бүх датаг арилгах"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Үйлдвэрийн дата утгыг өгсөнөөр таблетын дата шууд арилгагдана."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Анхааруулга өгөхгүйгээр үйлдвэрээс хийгдсэн тохиргоонд эргэн шилжих байдлаар телевиз-ийн датаг устга."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Үйлдвэрийн дата утгыг өгсөнөөр утасны дата шууд арилгагдана."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Хэрэглэгчийн мэдээллийг арилгах"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Анхааруулга өгөхгүйгээр энэ хэрэглэгчийн энэ таблет дээрх мэдээллийг устгах."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Анхааруулга өгөхгүйгээр энэ хэрэглэгчийн энэ телевизор дээрх мэдээллийг устгах."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Анхааруулга өгөхгүйгээр энэ хэрэглэгчийн энэ гар утсан дээрх мэдээллийг устгах."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Төхөрөөмжийн глобал проксиг тохируулах"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Бодлого идэвхтэй үед төхөөрөмжийн глобал проксиг ашиглахаар тохируулсан. Зөвхөн эхний төхөөрөмжийн админ л үр дүнтэй глобал проксиг тохируулна."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Дэлгэц түгжих нууц үгний хүчинтэй хугацааг тохируулах"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Дэлгэцний түгжих нууц үг хэр давтамжтай солигдохыг удирдах."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Бодлогыг ашиглах боломжтой үед төхөөрөмжийн олон улсын эрхийг тохируулах. Зөвхөн төхөөрөмж эзэмшигч нь олон улсын эрхийг тохируулах боломжтой."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Дэлгэц түгжих нууц үгний дуусах хугацааг тохируулах"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Дэлгэц түгжих нууц үг, ПИН эсвэл нууц үгний хэвийг хэр тогтмол хугацаанд сольж байх тохируулгыг өөрчлөх."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Сангийн шифрлэхийг тохируулах"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Хадгалагдсан апп дата шифрлэгдэх шаардлагатай"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Камер идэвхгүй болгох"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Төхөөрөмжийн бүх камерийг ашиглахгүй."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Түлхүүр хамгаалтын функцийг унтраах"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Түлхүүр хамгаалалтын зарим функцийг ашиглахыг хориглох."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Дэлгэцийн түгжээн дээрх үйлдлийг идэвхгүй болгох"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Дэлгэц түгжих зарим үйлдлийг ашиглахаас урьдчилан хамгаалах."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Гэрийн"</item>
     <item msgid="869923650527136615">"Мобайл"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрч танихыг идэвхжүүлэхийг шаардаж байна. Хүрч таних идэвхжсэн тохиолдолд та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба утастайгаа дохиогоор харилцах боломжтой."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 сарын өмнө"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 сарын өмнө"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секундын өмнө"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> секундын өмнө"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минутын өмнө"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 цагийн өмнө"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Сүүлийн <xliff:g id="COUNT">%d</xliff:g> өдөр"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Сүүлийн <xliff:g id="COUNT_1">%d</xliff:g> өдөр</item>
+      <item quantity="one">Сүүлийн <xliff:g id="COUNT_0">%d</xliff:g> өдөр</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Сүүлийн сар"</string>
     <string name="older" msgid="5211975022815554840">"Хуучин"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"өчигдөр"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 секундын дараа"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> секундын дараа"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 минутын дараа"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 цагийн дараа"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"маргааш"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 секундын өмнө"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 мин өмнө"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> минутын өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 цагийн өмнө"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> цагийн өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"өчигдөр"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> өдрийн өмнө"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 сек дараа"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> сек дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 мин дараа"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> минутын дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 цагийн дараа"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> цагийн дараа"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"маргааш"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> өдрийн дараа"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"7 хоног"</string>
     <string name="year" msgid="4001118221013892076">"жил"</string>
     <string name="years" msgid="6881577717993213522">"жил"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунд"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> секунд"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 минут"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минут"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 цаг"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> цаг"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="one">1 секунд</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минут</item>
+      <item quantity="one">1 минут</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> цаг</item>
+      <item quantity="one">1 цаг</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Видео алдаа"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Энэ видео энэ төхөөрөмж дээр урсгалаар гарч чадахгүй."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Энэ видеог тоглуулах боломжгүй."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Андройд эхэлж байна..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Хадгалалтыг сайжруулж байна."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>-н <xliff:g id="NUMBER_0">%1$d</xliff:g> апп-г тохируулж байна."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Бэлдэж байна <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Апп-г эхлүүлж байна."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Эхлэлийг дуусгаж байна."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ажиллаж байна"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Шинэ апп-г эхлүүлж болохгүй."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> эхлүүлэх"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Хуучин апп-г хадгалахгүйгээр зогсооно уу."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Текст илгээх үйлдлийг сонгох"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Хонхны аяны хэмжээ"</string>
     <string name="volume_music" msgid="5421651157138628171">"Медиа дууны хэмжээ"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Алийг нь ч биш"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Хонхны ая"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Үл мэдэгдэх хонхны ая"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi сүлжээ ашиглах боломжтой"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi сүлжээ ашиглах боломжгүй"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Нээллтэй Wi-Fi сүлжээ ашиглах боломжтой"</item>
-    <item quantity="other" msgid="7915895323644292768">"Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi сүлжээ ашиглах боломжтой</item>
+      <item quantity="one">Wi-Fi сүлжээ ашиглах боломжтой</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
+      <item quantity="one">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Сүлжээнд нэвтрэх"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" Интернет холболт муу байна."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Програм %1$s нь Wifi сүлжээ %2$s-тай холбох хүсэлтэй байна"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Аппликешн"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Шууд"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Шуудыг эхлүүлнэ үү. Энэ нь Wi-Fi клиент/холболтын цэг унтраана."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Шуудыг эхлүүлж чадсангүй."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Тийм"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Медиа төхөөрөмж болон холбогдов"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Камер болгон холбов"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI төхөөрөмж хэлбэрээр холбогдсон байна"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Суулгагч болгон холбогдсон"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB төхөөрөмжид холбогдов"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Бусад USB сонголт хийх бол хүрнэ үү."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Алгасах"</string>
     <string name="no_matches" msgid="8129421908915840737">"Илэрц алга"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Хуудаснаас олох"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 утга"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>-н <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>-н <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="one">1 үр дүн гарч ирсэн байна</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Дуусгах"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB санг салгаж байна…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD картыг салгаж байна…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Өөрчлөлтийг хязгаарлахад зориулан PIN үүсгэх"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN таарахгүй байна. Дахин оролдоно уу."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN хэт богино байна. Хамгийн багадаа 4 цифртэй байх ёстой."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 секундын дараа дахин оролдоно уу"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> секундын дараа дахин оролдоно уу"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секундын дараа дахин оролдоно уу</item>
+      <item quantity="one">1 секундын дараа дахин оролдоно уу</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Дараа дахин оролдоно уу"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Бүтэн дэлгэцээс гарахын тулд дээрээс нь доош шудрана уу."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Бүтэн дэлгэцээр үзэж байна"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ойлголоо"</string>
     <string name="done_label" msgid="2093726099505892398">"Дууссан"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Цаг гүйлгэгч"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Минут гүйлгэгч"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Энэ дэлгэцийг цуцлахын тулд Буцах болон Тойм-д зэрэг хүрч барина."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Энэ дэлгэцийг цуцлахын тулд Тойм харагдацанд хүрч барина."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Дэлгэцийг тогтоосон. Дэлгэц суллахыг таны байгууллага зөвшөөрөөгүй."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Дэлгэцийг сулласан"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
@@ -1844,24 +1813,22 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Батарей хадгалах функц нь таны төхөөрөмжийн цэнэгийг хадгалахын тулд гүйцэтгэлийг багасгаж, чичрэлтийг бууруулж, байршлын үйлчилгээнүүд болон бусад өгөгдлийн хэмжээг багасгадаг юм. И-мэйл, мессеж болон бусад синхрон хийдэг апликейшнүүд дараа дахин нээгдэх хүртлээ автоматаар шинэчлэлт хийхгүй.\n\nМөн батарей хадгалах функц нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтрах юм."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Таны уйтгартай байдал <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-д дуусах хүртэл"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Сул зогсолт дуусах хүртэл"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Нэг минутын турш (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> хүртэл)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d минутын турш (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> хүртэл)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Нэг цагийн турш (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> хүртэл)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d цагийн турш (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> хүртэл)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Нэг цагийн турш"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d цагийн турш"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other"> %1$d минутын турш ( <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> хүртэл)</item>
+      <item quantity="one">нэг минутын турш (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> хүртэл)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d цагийн турш (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> хүртэл)</item>
+      <item quantity="one">Нэг цагийн турш (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> хүртэл)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d минутын турш</item>
+      <item quantity="one">Нэг минутын турш</item>
+    </plurals>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for zen_mode_duration_hours (3938821308277433854) -->
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Тодорхойгүй"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Таныг унтраах хүртэл"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Хумих"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дахь дараагийн анхааруулга хүртэл"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Дараагийн анхааруулга хүртэл"</string>
@@ -1874,4 +1841,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS хүсэлтийг DIAL хүсэлт болгон өөрчилсөн байна"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS хүсэлтийг USSD хүсэлт болгон өөрчилсөн байна."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS хүсэлтийг шинэ SS хүсэлт болгон өөрчилсөн байна."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 81e234c..cea3828 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंद"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंद"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;अशीर्षकांकित&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(कोणताही फोन नंबर नाही)"</string>
     <string name="unknownName" msgid="6867811765370350269">"अज्ञात"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"व्हॉइसमेल"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"आपले सिम कार्ड PUK-लॉक केलेले आहे. ते अनलॉक करण्यासाठी PUK कोड टाइप करा."</string>
     <string name="needPuk2" msgid="4526033371987193070">"सिम कार्ड अनावरोधित करण्यासाठी PUK2 टाइप करा."</string>
     <string name="enablePin" msgid="209412020907207950">"अयशस्वी, सिम/RUIM लॉक सक्षम करा."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"सिम लॉक होण्‍यापूर्वी आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहे."</item>
-    <item quantity="other" msgid="7530597808358774740">"सिम लॉक होण्‍यापूर्वी आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहेत."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">सिम लॉक होण्यापूर्वी आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहे.</item>
+      <item quantity="other">सिम लॉक होण्यापूर्वी आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहेत.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"येणारा कॉलर ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"विमान मोड चालू आहे"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"विमान मोड बंद आहे"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग्ज"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -220,7 +219,7 @@
     <string name="permgroupdesc_location" msgid="5704679763124170100">"आपल्या प्रत्यक्ष स्थानाचे परीक्षण करेल."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"नेटवर्क संप्रेषण"</string>
     <string name="permgroupdesc_network" msgid="4478299413241861987">"विविध नेटवर्क वैशिष्ट्यांवर प्रवेश करेल."</string>
-    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"ब"</string>
+    <string name="permgrouplab_bluetoothNetwork" msgid="1585403544162128109">"ब्लूटुथ"</string>
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"ब द्वारे डिव्हाइसेसवर आणि नेटवर्कवर प्रवेश करेल."</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"ऑडिओ सेटिंग्ज"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"ऑडिओ सेटिंग्ज बदला."</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"होल्‍डरला दूरस्‍थ प्रदर्शनाच्‍या उच्च-दर्जाच्या इंटरफेसशी प्रतिबद्ध करण्‍याची अनुमती देते. सामान्‍य अ‍ॅप्‍ससाठी कधीही आवश्‍यक नसावे."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"विजेट सेवेवर प्रतिबद्ध व्हा"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"विजेट सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्‍यासाठी होल्‍डरला अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"एका मार्ग प्रदाता सेवेवर प्रतिबद्ध करा"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"कोणत्याही नोंदणीकृत मार्ग प्रदात्यांना प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यकता नसते."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"डिव्हाइस प्रशासनाशी संवाद साधा"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"डिव्हाइस प्रशासकाकडे अभिप्राय पाठविण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"एका टीव्ही इनपुटवर प्रतिबद्ध करा"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"फील्ड जवळील संप्रेषण (NFC) टॅग, कार्ड आणि वाचक यांच्यासह संप्रेषण करण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"आपले स्क्रीन लॉक अक्षम करा"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कीलॉक आणि कोणतीही संबद्ध संकेतशब्द सुरक्षितता अक्षम करण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, येणारा फोन कॉल प्राप्त करताना फोन कीलॉक अक्षम करतो, नंतर जेव्हा कॉल समाप्त होतो तेव्हा तो कीलॉक पुन्हा-सक्षम करतो."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"फिंगरप्रिंट हार्डवेअर व्यवस्थापित करा"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"वापर करण्याकरिता फिंगरप्रिंट टेम्पलेट जोडण्यासाठी आणि हटविण्यासाठी पद्धती रद्द करण्यास अॅपला अनुमती देते."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"फिंगरप्रिंट हार्डवेअर वापरा"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"प्रमाणीकरणाकरिता फिंगरप्रिंट हार्डवेअरचा वापर करण्यासाठी अॅपला अनुमती देते"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"संकालन सेटिंग्‍ज वाचा"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"खात्याच्या संकालन सेटिंग्ज वाचण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"संकालन चालू आणि बंद करा टॉगल करा"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"अनुप्रयोगाला इतर अ‍ॅप्‍सद्वारे पोस्‍ट केलेल्‍यांसह पुनर्प्राप्त करण्‍याची, तपासण्‍याची आणि सूचना साफ करण्‍याची अनुमती देते."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना ऐकणार्‍या सेवेशी प्रतिबद्ध"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्‍डरला सूचना ऐकणार्‍या सेवेच्‍या शीर्ष-दर्जाच्या इंटरफेसशी प्रतिबद्ध करण्‍याची अनुमती देते. सामान्‍य अ‍ॅप्‍ससाठी कधीही आवश्‍यक नसावे."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एका निवडकर्ता लक्ष्य सेवेसाठी प्रतिबद्ध करा"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"धारकास निवडकर्ता लक्ष्य सेवेच्या शीर्ष-स्‍तराच्या इंटरफेसशी प्रतिबद्ध करण्‍यास अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"एका अट प्रदाता सेवेवर प्रतिबद्ध करा"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"स्थिती प्रदाता सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मीडिया मार्ग सेवेशी प्रतिबद्ध व्हा"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"मीडीया मार्ग सेवेच्या शीर्ष-दर्जाच्या इंटरफेसशी प्रतिबद्ध होण्यासाठी होल्डरला अनुमती द्या. सामान्य अॅप्ससाठी कधीही आवश्यकता नसावी."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"स्‍वप्न सेवेवर प्रतिबद्ध करा"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"होल्‍डरला स्‍वप्नसेवेच्या शीर्ष-स्‍तराच्या इंटरफेसशी प्रतिबद्ध करण्‍यास अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहकाद्वारे-प्रदान केलेल्‍या कॉन्‍फिगरेशन अ‍ॅपची विनंती करा"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"एका वाहक संदेशन सेवेसाठी प्रतिबद्ध"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"वाहक संदेशन सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक संकेतशब्दांमध्ये अनुमती दिलेली लांबी आणि वर्ण नियंत्रित करा."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक संकेतशब्द आणि पिन मध्ये अनुमती दिलेली लांबी आणि वर्ण नियंत्रित करा."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक प्रयत्नांचे परीक्षण करा"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅब्लेट लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास टॅब्लेटचा सर्व डेटा मिटवा."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास फोनचा सर्व डेटा मिटवा."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"स्क्रीन-अनलॉक संकेतशब्द बदला"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"स्क्रीन-अनलॉक संकेतशब्द बदला."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टॅब्लेट लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"स्क्रीन लॉक बदला"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"स्क्रीन लॉक बदला."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"स्क्रीन लॉक करा"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"स्क्रीन कशी आणि केव्हा लॉक होते ते नियंत्रित करा."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"सर्व डेटा मिटवा"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"फॅक्टरी डेटा रीसेट करून चेतावणीशिवाय टॅब्लेटचा डेटा मिटवा."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"फॅक्टरी डेटा रीसेट करून चेतावणी न देता टीव्हीचा डेटा मिटवा."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"फॅक्टरी डेटा रीसेट करून चेतावणीशिवाय फोनचा डेटा मिटवा."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"वापरकर्ता डेटा मिटवा"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"कोणत्याही चेतावणी शिवाय या वापरकर्त्याचा या टॅब्लेटवरील डेटा मिटवा."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"कोणत्याही चेतावणी शिवाय या वापरकर्त्याचा या टीव्ही वरील डेटा मिटवा."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"कोणत्याही चेतावणी शिवाय या वापरकर्त्याचा या फोनवरील डेटा मिटवा."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"डिव्हाइस समग्र प्रॉक्सी सेट करा"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"धोरण सक्षम असताना वापरण्यासाठी डिव्हाइस समग्र प्रॉक्सी सेट करा. फक्त प्रथम डिव्हाइस प्रशासक परिणामकारक समग्र प्रॉक्सी सेट करते."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"लॉक-स्क्रीन संकेतशब्द कालबाह्यता सेट करा"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"लॉक-स्क्रीन संकेतशब्द किती वारंवार बदलणे आवश्यक आहे ते नियंत्रित करा."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"धोरण सक्षम असताना वापरण्यासाठी डिव्हाइस समग्र प्रॉक्सी सेट करा. फक्त डिव्हाइस मालक समग्र प्रॉक्सी सेट करु शकतो."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रीन लॉक संकेतशब्द कालबाह्यता सेट करा"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"लॉक-स्क्रीन संकेतशब्द किती वारंवार बदलणे आवश्यक आहे ते बदला."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"संचयन कूटबद्धीकरण सेट करा"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संचयित अॅप डेटा कूटबद्ध केला जाणे आवश्यक आहे."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"कॅमेरे अक्षम करा"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"सर्व डिव्हाइस कॅमेर्‍यांचा वापर प्रतिबंधित करा."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"कीगार्डमधील वैशिष्ट्ये अक्षम करा"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"कीगार्डमधील काही वैशिष्ट्यांचा वापर प्रतिबंधित करा."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"स्क्रीन लॉकची वैशिष्ट्ये अक्षम करा"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"स्क्रीन लॉकच्या काही वैशिष्ट्यांचा वापर प्रतिबंधित करा."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"घर"</item>
     <item msgid="869923650527136615">"मोबाइल"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> स्पर्श करून एक्सप्लोर करा सक्षम करू इच्छिते. स्पर्श करून एक्सप्लोर करा चालू असते, तेव्हा आपण आपल्या बोटाखाली काय आहे त्याचे वर्णन ऐकू किंवा पाहू शकता किंवा फोनसह संवाद साधण्यासाठी जेश्चर करू शकता."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 महिन्यापूर्वी"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 महिन्यापूर्वी"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 सेकंदापूर्वी"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 मिनिटापूर्वी"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 तासापूर्वी"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अंतिम <xliff:g id="COUNT">%d</xliff:g> दिवस"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">अंतिम <xliff:g id="COUNT_1">%d</xliff:g> दिवस</item>
+      <item quantity="other">अंतिम <xliff:g id="COUNT_1">%d</xliff:g> दिवस</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"अंतिम महिना"</string>
     <string name="older" msgid="5211975022815554840">"अधिक जुने"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"काल"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 सेकंदात"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 मिनिटात"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 तासात"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्‍ये"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"उद्या"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 सेकंदापूर्वी"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 मिनिटापूर्वी"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 तासापूर्वी"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> तासांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"काल"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिवसांपूर्वी"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 सेकंदामध्‍ये"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 मिनिटामध्‍ये"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनिटांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 तासात"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> तासांमध्‍ये"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"उद्या"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> दिवसांमध्‍ये"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> रोजी"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> वाजता"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मध्ये"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"आठवडे"</string>
     <string name="year" msgid="4001118221013892076">"वर्ष"</string>
     <string name="years" msgid="6881577717993213522">"वर्षे"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 सेकंद"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> सेकंद"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 मिनिट"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> मिनिटे"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 तास"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> तास"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंद</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंद</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> मिनिट</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> मिनिटे</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> तास</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> तास</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"व्हिडिओ समस्या"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"या डिव्हाइसवर प्रवाहित करण्यासाठी हा व्हिडिओ वैध नाही."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"हा व्हिडिओ प्ले करू शकत नाही."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android प्रारंभ करत आहे…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"संचयन ऑप्टिमाइझ करत आहे."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> पैकी <xliff:g id="NUMBER_0">%1$d</xliff:g> अॅप ऑप्टिमाइझ करत आहे."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करीत आहे."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"अॅप्स प्रारंभ करत आहे."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त होत आहे."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चालत आहे"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नवीन अॅप प्रारंभ करू नका."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करा"</string>
     <string name="new_app_description" msgid="1932143598371537340">"जतन न करता जुना अॅप थांबवा."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"रिंगर व्हॉल्यूम"</string>
     <string name="volume_music" msgid="5421651157138628171">"मीडिया व्हॉल्यूम"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"काहीही नाही"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिंगटोन"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"वाय-फाय नेटवर्क उपलब्‍ध"</item>
-    <item quantity="other" msgid="4192424489168397386">"वाय-फाय नेटवर्क उपलब्‍ध"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"खुले वाय-फाय नेटवर्क उपलब्‍ध"</item>
-    <item quantity="other" msgid="7915895323644292768">"खुले वाय-फाय नेटवर्क उपलब्‍ध"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">वाय-फाय नेटवर्क उपलब्ध</item>
+      <item quantity="other">वाय-फाय नेटवर्क उपलब्ध</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">खुले वाय-फाय नेटवर्क उपलब्ध</item>
+      <item quantity="other">खुले वाय-फाय नेटवर्क उपलब्ध</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"वाय-फाय नेटवर्कवर साइन इन करा"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"नेटवर्क वर साइन इन करा"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" खराब इंटरनेट कनेक्शन आहे."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s अनुप्रयोग %2$s वायफाय नेटवर्कशी कनेक्ट करू इच्छित आहे"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"अनुप्रयोग"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाय-फाय थेट"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाय-फाय थेट प्रारंभ करा. हे वाय-फाय क्लायंट/हॉटस्पॉट बंद करेल."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाय-फाय थेट प्रारंभ करू शकलो नाही."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"मीडिया हिव्‍हाइस म्‍हणून कनेक्‍ट केले"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"कॅमेरा म्हणून कनेक्ट केले"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"एक MIDI डिव्हाइस म्हणून कनेक्ट केले आहे"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"स्थापनकर्ता म्हणून कनेक्ट केले"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB उपसाधनावर कनेक्ट केले"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"अन्य USB पर्यायांसाठी स्पर्श करा."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"वगळा"</string>
     <string name="no_matches" msgid="8129421908915840737">"कोणत्याही जुळण्या नाहीत"</string>
     <string name="find_on_page" msgid="1946799233822820384">"पृष्ठावर शोधा"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 जुळणी"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> पैकी <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g> पैकी <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> पैकी <xliff:g id="INDEX">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"पूर्ण केले"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB संचयन अनमाउंट करत आहे…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD कार्ड अनमाउंट करत आहे…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबंध सुधारित करण्‍यासाठी पिन तयार करा"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"पिन जुळत नाहीत. पुन्‍हा प्रयत्न करा."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"पिन खूप लहान आहे. किमान 4 अंकांचा असणे आवश्‍यक आहे."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 सेकंदात पुन्‍हा प्रयत्न करा"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्‍ये पुन्‍हा प्रयत्न करा"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> सेकंदात पुन्हा प्रयत्न करा</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"नंतर पुन्हा प्रयत्न करा"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्ण स्क्रीनमधून निर्गमन करण्‍यासाठी शीर्षावरून खाली स्‍वाइप करा."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूर्ण स्क्रीन पाहत आहात"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"समजले"</string>
     <string name="done_label" msgid="2093726099505892398">"पूर्ण झाले"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"तास परिपत्रक स्लायडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनिटे परिपत्रक स्लायडर"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ही स्क्रीन अनपिन करण्यासाठी, एकाच वेळी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ही स्क्रीन अनपिन करण्यासाठी, विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रीन पिन केली आहे. आपल्या संस्थेद्वारे अनपिन करण्यास अनुमती नाही."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्‍यापूर्वी पिन साठी विचारा"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"बॅटरीचे आयुष्य सुधारित करण्‍यात मदत करण्यासाठी, बॅटरी बचतकर्ता आपल्या डिव्हाइसचे कार्यप्रदर्शन कमी करतो आणि कंपन, स्थान सेवा आणि बराच पार्श्वभूमी डेटा मर्यादित करतो. संकालनावर अवलंबून असणारे ईमेल, संदेशन आणि इतर अ‍ॅप्स आपण उघडल्याशिवाय अद्यतनित होऊ शकत नाहीत.\n\nआपले डिव्हाइस चार्ज होत असते तेव्हा बॅटरी बचतकर्ता स्वयंचलितपणे बंद होतो."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"आपला कार्य न करण्याचा कालावधी <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> वाजता समाप्त होईपर्यंत"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"आपला कार्य न करण्याचा कालावधी समाप्त होईपर्यंत"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"एका मिनिटासाठी (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> पर्यंत)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> पर्यंत)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"एका तासासाठी (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> पर्यंत)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d तासांसाठी (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> पर्यंत)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"एक मिनिटासाठी"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d मिनिटांसाठी"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"एका तासासाठी"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d तासांसाठी"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d मिनिटासाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
+      <item quantity="other">%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d तासासाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
+      <item quantity="other">%1$d तासांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d मिनिटासाठी</item>
+      <item quantity="other">%d मिनिटांसाठी</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d तासासाठी</item>
+      <item quantity="other">%d तासांसाठी</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"अनिश्‍चितपणे"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"आपण हे बंद करेपर्यंत"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"संक्षिप्त करा"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> वाजता पुढील अलार्मपर्यंत"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"पुढील अलार्मपर्यंत"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS विनंती डायल विनंतीवर सुधारित केली आहे."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS विनंती USSD विनंतीवर सुधारित केली आहे."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS विनंती नवीन SS विनंतीवर सुधारित केली आहे."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB बाह्यवर्ती पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index e500742..255d2e8 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> saat"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> saat"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Tidak bertajuk&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Tiada nombor telefon)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Tidak diketahui"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mel suara"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Kad SIM anda dikunci PUK. Taipkan kod PUK untuk membuka kuncinya."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Taipkan PUK2 untuk menyahsekat kad SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Tidak berjaya, dayakan Kunci SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM dikunci."</item>
-    <item quantity="other" msgid="7530597808358774740">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM dikunci."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Anda ada <xliff:g id="NUMBER_1">%d</xliff:g> cubaan lagi sebelum SIM dikunci.</item>
+      <item quantity="one">Anda ada <xliff:g id="NUMBER_0">%d</xliff:g> cubaan lagi sebelum SIM dikunci.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID Pemanggil Masuk"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Tetapan"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"terikat kepada perkhidmatan pembekal laluan"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Membenarkan pemegang untuk terikat kepada mana-mana pembekal laluan yang berdaftar. Tidak sekali-kali diperlukan untuk apl normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"ikat kepada input TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Membenarkan apl berkomunikasi dengan teg, kad dan pembaca Komunikasi Medan Dekat (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"lumpuhkan kunci skrin anda"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Membenarkan apl melumpuhkan kunci kekunci dan sebarang keselamatan kata laluan yang berkaitan. Sebagai contoh, telefon melumpuhkan kunci kekunci apabila menerima panggilan telefon masuk kemudian mendayakan semula kunci kekunci apabila panggilan selesai."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"urus perkakasan cap jari"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Membenarkan apl menggunakan kaedah untuk menambahkan dan memadamkan templat cap jari untuk digunakan."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan perkakasan cap jari"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Membenarkan apl menggunakan perkakasan cap jari untuk pengesahan"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"membaca tetapan penyegerakan"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Membenarkan apl membaca tetapan segerak untuk akaun. Sebagai contoh, ini boleh menentukan sama ada apl Orang disegerakkan dengan akaun."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"togol segerak hidup dan mati"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"terikat kepada perkhidmatan sasaran pemilih"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan sasaran pemilih. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"terikat kepada perkhidmatan pembekal keadaan"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pembekal keadaan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"terikat kepada perkhidmatan laluan media"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan laluan media. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"terikat kepada perkhidmatan impian"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan impian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gunakan apl konfigurasi yang disediakan oleh pembawa"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"terikat kepada perkhidmatan pemesejan pembawa"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi perkhidmatan pemesejan pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan  dan PIN kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Memantau bilangan kata laluan yang tersilap ditaip apabila membuka skrin, dan mengunci tablet atau memadam semua data tablet jika terlalu banyak kesilapan menaip kata laluan."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Pantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan kunci TV atau padam semua data TV jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Memantau bilangan kata laluan salah yang ditaip semasa membuka skrin, dan mengunci telefon atau memadam semua data telefon jika terlalu banyak kata laluan salah ditaip."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Tukar kata laluan buka kunci skrin"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Tukar kata laluan buka kunci skrin."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Pantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan kunci tablet atau padam semua data pengguna ini jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Pantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan kunci TV atau padam semua data pengguna ini jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Pantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan kunci telefon atau padam semua data pengguna ini jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Tukar kunci skrin"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Tukar kunci skrin."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Kunci skrin"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Mengawal cara dan bila skrin dikunci."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Padamkan semua data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Memadamkan data tablet tanpa amaran dengan melakukan tetapan semula data kilang."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Padam data TV tanpa amaran dengan melakukan tetapan semula data kilang."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Memadamkan data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Padam data pengguna"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Padam data pengguna ini pada tablet ini tanpa amaran."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Padam data pengguna ini pada TV ini tanpa amaran."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Padam data pengguna ini pada telefon ini tanpa amaran."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Tetapkan proksi global peranti"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Menetapkan proksi global peranti untuk digunakan sementara dasar didayakan. Hanya pentadbir peranti pertama boleh menetapkan proksi global dengan berkesan."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ttpkn tmt tmph k/lln kci skrin"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kawal kekerapan penukaran kata laluan kunci skrin."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Tetapkan proksi global peranti untuk digunakan sementara dasar didayakan. Hanya pemilik peranti boleh menetapkan proksi global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Tetapkan tempoh tamat kata laluan kunci skrin"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Tukar kekerapan penukaran kata laluan kunci, PIN atau corak kunci skrin."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Tetapkan penyulitan storan"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Memerlukan data apl yang disimpan itu disulitkan."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Lumpuhkan kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Menghalang penggunaan semua kamera peranti."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Lumpuh ciri pelindung kekunci"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Cegah penggunaan beberapa ciri dalam pelindung kekunci."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Lumpuhkan ciri kunci skrin"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Cegah penggunaan beberapa ciri kunci skrin."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Laman Utama"</item>
     <item msgid="869923650527136615">"Mudah alih"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 bulan yang lalu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Sebelum 1 bulan yang lalu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saat yang lalu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minit yang lalu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> hari terakhir"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> hari terakhir</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> hari terakhir</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Bulan lepas"</string>
     <string name="older" msgid="5211975022815554840">"Lebih lama"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"semalam"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"dalam 1 saat"</item>
-    <item quantity="other" msgid="1241926116443974687">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"dalam 1 minit"</item>
-    <item quantity="other" msgid="3330713936399448749">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"dalam 1 jam"</item>
-    <item quantity="other" msgid="547290677353727389">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"esok"</item>
-    <item quantity="other" msgid="5109449375100953247">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saat yang lalu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saat yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minit yang lalu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minit yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 jam yang lalu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> jam yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"semalam"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> hari yang lalu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"dalam 1 saat"</item>
-    <item quantity="other" msgid="5495880108825805108">"dalam <xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"dalam 1 minit"</item>
-    <item quantity="other" msgid="4216113292706568726">"dalam <xliff:g id="COUNT">%d</xliff:g> minit"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"dalam 1 jam"</item>
-    <item quantity="other" msgid="3705373766798013406">"dalam <xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"esok"</item>
-    <item quantity="other" msgid="2973062968038355991">"dalam <xliff:g id="COUNT">%d</xliff:g> hari"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pada <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"pada <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"dalam <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"minggu"</string>
     <string name="year" msgid="4001118221013892076">"tahun"</string>
     <string name="years" msgid="6881577717993213522">"tahun"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 saat"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minit"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minit"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 jam"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> jam"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> saat</item>
+      <item quantity="one">1 saat</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minit</item>
+      <item quantity="one">1 minit</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> jam</item>
+      <item quantity="one">1 jam</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Masalah video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Maaf, video ini tidak sah untuk penstriman ke peranti ini."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tidak dapat mainkan video ini."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android sedang dimulakan…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Mengoptimumkan storan."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimumkan apl <xliff:g id="NUMBER_0">%1$d</xliff:g> daripada <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Menyediakan <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulakan apl."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"But akhir."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> dijalankan"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Jangan mulakan apl baharu."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Mulakan <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Kelantangan pendering"</string>
     <string name="volume_music" msgid="5421651157138628171">"Kelantangan media"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Tiada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nada dering tidak diketahui"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Rangkaian Wi-Fi tersedia"</item>
-    <item quantity="other" msgid="4192424489168397386">"Rangkaian Wi-Fi tersedia"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Rangkaian Wi-Fi terbuka tersedia"</item>
-    <item quantity="other" msgid="7915895323644292768">"Rangkaian Wi-Fi terbuka tersedia"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Rangkaian Wi-Fi tersedia</item>
+      <item quantity="one">Rangkaian Wi-Fi tersedia</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Rangkaian Wi-Fi terbuka tersedia</item>
+      <item quantity="one">Rangkaian Wi-Fi terbuka tersedia</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Log masuk ke rangkaian Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Log masuk ke rangkaian"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin menyambung ke Rangkaian Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Satu aplikasi"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulakan Wi-Fi Langsung."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Disambungkan sebagai peranti media"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Disambungkan sebagai kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Disambungkan sebagai peranti MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Disambungkan sebagai pemasang"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Disambungkan kepada aksesori USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Sentuh untuk mendapatkan pilihan USB yang lain."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Langkau"</string>
     <string name="no_matches" msgid="8129421908915840737">"Tiada padanan"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Cari di halaman"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 padanan"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> daripada <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> daripada <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 padanan</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Selesai"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Menyahlekap storan USB…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Menyahlekap kad SD…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Buat PIN untuk mengubah suai sekatan"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN tidak sepadan. Cuba lagi."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN terlalu pendek. Mesti sekurang-kurangnya 4 angka."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Cuba 1 saat lagi"</item>
-    <item quantity="other" msgid="4730868920742952817">"Cuba <xliff:g id="COUNT">%d</xliff:g> saat lagi"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Cuba lagi dalam masa <xliff:g id="COUNT">%d</xliff:g> saat</item>
+      <item quantity="one">Cuba lagi dalam masa 1 saat</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Cuba sebentar lagi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Leret ke bawah dari atas untuk keluar dari skrin penuh."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Melihat skrin penuh"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Untuk keluar, leret dari atas ke bawah."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Faham"</string>
     <string name="done_label" msgid="2093726099505892398">"Selesai"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Penggelangsar bulatan jam"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Penggelangsar bulatan minit"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk menyahsemat skrin ini, sentuh dan tahan Kembali serta Ikhtisar pada masa yang sama."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Untuk menyahsemat skrin ini, sentuh dan tahan Ikhtisar."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrin disemat. Menyahsemat tidak dibenarkan oleh organisasi anda."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrin dinyahsemat"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan menghadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Sehingga waktu gendala anda berakhir pada <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Sehingga waktu gendala anda berakhir"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Selama satu minit (sehingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Selama %1$d minit (sehingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Selama satu jam (sehingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Selama %1$d jam (sehingga <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item>
-    <item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
-    <item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Selama %1$d minit (sehingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Selama satu minit (sehingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Selama %1$d jam (sehingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Selama satu jam (sehingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Selama %d minit</item>
+      <item quantity="one">Selama satu minit</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Selama %d jam</item>
+      <item quantity="one">Selama satu jam</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Sehingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Selama-lamanya"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Sehingga anda matikan"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Runtuhkan"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Sehingga penggera seterusnya pada <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Sehingga penggera seterusnya"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Permintaan SS diubah kepada permintaan DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Permintaan SS diubah kepada permintaan USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Permintaan SS diubah kepada permintaan SS baharu."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port Persisian USB"</string>
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index af0ffad..bf4e321 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> စက္ကန့်"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> စက္ကန့်"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ခေါင်းစဉ်မဲ့&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ဖုန်းနံပါတ်မရှိပါ)"</string>
     <string name="unknownName" msgid="6867811765370350269">"မသိရ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"အသံစာပို့စနစ်"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ဆင်းမ်ကဒ် ရဲ့ ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် သော့ကျနေပါသည်။ ဖွင့်ရန် ကုဒ်အားထည့်သွင်းပါ။"</string>
     <string name="needPuk2" msgid="4526033371987193070">"ဆင်းမ်ကဒ်အားမပိတ်ရန် PUK2အားထည့်သွင်းပါ"</string>
     <string name="enablePin" msgid="209412020907207950">"မအောင်မြင်ပါ, SIM/RUIM သော့ကို အရင် သုံးခွင့်ပြုရန်"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"ဆင်းမ်ကဒ် သော့မကျခင် သင့်တွင် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။"</item>
-    <item quantity="other" msgid="7530597808358774740">"နောက်ထပ် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစား၍ မအောင်မြင်ံပါက ဆင်းမ်ကဒ် သော့ကျသွားပါမည်။"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">ဆင်းမ်ကဒ် သော့မချခင် သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့်များကျန်ပါသေးသည်။</item>
+      <item quantity="one">ဆင်းမ်ကဒ် သော့မချခင် သင့်တွင် <xliff:g id="NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEIDနံပါတ်"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"အဝင်ခေါ်ဆိုမှုID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"လေယဥ်ပျံပေါ်၌အသုံးပြုသောစနစ်ဖွင့်ထားသည်"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"လေယဥ်ပျံပေါ်၌အသုံးပြုသောစနစ်ပိတ်ထားသည်"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ဆက်တင်များ"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"အသံ အကူအညီ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
     <string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ဖုန်းကိုင်ထားသူနဲ့ ထိန်းချုပ်ပြသမှုမှ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးခြင်း။ ပုံမှန် အပလီကေးရှင်းများမှာ မလိုအပ်ပါ"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ဝဒ်ဂျက်ဝန်ဆောင်မှုနှင့် ပူးပေါင်းရန်"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"စွဲကိုင်ထားသူအားဝီဂျက် ဝန်ဆောင်မှု၏ ထိပ်သီး အဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ကို ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"လမ်းကြောင်း စီမံပေးရေး ဝန်ဆောင်မှု တစ်ခုဆီသို့ ချိတ်တွဲခြင်း"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"စွဲကိုင်ထားသူအား မှတ်ပုံတင်ထားသည့်  လမ်းကြောင်း စီမံပေးသူ မည်သူနှင့်မဆို ချိတ်တွဲခွင့်ကို ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"စက်ပစ္စည်း ထိန်းချုပ်ခြင်းနှင့် တုံ့ပြန်မှု"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"စွဲကိုင်ထားသူအား ကိရိယာ စီမံအုပ်ချုပ်သူထံသို့ ရည်ရွယ်ချက်များကို ပို့ခွင့် ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"တီဗီ ထည့်သွင်းမှု တစ်ခုဆီသို့ ချိတ်တွဲပေးခြင်း"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"appအား တာတို စက်ကွင်း ဆက်သွယ်ရေး (NFC) တဲဂ်များ၊ ကဒ်များ နှင့် ဖတ်ကြသူတို့နှင့် ဆက်သွယ်ပြောဆိုခွင့် ပြုသည်။"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ဖန်သားပြင် သော့ချခြင်းအား မလုပ်နိုင်အောင် ပိတ်ရန်"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"အပလီကေးရှင်းအား သော့ချခြင်းနှင့် သက်ဆိုင်ရာ စကားဝှက်သတ်မှတ်ခြင်းများအား မသုံးနိုင်အောင် ပိတ်ခြင်းကို ခွင့်ပြုရန်။ ဥပမာ ဖုန်းလာလျှင် သော့ပိတ်ခြင်း ပယ်ဖျက်ခြင်း၊ ဖုန်းပြောပြီးလျှင် သော့ကို အလိုအလျောက် ပြန်ပိတ်ခြင်း"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"လက်ဗွေရာပစ္စည်းကို စီမံမည်"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"အသုံးပြုရန်အတွက် လက်ဗွေရာပုံစံများကို ပေါင်းထည့်ရန် သို့မဟုတ် ဖျက်ရန်နည်းလမ်းများကို အပ်ဖ်အား အသုံးပြုခွင့်ပြုသည်။"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"လက်ဗွေရာပစ္စည်းကို အသုံးပြုမည်"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"စစ်မှန်ကြောင်းအထောက်အထားပြသခြင်းအတွက် လက်ဗွေရာပစ္စည်းကို အသုံးပြုရန် အပ်ဖ်အားခွင့်ပြုသည်။"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ထပ်တူပြုအဆင်အပြင်အားဖတ်ခြင်း"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"အပလီကေးရှင်းအား အကောင့်တစ်ခုအတွက် ထပ်တူညီအောင် လုပ်ဆောင်မှု ဆက်တင်အား ကြည့်ခွင့် ပြုပါ။ ဥပမာ People app က အကောင့်တစ်ခုနဲ့ ထပ်တူညီအောင် လုပ်ရန် ဆက်သွယ်ထားမှု ရှိမရှိ သိရှိနိုင်ခြင်း"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ထပ်တူညီအောင် လုပ်ခြင်းအား ပြုနိုင်၊ မပြုနိုင် အပြောင်းအလဲလုပ်ခြင်း"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"အပလီကေးရှင်းကို အကြောင်းကြားချက်များအား ထုတ်လုပ်ရန်၊ လေ့လာရန်၊ ဖျက်ပစ်ရန် ခွင့်ပြုခြင်း။ တခြား အပလီကေးရှင်းများမှ သတိပေးချက်များလည်း ပါဝင်ပါသည်"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"သတိပေးချက် နားထောင်ခြင်း ဆားဗစ် နှင့် ပူးပေါင်းခြင်း"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ဖုန်းကိုင်ထားသူနှင့် အကြောင်းကြားချက် နားစွင့်သော ဆားဗစ်မှ ထိပ်ပိုင်းအင်တာဖေ့စ် ကို ပူးပေါင်းခွင့်ပေးခြင်း။ ပုံမှန် အပလီကေးရှင်းများမှာ မလိုအပ်ပါ"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှုနှင့် ပူးပေါင်းခြင်း"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"လက်ဝယ်ရှိသူအား ရွေးချယ်သူဦးစားပေး ဝန်ဆောင်မှု၏ ထိပ်သီးအဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ပြုပါ။ သာမန် app များ အတွက် မည်သည့်အခါမျှ မလိုအပ်ပါ။"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"အခြေအနေ စီမံပေးရေး ဝန်ဆောင်မှု တစ်ခုဆီသို့ ချိတ်တွဲခြင်း"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"စွဲကိုင်ထားသူအား အခြေအနေကို စီမံပေးသူ၏ ထိပ်သီး အဆင့် အင်တာဖေ့စ်သို့ ချိတ်တွဲခွင့်ကို ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"မီဒီယာ လမ်းကြောင်း ဝန်ဆောင်မှုသို့ တွဲချည်ရန်"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"ကိုင်ထားသူအား မီဒီယာ လမ်းကြောင်း ဝန်ဆောင်မှု၏ ထိပ်သီး အဆင့် အင်တာဖေ့စ်သို့ တွဲချည်ခွင့် ပြုသည်။ သာမန် appများ ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"အိပ်မက် ဝန်ဆောင်မှုသို့ ပေါင်းစည်းမည်"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"အိမ်မက်ဝန်ဆောင်မှု၏ ထိပ်တန်းအဆင့် မျက်နှာပြင်အား ကိုင်ဆောင်သူမှ ပေါင်းစည်းရန် ခွင့်ပြုမည်။ သာမန် အပလီကေးရှင်းများတွင် မလိုအပ်ပါ။"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"မိုဘိုင်းဆက်သွယ်ရေးဝန်ဆောင်မှုဌာန မှ ထည့်သွင်းပေးသော အခြေအနေများအား ပယ်ဖျက်ခြင်း"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"စာပို့စာယူ ဆက်သွယ်ရေးဝန်ဆောင်မှုတစ်ခုအား ပူးပေါင်းခွင့်ပြုရန်"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"စာပို့စာယူဆက်သွယ်ရေးဝန်ဆောင်မှုတစ်ခု၏ ထိပ်ဆုံးရှိအင်တာဖေ့စ်ဖြင့် ပူးပေါင်းရန် ပိုင်ရှင်အားခွင့်ပြုပါ။ ပုံမှန် app များအတွက် မလိုအပ်ပါ။"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"စကားဝှက်စည်းမျဥ်းကိုသတ်မှတ်ရန်"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"မျက်နှာပြင် သော့ဖွင့်ရန် လိုအပ်သော စကားလုံးအရေအတွက်နှင့် အမျိုးအစားအား ထိန်းချုပ်ရန်"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက်များနှင့် PINများရှိ ခွင့်ပြုထားသည့် စာလုံးအရေအတွက်နှင့် အက္ခရာများအား ထိန်းချုပ်ရန်။"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"မော်နီတာမျက်နှာပြင်ဖွင့်ရန် ကြိုးစားခွင့်များ"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"မျက်နှာပြင်ကို သော့ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက်၊ စကားဝှက် ရိုက်ထည့်မှု သိပ်များနေလျှင် တက်ဘလက်ကို သော့ခတ်ရန် သို့မဟုတ် တက်ဘလက် ဒေတာ အားလုံးကို ဖျက်ပစ်ရန်။"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တီဗွီအား သော့ချခြင်း သို့မဟုတ် တီဗွီ၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုရန်။"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"မျက်နှာပြင်ကို သော့ဖွင့်ရန် အတွက် စကားဝှက် မမှန်မကန် ထည့်သွင်းမှု အရေအတွက်ကို စောင့်ကြည့်လျက်၊ စကားဝှက် ရိုက်ထည့်မှု သိပ်များနေလျှင် ဖုန်းကို သော့ခတ်ရန် သို့မဟုတ် ဖုန်း ဒေတာ အားလုံးကို ဖျက်ပစ်ရန်။"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"မျက်နှာပြင်ဖွင့်ရန်စကားဝှက်အား ပြောင်းခြင်း"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"မျက်နှာပြင်ဖွင့်ရန်စကားဝှက်အား ပြောင်းခြင်း"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တက်ဘလက်အား သော့ချခြင်း သို့မဟုတ် တက်ဘလက်၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တီဗွီအား သော့ချခြင်း သို့မဟုတ် တီဗွီ၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက ဖုန်းအား သော့ချခြင်း သို့မဟုတ် ဖုန်း၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"မျက်နှာပြင်သော့ခတ်ခြင်းအား ပြောင်းမည်"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"မျက်နှာပြင်သော့ခတ်ခြင်းအား ပြောင်းမည်။"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"မျက်နှာပြင်အားသော့ချရန်"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"မည်သည့်အချိန်တွင် ဖန်သားပြင်အား မည်ကဲ့သို့နည်းဖြင် သော့ချရန် ထိန်းချုပ်ခြင်း"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ဒေတာအားလုံးအားဖျက်ခြင်း"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"စက်ရုံထုတ် အခြေအနေအား ပြန်ပြောင်းခြင်းဖြင့် တက်ဘလက်ရှိ အချက်အလက်များအား ကြိုတင်သတိပေးမှုမရှိပဲ ဖျက်စီးရန်"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"စက်ရုံထုတ်အခြေအနေအားပြန်လည်ရယူပါက တီဗွီရှိ အချက်အလက်များအား ကြိုတင်အသိပေးခြင်းမရှိဘဲ ဖျက်ပစ်နိုင်သည်။"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"စက်ရုံထုတ် အခြေအနေအား ပြန်ပြောင်းခြင်းဖြင့် ဖုန်းရှိ အချက်အလက်များအား ကြိုတင်သတိပေးမှုမရှိပဲ ဖျက်စီးရန်"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"အသုံးပြုသူဒေတာကို ဖျက်မည်"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"သတိပေးခြင်းမရှိဘဲ ဤတက်ဘလက်ပေါ်ရှိ ထိုအသုံးပြုသူ၏ဒေတာအား ဖျက်မည်။"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"သတိပေးခြင်းမရှိဘဲ ဤတီဗွီပေါ်ရှိ ထိုအသုံးပြုသူ၏ဒေတာအား ဖျက်မည်။"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"သတိပေးခြင်းမရှိဘဲ ဤဖုန်းပေါ်ရှိ ထိုအသုံးပြုသူ၏ဒေတာအား ဖျက်မည်။"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"တကမာ္ဘလုံးဆိုင်ရာပရော်စီကို သတ်မှတ်ခြင်း"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"မူဝါဒအသုံးပြုခွင့်ရလျှင် စက်ပစ္စည်းတကမ္ဘာလုံးဆိုင်ရာပရော်စီအားသုံးရန် သတ်မှတ်ခြင်း။ ပထမဦးဆုံးသောစက်၏ထိန်းချုပ်သူသာ တကမ္ဘာလုံးဆိုင်ရာပရော်စီသာအားအကျိုးသက်ရောက်စေရန် သတ်မှတ်နိုင်သည်။"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"စကားဝှက်သက်တမ်းသတ်မှတ်ရန်"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ဖန်သားပြင်သော့ချခြင်း စကားဝှက် ပြင်ဆင်ခွင့် အကြိမ်ရေအား ထိန်းချုပ်ခြင်း"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ပေါ်လစီအား ဖွင့်ထားချိန်တွင်  တစ်ကမ္ဘာလုံးဆိုင်ရာ ပရောက်စီအား အသုံးပြုရန် ကိရိယာကို သတ်မှတ်မည်။ ကိရိယာ၏ ပိုင်ရှင်သာ ကမ္ဘာလုံးဆိုင်ရာ ပရောက်စီကို သတ်မှတ်နိုင်သည်။"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက် သက်တမ်းကုန်ဆုံးခြင်းကို သတ်မှတ်မည်။"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက်၊ PIN၊ သို့မဟုတ် ပုံစံအား အကြိမ်မည်မျှပြောင်းလဲရမည်ကို ပြောင်းမည်။"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"သိုလှောင်လျို့ဝှက်ခြင်းသတ်မှတ်"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"အပလီကေးရှင်းမှ သိမ်းဆည်းထားသော အရာများအား လျို့ဝှက် အသွင်းပြောင်းရန် လိုအပ်ခြင်း"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ကင်မရာအား ပိတ်ခြင်း"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"စက်မှ ကင်မရာအားလုံး အသုံးပြုမှုအား ကန့်သတ်ရန်"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"keyguardရှိ စွမ်းဆောင်ချက်များရပ်ရန်"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"keyguard မှ တချို့ စွမ်းဆောင်ချက်များအား ကန့်သတ်ရန်"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"မျက်နှာပြင်သော့ခတ်ခြင်း၏ အင်္ဂါရပ်များအား ပိတ်မည်။"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"မျက်နှာပြင်သော့ခတ်ခြင်းမှ အချို့သော အင်္ဂါရပ်များအသုံးပြုခြင်းကို ကာကွယ်ထားသည်။"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"ပင်မစာမျက်နှာ"</item>
     <item msgid="869923650527136615">"မိုဘိုင်း"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> က ထိတွေ့ပြီး ရှာဖွေခြင်းကို လုပ်ချင်ပါသည်။ ထိတွေ့ရှာဖွေခြင်း ဖွင့်ထားလျှင် သင့်လက်ဖျားအောက်မှ အရာကို ကြားနိုင် သို့ ရှင်းလင်းချက်ကို မြင်နိုင်တဲ့ အပြင် လက် အနေအထားဖြင့် ဖုန်းကို ဆက်သွယ်ပြုလုပ်စေခိုင်းနိုင်ပါသည်"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"လွန်ခဲ့သော၁လက"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"လွန်ခဲ့သော၁လမတိုင်မီက"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
-    <item quantity="other" msgid="3903706804349556379">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"လွန်ခဲ့သော ၁မိနစ်က"</item>
-    <item quantity="other" msgid="2176942008915455116">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"လွနခဲ့သော ၁နာရီက"</item>
-    <item quantity="other" msgid="2467273239587587569">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"ပြီးခဲ့သော<xliff:g id="COUNT">%d</xliff:g>ရက်က"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> နောက်ဆုံး <xliff:g id="COUNT_1">%d</xliff:g> နေ့</item>
+      <item quantity="one"> နောက်ဆုံး <xliff:g id="COUNT_0">%d</xliff:g> နေ့ </item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"ပြီးခဲ့သောလ"</string>
     <string name="older" msgid="5211975022815554840">"ယခင်က"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"မနေ့က"</item>
-    <item quantity="other" msgid="2479586466153314633">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"နောက် ၁စက္ကန့်တွင်"</item>
-    <item quantity="other" msgid="1241926116443974687">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"နောက်၁မီနစ်တွင်"</item>
-    <item quantity="other" msgid="3330713936399448749">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"နောက်၁နာရီတွင်"</item>
-    <item quantity="other" msgid="547290677353727389">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"မနက်ဖြန်"</item>
-    <item quantity="other" msgid="5109449375100953247">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"လွန်ခဲ့သော ၁စက္ကန့်က"</item>
-    <item quantity="other" msgid="3699169366650930415">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်က"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"လွန်ခဲ့သော ၁မိနစ်က"</item>
-    <item quantity="other" msgid="851164968597150710">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> မိနစ်က"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"လွန်ခဲ့သော ၁နာရီက"</item>
-    <item quantity="other" msgid="6889970745748538901">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> နာရီက"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"မနေ့က"</item>
-    <item quantity="other" msgid="3453342639616481191">"လွန်ခဲ့သော <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"နောက် ၁စက္ကန့်တွင်"</item>
-    <item quantity="other" msgid="5495880108825805108">"နောက် <xliff:g id="COUNT">%d</xliff:g> စက္ကန့်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"နောက်၁မိနစ်တွင်"</item>
-    <item quantity="other" msgid="4216113292706568726">"နောက် <xliff:g id="COUNT">%d</xliff:g> မိနစ်တွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"နောက်၁နာရီတွင်"</item>
-    <item quantity="other" msgid="3705373766798013406">"နောက် <xliff:g id="COUNT">%d</xliff:g> နာရီတွင်"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"မနက်ဖြန်"</item>
-    <item quantity="other" msgid="2973062968038355991">"နောက် <xliff:g id="COUNT">%d</xliff:g> ရက်တွင်"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> တွင်"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>မှာ"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>တွင်"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"အပတ်"</string>
     <string name="year" msgid="4001118221013892076">"နှစ်"</string>
     <string name="years" msgid="6881577717993213522">"နှစ်ပေါင်း"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"၁ စက္ကန့်"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> စက္ကန့်"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"၁ မိနစ်"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> မိနစ်"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"၁ နာရီ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> နာရီ"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> စက္ကန့်</item>
+      <item quantity="one">1 စက္ကန့်</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> မိနစ်</item>
+      <item quantity="one">1 မိနစ်</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> နာရီ</item>
+      <item quantity="one"> 1 နာရီ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ဗီဒီယို ပြဿနာ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ဒီဗိဒီယိုမှာ ဒီကိရိယာ ပေါ်မှာ ဖွင့်ကြည့်၍ မရနိုင်ပါ။"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ဒီဗီဒီယိုကို ပြသလို့ မရပါ"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android စတင်နေ…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"သိုလှောင်မှုအား ပြုပြင်ခြင်း။"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> ထဲက app<xliff:g id="NUMBER_1">%2$d</xliff:g>ကို ဆီလျော်အောင် လုပ်နေ"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> အားပြင်ဆင်နေသည်။"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"appများကို စတင်နေ"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"လုပ်ငန်းစနစ်ထည့်သွင်း၍ ပြန်လည်စတင်ရန် ပြီးပါပြီ"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> က အလုပ်လုပ်နေသည်"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"pp အသစ်ကို မစတင်ပါနှင့်။"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>စတင်ပါ"</string>
     <string name="new_app_description" msgid="1932143598371537340">"app အဟောင်းကို မသိမ်းဆည်းဘဲ ရပ်လိုက်ပါ။"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"စာတိုအတွက် လုပ်ဆောင်ချက် ရေးပါ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ဖုန်းမြည်သံအတိုးအကျယ်"</string>
     <string name="volume_music" msgid="5421651157138628171">"မီဒီယာအသံအတိုးအကျယ်"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"တစ်ခုမှမဟုတ်"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"မြည်သံများ"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"မသိသောမြည်သံ"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"ဝိုင်ဖိုင်ကွန်ယက်ရှိသည်"</item>
-    <item quantity="other" msgid="4192424489168397386">"ဝိုင်ဖိုင်ကွန်ယက်များရှိသည်"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"ဖွင့်ထားသောဝိုင်ဖိုင်ကွန်ယက်ရှိသည်"</item>
-    <item quantity="other" msgid="7915895323644292768">"ဖွင့်ထားသောဝိုင်ဖိုင်ကွန်ယက်များရှိသည်"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်</item>
+      <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်အား ဖွင့်ပါ</item>
+      <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်အား ဖွင့်ပါ</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"ဝိုင်ဖိုင်ကွန်ရက်သို့ ဝင်ပါ"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ကွန်ရက်သို့ ဝင်ပါ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" အင်တာနက် ဆက်သွယ်မှု ကောင်းကောင်းမရှိပါ"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"အပ္ပလီကေးရှင်း %1$s သည် ဝိုင်ဖိုင်ကွန်ရက် %2$s ကိုချိတ်ဆက်လိုသည်"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"အပလီကေးရှင်း"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"တိုက်ရိုက် ဝိုင်ဖိုင်"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"တိုက်ရိုက်ဝိုင်ဖိုင်ကို စတင်ပါ။ ၎င်းသည် ဝိုင်ဖိုင် ဟော့စပေါ့ကို ရပ်ဆိုင်းစေမှာ ဖြစ်ပါသည်။"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"တိုက်ရိုက်ဝိုင်ဖိုင်ကို စတင်လို့ မရပါ"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ကောင်းပြီ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"မီဒီယာစက်အနေဖြင့် ချိတ်ဆက်သည်"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"ကင်မရာအနေဖြင့်ဆက်သွယ်ခြင်း"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI စက်ပစ္စည်းအဖြစ် ချိတ်ဆက်ထားသည်"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"installerအနေဖြင့် ချိတ်ဆက်သည်"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USBတွဲဖက်ပစ္စည်းအား ချိတ်ဆက်ထားသည်"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"အခြား USB စိတ်ကြိုက်ရွေးချယ်ခွင့်များ အတွက် တို့ထိပါ။"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ကျော်"</string>
     <string name="no_matches" msgid="8129421908915840737">"ထပ်တူမတွေ့ရှိပါ"</string>
     <string name="find_on_page" msgid="1946799233822820384">"စာမျက်နှာတွင်ရှာဖွေရန်"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"တူညီချက်တစ်ခု"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ၏ <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>ထဲမှ <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="one">ကိုက်ညီမှု 1 ခု</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"ပြီးပါပြီ"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB သိုလှောင်မှု ကိရိယာအား ဆက်သွယ်မှု ရပ်ရန် ပြုလုပ်နေစဉ်…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD ကဒ်အား ဆက်သွယ်မှု ရပ်ရန် ပြုလုပ်နေစဉ်…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"ကန့်သတ်ချက်များ ပြင်ဆင်ခွင့်ပေးသော ပင်နံပါတ် သတ်မှတ်ပါ"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"ပင် နံပါတ် မတူပါ။ ထပ်ကြိုးစားပါ"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"ပင် နံပါတ် တိုလွန်းသည်။. အနည်းဆုံး ဂဏန်း ၄ လုံး ဖြစ်ရမည်။"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"၁ စက္ကန့်အကြာတွင် ပြန်ကြိုးစားပါ"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်ကြိုးစားပါ"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> စက္ကန့်အတွင်း ထပ်မံကြိုးစားပါ</item>
+      <item quantity="one">1 စက္ကန့်အတွင်း ထပ်မံကြိုးစားပါ</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"နောက်မှ ပြန်ကြိုးစားပါ"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"မျက်နှာပြင်အပြည့်ကနေ ပြန်ပြောင်းရန် အပေါ်အောက် ဆွဲချပါ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"မျက်နှာပြင်အပြည့် ကြည့်နေစဉ်"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ထွက်ရန်၊ ထိပ်ဘက်မှ အောက်ဘက်သို့ ဆွဲချပါ။"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ရပါပြီ"</string>
     <string name="done_label" msgid="2093726099505892398">"ပြီးပါပြီ"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"နာရီရွေးချက်စရာ"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန်၊ နောက်သို့ နှင့် ခြုံကြည့်မှု ခလုတ်များကို တစ်ချိန်တည်း ထိကိုင်ထားပါ။"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန် ခြုံကြည့်မှု ခလုတ်ကို ထိကိုင်ထားပါ။"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"မျက်နှာပြင်ကို ပင်ထိုးထားသည်။ ပင်ထိုးထားမှု ဖြုတ်ခြင်းကို သင့် အဖွဲ့အစည်းက ခွင့် မပြုပါ။"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"မျက်နှာပြင် ပင်ထိုးမှု ဖြတ်လိုက်ပြီ"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
@@ -1844,22 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ဘက်ထရီသက်တမ်း ကြာရှည်ခံရန်၊ ဘက်ထရီအားထိန်းသည် သင့်ကိရိယာ၏ ဆောင်ရွက်ချက်ကို  လျှော့ပေးပြီး တုန်ခါမှု၊ တည်နေရာဝန်ဆောင်မှုများနှင့်၊ နောက်ခံဒေတာအများစုကို ကန့်သတ်ပေး၏။ စင့်လုပ်ပေးရလေ့ရှိသည့် အီးမေး၊ စာပို့ခြင်းနှင့်၊ အခြားအပလီကေးရှင်းများကို ၎င်းတို့အား သင် ဖွင့်မှသာ အဆင့်မြှင့်မွမ်းမံမည်ဖြစ်၏။ \n\n ကိရိယာအား အားသွင်းနေစဉ် ဘက်ထရီအားထိန်းအား အလိုအလျောက် ပိတ်ထားသည်။"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"သင်၏ စက်ရပ်ချိန် <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> မှာ ပြီးဆုံးသည့် အထိ။"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"သင့်ကျချိန်အဆုံးအထိ"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"တစ်မိနစ်ကြာ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>အထိ)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d မိနစ်ကြာ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>အထိ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"တစ်နာရီကြာ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>အထိ)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d နာရီကြာ (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>အထိ)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"တစ်မိနစ် အတွင်း"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d မိနစ် အတွင်း"</item>
-  </plurals>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d မိနစ်တွင် (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>အထိ)</item>
+      <item quantity="one">တစ်မိနစ်တွင် (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> အထိ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d နာရီကြာ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>အထိ)</item>
+      <item quantity="one">တစ်နာရီကြာ (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> အထိ)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d မိနစ်တွင်</item>
+      <item quantity="one">တစ်မိနစ်တွင်</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d နာရီကြာ</item>
+      <item quantity="one">တစ်နာရီကြာ</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>အထိ"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"အကန့်အသတ်မရှိစွာ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"သင်က ဒါကို ပိတ်မပစ်သည့် အထိ"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ခေါက်ရန်"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"နောက်ထပ် <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ၌နိုးစက်အထိ"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"နောက်ထပ်နိုးစက်အထိ"</string>
@@ -1872,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"DIAL တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"USSD တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS တောင်းဆိုချက်အရ SS တောင်းဆိုချက်အား ပြင်ဆင်ထား၏။"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"အန်းဒရွိုက်"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB ဘေးရှိပို့တ်"</string>
 </resources>
diff --git a/core/res/res/values-nb/donottranslate-cldr.xml b/core/res/res/values-nb/donottranslate-cldr.xml
index 3b2a6c6..17aea0e 100755
--- a/core/res/res/values-nb/donottranslate-cldr.xml
+++ b/core/res/res/values-nb/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e. %b %Y</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 9088b96..01415c0 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Uten navn&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Mangler telefonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Ukjent"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Telefonsvarer"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
     <string name="enablePin" msgid="209412020907207950">"Mislyktes – aktiver lås for SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet låses."</item>
-    <item quantity="other" msgid="7530597808358774740">"Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet låses."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet låses.</item>
+      <item quantity="one">Du har <xliff:g id="NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet låses.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Inngående nummervisning"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Innstillinger"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binde seg til en ruteleverandørtjeneste"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Innehaveren av tillatelsen kan binde seg til ruteleverandører. Dette er ikke nødvendig for vanlige apper."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"binde appen til en TV-inngang"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Lar appen kommunisere med etiketter, kort og lesere som benytter NFC-teknologi."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivere skjermlåsen"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Lar appen deaktivere tastelåsen og eventuell tilknyttet passordsikkerhet. Et eksempel er at telefonen deaktiverer tastelåsen når du mottar et innkommende anrop, og deretter aktiverer tastelåsen igjen når samtalen er ferdig."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"administrere fingeravtrykkmaskinvare"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Lar appen fremkalle metoder for å legge til og slette fingeravtrykkmaler for bruk."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"bruke fingeravtrykkmaskinvare"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Lar appen bruke fingeravtrykkmaskinvare til godkjenning"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"lese synkroniseringsinnstillinger"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Lar appen lese synkroniseringsinnstillingene for en konto. For eksempel kan den finne ut om Personer-appen er synkronisert med en konto."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"slå synkronisering av og på"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"velge om de vil binde seg til målrettingstjenester"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Lar innehavere velge om de vil binde seg til toppnivået av grensesnittet i målrettingstjenester. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binde seg til en leverandørtjeneste for betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en leverandørtjeneste for betingelser. Dette skal ikke være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binde seg til en mediarutingstjeneste"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Gir innehaveren tillatelse til å binde til øverste nivå av grensesnittet for en tjeneste som bruker mediaruting. Dette skal ikke være nødvendig for vanlige apper."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"binde til en drømmetjeneste"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Tillater eieren å binde seg til det øverste nivået av grensesnittet til en drømmetjeneste. Kreves aldri for vanlige apper."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"starte konfigurasjonsappen som ble levert av operatøren"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind til en operatørmeldingstjeneste"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Tillater at innehaveren binder seg til det øverste nivået av grensesnittet til en operatørtjeneste. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollerer tillatt lengde og tillatte tegn i passord og PIN-koder for opplåsing av skjermen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Overvåk antall feil passordforsøk ved opplåsing av skjerm, og lås nettbrettet eller slett alle data fra nettbrettet ved for mange feil passordforsøk."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Overvåk antall feilaktige passord som er skrevet inn ved opplåsing av skjermen, og lås TV-en eller slett alle TV-data hvis feil passord skrives inn for mange ganger."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Overvåk antall feil passordforsøk ved opplåsing av skjerm, og lås telefonen eller slett alle data fra telefonen ved for mange feil passordforsøk."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Endre passord for opplåsing av skjerm"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Endre passordet for opplåsing av skjerm."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Overvåker antallet feil passord som er skrevet inn når skjermen låses opp, og låser nettbrettet eller sletter denne brukerens data når for mange feil passord er skrevet inn."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Overvåker antallet feil passord som er skrevet inn når skjermen låses opp, og låser TV-en eller sletter denne brukerens data når for mange feil passord er skrevet inn."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Overvåker antallet feil passord som er skrevet inn når skjermen låses opp, og låser telefonen eller sletter denne brukerens data når for mange feil passord er skrevet inn."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Endre skjermlåsen"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Endrer skjermlåsen."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Lås skjermen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontroller hvordan og når skjermen låses."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Slett alle data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Tilbakestill nettbrettets data uten advarsel ved å tilbakestille til fabrikkstandard."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Slett TV-ens data uten advarsel ved å tilbakestille til fabrikkstandard."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Tilbakestill telefonens data uten advarsel, ved å tilbakestille til fabrikkstandard."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Slett brukerdataene"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Sletter denne brukerens data på dette nettbrettet uten advarsel."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Sletter denne brukerens data på denne TV-en uten advarsel."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Sletter denne brukerens data på denne telefonen uten advarsel."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angi enhetens globale mellomtjener"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for skjermlåspassordet"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Velg hvor lenge det skal gå før passordet til skjermlåsen må byttes."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Angir den globale proxy-tjeneren på enheten som skal brukes når regelen er aktivert. Bare eieren av enheten kan angi den globale proxy-tjeneren."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Angi utløpstid for skjermlås"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Endrer hvor ofte PIN-koden, passordet eller mønsteret til skjermlåsen skal byttes."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angi lagringskryptering"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Krev at lagrede appdata krypteres."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiver kameraer"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Hindre bruk av alle kameraer på enheten."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Deaktiv. funksj. i tastelås"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Forhindre bruk av enkelte funksjoner når tastelåsen er på."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Deaktiver skjermlåsfunksjoner"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Forhindrer bruk av enkelte skjermlåsfunksjoner."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjemmenummer"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ber om aktivering av Utforsk ved å trykke. Når Utforsk ved å trykke er slått på, kan du høre eller se beskrivelser av det som er under fingrene dine. Du kan også utføre handlinger på nettbrettet ved hjelp av bevegelser."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"For én måned siden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"For over en måned siden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"for et sekund siden"</item>
-    <item quantity="other" msgid="3903706804349556379">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"for et minutt siden"</item>
-    <item quantity="other" msgid="2176942008915455116">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"for en time siden"</item>
-    <item quantity="other" msgid="2467273239587587569">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Siste <xliff:g id="COUNT">%d</xliff:g> dager"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">De siste <xliff:g id="COUNT_1">%d</xliff:g> dagene</item>
+      <item quantity="one">Den siste <xliff:g id="COUNT_0">%d</xliff:g> dagen</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Forrige måned"</string>
     <string name="older" msgid="5211975022815554840">"Eldre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"i går"</item>
-    <item quantity="other" msgid="2479586466153314633">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om et sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om et minutt"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om et minutt"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"i morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 sek siden"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 min siden"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 t siden"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"i går"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sek"</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 t"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"i morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"i <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"uker"</string>
     <string name="year" msgid="4001118221013892076">"år"</string>
     <string name="years" msgid="6881577717993213522">"år"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"Ett sekund"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"Ett minutt"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutter"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"Én time"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timer"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="one">1 sekund</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutter</item>
+      <item quantity="one">1 minutt</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> timer</item>
+      <item quantity="one">1 time</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Denne videoen er ikke gyldig for direkteavspilling på enheten."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Kan ikke spille av denne videoen."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android starter …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimaliser lagring."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimaliserer app <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Starter apper."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Ferdigstiller oppstart."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ikke start den nye appen."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Start <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Stopp den gamle appen uten å lagre."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Velg handling for tekst"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringetonevolum"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medievolum"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ukjent ringetone"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Trådløsnett i nærheten"</item>
-    <item quantity="other" msgid="4192424489168397386">"Trådløsnett i nærheten"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Åpent trådløsnett i nærheten"</item>
-    <item quantity="other" msgid="7915895323644292768">"Åpne trådløsnett i nærheten"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi-nettverk er tilgjengelig</item>
+      <item quantity="one">Wi-Fi-nettverk er tilgjengelig</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Åpne Wi-Fi-nettverk er tilgjengelig</item>
+      <item quantity="one">Åpent Wi-Fi-nettverk er tilgjengelig</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Pålogging til Wi-Fi-nettverk"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Logg på nettverket"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vil koble til Wi-Fi-nettverket %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kunne ikke starte Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tilkoblet som medieenhet"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tilkoblet som kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Koblet til som MIDI-enhet"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tilkoblet som installasjonsprogram"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Koblet til et USB-tilbehør"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Trykk for få andre USB-alternativer."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Hopp over"</string>
     <string name="no_matches" msgid="8129421908915840737">"Ingen treff"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Finn på side"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 treff"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> av <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> av <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 kamp</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Ferdig"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Kobler fra USB-lagringen …"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Kobler fra SD-kort …"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Angi en PIN-kode for endring av begrensninger"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-kodene stemmer ikke overens. Prøv på nytt."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-koden er for kort. Den må bestå av minst fire sifre."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Prøv på nytt om 1 sekund"</item>
-    <item quantity="other" msgid="4730868920742952817">"Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Prøv på nytt om <xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="one">Prøv på nytt om 1 sekund</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Prøv på nytt senere"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Sveip ned fra toppen av skjermen for å gå ut av fullskjermvisningen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visning i fullskjerm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Sveip ned fra toppen for å avslutte."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Skjønner"</string>
     <string name="done_label" msgid="2093726099505892398">"Ferdig"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Sirkulær glidebryter for timer"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Sirkulær glidebryter for minutter"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Tilbake og Oversikt samtidig."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Oversikt."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skjermen er festet. Løsning er ikke tillatt av organisasjonen din."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skjermen er løsnet"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Krev PIN-kode for å løsne apper"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"For å bidra til å forbedre batterilevetiden reduserer batterispareren ytelsen til enheten din og begrenser vibrering, posisjonstjenester og mesteparten av bakgrunnsdataene. E-post, sending av meldinger og andre apper som er avhengig av synkronisering oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Til hviletiden din ender kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Inntil nedetiden din er over"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"I ett minutt (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"I %1$d minutter (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"I én time (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"I %1$d timer (til <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
-    <item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"I én time"</item>
-    <item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">I %1$d minutter (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">I 1 minutt (til <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">For %1$d timer (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">I 1 time (til <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">I %d minutter</item>
+      <item quantity="one">I 1 minutt</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">I %d timer</item>
+      <item quantity="one">I 1 time</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"På ubestemt tid"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skjul"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Inntil neste alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Inntil neste alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-forespørselen er endret til en RINGE-forespørsel."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-forespørselen er endret til en USSD-forespørsel."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-forespørselen er endret til en ny SS-forespørsel."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port for USB-tilleggsutstyr"</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 6c74900..a5558aa 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकेन्ड"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकेन्ड"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;बिना शीर्षक&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(कुनै फोन नम्बर छैन)"</string>
     <string name="unknownName" msgid="6867811765370350269">"अज्ञात"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"भ्वाइस मेल"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"तपाईंको SIM कार्ड PUK-लक छ। यसलाई अनलक गर्न PUK कोड टाइप गर्नुहोस्।"</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM कार्ड अनलक गर्न PUK2 टाइप गर्नुहोस्।"</string>
     <string name="enablePin" msgid="209412020907207950">"असफल, SIM/RUIM बन्द छ।"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"तपाईंसँग SIM बन्द हुनु अघि <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयास छ।"</item>
-    <item quantity="other" msgid="7530597808358774740">"SIM बन्द हुनु अघि तपाईंसँग <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयासहरू छन्।"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">तपाईंसँग SIM बन्द हुनु अघि <xliff:g id="NUMBER_1">%d</xliff:g> बाँकी प्रयासहरू छन्।</item>
+      <item quantity="one">तपाईंसँग SIM बन्द हुनु अघि <xliff:g id="NUMBER_0">%d</xliff:g> प्रयास बाँकी छ।</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"आगमन कलर ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाइजहाज मोड खुला छ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाइजहाज मोड बन्द छ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"सेटिङ्हरू"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ताररहित प्रदर्शनको उच्च स्तरको इन्टरफेसलाई पक्का गर्न सम्पर्क राख्ने अनुमति दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक पर्दैन।"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"एउटा विजेट सेवासँग संगठित हुनुहोस्"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"एउटा विजेट सेवाको उच्च स्तरको इन्टरफेसलाई पक्का गर्नको लागि समाती राख्नेलाई अनुमति दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक पर्ने छैन।"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"मार्ग प्रदाय सेवा बाँध्छ"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"होल्डरलाई कुनै पनि दर्ता मार्ग प्रदायहरूमा बाँध्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"उपकरणको प्रबन्धसँग अन्तरक्रिया गर्नुहोस्"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"उपकरण प्रशासक लाई आशय पठाउन समाती राख्‍नेलाई अनुमति दिन्छ। साधारण अनुप्रयोहरूको लागि कहिल्यै पनी आवश्यक पर्दैन।"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"टिभि निवेशलाई आबद्ध"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"अनुप्रयोगलाई नयाँ क्षेत्र संचार (NFC) ट्यागहरू, कार्डहरू र पाठकहरूसँग अन्तर्क्रिया गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"स्क्रिन लक असक्षम पार्नुहोस्"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कुनै सम्बन्धित पासवर्ड सुरक्षा र किलकलाई असक्षम पार्न अनुप्रयोगलाई अनुमति दिन्छ। उदाहरणको लागि, अन्तर्गमन फोन कल प्राप्त गर्दा फोनले किलकलाई असक्षम पार्छ, त्यसपछि कल सकिएको बेला किलक पुनःसक्षम पार्छ।"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"औठाछाप हार्डवेयर व्यवस्थापन गर्नुहोस्"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"अनुप्रयोगलाई प्रयोगको लागि औठाछाप टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"औठाछाप हार्डवेयर प्रयोग गर्नुहोस्"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"अनुप्रयोगलाई प्रमाणीकरणको लागि औठाछाप हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"अनुप्रयोगलाई खाताको लागि सिङ्क सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको अनुप्रयोग खातासँग सिङ्क भएको नभएको निर्धारण गर्न सक्दछ।"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"टगल सिङ्क खुला र बन्द"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"अन्य अनुप्रयोगहरूबाट पोस्ट गरिएकासहित पुनःप्राप्त गर्न, परीक्षण गर्न र सूचनाहरू हटाउन अनुप्रयोगहरूलाई अनुमति दिन्छ।"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"जानकारी श्रोता सेवामा बाँध्नुहोस्"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्डरलाई सूचना श्रोता सेवाको शीर्ष-स्तरको इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"एक चयनकर्ता लक्षित सेवामा बाँध्नुहोस्"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"होल्डरलाई चयनकर्ता लक्षित सेवाको शीर्ष-स्तर इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"सर्त प्रदायक सेवामा जोड्न"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"सर्त प्रदायक सेवाको माथिल्लो स्तरको इन्टरफेसमा जोड्न बाहकलाई अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"मिडिया मार्ग सेवासँग बाँध्नुहोस्"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"होल्डरलाई मिडिया मार्ग सेवाको शीर्ष तह इन्टरफेस बाध्ने गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"सपना सेवामा बाँध्नुहोस्"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"होल्डरलाई सपना सेवाको माथिल्लो स्तरको इन्टरफेसमा बाँध्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक-प्रदान विन्यास अनुप्रयोग सुरु गर्नुहोस्"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"वाहक मेसेजिङ सेवामा आबद्ध हुनुहोस्"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"धारकलाई वाहक मेसेजिङ सेवाको उच्च-स्तरको इन्टरफेसमा आबद्ध हुन अनुमति दिनुहोस्। सामान्य एपहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रिन-अनलक पासवर्डहरूमा अनुमति दिइएको लम्बाइ र अक्षरहरू नियन्त्रण गर्नुहोस्।"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"मोनिटर स्क्रिन-अनलक प्रयत्नहरू"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने ट्याब्लेट लक गर्नुहोस् वा ट्याब्लेटका सबै डेटा मेट्नुहोस्।"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रिन अनलक गर्दा गलत पासवर्डका संख्या अनुगमन गर्नुहोस् र TV लक गर्नुहोस् वा TV को सबै डेटा मेट्नुहोस् यदि ज्यादै धेरै गलत पासवर्ड टाइप गरिएका छन् भने।"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"स्क्रिनअनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने फोन लक गर्नुहोस् वा फोनका सबै डेटा मेट्नुहोस्।"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"स्क्रिन-अनलक पासवर्ड बदल्नुहोस्"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"स्क्रिन-अनलक पासवर्ड परिवर्तन गर्नुहोस्।"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा TV लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा फोन लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"स्क्रिन लक परिवर्तन गर्नुहोस्"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"स्क्रिन लक परिवर्तन गर्नुहोस्।"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"स्क्रिन लक गर्नुहोस्।"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"कसरी र कहिले स्क्रिन लक गर्ने नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"सबै डेटा मेट्नुहोस्"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"कारखाना डेटा रिसेट गरेर बिना चेतावनी TV को डेटा मेट्नुहोस्"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै फोनको डेटा मेट्नुहोस्।"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"चेतावनी बिना यो TV मा यो प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"चेतावनी बिना यो फोनमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"उपकरण विश्वव्यापी प्रोक्सी मिलाउनुहोस्"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"नीति सक्षम हुँदा प्रयोग हुने उपकरण  विश्वव्यापी प्रोक्सी सेट गर्नुहोस्। प्रथम उपकरण प्रशासशनले मात्र प्रभावकारी विश्वव्यापी प्रोक्सी सेट गर्छ।"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"लक-स्क्रिन पासवर्ड अन्त सेट गर्नुहोस्"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"प्रायः कति छिटो लक-स्क्रिन पासवर्ड बदल्नु पर्छ यसलाई नियन्त्रण गर्नुहोस्।"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"नीति सक्षम हुँदा प्रयोग गरिनको लागि यन्त्र ग्लोवल प्रोक्सी सेट गर्नुहोस्। केवल यन्त्र मालिकले ग्लोवल प्रोक्सी सेट गर्न सक्नुहुन्छ।"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रिन लक पासवर्ड म्याद समाप्ति सेट गर्नुहोस्"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"स्क्रिन लक पासवर्ड, PIN, वा ढाँचा परिवर्तन कसरी बारम्बार परिवर्तन हुनुपर्छ परिवर्तन गर्नुहोस्।"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"भण्डारण इन्क्रिप्सन मिलाउनुहोस्"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"भण्डार गरिएको डेटा इन्क्रिप्ट हुनु आवश्यक छ।"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"क्यामेरालाई असक्षम गराउनुहोस्"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"सबै उपकरण क्यामराहरूको प्रयोग रोक्नुहोस्"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"किगार्डमा भएका विशेषताहरू असक्षम पार्नुहोस्"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"केही किगार्ड विशेषताहरूको प्रयोग रोक्नुहोस्।"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"स्क्रिन लकका सुविधाहरू अक्षम गर्नुहोस्"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"स्क्रिन लकको केही सुविधाहरूको प्रयोग रोक्नुहोस्।"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"गृह"</item>
     <item msgid="869923650527136615">"मोबाइल"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>ले स्पर्षद्वारा अन्वेषण सक्षम गर्न चाहन्छ। स्पर्षद्वारा अन्वेषण सक्षम भएको बेला तपाईँ आफ्नो औँलाको मुनि भएका विषयवस्तुहरू बारे सुन्न वा विवरण हेर्न सक्नुहुन्छ वा फोनसँग अन्तर्क्रिया गर्न इशारा गर्नुहोस्।"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"१ महिना अघि"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"१ महिना अघि"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"१ सेकेन्ड अघि"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अघि"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"१ मिनेट अघि"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"१ घन्टा अघि"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"अन्तिम <xliff:g id="COUNT">%d</xliff:g> दिन"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> अन्तिम <xliff:g id="COUNT_1">%d</xliff:g> दिन</item>
+      <item quantity="one"> अन्तिम <xliff:g id="COUNT_0">%d</xliff:g> दिन</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"अन्तिम महिना"</string>
     <string name="older" msgid="5211975022815554840">"पुरानो"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"हिजो"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"१ सेकेन्डमा"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"१ मिनेटमा"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>मिनेटमा"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"१ घन्टामा"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"भोलि"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> दिनमा"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"१ सेकेन्ड अघि"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड अगाडि"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"१ मिनेट अघि"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> मिनेट अघि"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"१ घन्टा अघि"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> घन्टा अघि"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"हिजो"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> दिन अघि"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"१ सेकन्ड"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"१ मिनेटमा"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> मिनेटमा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"१ घन्टामा"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> घन्टामा"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"भोलि"</item>
-    <item quantity="other" msgid="2973062968038355991">"दिन<xliff:g id="COUNT">%d</xliff:g> मा"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> मा"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> मा"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> मा"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"हप्ताहरू"</string>
     <string name="year" msgid="4001118221013892076">"वर्ष"</string>
     <string name="years" msgid="6881577717993213522">"वर्षहरू"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"१ सेकेन्ड"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्ड"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"१ मिनेट"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> मिनेट"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"१ घन्टा"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> घन्टा"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> सेकेन्ड</item>
+      <item quantity="one">1 सेकेन्ड</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> मिनेट</item>
+      <item quantity="one">1 मिनेट</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> घण्टा</item>
+      <item quantity="one">1 घण्टा</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"भिडियो समस्या"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"यो भिडियो यस उपकरणको लागि स्ट्रिमिङ गर्न मान्य छैन।"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"यो भिडियो चलाउन सक्दैन।"</string>
@@ -1307,6 +1260,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android शुरू हुँदैछ..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"भण्डारण अनुकूलन गर्दै।"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"अनुप्रयोग अनुकुल हुँदै <xliff:g id="NUMBER_0">%1$d</xliff:g> को <xliff:g id="NUMBER_1">%2$d</xliff:g>।"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयारी गर्दै।"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"सुरुवात अनुप्रयोगहरू।"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"बुट पुरा हुँदै।"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string>
@@ -1317,6 +1271,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"नयाँ अनुप्रयोग सुरु नगर्नुहोस्।"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> सुरु गर्नुहोस्"</string>
     <string name="new_app_description" msgid="1932143598371537340">"बचत नगरी पुरानो अनुप्रयोग रोक्नुहोस्।"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"पाठको लागि एउटा प्रकार्य छान्नुहोस्"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"बजाउने मात्रा"</string>
     <string name="volume_music" msgid="5421651157138628171">"मिडियाको मात्रा"</string>
@@ -1337,20 +1299,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"कुनै पनि होइन"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"घन्टीका स्वरहरू"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"अज्ञात रिङटोन"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"वाइफाइ नेटवर्क उपलब्ध छ"</item>
-    <item quantity="other" msgid="4192424489168397386">"वाइफाइ नेटवर्कहरू उपलब्ध"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"खुल्ला वाइफाइ नेटवर्क उपलब्ध छ"</item>
-    <item quantity="other" msgid="7915895323644292768">"खुल्ला वाइफाइ नेटवर्क उपलब्ध छ"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
+      <item quantity="one">Wi-Fi सञ्जाल उपलब्ध छ</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other"> खुल्ला Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
+      <item quantity="one">खुल्ला Wi-Fi सञ्जाल उपलब्ध छ</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"वाइफाइ नेटवर्कमा साइन गर्नुहोस्"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"नेटवर्कमा साइन गर्नुहोस्।"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" कमजोर इन्टरनेट जडान छ।"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"अनुप्रयोग %1$s Wifi सञ्जाल %2$s मा जडान गर्न चाहन्छ"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"एउटा अनुप्रयोग"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाइफाइ प्रत्यक्ष"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाइफाइ सिधा सुरु गर्नुहोस्। यसले वाइफाइ ग्राहक/हट्स्पटलाई बन्द गराउने छ।"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाइफाइ सिधा सुरु हुन सकेन।"</string>
@@ -1417,6 +1382,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ठिक छ"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"मिडिया उपकरणको रूपमा जडित"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"क्यामेराको रूपमा जडान भएको"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI यन्त्रको रूपमा जडान गरियो"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"एउटा स्थापनकर्ताको रूपमा जोडिएको छ"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB सहायकमा जोडिएको छ"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"अन्य USB विकल्पहरूको लागि टच गर्नुहोस्।"</string>
@@ -1532,10 +1498,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"छोड्नुहोस्"</string>
     <string name="no_matches" msgid="8129421908915840737">"कुनै मिलेन"</string>
     <string name="find_on_page" msgid="1946799233822820384">"पृष्ठमा फेला पार्नुहोस्"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"१ मेल"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> को <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> को<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 मेल</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"भयो"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB  भण्डारण अनमाउन्ट गर्दै..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD कार्ड अनमाउन्ट गर्दै…"</string>
@@ -1821,12 +1787,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"प्रतिबन्धहरूलाई परिवर्तन गर्नको लागि एउटा PIN बनाउनुहोस्"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN हरू मेल खाएनन्। पुनः प्रयास गर्नुहोस्।"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN अति छोटो भयो। कम्तीमा ४ अङ्क हुन आवश्यक छ।"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"१ सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा पुनः प्रयास गर्नुहोस्"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"> फेरि <xliff:g id="COUNT">%d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्</item>
+      <item quantity="one">1 सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"पछि पुनः प्रयास गर्नुहोस्"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"पूर्णस्क्रिनबाट बाहिर निस्कन माथिबाट तलतिर स्वाइप गर्नुहोस्।"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"पूरा पर्दा हेर्दै"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"बुझेँ"</string>
     <string name="done_label" msgid="2093726099505892398">"भयो"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"घण्टा गोलाकार स्लाइडर"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"मिनेट गोलाकार स्लाइडर"</string>
@@ -1841,7 +1809,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"यस पर्दालाई अनपिन गर्न एकै समय फिर्ता र सारांशलाई छोई पक्डिनुहोस्।"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"यस पर्दालाई अनपिन गर्न सारांशलाई छुनुहोस् र पक्डनुहोस्।"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"स्क्रिन अनपिन हुँदैछ। अनपिन गर्ने तपाईँको संगठन द्वारा समर्थित छैन।"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रिन पिन गरियो"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रिन अनपिन गरियो"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
@@ -1850,24 +1819,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"ब्याट्रीको आयु सुधार्न, ब्याट्री रक्षकले तपाईँको यन्त्रको कार्यसम्पादन घटाउँछ र भाइब्रेसन, स्थान सेवा र बहुसंख्यक पृष्ठभूमि डेटा सीमित गर्दछ। इमेल, सन्देश, र अन्य अनुप्रयोगहरू जुन सिङ्कमा भर पर्छन् अद्यावधिक नहुन सक्छन् जबसम्म तपाईँ तिनीहरूलाई खोल्नुहुन्न\n\n ब्याट्री रक्षक स्वत: निस्कृय हुन्छ जब तपाईँको यन्त्र चार्ज हुँदै हुन्छ।"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"तपाईँको <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> डाउनटाइम समाप्त हुँदा सम्म"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"तपाईँको डाउनटाइम समाप्त नभए सम्म"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"एक मिनेटको लागि (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> सम्म)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d मिनेटको लागि (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> सम्म)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"एक घण्टाको लागि (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> सम्म)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d घण्टाको लागि (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> सम्म)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"एक मिनेटको लागि"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d मिनेटको लागि"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"एक घण्टाको लागि"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d घण्टाको लागि"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other"> %1$d मिनेटको लागि (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> सम्म)</item>
+      <item quantity="one">एक मिनेटको लागि (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> सम्म)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other"> %1$d घण्टाको लागि (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> सम्म)</item>
+      <item quantity="one">एक घण्टाको लागि (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> सम्म)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d मिनेटको लागि</item>
+      <item quantity="one">एक मिनेटको लागि</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d घण्टाको लागि</item>
+      <item quantity="one">एक घण्टाको लागि</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> सम्म"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"अनिश्चित"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"तपाईँले यसलाई बन्द नगरेसम्म"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"संक्षिप्त पार्नुहोस्"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> मा अर्को अलार्म सम्म"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"अर्को अलार्म सम्म"</string>
@@ -1880,4 +1849,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS अनुरोध  DIAL अनुरोधमा परिमार्जन गरिएको छ।"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS अनुरोध USSD अनुरोधमा परिमार्जन गरिएको छ।"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS अनुरोध नयाँ SS अनुरोधमा परिमार्जन गरिएको छ।"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB परिधीय पोर्ट"</string>
 </resources>
diff --git a/core/res/res/values-night/themes_material_daynight.xml b/core/res/res/values-night/themes_material_daynight.xml
new file mode 100644
index 0000000..da870b7
--- /dev/null
+++ b/core/res/res/values-night/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        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>
+
+    <!-- Material theme (day/night version) for activities. -->
+    <style name="Theme.Material.DayNight" parent="Theme.Material" />
+
+    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+         with an inverse color profile. The dark action bar sharply stands out against
+         the light content (when applicable).  -->
+    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material" />
+
+    <!-- Variant of Material.DayNight with no action bar.  -->
+    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.NoActionBar" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen. This theme
+         sets {@link android.R.attr#windowFullscreen} to true.  -->
+    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen and extends into the display overscan region. This theme
+         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+         to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
+
+    <!-- Variant of Material.DayNight that has no title bar and translucent
+         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+         {@link android.R.attr#windowTranslucentNavigation} to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
+
+    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+         window decorations, so you basically have an empty rectangle in which
+         to place your content. It makes the window floating, with a transparent
+         background, and turns off dimming behind the window. -->
+    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Panel" />
+
+    <!-- Material theme (day/night version) for dialog windows and activities,
+         which is used by the {@link android.app.Dialog} class. This changes
+         the window to be floating (not fill the entire screen), and puts a
+         frame around its contents. You can set this theme on an activity if
+         you would like to make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.BaseDialog" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Dialog.FixedSize" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Dialog.NoActionBar.FixedSize" />
+
+    <!-- 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.DayNight.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
+
+    <!-- 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.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
+
+    <!-- Theme for a presentation window on a secondary display. -->
+    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
+
+    <!-- Material user theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class. -->
+    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Dialog.BaseAlert" />
+
+    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.SearchBar" />
+    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-nl/donottranslate-cldr.xml
+++ b/core/res/res/values-nl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 863cc0f..7352267 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seconden"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seconde"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Zonder titel&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen telefoonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Onbekend"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Uw SIM-kaart is vergrendeld met de PUK-code. Typ de PUK-code om te ontgrendelen."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
     <string name="enablePin" msgid="209412020907207950">"Mislukt. Schakel SIM/RUIM-vergrendeling in."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"U heeft nog <xliff:g id="NUMBER">%d</xliff:g> poging over voordat de simkaart wordt vergrendeld."</item>
-    <item quantity="other" msgid="7530597808358774740">"U heeft nog <xliff:g id="NUMBER">%d</xliff:g> pogingen over voordat de simkaart wordt vergrendeld."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">U heeft nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart wordt vergrendeld.</item>
+      <item quantity="one">U heeft nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat de simkaart wordt vergrendeld.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Inkomende beller-id"</string>
@@ -198,10 +196,11 @@
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is UIT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binden aan de service van een routeprovider"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Hiermee kan de houder binden aan geregistreerde routeproviders. Nooit gebruikt voor normale apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"binden aan een tv-ingang"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Hiermee kan de app communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"uw schermvergrendeling uitschakelen"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Hiermee kan de app de toetsenblokkering en bijbehorende wachtwoordbeveiliging uitschakelen. Zo kan de telefoon de toetsenblokkering uitschakelen wanneer er een oproep binnenkomt en de toetsenblokkering weer inschakelen als de oproep is beëindigd."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"vingerafdrukhardware beheren"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Hiermee kan de app methoden aanroepen om vingerafdruksjablonen toe te voegen en te verwijderen voor gebruik."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"vingerafdrukhardware gebruiken"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Hiermee kan de app vingerafdrukhardware gebruiken voor verificatie"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Hiermee kan de app de synchronisatie-instellingen voor een account lezen. Dit kan bijvoorbeeld bepalen of de app Personen wordt gesynchroniseerd met een account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"synchronisatie in- en uitschakelen"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"verbinding maken met een doelservice voor kiezers"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Hiermee kan de houder verbinding maken met de hoofdinterface van een doelservice voor kiezers. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binden aan de service van een provider van voorwaarden"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Hiermee kan de houder binden aan de hoofdinterface van de service van een provider van voorwaarden. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binden aan een service voor mediaroutering"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Hiermee kan de houder binden aan de hoofdinterface van een service voor mediaroutering. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"verbinding maken met een droomservice"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een droomservice. Nooit vereist voor normale apps."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"binden aan de berichtenservice van een provider"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Hiermee wordt de houder toegestaan te binden aan de berichteninterface van een provider. Nooit vereist voor normale apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"De lengte en het aantal tekens beheren die zijn toegestaan in wachtwoorden en pincodes voor schermvergrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tablet vergrendelen of alle gegevens op de tablet wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tv vergrendelen of alle gegevens op de tv wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de telefoon vergrendelen of alle gegevens op de telefoon wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Het wachtwoord voor schermontgrendeling wijzigen"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Het wachtwoord voor schermontgrendeling wijzigen."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tablet vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tv vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de telefoon vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"De schermvergrendeling wijzigen"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"De schermvergrendeling wijzigen."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Het scherm vergrendelen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Beheren hoe en wanneer het scherm wordt vergrendeld."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle gegevens wissen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"De gegevens van de tablet zonder waarschuwing wissen door de fabrieksinstellingen te herstellen."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"De gegevens van de tv zonder waarschuwing wissen door de fabrieksinstellingen te herstellen."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"De gegevens van de telefoon zonder waarschuwing wissen door de fabrieksinstellingen te herstellen."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Gebruikersgegevens wissen"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"De gegevens van deze gebruiker op deze tablet zonder waarschuwing wissen."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"De gegevens van deze gebruiker op deze tv zonder waarschuwing wissen."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"De gegevens van deze gebruiker op deze telefoon zonder waarschuwing wissen."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Algemene proxy voor het apparaat instellen"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Beheren hoe vaak het wachtwoord voor schermvergrendeling moet worden gewijzigd."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"De algemene proxy voor het apparaat instellen die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eigenaar van het apparaat kan de algemene proxy instellen."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Verlopen van wachtwoord voor schermvergrendeling instellen"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Wijzigen hoe vaak het wachtwoord, de pincode of het patroon voor schermvergrendeling moet worden gewijzigd."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Codering voor opslag instellen"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vereisen dat opgeslagen appgegevens kunnen worden gecodeerd."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Camera\'s uitschakelen"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Het gebruik van alle apparaatcamera\'s voorkomen."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Functies uit in toetsblokk."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Gebruik van bepaalde functies voorkomen in toetsblokkering."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Functies van schermvergrendeling uitschakelen"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Gebruik van bepaalde functies van schermvergrendeling voorkomen."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Thuis"</item>
     <item msgid="869923650527136615">"Mobiel"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil \'Verkennen via aanraking\' inschakelen. Wanneer \'Verkennen via aanraking\' is ingeschakeld, kunt u beschrijvingen beluisteren of bekijken van wat er onder uw vinger staat of aanraakbewerkingen uitvoeren op de telefoon."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand geleden"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Meer dan 1 maand geleden"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 seconde geleden"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuut geleden"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 uur geleden"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Afgelopen <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Afgelopen <xliff:g id="COUNT_1">%d</xliff:g> dagen</item>
+      <item quantity="one">Afgelopen <xliff:g id="COUNT_0">%d</xliff:g> dag</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Afgelopen maand"</string>
     <string name="older" msgid="5211975022815554840">"Ouder"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"gisteren"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"over 1 seconde"</item>
-    <item quantity="other" msgid="1241926116443974687">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"over 1 minuut"</item>
-    <item quantity="other" msgid="3330713936399448749">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"over 1 uur"</item>
-    <item quantity="other" msgid="547290677353727389">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"morgen"</item>
-    <item quantity="other" msgid="5109449375100953247">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 seconde geleden"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuut geleden"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 uur geleden"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"gisteren"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"over 1 seconde"</item>
-    <item quantity="other" msgid="5495880108825805108">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"over 1 minuut"</item>
-    <item quantity="other" msgid="4216113292706568726">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"over 1 uur"</item>
-    <item quantity="other" msgid="3705373766798013406">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"morgen"</item>
-    <item quantity="other" msgid="2973062968038355991">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"om <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"weken"</string>
     <string name="year" msgid="4001118221013892076">"jaar"</string>
     <string name="years" msgid="6881577717993213522">"jaren"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 seconde"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> seconden"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuten"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 uur"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> uur"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> seconden</item>
+      <item quantity="one">1 seconde</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuten</item>
+      <item quantity="one">1 minuut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> uur</item>
+      <item quantity="one">1 uur</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem met video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Deze video kan niet worden gestreamd naar dit apparaat."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Deze video kan niet worden afgespeeld."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android wordt gestart…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Opslagruimte wordt geoptimaliseerd."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g> optimaliseren."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> voorbereiden."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Apps starten."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Opstarten afronden."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"De nieuwe app niet starten."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
     <string name="new_app_description" msgid="1932143598371537340">"De oude app stoppen zonder opslaan."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Een actie voor tekst selecteren"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Onbekende beltoon"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wifi-netwerk beschikbaar"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wifi-netwerken beschikbaar"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Open wifi-netwerk beschikbaar"</item>
-    <item quantity="other" msgid="7915895323644292768">"Open wifi-netwerken beschikbaar"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wifi-netwerken beschikbaar</item>
+      <item quantity="one">Wifi-netwerk beschikbaar</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Open wifi-netwerken beschikbaar</item>
+      <item quantity="one">Open wifi-netwerk beschikbaar</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Inloggen op wifi-netwerk"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Inloggen bij netwerk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"App %1$s wil verbinding maken met wifi-netwerk %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Een app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wifi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kan Wifi Direct niet starten."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Gekoppeld als media-apparaat"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Gekoppeld als camera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Verbonden als MIDI-apparaat"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Gekoppeld als installatieprogramma"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Aangesloten op een USB-accessoire"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Raak aan voor andere USB-opties."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Overslaan"</string>
     <string name="no_matches" msgid="8129421908915840737">"Geen overeenkomsten"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Zoeken op pagina"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 overeenkomst"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> van <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> van <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 overeenkomst</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Gereed"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB-opslag ontkoppelen..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-kaart ontkoppelen..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Maak een pincode voor het aanpassen van beperkingen"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"De pincodes komen niet overeen. Probeer het opnieuw."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pincode is te kort. Moet ten minste vier cijfers lang zijn."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Probeer het over één seconde opnieuw"</item>
-    <item quantity="other" msgid="4730868920742952817">"Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Probeer het over <xliff:g id="COUNT">%d</xliff:g> seconden opnieuw</item>
+      <item quantity="one">Probeer het over 1 seconde opnieuw</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Probeer het later opnieuw"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Veeg omlaag vanaf de bovenkant om het volledige scherm te sluiten."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Volledig scherm wordt weergegeven"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Veeg omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ik snap het"</string>
     <string name="done_label" msgid="2093726099505892398">"Gereed"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Ronde schuifregelaar voor uren"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Ronde schuifregelaar voor minuten"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Blijf \'Terug\' en \'Overzicht\' tegelijk aanraken om dit scherm los te maken."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Blijf \'Overzicht\' aanraken om dit scherm los te maken."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Scherm is vastgezet. Losmaken is niet toegestaan door uw organisatie."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Scherm vastgezet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Scherm losgemaakt"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vragen om pincode voordat items worden losgemaakt"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Accubesparing beperkt de prestaties van uw apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de accu te verlengen.\n\nAccubesparing wordt automatisch uitgeschakeld terwijl uw apparaat wordt opgeladen."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Totdat uw downtime eindigt om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tot uw downtime afloopt"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Eén minuut (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d minuten (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Eén uur (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d uur (tot <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Eén minuut"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d minuten"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Eén uur"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d uur"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d minuten (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Eén minuut (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d uur (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Eén uur (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d minuten</item>
+      <item quantity="one">Eén minuut</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d uur</item>
+      <item quantity="one">Eén uur</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Voor onbepaalde tijd"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Samenvouwen"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Tot het volgende alarm om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Tot het volgende alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-verzoek is gewijzigd in DIAL-verzoek."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-verzoek is gewijzigd in USSD-verzoek."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-verzoek is gewijzigd in nieuw SS-verzoek."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Poort voor USB-randapparatuur"</string>
 </resources>
diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml
index f9431b2..3f341b8 100755
--- a/core/res/res/values-pl/donottranslate-cldr.xml
+++ b/core/res/res/values-pl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d.%m.%Y %H:%M:%S</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7a42f3e..4816897 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Bez nazwy&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Brak numeru telefonu)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Nieznana"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Poczta głosowa"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"Karta SIM jest zablokowana kodem PUK. Wprowadź kod PUK, aby odblokować kartę."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Nie udało się. Włącz blokadę karty SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> próbę, zanim karta SIM zostanie zablokowana."</item>
-    <item quantity="other" msgid="7530597808358774740">"Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> prób(y), zanim karta SIM zostanie zablokowana."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="few">Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie zablokowana.</item>
+      <item quantity="many">Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> prób, zanim karta SIM zostanie zablokowana.</item>
+      <item quantity="other">Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie zablokowana.</item>
+      <item quantity="one">Masz jeszcze <xliff:g id="NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie zablokowana.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Nazwa rozmówcy przy połączeniach przychodzących"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ustawienia"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asystent głosowy"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
@@ -271,13 +272,13 @@
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Dostęp do karty SD."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcje ułatwień dostępu"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Funkcje, których może zażądać technologia ułatwień dostępu."</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pobierz zawartość okna"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pobieranie zawartości okna"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Sprawdzanie zawartości okna, z którego korzystasz."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Włącz czytanie dotykiem"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Włączenie czytania dotykiem"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Klikane elementy będą wymawiane na głos, a ekran można przeglądać, używając gestów."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Włącz ułatwienia dostępu w internecie"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Włączenie ułatwień dostępu w internecie"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Można zainstalować skrypty, by zawartość aplikacji była łatwiej dostępna."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obserwuj wpisywany tekst"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obserwowanie wpisywanego tekstu"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obejmuje informacje osobiste, takie jak numery kart kredytowych i hasła."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
@@ -431,6 +432,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"powiązanie z usługą dostawcy tras"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umożliwia właścicielowi powiązanie z dowolnymi zarejestrowanymi dostawcami tras. Nie powinno być nigdy potrzebne w normalnych aplikacjach."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"powiązanie z wejściem TV"</string>
@@ -701,7 +704,7 @@
     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Pozwala aplikacji na zmianę ustawień użycia danych w tle."</string>
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"wyświetlanie połączeń Wi-Fi"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Pozwala aplikacji na dostęp do informacji o połączeniach Wi-Fi – np. na sprawdzenie, czy obsługa Wi-Fi jest włączona, oraz odczytanie nazw podłączonych urządzeń Wi-Fi."</string>
-    <string name="permlab_changeWifiState" msgid="6550641188749128035">"łączenie się i rozłączanie z siecią Wi-Fi"</string>
+    <string name="permlab_changeWifiState" msgid="6550641188749128035">"łączenie się i rozłączanie z siecią Wi‑Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z punktami dostępowymi Wi-Fi oraz na zmienianie konfiguracji sieci Wi-Fi w urządzeniu."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Pozwala aplikacji na odbieranie pakietów wysyłanych przez sieć Wi-Fi do wszystkich urządzeń, a nie tylko do Twojego tabletu, przy użyciu adresów połączeń grupowych. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Pozwala aplikacji na komunikowanie się z tagami, kartami i czytnikami NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"wyłączanie blokady ekranu"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Na przykład telefon wyłącza blokadę klawiatury, gdy odbiera połączenie przychodzące, a następnie włącza ją ponownie po zakończeniu połączenia."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"zarządzanie czytnikiem linii papilarnych"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Zezwala aplikacji aktywować metody dodawania i usuwania szablonów odcisków palców."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"używanie czytnika linii papilarnych"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Zezwala aplikacji na używanie czytnika linii papilarnych na potrzeby autoryzacji"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"czytanie ustawień synchronizacji"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Zezwala aplikacji na odczyt ustawień synchronizacji konta. Pozwala to na przykład określić, czy aplikacja Ludzie jest zsynchronizowana z kontem."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"włączanie i wyłączanie synchronizacji"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"powiązanie z usługą docelową wybierania"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umożliwia posiadaczowi tworzenie powiązania z interfejsem najwyższego poziomu usługi docelowej wybierania. Zwykłe aplikacje nie powinny potrzebować tego uprawnienia."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"powiąż z usługą dostawcy warunków"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi dostawcy warunków. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"powiązanie z usługą kierowania multimediów"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi kierowania multimediów. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"powiąż z usługą wygaszacza ekranu"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi wygaszacza ekranu. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"powiąż z usługą przesyłania wiadomości przez operatora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Zezwala posiadaczowi na tworzenie powiązania z interfejsem najwyższego poziomu w usłudze przesyłania wiadomości przez operatora. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolowanie długości haseł blokady ekranu i kodów PIN oraz dozwolonych w nich znaków."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Przy odblokowywaniu ekranu monitoruj, ile razy wpisano nieprawidłowe hasło i blokuj tablet lub usuń z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitorowanie, ile razy wpisano niepoprawne hasło podczas odblokowywania ekranu, oraz blokowanie telewizora albo kasowanie na nim wszystkich danych, gdy zbyt wiele razy wpisano niepoprawne hasło."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Przy odblokowywaniu ekranu monitoruje, ile razy wpisano nieprawidłowe hasło, i blokuje telefon lub usuwa z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Zmień hasło odblokowania ekranu"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Zmienianie hasła odblokowania ekranu"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorowanie, ile razy wpisano błędne hasło podczas odblokowywania ekranu, oraz blokowanie tabletu albo kasowanie wszystkich danych tego użytkownika, gdy zbyt wiele razy wpisano błędne hasło."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitorowanie, ile razy wpisano błędne hasło podczas odblokowywania ekranu, oraz blokowanie telewizora albo kasowanie wszystkich danych tego użytkownika, gdy zbyt wiele razy wpisano błędne hasło."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitorowanie, ile razy wpisano błędne hasło podczas odblokowywania ekranu, oraz blokowanie telefonu albo kasowanie wszystkich danych tego użytkownika, gdy zbyt wiele razy wpisano błędne hasło."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Zmień blokadę ekranu"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Zmiana blokady ekranu."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Zablokuj ekran"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolowanie sposobu i warunków blokowania ekranu"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Usuń wszystkie dane"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Wymazywanie danych z tabletu bez ostrzeżenia przez przywrócenie danych fabrycznych"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Skasowanie danych w telewizorze bez ostrzeżenia przez przywrócenie danych fabrycznych."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Wymazywanie danych z telefonu bez ostrzeżenia przez przywrócenie danych fabrycznych"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Kasuj dane użytkownika"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Kasowanie danych tego użytkownika na tym tablecie bez ostrzeżenia."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Kasowanie danych tego użytkownika na tym telewizorze bez ostrzeżenia."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Kasowanie danych tego użytkownika na tym telefonie bez ostrzeżenia."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ustaw globalny serwer proxy urządzenia"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła blokady"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontrolowanie częstotliwości zmian hasła ekranu blokady"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Ustawianie globalnego serwera proxy urządzenia do użycia przy włączonych zasadach. Tylko właściciel urządzenia może ustawić globalny serwer proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ustaw czas ważności hasła blokady ekranu"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Zmiana częstotliwości, z jaką należy zmieniać hasło blokady ekranu, kod PIN lub wzór."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ustaw szyfrowanie pamięci"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Wymaganie szyfrowania przechowywanych danych aplikacji"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Wyłącz aparaty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zapobieganie używaniu wszystkich aparatów w urządzeniu"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Wyłącz funkcje w blokadzie"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Zablokuj używanie niektórych funkcji w blokadzie."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Wyłącz funkcje blokady ekranu"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Zapobieganie użyciu niektórych funkcji blokady ekranu."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Dom"</item>
     <item msgid="869923650527136615">"Komórka"</item>
@@ -884,7 +902,7 @@
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Faks domowy"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"Pager"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Inny"</string>
-    <string name="phoneTypeCallback" msgid="2712175203065678206">"Połączenie zwrotne"</string>
+    <string name="phoneTypeCallback" msgid="2712175203065678206">"Oddzwanianie"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"Samochód"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Firmowy główny"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
@@ -1128,77 +1146,16 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> chce włączyć Czytanie dotykiem. Gdy ta funkcja jest włączona, słyszysz i widzisz opisy elementów, które są pod Twoim palcem, oraz możesz obsługiwać telefon gestami."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 miesiąc temu"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ponad 1 miesiąc temu"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"sekundę temu"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minutę temu"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"godzinę temu"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ostatnie (<xliff:g id="COUNT">%d</xliff:g>) dni"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="few">Ostatnie <xliff:g id="COUNT_1">%d</xliff:g> dni</item>
+      <item quantity="many">Ostatnich <xliff:g id="COUNT_1">%d</xliff:g> dni</item>
+      <item quantity="other">Ostatnie <xliff:g id="COUNT_1">%d</xliff:g> dnia</item>
+      <item quantity="one">Ostatni <xliff:g id="COUNT_0">%d</xliff:g> dzień</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Ostatni miesiąc"</string>
     <string name="older" msgid="5211975022815554840">"Starsze"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"wczoraj"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"za sekundę"</item>
-    <item quantity="other" msgid="1241926116443974687">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"za minutę"</item>
-    <item quantity="other" msgid="3330713936399448749">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"za godzinę"</item>
-    <item quantity="other" msgid="547290677353727389">"za <xliff:g id="COUNT">%d</xliff:g> godzin"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"jutro"</item>
-    <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"sekundę temu"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> s temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"minutę temu"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"godzinę temu"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"wczoraj"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"za sekundę"</item>
-    <item quantity="other" msgid="5495880108825805108">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"za minutę"</item>
-    <item quantity="other" msgid="4216113292706568726">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"za godzinę"</item>
-    <item quantity="other" msgid="3705373766798013406">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"jutro"</item>
-    <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"w dniu <xliff:g id="DATE">%s</xliff:g>"</string>
-    <string name="preposition_for_time" msgid="5506831244263083793">"o godzinie <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="preposition_for_time" msgid="5506831244263083793">"o godzinie <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"w <xliff:g id="YEAR">%s</xliff:g> r."</string>
     <string name="day" msgid="8144195776058119424">"dzień"</string>
     <string name="days" msgid="4774547661021344602">"dni"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"tygodni"</string>
     <string name="year" msgid="4001118221013892076">"rok"</string>
     <string name="years" msgid="6881577717993213522">"lat"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekunda"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuta"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 godzina"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> godz."</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> sekund</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="one">1 sekunda</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minuty</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> minut</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuty</item>
+      <item quantity="one">1 minuta</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> godziny</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> godzin</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> godziny</item>
+      <item quantity="one">1 godzina</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problem z filmem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ten film nie nadaje się do strumieniowego przesyłania do tego urządzenia."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nie można odtworzyć tego filmu."</string>
@@ -1267,7 +1230,7 @@
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
-    <string name="whichSendApplication" msgid="6902512414057341668">"Udostępnij przez"</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"Udostępnij przez:"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Udostępnij przez %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Wybierz aplikację ekranu głównego"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Użyj %1$s jako ekranu głównego"</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android się uruchamia…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optymalizacja pamięci."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optymalizowanie aplikacji <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Przygotowuję aplikację <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uruchamianie aplikacji."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Kończenie uruchamiania."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nie uruchamiaj nowej aplikacji."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Uruchom <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zatrzymaj starą aplikację bez zapisywania."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Wybierz czynność, jaka ma zostać wykonana na tekście"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Głośność dzwonka"</string>
     <string name="volume_music" msgid="5421651157138628171">"Głośność multimediów"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Brak"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nieznany dzwonek"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Sieć Wi-Fi jest dostępna"</item>
-    <item quantity="other" msgid="4192424489168397386">"Dostępne sieci Wi-Fi"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Otwórz dostępne sieci Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"Otwórz dostępne sieci Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="few">Dostępne są sieci Wi-Fi</item>
+      <item quantity="many">Dostępne są sieci Wi-Fi</item>
+      <item quantity="other">Dostępne są sieci Wi-Fi</item>
+      <item quantity="one">Dostępna jest sieć Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="few">Dostępne są otwarte sieci Wi-Fi</item>
+      <item quantity="many">Dostępne są otwarte sieci Wi-Fi</item>
+      <item quantity="other">Dostępne są otwarte sieci Wi-Fi</item>
+      <item quantity="one">Dostępna jest otwarta sieć Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Zaloguj się do sieci Wi-Fi."</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Zaloguj się do sieci"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacja %1$s chce połączyć się z siecią Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacja"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nie można uruchomić Wi-Fi Direct."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Podłączono urządzenie multimedialne"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Podłączono jako aparat."</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Podłączono jako urządzenie MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Podłączono jako nośnik instalacyjny."</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Podłączono akcesorium USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Dotknij, aby wyświetlić inne opcje USB."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Pomiń"</string>
     <string name="no_matches" msgid="8129421908915840737">"Brak wyników"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Znajdź na stronie"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 wynik"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 dopasowanie</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Gotowe"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Odłączanie nośnika USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Odłączanie karty SD..."</string>
@@ -1651,7 +1633,7 @@
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string>
     <string name="media_route_button_content_description" msgid="591703006349356016">"Przesyłaj"</string>
     <string name="media_route_chooser_title" msgid="1751618554539087622">"Połącz z urządzeniem"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prezentuj ekran na urządzeniu"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prześlij ekran na urządzenie"</string>
     <string name="media_route_chooser_searching" msgid="4776236202610828706">"Szukam urządzeń…"</string>
     <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ustawienia"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Rozłącz"</string>
@@ -1694,7 +1676,7 @@
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Sprawdzam konto"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> razy narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Podałeś nieprawidłowe dane odblokowania telewizora <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telewizor zostanie zresetowany do stanu fabrycznego, a wszystkie dane użytkownika zostaną skasowane."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Utwórz PIN wymagany przy zmianie ograniczeń"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kody PIN nie są identyczne. Spróbuj ponownie."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN jest za krótki. Musi mieć co najmniej 4 cyfry."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Spróbuj za sekundę"</item>
-    <item quantity="other" msgid="4730868920742952817">"Spróbuj za <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="few">Spróbuj ponownie za <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many">Spróbuj ponownie za <xliff:g id="COUNT">%d</xliff:g> sekund</item>
+      <item quantity="other">Spróbuj ponownie za <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="one">Spróbuj ponownie za sekundę</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Spróbuj ponownie później"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Przesuń z góry w dół, by zamknąć pełny ekran."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Widok na pełnym ekranie"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Aby wyjść, przesuń palcem z góry na dół."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Gotowe"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kołowy suwak godzin"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kołowy suwak minut"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aby odpiąć ten ekran, naciśnij i przytrzymaj jednocześnie Wstecz i Przegląd."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Przegląd."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran jest przypięty. Ustawienia organizacji nie pozwalają go odpiąć."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran odpięty"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Aby odpiąć, poproś o PIN"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Do zakończenia przestoju o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do zakończenia wyłączenia"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Przez minutę (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Przez %1$d min (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Przez godzinę (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Przez %1$d godz. (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Przez minutę"</item>
-    <item quantity="other" msgid="6924190729213550991">"Przez %d min"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Przez 1 godz."</item>
-    <item quantity="other" msgid="5408537517529822157">"Przez %d godz."</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="few">Przez %1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">Przez %1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Przez %1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Przez minutę (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="few">Przez %1$d godziny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">Przez %1$d godzin (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Przez %1$d godziny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Przez godzinę (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="few">Przez %d minuty</item>
+      <item quantity="many">Przez %d minut</item>
+      <item quantity="other">Przez %d minuty</item>
+      <item quantity="one">Przez minutę</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="few">Przez %d godziny</item>
+      <item quantity="many">Przez %d godzin</item>
+      <item quantity="other">Przez %d godziny</item>
+      <item quantity="one">Przez godzinę</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Na czas nieokreślony"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Zwiń"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do następnego alarmu o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do następnego alarmu"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Żądanie SS zostało zmienione na żądanie DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Żądanie SS zostało zmienione na żądanie USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Żądanie SS zostało zmienione na nowe żądanie SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port peryferyjny USB"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/donottranslate-cldr.xml b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
index 9c9f903..6355432 100755
--- a/core/res/res/values-pt-rPT/donottranslate-cldr.xml
+++ b/core/res/res/values-pt-rPT/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e de %b de %Y</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0ac8ca9..18d498e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sem nome&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Desconhecido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado com PUK. Introduza o código PUK para desbloqueá-lo."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Introduza o PUK2 para desbloquear o cartão SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Ação sem êxito. Ative o bloqueio do SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado."</item>
-    <item quantity="other" msgid="7530597808358774740">"Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar bloqueado.</item>
+      <item quantity="one">Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar bloqueado.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID do Autor da Chamada"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está ativado"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desativado"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Definições"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular a serviço de fornecedor de trajeto"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite ao titular vincular a quaisquer fornecedores de trajeto registado. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a uma entrada de TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que a aplicação comunique com etiquetas, cartões e leitores Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desativar o bloqueio do ecrã"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que a aplicação desative o bloqueio de teclas e qualquer segurança por palavra-passe associada. Por exemplo, o telemóvel desativa o bloqueio de teclas quando recebe uma chamada e reativa o bloqueio de teclas ao terminar a chamada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gerir o hardware de impressão digital"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que a aplicação invoque métodos para adicionar e eliminar modelos de impressão digital para utilização."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizar o hardware de impressão digital"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que a aplicação utilize o hardware de impressão digital para autenticação"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler definições de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que a aplicação leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a aplicação Pessoas está sincronizada com uma conta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar a sincronização"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"vincular a um serviço de destino do selecionador"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite ao detentor ficar vinculado à interface de nível superior de um serviço de destino do selecionador. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a um serviço de fornecedor de condição"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o titular vincule a interface de nível superior de um serviço de fornecedor de condição. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"vincular a um serviço de encaminhamento multimédia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite que o titular vincule a interface de nível superior de um serviço de encaminhamento multimédia. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"vincular-se a um serviço de sonho"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite ao detentor ficar vinculado à interface de nível superior de um serviço de sonho. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ligar ao serviço de mensagens de um operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao titular ligar à interface de nível superior do serviço de mensagens de um operador. Nunca deve ser necessário para aplicações normais."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlar o comprimento e os carateres permitidos nos PINs e nas palavras-passe do bloqueio de ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizar o número de palavras-passe incorretas escritas ao desbloquear o ecrã e bloquear o tablet ou apagar todos os dados do tablet, se forem escritas demasiadas palavras-passe incorretas."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitorizar o número de palavras-passe incorretas introduzidas ao desbloquear o ecrã e bloquear a TV ou apagar todos os dados da TV caso sejam introduzidas demasiadas palavras-passe incorretas."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorizar o número de palavras-passe incorretas introduzidas ao desbloquear o ecrã e bloquear o telemóvel ou apagar todos os dados do telemóvel caso tenham sido introduzidas demasiadas palavras-passe."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Alterar a palavra-passe de desbloqueio do ecrã"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Alterar a palavra-passe de desbloqueio do ecrã."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorizar o número de palavras-passe incorretas introduzidas ao desbloquear o ecrã e bloquear o tablet ou apagar todos os dados deste utilizador se forem introduzidas demasiadas palavras-passe incorretas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitorizar o número de palavras-passe incorretas introduzidas ao desbloquear o ecrã e bloquear a TV ou apagar todos os dados deste utilizador se forem introduzidas demasiadas palavras-passe incorretas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitorizar o número de palavras-passe incorretas introduzidas ao desbloquear o ecrã e bloquear o telemóvel ou apagar todos os dados deste utilizador se forem introduzidas demasiadas palavras-passe incorretas."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Alterar o bloqueio de ecrã"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Alterar o bloqueio de ecrã."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear o ecrã"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar como e quando ocorre o bloqueio do ecrã."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Apagar todos os dados"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Apagar os dados do tablet sem avisar através de uma reposição de dados de fábrica."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Apagar os dados da TV sem aviso prévio ao executar uma reposição de dados de fábrica."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apagar os dados do telemóvel sem avisar através de uma reposição de dados de fábrica."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Apagar os dados do utilizador"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Apagar os dados deste utilizador neste tablet sem aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Apagar os dados deste utilizador nesta TV sem aviso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Apagar os dados deste utilizador neste telemóvel sem aviso."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do aparelho"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do dispositivo a ser utilizado quando a política estiver ativada. Só o primeiro administrador do dispositivo pode definir o proxy global efetivo."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Def. valid. palavra-passe bloq. ecrã"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controlar a frequência com que a palavra-passe do bloqueio de ecrã deve ser alterada."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Definir o proxy global do dispositivo a utilizar enquanto a política está ativada. Apenas o proprietário do dispositivo pode definir o proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Def. exp. p.-passe bloq. ecrã"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Alterar a frequência com que a palavra-passe, o PIN ou a sequência do bloqueio de ecrã deve ser alterado."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Def. encriptação armazenamento"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Solicitar encriptação dos dados da aplicação armazenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desativar câmaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evitar a utilização de todas as câmaras do dispositivo."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Desat. func. com teclado bloq."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Evitar a utilização de algumas funcionalidades com o teclado bloqueado."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desativar func. bloqueio ecrã"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Impedir a utilização de algumas funcionalidades do bloqueio de ecrã."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residência"</item>
     <item msgid="869923650527136615">"Móvel"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> pretende ativar a funcionalidade Explorar Através do Toque. Quando a funcionalidade Explorar Através do Toque estiver ativada, pode ouvir ou visualizar descrições sobre o que está por baixo do seu dedo ou executar gestos para interagir com o telemóvel."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Há 1 mês"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Há mais de 1 mês"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Há 1 segundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"Há <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Há 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Há <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Há 1 hora"</item>
-    <item quantity="other" msgid="2467273239587587569">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+      <item quantity="one">Último <xliff:g id="COUNT_0">%d</xliff:g> dia</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Último mês"</string>
     <string name="older" msgid="5211975022815554840">"Mais antiga"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ontem"</item>
-    <item quantity="other" msgid="2479586466153314633">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"daqui a 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"daqui a <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"daqui a 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"daqui a <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"daqui a 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"daqui a <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
-    <item quantity="other" msgid="5109449375100953247">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Há 1 seg"</item>
-    <item quantity="other" msgid="3699169366650930415">"Há <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"há 1 min"</item>
-    <item quantity="other" msgid="851164968597150710">"Há <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Há 1 hora"</item>
-    <item quantity="other" msgid="6889970745748538901">"Há <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ontem"</item>
-    <item quantity="other" msgid="3453342639616481191">"Há <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"daqui a 1 seg"</item>
-    <item quantity="other" msgid="5495880108825805108">"daqui a <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"daqui a 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"daqui a <xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"daqui a 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
-    <item quantity="other" msgid="2973062968038355991">"daqui a <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"a <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semanas"</string>
     <string name="year" msgid="4001118221013892076">"ano"</string>
     <string name="years" msgid="6881577717993213522">"anos"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">1 segundo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+      <item quantity="one">1 minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+      <item quantity="one">1 hora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão em fluxo contínuo neste aparelho."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"O Android está a iniciar…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"A otimizar o armazenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"A otimizar a aplicação <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"A preparar o <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"A iniciar aplicações"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"A concluir o arranque."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Não iniciar a nova aplicação."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Parar a aplicação antiga sem guardar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume de multimédia"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nada"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
-    <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
-    <item quantity="other" msgid="7915895323644292768">"Abrir redes Wi-Fi disponíveis"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Redes Wi-Fi disponíveis</item>
+      <item quantity="one">Rede Wi-Fi disponível</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Redes Wi-Fi abertas disponíveis</item>
+      <item quantity="one">Rede Wi-Fi aberta disponível</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Iniciar sessão na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Inicie sessão na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicação %1$s pretende estabelecer ligação à rede Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uma aplicação"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ligado como um dispositivo multimédia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ligado como uma câmara"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Ligado como um dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ligado como um instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ligado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toque para ver outras opções USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ignorar"</string>
     <string name="no_matches" msgid="8129421908915840737">"Sem correspondências"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Localizar na página"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 correspondência"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 correspondência</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Concluído"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"A desmontar memória de armazenamento USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"A desmontar cartão SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar as restrições"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não correspondem. Tente novamente."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é demasiado pequeno. Deve ter, no mínimo, 4 dígitos."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Tente em: 1 seg"</item>
-    <item quantity="other" msgid="4730868920742952817">"Tente em: <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Tente novamente dentro de <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="one">Tente novamente dentro de 1 segundo</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize rapidamente para baixo para sair do ecrã inteiro."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização de ecrã inteiro"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Compreendi"</string>
     <string name="done_label" msgid="2093726099505892398">"Concluído"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Controlo de deslize circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Controlo de deslize circular dos minutos"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar este ecrã, toque sem soltar em Retroceder e Visão geral em simultâneo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para soltar este ecrã, toque sem soltar em Visão geral."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"O ecrã está fixo. A sua entidade não o(a) autoriza a soltá-lo."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecrã fixo"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ecrã solto"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Até o período de inatividade terminar às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Até terminar o período de inatividade"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Durante um minuto (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Durante %1$d minutos (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Durante uma hora (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Durante %1$d horas (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Durante uma hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Durante %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante um minuto (até às <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Durante %1$d horas (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Durante uma hora (até às <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Durante %d minutos</item>
+      <item quantity="one">Durante um minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Durante %d horas</item>
+      <item quantity="one">Durante uma hora</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidamente"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Reduzir"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Até ao próximo alarme, às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Até ao próximo alarme"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"O pedido SS foi modificado para um pedido DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"O pedido SS foi modificado para um pedido USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"O pedido SS foi modificado para um novo pedido SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta periférica USB"</string>
 </resources>
diff --git a/core/res/res/values-pt/donottranslate-cldr.xml b/core/res/res/values-pt/donottranslate-cldr.xml
index 2da7599..c97b337 100755
--- a/core/res/res/values-pt/donottranslate-cldr.xml
+++ b/core/res/res/values-pt/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e de %B de %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %d/%m/%Y</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b44944c..14733e0 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sem título&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nenhum número de telefone)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Desconhecido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correio de voz"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"O seu cartão SIM está bloqueado por um PUK. Digite o código PUK para desbloqueá-lo."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Digite o PUK2 para desbloquear o cartão SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Falha. Ative o bloqueio do SIM/R-UIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado."</item>
-    <item quantity="other" msgid="7530597808358774740">"Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
+      <item quantity="other">Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM será bloqueado.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID do chamador de entrada"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Configurações"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
@@ -431,6 +430,8 @@
     <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 apps comuns."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para apps normais."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"usar um serviço provedor de rotas"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite que o proprietário use qualquer provedor de rotas registrado. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para apps normais."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"associar a uma entrada de TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que o app se comunique com leitores, cartões e etiqueta NFC (Comunicação a curta distância)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"desativar o bloqueio de tela"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite que o app desative o bloqueio de teclas e qualquer segurança por senha associada. Por exemplo, o telefone desativa o bloqueio de telas ao receber uma chamada e o reativa quando a chamada é finalizada."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gerenciar hardware de impressão digital"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"usar hardware de impressão digital"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite que o app use hardware de impressão digital para autenticação."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ativar e desativar sincronização"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o app recupere, examine e limpe notificações, inclusive as postadas por outros apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"associar a um serviço seletor alvo"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite que o sistema se associe à interface de nível superior de um serviço seletor alvo. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"associar a um serviço provedor de condições"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o proprietário use a interface de nível superior de um serviço provedor de condições. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"usar serviço de roteamento de mídia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite que o proprietário use a interface de nível superior de um serviço de roteamento de mídia. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"conectar-se a um serviço de sonho"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite que o sistema autorizado se conecte à interface de nível superior de um serviço de sonho. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar o app de configuração fornecido pela operadora"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a um serviço de mensagens de operadora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite que o proprietário use a interface de nível superior de um serviço de mensagens de operadora. Não deve ser necessária para apps comuns."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o tablet ou apagar todos os dados do tablet se a senha for digitada incorretamente muitas vezes."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitora o número de senhas incorretas digitadas ao desbloquear a tela e bloqueia a TV ou apagar todos os dados dela se muitas senhas incorretas forem digitadas."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorar quantas vezes a senha foi digitada incorretamente ao desbloquear a tela e bloquear o telefone ou apagar todos os dados do telefone se a senha for digitada incorretamente muitas vezes."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Alterar a senha para desbloqueio da tela"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Alterar a senha para desbloqueio da tela."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitora o número de senhas incorretas digitadas ao desbloquear a tela e bloqueia o tablet ou limpa todos os dados do usuário se muitas senhas incorretas forem digitadas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitora o número de senhas incorretas digitadas ao desbloquear a tela e bloqueia a TV ou limpa todos os dados do usuário se muitas senhas incorretas forem digitadas."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitora o número de senhas incorretas digitadas ao desbloquear a tela e bloqueia o smartphone ou limpa todos os dados do usuário se muitas senhas incorretas forem digitadas."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Alterar o bloqueio de tela"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Altera o bloqueio de tela."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear a tela"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar como e quando a tela é bloqueada."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Apagar todos os dados"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Apague os dados do tablet sem aviso redefinindo a configuração original."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Apaga dados da TV sem aviso, fazendo uma redefinição para configuração original."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Apagar os dados do telefone sem aviso redefinindo a configuração original."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Limpar dados do usuário"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Limpa os dados do usuário neste tablet sem aviso prévio."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Limpa os dados do usuário nesta TV sem aviso prévio."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Limpa os dados do usuário neste smartphone sem aviso prévio."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Definir val. da senha de bloqueio"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Controle a frequência com que a senha da tela de bloqueio deve ser alterada."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Configura o proxy global do dispositivo para ser usado enquanto a política está ativada. Somente o proprietário do dispositivo pode definir o proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Definir expiração da senha de bloqueio de tela"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Altera a frequência com que o PIN, a senha ou o padrão do bloqueio de tela deve ser alterado."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Definir criptografia de armazenamento"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exija que os dados armazenados do app sejam criptografados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desativar câmeras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impeça o uso de todas as câmeras do dispositivo."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Desat. recursos ao bloq. tecl."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Impede o uso de determinados recursos quando o teclado está bloqueado."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Desativar recursos de bloqueio de tela"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Impede o uso de determinados recursos do bloqueio de tela."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residencial"</item>
     <item msgid="869923650527136615">"Celular"</item>
@@ -989,7 +1005,7 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulte o Guia do usuário ou entre em contato com o Serviço de atendimento ao cliente."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"O cartão SIM está bloqueado."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Desbloqueando o cartão SIM…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes.\n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> quer ativar a exploração pelo toque. Com ela, você pode ouvir ou ver descrições do que está sob seu dedo e interagir com o telefone através de gestos."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 mês atrás"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Antes de 1 mês atrás"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 segundo atrás"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> segundos atrás"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto atrás"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 hora atrás"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Últimos <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+      <item quantity="other">Últimos <xliff:g id="COUNT_1">%d</xliff:g> dias</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Mês passado"</string>
     <string name="older" msgid="5211975022815554840">"Mais antigos"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ontem"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"em 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"em 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"em 1 hora"</item>
-    <item quantity="other" msgid="547290677353727389">"Em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"amanhã"</item>
-    <item quantity="other" msgid="5109449375100953247">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 seg. atrás"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> segundos   atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuto atrás"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> minutos atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 hora atrás"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> horas atrás"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ontem"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dias atrás"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"em 1 segundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"em 1 minuto"</item>
-    <item quantity="other" msgid="4216113292706568726">"em <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"em 1 hora"</item>
-    <item quantity="other" msgid="3705373766798013406">"em <xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"amanhã"</item>
-    <item quantity="other" msgid="2973062968038355991">"em <xliff:g id="COUNT">%d</xliff:g> dias"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"em <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"às <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"em <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"semanas"</string>
     <string name="year" msgid="4001118221013892076">"ano"</string>
     <string name="years" msgid="6881577717993213522">"anos"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"Um segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"Um minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minutos"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"Uma hora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> horas"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> segundos</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minutos</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> horas</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problema com o vídeo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Este vídeo não é válido para transmissão neste dispositivo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Não é possível reproduzir este vídeo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"O Android está iniciando..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Otimizando o armazenamento."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Otimizando app <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Iniciando apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Concluindo a inicialização."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Não inicie o novo app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Iniciar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Parar o app antigo sem salvar."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Escolha uma ação para o texto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volume da campainha"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volume da mídia"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Toque desconhecido"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Rede Wi-Fi disponível"</item>
-    <item quantity="other" msgid="4192424489168397386">"Redes Wi-Fi disponíveis"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Rede Wi-Fi aberta disponível"</item>
-    <item quantity="other" msgid="7915895323644292768">"Redes Wi-Fi abertas disponíveis"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Redes Wi-Fi disponíveis</item>
+      <item quantity="other">Redes Wi-Fi disponíveis</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
+      <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Fazer login na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Acessar a rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
@@ -1409,8 +1374,9 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Se você ativar o armazenamento USB, alguns apps que estão em uso serão interrompidos e poderão ficar indisponíveis até você desativar o armazenamento USB."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Falha na operação do USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como um dispositivo de mídia"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como disp. de mídia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como câmera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Conectado como dispositivo MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectados como um instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Toque para obter outras opções USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ignorar"</string>
     <string name="no_matches" msgid="8129421908915840737">"Não encontrado"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Localizar na página"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Uma correspondência"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> de <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Concluído"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Desconectando armazenamento USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Desconectando cartão SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Crie um PIN para modificar restrições"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Os PINs não coincidem. Tente novamente."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"O PIN é curto demais. Deve ter pelo menos 4 dígitos."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Tente novamente em 1 segundo"</item>
-    <item quantity="other" msgid="4730868920742952817">"Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+      <item quantity="other">Tente novamente em <xliff:g id="COUNT">%d</xliff:g> segundos</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Tente novamente mais tarde"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Deslize de cima para baixo para sair da tela inteira"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visualização em tela cheia"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Para sair, deslize de cima para baixo."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Entendi"</string>
     <string name="done_label" msgid="2093726099505892398">"Concluído"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Controle deslizante circular das horas"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Controle deslizante circular dos minutos"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para liberar esta tela, toque e mantenha pressionados \"Voltar\" e \"Visão geral\" ao mesmo tempo."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Para liberar esta tela, toque e mantenha pressionado \"Visão geral\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"A tela está fixada. A liberação não é permitida por sua organização."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Tela liberada"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Até o período de inatividade terminar às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Até que seu tempo de inatividade termine"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Por um minuto (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Por uma hora (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Por %1$d horas (até às <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Por 1 hora"</item>
-    <item quantity="other" msgid="5408537517529822157">"Por %d horas"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Por %1$d horas (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Por %1$d horas (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Por %d minutos</item>
+      <item quantity="other">Por %d minutos</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Por %d horas</item>
+      <item quantity="other">Por %d horas</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Indefinidamente"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Recolher"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Até o próximo alarme em <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Até o próximo alarme"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"A solicitação SS foi modificada para a solicitação DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"A solicitação SS foi modificada para a solicitação USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"A solicitação SS foi modificada para a nova solicitação SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Porta USB periférica"</string>
 </resources>
diff --git a/core/res/res/values-ro-rRO/donottranslate-cldr.xml b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro-rRO/donottranslate-cldr.xml
+++ b/core/res/res/values-ro-rRO/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
index cfb79e8..c874dcf 100755
--- a/core/res/res/values-ro/donottranslate-cldr.xml
+++ b/core/res/res/values-ro/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 9184458..dd87d74 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Fără titlu&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Niciun număr de telefon)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Necunoscut"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mesaj vocal"</string>
@@ -63,10 +61,11 @@
     <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Introduceţi codul PUK2 pentru a debloca cardul SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare până la blocarea cardului SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări până la blocarea cardului SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="few">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până la blocarea cardului SIM.</item>
+      <item quantity="other">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări până la blocarea cardului SIM.</item>
+      <item quantity="one">V-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare până la blocarea cardului SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID apelant de primire"</string>
@@ -202,6 +201,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Setări"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
@@ -431,6 +431,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"se conectează la un serviciu de furnizare a traseelor"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite titularului să se conecteze la furnizorii de trasee înregistrați. Nu este necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"se conectează la o intrare TV"</string>
@@ -737,6 +739,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite aplicaţiei să comunice cu etichetele, cardurile şi cititoarele NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"dezactivează blocarea ecranului"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permite aplicaţiei să dezactiveze blocarea tastelor şi orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primeşte un apel telefonic şi reactivează blocarea tastelor la terminarea apelului."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestionează hardware-ul pentru amprentă"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Permite aplicației să invoce metode pentru a adăuga și pentru a șterge șabloane de amprentă pentru utilizare."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"folosește hardware-ul pentru amprentă"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Permite aplicației să folosească hardware pentru amprentă pentru autentificare"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"citire setări sincronizare"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permite aplicaţiei să citească setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicaţia poate determina dacă aplicaţia Persoane este sincronizată cu un anumit cont."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activează/dezactivează sincronizarea"</string>
@@ -791,8 +797,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"se conectează la un serviciu de alegere a țintei"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de alegere a țintei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"conectare la un serviciu furnizor de condiții"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu furnizor de condiții. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"se conectează la un serviciu de trasee multimedia"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Permite deținătorului să se conecteze la interfața de nivel superior a unui serviciu de trasee multimedia. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"se conectează la un serviciu de vis"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Permite deținătorului să se conecteze la interfața superioară a unui serviciu de vis. Această opțiune nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
@@ -810,29 +820,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"se conectează la un serviciu de mesagerie oferit de operator"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de mesagerie oferit de operator. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Monitorizaţi numărul de parole incorecte introduse la deblocarea ecranului şi blocaţi tableta sau ştergeţi datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați televizorul sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Monitorizaţi numărul de parole incorecte introduse la deblocarea ecranului şi blocaţi telefonul sau ştergeţi toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Editaţi parola de deblocare a ecranului"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Editaţi parola de deblocare a ecranului."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați televizorul sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați telefonul sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Modificați blocarea ecranului"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Modificați blocarea ecranului."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Blocaţi ecranul"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Stabiliţi modul şi timpul în care se blochează ecranul."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Ștergere integrală date"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ștergeţi datele de pe tabletă fără avertisment, efectuând resetarea configurării din fabrică."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Ștergeți datele de pe televizor fără avertisment, prin revenirea la setările din fabrică."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ștergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Ștergeți datele utilizatorului"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ștergeți datele acestui utilizator de pe această tabletă fără avertisment."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ștergeți datele acestui utilizator de pe acest televizor fără avertisment."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Ștergeți datele acestui utilizator de pe acest telefon fără avertisment."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setaţi serverul proxy global pentru dispozitiv"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Expirare parolă blocare ecran"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Stabiliţi frecvenţa de schimbare a parolei de blocare a ecranului."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Setați serverul proxy global pentru dispozitiv, care să fie utilizat cât timp politica este activă. Numai proprietarul dispozitivului poate seta serverul proxy global."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Setați expirarea parolei pentru blocarea ecranului"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Modificați frecvența cu care trebuie să se schimbe parola, codul PIN sau modelul pentru blocarea ecranului."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setaţi criptarea stocării"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Necesită ca datele aplicaţiei stocate să fie criptate."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Dezactivaţi camerele foto"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Împiedicaţi utilizarea camerelor foto de pe dispozitiv."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Dezactiv. funcții după blocare"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Previne utilizarea unora dintre funcții când tastatura este blocată."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Opriți funcții blocare ecran"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Împiedicați utilizarea unor funcții ale blocării ecranului."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domiciliu"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1145,13 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcţie este activată, puteţi auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteţi efectua gesturi pentru a interacţiona cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"cu 1 secundă în urmă"</item>
-    <item quantity="other" msgid="3903706804349556379">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"cu 1 minut în urmă"</item>
-    <item quantity="other" msgid="2176942008915455116">"cu <xliff:g id="COUNT">%d</xliff:g> (de) minute în urmă"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"cu 1 oră în urmă"</item>
-    <item quantity="other" msgid="2467273239587587569">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Ultimele <xliff:g id="COUNT">%d</xliff:g> de zile"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="few">Ultimele <xliff:g id="COUNT_1">%d</xliff:g> zile</item>
+      <item quantity="other">Ultimele <xliff:g id="COUNT_1">%d</xliff:g> de zile</item>
+      <item quantity="one">Ultima <xliff:g id="COUNT_0">%d</xliff:g> zi</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Luna trecută"</string>
     <string name="older" msgid="5211975022815554840">"Mai vechi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ieri"</item>
-    <item quantity="other" msgid="2479586466153314633">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"într-o secundă"</item>
-    <item quantity="other" msgid="1241926116443974687">"în <xliff:g id="COUNT">%d</xliff:g> (de) secunde"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"în 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"în <xliff:g id="COUNT">%d</xliff:g> (de) minute"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"în 1 oră"</item>
-    <item quantity="other" msgid="547290677353727389">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"mâine"</item>
-    <item quantity="other" msgid="5109449375100953247">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"cu 1 sec. în urmă"</item>
-    <item quantity="other" msgid="3699169366650930415">"cu <xliff:g id="COUNT">%d</xliff:g> (de) secunde în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"cu 1 min. în urmă"</item>
-    <item quantity="other" msgid="851164968597150710">"cu <xliff:g id="COUNT">%d</xliff:g> (de) min. în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"cu 1 oră în urmă"</item>
-    <item quantity="other" msgid="6889970745748538901">"cu <xliff:g id="COUNT">%d</xliff:g> (de) ore în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ieri"</item>
-    <item quantity="other" msgid="3453342639616481191">"cu <xliff:g id="COUNT">%d</xliff:g> (de) zile în urmă"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"în 1 sec."</item>
-    <item quantity="other" msgid="5495880108825805108">"în <xliff:g id="COUNT">%d</xliff:g> (de) sec."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"în 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"în <xliff:g id="COUNT">%d</xliff:g> (de) min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"în 1 oră"</item>
-    <item quantity="other" msgid="3705373766798013406">"în <xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"mâine"</item>
-    <item quantity="other" msgid="2973062968038355991">"în <xliff:g id="COUNT">%d</xliff:g> (de) zile"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"pe <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"la <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"în <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1167,21 @@
     <string name="weeks" msgid="6509623834583944518">"săptămâni"</string>
     <string name="year" msgid="4001118221013892076">"an"</string>
     <string name="years" msgid="6881577717993213522">"ani"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"O secundă"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> (de) secunde"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"Un minut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> (de) minute"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"O oră"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> (de) ore"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> secunde</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> de secunde</item>
+      <item quantity="one">O secundă</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> de minute</item>
+      <item quantity="one">Un minut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> ore</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> de ore</item>
+      <item quantity="one">O oră</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problemă video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Acest fişier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Nu puteţi reda acest videoclip"</string>
@@ -1301,6 +1259,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android pornește..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Se optimizează stocarea."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Se optimizează aplicaţia <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Se pregătește <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Se pornesc aplicaţiile."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Se finalizează pornirea."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nu porniţi aplicaţia nouă."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Porniţi <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Opriţi vechea aplicaţie fără să salvaţi."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Alegeţi o acţiune pentru text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Volum sonerie"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volum media"</string>
@@ -1331,20 +1298,25 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Niciunul"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuri de apel"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Ton de apel necunoscut"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Reţea Wi-Fi disponibilă"</item>
-    <item quantity="other" msgid="4192424489168397386">"Reţele Wi-Fi disponibile"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Reţea Wi-Fi deschisă disponibilă"</item>
-    <item quantity="other" msgid="7915895323644292768">"Reţele Wi-Fi deschise disponibile"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="few">Rețele Wi-Fi disponibile</item>
+      <item quantity="other">Rețele Wi-Fi disponibile</item>
+      <item quantity="one">Rețea Wi-Fi disponibilă</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="few">Rețele Wi-Fi deschise disponibile</item>
+      <item quantity="other">Rețele Wi-Fi deschise disponibile</item>
+      <item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Conectaţi-vă în reţeaua Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Conectaţi-vă la reţea"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
@@ -1411,6 +1383,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectat ca dispozitiv media"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectat ca aparat foto"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Conectat ca dispozitiv MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectat ca program de instalare"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectat la un accesoriu USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Atingeţi pentru alte opţiuni USB."</string>
@@ -1526,10 +1499,11 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Omiteţi"</string>
     <string name="no_matches" msgid="8129421908915840737">"Nicio potrivire"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Găsiţi pe pagină"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 potrivire"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> din <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> din <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> din <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">Un rezultat</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Terminat"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Se demontează stocarea USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Se demontează cardul SD..."</string>
@@ -1815,12 +1789,15 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Creați un cod PIN pentru modificarea restricțiilor"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Codurile PIN nu se potrivesc. Încercați din nou."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Codul PIN este prea scurt. Trebuie să aibă cel puțin 4 cifre."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Reîncercați în 1 sec."</item>
-    <item quantity="other" msgid="4730868920742952817">"Reîncercați în <xliff:g id="COUNT">%d</xliff:g> sec."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="few">Reîncercați în <xliff:g id="COUNT">%d</xliff:g> secunde</item>
+      <item quantity="other">Reîncercați în <xliff:g id="COUNT">%d</xliff:g> de secunde</item>
+      <item quantity="one">Reîncercați într-o secundă</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Reîncercați mai târziu"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Glisați în jos pentru a ieși din ecran complet."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Vizualizare pe ecran complet"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Pentru a ieși, glisați de sus în jos."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Am înțeles"</string>
     <string name="done_label" msgid="2093726099505892398">"Terminat"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Selector circular pentru ore"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Selector circular pentru minute"</string>
@@ -1835,7 +1812,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pentru a anula fixarea pe ecran, apăsați lung, simultan, pe Înapoi și pe Vizualizare generală."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Pentru a anula fixarea pe ecran, apăsați lung pe Vizualizare generală."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ecranul este fixat. Anularea fixării nu este permisă de organizația dvs."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Fixarea ecranului anulată"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
@@ -1844,24 +1822,28 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Până când inactivitatea dvs. se încheie la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Până la finalizarea perioadei de inactivitate"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Timp de un minut (până la <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Timp de %1$d (de) minute (până la <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Timp de o oră (până la <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Timp de %1$d (de) ore (până la <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Timp de o oră"</item>
-    <item quantity="other" msgid="5408537517529822157">"Timp de %d (de) ore"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="few">Timp de %1$d minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Timp de %1$d de minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Timp de un minut (până la <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="few">Timp de %1$d ore (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Timp de %1$d de ore (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Timp de o oră (până la <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="few">Timp de %d minute</item>
+      <item quantity="other">Timp de %d de minute</item>
+      <item quantity="one">Timp de un minut</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="few">Timp de %d ore</item>
+      <item quantity="other">Timp de %d de ore</item>
+      <item quantity="one">Timp de o oră</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Nedefinit"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Până la dezactivare"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Restrângeți"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Până la alarma următoare, la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Până la alarma următoare"</string>
@@ -1874,4 +1856,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Solicitarea SS este modificată într-o solicitare DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Solicitarea SS este modificată într-o solicitare USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Solicitarea SS este modificată într-o nouă solicitare SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB periferic"</string>
 </resources>
diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml
index c22df99..a36f13d 100755
--- a/core/res/res/values-ru/donottranslate-cldr.xml
+++ b/core/res/res/values-ru/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y г.</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %d.%m.%Y</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2f9cd10..617065c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без названия&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Нет номера телефона)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Неизвестно"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Голосовая почта"</string>
@@ -63,17 +61,19 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-карта заблокирована с помощью кода PUK. Для разблокировки введите код PUK."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Для разблокировки SIM-карты введите PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"Произошла ошибка. Включите блокировку SIM-карты или карты R-UIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>. После этого SIM-карта будет заблокирована."</item>
-    <item quantity="other" msgid="7530597808358774740">"Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>. После этого SIM-карта будет заблокирована."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована.</item>
+      <item quantity="few">Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована.</item>
+      <item quantity="many">Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована.</item>
+      <item quantity="other">Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Идентификация вызывающего абонента"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"Идентификация звонящего абонента"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"Идентификатор подключенной линии"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"Ограничение идентификатора подключенной линии"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"Переадресация вызова"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Переадресация вызовов"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Параллельный вызов"</string>
     <string name="BaMmi" msgid="455193067926770581">"Запрет вызовов"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Смена пароля"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
@@ -431,6 +432,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Подключение к серверам поставщиков маршрутов"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Приложение сможет подключаться к серверам зарегистрированных поставщиков маршрутов. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"Подключение к ТВ-входу"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Приложение сможет обмениваться данными с NFC-метками, картами и устройствами считывания, используя связь малого радиуса действия."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Отключение функции блокировки экрана"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Приложение сможет отключать блокировку экрана и другие функции защиты. Например, блокировка экрана будет отключаться при получении входящего вызова и включаться после завершения разговора."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управление сканером отпечатков"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Приложение сможет добавлять и удалять шаблоны отпечатков пальцев."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"использование сканера отпечатков"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Приложение сможет использовать сканер отпечатков пальцев для аутентификации."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"Включение/выключение синхронизации"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"Подключение к сервису выбора цели"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Подключение к интерфейсу верхнего уровня для выбора цели. Это разрешение не требуется для работы обычных приложений."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"Привязка к средству передачи медиафайлов"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Привязка к интерфейсу верхнего уровня средства передачи медиафайлов. Не требуется для работы обычных приложений."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"Подключение к службе экранных заставок"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Подключение к базовому интерфейсу службы экранных заставок. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Запуск приложения настроек, предоставленного оператором"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Подключение к службе обмена сообщениями"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Подключение к базовому интерфейсу службы обмена сообщениями, предоставляемой оператором связи. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролировать длину и символы при вводе пароля и PIN-кода."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Отслеживает попытки ввода пароля при разблокировке экрана и блокирует планшетный ПК или удаляет с него все данные, если было сделано слишком много таких попыток."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Блокировка телевизора или удаление всех данных на нем при слишком большом количестве неудачных попыток ввести пароль для разблокировки экрана."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Отслеживает попытки ввода пароля при разблокировке экрана и блокирует телефон или удаляет с него все данные, если было сделано слишком много таких попыток."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Изменять пароль для снятия блокировки экрана"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Изменять пароль для снятия блокировки экрана."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Отслеживать неверно введенные пароли при разблокировке экрана и блокировать планшет или удалять с него все данные, если сделано слишком много неудачных попыток."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Отслеживать неверно введенные пароли при разблокировке экрана и блокировать телевизор или удалять с него все данные, если сделано слишком много неудачных попыток."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Отслеживать неверно введенные пароли при разблокировке экрана и блокировать телефон или удалять с него все данные, если сделано слишком много неудачных попыток."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Изменить блокировку экрана"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Изменить блокировку экрана."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Блокировать экран"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Контролировать способ и время блокировки экрана."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Удалить все данные"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Удалять все данные на планшетном ПК без предупреждения путем сброса настроек."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Сброс настроек и удаление всех данных на телевизоре без предупреждения."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Удалять все данные на телефоне без предупреждения путем сброса настроек."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Удалить пользовательские данные"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Удалить данные этого пользователя с планшета без предупреждения."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Удалить данные этого пользователя с телевизора без предупреждения."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Удалить данные этого пользователя с телефона без предупреждения."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Глобальный прокси-сервер"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Задать срок действия пароля"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Контролировать, как часто менять пароль блокировки экрана."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Настроить глобальный прокси-сервер устройства, который будет использоваться при активной политике. Это может сделать только владелец устройства."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Задать срок действия пароля"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Установить частоту изменения пароля, PIN-кода или графического ключа."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Настроить шифрование хранилища"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Шифровать данные приложений в хранилище."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Отключить камеры"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Запретить использование камер на устройстве."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Отключить функции блокировки"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Запретить использование некоторых функций блокировки клавиатуры."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Отключить функции блокировки экрана"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Запретить использование некоторых функций блокировки экрана."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашний"</item>
     <item msgid="869923650527136615">"Мобильный"</item>
@@ -841,30 +859,30 @@
     <item msgid="1735177144948329370">"Домашний факс"</item>
     <item msgid="603878674477207394">"Пейджер"</item>
     <item msgid="1650824275177931637">"Другой"</item>
-    <item msgid="9192514806975898961">"Создать свой ярлык"</item>
+    <item msgid="9192514806975898961">"Новый тип"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"Личный"</item>
     <item msgid="7084237356602625604">"Рабочий"</item>
     <item msgid="1112044410659011023">"Другой"</item>
-    <item msgid="2374913952870110618">"Создать свой ярлык"</item>
+    <item msgid="2374913952870110618">"Новый тип"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"Домашний"</item>
     <item msgid="5629153956045109251">"Рабочий"</item>
     <item msgid="4966604264500343469">"Другой"</item>
-    <item msgid="4932682847595299369">"Создать свой ярлык"</item>
+    <item msgid="4932682847595299369">"Новый тип"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"Домашний"</item>
     <item msgid="1359644565647383708">"Рабочий"</item>
     <item msgid="7868549401053615677">"Другое"</item>
-    <item msgid="3145118944639869809">"Создать свой ярлык"</item>
+    <item msgid="3145118944639869809">"Новый тип"</item>
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"Рабочий"</item>
     <item msgid="4378074129049520373">"Другое"</item>
-    <item msgid="3455047468583965104">"Создать свой ярлык"</item>
+    <item msgid="3455047468583965104">"Новый тип"</item>
   </string-array>
   <string-array name="imProtocols">
     <item msgid="8595261363518459565">"AIM"</item>
@@ -876,7 +894,7 @@
     <item msgid="2506857312718630823">"ICQ"</item>
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
-    <string name="phoneTypeCustom" msgid="1644738059053355820">"Создать свой ярлык"</string>
+    <string name="phoneTypeCustom" msgid="1644738059053355820">"Новый тип"</string>
     <string name="phoneTypeHome" msgid="2570923463033985887">"Домашний"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Мобильный"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"Рабочий"</string>
@@ -901,20 +919,20 @@
     <string name="eventTypeBirthday" msgid="2813379844211390740">"День рождения"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Юбилей"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Другой"</string>
-    <string name="emailTypeCustom" msgid="8525960257804213846">"Создать свой ярлык"</string>
+    <string name="emailTypeCustom" msgid="8525960257804213846">"Новый тип"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"Личный"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Рабочий"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Другой"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Мобильный"</string>
-    <string name="postalTypeCustom" msgid="8903206903060479902">"Создать свой ярлык"</string>
+    <string name="postalTypeCustom" msgid="8903206903060479902">"Новый тип"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"Домашний"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Рабочий"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Другой"</string>
-    <string name="imTypeCustom" msgid="2074028755527826046">"Создать свой ярлык"</string>
+    <string name="imTypeCustom" msgid="2074028755527826046">"Новый тип"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"Домашний"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Рабочий"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Другой"</string>
-    <string name="imProtocolCustom" msgid="6919453836618749992">"Создать свой ярлык"</string>
+    <string name="imProtocolCustom" msgid="6919453836618749992">"Новый тип"</string>
     <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
     <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -926,7 +944,7 @@
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
     <string name="orgTypeWork" msgid="29268870505363872">"Работа"</string>
     <string name="orgTypeOther" msgid="3951781131570124082">"Другое"</string>
-    <string name="orgTypeCustom" msgid="225523415372088322">"Создать свой ярлык"</string>
+    <string name="orgTypeCustom" msgid="225523415372088322">"Новый тип"</string>
     <string name="relationTypeCustom" msgid="3542403679827297300">"Особый"</string>
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Секретарь"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Брат"</string>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хочет включить функцию \"Аудиоподсказки\". Она позволяет прослушивать или просматривать описание элементов, которых вы касаетесь, и управлять телефоном с помощью жестов."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 месяц назад"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Более месяца назад"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 секунду назад"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> с. назад"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 минуту назад"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 час назад"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Последние <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">За последний <xliff:g id="COUNT_1">%d</xliff:g> день</item>
+      <item quantity="few">За последние <xliff:g id="COUNT_1">%d</xliff:g> дня</item>
+      <item quantity="many">За последние <xliff:g id="COUNT_1">%d</xliff:g> дней</item>
+      <item quantity="other">За последние <xliff:g id="COUNT_1">%d</xliff:g> дня</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Прошлый месяц"</string>
     <string name="older" msgid="5211975022815554840">"Еще раньше"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"вчера"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"через 1 секунду"</item>
-    <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"через 1 минуту"</item>
-    <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"через 1 час"</item>
-    <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"завтра"</item>
-    <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 сек. назад"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 мин. назад"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 час назад"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"вчера"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
-    <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> с."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"через 1 мин."</item>
-    <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"через 1 час"</item>
-    <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> ч."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"завтра"</item>
-    <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"в <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"в <xliff:g id="YEAR">%s</xliff:g> г."</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"нед."</string>
     <string name="year" msgid="4001118221013892076">"г."</string>
     <string name="years" msgid="6881577717993213522">"г."</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 сек."</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 мин."</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> мин."</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ч."</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ч."</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> секунды</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> минута</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> минуты</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> минут</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минут</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> час</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> часа</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> часов</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> часов</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Ошибка"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Это видео не предназначено для потокового воспроизведения на данном устройстве."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не удалось воспроизвести видео."</string>
@@ -1267,8 +1230,8 @@
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
-    <string name="whichSendApplication" msgid="6902512414057341668">"Поделиться с помощью приложения:"</string>
-    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Предоставлять доступ с помощью приложения \"%1$s\""</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"Поделиться с помощью:"</string>
+    <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Поделиться через %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Выберите главное приложение"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Назначьте приложение \"%1$s\" главным"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"По умолчанию для этого действия"</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Запуск Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимизация хранилища…"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизация приложения <xliff:g id="NUMBER_0">%1$d</xliff:g> из <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Подготовка приложения \"<xliff:g id="APPNAME">%1$s</xliff:g>\"..."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск приложений."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Окончание загрузки..."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Приложение <xliff:g id="APP">%1$s</xliff:g> запущено"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не запускать новое приложение."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Запустить приложение <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Остановить старое приложение без сохранения изменений."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Выберите действие для текста"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Громкость звонка"</string>
     <string name="volume_music" msgid="5421651157138628171">"Громкость мультимедиа"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Без звука"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодии"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Неизвестная мелодия"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Доступна сеть Wi-Fi"</item>
-    <item quantity="other" msgid="4192424489168397386">"Доступна сеть Wi-Fi"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Найдена доступная сеть Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"Найдены доступные сети Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Есть доступные сети Wi-Fi</item>
+      <item quantity="few">Есть доступные сети Wi-Fi</item>
+      <item quantity="many">Есть доступные сети Wi-Fi</item>
+      <item quantity="other">Есть доступные сети Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Есть открытые сети Wi-Fi</item>
+      <item quantity="few">Есть открытые сети Wi-Fi</item>
+      <item quantity="many">Есть открытые сети Wi-Fi</item>
+      <item quantity="other">Есть открытые сети Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Подключение к Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Войдите в сеть"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложение \"%1$s\" запрашивает доступ на подключение к сети Wi-Fi (%2$s)"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не удалось запустить Wi-Fi Direct."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Подключен как устройство хранения данных"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Подключен как камера"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Подключено как MIDI-устройство"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Подключен как установщик"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB-устройство подключено"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Нажмите, чтобы открыть список опций."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Пропустить"</string>
     <string name="no_matches" msgid="8129421908915840737">"Нет совпадений"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Найти на странице"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 совпадение"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> из <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> совпадение из <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> совпадения из <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> совпадений из <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> совпадений из <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Готово"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Отключение USB-накопителя..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Отключение SD-карты..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Создайте PIN-код для изменения ограничений."</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коды не совпадают. Повторите попытку."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код должен содержать не менее 4 символов."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Повтор через 1 сек."</item>
-    <item quantity="other" msgid="4730868920742952817">"Повтор через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунду</item>
+      <item quantity="few">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунды</item>
+      <item quantity="many">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other">Повторите попытку через <xliff:g id="COUNT">%d</xliff:g> секунд</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Повторите попытку позже."</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Чтобы вернуться в обычный режим, проведите пальцем вниз."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Полноэкранный режим"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Чтобы выйти, проведите по экрану сверху вниз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"ОК"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Выбор часов на циферблате"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Выбор минут на циферблате"</string>
@@ -1835,33 +1821,42 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\" одновременно."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Чтобы открепить экран, нажмите и удерживайте кнопку \"Обзор\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Блокировка включена. Ее отключение запрещено правилами организации."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Блокировка выключена"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запрашивать PIN-код для отключения блокировки"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запрашивать графический ключ для отключения блокировки"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запрашивать пароль для отключения блокировки"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы заряд батареи расходовался медленнее, режим энергосбережения уменьшает быстродействие устройства и ограничивает количество ресурсов, затрачиваемых на вибрацию, Геолокацию и большинство процессов обработки данных в фоновом режиме. Приложения, которые используют синхронизацию (например, для электронной почты и обмена SMS), могут не обновляться, пока вы их не откроете.\n\nКогда устройство заряжается, режим энергосбережения отключается автоматически."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"До отключения режима (в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До отключения режима"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"На 1 мин. (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"На %1$d мин. (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"На 1 ч. (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"На %1$d ч. (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 мин."</item>
-    <item quantity="other" msgid="6924190729213550991">"%d мин."</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 ч."</item>
-    <item quantity="other" msgid="5408537517529822157">"%d ч."</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d минуты (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d минут (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d минут (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d час (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d часа (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d часов (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d часов (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d минута</item>
+      <item quantity="few">%d минуты</item>
+      <item quantity="many">%d минут</item>
+      <item quantity="other">%d минут</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d час</item>
+      <item quantity="few">%d часа</item>
+      <item quantity="many">%d часов</item>
+      <item quantity="other">%d часов</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Бессрочно"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Свернуть"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следующего будильника в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следующего будильника"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-запрос преобразован в DIAL-запрос."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-запрос преобразован в USSD-запрос."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-запрос преобразован в новый SS-запрос."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Внешний USB-порт"</string>
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 99413d4..8d0619d 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"තත් <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
     <string name="durationSecond" msgid="985669622276420331">"තත් <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;නම් යොදා නැත&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(දුරකථන අංකයක් නොමැත)"</string>
     <string name="unknownName" msgid="6867811765370350269">"නොදනී"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"කටහඬ තැපෑල"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ඔබගේ SIM පත පතට PUK අගුළු වැටී ඇත. එම අගුල ඇරීමට PUK කේතය ටයිප් කරන්න."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM පතේ අගුළු ඇරීමට PUK2 ටයිප් කරන්න."</string>
     <string name="enablePin" msgid="209412020907207950">"අසාර්ථකයි, SIM/RUIM අඟුල සබල කරන්න."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"SIM කාඩ් පත අඟුළු වැටීමට පෙර ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ක් ඉතිරිව ඇත."</item>
-    <item quantity="other" msgid="7530597808358774740">"SIM කාඩ් පත අඟුළු වැටීමට පෙර ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ක් ඉතිරිව ඇත."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">ඔබේ SIM කාඩ් පත අඟුළු වැටීමට පෙර තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
+      <item quantity="other">ඔබේ SIM කාඩ් පත අඟුළු වැටීමට පෙර තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"පැමිණෙන අමතන්නාගේ ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"අහස්යානා අකාරය අක්‍රියයි"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"සැකසීම්"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"හඬ සහායක"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"ආරක්‍ෂිත ආකාරය"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"දූරස්ථ දර්ශනය ඉහල මට්ටමේ අතුරු මුහුණතක් වෙත සම්බන්ධ කිරීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"විජට සේවාවකට බඳින්න"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"විජට් සේවාව ඉහල මට්ටමේ අතුරු මුහුණතක් වෙත සම්බන්ධ කිරීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"මාර්ග ප්‍රතිපාදකගේ සේවාව බඳින්න"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ඕනෑම ලියාපදිංචි කළ මාර්ග ප්‍රතිපාදකයන්ට බඳින්න ධාරකයාට අනුමත කරන්න. සාමාන්‍ය යෙදුම් සඳහා කිසිදා අවශ්‍ය නොවෙයි."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"උපාංග පරිපාලක සමඟ අන්තර්ක්‍රියාකාරී වීම"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"උපාංග පාලකයා වෙතට අභිප්‍රායයන් යැවීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV ආදානයක් වෙතට බඳින්න"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"ආසන්න ක්ෂේත්‍ර සන්නිවේදන (NFC) ටැග්, පත්, සහ කියවන්නන් සමඟ සන්නිවේදනය කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ඔබගේ තිරයේ අගුල අබල කරන්න"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"යතුරු අගුල සහ ඕනෑම සම්බන්ධිත මුරපද ආරක්ෂාවක් අබල කිරීමට යෙදුමට අවසර දෙන්න. මෙහි උදාහරණයක් වන්නේ පැමිණෙන ඇමතුමක් ලැබෙද්දී, දුරකථනය අක්‍රිය වන අතර ඇමතුම අවසාන වන විට යතුරු අගුල නැවත සක්‍රිය වෙයි."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"ඇඟිලි සලකුණු දෘඩාංග කළමනාකරණය කිරීම."</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ඇඟිලි සලකුණු සැකිලි එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ විධික්‍රම භාවිතය සඳහා මෙම යෙදුමට අවසර දෙයි."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ඇඟිලි සලකුණු දෘඩාංග භාවිතා කරන්න."</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"අනන්‍යතාවය තහවුරු කරගැනීමට ඇඟිලි සලකුණු දෘඩාංග භාවිතා කිරීමට මෙම යෙදුමට ඉඩ දෙන්න."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"සමමුහුර්ත කිරීම සක්‍රිය කරන්න සහ අක්‍රිය කරන්න"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"වෙනත් යෙදුම් විසින් කළ පල කිරීම්ද ඇතුළත්ව දැන්වීම් ලබා ගැනීමට, පරීක්ෂා කිරීමට සහ හිස් කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"දැනුම්දීම ඇහුම්කන් දීම් සේවාවක් වෙත බඳින්න"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"දැනුම්දීම් අසන්නාගේ සේවාවේ ඉහළ මට්ටමේ අතුරුමුහුණතට බැඳීමට දරන්නාට අවසර දේ. සාමාන්‍ය යෙදුම් සඳහා කිසිසේත් අවශ්‍ය නොවේ."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"තෝරන්නා ඉලක්ක කරගත් සේවාවකට සම්බන්ධ කරන්න"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"තෝරන්නා ඉලක්ක කරගත් සේවාවක ඉහළ මට්ට‍‍‍මේ අතුරු මුහුණත වෙත සම්බන්ධ වීමට ධාරකයාට ඉඩ‍‍දෙන්න. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවනු ඇත."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"තත්ත්වය සපයන්නාගේ සේවාවට බඳින්න"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"තත්ත්වය සපයන්නාගේ සේවාවට ඉහළ-මට්ටමේ අතුරු මුහුණතක් බැඳිමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම් සඳහා කවදාවත් අවශ්‍යය නොවෙයි."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"මාධ්‍ය ගමන් කරන සේවාව බඳින්න"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"මාධ්‍ය ගමන් කරන සේවාවට ඉහළ-මට්ටමේ අතුරු මුහුණතක් බැඳිමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම් සඳහා කවදාවත් අවශ්‍යය නොවෙයි."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ඩ්‍රීම් සේවාවකට බැඳීම"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"ඩ්‍රීම් සේවාව ඉහල මට්ටමේ අතුරු මුහුණතක් වෙත සම්බන්ධ කිරීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"වාහකය සැපයු වින්‍යාසය යෙදුම ඉල්ලා සිටින්න"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"වාහක පණිවිඩ යැවීමේ සේවාවට බදින්න"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"වාහක සේවාව ඉහල මට්ටමේ අතුරු මුහුණතක් වෙත සම්බන්ධ කිරීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"මුරපද නීති සකස් කිරීම"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"තිරය අගුළු ඇරීමේ මුරපදයට අනුමත අකුරු සහ දිග පාලනය කරන්න."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"තිර අගුලු මුරපද සහ PIN තුළ ඉඩ දෙන දිග සහ අනුලකුණු පාලනය කිරීම."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"තිරය අගුළු හැරීමේදී වැරදියට ටයිප් කළ මුරපද ගණන නිරීක්ෂණය කරන්න සහ ටැබ්ලටය අගුළු දමන්න හෝ වැරදි මුරපද බොහෝ ගණනක් ටයිප් කර ඇති නම් ටැබ්ලටයේ සියලු දත්ත මකන්න."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"තීරය අගුළු අරින විට වැරදියට මුරපදය ටයිප් කළ වාර ගණන නිර්ක්ෂණය කරන්න, සහ බොහෝ විටක් වැරදි මුරපද ටයිප් කළේ නම් රුපවාහිනීය අගුළු දමන්න හෝ සියළුම රුපවාහිනී දත්ත මකන්න."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"තිරය අගුළු හැරීමේදී වැරදියට ටයිප් කළ මුරපද ගණන නිරීක්ෂණය කරන්න සහ දුරකථනය අගුළු දමන්න හෝ වැරදි මුරපද බොහෝ ගණනක් ටයිප් කර ඇති නම් දුරකථනයේ සියලු දත්ත මකන්න."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"තිරය අගුළු ඇරීමේ මුරපදය වෙනස් කිරීම"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"තිරය අගුළු ඇරීමේ මුරපදය වෙනස් කරන්න."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"තිරය අගුලු හරින විට වැරදියට මුරපදය ටයිප් කළ වාර ගණන නිරීක්ෂණය කර, ඉතා වැඩි වාර ගණනක් වැරදි මුරපද ටයිප් කළේ නම් ටැබ්ලටය අගුලු දමන්න නැතහොත් මෙම පරිශීලකයාගේ සියලු දත්ත මකන්න."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"තිරය අගුලු හරින විට වැරදියට මුරපදය ටයිප් කළ වාර ගණන නිරීක්ෂණය කර, ඉතා වැඩි වාර ගණනක් වැරදි මුරපද ටයිප් කළේ නම් TV අගුලු දමන්න නැතහොත් මෙම පරිශීලකයාගේ සියලු දත්ත මකන්න."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"තිරය අගුලු හරින විට වැරදියට මුරපදය ටයිප් කළ වාර ගණන නිරීක්ෂණය කර, ඉතා වැඩි වාර ගණනක් වැරදි මුරපද ටයිප් කළේ නම් දුරකථනය අගුලු දමන්න නැතහොත් මෙම පරිශීලකයාගේ සියලු දත්ත මකන්න."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"තිර අගුල වෙනස් කරන්න"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"තිර අගුල වෙනස් කරන්න."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"තිරය අගුළු දැමීම"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"තිරයට අගුළු වැටීම සිදුවන්නේ කෙසේද සහ කවදාද යන්න පාලනය කරන්න."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"සියලු දත්ත මකන්න"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"කර්මාන්ත ශාලා දත්ත යළි පිහිටුවීමෙන් පසුව අනතුරු ඇඟවිමකින් තොරවම ටැබ්ලට් දත්ත මකා දමයි."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"අනතුරු ඇඟවීමකින් තොරව කර්මාන්ත ශාලා දත්ත නැවත සැකසීමක් කිරීමෙන් රූපවාහිනියේ දත්ත මකා දමයි."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"කර්මාන්ත ශාලා දත්ත යළි පිහිටුවීමෙන් පසුව අනතුරු ඇඟවිමකින් තොරවම දුරකථන දත්ත මකා දමයි."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"පරිශීලක දත්ත මකන්න"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"අනතුරු ඇඟවීමකින් තොරව මෙම ටැබ්ලටයෙහි මෙම පරිශීලකයාගේ දත්ත මැකීම."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"අනතුරු ඇඟවීමකින් තොරව මෙම TV හි මෙම පරිශීලකයාගේ දත්ත මැකීම."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"අනතුරු ඇඟවීමකින් තොරව මෙම දුරකථනයෙහි මෙම පරිශීලකයාගේ දත්ත මැකීම."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"උපාංග ගෝලීය නියුතුව සකස් කිරීම"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"කොන්දේසි සක්‍රිය විට පොදු නියුතු එකක් භාවිත කරන ලෙස උපාංගය සකසන්න. පළමු උපාංග පරිපාලකයා පමණක් ඵලදායි පොදු නියුතුව සකසයි."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"තිරය අගුළු දැමීමේ මුරපදය කල් ඉකුත්වීම සකසන්න"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"තිර-අගුළේ මුරපදය වෙනස්වීම කොපමණ කාල පරාසයකින් සිදුවිය යුතුද යන්න පාලනය කිරීම."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ප්‍රතිපත්තිය සක්‍රිය අතරතුර ගෝලීය ප්‍රොක්සි භාවිත කිරීමට උපාංගය සකසන්න. උපාංග හිමිකරුට පමණක් ගෝලීය ප්‍රොක්සි සැකසිය හැකිය."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"තිර අගුලු මුරපදය කල් ඉකුත්වීම සකසන්න"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"තිර අගුලු මුරපදය, PIN, හෝ රටාව කොපමණ කාල පරාසයකින් වෙනස් කළ යුතුද යන්න වෙනස් කිරීම."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ආචයනයේ සංකේතනය සකස් කිරීම"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ආචයනය කළ යෙදුම් දත්ත සංකේතනය කිරීමට අවශ්‍යය."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"කැමරා අබල කිරීම"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"සියලු උපාංග කැමරාවල භාවිතය වලක්වන්න."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"යතුරු ආරක්ෂාවේ විශේෂාංග අබල කරන්න"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"යතුරු ආරක්ෂාව හි සමහර විශේෂාංග භාවිතය වළක්වයි."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"තිර අගුලෙහි විශේෂාංග අක්‍රිය කරන්න"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"තිර අගුලෙහි සමහර විශේෂාංග භාවිතය වළක්වන්න."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"නිවස"</item>
     <item msgid="869923650527136615">"ජංගම"</item>
@@ -1130,75 +1146,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"ස්පර්ශය වෙතින් ගවේෂණය සක්‍රිය කිරීමට <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ට අවශ්‍යයි. ස්පර්ශය වෙතින් ගවේෂණය සක්‍රිය විට, ඔබගේ ඇඟිලිවලට පහළ විස්තර ඇසිය හෝ බැලිය හැක හෝ දුරකථනය සමග අන්තර් ක්‍රියාකාරී වීමට ඉංගිති සිදු කළ හැක."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"මාස 1 කට පෙර"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"මාස 1 කට පෙර"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"තත්පර 1 කට පෙර"</item>
-    <item quantity="other" msgid="3903706804349556379">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"මිනිත්තු 1 ට පෙර"</item>
-    <item quantity="other" msgid="2176942008915455116">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"පැය 1 කට පෙර"</item>
-    <item quantity="other" msgid="2467273239587587569">"පැය <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"අන්තිම දවස් <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">අවසන් දින <xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="other">අවසන් දින <xliff:g id="COUNT_1">%d</xliff:g></item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"අවසාන මාසය"</string>
     <string name="older" msgid="5211975022815554840">"පරණ"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"ඊයේ"</item>
-    <item quantity="other" msgid="2479586466153314633">"දින <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"තත්පර 1 කින්"</item>
-    <item quantity="other" msgid="1241926116443974687">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කදී"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"මිනිත්තු 1 කදී"</item>
-    <item quantity="other" msgid="3330713936399448749">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"පැය 1 ක් තුළ"</item>
-    <item quantity="other" msgid="547290677353727389">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"හෙට"</item>
-    <item quantity="other" msgid="5109449375100953247">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"තත්පර 1 කට පෙර"</item>
-    <item quantity="other" msgid="3699169366650930415">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"මිනිත්තු 1 කට පෙර"</item>
-    <item quantity="other" msgid="851164968597150710">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"පැය 1 කට පෙර"</item>
-    <item quantity="other" msgid="6889970745748538901">"පැය <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"ඊයේ"</item>
-    <item quantity="other" msgid="3453342639616481191">"දින <xliff:g id="COUNT">%d</xliff:g> ට පෙර"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"තත්පර 1 ක් තුළ"</item>
-    <item quantity="other" msgid="5495880108825805108">"තත්පර <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"මිනිත්තු 1 ක් තුළ"</item>
-    <item quantity="other" msgid="4216113292706568726">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"පැය 1 ක් තුළ"</item>
-    <item quantity="other" msgid="3705373766798013406">"පැය <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"හෙට"</item>
-    <item quantity="other" msgid="2973062968038355991">"දින <xliff:g id="COUNT">%d</xliff:g> ක් තුළ"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> වන දා"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> ට"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> තුළ"</string>
@@ -1214,18 +1167,18 @@
     <string name="weeks" msgid="6509623834583944518">"සති"</string>
     <string name="year" msgid="4001118221013892076">"අවුරුද්ද"</string>
     <string name="years" msgid="6881577717993213522">"අවුරුදු"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"තත්පර 1"</item>
-    <item quantity="other" msgid="1886107766577166786">"තත්පර <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"මිනිත්තු 1"</item>
-    <item quantity="other" msgid="3165187169224908775">"මිනිත්තු <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"පැය 1"</item>
-    <item quantity="other" msgid="3863962854246773930">"පැය <xliff:g id="COUNT">%d</xliff:g> ක්"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one">තත්පර <xliff:g id="COUNT">%d</xliff:g> යි</item>
+      <item quantity="other">තත්පර <xliff:g id="COUNT">%d</xliff:g> යි</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one">මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> යි</item>
+      <item quantity="other">මිනිත්තු <xliff:g id="COUNT">%d</xliff:g> යි</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one">පැය <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="other">පැය <xliff:g id="COUNT">%d</xliff:g></item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"වීඩියෝ ගැටලුව"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"මේ වීඩියෝව මෙම උපාංගයට ප්‍රවාහනය සඳහා වලංගු නැත."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"මෙම වීඩියෝව ධාවනය කළ නොහැක."</string>
@@ -1303,6 +1256,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ආරම්භ කරමින්…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"ආචයනය ප්‍රශස්තිකරණය කිරීම."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> කින් <xliff:g id="NUMBER_0">%1$d</xliff:g> වැනි යෙදුම ප්‍රශස්ත කරමින්."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> සූදානම් කරමින්."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"යෙදුම් ආරම්භ කරමින්."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"ඇරඹුම අවසාන කරමින්."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string>
@@ -1313,6 +1267,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"නව යෙදුම ආරම්භ නොකරන්න."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> අරඹන්න"</string>
     <string name="new_app_description" msgid="1932143598371537340">"සුරැකීමකින් තොරව පරණ යෙදුම නවත්වන්න."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"පෙළ සඳහා ක්‍රියාව තෝරන්න"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"හඬ නඟනයේ ශබ්දය"</string>
     <string name="volume_music" msgid="5421651157138628171">"මාධ්‍ය ශබ්දය"</string>
@@ -1333,20 +1295,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"කිසිවක් නැත"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"රිගින්ටෝන"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"නොදන්නා රින්ටෝනය"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi ජාලයක් තිබේ"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi ජාල ඇත"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"විවෘත Wi-Fi ජාලය ලබාගත හැක"</item>
-    <item quantity="other" msgid="7915895323644292768">"විවෘත Wi-Fi ජාල තිබේ"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Wi-Fi ජාල තිබේ</item>
+      <item quantity="other">Wi-Fi ජාල තිබේ</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">විවෘත Wi-Fi ජාල තිබේ</item>
+      <item quantity="other">විවෘත Wi-Fi ජාල තිබේ</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi ජලයට පුරනය වන්න"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ජාලයට පුරනය වන්න"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" දුබල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"යෙදුම් %1$s ක් WiFi ජාලය %2$s වෙත සම්බන්ධ කිරීමට කැමතියි"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"යෙදුම"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ඍජු Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ඍජු Wi-Fi ආරම්භ කරන්න. මෙය Wi-Fi සේවාදායක/හොට්ස්පොට් එක අක්‍රිය කරනු ඇත."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ඍජු Wi-Fi ආරම්භ කළ නොහැක."</string>
@@ -1413,6 +1378,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"හරි"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"මාධ්‍ය උපාංගයක් ලෙස සම්බන්ධිතයි"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"කැමරාවක් ලෙස සම්බන්ධ කර ඇත"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI උපාංගයක් ලෙස සම්බන්ධ වන ලදි"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ස්ථාපිතයක් ලෙස සම්බන්ධයි"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB මෙවලමකට සම්බන්ධිතයි"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"අනෙක් USB විකල්පය සඳහා ස්පර්ශ කරන්න."</string>
@@ -1528,10 +1494,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"මඟ හරින්න"</string>
     <string name="no_matches" msgid="8129421908915840737">"ගැලපීම් නැත"</string>
     <string name="find_on_page" msgid="1946799233822820384">"පිටුවෙහි සෙවීම"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"ගැළපීම් 1 යි"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> කින් <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="TOTAL">%d</xliff:g> න් <xliff:g id="INDEX">%d</xliff:g> යි</item>
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> න් <xliff:g id="INDEX">%d</xliff:g> යි</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"හරි"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB ආචයනය ගැලවීම..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD පත ගලවමින්..."</string>
@@ -1817,12 +1783,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"සිමා වැඩිදියුණු කිරීමට PIN සාදන්න"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN නොගැළපෙයි. නැවත උත්සහ කරන්න."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN කුඩා වැඩිය. ඉලක්කම් 4 වත් විය යුතුය."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"තවත් තත්පර 1 කින් යළි උත්සාහ කරන්න"</item>
-    <item quantity="other" msgid="4730868920742952817">"තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සහ කරන්න"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සාහ කරන්න</item>
+      <item quantity="other">තත්පර <xliff:g id="COUNT">%d</xliff:g> කින් නැවත උත්සාහ කරන්න</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"පසුව නැවත උත්සාහ කරන්න"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"උඩ සිට පහළට ස්වයිප් කර පූර්ණ තිරයෙන් ඉවත්වන්න."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"මුළු තිරය බලමින්"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"වැටහුණි"</string>
     <string name="done_label" msgid="2093726099505892398">"අවසන්"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"පැය කවාකාර සර්පනය"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"මිනිත්තු කවාකාර සර්පනය"</string>
@@ -1837,7 +1805,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවේ ස්පර්ශ කර අල්ලා සිටින්න."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, දළ විශ්ලේෂණය ස්පර්ශ කර අල්ලා සිටින්න."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"තිරය අගුළු දමා ඇත. ඔබගේ සංවිධානය විසින් අගුළු ඇරීමට ඉඩ නොදෙයි."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"තිරයේ අගුළු ඇර ඇත"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
@@ -1846,24 +1815,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්‍රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊමේල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්‍රියව අක්‍රිය වේ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ඔබගේ බිඳවැටුම් වේලාව <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> දී අවසන්වන තුරු"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ඔබගේ බිදවැටුම් කාලය අවසන් වන තෙක්"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"මිනිත්තු එකක් සඳහා (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> තෙක්)"</item>
-    <item quantity="other" msgid="2787867221129368935">"මිනිත්තු %1$d සඳහා (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> තෙක්)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"පැය එකක් සඳහා (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> තෙක්)"</item>
-    <item quantity="other" msgid="2827214920627669898">"පැය %1$d සඳහා (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> තෙක්)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"විනාඩි එකක් සඳහා"</item>
-    <item quantity="other" msgid="6924190729213550991">"විනාඩි %d සඳහා"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"පැයක් සඳහා"</item>
-    <item quantity="other" msgid="5408537517529822157">"පැය %d ක් සඳහා"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">මිනිත්තු %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
+      <item quantity="other">මිනිත්තු %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">පැය %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
+      <item quantity="other">පැය %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">මිනිත්තු %d ක් සඳහා</item>
+      <item quantity="other">මිනිත්තු %d ක් සඳහා</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">පැය %d ක් සඳහා</item>
+      <item quantity="other">පැය %d ක් සඳහා</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> තෙක්"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"අනියත ආකාරයට"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"ඔබ මෙය අක්‍රිය කරන තුරු"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"හකුළන්න"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> හි ඊළඟ සීනුව තෙක්"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"ඊළඟ සීනුව තෙක්"</string>
@@ -1876,4 +1845,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS ඉල්ලීම DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS ඉල්ලීම USSD ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS ඉල්ලීම නව DIAL ඉල්ලීම වෙත විකරණය කරන ලදී."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB පර්යන්ත තොට"</string>
 </resources>
diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
index 765c51e..51f7e38 100755
--- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml
+++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e. %-m. %Y</string>
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
index d4953c3..b30fe97 100755
--- a/core/res/res/values-sk/donottranslate-cldr.xml
+++ b/core/res/res/values-sk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e. %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S %-e.%-m.%Y</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 873801b..60cb662 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Bez mena&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(žiadne telefónne číslo)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Bez názvu"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Hlasová schránka"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"Karta SIM je uzamknutá pomocou kódu PUK. Odomknite ju zadaním kódu PUK."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Ak chcete odblokovať kartu SIM, zadajte kód PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"Neúspešné, povoľte uzamknutie SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Zostáva vám <xliff:g id="NUMBER">%d</xliff:g> pokus, než sa vaša karta SIM uzamkne."</item>
-    <item quantity="other" msgid="7530597808358774740">"Počet zostávajúcich pokusov pred uzamknutím karty SIM: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="few">Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy, potom sa vaša SIM karta uzamkne.</item>
+      <item quantity="many">Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusu, potom sa vaša SIM karta uzamkne.</item>
+      <item quantity="other">Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusov, potom sa vaša SIM karta uzamkne.</item>
+      <item quantity="one">Zostáva vám <xliff:g id="NUMBER_0">%d</xliff:g> pokus, potom sa vaša SIM karta uzamkne.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Prichádzajúca identifikácia volajúceho"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim v lietadle je ZAPNUTÝ"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim v lietadle je VYPNUTÝ"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavenia"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Hlasový asistent"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
@@ -431,6 +432,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"viazanie na službu poskytovateľa cesty"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteľovi viazať sa na akýchkoľvek registrovaných poskytovateľov cesty. Normálne aplikácie by toto povolenie nemali nikdy nepotrebovať."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"viazanie na televízny vstup"</string>
@@ -703,7 +706,7 @@
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Umožňuje aplikácii zobraziť informácie o sieťach Wi-Fi. Napríklad o tom, či je sieť Wi-Fi povolená alebo názvy pripojených zariadení Wi-Fi."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"pripojiť a odpojiť od siete Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Umožňuje aplikácii pripojiť sa na prístupové body siete Wi-Fi, odpojiť sa od nich a meniť konfiguráciu zariadení pre siete Wi-Fi."</string>
-    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Povoliť príjem viacsmerového vysielania Wi-Fi"</string>
+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"povoliť príjem Wi-Fi Multicast"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Umožňuje aplikácii prijímať pakety odoslané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries, nielen pomocou vášho tabletu. Spotrebuje viac energie ako režim bez viacsmerového vysielania."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Umožňuje aplikácii prijímať pakety odosielané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries (a nie iba do vášho televízora). Spotrebúva viac energie ako režim bez viacsmerového vysielania."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Umožňuje aplikácii prijímať pakety odoslané na všetky zariadenia v sieti Wi-Fi pomocou viacsmerových adries, nielen pomocou vášho telefónu. Spotrebuje viac energie ako režim bez viacsmerového vysielania."</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie NFC."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivácia zámky obrazovky"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Umožňuje aplikácii zakázať uzamknutie klávesnice a akékoľvek súvisiace zabezpečenie heslom. Príkladom je zakázanie uzamknutia klávesnice pri prichádzajúcom telefonickom hovore a jeho opätovné povolenie po skončení hovoru."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"spravovať hardvér na snímanie odtlačkov prstov"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Umožňuje aplikácii zavolať metódy, ktoré pridávajú a odstraňujú vzory odtlačkov prstov."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"použiť hardvér na snímanie odtlačkov prstov"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Umožňuje aplikácii používať na overenie totožnosti hardvér na snímanie odtlačkov prstov."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítať nastavenia synchronizácie"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"zapnúť alebo vypnúť synchronizáciu"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"viazať sa na výber cieľovej služby"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania na výber cieľovej služby. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"viazanie na službu poskytovateľa podmienky"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby poskytovateľa podmienky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"viazanie na službu smerovania médií"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby smerovania médií. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"viazať sa so službou Dream service"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby Dream service. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"viazať sa na službu na odosielanie správ SMS a MMS operátora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby na odosielanie správ SMS a MMS operátora. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nastavte dĺžku hesiel na odomknutie obrazovky aj kódov PIN a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Sledovať počet nesprávnych hesiel zadaných pri odomykaní obrazovky a zamknúť tablet alebo vymazať všetky údaje tabletu v prípade príliš veľkého počtu neplatných pokusov o zadanie hesla."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite televízor alebo vymažte všetky údaje v ňom."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Sledovať počet nesprávnych hesiel zadaných pri odomykaní obrazovky a zamknúť telefón alebo vymazať všetky údaje v telefóne v prípade príliš veľkého počtu neplatných pokusov o zadanie hesla."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Zmeniť heslo na odomknutie obrazovky"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Zmena hesla na odomknutie obrazovky."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite tablet alebo vymažte všetky údaje tohto používateľa."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite televízor alebo vymažte všetky údaje tohto používateľa."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite telefón alebo vymažte všetky údaje tohto používateľa."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Zmeniť zámku obrazovky"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Zmeňte zámku obrazovky."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Uzamknúť obrazovku"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Ovládať, ako a kedy sa obrazovka uzamkne."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Vymazanie všetkých údajov"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia tabletu."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Vymažte údaje televízora bez upozornenia obnovením jeho továrenských nastavení."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia telefónu."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Vymazať údaje používateľa"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Vymažte bez upozornenia údaje tohto používateľa na tomto tablete."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Vymažte bez upozornenia údaje tohto používateľa na tomto televízore."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Vymažte bez upozornenia údaje tohto používateľa na tomto telefóne."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastaviť globálny server proxy zariadenia"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastaviť vypršanie hesla zámky"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Vyberte globálny proxy server, ktorý sa bude používať po aktivácii pravidiel. Nastaviť ho môže iba vlastník zariadenia."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Nastaviť dátum vypršania platnosti zámky obrazovky"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky, kód PIN alebo vzor."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifrovanie úložiska"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vyžadovať šifrovanie uložených údajov aplikácií."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Zakázať fotoaparáty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zakázať používanie všetkých fotoaparátov zariadenia."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Zákaz funkcií pri zámke klávesov"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Zabrániť používaniu niektorých funkcií pri zámke klávesov."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Vypnúť funkcie zámky obrazovky"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Zabráňte používaniu niektorých funkcií zámky obrazovky."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domov"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Služba <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> požaduje povolenie funkcie Preskúmanie dotykom. Ak je funkcia Preskúmanie dotykom zapnutá, môžete počuť alebo vidieť popisy objektov pod vaším prstom alebo ovládať telefón gestami."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"pred 1 mesiacom"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Viac ako pred 1 mesiacom"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"pred 1 sekundou"</item>
-    <item quantity="other" msgid="3903706804349556379">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Pred minútou"</item>
-    <item quantity="other" msgid="2176942008915455116">"pred <xliff:g id="COUNT">%d</xliff:g> minútami"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"pred 1 hodinou"</item>
-    <item quantity="other" msgid="2467273239587587569">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Posledných <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="few">Posledné <xliff:g id="COUNT_1">%d</xliff:g> dni</item>
+      <item quantity="many">Posledného <xliff:g id="COUNT_1">%d</xliff:g> dňa</item>
+      <item quantity="other">Posledných <xliff:g id="COUNT_1">%d</xliff:g> dní</item>
+      <item quantity="one">Posledný <xliff:g id="COUNT_0">%d</xliff:g> deň</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Minulý mesiac"</string>
     <string name="older" msgid="5211975022815554840">"Staršie"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včera"</item>
-    <item quantity="other" msgid="2479586466153314633">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"o 1 sekundu"</item>
-    <item quantity="other" msgid="1241926116443974687">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"o 1 minútu"</item>
-    <item quantity="other" msgid="3330713936399448749">"o <xliff:g id="COUNT">%d</xliff:g> minút"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"o 1 hodinu"</item>
-    <item quantity="other" msgid="547290677353727389">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"zajtra"</item>
-    <item quantity="other" msgid="5109449375100953247">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"pred 1 s"</item>
-    <item quantity="other" msgid="3699169366650930415">"pred <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"pred 1 min."</item>
-    <item quantity="other" msgid="851164968597150710">"pred <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"pred 1 hodinou"</item>
-    <item quantity="other" msgid="6889970745748538901">"pred <xliff:g id="COUNT">%d</xliff:g> hodinami"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včera"</item>
-    <item quantity="other" msgid="3453342639616481191">"pred <xliff:g id="COUNT">%d</xliff:g> dňami"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"o 1 s"</item>
-    <item quantity="other" msgid="5495880108825805108">"o <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"o 1 min."</item>
-    <item quantity="other" msgid="4216113292706568726">"o <xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"o 1 hodinu"</item>
-    <item quantity="other" msgid="3705373766798013406">"o <xliff:g id="COUNT">%d</xliff:g> hodín"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"zajtra"</item>
-    <item quantity="other" msgid="2973062968038355991">"o <xliff:g id="COUNT">%d</xliff:g> dní"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dňa <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"o <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"z <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"týždne"</string>
     <string name="year" msgid="4001118221013892076">"rok"</string>
     <string name="years" msgid="6881577717993213522">"roky"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 s"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 min."</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min."</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 hod."</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> hod."</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekúnd</item>
+      <item quantity="one">1 sekunda</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minúty</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> minúty</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minút</item>
+      <item quantity="one">1 minúta</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> hodiny</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> hodiny</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> hodín</item>
+      <item quantity="one">1 hodina</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problém s videom"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Je nám ľúto, ale toto video sa nedá streamovať do tohto zariadenia."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Toto video nie je možné prehrať."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Systém Android sa spúšťa…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimalizuje sa úložisko"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Prebieha optimalizácia aplikácie <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripravuje sa aplikácia <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Prebieha spúšťanie aplikácií."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Prebieha dokončovanie spúšťania."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Nespúšťať novú aplikáciu."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Spustiť <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zastaviť starú aplikáciu bez uloženia."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Zvoľte akciu pre text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Hlasitosť vyzváňania"</string>
     <string name="volume_music" msgid="5421651157138628171">"Hlasitosť médií"</string>
@@ -1329,22 +1301,29 @@
     <string name="ringtone_default" msgid="3789758980357696936">"Predvolený tón zvonenia"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Predvolený tón (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Žiadny"</string>
-    <string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváňacie tóny"</string>
+    <string name="ringtone_picker_title" msgid="3515143939175119094">"Tóny zvonenia"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznámy tón zvonenia"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"K dispozícii je sieť Wi-Fi"</item>
-    <item quantity="other" msgid="4192424489168397386">"K dispozícii sú siete Wi-Fi."</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"K dispozícii je verejná sieť Wi-Fi"</item>
-    <item quantity="other" msgid="7915895323644292768">"K dispozícii sú verejné siete Wi-Fi"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="few">K dispozícii sú siete Wi-Fi</item>
+      <item quantity="many">K dispozícii sú siete Wi-Fi</item>
+      <item quantity="other">K dispozícii sú siete Wi-Fi</item>
+      <item quantity="one">K dispozícii je sieť Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="few">K dispozícii sú verejné siete Wi-Fi</item>
+      <item quantity="many">K dispozícii sú verejné siete Wi-Fi</item>
+      <item quantity="other">K dispozícii sú verejné siete Wi-Fi</item>
+      <item quantity="one">K dispozícii je verejná sieť Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Prihlásenie sa do siete Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Prihláste sa do siete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikácia %1$s sa chce pripojiť k sieti Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikácia"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi-Fi. Táto možnosť vypne sieť Wi-Fi v režime klient alebo hotspot."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Priame pripojenie siete Wi-Fi sa nepodarilo spustiť"</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Pripojené ako mediálne zariadenie"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Pripojené ako fotoaparát"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Pripojené ako zariadenie MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Pripojené ako inštalátor"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Pripojené k periférnemu zariadeniu USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Dotykom zobrazíte ďalšie možnosti USB."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Preskočiť"</string>
     <string name="no_matches" msgid="8129421908915840737">"Žiadne zhody"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Vyhľadať na stránke"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Počet zhôd: 1"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> z <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 zápas</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Hotovo"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Prebieha odpájanie úložiska USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Prebieha odpájanie karty SD..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Vytvoriť kód PIN pre obmedzenia upravovania"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kódy PIN sa nezhodujú. Skúste to znova."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Kód PIN je príliš krátky. Musí mať minimálne 4 číslice."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Skúste to zas o 1 s"</item>
-    <item quantity="other" msgid="4730868920742952817">"Skúste to zas o <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="few">Skúste to znova o <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="many">Skúste to znova o <xliff:g id="COUNT">%d</xliff:g> sekundy</item>
+      <item quantity="other">Skúste to znova o <xliff:g id="COUNT">%d</xliff:g> sekúnd</item>
+      <item quantity="one">Skúste to znova o 1 sekundu</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Režim celej obrazovky ukončíte posunutím nadol."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazenie na celú obrazovku"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ukončite prejdením prstom z hornej časti nadol."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumiem"</string>
     <string name="done_label" msgid="2093726099505892398">"Hotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posúvač hodín"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posúvač minút"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ak chcete uvoľniť túto obrazovku, súčasne klepnite na tlačidlá Späť a Prehľad a podržte ich."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ak chcete uvoľniť túto obrazovku, klepnite na tlačidlo Prehľad a podržte ho."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Obrazovka je pripnutá. Uvoľnenie vaša organizácia nepovoľuje."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Obrazovka bola uvoľnená"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Šetrič batérie znižuje výkonnosť vášho zariadenia a obmedzuje vibrovanie, služby určovania polohy a väčšinu údajov na pozadí, aby tak pomohol predĺžiť výdrž batérie. E-mailová aplikácia, aplikácia na odosielanie správ SMS a MMS a ďalšie aplikácie, ktoré sú založené na synchronizácii, sa pravdepodobne aktualizujú až po ich otvorení.\n\nŠetrič batérie sa automaticky vypne, keď zariadenie začnete nabíjať."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dokým o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> neskončí výpadok"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kým skončí vaša odstávka"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Na minútu (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Na %1$d min. (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Na hodinu (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Na %1$d hod. (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Na 1 h"</item>
-    <item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="few">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d minút (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Minútu (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="few">%1$d hodiny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d hodiny (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d hodín (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Hodinu (do <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="few">%d minúty</item>
+      <item quantity="many">%d minúty</item>
+      <item quantity="other">%d minút</item>
+      <item quantity="one">Minútu</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="few">%d hodiny</item>
+      <item quantity="many">%d hodiny</item>
+      <item quantity="other">%d hodín</item>
+      <item quantity="one">Hodinu</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Natrvalo"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Zbaliť"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do ďalšieho budíka o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do ďalšieho budíka"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Žiadosť SS bola upravená na žiadosť DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Žiadosť SS bola upravená na žiadosť USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Žiadosť SS bola upravená na novú žiadosť SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Port USB pre periférne zariadenia"</string>
 </resources>
diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
index 17d8609..798f4c0 100755
--- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml
+++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%d. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S, %-e. %b %Y</string>
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
index 83e4693..92cd963 100755
--- a/core/res/res/values-sl/donottranslate-cldr.xml
+++ b/core/res/res/values-sl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s. %s. %s"</string>
     <string name="month_day_year">%d. %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e. %b. %Y</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5724abc..6fe00d1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Brez naslova&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ni telefonske številke)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Neznano"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Glasovna pošta"</string>
@@ -63,10 +61,12 @@
     <string name="needPuk" msgid="919668385956251611">"Kartica SIM je zaklenjena s kodo PUK. Če jo želite odkleniti, vnesite kodo PUK."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Če želite odstraniti blokiranje kartice SIM, vnesite PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"Ni uspelo. Omogočite zaklepanje kartice SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se bo kartica SIM zaklenila."</item>
-    <item quantity="other" msgid="7530597808358774740">"Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat. Potem se bo kartica SIM zaklenila."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus. Potem se bo kartica SIM zaklenila.</item>
+      <item quantity="two">Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusa. Potem se bo kartica SIM zaklenila.</item>
+      <item quantity="few">Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskuse. Potem se bo kartica SIM zaklenila.</item>
+      <item quantity="other">Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusov. Potem se bo kartica SIM zaklenila.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ID dohodnega klicatelja"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Način za letalo je VKLOPLJEN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način za letalo je IZKLOPLJEN"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
@@ -431,6 +432,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Povezava s storitvijo ponudnika poti"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Omogoča imetniku, da se povezuje z registriranimi ponudniki poti. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne aplikacije."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"povezava s TV-vhodom"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Podpira komunikacijo med računalnikom in oznakami, karticami in bralniki komunikacije s tehnologijo bližnjega polja."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"onemogočanje zaklepanja zaslona"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Aplikaciji dovoljuje, da onemogoči zaklep tipkovnice in morebitno povezano varnostno geslo. Telefon na primer onemogoči zaklep tipkovnice pri dohodnem klicu ter vnovič omogoči zaklep, ko je klic končan."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"upravljanje strojne opreme za prstne odtise"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Aplikaciji omogoča sprožanje načinov za dodajanje in brisanje predlog s prstnimi odtisi za uporabo."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"uporaba strojne opreme za prstne odtise"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Aplikaciji omogoča uporabo strojne opreme za prstne odtise za preverjanje pristnosti"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"branje nastavitev sinhronizacije"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Aplikaciji omogoča branje nastavitev sinhronizacije za račun. S tem lahko aplikacija na primer ugotovi, ali je aplikacija Ljudje sinhronizirana z računom."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"vklop in izklop sinhronizacije"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"povezava s storitvijo izbirnika cilja"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Imetniku omogoča povezovanje z vmesnikom storitve izbirnika cilja najvišje ravni. Nikoli ni potrebno za navadne aplikacije."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezovanje s storitvijo ponudnika pogojev"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Imetniku omogoča povezovanje z vmesnikom storitve ponudnika pogojev najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"povezovanje s storitvijo poti predstavnosti"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Imetniku omogoča povezovanje z vmesnikom storitve poti predstavnosti najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"povezava s storitvijo sanjarjenja"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Imetniku omogoča povezovanje z vmesnikom storitve sanjarjenja najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"sprožitev operaterjeve aplikacije za konfiguracijo"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"povezovanje z operaterjevo sporočilno storitvijo"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Imetniku omogoča povezovanje z vmesnikom operaterjeve sporočilne storitve najvišje ravni. To naj ne bi bilo nikoli potrebno za navadne aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih in kodah PIN za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Nadzoruje število nepravilno vnesenih gesel pri odklepanju zaslona in zaklene tablični računalnik ali izbriše vse podatke v njem, če je vnesenih preveč nepravilnih gesel."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene televizor ali izbriše vse podatke v televizorju, če je vnesenih preveč nepravilnih gesel."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Spremljajte število vnesenih napačnih gesel, s katerimi želite odkleniti zaslon. Če je teh vnosov preveč, zaklenite telefon ali izbrišite vse podatke v njem."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Spreminjanje gesla za odklepanje zaslona"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Sprememba gesla za odklepanje zaslona."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene tablični računalnik ali izbriše vse podatke lastnika, če je vnesenih preveč nepravilnih gesel."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene televizor ali izbriše vse podatke lastnika, če je vnesenih preveč nepravilnih gesel."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene telefon ali izbriše vse podatke lastnika, če je vnesenih preveč nepravilnih gesel."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Spreminjanje zaklepanja zaslona"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Spreminjanje zaklepanja zaslona."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Zaklepanje zaslona"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Nadzor nad tem, kako in kdaj se zaklene zaslon."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Brisanje vseh podatkov"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Izbris podatkov v tabličnem računalniku brez opozorila s ponastavitvijo na tovarniške nastavitve"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Brez opozorila izbriše podatke v televizorju, tako da izvede ponastavitev na tovarniške nastavitve."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Izbris podatkov v telefonu brez opozorila s ponastavitvijo na tovarniške nastavitve"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Izbris podatkov uporabnika"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Izbris podatkov uporabnika v tem tabličnem računalniku brez opozorila."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Izbris podatkov uporabnika v tem televizorju brez opozorila."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Izbris podatkov uporabnika v tem telefonu brez opozorila."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavitev globalnega strežnika proxy za napravo"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nastavite globalni strežnik proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo skrbnik prve naprave lahko nastavi veljaven globalni strežnik proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla za zaklepanje zaslona"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Nadzor nad tem, kako pogosto je treba spremeniti geslo za zaklepanje zaslona."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Nastavitev globalnega strežnika proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo lastnik naprave lahko nastavi globalni strežnik proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Nastavitev poteka gesla za zaklepanje zaslona"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Spreminjanje tega, kako pogosto je treba spremeniti geslo, kodo PIN ali vzorec za zaklepanje zaslona."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavitev šifriranja shrambe"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Shranjeni podatki aplikacije morajo biti šifrirani."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Onemogoči fotoaparate"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Prepreči uporabo vseh fotoaparatov v napravi."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Onemogočanje funkcij tipkov."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Preprečitev uporabe nekaterih funkcij tipkovnice."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Izklop funkcij zaklep. zaslona"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Preprečitev uporabe nekaterih funkcij zaklepanja zaslona."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Začetna stran"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Storitev <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi omogočiti raziskovanje z dotikom. Ko je raziskovanje z dotikom vklopljeno, lahko slišite ali vidite opise tega, kar je pod vašim prstom, ali izvajate poteze za interakcijo s telefonom."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pred 1 mesecem"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Pred več kot 1 mesecem"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Pred 1 sekundo"</item>
-    <item quantity="other" msgid="3903706804349556379">"pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"pred 1 minuto"</item>
-    <item quantity="other" msgid="2176942008915455116">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"pred 1 uro"</item>
-    <item quantity="other" msgid="2467273239587587569">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Zadnjih <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Zadnji <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
+      <item quantity="two">Zadnja <xliff:g id="COUNT_1">%d</xliff:g> dneva</item>
+      <item quantity="few">Zadnje <xliff:g id="COUNT_1">%d</xliff:g> dni</item>
+      <item quantity="other">Zadnjih <xliff:g id="COUNT_1">%d</xliff:g> dni</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Pretekli mesec"</string>
     <string name="older" msgid="5211975022815554840">"Starejše"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"včeraj"</item>
-    <item quantity="other" msgid="2479586466153314633">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"čez 1 sekundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"Čez <xliff:g id="COUNT">%d</xliff:g> sekund"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"čez 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"Čez toliko minut: <xliff:g id="COUNT">%d</xliff:g>."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"čez 1 uro"</item>
-    <item quantity="other" msgid="547290677353727389">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"jutri"</item>
-    <item quantity="other" msgid="5109449375100953247">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"pred 1 sekundo"</item>
-    <item quantity="other" msgid="3699169366650930415">"Pred toliko sekundami: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"pred 1 minuto"</item>
-    <item quantity="other" msgid="851164968597150710">"Pred <xliff:g id="COUNT">%d</xliff:g> minutami"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"pred 1 uro"</item>
-    <item quantity="other" msgid="6889970745748538901">"Pred <xliff:g id="COUNT">%d</xliff:g> urami"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"včeraj"</item>
-    <item quantity="other" msgid="3453342639616481191">"Pred <xliff:g id="COUNT">%d</xliff:g> dnevi"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"čez 1 sekundo"</item>
-    <item quantity="other" msgid="5495880108825805108">"čez toliko sekund: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"čez 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"čez <xliff:g id="COUNT">%d</xliff:g> minut"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"čez 1 uro"</item>
-    <item quantity="other" msgid="3705373766798013406">"čez <xliff:g id="COUNT">%d</xliff:g> ur"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"jutri"</item>
-    <item quantity="other" msgid="2973062968038355991">"čez <xliff:g id="COUNT">%d</xliff:g> dni"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"vsak <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ob <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"leta <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"tednov"</string>
     <string name="year" msgid="4001118221013892076">"leto"</string>
     <string name="years" msgid="6881577717993213522">"let"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekunda"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuta"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> min"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ura"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> h"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekunda</item>
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekund</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> minuti</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minute</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ura</item>
+      <item quantity="two"><xliff:g id="COUNT">%d</xliff:g> uri</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> ure</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ur</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Težava z videoposnetkom"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ta videoposnetek ni veljaven za pretakanje v to napravo."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Tega videoposnetka ni mogoče predvajati."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android se zaganja …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje shrambe."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Pripravljanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Zagon aplikacij."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Dokončevanje zagona."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> se izvaja"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ne zaženite nove aplikacije."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Začni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ustavi prejšnjo aplikacijo brez shranjevanja."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Izberite dejanje za besedilo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Glasnost zvonjenja"</string>
     <string name="volume_music" msgid="5421651157138628171">"Glasnost predstavnosti"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Brez"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvonjenja"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Neznana melodija zvonjenja"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Na voljo je brezžično omrežje"</item>
-    <item quantity="other" msgid="4192424489168397386">"Na voljo so brezžična omrežja"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Odpiranje razpoložljivega brezžičnega omrežja"</item>
-    <item quantity="other" msgid="7915895323644292768">"Odpiranje razpoložljivih brezžičnih omrežij"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Na voljo so omrežja Wi-Fi</item>
+      <item quantity="two">Na voljo so omrežja Wi-Fi</item>
+      <item quantity="few">Na voljo so omrežja Wi-Fi</item>
+      <item quantity="other">Na voljo so omrežja Wi-Fi</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Na voljo so odprta omrežja Wi-Fi</item>
+      <item quantity="two">Na voljo so odprta omrežja Wi-Fi</item>
+      <item quantity="few">Na voljo so odprta omrežja Wi-Fi</item>
+      <item quantity="other">Na voljo so odprta omrežja Wi-Fi</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Prijava v omrežje Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Prijava v omrežje"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi vzpostaviti povezavo z omrežjem Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"V redu"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Povezan kot predstavnostna naprava"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Povezan kot fotoaparat"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Povezano kot naprava MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Povezan kot namestitveni program"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Priključen na dodatek USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Dotaknite se za prikaz drugih možnosti za USB."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
     <string name="no_matches" msgid="8129421908915840737">"Ni ujemanj"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Najdi na strani"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 ujemanje"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="two"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Končano"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Izpenjanje pomnilnika USB ..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Izpenjanje kartice SD ..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Ustvarite PIN za spreminjanje omejitev"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Kodi PIN se ne ujemata. Poskusite znova."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratek. Imeti mora vsaj 4 števke."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Poskusite znova čez sekundo"</item>
-    <item quantity="other" msgid="4730868920742952817">"Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> s"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekundo</item>
+      <item quantity="two">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+      <item quantity="few">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+      <item quantity="other">Poskusite znova čez <xliff:g id="COUNT">%d</xliff:g> sekund</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Poskusite znova pozneje"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Povlecite z vrha, da zaprete celozaslonski način."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Celozaslonski način"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Zaprete tako, da z vrha s prstom povlečete navzdol."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Razumem"</string>
     <string name="done_label" msgid="2093726099505892398">"Dokončano"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Okrogli drsnik za ure"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Okrogli drsnik za minute"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Če želite odpeti ta zaslon, se hkrati dotaknite tipk Nazaj in Pregled ter ju pridržite."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Če želite odpeti ta zaslon, se dotaknite tipke Pregled in jo pridržite."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Zaslon je pripet. Vaša organizacija ne dovoli odpenjanja."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Zaslon je odpet"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred odpenjanjem vprašaj za PIN"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Do konca prekinitve delovanja ob <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do konca časa nedelovanja"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Eno minuto (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Toliko minut: %1$d (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Eno uro (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Toliko ur: %1$d (do <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
-    <item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Za eno uro"</item>
-    <item quantity="other" msgid="5408537517529822157">"Za %d h"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%d minuto (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="two">%d minuti (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d uro (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="two">%1$d uri (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d ure (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d ur (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d minuto</item>
+      <item quantity="two">%d minuti</item>
+      <item quantity="few">%d minute</item>
+      <item quantity="other">%d minut</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d uro</item>
+      <item quantity="two">%d uri</item>
+      <item quantity="few">%d ure</item>
+      <item quantity="other">%d ur</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Za nedoločen čas"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Strni"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Do naslednjega alarma ob <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Do naslednjega alarma"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Zahteva SS je spremenjena v zahtevo DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Zahteva SS je spremenjena v zahtevo USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Zahteva SS je spremenjena v novo zahtevo SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Zunanja vrata USB"</string>
 </resources>
diff --git a/core/res/res/values-sr-rRS/donottranslate-cldr.xml b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr-rRS/donottranslate-cldr.xml
+++ b/core/res/res/values-sr-rRS/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%d. %B %Y.</string>
     <string name="time_of_day">%H.%M.%S</string>
     <string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
index 8bb5fa7f1..a0f4bc2 100755
--- a/core/res/res/values-sr/donottranslate-cldr.xml
+++ b/core/res/res/values-sr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s."</string>
     <string name="month_day_year">%d. %B %Y.</string>
     <string name="time_of_day">%H.%M.%S</string>
     <string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 97659a2..1043b2c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без наслова&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Нема броја телефона)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Непознато"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Гласовна пошта"</string>
@@ -63,10 +61,11 @@
     <string name="needPuk" msgid="919668385956251611">"SIM картица је закључана PUK кодом. Унесите PUK кôд да бисте је откључали."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Унесите PUK2 да бисте деблокирали SIM картицу."</string>
     <string name="enablePin" msgid="209412020907207950">"Није успело. Омогућите закључавање SIM/RUIM картице."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Имате још <xliff:g id="NUMBER">%d</xliff:g> покушај пре него што се SIM картица закључа."</item>
-    <item quantity="other" msgid="7530597808358774740">"Имате још <xliff:g id="NUMBER">%d</xliff:g> покушаја пре него што се SIM картица закључа."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај пре него што се SIM картица закључа.</item>
+      <item quantity="few">Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја пре него што се SIM картица закључа.</item>
+      <item quantity="other">Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја пре него што се SIM картица закључа.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Долазни ИД позиваоца"</string>
@@ -202,6 +201,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Подешавања"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помоћ"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
@@ -431,6 +431,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"повежи са услугом добављача путања"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозвољава власнику да се повеже са добављачима путања. Никада не би требало да буде потребно за обичне апликације."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"повезивање са ТВ улазом"</string>
@@ -737,6 +739,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Дозвољава апликацији да комуницира са ознакама, картицама и читачима комуникације кратког домета (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"онемогућавање закључавања екрана"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Дозвољава апликацији да онемогући закључавање тастатуре и све повезане безбедносне мере са лозинкама. На пример, телефон онемогућава закључавање тастатуре при пријему долазног телефонског позива, а затим га поново омогућава по завршетку позива."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"управљај хардвером за отиске прстију"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозвољава апликацији да активира методе за додавање и брисање шаблона отисака прстију који ће се користити."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отиске прстију"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозвољава апликацији да користи хардвер за отиске прстију ради потврде аутентичности"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"читање подешавања синхронизације"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дозвољава апликацији да чита подешавања синхронизације за налог. На пример, овако може да се утврди да ли је апликација Људи синхронизована са налогом."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"укључивање и искључивање синхронизације"</string>
@@ -791,8 +797,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"повежи се са циљном услугом за бирање"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа циљне услуге за бирање. Никада не би требало да буде потребна за уобичајене апликације."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"повежи са услугом добављача услова"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге добављача услова. Не би требало никада да буде потребно за уобичајене апликације."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"повезивање са услугом усмеравања медија"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге усмеравања медија. Никада не би требало да буде потребно за уобичајене апликације."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"повезивање са услугом сањарења"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Дозвољава власнику да се повеже са интерфејсом услуге сањарења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string>
@@ -810,29 +820,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"повезивање са услугом за размену порука мобилног оператера"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа за услугу за размену порука мобилног оператера. Никада не би требало да буде потребно за стандардне апликације."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролише дужину и знакове дозвољене у лозинкама и PIN-овима за закључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Прати број нетачно унетих лозинки приликом откључавања екрана и закључава таблет или брише податке са таблета ако је нетачна лозинка унета превише пута."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Надгледа број нетачних лозинки које унесете при откључавању екрана и закључава ТВ или брише све податке са њега ако се унесе превише нетачних лозинки."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Прати број нетачно унетих лозинки при откључавању екрана и закључава телефон или брише све податке са телефона ако је нетачна лозинка унета превише пута."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Промена лозинке за откључавање екрана"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Промените лозинку за откључавање екрана."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава таблет или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава ТВ или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Надгледа број нетачних лозинки унетих при откључавању екрана и закључава телефон или брише све податке овог корисника ако се унесе превише нетачних лозинки."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Промени закључавање екрана"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Мења закључавање екрана."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Закључавање екрана"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Контролишите начин и време закључавања екрана."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Брисање свих података"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Брисање података на таблету без упозорења ресетовањем на фабричка подешавања."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Брише све податке са ТВ-а без упозорења ресетовањем на фабричка подешавања."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Избришите податке на телефону без упозорења ресетовањем на фабричка подешавања."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Обриши податке корисника"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Брише податке овог корисника на овом таблету без упозорења."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Брише податке овог корисника на овом ТВ-у без упозорења."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Брише податке овог корисника на овом телефону без упозорења."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подесите глобални прокси сервер уређаја"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Подешавање истека лозинке екрана"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Контролишите колико често лозинка за закључавање екрана мора да се мења."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Подешава глобални прокси уређаја који ће се користити док су смернице омогућене. Само власник уређаја може да подеси глобални прокси."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Подеси истек. лозин. за закљ. екр."</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Мења колико често лозинка, PIN или шаблон за закључавање екрана мора да се мења."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Подешавање шифровања складишта"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Захтева да сачувани подаци апликације буду шифровани."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Онемогућавање камера"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Спречите коришћење свих камера уређаја."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Онемогућавање функција закључавања тастатуре."</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Спречавање неких функција закључавања тастатуре."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Онемогући функ. закључ. екрана"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Спречава коришћење неких функција закључавања екрана."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Кућа"</item>
     <item msgid="869923650527136615">"Мобилни"</item>
@@ -1128,75 +1145,13 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> жели да омогући Истраживање додиром. Када је Истраживање додиром укључено, можете да чујете или видите описе ставке на коју сте ставили прст или да комуницирате са телефоном помоћу покрета."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Пре месец дана"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Пре месец дана"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Пре 1 секунде"</item>
-    <item quantity="other" msgid="3903706804349556379">"пре <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Пре једног минута"</item>
-    <item quantity="other" msgid="2176942008915455116">"пре <xliff:g id="COUNT">%d</xliff:g> минута"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Пре сат времена"</item>
-    <item quantity="other" msgid="2467273239587587569">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"У последња(их) <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Претходни <xliff:g id="COUNT_1">%d</xliff:g> дан</item>
+      <item quantity="few">Претходна <xliff:g id="COUNT_1">%d</xliff:g> дана</item>
+      <item quantity="other">Претходних <xliff:g id="COUNT_1">%d</xliff:g> дана</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Прошлог месеца"</string>
     <string name="older" msgid="5211975022815554840">"Старије"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"јуче"</item>
-    <item quantity="other" msgid="2479586466153314633">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"за 1 секунду"</item>
-    <item quantity="other" msgid="1241926116443974687">"за <xliff:g id="COUNT">%d</xliff:g> секунде(и)"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"за 1 минут"</item>
-    <item quantity="other" msgid="3330713936399448749">"за <xliff:g id="COUNT">%d</xliff:g> минута"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"за 1 сат"</item>
-    <item quantity="other" msgid="547290677353727389">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"сутра"</item>
-    <item quantity="other" msgid="5109449375100953247">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Пре једне сек"</item>
-    <item quantity="other" msgid="3699169366650930415">"пре <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Пре један мин"</item>
-    <item quantity="other" msgid="851164968597150710">"пре <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Пре сат времена"</item>
-    <item quantity="other" msgid="6889970745748538901">"пре <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"јуче"</item>
-    <item quantity="other" msgid="3453342639616481191">"пре <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"за 1 сек"</item>
-    <item quantity="other" msgid="5495880108825805108">"за <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"за 1 мин"</item>
-    <item quantity="other" msgid="4216113292706568726">"за <xliff:g id="COUNT">%d</xliff:g> мин"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"за 1 сат"</item>
-    <item quantity="other" msgid="3705373766798013406">"за <xliff:g id="COUNT">%d</xliff:g> сата(и)"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"сутра"</item>
-    <item quantity="other" msgid="2973062968038355991">"за <xliff:g id="COUNT">%d</xliff:g> дана"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"дана <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"у <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>."</string>
@@ -1212,18 +1167,21 @@
     <string name="weeks" msgid="6509623834583944518">"недеље(а)"</string>
     <string name="year" msgid="4001118221013892076">"година"</string>
     <string name="years" msgid="6881577717993213522">"годинe(а)"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 секунда"</item>
-    <item quantity="other" msgid="1886107766577166786">"Секунди: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 минут"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> минута"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 сат"</item>
-    <item quantity="other" msgid="3863962854246773930">"Сати: <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> секунде</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> минут</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> минута</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> минута</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> сат</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> сата</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> сати</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Проблем са видео снимком"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Овај видео не може да се стримује на овом уређају."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Не можете да пустите овај видео."</string>
@@ -1301,6 +1259,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android се покреће…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Меморија се оптимизује."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимизовање апликације <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Припрема се <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Покретање апликација."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завршавање покретања."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
@@ -1311,6 +1270,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не покрећите нову апликацију."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Покрени <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Зауставља стару апликацију без чувања."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Изаберите радњу за текст"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Јачина звука звона"</string>
     <string name="volume_music" msgid="5421651157138628171">"Јачина звука медија"</string>
@@ -1331,20 +1298,25 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Без"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Звукови звона"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Непознати звук звона"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Доступне су Wi-Fi мреже"</item>
-    <item quantity="other" msgid="4192424489168397386">"Доступне Wi-Fi мреже"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Доступна је отворена Wi-Fi мрежа"</item>
-    <item quantity="other" msgid="7915895323644292768">"Доступне су отворене Wi-Fi мреже"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Wi-Fi мреже су доступне</item>
+      <item quantity="few">Wi-Fi мреже су доступне</item>
+      <item quantity="other">Wi-Fi мреже су доступне</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Отворене Wi-Fi мреже су доступне</item>
+      <item quantity="few">Отворене Wi-Fi мреже су доступне</item>
+      <item quantity="other">Отворене Wi-Fi мреже су доступне</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Пријавите се на Wi-Fi мрежу"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Пријављивање на мрежу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликација %1$s жели да се повеже на Wi-Fi мрежу %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Није могуће покренути Wi-Fi Direct."</string>
@@ -1411,6 +1383,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Потврди"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Повезан као медијски уређај"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Повезан као камера"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Повезано је као MIDI уређај"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Повезан као инсталациони програм"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Повезано са USB додатком"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Додирните за друге опције USB-а."</string>
@@ -1526,10 +1499,11 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Прескочи"</string>
     <string name="no_matches" msgid="8129421908915840737">"Нема подударања"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Пронађи на страници"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 подударање"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> од <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Готово"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Искључивање USB меморије..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Искључивање SD картице..."</string>
@@ -1815,12 +1789,15 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Покушајте опет за 1 сек"</item>
-    <item quantity="other" msgid="4730868920742952817">"Покушајте опет за <xliff:g id="COUNT">%d</xliff:g> сек"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
+      <item quantity="few">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
+      <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Превуците прстом одозго надоле да бисте изашли из целог екрана."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Кружни клизач за сате"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Кружни клизач за минуте"</string>
@@ -1835,33 +1812,38 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Да бисте откачили овај екран, истовремено додирните и задржите Назад и Преглед."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Да бисте откачили овај екран, додирните и задржите Преглед."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран је закачен. Ваша организација не дозвољава откачињање."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран је закачен"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран је откачен"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тражи лозинку пре откачињања"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију можда неће да се ажурирају ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"Док се прекид рада не заврши у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Док се време одмора не заврши"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Један минут (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d минута (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Један сат (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d сата(и) (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Један минут"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d мин"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Један сат"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d с"</item>
-  </plurals>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"Док се одмор не заврши у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Док се одмор не заврши"</string>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d минут (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d сат (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d сата (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d сати (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d минут</item>
+      <item quantity="few">%d минута</item>
+      <item quantity="other">%d минута</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d сат</item>
+      <item quantity="few">%d сата</item>
+      <item quantity="other">%d сати</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Бесконачно"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Скупи"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До следећег аларма у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До следећег аларма"</string>
@@ -1874,4 +1856,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS захтев је промењен у DIAL захтев."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS захтев је промењен у USSD захтев."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS захтев је промењен у нови SS захтев."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB порт за периферијске уређаје"</string>
 </resources>
diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml
index 29b120c..35a84eb 100755
--- a/core/res/res/values-sv/donottranslate-cldr.xml
+++ b/core/res/res/values-sv/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index caa0123..a47cb65 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekunder"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekund"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Okänd&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Inget telefonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Okänt"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Röstbrevlåda"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Ditt SIM-kort är PUK-låst. Ange PUK-koden om du vill låsa upp det."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Ange PUK2-koden för att häva spärren av SIM-kortet."</string>
     <string name="enablePin" msgid="209412020907207950">"Försöket misslyckades. Aktivera SIM-/RUIM-lås."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Du har <xliff:g id="NUMBER">%d</xliff:g> försök kvar innan SIM-kortet låses."</item>
-    <item quantity="other" msgid="7530597808358774740">"Du har <xliff:g id="NUMBER">%d</xliff:g> försök kvar innan SIM-kortet låses."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Du har <xliff:g id="NUMBER_1">%d</xliff:g> försök kvar innan SIM-kortet låses.</item>
+      <item quantity="one">Du har <xliff:g id="NUMBER_0">%d</xliff:g> försök kvar innan SIM-kortet låses.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI-kod"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Nummerpresentatör för inkommande samtal"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind till en ruttleverantörstjänst"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillåter att innehavaren binds till en registrerad ruttleverantör. Detta ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"binda till en tv-insignal"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Tillåter att appen kommunicerar med etiketter, kort och läsare för närfältskommunikation (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"inaktivera skärmlåset"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Tillåter att appen inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel kan vara att tangentlåset inaktiveras vid inkommande samtal och aktiveras igen när samtalet är avslutat."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"hantera maskinvara för fingeravtryck"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Tillåter att appen anropar metoder för att lägga till och radera fingeravtrycksmallar."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"använda maskinvara för fingeravtryck"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Tillåter att appen använder maskinvara för fingeravtryck vid autentisering"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"läsa synkroniseringsinställningar"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Tillåter att appen läser synkroniseringsinställningarna för ett konto. Detta kan användas till exempel för att avgöra om appen Personer är synkroniserad med ett konto."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"aktivera/inaktivera synkronisering"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"binda till en målväljartjänst"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en målväljartjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind till en leverantörstjänst"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en leverantörstjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"binda till medieruttjänst"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Tillåter att innehavaren kan binda till den översta nivåns gränssnitt för en medieruttjänst. Detta ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"binda till en drömtjänst"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en drömtjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"anropa konfigurationsappen från operatören"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"binda till en operatörs meddelandetjänst"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en operatörs meddelandetjänst. Ska inte behövas för vanliga appar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Styr tillåten längd och tillåtna tecken i lösenord och pinkoder för skärmlåset."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Övervaka antalet felaktiga lösenord som angetts för skärmlåset och lås surfplattan eller ta bort alla data från surfplattan om för många felaktiga försök görs."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Övervakar antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och låser tv:n eller rensar alla uppgifter på tv:n om för många felaktiga lösenord har skrivits in."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Övervaka antalet felaktiga lösenord som angivits för skärmlåset och lås mobilen eller ta bort alla data från mobilen om för många felaktiga försök görs."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ändra skärmlåsets lösenord"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ändra skärmlåsets lösenord."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås surfplattan eller rensa alla uppgifter för den här användaren om för många felaktiga lösenord har skrivits in."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås tv:n eller rensa alla uppgifter för den här användaren om för många felaktiga lösenord har skrivits in."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås mobilen eller rensa alla uppgifter för den här användaren om för många felaktiga lösenord har skrivits in."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Ändra skärmlåset"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Ändra skärmlåset."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Lås skärmen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrollera hur och när skärmlåset aktiveras."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Radera alla data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ta bort data från surfplattan utan förvarning genom att återställa standardinställningarna."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Rensar uppgifterna på tv:n utan föregående varning genom att återställa standardinställningarna."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ta bort data från mobilen utan förvarning genom att återställa standardinställningarna."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Radera användaruppgifter"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Rensa användarens uppgifter på den här surfplattan utan förvarning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Rensa användarens uppgifter på den här tv:n utan förvarning."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Rensa användarens data på den här mobilen utan förvarning."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ange global proxyserver"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Styr hur ofta lösenordet till skärmlåset måste ändras."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Ange enhetens globala proxy som ska användas när policyn aktiveras. Det är bara enhetens ägare som kan ange global proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ange lösenordets slutdatum"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Ändra hur ofta lösenordet, pinkoden eller mönstret för skärmlåset måste bytas."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ange krypterad lagring"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Kräv att sparade appdata krypteras."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Inaktivera kameror"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Förhindra att enhetens kameror används."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Inaktivera vid knapplås"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Förhindra användning av vissa funktioner vid knapplås."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Inaktivera skärmlåsfunktioner"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Förhindra användning av vissa skärmlåsfunktioner."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vill aktivera Explore by Touch. När funktionen är aktiv kan du höra eller se beskrivningar av vad du har under fingret eller utföra gester för att göra saker med telefonen."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"för 1 månad sedan"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"För mer än en månad sedan"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"för 1 sekund sedan"</item>
-    <item quantity="other" msgid="3903706804349556379">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"för 1 minut sedan"</item>
-    <item quantity="other" msgid="2176942008915455116">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"för 1 timme sedan"</item>
-    <item quantity="other" msgid="2467273239587587569">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"De senaste <xliff:g id="COUNT">%d</xliff:g> dagarna"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">De senaste <xliff:g id="COUNT_1">%d</xliff:g> dagarna</item>
+      <item quantity="one">Den senaste dagen (<xliff:g id="COUNT_0">%d</xliff:g>)</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Föregående månad"</string>
     <string name="older" msgid="5211975022815554840">"Äldre"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"igår"</item>
-    <item quantity="other" msgid="2479586466153314633">"för <xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"om 1 sekund"</item>
-    <item quantity="other" msgid="1241926116443974687">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"om 1 minut"</item>
-    <item quantity="other" msgid="3330713936399448749">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"om 1 timme"</item>
-    <item quantity="other" msgid="547290677353727389">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"imorgon"</item>
-    <item quantity="other" msgid="5109449375100953247">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"för 1 sek sedan"</item>
-    <item quantity="other" msgid="3699169366650930415">"för <xliff:g id="COUNT">%d</xliff:g> sekunder sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"för 1 minut sedan"</item>
-    <item quantity="other" msgid="851164968597150710">"för <xliff:g id="COUNT">%d</xliff:g> minuter sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"för 1 timme sedan"</item>
-    <item quantity="other" msgid="6889970745748538901">"för <xliff:g id="COUNT">%d</xliff:g> timmar sedan"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"igår"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dagar sedan"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"om 1 sekund"</item>
-    <item quantity="other" msgid="5495880108825805108">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"om 1 minut"</item>
-    <item quantity="other" msgid="4216113292706568726">"om <xliff:g id="COUNT">%d</xliff:g> minuter"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"om 1 timme"</item>
-    <item quantity="other" msgid="3705373766798013406">"om <xliff:g id="COUNT">%d</xliff:g> timmar"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"imorgon"</item>
-    <item quantity="other" msgid="2973062968038355991">"om <xliff:g id="COUNT">%d</xliff:g> dagar"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"den <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"kl. <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"veckor"</string>
     <string name="year" msgid="4001118221013892076">"år"</string>
     <string name="years" msgid="6881577717993213522">"år"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 sekund"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minut"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> minuter"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 timme"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> timmar"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="one">1 sekund</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuter</item>
+      <item quantity="one">1 minut</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> timmar</item>
+      <item quantity="one">1 timme</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Videoproblem"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Videon kan tyvärr inte spelas upp i den här enheten."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Det går inte att spela upp videon."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android startar …"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Lagringsutrymmet optimeras."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimerar app <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> förbereds."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Appar startas."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Uppgraderingen är klar."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Starta inte den nya appen."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Avbryt den gamla appen utan att spara."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Välj en åtgärd för text"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ringvolym"</string>
     <string name="volume_music" msgid="5421651157138628171">"Mediavolym"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Okänd ringsignal"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi-nätverk är tillgängliga"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi-nätverk är tillgängliga"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
-    <item quantity="other" msgid="7915895323644292768">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi-nätverk är tillgängliga</item>
+      <item quantity="one">Wi-Fi-nätverk är tillgängligt</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Öppna Wi-Fi-nätverk är tillgängliga</item>
+      <item quantity="one">Öppet Wi-Fi-nätverk är tillgängligt</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Logga in på Wi-Fi-nätverk"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Logga in på nätverket"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vill ansluta till Wi-Fi-nätverket %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/trådlös surfzon."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Det gick inte att starta Wi-Fi direkt."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ansluten som en mediaenhet"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ansluten som en kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Ansluten som en MIDI-enhet"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ansluten som installationsprogram"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ansluten till ett USB-tillbehör"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Tryck om du vill visa andra USB-alternativ."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Hoppa över"</string>
     <string name="no_matches" msgid="8129421908915840737">"Inga träffar"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Sök på sidan"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 träff"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> av <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> av <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 träff</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Klar"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Monterar bort USB-lagringsenhet ..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Monterar bort SD-kort ..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Skapa en pinkod om du vill ändra begränsningar"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Pinkoderna stämmer inte överens. Försök igen."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Pinkoden är för kort. Måste vara minst fyra siffror."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Försök igen om en sekund"</item>
-    <item quantity="other" msgid="4730868920742952817">"Försök igen om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Försök igen om <xliff:g id="COUNT">%d</xliff:g> sekunder</item>
+      <item quantity="one">Försök igen om en sekund</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Försök igen senare"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Dra nedåt om du vill avbryta fullskärmsläget."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Visar på fullskärm"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Dra nedåt från skärmens överkant för att avsluta."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Klart"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Cirkelreglage för timmar"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Cirkelreglage för minuter"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om du vill lossa skärmen trycker du länge på Tillbaka och Översikt samtidigt."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Om du vill lossa skämen trycker du länge på Översikt."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skärmen är fäst. Din organisation tillåter inte att du avslutar läget."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skärmen är inte längre fäst"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Tills avbrottstiden är slut <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tills avbrottstiden är slut"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"I en minut (till kl. <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"I %1$d minuter (till kl. <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"I en timme (till kl. <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"I %1$d timmar (till kl. <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"I en minut"</item>
-    <item quantity="other" msgid="6924190729213550991">"I %d minuter"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"I en timme"</item>
-    <item quantity="other" msgid="5408537517529822157">"I %d timmar"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">I %1$d minuter (till kl. <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">I en minut (till kl. <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">I %1$d timmar (till kl. <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">I en timme (till kl. <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">I %d minuter</item>
+      <item quantity="one">I en minut</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">I %d timmar</item>
+      <item quantity="one">I en timme</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Till kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"För alltid"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Komprimera"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Till nästa alarm kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Till nästa alarm"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS-begäran har ändrats till en DIAL-begäran."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS-begäran har ändrats till en USSD-begäran."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS-begäran har ändrats till en ny SS-begäran."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Perifer USB-port"</string>
 </resources>
diff --git a/core/res/res/values-sw/donottranslate-cldr.xml b/core/res/res/values-sw/donottranslate-cldr.xml
index b6304e7..7313c71 100755
--- a/core/res/res/values-sw/donottranslate-cldr.xml
+++ b/core/res/res/values-sw/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y %B %-e</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8190fd1..1576c67 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"Sekunde <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
     <string name="durationSecond" msgid="985669622276420331">"Sekunde <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Haina jina&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Hakuna nambari ya simu)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Isiyojulikana"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Barua ya sauti"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Kadi yako ya SIM imefungwa na PUK. Anika msimbo wa PUK ili kuifungua."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Chapisha PUK2 ili kufungua SIM kadi."</string>
     <string name="enablePin" msgid="209412020907207950">"Imeshindwa, washa ufungaji wa SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kufungwa."</item>
-    <item quantity="other" msgid="7530597808358774740">"Umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kufungwa."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Umebakisha majaribio <xliff:g id="NUMBER_1">%d</xliff:g> kabla SIM haijafungwa.</item>
+      <item quantity="one">Umebakisha majaribio <xliff:g id="NUMBER_0">%d</xliff:g> kabla SIM haijafungwa.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Kitambulisho cha Mpigaji wa Simu Inayoingia"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Mipangilio"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Usaidizi wa Sauti"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bandika kwenye huduma ya mtoa huduma za njia"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Huruhusu mmiliki kubandika kwenye watoa huduma za njia waliosajiliwa. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Humruhusu mmiliki kutuma kidhibiti cha kifaa malengo. Programu za kawaida hazikihitaji."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bandika kwenye zana za data ya runinga"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Inaruhusu programu kuwasiliana na lebo, kadi na wasomaji wa Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"zima kufuli la skrini yako"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Inaruhusu programu kulemaza ufunguo wa vitufe na usalama mwingine ambata wa nenosiri. Kwa mfano, simu inalemaza ufunguo wa viitufe inapopokea simu inayoingia, kisha inawezesha upya ufunguo wa vitufe wakati simu inapokamilika."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"dhibiti maunzi ya kitambulisho"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Huruhusu programu kuomba njia za kuongeza na kufuta violezo vya kitambulisho kwa matumizi."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"tumia maunzi ya kitambulisho"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Huruhusu programu kutumia maunzi ya kitambulisho kwa uthibitisho"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"kusoma mipangilio ya usawazishaji"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kuwasha na kuzima usawazishaji"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bandika kwenye huduma lengwa ya mchaguaji"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Huruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma lengwa ya mchaguaji. Haitahitajika kamwe kwa programu za kawaida."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bandika kwenye huduma ya mtoa masharti"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Humruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma ya mtoa masharti. Isihitajike kamwe kwa pogramu za kawaida."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"bandika kwenye huduma ya njia za sauti, picha na video."</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Humruhusu mmiliki kubandika kwenye kiolesura cha ngazi ya juu cha huduma ya njia za sauti, picha na video. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"shurutisha kwa huduma murua"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Huruhusu mmiliki kushurutisha kwenye kiolesura cha kiwango cha juu cha huduma murua. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mtoa huduma."</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Shurutisha kwa huduma ya ujumbe ya mtoa huduma"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Huruhusu kishikiliaji kushurutisha kwa kiolesura cha hali ya juu cha huduma ya ujumbe ya mtoa huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Kuweka kanuni za nenosiri"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kudhibiti urefu na herufi zinazoruhusiwa katika manenosiri ya kufungua skrini."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Dhibiti urefu na maandishi yanayokubalika katika nenosiri la kufunga skrini na PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu mara ambazo skrini inajaribu kufunguliwa"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Kufuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na kufunga kompyuta kibao au kufuta data yote iliyomo kama manenosiri mengi yasiyo sahihi yataingizwa."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Fuatilia idadi ya manenosiri yasiyo sahihi yanayoandikwa wakati wa kufungua skrini, na funga runinga au ufute data yote ya runinga ikiwa manenosiri mengi mno yasiyosahihi yataandikwa."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Kufuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na kufunga simu au kufuta data yote iliyomo kama manenosiri mengi sana yasiyo sahihi yataingizwa."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Kubadilisha nenosiri la kufungua skrini"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Kubadilisha nenosiri la kufungua skrini."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Fuatilia idadi ya manenosiri yasiyo sahihi yaliyoingizwa wakati wa kufungua skrini, na ufunge kompyuta kibao au ufute data yote ya mtumiaji huyu kama ameingiza manenosiri yasiyo sahihi mara nyingi kupita kiasi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Fuatilia idadi ya manenosiri yasiyo sahihi yanayoingizwa wakati wa kufungua skrini, na ufunge televisheni au ufute data yote ya mtumiaji kama ameingiza manenosiri yasiyo sahihi mara nyingi kupita kiasi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Fuatilia idadi ya manenosiri yasiyo sahihi yaliyoingizwa wakati wa kufungua skrini, na ufunge simu au ufute data yote ya mtumiaji  huyu kama ameingiza manenosiri yasiyo sahihi mara nyingi kupita kiasi."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Badilisha nenosiri la kufunga skrini"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Badilisha nenosiri la kufunga skrini."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Kufunga skrini"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kudhibiti jinsi na wakati skrini inapofunga."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Kufuta data yote"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Futa data ya kompyuta kibao bila ilani kwa kurejesha mipangilio ya mwanzo."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Futa data ya runinga bila onyo kwa kurejesha katika hali iliyotoka nayo kiwandani."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Kufuta data ya simu bila ilani kwa kurejesha data ambayo kifaa kilitoka nayo kiwandani"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Futa data yote ya mtumiaji"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Futa data ya mtumiaji huyu iliyo kwenye kompyuta kibao hii bila ilani."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Futa data ya mtumiaji huyu iliyo kwenye televisheni hii bila ilani."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Futa data ya mtumiaji huyu iliyo kwenye simu hii bila ilani."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Weka seva mbadala ya ulimwengu kote ya kifaa"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Weka seva mbadala ya ulimwengu kote ya kifaa itakayotumiwa wakati sera iwezeshwa. Msimamizi wa kwanza wa kifaa pekee ndiye anaweza kuweka seva mbadala ya ulimwengu inayofanya kazi."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Kuweka kipindi cha kutumia nenosiri la kufunga skrini"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kudhibiti ni mara ngapi nenosiri la kufunga skrini linafaa libadilishwe."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Weka seva mbadala ya ulimwengu ya kifaa itakayotumika wakati sera imewashwa. Ni mmiliki wa kifaa pekee aneyeweza kuweka seva mbadala ya ulimwengu."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Weka kipindi cha kutumia nenosiri la kufunga skrini"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Badilisha mara ambazo nenosiri la kufunga skrini, PIN, au mchoro,  zinapaswa kubadilishwa."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Kuweka msimbo fiche wa hifadhi"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Inahitaji kwamba data iliyohifadhiwa ya programu iwe na msimbo fiche."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kuzima kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Kuzuia matumizi yote ya kamera za kifaa."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Kuzima vipengele kwenye kilinda vitufe"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Inazuia matumizi ya baadhi ya vipengele kwenye kilinda vitufe."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Zima vipengele vya kufunga skrini"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Inazuia baadhi ya vipengele vya kufunga skrini."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Nyumbani"</item>
     <item msgid="869923650527136615">"Simu ya mkononi"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> inataka kuwezesha Kuchunguza kwa Kugusa. Wakati Kuchunguza kwa Kugusa kumewezeshwa, unaweza kusikia au kuona maelezo ya kilicho chini ya kidole chako au kutumia ishara ili kuingiliana na simu."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Mwezi 1 uliopita"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Kabla ya mwezi 1 uliopita"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"Sekunde 1 iliopita"</item>
-    <item quantity="other" msgid="3903706804349556379">"sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"Dakika 1 iliyopita"</item>
-    <item quantity="other" msgid="2176942008915455116">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"Saa 1 iliyopita"</item>
-    <item quantity="other" msgid="2467273239587587569">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Siku <xliff:g id="COUNT_1">%d</xliff:g> zilizopita</item>
+      <item quantity="one">Siku <xliff:g id="COUNT_0">%d</xliff:g> iliyopita</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Mwezi uliopita"</string>
     <string name="older" msgid="5211975022815554840">"Kuukuu zaidi"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"jana"</item>
-    <item quantity="other" msgid="2479586466153314633">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"kati ya sekunde 1"</item>
-    <item quantity="other" msgid="1241926116443974687">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"kati ya dakika  1"</item>
-    <item quantity="other" msgid="3330713936399448749">"baada ya dakika <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"kati ya saa 1"</item>
-    <item quantity="other" msgid="547290677353727389">"kati ya saa <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"kesho"</item>
-    <item quantity="other" msgid="5109449375100953247">"katika siku <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"Sekunde 1 iliyopita"</item>
-    <item quantity="other" msgid="3699169366650930415">"Sekunde <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"Dakika 1 iliyopita"</item>
-    <item quantity="other" msgid="851164968597150710">"Dakika <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"Saa 1 iliyopita"</item>
-    <item quantity="other" msgid="6889970745748538901">"Saa <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"jana"</item>
-    <item quantity="other" msgid="3453342639616481191">"siku <xliff:g id="COUNT">%d</xliff:g> zilizopita"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"kati ya sekunde 1"</item>
-    <item quantity="other" msgid="5495880108825805108">"kati ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"baada ya dakika 1"</item>
-    <item quantity="other" msgid="4216113292706568726">"kati ya dakika<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"kati ya saa 1"</item>
-    <item quantity="other" msgid="3705373766798013406">"katika saa <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"kesho"</item>
-    <item quantity="other" msgid="2973062968038355991">"kati ya siku <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"tarehe <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"Saa <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ndani  ya <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"wiki"</string>
     <string name="year" msgid="4001118221013892076">"mwaka"</string>
     <string name="years" msgid="6881577717993213522">"miaka"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"Sekunde 1"</item>
-    <item quantity="other" msgid="1886107766577166786">"Sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"Dakika 1"</item>
-    <item quantity="other" msgid="3165187169224908775">"Dakika <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"Saa 1"</item>
-    <item quantity="other" msgid="3863962854246773930">"Saa <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other">Sekunde <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="one">Sekunde 1</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other">Dakika <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="one">Dakika 1</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other">Saa <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="one">Saa 1</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Shida ya video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video hii si halali kutiririshwa kwa kifaa hiki."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Haiwezi kucheza video hii."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Inaanzisha Android..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Inaboresha hifadhi."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Inaboresha programu <xliff:g id="NUMBER_0">%1$d</xliff:g> kutoka <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Inaandaa <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Programu zinaanza"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Inamaliza kuwasha."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> inaendelea"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Usianzishe programu mpya."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Anza <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Komesha programu ya zamani bila kuhifadhi."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Chagua kitendo kwa ajili ya maandishi"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Sauti ya mlio"</string>
     <string name="volume_music" msgid="5421651157138628171">"Sauti ya media"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Mlio amabo haujulikani"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Mtandao wa Wi-Fi unapatikana"</item>
-    <item quantity="other" msgid="4192424489168397386">"Mitandao ya Wi-Fi inapatikana"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Fungua mtandao wa Wi-Fi unaopatikana"</item>
-    <item quantity="other" msgid="7915895323644292768">"Fungua mitandao ya Wi-Fi inayopatikana"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Mitandao ya Wi-Fi inapatikana</item>
+      <item quantity="one">Mtandao wa Wi-Fi unapatikana</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Fungua mitandao ya Wi-Fi inayopatikana</item>
+      <item quantity="one">Fungua mtandao wa Wi-Fi unaopatikana</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Ingia kwenye mtandao wa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Ingia kwenye mtandao"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programu ya %1$s ingependa kuunganisha kwenye Mtandao wa Wifi wa %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programu"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima mteja/mtandao-hewa wa Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Haikuweza kuanzisha Wi-Fi Moja kwa Moja."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Sawa"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Imeunganishwa kama kifaa cha midia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Imeunganishwa kama kamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Kimeunganishwa kama kifaa cha MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Imeunganishwa kama kisakinishi"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Imeunganishwa kwa kifuasi cha USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Gusa ili uone chaguo zingine za USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Ruka"</string>
     <string name="no_matches" msgid="8129421908915840737">"Hakuna vinavyolingana"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Pata kwenye ukurasa"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"Linganisho 1"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ya <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> kati ya <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 inayolingana</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Nimemaliza"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Inaondoa hifadhi ya USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Inaondoa kadi ya SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Unda PIN ya kurekebisha vikwazo"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN hazilingani. Jaribu tena."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ni fupi mno. Lazima iwe angalau tarakimu 4."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Jaribu tena baada ya sekunde 1"</item>
-    <item quantity="other" msgid="4730868920742952817">"Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Jaribu tena baada ya sekunde <xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="one">Jaribu tena baada ya sekunde 1</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Jaribu tena baadaye"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Telezesha kidole kwa kasi chini kuanzia juu ili uondoke kwenye skrini zima."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Unatazama skrini nzima"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ili kuondoka, telezesha kidole chini kutoka sehemu ya juu."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Nimeelewa"</string>
     <string name="done_label" msgid="2093726099505892398">"Imekamilika"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kitelezi cha mviringo wa saa"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kitelezi cha mviringo wa dakika"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ili ubanue skrini hii, gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ili ubanue skrini hii, gusa na ushikilie Muhtasari."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Skrini imebandikwa. Ubanduaji hauruhusiwi na shirika lako."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Skrini imebanduliwa"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Kusaidia kuboresha muda wa matumizi ya betri, inayookoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali, na data nyingi ya chini chini. Barua pepe, ujumbe na programu nyingine zinazotege,ea usawazishaji huenda zisisasishwe usipozifungua.\n\nInayookoa betri hujizima kiotomatiki kifaa chako kinapokuwa kinachaji."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> wakati wa kutotenda kazi kwa kifaa chako unapoisha"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hadi muda wako wa hali tuli utakapoisha"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Kwa dakika moja (hadi <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Kwa dakika %1$d (hadi <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Kwa saa moja (hadi <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Kwa saa %1$d (hadi <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item>
-    <item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Kwa saa moja"</item>
-    <item quantity="other" msgid="5408537517529822157">"Kwa saa %d"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Kwa dakika %1$d (hadi <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Kwa dakika moja (hadi <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Kwa saa %1$d (hadi <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Kwa saa moja (hadi <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Kwa dakika %d</item>
+      <item quantity="one">Kwa dakika moja</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Kwa saa %d</item>
+      <item quantity="one">Kwa saa moja</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Bila kikomo"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hadi utakapozima hili"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Kunja"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hadi kengele inayofuata saa <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hadi kengele inayofuata"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ombi la SS limerekebishwa na kuwa ombi la DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ombi la SS limerekebishwa na kuwa ombi la USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ombi la SS limerekebishwa na kuwa ombi jipya la SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Mlango wa USB wa Pembeni"</string>
 </resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 1b2123c..828f36b 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> வினாடிகள்"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> வினாடி"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;பெயரிடப்படாதது&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(தொலைபேசி எண் இல்லை)"</string>
     <string name="unknownName" msgid="6867811765370350269">"அறியப்படாதவர்"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"குரலஞ்சல்"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"உங்கள் சிம் கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது. அதைத் திறக்க PUK குறியீட்டைத் உள்ளிடவும்."</string>
     <string name="needPuk2" msgid="4526033371987193070">"சிம் கார்டைத் தடுப்பு நீக்க PUK2 ஐ உள்ளிடவும்."</string>
     <string name="enablePin" msgid="209412020907207950">"தோல்வி, சிம்/RUIM பூட்டை இயக்கவும்."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item>
-    <item quantity="other" msgid="7530597808358774740">"சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER_1">%d</xliff:g> முறை முயற்சிக்கலாம்.</item>
+      <item quantity="one">சிம் பூட்டப்படுவதற்கு முன், நீங்கள் <xliff:g id="NUMBER_0">%d</xliff:g> முறை முயற்சிக்கலாம்.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"உள்வரும் அழைப்பாளர் ஐடி"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"விமானப் பயன்முறை இயக்கத்தில் உள்ளது"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"விமானப் பயன்முறை முடக்கத்தில் உள்ளது"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"அமைப்பு"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"தொலைநிலைக் காட்சியின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"விட்ஜெட் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"விட்ஜெட் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"வழு வழங்குநர் சேவையுடன் இணைத்தல்"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"பதிவு செய்த எந்தவொரு வழி வழங்குநர்கள் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"சாதன நிர்வாகியுடன் ஊடாடுதல்"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"சாதன நிர்வாகிக்கு இன்டென்ட்ஸை அனுப்ப, ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"டிவி உள்ளீட்டுடன் இணைத்தல்"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"குறுகிய இடைவெளி தகவல்பரிமாற்றம் (NFC), குறிகள், கார்டுகள் மற்றும் ரீடர்கள் ஆகியவற்றுடன் தொடர்புகொள்ள, பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"உங்கள் திரைப் பூட்டை முடக்குதல்"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"விசைப்பூட்டையும், தொடர்புடைய கடவுச்சொல் பாதுகாப்பையும் முடக்கப் பயன்பாட்டை அனுமதிக்கிறது. எடுத்துக்காட்டாக, உள்வரும் மொபைல் அழைப்பைப் பெறும்போது மொபைல் விசைப்பூட்டை முடக்குகிறது, பிறகு அழைப்பு முடிந்தவுடன் விசைப்பூட்டை மீண்டும் இயக்குகிறது."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"கைரேகை வன்பொருளை நிர்வகி"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"பயன்படுத்துவதற்காக, கைரேகை டெம்ப்ளேட்களைச் சேர்க்க மற்றும் நீக்குவதற்கான செயல்முறைகளை இயக்குவதற்குப் பயன்பாட்டை அனுமதிக்கும்."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"கைரேகை வன்பொருளைப் பயன்படுத்து"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"அங்கீகரிப்பதற்கு, கைரேகை வன்பொருளைப் பயன்படுத்த, பயன்பாட்டை அனுமதிக்கும்"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"ஒத்திசைவு அமைப்புகளைப் படித்தல்"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"கணக்கிற்கான ஒத்திசைவு அமைப்புகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது. எடுத்துக்காட்டாக, பீப்பிள் பயன்பாடு கணக்குடன் ஒத்திசைக்கப்பட்டுள்ளதா என்பதை இது தீர்மானிக்கலாம்."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"ஒத்திசைவை இயக்குவதையும், முடக்குவதையும் மாற்றுதல்"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"பிற பயன்பாடுகளால் இடுகையிடப்பட்ட அறிவிப்புகள் உள்பட எல்லா அறிவிப்புகளையும் பெற, பார்க்க மற்றும் அழிக்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"பயனர் தேர்வுசெய்த இடச் சேவையுடன் இணைக்கும்"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"பயனர் தேர்வுசெய்த இடச் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு, ஹோல்டரை அனுமதிக்கும். இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"நிபந்தனை வழங்குநர் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"நிபந்தனை வழங்குநர் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"மீடியா வழிச் சேவையுடன் இணைத்தல்"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"மீடியா வழிச் சேவையின் உயர்-அளவு இடைமுகத்துடன் இணைக்க உரிமையாளரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு ஒருபோதும் தேவையில்லை."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"டிரீம் சேவையுடன் இணை"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"டிரீம் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"மொபைல் நிறுவனம் வழங்கிய உள்ளமைவு பயன்பாட்டை செயலாக்குதல்"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"மொபைல் நிறுவனச் செய்தியிடல் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"மொபைல் நிறுவனச் செய்தியிடல் சேவையின் உயர்-நிலை இடைமுகத்துடன் ஹோல்டரை இணைக்க அனுமதிக்கும். இயல்பான பயன்பாடுகளுக்குத் தேவைப்படாது."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"கடவுச்சொல் விதிகளை அமைக்கவும்"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"திரையைத் திறக்க கடவுச்சொற்களில் அனுமதிக்கப்பட்ட நீளத்தையும், எழுத்துக்குறிகளையும் கட்டுப்படுத்தலாம்."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"திரைப் பூட்டின் கடவுச்சொற்கள் மற்றும் பின்களில் அனுமதிக்கப்படும் நீளத்தையும் எழுத்துக்குறிகளையும் கட்டுப்படுத்தும்."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"திரைத் திறக்க முயற்சிகளைக் கண்காணித்தல்"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"திரையைத் திறக்கும்போது உள்ளிட்ட தவறான கடவுச்சொற்களின் எண்ணிக்கையைக் கண்காணிக்கும், மேலும் கடவுச்சொற்கள் பலமுறை தவறாக உள்ளிட்டிருந்தால், டேப்லெட்டைப் பூட்டும் அல்லது டேப்லெட்டின் எல்லா தரவையும் அழிக்கும்."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"திரையைத் திறக்கும் போது, எத்தனை முறை கடவுச்சொல்லை உள்ளிட்டீர்கள் என்பதைக் கண்காணிக்கிறது மற்றும் கடவுச்சொற்களைப் பல முறை தவறாக உள்ளிடும் போது, டிவியைப் பூட்டும் அல்லது டிவியின் எல்லா தரவையும் அழிக்கும்."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"திரையைத் திறக்கும்போது உள்ளிட்ட தவறான கடவுச்சொற்களின் எண்ணிக்கையைக் கண்காணிக்கும், மேலும் கடவுச்சொற்கள் பலமுறை தவறாக உள்ளிட்டிருந்தால், மொபைலைப் பூட்டும் அல்லது மொபைலின் எல்லா தரவையும் அழிக்கும்."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"திரைத் திறக்க கடவுச்சொல்லை மாற்றவும்"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"திரையைத் திறக்க கடவுச்சொல்லை மாற்றலாம்."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"திரையைத் திறக்கும் போது, எத்தனை முறை தவறான கடவுச்சொல்லை உள்ளிட்டீர்கள் என்பதைக் கண்காணிக்கிறது மற்றும் கடவுச்சொற்களைப் பல முறை தவறாக உள்ளிட்டால், டேப்லெட்டைப் பூட்டும் அல்லது இந்தப் பயனரின் எல்லா தரவையும் அழிக்கும்."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"திரையைத் திறக்கும் போது, எத்தனை முறை தவறான கடவுச்சொல்லை உள்ளிட்டீர்கள் என்பதைக் கண்காணிக்கிறது மற்றும் கடவுச்சொற்களைப் பல முறை தவறாக உள்ளிட்டால், டிவியைப் பூட்டும் அல்லது இந்தப் பயனரின் எல்லா தரவையும் அழிக்கும்."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"திரையைத் திறக்கும் போது, எத்தனை முறை தவறான கடவுச்சொல்லை உள்ளிட்டீர்கள் என்பதைக் கண்காணிக்கிறது மற்றும் கடவுச்சொற்களைப் பல முறை தவறாக உள்ளிட்டால், ஃபோனைப் பூட்டும் அல்லது இந்தப் பயனரின் எல்லா தரவையும் அழிக்கும்."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"திரைப் பூட்டை மாற்று"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"திரைப் பூட்டை மாற்றும்."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"திரையைப் பூட்டு"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"திரை எப்படி, எப்போது பூட்டப்படுகிறது என்பதைக் கட்டுப்படுத்தலாம்."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"எல்லா தரவையும் அழித்தல்"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ஆரம்பநிலைத் தரவு மீட்டமைப்பின் மூலம் எச்சரிக்கை வழங்காமல் டேப்லெட்டின் தரவை அழிக்கலாம்."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"தரவின் ஆரம்பநிலை மீட்டமைப்பைச் செயற்படுத்துவதன் மூலம், எச்சரிக்கை எதுவும் செய்யாமல் டிவியின் தரவை அழிக்கிறது."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ஆரம்பநிலைத் தரவு மீட்டமைப்பின் மூலம் எச்சரிக்கை வழங்காமல் மொபைலின் தரவை அழிக்கலாம்."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"பயனர் தரவை அழி"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"எச்சரிக்கை எதுவுமின்றி, டேப்லெட்டில் உள்ள இந்தப் பயனரின் தரவை அழிக்கும்."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"எச்சரிக்கை எதுவுமின்றி, டிவியில் உள்ள இந்தப் பயனரின் தரவை அழிக்கும்."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"எச்சரிக்கை எதுவுமின்றி, ஃபோனில் உள்ள இந்தப் பயனரின் தரவை அழிக்கும்."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"சாதன குளோபல் ப்ராக்ஸியை அமை"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"கொள்கை இயக்கப்பட்டிருக்கும்போது பயன்படுத்த வேண்டிய சாதன குளோபல் ப்ராக்ஸியை அமைக்கவும். முதல் சாதன நிர்வாகி மட்டுமே பயனுள்ள குளோபல் ப்ராக்ஸியை அமைக்க முடியும்."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"பூட்டுத் திரை கடவுச்சொல்லின் காலாவதி நேரம் அமை"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"எந்த இடைவெளியில் திரைப்பூட்டின் கடவுச்சொல் மாற்றப்பட வேண்டும் என்பதைக் கட்டுப்படுத்தலாம்."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"கொள்கை இயக்கப்பட்டிருக்கும்போது பயன்படுத்த வேண்டிய சாதன குளோபல் ப்ராக்ஸியை அமைக்கவும். சாதன உரிமையாளரால் மட்டுமே குளோபல் ப்ராக்ஸியை அமைக்க முடியும்."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"திரைப் பூட்டு கடவுச்சொல் காலாவதி நேரத்தை அமை"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"எந்த இடைவெளியில் திரைப் பூட்டின் கடவுச்சொல், பின் அல்லது வடிவம் மாற்றப்பட வேண்டும் என்பதை மாற்றும்."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"சேமிப்பிட முறைமையாக்கலை அமை"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"சேமித்தப் பயன்பாட்டுத் தரவை முறைமையாக்கப்பட வேண்டும் என்பதைக் கோரலாம்."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"கேமராக்களை முடக்கு"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"எல்லா சாதன கேமராக்களைப் பயன்படுத்துவதையும் தடுக்கலாம்."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"விசைப்பாதுகாப்பு அம்சங்களை முடக்கு"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"விசைப்பாதுகாப்பில் சில அம்சங்களைப் பயன்படுத்துவதைத் தடுக்கலாம்."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"திரைப் பூட்டின் அம்சங்களை முடக்கு"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"திரைப் பூட்டின் சில அம்சங்களைப் பயன்படுத்துவதைத் தடுக்கும்."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"வீடு"</item>
     <item msgid="869923650527136615">"மொபைல்"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"தொடுவதன் மூலம் அறிக என்பதை இயக்க <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> விரும்புகிறது. தொடுவதன் மூலம் அறிக என்பது இயக்கப்பட்டிருக்கும்போது, உங்கள் விரலுக்கு அடியில் இருப்பவையின் விளக்கங்களை நீங்கள் கேட்கவோ, பார்க்கவோ செய்யலாம் அல்லது மொபைலுடன் ஊடாட சைகைகளை மேற்கொள்ளலாம்."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 மாதத்திற்கு முன்பு"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 மாதத்திற்கு முன்பு"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 வினாடிக்கு முன்பு"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 நிமிடம் முன்பு"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 மணிநேரம் முன்பு"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"கடந்த <xliff:g id="COUNT">%d</xliff:g> நாட்கள்"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">கடந்த <xliff:g id="COUNT_1">%d</xliff:g> நாட்களில்</item>
+      <item quantity="one">கடந்த <xliff:g id="COUNT_0">%d</xliff:g> நாளில்</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"சென்ற மாதம்"</string>
     <string name="older" msgid="5211975022815554840">"பழையது"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"நேற்று"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 வினாடியில்"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 நிமிடத்தில்"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 மணிநேரத்தில்"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"நாளை"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 வினாடி முன்பு"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 நிமிடம் முன்பு"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> நிமிடத்திற்கு முன்"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 மணிநேரம் முன்பு"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்திற்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"நேற்று"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> நாட்களுக்கு முன்பு"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 வினாடியில்"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகளில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 நிமிடத்தில்"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்களில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 மணிநேரத்தில்"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரத்தில்"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"நாளை"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> நாட்களில்"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> அன்று"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g> இல்"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> இல்"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"வாரங்கள்"</string>
     <string name="year" msgid="4001118221013892076">"ஆண்டு"</string>
     <string name="years" msgid="6881577717993213522">"ஆண்டுகள்"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 வினாடி"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகள்"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 நிமிடம்"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> நிமிடங்கள்"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 மணிநேரம்"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> மணிநேரம்"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> வினாடிகள்</item>
+      <item quantity="one">1 வினாடி</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> நிமிடங்கள்</item>
+      <item quantity="one">1 நிமிடம்</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> மணிநேரம்</item>
+      <item quantity="one">1 மணிநேரம்</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"வீடியோவில் சிக்கல்"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"சாதனத்தில் ஸ்ட்ரீம் செய்வதற்கு இது சரியான வீடியோ அல்ல."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"இந்த வீடியோவை இயக்க முடியவில்லை."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android துவங்குகிறது..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"சேமிப்பகத்தை உகந்ததாக்குகிறது."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> பயன்பாட்டை ஒருங்கிணைக்கிறது."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ஐத் தயார்செய்கிறது."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"பயன்பாடுகள் தொடங்கப்படுகின்றன."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"துவக்குதலை முடிக்கிறது."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> இயங்குகிறது"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"புதிய பயன்பாட்டைத் தொடங்க வேண்டாம்."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> ஐத் தொடங்கு"</string>
     <string name="new_app_description" msgid="1932143598371537340">"சேமிக்காமல், பழைய பயன்பாட்டை நிறுத்தவும்."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"உரைக்கான செயலைத் தேர்வுசெய்யவும்"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ரிங்கரின் ஒலியளவு"</string>
     <string name="volume_music" msgid="5421651157138628171">"மீடியாவின் ஒலியளவு"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ஏதுமில்லை"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"ரிங்டோன்கள்"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"அறியப்படாத ரிங்டோன்"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"வைஃபை நெட்வொர்க் உள்ளது"</item>
-    <item quantity="other" msgid="4192424489168397386">"வைஃபை நெட்வொர்க்குகள் உள்ளன"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"இருக்கும் வைஃபை நெட்வொர்க்கைத் திற"</item>
-    <item quantity="other" msgid="7915895323644292768">"இருக்கும் வைஃபை நெட்வொர்க்குகளைத் திற"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
+      <item quantity="one">வைஃபை நெட்வொர்க் உள்ளது</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">பொது வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
+      <item quantity="one">பொது வைஃபை நெட்வொர்க் உள்ளது</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" இணைய இணைப்பு மோசமாக உள்ளது."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s வைஃபை நெட்வொர்க்குடன், %1$s பயன்பாடு இணைக்க விரும்புகிறது"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ஒரு பயன்பாடு"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"வைஃபை Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"வைஃபை Direct ஐத் தொடங்குக. இது வைஃபை க்ளையண்ட்/ஹாட்ஸ்பாட்டை முடக்கும்."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"வைஃபை Direct ஐத் தொடங்க முடியவில்லை."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"சரி"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"மீடியா சாதனமாக இணைக்கப்பட்டது"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"கேமராவாக இணைக்கப்பட்டுள்ளது"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI சாதனமாக இணைக்கப்பட்டது"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"நிறுவியாக இணைக்கப்பட்டது"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB துணைக்கருவியுடன் இணைக்கப்பட்டுள்ளது"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"மற்ற USB விருப்பங்களுக்குத் தொடவும்."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"தவிர்"</string>
     <string name="no_matches" msgid="8129421908915840737">"பொருத்தம் ஏதுமில்லை"</string>
     <string name="find_on_page" msgid="1946799233822820384">"பக்கத்தில் கண்டறி"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 பொருத்தம்"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g> இல் <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> / <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 பொருத்தம்</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"முடிந்தது"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB சேமிப்பிடத்தை இணைப்பு நீக்குகிறது…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD கார்டை இணைப்பு நீக்குகிறது…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"வரம்புகளைத் திருத்துவதற்கு பின்னை உருவாக்கவும்"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINகள் பொருந்தவில்லை. மீண்டும் முயற்சிக்கவும்."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"பின் மிகவும் சிறியதாக உள்ளது. குறைந்தது 4 இலக்கங்கள் இருக்க வேண்டும்."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 வினாடி கழித்து முயற்சிக்கவும்"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்</item>
+      <item quantity="one">1 வினாடி கழித்து முயற்சிக்கவும்</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"மீண்டும் முயற்சிக்கவும்"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"முழுத் திரையிலிருந்து வெளியேற மேலிருந்து கீழே ஸ்வைப் செய்யவும்."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"முழுத் திரையில் காட்டுகிறது"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"புரிந்தது"</string>
     <string name="done_label" msgid="2093726099505892398">"முடிந்தது"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"மணிநேர வட்ட வடிவ ஸ்லைடர்"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"இந்தத் திரையை விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடித்திருக்கவும்."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"இந்தத் திரையை விலக்க, மேலோட்டப் பார்வையைத் தொட்டுப் பிடித்திருக்கவும்."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"திரை பின் செய்யப்பட்டது. பின்னை அகற்ற உங்கள் நிறுவனம் ஆதரிக்கவில்லை."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"திரையின் பின் அகற்றப்பட்டது"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"பேட்டரி ஆயுளை மேம்படுத்த, பேட்டரி சேமிப்பான் உங்கள் சாதனத்தின் செயல்திறனைக் குறைத்து, அதிர்வு, இடச் சேவைகள் மற்றும் பெரும்பாலான பின்புலத் தரவு போன்றவற்றைக் கட்டுப்படுத்துகிறது. ஒத்திசைவைச் சார்ந்துள்ள மின்னஞ்சல், செய்தியிடல் மற்றும் பிற பயன்பாடுகளானது அவற்றைத் திறக்கும்வரையில் புதுப்பிக்கப்படாமல் போகக்கூடும்.\n\nஉங்கள் ஃபோன் சார்ஜ் செய்யப்படும்போது, பேட்டரி சேமிப்பான் தானாகவே முடங்கும்."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> முடியும் வரை"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"செயலற்ற நேரம் முடியும் வரை"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ஒரு நிமிடத்திற்கு (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> வரை)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d நிமிடங்களுக்கு (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> வரை)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ஒரு மணிநேரத்திற்கு (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> வரை)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d மணிநேரத்திற்கு (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> வரை)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ஒரு நிமிடம்"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d நிமிடங்கள்"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ஒரு மணி நேரம்"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d மணிநேரம்"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d நிமிடங்களுக்கு (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> வரை)</item>
+      <item quantity="one">ஒரு நிமிடத்திற்கு (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> வரை)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d மணிநேரத்திற்கு (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> வரை)</item>
+      <item quantity="one">ஒரு மணிநேரத்திற்கு (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> வரை)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d நிமிடங்களுக்கு</item>
+      <item quantity="one">ஒரு நிமிடத்திற்கு</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d மணிநேரத்திற்கு</item>
+      <item quantity="one">ஒரு மணிநேரத்திற்கு</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> வரை"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"வரையறையற்றது"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"இதை முடக்கும்வரை"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"சுருக்கு"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>க்கு ஒலிக்கும் அடுத்த அலாரம் வரை"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"அடுத்த அலாரம் வரை"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS கோரிக்கையானது DIAL கோரிக்கைக்கு மாற்றப்பட்டது."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS கோரிக்கையானது USSD கோரிக்கைக்கு மாற்றப்பட்டது."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS கோரிக்கையானது புதிய SS கோரிக்கைக்கு மாற்றப்பட்டது."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB பெரிபெரல் போர்ட்"</string>
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 222944f..af672cc 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> సెకన్లు"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> సెకను"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;శీర్షిక లేనిది&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ఫోన్ నంబర్ లేదు)"</string>
     <string name="unknownName" msgid="6867811765370350269">"తెలియదు"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"వాయిస్ మెయిల్"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"మీ సిమ్ కార్డు PUK-లాక్ చేయబడింది. దీన్ని అన్‌లాక్ చేయడానికి PUK కోడ్‌ను టైప్ చేయండి."</string>
     <string name="needPuk2" msgid="4526033371987193070">"సిమ్ కార్డు‌ను అన్‌బ్లాక్ చేయడానికి PUK2ని టైప్ చేయండి."</string>
     <string name="enablePin" msgid="209412020907207950">"వైఫల్యం, సిమ్/RUIM లాక్‌ను ప్రారంభించండి."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"సిమ్ లాక్ కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది."</item>
-    <item quantity="other" msgid="7530597808358774740">"సిమ్ లాక్ కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">SIM లాక్ కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
+      <item quantity="one">SIM లాక్ కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"ఇన్‌కమింగ్ కాలర్ ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ఎయిర్‌ప్లేన్ మోడ్ ఆన్‌లో ఉంది"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ఎయిర్‌ప్లేన్ మోడ్ ఆఫ్‌లో ఉంది"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"సెట్టింగ్‌లు"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ సహాయకం"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"రిమోట్ డిస్‌ప్లే యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"విడ్జెట్ సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"విడ్జెట్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"మార్గ ప్రదాత సేవకు అనుబంధించడం"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"నమోదిత మార్గ ప్రదాతల్లో వేటికైనా అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"పరికర నిర్వాహికితో పరస్పర చర్య చేయడం"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"పరికర నిర్వాహకుడికి లక్ష్యాలను పంపడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"టీవీ ఇన్‌పుట్‌కి అనుబంధించడం"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"సమీప ఫీల్డ్ కమ్యూనికేషన్ (NFC) ట్యాగ్‌లు, కార్డులు మరియు రీడర్‌లతో కమ్యూనికేట్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"మీ స్క్రీన్ లాక్‌ను నిలిపివేయడం"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"కీలాక్ మరియు ఏదైనా అనుబంధించబడిన పాస్‌వర్డ్ భద్రతను నిలిపివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఉదాహరణకు, ఇన్‌కమింగ్ ఫోన్ కాల్ వస్తున్నప్పుడు ఫోన్ కీలాక్‌ను నిలిపివేస్తుంది, ఆపై కాల్ ముగిసిన తర్వాత కీలాక్‌ను మళ్లీ ప్రారంభిస్తుంది."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"వేలిముద్ర హార్డ్‌వేర్‌ని నిర్వహించడానికి అనుమతి"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"వినియోగం కోసం వేలిముద్ర టెంప్లేట్‌లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"వేలిముద్ర హార్డ్‌వేర్‌ని ఉపయోగించడానికి అనుమతి"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ప్రామాణీకరణ కోసం వేలిముద్ర హార్డ్‌వేర్‌ను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"సమకాలీకరణ సెట్టింగ్‌లను చదవడం"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"ఖాతా యొక్క సమకాలీకరణ సెట్టింగ్‌లను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల అనువర్తనం ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"సమకాలీకరణను ఆన్ మరియు ఆఫ్‌కు టోగుల్ చేయడం"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"నోటిఫికేషన్‌లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ఎంపిక లక్ష్యం సేవకు నిర్బంధించడం"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"ఎంపిక లక్ష్యం సేవ అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు నిర్బంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"మీడియా మార్గ సేవకు అనుబంధించడం"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"మీడియా మార్గ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"డ్రీమ్ సేవ‌కి అనుబంధించడం"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ అనువర్తనాన్ని అభ్యర్థించడం"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"పాస్‌వర్డ్ నియమాలను సెట్ చేయండి"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"స్క్రీన్-అన్‌లాక్ పాస్‌వర్డ్‌ల్లో అనుమతించబడే అక్షరాల  సంఖ్యను మరియు అక్షరాలను నియంత్రించండి."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"స్క్రీన్ లాక్ పాస్‌వర్డ్‌లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"స్క్రీన్-అన్‌లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"టైప్ చేసిన చెల్లని పాస్‌వర్డ్‌ల సంఖ్యను పర్యవేక్షిస్తుంది. స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు, అనేక సార్లు చెల్లని పాస్‌వర్డ్‌లను టైప్ చేస్తే టాబ్లెట్ లాక్ చేయబడుతుంది లేదా టాబ్లెట్‌లోని మొత్తం డేటా ఎరేజ్ చేయబడుతుంది."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు పాస్‌వర్డ్‌లను ఎన్నిసార్లు తప్పుగా టైప్ చేశారో పర్యవేక్షించండి మరియు చాలా ఎక్కువసార్లు పాస్‌వర్డ్‌లను తప్పుగా టైప్ చేసి ఉంటే టీవీని లాక్ చేయండి లేదా మొత్తం టీవీ డేటాను తీసివేయండి."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"టైప్ చేసిన చెల్లని పాస్‌వర్డ్‌ల సంఖ్యను పర్యవేక్షిస్తుంది. స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు, అనేక సార్లు చెల్లని పాస్‌వర్డ్‌లను టైప్ చేస్తే ఫోన్ లాక్ చేయబడుతుంది లేదా ఫోన్‌లోని మొత్తం డేటా ఎరేజ్ చేయబడుతుంది."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"స్క్రీన్-అన్‌లాక్ పాస్‌వర్డ్‌ను మార్చండి"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"స్క్రీన్-అన్‌లాక్ పాస్‌వర్డ్‌ను మార్చండి."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు పాస్‌వర్డ్‌ను ఎన్నిసార్లు తప్పుగా టైప్ చేశారో పర్యవేక్షిస్తుంది మరియు చాలా ఎక్కువసార్లు పాస్‌వర్డ్‌ను తప్పుగా టైప్ చేసి ఉంటే టాబ్లెట్‌ను లాక్ చేస్తుంది లేదా ఈ వినియోగదారు యొక్క మొత్తం డేటాను తీసివేస్తుంది."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు పాస్‌వర్డ్‌ను ఎన్నిసార్లు తప్పుగా టైప్ చేశారో పర్యవేక్షిస్తుంది మరియు చాలా ఎక్కువసార్లు పాస్‌వర్డ్‌ను తప్పుగా టైప్ చేసి ఉంటే టీవీని లాక్ చేస్తుంది లేదా ఈ వినియోగదారు యొక్క మొత్తం డేటాను తీసివేస్తుంది."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"స్క్రీన్‌ను అన్‌లాక్ చేస్తున్నప్పుడు పాస్‌వర్డ్‌ను ఎన్నిసార్లు తప్పుగా టైప్ చేశారో పర్యవేక్షిస్తుంది మరియు చాలా ఎక్కువసార్లు పాస్‌వర్డ్‌ను తప్పుగా టైప్ చేసి ఉంటే ఫోన్‌ను లాక్ చేస్తుంది లేదా ఈ వినియోగదారు యొక్క మొత్తం డేటాను తీసివేస్తుంది."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"స్క్రీన్ లాక్‌ని మార్చండి"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"స్క్రీన్ లాక్‌ని మారుస్తుంది."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"స్క్రీన్‌ను లాక్ చేయండి"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"స్క్రీన్‌ను ఎలా మరియు ఎప్పుడు లాక్ చేయాలనే దాన్ని నియంత్రించండి."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"మొత్తం డేటాను ఎరేజ్ చేయండి"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ఫ్యాక్టరీ డేటా రీసెట్‌ను అమలు చేయడం ద్వారా హెచ్చరించకుండానే టాబ్లెట్ డేటాను ఎరేజ్ చేయండి."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ఫ్యాక్టరీ డేటా రీసెట్‌ను అమలు చేయడం ద్వారా హెచ్చరిక లేకుండానే టీవీ డేటాను తీసివేయండి."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ఫ్యాక్టరీ డేటా రీసెట్‌ను అమలు చేయడం ద్వారా హెచ్చరించకుండానే ఫోన్ డేటాను ఎరేజ్ చేయండి."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"వినియోగదారు డేటాను తీసివేయండి"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"హెచ్చరిక లేకుండానే ఈ టాబ్లెట్‌లో ఈ వినియోగదారు డేటాను తీసివేస్తుంది."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"హెచ్చరిక లేకుండానే ఈ టీవీలో ఈ వినియోగదారు డేటాను తీసివేస్తుంది."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"హెచ్చరిక లేకుండానే ఈ ఫోన్‌లో ఈ వినియోగదారు డేటాను తీసివేస్తుంది."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"పరికరం గ్లోబల్ ప్రాక్సీని సెట్ చేయండి"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"విధానాన్ని ప్రారంభించినప్పుడు ఉపయోగించబడటానికి పరికరం గ్లోబల్ ప్రాక్సీని సెట్ చేయండి. మొదటి పరికర నిర్వాహకులు మాత్రమే ప్రభావవంతమైన గ్లోబల్ ప్రాక్సీని సెట్ చేస్తారు."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"లాక్-స్క్రీన్ పాస్‌వర్డ్ గడువు ముగింపును సెట్ చేయండి"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"లాక్-స్క్రీన్ పాస్‌వర్డ్‌ను తప్పనిసరిగా ఎంత తరచుగా మార్చాలనేదాన్ని నియంత్రించండి."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"విధానాన్ని ప్రారంభించినప్పుడు ఉపయోగించడానికి పరికర గ్లోబల్ ప్రాక్సీని సెట్ చేస్తుంది. పరికర యజమాని మాత్రమే గ్లోబల్ ప్రాక్సీని సెట్ చేయగలరు."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"స్క్రీన్ లాక్ పాస్‌వర్డ్ గడువు ముగింపుని సెట్ చేయండి"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"స్క్రీన్ లాక్ పాస్‌వర్డ్, PIN లేదా నమూనాని తప్పనిసరిగా ఎంత తరచుగా మార్చాలనే దాన్ని మారుస్తుంది."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"నిల్వ గుప్తీకరణను సెట్ చేయండి"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"నిల్వ చేయబడిన అనువర్తన డేటా గుప్తీకరించబడి ఉండటం అవసరం."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"కెమెరాలను నిలిపివేయండి"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"అన్ని పరికర కెమెరాల వినియోగాన్ని నిరోధించండి."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"కీగార్డ్‌లో లక్షణాలను నిలిపివేయండి"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"కీగార్డ్‌లో కొన్ని లక్షణాల వినియోగాన్ని నిరోధించండి."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"స్క్రీన్ లాక్ లక్షణా. నిలిపి."</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"స్క్రీన్ లాక్ యొక్క కొన్ని లక్షణాల వినియోగాన్ని నిరోధిస్తుంది."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"ఇల్లు"</item>
     <item msgid="869923650527136615">"మొబైల్"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> తాకడం ద్వారా విశ్లేషణను ప్రారంభించాలనుకుంటోంది. తాకడం ద్వారా విశ్లేషణ ఆన్ చేయబడినప్పుడు, మీరు మీ వేలి క్రింద ఉన్నవాటి యొక్క వివరణలను వినవచ్చు లేదా చూడవచ్చు లేదా ఫోన్‌తో పరస్పర చర్య చేయడానికి సంజ్ఞలు చేయవచ్చు."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 నెల క్రితం"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 నెలకు ముందు"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 సెకను క్రితం"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> సెకన్ల క్రితం"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 నిమిషం క్రితం"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల క్రితం"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 గంట క్రితం"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"గత <xliff:g id="COUNT">%d</xliff:g> రోజులు"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">గత <xliff:g id="COUNT_1">%d</xliff:g> రోజులు</item>
+      <item quantity="one">గత <xliff:g id="COUNT_0">%d</xliff:g> రోజు</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"గత నెల"</string>
     <string name="older" msgid="5211975022815554840">"పాతది"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"నిన్న"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 సెకనులో"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 నిమిషంలో"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 గంటలో"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"రేపు"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 సెక క్రితం"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> సెక క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 నిమి క్రితం"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> నిమి క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 గంట క్రితం"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> గంటల క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"నిన్న"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> రోజుల క్రితం"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 సెకనులో"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 నిమిషంలో"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 గంటలో"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> గంటల్లో"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"రేపు"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> రోజుల్లో"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>న"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>కి"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>లో"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"వారాలు"</string>
     <string name="year" msgid="4001118221013892076">"సంవత్సరం"</string>
     <string name="years" msgid="6881577717993213522">"సంవత్సరాలు"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 సెకను"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లు"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 నిమిషం"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> నిమిషాలు"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 గంట"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> గంటలు"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> సెకన్లు</item>
+      <item quantity="one">1 సెకను</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> నిమిషాలు</item>
+      <item quantity="one">1 నిమిషం</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> గంటలు</item>
+      <item quantity="one">1 గంట</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"వీడియో సమస్య"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"ఈ పరికరంలో ప్రసారం చేయడానికి ఈ వీడియో చెల్లదు."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ఈ వీడియోను ప్లే చేయడం సాధ్యపడదు."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ప్రారంభమవుతోంది…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"నిల్వను అనుకూలపరుస్తోంది."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g>లో <xliff:g id="NUMBER_0">%1$d</xliff:g> అనువర్తనాన్ని అనుకూలీకరిస్తోంది."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ని సిద్ధం చేస్తోంది."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"అనువర్తనాలను ప్రారంభిస్తోంది."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"బూట్‌ను ముగిస్తోంది."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> అమలవుతోంది"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"కొత్త అనువర్తనాన్ని ప్రారంభించవద్దు."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ని ప్రారంభించండి"</string>
     <string name="new_app_description" msgid="1932143598371537340">"పాత అనువర్తనాన్ని సేవ్ చేయకుండానే ఆపివేయండి."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"వచనం కోసం చర్యను ఎంచుకోండి"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"రింగర్ వాల్యూమ్"</string>
     <string name="volume_music" msgid="5421651157138628171">"మీడియా వాల్యూమ్"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ఏదీ వద్దు"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"రింగ్‌టోన్‌లు"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"తెలియని రింగ్‌టోన్"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"అందుబాటులో ఉన్న Wi-Fi నెట్‌వర్క్‌ను తెరవండి"</item>
-    <item quantity="other" msgid="7915895323644292768">"అందుబాటులో ఉన్న Wi-Fi నెట్‌వర్క్‌లను తెరవండి"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి</item>
+      <item quantity="one">Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">ఓపెన్ Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి</item>
+      <item quantity="one">ఓపెన్ Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi నెట్‌వర్క్‌కు సైన్ ఇన్ చేయండి"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"నెట్‌వర్క్‌కు సైన్ ఇన్ చేయండి"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" బలహీన ఇంటర్నెట్ కనెక్షన్‌ను కలిగి ఉంది."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s అనువర్తనం %2$s Wifi నెట్‌వర్క్‌కు కనెక్ట్ చేయాలనుకుంటోంది"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ఒక అనువర్తనం"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directను ప్రారంభించండి. దీని వలన Wi-Fi క్లయింట్/హాట్‌స్పాట్ ఆపివేయబడుతుంది."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directను ప్రారంభించడం సాధ్యపడలేదు."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"సరే"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"మీడియా పరికరంగా కనెక్ట్ చేయబడింది"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"కెమెరాగా కనెక్ట్ చేయబడింది"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI పరికరం వలె కనెక్ట్ చేయబడింది"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ఇన్‌స్టాలర్‌గా కనెక్ట్ చేయబడింది"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ఉపకరణానికి కనెక్ట్ చేయబడింది"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"ఇతర USB ఎంపికల కోసం తాకండి."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"దాటవేయి"</string>
     <string name="no_matches" msgid="8129421908915840737">"సరిపోలికలు లేవు"</string>
     <string name="find_on_page" msgid="1946799233822820384">"పేజీలో కనుగొనండి"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 సరిపోలిక"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>లో <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g>లో <xliff:g id="INDEX">%d</xliff:g></item>
+      <item quantity="one">1 సరిపోలిక</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"పూర్తయింది"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB నిల్వను అన్‌మౌంట్ చేస్తోంది…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD కార్డు‌ను అన్‌మౌంట్ చేస్తోంది…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"నియంత్రణలను సవరించడానికి పిన్‌ను రూపొందించండి"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PINలు సరిపోలలేదు. మళ్లీ ప్రయత్నించండి."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"పిన్‌ చాలా చిన్నదిగా ఉంది. తప్పనిసరిగా కనీసం 4 అంకెలు ఉండాలి."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 సెకనులో మళ్లీ ప్రయత్నించండి"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి</item>
+      <item quantity="one">1 సెకనులో మళ్లీ ప్రయత్నించండి</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"తర్వాత మళ్లీ ప్రయత్నించండి"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"పూర్తి స్క్రీన్ నుండి నిష్క్రమించడానికి పైనుండి కిందికి స్వైప్ చేయండి."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"పూర్తి స్క్రీన్‌లో వీక్షిస్తున్నారు"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"నిష్క్రమించడానికి, పై నుండి క్రిందికి స్వైప్ చేయండి."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"అర్థమైంది"</string>
     <string name="done_label" msgid="2093726099505892398">"పూర్తయింది"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"గంటల వృత్తాకార స్లయిడర్"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"నిమిషాల వృత్తాకార స్లయిడర్"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ఈ స్క్రీన్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు మరియు అవలోకనం బటన్‌లను ఒకేసారి నొక్కి, ఉంచండి."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"ఈ స్క్రీన్‌ని అన్‌పిన్ చేయడానికి, అవలోకనం నొక్కి, ఉంచండి."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"స్క్రీన్ పిన్ చేయబడింది. మీ సంస్థలో అన్‌పిన్ చేయడానికి అనుమతి లేదు."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"స్క్రీన్ పిన్ చేయబడింది"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"స్క్రీన్ అన్‌పిన్ చేయబడింది"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్‌ను, స్థాన సేవలను మరియు ఎక్కువ నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర అనువర్తనాలు మీరు వాటిని తెరిస్తే మినహా నవీకరించబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"మీ వృథా సమయం <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>కి ముగిసే వరకు"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"మీ వృథా సమయం ముగిసేవరకు"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ఒక నిమిషం పాటు (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> వరకు)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d నిమిషాల పాటు (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> వరకు)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ఒక గంట పాటు (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> వరకు)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d గంటల పాటు (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> వరకు)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ఒక నిమిషానికి"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d నిమిషాలకి"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ఒక గంటకు"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d గంటలకు"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d నిమిషాల పాటు (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> వరకు)</item>
+      <item quantity="one">ఒక నిమిషం పాటు (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> వరకు)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d గంటల పాటు (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> వరకు)</item>
+      <item quantity="one">ఒక గంట పాటు (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> వరకు)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d నిమిషాల పాటు</item>
+      <item quantity="one">ఒక నిమిషం పాటు</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d గంటల పాటు</item>
+      <item quantity="one">ఒక గంట పాటు</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> వరకు"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"నిరవధికంగా"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"మీరు దీన్ని ఆఫ్ చేసే వరకు"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"కుదించండి"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>కి సెట్ చేసిన తదుపరి అలారం వరకు"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"తదుపరి అలారం వరకు"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS అభ్యర్థన డయల్ అభ్యర్థనగా సవరించబడింది."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS అభ్యర్థన USSD అభ్యర్థనగా సవరించబడింది."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS అభ్యర్థన కొత్త SS అభ్యర్థనగా సవరించబడింది."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB పెరిఫెరాల్ పోర్ట్"</string>
 </resources>
diff --git a/core/res/res/values-th-rTH/donottranslate-cldr.xml b/core/res/res/values-th-rTH/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th-rTH/donottranslate-cldr.xml
+++ b/core/res/res/values-th-rTH/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
index 2f389f7..867a58e 100755
--- a/core/res/res/values-th/donottranslate-cldr.xml
+++ b/core/res/res/values-th/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-k:%M:%S</string>
     <string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3f7bee1..15e70c3 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> วินาที"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> วินาที"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;ไม่มีชื่อ&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(ไม่มีหมายเลขโทรศัพท์)"</string>
     <string name="unknownName" msgid="6867811765370350269">"ไม่ทราบ"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ข้อความเสียง"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"ซิมการ์ดของคุณถูกล็อกด้วย PUK พิมพ์รหัส PUK เพื่อปลดล็อก"</string>
     <string name="needPuk2" msgid="4526033371987193070">"พิมพ์ PUK2 เพื่อยกเลิกการปิดกั้นซิมการ์ด"</string>
     <string name="enablePin" msgid="209412020907207950">"ไม่สำเร็จ เปิดใช้การล็อกซิม/RUIM"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะถูกล็อก"</item>
-    <item quantity="other" msgid="7530597808358774740">"คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะถูกล็อก"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะล็อก</item>
+      <item quantity="one">คุณพยายามได้อีก <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะล็อก</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"หมายเลขผู้โทรเข้า"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"เปิดโหมดใช้งานบนเครื่องบิน"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"โหมดใช้งานบนเครื่องบินปิดทำงานอยู่"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"ตัวช่วยเสียง"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"เชื่อมโยงกับบริการของผู้ให้บริการเส้นทาง"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ช่วยให้เจ้าของสามารถเชื่อมโยงกับผู้ให้บริการเส้นทางที่ลงทะเบียนรายใดก็ได้ ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"เชื่อมโยงกับอินพุตทีวี"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"อนุญาตให้แอปพลิเคชันสื่อสารกับแท็ก Near Field Communication (NFC) การ์ด และโปรแกรมอ่าน"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ปิดใช้งานการล็อกหน้าจอของคุณ"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"อนุญาตให้แอปพลิเคชันปิดใช้งานการล็อกปุ่มกดและการรักษาความปลอดภัยด้วยรหัสผ่านใดๆ ที่เกี่ยวข้อง ตัวอย่างเช่น โทรศัพท์ปิดใช้งานการล็อกปุ่มกดเมื่อรับสายเรียกเข้า จากนั้นจึงเปิดใช้งานการล็อกปุ่มกดใหม่หลังจากวางสาย"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"จัดการฮาร์ดแวร์ลายนิ้วมือ"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"อนุญาตให้แอปเรียกใช้วิธีการเพื่อเพิ่มและลบเทมเพลตลายนิ้วมือสำหรับการใช้งาน"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"ใช้ฮาร์ดแวร์ลายนิ้วมือ"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"อนุญาตให้แอปใช้ฮาร์ดแวร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"อ่านการตั้งค่าการซิงค์แล้ว"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"อนุญาตให้แอปพลิเคชันอ่านการตั้งค่าการซิงค์ของบัญชี ตัวอย่างเช่น การอนุญาตนี้สามารถระบุได้ว่าแอปพลิเคชัน People ซิงค์กับบัญชีหรือไม่"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"สลับระหว่างเปิดและปิดการซิงค์"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"เชื่อมโยงกับบริการเป้าหมายของผู้เลือก"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"อนุญาตให้แอปเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการเป้าหมายของผู้เลือก ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"เชื่อมโยงกับบริการของผู้เสนอเงื่อนไข"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการของผู้เสนอเงื่อนไข ไม่จำเป็นสำหรับแอปทั่วไป"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"เชื่อมโยงกับบริการเส้นทางสื่อ"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"อนุญาตให้แอปพลิเคชันเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการเส้นทางสื่อ ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"เชื่อมโยงกับบริการที่ต้องการ"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"อนุญาตให้แอปพลิเคชันเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการที่ต้องการ ไม่จำเป็นสำหรับแอปทั่วไป"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"เรียกใช้แอปการกำหนดค่าของผู้ให้บริการ"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"เชื่อมโยงกับบริการรับส่งข้อความของผู้ให้บริการ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"อนุญาตให้แอปพลิเคชันเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการรับส่งข้อความของผู้ให้บริการ ไม่ควรใช้สำหรับแอปธรรมดาทั่วไป"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"ควบคุมความยาวและอักขระที่สามารถใช้ในรหัสผ่านของการล็อกหน้าจอและ PIN"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"ตรวจสอบจำนวนของรหัสผ่านที่พิมพ์ไม่ถูกต้องขณะปลดล็อกหน้าจอ และล็อกแท็บเล็ตหรือลบข้อมูลทั้งหมดในแท็บเล็ตถ้ามีการพิมพ์รหัสผ่านที่ไม่ถูกต้องมากเกินไป"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"ตรวจสอบจำนวนรหัสผ่านที่ไม่ถูกต้องที่คุณพิมพ์เวลาปลดล็อกหน้าจอ และล็อกทีวีหรือลบข้อมูลของทีวีทั้งหมด หากพิมพ์รหัสผ่านไม่ถูกต้องบ่อยครั้งเกินไป"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"ตรวจสอบจำนวนการพิมพ์รหัสผ่านที่ไม่ถูกต้องขณะปลดล็อกหน้าจอ และล็อกโทรศัพท์หรือลบข้อมูลทั้งหมดในโทรศัพท์ถ้ามีการพิมพ์รหัสผ่านที่ไม่ถูกต้องมากเกินไป"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"เปลี่ยนรหัสผ่านการปลดล็อกหน้าจอ"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"เปลี่ยนรหัสผ่านการปลดล็อกหน้าจอ"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"ตรวจสอบจำนวนรหัสผ่านที่พิมพ์ไม่ถูกต้องเวลาปลดล็อกหน้าจอ และล็อกแท็บเล็ตหรือลบข้อมูลทั้งหมดของผู้ใช้นี้หากพิมพ์รหัสผ่านไม่ถูกต้องบ่อยเกินไป"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"ตรวจสอบจำนวนรหัสผ่านที่พิมพ์ไม่ถูกต้องเวลาปลดล็อกหน้าจอ และล็อกทีวีหรือลบข้อมูลทั้งหมดของผู้ใช้นี้หากพิมพ์รหัสผ่านไม่ถูกต้องบ่อยเกินไป"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"ตรวจสอบจำนวนรหัสผ่านที่พิมพ์ไม่ถูกต้องเวลาปลดล็อกหน้าจอ และล็อกโทรศัพท์หรือลบข้อมูลทั้งหมดของผู้ใช้นี้หากพิมพ์รหัสผ่านไม่ถูกต้องบ่อยเกินไป"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"เปลี่ยนการล็อกหน้าจอ"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"เปลี่ยนการล็อกหน้าจอ"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"ล็อกหน้าจอ"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"ควบคุมว่าหน้าจอจะล็อกอย่างไรและเมื่อใด"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"ลบข้อมูลทั้งหมด"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"ลบข้อมูลของแท็บเล็ตโดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"ลบข้อมูลของทีวีโดยไม่ต้องมีคำเตือนโดยการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"ลบข้อมูลของโทรศัพท์โดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"ลบข้อมูลผู้ใช้"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"ลบข้อมูลของผู้ใช้นี้ในแท็บเล็ตเครื่องนี้โดยไม่มีการเตือน"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"ลบข้อมูลของผู้ใช้นี้ในทีวีเครื่องนี้โดยไม่มีการเตือน"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"ลบข้อมูลของผู้ใช้นี้ในโทรศัพท์เครื่องนี้โดยไม่มีการเตือน"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะเปิดการใช้งานนโยบาย เฉพาะผู้ดูแลอุปกรณ์คนแรกเท่านั้นที่ตั้งค่าพร็อกซีส่วนกลางที่มีผลบังคับ"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าวันหมดอายุของรหัสผ่านล็อกหน้าจอ"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"ควบคุมความถี่ในการเปลี่ยนรหัสผ่านล็อกหน้าจอ"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะที่เปิดใช้นโยบายอยู่ เฉพาะเจ้าของอุปกรณ์เท่านั้นที่สามารถตั้งค่าพร็อกซีส่วนกลาง"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"ตั้งวันหมดอายุรหัสผ่านล็อกจอ"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"เปลี่ยนความถี่ในการเปลี่ยนรหัสผ่านของการล็อกหน้าจอ, PIN หรือรูปแบบ"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"ตั้งค่าการเข้ารหัสที่เก็บข้อมูล"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ข้อมูลของแอปพลิเคชันที่จัดเก็บต้องมีการเข้ารหัส"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ปิดใช้งานกล้องถ่ายรูป"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"ป้องกันการใช้กล้องถ่ายรูปของอุปกรณ์ทั้งหมด"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"ปิดใช้งานคุณลักษณะการล็อกปุ่ม"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"ป้องกันการใช้คุณลักษณะบางส่วนในการล็อกปุ่ม"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"ปิดใช้คุณลักษณะการล็อกหน้าจอ"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"ป้องกันการใช้คุณลักษณะบางอย่างของการล็อกหน้าจอ"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"บ้าน"</item>
     <item msgid="869923650527136615">"มือถือ"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ต้องการเปิดใช้งาน \"สำรวจโดยการแตะ\" เมื่อเปิดใช้งานแล้ว คุณสามารถฟังหรือดูคำอธิบายของสิ่งที่อยู่ใต้นิ้วข​​องคุณ หรือใช้ท่าทางสัมผัสต่างๆ เพื่อโต้ตอบกับโทรศัพท์ได้"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 เดือนที่ผ่านมา"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ก่อน 1 เดือนที่แล้ว"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 วินาทีที่แล้ว"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่แล้ว"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 นาทีที่ผ่านมา"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ชั่วโมงที่ผ่านมา"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> วันที่แล้ว"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g> วันที่แล้ว</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g> วันที่แล้ว</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"เดือนที่แล้ว"</string>
     <string name="older" msgid="5211975022815554840">"เก่ากว่า"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"เมื่อวาน"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"ใน 1 วินาที"</item>
-    <item quantity="other" msgid="1241926116443974687">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"ใน 1 นาที"</item>
-    <item quantity="other" msgid="3330713936399448749">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ใน 1 ชั่วโมง"</item>
-    <item quantity="other" msgid="547290677353727389">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"พรุ่งนี้"</item>
-    <item quantity="other" msgid="5109449375100953247">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 วินาทีที่แล้ว"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> วินาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 นาทีที่ผ่านมา"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> นาทีที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ชั่วโมงที่ผ่านมา"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมงที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"เมื่อวาน"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> วันที่ผ่านมา"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"ใน 1 วินาที"</item>
-    <item quantity="other" msgid="5495880108825805108">"ใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"ใน 1 นาที"</item>
-    <item quantity="other" msgid="4216113292706568726">"ใน <xliff:g id="COUNT">%d</xliff:g> นาที"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ใน 1 ชั่วโมง"</item>
-    <item quantity="other" msgid="3705373766798013406">"ใน <xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"พรุ่งนี้"</item>
-    <item quantity="other" msgid="2973062968038355991">"ใน <xliff:g id="COUNT">%d</xliff:g> วัน"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"ใน <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"สัปดาห์"</string>
     <string name="year" msgid="4001118221013892076">"ปี"</string>
     <string name="years" msgid="6881577717993213522">" ปี"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 วินาที"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 นาที"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> นาที"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ชั่วโมง"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> ชั่วโมง"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> วินาที</item>
+      <item quantity="one">1 วินาที</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> นาที</item>
+      <item quantity="one">1 นาที</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> ชั่วโมง</item>
+      <item quantity="one">1 ชั่วโมง</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ปัญหาเกี่ยวกับวิดีโอ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"วิดีโอนี้ไม่สามารถสตรีมไปยังอุปกรณ์นี้"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"ไม่สามารถเล่นวิดีโอนี้"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android กำลังเริ่มต้น…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"กำลังเพิ่มประสิทธิภาพพื้นที่จัดเก็บข้อมูล"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"กำลังเพิ่มประสิทธิภาพแอปพลิเคชัน <xliff:g id="NUMBER_0">%1$d</xliff:g> จาก <xliff:g id="NUMBER_1">%2$d</xliff:g> รายการ"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"กำลังเตรียม <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"กำลังเริ่มต้นแอปพลิเคชัน"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"เสร็จสิ้นการบูต"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> กำลังทำงาน"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"อย่าเริ่มแอปพลิเคชันใหม่"</string>
     <string name="new_app_action" msgid="5472756926945440706">"เริ่มต้น <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"หยุดการทำงานของแอปพลิเคชันเก่าโดยไม่บันทึก"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"เลือกการทำงานกับข้อความ"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"ระดับความดังเสียงเรียกเข้า"</string>
     <string name="volume_music" msgid="5421651157138628171">"ระดับเสียงของสื่อ"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"ไม่มี"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"เสียงเรียกเข้า"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"ไม่ทราบเสียงเรียกเข้า"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"เครือข่าย WiFi ที่ใช้งานได้"</item>
-    <item quantity="other" msgid="4192424489168397386">"เครือข่าย WiFi ใช้งานได้"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"เปิดเครือข่าย WiFi ที่ใช้งานได้"</item>
-    <item quantity="other" msgid="7915895323644292768">"เปิดเครือข่าย WiFi ที่ใช้งานได้"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">มีหลายเครือข่าย Wi-Fi ที่ใช้งานได้</item>
+      <item quantity="one">มี 1 เครือข่าย Wi-Fi ที่ใช้งานได้</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">มีหลายเครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
+      <item quantity="one">มี 1 เครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"ลงชื่อเข้าใช้เครือข่าย"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"แอปพลิเคชัน %1$s ต้องการเชื่อมต่อเครือข่าย Wi-Fi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"แอปพลิเคชัน"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ไม่สามารถเริ่ม WiFi Direct ได้"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ตกลง"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"เชื่อมต่อเป็นอุปกรณ์สื่อ"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"เชื่อมต่อเป็นกล้องถ่ายรูป"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"เชื่อมต่อเป็นอุปกรณ์ MIDI แล้ว"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"เชื่อมต่อเป็นตัวติดตั้ง"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"เชื่อมต่อกับอุปกรณ์เสริม USB แล้ว"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"แตะสำหรับตัวเลือก USB อื่นๆ"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"ข้าม"</string>
     <string name="no_matches" msgid="8129421908915840737">"ไม่พบรายการที่ตรงกัน"</string>
     <string name="find_on_page" msgid="1946799233822820384">"ค้นหาบนหน้า"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 รายการที่ตรงกัน"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> จาก <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> จาก <xliff:g id="TOTAL">%d</xliff:g> รายการ</item>
+      <item quantity="one">ตรงกัน 1 รายการ</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"เสร็จสิ้น"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"กำลังยกเลิกการต่อเชื่อมที่จัดเก็บข้อมูล USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"กำลังยกเลิกการต่อเชื่อมการ์ด SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"สร้าง PIN สำหรับการแก้ไขข้อจำกัด"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN ไม่ตรงกัน โปรดลองอีกครั้ง"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN สั้นเกินไป ต้องมีอย่างน้อย 4 หลัก"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"ลองอีกใน 1 วิ"</item>
-    <item quantity="other" msgid="4730868920742952817">"ลองอีกใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">ลองอีกครั้งใน <xliff:g id="COUNT">%d</xliff:g> วินาที</item>
+      <item quantity="one">ลองอีกครั้งใน 1 วินาที</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"ลองอีกครั้งในภายหลัง"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"กำลังดูแบบเต็มหน้าจอ"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"หากต้องการออกไป ให้กวาดนิ้วลงจากด้านบน"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"รับทราบ"</string>
     <string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้พร้อมกัน"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"หากต้องการเลิกตรึงหน้าจอ แตะ \"ภาพรวม\" ค้างไว้"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"ตรึงหน้าจอแล้ว องค์กรของคุณไม่อนุญาตให้เลิกตรึง"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"เลิกตรึงหน้าจอแล้ว"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยปรับปรุงอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"จนกว่าจะสิ้นสุดช่วงเวลาที่เครื่องไม่ทำงานในเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"จนกว่าจะสิ้นสุดช่วงเวลาเครื่องไม่ทำงาน"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1 นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1 ชั่วโมง (จนถึงเวลา <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d ชั่วโมง (จนถึงเวลา <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 นาที"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d นาที"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 ชั่วโมง"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d ชั่วโมง"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">ระยะเวลา %1$d นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">ระยะเวลา 1 นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">ระยะเวลา %1$d ชั่วโมง (จนถึงเวลา <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">ระยะเวลา 1 ชั่วโมง (จนถึงเวลา <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">ระยะเวลา %d นาที</item>
+      <item quantity="one">ระยะเวลา 1 นาที</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">ระยะเวลา %d ชั่วโมง</item>
+      <item quantity="one">ระยะเวลา 1 ชั่วโมง</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"จนถึงเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"ไม่มีกำหนด"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"จนกว่าคุณจะปิดฟังก์ชันนี้"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"ยุบ"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"จนถึงการตั้งปลุกครั้งถัดไปในเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"จนถึงการตั้งปลุกครั้งถัดไป"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ DIAL"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ USSD"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"คำขอ SS ได้รับการแก้ไขให้เป็นคำขอ SS ใหม่"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"อุปกรณ์สำหรับต่อพอร์ต USB"</string>
 </resources>
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
index 4f69833..7313c71 100755
--- a/core/res/res/values-tl/donottranslate-cldr.xml
+++ b/core/res/res/values-tl/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y %B %-e</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b9f8ce7..f19e06f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> (na) seg"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> (na) seg"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Walang pamagat&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Walang numero ng telepono)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Hindi alam"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Na-PUK-lock ang iyong SIM card. I-type ang PUK code upang i-unlock ito."</string>
     <string name="needPuk2" msgid="4526033371987193070">"I-type ang PUK2 upang i-unblock ang SIM card."</string>
     <string name="enablePin" msgid="209412020907207950">"Hindi matagumpay, i-enable ang SIM/RUIM Lock."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok bago ma-lock ang SIM."</item>
-    <item quantity="other" msgid="7530597808358774740">"Mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok bago ma-lock ang SIM."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok bago ma-lock ang SIM.</item>
+      <item quantity="other">Mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> na natitirang pagsubok bago ma-lock ang SIM.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Papasok na Caller ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Mga Setting"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mag-bind sa isang serbisyo ng route provider"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nagbibigay-daan sa may-pahintulot na mag-bind sa anumang nakarehistrong route provider. Hindi dapat kailanganin kailanman ng mga normal na app."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"i-bind sa isang TV input"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Pinapayagan ang app na makipag-ugnay sa Near Field Communication (NFC) na mga tag, card, at reader."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"huwag paganahin ang iyong lock ng screen"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Pinapayagan ang app na huwag paganahin ang keylock at anumang nauugnay na seguridad sa password. Halimbawa, hindi pinapagana ng telepono ang keylock kapag nakakatanggap ng papasok na tawag sa telepono, pagkatapos ay muling pinapagana ang keylock kapag tapos na ang tawag."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"pamahalaan ang hardware ng fingerprint"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Pinapayagan ang app na mag-invoke ng mga paraan upang magdagdag at mag-delete ng mga template ng fingerprint na magagamit."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"gamitina ng hardware ng fingerprint"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Pinapayagan ang app na gumamit ng hardware ng fingerprint para sa pagpapatotoo"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"basahin ang mga setting ng sync"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Pinapayagan ang app na basahin ang mga setting ng pag-sync para sa isang account. Halimbawa, matutukoy nito kung naka-sync ang app na Mga Tao sa isang account."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"I-toggle on at off ang pag-sync"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"sumailalim sa isang serbisyo ng chooser target"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Nagbibigay-daan sa may-ari na sumailalim sa top-level interface ng isang serbisyo ng chooser target. Hindi dapat kailanman kailanganin para sa mga karaniwang app."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"i-bind sa isang serbisyo sa pagbibigay ng kundisyon"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Nagbibigay-daan sa naghahawak na i-bind ang top-level na interface ng isang serbisyo sa pagbibigay ng kundisyon. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"mag-bind sa isang serbisyo ng media route"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Nagbibigay-daan sa may-hawak na mag-bind sa top-level na interface ng isang serbisyo ng media route. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"sumailalim sa isang serbisyo ng dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Pinapayagan ang may-ari na sumailalim sa interface ng serbisyo ng dream na nasa nangungunang antas. Hindi kailanman dapat na kailanganin para sa mga normal na app."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"paganahin ang app ng configuration na ibinigay ng carrier"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"sumailalim sa isang serbisyo ng pagmemensahe ng carrier"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Binibigyang-daan ang may-ari na sumailalim sa interface sa nangungunang antas ng isang serbisyo ng pagmemensahe ng carrier. Hindi kailanman dapat kailanganin para sa mga normal na app."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolin ang haba at ang mga character na pinapayagan sa mga password at PIN sa lock ng screen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Subaybayan ang bilang ng mga hindi tamang password na na-type kapag ina-unlock ang screen, at i-lock ang tablet o burahin ang lahat ng data ng tablet kung masyadong maraming hindi tamang password ang na-type."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Subaybayan ang bilang ng mga maling password kapag ina-unlock ang screen at i-lock ang TV o burahin ang lahat ng data ng TV kung masyadong maraming maling password ang nata-type."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Subaybayan ang bilang ng mga hindi tamang password na na-type. kapag ina-unlock ang screen, at i-lock ang telepono o burahin ang lahat ng data ng telepono kung masyadong maraming hindi tamang password ang na-type."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Palitan ang password sa pag-unlock ng screen"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Palitan ang password sa pag-unlock ng screen."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Subaybayan ang bilang ng mga maling password na na-type kapag ina-unlock ang screen, at i-lock ang tablet o burahin ang lahat ng data ng user na ito kung masyadong maraming maling password ang nata-type."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Subaybayan ang bilang ng mga maling password na na-type kapag ina-unlock ang screen, at i-lock ang TV o burahin ang lahat ng data ng user na ito kung masyadong maraming maling password ang nata-type."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Subaybayan ang bilang ng mga maling password na na-type kapag ina-unlock ang screen, at i-lock ang telepono o burahin ang lahat ng data ng user na ito kung masyadong maraming maling password ang nata-type."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Palitan ang lock ng screen"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Palitan ang lock ng screen."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"I-lock ang screen"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolin kung paano at kailan magla-lock ang screen."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Burahin ang lahat ng data"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Burahin ang data ng tablet nang walang babala sa pamamagitan ng pagsasagawa ng pag-reset ng factory data."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Burahin ang data ng TV nang walang babala sa pamamagitan ng pagsasagawa ng pag-reset ng factory data."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Burahin ang data ng telepono nang walang babala sa pamamagitan ng pagsasagawa ng pag-reset ng factory data."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Burahin ang data ng user"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Burahin ang data ng user na ito sa tablet na ito nang walang babala."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Burahin ang data ng user na ito sa TV na ito nang walang babala."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Burahin ang data ng user na ito sa teleponong ito nang walang babala."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Itakda ang pandaigdigang proxy ng device"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Itakda ang pandaigdigang proxy ng device na gagamitin habang pinagana ang patakaran. Tanging ang unang admin ng device ang magtatakda sa may bisang pandaigdigang proxy."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda expire password pag-lock scr"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kontrolin kung gaano kadalas dapat palitan ang password sa pag-lock ng screen."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Itakda ang pandaigdigang proxy ng device na gagamitin habang naka-enable ang patakaran. Ang may-ari ng device lang ang makakapagtakda sa pandaigdigang proxy."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Itakda screen lock password expiration"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Baguhin kung gaano kadalas dapat palitan ang password, PIN o pattern sa lock ng screen."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Itakda pag-encrypt ng imbakan"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Hilinging naka-encrypt ang nakaimbak na data ng app."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Huwag paganahin mga camera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Pigilan ang paggamit sa lahat ng camera ng device."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Wag paganahin tampok keyguard"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Pigilan ang paggamit ng ilang tampok sa keyguard."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"I-disable screen lock feature"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Pigilan ang paggamit ng ilang feature ng lock ng screen."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -937,7 +953,7 @@
     <string name="relationTypeManager" msgid="6365677861610137895">"Manager"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"Ina"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Magulang"</string>
-    <string name="relationTypePartner" msgid="7266490285120262781">"Kasosyo"</string>
+    <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
     <string name="relationTypeReferredBy" msgid="101573059844135524">"Ni-refer ni"</string>
     <string name="relationTypeRelative" msgid="1799819930085610271">"Kamag-anak"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Kapatid na Babae"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"Nais paganahin ng <xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ang Galugarin sa pamamagitan ng pagpindot. Kapag naka-on ang Galugarin sa pamamagitan ng pagpindot, maaari mong marinig o makita ang mga paglalarawan ng nasa ilalim ng iyong daliri o maaari kang magsagawa ng mga galaw upang makipag-ugnayan sa telepono."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 buwan ang nakalipas"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Bago ang nakalipas na 1 buwan"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 segundo ang nakakalipas"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 minuto ang nakalipas"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 oras ang nakalipas"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Huling <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Huling <xliff:g id="COUNT_1">%d</xliff:g> araw</item>
+      <item quantity="other">Huling <xliff:g id="COUNT_1">%d</xliff:g> na araw</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Nakaraang buwan"</string>
     <string name="older" msgid="5211975022815554840">"Mas luma"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kahapon"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"sa 1 segundo"</item>
-    <item quantity="other" msgid="1241926116443974687">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"sa 1 minuto"</item>
-    <item quantity="other" msgid="3330713936399448749">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"sa 1 oras"</item>
-    <item quantity="other" msgid="547290677353727389">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"bukas"</item>
-    <item quantity="other" msgid="5109449375100953247">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 segundo ang nakalipas"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 minuto ang nakalipas"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 oras ang nakalipas"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> (na) oras ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kahapon"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> (na) araw ang nakalipas"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"sa 1 seg"</item>
-    <item quantity="other" msgid="5495880108825805108">"sa <xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"sa 1 min"</item>
-    <item quantity="other" msgid="4216113292706568726">"sa <xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"sa 1 oras"</item>
-    <item quantity="other" msgid="3705373766798013406">"sa <xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"bukas"</item>
-    <item quantity="other" msgid="2973062968038355991">"sa <xliff:g id="COUNT">%d</xliff:g> (na) araw"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"sa <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"nang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"sa <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"mga linggo"</string>
     <string name="year" msgid="4001118221013892076">"taon"</string>
     <string name="years" msgid="6881577717993213522">"mga taon"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 segundo"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> (na) segundo"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 minuto"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> (na) minuto"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 oras"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> (na) oras"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> segundo</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> na segundo</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minuto</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> na minuto</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> oras</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> na oras</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problema sa video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Hindi wasto ang video na ito para sa streaming sa device na ito."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Hindi ma-play ang video na ito."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Nagsisimula ang Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ino-optimize ang storage."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ino-optimize ang app <xliff:g id="NUMBER_0">%1$d</xliff:g> ng <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ihinahanda ang <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Sinisimulan ang apps."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Pagtatapos ng pag-boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Huwag simulan ang bagong app."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Simulan ang <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Ihinto ang lumang app nang hindi nagse-save."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Pumili ng pagkilos para sa teksto"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Lakas ng tunog ng ringer"</string>
     <string name="volume_music" msgid="5421651157138628171">"Lakas ng tunog ng media"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Wala"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Mga Ringtone"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Hindi kilalang ringtone"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Available ang Wi-Fi network"</item>
-    <item quantity="other" msgid="4192424489168397386">"Available ang mga Wi-Fi network"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Available ang bukas na Wi-Fi network"</item>
-    <item quantity="other" msgid="7915895323644292768">"Buksan ang mga available na Wi-Fi network"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Available ang mga Wi-Fi network</item>
+      <item quantity="other">Available ang mga Wi-Fi network</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Available ang mga bukas na Wi-Fi network</item>
+      <item quantity="other">Available ang mga bukas na Wi-Fi network</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Mag-sign in sa network ng Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Mag-sign in sa network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Gustong kumonekta ng application na %1$s sa Wifi Network na %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Isang application"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Hindi masimulan ang Wi-Fi Direct"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Nakakonekta bilang isang media device"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Nakakonekta bilang isang camera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Nakakonekta bilang isang MIDI device"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Nakakonekta bilang isang installer"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Nakakonekta sa isang accessory ng USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Pindutin para sa iba pang mga pagpipilian sa USB."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Laktawan"</string>
     <string name="no_matches" msgid="8129421908915840737">"Walang mga tugma"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Maghanap sa pahina"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 tugma"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ng <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> ng <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> ng <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Tapos na"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Ina-unmount ang USB storage..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Ina-unmount ang SD card..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Gumawa ng PIN para sa pagbago sa mga paghihigpit"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Hindi nagtutugma ang mga PIN. Subukang muli."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Masyadong maikli ang PIN. Hindi dapat mas maikli sa 4 na digit."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Subukan muli sa 1 seg"</item>
-    <item quantity="other" msgid="4730868920742952817">"Subukan muli sa <xliff:g id="COUNT">%d</xliff:g> seg"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Subukang muli sa loob ng <xliff:g id="COUNT">%d</xliff:g> segundo</item>
+      <item quantity="other">Subukang muli sa loob ng <xliff:g id="COUNT">%d</xliff:g> na segundo</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Subukang muli sa ibang pagkakataon"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Mag-swipe pababa mula sa itaas upang lumabas sa full screen."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Panonood sa full screen"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Upang lumabas, mag-swipe mula sa itaas pababa."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Nakuha ko"</string>
     <string name="done_label" msgid="2093726099505892398">"Tapos na"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Pabilog na slider ng mga oras"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Pabilog na slider ng mga minuto"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik at Overview nang sabay-sabay."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Overview."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Naka-pin ang screen. Hindi pinapayagan ng iyong organisasyon ang pag-a-unpin."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Naka-unpin ang screen"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang pagganap ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hanggang sa matapos ang iyong downtime nang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hanggang magtapos ang iyong downtime"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Sa loob ng isang minuto (hanggang <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Sa loob ng %1$d (na) minuto (hanggang <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Sa loob ng isang oras (hanggang <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Sa loob ng %1$d (na) oras (hanggang <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Sa loob ng isang oras"</item>
-    <item quantity="other" msgid="5408537517529822157">"Sa loob ng %d (na) oras"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Sa loob ng %1$d minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Sa loob ng %1$d na minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Sa loob ng %1$d oras (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Sa loob ng %1$d na oras (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Sa loob ng %d minuto</item>
+      <item quantity="other">Sa loob ng %d na minuto</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Sa loob ng %d oras</item>
+      <item quantity="other">Sa loob ng %d na oras</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Walang tiyak na katapusan"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"I-collapse"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Hanggang sa susunod na alarma sa <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Hanggang sa susunod na alarma"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Ginawang DIAL request ang SS request."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Ginawang USSD request ang SS request."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Ginawang bagong SS request ang SS request."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Peripheral Port"</string>
 </resources>
diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml
index 8bdcf48..0577fab 100755
--- a/core/res/res/values-tr/donottranslate-cldr.xml
+++ b/core/res/res/values-tr/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s %s %s"</string>
     <string name="month_day_year">%d %B %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d %b %Y %H:%M:%S</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 704a73d..1b5bd6c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sn."</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sn."</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Adsız&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon numarası yok)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Bilinmiyor"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Sesli Mesaj"</string>
@@ -57,16 +55,16 @@
     <string name="mmiComplete" msgid="8232527495411698359">"MMI tamamlandı."</string>
     <string name="badPin" msgid="9015277645546710014">"Yazdığınız eski PIN doğru değil."</string>
     <string name="badPuk" msgid="5487257647081132201">"Yazdığınız PUK doğru değil."</string>
-    <string name="mismatchPin" msgid="609379054496863419">"Girdiğiniz PIN kodları eşleşmiyor"</string>
+    <string name="mismatchPin" msgid="609379054496863419">"Girdiğiniz PIN\'ler eşleşmiyor"</string>
     <string name="invalidPin" msgid="3850018445187475377">"4 ila 8 rakamdan oluşan bir PIN girin."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"8 veya daha uzun basamaklı bir PUK kodu yazın."</string>
     <string name="needPuk" msgid="919668385956251611">"SIM kartınızın PUK kilidi devrede. Kilidi açmak için PUK kodunu yazın."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Engellenen SIM kartı açmak için PUK2 kodunu yazın."</string>
     <string name="enablePin" msgid="209412020907207950">"Başarısız. SIM/RUIM Kilidini etkinleştirin."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"SIM kilitlenmeden önce <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-    <item quantity="other" msgid="7530597808358774740">"SIM kilitlenmeden önce <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">SIM kilitlenmeden önce <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
+      <item quantity="one">SIM kilitlenmeden önce <xliff:g id="NUMBER_0">%d</xliff:g> deneme hakkınız kaldı.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Gelen Çağrı Kimliği"</string>
@@ -194,7 +192,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere mevcut cihazınızın durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Sessiz mod"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ses KAPALI"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ses AÇIK"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Sesli Yardım"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
@@ -210,8 +209,8 @@
     <string name="managed_profile_label" msgid="6260850669674791528">"İş"</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>
-    <string name="permgroupdesc_messages" msgid="7821999071003699236">"SMS mesajlarınızı, e-posta iletilerinizi ve diğer mesajlarınızı okuyup yazma."</string>
+    <string name="permgrouplab_messages" msgid="7521249148445456662">"İletileriniz"</string>
+    <string name="permgroupdesc_messages" msgid="7821999071003699236">"SMS, e-posta ve diğer iletilerinizi okuyup yazma."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Kişisel bilgileriniz"</string>
     <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"Sizinle ilgili, kişi kartınızda kayıtlı bilgilere doğrudan erişim."</string>
     <string name="permgrouplab_socialInfo" msgid="5799096623412043791">"Sosyal bilgileriniz"</string>
@@ -271,13 +270,13 @@
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"SD karta erişin."</string>
     <string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Erişilebilirlik özellikleri"</string>
     <string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Engelli kullanıcılara yardımcı olan teknolojinin istekte bulunabileceği özellikler."</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pencere içeriğini alın"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Etkileşim kurduğunuz pencerenin içeriğini inceleyin."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Dokunarak Keşfet\'i açın"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Pencere içeriğini alma"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Etkileşim kurduğunuz pencerenin içeriğini inceler."</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Dokunarak Keşfet\'i açma"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Dokunulan öğeler sesli olarak okunur ve ekranı keşfetmek için hareketler kullanılabilir."</string>
-    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Gelişmiş web erişilebilirliğini açın"</string>
+    <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Gelişmiş web erişilebilirliğini açma"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Uygulamanın erişilebilirliğini artırmak için komut dosyaları yüklenebilir."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Yazdığınız metni izleyin"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Yazdığınız metni izleme"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredi kartı ve şifre gibi kişisel bilgiler içerir."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
@@ -289,28 +288,28 @@
     <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Uygulamaya, kullanıcı müdahalesi olmadan kısayolları Ana Ekrana ekleme izni verir."</string>
     <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"kısayolların yüklemesini kaldırma"</string>
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Uygulamaya, kullanıcının müdahalesi olmadan kısayolları Ana Ekrandan kaldırma izni verir."</string>
-    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"giden çağrıları yeniden yönlendir"</string>
+    <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"giden çağrıları yeniden yönlendirme"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Uygulamaya, giden bir çağrının numarası çevrilirken çağrıyı farklı bir numaraya yönlendirme ya da tamamen kapatma seçeneğiyle birlikte numarayı görme izni verir."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"kısa mesajları al (SMS)"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Uygulamaya SMS mesajlarını alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen mesajları takip edip size göstermeden silebileceği anlamına gelir."</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Uygulamaya SMS iletilerini alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri takip edip size göstermeden silebileceği anlamına gelir."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"kısa mesajları (MMS) al"</string>
-    <string name="permdesc_receiveMms" msgid="533019437263212260">"Uygulamaya MMS mesajlarını alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen mesajları takip edip size göstermeden silebileceği anlamına gelir."</string>
+    <string name="permdesc_receiveMms" msgid="533019437263212260">"Uygulamaya MMS iletilerini alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen iletileri takip edip size göstermeden silebileceği anlamına gelir."</string>
     <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"acil durum yayınlarını al"</string>
     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Uygulamaya, acil yayın mesajları alma ve işleme izni verir. Bu izin, sadece sistem uygulamaları için kullanılabilir."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"hücre yayını mesajlarını oku"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Uygulamaya, cihazınız tarafından alınan hücre yayını mesajlarını okuma izni verir. Hücre yayını uyarıları bazı yerlerde acil durumlar konusunda sizi uyarmak için gönderilir. Kötü amaçlı uygulamalar acil hücre yayını alındığında cihazınızın performansına ya da çalışmasına engel olabilir."</string>
-    <string name="permlab_sendSms" msgid="5600830612147671529">"SMS mesajları gönder"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"Uygulamaya SMS mesajları gönderme izni verir. Bu durum beklenmeyen ödemelere neden olabilir. Kötü amaçlı uygulamalar onayınız olmadan mesajlar göndererek sizi zarara uğratabilir."</string>
+    <string name="permlab_sendSms" msgid="5600830612147671529">"SMS iletileri gönder"</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Uygulamaya SMS iletisi gönderme izni verir. Bu durum beklenmeyen ödemelere neden olabilir. Kötü amaçlı uygulamalar onayınız olmadan iletiler göndererek sizi zarara uğratabilir."</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"mesajla yanıtla etkinlikleri gönder"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"Uygulamaya, gelen çağrıları mesajla yanıtlama etkinliklerini işlemek üzere diğer mesajlaşma uygulamalarına istek gönderme izni verir."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"kısa mesajlarımı (SMS veya MMS) oku"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Uygulamaya tabletinizde veya SIM kartta saklanan SMS mesajlarını okuma izni verir. Bu izin, uygulamanın tüm SMS mesajlarını içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Uygulamaya, TV\'nizde veya SIM kartta depolanmış SMS mesajlarını okuma izni verir. Bu izin, uygulamanın içeriğe veya gizliliğe bakılmaksızın tüm SMS mesajlarını okumasına olanak sağlar."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Uygulamaya telefonunuzda veya SIM kartta saklanan SMS mesajlarını okuma izni verir. Bu izin, uygulamanın tüm SMS mesajlarını içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Uygulamaya tabletinizde veya SIM kartta saklanan SMS iletilerini okuma izni verir. Bu izin, uygulamanın tüm SMS iletilerini içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Uygulamaya, TV\'nizde veya SIM kartta depolanmış SMS iletilerini okuma izni verir. Bu izin, uygulamanın içeriğe veya gizliliğe bakılmaksızın tüm SMS iletilerini okumasına olanak sağlar."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Uygulamaya telefonunuzda veya SIM kartta saklanan SMS iletilerini okuma izni verir. Bu izin, uygulamanın tüm SMS iletilerini içeriğinden veya gizliliğinden bağımsız olarak okumasına olanak sağlar."</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"kısa mesajlarımı (SMS veya MMS) düzenle"</string>
-    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Uygulamaya, tabletinizde veya SIM kartınızda depolanan SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
-    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"Uygulamaya, TV\'niz ya da SIM kartınızda saklanan SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
-    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Uygulamaya, telefonunuzdaki veya SIM kartınızdaki SMS mesajlarına yazma izni verir. Kötü amaçlı uygulamalar mesajlarınızı silebilir."</string>
+    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Uygulamaya, tabletinizde veya SIM kartınızda depolanan SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
+    <string name="permdesc_writeSms" product="tv" msgid="955871498983538187">"Uygulamaya, TV\'niz ya da SIM kartınızda saklanan SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Uygulamaya, telefonunuzdaki veya SIM kartınızdaki SMS iletilerine yazma izni verir. Kötü amaçlı uygulamalar iletilerinizi silebilir."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"kısa mesajları (WAP) al"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Uygulamaya WAP mesajlarını alma ve işleme izni verir. Buna, size gönderilen mesajları takip edip size göstermeden silebilme izni de dahildir."</string>
     <string name="permlab_receiveBluetoothMap" msgid="7593811487142360528">"Bluetooth iletilerini al (MAP)"</string>
@@ -372,7 +371,7 @@
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"paket ile kaldırılan yayını gönder"</string>
     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Uygulamaya, bir uygulama paketinin kaldırıldığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar çalışan diğer uygulamaları kapatmak için bunu kullanabilir."</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"SMS ile alınan yayın gönder"</string>
-    <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS mesajları göndermek için bunu kullanabilir."</string>
+    <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS iletisi alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS iletileri göndermek için bunu kullanabilir."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Uygulamaya, WAP PUSH mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte MMS bildirimleri oluşturmak veya bir web sayfasının içeriğini sessiz şekilde zararlı öğelerle değiştirmek için bunu kullanabilir."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"rota sağlayıcı hizmetine bağlanma"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"İzin verilen uygulamaya tüm kayıtlı rota sağlayıcılarına bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV girişine bağlanma"</string>
@@ -526,15 +527,15 @@
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"sosyal akışınızı okuma"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Uygulamaya size veya arkadaşlarınıza ait sosyal güncellemelere erişme ve bunları senkronize etme izni verir. Bilgi paylaşırken dikkatli olun. Bu izin, uygulamanın sosyal ağlarda sizinle arkadaşlarınız arasındaki iletişimi, gizliliğine bakılmaksızın okumasına olanak sağlar. Not: Bu izin tüm sosyal ağlar için geçerli olmayabilir."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"sosyal akışınıza yazma"</string>
-    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Uygulamaya arkadaşlarınızın sosyal güncellemelerini gösterme izni verir. Bilgi paylaşırken dikkatli olun -- Bu uygulama bir arkadaşınızdan geliyormuş gibi görünen mesajlar oluşturabilir. Not: Bu izin, tüm sosyal ağlarda geçerli olmayabilir."</string>
+    <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"Uygulamaya arkadaşlarınızın sosyal güncellemelerini gösterme izni verir. Bilgi paylaşırken dikkatli olun -- Bu uygulama bir arkadaşınızdan geliyormuş gibi görünen iletiler oluşturabilir. Not: Bu izin, tüm sosyal ağlarda geçerli olmayabilir."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"takvim etkinliklerini ve gizli bilgileri oku"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri de olmak üzere tabletinizde depolanan tüm takvim etkinliklerini okuma izni verir. Bu izin, uygulamanın takvim verilerinizi gizliliğine ve hassaslığına bakmaksızın paylaşmasına ve kaydetmesine olanak sağlayabilir."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri dahil olmak üzere TV\'nizde kayıtlı tüm takvim etkinliklerini okuma izni verir. Bu da uygulamanın gizlilik ve duyarlılık dikkate alınmaksızın takvim verilerinizi paylaşmasına veya kaydetmesine olanak sağlayabilir."</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Uygulamaya, arkadaşlarınızın ve iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda depolanan tüm takvim etkinliklerini okuma izni verir. Bu izin, uygulamanın takvim verilerinizi gizliliğine ve hassaslığına bakmaksızın paylaşmasına ve kaydetmesine olanak sağlayabilir."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"sahibin bilgisi olmadan takvim etkinlikleri ekle veya mevcut etkinlikleri değiştir ve misafirlere e-posta gönder"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere tabletinizde değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen mesajlar göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere tabletinizde değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen iletiler göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere cihazınızda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın, takvim sahiplerinden gelmiş gibi görünen iletiler göndermesine veya takvim sahiplerinin bilgisi olmadan etkinlikleri değiştirmesine olanak sağlayabilir."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen mesajlar göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Uygulamaya, arkadaşlarınızın veya iş arkadaşlarınızın etkinlikleri de dahil olmak üzere telefonunuzda değiştirebileceğiniz etkinlikleri ekleme, kaldırma ve değiştirme izni verir. Bu izin, uygulamanın takvim sahiplerinden geliyormuş gibi görünen iletiler göndermesine veya etkinlikleri sahibinden habersiz olarak değiştirmesine olanak sağlar."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"test için sahte konum kaynakları"</string>
     <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Test amacıyla veya yeni bir konum sağlayıcı yüklemek için sahte konum kaynakları oluşturma. Bu izin, uygulamanın GPS veya konum sağlayıcıları gibi diğer konum kaynakları tarafından döndürülen konum ve/veya durum bilgisini geçersiz kılmasına olanak sağlar."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ek konum sağlayıcı komutlarına eriş"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Uygulamaya, Near Field Communication (NFC) etiketleri, kartlar ve okuyucular ile iletişim kurma izni verir."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ekran kilidimi devre dışı bırak"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Uygulamaya, tuş kilidini ve ilişkili tüm şifreli güvenlik önlemlerini devre dışı bırakma izni verir. Örneğin, telefon, çağrı alındığında tuş kilidinin devre dışı bırakır ve sonra, görüşme bittiğinde kilidi yeniden etkinleştirir."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"parmak izi donanımını yönetme"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Uygulamanın, kullanılacak parmak izi şablonlarını ekleme ve silme yöntemlerini başlatmasına izin verir."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"parmak izi donanımını kullanma"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Uygulamanın kimlik doğrulama için parmak izi donanımını kullanmasına izin verir."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"senk. ayarlarını okuma"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Uygulamaya bir hesaba ait senkronizasyon ayarlarını okuma izni verir. Örneğin, bu izne sahip bir uygulama Kişiler uygulamasının bir hesapla senkronize olup olmadığını belirleyebilir."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"senkronizasyonu açma/kapatma"</string>
@@ -747,9 +752,9 @@
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Uygulamaya, o anda senkronize olan özet akışları ile ilgili bilgi alma izni verir."</string>
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abone olunan yayınları yazma"</string>
     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Uygulamaya, o anda senkronize edilmiş özet akışlarını değiştirme izni verir. Kötü amaçlı uygulamalar senkronize edilmiş özet akışlarını değiştirebilir."</string>
-    <string name="permlab_readDictionary" msgid="4107101525746035718">"sözlüğe eklediğim terimleri oku"</string>
+    <string name="permlab_readDictionary" msgid="4107101525746035718">"sözlüğe eklediğiniz terimleri okuma"</string>
     <string name="permdesc_readDictionary" msgid="659614600338904243">"Uygulamaya, kullanıcının kullanıcı sözlüğünde depolamış olabileceği kelimeleri, adları ve kelime öbeklerini okuma izni verir."</string>
-    <string name="permlab_writeDictionary" msgid="2183110402314441106">"kullanıcı tanımlı sözlüğe kelime ekle"</string>
+    <string name="permlab_writeDictionary" msgid="2183110402314441106">"kullanıcı tanımlı sözlüğe kelime ekleme"</string>
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Uygulamaya, kullanıcı sözlüğüne yeni kelimeler yazma izni verir."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB belleğini okuma"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"SD kartımın içeriğini oku"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"seçici hedef hizmetine bağlanma"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"İzin sahibine bir seçici hedef hizmetinin üst seviye arayüzüne bağlanma olanağı sunar. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bir durum sağlayıcı hizmetine bağlanma"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"İzin sahibinin, bir durum sağlayıcı hizmete 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_bindMediaRouteService" msgid="6637740382272686835">"bir medya yönlendirme hizmetine bağlan"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"İzin sahibinin, bir medya yönlendirme 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_bindDreamService" msgid="4153646965978563462">"bir dream hizmetine bağla"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"İzin sahibine bir dream hizmetinin üst seviye arayüzüne bağlanma olanağı sunar. Normal uygulamalarda hiçbir zaman ihtiyaç duyulmamalıdır."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"operatör mesajlaşma hizmetine bağlan"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"İzin sahibinin, operatör mesajlaşma hizmetinin üst düzey arayüzüne bağlanmasına olanak verir. Normal uygulamalarda hiçbir zaman gerekmez."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran kilidini açma şifrelerinde ve PIN\'lerde izin verilen uzunluğu ve karakterleri denetleyin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Ekran kilidini açarken yapılan yanlış şifre girme denemelerini izle ve çok fazla sayıda yanlış şifre girme denemesi yapılmışsa tableti kilitle veya tabletteki tüm verileri sil."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Ekran kilidi açılırken girilen hatalı şifre sayısını takip etme ve çok fazla sayıda hatalı şifre girildiğinde TV\'yi kilitleme veya TV\'nin tüm verilerini silme."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Ekran kilidini açarken yapılan yanlış şifre girişi denemelerini izle ve çok sayıda yanlış şifre girişi denemesi yapılmışsa telefonu kilitle veya telefonun tüm verilerini sil."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekran kilidini açma şifresini değiştir"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekran kilidini açma şifresini değiştirme."</string>
-    <string name="policylab_forceLock" msgid="2274085384704248431">"Ekranı kilitle"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Ekran kilidi açılırken girilen hatalı şifre sayısını takip edin ve çok fazla sayıda hatalı şifre girildiğinde tableti kilitleyin veya söz konusu kullanıcının tüm verilerini silin."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Ekran kilidi açılırken girilen hatalı şifre sayısını takip edin ve çok fazla sayıda hatalı şifre girildiğinde TV\'yi kilitleyin veya söz konusu kullanıcının tüm verilerini silin."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Ekran kilidi açılırken girilen hatalı şifre sayısını takip edin ve çok fazla sayıda hatalı şifre girildiğinde telefonu kilitleyin veya söz konusu kullanıcının tüm verilerini silin."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Ekran kilidini değiştir"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Ekran kilidini değiştirin."</string>
+    <string name="policylab_forceLock" msgid="2274085384704248431">"Ekranı kilitleme"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Ekranın nasıl ve ne zaman kilitlendiğini denetleme."</string>
-    <string name="policylab_wipeData" msgid="3910545446758639713">"Tüm verileri sil"</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Tüm verileri silme"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek tabletteki verileri uyarıda bulunmadan silme."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Fabrika ayarlarına sıfırlama yoluyla TV\'nin verilerini uyarı vermeksizin silme."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silme."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Kullanıcı verilerini sil"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Uyarı yapmadan bu kullanıcının bu tabletteki verilerini silin."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Uyarı yapmadan bu kullanıcının bu TV\'deki verilerini silin."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Uyarı yapmadan bu kullanıcının bu telefondaki verilerini silin."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Cihaz genelinde geçerli proxy\'i ayarla"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekr kilt şifr süre sonu ayarla"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Ekran kilitleme şifresinin hangi sıklıkla değiştirilmesi gerektiğini denetleme."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Genel proxy\'yi yalnızca cihaz sahibi ayarlayabilir."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Ekran kilidi şifresinin kullanma süresini ayarla"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Ekran kilitleme şifresinin, PIN\'in veya desenin hangi sıklıkla değiştirileceğini ayarlayın."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Deplm şifrelemesini ayarla"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Depolanan uygulama verilerinin şifrelenmiş olmasını zorunlu kılma."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameraları devre dışı bırak"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Tüm cihaz kameralarının kullanımını engelleme."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Keyguard\'daki özellikleri devre dışı bırak"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Keyguard\'daki bazı özelliklerin kullanılmasını önle."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Ekran kilidinin özelliklerini devre dışı bırak"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Ekran kilidinin bazı özelliklerinin kullanılmasını önleyin."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Ev"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -893,8 +909,8 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Telsiz"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"İş Yeri Cep Telefonu"</string>
-    <string name="phoneTypeWorkPager" msgid="649938731231157056">"İş Yeri Çağrı Cihazı"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"İş Cep Telefonu"</string>
+    <string name="phoneTypeWorkPager" msgid="649938731231157056">"İş Çağrı Cihazı"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Yardımcı"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
     <string name="eventTypeCustom" msgid="7837586198458073404">"Özel"</string>
@@ -1001,7 +1017,7 @@
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Tablet kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Tablet şimdi fabrika varsayılanına sıfırlanacak."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"TV\'nizin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmaya çalıştınız. TV\'niz şimdi fabrika ayarlarına sıfırlanacaktır."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Telefon kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Telefon şimdi fabrika varsayılanına sıfırlanacak."</string>
-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Deseni unuttunuz mu?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Hesap kilidini açma"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Çok fazla sayıda desen denemesi yapıldı"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>, Dokunarak Keşfet özelliğini etkinleştirmek istiyor. Dokunarak Keşfet açık olduğunda parmağınızın altındaki öğelere ait açıklamaları duyabilir veya görebilir ya da telefonla etkileşimde bulunmak için birtakım hareketler yapabilirsiniz."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 ay önce"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 ay önce"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 saniye önce"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 dakika önce"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 saat önce"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Son <xliff:g id="COUNT">%d</xliff:g> gün"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">Son <xliff:g id="COUNT_1">%d</xliff:g> gün</item>
+      <item quantity="one">Son <xliff:g id="COUNT_0">%d</xliff:g> gün</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Son ay"</string>
     <string name="older" msgid="5211975022815554840">"Daha eski"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"dün"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 saniye içinde"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 dakika içinde"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 saat içinde"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"yarın"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 saniye önce"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> saniye önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 dak. önce"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> dakika önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 saat önce"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> saat önce"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"dün"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> gün önce"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 san. içinde"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 dak. içinde"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> dakika içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 saat içinde"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> saat içinde"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"yarın"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> gün içinde"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> tarihinde"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> yılında"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"hafta"</string>
     <string name="year" msgid="4001118221013892076">"yıl"</string>
     <string name="years" msgid="6881577717993213522">"yıl"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 saniye"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> saniye"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 dakika"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> dakika"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 saat"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> saat"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> saniye</item>
+      <item quantity="one">1 saniye</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> dakika</item>
+      <item quantity="one">1 dakika</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> saat</item>
+      <item quantity="one">1 saat</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video sorunu"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Bu video bu cihazda akış için uygun değil."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Bu video oynatılamıyor."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android başlatılıyor…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Depolama optimize ediliyor."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> uygulama optimize ediliyor."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> hazırlanıyor."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Uygulamalar başlatılıyor"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Açılış tamamlanıyor."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Yeni uygulamayı başlatmayın."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> uygulamasını başlat"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Kaydetmeden eski uygulamayı durdurun."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Kısa mesaj için bir işlem seçin"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Zil sesi düzeyi"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medya ses düzeyi"</string>
@@ -1331,24 +1293,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Yok"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Zil sesleri"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Bilinmeyen zil sesi"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Kablosuz ağ var"</item>
-    <item quantity="other" msgid="4192424489168397386">"Kablosuz ağlar var"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Kullanılabilir kablosuz ağı aç"</item>
-    <item quantity="other" msgid="7915895323644292768">"Kullanılabilir kablosuz ağları aç"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Kablosuz ağlar var</item>
+      <item quantity="one">Kablosuz ağ var</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Kullanılabilir Kablosuz ağları aç</item>
+      <item quantity="one">Kullanılabilir Kablosuz ağı aç</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Kablosuz ağda oturum açın"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Ağda oturum açın"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s uygulaması %2$s Kablosuz Ağına bağlanmak istiyor"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Bir uygulama"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantıyı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan bağlantı başlatılamadı."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantı\'yı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan Bağlantı başlatılamadı."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan Bağlantı özelliği açık"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string>
     <string name="accept" msgid="1645267259272829559">"Kabul et"</string>
     <string name="decline" msgid="2112225451706137894">"Reddet"</string>
@@ -1362,11 +1327,11 @@
     <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile bağlantıya sahipken TV\'nizin Kablosuz bağlantısı geçici olarak kesilecek."</string>
     <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
-    <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
-    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS mesajı gönderiyor. Bu uygulamanın mesaj göndermeye devam etmesine izin veriyor musunuz?"</string>
+    <string name="sms_control_title" msgid="7296612781128917719">"SMS iletileri gönderiliyor"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS iletisi gönderiyor. Bu uygulamanın ileti göndermeye devam etmesine izin veriyor musunuz?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"İzin ver"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Reddet"</string>
-    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;, &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; adresine bir mesaj göndermek istiyor."</string>
+    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;, &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; adresine bir ileti göndermek istiyor."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Bu işlem, mobil hesabınızdan "<b>"ödeme alınmasına neden olabilir"</b>"."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bu işlem, mobil hesabınızdan ödeme alınmasına neden olacak."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Gönder"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Medya cihazı olarak bağlandı"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kamera olarak bağlandı"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI cihazı olarak bağlandı"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Yükleyici olarak bağlandı"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB aksesuarına bağlandı"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Diğer USB seçenekleri için dokunun."</string>
@@ -1519,17 +1485,17 @@
     <string name="submit" msgid="1602335572089911941">"Gönder"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Araba modu etkin"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Araba modundan çıkmak için dokunun."</string>
-    <string name="tethered_notification_title" msgid="3146694234398202601">"Doğrudan bağlantı veya ortak erişim noktası etkin"</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering veya hotspot etkin"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"Kurulum için dokunun."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Geri"</string>
     <string name="next_button_label" msgid="1080555104677992408">"İleri"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Atla"</string>
     <string name="no_matches" msgid="8129421908915840737">"Eşleşme yok"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Sayfada bul"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 eşleşme"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> / <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 eşleşme</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Bitti"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB belleğin bağlantısı kesiliyor…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD kartın bağlantısı kesiliyor…"</string>
@@ -1670,7 +1636,7 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Yanlış Desen"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Yanlış Şifre"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Yanlış PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%1$d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Deseninizi çizin"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN\'i girin"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Kısıtlamaları değiştirmek için PIN oluşturun"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN\'ler eşleşmiyor. Tekrar deneyin."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN çok kısa. En az 4 basamaklı olmalı."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 saniye içinde tekrar deneyin"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> saniye içinde tekrar deneyin</item>
+      <item quantity="one">1 saniye içinde tekrar deneyin</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Daha sonra tekrar deneyin"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Tam ekrandan çıkmak için yukarıdan aşağıya hızlıca kaydırın."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Tam ekran olarak görüntüleme"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Anladım"</string>
     <string name="done_label" msgid="2093726099505892398">"Bitti"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Saat kaydırma çemberi"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Dakika kaydırma çemberi"</string>
@@ -1835,33 +1803,34 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Bu ekranın sabitlemesini kaldırmak için Geri ve Genel Bakış\'a aynı anda dokunup basılı tutun."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Bu ekranın sabitlemesini kaldırmak için Genel Bakış\'a dokunup basılı tutun."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran sabitlendi. Kuruluşunuz sabitlemenin kaldırılmasına izin vermiyor."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran sabitlendi"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran sabitlemesi kaldırıldı"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
-    <string name="downtime_condition_summary" msgid="8761776337475705749">"Kesinti süreniz <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatinde sona erene kadar"</string>
-    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kullanım dışı kalma durumunuz bitene kadar"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Bir dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Bir saat için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d saat için (şu saate kadar: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Bir saat süreyle"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d saat süreyle"</item>
-  </plurals>
+    <string name="downtime_condition_summary" msgid="8761776337475705749">"Bildirim istenmeyen zaman <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatinde sona erene kadar"</string>
+    <string name="downtime_condition_line_one" msgid="8762708714645352010">"Bildirim istenmeyen zaman bitene kadar"</string>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Bir dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d saat için (şu saate kadar: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Bir saat için (şu saate kadar: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d dakika süreyle</item>
+      <item quantity="one">Bir dakika süreyle</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d saat için</item>
+      <item quantity="one">Bir saat için</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Şu saate kadar: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Süresiz"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Daralt"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatindeki bir sonraki alarma kadar"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Bir sonraki alarma kadar"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS isteği DIAL isteği olarak değiştirildi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS isteği USSD isteği olarak değiştirildi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS isteği yeni SS isteği olarak değiştirildi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB Çevre Birimi Bağlantı Noktası"</string>
 </resources>
diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
index c137df9..75025d8 100755
--- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml
+++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y р.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%-e %b %Y р., %H:%M:%S</string>
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
index b8c0d1e..1c25b4d 100755
--- a/core/res/res/values-uk/donottranslate-cldr.xml
+++ b/core/res/res/values-uk/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s.%s.%s"</string>
     <string name="month_day_year">%-e %B %Y р.</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d503503..306137e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без назви&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Немає номера тел.)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Невідомо"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Голос. пошта"</string>
@@ -63,17 +61,19 @@
     <string name="needPuk" msgid="919668385956251611">"SIM-карта заблок. PUK-кодом. Введіть PUK-код, щоб її розблок."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Введ. PUK2, щоб розбл. SIM-карту."</string>
     <string name="enablePin" msgid="209412020907207950">"Помилка. Увімкніть блокування SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"У вас залишилась <xliff:g id="NUMBER">%d</xliff:g> спроба. Після цього SIM-карту буде заблоковано."</item>
-    <item quantity="other" msgid="7530597808358774740">"У вас залишилося стільки спроб: <xliff:g id="NUMBER">%d</xliff:g>. Після цього SIM-карту буде заблоковано."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">У вас залишилась <xliff:g id="NUMBER_1">%d</xliff:g> спроба. Після цього SIM-карту буде заблоковано.</item>
+      <item quantity="few">У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде заблоковано.</item>
+      <item quantity="many">У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде заблоковано.</item>
+      <item quantity="other">У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде заблоковано.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Вхідн. ід. абонента"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"Вихід. ід. абонента"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"Ідентифікатор під’єднаної лінії"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"Обмеження ідентифікатора під’єднаної лінії"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"Переадрес. виклику"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Переадресація виклику"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Паралел. виклик"</string>
     <string name="BaMmi" msgid="455193067926770581">"Заборона викл."</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Зміна пароля"</string>
@@ -202,6 +202,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим польоту ВВІМК."</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим польоту ВИМК."</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Налаштування"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Голос. підказки"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
@@ -431,6 +432,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"підключитися до служби постачання маршрутів"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозволяє власникові підключатися до зареєстрованих постачальників маршрутів. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"підключатися до TV-входу"</string>
@@ -737,6 +740,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Дозволяє програмі обмінюватися даними з тегами, картками та читачами екрана Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"вимикати блокування екрана"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Дозволяє програмі вимикати блокування клавіатури та будь-який пов’язаний паролем захист. Наприклад: телефон вимикає блокування клавіатури під час отримання вхідного дзвінка, після закінчення якого блокування клавіатури відновлюється."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"керувати апаратним забезпеченням для цифрових відбитків"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Увімкнути в додатку функції для додавання й видалення шаблонів цифрових відбитків."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"користуватися апаратним забезпеченням для цифрових відбитків"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозволити додатку використовувати апаратне забезпечення для автентифікації"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"читати налаштування синхронізації"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Дозволяє програмі читати налаштування синхронізації для облікового запису, наприклад, визначати, чи програма Люди синхронізується з обліковим записом."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"вмикати й вимикати синхронізацію"</string>
@@ -791,8 +798,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"підключатися до цільової служби для вибору"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Додаток зможе підключатися до інтерфейсу верхнього рівня цільової служби для вибору. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"підключитися до служби постачання умов"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби постачання умов. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"підключатися до служби передавання медіафайлів"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби передавання медіафайлів. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"підключення до служби заставок"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби заставок. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string>
@@ -810,29 +821,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"підключатися до служби надсилання повідомлень через оператора"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби надсилання повідомлень через оператора. Звичайні додатки ніколи не використовують цей дозвіл."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Укажіть максимальну довжину та кількість символів для паролів розблокування екрана та PIN-кодів."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Відстежувати кількість неправильних паролів, введених під час розблокування екрана, і блокувати планшетний ПК або стирати всі його дані, якщо введено забагато неправильних паролів."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Відстежувати кількість неправильних паролів, введених під час розблокування екрана, і блокувати телевізор або стирати всі його дані, якщо пароль введено неправильно забагато разів."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Відстежувати кількість неправильних паролів, введених під час розблокування екрана, і блокувати  телефон або стирати всі його дані, якщо введено забагато неправильних паролів."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Змінити пароль для розблокув. екрана"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Змінювати пароль для розблокування екрана."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Відстежуйте кількість неправильних паролів, введених під час розблокування екрана. Блокуйте планшет або стирайте всі його дані, якщо пароль введено неправильно забагато разів."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Відстежуйте кількість неправильних паролів, введених під час розблокування екрана. Блокуйте телевізор або стирайте всі його дані, якщо пароль введено неправильно забагато разів."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Відстежуйте кількість неправильних паролів, введених під час розблокування екрана. Блокуйте телефон або стирайте всі його дані, якщо пароль введено неправильно забагато разів."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Змінення пароля розблокування екрана"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Змініть пароль розблокування екрана."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Блокувати екран"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Контролювати, як і коли блокується екран."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Видалити всі дані"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Стирати дані планшетного ПК без попередження, відновлюючи заводські налаштування."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Без попередження стирати дані телевізора, відновлюючи заводські налаштування."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Стирати дані телефону без попередження, відновлюючи заводські налаштування."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Видалення даних користувача"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Видаляйте дані користувача на цьому планшеті без попередження."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Видаляйте дані користувача на цьому телевізорі без попередження."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Видаляйте дані користувача на цьому телефоні без попередження."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Установ. глоб. проксі пристрою"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Устан. використ. глоб. проксі, коли ввімкнено політику. Лише адміністратор першого пристрою встановлює активний глоб. проксі."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля блокування екрана"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Контролювати частоту зміни пароля блокування екрана."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Використовуйте глобальний проксі-сервер пристрою, коли це правило ввімкнено. Налаштувати глобальний проксі-сервер може лише власник пристрою."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Частота змінення пароля"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Укажіть, як часто потрібно змінювати пароль розблокування екрана, PIN-код або ключ."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Установити шифрування носія"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Вимагати шифрування даних збереженої програми."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Вимкнути камери"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Запобігати використанню всіх камер пристрою."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Вимикати функції на клавіатурі"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Запобігає використанню деяких функцій на клавіатурі."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Функції заблокованого екрана"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Забороніть використання деяких функцій, доступних на заблокованому екрані."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Дом."</item>
     <item msgid="869923650527136615">"Мобільний"</item>
@@ -877,9 +895,9 @@
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Указати"</string>
-    <string name="phoneTypeHome" msgid="2570923463033985887">"Дом."</string>
+    <string name="phoneTypeHome" msgid="2570923463033985887">"Домашній"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Мобільний"</string>
-    <string name="phoneTypeWork" msgid="8863939667059911633">"Роб."</string>
+    <string name="phoneTypeWork" msgid="8863939667059911633">"Робочий"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Роб. факс"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Дом. факс"</string>
     <string name="phoneTypePager" msgid="7582359955394921732">"Пейджер"</string>
@@ -1128,75 +1146,14 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> хоче ввімкнути функцію дослідження дотиком. Увімкнувши функцію дослідження дотиком, можна чути або бачити опис елемента, розташованого під вашим пальцем, або виконувати жести для взаємодії з телефоном."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 міс. тому"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Раніше 1 місяця тому"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 сек. тому"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 хвилину тому"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 год. тому"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Остан. <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Останній <xliff:g id="COUNT_1">%d</xliff:g> день</item>
+      <item quantity="few">Останні <xliff:g id="COUNT_1">%d</xliff:g> дні</item>
+      <item quantity="many">Останні <xliff:g id="COUNT_1">%d</xliff:g> днів</item>
+      <item quantity="other">Останні <xliff:g id="COUNT_1">%d</xliff:g> днів</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Останній міс."</string>
     <string name="older" msgid="5211975022815554840">"Давніше"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"учора"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"через 1 сек."</item>
-    <item quantity="other" msgid="1241926116443974687">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"через 1 хв."</item>
-    <item quantity="other" msgid="3330713936399448749">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"через 1 год."</item>
-    <item quantity="other" msgid="547290677353727389">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"завтра"</item>
-    <item quantity="other" msgid="5109449375100953247">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 сек. тому"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> сек. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 хв. тому"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> хв. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 годину тому"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> год. тому"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"учора"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> дн. тому"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"через 1 с."</item>
-    <item quantity="other" msgid="5495880108825805108">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"через 1 хв."</item>
-    <item quantity="other" msgid="4216113292706568726">"через <xliff:g id="COUNT">%d</xliff:g> хв."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"через 1 год."</item>
-    <item quantity="other" msgid="3705373766798013406">"через <xliff:g id="COUNT">%d</xliff:g> год."</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"завтра"</item>
-    <item quantity="other" msgid="2973062968038355991">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"о <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"у <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1169,24 @@
     <string name="weeks" msgid="6509623834583944518">"тижн."</string>
     <string name="year" msgid="4001118221013892076">"рік"</string>
     <string name="years" msgid="6881577717993213522">"р."</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 с"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> с"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 хв"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> хв"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 год"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> год"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> секунда</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> секунди</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> хвилина</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> хвилини</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> хвилин</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> хвилини</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> година</item>
+      <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> години</item>
+      <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> годин</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> години</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Проблема з відео"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відео не придатне для потокового передавання в цей пристрій."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Неможливо відтворити це відео."</string>
@@ -1301,6 +1264,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Запуск ОС Android…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Оптимізація пам’яті."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Оптимізація програми <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Підготовка додатка <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск програм."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завершення завантаження."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Працює <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1275,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Не запускати нову програму."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Запуст. <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Зупинити попередню програму без збереження."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Виберіть дію для тексту"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Гучність дзвінка"</string>
     <string name="volume_music" msgid="5421651157138628171">"Гучність медіа"</string>
@@ -1331,20 +1303,27 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Немає"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Мелодії"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Невідома мелодія"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi мережа доступна"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi мережі доступні"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Відкрита Wi-Fi мережа доступна"</item>
-    <item quantity="other" msgid="7915895323644292768">"Відкриті Wi-Fi мережі доступні"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Мережі Wi-Fi доступні</item>
+      <item quantity="few">Мережі Wi-Fi доступні</item>
+      <item quantity="many">Мережі Wi-Fi доступні</item>
+      <item quantity="other">Мережі Wi-Fi доступні</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Відкриті мережі Wi-Fi доступні</item>
+      <item quantity="few">Відкриті мережі Wi-Fi доступні</item>
+      <item quantity="many">Відкриті мережі Wi-Fi доступні</item>
+      <item quantity="other">Відкриті мережі Wi-Fi доступні</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Вхід у мережу Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Вхід у мережу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Додаток %1$s хоче під’єднатися до мережі Wi-Fi \"%2$s\""</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Додаток"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не вдалося запустити Wi-Fi Direct."</string>
@@ -1411,6 +1390,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Під’єднано як носій"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Під’єднано як камеру"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Підключено як пристрій MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Під’єднано як програму встановлення"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Під’єднано до аксесуара USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Торкніться, щоб побачити інші параметри USB."</string>
@@ -1526,10 +1506,12 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Пропустити"</string>
     <string name="no_matches" msgid="8129421908915840737">"Немає збігів"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Знайти на сторінці"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 збіг"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> із <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> із <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="many"><xliff:g id="INDEX">%d</xliff:g> із <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> із <xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Готово"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Відключення носія USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Відключення карти SD..."</string>
@@ -1815,12 +1797,16 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Створіть PIN-код для змінення обмежень"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Повтор за 1 с"</item>
-    <item quantity="other" msgid="4730868920742952817">"Повтор за <xliff:g id="COUNT">%d</xliff:g> с"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунду</item>
+      <item quantity="few">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+      <item quantity="many">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунд</item>
+      <item quantity="other">Повтор через <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Спробуйте пізніше"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Проведіть пальцем зверху вниз, щоб вийти з повноекранного режиму."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Перегляд на весь екран"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Щоб вийти, проведіть пальцем зверху вниз."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Зрозуміло"</string>
     <string name="done_label" msgid="2093726099505892398">"Готово"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Вибір годин на циферблаті"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Вибір хвилин на циферблаті"</string>
@@ -1835,7 +1821,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Щоб відкріпити екран, одночасно натисніть і утримуйте кнопки \"Назад\" та \"Огляд\"."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Щоб відкріпити екран, натисніть і утримуйте кнопку \"Огляд\"."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Екран закріплено. Ваша організація заборонила відкріплювати його."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Екран відкріплено"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитувати PIN-код перед відкріпленням"</string>
@@ -1844,24 +1831,32 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Щоб подовжити час роботи акумулятора, функція заощадження заряду акумулятора знижує продуктивність пристрою, а також обмежує вібрацію, функції служб локації та передавання більшості фонових даних. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nФункція заощадження заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Термін простою закінчується о <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До завершення терміну простою"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Одну хвилину (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d хв (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Одну годину (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d год (до <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item>
-    <item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Протягом години"</item>
-    <item quantity="other" msgid="5408537517529822157">"Протягом %d год"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">%1$d хвилину (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d хвилини (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d хвилин (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d хвилини (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">%1$d годину (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="few">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="many">%1$d годин (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">%d хвилину</item>
+      <item quantity="few">%d хвилини</item>
+      <item quantity="many">%d хвилин</item>
+      <item quantity="other">%d хвилини</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">%d годину</item>
+      <item quantity="few">%d години</item>
+      <item quantity="many">%d годин</item>
+      <item quantity="other">%d години</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Без обмежень"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Згорнути"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"До наступного сигналу о <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"До наступного сигналу"</string>
@@ -1874,4 +1869,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Запит SS перетворено на запит DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запит SS перетворено на запит USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запит SS перетворено на новий запит SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Периферійний USB-порт"</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 0108aac..5967744 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> سیکنڈ"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> سیکنڈ"</string>
     <string name="untitled" msgid="4638956954852782576">"‏‎&gt;‎بلا عنوان‎&lt;‎"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(کوئی فون نمبر نہیں ہے)"</string>
     <string name="unknownName" msgid="6867811765370350269">"نامعلوم"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"صوتی میل"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"‏آپ کا SIM کارڈ PUK مقفل ہے۔ PUK کوڈ کو غیر مقفل کرنے کیلئے اسے ٹائپ کریں۔"</string>
     <string name="needPuk2" msgid="4526033371987193070">"‏SIM کارڈ غیر مسدود کرنے کیلئے PUK2 ٹائپ کریں۔"</string>
     <string name="enablePin" msgid="209412020907207950">"‏ناکام، SIM/RUIM لاک کو فعال کریں۔"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"‏SIM مقفل ہونے سے پہلے آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوشش بچی ہے۔"</item>
-    <item quantity="other" msgid="7530597808358774740">"‏SIM مقفل ہونے سے پہلے آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوششیں بچی ہیں۔"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">‏آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں، اس کے بعد SIM مقفل ہو جائے گا۔</item>
+      <item quantity="one">‏آپ کے پاس <xliff:g id="NUMBER_0">%d</xliff:g> کوشش بچی ہے، اس کے بعد SIM مقفل ہو جائے گا۔</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"‏ان کمنگ کالر ID"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ہوائی جہاز وضع آن ہے"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ہوائی جہاز وضع آف ہے"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"ترتیبات"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"‎999+‎"</string>
     <string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"حامل کو ریموٹ ڈسپلے کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ایک ویجیٹ سروس کے پابند بنیں"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"حامل کو ویجیٹ سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"راستہ فراہم کرنے والی ایک سروس کے پابند بنیں"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"حامل کو کسی بھی رجسٹرڈ راستہ کے فراہم کنندگان کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"آلہ کے ایک منتظم کے ساتھ تعامل کریں"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"حامل کو ایک آلہ کے منتظم کو ارادے بھیجنے دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"‏ایک TV ان پٹ کے پابند بنیں"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"‏ایپ کو Near Field Communication (NFC)‎ ٹیگز، کارڈز اور ریڈرز کے ساتھ مواصلت کرنے کی اجازت دیٹا ہے۔"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"اپنے اسکرین لاک کو غیر فعال کریں"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"ایپ کو کلیدی لاک اور کسی بھی متعلقہ پاس ورڈ سیکیورٹی کو غیر فعال کرنے کی اجازت دیتا ہے۔ مثلاً، کوئی آنے والی فون کال موصول ہونے کے وقت فون کلیدی لاک کو غیر فعال کرتا ہے، پھر کال پوری ہوجانے پر کلیدی لاک کو دوبارہ فعال کردیتا ہے۔"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"فنگر پرنٹ ہارڈ ویئر کا نظم کریں"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"ایپ کو استعمال کیلئے فنگر پرنٹ کی تمثیلات شامل کرنے اور حذف کرنے کیلئے طریقوں کو کالعدم قرار دینے کی اجازت دیتا ہے۔"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"فنگر پرنٹ ہارڈ ویئر استعمال کریں"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"ایپ کو توثیق کیلئے فنگر پرنٹ ہارڈ ویئر استعمال کرنے کی اجازت دیتا ہے"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"مطابقت پذیری کی ترتیبات پڑھیں"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"‏ایپ کو کسی اکاؤنٹ کیلئے مطابقت پذیری کی ترتیبات پڑھنے کی اجازت دیتا ہے۔ مثلا، یہ تعین کرسکتا ہے کہ آیا People ایپ کسی اکاؤنٹ کے ساتھ مطابقت پذیر ہے۔"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"مطابقت پذیری آن اور آف ٹوگل کریں"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"دوسرے ایپس کے ذریعے شائع کردہ کے بشمول ایپ کو اطلاعات کی بازیابی، تفتیش اور انہیں صاف کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اطلاع سننے والی سروس کے پابند بنیں"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"حامل کو اطلاع سننے والی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"ایک انتخاب کنندہ کی اہدافی سروس کا پابند بنائیں"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"حامل کو ایک انتخاب کنندہ کی اہدافی سروس کے اعلی سطحی انٹرفیس کا پابند بنانے کی اجازت دیتا ہے۔ عام اطلاقات کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"شرط فراہم کرنے والی ایک سروس کے پابند بنیں"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"حامل کو شرط فراہم کنندہ کی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"میڈیا روٹ سروس کا پابند بنیں"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"حامل کو میڈیا روٹ سروس کے اعلی سطحی انٹرفیس کا پابند کرنے کی اجازت دیتا ہے۔ معمول کی ایپس کیلئے کبھی درکار نہیں ہونا چاہئے۔"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"ایک ڈریم سروس کا پابند بنیں"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"حامل کو ڈریم سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتی ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہیے۔"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"کیریئر کے ذریعے فراہم کردہ کنفگریشن ایپ طلب کریں"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ایک کیریئر پیغام رسانی سروس کا پابند بنیں"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"حامل کو ایک کیریئر پیغام رسانی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتی ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہیں ہونی چاہیے۔"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"پاس ورڈ کے اصول سیٹ کریں"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"اسکرین غیر مقفل کرنے کے پاس ورڈز میں مجاز طوالت اور حروف کو کنٹرول کریں۔"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"‏اسکرین لاک پاس ورڈز اور PINs میں اجازت یافتہ لمبائی اور حروف کو کنٹرول کریں۔"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"اسکرین غیر مقفل کرنے کی کوششیں مانیٹر کریں"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"اسکرین کو غیر مقفل کرتے وقت ٹائپ کیے گئے غلط پاس ورڈز کی تعداد مانیٹر کریں اور ٹیبلیٹ کو مقفل کریں یا اگر کافی زیادہ غلط پاس ورڈز ٹائپ کیے گئے ہیں تو ٹیبلیٹ کا سبھی ڈیٹا صاف کریں۔"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"‏اسکرین کو غیر مقفل کرتے وقت ٹائپ کردہ غلط پاس ورڈز کی تعداد پر نگاہ رکھیں اور اگر بہت زیادہ غلط پاس ورڈز ٹائپ کیے جاتے ہیں تو TV کو مقفل کریں یا TV کا سبھی ڈیٹا مٹائیں۔"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"اسکرین کو غیر مقفل کرتے وقت ٹائپ کیے گئے غلط پاس ورڈز کی تعداد مانیٹر کریں اور فون کو مقفل کریں یا اگر کافی زیادہ غلط پاس ورڈز ٹائپ کیے گئے ہیں تو فون کا سبھی ڈیٹا صاف کریں۔"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"اسکرین غیر مقفل کرنے کا پاس ورڈ تبدیل کریں"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"اسکرین غیر مقفل کرنے کا پاس ورڈ تبدیل کریں۔"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"اسکرین کو غیر مقفل کرتے وقت ٹائپ کردہ غلط پاس ورڈز کی تعداد پر نگاہ رکھیں اور اگر بہت زیادہ غلط پاس ورڈز ٹائپ کیے جاتے ہیں تو ٹیبلٹ کو مقفل کریں یا اس صارف کا سبھی ڈیٹا ہٹائیں۔"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"‏اسکرین کو غیر مقفل کرتے وقت ٹائپ کردہ غلط پاس ورڈز کی تعداد پر نگاہ رکھیں اور اگر بہت زیادہ غلط پاس ورڈز ٹائپ کیے جاتے ہیں تو TV کو مقفل کریں یا اس صارف کا سبھی ڈیٹا ہٹائیں۔"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"اسکرین کو غیر مقفل کرتے وقت ٹائپ کردہ غلط پاس ورڈز کی تعداد پر نگاہ رکھیں اور اگر بہت زیادہ غلط پاس ورڈز ٹائپ کیے جاتے ہیں تو فون کو مقفل کریں یا اس صارف کا سبھی ڈیٹا ہٹائیں۔"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"اسکرین لاک تبدیل کریں"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"اسکرین لاک تبدیل کریں۔"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"اسکرین مقفل کریں"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"اسکرین کب اور کس طرح مقفل ہوتا ہے اس کو کنٹرول کریں۔"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"سبھی ڈیٹا صاف کریں"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"فیکٹری ڈیٹا کی دوبارہ ترتیب انجام دے کر وارننگ کے بغیر ٹیبلٹ کا ڈیٹا مٹائیں۔"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"‏ایک فیکٹری ڈیٹا ری سیٹ انجام دے کر انتباہ کے بغیر TV کا ڈیٹا مٹائیں۔"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"فیکٹری ڈیٹا کی دوبارہ ترتیب انجام دے کر وارننگ کے بغیر فون کا ڈیٹا مٹائیں۔"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"صارف کا ڈیٹا ہٹائیں"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"وارننگ کے بغیر اس ٹیبلٹ پر موجود اس صارف کا ڈیٹا ہٹائیں۔"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"‏وارننگ کے بغیر اس TV پر موجود اس صارف کا ڈیٹا ہٹائیں۔"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"وارننگ کے بغیر اس فون پر موجود اس صارف کا ڈیٹا ہٹائیں۔"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"آلہ کی عالمی پراکسی سیٹ کریں"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پالیسی فعال ہونے پراستعمال کیے جانے کیلئے آلہ کی عالمی پراکسی سیٹ کریں۔ آلے کا صرف پہلا منتظم مؤثر عالمی پراکسی سیٹ کرتا ہے۔"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"لاک سکرین پاسورڈ مدت سیٹ کریں"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"اسکرین مقفل کرنے کا پاس ورڈ کتنی کثرت سے تبدیل کیا جانا چاہیے اس کو کنٹرول کریں۔"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"پالیسی فعال ہونے پر آلہ کی عالمی پراکسی کو استعمال کیے جانے کیلئے سیٹ کریں۔ صرف آلہ کا مالک ہی عالمی پراکسی سیٹ کر سکتا ہے۔"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"اسکرین لاک پاس ورڈ کی میعاد سیٹ کریں"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"‏تبدیل کریں کہ کتنے وقفہ میں اسکرین لاک پاس ورڈ، PIN یا پیٹرن تبدیل ہونا ضروری ہے۔"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"اسٹوریج کی مرموز کاری سیٹ کریں"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"مطالبہ کریں کہ اسٹور کردہ ایپ کا ڈیٹا مرموز کیا جائے۔"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"کیمروں کو غیر فعال کریں"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"سبھی آلے کے کیمروں کا استعمال روکیں۔"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"کی گارڈ کی خصوصیات غیر فعال کریں"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"کی گارڈ میں کچھ خصوصیات کے استعمال کو روکیں۔"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"اسکرین لاک کی خصوصیات غیر فعال کریں"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"اسکرین لاک کی کچھ خصوصیات کے استعمال سے روکیں۔"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"گھر"</item>
     <item msgid="869923650527136615">"موبائل"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ٹچ کرکے دریافت کریں کو فعال کرنا چاہتی ہے۔ ٹچ کرکے دریافت کریں کے آن ہو جانے پر، آپ کو اپنی انگلی کے نیچے موجود چیزوں کی تفصیلات دکھائی یا سنائی دے سکتی ہیں یا آپ فون کے ساتھ تعامل کرنے کیلئے اشارے انجام دے سکتے ہیں۔"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 مہینہ پہلے"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 مہینہ سے زیادہ پہلے"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 سیکنڈ پہلے"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 منٹ پہلے"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 گھنٹہ پہلے"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"آخری <xliff:g id="COUNT">%d</xliff:g> دن"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">گزشتہ <xliff:g id="COUNT_1">%d</xliff:g> دن</item>
+      <item quantity="one">گزشتہ <xliff:g id="COUNT_0">%d</xliff:g> دن</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"پچھلے مہینے"</string>
     <string name="older" msgid="5211975022815554840">"پرانا"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"گزشتہ کل"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 سیکنڈ میں"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 منٹ میں"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 گھنٹہ میں"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"آنے والا کل"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 سیکنڈ پہلے"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 منٹ پہلے"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> منٹ پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 گھنٹہ پہلے"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"گزشتہ کل"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> دن پہلے"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 سیکنڈ میں"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 منٹ میں"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> منٹ میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 گھنٹہ میں"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے میں"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"آنے والا کل"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> دن میں"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g> کو"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g> میں"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"ہفتے"</string>
     <string name="year" msgid="4001118221013892076">"سال"</string>
     <string name="years" msgid="6881577717993213522">"سال"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 سیکنڈ"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 منٹ"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> منٹ"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 گھنٹہ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> گھنٹے"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> سیکنڈ</item>
+      <item quantity="one">1 سیکنڈ</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> منٹ</item>
+      <item quantity="one">1 منٹ</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> گھنٹے</item>
+      <item quantity="one">1 گھنٹہ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"ویڈیو مسئلہ"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"یہ ویڈیو اس آلہ پر سلسلہ بندی کیلئے درست نہیں ہے۔"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"یہ ویڈیو نہیں چل سکتا۔"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"‏Android شروع ہو رہا ہے…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"اسٹوریج کو بہترین بنایا جا رہا ہے۔"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"ایپ <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g> کو بہتر بنایا جا رہا ہے۔"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> تیار ہو رہی ہے۔"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ایپس شروع ہو رہی ہیں۔"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"بوٹ مکمل ہو رہا ہے۔"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> چل رہی ہے"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"نئی ایپ شروع نہ کریں۔"</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> شروع کریں"</string>
     <string name="new_app_description" msgid="1932143598371537340">"محفوظ کیے بغیر پرانی ایپ بند کریں۔"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"متن کیلئے ایک کارروائی منتخب کریں"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"رنگر والیوم"</string>
     <string name="volume_music" msgid="5421651157138628171">"میڈیا والیوم"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"کوئی نہیں"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"رنگ ٹونز"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"نامعلوم رنگ ٹون"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"‏Wi-Fi نیٹ ورک دستیاب ہے"</item>
-    <item quantity="other" msgid="4192424489168397386">"‏Wi-Fi نیٹ ورکس دستیاب ہیں"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"‏عوامی Wi-Fi نیٹ ورک دستیاب ہے"</item>
-    <item quantity="other" msgid="7915895323644292768">"‏عوامی Wi-Fi نیٹ ورکس دستیاب ہیں"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">‏Wi-Fi نیٹ ورکس دستیاب ہیں</item>
+      <item quantity="one">‏Wi-Fi نیٹ ورک دستیاب ہے</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">‏عوامی Wi-Fi نیٹ ورکس دستیاب ہیں</item>
+      <item quantity="one">‏عوامی Wi-Fi نیٹ ورک دستیاب ہے</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"‏Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"نیٹ ورک میں سائن ان کریں"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اس میں ایک کمزور انٹرنیٹ کنکشن ہے۔"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏ایپلیکیشن ‎%1$s Wifi نیٹ ورک ‎%2$s سے منسلک ہونا چاہتی ہے"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ایک ایپلیکیشن"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ڈائریکٹ"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi ڈائرکٹ شروع کریں۔ یہ Wi-Fi کلائنٹ/ہاٹ اسپاٹ کو آف کردے گا۔"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏Wi-Fi ڈائرکٹ شروع نہیں کرسکا۔"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"ٹھیک ہے"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"ایک میڈیا آلہ کے بطور مربوط کر دیا گیا"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"ایک کیمرہ کے بطور مربوط ہے"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"‏MIDI آلہ کے بطور منسلک"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"ایک انسٹالر کے بطور مربوط ہے"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏ایک USB لوازم سے مربوط ہے"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"‏USB کے دوسرے اختیارات کیلئے چھوئیں۔"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"نظر انداز کریں"</string>
     <string name="no_matches" msgid="8129421908915840737">"کوئی مماثلتیں نہیں ہیں"</string>
     <string name="find_on_page" msgid="1946799233822820384">"صفحہ پر تلاش کریں"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 مماثلت"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 مماثلت</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"ہو گیا"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"‏USB اسٹوریج کو اَن ماؤںٹ کر رہا ہے…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"‏SD کارڈ کو اَن ماؤںٹ کر رہا ہے…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"‏تحدیدات میں ترمیم کرنے کیلئے ایک PIN بنائیں"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"‏PINs مماثل نہیں ہیں۔ دوبارہ کوشش کریں۔"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"‏PIN کافی چھوٹا ہے۔ کم از کم 4 ہندسے ہونا ضروری ہے۔"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 سیکنڈ میں دوبارہ کوشش کریں"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں</item>
+      <item quantity="one">1 سیکنڈ میں دوبارہ کوشش کریں</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"بعد میں دوبارہ کوشش کریں"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"مکمل اسکرین سے نکلنے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"پوری اسکرین میں دیکھ رہے ہیں"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"خارج ہونے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"سمجھ آ گئی"</string>
     <string name="done_label" msgid="2093726099505892398">"ہو گیا"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"گھنٹوں کا سرکلر سلائیڈر"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"منٹس سرکلر سلائیڈر"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"اس اسکرین سے پن ہٹانے کیلئے، واپس جائیں اور مجموعی جائزہ کو ایک ساتھ ٹچ کریں اور دبا کر رکھیں۔"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"اس اسکرین سے پن ہٹانے کیلئے، مجموعی جائزہ کو ٹچ کریں اور دبا کر رکھیں۔"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"اسکرین کو پن کر دیا گیا ہے۔ آپ کی تنظیم کی جانب سے پن ہٹانے کی اجازت نہیں ہے۔"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"اسکرین کو پن کر دیا گیا"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"اسکرین کا پن ہٹا دیا گیا"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"بیٹری کی میعاد بہتر کرنے میں مدد کرنے کیلئے، بیٹری کی بچت آپ کے آلہ کی کارکردگی کم کر دیتی ہے اور وائبریشن، مقام کی سروسز اور پس منظر کا بیشتر ڈیٹا محدود کر دیتی ہے۔ ای میل، پیغام رسانی اور مطابقت پذیری پر مبنی دیگر ایپس ممکن ہے اس وقت تک اپ ڈیٹ نہ ہوں جب تک آپ انہیں نہ کھولیں۔\n\nآپ کا آلہ چارج ہوتے وقت بیٹری کی بچت خود بخود آف ہو جاتی ہے۔"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> پر آپ کا آخری وقت ختم ہونے تک"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"آپ کا ڈاؤن ٹائم ختم ہونے تک"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"ایک منٹ کیلئے (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> تک)"</item>
-    <item quantity="other" msgid="2787867221129368935">"‏%1$d منٹ کیلئے (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> تک)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"ایک گھنٹے کیلئے (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> تک)"</item>
-    <item quantity="other" msgid="2827214920627669898">"‏%1$d گھنٹوں کیلئے (<xliff:g id="FORMATTEDTIME">%2$s</xliff:g> تک)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"ایک منٹ کیلئے"</item>
-    <item quantity="other" msgid="6924190729213550991">"‏%d منٹ کیلئے"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"ایک گھنٹے کیلئے"</item>
-    <item quantity="other" msgid="5408537517529822157">"‏%d گھنٹوں کیلئے"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">‏%1$d منٹ کیلئے (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> تک)</item>
+      <item quantity="one">ایک منٹ کیلئے (تک <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">‏%1$d گھنٹے کیلئے (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> تک)</item>
+      <item quantity="one">ایک گھنٹہ کیلئے (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> تک)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">‏‎%d منٹ کیلئے</item>
+      <item quantity="one">ایک منٹ کیلئے</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">‏‎%d گھنٹے کیلئے</item>
+      <item quantity="one">ایک گھنٹہ کیلئے</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> تک"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"غیر متعینہ"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"جب تک آپ اسے آف نہ کر دیں"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"سکیڑیں"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"اگلے الارم تک بوقت <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"اگلے الارم تک"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"‏SS درخواست میں ترمیم کر کے DIAL درخواست بنا دی گئی ہے۔"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"‏SS درخواست میں ترمیم کر کے USSD درخواست بنا دی گئی ہے۔"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"‏SS درخواست میں ترمیم کر کے نئی SS درخواست بنا دی گئی ہے۔"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"‏USB پیرفرل پورٹ"</string>
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index f23d175..812f34e 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> soniya"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> soniya"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Nomsiz&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon raqamlari yo‘q)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Noma’lum"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Ovozli xabar"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM kartangiz PUK kod bilan qulflangan. Uni qulfdan chiqarish uchun PUK kodni tering."</string>
     <string name="needPuk2" msgid="4526033371987193070">"SIM kartani blokdan chiqarish uchun PUK2 raqamini kiriting."</string>
     <string name="enablePin" msgid="209412020907207950">"Ishlamadi, SIM/RUIM qulfni yoqish."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"<xliff:g id="NUMBER">%d</xliff:g> marta uringaningizdan so‘ng, SIM karta qulflanib qoladi."</item>
-    <item quantity="other" msgid="7530597808358774740">"<xliff:g id="NUMBER">%d</xliff:g> marta uringaningizdan so‘ng, SIM karta qulflanib qoladi."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Yana <xliff:g id="NUMBER_1">%d</xliff:g> ta muvaffaqiyatsiz urinishdan so‘ng SIM karta qulflanadi.</item>
+      <item quantity="one">Yana <xliff:g id="NUMBER_0">%d</xliff:g> ta muvaffaqiyatsiz urinishdan so‘ng SIM karta qulflanadi.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Kiruvchi raqami"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Parvoz usuli yoqilgan"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Parvoz rejimi o‘chirilgan"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Sozlamalar"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Ovozli yordam"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Foydalanuvchiga masofaviy ekranning yuqori darajali interfeysini bog‘lash imkonini beradi. Oddiy dasturlar uchun hech qachon kerak bo‘lmaydi."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidjet xizmatiga bog‘lash"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ilova vidjetlar xizmatining yuqori darajali interfeysiga ulanishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"yo‘nalish taqdim etuvchilarning serveriga bog‘lanish"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ilova ro‘yxatdan o‘tgan shartlarni taqdim etuvchilarning serveriga ulanishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"administrator bilan kelishib harakat qilish"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ilova qurilma administratoriga maqsadlarni yuborishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV-kiritishga ulanish"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ilova qisqa masofali aloqa (NFC) texnologiyasi yordamida NFC yorliqlari, kartalar va o‘qish moslamalari bilan ma’lumot almashishi mumkin."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ekran qulfini o‘chirib qo‘yish"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ilovaga ekran qulfini va har qanday parol  yordamidagi xavfsizlik himoyalarini o‘chirishga ruxsat beradi. Masalan, kirish qo‘ng‘irog‘ida telefon ekran qulfini o‘chiradi va qo‘ng‘iroq tugashi bilan qulfni yoqadi."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"barmoq izi sensorini boshqarish"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Ilova foydalanish uchun barmoq izi namunalarini qo‘shish va o‘chirish usullarini qo‘llashi mumkin."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"barmoq izi sensoridan foydalanish"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Ilova haqiqiylikni tekshirish uchun barmoq izi sensoridan foydalanishi mumkin"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"sinx-sh sozlamalarini o‘qish"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ilovaga hisobning sinxronlash sozlamalarini o‘qish uchun ruxsat beradi. Masalan, bu \"Odamlar\" ilovasi hisob bilan sinxronlangan yoki aksini aniqlay oladi."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"sinx.ni yoqish/o‘chirish"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dasturga bildirishnomalar va boshqa dasturlar jo‘natgan xabarlarni qabul qilish, ko‘rib chiqish hamda tozalash imkonini beradi."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirishnomani tinglash xizmatiga bog‘lash"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Foydalanuvchiga bildirishnomani eshituvchi xizmat yuqori darajali interfeysini bog‘lash imkonini beradi. Oddiy dasturlar uchun hech qachon kerak bo‘lmaydi."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"mo‘ljaldagi xizmat bilan bog‘lanish"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Egasiga mo‘ljaldagi xizmatning yuqori darajali interfeysiga bog‘lanish uchun ruxsat beradi. Oddiy ilovalar uchun hech qachon kerak bo‘lmaydi."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"shartlarni taqdim etuvchilarning serveriga ulanish"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ilova shartlarni taqdim etuvchining yuqori darajali interfeysiga ulanishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"media fayllarni uzatish vositasiga bog‘lab qo‘yish"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Media fayllarni uzatishning yuqori darajali vositasiga bog‘lab qo‘yish. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"Ekran lavhalari xizmatiga ulanish"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Ekran lavhalari xizmatining yuqori darajali interfeysiga ulanish. Oddiy ilovalar tomonidan ishlatilmaydi."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aloqa operatorining sozlash dasturini so‘rash"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"aloqa operatorining xabar almashinuv xizmatiga bog‘lanish"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Egasiga aloqa operatorining xabar almashinuv xizmatining yuqori darajali interfeysiga bog‘lanish uchun ruxsat beradi. Oddiy ilovalar uchun hech qachon kerak bo‘lmaydi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qoidalarini o‘rnatish"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran qulfini ochish parollariga ruxsat berilgan belgilar va ularning uzunligini boshqarish."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran qulfi paroli va PIN kodlari uchun qo‘yiladigan talablarni (belgilar soni va uzunligi) nazorat qiladi."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekranni qulfdan chiqarish urinishlarini nazorat qilish"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Ekranni qulfini ochishda parolni kiritishga urinishlarni kuzatib boradi va agar parol bir necha marta noto‘g‘ri kiritilsa, planshetni qulflaydi yoki undagi ma’lumotlarni o‘chirib tashlaydi."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Ekranni qulfdan chiqarishda noto‘g‘ri kiritilgan parollarni sonini kuzatib boradi hamda agar parol juda ko‘p marta noto‘g‘ri kiritilsa, televizorni qulflash yoki undagi barcha ma’lumotlarni o‘chirib tashlaydi."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Ekranni qulfini ochishda parolni kiritishga urinishlarni kuzatib boradi va agar parol bir necha marta noto‘g‘ri kiritilsa, telefonni qulflaydi yoki undagi ma’lumotlarni o‘chirib tashlaydi."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekranni qulfdan chiqarish parolini o‘zgartirish"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekran qulfini ochish parolini o‘zgartirish."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Ekran qulfini ochishda kiritilgan noto‘g‘ri parollar sonini kuzatib boradi va agar parol juda ko‘p marta noto‘g‘ri kiritilsa, planshetni qulflaydi yoki undagi barcha ma’lumotlarni o‘chirib tashlaydi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Ekran qulfini ochishda kiritilgan noto‘g‘ri parollar sonini kuzatib boradi va agar parol juda ko‘p marta noto‘g‘ri kiritilsa, televizorni qulflaydi yoki undagi barcha ma’lumotlarni o‘chirib tashlaydi."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Ekran qulfini ochishda kiritilgan noto‘g‘ri parollar sonini kuzatib boradi va agar parol juda ko‘p marta noto‘g‘ri kiritilsa, telefonni qulflaydi yoki undagi barcha ma’lumotlarni o‘chirib tashlaydi."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Ekran qulfini o‘zgartirish"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Ekran qulfini o‘zgartiradi."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Ekranni qulflash"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Ekranning qachon va qanday qulflanishini boshqaradi."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Barcha ma’lumotlarni o‘chirish"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Planshet ma’lumotlarini ogohlantirishlarsiz ishlab chiqarilgan holatiga tiklash orqali o‘chirish"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Zavod sozlamalarini qayta tiklash orqali televizordagi ma’lumotlarni ogohlantirishsiz o‘chirib tashlaydi."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Telefon ma’lumotlarini ogohlantirishlarsiz zavod sozlamalarini tiklash orqali o‘chirish"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Foydalanuvchi ma’lumotlarini o‘chirish"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Ushbu planshetdagi foydalanuvchi ma’lumotlarini ogohlantirishsiz o‘chirib tashlaydi."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Ushbu televizordagi foydalanuvchi ma’lumotlarini ogohlantirishsiz o‘chirib tashlaydi."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Ushbu telefondagi foydalanuvchi ma’lumotlarini ogohlantirishsiz o‘chirib tashlaydi."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Qurilmaga global proksi o‘rnatish"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Siyosat yoqib qo‘yilganda foydalanish uchun global proksini qurilmaga o‘rnating. Faqat birinchi qurilma administratori samarali global proksini o‘rnatadi."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Ekran qulf-sh paroli muddati."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Ekranni qulflash parolini qancha muddatda almashtirish kerakligini boshqaradi."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Qoida faollashtirilgan vaqtda ishlatiladigan qurilmaning global proksi-serverini o‘rnatadi. Faqat qurilma egasi global proksi-serverini o‘rnatishi mumkin."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Parol muddatini o‘rnatish"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Ekran qulfi paroli, PIN kodi yoki chizmali paroli o‘zgartiriladigan muddatni o‘zgartiradi."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Xotirani kodlashni o‘rnatish"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zaxiralangan ilovalar ma‘lumotlarini kodlashni talab qiladi."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameralarni o‘chirish"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Barcha qurilma kameralaridan foydalanishga yo‘l qo‘ymaydi."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Tugmatagni qulflash xususiyatlarini o‘chirish"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Tugmatagni qulflashda ba’zi xususiyatlardan foydalanishga yo‘l qo‘ymaydi."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Funksiyalarni o‘chirib qo‘yish"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Ekran qulfining ba’zi funksiyalaridan foydalanishni cheklaydi."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Uy"</item>
     <item msgid="869923650527136615">"Mobayl"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> teginib o‘rganish xususiyatini yoqishni xohlamoqda. Bu xususiyat yoqilganda, barmog‘ingiz ostidagi elementlar ta‘rifini ko‘rishingiz yoki eshitishingiz mumkin yoki telefon bilan o‘zaro bog‘lanish uchun barmog‘ingiz bilan imo-ishorali harakatlarni bajaring."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 oy oldin"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 oydan oldinroq"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 soniya oldin"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 daqiqa oldin"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> daqiqa oldin"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 soat oldin"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"O‘tgan <xliff:g id="COUNT">%d</xliff:g> kun"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">So‘nggi <xliff:g id="COUNT_1">%d</xliff:g> kun</item>
+      <item quantity="one">So‘nggi <xliff:g id="COUNT_0">%d</xliff:g> kun</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"O‘tgan oy"</string>
     <string name="older" msgid="5211975022815554840">"Eskiroq"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"kecha"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 soniyada"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> soniyada"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 daqiqada"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> daqiqada"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 soatda"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ertaga"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 soniya oldin"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> soniya oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 daq. oldin"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> daq. oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 soat oldin"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"kecha"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 soniya da"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> soniya da"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 daq. da"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> daq. da"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 soatda"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> soatda"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ertaga"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> kunda"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>da"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>da"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"<xliff:g id="YEAR">%s</xliff:g>da"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"hafta"</string>
     <string name="year" msgid="4001118221013892076">"yil"</string>
     <string name="years" msgid="6881577717993213522">"yil"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 soniya"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> soniya"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 daqiqa"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> daqiqa"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 soat"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> soat"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> soniya</item>
+      <item quantity="one">1 soniya</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> daqiqa</item>
+      <item quantity="one">1 daqiqa</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> soat</item>
+      <item quantity="one">1 soat</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Video muammosi"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ushbu videoni mazkur qurilmada oqimli rejimda ijro etib bo‘lmaydi."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ushbu videoni ijro etib bo‘lmadi."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android ishga tushmoqda…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Xotira optimallashtirilmoqda."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ilovalar optimallashtirilmoqda (<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>)."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> tayyorlanmoqda."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Ilovalar ishga tushirilmoqda."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Tizimni yuklashni tugatish."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> ishlamoqda"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Yangi ilova ishga tushirilmasin."</string>
     <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g>ni ishga tushirish"</string>
     <string name="new_app_description" msgid="1932143598371537340">"O‘zgarishlarni saqlamasdan, eski ilova yopilsin"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Matn uchun amalni tanlash"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Qo‘ng‘iroq tovushi"</string>
     <string name="volume_music" msgid="5421651157138628171">"Media tovushi"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Yo‘q"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Musiqalar"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Noma’lum musiqa"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Wi-Fi tarmoq mavjud"</item>
-    <item quantity="other" msgid="4192424489168397386">"Wi-Fi tarmoqlar mavjud"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Mavjud Wi-Fi tarmoqni ochish"</item>
-    <item quantity="other" msgid="7915895323644292768">"Mavjud Wi-Fi tarmoqlarini ochish"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Wi-Fi tarmoqlari mavjud emas</item>
+      <item quantity="one">Wi-Fi tarmog‘i mavjud emas</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Ochiq Wi-Fi tarmoqlari mavjud</item>
+      <item quantity="one">Ochiq Wi-Fi tarmog‘i mavjud</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Wi-Fi tarmoqqa kirish"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Tarmoqqa kiring"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tezligi past Internetga ulangan."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ilovasi %2$s Wi-Fi tarmog‘iga ulanmoqchi"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ilova"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct’ni ishga tushirish. Bu Wi-Fi mijoz/ulanish nuqtasini o‘chiradi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ishga tushirilmadi."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Media qurilma sifatida ulangan"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kamera sifatida ulandi"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"MIDI qurilma sifatida ulandi"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"O‘rnatgich sifatida ulandi"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB jihozga ulangan"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Boshqa USB sozlamalarini ko‘rish uchun bosing."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Tashlab o‘tish"</string>
     <string name="no_matches" msgid="8129421908915840737">"Topilmadi"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Sahifadan topish"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 mos topildi"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="TOTAL">%d</xliff:g>dan <xliff:g id="INDEX">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 ta natija</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Tayyor"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB xotirasi uzilmoqda…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD xotira kartasi uzilmoqda…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Cheklovlarni o‘zgartirish uchun PIN kod yaratish"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN kodlar bir xil emas. Qaytadan urinib ko‘ring."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN kod juda qisqa. Kamida 4 raqamli bo‘lishi kerak."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 soniyadan keyin qayta urinib ko‘ring"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> soniyadan keyin qayta urinib ko‘ring"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring</item>
+      <item quantity="one">1 soniyadan so‘ng qayta urinib ko‘ring</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Keyinroq urinib ko‘ring"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"\"Butun ekran\" usulidan chiqish uchun barmoq bilan ekran tepasidan pastga tomon silang."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"To‘liq ekran ko‘rsatilmoqda"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Chiqish uchun tepadan pastga torting."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Tayyor"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Doiradan soatni tanlang"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Doiradan daqiqani tanlang"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ushbu ekrandan chiqish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosib turing."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ushbu ekrandan chiqish uchun “Umumiy nazar” tugmasini bosib turing."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Ekran qadab qo‘yildi. Uni bo‘shatishga tashkilotingiz ruxsat bermagan."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran bo‘shatildi"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bo‘shatishdan oldin PIN kod so‘ralsin"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Tanaffus vaqti tugaguncha – <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Nofoal vaqtingiz tugaguncha"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Bir daqiqa (ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d daqiqa (ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Bir soat (ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d soat (ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 daqiqa"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d daqiqa"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 soat"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d soat"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d daqiqa (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> gacha)</item>
+      <item quantity="one">Bir daqiqa (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> gacha)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d soat (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> gacha)</item>
+      <item quantity="one">Bir soat (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> gacha)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d daqiqa</item>
+      <item quantity="one">Bir daqiqa</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d soat</item>
+      <item quantity="one">Bir soat</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Ushbu vaqtgacha: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Uzluksiz ravishda"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Men o‘chirmaguncha"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Yig‘ish"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Keyingi uyg‘otkich vaqtigacha (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Keyingi uyg‘otkich vaqtigacha"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS so‘rovi DIAL so‘roviga o‘zgartirildi."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS so‘rovi USSD so‘roviga o‘zgartirildi."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS so‘rovi yangi SS so‘roviga o‘zgartirildi."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Tashqi USB porti"</string>
 </resources>
diff --git a/core/res/res/values-vi-rVN/donottranslate-cldr.xml b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi-rVN/donottranslate-cldr.xml
+++ b/core/res/res/values-vi-rVN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
index 3a735bf..8f5cf3b 100755
--- a/core/res/res/values-vi/donottranslate-cldr.xml
+++ b/core/res/res/values-vi/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
     <string name="time_of_day">%H:%M:%S</string>
     <string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 328cdc6..8c8c305 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> giây"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> giây"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Không có tiêu đề&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Không có số điện thoại nào)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Không xác định"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Thư thoại"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Thẻ SIM của bạn đã bị khóa PUK. Nhập mã PUK để mở khóa thẻ SIM đó."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Nhập mã PUK2 để bỏ chặn thẻ SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Không thành công, kích hoạt tính năng khóa SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử trước khi SIM bị khóa."</item>
-    <item quantity="other" msgid="7530597808358774740">"Bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử trước khi SIM bị khóa."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">Bạn còn <xliff:g id="NUMBER_1">%d</xliff:g> lần thử trước khi SIM bị khóa.</item>
+      <item quantity="one">Bạn còn <xliff:g id="NUMBER_0">%d</xliff:g> lần thử trước khi SIM bị khóa.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"Số gọi đến"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Cài đặt"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"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ụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"liên kết với dịch vụ nhà cung cấp định tuyến"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Cho phép chủ sở hữu liên kết với bất kỳ nhà cung cấp định tuyến đã đăng ký nào. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"liên kết với đầu vào TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Cho phép ứng dụng giao tiếp với thẻ Giao tiếp trường gần (NFC), thẻ và trình đọc."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"vô hiệu hóa khóa màn hình của bạn"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Cho phép ứng dụng tắt khóa phím và bất kỳ bảo mật mật khẩu được liên kết nào. Ví dụ: điện thoại tắt khóa phím khi nhận được cuộc gọi đến, sau đó bật lại khóa phím khi cuộc gọi kết thúc."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"quản lý phần cứng vân tay"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Cho phép ứng dụng gọi các phương pháp để thêm và xóa các mẫu vân tay để sử dụng."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"sử dụng phần cứng vân tay"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Cho phép ứng dụng sử dụng phần cứng vân tay để xác thực"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"đọc cài đặt đồng bộ hóa"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa cho tài khoản. Ví dụ: việc này có thể xác định liệu ứng dụng Mọi người đã được đồng bộ hóa với tài khoản chưa."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"chuyển đổi bật và tắt đồng bộ hóa"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"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ụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"liên kết với dịch vụ nhắm mục tiêu trình chọn"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"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ụ nhắm mục tiêu trình chọn. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"liên kết với dịch vụ trình cung cấp điều kiện"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"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ụ trình cung cấp điều kiện. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"liên kết với dịch vụ định tuyến phương tiện"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"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ụ định tuyến phương tiện. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"liên kết với dịch vụ dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"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ụ dream. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp"</string>
@@ -810,32 +819,39 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"liên kết với dịch vụ nhắn tin của nhà cung cấp dịch vụ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"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ụ nhắn tin của nhà cung cấp dịch vụ. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kiểm soát độ dài và ký tự được phép trong mật khẩu khóa màn hình và mã PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Theo dõi số lần nhập mật khẩu không chính xác khi mở khóa màn hình và khóa máy tính bảng hoặc xóa tất cả dữ liệu của máy tính bảng nếu có quá nhiều lần nhập mật khẩu không chính xác."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Giám sát số lượng mật khẩu đã nhập sai khi mở khóa màn hình và khóa TV hoặc xóa tất cả dữ liệu của TV nếu có quá nhiều mật khẩu sai được nhập vào."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Theo dõi số lần nhập mật khẩu không chính xác khi mở khóa màn hình và khóa điện thoại hoặc xóa tất cả dữ liệu của điện thoại nếu có quá nhiều lần nhập mật khẩu không chính xác."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Thay đổi mật khẩu mở khóa màn hình"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Thay đổi mật khẩu mở khóa màn hình."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Giám sát số lần nhập sai mật khẩu khi mở khóa màn hình và khóa máy tính bảng hoặc xóa tất cả dữ liệu của người dùng này nếu nhập sai mật khẩu quá nhiều lần."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Giám sát số lần nhập sai mật khẩu khi mở khóa màn hình và khóa TV hoặc xóa tất cả dữ liệu của người dùng này nếu nhập sai mật khẩu quá nhiều lần."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Giám sát số lần nhập sai mật khẩu khi mở khóa màn hình và khóa điện thoại hoặc xóa tất cả dữ liệu của người dùng này nếu nhập sai mật khẩu quá nhiều lần."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Thay đổi khóa màn hình"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Thay đổi khóa màn hình."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Khóa màn hình"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Kiểm soát cách và thời điểm khóa màn hình."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Xóa tất cả dữ liệu"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Xóa dữ liệu trên máy tính bảng mà không cần cảnh báo, bằng cách thực hiện thiết lập lại dữ liệu ban đầu."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Xóa dữ liệu trên TV mà không cần cảnh báo bằng cách thực hiện thiết lập lại dữ liệu ban đầu."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Xóa dữ liệu trên điện thoại mà không cần cảnh báo, bằng cách thiết lập lại dữ liệu ban đầu."</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Xóa dữ liệu người dùng"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Xóa dữ liệu của người dùng trên máy tính bảng này mà không cảnh báo."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Xóa dữ liệu của người dùng trên TV này mà không cảnh báo."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Xóa dữ liệu của người dùng trên điện thoại này mà không cảnh báo."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Đặt proxy chung của điện thoại"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Đặt proxy chung của điện thoại được sử dụng trong khi chính sách được bật. Chỉ quản trị viên đầu tiên của điện thoại mới có thể đặt proxy chung hiệu quả."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu khóa màn hình"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Kiểm soát tần suất bắt buộc phải thay đổi mật khẩu khóa màn hình."</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Đặt proxy chung của thiết bị được sử dụng trong khi chính sách bật. Chỉ chủ sở hữu thiết bị mới có thể đặt proxy chung."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Đặt thời hạn MK khóa màn hình"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Thay đổi tần suất phải thay đổi mật khẩu khóa màn hình, mã PIN hoặc mẫu."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Đặt mã hóa dung lượng lưu trữ"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Yêu cầu dữ liệu ứng dụng được lưu trữ phải được mã hóa."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Vô hiệu hóa máy ảnh"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Ngăn sử dụng tất cả máy ảnh của thiết bị."</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Tắt tính năng trong chế độ bảo vệ phím"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Ngăn sử dụng một số tính năng trong chế độ bảo vệ phím."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Tắt tính năng của khóa m.hình"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Ngăn sử dụng một số tính năng của khóa màn hình."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Nhà riêng"</item>
-    <item msgid="869923650527136615">"ĐT di động"</item>
+    <item msgid="869923650527136615">"Di Động"</item>
     <item msgid="7897544654242874543">"Cơ quan"</item>
     <item msgid="1103601433382158155">"Số fax Cơ quan"</item>
     <item msgid="1735177144948329370">"Số fax Nhà riêng"</item>
@@ -878,7 +894,7 @@
   </string-array>
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Tùy chỉnh"</string>
     <string name="phoneTypeHome" msgid="2570923463033985887">"Nhà riêng"</string>
-    <string name="phoneTypeMobile" msgid="6501463557754751037">"ĐT di động"</string>
+    <string name="phoneTypeMobile" msgid="6501463557754751037">"Di Động"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"Cơ quan"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Số fax Cơ quan"</string>
     <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Số fax Nhà riêng"</string>
@@ -905,7 +921,7 @@
     <string name="emailTypeHome" msgid="449227236140433919">"Nhà riêng"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Cơ quan"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Khác"</string>
-    <string name="emailTypeMobile" msgid="119919005321166205">"ĐT di động"</string>
+    <string name="emailTypeMobile" msgid="119919005321166205">"Di Động"</string>
     <string name="postalTypeCustom" msgid="8903206903060479902">"Tùy chỉnh"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"Nhà riêng"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Cơ quan"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> muốn bật Khám phá bằng cách chạm. Khi Khám phá bằng cách chạm được bật, bạn có thể nghe hoặc xem mô tả dưới ngón tay bạn hoặc thực hiện cử chỉ để tương tác với điện thoại."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 tháng trước"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Trước 1 tháng trước"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 giây trước"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 phút trước"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 giờ trước"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ngày qua</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ngày qua</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Tháng trước"</string>
     <string name="older" msgid="5211975022815554840">"Cũ hơn"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"hôm qua"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"trong 1 giây"</item>
-    <item quantity="other" msgid="1241926116443974687">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"trong 1 phút"</item>
-    <item quantity="other" msgid="3330713936399448749">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"trong 1 giờ"</item>
-    <item quantity="other" msgid="547290677353727389">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"ngày mai"</item>
-    <item quantity="other" msgid="5109449375100953247">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 giây trước"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> giây trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 phút trước"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> phút trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 giờ trước"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> giờ trước"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"hôm qua"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> ngày trước"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"trong 1 giây"</item>
-    <item quantity="other" msgid="5495880108825805108">"trong <xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"trong 1 phút"</item>
-    <item quantity="other" msgid="4216113292706568726">"trong <xliff:g id="COUNT">%d</xliff:g> phút"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"trong 1 giờ"</item>
-    <item quantity="other" msgid="3705373766798013406">"trong <xliff:g id="COUNT">%d</xliff:g> giờ"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"ngày mai"</item>
-    <item quantity="other" msgid="2973062968038355991">"trong <xliff:g id="COUNT">%d</xliff:g> ngày"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"vào <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"trong <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"tuần"</string>
     <string name="year" msgid="4001118221013892076">"năm"</string>
     <string name="years" msgid="6881577717993213522">"năm"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 giây"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 phút"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> phút"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 giờ"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> giờ"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> giây</item>
+      <item quantity="one">1 giây</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> phút</item>
+      <item quantity="one">1 phút</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> giờ</item>
+      <item quantity="one">1 giờ</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Sự cố video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Video này không hợp lệ để phát trực tuyến đến thiết bị này."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Không thể phát video này."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android đang khởi động..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Tối ưu hóa lưu trữ."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Đang tối ưu hóa ứng dụng <xliff:g id="NUMBER_0">%1$d</xliff:g> trong tổng số <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Đang chuẩn bị <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Khởi động ứng dụng."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Hoàn tất khởi động."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> đang hoạt động"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Không khởi động ứng dụng mới."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Bắt đầu <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Dừng ứng dụng cũ mà không lưu."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Chọn một tác vụ cho văn bản"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Âm lượng chuông"</string>
     <string name="volume_music" msgid="5421651157138628171">"Âm lượng phương tiện"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Không"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Nhạc chuông"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nhạc chuông không xác định"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Mạng Wi-Fi khả dụng"</item>
-    <item quantity="other" msgid="4192424489168397386">"Mạng Wi-Fi khả dụng"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Mở mạng Wi-Fi khả dụng"</item>
-    <item quantity="other" msgid="7915895323644292768">"Mở mạng Wi-Fi khả dụng"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">Các mạng Wi-Fi khả dụng</item>
+      <item quantity="one">Mạng Wi-Fi khả dụng</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">Mở các mạng Wi-Fi khả dụng</item>
+      <item quantity="one">Mở mạng Wi-Fi khả dụng</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Đăng nhập vào mạng Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Đăng nhập vào mạng"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Ứng dụng %1$s muốn kết nối với Mạng Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ứng dụng"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Không thể khởi động Wi-Fi Direct."</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Được kết nối là thiết bị truyền thông"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Được kết nối là máy ảnh"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Đã kết nối dưới dạng thiết bị MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Được kết nối như trình cài đặt"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Đã kết nối với phụ kiện USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Chạm để có các tùy chọn USB khác."</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Bỏ qua"</string>
     <string name="no_matches" msgid="8129421908915840737">"Không có kết quả nào phù hợp"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Tìm kiếm trên trang"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 kết quả phù hợp"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> trong tổng số <xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> trong số <xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="one">1 trận đấu</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Xong"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Đang ngắt kết nối bộ lưu trữ USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Đang ngắt kết nối thẻ SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Tạo mã PIN để hạn chế sửa đổi"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Mã PIN không khớp. Hãy thử lại."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Mã PIN quá ngắn. Phải có ít nhất 4 chữ số."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Hãy thử lại sau 1 giây"</item>
-    <item quantity="other" msgid="4730868920742952817">"Hãy thử lại sau <xliff:g id="COUNT">%d</xliff:g> giây"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">Hãy thử lại sau <xliff:g id="COUNT">%d</xliff:g> giây</item>
+      <item quantity="one">Hãy thử lại sau 1 giây</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Hãy thử lại sau"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Vuốt từ trên xuống để thoát toàn màn hình."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Xem toàn màn hình"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Để thoát, hãy vuốt xuống từ trên cùng."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Xong"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Thanh trượt giờ hình tròn"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Thanh trượt phút hình tròn"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Để bỏ khóa màn hình này, chạm và giữ Quay lại và Tổng quan cùng lúc."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Để bỏ khóa màn hình này, chạm và giữ Tổng quan."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Màn hình đã được ghim. Tổ chức của bạn không cho phép bỏ ghim."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Đã bỏ ghim màn hình"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Cho tới khi thời gian ngừng hoạt động của bạn kết thúc vào <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Cho đến khi thời gian ngừng hoạt động kết thúc"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Trong một phút (cho đến <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Trong %1$d phút (cho đến <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Trong một giờ (cho đến <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Trong %1$d giờ (cho đến <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <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>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Trong một giờ"</item>
-    <item quantity="other" msgid="5408537517529822157">"Trong %d giờ"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">Trong %1$d phút (cho đến <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Trong một phút (cho đến <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">Trong %1$d giờ (cho đến <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">Trong một giờ (cho đến <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">Trong %d phút</item>
+      <item quantity="one">Trong một phút</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">Trong %d giờ</item>
+      <item quantity="one">Trong một giờ</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Cho đến <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Không giới hạn"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Thu gọn"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Cho đến lần báo thức tiếp theo vào <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Cho đến lần báo thức tiếp theo"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Yêu cầu SS được sửa đổi thành yêu cầu DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Yêu cầu SS được sửa đổi thành yêu cầu USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Yêu cầu SS được sửa đổi thành yêu cầu SS mới."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Cổng ngoại vi USB"</string>
 </resources>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 3eede32..745aa73 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -23,7 +23,7 @@
 
     <!-- Only show settings item due to smaller real estate. -->
     <string-array translatable="false" name="config_globalActionsList">
-        <item>settings</item>
+        <item>voiceassist</item>
     </string-array>
 
     <!-- Base "touch slop" value used by ViewConfiguration as a
@@ -43,4 +43,12 @@
     <!-- Flags enabling default window features. See Window.java -->
     <bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
     <bool name="config_defaultWindowFeatureContextMenu">false</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">25</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.1</item>
 </resources>
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
new file mode 100644
index 0000000..4ea2b52
--- /dev/null
+++ b/core/res/res/values-watch/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- [CHAR LIMIT=16] Message shown in upgrading dialog for each .apk that is optimized. -->
+    <!-- Each word has an 8 character limit due to screen width limitation. -->
+    <string name="android_upgrading_apk">App
+        <xliff:g id="number" example="123">%1$d</xliff:g> of
+        <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+</resources>
diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
index b83f412..b3f009e 100755
--- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
     <string name="time_of_day">%p %I:%M:%S</string>
     <string name="date_and_time">%Y 年 %-m 月 %-e 日%p %I:%M:%S</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 24ec7ce..7a9da40 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;未命名&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(无电话号码)"</string>
     <string name="unknownName" msgid="6867811765370350269">"未知"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"语音信箱"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"已对SIM卡进行PUK码锁定。请输入PUK码将其解锁。"</string>
     <string name="needPuk2" msgid="4526033371987193070">"输入PUK2码以解锁SIM卡。"</string>
     <string name="enablePin" msgid="209412020907207950">"失败,请开启SIM/RUIM卡锁定设置。"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item>
-    <item quantity="other" msgid="7530597808358774740">"您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将被锁定。"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">您还可尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。如果仍不正确,SIM 卡将被锁定。</item>
+      <item quantity="one">您还可尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,SIM 卡将被锁定。</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"来电显示"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"绑定到路由程序服务"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允许应用绑定到任何已注册的路由程序。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许应用向设备管理器发送Intent。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"绑定至电视输入设备"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"允许应用与近距离无线通信(NFC)标签、卡和读取器通信。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"停用屏幕锁定"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"允许该应用停用键锁以及任何关联的密码安全措施。例如,让手机在接听来电时停用键锁,在通话结束后重新启用键锁。"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"管理指纹硬件"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允许该应用调用方法来添加和删除可用的指纹模板。"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指纹硬件"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允许该应用使用指纹硬件进行身份验证"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐户的同步设置。例如,此权限可确定“联系人”应用是否与某个帐户同步。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"启用和停用同步"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"绑定到选择器目标服务"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允许该应用绑定到选择器目标服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"绑定至媒体转接服务"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"允许应用绑定至媒体转接服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"绑定到互动屏保服务"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"允许应用绑定到互动屏保服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"绑定到运营商消息传递服务"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允许应用绑定到运营商消息传递服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制锁屏密码和 PIN 码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"监视在解锁屏幕时输错密码的次数,如果输错次数过多,则锁定平板电脑或清除其所有数据。"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定电视或清除电视上的所有数据。"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"监视在解锁屏幕时输错密码的次数,如果输错次数过多,则锁定手机或清除其所有数据。"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"更改屏幕解锁密码"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"更改屏幕解锁密码。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定平板电脑或清空此用户的所有数据。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定电视或清空此用户的所有数据。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定手机或清空此用户的所有数据。"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"更改锁屏密码"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"更改锁屏密码。"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"锁定屏幕"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"控制屏幕锁定的方式和时间。"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"清除所有数据"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"恢复出厂设置时,系统会在不发出警告的情况下清除平板电脑上的数据。"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"恢复出厂设置时,不发出警告就直接清除电视上的数据。"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"恢复出厂设置时,系统会在不发出警告的情况下清除手机上的数据。"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"清空用户数据"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"清空此用户在这台平板电脑上的数据,而不事先发出警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"清空此用户在这台电视上的数据,而不事先发出警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"清空此用户在这部手机上的数据,而不事先发出警告。"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"设置设备全局代理"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用规范的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"设置锁定屏幕密码的有效期"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"控制系统强制用户更改屏幕锁定密码的频率。"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"设置在规范启用时要使用的设备全局代理。只有设备所有者才能设置全局代理。"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"设置锁屏密码的有效期"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"调整系统强制用户更改锁屏密码、PIN 码或解锁图案的频率。"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"设置存储设备加密"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"要求对存储的应用数据进行加密。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"停用相机"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有设备摄像头。"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"锁屏时禁用某些功能"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"锁屏时禁止使用某些功能。"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"停用锁屏功能"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"禁止使用锁屏的部分功能。"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住宅"</item>
     <item msgid="869923650527136615">"手机"</item>
@@ -968,7 +984,7 @@
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"重试"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"重试"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有SIM卡"</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"没有 SIM 卡"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"平板电脑中没有SIM卡。"</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"电视中没有 SIM 卡。"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"手机中无SIM卡"</string>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g>想要启用“触摸浏览”。“触摸浏览”启用后,您可以听到或看到所触摸内容的说明,还可以通过手势操作与手机互动。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 个月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 个月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1分钟前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1小时前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"过去<xliff:g id="COUNT">%d</xliff:g>天"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">过去 <xliff:g id="COUNT_1">%d</xliff:g> 天</item>
+      <item quantity="one">过去 <xliff:g id="COUNT_0">%d</xliff:g> 天</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"上个月"</string>
     <string name="older" msgid="5211975022815554840">"往前"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1秒后"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1分钟后"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1小时后"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1分钟前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g>分钟前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1小时前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g>小时前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g>天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1秒后"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g>秒后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1分钟后"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g>分钟后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1小时后"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g>小时后"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"日期:<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"年份:<xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"周"</string>
     <string name="year" msgid="4001118221013892076">"年"</string>
     <string name="years" msgid="6881577717993213522">"年"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1秒"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g>秒"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1分钟"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g>分钟"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1小时"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g>小时"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 秒</item>
+      <item quantity="one">1 秒</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 分钟</item>
+      <item quantity="one">1 分钟</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 小时</item>
+      <item quantity="one">1 小时</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"视频问题"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"抱歉,该视频不适合在此设备上播放。"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"无法播放此视频。"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在启动…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在优化存储空间。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在优化第<xliff:g id="NUMBER_0">%1$d</xliff:g>个应用(共<xliff:g id="NUMBER_1">%2$d</xliff:g>个)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在准备升级<xliff:g id="APPNAME">%1$s</xliff:g>。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在启动应用。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"即将完成启动。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g>正在运行"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"不启动新的应用。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"启动<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止旧的应用,但不保存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"选择要对文字执行的操作"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"铃声音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒体音量"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"无"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"铃声"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"未知铃声"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"有可用的WLAN网络"</item>
-    <item quantity="other" msgid="4192424489168397386">"有可用的WLAN网络"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"打开可用的WLAN网络"</item>
-    <item quantity="other" msgid="7915895323644292768">"打开可用的WLAN网络"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">有可用的 WLAN 网络</item>
+      <item quantity="one">有可用的 WLAN 网络</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">有可用的开放 WLAN 网络</item>
+      <item quantity="one">有可用的开放 WLAN 网络</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"登录到WLAN网络"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"登录网络"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"“%1$s”应用想要连接到 WLAN 网络“%2$s”"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"一款应用"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN直连"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动WLAN直连。此操作将会关闭WLAN客户端/热点。"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动WLAN直连。"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"已作为媒体设备连接"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"作为相机连接"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"已作为 MIDI 设备连接"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"作为安装程序连接"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已连接到USB配件"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"触摸可显示其他USB选项。"</string>
@@ -1460,9 +1426,9 @@
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"允许应用调用默认的容器服务,以便复制内容。普通应用不应使用此权限。"</string>
     <string name="permlab_route_media_output" msgid="1642024455750414694">"更改媒体输出线路"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"允许该应用将媒体输出线路更改到其他外部设备。"</string>
-    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"访问密钥保护安全存储空间"</string>
+    <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"访问锁屏安全存储空间"</string>
     <string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允许应用访问密钥保护安全存储空间。"</string>
-    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制是显示还是隐藏锁屏"</string>
+    <string name="permlab_control_keyguard" msgid="172195184207828387">"控制锁屏界面的显示和隐藏状态"</string>
     <string name="permdesc_control_keyguard" msgid="3043732290518629061">"允许应用控制锁屏。"</string>
     <string name="permlab_trust_listener" msgid="1765718054003704476">"检测信任状态的变化。"</string>
     <string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"跳过"</string>
     <string name="no_matches" msgid="8129421908915840737">"无匹配项"</string>
     <string name="find_on_page" msgid="1946799233822820384">"在网页上查找"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 个匹配项"</item>
-    <item quantity="other" msgid="4641872797067609177">"第 <xliff:g id="INDEX">%d</xliff:g> 项,共 <xliff:g id="TOTAL">%d</xliff:g> 项"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other">第 <xliff:g id="INDEX">%d</xliff:g> 条结果(共 <xliff:g id="TOTAL">%d</xliff:g> 条)</item>
+      <item quantity="one">1 条结果</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"完成"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"正在卸载USB存储设备..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"正在卸载SD卡..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"设置PIN码,防止他人修改限制条件"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN码不符,请重试。"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN码太短,至少应包含4位数字。"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1秒后重试"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g>秒后重试"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 秒后重试</item>
+      <item quantity="one">1 秒后重试</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍后重试"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"从顶部向下滑动即可退出全屏模式。"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"正在全屏模式下查看"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"要退出,请从顶部向下滑动。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小时转盘"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分钟转盘"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"要取消固定此屏幕,请同时触摸并按住“返回”和“概览”按钮。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"要取消固定此屏幕,请触摸并按住概览按钮。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"屏幕处于固定状态。您所属的单位不允许取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定屏幕"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定屏幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到休息时间结束(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"到休息时间结束"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1 分钟(到<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d 分钟(到<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1 小时(到<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d 小时(到<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1分钟"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d分钟"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1小时"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d小时"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">%1$d 分钟(到<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">1 分钟(到<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">%1$d 小时(到<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">1 小时(到<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">%d 分钟</item>
+      <item quantity="one">1 分钟</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">%d 小时</item>
+      <item quantity="one">1 小时</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"无限期"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"直到您将其关闭"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"收起"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"到下次闹钟时间(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"到下次闹钟时间"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 请求已修改为 DIAL 请求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 请求已修改为 USSD 请求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 请求已修改为新的 SS 请求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 外设端口"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a0bcaa4..2f6f3fe 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;未命名&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(沒有電話號碼)"</string>
     <string name="unknownName" msgid="6867811765370350269">"不明"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"留言信箱"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"您的 SIM 卡已鎖定 PUK,請輸入 PUK 碼以解除鎖定。"</string>
     <string name="needPuk2" msgid="4526033371987193070">"輸入 PUK2 為 SIM 卡解除封鎖。"</string>
     <string name="enablePin" msgid="209412020907207950">"操作失敗,請啟用「SIM/RUIM 鎖定」。"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 將會被鎖定。"</item>
-    <item quantity="other" msgid="7530597808358774740">"您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 將會被鎖定。"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 卡將會被鎖定。</item>
+      <item quantity="one">您還有 <xliff:g id="NUMBER_0">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 卡將會被鎖定。</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"來電顯示"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛行模式為 [關閉]"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商,但一般應用程式並不需要使用。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"允許應用程式使用近距離無線通訊 (NFC) 標記、卡片及讀取程式進行通訊。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"停用螢幕上鎖"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"允許應用程式停用按鍵鎖定以及其他相關的密碼安全措施。例如:手機收到來電時停用按鍵鎖定,通話結束後重新啟用按鍵鎖定。"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"管理指紋硬件"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允許應用程式調用加入和刪除指紋模板的方法以供使用。"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指紋硬件"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允許應用程式使用指紋硬件驗證"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"開啟和關閉同步功能"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"繫結至所選服務"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至所選服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件供應商服務"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件供應商服務的頂層介面,但一般應用程式並不需要使用。"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"允許應用程式繫結至媒體轉送服務的頂層介面,但一般應用程式並不需要使用。"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"繫結至 Dream 服務"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"允許應用程式繫結至 Dream 服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"調用流動網絡供應商提供的設定應用程式"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"繫結至流動網絡供應商短訊服務"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式繫結至流動網絡供應商短訊服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制螢幕鎖定密碼和 PIN 所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監控螢幕解鎖嘗試次數"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"監視為螢幕解鎖時輸入錯誤密碼的次數;如果輸入錯誤密碼的次數過多,則會鎖定平板電腦或清除平板電腦的所有資料。"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"監察螢幕解鎖時錯誤輸入密碼的次數,如果錯誤輸入密碼的次數過多,即鎖定電視或清除電視中的所有資料。"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"監視為螢幕解鎖時輸入錯誤密碼的次數,如果輸入錯誤密碼的次數過多,則會鎖定手機或清除手機的所有資料。"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"更改螢幕解鎖密碼"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"更改螢幕解鎖密碼。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"監察螢幕解鎖時錯誤輸入密碼的次數,如果錯誤輸入密碼的次數過多,即鎖定平板電腦或清除這個使用者的資料。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"監察螢幕解鎖時錯誤輸入密碼的次數,如果錯誤輸入密碼的次數過多,即鎖定電視或清除這個使用者的資料。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"監察螢幕解鎖時錯誤輸入密碼的次數,如果錯誤輸入密碼的次數過多,即鎖定手機或清除這個使用者的資料。"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"變更螢幕鎖定"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"變更螢幕鎖定。"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"鎖定螢幕"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"控制鎖定螢幕的方式和時間。"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"清除所有資料"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"重設平板電腦為原廠設定,在不提出警告的情況下直接清除平板電腦的資料。"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"重設電視為原廠設定,在不提出警告的情況下直接清除電視的資料。"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"重設手機為原廠設定,在不提出警告的情況下直接清除手機的資料。"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"清除使用者資料"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"清除這個使用者在這部平板電腦上的資料而不作警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"清除這個使用者在這部電視上的資料而不作警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"清除這個使用者在這部手機上的資料而不作警告。"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置的全域代理伺服器"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域代理伺服器,只有第一個裝置管理員所設定的全域代理伺服器具有效力。"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"控制螢幕上鎖密碼的更改頻率。"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"設定政策啟用時所要使用的裝置全域代理伺服器,只有裝置擁有者可以設定全域代理伺服器。"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"設定螢幕鎖定密碼期限"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"變更螢幕鎖定密碼、PIN 或圖案的更改頻率。"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料加密。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"停用相機"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有裝置相機。"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"停用鍵盤保護框上的功能"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"禁止使用鍵盤保護框上的部分功能。"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"停用螢幕鎖定的功能"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"禁止使用螢幕鎖定的部分功能。"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住宅"</item>
     <item msgid="869923650527136615">"手機"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 秒前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 分鐘前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 小時前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">最近 <xliff:g id="COUNT_1">%d</xliff:g> 天</item>
+      <item quantity="one">最後 <xliff:g id="COUNT_0">%d</xliff:g> 天</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"上個月"</string>
     <string name="older" msgid="5211975022815554840">"較舊"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 秒後"</item>
-    <item quantity="other" msgid="1241926116443974687">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 分鐘後"</item>
-    <item quantity="other" msgid="3330713936399448749">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 小時後"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 秒前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 分鐘前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 小時前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 秒後"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 分鐘後"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 小時後"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時後"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天後"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"在 <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"星期"</string>
     <string name="year" msgid="4001118221013892076">"YEAR"</string>
     <string name="years" msgid="6881577717993213522">"年"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 秒"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> 秒"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 分鐘"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> 分鐘"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 小時"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> 小時"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 秒</item>
+      <item quantity="one">1 秒</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 分鐘</item>
+      <item quantity="one">1 分鐘</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 小時</item>
+      <item quantity="one">1 小時</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"影片問題"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"這部影片的格式無效,無法以串流傳送至這部裝置。"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"無法播放這部影片。"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在啟動…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在優化儲存空間。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在優化第 <xliff:g id="NUMBER_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="NUMBER_1">%2$d</xliff:g> 個)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在準備 <xliff:g id="APPNAME">%1$s</xliff:g>。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"正在執行 <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式,且不儲存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"選擇處理文字的操作"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"無"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"不明鈴聲"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"有 Wi-Fi 網絡可以連接"</item>
-    <item quantity="other" msgid="4192424489168397386">"有 Wi-Fi 網絡可以連接"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"有公開的 Wi-Fi 網絡可以連接"</item>
-    <item quantity="other" msgid="7915895323644292768">"有公開的 Wi-Fi 網絡可以連接"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">有可用的 Wi-Fi 網絡</item>
+      <item quantity="one">有可用的 Wi-Fi 網絡</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">有可用的公開 Wi-Fi 網絡</item>
+      <item quantity="one">有可用的公開 Wi-Fi 網絡</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"登入 Wi-Fi 網絡"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"登入網絡"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互聯網連線欠佳。"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"應用程式 %1$s 要求連線至 WiFi 網絡 %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct,這會關閉 Wi-Fi 使用者端/熱點。"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 Wi-Fi Direct。"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"已作為媒體裝置連線"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"已作為相機連線"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"已連接為 MIDI 裝置"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"已作為安裝程式連線"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已連接到一個 USB 配件"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"輕觸即可顯示其他 USB 選項。"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"略過"</string>
     <string name="no_matches" msgid="8129421908915840737">"沒有相符的結果"</string>
     <string name="find_on_page" msgid="1946799233822820384">"在頁面中尋找"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 個相符項目"</item>
-    <item quantity="other" msgid="4641872797067609177">"第 <xliff:g id="INDEX">%d</xliff:g> 個,共 <xliff:g id="TOTAL">%d</xliff:g> 個"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other"><xliff:g id="TOTAL">%d</xliff:g> 個相符項目的第 <xliff:g id="INDEX">%d</xliff:g> 個</item>
+      <item quantity="one">1 個相符項目</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"完成"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"正在卸載 USB 儲存裝置..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"正在卸載 SD 記憶卡..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"建立修改限制所需的 PIN 碼"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN 碼不符,請再試一次。"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN 碼太短,至少必須為 4 位數。"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 秒後再試一次"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> 秒後再試一次"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 秒後再試一次</item>
+      <item quantity="one">1 秒後再試一次</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"由頂端往下快速滑動即可離開全螢幕。"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"開啟全螢幕"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"由上往下刷退出。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小時環形滑桿"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分鐘環形滑桿"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住 [返回] 和 [概覽]。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住 [概覽]。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,而您的機構不允許取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"節約電池用量模式有助於延長電池壽命,但這會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。除非您啟用,否則電郵、短訊及其他需要使用同步功能的應用程式均不會更新。\n\n當裝置充電時,節約電池用量模式會自動關閉。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到停機時間於 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 結束"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"直到停機時間完結"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"需時 1 分鐘 (完成時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"需時 %1$d 分鐘 (完成時間 <xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"需時 1 小時 (完成時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"需時 %1$d 小時 (完成時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">需時 %1$d 分鐘 (完成時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">需時 1 分鐘 (完成時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">需時 %1$d 小時 (完成時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">需時 1 小時 (完成時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">需時 %d 分鐘</item>
+      <item quantity="one">需時 1 分鐘</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">需時 %d 小時</item>
+      <item quantity="one">需時 1 小時</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"完成時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"無限期"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"收合"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"直到下一個在 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 的鬧鐘"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"直到下一個鬧鐘"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已修改為 DIAL 要求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已修改為 USSD 要求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已修改為新的 SS 要求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 外端連接埠"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
index 0a19896..3e2b33d 100755
--- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml
+++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%Y 年 %-m 月 %-e 日</string>
     <string name="time_of_day">%p %I:%M:%S</string>
     <string name="date_and_time">%Y/%-m/%-e %p %I:%M:%S</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c27c101..35421ae 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;未命名&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"…"</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(沒有電話號碼)"</string>
     <string name="unknownName" msgid="6867811765370350269">"不明"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"語音留言"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"SIM 卡的 PUK 已鎖定。請輸入 PUK 碼解除鎖定。"</string>
     <string name="needPuk2" msgid="4526033371987193070">"請輸入 PUK2 以解鎖 SIM 卡。"</string>
     <string name="enablePin" msgid="209412020907207950">"操作失敗,請啟用 SIM/RUIM 鎖定。"</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。如果仍然失敗,SIM 卡將被鎖住。"</item>
-    <item quantity="other" msgid="7530597808358774740">"您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。如果仍然失敗,SIM 卡將被鎖住。"</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="other">您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。如果仍然失敗,SIM 卡將被鎖定。</item>
+      <item quantity="one">您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,SIM 卡將被鎖定。</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"來電顯示"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -431,6 +430,8 @@
     <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"允許應用程式與近距離無線通訊 (NFC) 電子感應標籤、卡片及感應器進行通訊。"</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"停用螢幕鎖定"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"允許應用程式停用按鍵鎖定以及其他相關的密碼安全性功能。例如:手機收到來電時停用按鍵鎖定,通話結束後重新啟用按鍵鎖定。"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"管理指紋硬體"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"允許應用程式呼叫方法來新增及移除可用的指紋範本"</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"使用指紋硬體"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"允許應用程式使用指紋硬體進行驗證"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"開啟及關閉同步功能"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"與選擇器目標服務繫結"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"允許應用程式繫結至選擇器目標服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件提供者服務"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件提供者服務的頂層介面 (一般應用程式並不需要)。"</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"繫結至媒體轉送服務"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"允許應用程式繫結至媒體轉送服務的頂層介面 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"繫結至 Dream 服務"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"允許應用程式繫結至 Dream 服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"叫用行動通訊業者提供的設定應用程式"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"與行動通訊業者簡訊服務繫結"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式與行動通訊業者簡訊服務的頂層介面繫結 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"管理螢幕鎖定密碼和 PIN 碼支援的字元和長度上限。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"監控螢幕解鎖時密碼輸入錯誤的次數;如果密碼輸入錯誤的次數過多,則會鎖住平板電腦或全部清除平板電腦中的資料。"</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"螢幕鎖定時監測密碼輸入錯誤次數,並於密碼輸入錯誤次數過多時鎖定電視,或是將電視的資料全部清除。"</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"監控螢幕解鎖時密碼輸入錯誤的次數;如果密碼輸入錯誤的次數過多,則會鎖住手機或清除手機的所有資料。"</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"變更螢幕解鎖密碼"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"變更螢幕解鎖密碼。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"監控螢幕解鎖密碼輸入錯誤的次數;如果輸入錯誤的次數超過上限,系統會將平板電腦鎖定,或將這個使用者的資料全部清除。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"監控螢幕解鎖密碼輸入錯誤的次數;如果輸入錯誤的次數超過上限,系統會將電視鎖定,或將這個使用者的資料全部清除。"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"監控螢幕解鎖密碼輸入錯誤的次數;如果輸入錯誤的次數超過上限,系統會將手機鎖定,或將這個使用者的資料全部清除。"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"變更螢幕鎖定密碼"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"變更螢幕鎖定密碼。"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"鎖定螢幕"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"控制鎖定螢幕的方式和時間。"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"清除所有資料"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"恢復原廠設定,不提出警告就直接清除平板電腦的資料。"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"不經警告即讓電視恢復原廠設定,藉此清除電視的資料。"</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"恢復原廠設定,不提出警告就直接清除手機的資料。"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"清除使用者資料"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"將這個使用者的資料從這台平板電腦中清除,而不事先發出警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"將這個使用者的資料從這台電視中清除,而不事先發出警告。"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"將這個使用者的資料從這支手機中清除,而不事先發出警告。"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"控制螢幕上鎖密碼的變更頻率。"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"設定政策啟用時要使用的裝置全域 Proxy。只有裝置擁有者可以設定全域 Proxy。"</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"設定螢幕鎖定密碼到期日"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"調整螢幕鎖定密碼、PIN 碼或解鎖圖形的強制變更頻率。"</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料進行加密。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"停用相機"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有裝置相機。"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"停用鍵盤保護框上的功能"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"禁止使用鍵盤保護框上的部分功能。"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"停用螢幕鎖定的功能。"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"禁止使用螢幕鎖定的部分功能。"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住家電話"</item>
     <item msgid="869923650527136615">"行動電話"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> 需要啟用「輕觸探索」。開啟這項功能時,系統會在您的手指輕觸螢幕上的物件時顯示或朗讀說明,您也可以執行手勢來與手機互動。"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"1 個月以前"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"1 個月前"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 秒以前"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 分鐘以前"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> 分鐘前"</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 小時以前"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"最近 <xliff:g id="COUNT">%d</xliff:g> 天"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="other">過去 <xliff:g id="COUNT_1">%d</xliff:g> 天內</item>
+      <item quantity="one">過去 <xliff:g id="COUNT_0">%d</xliff:g> 天內</item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"上個月"</string>
     <string name="older" msgid="5211975022815554840">"較舊"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"昨天"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"1 秒內"</item>
-    <item quantity="other" msgid="1241926116443974687">"在 <xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"1 分鐘內"</item>
-    <item quantity="other" msgid="3330713936399448749">"在 <xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"1 小時內"</item>
-    <item quantity="other" msgid="547290677353727389">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"明天"</item>
-    <item quantity="other" msgid="5109449375100953247">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 秒以前"</item>
-    <item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 分鐘以前"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 小時以前"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> 小時前"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"昨天"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"1 秒內"</item>
-    <item quantity="other" msgid="5495880108825805108">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"1 分鐘內"</item>
-    <item quantity="other" msgid="4216113292706568726">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"1 小時內"</item>
-    <item quantity="other" msgid="3705373766798013406">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"明天"</item>
-    <item quantity="other" msgid="2973062968038355991">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"於 <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"於<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"於 <xliff:g id="YEAR">%s</xliff:g> 年"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"週"</string>
     <string name="year" msgid="4001118221013892076">"年"</string>
     <string name="years" msgid="6881577717993213522">"年"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 秒"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> 秒"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 分鐘"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> 分鐘"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 小時"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> 小時"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 秒</item>
+      <item quantity="one">1 秒</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 分鐘</item>
+      <item quantity="one">1 分鐘</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> 小時</item>
+      <item quantity="one">1 小時</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"影片發生問題"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"這部影片的格式無效,因此無法在此裝置中串流播放。"</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"無法播放這部影片。"</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"Android 正在啟動…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"正在對儲存空間進行最佳化處理。"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"正在最佳化第 <xliff:g id="NUMBER_0">%1$d</xliff:g> 個應用程式 (共 <xliff:g id="NUMBER_1">%2$d</xliff:g> 個)。"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"正在準備升級「<xliff:g id="APPNAME">%1$s</xliff:g>」。"</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"正在啟動應用程式。"</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"啟動完成。"</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> 執行中"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"請勿啟動新的應用程式。"</string>
     <string name="new_app_action" msgid="5472756926945440706">"啟動 <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"停止舊的應用程式且不儲存。"</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"選取傳送文字內容的方式"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"鈴聲音量"</string>
     <string name="volume_music" msgid="5421651157138628171">"媒體音量"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"無"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"鈴聲"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"未知的鈴聲"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"已偵測到 Wi-Fi 網路"</item>
-    <item quantity="other" msgid="4192424489168397386">"已偵測到 Wi-Fi 網路"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"開啟可用 Wi-Fi 網路"</item>
-    <item quantity="other" msgid="7915895323644292768">"開啟可用 Wi-Fi 網路"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="other">有多個可用的 Wi-Fi 網路</item>
+      <item quantity="one">有一個可用的 Wi-Fi 網路</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="other">有多個可用的開放 Wi-Fi 網路</item>
+      <item quantity="one">有多個可用的開放 Wi-Fi 網路</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"登入 Wi-Fi 網路"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"登入網路"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"「%1$s」應用程式要求連線至 WiFi 網路 %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct 作業,這會關閉 Wi-Fi 用戶端/無線基地台作業。"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 Wi-Fi Direct。"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"已視為媒體裝置連線"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"已視為相機連線"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"已採用 MIDI 模式連接到電腦"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"已視為安裝程式連線"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已連接 USB 配件"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"輕觸即可顯示其他 USB 選項。"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"略過"</string>
     <string name="no_matches" msgid="8129421908915840737">"沒有相符項目"</string>
     <string name="find_on_page" msgid="1946799233822820384">"在頁面中尋找"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 個相符項目"</item>
-    <item quantity="other" msgid="4641872797067609177">"第 <xliff:g id="INDEX">%d</xliff:g> 個相符項目 (共 <xliff:g id="TOTAL">%d</xliff:g> 個相符項目)"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="other">第 <xliff:g id="INDEX">%d</xliff:g> 個相符項目 (共 <xliff:g id="TOTAL">%d</xliff:g> 個)</item>
+      <item quantity="one">1 個相符項目</item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"完成"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"正在卸載 USB 儲存裝置…"</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"正在卸載 SD 卡…"</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"建立修改限制所需的 PIN"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN 不符,請再試一次。"</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN 長度太短,至少必須為 4 位數。"</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"1 秒後再試一次"</item>
-    <item quantity="other" msgid="4730868920742952817">"<xliff:g id="COUNT">%d</xliff:g> 秒後再試一次"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="other">請於 <xliff:g id="COUNT">%d</xliff:g> 秒後再試一次</item>
+      <item quantity="one">請於 1 秒後再試一次</item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"稍後再試"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"從頂端往下滑動即可退出全螢幕模式。"</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"以全螢幕檢視"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"如要退出,請從畫面頂端向下滑動。"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"知道了"</string>
     <string name="done_label" msgid="2093726099505892398">"完成"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"小時數環狀滑桿"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"分鐘數環狀滑桿"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住返回按鈕和總覽按鈕。"</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"如要取消固定這個畫面,請輕觸並按住總覽按鈕。"</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"螢幕已固定,且貴機構不允許取消固定。"</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"已取消固定螢幕"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"節約耗電量模式會透過降低裝置效能、震動限制、定位服務限制和大多數背景資料運作限制等方式,延長電池續航力。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當您為裝置充電時,節約耗電量模式會自動關閉。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 停機時間結束"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"直到停機時間結束"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"1 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"%1$d 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"1 小時 (結束時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"%1$d 小時 (結束時間:<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
-    <item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"1 小時"</item>
-    <item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="other">持續 %1$d 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">持續 1 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="other">持續 %1$d 小時 (結束時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="one">持續 1 小時 (結束時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="other">持續 %d 分鐘</item>
+      <item quantity="one">持續 1 分鐘</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="other">持續 %d 小時</item>
+      <item quantity="one">持續 1 小時</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"結束時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"無限期"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"收合"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"直到下次鬧鐘鈴響:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"直到下次鬧鐘鈴響"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS 要求已改為 DIAL 要求。"</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS 要求已改為 USSD 要求。"</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS 要求已改為新的 SS 要求。"</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"USB 週邊連接埠"</string>
 </resources>
diff --git a/core/res/res/values-zu/donottranslate-cldr.xml b/core/res/res/values-zu/donottranslate-cldr.xml
index 087ad833..e2cf516 100755
--- a/core/res/res/values-zu/donottranslate-cldr.xml
+++ b/core/res/res/values-zu/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s-%s-%s"</string>
     <string name="month_day_year">%-e %B %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%-l:%M:%S %p %-e %b %Y</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4ef496c..98b9e73d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -40,8 +40,6 @@
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> amasekhondi"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> isekhondi"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Akunasihloko&gt;"</string>
-    <string name="ellipsis" msgid="7899829516048813237">"..."</string>
-    <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Ayikho inombolo yefoni)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Akwaziwa"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Ivoyisimeyili"</string>
@@ -63,10 +61,10 @@
     <string name="needPuk" msgid="919668385956251611">"Ikhadi lakho le-SIM livalwe nge-PUK. Thayipha ikhodi ye-PUK ukulivula."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Thayipha i-PUK2 ukuze uvule ikhadi le-SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Akuphumelelanga, nika amandla ukhiye we-SIM/RUIM."</string>
-  <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> ngaphambi kokuba i-SIM ikhiywe."</item>
-    <item quantity="other" msgid="7530597808358774740">"Unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> ngaphambi kokuba i-SIM ikhiywe."</item>
-  </plurals>
+    <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+      <item quantity="one">Unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ikhiywe.</item>
+      <item quantity="other">Unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ikhiywe.</item>
+    </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
     <string name="ClipMmi" msgid="6952821216480289285">"I-ID Yocingo Olungenayo"</string>
@@ -202,6 +200,7 @@
     <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Imodi yendiza IVULIWE"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Imodi yendiza IVALIWE"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Izilungiselelo"</string>
+    <string name="global_action_voice_assist" msgid="7751191495200504480">"Isisekeli sezwi"</string>
     <string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
@@ -431,6 +430,8 @@
     <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>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bophezela kusevisi yomhlinzeki womzila"</string>
+    <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ivumela isibambi ukubophezela kunoma yimuphi umhlinzeki womzila obhalisiwe. Akufanele kudingeke izinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindTvInput" msgid="5601264742478168987">"bophezela kokokufaka kwe-TV"</string>
@@ -737,6 +738,10 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ivuela uhlelo lokusebenza ukuthi ixhumane ne-Near Field Communication (NFC) amathegi, amakhadi kanye nezinhlelo zokufunda."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"khubaza ukukhiya kwakho iskrini"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ivumela uhlelo lokusebenza ukukhubaza ukuvala ukhiye nanoma yikuphi ukuphepha kwephasiwedi okuhlobene. Isibonelo, ifoni ikhubaza ukuvala ukhiye lapho ithola ikholi yefoni engenayo, bese inike amandla kabusha ukuvala ukhiye lapho ikholi isiqedile."</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"phatha izingxenyekazi zekhompyutha zezigxivizo zeminwe"</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Ivumela uhlelo lokusebenza ukuthi libuyisele izindlela zokungeza nokususa izifanekiso zezigxivizo zeminwe ngokusetshenziswa."</string>
+    <string name="permlab_useFingerprint" msgid="3150478619915124905">"sebenzisa izingxenyekazi zekhompyutha zezigxivizo zeminwe"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Ivumela uhlelo lokusebenza ukuthi lusebenzise izingxenyekazi zekhompyutha zezigxivizo zeminwe ukuze kuqinisekiswe"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"funda izilungiselelo zokuvumelanisa"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ivumela uhlelo lokusebenza ukufunda izilungiselelo zokuvumelanisa ze-akhawunti. Isibonelo, lokhu kungacacisa ukuthi noma ngabe uhlelo lokusebenza le-People livumelanisiwe ne-akhawunti."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"shintsha phakathi kokuvula kanye nokucisha ukuvumelanisa"</string>
@@ -791,8 +796,12 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindChooserTargetService" msgid="3443261076710185673">"bophezela isevisi eqondisiwe yesikhethi"</string>
+    <string name="permdesc_bindChooserTargetService" msgid="1413908999583734970">"Ivumela umbambi ukuthi ahlanganise kuleveli ephezulu yesevisi yesikhethi. Akudingeki kuzinhlelo zokusebenza ezimvamile."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"hlanganisa kwisevisi yomhlinzeki wesimo"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo seleveli ephezulu sesevisi yomhlinzeki wesimo. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindMediaRouteService" msgid="6637740382272686835">"hlanganisela kusevisi yomzila yemidiya"</string>
+    <string name="permdesc_bindMediaRouteService" msgid="6436655024972496687">"Ivumela umbambi ukuhlanganisa kusibonisi esiphezulu sesevisi yomzila wemidiya. Akufanele kudingeke kuzinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"bophezela kusevisi yephupho"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Ivumela isiphathi ukuthi sibophezele ukusebenzisana kwezinga eliphezulu kwesevisi yephupho. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string>
@@ -810,29 +819,36 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bophezela kusevisi yomlayezo yenkampani yenethiwekhi"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ivumela isibambi ukuhlanganisa isixhumanisi sokubona esiphezulu sesevisi yomlayezo yenkampani yenethiwekhi. Akufanele idingeke kuzinhlelo zokusebenza ezivamile."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
-    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
+    <string name="policydesc_limitPassword" msgid="2502021457917874968">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi wokukhiya isikrini nama-PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Bheka inani lamaphasiwedi angafanele athayishiwe uma kuvulwa iskrini bese kuvalwa ithebhulethi noma kususwe yonke idatha yethebhulethi uma kubhalwe amaphasiwedi amaningi angalungile."</string>
     <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Qaphela inombolo yamaphasiwedi angalungile athayiphiwe uma kuvulwa isikrini, uphinde ukhiye isikrini noma usule yonke idatha ye-TV uma ngabe kuthayiphwa amaphasiwedi amaningi angalungile."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Bheka isibalo samaphasiwedi ngalungile afakiwe uma uvula iskrini bese uvala ucingo noma ususe yonke imininingwane yocingo uma kubhalwe amaphasiwedi amaningi angalungile."</string>
-    <string name="policylab_resetPassword" msgid="2620077191242688955">"Shintsha iphasiwedi yokuvula isikrini"</string>
-    <string name="policydesc_resetPassword" msgid="605963962301904458">"Shintsha iphasiwedi yokuvula isikrini"</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Qaphela inombolo yamaphasiwedi angalungile athayiphwe uma kuvulwa isikrini, uphinde ukhiye ithebulethi noma usule yonke idatha yalo msebenzisi uma ngabe kuthayiphwe amaphasiwedi amaningi kakhulu angalungile."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Qaphela inombolo yamaphasiwedi angalungile athayiphiwe uma kuvulwa isikrini, uphinde ukhiphe i-TV noma usule yonke idatha yalo msebenzisi uma ngabe kuthayiphwe amaphasiwedi amaningi kakhulu angalungile."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Qaphela inombolo yamaphasiwedi angalungile athayiphiwe uma kuvulwa isikrini, uphinde ukhiye ifoni noma usule yonke idatha yalo msebenzisi uma ngabe kuthayiphwe amaphasiwedi amaningi kakhulu angalungile."</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"Guqula ukukhiya isikrini"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"Guqula ukukhiya isikrini."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Vala isikrini"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Lawula ukuthi isikrini sivala kanjani futhi nini"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Sula yonke idatha"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Sula idatha yethebhulethi ngaphandle kwesaziso, ngokwenza ukusetha kabusha kwemboni."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Sula idatha ye-TV ngaphandle kokuxwayisa ngokwenza ukusetha kabusha kwasekuqaleni kwedatha."</string>
     <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Sula idatha yefoni ngaphandle kwesixwayiso, ngokwenza ukuhlela kabusha idatha yemboni"</string>
+    <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Sula idatha yomsebenzisi"</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Sula idatha yalo msebenzisi kule thebulethi ngaphandle kwesexwayiso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Sula idatha yalo msebenzisi kule TV ngaphandle kwesexwayiso."</string>
+    <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Sula idatha yalo msebenzisi kule foni ngaphandle kwesexwayiso."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Misa ummelelii jikelele yedivaysi"</string>
-    <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Misa iphrokzi jikelele yedivaysi ukusebenzisa ngenkathi inqumbomgomo ivunyelwa. Idivaysi yokuqala kuphela yokuphatha emisa ummeleli jikelele esebenzayo."</string>
-    <string name="policylab_expirePassword" msgid="885279151847254056">"Hlela ukuphelelwa isikhathi sokuvala-isikrini."</string>
-    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Lawula ukuthi iphasiwedi yokuvala isikrini ishintshwa kangaki"</string>
+    <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Setha ummeleli womhlaba wonke wedivayisi ozosetshenziswa ngenkathi inqubomgomo inikwe amandla. Ngumnikazi wedivayisi kuphela ongasetha ummeleli womhlaba wonke."</string>
+    <string name="policylab_expirePassword" msgid="5610055012328825874">"Setha ukuphelelwa yisikhathi kwephasiwedi yokukhiya isikrini"</string>
+    <string name="policydesc_expirePassword" msgid="5367525762204416046">"Guqula ukuthi kumele iphasiwedi yokukhiya isikrini, i-PIN, noma iphethini kumele iguqulwe ngokuvame kangakanani."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setha umbhalo wemfihlo yesitoreji"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Idinga ukuthi idatha yohlelo lokusebenza olugciniwe ibethelwe"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Khubaza amakhamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vimbela ukusetshenziswa kwamadivaysi wonke wamakhamera"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Khubaza izici kokhiye abagadile"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Vikela ukusebenza kwezinye izici kokhiye abagadile."</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="3565888260412415862">"Khubaza izici zokukhiya isikrini"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="3980868516629887575">"Vimbela ukusetshenziswa kwezinye izici zokukhiywa kwesikrini."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Ekhaya"</item>
     <item msgid="869923650527136615">"Iselula"</item>
@@ -1128,75 +1144,12 @@
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"I-<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ifuna ukunika amandla i-Explore by Touch. Uma i-Explore by Touch ikhanya, ungezwa noma ubone izincazelo ezingaphansi komunwe wakho noma wenze izenzo zomzimba ukuze uxhumane nefoni."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"inyanga engu-1 edlule"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Ngaphambi kwenyanga engu-1 edlule"</string>
-  <plurals name="num_seconds_ago">
-    <item quantity="one" msgid="4869870056547896011">"1 isekhondi eledlule"</item>
-    <item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> amasekhondi adlule"</item>
-  </plurals>
-  <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"1 iminithi elidlule"</item>
-    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule.."</item>
-  </plurals>
-  <plurals name="num_hours_ago">
-    <item quantity="one" msgid="9150797944610821849">"1 ihora eledlule"</item>
-    <item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
-  </plurals>
-  <plurals name="last_num_days">
-    <item quantity="other" msgid="3069992808164318268">"Izinsuku zokugcina ezingu- <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+      <item quantity="one">Izinsuku zokugcina ezingu-<xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="other">Izinsuku zokugcina ezingu-<xliff:g id="COUNT_1">%d</xliff:g></item>
+    </plurals>
     <string name="last_month" msgid="3959346739979055432">"Inyanga edlule"</string>
     <string name="older" msgid="5211975022815554840">"Okudala kakhulu"</string>
-  <plurals name="num_days_ago">
-    <item quantity="one" msgid="861358534398115820">"Izolo"</item>
-    <item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
-  </plurals>
-  <plurals name="in_num_seconds">
-    <item quantity="one" msgid="2729745560954905102">"esekhondini elingu-1"</item>
-    <item quantity="other" msgid="1241926116443974687">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_minutes">
-    <item quantity="one" msgid="8793095251325200395">"eminithini engu-1"</item>
-    <item quantity="other" msgid="3330713936399448749">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_hours">
-    <item quantity="one" msgid="7164353342477769999">"ehoreni elingu-1"</item>
-    <item quantity="other" msgid="547290677353727389">"emahoreni angu- <xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="in_num_days">
-    <item quantity="one" msgid="5413088743009839518">"Kusasa"</item>
-    <item quantity="other" msgid="5109449375100953247">"ezinsukwini ezingu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_num_seconds_ago">
-    <item quantity="one" msgid="1849036840200069118">"1 isekhondi edlule"</item>
-    <item quantity="other" msgid="3699169366650930415">"amasekhondi angu-<xliff:g id="COUNT">%d</xliff:g> edlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_minutes_ago">
-    <item quantity="one" msgid="6361490147113871545">"1 iminithi eledlule"</item>
-    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_hours_ago">
-    <item quantity="one" msgid="4796212039724722116">"1 ihora eledlule"</item>
-    <item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> amahora adlule"</item>
-  </plurals>
-  <plurals name="abbrev_num_days_ago">
-    <item quantity="one" msgid="8463161711492680309">"Izolo"</item>
-    <item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> izinsuku ezedlule"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_seconds">
-    <item quantity="one" msgid="5842225370795066299">"esekhondini elingu-1"</item>
-    <item quantity="other" msgid="5495880108825805108">"emasekhondini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_minutes">
-    <item quantity="one" msgid="562786149928284878">"eminithini engu-1"</item>
-    <item quantity="other" msgid="4216113292706568726">"emaminithini angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_hours">
-    <item quantity="one" msgid="3274708118124045246">"ehoreni elingu-1"</item>
-    <item quantity="other" msgid="3705373766798013406">"emahoreni angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
-  <plurals name="abbrev_in_num_days">
-    <item quantity="one" msgid="2178576254385739855">"Kusasa"</item>
-    <item quantity="other" msgid="2973062968038355991">"ezinsukwini ezing-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"e-<xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"phakathi- <xliff:g id="YEAR">%s</xliff:g>"</string>
@@ -1212,18 +1165,18 @@
     <string name="weeks" msgid="6509623834583944518">"amaviki"</string>
     <string name="year" msgid="4001118221013892076">"unyaka"</string>
     <string name="years" msgid="6881577717993213522">"iminyaka"</string>
-  <plurals name="duration_seconds">
-    <item quantity="one" msgid="6962015528372969481">"1 isekhondi"</item>
-    <item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> amasekhondi"</item>
-  </plurals>
-  <plurals name="duration_minutes">
-    <item quantity="one" msgid="4915414002546085617">"1 iminithi"</item>
-    <item quantity="other" msgid="3165187169224908775">"<xliff:g id="COUNT">%d</xliff:g> amaminithi"</item>
-  </plurals>
-  <plurals name="duration_hours">
-    <item quantity="one" msgid="8917467491248809972">"1 ihora"</item>
-    <item quantity="other" msgid="3863962854246773930">"<xliff:g id="COUNT">%d</xliff:g> amahora"</item>
-  </plurals>
+    <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> amasekhondi</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> amasekhondi</item>
+    </plurals>
+    <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> amaminithi</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> amaminithi</item>
+    </plurals>
+    <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+      <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> amahora</item>
+      <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> amahora</item>
+    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Inkinga yevidiyo"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Uxolo, le vidiyo ayilungele ukusakaza bukhomo kwale divaysi."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Iyehluleka ukudlala levidiyo."</string>
@@ -1301,6 +1254,7 @@
     <string name="android_start_title" msgid="8418054686415318207">"I-Android iyaqala…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Ikhulisa isitoreji."</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Ukubeka ezingeni eliphezulu <xliff:g id="NUMBER_0">%1$d</xliff:g> uhlelo lokusebenza <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+    <string name="android_preparing_apk" msgid="8162599310274079154">"Ukulungisela i-<xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Qalisa izinhlelo zokusebenza."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Qedela ukuqala kabusha."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> iyasebenza"</string>
@@ -1311,6 +1265,14 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ungayiqali uhlelo lokusebenza entsha."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Qala <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Misa uhlelo lokusebenza endala ngaphandle kokulondoloza."</string>
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
     <string name="sendText" msgid="5209874571959469142">"Khetha okufanele kwenziwe okomqhafazo"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Ivolumu yesishayeli"</string>
     <string name="volume_music" msgid="5421651157138628171">"Ivolumu yemidiya"</string>
@@ -1331,20 +1293,23 @@
     <string name="ringtone_silent" msgid="7937634392408977062">"Akunalutho"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Amaringithoni"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Iringithoni engaziwa"</string>
-  <plurals name="wifi_available">
-    <item quantity="one" msgid="6654123987418168693">"Inethiwekhi ye-Wi-Fi iyatholakala"</item>
-    <item quantity="other" msgid="4192424489168397386">"Amanethiwekhi e-Wi-Fi ayatholakala"</item>
-  </plurals>
-  <plurals name="wifi_available_detailed">
-    <item quantity="one" msgid="1634101450343277345">"Vula inethiwekhi ye-Wi-Fi etholakalayo"</item>
-    <item quantity="other" msgid="7915895323644292768">"Vula amanethiwekhi we-Wi-Fi atholakalayo"</item>
-  </plurals>
+    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+      <item quantity="one">Amanethiwekhi we-Wi-Fi ayatholakala</item>
+      <item quantity="other">Amanethiwekhi we-Wi-Fi ayatholakala</item>
+    </plurals>
+    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+      <item quantity="one">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
+      <item quantity="other">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
+    </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Ngena enethiwekhini ye-Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="8495155593358054676">"Ngena ngemvume kunethiwekhi"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
+    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
+    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Uhlelo lokusebenza %1$s lungathanda ukuxhuma kunethiwekhi ye-Wifi %2$s"</string>
+    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uhlelo lokusebenza"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-Wi-Fi Eqondile"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-Wi-Fi Okuqondile. Lokhu kuzocima ikhasimende le-Wi-Fi/Ukusebenza okwe-hotspot"</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Yehlulekile ukuqala i-Wi-Fi Ngqo"</string>
@@ -1411,6 +1376,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"KULUNGILE"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ixhunyiwe njengedivayisi yemidiya"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ixhunywe njengekhamera"</string>
+    <string name="usb_midi_notification_title" msgid="1399152904227676460">"Kuxhunywe njengedivayisi ye-MIDI"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ixhunywe njengesifaki"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ixhunywe ku-accessory ye-USB"</string>
     <string name="usb_notification_message" msgid="2290859399983720271">"Cindezela ukuze ubone ezinye izinketho ze-USB"</string>
@@ -1526,10 +1492,10 @@
     <string name="skip_button_label" msgid="1275362299471631819">"Yeqa"</string>
     <string name="no_matches" msgid="8129421908915840737">"Akukho okufanayo"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Thola ekhasini"</string>
-  <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"1 okufanayo"</item>
-    <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ku-<xliff:g id="TOTAL">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+      <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> kokungu-<xliff:g id="TOTAL">%d</xliff:g></item>
+      <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> kokungu-<xliff:g id="TOTAL">%d</xliff:g></item>
+    </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Kwenziwe"</string>
     <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Iyehlisa isitoreji se-USB..."</string>
     <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Yehlisa ikhadi le-SD..."</string>
@@ -1815,12 +1781,14 @@
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"Dala i-PIN yemikhawulo yokushintsha"</string>
     <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Ama-PIN awafani. Zama futhi."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"I-PIN yimfushane kakhulu. Okungenani kumele ibe namadijithi angu-4."</string>
-  <plurals name="restr_pin_countdown">
-    <item quantity="one" msgid="311050995198548675">"Zama futhi kusekhondi elingu-1"</item>
-    <item quantity="other" msgid="4730868920742952817">"Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g>"</item>
-  </plurals>
+    <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+      <item quantity="one">Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g></item>
+      <item quantity="other">Zama futhi kumasekhondi angu-<xliff:g id="COUNT">%d</xliff:g></item>
+    </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Zama futhi emva kwesikhathi"</string>
-    <string name="immersive_mode_confirmation" msgid="7227416894979047467">"Swayiphela phansi kusukela phezulu ukuze uphume kusikrini esigcwele."</string>
+    <string name="immersive_cling_title" msgid="8394201622932303336">"Ukubuka isikrini esigcwele"</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Ngiyitholile"</string>
     <string name="done_label" msgid="2093726099505892398">"Kwenziwe"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Amahora weslayidi esiyindingilizi"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Amaminithi weslayidi esiyindingilizi"</string>
@@ -1835,7 +1803,8 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ukuze ususe ukuphina kulesi sikrini, thinta uphinde ubambe i-Emuva ne-Buka konke ngesikhathi esisodwa."</string>
     <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Ukuze ususe ukuphina lesi sikrini, thinta uphinde ubambe Buka konke."</string>
-    <string name="lock_to_app_toast_locked" msgid="8739004135132606329">"Isikrini siphiniwe. Ukususa ukuphina akuvumelekile inhlangano yakho."</string>
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
     <string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Isikrini sisuswe ukuphina"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
@@ -1844,24 +1813,24 @@
     <string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kuze kuphele isikhathi sakho ngo-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kuze kuphele isikhathi sakho sokuphumula"</string>
-  <plurals name="zen_mode_duration_minutes_summary">
-    <item quantity="one" msgid="3177683545388923234">"Okweminithi elilodwa (kuze kube ngu-<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2787867221129368935">"Okwamaminithi angu-%1$d (kuze kube ngu-<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours_summary">
-    <item quantity="one" msgid="597194865053253679">"Okwehora elilodwa (kuze kube ngu-<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-    <item quantity="other" msgid="2827214920627669898">"Ngamahora angu-%1$d (kuze kube ngu-<xliff:g id="FORMATTEDTIME">%2$s</xliff:g>)"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_minutes">
-    <item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item>
-    <item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item>
-  </plurals>
-  <plurals name="zen_mode_duration_hours">
-    <item quantity="one" msgid="3480040795582254384">"Ihora elilodwa"</item>
-    <item quantity="other" msgid="5408537517529822157">"Amahora angu-%d"</item>
-  </plurals>
+    <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+      <item quantity="one">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+      <item quantity="one">Kwamahora angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+      <item quantity="other">Kwamahora angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+    </plurals>
+    <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+      <item quantity="one">Amaminithi angu-%d</item>
+      <item quantity="other">Amaminithi angu-%d</item>
+    </plurals>
+    <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+      <item quantity="one">Amahora angu-%d</item>
+      <item quantity="other">Amahora angu-%d</item>
+    </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_forever" msgid="4316804956488785559">"Unaphakade"</string>
+    <string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Goqa"</string>
     <string name="zen_mode_next_alarm_summary" msgid="5915140424683747372">"Kuze kube yi-alamu elandelayo ngo-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_next_alarm_line_one" msgid="5537042951553420916">"Kuze kube yi-alamu elandelayo"</string>
@@ -1874,4 +1843,6 @@
     <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"Isicelo se-SS siguqulelwe kusicelo se-DIAL."</string>
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Isicelo se-SS siguqulelwe kusicelo se-USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Isicelo se-SS siguqulelwe kusicelo esisha se-SS."</string>
+    <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"I-Android"</string>
+    <string name="usb_midi_peripheral_model_name" msgid="1959288763942653301">"Imbobo ye-USB Peripheral"</string>
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f6a5787..3312f4f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -302,7 +302,6 @@
        <item>@drawable/ab_solid_shadow_material</item>
        <item>@drawable/activated_background_material</item>
        <item>@drawable/btn_borderless_material</item>
-       <item>@drawable/btn_cab_done_material</item>
        <item>@drawable/btn_check_material_anim</item>
        <item>@drawable/btn_default_material</item>
        <item>@drawable/btn_radio_material_anim</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2fd7d30..15797dd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -31,8 +31,10 @@
         <attr name="colorForeground" format="color" />
         <!-- Default color of foreground imagery on an inverted background. -->
         <attr name="colorForegroundInverse" format="color" />
-        <!-- Color that matches (as closely as possible) the window background. -->
+        <!-- Default color of background imagery, ex. full-screen windows. -->
         <attr name="colorBackground" format="color" />
+        <!-- Default color of background imagery for floating components, ex. dialogs, popups, and cards. -->
+        <attr name="colorBackgroundFloating" format="color" />
         <!-- This is a hint for a solid color that can be used for caching
              rendered views.  This should be the color of the background when
              there is a solid background color; it should be null when the
@@ -329,7 +331,9 @@
         <attr name="windowOverscan" format="boolean" />
         <!-- Flag indicating whether this is a floating window. -->
         <attr name="windowIsFloating" format="boolean" />
-        <!-- Flag indicating whether this is a translucent window. -->
+        <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
+             not if set to false), the window might still be considered translucent, if
+             windowSwipeToDismiss is set to true. -->
         <attr name="windowIsTranslucent" format="boolean" />
         <!-- Flag indicating that this window's background should be the
              user's current wallpaper.  Corresponds
@@ -455,7 +459,9 @@
         <attr name="windowTranslucentNavigation" format="boolean" />
 
         <!-- Flag to indicate that a window can be swiped away to be dismissed.
-             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
+             dynamically change translucency of the window, if the windowIsTranslucent is not set.
+             If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
         <attr name="windowSwipeToDismiss" format="boolean" />
 
         <!-- Flag indicating whether this window requests that content changes be performed
@@ -1029,6 +1035,9 @@
         <!-- The color applied to framework switch thumbs in their normal state. -->
         <attr name="colorSwitchThumbNormal" format="color" />
 
+        <!-- @hide The background used by framework controls. -->
+        <attr name="controlBackground" format="color" />
+
         <!-- The color applied to the edge effect on scrolling containers. -->
         <attr name="colorEdgeEffect" format="color" />
 
@@ -1949,6 +1958,16 @@
 
         <!-- Whether to clip window content to the outline of the window background. -->
         <attr name="windowClipToOutline" format="boolean" />
+
+        <!-- If set, the status bar will be drawn such that it is compatible with a light
+             status bar background.
+             <p>For this to take effect, the window must be drawing the system bar backgrounds with
+             {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the status bar must not
+             have been requested to be translucent with
+             {@link android.R.attr#windowTranslucentStatus}.
+             Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_STATUS_BAR} on
+             the decor view. -->
+        <attr name="windowHasLightStatusBar" format="boolean" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2206,7 +2225,7 @@
             <enum name="outsideInset" value="0x03000000" />
         </attr>
 
-        <!-- Set this if the view will serve as a scrolling container, meaing
+        <!-- Set this if the view will serve as a scrolling container, meaning
              that it can be resized to shrink its overall window so that there
              will be space for an input method.  If not set, the default
              value will be true if "scrollbars" has the vertical scrollbar
@@ -2624,6 +2643,14 @@
         <attr name="value" />
     </declare-styleable>
 
+    <!-- Attributes that can be assigned to an &lt;include&gt; tag. -->
+    <declare-styleable name="Include">
+        <attr name="id" />
+        <attr name="visibility" />
+        <attr name="layout_width" />
+        <attr name="layout_height" />
+    </declare-styleable>
+
     <!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
          of its subclasses.  Also see {@link #ViewGroup_Layout} for
          attributes that this class processes in its children. -->
@@ -2722,6 +2749,8 @@
     <!-- A {@link android.view.ViewStub} lets you lazily include other XML layouts
          inside your application at runtime. -->
     <declare-styleable name="ViewStub">
+        <!-- Supply an identifier name for this view. -->
+        <attr name="id" />
         <!-- Supply an identifier for the layout resource to inflate when the ViewStub
              becomes visible or when forced to do so. The layout resource must be a
              valid reference to a layout. -->
@@ -2950,6 +2979,24 @@
             <flag name="typeViewScrolled" value="0x000001000" />
             <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED} events. -->
             <flag name="typeViewTextSelectionChanged" value="0x000002000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT} events. -->
+            <flag name="typeAnnouncement" value="0x00004000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED} events. -->
+            <flag name="typeViewAccessibilityFocused" value="0x00008000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED} events. -->
+            <flag name="typeViewAccessibilityFocusCleared" value="0x00010000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY} events. -->
+            <flag name="typeViewTextTraversedAtMovementGranularity" value="0x00020000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START} events. -->
+            <flag name="typeGestureDetectionStart" value="0x00040000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END} events. -->
+            <flag name="typeGestureDetectionEnd" value="0x00080000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START} events. -->
+            <flag name="typeTouchInteractionStart" value="0x00100000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END} events. -->
+            <flag name="typeTouchInteractionEnd" value="0x00200000" />
+            <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED} events. -->
+            <flag name="typeWindowsChanged" value="0x00400000" />
             <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPES_ALL_MASK} i.e. all events. -->
             <flag name="typeAllMask" value="0xffffffff" />
         </attr>
@@ -4137,6 +4184,28 @@
         <attr name="drawableEnd" format="reference|color" />
         <!-- The padding between the drawables and the text. -->
         <attr name="drawablePadding" format="dimension" />
+        <!-- Tint to apply to the compound (left, top, etc.) drawables. -->
+        <attr name="drawableTint" format="color" />
+        <!-- Blending mode used to apply the compound (left, top, etc.) drawables tint. -->
+        <attr name="drawableTintMode">
+            <!-- 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>
         <!-- Extra spacing between lines of text. -->
         <attr name="lineSpacingExtra" format="dimension" />
         <!-- Extra spacing between lines of text, as a multiplier. -->
@@ -4148,6 +4217,8 @@
             <enum name="marquee_forever" value="-1" />
         </attr>
         <attr name="inputType" />
+        <!-- Whether undo should be allowed for editable text. Defaults to true. -->
+        <attr name="allowUndo" format="boolean" />
         <attr name="imeOptions" />
         <!-- An addition content type description to supply to the input
              method attached to the text view, which is private to the
@@ -4287,6 +4358,10 @@
         <attr name="popupAnimationStyle" format="reference" />
         <!-- Whether the popup window should overlap its anchor view. -->
         <attr name="overlapAnchor" format="boolean" />
+        <!-- Transition used to move views into the popup window. -->
+        <attr name="popupEnterTransition" format="reference" />
+        <!-- Transition used to move views out of the popup window. -->
+        <attr name="popupExitTransition" format="reference" />
     </declare-styleable>
     <declare-styleable name="ListPopupWindow">
         <!-- Amount of pixels by which the drop down should be offset vertically. -->
@@ -4348,6 +4423,8 @@
         </attr>
         <!-- List selector to use for spinnerMode="dropdown" display. -->
         <attr name="dropDownSelector" />
+        <!-- Theme to use for the drop-down or dialog popup window. -->
+        <attr name="popupTheme" />
         <!-- Background drawable to use for the dropdown in spinnerMode="dropdown". -->
         <attr name="popupBackground" />
         <!-- Window elevation to use for the dropdown in spinnerMode="dropdown". -->
@@ -4398,20 +4475,14 @@
         <attr name="headerYearTextAppearance" format="reference" />
         <!-- The background for the date selector. -->
         <attr name="headerBackground" />
-        <!-- @hide The selected text color for the date selector. Used as a
-             backup if the text appearance does not explicitly have a color
-             set for the selected state. -->
-        <attr name="headerSelectedTextColor" />
         <!-- The list year's text appearance in the list. -->
         <attr name="yearListItemTextAppearance" format="reference" />
         <!-- The list year's selected circle color in the list. -->
         <attr name="yearListSelectorColor" format="color" />
         <!-- The text color list of the calendar. -->
         <attr name="calendarTextColor" format="color" />
-        <!-- @hide The selected text color for the calendar. Used as a backup
-             if the text color does not explicitly have a color set for the
-             selected state. -->
-        <attr name="calendarSelectedTextColor" format="color" />
+        <!-- @hide The activated background color for the calendar. -->
+        <attr name="calendarDayBackgroundColor" format="color" />
         <!-- Defines the look of the widget. Prior to the L release, the only choice was
              spinner. As of L, with the Material theme selected, the default layout is calendar,
              but this attribute can be used to force spinner to be used instead. -->
@@ -4703,24 +4774,18 @@
         <attr name="headerAmPmTextAppearance" format="reference" />
         <!-- The text appearance for the time header. -->
         <attr name="headerTimeTextAppearance" format="reference" />
-        <!-- @hide The text color for selected time header of the TimePicker.
-             This will override the value from the text appearance if it does
-             not explicitly have a color set for the selected state. -->
-        <attr name="headerSelectedTextColor" format="color" />
         <!-- The background for the header containing the currently selected time. -->
         <attr name="headerBackground" />
         <!-- The color for the hours/minutes numbers. -->
         <attr name="numbersTextColor" format="color" />
+        <!-- The color for the inner hours numbers used in 24-hour mode. -->
+        <attr name="numbersInnerTextColor" format="color" />
         <!-- The background color for the hours/minutes numbers. -->
         <attr name="numbersBackgroundColor" format="color" />
         <!-- The color for the AM/PM selectors. -->
         <attr name="amPmTextColor" format="color" />
         <!-- The background color state list for the AM/PM selectors. -->
         <attr name="amPmBackgroundColor" format="color" />
-        <!-- @hide The background color for the AM/PM selectors of the
-             TimePicker when selected. Used if the background color does not
-             explicitly have a color set for the selected state. -->
-        <attr name="amPmSelectedBackgroundColor" format="color" />
         <!-- The color for the hours/minutes selector. -->
         <attr name="numbersSelectorColor" format="color" />
         <!-- Defines the look of the widget. Prior to the L release, the only choice was
@@ -4864,6 +4929,14 @@
         <attr name="animation"/>
     </declare-styleable>
 
+    <!-- Attributes that can be assigned to a ColorStateList item. -->
+    <declare-styleable name="ColorStateListItem">
+        <!-- Base color for this state. -->
+        <attr name="color" />
+        <!-- Alpha multiplier applied to the base color. -->
+        <attr name="alpha" />
+    </declare-styleable>
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
@@ -5015,14 +5088,31 @@
 
     <!-- Describes an item (or child) of a LayerDrawable. -->
     <declare-styleable name="LayerDrawableItem">
-        <!-- Left coordinate of the layer. -->
+        <!-- Left inset to apply to the layer. -->
         <attr name="left" />
-        <!-- Top coordinate of the layer. -->
+        <!-- Top inset to apply to the layer. -->
         <attr name="top" />
-        <!-- Right coordinate of the layer. -->
+        <!-- Right inset to apply to the layer. -->
         <attr name="right" />
-        <!-- Bottom coordinate of the layer. -->
+        <!-- Bottom inset to apply to the layer. -->
         <attr name="bottom" />
+        <!-- Start inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="start" format="dimension" />
+        <!-- End inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="end" format="dimension" />
+        <!-- Width of the layer. Defaults to the layer's intrinsic width. -->
+        <attr name="width" />
+        <!-- Height of the layer. Defaults to the layer's intrinsic height -->
+        <attr name="height" />
+        <!-- Gravity used to align the layer within its container. If no value
+             is specified, the default behavior depends on whether an explicit
+             width or height has been set, If no dimension is set, gravity in
+             that direction defaults to {@code fill_horizontal} or
+             {@code fill_vertical}; otherwise, it defaults to {@code left} or
+             {@code top}. -->
+        <attr name="gravity" />
         <!-- Drawable used to render the layer. -->
         <attr name="drawable" />
         <!-- Identifier of the layer. This can be used to retrieve the layer
@@ -5199,6 +5289,9 @@
     <declare-styleable name="RippleDrawable">
         <!-- The color to use for ripple effects. This attribute is required. -->
         <attr name="color" />
+        <!-- The radius of the ripple when fully expanded. By default, the
+             radius is computed based on the size of the ripple's container. -->
+        <attr name="radius" />
     </declare-styleable>
 
     <declare-styleable name="ScaleDrawable">
@@ -5800,19 +5893,34 @@
         <attr name="valueTo" format="float|integer|color|dimension|string"/>
         <!-- The type of valueFrom and valueTo. -->
         <attr name="valueType">
-            <!-- valueFrom and valueTo are floats. This is the default value is valueType is
-                 unspecified. Note that if either valueFrom or valueTo represent colors
+            <!-- The given values are floats. This is the default value if valueType is
+                 unspecified. Note that if any value attribute has a color value
                  (beginning with "#"), then this attribute is ignored and the color values are
                  interpreted as integers. -->
             <enum name="floatType" value="0" />
-            <!-- valueFrom and valueTo are integers. -->
+            <!-- values are integers. -->
             <enum name="intType"   value="1" />
-            <!-- valueFrom and valueTo are paths defined as strings.
+            <!-- values are paths defined as strings.
                  This type is used for path morphing in AnimatedVectorDrawable. -->
             <enum name="pathType"   value="2" />
+            <!-- values are colors, which are integers starting with "#". -->
+            <enum name="colorType"   value="3" />
         </attr>
     </declare-styleable>
 
+    <declare-styleable name="PropertyValuesHolder">
+        <attr name="valueType" />
+        <attr name="propertyName" />
+        <attr name="valueFrom" />
+        <attr name="valueTo" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyframe">
+        <attr name="valueType" />
+        <attr name="value" />
+        <attr name="fraction" format="float" />
+    </declare-styleable>
+
     <!-- ========================== -->
     <!-- ObjectAnimator class attributes -->
     <!-- ========================== -->
@@ -5889,11 +5997,11 @@
              set when a view is enabled. -->
         <attr name="state_enabled" format="boolean" />
         <!-- State identifier indicating that the object <var>may</var> display a check mark.
-             See {@link R.attr#state_checked} for the identifier that indicates whether it is
+             See {@link android.R.attr#state_checked} for the identifier that indicates whether it is
              actually checked. -->
         <attr name="state_checkable" format="boolean"/>
         <!-- State identifier indicating that the object is currently checked.  See
-             {@link R.attr#state_checkable} for an additional identifier that can indicate if
+             {@link android.R.attr#state_checkable} for an additional identifier that can indicate if
              any object may ever display a check, regardless of whether state_checked is
              currently set. -->
         <attr name="state_checked" format="boolean"/>
@@ -6343,6 +6451,33 @@
              for more info. -->
         <attr name="actionProviderClass" format="string" />
 
+        <!-- An optional tint for the item's icon.
+             See {@link android.view.MenuItem#setIconTintList(android.content.res.ColorStateList)}
+             for more info. -->
+        <attr name="iconTint" format="color" />
+
+        <!-- The blending mode used for tinting the item's icon
+             See {@link android.view.MenuItem#setIconTintMode(android.graphics.PorterDuff.Mode)}
+             for more info. -->
+        <attr name="iconTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <!-- Attrbitutes for a ActvityChooserView. -->
@@ -6960,75 +7095,16 @@
     <!-- =============================== -->
     <eat-comment />
     <declare-styleable name="GlowPadView">
-        <!-- Reference to an array resource that be shown as targets around a circle. -->
-        <attr name="targetDrawables" format="reference" />
-
-        <!-- Reference to an array resource that be used as description for the targets around the circle. -->
+        <!-- Reference to an array resource that be used as description for the targets around the circle.
+             {@deprecated Removed.} -->
         <attr name="targetDescriptions" format="reference" />
 
-        <!-- Reference to an array resource that be used to announce the directions with targets around the circle. -->
+        <!-- Reference to an array resource that be used to announce the directions with targets around the circle.
+             {@deprecated Removed.}-->
         <attr name="directionDescriptions" format="reference" />
-
-        <!-- Sets a drawable as the center. -->
-        <attr name="handleDrawable" format="reference" />
-
-        <!-- Drawable to use for wave ripple animation. -->
-        <attr name="outerRingDrawable" format="reference"/>
-
-        <!-- Drawble used for drawing points -->
-        <attr name="pointDrawable" format="reference" />
-
-        <!-- Inner radius of glow area. -->
-        <attr name="innerRadius"/>
-
-        <!-- Outer radius of glow area. Target icons will be drawn on this circle. -->
-        <attr name="outerRadius" format="dimension" />
-
-        <!-- Radius of glow under finger. -->
-        <attr name="glowRadius" format="dimension" />
-
-        <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
-        <attr name="vibrationDuration" format="integer" />
-
-        <!-- How close we need to be before snapping to a target. -->
-        <attr name="snapMargin" format="dimension" />
-
-        <!-- Number of waves/chevrons to show in animation. -->
-        <attr name="feedbackCount" format="integer" />
-
-        <!-- Used when the handle shouldn't wait to be hit before following the finger -->
-        <attr name="alwaysTrackFinger" format="boolean" />
-
-        <!-- Location along the circle of the first item, in degrees.-->
-        <attr name="firstItemOffset" format="float" />
-
-        <!-- Causes targets to snap to the finger location on activation. -->
-        <attr name="magneticTargets" format="boolean" />
-
-        <attr name="gravity" />
-
-        <!-- Determine whether the glow pad is allowed to scale to fit the bounds indicated
-            by its parent. If this is set to false, no scaling will occur. If this is set to true
-            scaling will occur to fit for any axis in which gravity is set to center. -->
-        <attr name="allowScaling" format="boolean" />
     </declare-styleable>
 
     <!-- =============================== -->
-    <!-- SizeAdaptiveLayout class attributes -->
-    <!-- =============================== -->
-    <eat-comment />
-    <declare-styleable name="SizeAdaptiveLayout_Layout">
-      <!-- The maximum valid height for this item. -->
-      <attr name="layout_maxHeight" format="dimension">
-        <!-- Indicates that the view may be resized arbitrarily large. -->
-        <enum name="unbounded" value="-1" />
-      </attr>
-      <!-- The minimum valid height for this item. -->
-      <attr name="layout_minHeight" format="dimension" />
-    </declare-styleable>
-    <declare-styleable name="SizeAdaptiveLayout" />
-
-    <!-- =============================== -->
     <!-- Location package class attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -7242,8 +7318,34 @@
     <declare-styleable name="Switch">
         <!-- Drawable to use as the "thumb" that switches back and forth. -->
         <attr name="thumb" />
+        <!-- Tint to apply to the thumb. -->
+        <attr name="thumbTint" />
+        <!-- Blending mode used to apply the thumb tint. -->
+        <attr name="thumbTintMode" />
         <!-- Drawable to use as the "track" that the switch thumb slides within. -->
         <attr name="track" format="reference" />
+        <!-- Tint to apply to the track. -->
+        <attr name="trackTint" format="color" />
+        <!-- Blending mode used to apply the track tint. -->
+        <attr name="trackTintMode">
+            <!-- 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>
         <!-- Text to use when the switch is in the checked/"on" state. -->
         <attr name="textOn" />
         <!-- Text to use when the switch is in the unchecked/"off" state. -->
@@ -7435,11 +7537,6 @@
         <enum name="pageDeleteDropTarget" value="7" />
     </attr>
 
-    <declare-styleable name="SlidingChallengeLayout_Layout">
-        <attr name="layout_childType" />
-        <attr name="layout_maxHeight" />
-    </declare-styleable>
-
     <!-- Attributes that can be used with <code>&lt;FragmentBreadCrumbs&gt;</code>
     tags. -->
     <declare-styleable name="FragmentBreadCrumbs">
@@ -7448,27 +7545,6 @@
         <attr name="itemColor" format="color|reference" />
     </declare-styleable>
 
-    <declare-styleable name="MultiPaneChallengeLayout">
-        <!-- Influences how layout_centerWithinArea behaves -->
-        <attr name="orientation" />
-    </declare-styleable>
-
-    <declare-styleable name="MultiPaneChallengeLayout_Layout">
-        <!-- Percentage of the screen this child should consume or center within.
-             If 0/default, the view will be measured by standard rules
-             as if this were a FrameLayout. -->
-        <attr name="layout_centerWithinArea" format="float" />
-        <attr name="layout_childType" />
-        <attr name="layout_gravity" />
-        <attr name="layout_maxWidth" format="dimension" />
-        <attr name="layout_maxHeight" />
-    </declare-styleable>
-
-    <declare-styleable name="KeyguardSecurityViewFlipper_Layout">
-        <attr name="layout_maxWidth" />
-        <attr name="layout_maxHeight" />
-    </declare-styleable>
-
     <declare-styleable name="Toolbar">
         <attr name="titleTextAppearance" format="reference" />
         <attr name="subtitleTextAppearance" format="reference" />
@@ -7505,6 +7581,52 @@
         <!-- Text to set as the content description for the navigation button
              located at the start of the toolbar. -->
         <attr name="navigationContentDescription" format="string" />
+
+        <!-- Tint used for the navigation button -->
+        <attr name="navigationTint" format="color" />
+        <!-- The blending mode used for tinting the navigation button -->
+        <attr name="navigationTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
+            <enum name="add" value="16" />
+        </attr>
+
+        <!-- Tint used for the overflow button -->
+        <attr name="overflowTint" format="color" />
+        <!-- The blending mode used for tinting the overflow button -->
+        <attr name="overflowTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0c3fb9a..9678322 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1012,6 +1012,24 @@
          <p>The default value of this attribute is <code>false</code>. -->
     <attr name="resumeWhilePausing" format="boolean" />
 
+    <!-- Indicates that it is okay for this activity to be resized to any dimension. Intended for a
+         multi-window device where there can be multiple activities of various sizes on the screen
+         at the same time.
+
+         <p>The default value is <code>false</code> for applications with
+         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#MNC} and
+         <code>true</code> otherwise.
+
+         <p>NOTE: A task's root activity value is applied to all additional activities launched in
+         the task. That is if the root activity of a task is resizeable then the system will treat
+         all other activities in the task as resizeable and will not if the root activity isn't
+         resizeable.
+
+         <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
+         resizeable activities as the system doesn't support fixed orientation on a resizeable
+         activity. -->
+    <attr name="resizeableActivity" format="boolean" />
+
     <!-- The <code>manifest</code> tag is the root of an
          <code>AndroidManifest.xml</code> file,
          describing the contents of an Android package (.apk) file.  One
@@ -1020,7 +1038,7 @@
          to avoid name collisions.  For example, applications published
          by Google could have names of the form
          <code>com.google.app.<em>appname</em></code>
-         
+
          <p>Inside of the manifest tag, may appear the following tags
          in any order: {@link #AndroidManifestPermission permission},
          {@link #AndroidManifestPermissionGroup permission-group},
@@ -1039,7 +1057,7 @@
         <attr name="sharedUserLabel" />
         <attr name="installLocation" />
     </declare-styleable>
-    
+
     <!-- The <code>application</code> tag describes application-level components
          contained in the package, as well as general application
          attributes.  Many of the attributes you can supply here (such
@@ -1047,7 +1065,7 @@
          and allowTaskReparenting) serve
          as default values for the corresponding attributes of components
          declared inside of the application.
-         
+
          <p>Inside of this element you specify what the application contains,
          using the elements {@link #AndroidManifestProvider provider},
          {@link #AndroidManifestService service},
@@ -1698,6 +1716,7 @@
         <attr name="autoRemoveFromRecents" />
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
+        <attr name="resizeableActivity" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 457131a..7c63950 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -25,4 +25,8 @@
     <bool name="show_ongoing_ime_switcher">true</bool>
     <bool name="action_bar_expanded_action_views_exclusive">true</bool>
     <bool name="target_honeycomb_needs_options_menu">true</bool>
+
+    <!-- Whether to allow vertically stacked button bars. This is disabled for
+         configurations with a small (e.g. less than 320dp) screen height. -->
+    <bool name="allow_stacked_button_bar">false</bool>
 </resources>
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index eab1e3f..c29fec6 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -103,46 +103,4 @@
     <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
     <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
 
-    <!-- Time picker -->
-    <eat-comment />
-
-    <color name="timepicker_default_background_holo_light">@color/white</color>
-    <color name="timepicker_default_background_holo_dark">#ff303030</color>
-
-    <color name="timepicker_default_text_color_holo_light">#8c8c8c</color>
-    <color name="timepicker_default_text_color_holo_dark">@color/white</color>
-
-    <color name="timepicker_default_ampm_selected_background_color_holo_light">@color/holo_blue_light</color>
-    <color name="timepicker_default_ampm_selected_background_color_holo_dark">@color/holo_blue_light</color>
-
-    <color name="timepicker_default_ampm_unselected_background_color_holo_light">@color/white</color>
-    <color name="timepicker_default_ampm_unselected_background_color_holo_dark">@color/transparent</color>
-
-    <!-- DatePicker colors -->
-    <eat-comment />
-
-    <color name="datepicker_default_header_selector_background_holo_light">@android:color/white</color>
-    <color name="datepicker_default_header_selector_background_holo_dark">#ff303030</color>
-
-    <color name="datepicker_default_header_dayofweek_background_color_holo_light">#999999</color>
-    <color name="datepicker_default_header_dayofweek_background_color_holo_dark">@android:color/white</color>
-
-    <color name="datepicker_default_normal_text_color_holo_light">#ff999999</color>
-    <color name="datepicker_default_normal_text_color_holo_dark">@android:color/white</color>
-
-    <color name="datepicker_default_disabled_text_color_holo_light">#80999999</color>
-    <color name="datepicker_default_disabled_text_color_holo_dark">#80999999</color>
-
-    <color name="datepicker_default_selected_text_color_holo_light">#33b5e5</color>
-    <color name="datepicker_default_selected_text_color_holo_dark">#33b5e5</color>
-
-    <color name="datepicker_default_pressed_text_color_holo_light">#0099cc</color>
-    <color name="datepicker_default_pressed_text_color_holo_dark">#0099cc</color>
-
-    <color name="datepicker_default_circle_background_color_holo_light">@android:color/holo_blue_light</color>
-    <color name="datepicker_default_circle_background_color_holo_dark">@android:color/holo_blue_light</color>
-
-    <color name="datepicker_default_view_animator_color_holo_light">#f2f2f2</color>
-    <color name="datepicker_default_view_animator_color_holo_dark">#ff303030</color>
-
 </resources>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 8dad63e..da68c92 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -17,17 +17,15 @@
 <!-- Colors specific to Material themes. -->
 <resources>
     <color name="background_material_dark">#ff303030</color>
-    <color name="background_material_light">#ffeeeeee</color>
+    <color name="background_material_light">#fffafafa</color>
     <color name="background_floating_material_dark">#ff424242</color>
-    <color name="background_floating_material_light">#ffeeeeee</color>
+    <color name="background_floating_material_light">#ffffffff</color>
 
     <color name="primary_material_dark">#ff212121</color>
-    <color name="primary_material_light">#ffefefef</color>
+    <color name="primary_material_light">#fff5f5f5</color>
     <color name="primary_dark_material_dark">#ff000000</color>
     <color name="primary_dark_material_light">#ff757575</color>
-
-    <color name="ripple_material_dark">#4dffffff</color>
-    <color name="ripple_material_light">#1f000000</color>
+    <color name="primary_dark_material_light_light_status_bar">#ffe0e0e0</color>
 
     <color name="accent_material_light">@color/material_deep_teal_500</color>
     <color name="accent_material_dark">@color/material_deep_teal_200</color>
@@ -40,27 +38,8 @@
     <color name="switch_thumb_disabled_material_dark">#ff616161</color>
     <color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
 
-    <color name="bright_foreground_material_dark">@color/white</color>
-    <color name="bright_foreground_material_light">@color/black</color>
-    <!-- White 50% -->
-    <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>
-
-    <color name="dim_foreground_material_dark">#ffbebebe</color>
-    <color name="dim_foreground_material_light">#ff323232</color>
-    <color name="dim_foreground_disabled_material_dark">#80bebebe</color>
-    <color name="dim_foreground_disabled_material_light">#80323232</color>
-
-    <color name="hint_foreground_material_dark">@color/bright_foreground_disabled_material_dark</color>
-    <color name="hint_foreground_material_light">@color/bright_foreground_disabled_material_light</color>
-
-    <!-- TODO: This is 40% alpha on the default accent color. -->
-    <color name="highlighted_text_material_dark">#6680cbc4</color>
-    <!-- TODO: This is 40% alpha on the default accent color. -->
-    <color name="highlighted_text_material_light">#66009688</color>
+    <color name="foreground_material_dark">@color/white</color>
+    <color name="foreground_material_light">@color/black</color>
 
     <color name="link_text_material_dark">@color/material_deep_teal_200</color>
     <color name="link_text_material_light">@color/material_deep_teal_500</color>
@@ -74,9 +53,16 @@
     <color name="primary_text_default_material_dark">#ffffffff</color>
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
+    <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
+    <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item>
+
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
 
+    <item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
+    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
+    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.26</item>
+
     <!-- Primary & accent colors -->
     <eat-comment />
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3de2268..a781786 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -64,26 +64,11 @@
          As of Honeycomb, blurring is not supported anymore. -->
     <bool name="config_sf_slowBlur">true</bool>
 
-    <!-- Flag indicating that the media framework should allow changing
-         master volume stream and nothing else . -->
-    <bool name="config_useMasterVolume">false</bool>
-
     <!-- Flag indicating that the media framework should support playing of sounds on volume
          key usage.  This adds noticeable additional overhead to volume key processing, so
          is disableable for products for which it is irrelevant. -->
     <bool name="config_useVolumeKeySounds">true</bool>
 
-    <!-- Array of integer pairs controlling the rate at which the master volume changes
-         in response to volume up and down key events.
-         The first integer of each pair is compared against the current master volume
-         (in range 0 to 100).
-         The last pair with first integer <= the current volume is chosen,
-         and the second integer of the pair indicates the amount to increase the master volume
-         when volume up is pressed. -->
-    <integer-array name="config_masterVolumeRamp">
-        <item>0</item>  <item>5</item>  <!-- default: always increase volume by 5% -->
-    </integer-array>
-
     <!-- The attenuation in dB applied to the sound effects played
          through AudioManager.playSoundEffect() when no volume is specified. -->
     <integer name="config_soundEffectVolumeDb">-6</integer>
@@ -530,6 +515,8 @@
     <bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool>
     <!-- If this is true, go to sleep when theater mode is enabled from button press -->
     <bool name="config_goToSleepOnButtonPressTheaterMode">true</bool>
+    <!-- If this is true, long press on power button will be available from the non-interactive state -->
+    <bool name="config_supportLongPressPowerWhenNonInteractive">false</bool>
 
     <!-- Auto-rotation behavior -->
 
@@ -632,6 +619,14 @@
          Any other values will have surprising consequences. -->
     <integer name="config_defaultUiModeType">1</integer>
 
+    <!-- Control the default night mode to use when there is no other mode override set.
+         One of the following values (see UiModeManager.java):
+             0 - MODE_NIGHT_AUTO
+             1 - MODE_NIGHT_NO
+             2 - MODE_NIGHT_YES
+    -->
+    <integer name="config_defaultNightMode">1</integer>
+
     <!-- Indicate whether to allow the device to suspend when the screen is off
          due to the proximity sensor.  This resource should only be set to true
          if the sensor HAL correctly handles the proximity sensor as a wake-up source.
@@ -670,10 +665,10 @@
     <integer name="config_triplePressOnPowerBehavior">0</integer>
 
     <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
-    <string name="widget_default_package_name"></string>
+    <string name="widget_default_package_name" translatable="false"></string>
 
     <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
-    <string name="widget_default_class_name"></string>
+    <string name="widget_default_class_name" translatable="false"></string>
 
     <!-- Indicate whether the SD card is accessible without removing the battery. -->
     <bool name="config_batterySdCardAccessibility">false</bool>
@@ -861,10 +856,34 @@
     <!-- Allow automatic adjusting of the screen brightness while dozing in low power state. -->
     <bool name="config_allowAutoBrightnessWhileDozing">false</bool>
 
+    <!-- Stability requirements in milliseconds for accepting a new brightness level.  This is used
+         for debouncing the light sensor.  Different constants are used to debounce the light sensor
+         when adapting to brighter or darker environments.  This parameter controls how quickly
+         brightness changes occur in response to an observed change in light level that exceeds the
+         hysteresis threshold. -->
+    <integer name="config_autoBrightnessBrighteningLightDebounce">4000</integer>
+    <integer name="config_autoBrightnessDarkeningLightDebounce">8000</integer>
+
+    <!-- Light sensor event rate in milliseconds for automatic brightness control. -->
+    <integer name="config_autoBrightnessLightSensorRate">250</integer>
+
     <!-- If we allow automatic adjustment of screen brightness while dozing, how many times we want
          to reduce it to preserve the battery. Value of 100% means no scaling. -->
     <fraction name="config_screenAutoBrightnessDozeScaleFactor">100%</fraction>
 
+    <!-- When the screen is turned on, the previous estimate of the ambient light level at the time
+         the screen was turned off is restored and is used to determine the initial screen
+         brightness.
+
+         If this flag is true, then the ambient light level estimate will be promptly recomputed
+         after the warm-up interface and the screen brightness will be adjusted immediately.
+
+         If this flag is false, then the ambient light level estimate will be adjusted more
+         gradually in the same manner that normally happens when the screen is on according to the
+         brightening or dimming debounce thresholds.  As a result, it may take somewhat longer to
+         adapt to the environment.  This mode may be better suited for watches. -->
+    <bool name="config_autoBrightnessResetAmbientLuxAfterWarmUp">true</bool>
+
     <!-- Screen brightness used to dim the screen when the user activity
          timeout expires.  May be less than the minimum allowed brightness setting
          that can be set by the user. -->
@@ -1186,7 +1205,7 @@
          PERSIST may improve performance by reducing how often journal blocks are
          reallocated (compared to truncation) resulting in better data block locality
          and less churn of the storage media. -->
-    <string name="db_default_journal_mode">PERSIST</string>
+    <string name="db_default_journal_mode" translatable="false">PERSIST</string>
 
     <!-- Maximum size of the persistent journal file in bytes.
          If the journal file grows to be larger than this amount then SQLite will
@@ -1198,7 +1217,7 @@
          NORMAL also preserves durability in non-WAL modes and uses checksums to ensure
          integrity although there is a small chance that an error might go unnoticed.
          Choices are: FULL, NORMAL, OFF. -->
-    <string name="db_default_sync_mode">FULL</string>
+    <string name="db_default_sync_mode" translatable="false">FULL</string>
 
     <!-- The database synchronization mode when using Write-Ahead Logging.
          FULL is safest and preserves durability at the cost of extra fsyncs.
@@ -1206,7 +1225,7 @@
          and after checkpoint operations.  If checkpoints are infrequent and power loss
          occurs, then committed transactions could be lost and applications might break.
          Choices are: FULL, NORMAL, OFF. -->
-    <string name="db_wal_sync_mode">FULL</string>
+    <string name="db_wal_sync_mode" translatable="false">FULL</string>
 
     <!-- The Write-Ahead Log auto-checkpoint interval in database pages (typically 1 to 4KB).
          The log is checkpointed automatically whenever it exceeds this many pages.
@@ -1391,7 +1410,7 @@
     <!-- If supported and enabled, are dreams activated when asleep and charging? (by default) -->
     <bool name="config_dreamsActivatedOnSleepByDefault">false</bool>
     <!-- ComponentName of the default dream (Settings.Secure.DEFAULT_SCREENSAVER_COMPONENT) -->
-    <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+    <string name="config_dreamsDefaultComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
     <!-- Are we allowed to dream while not plugged in? -->
     <bool name="config_dreamsEnabledOnBattery">false</bool>
@@ -1415,7 +1434,7 @@
 
          Note that doze dreams are not subject to the same start conditions as ordinary dreams.
          Doze dreams will run whenever the power manager is in a dozing state. -->
-    <string name="config_dozeComponent"></string>
+    <string name="config_dozeComponent" translatable="false"></string>
 
     <!-- If true, the doze component is not started until after the screen has been
          turned off and the screen off animation has been performed. -->
@@ -1672,17 +1691,17 @@
 
     <!-- Class name of the framework account picker activity.
          Can be customized for other product types -->
-    <string name="config_chooseAccountActivity"
+    <string name="config_chooseAccountActivity" translatable="false"
             >android/android.accounts.ChooseAccountActivity</string>
     <!-- Class name of the account type and account picker activity.
          Can be customized for other product types -->
-    <string name="config_chooseTypeAndAccountActivity"
+    <string name="config_chooseTypeAndAccountActivity" translatable="false"
             >android/android.accounts.ChooseTypeAndAccountActivity</string>
 
     <!-- Component name of a custom ResolverActivity (Intent resolver) to be used instead of
          the default framework version. If left empty, then the framework version will be used.
          Example: com.google.android.myapp/.resolver.MyResolverActivity  -->
-    <string name="config_customResolverActivity"></string>
+    <string name="config_customResolverActivity" translatable="false"></string>
 
     <!-- Name of the activity or service that prompts the user to reject, accept, or whitelist
          an adb host's public key, when an unwhitelisted host connects to the local adbd.
@@ -1695,7 +1714,7 @@
             >com.android.vpndialogs/com.android.vpndialogs.ConfirmDialog</string>
 
     <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
-    <string name="config_appsAuthorizedForSharedAccounts">;com.android.settings;</string>
+    <string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
 
     <!-- Flag indicating that the media framework should not allow changes or mute on any
          stream or master volumes. -->
@@ -1820,6 +1839,12 @@
         <item>users</item>
     </string-array>
 
+    <!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
+         flushed to the display while dozing.  This value needs to be large enough
+         to account for processing and rendering time plus a frame or two of latency
+         in the display pipeline plus some slack just to be sure. -->
+    <integer name="config_drawLockTimeoutMillis">120</integer>
+
     <!-- default telephony hardware configuration for this platform.
     -->
     <!-- this string array should be overridden by the device to present a list
@@ -2036,4 +2061,34 @@
 
     <!-- Whether to start in touch mode -->
     <bool name="config_defaultInTouchMode">true</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">-50</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
+
+    <!-- If true, the display will be shifted around in ambient mode. -->
+    <bool name="config_enableBurnInProtection">false</bool>
+
+    <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
+         will be used. -->
+    <integer name="config_burnInProtectionMaxRadius">-1</integer>
+
+    <!-- Specifies the minimum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>
+
+    <!-- Specifies the minimum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMinVerticalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
+
+    <!-- Keyguard component -->
+    <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 02fa128..6c6d2cc 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -31,7 +31,7 @@
     <integer name="max_action_buttons">2</integer>
     <dimen name="toast_y_offset">64dip</dimen>
     <!-- Height of the status bar -->
-    <dimen name="status_bar_height">25dip</dimen>
+    <dimen name="status_bar_height">24dp</dimen>
     <!-- Height of the bottom navigation / system bar. -->
     <dimen name="navigation_bar_height">48dp</dimen>
     <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
@@ -304,6 +304,9 @@
     <!-- Touch slop for the global toggle accessibility gesture -->
     <dimen name="accessibility_touch_slop">80dip</dimen>
 
+    <!-- Width of the outline stroke used by the accessibility screen magnification indicator -->
+    <dimen name="accessibility_magnification_indicator_width">4dip</dimen>
+
     <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
     <dimen name="keyguard_security_width">320dp</dimen>
 
@@ -353,51 +356,6 @@
     <!-- Outline width for video subtitles. -->
     <dimen name="subtitle_outline_width">2dp</dimen>
 
-    <!-- New TimePicker dimensions. -->
-    <item name="timepicker_circle_radius_multiplier" format="float" type="string">0.82</item>
-    <item name="timepicker_circle_radius_multiplier_24HourMode" format="float" type="string">0.85</item>
-    <item name="timepicker_selection_radius_multiplier" format="float" type="string">0.16</item>
-    <item name="timepicker_ampm_circle_radius_multiplier" format="float" type="string">0.19</item>
-    <item name="timepicker_numbers_radius_multiplier_normal" format="float" type="string">0.81</item>
-    <item name="timepicker_numbers_radius_multiplier_inner" format="float" type="string">0.60</item>
-    <item name="timepicker_numbers_radius_multiplier_outer" format="float" type="string">0.83</item>
-    <item name="timepicker_text_size_multiplier_normal" format="float" type="string">0.17</item>
-    <item name="timepicker_text_size_multiplier_inner" format="float" type="string">0.14</item>
-    <item name="timepicker_text_size_multiplier_outer" format="float" type="string">0.11</item>
-    <item name="timepicker_transition_mid_radius_multiplier" format="float" type="string">0.95</item>
-    <item name="timepicker_transition_end_radius_multiplier" format="float" type="string">1.3</item>
-
-    <dimen name="timepicker_time_label_size">60sp</dimen>
-    <dimen name="timepicker_extra_time_label_margin">-30dp</dimen>
-    <dimen name="timepicker_ampm_label_size">16sp</dimen>
-    <dimen name="timepicker_ampm_horizontal_padding">12dp</dimen>
-    <dimen name="timepicker_ampm_vertical_padding">16dp</dimen>
-    <dimen name="timepicker_pm_top_padding">3dp</dimen>
-    <dimen name="timepicker_separator_padding">4dp</dimen>
-    <dimen name="timepicker_header_height">96dp</dimen>
-    <dimen name="timepicker_minimum_margin_sides">48dp</dimen>
-    <dimen name="timepicker_minimum_margin_top_bottom">24dp</dimen>
-    <dimen name="timepicker_radial_picker_dimen">270dp</dimen>
-
-    <!-- Used by SimpleMonthView -->
-    <dimen name="datepicker_day_number_size">12sp</dimen>
-    <dimen name="datepicker_month_label_size">14sp</dimen>
-    <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
-    <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
-    <dimen name="datepicker_day_number_select_circle_radius">16dp</dimen>
-    <dimen name="datepicker_view_animator_height">226dp</dimen>
-
-    <dimen name="datepicker_year_picker_padding_top">8dp</dimen>
-    <dimen name="datepicker_year_label_height">64dp</dimen>
-    <dimen name="datepicker_year_label_text_size">22dp</dimen>
-    <dimen name="datepicker_component_width">260dp</dimen>
-    <dimen name="datepicker_dialog_width">520dp</dimen>
-    <dimen name="datepicker_selected_date_day_size">88dp</dimen>
-    <dimen name="datepicker_selected_date_month_size">24dp</dimen>
-    <dimen name="datepicker_selected_date_year_size">24dp</dimen>
-    <dimen name="datepicker_header_height">30dp</dimen>
-    <dimen name="datepicker_header_text_size">14dp</dimen>
-
     <!-- Minimum size of the fast scroller thumb's touch target. -->
     <dimen name="fast_scroller_minimum_touch_target">48dp</dimen>
 
@@ -411,6 +369,10 @@
      to 0 -->
      <dimen name="circular_display_mask_offset">0px</dimen>
 
+     <!-- Amount to reduce the size of the circular mask by (to compensate for aliasing
+     effects). This is only used on circular displays. -->
+     <dimen name="circular_display_mask_thickness">1px</dimen>
+
      <dimen name="lock_pattern_dot_line_width">3dp</dimen>
      <dimen name="lock_pattern_dot_size">12dp</dimen>
      <dimen name="lock_pattern_dot_size_activated">28dp</dimen>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index e1e1ffed..8d2afde 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -23,7 +23,7 @@
     <dimen name="preference_screen_side_margin_negative_material">0dp</dimen>
 
     <!-- Preference fragment padding, sides -->
-    <dimen name="preference_fragment_padding_side_material">8dp</dimen>
+    <dimen name="preference_fragment_padding_side_material">0dp</dimen>
 
     <!-- Preference breadcrumbs padding, start padding -->
     <dimen name="preference_breadcrumbs_padding_start_material">12dp</dimen>
@@ -114,4 +114,50 @@
 
     <!-- Padding above and below selection dialog lists. -->
     <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
+
+    <dimen name="scrubber_track_height_material">2dp</dimen>
+    <dimen name="progress_bar_height_material">4dp</dimen>
+
+    <!-- Material time picker dimensions. -->
+    <!-- Text size for the time picker header HH:MM label. This value is large
+         enough that we don't need to use scaled pixels, dp is fine. -->
+    <dimen name="timepicker_time_label_size">60dp</dimen>
+    <dimen name="timepicker_ampm_label_size">16sp</dimen>
+    <dimen name="timepicker_ampm_horizontal_padding">16dp</dimen>
+    <dimen name="timepicker_am_top_padding">4dp</dimen>
+    <dimen name="timepicker_pm_top_padding">4dp</dimen>
+    <dimen name="timepicker_separator_padding">2dp</dimen>
+    <dimen name="timepicker_header_height">96dp</dimen>
+    <dimen name="timepicker_radial_picker_dimen">296dp</dimen>
+    <dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
+    <dimen name="timepicker_radial_picker_horizontal_margin">16dp</dimen>
+
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_selector_radius">20dp</dimen>
+    <dimen name="timepicker_selector_stroke">2dp</dimen>
+    <dimen name="timepicker_center_dot_radius">3dp</dimen>
+    <dimen name="timepicker_selector_dot_radius">3dp</dimen>
+    <dimen name="timepicker_text_inset_normal">22dp</dimen>
+    <dimen name="timepicker_text_inset_inner">58dp</dimen>
+    <dimen name="timepicker_text_size_normal">16sp</dimen>
+    <dimen name="timepicker_text_size_inner">12sp</dimen>
+
+    <!-- Material date picker dimensions. -->
+    <dimen name="datepicker_year_picker_padding_top">8dp</dimen>
+    <dimen name="datepicker_year_label_height">64dp</dimen>
+    <dimen name="datepicker_year_label_text_size">22dp</dimen>
+    <dimen name="datepicker_component_width">260dp</dimen>
+    <dimen name="datepicker_dialog_width">520dp</dimen>
+    <dimen name="datepicker_selected_date_day_size">88dp</dimen>
+    <dimen name="datepicker_selected_date_month_size">24dp</dimen>
+    <dimen name="datepicker_selected_date_year_size">24dp</dimen>
+    <dimen name="datepicker_header_height">30dp</dimen>
+    <dimen name="datepicker_header_text_size">14dp</dimen>
+
+    <!-- Used by Material-style SimpleMonthView -->
+    <dimen name="datepicker_day_number_size">12sp</dimen>
+    <dimen name="datepicker_month_label_size">14sp</dimen>
+    <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
+    <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
+    <dimen name="datepicker_view_animator_height">226dp</dimen>
 </resources>
diff --git a/core/res/res/values/donottranslate-cldr.xml b/core/res/res/values/donottranslate-cldr.xml
index 80db6e4..a8e2b2b 100755
--- a/core/res/res/values/donottranslate-cldr.xml
+++ b/core/res/res/values/donottranslate-cldr.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="numeric_date_template">"%s/%s/%s"</string>
     <string name="month_day_year">%B %-e, %Y</string>
     <string name="time_of_day">%-l:%M:%S %p</string>
     <string name="date_and_time">%b %-e, %Y, %-l:%M:%S %p</string>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bd24f3e..6108b27 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -89,4 +89,8 @@
   <item type="id" name="parentMatrix" />
   <item type="id" name="statusBarBackground" />
   <item type="id" name="navigationBarBackground" />
+  <item type="id" name="pasteAsPlainText" />
+  <item type="id" name="undo" />
+  <item type="id" name="redo" />
+  <item type="id" name="replaceText" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2bb9aa8..e507b3d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1759,7 +1759,9 @@
   <public type="attr" name="actionModeSplitBackground" id="0x0101039d" />
   <public type="attr" name="textAppearanceListItem" id="0x0101039e" />
   <public type="attr" name="textAppearanceListItemSmall" id="0x0101039f" />
+  <!-- @deprecated Removed. -->
   <public type="attr" name="targetDescriptions" id="0x010103a0" />
+  <!-- @deprecated Removed. -->
   <public type="attr" name="directionDescriptions" id="0x010103a1" />
   <public type="attr" name="overridesImplicitlyEnabledSubtype" id="0x010103a2" />
   <public type="attr" name="listPreferredItemPaddingLeft" id="0x010103a3" />
@@ -2594,8 +2596,59 @@
     <public type="attr" name="dialogPreferredPadding" id="0x010104d3" />
     <public type="attr" name="searchHintIcon" id="0x010104d4" />
     <public type="attr" name="revisionCode" />
+    <public type="attr" name="drawableTint" />
+    <public type="attr" name="drawableTintMode" />
+    <public type="attr" name="fraction" />
 
     <public type="style" name="Theme.DeviceDefault.Dialog.Alert" />
     <public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
 
+  <!-- ===============================================================
+       Resources added in version MNC of the platform
+       =============================================================== -->
+  <eat-comment />
+
+  <public type="attr" name="trackTint" />
+  <public type="attr" name="trackTintMode" />
+  <public type="attr" name="resizeableActivity" />
+  <public type="attr" name="start" />
+  <public type="attr" name="end" />
+  <public type="attr" name="windowHasLightStatusBar" />
+  <public type="attr" name="numbersInnerTextColor" />
+  <public type="attr" name="iconTint" />
+  <public type="attr" name="iconTintMode" />
+  <public type="attr" name="overflowTint" />
+  <public type="attr" name="overflowTintMode" />
+  <public type="attr" name="navigationTint" />
+  <public type="attr" name="navigationTintMode" />
+
+  <public type="style" name="Widget.Material.Button.Colored" />
+
+  <public type="style" name="Theme.Material.DayNight" />
+  <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
+  <public type="style" name="Theme.Material.DayNight.Dialog" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.Alert" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
+  <public type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
+  <public type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
+  <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
+  <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
+  <public type="style" name="Theme.Material.DayNight.Panel" />
+  <public type="style" name="Theme.Material.Light.LightStatusBar" />
+  <public type="style" name="ThemeOverlay.Material.Dialog" />
+
+  <public type="id" name="pasteAsPlainText" />
+  <public type="id" name="undo" />
+  <public type="id" name="redo" />
+  <public type="id" name="replaceText" />
+
+  <public type="attr" name="allowUndo" />
+
+  <public type="attr" name="colorBackgroundFloating" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7633950..4189b83 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -488,6 +488,9 @@
     <!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
     <string name="global_action_settings">Settings</string>
 
+    <!-- label for item that launches voice assist in phone options dialog [CHAR LIMIT=15]-->
+    <string name="global_action_voice_assist">Voice Assist</string>
+
     <!-- label for item that locks the phone and enforces that it can't be unlocked without entering a credential. [CHAR LIMIT=15] -->
     <string name="global_action_lockdown">Lock now</string>
 
@@ -1213,6 +1216,12 @@
         interface of a widget 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_bindRouteProvider">bind to a route provider service</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_bindRouteProvider">Allows the holder to bind to any registered
+        route providers. 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_bindDeviceAdmin">interact with a device admin</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_bindDeviceAdmin">Allows the holder to send intents to
@@ -2206,6 +2215,15 @@
       re-enables the keylock when the call is finished.</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_manageFingerprint">manage fingerprint hardware</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_manageFingerprint">Allows the app to invoke methods to add and delete fingerprint templates for use.</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_useFingerprint">use fingerprint hardware</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_useFingerprint">Allows the app to use fingerprint hardware for authentication</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_readSyncSettings">read sync settings</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_readSyncSettings">Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account.</string>
@@ -2342,11 +2360,21 @@
     <string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener 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_bindChooserTargetService">bind to a chooser target service</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_bindChooserTargetService">Allows the holder to bind to the top-level interface of a chooser target 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_bindConditionProviderService">bind to a condition provider service</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_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider 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_bindMediaRouteService">bind to a media route service</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_bindMediaRouteService">Allows the holder to bind to the top-level interface of a media route 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_bindDreamService">bind to a dream service</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_bindDreamService">Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps.</string>
@@ -2388,7 +2416,7 @@
     <!-- Title of policy access to limiting the user's password choices -->
     <string name="policylab_limitPassword">Set password rules</string>
     <!-- Description of policy access to limiting the user's password choices -->
-    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
+    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen lock passwords and PINs.</string>
     <!-- Title of policy access to watch user login attempts -->
     <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
     <!-- Description of policy access to watch user login attempts -->
@@ -2403,15 +2431,24 @@
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
     typed. when unlocking the screen, and lock the phone or erase all the phone\'s
     data if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the tablet or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the TV or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the phone or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
     <!-- Title of policy access to reset user's password -->
-    <string name="policylab_resetPassword">Change the screen-unlock password</string>
+    <string name="policylab_resetPassword">Change the screen lock</string>
     <!-- Description of policy access to reset user's password -->
-    <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
+    <string name="policydesc_resetPassword">Change the screen lock.</string>
     <!-- Title of policy access to force lock the device -->
     <string name="policylab_forceLock">Lock the screen</string>
     <!-- Description of policy access to limiting the user's password choices -->
     <string name="policydesc_forceLock">Control how and when the screen locks.</string>
-    <!-- Title of policy access to wipe the user's data -->
+    <!-- Title of policy access to wipe primary user's data -->
     <string name="policylab_wipeData">Erase all data</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
@@ -2419,15 +2456,23 @@
     <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
-    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Title of policy access to wipe secondary user's data -->
+    <string name="policylab_wipeData_secondaryUser">Erase user data</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
+    <!-- Title of policy access to set global proxy -->
+    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Description of policy access to set global proxy -->
     <string name="policydesc_setGlobalProxy">Set the device global proxy
-        to be used while policy is enabled. Only the first device admin
-        sets the effective global proxy.</string>
-    <!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
-    <string name="policylab_expirePassword">Set lock-screen password expiration</string>
+    to be used while policy is enabled. Only the device owner can set the global proxy.</string>
+    <!-- Title of policy access to enforce password expiration [CHAR LIMIT=50]-->
+    <string name="policylab_expirePassword">Set screen lock password expiration</string>
     <!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
-    <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
+    <string name="policydesc_expirePassword">Change how frequently the screen lock password, PIN, or pattern must be changed.</string>
     <!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
     <string name="policylab_encryptedStorage">Set storage encryption</string>
     <!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
@@ -2437,9 +2482,9 @@
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
     <string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
     <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
-    <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
+    <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
-    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -3372,26 +3417,9 @@
     <!-- String used to display the date. This is the string to say something happened more than 1 month ago. -->
     <string name="beforeOneMonthDurationPast">Before 1 month ago</string>
 
-    <!-- This is used to express that something occurred some number of seconds in the past (e.g., 5 seconds ago). -->
-    <plurals name="num_seconds_ago">
-        <item quantity="one">1 second ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> seconds ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of minutes in the past (e.g., 5 minutes ago). -->
-    <plurals name="num_minutes_ago">
-        <item quantity="one">1 minute ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> minutes ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of hours in the past (e.g., 5 hours ago). -->
-    <plurals name="num_hours_ago">
-        <item quantity="one">1 hour ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
-    </plurals>
-
     <!-- This is used to express that something occurred within the last X days (e.g., Last 7 days). -->
     <plurals name="last_num_days">
+        <item quantity="one">Last <xliff:g id="count">%d</xliff:g> day</item>
         <item quantity="other">Last <xliff:g id="count">%d</xliff:g> days</item>
     </plurals>
 
@@ -3401,84 +3429,6 @@
     <!-- This is used to express that something happened longer ago than the previous options -->
     <string name="older">Older</string>
 
-    <!-- This is used to express that something occurred some number of days in the past (e.g., 5 days ago). -->
-    <plurals name="num_days_ago">
-        <item quantity="one">yesterday</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of seconds in the future (e.g., in 5 seconds). -->
-    <plurals name="in_num_seconds">
-        <item quantity="one">in 1 second</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> seconds</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of minutes in the future (e.g., in 5 minutes). -->
-    <plurals name="in_num_minutes">
-        <item quantity="one">in 1 minute</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> minutes</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of hours in the future (e.g., in 5 hours). -->
-    <plurals name="in_num_hours">
-        <item quantity="one">in 1 hour</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of days in the future (e.g., in 5 days). -->
-    <plurals name="in_num_days">
-        <item quantity="one">tomorrow</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated seconds in the past (e.g., 5 secs ago). -->
-    <plurals name="abbrev_num_seconds_ago">
-        <item quantity="one">1 sec ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> secs ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated minutes in the past (e.g., 5 mins ago). -->
-    <plurals name="abbrev_num_minutes_ago">
-        <item quantity="one">1 min ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> mins ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated hours in the past (e.g., 5 hrs ago). -->
-    <plurals name="abbrev_num_hours_ago">
-        <item quantity="one">1 hour ago</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
-    </plurals>
-
-    <!-- This is used to express that something occurred some number of abbreviated days in the past (e.g., 5 days ago). -->
-    <plurals name="abbrev_num_days_ago">
-        <item quantity="one">yesterday</item>
-        <item quantity="other"><xliff:g id="count">%d</xliff:g> days ago</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated seconds in the future (e.g., in 5 secs). -->
-    <plurals name="abbrev_in_num_seconds">
-        <item quantity="one">in 1 sec</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> secs</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated minutes in the future (e.g., in 5 mins). -->
-    <plurals name="abbrev_in_num_minutes">
-        <item quantity="one">in 1 min</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> mins</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated hours in the future (e.g., in 5 hrs). -->
-    <plurals name="abbrev_in_num_hours">
-        <item quantity="one">in 1 hour</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> hours</item>
-    </plurals>
-
-    <!-- This is used to express that something will occur some number of abbreviated days in the future (e.g., in 5 days). -->
-    <plurals name="abbrev_in_num_days">
-        <item quantity="one">tomorrow</item>
-        <item quantity="other">in <xliff:g id="count">%d</xliff:g> days</item>
-    </plurals>
-
     <!-- String used to display the date. Preposition for date display ("on May 29") -->
     <string name="preposition_for_date">on <xliff:g id="date" example="May 29">%s</xliff:g></string>
     <!-- String used to display the date. Preposition for time display ("at 2:33am") -->
@@ -3743,6 +3693,9 @@
         <xliff:g id="number" example="123">%1$d</xliff:g> of
         <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
 
+    <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk pre boot broadcast -->
+    <string name="android_preparing_apk">Preparing <xliff:g id="appname">%1$s</xliff:g>.</string>
+
     <!-- [CHAR LIMIT=NONE] Message to show in upgrading dialog when reached the point of starting apps. -->
     <string name="android_upgrading_starting_apps">Starting apps.</string>
 
@@ -3768,6 +3721,23 @@
     <string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string>
     <string name="new_app_description">Stop the old app without saving.</string>
 
+    <!-- Notification text to tell the user that a process has exceeded its memory limit. -->
+    <string name="dump_heap_notification"><xliff:g id="proc">%1$s</xliff:g> exceeded memory
+        limit</string>
+
+    <!-- Notification details to tell the user that a process has exceeded its memory limit. -->
+    <string name="dump_heap_notification_detail">Heap dump has been collected;
+        touch to share</string>
+
+    <!-- Title of dialog prompting the user to share a heap dump. -->
+    <string name="dump_heap_title">Share heap dump?</string>
+
+    <!-- Text of dialog prompting the user to share a heap dump. -->
+    <string name="dump_heap_text">The process <xliff:g id="proc">%1$s</xliff:g> has exceeded
+        its process memory limit of <xliff:g id="size">%2$s</xliff:g>.  A heap dump is available
+        for you to share with its developer.  Be careful: this heap dump can contain any
+        of your personal information that the application has access to.</string>
+
     <!-- Displayed in the title of the chooser for things to do with text that
          is to be sent to another application. For example, I can send
          text through SMS or IM.  A dialog with those choices would be shown,
@@ -3844,6 +3814,14 @@
     <!-- Do not translate. Default access point SSID used for tethering -->
     <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>
 
+    <!-- A notification is shown the first time a connection is attempted on an app owned AP -->
+    <!-- title for this message -->
+    <string name="wifi_connect_alert_title">Allow connection?</string>
+    <!-- message explaining who is connecting to what -->
+    <string name="wifi_connect_alert_message">Application %1$s would like to connect to Wifi Network %2$s</string>
+    <!-- default application in case name can not be found -->
+    <string name="wifi_connect_default_application">An application</string>
+
     <string name="wifi_p2p_dialog_title">Wi-Fi Direct</string>
     <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string>
     <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string>
@@ -3985,6 +3963,8 @@
     <string name="usb_mtp_notification_title">Connected as a media device</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode.  This is the title -->
     <string name="usb_ptp_notification_title">Connected as a camera</string>
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MIDI mode.  This is the title -->
+    <string name="usb_midi_notification_title">Connected as a MIDI device</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in mass storage mode (for installer CD image).  This is the title -->
     <string name="usb_cd_installer_notification_title">Connected as an installer</string>
     <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->
@@ -5031,8 +5011,14 @@
     <!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
     <string name="restr_pin_try_later">Try again later</string>
 
-    <!-- Cling help message when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
-    <string name="immersive_mode_confirmation" msgid="8554991488096662508">Swipe down from the top to exit full screen.</string>
+    <!-- Cling help message title when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
+    <string name="immersive_cling_title">Viewing full screen</string>
+
+    <!-- Cling help message description when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
+    <string name="immersive_cling_description">To exit, swipe down from the top.</string>
+
+    <!-- Cling help message confirmation button when hiding the navigation bar entering immersive mode [CHAR LIMIT=30] -->
+    <string name="immersive_cling_positive">Got it</string>
 
     <!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
     <string name="done_label">Done</string>
@@ -5097,7 +5083,7 @@
     <!-- Notify use that they are in Lock-to-app in accessibility mode -->
     <string name="lock_to_app_toast_accessible">To unpin this screen, touch and hold Overview.</string>
     <!-- Notify user that they are locked in lock-to-app mode -->
-    <string name="lock_to_app_toast_locked">Screen is pinned. Unpinning isn\'t allowed by your organization.</string>
+    <string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
     <!-- Starting lock-to-app indication. -->
     <string name="lock_to_app_start">Screen pinned</string>
     <!-- Exting lock-to-app indication. -->
@@ -5147,7 +5133,7 @@
     <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
 
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever">Indefinitely</string>
+    <string name="zen_mode_forever">Until you turn this off</string>
 
     <!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
     <string name="toolbar_collapse_description">Collapse</string>
@@ -5175,4 +5161,9 @@
     <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
     <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
 
+    <!-- Manufacturer name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_manufacturer_name">Android</string>
+    <!-- Model name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_model_name">USB Peripheral Port</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c520a46..cc64b43 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -237,6 +237,12 @@
         <item name="windowExitAnimation">@anim/fade_out</item>
     </style>
 
+    <!-- Window animations used for immersive mode confirmation. -->
+    <style name="Animation.ImmersiveModeConfirmation">
+        <item name="windowEnterAnimation">@null</item>
+        <item name="windowExitAnimation">@anim/fast_fade_out</item>
+    </style>
+
     <!-- Window animations for screen savers. {@hide} -->
     <style name="Animation.Dream">
         <item name="windowEnterAnimation">@anim/slow_fade_in</item>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 41b8b25..6861069 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -463,40 +463,14 @@
         <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
     </style>
 
-    <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Holo.TimePicker" parent="Widget.Material.TimePicker">
+        <!-- If the developer chooses "clock", they get the Material picker. -->
         <item name="timePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
-        <!-- Attributes for new-style TimePicker. -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
-        <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.TimePicker.TimeLabel</item>
-        <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.TimePicker.AmPmLabel</item>
-        <item name="headerBackground">@color/timepicker_default_background_holo_dark</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="numbersTextColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_dark</item>
-        <item name="amPmTextColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_dark</item>
-        <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
-        <item name="numbersSelectorColor">@color/holo_blue_light</item>
     </style>
 
-    <style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Holo.DatePicker" parent="Widget.Material.DatePicker">
+        <!-- If the developer chooses "calendar", they get the Material picker. -->
         <item name="datePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
-        <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
-        <!-- New-style date picker attributes. -->
-        <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item>
-        <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item>
-        <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_dark</item>
-        <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item>
-        <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item>
-        <item name="headerYearTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.DatePicker.List.YearLabel</item>
-        <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_dark</item>
-        <item name="calendarTextColor">@color/date_picker_calendar_holo_dark</item>
-        <item name="calendarSelectedTextColor">@color/holo_blue_light</item>
     </style>
 
     <style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView" />
@@ -888,40 +862,14 @@
 
     <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker" />
 
-    <style name="Widget.Holo.Light.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Holo.Light.TimePicker" parent="Widget.Material.Light.TimePicker">
+        <!-- If the developer chooses "clock", they get the Material picker. -->
         <item name="timePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
-        <!-- Non-legacy styling -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
-        <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.TimeLabel</item>
-        <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.AmPmLabel</item>
-        <item name="headerBackground">@color/timepicker_default_background_holo_light</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="numbersTextColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_light</item>
-        <item name="amPmTextColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_light</item>
-        <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
-        <item name="numbersSelectorColor">@color/holo_blue_light</item>
     </style>
 
-    <style name="Widget.Holo.Light.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Holo.Light.DatePicker" parent="Widget.Material.Light.DatePicker">
+        <!-- If the developer chooses "calendar", they get the Material picker. -->
         <item name="datePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
-        <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
-        <!-- New-style date picker attributes. -->
-        <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_light</item>
-        <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item>
-        <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item>
-        <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item>
-        <item name="headerYearTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item>
-        <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_light</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item>
-        <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_light</item>
-        <item name="calendarTextColor">@color/date_picker_calendar_holo_light</item>
-        <item name="calendarSelectedTextColor">@color/holo_blue_light</item>
     </style>
 
     <style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
@@ -1221,86 +1169,6 @@
         <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
     </style>
 
-    <style name="TextAppearance.Holo.TimePicker.TimeLabel" parent="TextAppearance.Holo">
-        <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_dark</item>
-    </style>
-
-    <style name="TextAppearance.Holo.TimePicker.AmPmLabel" parent="TextAppearance.Holo">
-        <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="textStyle">bold</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.TimePicker.TimeLabel" parent="TextAppearance.Holo.Light">
-        <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_light</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.TimePicker.AmPmLabel" parent="TextAppearance.Holo.Light">
-        <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="textStyle">bold</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.DayOfWeekLabel" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/black</item>
-        <item name="textSize">@dimen/datepicker_header_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/date_picker_selector_holo_dark</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.MonthLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.YearLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.List.YearLabel" parent="TextAppearance.Holo">
-        <item name="textColor">@color/date_picker_year_selector_holo_dark</item>
-        <item name="textSize">@dimen/datepicker_year_label_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/white</item>
-        <item name="textSize">@dimen/datepicker_header_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/date_picker_selector_holo_light</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.YearLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.List.YearLabel" parent="TextAppearance.Holo">
-        <item name="textColor">@color/date_picker_year_selector_holo_light</item>
-        <item name="textSize">@dimen/datepicker_year_label_text_size</item>
-    </style>
-
     <style name="Widget.Holo.FastScroll" parent="Widget.FastScroll">
         <item name="thumbMinWidth">0dp</item>
         <item name="thumbMinHeight">0dp</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 419beba..a8ab18d 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -37,7 +37,7 @@
     </style>
 
     <style name="PreferenceFragment.Material">
-        <item name="layout">@android:layout/preference_list_fragment_material</item>
+        <item name="layout">@layout/preference_list_fragment_material</item>
         <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
         <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
     </style>
@@ -72,7 +72,7 @@
     </style>
 
     <style name="Preference.Material.SeekBarPreference">
-        <item name="layout">@android:layout/preference_widget_seekbar_material</item>
+        <item name="layout">@layout/preference_widget_seekbar_material</item>
     </style>
 
     <style name="Preference.Material.PreferenceScreen"/>
@@ -306,7 +306,9 @@
         <item name="textColor">?attr/textColorPrimary</item>
     </style>
 
-    <style name="TextAppearance.Material.Widget.TabWidget" parent="TextAppearance.Material.Button" />
+    <style name="TextAppearance.Material.Widget.TabWidget" parent="TextAppearance.Material.Button">
+        <item name="textColor">@color/tab_indicator_text_material</item>
+    </style>
 
     <style name="TextAppearance.Material.Widget.TextView">
         <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
@@ -377,14 +379,12 @@
 
     <style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material">
         <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
+        <item name="textColor">@color/time_picker_header_text_material</item>
     </style>
 
-    <style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material">
+    <style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material.Button">
         <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
-        <item name="textStyle">bold</item>
+        <item name="textColor">@color/time_picker_header_text_material</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
@@ -395,24 +395,24 @@
 
     <style name="TextAppearance.Material.DatePicker.MonthLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item> <!-- selected should be accent -->
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.List.YearLabel" parent="TextAppearance.Material">
-        <item name="textColor">?attr/textColorSecondary</item> <!-- selected should be accent -->
+        <item name="textColor">?attr/textColorSecondaryActivated</item>
         <item name="textSize">@dimen/datepicker_year_label_text_size</item>
     </style>
 
@@ -462,6 +462,11 @@
         <item name="gravity">center_vertical|center_horizontal</item>
     </style>
 
+    <!-- Colored bordered ink button -->
+    <style name="Widget.Material.Button.Colored">
+        <item name="backgroundTint">@color/btn_colored_material</item>
+    </style>
+
     <!-- Small bordered ink button -->
     <style name="Widget.Material.Button.Small">
         <item name="minHeight">48dip</item>
@@ -476,8 +481,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Widget.Material.Button.Borderless.Colored">
-        <item name="textColor">?attr/colorAccent</item>
-        <item name="stateListAnimator">@anim/disabled_anim_material</item>
+        <item name="textColor">@color/btn_colored_text_material</item>
     </style>
 
     <!-- Alert dialog button bar button -->
@@ -507,9 +511,7 @@
         <item name="background">@null</item>
     </style>
 
-    <style name="Widget.Material.ButtonBar.AlertDialog">
-        <item name="background">@null</item>
-    </style>
+    <style name="Widget.Material.ButtonBar.AlertDialog" />
 
     <style name="Widget.Material.SearchView">
         <item name="layout">@layout/search_view</item>
@@ -567,16 +569,16 @@
     <style name="Widget.Material.CompoundButton" parent="Widget.CompoundButton"/>
 
     <style name="Widget.Material.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.Star" parent="Widget.CompoundButton.Star">
         <item name="button">@drawable/btn_star_material</item>
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
     </style>
 
     <style name="Widget.Material.CompoundButton.Switch">
@@ -585,7 +587,7 @@
         <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item>
         <item name="textOn">@string/capital_on</item>
         <item name="textOff">@string/capital_off</item>
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
         <item name="showText">false</item>
     </style>
 
@@ -638,40 +640,37 @@
         <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
     </style>
 
-    <style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Material.TimePicker">
         <item name="timePickerMode">clock</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+        <item name="legacyLayout">@layout/time_picker_legacy_material</item>
         <!-- Attributes for new-style TimePicker. -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
+        <item name="internalLayout">@layout/time_picker_material</item>
         <item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
         <item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
-        <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
         <item name="headerBackground">@drawable/time_picker_header_material</item>
-        <item name="numbersTextColor">?attr/textColorSecondary</item>
+        <item name="numbersTextColor">?attr/textColorPrimaryActivated</item>
+        <item name="numbersInnerTextColor">?attr/textColorSecondaryActivated</item>
         <item name="numbersBackgroundColor">#10ffffff</item>
-        <item name="amPmTextColor">?attr/textColorSecondary</item>
-        <item name="amPmBackgroundColor">@color/transparent</item>
-        <item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
         <item name="numbersSelectorColor">?attr/colorControlActivated</item>
+        <item name="amPmTextColor">?attr/textColorSecondary</item>
     </style>
 
-    <style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Material.DatePicker">
         <item name="datePickerMode">calendar</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
+        <item name="calendarViewShown">true</item>
         <!-- Attributes for new-style DatePicker. -->
         <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
         <item name="dayOfWeekBackground">#10000000</item>
         <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
         <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item>
         <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item>
         <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item>
-        <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
         <item name="headerBackground">?attr/colorAccent</item>
         <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
         <item name="yearListSelectorColor">?attr/colorControlActivated</item>
-        <item name="calendarTextColor">?attr/textColorSecondary</item>
-        <item name="calendarSelectedTextColor">?attr/colorControlActivated</item>
+        <item name="calendarTextColor">?attr/textColorSecondaryActivated</item>
+        <item name="calendarDayBackgroundColor">?attr/colorControlActivated</item>
     </style>
 
     <style name="Widget.Material.ActivityChooserView" parent="Widget.ActivityChooserView">
@@ -735,7 +734,7 @@
         <item name="paddingStart">16dip</item>
         <item name="paddingEnd">16dip</item>
         <item name="mirrorForRtl">true</item>
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
     </style>
 
     <style name="Widget.Material.RatingBar" parent="Widget.RatingBar">
@@ -765,6 +764,9 @@
         <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
         <item name="popupBackground">@drawable/popup_background_material</item>
         <item name="popupElevation">@dimen/floating_window_z</item>
+        <item name="popupAnimationStyle">@empty</item>
+        <item name="popupEnterTransition">@transition/popup_window_enter</item>
+        <item name="popupExitTransition">@transition/popup_window_exit</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="overlapAnchor">true</item>
@@ -775,22 +777,22 @@
     </style>
 
     <style name="Widget.Material.Spinner.DropDown"/>
-
-    <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.Spinner.DropDown.ActionBar" />
 
     <style name="Widget.Material.Spinner.Underlined">
         <item name="background">@drawable/spinner_textfield_background_material</item>
     </style>
 
-    <style name="Widget.Material.TabWidget" parent="Widget.TabWidget">
-        <item name="tabStripLeft">@null</item>
-        <item name="tabStripRight">@null</item>
+    <style name="Widget.Material.TabWidget">
+        <item name="textAppearance">@style/TextAppearance.Material.Widget.TabWidget</item>
+        <item name="ellipsize">marquee</item>
+        <item name="singleLine">true</item>
+        <item name="tabStripLeft">@empty</item>
+        <item name="tabStripRight">@empty</item>
         <item name="tabStripEnabled">false</item>
         <item name="divider">?attr/dividerVertical</item>
-        <item name="showDividers">middle</item>
+        <item name="gravity">fill_horizontal|center_vertical</item>
+        <item name="showDividers">none</item>
         <item name="dividerPadding">8dip</item>
         <item name="measureWithLargestChild">true</item>
         <item name="tabLayout">@layout/tab_indicator_material</item>
@@ -813,19 +815,21 @@
         <item name="subtitleTextAppearance">@style/TextAppearance.Material.Widget.Toolbar.Subtitle</item>
     </style>
 
-    <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Toolbar.Button.Navigation">
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+    <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Material">
+        <item name="background">?attr/controlBackground</item>
+        <item name="minWidth">56dp</item>
+        <item name="scaleType">center</item>
         <item name="paddingStart">@dimen/action_bar_navigation_padding_start_material</item>
     </style>
 
     <style name="Widget.Material.WebTextView" parent="Widget.WebTextView"/>
-
     <style name="Widget.Material.WebView" parent="Widget.WebView"/>
 
-    <style name="Widget.Material.DropDownItem" parent="Widget.DropDownItem">
+    <style name="Widget.Material.DropDownItem">
         <item name="textAppearance">@style/TextAppearance.Material.Widget.DropDownItem</item>
         <item name="paddingStart">8dp</item>
         <item name="paddingEnd">8dp</item>
+        <item name="gravity">center_vertical</item>
     </style>
 
     <style name="Widget.Material.DropDownItem.Spinner"/>
@@ -838,11 +842,13 @@
     <style name="Widget.Material.QuickContactBadgeSmall.WindowMedium" parent="Widget.QuickContactBadgeSmall.WindowMedium"/>
     <style name="Widget.Material.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
 
-    <style name="Widget.Material.ListPopupWindow" parent="Widget.ListPopupWindow">
+    <style name="Widget.Material.ListPopupWindow">
         <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
         <item name="popupBackground">@drawable/popup_background_material</item>
         <item name="popupElevation">@dimen/floating_window_z</item>
-        <item name="popupAnimationStyle">@style/Animation.Material.Popup</item>
+        <item name="popupAnimationStyle">@empty</item>
+        <item name="popupEnterTransition">@transition/popup_window_enter</item>
+        <item name="popupExitTransition">@transition/popup_window_exit</item>
         <item name="dropDownVerticalOffset">0dip</item>
         <item name="dropDownHorizontalOffset">0dip</item>
         <item name="dropDownWidth">wrap_content</item>
@@ -855,18 +861,19 @@
         <item name="dropDownHorizontalOffset">-4dip</item>
     </style>
 
-    <style name="Widget.Material.ActionButton" parent="Widget.ActionButton">
+    <style name="Widget.Material.ActionButton">
+        <item name="background">?attr/actionBarItemBackground</item>
+        <item name="paddingStart">12dp</item>
+        <item name="paddingEnd">12dp</item>
         <item name="minWidth">@dimen/action_button_min_width_material</item>
         <item name="minHeight">@dimen/action_button_min_height_material</item>
         <item name="gravity">center</item>
         <item name="scaleType">center</item>
         <item name="maxLines">2</item>
-        <item name="paddingStart">12dp</item>
-        <item name="paddingEnd">12dp</item>
     </style>
 
     <style name="Widget.Material.ActionButton.CloseMode">
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
     </style>
 
     <style name="Widget.Material.ActionButton.Overflow">
@@ -879,34 +886,36 @@
         <item name="paddingEnd">@dimen/action_bar_overflow_padding_end_material</item>
     </style>
 
-    <style name="Widget.Material.ActionBar.TabView" parent="Widget.ActionBar.TabView">
+    <style name="Widget.Material.ActionBar.TabView" parent="Widget.Material">
+        <item name="gravity">center_horizontal</item>
         <item name="background">@drawable/tab_indicator_material</item>
         <item name="paddingStart">16dip</item>
         <item name="paddingEnd">16dip</item>
     </style>
 
-    <style name="Widget.Material.ActionBar.TabBar" parent="Widget.ActionBar.TabBar">
+    <style name="Widget.Material.ActionBar.TabBar" parent="Widget.Material">
         <item name="divider">?attr/actionBarDivider</item>
         <item name="showDividers">middle</item>
         <item name="dividerPadding">12dip</item>
     </style>
 
-    <style name="Widget.Material.ActionBar.TabText" parent="Widget.ActionBar.TabText">
-        <item name="textAppearance">@style/TextAppearance.Material.Medium</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textSize">12sp</item>
-        <item name="textStyle">bold</item>
-        <item name="textAllCaps">true</item>
+    <style name="Widget.Material.ActionBar.TabText">
+        <item name="textAppearance">@style/TextAppearance.Material.Widget.TabWidget</item>
         <item name="ellipsize">marquee</item>
         <item name="maxLines">2</item>
     </style>
 
-    <style name="Widget.Material.ActionBar" parent="Widget.ActionBar">
+    <style name="Widget.Material.ActionBar">
         <item name="background">@null</item>
         <item name="backgroundStacked">@null</item>
         <item name="backgroundSplit">@null</item>
         <item name="displayOptions">showTitle</item>
         <item name="divider">?attr/dividerVertical</item>
+        <item name="height">?attr/actionBarSize</item>
+        <item name="paddingStart">0dip</item>
+        <item name="paddingTop">0dip</item>
+        <item name="paddingEnd">0dip</item>
+        <item name="paddingBottom">0dip</item>
         <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Subtitle</item>
         <item name="progressBarStyle">?attr/progressBarStyleHorizontal</item>
@@ -927,19 +936,28 @@
         <item name="backgroundSplit">?attr/colorPrimary</item>
     </style>
 
-    <style name="Widget.Material.ActionMode" parent="Widget.ActionMode">
+    <style name="Widget.Material.ActionMode">
+        <item name="background">?attr/actionModeBackground</item>
+        <item name="backgroundSplit">?attr/actionModeSplitBackground</item>
+        <item name="height">?attr/actionBarSize</item>
         <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Subtitle</item>
         <item name="closeItemLayout">@layout/action_mode_close_item_material</item>
     </style>
 
-    <style name="Widget.Material.FastScroll" parent="Widget.FastScroll">
+    <style name="Widget.Material.FastScroll">
+        <item name="thumbDrawable">?attr/fastScrollThumbDrawable</item>
+        <item name="trackDrawable">?attr/fastScrollTrackDrawable</item>
+        <item name="backgroundLeft">?attr/fastScrollPreviewBackgroundLeft</item>
+        <item name="backgroundRight">?attr/fastScrollPreviewBackgroundRight</item>
+        <item name="position">?attr/fastScrollOverlayPosition</item>
+        <item name="textColor">?attr/fastScrollTextColor</item>
         <item name="thumbMinWidth">0dp</item>
         <item name="thumbMinHeight">0dp</item>
+        <item name="textSize">45sp</item>
         <item name="minWidth">88dp</item>
         <item name="minHeight">88dp</item>
         <item name="padding">0dp</item>
-        <item name="textSize">45sp</item>
     </style>
 
     <style name="Widget.Material.PreferenceFrameLayout">
@@ -950,7 +968,7 @@
     </style>
 
     <style name="Widget.Material.MediaRouteButton">
-        <item name="background">?attr/selectableItemBackgroundBorderless</item>
+        <item name="background">?attr/controlBackground</item>
         <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_material</item>
         <item name="minWidth">56dp</item>
         <item name="minHeight">48dp</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b417968..20ec563 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,7 @@
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
   <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+  <java-symbol type="bool" name="config_enableBurnInProtection" />
   <java-symbol type="bool" name="config_hotswapCapable" />
   <java-symbol type="bool" name="config_mms_content_disposition_support" />
   <java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -273,7 +274,6 @@
   <java-symbol type="bool" name="preferences_prefer_dual_pane" />
   <java-symbol type="bool" name="skip_restoring_network_selection" />
   <java-symbol type="bool" name="split_action_bar_is_narrow" />
-  <java-symbol type="bool" name="config_useMasterVolume" />
   <java-symbol type="bool" name="config_useVolumeKeySounds" />
   <java-symbol type="bool" name="config_enableWallpaperService" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
@@ -344,7 +344,13 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+  <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
+  <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
@@ -412,6 +418,8 @@
   <java-symbol type="dimen" name="notification_badge_size" />
   <java-symbol type="dimen" name="immersive_mode_cling_width" />
   <java-symbol type="dimen" name="circular_display_mask_offset" />
+  <java-symbol type="dimen" name="accessibility_magnification_indicator_width" />
+  <java-symbol type="dimen" name="circular_display_mask_thickness" />
 
   <java-symbol type="string" name="add_account_button_label" />
   <java-symbol type="string" name="addToDictionary" />
@@ -708,7 +716,6 @@
   <java-symbol type="string" name="noon" />
   <java-symbol type="string" name="number_picker_increment_scroll_action" />
   <java-symbol type="string" name="number_picker_increment_scroll_mode" />
-  <java-symbol type="string" name="numeric_date_template" />
   <java-symbol type="string" name="old_app_action" />
   <java-symbol type="string" name="old_app_description" />
   <java-symbol type="string" name="older" />
@@ -756,7 +763,9 @@
   <java-symbol type="string" name="policydesc_resetPassword" />
   <java-symbol type="string" name="policydesc_setGlobalProxy" />
   <java-symbol type="string" name="policydesc_watchLogin" />
+  <java-symbol type="string" name="policydesc_watchLogin_secondaryUser" />
   <java-symbol type="string" name="policydesc_wipeData" />
+  <java-symbol type="string" name="policydesc_wipeData_secondaryUser" />
   <java-symbol type="string" name="policydesc_disableKeyguardFeatures" />
   <java-symbol type="string" name="policylab_disableCamera" />
   <java-symbol type="string" name="policylab_encryptedStorage" />
@@ -767,6 +776,7 @@
   <java-symbol type="string" name="policylab_setGlobalProxy" />
   <java-symbol type="string" name="policylab_watchLogin" />
   <java-symbol type="string" name="policylab_wipeData" />
+  <java-symbol type="string" name="policylab_wipeData_secondaryUser" />
   <java-symbol type="string" name="policylab_disableKeyguardFeatures" />
   <java-symbol type="string" name="postalTypeCustom" />
   <java-symbol type="string" name="postalTypeHome" />
@@ -905,6 +915,9 @@
   <java-symbol type="string" name="wifi_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in_detailed" />
+  <java-symbol type="string" name="wifi_connect_alert_title" />
+  <java-symbol type="string" name="wifi_connect_alert_message" />
+  <java-symbol type="string" name="wifi_connect_default_application" />
   <java-symbol type="string" name="wifi_p2p_dialog_title" />
   <java-symbol type="string" name="wifi_p2p_enabled_notification_message" />
   <java-symbol type="string" name="wifi_p2p_enabled_notification_title" />
@@ -1058,27 +1071,11 @@
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
 
-  <java-symbol type="plurals" name="abbrev_in_num_days" />
-  <java-symbol type="plurals" name="abbrev_in_num_hours" />
-  <java-symbol type="plurals" name="abbrev_in_num_minutes" />
-  <java-symbol type="plurals" name="abbrev_in_num_seconds" />
-  <java-symbol type="plurals" name="abbrev_num_days_ago" />
-  <java-symbol type="plurals" name="abbrev_num_hours_ago" />
-  <java-symbol type="plurals" name="abbrev_num_minutes_ago" />
-  <java-symbol type="plurals" name="abbrev_num_seconds_ago" />
   <java-symbol type="plurals" name="duration_hours" />
   <java-symbol type="plurals" name="duration_minutes" />
   <java-symbol type="plurals" name="duration_seconds" />
-  <java-symbol type="plurals" name="in_num_days" />
-  <java-symbol type="plurals" name="in_num_hours" />
-  <java-symbol type="plurals" name="in_num_minutes" />
-  <java-symbol type="plurals" name="in_num_seconds" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
-  <java-symbol type="plurals" name="num_days_ago" />
-  <java-symbol type="plurals" name="num_hours_ago" />
-  <java-symbol type="plurals" name="num_minutes_ago" />
-  <java-symbol type="plurals" name="num_seconds_ago" />
   <java-symbol type="plurals" name="restr_pin_countdown" />
   <java-symbol type="plurals" name="pinpuk_attempts" />
 
@@ -1093,7 +1090,6 @@
   <java-symbol type="array" name="sim_colors" />
   <java-symbol type="array" name="special_locale_codes" />
   <java-symbol type="array" name="special_locale_names" />
-  <java-symbol type="array" name="config_masterVolumeRamp" />
   <java-symbol type="array" name="config_cdma_dun_supported_types" />
   <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
   <java-symbol type="array" name="config_operatorConsideredNonRoaming" />
@@ -1514,6 +1510,7 @@
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="string" name="system_ui_date_pattern" />
+  <java-symbol type="string" name="android_preparing_apk" />
   <java-symbol type="string" name="android_start_title" />
   <java-symbol type="string" name="android_upgrading_title" />
   <java-symbol type="string" name="bugreport_title" />
@@ -1530,6 +1527,7 @@
   <java-symbol type="string" name="global_action_silent_mode_on_status" />
   <java-symbol type="string" name="global_action_toggle_silent_mode" />
   <java-symbol type="string" name="global_action_lockdown" />
+  <java-symbol type="string" name="global_action_voice_assist" />
   <java-symbol type="string" name="invalidPuk" />
   <java-symbol type="string" name="lockscreen_carrier_default" />
   <java-symbol type="style" name="Animation.LockScreen" />
@@ -1587,6 +1585,7 @@
   <java-symbol type="bool" name="config_useAttentionLight" />
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
+  <java-symbol type="bool" name="config_autoBrightnessResetAmbientLuxAfterWarmUp" />
   <java-symbol type="bool" name="config_dozeAfterScreenOff" />
   <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
@@ -1608,6 +1607,7 @@
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
   <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
+  <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
   <java-symbol type="bool" name="config_wifi_background_scan_support" />
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
@@ -1617,6 +1617,7 @@
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="ic_settings" />
+  <java-symbol type="drawable" name="ic_voice_search" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled_data" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1641,6 +1642,9 @@
   <java-symbol type="id" name="replace_message" />
   <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
   <java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
+  <java-symbol type="integer" name="config_autoBrightnessBrighteningLightDebounce"/>
+  <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
+  <java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>
   <java-symbol type="integer" name="config_carDockKeepsScreenOn" />
   <java-symbol type="integer" name="config_criticalBatteryWarningLevel" />
   <java-symbol type="integer" name="config_datause_notification_type" />
@@ -1724,6 +1728,10 @@
   <java-symbol type="string" name="data_usage_wifi_limit_title" />
   <java-symbol type="string" name="default_wallpaper_component" />
   <java-symbol type="string" name="dlg_ok" />
+  <java-symbol type="string" name="dump_heap_notification" />
+  <java-symbol type="string" name="dump_heap_notification_detail" />
+  <java-symbol type="string" name="dump_heap_text" />
+  <java-symbol type="string" name="dump_heap_title" />
   <java-symbol type="string" name="factorytest_failed" />
   <java-symbol type="string" name="factorytest_no_action" />
   <java-symbol type="string" name="factorytest_not_system" />
@@ -1759,6 +1767,7 @@
   <java-symbol type="string" name="usb_notification_message" />
   <java-symbol type="string" name="use_physical_keyboard" />
   <java-symbol type="string" name="usb_ptp_notification_title" />
+  <java-symbol type="string" name="usb_midi_notification_title" />
   <java-symbol type="string" name="vpn_text" />
   <java-symbol type="string" name="vpn_text_long" />
   <java-symbol type="string" name="vpn_title" />
@@ -1973,10 +1982,8 @@
 
   <java-symbol type="attr" name="nestedScrollingEnabled" />
 
-  <java-symbol type="style" name="TextAppearance.Holo.TimePicker.TimeLabel" />
-
-  <java-symbol type="layout" name="time_picker_holo" />
-  <java-symbol type="layout" name="time_header_label" />
+  <java-symbol type="layout" name="time_picker_material" />
+  <java-symbol type="layout" name="time_picker_header_material" />
   <java-symbol type="layout" name="year_label_text_view" />
   <java-symbol type="layout" name="date_picker_holo" />
 
@@ -2002,21 +2009,16 @@
   <java-symbol type="string" name="select_hours" />
   <java-symbol type="string" name="select_minutes" />
   <java-symbol type="string" name="time_placeholder" />
-  <java-symbol type="string" name="timepicker_circle_radius_multiplier" />
-  <java-symbol type="string" name="timepicker_circle_radius_multiplier_24HourMode" />
-  <java-symbol type="string" name="timepicker_ampm_circle_radius_multiplier" />
   <java-symbol type="string" name="deleted_key" />
   <java-symbol type="string" name="sans_serif" />
   <java-symbol type="string" name="radial_numbers_typeface" />
-  <java-symbol type="string" name="timepicker_text_size_multiplier_inner" />
-  <java-symbol type="string" name="timepicker_text_size_multiplier_outer" />
-  <java-symbol type="string" name="timepicker_text_size_multiplier_normal" />
-  <java-symbol type="string" name="timepicker_numbers_radius_multiplier_outer" />
-  <java-symbol type="string" name="timepicker_selection_radius_multiplier" />
-  <java-symbol type="string" name="timepicker_numbers_radius_multiplier_inner" />
-  <java-symbol type="string" name="timepicker_numbers_radius_multiplier_normal" />
-  <java-symbol type="string" name="timepicker_transition_mid_radius_multiplier" />
-  <java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
+  <java-symbol type="dimen" name="timepicker_selector_radius" />
+  <java-symbol type="dimen" name="timepicker_selector_dot_radius" />
+  <java-symbol type="dimen" name="timepicker_center_dot_radius" />
+  <java-symbol type="dimen" name="timepicker_text_inset_normal" />
+  <java-symbol type="dimen" name="timepicker_text_inset_inner" />
+  <java-symbol type="dimen" name="timepicker_text_size_normal" />
+  <java-symbol type="dimen" name="timepicker_text_size_inner" />
   <java-symbol type="string" name="battery_saver_description" />
   <java-symbol type="string" name="downtime_condition_summary" />
   <java-symbol type="string" name="downtime_condition_line_one" />
@@ -2044,30 +2046,16 @@
   <java-symbol type="dimen" name="datepicker_month_label_size" />
   <java-symbol type="dimen" name="datepicker_month_day_label_text_size" />
   <java-symbol type="dimen" name="datepicker_month_list_item_header_height" />
-  <java-symbol type="dimen" name="datepicker_day_number_select_circle_radius" />
   <java-symbol type="dimen" name="datepicker_view_animator_height" />
   <java-symbol type="dimen" name="datepicker_year_label_height" />
   <java-symbol type="dimen" name="datepicker_year_picker_padding_top" />
 
-  <java-symbol type="color" name="timepicker_default_text_color_holo_light" />
-  <java-symbol type="color" name="timepicker_default_ampm_unselected_background_color_holo_light" />
-  <java-symbol type="color" name="timepicker_default_ampm_selected_background_color_holo_light" />
-
-  <java-symbol type="color" name="datepicker_default_normal_text_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_disabled_text_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_circle_background_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_header_dayofweek_background_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_header_selector_background_holo_light" />
-
-  <java-symbol type="color" name="datepicker_default_normal_text_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_disabled_text_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_circle_background_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_header_dayofweek_background_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_header_selector_background_material_light" />
-
   <java-symbol type="array" name="config_clockTickVibePattern" />
   <java-symbol type="array" name="config_calendarDateVibePattern" />
 
+  <!-- From KeyguardServiceDelegate -->
+  <java-symbol type="string" name="config_keyguardComponent" />
+
   <!-- From various Material changes -->
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
@@ -2112,8 +2100,6 @@
   <java-symbol type="attr" name="ambientShadowAlpha" />
   <java-symbol type="attr" name="spotShadowAlpha" />
   <java-symbol type="array" name="config_cdma_home_system" />
-  <java-symbol type="attr" name="headerSelectedTextColor" />
-  <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
   <java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
   <java-symbol type="dimen" name="text_size_small_material" />
   <java-symbol type="attr" name="checkMarkGravity" />
@@ -2162,4 +2148,20 @@
   <java-symbol type="bool" name="config_use_sim_language_file" />
   <java-symbol type="bool" name="config_LTE_eri_for_network_name" />
   <java-symbol type="bool" name="config_defaultInTouchMode" />
+
+  <java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
+  <java-symbol type="string" name="usb_midi_peripheral_model_name" />
+
+  <java-symbol type="bool" name="allow_stacked_button_bar" />
+  <java-symbol type="id" name="spacer" />
+
+  <java-symbol type="xml" name="bookmarks" />
+
+  <java-symbol type="integer" name="config_defaultNightMode" />
+
+  <java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
+
+  <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
+  <java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" />
+  <java-symbol type="dimen" name="timepicker_selector_stroke"/>
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 4ba6c0b..9e87b4d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -45,6 +45,7 @@
         <item name="colorForeground">@color/bright_foreground_dark</item>
         <item name="colorForegroundInverse">@color/bright_foreground_dark_inverse</item>
         <item name="colorBackground">@color/background_dark</item>
+        <item name="colorBackgroundFloating">?attr/colorBackground</item>
         <item name="colorBackgroundCacheHint">?attr/colorBackground</item>
 
         <item name="colorPressedHighlight">@color/legacy_pressed_highlight</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index c30b3d5..701d0ef 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -65,6 +65,7 @@
         <item name="colorForeground">@color/bright_foreground_holo_dark</item>
         <item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_dark</item>
         <item name="colorBackground">@color/background_holo_dark</item>
+        <item name="colorBackgroundFloating">@color/background_holo_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_dark</item>
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
@@ -404,6 +405,7 @@
         <item name="colorForeground">@color/bright_foreground_holo_light</item>
         <item name="colorForegroundInverse">@color/bright_foreground_inverse_holo_light</item>
         <item name="colorBackground">@color/background_holo_light</item>
+        <item name="colorBackgroundFloating">@color/background_holo_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_holo_light</item>
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9690238..38cfecd 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -42,9 +42,10 @@
          with trailing _dark or _light specifiers if they are not shared between both light and
          dark versions of the theme. -->
     <style name="Theme.Material">
-        <item name="colorForeground">@color/bright_foreground_material_dark</item>
-        <item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
+        <item name="colorForeground">@color/foreground_material_dark</item>
+        <item name="colorForegroundInverse">@color/foreground_material_light</item>
         <item name="colorBackground">@color/background_material_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
@@ -64,8 +65,8 @@
         <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
         <item name="textColorHint">@color/hint_foreground_material_dark</item>
         <item name="textColorHintInverse">@color/hint_foreground_material_light</item>
-        <item name="textColorHighlight">@color/highlighted_text_material_dark</item>
-        <item name="textColorHighlightInverse">@color/highlighted_text_material_light</item>
+        <item name="textColorHighlight">@color/highlighted_text_material</item>
+        <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorLink">@color/link_text_material_dark</item>
         <item name="textColorLinkInverse">@color/link_text_material_light</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
@@ -128,8 +129,8 @@
         <item name="listChoiceIndicatorSingle">@drawable/btn_radio_material_anim</item>
         <item name="listChoiceIndicatorMultiple">@drawable/btn_check_material_anim</item>
 
-        <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item>
-        <item name="activatedBackgroundIndicator">@drawable/activated_background_material</item>
+        <item name="listChoiceBackgroundIndicator">@drawable/list_highlight_material</item>
+        <item name="activatedBackgroundIndicator">@null</item>
 
         <item name="listDividerAlertDialog">@null</item>
 
@@ -174,14 +175,14 @@
         <item name="windowSharedElementExitTransition">@transition/move</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@style/Theme.Material.Dialog</item>
+        <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+        <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="alertDialogStyle">@style/AlertDialog.Material</item>
         <item name="alertDialogCenterButtons">false</item>
         <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -276,6 +277,7 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Material.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@style/Widget.Material.ListPopupWindow</item>
         <item name="popupMenuStyle">@style/Widget.Material.PopupMenu</item>
+        <item name="popupTheme">@null</item>
         <item name="stackViewStyle">@style/Widget.Material.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
@@ -324,9 +326,9 @@
         <item name="actionMenuTextAppearance">@style/TextAppearance.Material.Widget.ActionBar.Menu</item>
         <item name="actionMenuTextColor">?attr/textColorPrimary</item>
         <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarPopupTheme">@null</item>
+        <item name="actionBarPopupTheme">?attr/popupTheme</item>
         <item name="actionBarTheme">@style/ThemeOverlay.Material.ActionBar</item>
-        <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
+        <item name="actionBarItemBackground">@drawable/action_bar_item_background_material</item>
 
         <item name="actionModeCutDrawable">@drawable/ic_menu_cut_material</item>
         <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_material</item>
@@ -388,13 +390,16 @@
         <item name="colorControlHighlight">@color/ripple_material_dark</item>
         <item name="colorButtonNormal">@color/btn_default_material_dark</item>
         <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
+
+        <item name="controlBackground">@drawable/control_background_material</item>
     </style>
 
     <!-- Material theme (light version). -->
     <style name="Theme.Material.Light" parent="Theme.Light">
-        <item name="colorForeground">@color/bright_foreground_material_light</item>
-        <item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
+        <item name="colorForeground">@color/foreground_material_light</item>
+        <item name="colorForegroundInverse">@color/foreground_material_dark</item>
         <item name="colorBackground">@color/background_material_light</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
         <item name="backgroundDimAmount">0.6</item>
@@ -415,8 +420,8 @@
         <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorHint">@color/hint_foreground_material_light</item>
         <item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
-        <item name="textColorHighlight">@color/highlighted_text_material_light</item>
-        <item name="textColorHighlightInverse">@color/highlighted_text_material_dark</item>
+        <item name="textColorHighlight">@color/highlighted_text_material</item>
+        <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorLink">@color/link_text_material_light</item>
         <item name="textColorLinkInverse">@color/link_text_material_dark</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
@@ -526,14 +531,14 @@
         <item name="windowActivityTransitions">true</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
+        <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
+        <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="alertDialogStyle">@style/AlertDialog.Material.Light</item>
         <item name="alertDialogCenterButtons">false</item>
         <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -677,9 +682,8 @@
         <item name="actionBarSize">@dimen/action_bar_default_height_material</item>
         <item name="actionModePopupWindowStyle">@style/Widget.Material.Light.PopupWindow.ActionMode</item>
         <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarPopupTheme">@null</item>
         <item name="actionBarTheme">@style/ThemeOverlay.Material.ActionBar</item>
-        <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
+        <item name="actionBarItemBackground">@drawable/action_bar_item_background_material</item>
 
         <item name="actionModeCutDrawable">@drawable/ic_menu_cut_material</item>
         <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_material</item>
@@ -693,7 +697,7 @@
 
         <item name="dividerVertical">?attr/listDivider</item>
         <item name="dividerHorizontal">?attr/listDivider</item>
-        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar</item>
+        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
         <item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
         <item name="segmentedButtonStyle">@style/Widget.Material.Light.SegmentedButton</item>
 
@@ -736,6 +740,8 @@
         <item name="colorControlHighlight">@color/ripple_material_light</item>
         <item name="colorButtonNormal">@color/btn_default_material_light</item>
         <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+
+        <item name="controlBackground">@drawable/control_background_material</item>
     </style>
 
     <!-- Variant of the material (light) theme that has a solid (opaque) action bar
@@ -744,21 +750,29 @@
     <style name="Theme.Material.Light.DarkActionBar">
         <item name="actionBarWidgetTheme">@null</item>
         <item name="actionBarTheme">@style/ThemeOverlay.Material.Dark.ActionBar</item>
-        <item name="actionBarPopupTheme">@style/ThemeOverlay.Material.Light</item>
+        <item name="popupTheme">@style/ThemeOverlay.Material.Light</item>
 
         <item name="colorPrimaryDark">@color/primary_dark_material_dark</item>
         <item name="colorPrimary">@color/primary_material_dark</item>
     </style>
 
+    <!-- Variant of the material (light) theme that has a light status bar background with dark
+         status bar contents. -->
+    <style name="Theme.Material.Light.LightStatusBar">
+        <item name="colorPrimaryDark">@color/primary_dark_material_light_light_status_bar</item>
+        <item name="windowHasLightStatusBar">true</item>
+    </style>
+
     <style name="ThemeOverlay" />
     <style name="ThemeOverlay.Material" />
 
     <!-- Theme overlay that replaces colors with their light versions but preserves
          the value of colorAccent, colorPrimary and its variants. -->
     <style name="ThemeOverlay.Material.Light">
-        <item name="colorForeground">@color/bright_foreground_material_light</item>
-        <item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
+        <item name="colorForeground">@color/foreground_material_light</item>
+        <item name="colorForegroundInverse">@color/foreground_material_dark</item>
         <item name="colorBackground">@color/background_material_light</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
 
         <item name="textColorPrimary">@color/primary_text_material_light</item>
@@ -773,8 +787,8 @@
         <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorHint">@color/hint_foreground_material_light</item>
         <item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
-        <item name="textColorHighlight">@color/highlighted_text_material_light</item>
-        <item name="textColorHighlightInverse">@color/highlighted_text_material_dark</item>
+        <item name="textColorHighlight">@color/highlighted_text_material</item>
+        <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorLink">@color/link_text_material_light</item>
         <item name="textColorLinkInverse">@color/link_text_material_dark</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
@@ -792,9 +806,10 @@
     <!-- Theme overlay that replaces colors with their dark versions but preserves
          the value of colorAccent, colorPrimary and its variants. -->
     <style name="ThemeOverlay.Material.Dark">
-        <item name="colorForeground">@color/bright_foreground_material_dark</item>
-        <item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
+        <item name="colorForeground">@color/foreground_material_dark</item>
+        <item name="colorForegroundInverse">@color/foreground_material_light</item>
         <item name="colorBackground">@color/background_material_dark</item>
+        <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
 
         <item name="textColorPrimary">@color/primary_text_material_dark</item>
@@ -808,8 +823,8 @@
         <item name="textColorTertiaryInverse">@color/secondary_text_material_light</item>
         <item name="textColorHint">@color/hint_foreground_material_dark</item>
         <item name="textColorHintInverse">@color/hint_foreground_material_light</item>
-        <item name="textColorHighlight">@color/highlighted_text_material_dark</item>
-        <item name="textColorHighlightInverse">@color/highlighted_text_material_light</item>
+        <item name="textColorHighlight">@color/highlighted_text_material</item>
+        <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorLink">@color/link_text_material_dark</item>
         <item name="textColorLinkInverse">@color/link_text_material_light</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
@@ -828,7 +843,7 @@
          secondary text color, with the primary text color. -->
     <style name="ThemeOverlay.Material.ActionBar">
         <item name="colorControlNormal">?attr/textColorPrimary</item>
-        <item name="searchViewStyle">@style/Widget.Material.Light.SearchView.ActionBar</item>
+        <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
     </style>
 
     <!-- Theme overlay that replaces colors with their dark versions and replaces the normal
@@ -839,6 +854,33 @@
         <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
     </style>
 
+    <!-- Theme overlay that overrides window properties to display as a dialog. -->
+    <style name="ThemeOverlay.Material.Dialog">
+        <item name="colorBackgroundCacheHint">@null</item>
+
+        <item name="windowFrame">@null</item>
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+        <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
+        <item name="windowBackground">@drawable/dialog_background_material</item>
+        <item name="windowElevation">@dimen/floating_window_z</item>
+        <item name="windowIsFloating">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+        <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+        <item name="windowActionBar">false</item>
+        <item name="windowActionModeOverlay">true</item>
+        <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+        <item name="listPreferredItemPaddingLeft">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingRight">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+
+        <item name="listDivider">@null</item>
+
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+
     <!-- Variant of the material (dark) theme with no action bar. -->
     <style name="Theme.Material.NoActionBar">
         <item name="windowActionBar">false</item>
@@ -968,8 +1010,12 @@
          {@link android.service.voice.VoiceInteractionSession} class.
          this inherits from Theme.Panel, but sets up appropriate animations
          and a few custom attributes. -->
-    <style name="Theme.Material.VoiceInteractionSession" parent="Theme.Material.Light.Panel">
-        <item name="windowAnimationStyle">@style/Animation.VoiceInteractionSession</item>
+    <style name="Theme.Material.VoiceInteractionSession"
+           parent="Theme.Material.Light.NoActionBar.TranslucentDecor">
+        <item name="windowBackground">@color/transparent</item>
+        <item name="colorBackgroundCacheHint">@null</item>
+        <item name="windowIsTranslucent">true</item>
+        <item name="windowAnimationStyle">@style/Animation</item>
     </style>
 
     <!-- Theme for the search input bar. -->
@@ -1001,7 +1047,7 @@
     <eat-comment />
 
     <style name="Theme.Material.BaseDialog">
-        <item name="colorBackground">@color/background_floating_material_dark</item>
+        <item name="colorBackground">?attr/colorBackgroundFloating</item>
 
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
@@ -1018,12 +1064,6 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="buttonBarStyle">@style/Widget.Material.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@style/Widget.Material.Button.Borderless</item>
-
-        <item name="textAppearance">@style/TextAppearance.Material</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
         <item name="listPreferredItemPaddingLeft">24dip</item>
         <item name="listPreferredItemPaddingRight">24dip</item>
         <item name="listPreferredItemPaddingStart">24dip</item>
@@ -1118,7 +1158,7 @@
     <!-- Light material dialog themes -->
 
     <style name="Theme.Material.Light.BaseDialog">
-        <item name="colorBackground">@color/background_floating_material_light</item>
+        <item name="colorBackground">?attr/colorBackgroundFloating</item>
 
         <item name="windowFrame">@null</item>
         <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
@@ -1135,12 +1175,6 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
-
-        <item name="textAppearance">@style/TextAppearance.Material</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
         <item name="listPreferredItemPaddingLeft">24dip</item>
         <item name="listPreferredItemPaddingRight">24dip</item>
         <item name="listPreferredItemPaddingStart">24dip</item>
@@ -1234,21 +1268,17 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
 
-        <item name="dialogTheme">@style/Theme.Material.Settings.Dialog</item>
-        <item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
         <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
         <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
     </style>
 
-    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1256,8 +1286,7 @@
 
     <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
 
-    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
@@ -1265,22 +1294,19 @@
 
     <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
 
-    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
     </style>
 
-    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
     </style>
 
-    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
-        <item name="colorBackground">@color/white</item>
+    <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
         <item name="colorPrimary">@color/material_blue_grey_900</item>
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
diff --git a/core/res/res/values/themes_material_daynight.xml b/core/res/res/values/themes_material_daynight.xml
new file mode 100644
index 0000000..5d9b860
--- /dev/null
+++ b/core/res/res/values/themes_material_daynight.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        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>
+
+    <!-- Material theme (day/night vesion) for activities. -->
+    <style name="Theme.Material.DayNight" parent="Theme.Material.Light" />
+
+    <!-- Variant of Material.DayNight that has a solid (opaque) action bar
+         with an inverse color profile. The dark action bar sharply stands out against
+         the light content (when applicable).  -->
+    <style name="Theme.Material.DayNight.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
+
+    <!-- Variant of Material.DayNight with no action bar.  -->
+    <style name="Theme.Material.DayNight.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen. This theme
+         sets {@link android.R.attr#windowFullscreen} to true.  -->
+    <style name="Theme.Material.DayNight.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
+
+    <!-- Variant of Material.DayNight that has no title bar and fills
+         the entire screen and extends into the display overscan region. This theme
+         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+         to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
+
+    <!-- Variant of Material.DayNight that has no title bar and translucent
+         system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+         {@link android.R.attr#windowTranslucentNavigation} to true. -->
+    <style name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
+
+    <!-- Default Material.DayNight theme for panel windows. This removes all extraneous
+         window decorations, so you basically have an empty rectangle in which
+         to place your content. It makes the window floating, with a transparent
+         background, and turns off dimming behind the window. -->
+    <style name="Theme.Material.DayNight.Panel" parent="Theme.Material.Light.Panel" />
+
+    <!-- Material theme (day/night vesion) for dialog windows and activities,
+         which is used by the {@link android.app.Dialog} class. This changes
+         the window to be floating (not fill the entire screen), and puts a
+         frame around its contents. You can set this theme on an activity if
+         you would like to make an activity that looks like a Dialog. -->
+    <style name="Theme.Material.DayNight.Dialog" parent="Theme.Material.DayNight.BaseDialog" />
+    <style name="Theme.Material.DayNight.BaseDialog" parent="Theme.Material.Light.BaseDialog" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that does not include a title bar. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a nice minimum width for
+         a regular dialog. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.FixedSize" parent="Theme.Material.Light.Dialog.FixedSize" />
+
+    <!-- Variant of Theme.Material.DayNight.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Material.DayNight.Dialog.NoActionBar.FixedSize" parent="Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+
+    <!-- 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.DayNight.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
+
+    <!-- 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.DayNight.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
+
+    <!-- Theme for a presentation window on a secondary display. -->
+    <style name="Theme.Material.DayNight.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
+
+    <!-- Material user theme for alert dialog windows, which is used by the
+         {@link android.app.AlertDialog} class. -->
+    <style name="Theme.Material.DayNight.Dialog.Alert" parent="Theme.Material.DayNight.Dialog.BaseAlert" />
+    <style name="Theme.Material.DayNight.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert" />
+
+    <style name="Theme.Material.DayNight.SearchBar" parent="Theme.Material.Light.SearchBar" />
+    <style name="Theme.Material.DayNight.CompactMenu" parent="Theme.Material.Light.CompactMenu" />
+
+</resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 1ebc708..e730dff 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,9 +24,6 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
@@ -42,9 +39,6 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml
new file mode 100644
index 0000000..454f456
--- /dev/null
+++ b/core/res/res/xml/bookmarks.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!--
+     Default system bookmarks for AOSP.
+     Bookmarks for vendor apps should be added to a bookmarks resource overlay; not here.
+
+     Typical shortcuts (not necessarily defined here):
+       'a': Calculator
+       'b': Browser
+       'c': Contacts
+       'e': Email
+       'g': GMail
+       'l': Calendar
+       'm': Maps
+       'p': Music
+       's': SMS
+       't': Talk
+       'y': YouTube
+-->
+<bookmarks>
+    <bookmark
+        category="android.intent.category.APP_CALCULATOR"
+        shortcut="a" />
+    <bookmark
+        category="android.intent.category.APP_BROWSER"
+        shortcut="b" />
+    <bookmark
+        category="android.intent.category.APP_CONTACTS"
+        shortcut="c" />
+    <bookmark
+        category="android.intent.category.APP_EMAIL"
+        shortcut="e" />
+    <bookmark
+        category="android.intent.category.APP_CALENDAR"
+        shortcut="l" />
+    <bookmark
+        category="android.intent.category.APP_MAPS"
+        shortcut="m" />
+    <bookmark
+        category="android.intent.category.APP_MUSIC"
+        shortcut="p" />
+    <bookmark
+        category="android.intent.category.APP_MESSAGING"
+        shortcut="s" />
+</bookmarks>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7804dd2..18c83b4 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -75,7 +75,7 @@
     <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
 
     <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
-    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}" />
+    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215" />
 
     <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
     <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" />
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
index 6871efd..cb44721 100644
--- a/core/tests/bandwidthtests/Android.mk
+++ b/core/tests/bandwidthtests/Android.mk
@@ -22,9 +22,9 @@
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 LOCAL_PACKAGE_NAME := BandwidthTests
 
 include $(BUILD_PACKAGE)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/bandwidthtests/AndroidManifest.xml b/core/tests/bandwidthtests/AndroidManifest.xml
index 24221bc..d0a6198 100644
--- a/core/tests/bandwidthtests/AndroidManifest.xml
+++ b/core/tests/bandwidthtests/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <application >
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
     </application>
 
     <instrumentation
diff --git a/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java b/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java
new file mode 100644
index 0000000..2858128
--- /dev/null
+++ b/core/tests/benchmarks/src/android/util/FloatMathBenchmark.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import com.google.caliper.Param;
+import com.google.caliper.Runner;
+import com.google.caliper.SimpleBenchmark;
+
+import android.util.FloatMath;
+
+public class FloatMathBenchmark extends SimpleBenchmark {
+
+    public float timeFloatMathCeil(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.ceil(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathCeil_math(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += (float) Math.ceil(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathCos(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.cos(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathExp(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.exp(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathFloor(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.floor(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathHypot(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.hypot(100.123f, 100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathPow(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.pow(10.123f, 10.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathSin(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.sin(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathSqrt(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += FloatMath.sqrt(100.123f);
+        }
+        return f;
+    }
+
+    public float timeFloatMathSqrt_math(int reps) {
+        // Keep an answer so we don't optimize the method call away.
+        float f = 0.0f;
+        for (int i = 0; i < reps; i++) {
+            f += (float) Math.sqrt(100.123f);
+        }
+        return f;
+    }
+
+}
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 6bdeaf0..79a0b0c 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_DX_FLAGS := --core-library
 LOCAL_AAPT_FLAGS = -0 dat -0 gld
 LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support android-common frameworks-core-util-lib mockwebserver guava littlemock mockito-target
-LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common
+LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
 
 LOCAL_CERTIFICATE := platform
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 226717e..bfaea8f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -112,6 +112,7 @@
 
     <application android:theme="@style/Theme">
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
         <activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.mk b/core/tests/coretests/apks/install_bad_dex/Android.mk
index 769a1b0..05983aa 100644
--- a/core/tests/coretests/apks/install_bad_dex/Android.mk
+++ b/core/tests/coretests/apks/install_bad_dex/Android.mk
@@ -5,6 +5,7 @@
 
 LOCAL_PACKAGE_NAME := install_bad_dex
 
-LOCAL_JAVA_RESOURCE_FILES := $(LOCAL_PATH)/classes.dex
-
 include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+# Override target specific variable PRIVATE_DEX_FILE to inject bad classes.dex file.
+$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(LOCAL_PATH)/classes.dex
diff --git a/core/tests/coretests/res/layout/size_adaptive.xml b/core/tests/coretests/res/layout/size_adaptive.xml
deleted file mode 100644
index 03d0574..0000000
--- a/core/tests/coretests/res/layout/size_adaptive.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/multi1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_color.xml b/core/tests/coretests/res/layout/size_adaptive_color.xml
deleted file mode 100644
index cdb7a59..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_color.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="#ffffff"
-    android:id="@+id/multi1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_color_statelist.xml b/core/tests/coretests/res/layout/size_adaptive_color_statelist.xml
deleted file mode 100644
index d24df5b..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_color_statelist.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@drawable/size_adaptive_statelist"
-    android:id="@+id/multi1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u.xml b/core/tests/coretests/res/layout/size_adaptive_four_u.xml
deleted file mode 100644
index 232b921..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_four_u.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/gridLayout4"
-    android:layout_width="match_parent"
-    android:layout_height="256dp"
-    android:background="#000000"
-    android:columnCount="2"
-    android:padding="1dp" >
-
-    <ImageView
-        android:id="@+id/actor"
-        android:layout_width="62dp"
-        android:layout_height="62dp"
-        android:layout_row="0"
-        android:layout_column="0"
-        android:layout_rowSpan="2"
-        android:contentDescription="@string/actor"
-        android:src="@drawable/abe" />
-
-    <TextView
-        android:layout_width="0dp"
-        android:id="@+id/name"
-        android:layout_row="0"
-        android:layout_column="1"
-        android:layout_gravity="fill_horizontal"
-        android:padding="3dp"
-        android:text="@string/actor"
-        android:textColor="#ffffff"
-        android:textStyle="bold" />
-
-    <ImageView
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_row="1"
-        android:layout_column="1"
-        android:layout_gravity="fill_horizontal"
-        android:padding="5dp"
-        android:adjustViewBounds="true"
-        android:background="#555555"
-        android:scaleType="centerCrop"
-        android:src="@drawable/gettysburg"
-        android:contentDescription="@string/caption" />
-
-    <TextView
-        android:layout_width="0dp"
-        android:id="@+id/note"
-        android:layout_row="2"
-        android:layout_column="1"
-        android:layout_gravity="fill_horizontal"
-        android:padding="3dp"
-        android:singleLine="true"
-        android:text="@string/first"
-        android:textColor="#ffffff" />
-</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
deleted file mode 100644
index 93a10de..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/gridLayout4"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:background="#000000"
-    android:columnCount="2"
-    android:padding="1dp"
-    android:orientation="horizontal" >
-
-    <ImageView
-        android:id="@+id/actor"
-        android:layout_width="62dp"
-        android:layout_height="62dp"
-        android:layout_row="0"
-        android:layout_column="0"
-        android:layout_rowSpan="2"
-        android:contentDescription="@string/actor"
-        android:src="@drawable/abe" />
-
-    <TextView
-        android:layout_width="0dp"
-        android:id="@+id/name"
-        android:layout_row="0"
-        android:layout_column="1"
-        android:layout_gravity="fill_horizontal"
-        android:padding="3dp"
-        android:text="@string/actor"
-        android:textColor="#ffffff"
-        android:textStyle="bold" />
-
-    <TextView
-        android:id="@+id/note"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_column="1"
-        android:layout_gravity="fill_horizontal"
-        android:layout_marginTop="5dp"
-        android:layout_row="1"
-        android:padding="3dp"
-        android:singleLine="false"
-        android:text="@string/first"
-        android:textColor="#ffffff" />
-
-    </GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_gappy.xml b/core/tests/coretests/res/layout/size_adaptive_gappy.xml
deleted file mode 100644
index d5e3b41..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_gappy.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/multi_with_gap"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="256dp"
-        internal:layout_minHeight="128dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_large_only.xml b/core/tests/coretests/res/layout/size_adaptive_large_only.xml
deleted file mode 100644
index cf58265..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_large_only.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/large_only_multi"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="256dp"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_lies.xml b/core/tests/coretests/res/layout/size_adaptive_lies.xml
deleted file mode 100644
index 7de892e..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_lies.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/multi1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u.xml b/core/tests/coretests/res/layout/size_adaptive_one_u.xml
deleted file mode 100644
index b6fe4a0..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_one_u.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/gridLayout1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp"
-    android:background="#000000"
-    android:columnCount="3"
-    android:padding="1dp"
-    android:rowCount="2" >
-
-    <ImageView
-        android:id="@+id/actor"
-        android:layout_width="62dp"
-        android:layout_height="62dp"
-        android:layout_column="0"
-        android:layout_row="0"
-        android:layout_rowSpan="2"
-        android:contentDescription="@string/actor"
-        android:src="@drawable/abe" />
-
-    <TextView
-        android:id="@+id/name"
-        android:layout_gravity="fill"
-        android:padding="3dp"
-        android:text="@string/actor"
-        android:textColor="#ffffff"
-        android:textStyle="bold" />
-
-    <ImageView
-        android:layout_width="62dp"
-        android:layout_height="62dp"
-        android:layout_gravity="fill_vertical"
-        android:layout_rowSpan="2"
-        android:adjustViewBounds="true"
-        android:background="#555555"
-        android:padding="2dp"
-        android:scaleType="fitXY"
-        android:src="@drawable/gettysburg"
-        android:contentDescription="@string/caption" />
-
-    <TextView
-        android:id="@+id/note"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_gravity="fill"
-        android:layout_marginTop="5dp"
-        android:padding="3dp"
-        android:singleLine="true"
-        android:text="@string/first"
-        android:textColor="#ffffff" />
-
-</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
deleted file mode 100644
index df54eb6..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/gridLayout1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp"
-    android:background="#000000"
-    android:columnCount="2"
-    android:padding="1dp"
-    android:rowCount="2" >
-
-    <ImageView
-        android:id="@+id/actor"
-        android:layout_width="62dp"
-        android:layout_height="62dp"
-        android:layout_column="0"
-        android:layout_row="0"
-        android:layout_rowSpan="2"
-        android:contentDescription="@string/actor"
-        android:src="@drawable/abe" />
-
-    <TextView
-        android:id="@+id/name"
-        android:layout_gravity="fill"
-        android:padding="3dp"
-        android:text="@string/actor"
-        android:textColor="#ffffff"
-        android:textStyle="bold" />
-
-    <TextView
-        android:id="@+id/note"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_gravity="fill"
-        android:layout_marginTop="5dp"
-        android:padding="3dp"
-        android:singleLine="true"
-        android:text="@string/first"
-        android:textColor="#ffffff" />
-
-</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_overlapping.xml b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
deleted file mode 100644
index 4abe8b0..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/multi_with_overlap"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="256dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="256dp"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_singleton.xml b/core/tests/coretests/res/layout/size_adaptive_singleton.xml
deleted file mode 100644
index eba387f..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_singleton.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u_text"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_text.xml b/core/tests/coretests/res/layout/size_adaptive_text.xml
deleted file mode 100644
index a9f0ba9..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_text.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/multi1"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u_text"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u_text"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_three_way.xml b/core/tests/coretests/res/layout/size_adaptive_three_way.xml
deleted file mode 100644
index 1eb5396..0000000
--- a/core/tests/coretests/res/layout/size_adaptive_three_way.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.internal.widget.SizeAdaptiveLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/three_way_multi"
-    android:layout_width="match_parent"
-    android:layout_height="64dp" >
-
-    <include
-        android:id="@+id/one_u"
-        layout="@layout/size_adaptive_one_u"
-        android:layout_width="fill_parent"
-        android:layout_height="64dp"
-        internal:layout_minHeight="64dp"
-        internal:layout_maxHeight="64dp"
-        />
-
-    <include
-        android:id="@+id/two_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="128dp"
-        internal:layout_minHeight="65dp"
-        internal:layout_maxHeight="128dp"/>
-
-    <include
-        android:id="@+id/four_u"
-        layout="@layout/size_adaptive_four_u"
-        android:layout_width="fill_parent"
-        android:layout_height="256dp"
-        internal:layout_minHeight="129dp"
-        internal:layout_maxHeight="unbounded"/>
-
-</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index dc43a2f..a59581b 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -425,7 +425,7 @@
             if (rLoc == INSTALL_LOC_INT) {
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                     assertStartsWith("The APK path should point to the ASEC",
                             SECURE_CONTAINERS_PREFIX, srcPath);
                     assertStartsWith("The public APK path should point to the ASEC",
@@ -441,7 +441,8 @@
                         fail("compat check: Can't read " + info.dataDir + "/lib");
                     }
                 } else {
-                    assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                    assertFalse(
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                     assertEquals(appInstallPath, srcPath);
                     assertEquals(appInstallPath, publicSrcPath);
                     assertStartsWith("Native library should point to shared lib directory",
@@ -467,16 +468,16 @@
             } else if (rLoc == INSTALL_LOC_SD) {
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                 } else {
                     assertFalse("The application should not be installed forward locked",
-                            (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+                            (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0);
                 }
                 assertTrue("Application flags (" + info.flags
                         + ") should contain FLAG_EXTERNAL_STORAGE",
                         (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 // Might need to check:
-                // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
+                // ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0)
                 assertStartsWith("The APK path should point to the ASEC",
                         SECURE_CONTAINERS_PREFIX, srcPath);
                 assertStartsWith("The public APK path should point to the ASEC",
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
new file mode 100644
index 0000000..32b4557
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm;
+
+import android.content.res.Resources;
+import android.os.FileUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests for {@link android.content.pm.RegisteredServicesCache}
+ */
+public class RegisteredServicesCacheTest extends AndroidTestCase {
+    private static final int U0 = 0;
+    private static final int U1 = 1;
+    private static final int UID1 = 1;
+    private static final int UID2 = 2;
+    // Represents UID of a system image process
+    private static final int SYSTEM_IMAGE_UID = 20;
+
+    private final ResolveInfo r1 = new ResolveInfo();
+    private final ResolveInfo r2 = new ResolveInfo();
+    private final TestServiceType t1 = new TestServiceType("t1", "value1");
+    private final TestServiceType t2 = new TestServiceType("t2", "value2");
+    private File mDataDir;
+    private File mSyncDir;
+    private List<UserInfo> mUsers;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        File cacheDir = mContext.getCacheDir();
+        mDataDir = new File(cacheDir, "testServicesCache");
+        FileUtils.deleteContents(mDataDir);
+        mSyncDir = new File(mDataDir, "system/"+RegisteredServicesCache.REGISTERED_SERVICES_DIR);
+        mSyncDir.mkdirs();
+        mUsers = new ArrayList<>();
+        mUsers.add(new UserInfo(0, "Owner", UserInfo.FLAG_ADMIN));
+        mUsers.add(new UserInfo(1, "User1", 0));
+    }
+
+    public void testGetAllServicesHappyPath() {
+        TestServicesCache cache = new TestServicesCache();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2));
+        assertEquals(2, cache.getAllServicesSize(U0));
+        assertEquals(2, cache.getPersistentServicesSize(U0));
+        assertNotEmptyFileCreated(cache, U0);
+        // Make sure all services can be loaded from xml
+        cache = new TestServicesCache();
+        assertEquals(2, cache.getPersistentServicesSize(U0));
+    }
+
+    public void testGetAllServicesReplaceUid() {
+        TestServicesCache cache = new TestServicesCache();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2));
+        cache.getAllServices(U0);
+        // Invalidate cache and clear update query results
+        cache.invalidateCache(U0);
+        cache.clearServicesForQuerying();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, SYSTEM_IMAGE_UID));
+        Collection<RegisteredServicesCache.ServiceInfo<TestServiceType>> allServices = cache
+                .getAllServices(U0);
+        assertEquals(2, allServices.size());
+        Set<Integer> uids = new HashSet<>();
+        for (RegisteredServicesCache.ServiceInfo<TestServiceType> srv : allServices) {
+            uids.add(srv.uid);
+        }
+        assertTrue("UID must be updated to the new value",
+                uids.contains(SYSTEM_IMAGE_UID));
+        assertFalse("UID must be updated to the new value", uids.contains(UID2));
+    }
+
+    public void testGetAllServicesServiceRemoved() {
+        TestServicesCache cache = new TestServicesCache();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2));
+        assertEquals(2, cache.getAllServicesSize(U0));
+        assertEquals(2, cache.getPersistentServicesSize(U0));
+        // Re-read data from disk and verify services were saved
+        cache = new TestServicesCache();
+        assertEquals(2, cache.getPersistentServicesSize(U0));
+        // Now register only one service and verify that another one is removed
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        assertEquals(1, cache.getAllServicesSize(U0));
+        assertEquals(1, cache.getPersistentServicesSize(U0));
+    }
+
+    public void testGetAllServicesMultiUser() {
+        TestServicesCache cache = new TestServicesCache();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        int u1uid = UserHandle.getUid(U1, 0);
+        cache.addServiceForQuerying(U1, r2, newServiceInfo(t2, u1uid));
+        assertEquals(1, cache.getAllServicesSize(U0));
+        assertEquals(1, cache.getPersistentServicesSize(U0));
+        assertEquals(1, cache.getAllServicesSize(U1));
+        assertEquals(1, cache.getPersistentServicesSize(U1));
+        assertEquals("No services should be available for user 3", 0, cache.getAllServicesSize(3));
+        // Re-read data from disk and verify services were saved
+        cache = new TestServicesCache();
+        assertEquals(1, cache.getPersistentServicesSize(U0));
+        assertEquals(1, cache.getPersistentServicesSize(U1));
+        assertNotEmptyFileCreated(cache, U0);
+        assertNotEmptyFileCreated(cache, U1);
+    }
+
+    public void testOnRemove() {
+        TestServicesCache cache = new TestServicesCache();
+        cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
+        int u1uid = UserHandle.getUid(U1, 0);
+        cache.addServiceForQuerying(U1, r2, newServiceInfo(t2, u1uid));
+        assertEquals(1, cache.getAllServicesSize(U0));
+        assertEquals(1, cache.getAllServicesSize(U1));
+        // Simulate ACTION_USER_REMOVED
+        cache.onUserRemoved(U1);
+        // Make queryIntentServices(u1) return no results for U1
+        cache.clearServicesForQuerying();
+        assertEquals(1, cache.getAllServicesSize(U0));
+        assertEquals(0, cache.getAllServicesSize(U1));
+    }
+
+    public void testMigration() {
+        // Prepare "old" file for testing
+        String oldFile = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<services>\n"
+                + "    <service uid=\"1\" type=\"type1\" value=\"value1\" />\n"
+                + "    <service uid=\"100002\" type=\"type2\" value=\"value2\" />\n"
+                + "<services>\n";
+
+        File file = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml");
+        FileUtils.copyToFile(new ByteArrayInputStream(oldFile.getBytes()), file);
+
+        int u0 = 0;
+        int u1 = 1;
+        TestServicesCache cache = new TestServicesCache();
+        assertEquals(1, cache.getPersistentServicesSize(u0));
+        assertEquals(1, cache.getPersistentServicesSize(u1));
+        assertNotEmptyFileCreated(cache, u0);
+        assertNotEmptyFileCreated(cache, u1);
+        // Check that marker was created
+        File markerFile = new File(mSyncDir, TestServicesCache.SERVICE_INTERFACE + ".xml.migrated");
+        assertTrue("Marker file should be created at " + markerFile, markerFile.exists());
+        // Now introduce 2 service types for u0: t1, t2. type1 will be removed
+        cache.addServiceForQuerying(0, r1, newServiceInfo(t1, 1));
+        cache.addServiceForQuerying(0, r2, newServiceInfo(t2, 2));
+        assertEquals(2, cache.getAllServicesSize(u0));
+        assertEquals(0, cache.getAllServicesSize(u1));
+        // Re-read data from disk. Verify that services were saved and old file was ignored
+        cache = new TestServicesCache();
+        assertEquals(2, cache.getPersistentServicesSize(u0));
+        assertEquals(0, cache.getPersistentServicesSize(u1));
+    }
+
+    private static RegisteredServicesCache.ServiceInfo<TestServiceType> newServiceInfo(
+            TestServiceType type, int uid) {
+        return new RegisteredServicesCache.ServiceInfo<>(type, null, uid);
+    }
+
+    private void assertNotEmptyFileCreated(TestServicesCache cache, int userId) {
+        File dir = new File(cache.getUserSystemDirectory(userId),
+                RegisteredServicesCache.REGISTERED_SERVICES_DIR);
+        File file = new File(dir, TestServicesCache.SERVICE_INTERFACE+".xml");
+        assertTrue("File should be created at " + file, file.length() > 0);
+    }
+
+    /**
+     * Mock implementation of {@link android.content.pm.RegisteredServicesCache} for testing
+     */
+    private class TestServicesCache extends RegisteredServicesCache<TestServiceType> {
+        static final String SERVICE_INTERFACE = "RegisteredServicesCacheTest";
+        static final String SERVICE_META_DATA = "RegisteredServicesCacheTest";
+        static final String ATTRIBUTES_NAME = "test";
+        private SparseArray<Map<ResolveInfo, ServiceInfo<TestServiceType>>> mServices
+                = new SparseArray<>();
+
+        public TestServicesCache() {
+            super(RegisteredServicesCacheTest.this.mContext,
+                    SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, new TestSerializer());
+        }
+
+        @Override
+        public TestServiceType parseServiceAttributes(Resources res, String packageName,
+                AttributeSet attrs) {
+            return null;
+        }
+
+        @Override
+        protected List<ResolveInfo> queryIntentServices(int userId) {
+            Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices
+                    .get(userId, new HashMap<ResolveInfo, ServiceInfo<TestServiceType>>());
+            return new ArrayList<>(map.keySet());
+        }
+
+        @Override
+        protected File getUserSystemDirectory(int userId) {
+            File dir = new File(mDataDir, "users/" + userId);
+            dir.mkdirs();
+            return dir;
+        }
+
+        @Override
+        protected List<UserInfo> getUsers() {
+            return mUsers;
+        }
+
+        @Override
+        protected UserInfo getUser(int userId) {
+            for (UserInfo user : getUsers()) {
+                if (user.id == userId) {
+                    return user;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        protected File getDataDirectory() {
+            return mDataDir;
+        }
+
+        void addServiceForQuerying(int userId, ResolveInfo resolveInfo,
+                ServiceInfo<TestServiceType> serviceInfo) {
+            Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.get(userId);
+            if (map == null) {
+                map = new HashMap<>();
+                mServices.put(userId, map);
+            }
+            map.put(resolveInfo, serviceInfo);
+        }
+
+        void clearServicesForQuerying() {
+            mServices.clear();
+        }
+
+        int getPersistentServicesSize(int user) {
+            return getPersistentServices(user).size();
+        }
+
+        int getAllServicesSize(int user) {
+            return getAllServices(user).size();
+        }
+
+        @Override
+        protected boolean inSystemImage(int callerUid) {
+            return callerUid == SYSTEM_IMAGE_UID;
+        }
+
+        @Override
+        protected ServiceInfo<TestServiceType> parseServiceInfo(
+                ResolveInfo resolveInfo) throws XmlPullParserException, IOException {
+            int size = mServices.size();
+            for (int i = 0; i < size; i++) {
+                Map<ResolveInfo, ServiceInfo<TestServiceType>> map = mServices.valueAt(i);
+                ServiceInfo<TestServiceType> serviceInfo = map.get(resolveInfo);
+                if (serviceInfo != null) {
+                    return serviceInfo;
+                }
+            }
+            throw new IllegalArgumentException("Unexpected service " + resolveInfo);
+        }
+
+        @Override
+        public void onUserRemoved(int userId) {
+            super.onUserRemoved(userId);
+        }
+    }
+
+    static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
+
+        public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException {
+            out.attribute(null, "type", item.type);
+            out.attribute(null, "value", item.value);
+        }
+
+        public TestServiceType createFromXml(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            final String type = parser.getAttributeValue(null, "type");
+            final String value = parser.getAttributeValue(null, "value");
+            return new TestServiceType(type, value);
+        }
+    }
+
+    static class TestServiceType implements Parcelable {
+        final String type;
+        final String value;
+
+        public TestServiceType(String type, String value) {
+            this.type = type;
+            this.value = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            TestServiceType that = (TestServiceType) o;
+
+            return type.equals(that.type) && value.equals(that.value);
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * type.hashCode() + value.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return "TestServiceType{" +
+                    "type='" + type + '\'' +
+                    ", value='" + value + '\'' +
+                    '}';
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(type);
+            dest.writeString(value);
+        }
+
+        public TestServiceType(Parcel source) {
+            this(source.readString(), source.readString());
+        }
+
+        public static final Creator<TestServiceType> CREATOR = new Creator<TestServiceType>() {
+            public TestServiceType createFromParcel(Parcel source) {
+                return new TestServiceType(source);
+            }
+
+            public TestServiceType[] newArray(int size) {
+                return new TestServiceType[size];
+            }
+        };
+    }
+}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 9ee4e20..fd922a2 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -320,6 +320,73 @@
         red.combineAllValues(blue);
     }
 
+    public void testMigrateTun() throws Exception {
+        final int tunUid = 10030;
+        final String tunIface = "tun0";
+        final String underlyingIface = "wlan0";
+        final int testTag1 = 8888;
+        NetworkStats delta = new NetworkStats(TEST_START, 17)
+            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 39605L, 46L, 12259L, 55L, 0L)
+            .addValues(tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
+            .addValues(tunIface, 10120, SET_DEFAULT, TAG_NONE, 72667L, 197L, 43909L, 241L, 0L)
+            .addValues(tunIface, 10120, SET_FOREGROUND, TAG_NONE, 9297L, 17L, 4128L, 21L, 0L)
+            // VPN package also uses some traffic through unprotected network.
+            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 4983L, 10L, 1801L, 12L, 0L)
+            .addValues(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
+            // Tag entries
+            .addValues(tunIface, 10120, SET_DEFAULT, testTag1, 21691L, 41L, 13820L, 51L, 0L)
+            .addValues(tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L)
+            // Irrelevant entries
+            .addValues(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L)
+            // Underlying Iface entries
+            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 5178L, 8L, 2139L, 11L, 0L)
+            .addValues(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L)
+            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, 149873L, 287L,
+                    59217L /* smaller than sum(tun0) */, 299L /* smaller than sum(tun0) */, 0L)
+            .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+
+        assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
+        assertEquals(17, delta.size());
+
+        // tunIface and TEST_IFACE entries are not changed.
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE,
+                39605L, 46L, 12259L, 55L, 0L);
+        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE,
+                72667L, 197L, 43909L, 241L, 0L);
+        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE,
+                9297L, 17L, 4128L, 21L, 0L);
+        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE,
+                4983L, 10L, 1801L, 12L, 0L);
+        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
+        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1,
+                21691L, 41L, 13820L, 51L, 0L);
+        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L);
+        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L);
+
+        // Existing underlying Iface entries are updated
+        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE,
+                44783L, 54L, 13829L, 60L, 0L);
+        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE,
+                0L, 0L, 0L, 0L, 0L);
+
+        // VPN underlying Iface entries are updated
+        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
+                28304L, 27L, 1719L, 12L, 0L);
+        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
+                0L, 0L, 0L, 0L, 0L);
+
+        // New entries are added for new application's underlying Iface traffic
+        assertValues(delta, 13, underlyingIface, 10120, SET_DEFAULT, TAG_NONE,
+                72667L, 197L, 41872l, 219L, 0L);
+        assertValues(delta, 14, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE,
+                9297L, 17L, 3936, 19L, 0L);
+        assertValues(delta, 15, underlyingIface, 10120, SET_DEFAULT, testTag1,
+                21691L, 41L, 13179L, 46L, 0L);
+        assertValues(delta, 16, underlyingIface, 10120, SET_FOREGROUND, testTag1,
+                1281L, 2L, 634L, 1L, 0L);
+    }
+
     private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
             int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
         final NetworkStats.Entry entry = stats.getValues(index, null);
diff --git a/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java b/core/tests/coretests/src/android/net/StaticIpConfigurationTest.java
new file mode 100644
index 0000000..59f780f
--- /dev/null
+++ b/core/tests/coretests/src/android/net/StaticIpConfigurationTest.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 android.net;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.junit.Assert.*;
+
+
+public class StaticIpConfigurationTest extends TestCase {
+
+    private static final String ADDRSTR = "192.0.2.2/25";
+    private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
+    private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
+    private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
+    private static final InetAddress DNS1 = IpAddress("8.8.8.8");
+    private static final InetAddress DNS2 = IpAddress("8.8.4.4");
+    private static final InetAddress DNS3 = IpAddress("4.2.2.2");
+    private static final String IFACE = "eth0";
+
+    private static InetAddress IpAddress(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
+    private void checkEmpty(StaticIpConfiguration s) {
+        assertNull(s.ipAddress);
+        assertNull(s.gateway);
+        assertNull(s.domains);
+        assertEquals(0, s.dnsServers.size());
+    }
+
+    private boolean isEqual(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        return s1.equals(s2);
+    }
+
+    private void assertEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        assertTrue(isEqual(s1, s2));
+    }
+
+    private void assertNotEquals(StaticIpConfiguration s1, StaticIpConfiguration s2) {
+        assertFalse(isEqual(s1, s2));
+    }
+
+    private StaticIpConfiguration makeTestObject() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        s.ipAddress = ADDR;
+        s.gateway = GATEWAY;
+        s.dnsServers.add(DNS1);
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        s.domains = "google.com";
+        return s;
+    }
+
+    @SmallTest
+    public void testConstructor() {
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        checkEmpty(s);
+    }
+
+    @SmallTest
+    public void testCopyAndClear() {
+        StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
+        checkEmpty(empty);
+
+        StaticIpConfiguration s1 = makeTestObject();
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
+        assertEquals(s1, s2);
+        s2.clear();
+        assertEquals(empty, s2);
+    }
+
+    @SmallTest
+    public void testHashCodeAndEquals() {
+        HashSet<Integer> hashCodes = new HashSet();
+        hashCodes.add(0);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        // Check that this hash code is nonzero and different from all the ones seen so far.
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.ipAddress = ADDR;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.gateway = GATEWAY;
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS1);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS2);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.dnsServers.add(DNS3);
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        s.domains = "example.com";
+        assertTrue(hashCodes.add(s.hashCode()));
+
+        assertFalse(s.equals(null));
+        assertEquals(s, s);
+
+        StaticIpConfiguration s2 = new StaticIpConfiguration(s);
+        assertEquals(s, s2);
+
+        s.ipAddress = new LinkAddress(DNS1, 32);
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.domains = "foo";
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.gateway = DNS2;
+        assertNotEquals(s, s2);
+
+        s2 = new StaticIpConfiguration(s);
+        s.dnsServers.add(DNS3);
+        assertNotEquals(s, s2);
+    }
+
+    @SmallTest
+    public void testToLinkProperties() {
+        LinkProperties expected = new LinkProperties();
+        expected.setInterfaceName(IFACE);
+
+        StaticIpConfiguration s = new StaticIpConfiguration();
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
+        s.ipAddress = ADDR;
+        expected.addLinkAddress(ADDR);
+        expected.addRoute(connectedRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = GATEWAY;
+        RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = OFFLINKGATEWAY;
+        expected.removeRoute(defaultRoute);
+        defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
+        expected.addRoute(defaultRoute);
+
+        RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
+        expected.addRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS1);
+        expected.addDnsServer(DNS1);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.dnsServers.add(DNS2);
+        s.dnsServers.add(DNS3);
+        expected.addDnsServer(DNS2);
+        expected.addDnsServer(DNS3);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.domains = "google.com";
+        expected.setDomains("google.com");
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        s.gateway = null;
+        expected.removeRoute(defaultRoute);
+        expected.removeRoute(gatewayRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+
+        // Without knowing the IP address, we don't have a directly-connected route, so we can't
+        // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
+        // configuration, but we should at least not crash.
+        s.gateway = OFFLINKGATEWAY;
+        s.ipAddress = null;
+        expected.removeLinkAddress(ADDR);
+        expected.removeRoute(connectedRoute);
+        expected.addRoute(defaultRoute);
+        assertEquals(expected, s.toLinkProperties(IFACE));
+    }
+
+    private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
+        Parcel p = Parcel.obtain();
+        StaticIpConfiguration s2 = null;
+        try {
+            s.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+        assertNotNull(s2);
+        return s2;
+    }
+
+    @SmallTest
+    public void testParceling() {
+        StaticIpConfiguration s = makeTestObject();
+        StaticIpConfiguration s2 = passThroughParcel(s);
+        assertEquals(s, s2);
+    }
+}
+
diff --git a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java b/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java
deleted file mode 100644
index 9015a6f..0000000
--- a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import com.google.mockwebserver.MockResponse;
-import com.google.mockwebserver.MockWebServer;
-import java.io.File;
-import java.net.CacheRequest;
-import java.net.CacheResponse;
-import java.net.ResponseCache;
-import java.net.URI;
-import java.net.URLConnection;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import junit.framework.TestCase;
-
-public final class HttpResponseCacheTest extends TestCase {
-
-    private File cacheDir;
-    private MockWebServer server = new MockWebServer();
-
-    @Override public void setUp() throws Exception {
-        super.setUp();
-        String tmp = System.getProperty("java.io.tmpdir");
-        cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
-    }
-
-    @Override protected void tearDown() throws Exception {
-        ResponseCache.setDefault(null);
-        server.shutdown();
-        super.tearDown();
-    }
-
-    public void testInstall() throws Exception {
-        HttpResponseCache installed = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        assertNotNull(installed);
-        assertSame(installed, ResponseCache.getDefault());
-        assertSame(installed, HttpResponseCache.getDefault());
-    }
-
-    public void testSecondEquivalentInstallDoesNothing() throws Exception {
-        HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        HttpResponseCache another = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        assertSame(first, another);
-    }
-
-    public void testInstallClosesPreviouslyInstalled() throws Exception {
-        HttpResponseCache first = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        HttpResponseCache another = HttpResponseCache.install(cacheDir, 8 * 1024 * 1024);
-        assertNotSame(first, another);
-        try {
-            first.flush();
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    public void testGetInstalledWithWrongTypeInstalled() {
-        ResponseCache.setDefault(new ResponseCache() {
-            @Override public CacheResponse get(URI uri, String requestMethod,
-                    Map<String, List<String>> requestHeaders) {
-                return null;
-            }
-            @Override public CacheRequest put(URI uri, URLConnection connection) {
-                return null;
-            }
-        });
-        assertNull(HttpResponseCache.getInstalled());
-    }
-
-    public void testCloseCloses() throws Exception {
-        HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        cache.close();
-        try {
-            cache.flush();
-            fail();
-        } catch (IllegalStateException expected) {
-        }
-    }
-
-    public void testCloseUninstalls() throws Exception {
-        HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        cache.close();
-        assertNull(ResponseCache.getDefault());
-    }
-
-    public void testDeleteUninstalls() throws Exception {
-        HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-        cache.delete();
-        assertNull(ResponseCache.getDefault());
-    }
-
-    /**
-     * Make sure that statistics tracking are wired all the way through the
-     * wrapper class. http://code.google.com/p/android/issues/detail?id=25418
-     */
-    public void testStatisticsTracking() throws Exception {
-        HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024);
-
-        server.enqueue(new MockResponse()
-                .addHeader("Cache-Control: max-age=60")
-                .setBody("A"));
-        server.play();
-
-        URLConnection c1 = server.getUrl("/").openConnection();
-        assertEquals('A', c1.getInputStream().read());
-        assertEquals(1, cache.getRequestCount());
-        assertEquals(1, cache.getNetworkCount());
-        assertEquals(0, cache.getHitCount());
-
-        URLConnection c2 = server.getUrl("/").openConnection();
-        assertEquals('A', c2.getInputStream().read());
-
-        URLConnection c3 = server.getUrl("/").openConnection();
-        assertEquals('A', c3.getInputStream().read());
-        assertEquals(3, cache.getRequestCount());
-        assertEquals(1, cache.getNetworkCount());
-        assertEquals(2, cache.getHitCount());
-    }
-}
diff --git a/core/tests/coretests/src/android/os/SELinuxTest.java b/core/tests/coretests/src/android/os/SELinuxTest.java
deleted file mode 100644
index 9b63a6b..0000000
--- a/core/tests/coretests/src/android/os/SELinuxTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package android.os;
-
-import android.os.Process;
-import android.os.SELinux;
-import android.test.AndroidTestCase;
-import static junit.framework.Assert.assertEquals;
-
-public class SELinuxTest extends AndroidTestCase {
-
-    public void testgetFileCon() {
-        if(SELinux.isSELinuxEnabled() == false)
-            return;
-
-        String ctx = SELinux.getFileContext("/system/bin/toolbox");
-        assertEquals(ctx, "u:object_r:system_file:s0");
-    }
-
-    public void testgetCon() {
-        if(SELinux.isSELinuxEnabled() == false)
-            return;
-
-        String mycon = SELinux.getContext();
-        assertEquals(mycon, "u:r:untrusted_app:s0:c33");
-    }
-
-    public void testgetPidCon() {
-        if(SELinux.isSELinuxEnabled() == false)
-            return;
-
-        String mycon = SELinux.getPidContext(Process.myPid());
-        assertEquals(mycon, "u:r:untrusted_app:s0:c33");
-    }
-
-    public void testcheckSELinuxAccess() {
-        if(SELinux.isSELinuxEnabled() == false)
-            return;
-
-        String mycon = SELinux.getContext();
-        boolean ret;
-        ret = SELinux.checkSELinuxAccess(mycon, mycon, "process", "fork");
-        assertEquals(ret,"true");
-        ret = SELinux.checkSELinuxAccess(mycon, mycon, "memprotect", "mmap_zero");
-        assertEquals(ret,"true");
-    }
-}
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index d494c5d..5a6ef30 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -353,6 +353,7 @@
         assertNull("null CharSequence should generate null from parcel", text);
         p = Parcel.obtain();
         TextUtils.writeToParcel("test", p, 0);
+        p.setDataPosition(0);
         text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
         assertEquals("conversion to/from parcel failed", "test", text);
     }
diff --git a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
deleted file mode 100644
index 18411b0..0000000
--- a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import com.android.frameworks.coretests.R;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.internal.widget.SizeAdaptiveLayout;
-
-
-public class SizeAdaptiveLayoutTest extends AndroidTestCase {
-
-    private LayoutInflater mInflater;
-    private int mOneU;
-    private int mFourU;
-    private SizeAdaptiveLayout mSizeAdaptiveLayout;
-    private View mSmallView;
-    private View mMediumView;
-    private View mLargeView;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        // inflate the layout
-        final Context context = getContext();
-        mInflater = LayoutInflater.from(context);
-        mOneU = 64;
-        mFourU = 4 * mOneU;
-    }
-
-    private void inflate(int resource){
-        mSizeAdaptiveLayout = (SizeAdaptiveLayout) mInflater.inflate(resource, null);
-        mSizeAdaptiveLayout.onAttachedToWindow();
-
-        mSmallView = mSizeAdaptiveLayout.findViewById(R.id.one_u);
-        mMediumView = mSizeAdaptiveLayout.findViewById(R.id.two_u);
-        mLargeView = mSizeAdaptiveLayout.findViewById(R.id.four_u);
-    }
-
-    /**
-     * The name 'test preconditions' is a convention to signal that if this
-     * test doesn't pass, the test case was not set up properly and it might
-     * explain any and all failures in other tests.  This is not guaranteed
-     * to run before other tests, as junit uses reflection to find the tests.
-     */
-    @SmallTest
-    public void testPreconditions() {
-        assertNotNull(mInflater);
-
-        inflate(R.layout.size_adaptive);
-        assertNotNull(mSizeAdaptiveLayout);
-        assertNotNull(mSmallView);
-        assertNotNull(mLargeView);
-    }
-
-    @SmallTest
-    public void testOpenLarge() {
-        inflate(R.layout.size_adaptive);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight + 10;
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertEquals("1U should be gone",
-                View.GONE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenSmall() {
-        inflate(R.layout.size_adaptive);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-        assertEquals("4U should be gone",
-                View.GONE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenTooSmall() {
-        inflate(R.layout.size_adaptive);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight - 10;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-        assertEquals("4U should be gone",
-                View.GONE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenTooBig() {
-        inflate(R.layout.size_adaptive);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        lp.maxHeight = 500;
-        mLargeView.setLayoutParams(lp);
-        int height = (int) (lp.minHeight + 10);
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertEquals("1U should be gone",
-                View.GONE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenWrapContent() {
-        inflate(R.layout.size_adaptive_text);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight + 10;
-
-        // manually measure it, and lay it out
-        int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
-        mSizeAdaptiveLayout.measure(500, measureSpec);
-        assertTrue("should not be forced to 4U",
-                mSizeAdaptiveLayout.getMeasuredHeight() < mFourU);
-    }
-
-    @SmallTest
-    public void testOpenOneUOnlySmall() {
-        inflate(R.layout.size_adaptive_singleton);
-        assertNull("largeView should be NULL in the singleton layout", mLargeView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight - 10;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenOneUOnlyLarge() {
-        inflate(R.layout.size_adaptive_singleton);
-        assertNull("largeView should be NULL in the singleton layout", mLargeView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.maxHeight + 10;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenOneUOnlyJustRight() {
-        inflate(R.layout.size_adaptive_singleton);
-        assertNull("largeView should be NULL in the singleton layout", mLargeView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenFourUOnlySmall() {
-        inflate(R.layout.size_adaptive_large_only);
-        assertNull("smallView should be NULL in the singleton layout", mSmallView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight - 10;
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenFourUOnlyLarge() {
-        inflate(R.layout.size_adaptive_large_only);
-        assertNull("smallView should be NULL in the singleton layout", mSmallView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.maxHeight + 10;
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenFourUOnlyJustRight() {
-        inflate(R.layout.size_adaptive_large_only);
-        assertNull("smallView should be NULL in the singleton layout", mSmallView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenIntoAGap() {
-        inflate(R.layout.size_adaptive_gappy);
-
-        SizeAdaptiveLayout.LayoutParams smallParams =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        SizeAdaptiveLayout.LayoutParams largeParams =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        assertTrue("gappy layout should have a gap",
-                smallParams.maxHeight + 10 < largeParams.minHeight);
-        int height = (int) smallParams.maxHeight + 10;
-
-        measureAndLayout(height);
-
-        assertTrue("one and only one view should be visible",
-                mLargeView.getVisibility() != mSmallView.getVisibility());
-        // behavior is undefined in this case.
-    }
-
-    @SmallTest
-    public void testOpenIntoAnOverlap() {
-        inflate(R.layout.size_adaptive_overlapping);
-
-        SizeAdaptiveLayout.LayoutParams smallParams =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        SizeAdaptiveLayout.LayoutParams largeParams =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        assertEquals("overlapping layout should overlap",
-                smallParams.minHeight,
-                largeParams.minHeight);
-        int height = (int) smallParams.maxHeight;
-
-        measureAndLayout(height);
-
-        assertTrue("one and only one view should be visible",
-                mLargeView.getVisibility() != mSmallView.getVisibility());
-        assertEquals("1U should get priority in an overlap because it is first",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenThreeWayViewSmall() {
-        inflate(R.layout.size_adaptive_three_way);
-        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-        assertEquals("2U should be gone",
-                View.GONE,
-                mMediumView.getVisibility());
-        assertEquals("4U should be gone",
-                View.GONE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenThreeWayViewMedium() {
-        inflate(R.layout.size_adaptive_three_way);
-        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mMediumView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be gone",
-                View.GONE,
-                mSmallView.getVisibility());
-        assertEquals("2U should be visible",
-                View.VISIBLE,
-                mMediumView.getVisibility());
-        assertEquals("4U should be gone",
-                View.GONE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testOpenThreeWayViewLarge() {
-        inflate(R.layout.size_adaptive_three_way);
-        assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
-
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be gone",
-                View.GONE,
-                mSmallView.getVisibility());
-        assertEquals("2U should be gone",
-                View.GONE,
-                mMediumView.getVisibility());
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-    }
-
-    @SmallTest
-    public void testResizeWithoutAnimation() {
-        inflate(R.layout.size_adaptive);
-
-        SizeAdaptiveLayout.LayoutParams largeParams =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int startHeight = (int) largeParams.minHeight + 10;
-        int endHeight = (int) largeParams.minHeight + 10;
-
-        measureAndLayout(startHeight);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertFalse("There should be no animation on initial rendering.",
-                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
-
-        measureAndLayout(endHeight);
-
-        assertEquals("4U should still be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertFalse("There should be no animation on scale within a view.",
-                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
-    }
-
-    @SmallTest
-    public void testResizeWithAnimation() {
-        inflate(R.layout.size_adaptive);
-
-        SizeAdaptiveLayout.LayoutParams smallParams =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        SizeAdaptiveLayout.LayoutParams largeParams =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int startHeight = (int) largeParams.minHeight + 10;
-        int endHeight = (int) smallParams.maxHeight;
-
-        measureAndLayout(startHeight);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertFalse("There should be no animation on initial rendering.",
-                    mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
-
-        measureAndLayout(endHeight);
-
-        assertEquals("1U should now be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-        assertTrue("There should be an animation on scale between views.",
-                   mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
-    }
-
-    @SmallTest
-    public void testModestyPanelChangesColorWhite() {
-        inflate(R.layout.size_adaptive_color);
-        View panel = mSizeAdaptiveLayout.getModestyPanel();
-        assertTrue("ModestyPanel should have a ColorDrawable background",
-                   panel.getBackground() instanceof ColorDrawable);
-        ColorDrawable panelColor = (ColorDrawable) panel.getBackground();
-        ColorDrawable salColor = (ColorDrawable) mSizeAdaptiveLayout.getBackground();
-        assertEquals("ModestyPanel color should match the SizeAdaptiveLayout",
-                     panelColor.getColor(), salColor.getColor());
-    }
-
-    @SmallTest
-    public void testModestyPanelTracksStateListColor() {
-        inflate(R.layout.size_adaptive_color_statelist);
-        View panel = mSizeAdaptiveLayout.getModestyPanel();
-        assertEquals("ModestyPanel should have a ColorDrawable background" ,
-                     panel.getBackground().getClass(), ColorDrawable.class);
-        ColorDrawable panelColor = (ColorDrawable) panel.getBackground();
-        assertEquals("ModestyPanel color should match the SizeAdaptiveLayout",
-                     panelColor.getColor(), Color.RED);
-    }
-    @SmallTest
-    public void testOpenSmallEvenWhenLargeIsActuallySmall() {
-        inflate(R.layout.size_adaptive_lies);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("1U should be visible",
-                View.VISIBLE,
-                mSmallView.getVisibility());
-        assertTrue("1U should also have been measured",
-                   mSmallView.getMeasuredHeight() > 0);
-    }
-
-    @SmallTest
-    public void testOpenLargeEvenWhenLargeIsActuallySmall() {
-        inflate(R.layout.size_adaptive_lies);
-        SizeAdaptiveLayout.LayoutParams lp =
-          (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
-        int height = (int) lp.minHeight;
-
-        measureAndLayout(height);
-
-        assertEquals("4U should be visible",
-                View.VISIBLE,
-                mLargeView.getVisibility());
-        assertTrue("4U should also have been measured",
-                   mLargeView.getMeasuredHeight() > 0);
-    }
-
-    private void measureAndLayout(int height) {
-        // manually measure it, and lay it out
-        int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
-        mSizeAdaptiveLayout.measure(500, measureSpec);
-        mSizeAdaptiveLayout.layout(0, 0, 500, mSizeAdaptiveLayout.getMeasuredHeight());
-    }
-}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 7839d26..78e718f 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -27,18 +27,30 @@
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
 
+LOCAL_DEX_PREOPT := false
+
 mainDexList:= \
-	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+    $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
-LOCAL_DEX_PREOPT := false
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacyandexception/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/test.jpp
new file mode 100644
index 0000000..0d027ed
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/test.jpp
@@ -0,0 +1,3 @@
+test:
+  @@com.android.jack.annotations.ForceInMainDex
+  class com.android.multidexlegacyandexception.Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index e2ab1a8..7c699b6 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -27,21 +27,33 @@
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
 
+LOCAL_DEX_PREOPT := false
+
 mainDexList:= \
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
-LOCAL_DEX_PREOPT := false
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
 
 ## The application with a full main dex
 include $(CLEAR_VARS)
@@ -56,17 +68,30 @@
 
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
 
+LOCAL_DEX_PREOPT := false
+
 mainDexList2:= \
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
-LOCAL_DEX_PREOPT := false
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList2): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList2)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
index bbdd3e5..41b8956 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
@@ -31,7 +31,7 @@
         assertEquals(3366, getActivity().getValue());
     }
 
-    public void testAnnotation() {
+    public void testAnnotation() throws Exception {
         assertEquals(ReferencedByAnnotation.B,
                 ((AnnotationWithEnum) TestApplication.annotation).value());
         assertEquals(ReferencedByAnnotation.B,
@@ -43,10 +43,25 @@
                 ((AnnotationWithClass) TestApplication.annotation3).value());
         // Just to verify that it doesn't crash
         ReferencedByClassInAnnotation.A.get();
+
+        // Tests about bug https://code.google.com/p/android/issues/detail?id=78144
+        // Dalvik may throw IllegalAccessError when a class is in a different dex than an enum
+        // used in its annotations.
+        String annotationPackage = "com.android.multidexlegacytestapp.annotation.";
+        Class<?> clazz = Class.forName(annotationPackage + "Annotated");
+        // Just to verify that it doesn't crash
+        clazz.getAnnotations();
+        clazz = Class.forName(annotationPackage + "Annotated2");
+        // Just to verify that it doesn't crash
+        clazz.getAnnotations();
+        clazz = Class.forName(annotationPackage + "Annotated3");
+        // Just to verify that it doesn't crash
+        clazz.getAnnotations();
     }
 
     public void testInterface() {
         assertEquals(InterfaceWithEnum.class,
                 TestApplication.interfaceClass);
     }
+
 }
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated.java
new file mode 100644
index 0000000..fb7787b
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated.java
@@ -0,0 +1,26 @@
+/*
+ * 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.multidexlegacytestapp.annotation;
+
+@TestAnnotation(AnnotationValue.V1)
+public class Annotated {
+
+    public void m() {
+
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated2.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated2.java
new file mode 100644
index 0000000..7e2dea7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated2.java
@@ -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.
+ */
+
+package com.android.multidexlegacytestapp.annotation;
+
+@TestAnnotation2(AnnotationValue.V1)
+public class Annotated2 {
+    public void m() {
+
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated3.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated3.java
new file mode 100644
index 0000000..8a01c5b
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/Annotated3.java
@@ -0,0 +1,27 @@
+/*
+ * 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.multidexlegacytestapp.annotation;
+
+import com.android.multidexlegacytestapp.annotation.TestAnnotation3.Value;
+
+@TestAnnotation3(Value.V1)
+public class Annotated3 {
+    public void m() {
+
+    }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/AnnotationValue.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/AnnotationValue.java
new file mode 100644
index 0000000..1322d73
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/AnnotationValue.java
@@ -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.
+ */
+
+package com.android.multidexlegacytestapp.annotation;
+
+public enum AnnotationValue {
+  V1,
+  V2;
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation.java
new file mode 100644
index 0000000..68684b6
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation.java
@@ -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.
+ */
+
+package com.android.multidexlegacytestapp.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestAnnotation {
+  AnnotationValue value();
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation2.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation2.java
new file mode 100644
index 0000000..327d49c
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation2.java
@@ -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.
+ */
+
+package com.android.multidexlegacytestapp.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestAnnotation2 {
+  AnnotationValue value();
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation3.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation3.java
new file mode 100644
index 0000000..b1bf75e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/annotation/TestAnnotation3.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.multidexlegacytestapp.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestAnnotation3 {
+    public enum Value {
+        V1,
+        V2;
+
+      }
+
+  Value value();
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
new file mode 100644
index 0000000..a1f5656
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/test.jpp
@@ -0,0 +1,3 @@
+test:
+  @@com.android.jack.annotations.ForceInMainDex
+  class com.android.multidexlegacytestapp.Test
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 329f544..b85c02c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -30,13 +30,16 @@
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
 
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index e79fd71..0f1d9c0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -26,18 +26,30 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
 
+LOCAL_DEX_PREOPT := false
+
 mainDexList:= \
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
-LOCAL_DEX_PREOPT := false
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
new file mode 100644
index 0000000..6d384e3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/test.jpp
@@ -0,0 +1,3 @@
+test:
+  @@com.android.jack.annotations.ForceInMainDex
+  class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index 3742004..67ca483 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -26,18 +26,30 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
 
+LOCAL_DEX_PREOPT := false
+
 mainDexList:= \
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
 
-LOCAL_DEX_PREOPT := false
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
 
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
new file mode 100644
index 0000000..6d384e3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/test.jpp
@@ -0,0 +1,3 @@
+test:
+  @@com.android.jack.annotations.ForceInMainDex
+  class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 7f400bc..bf2efb1 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -29,15 +29,28 @@
 mainDexList:= \
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
-LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-
 LOCAL_DEX_PREOPT := false
 
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
+    -D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
+
 include $(BUILD_PACKAGE)
 
+ifndef LOCAL_JACK_ENABLED
 $(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+	$(hide) mkdir -p $(dir $@)
 	$(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
+endif
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
new file mode 100644
index 0000000..6d384e3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/test.jpp
@@ -0,0 +1,3 @@
+test:
+  @@com.android.jack.annotations.ForceInMainDex
+  class com.android.framework.multidexlegacyversionedtestapp.MultiDexUpdateTest
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
index 1557918..a50fb54 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -29,8 +29,6 @@
 import com.android.internal.inputmethod.InputMethodUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -38,19 +36,33 @@
 public class InputMethodTest extends InstrumentationTestCase {
     private static final boolean IS_AUX = true;
     private static final boolean IS_DEFAULT = true;
-    private static final boolean IS_AUTO = true;
+    private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
     private static final boolean IS_ASCII_CAPABLE = true;
+    private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
     private static final boolean IS_SYSTEM_READY = true;
-    private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
+    private static final Locale LOCALE_EN = new Locale("en");
     private static final Locale LOCALE_EN_US = new Locale("en", "US");
     private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
     private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FI = new Locale("fi");
+    private static final Locale LOCALE_FI_FI = new Locale("fi", "FI");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_FR = new Locale("fr");
+    private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
     private static final Locale LOCALE_HI = new Locale("hi");
     private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
     private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
     private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
+    private static final Locale LOCALE_IN = new Locale("in");
+    private static final Locale LOCALE_ID = new Locale("id");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
+    private static final String SUBTYPE_MODE_ANY = null;
+    private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
+    private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
+    private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
+            "EnabledWhenDefaultIsNotAsciiCapable";
 
     @SmallTest
     public void testVoiceImes() throws Exception {
@@ -159,10 +171,415 @@
         }
     }
 
+    @SmallTest
+    public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
+        // selected no matter what locale is specified.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(autoSubtype);  // overridesImplicitlyEnabledSubtype == true
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(autoSubtype, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);  // locale == "en_US"
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB); // locale == "en_GB"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_GB, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnGB, result.get(0));
+        }
+
+        // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
+        // any subtype whose locale is exactly equal to the specified locale in the given list,
+        // try to find a subtype whose language is equal to the language part of the given locale.
+        // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFrCA);  // locale == "fr_CA"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+        // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFr);  // locale == "fr"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR_CA, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+
+        // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
+        // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoJa);    // not ASCII capable
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_JA_JP, imi);
+            assertEquals(3, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
+        }
+
+        // Make sure that 3-letter language code can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FIL_PH, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFil, result.get(0));
+        }
+
+        // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
+        // Also make sure that the first subtype will be used as the last-resort candidate.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FI, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+        }
+
+        // Make sure that "in" and "id" conversion is taken into account.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+    }
+
+    @SmallTest
+    public void testContainsSubtypeOf() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        final boolean CHECK_COUNTRY = true;
+
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil_PH") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFilPH);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "in" can be queried with "id".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "id" can be queried with "in".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+    }
+
+    private ArrayList<InputMethodSubtype> callGetImplicitlyApplicableSubtypesLockedWithLocale(
+            final Locale locale, final InputMethodInfo imi) {
+        final Context context = getInstrumentation().getTargetContext();
+        final Locale initialLocale = context.getResources().getConfiguration().locale;
+        try {
+            context.getResources().getConfiguration().setLocale(locale);
+            return InputMethodUtils.getImplicitlyApplicableSubtypesLocked(context.getResources(),
+                    imi);
+        } finally {
+            context.getResources().getConfiguration().setLocale(initialLocale);
+        }
+    }
+
     private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
             final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) {
         final Context context = getInstrumentation().getTargetContext();
-        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesUnderWithLocale(
+        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesWithLocale(
                 context, isSystemReady, preinstalledImes, systemLocale));
         assertEquals(expectedImeNames.length, actualImeNames.length);
         for (int i = 0; i < expectedImeNames.length; ++i) {
@@ -184,7 +601,7 @@
         }
     }
 
-    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesUnderWithLocale(
+    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesWithLocale(
             final Context context, final boolean isSystemReady,
             final ArrayList<InputMethodInfo> imis, final Locale locale) {
         final Locale initialLocale = context.getResources().getConfiguration().locale;
@@ -210,11 +627,15 @@
         for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
             final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
             final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
-            assertEquals(expectedSubtype, actualSubtype);
-            assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
+            verifyEquality(expectedSubtype, actualSubtype);
         }
     }
 
+    private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
+        assertEquals(expected, actual);
+        assertEquals(expected.hashCode(), actual.hashCode());
+    }
+
     private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
             CharSequence label, boolean isAuxIme, boolean isDefault,
             List<InputMethodSubtype> subtypes) {
@@ -236,13 +657,27 @@
 
     private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
-            boolean isAsciiCapable) {
+            boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
+
+        final StringBuilder subtypeExtraValue = new StringBuilder();
+        if (isEnabledWhenDefaultIsNotAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        }
+
+        // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
+        // available since API level 19 (KitKat). We no longer need to rely on extra value.
+        if (isAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
+        }
+
         return new InputMethodSubtypeBuilder()
                 .setSubtypeNameResId(0)
                 .setSubtypeIconResId(0)
                 .setSubtypeLocale(locale)
                 .setSubtypeMode(mode)
-                .setSubtypeExtraValue("")
+                .setSubtypeExtraValue(subtypeExtraValue.toString())
                 .setIsAuxiliary(isAuxiliary)
                 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
                 .setIsAsciiCapable(isAsciiCapable)
@@ -253,10 +688,12 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
                     "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -268,33 +705,39 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
                     "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
                     "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
                     "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme",
                     "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -321,7 +764,8 @@
             final boolean isDefaultIme = false;
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
-                    IS_AUTO, !IS_ASCII_CAPABLE));
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice",
                     "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
                     subtypes));
@@ -332,9 +776,11 @@
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             // TODO: This subtype should be marked as IS_ASCII_CAPABLE
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
                     "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -345,7 +791,8 @@
             final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
                     "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -356,7 +803,8 @@
             final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
                     "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -368,13 +816,17 @@
                     new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -385,9 +837,11 @@
             final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
                     "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
                     isDefaultIme, subtypes));
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 42de9ea..e57c55c 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -225,8 +225,12 @@
             reader = new BufferedReader(new InputStreamReader(input));
             actual = reader.readLine();
         } finally {
-            reader.close();
-            input.close();
+            if (reader != null) {
+                reader.close();
+            }
+            if (input != null) {
+                input.close();
+            }
         }
 
         final String no = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py
index 4f94373..3703f4a 100755
--- a/core/tests/overlaytests/testrunner.py
+++ b/core/tests/overlaytests/testrunner.py
@@ -421,8 +421,8 @@
         _create_disable_overlays_task(),
         MkdirTask('/system/vendor'),
         MkdirTask('/vendor/overlay'),
-        PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
-        PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+        PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
+        PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
     ]
     return CompoundTask(TASK_ENABLE_SINGLE_OVERLAY, tasks)
 
@@ -432,9 +432,9 @@
         MkdirTask('/system/vendor'),
         MkdirTask('/vendor/overlay'),
 
-        PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
-        PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
-        PushTask('/data/app/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
+        PushTask('/data/app/com.android.overlaytest.overlay/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
+        PushTask('/data/app/com.android.overlaytest.first_app_overlay/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+        PushTask('/data/app/com.android.overlaytest.second_app_overlay/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
     ]
     return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks)
 
@@ -584,7 +584,7 @@
     # remount filesystem, install test project
     tasks.append(RootTask())
     tasks.append(RemountTask())
-    tasks.append(PushTask('/system/app/OverlayTest.apk', '/system/app/OverlayTest.apk'))
+    tasks.append(PushTask('/system/app/OverlayTest/OverlayTest.apk', '/system/app/OverlayTest.apk'))
 
     # test idmap
     if opts.test_idmap:
@@ -609,9 +609,9 @@
         tasks.append(GrepIdmapTest(idmap, 'bool/config_annoy_dianne', 1))
 
         # overlays.list
-        overlays_list_path = '/data/resource-cache/overlays.list'
+        overlays_list_path = idmaps + '/overlays.list'
         expected_content = '''\
-/vendor/overlay/framework_b.apk /data/resource-cache/vendor@overlay@framework_b.apk@idmap
+/vendor/overlay/framework_b.apk /data/local/tmp/idmaps/vendor@overlay@framework_b.apk@idmap
 '''
         tasks.append(FileExistsTest(overlays_list_path))
         tasks.append(Md5Test(overlays_list_path, expected_content))
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 9fd8a4a..6659769 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -149,7 +149,9 @@
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar" />
     <library name="javax.obex"
-            file="/system/framework/javax.obex.jar"/>
+            file="/system/framework/javax.obex.jar" />
+    <library name="org.apache.http.legacy"
+            file="/system/framework/org.apache.http.legacy.jar" />
 
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 80fb1fd..38321a3 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -111,49 +111,11 @@
 endef
 
 font_src_files := \
-    Roboto-Regular.ttf \
-    Roboto-Bold.ttf \
-    Roboto-Italic.ttf \
-    Roboto-BoldItalic.ttf \
     Clockopia.ttf \
     AndroidClock.ttf \
     AndroidClock_Highlight.ttf \
     AndroidClock_Solid.ttf
 
-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))
-$(eval $(call create-font-symlink,Roboto-MediumItalic.ttf,Roboto-Italic.ttf))
-$(eval $(call create-font-symlink,Roboto-Thin.ttf,Roboto-Regular.ttf))
-$(eval $(call create-font-symlink,Roboto-ThinItalic.ttf,Roboto-Italic.ttf))
-$(eval $(call create-font-symlink,RobotoCondensed-Regular.ttf,Roboto-Regular.ttf))
-$(eval $(call create-font-symlink,RobotoCondensed-Bold.ttf,Roboto-Bold.ttf))
-$(eval $(call create-font-symlink,RobotoCondensed-Italic.ttf,Roboto-Italic.ttf))
-$(eval $(call create-font-symlink,RobotoCondensed-BoldItalic.ttf,Roboto-BoldItalic.ttf))
-
-else # !MINIMAL_FONT
-font_src_files += \
-    Roboto-Black.ttf \
-    Roboto-BlackItalic.ttf \
-    Roboto-Light.ttf \
-    Roboto-LightItalic.ttf \
-    Roboto-Medium.ttf \
-    Roboto-MediumItalic.ttf \
-    Roboto-Thin.ttf \
-    Roboto-ThinItalic.ttf \
-    RobotoCondensed-Regular.ttf \
-    RobotoCondensed-Bold.ttf \
-    RobotoCondensed-Italic.ttf \
-    RobotoCondensed-BoldItalic.ttf \
-    RobotoCondensed-Light.ttf \
-    RobotoCondensed-LightItalic.ttf
-
-endif # !MINIMAL_FONT
-
 $(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
 
 build-one-font-module :=
diff --git a/data/fonts/Roboto-Black.ttf b/data/fonts/Roboto-Black.ttf
deleted file mode 100644
index 79b5f74..0000000
--- a/data/fonts/Roboto-Black.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf
deleted file mode 100644
index 4c58b7b..0000000
--- a/data/fonts/Roboto-BlackItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
deleted file mode 100644
index 58397cc..0000000
--- a/data/fonts/Roboto-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
deleted file mode 100644
index 606252c..0000000
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
deleted file mode 100644
index cc3fd40..0000000
--- a/data/fonts/Roboto-Italic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
deleted file mode 100644
index e65c2d2..0000000
--- a/data/fonts/Roboto-Light.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
deleted file mode 100644
index d5476e7..0000000
--- a/data/fonts/Roboto-LightItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf
deleted file mode 100644
index 9263090..0000000
--- a/data/fonts/Roboto-Medium.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-MediumItalic.ttf b/data/fonts/Roboto-MediumItalic.ttf
deleted file mode 100644
index 329aab9..0000000
--- a/data/fonts/Roboto-MediumItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
deleted file mode 100644
index c515eca..0000000
--- a/data/fonts/Roboto-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
deleted file mode 100644
index 35ab525..0000000
--- a/data/fonts/Roboto-Thin.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
deleted file mode 100644
index edada2e..0000000
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
deleted file mode 100644
index bcbeece..0000000
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
deleted file mode 100644
index 7680d0a..0000000
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
deleted file mode 100644
index 04c83a0..0000000
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf
deleted file mode 100644
index 9f57418..0000000
--- a/data/fonts/RobotoCondensed-Light.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf
deleted file mode 100644
index f9eac04..0000000
--- a/data/fonts/RobotoCondensed-LightItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
deleted file mode 100644
index 3a06286..0000000
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index f94fe66..42b5d5d 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -335,11 +335,6 @@
     </family>
     <family>
         <fileset>
-            <file>NotoSansTaiLe-Regular.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
             <file>NotoSansTaiTham-Regular.ttf</file>
         </fileset>
     </family>
@@ -408,10 +403,13 @@
             <file lang="ja">MTLmr3m.ttf</file>
         </fileset>
     </family>
-    <!-- Note: complex scripts (i.e. those requiring shaping in Harfbuzz) have
-         a cumulative limit of 64k glyphs. Thus, if they are placed after the
-         large fonts such as DroidSansFallback, they are likely to render
-         incorrectly. Please use caution when putting fonts toward the end of
-         the list.
+    <!--
+        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        the East Asian punctuation for Chinese.
     -->
+    <family>
+        <fileset>
+            <file>NotoSansTaiLe-Regular.ttf</file>
+        </fileset>
+    </family>
 </familyset>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index f285ebe..a5939fa 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -21,24 +21,6 @@
 
 PRODUCT_PACKAGES := \
     DroidSansFallback.ttf \
-    Roboto-Regular.ttf \
-    Roboto-Bold.ttf \
-    Roboto-Italic.ttf \
-    Roboto-BoldItalic.ttf \
-    Roboto-Black.ttf \
-    Roboto-BlackItalic.ttf \
-    Roboto-Light.ttf \
-    Roboto-LightItalic.ttf \
-    Roboto-Medium.ttf \
-    Roboto-MediumItalic.ttf \
-    Roboto-Thin.ttf \
-    Roboto-ThinItalic.ttf \
-    RobotoCondensed-Regular.ttf \
-    RobotoCondensed-Bold.ttf \
-    RobotoCondensed-Italic.ttf \
-    RobotoCondensed-BoldItalic.ttf \
-    RobotoCondensed-Light.ttf \
-    RobotoCondensed-LightItalic.ttf \
     DroidSansMono.ttf \
     Clockopia.ttf \
     AndroidClock.ttf \
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 02bf877..37527e9 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -288,9 +288,6 @@
         <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
     <family>
-        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
-    </family>
-    <family>
         <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
     </family>
     <family>
@@ -332,4 +329,11 @@
     <family lang="ja">
         <font weight="400" style="normal">MTLmr3m.ttf</font>
     </family>
+    <!--
+        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        the East Asian punctuation for Chinese.
+    -->
+    <family>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
 </familyset>
diff --git a/docs/html/about/about_toc.cs b/docs/html/about/about_toc.cs
index 62d37c5..b1357f2 100644
--- a/docs/html/about/about_toc.cs
+++ b/docs/html/about/about_toc.cs
@@ -16,7 +16,6 @@
               es-lang="Lollipop">
       <span class="en">Lollipop</span></a></div>
       <ul>
-        <li><a href="<?cs var:toroot ?>about/versions/android-5.1.html">Android 5.1 APIs</a></li>
         <li><a href="<?cs var:toroot ?>about/versions/android-5.0.html"
               zh-tw-lang="Android 5.0 API"
               zh-cn-lang="Android 5.0 API"
diff --git a/docs/html/about/versions/android-5.1.jd b/docs/html/about/versions/android-5.1.jd
deleted file mode 100644
index 12386805..0000000
--- a/docs/html/about/versions/android-5.1.jd
+++ /dev/null
@@ -1,124 +0,0 @@
-page.title=Android 5.1 APIs
-excludeFromSuggestions=true
-sdk.platform.version=5.1
-sdk.platform.apiLevel=22
-@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="#ApiLevel">Update your target API level</a></li>
-
-  <li><a href="#multisim">Multiple SIM Card Support</a></li>
-  <li><a href="#http">Deprecated HTTP Classes</a></li>
-  <li><a href="#carrier">Carrier Services</a></li>
-</ol>
-
-<h2>API Differences</h2>
-<ol>
-<li><a href="{@docRoot}sdk/api_diff/22/changes.html">API level 21 to 22 &raquo;</a> </li>
-</ol>
-
-<h2>See Also</h2>
-<ol>
-<li><a href="{@docRoot}about/versions/lollipop.html">Android Lollipop Highlights</a> </li>
-</ol>
-
-
-</div>
-</div>
-
-<p>API Level: {@sdkPlatformApiLevel}</p>
-
-<p>
-  Android 5.1
-  (<a href="{@docRoot}reference/android/os/Build.VERSION_CODES.html#LOLLIPOP_MR1">LOLLIPOP_MR1</a>)
-  is an update to the Lollipop release that offers new features for users and app developers.
-  This document provides an introduction to the most notable new APIs.
-</p>
-
-<p>
-  For a high-level look at the new platform features, see the <a href=
-  "{@docRoot}about/versions/lollipop.html">Android Lollipop highlights</a>.
-</p>
-
-
-<h3 id="ApiLevel">Update your target API level</h3>
-
-<p>
-  To start building apps for Android 5.1, use the
-  <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> to download the Android 5.1 SDK
-  Platform and System Images. Then set your app development project to use a
-  <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
-  of <code>"{@sdkPlatformApiLevel}"</code>. Install your app on an Android {@sdkPlatformVersion}
-  system image, test it, then publish the updated app with this change.
-</p>
-
-<p>
-  You can use Android {@sdkPlatformVersion} APIs while also supporting older versions by adding
-  conditions to your code that check for the system API level before executing APIs not supported
-  by your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-  minSdkVersion}</a>. To learn more about maintaining backward compatibility, read <a href=
-  "{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different Platform
-  Versions</a>.
-</p>
-
-<p>
-  For more information about how API levels work, read <a href=
-  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">What is API Level?</a>
-</p>
-
-<h2 id="multisim">Multiple SIM Card Support</h2>
-
-<p>
-  Android 5.1 adds support for using more than one cellular carrier SIM card at a time. This
-  feature lets users activate and use additional SIMs on devices that have two or more SIM card
-  slots.
-</p>
-
-<p>
-  You can access information about the currently active SIM through the {@link
-  android.telephony.SubscriptionManager} class, including whether or not the device is considered
-  to be roaming on the current network. This information is useful for developers who want to
-  throttle their apps' data access down or off for device users who are sensitive to data access
-  charges. Your app can be alerted to changes in a device's current network connection by
-  requesting the {@link android.Manifest.permission#READ_PHONE_STATE} permission and setting {@link
-  android.telephony.SubscriptionManager.OnSubscriptionsChangedListener} on the {@link
-  android.telephony.SubscriptionManager} object.
-</p>
-
-
-<h2 id="http">Deprecated HTTP Classes</h2>
-
-<p>
-  The {@code org.apache.http} classes and the {@link android.net.http.AndroidHttpClient} class
-  have been deprecated in Android 5.1. These classes are no longer being maintained and you should
-  migrate any app code using these APIs to the {@link java.net.URLConnection} classes as soon as
-  possible.
-</p>
-
-
-<h2 id="carrier">Carrier Services</h2>
-
-<p>
-  Android 5.1 provides support for telecommunication service providers to create apps that can
-  perform carrier provisioning tasks on an Android device. These APIs provide a secure and flexible
-  way for carrier-developed apps to perform these tasks and be distributed through Google Play. Apps
-  that use these functions must be signed by a certificate that matches the certificate in the
-  device's Universal Integrated Circuit Card (UICC).
-</p>
-
-<p>
-  The carrier service APIs have been added to the {@link android.telephony.TelephonyManager} class,
-  the {@link android.telephony.SmsManager} class, and the new {@link
-  android.service.carrier.CarrierMessagingService} class. Apps can check for access to these APIs
-  by calling the {@link android.telephony.TelephonyManager#hasCarrierPrivileges} method. Apps that
-  call these APIs without access receive a {@link java.lang.SecurityException}.
-</p>
diff --git a/docs/html/about/versions/lollipop.jd b/docs/html/about/versions/lollipop.jd
index 8bc7200..1ad5d24 100644
--- a/docs/html/about/versions/lollipop.jd
+++ b/docs/html/about/versions/lollipop.jd
@@ -55,11 +55,6 @@
 <a href="http://www.android.com/versions/lollipop-5-0/"
 >www.android.com</a>.</p>
 
-<p class="note">
-  <strong>Note:</strong> The Android 5.1 Lollipop MR1 update is available with additional features
-  and fixes. For more information, see the
-  <a href="{@docRoot}about/versions/android-5.1.html">Android 5.1 API Overview</a>.
-</p>
 
 
 <h2 id="Material">Material design</h2>
diff --git a/docs/html/guide/appendix/glossary.jd b/docs/html/guide/appendix/glossary.jd
index af60eb7..db518f9 100644
--- a/docs/html/guide/appendix/glossary.jd
+++ b/docs/html/guide/appendix/glossary.jd
@@ -94,7 +94,7 @@
     Plugin, DDMS is integrated into your development environment. See <a
     href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a> to learn more about the program.</dd>
 
-    <dt id="dialog">Dialog</dt> <dd> A floating window that that acts as a lightweight
+    <dt id="dialog">Dialog</dt> <dd> A floating window that acts as a lightweight
     form. A dialog can have button controls only and is intended to perform a
     simple action (such as button choice) and perhaps return a value. A dialog
     is not intended to persist in the history stack, contain complex layout,
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 05e3133..167ebde 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -50,15 +50,6 @@
       <li><a href="#OpenFile">Open a specific type of file</a></li>
     </ol>
   </li>
-  <li><a href="#Fitness">Fitness</a>
-    <ol>
-      <li><a href="#TrackRide">Start/Stop a bike ride</a></li>
-      <li><a href="#TrackRun">Start/Stop a run</a></li>
-      <li><a href="#TrackWorkout">Start/Stop a workout</a></li>
-      <li><a href="#ShowHR">Show heart rate</a></li>
-      <li><a href="#ShowStepCount">Show step count</a></li>
-    </ol>
-  </li>
   <li><a href="#Local">Local Actions</a>
     <ol>
       <li><a href="#CallCar">Call a car</a></li>
@@ -1027,7 +1018,7 @@
 <dt><b>MIME Type</b></dt>
 <dd>
   <dl>
-    <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} ("text/plain")
+    <dt><code>"text/plain"</code>
     <dt><code>"*/*"</code>
   </dl>
 </dd>
@@ -1348,391 +1339,6 @@
 
 
 
-
-
-
-
-
-<h2 id="Fitness">Fitness</h2>
-
-<h3 id="TrackRide">Start/Stop a bike ride</h3>
-
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
-  </div>
-  <p class="now-title">Google Now</p>
-  <ul>
-    <li>"start cycling"</li>
-    <li>"start my bike ride"</li>
-    <li>"stop cycling"</li>
-  </ul>
-</div>
-
-<p>To track a bike ride, use the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/biking"</code>
-MIME type and set the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-<code>EXTRA_STATUS</code></a> extra to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-<code>STATUS_ACTIVE</code></a> when starting and to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-<code>STATUS_COMPLETED</code></a> when stopping.</p>
-
-<dl>
-  <dt><b>Action</b></dt>
-  <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>ACTION_TRACK</code></a><dd>
-
-  <dt><b>Data URI</b></dt>
-  <dd>None</dd>
-
-  <dt><b>MIME Type</b></dt>
-  <dd><code>"vnd.google.fitness.activity/biking"</code></dd>
-
-  <dt><b>Extras</b></dt>
-  <dd>
-    <dl>
-      <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-          <code>EXTRA_STATUS</code></a></dt>
-      <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-          <code>STATUS_ACTIVE</code></a> when starting and
-      <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-          <code>STATUS_COMPLETED</code></a> when stopping.</dd>
-    </dl>
-  </dd>
-</dl>
-
-
-<p><b>Example intent:</b></p>
-<pre>
-public void startBikeRide() {
-    Intent intent = new Intent(FitnessIntents.ACTION_TRACK)
-            .setType("vnd.google.fitness.activity/biking")
-            .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE);
-    if (intent.resolveActivity(getPackageManager()) != null) {
-        startActivity(intent);
-    }
-}
-</pre>
-
-
-<p><b>Example intent filter:</b></p>
-<pre>
-&lt;activity ...>
-    &lt;intent-filter>
-        &lt;action android:name="vnd.google.fitness.TRACK" />
-        &lt;data android:mimeType="vnd.google.fitness.activity/biking" />
-        &lt;category android:name="android.intent.category.DEFAULT" />
-    &lt;/intent-filter>
-&lt;/activity>
-</pre>
-
-
-
-
-
-<h3 id="TrackRun">Start/Stop a run</h3>
-
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
-  </div>
-  <p class="now-title">Google Now</p>
-  <ul>
-    <li>"track my run"</li>
-    <li>"start running"</li>
-    <li>"stop running"</li>
-  </ul>
-</div>
-
-<p>To track a run, use the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/running"</code>
-MIME type and set the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-<code>EXTRA_STATUS</code></a> extra to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-<code>STATUS_ACTIVE</code></a> when starting and to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-<code>STATUS_COMPLETED</code></a> when stopping.</p>
-
-<dl>
-  <dt><b>Action</b></dt>
-  <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>ACTION_TRACK</code></a><dd>
-
-  <dt><b>Data URI</b></dt>
-  <dd>None</dd>
-
-  <dt><b>MIME Type</b></dt>
-  <dd><code>"vnd.google.fitness.activity/running"</code></dd>
-
-  <dt><b>Extras</b></dt>
-  <dd>
-    <dl>
-      <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-          <code>EXTRA_STATUS</code></a></dt>
-      <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-          <code>STATUS_ACTIVE</code></a> when starting and
-      <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-          <code>STATUS_COMPLETED</code></a> when stopping.</dd>
-    </dl>
-  </dd>
-</dl>
-
-
-<p><b>Example intent:</b></p>
-<pre>
-public void startRun() {
-    Intent intent = new Intent(FitnessIntents.ACTION_TRACK)
-            .setType("vnd.google.fitness.activity/running")
-            .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE);
-    if (intent.resolveActivity(getPackageManager()) != null) {
-        startActivity(intent);
-    }
-}
-</pre>
-
-
-<p><b>Example intent filter:</b></p>
-<pre>
-&lt;activity ...>
-    &lt;intent-filter>
-        &lt;action android:name="vnd.google.fitness.TRACK" />
-        &lt;data android:mimeType="vnd.google.fitness.activity/running" />
-        &lt;category android:name="android.intent.category.DEFAULT" />
-    &lt;/intent-filter>
-&lt;/activity>
-</pre>
-
-
-
-
-<h3 id="TrackWorkout">Start/Stop a workout</h3>
-
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
-  </div>
-  <p class="now-title">Google Now</p>
-  <ul>
-    <li>"start a workout"</li>
-    <li>"track my workout"</li>
-    <li>"stop workout"</li>
-  </ul>
-</div>
-
-<p>To track a workout, use the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/other"</code>
-MIME type and set the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-<code>EXTRA_STATUS</code></a> extra to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-<code>STATUS_ACTIVE</code></a> when starting and to
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-<code>STATUS_COMPLETED</code></a> when stopping.</p>
-
-<dl>
-  <dt><b>Action</b></dt>
-  <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>ACTION_TRACK</code></a><dd>
-
-  <dt><b>Data URI</b></dt>
-  <dd>None</dd>
-
-  <dt><b>MIME Type</b></dt>
-  <dd><code>"vnd.google.fitness.activity/other"</code></dd>
-
-  <dt><b>Extras</b></dt>
-  <dd>
-    <dl>
-      <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS">
-          <code>EXTRA_STATUS</code></a></dt>
-      <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE">
-          <code>STATUS_ACTIVE</code></a> when starting and
-      <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED">
-          <code>STATUS_COMPLETED</code></a> when stopping.</dd>
-    </dl>
-  </dd>
-</dl>
-
-
-<p><b>Example intent:</b></p>
-<pre>
-public void startWorkout() {
-    Intent intent = new Intent(FitnessIntents.ACTION_TRACK)
-            .setType("vnd.google.fitness.activity/other")
-            .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE);
-    if (intent.resolveActivity(getPackageManager()) != null) {
-        startActivity(intent);
-    }
-}
-</pre>
-
-
-<p><b>Example intent filter:</b></p>
-<pre>
-&lt;activity ...>
-    &lt;intent-filter>
-        &lt;action android:name="vnd.google.fitness.TRACK" />
-        &lt;data android:mimeType="vnd.google.fitness.activity/other" />
-        &lt;category android:name="android.intent.category.DEFAULT" />
-    &lt;/intent-filter>
-&lt;/activity>
-</pre>
-
-
-
-
-<h3 id="ShowHeartRate">Show heart rate</h3>
-
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
-  </div>
-  <p class="now-title">Google Now</p>
-  <ul>
-    <li>"what's my heart rate?"</li>
-    <li>"what's my bpm?"</li>
-  </ul>
-</div>
-
-<p>To show the user's heart rate, use the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-<code>ACTION_VIEW</code></a> action with the
-<code>"vnd.google.fitness.data_type/com.google.heart_rate.bpm"</code> MIME type.</p>
-
-<dl>
-  <dt><b>Action</b></dt>
-  <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-      <code>ACTION_VIEW</code></a><dd>
-
-  <dt><b>Data URI</b></dt>
-  <dd>None</dd>
-
-  <dt><b>MIME Type</b></dt>
-  <dd><code>"vnd.google.fitness.data_type/com.google.heart_rate.bpm"</code></dd>
-
-  <dt><b>Extras</b></dt>
-  <dd>None</dd>
-</dl>
-
-
-<p><b>Example intent:</b></p>
-<pre>
-public void showHeartRate() {
-    Intent intent = new Intent(FitnessIntents.ACTION_VIEW)
-            .setType("vnd.google.fitness.data_type/com.google.heart_rate.bpm");
-    if (intent.resolveActivity(getPackageManager()) != null) {
-        startActivity(intent);
-    }
-}
-</pre>
-
-
-<p><b>Example intent filter:</b></p>
-<pre>
-&lt;activity ...>
-    &lt;intent-filter>
-        &lt;action android:name="vnd.google.fitness.VIEW" />
-        &lt;data android:mimeType="vnd.google.fitness.data_type/com.google.heart_rate.bpm" />
-        &lt;category android:name="android.intent.category.DEFAULT" />
-    &lt;/intent-filter>
-&lt;/activity>
-</pre>
-
-
-
-
-
-<h3 id="ShowStepCount">Show step count</h3>
-
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
-  </div>
-  <p class="now-title">Google Now</p>
-  <ul>
-    <li>"how many steps have I taken?"</li>
-    <li>"what's my step count?"</li>
-  </ul>
-</div>
-
-<p>To show the user's step count, use the
-<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-<code>ACTION_VIEW</code></a> action with the
-<code>"vnd.google.fitness.data_type<br/>/com.google.step_count<br/>.cumulative"</code> MIME
-type.</p>
-
-<dl>
-  <dt><b>Action</b></dt>
-  <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-      <code>ACTION_VIEW</code></a><dd>
-
-  <dt><b>Data URI</b></dt>
-  <dd>None</dd>
-
-  <dt><b>MIME Type</b></dt>
-  <dd><code>"vnd.google.fitness.data_type/com.google.step_count.cumulative"</code></dd>
-
-  <dt><b>Extras</b></dt>
-  <dd>None</dd>
-</dl>
-
-
-<p><b>Example intent:</b></p>
-<pre>
-public void showStepCount() {
-    Intent intent = new Intent(FitnessIntents.ACTION_VIEW)
-            .setType("vnd.google.fitness.data_type/com.google.step_count.cumulative");
-    if (intent.resolveActivity(getPackageManager()) != null) {
-        startActivity(intent);
-    }
-}
-</pre>
-
-
-<p><b>Example intent filter:</b></p>
-<pre>
-&lt;activity ...>
-    &lt;intent-filter>
-        &lt;action android:name="vnd.google.fitness.VIEW" />
-        &lt;data android:mimeType="vnd.google.fitness.data_type/com.google.step_count.cumulative" />
-        &lt;category android:name="android.intent.category.DEFAULT" />
-    &lt;/intent-filter>
-&lt;/activity>
-</pre>
-
-
-
-
-
-
-
-
 <h2 id="Local">Local Actions</h2>
 
 <h3 id="CallCar">Call a car</h3>
@@ -2447,7 +2053,7 @@
 <dt><b>MIME Type</b></dt>
 <dd>
   <dl>
-    <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} (<code>"text/plain"</code>)
+    <dt><code>"text/plain"</code>
     <dt><code>"image/*"</code>
     <dt><code>"video/*"</code>
   </dl>
@@ -2558,7 +2164,7 @@
   <dt><b>MIME Type</b></dt>
   <dd>
     <dl>
-      <dt>{@link org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE} (<code>"text/plain"</code>)
+      <dt><code>"text/plain"</code>
       <dt><code>"text/html"</code>
       <dt><code>"application/xhtml+xml"</code>
       <dt><code>"application/vnd.wap.xhtml+xml"</code>
@@ -2695,65 +2301,6 @@
   <td>{@link android.content.Intent#ACTION_CALL Intent.ACTION_CALL}</td>
 </tr>
 <tr>
-  <td rowspan="5" style="vertical-align:middle">Fitness</td>
-  <td>
-    <p><a href="#TrackRide">Start/stop a bike ride</a></p>
-    <ul class="now-list">
-      <li>"start cycling"</li>
-      <li>"start my bike ride"</li>
-      <li>"stop cycling"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>FitnessIntents.ACTION_TRACK</code></a></td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#TrackRun">Start/stop a run</a></p>
-    <ul class="now-list">
-      <li>"track my run"</li>
-      <li>"start running"</li>
-      <li>"stop running"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>FitnessIntents.ACTION_TRACK</code></a></td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#TrackWorkout">Start/stop a workout</a></p>
-    <ul class="now-list">
-      <li>"start a workout"</li>
-      <li>"track my workout"</li>
-      <li>"stop workout"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK">
-      <code>FitnessIntents.ACTION_TRACK</code></a></code></td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#ShowHeartRate">Show heart rate</a></p>
-    <ul class="now-list">
-      <li>"what's my heart rate"</li>
-      <li>"what's my bpm"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-      <code>FitnessIntents.ACTION_VIEW</code></a></code></td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#ShowStepCount">Show step count</a></p>
-    <ul class="now-list">
-      <li>"how many steps have I taken"</li>
-      <li>"what's my step count"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW">
-      <code>FitnessIntents.ACTION_VIEW</code></a></td>
-</tr>
-<tr>
   <td style="vertical-align:middle">Local</td>
   <td>
     <p><a href="#CallCar">Book a car</a></p>
diff --git a/docs/html/guide/components/intents-filters.jd b/docs/html/guide/components/intents-filters.jd
index 3dec216..0759088 100644
--- a/docs/html/guide/components/intents-filters.jd
+++ b/docs/html/guide/components/intents-filters.jd
@@ -376,9 +376,7 @@
 Intent sendIntent = new Intent();
 sendIntent.setAction(Intent.ACTION_SEND);
 sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
-sendIntent.setType({@link
-        org.apache.http.protocol.HTTP#PLAIN_TEXT_TYPE
-        HTTP.PLAIN_TEXT_TYPE}); // "text/plain" MIME type
+sendIntent.setType("text/plain");
 
 // Verify that the intent will resolve to an activity
 if (sendIntent.resolveActivity(getPackageManager()) != null) {
diff --git a/docs/html/guide/faq/commontasks.jd b/docs/html/guide/faq/commontasks.jd
index 086721f..2943aef 100644
--- a/docs/html/guide/faq/commontasks.jd
+++ b/docs/html/guide/faq/commontasks.jd
@@ -653,7 +653,7 @@
 <p>You can highlight or style the formatting of strings or substrings of text in
     a TextView object. There are two ways to do this:</p>
 <ul>
-    <li>If you use a <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">string resource</a>,
+    <li>If you use a <a href="{@docRoot}guide/topics/resources/string-resource.html">string resource</a>,
         you can add some simple styling, such as bold or italic using HTML notation.
         The currently supported tags are: <code>B</code> (bold),
         <code>I</code> (italic), <code>U</code> (underline),
@@ -661,8 +661,8 @@
         <code>SUP</code> (superscript), <code>SUB</code> (subscript),
         and <code>STRIKE</code> (strikethrough).
         So, for example, in res/values/strings.xml you could declare this:<br />
-        <code>&lt;resource&gt;<br />
-        &nbsp;&nbsp;&nbsp;&nbsp;&lt;string&nbsp;id=&quot;@+id/styled_welcome_message&quot;&gt;We
+        <code>&lt;resources&gt;<br />
+        &nbsp;&nbsp;&nbsp;&nbsp;&lt;string&nbsp;name=&quot;styled_welcome_message&quot;&gt;We
         are &lt;b&gt;&lt;i&gt;so&lt;/i&gt;&lt;/b&gt; glad to see you.&lt;/string&gt;<br />
         &lt;/resources&gt;</code></li>
     <li>To style text on the fly, or to add highlighting or more complex styling,
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index 4b5a121..9cae53c 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -228,9 +228,9 @@
 <p>The following code snippet demonstrates how to build an {@link android.widget.ImageView} that
   uses an image from drawable resources and add it to the layout.</p>
 <pre>
-  LinearLayout mLinearLayout;
+LinearLayout mLinearLayout;
 
-  protected void onCreate(Bundle savedInstanceState) {
+protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
 
   // Create a LinearLayout in which to add the ImageView
@@ -241,20 +241,20 @@
   i.setImageResource(R.drawable.my_image);
   i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions
   i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT,
-  LayoutParams.WRAP_CONTENT));
+      LayoutParams.WRAP_CONTENT));
 
   // Add the ImageView to the layout and set the layout as the content view
   mLinearLayout.addView(i);
   setContentView(mLinearLayout);
-  }
+}
 </pre>
 <p>In other cases, you may want to handle your image resource as a
   {@link android.graphics.drawable.Drawable} object.
   To do so, create a Drawable from the resource like so:
   <pre>
-    Resources res = mContext.getResources();
-    Drawable myImage = res.getDrawable(R.drawable.my_image);
-  </pre>
+Resources res = mContext.getResources();
+Drawable myImage = res.getDrawable(R.drawable.my_image);
+</pre>
 
   <p class="warning"><strong>Note:</strong> Each unique resource in your project can maintain only
 one state, no matter how many different objects you may instantiate for it. For example, if you
@@ -269,12 +269,12 @@
   <p>The XML snippet below shows how to add a resource Drawable to an
     {@link android.widget.ImageView} in the XML layout (with some red tint just for fun).
     <pre>
-      &lt;ImageView
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:tint="#55ff0000"
-      android:src="@drawable/my_image"/>
-  </pre>
+&lt;ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:tint="#55ff0000"
+        android:src="@drawable/my_image"/>
+</pre>
   <p>For more information on using project resources, read about
     <a href="{@docRoot}guide/topics/resources/index.html">Resources and Assets</a>.</p>
 
@@ -305,22 +305,22 @@
     <h4 id="drawable-xml-example">Example</h4>
     <p>Here's some XML that defines a TransitionDrawable:</p>
     <pre>
-      &lt;transition xmlns:android="http://schemas.android.com/apk/res/android">
-      &lt;item android:drawable="&#64;drawable/image_expand">
-      &lt;item android:drawable="&#64;drawable/image_collapse">
-      &lt;/transition>
-    </pre>
+&lt;transition xmlns:android="http://schemas.android.com/apk/res/android">
+    &lt;item android:drawable="&#64;drawable/image_expand">
+    &lt;item android:drawable="&#64;drawable/image_collapse">
+&lt;/transition>
+</pre>
 
     <p>With this XML saved in the file <code>res/drawable/expand_collapse.xml</code>,
       the following code will instantiate the TransitionDrawable and set it as the content of an
       ImageView:</p>
     <pre>
-      Resources res = mContext.getResources();
-      TransitionDrawable transition = (TransitionDrawable)
-res.getDrawable(R.drawable.expand_collapse);
-      ImageView image = (ImageView) findViewById(R.id.toggle_image);
-      image.setImageDrawable(transition);
-    </pre>
+Resources res = mContext.getResources();
+TransitionDrawable transition = (TransitionDrawable)
+    res.getDrawable(R.drawable.expand_collapse);
+ImageView image = (ImageView) findViewById(R.id.toggle_image);
+image.setImageDrawable(transition);
+</pre>
     <p>Then this transition can be run forward (for 1 second) with:</p>
     <pre>transition.startTransition(1000);</pre>
 
@@ -337,7 +337,7 @@
       primitive shapes and style them in any way imaginable.</p>
 
     <p>A ShapeDrawable is an extension of {@link android.graphics.drawable.Drawable}, so you can use
-one      where ever
+one wherever
       a Drawable is expected &mdash; perhaps for the background of a View, set with
       {@link android.view.View#setBackgroundDrawable(android.graphics.drawable.Drawable)
       setBackgroundDrawable()}.
@@ -349,27 +349,27 @@
       Here's a basic extension of the View class that does just this, to draw a ShapeDrawable as a
       View:</p>
     <pre>
-      public class CustomDrawableView extends View {
-      private ShapeDrawable mDrawable;
+public class CustomDrawableView extends View {
+  private ShapeDrawable mDrawable;
 
-      public CustomDrawableView(Context context) {
-      super(context);
+  public CustomDrawableView(Context context) {
+    super(context);
 
-      int x = 10;
-      int y = 10;
-      int width = 300;
-      int height = 50;
+    int x = 10;
+    int y = 10;
+    int width = 300;
+    int height = 50;
 
-      mDrawable = new ShapeDrawable(new OvalShape());
-      mDrawable.getPaint().setColor(0xff74AC23);
-      mDrawable.setBounds(x, y, x + width, y + height);
-      }
+    mDrawable = new ShapeDrawable(new OvalShape());
+    mDrawable.getPaint().setColor(0xff74AC23);
+    mDrawable.setBounds(x, y, x + width, y + height);
+  }
 
-      protected void onDraw(Canvas canvas) {
-      mDrawable.draw(canvas);
-      }
-      }
-    </pre>
+  protected void onDraw(Canvas canvas) {
+    mDrawable.draw(canvas);
+  }
+}
+</pre>
 
     <p>In the constructor, a ShapeDrawable is defines as an {@link
       android.graphics.drawable.shapes.OvalShape}.
@@ -379,15 +379,15 @@
     <p>With the custom View defined, it can be drawn any way you like. With the sample above, we can
       draw the shape programmatically in an Activity:</p>
     <pre>
-      CustomDrawableView mCustomDrawableView;
+CustomDrawableView mCustomDrawableView;
 
-      protected void onCreate(Bundle savedInstanceState) {
-      super.onCreate(savedInstanceState);
-      mCustomDrawableView = new CustomDrawableView(this);
+protected void onCreate(Bundle savedInstanceState) {
+  super.onCreate(savedInstanceState);
+  mCustomDrawableView = new CustomDrawableView(this);
 
-      setContentView(mCustomDrawableView);
-      }
-    </pre>
+  setContentView(mCustomDrawableView);
+}
+</pre>
 
     <p>If you'd like to draw this custom drawable from the XML layout instead of from the Activity,
       then the CustomDrawable class must override the {@link
@@ -396,11 +396,11 @@
       instantiating a View via inflation from XML. Then add a CustomDrawable element to the XML,
       like so:</p>
     <pre>
-      &lt;com.example.shapedrawable.CustomDrawableView
-      android:layout_width="fill_parent"
-      android:layout_height="wrap_content"
-      />
-  </pre>
+&lt;com.example.shapedrawable.CustomDrawableView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        />
+</pre>
 
   <p>The ShapeDrawable class (like many other Drawable types in the {@link
 android.graphics.drawable}    package)
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index ecba508..77f16dd 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -24,7 +24,7 @@
 attributes for each of its parts:
 
 <p style="margin-left: 2em">
-{@code &lt;scheme>://&lt;host>:&lt;port>/[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
+{@code &lt;scheme>://&lt;host>:&lt;port>[&lt;path>|&lt;pathPrefix>|&lt;pathPattern>]}</p>
 
 <p>
 These attributes that specify the URL format are optional, but also mutually dependent:
@@ -115,7 +115,8 @@
 <dt><a name="path"></a>{@code android:path}
 <br/>{@code android:pathPrefix}
 <br/>{@code android:pathPattern}</dt>
-<dd>The path part of a URI.  The {@code path} attribute specifies a complete
+<dd>The path part of a URI which must begin with a /.
+The {@code path} attribute specifies a complete
 path that is matched against the complete path in an Intent object.  The
 {@code pathPrefix} attribute specifies a partial path that is matched against
 only the initial part of the path in the Intent object.  The {@code pathPattern}
diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd
index 2213b72..e26f263 100644
--- a/docs/html/guide/topics/manifest/service-element.jd
+++ b/docs/html/guide/topics/manifest/service-element.jd
@@ -138,7 +138,7 @@
 </p></dd>
 
 <dt><a name="prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that that an entity must have in order to 
+<dd>The name of a permission that an entity must have in order to 
 launch the service or bind to it.  If a caller of 
 <code>{@link android.content.Context#startService startService()}</code>,
 <code>{@link android.content.Context#bindService bindService()}</code>, or
@@ -156,7 +156,7 @@
 
 <p>
 For more information on permissions, see the 
-<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a> 
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a> 
 section in the introduction and a separate document, 
 <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
 </p></dd>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 1ee6606..0a96a15 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -433,8 +433,8 @@
 <p>To change the locale in the emulator by using the adb shell. </p>

 

 <ol>

-  <li>Pick the locale you want to test and determine its language and region codes, for

-example <code>fr</code> for French and <code>CA</code> for Canada.<br>

+  <li>Pick the locale you want to test and determine its BCP-47 language tag, for

+example, Canadian French would be <code>fr-CA</code>.<br>

   </li>

   <li>Launch an emulator.</li>

   <li>From a command-line shell on the host computer, run the following

@@ -444,16 +444,14 @@
 the <code>-e</code> option:<br>

   <code>adb -e shell</code></li>

   <li>At  the  adb shell prompt (<code>#</code>), run this command: <br>

-    <code>setprop persist.sys.language  [<em>language code</em>];setprop

-persist.sys.country [<em>country  code</em>];stop;sleep 5;start <br>

+    <code>setprop persist.sys.locale [<em>BCP-47 language tag</em>];stop;sleep 5;start <br>

     </code>Replace bracketed sections with the  appropriate codes from Step

 1.</li>

 </ol>

 

 <p>For instance, to test in Canadian French:</p>

 

-<p><code>setprop persist.sys.language  fr;setprop persist.sys.country

-CA;stop;sleep 5;start </code></p>

+<p><code>setprop persist.sys.locale fr-CA;stop;sleep 5;start </code></p>

 

 <p>This will cause the emulator  to restart. (It will look like a full reboot,

 but it is not.) Once the Home screen appears again, re-launch your application (for

diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
index 9d2fa94..4874bb4 100644
--- a/docs/html/guide/topics/search/searchable-config.jd
+++ b/docs/html/guide/topics/search/searchable-config.jd
@@ -329,7 +329,7 @@
       <dt><a name="suggestActionMsg"></a><code>android:suggestActionMsg</code></dt>
         <dd><em>String</em>. An action message to be sent if the action key is pressed while a
         suggestion is in focus. This is added to the
-        intent that that the system passes to your searchable activity (using the action
+        intent that the system passes to your searchable activity (using the action
 you've defined for the suggestion). To examine the string,
         use {@link android.content.Intent#getStringExtra
         getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
index ec89e37..a02fd89 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
index cf0c63d..c309ac5 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
index f226a54..414fad4 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
new file mode 100644
index 0000000..c147a87
--- /dev/null
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
index ded0645..4ce2125 100644
--- a/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
+++ b/docs/html/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/docs/html/reference/com/google/android/gms/location/LocationRequest.html b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
index 4e67554..6145607 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationRequest.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
@@ -2614,7 +2614,7 @@
  <p>This interval is inexact. You may not receive updates at all (if no location sources
  are available), or you may receive them slower than requested. You may also receive them
  faster than requested (if other applications are requesting location at a faster interval).
- The fastest rate that that you will receive updates can be controlled with
+ The fastest rate that you will receive updates can be controlled with
  <code><a href="/reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">setFastestInterval(long)</a></code>.  By default this fastest rate is 6x the interval frequency.
 
  <p>Applications with only the coarse location permission may have their interval silently
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 124b4e2..a43ba3c 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -141,7 +141,7 @@
 
 3.2 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "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 SDK 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 SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.
+3.3 You may not use the SDK 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 SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.
 
 3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the SDK.
 
@@ -244,7 +244,7 @@
 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.
 
 
-<em>November 13, 2012</em>
+<em>December 8, 2014</em>
 </div>
 
 
@@ -298,7 +298,6 @@
 <li>Android 5.0 emulator system image with Google APIs</li>
 </ul>
 
-
 <a class="online landing-button green download-bundle-button" style="margin-top:30px;"
 href="#Other" >Download Android Studio</a>
 
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index 88619bd..58a8065 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -64,10 +64,10 @@
 
 <p>To start adding packages, launch the Android SDK Manager in one of the following ways:</p>
 <ul>
-  <li>In Android Studio, click <strong>SDK Manager</strong>
+  <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 Android Studio:
+  <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>
@@ -77,7 +77,7 @@
   </li>
 </ul>
 
-<p>When you open the SDK Manager for the first time, several packages are selected by
+<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>
 
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index dc258db..45d1890 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -87,7 +87,7 @@
 
 <p><b>To set up Android Studio on Mac OSX:</b></p>
   <ol>
-    <li>Launch the {@code .dmg} file you just downloaded.</li>
+    <li>Unzip the downloaded zip file, {@code android-studio-ide-&lt;version&gt;-mac.zip}.</li>
     <li>Drag and drop Android Studio into the Applications folder.
     <li>Open Android Studio and follow the setup wizard to install any necessary SDK tools.
       <p>
@@ -97,11 +97,13 @@
       <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
       Then open Android Studio again.</p>
     </li>
+    <li>Follow the links to install the SDK outside of the Android Studio directories.</li>
   </ol>
 
-<p>If you need use the Android SDK tools from a command line,
-you can access them at:</p>
-<p><code>/Users/&lt;user>/Library/Android/sdk/</code></p>
+<p>The individual tools and other SDK packages are saved outside the Android Studio application
+directory. If you need access the tools directly, use a terminal to navigate into the location
+where they are installed. For example:</p>
+<p><code>/Applications/sdk/</code></p>
 
 
 </div><!-- end mac -->
@@ -112,7 +114,7 @@
 <p><b>To set up Android Studio on Linux:</b></p>
 
   <ol>
-    <li>Unpack the downloaded ZIP file into an
+    <li>Unpack the downloaded Tar file, {@code android-studio-ide-&lt;version&gt;-linux.zip}, 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}.
diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd
index 69c188c..c3edff6 100644
--- a/docs/html/sdk/installing/studio-tips.jd
+++ b/docs/html/sdk/installing/studio-tips.jd
@@ -4,16 +4,9 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-    <h2>In this document</h2>
-    <ol>
-      <li><a href="#productivity-features">Productivity Features</a></li>
-      <li><a href="#intellij">Working with IntelliJ</a></li>
-      <li><a href="#key-commands">Key Commands</a></li>
-    </ol>
-
   <h2>See also</h2>
   <ol>
-    <li><a href="{@docRoot}sdk/index.html">Download Android Studio</a></li>
+    <li><a href="{@docRoot}tools/sdk/index.html">Download Android Studio</a></li>
     <li><a href="http://wiki.jetbrains.net/intellij/Android">IntelliJ IDEA Android Tutorials</a></li>
     <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li>
   </ol>
@@ -26,136 +19,135 @@
 enhancements. </p>
 
 
-<h2 id="productivity-features">Productivity Features</h2>
-
-<p>Android Studio includes a number of features to help you be more productive in your coding.
-This section notes a few of the key features to help you work quickly and efficiently.
-</p>
+     <h2>Smart Rendering</h2>
+     <p>With smart rendering, Android Studio displays links for quick fixes to rendering errors.
+     For example, if you add a button to the layout without specifying the <em>width</em> and
+     <em>height</em> atttributes, Android Studio displays the rendering message <em>Automatically
+     add all missing attributs</em>. Clicking the message adds the missing attributes to the layout.</p>
 
 
-<h3>Smart Rendering</h3>
-<p>With smart rendering, Android Studio displays links for quick fixes to rendering errors.
-For example, if you add a button to the layout without specifying the <em>width</em> and
-<em>height</em> atttributes, Android Studio displays the rendering message <em>Automatically
-add all missing attributs</em>. Clicking the message adds the missing attributes to the layout.</p>
+     <h2> Bitmap rendering in the debugger</h2>
+     <p>While debugging, you can now right-click on bitmap variables in your app and invoke
+     <em>View Bitmap</em>. This fetches the associated data from the debugged process and renders
+     the bitmap in the debugger. </p>
+    <p><img src="{@docRoot}images/tools/studio-bitmap-rendering.png" style="width:350px"/></p>
+    <p class="img-caption"><strong>Figure 13.</strong> Bitmap Rendering/p>
 
 
-<h3> Bitmap rendering in the debugger</h3>
-<p>While debugging, you can now right-click on bitmap variables in your app and invoke
-<em>View Bitmap</em>. This fetches the associated data from the debugged process and renders
-the bitmap in the debugger. </p>
-<p><img src="{@docRoot}images/tools/studio-bitmap-rendering.png" style="width:350px"/></p>
-<p class="img-caption"><strong>Figure 1.</strong> Bitmap Rendering</p>
+     <h2>Output window message filtering</h2>
+     <p>When checking build results, you can filter messages by <em>message type</em> to quickly
+     locate messages of interest.</p>
+     <img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" />
+     <p class="img-caption"><strong>Figure 14.</strong> Filter Build Messages</p>
 
 
-<h3>Output window message filtering</h3>
-<p>When checking build results, you can filter messages by <em>message type</em> to quickly
-locate messages of interest.</p>
-<img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" />
-<p class="img-caption"><strong>Figure 2.</strong> Filter Build Messages</p>
+
+    <h2>Hierarchical parent setting</h2>
+    <p>The activity parent can now be set in the Activity Wizard when creating a new
+    activity. Setting a <em>hierarchal parent</em> sets the {@code Up} button to automatically
+    appear in the app's Action bar when viewing a child activity, so the {@code Up}
+    button no longer needs to be manually specified in the <em>menu.xml</em> file.</p>
 
 
-<h3>Hierarchical parent setting</h3>
-<p>The activity parent can now be set in the Activity Wizard when creating a new
-activity. Setting a <em>hierarchal parent</em> sets the {@code Up} button to automatically
-appear in the app's Action bar when viewing a child activity, so the {@code Up}
-button no longer needs to be manually specified in the <em>menu.xml</em> file.</p>
+    <h2>Creating layouts</h2>
+    <p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets
+    into your layout and preview your layout while editing the XML.</p>
+
+    <p>While editing in the <strong>Text</strong> view, you can preview the layout on devices by
+    opening the <strong>Preview</strong> pane available on the right side of the window. Within the
+    Preview pane, you can modify the preview by changing various options at the top of the pane,
+    including the preview device, layout theme, platform version and more. To preview the layout on
+    multiple devices simultaneously, select <strong>Preview All Screen Sizes</strong> from the
+    device drop-down.</p>
+    <p><img src="{@docRoot}images/tools/studio-previewall.png" style="width:350px"/></p>
+    <p class="img-caption"><strong>Figure 15.</strong> Preview All Screens/p>
+
+    <p>You can switch to the graphical editor by clicking <strong>Design</strong> at the
+    bottom of the window. While editing in the Design view, you can show and hide the
+    widgets available to drag-and-drop by clicking <strong>Palette</strong> on the left side of the
+    window. Clicking <strong>Designer</strong> on the right side of the window reveals a panel
+    with a layout hierarchy and a list of properties for each view in the layout.</p>
 
 
-<h3>Creating layouts</h3>
-<p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets
-into your layout and preview your layout while editing the XML.</p>
+     <h2 id="intellij">Working with IntelliJ</h3>
 
-<p>While editing in the <strong>Text</strong> view, you can preview the layout on devices by
-opening the <strong>Preview</strong> pane available on the right side of the window. Within the
-Preview pane, you can modify the preview by changing various options at the top of the pane,
-including the preview device, layout theme, platform version and more. To preview the layout on
-multiple devices simultaneously, select <strong>Preview All Screen Sizes</strong> from the
-device drop-down.</p>
-<p><img src="{@docRoot}images/tools/studio-previewall.png" style="width:350px"/></p>
-<p class="img-caption"><strong>Figure 3.</strong> Preview All Screens</p>
+     <p>This section list just a few of the code editing
+     practices you should consider using when creating Android Studio apps. </p>
 
-<p>You can switch to the graphical editor by clicking <strong>Design</strong> at the
-bottom of the window. While editing in the Design view, you can show and hide the
-widgets available to drag-and-drop by clicking <strong>Palette</strong> on the left side of the
-window. Clicking <strong>Designer</strong> on the right side of the window reveals a panel
-with a layout hierarchy and a list of properties for each view in the layout.</p>
+     <p>For complete user documentation for the IntelliJ IDEA interface (upon which Android Studio
+     is based), refer to the
+     <a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA documentation</a>.</p>
 
 
-<h2 id="intellij">Working with IntelliJ</h3>
 
-<p>This section list just a few of the code editing
-practices you should consider using when creating Android Studio apps. </p>
-
-<p>For complete user documentation for the IntelliJ IDEA interface (upon which Android Studio
-is based), refer to the
-<a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA documentation</a>.</p>
+     <h3><em>Alt + Enter</em> key binding</h3>
+     <p>For quick fixes to coding errors, the IntelliJ powered IDE implements the <em>Alt + Enter</em>
+     key binding to fix errors (missing imports, variable assignments, missing references, etc) when
+     possible, and if not, suggest the most probable solution. </p>
 
 
-<h3><em>Alt + Enter</em> key binding</h3>
-<p>For quick fixes to coding errors, the IntelliJ powered IDE implements the <em>Alt + Enter</em>
-key binding to fix errors (missing imports, variable assignments, missing references, etc) when
-possible, and if not, suggest the most probable solution. </p>
+    <h3><em>Ctrl + D</em> key binding</h3>
+    <p>The <em>Ctrl + D</em> key binding is great for quickly duplicating code lines or fragments.
+    Simply select the desired line or fragment and enter this key binding. </p>
+
+    <h3>Navigate menu</h3>
+    <p>In case you're not familiar with an API class, file or symbol, the <em>Navigate</em> menu lets
+    you jump directly to the class of a method or field name without having to search through
+    individual classes. </p>
 
 
-<h3><em>Ctrl + D</em> key binding</h3>
-<p>The <em>Ctrl + D</em> key binding is great for quickly duplicating code lines or fragments.
-Simply select the desired line or fragment and enter this key binding. </p>
+    <h3>Inspection scopes</h3>
+    <p>Scopes set the color of code segments for easy code identification and location. For example,
+    you can set a scope to identify all code related to a specific action bar.   </p>
 
 
-<h3>Navigate menu</h3>
-<p>In case you're not familiar with an API class, file or symbol, the <em>Navigate</em> menu lets
-you jump directly to the class of a method or field name without having to search through
-individual classes. </p>
+
+    <h3>External annotations</h3>
+    <p>Specify annotations within the code or from an external annotation file. The Android Studio
+    IDE keeps track of the restrictions and validates compliance, for example setting the data type
+    of a string as not null.</p>
 
 
-<h3>Inspection scopes</h3>
-<p>Scopes set the color of code segments for easy code identification and location. For example,
-you can set a scope to identify all code related to a specific action bar.   </p>
+
+    <h3>Injecting languages</h3>
+    <p>With language injection, the Android Studio IDE allows you to work with islands of different
+    languages embedded in the source code. This extends the syntax, error highlighting and coding
+    assistance to the embedded language. This can be especially useful for checking regular expression
+    values inline, and validating XML and SQL statments.</p>
 
 
-<h3>External annotations</h3>
-<p>Specify annotations within the code or from an external annotation file. The Android Studio
-IDE keeps track of the restrictions and validates compliance, for example setting the data type
-of a string as not null.</p>
+    <h3>Code folding</h3>
+    <p>This allows you to selectively hide and display sections of the code for readability. For
+    example, resource expressions or code for a nested class can be folded or hidden in to one line
+    to make the outer class structure easier to read. The inner clas can be later expanded for
+    updates. </p>
 
 
-<h3>Injecting languages</h3>
-<p>With language injection, the Android Studio IDE allows you to work with islands of different
-languages embedded in the source code. This extends the syntax, error highlighting and coding
-assistance to the embedded language. This can be especially useful for checking regular expression
-values inline, and validating XML and SQL statments.</p>
+    <h3>Image and color preview</h3>
+    <p>When referencing images and icons in your code, a preview of the image or icon appears
+    (in actual size at different densities) in the code margin to help you verify the image or icon
+    reference.  Pressing {@code F1} with the preview image or icon selected displays resource asset
+    details, such as the <em>dp</em> settings.   </p>
 
 
-<h3>Code folding</h3>
-<p>This allows you to selectively hide and display sections of the code for readability. For
-example, resource expressions or code for a nested class can be folded or hidden in to one line
-to make the outer class structure easier to read. The inner clas can be later expanded for
-updates. </p>
+    <h3>Quick F1 documentation</h3>
+    <p>You can now inspect theme attributes using <strong>View > Quick Documentation</strong>
+    (<strong>F1</strong>),
+    see the theme inheritance hierarchy, and resolve values for the various attributes.</p>
+
+    <p>If you invoke <strong> View > Quick Documentation</strong> (usually bound to F1) on the theme
+    attribute <em>?android:textAppearanceLarge</em>, you will see the theme inheritance hierarchy and
+    resolved values for the various attributes that are pulled in.</p>
 
 
-<h3>Image and color preview</h3>
-<p>When referencing images and icons in your code, a preview of the image or icon appears
-(in actual size at different densities) in the code margin to help you verify the image or icon
-reference.  Pressing {@code F1} with the preview image or icon selected displays resource asset
-details, such as the <em>dp</em> settings.   </p>
-
-<h3>Quick F1 documentation</h3>
-<p>You can now inspect theme attributes using <strong>View > Quick Documentation</strong>
-(<strong>F1</strong>),
-see the theme inheritance hierarchy, and resolve values for the various attributes.</p>
-
-<p>If you invoke <strong> View > Quick Documentation</strong> (usually bound to F1) on the theme
-attribute <em>?android:textAppearanceLarge</em>, you will see the theme inheritance hierarchy and
-resolved values for the various attributes that are pulled in.</p>
+     <h3>New Allocation Tracker integration in the Android/DDMS window</h3>
+     <p>You can now inspect theme attributes using <strong> View > Quick Documentation
+     </strong> <code>F1</code>, see the theme inheritance hierarchy, and resolved values for the
+     various attributes.</p>
+      <img src="{@docRoot}images/tools/studio-allocationtracker.png" style="width:300px" />
+      <p class="img-caption"><strong>Figure 16</strong> Allocation Tracker</p>
 
 
-<h3>New Allocation Tracker integration in the Android/DDMS window</h3>
-<p>You can now inspect theme attributes using <strong> View > Quick Documentation
-</strong> <code>F1</code>, see the theme inheritance hierarchy, and resolved values for the
-various attributes.</p>
-<img src="{@docRoot}images/tools/studio-allocationtracker.png" style="width:300px" />
-<p class="img-caption"><strong>Figure 4.</strong> Allocation Tracker</p>
 
 
 <h3 id="key-commands">Keyboard Commands</h3>
@@ -260,5 +252,13 @@
 </table>
 
 <p>For a complete keymap reference guide, see the
-<a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA</a>
-documentation.</p>
+<a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA</a> documentation.</p>
+
+
+</div>
+
+
+</div>
+
+
+
diff --git a/docs/html/tools/building/buidling-cmdline-ant.jd b/docs/html/tools/building/buidling-cmdline-ant.jd
new file mode 100644
index 0000000..51158de
--- /dev/null
+++ b/docs/html/tools/building/buidling-cmdline-ant.jd
@@ -0,0 +1,381 @@
+page.title=Building and Running from the Command Line
+parent.title=Building and Running
+parent.link=index.html
+@jd:body
+
+ <div id="qv-wrapper">
+    <div id="qv">
+      <h2>In this document</h2>
+      <ol>
+        <li><a href="#DebugMode">Building in Debug Mode</a></li>
+        <li><a href="#ReleaseMode">Building in Release Mode</a>
+          <ol>
+            <li><a href="#ManualReleaseMode">Build unsigned</a></li>
+            <li><a href="#AutoReleaseMode">Build signed and aligned</a></li>
+            <li><a href="#OnceBuilt">Once built and signed in release mode</a></li>
+          </ol>
+        </li>
+        <li><a href="#RunningOnEmulator">Running on the Emulator</a></li>
+        <li><a href="#RunningOnDevice">Running on a Device</a></li>
+        <li><a href="#Signing">Application Signing</a></li>
+        <li><a href="#AntReference">Ant Command Reference</a></li>
+      </ol>
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from
+the Command Line</a></li>
+    <li><a href="{@docRoot}tools/devices/emulator.html">Using the Android
+Emulator</a></li>
+    <li><a href="{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a></li>
+  </ol>
+    </div>
+  </div>
+
+  <p>There are two ways to build your application using the Ant build script: one for
+  testing/debugging your application &mdash; <em>debug mode</em> &mdash; and one for building your
+  final package for release &mdash; <em>release mode</em>. Regardless of which way you build your application,
+  it must be signed before it can install on an emulator or device&mdash;with a debug key when building
+  in debug mode and with your own private key when building in release mode.</p>
+
+  <p>Whether you're building in debug mode or release mode, you need to use the Ant tool to compile
+  and build your project. This will create the .apk file that you can install on an emulator or device.
+  When you build in debug mode, the .apk file is automatically signed by the SDK tools with
+  a debug key, so it's instantly ready for installation onto an emulator or attached
+  development device. You cannot distribute an application that is signed with a debug key.
+  When you build in release mode, the .apk file is <em>unsigned</em>, so you
+  must manually sign it with your own private key, using Keytool and Jarsigner.</p>
+
+  <p>It's important that you read and understand <a href=
+  "{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a>, particularly once
+  you're ready to release your application and share it with end-users. That document describes the
+  procedure for generating a private key and then using it to sign your .apk file. If you're just
+  getting started, however, you can quickly run your applications on an emulator or your own
+  development device by building in debug mode.</p>
+
+  <p>If you don't have Ant, you can obtain it from the <a href="http://ant.apache.org/">Apache Ant
+  home page</a>. Install it and make sure it is in your executable PATH. Before calling Ant, you
+  need to declare the JAVA_HOME environment variable to specify the path to where the JDK is
+  installed.</p>
+
+  <p class="note"><strong>Note:</strong> When installing JDK on Windows, the default is to install
+  in the "Program Files" directory. This location will cause <code>ant</code> to fail, because of
+  the space. To fix the problem, you can specify the JAVA_HOME variable like this:
+  <pre>set JAVA_HOME=c:\Progra~1\Java\&lt;jdkdir&gt;</pre>
+
+  <p>The easiest solution, however, is to install JDK in a non-space directory, for example:</p>
+
+  <pre>c:\java\jdk1.7</pre>
+
+  <h2 id="DebugMode">Building in Debug Mode</h2>
+
+  <p>For immediate application testing and debugging, you can build your application in debug mode
+  and immediately install it on an emulator. In debug mode, the build tools automatically sign your
+  application with a debug key and optimize the package with {@code zipalign}.</p>
+
+  <p>To build in debug mode:</p>
+
+  <ol>
+    <li>Open a command-line and navigate to the root of your project directory.</li>
+    <li>Use Ant to compile your project in debug mode:
+      <pre>
+ant debug
+</pre>
+
+      <p>This creates your debug <code>.apk</code> file inside the project <code>bin/</code> directory, named
+      <code>&lt;your_project_name&gt;-debug.apk</code>. The file is already signed with
+      the debug key and has been aligned with
+      <a href="{@docRoot}tools/help/zipalign.html"><code>zipalign</code></a>.
+      </p>
+    </li>
+  </ol>
+
+  <p>Each time you change a source file or resource, you must run Ant again in order to package up
+  the latest version of the application.</p>
+
+  <p>To install and run your application on an emulator, see the following section about <a href=
+  "#RunningOnEmulator">Running on the Emulator</a>.</p>
+
+  <h2 id="ReleaseMode">Building in Release Mode</h2>
+
+  <p>When you're ready to release and distribute your application to end-users, you must build your
+  application in release mode. Once you have built in release mode, it's a good idea to perform
+  additional testing and debugging with the final .apk.</p>
+
+  <p>Before you start building your application in release mode, be aware that you must sign the
+  resulting application package with your private key, and should then align it using the {@code
+  zipalign} tool. There are two approaches to building in release mode: build an unsigned package
+  in release mode and then manually sign and align the package, or allow the build script to sign
+  and align the package for you.</p>
+
+  <h3 id="ManualReleaseMode">Build unsigned</h3>
+
+  <p>If you build your application <em>unsigned</em>, then you will need to manually sign and align
+  the package.</p>
+
+  <p>To build an <em>unsigned</em> .apk in release mode:</p>
+
+  <ol>
+    <li>Open a command-line and navigate to the root of your project directory.</li>
+
+    <li>Use Ant to compile your project in release mode:
+      <pre>
+ant release
+</pre>
+    </li>
+  </ol>
+
+  <p>This creates your Android application .apk file inside the project <code>bin/</code>
+  directory, named <code><em>&lt;your_project_name&gt;</em>-unsigned.apk</code>.</p>
+
+  <p class="note"><strong>Note:</strong> The .apk file is <em>unsigned</em> at this point and can't
+  be installed until signed with your private key.</p>
+
+  <p>Once you have created the unsigned .apk, your next step is to sign the .apk with your private
+  key and then align it with {@code zipalign}. To complete this procedure, read <a href=
+  "{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a>.</p>
+
+  <p>When your <code>.apk</code> has been signed and aligned, it's ready to be distributed to end-users.
+  You should test the final build on different devices or AVDs to ensure that it
+  runs properly on different platforms.</p>
+
+  <h3 id="AutoReleaseMode">Build signed and aligned</h3>
+
+  <p>If you would like, you can configure the Android build script to automatically sign and align
+  your application package. To do so, you must provide the path to your keystore and the name of
+  your key alias in your project's {@code ant.properties} file. With this information provided,
+  the build script will prompt you for your keystore and alias password when you build in release
+  mode and produce your final application package, which will be ready for distribution.</p>
+
+  <p class="caution"><strong>Caution:</strong> Due to the way Ant handles input, the password that
+  you enter during the build process <strong>will be visible</strong>. If you are concerned about
+  your keystore and alias password being visible on screen, then you may prefer to perform the
+  application signing manually, via Jarsigner (or a similar tool). To instead perform the signing
+  procedure manually, <a href="#ManualReleaseMode">build unsigned</a> and then continue with
+  <a href="{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a>.</p>
+
+  <p>To specify your keystore and alias, open the project {@code ant.properties} file (found in
+  the root of the project directory) and add entries for {@code key.store} and {@code key.alias}.
+  For example:</p>
+  <pre>
+key.store=path/to/my.keystore
+key.alias=mykeystore
+</pre>
+
+  <p>Save your changes. Now you can build a <em>signed</em> .apk in release mode:</p>
+
+  <ol>
+    <li>Open a command-line and navigate to the root of your project directory.</li>
+
+    <li>Use Ant to compile your project in release mode:
+      <pre>
+ant release
+</pre>
+    </li>
+
+    <li>When prompted, enter you keystore and alias passwords.
+
+      <p class="caution"><strong>Caution:</strong> As described above, your password will be
+      visible on the screen.</p>
+    </li>
+  </ol>
+
+  <p>This creates your Android application .apk file inside the project <code>bin/</code>
+  directory, named <code><em>&lt;your_project_name&gt;</em>-release.apk</code>. This .apk file has
+  been signed with the private key specified in {@code ant.properties} and aligned with {@code
+  zipalign}. It's ready for installation and distribution.</p>
+
+  <h3 id="OnceBuilt">Once built and signed in release mode</h3>
+
+  <p>Once you have signed your application with a private key, you can install and run it on an
+  <a href="#RunningOnEmulator">emulator</a> or <a href="#RunningOnDevice">device</a>. You can
+  also try installing it onto a device from a web server. Simply upload the signed .apk to a web
+  site, then load the .apk URL in your Android web browser to download the application and begin
+  installation. (On your device, be sure you have enabled
+  <em>Settings &gt; Applications &gt; Unknown sources</em>.)</p>
+
+  <h2 id="RunningOnEmulator">Running on the Emulator</h2>
+
+  <p>Before you can run your application on the Android Emulator, you must <a href=
+  "{@docRoot}tools/devices/managing-avds.html">create an AVD</a>.</p>
+
+  <p>To run your application:</p>
+
+  <ol>
+    <li>
+      <strong>Open the AVD Manager and launch a virtual device</strong>
+
+      <p>From your SDK's <code>platform-tools/</code> directory, execute the {@code android} tool
+with the <code>avd</code> options:</p>
+      <pre>
+android avd
+</pre>
+
+      <p>In the <em>Virtual Devices</em> view, select an AVD and click <strong>Start</strong>.</p>
+    </li>
+
+    <li>
+      <strong>Install your application</strong>
+
+      <p>From your SDK's <code>tools/</code> directory, install the {@code .apk} on the
+      emulator:</p>
+      <pre>
+adb install <em>&lt;path_to_your_bin&gt;</em>.apk
+</pre>
+
+      <p>Your .apk file (signed with either a release or debug key) is in your project {@code bin/}
+      directory after you build your application.</p>
+
+      <p>If there is more than one emulator running, you must specify the emulator upon which to
+      install the application, by its serial number, with the <code>-s</code> option. For
+      example:</p>
+      <pre>
+adb -s emulator-5554 install <em>path/to/your/app</em>.apk
+</pre>
+
+      <p>To see a list of available device serial numbers, execute {@code adb devices}.</p>
+    </li>
+  </ol>
+
+  <p>If you don't see your application on the emulator, try closing the emulator and launching the
+  virtual device again from the AVD Manager. Sometimes when you install an application for the
+  first time, it won't show up in the application launcher or be accessible by other applications.
+  This is because the package manager usually examines manifests completely only on emulator
+  startup.</p>
+
+  <p>Be certain to create multiple AVDs upon which to test your application. You should have one
+  AVD for each platform and screen type with which your application is compatible. For instance, if
+  your application compiles against the Android 4.0 (API Level 14) platform, you should create an
+  AVD for each platform equal to and greater than 4.0 and an AVD for each <a href=
+  "{@docRoot}guide/practices/screens_support.html">screen type</a> you support, then test your
+  application on each one.</p>
+
+  <p class="note"><strong>Tip:</strong> If you have <em>only one</em> emulator running, you can
+  build your application and install it on the emulator in one simple step. Navigate to the root of
+  your project directory and use Ant to compile the project with <em>install mode</em>: <code>ant
+  install</code>. This will build your application, sign it with the debug key, and install it on
+  the currently running emulator.</p>
+
+  <h2 id="RunningOnDevice">Running on a Device</h2>
+
+  <p>Before you can run your application on a device, you must perform some basic setup for your
+  device:</p>
+
+  <ul>
+    <li>Enable <strong>USB debugging</strong> on your device.
+      <ul>
+        <li>On most devices running Android 3.2 or older, you can find the option under
+          <strong>Settings > Applications > Development</strong>.</li>
+        <li>On Android 4.0 and newer, it's in <strong>Settings > Developer options</strong>.
+          <p class="note"><strong>Note:</strong> On Android 4.2 and newer, <strong>Developer
+          options</strong> is hidden by default. To make it available, go
+          to <strong>Settings > About phone</strong> and tap <strong>Build number</strong>
+          seven times. Return to the previous screen to find <strong>Developer options</strong>.</p>
+        </li>
+      </ul>
+    </li>
+
+    <li>Ensure that your development computer can detect your device when connected via USB</li>
+  </ul>
+
+  <p>Read <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for
+  Development</a> for more information.</p>
+
+  <p>Once your device is set up and connected via USB, navigate to your SDK's <code>platform-tools/</code>
+  directory and install the <code>.apk</code> on the device:</p>
+  <pre>
+adb -d install <em>path/to/your/app</em>.apk
+</pre>
+
+  <p>The {@code -d} flag specifies that you want to use the attached device (in case you also have
+  an emulator running).</p>
+
+  <p>For more information on the tools used above, please see the following documents:</p>
+
+  <ul>
+    <li><a href="{@docRoot}tools/help/android.html">android Tool</a></li>
+
+    <li><a href="{@docRoot}tools/devices/emulator.html">Android Emulator</a></li>
+
+    <li><a href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> (ADB)</li>
+  </ul>
+
+  <h2 id="Signing">Application Signing</h2>
+
+  <p>As you begin developing Android applications, understand that all Android applications must be
+  digitally signed before the system will install them on an emulator or device. There are two ways
+  to do this: with a <em>debug key</em> (for immediate testing on an emulator or development
+  device) or with a <em>private key</em> (for application distribution).</p>
+
+  <p>The Android build tools help you get started by automatically signing your .apk files with a
+  debug key at build time. This means that you can compile your application and install it on the
+  emulator without having to generate your own private key. However, please note that if you intend
+  to publish your application, you <strong>must</strong> sign the application with your own private
+  key, rather than the debug key generated by the SDK tools.</p>
+
+  <p>The ADT plugin helps you get started quickly by signing your .apk files with a debug key,
+  prior to installing them on an emulator or development device. This means that you can quickly
+  run your application from Eclipse without having to generate your own private key. No specific
+  action on your part is needed, provided ADT has access to Keytool. However, please note that if
+  you intend to publish your application, you <strong>must</strong> sign the application with your
+  own private key, rather than the debug key generated by the SDK tools.</p>
+
+  <p>Please read <a href="{@docRoot}tools/publishing/app-signing.html">Signing Your
+  Applications</a>, which provides a thorough guide to application signing on Android and what it
+  means to you as an Android application developer. The document also includes a guide to exporting
+  and signing your application with the ADT's Export Wizard.</p>
+
+  <h2 id="AntReference">Ant Command Reference</h2>
+  <dt><code>ant clean</code></dt>
+  <dd>Cleans the project. If you include the <code>all</code> target before <code>clean</code>
+(<code>ant all clean</code>), other projects are also cleaned. For instance if you clean a
+test project, the tested project is also cleaned.</dd>
+
+  <dt><code>ant debug</code></dt>
+  <dd>Builds a debug package. Works on application, library, and test projects and compiles
+  dependencies as  needed.</dd>
+
+  <dt id="emma"><code>ant emma debug</code></dt>
+  <dd>Builds a test project while building the tested project with instrumentation turned on.
+  This is used to run tests with code coverage enabled.</dd>
+
+  <dt><code>ant release</code></dt>
+  <dd>Builds a release package.</dd>
+
+  <dt><code>ant instrument</code>
+  </dt>
+  <dd>Builds an instrumented debug package. This is generally called automatically when building a
+  test project with code coverage enabled (with the <code>emma</code>
+  target)</dd>
+
+  <dt><code>ant &lt;build_target&gt; install</code></dt>
+  <dd>Builds and installs a package. Using <code>install</code> by itself fails.</dd>
+
+  <dt><code>ant installd</code></dt>
+  <dd>Installs an already compiled debug package. This fails if the <code>.apk</code> is not
+  already built.</dd>
+
+  <dt><code>ant installr</code></dt>
+  <dd>Installs an already compiled release package. This fails if the <code>.apk</code> is not
+  already built.</dd>
+
+  <dt><code>ant installt</code></dt>
+  <dd>Installs an already compiled test package. Also installs the <code>.apk</code> of the
+  tested application. This fails if the <code>.apk</code> is not already built.</dd>
+
+  <dt><code>ant installi</code></dt>
+  <dd>Installs an already compiled instrumented package. This is generally not used manually as
+  it's called when installing a test package. This fails if the <code>.apk</code> is not already
+  built.</dd>
+
+   <dt><code>ant test</code></dt>
+   <dd>Runs the tests (for test projects). The tested and test <code>.apk</code> files must be
+   previously installed.</dd>
+
+  <dt><code>ant debug installt test</code></dt>
+  <dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
+  runs the tests.</dd>
+
+  <dt><code>ant emma debug install test</code></dt>
+  <dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
+  runs the tests with code coverage enabled.</dd>
+
diff --git a/docs/html/tools/building/building-eclipse.jd b/docs/html/tools/building/building-eclipse.jd
index 89c3e16..79ef3de 100644
--- a/docs/html/tools/building/building-eclipse.jd
+++ b/docs/html/tools/building/building-eclipse.jd
@@ -34,12 +34,12 @@
    <p>This document shows you how to run your application on an emulator or a real device
    from Eclipse&mdash;all of which is done using the debug version of your application.
    For more information about how to sign your application with a private key for release, see <a href=
-  "{@docRoot}tools/publishing/app-signing.html#ExportWizard">Signing Your Applications</a></p>
+  "{@docRoot}tools/workflow/publishing/app-signing.html#ExportWizard">Signing Your Applications</a></p>
 
   <h2 id="RunningOnEmulatorEclipse">Running on the emulator</h2>
 
   <p>Before you can run your application on the Android Emulator, you must <a href=
-  "{@docRoot}tools/devices/managing-avds.html">create an AVD</a>.</p>
+  "{@docRoot}tools/workflow/devices/managing-avds.html">create an AVD</a>.</p>
 
   <p>To run (or debug) your application, select <strong>Run</strong> &gt; <strong>Run</strong> (or
   <strong>Run</strong> &gt; <strong>Debug</strong>) from the Eclipse menu bar. The ADT plugin will
@@ -100,7 +100,7 @@
     <li>Ensure that your development computer can detect your device when connected via USB</li>
   </ul>
 
-  <p>Read <a href="{@docRoot}tools/device.html">Using Hardware Devices</a>
+  <p>Read <a href="{@docRoot}tools/workflow/devices/device.html">Using Hardware Devices</a>
   for more information.</p>
 
   <p>Once set up and your device is connected via USB, install your application on the device by
diff --git a/docs/html/tools/debugging/ddms.jd b/docs/html/tools/debugging/ddms.jd
index d2fb47a..e9c2877 100644
--- a/docs/html/tools/debugging/ddms.jd
+++ b/docs/html/tools/debugging/ddms.jd
@@ -140,7 +140,7 @@
 
     <li>Click <strong>Get Allocations</strong> to see a list of objects that have been allocated
     since you clicked on the <strong>Start Tracking</strong> button. You can click on <strong>Get
-    Allocations</strong> again to append to the list new objects that that have been
+    Allocations</strong> again to append to the list new objects that have been
     allocated.</li>
 
     <li>To stop tracking or to clear the data and start over, click the <strong>Stop Tracking
@@ -246,10 +246,8 @@
 // Transfer data using socket
 TrafficStats.untagSocket(outputSocket);</pre>
 
-<p>Alternatively, the Apache {@link org.apache.http.client.HttpClient} and 
-{@link java.net.URLConnection} APIs included in the platform
-automatically tag sockets internally based on the active tag (as 
-identified by 
+<p>Alternatively, the {@link java.net.URLConnection} APIs included in the platform
+automatically tag sockets internally based on the active tag (as identified by 
 {@link android.net.TrafficStats#getThreadStatsTag getThreadStatsTag()}).
 These APIs correctly tag/untag sockets when recycled through
 keep-alive pools. In the following example,  
@@ -258,15 +256,14 @@
 There can only be one active tag per thread. 
 That is the value that will 
 be returned by {@link android.net.TrafficStats#getThreadStatsTag getThreadStatsTag()}
-and thus used by {@link org.apache.http.client.HttpClient}  
- to tag sockets. The {@code finally} statement 
+and thus used by the HTTP client to tag sockets. The {@code finally} statement 
 invokes 
 {@link android.net.TrafficStats#clearThreadStatsTag clearThreadStatsTag()} 
 to clear the tag.</p>
 
 <pre>TrafficStats.setThreadStatsTag(0xF00D);
     try {
-        // Make network request using HttpClient.execute()
+        // Make network request using your http client.
     } finally {
         TrafficStats.clearThreadStatsTag();
 }</pre>
diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd
index eaa96d3..1860feb 100644
--- a/docs/html/tools/studio/index.jd
+++ b/docs/html/tools/studio/index.jd
@@ -101,7 +101,6 @@
 the <strong>Project</strong> drop-down. </p>
 
 
-
 <h3>Android Studio Project and Directory Structure</h3>
 <p>When you use the <em>Project</em> view of a new project in Android Studio, you
 should notice that the project structure appears different than you may be used to in Eclipse. Each
@@ -574,7 +573,6 @@
     <p><img src="{@docRoot}images/tools/studio-samples-githubaccess.png" /></p>
     <p class="img-caption"><strong>Figure 13.</strong> Code Sample Access</p>
 
-
     <p><img src="{@docRoot}images/tools/studio-sample-in-editor.png" /></p>
     <p class="img-caption"><strong>Figure 14.</strong> Imported Code Sample</p>
 
diff --git a/docs/html/tools/testing/testing_eclipse.jd b/docs/html/tools/testing/testing_eclipse.jd
index 7d3be47..6c9d55b 100644
--- a/docs/html/tools/testing/testing_eclipse.jd
+++ b/docs/html/tools/testing/testing_eclipse.jd
@@ -218,7 +218,7 @@
 <p>
     Another useful convention is to add the method <code>testPreconditions()</code> to your test
     class. Use this method to test that the application under test is initialized correctly. If this
-    test fails, you know that that the initial conditions were in error. When this happens, further
+    test fails, you know that the initial conditions were in error. When this happens, further
     test results are suspect, regardless of whether or not the tests succeeded.
 </p>
 <p>
diff --git a/docs/html/tools/testing/testing_otheride.jd b/docs/html/tools/testing/testing_otheride.jd
index 9484158..a774087 100644
--- a/docs/html/tools/testing/testing_otheride.jd
+++ b/docs/html/tools/testing/testing_otheride.jd
@@ -281,7 +281,7 @@
 <p>
     Another useful convention is to add the method <code>testPreConditions()</code> to your test
     class. Use this method to test that the application under test is initialized correctly. If this
-    test fails, you know that that the initial conditions were in error. When this happens, further
+    test fails, you know that the initial conditions were in error. When this happens, further
     test results are suspect, regardless of whether or not the tests succeeded.
 </p>
 <p>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 9ba7a22..3f4b111 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -1,10 +1,12 @@
 <ul id="nav">
 
+
+<!-- Downloads menu-->
+
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot
-?>sdk/index.html"><span class="en">Download</span></a></div>
+    <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/index.html">
+            <li><a href="<?cs var:toroot ?>sdk/installing/index.html">
           <span class="en">Installing the SDK</span></a></li>
 
       <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
@@ -16,15 +18,13 @@
 <!-- Android Studio menu-->
 
  <li class="nav-section">
-    <div class="nav-section-header">
-      <a href="<?cs var:toroot?>tools/studio/index.html">Android Studio</a>
-    </div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
-          Tips and Tricks</a></li>
-    </ul>
+    <div class="nav-section-header"><a href="<?cs var:toroot?>tools/studio/index.html"><span class="en">Android Studio</span></a></div>
+       <ul>
+         <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">Tips and Tricks</a> </li>
+       </ul>
 
- </li><!-- End of Android Studio menu -->
+ </li><!-- End of Android Studio Basics -->
+
 
 
 <!-- Workflow menu-->
@@ -70,7 +70,6 @@
           <li><a href="<?cs var:toroot ?>tools/building/building-cmdline.html">
             <span class="en">From the Command Line</span></a></li>
         </ul>
-      </li>
 
 
   <li class="nav-section">
@@ -82,8 +81,8 @@
             <a href="<?cs var:toroot?>tools/testing/testing_android.html">
             <span class="en">Fundamentals</span></a>
           </li>
-          <li><a href="<?cs var:toroot ?>tools/testing/testing_eclipse.html">
-            <span class="en">From Eclipse</span></a>
+          <li><a href="<?cs var:toroot ?>tools/testing/testing_studio.html">
+            <span class="en">From Android Studio</span></a>
           </li>
           <li><a href="<?cs var:toroot ?>tools/testing/testing_otheride.html">
             <span class="en">From Other IDEs</span></a>
@@ -143,12 +142,14 @@
         </ul>
       </li>
     </ul>
-  </li>
+  </li><!-- end of debugging -->
 
 
+
+<!-- Tool Help menu-->
+
   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/index.html"><span
-class="en">Tools Help</span></a></div>
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/index.html"><span 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/android.html">android</a></li>
@@ -173,7 +174,6 @@
        <li><a href="<?cs var:toroot ?>tools/help/zipalign.html">zipalign</a></li>
     </ul>
   </li>
-
   </li><!-- end of tools help -->
 
 
@@ -234,6 +234,7 @@
   </li><!-- end of support library -->
 
 
+
 <!-- Revision menu-->
 
   <li class="nav-section">
@@ -243,9 +244,10 @@
       <li><a href="<?cs var:toroot ?>tools/revisions/studio.html">
         <span class="en">Android Studio</span>
       </a></li>
-      <li><a href="<?cs var:toroot ?>tools/sdk/tools-notes.html">
+      <li><a href="<?cs var:toroot ?>tools/revisions/sdk/tools-notes.html">
         <span class="en">SDK Tools</span>
       </a></li>
+      </a></li>
       <li><a href="<?cs var:toroot ?>tools/revisions/build-tools.html">
         <span class="en">SDK Build Tools</span>
       </a></li>
@@ -257,13 +259,21 @@
       <li><a href="<?cs var:toroot ?>tools/sdk/eclipse-adt.html">
         <span class="en">ADT Plugin</span></a></li>
     </ul>
-  </li>
+  </li><!-- end of revision -->
+
+
+
+<!-- NDK menu-->
 
   <li class="nav-section">
     <div class="nav-section-header empty">
-      <a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">NDK</a>
+      <a href="<?cs var:toroot ?>tools/ndk/index.html">NDK</a>
     </div>
-  </li>
+  </li><!-- end of NDK -->
+
+
+
+<!-- ADK menu-->
 
   <li class="nav-section">
     <div class="nav-section-header">
@@ -274,7 +284,8 @@
       <li><a href="<?cs var:toroot ?>tools/adk/adk2.html">ADK 2012 Guide</a></li>
       <li><a href="<?cs var:toroot ?>tools/adk/adk.html">ADK 2011 Guide</a></li>
     </ul>
-  </li>
+  </li><!-- end of ADK -->
+
 
 
 <!-- Eclipse ADT menu-->
diff --git a/docs/html/training/articles/security-gms-provider.jd b/docs/html/training/articles/security-gms-provider.jd
index 0d3cf1e..59983cc 100644
--- a/docs/html/training/articles/security-gms-provider.jd
+++ b/docs/html/training/articles/security-gms-provider.jd
@@ -52,8 +52,7 @@
 android.net.SSLCertificateSocketFactory}. Rather than using this class, we
 encourage app developers to use high-level methods for interacting with
 cryptography. Most apps can use APIs like {@link
-javax.net.ssl.HttpsURLConnection}, {@link org.apache.http.client.HttpClient},
-and {@link android.net.http.AndroidHttpClient} without needing to set a custom
+javax.net.ssl.HttpsURLConnection} without needing to set a custom
 {@link javax.net.ssl.TrustManager} or create an {@link
 android.net.SSLCertificateSocketFactory}.</p>
 
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 4bd92ee..79268a0 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -24,6 +24,8 @@
 <h2>You should also read</h2>
 
 <ul>
+  <li><a href="{@docRoot}sdk/installing/index.html">Installing the
+SDK</a></li>
   <li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
 </ul>
 
@@ -32,7 +34,8 @@
 </div>
 
 <p>An Android project contains all the files that comprise the source code for your Android
-app.</p>
+app. The Android SDK tools make it easy to start a new Android project with a set of
+default project directories and files.</p>
 
 <p>This lesson
 shows how to create a new project either using Android Studio or using the
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 4e3689a..1b6e00f 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -12,7 +12,7 @@
 <div id="tb-wrapper">
 <div id="tb">
 
-<h2>Dependencies</h2>
+<h2>Dependencies and prerequisites</h2>
 
 <ul>
   <li><a href="{@docRoot}sdk/index.html">Android Studio</a></li>
@@ -37,11 +37,14 @@
   <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
 </ol>
 
-<p class="note"><strong>Note:</strong> Although most of this training class
-expects that you're using Android Studio, some procedures include alternative
-instructions for using
-the SDK tools from the command line instead.</p>
+<p class="note"><strong>Note:</strong> Make sure you install the most recent versions of Android
+Studio and the Android SDK before you start this class. The procedures described in this class may
+not apply to earlier versions.</p>
 
-<p>This class uses a tutorial format to create a small Android app that teaches
+<p>If you haven't already done these tasks, start by downloading the
+  <a href="{@docRoot}sdk/index.html">Android SDK</a> and following the install steps.
+  Once you've finished the setup, you're ready to begin this class.</p>
+
+<p>This class uses a tutorial format that incrementally builds a small Android app that teaches
 you some fundamental concepts about Android development, so it's important that you follow each
 step.</p>
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
index 6e4605f..fdf0d1f 100644
--- a/docs/html/training/basics/firstapp/running-app.jd
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -25,7 +25,7 @@
 
 <ul>
   <li><a href="{@docRoot}tools/device.html">Using Hardware Devices</a></li>
-  <li><a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD Manager</a></li>
+  <li><a href="{@docRoot}tools/devices/index.html">Managing Virtual Devices</a></li>
   <li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
 </ul>
 
@@ -128,6 +128,10 @@
 AVD is a device configuration for the Android emulator that allows you to model a specific
 device.</p>
 
+<div class="figure" style="width:457px">
+  <img src="{@docRoot}images/screens_support/as-mac-avds-config.png" />
+  <p class="img-caption"><strong>Figure 1.</strong> The AVD Manager showing a virtual device.</p>
+</div>
 
 <h3>Create an AVD</h3>
 <ol>
@@ -157,11 +161,19 @@
   </li>
   <li>Verify the configuration settings, then click <strong>Finish</strong>.
   </li>
+  <li>In the <strong>Android Virtual Device Manager</strong> window, click <strong>Create</strong>.</li>
+  <li>Enter an <strong>AVD Name</strong>.</li>
+  <li>Select a <strong>Device</strong> type.
+    <p>When you select a device type, most of the fields auto-populate.</p>
+  <li>For <strong>Skin</strong> select <strong>HVGA</strong>.</li>
+  <li>For <strong>SD Card</strong>, enter something small, like 10 MiB.
+    <p>It really doesn't matter what you enter here since you're not using any storage. But if you
+      reuse this AVD, you might have to adjust this setting.</p></li>
+  <li>Ignore the <strong>Emulation Options</strong> and click <strong>OK</strong>.</li>
+  <li>In the <strong>Result</strong> screen, click <strong>OK</strong>.</li>
+  <li>Close the <strong>Android Virtual Device Manager</strong> window.</li>
 </ol>
 
-<p>For more information about using AVDs, see
-<a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD Manager</a>.</p>
-
 <h3>Run the app from Android Studio</h3>
 <ol>
   <li>In <strong>Android Studio</strong>, select your project and click <strong>Run</strong>
diff --git a/docs/html/training/basics/network-ops/connecting.jd b/docs/html/training/basics/network-ops/connecting.jd
index 1452ded..0601480 100644
--- a/docs/html/training/basics/network-ops/connecting.jd
+++ b/docs/html/training/basics/network-ops/connecting.jd
@@ -50,8 +50,8 @@
 <h2 id="http-client">Choose an HTTP Client</h2>
 
 <p>Most network-connected Android apps  use HTTP to send and receive  data.
-Android includes two HTTP clients: {@link java.net.HttpURLConnection} and Apache
- {@link org.apache.http.client.HttpClient}. Both support HTTPS, streaming uploads and downloads,  configurable
+Android includes two HTTP clients: {@link java.net.HttpURLConnection} and the Apache HTTP client.
+Both support HTTPS, streaming uploads and downloads,  configurable
 timeouts, IPv6, and connection pooling. We recommend using {@link
 java.net.HttpURLConnection} for applications targeted at Gingerbread and higher. For
 more discussion of this topic, see the blog post <a
diff --git a/docs/html/training/volley/requestqueue.jd b/docs/html/training/volley/requestqueue.jd
index 6858d91..5e892bf 100644
--- a/docs/html/training/volley/requestqueue.jd
+++ b/docs/html/training/volley/requestqueue.jd
@@ -39,14 +39,14 @@
 of the requests, and a cache to handle caching. There are standard implementations of these
 available in the Volley toolbox: {@code DiskBasedCache} provides a one-file-per-response
 cache with an in-memory index, and {@code BasicNetwork} provides a network transport based
-on your choice of {@link android.net.http.AndroidHttpClient} or {@link java.net.HttpURLConnection}.</p>
+on your choice of the Apache HTTP client {@code android.net.http.AndroidHttpClient} or
+{@link java.net.HttpURLConnection}.</p>
 
 <p>{@code BasicNetwork} is Volley's default network implementation. A {@code BasicNetwork}
 must be initialized with the HTTP client your app is using to connect to the network.
-Typically this is {@link android.net.http.AndroidHttpClient} or
-{@link java.net.HttpURLConnection}:</p>
+Typically this is a {@link java.net.HttpURLConnection}:</p>
 <ul>
-<li>Use {@link android.net.http.AndroidHttpClient} for apps targeting Android API levels
+<li>Use {@code android.net.http.AndroidHttpClient} for apps targeting Android API levels
 lower than API Level 9 (Gingerbread). Prior to Gingerbread, {@link java.net.HttpURLConnection}
 was unreliable. For more discussion of this topic, see
 <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">
diff --git a/docs/html/wear/design/index.jd b/docs/html/wear/design/index.jd
index 247cc87..e01d17f 100644
--- a/docs/html/wear/design/index.jd
+++ b/docs/html/wear/design/index.jd
@@ -164,7 +164,7 @@
 <img src="{@docRoot}wear/images/circle_voice_B.png" height="200" style="float:right;margin:0 0 20px 40px" />
 <img src="{@docRoot}wear/images/circle_voice_A.png" height="200" style="float:right;margin:0 0 20px 40px" />
 
-<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide a up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
+<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
 
 <p>You should attempt to cover a range of simple, neutral replies in your choices. Longer voice replies may be automatically truncated in the Voice reply UI.</p>
 
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index 474b9b2..08c7b95 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -39,8 +39,8 @@
     $(TOP)/frameworks/av/include \
     $(TOP)/libcore/include
 
-
-
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index d321baf..52597e1 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -381,7 +381,8 @@
 }
 
 static void android_drm_DrmManagerClient_installDrmEngine(
-            JNIEnv* env, jobject thiz, jint uniqueId, jstring engineFilePath) {
+            JNIEnv* /* env */, jobject /* thiz */, jint /* uniqueId */,
+            jstring /* engineFilePath */) {
     ALOGV("installDrmEngine - Enter");
     //getDrmManagerClient(env, thiz)
     //  ->installDrmEngine(uniqueId, Utility::getStringValue(env, engineFilePath));
@@ -776,7 +777,7 @@
     return result;
 }
 
-jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
     JNIEnv* env = NULL;
     jint result = -1;
 
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
index 206c959..48ee6fa 100644
--- a/graphics/java/android/graphics/AvoidXfermode.java
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -23,7 +23,7 @@
 @Deprecated
 public class AvoidXfermode extends Xfermode {
 
-    // these need to match the enum in SkAvoidXfermode.h on the native side
+    // these need to match the enum in AvoidXfermode.h on the native side
     public enum Mode {
         AVOID   (0),    //!< draw everywhere except on the opColor
         TARGET  (1);    //!< draw only on top of the opColor
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 72f6118..e2f7799 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,11 +16,14 @@
 
 package android.graphics;
 
+import android.annotation.CheckResult;
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Trace;
 import android.util.DisplayMetrics;
+
 import dalvik.system.VMRuntime;
 
 import java.io.OutputStream;
@@ -37,21 +40,14 @@
      * @see Bitmap#setDensity(int)
      */
     public static final int DENSITY_NONE = 0;
-    
-    /**
-     * Note:  mNativeBitmap is used by FaceDetector_jni.cpp
-     * Don't change/rename without updating FaceDetector_jni.cpp
-     * 
-     * @hide
-     */
-    public final long mNativeBitmap;
+
+    private final long mSkBitmapPtr;
 
     /**
      * Backing buffer for the Bitmap.
      */
     private byte[] mBuffer;
 
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
     private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
@@ -92,11 +88,11 @@
         sDefaultDensity = density;
     }
 
+    @SuppressWarnings("deprecation")
     static int getDefaultDensity() {
         if (sDefaultDensity >= 0) {
             return sDefaultDensity;
         }
-        //noinspection deprecation
         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
         return sDefaultDensity;
     }
@@ -105,7 +101,7 @@
      * Private constructor that must received an already allocated native bitmap
      * int (pointer).
      */
-    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    // called from JNI
     Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
             boolean isMutable, boolean requestPremultiplied,
             byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
@@ -120,7 +116,7 @@
         mBuffer = buffer;
 
         // we delete this in our finalizer
-        mNativeBitmap = nativeBitmap;
+        mSkBitmapPtr = nativeBitmap;
 
         mNinePatchChunk = ninePatchChunk;
         mNinePatchInsets = ninePatchInsets;
@@ -136,7 +132,7 @@
      * Native bitmap has been reconfigured, so set premult and cached
      * width/height values
      */
-    @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
+    // called from JNI
     void reinit(int width, int height, boolean requestPremultiplied) {
         mWidth = width;
         mHeight = height;
@@ -227,7 +223,7 @@
             throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
         }
 
-        nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+        nativeReconfigure(mSkBitmapPtr, width, height, config.nativeInt, mBuffer.length,
                 mRequestPremultiplied);
         mWidth = width;
         mHeight = height;
@@ -305,7 +301,7 @@
      */
     public void recycle() {
         if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
-            if (nativeRecycle(mNativeBitmap)) {
+            if (nativeRecycle(mSkBitmapPtr)) {
                 // return value indicates whether native pixel object was actually recycled.
                 // false indicates that it is still in use at the native level and these
                 // objects should not be collected now. They will be collected later when the
@@ -331,13 +327,13 @@
      * Returns the generation ID of this bitmap. The generation ID changes
      * whenever the bitmap is modified. This can be used as an efficient way to
      * check if a bitmap has changed.
-     * 
+     *
      * @return The current generation ID for this bitmap.
      */
     public int getGenerationId() {
-        return nativeGenerationId(mNativeBitmap);
+        return nativeGenerationId(mSkBitmapPtr);
     }
-    
+
     /**
      * This is called by methods that want to throw an exception if the bitmap
      * has already been recycled.
@@ -399,12 +395,12 @@
          * encoded: red is stored with 5 bits of precision (32 possible
          * values), green is stored with 6 bits of precision (64 possible
          * values) and blue is stored with 5 bits of precision.
-         * 
+         *
          * This configuration can produce slight visual artifacts depending
          * on the configuration of the source. For instance, without
          * dithering, the result might show a greenish tint. To get better
          * results dithering should be applied.
-         * 
+         *
          * This configuration may be useful when using opaque bitmaps
          * that do not require high color fidelity.
          */
@@ -414,18 +410,18 @@
          * Each pixel is stored on 2 bytes. The three RGB color channels
          * and the alpha channel (translucency) are stored with a 4 bits
          * precision (16 possible values.)
-         * 
+         *
          * This configuration is mostly useful if the application needs
          * to store translucency information but also needs to save
          * memory.
-         * 
+         *
          * It is recommended to use {@link #ARGB_8888} instead of this
          * configuration.
          *
          * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
          * any bitmap created with this configuration will be created
          * using {@link #ARGB_8888} instead.
-         * 
+         *
          * @deprecated Because of the poor quality of this configuration,
          *             it is advised to use {@link #ARGB_8888} instead.
          */
@@ -436,7 +432,7 @@
          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
          * for translucency) is stored with 8 bits of precision (256
          * possible values.)
-         * 
+         *
          * This configuration is very flexible and offers the best
          * quality. It should be used whenever possible.
          */
@@ -444,11 +440,10 @@
 
         final int nativeInt;
 
-        @SuppressWarnings({"deprecation"})
         private static Config sConfigs[] = {
             null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
         };
-        
+
         Config(int ni) {
             this.nativeInt = ni;
         }
@@ -492,7 +487,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsToBuffer(mNativeBitmap, dst);
+        nativeCopyPixelsToBuffer(mSkBitmapPtr, dst);
 
         // now update the buffer's position
         int position = dst.position();
@@ -532,7 +527,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsFromBuffer(mNativeBitmap, src);
+        nativeCopyPixelsFromBuffer(mSkBitmapPtr, src);
 
         // now update the buffer's position
         int position = src.position();
@@ -554,7 +549,7 @@
      */
     public Bitmap copy(Config config, boolean isMutable) {
         checkRecycled("Can't copy a recycled bitmap");
-        Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
+        Bitmap b = nativeCopy(mSkBitmapPtr, config.nativeInt, isMutable);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
             b.mDensity = mDensity;
@@ -564,7 +559,7 @@
 
     /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
-     * specified width and height are the same as the current width and height of 
+     * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
      * created.
      *
@@ -639,7 +634,7 @@
      * transformed by the optional matrix. The new bitmap may be the
      * same object as source, or a copy may have been made. It is
      * initialized with the same density as the original bitmap.
-     * 
+     *
      * If the source bitmap is immutable and the requested subset is the
      * same as the source bitmap itself, then the source bitmap is
      * returned and no new bitmap is created.
@@ -781,8 +776,8 @@
      * @param config   The bitmap config to create.
      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
      *                 bitmap as opaque. Doing so will clear the bitmap in black
-     *                 instead of transparent.  
-     * 
+     *                 instead of transparent.
+     *
      * @throws IllegalArgumentException if the width or height are <= 0
      */
     private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
@@ -800,8 +795,8 @@
      * @param config   The bitmap config to create.
      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
      *                 bitmap as opaque. Doing so will clear the bitmap in black
-     *                 instead of transparent.  
-     * 
+     *                 instead of transparent.
+     *
      * @throws IllegalArgumentException if the width or height are <= 0
      */
     private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
@@ -815,7 +810,7 @@
         }
         bm.setHasAlpha(hasAlpha);
         if (config == Config.ARGB_8888 && !hasAlpha) {
-            nativeErase(bm.mNativeBitmap, 0xff000000);
+            nativeErase(bm.mSkBitmapPtr, 0xff000000);
         }
         // No need to initialize the bitmap to zeroes with other configs;
         // it is backed by a VM byte array which is by definition preinitialized
@@ -1005,7 +1000,7 @@
             throw new IllegalArgumentException("quality must be 0..100");
         }
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
-        boolean result = nativeCompress(mNativeBitmap, format.nativeInt, quality,
+        boolean result = nativeCompress(mSkBitmapPtr, format.nativeInt, quality,
                               stream, new byte[WORKING_COMPRESS_STORAGE]);
         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         return result;
@@ -1022,12 +1017,12 @@
      * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
      * When a pixel is pre-multiplied, the RGB components have been multiplied by
      * the alpha component. For instance, if the original color is a 50%
-     * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is 
+     * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
      * <code>(128, 128, 0, 0)</code>.</p>
-     * 
+     *
      * <p>This method always returns false if {@link #getConfig()} is
      * {@link Bitmap.Config#RGB_565}.</p>
-     * 
+     *
      * <p>The return value is undefined if {@link #getConfig()} is
      * {@link Bitmap.Config#ALPHA_8}.</p>
      *
@@ -1046,7 +1041,7 @@
      * @see BitmapFactory.Options#inPremultiplied
      */
     public final boolean isPremultiplied() {
-        return nativeIsPremultiplied(mNativeBitmap);
+        return nativeIsPremultiplied(mSkBitmapPtr);
     }
 
     /**
@@ -1071,7 +1066,7 @@
      */
     public final void setPremultiplied(boolean premultiplied) {
         mRequestPremultiplied = premultiplied;
-        nativeSetPremultiplied(mNativeBitmap, premultiplied);
+        nativeSetPremultiplied(mSkBitmapPtr, premultiplied);
     }
 
     /** Returns the bitmap's width */
@@ -1137,7 +1132,7 @@
     public int getScaledHeight(int targetDensity) {
         return scaleFromDensity(getHeight(), mDensity, targetDensity);
     }
-    
+
     /**
      * @hide
      */
@@ -1145,11 +1140,11 @@
         if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
             return size;
         }
-        
+
         // Scale by tdensity / sdensity, rounding up.
         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
     }
-    
+
     /**
      * Return the number of bytes between rows in the bitmap's pixels. Note that
      * this refers to the pixels as stored natively by the bitmap. If you call
@@ -1163,7 +1158,7 @@
      * @return number of bytes between rows of the native bitmap pixels.
      */
     public final int getRowBytes() {
-        return nativeRowBytes(mNativeBitmap);
+        return nativeRowBytes(mSkBitmapPtr);
     }
 
     /**
@@ -1206,7 +1201,7 @@
      * that config, otherwise return null.
      */
     public final Config getConfig() {
-        return Config.nativeToConfig(nativeConfig(mNativeBitmap));
+        return Config.nativeToConfig(nativeConfig(mSkBitmapPtr));
     }
 
     /** Returns true if the bitmap's config supports per-pixel alpha, and
@@ -1218,7 +1213,7 @@
      * it will return true by default.
      */
     public final boolean hasAlpha() {
-        return nativeHasAlpha(mNativeBitmap);
+        return nativeHasAlpha(mSkBitmapPtr);
     }
 
     /**
@@ -1232,28 +1227,28 @@
      * non-opaque per-pixel alpha values.
      */
     public void setHasAlpha(boolean hasAlpha) {
-        nativeSetHasAlpha(mNativeBitmap, hasAlpha, mRequestPremultiplied);
+        nativeSetHasAlpha(mSkBitmapPtr, hasAlpha, mRequestPremultiplied);
     }
 
     /**
      * Indicates whether the renderer responsible for drawing this
      * bitmap should attempt to use mipmaps when this bitmap is drawn
      * scaled down.
-     * 
+     *
      * If you know that you are going to draw this bitmap at less than
      * 50% of its original size, you may be able to obtain a higher
      * quality
-     * 
+     *
      * This property is only a suggestion that can be ignored by the
      * renderer. It is not guaranteed to have any effect.
-     * 
+     *
      * @return true if the renderer should attempt to use mipmaps,
      *         false otherwise
-     * 
+     *
      * @see #setHasMipMap(boolean)
      */
     public final boolean hasMipMap() {
-        return nativeHasMipMap(mNativeBitmap);
+        return nativeHasMipMap(mSkBitmapPtr);
     }
 
     /**
@@ -1264,7 +1259,7 @@
      * If you know that you are going to draw this bitmap at less than
      * 50% of its original size, you may be able to obtain a higher
      * quality by turning this property on.
-     * 
+     *
      * Note that if the renderer respects this hint it might have to
      * allocate extra memory to hold the mipmap levels for this bitmap.
      *
@@ -1277,7 +1272,7 @@
      * @see #hasMipMap()
      */
     public final void setHasMipMap(boolean hasMipMap) {
-        nativeSetHasMipMap(mNativeBitmap, hasMipMap);
+        nativeSetHasMipMap(mSkBitmapPtr, hasMipMap);
     }
 
     /**
@@ -1285,12 +1280,12 @@
      *
      * @throws IllegalStateException if the bitmap is not mutable.
      */
-    public void eraseColor(int c) {
+    public void eraseColor(@ColorInt int c) {
         checkRecycled("Can't erase a recycled bitmap");
         if (!isMutable()) {
             throw new IllegalStateException("cannot erase immutable bitmaps");
         }
-        nativeErase(mNativeBitmap, c);
+        nativeErase(mSkBitmapPtr, c);
     }
 
     /**
@@ -1303,10 +1298,11 @@
      * @return     The argb {@link Color} at the specified coordinate
      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
      */
+    @ColorInt
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
         checkPixelAccess(x, y);
-        return nativeGetPixel(mNativeBitmap, x, y);
+        return nativeGetPixel(mSkBitmapPtr, x, y);
     }
 
     /**
@@ -1332,21 +1328,21 @@
      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
      *         to receive the specified number of pixels.
      */
-    public void getPixels(int[] pixels, int offset, int stride,
+    public void getPixels(@ColorInt int[] pixels, int offset, int stride,
                           int x, int y, int width, int height) {
         checkRecycled("Can't call getPixels() on a recycled bitmap");
         if (width == 0 || height == 0) {
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeGetPixels(mNativeBitmap, pixels, offset, stride,
+        nativeGetPixels(mSkBitmapPtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
     /**
      * Shared code to check for illegal arguments passed to getPixel()
      * or setPixel()
-     * 
+     *
      * @param x x coordinate of the pixel
      * @param y y coordinate of the pixel
      */
@@ -1414,13 +1410,13 @@
      * @throws IllegalArgumentException if x, y are outside of the bitmap's
      *         bounds.
      */
-    public void setPixel(int x, int y, int color) {
+    public void setPixel(int x, int y, @ColorInt int color) {
         checkRecycled("Can't call setPixel() on a recycled bitmap");
         if (!isMutable()) {
             throw new IllegalStateException();
         }
         checkPixelAccess(x, y);
-        nativeSetPixel(mNativeBitmap, x, y, color);
+        nativeSetPixel(mSkBitmapPtr, x, y, color);
     }
 
     /**
@@ -1446,7 +1442,7 @@
      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
      *         to receive the specified number of pixels.
      */
-    public void setPixels(int[] pixels, int offset, int stride,
+    public void setPixels(@ColorInt int[] pixels, int offset, int stride,
             int x, int y, int width, int height) {
         checkRecycled("Can't call setPixels() on a recycled bitmap");
         if (!isMutable()) {
@@ -1456,7 +1452,7 @@
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeSetPixels(mNativeBitmap, pixels, offset, stride,
+        nativeSetPixels(mSkBitmapPtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
@@ -1494,7 +1490,7 @@
      */
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
-        if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
+        if (!nativeWriteToParcel(mSkBitmapPtr, mIsMutable, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
     }
@@ -1506,6 +1502,7 @@
      *
      * @return new bitmap containing the alpha channel of the original bitmap.
      */
+    @CheckResult
     public Bitmap extractAlpha() {
         return extractAlpha(null, null);
     }
@@ -1522,9 +1519,9 @@
      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
      * drawing the original would result in the blur visually aligning with
      * the original.
-     * 
+     *
      * <p>The initial density of the returned bitmap is the same as the original's.
-     * 
+     *
      * @param paint Optional paint used to modify the alpha values in the
      *              resulting bitmap. Pass null for default behavior.
      * @param offsetXY Optional array that returns the X (index 0) and Y
@@ -1535,10 +1532,11 @@
      *         Canvas.drawBitmap(), where the color(s) will be taken from the
      *         paint that is passed to the draw call.
      */
+    @CheckResult
     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
         checkRecycled("Can't extractAlpha on a recycled bitmap");
-        long nativePaint = paint != null ? paint.mNativePaint : 0;
-        Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
+        long nativePaint = paint != null ? paint.getNativeInstance() : 0;
+        Bitmap bm = nativeExtractAlpha(mSkBitmapPtr, nativePaint, offsetXY);
         if (bm == null) {
             throw new RuntimeException("Failed to extractAlpha on Bitmap");
         }
@@ -1552,7 +1550,7 @@
      *  If other is null, return false.
      */
     public boolean sameAs(Bitmap other) {
-        return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
+        return this == other || (other != null && nativeSameAs(mSkBitmapPtr, other.mSkBitmapPtr));
     }
 
     /**
@@ -1567,7 +1565,12 @@
      * and therefore is harmless.
      */
     public void prepareToDraw() {
-        nativePrepareToDraw(mNativeBitmap);
+        nativePrepareToDraw(mSkBitmapPtr);
+    }
+
+    /** @hide */
+    public final long getSkBitmap() {
+        return mSkBitmapPtr;
     }
 
     private static class BitmapFinalizer {
@@ -1658,8 +1661,4 @@
     private static native boolean nativeHasMipMap(long nativeBitmap);
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
-
-    /* package */ final long ni() {
-        return mNativeBitmap;
-    }
 }
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 5e004a3..f2f890e 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,7 +42,7 @@
         mBitmap = bitmap;
         mTileX = tileX;
         mTileY = tileY;
-        final long b = bitmap.ni();
+        final long b = bitmap.getSkBitmap();
         init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index b0580d5..150f195 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,9 +16,11 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -44,8 +46,12 @@
  */
 public class Canvas {
 
-    // assigned in constructors or setBitmap, freed in finalizer
-    private long mNativeCanvasWrapper;
+    /**
+     * Should only be assigned in constructors (or setBitmap if software canvas),
+     * freed in finalizer.
+     * @hide
+     */
+    protected long mNativeCanvasWrapper;
 
     /** @hide */
     public long getNativeCanvasWrapper() {
@@ -150,7 +156,7 @@
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
         throwIfCannotDraw(bitmap);
-        mNativeCanvasWrapper = initRaster(bitmap.ni());
+        mNativeCanvasWrapper = initRaster(bitmap.getSkBitmap());
         mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
@@ -215,7 +221,7 @@
             }
             throwIfCannotDraw(bitmap);
 
-            native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true);
+            native_setBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), true);
             mDensity = bitmap.mDensity;
         }
 
@@ -475,7 +481,7 @@
     public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint,
             @Saveflags int saveFlags) {
         return native_saveLayer(mNativeCanvasWrapper, left, top, right, bottom,
-                paint != null ? paint.mNativePaint : 0,
+                paint != null ? paint.getNativeInstance() : 0,
                 saveFlags);
     }
 
@@ -1008,7 +1014,7 @@
      *
      * @param color the color to draw onto the canvas
      */
-    public void drawColor(int color) {
+    public void drawColor(@ColorInt int color) {
         native_drawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
     }
 
@@ -1019,7 +1025,7 @@
      * @param color the color to draw with
      * @param mode  the porter-duff mode to apply to the color
      */
-    public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
+    public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
         native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt);
     }
 
@@ -1031,7 +1037,7 @@
      * @param paint The paint used to draw onto the canvas
      */
     public void drawPaint(@NonNull Paint paint) {
-        native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint);
+        native_drawPaint(mNativeCanvasWrapper, paint.getNativeInstance());
     }
 
     /**
@@ -1050,14 +1056,15 @@
      *                 "points" that are drawn is really (count >> 1).
      * @param paint    The paint used to draw the points
      */
-    public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) {
-        native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
+    public void drawPoints(@Size(multiple=2) float[] pts, int offset, int count,
+            @NonNull Paint paint) {
+        native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     /**
      * Helper for drawPoints() that assumes you want to draw the entire array
      */
-    public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) {
+    public void drawPoints(@Size(multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
         drawPoints(pts, 0, pts.length, paint);
     }
 
@@ -1065,7 +1072,7 @@
      * Helper for drawPoints() for drawing a single point.
      */
     public void drawPoint(float x, float y, @NonNull Paint paint) {
-        native_drawPoint(mNativeCanvasWrapper, x, y, paint.mNativePaint);
+        native_drawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
     }
 
     /**
@@ -1082,7 +1089,7 @@
      */
     public void drawLine(float startX, float startY, float stopX, float stopY,
             @NonNull Paint paint) {
-        native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.mNativePaint);
+        native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
     }
 
     /**
@@ -1100,11 +1107,11 @@
      *                 (count >> 2).
      * @param paint    The paint used to draw the points
      */
-    public void drawLines(float[] pts, int offset, int count, Paint paint) {
-        native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
+    public void drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint) {
+        native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
-    public void drawLines(@NonNull float[] pts, @NonNull Paint paint) {
+    public void drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
         drawLines(pts, 0, pts.length, paint);
     }
 
@@ -1117,7 +1124,7 @@
      */
     public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
         native_drawRect(mNativeCanvasWrapper,
-                rect.left, rect.top, rect.right, rect.bottom, paint.mNativePaint);
+                rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
     }
 
     /**
@@ -1143,7 +1150,7 @@
      * @param paint  The paint used to draw the rect
      */
     public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
-        native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
+        native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
     /**
@@ -1164,7 +1171,7 @@
      * 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);
+        native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
     /**
@@ -1178,7 +1185,7 @@
      * @param paint  The paint used to draw the circle
      */
     public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
-        native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.mNativePaint);
+        native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
     }
 
     /**
@@ -1234,7 +1241,7 @@
     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);
+                useCenter, paint.getNativeInstance());
     }
 
     /**
@@ -1260,7 +1267,7 @@
      */
     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
             @NonNull Paint paint) {
-        native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.mNativePaint);
+        native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.getNativeInstance());
     }
 
     /**
@@ -1271,7 +1278,7 @@
      * @param paint The paint used to draw the path
      */
     public void drawPath(@NonNull Path path, @NonNull Paint paint) {
-        native_drawPath(mNativeCanvasWrapper, path.ni(), paint.mNativePaint);
+        native_drawPath(mNativeCanvasWrapper, path.ni(), paint.getNativeInstance());
     }
 
     /**
@@ -1335,8 +1342,8 @@
      */
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
-        native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top,
-                paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top,
+                paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
     }
 
     /**
@@ -1367,7 +1374,7 @@
           throw new NullPointerException();
       }
       throwIfCannotDraw(bitmap);
-      final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+      final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
       float left, top, right, bottom;
       if (src == null) {
@@ -1381,7 +1388,7 @@
           bottom = src.bottom;
       }
 
-      native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+      native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
               dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
               bitmap.mDensity);
   }
@@ -1414,7 +1421,7 @@
             throw new NullPointerException();
         }
         throwIfCannotDraw(bitmap);
-        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
         int left, top, right, bottom;
         if (src == null) {
@@ -1428,7 +1435,7 @@
             bottom = src.bottom;
         }
 
-        native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top, right, bottom,
+        native_drawBitmap(mNativeCanvasWrapper, bitmap.getSkBitmap(), left, top, right, bottom,
             dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
             bitmap.mDensity);
     }
@@ -1482,7 +1489,7 @@
         }
         // punch down to native for the actual draw
         native_drawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha,
-                paint != null ? paint.mNativePaint : 0);
+                paint != null ? paint.getNativeInstance() : 0);
     }
 
     /**
@@ -1509,8 +1516,8 @@
      * @param paint  May be null. The paint used to draw the bitmap
      */
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
-        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(),
-                paint != null ? paint.mNativePaint : 0);
+        nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getSkBitmap(), matrix.ni(),
+                paint != null ? paint.getNativeInstance() : 0);
     }
 
     /**
@@ -1564,9 +1571,9 @@
             // no mul by 2, since we need only 1 color per vertex
             checkRange(colors.length, colorOffset, count);
         }
-        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight,
+        nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getSkBitmap(), meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset,
-                paint != null ? paint.mNativePaint : 0);
+                paint != null ? paint.getNativeInstance() : 0);
     }
 
     public enum VertexMode {
@@ -1619,6 +1626,9 @@
             int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
             @NonNull Paint paint) {
         checkRange(verts.length, vertOffset, vertexCount);
+        if (isHardwareAccelerated()) {
+            return;
+        }
         if (texs != null) {
             checkRange(texs.length, texOffset, vertexCount);
         }
@@ -1630,7 +1640,7 @@
         }
         nativeDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
                 vertOffset, texs, texOffset, colors, colorOffset,
-                indices, indexOffset, indexCount, paint.mNativePaint);
+                indices, indexOffset, indexCount, paint.getNativeInstance());
     }
 
     /**
@@ -1639,7 +1649,7 @@
      *
      * @param text  The text to be drawn
      * @param x     The x-coordinate of the origin of the text being drawn
-     * @param y     The y-coordinate of the origin of the text being drawn
+     * @param y     The y-coordinate of the baseline of the text being drawn
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(@NonNull char[] text, int index, int count, float x, float y,
@@ -1649,7 +1659,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint, paint.mNativeTypeface);
+                paint.getNativeInstance(), paint.mNativeTypeface);
     }
 
     /**
@@ -1658,12 +1668,12 @@
      *
      * @param text  The text to be drawn
      * @param x     The x-coordinate of the origin of the text being drawn
-     * @param y     The y-coordinate of the origin of the text being drawn
+     * @param y     The y-coordinate of the baseline of the text being drawn
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
         native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
-                paint.mNativePaint, paint.mNativeTypeface);
+                paint.getNativeInstance(), paint.mNativeTypeface);
     }
 
     /**
@@ -1674,7 +1684,7 @@
      * @param start The index of the first character in text to draw
      * @param end   (end - 1) is the index of the last character in text to draw
      * @param x     The x-coordinate of the origin of the text being drawn
-     * @param y     The y-coordinate of the origin of the text being drawn
+     * @param y     The y-coordinate of the baseline of the text being drawn
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(@NonNull String text, int start, int end, float x, float y,
@@ -1683,7 +1693,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
-                paint.mNativePaint, paint.mNativeTypeface);
+                paint.getNativeInstance(), paint.mNativeTypeface);
     }
 
     /**
@@ -1707,7 +1717,7 @@
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
             native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
-                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+                    paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
                     paint);
@@ -1715,7 +1725,7 @@
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
             native_drawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
-                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+                    paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1754,7 +1764,7 @@
         }
 
         native_drawTextRun(mNativeCanvasWrapper, text, index, count,
-                contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
+                contextIndex, contextCount, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
     }
 
     /**
@@ -1790,7 +1800,7 @@
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
+                    contextStart, contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
                     contextStart, contextEnd, x, y, isRtl, paint);
@@ -1800,7 +1810,7 @@
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
-                    0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
+                    0, contextLen, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1821,7 +1831,8 @@
      * @param paint    The paint used for the text (e.g. color, size, style)
      */
     @Deprecated
-    public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos,
+    public void drawPosText(@NonNull char[] text, int index, int count,
+            @NonNull @Size(multiple=2) float[] pos,
             @NonNull Paint paint) {
         if (index < 0 || index + count > text.length || count*2 > pos.length) {
             throw new IndexOutOfBoundsException();
@@ -1844,7 +1855,8 @@
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     @Deprecated
-    public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) {
+    public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
+            @NonNull Paint paint) {
         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
     }
 
@@ -1868,7 +1880,7 @@
         }
         native_drawTextOnPath(mNativeCanvasWrapper, text, index, count,
                 path.ni(), hOffset, vOffset,
-                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+                paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
     }
 
     /**
@@ -1888,7 +1900,7 @@
             float vOffset, @NonNull Paint paint) {
         if (text.length() > 0) {
             native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+                    paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
         }
     }
 
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
index be86060..ea3886c 100644
--- a/graphics/java/android/graphics/CanvasProperty.java
+++ b/graphics/java/android/graphics/CanvasProperty.java
@@ -31,7 +31,7 @@
     }
 
     public static CanvasProperty<Paint> createPaint(Paint initialValue) {
-        return new CanvasProperty<Paint>(nCreatePaint(initialValue.mNativePaint));
+        return new CanvasProperty<Paint>(nCreatePaint(initialValue.getNativeInstance()));
     }
 
     private CanvasProperty(long nativeContainer) {
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 8fbedae..666dbd8 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
+import android.annotation.Size;
 import android.util.MathUtils;
 import com.android.internal.util.XmlUtils;
 
@@ -35,23 +37,24 @@
  * 0xFFFFFFFF
  */
 public class Color {
-    public static final int BLACK       = 0xFF000000;
-    public static final int DKGRAY      = 0xFF444444;
-    public static final int GRAY        = 0xFF888888;
-    public static final int LTGRAY      = 0xFFCCCCCC;
-    public static final int WHITE       = 0xFFFFFFFF;
-    public static final int RED         = 0xFFFF0000;
-    public static final int GREEN       = 0xFF00FF00;
-    public static final int BLUE        = 0xFF0000FF;
-    public static final int YELLOW      = 0xFFFFFF00;
-    public static final int CYAN        = 0xFF00FFFF;
-    public static final int MAGENTA     = 0xFFFF00FF;
-    public static final int TRANSPARENT = 0;
+    @ColorInt public static final int BLACK       = 0xFF000000;
+    @ColorInt public static final int DKGRAY      = 0xFF444444;
+    @ColorInt public static final int GRAY        = 0xFF888888;
+    @ColorInt public static final int LTGRAY      = 0xFFCCCCCC;
+    @ColorInt public static final int WHITE       = 0xFFFFFFFF;
+    @ColorInt public static final int RED         = 0xFFFF0000;
+    @ColorInt public static final int GREEN       = 0xFF00FF00;
+    @ColorInt public static final int BLUE        = 0xFF0000FF;
+    @ColorInt public static final int YELLOW      = 0xFFFFFF00;
+    @ColorInt public static final int CYAN        = 0xFF00FFFF;
+    @ColorInt public static final int MAGENTA     = 0xFFFF00FF;
+    @ColorInt public static final int TRANSPARENT = 0;
 
     /**
      * Return the alpha component of a color int. This is the same as saying
      * color >>> 24
      */
+    @ColorInt
     public static int alpha(int color) {
         return color >>> 24;
     }
@@ -60,6 +63,7 @@
      * Return the red component of a color int. This is the same as saying
      * (color >> 16) & 0xFF
      */
+    @ColorInt
     public static int red(int color) {
         return (color >> 16) & 0xFF;
     }
@@ -68,6 +72,7 @@
      * Return the green component of a color int. This is the same as saying
      * (color >> 8) & 0xFF
      */
+    @ColorInt
     public static int green(int color) {
         return (color >> 8) & 0xFF;
     }
@@ -76,6 +81,7 @@
      * Return the blue component of a color int. This is the same as saying
      * color & 0xFF
      */
+    @ColorInt
     public static int blue(int color) {
         return color & 0xFF;
     }
@@ -90,6 +96,7 @@
      * @param green Green component [0..255] of the color
      * @param blue  Blue component [0..255] of the color
      */
+    @ColorInt
     public static int rgb(int red, int green, int blue) {
         return (0xFF << 24) | (red << 16) | (green << 8) | blue;
     }
@@ -104,6 +111,7 @@
      * @param green Green component [0..255] of the color
      * @param blue  Blue component [0..255] of the color
      */
+    @ColorInt
     public static int argb(int alpha, int red, int green, int blue) {
         return (alpha << 24) | (red << 16) | (green << 8) | blue;
     }
@@ -115,7 +123,7 @@
      * 
      * @hide Pending API council
      */
-    public static float hue(int color) {
+    public static float hue(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -157,7 +165,7 @@
      * 
      * @hide Pending API council
      */
-    public static float saturation(int color) {
+    public static float saturation(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -184,7 +192,7 @@
      *
      * @hide Pending API council
      */
-    public static float brightness(int color) {
+    public static float brightness(@ColorInt int color) {
         int r = (color >> 16) & 0xFF;
         int g = (color >> 8) & 0xFF;
         int b = color & 0xFF;
@@ -200,12 +208,14 @@
      * exception. Supported formats are:
      * #RRGGBB
      * #AARRGGBB
+     * or one of the following names:
      * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
      * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey',
-     * 'aqua', 'fuschia', 'lime', 'maroon', 'navy', 'olive', 'purple',
-     * 'silver', 'teal'
+     * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
+     * 'silver', 'teal'.
      */
-    public static int parseColor(String colorString) {
+    @ColorInt
+    public static int parseColor(@Size(min=1) String colorString) {
         if (colorString.charAt(0) == '#') {
             // Use a long to avoid rollovers on #ffXXXXXX
             long color = Long.parseLong(colorString.substring(1), 16);
@@ -236,7 +246,8 @@
      * 
      * @hide Pending API council
      */
-    public static int HSBtoColor(float[] hsb) {
+    @ColorInt
+    public static int HSBtoColor(@Size(3) float[] hsb) {
         return HSBtoColor(hsb[0], hsb[1], hsb[2]);
     }
     
@@ -253,6 +264,7 @@
      * 
      * @hide Pending API council
      */
+    @ColorInt
     public static int HSBtoColor(float h, float s, float b) {
         h = MathUtils.constrain(h, 0.0f, 1.0f);
         s = MathUtils.constrain(s, 0.0f, 1.0f);
@@ -316,7 +328,7 @@
      * @param blue  blue component value [0..255]
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void RGBToHSV(int red, int green, int blue, float hsv[]) {
+    public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -331,7 +343,7 @@
      * @param color the argb color to convert. The alpha component is ignored.
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void colorToHSV(int color, float hsv[]) {
+    public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[]) {
         RGBToHSV((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, hsv);
     }
 
@@ -344,7 +356,7 @@
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
-    public static int HSVToColor(float hsv[]) {
+    public static int HSVToColor(@Size(3) float hsv[]) {
         return HSVToColor(0xFF, hsv);
     }
 
@@ -359,7 +371,7 @@
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
-    public static int HSVToColor(int alpha, float hsv[]) {
+    public static int HSVToColor(int alpha, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -378,6 +390,7 @@
      *
      * @hide
      */
+    @ColorInt
     public static int getHtmlColor(String color) {
         Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
         if (i != null) {
diff --git a/graphics/java/android/graphics/ColorMatrix.java b/graphics/java/android/graphics/ColorMatrix.java
index 64f0c05..1b1849e 100644
--- a/graphics/java/android/graphics/ColorMatrix.java
+++ b/graphics/java/android/graphics/ColorMatrix.java
@@ -16,8 +16,6 @@
 
 package android.graphics;
 
-import android.util.FloatMath;
-
 import java.util.Arrays;
 
 /**
@@ -145,9 +143,9 @@
      */
     public void setRotate(int axis, float degrees) {
         reset();
-        float radians = degrees * (float)Math.PI / 180;
-        float cosine = FloatMath.cos(radians);
-        float sine = FloatMath.sin(radians);
+        double radians = degrees * Math.PI / 180d;
+        float cosine = (float) Math.cos(radians);
+        float sine = (float) Math.sin(radians);
         switch (axis) {
         // Rotation around the red color
         case 0:
diff --git a/graphics/java/android/graphics/DrawFilter.java b/graphics/java/android/graphics/DrawFilter.java
index ed38f37..aaefce9 100644
--- a/graphics/java/android/graphics/DrawFilter.java
+++ b/graphics/java/android/graphics/DrawFilter.java
@@ -24,8 +24,11 @@
  */
 public class DrawFilter {
 
-    // this is set by subclasses, but don't make it public
-    /* package */ long mNativeInt;    // pointer to native object
+    /**
+     * this is set by subclasses
+     * @hide
+     */
+    public long mNativeInt;
 
     protected void finalize() throws Throwable {
         try {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 3efb9c0..49c4247 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -356,6 +356,38 @@
     public static final int RAW10 = 0x25;
 
     /**
+     * Android dense depth image format.
+     *
+     * Each pixel is 16 bits, representing a depth ranging measurement from
+     * a depth camera or similar sensor.
+     *
+     * <p>This format assumes
+     * <ul>
+     * <li>an even width</li>
+     * <li>an even height</li>
+     * <li>a horizontal stride multiple of 16 pixels</li>
+     * </ul>
+     * </p>
+     *
+     * <pre> y_size = stride * height </pre>
+     *
+     * When produced by a camera, the units are millimeters.
+     */
+    public static final int DEPTH16 = 0x44363159;
+
+    /**
+     * Android sparse depth point cloud format.
+     *
+     * <p>A variable-length list of 3D points, with each point represented
+     * by a triple of floats.</p>
+     *
+     * <p>The number of points is {@code (size of the buffer in bytes) / 12}.
+     *
+     * The coordinate system and units depend on the source of the point cloud data.
+     */
+    public static final int DEPTH_POINT_CLOUD = 0x101;
+
+    /**
      * Use this function to retrieve the number of bits per pixel of an
      * ImageFormat.
      *
@@ -376,6 +408,7 @@
             case Y8:
                 return 8;
             case Y16:
+            case DEPTH16:
                 return 16;
             case NV21:
                 return 12;
@@ -412,6 +445,8 @@
             case YUV_420_888:
             case RAW_SENSOR:
             case RAW10:
+            case DEPTH16:
+            case DEPTH_POINT_CLOUD:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java
index e7a24a4..b692ecf 100644
--- a/graphics/java/android/graphics/LayerRasterizer.java
+++ b/graphics/java/android/graphics/LayerRasterizer.java
@@ -28,11 +28,11 @@
         object itself, so it may be reused without danger of side-effects.
     */
     public void addLayer(Paint paint, float dx, float dy) {
-        nativeAddLayer(native_instance, paint.mNativePaint, dx, dy);
+        nativeAddLayer(native_instance, paint.getNativeInstance(), dx, dy);
     }
 
     public void addLayer(Paint paint) {
-        nativeAddLayer(native_instance, paint.mNativePaint, 0, 0);
+        nativeAddLayer(native_instance, paint.getNativeInstance(), 0, 0);
     }
 
     private static native long nativeConstructor();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index b0a4553..ecb4255 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -35,12 +35,17 @@
     public native boolean isOpaque();
     public native int duration();
 
-    public native boolean setTime(int relativeMilliseconds);    
+    public native boolean setTime(int relativeMilliseconds);
 
-    public native void draw(Canvas canvas, float x, float y, Paint paint);
-    
+    private native void nDraw(long nativeCanvas, float x, float y, long paintHandle);
+
+    public void draw(Canvas canvas, float x, float y, Paint paint) {
+        nDraw(canvas.getNativeCanvasWrapper(), x, y,
+                paint != null ? paint.getNativeInstance() : 0);
+    }
+
     public void draw(Canvas canvas, float x, float y) {
-        draw(canvas, x, y, null);
+        nDraw(canvas.getNativeCanvasWrapper(), x, y, 0);
     }
 
     public static Movie decodeStream(InputStream is) {
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 6f42046..9c4299a 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -98,7 +98,7 @@
     public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
         mBitmap = bitmap;
         mSrcName = srcName;
-        mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
+        mNativeChunk = validateNinePatchChunk(mBitmap.getSkBitmap(), chunk);
     }
 
     /**
@@ -199,13 +199,13 @@
     }
 
     void drawSoftware(Canvas canvas, RectF location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
-                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
+                paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     void drawSoftware(Canvas canvas, Rect location, Paint paint) {
-        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
-                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
+        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.getSkBitmap(), mNativeChunk,
+                paint != null ? paint.getNativeInstance() : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     /**
@@ -252,7 +252,7 @@
      * that are transparent.
      */
     public final Region getTransparentRegion(Rect bounds) {
-        long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
+        long r = nativeGetTransparentRegion(mBitmap.getSkBitmap(), mNativeChunk, bounds);
         return r != 0 ? new Region(r) : null;
     }
 
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index f76184f..aa40408 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.graphics.drawable.Drawable;
 
@@ -101,7 +102,7 @@
      * assumed by the drawing system to fully cover content beneath it,
      * meaning content beneath may be optimized away.
      */
-    public void setAlpha(float alpha) {
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         mAlpha = alpha;
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 652fe64..1da198c 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.ColorInt;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -29,10 +30,9 @@
  */
 public class Paint {
 
-    /**
-     * @hide
-     */
-    public long mNativePaint;
+    private long mNativePaint;
+    private long mNativeShader = 0;
+
     /**
      * @hide
      */
@@ -445,7 +445,7 @@
      *              new paint.
      */
     public Paint(Paint paint) {
-        mNativePaint = native_initWithPaint(paint.mNativePaint);
+        mNativePaint = native_initWithPaint(paint.getNativeInstance());
         setClassVariablesFrom(paint);
     }
 
@@ -464,6 +464,7 @@
         mPathEffect = null;
         mRasterizer = null;
         mShader = null;
+        mNativeShader = 0;
         mTypeface = null;
         mNativeTypeface = 0;
         mXfermode = null;
@@ -500,11 +501,8 @@
         mMaskFilter = paint.mMaskFilter;
         mPathEffect = paint.mPathEffect;
         mRasterizer = paint.mRasterizer;
-        if (paint.mShader != null) {
-            mShader = paint.mShader.copy();
-        } else {
-            mShader = null;
-        }
+        mShader = paint.mShader;
+        mNativeShader = paint.mNativeShader;
         mTypeface = paint.mTypeface;
         mNativeTypeface = paint.mNativeTypeface;
         mXfermode = paint.mXfermode;
@@ -531,6 +529,21 @@
     }
 
     /**
+     * Return the pointer to the native object while ensuring that any
+     * mutable objects that are attached to the paint are also up-to-date.
+     *
+     * @hide
+     */
+    public long getNativeInstance() {
+        long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
+        if (newNativeShader != mNativeShader) {
+            mNativeShader = newNativeShader;
+            native_setShader(mNativePaint, mNativeShader);
+        }
+        return mNativePaint;
+    }
+
+    /**
      * Return the bidi flags on the paint.
      *
      * @return the bidi flags on the paint
@@ -765,6 +778,7 @@
      *
      * @return the paint's color (and alpha).
      */
+    @ColorInt
     public native int getColor();
 
     /**
@@ -775,7 +789,7 @@
      *
      * @param color The new color (including alpha) to set in the paint.
      */
-    public native void setColor(int color);
+    public native void setColor(@ColorInt int color);
 
     /**
      * Helper to getColor() that just returns the color's alpha value. This is
@@ -920,10 +934,7 @@
      * @return       shader
      */
     public Shader setShader(Shader shader) {
-        long shaderNative = 0;
-        if (shader != null)
-            shaderNative = shader.getNativeInstance();
-        native_setShader(mNativePaint, shaderNative);
+        // Defer setting the shader natively until getNativeInstance() is called
         mShader = shader;
         return shader;
     }
@@ -1320,6 +1331,29 @@
     }
 
     /**
+     * Get the current value of hyphen edit.
+     *
+     * @return the current hyphen edit value
+     *
+     * @hide
+     */
+    public int getHyphenEdit() {
+        return native_getHyphenEdit(mNativePaint);
+    }
+
+    /**
+     * Set a hyphen edit on the paint (causes a hyphen to be added to text when
+     * measured or drawn).
+     *
+     * @param hyphen 0 for no edit, 1 for adding a hyphen (other values in future)
+     *
+     * @hide
+     */
+    public void setHyphenEdit(int hyphen) {
+        native_setHyphenEdit(mNativePaint, hyphen);
+    }
+
+    /**
      * Return the distance above (negative) the baseline (ascent) based on the
      * current typeface and text size.
      *
@@ -2298,4 +2332,6 @@
                                                        float letterSpacing);
     private static native void native_setFontFeatureSettings(long native_object,
                                                              String settings);
+    private static native int native_getHyphenEdit(long native_object);
+    private static native void native_setHyphenEdit(long native_object, int hyphen);
 }
diff --git a/graphics/java/android/graphics/PaintFlagsDrawFilter.java b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
index 65a6218..2326611 100644
--- a/graphics/java/android/graphics/PaintFlagsDrawFilter.java
+++ b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
@@ -17,11 +17,6 @@
 package android.graphics;
 
 public class PaintFlagsDrawFilter extends DrawFilter {
-    /** @hide **/
-    public final int clearBits;
-    /** @hide **/
-    public final int setBits;
-
     /**
      * Subclass of DrawFilter that affects every paint by first clearing
      * the specified clearBits in the paint's flags, and then setting the
@@ -31,8 +26,6 @@
      * @param setBits These bits will be set in the paint's flags
      */
     public PaintFlagsDrawFilter(int clearBits, int setBits) {
-        this.clearBits = clearBits;
-        this.setBits = setBits;
         // our native constructor can return 0, if the specified bits
         // are effectively a no-op
         mNativeInt = nativeConstructor(clearBits, setBits);
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index fa9af2a..39272b9 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -122,11 +122,6 @@
      * @param canvas  The picture is drawn to this canvas
      */
     public void draw(Canvas canvas) {
-        if (canvas.isHardwareAccelerated()) {
-            throw new IllegalArgumentException(
-                    "Picture playback is only supported on software canvas.");
-        }
-
         if (mRecordingCanvas != null) {
             endRecording();
         }
diff --git a/graphics/java/android/graphics/PointF.java b/graphics/java/android/graphics/PointF.java
index ee38dbb..8e4288e 100644
--- a/graphics/java/android/graphics/PointF.java
+++ b/graphics/java/android/graphics/PointF.java
@@ -18,7 +18,6 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.FloatMath;
 
 
 /**
@@ -109,7 +108,7 @@
      * Returns the euclidian distance from (0,0) to (x,y)
      */
     public static float length(float x, float y) {
-        return FloatMath.sqrt(x * x + y * y);
+        return (float) Math.hypot(x, y);
     }
 
     /**
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index 2ef1662..dcccf35 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -18,7 +18,7 @@
 
 public class PorterDuff {
 
-    // these value must match their native equivalents. See SkPorterDuff.h
+    // these value must match their native equivalents. See SkXfermode.h
     public enum Mode {
         /** [0, 0] */
         CLEAR       (0),
@@ -46,17 +46,17 @@
         XOR         (11),
         /** [Sa + Da - Sa*Da,
              Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
-        DARKEN      (12),
+        DARKEN      (16),
         /** [Sa + Da - Sa*Da,
              Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
-        LIGHTEN     (13),
+        LIGHTEN     (17),
         /** [Sa * Da, Sc * Dc] */
-        MULTIPLY    (14),
+        MULTIPLY    (13),
         /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
-        SCREEN      (15),
+        SCREEN      (14),
         /** Saturate(S + D) */
-        ADD         (16),
-        OVERLAY     (17);
+        ADD         (12),
+        OVERLAY     (15);
 
         Mode(int nativeInt) {
             this.nativeInt = nativeInt;
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index fe4f8b8..bddd224 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
+
 /**
  * A color filter that can be used to tint the source pixels using a single
  * color and a specific {@link PorterDuff Porter-Duff composite mode}.
@@ -34,7 +36,7 @@
      * @see #setColor(int)
      * @see #setMode(android.graphics.PorterDuff.Mode)
      */
-    public PorterDuffColorFilter(int color, PorterDuff.Mode mode) {
+    public PorterDuffColorFilter(int color, @NonNull PorterDuff.Mode mode) {
         mColor = color;
         mMode = mode;
         update();
@@ -93,7 +95,7 @@
      *
      * @hide
      */
-    public void setMode(PorterDuff.Mode mode) {
+    public void setMode(@NonNull PorterDuff.Mode mode) {
         mMode = mode;
         update();
     }
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 53178b0..f5cedfa 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -20,7 +20,6 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.FloatMath;
 import com.android.internal.util.FastMath;
 
 /**
@@ -450,8 +449,8 @@
      * floor of top and left, and the ceiling of right and bottom.
      */
     public void roundOut(Rect dst) {
-        dst.set((int) FloatMath.floor(left), (int) FloatMath.floor(top),
-                (int) FloatMath.ceil(right), (int) FloatMath.ceil(bottom));
+        dst.set((int) Math.floor(left), (int) Math.floor(top),
+                (int) Math.ceil(right), (int) Math.ceil(bottom));
     }
 
     /**
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 6934955..a96d2cb 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -82,7 +82,8 @@
      */
     public void setLocalMatrix(Matrix localM) {
         mLocalMatrix = localM;
-        nativeSetLocalMatrix(native_instance, localM == null ? 0 : localM.native_instance);
+        native_instance = nativeSetLocalMatrix(native_instance,
+                localM == null ? 0 : localM.native_instance);
     }
 
     protected void finalize() throws Throwable {
@@ -120,5 +121,5 @@
     }
 
     private static native void nativeDestructor(long native_shader);
-    private static native void nativeSetLocalMatrix(long native_shader, long matrix_instance);
+    private static native long nativeSetLocalMatrix(long native_shader, long matrix_instance);
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index d2799e1..24e0d6a 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -20,15 +20,11 @@
 import android.annotation.Nullable;
 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;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.util.Log;
 import android.os.SystemClock;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -41,58 +37,47 @@
 /**
  * @hide
  */
-public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
-        Animatable {
-    private static final String TAG = "AnimatedRotateDrawable";
-
+public class AnimatedRotateDrawable extends DrawableWrapper implements Animatable {
     private AnimatedRotateState mState;
-    private boolean mMutated;
+
     private float mCurrentDegrees;
     private float mIncrement;
+
+    /** Whether this drawable is currently animating. */
     private boolean mRunning;
 
+    /**
+     * Creates a new animated rotating drawable with no wrapped drawable.
+     */
     public AnimatedRotateDrawable() {
-        this(null, null);
-    }
-
-    private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) {
-        mState = new AnimatedRotateState(rotateState, this, res);
-        init();
-    }
-
-    private void init() {
-        final AnimatedRotateState state = mState;
-        mIncrement = 360.0f / state.mFramesCount;
-        final Drawable drawable = state.mDrawable;
-        if (drawable != null) {
-            drawable.setFilterBitmap(true);
-            if (drawable instanceof BitmapDrawable) {
-                ((BitmapDrawable) drawable).setAntiAlias(true);
-            }
-        }
+        this(new AnimatedRotateState(null), null);
     }
 
     @Override
     public void draw(Canvas canvas) {
-        int saveCount = canvas.save();
+        final Drawable drawable = getDrawable();
+        final Rect bounds = drawable.getBounds();
+        final int w = bounds.right - bounds.left;
+        final int h = bounds.bottom - bounds.top;
 
         final AnimatedRotateState st = mState;
-        final Drawable drawable = st.mDrawable;
-        final Rect bounds = drawable.getBounds();
+        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
-        int w = bounds.right - bounds.left;
-        int h = bounds.bottom - bounds.top;
-
-        float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
-        float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
-
+        final int saveCount = canvas.save();
         canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
-
         drawable.draw(canvas);
-
         canvas.restoreToCount(saveCount);
     }
 
+    /**
+     * Starts the rotation animation.
+     * <p>
+     * The animation will run until {@link #stop()} is called. Calling this
+     * method while the animation is already running has no effect.
+     *
+     * @see #stop()
+     */
     @Override
     public void start() {
         if (!mRunning) {
@@ -101,10 +86,15 @@
         }
     }
 
+    /**
+     * Stops the rotation animation.
+     *
+     * @see #start()
+     */
     @Override
     public void stop() {
         mRunning = false;
-        unscheduleSelf(this);
+        unscheduleSelf(mNextFrame);
     }
 
     @Override
@@ -113,154 +103,24 @@
     }
 
     private void nextFrame() {
-        unscheduleSelf(this);
-        scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
-    }
-
-    @Override
-    public void run() {
-        // TODO: This should be computed in draw(Canvas), based on the amount
-        // of time since the last frame drawn
-        mCurrentDegrees += mIncrement;
-        if (mCurrentDegrees > (360.0f - mIncrement)) {
-            mCurrentDegrees = 0.0f;
-        }
-        invalidateSelf();
-        nextFrame();
+        unscheduleSelf(mNextFrame);
+        scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + mState.mFrameDuration);
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        boolean changed = super.setVisible(visible, restart);
+        final boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (changed || restart) {
                 mCurrentDegrees = 0.0f;
                 nextFrame();
             }
         } else {
-            unscheduleSelf(this);
+            unscheduleSelf(mNextFrame);
         }
         return changed;
     }
 
-    /**
-     * Returns the drawable rotated by this RotateDrawable.
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
-    }
-
-    @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();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
     @Override
     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
@@ -268,50 +128,27 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
         updateStateFromTypedArray(a);
+        verifyRequiredAttributes(a);
         a.recycle();
 
-        inflateChildElements(r, parser, attrs, theme);
+        updateLocalState();
+    }
 
-        init();
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
     }
 
     @Override
-    public void applyTheme(@Nullable Theme t) {
-        super.applyTheme(t);
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
 
         final AnimatedRotateState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-
-        init();
-    }
-
-    private void updateStateFromTypedArray(TypedArray a) {
-        final AnimatedRotateState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
 
         if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
             final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
@@ -332,43 +169,35 @@
 
         final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
+    @Override
+    public void applyTheme(@Nullable Theme t) {
         final AnimatedRotateState state = mState;
+        if (state == null) {
+            return;
+        }
 
-        Drawable dr = null;
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
-                Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName());
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
             }
         }
 
-        if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
-        // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
+        updateLocalState();
     }
 
     public void setFramesCount(int framesCount) {
@@ -380,30 +209,7 @@
         mState.mFrameDuration = framesDuration;
     }
 
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class AnimatedRotateState extends Drawable.ConstantState {
-        Drawable mDrawable;
-        int[] mThemeAttrs;
-
-        int mChangingConfigurations;
-
+    static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {
         boolean mPivotXRel = false;
         float mPivotX = 0;
         boolean mPivotYRel = false;
@@ -411,60 +217,59 @@
         int mFrameDuration = 150;
         int mFramesCount = 12;
 
-        private boolean mCanConstantState;
-        private boolean mCheckedConstantState;
+        public AnimatedRotateState(AnimatedRotateState orig) {
+            super(orig);
 
-        public AnimatedRotateState(AnimatedRotateState orig, AnimatedRotateDrawable owner,
-                Resources res) {
             if (orig != null) {
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
-                mThemeAttrs = orig.mThemeAttrs;
                 mPivotXRel = orig.mPivotXRel;
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
                 mPivotY = orig.mPivotY;
                 mFramesCount = orig.mFramesCount;
                 mFrameDuration = orig.mFrameDuration;
-                mCanConstantState = mCheckedConstantState = true;
             }
         }
 
         @Override
-        public Drawable newDrawable() {
-            return new AnimatedRotateDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new AnimatedRotateDrawable(this, res);
         }
+    }
 
-        @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
+    private AnimatedRotateDrawable(AnimatedRotateState state, Resources res) {
+        super(state, res);
 
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
+        mState = state;
 
-        public boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
+        updateLocalState();
+    }
+
+    private void updateLocalState() {
+        final AnimatedRotateState state = mState;
+        mIncrement = 360.0f / state.mFramesCount;
+
+        // Force the wrapped drawable to use filtering and AA, if applicable,
+        // so that it looks smooth when rotated.
+        final Drawable drawable = getDrawable();
+        if (drawable != null) {
+            drawable.setFilterBitmap(true);
+            if (drawable instanceof BitmapDrawable) {
+                ((BitmapDrawable) drawable).setAntiAlias(true);
             }
-
-            return mCanConstantState;
         }
     }
+
+    private final Runnable mNextFrame = new Runnable() {
+        @Override
+        public void run() {
+            // TODO: This should be computed in draw(Canvas), based on the amount
+            // of time since the last frame drawn
+            mCurrentDegrees += mIncrement;
+            if (mCurrentDegrees > (360.0f - mIncrement)) {
+                mCurrentDegrees = 0.0f;
+            }
+            invalidateSelf();
+            nextFrame();
+        }
+    };
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 4af5946..2c603e2 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -594,7 +594,7 @@
                 mTransitions.append(keyToFrom, pos | REVERSED_BIT | reversibleBit);
             }
 
-            return addChild(anim);
+            return pos;
         }
 
         int addStateSet(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 2a17a60..17e5b0b 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -197,6 +197,11 @@
     }
 
     @Override
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        return mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection);
+    }
+
+    @Override
     public int getAlpha() {
         return mAnimatedVectorState.mVectorDrawable.getAlpha();
     }
@@ -237,12 +242,6 @@
         return super.setVisible(visible, restart);
     }
 
-    /** {@hide} */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection);
-    }
-
     @Override
     public boolean isStateful() {
         return mAnimatedVectorState.mVectorDrawable.isStateful();
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 74ff1b0..5ccb165 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -31,20 +31,23 @@
 import android.util.AttributeSet;
 
 /**
- * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
- * which can be used as a View object's background.
+ * An object used to create frame-by-frame animations, defined by a series of
+ * Drawable objects, which can be used as a View object's background.
  * <p>
- * The simplest way to create a frame-by-frame animation is to define the animation in an XML
- * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
- * {@link #start()} to run the animation.
+ * The simplest way to create a frame-by-frame animation is to define the
+ * animation in an XML file, placed in the res/drawable/ folder, and set it as
+ * the background to a View object. Then, call {@link #start()} to run the
+ * animation.
  * <p>
- * An AnimationDrawable defined in XML consists of a single <code>&lt;animation-list></code> element,
- * and a series of nested <code>&lt;item></code> tags. Each item defines a frame of the animation.
- * See the example below.
- * </p>
- * <p>spin_animation.xml file in res/drawable/ folder:</p>
- * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
- * res/drawable/ folder --&gt;
+ * An AnimationDrawable defined in XML consists of a single
+ * {@code &lt;animation-list&gt;} element and a series of nested
+ * {@code &lt;item&gt;} tags. Each item defines a frame of the animation. See
+ * the example below.
+ * <p>
+ * spin_animation.xml file in res/drawable/ folder:
+ * <pre>
+ * &lt;!-- Animation frames are wheel0.png through wheel5.png
+ *     files inside the res/drawable/ folder --&gt;
  * &lt;animation-list android:id=&quot;@+id/selected&quot; android:oneshot=&quot;false&quot;&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
@@ -53,8 +56,8 @@
  *    &lt;item android:drawable=&quot;@drawable/wheel4&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel5&quot; android:duration=&quot;50&quot; /&gt;
  * &lt;/animation-list&gt;</pre>
- *
- * <p>Here is the code to load and play this animation.</p>
+ * <p>
+ * Here is the code to load and play this animation.
  * <pre>
  * // Load the ImageView that will host the animation and
  * // set its background to our AnimationDrawable XML resource.
@@ -128,13 +131,17 @@
     }
 
     /**
-     * <p>Starts the animation, looping if necessary. This method has no effect
-     * if the animation is running. Do not call this in the {@link android.app.Activity#onCreate}
-     * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
-     * not yet fully attached to the window. If you want to play
-     * the animation immediately, without requiring interaction, then you might want to call it
-     * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
-     * which will get called when Android brings your window into focus.</p>
+     * Starts the animation, looping if necessary. This method has no effect
+     * if the animation is running.
+     * <p>
+     * <strong>Note:</strong> Do not call this in the
+     * {@link android.app.Activity#onCreate} method of your activity, because
+     * the {@link AnimationDrawable} is not yet fully attached to the window.
+     * If you want to play the animation immediately without requiring
+     * interaction, then you might want to call it from the
+     * {@link android.app.Activity#onWindowFocusChanged} method in your
+     * activity, which will get called when Android brings your window into
+     * focus.
      *
      * @see #isRunning()
      * @see #stop()
@@ -149,8 +156,8 @@
     }
 
     /**
-     * <p>Stops the animation. This method has no effect if the animation is
-     * not running.</p>
+     * Stops the animation. This method has no effect if the animation is not
+     * running.
      *
      * @see #isRunning()
      * @see #start()
@@ -165,7 +172,7 @@
     }
 
     /**
-     * <p>Indicates whether the animation is currently running or not.</p>
+     * Indicates whether the animation is currently running or not.
      *
      * @return true if the animation is running, false otherwise
      */
@@ -175,8 +182,8 @@
     }
 
     /**
-     * <p>This method exists for implementation purpose only and should not be
-     * called directly. Invoke {@link #start()} instead.</p>
+     * This method exists for implementation purpose only and should not be
+     * called directly. Invoke {@link #start()} instead.
      *
      * @see #start()
      */
@@ -208,7 +215,7 @@
 
     /**
      * @return The duration in milliseconds of the frame at the
-     * specified index
+     *         specified index
      */
     public int getDuration(int i) {
         return mAnimationState.mDurations[i];
@@ -231,12 +238,12 @@
     }
 
     /**
-     * Add a frame to the animation
+     * Adds a frame to the animation
      *
      * @param frame The frame to add
      * @param duration How long in milliseconds the frame should appear
      */
-    public void addFrame(Drawable frame, int duration) {
+    public void addFrame(@NonNull Drawable frame, int duration) {
         mAnimationState.addFrame(frame, duration);
         if (mCurFrame < 0) {
             setFrame(0, true, false);
@@ -244,13 +251,16 @@
     }
 
     private void nextFrame(boolean unschedule) {
-        int next = mCurFrame+1;
-        final int N = mAnimationState.getChildCount();
-        if (next >= N) {
-            next = 0;
+        int nextFrame = mCurFrame + 1;
+        final int numFrames = mAnimationState.getChildCount();
+        final boolean isLastFrame = mAnimationState.mOneShot && nextFrame >= (numFrames - 1);
+
+        // Loop if necessary. One-shot animations should never hit this case.
+        if (!mAnimationState.mOneShot && nextFrame >= numFrames) {
+            nextFrame = 0;
         }
 
-        setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
+        setFrame(nextFrame, unschedule, !isLastFrame);
     }
 
     private void setFrame(int frame, boolean unschedule, boolean animate) {
@@ -262,6 +272,7 @@
         selectDrawable(frame);
         if (unschedule || animate) {
             unscheduleSelf(this);
+            mRunning = false;
         }
         if (animate) {
             // Unscheduling may have clobbered these values; restore them
@@ -341,6 +352,7 @@
     }
 
     @Override
+    @NonNull
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mAnimationState.mutate();
@@ -366,8 +378,7 @@
         private int[] mDurations;
         private boolean mOneShot = false;
 
-        AnimationState(AnimationState orig, AnimationDrawable owner,
-                Resources res) {
+        AnimationState(AnimationState orig, AnimationDrawable owner, Resources res) {
             super(orig, owner, res);
 
             if (orig != null) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 9be296a..68ffed6 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -357,6 +357,11 @@
         invalidateSelf();
     }
 
+    @Override
+    public boolean getDither() {
+        return mBitmapState.mPaint.isDither();
+    }
+
     /**
      * Indicates the repeat behavior of this drawable on the X axis.
      *
@@ -623,8 +628,8 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        mBitmapState.mPaint.setColorFilter(cf);
+    public void setColorFilter(ColorFilter colorFilter) {
+        mBitmapState.mPaint.setColorFilter(colorFilter);
         invalidateSelf();
     }
 
@@ -705,8 +710,8 @@
 
     @Override
     public boolean isStateful() {
-        final BitmapState s = mBitmapState;
-        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
+        return (mBitmapState.mTint != null && mBitmapState.mTint.isStateful())
+                || super.isStateful();
     }
 
     @Override
@@ -718,6 +723,9 @@
         updateStateFromTypedArray(a);
         verifyState(a);
         a.recycle();
+
+        // Update local properties.
+        updateLocalState(r);
     }
 
     /**
@@ -800,9 +808,6 @@
         if (tileModeY != TILE_MODE_UNDEFINED) {
             setTileModeY(parseTileMode(tileModeY));
         }
-
-        // Update local properties.
-        initializeWithState(state, r);
     }
 
     @Override
@@ -810,18 +815,28 @@
         super.applyTheme(t);
 
         final BitmapState state = mBitmapState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
-        try {
-            updateStateFromTypedArray(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
+            try {
+                updateStateFromTypedArray(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
         }
+
+        // Apply theme to contained color state list.
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
+        }
+
+        // Update local properties.
+        updateLocalState(t.getResources());
     }
 
     private static Shader.TileMode parseTileMode(int tileMode) {
@@ -839,7 +854,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return mBitmapState != null && mBitmapState.mThemeAttrs != null;
+        return mBitmapState != null && mBitmapState.canApplyTheme();
     }
 
     @Override
@@ -910,7 +925,7 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            return mThemeAttrs != null || mTint != null && mTint.canApplyTheme();
         }
 
         @Override
@@ -944,7 +959,7 @@
     private BitmapDrawable(BitmapState state, Resources res) {
         mBitmapState = state;
 
-        initializeWithState(mBitmapState, res);
+        updateLocalState(res);
     }
 
     /**
@@ -952,14 +967,14 @@
      * after significant state changes, e.g. from the One True Constructor and
      * after inflating or applying a theme.
      */
-    private void initializeWithState(BitmapState state, Resources res) {
+    private void updateLocalState(Resources res) {
         if (res != null) {
             mTargetDensity = res.getDisplayMetrics().densityDpi;
         } else {
-            mTargetDensity = state.mTargetDensity;
+            mTargetDensity = mBitmapState.mTargetDensity;
         }
 
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode);
         computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index e5b2b76..2acf602 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -21,12 +21,10 @@
 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;
 
@@ -50,32 +48,36 @@
  * @attr ref android.R.styleable#ClipDrawable_gravity
  * @attr ref android.R.styleable#ClipDrawable_drawable
  */
-public class ClipDrawable extends Drawable implements Drawable.Callback {
-    private ClipState mState;
-    private final Rect mTmpRect = new Rect();
-
+public class ClipDrawable extends DrawableWrapper {
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
 
-    private boolean mMutated;
+    private static final int MAX_LEVEL = 10000;
+
+    private final Rect mTmpRect = new Rect();
+
+    private ClipState mState;
 
     ClipDrawable() {
-        this(null, null);
+        this(new ClipState(null), null);
     }
 
     /**
-     * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
+     * Creates a new clip drawable with the specified gravity and orientation.
+     *
+     * @param drawable the drawable to clip
+     * @param gravity gravity constant (see {@link Gravity} used to position
+     *                the clipped drawable within the parent container
+     * @param orientation bitwise-or of {@link #HORIZONTAL} and/or
+     *                   {@link #VERTICAL}
      */
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
-        this(null, null);
+        this(new ClipState(null), null);
 
-        mState.mDrawable = drawable;
         mState.mGravity = gravity;
         mState.mOrientation = orientation;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
+        setDrawable(drawable);
     }
 
     @Override
@@ -84,39 +86,15 @@
         super.inflate(r, parser, attrs, theme);
 
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
-
-        // Reset mDrawable to preserve old multiple-inflate behavior. This is
-        // silly, but we have CTS tests that rely on it.
-        mState.mDrawable = null;
-
         updateStateFromTypedArray(a);
-        inflateChildElements(r, parser, attrs, theme);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
     private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+        if (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <clip> tag requires a 'drawable' attribute or "
@@ -124,292 +102,110 @@
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final ClipState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
-        state.mOrientation = a.getInt(R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
-        state.mGravity = a.getInt(R.styleable.ClipDrawable_gravity, state.mGravity);
+        state.mOrientation = a.getInt(
+                R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
+        state.mGravity = a.getInt(
+                R.styleable.ClipDrawable_gravity, state.mGravity);
 
         final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final ClipState state = mState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
-        try {
-            updateStateFromTypedArray(a);
-            verifyRequiredAttributes(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    // overrides from Drawable.Callback
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    // overrides from Drawable
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        // XXX need to adjust padding!
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        return mState.mDrawable.setState(state);
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
+        super.onLevelChange(level);
         invalidateSelf();
         return true;
     }
 
     @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds);
-    }
-
-    @Override
     public void draw(Canvas canvas) {
-
-        if (mState.mDrawable.getLevel() == 0) {
+        final Drawable dr = getDrawable();
+        if (dr.getLevel() == 0) {
             return;
         }
 
         final Rect r = mTmpRect;
         final Rect bounds = getBounds();
-        int level = getLevel();
+        final int level = getLevel();
+
         int w = bounds.width();
         final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
         if ((mState.mOrientation & HORIZONTAL) != 0) {
-            w -= (w - iw) * (10000 - level) / 10000;
+            w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
+
         int h = bounds.height();
         final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
         if ((mState.mOrientation & VERTICAL) != 0) {
-            h -= (h - ih) * (10000 - level) / 10000;
+            h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
+
         final int layoutDirection = getLayoutDirection();
         Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
             canvas.save();
             canvas.clipRect(r);
-            mState.mDrawable.draw(canvas);
+            dr.draw(canvas);
             canvas.restore();
         }
     }
 
-    @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
-    /** @hide */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mState.mDrawable.setLayoutDirection(layoutDirection);
-        super.setLayoutDirection(layoutDirection);
-    }
-
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class ClipState extends ConstantState {
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
-
-        Drawable mDrawable;
-
+    static final class ClipState extends DrawableWrapper.DrawableWrapperState {
         int mOrientation = HORIZONTAL;
         int mGravity = Gravity.LEFT;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        ClipState(ClipState orig) {
+            super(orig);
 
-        ClipState(ClipState orig, ClipDrawable owner, Resources res) {
             if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mChangingConfigurations = orig.mChangingConfigurations;
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mOrientation = orig.mOrientation;
                 mGravity = orig.mGravity;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new ClipDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new ClipDrawable(this, res);
         }
-
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
-
-        boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
     }
 
     private ClipDrawable(ClipState state, Resources res) {
-        mState = new ClipState(state, this, res);
+        super(state, res);
+
+        mState = state;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index e3b50ea..f75ab36 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.graphics.*;
 import android.graphics.PorterDuff.Mode;
@@ -62,7 +63,7 @@
      *
      * @param color The color to draw.
      */
-    public ColorDrawable(int color) {
+    public ColorDrawable(@ColorInt int color) {
         mColorState = new ColorState();
 
         setColor(color);
@@ -70,7 +71,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mColorState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mColorState.getChangingConfigurations();
     }
 
     /**
@@ -117,6 +118,7 @@
      *
      * @return int The color to draw.
      */
+    @ColorInt
     public int getColor() {
         return mColorState.mUseColor;
     }
@@ -128,7 +130,7 @@
      *
      * @param color The color to draw.
      */
-    public void setColor(int color) {
+    public void setColor(@ColorInt int color) {
         if (mColorState.mBaseColor != color || mColorState.mUseColor != color) {
             mColorState.mBaseColor = mColorState.mUseColor = color;
             invalidateSelf();
@@ -233,6 +235,8 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
+
+        updateLocalState(r);
     }
 
     /**
@@ -261,13 +265,21 @@
         super.applyTheme(t);
 
         final ColorState state = mColorState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable);
-        updateStateFromTypedArray(a);
-        a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
+        }
+
+        updateLocalState(t.getResources());
     }
 
     @Override
@@ -299,17 +311,18 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            return mThemeAttrs != null
+                    || (mTint != null && mTint.canApplyTheme());
         }
 
         @Override
         public Drawable newDrawable() {
-            return new ColorDrawable(this);
+            return new ColorDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new ColorDrawable(this);
+            return new ColorDrawable(this, res);
         }
 
         @Override
@@ -318,8 +331,18 @@
         }
     }
 
-    private ColorDrawable(ColorState state) {
+    private ColorDrawable(ColorState state, Resources res) {
         mColorState = state;
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+
+        updateLocalState(res);
+    }
+
+    /**
+     * Initializes local dynamic properties from state. This should be called
+     * after significant state changes, e.g. from the One True Constructor and
+     * after inflating or applying a theme.
+     */
+    private void updateLocalState(Resources r) {
+        mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 0e38cc0..16760c7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,7 +16,9 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -274,6 +276,14 @@
     public void setDither(boolean dither) {}
 
     /**
+     * @return whether this drawable dither its colors
+     * @see #setDither(boolean)
+     */
+    public boolean getDither() {
+        return false;
+    }
+
+    /**
      * Set to true to have the drawable filter its bitmap when scaled or rotated
      * (for drawables that use bitmaps). If the drawable does not use bitmaps,
      * this call is ignored. This can improve the look when scaled or rotated,
@@ -282,6 +292,14 @@
     public void setFilterBitmap(boolean filter) {}
 
     /**
+     * @return whether this drawable filters its bitmap
+     * @see #setFilterBitmap(boolean)
+     */
+    public boolean getFilterBitmap() {
+        return false;
+    }
+
+    /**
      * Implement this interface if you want to create an animated drawable that
      * extends {@link android.graphics.drawable.Drawable Drawable}.
      * Upon retrieving a drawable, use
@@ -406,27 +424,41 @@
      * Returns the resolved layout direction for this Drawable.
      *
      * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
-     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
-     *
-     * @hide
+     *         {@link android.view.View#LAYOUT_DIRECTION_RTL}
+     * @see #setLayoutDirection(int)
      */
     public int getLayoutDirection() {
         return mLayoutDirection;
     }
 
     /**
-     * Set the layout direction for this drawable. Should be a resolved direction as the
-     * Drawable as no capacity to do the resolution on his own.
+     * Set the layout direction for this drawable. Should be a resolved
+     * layout direction, as the Drawable as no capacity to do the resolution on
+     * its own.
      *
-     * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
-     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
-     *
-     * @hide
+     * @param layoutDirection the resolved layout direction for the drawable,
+     *                        either {@link android.view.View#LAYOUT_DIRECTION_LTR}
+     *                        or {@link android.view.View#LAYOUT_DIRECTION_RTL}
+     * @see #getLayoutDirection()
      */
-    public void setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
-        if (getLayoutDirection() != layoutDirection) {
+    public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
+        if (mLayoutDirection != layoutDirection) {
             mLayoutDirection = layoutDirection;
+            return onLayoutDirectionChange(layoutDirection);
         }
+        return false;
+    }
+
+    /**
+     * Called when the drawable's resolved layout direction changes.
+     *
+     * @param layoutDirection the new resolved layout direction
+     * @return true if the layout direction change has caused the appearance of
+     *         the drawable to change and it needs to be re-drawn
+     * @see #setLayoutDirection(int)
+     */
+    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) {
+        return false;
     }
 
     /**
@@ -447,67 +479,111 @@
     }
 
     /**
-     * @hide Consider for future API inclusion
+     * @hide
+     *
+     * Internal-only method for setting xfermode on certain supported drawables.
+     *
+     * Should not be made public since the layers and drawing area with which
+     * Drawables draw is private implementation detail, and not something apps
+     * should rely upon.
      */
     public void setXfermode(Xfermode mode) {
         // Base implementation drops it on the floor for compatibility. Whee!
-        // TODO: For this to be included in the API proper, all framework drawables need impls.
-        // For right now only BitmapDrawable has it.
     }
 
     /**
-     * Specify an optional color filter for the drawable. Pass {@code null} to
-     * remove any existing color filter.
+     * Specify an optional color filter for the drawable.
+     * <p>
+     * If a Drawable has a ColorFilter, each output pixel of the Drawable's
+     * drawing contents will be modified by the color filter before it is
+     * blended onto the render target of a Canvas.
+     * </p>
+     * <p>
+     * Pass {@code null} to remove any existing color filter.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a non-{@code null} color
+     * filter disables {@link #setTintList(ColorStateList) tint}.
+     * </p>
      *
-     * @param cf the color filter to apply, or {@code null} to remove the
+     * @param colorFilter The color filter to apply, or {@code null} to remove the
      *            existing color filter
      */
-    public abstract void setColorFilter(ColorFilter cf);
+    public abstract void setColorFilter(@Nullable ColorFilter colorFilter);
 
     /**
      * Specify a color and Porter-Duff mode to be the color filter for this
      * drawable.
+     * <p>
+     * Convenience for {@link #setColorFilter(ColorFilter)} which constructs a
+     * {@link PorterDuffColorFilter}.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a color filter disables
+     * {@link #setTintList(ColorStateList) tint}.
+     * </p>
      */
-    public void setColorFilter(int color, PorterDuff.Mode mode) {
+    public void setColorFilter(int color, @NonNull PorterDuff.Mode mode) {
         setColorFilter(new PorterDuffColorFilter(color, mode));
     }
 
     /**
-     * Specifies a tint for this drawable.
+     * Specifies tint color for this drawable.
      * <p>
-     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
-     * tint.
+     * A Drawable's drawing content will be blended together with its tint
+     * before it is drawn to the screen. This functions similarly to
+     * {@link #setColorFilter(int, PorterDuff.Mode)}.
+     * </p>
+     * <p>
+     * To clear the tint, pass {@code null} to
+     * {@link #setTintList(ColorStateList)}.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a color filter via
+     * {@link #setColorFilter(ColorFilter)} or
+     * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
+     * </p>
      *
-     * @param tint Color to use for tinting this drawable
+     * @param tintColor Color to use for tinting this drawable
+     * @see #setTintList(ColorStateList)
      * @see #setTintMode(PorterDuff.Mode)
      */
-    public void setTint(int tint) {
-        setTintList(ColorStateList.valueOf(tint));
+    public void setTint(@ColorInt int tintColor) {
+        setTintList(ColorStateList.valueOf(tintColor));
     }
 
     /**
-     * Specifies a tint for this drawable as a color state list.
+     * Specifies tint color for this drawable as a color state list.
      * <p>
-     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
-     * tint.
+     * A Drawable's drawing content will be blended together with its tint
+     * before it is drawn to the screen. This functions similarly to
+     * {@link #setColorFilter(int, PorterDuff.Mode)}.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a color filter via
+     * {@link #setColorFilter(ColorFilter)} or
+     * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
+     * </p>
      *
-     * @param tint Color state list to use for tinting this drawable, or null to
-     *            clear the tint
+     * @param tint Color state list to use for tinting this drawable, or
+     *            {@code null} to clear the tint
+     * @see #setTint(int)
      * @see #setTintMode(PorterDuff.Mode)
      */
-    public void setTintList(ColorStateList tint) {}
+    public void setTintList(@Nullable ColorStateList tint) {}
 
     /**
      * Specifies a tint blending mode for this drawable.
      * <p>
-     * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
-     * tint.
+     * Defines how this drawable's tint color should be blended into the drawable
+     * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#MULTIPLY}.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a color filter via
+     * {@link #setColorFilter(ColorFilter)} or
+     * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint.
+     * </p>
      *
-     * @param tintMode Color state list to use for tinting this drawable, or null to
-     *            clear the tint
      * @param tintMode A Porter-Duff blending mode
+     * @see #setTint(int)
+     * @see #setTintList(ColorStateList)
      */
-    public void setTintMode(PorterDuff.Mode tintMode) {}
+    public void setTintMode(@NonNull PorterDuff.Mode tintMode) {}
 
     /**
      * Returns the current color filter, or {@code null} if none set.
@@ -537,14 +613,20 @@
      * Sets the bounds to which the hotspot is constrained, if they should be
      * different from the drawable bounds.
      *
-     * @param left
-     * @param top
-     * @param right
-     * @param bottom
+     * @param left position in pixels of the left bound
+     * @param top position in pixels of the top bound
+     * @param right position in pixels of the right bound
+     * @param bottom position in pixels of the bottom bound
+     * @see #getHotspotBounds(android.graphics.Rect)
      */
     public void setHotspotBounds(int left, int top, int right, int bottom) {}
 
-    /** @hide For internal use only. Individual results may vary. */
+    /**
+     * Populates {@code outRect} with the hotspot bounds.
+     *
+     * @param outRect the rect to populate with the hotspot bounds
+     * @see #setHotspotBounds(int, int, int, int)
+     */
     public void getHotspotBounds(Rect outRect) {
         outRect.set(getBounds());
     }
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 39ef10c..ddcb48b 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -167,14 +167,19 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        mDrawableContainerState.mHasColorFilter = (cf != null);
+    public boolean getDither() {
+        return mDrawableContainerState.mDither;
+    }
 
-        if (mDrawableContainerState.mColorFilter != cf) {
-            mDrawableContainerState.mColorFilter = cf;
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mDrawableContainerState.mHasColorFilter = true;
+
+        if (mDrawableContainerState.mColorFilter != colorFilter) {
+            mDrawableContainerState.mColorFilter = colorFilter;
 
             if (mCurrDrawable != null) {
-                mCurrDrawable.mutate().setColorFilter(cf);
+                mCurrDrawable.mutate().setColorFilter(colorFilter);
             }
         }
     }
@@ -301,7 +306,6 @@
         }
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         if (mHotspotBounds != null) {
@@ -334,6 +338,13 @@
     }
 
     @Override
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        // Let the container handle setting its own layout direction. Otherwise,
+        // we're accessing potentially unused states.
+        return mDrawableContainerState.setLayoutDirection(layoutDirection, getCurrentIndex());
+    }
+
+    @Override
     public int getIntrinsicWidth() {
         if (mDrawableContainerState.isConstantSize()) {
             return mDrawableContainerState.getConstantWidth();
@@ -674,7 +685,7 @@
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
-            mRes = res;
+            mRes = res != null ? res : orig != null ? orig.mRes : null;
 
             if (orig != null) {
                 mChangingConfigurations = orig.mChangingConfigurations;
@@ -824,18 +835,25 @@
             return null;
         }
 
-        final void setLayoutDirection(int layoutDirection) {
+        final boolean setLayoutDirection(int layoutDirection, int currentIndex) {
+            boolean changed = false;
+
             // No need to call createAllFutures, since future drawables will
             // change layout direction when they are prepared.
             final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             for (int i = 0; i < N; i++) {
                 if (drawables[i] != null) {
-                    drawables[i].setLayoutDirection(layoutDirection);
+                    final boolean childChanged = drawables[i].setLayoutDirection(layoutDirection);
+                    if (i == currentIndex) {
+                        changed = childChanged;
+                    }
                 }
             }
 
             mLayoutDirection = layoutDirection;
+
+            return changed;
         }
 
         final void applyTheme(Theme theme) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
new file mode 100644
index 0000000..a213af8
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Insets;
+import android.graphics.Outline;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * Drawable container with only one child element.
+ */
+public abstract class DrawableWrapper extends Drawable implements Drawable.Callback {
+    private DrawableWrapperState mState;
+    private Drawable mDrawable;
+    private boolean mMutated;
+
+    DrawableWrapper(DrawableWrapperState state, Resources res) {
+        mState = state;
+
+        updateLocalState(res);
+    }
+
+    /**
+     * Creates a new wrapper around the specified drawable.
+     *
+     * @param dr the drawable to wrap
+     */
+    public DrawableWrapper(@Nullable Drawable dr) {
+        mState = null;
+        mDrawable = dr;
+    }
+
+    /**
+     * Initializes local dynamic properties from state. This should be called
+     * after significant state changes, e.g. from the One True Constructor and
+     * after inflating or applying a theme.
+     */
+    private void updateLocalState(Resources res) {
+        if (mState != null && mState.mDrawableState != null) {
+            final Drawable dr = mState.mDrawableState.newDrawable(res);
+            setDrawable(dr);
+        }
+    }
+
+    /**
+     * Sets the wrapped drawable.
+     *
+     * @param dr the wrapped drawable
+     */
+    public void setDrawable(@Nullable Drawable dr) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+        }
+
+        mDrawable = dr;
+
+        if (dr != null) {
+            dr.setCallback(this);
+
+            // Only call setters for data that's stored in the base Drawable.
+            dr.setVisible(isVisible(), true);
+            dr.setState(getState());
+            dr.setLevel(getLevel());
+            dr.setBounds(getBounds());
+            dr.setLayoutDirection(getLayoutDirection());
+
+            if (mState != null) {
+                mState.mDrawableState = dr.getConstantState();
+            }
+        }
+
+        invalidateSelf();
+    }
+
+    /**
+     * @return the wrapped drawable
+     */
+    @Nullable
+    public Drawable getDrawable() {
+        return mDrawable;
+    }
+
+    void updateStateFromTypedArray(TypedArray a) {
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        // TODO: Consider using R.styleable.DrawableWrapper_drawable
+    }
+
+    @Override
+    public void applyTheme(Resources.Theme t) {
+        super.applyTheme(t);
+
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (mDrawable != null && mDrawable.canApplyTheme()) {
+            mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable who) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.invalidateDrawable(this);
+        }
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.scheduleDrawable(this, what, when);
+        }
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.unscheduleDrawable(this, what);
+        }
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        if (mDrawable != null) {
+            mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    public int getChangingConfigurations() {
+        return super.getChangingConfigurations()
+                | (mState != null ? mState.mChangingConfigurations : 0)
+                | mDrawable.getChangingConfigurations();
+    }
+
+    @Override
+    public boolean getPadding(@NonNull Rect padding) {
+        return mDrawable != null && mDrawable.getPadding(padding);
+    }
+
+    /** @hide */
+    @Override
+    public Insets getOpticalInsets() {
+        return mDrawable != null ? mDrawable.getOpticalInsets() : Insets.NONE;
+    }
+
+    @Override
+    public void setHotspot(float x, float y) {
+        if (mDrawable != null) {
+            mDrawable.setHotspot(x, y);
+        }
+    }
+
+    @Override
+    public void setHotspotBounds(int left, int top, int right, int bottom) {
+        if (mDrawable != null) {
+            mDrawable.setHotspotBounds(left, top, right, bottom);
+        }
+    }
+
+    @Override
+    public void getHotspotBounds(@NonNull Rect outRect) {
+        if (mDrawable != null) {
+            mDrawable.getHotspotBounds(outRect);
+        } else {
+            outRect.set(getBounds());
+        }
+    }
+
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        final boolean superChanged = super.setVisible(visible, restart);
+        final boolean changed = mDrawable != null && mDrawable.setVisible(visible, restart);
+        return superChanged | changed;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        if (mDrawable != null) {
+            mDrawable.setAlpha(alpha);
+        }
+    }
+
+    @Override
+    public int getAlpha() {
+        return mDrawable != null ? mDrawable.getAlpha() : 255;
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        if (mDrawable != null) {
+            mDrawable.setColorFilter(colorFilter);
+        }
+    }
+
+    @Override
+    public void setTintList(@Nullable ColorStateList tint) {
+        if (mDrawable != null) {
+            mDrawable.setTintList(tint);
+        }
+    }
+
+    @Override
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mDrawable != null) {
+            mDrawable.setTintMode(tintMode);
+        }
+    }
+
+    @Override
+    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) {
+        return mDrawable != null && mDrawable.setLayoutDirection(layoutDirection);
+    }
+
+    @Override
+    public int getOpacity() {
+        return mDrawable != null ? mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mDrawable != null && mDrawable.isStateful();
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        if (mDrawable != null) {
+            final boolean changed = mDrawable.setState(state);
+            if (changed) {
+                onBoundsChange(getBounds());
+            }
+            return changed;
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        return mDrawable != null && mDrawable.setLevel(level);
+    }
+
+    @Override
+    protected void onBoundsChange(@NonNull Rect bounds) {
+        if (mDrawable != null) {
+            mDrawable.setBounds(bounds);
+        }
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mDrawable != null ? mDrawable.getIntrinsicWidth() : -1;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mDrawable != null ? mDrawable.getIntrinsicHeight() : -1;
+    }
+
+    @Override
+    public void getOutline(@NonNull Outline outline) {
+        if (mDrawable != null) {
+            mDrawable.getOutline(outline);
+        } else {
+            super.getOutline(outline);
+        }
+    }
+
+    @Override
+    @Nullable
+    public ConstantState getConstantState() {
+        if (mState != null && mState.canConstantState()) {
+            mState.mChangingConfigurations = getChangingConfigurations();
+            return mState;
+        }
+        return null;
+    }
+
+    @Override
+    @NonNull
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState = mutateConstantState();
+            if (mDrawable != null) {
+                mDrawable.mutate();
+            }
+            if (mState != null) {
+                mState.mDrawableState = mDrawable != null ? mDrawable.getConstantState() : null;
+            }
+            mMutated = true;
+        }
+        return this;
+    }
+
+    /**
+     * Mutates the constant state and returns the new state. Responsible for
+     * updating any local copy.
+     * <p>
+     * This method should never call the super implementation; it should always
+     * mutate and return its own constant state.
+     *
+     * @return the new state
+     */
+    DrawableWrapperState mutateConstantState() {
+        return mState;
+    }
+
+    /**
+     * @hide Only used by the framework for pre-loading resources.
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        if (mDrawable != null) {
+            mDrawable.clearMutated();
+        }
+        mMutated = false;
+    }
+
+    /**
+     * Called during inflation to inflate the child element.
+     */
+    void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Resources.Theme theme) throws XmlPullParserException, IOException {
+        // Drawable specified on the root element takes precedence.
+        if (getDrawable() != null) {
+            return;
+        }
+
+        // Seek to the first child element.
+        Drawable dr = null;
+        int type;
+        final int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.START_TAG) {
+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+                break;
+            }
+        }
+
+        if (dr != null) {
+            setDrawable(dr);
+        }
+    }
+
+    abstract static class DrawableWrapperState extends Drawable.ConstantState {
+        int[] mThemeAttrs;
+        int mChangingConfigurations;
+
+        Drawable.ConstantState mDrawableState;
+
+        DrawableWrapperState(DrawableWrapperState orig) {
+            if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
+                mChangingConfigurations = orig.mChangingConfigurations;
+                mDrawableState = orig.mDrawableState;
+            }
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null
+                    || (mDrawableState != null && mDrawableState.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final Drawable.ConstantState state = mDrawableState;
+            if (state != null) {
+                return state.addAtlasableBitmaps(atlasList);
+            }
+            return 0;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return newDrawable(null);
+        }
+
+        @Override
+        public abstract Drawable newDrawable(Resources res);
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+
+        public boolean canConstantState() {
+            return mDrawableState != null;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index cb42397..eff152c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.ColorInt;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -143,7 +144,7 @@
     private final RectF mRect = new RectF();
 
     private Paint mLayerPaint;    // internal, used if we use saveLayer()
-    private boolean mGradientIsDirty;   // internal state
+    private boolean mGradientIsDirty;
     private boolean mMutated;
     private Path mRingPath;
     private boolean mPathIsDirty = true;
@@ -174,15 +175,15 @@
     }
 
     public GradientDrawable() {
-        this(new GradientState(Orientation.TOP_BOTTOM, null));
+        this(new GradientState(Orientation.TOP_BOTTOM, null), null);
     }
 
     /**
      * Create a new gradient drawable given an orientation and an array
      * of colors for the gradient.
      */
-    public GradientDrawable(Orientation orientation, int[] colors) {
-        this(new GradientState(orientation, colors));
+    public GradientDrawable(Orientation orientation, @ColorInt int[] colors) {
+        this(new GradientState(orientation, colors), null);
     }
 
     @Override
@@ -250,7 +251,7 @@
      * @see #mutate()
      * @see #setStroke(int, int, float, float)
      */
-    public void setStroke(int width, int color) {
+    public void setStroke(int width, @ColorInt int color) {
         setStroke(width, color, 0, 0);
     }
 
@@ -286,7 +287,7 @@
      * @see #mutate()
      * @see #setStroke(int, int)
      */
-    public void setStroke(int width, int color, float dashWidth, float dashGap) {
+    public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) {
         mGradientState.setStroke(width, ColorStateList.valueOf(color), dashWidth, dashGap);
         setStrokeInternal(width, color, dashWidth, dashGap);
     }
@@ -492,16 +493,16 @@
     /**
      * <p>Sets the colors used to draw the gradient. Each color is specified as an
      * ARGB integer and the array must contain at least 2 colors.</p>
-     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * <p><strong>Note</strong>: changing colors will affect all instances
      * of a drawable loaded from a resource. It is recommended to invoke
-     * {@link #mutate()} before changing the orientation.</p>
+     * {@link #mutate()} before changing the colors.</p>
      *
      * @param colors 2 or more ARGB colors
      *
      * @see #mutate()
      * @see #setColor(int)
      */
-    public void setColors(int[] colors) {
+    public void setColors(@ColorInt int[] colors) {
         mGradientState.setColors(colors);
         mGradientIsDirty = true;
         invalidateSelf();
@@ -713,7 +714,7 @@
      * @see #mutate()
      * @see #setColors(int[])
      */
-    public void setColor(int argb) {
+    public void setColor(@ColorInt int argb) {
         mGradientState.setColorStateList(ColorStateList.valueOf(argb));
         mFillPaint.setColor(argb);
         invalidateSelf();
@@ -822,14 +823,19 @@
     }
 
     @Override
+    public boolean getDither() {
+        return mGradientState.mDither;
+    }
+
+    @Override
     public ColorFilter getColorFilter() {
         return mColorFilter;
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        if (cf != mColorFilter) {
-            mColorFilter = cf;
+    public void setColorFilter(ColorFilter colorFilter) {
+        if (colorFilter != mColorFilter) {
+            mColorFilter = colorFilter;
             invalidateSelf();
         }
     }
@@ -1018,7 +1024,7 @@
 
         inflateChildElements(r, parser, attrs, theme);
 
-        mGradientState.computeOpacity();
+        updateLocalState(r);
     }
 
     @Override
@@ -1037,9 +1043,21 @@
             a.recycle();
         }
 
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
+        }
+
+        if (state.mColorStateList != null && state.mColorStateList.canApplyTheme()) {
+            state.mColorStateList.applyTheme(t);
+        }
+
+        if (state.mStrokeColorStateList != null && state.mStrokeColorStateList.canApplyTheme()) {
+            state.mStrokeColorStateList.applyTheme(t);
+        }
+
         applyThemeChildElements(t);
 
-        state.computeOpacity();
+        updateLocalState(t.getResources());
     }
 
     /**
@@ -1087,8 +1105,6 @@
         if (tint != null) {
             state.mTint = tint;
         }
-
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
     @Override
@@ -1516,7 +1532,7 @@
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mGradientState = new GradientState(mGradientState);
-            initializeWithState(mGradientState);
+            updateLocalState(null);
             mMutated = true;
         }
         return this;
@@ -1577,7 +1593,7 @@
         int[] mAttrCorners;
         int[] mAttrPadding;
 
-        GradientState(Orientation orientation, int[] colors) {
+        public GradientState(Orientation orientation, int[] colors) {
             mOrientation = orientation;
             setColors(colors);
         }
@@ -1634,19 +1650,24 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
-                    || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
-                    || mAttrPadding != null || super.canApplyTheme();
+            return mThemeAttrs != null
+                    || mAttrSize != null || mAttrGradient != null
+                    || mAttrSolid != null || mAttrStroke != null
+                    || mAttrCorners != null || mAttrPadding != null
+                    || (mTint != null && mTint.canApplyTheme())
+                    || (mStrokeColorStateList != null && mStrokeColorStateList.canApplyTheme())
+                    || (mColorStateList != null && mColorStateList.canApplyTheme())
+                    || super.canApplyTheme();
         }
 
         @Override
         public Drawable newDrawable() {
-            return new GradientDrawable(this);
+            return new GradientDrawable(this, null);
         }
 
         @Override
         public Drawable newDrawable(Resources res) {
-            return new GradientDrawable(this);
+            return new GradientDrawable(this, res);
         }
 
         @Override
@@ -1751,16 +1772,15 @@
      *
      * @param state Constant state from which the drawable inherits
      */
-    private GradientDrawable(GradientState state) {
+    private GradientDrawable(GradientState state, Resources res) {
         mGradientState = state;
 
-        initializeWithState(mGradientState);
-
-        mGradientIsDirty = true;
-        mMutated = false;
+        updateLocalState(res);
     }
 
-    private void initializeWithState(GradientState state) {
+    private void updateLocalState(Resources res) {
+        final GradientState state = mGradientState;
+
         if (state.mColorStateList != null) {
             final int[] currentState = getState();
             final int stateColor = state.mColorStateList.getColorForState(currentState, 0);
@@ -1797,5 +1817,8 @@
         }
 
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        mGradientIsDirty = true;
+
+        state.computeOpacity();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 8b70a08..97f7105 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -18,28 +18,20 @@
 
 import com.android.internal.R;
 
-import android.annotation.NonNull;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.res.ColorStateList;
+import android.annotation.NonNull;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
+import android.content.res.TypedArray;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 
 import java.io.IOException;
-import java.util.Collection;
 
 /**
  * A Drawable that insets another Drawable by a specified distance.
@@ -57,74 +49,64 @@
  * @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 DrawableWrapper {
     private final Rect mTmpRect = new Rect();
 
-    private final InsetState mState;
+    private InsetState mState;
 
-    private boolean mMutated;
-
-    /*package*/ InsetDrawable() {
-        this(null, null);
+    /**
+     * No-arg constructor used by drawable inflation.
+     */
+    InsetDrawable() {
+        this(new InsetState(null), null);
     }
 
+    /**
+     * Creates a new inset drawable with the specified inset.
+     *
+     * @param drawable The drawable to inset.
+     * @param inset Inset in pixels around the drawable.
+     */
     public InsetDrawable(Drawable drawable, int inset) {
         this(drawable, inset, inset, inset, inset);
     }
 
-    public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
-                         int insetRight, int insetBottom) {
-        this(null, null);
+    /**
+     * Creates a new inset drawable with the specified insets.
+     *
+     * @param drawable The drawable to inset.
+     * @param insetLeft Left inset in pixels.
+     * @param insetTop Top inset in pixels.
+     * @param insetRight Right inset in pixels.
+     * @param insetBottom Bottom inset in pixels.
+     */
+    public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
+            int insetBottom) {
+        this(new InsetState(null), null);
 
-        mState.mDrawable = drawable;
         mState.mInsetLeft = insetLeft;
         mState.mInsetTop = insetTop;
         mState.mInsetRight = insetRight;
         mState.mInsetBottom = insetBottom;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
+        setDrawable(drawable);
     }
 
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs, theme);
+
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
-        super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
-
-        // Reset mDrawable to preserve old multiple-inflate behavior. This is
-        // silly, but we have CTS tests that rely on it.
-        mState.mDrawable = null;
-
         updateStateFromTypedArray(a);
-        inflateChildElements(r, parser, attrs, theme);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        // Load inner XML elements.
-        if (mState.mDrawable == null) {
-            int type;
-            while ((type=parser.next()) == XmlPullParser.TEXT) {
-            }
-            if (type != XmlPullParser.START_TAG) {
-                throw new XmlPullParserException(
-                        parser.getPositionDescription()
-                                + ": <inset> tag requires a 'drawable' attribute or "
-                                + "child tag defining a drawable");
-            }
-            final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
     private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+        if (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <inset> tag requires a 'drawable' attribute or "
@@ -132,15 +114,11 @@
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final InsetState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
             final int attr = a.getIndex(i);
@@ -148,8 +126,7 @@
                 case R.styleable.InsetDrawable_drawable:
                     final Drawable dr = a.getDrawable(attr);
                     if (dr != null) {
-                        state.mDrawable = dr;
-                        dr.setCallback(this);
+                        setDrawable(dr);
                     }
                     break;
                 case R.styleable.InsetDrawable_inset:
@@ -179,8 +156,6 @@
 
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final InsetState state = mState;
         if (state == null) {
             return;
@@ -198,63 +173,22 @@
             }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        mState.mDrawable.draw(canvas);
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
     @Override
     public boolean getPadding(Rect padding) {
-        boolean pad = mState.mDrawable.getPadding(padding);
+        final boolean pad = super.getPadding(padding);
 
         padding.left += mState.mInsetLeft;
         padding.right += mState.mInsetRight;
         padding.top += mState.mInsetTop;
         padding.bottom += mState.mInsetBottom;
 
-        return pad || (mState.mInsetLeft | mState.mInsetRight |
-                mState.mInsetTop | mState.mInsetBottom) != 0;
+        return pad || (mState.mInsetLeft | mState.mInsetRight
+                | mState.mInsetTop | mState.mInsetBottom) != 0;
     }
 
     /** @hide */
@@ -268,62 +202,9 @@
     }
 
     @Override
-    public void setHotspot(float x, float y) {
-        mState.mDrawable.setHotspot(x, y);
-    }
-
-    @Override
-    public void setHotspotBounds(int left, int top, int right, int bottom) {
-        mState.mDrawable.setHotspotBounds(left, top, right, bottom);
-    }
-
-    /** @hide */
-    @Override
-    public void getHotspotBounds(Rect outRect) {
-        mState.mDrawable.getHotspotBounds(outRect);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    /** {@hide} */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mState.mDrawable.setLayoutDirection(layoutDirection);
-    }
-
-    @Override
     public int getOpacity() {
         final InsetState state = mState;
-        final int opacity = state.mDrawable.getOpacity();
+        final int opacity = getDrawable().getOpacity();
         if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0
                 || state.mInsetRight > 0 || state.mInsetBottom > 0)) {
             return PixelFormat.TRANSLUCENT;
@@ -332,23 +213,6 @@
     }
 
     @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        boolean changed = mState.mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
-    }
-
-    @Override
-    protected boolean onLevelChange(int level) {
-        return mState.mDrawable.setLevel(level);
-    }
-
-    @Override
     protected void onBoundsChange(Rect bounds) {
         final Rect r = mTmpRect;
         r.set(bounds);
@@ -358,24 +222,23 @@
         r.right -= mState.mInsetRight;
         r.bottom -= mState.mInsetBottom;
 
-        mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+        // Apply inset bounds to the wrapped drawable.
+        super.onBoundsChange(r);
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth()
-                + mState.mInsetLeft + mState.mInsetRight;
+        return getDrawable().getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight()
-                + mState.mInsetTop + mState.mInsetBottom;
+        return getDrawable().getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
     }
 
     @Override
     public void getOutline(@NonNull Outline outline) {
-        mState.mDrawable.getOutline(outline);
+        getDrawable().getOutline(outline);
     }
 
     @Override
@@ -388,107 +251,47 @@
     }
 
     @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
+    DrawableWrapperState mutateConstantState() {
+        mState = new InsetState(mState);
+        return mState;
     }
 
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    /**
-     * Returns the drawable wrapped by this InsetDrawable. May be null.
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    final static class InsetState extends ConstantState {
+    static final class InsetState extends DrawableWrapper.DrawableWrapperState {
         int[] mThemeAttrs;
         int mChangingConfigurations;
 
-        Drawable mDrawable;
+        ConstantState mDrawableState;
 
         int mInsetLeft = 0;
         int mInsetTop = 0;
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        InsetState(InsetState orig) {
+            super(orig);
 
-        InsetState(InsetState orig, InsetDrawable owner, Resources res) {
             if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mChangingConfigurations = orig.mChangingConfigurations;
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
                 mInsetRight = orig.mInsetRight;
                 mInsetBottom = orig.mInsetBottom;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        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;
-        }
-
-        boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
-
-        @Override
-        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
-            final ConstantState state = mDrawable.getConstantState();
-            if (state != null) {
-                return state.addAtlasableBitmaps(atlasList);
-            }
-            return 0;
-        }
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     private InsetDrawable(InsetState state, Resources res) {
-        mState = new InsetState(state, this, res);
+        super(state, res);
+
+        mState = state;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 4aa5f59..74f62be 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -29,6 +29,8 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.LayoutDirection;
+import android.view.Gravity;
 import android.view.View;
 
 import com.android.internal.R;
@@ -54,6 +56,11 @@
  * @attr ref android.R.styleable#LayerDrawableItem_top
  * @attr ref android.R.styleable#LayerDrawableItem_right
  * @attr ref android.R.styleable#LayerDrawableItem_bottom
+ * @attr ref android.R.styleable#LayerDrawableItem_start
+ * @attr ref android.R.styleable#LayerDrawableItem_end
+ * @attr ref android.R.styleable#LayerDrawableItem_width
+ * @attr ref android.R.styleable#LayerDrawableItem_height
+ * @attr ref android.R.styleable#LayerDrawableItem_gravity
  * @attr ref android.R.styleable#LayerDrawableItem_drawable
  * @attr ref android.R.styleable#LayerDrawableItem_id
 */
@@ -73,6 +80,9 @@
      */
     public static final int PADDING_MODE_STACK = 1;
 
+    /** Value used for undefined start and end insets. */
+    private static final int UNDEFINED_INSET = Integer.MIN_VALUE;
+
     LayerState mLayerState;
 
     private int mOpacityOverride = PixelFormat.UNKNOWN;
@@ -82,6 +92,8 @@
     private int[] mPaddingB;
 
     private final Rect mTmpRect = new Rect();
+    private final Rect mTmpOutRect = new Rect();
+    private final Rect mTmpContainer = new Rect();
     private Rect mHotspotBounds;
     private boolean mMutated;
 
@@ -231,6 +243,16 @@
                 R.styleable.LayerDrawableItem_right, layer.mInsetR);
         layer.mInsetB = a.getDimensionPixelOffset(
                 R.styleable.LayerDrawableItem_bottom, layer.mInsetB);
+        layer.mInsetS = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_start, layer.mInsetS);
+        layer.mInsetE = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_end, layer.mInsetE);
+        layer.mWidth = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_width, layer.mWidth);
+        layer.mHeight = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_height, layer.mHeight);
+        layer.mGravity = a.getInteger(
+                R.styleable.LayerDrawableItem_gravity, layer.mGravity);
         layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId);
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
@@ -300,7 +322,13 @@
         return false;
     }
 
-    void addLayer(ChildDrawable layer) {
+    /**
+     * Adds a new layer at the end of list of layers and returns its index.
+     *
+     * @param layer The layer to add.
+     * @return The index of the layer.
+     */
+    int addLayer(ChildDrawable layer) {
         final LayerState st = mLayerState;
         final int N = st.mChildren != null ? st.mChildren.length : 0;
         final int i = st.mNum;
@@ -316,12 +344,13 @@
         st.mChildren[i] = layer;
         st.mNum++;
         st.invalidateCache();
+        return i;
     }
 
     /**
      * Add a new layer to this drawable. The new layer is identified by an id.
      *
-     * @param layer The drawable to add as a layer.
+     * @param dr The drawable to add as a layer.
      * @param themeAttrs Theme attributes extracted from the layer.
      * @param id The id of the new layer.
      * @param left The left padding of the new layer.
@@ -329,12 +358,11 @@
      * @param right The right padding of the new layer.
      * @param bottom The bottom padding of the new layer.
      */
-    ChildDrawable addLayer(Drawable layer, int[] themeAttrs, int id, int left, int top, int right,
-            int bottom) {
-        final ChildDrawable childDrawable = new ChildDrawable();
+    ChildDrawable addLayer(Drawable dr, int[] themeAttrs, int id,
+            int left, int top, int right, int bottom) {
+        final ChildDrawable childDrawable = createLayer(dr);
         childDrawable.mId = id;
         childDrawable.mThemeAttrs = themeAttrs;
-        childDrawable.mDrawable = layer;
         childDrawable.mDrawable.setAutoMirrored(isAutoMirrored());
         childDrawable.mInsetL = left;
         childDrawable.mInsetT = top;
@@ -343,12 +371,31 @@
 
         addLayer(childDrawable);
 
-        mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
-        layer.setCallback(this);
+        mLayerState.mChildrenChangingConfigurations |= dr.getChangingConfigurations();
+        dr.setCallback(this);
 
         return childDrawable;
     }
 
+    private ChildDrawable createLayer(Drawable dr) {
+        final ChildDrawable layer = new ChildDrawable();
+        layer.mDrawable = dr;
+        return layer;
+    }
+
+    /**
+     * Adds a new layer containing the specified {@code drawable} to the end of
+     * the layer list and returns its index.
+     *
+     * @param dr The drawable to add as a new layer.
+     * @return The index of the new layer.
+     */
+    public int addLayer(Drawable dr) {
+        final ChildDrawable layer = createLayer(dr);
+        final int index = addLayer(layer);
+        return index;
+    }
+
     /**
      * Looks for a layer with the given ID and returns its {@link Drawable}.
      * <p>
@@ -373,15 +420,38 @@
     /**
      * Sets the ID of a layer.
      *
-     * @param index The index of the layer which will received the ID.
-     * @param id The ID to assign to the layer.
+     * @param index The index of the layer to modify, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @param id The id to assign to the layer.
+     *
+     * @see #getId(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_id
      */
     public void setId(int index, int id) {
         mLayerState.mChildren[index].mId = id;
     }
 
     /**
-     * Returns the number of layers contained within this.
+     * Returns the ID of the specified layer.
+     *
+     * @param index The index of the layer, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @return The id of the layer or {@link android.view.View#NO_ID} if the
+     *         layer has no id.
+     *
+     * @see #setId(int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_id
+     */
+    public int getId(int index) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mLayerState.mChildren[index].mId;
+    }
+
+    /**
+     * Returns the number of layers contained within this layer drawable.
+     *
      * @return The number of layers.
      */
     public int getNumberOfLayers() {
@@ -389,29 +459,7 @@
     }
 
     /**
-     * Returns the drawable at the specified layer index.
-     *
-     * @param index The layer index of the drawable to retrieve.
-     *
-     * @return The {@link android.graphics.drawable.Drawable} at the specified layer index.
-     */
-    public Drawable getDrawable(int index) {
-        return mLayerState.mChildren[index].mDrawable;
-    }
-
-    /**
-     * Returns the id of the specified layer.
-     *
-     * @param index The index of the layer.
-     *
-     * @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.
-     */
-    public int getId(int index) {
-        return mLayerState.mChildren[index].mId;
-    }
-
-    /**
-     * Sets (or replaces) the {@link Drawable} for the layer with the given id.
+     * Replaces the {@link Drawable} for the layer with the given id.
      *
      * @param id The layer ID to search for.
      * @param drawable The replacement {@link Drawable}.
@@ -419,31 +467,188 @@
      *         the id was not found).
      */
     public boolean setDrawableByLayerId(int id, Drawable drawable) {
+        final int index = findIndexByLayerId(id);
+        if (index < 0) {
+            return false;
+        }
+
+        setDrawable(index, drawable);
+        return true;
+    }
+
+    /**
+     * Returns the layer with the specified {@code id}.
+     * <p>
+     * If multiple layers have the same ID, returns the layer with the lowest
+     * index.
+     *
+     * @param id The ID of the layer to return.
+     * @return The index of the layer with the specified ID.
+     */
+    public int findIndexByLayerId(int id) {
         final ChildDrawable[] layers = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable childDrawable = layers[i];
             if (childDrawable.mId == id) {
-                if (childDrawable.mDrawable != null) {
-                    if (drawable != null) {
-                        final Rect bounds = childDrawable.mDrawable.getBounds();
-                        drawable.setBounds(bounds);
-                    }
-
-                    childDrawable.mDrawable.setCallback(null);
-                }
-
-                if (drawable != null) {
-                    drawable.setCallback(this);
-                }
-
-                childDrawable.mDrawable = drawable;
-                mLayerState.invalidateCache();
-                return true;
+                return i;
             }
         }
 
-        return false;
+        return -1;
+    }
+
+    /**
+     * Sets the drawable for the layer at the specified index.
+     *
+     * @param index The index of the layer to modify, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @param drawable The drawable to set for the layer.
+     *
+     * @see #getDrawable(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_drawable
+     */
+    public void setDrawable(int index, Drawable drawable) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        final ChildDrawable[] layers = mLayerState.mChildren;
+        final ChildDrawable childDrawable = layers[index];
+        if (childDrawable.mDrawable != null) {
+            if (drawable != null) {
+                final Rect bounds = childDrawable.mDrawable.getBounds();
+                drawable.setBounds(bounds);
+            }
+
+            childDrawable.mDrawable.setCallback(null);
+        }
+
+        if (drawable != null) {
+            drawable.setCallback(this);
+            drawable.setLayoutDirection(getLayoutDirection());
+            drawable.setLevel(getLevel());
+        }
+
+        childDrawable.mDrawable = drawable;
+        mLayerState.invalidateCache();
+    }
+
+    /**
+     * Returns the drawable for the layer at the specified index.
+     *
+     * @param index The index of the layer, must be in the range
+     *              {@code 0...getNumberOfLayers()-1}.
+     * @return The {@link Drawable} at the specified layer index.
+     *
+     * @see #setDrawable(int, Drawable)
+     * @attr ref android.R.styleable#LayerDrawableItem_drawable
+     */
+    public Drawable getDrawable(int index) {
+        if (index >= mLayerState.mNum) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mLayerState.mChildren[index].mDrawable;
+    }
+
+    /**
+     * Sets an explicit size for the specified layer.
+     * <p>
+     * <strong>Note:</strong> Setting an explicit layer size changes the
+     * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
+     * for more information.
+     *
+     * @param index the index of the layer to adjust
+     * @param w width in pixels, or -1 to use the intrinsic width
+     * @param h height in pixels, or -1 to use the intrinsic height
+     * @see #getLayerWidth(int)
+     * @see #getLayerHeight(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public void setLayerSize(int index, int w, int h) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mWidth = w;
+        childDrawable.mHeight = h;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param w width in pixels, or -1 to use the intrinsic width
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     */
+    public void setLayerWidth(int index, int w) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mWidth = w;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit width of the layer, or -1 if not specified
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     */
+    public int getLayerWidth(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mWidth;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param h height in pixels, or -1 to use the intrinsic height
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public void setLayerHeight(int index, int h) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mHeight = h;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit height of the layer, or -1 if not specified
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public int getLayerHeight(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mHeight;
+    }
+
+    /**
+     * Sets the gravity used to position or stretch the specified layer within
+     * its container. Gravity is applied after any layer insets (see
+     * {@link #setLayerInset(int, int, int, int, int)}) or padding (see
+     * {@link #setPaddingMode(int)}).
+     * <p>
+     * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default
+     * behavior depends on whether an explicit width or height has been set
+     * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set,
+     * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or
+     * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction
+     * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}.
+     *
+     * @param index the index of the drawable to adjust
+     * @param gravity the gravity to set for the layer
+     *
+     * @see #getLayerGravity(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public void setLayerGravity(int index, int gravity) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mGravity = gravity;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return the gravity used to position or stretch the specified layer
+     *         within its container
+     *
+     * @see #setLayerGravity(int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public int getLayerGravity(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mGravity;
     }
 
     /**
@@ -454,13 +659,163 @@
      * @param t number of pixels to add to the top bound
      * @param r number of pixels to subtract from the right bound
      * @param b number of pixels to subtract from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
      */
     public void setLayerInset(int index, int l, int t, int r, int b) {
+        setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET);
+    }
+
+    /**
+     * Specifies the relative insets in pixels for the drawable at the
+     * specified index.
+     *
+     * @param index the index of the layer to adjust
+     * @param s number of pixels to inset from the start bound
+     * @param t number of pixels to inset from the top bound
+     * @param e number of pixels to inset from the end bound
+     * @param b number of pixels to inset from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public void setLayerInsetRelative(int index, int s, int t, int e, int b) {
+        setLayerInsetInternal(index, 0, t, 0, b, s, e);
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param l number of pixels to inset from the left bound
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     */
+    public void setLayerInsetLeft(int index, int l) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetL = l;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the left bound
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     */
+    public int getLayerInsetLeft(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetL;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param r number of pixels to inset from the right bound
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     */
+    public void setLayerInsetRight(int index, int r) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetR = r;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the right bound
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     */
+    public int getLayerInsetRight(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetR;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param t number of pixels to inset from the top bound
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     */
+    public void setLayerInsetTop(int index, int t) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetT = t;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the top bound
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     */
+    public int getLayerInsetTop(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetT;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param b number of pixels to inset from the bottom bound
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public void setLayerInsetBottom(int index, int b) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetB = b;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the bottom bound
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public int getLayerInsetBottom(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetB;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param s number of pixels to inset from the start bound
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     */
+    public void setLayerInsetStart(int index, int s) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetS = s;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the start bound
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     */
+    public int getLayerInsetStart(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetS;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param e number of pixels to inset from the end bound
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     */
+    public void setLayerInsetEnd(int index, int e) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetE = e;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the end bound
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     */
+    public int getLayerInsetEnd(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetE;
+    }
+
+    private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) {
         final ChildDrawable childDrawable = mLayerState.mChildren[index];
         childDrawable.mInsetL = l;
         childDrawable.mInsetT = t;
         childDrawable.mInsetR = r;
         childDrawable.mInsetB = b;
+        childDrawable.mInsetS = s;
+        childDrawable.mInsetE = e;
     }
 
     /**
@@ -616,7 +971,6 @@
         }
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         if (mHotspotBounds != null) {
@@ -648,6 +1002,18 @@
     }
 
     @Override
+    public boolean getDither() {
+        final ChildDrawable[] array = mLayerState.mChildren;
+        if (mLayerState.mNum > 0) {
+            // All layers should have the same dither set on them - just return
+            // the first one
+            return array[0].mDrawable.getDither();
+        } else {
+            return super.getDither();
+        }
+    }
+
+    @Override
     public void setAlpha(int alpha) {
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
@@ -669,11 +1035,11 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
+    public void setColorFilter(ColorFilter colorFilter) {
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setColorFilter(cf);
+            array[i].mDrawable.setColorFilter(colorFilter);
         }
     }
 
@@ -758,7 +1124,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -783,7 +1149,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -791,18 +1157,51 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
+        updateLayerBounds(bounds);
+    }
+
+    private void updateLayerBounds(Rect bounds) {
         int padL = 0;
         int padT = 0;
         int padR = 0;
         int padB = 0;
 
+        final Rect outRect = mTmpOutRect;
+        final int layoutDirection = getLayoutDirection();
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT,
-                    bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB);
+            final Drawable d = r.mDrawable;
+            final Rect container = mTmpContainer;
+            container.set(d.getBounds());
+
+            // Take the resolved layout direction into account. If start / end
+            // padding are defined, they will be resolved (hence overriding) to
+            // left / right or right / left depending on the resolved layout
+            // direction. If start / end padding are not defined, use the
+            // left / right ones.
+            final int insetL, insetR;
+            if (layoutDirection == LayoutDirection.RTL) {
+                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
+                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
+            } else {
+                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
+                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
+            }
+
+            // Establish containing region based on aggregate padding and
+            // requested insets for the current layer.
+            container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT,
+                    bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);
+
+            // Apply resolved gravity to drawable based on resolved size.
+            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight);
+            final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
+            final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
+            Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
+            d.setBounds(outRect);
 
             if (nest) {
                 padL += mPaddingL[i];
@@ -813,6 +1212,38 @@
         }
     }
 
+    /**
+     * Resolves layer gravity given explicit gravity and dimensions.
+     * <p>
+     * If the client hasn't specified a gravity but has specified an explicit
+     * dimension, defaults to START or TOP. Otherwise, defaults to FILL to
+     * preserve legacy behavior.
+     *
+     * @param gravity
+     * @param width
+     * @param height
+     * @return
+     */
+    private int resolveGravity(int gravity, int width, int height) {
+        if (!Gravity.isHorizontal(gravity)) {
+            if (width < 0) {
+                gravity |= Gravity.FILL_HORIZONTAL;
+            } else {
+                gravity |= Gravity.START;
+            }
+        }
+
+        if (!Gravity.isVertical(gravity)) {
+            if (height < 0) {
+                gravity |= Gravity.FILL_VERTICAL;
+            } else {
+                gravity |= Gravity.TOP;
+            }
+        }
+
+        return gravity;
+    }
+
     @Override
     public int getIntrinsicWidth() {
         int width = -1;
@@ -824,7 +1255,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR;
+            final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
+            final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR;
             if (w > width) {
                 width = w;
             }
@@ -849,7 +1281,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB;
+            final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
+            final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB;
             if (h > height) {
                 height = h;
             }
@@ -933,21 +1366,27 @@
         mMutated = false;
     }
 
-    /** @hide */
     @Override
-    public void setLayoutDirection(int layoutDirection) {
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        boolean changed = false;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setLayoutDirection(layoutDirection);
+            changed |= array[i].mDrawable.setLayoutDirection(layoutDirection);
         }
-        super.setLayoutDirection(layoutDirection);
+        updateLayerBounds(getBounds());
+        return changed;
     }
 
     static class ChildDrawable {
         public Drawable mDrawable;
         public int[] mThemeAttrs;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
+        public int mInsetS = UNDEFINED_INSET;
+        public int mInsetE = UNDEFINED_INSET;
+        public int mWidth = -1;
+        public int mHeight = -1;
+        public int mGravity = Gravity.NO_GRAVITY;
         public int mId = View.NO_ID;
 
         ChildDrawable() {
@@ -969,6 +1408,11 @@
             mInsetT = orig.mInsetT;
             mInsetR = orig.mInsetR;
             mInsetB = orig.mInsetB;
+            mInsetS = orig.mInsetS;
+            mInsetE = orig.mInsetE;
+            mWidth = orig.mWidth;
+            mHeight = orig.mHeight;
+            mGravity = orig.mGravity;
             mId = orig.mId;
         }
     }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index b87ae92..487162e 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -338,12 +338,12 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        if (mPaint == null && cf == null) {
+    public void setColorFilter(ColorFilter colorFilter) {
+        if (mPaint == null && colorFilter == null) {
             // Fast common case -- leave at no color filter.
             return;
         }
-        getPaint().setColorFilter(cf);
+        getPaint().setColorFilter(colorFilter);
         invalidateSelf();
     }
 
@@ -374,6 +374,11 @@
     }
 
     @Override
+    public boolean getDither() {
+        return mPaint == null ? DEFAULT_DITHER : mPaint.isDither();
+    }
+
+    @Override
     public void setAutoMirrored(boolean mirrored) {
         mNinePatchState.mAutoMirrored = mirrored;
     }
@@ -401,6 +406,8 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
+
+        updateLocalState(r);
     }
 
     /**
@@ -467,12 +474,6 @@
         if (tint != null) {
             state.mTint = tint;
         }
-
-        // Update local properties.
-        initializeWithState(state, r);
-
-        // Push density applied by setNinePatchState into state.
-        state.mTargetDensity = mTargetDensity;
     }
 
     @Override
@@ -480,23 +481,32 @@
         super.applyTheme(t);
 
         final NinePatchState state = mNinePatchState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
-        try {
-            updateStateFromTypedArray(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.NinePatchDrawable);
+            try {
+                updateStateFromTypedArray(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
         }
+
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
+        }
+
+        updateLocalState(t.getResources());
     }
 
     @Override
     public boolean canApplyTheme() {
-        return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
+        return mNinePatchState != null && mNinePatchState.canApplyTheme();
     }
 
     public Paint getPaint() {
@@ -645,7 +655,8 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            return mThemeAttrs != null
+                    || (mTint != null && mTint.canApplyTheme());
         }
 
         @Override
@@ -680,19 +691,25 @@
     private NinePatchDrawable(NinePatchState state, Resources res) {
         mNinePatchState = state;
 
-        initializeWithState(mNinePatchState, res);
+        updateLocalState(res);
+
+        // Push density applied by setNinePatchState into state.
+        mNinePatchState.mTargetDensity = mTargetDensity;
     }
 
     /**
      * Initializes local dynamic properties from state.
      */
-    private void initializeWithState(NinePatchState state, Resources res) {
+    private void updateLocalState(Resources res) {
+        final NinePatchState state = mNinePatchState;
+
         if (res != null) {
             mTargetDensity = res.getDisplayMetrics().densityDpi;
         } else {
             mTargetDensity = state.mTargetDensity;
         }
 
+
         // If we can, avoid calling any methods that initialize Paint.
         if (state.mDither != DEFAULT_DITHER) {
             setDither(state.mDither);
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index 6dcda1f..583cffb 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -88,12 +88,6 @@
     }
 
     @Override
-    public void setFilterBitmap(boolean filter) {}
-
-    @Override
-    public void setDither(boolean dither) {}
-
-    @Override
     public void setColorFilter(ColorFilter colorFilter) {}
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
deleted file mode 100644
index bb1d3cb..0000000
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.drawable;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.graphics.Canvas;
-import android.graphics.CanvasProperty;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.MathUtils;
-import android.view.HardwareCanvas;
-import android.view.RenderNodeAnimator;
-import android.view.animation.LinearInterpolator;
-
-import java.util.ArrayList;
-
-/**
- * Draws a Material ripple.
- */
-class Ripple {
-    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    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 = 3400.0f * GLOBAL_SPEED;
-    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
-
-    private static final long RIPPLE_ENTER_DELAY = 80;
-
-    // Hardware animators.
-    private final ArrayList<RenderNodeAnimator> mRunningAnimations =
-            new ArrayList<RenderNodeAnimator>();
-
-    private final RippleDrawable mOwner;
-
-    /** Bounds used for computing max radius. */
-    private final Rect mBounds;
-
-    /** Maximum ripple radius. */
-    private float mOuterRadius;
-
-    /** Screen density used to adjust pixel-based velocities. */
-    private float mDensity;
-
-    private float mStartingX;
-    private float mStartingY;
-    private float mClampedStartingX;
-    private float mClampedStartingY;
-
-    // Hardware rendering properties.
-    private CanvasProperty<Paint> mPropPaint;
-    private CanvasProperty<Float> mPropRadius;
-    private CanvasProperty<Float> mPropX;
-    private CanvasProperty<Float> mPropY;
-
-    // Software animators.
-    private ObjectAnimator mAnimRadius;
-    private ObjectAnimator mAnimOpacity;
-    private ObjectAnimator mAnimX;
-    private ObjectAnimator mAnimY;
-
-    // Temporary paint used for creating canvas properties.
-    private Paint mTempPaint;
-
-    // Software rendering properties.
-    private float mOpacity = 1;
-    private float mOuterX;
-    private float mOuterY;
-
-    // Values used to tween between the start and end positions.
-    private float mTweenRadius = 0;
-    private float mTweenX = 0;
-    private float mTweenY = 0;
-
-    /** Whether we should be drawing hardware animations. */
-    private boolean mHardwareAnimating;
-
-    /** Whether we can use hardware acceleration for the exit animation. */
-    private boolean mCanUseHardware;
-
-    /** Whether we have an explicit maximum radius. */
-    private boolean mHasMaxRadius;
-
-    /** Whether we were canceled externally and should avoid self-removal. */
-    private boolean mCanceled;
-
-    private boolean mHasPendingHardwareExit;
-    private int mPendingRadiusDuration;
-    private int mPendingOpacityDuration;
-
-    /**
-     * Creates a new ripple.
-     */
-    public Ripple(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
-        mOwner = owner;
-        mBounds = bounds;
-
-        mStartingX = startingX;
-        mStartingY = startingY;
-    }
-
-    public void setup(int maxRadius, float density) {
-        if (maxRadius != RippleDrawable.RADIUS_AUTO) {
-            mHasMaxRadius = true;
-            mOuterRadius = maxRadius;
-        } else {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-
-        mOuterX = 0;
-        mOuterY = 0;
-        mDensity = density;
-
-        clampStartingPosition();
-    }
-
-    public boolean isHardwareAnimating() {
-        return mHardwareAnimating;
-    }
-
-    private void clampStartingPosition() {
-        final float cX = mBounds.exactCenterX();
-        final float cY = mBounds.exactCenterY();
-        final float dX = mStartingX - cX;
-        final float dY = mStartingY - cY;
-        final float r = mOuterRadius;
-        if (dX * dX + dY * dY > r * r) {
-            // Point is outside the circle, clamp to the circumference.
-            final double angle = Math.atan2(dY, dX);
-            mClampedStartingX = cX + (float) (Math.cos(angle) * r);
-            mClampedStartingY = cY + (float) (Math.sin(angle) * r);
-        } else {
-            mClampedStartingX = mStartingX;
-            mClampedStartingY = mStartingY;
-        }
-    }
-
-    public void onHotspotBoundsChanged() {
-        if (!mHasMaxRadius) {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-
-            clampStartingPosition();
-        }
-    }
-
-    public void setOpacity(float a) {
-        mOpacity = a;
-        invalidateSelf();
-    }
-
-    public float getOpacity() {
-        return mOpacity;
-    }
-
-    @SuppressWarnings("unused")
-    public void setRadiusGravity(float r) {
-        mTweenRadius = r;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getRadiusGravity() {
-        return mTweenRadius;
-    }
-
-    @SuppressWarnings("unused")
-    public void setXGravity(float x) {
-        mTweenX = x;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getXGravity() {
-        return mTweenX;
-    }
-
-    @SuppressWarnings("unused")
-    public void setYGravity(float y) {
-        mTweenY = y;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getYGravity() {
-        return mTweenY;
-    }
-
-    /**
-     * Draws the ripple centered at (0,0) using the specified paint.
-     */
-    public boolean draw(Canvas c, Paint p) {
-        final boolean canUseHardware = c.isHardwareAccelerated();
-        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
-            // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations(true);
-        }
-        mCanUseHardware = canUseHardware;
-
-        final boolean hasContent;
-        if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) {
-            hasContent = drawHardware((HardwareCanvas) c, p);
-        } else {
-            hasContent = drawSoftware(c, p);
-        }
-
-        return hasContent;
-    }
-
-    private boolean drawHardware(HardwareCanvas c, Paint p) {
-        if (mHasPendingHardwareExit) {
-            cancelHardwareAnimations(false);
-            startPendingHardwareExit(c, p);
-        }
-
-        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
-
-        return true;
-    }
-
-    private boolean drawSoftware(Canvas c, Paint p) {
-        boolean hasContent = false;
-
-        final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
-        final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        if (alpha > 0 && radius > 0) {
-            final float x = MathUtils.lerp(
-                    mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-            final float y = MathUtils.lerp(
-                    mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-            p.setAlpha(alpha);
-            c.drawCircle(x, y, radius, p);
-            p.setAlpha(paintAlpha);
-            hasContent = true;
-        }
-
-        return hasContent;
-    }
-
-    /**
-     * Returns the maximum bounds of the ripple relative to the ripple center.
-     */
-    public void getBounds(Rect bounds) {
-        final int outerX = (int) mOuterX;
-        final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius + 1;
-        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
-    }
-
-    /**
-     * Specifies the starting position relative to the drawable bounds. No-op if
-     * the ripple has already entered.
-     */
-    public void move(float x, float y) {
-        mStartingX = x;
-        mStartingY = y;
-
-        clampStartingPosition();
-    }
-
-    /**
-     * Starts the enter animation.
-     */
-    public void enter() {
-        cancel();
-
-        final int radiusDuration = (int)
-                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
-
-        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
-        radius.setAutoCancel(true);
-        radius.setDuration(radiusDuration);
-        radius.setInterpolator(LINEAR_INTERPOLATOR);
-        radius.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        cX.setAutoCancel(true);
-        cX.setDuration(radiusDuration);
-        cX.setInterpolator(LINEAR_INTERPOLATOR);
-        cX.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        cY.setAutoCancel(true);
-        cY.setDuration(radiusDuration);
-        cY.setInterpolator(LINEAR_INTERPOLATOR);
-        cY.setStartDelay(RIPPLE_ENTER_DELAY);
-
-        mAnimRadius = radius;
-        mAnimX = cX;
-        mAnimY = cY;
-
-        // Enter animations always run on the UI thread, since it's unlikely
-        // that anything interesting is happening until the user lifts their
-        // finger.
-        radius.start();
-        cX.start();
-        cY.start();
-    }
-
-    /**
-     * Starts the exit animation.
-     */
-    public void exit() {
-        final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        final float remaining;
-        if (mAnimRadius != null && mAnimRadius.isRunning()) {
-            remaining = mOuterRadius - radius;
-        } else {
-            remaining = mOuterRadius;
-        }
-
-        cancel();
-
-        final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
-                + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
-        final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
-
-        if (mCanUseHardware) {
-            createPendingHardwareExit(radiusDuration, opacityDuration);
-        } else {
-            exitSoftware(radiusDuration, opacityDuration);
-        }
-    }
-
-    private void createPendingHardwareExit(int radiusDuration, int opacityDuration) {
-        mHasPendingHardwareExit = true;
-        mPendingRadiusDuration = radiusDuration;
-        mPendingOpacityDuration = opacityDuration;
-
-        // The animation will start on the next draw().
-        invalidateSelf();
-    }
-
-    private void startPendingHardwareExit(HardwareCanvas c, Paint p) {
-        mHasPendingHardwareExit = false;
-
-        final int radiusDuration = mPendingRadiusDuration;
-        final int opacityDuration = mPendingOpacityDuration;
-
-        final float startX = MathUtils.lerp(
-                mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
-        final float startY = MathUtils.lerp(
-                mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
-
-        final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
-        final Paint paint = getTempPaint(p);
-        paint.setAlpha((int) (paint.getAlpha() * mOpacity + 0.5f));
-        mPropPaint = CanvasProperty.createPaint(paint);
-        mPropRadius = CanvasProperty.createFloat(startRadius);
-        mPropX = CanvasProperty.createFloat(startX);
-        mPropY = CanvasProperty.createFloat(startY);
-
-        final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius);
-        radiusAnim.setDuration(radiusDuration);
-        radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
-        radiusAnim.setTarget(c);
-        radiusAnim.start();
-
-        final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX);
-        xAnim.setDuration(radiusDuration);
-        xAnim.setInterpolator(DECEL_INTERPOLATOR);
-        xAnim.setTarget(c);
-        xAnim.start();
-
-        final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY);
-        yAnim.setDuration(radiusDuration);
-        yAnim.setInterpolator(DECEL_INTERPOLATOR);
-        yAnim.setTarget(c);
-        yAnim.start();
-
-        final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint,
-                RenderNodeAnimator.PAINT_ALPHA, 0);
-        opacityAnim.setDuration(opacityDuration);
-        opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-        opacityAnim.addListener(mAnimationListener);
-        opacityAnim.setTarget(c);
-        opacityAnim.start();
-
-        mRunningAnimations.add(radiusAnim);
-        mRunningAnimations.add(opacityAnim);
-        mRunningAnimations.add(xAnim);
-        mRunningAnimations.add(yAnim);
-
-        mHardwareAnimating = true;
-
-        // Set up the software values to match the hardware end values.
-        mOpacity = 0;
-        mTweenX = 1;
-        mTweenY = 1;
-        mTweenRadius = 1;
-    }
-
-    /**
-     * Jump all animations to their end state. The caller is responsible for
-     * removing the ripple from the list of animating ripples.
-     */
-    public void jump() {
-        mCanceled = true;
-        endSoftwareAnimations();
-        cancelHardwareAnimations(true);
-        mCanceled = false;
-    }
-
-    private void endSoftwareAnimations() {
-        if (mAnimRadius != null) {
-            mAnimRadius.end();
-            mAnimRadius = null;
-        }
-
-        if (mAnimOpacity != null) {
-            mAnimOpacity.end();
-            mAnimOpacity = null;
-        }
-
-        if (mAnimX != null) {
-            mAnimX.end();
-            mAnimX = null;
-        }
-
-        if (mAnimY != null) {
-            mAnimY.end();
-            mAnimY = null;
-        }
-    }
-
-    private Paint getTempPaint(Paint original) {
-        if (mTempPaint == null) {
-            mTempPaint = new Paint();
-        }
-        mTempPaint.set(original);
-        return mTempPaint;
-    }
-
-    private void exitSoftware(int radiusDuration, int opacityDuration) {
-        final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
-        radiusAnim.setAutoCancel(true);
-        radiusAnim.setDuration(radiusDuration);
-        radiusAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1);
-        xAnim.setAutoCancel(true);
-        xAnim.setDuration(radiusDuration);
-        xAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1);
-        yAnim.setAutoCancel(true);
-        yAnim.setDuration(radiusDuration);
-        yAnim.setInterpolator(DECEL_INTERPOLATOR);
-
-        final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0);
-        opacityAnim.setAutoCancel(true);
-        opacityAnim.setDuration(opacityDuration);
-        opacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-        opacityAnim.addListener(mAnimationListener);
-
-        mAnimRadius = radiusAnim;
-        mAnimOpacity = opacityAnim;
-        mAnimX = xAnim;
-        mAnimY = yAnim;
-
-        radiusAnim.start();
-        opacityAnim.start();
-        xAnim.start();
-        yAnim.start();
-    }
-
-    /**
-     * Cancels all animations. The caller is responsible for removing
-     * the ripple from the list of animating ripples.
-     */
-    public void cancel() {
-        mCanceled = true;
-        cancelSoftwareAnimations();
-        cancelHardwareAnimations(false);
-        mCanceled = false;
-    }
-
-    private void cancelSoftwareAnimations() {
-        if (mAnimRadius != null) {
-            mAnimRadius.cancel();
-            mAnimRadius = null;
-        }
-
-        if (mAnimOpacity != null) {
-            mAnimOpacity.cancel();
-            mAnimOpacity = null;
-        }
-
-        if (mAnimX != null) {
-            mAnimX.cancel();
-            mAnimX = null;
-        }
-
-        if (mAnimY != null) {
-            mAnimY.cancel();
-            mAnimY = null;
-        }
-    }
-
-    /**
-     * Cancels any running hardware animations.
-     */
-    private void cancelHardwareAnimations(boolean jumpToEnd) {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            if (jumpToEnd) {
-                runningAnimations.get(i).end();
-            } else {
-                runningAnimations.get(i).cancel();
-            }
-        }
-        runningAnimations.clear();
-
-        if (mHasPendingHardwareExit) {
-            // If we had a pending hardware exit, jump to the end state.
-            mHasPendingHardwareExit = false;
-
-            if (jumpToEnd) {
-                mOpacity = 0;
-                mTweenX = 1;
-                mTweenY = 1;
-                mTweenRadius = 1;
-            }
-        }
-
-        mHardwareAnimating = false;
-    }
-
-    private void removeSelf() {
-        // The owner will invalidate itself.
-        if (!mCanceled) {
-            mOwner.removeRipple(this);
-        }
-    }
-
-    private void invalidateSelf() {
-        mOwner.invalidateSelf();
-    }
-
-    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            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/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index fae4902..6d1b1fe 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -17,433 +17,162 @@
 package android.graphics.drawable;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.util.MathUtils;
+import android.util.FloatProperty;
 import android.view.HardwareCanvas;
 import android.view.RenderNodeAnimator;
 import android.view.animation.LinearInterpolator;
 
-import java.util.ArrayList;
-
 /**
- * Draws a Material ripple.
+ * Draws a ripple background.
  */
-class RippleBackground {
+class RippleBackground extends RippleComponent {
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
 
-    private static final float GLOBAL_SPEED = 1.0f;
-    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
-    private static final float WAVE_OUTER_OPACITY_EXIT_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 int ENTER_DURATION = 667;
-    private static final int ENTER_DURATION_FAST = 100;
-
-    // Hardware animators.
-    private final ArrayList<RenderNodeAnimator> mRunningAnimations =
-            new ArrayList<RenderNodeAnimator>();
-
-    private final RippleDrawable mOwner;
-
-    /** Bounds used for computing max radius. */
-    private final Rect mBounds;
-
-    /** ARGB color for drawing this ripple. */
-    private int mColor;
-
-    /** Maximum ripple radius. */
-    private float mOuterRadius;
-
-    /** Screen density used to adjust pixel-based velocities. */
-    private float mDensity;
+    private static final int OPACITY_ENTER_DURATION = 600;
+    private static final int OPACITY_ENTER_DURATION_FAST = 120;
+    private static final int OPACITY_EXIT_DURATION = 480;
 
     // Hardware rendering properties.
-    private CanvasProperty<Paint> mPropOuterPaint;
-    private CanvasProperty<Float> mPropOuterRadius;
-    private CanvasProperty<Float> mPropOuterX;
-    private CanvasProperty<Float> mPropOuterY;
-
-    // Software animators.
-    private ObjectAnimator mAnimOuterOpacity;
-
-    // Temporary paint used for creating canvas properties.
-    private Paint mTempPaint;
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
 
     // Software rendering properties.
-    private float mOuterOpacity = 0;
-    private float mOuterX;
-    private float mOuterY;
+    private float mOpacity = 0;
 
-    /** Whether we should be drawing hardware animations. */
-    private boolean mHardwareAnimating;
-
-    /** Whether we can use hardware acceleration for the exit animation. */
-    private boolean mCanUseHardware;
-
-    /** Whether we have an explicit maximum radius. */
-    private boolean mHasMaxRadius;
-
-    private boolean mHasPendingHardwareExit;
-    private int mPendingOpacityDuration;
-    private int mPendingInflectionDuration;
-    private int mPendingInflectionOpacity;
-
-    /**
-     * Creates a new ripple.
-     */
     public RippleBackground(RippleDrawable owner, Rect bounds) {
-        mOwner = owner;
-        mBounds = bounds;
+        super(owner, bounds);
     }
 
-    public void setup(int maxRadius, float density) {
-        if (maxRadius != RippleDrawable.RADIUS_AUTO) {
-            mHasMaxRadius = true;
-            mOuterRadius = maxRadius;
-        } else {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-
-        mOuterX = 0;
-        mOuterY = 0;
-        mDensity = density;
+    public boolean isVisible() {
+        return mOpacity > 0 || isHardwareAnimating();
     }
 
-    public void onHotspotBoundsChanged() {
-        if (!mHasMaxRadius) {
-            final float halfWidth = mBounds.width() / 2.0f;
-            final float halfHeight = mBounds.height() / 2.0f;
-            mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public void setOuterOpacity(float a) {
-        mOuterOpacity = a;
-        invalidateSelf();
-    }
-
-    @SuppressWarnings("unused")
-    public float getOuterOpacity() {
-        return mOuterOpacity;
-    }
-
-    /**
-     * Draws the ripple centered at (0,0) using the specified paint.
-     */
-    public boolean draw(Canvas c, Paint p) {
-        mColor = p.getColor();
-
-        final boolean canUseHardware = c.isHardwareAccelerated();
-        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
-            // We've switched from hardware to non-hardware mode. Panic.
-            cancelHardwareAnimations(true);
-        }
-        mCanUseHardware = canUseHardware;
-
-        final boolean hasContent;
-        if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) {
-            hasContent = drawHardware((HardwareCanvas) c, p);
-        } else {
-            hasContent = drawSoftware(c, p);
-        }
-
-        return hasContent;
-    }
-
-    public boolean shouldDraw() {
-        return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0);
-    }
-
-    private boolean drawHardware(HardwareCanvas c, Paint p) {
-        if (mHasPendingHardwareExit) {
-            cancelHardwareAnimations(false);
-            startPendingHardwareExit(c, p);
-        }
-
-        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
-
-        return true;
-    }
-
-    private boolean drawSoftware(Canvas c, Paint p) {
+    @Override
+    protected boolean drawSoftware(Canvas c, Paint p) {
         boolean hasContent = false;
 
-        final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
-        final float radius = mOuterRadius;
-        if (alpha > 0 && radius > 0) {
+        final int origAlpha = p.getAlpha();
+        final int alpha = (int) (origAlpha * mOpacity + 0.5f);
+        if (alpha > 0) {
             p.setAlpha(alpha);
-            c.drawCircle(mOuterX, mOuterY, radius, p);
-            p.setAlpha(paintAlpha);
+            c.drawCircle(0, 0, mTargetRadius, p);
+            p.setAlpha(origAlpha);
             hasContent = true;
         }
 
         return hasContent;
     }
 
-    /**
-     * Returns the maximum bounds of the ripple relative to the ripple center.
-     */
-    public void getBounds(Rect bounds) {
-        final int outerX = (int) mOuterX;
-        final int outerY = (int) mOuterY;
-        final int r = (int) mOuterRadius + 1;
-        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+    @Override
+    protected boolean drawHardware(HardwareCanvas c) {
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+        return true;
     }
 
-    /**
-     * Starts the enter animation.
-     */
-    public void enter(boolean fast) {
-        cancel();
+    @Override
+    protected Animator createSoftwareEnter(boolean fast) {
+        // Linear enter based on current opacity.
+        final int maxDuration = fast ? OPACITY_ENTER_DURATION_FAST : OPACITY_ENTER_DURATION;
+        final int duration = (int) ((1 - mOpacity) * maxDuration);
 
-        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
         opacity.setAutoCancel(true);
-        opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION);
+        opacity.setDuration(duration);
         opacity.setInterpolator(LINEAR_INTERPOLATOR);
 
-        mAnimOuterOpacity = opacity;
-
-        // Enter animations always run on the UI thread, since it's unlikely
-        // that anything interesting is happening until the user lifts their
-        // finger.
-        opacity.start();
+        return opacity;
     }
 
-    /**
-     * Starts the exit animation.
-     */
-    public void exit() {
-        cancel();
+    @Override
+    protected Animator createSoftwareExit() {
+        final AnimatorSet set = new AnimatorSet();
 
-        // Scale the outer max opacity and opacity velocity based
-        // on the size of the outer radius.
-        final int opacityDuration = (int) (1000 / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
-        final float outerSizeInfluence = MathUtils.constrain(
-                (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
-                / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
-        final float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN,
-                WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX, outerSizeInfluence);
+        // Linear exit after enter is completed.
+        final ObjectAnimator exit = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 0);
+        exit.setInterpolator(LINEAR_INTERPOLATOR);
+        exit.setDuration(OPACITY_EXIT_DURATION);
+        exit.setAutoCancel(true);
 
-        // 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 inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
-                / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
-        final int inflectionOpacity = (int) (Color.alpha(mColor) * (mOuterOpacity
-                + inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
+        final AnimatorSet.Builder builder = set.play(exit);
 
-        if (mCanUseHardware) {
-            createPendingHardwareExit(opacityDuration, inflectionDuration, inflectionOpacity);
-        } else {
-            exitSoftware(opacityDuration, inflectionDuration, inflectionOpacity);
+        // Linear "fast" enter based on current opacity.
+        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        if (fastEnterDuration > 0) {
+            final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1);
+            enter.setInterpolator(LINEAR_INTERPOLATOR);
+            enter.setDuration(fastEnterDuration);
+            enter.setAutoCancel(true);
+
+            builder.after(enter);
+        }
+
+        return set;
+    }
+
+    @Override
+    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
+        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
+
+        final int targetAlpha = p.getAlpha();
+        final int currentAlpha = (int) (mOpacity * targetAlpha + 0.5f);
+        p.setAlpha(currentAlpha);
+
+        mPropPaint = CanvasProperty.createPaint(p);
+        mPropRadius = CanvasProperty.createFloat(mTargetRadius);
+        mPropX = CanvasProperty.createFloat(0);
+        mPropY = CanvasProperty.createFloat(0);
+
+        // Linear "fast" enter based on current opacity.
+        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        if (fastEnterDuration > 0) {
+            final RenderNodeAnimator enter = new RenderNodeAnimator(
+                    mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
+            enter.setInterpolator(LINEAR_INTERPOLATOR);
+            enter.setDuration(fastEnterDuration);
+            set.add(enter);
+        }
+
+        // Linear exit after enter is completed.
+        final RenderNodeAnimator exit = new RenderNodeAnimator(
+                mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+        exit.setInterpolator(LINEAR_INTERPOLATOR);
+        exit.setDuration(OPACITY_EXIT_DURATION);
+        exit.setStartDelay(fastEnterDuration);
+        set.add(exit);
+
+        return set;
+    }
+
+    @Override
+    protected void jumpValuesToExit() {
+        mOpacity = 0;
+    }
+
+    private static abstract class BackgroundProperty extends FloatProperty<RippleBackground> {
+        public BackgroundProperty(String name) {
+            super(name);
         }
     }
 
-    private void createPendingHardwareExit(
-            int opacityDuration, int inflectionDuration, int inflectionOpacity) {
-        mHasPendingHardwareExit = true;
-        mPendingOpacityDuration = opacityDuration;
-        mPendingInflectionDuration = inflectionDuration;
-        mPendingInflectionOpacity = inflectionOpacity;
-
-        // The animation will start on the next draw().
-        invalidateSelf();
-    }
-
-    private void startPendingHardwareExit(HardwareCanvas c, Paint p) {
-        mHasPendingHardwareExit = false;
-
-        final int opacityDuration = mPendingOpacityDuration;
-        final int inflectionDuration = mPendingInflectionDuration;
-        final int inflectionOpacity = mPendingInflectionOpacity;
-
-        final Paint outerPaint = getTempPaint(p);
-        outerPaint.setAlpha((int) (outerPaint.getAlpha() * mOuterOpacity + 0.5f));
-        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
-        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
-        mPropOuterX = CanvasProperty.createFloat(mOuterX);
-        mPropOuterY = CanvasProperty.createFloat(mOuterY);
-
-        final RenderNodeAnimator outerOpacityAnim;
-        if (inflectionDuration > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = new RenderNodeAnimator(mPropOuterPaint,
-                    RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
-            outerOpacityAnim.setDuration(inflectionDuration);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - inflectionDuration;
-            if (outerDuration > 0) {
-                final RenderNodeAnimator outerFadeOutAnim = new RenderNodeAnimator(
-                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-                outerFadeOutAnim.setDuration(outerDuration);
-                outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                outerFadeOutAnim.setStartDelay(inflectionDuration);
-                outerFadeOutAnim.setStartValue(inflectionOpacity);
-                outerFadeOutAnim.addListener(mAnimationListener);
-                outerFadeOutAnim.setTarget(c);
-                outerFadeOutAnim.start();
-
-                mRunningAnimations.add(outerFadeOutAnim);
-            } else {
-                outerOpacityAnim.addListener(mAnimationListener);
-            }
-        } else {
-            outerOpacityAnim = new RenderNodeAnimator(
-                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-            outerOpacityAnim.setDuration(opacityDuration);
-            outerOpacityAnim.addListener(mAnimationListener);
-        }
-
-        outerOpacityAnim.setTarget(c);
-        outerOpacityAnim.start();
-
-        mRunningAnimations.add(outerOpacityAnim);
-
-        mHardwareAnimating = true;
-
-        // Set up the software values to match the hardware end values.
-        mOuterOpacity = 0;
-    }
-
-    /**
-     * Jump all animations to their end state. The caller is responsible for
-     * removing the ripple from the list of animating ripples.
-     */
-    public void jump() {
-        endSoftwareAnimations();
-        cancelHardwareAnimations(true);
-    }
-
-    private void endSoftwareAnimations() {
-        if (mAnimOuterOpacity != null) {
-            mAnimOuterOpacity.end();
-            mAnimOuterOpacity = null;
-        }
-    }
-
-    private Paint getTempPaint(Paint original) {
-        if (mTempPaint == null) {
-            mTempPaint = new Paint();
-        }
-        mTempPaint.set(original);
-        return mTempPaint;
-    }
-
-    private void exitSoftware(int opacityDuration, int inflectionDuration, int inflectionOpacity) {
-        final ObjectAnimator outerOpacityAnim;
-        if (inflectionDuration > 0) {
-            // Outer opacity continues to increase for a bit.
-            outerOpacityAnim = ObjectAnimator.ofFloat(this,
-                    "outerOpacity", inflectionOpacity / 255.0f);
-            outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(inflectionDuration);
-            outerOpacityAnim.setInterpolator(LINEAR_INTERPOLATOR);
-
-            // Chain the outer opacity exit animation.
-            final int outerDuration = opacityDuration - inflectionDuration;
-            if (outerDuration > 0) {
-                outerOpacityAnim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        final ObjectAnimator outerFadeOutAnim = ObjectAnimator.ofFloat(
-                                RippleBackground.this, "outerOpacity", 0);
-                        outerFadeOutAnim.setAutoCancel(true);
-                        outerFadeOutAnim.setDuration(outerDuration);
-                        outerFadeOutAnim.setInterpolator(LINEAR_INTERPOLATOR);
-                        outerFadeOutAnim.addListener(mAnimationListener);
-
-                        mAnimOuterOpacity = outerFadeOutAnim;
-
-                        outerFadeOutAnim.start();
-                    }
-
-                    @Override
-                    public void onAnimationCancel(Animator animation) {
-                        animation.removeListener(this);
-                    }
-                });
-            } else {
-                outerOpacityAnim.addListener(mAnimationListener);
-            }
-        } else {
-            outerOpacityAnim = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
-            outerOpacityAnim.setAutoCancel(true);
-            outerOpacityAnim.setDuration(opacityDuration);
-            outerOpacityAnim.addListener(mAnimationListener);
-        }
-
-        mAnimOuterOpacity = outerOpacityAnim;
-
-        outerOpacityAnim.start();
-    }
-
-    /**
-     * Cancel all animations. The caller is responsible for removing
-     * the ripple from the list of animating ripples.
-     */
-    public void cancel() {
-        cancelSoftwareAnimations();
-        cancelHardwareAnimations(false);
-    }
-
-    private void cancelSoftwareAnimations() {
-        if (mAnimOuterOpacity != null) {
-            mAnimOuterOpacity.cancel();
-            mAnimOuterOpacity = null;
-        }
-    }
-
-    /**
-     * Cancels any running hardware animations.
-     */
-    private void cancelHardwareAnimations(boolean jumpToEnd) {
-        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
-        final int N = runningAnimations.size();
-        for (int i = 0; i < N; i++) {
-            if (jumpToEnd) {
-                runningAnimations.get(i).end();
-            } else {
-                runningAnimations.get(i).cancel();
-            }
-        }
-        runningAnimations.clear();
-
-        if (mHasPendingHardwareExit) {
-            // If we had a pending hardware exit, jump to the end state.
-            mHasPendingHardwareExit = false;
-
-            if (jumpToEnd) {
-                mOuterOpacity = 0;
-            }
-        }
-
-        mHardwareAnimating = false;
-    }
-
-    private void invalidateSelf() {
-        mOwner.invalidateSelf();
-    }
-
-    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
+    private static final BackgroundProperty OPACITY = new BackgroundProperty("opacity") {
         @Override
-        public void onAnimationEnd(Animator animation) {
-            mHardwareAnimating = false;
+        public void setValue(RippleBackground object, float value) {
+            object.mOpacity = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleBackground object) {
+            return object.mOpacity;
         }
     };
 }
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
new file mode 100644
index 0000000..79407f7
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.animation.Animator;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+
+import java.util.ArrayList;
+
+/**
+ * Abstract class that handles hardware/software hand-off and lifecycle for
+ * animated ripple foreground and background components.
+ */
+abstract class RippleComponent {
+    private final RippleDrawable mOwner;
+
+    /** Bounds used for computing max radius. May be modified by the owner. */
+    protected final Rect mBounds;
+
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mHasHardwareCanvas;
+
+    private boolean mHasPendingHardwareAnimator;
+    private RenderNodeAnimatorSet mHardwareAnimator;
+
+    private Animator mSoftwareAnimator;
+
+    /** Whether we have an explicit maximum radius. */
+    private boolean mHasMaxRadius;
+
+    /** How big this ripple should be when fully entered. */
+    protected float mTargetRadius;
+
+    /** Screen density used to adjust pixel-based constants. */
+    protected float mDensity;
+
+    public RippleComponent(RippleDrawable owner, Rect bounds) {
+        mOwner = owner;
+        mBounds = bounds;
+    }
+
+    public final void setup(float maxRadius, float density) {
+        if (maxRadius >= 0) {
+            mHasMaxRadius = true;
+            mTargetRadius = maxRadius;
+        } else {
+            final float halfWidth = mBounds.width() / 2.0f;
+            final float halfHeight = mBounds.height() / 2.0f;
+            mTargetRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+        }
+
+        mDensity = density;
+
+        onTargetRadiusChanged(mTargetRadius);
+    }
+
+    /**
+     * Starts a ripple enter animation.
+     *
+     * @param fast whether the ripple should enter quickly
+     */
+    public final void enter(boolean fast) {
+        cancel();
+
+        mSoftwareAnimator = createSoftwareEnter(fast);
+
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.start();
+        }
+    }
+
+    /**
+     * Starts a ripple exit animation.
+     */
+    public final void exit() {
+        cancel();
+
+        if (mHasHardwareCanvas) {
+            // We don't have access to a canvas here, but we expect one on the
+            // next frame. We'll start the render thread animation then.
+            mHasPendingHardwareAnimator = true;
+
+            // Request another frame.
+            invalidateSelf();
+        } else {
+            mSoftwareAnimator = createSoftwareExit();
+            mSoftwareAnimator.start();
+        }
+    }
+
+    /**
+     * Cancels all animations. Software animation values are left in the
+     * current state, while hardware animation values jump to the end state.
+     */
+    public void cancel() {
+        cancelSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    /**
+     * Ends all animations, jumping values to the end state.
+     */
+    public void end() {
+        endSoftwareAnimations();
+        endHardwareAnimations();
+    }
+
+    /**
+     * Draws the ripple to the canvas, inheriting the paint's color and alpha
+     * properties.
+     *
+     * @param c the canvas to which the ripple should be drawn
+     * @param p the paint used to draw the ripple
+     * @return {@code true} if something was drawn, {@code false} otherwise
+     */
+    public boolean draw(Canvas c, Paint p) {
+        final boolean hasHardwareCanvas = c.isHardwareAccelerated()
+                && c instanceof HardwareCanvas;
+        if (mHasHardwareCanvas != hasHardwareCanvas) {
+            mHasHardwareCanvas = hasHardwareCanvas;
+
+            if (!hasHardwareCanvas) {
+                // We've switched from hardware to non-hardware mode. Panic.
+                endHardwareAnimations();
+            }
+        }
+
+        if (hasHardwareCanvas) {
+            final HardwareCanvas hw = (HardwareCanvas) c;
+            startPendingAnimation(hw, p);
+
+            if (mHardwareAnimator != null) {
+                return drawHardware(hw);
+            }
+        }
+
+        return drawSoftware(c, p);
+    }
+
+    /**
+     * Populates {@code bounds} with the maximum drawing bounds of the ripple
+     * relative to its center. The resulting bounds should be translated into
+     * parent drawable coordinates before use.
+     *
+     * @param bounds the rect to populate with drawing bounds
+     */
+    public void getBounds(Rect bounds) {
+        final int r = (int) Math.ceil(mTargetRadius);
+        bounds.set(-r, -r, r, r);
+    }
+
+    /**
+     * Starts the pending hardware animation, if available.
+     *
+     * @param hw hardware canvas on which the animation should draw
+     * @param p paint whose properties the hardware canvas should use
+     */
+    private void startPendingAnimation(HardwareCanvas hw, Paint p) {
+        if (mHasPendingHardwareAnimator) {
+            mHasPendingHardwareAnimator = false;
+
+            mHardwareAnimator = createHardwareExit(new Paint(p));
+            mHardwareAnimator.start(hw);
+
+            // Preemptively jump the software values to the end state now that
+            // the hardware exit has read whatever values it needs.
+            jumpValuesToExit();
+        }
+    }
+
+    /**
+     * Cancels any current software animations, leaving the values in their
+     * current state.
+     */
+    private void cancelSoftwareAnimations() {
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.cancel();
+        }
+    }
+
+    /**
+     * Ends any current software animations, jumping the values to their end
+     * state.
+     */
+    private void endSoftwareAnimations() {
+        if (mSoftwareAnimator != null) {
+            mSoftwareAnimator.end();
+        }
+    }
+
+    /**
+     * Ends any pending or current hardware animations.
+     * <p>
+     * Hardware animations can't synchronize values back to the software
+     * thread, so there is no "cancel" equivalent.
+     */
+    private void endHardwareAnimations() {
+        if (mHardwareAnimator != null) {
+            mHardwareAnimator.end();
+            mHardwareAnimator = null;
+        }
+
+        if (mHasPendingHardwareAnimator) {
+            mHasPendingHardwareAnimator = false;
+        }
+    }
+
+    protected final void invalidateSelf() {
+        mOwner.invalidateSelf();
+    }
+
+    protected final boolean isHardwareAnimating() {
+        return mHardwareAnimator != null && mHardwareAnimator.isRunning()
+                || mHasPendingHardwareAnimator;
+    }
+
+    protected final void onHotspotBoundsChanged() {
+        if (!mHasMaxRadius) {
+            final float halfWidth = mBounds.width() / 2.0f;
+            final float halfHeight = mBounds.height() / 2.0f;
+            final float targetRadius = (float) Math.sqrt(halfWidth * halfWidth
+                    + halfHeight * halfHeight);
+
+            onTargetRadiusChanged(targetRadius);
+        }
+    }
+
+    /**
+     * Called when the target radius changes.
+     *
+     * @param targetRadius the new target radius
+     */
+    protected void onTargetRadiusChanged(float targetRadius) {
+        // Stub.
+    }
+
+    protected abstract Animator createSoftwareEnter(boolean fast);
+
+    protected abstract Animator createSoftwareExit();
+
+    protected abstract RenderNodeAnimatorSet createHardwareExit(Paint p);
+
+    protected abstract boolean drawHardware(HardwareCanvas c);
+
+    protected abstract boolean drawSoftware(Canvas c, Paint p);
+
+    /**
+     * Called when the hardware exit is cancelled. Jumps software values to end
+     * state to ensure that software and hardware values are synchronized.
+     */
+    protected abstract void jumpValuesToExit();
+
+    public static class RenderNodeAnimatorSet {
+        private final ArrayList<RenderNodeAnimator> mAnimators = new ArrayList<>();
+
+        public void add(RenderNodeAnimator anim) {
+            mAnimators.add(anim);
+        }
+
+        public void clear() {
+            mAnimators.clear();
+        }
+
+        public void start(HardwareCanvas target) {
+            if (target == null) {
+                throw new IllegalArgumentException("Hardware canvas must be non-null");
+            }
+
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.setTarget(target);
+                anim.start();
+            }
+        }
+
+        public void cancel() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.cancel();
+            }
+        }
+
+        public void end() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                anim.end();
+            }
+        }
+
+        public boolean isRunning() {
+            final ArrayList<RenderNodeAnimator> animators = mAnimators;
+            final int N = animators.size();
+            for (int i = 0; i < N; i++) {
+                final RenderNodeAnimator anim = animators.get(i);
+                if (anim.isRunning()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 1263447..66160c0 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -92,19 +92,17 @@
  * @attr ref android.R.styleable#RippleDrawable_color
  */
 public class RippleDrawable extends LayerDrawable {
+    /**
+     * Radius value that specifies the ripple radius should be computed based
+     * on the size of the ripple's container.
+     */
+    public static final int RADIUS_AUTO = -1;
+
     private static final int MASK_UNKNOWN = -1;
     private static final int MASK_NONE = 0;
     private static final int MASK_CONTENT = 1;
     private static final int MASK_EXPLICIT = 2;
 
-    /**
-     * Constant for automatically determining the maximum ripple radius.
-     *
-     * @see #setMaxRadius(int)
-     * @hide
-     */
-    public static final int RADIUS_AUTO = -1;
-
     /** The maximum number of ripples supported. */
     private static final int MAX_RIPPLES = 10;
 
@@ -139,7 +137,7 @@
     private boolean mBackgroundActive;
 
     /** The current ripple. May be actively animating or pending entry. */
-    private Ripple mRipple;
+    private RippleForeground mRipple;
 
     /** Whether we expect to draw a ripple when visible. */
     private boolean mRippleActive;
@@ -153,7 +151,7 @@
      * Lazily-created array of actively animating ripples. Inactive ripples are
      * pruned during draw(). The locations of these will not change.
      */
-    private Ripple[] mExitingRipples;
+    private RippleForeground[] mExitingRipples;
     private int mExitingRipplesCount = 0;
 
     /** Paint used to control appearance of ripples. */
@@ -198,7 +196,7 @@
 
         setColor(color);
         ensurePadding();
-        initializeFromState();
+        updateLocalState();
     }
 
     @Override
@@ -206,11 +204,11 @@
         super.jumpToCurrentState();
 
         if (mRipple != null) {
-            mRipple.jump();
+            mRipple.end();
         }
 
         if (mBackground != null) {
-            mBackground.jump();
+            mBackground.end();
         }
 
         cancelExitingRipples();
@@ -221,10 +219,13 @@
         boolean needsDraw = false;
 
         final int count = mExitingRipplesCount;
-        final Ripple[] ripples = mExitingRipples;
+        final RippleForeground[] ripples = mExitingRipples;
         for (int i = 0; i < count; i++) {
+            // If the ripple is animating on the hardware thread, we'll need to
+            // draw an additional frame after canceling to restore the software
+            // drawing path.
             needsDraw |= ripples[i].isHardwareAnimating();
-            ripples[i].cancel();
+            ripples[i].end();
         }
 
         if (ripples != null) {
@@ -243,8 +244,8 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        super.setColorFilter(cf);
+    public void setColorFilter(ColorFilter colorFilter) {
+        super.setColorFilter(colorFilter);
 
         // TODO: Should we support this?
     }
@@ -266,11 +267,9 @@
         for (int state : stateSet) {
             if (state == R.attr.state_enabled) {
                 enabled = true;
-            }
-            if (state == R.attr.state_focused) {
+            } else if (state == R.attr.state_focused) {
                 focused = true;
-            }
-            if (state == R.attr.state_pressed) {
+            } else if (state == R.attr.state_pressed) {
                 pressed = true;
             }
         }
@@ -352,11 +351,40 @@
         return true;
     }
 
+    /**
+     * Sets the ripple color.
+     *
+     * @param color Ripple color as a color state list.
+     *
+     * @attr ref android.R.styleable#RippleDrawable_color
+     */
     public void setColor(ColorStateList color) {
         mState.mColor = color;
         invalidateSelf();
     }
 
+    /**
+     * Sets the radius in pixels of the fully expanded ripple.
+     *
+     * @param radius ripple radius in pixels, or {@link #RADIUS_AUTO} to
+     *               compute the radius based on the container size
+     * @attr ref android.R.styleable#RippleDrawable_radius
+     */
+    public void setRadius(int radius) {
+        mState.mMaxRadius = radius;
+        invalidateSelf();
+    }
+
+    /**
+     * @return the radius in pixels of the fully expanded ripple if an explicit
+     *         radius has been set, or {@link #RADIUS_AUTO} if the radius is
+     *         computed based on the container size
+     * @attr ref android.R.styleable#RippleDrawable_radius
+     */
+    public int getRadius() {
+        return mState.mMaxRadius;
+    }
+
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
@@ -370,7 +398,8 @@
         super.inflate(r, parser, attrs, theme);
 
         setTargetDensity(r.getDisplayMetrics());
-        initializeFromState();
+
+        updateLocalState();
     }
 
     @Override
@@ -422,6 +451,9 @@
             mState.mColor = color;
         }
 
+        mState.mMaxRadius = a.getDimensionPixelSize(
+                R.styleable.RippleDrawable_radius, mState.mMaxRadius);
+
         verifyRequiredAttributes(a);
     }
 
@@ -450,21 +482,27 @@
         super.applyTheme(t);
 
         final RippleState state = mState;
-        if (state == null || state.mTouchThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
-                R.styleable.RippleDrawable);
-        try {
-            updateStateFromTypedArray(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mTouchThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
+                    R.styleable.RippleDrawable);
+            try {
+                updateStateFromTypedArray(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
         }
 
-        initializeFromState();
+        if (state.mColor != null && state.mColor.canApplyTheme()) {
+            state.mColor.applyTheme(t);
+        }
+
+        updateLocalState();
     }
 
     @Override
@@ -526,11 +564,13 @@
                 x = mHotspotBounds.exactCenterX();
                 y = mHotspotBounds.exactCenterY();
             }
-            mRipple = new Ripple(this, mHotspotBounds, x, y);
+
+            final boolean isBounded = !isProjected();
+            mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded);
         }
 
         mRipple.setup(mState.mMaxRadius, mDensity);
-        mRipple.enter();
+        mRipple.enter(false);
     }
 
     /**
@@ -540,7 +580,7 @@
     private void tryRippleExit() {
         if (mRipple != null) {
             if (mExitingRipples == null) {
-                mExitingRipples = new Ripple[MAX_RIPPLES];
+                mExitingRipples = new RippleForeground[MAX_RIPPLES];
             }
             mExitingRipples[mExitingRipplesCount++] = mRipple;
             mRipple.exit();
@@ -554,13 +594,13 @@
      */
     private void clearHotspots() {
         if (mRipple != null) {
-            mRipple.cancel();
+            mRipple.end();
             mRipple = null;
             mRippleActive = false;
         }
 
         if (mBackground != null) {
-            mBackground.cancel();
+            mBackground.end();
             mBackground = null;
             mBackgroundActive = false;
         }
@@ -577,7 +617,6 @@
         onHotspotBoundsChanged();
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         outRect.set(mHotspotBounds);
@@ -588,7 +627,7 @@
      */
     private void onHotspotBoundsChanged() {
         final int count = mExitingRipplesCount;
-        final Ripple[] ripples = mExitingRipples;
+        final RippleForeground[] ripples = mExitingRipples;
         for (int i = 0; i < count; i++) {
             ripples[i].onHotspotBoundsChanged();
         }
@@ -626,6 +665,8 @@
      */
     @Override
     public void draw(@NonNull Canvas canvas) {
+        pruneRipples();
+
         // Clip to the dirty bounds, which will be the drawable bounds if we
         // have a mask or content and the ripple bounds if we're projecting.
         final Rect bounds = getDirtyBounds();
@@ -646,6 +687,26 @@
         mHasValidMask = false;
     }
 
+    private void pruneRipples() {
+        int remaining = 0;
+
+        // Move remaining entries into pruned spaces.
+        final RippleForeground[] ripples = mExitingRipples;
+        final int count = mExitingRipplesCount;
+        for (int i = 0; i < count; i++) {
+            if (!ripples[i].hasFinishedExit()) {
+                ripples[remaining++] = ripples[i];
+            }
+        }
+
+        // Null out the remaining entries.
+        for (int i = remaining; i < count; i++) {
+            ripples[i] = null;
+        }
+
+        mExitingRipplesCount = remaining;
+    }
+
     /**
      * @return whether we need to use a mask
      */
@@ -711,7 +772,7 @@
 
     private int getMaskType() {
         if (mRipple == null && mExitingRipplesCount <= 0
-                && (mBackground == null || !mBackground.shouldDraw())) {
+                && (mBackground == null || !mBackground.isVisible())) {
             // We might need a mask later.
             return MASK_UNKNOWN;
         }
@@ -738,36 +799,6 @@
         return MASK_NONE;
     }
 
-    /**
-     * Removes a ripple from the exiting ripple list.
-     *
-     * @param ripple the ripple to remove
-     */
-    void removeRipple(Ripple ripple) {
-        // Ripple ripple ripple ripple. Ripple ripple.
-        final Ripple[] ripples = mExitingRipples;
-        final int count = mExitingRipplesCount;
-        final int index = getRippleIndex(ripple);
-        if (index >= 0) {
-            System.arraycopy(ripples, index + 1, ripples, index, count - (index + 1));
-            ripples[count - 1] = null;
-            mExitingRipplesCount--;
-
-            invalidateSelf();
-        }
-    }
-
-    private int getRippleIndex(Ripple ripple) {
-        final Ripple[] ripples = mExitingRipples;
-        final int count = mExitingRipplesCount;
-        for (int i = 0; i < count; i++) {
-            if (ripples[i] == ripple) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
     private void drawContent(Canvas canvas) {
         // Draw everything except the mask.
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -780,10 +811,10 @@
     }
 
     private void drawBackgroundAndRipples(Canvas canvas) {
-        final Ripple active = mRipple;
+        final RippleForeground active = mRipple;
         final RippleBackground background = mBackground;
         final int count = mExitingRipplesCount;
-        if (active == null && count <= 0 && (background == null || !background.shouldDraw())) {
+        if (active == null && count <= 0 && (background == null || !background.isVisible())) {
             // Move along, nothing to draw here.
             return;
         }
@@ -823,12 +854,12 @@
             p.setShader(null);
         }
 
-        if (background != null && background.shouldDraw()) {
+        if (background != null && background.isVisible()) {
             background.draw(canvas, p);
         }
 
         if (count > 0) {
-            final Ripple[] ripples = mExitingRipples;
+            final RippleForeground[] ripples = mExitingRipples;
             for (int i = 0; i < count; i++) {
                 ripples[i].draw(canvas, p);
             }
@@ -866,7 +897,7 @@
             final int cY = (int) mHotspotBounds.exactCenterY();
             final Rect rippleBounds = mTempRect;
 
-            final Ripple[] activeRipples = mExitingRipples;
+            final RippleForeground[] activeRipples = mExitingRipples;
             final int N = mExitingRipplesCount;
             for (int i = 0; i < N; i++) {
                 activeRipples[i].getBounds(rippleBounds);
@@ -931,7 +962,9 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mTouchThemeAttrs != null || super.canApplyTheme();
+            return mTouchThemeAttrs != null
+                    || (mColor != null && mColor.canApplyTheme())
+                    || super.canApplyTheme();
         }
 
         @Override
@@ -945,36 +978,6 @@
         }
     }
 
-    /**
-     * Sets the maximum ripple radius in pixels. The default value of
-     * {@link #RADIUS_AUTO} defines the radius as the distance from the center
-     * of the drawable bounds (or hotspot bounds, if specified) to a corner.
-     *
-     * @param maxRadius the maximum ripple radius in pixels or
-     *            {@link #RADIUS_AUTO} to automatically determine the maximum
-     *            radius based on the bounds
-     * @see #getMaxRadius()
-     * @see #setHotspotBounds(int, int, int, int)
-     * @hide
-     */
-    public void setMaxRadius(int maxRadius) {
-        if (maxRadius != RADIUS_AUTO && maxRadius < 0) {
-            throw new IllegalArgumentException("maxRadius must be RADIUS_AUTO or >= 0");
-        }
-
-        mState.mMaxRadius = maxRadius;
-    }
-
-    /**
-     * @return the maximum ripple radius in pixels, or {@link #RADIUS_AUTO} if
-     *         the radius is determined automatically
-     * @see #setMaxRadius(int)
-     * @hide
-     */
-    public int getMaxRadius() {
-        return mState.mMaxRadius;
-    }
-
     private RippleDrawable(RippleState state, Resources res) {
         mState = new RippleState(state, this, res);
         mLayerState = mState;
@@ -987,10 +990,10 @@
             mDensity = res.getDisplayMetrics().density;
         }
 
-        initializeFromState();
+        updateLocalState();
     }
 
-    private void initializeFromState() {
+    private void updateLocalState() {
         // Initialize from constant state.
         mMask = findDrawableByLayerId(R.id.mask);
     }
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
new file mode 100644
index 0000000..334122d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.FloatProperty;
+import android.util.MathUtils;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Draws a ripple foreground.
+ */
+class RippleForeground extends RippleComponent {
+    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+    private static final TimeInterpolator DECELERATE_INTERPOLATOR = new LogDecelerateInterpolator(
+            400f, 1.4f, 0);
+
+    // Pixel-based accelerations and velocities.
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 3400;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 3;
+
+    // Bounded ripple animation properties.
+    private static final int BOUNDED_ORIGIN_EXIT_DURATION = 300;
+    private static final int BOUNDED_RADIUS_EXIT_DURATION = 800;
+    private static final int BOUNDED_OPACITY_EXIT_DURATION = 400;
+    private static final float MAX_BOUNDED_RADIUS = 350;
+
+    private static final int RIPPLE_ENTER_DELAY = 80;
+    private static final int OPACITY_ENTER_DURATION_FAST = 120;
+
+    // Parent-relative values for starting position.
+    private float mStartingX;
+    private float mStartingY;
+    private float mClampedStartingX;
+    private float mClampedStartingY;
+
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
+
+    // Target values for tween animations.
+    private float mTargetX = 0;
+    private float mTargetY = 0;
+
+    /** Ripple target radius used when bounded. Not used for clamping. */
+    private float mBoundedRadius = 0;
+
+    // Software rendering properties.
+    private float mOpacity = 1;
+
+    // Values used to tween between the start and end positions.
+    private float mTweenRadius = 0;
+    private float mTweenX = 0;
+    private float mTweenY = 0;
+
+    /** Whether this ripple is bounded. */
+    private boolean mIsBounded;
+
+    /** Whether this ripple has finished its exit animation. */
+    private boolean mHasFinishedExit;
+
+    public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
+            boolean isBounded) {
+        super(owner, bounds);
+
+        mIsBounded = isBounded;
+        mStartingX = startingX;
+        mStartingY = startingY;
+
+        if (isBounded) {
+            mBoundedRadius = MAX_BOUNDED_RADIUS * 0.9f
+                    + (float) (MAX_BOUNDED_RADIUS * Math.random() * 0.1);
+        } else {
+            mBoundedRadius = 0;
+        }
+    }
+
+    @Override
+    protected void onTargetRadiusChanged(float targetRadius) {
+        clampStartingPosition();
+    }
+
+    @Override
+    protected boolean drawSoftware(Canvas c, Paint p) {
+        boolean hasContent = false;
+
+        final int origAlpha = p.getAlpha();
+        final int alpha = (int) (origAlpha * mOpacity + 0.5f);
+        final float radius = getCurrentRadius();
+        if (alpha > 0 && radius > 0) {
+            final float x = getCurrentX();
+            final float y = getCurrentY();
+            p.setAlpha(alpha);
+            c.drawCircle(x, y, radius, p);
+            p.setAlpha(origAlpha);
+            hasContent = true;
+        }
+
+        return hasContent;
+    }
+
+    @Override
+    protected boolean drawHardware(HardwareCanvas c) {
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+        return true;
+    }
+
+    /**
+     * Returns the maximum bounds of the ripple relative to the ripple center.
+     */
+    public void getBounds(Rect bounds) {
+        final int outerX = (int) mTargetX;
+        final int outerY = (int) mTargetY;
+        final int r = (int) mTargetRadius + 1;
+        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+    }
+
+    /**
+     * Specifies the starting position relative to the drawable bounds. No-op if
+     * the ripple has already entered.
+     */
+    public void move(float x, float y) {
+        mStartingX = x;
+        mStartingY = y;
+
+        clampStartingPosition();
+    }
+
+    /**
+     * @return {@code true} if this ripple has finished its exit animation
+     */
+    public boolean hasFinishedExit() {
+        return mHasFinishedExit;
+    }
+
+    @Override
+    protected Animator createSoftwareEnter(boolean fast) {
+        // Bounded ripples don't have enter animations.
+        if (mIsBounded) {
+            return null;
+        }
+
+        final int duration = (int)
+                (1000 * Math.sqrt(mTargetRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
+
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(duration);
+        tweenRadius.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenRadius.setStartDelay(RIPPLE_ENTER_DELAY);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(duration);
+        tweenOrigin.setInterpolator(LINEAR_INTERPOLATOR);
+        tweenOrigin.setStartDelay(RIPPLE_ENTER_DELAY);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(OPACITY_ENTER_DURATION_FAST);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+
+        final AnimatorSet set = new AnimatorSet();
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
+
+        return set;
+    }
+
+    private float getCurrentX() {
+        return MathUtils.lerp(mClampedStartingX - mBounds.exactCenterX(), mTargetX, mTweenX);
+    }
+
+    private float getCurrentY() {
+        return MathUtils.lerp(mClampedStartingY - mBounds.exactCenterY(), mTargetY, mTweenY);
+    }
+
+    private int getRadiusExitDuration() {
+        final float remainingRadius = mTargetRadius - getCurrentRadius();
+        return (int) (1000 * Math.sqrt(remainingRadius / (WAVE_TOUCH_UP_ACCELERATION
+                + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
+    }
+
+    private float getCurrentRadius() {
+        return MathUtils.lerp(0, mTargetRadius, mTweenRadius);
+    }
+
+    private int getOpacityExitDuration() {
+        return (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+    }
+
+    /**
+     * Compute target values that are dependent on bounding.
+     */
+    private void computeBoundedTargetValues() {
+        mTargetX = (mClampedStartingX - mBounds.exactCenterX()) * .7f;
+        mTargetY = (mClampedStartingY - mBounds.exactCenterY()) * .7f;
+        mTargetRadius = mBoundedRadius;
+    }
+
+    @Override
+    protected Animator createSoftwareExit() {
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
+
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
+
+        final ObjectAnimator tweenRadius = ObjectAnimator.ofFloat(this, TWEEN_RADIUS, 1);
+        tweenRadius.setAutoCancel(true);
+        tweenRadius.setDuration(radiusDuration);
+        tweenRadius.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final ObjectAnimator tweenOrigin = ObjectAnimator.ofFloat(this, TWEEN_ORIGIN, 1);
+        tweenOrigin.setAutoCancel(true);
+        tweenOrigin.setDuration(originDuration);
+        tweenOrigin.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 0);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(opacityDuration);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+
+        final AnimatorSet set = new AnimatorSet();
+        set.play(tweenOrigin).with(tweenRadius).with(opacity);
+        set.addListener(mAnimationListener);
+
+        return set;
+    }
+
+    @Override
+    protected RenderNodeAnimatorSet createHardwareExit(Paint p) {
+        final int radiusDuration;
+        final int originDuration;
+        final int opacityDuration;
+        if (mIsBounded) {
+            computeBoundedTargetValues();
+
+            radiusDuration = BOUNDED_RADIUS_EXIT_DURATION;
+            originDuration = BOUNDED_ORIGIN_EXIT_DURATION;
+            opacityDuration = BOUNDED_OPACITY_EXIT_DURATION;
+        } else {
+            radiusDuration = getRadiusExitDuration();
+            originDuration = radiusDuration;
+            opacityDuration = getOpacityExitDuration();
+        }
+
+        final float startX = getCurrentX();
+        final float startY = getCurrentY();
+        final float startRadius = getCurrentRadius();
+
+        p.setAlpha((int) (p.getAlpha() * mOpacity + 0.5f));
+
+        mPropPaint = CanvasProperty.createPaint(p);
+        mPropRadius = CanvasProperty.createFloat(startRadius);
+        mPropX = CanvasProperty.createFloat(startX);
+        mPropY = CanvasProperty.createFloat(startY);
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mTargetRadius);
+        radius.setDuration(radiusDuration);
+        radius.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mTargetX);
+        x.setDuration(originDuration);
+        x.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mTargetY);
+        y.setDuration(originDuration);
+        y.setInterpolator(DECELERATE_INTERPOLATOR);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(opacityDuration);
+        opacity.setInterpolator(LINEAR_INTERPOLATOR);
+        opacity.addListener(mAnimationListener);
+
+        final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet();
+        set.add(radius);
+        set.add(opacity);
+        set.add(x);
+        set.add(y);
+
+        return set;
+    }
+
+    @Override
+    protected void jumpValuesToExit() {
+        mOpacity = 0;
+        mTweenX = 1;
+        mTweenY = 1;
+        mTweenRadius = 1;
+    }
+
+    /**
+     * Clamps the starting position to fit within the ripple bounds.
+     */
+    private void clampStartingPosition() {
+        final float cX = mBounds.exactCenterX();
+        final float cY = mBounds.exactCenterY();
+        final float dX = mStartingX - cX;
+        final float dY = mStartingY - cY;
+        final float r = mTargetRadius;
+        if (dX * dX + dY * dY > r * r) {
+            // Point is outside the circle, clamp to the perimeter.
+            final double angle = Math.atan2(dY, dX);
+            mClampedStartingX = cX + (float) (Math.cos(angle) * r);
+            mClampedStartingY = cY + (float) (Math.sin(angle) * r);
+        } else {
+            mClampedStartingX = mStartingX;
+            mClampedStartingY = mStartingY;
+        }
+    }
+
+    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animator) {
+            mHasFinishedExit = true;
+        }
+    };
+
+    /**
+    * Interpolator with a smooth log deceleration.
+    */
+    private static final class LogDecelerateInterpolator implements TimeInterpolator {
+        private final float mBase;
+        private final float mDrift;
+        private final float mTimeScale;
+        private final float mOutputScale;
+
+        public LogDecelerateInterpolator(float base, float timeScale, float drift) {
+            mBase = base;
+            mDrift = drift;
+            mTimeScale = 1f / timeScale;
+
+            mOutputScale = 1f / computeLog(1f);
+        }
+
+        private float computeLog(float t) {
+            return 1f - (float) Math.pow(mBase, -t * mTimeScale) + (mDrift * t);
+        }
+
+        @Override
+        public float getInterpolation(float t) {
+            return computeLog(t) * mOutputScale;
+        }
+    }
+
+    /**
+     * Property for animating radius between its initial and target values.
+     */
+    private static final FloatProperty<RippleForeground> TWEEN_RADIUS =
+            new FloatProperty<RippleForeground>("tweenRadius") {
+        @Override
+        public void setValue(RippleForeground object, float value) {
+            object.mTweenRadius = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleForeground object) {
+            return object.mTweenRadius;
+        }
+    };
+
+    /**
+     * Property for animating origin between its initial and target values.
+     */
+    private static final FloatProperty<RippleForeground> TWEEN_ORIGIN =
+            new FloatProperty<RippleForeground>("tweenOrigin") {
+                @Override
+                public void setValue(RippleForeground object, float value) {
+                    object.mTweenX = value;
+                    object.mTweenY = value;
+                    object.invalidateSelf();
+                }
+
+                @Override
+                public Float get(RippleForeground object) {
+                    return object.mTweenX;
+                }
+            };
+
+    /**
+     * Property for animating opacity between 0 and its target value.
+     */
+    private static final FloatProperty<RippleForeground> OPACITY =
+            new FloatProperty<RippleForeground>("opacity") {
+        @Override
+        public void setValue(RippleForeground object, float value) {
+            object.mOpacity = value;
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Float get(RippleForeground object) {
+            return object.mOpacity;
+        }
+    };
+}
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index e1991fe..15e16f1 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -22,13 +22,11 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 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;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.util.AttributeSet;
 
@@ -51,355 +49,16 @@
  * @attr ref android.R.styleable#RotateDrawable_pivotY
  * @attr ref android.R.styleable#RotateDrawable_drawable
  */
-public class RotateDrawable extends Drawable implements Drawable.Callback {
-    private static final float MAX_LEVEL = 10000.0f;
+public class RotateDrawable extends DrawableWrapper {
+    private static final int MAX_LEVEL = 10000;
 
-    private final RotateState mState;
-
-    private boolean mMutated;
+    private RotateState mState;
 
     /**
-     * Create a new rotating drawable with an empty state.
+     * Creates a new rotating drawable with no wrapped drawable.
      */
     public RotateDrawable() {
-        this(null, null);
-    }
-
-    /**
-     * Create a new rotating drawable with the specified state. A copy of
-     * this state is used as the internal state for the newly created
-     * drawable.
-     *
-     * @param rotateState the state for this drawable
-     */
-    private RotateDrawable(RotateState rotateState, Resources res) {
-        mState = new RotateState(rotateState, this, res);
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        final RotateState st = mState;
-        final Drawable d = st.mDrawable;
-        final Rect bounds = d.getBounds();
-        final int w = bounds.right - bounds.left;
-        final int h = bounds.bottom - bounds.top;
-        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
-        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
-
-        final int saveCount = canvas.save();
-        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
-        d.draw(canvas);
-        canvas.restoreToCount(saveCount);
-    }
-
-    /**
-     * Sets the drawable rotated by this RotateDrawable.
-     *
-     * @param drawable The drawable to rotate
-     */
-    public void setDrawable(Drawable drawable) {
-        final Drawable oldDrawable = mState.mDrawable;
-        if (oldDrawable != drawable) {
-            if (oldDrawable != null) {
-                oldDrawable.setCallback(null);
-            }
-            mState.mDrawable = drawable;
-            if (drawable != null) {
-                drawable.setCallback(this);
-            }
-        }
-    }
-
-    /**
-     * @return The drawable rotated by this RotateDrawable
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    /**
-     * Sets the start angle for rotation.
-     *
-     * @param fromDegrees Starting angle in degrees
-     *
-     * @see #getFromDegrees()
-     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
-     */
-    public void setFromDegrees(float fromDegrees) {
-        if (mState.mFromDegrees != fromDegrees) {
-            mState.mFromDegrees = fromDegrees;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return The starting angle for rotation in degrees
-     *
-     * @see #setFromDegrees(float)
-     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
-     */
-    public float getFromDegrees() {
-        return mState.mFromDegrees;
-    }
-
-    /**
-     * Sets the end angle for rotation.
-     *
-     * @param toDegrees Ending angle in degrees
-     *
-     * @see #getToDegrees()
-     * @attr ref android.R.styleable#RotateDrawable_toDegrees
-     */
-    public void setToDegrees(float toDegrees) {
-        if (mState.mToDegrees != toDegrees) {
-            mState.mToDegrees = toDegrees;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return The ending angle for rotation in degrees
-     *
-     * @see #setToDegrees(float)
-     * @attr ref android.R.styleable#RotateDrawable_toDegrees
-     */
-    public float getToDegrees() {
-        return mState.mToDegrees;
-    }
-
-    /**
-     * Sets the X position around which the drawable is rotated.
-     *
-     * @param pivotX X position around which to rotate. If the X pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            width. Otherwise, the position represents an absolute value in
-     *            pixels.
-     *
-     * @see #setPivotXRelative(boolean)
-     * @attr ref android.R.styleable#RotateDrawable_pivotX
-     */
-    public void setPivotX(float pivotX) {
-        if (mState.mPivotX != pivotX) {
-            mState.mPivotX = pivotX;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return X position around which to rotate
-     *
-     * @see #setPivotX(float)
-     * @attr ref android.R.styleable#RotateDrawable_pivotX
-     */
-    public float getPivotX() {
-        return mState.mPivotX;
-    }
-
-    /**
-     * Sets whether the X pivot value represents a fraction of the drawable
-     * width or an absolute value in pixels.
-     *
-     * @param relative True if the X pivot represents a fraction of the drawable
-     *            width, or false if it represents an absolute value in pixels
-     *
-     * @see #isPivotXRelative()
-     */
-    public void setPivotXRelative(boolean relative) {
-        if (mState.mPivotXRel != relative) {
-            mState.mPivotXRel = relative;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return True if the X pivot represents a fraction of the drawable width,
-     *         or false if it represents an absolute value in pixels
-     *
-     * @see #setPivotXRelative(boolean)
-     */
-    public boolean isPivotXRelative() {
-        return mState.mPivotXRel;
-    }
-
-    /**
-     * Sets the Y position around which the drawable is rotated.
-     *
-     * @param pivotY Y position around which to rotate. If the Y pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            height. Otherwise, the position represents an absolute value
-     *            in pixels.
-     *
-     * @see #getPivotY()
-     * @attr ref android.R.styleable#RotateDrawable_pivotY
-     */
-    public void setPivotY(float pivotY) {
-        if (mState.mPivotY != pivotY) {
-            mState.mPivotY = pivotY;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return Y position around which to rotate
-     *
-     * @see #setPivotY(float)
-     * @attr ref android.R.styleable#RotateDrawable_pivotY
-     */
-    public float getPivotY() {
-        return mState.mPivotY;
-    }
-
-    /**
-     * Sets whether the Y pivot value represents a fraction of the drawable
-     * height or an absolute value in pixels.
-     *
-     * @param relative True if the Y pivot represents a fraction of the drawable
-     *            height, or false if it represents an absolute value in pixels
-     *
-     * @see #isPivotYRelative()
-     */
-    public void setPivotYRelative(boolean relative) {
-        if (mState.mPivotYRel != relative) {
-            mState.mPivotYRel = relative;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return True if the Y pivot represents a fraction of the drawable height,
-     *         or false if it represents an absolute value in pixels
-     *
-     * @see #setPivotYRelative(boolean)
-     */
-    public boolean isPivotYRelative() {
-        return mState.mPivotYRel;
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-   @Override
-    public boolean getPadding(Rect padding) {
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        final boolean changed = mState.mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
-    }
-
-    @Override
-    protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
-        onBoundsChange(getBounds());
-
-        mState.mCurrentDegrees = mState.mFromDegrees +
-                (mState.mToDegrees - mState.mFromDegrees) *
-                        (level / MAX_LEVEL);
-
-        invalidateSelf();
-        return true;
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds.left, bounds.top,
-                bounds.right, bounds.bottom);
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
+        this(new RotateState(null), null);
     }
 
     @Override
@@ -408,73 +67,26 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
 
-        // Reset mDrawable to preserve old multiple-inflate behavior. This is
-        // silly, but we have CTS tests that rely on it.
-        mState.mDrawable = null;
-
         updateStateFromTypedArray(a);
-        inflateChildElements(r, parser, attrs, theme);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    @Override
-    public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
-        final RotateState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-
-    }
-
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
     private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.RotateDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <rotate> tag requires a 'drawable' attribute or "
                     + "child tag defining a drawable");
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final RotateState state = mState;
 
         // Account for any configuration changes.
@@ -495,72 +107,235 @@
             state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
         }
 
-        state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
-        state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
+        state.mFromDegrees = a.getFloat(
+                R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
+        state.mToDegrees = a.getFloat(
+                R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
         state.mCurrentDegrees = state.mFromDegrees;
 
         final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
     @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
+    public void applyTheme(Theme t) {
+        final RotateState state = mState;
+        if (state == null) {
+            return;
         }
-        return this;
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final Drawable d = getDrawable();
+        final Rect bounds = d.getBounds();
+        final int w = bounds.right - bounds.left;
+        final int h = bounds.bottom - bounds.top;
+        final RotateState st = mState;
+        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+
+        final int saveCount = canvas.save();
+        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
+        d.draw(canvas);
+        canvas.restoreToCount(saveCount);
     }
 
     /**
-     * @hide
+     * Sets the start angle for rotation.
+     *
+     * @param fromDegrees starting angle in degrees
+     * @see #getFromDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
+    public void setFromDegrees(float fromDegrees) {
+        if (mState.mFromDegrees != fromDegrees) {
+            mState.mFromDegrees = fromDegrees;
+            invalidateSelf();
+        }
     }
 
     /**
-     * Represents the state of a rotation for a given drawable. The same
-     * rotate drawable can be invoked with different states to drive several
-     * rotations at the same time.
+     * @return starting angle for rotation in degrees
+     * @see #setFromDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
-    final static class RotateState extends Drawable.ConstantState {
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
+    public float getFromDegrees() {
+        return mState.mFromDegrees;
+    }
 
-        Drawable mDrawable;
+    /**
+     * Sets the end angle for rotation.
+     *
+     * @param toDegrees ending angle in degrees
+     * @see #getToDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
+     */
+    public void setToDegrees(float toDegrees) {
+        if (mState.mToDegrees != toDegrees) {
+            mState.mToDegrees = toDegrees;
+            invalidateSelf();
+        }
+    }
 
+    /**
+     * @return ending angle for rotation in degrees
+     * @see #setToDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
+     */
+    public float getToDegrees() {
+        return mState.mToDegrees;
+    }
+
+    /**
+     * Sets the X position around which the drawable is rotated.
+     *
+     * @param pivotX X position around which to rotate. If the X pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            width. Otherwise, the position represents an absolute value in
+     *            pixels.
+     * @see #setPivotXRelative(boolean)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
+     */
+    public void setPivotX(float pivotX) {
+        if (mState.mPivotX != pivotX) {
+            mState.mPivotX = pivotX;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return X position around which to rotate
+     * @see #setPivotX(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
+     */
+    public float getPivotX() {
+        return mState.mPivotX;
+    }
+
+    /**
+     * Sets whether the X pivot value represents a fraction of the drawable
+     * width or an absolute value in pixels.
+     *
+     * @param relative true if the X pivot represents a fraction of the drawable
+     *            width, or false if it represents an absolute value in pixels
+     * @see #isPivotXRelative()
+     */
+    public void setPivotXRelative(boolean relative) {
+        if (mState.mPivotXRel != relative) {
+            mState.mPivotXRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return true if the X pivot represents a fraction of the drawable width,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotXRelative(boolean)
+     */
+    public boolean isPivotXRelative() {
+        return mState.mPivotXRel;
+    }
+
+    /**
+     * Sets the Y position around which the drawable is rotated.
+     *
+     * @param pivotY Y position around which to rotate. If the Y pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            height. Otherwise, the position represents an absolute value
+     *            in pixels.
+     * @see #getPivotY()
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
+     */
+    public void setPivotY(float pivotY) {
+        if (mState.mPivotY != pivotY) {
+            mState.mPivotY = pivotY;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return Y position around which to rotate
+     * @see #setPivotY(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
+     */
+    public float getPivotY() {
+        return mState.mPivotY;
+    }
+
+    /**
+     * Sets whether the Y pivot value represents a fraction of the drawable
+     * height or an absolute value in pixels.
+     *
+     * @param relative True if the Y pivot represents a fraction of the drawable
+     *            height, or false if it represents an absolute value in pixels
+     * @see #isPivotYRelative()
+     */
+    public void setPivotYRelative(boolean relative) {
+        if (mState.mPivotYRel != relative) {
+            mState.mPivotYRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return true if the Y pivot represents a fraction of the drawable height,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotYRelative(boolean)
+     */
+    public boolean isPivotYRelative() {
+        return mState.mPivotYRel;
+    }
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        super.onLevelChange(level);
+
+        final float value = level / (float) MAX_LEVEL;
+        final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
+        mState.mCurrentDegrees = degrees;
+
+        invalidateSelf();
+        return true;
+    }
+
+    @Override
+    DrawableWrapperState mutateConstantState() {
+        mState = new RotateState(mState);
+        return mState;
+    }
+
+    static final class RotateState extends DrawableWrapper.DrawableWrapperState {
         boolean mPivotXRel = true;
         float mPivotX = 0.5f;
         boolean mPivotYRel = true;
         float mPivotY = 0.5f;
-
         float mFromDegrees = 0.0f;
         float mToDegrees = 360.0f;
-
         float mCurrentDegrees = 0.0f;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        RotateState(RotateState orig) {
+            super(orig);
 
-        RotateState(RotateState orig, RotateDrawable owner, Resources res) {
             if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mChangingConfigurations = orig.mChangingConfigurations;
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mPivotXRel = orig.mPivotXRel;
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
@@ -568,38 +343,18 @@
                 mFromDegrees = orig.mFromDegrees;
                 mToDegrees = orig.mToDegrees;
                 mCurrentDegrees = orig.mCurrentDegrees;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new RotateDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new RotateDrawable(this, res);
         }
+    }
 
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
+    private RotateDrawable(RotateState state, Resources res) {
+        super(state, res);
 
-        public boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
+        mState = state;
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index da722f3..0acbeda 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -21,17 +21,17 @@
 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.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
 
 import java.io.IOException;
-import java.util.Collection;
 
 /**
  * A Drawable that changes the size of another Drawable based on its current
@@ -49,44 +49,37 @@
  * @attr ref android.R.styleable#ScaleDrawable_scaleGravity
  * @attr ref android.R.styleable#ScaleDrawable_drawable
  */
-public class ScaleDrawable extends Drawable implements Drawable.Callback {
-    private ScaleState mState;
-    private boolean mMutated;
+public class ScaleDrawable extends DrawableWrapper {
+    private static final int MAX_LEVEL = 10000;
+
     private final Rect mTmpRect = new Rect();
 
+    private ScaleState mState;
+
     ScaleDrawable() {
-        this(null, null);
+        this(new ScaleState(null), null);
     }
 
+    /**
+     * Creates a new scale drawable with the specified gravity and scale
+     * properties.
+     *
+     * @param drawable the drawable to scale
+     * @param gravity gravity constant (see {@link Gravity} used to position
+     *                the scaled drawable within the parent container
+     * @param scaleWidth width scaling factor [0...1] to use then the level is
+     *                   at the maximum value, or -1 to not scale width
+     * @param scaleHeight height scaling factor [0...1] to use then the level
+     *                    is at the maximum value, or -1 to not scale height
+     */
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
-        this(null, null);
+        this(new ScaleState(null), null);
 
-        mState.mDrawable = drawable;
         mState.mGravity = gravity;
         mState.mScaleWidth = scaleWidth;
         mState.mScaleHeight = scaleHeight;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
-    }
-
-    /**
-     * Returns the drawable scaled by this ScaleDrawable.
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    private static float getPercent(TypedArray a, int name, float defaultValue) {
-        final String s = a.getString(name);
-        if (s != null) {
-            if (s.endsWith("%")) {
-                String f = s.substring(0, s.length() - 1);
-                return Float.parseFloat(f) / 100.0f;
-            }
-        }
-        return defaultValue;
+        setDrawable(drawable);
     }
 
     @Override
@@ -95,28 +88,70 @@
         super.inflate(r, parser, attrs, theme);
 
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
-
-        // Reset mDrawable to preserve old multiple-inflate behavior. This is
-        // silly, but we have CTS tests that rely on it.
-        mState.mDrawable = null;
-
         updateStateFromTypedArray(a);
-        inflateChildElements(r, parser, attrs, theme);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <scale> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
+        final ScaleState state = mState;
+        state.mScaleWidth = getPercent(a,
+                R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
+        state.mScaleHeight = getPercent(a,
+                R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
+        state.mGravity = a.getInt(
+                R.styleable.ScaleDrawable_scaleGravity, state.mGravity);
+        state.mUseIntrinsicSizeAsMin = a.getBoolean(
+                R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
+
+        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
+        if (dr != null) {
+            setDrawable(dr);
+        }
+    }
+
+    private static float getPercent(TypedArray a, int index, float defaultValue) {
+        final int type = a.getType(index);
+        if (type == TypedValue.TYPE_FRACTION || type == TypedValue.TYPE_NULL) {
+            return a.getFraction(index, 1, 1, defaultValue);
+        }
+
+        // Coerce to float.
+        final String s = a.getString(index);
+        if (s != null) {
+            if (s.endsWith("%")) {
+                final String f = s.substring(0, s.length() - 1);
+                return Float.parseFloat(f) / 100.0f;
+            }
+        }
+
+        return defaultValue;
+    }
+
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final ScaleState state = mState;
         if (state == null) {
             return;
         }
 
         if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable);
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.ScaleDrawable);
             try {
                 updateStateFromTypedArray(a);
                 verifyRequiredAttributes(a);
@@ -127,161 +162,37 @@
             }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
-        // If we're not waiting on a theme, verify required attributes.
-        if (mState.mDrawable == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <scale> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
-    }
-
-    private void updateStateFromTypedArray(TypedArray a) {
-        final ScaleState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
-        state.mScaleWidth = getPercent(
-                a, R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
-        state.mScaleHeight = getPercent(
-                a, R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
-        state.mGravity = a.getInt(R.styleable.ScaleDrawable_scaleGravity, state.mGravity);
-        state.mUseIntrinsicSizeAsMin = a.getBoolean(
-                R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
-
-        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
-        if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    // overrides from Drawable.Callback
-
-    public void invalidateDrawable(Drawable who) {
-        if (getCallback() != null) {
-            getCallback().invalidateDrawable(this);
-        }
-    }
-
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        if (getCallback() != null) {
-            getCallback().scheduleDrawable(this, what, when);
-        }
-    }
-
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        if (getCallback() != null) {
-            getCallback().unscheduleDrawable(this, what);
-        }
-    }
-
-    // overrides from Drawable
-
     @Override
     public void draw(Canvas canvas) {
-        if (mState.mDrawable.getLevel() != 0)
-            mState.mDrawable.draw(canvas);
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        // XXX need to adjust padding!
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
+        final Drawable d = getDrawable();
+        if (d != null && d.getLevel() != 0) {
+            d.draw(canvas);
+        }
     }
 
     @Override
     public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
+        final Drawable d = getDrawable();
+        if (d.getLevel() == 0) {
+            return PixelFormat.TRANSPARENT;
+        }
 
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
+        final int opacity = d.getOpacity();
+        if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) {
+            return PixelFormat.TRANSLUCENT;
+        }
 
-    @Override
-    protected boolean onStateChange(int[] state) {
-        boolean changed = mState.mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
+        return opacity;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
+        super.onLevelChange(level);
         onBoundsChange(getBounds());
         invalidateSelf();
         return true;
@@ -289,144 +200,67 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
+        final Drawable d = getDrawable();
         final Rect r = mTmpRect;
         final boolean min = mState.mUseIntrinsicSizeAsMin;
-        int level = getLevel();
+        final int level = getLevel();
+
         int w = bounds.width();
         if (mState.mScaleWidth > 0) {
-            final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0;
-            w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000);
+            final int iw = min ? d.getIntrinsicWidth() : 0;
+            w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
         }
+
         int h = bounds.height();
         if (mState.mScaleHeight > 0) {
-            final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0;
-            h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000);
+            final int ih = min ? d.getIntrinsicHeight() : 0;
+            h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
         }
+
         final int layoutDirection = getLayoutDirection();
         Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
-            mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+            d.setBounds(r.left, r.top, r.right, r.bottom);
         }
     }
 
     @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
+    DrawableWrapperState mutateConstantState() {
+        mState = new ScaleState(mState);
+        return mState;
     }
 
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class ScaleState extends ConstantState {
+    static final class ScaleState extends DrawableWrapper.DrawableWrapperState {
         /** Constant used to disable scaling for a particular dimension. */
         private static final float DO_NOT_SCALE = -1.0f;
 
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
-
-        Drawable mDrawable;
-
         float mScaleWidth = DO_NOT_SCALE;
         float mScaleHeight = DO_NOT_SCALE;
         int mGravity = Gravity.LEFT;
         boolean mUseIntrinsicSizeAsMin = false;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        ScaleState(ScaleState orig) {
+            super(orig);
 
-        ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
             if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mChangingConfigurations = orig.mChangingConfigurations;
-                if (res != null) {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
-                } else {
-                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
-                }
-                mDrawable.setCallback(owner);
-                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
-                mDrawable.setBounds(orig.mDrawable.getBounds());
-                mDrawable.setLevel(orig.mDrawable.getLevel());
                 mScaleWidth = orig.mScaleWidth;
                 mScaleHeight = orig.mScaleHeight;
                 mGravity = orig.mGravity;
                 mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new ScaleDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new ScaleDrawable(this, res);
         }
-
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
-
-        boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
-
-        @Override
-        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
-            final ConstantState state = mDrawable.getConstantState();
-            if (state != null) {
-                return state.addAtlasableBitmaps(atlasList);
-            }
-            return 0;
-        }
     }
 
     private ScaleDrawable(ScaleState state, Resources res) {
-        mState = new ScaleState(state, this, res);
+        super(state, res);
+
+        mState = state;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index a3d8c92..fc88c15 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -299,8 +299,8 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        mShapeState.mPaint.setColorFilter(cf);
+    public void setColorFilter(ColorFilter colorFilter) {
+        mShapeState.mPaint.setColorFilter(colorFilter);
         invalidateSelf();
     }
 
@@ -329,6 +329,11 @@
     }
 
     @Override
+    public boolean getDither() {
+        return mShapeState.mPaint.isDither();
+    }
+
+    @Override
     protected void onBoundsChange(Rect bounds) {
         super.onBoundsChange(bounds);
         updateShape();
@@ -402,7 +407,7 @@
         }
 
         // Update local properties.
-        initializeWithState(mShapeState, r);
+        updateLocalState(r);
     }
 
     @Override
@@ -410,16 +415,23 @@
         super.applyTheme(t);
 
         final ShapeState state = mShapeState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
-        updateStateFromTypedArray(a);
-        a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        // Apply theme to contained color state list.
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
+        }
 
         // Update local properties.
-        initializeWithState(state, t.getResources());
+        updateLocalState(t.getResources());
     }
 
     private void updateStateFromTypedArray(TypedArray a) {
@@ -550,7 +562,8 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            return mThemeAttrs != null
+                    || (mTint != null && mTint.canApplyTheme());
         }
 
         @Override
@@ -576,7 +589,7 @@
     private ShapeDrawable(ShapeState state, Resources res) {
         mShapeState = state;
 
-        initializeWithState(state, res);
+        updateLocalState(res);
     }
 
     /**
@@ -584,8 +597,8 @@
      * after significant state changes, e.g. from the One True Constructor and
      * after inflating or applying a theme.
      */
-    private void initializeWithState(ShapeState state, Resources res) {
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+    private void updateLocalState(Resources res) {
+        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 59d0ba6..c83af11 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -309,16 +309,6 @@
         mMutated = false;
     }
 
-    /** @hide */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        super.setLayoutDirection(layoutDirection);
-
-        // Let the container handle setting its own layout direction. Otherwise,
-        // we're accessing potentially unused states.
-        mStateListState.setLayoutDirection(layoutDirection);
-    }
-
     static class StateListState extends DrawableContainerState {
         int[] mThemeAttrs;
         int[][] mStateSets;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 8b0f635..5f1dcec 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -150,7 +150,8 @@
  *
  * <dl>
  * <dt><code>&lt;clip-path></code></dt>
- * <dd>Defines path to be the current clip.
+ * <dd>Defines path to be the current clip. Note that the clip path only apply to
+ * the current group and its children.
  * <dl>
  * <dt><code>android:name</code></dt>
  * <dd>Defines the name of the clip path.</dd>
@@ -369,8 +370,13 @@
         super.applyTheme(t);
 
         final VectorDrawableState state = mVectorState;
-        if (state != null && state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.VectorDrawable);
+        if (state == null) {
+            return;
+        }
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.VectorDrawable);
             try {
                 state.mCacheDirty = true;
                 updateStateFromTypedArray(a);
@@ -379,14 +385,20 @@
             } finally {
                 a.recycle();
             }
+        }
 
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        // Apply theme to contained color state list.
+        if (state.mTint != null && state.mTint.canApplyTheme()) {
+            state.mTint.applyTheme(t);
         }
 
         final VPathRenderer path = state.mVPathRenderer;
         if (path != null && path.canApplyTheme()) {
             path.applyTheme(t);
         }
+
+        // Update local state.
+        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
     /**
@@ -750,7 +762,9 @@
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+            return mThemeAttrs != null
+                    || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+                    || (mTint != null && mTint.canApplyTheme())
                     || super.canApplyTheme();
         }
 
@@ -913,9 +927,10 @@
             // Basically the Mfinal = Mviewport * M0 * M1 * M2;
             // Mi the local matrix at level i of the group tree.
             currentGroup.mStackedMatrix.set(currentMatrix);
-
             currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
 
+            // Save the current clip information, which is local to this group.
+            canvas.save();
             // Draw the group tree in the same order as the XML file.
             for (int i = 0; i < currentGroup.mChildren.size(); i++) {
                 Object child = currentGroup.mChildren.get(i);
@@ -928,6 +943,7 @@
                     drawPath(currentGroup, childPath, canvas, w, h, filter);
                 }
             }
+            canvas.restore();
         }
 
         public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 79934da..b32dcc6 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -380,7 +380,7 @@
 
             final long transformPtr = (transform != null) ? transform.native_instance : 0;
 
-            nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+            nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft,
                     contentTop, contentRight, contentBottom, transformPtr, renderMode);
         }
 
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index 53e8b49..a6836a8 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -26,6 +26,33 @@
 class Surface;
 class IGraphicBufferProducer;
 
+/**
+ * Enum mirroring the public API definitions for image and pixel formats.
+ * Some of these are hidden in the public API
+ *
+ * Keep up to date with android.graphics.ImageFormat and
+ * android.graphics.PixelFormat
+ */
+enum class PublicFormat {
+    UNKNOWN           = 0x0,
+    RGBA_8888         = 0x1,
+    RGBX_8888         = 0x2,
+    RGB_888           = 0x3,
+    RGB_565           = 0x4,
+    NV16              = 0x10,
+    NV21              = 0x11,
+    YUY2              = 0x14,
+    RAW_SENSOR        = 0x20,
+    YUV_420_888       = 0x23,
+    RAW10             = 0x25,
+    JPEG              = 0x100,
+    DEPTH_POINT_CLOUD = 0x101,
+    YV12              = 0x32315659,
+    Y8                = 0x20203859, // @hide
+    Y16               = 0x20363159, // @hide
+    DEPTH16           = 0x44363159
+};
+
 /* Gets the underlying ANativeWindow for a Surface. */
 extern sp<ANativeWindow> android_view_Surface_getNativeWindow(
         JNIEnv* env, jobject surfaceObj);
@@ -40,6 +67,21 @@
 extern jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
         const sp<IGraphicBufferProducer>& bufferProducer);
 
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * format */
+extern int android_view_Surface_mapPublicFormatToHalFormat(PublicFormat f);
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * dataspace */
+extern android_dataspace android_view_Surface_mapPublicFormatToHalDataspace(
+        PublicFormat f);
+
+/* Convert from HAL format, dataspace pair to
+ * android.graphics.ImageFormat/PixelFormat.
+ * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */
+extern PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+        int format, android_dataspace dataSpace);
+
 } // namespace android
 
 #endif // _ANDROID_VIEW_SURFACE_H
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 99b3195..0cfd2b1 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -236,9 +236,11 @@
 private:
     struct asset_path
     {
+        asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
         String8 path;
         FileType type;
         String8 idmap;
+        bool isSystemOverlay;
     };
 
     Asset* openInPathLocked(const char* fileName, AccessMode mode,
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index bf993f4..8673219 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -247,8 +247,8 @@
 #define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF))
 #define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF))
 
-#define Res_MAXPACKAGE 255
-#define Res_MAXTYPE 255
+static const size_t Res_MAXPACKAGE = 255;
+static const size_t Res_MAXTYPE = 255;
 
 /**
  * Representation of a value in a resource, supplying type
@@ -1793,9 +1793,7 @@
             const char* targetPath, const char* overlayPath,
             void** outData, size_t* outSize) const;
 
-    enum {
-        IDMAP_HEADER_SIZE_BYTES = 4 * sizeof(uint32_t) + 2 * 256,
-    };
+    static const size_t IDMAP_HEADER_SIZE_BYTES = 4 * sizeof(uint32_t) + 2 * 256;
 
     // Retrieve idmap meta-data.
     //
diff --git a/include/private/graphics/Canvas.h b/include/private/graphics/Canvas.h
deleted file mode 100644
index 3cd57f4..0000000
--- a/include/private/graphics/Canvas.h
+++ /dev/null
@@ -1,143 +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.
- */
-
-#ifndef ANDROID_GRAPHICS_CANVAS_H
-#define ANDROID_GRAPHICS_CANVAS_H
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkMatrix.h"
-
-namespace android {
-
-class Canvas {
-public:
-    virtual ~Canvas() {};
-
-    static Canvas* create_canvas(SkBitmap* bitmap);
-    static Canvas* create_canvas(SkCanvas* skiaCanvas);
-
-    // TODO: enable HWUI to either create similar canvas wrapper or subclass
-    //       directly from Canvas
-    //static Canvas* create_canvas(uirenderer::Renderer* renderer);
-
-    // TODO: this is a temporary affordance until all necessary logic can be
-    //       moved within this interface! Further, the return value should
-    //       NOT be unref'd and is valid until this canvas is destroyed or a
-    //       new bitmap is set.
-    virtual SkCanvas* getSkCanvas() = 0;
-
-    virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
-
-    virtual bool isOpaque() = 0;
-    virtual int width() = 0;
-    virtual int height() = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-    // Save (layer)
-    virtual int getSaveCount() const = 0;
-    virtual int save(SkCanvas::SaveFlags flags) = 0;
-    virtual void restore() = 0;
-    virtual void restoreToCount(int saveCount) = 0;
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-                const SkPaint* paint, SkCanvas::SaveFlags flags) = 0;
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) = 0;
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
-    virtual void setMatrix(const SkMatrix& matrix) = 0;
-
-    virtual void concat(const SkMatrix& matrix) = 0;
-    virtual void rotate(float degrees) = 0;
-    virtual void scale(float sx, float sy) = 0;
-    virtual void skew(float sx, float sy) = 0;
-    virtual void translate(float dx, float dy) = 0;
-
-    // clip
-    virtual bool getClipBounds(SkRect* outRect) const = 0;
-    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
-    virtual bool quickRejectPath(const SkPath& path) const = 0;
-
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
-
-    // filters
-    virtual SkDrawFilter* getDrawFilter() = 0;
-    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
-    virtual void drawPaint(const SkPaint& paint) = 0;
-
-    // Geometry
-    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
-    virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0;
-    virtual void drawLine(float startX, float startY, float stopX, float stopY,
-                const SkPaint& paint) = 0;
-    virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0;
-    virtual void drawRect(float left, float top, float right, float bottom,
-            const SkPaint& paint) = 0;
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint& paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
-    virtual void drawOval(float left, float top, float right, float bottom,
-            const SkPaint& paint) = 0;
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
-    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
-    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
-                              const float* verts, const float* tex, const int* colors,
-                              const uint16_t* indices, int indexCount, const SkPaint& paint) = 0;
-
-    // Bitmap-based
-    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
-            const SkPaint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
-            const SkPaint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint) = 0;
-    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint) = 0;
-
-    // Text
-    virtual void drawText(const uint16_t* text, const float* positions, int count,
-            const SkPaint& paint, float x, float y,
-            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom) = 0;
-    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
-            int posCount, const SkPaint& paint) = 0;
-    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
-            float hOffset, float vOffset, const SkPaint& paint) = 0;
-
-    /*
-     * Specifies if the positions passed to ::drawText are absolute or relative
-     * to the (x,y) value provided.
-     *
-     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
-     * to be added to each glyph's position to get its absolute position.
-     */
-    virtual bool drawTextAbsolutePos() const = 0;
-};
-
-}; // namespace android
-#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
index 458a46c..9d9a173 100644
--- a/keystore/java/android/security/AndroidKeyPairGenerator.java
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -17,7 +17,6 @@
 package android.security;
 
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-
 import com.android.org.conscrypt.NativeCrypto;
 import com.android.org.conscrypt.OpenSSLEngine;
 
@@ -34,7 +33,6 @@
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.security.spec.X509EncodedKeySpec;
@@ -52,10 +50,50 @@
  *
  * {@hide}
  */
-public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
+public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
+
+    public static class RSA extends AndroidKeyPairGenerator {
+        public RSA() {
+            super("RSA");
+        }
+    }
+
+    public static class EC extends AndroidKeyPairGenerator {
+        public EC() {
+            super("EC");
+        }
+    }
+
+    /*
+     * These must be kept in sync with system/security/keystore/defaults.h
+     */
+
+    /* EC */
+    private static final int EC_DEFAULT_KEY_SIZE = 256;
+    private static final int EC_MIN_KEY_SIZE = 192;
+    private static final int EC_MAX_KEY_SIZE = 521;
+
+    /* RSA */
+    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
+    private static final int RSA_MIN_KEY_SIZE = 512;
+    private static final int RSA_MAX_KEY_SIZE = 8192;
+
+    private final String mAlgorithm;
+
     private android.security.KeyStore mKeyStore;
 
     private KeyPairGeneratorSpec mSpec;
+    private String mKeyAlgorithm;
+    private int mKeyType;
+    private int mKeySize;
+
+    protected AndroidKeyPairGenerator(String algorithm) {
+        mAlgorithm = algorithm;
+    }
+
+    public String getAlgorithm() {
+        return mAlgorithm;
+    }
 
     /**
      * Generate a KeyPair which is backed by the Android keystore service. You
@@ -90,12 +128,11 @@
 
         Credentials.deleteAllTypesForAlias(mKeyStore, alias);
 
-        final int keyType = KeyStore.getKeyTypeForAlgorithm(mSpec.getKeyType());
-        byte[][] args = getArgsForKeyType(keyType, mSpec.getAlgorithmParameterSpec());
+        byte[][] args = getArgsForKeyType(mKeyType, mSpec.getAlgorithmParameterSpec());
 
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, keyType,
-                mSpec.getKeySize(), mSpec.getFlags(), args)) {
+        if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mKeyType, mKeySize,
+                mSpec.getFlags(), args)) {
             throw new IllegalStateException("could not generate key in keystore");
         }
 
@@ -111,7 +148,7 @@
 
         final PublicKey pubKey;
         try {
-            final KeyFactory keyFact = KeyFactory.getInstance(mSpec.getKeyType());
+            final KeyFactory keyFact = KeyFactory.getInstance(mKeyAlgorithm);
             pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
         } catch (NoSuchAlgorithmException e) {
             throw new IllegalStateException("Can't instantiate key generator", e);
@@ -119,18 +156,9 @@
             throw new IllegalStateException("keystore returned invalid key encoding", e);
         }
 
-        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
-        certGen.setPublicKey(pubKey);
-        certGen.setSerialNumber(mSpec.getSerialNumber());
-        certGen.setSubjectDN(mSpec.getSubjectDN());
-        certGen.setIssuerDN(mSpec.getSubjectDN());
-        certGen.setNotBefore(mSpec.getStartDate());
-        certGen.setNotAfter(mSpec.getEndDate());
-        certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyType(mSpec.getKeyType()));
-
         final X509Certificate cert;
         try {
-            cert = certGen.generate(privKey);
+            cert = generateCertificate(privKey, pubKey);
         } catch (Exception e) {
             Credentials.deleteAllTypesForAlias(mKeyStore, alias);
             throw new IllegalStateException("Can't generate certificate", e);
@@ -153,15 +181,78 @@
         return new KeyPair(pubKey, privKey);
     }
 
-    private static String getDefaultSignatureAlgorithmForKeyType(String keyType) {
-        if ("RSA".equalsIgnoreCase(keyType)) {
+    @SuppressWarnings("deprecation")
+    private X509Certificate generateCertificate(PrivateKey privateKey, PublicKey publicKey)
+            throws Exception {
+        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+        certGen.setPublicKey(publicKey);
+        certGen.setSerialNumber(mSpec.getSerialNumber());
+        certGen.setSubjectDN(mSpec.getSubjectDN());
+        certGen.setIssuerDN(mSpec.getSubjectDN());
+        certGen.setNotBefore(mSpec.getStartDate());
+        certGen.setNotAfter(mSpec.getEndDate());
+        certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyAlgorithm(mKeyAlgorithm));
+        return certGen.generate(privateKey);
+    }
+
+    private String getKeyAlgorithm(KeyPairGeneratorSpec spec) {
+        String result = spec.getKeyType();
+        if (result != null) {
+            return result;
+        }
+        return getAlgorithm();
+    }
+
+    private static int getDefaultKeySize(int keyType) {
+        if (keyType == NativeCrypto.EVP_PKEY_EC) {
+            return EC_DEFAULT_KEY_SIZE;
+        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
+            return RSA_DEFAULT_KEY_SIZE;
+        }
+        return -1;
+    }
+
+    private static void checkValidKeySize(String keyAlgorithm, int keyType, int keySize)
+            throws InvalidAlgorithmParameterException {
+        if (keyType == NativeCrypto.EVP_PKEY_EC) {
+            if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
+                throw new InvalidAlgorithmParameterException("EC keys must be >= "
+                        + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE);
+            }
+        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
+            if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
+                throw new InvalidAlgorithmParameterException("RSA keys must be >= "
+                        + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
+            }
+        } else {
+            throw new InvalidAlgorithmParameterException(
+                "Unsupported key algorithm: " + keyAlgorithm);
+        }
+    }
+
+    private static void checkCorrectParametersSpec(int keyType, int keySize,
+            AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException {
+        if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
+            if (spec instanceof RSAKeyGenParameterSpec) {
+                RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
+                if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
+                    throw new InvalidAlgorithmParameterException("RSA key size must match: "
+                            + keySize + " vs " + rsaSpec.getKeysize());
+                }
+            } else {
+                throw new InvalidAlgorithmParameterException(
+                    "RSA may only use RSAKeyGenParameterSpec");
+            }
+        }
+    }
+
+    private static String getDefaultSignatureAlgorithmForKeyAlgorithm(String algorithm) {
+        if ("RSA".equalsIgnoreCase(algorithm)) {
             return "sha256WithRSA";
-        } else if ("DSA".equalsIgnoreCase(keyType)) {
-            return "sha1WithDSA";
-        } else if ("EC".equalsIgnoreCase(keyType)) {
+        } else if ("EC".equalsIgnoreCase(algorithm)) {
             return "sha256WithECDSA";
         } else {
-            throw new IllegalArgumentException("Unsupported key type " + keyType);
+            throw new IllegalArgumentException("Unsupported key type " + algorithm);
         }
     }
 
@@ -173,13 +264,6 @@
                     return new byte[][] { rsaSpec.getPublicExponent().toByteArray() };
                 }
                 break;
-            case NativeCrypto.EVP_PKEY_DSA:
-                if (spec instanceof DSAParameterSpec) {
-                    DSAParameterSpec dsaSpec = (DSAParameterSpec) spec;
-                    return new byte[][] { dsaSpec.getG().toByteArray(),
-                            dsaSpec.getP().toByteArray(), dsaSpec.getQ().toByteArray() };
-                }
-                break;
         }
         return null;
     }
@@ -201,7 +285,26 @@
         }
 
         KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params;
+        String keyAlgorithm = getKeyAlgorithm(spec);
+        int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm);
+        if (keyType == -1) {
+            throw new InvalidAlgorithmParameterException(
+                    "Unsupported key algorithm: " + keyAlgorithm);
+        }
+        int keySize = spec.getKeySize();
+        if (keySize == -1) {
+            keySize = getDefaultKeySize(keyType);
+            if (keySize == -1) {
+                throw new InvalidAlgorithmParameterException(
+                    "Unsupported key algorithm: " + keyAlgorithm);
+            }
+        }
+        checkCorrectParametersSpec(keyType, keySize, spec.getAlgorithmParameterSpec());
+        checkValidKeySize(keyAlgorithm, keyType, keySize);
 
+        mKeyAlgorithm = keyAlgorithm;
+        mKeyType = keyType;
+        mKeySize = keySize;
         mSpec = spec;
         mKeyStore = android.security.KeyStore.getInstance();
     }
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index b17e450..9081e92 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -33,6 +33,7 @@
         put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
 
         // java.security.KeyPairGenerator
-        put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.class.getName());
+        put("KeyPairGenerator.EC", AndroidKeyPairGenerator.EC.class.getName());
+        put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.RSA.class.getName());
     }
 }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 131e689..e9c24dd 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -127,6 +127,12 @@
      * Extra for use with {@link #ACTION_CHOOSER}
      * @hide Also used by KeyChainActivity implementation
      */
+    public static final String EXTRA_URL = "url";
+
+    /**
+     * Extra for use with {@link #ACTION_CHOOSER}
+     * @hide Also used by KeyChainActivity implementation
+     */
     public static final String EXTRA_ALIAS = "alias";
 
     /**
@@ -224,6 +230,9 @@
      * selected alias or null will be returned via the
      * KeyChainAliasCallback callback.
      *
+     * <p>The device or profile owner can intercept this before the activity
+     * is shown, to pick a specific private key alias.
+     *
      * <p>{@code keyTypes} and {@code issuers} may be used to
      * highlight suggested choices to the user, although to cope with
      * sometimes erroneous values provided by servers, the user may be
@@ -253,8 +262,52 @@
      *     unavailable.
      */
     public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response,
+            String[] keyTypes, Principal[] issuers, String host, int port, String alias) {
+        choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias);
+    }
+
+    /**
+     * Launches an {@code Activity} for the user to select the alias
+     * for a private key and certificate pair for authentication. The
+     * selected alias or null will be returned via the
+     * KeyChainAliasCallback callback.
+     *
+     * <p>The device or profile owner can intercept this before the activity
+     * is shown, to pick a specific private key alias.</p>
+     *
+     * <p>{@code keyTypes} and {@code issuers} may be used to
+     * highlight suggested choices to the user, although to cope with
+     * sometimes erroneous values provided by servers, the user may be
+     * able to override these suggestions.
+     *
+     * <p>{@code host} and {@code port} may be used to give the user
+     * more context about the server requesting the credentials.
+     *
+     * <p>{@code alias} allows the chooser to preselect an existing
+     * alias which will still be subject to user confirmation.
+     *
+     * @param activity The {@link Activity} context to use for
+     *     launching the new sub-Activity to prompt the user to select
+     *     a private key; used only to call startActivity(); must not
+     *     be null.
+     * @param response Callback to invoke when the request completes;
+     *     must not be null
+     * @param keyTypes The acceptable types of asymmetric keys such as
+     *     "EC" or "RSA", or a null array.
+     * @param issuers The acceptable certificate issuers for the
+     *     certificate matching the private key, or null.
+     * @param host The host name of the server requesting the
+     *     certificate, or null if unavailable.
+     * @param port The port number of the server requesting the
+     *     certificate, or -1 if unavailable.
+     * @param url The full url the server is requesting the certificate
+     *     for, or null if unavailable.
+     * @param alias The alias to preselect if available, or null if
+     *     unavailable.
+     */
+    public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response,
                                              String[] keyTypes, Principal[] issuers,
-                                             String host, int port,
+                                             String host, int port, String url,
                                              String alias) {
         /*
          * TODO currently keyTypes, issuers are unused. They are meant
@@ -263,7 +316,7 @@
          *
          * keyTypes would allow the list to be filtered and typically
          * will be set correctly by the server. In practice today,
-         * most all users will want only RSA, rarely DSA, and usually
+         * most all users will want only RSA or EC, and usually
          * only a small number of certs will be available.
          *
          * issuers is typically not useful. Some servers historically
@@ -283,6 +336,7 @@
         intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
         intent.putExtra(EXTRA_HOST, host);
         intent.putExtra(EXTRA_PORT, port);
+        intent.putExtra(EXTRA_URL, url);
         intent.putExtra(EXTRA_ALIAS, alias);
         // the PendingIntent is used to get calling package name
         intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0));
@@ -379,7 +433,7 @@
      */
     public static boolean isKeyAlgorithmSupported(String algorithm) {
         final String algUpper = algorithm.toUpperCase(Locale.US);
-        return "DSA".equals(algUpper) || "EC".equals(algUpper) || "RSA".equals(algUpper);
+        return "EC".equals(algUpper) || "RSA".equals(algUpper);
     }
 
     /**
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 4a823cc..cc097aa 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -16,8 +16,6 @@
 
 package android.security;
 
-import com.android.org.conscrypt.NativeCrypto;
-
 import android.content.Context;
 import android.text.TextUtils;
 
@@ -26,8 +24,6 @@
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
 import java.util.Date;
 
 import javax.security.auth.x500.X500Principal;
@@ -55,24 +51,6 @@
  * certificate signed by a real Certificate Authority.
  */
 public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
-    /*
-     * These must be kept in sync with system/security/keystore/defaults.h
-     */
-
-    /* DSA */
-    private static final int DSA_DEFAULT_KEY_SIZE = 1024;
-    private static final int DSA_MIN_KEY_SIZE = 512;
-    private static final int DSA_MAX_KEY_SIZE = 8192;
-
-    /* EC */
-    private static final int EC_DEFAULT_KEY_SIZE = 256;
-    private static final int EC_MIN_KEY_SIZE = 192;
-    private static final int EC_MAX_KEY_SIZE = 521;
-
-    /* RSA */
-    private static final int RSA_DEFAULT_KEY_SIZE = 2048;
-    private static final int RSA_MIN_KEY_SIZE = 512;
-    private static final int RSA_MAX_KEY_SIZE = 8192;
 
     private final Context mContext;
 
@@ -114,7 +92,7 @@
      * @param context Android context for the activity
      * @param keyStoreAlias name to use for the generated key in the Android
      *            keystore
-     * @param keyType key algorithm to use (RSA, DSA, EC)
+     * @param keyType key algorithm to use (EC, RSA)
      * @param keySize size of key to generate
      * @param spec the underlying key type parameters
      * @param subjectDN X.509 v3 Subject Distinguished Name
@@ -145,13 +123,6 @@
             throw new IllegalArgumentException("endDate < startDate");
         }
 
-        final int keyTypeInt = KeyStore.getKeyTypeForAlgorithm(keyType);
-        if (keySize == -1) {
-            keySize = getDefaultKeySizeForType(keyTypeInt);
-        }
-        checkCorrectParametersSpec(keyTypeInt, keySize, spec);
-        checkValidKeySize(keyTypeInt, keySize);
-
         mContext = context;
         mKeystoreAlias = keyStoreAlias;
         mKeyType = keyType;
@@ -164,57 +135,6 @@
         mFlags = flags;
     }
 
-    private static int getDefaultKeySizeForType(int keyType) {
-        if (keyType == NativeCrypto.EVP_PKEY_DSA) {
-            return DSA_DEFAULT_KEY_SIZE;
-        } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
-            return EC_DEFAULT_KEY_SIZE;
-        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
-            return RSA_DEFAULT_KEY_SIZE;
-        }
-        throw new IllegalArgumentException("Invalid key type " + keyType);
-    }
-
-    private static void checkValidKeySize(int keyType, int keySize) {
-        if (keyType == NativeCrypto.EVP_PKEY_DSA) {
-            if (keySize < DSA_MIN_KEY_SIZE || keySize > DSA_MAX_KEY_SIZE) {
-                throw new IllegalArgumentException("DSA keys must be >= " + DSA_MIN_KEY_SIZE
-                        + " and <= " + DSA_MAX_KEY_SIZE);
-            }
-        } else if (keyType == NativeCrypto.EVP_PKEY_EC) {
-            if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
-                throw new IllegalArgumentException("EC keys must be >= " + EC_MIN_KEY_SIZE
-                        + " and <= " + EC_MAX_KEY_SIZE);
-            }
-        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
-            if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
-                throw new IllegalArgumentException("RSA keys must be >= " + RSA_MIN_KEY_SIZE
-                        + " and <= " + RSA_MAX_KEY_SIZE);
-            }
-        } else {
-            throw new IllegalArgumentException("Invalid key type " + keyType);
-        }
-    }
-
-    private static void checkCorrectParametersSpec(int keyType, int keySize,
-            AlgorithmParameterSpec spec) {
-        if (keyType == NativeCrypto.EVP_PKEY_DSA && spec != null) {
-            if (!(spec instanceof DSAParameterSpec)) {
-                throw new IllegalArgumentException("DSA keys must have DSAParameterSpec specified");
-            }
-        } else if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
-            if (spec instanceof RSAKeyGenParameterSpec) {
-                RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
-                if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
-                    throw new IllegalArgumentException("RSA key size must match: " + keySize
-                            + " vs " + rsaSpec.getKeysize());
-                }
-            } else {
-                throw new IllegalArgumentException("RSA may only use RSAKeyGenParameterSpec");
-            }
-        }
-    }
-
     /**
      * Gets the Android context used for operations with this instance.
      */
@@ -231,8 +151,7 @@
     }
 
     /**
-     * Returns the key type (e.g., "RSA", "DSA", "EC") specified by this
-     * parameter.
+     * Returns the key type (e.g., "EC", "RSA") specified by this parameter.
      */
     public String getKeyType() {
         return mKeyType;
@@ -328,7 +247,7 @@
 
         private String mKeystoreAlias;
 
-        private String mKeyType = "RSA";
+        private String mKeyType;
 
         private int mKeySize = -1;
 
@@ -371,15 +290,13 @@
         }
 
         /**
-         * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created.
+         * Sets the key type (e.g., EC, RSA) of the keypair to be created.
          */
         public Builder setKeyType(String keyType) throws NoSuchAlgorithmException {
             if (keyType == null) {
                 throw new NullPointerException("keyType == null");
             } else {
-                try {
-                    KeyStore.getKeyTypeForAlgorithm(keyType);
-                } catch (IllegalArgumentException e) {
+                if (KeyStore.getKeyTypeForAlgorithm(keyType) == -1) {
                     throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
                 }
             }
@@ -401,9 +318,8 @@
         }
 
         /**
-         * Sets the underlying key type's parameters. This is required for DSA
-         * where you must set this to an instance of
-         * {@link java.security.spec.DSAParameterSpec}.
+         * Sets the algorithm-specific key generation parameters. For example, for RSA keys
+         * this may be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}.
          */
         public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) {
             if (spec == null) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 0db8c77..bfbf028 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -18,8 +18,14 @@
 
 import com.android.org.conscrypt.NativeCrypto;
 
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.OperationResult;
 import android.util.Log;
 
 import java.util.Locale;
@@ -58,6 +64,8 @@
 
     private final IKeystoreService mBinder;
 
+    private IBinder mToken;
+
     private KeyStore(IKeystoreService binder) {
         mBinder = binder;
     }
@@ -68,15 +76,20 @@
         return new KeyStore(keystore);
     }
 
-    static int getKeyTypeForAlgorithm(String keyType) throws IllegalArgumentException {
+    private synchronized IBinder getToken() {
+        if (mToken == null) {
+            mToken = new Binder();
+        }
+        return mToken;
+    }
+
+    static int getKeyTypeForAlgorithm(String keyType) {
         if ("RSA".equalsIgnoreCase(keyType)) {
             return NativeCrypto.EVP_PKEY_RSA;
-        } else if ("DSA".equalsIgnoreCase(keyType)) {
-            return NativeCrypto.EVP_PKEY_DSA;
         } else if ("EC".equalsIgnoreCase(keyType)) {
             return NativeCrypto.EVP_PKEY_EC;
         } else {
-            throw new IllegalArgumentException("Unsupported key type: " + keyType);
+            return -1;
         }
     }
 
@@ -207,7 +220,8 @@
     public boolean generate(String key, int uid, int keyType, int keySize, int flags,
             byte[][] args) {
         try {
-            return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR;
+            return mBinder.generate(key, uid, keyType, keySize, flags,
+                    new KeystoreArguments(args)) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -364,4 +378,100 @@
     public int getLastError() {
         return mError;
     }
+
+    public boolean addRngEntropy(byte[] data) {
+        try {
+            return mBinder.addRngEntropy(data) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public int generateKey(String alias, KeymasterArguments args, int uid, int flags,
+            KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.generateKey(alias, args, uid, flags, outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int generateKey(String alias, KeymasterArguments args, int flags,
+            KeyCharacteristics outCharacteristics) {
+        return generateKey(alias, args, UID_SELF, flags, outCharacteristics);
+    }
+
+    public int getKeyCharacteristics(String alias, byte[] clientId, byte[] appId,
+            KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
+            int uid, int flags, KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.importKey(alias, args, format, keyData, uid, flags,
+                    outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
+            int flags, KeyCharacteristics outCharacteristics) {
+        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
+    }
+
+    public ExportResult exportKey(String alias, int format, byte[] clientId, byte[] appId) {
+        try {
+            return mBinder.exportKey(alias, format, clientId, appId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult begin(String alias, int purpose, boolean pruneable,
+            KeymasterArguments args, KeymasterArguments outArgs) {
+        try {
+            return mBinder.begin(getToken(), alias, purpose, pruneable, args, outArgs);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
+        try {
+            return mBinder.update(token, arguments, input);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
+        try {
+            return mBinder.finish(token, arguments, signature);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public int abort(IBinder token) {
+        try {
+            return mBinder.abort(token);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
 }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
index ea6c43d..95d14b7 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -27,12 +27,9 @@
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAParams;
-import java.security.interfaces.DSAPublicKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.DSAParameterSpec;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -155,167 +152,6 @@
                 NOW_PLUS_10_YEARS);
     }
 
-    public void testKeyPairGenerator_GenerateKeyPair_DSA_Unencrypted_Success() throws Exception {
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("DSA")
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "DSA", 1024, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_DSA_2048_Unencrypted_Success()
-            throws Exception {
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("DSA")
-                .setKeySize(2048)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "DSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_DSA_SpecifiedParams_Unencrypted_Success()
-            throws Exception {
-        /*
-         * generated using: openssl dsaparam -C 2048
-         */
-        BigInteger p = new BigInteger(1, new byte[] {
-                (byte) 0xC0, (byte) 0x3D, (byte) 0x86, (byte) 0x09, (byte) 0xCA, (byte) 0x8C,
-                (byte) 0x37, (byte) 0xCA, (byte) 0xCC, (byte) 0x4A, (byte) 0x81, (byte) 0xBD,
-                (byte) 0xD8, (byte) 0x50, (byte) 0x77, (byte) 0xCD, (byte) 0xDD, (byte) 0x32,
-                (byte) 0x0B, (byte) 0x43, (byte) 0xBF, (byte) 0x42, (byte) 0x06, (byte) 0x5A,
-                (byte) 0x3D, (byte) 0x18, (byte) 0x50, (byte) 0x47, (byte) 0x79, (byte) 0xE1,
-                (byte) 0x5B, (byte) 0x86, (byte) 0x03, (byte) 0xB9, (byte) 0x28, (byte) 0x9C,
-                (byte) 0x18, (byte) 0xA9, (byte) 0xF5, (byte) 0xD6, (byte) 0xF4, (byte) 0x94,
-                (byte) 0x5B, (byte) 0x87, (byte) 0x58, (byte) 0xCA, (byte) 0xB2, (byte) 0x1E,
-                (byte) 0xFC, (byte) 0xED, (byte) 0x37, (byte) 0xC3, (byte) 0x49, (byte) 0xAC,
-                (byte) 0xFA, (byte) 0x46, (byte) 0xDB, (byte) 0x7A, (byte) 0x50, (byte) 0x96,
-                (byte) 0xCF, (byte) 0x52, (byte) 0xD7, (byte) 0x4E, (byte) 0xEB, (byte) 0x26,
-                (byte) 0x41, (byte) 0xA2, (byte) 0x6F, (byte) 0x99, (byte) 0x80, (byte) 0x9F,
-                (byte) 0x0F, (byte) 0x0A, (byte) 0xA8, (byte) 0x0D, (byte) 0xAC, (byte) 0xAB,
-                (byte) 0xEF, (byte) 0x7D, (byte) 0xE7, (byte) 0x4C, (byte) 0xF1, (byte) 0x88,
-                (byte) 0x44, (byte) 0xC9, (byte) 0x17, (byte) 0xD0, (byte) 0xBB, (byte) 0xE2,
-                (byte) 0x01, (byte) 0x8C, (byte) 0xC1, (byte) 0x02, (byte) 0x1D, (byte) 0x3C,
-                (byte) 0x15, (byte) 0xB7, (byte) 0x41, (byte) 0x30, (byte) 0xD8, (byte) 0x11,
-                (byte) 0xBD, (byte) 0x6A, (byte) 0x2A, (byte) 0x0D, (byte) 0x36, (byte) 0x44,
-                (byte) 0x9C, (byte) 0x3F, (byte) 0x32, (byte) 0xE2, (byte) 0x1C, (byte) 0xFB,
-                (byte) 0xE3, (byte) 0xFF, (byte) 0xCC, (byte) 0x1A, (byte) 0x72, (byte) 0x38,
-                (byte) 0x37, (byte) 0x69, (byte) 0x5E, (byte) 0x35, (byte) 0x73, (byte) 0xE1,
-                (byte) 0x1E, (byte) 0x74, (byte) 0x35, (byte) 0x44, (byte) 0x07, (byte) 0xB5,
-                (byte) 0x2F, (byte) 0x0B, (byte) 0x60, (byte) 0xF4, (byte) 0xA9, (byte) 0xE0,
-                (byte) 0x81, (byte) 0xB2, (byte) 0xCD, (byte) 0x8B, (byte) 0x82, (byte) 0x76,
-                (byte) 0x7F, (byte) 0xD4, (byte) 0x17, (byte) 0x32, (byte) 0x86, (byte) 0x98,
-                (byte) 0x7C, (byte) 0x85, (byte) 0x66, (byte) 0xF6, (byte) 0x77, (byte) 0xED,
-                (byte) 0x8B, (byte) 0x1A, (byte) 0x52, (byte) 0x16, (byte) 0xDA, (byte) 0x1C,
-                (byte) 0xA7, (byte) 0x16, (byte) 0x79, (byte) 0x20, (byte) 0x1C, (byte) 0x99,
-                (byte) 0x5F, (byte) 0x12, (byte) 0x66, (byte) 0x15, (byte) 0x9F, (byte) 0xE5,
-                (byte) 0x73, (byte) 0xA9, (byte) 0x61, (byte) 0xBA, (byte) 0xA7, (byte) 0x23,
-                (byte) 0x93, (byte) 0x77, (byte) 0xB5, (byte) 0xF6, (byte) 0xEC, (byte) 0x13,
-                (byte) 0xBF, (byte) 0x95, (byte) 0x60, (byte) 0x78, (byte) 0x84, (byte) 0xE3,
-                (byte) 0x44, (byte) 0xEC, (byte) 0x74, (byte) 0xC2, (byte) 0xCB, (byte) 0xD4,
-                (byte) 0x70, (byte) 0xC5, (byte) 0x7B, (byte) 0xF8, (byte) 0x07, (byte) 0x3B,
-                (byte) 0xEB, (byte) 0x9F, (byte) 0xC9, (byte) 0x7D, (byte) 0xE0, (byte) 0xA5,
-                (byte) 0xBA, (byte) 0x68, (byte) 0x7B, (byte) 0xF4, (byte) 0x70, (byte) 0x40,
-                (byte) 0xAE, (byte) 0xE9, (byte) 0x65, (byte) 0xEE, (byte) 0x5B, (byte) 0x71,
-                (byte) 0x36, (byte) 0x0B, (byte) 0xB0, (byte) 0xA2, (byte) 0x98, (byte) 0x7D,
-                (byte) 0xE3, (byte) 0x24, (byte) 0x95, (byte) 0x2B, (byte) 0xC2, (byte) 0x0A,
-                (byte) 0x78, (byte) 0x3D, (byte) 0xCC, (byte) 0x3A, (byte) 0xEE, (byte) 0xED,
-                (byte) 0x48, (byte) 0xEB, (byte) 0xA3, (byte) 0x78, (byte) 0xA8, (byte) 0x9D,
-                (byte) 0x0A, (byte) 0x8F, (byte) 0x9E, (byte) 0x59, (byte) 0x2C, (byte) 0x44,
-                (byte) 0xB5, (byte) 0xF9, (byte) 0x53, (byte) 0x43,
-        });
-
-        BigInteger q = new BigInteger(1, new byte[] {
-                (byte) 0xA1, (byte) 0x9B, (byte) 0x1D, (byte) 0xC0, (byte) 0xE3, (byte) 0xF6,
-                (byte) 0x4A, (byte) 0x35, (byte) 0xE1, (byte) 0x8A, (byte) 0x43, (byte) 0xC2,
-                (byte) 0x9C, (byte) 0xF9, (byte) 0x52, (byte) 0x8F, (byte) 0x94, (byte) 0xA1,
-                (byte) 0x12, (byte) 0x11, (byte) 0xDB, (byte) 0x9A, (byte) 0xB6, (byte) 0x35,
-                (byte) 0x56, (byte) 0x26, (byte) 0x60, (byte) 0x89, (byte) 0x11, (byte) 0xAC,
-                (byte) 0xA8, (byte) 0xE5,
-        });
-
-        BigInteger g = new BigInteger(1, new byte[] {
-                (byte) 0xA1, (byte) 0x5C, (byte) 0x57, (byte) 0x15, (byte) 0xC3, (byte) 0xD9,
-                (byte) 0xD7, (byte) 0x41, (byte) 0x89, (byte) 0xD6, (byte) 0xB8, (byte) 0x7B,
-                (byte) 0xF3, (byte) 0xE0, (byte) 0xB3, (byte) 0xC5, (byte) 0xD1, (byte) 0xAA,
-                (byte) 0xF9, (byte) 0x55, (byte) 0x48, (byte) 0xF1, (byte) 0xDA, (byte) 0xE8,
-                (byte) 0x6F, (byte) 0x51, (byte) 0x05, (byte) 0xB2, (byte) 0xC9, (byte) 0x64,
-                (byte) 0xDA, (byte) 0x5F, (byte) 0xD4, (byte) 0xAA, (byte) 0xFD, (byte) 0x67,
-                (byte) 0xE0, (byte) 0x10, (byte) 0x2C, (byte) 0x1F, (byte) 0x03, (byte) 0x10,
-                (byte) 0xD4, (byte) 0x4B, (byte) 0x20, (byte) 0x82, (byte) 0x2B, (byte) 0x04,
-                (byte) 0xF9, (byte) 0x09, (byte) 0xAE, (byte) 0x28, (byte) 0x3D, (byte) 0x9B,
-                (byte) 0xFF, (byte) 0x87, (byte) 0x76, (byte) 0xCD, (byte) 0xF0, (byte) 0x11,
-                (byte) 0xB7, (byte) 0xEA, (byte) 0xE6, (byte) 0xCD, (byte) 0x60, (byte) 0xD3,
-                (byte) 0x8C, (byte) 0x74, (byte) 0xD3, (byte) 0x45, (byte) 0x63, (byte) 0x69,
-                (byte) 0x3F, (byte) 0x1D, (byte) 0x31, (byte) 0x25, (byte) 0x49, (byte) 0x97,
-                (byte) 0x4B, (byte) 0x73, (byte) 0x34, (byte) 0x12, (byte) 0x73, (byte) 0x27,
-                (byte) 0x4C, (byte) 0xDA, (byte) 0xF3, (byte) 0x08, (byte) 0xA8, (byte) 0xA9,
-                (byte) 0x27, (byte) 0xE4, (byte) 0xB8, (byte) 0xD6, (byte) 0xB5, (byte) 0xC4,
-                (byte) 0x18, (byte) 0xED, (byte) 0xBD, (byte) 0x6F, (byte) 0xA2, (byte) 0x36,
-                (byte) 0xA2, (byte) 0x9C, (byte) 0x27, (byte) 0x62, (byte) 0x7F, (byte) 0x93,
-                (byte) 0xD7, (byte) 0x52, (byte) 0xA9, (byte) 0x76, (byte) 0x55, (byte) 0x99,
-                (byte) 0x00, (byte) 0x5B, (byte) 0xC2, (byte) 0xB9, (byte) 0x18, (byte) 0xAC,
-                (byte) 0x6B, (byte) 0x83, (byte) 0x0D, (byte) 0xA1, (byte) 0xC5, (byte) 0x01,
-                (byte) 0x1A, (byte) 0xE5, (byte) 0x4D, (byte) 0x2F, (byte) 0xCF, (byte) 0x5D,
-                (byte) 0xB2, (byte) 0xE7, (byte) 0xC7, (byte) 0xCB, (byte) 0x2C, (byte) 0xFF,
-                (byte) 0x51, (byte) 0x1B, (byte) 0x9D, (byte) 0xA4, (byte) 0x05, (byte) 0xEB,
-                (byte) 0x17, (byte) 0xD8, (byte) 0x97, (byte) 0x9D, (byte) 0x0C, (byte) 0x59,
-                (byte) 0x92, (byte) 0x8A, (byte) 0x03, (byte) 0x34, (byte) 0xFD, (byte) 0x16,
-                (byte) 0x0F, (byte) 0x2A, (byte) 0xF9, (byte) 0x7D, (byte) 0xC3, (byte) 0x41,
-                (byte) 0x0D, (byte) 0x06, (byte) 0x5A, (byte) 0x4B, (byte) 0x34, (byte) 0xD5,
-                (byte) 0xF5, (byte) 0x09, (byte) 0x1C, (byte) 0xCE, (byte) 0xA7, (byte) 0x19,
-                (byte) 0x6D, (byte) 0x04, (byte) 0x53, (byte) 0x71, (byte) 0xCC, (byte) 0x84,
-                (byte) 0xA0, (byte) 0xB2, (byte) 0xA0, (byte) 0x68, (byte) 0xA3, (byte) 0x40,
-                (byte) 0xC0, (byte) 0x67, (byte) 0x38, (byte) 0x96, (byte) 0x73, (byte) 0x2E,
-                (byte) 0x8E, (byte) 0x2A, (byte) 0x9D, (byte) 0x56, (byte) 0xE9, (byte) 0xAC,
-                (byte) 0xC7, (byte) 0xEC, (byte) 0x84, (byte) 0x7F, (byte) 0xFC, (byte) 0xE0,
-                (byte) 0x69, (byte) 0x03, (byte) 0x8B, (byte) 0x48, (byte) 0x64, (byte) 0x76,
-                (byte) 0x85, (byte) 0xA5, (byte) 0x10, (byte) 0xD9, (byte) 0x31, (byte) 0xC3,
-                (byte) 0x8B, (byte) 0x07, (byte) 0x48, (byte) 0x62, (byte) 0xF6, (byte) 0x68,
-                (byte) 0xF2, (byte) 0x96, (byte) 0xB2, (byte) 0x18, (byte) 0x5B, (byte) 0xFF,
-                (byte) 0x6D, (byte) 0xD1, (byte) 0x6B, (byte) 0xF5, (byte) 0xFD, (byte) 0x81,
-                (byte) 0xF1, (byte) 0xFD, (byte) 0x04, (byte) 0xF0, (byte) 0x9F, (byte) 0xB7,
-                (byte) 0x08, (byte) 0x95, (byte) 0x57, (byte) 0x48, (byte) 0x07, (byte) 0x00,
-                (byte) 0x52, (byte) 0xEC, (byte) 0x75, (byte) 0x91, (byte) 0x02, (byte) 0x11,
-                (byte) 0xA3, (byte) 0x64, (byte) 0x26, (byte) 0xCA,
-        });
-
-        AlgorithmParameterSpec spec = new DSAParameterSpec(p, q, g);
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("DSA")
-                .setKeySize(2048)
-                .setAlgorithmParameterSpec(spec)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "DSA", 2048, spec, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
     public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
         mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
@@ -469,17 +305,7 @@
         assertNotNull("The PublicKey for the KeyPair should be not null", pubKey);
         assertEquals(keyType, pubKey.getAlgorithm());
 
-        if ("DSA".equalsIgnoreCase(keyType)) {
-            DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey;
-            DSAParams actualParams = dsaPubKey.getParams();
-            assertEquals(keySize, (actualParams.getP().bitLength() + 7) & ~7);
-            if (spec != null) {
-                DSAParameterSpec expectedParams = (DSAParameterSpec) spec;
-                assertEquals(expectedParams.getP(), actualParams.getP());
-                assertEquals(expectedParams.getQ(), actualParams.getQ());
-                assertEquals(expectedParams.getG(), actualParams.getG());
-            }
-        } else if ("EC".equalsIgnoreCase(keyType)) {
+        if ("EC".equalsIgnoreCase(keyType)) {
             assertEquals("Curve should be what was specified during initialization", keySize,
                     ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize());
         } else if ("RSA".equalsIgnoreCase(keyType)) {
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index 6597d3f..9775e64 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -20,7 +20,6 @@
 
 import com.android.org.conscrypt.NativeCrypto;
 import com.android.org.conscrypt.OpenSSLEngine;
-import com.android.org.conscrypt.OpenSSLKeyHolder;
 
 import android.test.AndroidTestCase;
 
@@ -41,8 +40,6 @@
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.DSAPublicKey;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPrivateKey;
@@ -722,368 +719,6 @@
             (byte) 0x7e, (byte) 0xde, (byte) 0xb2
     };
 
-    /*
-     * The keys and certificates below are generated with:
-     *
-     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
-     * openssl dsaparam -out dsaparam.pem 1024
-     * openssl req -newkey dsa:dsaparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req
-     * mkdir -p demoCA/newcerts
-     * touch demoCA/index.txt
-     * echo "01" > demoCA/serial
-     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
-     */
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_DSA_CA_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x8a, (byte) 0x30, (byte) 0x82,
-            (byte) 0x01, (byte) 0xf3, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0x87, (byte) 0xc0,
-            (byte) 0x68, (byte) 0x7f, (byte) 0x42, (byte) 0x92, (byte) 0x0b, (byte) 0x7a,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x5e, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
-            (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
-            (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
-            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
-            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
-            (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
-            (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
-            (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
-            (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17, (byte) 0x30, (byte) 0x15,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c,
-            (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
-            (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
-            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17,
-            (byte) 0x0d, (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32,
-            (byte) 0x37, (byte) 0x32, (byte) 0x33, (byte) 0x33, (byte) 0x31, (byte) 0x32,
-            (byte) 0x39, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33,
-            (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x32, (byte) 0x33,
-            (byte) 0x33, (byte) 0x31, (byte) 0x32, (byte) 0x39, (byte) 0x5a, (byte) 0x30,
-            (byte) 0x5e, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02,
-            (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c,
-            (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d,
-            (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31,
-            (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e,
-            (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74,
-            (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69,
-            (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79,
-            (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x17,
-            (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x03, (byte) 0x0c, (byte) 0x0e, (byte) 0x63, (byte) 0x61, (byte) 0x2e,
-            (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c,
-            (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30,
-            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
-            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
-            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa4, (byte) 0xc7,
-            (byte) 0x06, (byte) 0xba, (byte) 0xdf, (byte) 0x2b, (byte) 0xee, (byte) 0xd2,
-            (byte) 0xb9, (byte) 0xe4, (byte) 0x52, (byte) 0x21, (byte) 0x68, (byte) 0x2b,
-            (byte) 0x83, (byte) 0xdf, (byte) 0xe3, (byte) 0x9c, (byte) 0x08, (byte) 0x73,
-            (byte) 0xdd, (byte) 0x90, (byte) 0xea, (byte) 0x97, (byte) 0x0c, (byte) 0x96,
-            (byte) 0x20, (byte) 0xb1, (byte) 0xee, (byte) 0x11, (byte) 0xd5, (byte) 0xd4,
-            (byte) 0x7c, (byte) 0x44, (byte) 0x96, (byte) 0x2e, (byte) 0x6e, (byte) 0xa2,
-            (byte) 0xb2, (byte) 0xa3, (byte) 0x4b, (byte) 0x0f, (byte) 0x32, (byte) 0x90,
-            (byte) 0xaf, (byte) 0x5c, (byte) 0x6f, (byte) 0x00, (byte) 0x88, (byte) 0x45,
-            (byte) 0x4e, (byte) 0x9b, (byte) 0x26, (byte) 0xc1, (byte) 0x94, (byte) 0x3c,
-            (byte) 0xfe, (byte) 0x10, (byte) 0xbd, (byte) 0xda, (byte) 0xf2, (byte) 0x8d,
-            (byte) 0x03, (byte) 0x52, (byte) 0x32, (byte) 0x11, (byte) 0xff, (byte) 0xf6,
-            (byte) 0xf9, (byte) 0x6e, (byte) 0x8f, (byte) 0x0f, (byte) 0xc8, (byte) 0x0a,
-            (byte) 0x48, (byte) 0x39, (byte) 0x33, (byte) 0xb9, (byte) 0x0c, (byte) 0xb3,
-            (byte) 0x2b, (byte) 0xab, (byte) 0x7d, (byte) 0x79, (byte) 0x6f, (byte) 0x57,
-            (byte) 0x5b, (byte) 0xb8, (byte) 0x84, (byte) 0xb6, (byte) 0xcc, (byte) 0xe8,
-            (byte) 0x30, (byte) 0x78, (byte) 0xff, (byte) 0x92, (byte) 0xe5, (byte) 0x43,
-            (byte) 0x2e, (byte) 0xef, (byte) 0x66, (byte) 0x98, (byte) 0xb4, (byte) 0xfe,
-            (byte) 0xa2, (byte) 0x40, (byte) 0xf2, (byte) 0x1f, (byte) 0xd0, (byte) 0x86,
-            (byte) 0x16, (byte) 0xc8, (byte) 0x45, (byte) 0xc4, (byte) 0x52, (byte) 0xcb,
-            (byte) 0x31, (byte) 0x5c, (byte) 0x9f, (byte) 0x32, (byte) 0x3b, (byte) 0xf7,
-            (byte) 0x19, (byte) 0x08, (byte) 0xc7, (byte) 0x00, (byte) 0x21, (byte) 0x7d,
-            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
-            (byte) 0x50, (byte) 0x30, (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16,
-            (byte) 0x04, (byte) 0x14, (byte) 0x47, (byte) 0x82, (byte) 0xa3, (byte) 0xf1,
-            (byte) 0xc2, (byte) 0x7e, (byte) 0x3a, (byte) 0xde, (byte) 0x4f, (byte) 0x30,
-            (byte) 0x4c, (byte) 0x7f, (byte) 0x72, (byte) 0x81, (byte) 0x15, (byte) 0x32,
-            (byte) 0xda, (byte) 0x7f, (byte) 0x58, (byte) 0x18, (byte) 0x30, (byte) 0x1f,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04,
-            (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x47,
-            (byte) 0x82, (byte) 0xa3, (byte) 0xf1, (byte) 0xc2, (byte) 0x7e, (byte) 0x3a,
-            (byte) 0xde, (byte) 0x4f, (byte) 0x30, (byte) 0x4c, (byte) 0x7f, (byte) 0x72,
-            (byte) 0x81, (byte) 0x15, (byte) 0x32, (byte) 0xda, (byte) 0x7f, (byte) 0x58,
-            (byte) 0x18, (byte) 0x30, (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03,
-            (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06,
-            (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7,
-            (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00,
-            (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x08, (byte) 0x7f,
-            (byte) 0x6a, (byte) 0x48, (byte) 0x90, (byte) 0x7b, (byte) 0x9b, (byte) 0x72,
-            (byte) 0x13, (byte) 0xa7, (byte) 0xef, (byte) 0x6b, (byte) 0x0b, (byte) 0x59,
-            (byte) 0xe5, (byte) 0x49, (byte) 0x72, (byte) 0x3a, (byte) 0xc8, (byte) 0x84,
-            (byte) 0xcc, (byte) 0x23, (byte) 0x18, (byte) 0x4c, (byte) 0xec, (byte) 0xc7,
-            (byte) 0xef, (byte) 0xcb, (byte) 0xa7, (byte) 0xbe, (byte) 0xe4, (byte) 0xef,
-            (byte) 0x8f, (byte) 0xc6, (byte) 0x06, (byte) 0x8c, (byte) 0xc0, (byte) 0xe4,
-            (byte) 0x2f, (byte) 0x2a, (byte) 0xc0, (byte) 0x35, (byte) 0x7d, (byte) 0x5e,
-            (byte) 0x19, (byte) 0x29, (byte) 0x8c, (byte) 0xb9, (byte) 0xf1, (byte) 0x1e,
-            (byte) 0xaf, (byte) 0x82, (byte) 0xd8, (byte) 0xe3, (byte) 0x88, (byte) 0xe1,
-            (byte) 0x31, (byte) 0xc8, (byte) 0x82, (byte) 0x1f, (byte) 0x83, (byte) 0xa9,
-            (byte) 0xde, (byte) 0xfe, (byte) 0x4b, (byte) 0xe2, (byte) 0x78, (byte) 0x64,
-            (byte) 0xed, (byte) 0xa4, (byte) 0x7b, (byte) 0xee, (byte) 0x8d, (byte) 0x71,
-            (byte) 0x1b, (byte) 0x44, (byte) 0xe6, (byte) 0xb7, (byte) 0xe8, (byte) 0xc5,
-            (byte) 0x9a, (byte) 0x93, (byte) 0x92, (byte) 0x6f, (byte) 0x6f, (byte) 0xdb,
-            (byte) 0xbd, (byte) 0xd7, (byte) 0x03, (byte) 0x85, (byte) 0xa9, (byte) 0x5f,
-            (byte) 0x53, (byte) 0x5f, (byte) 0x5d, (byte) 0x30, (byte) 0xc6, (byte) 0xd9,
-            (byte) 0xce, (byte) 0x34, (byte) 0xa8, (byte) 0xbe, (byte) 0x31, (byte) 0x47,
-            (byte) 0x1c, (byte) 0xa4, (byte) 0x7f, (byte) 0xc0, (byte) 0x2c, (byte) 0xbc,
-            (byte) 0xfe, (byte) 0x1a, (byte) 0x31, (byte) 0xd8, (byte) 0x77, (byte) 0x4d,
-            (byte) 0xfc, (byte) 0x45, (byte) 0x84, (byte) 0xfc, (byte) 0x45, (byte) 0x12,
-            (byte) 0xab, (byte) 0x50, (byte) 0xe4, (byte) 0x45, (byte) 0xe5, (byte) 0x11
-    };
-
-    /**
-     * Generated from above and converted with: openssl pkcs8 -topk8 -outform d
-     * -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_DSA_KEY_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x4c, (byte) 0x02, (byte) 0x01,
-            (byte) 0x00, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x2c, (byte) 0x06,
-            (byte) 0x07, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x38,
-            (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1f,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xb3, (byte) 0x23,
-            (byte) 0xf7, (byte) 0x86, (byte) 0xbd, (byte) 0x3b, (byte) 0x86, (byte) 0xcc,
-            (byte) 0xc3, (byte) 0x91, (byte) 0xc0, (byte) 0x30, (byte) 0x32, (byte) 0x02,
-            (byte) 0x47, (byte) 0x35, (byte) 0x01, (byte) 0xef, (byte) 0xee, (byte) 0x98,
-            (byte) 0x13, (byte) 0x56, (byte) 0x49, (byte) 0x47, (byte) 0xb5, (byte) 0x20,
-            (byte) 0xa8, (byte) 0x60, (byte) 0xcb, (byte) 0xc0, (byte) 0xd5, (byte) 0x77,
-            (byte) 0xc1, (byte) 0x69, (byte) 0xcd, (byte) 0x18, (byte) 0x34, (byte) 0x92,
-            (byte) 0xf2, (byte) 0x6a, (byte) 0x2a, (byte) 0x10, (byte) 0x59, (byte) 0x1c,
-            (byte) 0x91, (byte) 0x20, (byte) 0x51, (byte) 0xca, (byte) 0x37, (byte) 0xb2,
-            (byte) 0x87, (byte) 0xa6, (byte) 0x8a, (byte) 0x02, (byte) 0xfd, (byte) 0x45,
-            (byte) 0x46, (byte) 0xf9, (byte) 0x76, (byte) 0xb1, (byte) 0x35, (byte) 0x38,
-            (byte) 0x8d, (byte) 0xff, (byte) 0x4c, (byte) 0x5d, (byte) 0x75, (byte) 0x8f,
-            (byte) 0x66, (byte) 0x15, (byte) 0x7d, (byte) 0x7b, (byte) 0xda, (byte) 0xdb,
-            (byte) 0x57, (byte) 0x39, (byte) 0xff, (byte) 0x91, (byte) 0x3f, (byte) 0xdd,
-            (byte) 0xe2, (byte) 0xb4, (byte) 0x22, (byte) 0x60, (byte) 0x4c, (byte) 0x32,
-            (byte) 0x3b, (byte) 0x9d, (byte) 0x34, (byte) 0x9f, (byte) 0xb9, (byte) 0x5d,
-            (byte) 0x75, (byte) 0xb9, (byte) 0xd3, (byte) 0x7f, (byte) 0x11, (byte) 0xba,
-            (byte) 0xb7, (byte) 0xc8, (byte) 0x32, (byte) 0xc6, (byte) 0xce, (byte) 0x71,
-            (byte) 0x91, (byte) 0xd3, (byte) 0x32, (byte) 0xaf, (byte) 0x4d, (byte) 0x7e,
-            (byte) 0x7c, (byte) 0x15, (byte) 0xf7, (byte) 0x71, (byte) 0x2c, (byte) 0x52,
-            (byte) 0x65, (byte) 0x4d, (byte) 0xa9, (byte) 0x81, (byte) 0x25, (byte) 0x35,
-            (byte) 0xce, (byte) 0x0b, (byte) 0x5b, (byte) 0x56, (byte) 0xfe, (byte) 0xf1,
-            (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xeb, (byte) 0x4e, (byte) 0x7f,
-            (byte) 0x7a, (byte) 0x31, (byte) 0xb3, (byte) 0x7d, (byte) 0x8d, (byte) 0xb2,
-            (byte) 0xf7, (byte) 0xaf, (byte) 0xad, (byte) 0xb1, (byte) 0x42, (byte) 0x92,
-            (byte) 0xf3, (byte) 0x6c, (byte) 0xe4, (byte) 0xed, (byte) 0x8b, (byte) 0x02,
-            (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x81, (byte) 0xc8, (byte) 0x36,
-            (byte) 0x48, (byte) 0xdb, (byte) 0x71, (byte) 0x2b, (byte) 0x91, (byte) 0xce,
-            (byte) 0x6d, (byte) 0xbc, (byte) 0xb8, (byte) 0xf9, (byte) 0xcb, (byte) 0x50,
-            (byte) 0x91, (byte) 0x10, (byte) 0x8a, (byte) 0xf8, (byte) 0x37, (byte) 0x50,
-            (byte) 0xda, (byte) 0x4f, (byte) 0xc8, (byte) 0x4d, (byte) 0x73, (byte) 0xcb,
-            (byte) 0x4d, (byte) 0xb0, (byte) 0x19, (byte) 0x54, (byte) 0x5a, (byte) 0xf3,
-            (byte) 0x6c, (byte) 0xc9, (byte) 0xd8, (byte) 0x96, (byte) 0xd9, (byte) 0xb0,
-            (byte) 0x54, (byte) 0x7e, (byte) 0x7d, (byte) 0xe2, (byte) 0x58, (byte) 0x0e,
-            (byte) 0x5f, (byte) 0xc0, (byte) 0xce, (byte) 0xb9, (byte) 0x5c, (byte) 0xe3,
-            (byte) 0xd3, (byte) 0xdf, (byte) 0xcf, (byte) 0x45, (byte) 0x74, (byte) 0xfb,
-            (byte) 0xe6, (byte) 0x20, (byte) 0xe7, (byte) 0xfc, (byte) 0x0f, (byte) 0xca,
-            (byte) 0xdb, (byte) 0xc0, (byte) 0x0b, (byte) 0xe1, (byte) 0x5a, (byte) 0x16,
-            (byte) 0x1d, (byte) 0xb3, (byte) 0x2e, (byte) 0xe5, (byte) 0x5f, (byte) 0x89,
-            (byte) 0x17, (byte) 0x73, (byte) 0x50, (byte) 0xd1, (byte) 0x4a, (byte) 0x60,
-            (byte) 0xb7, (byte) 0xaa, (byte) 0xf0, (byte) 0xc7, (byte) 0xc5, (byte) 0x03,
-            (byte) 0x4e, (byte) 0x36, (byte) 0x51, (byte) 0x9e, (byte) 0x2f, (byte) 0xfa,
-            (byte) 0xf3, (byte) 0xd6, (byte) 0x58, (byte) 0x14, (byte) 0x02, (byte) 0xb4,
-            (byte) 0x41, (byte) 0xd6, (byte) 0x72, (byte) 0x6f, (byte) 0x58, (byte) 0x5b,
-            (byte) 0x2d, (byte) 0x23, (byte) 0xc0, (byte) 0x75, (byte) 0x4f, (byte) 0x39,
-            (byte) 0xa8, (byte) 0x6a, (byte) 0xdf, (byte) 0x79, (byte) 0x21, (byte) 0xf2,
-            (byte) 0x77, (byte) 0x91, (byte) 0x3f, (byte) 0x1c, (byte) 0x4d, (byte) 0x48,
-            (byte) 0x78, (byte) 0xcd, (byte) 0xed, (byte) 0x79, (byte) 0x23, (byte) 0x04,
-            (byte) 0x17, (byte) 0x02, (byte) 0x15, (byte) 0x00, (byte) 0xc7, (byte) 0xe7,
-            (byte) 0xe2, (byte) 0x6b, (byte) 0x14, (byte) 0xe6, (byte) 0x31, (byte) 0x12,
-            (byte) 0xb2, (byte) 0x1e, (byte) 0xd4, (byte) 0xf2, (byte) 0x9b, (byte) 0x2c,
-            (byte) 0xf6, (byte) 0x54, (byte) 0x4c, (byte) 0x12, (byte) 0xe8, (byte) 0x22
-    };
-
-    /**
-     * Generated from above and converted with: openssl x509 -outform d -in
-     * usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_DSA_USER_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x03, (byte) 0xca, (byte) 0x30, (byte) 0x82,
-            (byte) 0x03, (byte) 0x33, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
-            (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
-            (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
-            (byte) 0x00, (byte) 0x30, (byte) 0x5e, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
-            (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
-            (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
-            (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
-            (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18,
-            (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e,
-            (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64,
-            (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50,
-            (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64,
-            (byte) 0x31, (byte) 0x17, (byte) 0x30, (byte) 0x15, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x0e, (byte) 0x63,
-            (byte) 0x61, (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d,
-            (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f,
-            (byte) 0x6d, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31,
-            (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x37, (byte) 0x32,
-            (byte) 0x33, (byte) 0x33, (byte) 0x34, (byte) 0x32, (byte) 0x32, (byte) 0x5a,
-            (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33, (byte) 0x30, (byte) 0x38,
-            (byte) 0x32, (byte) 0x35, (byte) 0x32, (byte) 0x33, (byte) 0x33, (byte) 0x34,
-            (byte) 0x32, (byte) 0x32, (byte) 0x5a, (byte) 0x30, (byte) 0x62, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
-            (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
-            (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
-            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
-            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
-            (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
-            (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
-            (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
-            (byte) 0x74, (byte) 0x64, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c,
-            (byte) 0x12, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65,
-            (byte) 0x72, (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d,
-            (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f,
-            (byte) 0x6d, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xb7, (byte) 0x30,
-            (byte) 0x82, (byte) 0x01, (byte) 0x2c, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
-            (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x38, (byte) 0x04, (byte) 0x01,
-            (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x1f, (byte) 0x02, (byte) 0x81,
-            (byte) 0x81, (byte) 0x00, (byte) 0xb3, (byte) 0x23, (byte) 0xf7, (byte) 0x86,
-            (byte) 0xbd, (byte) 0x3b, (byte) 0x86, (byte) 0xcc, (byte) 0xc3, (byte) 0x91,
-            (byte) 0xc0, (byte) 0x30, (byte) 0x32, (byte) 0x02, (byte) 0x47, (byte) 0x35,
-            (byte) 0x01, (byte) 0xef, (byte) 0xee, (byte) 0x98, (byte) 0x13, (byte) 0x56,
-            (byte) 0x49, (byte) 0x47, (byte) 0xb5, (byte) 0x20, (byte) 0xa8, (byte) 0x60,
-            (byte) 0xcb, (byte) 0xc0, (byte) 0xd5, (byte) 0x77, (byte) 0xc1, (byte) 0x69,
-            (byte) 0xcd, (byte) 0x18, (byte) 0x34, (byte) 0x92, (byte) 0xf2, (byte) 0x6a,
-            (byte) 0x2a, (byte) 0x10, (byte) 0x59, (byte) 0x1c, (byte) 0x91, (byte) 0x20,
-            (byte) 0x51, (byte) 0xca, (byte) 0x37, (byte) 0xb2, (byte) 0x87, (byte) 0xa6,
-            (byte) 0x8a, (byte) 0x02, (byte) 0xfd, (byte) 0x45, (byte) 0x46, (byte) 0xf9,
-            (byte) 0x76, (byte) 0xb1, (byte) 0x35, (byte) 0x38, (byte) 0x8d, (byte) 0xff,
-            (byte) 0x4c, (byte) 0x5d, (byte) 0x75, (byte) 0x8f, (byte) 0x66, (byte) 0x15,
-            (byte) 0x7d, (byte) 0x7b, (byte) 0xda, (byte) 0xdb, (byte) 0x57, (byte) 0x39,
-            (byte) 0xff, (byte) 0x91, (byte) 0x3f, (byte) 0xdd, (byte) 0xe2, (byte) 0xb4,
-            (byte) 0x22, (byte) 0x60, (byte) 0x4c, (byte) 0x32, (byte) 0x3b, (byte) 0x9d,
-            (byte) 0x34, (byte) 0x9f, (byte) 0xb9, (byte) 0x5d, (byte) 0x75, (byte) 0xb9,
-            (byte) 0xd3, (byte) 0x7f, (byte) 0x11, (byte) 0xba, (byte) 0xb7, (byte) 0xc8,
-            (byte) 0x32, (byte) 0xc6, (byte) 0xce, (byte) 0x71, (byte) 0x91, (byte) 0xd3,
-            (byte) 0x32, (byte) 0xaf, (byte) 0x4d, (byte) 0x7e, (byte) 0x7c, (byte) 0x15,
-            (byte) 0xf7, (byte) 0x71, (byte) 0x2c, (byte) 0x52, (byte) 0x65, (byte) 0x4d,
-            (byte) 0xa9, (byte) 0x81, (byte) 0x25, (byte) 0x35, (byte) 0xce, (byte) 0x0b,
-            (byte) 0x5b, (byte) 0x56, (byte) 0xfe, (byte) 0xf1, (byte) 0x02, (byte) 0x15,
-            (byte) 0x00, (byte) 0xeb, (byte) 0x4e, (byte) 0x7f, (byte) 0x7a, (byte) 0x31,
-            (byte) 0xb3, (byte) 0x7d, (byte) 0x8d, (byte) 0xb2, (byte) 0xf7, (byte) 0xaf,
-            (byte) 0xad, (byte) 0xb1, (byte) 0x42, (byte) 0x92, (byte) 0xf3, (byte) 0x6c,
-            (byte) 0xe4, (byte) 0xed, (byte) 0x8b, (byte) 0x02, (byte) 0x81, (byte) 0x81,
-            (byte) 0x00, (byte) 0x81, (byte) 0xc8, (byte) 0x36, (byte) 0x48, (byte) 0xdb,
-            (byte) 0x71, (byte) 0x2b, (byte) 0x91, (byte) 0xce, (byte) 0x6d, (byte) 0xbc,
-            (byte) 0xb8, (byte) 0xf9, (byte) 0xcb, (byte) 0x50, (byte) 0x91, (byte) 0x10,
-            (byte) 0x8a, (byte) 0xf8, (byte) 0x37, (byte) 0x50, (byte) 0xda, (byte) 0x4f,
-            (byte) 0xc8, (byte) 0x4d, (byte) 0x73, (byte) 0xcb, (byte) 0x4d, (byte) 0xb0,
-            (byte) 0x19, (byte) 0x54, (byte) 0x5a, (byte) 0xf3, (byte) 0x6c, (byte) 0xc9,
-            (byte) 0xd8, (byte) 0x96, (byte) 0xd9, (byte) 0xb0, (byte) 0x54, (byte) 0x7e,
-            (byte) 0x7d, (byte) 0xe2, (byte) 0x58, (byte) 0x0e, (byte) 0x5f, (byte) 0xc0,
-            (byte) 0xce, (byte) 0xb9, (byte) 0x5c, (byte) 0xe3, (byte) 0xd3, (byte) 0xdf,
-            (byte) 0xcf, (byte) 0x45, (byte) 0x74, (byte) 0xfb, (byte) 0xe6, (byte) 0x20,
-            (byte) 0xe7, (byte) 0xfc, (byte) 0x0f, (byte) 0xca, (byte) 0xdb, (byte) 0xc0,
-            (byte) 0x0b, (byte) 0xe1, (byte) 0x5a, (byte) 0x16, (byte) 0x1d, (byte) 0xb3,
-            (byte) 0x2e, (byte) 0xe5, (byte) 0x5f, (byte) 0x89, (byte) 0x17, (byte) 0x73,
-            (byte) 0x50, (byte) 0xd1, (byte) 0x4a, (byte) 0x60, (byte) 0xb7, (byte) 0xaa,
-            (byte) 0xf0, (byte) 0xc7, (byte) 0xc5, (byte) 0x03, (byte) 0x4e, (byte) 0x36,
-            (byte) 0x51, (byte) 0x9e, (byte) 0x2f, (byte) 0xfa, (byte) 0xf3, (byte) 0xd6,
-            (byte) 0x58, (byte) 0x14, (byte) 0x02, (byte) 0xb4, (byte) 0x41, (byte) 0xd6,
-            (byte) 0x72, (byte) 0x6f, (byte) 0x58, (byte) 0x5b, (byte) 0x2d, (byte) 0x23,
-            (byte) 0xc0, (byte) 0x75, (byte) 0x4f, (byte) 0x39, (byte) 0xa8, (byte) 0x6a,
-            (byte) 0xdf, (byte) 0x79, (byte) 0x21, (byte) 0xf2, (byte) 0x77, (byte) 0x91,
-            (byte) 0x3f, (byte) 0x1c, (byte) 0x4d, (byte) 0x48, (byte) 0x78, (byte) 0xcd,
-            (byte) 0xed, (byte) 0x79, (byte) 0x23, (byte) 0x03, (byte) 0x81, (byte) 0x84,
-            (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x1a, (byte) 0x50,
-            (byte) 0x9d, (byte) 0x3e, (byte) 0xa1, (byte) 0x6c, (byte) 0x99, (byte) 0x35,
-            (byte) 0x36, (byte) 0x26, (byte) 0x22, (byte) 0x6b, (byte) 0x47, (byte) 0x45,
-            (byte) 0x80, (byte) 0x5b, (byte) 0xd5, (byte) 0xc1, (byte) 0xc5, (byte) 0x70,
-            (byte) 0x75, (byte) 0x55, (byte) 0x66, (byte) 0x33, (byte) 0x1d, (byte) 0xae,
-            (byte) 0xd0, (byte) 0x01, (byte) 0x64, (byte) 0x8b, (byte) 0xae, (byte) 0x9d,
-            (byte) 0x66, (byte) 0x58, (byte) 0xf9, (byte) 0x42, (byte) 0x74, (byte) 0x3a,
-            (byte) 0x32, (byte) 0xc7, (byte) 0x7f, (byte) 0x25, (byte) 0x64, (byte) 0x7d,
-            (byte) 0x08, (byte) 0x26, (byte) 0xbf, (byte) 0x21, (byte) 0x3a, (byte) 0x84,
-            (byte) 0xcc, (byte) 0x2c, (byte) 0x66, (byte) 0x7d, (byte) 0xc7, (byte) 0xd6,
-            (byte) 0xb1, (byte) 0x69, (byte) 0x57, (byte) 0x67, (byte) 0x52, (byte) 0x73,
-            (byte) 0x3f, (byte) 0x79, (byte) 0x60, (byte) 0xaa, (byte) 0xf4, (byte) 0x8a,
-            (byte) 0x48, (byte) 0x42, (byte) 0x46, (byte) 0x41, (byte) 0xd0, (byte) 0x50,
-            (byte) 0x9b, (byte) 0xa2, (byte) 0x4e, (byte) 0xa5, (byte) 0x88, (byte) 0x10,
-            (byte) 0xf7, (byte) 0x61, (byte) 0xa2, (byte) 0xfa, (byte) 0x8d, (byte) 0xa6,
-            (byte) 0x13, (byte) 0x9e, (byte) 0x36, (byte) 0x86, (byte) 0x62, (byte) 0xf0,
-            (byte) 0x97, (byte) 0xef, (byte) 0x11, (byte) 0xc6, (byte) 0x35, (byte) 0xd3,
-            (byte) 0x79, (byte) 0x30, (byte) 0xde, (byte) 0xf2, (byte) 0x7f, (byte) 0x7a,
-            (byte) 0x3c, (byte) 0x03, (byte) 0xa3, (byte) 0xc5, (byte) 0xbc, (byte) 0xb1,
-            (byte) 0xbc, (byte) 0x2f, (byte) 0x10, (byte) 0xf4, (byte) 0x51, (byte) 0x89,
-            (byte) 0xe2, (byte) 0xaf, (byte) 0xf7, (byte) 0x61, (byte) 0x1a, (byte) 0xf0,
-            (byte) 0x87, (byte) 0x5e, (byte) 0xa5, (byte) 0x02, (byte) 0xd2, (byte) 0xe4,
-            (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30, (byte) 0x09,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04,
-            (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c, (byte) 0x06,
-            (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, (byte) 0x86,
-            (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04, (byte) 0x1f,
-            (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65, (byte) 0x6e,
-            (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47, (byte) 0x65,
-            (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74, (byte) 0x65,
-            (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72, (byte) 0x74,
-            (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, (byte) 0x74,
-            (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14,
-            (byte) 0xd1, (byte) 0x6c, (byte) 0x36, (byte) 0x36, (byte) 0x61, (byte) 0x6c,
-            (byte) 0xf6, (byte) 0x90, (byte) 0x82, (byte) 0x82, (byte) 0x87, (byte) 0x93,
-            (byte) 0xbe, (byte) 0x99, (byte) 0x60, (byte) 0x1b, (byte) 0x03, (byte) 0x58,
-            (byte) 0x36, (byte) 0x63, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30,
-            (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x47, (byte) 0x82, (byte) 0xa3,
-            (byte) 0xf1, (byte) 0xc2, (byte) 0x7e, (byte) 0x3a, (byte) 0xde, (byte) 0x4f,
-            (byte) 0x30, (byte) 0x4c, (byte) 0x7f, (byte) 0x72, (byte) 0x81, (byte) 0x15,
-            (byte) 0x32, (byte) 0xda, (byte) 0x7f, (byte) 0x58, (byte) 0x18, (byte) 0x30,
-            (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
-            (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
-            (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
-            (byte) 0x81, (byte) 0xde, (byte) 0x20, (byte) 0xa1, (byte) 0xb2, (byte) 0x50,
-            (byte) 0x03, (byte) 0xcd, (byte) 0x90, (byte) 0x4f, (byte) 0x2b, (byte) 0x47,
-            (byte) 0x1d, (byte) 0xac, (byte) 0x6e, (byte) 0xb4, (byte) 0xc7, (byte) 0x14,
-            (byte) 0xc6, (byte) 0x4f, (byte) 0x45, (byte) 0xaf, (byte) 0x81, (byte) 0x5d,
-            (byte) 0x5a, (byte) 0x31, (byte) 0xff, (byte) 0x9c, (byte) 0x4d, (byte) 0xdc,
-            (byte) 0x9e, (byte) 0x36, (byte) 0x9f, (byte) 0x9b, (byte) 0xb1, (byte) 0xc9,
-            (byte) 0x50, (byte) 0xa3, (byte) 0xf6, (byte) 0x9c, (byte) 0x68, (byte) 0x6f,
-            (byte) 0x68, (byte) 0xd9, (byte) 0x56, (byte) 0x1b, (byte) 0xe5, (byte) 0x1b,
-            (byte) 0x41, (byte) 0xd4, (byte) 0xcc, (byte) 0xb6, (byte) 0x37, (byte) 0xd5,
-            (byte) 0x69, (byte) 0x6b, (byte) 0x39, (byte) 0xaf, (byte) 0xc6, (byte) 0xb8,
-            (byte) 0x39, (byte) 0x76, (byte) 0xe3, (byte) 0xf7, (byte) 0x97, (byte) 0x74,
-            (byte) 0x31, (byte) 0xc4, (byte) 0x2d, (byte) 0xb7, (byte) 0x9a, (byte) 0xa4,
-            (byte) 0xfa, (byte) 0x9f, (byte) 0xa8, (byte) 0xe3, (byte) 0x41, (byte) 0xda,
-            (byte) 0x2f, (byte) 0x0c, (byte) 0x9d, (byte) 0x83, (byte) 0xdc, (byte) 0x86,
-            (byte) 0x1f, (byte) 0x5c, (byte) 0x0f, (byte) 0x87, (byte) 0x05, (byte) 0xc9,
-            (byte) 0xb0, (byte) 0x63, (byte) 0xca, (byte) 0x9b, (byte) 0xdb, (byte) 0xe6,
-            (byte) 0x3c, (byte) 0xe9, (byte) 0x23, (byte) 0x9e, (byte) 0x23, (byte) 0x44,
-            (byte) 0x1d, (byte) 0x5b, (byte) 0x60, (byte) 0x66, (byte) 0xb6, (byte) 0x72,
-            (byte) 0x8c, (byte) 0x87, (byte) 0x86, (byte) 0xe8, (byte) 0xdb, (byte) 0x29,
-            (byte) 0x67, (byte) 0x9c, (byte) 0x33, (byte) 0x5c, (byte) 0x39, (byte) 0xf1,
-            (byte) 0xb5, (byte) 0x9b, (byte) 0xb8, (byte) 0xe1, (byte) 0x42, (byte) 0x51,
-            (byte) 0xed, (byte) 0x2c
-    };
-
     /**
      * The amount of time to allow before and after expected time for variance
      * in timing tests.
@@ -1500,26 +1135,6 @@
                 FAKE_RSA_CA_1);
     }
 
-    public void testKeyStore_GetEntry_DSA_NullParams_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_DSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                FAKE_DSA_USER_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_DSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-
-        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Entry should exist", entry);
-
-        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-        assertPrivateKeyEntryEquals(keyEntry, "DSA", FAKE_DSA_KEY_1, FAKE_DSA_USER_1, FAKE_DSA_CA_1);
-    }
-
     public void testKeyStore_GetEntry_EC_NullParams_Unencrypted_Success() throws Exception {
         mKeyStore.load(null, null);
 
@@ -1583,11 +1198,7 @@
 
     private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
             Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
-        if (expectedKey instanceof DSAPrivateKey) {
-            assertEquals("Returned PrivateKey should be what we inserted",
-                    ((DSAPrivateKey) expectedKey).getParams(),
-                    ((DSAPublicKey) keyEntry.getCertificate().getPublicKey()).getParams());
-        } else if (expectedKey instanceof ECPrivateKey) {
+        if (expectedKey instanceof ECPrivateKey) {
             assertEquals("Returned PrivateKey should be what we inserted",
                     ((ECPrivateKey) expectedKey).getParams().getCurve(),
                     ((ECPublicKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
@@ -1871,33 +1482,6 @@
         assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1);
     }
 
-    public void testKeyStore_SetEntry_PrivateKeyEntry_DSA_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        KeyFactory keyFact = KeyFactory.getInstance("DSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_DSA_KEY_1));
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate[] expectedChain = new Certificate[2];
-        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_DSA_USER_1));
-        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_DSA_CA_1));
-
-        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Retrieved entry should exist", actualEntry);
-
-        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                actualEntry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-        assertPrivateKeyEntryEquals(actual, "DSA", FAKE_DSA_KEY_1, FAKE_DSA_USER_1, FAKE_DSA_CA_1);
-    }
-
     public void testKeyStore_SetEntry_PrivateKeyEntry_EC_Unencrypted_Success() throws Exception {
         mKeyStore.load(null, null);
 
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index c3cba2b..f935bb1 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -17,10 +17,19 @@
 package android.security;
 
 import android.app.Activity;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.Process;
+import android.os.ServiceManager;
 import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keymaster.OperationResult;
 import android.test.ActivityUnitTestCase;
 import android.test.AssertionFailedError;
+import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.MediumTest;
 import com.android.org.conscrypt.NativeCrypto;
 import java.nio.charset.StandardCharsets;
@@ -28,6 +37,9 @@
 import java.util.Date;
 import java.util.HashSet;
 
+import android.util.Log;
+import android.util.Base64;
+
 /**
  * Junit / Instrumentation test case for KeyStore class
  *
@@ -103,6 +115,8 @@
             "286BDA73F629296F5FA9146D8976357D3C751E75148696A40B74685C82CE30902D639D72" +
             "4FF24D5E2E9407EE34EDED2E3B4DF65AA9BCFEB6DF28D07BA6903F165768");
 
+    private static final byte[] AES256_BYTES = hexToBytes(
+            "0CC175B9C0F1B6A831C399E269772661CEC520EA51EA0A47E87295FA3245A605");
 
     private static byte[] hexToBytes(String s) {
         int len = s.length();
@@ -689,4 +703,208 @@
         assertEquals("-1 should be returned for non-existent key",
                 -1L, mKeyStore.getmtime(TEST_KEYNAME2));
     }
+
+    private KeyCharacteristics generateRsaKey(String name) throws Exception {
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+
+        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
+        int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
+        assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
+        return outCharacteristics;
+    }
+
+    public void testGenerateKey() throws Exception {
+        generateRsaKey("test");
+        mKeyStore.delete("test");
+    }
+    public void testGenerateAndDelete() throws Exception {
+        generateRsaKey("test");
+        assertTrue("delete should succeed", mKeyStore.delete("test"));
+    }
+
+    public void testGetKeyCharacteristicsSuccess() throws Exception {
+        mKeyStore.password(TEST_PASSWD);
+        String name = "test";
+        KeyCharacteristics gen = generateRsaKey(name);
+        KeyCharacteristics call = new KeyCharacteristics();
+        int result = mKeyStore.getKeyCharacteristics(name, null, null, call);
+        assertEquals("getKeyCharacteristics should succeed", KeyStore.NO_ERROR, result);
+        mKeyStore.delete("test");
+    }
+
+    public void testAppId() throws Exception {
+        String name = "test";
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, new byte[] {0x01, 0x02, 0x03});
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+
+        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
+        int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
+        assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
+        assertEquals("getKeyCharacteristics should fail without application ID",
+                KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB,
+                mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
+        assertEquals("getKeyCharacteristics should succeed with application ID",
+                KeyStore.NO_ERROR,
+                mKeyStore.getKeyCharacteristics(name, new byte[] {0x01, 0x02, 0x03}, null,
+                    outCharacteristics));
+    }
+
+
+    public void testExportRsa() throws Exception {
+        String name = "test";
+        generateRsaKey(name);
+        ExportResult result = mKeyStore.exportKey(name, KeymasterDefs.KM_KEY_FORMAT_X509, null,
+                null);
+        assertEquals("Export success", KeyStore.NO_ERROR, result.resultCode);
+        // TODO: Verify we have an RSA public key that's well formed.
+    }
+
+    public void testAesOcbEncryptSuccess() throws Exception {
+        String name = "test";
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
+        args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
+        args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+
+        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
+        int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
+        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
+
+        KeymasterArguments out = new KeymasterArguments();
+        args = new KeymasterArguments();
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
+                true, args, out);
+        IBinder token = result.token;
+        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
+        result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04});
+        assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode);
+        assertEquals("Finish should succeed", KeyStore.NO_ERROR,
+                mKeyStore.finish(token, null, null).resultCode);
+    }
+
+    public void testBadToken() throws Exception {
+        IBinder token = new Binder();
+        OperationResult result = mKeyStore.update(token, null, new byte[] {0x01});
+        assertEquals("Update with invalid token should fail",
+                KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, result.resultCode);
+    }
+
+    private int importAesKey(String name, byte[] key, int size, int mode) {
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mode);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, size);
+        return mKeyStore.importKey(name, args, KeymasterDefs.KM_KEY_FORMAT_RAW, key, 0,
+                new KeyCharacteristics());
+    }
+    private byte[] doOperation(String name, int purpose, byte[] in, KeymasterArguments beginArgs) {
+        KeymasterArguments out = new KeymasterArguments();
+        OperationResult result = mKeyStore.begin(name, purpose,
+                true, beginArgs, out);
+        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
+        IBinder token = result.token;
+        result = mKeyStore.update(token, null, in);
+        assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode);
+        assertEquals("All data should be consumed", in.length, result.inputConsumed);
+        assertEquals("Finish should succeed", KeyStore.NO_ERROR,
+                mKeyStore.finish(token, null, null).resultCode);
+        return result.output;
+    }
+
+    public void testImportAes() throws Exception {
+        int result = importAesKey("aes", AES256_BYTES, 256, KeymasterDefs.KM_MODE_ECB);
+        assertEquals("import should succeed", KeyStore.NO_ERROR, result);
+        mKeyStore.delete("aes");
+    }
+
+    public void testAes256Ecb() throws Exception {
+        byte[] key =
+                hexToBytes("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
+        String name = "aes";
+        assertEquals(KeyStore.NO_ERROR, importAesKey(name, key, 256, KeymasterDefs.KM_MODE_ECB));
+        byte[][] testVectors = new byte[][] {
+            hexToBytes("6bc1bee22e409f96e93d7e117393172a"),
+            hexToBytes("ae2d8a571e03ac9c9eb76fac45af8e51"),
+            hexToBytes("30c81c46a35ce411e5fbc1191a0a52ef"),
+            hexToBytes("f69f2445df4f9b17ad2b417be66c3710")};
+        byte[][] cipherVectors = new byte[][] {
+            hexToBytes("f3eed1bdb5d2a03c064b5a7e3db181f8"),
+            hexToBytes("591ccb10d410ed26dc5ba74a31362870"),
+            hexToBytes("b6ed21b99ca6f4f9f153e7b1beafed1d"),
+            hexToBytes("23304b7a39f9f3ff067d8d8f9e24ecc7")};
+        for (int i = 0; i < testVectors.length; i++) {
+            byte[] cipherText = doOperation(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, testVectors[i],
+                    new KeymasterArguments());
+            MoreAsserts.assertEquals(cipherVectors[i], cipherText);
+        }
+        for (int i = 0; i < testVectors.length; i++) {
+            byte[] plainText = doOperation(name, KeymasterDefs.KM_PURPOSE_DECRYPT,
+                    cipherVectors[i], new KeymasterArguments());
+            MoreAsserts.assertEquals(testVectors[i], plainText);
+        }
+    }
+
+    // This is a very implementation specific test and should be thrown out eventually, however it
+    // is nice for now to test that keystore is properly pruning operations.
+    public void testOperationPruning() throws Exception {
+        String name = "test";
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
+        args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
+        args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+
+        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
+        int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
+        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
+
+        KeymasterArguments out = new KeymasterArguments();
+        args = new KeymasterArguments();
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
+                true, args, out);
+        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
+        IBinder first = result.token;
+        // Implementation detail: softkeymaster supports 16 concurrent operations
+        for (int i = 0; i < 16; i++) {
+            result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, out);
+            assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
+        }
+        // At this point the first operation should be pruned.
+        assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE,
+                mKeyStore.update(first, null, new byte[] {0x01}).resultCode);
+    }
 }
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 20d5470..461160a 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -40,10 +40,12 @@
 # For the host
 # =====================================================
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 LOCAL_SRC_FILES:= $(hostSources)
 LOCAL_C_INCLUDES := external/zlib
 
@@ -54,6 +56,7 @@
 # =====================================================
 
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
 LOCAL_MODULE_TAGS := optional
@@ -63,11 +66,13 @@
     system/core/include
 LOCAL_STATIC_LIBRARIES := libziparchive
 LOCAL_SHARED_LIBRARIES := \
-	libbinder \
-	liblog \
-	libcutils \
-	libutils \
-	libz
+    libbinder \
+    liblog \
+    libcutils \
+    libutils \
+    libz
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index 589211f..782806e 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -45,6 +45,8 @@
 # define O_BINARY 0
 #endif
 
+static const bool kIsDebug = false;
+
 static Mutex gAssetLock;
 static int32_t gCount = 0;
 static Asset* gHead = NULL;
@@ -89,7 +91,9 @@
         gTail->mNext = this;
         gTail = this;
     }
-    //ALOGI("Creating Asset %p #%d\n", this, gCount);
+    if (kIsDebug) {
+        ALOGI("Creating Asset %p #%d\n", this, gCount);
+    }
 }
 
 Asset::~Asset(void)
@@ -109,7 +113,9 @@
         mPrev->mNext = mNext;
     }
     mNext = mPrev = NULL;
-    //ALOGI("Destroying Asset in %p #%d\n", this, gCount);
+    if (kIsDebug) {
+        ALOGI("Destroying Asset in %p #%d\n", this, gCount);
+    }
 }
 
 /*
@@ -526,7 +532,7 @@
 void _FileAsset::close(void)
 {
     if (mMap != NULL) {
-        mMap->release();
+        delete mMap;
         mMap = NULL;
     }
     if (mBuf != NULL) {
@@ -606,7 +612,7 @@
 
         map = new FileMap;
         if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
-            map->release();
+            delete map;
             return NULL;
         }
 
@@ -821,7 +827,7 @@
 void _CompressedAsset::close(void)
 {
     if (mMap != NULL) {
-        mMap->release();
+        delete mMap;
         mMap = NULL;
     }
 
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index de6a33cf..25cd363 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -64,6 +64,8 @@
 
 using namespace android;
 
+static const bool kIsDebug = false;
+
 /*
  * Names for default app, locale, and vendor.  We might want to change
  * these to be an actual locale, e.g. always use en-US as the default.
@@ -152,15 +154,19 @@
       mResources(NULL), mConfig(new ResTable_config),
       mCacheMode(cacheMode), mCacheValid(false)
 {
-    int count = android_atomic_inc(&gCount)+1;
-    //ALOGI("Creating AssetManager %p #%d\n", this, count);
+    int count = android_atomic_inc(&gCount) + 1;
+    if (kIsDebug) {
+        ALOGI("Creating AssetManager %p #%d\n", this, count);
+    }
     memset(mConfig, 0, sizeof(ResTable_config));
 }
 
 AssetManager::~AssetManager(void)
 {
     int count = android_atomic_dec(&gCount);
-    //ALOGI("Destroying AssetManager in %p #%d\n", this, count);
+    if (kIsDebug) {
+        ALOGI("Destroying AssetManager in %p #%d\n", this, count);
+    }
 
     delete mConfig;
     delete mResources;
@@ -296,6 +302,10 @@
     mAssetPaths.add(oap);
     *cookie = static_cast<int32_t>(mAssetPaths.size());
 
+    if (mResources != NULL) {
+        appendPathToResTable(oap);
+    }
+
     return true;
  }
 
@@ -601,6 +611,11 @@
 }
 
 bool AssetManager::appendPathToResTable(const asset_path& ap) const {
+    // skip those ap's that correspond to system overlays
+    if (ap.isSystemOverlay) {
+        return true;
+    }
+
     Asset* ass = NULL;
     ResTable* sharedRes = NULL;
     bool shared = true;
@@ -786,6 +801,7 @@
         oap.path = String8(buf, space - buf);
         oap.type = kFileTypeRegular;
         oap.idmap = String8(space + 1, newline - space - 1);
+        oap.isSystemOverlay = true;
 
         Asset* oass = const_cast<AssetManager*>(this)->
             openNonAssetInPathLocked("resources.arsc",
@@ -1864,7 +1880,9 @@
     : mPath(path), mZipFile(NULL), mModWhen(modWhen),
       mResourceTableAsset(NULL), mResourceTable(NULL)
 {
-    //ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
+    if (kIsDebug) {
+        ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
+    }
     ALOGV("+++ opening zip '%s'\n", mPath.string());
     mZipFile = ZipFileRO::open(mPath.string());
     if (mZipFile == NULL) {
@@ -1958,7 +1976,9 @@
 
 AssetManager::SharedZip::~SharedZip()
 {
-    //ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+    if (kIsDebug) {
+        ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
+    }
     if (mResourceTable != NULL) {
         delete mResourceTable;
     }
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index d16d5498..ba4a4ff 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -27,7 +27,7 @@
 
 namespace android {
 
-static const bool DEBUG = false;
+static const bool kIsDebug = false;
 
 /*
  * File Format (v1):
@@ -45,12 +45,6 @@
 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
 
 static inline size_t
-round_up(size_t n)
-{
-    return n + ROUND_UP[n % 4];
-}
-
-static inline size_t
 padding_extra(size_t n)
 {
     return ROUND_UP[n % 4];
@@ -62,7 +56,7 @@
      m_entityCount(0)
 {
     m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR);
-    if (DEBUG) ALOGI("BackupDataWriter(%d) @ %ld", fd, (long)m_pos);
+    if (kIsDebug) ALOGI("BackupDataWriter(%d) @ %ld", fd, (long)m_pos);
 }
 
 BackupDataWriter::~BackupDataWriter()
@@ -79,7 +73,7 @@
     paddingSize = padding_extra(n);
     if (paddingSize > 0) {
         uint32_t padding = 0xbcbcbcbc;
-        if (DEBUG) ALOGI("writing %zd padding bytes for %d", paddingSize, n);
+        if (kIsDebug) ALOGI("writing %zd padding bytes for %d", paddingSize, n);
         amt = write(m_fd, &padding, paddingSize);
         if (amt != paddingSize) {
             m_status = errno;
@@ -112,7 +106,7 @@
     } else {
         k = key;
     }
-    if (DEBUG) {
+    if (kIsDebug) {
         ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.string(),
                 key.string(), dataSize);
     }
@@ -126,7 +120,7 @@
     header.keyLen = tolel(keyLen);
     header.dataSize = tolel(dataSize);
 
-    if (DEBUG) ALOGI("writing entity header, %zu bytes", sizeof(entity_header_v1));
+    if (kIsDebug) ALOGI("writing entity header, %zu bytes", sizeof(entity_header_v1));
     amt = write(m_fd, &header, sizeof(entity_header_v1));
     if (amt != sizeof(entity_header_v1)) {
         m_status = errno;
@@ -134,7 +128,7 @@
     }
     m_pos += amt;
 
-    if (DEBUG) ALOGI("writing entity header key, %zd bytes", keyLen+1);
+    if (kIsDebug) ALOGI("writing entity header key, %zd bytes", keyLen+1);
     amt = write(m_fd, k.string(), keyLen+1);
     if (amt != keyLen+1) {
         m_status = errno;
@@ -152,10 +146,10 @@
 status_t
 BackupDataWriter::WriteEntityData(const void* data, size_t size)
 {
-    if (DEBUG) ALOGD("Writing data: size=%lu", (unsigned long) size);
+    if (kIsDebug) ALOGD("Writing data: size=%lu", (unsigned long) size);
 
     if (m_status != NO_ERROR) {
-        if (DEBUG) {
+        if (kIsDebug) {
             ALOGD("Not writing data - stream in error state %d (%s)", m_status, strerror(m_status));
         }
         return m_status;
@@ -167,7 +161,7 @@
     ssize_t amt = write(m_fd, data, size);
     if (amt != (ssize_t)size) {
         m_status = errno;
-        if (DEBUG) ALOGD("write returned error %d (%s)", m_status, strerror(m_status));
+        if (kIsDebug) ALOGD("write returned error %d (%s)", m_status, strerror(m_status));
         return m_status;
     }
     m_pos += amt;
@@ -189,7 +183,7 @@
 {
     memset(&m_header, 0, sizeof(m_header));
     m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR);
-    if (DEBUG) ALOGI("BackupDataReader(%d) @ %ld", fd, (long)m_pos);
+    if (kIsDebug) ALOGI("BackupDataReader(%d) @ %ld", fd, (long)m_pos);
 }
 
 BackupDataReader::~BackupDataReader()
@@ -342,15 +336,19 @@
         return -1;
     }
     int remaining = m_dataEndPos - m_pos;
-    //ALOGD("ReadEntityData size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
-    //        size, m_pos, m_dataEndPos, remaining);
+    if (kIsDebug) {
+        ALOGD("ReadEntityData size=%zu m_pos=0x%zx m_dataEndPos=0x%zx remaining=%d\n",
+                size, m_pos, m_dataEndPos, remaining);
+    }
     if (remaining <= 0) {
         return 0;
     }
     if (((int)size) > remaining) {
         size = remaining;
     }
-    //ALOGD("   reading %d bytes", size);
+    if (kIsDebug) {
+        ALOGD("   reading %zu bytes", size);
+    }
     int amt = read(m_fd, data, size);
     if (amt < 0) {
         m_status = errno;
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 33cf8ef..227de3b 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -68,14 +68,11 @@
 
 const static int CURRENT_METADATA_VERSION = 1;
 
-#if 1
-#define LOGP(f, x...)
-#else
+static const bool kIsDebug = false;
 #if TEST_BACKUP_HELPERS
-#define LOGP(f, x...) printf(f "\n", x)
+#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x)
 #else
-#define LOGP(x...) ALOGD(x)
-#endif
+#define LOGP(x...) if (kIsDebug) ALOGD(x)
 #endif
 
 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
@@ -445,18 +442,6 @@
     return 0;
 }
 
-// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
-// returning the initial dest, return a pointer to the trailing NUL.
-static char* strcpy_ptr(char* dest, const char* str) {
-    if (dest && str) {
-        while ((*dest = *str) != 0) {
-            dest++;
-            str++;
-        }
-    }
-    return dest;
-}
-
 static void calc_tar_checksum(char* buf) {
     // [ 148 :   8 ] checksum -- to be calculated with this field as space chars
     memset(buf + 148, ' ', 8);
@@ -582,7 +567,7 @@
     snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
 
     // [ 136 :  12 ] last mod time as a UTC time_t
-    snprintf(buf + 136, 12, "%0lo", s.st_mtime);
+    snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime);
 
     // [ 156 :   1 ] link/file type
     uint8_t type;
@@ -638,7 +623,6 @@
 
         // construct the pax extended header data block
         memset(paxData, 0, BUFSIZE - (paxData - buf));
-        int len;
 
         // size header -- calc len in digits by actually rendering the number
         // to a string - brute force but simple
@@ -1203,7 +1187,6 @@
     size_t bufSize = strlen(str)+1;
     char* buf = (char*)malloc(bufSize);
     String8 string;
-    int cookie = 0x11111111;
     size_t actualSize;
     bool done;
     int type;
@@ -1336,23 +1319,12 @@
         fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
         return errno;
     }
-    times[0].tv_sec = st.st_atime;
-    times[1].tv_sec = st.st_mtime;
 
-    // If st_atime is a macro then struct stat64 uses struct timespec
-    // to store the access and modif time values and typically
-    // st_*time_nsec is not defined. In glibc, this is controlled by
-    // __USE_MISC.
-#ifdef __USE_MISC
-#if !defined(st_atime) || defined(st_atime_nsec)
-#error "Check if this __USE_MISC conditional is still needed."
-#endif
+    times[0].tv_sec = st.st_atim.tv_sec;
     times[0].tv_usec = st.st_atim.tv_nsec / 1000;
+
+    times[1].tv_sec = st.st_mtim.tv_sec;
     times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
-#else
-    times[0].tv_usec = st.st_atime_nsec / 1000;
-    times[1].tv_usec = st.st_mtime_nsec / 1000;
-#endif
 
     return 0;
 }
@@ -1493,7 +1465,6 @@
 backup_helper_test_null_base()
 {
     int err;
-    int oldSnapshotFD;
     int dataStreamFD;
     int newSnapshotFD;
 
@@ -1542,7 +1513,6 @@
 backup_helper_test_missing_file()
 {
     int err;
-    int oldSnapshotFD;
     int dataStreamFD;
     int newSnapshotFD;
 
diff --git a/libs/androidfw/ObbFile.cpp b/libs/androidfw/ObbFile.cpp
index ec59f06..195fa9a 100644
--- a/libs/androidfw/ObbFile.cpp
+++ b/libs/androidfw/ObbFile.cpp
@@ -122,7 +122,7 @@
         if (fileLength < 0) {
             ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
         } else {
-            ALOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
+            ALOGW("file is only %lld (less than %d minimum)\n", (long long int)fileLength, kFooterMinSize);
         }
         return false;
     }
@@ -150,8 +150,8 @@
         footerSize = get4LE((unsigned char*)footer);
         if (footerSize > (size_t)fileLength - kFooterTagSize
                 || footerSize > kMaxBufSize) {
-            ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
-                    footerSize, fileLength);
+            ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08lld)\n",
+                    footerSize, (long long int)fileLength);
             return false;
         }
 
@@ -164,7 +164,7 @@
 
     off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
     if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
-        ALOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
+        ALOGW("seek %lld failed: %s\n", (long long int)fileOffset, strerror(errno));
         return false;
     }
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bdb53c3..d5d583c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -27,6 +27,10 @@
 #include <utils/String16.h>
 #include <utils/String8.h>
 
+#ifdef HAVE_ANDROID_OS
+#include <binder/TextOutput.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include <memory.h>
@@ -38,32 +42,15 @@
 #define INT32_MAX ((int32_t)(2147483647))
 #endif
 
-#define STRING_POOL_NOISY(x) //x
-#define XML_NOISY(x) //x
-#define TABLE_NOISY(x) //x
-#define TABLE_GETENTRY(x) //x
-#define TABLE_SUPER_NOISY(x) //x
-#define LOAD_TABLE_NOISY(x) //x
-#define TABLE_THEME(x) //x
-#define LIB_NOISY(x) //x
-
 namespace android {
 
 #ifdef HAVE_WINSOCK
 #undef  nhtol
 #undef  htonl
-
-#ifdef HAVE_LITTLE_ENDIAN
 #define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
 #define htonl(x)    ntohl(x)
 #define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
 #define htons(x)    ntohs(x)
-#else
-#define ntohl(x)    (x)
-#define htonl(x)    (x)
-#define ntohs(x)    (x)
-#define htons(x)    (x)
-#endif
 #endif
 
 #define IDMAP_MAGIC             0x504D4449
@@ -72,6 +59,19 @@
 #define APP_PACKAGE_ID      0x7f
 #define SYS_PACKAGE_ID      0x01
 
+static const bool kDebugStringPoolNoisy = false;
+static const bool kDebugXMLNoisy = false;
+static const bool kDebugTableNoisy = false;
+static const bool kDebugTableGetEntry = false;
+static const bool kDebugTableSuperNoisy = false;
+static const bool kDebugLoadTableNoisy = false;
+static const bool kDebugLoadTableSuperNoisy = false;
+static const bool kDebugTableTheme = false;
+static const bool kDebugResXMLTree = false;
+static const bool kDebugLibNoisy = false;
+
+// TODO: This code uses 0xFFFFFFFF converted to bag_set* as a sentinel value. This is bad practice.
+
 // Standard C isspace() is only required to look at the low byte of its input, so
 // produces incorrect results for UTF-16 characters.  For safety's sake, assume that
 // any high-byte UTF-16 code point is not whitespace.
@@ -701,6 +701,12 @@
 
                 *u16len = decodeLength(&str);
                 if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
+                    // Reject malformed (non null-terminated) strings
+                    if (str[*u16len] != 0x0000) {
+                        ALOGW("Bad string block: string #%d is not null-terminated",
+                              (int)idx);
+                        return NULL;
+                    }
                     return reinterpret_cast<const char16_t*>(str);
                 } else {
                     ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
@@ -719,12 +725,14 @@
 
                     if (mCache == NULL) {
 #ifndef HAVE_ANDROID_OS
-                        STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes",
-                                mHeader->stringCount*sizeof(char16_t**)));
+                        if (kDebugStringPoolNoisy) {
+                            ALOGI("CREATING STRING CACHE OF %zu bytes",
+                                    mHeader->stringCount*sizeof(char16_t**));
+                        }
 #else
                         // We do not want to be in this case when actually running Android.
-                        ALOGW("CREATING STRING CACHE OF %d bytes",
-                                mHeader->stringCount*sizeof(char16_t**));
+                        ALOGW("CREATING STRING CACHE OF %zu bytes",
+                                static_cast<size_t>(mHeader->stringCount*sizeof(char16_t**)));
 #endif
                         mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
                         if (mCache == NULL) {
@@ -746,6 +754,13 @@
                         return NULL;
                     }
 
+                    // Reject malformed (non null-terminated) strings
+                    if (u8str[u8len] != 0x00) {
+                        ALOGW("Bad string block: string #%d is not null-terminated",
+                              (int)idx);
+                        return NULL;
+                    }
+
                     char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
                     if (!u16str) {
                         ALOGW("No memory when trying to allocate decode cache for string #%d\n",
@@ -753,7 +768,9 @@
                         return NULL;
                     }
 
-                    STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("Caching UTF8 string: %s", u8str);
+                    }
                     utf8_to_utf16(u8str, u8len, u16str);
                     mCache[idx] = u16str;
                     return u16str;
@@ -843,7 +860,9 @@
     size_t len;
 
     if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
-        STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()));
+        if (kDebugStringPoolNoisy) {
+            ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
+        }
 
         // The string pool contains UTF 8 strings; we don't want to cause
         // temporary UTF-16 strings to be created as we search.
@@ -869,10 +888,14 @@
                 } else {
                     c = -1;
                 }
-                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                             (const char*)s, c, (int)l, (int)mid, (int)h));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                            (const char*)s, c, (int)l, (int)mid, (int)h);
+                }
                 if (c == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     free(convBuffer);
                     return mid;
                 } else if (c < 0) {
@@ -891,18 +914,22 @@
             const size_t str8Len = str8.size();
             for (int i=mHeader->stringCount-1; i>=0; i--) {
                 const char* s = string8At(i, &len);
-                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
-                             String8(s).string(),
-                             i));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+                }
                 if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return i;
                 }
             }
         }
 
     } else {
-        STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()));
+        if (kDebugStringPoolNoisy) {
+            ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
+        }
 
         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
             // Do a binary search for the string...
@@ -914,11 +941,14 @@
                 mid = l + (h - l)/2;
                 const char16_t* s = stringAt(mid, &len);
                 int c = s ? strzcmp16(s, len, str, strLen) : -1;
-                STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                             String8(s).string(),
-                             c, (int)l, (int)mid, (int)h));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+                            String8(s).string(), c, (int)l, (int)mid, (int)h);
+                }
                 if (c == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return mid;
                 } else if (c < 0) {
                     l = mid + 1;
@@ -933,11 +963,13 @@
             // block, start searching at the back.
             for (int i=mHeader->stringCount-1; i>=0; i--) {
                 const char16_t* s = stringAt(i, &len);
-                STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
-                             String8(s).string(),
-                             i));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+                }
                 if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
-                    STRING_POOL_NOISY(ALOGI("MATCH!"));
+                    if (kDebugStringPoolNoisy) {
+                        ALOGI("MATCH!");
+                    }
                     return i;
                 }
             }
@@ -1138,7 +1170,9 @@
 {
     int32_t id = getAttributeNamespaceID(idx);
     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1146,7 +1180,9 @@
 {
     int32_t id = getAttributeNamespaceID(idx);
     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
 }
 
@@ -1169,7 +1205,9 @@
 {
     int32_t id = getAttributeNameID(idx);
     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeName 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1177,7 +1215,9 @@
 {
     int32_t id = getAttributeNameID(idx);
     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
-    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeName 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
 }
 
@@ -1212,7 +1252,9 @@
 const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
 {
     int32_t id = getAttributeValueStringID(idx);
-    //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
+    if (kDebugXMLNoisy) {
+        printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
+    }
     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
 }
 
@@ -1303,54 +1345,69 @@
                 ns8 = String8(ns, nsLen);
             }
             attr8 = String8(attr, attrLen);
-            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen,
-                    attr8.string(), attrLen));
+            if (kDebugStringPoolNoisy) {
+                ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.string(), nsLen,
+                        attr8.string(), attrLen);
+            }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
                 const char* curNs = getAttributeNamespace8(i, &curNsLen);
                 const char* curAttr = getAttributeName8(i, &curAttrLen);
-                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen,
-                        curAttr, curAttrLen));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
+                }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                         && memcmp(attr8.string(), curAttr, attrLen) == 0) {
                     if (ns == NULL) {
                         if (curNs == NULL) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
                         //       String8(ns).string(), String8(curNs).string());
                         if (memcmp(ns8.string(), curNs, nsLen) == 0) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     }
                 }
             }
         } else {
-            STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)",
-                    String8(ns, nsLen).string(), nsLen,
-                    String8(attr, attrLen).string(), attrLen));
+            if (kDebugStringPoolNoisy) {
+                ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
+                        String8(ns, nsLen).string(), nsLen,
+                        String8(attr, attrLen).string(), attrLen);
+            }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
                 const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
                 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
-                STRING_POOL_NOISY(ALOGI("  curNs=%s (%d), curAttr=%s (%d)",
-                        String8(curNs, curNsLen).string(), curNsLen,
-                        String8(curAttr, curAttrLen).string(), curAttrLen));
+                if (kDebugStringPoolNoisy) {
+                    ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)",
+                            String8(curNs, curNsLen).string(), curNsLen,
+                            String8(curAttr, curAttrLen).string(), curAttrLen);
+                }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                         && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
                     if (ns == NULL) {
                         if (curNs == NULL) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
                         //       String8(ns).string(), String8(curNs).string());
                         if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
-                            STRING_POOL_NOISY(ALOGI("  FOUND!"));
+                            if (kDebugStringPoolNoisy) {
+                                ALOGI("  FOUND!");
+                            }
                             return i;
                         }
                     }
@@ -1398,7 +1455,9 @@
     do {
         const ResXMLTree_node* next = (const ResXMLTree_node*)
             (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
-        //ALOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
+        if (kDebugXMLNoisy) {
+            ALOGI("Next node: prev=%p, next=%p\n", mCurNode, next);
+        }
 
         if (((const uint8_t*)next) >= mTree.mDataEnd) {
             mCurNode = NULL;
@@ -1475,7 +1534,9 @@
     , mDynamicRefTable(dynamicRefTable)
     , mError(NO_INIT), mOwnedData(NULL)
 {
-    //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    if (kDebugResXMLTree) {
+        ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    }
     restart();
 }
 
@@ -1484,13 +1545,17 @@
     , mDynamicRefTable(NULL)
     , mError(NO_INIT), mOwnedData(NULL)
 {
-    //ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    if (kDebugResXMLTree) {
+        ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
+    }
     restart();
 }
 
 ResXMLTree::~ResXMLTree()
 {
-    //ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+    if (kDebugResXMLTree) {
+        ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
+    }
     uninit();
 }
 
@@ -1543,8 +1608,10 @@
         }
         const uint16_t type = dtohs(chunk->type);
         const size_t size = dtohl(chunk->size);
-        XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
-                     (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
+        if (kDebugXMLNoisy) {
+            printf("Scanning @ %p: type=0x%x, size=0x%zx\n",
+                    (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size);
+        }
         if (type == RES_STRING_POOL_TYPE) {
             mStrings.setTo(chunk, size);
         } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
@@ -1567,7 +1634,9 @@
             mRootCode = mEventCode;
             break;
         } else {
-            XML_NOISY(printf("Skipping unknown chunk!\n"));
+            if (kDebugXMLNoisy) {
+                printf("Skipping unknown chunk!\n");
+            }
         }
         lastChunk = chunk;
         chunk = (const ResChunk_header*)
@@ -2151,9 +2220,11 @@
                 myDelta += requested->screenHeightDp - screenHeightDp;
                 otherDelta += requested->screenHeightDp - o.screenHeightDp;
             }
-            //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
-            //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
-            //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+                        screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+                        requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            }
             if (myDelta != otherDelta) {
                 return myDelta < otherDelta;
             }
@@ -2408,11 +2479,17 @@
     }
     if (screenSizeDp != 0) {
         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
-            //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Filtering out width %d in requested %d", screenWidthDp,
+                        settings.screenWidthDp);
+            }
             return false;
         }
         if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
-            //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Filtering out height %d in requested %d", screenHeightDp,
+                        settings.screenHeightDp);
+            }
             return false;
         }
     }
@@ -2432,9 +2509,13 @@
             // For compatibility, we count a request for KEYSHIDDEN_NO as also
             // matching the more recent KEYSHIDDEN_SOFT.  Basically
             // KEYSHIDDEN_NO means there is some kind of keyboard available.
-            //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            if (kDebugTableSuperNoisy) {
+                ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            }
             if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
-                //ALOGI("No match!");
+                if (kDebugTableSuperNoisy) {
+                    ALOGI("No match!");
+                }
                 return false;
             }
         }
@@ -2939,17 +3020,25 @@
 
     void clearBagCache() {
         if (bags) {
-            TABLE_NOISY(printf("bags=%p\n", bags));
+            if (kDebugTableNoisy) {
+                printf("bags=%p\n", bags);
+            }
             for (size_t i = 0; i < bags->size(); i++) {
-                TABLE_NOISY(printf("type=%d\n", i));
+                if (kDebugTableNoisy) {
+                    printf("type=%zu\n", i);
+                }
                 const TypeList& typeList = types[i];
                 if (!typeList.isEmpty()) {
                     bag_set** typeBags = bags->get(i);
-                    TABLE_NOISY(printf("typeBags=%p\n", typeBags));
+                    if (kDebugTableNoisy) {
+                        printf("typeBags=%p\n", typeBags);
+                    }
                     if (typeBags) {
                         const size_t N = typeList[0]->entryCount;
-                        TABLE_NOISY(printf("type->entryCount=%x\n", N));
-                        for (size_t j=0; j<N; j++) {
+                        if (kDebugTableNoisy) {
+                            printf("type->entryCount=%zu\n", N);
+                        }
+                        for (size_t j = 0; j < N; j++) {
                             if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
                                 free(typeBags[j]);
                         }
@@ -3040,7 +3129,8 @@
         size_t cnt = pi->types[j].numEntries;
         newpi->types[j].numEntries = cnt;
         theme_entry* te = pi->types[j].entries;
-        if (te != NULL) {
+        size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+        if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
             newpi->types[j].entries = newte;
             memcpy(newte, te, cnt*sizeof(theme_entry));
@@ -3057,7 +3147,9 @@
     uint32_t bagTypeSpecFlags = 0;
     mTable.lock();
     const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
-    TABLE_NOISY(ALOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
+    if (kDebugTableNoisy) {
+        ALOGV("Applying style 0x%08x to theme %p, count=%zu", resID, this, N);
+    }
     if (N < 0) {
         mTable.unlock();
         return N;
@@ -3088,7 +3180,6 @@
             curPackageIndex = pidx;
             curPI = mPackages[pidx];
             if (curPI == NULL) {
-                PackageGroup* const grp = mTable.mPackageGroups[pidx];
                 curPI = (package_info*)malloc(sizeof(package_info));
                 memset(curPI, 0, sizeof(*curPI));
                 mPackages[pidx] = curPI;
@@ -3106,9 +3197,12 @@
             if (curEntries == NULL) {
                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
                 const TypeList& typeList = grp->types[t];
-                int cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
-                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
-                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
+                size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
+                size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
+                size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
+                                          cnt*sizeof(theme_entry) : 0;
+                curEntries = (theme_entry*)malloc(buff_size);
+                memset(curEntries, Res_value::TYPE_NULL, buff_size);
                 curPI->types[t].numEntries = cnt;
                 curPI->types[t].entries = curEntries;
             }
@@ -3120,9 +3214,11 @@
             continue;
         }
         theme_entry* curEntry = curEntries + e;
-        TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
-                attrRes, bag->map.value.dataType, bag->map.value.data,
-                curEntry->value.dataType));
+        if (kDebugTableNoisy) {
+            ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
+                    attrRes, bag->map.value.dataType, bag->map.value.data,
+                    curEntry->value.dataType);
+        }
         if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
             curEntry->stringBlock = bag->stringBlock;
             curEntry->typeSpecFlags |= bagTypeSpecFlags;
@@ -3134,17 +3230,21 @@
 
     mTable.unlock();
 
-    //ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
-    //dumpToLog();
+    if (kDebugTableTheme) {
+        ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
+        dumpToLog();
+    }
 
     return NO_ERROR;
 }
 
 status_t ResTable::Theme::setTo(const Theme& other)
 {
-    //ALOGI("Setting theme %p from theme %p...\n", this, &other);
-    //dumpToLog();
-    //other.dumpToLog();
+    if (kDebugTableTheme) {
+        ALOGI("Setting theme %p from theme %p...\n", this, &other);
+        dumpToLog();
+        other.dumpToLog();
+    }
 
     if (&mTable == &other.mTable) {
         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
@@ -3173,8 +3273,10 @@
         }
     }
 
-    //ALOGI("Final theme:");
-    //dumpToLog();
+    if (kDebugTableTheme) {
+        ALOGI("Final theme:");
+        dumpToLog();
+    }
 
     return NO_ERROR;
 }
@@ -3191,23 +3293,33 @@
         const uint32_t t = Res_GETTYPE(resID);
         const uint32_t e = Res_GETENTRY(resID);
 
-        TABLE_THEME(ALOGI("Looking up attr 0x%08x in theme %p", resID, this));
+        if (kDebugTableTheme) {
+            ALOGI("Looking up attr 0x%08x in theme %p", resID, this);
+        }
 
         if (p >= 0) {
             const package_info* const pi = mPackages[p];
-            TABLE_THEME(ALOGI("Found package: %p", pi));
+            if (kDebugTableTheme) {
+                ALOGI("Found package: %p", pi);
+            }
             if (pi != NULL) {
-                TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, Res_MAXTYPE + 1));
+                if (kDebugTableTheme) {
+                    ALOGI("Desired type index is %zd in avail %zu", t, Res_MAXTYPE + 1);
+                }
                 if (t <= Res_MAXTYPE) {
                     const type_info& ti = pi->types[t];
-                    TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries));
+                    if (kDebugTableTheme) {
+                        ALOGI("Desired entry index is %u in avail %zu", e, ti.numEntries);
+                    }
                     if (e < ti.numEntries) {
                         const theme_entry& te = ti.entries[e];
                         if (outTypeSpecFlags != NULL) {
                             *outTypeSpecFlags |= te.typeSpecFlags;
                         }
-                        TABLE_THEME(ALOGI("Theme value: type=0x%x, data=0x%08x",
-                                te.value.dataType, te.value.data));
+                        if (kDebugTableTheme) {
+                            ALOGI("Theme value: type=0x%x, data=0x%08x",
+                                    te.value.dataType, te.value.data);
+                        }
                         const uint8_t type = te.value.dataType;
                         if (type == Res_value::TYPE_ATTRIBUTE) {
                             if (cnt > 0) {
@@ -3241,8 +3353,10 @@
     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
         uint32_t newTypeSpecFlags;
         blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
-        TABLE_THEME(ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n",
-             (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data));
+        if (kDebugTableTheme) {
+            ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=0x%x\n",
+                    (int)blockIndex, (int)inOutValue->dataType, inOutValue->data);
+        }
         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
         //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
         if (blockIndex < 0) {
@@ -3281,7 +3395,9 @@
 {
     memset(&mParams, 0, sizeof(mParams));
     memset(mPackageMap, 0, sizeof(mPackageMap));
-    //ALOGI("Creating ResTable %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Creating ResTable %p\n", this);
+    }
 }
 
 ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
@@ -3291,12 +3407,16 @@
     memset(mPackageMap, 0, sizeof(mPackageMap));
     addInternal(data, size, NULL, 0, cookie, copyData);
     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
-    //ALOGI("Creating ResTable %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Creating ResTable %p\n", this);
+    }
 }
 
 ResTable::~ResTable()
 {
-    //ALOGI("Destroying ResTable in %p\n", this);
+    if (kDebugTableSuperNoisy) {
+        ALOGI("Destroying ResTable in %p\n", this);
+    }
     uninit();
 }
 
@@ -3425,9 +3545,10 @@
 
     const bool notDeviceEndian = htods(0xf0) != 0xf0;
 
-    LOAD_TABLE_NOISY(
-        ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, copy=%d "
-             "idmap=%p\n", data, dataSize, cookie, copyData, idmap));
+    if (kDebugLoadTableNoisy) {
+        ALOGV("Adding resources to ResTable: data=%p, size=%zu, cookie=%d, copy=%d "
+                "idmap=%p\n", data, dataSize, cookie, copyData, idmapData);
+    }
 
     if (copyData || notDeviceEndian) {
         header->ownedData = malloc(dataSize);
@@ -3440,9 +3561,13 @@
 
     header->header = (const ResTable_header*)data;
     header->size = dtohl(header->header->header.size);
-    //ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
-    //     dtohl(header->header->header.size), header->header->header.size);
-    LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header));
+    if (kDebugLoadTableSuperNoisy) {
+        ALOGI("Got size %zu, again size 0x%x, raw size 0x%x\n", header->size,
+                dtohl(header->header->header.size), header->header->header.size);
+    }
+    if (kDebugLoadTableNoisy) {
+        ALOGV("Loading ResTable @%p:\n", header->header);
+    }
     if (dtohs(header->header->header.headerSize) > header->size
             || header->size > dataSize) {
         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
@@ -3470,9 +3595,11 @@
         if (err != NO_ERROR) {
             return (mError=err);
         }
-        TABLE_NOISY(ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
-                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
-                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        if (kDebugTableNoisy) {
+            ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                    dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                    (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+        }
         const size_t csize = dtohl(chunk->size);
         const uint16_t ctype = dtohs(chunk->type);
         if (ctype == RES_STRING_POOL_TYPE) {
@@ -3516,7 +3643,9 @@
         ALOGW("No string values found in resource table!");
     }
 
-    TABLE_NOISY(ALOGV("Returning from add with mError=%d\n", mError));
+    if (kDebugTableNoisy) {
+        ALOGV("Returning from add with mError=%d\n", mError);
+    }
     return mError;
 }
 
@@ -3682,15 +3811,16 @@
         return BAD_VALUE;
     }
 
-    TABLE_NOISY(size_t len;
-          printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
-                 entry.package->header->index,
-                 outValue->dataType,
-                 outValue->dataType == Res_value::TYPE_STRING
-                 ? String8(entry.package->header->values.stringAt(
-                     outValue->data, &len)).string()
-                 : "",
-                 outValue->data));
+    if (kDebugTableNoisy) {
+        size_t len;
+        printf("Found value: pkg=%zu, type=%d, str=%s, int=%d\n",
+                entry.package->header->index,
+                outValue->dataType,
+                outValue->dataType == Res_value::TYPE_STRING ?
+                    String8(entry.package->header->values.stringAt(outValue->data, &len)).string() :
+                    "",
+                outValue->data);
+    }
 
     if (outSpecFlags != NULL) {
         *outSpecFlags = entry.specFlags;
@@ -3711,15 +3841,16 @@
     while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
             && value->data != 0 && count < 20) {
         if (outLastRef) *outLastRef = value->data;
-        uint32_t lastRef = value->data;
         uint32_t newFlags = 0;
         const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
                 outConfig);
         if (newIndex == BAD_INDEX) {
             return BAD_INDEX;
         }
-        TABLE_THEME(ALOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n",
-             (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data));
+        if (kDebugTableTheme) {
+            ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
+                    value->data, (int)newIndex, (int)value->dataType, value->data);
+        }
         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
         if (newIndex < 0) {
@@ -3826,7 +3957,9 @@
                         *outTypeSpecFlags = set->typeSpecFlags;
                     }
                     *outBag = (bag_entry*)(set+1);
-                    //ALOGI("Found existing bag for: %p\n", (void*)resID);
+                    if (kDebugTableSuperNoisy) {
+                        ALOGI("Found existing bag for: 0x%x\n", resID);
+                    }
                     return set->numAttrs;
                 }
                 ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
@@ -3852,7 +3985,9 @@
     // Mark that we are currently working on this one.
     typeSet[e] = (bag_set*)0xFFFFFFFF;
 
-    TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
+    if (kDebugTableNoisy) {
+        ALOGI("Building bag: %x\n", resID);
+    }
 
     // Now collect all bag attributes
     Entry entry;
@@ -3869,13 +4004,13 @@
 
     size_t N = count;
 
-    TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
-                     entrySize, parent, count));
+    if (kDebugTableNoisy) {
+        ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
 
     // If this map inherits from another, we need to start
     // with its parent's values.  Otherwise start out empty.
-    TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
-                       entrySize, parent));
+        ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
+    }
 
     // This is what we are building.
     bag_set* set = NULL;
@@ -3904,9 +4039,13 @@
         if (NP > 0) {
             memcpy(set+1, parentBag, NP*sizeof(bag_entry));
             set->numAttrs = NP;
-            TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP));
+            if (kDebugTableNoisy) {
+                ALOGI("Initialized new bag with %zd inherited attributes.\n", NP);
+            }
         } else {
-            TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n"));
+            if (kDebugTableNoisy) {
+                ALOGI("Initialized new bag with no inherited attributes.\n");
+            }
             set->numAttrs = 0;
         }
         set->availAttrs = NT;
@@ -3930,10 +4069,13 @@
     bag_entry* entries = (bag_entry*)(set+1);
     size_t curEntry = 0;
     uint32_t pos = 0;
-    TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n",
-                 set, entries, set->availAttrs));
+    if (kDebugTableNoisy) {
+        ALOGI("Starting with set %p, entries=%p, avail=%zu\n", set, entries, set->availAttrs);
+    }
     while (pos < count) {
-        TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
+        if (kDebugTableNoisy) {
+            ALOGI("Now at %p\n", (void*)curOff);
+        }
 
         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
             ALOGW("ResTable_map at %d is beyond type chunk data %d",
@@ -3958,8 +4100,10 @@
         uint32_t oldName = 0;
         while ((isInside=(curEntry < set->numAttrs))
                 && (oldName=entries[curEntry].map.name.ident) < newName) {
-            TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
-                         curEntry, entries[curEntry].map.name.ident));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Keeping existing attribute: 0x%08x\n",
+                        curEntry, entries[curEntry].map.name.ident);
+            }
             curEntry++;
         }
 
@@ -3976,8 +4120,10 @@
                 }
                 set->availAttrs = newAvail;
                 entries = (bag_entry*)(set+1);
-                TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
-                             set, entries, set->availAttrs));
+                if (kDebugTableNoisy) {
+                    ALOGI("Reallocated set %p, entries=%p, avail=%zu\n",
+                            set, entries, set->availAttrs);
+                }
             }
             if (isInside) {
                 // Going in the middle, need to make space.
@@ -3985,11 +4131,13 @@
                         sizeof(bag_entry)*(set->numAttrs-curEntry));
                 set->numAttrs++;
             }
-            TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
-                         curEntry, newName));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Inserting new attribute: 0x%08x\n", curEntry, newName);
+            }
         } else {
-            TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
-                         curEntry, oldName));
+            if (kDebugTableNoisy) {
+                ALOGI("#%zu: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
+            }
         }
 
         bag_entry* cur = entries+curEntry;
@@ -4003,9 +4151,11 @@
             return UNKNOWN_ERROR;
         }
 
-        TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
-                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
-                     cur->map.value.dataType, cur->map.value.data));
+        if (kDebugTableNoisy) {
+            ALOGI("Setting entry #%zu %p: block=%zd, name=0x%08d, type=%d, data=0x%08x\n",
+                    curEntry, cur, cur->stringBlock, cur->map.name.ident,
+                    cur->map.value.dataType, cur->map.value.data);
+        }
 
         // On to the next!
         curEntry++;
@@ -4025,7 +4175,9 @@
             *outTypeSpecFlags = set->typeSpecFlags;
         }
         *outBag = (bag_entry*)(set+1);
-        TABLE_NOISY(ALOGI("Returning %d attrs\n", set->numAttrs));
+        if (kDebugTableNoisy) {
+            ALOGI("Returning %zu attrs\n", set->numAttrs);
+        }
         return set->numAttrs;
     }
     return BAD_INDEX;
@@ -4034,10 +4186,14 @@
 void ResTable::setParameters(const ResTable_config* params)
 {
     mLock.lock();
-    TABLE_GETENTRY(ALOGI("Setting parameters: %s\n", params->toString().string()));
+    if (kDebugTableGetEntry) {
+        ALOGI("Setting parameters: %s\n", params->toString().string());
+    }
     mParams = *params;
     for (size_t i=0; i<mPackageGroups.size(); i++) {
-        TABLE_NOISY(ALOGI("CLEARING BAGS FOR GROUP %d!", i));
+        if (kDebugTableNoisy) {
+            ALOGI("CLEARING BAGS FOR GROUP %zu!", i);
+        }
         mPackageGroups[i]->clearBagCache();
     }
     mLock.unlock();
@@ -4075,7 +4231,9 @@
                                      size_t packageLen,
                                      uint32_t* outTypeSpecFlags) const
 {
-    TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
+    if (kDebugTableSuperNoisy) {
+        printf("Identifier for name: error=%d\n", mError);
+    }
 
     // Check for internal resource identifier as the very first thing, so
     // that we will always find them even when there are no resources.
@@ -4168,10 +4326,12 @@
     }
     nameLen = nameEnd-name;
 
-    TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
-                 String8(type, typeLen).string(),
-                 String8(name, nameLen).string(),
-                 String8(package, packageLen).string()));
+    if (kDebugTableNoisy) {
+        printf("Looking for identifier: type=%s, name=%s, package=%s\n",
+                String8(type, typeLen).string(),
+                String8(name, nameLen).string(),
+                String8(package, packageLen).string());
+    }
 
     const String16 attr("attr");
     const String16 attrPrivate("^attr-private");
@@ -4182,7 +4342,9 @@
 
         if (strzcmp16(package, packageLen,
                       group->name.string(), group->name.size())) {
-            TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
+            if (kDebugTableNoisy) {
+                printf("Skipping package group: %s\n", String8(group->name).string());
+            }
             continue;
         }
 
@@ -4495,7 +4657,7 @@
     if (len > 0) {
         return false;
     }
-    if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+    if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
         return false;
     }
 
@@ -4712,9 +4874,11 @@
                     rid = Res_MAKEID(
                         accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
                         Res_GETTYPE(rid), Res_GETENTRY(rid));
-                    TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
-                           String8(package).string(), String8(type).string(),
-                           String8(name).string(), rid));
+                    if (kDebugTableNoisy) {
+                        ALOGI("Incl %s:%s/%s: 0x%08x\n",
+                                String8(package).string(), String8(type).string(),
+                                String8(name).string(), rid);
+                    }
                 }
 
                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
@@ -4729,9 +4893,11 @@
                 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
                                                                        createIfNotFound);
                 if (rid != 0) {
-                    TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
-                           String8(package).string(), String8(type).string(),
-                           String8(name).string(), rid));
+                    if (kDebugTableNoisy) {
+                        ALOGI("Pckg %s:%s/%s: 0x%08x\n",
+                                String8(package).string(), String8(type).string(),
+                                String8(name).string(), rid);
+                    }
                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
                     if (packageId == 0x00) {
                         outValue->data = rid;
@@ -5540,8 +5706,6 @@
             }
 
             // Check if there is the desired entry in this type.
-            const uint8_t* const end = reinterpret_cast<const uint8_t*>(thisType)
-                    + dtohl(thisType->header.size);
             const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
                     reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
 
@@ -5730,9 +5894,11 @@
     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
            ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
-        TABLE_NOISY(ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
-                         dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
-                         (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
+        if (kDebugTableNoisy) {
+            ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
+                    dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
+                    (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
+        }
         const size_t csize = dtohl(chunk->size);
         const uint16_t ctype = dtohs(chunk->type);
         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
@@ -5746,11 +5912,13 @@
             const size_t typeSpecSize = dtohl(typeSpec->header.size);
             const size_t newEntryCount = dtohl(typeSpec->entryCount);
 
-            LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
-                                    (void*)(base-(const uint8_t*)chunk),
-                                    dtohs(typeSpec->header.type),
-                                    dtohs(typeSpec->header.headerSize),
-                                    (void*)typeSpecSize));
+            if (kDebugLoadTableNoisy) {
+                ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
+                        (void*)(base-(const uint8_t*)chunk),
+                        dtohs(typeSpec->header.type),
+                        dtohs(typeSpec->header.headerSize),
+                        (void*)typeSpecSize);
+            }
             // look for block overrun or int overflow when multiplying by 4
             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
                     || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
@@ -5808,13 +5976,14 @@
             const uint32_t typeSize = dtohl(type->header.size);
             const size_t newEntryCount = dtohl(type->entryCount);
 
-            LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
-                                    (void*)(base-(const uint8_t*)chunk),
-                                    dtohs(type->header.type),
-                                    dtohs(type->header.headerSize),
-                                    (void*)typeSize));
-            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
-                    > typeSize) {
+            if (kDebugLoadTableNoisy) {
+                printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
+                        (void*)(base-(const uint8_t*)chunk),
+                        dtohs(type->header.type),
+                        dtohs(type->header.headerSize),
+                        typeSize);
+            }
+            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) > typeSize) {
                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
                         (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
                         typeSize);
@@ -5860,11 +6029,12 @@
 
                 t->configs.add(type);
 
-                TABLE_GETENTRY(
+                if (kDebugTableGetEntry) {
                     ResTable_config thisConfig;
                     thisConfig.copyFromDtoH(type->config);
-                    ALOGI("Adding config to type %d: %s\n",
-                          type->id, thisConfig.toString().string()));
+                    ALOGI("Adding config to type %d: %s\n", type->id,
+                            thisConfig.toString().string());
+                }
             } else {
                 ALOGV("Skipping empty ResTable_type for type %d", type->id);
             }
@@ -5925,8 +6095,10 @@
         uint32_t packageId = dtohl(entry->packageId);
         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
-        LIB_NOISY(ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
-                dtohl(entry->packageId)));
+        if (kDebugLibNoisy) {
+            ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
+                    dtohl(entry->packageId));
+        }
         if (packageId >= 256) {
             ALOGE("Bad package id 0x%08x", packageId);
             return UNKNOWN_ERROR;
@@ -6109,20 +6281,20 @@
 
             if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
                 ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
-                        " but entries should map to resources of type %02x",
+                        " but entries should map to resources of type %02zx",
                         resID, overlayResID, typeMap.overlayTypeId);
                 return BAD_TYPE;
             }
 
             if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
-                // Resize to accomodate this entry and the 0's in between.
-                if (typeMap.entryMap.resize((entryIndex - typeMap.entryOffset) + 1) < 0) {
+                // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
+                size_t index = typeMap.entryMap.size();
+                size_t numItems = entryIndex - (typeMap.entryOffset + index);
+                if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
                     return NO_MEMORY;
                 }
-                typeMap.entryMap.editTop() = Res_GETENTRY(overlayResID);
-            } else {
-                typeMap.entryMap.add(Res_GETENTRY(overlayResID));
             }
+            typeMap.entryMap.add(Res_GETENTRY(overlayResID));
         }
 
         if (!typeMap.entryMap.isEmpty()) {
@@ -6445,9 +6617,6 @@
                     continue;
                 }
                 for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
-
-                    const uint8_t* const end = ((const uint8_t*)type)
-                        + dtohl(type->header.size);
                     const uint32_t* const eindex = (const uint32_t*)
                         (((const uint8_t*)type) + dtohs(type->header.headerSize));
 
diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
index 1dfec23..b39b5f0 100644
--- a/libs/androidfw/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -41,6 +41,8 @@
     _rc; })
 #endif
 
+static const bool kIsDebug = false;
+
 static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
 
 using namespace android;
@@ -209,7 +211,9 @@
         size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
         if (toRead > 0) {
             ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
-            //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
+            if (kIsDebug) {
+                ALOGV("Reading input chunk, size %08zx didread %08zx", toRead, didRead);
+            }
             if (didRead < 0) {
                 ALOGE("Error reading asset data: %s", strerror(errno));
                 return didRead;
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 1ab18ad..af3d9b3 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -34,14 +34,6 @@
 #include <assert.h>
 #include <unistd.h>
 
-/*
- * We must open binary files using open(path, ... | O_BINARY) under Windows.
- * Otherwise strange read errors will happen.
- */
-#ifndef O_BINARY
-#  define O_BINARY  0
-#endif
-
 using namespace android;
 
 class _ZipEntryRO {
@@ -50,7 +42,10 @@
     ZipEntryName name;
     void *cookie;
 
-    _ZipEntryRO() : cookie(NULL) {
+    _ZipEntryRO() : cookie(NULL) {}
+
+    ~_ZipEntryRO() {
+      EndIteration(cookie);
     }
 
 private:
@@ -83,15 +78,15 @@
 ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
 {
     _ZipEntryRO* data = new _ZipEntryRO;
-    const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
+
+    data->name = ZipEntryName(entryName);
+
+    const int32_t error = FindEntry(mHandle, data->name, &(data->entry));
     if (error) {
         delete data;
         return NULL;
     }
 
-    data->name.name = entryName;
-    data->name.name_length = strlen(entryName);
-
     return (ZipEntryRO) data;
 }
 
@@ -205,7 +200,7 @@
 
     FileMap* newMap = new FileMap();
     if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) {
-        newMap->release();
+        delete newMap;
         return NULL;
     }
 
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index ea54cc5..5285420 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -56,9 +56,11 @@
             return kFileTypeBlockDev;
         else if (S_ISFIFO(sb.st_mode))
             return kFileTypeFifo;
-#ifdef HAVE_SYMLINKS
+#if defined(S_ISLNK)
         else if (S_ISLNK(sb.st_mode))
             return kFileTypeSymlink;
+#endif
+#if defined(S_ISSOCK)
         else if (S_ISSOCK(sb.st_mode))
             return kFileTypeSocket;
 #endif
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index c1014be..58b78b5 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -38,12 +38,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libandroidfw_tests
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+# gtest is broken.
+LOCAL_CFLAGS += -Wno-unnamed-type-template-args
+
 LOCAL_SRC_FILES := $(testFiles)
 LOCAL_STATIC_LIBRARIES := \
     libandroidfw \
     libutils \
     libcutils \
-	liblog
+    liblog
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -55,6 +60,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libandroidfw_tests
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+# gtest is broken.
+LOCAL_CFLAGS += -Wno-unnamed-type-template-args
+
 LOCAL_SRC_FILES := $(testFiles) \
     BackupData_test.cpp \
     ObbFile_test.cpp
@@ -63,7 +73,6 @@
     libcutils \
     libutils \
     libui \
-    libstlport
 
 include $(BUILD_NATIVE_TEST)
 endif # Not SDK_ONLY
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
index 75eb528..1fec504 100644
--- a/libs/common_time/Android.mk
+++ b/libs/common_time/Android.mk
@@ -33,4 +33,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := common_time
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_EXECUTABLE)
diff --git a/libs/common_time/clock_recovery.cpp b/libs/common_time/clock_recovery.cpp
index 3a7c70c..392caa0 100644
--- a/libs/common_time/clock_recovery.cpp
+++ b/libs/common_time/clock_recovery.cpp
@@ -22,6 +22,7 @@
 #define __STDC_LIMIT_MACROS
 #define LOG_TAG "common_time"
 #include <utils/Log.h>
+#include <inttypes.h>
 #include <stdint.h>
 
 #include <common_time/local_clock.h>
@@ -280,7 +281,7 @@
     // system.
     setTargetCorrection_l(tgt_correction);
 
-    LOG_TS("clock_loop %lld %f %f %f %d\n", raw_delta, delta_f, CO, CObias, tgt_correction);
+    LOG_TS("clock_loop %" PRId64 " %f %f %f %d\n", raw_delta, delta_f, CO, CObias, tgt_correction);
 
 #ifdef TIME_SERVICE_DEBUG
     diag_thread_->pushDisciplineEvent(
@@ -335,7 +336,6 @@
     // 300mSec.
     if (tgt_correction_ != tgt) {
         int64_t now = local_clock_->getLocalTime();
-        status_t res;
 
         tgt_correction_ = tgt;
 
diff --git a/libs/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
index b6c87ff..278a75e 100644
--- a/libs/common_time/clock_recovery.h
+++ b/libs/common_time/clock_recovery.h
@@ -111,7 +111,6 @@
     bool    last_error_est_valid_;
     int32_t last_error_est_usec_;
     float last_delta_f_;
-    int32_t integrated_error_;
     int32_t tgt_correction_;
     int32_t cur_correction_;
     LinearTransform time_to_cur_slew_;
diff --git a/libs/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
index c9eb388..ee326e1 100644
--- a/libs/common_time/common_clock.cpp
+++ b/libs/common_time/common_clock.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "common_time"
 #include <utils/Log.h>
 
+#include <inttypes.h>
 #include <stdint.h>
 
 #include <utils/Errors.h>
@@ -50,7 +51,7 @@
 
     LinearTransform::reduce(&numer, &denom);
     if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) {
-        ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld",
+        ALOGE("Overflow in CommonClock::init while trying to reduce %" PRIu64 "/%" PRIu64,
              kCommonFreq, local_freq);
         return false;
     }
diff --git a/libs/common_time/common_clock_service.cpp b/libs/common_time/common_clock_service.cpp
index 9ca6f35..592ab1d 100644
--- a/libs/common_time/common_clock_service.cpp
+++ b/libs/common_time/common_clock_service.cpp
@@ -99,14 +99,14 @@
         Mutex::Autolock lock(mCallbackLock);
         // check whether this is a duplicate
         for (size_t i = 0; i < mListeners.size(); i++) {
-            if (mListeners[i]->asBinder() == listener->asBinder())
+            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener))
                 return ALREADY_EXISTS;
         }
     }
 
     mListeners.add(listener);
     mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
-    return listener->asBinder()->linkToDeath(this);
+    return IInterface::asBinder(listener)->linkToDeath(this);
 }
 
 status_t CommonClockService::unregisterListener(
@@ -117,8 +117,8 @@
     {   // scoping for autolock pattern
         Mutex::Autolock lock(mCallbackLock);
         for (size_t i = 0; i < mListeners.size(); i++) {
-            if (mListeners[i]->asBinder() == listener->asBinder()) {
-                mListeners[i]->asBinder()->unlinkToDeath(this);
+            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
+                IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
                 mListeners.removeAt(i);
                 ret_val = OK;
                 break;
@@ -136,7 +136,7 @@
     {   // scoping for autolock pattern
         Mutex::Autolock lock(mCallbackLock);
         for (size_t i = 0; i < mListeners.size(); i++) {
-            if (mListeners[i]->asBinder() == who) {
+            if (IInterface::asBinder(mListeners[i]) == who) {
                 mListeners.removeAt(i);
                 break;
             }
diff --git a/libs/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
index 3e11987..01372e0 100644
--- a/libs/common_time/common_time_server.cpp
+++ b/libs/common_time/common_time_server.cpp
@@ -25,6 +25,7 @@
 #include <arpa/inet.h>
 #include <assert.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <linux/if_ether.h>
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -969,13 +970,14 @@
         // if the RTT of the packet is significantly larger than the panic
         // threshold, we should simply discard it.  Its better to do nothing
         // than to take cues from a packet like that.
-        int rttCommon = mCommonClock.localDurationToCommonDuration(rtt);
+        int64_t rttCommon = mCommonClock.localDurationToCommonDuration(rtt);
         if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * 
                          kRTTDiscardPanicThreshMultiplier)) {
-            ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon);
+            ALOGV("Dropping sync response with RTT of %" PRId64 " uSec", rttCommon);
             mClient_ExpiredSyncRespsRXedFromCurMaster++;
             if (shouldPanicNotGettingGoodData())
                 return becomeInitial("RX panic, no good data");
+            return true;
         } else {
             result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon);
             mClient_LastGoodSyncRX = clientRxLocalTime;
diff --git a/libs/common_time/common_time_server_api.cpp b/libs/common_time/common_time_server_api.cpp
index e157071..e0f35a9 100644
--- a/libs/common_time/common_time_server_api.cpp
+++ b/libs/common_time/common_time_server_api.cpp
@@ -27,6 +27,8 @@
 
 #include "common_time_server.h"
 
+#include <inttypes.h>
+
 namespace android {
 
 //
@@ -286,7 +288,7 @@
 #define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b))
 
 status_t CommonTimeServer::dumpClockInterface(int fd,
-                                              const Vector<String16>& args,
+                                              const Vector<String16>& /* args */,
                                               size_t activeClients) {
     AutoMutex _lock(&mLock);
     const size_t SIZE = 256;
@@ -308,15 +310,15 @@
         synced     = (OK == mCommonClock.localToCommon(localTime, &commonTime));
         sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr));
 
-        dump_printf("Common Clock Service Status\nLocal time     : %lld\n",
+        dump_printf("Common Clock Service Status\nLocal time     : %" PRId64 "\n",
                     localTime);
 
         if (synced)
-            dump_printf("Common time    : %lld\n", commonTime);
+            dump_printf("Common time    : %" PRId64 "\n", commonTime);
         else
             dump_printf("Common time    : %s\n", "not synced");
 
-        dump_printf("Timeline ID    : %016llx\n", mTimelineID);
+        dump_printf("Timeline ID    : %016" PRIu64 "\n", mTimelineID);
         dump_printf("State          : %s\n", stateToString(mState));
         dump_printf("Master Addr    : %s\n", maStr);
 
@@ -349,10 +351,10 @@
             int64_t localDelta, usecDelta;
             localDelta = localTime - mClient_LastGoodSyncRX;
             usecDelta  = mCommonClock.localDurationToCommonDuration(localDelta);
-            dump_printf("Last Good RX   : %lld uSec ago\n", usecDelta);
+            dump_printf("Last Good RX   : %" PRId64 " uSec ago\n", usecDelta);
         }
 
-        dump_printf("Active Clients : %u\n", activeClients);
+        dump_printf("Active Clients : %zu\n", activeClients);
         mClient_PacketRTTLog.dumpLog(fd, mCommonClock);
         mStateChangeLog.dumpLog(fd);
         mElectionLog.dumpLog(fd);
@@ -363,7 +365,7 @@
 }
 
 status_t CommonTimeServer::dumpConfigInterface(int fd,
-                                               const Vector<String16>& args) {
+                                               const Vector<String16>& /* args */) {
     AutoMutex _lock(&mLock);
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -383,7 +385,7 @@
                     "Bound Interface           : %s\n",
                     mBindIfaceValid ? mBindIface.string() : "<unbound>");
         dump_printf("Master Election Endpoint  : %s\n", meStr);
-        dump_printf("Master Election Group ID  : %016llx\n", mSyncGroupID);
+        dump_printf("Master Election Group ID  : %016" PRIu64 "\n", mSyncGroupID);
         dump_printf("Master Announce Interval  : %d mSec\n",
                     mMasterAnnounceIntervalMs);
         dump_printf("Client Sync Interval      : %d mSec\n",
@@ -419,12 +421,12 @@
         if (rxTimes[i]) {
             int64_t delta = rxTimes[i] - txTimes[i];
             int64_t deltaUsec = cclk.localDurationToCommonDuration(delta);
-            dump_printf("pkt[%2d] : localTX %12lld localRX %12lld "
+            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX %12" PRId64 " "
                         "(%.3f msec RTT)\n",
                         ndx, txTimes[i], rxTimes[i],
                         static_cast<float>(deltaUsec) / 1000.0);
         } else {
-            dump_printf("pkt[%2d] : localTX %12lld localRX never\n",
+            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX never\n",
                         ndx, txTimes[i]);
         }
         i = (i + 1) % RTT_LOG_SIZE;
diff --git a/libs/common_time/main.cpp b/libs/common_time/main.cpp
index 49eb30a..ac52c85 100644
--- a/libs/common_time/main.cpp
+++ b/libs/common_time/main.cpp
@@ -27,7 +27,7 @@
 
 #include "common_time_server.h"
 
-int main(int argc, char *argv[]) {
+int main() {
     using namespace android;
 
     sp<CommonTimeServer> service = new CommonTimeServer();
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index b2dba00..0a210d6 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -60,6 +60,7 @@
 #include "AmbientShadow.h"
 #include "ShadowTessellator.h"
 #include "Vertex.h"
+#include "VertexBuffer.h"
 #include "utils/MathUtils.h"
 
 namespace android {
@@ -121,14 +122,14 @@
     *totalUmbraCount = 0;
     if (!isCasterOpaque) {
         // Add the centroid if occluder is translucent.
-        *totalVertexCount++;
+        (*totalVertexCount)++;
         *totalIndexCount += 2 * innerVertexCount + 1;
         *totalUmbraCount = innerVertexCount;
     }
 }
 
 inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
-    return abs(firstAlpha - secondAlpha) > ALPHA_THRESHOLD;
+    return fabsf(firstAlpha - secondAlpha) > ALPHA_THRESHOLD;
 }
 
 /**
@@ -178,7 +179,7 @@
 void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
         const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
         float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
-    shadowVertexBuffer.setMode(VertexBuffer::kIndices);
+    shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
 
     // In order to computer the outer vertices in one loop, we need pre-compute
     // the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 9660dc0..8eb1048 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -19,13 +19,13 @@
 #define ANDROID_HWUI_AMBIENT_SHADOW_H
 
 #include "Debug.h"
-#include "OpenGLRenderer.h"
 #include "Vector.h"
-#include "VertexBuffer.h"
 
 namespace android {
 namespace uirenderer {
 
+class VertexBuffer;
+
 /**
  * AmbientShadow is used to calculate the ambient shadow value around a polygon.
  */
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
new file mode 100644
index 0000000..ecb625b
--- /dev/null
+++ b/libs/hwui/Android.common.mk
@@ -0,0 +1,118 @@
+# getConfig in external/skia/include/core/SkBitmap.h is deprecated.
+# Allow Gnu extension: in-class initializer of static 'const float' member.
+LOCAL_CLANG_CFLAGS += \
+    -Wno-deprecated-declarations \
+    -Wno-gnu-static-float-init
+
+LOCAL_SRC_FILES := \
+    font/CacheTexture.cpp \
+    font/Font.cpp \
+    renderstate/Blend.cpp \
+    renderstate/MeshState.cpp \
+    renderstate/PixelBufferState.cpp \
+    renderstate/RenderState.cpp \
+    renderstate/Scissor.cpp \
+    renderstate/Stencil.cpp \
+    renderstate/TextureState.cpp \
+    renderthread/CanvasContext.cpp \
+    renderthread/DrawFrameTask.cpp \
+    renderthread/EglManager.cpp \
+    renderthread/RenderProxy.cpp \
+    renderthread/RenderTask.cpp \
+    renderthread/RenderThread.cpp \
+    renderthread/TimeLord.cpp \
+    thread/TaskManager.cpp \
+    utils/Blur.cpp \
+    utils/GLUtils.cpp \
+    utils/SortedListImpl.cpp \
+    AmbientShadow.cpp \
+    AnimationContext.cpp \
+    Animator.cpp \
+    AnimatorManager.cpp \
+    AssetAtlas.cpp \
+    Caches.cpp \
+    CanvasState.cpp \
+    ClipArea.cpp \
+    DamageAccumulator.cpp \
+    DeferredDisplayList.cpp \
+    DeferredLayerUpdater.cpp \
+    DisplayList.cpp \
+    DisplayListRenderer.cpp \
+    Dither.cpp \
+    DrawProfiler.cpp \
+    Extensions.cpp \
+    FboCache.cpp \
+    FontRenderer.cpp \
+    FrameInfo.cpp \
+    GammaFontRenderer.cpp \
+    GlopBuilder.cpp \
+    GradientCache.cpp \
+    Image.cpp \
+    Interpolator.cpp \
+    JankTracker.cpp \
+    Layer.cpp \
+    LayerCache.cpp \
+    LayerRenderer.cpp \
+    Matrix.cpp \
+    OpenGLRenderer.cpp \
+    Patch.cpp \
+    PatchCache.cpp \
+    PathCache.cpp \
+    PathTessellator.cpp \
+    PixelBuffer.cpp \
+    Program.cpp \
+    ProgramCache.cpp \
+    RenderBufferCache.cpp \
+    RenderNode.cpp \
+    RenderProperties.cpp \
+    ResourceCache.cpp \
+    ShadowTessellator.cpp \
+    SkiaCanvas.cpp \
+    SkiaCanvasProxy.cpp \
+    SkiaShader.cpp \
+    Snapshot.cpp \
+    SpotShadow.cpp \
+    TessellationCache.cpp \
+    TextDropShadowCache.cpp \
+    Texture.cpp \
+    TextureCache.cpp
+
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+
+LOCAL_C_INCLUDES += \
+    external/skia/src/core
+
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
+LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
+
+ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+    LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
+    LOCAL_SHARED_LIBRARIES += libRS libRScpp
+    LOCAL_C_INCLUDES += \
+        $(intermediates) \
+        frameworks/rs/cpp \
+        frameworks/rs \
+
+endif
+
+ifndef HWUI_COMPILE_SYMBOLS
+    LOCAL_CFLAGS += -fvisibility=hidden
+endif
+
+ifdef HWUI_COMPILE_FOR_PERF
+    # TODO: Non-arm?
+    LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
+endif
+
+ifeq (true, $(HWUI_NULL_GPU))
+    LOCAL_SRC_FILES += \
+        tests/nullegl.cpp \
+        tests/nullgles.cpp
+
+    LOCAL_CFLAGS += -DHWUI_NULL_GPU
+endif
+
+# Defaults for ATRACE_TAG and LOG_TAG for libhwui
+LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
+
+LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wunreachable-code
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 49560ff..91e289c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -1,110 +1,12 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-# Only build libhwui when USE_OPENGL_RENDERER is
-# defined in the current device/board configuration
-ifeq ($(USE_OPENGL_RENDERER),true)
-	LOCAL_SRC_FILES := \
-		utils/Blur.cpp \
-		utils/GLUtils.cpp \
-		utils/SortedListImpl.cpp \
-		thread/TaskManager.cpp \
-		font/CacheTexture.cpp \
-		font/Font.cpp \
-		AmbientShadow.cpp \
-		AnimationContext.cpp \
-		Animator.cpp \
-		AnimatorManager.cpp \
-		AssetAtlas.cpp \
-		DamageAccumulator.cpp \
-		FontRenderer.cpp \
-		GammaFontRenderer.cpp \
-		Caches.cpp \
-		DisplayList.cpp \
-		DeferredDisplayList.cpp \
-		DeferredLayerUpdater.cpp \
-		DisplayListLogBuffer.cpp \
-		DisplayListRenderer.cpp \
-		Dither.cpp \
-		DrawProfiler.cpp \
-		Extensions.cpp \
-		FboCache.cpp \
-		GradientCache.cpp \
-		Image.cpp \
-		Interpolator.cpp \
-		Layer.cpp \
-		LayerCache.cpp \
-		LayerRenderer.cpp \
-		Matrix.cpp \
-		OpenGLRenderer.cpp \
-		Patch.cpp \
-		PatchCache.cpp \
-		PathCache.cpp \
-		PathTessellator.cpp \
-		PixelBuffer.cpp \
-		Program.cpp \
-		ProgramCache.cpp \
-		RenderBufferCache.cpp \
-		RenderNode.cpp \
-		RenderProperties.cpp \
-		RenderState.cpp \
-		ResourceCache.cpp \
-		ShadowTessellator.cpp \
-		SkiaShader.cpp \
-		Snapshot.cpp \
-		SpotShadow.cpp \
-		StatefulBaseRenderer.cpp \
-		Stencil.cpp \
-		TessellationCache.cpp \
-		Texture.cpp \
-		TextureCache.cpp \
-		TextDropShadowCache.cpp
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libhwui
 
-# RenderThread stuff
-	LOCAL_SRC_FILES += \
-		renderthread/CanvasContext.cpp \
-		renderthread/DrawFrameTask.cpp \
-		renderthread/EglManager.cpp \
-		renderthread/RenderProxy.cpp \
-		renderthread/RenderTask.cpp \
-		renderthread/RenderThread.cpp \
-		renderthread/TimeLord.cpp
+include $(LOCAL_PATH)/Android.common.mk
 
-	intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+include $(BUILD_SHARED_LIBRARY)
 
-	LOCAL_C_INCLUDES += \
-		external/skia/src/core
-
-	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-	LOCAL_CFLAGS += -Wno-unused-parameter
-	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
-	LOCAL_MODULE := libhwui
-	LOCAL_MODULE_TAGS := optional
-
-	include external/stlport/libstlport.mk
-
-	ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
-		LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
-		LOCAL_SHARED_LIBRARIES += libRS libRScpp
-		LOCAL_C_INCLUDES += \
-			$(intermediates) \
-			frameworks/rs/cpp \
-			frameworks/rs
-	endif
-
-	ifndef HWUI_COMPILE_SYMBOLS
-		LOCAL_CFLAGS += -fvisibility=hidden
-	endif
-
-	ifdef HWUI_COMPILE_FOR_PERF
-		LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
-	endif
-
-	# Defaults for ATRACE_TAG and LOG_TAG for libhwui
-	LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
-
-	include $(BUILD_SHARED_LIBRARY)
-
-	include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index a20bdae..097be08 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -59,7 +59,7 @@
             "Missed running animations last frame!");
     AnimationHandle* head = mNextFrameAnimations.mNextHandle;
     if (head) {
-        mNextFrameAnimations.mNextHandle = NULL;
+        mNextFrameAnimations.mNextHandle = nullptr;
         mCurrentFrameAnimations.mNextHandle = head;
         head->mPreviousHandle = &mCurrentFrameAnimations;
     }
@@ -84,15 +84,15 @@
 
 AnimationHandle::AnimationHandle(AnimationContext& context)
         : mContext(context)
-        , mPreviousHandle(NULL)
-        , mNextHandle(NULL) {
+        , mPreviousHandle(nullptr)
+        , mNextHandle(nullptr) {
 }
 
 AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
         : mRenderNode(&animatingNode)
         , mContext(context)
-        , mPreviousHandle(NULL)
-        , mNextHandle(NULL) {
+        , mPreviousHandle(nullptr)
+        , mNextHandle(nullptr) {
     mRenderNode->animators().setAnimationHandle(this);
 }
 
@@ -114,7 +114,7 @@
     LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(),
             "Releasing the handle for an RenderNode with outstanding animators!");
     removeFromList();
-    mRenderNode->animators().setAnimationHandle(NULL);
+    mRenderNode->animators().setAnimationHandle(nullptr);
     delete this;
 }
 
@@ -135,8 +135,8 @@
     if (mNextHandle) {
         mNextHandle->mPreviousHandle = mPreviousHandle;
     }
-    mPreviousHandle = NULL;
-    mNextHandle = NULL;
+    mPreviousHandle = nullptr;
+    mNextHandle = nullptr;
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 8bf2107..512e0e2 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -20,6 +20,7 @@
 #include <set>
 
 #include "AnimationContext.h"
+#include "Interpolator.h"
 #include "RenderNode.h"
 #include "RenderProperties.h"
 
@@ -31,11 +32,10 @@
  ************************************************************/
 
 BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
-        : mTarget(NULL)
+        : mTarget(nullptr)
         , mFinalValue(finalValue)
         , mDeltaValue(0)
         , mFromValue(0)
-        , mInterpolator(0)
         , mStagingPlayState(NOT_STARTED)
         , mPlayState(NOT_STARTED)
         , mHasStartValue(false)
@@ -46,7 +46,6 @@
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
-    delete mInterpolator;
 }
 
 void BaseRenderNodeAnimator::checkMutable() {
@@ -57,8 +56,7 @@
 
 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
     checkMutable();
-    delete mInterpolator;
-    mInterpolator = interpolator;
+    mInterpolator.reset(interpolator);
 }
 
 void BaseRenderNodeAnimator::setStartValue(float value) {
@@ -118,7 +116,7 @@
     }
     // No interpolator was set, use the default
     if (!mInterpolator) {
-        mInterpolator = Interpolator::createDefaultInterpolator();
+        mInterpolator.reset(Interpolator::createDefaultInterpolator());
     }
     if (mDuration < 0 || mDuration > 50000) {
         ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 35a4a09..1b3d8e7 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -16,13 +16,12 @@
 #ifndef ANIMATOR_H
 #define ANIMATOR_H
 
+#include <memory>
 #include <cutils/compiler.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
+#include <utils/Timers.h>
 
-#include "CanvasProperty.h"
-#include "Interpolator.h"
-#include "TreeInfo.h"
 #include "utils/Macros.h"
 
 namespace android {
@@ -30,6 +29,9 @@
 
 class AnimationContext;
 class BaseRenderNodeAnimator;
+class CanvasPropertyPrimitive;
+class CanvasPropertyPaint;
+class Interpolator;
 class RenderNode;
 class RenderProperties;
 
@@ -62,7 +64,7 @@
 
     void attach(RenderNode* target);
     virtual void onAttached() {}
-    void detach() { mTarget = 0; }
+    void detach() { mTarget = nullptr; }
     void pushStaging(AnimationContext& context);
     bool animate(AnimationContext& context);
 
@@ -98,7 +100,7 @@
     float mDeltaValue;
     float mFromValue;
 
-    Interpolator* mInterpolator;
+    std::unique_ptr<Interpolator> mInterpolator;
     PlayState mStagingPlayState;
     PlayState mPlayState;
     bool mHasStartValue;
@@ -137,10 +139,10 @@
     ANDROID_API virtual uint32_t dirtyMask();
 
 protected:
-    virtual float getValue(RenderNode* target) const;
-    virtual void setValue(RenderNode* target, float value);
-    virtual void onAttached();
-    virtual void onStagingPlayStateChanged();
+    virtual float getValue(RenderNode* target) const override;
+    virtual void setValue(RenderNode* target, float value) override;
+    virtual void onAttached() override;
+    virtual void onStagingPlayStateChanged() override;
 
 private:
     typedef bool (RenderProperties::*SetFloatProperty)(float value);
@@ -160,8 +162,8 @@
     ANDROID_API virtual uint32_t dirtyMask();
 
 protected:
-    virtual float getValue(RenderNode* target) const;
-    virtual void setValue(RenderNode* target, float value);
+    virtual float getValue(RenderNode* target) const override;
+    virtual void setValue(RenderNode* target, float value) override;
 private:
     sp<CanvasPropertyPrimitive> mProperty;
 };
@@ -179,8 +181,8 @@
     ANDROID_API virtual uint32_t dirtyMask();
 
 protected:
-    virtual float getValue(RenderNode* target) const;
-    virtual void setValue(RenderNode* target, float value);
+    virtual float getValue(RenderNode* target) const override;
+    virtual void setValue(RenderNode* target, float value) override;
 private:
     sp<CanvasPropertyPaint> mProperty;
     PaintField mField;
@@ -194,8 +196,8 @@
     ANDROID_API virtual uint32_t dirtyMask();
 
 protected:
-    virtual float getValue(RenderNode* target) const;
-    virtual void setValue(RenderNode* target, float value);
+    virtual float getValue(RenderNode* target) const override;
+    virtual void setValue(RenderNode* target, float value) override;
 
 private:
     int mCenterX, mCenterY;
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index c28fb88..966959a 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,7 +17,9 @@
 
 #include <algorithm>
 
+#include "Animator.h"
 #include "AnimationContext.h"
+#include "DamageAccumulator.h"
 #include "RenderNode.h"
 
 namespace android {
@@ -27,12 +29,12 @@
 
 static void unref(BaseRenderNodeAnimator* animator) {
     animator->detach();
-    animator->decStrong(0);
+    animator->decStrong(nullptr);
 }
 
 AnimatorManager::AnimatorManager(RenderNode& parent)
         : mParent(parent)
-        , mAnimationHandle(NULL) {
+        , mAnimationHandle(nullptr) {
 }
 
 AnimatorManager::~AnimatorManager() {
@@ -41,7 +43,7 @@
 }
 
 void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-    animator->incStrong(0);
+    animator->incStrong(nullptr);
     animator->attach(&mParent);
     mNewAnimators.push_back(animator.get());
 }
@@ -85,7 +87,7 @@
         dirtyMask |= animator->dirtyMask();
         bool remove = animator->animate(mContext);
         if (remove) {
-            animator->decStrong(0);
+            animator->decStrong(nullptr);
         } else {
             if (animator->isRunning()) {
                 mInfo.out.hasAnimations = true;
@@ -142,7 +144,7 @@
     if (animator->listener()) {
         animator->listener()->onAnimationFinished(animator);
     }
-    animator->decStrong(0);
+    animator->decStrong(nullptr);
 }
 
 void AnimatorManager::endAllStagingAnimators() {
@@ -159,7 +161,7 @@
 
     void operator() (BaseRenderNodeAnimator* animator) {
         animator->forceEndNow(mContext);
-        animator->decStrong(0);
+        animator->decStrong(nullptr);
     }
 
 private:
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index d03d427..fb75eb8 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -21,7 +21,6 @@
 #include <cutils/compiler.h>
 #include <utils/StrongPointer.h>
 
-#include "TreeInfo.h"
 #include "utils/Macros.h"
 
 namespace android {
@@ -30,6 +29,7 @@
 class AnimationHandle;
 class BaseRenderNodeAnimator;
 class RenderNode;
+class TreeInfo;
 
 // Responsible for managing the animators for a single RenderNode
 class AnimatorManager {
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 52ca92d..4d2e3a0 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -18,6 +18,7 @@
 
 #include "AssetAtlas.h"
 #include "Caches.h"
+#include "Image.h"
 
 #include <GLES2/gl2ext.h>
 
@@ -47,7 +48,7 @@
     } else {
         ALOGW("Could not create atlas image");
         delete mImage;
-        mImage = NULL;
+        mImage = nullptr;
     }
 
     updateTextureId();
@@ -56,7 +57,7 @@
 void AssetAtlas::terminate() {
     if (mImage) {
         delete mImage;
-        mImage = NULL;
+        mImage = nullptr;
         updateTextureId();
     }
 }
@@ -82,12 +83,12 @@
 
 AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const {
     ssize_t index = mEntries.indexOfKey(bitmap);
-    return index >= 0 ? mEntries.valueAt(index) : NULL;
+    return index >= 0 ? mEntries.valueAt(index) : nullptr;
 }
 
 Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const {
     ssize_t index = mEntries.indexOfKey(bitmap);
-    return index >= 0 ? mEntries.valueAt(index)->texture : NULL;
+    return index >= 0 ? mEntries.valueAt(index)->texture : nullptr;
 }
 
 /**
@@ -98,12 +99,12 @@
     DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { }
 
     virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
-            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
         mDelegate->setWrapST(wrapS, wrapT, bindTexture, force, renderTarget);
     }
 
     virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
-            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
         mDelegate->setFilterMinMag(min, mag, bindTexture, force, renderTarget);
     }
 
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index fffd740..1772eff 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -27,7 +27,6 @@
 
 #include <SkBitmap.h>
 
-#include "Image.h"
 #include "Texture.h"
 #include "UvMapper.h"
 
@@ -35,6 +34,7 @@
 namespace uirenderer {
 
 class Caches;
+class Image;
 
 /**
  * An asset atlas holds a collection of framework bitmaps in a single OpenGL
@@ -106,7 +106,7 @@
         friend class AssetAtlas;
     };
 
-    AssetAtlas(): mTexture(NULL), mImage(NULL),
+    AssetAtlas(): mTexture(nullptr), mImage(nullptr),
             mBlendKey(true), mOpaqueKey(false) { }
     ~AssetAtlas() { terminate(); }
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index cdf8150..e5489a8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -16,25 +16,23 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
+#include "Caches.h"
+
+#include "DisplayListRenderer.h"
+#include "GammaFontRenderer.h"
+#include "LayerRenderer.h"
+#include "Properties.h"
+#include "renderstate/RenderState.h"
+#include "ShadowTessellator.h"
+
 #include <utils/Log.h>
 #include <utils/String8.h>
 
-#include "Caches.h"
-#include "DisplayListRenderer.h"
-#include "Properties.h"
-#include "LayerRenderer.h"
-#include "ShadowTessellator.h"
-#include "RenderState.h"
-
 namespace android {
-
-#ifdef USE_OPENGL_RENDERER
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
-#endif
-
 namespace uirenderer {
 
+Caches* Caches::sInstance = nullptr;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Macros
 ///////////////////////////////////////////////////////////////////////////////
@@ -49,8 +47,14 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Caches::Caches(): Singleton<Caches>(),
-        mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(NULL) {
+Caches::Caches(RenderState& renderState)
+        : gradientCache(mExtensions)
+        , patchCache(renderState)
+        , programCache(mExtensions)
+        , dither(*this)
+        , mRenderState(&renderState)
+        , mInitialized(false) {
+    INIT_LOGD("Creating OpenGL renderer caches");
     init();
     initFont();
     initConstraints();
@@ -60,7 +64,8 @@
     initTempProperties();
 
     mDebugLevel = readDebugLevel();
-    ALOGD("Enabling debug mode %d", mDebugLevel);
+    ALOGD_IF(mDebugLevel != kDebugDisabled,
+            "Enabling debug mode %d", mDebugLevel);
 }
 
 bool Caches::init() {
@@ -68,33 +73,8 @@
 
     ATRACE_NAME("Caches::init");
 
-    glGenBuffers(1, &meshBuffer);
-    glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
-    mCurrentBuffer = meshBuffer;
-    mCurrentIndicesBuffer = 0;
-    mCurrentPositionPointer = this;
-    mCurrentPositionStride = 0;
-    mCurrentTexCoordsPointer = this;
-    mCurrentPixelBuffer = 0;
-
-    mTexCoordsArrayEnabled = false;
-
-    glDisable(GL_SCISSOR_TEST);
-    scissorEnabled = false;
-    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
-
-    glActiveTexture(gTextureUnits[0]);
-    mTextureUnit = 0;
-
-    mRegionMesh = NULL;
-    mMeshIndices = 0;
-    mShadowStripsIndices = 0;
-    blend = false;
-    lastSrcMode = GL_ZERO;
-    lastDstMode = GL_ZERO;
-    currentProgram = NULL;
+    mRegionMesh = nullptr;
+    mProgram = nullptr;
 
     mFunctorsCount = 0;
 
@@ -102,11 +82,12 @@
     debugOverdraw = false;
     debugStencilClip = kStencilHide;
 
-    patchCache.init(*this);
+    patchCache.init();
 
     mInitialized = true;
 
-    resetBoundTextures();
+    mPixelBufferState = new PixelBufferState();
+    mTextureState = new TextureState();
 
     return true;
 }
@@ -126,23 +107,9 @@
         startMark = startMarkNull;
         endMark = endMarkNull;
     }
-
-    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
-        setLabel = glLabelObjectEXT;
-        getLabel = glGetObjectLabelEXT;
-    } else {
-        setLabel = setLabelNull;
-        getLabel = getLabelNull;
-    }
 }
 
 void Caches::initConstraints() {
-    GLint maxTextureUnits;
-    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
-    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
-        ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
-    }
-
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 }
 
@@ -164,7 +131,7 @@
     StencilClipDebug prevDebugStencilClip = debugStencilClip;
 
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
+    if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) {
         INIT_LOGD("  Layers updates debug enabled: %s", property);
         debugLayersUpdates = !strcmp(property, "true");
     } else {
@@ -172,7 +139,7 @@
     }
 
     debugOverdraw = false;
-    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
+    if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
         INIT_LOGD("  Overdraw debug enabled: %s", property);
         if (!strcmp(property, "show")) {
             debugOverdraw = true;
@@ -184,7 +151,7 @@
     }
 
     // See Properties.h for valid values
-    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
+    if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
         INIT_LOGD("  Stencil clip debug enabled: %s", property);
         if (!strcmp(property, "hide")) {
             debugStencilClip = kStencilHide;
@@ -213,37 +180,47 @@
         INIT_LOGD("  Draw reorder enabled");
     }
 
-    return (prevDebugLayersUpdates != debugLayersUpdates) ||
-            (prevDebugOverdraw != debugOverdraw) ||
-            (prevDebugStencilClip != debugStencilClip);
+    return (prevDebugLayersUpdates != debugLayersUpdates)
+            || (prevDebugOverdraw != debugOverdraw)
+            || (prevDebugStencilClip != debugStencilClip);
 }
 
 void Caches::terminate() {
     if (!mInitialized) return;
-
-    glDeleteBuffers(1, &meshBuffer);
-    mCurrentBuffer = 0;
-
-    glDeleteBuffers(1, &mMeshIndices);
-    delete[] mRegionMesh;
-    mMeshIndices = 0;
-    mRegionMesh = NULL;
-
-    glDeleteBuffers(1, &mShadowStripsIndices);
-    mShadowStripsIndices = 0;
+    mRegionMesh.release();
 
     fboCache.clear();
 
     programCache.clear();
-    currentProgram = NULL;
+    mProgram = nullptr;
 
     patchCache.clear();
 
     clearGarbage();
 
+    delete mPixelBufferState;
+    mPixelBufferState = nullptr;
+    delete mTextureState;
+    mTextureState = nullptr;
     mInitialized = false;
 }
 
+void Caches::setProgram(const ProgramDescription& description) {
+    setProgram(programCache.get(description));
+}
+
+void Caches::setProgram(Program* program) {
+    if (!program || !program->isInUse()) {
+        if (mProgram) {
+            mProgram->remove();
+        }
+        if (program) {
+            program->use();
+        }
+        mProgram = program;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Debug
 ///////////////////////////////////////////////////////////////////////////////
@@ -278,7 +255,7 @@
             const Layer* layer = *it;
             log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
                     layer->getWidth(), layer->getHeight(),
-                    layer->isTextureLayer(), layer->getTexture(),
+                    layer->isTextureLayer(), layer->getTextureId(),
                     layer->getFbo(), layer->getStrongCount());
             memused += layer->getWidth() * layer->getHeight() * 4;
         }
@@ -371,285 +348,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// VBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindMeshBuffer() {
-    return bindMeshBuffer(meshBuffer);
-}
-
-bool Caches::bindMeshBuffer(const GLuint buffer) {
-    if (mCurrentBuffer != buffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, buffer);
-        mCurrentBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindMeshBuffer() {
-    if (mCurrentBuffer) {
-        glBindBuffer(GL_ARRAY_BUFFER, 0);
-        mCurrentBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
-    if (mCurrentIndicesBuffer != buffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
-        mCurrentIndicesBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::bindQuadIndicesBuffer() {
-    if (!mMeshIndices) {
-        uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
-        for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
-            uint16_t quad = i * 4;
-            int index = i * 6;
-            regionIndices[index    ] = quad;       // top-left
-            regionIndices[index + 1] = quad + 1;   // top-right
-            regionIndices[index + 2] = quad + 2;   // bottom-left
-            regionIndices[index + 3] = quad + 2;   // bottom-left
-            regionIndices[index + 4] = quad + 1;   // top-right
-            regionIndices[index + 5] = quad + 3;   // bottom-right
-        }
-
-        glGenBuffers(1, &mMeshIndices);
-        bool force = bindIndicesBufferInternal(mMeshIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
-                regionIndices, GL_STATIC_DRAW);
-
-        delete[] regionIndices;
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mMeshIndices);
-}
-
-bool Caches::bindShadowIndicesBuffer() {
-    if (!mShadowStripsIndices) {
-        uint16_t* shadowIndices = new uint16_t[MAX_SHADOW_INDEX_COUNT];
-        ShadowTessellator::generateShadowIndices(shadowIndices);
-        glGenBuffers(1, &mShadowStripsIndices);
-        bool force = bindIndicesBufferInternal(mShadowStripsIndices);
-        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
-            shadowIndices, GL_STATIC_DRAW);
-
-        delete[] shadowIndices;
-        return force;
-    }
-
-    return bindIndicesBufferInternal(mShadowStripsIndices);
-}
-
-bool Caches::unbindIndicesBuffer() {
-    if (mCurrentIndicesBuffer) {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-        mCurrentIndicesBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindPixelBuffer(const GLuint buffer) {
-    if (mCurrentPixelBuffer != buffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
-        mCurrentPixelBuffer = buffer;
-        return true;
-    }
-    return false;
-}
-
-bool Caches::unbindPixelBuffer() {
-    if (mCurrentPixelBuffer) {
-        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
-        mCurrentPixelBuffer = 0;
-        return true;
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Meshes and textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
-        GLuint slot = currentProgram->position;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentPositionPointer = vertices;
-        mCurrentPositionStride = stride;
-    }
-}
-
-void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
-    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
-        GLuint slot = currentProgram->texCoords;
-        glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
-        mCurrentTexCoordsPointer = vertices;
-        mCurrentTexCoordsStride = stride;
-    }
-}
-
-void Caches::resetVertexPointers() {
-    mCurrentPositionPointer = this;
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::resetTexCoordsVertexPointer() {
-    mCurrentTexCoordsPointer = this;
-}
-
-void Caches::enableTexCoordsVertexArray() {
-    if (!mTexCoordsArrayEnabled) {
-        glEnableVertexAttribArray(Program::kBindingTexCoords);
-        mCurrentTexCoordsPointer = this;
-        mTexCoordsArrayEnabled = true;
-    }
-}
-
-void Caches::disableTexCoordsVertexArray() {
-    if (mTexCoordsArrayEnabled) {
-        glDisableVertexAttribArray(Program::kBindingTexCoords);
-        mTexCoordsArrayEnabled = false;
-    }
-}
-
-void Caches::activeTexture(GLuint textureUnit) {
-    if (mTextureUnit != textureUnit) {
-        glActiveTexture(gTextureUnits[textureUnit]);
-        mTextureUnit = textureUnit;
-    }
-}
-
-void Caches::resetActiveTexture() {
-    mTextureUnit = -1;
-}
-
-void Caches::bindTexture(GLuint texture) {
-    if (mBoundTextures[mTextureUnit] != texture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
-        mBoundTextures[mTextureUnit] = texture;
-    }
-}
-
-void Caches::bindTexture(GLenum target, GLuint texture) {
-    if (target == GL_TEXTURE_2D) {
-        bindTexture(texture);
-    } else {
-        // GLConsumer directly calls glBindTexture() with
-        // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
-        // since the cached state could be stale
-        glBindTexture(target, texture);
-    }
-}
-
-void Caches::deleteTexture(GLuint texture) {
-    // When glDeleteTextures() is called on a currently bound texture,
-    // OpenGL ES specifies that the texture is then considered unbound
-    // Consider the following series of calls:
-    //
-    // glGenTextures -> creates texture name 2
-    // glBindTexture(2)
-    // glDeleteTextures(2) -> 2 is now unbound
-    // glGenTextures -> can return 2 again
-    //
-    // If we don't call glBindTexture(2) after the second glGenTextures
-    // call, any texture operation will be performed on the default
-    // texture (name=0)
-
-    unbindTexture(texture);
-
-    glDeleteTextures(1, &texture);
-}
-
-void Caches::resetBoundTextures() {
-    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
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
-    if (scissorEnabled && (x != mScissorX || y != mScissorY ||
-            width != mScissorWidth || height != mScissorHeight)) {
-
-        if (x < 0) {
-            width += x;
-            x = 0;
-        }
-        if (y < 0) {
-            height += y;
-            y = 0;
-        }
-        if (width < 0) {
-            width = 0;
-        }
-        if (height < 0) {
-            height = 0;
-        }
-        glScissor(x, y, width, height);
-
-        mScissorX = x;
-        mScissorY = y;
-        mScissorWidth = width;
-        mScissorHeight = height;
-
-        return true;
-    }
-    return false;
-}
-
-bool Caches::enableScissor() {
-    if (!scissorEnabled) {
-        glEnable(GL_SCISSOR_TEST);
-        scissorEnabled = true;
-        resetScissor();
-        return true;
-    }
-    return false;
-}
-
-bool Caches::disableScissor() {
-    if (scissorEnabled) {
-        glDisable(GL_SCISSOR_TEST);
-        scissorEnabled = false;
-        return true;
-    }
-    return false;
-}
-
-void Caches::setScissorEnabled(bool enabled) {
-    if (scissorEnabled != enabled) {
-        if (enabled) glEnable(GL_SCISSOR_TEST);
-        else glDisable(GL_SCISSOR_TEST);
-        scissorEnabled = enabled;
-    }
-}
-
-void Caches::resetScissor() {
-    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Tiling
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -688,10 +386,10 @@
 TextureVertex* Caches::getRegionMesh() {
     // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
     if (!mRegionMesh) {
-        mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
+        mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
     }
 
-    return mRegionMesh;
+    return mRegionMesh.get();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -699,7 +397,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Caches::initTempProperties() {
-    propertyLightDiameter = -1.0f;
+    propertyLightRadius = -1.0f;
     propertyLightPosY = -1.0f;
     propertyLightPosZ = -1.0f;
     propertyAmbientRatio = -1.0f;
@@ -713,9 +411,9 @@
         propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
         ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
         return;
-    } else if (!strcmp(name, "lightDiameter")) {
-        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
-        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
+    } else if (!strcmp(name, "lightRadius")) {
+        propertyLightRadius = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightRadius = %.2f", propertyLightRadius);
         return;
     } else if (!strcmp(name, "lightPosY")) {
         propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 2e179af..8aea8ff 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,7 +21,28 @@
     #define LOG_TAG "OpenGLRenderer"
 #endif
 
+
+#include "AssetAtlas.h"
+#include "Dither.h"
+#include "Extensions.h"
+#include "FboCache.h"
+#include "GradientCache.h"
+#include "LayerCache.h"
+#include "PatchCache.h"
+#include "ProgramCache.h"
+#include "PathCache.h"
+#include "RenderBufferCache.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
+#include "ResourceCache.h"
+#include "TessellationCache.h"
+#include "TextDropShadowCache.h"
+#include "TextureCache.h"
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
+
 #include <vector>
+#include <memory>
 
 #include <GLES3/gl3.h>
 
@@ -31,76 +52,12 @@
 
 #include <cutils/compiler.h>
 
-#include "thread/TaskProcessor.h"
-#include "thread/TaskManager.h"
-
-#include "AssetAtlas.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "GammaFontRenderer.h"
-#include "TextureCache.h"
-#include "LayerCache.h"
-#include "RenderBufferCache.h"
-#include "GradientCache.h"
-#include "PatchCache.h"
-#include "ProgramCache.h"
-#include "PathCache.h"
-#include "TessellationCache.h"
-#include "TextDropShadowCache.h"
-#include "FboCache.h"
-#include "ResourceCache.h"
-#include "Stencil.h"
-#include "Dither.h"
+#include <SkPath.h>
 
 namespace android {
 namespace uirenderer {
 
-///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
-
-// GL ES 2.0 defines that at least 16 texture units must be supported
-#define REQUIRED_TEXTURE_UNITS_COUNT 3
-
-// Maximum number of quads that pre-allocated meshes can draw
-static const uint32_t gMaxNumberOfQuads = 2048;
-
-// Generates simple and textured vertices
-#define FV(x, y, u, v) { x, y, u, v }
-
-// This array is never used directly but used as a memcpy source in the
-// OpenGLRenderer constructor
-static const TextureVertex gMeshVertices[] = {
-        FV(0.0f, 0.0f, 0.0f, 0.0f),
-        FV(1.0f, 0.0f, 1.0f, 0.0f),
-        FV(0.0f, 1.0f, 0.0f, 1.0f),
-        FV(1.0f, 1.0f, 1.0f, 1.0f)
-};
-static const GLsizei gMeshStride = sizeof(TextureVertex);
-static const GLsizei gVertexStride = sizeof(Vertex);
-static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
-static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
-static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
-static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
-static const GLsizei gMeshCount = 4;
-
-// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
-static const GLenum gTextureUnits[] = {
-    GL_TEXTURE0,
-    GL_TEXTURE1,
-    GL_TEXTURE2
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Debug
-///////////////////////////////////////////////////////////////////////////////
-
-struct CacheLogger {
-    CacheLogger() {
-        INIT_LOGD("Creating OpenGL renderer caches");
-    }
-}; // struct CacheLogger
+class GammaFontRenderer;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Caches
@@ -109,12 +66,25 @@
 class RenderNode;
 class RenderState;
 
-class ANDROID_API Caches: public Singleton<Caches> {
-    Caches();
+class ANDROID_API Caches {
+public:
+    static Caches& createInstance(RenderState& renderState) {
+        LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted");
+        sInstance = new Caches(renderState);
+        return *sInstance;
+    }
 
-    friend class Singleton<Caches>;
+    static Caches& getInstance() {
+        LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created");
+        return *sInstance;
+    }
 
-    CacheLogger mLogger;
+    static bool hasInstance() {
+        return sInstance != 0;
+    }
+private:
+    Caches(RenderState& renderState);
+    static Caches* sInstance;
 
 public:
     enum FlushMode {
@@ -133,8 +103,6 @@
      */
     bool initProperties();
 
-    void setRenderState(RenderState* renderState) { mRenderState = renderState; }
-
     /**
      * Flush the cache.
      *
@@ -173,116 +141,6 @@
      */
     void deleteLayerDeferred(Layer* layer);
 
-    /**
-     * Binds the VBO used to render simple textured quads.
-     */
-    bool bindMeshBuffer();
-
-    /**
-     * Binds the specified VBO if needed.
-     */
-    bool bindMeshBuffer(const GLuint buffer);
-
-    /**
-     * Unbinds the VBO used to render simple textured quads.
-     */
-    bool unbindMeshBuffer();
-
-    /**
-     * Binds a global indices buffer that can draw up to
-     * gMaxNumberOfQuads quads.
-     */
-    bool bindQuadIndicesBuffer();
-    bool bindShadowIndicesBuffer();
-    bool unbindIndicesBuffer();
-
-    /**
-     * Binds the specified buffer as the current GL unpack pixel buffer.
-     */
-    bool bindPixelBuffer(const GLuint buffer);
-
-    /**
-     * Resets the current unpack pixel buffer to 0 (default value.)
-     */
-    bool unbindPixelBuffer();
-
-    /**
-     * Binds an attrib to the specified float vertex pointer.
-     * Assumes a stride of gMeshStride and a size of 2.
-     */
-    void bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
-    /**
-     * Binds an attrib to the specified float vertex pointer.
-     * Assumes a stride of gMeshStride and a size of 2.
-     */
-    void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
-    /**
-     * Resets the vertex pointers.
-     */
-    void resetVertexPointers();
-    void resetTexCoordsVertexPointer();
-
-    void enableTexCoordsVertexArray();
-    void disableTexCoordsVertexArray();
-
-    /**
-     * Activate the specified texture unit. The texture unit must
-     * be specified using an integer number (0 for GL_TEXTURE0 etc.)
-     */
-    void activeTexture(GLuint textureUnit);
-
-    /**
-     * Invalidate the cached value of the active texture unit.
-     */
-    void resetActiveTexture();
-
-    /**
-     * Binds the specified texture as a GL_TEXTURE_2D texture.
-     * All texture bindings must be performed with this method or
-     * bindTexture(GLenum, GLuint).
-     */
-    void bindTexture(GLuint texture);
-
-    /**
-     * Binds the specified texture with the specified render target.
-     * All texture bindings must be performed with this method or
-     * bindTexture(GLuint).
-     */
-    void bindTexture(GLenum target, GLuint texture);
-
-    /**
-     * Deletes the specified texture and clears it from the cache
-     * of bound textures.
-     * All textures must be deleted using this method.
-     */
-    void deleteTexture(GLuint texture);
-
-    /**
-     * Signals that the cache of bound textures should be cleared.
-     * Other users of the context may have altered which textures are bound.
-     */
-    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);
-
-    /**
-     * Resets the scissor state.
-     */
-    void resetScissor();
-
-    bool enableScissor();
-    bool disableScissor();
-    void setScissorEnabled(bool enabled);
 
     void startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard);
     void endTiling();
@@ -304,18 +162,9 @@
     void registerFunctors(uint32_t functorCount);
     void unregisterFunctors(uint32_t functorCount);
 
-    bool blend;
-    GLenum lastSrcMode;
-    GLenum lastDstMode;
-    Program* currentProgram;
-    bool scissorEnabled;
-
     bool drawDeferDisabled;
     bool drawReorderDisabled;
 
-    // VBO to draw with
-    GLuint meshBuffer;
-
     // Misc
     GLint maxTextureSize;
 
@@ -329,14 +178,18 @@
         kStencilShowRegion
     };
     StencilClipDebug debugStencilClip;
-
+private:
+    // Declared before gradientCache and programCache which need this to initialize.
+    // TODO: cleanup / move elsewhere
+    Extensions mExtensions;
+public:
     TextureCache textureCache;
     LayerCache layerCache;
     RenderBufferCache renderBufferCache;
     GradientCache gradientCache;
-    ProgramCache programCache;
-    PathCache pathCache;
     PatchCache patchCache;
+    PathCache pathCache;
+    ProgramCache programCache;
     TessellationCache tessellationCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
@@ -346,7 +199,6 @@
     TaskManager tasks;
 
     Dither dither;
-    Stencil stencil;
 
     bool gpuPixelBuffersEnabled;
 
@@ -355,20 +207,25 @@
     PFNGLPUSHGROUPMARKEREXTPROC startMark;
     PFNGLPOPGROUPMARKEREXTPROC endMark;
 
-    PFNGLLABELOBJECTEXTPROC setLabel;
-    PFNGLGETOBJECTLABELEXTPROC getLabel;
-
     // TEMPORARY properties
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
 
-    float propertyLightDiameter;
+    float propertyLightRadius;
     float propertyLightPosY;
     float propertyLightPosZ;
     float propertyAmbientRatio;
     int propertyAmbientShadowStrength;
     int propertySpotShadowStrength;
 
+    void setProgram(const ProgramDescription& description);
+    void setProgram(Program* program);
+
+    Extensions& extensions() { return mExtensions; }
+    Program& program() { return *mProgram; }
+    PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
+    TextureState& textureState() { return *mTextureState; }
+
 private:
     enum OverdrawColorSet {
         kColorSet_Default = 0,
@@ -380,45 +237,14 @@
     void initConstraints();
     void initStaticProperties();
 
-    bool bindIndicesBufferInternal(const GLuint buffer);
-
     static void eventMarkNull(GLsizei length, const GLchar* marker) { }
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
     static void endMarkNull() { }
 
-    static void setLabelNull(GLenum type, uint object, GLsizei length,
-            const char* label) { }
-    static void getLabelNull(GLenum type, uint object, GLsizei bufferSize,
-            GLsizei* length, char* label) {
-        if (length) *length = 0;
-        if (label) *label = '\0';
-    }
-
-    GLuint mCurrentBuffer;
-    GLuint mCurrentIndicesBuffer;
-    GLuint mCurrentPixelBuffer;
-    const void* mCurrentPositionPointer;
-    GLsizei mCurrentPositionStride;
-    const void* mCurrentTexCoordsPointer;
-    GLsizei mCurrentTexCoordsStride;
-
-    bool mTexCoordsArrayEnabled;
-
-    GLuint mTextureUnit;
-
-    GLint mScissorX;
-    GLint mScissorY;
-    GLint mScissorWidth;
-    GLint mScissorHeight;
-
-    Extensions& mExtensions;
+    RenderState* mRenderState;
 
     // Used to render layers
-    TextureVertex* mRegionMesh;
-
-    // Global index buffer
-    GLuint mMeshIndices;
-    GLuint mShadowStripsIndices;
+    std::unique_ptr<TextureVertex[]> mRegionMesh;
 
     mutable Mutex mGarbageLock;
     Vector<Layer*> mLayerGarbage;
@@ -428,12 +254,13 @@
 
     uint32_t mFunctorsCount;
 
-    // Caches texture bindings for the GL_TEXTURE_2D target
-    GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
-
     OverdrawColorSet mOverdrawDebugColorSet;
 
-    RenderState* mRenderState;
+    // TODO: move below to RenderState
+    PixelBufferState* mPixelBufferState = nullptr;
+    TextureState* mTextureState = nullptr;
+    Program* mProgram = nullptr; // note: object owned by ProgramCache
+
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
new file mode 100644
index 0000000..7ad0683
--- /dev/null
+++ b/libs/hwui/Canvas.h
@@ -0,0 +1,163 @@
+/*
+ * 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_GRAPHICS_CANVAS_H
+#define ANDROID_GRAPHICS_CANVAS_H
+
+#include <cutils/compiler.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+
+namespace android {
+
+class ANDROID_API Canvas {
+public:
+    virtual ~Canvas() {};
+
+    static Canvas* create_canvas(SkBitmap* bitmap);
+
+    /**
+     *  Create a new Canvas object which delegates to an SkCanvas.
+     *
+     *  @param skiaCanvas Must not be NULL. All drawing calls will be
+     *      delegated to this object. This function will call ref() on the
+     *      SkCanvas, and the returned Canvas will unref() it upon
+     *      destruction.
+     *  @return new Canvas object. Will not return NULL.
+     */
+    static Canvas* create_canvas(SkCanvas* skiaCanvas);
+
+    /**
+     *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
+     *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
+     *  draw their contents into an SkCanvas.
+     *
+     *  Further, the returned SkCanvas should NOT be unref'd and is valid until
+     *  this canvas is destroyed or a new bitmap is set.
+     */
+    virtual SkCanvas* asSkCanvas() = 0;
+
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
+
+    virtual bool isOpaque() = 0;
+    virtual int width() = 0;
+    virtual int height() = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+    // Save (layer)
+    virtual int getSaveCount() const = 0;
+    virtual int save(SkCanvas::SaveFlags flags) = 0;
+    virtual void restore() = 0;
+    virtual void restoreToCount(int saveCount) = 0;
+
+    virtual int saveLayer(float left, float top, float right, float bottom,
+                const SkPaint* paint, SkCanvas::SaveFlags flags) = 0;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SkCanvas::SaveFlags flags) = 0;
+
+    // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
+    virtual void setMatrix(const SkMatrix& matrix) = 0;
+
+    virtual void concat(const SkMatrix& matrix) = 0;
+    virtual void rotate(float degrees) = 0;
+    virtual void scale(float sx, float sy) = 0;
+    virtual void skew(float sx, float sy) = 0;
+    virtual void translate(float dx, float dy) = 0;
+
+    // clip
+    virtual bool getClipBounds(SkRect* outRect) const = 0;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
+    virtual bool quickRejectPath(const SkPath& path) const = 0;
+
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
+
+    // filters
+    virtual SkDrawFilter* getDrawFilter() = 0;
+    virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
+    virtual void drawPaint(const SkPaint& paint) = 0;
+
+    // Geometry
+    virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+                const SkPaint& paint) = 0;
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0;
+    virtual void drawRect(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) = 0;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+    virtual void drawOval(float left, float top, float right, float bottom,
+            const SkPaint& paint) = 0;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
+    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+                              const float* verts, const float* tex, const int* colors,
+                              const uint16_t* indices, int indexCount, const SkPaint& paint) = 0;
+
+    // Bitmap-based
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+            const SkPaint* paint) = 0;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) = 0;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) = 0;
+
+    // Text
+    /**
+     * drawText: count is of glyphs
+     * totalAdvance is ignored in software renderering, used by hardware renderer for
+     * text decorations (underlines, strikethroughs).
+     */
+    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+            float totalAdvance) = 0;
+    /** drawPosText: count is of UTF16 characters, posCount is floats (2 * glyphs) */
+    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) = 0;
+    /** drawTextOnPath: count is of glyphs */
+    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) = 0;
+
+    /**
+     * Specifies if the positions passed to ::drawText are absolute or relative
+     * to the (x,y) value provided.
+     *
+     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
+     * to be added to each glyph's position to get its absolute position.
+     */
+    virtual bool drawTextAbsolutePos() const = 0;
+};
+
+}; // namespace android
+#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
new file mode 100644
index 0000000..e88e9f6
--- /dev/null
+++ b/libs/hwui/CanvasState.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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 <SkCanvas.h>
+
+#include "CanvasState.h"
+#include "utils/MathUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+
+CanvasState::CanvasState(CanvasStateClient& renderer)
+        : mDirtyClip(false)
+        , mWidth(-1)
+        , mHeight(-1)
+        , mSaveCount(1)
+        , mFirstSnapshot(new Snapshot)
+        , mCanvas(renderer)
+        , mSnapshot(mFirstSnapshot) {
+
+}
+
+CanvasState::~CanvasState() {
+
+}
+
+void CanvasState::initializeSaveStack(float clipLeft, float clipTop,
+        float clipRight, float clipBottom, const Vector3& lightCenter) {
+    mSnapshot = new Snapshot(mFirstSnapshot,
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
+    mSnapshot->fbo = mCanvas.getTargetFbo();
+    mSnapshot->setRelativeLightCenter(lightCenter);
+    mSaveCount = 1;
+}
+
+void CanvasState::setViewport(int width, int height) {
+    mWidth = width;
+    mHeight = height;
+    mFirstSnapshot->initializeViewport(width, height);
+    mCanvas.onViewportInitialized();
+
+    // create a temporary 1st snapshot, so old snapshots are released,
+    // and viewport can be queried safely.
+    // TODO: remove, combine viewport + save stack initialization
+    mSnapshot = new Snapshot(mFirstSnapshot,
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    mSaveCount = 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Save (layer)
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Guaranteed to save without side-effects
+ *
+ * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
+ * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
+ */
+int CanvasState::saveSnapshot(int flags) {
+    mSnapshot = new Snapshot(mSnapshot, flags);
+    return mSaveCount++;
+}
+
+int CanvasState::save(int flags) {
+    return saveSnapshot(flags);
+}
+
+/**
+ * Guaranteed to restore without side-effects.
+ */
+void CanvasState::restoreSnapshot() {
+    sp<Snapshot> toRemove = mSnapshot;
+    sp<Snapshot> toRestore = mSnapshot->previous;
+
+    mSaveCount--;
+    mSnapshot = toRestore;
+
+    // subclass handles restore implementation
+    mCanvas.onSnapshotRestored(*toRemove, *toRestore);
+}
+
+void CanvasState::restore() {
+    if (mSaveCount > 1) {
+        restoreSnapshot();
+    }
+}
+
+void CanvasState::restoreToCount(int saveCount) {
+    if (saveCount < 1) saveCount = 1;
+
+    while (mSaveCount > saveCount) {
+        restoreSnapshot();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Matrix
+///////////////////////////////////////////////////////////////////////////////
+
+void CanvasState::getMatrix(SkMatrix* matrix) const {
+    mSnapshot->transform->copyTo(*matrix);
+}
+
+void CanvasState::translate(float dx, float dy, float dz) {
+    mSnapshot->transform->translate(dx, dy, dz);
+}
+
+void CanvasState::rotate(float degrees) {
+    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
+}
+
+void CanvasState::scale(float sx, float sy) {
+    mSnapshot->transform->scale(sx, sy, 1.0f);
+}
+
+void CanvasState::skew(float sx, float sy) {
+    mSnapshot->transform->skew(sx, sy);
+}
+
+void CanvasState::setMatrix(const SkMatrix& matrix) {
+    mSnapshot->transform->load(matrix);
+}
+
+void CanvasState::setMatrix(const Matrix4& matrix) {
+    mSnapshot->transform->load(matrix);
+}
+
+void CanvasState::concatMatrix(const SkMatrix& matrix) {
+    mat4 transform(matrix);
+    mSnapshot->transform->multiply(transform);
+}
+
+void CanvasState::concatMatrix(const Matrix4& matrix) {
+    mSnapshot->transform->multiply(matrix);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clip
+///////////////////////////////////////////////////////////////////////////////
+
+bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+    mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
+    return !mSnapshot->clipIsEmpty();
+}
+
+bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
+    mDirtyClip |= mSnapshot->clipPath(*path, op);
+    return !mSnapshot->clipIsEmpty();
+}
+
+bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
+    mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
+    return !mSnapshot->clipIsEmpty();
+}
+
+void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+    Rect bounds;
+    float radius;
+    if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+
+    bool outlineIsRounded = MathUtils::isPositive(radius);
+    if (!outlineIsRounded || currentTransform()->isSimple()) {
+        // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
+        clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
+    }
+    if (outlineIsRounded) {
+        setClippingRoundRect(allocator, bounds, radius, false);
+    }
+}
+
+void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
+        const Rect& rect, float radius, bool highPriority) {
+    mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Quick Rejection
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
+ * the clipRect. Does not modify the scissor.
+ *
+ * @param clipRequired if not null, will be set to true if element intersects clip
+ *         (and wasn't rejected)
+ *
+ * @param snapOut if set, the geometry will be treated as having an AA ramp.
+ *         See Rect::snapGeometryToPixelBoundaries()
+ */
+bool CanvasState::calculateQuickRejectForScissor(float left, float top,
+        float right, float bottom,
+        bool* clipRequired, bool* roundRectClipRequired,
+        bool snapOut) const {
+    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+        return true;
+    }
+
+    Rect r(left, top, right, bottom);
+    currentTransform()->mapRect(r);
+    r.snapGeometryToPixelBoundaries(snapOut);
+
+    Rect clipRect(currentClipRect());
+    clipRect.snapToPixelBoundaries();
+
+    if (!clipRect.intersects(r)) return true;
+
+    // clip is required if geometry intersects clip rect
+    if (clipRequired) {
+        *clipRequired = !clipRect.contains(r);
+    }
+
+    // round rect clip is required if RR clip exists, and geometry intersects its corners
+    if (roundRectClipRequired) {
+        *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
+                && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
+    }
+    return false;
+}
+
+bool CanvasState::quickRejectConservative(float left, float top,
+        float right, float bottom) const {
+    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+        return true;
+    }
+
+    Rect r(left, top, right, bottom);
+    currentTransform()->mapRect(r);
+    r.roundOut(); // rounded out to be conservative
+
+    Rect clipRect(currentClipRect());
+    clipRect.snapToPixelBoundaries();
+
+    if (!clipRect.intersects(r)) return true;
+
+    return false;
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
new file mode 100644
index 0000000..4db5ed2
--- /dev/null
+++ b/libs/hwui/CanvasState.h
@@ -0,0 +1,192 @@
+/*
+ * 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_HWUI_CANVAS_STATE_H
+#define ANDROID_HWUI_CANVAS_STATE_H
+
+#include <SkMatrix.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+
+#include "Snapshot.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Abstract base class for any class containing CanvasState.
+ * Defines three mandatory callbacks.
+ */
+class CanvasStateClient {
+public:
+    CanvasStateClient() { }
+    virtual ~CanvasStateClient() { }
+
+    /**
+     * Callback allowing embedder to take actions in the middle of a
+     * setViewport() call.
+     */
+    virtual void onViewportInitialized() = 0;
+
+    /**
+     * Callback allowing embedder to take actions in the middle of a
+     * restore() call.  May be called several times sequentially.
+     */
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
+
+    /**
+     * Allows subclasses to control what value is stored in snapshot's
+     * fbo field in * initializeSaveStack.
+     */
+    virtual GLuint getTargetFbo() const = 0;
+
+}; // class CanvasStateClient
+
+/**
+ * Implements Canvas state methods on behalf of Renderers.
+ *
+ * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
+ * Renderer interface. Drawing and recording classes that include a CanvasState will have
+ * different use cases:
+ *
+ * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
+ * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
+ *
+ * Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
+ * to CanvasState, so that not only will querying operations work (getClip/Matrix), but so
+ * that quickRejection can also be used.
+ */
+
+class ANDROID_API CanvasState {
+public:
+    CanvasState(CanvasStateClient& renderer);
+    ~CanvasState();
+
+    /**
+     * Initializes the first snapshot, computing the projection matrix,
+     * and stores the dimensions of the render target.
+     */
+    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
+            const Vector3& lightCenter);
+
+    void setViewport(int width, int height);
+
+    bool hasRectToRectTransform() const {
+        return CC_LIKELY(currentTransform()->rectToRect());
+    }
+
+    // Save (layer)
+    int getSaveCount() const { return mSaveCount; }
+    int save(int flags);
+    void restore();
+    void restoreToCount(int saveCount);
+
+    // Save/Restore without side-effects
+    int saveSnapshot(int flags);
+    void restoreSnapshot();
+
+    // Matrix
+    void getMatrix(SkMatrix* outMatrix) const;
+    void translate(float dx, float dy, float dz = 0.0f);
+    void rotate(float degrees);
+    void scale(float sx, float sy);
+    void skew(float sx, float sy);
+
+    void setMatrix(const SkMatrix& matrix);
+    void setMatrix(const Matrix4& matrix); // internal only convenience method
+    void concatMatrix(const SkMatrix& matrix);
+    void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+    // Clip
+    const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
+    const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
+
+    bool quickRejectConservative(float left, float top, float right, float bottom) const;
+
+    bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    bool clipPath(const SkPath* path, SkRegion::Op op);
+    bool clipRegion(const SkRegion* region, SkRegion::Op op);
+
+    /**
+     * Sets a "clipping outline", which is independent from the regular clip.
+     * Currently only supports rectangles or rounded rectangles; passing in a
+     * more complicated outline fails silently. Replaces any previous clipping
+     * outline.
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator,
+            const Rect& rect, float radius, bool highPriority = true);
+
+    /**
+     * Returns true if drawing in the rectangle (left, top, right, bottom)
+     * will be clipped out. Is conservative: might return false when subpixel-
+     * perfect tests would return true.
+     */
+    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
+            bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
+
+    void setDirtyClip(bool opaque) { mDirtyClip = opaque; }
+    bool getDirtyClip() const { return mDirtyClip; }
+
+    void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
+    void setEmpty(bool value) { mSnapshot->empty = value; }
+    void setInvisible(bool value) { mSnapshot->invisible = value; }
+
+    inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
+    inline const Rect& currentClipRect() const { return currentSnapshot()->getClipRect(); }
+    inline Region* currentRegion() const { return currentSnapshot()->region; }
+    inline int currentFlags() const { return currentSnapshot()->flags; }
+    const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+    inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); }
+    int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
+    int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
+    int getWidth() { return mWidth; }
+    int getHeight() { return mHeight; }
+
+    inline const Snapshot* currentSnapshot() const {
+        return mSnapshot != nullptr ? mSnapshot.get() : mFirstSnapshot.get();
+    }
+    inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
+    inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
+
+private:
+    /// No default constructor - must supply a CanvasStateClient (mCanvas).
+    CanvasState();
+
+    /// indicates that the clip has been changed since the last time it was consumed
+    bool mDirtyClip;
+
+    /// Dimensions of the drawing surface
+    int mWidth, mHeight;
+
+    /// Number of saved states
+    int mSaveCount;
+
+    /// Base state
+    sp<Snapshot> mFirstSnapshot;
+
+    /// Host providing callbacks
+    CanvasStateClient& mCanvas;
+
+    /// Current state
+    sp<Snapshot> mSnapshot;
+
+}; // class CanvasState
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_CANVAS_STATE_H
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
new file mode 100644
index 0000000..852204a
--- /dev/null
+++ b/libs/hwui/ClipArea.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ClipArea.h"
+
+#include <SkPath.h>
+#include <limits>
+
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+static bool intersect(Rect& r, const Rect& r2) {
+    bool hasIntersection = r.intersect(r2);
+    if (!hasIntersection) {
+        r.setEmpty();
+    }
+    return hasIntersection;
+}
+
+static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
+    Vertex v;
+    v.x = x;
+    v.y = y;
+    transform.mapPoint(v.x, v.y);
+    transformedBounds.expandToCoverVertex(v.x, v.y);
+}
+
+Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
+    const float kMinFloat = std::numeric_limits<float>::lowest();
+    const float kMaxFloat = std::numeric_limits<float>::max();
+    Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
+    handlePoint(transformedBounds, transform, r.left, r.top);
+    handlePoint(transformedBounds, transform, r.right, r.top);
+    handlePoint(transformedBounds, transform, r.left, r.bottom);
+    handlePoint(transformedBounds, transform, r.right, r.bottom);
+    return transformedBounds;
+}
+
+/*
+ * TransformedRectangle
+ */
+
+TransformedRectangle::TransformedRectangle() {
+}
+
+TransformedRectangle::TransformedRectangle(const Rect& bounds,
+        const Matrix4& transform)
+        : mBounds(bounds)
+        , mTransform(transform) {
+}
+
+bool TransformedRectangle::canSimplyIntersectWith(
+        const TransformedRectangle& other) const {
+
+    return mTransform == other.mTransform;
+}
+
+bool TransformedRectangle::intersectWith(const TransformedRectangle& other) {
+    Rect translatedBounds(other.mBounds);
+    return intersect(mBounds, translatedBounds);
+}
+
+bool TransformedRectangle::isEmpty() const {
+    return mBounds.isEmpty();
+}
+
+/*
+ * RectangleList
+ */
+
+RectangleList::RectangleList()
+        : mTransformedRectanglesCount(0) {
+}
+
+bool RectangleList::isEmpty() const {
+    if (mTransformedRectanglesCount < 1) {
+        return true;
+    }
+
+    for (int i = 0; i < mTransformedRectanglesCount; i++) {
+        if (mTransformedRectangles[i].isEmpty()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+int RectangleList::getTransformedRectanglesCount() const {
+    return mTransformedRectanglesCount;
+}
+
+const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
+    return mTransformedRectangles[i];
+}
+
+void RectangleList::setEmpty() {
+    mTransformedRectanglesCount = 0;
+}
+
+void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
+    mTransformedRectanglesCount = 1;
+    mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
+}
+
+bool RectangleList::intersectWith(const Rect& bounds,
+        const Matrix4& transform) {
+    TransformedRectangle newRectangle(bounds, transform);
+
+    // Try to find a rectangle with a compatible transformation
+    int index = 0;
+    for (; index < mTransformedRectanglesCount; index++) {
+        TransformedRectangle& tr(mTransformedRectangles[index]);
+        if (tr.canSimplyIntersectWith(newRectangle)) {
+            tr.intersectWith(newRectangle);
+            return true;
+        }
+    }
+
+    // Add it to the list if there is room
+    if (index < kMaxTransformedRectangles) {
+        mTransformedRectangles[index] = newRectangle;
+        mTransformedRectanglesCount += 1;
+        return true;
+    }
+
+    // This rectangle list is full
+    return false;
+}
+
+Rect RectangleList::calculateBounds() const {
+    Rect bounds;
+    for (int index = 0; index < mTransformedRectanglesCount; index++) {
+        const TransformedRectangle& tr(mTransformedRectangles[index]);
+        if (index == 0) {
+            bounds = tr.transformedBounds();
+        } else {
+            bounds.intersect(tr.transformedBounds());
+        }
+    }
+    return bounds;
+}
+
+static SkPath pathFromTransformedRectangle(const Rect& bounds,
+        const Matrix4& transform) {
+    SkPath rectPath;
+    SkPath rectPathTransformed;
+    rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    SkMatrix skTransform;
+    transform.copyTo(skTransform);
+    rectPath.transform(skTransform, &rectPathTransformed);
+    return rectPathTransformed;
+}
+
+SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
+    SkRegion rectangleListAsRegion;
+    for (int index = 0; index < mTransformedRectanglesCount; index++) {
+        const TransformedRectangle& tr(mTransformedRectangles[index]);
+        SkPath rectPathTransformed = pathFromTransformedRectangle(
+                tr.getBounds(), tr.getTransform());
+        if (index == 0) {
+            rectangleListAsRegion.setPath(rectPathTransformed, clip);
+        } else {
+            SkRegion rectRegion;
+            rectRegion.setPath(rectPathTransformed, clip);
+            rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
+        }
+    }
+    return rectangleListAsRegion;
+}
+
+/*
+ * ClipArea
+ */
+
+ClipArea::ClipArea()
+        : mMode(kModeRectangle) {
+}
+
+/*
+ * Interface
+ */
+
+void ClipArea::setViewportDimensions(int width, int height) {
+    mViewportBounds.set(0, 0, width, height);
+    mClipRect = mViewportBounds;
+}
+
+void ClipArea::setEmpty() {
+    mMode = kModeRectangle;
+    mClipRect.setEmpty();
+    mClipRegion.setEmpty();
+    mRectangleList.setEmpty();
+}
+
+void ClipArea::setClip(float left, float top, float right, float bottom) {
+    mMode = kModeRectangle;
+    mClipRect.set(left, top, right, bottom);
+    mClipRegion.setEmpty();
+}
+
+bool ClipArea::clipRectWithTransform(float left, float top, float right,
+        float bottom, const mat4* transform, SkRegion::Op op) {
+    Rect r(left, top, right, bottom);
+    return clipRectWithTransform(r, transform, op);
+}
+
+bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
+        SkRegion::Op op) {
+    switch (mMode) {
+    case kModeRectangle:
+        return rectangleModeClipRectWithTransform(r, transform, op);
+    case kModeRectangleList:
+        return rectangleListModeClipRectWithTransform(r, transform, op);
+    case kModeRegion:
+        return regionModeClipRectWithTransform(r, transform, op);
+    }
+    return false;
+}
+
+bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+    enterRegionMode();
+    mClipRegion.op(region, op);
+    setClipRectToRegionBounds();
+    return true;
+}
+
+bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
+        SkRegion::Op op) {
+    SkMatrix skTransform;
+    transform->copyTo(skTransform);
+    SkPath transformed;
+    path.transform(skTransform, &transformed);
+    SkRegion region;
+    regionFromPath(transformed, region);
+    return clipRegion(region, op);
+}
+
+/*
+ * Rectangle mode
+ */
+
+void ClipArea::enterRectangleMode() {
+    // Entering rectangle mode discards any
+    // existing clipping information from the other modes.
+    // The only way this occurs is by a clip setting operation.
+    mMode = kModeRectangle;
+}
+
+bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
+        const mat4* transform, SkRegion::Op op) {
+
+    if (op != SkRegion::kIntersect_Op) {
+        enterRegionMode();
+        return regionModeClipRectWithTransform(r, transform, op);
+    }
+
+    if (transform->rectToRect()) {
+        Rect transformed(r);
+        transform->mapRect(transformed);
+        bool hasIntersection = mClipRect.intersect(transformed);
+        if (!hasIntersection) {
+            mClipRect.setEmpty();
+        }
+        return true;
+    }
+
+    enterRectangleListMode();
+    return rectangleListModeClipRectWithTransform(r, transform, op);
+}
+
+bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
+        float right, float bottom, const mat4* transform, SkRegion::Op op) {
+    Rect r(left, top, right, bottom);
+    bool result = rectangleModeClipRectWithTransform(r, transform, op);
+    mClipRect = mRectangleList.calculateBounds();
+    return result;
+}
+
+/*
+ * RectangleList mode implementation
+ */
+
+void ClipArea::enterRectangleListMode() {
+    // Is is only legal to enter rectangle list mode from
+    // rectangle mode, since rectangle list mode cannot represent
+    // all clip areas that can be represented by a region.
+    ALOG_ASSERT(mMode == kModeRectangle);
+    mMode = kModeRectangleList;
+    mRectangleList.set(mClipRect, Matrix4::identity());
+}
+
+bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
+        const mat4* transform, SkRegion::Op op) {
+    if (op != SkRegion::kIntersect_Op
+            || !mRectangleList.intersectWith(r, *transform)) {
+        enterRegionMode();
+        return regionModeClipRectWithTransform(r, transform, op);
+    }
+    return true;
+}
+
+bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
+        float right, float bottom, const mat4* transform, SkRegion::Op op) {
+    Rect r(left, top, right, bottom);
+    return rectangleListModeClipRectWithTransform(r, transform, op);
+}
+
+/*
+ * Region mode implementation
+ */
+
+void ClipArea::enterRegionMode() {
+    if (mMode != kModeRegion) {
+        if (mMode == kModeRectangle) {
+            mClipRegion.setRect(mClipRect.left, mClipRect.top,
+                    mClipRect.right, mClipRect.bottom);
+        } else {
+            mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
+            setClipRectToRegionBounds();
+        }
+        mMode = kModeRegion;
+    }
+}
+
+bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
+        const mat4* transform, SkRegion::Op op) {
+    SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
+    SkRegion transformedRectRegion;
+    regionFromPath(transformedRect, transformedRectRegion);
+    mClipRegion.op(transformedRectRegion, op);
+    setClipRectToRegionBounds();
+    return true;
+}
+
+bool ClipArea::regionModeClipRectWithTransform(float left, float top,
+        float right, float bottom, const mat4* transform, SkRegion::Op op) {
+    return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
+            transform, op);
+}
+
+void ClipArea::setClipRectToRegionBounds() {
+    if (!mClipRegion.isEmpty()) {
+        mClipRect.set(mClipRegion.getBounds());
+
+        if (mClipRegion.isRect()) {
+            mClipRegion.setEmpty();
+        }
+    } else {
+        mClipRect.setEmpty();
+    }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
new file mode 100644
index 0000000..16e6df9
--- /dev/null
+++ b/libs/hwui/ClipArea.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef CLIPAREA_H
+#define CLIPAREA_H
+
+#include <SkRegion.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/Pair.h"
+
+namespace android {
+namespace uirenderer {
+
+Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
+
+class TransformedRectangle {
+public:
+    TransformedRectangle();
+    TransformedRectangle(const Rect& bounds, const Matrix4& transform);
+
+    bool canSimplyIntersectWith(const TransformedRectangle& other) const;
+    bool intersectWith(const TransformedRectangle& other);
+
+    bool isEmpty() const;
+
+    const Rect& getBounds() const {
+        return mBounds;
+    }
+
+    Rect transformedBounds() const {
+        Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
+        return transformedBounds;
+    }
+
+    const Matrix4& getTransform() const {
+        return mTransform;
+    }
+
+private:
+    Rect mBounds;
+    Matrix4 mTransform;
+};
+
+class RectangleList {
+public:
+    RectangleList();
+
+    bool isEmpty() const;
+    int getTransformedRectanglesCount() const;
+    const TransformedRectangle& getTransformedRectangle(int i) const;
+
+    void setEmpty();
+    void set(const Rect& bounds, const Matrix4& transform);
+    bool intersectWith(const Rect& bounds, const Matrix4& transform);
+
+    SkRegion convertToRegion(const SkRegion& clip) const;
+    Rect calculateBounds() const;
+
+private:
+    enum {
+        kMaxTransformedRectangles = 5
+    };
+
+    int mTransformedRectanglesCount;
+    TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
+};
+
+class ClipArea {
+public:
+    ClipArea();
+
+    void setViewportDimensions(int width, int height);
+
+    bool isEmpty() const {
+        return mClipRect.isEmpty();
+    }
+
+    void setEmpty();
+    void setClip(float left, float top, float right, float bottom);
+    bool clipRectWithTransform(float left, float top, float right, float bottom,
+            const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
+    bool clipRectWithTransform(const Rect& r, const mat4* transform,
+            SkRegion::Op op = SkRegion::kIntersect_Op);
+    bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
+    bool clipPathWithTransform(const SkPath& path, const mat4* transform,
+            SkRegion::Op op);
+
+    const Rect& getClipRect() const {
+        return mClipRect;
+    }
+
+    const SkRegion& getClipRegion() const {
+        return mClipRegion;
+    }
+
+    const RectangleList& getRectangleList() const {
+        return mRectangleList;
+    }
+
+    bool isRegion() const {
+        return kModeRegion == mMode;
+    }
+
+    bool isSimple() const {
+        return mMode == kModeRectangle;
+    }
+
+    bool isRectangleList() const {
+        return mMode == kModeRectangleList;
+    }
+
+private:
+    void enterRectangleMode();
+    bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+    bool rectangleModeClipRectWithTransform(float left, float top, float right,
+            float bottom, const mat4* transform, SkRegion::Op op);
+
+    void enterRectangleListMode();
+    bool rectangleListModeClipRectWithTransform(float left, float top,
+            float right, float bottom, const mat4* transform, SkRegion::Op op);
+    bool rectangleListModeClipRectWithTransform(const Rect& r,
+            const mat4* transform, SkRegion::Op op);
+
+    void enterRegionModeFromRectangleMode();
+    void enterRegionModeFromRectangleListMode();
+    void enterRegionMode();
+    bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+            SkRegion::Op op);
+    bool regionModeClipRectWithTransform(float left, float top, float right,
+            float bottom, const mat4* transform, SkRegion::Op op);
+
+    void ensureClipRegion();
+    void setClipRectToRegionBounds();
+    bool clipRegionOp(float left, float top, float right, float bottom,
+            SkRegion::Op op);
+
+    SkRegion createViewportRegion() {
+        return SkRegion(mViewportBounds.toSkIRect());
+    }
+
+    void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
+        pathAsRegion.setPath(path, createViewportRegion());
+    }
+
+    enum Mode {
+        kModeRectangle,
+        kModeRegion,
+        kModeRectangleList
+    };
+
+    Mode mMode;
+    Rect mViewportBounds;
+    Rect mClipRect;
+    SkRegion mClipRegion;
+    RectangleList mRectangleList;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CLIPAREA_H_ */
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 420e331..9bd3bdc 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -79,7 +79,7 @@
 void DamageAccumulator::pushCommon() {
     if (!mHead->next) {
         DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
-        nextFrame->next = 0;
+        nextFrame->next = nullptr;
         nextFrame->prev = mHead;
         mHead->next = nextFrame;
     }
@@ -147,7 +147,7 @@
             return frame;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
@@ -160,7 +160,7 @@
             }
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
@@ -222,7 +222,7 @@
     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
     *totalDirty = mHead->pendingDirty;
-    totalDirty->roundOut();
+    totalDirty->roundOut(totalDirty);
     mHead->pendingDirty.setEmpty();
 }
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index a998594..c78971a 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -52,7 +52,7 @@
 
 class Batch {
 public:
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
     virtual ~Batch() {}
     virtual bool purelyDrawBatch() { return false; }
     virtual bool coversBounds(const Rect& bounds) { return false; }
@@ -91,12 +91,10 @@
         return false;
     }
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override {
         DEFER_LOGD("%d  replaying DrawBatch %p, with %d ops (batch id %x, merge id %p)",
                 index, this, mOps.size(), getBatchId(), getMergeId());
 
-        status_t status = DrawGlInfo::kStatusDone;
-        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
         for (unsigned int i = 0; i < mOps.size(); i++) {
             DrawOp* op = mOps[i].op;
             const DeferredDisplayState* state = mOps[i].state;
@@ -105,8 +103,7 @@
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
             renderer.eventMark(op->name());
 #endif
-            logBuffer.writeCommand(0, op->name());
-            status |= op->applyDraw(renderer, dirty);
+            op->applyDraw(renderer, dirty);
 
 #if DEBUG_MERGE_BEHAVIOR
             const Rect& bounds = state->mBounds;
@@ -118,12 +115,11 @@
                     batchColor);
 #endif
         }
-        return status;
     }
 
-    virtual bool purelyDrawBatch() { return true; }
+    virtual bool purelyDrawBatch() override { return true; }
 
-    virtual bool coversBounds(const Rect& bounds) {
+    virtual bool coversBounds(const Rect& bounds) override {
         if (CC_LIKELY(!mAllOpsOpaque || !mBounds.contains(bounds) || count() == 1)) return false;
 
         Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom));
@@ -235,30 +231,11 @@
             return false;
         }
 
-        /* Draw Modifiers compatibility check
-         *
-         * Shadows are ignored, as only text uses them, and in that case they are drawn
-         * per-DrawTextOp, before the unified text draw. Because of this, it's always safe to merge
-         * text UNLESS a later draw's shadow should overlays a previous draw's text. This is covered
-         * above with the intersection check.
-         *
-         * OverrideLayerAlpha is also ignored, as it's only used for drawing layers, which are never
-         * merged.
-         *
-         * These ignore cases prevent us from simply memcmp'ing the drawModifiers
-         */
-        const DrawModifiers& lhsMod = lhs->mDrawModifiers;
-        const DrawModifiers& rhsMod = rhs->mDrawModifiers;
-
-        // Draw filter testing expects bit fields to be clear if filter not set.
-        if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
-        if (lhsMod.mPaintFilterClearBits != rhsMod.mPaintFilterClearBits) return false;
-        if (lhsMod.mPaintFilterSetBits != rhsMod.mPaintFilterSetBits) return false;
-
         return true;
     }
 
-    virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
+    virtual void add(DrawOp* op, const DeferredDisplayState* state,
+            bool opaqueOverBounds) override {
         DrawBatch::add(op, state, opaqueOverBounds);
 
         const int newClipSideFlags = state->mClipSideFlags;
@@ -269,33 +246,29 @@
         if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom;
     }
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override {
         DEFER_LOGD("%d  replaying MergingDrawBatch %p, with %d ops,"
                 " clip flags %x (batch id %x, merge id %p)",
                 index, this, mOps.size(), mClipSideFlags, getBatchId(), getMergeId());
         if (mOps.size() == 1) {
-            return DrawBatch::replay(renderer, dirty, -1);
+            DrawBatch::replay(renderer, dirty, -1);
+            return;
         }
 
         // clipping in the merged case is done ahead of time since all ops share the clip (if any)
-        renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : NULL);
+        renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : nullptr);
 
         DrawOp* op = mOps[0].op;
-        DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
-        buffer.writeCommand(0, "multiDraw");
-        buffer.writeCommand(1, op->name());
-
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
         renderer.eventMark("multiDraw");
         renderer.eventMark(op->name());
 #endif
-        status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
+        op->multiDraw(renderer, dirty, mOps, mBounds);
 
 #if DEBUG_MERGE_BEHAVIOR
         renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
                 DEBUG_COLOR_MERGEDBATCH);
 #endif
-        return status;
     }
 
 private:
@@ -313,7 +286,7 @@
     // creates a single operation batch
     StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {}
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override {
         DEFER_LOGD("replaying state op batch %p", this);
         renderer.restoreDisplayState(*mState);
 
@@ -322,7 +295,6 @@
         // renderer.restoreToCount directly
         int saveCount = -1;
         mOp->applyState(renderer, saveCount);
-        return DrawGlInfo::kStatusDone;
     }
 
 private:
@@ -333,19 +305,17 @@
 class RestoreToCountBatch : public Batch {
 public:
     RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) :
-            mOp(op), mState(state), mRestoreCount(restoreCount) {}
+            mState(state), mRestoreCount(restoreCount) {}
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override {
         DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
 
         renderer.restoreDisplayState(*mState);
         renderer.restoreToCount(mRestoreCount);
-        return DrawGlInfo::kStatusDone;
     }
 
 private:
     // we use the state storage for the RestoreToCountOp, but don't replay the op itself
-    const StateOp* mOp;
     const DeferredDisplayState* mState;
 
     /*
@@ -359,9 +329,8 @@
 
 #if DEBUG_MERGE_BEHAVIOR
 class BarrierDebugBatch : public Batch {
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+    virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
         renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER);
-        return DrawGlInfo::kStatusDrew;
     }
 };
 #endif
@@ -372,7 +341,7 @@
 
 void DeferredDisplayList::resetBatchingState() {
     for (int i = 0; i < kOpBatch_Count; i++) {
-        mBatchLookup[i] = NULL;
+        mBatchLookup[i] = nullptr;
         mMergingBatches[i].clear();
     }
 #if DEBUG_MERGE_BEHAVIOR
@@ -542,7 +511,7 @@
     }
 
     // find the latest batch of the new op's type, and try to merge the new op into it
-    DrawBatch* targetBatch = NULL;
+    DrawBatch* targetBatch = nullptr;
 
     // insertion point of a new batch, will hopefully be immediately after similar batch
     // (eventually, should be similar shader)
@@ -565,7 +534,7 @@
             // Try to merge with any existing batch with same mergeId.
             if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
                 if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
-                    targetBatch = NULL;
+                    targetBatch = nullptr;
                 }
             }
         } else {
@@ -591,7 +560,7 @@
                     // NOTE: it may be possible to optimize for special cases where two operations
                     // of the same batch/paint could swap order, such as with a non-mergeable
                     // (clipped) and a mergeable text operation
-                    targetBatch = NULL;
+                    targetBatch = nullptr;
 #if DEBUG_DEFER
                     DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d",
                             targetBatch, i);
@@ -648,26 +617,22 @@
 // Replay / flush
 /////////////////////////////////////////////////////////////////////////////////
 
-static status_t replayBatchList(const Vector<Batch*>& batchList,
+static void replayBatchList(const Vector<Batch*>& batchList,
         OpenGLRenderer& renderer, Rect& dirty) {
-    status_t status = DrawGlInfo::kStatusDone;
 
     for (unsigned int i = 0; i < batchList.size(); i++) {
         if (batchList[i]) {
-            status |= batchList[i]->replay(renderer, dirty, i);
+            batchList[i]->replay(renderer, dirty, i);
         }
     }
     DEFER_LOGD("--flushed, drew %d batches", batchList.size());
-    return status;
 }
 
-status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
+void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
     ATRACE_NAME("flush drawing commands");
     Caches::getInstance().fontRenderer->endPrecaching();
 
-    status_t status = DrawGlInfo::kStatusDone;
-
-    if (isEmpty()) return status; // nothing to flush
+    if (isEmpty()) return; // nothing to flush
     renderer.restoreToCount(1);
 
     DEFER_LOGD("--flushing");
@@ -686,23 +651,21 @@
     }
     // NOTE: depth of the save stack at this point, before playback, should be reflected in
     // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly
-    status |= replayBatchList(mBatches, renderer, dirty);
+    replayBatchList(mBatches, renderer, dirty);
 
     renderer.restoreToCount(1);
     renderer.setDrawModifiers(restoreDrawModifiers);
 
     DEFER_LOGD("--flush complete, returning %x", status);
     clear();
-    return status;
 }
 
 void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) {
     for (unsigned int i = mEarliestUnclearedIndex; i <= maxIndex; i++) {
         // leave deferred state ops alone for simplicity (empty save restore pairs may now exist)
         if (mBatches[i] && mBatches[i]->purelyDrawBatch()) {
-            DrawBatch* b = (DrawBatch*) mBatches[i];
             delete mBatches[i];
-            mBatches.replaceAt(NULL, i);
+            mBatches.replaceAt(nullptr, i);
         }
     }
     mEarliestUnclearedIndex = maxIndex + 1;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 8a015b21..c92ab91 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -69,7 +69,7 @@
 class OpStatePair {
 public:
     OpStatePair()
-            : op(NULL), state(NULL) {}
+            : op(nullptr), state(nullptr) {}
     OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState)
             : op(newOp), state(newState) {}
     OpStatePair(const OpStatePair& other)
@@ -79,7 +79,7 @@
 };
 
 class DeferredDisplayList {
-    friend class DeferStateStruct; // used to give access to allocator
+    friend struct DeferStateStruct; // used to give access to allocator
 public:
     DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
             mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
@@ -106,7 +106,7 @@
      * Plays back all of the draw ops recorded into batches to the renderer.
      * Adjusts the state of the renderer as necessary, and restores it when complete
      */
-    status_t flush(OpenGLRenderer& renderer, Rect& dirty);
+    void flush(OpenGLRenderer& renderer, Rect& dirty);
 
     void addClip(OpenGLRenderer& renderer, ClipOp* op);
     void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount);
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d02455c..6b8c780 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -25,8 +25,8 @@
 namespace uirenderer {
 
 DeferredLayerUpdater::DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer)
-        : mSurfaceTexture(0)
-        , mTransform(0)
+        : mSurfaceTexture(nullptr)
+        , mTransform(nullptr)
         , mNeedsGLContextAttach(false)
         , mUpdateTexImage(false)
         , mLayer(layer)
@@ -42,14 +42,14 @@
 
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
-    setTransform(0);
+    setTransform(nullptr);
     mLayer->postDecStrong();
-    mLayer = 0;
+    mLayer = nullptr;
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
     OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
-    SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : NULL;
+    SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
 
@@ -62,7 +62,7 @@
     if (mSurfaceTexture.get()) {
         if (mNeedsGLContextAttach) {
             mNeedsGLContextAttach = false;
-            mSurfaceTexture->attachToContext(mLayer->getTexture());
+            mSurfaceTexture->attachToContext(mLayer->getTextureId());
         }
         if (mUpdateTexImage) {
             mUpdateTexImage = false;
@@ -70,7 +70,7 @@
         }
         if (mTransform) {
             mLayer->getTransform().load(*mTransform);
-            setTransform(0);
+            setTransform(nullptr);
         }
     }
     return success;
@@ -95,10 +95,10 @@
 
         bool forceFilter = false;
         sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
-        if (buffer != NULL) {
+        if (buffer != nullptr) {
             // force filtration if buffer size != layer size
-            forceFilter = mWidth != buffer->getWidth()
-                    || mHeight != buffer->getHeight();
+            forceFilter = mWidth != static_cast<int>(buffer->getWidth())
+                    || mHeight != static_cast<int>(buffer->getHeight());
         }
 
         #if DEBUG_RENDERER
@@ -109,6 +109,9 @@
         mSurfaceTexture->getTransformMatrix(transform);
         GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
 
+        LOG_ALWAYS_FATAL_IF(renderTarget != GL_TEXTURE_2D && renderTarget != GL_TEXTURE_EXTERNAL_OES,
+                "doUpdateTexImage target %x, 2d %x, EXT %x",
+                renderTarget, GL_TEXTURE_2D, GL_TEXTURE_EXTERNAL_OES);
         LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight,
                 !mBlend, forceFilter, renderTarget, transform);
     }
@@ -122,7 +125,7 @@
             // TODO: Elevate to fatal exception
             ALOGE("Failed to detach SurfaceTexture from context %d", err);
         }
-        mSurfaceTexture = 0;
+        mSurfaceTexture = nullptr;
         mLayer->clearTexture();
     }
 }
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 84411ed..82f2741 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -24,7 +24,6 @@
 
 #include "Layer.h"
 #include "Rect.h"
-#include "RenderNode.h"
 #include "renderthread/RenderThread.h"
 
 namespace android {
@@ -39,7 +38,7 @@
     ANDROID_API DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer);
     ANDROID_API ~DeferredLayerUpdater();
 
-    ANDROID_API bool setSize(uint32_t width, uint32_t height) {
+    ANDROID_API bool setSize(int width, int height) {
         if (mWidth != width || mHeight != height) {
             mWidth = width;
             mHeight = height;
@@ -60,6 +59,10 @@
         if (texture.get() != mSurfaceTexture.get()) {
             mNeedsGLContextAttach = needsAttach;
             mSurfaceTexture = texture;
+
+            GLenum target = texture->getCurrentTextureTarget();
+            LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
+                    "set unsupported GLConsumer with target %x", target);
         }
     }
 
@@ -69,7 +72,7 @@
 
     ANDROID_API void setTransform(const SkMatrix* matrix) {
         delete mTransform;
-        mTransform = matrix ? new SkMatrix(*matrix) : 0;
+        mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
     }
 
     ANDROID_API void setPaint(const SkPaint* paint);
@@ -84,8 +87,8 @@
 
 private:
     // Generic properties
-    uint32_t mWidth;
-    uint32_t mHeight;
+    int mWidth;
+    int mHeight;
     bool mBlend;
     SkColorFilter* mColorFilter;
     int mAlpha;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 8953166..4540bec 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -24,7 +24,6 @@
 #include "Debug.h"
 #include "DisplayList.h"
 #include "DisplayListOp.h"
-#include "DisplayListLogBuffer.h"
 
 namespace android {
 namespace uirenderer {
@@ -46,41 +45,25 @@
         resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i));
     }
 
-    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
-        const SkBitmap* bitmap = ownedBitmapResources.itemAt(i);
-        resourceCache.decrementRefcountLocked(bitmap);
-        resourceCache.destructorLocked(bitmap);
-    }
-
     for (size_t i = 0; i < patchResources.size(); i++) {
         resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
     }
 
-    for (size_t i = 0; i < sourcePaths.size(); i++) {
-        resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
-    }
-
     resourceCache.unlock();
 
-    for (size_t i = 0; i < paints.size(); i++) {
-        delete paints.itemAt(i);
-    }
-
-    for (size_t i = 0; i < regions.size(); i++) {
-        delete regions.itemAt(i);
-    }
-
-    for (size_t i = 0; i < paths.size(); i++) {
-        delete paths.itemAt(i);
+    for (size_t i = 0; i < pathResources.size(); i++) {
+        const SkPath* path = pathResources.itemAt(i);
+        if (path->unique() && Caches::hasInstance()) {
+            Caches::getInstance().pathCache.removeDeferred(path);
+        }
+        delete path;
     }
 
     bitmapResources.clear();
-    ownedBitmapResources.clear();
     patchResources.clear();
-    sourcePaths.clear();
+    pathResources.clear();
     paints.clear();
     regions.clear();
-    paths.clear();
 }
 
 size_t DisplayListData::addChild(DrawRenderNodeOp* op) {
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 7a43a2a..3178584 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -38,8 +38,9 @@
 #include <androidfw/ResourceTypes.h>
 
 #include "Debug.h"
-#include "Matrix.h"
+#include "CanvasProperty.h"
 #include "DeferredDisplayList.h"
+#include "Matrix.h"
 #include "RenderProperties.h"
 
 class SkBitmap;
@@ -66,7 +67,7 @@
 /**
  * Holds data used in the playback a tree of DisplayLists.
  */
-class PlaybackStateStruct {
+struct PlaybackStateStruct {
 protected:
     PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
             : mRenderer(renderer)
@@ -87,8 +88,7 @@
     }
 };
 
-class DeferStateStruct : public PlaybackStateStruct {
-public:
+struct DeferStateStruct : public PlaybackStateStruct {
     DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
             : PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)),
             mDeferredList(deferredList) {}
@@ -96,14 +96,12 @@
     DeferredDisplayList& mDeferredList;
 };
 
-class ReplayStateStruct : public PlaybackStateStruct {
-public:
+struct ReplayStateStruct : public PlaybackStateStruct {
     ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
             : PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator),
-            mDirty(dirty), mDrawGlStatus(DrawGlInfo::kStatusDone) {}
+            mDirty(dirty) {}
 
     Rect& mDirty;
-    status_t mDrawGlStatus;
     LinearAllocator mReplayAllocator;
 };
 
@@ -136,13 +134,11 @@
     int projectionReceiveIndex;
 
     Vector<const SkBitmap*> bitmapResources;
-    Vector<const SkBitmap*> ownedBitmapResources;
+    Vector<const SkPath*> pathResources;
     Vector<const Res_png_9patch*> patchResources;
 
-    Vector<const SkPaint*> paints;
-    Vector<const SkPath*> paths;
-    SortedVector<const SkPath*> sourcePaths;
-    Vector<const SkRegion*> regions;
+    std::vector<std::unique_ptr<const SkPaint>> paints;
+    std::vector<std::unique_ptr<const SkRegion>> regions;
     Vector<Functor*> functors;
 
     const Vector<Chunk>& getChunks() const {
diff --git a/libs/hwui/DisplayListLogBuffer.cpp b/libs/hwui/DisplayListLogBuffer.cpp
deleted file mode 100644
index 45aacca..0000000
--- a/libs/hwui/DisplayListLogBuffer.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "DisplayListLogBuffer.h"
-
-// BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
-// that mStart always points at the next command, not just the next item
-#define NUM_COMMANDS 50
-#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
-
-/**
- * DisplayListLogBuffer is a utility class which logs the most recent display
- * list operations in a circular buffer. The log is process-wide, because we
- * only care about the most recent operations, not the operations on a per-window
- * basis for a given activity. The purpose of the log is to provide more debugging
- * information in a bug report, by telling us not just where a process hung (which
- * generally is just reported as a stack trace at the Java level) or crashed, but
- * also what happened immediately before that hang or crash. This may help track down
- * problems in the native rendering code or driver interaction related to the display
- * list operations that led up to the hang or crash.
- *
- * The log is implemented as a circular buffer for both space and performance
- * reasons - we only care about the last several operations to give us context
- * leading up to the problem, and we don't want to constantly copy data around or do
- * additional mallocs to keep the most recent operations logged. Only numbers are
- * logged to make the operation fast. If and when the log is output, we process this
- * data into meaningful strings.
- *
- * There is an assumption about the format of the command (currently 2 ints: the
- * opcode and the nesting level). If the type of information logged changes (for example,
- * we may want to save a timestamp), then the size of the buffer and the way the
- * information is recorded in writeCommand() should change to suit.
- */
-
-namespace android {
-
-#ifdef USE_OPENGL_RENDERER
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(DisplayListLogBuffer);
-#endif
-
-namespace uirenderer {
-
-
-DisplayListLogBuffer::DisplayListLogBuffer() {
-    mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
-    mStart = mBufferFirst;
-    mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
-    mEnd = mStart;
-}
-
-DisplayListLogBuffer::~DisplayListLogBuffer() {
-    free(mBufferFirst);
-}
-
-/**
- * Called from DisplayListRenderer to output the current buffer into the
- * specified FILE. This only happens in a dumpsys/bugreport operation.
- */
-void DisplayListLogBuffer::outputCommands(FILE *file)
-{
-    OpLog* tmpBufferPtr = mStart;
-    while (true) {
-        if (tmpBufferPtr == mEnd) {
-            break;
-        }
-
-        fprintf(file, "%*s%s\n", 2 * tmpBufferPtr->level, "", tmpBufferPtr->label);
-
-        OpLog* nextOp = tmpBufferPtr++;
-        if (tmpBufferPtr > mBufferLast) {
-            tmpBufferPtr = mBufferFirst;
-        }
-    }
-}
-
-/**
- * Store the given level and label in the buffer and increment/wrap the mEnd
- * and mStart values as appropriate. Label should point to static memory.
- */
-void DisplayListLogBuffer::writeCommand(int level, const char* label) {
-    mEnd->level = level;
-    mEnd->label = label;
-
-    if (mEnd == mBufferLast) {
-        mEnd = mBufferFirst;
-    } else {
-        mEnd++;
-    }
-    if (mEnd == mStart) {
-        mStart++;
-        if (mStart > mBufferLast) {
-            mStart = mBufferFirst;
-        }
-    }
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
deleted file mode 100644
index c884789..0000000
--- a/libs/hwui/DisplayListLogBuffer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
-#define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
-
-#include <utils/Singleton.h>
-
-#include <stdio.h>
-
-namespace android {
-namespace uirenderer {
-
-class DisplayListLogBuffer: public Singleton<DisplayListLogBuffer> {
-    DisplayListLogBuffer();
-    ~DisplayListLogBuffer();
-
-    friend class Singleton<DisplayListLogBuffer>;
-
-public:
-    void writeCommand(int level, const char* label);
-    void outputCommands(FILE *file);
-
-    bool isEmpty() {
-        return (mStart == mEnd);
-    }
-
-    struct OpLog {
-        int level;
-        const char* label;
-    };
-
-private:
-    OpLog* mBufferFirst; // where the memory starts
-    OpLog* mStart;       // where the current command stream starts
-    OpLog* mEnd;         // where the current commands end
-    OpLog* mBufferLast;  // where the buffer memory ends
-
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8a5e21d..1963475 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -17,9 +17,17 @@
 #ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
 #define ANDROID_HWUI_DISPLAY_OPERATION_H
 
-#ifndef LOG_TAG
-    #define LOG_TAG "OpenGLRenderer"
-#endif
+#include "OpenGLRenderer.h"
+#include "AssetAtlas.h"
+#include "DeferredDisplayList.h"
+#include "DisplayListRenderer.h"
+#include "GammaFontRenderer.h"
+#include "Patch.h"
+#include "RenderNode.h"
+#include "renderstate/RenderState.h"
+#include "UvMapper.h"
+#include "utils/LinearAllocator.h"
+#include "utils/PaintUtils.h"
 
 #include <SkColor.h>
 #include <SkPath.h>
@@ -28,19 +36,6 @@
 
 #include <private/hwui/DrawGlInfo.h>
 
-#include "OpenGLRenderer.h"
-#include "AssetAtlas.h"
-#include "DeferredDisplayList.h"
-#include "DisplayListRenderer.h"
-#include "RenderState.h"
-#include "UvMapper.h"
-#include "utils/LinearAllocator.h"
-
-#define CRASH() do { \
-    *(int *)(uintptr_t) 0xbbadbeef = 0; \
-    ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
-} while(false)
-
 // Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
 #define OP_LOGS(s) OP_LOG("%s", (s))
 #define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
@@ -63,9 +58,9 @@
 public:
     // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
     // standard new() intentionally not implemented, and delete/deconstructor should never be used.
-    virtual ~DisplayListOp() { CRASH(); }
-    static void operator delete(void* ptr) { CRASH(); }
-    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+    virtual ~DisplayListOp() { LOG_ALWAYS_FATAL("Destructor not supported"); }
+    static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
+    static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
     static void* operator new(size_t size, LinearAllocator& allocator) {
         return allocator.alloc(size);
     }
@@ -90,12 +85,8 @@
 
 class StateOp : public DisplayListOp {
 public:
-    StateOp() {};
-
-    virtual ~StateOp() {}
-
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         // default behavior only affects immediate, deferrable state, issue directly to renderer
         applyState(deferStruct.mRenderer, saveCount);
     }
@@ -105,7 +96,7 @@
      * list to flush
      */
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         applyState(replayStruct.mRenderer, saveCount);
     }
 
@@ -119,7 +110,7 @@
             : mPaint(paint), mQuickRejected(false) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         if (mQuickRejected && CC_LIKELY(useQuickReject)) {
             return;
         }
@@ -128,15 +119,15 @@
     }
 
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         if (mQuickRejected && CC_LIKELY(useQuickReject)) {
             return;
         }
 
-        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
+        applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
 
     /**
      * Draw multiple instances of an operation, must be overidden for operations that merge
@@ -145,14 +136,12 @@
      * and pure translation transformations. Other guarantees of similarity should be enforced by
      * reducing which operations are tagged as mergeable.
      */
-    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
             const Vector<OpStatePair>& ops, const Rect& bounds) {
-        status_t status = DrawGlInfo::kStatusDone;
         for (unsigned int i = 0; i < ops.size(); i++) {
             renderer.restoreDisplayState(*(ops[i].state), true);
-            status |= ops[i].op->applyDraw(renderer, dirty);
+            ops[i].op->applyDraw(renderer, dirty);
         }
-        return status;
     }
 
     /**
@@ -199,10 +188,6 @@
     }
 
 protected:
-    const SkPaint* getPaint(OpenGLRenderer& renderer) {
-        return renderer.filterPaint(mPaint);
-    }
-
     // Helper method for determining op opaqueness. Assumes op fills its bounds in local
     // coordinates, and that paint's alpha is used
     inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
@@ -219,7 +204,7 @@
             if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
                 return false;
             }
-            if (Renderer::isBlendedColorFilter(mPaint->getColorFilter())) {
+            if (PaintUtils::isBlendedColorFilter(mPaint->getColorFilter())) {
                 return false;
             }
         }
@@ -232,7 +217,7 @@
 
     }
 
-    const SkPaint* mPaint; // should be accessed via getPaint() when applying
+    const SkPaint* mPaint;
     bool mQuickRejected;
 };
 
@@ -260,7 +245,7 @@
     // default empty constructor for bounds, to be overridden in child constructor body
     DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { }
 
-    virtual bool getLocalBounds(Rect& localBounds) {
+    virtual bool getLocalBounds(Rect& localBounds) override {
         localBounds.set(mLocalBounds);
         OpenGLRenderer::TextShadow textShadow;
         if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
@@ -287,20 +272,20 @@
             : mFlags(flags) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         int newSaveCount = deferStruct.mRenderer.save(mFlags);
         deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
     }
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.save(mFlags);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Save flags %x", mFlags);
     }
 
-    virtual const char* name() { return "Save"; }
+    virtual const char* name() override { return "Save"; }
 
     int getFlags() const { return mFlags; }
 private:
@@ -313,21 +298,21 @@
             : mCount(count) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
                 this, saveCount + mCount);
         deferStruct.mRenderer.restoreToCount(saveCount + mCount);
     }
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.restoreToCount(saveCount + mCount);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Restore to count %d", mCount);
     }
 
-    virtual const char* name() { return "RestoreToCount"; }
+    virtual const char* name() override { return "RestoreToCount"; }
 
 private:
     int mCount;
@@ -339,7 +324,7 @@
             : mArea(left, top, right, bottom)
             , mPaint(&mCachedPaint)
             , mFlags(flags)
-            , mConvexMask(NULL) {
+            , mConvexMask(nullptr) {
         mCachedPaint.setAlpha(alpha);
     }
 
@@ -347,11 +332,11 @@
             : mArea(left, top, right, bottom)
             , mPaint(paint)
             , mFlags(flags)
-            , mConvexMask(NULL)
+            , mConvexMask(nullptr)
     {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
         int newSaveCount = deferStruct.mRenderer.getSaveCount();
         deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
@@ -362,17 +347,19 @@
                 mPaint, mFlags);
     }
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom,
                 mPaint, mFlags, mConvexMask);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("SaveLayer%s of area " RECT_STRING,
                 (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
     }
 
-    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
+    virtual const char* name() override {
+        return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer";
+    }
 
     int getFlags() { return mFlags; }
 
@@ -403,15 +390,15 @@
     TranslateOp(float dx, float dy)
             : mDx(dx), mDy(dy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.translate(mDx, mDy);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Translate by %f %f", mDx, mDy);
     }
 
-    virtual const char* name() { return "Translate"; }
+    virtual const char* name() override { return "Translate"; }
 
 private:
     float mDx;
@@ -423,15 +410,15 @@
     RotateOp(float degrees)
             : mDegrees(degrees) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.rotate(mDegrees);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Rotate by %f degrees", mDegrees);
     }
 
-    virtual const char* name() { return "Rotate"; }
+    virtual const char* name() override { return "Rotate"; }
 
 private:
     float mDegrees;
@@ -442,15 +429,15 @@
     ScaleOp(float sx, float sy)
             : mSx(sx), mSy(sy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.scale(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Scale by %f %f", mSx, mSy);
     }
 
-    virtual const char* name() { return "Scale"; }
+    virtual const char* name() override { return "Scale"; }
 
 private:
     float mSx;
@@ -462,15 +449,15 @@
     SkewOp(float sx, float sy)
             : mSx(sx), mSy(sy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.skew(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Skew by %f %f", mSx, mSy);
     }
 
-    virtual const char* name() { return "Skew"; }
+    virtual const char* name() override { return "Skew"; }
 
 private:
     float mSx;
@@ -482,11 +469,11 @@
     SetMatrixOp(const SkMatrix& matrix)
             : mMatrix(matrix) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.setMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         if (mMatrix.isIdentity()) {
             OP_LOGS("SetMatrix (reset)");
         } else {
@@ -494,7 +481,7 @@
         }
     }
 
-    virtual const char* name() { return "SetMatrix"; }
+    virtual const char* name() override { return "SetMatrix"; }
 
 private:
     const SkMatrix mMatrix;
@@ -505,15 +492,15 @@
     ConcatMatrixOp(const SkMatrix& matrix)
             : mMatrix(matrix) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.concatMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
     }
 
-    virtual const char* name() { return "ConcatMatrix"; }
+    virtual const char* name() override { return "ConcatMatrix"; }
 
 private:
     const SkMatrix mMatrix;
@@ -524,7 +511,7 @@
     ClipOp(SkRegion::Op op) : mOp(op) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         // NOTE: must defer op BEFORE applying state, since it may read clip
         deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
 
@@ -547,18 +534,18 @@
     ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
             : ClipOp(op), mArea(left, top, right, bottom) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
     }
 
-    virtual const char* name() { return "ClipRect"; }
+    virtual const char* name() override { return "ClipRect"; }
 
 protected:
-    virtual bool isRect() { return true; }
+    virtual bool isRect() override { return true; }
 
 private:
     Rect mArea;
@@ -569,17 +556,17 @@
     ClipPathOp(const SkPath* path, SkRegion::Op op)
             : ClipOp(op), mPath(path) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.clipPath(mPath, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         SkRect bounds = mPath->getBounds();
         OP_LOG("ClipPath bounds " RECT_STRING,
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
     }
 
-    virtual const char* name() { return "ClipPath"; }
+    virtual const char* name() override { return "ClipPath"; }
 
 private:
     const SkPath* mPath;
@@ -590,55 +577,22 @@
     ClipRegionOp(const SkRegion* region, SkRegion::Op op)
             : ClipOp(op), mRegion(region) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
         renderer.clipRegion(mRegion, mOp);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         SkIRect bounds = mRegion->getBounds();
         OP_LOG("ClipRegion bounds %d %d %d %d",
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
     }
 
-    virtual const char* name() { return "ClipRegion"; }
+    virtual const char* name() override { return "ClipRegion"; }
 
 private:
     const SkRegion* mRegion;
 };
 
-class ResetPaintFilterOp : public StateOp {
-public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.resetPaintFilter();
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOGS("ResetPaintFilter");
-    }
-
-    virtual const char* name() { return "ResetPaintFilter"; }
-};
-
-class SetupPaintFilterOp : public StateOp {
-public:
-    SetupPaintFilterOp(int clearBits, int setBits)
-            : mClearBits(clearBits), mSetBits(setBits) {}
-
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.setupPaintFilter(mClearBits, mSetBits);
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
-    }
-
-    virtual const char* name() { return "SetupPaintFilter"; }
-
-private:
-    int mClearBits;
-    int mSetBits;
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 // DRAW OPERATIONS - these are operations that can draw to the canvas's device
 ///////////////////////////////////////////////////////////////////////////////
@@ -648,11 +602,11 @@
     DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint)
             : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint)
             , mBitmap(bitmap)
-            , mEntryValid(false), mEntry(NULL) {
+            , mEntryValid(false), mEntry(nullptr) {
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmap(mBitmap, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawBitmap(mBitmap, mPaint);
     }
 
     AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
@@ -672,8 +626,8 @@
      * for each bitmap in the batch. This method is also responsible for dirtying
      * the current layer, if any.
      */
-    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<OpStatePair>& ops, const Rect& bounds) {
+    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<OpStatePair>& ops, const Rect& bounds) override {
         const DeferredDisplayState& firstState = *(ops[0].state);
         renderer.restoreDisplayState(firstState, true); // restore all but the clip
 
@@ -709,19 +663,20 @@
             }
         }
 
-        return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
+        renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
                 pureTranslate, bounds, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
+    virtual void output(int level, uint32_t logFlags) const override {
+        OP_LOG("Draw bitmap %p of size %dx%d%s",
+                mBitmap, mBitmap->width(), mBitmap->height(),
                 mEntry ? " using AssetAtlas" : "");
     }
 
-    virtual const char* name() { return "DrawBitmap"; }
+    virtual const char* name() override { return "DrawBitmap"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
         deferInfo.mergeId = getAtlasEntry(renderer) ?
                 (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
@@ -757,21 +712,19 @@
             : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
             mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
-                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
-                getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING,
                 mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
     }
 
-    virtual const char* name() { return "DrawBitmapRect"; }
+    virtual const char* name() override { return "DrawBitmapRect"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 
@@ -780,27 +733,6 @@
     Rect mSrc;
 };
 
-class DrawBitmapDataOp : public DrawBitmapOp {
-public:
-    DrawBitmapDataOp(const SkBitmap* bitmap, const SkPaint* paint)
-            : DrawBitmapOp(bitmap, paint) {}
-
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmapData(mBitmap, getPaint(renderer));
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("Draw bitmap %p", mBitmap);
-    }
-
-    virtual const char* name() { return "DrawBitmapData"; }
-
-    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
-        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
-    }
-};
-
 class DrawBitmapMeshOp : public DrawBoundedOp {
 public:
     DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -809,19 +741,19 @@
             mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
             mVertices(vertices), mColors(colors) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
-                mVertices, mColors, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
+                mVertices, mColors, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
     }
 
-    virtual const char* name() { return "DrawBitmapMesh"; }
+    virtual const char* name() override { return "DrawBitmapMesh"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
     }
 
@@ -838,8 +770,8 @@
     DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch,
             float left, float top, float right, float bottom, const SkPaint* paint)
             : DrawBoundedOp(left, top, right, bottom, paint),
-            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL),
-            mEntryValid(false), mEntry(NULL) {
+            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(nullptr),
+            mEntryValid(false), mEntry(nullptr) {
     };
 
     AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
@@ -865,8 +797,8 @@
      * and transforming the vertices of each 9-patch in the batch. This method
      * is also responsible for dirtying the current layer, if any.
      */
-    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<OpStatePair>& ops, const Rect& bounds) {
+    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<OpStatePair>& ops, const Rect& bounds) override {
         const DeferredDisplayState& firstState = *(ops[0].state);
         renderer.restoreDisplayState(firstState, true); // restore all but the clip
 
@@ -905,7 +837,7 @@
                     patchOp->mLocalBounds.top + 0.5f);
 
             // Copy & transform all the vertices for the current operation
-            TextureVertex* opVertices = opMesh->vertices;
+            TextureVertex* opVertices = opMesh->vertices.get();
             for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
                 TextureVertex::set(vertex++,
                         opVertices->x + tx, opVertices->y + ty,
@@ -935,27 +867,27 @@
             indexCount += opMesh->indexCount;
         }
 
-        return renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
-                &vertices[0], indexCount, getPaint(renderer));
+        renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
+                &vertices[0], indexCount, mPaint);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         // We're not calling the public variant of drawPatch() here
         // This method won't perform the quickReject() since we've already done it at this point
-        return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
+        renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
                 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
-                getPaint(renderer));
+                mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds),
                 mEntry ? " with AssetAtlas" : "");
     }
 
-    virtual const char* name() { return "DrawPatch"; }
+    virtual const char* name() override { return "DrawPatch"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
         deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
         deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
@@ -977,17 +909,17 @@
 class DrawColorOp : public DrawOp {
 public:
     DrawColorOp(int color, SkXfermode::Mode mode)
-            : DrawOp(NULL), mColor(color), mMode(mode) {};
+            : DrawOp(nullptr), mColor(color), mMode(mode) {};
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawColor(mColor, mMode);
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawColor(mColor, mMode);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw color %#x, mode %d", mColor, mMode);
     }
 
-    virtual const char* name() { return "DrawColor"; }
+    virtual const char* name() override { return "DrawColor"; }
 
 private:
     int mColor;
@@ -1001,7 +933,7 @@
     DrawStrokableOp(const Rect& localBounds, const SkPaint* paint)
             : DrawBoundedOp(localBounds, paint) {};
 
-    virtual bool getLocalBounds(Rect& localBounds) {
+    virtual bool getLocalBounds(Rect& localBounds) override {
         localBounds.set(mLocalBounds);
         if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
             localBounds.outset(strokeWidthOutset());
@@ -1010,7 +942,7 @@
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         if (mPaint->getPathEffect()) {
             deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
         } else {
@@ -1026,23 +958,23 @@
     DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
-                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         DrawStrokableOp::onDefer(renderer, deferInfo, state);
         deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
                 mPaint->getStyle() == SkPaint::kFill_Style;
     }
 
-    virtual const char* name() { return "DrawRect"; }
+    virtual const char* name() override { return "DrawRect"; }
 };
 
 class DrawRectsOp : public DrawBoundedOp {
@@ -1051,18 +983,18 @@
             : DrawBoundedOp(rects, count, paint),
             mRects(rects), mCount(count) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawRects(mRects, mCount, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawRects(mRects, mCount, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Rects count %d", mCount);
     }
 
-    virtual const char* name() { return "DrawRects"; }
+    virtual const char* name() override { return "DrawRects"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
     }
 
@@ -1077,17 +1009,17 @@
             float rx, float ry, const SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
-                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         DrawStrokableOp::onDefer(renderer, deferInfo, state);
         if (!mPaint->getPathEffect()) {
             renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint,
@@ -1095,7 +1027,7 @@
         }
     }
 
-    virtual const char* name() { return "DrawRoundRect"; }
+    virtual const char* name() override { return "DrawRoundRect"; }
 
 private:
     float mRx;
@@ -1109,17 +1041,17 @@
             : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom),
             mRx(rx), mRy(ry) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
-                *mRx, *mRy, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
+                *mRx, *mRy, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f",
                 *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy);
     }
 
-    virtual const char* name() { return "DrawRoundRectProps"; }
+    virtual const char* name() override { return "DrawRoundRectProps"; }
 
 private:
     float* mLeft;
@@ -1136,15 +1068,15 @@
             : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
             mX(x), mY(y), mRadius(radius) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawCircle(mX, mY, mRadius, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
     }
 
-    virtual const char* name() { return "DrawCircle"; }
+    virtual const char* name() override { return "DrawCircle"; }
 
 private:
     float mX;
@@ -1157,15 +1089,15 @@
     DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
             : DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawCircle(*mX, *mY, *mRadius, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
     }
 
-    virtual const char* name() { return "DrawCircleProps"; }
+    virtual const char* name() override { return "DrawCircleProps"; }
 
 private:
     float* mX;
@@ -1178,16 +1110,16 @@
     DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
-                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
+                mLocalBounds.right, mLocalBounds.bottom, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
-    virtual const char* name() { return "DrawOval"; }
+    virtual const char* name() override { return "DrawOval"; }
 };
 
 class DrawArcOp : public DrawStrokableOp {
@@ -1197,18 +1129,18 @@
             : DrawStrokableOp(left, top, right, bottom, paint),
             mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom,
-                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
+                mStartAngle, mSweepAngle, mUseCenter, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d",
                 RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
     }
 
-    virtual const char* name() { return "DrawArc"; }
+    virtual const char* name() override { return "DrawArc"; }
 
 private:
     float mStartAngle;
@@ -1228,23 +1160,22 @@
         mLocalBounds.set(left, top, left + width, top + height);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawPath(mPath, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawPath(mPath, mPaint);
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
-        const SkPaint* paint = getPaint(renderer);
-        renderer.getCaches().pathCache.precache(mPath, paint);
+            const DeferredDisplayState& state) override {
+        renderer.getCaches().pathCache.precache(mPath, mPaint);
 
         deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
     }
 
-    virtual const char* name() { return "DrawPath"; }
+    virtual const char* name() override { return "DrawPath"; }
 
 private:
     const SkPath* mPath;
@@ -1258,18 +1189,18 @@
         mLocalBounds.outset(strokeWidthOutset());
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawLines(mPoints, mCount, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Lines count %d", mCount);
     }
 
-    virtual const char* name() { return "DrawLines"; }
+    virtual const char* name() override { return "DrawLines"; }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         deferInfo.batchId = mPaint->isAntiAlias() ?
                 DeferredDisplayList::kOpBatch_AlphaVertices :
                 DeferredDisplayList::kOpBatch_Vertices;
@@ -1285,15 +1216,15 @@
     DrawPointsOp(const float* points, int count, const SkPaint* paint)
             : DrawLinesOp(points, count, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawPoints(mPoints, mCount, mPaint);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Points count %d", mCount);
     }
 
-    virtual const char* name() { return "DrawPoints"; }
+    virtual const char* name() override { return "DrawPoints"; }
 };
 
 class DrawSomeTextOp : public DrawOp {
@@ -1301,19 +1232,18 @@
     DrawSomeTextOp(const char* text, int bytesCount, int count, const SkPaint* paint)
             : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
-    virtual bool hasTextShadow() const {
+    virtual bool hasTextShadow() const override {
         return OpenGLRenderer::hasTextShadow(mPaint);
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
-        const SkPaint* paint = getPaint(renderer);
-        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
-        fontRenderer.precache(paint, mText, mCount, SkMatrix::I());
+            const DeferredDisplayState& state) override {
+        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
+        fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
 
         deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
                 DeferredDisplayList::kOpBatch_Text :
@@ -1335,12 +1265,12 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
-                mHOffset, mVOffset, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
+                mHOffset, mVOffset, mPaint);
     }
 
-    virtual const char* name() { return "DrawTextOnPath"; }
+    virtual const char* name() override { return "DrawTextOnPath"; }
 
 private:
     const SkPath* mPath;
@@ -1356,11 +1286,11 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawPosText(mText, mBytesCount, mCount, mPositions, mPaint);
     }
 
-    virtual const char* name() { return "DrawPosText"; }
+    virtual const char* name() override { return "DrawPosText"; }
 
 private:
     const float* mPositions;
@@ -1376,13 +1306,12 @@
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
-        const SkPaint* paint = getPaint(renderer);
-        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
+            const DeferredDisplayState& state) override {
+        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
         SkMatrix transform;
         renderer.findBestFontTransform(state.mMatrix, &transform);
         if (mPrecacheTransform != transform) {
-            fontRenderer.precache(paint, mText, mCount, transform);
+            fontRenderer.precache(mPaint, mText, mCount, transform);
             mPrecacheTransform = transform;
         }
         deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
@@ -1400,36 +1329,34 @@
                 && OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         Rect bounds;
         getLocalBounds(bounds);
-        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
-                mPositions, getPaint(renderer), mTotalAdvance, bounds);
+        renderer.drawText(mText, mBytesCount, mCount, mX, mY,
+                mPositions, mPaint, mTotalAdvance, bounds);
     }
 
-    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
-            const Vector<OpStatePair>& ops, const Rect& bounds) {
-        status_t status = DrawGlInfo::kStatusDone;
+    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+            const Vector<OpStatePair>& ops, const Rect& bounds) override {
         for (unsigned int i = 0; i < ops.size(); i++) {
             const DeferredDisplayState& state = *(ops[i].state);
-            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
+            DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer;
             renderer.restoreDisplayState(state, true); // restore all but the clip
 
             DrawTextOp& op = *((DrawTextOp*)ops[i].op);
             // quickReject() will not occure in drawText() so we can use mLocalBounds
             // directly, we do not need to account for shadow by calling getLocalBounds()
-            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
-                    op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
+            renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
+                    op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds,
                     drawOpMode);
         }
-        return status;
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
     }
 
-    virtual const char* name() { return "DrawText"; }
+    virtual const char* name() override { return "DrawText"; }
 
 private:
     const char* mText;
@@ -1449,20 +1376,19 @@
 class DrawFunctorOp : public DrawOp {
 public:
     DrawFunctorOp(Functor* functor)
-            : DrawOp(NULL), mFunctor(functor) {}
+            : DrawOp(nullptr), mFunctor(functor) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         renderer.startMark("GL functor");
-        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
+        renderer.callDrawGLFunction(mFunctor, dirty);
         renderer.endMark();
-        return ret;
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Functor %p", mFunctor);
     }
 
-    virtual const char* name() { return "DrawFunctor"; }
+    virtual const char* name() override { return "DrawFunctor"; }
 
 private:
     Functor* mFunctor;
@@ -1473,36 +1399,38 @@
     friend class DisplayListData; // grant DisplayListData access to info of child
 public:
     DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
-            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), 0),
-            mRenderNode(renderNode), mFlags(flags), mTransformFromParent(transformFromParent) {}
+            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
+            , mRenderNode(renderNode)
+            , mFlags(flags)
+            , mTransformFromParent(transformFromParent)
+            , mSkipInOrderDraw(false) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
             mRenderNode->defer(deferStruct, level + 1);
         }
     }
 
     virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
-            bool useQuickReject) {
+            bool useQuickReject) override {
         if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
             mRenderNode->replay(replayStruct, level + 1);
         }
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         LOG_ALWAYS_FATAL("should not be called, because replay() is overridden");
-        return 0;
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw RenderNode %p %s, flags %#x", mRenderNode, mRenderNode->getName(), mFlags);
         if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
             mRenderNode->output(level + 1);
         }
     }
 
-    virtual const char* name() { return "DrawRenderNode"; }
+    virtual const char* name() override { return "DrawRenderNode"; }
 
     RenderNode* renderNode() { return mRenderNode; }
 
@@ -1537,7 +1465,7 @@
 public:
     DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
             float casterAlpha, const SkPath* casterOutline)
-        : DrawOp(NULL)
+        : DrawOp(nullptr)
         , mTransformXY(transformXY)
         , mTransformZ(transformZ)
         , mCasterAlpha(casterAlpha)
@@ -1545,13 +1473,13 @@
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
-            const DeferredDisplayState& state) {
+            const DeferredDisplayState& state) override {
         renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
                 renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
                 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
         TessellationCache::vertexBuffer_pair_t buffers;
         Matrix4 drawTransform(*(renderer.currentTransform()));
         renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
@@ -1559,14 +1487,14 @@
                 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
                 buffers);
 
-        return renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
+        renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOGS("DrawShadow");
     }
 
-    virtual const char* name() { return "DrawShadow"; }
+    virtual const char* name() override { return "DrawShadow"; }
 
 private:
     bool isCasterOpaque() { return mCasterAlpha >= 1.0f; }
@@ -1580,17 +1508,17 @@
 class DrawLayerOp : public DrawOp {
 public:
     DrawLayerOp(Layer* layer, float x, float y)
-            : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
+            : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
-        return renderer.drawLayer(mLayer, mX, mY);
+    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+        renderer.drawLayer(mLayer, mX, mY);
     }
 
-    virtual void output(int level, uint32_t logFlags) const {
+    virtual void output(int level, uint32_t logFlags) const override {
         OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
     }
 
-    virtual const char* name() { return "DrawLayer"; }
+    virtual const char* name() override { return "DrawLayer"; }
 
 private:
     Layer* mLayer;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c2cb76e..2a673f4 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -24,19 +24,21 @@
 #include "ResourceCache.h"
 #include "DeferredDisplayList.h"
 #include "DeferredLayerUpdater.h"
-#include "DisplayListLogBuffer.h"
 #include "DisplayListOp.h"
 #include "DisplayListRenderer.h"
 #include "RenderNode.h"
+#include "utils/PaintUtils.h"
 
 namespace android {
 namespace uirenderer {
 
 DisplayListRenderer::DisplayListRenderer()
-    : mResourceCache(ResourceCache::getInstance())
-    , mDisplayListData(NULL)
+    : mState(*this)
+    , mResourceCache(ResourceCache::getInstance())
+    , mDisplayListData(nullptr)
     , mTranslateX(0.0f)
     , mTranslateY(0.0f)
+    , mHasDeferredTranslate(false)
     , mDeferredBarrierType(kBarrier_None)
     , mHighContrastText(false)
     , mRestoreSaveCount(-1) {
@@ -56,29 +58,29 @@
     mRegionMap.clear();
     mPathMap.clear();
     DisplayListData* data = mDisplayListData;
-    mDisplayListData = 0;
+    mDisplayListData = nullptr;
+    mSkiaCanvasProxy.reset(nullptr);
     return data;
 }
 
-status_t DisplayListRenderer::prepareDirty(float left, float top,
-        float right, float bottom, bool opaque) {
+void DisplayListRenderer::prepareDirty(float left, float top,
+        float right, float bottom) {
 
     LOG_ALWAYS_FATAL_IF(mDisplayListData,
             "prepareDirty called a second time during a recording!");
     mDisplayListData = new DisplayListData();
 
-    initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
+    mState.initializeSaveStack(0, 0, mState.getWidth(), mState.getHeight(), Vector3());
 
     mDeferredBarrierType = kBarrier_InOrder;
-    mDirtyClip = opaque;
+    mState.setDirtyClip(false);
     mRestoreSaveCount = -1;
-
-    return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
 }
 
-void DisplayListRenderer::finish() {
+bool DisplayListRenderer::finish() {
     flushRestoreToCount();
     flushTranslate();
+    return false;
 }
 
 void DisplayListRenderer::interrupt() {
@@ -87,16 +89,24 @@
 void DisplayListRenderer::resume() {
 }
 
-status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+void DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     // Ignore dirty during recording, it matters only when we replay
     addDrawOp(new (alloc()) DrawFunctorOp(functor));
     mDisplayListData->functors.add(functor);
-    return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
 }
 
-int DisplayListRenderer::save(int flags) {
-    addStateOp(new (alloc()) SaveOp(flags));
-    return StatefulBaseRenderer::save(flags);
+SkCanvas* DisplayListRenderer::asSkCanvas() {
+    LOG_ALWAYS_FATAL_IF(!mDisplayListData,
+            "attempting to get an SkCanvas when we are not recording!");
+    if (!mSkiaCanvasProxy) {
+        mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
+    }
+    return mSkiaCanvasProxy.get();
+}
+
+int DisplayListRenderer::save(SkCanvas::SaveFlags flags) {
+    addStateOp(new (alloc()) SaveOp((int) flags));
+    return mState.save((int) flags);
 }
 
 void DisplayListRenderer::restore() {
@@ -107,178 +117,232 @@
 
     mRestoreSaveCount--;
     flushTranslate();
-    StatefulBaseRenderer::restore();
+    mState.restore();
 }
 
 void DisplayListRenderer::restoreToCount(int saveCount) {
     mRestoreSaveCount = saveCount;
     flushTranslate();
-    StatefulBaseRenderer::restoreToCount(saveCount);
+    mState.restoreToCount(saveCount);
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
-        const SkPaint* paint, int flags) {
+        const SkPaint* paint, SkCanvas::SaveFlags flags) {
     // force matrix/clip isolation for layer
     flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
 
     paint = refPaint(paint);
-    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
-    return StatefulBaseRenderer::save(flags);
+    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags));
+    return mState.save((int) flags);
 }
 
-void DisplayListRenderer::translate(float dx, float dy, float dz) {
-    // ignore dz, not used at defer time
+void DisplayListRenderer::translate(float dx, float dy) {
     mHasDeferredTranslate = true;
     mTranslateX += dx;
     mTranslateY += dy;
     flushRestoreToCount();
-    StatefulBaseRenderer::translate(dx, dy, dz);
+    mState.translate(dx, dy, 0.0f);
 }
 
 void DisplayListRenderer::rotate(float degrees) {
     addStateOp(new (alloc()) RotateOp(degrees));
-    StatefulBaseRenderer::rotate(degrees);
+    mState.rotate(degrees);
 }
 
 void DisplayListRenderer::scale(float sx, float sy) {
     addStateOp(new (alloc()) ScaleOp(sx, sy));
-    StatefulBaseRenderer::scale(sx, sy);
+    mState.scale(sx, sy);
 }
 
 void DisplayListRenderer::skew(float sx, float sy) {
     addStateOp(new (alloc()) SkewOp(sx, sy));
-    StatefulBaseRenderer::skew(sx, sy);
+    mState.skew(sx, sy);
 }
 
 void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
     addStateOp(new (alloc()) SetMatrixOp(matrix));
-    StatefulBaseRenderer::setMatrix(matrix);
+    mState.setMatrix(matrix);
 }
 
-void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
+void DisplayListRenderer::concat(const SkMatrix& matrix) {
     addStateOp(new (alloc()) ConcatMatrixOp(matrix));
-    StatefulBaseRenderer::concatMatrix(matrix);
+    mState.concatMatrix(matrix);
 }
 
+bool DisplayListRenderer::getClipBounds(SkRect* outRect) const {
+    Rect bounds = mState.getLocalClipBounds();
+    *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    return !(outRect->isEmpty());
+}
+
+bool DisplayListRenderer::quickRejectRect(float left, float top, float right, float bottom) const {
+    return mState.quickRejectConservative(left, top, right, bottom);
+}
+
+bool DisplayListRenderer::quickRejectPath(const SkPath& path) const {
+    SkRect bounds = path.getBounds();
+    return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
+}
+
+
 bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
         SkRegion::Op op) {
     addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
-    return StatefulBaseRenderer::clipRect(left, top, right, bottom, op);
+    return mState.clipRect(left, top, right, bottom, op);
 }
 
 bool DisplayListRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
     path = refPath(path);
     addStateOp(new (alloc()) ClipPathOp(path, op));
-    return StatefulBaseRenderer::clipPath(path, op);
+    return mState.clipPath(path, op);
 }
 
 bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
     region = refRegion(region);
     addStateOp(new (alloc()) ClipRegionOp(region, op));
-    return StatefulBaseRenderer::clipRegion(region, op);
+    return mState.clipRegion(region, op);
 }
 
-status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
+void DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
     LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
 
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
-    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
+    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *mState.currentTransform());
     addRenderNodeOp(op);
-
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
+void DisplayListRenderer::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
     // We ref the DeferredLayerUpdater due to its thread-safe ref-counting
     // semantics.
     mDisplayListData->ref(layerHandle);
     addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+void DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
     bitmap = refBitmap(bitmap);
     paint = refPaint(paint);
 
     addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
+void DisplayListRenderer::drawBitmap(const SkBitmap& bitmap, float left, float top,
+        const SkPaint* paint) {
+    save(SkCanvas::kMatrix_SaveFlag);
+    translate(left, top);
+    drawBitmap(&bitmap, paint);
+    restore();
+}
+
+void DisplayListRenderer::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+        const SkPaint* paint) {
+    if (matrix.isIdentity()) {
+        drawBitmap(&bitmap, paint);
+    } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))) {
+        // SkMatrix::isScaleTranslate() not available in L
+        SkRect src;
+        SkRect dst;
+        bitmap.getBounds(&src);
+        matrix.mapRect(&dst, src);
+        drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+                   dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+    } else {
+        save(SkCanvas::kMatrix_SaveFlag);
+        concat(matrix);
+        drawBitmap(&bitmap, paint);
+        restore();
+    }
+}
+
+void DisplayListRenderer::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, const SkPaint* paint) {
     if (srcLeft == 0 && srcTop == 0
-            && srcRight == bitmap->width() && srcBottom == bitmap->height()
+            && srcRight == bitmap.width()
+            && srcBottom == bitmap.height()
             && (srcBottom - srcTop == dstBottom - dstTop)
             && (srcRight - srcLeft == dstRight - dstLeft)) {
         // transform simple rect to rect drawing case into position bitmap ops, since they merge
         save(SkCanvas::kMatrix_SaveFlag);
         translate(dstLeft, dstTop);
-        drawBitmap(bitmap, paint);
+        drawBitmap(&bitmap, paint);
         restore();
     } else {
-        bitmap = refBitmap(bitmap);
         paint = refPaint(paint);
 
-        addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
+        if (paint && paint->getShader()) {
+            float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
+            float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
+            if (!MathUtils::areEqual(scaleX, 1.0f) || !MathUtils::areEqual(scaleY, 1.0f)) {
+                // Apply the scale transform on the canvas, so that the shader
+                // effectively calculates positions relative to src rect space
+
+                save(SkCanvas::kMatrix_SaveFlag);
+                translate(dstLeft, dstTop);
+                scale(scaleX, scaleY);
+
+                dstLeft = 0.0f;
+                dstTop = 0.0f;
+                dstRight = srcRight - srcLeft;
+                dstBottom = srcBottom - srcTop;
+
+                addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
+                        srcLeft, srcTop, srcRight, srcBottom,
+                        dstLeft, dstTop, dstRight, dstBottom, paint));
+                restore();
+                return;
+            }
+        }
+
+        addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
                 srcLeft, srcTop, srcRight, srcBottom,
                 dstLeft, dstTop, dstRight, dstBottom, paint));
     }
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
-    bitmap = refBitmapData(bitmap);
-    paint = refPaint(paint);
-
-    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, paint));
-    return DrawGlInfo::kStatusDone;
-}
-
-status_t DisplayListRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+void DisplayListRenderer::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
     int vertexCount = (meshWidth + 1) * (meshHeight + 1);
-    bitmap = refBitmap(bitmap);
     vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex
     paint = refPaint(paint);
     colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
 
-    addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
-                    vertices, colors, paint));
-    return DrawGlInfo::kStatusDone;
+    addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(&bitmap), meshWidth, meshHeight,
+           vertices, colors, paint));
 }
 
-status_t DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+void DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
         float left, float top, float right, float bottom, const SkPaint* paint) {
     bitmap = refBitmap(bitmap);
     patch = refPatch(patch);
     paint = refPaint(paint);
 
     addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
+void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
     addDrawOp(new (alloc()) DrawColorOp(color, mode));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
-        const SkPaint* paint) {
-    paint = refPaint(paint);
-    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, paint));
-    return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPaint(const SkPaint& paint) {
+    SkRect bounds;
+    if (getClipBounds(&bounds)) {
+        drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
+    }
 }
 
-status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
-        float rx, float ry, const SkPaint* paint) {
-    paint = refPaint(paint);
-    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, paint));
-    return DrawGlInfo::kStatusDone;
+
+void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
+        const SkPaint& paint) {
+    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawRoundRect(
+void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
+        float rx, float ry, const SkPaint& paint) {
+    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, refPaint(&paint)));
+}
+
+void DisplayListRenderer::drawRoundRect(
         CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
         CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
         CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
@@ -292,16 +356,13 @@
     mDisplayListData->ref(paint);
     addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
             &right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint* paint) {
-    paint = refPaint(paint);
-    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint));
-    return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+void DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
         CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
     mDisplayListData->ref(x);
     mDisplayListData->ref(y);
@@ -309,143 +370,121 @@
     mDisplayListData->ref(paint);
     addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
             &radius->value, &paint->value));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
-        const SkPaint* paint) {
-    paint = refPaint(paint);
-    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, paint));
-    return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
+        const SkPaint& paint) {
+    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
-        float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
+void DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
+        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
     if (fabs(sweepAngle) >= 360.0f) {
-        return drawOval(left, top, right, bottom, paint);
+        drawOval(left, top, right, bottom, paint);
+    } else {
+        addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
+                        startAngle, sweepAngle, useCenter, refPaint(&paint)));
     }
-
-    paint = refPaint(paint);
-    addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
-                    startAngle, sweepAngle, useCenter, paint));
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
-    path = refPath(path);
-    paint = refPaint(paint);
-
-    addDrawOp(new (alloc()) DrawPathOp(path, paint));
-    return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPath(const SkPath& path, const SkPaint& paint) {
+    addDrawOp(new (alloc()) DrawPathOp(refPath(&path), refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
+void DisplayListRenderer::drawLines(const float* points, int count, const SkPaint& paint) {
     points = refBuffer<float>(points, count);
-    paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawLinesOp(points, count, paint));
-    return DrawGlInfo::kStatusDone;
+    addDrawOp(new (alloc()) DrawLinesOp(points, count, refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
+void DisplayListRenderer::drawPoints(const float* points, int count, const SkPaint& paint) {
     points = refBuffer<float>(points, count);
-    paint = refPaint(paint);
 
-    addDrawOp(new (alloc()) DrawPointsOp(points, count, paint));
-    return DrawGlInfo::kStatusDone;
+    addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint)));
 }
 
-status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
-        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
-    if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawTextOnPath(const uint16_t* glyphs, int count,
+        const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) {
+    if (!glyphs || count <= 0) return;
 
-    text = refText(text, bytesCount);
-    path = refPath(path);
-    paint = refPaint(paint);
-
-    DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
-            hOffset, vOffset, paint);
+    int bytesCount = 2 * count;
+    DrawOp* op = new (alloc()) DrawTextOnPathOp(refText((const char*) glyphs, bytesCount),
+            bytesCount, count, refPath(&path),
+            hOffset, vOffset, refPaint(&paint));
     addDrawOp(op);
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
-        const float* positions, const SkPaint* paint) {
-    if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPosText(const uint16_t* text, const float* positions,
+        int count, int posCount, const SkPaint& paint) {
+    if (!text || count <= 0) return;
 
-    text = refText(text, bytesCount);
+    int bytesCount = 2 * count;
     positions = refBuffer<float>(positions, count * 2);
-    paint = refPaint(paint);
 
-    DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
+    DrawOp* op = new (alloc()) DrawPosTextOp(refText((const char*) text, bytesCount),
+                                             bytesCount, count, positions, refPaint(&paint));
     addDrawOp(op);
-    return DrawGlInfo::kStatusDone;
 }
 
 static void simplifyPaint(int color, SkPaint* paint) {
     paint->setColor(color);
-    paint->setShader(NULL);
-    paint->setColorFilter(NULL);
-    paint->setLooper(NULL);
+    paint->setShader(nullptr);
+    paint->setColorFilter(nullptr);
+    paint->setLooper(nullptr);
     paint->setStrokeWidth(4 + 0.04 * paint->getTextSize());
     paint->setStrokeJoin(SkPaint::kRound_Join);
-    paint->setLooper(NULL);
+    paint->setLooper(nullptr);
 }
 
-status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
-        float x, float y, const float* positions, const SkPaint* paint,
-        float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) {
+void DisplayListRenderer::drawText(const uint16_t* glyphs, const float* positions,
+        int count, const SkPaint& paint, float x, float y,
+        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+        float totalAdvance) {
 
-    if (!text || count <= 0 || paintWillNotDrawText(*paint)) return DrawGlInfo::kStatusDone;
+    if (!glyphs || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
 
-    text = refText(text, bytesCount);
+    int bytesCount = count * 2;
+    const char* text = refText((const char*) glyphs, bytesCount);
     positions = refBuffer<float>(positions, count * 2);
+    Rect bounds(boundsLeft, boundsTop, boundsRight, boundsBottom);
 
     if (CC_UNLIKELY(mHighContrastText)) {
         // high contrast draw path
-        int color = paint->getColor();
+        int color = paint.getColor();
         int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
         bool darken = channelSum < (128 * 3);
 
         // outline
-        SkPaint* outlinePaint = copyPaint(paint);
+        SkPaint* outlinePaint = copyPaint(&paint);
         simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, outlinePaint);
         outlinePaint->setStyle(SkPaint::kStrokeAndFill_Style);
         addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
                 x, y, positions, outlinePaint, totalAdvance, bounds)); // bounds?
 
         // inner
-        SkPaint* innerPaint = copyPaint(paint);
+        SkPaint* innerPaint = copyPaint(&paint);
         simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, innerPaint);
         innerPaint->setStyle(SkPaint::kFill_Style);
         addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
                 x, y, positions, innerPaint, totalAdvance, bounds));
     } else {
         // standard draw path
-        paint = refPaint(paint);
-
         DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count,
-                x, y, positions, paint, totalAdvance, bounds);
+                x, y, positions, refPaint(&paint), totalAdvance, bounds);
         addDrawOp(op);
     }
-    return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
-    if (count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+    if (count <= 0) return;
 
     rects = refBuffer<float>(rects, count);
     paint = refPaint(paint);
     addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint));
-    return DrawGlInfo::kStatusDone;
 }
 
-void DisplayListRenderer::resetPaintFilter() {
-    addStateOp(new (alloc()) ResetPaintFilterOp());
-}
-
-void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
-    addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
+void DisplayListRenderer::setDrawFilter(SkDrawFilter* filter) {
+    mDrawFilter.reset(filter);
 }
 
 void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {
@@ -504,7 +543,7 @@
 size_t DisplayListRenderer::addDrawOp(DrawOp* op) {
     Rect localBounds;
     if (op->getLocalBounds(localBounds)) {
-        bool rejected = quickRejectConservative(localBounds.left, localBounds.top,
+        bool rejected = quickRejectRect(localBounds.left, localBounds.top,
                 localBounds.right, localBounds.bottom);
         op->setQuickRejected(rejected);
     }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2cc2be3..48ecd69 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -17,12 +17,18 @@
 #ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 #define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 
+#include <SkDrawFilter.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkPath.h>
+#include <SkRegion.h>
+#include <SkTLazy.h>
 #include <cutils/compiler.h>
 
-#include "DisplayListLogBuffer.h"
+#include "Canvas.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "SkiaCanvasProxy.h"
 #include "RenderNode.h"
 #include "ResourceCache.h"
 
@@ -48,13 +54,15 @@
 class DeferredLayerUpdater;
 class DisplayListRenderer;
 class DisplayListOp;
+class DisplayListRenderer;
 class DrawOp;
+class RenderNode;
 class StateOp;
 
 /**
  * Records drawing commands in a display list for later playback into an OpenGLRenderer.
  */
-class ANDROID_API DisplayListRenderer: public StatefulBaseRenderer {
+class ANDROID_API DisplayListRenderer: public Canvas, public CanvasStateClient {
 public:
     DisplayListRenderer();
     virtual ~DisplayListRenderer();
@@ -64,104 +72,178 @@
     DisplayListData* finishRecording();
 
 // ----------------------------------------------------------------------------
-// Frame state operations
+// HWUI Frame state operations
 // ----------------------------------------------------------------------------
-    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    virtual void finish();
-    virtual void interrupt();
-    virtual void resume();
+
+    void prepareDirty(float left, float top, float right, float bottom);
+    void prepare() { prepareDirty(0.0f, 0.0f, width(), height()); }
+    bool finish();
+    void interrupt();
+    void resume();
 
 // ----------------------------------------------------------------------------
-// Canvas state operations
+// HWUI Canvas state operations
 // ----------------------------------------------------------------------------
-    // Save (layer)
-    virtual int save(int flags);
-    virtual void restore();
-    virtual void restoreToCount(int saveCount);
-    virtual int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, int flags);
 
-    // Matrix
-    virtual void translate(float dx, float dy, float dz = 0.0f);
-    virtual void rotate(float degrees);
-    virtual void scale(float sx, float sy);
-    virtual void skew(float sx, float sy);
+    void setViewport(int width, int height) { mState.setViewport(width, height); }
 
-    virtual void setMatrix(const SkMatrix& matrix);
-    virtual void concatMatrix(const SkMatrix& matrix);
-
-    // Clip
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
-
-    // Misc - should be implemented with SkPaint inspection
-    virtual void resetPaintFilter();
-    virtual void setupPaintFilter(int clearBits, int setBits);
+    const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
 
     bool isCurrentTransformSimple() {
-        return currentTransform()->isSimple();
+        return mState.currentTransform()->isSimple();
     }
 
 // ----------------------------------------------------------------------------
-// Canvas draw operations
+// HWUI Canvas draw operations
 // ----------------------------------------------------------------------------
-    virtual status_t drawColor(int color, SkXfermode::Mode mode);
 
     // Bitmap-based
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
-    virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint);
-    virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+    void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
+    // TODO: move drawPatch() to Canvas.h
+    void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
             float left, float top, float right, float bottom, const SkPaint* paint);
 
     // Shapes
-    virtual status_t drawRect(float left, float top, float right, float bottom,
-            const SkPaint* paint);
-    virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
-    virtual status_t drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint* paint);
-    virtual status_t drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+    void drawRects(const float* rects, int count, const SkPaint* paint);
+    void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
                 CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
                 CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
                 CanvasPropertyPaint* paint);
-    virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
-    virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+    void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
                 CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
-    virtual status_t drawOval(float left, float top, float right, float bottom,
-            const SkPaint* paint);
-    virtual status_t drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint);
-    virtual status_t drawPath(const SkPath* path, const SkPaint* paint);
-    virtual status_t drawLines(const float* points, int count, const SkPaint* paint);
-    virtual status_t drawPoints(const float* points, int count, const SkPaint* paint);
 
-    // Text
-    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
-            DrawOpMode drawOpMode = kDrawOpMode_Immediate);
-    virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
-            float hOffset, float vOffset, const SkPaint* paint);
-    virtual status_t drawPosText(const char* text, int bytesCount, int count,
-            const float* positions, const SkPaint* paint);
 
 // ----------------------------------------------------------------------------
-// Canvas draw operations - special
+// HWUI Canvas draw operations - special
 // ----------------------------------------------------------------------------
-    virtual status_t drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
-    virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
+    void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
+    void drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
 
     // TODO: rename for consistency
-    virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
+    void callDrawGLFunction(Functor* functor, Rect& dirty);
 
     void setHighContrastText(bool highContrastText) {
         mHighContrastText = highContrastText;
     }
+
+// ----------------------------------------------------------------------------
+// CanvasStateClient interface
+// ----------------------------------------------------------------------------
+    virtual void onViewportInitialized() override { }
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override { }
+    virtual GLuint getTargetFbo() const override { return -1; }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas interface
+// ----------------------------------------------------------------------------
+    virtual SkCanvas* asSkCanvas() override;
+
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) override {
+        LOG_ALWAYS_FATAL("DisplayListRenderer is not backed by a bitmap.");
+    }
+
+    virtual bool isOpaque() override { return false; }
+    virtual int width() override { return mState.getWidth(); }
+    virtual int height() override { return mState.getHeight(); }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas state operations
+// ----------------------------------------------------------------------------
+    // Save (layer)
+    virtual int getSaveCount() const override { return mState.getSaveCount(); }
+    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual void restore() override;
+    virtual void restoreToCount(int saveCount) override;
+
+    virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+        SkCanvas::SaveFlags flags) override;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SkCanvas::SaveFlags flags) override {
+        SkPaint paint;
+        paint.setAlpha(alpha);
+        return saveLayer(left, top, right, bottom, &paint, flags);
+    }
+
+    // Matrix
+    virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); }
+    virtual void setMatrix(const SkMatrix& matrix) override;
+
+    virtual void concat(const SkMatrix& matrix) override;
+    virtual void rotate(float degrees) override;
+    virtual void scale(float sx, float sy) override;
+    virtual void skew(float sx, float sy) override;
+    virtual void translate(float dx, float dy) override;
+
+    // Clip
+    virtual bool getClipBounds(SkRect* outRect) const override;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
+    virtual bool quickRejectPath(const SkPath& path) const override;
+
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) override;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) override;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override;
+
+    // Misc
+    virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); }
+    virtual void setDrawFilter(SkDrawFilter* filter) override;
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas draw operations
+// ----------------------------------------------------------------------------
+    virtual void drawColor(int color, SkXfermode::Mode mode) override;
+    virtual void drawPaint(const SkPaint& paint) override;
+
+    // Geometry
+    virtual void drawPoint(float x, float y, const SkPaint& paint) override {
+        float points[2] = { x, y };
+        drawPoints(points, 2, paint);
+    }
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+            const SkPaint& paint) override {
+        float points[4] = { startX, startY, stopX, stopY };
+        drawLines(points, 4, paint);
+    }
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
+    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+            const float* verts, const float* tex, const int* colors,
+            const uint16_t* indices, int indexCount, const SkPaint& paint) override
+        { /* DisplayListRenderer does not support drawVertices(); ignore */ }
+
+    // Bitmap-based
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+                            const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) override;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) override;
+
+    // Text
+    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+            const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
+            float boundsRight, float boundsBottom, float totalAdvance) override;
+    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) override;
+    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) override;
+    virtual bool drawTextAbsolutePos() const override { return false; }
+
+
 private:
+
+    CanvasState mState;
+    std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
+
     enum DeferredBarrierType {
         kBarrier_None,
         kBarrier_InOrder,
@@ -186,7 +268,7 @@
 
     template<class T>
     inline const T* refBuffer(const T* srcBuffer, int32_t count) {
-        if (!srcBuffer) return NULL;
+        if (!srcBuffer) return nullptr;
 
         T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
         memcpy(dstBuffer, srcBuffer, count * sizeof(T));
@@ -198,58 +280,51 @@
     }
 
     inline const SkPath* refPath(const SkPath* path) {
-        if (!path) return NULL;
+        if (!path) return nullptr;
 
-        const SkPath* pathCopy = mPathMap.valueFor(path);
-        if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
-            SkPath* newPathCopy = new SkPath(*path);
-            newPathCopy->setSourcePath(path);
-
-            pathCopy = newPathCopy;
-            // replaceValueFor() performs an add if the entry doesn't exist
-            mPathMap.replaceValueFor(path, pathCopy);
-            mDisplayListData->paths.add(pathCopy);
-        }
-        if (mDisplayListData->sourcePaths.indexOf(path) < 0) {
-            mResourceCache.incrementRefcount(path);
-            mDisplayListData->sourcePaths.add(path);
-        }
-        return pathCopy;
+        // The points/verbs within the path are refcounted so this copy operation
+        // is inexpensive and maintains the generationID of the original path.
+        const SkPath* cachedPath = new SkPath(*path);
+        mDisplayListData->pathResources.add(cachedPath);
+        return cachedPath;
     }
 
     inline const SkPaint* refPaint(const SkPaint* paint) {
-        if (!paint) return NULL;
+        if (!paint) return nullptr;
 
-        const SkPaint* paintCopy = mPaintMap.valueFor(paint);
-        if (paintCopy == NULL
-                || paintCopy->getGenerationID() != paint->getGenerationID()
-                // We can't compare shader pointers because that will always
-                // change as we do partial copying via wrapping. However, if the
-                // shader changes the paint generationID will have changed and
-                // so we don't hit this comparison anyway
-                || !(paint->getShader() && paintCopy->getShader()
-                        && paint->getShader()->getGenerationID() == paintCopy->getShader()->getGenerationID())) {
-            paintCopy = copyPaint(paint);
-            // replaceValueFor() performs an add if the entry doesn't exist
-            mPaintMap.replaceValueFor(paint, paintCopy);
+        // If there is a draw filter apply it here and store the modified paint
+        // so that we don't need to modify the paint every time we access it.
+        SkTLazy<SkPaint> filteredPaint;
+        if (mDrawFilter.get()) {
+            paint = filteredPaint.init();
+            mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type);
         }
 
-        return paintCopy;
+        // compute the hash key for the paint and check the cache.
+        const uint32_t key = paint->getHash();
+        const SkPaint* cachedPaint = mPaintMap.valueFor(key);
+        // In the unlikely event that 2 unique paints have the same hash we do a
+        // object equality check to ensure we don't erroneously dedup them.
+        if (cachedPaint == nullptr || *cachedPaint != *paint) {
+            cachedPaint = new SkPaint(*paint);
+            std::unique_ptr<const SkPaint> copy(cachedPaint);
+            mDisplayListData->paints.push_back(std::move(copy));
+
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mPaintMap.replaceValueFor(key, cachedPaint);
+        }
+
+        return cachedPaint;
     }
 
     inline SkPaint* copyPaint(const SkPaint* paint) {
-        if (!paint) return NULL;
-        SkPaint* paintCopy = new SkPaint(*paint);
-        if (paint->getShader()) {
-            SkShader* shaderCopy = SkShader::CreateLocalMatrixShader(
-                    paint->getShader(), paint->getShader()->getLocalMatrix());
-            paintCopy->setShader(shaderCopy);
-            paintCopy->setGenerationID(paint->getGenerationID());
-            shaderCopy->setGenerationID(paint->getShader()->getGenerationID());
-            shaderCopy->unref();
-        }
-        mDisplayListData->paints.add(paintCopy);
-        return paintCopy;
+        if (!paint) return nullptr;
+
+        SkPaint* returnPaint = new SkPaint(*paint);
+        std::unique_ptr<const SkPaint> copy(returnPaint);
+        mDisplayListData->paints.push_back(std::move(copy));
+
+        return returnPaint;
     }
 
     inline const SkRegion* refRegion(const SkRegion* region) {
@@ -257,16 +332,18 @@
             return region;
         }
 
-        const SkRegion* regionCopy = mRegionMap.valueFor(region);
+        const SkRegion* cachedRegion = mRegionMap.valueFor(region);
         // TODO: Add generation ID to SkRegion
-        if (regionCopy == NULL) {
-            regionCopy = new SkRegion(*region);
+        if (cachedRegion == nullptr) {
+            std::unique_ptr<const SkRegion> copy(new SkRegion(*region));
+            cachedRegion = copy.get();
+            mDisplayListData->regions.push_back(std::move(copy));
+
             // replaceValueFor() performs an add if the entry doesn't exist
-            mRegionMap.replaceValueFor(region, regionCopy);
-            mDisplayListData->regions.add(regionCopy);
+            mRegionMap.replaceValueFor(region, cachedRegion);
         }
 
-        return regionCopy;
+        return cachedRegion;
     }
 
     inline const SkBitmap* refBitmap(const SkBitmap* bitmap) {
@@ -274,15 +351,9 @@
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        mDisplayListData->bitmapResources.add(bitmap);
-        mResourceCache.incrementRefcount(bitmap);
-        return bitmap;
-    }
-
-    inline const SkBitmap* refBitmapData(const SkBitmap* bitmap) {
-        mDisplayListData->ownedBitmapResources.add(bitmap);
-        mResourceCache.incrementRefcount(bitmap);
-        return bitmap;
+        const SkBitmap* cachedBitmap = mResourceCache.insert(bitmap);
+        mDisplayListData->bitmapResources.add(cachedBitmap);
+        return cachedBitmap;
     }
 
     inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
@@ -291,7 +362,7 @@
         return patch;
     }
 
-    DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
+    DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap;
     DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
     DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
 
@@ -306,6 +377,8 @@
 
     int mRestoreSaveCount;
 
+    SkAutoTUnref<SkDrawFilter> mDrawFilter;
+
     friend class RenderNode;
 
 }; // class DisplayListRenderer
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 77006a4..1ba6511 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,15 +24,16 @@
 // Lifecycle
 ///////////////////////////////////////////////////////////////////////////////
 
-Dither::Dither(): mCaches(NULL), mInitialized(false), mDitherTexture(0) {
+Dither::Dither(Caches& caches)
+        : mCaches(caches)
+        , mInitialized(false)
+        , mDitherTexture(0) {
 }
 
 void Dither::bindDitherTexture() {
     if (!mInitialized) {
-        bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
-
         glGenTextures(1, &mDitherTexture);
-        mCaches->bindTexture(mDitherTexture);
+        mCaches.textureState().bindTexture(mDitherTexture);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -40,7 +41,7 @@
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
-        if (useFloatTexture) {
+        if (mCaches.extensions().hasFloatTextures()) {
             // We use a R16F texture, let's remap the alpha channel to the
             // red channel to avoid changing the shader sampling code on GL ES 3.0+
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
@@ -71,13 +72,13 @@
 
         mInitialized = true;
     } else {
-        mCaches->bindTexture(mDitherTexture);
+        mCaches.textureState().bindTexture(mDitherTexture);
     }
 }
 
 void Dither::clear() {
     if (mInitialized) {
-        mCaches->deleteTexture(mDitherTexture);
+        mCaches.textureState().deleteTexture(mDitherTexture);
         mInitialized = false;
     }
 }
@@ -86,15 +87,13 @@
 // Program management
 ///////////////////////////////////////////////////////////////////////////////
 
-void Dither::setupProgram(Program* program, GLuint* textureUnit) {
-    if (!mCaches) mCaches = &Caches::getInstance();
-
+void Dither::setupProgram(Program& program, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
-    mCaches->activeTexture(textureSlot);
+    mCaches.textureState().activateTexture(textureSlot);
 
     bindDitherTexture();
 
-    glUniform1i(program->getUniform("ditherSampler"), textureSlot);
+    glUniform1i(program.getUniform("ditherSampler"), textureSlot);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 546236be..b589b80 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -19,12 +19,12 @@
 
 #include <GLES3/gl3.h>
 
-#include "Program.h"
-
 namespace android {
 namespace uirenderer {
 
 class Caches;
+class Extensions;
+class Program;
 
 // Must be a power of two
 #define DITHER_KERNEL_SIZE 4
@@ -37,15 +37,15 @@
  */
 class Dither {
 public:
-    Dither();
+    Dither(Caches& caches);
 
     void clear();
-    void setupProgram(Program* program, GLuint* textureUnit);
+    void setupProgram(Program& program, GLuint* textureUnit);
 
 private:
     void bindDitherTexture();
 
-    Caches* mCaches;
+    Caches& mCaches;
     bool mInitialized;
     GLuint mDitherTexture;
 };
diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp
index e590642..ecde5ff 100644
--- a/libs/hwui/DrawProfiler.cpp
+++ b/libs/hwui/DrawProfiler.cpp
@@ -59,7 +59,7 @@
 DrawProfiler::DrawProfiler()
         : mType(kNone)
         , mDensity(0)
-        , mData(NULL)
+        , mData(nullptr)
         , mDataSize(0)
         , mCurrentFrame(-1)
         , mPreviousTime(0)
@@ -160,7 +160,7 @@
 
 void DrawProfiler::destroyData() {
     delete mData;
-    mData = NULL;
+    mData = nullptr;
 }
 
 void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) {
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 84e7e65..2a82216 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -16,18 +16,16 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include "Extensions.h"
+
+#include "Debug.h"
+#include "Properties.h"
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-
+#include <GLES2/gl2ext.h>
 #include <utils/Log.h>
 
-#include "Debug.h"
-#include "Extensions.h"
-#include "Properties.h"
-
 namespace android {
 
 using namespace uirenderer;
@@ -50,14 +48,13 @@
 // Constructors
 ///////////////////////////////////////////////////////////////////////////////
 
-Extensions::Extensions(): Singleton<Extensions>() {
+Extensions::Extensions() {
     // Query GL extensions
     findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
     mHasNPot = hasGlExtension("GL_OES_texture_npot");
     mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
     mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
     mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
-    mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
     mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
     mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
     mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
@@ -66,7 +63,7 @@
     findExtensions(eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS), mEglExtensionList);
 
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_DEBUG_NV_PROFILING, property, NULL) > 0) {
+    if (property_get(PROPERTY_DEBUG_NV_PROFILING, property, nullptr) > 0) {
         mHasNvSystemTime = !strcmp(property, "true") && hasEglExtension("EGL_NV_system_time");
     } else {
         mHasNvSystemTime = false;
@@ -93,9 +90,6 @@
     }
 }
 
-Extensions::~Extensions() {
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Methods
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 25d4c5e..e7d317d 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -23,6 +23,8 @@
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
 
+#include <GLES2/gl2.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -30,13 +32,14 @@
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-class ANDROID_API Extensions: public Singleton<Extensions> {
+class ANDROID_API Extensions {
 public:
+    Extensions();
+
     inline bool hasNPot() const { return mHasNPot; }
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
     inline bool hasDebugMarker() const { return mHasDebugMarker; }
-    inline bool hasDebugLabel() const { return mHasDebugLabel; }
     inline bool hasTiledRendering() const { return mHasTiledRendering; }
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
@@ -55,13 +58,8 @@
     void dump() const;
 
 private:
-    Extensions();
-    ~Extensions();
-
     void findExtensions(const char* extensions, SortedVector<String8>& list) const;
 
-    friend class Singleton<Extensions>;
-
     SortedVector<String8> mGlExtensionList;
     SortedVector<String8> mEglExtensionList;
 
@@ -69,7 +67,6 @@
     bool mHasFramebufferFetch;
     bool mHasDiscardFramebuffer;
     bool mHasDebugMarker;
-    bool mHasDebugLabel;
     bool mHasTiledRendering;
     bool mHas1BitStencil;
     bool mHas4BitStencil;
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
index beef7be..b54d532 100644
--- a/libs/hwui/FboCache.cpp
+++ b/libs/hwui/FboCache.cpp
@@ -31,7 +31,7 @@
 
 FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_FBO_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_FBO_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting fbo cache size to %s", property);
         mMaxSize = atoi(property);
     } else {
diff --git a/libs/hwui/Fence.h b/libs/hwui/Fence.h
deleted file mode 100644
index f175e98..0000000
--- a/libs/hwui/Fence.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_FENCE_H
-#define ANDROID_HWUI_FENCE_H
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Creating a Fence instance inserts a new sync fence in the OpenGL
- * commands stream. The caller can then wait for the fence to be signaled
- * by calling the wait method.
- */
-class Fence {
-public:
-    enum {
-        /**
-         * Default timeout in nano-seconds for wait()
-         */
-        kDefaultTimeout = 1000000000
-    };
-
-    /**
-     * Inserts a new sync fence in the OpenGL commands stream.
-     */
-    Fence() {
-        mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        if (mDisplay != EGL_NO_DISPLAY) {
-            mFence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
-        } else {
-            mFence = EGL_NO_SYNC_KHR;
-        }
-    }
-
-    /**
-     * Destroys the fence. Any caller waiting on the fence will be
-     * signaled immediately.
-     */
-    ~Fence() {
-        if (mFence != EGL_NO_SYNC_KHR) {
-            eglDestroySyncKHR(mDisplay, mFence);
-        }
-    }
-
-    /**
-     * Blocks the calling thread until this fence is signaled, or until
-     * <timeout> nanoseconds have passed.
-     *
-     * Returns true if waiting for the fence was successful, false if
-     * a timeout or an error occurred.
-     */
-    bool wait(EGLTimeKHR timeout = kDefaultTimeout) {
-        EGLint waitStatus = eglClientWaitSyncKHR(mDisplay, mFence,
-                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, timeout);
-        if (waitStatus == EGL_FALSE) {
-            ALOGW("Failed to wait for the fence %#x", eglGetError());
-        }
-        return waitStatus == EGL_CONDITION_SATISFIED_KHR;
-    }
-
-private:
-    EGLDisplay mDisplay;
-    EGLSyncKHR mFence;
-
-}; // class Fence
-
-/**
- * An AutoFence creates a Fence instance and waits for the fence
- * to be signaled when the AutoFence is destroyed. This is useful
- * to automatically wait for a series of OpenGL commands to be
- * executed. For example:
- *
- * void drawAndWait() {
- *     glDrawElements();
- *     AutoFence fence;
- * }
- */
-class AutoFence {
-public:
-    AutoFence(EGLTimeKHR timeout = Fence::kDefaultTimeout): mTimeout(timeout) {
-    }
-
-    ~AutoFence() {
-        mFence.wait(mTimeout);
-    }
-
-private:
-    EGLTimeKHR mTimeout;
-    Fence mFence;
-
-}; // class AutoFence
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_FENCE_H
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
new file mode 100644
index 0000000..97dec88
--- /dev/null
+++ b/libs/hwui/FloatColor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FLOATCOLOR_H
+#define FLOATCOLOR_H
+
+#include "utils/Macros.h"
+
+#include <stdint.h>
+
+namespace android {
+namespace uirenderer {
+
+struct FloatColor {
+    void set(uint32_t color) {
+        a = ((color >> 24) & 0xff) / 255.0f;
+        r = a * ((color >> 16) & 0xff) / 255.0f;
+        g = a * ((color >>  8) & 0xff) / 255.0f;
+        b = a * ((color      ) & 0xff) / 255.0f;
+    }
+
+    bool isNotBlack() {
+        return a < 1.0f
+                || r > 0.0f
+                || g > 0.0f
+                || b > 0.0f;
+    }
+
+    float r;
+    float g;
+    float b;
+    float a;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FloatColor);
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FLOATCOLOR_H */
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 3910381..d1d2fcc 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -14,7 +14,18 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
+#include "FontRenderer.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "OpenGLRenderer.h"
+#include "PixelBuffer.h"
+#include "Rect.h"
+#include "renderstate/RenderState.h"
+#include "utils/Blur.h"
+#include "utils/MathUtils.h"
+#include "utils/Timing.h"
 
 #include <SkGlyph.h>
 #include <SkUtils.h>
@@ -27,17 +38,6 @@
 #include <RenderScript.h>
 #endif
 
-#include "utils/Blur.h"
-#include "utils/Timing.h"
-
-#include "Caches.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "OpenGLRenderer.h"
-#include "PixelBuffer.h"
-#include "Rect.h"
-
 namespace android {
 namespace uirenderer {
 
@@ -47,10 +47,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // TextSetupFunctor
 ///////////////////////////////////////////////////////////////////////////////
-status_t TextSetupFunctor::operator ()(int what, void* data) {
-    Data* typedData = reinterpret_cast<Data*>(data);
-    GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
-
+status_t TextSetupFunctor::setup(GLenum glyphFormat) {
     renderer->setupDraw();
     renderer->setupDrawTextGamma(paint);
     renderer->setupDrawDirtyRegionsDisabled();
@@ -97,47 +94,51 @@
 
 static bool sLogFontRendererCreate = true;
 
-FontRenderer::FontRenderer() :
-        mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
+FontRenderer::FontRenderer()
+        : mGammaTable(nullptr)
+        , mCurrentFont(nullptr)
+        , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
+        , mCurrentCacheTexture(nullptr)
+        , mUploadTexture(false)
+        , mFunctor(nullptr)
+        , mClip(nullptr)
+        , mBounds(nullptr)
+        , mDrawn(false)
+        , mInitialized(false)
+        , mLinearFiltering(false) {
 
     if (sLogFontRendererCreate) {
         INIT_LOGD("Creating FontRenderer");
     }
 
-    mGammaTable = NULL;
-    mInitialized = false;
-
-    mCurrentCacheTexture = NULL;
-
-    mLinearFiltering = false;
-
     mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
     mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
     mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
     mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
 
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
         mSmallCacheWidth = atoi(property);
     }
 
-    if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
         mSmallCacheHeight = atoi(property);
     }
 
-    if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
         mLargeCacheWidth = atoi(property);
     }
 
-    if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
         mLargeCacheHeight = atoi(property);
     }
 
     uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
-    mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
-    mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
-    mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
-    mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
+
+    mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
+    mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
+    mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
+    mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
 
     if (sLogFontRendererCreate) {
         INIT_LOGD("  Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
@@ -213,7 +214,7 @@
         }
     }
     // Could not fit glyph into current cache textures
-    return NULL;
+    return nullptr;
 }
 
 void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
@@ -224,7 +225,7 @@
     // so we can avoid doing extra work later on
     if (glyph.fWidth == 0 || glyph.fHeight == 0) {
         cachedGlyph->mIsValid = true;
-        cachedGlyph->mCacheTexture = NULL;
+        cachedGlyph->mCacheTexture = nullptr;
         return;
     }
 
@@ -232,7 +233,7 @@
 
     // choose an appropriate cache texture list for this glyph format
     SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
-    Vector<CacheTexture*>* cacheTextures = NULL;
+    Vector<CacheTexture*>* cacheTextures = nullptr;
     switch (format) {
         case SkMask::kA8_Format:
         case SkMask::kBW_Format:
@@ -287,7 +288,7 @@
     uint32_t cacheWidth = cacheTexture->getWidth();
 
     if (!cacheTexture->getPixelBuffer()) {
-        Caches::getInstance().activeTexture(0);
+        Caches::getInstance().textureState().activateTexture(0);
         // Large-glyph texture memory is allocated only as needed
         cacheTexture->allocateTexture();
     }
@@ -358,7 +359,7 @@
             break;
         }
         case SkMask::kBW_Format: {
-            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
+            uint32_t cacheX = 0, cacheY = 0;
             uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
                     - TEXTURE_BORDER_SIZE;
             static const uint8_t COLORS[2] = { 0, 255 };
@@ -397,10 +398,10 @@
 
 CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
         bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
+    CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
 
     if (allocate) {
-        Caches::getInstance().activeTexture(0);
+        Caches::getInstance().textureState().activateTexture(0);
         cacheTexture->allocateTexture();
         cacheTexture->allocateMesh();
     }
@@ -446,8 +447,8 @@
         if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
             if (cacheTexture->getTextureId() != lastTextureId) {
                 lastTextureId = cacheTexture->getTextureId();
-                caches.activeTexture(0);
-                caches.bindTexture(lastTextureId);
+                caches.textureState().activateTexture(0);
+                caches.textureState().bindTexture(lastTextureId);
             }
 
             if (cacheTexture->upload()) {
@@ -473,7 +474,7 @@
     checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
 
     // Unbind any PBO we might have used to update textures
-    caches.unbindPixelBuffer();
+    caches.pixelBufferState().unbind();
 
     // Reset to default unpack row length to avoid affecting texture
     // uploads in other parts of the renderer
@@ -485,44 +486,45 @@
 }
 
 void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
-    Caches& caches = Caches::getInstance();
+    if (!mFunctor) return;
+
+    Caches& caches = mFunctor->renderer->getCaches();
+    RenderState& renderState = mFunctor->renderer->renderState();
+
     bool first = true;
-    bool force = false;
+    bool forceRebind = false;
     for (uint32_t i = 0; i < cacheTextures.size(); i++) {
         CacheTexture* texture = cacheTextures[i];
         if (texture->canDraw()) {
             if (first) {
-                if (mFunctor) {
-                    TextSetupFunctor::Data functorData(texture->getFormat());
-                    (*mFunctor)(0, &functorData);
-                }
+                mFunctor->setup(texture->getFormat());
 
                 checkTextureUpdate();
-                caches.bindQuadIndicesBuffer();
+                renderState.meshState().bindQuadIndicesBuffer();
 
-                if (!mDrawn) {
-                    // If returns true, a VBO was bound and we must
-                    // rebind our vertex attrib pointers even if
-                    // they have the same values as the current pointers
-                    force = caches.unbindMeshBuffer();
-                }
+                // If returns true, a VBO was bound and we must
+                // rebind our vertex attrib pointers even if
+                // they have the same values as the current pointers
+                forceRebind = renderState.meshState().unbindMeshBuffer();
 
-                caches.activeTexture(0);
+                caches.textureState().activateTexture(0);
                 first = false;
+                mDrawn = true;
             }
 
-            caches.bindTexture(texture->getTextureId());
+            caches.textureState().bindTexture(texture->getTextureId());
             texture->setLinearFiltering(mLinearFiltering, false);
 
             TextureVertex* mesh = texture->mesh();
-            caches.bindPositionVertexPointer(force, &mesh[0].x);
-            caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
-            force = false;
+            MeshState& meshState = renderState.meshState();
+            meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
+            meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
 
             glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
                     GL_UNSIGNED_SHORT, texture->indices());
 
             texture->resetMesh();
+            forceRebind = false;
         }
     }
 }
@@ -530,8 +532,6 @@
 void FontRenderer::issueDrawCommand() {
     issueDrawCommand(mACacheTextures);
     issueDrawCommand(mRGBACacheTextures);
-
-    mDrawn = true;
 }
 
 void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
@@ -598,7 +598,7 @@
     DropShadow image;
     image.width = 0;
     image.height = 0;
-    image.image = NULL;
+    image.image = nullptr;
     image.penX = 0;
     image.penY = 0;
 
@@ -607,8 +607,8 @@
     }
 
     mDrawn = false;
-    mClip = NULL;
-    mBounds = NULL;
+    mClip = nullptr;
+    mBounds = nullptr;
 
     Rect bounds;
     mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
@@ -644,10 +644,10 @@
         // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
         // TODO: don't draw pure whitespace in the first place, and avoid needing this check
         mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
-                Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
+                Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
 
         // Unbind any PBO we might have used
-        Caches::getInstance().unbindPixelBuffer();
+        Caches::getInstance().pixelBufferState().unbind();
 
         blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
     }
@@ -661,7 +661,7 @@
     return image;
 }
 
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
     checkInit();
 
     mDrawn = false;
@@ -671,8 +671,8 @@
 }
 
 void FontRenderer::finishRender() {
-    mBounds = NULL;
-    mClip = NULL;
+    mBounds = nullptr;
+    mClip = nullptr;
 
     issueDrawCommand();
 }
@@ -689,7 +689,7 @@
 
 bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
-        const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
+        const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
@@ -707,7 +707,7 @@
 
 bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-        float hOffset, float vOffset, Rect* bounds, Functor* functor) {
+        float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
@@ -724,7 +724,7 @@
     mActiveFonts.remove(font->getDescription());
 
     if (mCurrentFont == font) {
-        mCurrentFont = NULL;
+        mCurrentFont = nullptr;
     }
 }
 
@@ -734,7 +734,7 @@
     if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
         uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
 
-        if (mRs == 0) {
+        if (mRs == nullptr) {
             mRs = new RSC::RS();
             // a null path is OK because there are no custom kernels used
             // hence nothing gets cached by RS
@@ -746,7 +746,7 @@
                 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
             }
         }
-        if (mRs != 0) {
+        if (mRs != nullptr) {
             RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
             RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
                     RS_ALLOCATION_MIPMAP_NONE,
@@ -770,15 +770,12 @@
     }
 #endif
 
-    float *gaussian = new float[2 * intRadius + 1];
-    Blur::generateGaussianWeights(gaussian, intRadius);
+    std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
+    Blur::generateGaussianWeights(gaussian.get(), intRadius);
 
-    uint8_t* scratch = new uint8_t[width * height];
-    Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
-    Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
-
-    delete[] gaussian;
-    delete[] scratch;
+    std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
+    Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
+    Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
 }
 
 static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 5c96c6b4..cb63684 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,7 +17,12 @@
 #ifndef ANDROID_HWUI_FONT_RENDERER_H
 #define ANDROID_HWUI_FONT_RENDERER_H
 
-#include <utils/Functor.h>
+#include "font/FontUtil.h"
+#include "font/CacheTexture.h"
+#include "font/CachedGlyphInfo.h"
+#include "font/Font.h"
+#include "utils/SortedList.h"
+
 #include <utils/LruCache.h>
 #include <utils/Vector.h>
 #include <utils/StrongPointer.h>
@@ -26,14 +31,6 @@
 
 #include <GLES2/gl2.h>
 
-#include "font/FontUtil.h"
-#include "font/CacheTexture.h"
-#include "font/CachedGlyphInfo.h"
-#include "font/Font.h"
-#include "utils/SortedList.h"
-#include "Matrix.h"
-#include "Properties.h"
-
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
 #include "RenderScript.h"
 namespace RSC {
@@ -49,26 +46,20 @@
 
 class OpenGLRenderer;
 
-///////////////////////////////////////////////////////////////////////////////
-// TextSetupFunctor
-///////////////////////////////////////////////////////////////////////////////
-class TextSetupFunctor: public Functor {
+class TextSetupFunctor {
 public:
-    struct Data {
-        Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
-        }
-
-        GLenum glyphFormat;
-    };
-
     TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
-            int alpha, SkXfermode::Mode mode, const SkPaint* paint): Functor(),
-            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
-            alpha(alpha), mode(mode), paint(paint) {
+            int alpha, SkXfermode::Mode mode, const SkPaint* paint)
+        : renderer(renderer)
+        , x(x)
+        , y(y)
+        , pureTranslate(pureTranslate)
+        , alpha(alpha)
+        , mode(mode)
+        , paint(paint) {
     }
-    ~TextSetupFunctor() { }
 
-    status_t operator ()(int what, void* data);
+    status_t setup(GLenum glyphFormat);
 
     OpenGLRenderer* renderer;
     float x;
@@ -79,10 +70,6 @@
     const SkPaint* paint;
 };
 
-///////////////////////////////////////////////////////////////////////////////
-// FontRenderer
-///////////////////////////////////////////////////////////////////////////////
-
 class FontRenderer {
 public:
     FontRenderer();
@@ -103,22 +90,14 @@
     // bounds is an out parameter
     bool renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, const float* positions,
-            Rect* bounds, Functor* functor, bool forceFinish = true);
+            Rect* bounds, TextSetupFunctor* functor, bool forceFinish = true);
 
     // bounds is an out parameter
     bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-            float hOffset, float vOffset, Rect* bounds, Functor* functor);
+            float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor);
 
     struct DropShadow {
-        DropShadow() { };
-
-        DropShadow(const DropShadow& dropShadow):
-            width(dropShadow.width), height(dropShadow.height),
-            image(dropShadow.image), penX(dropShadow.penX),
-            penY(dropShadow.penY) {
-        }
-
         uint32_t width;
         uint32_t height;
         uint8_t* image;
@@ -154,7 +133,7 @@
     void flushAllAndInvalidate();
 
     void checkInit();
-    void initRender(const Rect* clip, Rect* bounds, Functor* functor);
+    void initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor);
     void finishRender();
 
     void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
@@ -195,7 +174,7 @@
 
     bool mUploadTexture;
 
-    Functor* mFunctor;
+    TextSetupFunctor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
     bool mDrawn;
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
new file mode 100644
index 0000000..6da1fa8
--- /dev/null
+++ b/libs/hwui/FrameInfo.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "FrameInfo.h"
+
+#include <cstring>
+
+namespace android {
+namespace uirenderer {
+
+void FrameInfo::importUiThreadInfo(int64_t* info) {
+    memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
new file mode 100644
index 0000000..65daf03
--- /dev/null
+++ b/libs/hwui/FrameInfo.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef FRAMEINFO_H_
+#define FRAMEINFO_H_
+
+#include "utils/Macros.h"
+
+#include <cutils/compiler.h>
+#include <utils/Timers.h>
+
+#include <memory.h>
+
+namespace android {
+namespace uirenderer {
+
+#define UI_THREAD_FRAME_INFO_SIZE 9
+
+enum class FrameInfoIndex {
+    kFlags = 0,
+    kIntendedVsync,
+    kVsync,
+    kOldestInputEvent,
+    kNewestInputEvent,
+    kHandleInputStart,
+    kAnimationStart,
+    kPerformTraversalsStart,
+    kDrawStart,
+    // End of UI frame info
+
+    kSyncStart,
+    kIssueDrawCommandsStart,
+    kSwapBuffers,
+    kFrameCompleted,
+
+    // Must be the last value!
+    kNumIndexes
+};
+
+enum class FrameInfoFlags {
+    kWindowLayoutChanged = 1 << 0,
+    kRTAnimation = 1 << 1,
+    kSurfaceCanvas = 1 << 2,
+};
+MAKE_FLAGS_ENUM(FrameInfoFlags)
+
+class ANDROID_API UiFrameInfoBuilder {
+public:
+    UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
+        memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+    }
+
+    UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) {
+        set(FrameInfoIndex::kVsync) = vsyncTime;
+        set(FrameInfoIndex::kIntendedVsync) = intendedVsync;
+        return *this;
+    }
+
+    UiFrameInfoBuilder& addFlag(FrameInfoFlags flag) {
+        set(FrameInfoIndex::kFlags) |= static_cast<uint64_t>(flag);
+        return *this;
+    }
+
+private:
+    inline int64_t& set(FrameInfoIndex index) {
+        return mBuffer[static_cast<int>(index)];
+    }
+
+    int64_t* mBuffer;
+};
+
+class FrameInfo {
+public:
+    void importUiThreadInfo(int64_t* info);
+
+    void markSyncStart() {
+        set(FrameInfoIndex::kSyncStart) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markIssueDrawCommandsStart() {
+        set(FrameInfoIndex::kIssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markSwapBuffers() {
+        set(FrameInfoIndex::kSwapBuffers) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markFrameCompleted() {
+        set(FrameInfoIndex::kFrameCompleted) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    int64_t operator[](FrameInfoIndex index) const {
+        if (index == FrameInfoIndex::kNumIndexes) return 0;
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+    int64_t operator[](int index) const {
+        if (index < 0 || index >= static_cast<int>(FrameInfoIndex::kNumIndexes)) return 0;
+        return mFrameInfo[index];
+    }
+
+private:
+    inline int64_t& set(FrameInfoIndex index) {
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+    int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::kNumIndexes)];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FRAMEINFO_H_ */
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 06d2aad..0bcd83a 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
-
 #include "Debug.h"
 #include "GammaFontRenderer.h"
 #include "Properties.h"
@@ -61,7 +59,7 @@
 
     // Get the gamma
     mGamma = DEFAULT_TEXT_GAMMA;
-    if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
         INIT_LOGD("  Setting text gamma to %s", property);
         mGamma = atof(property);
     } else {
@@ -70,7 +68,7 @@
 
     // Get the black gamma threshold
     mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
-    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
         INIT_LOGD("  Setting text black gamma threshold to %s", property);
         mBlackThreshold = atoi(property);
     } else {
@@ -80,7 +78,7 @@
 
     // Get the white gamma threshold
     mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
-    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
         INIT_LOGD("  Setting text white gamma threshold to %s", property);
         mWhiteThreshold = atoi(property);
     } else {
@@ -96,15 +94,16 @@
 // Shader-based renderer
 ///////////////////////////////////////////////////////////////////////////////
 
-ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() {
+ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma)
+        : GammaFontRenderer() {
     INIT_LOGD("Creating shader gamma font renderer");
-    mRenderer = NULL;
+    mRenderer = nullptr;
     mMultiGamma = multiGamma;
 }
 
 void ShaderGammaFontRenderer::describe(ProgramDescription& description,
         const SkPaint* paint) const {
-    if (paint->getShader() == NULL) {
+    if (paint->getShader() == nullptr) {
         if (mMultiGamma) {
             const int l = luminance(paint);
 
@@ -123,9 +122,9 @@
 }
 
 void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
-        Program* program) const {
+        Program& program) const {
     if (description.hasGammaCorrection) {
-        glUniform1f(program->getUniform("gamma"), description.gamma);
+        glUniform1f(program.getUniform("gamma"), description.gamma);
     }
 }
 
@@ -139,7 +138,8 @@
 // Lookup-based renderer
 ///////////////////////////////////////////////////////////////////////////////
 
-LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
+LookupGammaFontRenderer::LookupGammaFontRenderer()
+        : GammaFontRenderer() {
     INIT_LOGD("Creating lookup gamma font renderer");
 
     // Compute the gamma tables
@@ -149,7 +149,7 @@
         mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f));
     }
 
-    mRenderer = NULL;
+    mRenderer = nullptr;
 }
 
 void LookupGammaFontRenderer::endPrecaching() {
@@ -162,7 +162,8 @@
 // Lookup-based renderer, using 3 different correction tables
 ///////////////////////////////////////////////////////////////////////////////
 
-Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() {
+Lookup3GammaFontRenderer::Lookup3GammaFontRenderer()
+        : GammaFontRenderer() {
     INIT_LOGD("Creating lookup3 gamma font renderer");
 
     // Compute the gamma tables
@@ -183,12 +184,6 @@
     memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
 }
 
-Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() {
-    for (int i = 0; i < kGammaCount; i++) {
-        delete mRenderers[i];
-    }
-}
-
 void Lookup3GammaFontRenderer::endPrecaching() {
     for (int i = 0; i < kGammaCount; i++) {
         if (mRenderers[i]) {
@@ -199,8 +194,7 @@
 
 void Lookup3GammaFontRenderer::clear() {
     for (int i = 0; i < kGammaCount; i++) {
-        delete mRenderers[i];
-        mRenderers[i] = NULL;
+        mRenderers[i].release();
     }
 }
 
@@ -221,8 +215,7 @@
 
     if (count <= 1 || min < 0) return;
 
-    delete mRenderers[min];
-    mRenderers[min] = NULL;
+    mRenderers[min].release();
 
     // Also eliminate the caches for large glyphs, as they consume significant memory
     for (int i = 0; i < kGammaCount; ++i) {
@@ -233,18 +226,16 @@
 }
 
 FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) {
-    FontRenderer* renderer = mRenderers[gamma];
-    if (!renderer) {
-        renderer = new FontRenderer();
-        mRenderers[gamma] = renderer;
-        renderer->setGammaTable(&mGammaTable[gamma * 256]);
+    if (!mRenderers[gamma]) {
+        mRenderers[gamma].reset(new FontRenderer());
+        mRenderers[gamma]->setGammaTable(&mGammaTable[gamma * 256]);
     }
     mRenderersUsageCount[gamma]++;
-    return renderer;
+    return mRenderers[gamma].get();
 }
 
 FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
-    if (paint->getShader() == NULL) {
+    if (paint->getShader() == nullptr) {
         const int l = luminance(paint);
 
         if (l <= mBlackThreshold) {
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 46cfd04..ca55bf1 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -38,7 +38,7 @@
     virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
 
     virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
-    virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
+    virtual void setupProgram(ProgramDescription& description, Program& program) const = 0;
 
     virtual void endPrecaching() = 0;
 
@@ -59,36 +59,36 @@
         delete mRenderer;
     }
 
-    void clear() {
+    void clear() override {
         delete mRenderer;
-        mRenderer = NULL;
+        mRenderer = nullptr;
     }
 
-    void flush() {
+    void flush() override {
         if (mRenderer) {
             mRenderer->flushLargeCaches();
         }
     }
 
-    FontRenderer& getFontRenderer(const SkPaint* paint) {
+    FontRenderer& getFontRenderer(const SkPaint* paint) override {
         if (!mRenderer) {
             mRenderer = new FontRenderer;
         }
         return *mRenderer;
     }
 
-    uint32_t getFontRendererCount() const {
+    uint32_t getFontRendererCount() const override {
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
         return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
-    void describe(ProgramDescription& description, const SkPaint* paint) const;
-    void setupProgram(ProgramDescription& description, Program* program) const;
+    void describe(ProgramDescription& description, const SkPaint* paint) const override;
+    void setupProgram(ProgramDescription& description, Program& program) const override;
 
-    void endPrecaching();
+    void endPrecaching() override;
 
 private:
     ShaderGammaFontRenderer(bool multiGamma);
@@ -105,18 +105,18 @@
         delete mRenderer;
     }
 
-    void clear() {
+    void clear() override {
         delete mRenderer;
-        mRenderer = NULL;
+        mRenderer = nullptr;
     }
 
-    void flush() {
+    void flush() override {
         if (mRenderer) {
             mRenderer->flushLargeCaches();
         }
     }
 
-    FontRenderer& getFontRenderer(const SkPaint* paint) {
+    FontRenderer& getFontRenderer(const SkPaint* paint) override {
         if (!mRenderer) {
             mRenderer = new FontRenderer;
             mRenderer->setGammaTable(&mGammaTable[0]);
@@ -124,21 +124,21 @@
         return *mRenderer;
     }
 
-    uint32_t getFontRendererCount() const {
+    uint32_t getFontRendererCount() const override {
         return 1;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
         return mRenderer ? mRenderer->getCacheSize(format) : 0;
     }
 
-    void describe(ProgramDescription& description, const SkPaint* paint) const {
+    void describe(ProgramDescription& description, const SkPaint* paint) const override {
     }
 
-    void setupProgram(ProgramDescription& description, Program* program) const {
+    void setupProgram(ProgramDescription& description, Program& program) const override {
     }
 
-    void endPrecaching();
+    void endPrecaching() override;
 
 private:
     LookupGammaFontRenderer();
@@ -151,33 +151,30 @@
 
 class Lookup3GammaFontRenderer: public GammaFontRenderer {
 public:
-    ~Lookup3GammaFontRenderer();
+    void clear() override;
+    void flush() override;
 
-    void clear();
-    void flush();
+    FontRenderer& getFontRenderer(const SkPaint* paint) override;
 
-    FontRenderer& getFontRenderer(const SkPaint* paint);
-
-    uint32_t getFontRendererCount() const {
+    uint32_t getFontRendererCount() const override {
         return kGammaCount;
     }
 
-    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+    uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
         if (fontRenderer >= kGammaCount) return 0;
 
-        FontRenderer* renderer = mRenderers[fontRenderer];
-        if (!renderer) return 0;
+        if (!mRenderers[fontRenderer]) return 0;
 
-        return renderer->getCacheSize(format);
+        return mRenderers[fontRenderer]->getCacheSize(format);
     }
 
-    void describe(ProgramDescription& description, const SkPaint* paint) const {
+    void describe(ProgramDescription& description, const SkPaint* paint) const override {
     }
 
-    void setupProgram(ProgramDescription& description, Program* program) const {
+    void setupProgram(ProgramDescription& description, Program& program) const override {
     }
 
-    void endPrecaching();
+    void endPrecaching() override;
 
 private:
     Lookup3GammaFontRenderer();
@@ -192,7 +189,7 @@
     FontRenderer* getRenderer(Gamma gamma);
 
     uint32_t mRenderersUsageCount[kGammaCount];
-    FontRenderer* mRenderers[kGammaCount];
+    std::unique_ptr<FontRenderer> mRenderers[kGammaCount];
 
     uint8_t mGammaTable[256 * kGammaCount];
 
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
new file mode 100644
index 0000000..2c6f6c1
--- /dev/null
+++ b/libs/hwui/Glop.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_GLOP_H
+#define ANDROID_HWUI_GLOP_H
+
+#include "FloatColor.h"
+#include "Matrix.h"
+#include "Program.h"
+#include "Rect.h"
+#include "SkiaShader.h"
+#include "utils/Macros.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+class RoundRectClipState;
+class Texture;
+
+/*
+ * Enumerates optional vertex attributes
+ *
+ * Position is always enabled by MeshState, these other attributes
+ * are enabled/disabled dynamically based on mesh content.
+ */
+enum class VertexAttribFlags {
+    kNone = 0,
+    kTextureCoord = 1 << 0,
+    kColor = 1 << 1,
+    kAlpha = 1 << 2,
+};
+MAKE_FLAGS_ENUM(VertexAttribFlags)
+
+/**
+ * Structure containing all data required to issue an OpenGL draw
+ *
+ * Includes all of the mesh, fill, and GL state required to perform
+ * the operation. Pieces of data are either directly copied into the
+ * structure, or stored as a pointer or GL object reference to data
+ * managed.
+ *
+ * Eventually, a Glop should be able to be drawn multiple times from
+ * a single construction, up until GL context destruction. Currently,
+ * vertex/index/Texture/RoundRectClipState pointers prevent this from
+ * being safe.
+ */
+// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
+struct Glop {
+    struct Mesh {
+        GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
+
+        // buffer object and void* are mutually exclusive.
+        // Only GL_UNSIGNED_SHORT supported.
+        struct Indices {
+            GLuint bufferObject;
+            const void* indices;
+        } indices;
+
+        // buffer object and void*s are mutually exclusive.
+        // TODO: enforce mutual exclusion with restricted setters and/or unions
+        struct Vertices {
+            GLuint bufferObject;
+            int attribFlags;
+            const void* position;
+            const void* texCoord;
+            const void* color;
+            GLsizei stride;
+        } vertices;
+
+        int elementCount;
+        TextureVertex mappedVertices[4];
+    } mesh;
+
+    struct Fill {
+        Program* program;
+
+        struct TextureData {
+            Texture* texture;
+            GLenum target;
+            GLenum filter;
+            GLenum clamp;
+            Matrix4* textureTransform;
+        } texture;
+
+        bool colorEnabled;
+        FloatColor color;
+
+        ProgramDescription::ColorFilterMode filterMode;
+        union Filter {
+            struct Matrix {
+                float matrix[16];
+                float vector[4];
+            } matrix;
+            FloatColor color;
+        } filter;
+
+        SkiaShaderData skiaShaderData;
+    } fill;
+
+    struct Transform {
+        Matrix4 ortho; // TODO: out of op, since this is static per FBO
+        Matrix4 modelView;
+        Matrix4 canvas;
+        bool fudgingOffset;
+    } transform;
+
+    const RoundRectClipState* roundRectClipState;
+
+    /**
+     * Blending to be used by this draw - both GL_NONE if blending is disabled.
+     *
+     * Defined by fill step, but can be force-enabled by presence of kAlpha_Attrib
+     */
+    struct Blend {
+        GLenum src;
+        GLenum dst;
+    } blend;
+
+    /**
+     * Bounds of the drawing command in layer space. Only mapped into layer
+     * space once GlopBuilder::build() is called.
+     */
+    Rect bounds;
+
+    /**
+     * Additional render state to enumerate:
+     * - scissor + (bits for whether each of LTRB needed?)
+     * - stencil mode (draw into, mask, count, etc)
+     */
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // ANDROID_HWUI_GLOP_H
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
new file mode 100644
index 0000000..0a46014
--- /dev/null
+++ b/libs/hwui/GlopBuilder.cpp
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "GlopBuilder.h"
+
+#include "Caches.h"
+#include "Glop.h"
+#include "Matrix.h"
+#include "Patch.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "SkiaShader.h"
+#include "Texture.h"
+#include "utils/PaintUtils.h"
+#include "VertexBuffer.h"
+
+#include <GLES2/gl2.h>
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+#define TRIGGER_STAGE(stageFlag) \
+    LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
+    mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
+
+#define REQUIRE_STAGES(requiredFlags) \
+    LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
+            "not prepared for current stage")
+
+static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
+    quadVertex[0] = {0, 0, uvs.left, uvs.top};
+    quadVertex[1] = {1, 0, uvs.right, uvs.top};
+    quadVertex[2] = {0, 1, uvs.left, uvs.bottom};
+    quadVertex[3] = {1, 1, uvs.right, uvs.bottom};
+}
+
+GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
+        : mRenderState(renderState)
+        , mCaches(caches)
+        , mShader(nullptr)
+        , mOutGlop(outGlop) {
+    mStageFlags = kInitialStage;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Mesh
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setMeshUnitQuad() {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            mRenderState.meshState().getUnitQuadVBO(),
+            static_cast<int>(VertexAttribFlags::kNone),
+            nullptr, nullptr, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = 4;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
+    if (uvMapper) {
+        // can't use unit quad VBO, so build UV vertices manually
+        return setMeshTexturedUvQuad(uvMapper, Rect(0, 0, 1, 1));
+    }
+
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            mRenderState.meshState().getUnitQuadVBO(),
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            nullptr, (const void*) kMeshTextureOffset, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = 4;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect uvs) {
+    TRIGGER_STAGE(kMeshStage);
+
+    if (CC_UNLIKELY(uvMapper)) {
+        uvMapper->map(uvs);
+    }
+    setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
+
+    const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            &textureVertex[0].x, &textureVertex[0].u, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = 4;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<int>(VertexAttribFlags::kNone),
+            vertexData, nullptr, nullptr,
+            kVertexStride };
+    mOutGlop->mesh.elementCount = 6 * quadCount;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            &vertexData[0].x, &vertexData[0].u, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = elementCount;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int elementCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            &vertexData[0].x, &vertexData[0].u, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = elementCount;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor,
+            &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
+            kColorTextureVertexStride };
+    mOutGlop->mesh.elementCount = elementCount;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
+    TRIGGER_STAGE(kMeshStage);
+
+    const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
+
+    bool alphaVertex = flags & VertexBuffer::kAlpha;
+    bool indices = flags & VertexBuffer::kIndices;
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<int>(alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone),
+            vertexBuffer.getBuffer(), nullptr, nullptr,
+            alphaVertex ? kAlphaVertexStride : kVertexStride };
+    mOutGlop->mesh.elementCount = indices
+                ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+
+    mDescription.useShadowAlphaInterp = shadowInterp;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+    mOutGlop->mesh.vertices = {
+            mCaches.patchCache.getMeshBuffer(),
+            static_cast<int>(VertexAttribFlags::kTextureCoord),
+            (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = patch.indexCount;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Fill
+////////////////////////////////////////////////////////////////////////////////
+
+void GlopBuilder::setFill(int color, float alphaScale,
+        SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
+        const SkShader* shader, const SkColorFilter* colorFilter) {
+    if (mode != SkXfermode::kClear_Mode) {
+        float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
+        if (!shader) {
+            float colorScale = alpha / 255.0f;
+            mOutGlop->fill.color = {
+                    colorScale * SkColorGetR(color),
+                    colorScale * SkColorGetG(color),
+                    colorScale * SkColorGetB(color),
+                    alpha
+            };
+        } else {
+            mOutGlop->fill.color = { 1, 1, 1, alpha };
+        }
+    } else {
+        mOutGlop->fill.color = { 0, 0, 0, 1 };
+    }
+
+    mOutGlop->blend = { GL_ZERO, GL_ZERO };
+    if (mOutGlop->fill.color.a < 1.0f
+            || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
+            || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
+            || mOutGlop->roundRectClipState
+            || PaintUtils::isBlendedShader(shader)
+            || PaintUtils::isBlendedColorFilter(colorFilter)
+            || mode != SkXfermode::kSrcOver_Mode) {
+        if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
+            Blend::getFactors(mode, modeUsage,
+                    &mOutGlop->blend.src, &mOutGlop->blend.dst);
+        } else {
+            // These blend modes are not supported by OpenGL directly and have
+            // to be implemented using shaders. Since the shader will perform
+            // the blending, don't enable GL blending off here
+            // If the blend mode cannot be implemented using shaders, fall
+            // back to the default SrcOver blend mode instead
+            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
+                mDescription.framebufferMode = mode;
+                mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap);
+                // blending in shader, don't enable
+            } else {
+                // unsupported
+                Blend::getFactors(SkXfermode::kSrcOver_Mode, modeUsage,
+                        &mOutGlop->blend.src, &mOutGlop->blend.dst);
+            }
+        }
+    }
+    mShader = shader; // shader resolved in ::build()
+
+    if (colorFilter) {
+        SkColor color;
+        SkXfermode::Mode mode;
+        SkScalar srcColorMatrix[20];
+        if (colorFilter->asColorMode(&color, &mode)) {
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+            mDescription.colorMode = mode;
+
+            const float alpha = SkColorGetA(color) / 255.0f;
+            float colorScale = alpha / 255.0f;
+            mOutGlop->fill.filter.color = {
+                    colorScale * SkColorGetR(color),
+                    colorScale * SkColorGetG(color),
+                    colorScale * SkColorGetB(color),
+                    alpha,
+            };
+        } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+
+            float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
+            memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+            memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+            memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+            memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+            // Skia uses the range [0..255] for the addition vector, but we need
+            // the [0..1] range to apply the vector in GLSL
+            float* colorVector = mOutGlop->fill.filter.matrix.vector;
+            colorVector[0] = srcColorMatrix[4] / 255.0f;
+            colorVector[1] = srcColorMatrix[9] / 255.0f;
+            colorVector[2] = srcColorMatrix[14] / 255.0f;
+            colorVector[3] = srcColorMatrix[19] / 255.0f;
+        } else {
+            LOG_ALWAYS_FATAL("unsupported ColorFilter");
+        }
+    } else {
+        mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+    }
+}
+
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, int textureFillFlags,
+        const SkPaint* paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    GLenum filter = (textureFillFlags & TextureFillFlags::kForceFilter)
+            ? GL_LINEAR : PaintUtils::getFilter(paint);
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, filter, GL_CLAMP_TO_EDGE, nullptr };
+
+    if (paint) {
+        int color = paint->getColor();
+        SkShader* shader = paint->getShader();
+
+        if (!(textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture)) {
+            // Texture defines color, so disable shaders, and reset all non-alpha color channels
+            color |= 0x00FFFFFF;
+            shader = nullptr;
+        }
+        setFill(color, alphaScale,
+                PaintUtils::getXfermode(paint->getXfermode()), Blend::ModeOrderSwap::NoSwap,
+                shader, paint->getColorFilter());
+    } else {
+        mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+
+        if (alphaScale < 1.0f
+                || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
+                || texture.blend
+                || mOutGlop->roundRectClipState) {
+            Blend::getFactors(SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
+                    &mOutGlop->blend.src, &mOutGlop->blend.dst);
+        } else {
+            mOutGlop->blend = { GL_ZERO, GL_ZERO };
+        }
+    }
+
+    if (textureFillFlags & TextureFillFlags::kIsAlphaMaskTexture) {
+        mDescription.modulate = mOutGlop->fill.color.isNotBlack();
+        mDescription.hasAlpha8Texture = true;
+    } else {
+        mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    }
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
+            paint.getShader(), paint.getColorFilter());
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
+        const SkPaint& paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    //specify invalid filter/clamp, since these are always static for PathTextures
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+
+    setFill(paint.getColor(), alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
+            paint.getShader(), paint.getColorFilter());
+
+    mDescription.hasAlpha8Texture = true;
+    mDescription.modulate = mOutGlop->fill.color.isNotBlack();
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
+        const SkPaint& paint, float alphaScale) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    //specify invalid filter/clamp, since these are always static for ShadowTextures
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+
+    const int ALPHA_BITMASK = SK_ColorBLACK;
+    const int COLOR_BITMASK = ~ALPHA_BITMASK;
+    if ((shadowColor & ALPHA_BITMASK) == ALPHA_BITMASK) {
+        // shadow color is fully opaque: override its alpha with that of paint
+        shadowColor &= paint.getColor() | COLOR_BITMASK;
+    }
+
+    setFill(shadowColor, alphaScale,
+            PaintUtils::getXfermode(paint.getXfermode()), Blend::ModeOrderSwap::NoSwap,
+            paint.getShader(), paint.getColorFilter());
+
+    mDescription.hasAlpha8Texture = true;
+    mDescription.modulate = mOutGlop->fill.color.isNotBlack();
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillBlack() {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillClear() {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+    setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap,
+            nullptr, nullptr);
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
+        float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
+    mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
+
+    setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { &(layer.getTexture()),
+            layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
+    mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
+
+    setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
+            nullptr, layer.getColorFilter());
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    mDescription.hasTextureTransform = true;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Transform
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
+        const Matrix4& transform, bool fudgingOffset) {
+    TRIGGER_STAGE(kTransformStage);
+
+    mOutGlop->transform.ortho.load(ortho);
+    mOutGlop->transform.canvas.load(transform);
+    mOutGlop->transform.fudgingOffset = fudgingOffset;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ModelView
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+    TRIGGER_STAGE(kModelViewStage);
+
+    mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+    mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+    mOutGlop->bounds = destination;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) {
+    TRIGGER_STAGE(kModelViewStage);
+    REQUIRE_STAGES(kTransformStage | kFillStage);
+
+    float left = destination.left;
+    float top = destination.top;
+
+    const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+    if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+        // snap by adjusting the model view matrix
+        const float translateX = canvasTransform.getTranslateX();
+        const float translateY = canvasTransform.getTranslateY();
+
+        left = (int) floorf(left + translateX + 0.5f) - translateX;
+        top = (int) floorf(top + translateY + 0.5f) - translateY;
+        mOutGlop->fill.texture.filter = GL_NEAREST;
+    }
+
+    mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
+    mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+    mOutGlop->bounds = destination;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+    TRIGGER_STAGE(kModelViewStage);
+
+    mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+    mOutGlop->bounds = source;
+    mOutGlop->bounds.translate(offsetX, offsetY);
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
+    TRIGGER_STAGE(kModelViewStage);
+    REQUIRE_STAGES(kTransformStage | kFillStage);
+
+    const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+    if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+        // snap by adjusting the model view matrix
+        const float translateX = canvasTransform.getTranslateX();
+        const float translateY = canvasTransform.getTranslateY();
+
+        offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
+        offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
+        mOutGlop->fill.texture.filter = GL_NEAREST;
+    }
+
+    mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+    mOutGlop->bounds = source;
+    mOutGlop->bounds.translate(offsetX, offsetY);
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RoundRectClip
+////////////////////////////////////////////////////////////////////////////////
+
+GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
+    TRIGGER_STAGE(kRoundRectClipStage);
+
+    mOutGlop->roundRectClipState = roundRectClipState;
+    mDescription.hasRoundRectClip = roundRectClipState != nullptr;
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Build
+////////////////////////////////////////////////////////////////////////////////
+
+void verify(const ProgramDescription& description, const Glop& glop) {
+    if (glop.fill.texture.texture != nullptr) {
+        LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
+                        || (!description.hasTexture && !description.hasExternalTexture)
+                        || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) == 0)),
+                "Texture %p, hT%d, hET %d, attribFlags %x",
+                glop.fill.texture.texture,
+                description.hasTexture, description.hasExternalTexture,
+                glop.mesh.vertices.attribFlags);
+    } else {
+        LOG_ALWAYS_FATAL_IF((description.hasTexture
+                        || description.hasExternalTexture
+                        || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) != 0)),
+                "No texture, hT%d, hET %d, attribFlags %x",
+                description.hasTexture, description.hasExternalTexture,
+                glop.mesh.vertices.attribFlags);
+    }
+
+    if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::kAlpha)
+            && glop.mesh.vertices.bufferObject) {
+        LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
+    }
+
+    if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) {
+        LOG_ALWAYS_FATAL("Texture transform incorrectly specified");
+    }
+}
+
+void GlopBuilder::build() {
+    REQUIRE_STAGES(kAllStages);
+    if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
+        if (mOutGlop->fill.texture.target == GL_TEXTURE_2D) {
+            mDescription.hasTexture = true;
+        } else {
+            mDescription.hasExternalTexture = true;
+        }
+
+    }
+    mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor;
+    mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha;
+
+    // serialize shader info into ShaderData
+    GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
+    SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView,
+            &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
+
+    // duplicates ProgramCache's definition of color uniform presence
+    const bool singleColor = !mDescription.hasTexture
+            && !mDescription.hasExternalTexture
+            && !mDescription.hasGradient
+            && !mDescription.hasBitmap;
+    mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
+
+    verify(mDescription, *mOutGlop);
+
+    // Final step: populate program and map bounds into render target space
+    mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+    mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
new file mode 100644
index 0000000..b335a2c
--- /dev/null
+++ b/libs/hwui/GlopBuilder.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_GLOPBUILDER_H
+#define RENDERSTATE_GLOPBUILDER_H
+
+#include "OpenGLRenderer.h"
+#include "Program.h"
+#include "renderstate/Blend.h"
+#include "utils/Macros.h"
+
+class SkPaint;
+class SkShader;
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+class Matrix4;
+class RenderState;
+class Texture;
+class VertexBuffer;
+struct Glop;
+
+enum class TextureFillFlags {
+    kNone = 0,
+    kIsAlphaMaskTexture = 1 << 0,
+    kForceFilter = 1 << 1,
+};
+MAKE_FLAGS_ENUM(TextureFillFlags);
+
+class GlopBuilder {
+    PREVENT_COPY_AND_ASSIGN(GlopBuilder);
+public:
+    GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
+
+    GlopBuilder& setMeshUnitQuad();
+    GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper);
+    GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs);
+    GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
+    GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount);
+    GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: use indexed quads
+    GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads
+    GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
+    GlopBuilder& setMeshPatchQuads(const Patch& patch);
+
+    GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale);
+    GlopBuilder& setFillTexturePaint(Texture& texture, int textureFillFlags,
+            const SkPaint* paint, float alphaScale);
+    GlopBuilder& setFillPathTexturePaint(PathTexture& texture,
+            const SkPaint& paint, float alphaScale);
+    GlopBuilder& setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
+            const SkPaint& paint, float alphaScale);
+    GlopBuilder& setFillBlack();
+    GlopBuilder& setFillClear();
+    GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
+            float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage);
+    GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
+
+    GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
+
+    GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
+    GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
+    GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect& destination) {
+        if (snap) {
+            return setModelViewMapUnitToRectSnap(destination);
+        } else {
+            return setModelViewMapUnitToRect(destination);
+        }
+    }
+    GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
+    GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
+    GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap,
+            float offsetX, float offsetY, const Rect& source) {
+        if (snap) {
+            return setModelViewOffsetRectSnap(offsetX, offsetY, source);
+        } else {
+            return setModelViewOffsetRect(offsetX, offsetY, source);
+        }
+    }
+
+    GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
+
+    void build();
+private:
+    void setFill(int color, float alphaScale,
+            SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
+            const SkShader* shader, const SkColorFilter* colorFilter);
+
+    enum StageFlags {
+        kInitialStage = 0,
+        kMeshStage = 1 << 0,
+        kTransformStage = 1 << 1,
+        kModelViewStage = 1 << 2,
+        kFillStage = 1 << 3,
+        kRoundRectClipStage = 1 << 4,
+        kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
+    } mStageFlags;
+
+    ProgramDescription mDescription;
+    RenderState& mRenderState;
+    Caches& mCaches;
+    const SkShader* mShader;
+    Glop* mOutGlop;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_GLOPBUILDER_H
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index ffd1e8c..ea93e7f 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -52,21 +52,24 @@
     int deltaInt = int(lhs.count) - int(rhs.count);
     if (deltaInt != 0) return deltaInt;
 
-    deltaInt = memcmp(lhs.colors, rhs.colors, lhs.count * sizeof(uint32_t));
+    deltaInt = memcmp(lhs.colors.get(), rhs.colors.get(), lhs.count * sizeof(uint32_t));
     if (deltaInt != 0) return deltaInt;
 
-    return memcmp(lhs.positions, rhs.positions, lhs.count * sizeof(float));
+    return memcmp(lhs.positions.get(), rhs.positions.get(), lhs.count * sizeof(float));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-GradientCache::GradientCache():
-        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
+GradientCache::GradientCache(Extensions& extensions)
+        : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
+        , mSize(0)
+        , mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE))
+        , mUseFloatTexture(extensions.hasFloatTextures())
+        , mHasNpot(extensions.hasNPot()){
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting gradient cache size to %sMB", property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -76,16 +79,6 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 
     mCache.setOnEntryRemovedListener(this);
-
-    const Extensions& extensions = Extensions::getInstance();
-    mUseFloatTexture = extensions.hasFloatTextures();
-    mHasNpot = extensions.hasNPot();
-}
-
-GradientCache::GradientCache(uint32_t maxByteSize):
-        mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(maxByteSize) {
-    mCache.setOnEntryRemovedListener(this);
 }
 
 GradientCache::~GradientCache() {
@@ -173,7 +166,7 @@
     GradientInfo info;
     getGradientInfo(colors, count, info);
 
-    Texture* texture = new Texture();
+    Texture* texture = new Texture(Caches::getInstance());
     texture->width = info.width;
     texture->height = 2;
     texture->blend = info.hasAlpha;
@@ -285,7 +278,7 @@
     memcpy(pixels + rowBytes, pixels, rowBytes);
 
     glGenTextures(1, &texture->id);
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
     if (mUseFloatTexture) {
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 6a783b1..08319ea 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_GRADIENT_CACHE_H
 #define ANDROID_HWUI_GRADIENT_CACHE_H
 
+#include <memory>
+
 #include <GLES3/gl3.h>
 
 #include <SkShader.h>
@@ -25,16 +27,16 @@
 #include <utils/Mutex.h>
 #include <utils/Vector.h>
 
-#include "Texture.h"
-
 namespace android {
 namespace uirenderer {
 
+class Texture;
+
 struct GradientCacheEntry {
     GradientCacheEntry() {
         count = 0;
-        colors = NULL;
-        positions = NULL;
+        colors = nullptr;
+        positions = nullptr;
     }
 
     GradientCacheEntry(uint32_t* colors, float* positions, uint32_t count) {
@@ -42,20 +44,12 @@
     }
 
     GradientCacheEntry(const GradientCacheEntry& entry) {
-        copy(entry.colors, entry.positions, entry.count);
-    }
-
-    ~GradientCacheEntry() {
-        delete[] colors;
-        delete[] positions;
+        copy(entry.colors.get(), entry.positions.get(), entry.count);
     }
 
     GradientCacheEntry& operator=(const GradientCacheEntry& entry) {
         if (this != &entry) {
-            delete[] colors;
-            delete[] positions;
-
-            copy(entry.colors, entry.positions, entry.count);
+            copy(entry.colors.get(), entry.positions.get(), entry.count);
         }
 
         return *this;
@@ -73,18 +67,18 @@
         return compare(*this, other) != 0;
     }
 
-    uint32_t* colors;
-    float* positions;
+    std::unique_ptr<uint32_t[]> colors;
+    std::unique_ptr<float[]> positions;
     uint32_t count;
 
 private:
     void copy(uint32_t* colors, float* positions, uint32_t count) {
         this->count = count;
-        this->colors = new uint32_t[count];
-        this->positions = new float[count];
+        this->colors.reset(new uint32_t[count]);
+        this->positions.reset(new float[count]);
 
-        memcpy(this->colors, colors, count * sizeof(uint32_t));
-        memcpy(this->positions, positions, count * sizeof(float));
+        memcpy(this->colors.get(), colors, count * sizeof(uint32_t));
+        memcpy(this->positions.get(), positions, count * sizeof(float));
     }
 
 }; // GradientCacheEntry
@@ -110,15 +104,14 @@
  */
 class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
 public:
-    GradientCache();
-    GradientCache(uint32_t maxByteSize);
+    GradientCache(Extensions& extensions);
     ~GradientCache();
 
     /**
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(GradientCacheEntry& shader, Texture*& texture);
+    void operator()(GradientCacheEntry& shader, Texture*& texture) override;
 
     /**
      * Returns the texture associated with the specified shader.
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index edf3930..a31c546 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -39,7 +39,7 @@
     } else {
         // Create a 2D texture to sample from the EGLImage
         glGenTextures(1, &mTexture);
-        Caches::getInstance().bindTexture(mTexture);
+        Caches::getInstance().textureState().bindTexture(mTexture);
         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
 
         GLenum status = GL_NO_ERROR;
@@ -54,7 +54,7 @@
         eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
         mImage = EGL_NO_IMAGE_KHR;
 
-        Caches::getInstance().deleteTexture(mTexture);
+        Caches::getInstance().textureState().deleteTexture(mTexture);
         mTexture = 0;
     }
 }
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index ff8ff73..e1b0fc3 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Interpolator"
-
 #include "Interpolator.h"
 
 #include <cmath>
@@ -90,14 +88,12 @@
     return t * t * ((mTension + 1) * t + mTension) + 1.0f;
 }
 
-LUTInterpolator::LUTInterpolator(float* values, size_t size) {
-    mValues = values;
-    mSize = size;
+LUTInterpolator::LUTInterpolator(float* values, size_t size)
+    : mValues(values)
+    , mSize(size) {
 }
 
 LUTInterpolator::~LUTInterpolator() {
-    delete mValues;
-    mValues = 0;
 }
 
 float LUTInterpolator::interpolate(float input) {
@@ -114,7 +110,7 @@
 
     LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
             " i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
-            i1, i2, input, lutpos, mSize, mValues, ipart, weight);
+            i1, i2, input, lutpos, mSize, mValues.get(), ipart, weight);
 
     float v1 = mValues[i1];
     float v2 = mValues[i2];
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index dfa0a85..66ce119 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -17,6 +17,7 @@
 #define INTERPOLATOR_H
 
 #include <stddef.h>
+#include <memory>
 
 #include <cutils/compiler.h>
 
@@ -37,13 +38,13 @@
 
 class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator {
 public:
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 };
 
 class ANDROID_API AccelerateInterpolator : public Interpolator {
 public:
     AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mFactor;
     const float mDoubleFactor;
@@ -52,7 +53,7 @@
 class ANDROID_API AnticipateInterpolator : public Interpolator {
 public:
     AnticipateInterpolator(float tension) : mTension(tension) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mTension;
 };
@@ -60,20 +61,20 @@
 class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
 public:
     AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mTension;
 };
 
 class ANDROID_API BounceInterpolator : public Interpolator {
 public:
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 };
 
 class ANDROID_API CycleInterpolator : public Interpolator {
 public:
     CycleInterpolator(float cycles) : mCycles(cycles) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mCycles;
 };
@@ -81,20 +82,20 @@
 class ANDROID_API DecelerateInterpolator : public Interpolator {
 public:
     DecelerateInterpolator(float factor) : mFactor(factor) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mFactor;
 };
 
 class ANDROID_API LinearInterpolator : public Interpolator {
 public:
-    virtual float interpolate(float input) { return input; }
+    virtual float interpolate(float input) override { return input; }
 };
 
 class ANDROID_API OvershootInterpolator : public Interpolator {
 public:
     OvershootInterpolator(float tension) : mTension(tension) {}
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 private:
     const float mTension;
 };
@@ -104,10 +105,10 @@
     LUTInterpolator(float* values, size_t size);
     ~LUTInterpolator();
 
-    virtual float interpolate(float input);
+    virtual float interpolate(float input) override;
 
 private:
-    float* mValues;
+    std::unique_ptr<float[]> mValues;
     size_t mSize;
 };
 
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
new file mode 100644
index 0000000..7df61f27
--- /dev/null
+++ b/libs/hwui/JankTracker.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "JankTracker.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <inttypes.h>
+
+namespace android {
+namespace uirenderer {
+
+static const char* JANK_TYPE_NAMES[] = {
+        "Missed Vsync",
+        "High input latency",
+        "Slow UI thread",
+        "Slow bitmap uploads",
+        "Slow draw",
+};
+
+struct Comparison {
+    FrameInfoIndex start;
+    FrameInfoIndex end;
+};
+
+static const Comparison COMPARISONS[] = {
+        {FrameInfoIndex::kIntendedVsync, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kOldestInputEvent, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kVsync, FrameInfoIndex::kSyncStart},
+        {FrameInfoIndex::kSyncStart, FrameInfoIndex::kIssueDrawCommandsStart},
+        {FrameInfoIndex::kIssueDrawCommandsStart, FrameInfoIndex::kFrameCompleted},
+};
+
+// If the event exceeds 10 seconds throw it away, this isn't a jank event
+// it's an ANR and will be handled as such
+static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
+
+/*
+ * Frames that are exempt from jank metrics.
+ * First-draw frames, for example, are expected to
+ * be slow, this is hidden from the user with window animations and
+ * other tricks
+ *
+ * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * for now
+ *
+ * TODO: kSurfaceCanvas can negatively impact other drawing by using up
+ * time on the RenderThread, figure out how to attribute that as a jank-causer
+ */
+static const int64_t EXEMPT_FRAMES_FLAGS
+        = FrameInfoFlags::kWindowLayoutChanged
+        | FrameInfoFlags::kSurfaceCanvas;
+
+JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
+    reset();
+    setFrameInterval(frameIntervalNanos);
+}
+
+void JankTracker::setFrameInterval(nsecs_t frameInterval) {
+    mFrameInterval = frameInterval;
+    mThresholds[kMissedVsync] = 1;
+    /*
+     * Due to interpolation and sample rate differences between the touch
+     * panel and the display (example, 85hz touch panel driving a 60hz display)
+     * we call high latency 1.5 * frameinterval
+     *
+     * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel
+     * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms
+     * Thus this must always be larger than frameInterval, or it will fail
+     */
+    mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval);
+
+    // Note that these do not add up to 1. This is intentional. It's to deal
+    // with variance in values, and should be sort of an upper-bound on what
+    // is reasonable to expect.
+    mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
+    mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
+    mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
+
+}
+
+void JankTracker::addFrame(const FrameInfo& frame) {
+    mTotalFrameCount++;
+    // Fast-path for jank-free frames
+    int64_t totalDuration =
+            frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
+    uint32_t framebucket = std::min(
+            static_cast<typeof mFrameCounts.size()>(ns2ms(totalDuration)),
+            mFrameCounts.size());
+    // Keep the fast path as fast as possible.
+    if (CC_LIKELY(totalDuration < mFrameInterval)) {
+        mFrameCounts[framebucket]++;
+        return;
+    }
+
+    if (frame[FrameInfoIndex::kFlags] & EXEMPT_FRAMES_FLAGS) {
+        return;
+    }
+
+    mFrameCounts[framebucket]++;
+    mJankFrameCount++;
+
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        int64_t delta = frame[COMPARISONS[i].end] - frame[COMPARISONS[i].start];
+        if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
+            mBuckets[i].count++;
+        }
+    }
+}
+
+void JankTracker::dump(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\nFrame stats:");
+    fprintf(file, "\n  Total frames rendered: %u", mTotalFrameCount);
+    fprintf(file, "\n  Janky frames: %u (%.2f%%)", mJankFrameCount,
+            (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+    fprintf(file, "\n  90th percentile: %ums", findPercentile(90));
+    fprintf(file, "\n  95th percentile: %ums", findPercentile(95));
+    fprintf(file, "\n  99th percentile: %ums", findPercentile(99));
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        fprintf(file, "\n   Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
+    }
+    fprintf(file, "\n");
+    fflush(file);
+}
+
+void JankTracker::reset() {
+    mBuckets.fill({0});
+    mFrameCounts.fill(0);
+    mTotalFrameCount = 0;
+    mJankFrameCount = 0;
+}
+
+uint32_t JankTracker::findPercentile(int percentile) {
+    int pos = percentile * mTotalFrameCount / 100;
+    int remaining = mTotalFrameCount - pos;
+    for (int i = mFrameCounts.size() - 1; i >= 0; i--) {
+        remaining -= mFrameCounts[i];
+        if (remaining <= 0) {
+            return i;
+        }
+    }
+    return 0;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
new file mode 100644
index 0000000..ae339ec
--- /dev/null
+++ b/libs/hwui/JankTracker.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef JANKTRACKER_H_
+#define JANKTRACKER_H_
+
+#include "FrameInfo.h"
+#include "renderthread/TimeLord.h"
+#include "utils/RingBuffer.h"
+
+#include <array>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+enum JankType {
+    kMissedVsync = 0,
+    kHighInputLatency,
+    kSlowUI,
+    kSlowSync,
+    kSlowRT,
+
+    // must be last
+    NUM_BUCKETS,
+};
+
+struct JankBucket {
+    // Number of frames that hit this bucket
+    uint32_t count;
+};
+
+// TODO: Replace DrawProfiler with this
+class JankTracker {
+public:
+    JankTracker(nsecs_t frameIntervalNanos);
+
+    void setFrameInterval(nsecs_t frameIntervalNanos);
+
+    void addFrame(const FrameInfo& frame);
+
+    void dump(int fd);
+    void reset();
+
+private:
+    uint32_t findPercentile(int p);
+
+    std::array<JankBucket, NUM_BUCKETS> mBuckets;
+    std::array<int64_t, NUM_BUCKETS> mThresholds;
+    std::array<uint32_t, 128> mFrameCounts;
+
+    int64_t mFrameInterval;
+    uint32_t mTotalFrameCount;
+    uint32_t mJankFrameCount;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* JANKTRACKER_H_ */
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 05259ff..458f35b 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -16,17 +16,18 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <utils/Log.h>
+#include "Layer.h"
 
 #include "Caches.h"
 #include "DeferredDisplayList.h"
-#include "Layer.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
 #include "RenderNode.h"
-#include "RenderState.h"
+#include "renderstate/RenderState.h"
 #include "utils/TraceUtils.h"
 
+#include <utils/Log.h>
+
 #define ATRACE_LAYER_WORK(label) \
     ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
             label, \
@@ -36,7 +37,7 @@
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
+Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
         : state(kState_Uncached)
         , caches(Caches::getInstance())
         , renderState(renderState)
@@ -44,27 +45,10 @@
         , type(layerType) {
     // TODO: This is a violation of Android's typical ref counting, but it
     // preserves the old inc/dec ref locations. This should be changed...
-    incStrong(0);
-    mesh = NULL;
-    meshElementCount = 0;
-    cacheable = true;
-    dirty = false;
+    incStrong(nullptr);
     renderTarget = GL_TEXTURE_2D;
     texture.width = layerWidth;
     texture.height = layerHeight;
-    colorFilter = NULL;
-    deferredUpdateScheduled = false;
-    renderer = NULL;
-    renderNode = NULL;
-    fbo = 0;
-    stencil = NULL;
-    debugDrawUpdate = false;
-    hasDrawnSinceUpdate = false;
-    forceFilter = false;
-    deferredList = NULL;
-    convexMask = NULL;
-    rendererLightPosDirty = true;
-    wasBuildLayered = false;
     renderState.registerLayer(this);
 }
 
@@ -79,8 +63,6 @@
     }
 
     delete[] mesh;
-    delete deferredList;
-    delete renderer;
 }
 
 void Layer::onGlContextLost() {
@@ -98,7 +80,7 @@
 
 void Layer::requireRenderer() {
     if (!renderer) {
-        renderer = new LayerRenderer(renderState, this);
+        renderer.reset(new LayerRenderer(renderState, this));
         renderer->initProperties();
     }
 }
@@ -137,7 +119,7 @@
     setSize(desiredWidth, desiredHeight);
 
     if (fbo) {
-        caches.activeTexture(0);
+        caches.textureState().activateTexture(0);
         bindTexture();
         allocateTexture();
 
@@ -168,7 +150,7 @@
         renderState.bindFramebuffer(previousFbo);
 
         caches.renderBufferCache.put(stencil);
-        stencil = NULL;
+        stencil = nullptr;
     }
 
     if (fbo) {
@@ -189,7 +171,7 @@
 
 void Layer::setPaint(const SkPaint* paint) {
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
-    setColorFilter((paint) ? paint->getColorFilter() : NULL);
+    setColorFilter((paint) ? paint->getColorFilter() : nullptr);
 }
 
 void Layer::setColorFilter(SkColorFilter* filter) {
@@ -198,7 +180,7 @@
 
 void Layer::bindTexture() const {
     if (texture.id) {
-        caches.bindTexture(renderTarget, texture.id);
+        caches.textureState().bindTexture(renderTarget, texture.id);
     }
 }
 
@@ -222,7 +204,7 @@
 }
 
 void Layer::clearTexture() {
-    caches.unbindTexture(texture.id);
+    caches.textureState().unbindTexture(texture.id);
     texture.id = 0;
 }
 
@@ -233,7 +215,7 @@
     if (texture.id) {
         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
         glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+                GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
     }
 }
 
@@ -249,8 +231,7 @@
         dirtyRect.set(0, 0, width, height);
     }
 
-    delete deferredList;
-    deferredList = new DeferredDisplayList(dirtyRect);
+    deferredList.reset(new DeferredDisplayList(dirtyRect));
 
     DeferStateStruct deferredState(*deferredList, *renderer,
             RenderNode::kReplayFlag_ClipChildren);
@@ -266,19 +247,16 @@
 }
 
 void Layer::cancelDefer() {
-    renderNode = NULL;
+    renderNode = nullptr;
     deferredUpdateScheduled = false;
-    if (deferredList) {
-        delete deferredList;
-        deferredList = NULL;
-    }
+    deferredList.release();
 }
 
 void Layer::flush() {
     // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
     if (deferredList && renderer) {
         ATRACE_LAYER_WORK("Issue");
-        renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
+        renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer");
 
         renderer->setViewport(layer.getWidth(), layer.getHeight());
         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
@@ -289,7 +267,7 @@
         renderer->finish();
 
         dirtyRect.setEmpty();
-        renderNode = NULL;
+        renderNode = nullptr;
 
         renderer->endMark();
     }
@@ -310,7 +288,7 @@
     dirtyRect.setEmpty();
 
     deferredUpdateScheduled = false;
-    renderNode = NULL;
+    renderNode = nullptr;
 }
 
 void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e196cb1..b670870 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -20,6 +20,8 @@
 #include <cutils/compiler.h>
 #include <sys/types.h>
 #include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <memory>
 
 #include <GLES2/gl2.h>
 
@@ -43,11 +45,11 @@
 
 // Forward declarations
 class Caches;
+class RenderNode;
 class RenderState;
 class OpenGLRenderer;
-class RenderNode;
 class DeferredDisplayList;
-class DeferStateStruct;
+struct DeferStateStruct;
 
 /**
  * A layer has dimensions and is backed by an OpenGL texture or FBO.
@@ -70,7 +72,7 @@
     };
     State state; // public for logging/debugging purposes
 
-    Layer(Type type, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight);
+    Layer(Type type, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight);
     ~Layer();
 
     static uint32_t computeIdealWidth(uint32_t layerWidth);
@@ -198,10 +200,14 @@
         return stencil;
     }
 
-    inline GLuint getTexture() const {
+    inline GLuint getTextureId() const {
         return texture.id;
     }
 
+    inline Texture& getTexture() {
+        return texture;
+    }
+
     inline GLenum getRenderTarget() const {
         return renderTarget;
     }
@@ -318,19 +324,19 @@
     /**
      * If the layer can be rendered as a mesh, this is non-null.
      */
-    TextureVertex* mesh;
-    GLsizei meshElementCount;
+    TextureVertex* mesh = nullptr;
+    GLsizei meshElementCount = 0;
 
     /**
      * Used for deferred updates.
      */
-    bool deferredUpdateScheduled;
-    OpenGLRenderer* renderer;
+    bool deferredUpdateScheduled = false;
+    std::unique_ptr<OpenGLRenderer> renderer;
     sp<RenderNode> renderNode;
     Rect dirtyRect;
-    bool debugDrawUpdate;
-    bool hasDrawnSinceUpdate;
-    bool wasBuildLayered;
+    bool debugDrawUpdate = false;
+    bool hasDrawnSinceUpdate = false;
+    bool wasBuildLayered = false;
 
 private:
     void requireRenderer();
@@ -344,17 +350,17 @@
      * Name of the FBO used to render the layer. If the name is 0
      * this layer is not backed by an FBO, but a simple texture.
      */
-    GLuint fbo;
+    GLuint fbo = 0;
 
     /**
      * The render buffer used as the stencil buffer.
      */
-    RenderBuffer* stencil;
+    RenderBuffer* stencil = nullptr;
 
     /**
      * Indicates whether this layer has been used already.
      */
-    bool empty;
+    bool empty = true;
 
     /**
      * The texture backing this layer.
@@ -364,7 +370,7 @@
     /**
      * If set to true (by default), the layer can be reused.
      */
-    bool cacheable;
+    bool cacheable = true;
 
     /**
      * Denotes whether the layer is a DisplayList, or Texture layer.
@@ -375,32 +381,32 @@
      * When set to true, this layer is dirty and should be cleared
      * before any rendering occurs.
      */
-    bool dirty;
+    bool dirty = false;
 
     /**
      * Indicates the render target.
      */
-    GLenum renderTarget;
+    GLenum renderTarget = GL_TEXTURE_2D;
 
     /**
      * Color filter used to draw this layer. Optional.
      */
-    SkColorFilter* colorFilter;
+    SkColorFilter* colorFilter = nullptr;
 
     /**
      * Indicates raster data backing the layer is scaled, requiring filtration.
      */
-    bool forceFilter;
+    bool forceFilter = false;
 
     /**
      * Opacity of the layer.
      */
-    int alpha;
+    int alpha = 255;
 
     /**
      * Blending mode of the layer.
      */
-    SkXfermode::Mode mode;
+    SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
 
     /**
      * Optional texture coordinates transform.
@@ -416,20 +422,20 @@
      * Cached transform of layer in window, updated only on creation / resize
      */
     mat4 cachedInvTransformInWindow;
-    bool rendererLightPosDirty;
+    bool rendererLightPosDirty = true;
 
     /**
      * Used to defer display lists when the layer is updated with a
      * display list.
      */
-    DeferredDisplayList* deferredList;
+    std::unique_ptr<DeferredDisplayList> deferredList;
 
     /**
      * This convex path should be used to mask the layer's draw to the screen.
      *
      * Data not owned/managed by layer object.
      */
-    const SkPath* convexMask;
+    const SkPath* convexMask = nullptr;
 
 }; // struct Layer
 
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 3033dc6..bcbd412 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -33,7 +33,7 @@
 
 LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting layer cache size to %sMB", property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -84,7 +84,7 @@
                 layer->getFbo());
         mSize -= layer->getWidth() * layer->getHeight() * 4;
         layer->state = Layer::kState_DeletedFromCache;
-        layer->decStrong(0);
+        layer->decStrong(nullptr);
     }
 }
 
@@ -97,7 +97,7 @@
 }
 
 Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
-    Layer* layer = NULL;
+    Layer* layer = nullptr;
 
     LayerEntry entry(width, height);
     ssize_t index = mCache.indexOf(entry);
@@ -116,9 +116,6 @@
 
         layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
         layer->setBlend(true);
-        layer->setEmpty(true);
-        layer->setFbo(0);
-
         layer->generateTexture();
         layer->bindTexture();
         layer->setFilter(GL_NEAREST);
@@ -137,7 +134,7 @@
     size_t size = mCache.size();
     for (size_t i = 0; i < size; i++) {
         const LayerEntry& entry = mCache.itemAt(i);
-        LAYER_LOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
+        ALOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
     }
 }
 
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 6b93e8f..7d17b9b 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -30,7 +30,6 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-// Debug
 #if DEBUG_LAYERS
     #define LAYER_LOGD(...) ALOGD(__VA_ARGS__)
 #else
@@ -97,10 +96,10 @@
 private:
     struct LayerEntry {
         LayerEntry():
-            mLayer(NULL), mWidth(0), mHeight(0) {
+            mLayer(nullptr), mWidth(0), mHeight(0) {
         }
 
-        LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) {
+        LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(nullptr) {
             mWidth = Layer::computeIdealWidth(layerWidth);
             mHeight = Layer::computeIdealHeight(layerHeight);
         }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 83f9c6a..223bdf0 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -17,18 +17,19 @@
 #define LOG_TAG "OpenGLRenderer"
 #define ATRACE_TAG ATRACE_TAG_VIEW
 
-#include <ui/Rect.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
-#include "RenderState.h"
 #include "LayerCache.h"
 #include "LayerRenderer.h"
 #include "Matrix.h"
 #include "Properties.h"
 #include "Rect.h"
+#include "renderstate/RenderState.h"
 #include "utils/TraceUtils.h"
 
+#include <ui/Rect.h>
+
+#include <private/hwui/DrawGlInfo.h>
+
+
 namespace android {
 namespace uirenderer {
 
@@ -44,11 +45,11 @@
 LayerRenderer::~LayerRenderer() {
 }
 
-status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
+void LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
         bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
 
-    renderState().bindFramebuffer(mLayer->getFbo());
+    mRenderState.bindFramebuffer(mLayer->getFbo());
 
     const float width = mLayer->layer.getWidth();
     const float height = mLayer->layer.getHeight();
@@ -65,25 +66,23 @@
     }
     mLayer->clipRect.set(dirty);
 
-    return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
+    OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
 }
 
-status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+void LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
     if (mLayer->isDirty()) {
-        getCaches().disableScissor();
+        mRenderState.scissor().setEnabled(false);
         glClear(GL_COLOR_BUFFER_BIT);
 
-        getCaches().resetScissor();
+        mRenderState.scissor().reset();
         mLayer->setDirty(false);
-
-        return DrawGlInfo::kStatusDone;
+    } else {
+        OpenGLRenderer::clear(left, top, right, bottom, opaque);
     }
-
-    return OpenGLRenderer::clear(left, top, right, bottom, opaque);
 }
 
-void LayerRenderer::finish() {
-    OpenGLRenderer::finish();
+bool LayerRenderer::finish() {
+    bool retval = OpenGLRenderer::finish();
 
     generateMesh();
 
@@ -91,6 +90,7 @@
 
     // No need to unbind our FBO, this will be taken care of by the caller
     // who will invoke OpenGLRenderer::resume()
+    return retval;
 }
 
 GLuint LayerRenderer::getTargetFbo() const {
@@ -118,7 +118,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Region* LayerRenderer::getRegion() const {
-    if (currentSnapshot()->flags & Snapshot::kFlagFboTarget) {
+    if (mState.currentFlags() & Snapshot::kFlagFboTarget) {
         return OpenGLRenderer::getRegion();
     }
     return &mLayer->region;
@@ -131,7 +131,7 @@
     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
         if (mLayer->mesh) {
             delete[] mLayer->mesh;
-            mLayer->mesh = NULL;
+            mLayer->mesh = nullptr;
             mLayer->meshElementCount = 0;
         }
 
@@ -152,7 +152,7 @@
 
     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
         delete[] mLayer->mesh;
-        mLayer->mesh = NULL;
+        mLayer->mesh = nullptr;
     }
 
     if (!mLayer->mesh) {
@@ -193,14 +193,14 @@
     GLuint fbo = caches.fboCache.get();
     if (!fbo) {
         ALOGW("Could not obtain an FBO");
-        return NULL;
+        return nullptr;
     }
 
-    caches.activeTexture(0);
+    caches.textureState().activateTexture(0);
     Layer* layer = caches.layerCache.get(renderState, width, height);
     if (!layer) {
         ALOGW("Could not obtain a layer");
-        return NULL;
+        return nullptr;
     }
 
     // We first obtain a layer before comparing against the max texture size
@@ -213,9 +213,9 @@
 
         // Creating a new layer always increment its refcount by 1, this allows
         // us to destroy the layer object if one was created for us
-        layer->decStrong(0);
+        layer->decStrong(nullptr);
 
-        return NULL;
+        return nullptr;
     }
 
     layer->setFbo(fbo);
@@ -223,7 +223,7 @@
     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
             width / float(layer->getWidth()), 0.0f);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
-    layer->setColorFilter(NULL);
+    layer->setColorFilter(nullptr);
     layer->setDirty(true);
     layer->region.clear();
 
@@ -241,13 +241,13 @@
         if (glGetError() != GL_NO_ERROR) {
             ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
             renderState.bindFramebuffer(previousFbo);
-            layer->decStrong(0);
-            return NULL;
+            layer->decStrong(nullptr);
+            return nullptr;
         }
     }
 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            layer->getTexture(), 0);
+            layer->getTextureId(), 0);
 
     renderState.bindFramebuffer(previousFbo);
 
@@ -275,15 +275,12 @@
 
     Layer* layer = new Layer(Layer::kType_Texture, renderState, 0, 0);
     layer->setCacheable(false);
-    layer->setEmpty(true);
-    layer->setFbo(0);
-    layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
     layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
     layer->region.clear();
     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
 
-    Caches::getInstance().activeTexture(0);
+    Caches::getInstance().textureState().activateTexture(0);
     layer->generateTexture();
 
     return layer;
@@ -317,7 +314,7 @@
 
         if (!Caches::getInstance().layerCache.put(layer)) {
             LAYER_RENDERER_LOGD("  Destroyed!");
-            layer->decStrong(0);
+            layer->decStrong(nullptr);
         } else {
             LAYER_RENDERER_LOGD("  Cached!");
 #if DEBUG_LAYER_RENDERER
@@ -337,7 +334,7 @@
     if (fbo) {
         // If possible, discard any enqueud operations on deferred
         // rendering architectures
-        if (Extensions::getInstance().hasDiscardFramebuffer()) {
+        if (Caches::getInstance().extensions().hasDiscardFramebuffer()) {
             GLuint previousFbo = renderState.getFramebuffer();
             if (fbo != previousFbo) {
                 renderState.bindFramebuffer(fbo);
@@ -356,8 +353,9 @@
 
 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
-    if (layer && bitmap->width() <= caches.maxTextureSize &&
-            bitmap->height() <= caches.maxTextureSize) {
+    if (layer
+            && bitmap->width() <= caches.maxTextureSize
+            && bitmap->height() <= caches.maxTextureSize) {
 
         GLuint fbo = caches.fboCache.get();
         if (!fbo) {
@@ -412,8 +410,8 @@
         glGenTextures(1, &texture);
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        caches.activeTexture(0);
-        caches.bindTexture(texture);
+        caches.textureState().activateTexture(0);
+        caches.textureState().bindTexture(texture);
 
         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
 
@@ -424,7 +422,7 @@
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
-                0, format, type, NULL);
+                0, format, type, nullptr);
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -437,7 +435,7 @@
             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
                     bitmap->width(), bitmap->height(), !layer->isBlend());
 
-            caches.disableScissor();
+            renderState.scissor().setEnabled(false);
             renderer.translate(0.0f, bitmap->height());
             renderer.scale(1.0f, -1.0f);
 
@@ -475,7 +473,7 @@
         renderState.bindFramebuffer(previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
-        caches.deleteTexture(texture);
+        caches.textureState().deleteTexture(texture);
         caches.fboCache.put(fbo);
         renderState.setViewport(previousViewportWidth, previousViewportHeight);
 
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 4d8620b..47ded7e 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -49,10 +49,11 @@
     LayerRenderer(RenderState& renderState, Layer* layer);
     virtual ~LayerRenderer();
 
-    virtual void onViewportInitialized() { /* do nothing */ }
-    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
-    virtual void finish();
+    virtual void onViewportInitialized() override { /* do nothing */ }
+    virtual void prepareDirty(float left, float top, float right, float bottom,
+            bool opaque) override;
+    virtual void clear(float left, float top, float right, float bottom, bool opaque) override;
+    virtual bool finish() override;
 
     static Layer* createTextureLayer(RenderState& renderState);
     static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height);
@@ -65,11 +66,11 @@
     static void flushLayer(RenderState& renderState, Layer* layer);
 
 protected:
-    virtual void ensureStencilBuffer();
-    virtual bool hasLayer() const;
-    virtual Region* getRegion() const;
-    virtual GLuint getTargetFbo() const;
-    virtual bool suppressErrorChecks() const;
+    virtual void ensureStencilBuffer() override;
+    virtual bool hasLayer() const override;
+    virtual Region* getRegion() const override;
+    virtual GLuint getTargetFbo() const override;
+    virtual bool suppressErrorChecks() const override;
 
 private:
     void generateMesh();
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 9f2014f..061d26a 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -203,6 +203,34 @@
 }
 
 void Matrix4::loadInverse(const Matrix4& v) {
+    // Fast case for common translation matrices
+    if (v.isPureTranslate()) {
+        // Reset the matrix
+        // Unnamed fields are never written to except by
+        // loadIdentity(), they don't need to be reset
+        data[kScaleX]       = 1.0f;
+        data[kSkewX]        = 0.0f;
+
+        data[kScaleY]       = 1.0f;
+        data[kSkewY]        = 0.0f;
+
+        data[kScaleZ]       = 1.0f;
+
+        data[kPerspective0] = 0.0f;
+        data[kPerspective1] = 0.0f;
+        data[kPerspective2] = 1.0f;
+
+        // No need to deal with kTranslateZ because isPureTranslate()
+        // only returns true when the kTranslateZ component is 0
+        data[kTranslateX]   = -v.data[kTranslateX];
+        data[kTranslateY]   = -v.data[kTranslateY];
+        data[kTranslateZ]   = 0.0f;
+
+        // A "pure translate" matrix can be identity or translation
+        mType = v.getType();
+        return;
+    }
+
     double scale = 1.0 /
             (v.data[kScaleX] * ((double) v.data[kScaleY]  * v.data[kPerspective2] -
                     (double) v.data[kTranslateY] * v.data[kPerspective1]) +
@@ -212,18 +240,18 @@
                      (double) v.data[kScaleY] * v.data[kPerspective0]));
 
     data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] -
-            v.data[kTranslateY] * v.data[kPerspective1])  * scale;
+            v.data[kTranslateY] * v.data[kPerspective1]) * scale;
     data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] -
             v.data[kSkewX]  * v.data[kPerspective2]) * scale;
     data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] -
-            v.data[kTranslateX] * v.data[kScaleY])  * scale;
+            v.data[kTranslateX] * v.data[kScaleY]) * scale;
 
     data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] -
             v.data[kSkewY]  * v.data[kPerspective2]) * scale;
     data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] -
-            v.data[kTranslateX] * v.data[kPerspective0])  * scale;
+            v.data[kTranslateX] * v.data[kPerspective0]) * scale;
     data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] -
-            v.data[kScaleX]  * v.data[kTranslateY]) * scale;
+            v.data[kScaleX] * v.data[kTranslateY]) * scale;
 
     data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] -
             v.data[kScaleY] * v.data[kPerspective0]) * scale;
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 1c5c578..a760135 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -210,7 +210,7 @@
 
     void decomposeScale(float& sx, float& sy) const;
 
-    void dump(const char* label = NULL) const;
+    void dump(const char* label = nullptr) const;
 
     static const Matrix4& identity();
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
old mode 100755
new mode 100644
index 6f1e8a2..622b570
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -14,7 +14,26 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "OpenGLRenderer"
+#include "OpenGLRenderer.h"
+
+#include "DeferredDisplayList.h"
+#include "DisplayListRenderer.h"
+#include "GammaFontRenderer.h"
+#include "Glop.h"
+#include "GlopBuilder.h"
+#include "Patch.h"
+#include "PathTessellator.h"
+#include "Properties.h"
+#include "RenderNode.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "ShadowTessellator.h"
+#include "SkiaShader.h"
+#include "Vector.h"
+#include "VertexBuffer.h"
+#include "utils/GLUtils.h"
+#include "utils/PaintUtils.h"
+#include "utils/TraceUtils.h"
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -32,111 +51,30 @@
 
 #include <ui/Rect.h>
 
-#include "OpenGLRenderer.h"
-#include "DeferredDisplayList.h"
-#include "DisplayListRenderer.h"
-#include "Fence.h"
-#include "RenderState.h"
-#include "PathTessellator.h"
-#include "Properties.h"
-#include "ShadowTessellator.h"
-#include "SkiaShader.h"
-#include "utils/GLUtils.h"
-#include "utils/TraceUtils.h"
-#include "Vector.h"
-#include "VertexBuffer.h"
-
 #if DEBUG_DETAILED_EVENTS
     #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
 #else
     #define EVENT_LOGD(...)
 #endif
 
+#define USE_GLOPS true
+
 namespace android {
 namespace uirenderer {
 
-static GLenum getFilter(const SkPaint* paint) {
-    if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
-        return GL_LINEAR;
-    }
-    return GL_NEAREST;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
-struct Blender {
-    SkXfermode::Mode mode;
-    GLenum src;
-    GLenum dst;
-}; // struct Blender
-
-// In this array, the index of each Blender equals the value of the first
-// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
-static const Blender gBlends[] = {
-    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
-    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
-    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
-    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
-    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
-    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
-    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
-};
-
-// This array contains the swapped version of each SkXfermode. For instance
-// this array's SrcOver blending mode is actually DstOver. You can refer to
-// createLayer() for more information on the purpose of this array.
-static const Blender gBlendsSwap[] = {
-    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
-    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
-    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
-    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
-    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
-    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
-    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
-    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
-    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
-    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
-    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Functions
-///////////////////////////////////////////////////////////////////////////////
-
-template<typename T>
-static inline T min(T a, T b) {
-    return a < b ? a : b;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
-        : mFrameStarted(false)
+        : mState(*this)
         , mCaches(Caches::getInstance())
-        , mExtensions(Extensions::getInstance())
         , mRenderState(renderState)
+        , mFrameStarted(false)
         , mScissorOptimizationDisabled(false)
         , mSuppressTiling(false)
         , mFirstFrameAfterResize(true)
+        , mDirty(false)
         , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
         , mLightRadius(FLT_MIN)
         , mAmbientShadowAlpha(0)
@@ -145,7 +83,7 @@
     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
 
-    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
+    memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -179,28 +117,26 @@
 void OpenGLRenderer::onViewportInitialized() {
     glDisable(GL_DITHER);
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-    glEnableVertexAttribArray(Program::kBindingPosition);
     mFirstFrameAfterResize = true;
 }
 
 void OpenGLRenderer::setupFrameState(float left, float top,
         float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
-    initializeSaveStack(left, top, right, bottom, mLightCenter);
+    mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
     mOpaque = opaque;
     mTilingClip.set(left, top, right, bottom);
 }
 
-status_t OpenGLRenderer::startFrame() {
-    if (mFrameStarted) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::startFrame() {
+    if (mFrameStarted) return;
     mFrameStarted = true;
 
-    mDirtyClip = true;
+    mState.setDirtyClip(true);
 
     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
 
-    mRenderState.setViewport(getWidth(), getHeight());
+    mRenderState.setViewport(mState.getWidth(), mState.getHeight());
 
     // Functors break the tiling extension in pretty spectacular ways
     // This ensures we don't use tiling when a functor is going to be
@@ -213,11 +149,11 @@
 
     debugOverdraw(true, true);
 
-    return clear(mTilingClip.left, mTilingClip.top,
+    clear(mTilingClip.left, mTilingClip.top,
             mTilingClip.right, mTilingClip.bottom, mOpaque);
 }
 
-status_t OpenGLRenderer::prepareDirty(float left, float top,
+void OpenGLRenderer::prepareDirty(float left, float top,
         float right, float bottom, bool opaque) {
 
     setupFrameState(left, top, right, bottom, opaque);
@@ -227,21 +163,19 @@
     // for each layer and wait until the first drawing command
     // to start the frame
     if (currentSnapshot()->fbo == 0) {
-        syncState();
+        mRenderState.blend().syncEnabled();
         updateLayers();
     } else {
-        return startFrame();
+        startFrame();
     }
-
-    return DrawGlInfo::kStatusDone;
 }
 
 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
     // If we know that we are going to redraw the entire framebuffer,
     // perform a discard to let the driver know we don't need to preserve
     // the back buffer for this frame.
-    if (mExtensions.hasDiscardFramebuffer() &&
-            left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
+    if (mCaches.extensions().hasDiscardFramebuffer() &&
+            left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
         const bool isFbo = getTargetFbo() == 0;
         const GLenum attachments[] = {
                 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
@@ -250,24 +184,16 @@
     }
 }
 
-status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
     if (!opaque) {
-        mCaches.enableScissor();
-        mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
+        mRenderState.scissor().setEnabled(true);
+        mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
-        return DrawGlInfo::kStatusDrew;
+        mDirty = true;
+        return;
     }
 
-    mCaches.resetScissor();
-    return DrawGlInfo::kStatusDone;
-}
-
-void OpenGLRenderer::syncState() {
-    if (mCaches.blend) {
-        glEnable(GL_BLEND);
-    } else {
-        glDisable(GL_BLEND);
-    }
+    mRenderState.scissor().reset();
 }
 
 void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
@@ -307,13 +233,9 @@
     if (!mSuppressTiling) mCaches.endTiling();
 }
 
-void OpenGLRenderer::finish() {
+bool OpenGLRenderer::finish() {
     renderOverdraw();
     endTiling();
-
-    for (size_t i = 0; i < mTempPaths.size(); i++) {
-        delete mTempPaths[i];
-    }
     mTempPaths.clear();
 
     // When finish() is invoked on FBO 0 we've reached the end
@@ -338,6 +260,8 @@
     }
 
     mFrameStarted = false;
+
+    return reportAndClearDirty();
 }
 
 void OpenGLRenderer::resumeAfterLayer() {
@@ -345,14 +269,14 @@
     mRenderState.bindFramebuffer(currentSnapshot()->fbo);
     debugOverdraw(true, false);
 
-    mCaches.resetScissor();
+    mRenderState.scissor().reset();
     dirtyClip();
 }
 
-status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
-    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
+    if (mState.currentlyIgnored()) return;
 
-    Rect clip(*currentClipRect());
+    Rect clip(mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
     // Since we don't know what the functor will draw, let's dirty
@@ -371,12 +295,12 @@
     info.height = getViewportHeight();
     currentTransform()->copyTo(&info.transform[0]);
 
-    bool prevDirtyClip = mDirtyClip;
+    bool prevDirtyClip = mState.getDirtyClip();
     // setup GL state for functor
-    if (mDirtyClip) {
+    if (mState.getDirtyClip()) {
         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
     }
-    if (mCaches.enableScissor() || prevDirtyClip) {
+    if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
         setScissorFromClip();
     }
 
@@ -384,7 +308,7 @@
     // Scissor may have been modified, reset dirty clip
     dirtyClip();
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -426,27 +350,29 @@
     if (mCaches.debugOverdraw && getTargetFbo() == 0) {
         const Rect* clip = &mTilingClip;
 
-        mCaches.enableScissor();
-        mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
-                clip->right - clip->left, clip->bottom - clip->top);
+        mRenderState.scissor().setEnabled(true);
+        mRenderState.scissor().set(clip->left,
+                mState.firstSnapshot()->getViewportHeight() - clip->bottom,
+                clip->right - clip->left,
+                clip->bottom - clip->top);
 
         // 1x overdraw
-        mCaches.stencil.enableDebugTest(2);
+        mRenderState.stencil().enableDebugTest(2);
         drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
 
         // 2x overdraw
-        mCaches.stencil.enableDebugTest(3);
+        mRenderState.stencil().enableDebugTest(3);
         drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
 
         // 3x overdraw
-        mCaches.stencil.enableDebugTest(4);
+        mRenderState.stencil().enableDebugTest(4);
         drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
 
         // 4x overdraw and higher
-        mCaches.stencil.enableDebugTest(4, true);
+        mRenderState.stencil().enableDebugTest(4, true);
         drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
 
-        mCaches.stencil.disable();
+        mRenderState.stencil().disable();
     }
 }
 
@@ -457,7 +383,6 @@
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
     if (layer->deferredUpdateScheduled && layer->renderer
             && layer->renderNode.get() && layer->renderNode->isRenderable()) {
-        Rect& dirty = layer->dirtyRect;
 
         if (inFrame) {
             endTiling();
@@ -555,11 +480,11 @@
 
 void OpenGLRenderer::flushLayerUpdates() {
     ATRACE_NAME("Update HW Layers");
-    syncState();
+    mRenderState.blend().syncEnabled();
     updateLayers();
     flushLayers();
     // Wait for all the layer updates to be executed
-    AutoFence fence;
+    glFinish();
 }
 
 void OpenGLRenderer::markLayersAsBuildLayers() {
@@ -603,9 +528,9 @@
     // force matrix/clip isolation for layer
     flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
 
-    const int count = saveSnapshot(flags);
+    const int count = mState.saveSnapshot(flags);
 
-    if (!currentSnapshot()->isIgnored()) {
+    if (!mState.currentlyIgnored()) {
         createLayer(left, top, right, bottom, paint, flags, convexMask);
     }
 
@@ -618,7 +543,7 @@
     currentTransform()->mapRect(bounds);
 
     // Layers only make sense if they are in the framebuffer's bounds
-    if (bounds.intersect(*currentClipRect())) {
+    if (bounds.intersect(mState.currentClipRect())) {
         // We cannot work with sub-pixels in this case
         bounds.snapToPixelBoundaries();
 
@@ -652,17 +577,17 @@
     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
             bounds.getHeight() > mCaches.maxTextureSize ||
             (fboLayer && clip.isEmpty())) {
-        mSnapshot->empty = fboLayer;
+        writableSnapshot()->empty = fboLayer;
     } else {
-        mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
+        writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
     }
 }
 
 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
         const SkPaint* paint, int flags) {
-    const int count = saveSnapshot(flags);
+    const int count = mState.saveSnapshot(flags);
 
-    if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+    if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
         // operations will be able to store and restore the current clip and transform info, and
         // quick rejection will be correct (for display lists)
@@ -672,11 +597,11 @@
         calculateLayerBoundsAndClip(bounds, clip, true);
         updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
 
-        if (!currentSnapshot()->isIgnored()) {
-            mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
-            mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-            mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
-            mSnapshot->roundRectClipState = NULL;
+        if (!mState.currentlyIgnored()) {
+            writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
+            writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+            writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
+            writableSnapshot()->roundRectClipState = nullptr;
         }
     }
 
@@ -748,11 +673,11 @@
     updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
 
     // Bail out if we won't draw in this snapshot
-    if (currentSnapshot()->isIgnored()) {
+    if (mState.currentlyIgnored()) {
         return false;
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
     if (!layer) {
         return false;
@@ -768,8 +693,8 @@
     layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
 
     // Save the layer in the snapshot
-    mSnapshot->flags |= Snapshot::kFlagIsLayer;
-    mSnapshot->layer = layer;
+    writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
+    writableSnapshot()->layer = layer;
 
     ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
             fboLayer ? "" : "unclipped ",
@@ -787,7 +712,7 @@
                 // Unfortunately some drivers will turn the entire target texture black
                 // when reading outside of the window.
                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
-                        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+                        0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
                 layer->setEmpty(false);
             }
 
@@ -796,7 +721,7 @@
                     bounds.getWidth(), bounds.getHeight());
 
             // Enqueue the buffer coordinates to clear the corresponding region later
-            mLayers.push(new Rect(bounds));
+            mLayers.push_back(Rect(bounds));
         }
     }
 
@@ -807,13 +732,13 @@
     layer->clipRect.set(clip);
     layer->setFbo(mCaches.fboCache.get());
 
-    mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
-    mSnapshot->fbo = layer->getFbo();
-    mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
-    mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
-    mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
-    mSnapshot->roundRectClipState = NULL;
+    writableSnapshot()->region = &writableSnapshot()->layer->region;
+    writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
+    writableSnapshot()->fbo = layer->getFbo();
+    writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
+    writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+    writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
+    writableSnapshot()->roundRectClipState = nullptr;
 
     endTiling();
     debugOverdraw(false, false);
@@ -828,14 +753,14 @@
     }
 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            layer->getTexture(), 0);
+            layer->getTextureId(), 0);
 
     // Expand the startTiling region by 1
     startTilingCurrentClip(true, true);
 
     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
-    mCaches.enableScissor();
-    mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+    mRenderState.scissor().setEnabled(true);
+    mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 
@@ -860,9 +785,9 @@
     const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
 
     bool clipRequired = false;
-    calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
-            &clipRequired, NULL, false); // safely ignore return, should never be rejected
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+    mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
+            &clipRequired, nullptr, false); // safely ignore return, should never be rejected
+    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
 
     if (fboLayer) {
         endTiling();
@@ -890,9 +815,9 @@
         layer->setAlpha(255);
     }
 
-    mCaches.unbindMeshBuffer();
+    mRenderState.meshState().unbindMeshBuffer();
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     // When the layer is stored in an FBO, we can save a bit of fillrate by
     // drawing only the dirty region
@@ -905,7 +830,7 @@
         save(0);
         // the layer contains screen buffer content that shouldn't be alpha modulated
         // (and any necessary alpha modulation was handled drawing into the layer)
-        mSnapshot->alpha = 1.0f;
+        writableSnapshot()->alpha = 1.0f;
         composeLayerRect(layer, rect, true);
         restore();
     }
@@ -913,16 +838,29 @@
     dirtyClip();
 
     // Failing to add the layer to the cache should happen only if the layer is too large
-    layer->setConvexMask(NULL);
+    layer->setConvexMask(nullptr);
     if (!mCaches.layerCache.put(layer)) {
         LAYER_LOGD("Deleting layer");
-        layer->decStrong(0);
+        layer->decStrong(nullptr);
     }
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    float alpha = getLayerAlpha(layer);
+    if (USE_GLOPS) {
+        bool snap = !layer->getForceFilter()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+                .setFillTextureLayer(*layer, getLayerAlpha(layer))
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+    }
 
+    float alpha = getLayerAlpha(layer);
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
         setupDrawWithTexture();
@@ -937,16 +875,16 @@
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(layer->getColorFilter());
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
-        setupDrawTexture(layer->getTexture());
+        setupDrawTexture(layer->getTextureId());
     } else {
-        setupDrawExternalTexture(layer->getTexture());
+        setupDrawExternalTexture(layer->getTextureId());
     }
-    if (currentTransform()->isPureTranslate() &&
-            !layer->getForceFilter() &&
-            layer->getWidth() == (uint32_t) rect.getWidth() &&
-            layer->getHeight() == (uint32_t) rect.getHeight()) {
-        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+    if (currentTransform()->isPureTranslate()
+            && !layer->getForceFilter()
+            && layer->getWidth() == (uint32_t) rect.getWidth()
+            && layer->getHeight() == (uint32_t) rect.getHeight()) {
+        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
 
         layer->setFilter(GL_NEAREST);
         setupDrawModelView(kModelViewMode_TranslateAndScale, false,
@@ -959,7 +897,7 @@
     setupDrawTextureTransformUniforms(layer->getTexTransform());
     setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -970,21 +908,41 @@
         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     } else {
         EVENT_LOGD("composeHardwareLayerRect");
+
+        if (USE_GLOPS) {
+            Blend::ModeOrderSwap modeUsage = swap ?
+                    Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
+            const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
+            bool snap = !swap
+                    && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
+                    && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setMeshTexturedUvQuad(nullptr, layer->texCoords)
+                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                    .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                    .build();
+            renderGlop(glop);
+            return;
+        }
+
         const Rect& texCoords = layer->texCoords;
         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
                 texCoords.right, texCoords.bottom);
 
         float x = rect.left;
         float y = rect.top;
-        bool simpleTransform = currentTransform()->isPureTranslate() &&
-                layer->getWidth() == (uint32_t) rect.getWidth() &&
-                layer->getHeight() == (uint32_t) rect.getHeight();
+        bool simpleTransform = currentTransform()->isPureTranslate()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
 
         if (simpleTransform) {
             // When we're swapping, the layer is already in screen coordinates
             if (!swap) {
-                x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-                y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+                x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+                y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
             }
 
             layer->setFilter(GL_NEAREST, true);
@@ -999,9 +957,9 @@
 
         bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
-                layer->getTexture(), &layerPaint, blend,
+                layer->getTextureId(), &layerPaint, blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
 
         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     }
@@ -1033,14 +991,14 @@
     , mLayer(layer) {
     }
 
-    virtual bool asACustomShader(void** data) const {
+    virtual bool asACustomShader(void** data) const override {
         if (data) {
             *data = static_cast<void*>(mLayer);
         }
         return true;
     }
 
-    virtual bool isOpaque() const {
+    virtual bool isOpaque() const override {
         return !mLayer->isBlend();
     }
 
@@ -1049,13 +1007,13 @@
         LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
     }
 
-    virtual void flatten(SkWriteBuffer&) const {
+    virtual void flatten(SkWriteBuffer&) const override {
         LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
     }
 
-    virtual Factory getFactory() const {
+    virtual Factory getFactory() const override {
         LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
-        return NULL;
+        return nullptr;
     }
 private:
     // Unowned.
@@ -1088,7 +1046,7 @@
         const SkPath* maskPath = layer->getConvexMask();
         DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
 
-        paint.setShader(NULL);
+        paint.setShader(nullptr);
         restore();
 
         return;
@@ -1115,11 +1073,42 @@
         rects = safeRegion.getArray(&count);
     }
 
-    const float alpha = getLayerAlpha(layer);
     const float texX = 1.0f / float(layer->getWidth());
     const float texY = 1.0f / float(layer->getHeight());
     const float height = rect.getHeight();
 
+    if (USE_GLOPS) {
+        TextureVertex quadVertices[count * 4];
+        //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]);
+        TextureVertex* mesh = &quadVertices[0];
+        for (size_t i = 0; i < count; i++) {
+            const android::Rect* r = &rects[i];
+
+            const float u1 = r->left * texX;
+            const float v1 = (height - r->top) * texY;
+            const float u2 = r->right * texX;
+            const float v2 = (height - r->bottom) * texY;
+
+            // TODO: Reject quads outside of the clip
+            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
+                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRectSnap(0, 0, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
+        return;
+    }
+
+    const float alpha = getLayerAlpha(layer);
+
     setupDraw();
 
     // We must get (and therefore bind) the region mesh buffer
@@ -1136,10 +1125,10 @@
     setupDrawDirtyRegionsDisabled();
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(layer->getColorFilter());
-    setupDrawTexture(layer->getTexture());
+    setupDrawTexture(layer->getTextureId());
     if (currentTransform()->isPureTranslate()) {
-        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
 
         layer->setFilter(GL_NEAREST);
         setupDrawModelView(kModelViewMode_Translate, false,
@@ -1167,9 +1156,9 @@
 
         numQuads++;
 
-        if (numQuads >= gMaxNumberOfQuads) {
+        if (numQuads >= kMaxNumberOfQuads) {
             DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
-                            GL_UNSIGNED_SHORT, NULL));
+                    GL_UNSIGNED_SHORT, nullptr));
             numQuads = 0;
             mesh = mCaches.getRegionMesh();
         }
@@ -1177,7 +1166,7 @@
 
     if (numQuads > 0) {
         DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
-                        GL_UNSIGNED_SHORT, NULL));
+                GL_UNSIGNED_SHORT, nullptr));
     }
 
 #if DEBUG_LAYERS_AS_REGIONS
@@ -1231,7 +1220,7 @@
 }
 
 void OpenGLRenderer::dirtyLayer(const float left, const float top,
-        const float right, const float bottom, const mat4 transform) {
+        const float right, const float bottom, const Matrix4& transform) {
     if (hasLayer()) {
         Rect bounds(left, top, right, bottom);
         transform.mapRect(bounds);
@@ -1248,7 +1237,7 @@
 }
 
 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
-    if (bounds.intersect(*currentClipRect())) {
+    if (bounds.intersect(mState.currentClipRect())) {
         bounds.snapToPixelBoundaries();
         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
         if (!dirty.isEmpty()) {
@@ -1260,10 +1249,10 @@
 void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
     GLsizei elementsCount = quadsCount * 6;
     while (elementsCount > 0) {
-        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+        GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
 
         setupDrawIndexedVertices(&mesh[0].x);
-        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
+        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
 
         elementsCount -= drawCount;
         // Though there are 4 vertices in a quad, we use 6 indices per
@@ -1273,10 +1262,10 @@
 }
 
 void OpenGLRenderer::clearLayerRegions() {
-    const size_t count = mLayers.size();
-    if (count == 0) return;
+    const size_t quadCount = mLayers.size();
+    if (quadCount == 0) return;
 
-    if (!currentSnapshot()->isIgnored()) {
+    if (!mState.currentlyIgnored()) {
         EVENT_LOGD("clearLayerRegions");
         // Doing several glScissor/glClear here can negatively impact
         // GPUs with a tiler architecture, instead we draw quads with
@@ -1285,44 +1274,51 @@
         // The list contains bounds that have already been clipped
         // against their initial clip rect, and the current clip
         // is likely different so we need to disable clipping here
-        bool scissorChanged = mCaches.disableScissor();
+        bool scissorChanged = mRenderState.scissor().setEnabled(false);
 
-        Vertex mesh[count * 4];
+        Vertex mesh[quadCount * 4];
         Vertex* vertex = mesh;
 
-        for (uint32_t i = 0; i < count; i++) {
-            Rect* bounds = mLayers.itemAt(i);
+        for (uint32_t i = 0; i < quadCount; i++) {
+            const Rect& bounds = mLayers[i];
 
-            Vertex::set(vertex++, bounds->left, bounds->top);
-            Vertex::set(vertex++, bounds->right, bounds->top);
-            Vertex::set(vertex++, bounds->left, bounds->bottom);
-            Vertex::set(vertex++, bounds->right, bounds->bottom);
-
-            delete bounds;
+            Vertex::set(vertex++, bounds.left, bounds.top);
+            Vertex::set(vertex++, bounds.right, bounds.top);
+            Vertex::set(vertex++, bounds.left, bounds.bottom);
+            Vertex::set(vertex++, bounds.right, bounds.bottom);
         }
         // We must clear the list of dirty rects before we
         // call setupDraw() to prevent stencil setup to do
         // the same thing again
         mLayers.clear();
 
-        SkPaint clearPaint;
-        clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
+        if (USE_GLOPS) {
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setMeshIndexedQuads(&mesh[0], quadCount)
+                    .setFillClear()
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                    .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
+                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                    .build();
+            renderGlop(glop, false);
+        } else {
+            SkPaint clearPaint;
+            clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
 
-        setupDraw(false);
-        setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
-        setupDrawBlending(&clearPaint, true);
-        setupDrawProgram();
-        setupDrawPureColorUniforms();
-        setupDrawModelView(kModelViewMode_Translate, false,
-                0.0f, 0.0f, 0.0f, 0.0f, true);
+            setupDraw(false);
+            setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
+            setupDrawBlending(&clearPaint, true);
+            setupDrawProgram();
+            setupDrawPureColorUniforms();
+            setupDrawModelView(kModelViewMode_Translate, false,
+                    0.0f, 0.0f, 0.0f, 0.0f, true);
 
-        issueIndexedQuadDraw(&mesh[0], count);
-
-        if (scissorChanged) mCaches.enableScissor();
-    } else {
-        for (uint32_t i = 0; i < count; i++) {
-            delete mLayers.itemAt(i);
+            issueIndexedQuadDraw(&mesh[0], quadCount);
         }
+
+        if (scissorChanged) mRenderState.scissor().setEnabled(true);
+    } else {
         mLayers.clear();
     }
 }
@@ -1332,7 +1328,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
-    const Rect* currentClip = currentClipRect();
+    const Rect& currentClip = mState.currentClipRect();
     const mat4* currentMatrix = currentTransform();
 
     if (stateDeferFlags & kStateDeferFlag_Draw) {
@@ -1344,32 +1340,32 @@
             // is used, it should more closely duplicate the quickReject logic (in how it uses
             // snapToPixelBoundaries)
 
-            if(!clippedBounds.intersect(*currentClip)) {
+            if (!clippedBounds.intersect(currentClip)) {
                 // quick rejected
                 return true;
             }
 
             state.mClipSideFlags = kClipSide_None;
-            if (!currentClip->contains(state.mBounds)) {
+            if (!currentClip.contains(state.mBounds)) {
                 int& flags = state.mClipSideFlags;
                 // op partially clipped, so record which sides are clipped for clip-aware merging
-                if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left;
-                if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top;
-                if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right;
-                if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
+                if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
+                if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
+                if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
+                if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
             }
             state.mBounds.set(clippedBounds);
         } else {
             // Empty bounds implies size unknown. Label op as conservatively clipped to disable
             // overdraw avoidance (since we don't know what it overlaps)
             state.mClipSideFlags = kClipSide_ConservativeFull;
-            state.mBounds.set(*currentClip);
+            state.mBounds.set(currentClip);
         }
     }
 
     state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
     if (state.mClipValid) {
-        state.mClip.set(*currentClip);
+        state.mClip.set(currentClip);
     }
 
     // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
@@ -1385,12 +1381,12 @@
 
 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
     setMatrix(state.mMatrix);
-    mSnapshot->alpha = state.mAlpha;
+    writableSnapshot()->alpha = state.mAlpha;
     mDrawModifiers = state.mDrawModifiers;
-    mSnapshot->roundRectClipState = state.mRoundRectClipState;
+    writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
 
     if (state.mClipValid && !skipClipRestore) {
-        mSnapshot->setClip(state.mClip.left, state.mClip.top,
+        writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
                 state.mClip.right, state.mClip.bottom);
         dirtyClip();
     }
@@ -1404,13 +1400,14 @@
  * This method should be called when restoreDisplayState() won't be restoring the clip
  */
 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
-    if (clipRect != NULL) {
-        mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+    if (clipRect != nullptr) {
+        writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
     } else {
-        mSnapshot->setClip(0, 0, getWidth(), getHeight());
+        writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
     }
     dirtyClip();
-    mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
+    bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
+    mRenderState.scissor().setEnabled(enableScissor);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1418,12 +1415,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::setScissorFromClip() {
-    Rect clip(*currentClipRect());
+    Rect clip(mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
-    if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
+    if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
             clip.getWidth(), clip.getHeight())) {
-        mDirtyClip = false;
+        mState.setDirtyClip(false);
     }
 }
 
@@ -1445,34 +1442,123 @@
         endTiling();
 
         RenderBuffer* buffer = mCaches.renderBufferCache.get(
-                Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
+                Stencil::getSmallestStencilFormat(),
+                layer->getWidth(), layer->getHeight());
         layer->setStencilRenderBuffer(buffer);
 
         startTiling(layer->clipRect, layer->layer.getHeight());
     }
 }
 
+static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
+        float x, float y) {
+    Vertex v;
+    v.x = x;
+    v.y = y;
+    transform.mapPoint(v.x, v.y);
+    rectangleVertices.push_back(v);
+}
+
+static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
+    Vertex v;
+    v.x = x;
+    v.y = y;
+    rectangleVertices.push_back(v);
+}
+
+void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
+    int quadCount = rectangleList.getTransformedRectanglesCount();
+    std::vector<Vertex> rectangleVertices(quadCount * 4);
+    Rect scissorBox = rectangleList.calculateBounds();
+    scissorBox.snapToPixelBoundaries();
+    for (int i = 0; i < quadCount; ++i) {
+        const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
+        const Matrix4& transform = tr.getTransform();
+        Rect bounds = tr.getBounds();
+        if (transform.rectToRect()) {
+            transform.mapRect(bounds);
+            if (!bounds.intersect(scissorBox)) {
+                bounds.setEmpty();
+            } else {
+                handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
+                handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
+                handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
+                handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
+            }
+        } else {
+            handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
+            handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
+            handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
+            handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
+        }
+    }
+
+    mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
+            scissorBox.getWidth(), scissorBox.getHeight());
+
+    if (USE_GLOPS) {
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4)
+                .setFillBlack()
+                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                .setModelViewOffsetRect(0, 0, scissorBox)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    const SkPaint* paint = nullptr;
+    setupDraw();
+    setupDrawNoTexture();
+    setupDrawColor(0, 0xff * currentSnapshot()->alpha);
+    setupDrawShader(getShader(paint));
+    setupDrawColorFilter(getColorFilter(paint));
+    setupDrawBlending(paint);
+    setupDrawProgram();
+    setupDrawDirtyRegionsDisabled();
+    setupDrawModelView(kModelViewMode_Translate, false,
+            0.0f, 0.0f, 0.0f, 0.0f, true);
+    setupDrawColorUniforms(getShader(paint));
+    setupDrawShaderUniforms(getShader(paint));
+    setupDrawColorFilterUniforms(getColorFilter(paint));
+
+    issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
+}
+
 void OpenGLRenderer::setStencilFromClip() {
     if (!mCaches.debugOverdraw) {
-        if (!currentSnapshot()->clipRegion->isEmpty()) {
+        if (!currentSnapshot()->clipIsSimple()) {
+            int incrementThreshold;
             EVENT_LOGD("setStencilFromClip - enabling");
 
             // NOTE: The order here is important, we must set dirtyClip to false
             //       before any draw call to avoid calling back into this method
-            mDirtyClip = false;
+            mState.setDirtyClip(false);
 
             ensureStencilBuffer();
 
-            mCaches.stencil.enableWrite();
+            const ClipArea& clipArea = currentSnapshot()->getClipArea();
 
-            // Clear and update the stencil, but first make sure we restrict drawing
+            bool isRectangleList = clipArea.isRectangleList();
+            if (isRectangleList) {
+                incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
+            } else {
+                incrementThreshold = 0;
+            }
+
+            mRenderState.stencil().enableWrite(incrementThreshold);
+
+            // Clean and update the stencil, but first make sure we restrict drawing
             // to the region's bounds
-            bool resetScissor = mCaches.enableScissor();
+            bool resetScissor = mRenderState.scissor().setEnabled(true);
             if (resetScissor) {
                 // The scissor was not set so we now need to update it
                 setScissorFromClip();
             }
-            mCaches.stencil.clear();
+
+            mRenderState.stencil().clear();
 
             // stash and disable the outline clip state, since stencil doesn't account for outline
             bool storedSkipOutlineClip = mSkipOutlineClip;
@@ -1482,28 +1568,34 @@
             paint.setColor(SK_ColorBLACK);
             paint.setXfermodeMode(SkXfermode::kSrc_Mode);
 
-            // NOTE: We could use the region contour path to generate a smaller mesh
-            //       Since we are using the stencil we could use the red book path
-            //       drawing technique. It might increase bandwidth usage though.
+            if (isRectangleList) {
+                drawRectangleList(clipArea.getRectangleList());
+            } else {
+                // NOTE: We could use the region contour path to generate a smaller mesh
+                //       Since we are using the stencil we could use the red book path
+                //       drawing technique. It might increase bandwidth usage though.
 
-            // The last parameter is important: we are not drawing in the color buffer
-            // so we don't want to dirty the current layer, if any
-            drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
-            if (resetScissor) mCaches.disableScissor();
+                // The last parameter is important: we are not drawing in the color buffer
+                // so we don't want to dirty the current layer, if any
+                drawRegionRects(clipArea.getClipRegion(), paint, false);
+            }
+            if (resetScissor) mRenderState.scissor().setEnabled(false);
             mSkipOutlineClip = storedSkipOutlineClip;
 
-            mCaches.stencil.enableTest();
+            mRenderState.stencil().enableTest(incrementThreshold);
 
             // Draw the region used to generate the stencil if the appropriate debug
             // mode is enabled
-            if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
+            // TODO: Implement for rectangle list clip areas
+            if (mCaches.debugStencilClip == Caches::kStencilShowRegion &&
+                    !clipArea.isRectangleList()) {
                 paint.setColor(0x7f0000ff);
                 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
-                drawRegionRects(*(currentSnapshot()->clipRegion), paint);
+                drawRegionRects(currentSnapshot()->getClipRegion(), paint);
             }
         } else {
             EVENT_LOGD("setStencilFromClip - disabling");
-            mCaches.stencil.disable();
+            mRenderState.stencil().disable();
         }
     }
 }
@@ -1528,13 +1620,13 @@
 
     bool clipRequired = false;
     bool roundRectClipRequired = false;
-    if (calculateQuickRejectForScissor(left, top, right, bottom,
+    if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
             &clipRequired, &roundRectClipRequired, snapOut)) {
         return true;
     }
 
     // not quick rejected, so enable the scissor if clipRequired
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
     mSkipOutlineClip = !roundRectClipRequired;
     return false;
 }
@@ -1550,6 +1642,27 @@
 #endif
 }
 
+void OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) {
+    // TODO: It would be best if we could do this before quickRejectSetupScissor()
+    //       changes the scissor test state
+    if (clearLayer) clearLayerRegions();
+
+    if (mState.getDirtyClip()) {
+        if (mRenderState.scissor().isEnabled()) {
+            setScissorFromClip();
+        }
+
+        setStencilFromClip();
+    }
+    mRenderState.render(glop);
+    if (!mRenderState.stencil().isWriteEnabled()) {
+        // TODO: specify more clearly when a draw should dirty the layer.
+        // is writing to the stencil the only time we should ignore this?
+        dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+        mDirty = true;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Drawing commands
 ///////////////////////////////////////////////////////////////////////////////
@@ -1560,8 +1673,8 @@
     if (clearLayer) clearLayerRegions();
     // Make sure setScissor & setStencil happen at the beginning of
     // this method
-    if (mDirtyClip) {
-        if (mCaches.scissorEnabled) {
+    if (mState.getDirtyClip()) {
+        if (mRenderState.scissor().isEnabled()) {
             setScissorFromClip();
         }
 
@@ -1572,15 +1685,15 @@
 
     mSetShaderColor = false;
     mColorSet = false;
-    mColorA = mColorR = mColorG = mColorB = 0.0f;
+    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
     mTextureUnit = 0;
     mTrackDirtyRegions = true;
 
     // Enable debug highlight when what we're about to draw is tested against
     // the stencil buffer and if stencil highlight debugging is on
-    mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
-            mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
-            mCaches.stencil.isTestEnabled();
+    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
+            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
+            && mRenderState.stencil().isTestEnabled();
 }
 
 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1599,7 +1712,7 @@
 }
 
 void OpenGLRenderer::setupDrawNoTexture() {
-    mCaches.disableTexCoordsVertexArray();
+    mRenderState.meshState().disableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
@@ -1608,21 +1721,21 @@
 }
 
 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
-    mColorA = alpha / 255.0f;
-    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
-    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
-    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
+    mColor.a = alpha / 255.0f;
+    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
+    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
     mColorSet = true;
-    mSetShaderColor = mDescription.setColorModulate(mColorA);
+    mSetShaderColor = mDescription.setColorModulate(mColor.a);
 }
 
 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
-    mColorA = alpha / 255.0f;
-    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
-    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
-    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
+    mColor.a = alpha / 255.0f;
+    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
+    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
+    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
     mColorSet = true;
-    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
+    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
 }
 
 void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
@@ -1630,38 +1743,38 @@
 }
 
 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
-    mColorA = a;
-    mColorR = r;
-    mColorG = g;
-    mColorB = b;
+    mColor.a = a;
+    mColor.r = r;
+    mColor.g = g;
+    mColor.b = b;
     mColorSet = true;
     mSetShaderColor = mDescription.setColorModulate(a);
 }
 
 void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
-    if (shader != NULL) {
-        SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
+    if (shader != nullptr) {
+        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
     }
 }
 
 void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
-    if (filter == NULL) {
+    if (filter == nullptr) {
         return;
     }
 
     SkXfermode::Mode mode;
-    if (filter->asColorMode(NULL, &mode)) {
+    if (filter->asColorMode(nullptr, &mode)) {
         mDescription.colorOp = ProgramDescription::kColorBlend;
         mDescription.colorMode = mode;
-    } else if (filter->asColorMatrix(NULL)) {
+    } else if (filter->asColorMatrix(nullptr)) {
         mDescription.colorOp = ProgramDescription::kColorMatrix;
     }
 }
 
 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
     if (mColorSet && mode == SkXfermode::kClear_Mode) {
-        mColorA = 1.0f;
-        mColorR = mColorG = mColorB = 0.0f;
+        mColor.a = 1.0f;
+        mColor.r = mColor.g = mColor.b = 0.0f;
         mSetShaderColor = mDescription.modulate = true;
     }
 }
@@ -1672,8 +1785,10 @@
     // argb=1,0,0,0
     accountForClear(mode);
     // TODO: check shader blending, once we have shader drawing support for layers.
-    bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
-            (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
+    bool blend = layer->isBlend()
+            || getLayerAlpha(layer) < 1.0f
+            || (mColorSet && mColor.a < 1.0f)
+            || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
@@ -1682,27 +1797,27 @@
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
-    blend |= (mColorSet && mColorA < 1.0f) ||
-            (getShader(paint) && !getShader(paint)->isOpaque()) ||
-            isBlendedColorFilter(getColorFilter(paint));
+    blend |= (mColorSet && mColor.a < 1.0f)
+            || (getShader(paint) && !getShader(paint)->isOpaque())
+            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
 void OpenGLRenderer::setupDrawProgram() {
-    useProgram(mCaches.programCache.get(mDescription));
+    mCaches.setProgram(mDescription);
     if (mDescription.hasRoundRectClip) {
         // TODO: avoid doing this repeatedly, stashing state pointer in program
-        const RoundRectClipState* state = mSnapshot->roundRectClipState;
+        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
         const Rect& innerRect = state->innerRect;
-        glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
+        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
                 innerRect.left, innerRect.top,
                 innerRect.right, innerRect.bottom);
-        glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
+        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
                 1, GL_FALSE, &state->matrix.data[0]);
 
         // add half pixel to round out integer rect space to cover pixel centers
         float roundedOutRadius = state->radius + 0.5f;
-        glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
+        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
                 roundedOutRadius);
     }
 }
@@ -1720,7 +1835,9 @@
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
     const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
-    mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+
+    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
+            mModelViewMatrix, transformMatrix, offset);
     if (dirty && mTrackDirtyRegions) {
         if (!ignoreTransform) {
             dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -1732,18 +1849,18 @@
 
 void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
     if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
-        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+        mCaches.program().setColor(mColor);
     }
 }
 
 void OpenGLRenderer::setupDrawPureColorUniforms() {
     if (mSetShaderColor) {
-        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+        mCaches.program().setColor(mColor);
     }
 }
 
 void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
-    if (shader == NULL) {
+    if (shader == nullptr) {
         return;
     }
 
@@ -1757,11 +1874,12 @@
         mModelViewMatrix.load(modelViewWithoutTransform);
     }
 
-    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
+    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
+            mCaches.extensions(), *shader);
 }
 
 void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
-    if (NULL == filter) {
+    if (nullptr == filter) {
         return;
     }
 
@@ -1773,7 +1891,7 @@
         const GLfloat r = a * SkColorGetR(color) / 255.0f;
         const GLfloat g = a * SkColorGetG(color) / 255.0f;
         const GLfloat b = a * SkColorGetB(color) / 255.0f;
-        glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
+        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
         return;
     }
 
@@ -1794,9 +1912,9 @@
         colorVector[2] = srcColorMatrix[14] / 255.0f;
         colorVector[3] = srcColorMatrix[19] / 255.0f;
 
-        glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
+        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
                 GL_FALSE, colorMatrix);
-        glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
+        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
         return;
     }
 
@@ -1804,25 +1922,25 @@
 }
 
 void OpenGLRenderer::setupDrawTextGammaUniforms() {
-    mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
+    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
 }
 
 void OpenGLRenderer::setupDrawSimpleMesh() {
-    bool force = mCaches.bindMeshBuffer();
-    mCaches.bindPositionVertexPointer(force, 0);
-    mCaches.unbindIndicesBuffer();
+    bool force = mRenderState.meshState().bindMeshBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
-    if (texture) bindTexture(texture);
+    if (texture) mCaches.textureState().bindTexture(texture);
     mTextureUnit++;
-    mCaches.enableTexCoordsVertexArray();
+    mRenderState.meshState().enableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
-    bindExternalTexture(texture);
+    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
     mTextureUnit++;
-    mCaches.enableTexCoordsVertexArray();
+    mRenderState.meshState().enableTexCoordsVertexArray();
 }
 
 void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1830,7 +1948,7 @@
 }
 
 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
-    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
             GL_FALSE, &transform.data[0]);
 }
 
@@ -1838,35 +1956,35 @@
         const GLvoid* texCoords, GLuint vbo) {
     bool force = false;
     if (!vertices || vbo) {
-        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+        force = mRenderState.meshState().bindMeshBuffer(vbo);
     } else {
-        force = mCaches.unbindMeshBuffer();
+        force = mRenderState.meshState().unbindMeshBuffer();
     }
 
-    mCaches.bindPositionVertexPointer(force, vertices);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
     }
 
-    mCaches.unbindIndicesBuffer();
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
         const GLvoid* texCoords, const GLvoid* colors) {
-    bool force = mCaches.unbindMeshBuffer();
+    bool force = mRenderState.meshState().unbindMeshBuffer();
     GLsizei stride = sizeof(ColorTextureVertex);
 
-    mCaches.bindPositionVertexPointer(force, vertices, stride);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
     }
-    int slot = mCaches.currentProgram->getAttrib("colors");
+    int slot = mCaches.program().getAttrib("colors");
     if (slot >= 0) {
         glEnableVertexAttribArray(slot);
         glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
     }
 
-    mCaches.unbindIndicesBuffer();
+    mRenderState.meshState().unbindIndicesBuffer();
 }
 
 void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
@@ -1874,86 +1992,83 @@
     bool force = false;
     // If vbo is != 0 we want to treat the vertices parameter as an offset inside
     // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
-    // use the default VBO found in Caches
+    // use the default VBO found in RenderState
     if (!vertices || vbo) {
-        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+        force = mRenderState.meshState().bindMeshBuffer(vbo);
     } else {
-        force = mCaches.unbindMeshBuffer();
+        force = mRenderState.meshState().unbindMeshBuffer();
     }
-    mCaches.bindQuadIndicesBuffer();
+    mRenderState.meshState().bindQuadIndicesBuffer();
 
-    mCaches.bindPositionVertexPointer(force, vertices);
-    if (mCaches.currentProgram->texCoords >= 0) {
-        mCaches.bindTexCoordsVertexPointer(force, texCoords);
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+    if (mCaches.program().texCoords >= 0) {
+        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
     }
 }
 
 void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
-    bool force = mCaches.unbindMeshBuffer();
-    mCaches.bindQuadIndicesBuffer();
-    mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
+    bool force = mRenderState.meshState().unbindMeshBuffer();
+    mRenderState.meshState().bindQuadIndicesBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
-    status_t status;
+void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (renderNode && renderNode->isRenderable()) {
         // compute 3d ordering
         renderNode->computeOrdering();
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
-            status = startFrame();
+            startFrame();
             ReplayStateStruct replayStruct(*this, dirty, replayFlags);
             renderNode->replay(replayStruct, 0);
-            return status | replayStruct.mDrawGlStatus;
+            return;
         }
 
         // Don't avoid overdraw when visualizing, since that makes it harder to
         // debug where it's coming from, and when the problem occurs.
         bool avoidOverdraw = !mCaches.debugOverdraw;
-        DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
+        DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
         renderNode->defer(deferStruct, 0);
 
         flushLayers();
-        status = startFrame();
+        startFrame();
 
-        return deferredList.flush(*this, dirty) | status;
+        deferredList.flush(*this, dirty);
+    } else {
+        // Even if there is no drawing command(Ex: invisible),
+        // it still needs startFrame to clear buffer and start tiling.
+        startFrame();
     }
-
-    // Even if there is no drawing command(Ex: invisible),
-    // it still needs startFrame to clear buffer and start tiling.
-    return startFrame();
 }
 
-void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
-    int color = paint != NULL ? paint->getColor() : 0;
-
-    float x = left;
-    float y = top;
+void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
+    float x = 0;
+    float y = 0;
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
     bool ignoreTransform = false;
     if (currentTransform()->isPureTranslate()) {
-        x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
-        y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+        x = floorf(currentTransform()->getTranslateX() + 0.5f);
+        y = floorf(currentTransform()->getTranslateY() + 0.5f);
         ignoreTransform = true;
 
         texture->setFilter(GL_NEAREST, true);
     } else {
-        texture->setFilter(getFilter(paint), true);
+        texture->setFilter(PaintUtils::getFilter(paint), true);
     }
 
     // No need to check for a UV mapper on the texture object, only ARGB_8888
     // bitmaps get packed in the atlas
     drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-            paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
-            GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
+            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
 }
 
 /**
@@ -1961,20 +2076,40 @@
  * will not set the scissor enable or dirty the current layer, if any.
  * The caller is responsible for properly dirtying the current layer.
  */
-status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
         int bitmapCount, TextureVertex* vertices, bool pureTranslate,
         const Rect& bounds, const SkPaint* paint) {
-    mCaches.activeTexture(0);
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) return;
 
     const AutoTexture autoCleanup(texture);
 
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
+    if (USE_GLOPS) {
+        // TODO: remove layer dirty in multi-draw callers
+        // TODO: snap doesn't need to touch transform, only texture filter.
+        bool snap = pureTranslate;
+        const float x = floorf(bounds.left + 0.5f);
+        const float y = floorf(bounds.top + 0.5f);
+        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedMesh(vertices, bitmapCount * 6)
+                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
 
-    const float x = (int) floorf(bounds.left + 0.5f);
-    const float y = (int) floorf(bounds.top + 0.5f);
+    mCaches.textureState().activateTexture(0);
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
+
+    const float x = floorf(bounds.left + 0.5f);
+    const float y = floorf(bounds.top + 0.5f);
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
                 texture->id, paint, &vertices[0].x, &vertices[0].u,
@@ -1987,76 +2122,67 @@
                 kModelViewMode_Translate, false);
     }
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
     if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
     Texture* texture = getTexture(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, 0, 0, paint);
-    } else {
-        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
+    if (USE_GLOPS) {
+        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUnitQuad(texture->uvMapper)
+                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
     }
 
-    return DrawGlInfo::kStatusDrew;
-}
-
-status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
-    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
-        return DrawGlInfo::kStatusDone;
-    }
-
-    mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.getTransient(bitmap);
-    const AutoTexture autoCleanup(texture);
-
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, 0, 0, paint);
+        drawAlphaBitmap(texture, paint);
     } else {
-        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
+        drawTextureRect(texture, paint);
     }
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
-    if (!vertices || currentSnapshot()->isIgnored()) {
-        return DrawGlInfo::kStatusDone;
+    if (!vertices || mState.currentlyIgnored()) {
+        return;
     }
 
-    // TODO: use quickReject on bounds from vertices
-    mCaches.enableScissor();
-
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-    const uint32_t count = meshWidth * meshHeight * 6;
+    const uint32_t elementCount = meshWidth * meshHeight * 6;
 
-    Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
-    mesh.setCapacity(count);
-    ColorTextureVertex* vertex = mesh.editArray();
+    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
+    ColorTextureVertex* vertex = &mesh[0];
 
-    bool cleanupColors = false;
+    std::unique_ptr<int[]> tempColors;
     if (!colors) {
         uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
-        int* newColors = new int[colorsCount];
-        memset(newColors, 0xff, colorsCount * sizeof(int));
-        colors = newColors;
-        cleanupColors = true;
+        tempColors.reset(new int[colorsCount]);
+        memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
+        colors = tempColors.get();
     }
 
-    mCaches.activeTexture(0);
     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
     const UvMapper& mapper(getMapper(texture));
 
@@ -2096,32 +2222,46 @@
     }
 
     if (quickRejectSetupScissor(left, top, right, bottom)) {
-        if (cleanupColors) delete[] colors;
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
     if (!texture) {
         texture = mCaches.textureCache.get(bitmap);
         if (!texture) {
-            if (cleanupColors) delete[] colors;
-            return DrawGlInfo::kStatusDone;
+            return;
         }
     }
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        /*
+         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
+         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
+         */
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshColoredTexturedMesh(mesh.get(), elementCount)
+                .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    mCaches.textureState().activateTexture(0);
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(getFilter(paint), true);
+    texture->setFilter(PaintUtils::getFilter(paint), true);
 
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+
+    dirtyLayer(left, top, right, bottom, *currentTransform());
+
     float a = alpha / 255.0f;
-
-    if (hasLayer()) {
-        dirtyLayer(left, top, right, bottom, *currentTransform());
-    }
-
     setupDraw();
     setupDrawWithTextureAndColor();
     setupDrawColor(a, a, a, a);
@@ -2129,177 +2269,177 @@
     setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
+    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
 
-    glDrawArrays(GL_TRIANGLES, 0, count);
+    glDrawArrays(GL_TRIANGLES, 0, elementCount);
 
-    int slot = mCaches.currentProgram->getAttrib("colors");
+    int slot = mCaches.program().getAttrib("colors");
     if (slot >= 0) {
         glDisableVertexAttribArray(slot);
     }
 
-    if (cleanupColors) delete[] colors;
-
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
-         float srcLeft, float srcTop, float srcRight, float srcBottom,
-         float dstLeft, float dstTop, float dstRight, float dstBottom,
-         const SkPaint* paint) {
-    if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
-        return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
+    if (quickRejectSetupScissor(dst)) {
+        return;
     }
 
-    mCaches.activeTexture(0);
     Texture* texture = getTexture(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        Rect uv(fmax(0.0f, src.left / texture->width),
+                fmax(0.0f, src.top / texture->height),
+                fmin(1.0f, src.right / texture->width),
+                fmin(1.0f, src.bottom / texture->height));
+
+        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUvQuad(texture->uvMapper, uv)
+                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(dst)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    mCaches.textureState().activateTexture(0);
+
     const float width = texture->width;
     const float height = texture->height;
 
-    float u1 = fmax(0.0f, srcLeft / width);
-    float v1 = fmax(0.0f, srcTop / height);
-    float u2 = fmin(1.0f, srcRight / width);
-    float v2 = fmin(1.0f, srcBottom / height);
+    float u1 = fmax(0.0f, src.left / width);
+    float v1 = fmax(0.0f, src.top / height);
+    float u2 = fmin(1.0f, src.right / width);
+    float v2 = fmin(1.0f, src.bottom / height);
 
     getMapper(texture).map(u1, v1, u2, v2);
 
-    mCaches.unbindMeshBuffer();
+    mRenderState.meshState().unbindMeshBuffer();
     resetDrawTextureTexCoords(u1, v1, u2, v2);
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
-    float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
+    float scaleX = (dst.right - dst.left) / (src.right - src.left);
+    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
 
     bool scaled = scaleX != 1.0f || scaleY != 1.0f;
-    // Apply a scale transform on the canvas only when a shader is in use
-    // Skia handles the ratio between the dst and src rects as a scale factor
-    // when a shader is set
-    bool useScaleTransform = getShader(paint) && scaled;
     bool ignoreTransform = false;
 
-    if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
-        float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
-        float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
+    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
+        float x = floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
+        float y = floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
 
-        dstRight = x + (dstRight - dstLeft);
-        dstBottom = y + (dstBottom - dstTop);
+        dst.right = x + (dst.right - dst.left);
+        dst.bottom = y + (dst.bottom - dst.top);
 
-        dstLeft = x;
-        dstTop = y;
+        dst.left = x;
+        dst.top = y;
 
-        texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
+        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
         ignoreTransform = true;
     } else {
-        texture->setFilter(getFilter(paint), true);
-    }
-
-    if (CC_UNLIKELY(useScaleTransform)) {
-        save(SkCanvas::kMatrix_SaveFlag);
-        translate(dstLeft, dstTop);
-        scale(scaleX, scaleY);
-
-        dstLeft = 0.0f;
-        dstTop = 0.0f;
-
-        dstRight = srcRight - srcLeft;
-        dstBottom = srcBottom - srcTop;
+        texture->setFilter(PaintUtils::getFilter(paint), true);
     }
 
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
+        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
                 texture->id, paint,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
     } else {
-        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
+        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
                 texture->id, paint, texture->blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
-    }
-
-    if (CC_UNLIKELY(useScaleTransform)) {
-        restore();
+                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
     }
 
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
-    if (quickRejectSetupScissor(left, top, right, bottom)) {
-        return DrawGlInfo::kStatusDone;
-    }
-
-    AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
-    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
-            right - left, bottom - top, patch);
-
-    return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
-}
-
-status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
+void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
         AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
         const SkPaint* paint) {
-    if (quickRejectSetupScissor(left, top, right, bottom)) {
-        return DrawGlInfo::kStatusDone;
+    if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) {
+        return;
     }
 
-    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
-        mCaches.activeTexture(0);
-        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
-        if (!texture) return DrawGlInfo::kStatusDone;
-        const AutoTexture autoCleanup(texture);
+    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
+    if (!texture) return;
 
-        texture->setWrap(GL_CLAMP_TO_EDGE, true);
-        texture->setFilter(GL_LINEAR, true);
+    if (USE_GLOPS) {
+        // 9 patches are built for stretching - always filter
+        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
+        if (bitmap->colorType() == kAlpha_8_SkColorType) {
+            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
+        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshPatchQuads(*mesh)
+                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
 
-        const bool pureTranslate = currentTransform()->isPureTranslate();
-        // Mark the current layer dirty where we are going to draw the patch
-        if (hasLayer() && mesh->hasEmptyQuads) {
-            const float offsetX = left + currentTransform()->getTranslateX();
-            const float offsetY = top + currentTransform()->getTranslateY();
-            const size_t count = mesh->quads.size();
-            for (size_t i = 0; i < count; i++) {
-                const Rect& bounds = mesh->quads.itemAt(i);
-                if (CC_LIKELY(pureTranslate)) {
-                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
-                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
-                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
-                } else {
-                    dirtyLayer(left + bounds.left, top + bounds.top,
-                            left + bounds.right, top + bounds.bottom, *currentTransform());
-                }
+    mCaches.textureState().activateTexture(0);
+    const AutoTexture autoCleanup(texture);
+
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(GL_LINEAR, true);
+
+    const bool pureTranslate = currentTransform()->isPureTranslate();
+    // Mark the current layer dirty where we are going to draw the patch
+    if (hasLayer() && mesh->hasEmptyQuads) {
+        const float offsetX = left + currentTransform()->getTranslateX();
+        const float offsetY = top + currentTransform()->getTranslateY();
+        const size_t count = mesh->quads.size();
+        for (size_t i = 0; i < count; i++) {
+            const Rect& bounds = mesh->quads.itemAt(i);
+            if (CC_LIKELY(pureTranslate)) {
+                const float x = floorf(bounds.left + offsetX + 0.5f);
+                const float y = floorf(bounds.top + offsetY + 0.5f);
+                dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
+            } else {
+                dirtyLayer(left + bounds.left, top + bounds.top,
+                        left + bounds.right, top + bounds.bottom, *currentTransform());
             }
         }
-
-        bool ignoreTransform = false;
-        if (CC_LIKELY(pureTranslate)) {
-            const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
-            const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
-
-            right = x + right - left;
-            bottom = y + bottom - top;
-            left = x;
-            top = y;
-            ignoreTransform = true;
-        }
-        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
-                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
-                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
-                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
     }
 
-    return DrawGlInfo::kStatusDrew;
+    bool ignoreTransform = false;
+    if (CC_LIKELY(pureTranslate)) {
+        const float x = floorf(left + currentTransform()->getTranslateX() + 0.5f);
+        const float y = floorf(top + currentTransform()->getTranslateY() + 0.5f);
+
+        right = x + right - left;
+        bottom = y + bottom - top;
+        left = x;
+        top = y;
+        ignoreTransform = true;
+    }
+    drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
+            texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset,
+            GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
+            mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
+
+    mDirty = true;
 }
 
 /**
@@ -2307,42 +2447,77 @@
  * will not set the scissor enable or dirty the current layer, if any.
  * The caller is responsible for properly dirtying the current layer.
  */
-status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
-        TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
-    mCaches.activeTexture(0);
+void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+        TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) {
+    mCaches.textureState().activateTexture(0);
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        // TODO: get correct bounds from caller
+        // 9 patches are built for stretching - always filter
+        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
+        if (bitmap->colorType() == kAlpha_8_SkColorType) {
+            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
+        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedIndexedQuads(vertices, elementCount)
+                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
     texture->setFilter(GL_LINEAR, true);
 
     drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
             texture->blend, &vertices[0].x, &vertices[0].u,
-            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
+            GL_TRIANGLES, elementCount, false, true, 0, kModelViewMode_Translate, false);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
+void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
         const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
     // not missing call to quickReject/dirtyLayer, always done at a higher level
     if (!vertexBuffer.getVertexCount()) {
         // no vertices to draw
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
+    if (USE_GLOPS) {
+        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
+        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
     Rect bounds(vertexBuffer.getBounds());
     bounds.translate(translateX, translateY);
     dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
 
     int color = paint->getColor();
-    bool isAA = paint->isAntiAlias();
+    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
 
     setupDraw();
     setupDrawNoTexture();
     if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
-    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
+    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader(getShader(paint));
     setupDrawBlending(paint, isAA);
@@ -2354,40 +2529,34 @@
     setupDrawShaderUniforms(getShader(paint));
 
     const void* vertices = vertexBuffer.getBuffer();
-    bool force = mCaches.unbindMeshBuffer();
-    mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
-    mCaches.resetTexCoordsVertexPointer();
+    mRenderState.meshState().unbindMeshBuffer();
+    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
+            isAA ? kAlphaVertexStride : kVertexStride);
+    mRenderState.meshState().resetTexCoordsVertexPointer();
 
     int alphaSlot = -1;
     if (isAA) {
-        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
-        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
+        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
+        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
         // TODO: avoid enable/disable in back to back uses of the alpha attribute
         glEnableVertexAttribArray(alphaSlot);
-        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
+        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
     }
 
-    const VertexBuffer::Mode mode = vertexBuffer.getMode();
-    if (mode == VertexBuffer::kStandard) {
-        mCaches.unbindIndicesBuffer();
+    if (meshFeatureFlags & VertexBuffer::kIndices) {
+        mRenderState.meshState().unbindIndicesBuffer();
+        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
+                GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
+    } else {
+        mRenderState.meshState().unbindIndicesBuffer();
         glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
-    } else if (mode == VertexBuffer::kOnePolyRingShadow) {
-        mCaches.bindShadowIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
-    } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
-        mCaches.bindShadowIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
-    } else if (mode == VertexBuffer::kIndices) {
-        mCaches.unbindIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT,
-                vertexBuffer.getIndices());
     }
 
     if (isAA) {
         glDisableVertexAttribArray(alphaSlot);
     }
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
 /**
@@ -2399,11 +2568,11 @@
  *
  * Doesn't yet support joins, caps, or path effects.
  */
-status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
+void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
     VertexBuffer vertexBuffer;
     // TODO: try clipping large paths to viewport
     PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
-    return drawVertexBuffer(vertexBuffer, paint);
+    drawVertexBuffer(vertexBuffer, paint);
 }
 
 /**
@@ -2417,8 +2586,8 @@
  * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
  * memory transfer by removing need for degenerate vertices.
  */
-status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
+    if (mState.currentlyIgnored() || count < 4) return;
 
     count &= ~0x3; // round down to nearest four
 
@@ -2427,15 +2596,15 @@
     const Rect& bounds = buffer.getBounds();
 
     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
-    return drawVertexBuffer(buffer, paint, displayFlags);
+    drawVertexBuffer(buffer, paint, displayFlags);
 }
 
-status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
+    if (mState.currentlyIgnored() || count < 2) return;
 
     count &= ~0x1; // round down to nearest two
 
@@ -2444,18 +2613,20 @@
 
     const Rect& bounds = buffer.getBounds();
     if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
     int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
-    return drawVertexBuffer(buffer, paint, displayFlags);
+    drawVertexBuffer(buffer, paint, displayFlags);
+
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
+void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     // No need to check against the clip, we fill the clip region
-    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+    if (mState.currentlyIgnored()) return;
 
-    Rect clip(*currentClipRect());
+    Rect clip(mState.currentClipRect());
     clip.snapToPixelBoundaries();
 
     SkPaint paint;
@@ -2464,12 +2635,12 @@
 
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
+void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
         const SkPaint* paint) {
-    if (!texture) return DrawGlInfo::kStatusDone;
+    if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
     const float x = left + texture->left - texture->offset;
@@ -2477,89 +2648,89 @@
 
     drawPathTexture(texture, x, y, paint);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
-            || paintWillNotDraw(*p)) {
-        return DrawGlInfo::kStatusDone;
+            || PaintUtils::paintWillNotDraw(*p)) {
+        return;
     }
 
-    if (p->getPathEffect() != 0) {
-        mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.pathCache.getRoundRect(
+    if (p->getPathEffect() != nullptr) {
+        mCaches.textureState().activateTexture(0);
+        PathTexture* texture = mCaches.pathCache.getRoundRect(
                 right - left, bottom - top, rx, ry, p);
-        return drawShape(left, top, texture, p);
-    }
-
-    const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
-            *currentTransform(), *p, right - left, bottom - top, rx, ry);
-    return drawVertexBuffer(left, top, *vertexBuffer, p);
-}
-
-status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
-            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
-            || paintWillNotDraw(*p)) {
-        return DrawGlInfo::kStatusDone;
-    }
-    if (p->getPathEffect() != 0) {
-        mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
-        return drawShape(x - radius, y - radius, texture, p);
-    }
-
-    SkPath path;
-    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
-        path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
+        drawShape(left, top, texture, p);
     } else {
-        path.addCircle(x, y, radius);
+        const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
+                *currentTransform(), *p, right - left, bottom - top, rx, ry);
+        drawVertexBuffer(left, top, *vertexBuffer, p);
     }
-    return drawConvexPath(path, p);
 }
 
-status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
+    if (mState.currentlyIgnored()
+            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
+            || PaintUtils::paintWillNotDraw(*p)) {
+        return;
+    }
+    if (p->getPathEffect() != nullptr) {
+        mCaches.textureState().activateTexture(0);
+        PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
+        drawShape(x - radius, y - radius, texture, p);
+    } else {
+        SkPath path;
+        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+            path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
+        } else {
+            path.addCircle(x, y, radius);
+        }
+        drawConvexPath(path, p);
+    }
+}
+
+void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
-            || paintWillNotDraw(*p)) {
-        return DrawGlInfo::kStatusDone;
+            || PaintUtils::paintWillNotDraw(*p)) {
+        return;
     }
 
-    if (p->getPathEffect() != 0) {
-        mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
-        return drawShape(left, top, texture, p);
+    if (p->getPathEffect() != nullptr) {
+        mCaches.textureState().activateTexture(0);
+        PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
+        drawShape(left, top, texture, p);
+    } else {
+        SkPath path;
+        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
+        }
+        path.addOval(rect);
+        drawConvexPath(path, p);
     }
-
-    SkPath path;
-    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
-        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
-    }
-    path.addOval(rect);
-    return drawConvexPath(path, p);
 }
 
-status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
-            || paintWillNotDraw(*p)) {
-        return DrawGlInfo::kStatusDone;
+            || PaintUtils::paintWillNotDraw(*p)) {
+        return;
     }
 
     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
-    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
-        mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
+    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
+        mCaches.textureState().activateTexture(0);
+        PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
                 startAngle, sweepAngle, useCenter, p);
-        return drawShape(left, top, texture, p);
+        drawShape(left, top, texture, p);
+        return;
     }
-
     SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
     if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
         rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
@@ -2573,53 +2744,54 @@
     if (useCenter) {
         path.close();
     }
-    return drawConvexPath(path, p);
+    drawConvexPath(path, p);
 }
 
 // See SkPaintDefaults.h
 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
 
-status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
         const SkPaint* p) {
-    if (currentSnapshot()->isIgnored()
+    if (mState.currentlyIgnored()
             || quickRejectSetupScissor(left, top, right, bottom, p)
-            || paintWillNotDraw(*p)) {
-        return DrawGlInfo::kStatusDone;
+            || PaintUtils::paintWillNotDraw(*p)) {
+        return;
     }
 
     if (p->getStyle() != SkPaint::kFill_Style) {
         // only fill style is supported by drawConvexPath, since others have to handle joins
-        if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
+        if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
-            mCaches.activeTexture(0);
-            const PathTexture* texture =
+            mCaches.textureState().activateTexture(0);
+            PathTexture* texture =
                     mCaches.pathCache.getRect(right - left, bottom - top, p);
-            return drawShape(left, top, texture, p);
+            drawShape(left, top, texture, p);
+        } else {
+            SkPath path;
+            SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+            if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+                rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
+            }
+            path.addRect(rect);
+            drawConvexPath(path, p);
         }
-
-        SkPath path;
-        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
-        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
-            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
-        }
-        path.addRect(rect);
-        return drawConvexPath(path, p);
-    }
-
-    if (p->isAntiAlias() && !currentTransform()->isSimple()) {
-        SkPath path;
-        path.addRect(left, top, right, bottom);
-        return drawConvexPath(path, p);
     } else {
-        drawColorRect(left, top, right, bottom, p);
-        return DrawGlInfo::kStatusDrew;
+        if (p->isAntiAlias() && !currentTransform()->isSimple()) {
+            SkPath path;
+            path.addRect(left, top, right, bottom);
+            drawConvexPath(path, p);
+        } else {
+            drawColorRect(left, top, right, bottom, p);
+
+            mDirty = true;
+        }
     }
 }
 
 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
         int bytesCount, int count, const float* positions,
         FontRenderer& fontRenderer, int alpha, float x, float y) {
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
     TextShadow textShadow;
     if (!getTextShadow(paint, &textShadow)) {
@@ -2629,17 +2801,30 @@
     // NOTE: The drop shadow will not perform gamma correction
     //       if shader-based correction is enabled
     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
-    const ShadowTexture* shadow = mCaches.dropShadowCache.get(
+    ShadowTexture* texture = mCaches.dropShadowCache.get(
             paint, text, bytesCount, count, textShadow.radius, positions);
     // If the drop shadow exceeds the max texture size or couldn't be
     // allocated, skip drawing
-    if (!shadow) return;
-    const AutoTexture autoCleanup(shadow);
+    if (!texture) return;
+    const AutoTexture autoCleanup(texture);
 
-    const float sx = x - shadow->left + textShadow.dx;
-    const float sy = y - shadow->top + textShadow.dy;
+    const float sx = x - texture->left + textShadow.dx;
+    const float sy = y - texture->top + textShadow.dy;
 
-    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
+    if (USE_GLOPS) {
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUnitQuad(nullptr)
+                .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha;
     if (getShader(paint)) {
         textShadow.color = SK_ColorWHITE;
     }
@@ -2652,40 +2837,41 @@
     setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-            sx, sy, sx + shadow->width, sy + shadow->height);
-    setupDrawTexture(shadow->id);
+            sx, sy, sx + texture->width, sy + texture->height);
+    setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
+    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
-    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
-    return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
+    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
+    return MathUtils::isZero(alpha)
+            && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
-status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
+void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, const SkPaint* paint) {
-    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
-        return DrawGlInfo::kStatusDone;
+    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
+        return;
     }
 
     // NOTE: Skia does not support perspective transform on drawPosText yet
     if (!currentTransform()->isSimple()) {
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
-    mCaches.enableScissor();
+    mRenderState.scissor().setEnabled(true);
 
     float x = 0.0f;
     float y = 0.0f;
     const bool pureTranslate = currentTransform()->isPureTranslate();
     if (pureTranslate) {
-        x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
-        y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
+        x = floorf(x + currentTransform()->getTranslateX() + 0.5f);
+        y = floorf(y + currentTransform()->getTranslateY() + 0.5f);
     }
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
@@ -2707,23 +2893,16 @@
     }
     fontRenderer.setTextureFiltering(linearFilter);
 
-    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
+    const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-    const bool hasActiveLayer = hasLayer();
-
     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
-    if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-            positions, hasActiveLayer ? &bounds : NULL, &functor)) {
-        if (hasActiveLayer) {
-            if (!pureTranslate) {
-                currentTransform()->mapRect(bounds);
-            }
-            dirtyLayerUnchecked(bounds, getRegion());
-        }
+    if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
+            positions, hasLayer() ? &bounds : nullptr, &functor)) {
+        dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
+        mDirty = true;
     }
 
-    return DrawGlInfo::kStatusDrew;
 }
 
 bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
@@ -2747,16 +2926,77 @@
     return true;
 }
 
-status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
+int OpenGLRenderer::getSaveCount() const {
+    return mState.getSaveCount();
+}
+
+int OpenGLRenderer::save(int flags) {
+    return mState.save(flags);
+}
+
+void OpenGLRenderer::restore() {
+    return mState.restore();
+}
+
+void OpenGLRenderer::restoreToCount(int saveCount) {
+    return mState.restoreToCount(saveCount);
+}
+
+void OpenGLRenderer::translate(float dx, float dy, float dz) {
+    return mState.translate(dx, dy, dz);
+}
+
+void OpenGLRenderer::rotate(float degrees) {
+    return mState.rotate(degrees);
+}
+
+void OpenGLRenderer::scale(float sx, float sy) {
+    return mState.scale(sx, sy);
+}
+
+void OpenGLRenderer::skew(float sx, float sy) {
+    return mState.skew(sx, sy);
+}
+
+void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
+    mState.setMatrix(matrix);
+}
+
+void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
+    mState.concatMatrix(matrix);
+}
+
+bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+    return mState.clipRect(left, top, right, bottom, op);
+}
+
+bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
+    return mState.clipPath(path, op);
+}
+
+bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
+    return mState.clipRegion(region, op);
+}
+
+void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+    mState.setClippingOutline(allocator, outline);
+}
+
+void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
+        const Rect& rect, float radius, bool highPriority) {
+    mState.setClippingRoundRect(allocator, rect, radius, highPriority);
+}
+
+void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
         DrawOpMode drawOpMode) {
 
-    if (drawOpMode == kDrawOpMode_Immediate) {
+    if (drawOpMode == DrawOpMode::kImmediate) {
         // The checks for corner-case ignorable text and quick rejection is only done for immediate
         // drawing as ops from DeferredDisplayList are already filtered for these
-        if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
+        if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
                 quickRejectSetupScissor(bounds)) {
-            return DrawGlInfo::kStatusDone;
+            return;
         }
     }
 
@@ -2767,8 +3007,8 @@
     const bool pureTranslate = transform.isPureTranslate();
 
     if (CC_LIKELY(pureTranslate)) {
-        x = (int) floorf(x + transform.getTranslateX() + 0.5f);
-        y = (int) floorf(y + transform.getTranslateY() + 0.5f);
+        x = floorf(x + transform.getTranslateX() + 0.5f);
+        y = floorf(y + transform.getTranslateY() + 0.5f);
     }
 
     int alpha;
@@ -2804,25 +3044,25 @@
     fontRenderer.setTextureFiltering(linearFilter);
 
     // TODO: Implement better clipping for scaled/rotated text
-    const Rect* clip = !pureTranslate ? NULL : currentClipRect();
+    const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
 
     // don't call issuedrawcommand, do it at end of batch
-    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
+    bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
         SkPaint paintCopy(*paint);
         paintCopy.setTextAlign(SkPaint::kLeft_Align);
         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
+                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
     } else {
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
+                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
     }
 
-    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
+    if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
         if (!pureTranslate) {
             transform.mapRect(layerBounds);
         }
@@ -2831,17 +3071,17 @@
 
     drawTextDecorations(totalAdvance, oldX, oldY, paint);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
+void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
         const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
-    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
-        return DrawGlInfo::kStatusDone;
+    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
+        return;
     }
 
     // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
-    mCaches.enableScissor();
+    mRenderState.scissor().setEnabled(true);
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, SkMatrix::I());
@@ -2852,45 +3092,38 @@
     getAlphaAndMode(paint, &alpha, &mode);
     TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
-    const Rect* clip = &mSnapshot->getLocalClip();
+    const Rect* clip = &writableSnapshot()->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-    const bool hasActiveLayer = hasLayer();
-
     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
-            hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
-        if (hasActiveLayer) {
-            currentTransform()->mapRect(bounds);
-            dirtyLayerUnchecked(bounds, getRegion());
-        }
+            hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
+        dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
+        mDirty = true;
     }
-
-    return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
+    if (mState.currentlyIgnored()) return;
 
-    mCaches.activeTexture(0);
+    mCaches.textureState().activateTexture(0);
 
-    const PathTexture* texture = mCaches.pathCache.get(path, paint);
-    if (!texture) return DrawGlInfo::kStatusDone;
+    PathTexture* texture = mCaches.pathCache.get(path, paint);
+    if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
     const float x = texture->left - texture->offset;
     const float y = texture->top - texture->offset;
 
     drawPathTexture(texture, x, y, paint);
-
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
-status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
+void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
     if (!layer) {
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
-    mat4* transform = NULL;
+    mat4* transform = nullptr;
     if (layer->isTextureLayer()) {
         transform = &layer->getTransform();
         if (!transform->isIdentity()) {
@@ -2900,14 +3133,15 @@
     }
 
     bool clipRequired = false;
-    const bool rejected = calculateQuickRejectForScissor(x, y,
-            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
+    const bool rejected = mState.calculateQuickRejectForScissor(
+            x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+            &clipRequired, nullptr, false);
 
     if (rejected) {
         if (transform && !transform->isIdentity()) {
             restore();
         }
-        return DrawGlInfo::kStatusDone;
+        return;
     }
 
     EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
@@ -2915,54 +3149,64 @@
 
     updateLayer(layer, true);
 
-    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
-    mCaches.activeTexture(0);
+    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
+    mCaches.textureState().activateTexture(0);
 
     if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
                     composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
-
-            const float a = getLayerAlpha(layer);
-            setupDraw();
-            setupDrawWithTexture();
-            setupDrawColor(a, a, a, a);
-            setupDrawColorFilter(layer->getColorFilter());
-            setupDrawBlending(layer);
-            setupDrawProgram();
-            setupDrawPureColorUniforms();
-            setupDrawColorFilterUniforms(layer->getColorFilter());
-            setupDrawTexture(layer->getTexture());
-            if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-                int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
-                int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
-
-                layer->setFilter(GL_NEAREST);
-                setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
-                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
+            if (USE_GLOPS) {
+                Glop glop;
+                GlopBuilder(mRenderState, mCaches, &glop)
+                        .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
+                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                        .build();
+                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
             } else {
-                layer->setFilter(GL_LINEAR);
-                setupDrawModelView(kModelViewMode_Translate, false, x, y,
-                        x + layer->layer.getWidth(), y + layer->layer.getHeight());
+                const float a = getLayerAlpha(layer);
+                setupDraw();
+                setupDrawWithTexture();
+                setupDrawColor(a, a, a, a);
+                setupDrawColorFilter(layer->getColorFilter());
+                setupDrawBlending(layer);
+                setupDrawProgram();
+                setupDrawPureColorUniforms();
+                setupDrawColorFilterUniforms(layer->getColorFilter());
+                setupDrawTexture(layer->getTextureId());
+                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
+                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
+                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
+
+                    layer->setFilter(GL_NEAREST);
+                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
+                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
+                } else {
+                    layer->setFilter(GL_LINEAR);
+                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
+                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
+                }
+
+                TextureVertex* mesh = &layer->mesh[0];
+                GLsizei elementsCount = layer->meshElementCount;
+
+                while (elementsCount > 0) {
+                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+
+                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
+                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
+
+                    elementsCount -= drawCount;
+                    // Though there are 4 vertices in a quad, we use 6 indices per
+                    // quad to draw with GL_TRIANGLES
+                    mesh += (drawCount / 6) * 4;
+                }
             }
-
-            TextureVertex* mesh = &layer->mesh[0];
-            GLsizei elementsCount = layer->meshElementCount;
-
-            while (elementsCount > 0) {
-                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
-
-                setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
-                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
-                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
-
-                elementsCount -= drawCount;
-                // Though there are 4 vertices in a quad, we use 6 indices per
-                // quad to draw with GL_TRIANGLES
-                mesh += (drawCount / 6) * 4;
-            }
-
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRectsDebug(layer->region);
 #endif
@@ -2982,53 +3226,16 @@
         restore();
     }
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Draw filters
 ///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetPaintFilter() {
-    // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
-    // comparison, see MergingDrawBatch::canMergeWith
-    mDrawModifiers.mHasDrawFilter = false;
-    mDrawModifiers.mPaintFilterClearBits = 0;
-    mDrawModifiers.mPaintFilterSetBits = 0;
-}
-
-void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
-    // TODO: don't bother with boolean, it's redundant with clear/set bits
-    mDrawModifiers.mHasDrawFilter = true;
-    mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
-    mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
-}
-
-const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
-    // TODO: use CompatFlagsDrawFilter here, and combine logic with android/graphics/DrawFilter.cpp
-    // to avoid clobbering 0x02 paint flag
-
-    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
-    static const uint32_t sFilterBitmapFlag = 0x02;
-
-    if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
-        return paint;
-    }
-
-    const uint32_t clearBits = mDrawModifiers.mPaintFilterClearBits;
-    const uint32_t setBits = mDrawModifiers.mPaintFilterSetBits;
-
-    const uint32_t flags = (paint->getFlags() & ~clearBits) | setBits;
-    mFilteredPaint = *paint;
-    mFilteredPaint.setFlags(flags);
-
-    // check if paint filter trying to override bitmap filter
-    if ((clearBits | setBits) & sFilterBitmapFlag) {
-        mFilteredPaint.setFilterLevel(flags & sFilterBitmapFlag
-                ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel);
-    }
-
-    return &mFilteredPaint;
+void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
+    // We should never get here since we apply the draw filter when stashing
+    // the paints in the DisplayList.
+    LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -3043,12 +3250,26 @@
     return texture;
 }
 
-void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
-        float x, float y, const SkPaint* paint) {
+void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
+        const SkPaint* paint) {
     if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
         return;
     }
 
+    if (USE_GLOPS) {
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUnitQuad(nullptr)
+                .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
@@ -3066,9 +3287,9 @@
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
+    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
 // Same values used by Skia
@@ -3121,28 +3342,20 @@
     }
 }
 
-status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
-    if (currentSnapshot()->isIgnored()) {
-        return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+    if (mState.currentlyIgnored()) {
+        return;
     }
 
-    return drawColorRects(rects, count, paint, false, true, true);
+    drawColorRects(rects, count, paint, false, true, true);
 }
 
-static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) {
-    // map z coordinate with true 3d matrix
-    point.z = transformZ.mapZ(point);
-
-    // map x,y coordinates with draw/Skia matrix
-    transformXY.mapPoint(point.x, point.y);
-}
-
-status_t OpenGLRenderer::drawShadow(float casterAlpha,
+void OpenGLRenderer::drawShadow(float casterAlpha,
         const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
-    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+    if (mState.currentlyIgnored()) return;
 
     // TODO: use quickRejectWithScissor. For now, always force enable scissor.
-    mCaches.enableScissor();
+    mRenderState.scissor().setEnabled(true);
 
     SkPaint paint;
     paint.setAntiAlias(true); // want to use AlphaVertex
@@ -3166,19 +3379,13 @@
         drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
     }
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty=true;
 }
 
-status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
+void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
         bool ignoreTransform, bool dirty, bool clip) {
     if (count == 0) {
-        return DrawGlInfo::kStatusDone;
-    }
-
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (getShader(paint)) {
-        color |= 0x00ffffff;
+        return;
     }
 
     float left = FLT_MAX;
@@ -3207,7 +3414,27 @@
     }
 
     if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
-        return DrawGlInfo::kStatusDone;
+        return;
+    }
+
+    if (USE_GLOPS) {
+        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshIndexedQuads(&mesh[0], count / 4)
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    int color = paint->getColor();
+    // If a shader is set, preserve only the alpha
+    if (getShader(paint)) {
+        color |= 0x00ffffff;
     }
 
     setupDraw();
@@ -3230,11 +3457,26 @@
 
     issueIndexedQuadDraw(&mesh[0], count / 4);
 
-    return DrawGlInfo::kStatusDrew;
+    mDirty = true;
 }
 
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
         const SkPaint* paint, bool ignoreTransform) {
+
+    if (USE_GLOPS) {
+        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshUnitQuad()
+                .setFillPaint(*paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
     int color = paint->getColor();
     // If a shader is set, preserve only the alpha
     if (getShader(paint)) {
@@ -3255,15 +3497,14 @@
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawSimpleMesh();
 
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
 }
 
-void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        Texture* texture, const SkPaint* paint) {
+void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    GLvoid* vertices = (GLvoid*) NULL;
-    GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
+    GLvoid* vertices = (GLvoid*) nullptr;
+    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
 
     if (texture->uvMapper) {
         vertices = &mMeshVertices[0].x;
@@ -3276,17 +3517,17 @@
     }
 
     if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-        const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
+        const float x = floorf(currentTransform()->getTranslateX() + 0.5f);
+        const float y = floorf(currentTransform()->getTranslateY() + 0.5f);
 
         texture->setFilter(GL_NEAREST, true);
         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
                 paint, texture->blend, vertices, texCoords,
-                GL_TRIANGLE_STRIP, gMeshCount, false, true);
+                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
     } else {
-        texture->setFilter(getFilter(paint), true);
-        drawTextureMesh(left, top, right, bottom, texture->id, paint,
-                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
+        texture->setFilter(PaintUtils::getFilter(paint), true);
+        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
+                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
     }
 
     if (texture->uvMapper) {
@@ -3345,7 +3586,7 @@
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMeshIndices(vertices, texCoords, vbo);
 
-    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
+    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
 }
 
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
@@ -3353,14 +3594,14 @@
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
         bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
 
-    int color = paint != NULL ? paint->getColor() : 0;
+    int color = paint != nullptr ? paint->getColor() : 0;
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
     setupDraw();
     setupDrawWithTexture(true);
-    if (paint != NULL) {
+    if (paint != nullptr) {
         setupDrawAlpha8Color(color, alpha);
     }
     setupDrawColorFilter(getColorFilter(paint));
@@ -3381,7 +3622,7 @@
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
         ProgramDescription& description, bool swapSrcDst) {
 
-    if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
+    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
         blend = true;
         mDescription.hasRoundRectClip = true;
     }
@@ -3396,47 +3637,21 @@
         // If the blend mode cannot be implemented using shaders, fall
         // back to the default SrcOver blend mode instead
         if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
-            if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
+            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
                 description.framebufferMode = mode;
                 description.swapSrcDst = swapSrcDst;
 
-                if (mCaches.blend) {
-                    glDisable(GL_BLEND);
-                    mCaches.blend = false;
-                }
-
+                mRenderState.blend().disable();
                 return;
             } else {
                 mode = SkXfermode::kSrcOver_Mode;
             }
         }
-
-        if (!mCaches.blend) {
-            glEnable(GL_BLEND);
-        }
-
-        GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
-        GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
-
-        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
-            glBlendFunc(sourceMode, destMode);
-            mCaches.lastSrcMode = sourceMode;
-            mCaches.lastDstMode = destMode;
-        }
-    } else if (mCaches.blend) {
-        glDisable(GL_BLEND);
+        mRenderState.blend().enable(mode,
+                swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap);
+    } else {
+        mRenderState.blend().disable();
     }
-    mCaches.blend = blend;
-}
-
-bool OpenGLRenderer::useProgram(Program* program) {
-    if (!program->isInUse()) {
-        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
-        program->use();
-        mCaches.currentProgram = program;
-        return false;
-    }
-    return true;
 }
 
 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
@@ -3447,7 +3662,8 @@
     TextureVertex::setUV(v++, u2, v2);
 }
 
-void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
+void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
+        SkXfermode::Mode* mode) const {
     getAlphaAndModeDirect(paint, alpha,  mode);
     if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
         // if drawing a layer, ignore the paint's alpha
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5eee2e2..f4acad0 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -17,6 +17,18 @@
 #ifndef ANDROID_HWUI_OPENGL_RENDERER_H
 #define ANDROID_HWUI_OPENGL_RENDERER_H
 
+#include "CanvasState.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "Matrix.h"
+#include "Program.h"
+#include "Rect.h"
+#include "Snapshot.h"
+#include "UvMapper.h"
+#include "Vertex.h"
+#include "Caches.h"
+#include "utils/PaintUtils.h"
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
@@ -38,45 +50,33 @@
 
 #include <androidfw/ResourceTypes.h>
 
-#include "Debug.h"
-#include "Extensions.h"
-#include "Matrix.h"
-#include "Program.h"
-#include "Rect.h"
-#include "Renderer.h"
-#include "Snapshot.h"
-#include "StatefulBaseRenderer.h"
-#include "UvMapper.h"
-#include "Vertex.h"
-#include "Caches.h"
-#include "CanvasProperty.h"
-
 class SkShader;
 
 namespace android {
 namespace uirenderer {
 
+enum class DrawOpMode {
+    kImmediate,
+    kDefer,
+    kFlush
+};
+
 class DeferredDisplayState;
+struct Glop;
 class RenderState;
 class RenderNode;
 class TextSetupFunctor;
 class VertexBuffer;
 
 struct DrawModifiers {
-    DrawModifiers() {
-        reset();
-    }
+    DrawModifiers()
+        : mOverrideLayerAlpha(0.0f) {}
 
     void reset() {
-        memset(this, 0, sizeof(DrawModifiers));
+        mOverrideLayerAlpha = 0.0f;
     }
 
     float mOverrideLayerAlpha;
-
-    // Draw filters
-    bool mHasDrawFilter;
-    int mPaintFilterClearBits;
-    int mPaintFilterSetBits;
 };
 
 enum StateDeferFlags {
@@ -123,20 +123,59 @@
 /**
  * OpenGL Renderer implementation.
  */
-class OpenGLRenderer : public StatefulBaseRenderer {
+class OpenGLRenderer : public CanvasStateClient {
 public:
     OpenGLRenderer(RenderState& renderState);
     virtual ~OpenGLRenderer();
 
+    /**
+     * Sets the dimension of the underlying drawing surface. This method must
+     * be called at least once every time the drawing surface changes size.
+     *
+     * @param width The width in pixels of the underlysing surface
+     * @param height The height in pixels of the underlysing surface
+     */
+    void setViewport(int width, int height) { mState.setViewport(width, height); }
+
     void initProperties();
     void initLight(const Vector3& lightCenter, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
 
-    virtual void onViewportInitialized();
-    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
-    virtual void finish();
+    /*
+     * Prepares the renderer to draw a frame. This method must be invoked
+     * at the beginning of each frame. Only the specified rectangle of the
+     * frame is assumed to be dirty. A clip will automatically be set to
+     * the specified rectangle.
+     *
+     * @param opaque If true, the target surface is considered opaque
+     *               and will not be cleared. If false, the target surface
+     *               will be cleared
+     */
+    virtual void prepareDirty(float left, float top, float right, float bottom,
+            bool opaque);
 
-    virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
+    /**
+     * Prepares the renderer to draw a frame. This method must be invoked
+     * at the beginning of each frame. When this method is invoked, the
+     * entire drawing surface is assumed to be redrawn.
+     *
+     * @param opaque If true, the target surface is considered opaque
+     *               and will not be cleared. If false, the target surface
+     *               will be cleared
+     */
+    void prepare(bool opaque) {
+        prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
+    }
+
+    /**
+     * Indicates the end of a frame. This method must be invoked whenever
+     * the caller is done rendering a frame.
+     * Returns true if any drawing was done during the frame (the output
+     * has changed / is "dirty" and should be displayed to the user).
+     */
+    virtual bool finish();
+
+    void callDrawGLFunction(Functor* functor, Rect& dirty);
 
     void pushLayerUpdate(Layer* layer);
     void cancelLayerUpdate(Layer* layer);
@@ -145,7 +184,7 @@
 
     virtual int saveLayer(float left, float top, float right, float bottom,
             const SkPaint* paint, int flags) {
-        return saveLayer(left, top, right, bottom, paint, flags, NULL);
+        return saveLayer(left, top, right, bottom, paint, flags, nullptr);
     }
 
     // Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if
@@ -156,56 +195,50 @@
     int saveLayerDeferred(float left, float top, float right, float bottom,
             const SkPaint* paint, int flags);
 
-    virtual status_t drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
-    virtual status_t drawLayer(Layer* layer, float x, float y);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
-    status_t drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
+    void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
+    void drawLayer(Layer* layer, float x, float y);
+    void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
+    void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
             TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
-    virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+    void drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst,
+            const SkPaint* paint);
+    void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
             const float* vertices, const int* colors, const SkPaint* paint);
-    status_t drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+    void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
             TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint);
-    virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+    void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
             float left, float top, float right, float bottom, const SkPaint* paint);
-    status_t drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
-            float left, float top, float right, float bottom, const SkPaint* paint);
-    virtual status_t drawColor(int color, SkXfermode::Mode mode);
-    virtual status_t drawRect(float left, float top, float right, float bottom,
+    void drawColor(int color, SkXfermode::Mode mode);
+    void drawRect(float left, float top, float right, float bottom,
             const SkPaint* paint);
-    virtual status_t drawRoundRect(float left, float top, float right, float bottom,
+    void drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, const SkPaint* paint);
-    virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
-    virtual status_t drawOval(float left, float top, float right, float bottom,
+    void drawCircle(float x, float y, float radius, const SkPaint* paint);
+    void drawOval(float left, float top, float right, float bottom,
             const SkPaint* paint);
-    virtual status_t drawArc(float left, float top, float right, float bottom,
+    void drawArc(float left, float top, float right, float bottom,
             float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint);
-    virtual status_t drawPath(const SkPath* path, const SkPaint* paint);
-    virtual status_t drawLines(const float* points, int count, const SkPaint* paint);
-    virtual status_t drawPoints(const float* points, int count, const SkPaint* paint);
-    virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
+    void drawPath(const SkPath* path, const SkPaint* paint);
+    void drawLines(const float* points, int count, const SkPaint* paint);
+    void drawPoints(const float* points, int count, const SkPaint* paint);
+    void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
             float hOffset, float vOffset, const SkPaint* paint);
-    virtual status_t drawPosText(const char* text, int bytesCount, int count,
+    void drawPosText(const char* text, int bytesCount, int count,
             const float* positions, const SkPaint* paint);
-    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
+    void drawText(const char* text, int bytesCount, int count, float x, float y,
             const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
-            DrawOpMode drawOpMode = kDrawOpMode_Immediate);
-    virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
+            DrawOpMode drawOpMode = DrawOpMode::kImmediate);
+    void drawRects(const float* rects, int count, const SkPaint* paint);
 
-    status_t drawShadow(float casterAlpha,
-            const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer);
+    void drawShadow(float casterAlpha,
+            const VertexBuffer* ambientShadowVertexBuffer,
+            const VertexBuffer* spotShadowVertexBuffer);
 
-    virtual void resetPaintFilter();
-    virtual void setupPaintFilter(int clearBits, int setBits);
+    void setDrawFilter(SkDrawFilter* filter);
 
     // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
     void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
 
-    const SkPaint* filterPaint(const SkPaint* paint);
-
     /**
      * Store the current display state (most importantly, the current clip and transform), and
      * additionally map the state's bounds from local to window coordinates.
@@ -227,21 +260,18 @@
         return mCaches;
     }
 
-    // simple rect clip
-    bool isCurrentClipSimple() {
-        return mSnapshot->clipRegion->isEmpty();
+    RenderState& renderState() {
+        return mRenderState;
     }
 
-    int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
-    int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
+    int getViewportWidth() { return mState.getViewportWidth(); }
+    int getViewportHeight() { return mState.getViewportHeight(); }
 
     /**
      * Scales the alpha on the current snapshot. This alpha value will be modulated
      * with other alpha values when drawing primitives.
      */
-    void scaleAlpha(float alpha) {
-        mSnapshot->alpha *= alpha;
-    }
+    void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); }
 
     /**
      * Inserts a named event marker in the stream of GL commands.
@@ -275,14 +305,15 @@
      * @param alpha Where to store the resulting alpha
      * @param mode Where to store the resulting xfermode
      */
-    static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+    static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha,
+            SkXfermode::Mode* mode) {
         *mode = getXfermodeDirect(paint);
         *alpha = getAlphaDirect(paint);
     }
 
     static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) {
         if (!paint) return SkXfermode::kSrcOver_Mode;
-        return getXfermode(paint->getXfermode());
+        return PaintUtils::getXfermode(paint->getXfermode());
     }
 
     static inline int getAlphaDirect(const SkPaint* paint) {
@@ -312,7 +343,7 @@
     }
 
     static inline bool hasTextShadow(const SkPaint* paint) {
-        return getTextShadow(paint, NULL);
+        return getTextShadow(paint, nullptr);
     }
 
     /**
@@ -334,18 +365,72 @@
         drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true);
 
         if (stencilWasEnabled) mCaches.stencil.enableTest();
+        mDirty = true;
     }
 #endif
 
-    const Vector3& getLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+    const Vector3& getLightCenter() const { return mState.currentLightCenter(); }
     float getLightRadius() const { return mLightRadius; }
     uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; }
     uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; }
 
+    ///////////////////////////////////////////////////////////////////
+    /// State manipulation
+
+    int getSaveCount() const;
+    int save(int flags);
+    void restore();
+    void restoreToCount(int saveCount);
+
+    void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
+    void setMatrix(const SkMatrix& matrix) { mState.setMatrix(matrix); }
+    void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); }
+
+    void translate(float dx, float dy, float dz = 0.0f);
+    void rotate(float degrees);
+    void scale(float sx, float sy);
+    void skew(float sx, float sy);
+
+    void setMatrix(const Matrix4& matrix); // internal only convenience method
+    void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+    const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
+    const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
+    bool quickRejectConservative(float left, float top,
+            float right, float bottom) const {
+        return mState.quickRejectConservative(left, top, right, bottom);
+    }
+
+    bool clipRect(float left, float top,
+            float right, float bottom, SkRegion::Op op);
+    bool clipPath(const SkPath* path, SkRegion::Op op);
+    bool clipRegion(const SkRegion* region, SkRegion::Op op);
+
+    /**
+     * Does not support different clipping Ops (that is, every call to setClippingOutline is
+     * effectively using SkRegion::kReplaceOp)
+     *
+     * The clipping outline is independent from the regular clip.
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+    void setClippingRoundRect(LinearAllocator& allocator,
+            const Rect& rect, float radius, bool highPriority = true);
+
+    inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); }
+    inline const mat4* currentTransform() const { return mState.currentTransform(); }
+
+    ///////////////////////////////////////////////////////////////////
+    /// CanvasStateClient interface
+
+    virtual void onViewportInitialized() override;
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
+    virtual GLuint getTargetFbo() const override { return 0; }
+
     SkPath* allocPathForFrame() {
-        SkPath* path = new SkPath();
-        mTempPaths.push_back(path);
-        return path;
+        std::unique_ptr<SkPath> path(new SkPath());
+        SkPath* returnPath = path.get();
+        mTempPaths.push_back(std::move(path));
+        return returnPath;
     }
 
 protected:
@@ -359,12 +444,12 @@
      * Indicates the start of rendering. This method will setup the
      * initial OpenGL state (viewport, clearing the buffer, etc.)
      */
-    status_t startFrame();
+    void startFrame();
 
     /**
      * Clears the underlying surface if needed.
      */
-    virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
+    virtual void clear(float left, float top, float right, float bottom, bool opaque);
 
     /**
      * Call this method after updating a layer during a drawing pass.
@@ -384,9 +469,16 @@
      */
     void attachStencilBufferToLayer(Layer* layer);
 
+    /**
+     * Draw a rectangle list. Currently only used for the the stencil buffer so that the stencil
+     * will have a value of 'n' in every unclipped pixel, where 'n' is the number of rectangles
+     * in the list.
+     */
+    void drawRectangleList(const RectangleList& rectangleList);
+
     bool quickRejectSetupScissor(float left, float top, float right, float bottom,
-            const SkPaint* paint = NULL);
-    bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = NULL) {
+            const SkPaint* paint = nullptr);
+    bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = nullptr) {
         return quickRejectSetupScissor(bounds.left, bounds.top,
                 bounds.right, bounds.bottom, paint);
     }
@@ -411,21 +503,14 @@
      * Returns the region of the current layer.
      */
     virtual Region* getRegion() const {
-        return mSnapshot->region;
+        return mState.currentRegion();
     }
 
     /**
      * Indicates whether rendering is currently targeted at a layer.
      */
     virtual bool hasLayer() const {
-        return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
-    }
-
-    /**
-     * Returns the name of the FBO this renderer is rendering into.
-     */
-    virtual GLuint getTargetFbo() const {
-        return 0;
+        return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion();
     }
 
     /**
@@ -459,7 +544,7 @@
      * null then null is returned.
      */
     static inline SkColorFilter* getColorFilter(const SkPaint* paint) {
-        return paint ? paint->getColorFilter() : NULL;
+        return paint ? paint->getColorFilter() : nullptr;
     }
 
     /**
@@ -467,7 +552,7 @@
      * null then null is returned.
      */
     static inline const SkShader* getShader(const SkPaint* paint) {
-        return paint ? paint->getShader() : NULL;
+        return paint ? paint->getShader() : nullptr;
     }
 
     /**
@@ -477,9 +562,13 @@
         return false;
     }
 
-    inline RenderState& renderState() { return mRenderState; }
+    CanvasState mState;
+    Caches& mCaches;
+    RenderState& mRenderState;
 
 private:
+    void renderGlop(const Glop& glop, bool clearLayer = true);
+
     /**
      * Discards the content of the framebuffer if supported by the driver.
      * This method should be called at the beginning of a frame to optimize
@@ -488,12 +577,6 @@
     void discardFramebuffer(float left, float top, float right, float bottom);
 
     /**
-     * Ensures the state of the renderer is the same as the state of
-     * the GL context.
-     */
-    void syncState();
-
-    /**
      * Tells the GPU what part of the screen is about to be redrawn.
      * This method will use the current layer space clip rect.
      * This method needs to be invoked every time getTargetFbo() is
@@ -514,8 +597,6 @@
      */
     void endTiling();
 
-    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
-
     /**
      * Sets the clipping rectangle using glScissor. The clip is defined by
      * the current snapshot's clipRect member.
@@ -594,7 +675,7 @@
      * are transformed with the supplied matrix.
      */
     void dirtyLayer(const float left, const float top,
-            const float right, const float bottom, const mat4 transform);
+            const float right, const float bottom, const Matrix4& transform);
 
     /**
      * Mark the layer as dirty at the specified coordinates.
@@ -629,7 +710,7 @@
      * @param dirty True if calling this method should dirty the current layer
      * @param clip True if the rects should be clipped, false otherwise
      */
-    status_t drawColorRects(const float* rects, int count, const SkPaint* paint,
+    void drawColorRects(const float* rects, int count, const SkPaint* paint,
             bool ignoreTransform = false, bool dirty = true, bool clip = true);
 
     /**
@@ -643,18 +724,16 @@
      * @param texture The texture reprsenting the shape
      * @param paint The paint to draw the shape with
      */
-    status_t drawShape(float left, float top, const PathTexture* texture, const SkPaint* paint);
+    void drawShape(float left, float top, PathTexture* texture, const SkPaint* paint);
 
     /**
      * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
      * different compositing rules.
      *
      * @param texture The texture to draw with
-     * @param left The x coordinate of the bitmap
-     * @param top The y coordinate of the bitmap
      * @param paint The paint to render with
      */
-    void drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint);
+    void drawAlphaBitmap(Texture* texture, const SkPaint* paint);
 
     /**
      * Renders a strip of polygons with the specified paint, used for tessellated geometry.
@@ -663,15 +742,15 @@
      * @param paint The paint to render with
      * @param flags flags with which to draw
      */
-    status_t drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer,
+    void drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer,
             const SkPaint* paint, int flags = 0);
 
     /**
      * Convenience for translating method
      */
-    status_t drawVertexBuffer(const VertexBuffer& vertexBuffer,
+    void drawVertexBuffer(const VertexBuffer& vertexBuffer,
             const SkPaint* paint, int flags = 0) {
-        return drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags);
+        drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags);
     }
 
     /**
@@ -680,21 +759,15 @@
      * @param path The hull of the path to draw
      * @param paint The paint to render with
      */
-    status_t drawConvexPath(const SkPath& path, const SkPaint* paint);
+    void drawConvexPath(const SkPath& path, const SkPaint* paint);
 
     /**
-     * Draws a textured rectangle with the specified texture. The specified coordinates
-     * are transformed by the current snapshot's transform matrix.
+     * Draws a textured rectangle with the specified texture.
      *
-     * @param left The left coordinate of the rectangle
-     * @param top The top coordinate of the rectangle
-     * @param right The right coordinate of the rectangle
-     * @param bottom The bottom coordinate of the rectangle
      * @param texture The texture to use
      * @param paint The paint containing the alpha, blending mode, etc.
      */
-    void drawTextureRect(float left, float top, float right, float bottom,
-            Texture* texture, const SkPaint* paint);
+    void drawTextureRect(Texture* texture, const SkPaint* paint);
 
     /**
      * Draws a textured mesh with the specified texture. If the indices are omitted,
@@ -780,7 +853,7 @@
      * @param y The y coordinate where the texture will be drawn
      * @param paint The paint to draw the texture with
      */
-     void drawPathTexture(const PathTexture* texture, float x, float y, const SkPaint* paint);
+     void drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint);
 
     /**
      * Resets the texture coordinates stored in mMeshVertices. Setting the values
@@ -801,22 +874,6 @@
     bool canSkipText(const SkPaint* paint) const;
 
     /**
-     * Binds the specified texture. The texture unit must have been selected
-     * prior to calling this method.
-     */
-    inline void bindTexture(GLuint texture) {
-        mCaches.bindTexture(texture);
-    }
-
-    /**
-     * Binds the specified EGLImage texture. The texture unit must have been selected
-     * prior to calling this method.
-     */
-    inline void bindExternalTexture(GLuint texture) {
-        mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
-    }
-
-    /**
      * Enable or disable blending as necessary. This function sets the appropriate
      * blend function based on the specified xfermode.
      */
@@ -824,18 +881,6 @@
             bool swapSrcDst = false);
 
     /**
-     * Use the specified program with the current GL context. If the program is already
-     * in use, it will not be bound again. If it is not in use, the current program is
-     * marked unused and the specified program becomes used and becomes the new
-     * current program.
-     *
-     * @param program The program to use
-     *
-     * @return true If the specified program was already in use, false otherwise.
-     */
-    inline bool useProgram(Program* program);
-
-    /**
      * Invoked before any drawing operation. This sets required state.
      */
     void setupDraw(bool clear = true);
@@ -867,8 +912,8 @@
      * space must be scaled up and translated to fill the quad provided in (l,t,r,b). These
      * transformations are stored in the modelView matrix and uploaded to the shader.
      *
-     * @param offset Set to true if the the matrix should be fudged (translated) slightly to disambiguate
-     * geometry pixel positioning. See Vertex::GeometryFudgeFactor().
+     * @param offset Set to true if the the matrix should be fudged (translated) slightly to
+     * disambiguate geometry pixel positioning. See Vertex::GeometryFudgeFactor().
      *
      * @param ignoreTransform Set to true if l,t,r,b coordinates already in layer space,
      * currentTransform() will be ignored. (e.g. when drawing clip in layer coordinates to stencil,
@@ -894,7 +939,7 @@
     void setupDrawTextureTransform();
     void setupDrawTextureTransformUniforms(mat4& transform);
     void setupDrawTextGammaUniforms();
-    void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords = NULL, GLuint vbo = 0);
+    void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords = nullptr, GLuint vbo = 0);
     void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords, const GLvoid* colors);
     void setupDrawMeshIndices(const GLvoid* vertices, const GLvoid* texCoords, GLuint vbo = 0);
     void setupDrawIndexedVertices(GLvoid* vertices);
@@ -931,9 +976,7 @@
     /**
      * Should be invoked every time the glScissor is modified.
      */
-    inline void dirtyClip() {
-        mDirtyClip = true;
-    }
+    inline void dirtyClip() { mState.setDirtyClip(true); }
 
     inline const UvMapper& getMapper(const Texture* texture) {
         return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
@@ -946,6 +989,10 @@
      */
     Texture* getTexture(const SkBitmap* bitmap);
 
+    bool reportAndClearDirty() { bool ret = mDirty; mDirty = false; return ret; }
+    inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); }
+    inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); }
+
     /**
      * Model-view matrix used to position/size objects
      *
@@ -979,13 +1026,8 @@
     DrawModifiers mDrawModifiers;
     SkPaint mFilteredPaint;
 
-    // Various caches
-    Caches& mCaches;
-    Extensions& mExtensions;
-    RenderState& mRenderState;
-
     // List of rectangles to clear after saveLayer() is invoked
-    Vector<Rect*> mLayers;
+    std::vector<Rect> mLayers;
     // List of layers to update at the beginning of a frame
     Vector< sp<Layer> > mLayerUpdates;
 
@@ -994,7 +1036,7 @@
     ProgramDescription mDescription;
     // Color description
     bool mColorSet;
-    float mColorA, mColorR, mColorG, mColorB;
+    FloatColor mColor;
     // Indicates that the shader should get a color
     bool mSetShaderColor;
     // Current texture unit
@@ -1014,6 +1056,10 @@
 
     bool mSkipOutlineClip;
 
+    // True if anything has been drawn since the last call to
+    // reportAndClearDirty()
+    bool mDirty;
+
     // Lighting + shadows
     Vector3 mLightCenter;
     float mLightRadius;
@@ -1021,7 +1067,7 @@
     uint8_t mSpotShadowAlpha;
 
     // Paths kept alive for the duration of the frame
-    std::vector<SkPath*> mTempPaths;
+    std::vector<std::unique_ptr<SkPath>> mTempPaths;
 
     friend class Layer;
     friend class TextSetupFunctor;
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 6dacd5ed..5e9b213 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -95,7 +95,7 @@
     }
 
     const SkPath* getPath() const {
-        if (mType == kOutlineType_None || mType == kOutlineType_Empty) return NULL;
+        if (mType == kOutlineType_None || mType == kOutlineType_Empty) return nullptr;
 
         return &mPath;
     }
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 442e9ba..f673c6a 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -24,22 +24,12 @@
 #include "Patch.h"
 #include "Properties.h"
 #include "UvMapper.h"
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Constructors/destructor
-///////////////////////////////////////////////////////////////////////////////
-
-Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
-}
-
-Patch::~Patch() {
-    delete[] vertices;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Vertices management
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -47,19 +37,11 @@
     return verticesCount * sizeof(TextureVertex);
 }
 
-TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
-        float width, float height, const Res_png_9patch* patch) {
-    UvMapper mapper;
-    return createMesh(bitmapWidth, bitmapHeight, width, height, mapper, patch);
-}
-
-TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
-        float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) {
-    if (vertices) return vertices;
+Patch::Patch(const float bitmapWidth, const float bitmapHeight,
+        float width, float height, const UvMapper& mapper, const Res_png_9patch* patch)
+        : mColors(patch->getColors()) {
 
     int8_t emptyQuads = 0;
-    mColors = patch->getColors();
-
     const int8_t numColors = patch->numColors;
     if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
         for (int8_t i = 0; i < numColors; i++) {
@@ -75,10 +57,10 @@
     uint32_t yCount = patch->numYDivs;
 
     uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4;
-    if (maxVertices == 0) return NULL;
+    if (maxVertices == 0) return;
 
-    TextureVertex* tempVertices = new TextureVertex[maxVertices];
-    TextureVertex* vertex = tempVertices;
+    vertices.reset(new TextureVertex[maxVertices]);
+    TextureVertex* vertex = vertices.get();
 
     const int32_t* xDivs = patch->getXDivs();
     const int32_t* yDivs = patch->getYDivs();
@@ -157,15 +139,11 @@
                 width, bitmapWidth, quadCount);
     }
 
-    if (verticesCount == maxVertices) {
-        vertices = tempVertices;
-    } else {
-        vertices = new TextureVertex[verticesCount];
-        memcpy(vertices, tempVertices, verticesCount * sizeof(TextureVertex));
-        delete[] tempVertices;
+    if (verticesCount != maxVertices) {
+        std::unique_ptr<TextureVertex[]> reducedVertices(new TextureVertex[verticesCount]);
+        memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex));
+        vertices = std::move(reducedVertices);
     }
-
-    return vertices;
 }
 
 void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
@@ -213,10 +191,10 @@
     const uint32_t oldQuadCount = quadCount;
     quadCount++;
 
-    if (x1 < 0.0f) x1 = 0.0f;
-    if (x2 < 0.0f) x2 = 0.0f;
-    if (y1 < 0.0f) y1 = 0.0f;
-    if (y2 < 0.0f) y2 = 0.0f;
+    x1 = MathUtils::max(x1, 0.0f);
+    x2 = MathUtils::max(x2, 0.0f);
+    y1 = MathUtils::max(y1, 0.0f);
+    y2 = MathUtils::max(y2, 0.0f);
 
     // Skip degenerate and transparent (empty) quads
     if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) {
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 1ba045d..b63bd24 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -27,38 +27,35 @@
 
 #include "Rect.h"
 #include "UvMapper.h"
-#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
 
+struct TextureVertex;
+
 ///////////////////////////////////////////////////////////////////////////////
 // 9-patch structures
 ///////////////////////////////////////////////////////////////////////////////
 
 class Patch {
 public:
-    Patch();
-    ~Patch();
+    Patch(const float bitmapWidth, const float bitmapHeight,
+            float width, float height,
+            const UvMapper& mapper, const Res_png_9patch* patch);
 
     /**
      * Returns the size of this patch's mesh in bytes.
      */
     uint32_t getSize() const;
 
-    TextureVertex* vertices;
-    uint32_t verticesCount;
-    uint32_t indexCount;
-    bool hasEmptyQuads;
+    std::unique_ptr<TextureVertex[]> vertices;
+    uint32_t verticesCount = 0;
+    uint32_t indexCount = 0;
+    bool hasEmptyQuads = false;
     Vector<Rect> quads;
 
-    GLintptr offset;
-    GLintptr textureOffset;
-
-    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
-            float width, float height, const Res_png_9patch* patch);
-    TextureVertex* createMesh(const float bitmapWidth, const float bitmapHeight,
-            float width, float height, const UvMapper& mapper, const Res_png_9patch* patch);
+    GLintptr positionOffset = 0;
+    GLintptr textureOffset = 0;
 
 private:
     void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 2f2debc..2765262 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -20,8 +20,10 @@
 #include <utils/Log.h>
 
 #include "Caches.h"
+#include "Patch.h"
 #include "PatchCache.h"
 #include "Properties.h"
+#include "renderstate/RenderState.h"
 
 namespace android {
 namespace uirenderer {
@@ -30,11 +32,15 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-PatchCache::PatchCache():
-        mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
-        mMeshBuffer(0), mFreeBlocks(NULL), mGenerationId(0) {
+PatchCache::PatchCache(RenderState& renderState)
+        : mRenderState(renderState)
+        , mSize(0)
+        , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
+        , mMeshBuffer(0)
+        , mFreeBlocks(nullptr)
+        , mGenerationId(0) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting patch cache size to %skB", property);
         mMaxSize = KB(atoi(property));
     } else {
@@ -47,15 +53,15 @@
     clear();
 }
 
-void PatchCache::init(Caches& caches) {
+void PatchCache::init() {
     bool created = false;
     if (!mMeshBuffer) {
         glGenBuffers(1, &mMeshBuffer);
         created = true;
     }
 
-    caches.bindMeshBuffer(mMeshBuffer);
-    caches.resetVertexPointers();
+    mRenderState.meshState().bindMeshBuffer(mMeshBuffer);
+    mRenderState.meshState().resetVertexPointers();
 
     if (created) {
         createVertexBuffer();
@@ -84,7 +90,7 @@
     clearCache();
 
     if (mMeshBuffer) {
-        Caches::getInstance().unbindMeshBuffer();
+        mRenderState.meshState().unbindMeshBuffer();
         glDeleteBuffers(1, &mMeshBuffer);
         mMeshBuffer = 0;
         mSize = 0;
@@ -104,7 +110,7 @@
         delete block;
         block = next;
     }
-    mFreeBlocks = NULL;
+    mFreeBlocks = nullptr;
 }
 
 void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) {
@@ -124,11 +130,11 @@
     size_t count = mGarbage.size();
     for (size_t i = 0; i < count; i++) {
         if (patch == mGarbage[i]) {
-            patch = NULL;
+            patch = nullptr;
             break;
         }
     }
-    LOG_ALWAYS_FATAL_IF(patch == NULL);
+    LOG_ALWAYS_FATAL_IF(patch == nullptr);
 
     mGarbage.push(patch);
 }
@@ -156,7 +162,7 @@
 
         // Release the patch and mark the space in the free list
         Patch* patch = pair.getSecond();
-        BufferBlock* block = new BufferBlock(patch->offset, patch->getSize());
+        BufferBlock* block = new BufferBlock(patch->positionOffset, patch->getSize());
         block->next = mFreeBlocks;
         mFreeBlocks = block;
 
@@ -174,7 +180,7 @@
 }
 
 void PatchCache::createVertexBuffer() {
-    glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, mMaxSize, nullptr, GL_DYNAMIC_DRAW);
     mSize = 0;
     mFreeBlocks = new BufferBlock(0, mMaxSize);
     mGenerationId++;
@@ -184,9 +190,9 @@
  * Sets the mesh's offsets and copies its associated vertices into
  * the mesh buffer (VBO).
  */
-void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
+void PatchCache::setupMesh(Patch* newMesh) {
     // This call ensures the VBO exists and that it is bound
-    init(Caches::getInstance());
+    init();
 
     // If we're running out of space, let's clear the entire cache
     uint32_t size = newMesh->getSize();
@@ -196,7 +202,7 @@
     }
 
     // Find a block where we can fit the mesh
-    BufferBlock* previous = NULL;
+    BufferBlock* previous = nullptr;
     BufferBlock* block = mFreeBlocks;
     while (block) {
         // The mesh fits
@@ -212,14 +218,14 @@
     if (!block) {
         clearCache();
         createVertexBuffer();
-        previous = NULL;
+        previous = nullptr;
         block = mFreeBlocks;
     }
 
     // Copy the 9patch mesh in the VBO
-    newMesh->offset = (GLintptr) (block->offset);
-    newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
-    glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
+    newMesh->positionOffset = (GLintptr) (block->offset);
+    newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
+    glBufferSubData(GL_ARRAY_BUFFER, newMesh->positionOffset, size, newMesh->vertices.get());
 
     // Remove the block since we've used it entirely
     if (block->size == size) {
@@ -238,6 +244,8 @@
     mSize += size;
 }
 
+static const UvMapper sIdentity;
+
 const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
         const uint32_t bitmapWidth, const uint32_t bitmapHeight,
         const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
@@ -246,20 +254,12 @@
     const Patch* mesh = mCache.get(description);
 
     if (!mesh) {
-        Patch* newMesh = new Patch();
-        TextureVertex* vertices;
+        const UvMapper& mapper = entry ? entry->uvMapper : sIdentity;
+        Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
+                pixelWidth, pixelHeight, mapper, patch);
 
-        if (entry) {
-            // An atlas entry has a UV mapper
-            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
-                    pixelWidth, pixelHeight, entry->uvMapper, patch);
-        } else {
-            vertices = newMesh->createMesh(bitmapWidth, bitmapHeight,
-                    pixelWidth, pixelHeight, patch);
-        }
-
-        if (vertices) {
-            setupMesh(newMesh, vertices);
+        if (newMesh->vertices) {
+            setupMesh(newMesh);
         }
 
 #if DEBUG_PATCHES
@@ -278,7 +278,7 @@
     String8 dump;
     BufferBlock* block = mFreeBlocks;
     while (block) {
-        dump.appendFormat("->(%d, %d)", block->offset, block->size);
+        dump.appendFormat("->(%d, %d)", block->positionOffset, block->size);
         block = block->next;
     }
     ALOGD("%s: Free blocks%s", prefix, dump.string());
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 9f2c9a5..387f79a 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -25,12 +25,13 @@
 
 #include "AssetAtlas.h"
 #include "Debug.h"
-#include "Patch.h"
 #include "utils/Pair.h"
 
 namespace android {
 namespace uirenderer {
 
+class Patch;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
@@ -50,9 +51,9 @@
 
 class PatchCache {
 public:
-    PatchCache();
+    PatchCache(RenderState& renderState);
     ~PatchCache();
-    void init(Caches& caches);
+    void init();
 
     const Patch* get(const AssetAtlas::Entry* entry,
             const uint32_t bitmapWidth, const uint32_t bitmapHeight,
@@ -90,7 +91,7 @@
 
 private:
     struct PatchDescription {
-        PatchDescription(): mPatch(NULL), mBitmapWidth(0), mBitmapHeight(0),
+        PatchDescription(): mPatch(nullptr), mBitmapWidth(0), mBitmapHeight(0),
                 mPixelWidth(0), mPixelHeight(0) {
         }
 
@@ -145,7 +146,7 @@
      * to track available regions of memory in the VBO.
      */
     struct BufferBlock {
-        BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(NULL) {
+        BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(nullptr) {
         }
 
         uint32_t offset;
@@ -159,7 +160,7 @@
     void clearCache();
     void createVertexBuffer();
 
-    void setupMesh(Patch* newMesh, TextureVertex* vertices);
+    void setupMesh(Patch* newMesh);
 
     void remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch);
 
@@ -167,6 +168,7 @@
     void dumpFreeBlocks(const char* prefix);
 #endif
 
+    RenderState& mRenderState;
     uint32_t mMaxSize;
     uint32_t mSize;
 
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 6f48e4d..5b2e5e2 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -31,7 +31,6 @@
 #include "PathCache.h"
 
 #include "thread/Signal.h"
-#include "thread/Task.h"
 #include "thread/TaskProcessor.h"
 
 namespace android {
@@ -48,7 +47,7 @@
         style(SkPaint::kFill_Style),
         miter(4.0f),
         strokeWidth(1.0f),
-        pathEffect(NULL) {
+        pathEffect(nullptr) {
     memset(&shape, 0, sizeof(Shape));
 }
 
@@ -81,7 +80,7 @@
 
 bool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) {
     // NOTE: This should only be used after PathTessellator handles joins properly
-    return paint->getPathEffect() == NULL && path->getConvexity() == SkPath::kConvex_Convexity;
+    return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity;
 }
 
 void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
@@ -114,9 +113,9 @@
     // will be applied later when compositing the alpha8 texture
     paint.setColor(SK_ColorBLACK);
     paint.setAlpha(255);
-    paint.setColorFilter(NULL);
-    paint.setMaskFilter(NULL);
-    paint.setShader(NULL);
+    paint.setColorFilter(nullptr);
+    paint.setMaskFilter(nullptr);
+    paint.setShader(nullptr);
     SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
     SkSafeUnref(paint.setXfermode(mode));
 }
@@ -153,7 +152,7 @@
         mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity),
         mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting %s cache size to %sMB", name, property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -211,8 +210,8 @@
         // If there is a pending task we must wait for it to return
         // before attempting our cleanup
         const sp<Task<SkBitmap*> >& task = texture->task();
-        if (task != NULL) {
-            SkBitmap* bitmap = task->getResult();
+        if (task != nullptr) {
+            task->getResult();
             texture->clearTask();
         } else {
             // If there is a pending task, the path was not added
@@ -231,7 +230,7 @@
         }
 
         if (texture->id) {
-            Caches::getInstance().deleteTexture(texture->id);
+            Caches::getInstance().textureState().deleteTexture(texture->id);
         }
         delete texture;
     }
@@ -261,7 +260,7 @@
     uint32_t width, height;
     computePathBounds(path, paint, left, top, offset, width, height);
 
-    if (!checkTextureSize(width, height)) return NULL;
+    if (!checkTextureSize(width, height)) return nullptr;
 
     purgeCache(width, height);
 
@@ -313,7 +312,7 @@
 
     glGenTextures(1, &texture->id);
 
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
     // Textures are Alpha8
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
@@ -355,7 +354,7 @@
     } else {
         texture->width = 0;
         texture->height = 0;
-        t->setResult(NULL);
+        t->setResult(nullptr);
     }
 }
 
@@ -363,22 +362,9 @@
 // Paths
 ///////////////////////////////////////////////////////////////////////////////
 
-void PathCache::remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair) {
-    LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
-
-    while (i.next()) {
-        const PathDescription& key = i.key();
-        if (key.type == kShapePath &&
-                (key.shape.path.mPath == pair.getFirst() ||
-                        key.shape.path.mPath == pair.getSecond())) {
-            pathsToRemove.push(key);
-        }
-    }
-}
-
-void PathCache::removeDeferred(SkPath* path) {
+void PathCache::removeDeferred(const SkPath* path) {
     Mutex::Autolock l(mLock);
-    mGarbage.push(path_pair_t(path, const_cast<SkPath*>(path->getSourcePath())));
+    mGarbage.push(path->getGenerationID());
 }
 
 void PathCache::clearGarbage() {
@@ -388,9 +374,15 @@
         Mutex::Autolock l(mLock);
         size_t count = mGarbage.size();
         for (size_t i = 0; i < count; i++) {
-            const path_pair_t& pair = mGarbage.itemAt(i);
-            remove(pathsToRemove, pair);
-            delete pair.getFirst();
+            const uint32_t generationID = mGarbage.itemAt(i);
+
+            LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
+            while (iter.next()) {
+                const PathDescription& key = iter.key();
+                if (key.type == kShapePath && key.shape.path.mGenerationID == generationID) {
+                    pathsToRemove.push(key);
+                }
+            }
         }
         mGarbage.clear();
     }
@@ -400,27 +392,9 @@
     }
 }
 
-/**
- * To properly handle path mutations at draw time we always make a copy
- * of paths objects when recording display lists. The source path points
- * to the path we originally copied the path from. This ensures we use
- * the original path as a cache key the first time a path is inserted
- * in the cache. The source path is also used to reclaim garbage when a
- * Dalvik Path object is collected.
- */
-static const SkPath* getSourcePath(const SkPath* path) {
-    const SkPath* sourcePath = path->getSourcePath();
-    if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) {
-        return const_cast<SkPath*>(sourcePath);
-    }
-    return path;
-}
-
 PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
-    path = getSourcePath(path);
-
     PathDescription entry(kShapePath, paint);
-    entry.shape.path.mPath = path;
+    entry.shape.path.mGenerationID = path->getGenerationID();
 
     PathTexture* texture = mCache.get(entry);
 
@@ -430,7 +404,7 @@
         // A bitmap is attached to the texture, this means we need to
         // upload it as a GL texture
         const sp<Task<SkBitmap*> >& task = texture->task();
-        if (task != NULL) {
+        if (task != nullptr) {
             // But we must first wait for the worker thread to be done
             // producing the bitmap, so let's wait
             SkBitmap* bitmap = task->getResult();
@@ -440,14 +414,9 @@
             } else {
                 ALOGW("Path too large to be rendered into a texture");
                 texture->clearTask();
-                texture = NULL;
+                texture = nullptr;
                 mCache.remove(entry);
             }
-        } else if (path->getGenerationID() != texture->generation) {
-            // The size of the path might have changed so we first
-            // remove the entry from the cache
-            mCache.remove(entry);
-            texture = addTexture(entry, path, paint);
         }
     }
 
@@ -459,19 +428,14 @@
         return;
     }
 
-    path = getSourcePath(path);
-
     PathDescription entry(kShapePath, paint);
-    entry.shape.path.mPath = path;
+    entry.shape.path.mGenerationID = path->getGenerationID();
 
     PathTexture* texture = mCache.get(entry);
 
     bool generate = false;
     if (!texture) {
         generate = true;
-    } else if (path->getGenerationID() != texture->generation) {
-        mCache.remove(entry);
-        generate = true;
     }
 
     if (generate) {
@@ -490,10 +454,12 @@
         // be enforced.
         mCache.put(entry, texture);
 
-        if (mProcessor == NULL) {
+        if (mProcessor == nullptr) {
             mProcessor = new PathProcessor(Caches::getInstance());
         }
-        mProcessor->add(task);
+        if (!mProcessor->add(task)) {
+            mProcessor->process(task);
+        }
     }
 }
 
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index bc34188..23e35cb 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -17,22 +17,22 @@
 #ifndef ANDROID_HWUI_PATH_CACHE_H
 #define ANDROID_HWUI_PATH_CACHE_H
 
-#include <GLES2/gl2.h>
+#include "Debug.h"
+#include "Texture.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
+#include "utils/Macros.h"
+#include "utils/Pair.h"
 
+#include <GLES2/gl2.h>
+#include <SkPath.h>
 #include <utils/LruCache.h>
 #include <utils/Mutex.h>
 #include <utils/Vector.h>
 
-#include "Debug.h"
-#include "Properties.h"
-#include "Texture.h"
-#include "utils/Macros.h"
-#include "utils/Pair.h"
-
 class SkBitmap;
 class SkCanvas;
 class SkPaint;
-class SkPath;
 struct SkRect;
 
 namespace android {
@@ -88,7 +88,7 @@
     }
 
     void clearTask() {
-        if (mTask != NULL) {
+        if (mTask != nullptr) {
             mTask.clear();
         }
     }
@@ -118,7 +118,7 @@
     SkPathEffect* pathEffect;
     union Shape {
         struct Path {
-            const SkPath* mPath;
+            uint32_t mGenerationID;
         } path;
         struct RoundRect {
             float mWidth;
@@ -166,7 +166,7 @@
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(PathDescription& path, PathTexture*& texture);
+    void operator()(PathDescription& path, PathTexture*& texture) override;
 
     /**
      * Clears the cache. This causes all textures to be deleted.
@@ -198,7 +198,7 @@
      * Removes the specified path. This is meant to be called from threads
      * that are not the EGL context thread.
      */
-    void removeDeferred(SkPath* path);
+    ANDROID_API void removeDeferred(const SkPath* path);
     /**
      * Process deferred removals.
      */
@@ -227,8 +227,6 @@
             float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
 
 private:
-    typedef Pair<SkPath*, SkPath*> path_pair_t;
-
     PathTexture* addTexture(const PathDescription& entry,
             const SkPath *path, const SkPaint* paint);
     PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
@@ -245,12 +243,6 @@
     }
 
     /**
-     * Removes an entry.
-     * The pair must define first=path, second=sourcePath
-     */
-    void remove(Vector<PathDescription>& pathsToRemove, const path_pair_t& pair);
-
-    /**
      * Ensures there is enough space in the cache for a texture of the specified
      * dimensions.
      */
@@ -279,8 +271,7 @@
             delete future()->get();
         }
 
-        // copied, since input path not refcounted / guaranteed to survive for duration of task
-        // TODO: avoid deep copy with refcounting
+        // copied, since input path not guaranteed to survive for duration of task
         const SkPath path;
 
         // copied, since input paint may not be immutable
@@ -293,7 +284,7 @@
         PathProcessor(Caches& caches);
         ~PathProcessor() { }
 
-        virtual void onProcess(const sp<Task<SkBitmap*> >& task);
+        virtual void onProcess(const sp<Task<SkBitmap*> >& task) override;
 
     private:
         uint32_t mMaxTextureSize;
@@ -308,7 +299,7 @@
 
     sp<PathProcessor> mProcessor;
 
-    Vector<path_pair_t> mGarbage;
+    Vector<uint32_t> mGarbage;
     mutable Mutex mLock;
 }; // class PathCache
 
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 27ef06f..3d8a749 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -229,7 +229,6 @@
                 current->x - totalOffset.x,
                 current->y - totalOffset.y);
 
-        last = current;
         current = next;
         lastNormal = nextNormal;
     }
@@ -279,7 +278,6 @@
                     - (vertices[lastIndex].x - vertices[lastIndex - 1].x),
                     vertices[lastIndex].y - vertices[lastIndex - 1].y);
         const float dTheta = PI / (extra + 1);
-        const float radialScale = 2.0f / (1 + cos(dTheta));
 
         int capOffset;
         for (int i = 0; i < extra; i++) {
@@ -290,14 +288,14 @@
             }
 
             beginTheta += dTheta;
-            Vector2 beginRadialOffset = {cos(beginTheta), sin(beginTheta)};
+            Vector2 beginRadialOffset = {cosf(beginTheta), sinf(beginTheta)};
             paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
             Vertex::set(&buffer[capOffset],
                     vertices[0].x + beginRadialOffset.x,
                     vertices[0].y + beginRadialOffset.y);
 
             endTheta += dTheta;
-            Vector2 endRadialOffset = {cos(endTheta), sin(endTheta)};
+            Vector2 endRadialOffset = {cosf(endTheta), sinf(endTheta)};
             paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
             Vertex::set(&buffer[allocSize - 1 - capOffset],
                     vertices[lastIndex].x + endRadialOffset.x,
@@ -373,7 +371,6 @@
                 current->y - totalOffset.y,
                 maxAlpha);
 
-        last = current;
         current = next;
         lastNormal = nextNormal;
     }
@@ -468,7 +465,7 @@
         for (int i = 0; i < extra; i++) {
             theta += dTheta;
 
-            Vector2 radialOffset = {cos(theta), sin(theta)};
+            Vector2 radialOffset = {cosf(theta), sinf(theta)};
 
             // scale to compensate for pinching at sharp angles, see totalOffsetFromNormals()
             radialOffset *= radialScale;
@@ -701,7 +698,6 @@
                 current->y - outerOffset.y,
                 0.0f);
 
-        last = current;
         current = next;
         lastNormal = nextNormal;
     }
@@ -787,6 +783,7 @@
     Rect bounds(path.getBounds());
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 template <class TYPE>
@@ -831,7 +828,6 @@
 
     Rect bounds;
     // tessellate, then duplicate outline across points
-    int numPoints = count / 2;
     VertexBuffer tempBuffer;
     if (!paintInfo.isAA) {
         getFillVerticesFromPerimeter(outlineVertices, tempBuffer);
@@ -845,6 +841,7 @@
     // expand bounds from vertex coords to pixel data
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
@@ -895,6 +892,7 @@
     // expand bounds from vertex coords to pixel data
     paintInfo.expandBoundsForStroke(&bounds);
     vertexBuffer.setBounds(bounds);
+    vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 5b642b9..9665a68 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -16,13 +16,14 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <utils/Log.h>
+#include "PixelBuffer.h"
 
-#include "Caches.h"
 #include "Debug.h"
 #include "Extensions.h"
-#include "PixelBuffer.h"
 #include "Properties.h"
+#include "renderstate/RenderState.h"
+
+#include <utils/Log.h>
 
 namespace android {
 namespace uirenderer {
@@ -34,33 +35,28 @@
 class CpuPixelBuffer: public PixelBuffer {
 public:
     CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
-    ~CpuPixelBuffer();
 
-    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
-    void unmap();
+    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
+    void unmap() override;
 
-    uint8_t* getMappedPointer() const;
+    uint8_t* getMappedPointer() const override;
 
-    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
+    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
 
 private:
-    uint8_t* mBuffer;
+    std::unique_ptr<uint8_t[]> mBuffer;
 };
 
-CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
-        PixelBuffer(format, width, height) {
-    mBuffer = new uint8_t[width * height * formatSize(format)];
-}
-
-CpuPixelBuffer::~CpuPixelBuffer() {
-    delete[] mBuffer;
+CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
+        : PixelBuffer(format, width, height)
+        , mBuffer(new uint8_t[width * height * formatSize(format)]) {
 }
 
 uint8_t* CpuPixelBuffer::map(AccessMode mode) {
     if (mAccessMode == kAccessMode_None) {
         mAccessMode = mode;
     }
-    return mBuffer;
+    return mBuffer.get();
 }
 
 void CpuPixelBuffer::unmap() {
@@ -68,12 +64,12 @@
 }
 
 uint8_t* CpuPixelBuffer::getMappedPointer() const {
-    return mAccessMode == kAccessMode_None ? NULL : mBuffer;
+    return mAccessMode == kAccessMode_None ? nullptr : mBuffer.get();
 }
 
 void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
-            mFormat, GL_UNSIGNED_BYTE, mBuffer + offset);
+            mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -85,12 +81,12 @@
     GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
     ~GpuPixelBuffer();
 
-    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
-    void unmap();
+    uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
+    void unmap() override;
 
-    uint8_t* getMappedPointer() const;
+    uint8_t* getMappedPointer() const override;
 
-    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
+    void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
 
 private:
     GLuint mBuffer;
@@ -98,12 +94,16 @@
     Caches& mCaches;
 };
 
-GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
-        PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) {
+GpuPixelBuffer::GpuPixelBuffer(GLenum format,
+        uint32_t width, uint32_t height)
+        : PixelBuffer(format, width, height)
+        , mMappedPointer(nullptr)
+        , mCaches(Caches::getInstance()){
     glGenBuffers(1, &mBuffer);
-    mCaches.bindPixelBuffer(mBuffer);
-    glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW);
-    mCaches.unbindPixelBuffer();
+
+    mCaches.pixelBufferState().bind(mBuffer);
+    glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
+    mCaches.pixelBufferState().unbind();
 }
 
 GpuPixelBuffer::~GpuPixelBuffer() {
@@ -112,7 +112,7 @@
 
 uint8_t* GpuPixelBuffer::map(AccessMode mode) {
     if (mAccessMode == kAccessMode_None) {
-        mCaches.bindPixelBuffer(mBuffer);
+        mCaches.pixelBufferState().bind(mBuffer);
         mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
 #if DEBUG_OPENGL
         if (!mMappedPointer) {
@@ -131,14 +131,14 @@
 void GpuPixelBuffer::unmap() {
     if (mAccessMode != kAccessMode_None) {
         if (mMappedPointer) {
-            mCaches.bindPixelBuffer(mBuffer);
+            mCaches.pixelBufferState().bind(mBuffer);
             GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
             if (status == GL_FALSE) {
                 ALOGE("Corrupted GPU pixel buffer");
             }
         }
         mAccessMode = kAccessMode_None;
-        mMappedPointer = NULL;
+        mMappedPointer = nullptr;
     }
 }
 
@@ -148,7 +148,7 @@
 
 void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
     // If the buffer is not mapped, unmap() will not bind it
-    mCaches.bindPixelBuffer(mBuffer);
+    mCaches.pixelBufferState().bind(mBuffer);
     unmap();
     glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
             GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
@@ -158,7 +158,8 @@
 // Factory
 ///////////////////////////////////////////////////////////////////////////////
 
-PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format,
+        uint32_t width, uint32_t height, BufferType type) {
     if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
         return new GpuPixelBuffer(format, width, height);
     }
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 04225a2..aac5ec4 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,6 +18,7 @@
 #define ANDROID_HWUI_PIXEL_BUFFER_H
 
 #include <GLES3/gl3.h>
+#include <cutils/log.h>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index e6fd2dc..32713e9 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -46,7 +46,7 @@
             glAttachShader(mProgramId, mVertexShader);
             glAttachShader(mProgramId, mFragmentShader);
 
-            position = bindAttrib("position", kBindingPosition);
+            bindAttrib("position", kBindingPosition);
             if (description.hasTexture || description.hasExternalTexture) {
                 texCoords = bindAttrib("texCoords", kBindingTexCoords);
             } else {
@@ -64,7 +64,7 @@
                 glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
                 if (infoLen > 1) {
                     GLchar log[infoLen];
-                    glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
+                    glGetProgramInfoLog(mProgramId, infoLen, nullptr, &log[0]);
                     ALOGE("%s", log);
                 }
                 LOG_ALWAYS_FATAL("Error while linking shaders");
@@ -135,7 +135,7 @@
     ATRACE_NAME("Build GL Shader");
 
     GLuint shader = glCreateShader(type);
-    glShaderSource(shader, 1, &source, 0);
+    glShaderSource(shader, 1, &source, nullptr);
     glCompileShader(shader);
 
     GLint status;
@@ -145,7 +145,7 @@
         // Some drivers return wrong values for GL_INFO_LOG_LENGTH
         // use a fixed size instead
         GLchar log[512];
-        glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
+        glGetShaderInfoLog(shader, sizeof(log), nullptr, &log[0]);
         LOG_ALWAYS_FATAL("Shader info log: %s", log);
         return 0;
     }
@@ -177,12 +177,12 @@
     glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
 }
 
-void Program::setColor(const float r, const float g, const float b, const float a) {
+void Program::setColor(FloatColor color) {
     if (!mHasColorUniform) {
         mColorUniform = getUniform("color");
         mHasColorUniform = true;
     }
-    glUniform4f(mColorUniform, r, g, b, a);
+    glUniform4f(mColorUniform, color.r, color.g, color.b, color.a);
 }
 
 void Program::use() {
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index d05b331..af1e4a7 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -25,6 +25,7 @@
 #include <SkXfermode.h>
 
 #include "Debug.h"
+#include "FloatColor.h"
 #include "Matrix.h"
 #include "Properties.h"
 
@@ -102,7 +103,7 @@
  * A ProgramDescription must be used in conjunction with a ProgramCache.
  */
 struct ProgramDescription {
-    enum ColorModifier {
+    enum ColorFilterMode {
         kColorNone = 0,
         kColorMatrix,
         kColorBlend
@@ -148,7 +149,7 @@
     GLenum bitmapWrapT;
 
     // Color operations
-    ColorModifier colorOp;
+    ColorFilterMode colorOp;
     SkXfermode::Mode colorMode;
 
     // Framebuffer blending (requires Extensions.hasFramebufferFetch())
@@ -363,15 +364,10 @@
     /**
      * Sets the color associated with this shader.
      */
-    void setColor(const float r, const float g, const float b, const float a);
+    void setColor(FloatColor color);
 
     /**
-     * Name of the position attribute.
-     */
-    int position;
-
-    /**
-     * Name of the texCoords attribute if it exists, -1 otherwise.
+     * Name of the texCoords attribute if it exists (kBindingTexCoords), -1 otherwise.
      */
     int texCoords;
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 62835e0..e9b22e2 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -380,9 +380,9 @@
         // Xor
         "return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
                 "src.a + dst.a - 2.0 * src.a * dst.a);\n",
-        // Add
+        // Plus
         "return min(src + dst, 1.0);\n",
-        // Multiply
+        // Modulate
         "return src * dst;\n",
         // Screen
         "return src + dst - src * dst;\n",
@@ -404,7 +404,8 @@
 // Constructors/destructors
 ///////////////////////////////////////////////////////////////////////////////
 
-ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
+ProgramCache::ProgramCache(Extensions& extensions)
+        : mHasES3(extensions.getMajorGlVersion() >= 3) {
 }
 
 ProgramCache::~ProgramCache() {
@@ -417,11 +418,6 @@
 
 void ProgramCache::clear() {
     PROGRAM_LOGD("Clearing program cache");
-
-    size_t count = mCache.size();
-    for (size_t i = 0; i < count; i++) {
-        delete mCache.valueAt(i);
-    }
     mCache.clear();
 }
 
@@ -433,14 +429,14 @@
         key = PROGRAM_KEY_TEXTURE;
     }
 
-    ssize_t index = mCache.indexOfKey(key);
-    Program* program = NULL;
-    if (index < 0) {
+    auto iter = mCache.find(key);
+    Program* program = nullptr;
+    if (iter == mCache.end()) {
         description.log("Could not find program");
         program = generateProgram(description, key);
-        mCache.add(key, program);
+        mCache[key] = std::unique_ptr<Program>(program);
     } else {
-        program = mCache.valueAt(index);
+        program = iter->second.get();
     }
     return program;
 }
@@ -834,7 +830,7 @@
     while ((index = shader.find("\n", index)) > -1) {
         String8 line(str, index - lastIndex);
         if (line.length() == 0) line.append("\n");
-        PROGRAM_LOGD("%s", line.string());
+        ALOGD("%s", line.string());
         index++;
         str += (index - lastIndex);
         lastIndex = index;
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 38f6f99..1dadda1 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -20,12 +20,12 @@
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <map>
 
 #include <GLES2/gl2.h>
 
 #include "Debug.h"
 #include "Program.h"
-#include "Properties.h"
 
 namespace android {
 namespace uirenderer {
@@ -40,7 +40,7 @@
  */
 class ProgramCache {
 public:
-    ProgramCache();
+    ProgramCache(Extensions& extensions);
     ~ProgramCache();
 
     Program* get(const ProgramDescription& description);
@@ -56,7 +56,7 @@
 
     void printLongString(const String8& shader) const;
 
-    KeyedVector<programid, Program*> mCache;
+    std::map<programid, std::unique_ptr<Program>> mCache;
 
     const bool mHasES3;
 }; // class ProgramCache
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index befed16..a0312e1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -253,9 +253,9 @@
 // Converts a number of kilo-bytes into bytes
 #define KB(s) s * 1024
 
-static DebugLevel readDebugLevel() {
+static inline DebugLevel readDebugLevel() {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_DEBUG, property, NULL) > 0) {
+    if (property_get(PROPERTY_DEBUG, property, nullptr) > 0) {
         return (DebugLevel) atoi(property);
     }
     return kDebugDisabled;
diff --git a/libs/hwui/Query.h b/libs/hwui/Query.h
deleted file mode 100644
index e25b16b..0000000
--- a/libs/hwui/Query.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_QUERY_H
-#define ANDROID_HWUI_QUERY_H
-
-#include <GLES3/gl3.h>
-
-#include "Extensions.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * A Query instance can be used to perform occlusion queries. If the device
- * does not support occlusion queries, the result of a query will always be
- * 0 and the result will always be marked available.
- *
- * To run an occlusion query successfully, you must start end end the query:
- *
- * Query query;
- * query.begin();
- * // execute OpenGL calls
- * query.end();
- * GLuint result = query.getResult();
- */
-class Query {
-public:
-    /**
-     * Possible query targets.
-     */
-    enum Target {
-        /**
-         * Indicates if any sample passed the depth & stencil tests.
-         */
-        kTargetSamples = GL_ANY_SAMPLES_PASSED,
-        /**
-         * Indicates if any sample passed the depth & stencil tests.
-         * The implementation may choose to use a less precise version
-         * of the test, potentially resulting in false positives.
-         */
-        kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
-    };
-
-    /**
-     * Creates a new query with the specified target. The default
-     * target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.)
-     */
-    Query(Target target = kTargetSamples): mActive(false), mTarget(target),
-            mCanQuery(Extensions::getInstance().hasOcclusionQueries()),
-            mQuery(0) {
-    }
-
-    ~Query() {
-        if (mQuery) {
-            glDeleteQueries(1, &mQuery);
-        }
-    }
-
-    /**
-     * Begins the query. If the query has already begun or if the device
-     * does not support occlusion queries, calling this method as no effect.
-     * After calling this method successfully, the query is marked active.
-     */
-    void begin() {
-        if (!mActive && mCanQuery) {
-            if (!mQuery) {
-                glGenQueries(1, &mQuery);
-            }
-
-            glBeginQuery(mTarget, mQuery);
-            mActive = true;
-        }
-    }
-
-    /**
-     * Ends the query. If the query has already begun or if the device
-     * does not support occlusion queries, calling this method as no effect.
-     * After calling this method successfully, the query is marked inactive.
-     */
-    void end() {
-        if (mQuery && mActive) {
-            glEndQuery(mTarget);
-            mActive = false;
-        }
-    }
-
-    /**
-     * Returns true if the query is active, false otherwise.
-     */
-    bool isActive() {
-        return mActive;
-    }
-
-    /**
-     * Returns true if the result of the query is available,
-     * false otherwise. Calling getResult() before the result
-     * is available may result in the calling thread being blocked.
-     * If the device does not support queries, this method always
-     * returns true.
-     */
-    bool isResultAvailable() {
-        if (!mQuery) return true;
-
-        GLuint result;
-        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result);
-        return result == GL_TRUE;
-    }
-
-    /**
-     * Returns the result of the query. If the device does not
-     * support queries this method will return 0.
-     *
-     * Calling this method implicitely calls end() if the query
-     * is currently active.
-     */
-    GLuint getResult() {
-        if (!mQuery) return 0;
-
-        end();
-
-        GLuint result;
-        glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result);
-        return result;
-    }
-
-
-private:
-    bool mActive;
-    GLenum mTarget;
-    bool mCanQuery;
-    GLuint mQuery;
-
-}; // class Query
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_QUERY_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 13265a9..c82082f 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -111,6 +111,10 @@
         set(r.left, r.top, r.right, r.bottom);
     }
 
+    inline void set(const SkIRect& r) {
+        set(r.left(), r.top(), r.right(), r.bottom());
+    }
+
     inline float getWidth() const {
         return right - left;
     }
@@ -248,7 +252,22 @@
         bottom = fmaxf(bottom, y);
     }
 
-    void dump(const char* label = NULL) const {
+    void expandToCoverRect(float otherLeft, float otherTop, float otherRight, float otherBottom) {
+        left = fminf(left, otherLeft);
+        top = fminf(top, otherTop);
+        right = fmaxf(right, otherRight);
+        bottom = fmaxf(bottom, otherBottom);
+    }
+
+    SkRect toSkRect() const {
+        return SkRect::MakeLTRB(left, top, right, bottom);
+    }
+
+    SkIRect toSkIRect() const {
+        return SkIRect::MakeLTRB(left, top, right, bottom);
+    }
+
+    void dump(const char* label = nullptr) const {
         ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
     }
 
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 830a13a..0380c51 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -42,7 +42,7 @@
 
 RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting render buffer cache size to %sMB", property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -108,7 +108,7 @@
 }
 
 RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
-    RenderBuffer* buffer = NULL;
+    RenderBuffer* buffer = nullptr;
 
     RenderBufferEntry entry(format, width, height);
     ssize_t index = mCache.indexOf(entry);
diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h
index af8060f..6c668b0 100644
--- a/libs/hwui/RenderBufferCache.h
+++ b/libs/hwui/RenderBufferCache.h
@@ -78,11 +78,11 @@
 private:
     struct RenderBufferEntry {
         RenderBufferEntry():
-            mBuffer(NULL), mWidth(0), mHeight(0) {
+            mBuffer(nullptr), mWidth(0), mHeight(0) {
         }
 
         RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
-            mBuffer(NULL), mFormat(format), mWidth(width), mHeight(height) {
+            mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {
         }
 
         RenderBufferEntry(RenderBuffer* buffer):
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 787ee62..e009451 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -29,9 +29,9 @@
 #include "DamageAccumulator.h"
 #include "Debug.h"
 #include "DisplayListOp.h"
-#include "DisplayListLogBuffer.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
+#include "TreeInfo.h"
 #include "utils/MathUtils.h"
 #include "utils/TraceUtils.h"
 #include "renderthread/CanvasContext.h"
@@ -39,28 +39,6 @@
 namespace android {
 namespace uirenderer {
 
-void RenderNode::outputLogBuffer(int fd) {
-    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
-    if (logBuffer.isEmpty()) {
-        return;
-    }
-
-    FILE *file = fdopen(fd, "a");
-
-    fprintf(file, "\nRecent DisplayList operations\n");
-    logBuffer.outputCommands(file);
-
-    if (Caches::hasInstance()) {
-        String8 cachesLog;
-        Caches::getInstance().dumpMemoryUsage(cachesLog);
-        fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
-    } else {
-        fprintf(file, "\nNo caches instance.\n");
-    }
-
-    fflush(file);
-}
-
 void RenderNode::debugDumpLayers(const char* prefix) {
     if (mLayer) {
         ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)",
@@ -77,10 +55,10 @@
 RenderNode::RenderNode()
         : mDirtyPropertyFields(0)
         , mNeedsDisplayListDataSync(false)
-        , mDisplayListData(0)
-        , mStagingDisplayListData(0)
+        , mDisplayListData(nullptr)
+        , mStagingDisplayListData(nullptr)
         , mAnimatorManager(*this)
-        , mLayer(0)
+        , mLayer(nullptr)
         , mParentCount(0) {
 }
 
@@ -90,7 +68,7 @@
     if (mLayer) {
         ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer);
         mLayer->postDecStrong();
-        mLayer = 0;
+        mLayer = nullptr;
     }
 }
 
@@ -109,7 +87,7 @@
             getName(),
             (properties().hasShadow() ? ", casting shadow" : ""),
             (isRenderable() ? "" : ", empty"),
-            (mLayer != NULL ? ", on HW Layer" : ""));
+            (mLayer != nullptr ? ", on HW Layer" : ""));
     ALOGD("%*s%s %d", level * 2, "", "Save",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
@@ -161,7 +139,7 @@
 
 void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {
     LayerType layerType = properties().layerProperties().type();
-    if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+    if (CC_UNLIKELY(layerType == LayerType::RenderLayer)) {
         // Damage applied so far needs to affect our parent, but does not require
         // the layer to be updated. So we pop/push here to clear out the current
         // damage and get a clean state for display list or children updates to
@@ -178,10 +156,10 @@
     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 (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
         if (CC_UNLIKELY(mLayer)) {
             LayerRenderer::destroyLayer(mLayer);
-            mLayer = NULL;
+            mLayer = nullptr;
         }
         return;
     }
@@ -195,7 +173,7 @@
     } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
         if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
             LayerRenderer::destroyLayer(mLayer);
-            mLayer = 0;
+            mLayer = nullptr;
         }
         damageSelf(info);
         transformUpdateNeeded = true;
@@ -222,7 +200,7 @@
     }
 
     if (dirty.intersect(0, 0, getWidth(), getHeight())) {
-        dirty.roundOut();
+        dirty.roundOut(&dirty);
         mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
     }
     // This is not inside the above if because we may have called
@@ -310,10 +288,10 @@
             Caches::getInstance().registerFunctors(mStagingDisplayListData->functors.size());
         }
         mDisplayListData = mStagingDisplayListData;
-        mStagingDisplayListData = NULL;
+        mStagingDisplayListData = nullptr;
         if (mDisplayListData) {
             for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
-                (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, NULL);
+                (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
             }
         }
         damageSelf(info);
@@ -330,18 +308,13 @@
         }
     }
     delete mDisplayListData;
-    mDisplayListData = NULL;
+    mDisplayListData = nullptr;
 }
 
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
         info.out.hasFunctors |= subtree->functors.size();
-        // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
-        // and thus falling out of async drawing path.
-        if (subtree->ownedBitmapResources.size()) {
-            info.prepareTextures = false;
-        }
         for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
             info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
         }
@@ -358,7 +331,7 @@
 void RenderNode::destroyHardwareResources() {
     if (mLayer) {
         LayerRenderer::destroyLayer(mLayer);
-        mLayer = NULL;
+        mLayer = nullptr;
     }
     if (mDisplayListData) {
         for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
@@ -411,7 +384,7 @@
             renderer.concatMatrix(*properties().getTransformMatrix());
         }
     }
-    const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = properties().layerProperties().type() != LayerType::None;
     int clipFlags = properties().getClippingFlags();
     if (properties().getAlpha() < 1) {
         if (isLayer) {
@@ -429,9 +402,10 @@
                 clipFlags = 0; // all clipping done by saveLayer
             }
 
-            ATRACE_FORMAT("%s alpha caused %ssaveLayer %dx%d",
-                    getName(), clipFlags ? "" : "unclipped ",
-                    (int)layerBounds.getWidth(), (int)layerBounds.getHeight());
+            ATRACE_FORMAT("%s alpha caused %ssaveLayer %dx%d", getName(),
+                    (saveFlags & SkCanvas::kClipToLayer_SaveFlag) ? "" : "unclipped ",
+                    static_cast<int>(layerBounds.getWidth()),
+                    static_cast<int>(layerBounds.getHeight()));
 
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
                     layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
@@ -516,7 +490,7 @@
 
     // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
     // transform properties are applied correctly to top level children
-    if (mDisplayListData == NULL) return;
+    if (mDisplayListData == nullptr) return;
     for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
         DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
         childOp->mRenderNode->computeOrderingImpl(childOp,
@@ -530,7 +504,7 @@
         Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
         const mat4* transformFromProjectionSurface) {
     mProjectedNodes.clear();
-    if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
+    if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return;
 
     // TODO: should avoid this calculation in most cases
     // TODO: just calculate single matrix, down to all leaf composited elements
@@ -554,9 +528,9 @@
             DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
             RenderNode* child = childOp->mRenderNode;
 
-            const SkPath* projectionOutline = NULL;
-            Vector<DrawRenderNodeOp*>* projectionChildren = NULL;
-            const mat4* projectionTransform = NULL;
+            const SkPath* projectionOutline = nullptr;
+            Vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
+            const mat4* projectionTransform = nullptr;
             if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
                 // if receiving projections, collect projecting descendent
 
@@ -682,7 +656,7 @@
 
 
     // holds temporary SkPath to store the result of intersections
-    SkPath* frameAllocatedPath = NULL;
+    SkPath* frameAllocatedPath = nullptr;
     const SkPath* outlinePath = casterOutlinePath;
 
     // intersect the outline with the reveal clip, if present
@@ -777,7 +751,6 @@
         int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
 
         DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
-        RenderNode* child = childOp->mRenderNode;
 
         renderer.concatMatrix(childOp->mTransformFromParent);
         childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
@@ -810,9 +783,9 @@
 
     // If the projection reciever has an outline, we mask each of the projected rendernodes to it
     // Either with clipRect, or special saveLayer masking
-    if (projectionReceiverOutline != NULL) {
+    if (projectionReceiverOutline != nullptr) {
         const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
-        if (projectionReceiverOutline->isRect(NULL)) {
+        if (projectionReceiverOutline->isRect(nullptr)) {
             // mask to the rect outline simply with clipRect
             ClipRectOp* clipOp = new (alloc) ClipRectOp(
                     outlineBounds.left(), outlineBounds.top(),
@@ -847,7 +820,7 @@
         renderer.restoreToCount(restoreTo);
     }
 
-    if (projectionReceiverOutline != NULL) {
+    if (projectionReceiverOutline != nullptr) {
         handler(new (alloc) RestoreToCountOp(restoreTo),
                 PROPERTY_SAVECOUNT, properties().getClipToBounds());
     }
@@ -864,13 +837,12 @@
  */
 template <class T>
 void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
-    const int level = handler.level();
     if (mDisplayListData->isEmpty()) {
         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
         return;
     }
 
-    const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+    const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get()));
     // 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.
@@ -888,7 +860,7 @@
 #if DEBUG_DISPLAY_LIST
     const Rect& clipRect = renderer.getLocalClipBounds();
     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
-            level * 2, "", this, getName(),
+            handler.level() * 2, "", this, getName(),
             clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
 #endif
 
@@ -915,7 +887,6 @@
         } else {
             const int saveCountOffset = renderer.getSaveCount() - 1;
             const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
-            DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
             for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) {
                 const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex];
 
@@ -926,15 +897,15 @@
                         initialTransform, zTranslatedNodes, renderer, handler);
 
 
-                for (int opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
+                for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
                     DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
 #if DEBUG_DISPLAY_LIST
-                    op->output(level + 1);
+                    op->output(handler.level() + 1);
 #endif
-                    logBuffer.writeCommand(level, op->name());
                     handler(op, saveCountOffset, properties().getClipToBounds());
 
-                    if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && opIndex == projectionReceiveIndex)) {
+                    if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && projectionReceiveIndex >= 0 &&
+                        opIndex == static_cast<size_t>(projectionReceiveIndex))) {
                         issueOperationsOfProjectedChildren(renderer, handler);
                     }
                 }
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 2ce7cb7..bbe53ff 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -33,13 +33,10 @@
 #include <androidfw/ResourceTypes.h>
 
 #include "AnimatorManager.h"
-#include "DamageAccumulator.h"
 #include "Debug.h"
 #include "Matrix.h"
-#include "DeferredDisplayList.h"
 #include "DisplayList.h"
 #include "RenderProperties.h"
-#include "TreeInfo.h"
 
 class SkBitmap;
 class SkPaint;
@@ -61,6 +58,7 @@
 class SaveOp;
 class RestoreToCountOp;
 class DrawRenderNodeOp;
+class TreeInfo;
 
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 250cadc..9f1ceed 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -33,19 +33,17 @@
 namespace android {
 namespace uirenderer {
 
-LayerProperties::LayerProperties()
-        : mType(kLayerTypeNone)
-        , mColorFilter(NULL) {
+LayerProperties::LayerProperties() {
     reset();
 }
 
 LayerProperties::~LayerProperties() {
-    setType(kLayerTypeNone);
+    setType(LayerType::None);
 }
 
 void LayerProperties::reset() {
     mOpaque = false;
-    setFromPaint(NULL);
+    setFromPaint(nullptr);
 }
 
 bool LayerProperties::setColorFilter(SkColorFilter* filter) {
@@ -61,7 +59,7 @@
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
     changed |= setAlpha(static_cast<uint8_t>(alpha));
     changed |= setXferMode(mode);
-    changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+    changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr);
     return changed;
 }
 
@@ -92,7 +90,7 @@
 }
 
 RenderProperties::ComputedFields::ComputedFields()
-        : mTransformMatrix(NULL) {
+        : mTransformMatrix(nullptr) {
 }
 
 RenderProperties::ComputedFields::~ComputedFields() {
@@ -100,8 +98,8 @@
 }
 
 RenderProperties::RenderProperties()
-        : mStaticMatrix(NULL)
-        , mAnimationMatrix(NULL) {
+        : mStaticMatrix(nullptr)
+        , mAnimationMatrix(nullptr) {
 }
 
 RenderProperties::~RenderProperties() {
@@ -146,7 +144,7 @@
         }
     }
 
-    const bool isLayer = layerProperties().type() != kLayerTypeNone;
+    const bool isLayer = layerProperties().type() != LayerType::None;
     int clipFlags = getClippingFlags();
     if (mPrimitiveFields.mAlpha < 1) {
         if (isLayer) {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 31c4f22..61e98d2 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -26,8 +26,8 @@
 #include <SkCamera.h>
 #include <SkMatrix.h>
 #include <SkRegion.h>
+#include <SkXfermode.h>
 
-#include "Animator.h"
 #include "Rect.h"
 #include "RevealClip.h"
 #include "Outline.h"
@@ -49,12 +49,12 @@
 #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,
+enum class LayerType {
+    None = 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,
+    Software = 1,
+    RenderLayer = 2,
     // TODO: LayerTypeSurfaceTexture? Maybe?
 };
 
@@ -124,12 +124,12 @@
 
     friend class RenderProperties;
 
-    LayerType mType;
+    LayerType mType = LayerType::None;
     // Whether or not that Layer's content is opaque, doesn't include alpha
     bool mOpaque;
     uint8_t mAlpha;
     SkXfermode::Mode mMode;
-    SkColorFilter* mColorFilter;
+    SkColorFilter* mColorFilter = nullptr;
 };
 
 /*
@@ -188,7 +188,7 @@
         if (matrix) {
             mStaticMatrix = new SkMatrix(*matrix);
         } else {
-            mStaticMatrix = NULL;
+            mStaticMatrix = nullptr;
         }
         return true;
     }
@@ -203,7 +203,7 @@
         if (matrix) {
             mAnimationMatrix = new SkMatrix(*matrix);
         } else {
-            mAnimationMatrix = NULL;
+            mAnimationMatrix = nullptr;
         }
         return true;
     }
@@ -571,7 +571,7 @@
 
     bool hasShadow() const {
         return getZ() > 0.0f
-                && getOutline().getPath() != NULL
+                && getOutline().getPath() != nullptr
                 && getOutline().getAlpha() != 0.0f;
     }
 
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
deleted file mode 100644
index ca640e5..0000000
--- a/libs/hwui/RenderState.cpp
+++ /dev/null
@@ -1,188 +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.
- */
-#include "RenderState.h"
-
-#include "renderthread/CanvasContext.h"
-#include "renderthread/EglManager.h"
-
-namespace android {
-namespace uirenderer {
-
-RenderState::RenderState(renderthread::RenderThread& thread)
-        : mRenderThread(thread)
-        , mCaches(NULL)
-        , mViewportWidth(0)
-        , mViewportHeight(0)
-        , mFramebuffer(0) {
-    mThreadId = pthread_self();
-}
-
-RenderState::~RenderState() {
-}
-
-void RenderState::onGLContextCreated() {
-    // This is delayed because the first access of Caches makes GL calls
-    mCaches = &Caches::getInstance();
-    mCaches->init();
-    mCaches->setRenderState(this);
-    mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
-}
-
-static void layerLostGlContext(Layer* layer) {
-    layer->onGlContextLost();
-}
-
-void RenderState::onGLContextDestroyed() {
-/*
-    size_t size = mActiveLayers.size();
-    if (CC_UNLIKELY(size != 0)) {
-        ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d",
-                mRegisteredContexts.size(), size, mActiveLayers.empty());
-        mCaches->dumpMemoryUsage();
-        for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
-                cit != mRegisteredContexts.end(); cit++) {
-            renderthread::CanvasContext* context = *cit;
-            ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get());
-            ALOGE("  Prefeteched layers: %zu", context->mPrefetechedLayers.size());
-            for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin();
-                    pit != context->mPrefetechedLayers.end(); pit++) {
-                (*pit)->debugDumpLayers("    ");
-            }
-            context->mRootRenderNode->debugDumpLayers("  ");
-        }
-
-
-        if (mActiveLayers.begin() == mActiveLayers.end()) {
-            ALOGE("set has become empty. wat.");
-        }
-        for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
-             lit != mActiveLayers.end(); lit++) {
-            const Layer* layer = *(lit);
-            ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d",
-                    layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered);
-        }
-        LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
-    }
-*/
-    std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
-    mAssetAtlas.terminate();
-}
-
-void RenderState::setViewport(GLsizei width, GLsizei height) {
-    mViewportWidth = width;
-    mViewportHeight = height;
-    glViewport(0, 0, mViewportWidth, mViewportHeight);
-}
-
-
-void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
-    *outWidth = mViewportWidth;
-    *outHeight = mViewportHeight;
-}
-
-void RenderState::bindFramebuffer(GLuint fbo) {
-    if (mFramebuffer != fbo) {
-        mFramebuffer = fbo;
-        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
-    }
-}
-
-void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
-    interruptForFunctorInvoke();
-    (*functor)(mode, info);
-    resumeFromFunctorInvoke();
-}
-
-void RenderState::interruptForFunctorInvoke() {
-    if (mCaches->currentProgram) {
-        if (mCaches->currentProgram->isInUse()) {
-            mCaches->currentProgram->remove();
-            mCaches->currentProgram = NULL;
-        }
-    }
-    mCaches->resetActiveTexture();
-    mCaches->unbindMeshBuffer();
-    mCaches->unbindIndicesBuffer();
-    mCaches->resetVertexPointers();
-    mCaches->disableTexCoordsVertexArray();
-    debugOverdraw(false, false);
-}
-
-void RenderState::resumeFromFunctorInvoke() {
-    glViewport(0, 0, mViewportWidth, mViewportHeight);
-    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
-    debugOverdraw(false, false);
-
-    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-    mCaches->scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
-    mCaches->enableScissor();
-    mCaches->resetScissor();
-
-    mCaches->activeTexture(0);
-    mCaches->resetBoundTextures();
-
-    mCaches->blend = true;
-    glEnable(GL_BLEND);
-    glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode);
-    glBlendEquation(GL_FUNC_ADD);
-}
-
-void RenderState::debugOverdraw(bool enable, bool clear) {
-    if (mCaches->debugOverdraw && mFramebuffer == 0) {
-        if (clear) {
-            mCaches->disableScissor();
-            mCaches->stencil.clear();
-        }
-        if (enable) {
-            mCaches->stencil.enableDebugWrite();
-        } else {
-            mCaches->stencil.disable();
-        }
-    }
-}
-
-void RenderState::requireGLContext() {
-    assertOnGLThread();
-    mRenderThread.eglManager().requireGlContext();
-}
-
-void RenderState::assertOnGLThread() {
-    pthread_t curr = pthread_self();
-    LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
-}
-
-
-class DecStrongTask : public renderthread::RenderTask {
-public:
-    DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
-
-    virtual void run() {
-        mObject->decStrong(0);
-        mObject = 0;
-        delete this;
-    }
-
-private:
-    VirtualLightRefBase* mObject;
-};
-
-void RenderState::postDecStrong(VirtualLightRefBase* object) {
-    mRenderThread.queue(new DecStrongTask(object));
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
deleted file mode 100644
index 9ac9356..0000000
--- a/libs/hwui/RenderState.h
+++ /dev/null
@@ -1,106 +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.
- */
-#ifndef RENDERSTATE_H
-#define RENDERSTATE_H
-
-#include <set>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <utils/Mutex.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
-#include "AssetAtlas.h"
-#include "Caches.h"
-#include "utils/Macros.h"
-
-namespace android {
-namespace uirenderer {
-
-namespace renderthread {
-class CanvasContext;
-class RenderThread;
-}
-
-// TODO: Replace Cache's GL state tracking with this. For now it's more a thin
-// wrapper of Caches for users to migrate to.
-class RenderState {
-    PREVENT_COPY_AND_ASSIGN(RenderState);
-public:
-    void onGLContextCreated();
-    void onGLContextDestroyed();
-
-    void setViewport(GLsizei width, GLsizei height);
-    void getViewport(GLsizei* outWidth, GLsizei* outHeight);
-
-    void bindFramebuffer(GLuint fbo);
-    GLint getFramebuffer() { return mFramebuffer; }
-
-    void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
-
-    void debugOverdraw(bool enable, bool clear);
-
-    void registerLayer(Layer* layer) {
-        mActiveLayers.insert(layer);
-    }
-    void unregisterLayer(Layer* layer) {
-        mActiveLayers.erase(layer);
-    }
-
-    void registerCanvasContext(renderthread::CanvasContext* context) {
-        mRegisteredContexts.insert(context);
-    }
-
-    void unregisterCanvasContext(renderthread::CanvasContext* context) {
-        mRegisteredContexts.erase(context);
-    }
-
-    void requireGLContext();
-
-    // TODO: This system is a little clunky feeling, this could use some
-    // more thinking...
-    void postDecStrong(VirtualLightRefBase* object);
-
-    AssetAtlas& assetAtlas() { return mAssetAtlas; }
-
-private:
-    friend class renderthread::RenderThread;
-    friend class Caches;
-
-    void interruptForFunctorInvoke();
-    void resumeFromFunctorInvoke();
-    void assertOnGLThread();
-
-    RenderState(renderthread::RenderThread& thread);
-    ~RenderState();
-
-    renderthread::RenderThread& mRenderThread;
-    Caches* mCaches;
-    AssetAtlas mAssetAtlas;
-    std::set<Layer*> mActiveLayers;
-    std::set<renderthread::CanvasContext*> mRegisteredContexts;
-
-    GLsizei mViewportWidth;
-    GLsizei mViewportHeight;
-    GLuint mFramebuffer;
-
-    pthread_t mThreadId;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* RENDERSTATE_H */
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
deleted file mode 100644
index 3159d1e..0000000
--- a/libs/hwui/Renderer.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_RENDERER_H
-#define ANDROID_HWUI_RENDERER_H
-
-#include <SkColorFilter.h>
-#include <SkPaint.h>
-#include <SkRegion.h>
-
-#include <utils/String8.h>
-
-#include "AssetAtlas.h"
-
-namespace android {
-
-class Functor;
-struct Res_png_9patch;
-
-namespace uirenderer {
-
-class RenderNode;
-class Layer;
-class Matrix4;
-class SkiaColorFilter;
-class Patch;
-
-enum DrawOpMode {
-    kDrawOpMode_Immediate,
-    kDrawOpMode_Defer,
-    kDrawOpMode_Flush
-};
-
-/**
- * Hwui's abstract version of Canvas.
- *
- * Provides methods for frame state operations, as well as the SkCanvas style transform/clip state,
- * and varied drawing operations.
- *
- * Should at some point interact with native SkCanvas.
- */
-class ANDROID_API Renderer {
-public:
-    virtual ~Renderer() {}
-
-    /**
-     * Safely retrieves the mode from the specified xfermode. If the specified
-     * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
-     */
-    static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
-        SkXfermode::Mode resultMode;
-        if (!SkXfermode::AsMode(mode, &resultMode)) {
-            resultMode = SkXfermode::kSrcOver_Mode;
-        }
-        return resultMode;
-    }
-
-    // TODO: move to a method on android:Paint
-    static inline bool paintWillNotDraw(const SkPaint& paint) {
-        return paint.getAlpha() == 0
-                && !paint.getColorFilter()
-                && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
-    }
-
-    // TODO: move to a method on android:Paint
-    static inline bool paintWillNotDrawText(const SkPaint& paint) {
-        return paint.getAlpha() == 0
-                && paint.getLooper() == NULL
-                && !paint.getColorFilter()
-                && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
-    }
-
-    static bool isBlendedColorFilter(const SkColorFilter* filter) {
-        if (filter == NULL) {
-            return false;
-        }
-        return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
-    }
-
-// ----------------------------------------------------------------------------
-// Frame state operations
-// ----------------------------------------------------------------------------
-    /**
-     * Sets the dimension of the underlying drawing surface. This method must
-     * be called at least once every time the drawing surface changes size.
-     *
-     * @param width The width in pixels of the underlysing surface
-     * @param height The height in pixels of the underlysing surface
-     */
-    virtual void setViewport(int width, int height) = 0;
-
-    /**
-     * Prepares the renderer to draw a frame. This method must be invoked
-     * at the beginning of each frame. When this method is invoked, the
-     * entire drawing surface is assumed to be redrawn.
-     *
-     * @param opaque If true, the target surface is considered opaque
-     *               and will not be cleared. If false, the target surface
-     *               will be cleared
-     */
-    virtual status_t prepare(bool opaque) = 0;
-
-    /**
-     * Prepares the renderer to draw a frame. This method must be invoked
-     * at the beginning of each frame. Only the specified rectangle of the
-     * frame is assumed to be dirty. A clip will automatically be set to
-     * the specified rectangle.
-     *
-     * @param left The left coordinate of the dirty rectangle
-     * @param top The top coordinate of the dirty rectangle
-     * @param right The right coordinate of the dirty rectangle
-     * @param bottom The bottom coordinate of the dirty rectangle
-     * @param opaque If true, the target surface is considered opaque
-     *               and will not be cleared. If false, the target surface
-     *               will be cleared in the specified dirty rectangle
-     */
-    virtual status_t prepareDirty(float left, float top, float right, float bottom,
-            bool opaque) = 0;
-
-    /**
-     * Indicates the end of a frame. This method must be invoked whenever
-     * the caller is done rendering a frame.
-     */
-    virtual void finish() = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-    // Save (layer)
-    virtual int getSaveCount() const = 0;
-    virtual int save(int flags) = 0;
-    virtual void restore() = 0;
-    virtual void restoreToCount(int saveCount) = 0;
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, int flags) = 0;
-
-    int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, int flags) {
-        SkPaint paint;
-        paint.setAlpha(alpha);
-        return saveLayer(left, top, right, bottom, &paint, flags);
-    }
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
-    virtual void translate(float dx, float dy, float dz = 0.0f) = 0;
-    virtual void rotate(float degrees) = 0;
-    virtual void scale(float sx, float sy) = 0;
-    virtual void skew(float sx, float sy) = 0;
-
-    virtual void setMatrix(const SkMatrix& matrix) = 0;
-    virtual void concatMatrix(const SkMatrix& matrix) = 0;
-
-    // clip
-    virtual const Rect& getLocalClipBounds() const = 0;
-    virtual bool quickRejectConservative(float left, float top,
-            float right, float bottom) const = 0;
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
-
-    // Misc - should be implemented with SkPaint inspection
-    virtual void resetPaintFilter() = 0;
-    virtual void setupPaintFilter(int clearBits, int setBits) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-    virtual status_t drawColor(int color, SkXfermode::Mode mode) = 0;
-
-    // Bitmap-based
-    virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) = 0;
-    virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint) = 0;
-    virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) = 0;
-    virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint) = 0;
-    virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
-            float left, float top, float right, float bottom, const SkPaint* paint) = 0;
-
-    // Shapes
-    virtual status_t drawRect(float left, float top, float right, float bottom,
-            const SkPaint* paint) = 0;
-    virtual status_t drawRects(const float* rects, int count, const SkPaint* paint) = 0;
-    virtual status_t drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint* paint) = 0;
-    virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint) = 0;
-    virtual status_t drawOval(float left, float top, float right, float bottom,
-            const SkPaint* paint) = 0;
-    virtual status_t drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) = 0;
-    virtual status_t drawPath(const SkPath* path, const SkPaint* paint) = 0;
-    virtual status_t drawLines(const float* points, int count, const SkPaint* paint) = 0;
-    virtual status_t drawPoints(const float* points, int count, const SkPaint* paint) = 0;
-
-    // Text
-    virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
-            DrawOpMode drawOpMode = kDrawOpMode_Immediate) = 0;
-    virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
-            float hOffset, float vOffset, const SkPaint* paint) = 0;
-    virtual status_t drawPosText(const char* text, int bytesCount, int count,
-            const float* positions, const SkPaint* paint) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations - special
-// ----------------------------------------------------------------------------
-    virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty,
-            int32_t replayFlags) = 0;
-
-    // TODO: rename for consistency
-    virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty) = 0;
-}; // class Renderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_RENDERER_H
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 31bd637..d3b8d70 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -16,16 +16,13 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <SkPixelRef.h>
 #include "ResourceCache.h"
 #include "Caches.h"
 
 namespace android {
 
-#ifdef USE_OPENGL_RENDERER
 using namespace uirenderer;
 ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
-#endif
 
 namespace uirenderer {
 
@@ -39,8 +36,8 @@
         ResourceReference* ref = mCache->valueAt(i);
         ALOGD("  ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
                 i, mCache->keyAt(i), mCache->valueAt(i));
-        ALOGD("  ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
-                i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
+        ALOGD("  ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
+                i, ref->refCount, ref->destroyed, ref->resourceType);
     }
 }
 
@@ -62,56 +59,48 @@
     mLock.unlock();
 }
 
+const SkBitmap* ResourceCache::insert(const SkBitmap* bitmapResource) {
+    Mutex::Autolock _l(mLock);
+
+    BitmapKey bitmapKey(bitmapResource);
+    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
+    if (index == NAME_NOT_FOUND) {
+        SkBitmap* cachedBitmap = new SkBitmap(*bitmapResource);
+        index = mBitmapCache.add(bitmapKey, cachedBitmap);
+        return cachedBitmap;
+    }
+
+    mBitmapCache.keyAt(index).mRefCount++;
+    return mBitmapCache.valueAt(index);
+}
+
 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     Mutex::Autolock _l(mLock);
     incrementRefcountLocked(resource, resourceType);
 }
 
-void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
-    incrementRefcount((void*) bitmapResource, kBitmap);
-}
-
-void ResourceCache::incrementRefcount(const SkPath* pathResource) {
-    incrementRefcount((void*) pathResource, kPath);
-}
-
 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
     incrementRefcount((void*) patchResource, kNinePatch);
 }
 
 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
     ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL || mCache->size() == 0) {
+    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+    if (ref == nullptr || mCache->size() == 0) {
         ref = new ResourceReference(resourceType);
         mCache->add(resource, ref);
     }
     ref->refCount++;
 }
 
-void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
-    incrementRefcountLocked((void*) bitmapResource, kBitmap);
-}
-
-void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
-    incrementRefcountLocked((void*) pathResource, kPath);
-}
-
-void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
-    incrementRefcountLocked((void*) patchResource, kNinePatch);
-}
-
 void ResourceCache::decrementRefcount(void* resource) {
     Mutex::Autolock _l(mLock);
     decrementRefcountLocked(resource);
 }
 
 void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
-    decrementRefcount((void*) bitmapResource);
-}
-
-void ResourceCache::decrementRefcount(const SkPath* pathResource) {
-    decrementRefcount((void*) pathResource);
+    Mutex::Autolock _l(mLock);
+    decrementRefcountLocked(bitmapResource);
 }
 
 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
@@ -120,8 +109,8 @@
 
 void ResourceCache::decrementRefcountLocked(void* resource) {
     ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
+    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+    if (ref == nullptr) {
         // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
         return;
     }
@@ -132,62 +121,26 @@
 }
 
 void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
-    decrementRefcountLocked((void*) bitmapResource);
-}
+    BitmapKey bitmapKey(bitmapResource);
+    ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
 
-void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
-    decrementRefcountLocked((void*) pathResource);
+    LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
+                    "Decrementing the reference of an untracked Bitmap");
+
+    const BitmapKey& cacheEntry = mBitmapCache.keyAt(index);
+    if (cacheEntry.mRefCount == 1) {
+        // delete the bitmap and remove it from the cache
+        delete mBitmapCache.valueAt(index);
+        mBitmapCache.removeItemsAt(index);
+    } else {
+        cacheEntry.mRefCount--;
+    }
 }
 
 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
     decrementRefcountLocked((void*) patchResource);
 }
 
-void ResourceCache::destructor(SkPath* resource) {
-    Mutex::Autolock _l(mLock);
-    destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(SkPath* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        if (Caches::hasInstance()) {
-            Caches::getInstance().pathCache.removeDeferred(resource);
-        } else {
-            delete resource;
-        }
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-    }
-}
-
-void ResourceCache::destructor(const SkBitmap* resource) {
-    Mutex::Autolock _l(mLock);
-    destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(const SkBitmap* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(resource);
-        }
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-    }
-}
-
 void ResourceCache::destructor(Res_png_9patch* resource) {
     Mutex::Autolock _l(mLock);
     destructorLocked(resource);
@@ -195,8 +148,8 @@
 
 void ResourceCache::destructorLocked(Res_png_9patch* resource) {
     ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
+    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+    if (ref == nullptr) {
         // If we're not tracking this resource, just delete it
         if (Caches::hasInstance()) {
             Caches::getInstance().patchCache.removeDeferred(resource);
@@ -214,73 +167,12 @@
 }
 
 /**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycle(SkBitmap* resource) {
-    Mutex::Autolock _l(mLock);
-    return recycleLocked(resource);
-}
-
-/**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycleLocked(SkBitmap* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    if (index < 0) {
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(resource);
-        }
-        // not tracking this resource; just recycle the pixel data
-        resource->setPixels(NULL, NULL);
-        return true;
-    }
-    ResourceReference* ref = mCache->valueAt(index);
-    if (ref == NULL) {
-        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
-        return true;
-    }
-    ref->recycled = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-        return true;
-    }
-    // Still referring to resource, don't recycle yet
-    return false;
-}
-
-/**
  * This method should only be called while the mLock mutex is held (that mutex is grabbed
  * by the various destructor() and recycle() methods which call this method).
  */
 void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
-    if (ref->recycled && ref->resourceType == kBitmap) {
-        SkBitmap* bitmap = (SkBitmap*) resource;
-        if (Caches::hasInstance()) {
-            Caches::getInstance().textureCache.releaseTexture(bitmap);
-        }
-        bitmap->setPixels(NULL, NULL);
-    }
     if (ref->destroyed) {
         switch (ref->resourceType) {
-            case kBitmap: {
-                SkBitmap* bitmap = (SkBitmap*) resource;
-                if (Caches::hasInstance()) {
-                    Caches::getInstance().textureCache.releaseTexture(bitmap);
-                }
-                delete bitmap;
-            }
-            break;
-            case kPath: {
-                SkPath* path = (SkPath*) resource;
-                if (Caches::hasInstance()) {
-                    Caches::getInstance().pathCache.removeDeferred(path);
-                } else {
-                    delete path;
-                }
-            }
-            break;
             case kNinePatch: {
                 if (Caches::hasInstance()) {
                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
@@ -298,5 +190,38 @@
     delete ref;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Bitmap Key
+///////////////////////////////////////////////////////////////////////////////
+
+void BitmapKey::operator=(const BitmapKey& other) {
+    this->mRefCount = other.mRefCount;
+    this->mBitmapDimensions = other.mBitmapDimensions;
+    this->mPixelRefOrigin = other.mPixelRefOrigin;
+    this->mPixelRefStableID = other.mPixelRefStableID;
+}
+
+bool BitmapKey::operator==(const BitmapKey& other) const {
+    return mPixelRefStableID == other.mPixelRefStableID &&
+           mPixelRefOrigin == other.mPixelRefOrigin &&
+           mBitmapDimensions == other.mBitmapDimensions;
+}
+
+bool BitmapKey::operator<(const BitmapKey& other) const {
+    if (mPixelRefStableID != other.mPixelRefStableID) {
+        return mPixelRefStableID < other.mPixelRefStableID;
+    }
+    if (mPixelRefOrigin.x() != other.mPixelRefOrigin.x()) {
+        return mPixelRefOrigin.x() < other.mPixelRefOrigin.x();
+    }
+    if (mPixelRefOrigin.y() != other.mPixelRefOrigin.y()) {
+        return mPixelRefOrigin.y() < other.mPixelRefOrigin.y();
+    }
+    if (mBitmapDimensions.width() != other.mBitmapDimensions.width()) {
+        return mBitmapDimensions.width() < other.mBitmapDimensions.width();
+    }
+    return mBitmapDimensions.height() < other.mBitmapDimensions.height();
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index f12f2a4..fae55d1 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -20,39 +20,68 @@
 #include <cutils/compiler.h>
 
 #include <SkBitmap.h>
+#include <SkPixelRef.h>
 
 #include <utils/KeyedVector.h>
 #include <utils/Singleton.h>
 
 #include <androidfw/ResourceTypes.h>
 
-#include "Layer.h"
-
 namespace android {
 namespace uirenderer {
 
+class Layer;
+
 /**
  * Type of Resource being cached
  */
 enum ResourceType {
-    kBitmap,
     kNinePatch,
-    kPath
 };
 
 class ResourceReference {
 public:
 
     ResourceReference(ResourceType type) {
-        refCount = 0; recycled = false; destroyed = false; resourceType = type;
+        refCount = 0; destroyed = false; resourceType = type;
     }
 
     int refCount;
-    bool recycled;
     bool destroyed;
     ResourceType resourceType;
 };
 
+class BitmapKey {
+public:
+    BitmapKey(const SkBitmap* bitmap)
+        : mRefCount(1)
+        , mBitmapDimensions(bitmap->dimensions())
+        , mPixelRefOrigin(bitmap->pixelRefOrigin())
+        , mPixelRefStableID(bitmap->pixelRef()->getStableID()) { }
+
+    void operator=(const BitmapKey& other);
+    bool operator==(const BitmapKey& other) const;
+    bool operator<(const BitmapKey& other) const;
+
+private:
+    // This constructor is only used by the KeyedVector implementation
+    BitmapKey()
+        : mRefCount(-1)
+        , mBitmapDimensions(SkISize::Make(0,0))
+        , mPixelRefOrigin(SkIPoint::Make(0,0))
+        , mPixelRefStableID(0) { }
+
+    // reference count of all HWUI object using this bitmap
+    mutable int mRefCount;
+
+    SkISize mBitmapDimensions;
+    SkIPoint mPixelRefOrigin;
+    uint32_t mPixelRefStableID;
+
+    friend class ResourceCache;
+    friend struct android::key_value_pair_t<BitmapKey, SkBitmap*>;
+};
+
 class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
     ResourceCache();
     ~ResourceCache();
@@ -68,33 +97,24 @@
     void lock();
     void unlock();
 
-    void incrementRefcount(const SkPath* resource);
-    void incrementRefcount(const SkBitmap* resource);
+    /**
+     * The cache stores a copy of the provided resource or refs an existing resource
+     * if the bitmap has previously been inserted and returns the cached copy.
+     */
+    const SkBitmap* insert(const SkBitmap* resource);
+
     void incrementRefcount(const Res_png_9patch* resource);
 
-    void incrementRefcountLocked(const SkPath* resource);
-    void incrementRefcountLocked(const SkBitmap* resource);
-    void incrementRefcountLocked(const Res_png_9patch* resource);
-
     void decrementRefcount(const SkBitmap* resource);
-    void decrementRefcount(const SkPath* resource);
     void decrementRefcount(const Res_png_9patch* resource);
 
     void decrementRefcountLocked(const SkBitmap* resource);
-    void decrementRefcountLocked(const SkPath* resource);
     void decrementRefcountLocked(const Res_png_9patch* resource);
 
-    void destructor(SkPath* resource);
-    void destructor(const SkBitmap* resource);
     void destructor(Res_png_9patch* resource);
 
-    void destructorLocked(SkPath* resource);
-    void destructorLocked(const SkBitmap* resource);
     void destructorLocked(Res_png_9patch* resource);
 
-    bool recycle(SkBitmap* resource);
-    bool recycleLocked(SkBitmap* resource);
-
 private:
     void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref);
 
@@ -114,6 +134,7 @@
     mutable Mutex mLock;
 
     KeyedVector<const void*, ResourceReference*>* mCache;
+    KeyedVector<BitmapKey, SkBitmap*> mBitmapCache;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index a9600f1..0084a8e 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -54,7 +54,7 @@
     float getRadius() const { return mRadius; }
 
     const SkPath* getPath() const {
-        if (!mShouldClip) return NULL;
+        if (!mShouldClip) return nullptr;
 
         return &mPath;
     }
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index c1ffa0a..9509c48 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -87,9 +87,8 @@
     reverseReceiverTransform.loadInverse(receiverTransform);
     reverseReceiverTransform.mapPoint3d(adjustedLightCenter);
 
-    const int lightVertexCount = 8;
-    if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
-        lightRadius = caches.propertyLightDiameter;
+    if (CC_UNLIKELY(caches.propertyLightRadius > 0)) {
+        lightRadius = caches.propertyLightRadius;
     }
 
     // Now light and caster are both in local space, we will check whether
@@ -114,33 +113,6 @@
 #endif
 }
 
-void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
-    int currentIndex = 0;
-    const int rays = SHADOW_RAY_COUNT;
-    // For the penumbra area.
-    for (int layer = 0; layer < 2; layer ++) {
-        int baseIndex = layer * rays;
-        for (int i = 0; i < rays; i++) {
-            shadowIndices[currentIndex++] = i + baseIndex;
-            shadowIndices[currentIndex++] = rays + i + baseIndex;
-        }
-        // To close the loop, back to the ray 0.
-        shadowIndices[currentIndex++] = 0 + baseIndex;
-         // Note this is the same as the first index of next layer loop.
-        shadowIndices[currentIndex++] = rays + baseIndex;
-    }
-
-#if DEBUG_SHADOW
-    if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
-        ALOGW("vertex index count is wrong. current %d, expected %d",
-                currentIndex, MAX_SHADOW_INDEX_COUNT);
-    }
-    for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
-        ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
-    }
-#endif
-}
-
 /**
  * Calculate the centroid of a 2d polygon.
  *
@@ -194,7 +166,7 @@
  * @param len the number of points of the polygon
  */
 bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
-    if (len < 2 || polygon == NULL) {
+    if (len < 2 || polygon == nullptr) {
         return true;
     }
     double sum = 0;
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 8f19b5c..c04d8ef 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -18,14 +18,16 @@
 #ifndef ANDROID_HWUI_SHADOW_TESSELLATOR_H
 #define ANDROID_HWUI_SHADOW_TESSELLATOR_H
 
+#include <SkPath.h>
+
 #include "Debug.h"
 #include "Matrix.h"
-#include "OpenGLRenderer.h"
-#include "VertexBuffer.h"
 
 namespace android {
 namespace uirenderer {
 
+class VertexBuffer;
+
 // All SHADOW_* are used to define all the geometry property of shadows.
 // Use a simplified example to illustrate the geometry setup here.
 // Assuming we use 6 rays and only 1 layer, Then we will have 2 hexagons, which
@@ -76,8 +78,6 @@
             const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
             const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
 
-    static void generateShadowIndices(uint16_t*  shadowIndices);
-
     static Vector2 centroid2d(const Vector2* poly, int polyLength);
 
     static bool isClockwise(const Vector2* polygon, int len);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
new file mode 100644
index 0000000..71088b7
--- /dev/null
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -0,0 +1,715 @@
+/*
+ * 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 "Canvas.h"
+
+#include <SkCanvas.h>
+#include <SkClipStack.h>
+#include <SkDevice.h>
+#include <SkDeque.h>
+#include <SkDrawFilter.h>
+#include <SkGraphics.h>
+#include <SkShader.h>
+#include <SkTArray.h>
+#include <SkTemplates.h>
+
+namespace android {
+
+// Holds an SkCanvas reference plus additional native data.
+class SkiaCanvas : public Canvas {
+public:
+    explicit SkiaCanvas(SkBitmap* bitmap);
+
+    /**
+     *  Create a new SkiaCanvas.
+     *
+     *  @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
+     *      not be NULL. This constructor will ref() the SkCanvas, and unref()
+     *      it in its destructor.
+     */
+    explicit SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {
+        SkASSERT(canvas);
+        canvas->ref();
+    }
+
+    virtual SkCanvas* asSkCanvas() override {
+        return mCanvas.get();
+    }
+
+    virtual void setBitmap(SkBitmap* bitmap, bool copyState) override;
+
+    virtual bool isOpaque() override;
+    virtual int width() override;
+    virtual int height() override;
+
+    virtual int getSaveCount() const override;
+    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual void restore() override;
+    virtual void restoreToCount(int saveCount) override;
+
+    virtual int saveLayer(float left, float top, float right, float bottom,
+                const SkPaint* paint, SkCanvas::SaveFlags flags) override;
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, SkCanvas::SaveFlags flags) override;
+
+    virtual void getMatrix(SkMatrix* outMatrix) const override;
+    virtual void setMatrix(const SkMatrix& matrix) override;
+    virtual void concat(const SkMatrix& matrix) override;
+    virtual void rotate(float degrees) override;
+    virtual void scale(float sx, float sy) override;
+    virtual void skew(float sx, float sy) override;
+    virtual void translate(float dx, float dy) override;
+
+    virtual bool getClipBounds(SkRect* outRect) const override;
+    virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
+    virtual bool quickRejectPath(const SkPath& path) const override;
+    virtual bool clipRect(float left, float top, float right, float bottom,
+            SkRegion::Op op) override;
+    virtual bool clipPath(const SkPath* path, SkRegion::Op op) override;
+    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override;
+
+    virtual SkDrawFilter* getDrawFilter() override;
+    virtual void setDrawFilter(SkDrawFilter* drawFilter) override;
+
+    virtual void drawColor(int color, SkXfermode::Mode mode) override;
+    virtual void drawPaint(const SkPaint& paint) override;
+
+    virtual void drawPoint(float x, float y, const SkPaint& paint) override;
+    virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawLine(float startX, float startY, float stopX, float stopY,
+            const SkPaint& paint) override;
+    virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
+    virtual void drawRect(float left, float top, float right, float bottom,
+            const SkPaint& paint) override;
+    virtual void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint& paint) override;
+    virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
+    virtual void drawOval(float left, float top, float right, float bottom,
+            const SkPaint& paint) override;
+    virtual void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+    virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
+    virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+            const float* verts, const float* tex, const int* colors,
+            const uint16_t* indices, int indexCount, const SkPaint& paint) override;
+
+    virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+            const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+            const SkPaint* paint) override;
+    virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint) override;
+    virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint) override;
+
+    virtual void drawText(const uint16_t* text, const float* positions, int count,
+            const SkPaint& paint, float x, float y,
+            float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+            float totalAdvance) override;
+    virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+            int posCount, const SkPaint& paint) override;
+    virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+            float hOffset, float vOffset, const SkPaint& paint) override;
+
+    virtual bool drawTextAbsolutePos() const  override { return true; }
+
+private:
+    struct SaveRec {
+        int                 saveCount;
+        SkCanvas::SaveFlags saveFlags;
+    };
+
+    void recordPartialSave(SkCanvas::SaveFlags flags);
+    void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
+    void applyClips(const SkTArray<SkClipStack::Element>& clips);
+
+    void drawPoints(const float* points, int count, const SkPaint& paint,
+                    SkCanvas::PointMode mode);
+    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+
+    SkAutoTUnref<SkCanvas> mCanvas;
+    SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
+};
+
+// Construct an SkCanvas from the bitmap.
+static SkCanvas* createCanvas(SkBitmap* bitmap) {
+    if (bitmap) {
+        return SkNEW_ARGS(SkCanvas, (*bitmap));
+    }
+
+    // Create an empty bitmap device to prevent callers from crashing
+    // if they attempt to draw into this canvas.
+    SkBitmap emptyBitmap;
+    return new SkCanvas(emptyBitmap);
+}
+
+Canvas* Canvas::create_canvas(SkBitmap* bitmap) {
+    return new SkiaCanvas(bitmap);
+}
+
+Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
+    return new SkiaCanvas(skiaCanvas);
+}
+
+SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) {
+    mCanvas.reset(createCanvas(bitmap));
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Replace Bitmap
+// ----------------------------------------------------------------------------
+
+class ClipCopier : public SkCanvas::ClipVisitor {
+public:
+    ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
+
+    virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
+        m_dstCanvas->clipRect(rect, op, antialias);
+    }
+    virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
+        m_dstCanvas->clipRRect(rrect, op, antialias);
+    }
+    virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
+        m_dstCanvas->clipPath(path, op, antialias);
+    }
+
+private:
+    SkCanvas* m_dstCanvas;
+};
+
+void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) {
+    SkCanvas* newCanvas = createCanvas(bitmap);
+    SkASSERT(newCanvas);
+
+    if (copyState) {
+        // Copy the canvas matrix & clip state.
+        newCanvas->setMatrix(mCanvas->getTotalMatrix());
+        if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
+            ClipCopier copier(newCanvas);
+            mCanvas->replayClips(&copier);
+        }
+    }
+
+    // unrefs the existing canvas
+    mCanvas.reset(newCanvas);
+
+    // clean up the old save stack
+    mSaveStack.reset(NULL);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+
+bool SkiaCanvas::isOpaque() {
+    return mCanvas->getDevice()->accessBitmap(false).isOpaque();
+}
+
+int SkiaCanvas::width() {
+    return mCanvas->getBaseLayerSize().width();
+}
+
+int SkiaCanvas::height() {
+    return mCanvas->getBaseLayerSize().height();
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Save (layer)
+// ----------------------------------------------------------------------------
+
+int SkiaCanvas::getSaveCount() const {
+    return mCanvas->getSaveCount();
+}
+
+int SkiaCanvas::save(SkCanvas::SaveFlags flags) {
+    int count = mCanvas->save();
+    recordPartialSave(flags);
+    return count;
+}
+
+void SkiaCanvas::restore() {
+    const SaveRec* rec = (NULL == mSaveStack.get())
+            ? 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();
+}
+
+void SkiaCanvas::restoreToCount(int restoreCount) {
+    while (mCanvas->getSaveCount() > restoreCount) {
+        this->restore();
+    }
+}
+
+int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* paint, SkCanvas::SaveFlags flags) {
+    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+    int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
+    recordPartialSave(flags);
+    return count;
+}
+
+int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
+        int alpha, SkCanvas::SaveFlags flags) {
+    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+    int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag);
+    recordPartialSave(flags);
+    return count;
+}
+
+// ----------------------------------------------------------------------------
+// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::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.get()) {
+        mSaveStack.reset(SkNEW_ARGS(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 SkiaCanvas::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 SkiaCanvas::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);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Matrix
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
+    *outMatrix = mCanvas->getTotalMatrix();
+}
+
+void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
+    mCanvas->setMatrix(matrix);
+}
+
+void SkiaCanvas::concat(const SkMatrix& matrix) {
+    mCanvas->concat(matrix);
+}
+
+void SkiaCanvas::rotate(float degrees) {
+    mCanvas->rotate(degrees);
+}
+
+void SkiaCanvas::scale(float sx, float sy) {
+    mCanvas->scale(sx, sy);
+}
+
+void SkiaCanvas::skew(float sx, float sy) {
+    mCanvas->skew(sx, sy);
+}
+
+void SkiaCanvas::translate(float dx, float dy) {
+    mCanvas->translate(dx, dy);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Clips
+// ----------------------------------------------------------------------------
+
+// This function is a mirror of SkCanvas::getClipBounds except that it does
+// not outset the edge of the clip to account for anti-aliasing. There is
+// a skia bug to investigate pushing this logic into back into skia.
+// (see https://code.google.com/p/skia/issues/detail?id=1303)
+bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
+    SkIRect ibounds;
+    if (!mCanvas->getClipDeviceBounds(&ibounds)) {
+        return false;
+    }
+
+    SkMatrix inverse;
+    // if we can't invert the CTM, we can't return local clip bounds
+    if (!mCanvas->getTotalMatrix().invert(&inverse)) {
+        if (outRect) {
+            outRect->setEmpty();
+        }
+        return false;
+    }
+
+    if (NULL != outRect) {
+        SkRect r = SkRect::Make(ibounds);
+        inverse.mapRect(outRect, r);
+    }
+    return true;
+}
+
+bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
+    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+    return mCanvas->quickReject(bounds);
+}
+
+bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
+    return mCanvas->quickReject(path);
+}
+
+bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+    mCanvas->clipRect(rect, op);
+    return mCanvas->isClipEmpty();
+}
+
+bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
+    mCanvas->clipPath(*path, op);
+    return mCanvas->isClipEmpty();
+}
+
+bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
+    SkPath rgnPath;
+    if (region->getBoundaryPath(&rgnPath)) {
+        // The region is specified in device space.
+        SkMatrix savedMatrix = mCanvas->getTotalMatrix();
+        mCanvas->resetMatrix();
+        mCanvas->clipPath(rgnPath, op);
+        mCanvas->setMatrix(savedMatrix);
+    } else {
+        mCanvas->clipRect(SkRect::MakeEmpty(), op);
+    }
+    return mCanvas->isClipEmpty();
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Filters
+// ----------------------------------------------------------------------------
+
+SkDrawFilter* SkiaCanvas::getDrawFilter() {
+    return mCanvas->getDrawFilter();
+}
+
+void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
+    mCanvas->setDrawFilter(drawFilter);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) {
+    mCanvas->drawColor(color, mode);
+}
+
+void SkiaCanvas::drawPaint(const SkPaint& paint) {
+    mCanvas->drawPaint(paint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Geometry
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
+                            SkCanvas::PointMode mode) {
+    // convert the floats into SkPoints
+    count >>= 1;    // now it is the number of points
+    SkAutoSTMalloc<32, SkPoint> storage(count);
+    SkPoint* pts = storage.get();
+    for (int i = 0; i < count; i++) {
+        pts[i].set(points[0], points[1]);
+        points += 2;
+    }
+    mCanvas->drawPoints(mode, count, pts, paint);
+}
+
+
+void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
+    mCanvas->drawPoint(x, y, paint);
+}
+
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
+    this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
+}
+
+void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
+                          const SkPaint& paint) {
+    mCanvas->drawLine(startX, startY, stopX, stopY, paint);
+}
+
+void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+    this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
+}
+
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
+        const SkPaint& paint) {
+    mCanvas->drawRectCoords(left, top, right, bottom, paint);
+
+}
+
+void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
+        float rx, float ry, const SkPaint& paint) {
+    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+    mCanvas->drawRoundRect(rect, rx, ry, paint);
+}
+
+void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+    mCanvas->drawCircle(x, y, radius, paint);
+}
+
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+    SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+    mCanvas->drawOval(oval, paint);
+}
+
+void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
+        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+    SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
+    mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+}
+
+void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+    mCanvas->drawPath(path, paint);
+}
+
+void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+                              const float* verts, const float* texs, const int* colors,
+                              const uint16_t* indices, int indexCount, const SkPaint& paint) {
+#ifndef SK_SCALAR_IS_FLOAT
+    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
+#endif
+    const int ptCount = vertexCount >> 1;
+    mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
+                          (SkColor*)colors, NULL, indices, indexCount, paint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Bitmaps
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
+    mCanvas->drawBitmap(bitmap, left, top, paint);
+}
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+    SkAutoCanvasRestore acr(mCanvas, true);
+    mCanvas->concat(matrix);
+    mCanvas->drawBitmap(bitmap, 0, 0, paint);
+}
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+                            float srcRight, float srcBottom, float dstLeft, float dstTop,
+                            float dstRight, float dstBottom, const SkPaint* paint) {
+    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
+    SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
+    mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
+}
+
+void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+        const float* vertices, const int* colors, const SkPaint* paint) {
+
+    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
+    const int indexCount = meshWidth * meshHeight * 6;
+
+    /*  Our temp storage holds 2 or 3 arrays.
+        texture points [ptCount * sizeof(SkPoint)]
+        optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
+            copy to convert from float to fixed
+        indices [ptCount * sizeof(uint16_t)]
+    */
+    ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
+    storageSize += indexCount * sizeof(uint16_t);  // indices[]
+
+
+#ifndef SK_SCALAR_IS_FLOAT
+    SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
+#endif
+    SkAutoMalloc storage(storageSize);
+    SkPoint* texs = (SkPoint*)storage.get();
+    uint16_t* indices = (uint16_t*)(texs + ptCount);
+
+    // cons up texture coordinates and indices
+    {
+        const SkScalar w = SkIntToScalar(bitmap.width());
+        const SkScalar h = SkIntToScalar(bitmap.height());
+        const SkScalar dx = w / meshWidth;
+        const SkScalar dy = h / meshHeight;
+
+        SkPoint* texsPtr = texs;
+        SkScalar y = 0;
+        for (int i = 0; i <= meshHeight; i++) {
+            if (i == meshHeight) {
+                y = h;  // to ensure numerically we hit h exactly
+            }
+            SkScalar x = 0;
+            for (int j = 0; j < meshWidth; j++) {
+                texsPtr->set(x, y);
+                texsPtr += 1;
+                x += dx;
+            }
+            texsPtr->set(w, y);
+            texsPtr += 1;
+            y += dy;
+        }
+        SkASSERT(texsPtr - texs == ptCount);
+    }
+
+    // cons up indices
+    {
+        uint16_t* indexPtr = indices;
+        int index = 0;
+        for (int i = 0; i < meshHeight; i++) {
+            for (int j = 0; j < meshWidth; j++) {
+                // lower-left triangle
+                *indexPtr++ = index;
+                *indexPtr++ = index + meshWidth + 1;
+                *indexPtr++ = index + meshWidth + 2;
+                // upper-right triangle
+                *indexPtr++ = index;
+                *indexPtr++ = index + meshWidth + 2;
+                *indexPtr++ = index + 1;
+                // bump to the next cell
+                index += 1;
+            }
+            // bump to the next row
+            index += 1;
+        }
+        SkASSERT(indexPtr - indices == indexCount);
+        SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
+    }
+
+    // double-check that we have legal indices
+#ifdef SK_DEBUG
+    {
+        for (int i = 0; i < indexCount; i++) {
+            SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
+        }
+    }
+#endif
+
+    // cons-up a shader for the bitmap
+    SkPaint tmpPaint;
+    if (paint) {
+        tmpPaint = *paint;
+    }
+    SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+                                                    SkShader::kClamp_TileMode,
+                                                    SkShader::kClamp_TileMode);
+    SkSafeUnref(tmpPaint.setShader(shader));
+
+    mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
+                         texs, (const SkColor*)colors, NULL, indices,
+                         indexCount, tmpPaint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Text
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
+        const SkPaint& paint, float x, float y,
+        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+        float totalAdvance) {
+    // Set align to left for drawing, as we don't want individual
+    // glyphs centered or right-aligned; the offset above takes
+    // care of all alignment.
+    SkPaint paintCopy(paint);
+    paintCopy.setTextAlign(SkPaint::kLeft_Align);
+
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
+}
+
+void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount,
+        const SkPaint& paint) {
+    SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
+    int indx;
+    for (indx = 0; indx < posCount; indx++) {
+        posPtr[indx].fX = positions[indx << 1];
+        posPtr[indx].fY = positions[(indx << 1) + 1];
+    }
+
+    SkPaint paintCopy(paint);
+    paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+    mCanvas->drawPosText(text, count, posPtr, paintCopy);
+
+    delete[] posPtr;
+}
+
+void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+        float hOffset, float vOffset, const SkPaint& paint) {
+    mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
+}
+
+} // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
new file mode 100644
index 0000000..ec1bb90
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkiaCanvasProxy.h"
+
+#include <cutils/log.h>
+#include <SkPatchUtils.h>
+
+namespace android {
+namespace uirenderer {
+
+SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
+        : INHERITED(canvas->width(), canvas->height())
+        , mCanvas(canvas)
+        , mFilterHwuiCalls(filterHwuiCalls) {}
+
+void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
+    mCanvas->drawPaint(paint);
+}
+
+void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
+        const SkPaint& paint) {
+    if (!pts || count == 0) {
+        return;
+    }
+
+    // convert the SkPoints into floats
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    const size_t floatCount = count << 1;
+    const float* floatArray = &pts[0].fX;
+
+    switch (pointMode) {
+        case kPoints_PointMode: {
+            mCanvas->drawPoints(floatArray, floatCount, paint);
+            break;
+        }
+        case kLines_PointMode: {
+            mCanvas->drawLines(floatArray, floatCount, paint);
+            break;
+        }
+        case kPolygon_PointMode: {
+            SkPaint strokedPaint(paint);
+            strokedPaint.setStyle(SkPaint::kStroke_Style);
+
+            SkPath path;
+            for (size_t i = 0; i < count - 1; i++) {
+                path.moveTo(pts[i]);
+                path.lineTo(pts[i+1]);
+                this->drawPath(path, strokedPaint);
+                path.rewind();
+            }
+            break;
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown point type");
+    }
+}
+
+void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
+    mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+    mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
+    if (!roundRect.isComplex()) {
+        const SkRect& rect = roundRect.rect();
+        SkVector radii = roundRect.getSimpleRadii();
+        mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+                               radii.fX, radii.fY, paint);
+    } else {
+        SkPath path;
+        path.addRRect(roundRect);
+        mCanvas->drawPath(path, paint);
+    }
+}
+
+void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
+    mCanvas->drawPath(path, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+        const SkPaint* paint) {
+    mCanvas->drawBitmap(bitmap, left, top, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr,
+        const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags) {
+    SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height());
+    mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+                        dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+        const SkRect& dst, const SkPaint*) {
+    //TODO make nine-patch drawing a method on Canvas.h
+    SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
+}
+
+void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top,
+        const SkPaint* paint) {
+    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+    mCanvas->setMatrix(SkMatrix::I());
+    mCanvas->drawBitmap(bitmap, left, top, paint);
+    mCanvas->restore();
+}
+
+void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
+        const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
+        int indexCount, const SkPaint& paint) {
+    if (mFilterHwuiCalls) {
+        return;
+    }
+    // convert the SkPoints into floats
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    const int floatCount = vertexCount << 1;
+    const float* vArray = &vertices[0].fX;
+    const float* tArray = (texs) ? &texs[0].fX : NULL;
+    const int* cArray = (colors) ? (int*)colors : NULL;
+    mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
+}
+
+SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
+    SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
+    return NULL;
+}
+
+void SkiaCanvasProxy::willSave() {
+    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+}
+
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::willSaveLayer(const SkRect* rectPtr,
+        const SkPaint* paint, SaveFlags flags) {
+    SkRect rect;
+    if (rectPtr) {
+        rect = *rectPtr;
+    } else if(!mCanvas->getClipBounds(&rect)) {
+        rect = SkRect::MakeEmpty();
+    }
+    mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint, flags);
+    return SkCanvas::kNoLayer_SaveLayerStrategy;
+}
+
+void SkiaCanvasProxy::willRestore() {
+    mCanvas->restore();
+}
+
+void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
+    mCanvas->concat(matrix);
+}
+
+void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
+    mCanvas->setMatrix(matrix);
+}
+
+void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+        const SkPaint& paint) {
+    SkPath path;
+    path.addRRect(outer);
+    path.addRRect(inner);
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    this->drawPath(path, paint);
+}
+
+/**
+ * Utility class that converts the incoming text & paint from the given encoding
+ * into glyphIDs.
+ */
+class GlyphIDConverter {
+public:
+    GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
+        paint = origPaint;
+        if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
+            glyphIDs = (uint16_t*)text;
+            count = byteLength >> 1;
+        } else {
+            storage.reset(byteLength); // ensures space for one glyph per ID given UTF8 encoding.
+            glyphIDs = storage.get();
+            count = paint.textToGlyphs(text, byteLength, storage.get());
+            paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        }
+    }
+
+    SkPaint paint;
+    uint16_t* glyphIDs;
+    int count;
+private:
+    SkAutoSTMalloc<32, uint16_t> storage;
+};
+
+void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+        const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+    // compute the glyph positions
+    SkAutoSTMalloc<32, SkPoint> pointStorage(glyphs.count);
+    SkAutoSTMalloc<32, SkScalar> glyphWidths(glyphs.count);
+    glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
+
+    // compute conservative bounds
+    // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+    //       but even more conservative bounds if this  is too slow.
+    SkRect bounds;
+    glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+    // adjust for non-left alignment
+    if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
+        SkScalar stop = 0;
+        for (int i = 0; i < glyphs.count; i++) {
+            stop += glyphWidths[i];
+        }
+        if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
+            stop = SkScalarHalf(stop);
+        }
+        if (glyphs.paint.isVerticalText()) {
+            y -= stop;
+        } else {
+            x -= stop;
+        }
+    }
+
+    // setup the first glyph position and adjust bounds if needed
+    int xBaseline = 0;
+    int yBaseline = 0;
+    if (mCanvas->drawTextAbsolutePos()) {
+        bounds.offset(x,y);
+        xBaseline = x;
+        yBaseline = y;
+    }
+    pointStorage[0].set(xBaseline, yBaseline);
+
+    // setup the remaining glyph positions
+    if (glyphs.paint.isVerticalText()) {
+        for (int i = 1; i < glyphs.count; i++) {
+            pointStorage[i].set(xBaseline, glyphWidths[i-1] + pointStorage[i-1].fY);
+        }
+    } else {
+        for (int i = 1; i < glyphs.count; i++) {
+            pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline);
+        }
+    }
+
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
+                      x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+        const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+    // convert to relative positions if necessary
+    int x, y;
+    const SkPoint* posArray;
+    SkAutoSTMalloc<32, SkPoint> pointStorage;
+    if (mCanvas->drawTextAbsolutePos()) {
+        x = 0;
+        y = 0;
+        posArray = pos;
+    } else {
+        x = pos[0].fX;
+        y = pos[0].fY;
+        posArray = pointStorage.reset(glyphs.count);
+        for (int i = 0; i < glyphs.count; i++) {
+            pointStorage[i].fX = pos[i].fX- x;
+            pointStorage[i].fY = pos[i].fY- y;
+        }
+    }
+
+    // compute conservative bounds
+    // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+    //       but even more conservative bounds if this  is too slow.
+    SkRect bounds;
+    glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+    SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+    mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
+                      bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+        SkScalar constY, const SkPaint& paint) {
+    const size_t pointCount = byteLength >> 1;
+    SkAutoSTMalloc<32, SkPoint> storage(pointCount);
+    SkPoint* pts = storage.get();
+    for (size_t i = 0; i < pointCount; i++) {
+        pts[i].set(xpos[i], constY);
+    }
+    this->onDrawPosText(text, byteLength, pts, paint);
+}
+
+void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+        const SkMatrix* matrix, const SkPaint& origPaint) {
+    // convert to glyphIDs if necessary
+    GlyphIDConverter glyphs(text, byteLength, origPaint);
+    mCanvas->drawTextOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
+}
+
+void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+        const SkPaint& paint) {
+    SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
+}
+
+void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+        const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    if (mFilterHwuiCalls) {
+        return;
+    }
+    SkPatchUtils::VertexData data;
+
+    SkMatrix matrix;
+    mCanvas->getMatrix(&matrix);
+    SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
+
+    // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
+    // If it fails to generate the vertices, then we do not draw.
+    if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
+        this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
+                           data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
+                           paint);
+    }
+}
+
+void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) {
+    mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
+}
+
+void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) {
+    SkPath path;
+    path.addRRect(roundRect);
+    mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) {
+    mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+    mCanvas->clipRegion(&region, op);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
new file mode 100644
index 0000000..0de9650
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkiaCanvasProxy_DEFINED
+#define SkiaCanvasProxy_DEFINED
+
+#include <cutils/compiler.h>
+#include <SkCanvas.h>
+
+#include "Canvas.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * This class serves as a proxy between Skia's SkCanvas and Android Framework's
+ * Canvas.  The class does not maintain any draw-related state and will pass
+ * through most requests directly to the Canvas provided in the constructor.
+ *
+ * Upon construction it is expected that the provided Canvas has already been
+ * prepared for recording and will continue to be in the recording state while
+ * this proxy class is being used.
+ *
+ * If filterHwuiCalls is true, the proxy silently ignores away draw calls that
+ * aren't supported by HWUI.
+ */
+class ANDROID_API SkiaCanvasProxy : public SkCanvas {
+public:
+    SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls = false);
+    virtual ~SkiaCanvasProxy() {}
+
+protected:
+
+    virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
+
+    virtual void willSave() override;
+    virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
+    virtual void willRestore() override;
+
+    virtual void didConcat(const SkMatrix&) override;
+    virtual void didSetMatrix(const SkMatrix&) override;
+
+    virtual void onDrawPaint(const SkPaint& paint) override;
+    virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
+                              const SkPaint&) override;
+    virtual void onDrawOval(const SkRect&, const SkPaint&) override;
+    virtual void onDrawRect(const SkRect&, const SkPaint&) override;
+    virtual void onDrawRRect(const SkRRect&, const SkPaint&) override;
+    virtual void onDrawPath(const SkPath& path, const SkPaint&) override;
+    virtual void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
+                              const SkPaint*) override;
+    virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
+                                  const SkPaint* paint, DrawBitmapRectFlags flags) override;
+    virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+                                  const SkRect& dst, const SkPaint*) override;
+    virtual void onDrawSprite(const SkBitmap&, int left, int top,
+                              const SkPaint*) override;
+    virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
+                                const SkPoint texs[], const SkColor colors[], SkXfermode*,
+                                const uint16_t indices[], int indexCount,
+                                const SkPaint&) override;
+
+    virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+
+    virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+                            const SkPaint&) override;
+    virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+                               const SkPaint&) override;
+    virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+                                SkScalar constY, const SkPaint&) override;
+    virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+                                  const SkMatrix* matrix, const SkPaint&) override;
+    virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                                const SkPaint& paint) override;
+
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) override;
+
+    virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
+    virtual void onClipRegion(const SkRegion&, SkRegion::Op) override;
+
+private:
+    Canvas* mCanvas;
+    bool mFilterHwuiCalls;
+
+    typedef SkCanvas INHERITED;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c672bc4..2fcf7f3 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -16,16 +16,17 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
-#include <utils/Log.h>
-
-#include <SkMatrix.h>
+#include "SkiaShader.h"
 
 #include "Caches.h"
+#include "Extensions.h"
 #include "Layer.h"
 #include "Matrix.h"
-#include "SkiaShader.h"
 #include "Texture.h"
 
+#include <SkMatrix.h>
+#include <utils/Log.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -33,7 +34,7 @@
 // Support
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GLint gTileModes[] = {
+static const GLenum gTileModes[] = {
         GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
         GL_REPEAT,          // == SkShader::kRepeat_Mode
         GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
@@ -55,8 +56,12 @@
             a);
 }
 
+static inline void bindUniformColor(int slot, FloatColor color) {
+    glUniform4fv(slot, 1, reinterpret_cast<const float*>(&color));
+}
+
 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
-    caches->bindTexture(texture->id);
+    caches->textureState().bindTexture(texture->id);
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -86,7 +91,7 @@
 
 SkiaShaderType SkiaShader::getType(const SkShader& shader) {
     // First check for a gradient shader.
-    switch (shader.asAGradient(NULL)) {
+    switch (shader.asAGradient(nullptr)) {
         case SkShader::kNone_GradientType:
             // Not a gradient shader. Fall through to check for other types.
             break;
@@ -100,7 +105,7 @@
     }
 
     // The shader is not a gradient. Check for a bitmap shader.
-    if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+    if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
         return kBitmap_SkiaShaderType;
     }
 
@@ -118,7 +123,7 @@
         return kCompose_SkiaShaderType;
     }
 
-    if (shader.asACustomShader(NULL)) {
+    if (shader.asACustomShader(nullptr)) {
         return kLayer_SkiaShaderType;
     }
 
@@ -175,7 +180,7 @@
     }
 
     GLuint textureSlot = (*textureUnit)++;
-    caches->activeTexture(textureSlot);
+    caches->textureState().activateTexture(textureSlot);
 
     const float width = layer->getWidth();
     const float height = layer->getHeight();
@@ -190,11 +195,11 @@
     layer->setWrap(GL_CLAMP_TO_EDGE);
     layer->setFilter(GL_LINEAR);
 
-    Program* program = caches->currentProgram;
-    glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+    Program& program = caches->program();
+    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+    glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -254,29 +259,29 @@
         const Extensions& extensions, const SkShader& shader) {
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
-    if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
         LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
     }
-    bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy);
+    bitmapShaderHelper(caches, &description, nullptr, extensions, bitmap, xy);
 }
 
 void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
         GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
-    if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
         LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
     }
 
     GLuint textureSlot = (*textureUnit)++;
-    Caches::getInstance().activeTexture(textureSlot);
+    caches->textureState().activateTexture(textureSlot);
 
     BitmapShaderInfo shaderInfo;
-    if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) {
+    if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) {
         return;
     }
 
-    Program* program = caches->currentProgram;
+    Program& program = caches->program();
     Texture* texture = shaderInfo.texture;
 
     const AutoTexture autoCleanup(texture);
@@ -289,10 +294,10 @@
     bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
     texture->setFilter(GL_LINEAR);
 
-    glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
+    glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width,
             1.0f / shaderInfo.height);
 }
 
@@ -342,8 +347,8 @@
         const Extensions& extensions, const SkShader& shader) {
     SkShader::GradientInfo gradInfo;
     gradInfo.fColorCount = 0;
-    gradInfo.fColors = NULL;
-    gradInfo.fColorOffsets = NULL;
+    gradInfo.fColors = nullptr;
+    gradInfo.fColorOffsets = nullptr;
 
     switch (shader.asAGradient(&gradInfo)) {
         case SkShader::kLinear_GradientType:
@@ -380,7 +385,7 @@
 
     SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
 
-    Program* program = caches->currentProgram;
+    Program& program = caches->program();
     if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
         if (gradInfo.fColorCount > COLOR_COUNT) {
             // There was not enough room in our arrays for all the colors and offsets. Try again,
@@ -391,7 +396,7 @@
             shader.asAGradient(&gradInfo);
         }
         GLuint textureSlot = (*textureUnit)++;
-        caches->activeTexture(textureSlot);
+        caches->textureState().activateTexture(textureSlot);
 
 #ifndef SK_SCALAR_IS_FLOAT
     #error Need to convert gradInfo.fColorOffsets to float!
@@ -401,10 +406,10 @@
 
         // Uniforms
         bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
-        glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+        glUniform1i(program.getUniform("gradientSampler"), textureSlot);
     } else {
-        bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
-        bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
+        bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]);
+        bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]);
     }
 
     caches->dither.setupProgram(program, textureUnit);
@@ -427,7 +432,7 @@
 
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
-    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
+    glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -469,5 +474,290 @@
     SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// Store / apply
+///////////////////////////////////////////////////////////////////////////////
+
+bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 modelViewMatrix,
+        GLuint* textureUnit, ProgramDescription* description,
+        SkiaShaderData::GradientShaderData* outData) {
+    SkShader::GradientInfo gradInfo;
+    gradInfo.fColorCount = 0;
+    gradInfo.fColors = nullptr;
+    gradInfo.fColorOffsets = nullptr;
+
+    SkMatrix unitMatrix;
+    switch (shader.asAGradient(&gradInfo)) {
+        case SkShader::kLinear_GradientType:
+            description->gradientType = ProgramDescription::kGradientLinear;
+
+            toUnitMatrix(gradInfo.fPoint, &unitMatrix);
+            break;
+        case SkShader::kRadial_GradientType:
+            description->gradientType = ProgramDescription::kGradientCircular;
+
+            toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
+                    gradInfo.fRadius[0], &unitMatrix);
+            break;
+        case SkShader::kSweep_GradientType:
+            description->gradientType = ProgramDescription::kGradientSweep;
+
+            toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix);
+            break;
+        default:
+            // Do nothing. This shader is unsupported.
+            return false;
+    }
+    description->hasGradient = true;
+    description->isSimpleGradient = isSimpleGradient(gradInfo);
+
+    computeScreenSpaceMatrix(outData->screenSpace, unitMatrix,
+            shader.getLocalMatrix(), modelViewMatrix);
+
+    // re-query shader to get full color / offset data
+    std::unique_ptr<SkColor[]> colorStorage(new SkColor[gradInfo.fColorCount]);
+    std::unique_ptr<SkScalar[]> colorOffsets(new SkScalar[gradInfo.fColorCount]);
+    gradInfo.fColors = &colorStorage[0];
+    gradInfo.fColorOffsets = &colorOffsets[0];
+    shader.asAGradient(&gradInfo);
+
+    if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
+        outData->gradientSampler = (*textureUnit)++;
+
+#ifndef SK_SCALAR_IS_FLOAT
+    #error Need to convert gradInfo.fColorOffsets to float!
+#endif
+        outData->gradientTexture = caches.gradientCache.get(
+                gradInfo.fColors, gradInfo.fColorOffsets, gradInfo.fColorCount);
+        outData->wrapST = gTileModes[gradInfo.fTileMode];
+    } else {
+        outData->gradientSampler = 0;
+        outData->gradientTexture = nullptr;
+
+        outData->startColor.set(gradInfo.fColors[0]);
+        outData->endColor.set(gradInfo.fColors[1]);
+    }
+
+    outData->ditherSampler = (*textureUnit)++;
+    return true;
+}
+
+void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data) {
+    if (CC_UNLIKELY(data.gradientTexture)) {
+        caches.textureState().activateTexture(data.gradientSampler);
+        bindTexture(&caches, data.gradientTexture, data.wrapST, data.wrapST);
+        glUniform1i(caches.program().getUniform("gradientSampler"), data.gradientSampler);
+    } else {
+        bindUniformColor(caches.program().getUniform("startColor"), data.startColor);
+        bindUniformColor(caches.program().getUniform("endColor"), data.endColor);
+    }
+
+    // TODO: remove sampler slot incrementing from dither.setupProgram,
+    // since this assignment of slots is done at store, not apply time
+    GLuint ditherSampler = data.ditherSampler;
+    caches.dither.setupProgram(caches.program(), &ditherSampler);
+    glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1,
+            GL_FALSE, &data.screenSpace.data[0]);
+}
+
+bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
+        GLuint* textureUnit, ProgramDescription* description,
+        SkiaShaderData::BitmapShaderData* outData) {
+    SkBitmap bitmap;
+    SkShader::TileMode xy[2];
+    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
+        return false;
+    }
+
+    outData->bitmapTexture = caches.textureCache.get(&bitmap);
+    if (!outData->bitmapTexture) return false;
+
+    outData->bitmapSampler = (*textureUnit)++;
+
+    const float width = outData->bitmapTexture->width;
+    const float height = outData->bitmapTexture->height;
+
+    description->hasBitmap = true;
+    if (!caches.extensions().hasNPot()
+            && (!isPowerOfTwo(width) || !isPowerOfTwo(height))
+            && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode)) {
+        description->isBitmapNpot = true;
+        description->bitmapWrapS = gTileModes[xy[0]];
+        description->bitmapWrapT = gTileModes[xy[1]];
+
+        outData->wrapS = GL_CLAMP_TO_EDGE;
+        outData->wrapT = GL_CLAMP_TO_EDGE;
+    } else {
+        outData->wrapS = gTileModes[xy[0]];
+        outData->wrapT = gTileModes[xy[1]];
+    }
+
+    computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
+            modelViewMatrix);
+    outData->textureDimension[0] = 1.0f / width;
+    outData->textureDimension[1] = 1.0f / height;
+
+    return true;
+}
+
+void applyBitmap(Caches& caches, const SkiaShaderData::BitmapShaderData& data) {
+    caches.textureState().activateTexture(data.bitmapSampler);
+    bindTexture(&caches, data.bitmapTexture, data.wrapS, data.wrapT);
+    data.bitmapTexture->setFilter(GL_LINEAR);
+
+    glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler);
+    glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1, GL_FALSE,
+            &data.textureTransform.data[0]);
+    glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]);
+}
+
+SkiaShaderType getComposeSubType(const SkShader& shader) {
+    // First check for a gradient shader.
+    switch (shader.asAGradient(nullptr)) {
+        case SkShader::kNone_GradientType:
+            // Not a gradient shader. Fall through to check for other types.
+            break;
+        case SkShader::kLinear_GradientType:
+        case SkShader::kRadial_GradientType:
+        case SkShader::kSweep_GradientType:
+            return kGradient_SkiaShaderType;
+        default:
+            // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip.
+            return kNone_SkiaShaderType;
+    }
+
+    // The shader is not a gradient. Check for a bitmap shader.
+    if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
+        return kBitmap_SkiaShaderType;
+    }
+    return kNone_SkiaShaderType;
+}
+
+void storeCompose(Caches& caches, const SkShader& bitmapShader, const SkShader& gradientShader,
+        const Matrix4& modelViewMatrix, GLuint* textureUnit,
+        ProgramDescription* description, SkiaShaderData* outData) {
+    LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix,
+                textureUnit, description, &outData->bitmapData),
+            "failed storing bitmap shader data");
+    LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix,
+                textureUnit, description, &outData->gradientData),
+            "failing storing gradient shader data");
+}
+
+bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
+        GLuint* textureUnit, ProgramDescription* description,
+        SkiaShaderData* outData) {
+
+    SkShader::ComposeRec rec;
+    if (!shader.asACompose(&rec)) return false;
+
+    const SkiaShaderType shaderAType = getComposeSubType(*rec.fShaderA);
+    const SkiaShaderType shaderBType = getComposeSubType(*rec.fShaderB);
+
+    // check that type enum values are the 2 flags that compose the kCompose value
+    if ((shaderAType & shaderBType) != 0) return false;
+    if ((shaderAType | shaderBType) != kCompose_SkiaShaderType) return false;
+
+    mat4 transform;
+    computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), modelViewMatrix);
+    if (shaderAType == kBitmap_SkiaShaderType) {
+        description->isBitmapFirst = true;
+        storeCompose(caches, *rec.fShaderA, *rec.fShaderB,
+                transform, textureUnit, description, outData);
+    } else {
+        description->isBitmapFirst = false;
+        storeCompose(caches, *rec.fShaderB, *rec.fShaderA,
+                transform, textureUnit, description, outData);
+    }
+    if (!SkXfermode::AsMode(rec.fMode, &description->shadersMode)) {
+        // TODO: Support other modes.
+        description->shadersMode = SkXfermode::kSrcOver_Mode;
+    }
+    return true;
+}
+
+bool tryStoreLayer(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
+        GLuint* textureUnit, ProgramDescription* description,
+        SkiaShaderData::LayerShaderData* outData) {
+    Layer* layer;
+    if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
+        return false;
+    }
+
+    description->hasBitmap = true;
+    outData->layer = layer;
+    outData->bitmapSampler = (*textureUnit)++;
+
+    const float width = layer->getWidth();
+    const float height = layer->getHeight();
+
+    computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
+            modelViewMatrix);
+
+    outData->textureDimension[0] = 1.0f / width;
+    outData->textureDimension[1] = 1.0f / height;
+    return true;
+}
+
+void applyLayer(Caches& caches, const SkiaShaderData::LayerShaderData& data) {
+    caches.textureState().activateTexture(data.bitmapSampler);
+
+    data.layer->bindTexture();
+    data.layer->setWrap(GL_CLAMP_TO_EDGE);
+    data.layer->setFilter(GL_LINEAR);
+
+    glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler);
+    glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1,
+            GL_FALSE, &data.textureTransform.data[0]);
+    glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]);
+}
+
+void SkiaShader::store(Caches& caches, const SkShader* shader, const Matrix4& modelViewMatrix,
+        GLuint* textureUnit, ProgramDescription* description,
+        SkiaShaderData* outData) {
+    if (!shader) {
+        outData->skiaShaderType = kNone_SkiaShaderType;
+        return;
+    }
+
+    if (tryStoreGradient(caches, *shader, modelViewMatrix,
+            textureUnit, description, &outData->gradientData)) {
+        outData->skiaShaderType = kGradient_SkiaShaderType;
+        return;
+    }
+
+    if (tryStoreBitmap(caches, *shader, modelViewMatrix,
+            textureUnit, description, &outData->bitmapData)) {
+        outData->skiaShaderType = kBitmap_SkiaShaderType;
+        return;
+    }
+
+    if (tryStoreCompose(caches, *shader, modelViewMatrix,
+            textureUnit, description, outData)) {
+        outData->skiaShaderType = kCompose_SkiaShaderType;
+        return;
+    }
+
+    if (tryStoreLayer(caches, *shader, modelViewMatrix,
+            textureUnit, description, &outData->layerData)) {
+        outData->skiaShaderType = kLayer_SkiaShaderType;
+    }
+}
+
+void SkiaShader::apply(Caches& caches, const SkiaShaderData& data) {
+    if (!data.skiaShaderType) return;
+
+    if (data.skiaShaderType & kGradient_SkiaShaderType) {
+        applyGradient(caches, data.gradientData);
+    }
+    if (data.skiaShaderType & kBitmap_SkiaShaderType) {
+        applyBitmap(caches, data.bitmapData);
+    }
+
+    if (data.skiaShaderType == kLayer_SkiaShaderType) {
+        applyLayer(caches, data.layerData);
+    }
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 034c3f6..2962441c 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -17,33 +17,72 @@
 #ifndef ANDROID_HWUI_SKIA_SHADER_H
 #define ANDROID_HWUI_SKIA_SHADER_H
 
-#include <SkShader.h>
-#include <SkXfermode.h>
+#include "FloatColor.h"
+#include "Matrix.h"
 
 #include <GLES2/gl2.h>
-
+#include <SkShader.h>
+#include <SkXfermode.h>
 #include <cutils/compiler.h>
 
-#include "Extensions.h"
-#include "ProgramCache.h"
-#include "TextureCache.h"
-#include "GradientCache.h"
-
 namespace android {
 namespace uirenderer {
 
 class Caches;
+class Extensions;
 class Layer;
+class Texture;
+struct ProgramDescription;
 
 /**
  * Type of Skia shader in use.
+ *
+ * Note that kBitmap | kGradient = kCompose, since Compose implies
+ * both its component types are in use simultaneously. No other
+ * composition of multiple types is supported.
  */
 enum SkiaShaderType {
-    kNone_SkiaShaderType,
-    kBitmap_SkiaShaderType,
-    kGradient_SkiaShaderType,
-    kCompose_SkiaShaderType,
-    kLayer_SkiaShaderType
+    kNone_SkiaShaderType = 0,
+    kBitmap_SkiaShaderType = 1,
+    kGradient_SkiaShaderType = 2,
+    kCompose_SkiaShaderType = kBitmap_SkiaShaderType | kGradient_SkiaShaderType,
+    kLayer_SkiaShaderType = 4,
+};
+
+struct SkiaShaderData {
+    SkiaShaderType skiaShaderType;
+    struct BitmapShaderData {
+        Texture* bitmapTexture;
+        GLuint bitmapSampler;
+        GLenum wrapS;
+        GLenum wrapT;
+
+        Matrix4 textureTransform;
+        float textureDimension[2];
+    } bitmapData;
+    struct GradientShaderData {
+        Matrix4 screenSpace;
+        GLuint ditherSampler;
+
+        // simple gradient
+        FloatColor startColor;
+        FloatColor endColor;
+
+        // complex gradient
+        Texture* gradientTexture;
+        GLuint gradientSampler;
+        GLenum wrapST;
+
+    } gradientData;
+    struct LayerShaderData {
+        Layer* layer;
+        GLuint bitmapSampler;
+        GLenum wrapS;
+        GLenum wrapT;
+
+        Matrix4 textureTransform;
+        float textureDimension[2];
+    } layerData;
 };
 
 class SkiaShader {
@@ -53,6 +92,12 @@
             const Extensions& extensions, const SkShader& shader);
     static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
             GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+
+    // new SkiaShader interaction model - store into ShaderData, and apply to Caches/Program/GL
+    static void store(Caches& caches, const SkShader* shader, const Matrix4& modelViewMatrix,
+            GLuint* textureUnit, ProgramDescription* description,
+            SkiaShaderData* outData);
+    static void apply(Caches& caches, const SkiaShaderData& data);
 };
 
 class InvalidSkiaShader {
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index cf8229fd..597d95c 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -29,17 +29,16 @@
 
 Snapshot::Snapshot()
         : flags(0)
-        , previous(NULL)
-        , layer(NULL)
+        , previous(nullptr)
+        , layer(nullptr)
         , fbo(0)
         , invisible(false)
         , empty(false)
         , alpha(1.0f)
-        , roundRectClipState(NULL) {
+        , roundRectClipState(nullptr)
+        , mClipArea(&mClipAreaRoot) {
     transform = &mTransformRoot;
-    clipRect = &mClipRectRoot;
-    region = NULL;
-    clipRegion = &mClipRegionRoot;
+    region = nullptr;
 }
 
 /**
@@ -55,6 +54,7 @@
         , empty(false)
         , alpha(s->alpha)
         , roundRectClipState(s->roundRectClipState)
+        , mClipArea(nullptr)
         , mViewportData(s->mViewportData)
         , mRelativeLightCenter(s->mRelativeLightCenter) {
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
@@ -65,22 +65,17 @@
     }
 
     if (saveFlags & SkCanvas::kClip_SaveFlag) {
-        mClipRectRoot.set(*s->clipRect);
-        clipRect = &mClipRectRoot;
-        if (!s->clipRegion->isEmpty()) {
-            mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
-        }
-        clipRegion = &mClipRegionRoot;
+        mClipAreaRoot = s->getClipArea();
+        mClipArea = &mClipAreaRoot;
     } else {
-        clipRect = s->clipRect;
-        clipRegion = s->clipRegion;
+        mClipArea = s->mClipArea;
     }
 
     if (s->flags & Snapshot::kFlagFboTarget) {
         flags |= Snapshot::kFlagFboTarget;
         region = s->region;
     } else {
-        region = NULL;
+        region = nullptr;
     }
 }
 
@@ -88,88 +83,23 @@
 // Clipping
 ///////////////////////////////////////////////////////////////////////////////
 
-void Snapshot::ensureClipRegion() {
-    if (clipRegion->isEmpty()) {
-        clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
-    }
-}
-
-void Snapshot::copyClipRectFromRegion() {
-    if (!clipRegion->isEmpty()) {
-        const SkIRect& bounds = clipRegion->getBounds();
-        clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
-
-        if (clipRegion->isRect()) {
-            clipRegion->setEmpty();
-        }
-    } else {
-        clipRect->setEmpty();
-    }
-}
-
-bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
-    SkIRect tmp;
-    tmp.set(left, top, right, bottom);
-    clipRegion->op(tmp, op);
-    copyClipRectFromRegion();
-    return true;
-}
-
 bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
-    ensureClipRegion();
-    clipRegion->op(region, op);
-    copyClipRectFromRegion();
     flags |= Snapshot::kFlagClipSet;
-    return true;
+    return mClipArea->clipRegion(region, op);
 }
 
 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
-    Rect r(left, top, right, bottom);
-    transform->mapRect(r);
-    return clipTransformed(r, op);
+    flags |= Snapshot::kFlagClipSet;
+    return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
 }
 
-bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
-    bool clipped = false;
-
-    switch (op) {
-        case SkRegion::kIntersect_Op: {
-            if (CC_UNLIKELY(!clipRegion->isEmpty())) {
-                ensureClipRegion();
-                clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
-            } else {
-                clipped = clipRect->intersect(r);
-                if (!clipped) {
-                    clipRect->setEmpty();
-                    clipped = true;
-                }
-            }
-            break;
-        }
-        case SkRegion::kReplace_Op: {
-            setClip(r.left, r.top, r.right, r.bottom);
-            clipped = true;
-            break;
-        }
-        default: {
-            ensureClipRegion();
-            clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
-            break;
-        }
-    }
-
-    if (clipped) {
-        flags |= Snapshot::kFlagClipSet;
-    }
-
-    return clipped;
+bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+    flags |= Snapshot::kFlagClipSet;
+    return mClipArea->clipPathWithTransform(path, transform, op);
 }
 
 void Snapshot::setClip(float left, float top, float right, float bottom) {
-    clipRect->set(left, top, right, bottom);
-    if (!clipRegion->isEmpty()) {
-        clipRegion->setEmpty();
-    }
+    mClipArea->setClip(left, top, right, bottom);
     flags |= Snapshot::kFlagClipSet;
 }
 
@@ -181,7 +111,7 @@
     mat4 inverse;
     inverse.loadInverse(*transform);
 
-    mLocalClip.set(*clipRect);
+    mLocalClip.set(mClipArea->getClipRect());
     inverse.mapRect(mLocalClip);
 
     return mLocalClip;
@@ -191,8 +121,7 @@
     // TODO: This is incorrect, when we start rendering into a new layer,
     // we may have to modify the previous snapshot's clip rect and clip
     // region if the previous restore() call did not restore the clip
-    clipRect = &mClipRectRoot;
-    clipRegion = &mClipRegionRoot;
+    mClipArea = &mClipAreaRoot;
     setClip(left, top, right, bottom);
 }
 
@@ -219,7 +148,7 @@
 void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
         float radius, bool highPriority) {
     if (bounds.isEmpty()) {
-        clipRect->setEmpty();
+        mClipArea->setEmpty();
         return;
     }
 
@@ -272,9 +201,10 @@
 
 void Snapshot::dump() const {
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
-            this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
-    ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
-            clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+            this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
+    const Rect& clipRect(mClipArea->getClipRect());
+    ALOGD("  ClipRect %.1f %.1f %.1f %.1f",
+            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
     ALOGD("  Transform (at %p):", transform);
     transform->dump();
 }
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 549de9b..4d704ab 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -26,6 +26,7 @@
 
 #include <SkRegion.h>
 
+#include "ClipArea.h"
 #include "Layer.h"
 #include "Matrix.h"
 #include "Outline.h"
@@ -129,6 +130,11 @@
     bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
 
     /**
+     * Modifies the current clip with the specified path and operation.
+     */
+    bool clipPath(const SkPath& path, SkRegion::Op op);
+
+    /**
      * Sets the current clip.
      */
     void setClip(float left, float top, float right, float bottom);
@@ -142,7 +148,16 @@
     /**
      * Returns the current clip in render target coordinates.
      */
-    const Rect& getRenderTargetClip() { return *clipRect; }
+    const Rect& getRenderTargetClip() { return mClipArea->getClipRect(); }
+
+    /*
+     * Accessor functions so that the clip area can stay private
+     */
+    bool clipIsEmpty() const { return mClipArea->isEmpty(); }
+    const Rect& getClipRect() const { return mClipArea->getClipRect(); }
+    const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
+    bool clipIsSimple() const { return mClipArea->isSimple(); }
+    const ClipArea& getClipArea() const { return *mClipArea; }
 
     /**
      * Resets the clip to the specified rect.
@@ -156,6 +171,7 @@
 
     void initializeViewport(int width, int height) {
         mViewportData.initialize(width, height);
+        mClipAreaRoot.setViewportDimensions(width, height);
     }
 
     int getViewportWidth() const { return mViewportData.mWidth; }
@@ -175,7 +191,7 @@
 
     /**
      * Indicates whether this snapshot should be ignored. A snapshot
-     * is typicalled ignored if its layer is invisible or empty.
+     * is typically ignored if its layer is invisible or empty.
      */
     bool isIgnored() const;
 
@@ -230,24 +246,6 @@
     mat4* transform;
 
     /**
-     * Current clip rect. The clip is stored in canvas-space coordinates,
-     * (screen-space coordinates in the regular case.)
-     *
-     * This is a reference to a rect owned by this snapshot or another
-     * snapshot. This pointer must not be freed. See ::mClipRectRoot.
-     */
-    Rect* clipRect;
-
-    /**
-     * Current clip region. The clip is stored in canvas-space coordinates,
-     * (screen-space coordinates in the regular case.)
-     *
-     * This is a reference to a region owned by this snapshot or another
-     * snapshot. This pointer must not be freed. See ::mClipRegionRoot.
-     */
-    SkRegion* clipRegion;
-
-    /**
      * The ancestor layer's dirty region.
      *
      * This is a reference to a region owned by a layer. This pointer must
@@ -260,7 +258,7 @@
      * has translucent rendering in a non-overlapping View. This value will be used by
      * the renderer to set the alpha in the current color being used for ensuing drawing
      * operations. The value is inherited by child snapshots because the same value should
-     * be applied to descendents of the current DisplayList (for example, a TextView contains
+     * be applied to descendants of the current DisplayList (for example, a TextView contains
      * the base alpha value which should be applied to the child DisplayLists used for drawing
      * the actual text).
      */
@@ -298,16 +296,12 @@
         mat4 mOrthoMatrix;
     };
 
-    void ensureClipRegion();
-    void copyClipRectFromRegion();
-
-    bool clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op);
-
     mat4 mTransformRoot;
-    Rect mClipRectRoot;
-    Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
 
-    SkRegion mClipRegionRoot;
+    ClipArea mClipAreaRoot;
+    ClipArea* mClipArea;
+    Rect mLocalClip;
+
     ViewportData mViewportData;
     Vector3 mRelativeLightCenter;
 
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index b2dd899..b3b06d6 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -52,6 +52,7 @@
 #include "ShadowTessellator.h"
 #include "SpotShadow.h"
 #include "Vertex.h"
+#include "VertexBuffer.h"
 #include "utils/MathUtils.h"
 
 // TODO: After we settle down the new algorithm, we can remove the old one and
@@ -331,7 +332,7 @@
  * @param len the number of points of the polygon
  */
 void SpotShadow::makeClockwise(Vector2* polygon, int len) {
-    if (polygon == 0  || len == 0) {
+    if (polygon == nullptr  || len == 0) {
         return;
     }
     if (!ShadowTessellator::isClockwise(polygon, len)) {
@@ -797,11 +798,15 @@
                     previousPenumbra * weightForPreviousPenumbra;
 
                 int skippedUmbraIndex = (previousClosestUmbraIndex + k + 1) % umbraLength;
-                verticesPair[verticesPairIndex++] = {newPenumbraIndex, skippedUmbraIndex};
+                verticesPair[verticesPairIndex].outerIndex = newPenumbraIndex;
+                verticesPair[verticesPairIndex].innerIndex = skippedUmbraIndex;
+                verticesPairIndex++;
                 newPenumbra[newPenumbraIndex++] = interpolatedPenumbra;
             }
         }
-        verticesPair[verticesPairIndex++] = {newPenumbraIndex, currentClosestUmbraIndex};
+        verticesPair[verticesPairIndex].outerIndex = newPenumbraIndex;
+        verticesPair[verticesPairIndex].innerIndex = currentClosestUmbraIndex;
+        verticesPairIndex++;
         newPenumbra[newPenumbraIndex++] = currentPenumbraVertex;
 
         previousClosestUmbraIndex = currentClosestUmbraIndex;
@@ -1026,7 +1031,7 @@
     ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Spot Vertex Buffer");
     ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Spot Index Buffer");
 
-    shadowTriangleStrip.setMode(VertexBuffer::kIndices);
+    shadowTriangleStrip.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
     shadowTriangleStrip.computeBounds<AlphaVertex>();
 }
 
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index e2d94f7..62a7e5d 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -19,11 +19,12 @@
 
 #include "Debug.h"
 #include "Vector.h"
-#include "VertexBuffer.h"
 
 namespace android {
 namespace uirenderer {
 
+class VertexBuffer;
+
 class SpotShadow {
 public:
     static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
deleted file mode 100644
index 88d6f68..0000000
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ /dev/null
@@ -1,292 +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.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include <SkCanvas.h>
-
-#include "StatefulBaseRenderer.h"
-
-#include "utils/MathUtils.h"
-
-namespace android {
-namespace uirenderer {
-
-StatefulBaseRenderer::StatefulBaseRenderer()
-        : mDirtyClip(false)
-        , mWidth(-1)
-        , mHeight(-1)
-        , mSaveCount(1)
-        , mFirstSnapshot(new Snapshot)
-        , mSnapshot(mFirstSnapshot) {
-}
-
-void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
-        float clipRight, float clipBottom, const Vector3& lightCenter) {
-    mSnapshot = new Snapshot(mFirstSnapshot,
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
-    mSnapshot->fbo = getTargetFbo();
-    mSnapshot->setRelativeLightCenter(lightCenter);
-    mSaveCount = 1;
-}
-
-void StatefulBaseRenderer::setViewport(int width, int height) {
-    mWidth = width;
-    mHeight = height;
-    mFirstSnapshot->initializeViewport(width, height);
-    onViewportInitialized();
-
-    // create a temporary 1st snapshot, so old snapshots are released,
-    // and viewport can be queried safely.
-    // TODO: remove, combine viewport + save stack initialization
-    mSnapshot = new Snapshot(mFirstSnapshot,
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    mSaveCount = 1;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Save (layer)
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Non-virtual implementation of save, guaranteed to save without side-effects
- *
- * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
- * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
- */
-int StatefulBaseRenderer::saveSnapshot(int flags) {
-    mSnapshot = new Snapshot(mSnapshot, flags);
-    return mSaveCount++;
-}
-
-int StatefulBaseRenderer::save(int flags) {
-    return saveSnapshot(flags);
-}
-
-/**
- * Non-virtual implementation of restore, guaranteed to restore without side-effects.
- */
-void StatefulBaseRenderer::restoreSnapshot() {
-    sp<Snapshot> toRemove = mSnapshot;
-    sp<Snapshot> toRestore = mSnapshot->previous;
-
-    mSaveCount--;
-    mSnapshot = toRestore;
-
-    // subclass handles restore implementation
-    onSnapshotRestored(*toRemove, *toRestore);
-}
-
-void StatefulBaseRenderer::restore() {
-    if (mSaveCount > 1) {
-        restoreSnapshot();
-    }
-}
-
-void StatefulBaseRenderer::restoreToCount(int saveCount) {
-    if (saveCount < 1) saveCount = 1;
-
-    while (mSaveCount > saveCount) {
-        restoreSnapshot();
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Matrix
-///////////////////////////////////////////////////////////////////////////////
-
-void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
-    mSnapshot->transform->copyTo(*matrix);
-}
-
-void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
-    mSnapshot->transform->translate(dx, dy, dz);
-}
-
-void StatefulBaseRenderer::rotate(float degrees) {
-    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
-}
-
-void StatefulBaseRenderer::scale(float sx, float sy) {
-    mSnapshot->transform->scale(sx, sy, 1.0f);
-}
-
-void StatefulBaseRenderer::skew(float sx, float sy) {
-    mSnapshot->transform->skew(sx, sy);
-}
-
-void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
-    mSnapshot->transform->load(matrix);
-}
-
-void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
-    mSnapshot->transform->load(matrix);
-}
-
-void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
-    mat4 transform(matrix);
-    mSnapshot->transform->multiply(transform);
-}
-
-void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
-    mSnapshot->transform->multiply(matrix);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clip
-///////////////////////////////////////////////////////////////////////////////
-
-bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
-    if (CC_LIKELY(currentTransform()->rectToRect())) {
-        mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
-        return !mSnapshot->clipRect->isEmpty();
-    }
-
-    SkPath path;
-    path.addRect(left, top, right, bottom);
-
-    return StatefulBaseRenderer::clipPath(&path, op);
-}
-
-bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
-    SkMatrix transform;
-    currentTransform()->copyTo(transform);
-
-    SkPath transformed;
-    path->transform(transform, &transformed);
-
-    SkRegion clip;
-    if (!mSnapshot->previous->clipRegion->isEmpty()) {
-        clip.setRegion(*mSnapshot->previous->clipRegion);
-    } else {
-        if (mSnapshot->previous == firstSnapshot()) {
-            clip.setRect(0, 0, getWidth(), getHeight());
-        } else {
-            Rect* bounds = mSnapshot->previous->clipRect;
-            clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
-        }
-    }
-
-    SkRegion region;
-    region.setPath(transformed, clip);
-
-    // region is the transformed input path, masked by the previous clip
-    mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
-    return !mSnapshot->clipRect->isEmpty();
-}
-
-bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
-    mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
-    return !mSnapshot->clipRect->isEmpty();
-}
-
-void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
-    Rect bounds;
-    float radius;
-    if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
-
-    bool outlineIsRounded = MathUtils::isPositive(radius);
-    if (!outlineIsRounded || currentTransform()->isSimple()) {
-        // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
-        clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
-    }
-    if (outlineIsRounded) {
-        setClippingRoundRect(allocator, bounds, radius, false);
-    }
-}
-
-void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
-        const Rect& rect, float radius, bool highPriority) {
-    mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Quick Rejection
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
- * the clipRect. Does not modify the scissor.
- *
- * @param clipRequired if not null, will be set to true if element intersects clip
- *         (and wasn't rejected)
- *
- * @param snapOut if set, the geometry will be treated as having an AA ramp.
- *         See Rect::snapGeometryToPixelBoundaries()
- */
-bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
-        float right, float bottom,
-        bool* clipRequired, bool* roundRectClipRequired,
-        bool snapOut) const {
-    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
-        return true;
-    }
-
-    Rect r(left, top, right, bottom);
-    currentTransform()->mapRect(r);
-    r.snapGeometryToPixelBoundaries(snapOut);
-
-    Rect clipRect(*currentClipRect());
-    clipRect.snapToPixelBoundaries();
-
-    if (!clipRect.intersects(r)) return true;
-
-    // clip is required if geometry intersects clip rect
-    if (clipRequired) {
-        *clipRequired = !clipRect.contains(r);
-    }
-
-    // round rect clip is required if RR clip exists, and geometry intersects its corners
-    if (roundRectClipRequired) {
-        *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
-                && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
-    }
-    return false;
-}
-
-/**
- * Returns false if drawing won't be clipped out.
- *
- * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
- * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
- * rejection is still desired.
- *
- * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
- * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
- * rejection where precise rejection isn't important, or precise information isn't available.
- */
-bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
-        float right, float bottom) const {
-    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
-        return true;
-    }
-
-    Rect r(left, top, right, bottom);
-    currentTransform()->mapRect(r);
-    r.roundOut(); // rounded out to be conservative
-
-    Rect clipRect(*currentClipRect());
-    clipRect.snapToPixelBoundaries();
-
-    if (!clipRect.intersects(r)) return true;
-
-    return false;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
deleted file mode 100644
index 745e48a..0000000
--- a/libs/hwui/StatefulBaseRenderer.h
+++ /dev/null
@@ -1,170 +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.
- */
-
-#ifndef ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
-#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
-
-#include <utils/RefBase.h>
-
-#include "Renderer.h"
-#include "Snapshot.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Abstract Renderer subclass, which implements Canvas state methods.
- *
- * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
- * Renderer interface. Drawing and recording classes that extend StatefulBaseRenderer will have
- * different use cases:
- *
- * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
- * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
- *
- * Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
- * to StatefulBaseRenderer, so that not only will querying operations work (getClip/Matrix), but so
- * that quickRejection can also be used.
- */
-class StatefulBaseRenderer : public Renderer {
-public:
-    StatefulBaseRenderer();
-
-    virtual status_t prepare(bool opaque) {
-        return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
-    }
-
-    /**
-     * Initialize the first snapshot, computing the projection matrix, and stores the dimensions of
-     * the render target.
-     */
-    virtual void setViewport(int width, int height);
-    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
-            const Vector3& lightCenter);
-
-    // getters
-    bool hasRectToRectTransform() const {
-        return CC_LIKELY(currentTransform()->rectToRect());
-    }
-
-    // Save (layer)
-    virtual int getSaveCount() const { return mSaveCount; }
-    virtual int save(int flags);
-    virtual void restore();
-    virtual void restoreToCount(int saveCount);
-    //virtual int saveLayer(float left, float top, float right, float bottom,
-    //        int alpha, SkXfermode::Mode mode, int flags);
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const;
-    virtual void translate(float dx, float dy, float dz = 0.0f);
-    virtual void rotate(float degrees);
-    virtual void scale(float sx, float sy);
-    virtual void skew(float sx, float sy);
-
-    virtual void setMatrix(const SkMatrix& matrix);
-    void setMatrix(const Matrix4& matrix); // internal only convenience method
-    virtual void concatMatrix(const SkMatrix& matrix);
-    void concatMatrix(const Matrix4& matrix); // internal only convenience method
-
-    // Clip
-    virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
-
-    virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
-
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op);
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
-
-    /**
-     * Does not support different clipping Ops (that is, every call to setClippingOutline is
-     * effectively using SkRegion::kReplaceOp)
-     *
-     * The clipping outline is independent from the regular clip.
-     */
-    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
-    void setClippingRoundRect(LinearAllocator& allocator,
-            const Rect& rect, float radius, bool highPriority = true);
-
-    inline const mat4* currentTransform() const {
-        return mSnapshot->transform;
-    }
-
-protected:
-    const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
-
-    int getWidth() { return mWidth; }
-    int getHeight() { return mHeight; }
-
-    // Save
-    int saveSnapshot(int flags);
-    void restoreSnapshot();
-
-    // allows subclasses to control what value is stored in snapshot's fbo field in
-    // initializeSaveStack
-    virtual GLuint getTargetFbo() const {
-        return -1;
-    }
-
-    // Clip
-    bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
-            bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
-
-    /**
-     * Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
-     * 'restored' snapshot has become the top/current.
-     *
-     * Subclasses can override this method to handle layer restoration
-     */
-    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {};
-
-    virtual void onViewportInitialized() {};
-
-    inline const Rect* currentClipRect() const {
-        return mSnapshot->clipRect;
-    }
-
-    inline const Snapshot* currentSnapshot() const {
-        return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
-    }
-
-    inline const Snapshot* firstSnapshot() const {
-        return mFirstSnapshot.get();
-    }
-
-    // indicites that the clip has been changed since the last time it was consumed
-    bool mDirtyClip;
-
-private:
-    // Dimensions of the drawing surface
-    int mWidth, mHeight;
-
-    // Number of saved states
-    int mSaveCount;
-
-    // Base state
-    sp<Snapshot> mFirstSnapshot;
-
-protected:
-    // Current state
-    // TODO: should become private, once hooks needed by OpenGLRenderer are added
-    sp<Snapshot> mSnapshot;
-}; // class StatefulBaseRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp
deleted file mode 100644
index 8ce57db..0000000
--- a/libs/hwui/Stencil.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Debug.h"
-#include "Extensions.h"
-#include "Properties.h"
-#include "Stencil.h"
-
-#include <GLES2/gl2ext.h>
-
-namespace android {
-namespace uirenderer {
-
-#if DEBUG_STENCIL
-#define STENCIL_WRITE_VALUE 0xff
-#define STENCIL_MASK_VALUE 0xff
-#else
-#define STENCIL_WRITE_VALUE 0x1
-#define STENCIL_MASK_VALUE 0x1
-#endif
-
-Stencil::Stencil(): mState(kDisabled) {
-}
-
-uint8_t Stencil::getStencilSize() {
-    return STENCIL_BUFFER_SIZE;
-}
-
-GLenum Stencil::getSmallestStencilFormat() {
-#if !DEBUG_STENCIL
-    const Extensions& extensions = Extensions::getInstance();
-    if (extensions.has1BitStencil()) {
-        return GL_STENCIL_INDEX1_OES;
-    } else if (extensions.has4BitStencil()) {
-        return GL_STENCIL_INDEX4_OES;
-    }
-#endif
-    return GL_STENCIL_INDEX8;
-}
-
-void Stencil::clear() {
-    glClearStencil(0);
-    glClear(GL_STENCIL_BUFFER_BIT);
-}
-
-void Stencil::enableTest() {
-    if (mState != kTest) {
-        enable();
-        glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
-        // We only want to test, let's keep everything
-        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        mState = kTest;
-    }
-}
-
-void Stencil::enableWrite() {
-    if (mState != kWrite) {
-        enable();
-        glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
-        // The test always passes so the first two values are meaningless
-        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-        mState = kWrite;
-    }
-}
-
-void Stencil::enableDebugTest(GLint value, bool greater) {
-    enable();
-    glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
-    // We only want to test, let's keep everything
-    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-    mState = kTest;
-}
-
-void Stencil::enableDebugWrite() {
-    if (mState != kWrite) {
-        enable();
-        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
-        // The test always passes so the first two values are meaningless
-        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        mState = kWrite;
-    }
-}
-
-void Stencil::enable() {
-    if (mState == kDisabled) {
-        glEnable(GL_STENCIL_TEST);
-    }
-}
-
-void Stencil::disable() {
-    if (mState != kDisabled) {
-        glDisable(GL_STENCIL_TEST);
-        mState = kDisabled;
-    }
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h
deleted file mode 100644
index c5e5186..0000000
--- a/libs/hwui/Stencil.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_STENCIL_H
-#define ANDROID_HWUI_STENCIL_H
-
-#ifndef LOG_TAG
-    #define LOG_TAG "OpenGLRenderer"
-#endif
-
-#include <GLES2/gl2.h>
-
-#include <cutils/compiler.h>
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Stencil buffer management
-///////////////////////////////////////////////////////////////////////////////
-
-class ANDROID_API Stencil {
-public:
-    Stencil();
-
-    /**
-     * Returns the desired size for the stencil buffer. If the returned value
-     * is 0, then no stencil buffer is required.
-     */
-    ANDROID_API static uint8_t getStencilSize();
-
-    /**
-     * Returns the smallest stencil format accepted by render buffers.
-     */
-    static GLenum getSmallestStencilFormat();
-
-    /**
-     * Clears the stencil buffer.
-     */
-    void clear();
-
-    /**
-     * Enables stencil test. When the stencil test is enabled the stencil
-     * buffer is not written into.
-     */
-    void enableTest();
-
-    /**
-     * Enables stencil write. When stencil write is enabled, the stencil
-     * test always succeeds and the value 0x1 is written in the stencil
-     * buffer for each fragment.
-     */
-    void enableWrite();
-
-    /**
-     * The test passes only when equal to the specified value.
-     */
-    void enableDebugTest(GLint value, bool greater = false);
-
-    /**
-     * Used for debugging. The stencil test always passes and increments.
-     */
-    void enableDebugWrite();
-
-    /**
-     * Disables stencil test and write.
-     */
-    void disable();
-
-    /**
-     * Indicates whether either test or write is enabled.
-     */
-    bool isEnabled() {
-        return mState != kDisabled;
-    }
-
-    /**
-     * Indicates whether testing only is enabled.
-     */
-    bool isTestEnabled() {
-        return mState == kTest;
-    }
-
-private:
-    void enable();
-
-    enum StencilState {
-        kDisabled,
-        kTest,
-        kWrite
-    };
-
-    StencilState mState;
-
-}; // class Stencil
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_STENCIL_H
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 1e38f9e..66de333 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -76,7 +76,7 @@
 }
 
 TessellationCache::ShadowDescription::ShadowDescription()
-        : nodeKey(NULL) {
+        : nodeKey(nullptr) {
     memset(&matrixData, 0, 16 * sizeof(float));
 }
 
@@ -114,7 +114,7 @@
             : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
     ~TessellationProcessor() {}
 
-    virtual void onProcess(const sp<Task<VertexBuffer*> >& task) {
+    virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
         TessellationTask* t = static_cast<TessellationTask*>(task.get());
         ATRACE_NAME("shape tessellation");
         VertexBuffer* buffer = t->tessellator(t->description);
@@ -126,7 +126,7 @@
 public:
     Buffer(const sp<Task<VertexBuffer*> >& task)
             : mTask(task)
-            , mBuffer(NULL) {
+            , mBuffer(nullptr) {
     }
 
     ~Buffer() {
@@ -146,9 +146,9 @@
 
 private:
     void blockOnPrecache() {
-        if (mTask != NULL) {
+        if (mTask != nullptr) {
             mBuffer = mTask->getResult();
-            LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache");
+            LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "Failed to precache");
             mTask.clear();
         }
     }
@@ -278,7 +278,7 @@
             : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
     ~ShadowProcessor() {}
 
-    virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) {
+    virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override {
         ShadowTask* t = static_cast<ShadowTask*>(task.get());
         ATRACE_NAME("shadow tessellation");
 
@@ -302,7 +302,7 @@
         , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
         , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting %s cache size to %sMB", name, property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -382,12 +382,14 @@
 
     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
-    if (mShadowProcessor == NULL) {
+    if (mShadowProcessor == nullptr) {
         mShadowProcessor = new ShadowProcessor(Caches::getInstance());
     }
-    mShadowProcessor->add(task);
+    if (!mShadowProcessor->add(task)) {
+        mShadowProcessor->process(task);
+    }
 
-    task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
+    task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
     mShadowCache.put(key, task.get());
 }
 
@@ -402,7 +404,7 @@
                 transformXY, transformZ, lightCenter, lightRadius);
         task = static_cast<ShadowTask*>(mShadowCache.get(key));
     }
-    LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
+    LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
     outBuffers = *(task->getResult());
 }
 
@@ -418,10 +420,12 @@
         sp<TessellationTask> task = new TessellationTask(tessellator, entry);
         buffer = new Buffer(task);
 
-        if (mProcessor == NULL) {
+        if (mProcessor == nullptr) {
             mProcessor = new TessellationProcessor(Caches::getInstance());
         }
-        mProcessor->add(task);
+        if (!mProcessor->add(task)) {
+            mProcessor->process(task);
+        }
         mCache.put(entry, buffer);
     }
     return buffer;
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index 688a699..3efeaf6 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -24,7 +24,6 @@
 #include "Debug.h"
 #include "utils/Macros.h"
 #include "utils/Pair.h"
-#include "VertexBuffer.h"
 
 class SkBitmap;
 class SkCanvas;
@@ -36,6 +35,7 @@
 namespace uirenderer {
 
 class Caches;
+class VertexBuffer;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Classes
@@ -166,7 +166,7 @@
     sp<TaskProcessor<VertexBuffer*> > mProcessor;
     LruCache<Description, Buffer*> mCache;
     class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> {
-        void operator()(Description& description, Buffer*& buffer);
+        void operator()(Description& description, Buffer*& buffer) override;
     };
     BufferRemovedListener mBufferRemovedListener;
 
@@ -178,8 +178,8 @@
     // holds a pointer, and implicit strong ref to each shadow task of the frame
     LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*> mShadowCache;
     class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t*>*> {
-        void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t*>*& bufferPairTask) {
-            bufferPairTask->decStrong(NULL);
+        void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t*>*& bufferPairTask) override {
+            bufferPairTask->decStrong(nullptr);
         }
     };
     BufferPairRemovedListener mBufferPairRemovedListener;
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 4eec462..c2e88f3 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -20,6 +20,7 @@
 
 #include "Caches.h"
 #include "Debug.h"
+#include "FontRenderer.h"
 #include "TextDropShadowCache.h"
 #include "Properties.h"
 
@@ -40,7 +41,8 @@
     hash = JenkinsHashMix(hash, android::hash_type(italicStyle));
     hash = JenkinsHashMix(hash, android::hash_type(scaleX));
     if (text) {
-        hash = JenkinsHashMixShorts(hash, text, charCount);
+        hash = JenkinsHashMixShorts(
+            hash, reinterpret_cast<const uint16_t*>(text), charCount);
     }
     if (positions) {
         for (uint32_t i = 0; i < charCount * 2; i++) {
@@ -98,7 +100,7 @@
         mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
         mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting drop shadow cache size to %sMB", property);
         setMaxSize(MB(atof(property)));
     } else {
@@ -180,7 +182,7 @@
                 len, numGlyphs, radius, positions);
 
         if (!shadow.image) {
-            return NULL;
+            return nullptr;
         }
 
         Caches& caches = Caches::getInstance();
@@ -205,7 +207,7 @@
 
         glGenTextures(1, &texture->id);
 
-        caches.bindTexture(texture->id);
+        caches.textureState().bindTexture(texture->id);
         // Textures are Alpha8
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 54b930b..caf089f 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -24,17 +24,18 @@
 #include <utils/LruCache.h>
 #include <utils/String16.h>
 
-#include "FontRenderer.h"
+#include "font/Font.h"
 #include "Texture.h"
 
 namespace android {
 namespace uirenderer {
 
 class Caches;
+class FontRenderer;
 
 struct ShadowText {
-    ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(NULL),
-            flags(0), italicStyle(0.0f), scaleX(0), text(NULL), positions(NULL) {
+    ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(nullptr),
+            flags(0), italicStyle(0.0f), scaleX(0), text(nullptr), positions(nullptr) {
     }
 
     // len is the number of bytes in text
@@ -75,7 +76,7 @@
         uint32_t charCount = len / sizeof(char16_t);
         str.setTo((const char16_t*) text, charCount);
         text = str.string();
-        if (positions != NULL) {
+        if (positions != nullptr) {
             positionsCopy.clear();
             positionsCopy.appendArray(positions, charCount * 2);
             positions = positionsCopy.array();
@@ -133,7 +134,7 @@
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(ShadowText& text, ShadowTexture*& texture);
+    void operator()(ShadowText& text, ShadowTexture*& texture) override;
 
     ShadowTexture* get(const SkPaint* paint, const char* text, uint32_t len,
             int numGlyphs, float radius, const float* positions);
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index e783905..593e918 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -24,20 +24,6 @@
 namespace android {
 namespace uirenderer {
 
-Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
-        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
-        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
-        mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
-}
-
-Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
-        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
-        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
-        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
-        mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
-}
-
 void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
         GLenum renderTarget) {
 
@@ -48,7 +34,7 @@
         mWrapT = wrapT;
 
         if (bindTexture) {
-            mCaches.bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, id);
         }
 
         glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
@@ -66,7 +52,7 @@
         mMagFilter = mag;
 
         if (bindTexture) {
-            mCaches.bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, id);
         }
 
         if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
@@ -77,7 +63,7 @@
 }
 
 void Texture::deleteTexture() const {
-    mCaches.deleteTexture(id);
+    mCaches.textureState().deleteTexture(id);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index d5601f8..dfec462 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -30,8 +30,7 @@
  */
 class Texture {
 public:
-    Texture();
-    Texture(Caches& caches);
+    Texture(Caches& caches) : mCaches(caches) { }
 
     virtual ~Texture() { }
 
@@ -59,62 +58,62 @@
     /**
      * Name of the texture.
      */
-    GLuint id;
+    GLuint id = 0;
     /**
      * Generation of the backing bitmap,
      */
-    uint32_t generation;
+    uint32_t generation = 0;
     /**
      * Indicates whether the texture requires blending.
      */
-    bool blend;
+    bool blend = false;
     /**
      * Width of the backing bitmap.
      */
-    uint32_t width;
+    uint32_t width = 0;
     /**
      * Height of the backing bitmap.
      */
-    uint32_t height;
+    uint32_t height = 0;
     /**
      * Indicates whether this texture should be cleaned up after use.
      */
-    bool cleanup;
+    bool cleanup= false;
     /**
      * Optional, size of the original bitmap.
      */
-    uint32_t bitmapSize;
+    uint32_t bitmapSize = 0;
     /**
      * Indicates whether this texture will use trilinear filtering.
      */
-    bool mipMap;
+    bool mipMap = false;
 
     /**
      * Optional, pointer to a texture coordinates mapper.
      */
-    const UvMapper* uvMapper;
+    const UvMapper* uvMapper = nullptr;
 
     /**
      * Whether or not the Texture is marked in use and thus not evictable for
      * the current frame. This is reset at the start of a new frame.
      */
-    bool isInUse;
+    bool isInUse = false;
 
 private:
     /**
-     * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
+     * Last wrap modes set on this texture.
      */
-    GLenum mWrapS;
-    GLenum mWrapT;
+    GLenum mWrapS = GL_CLAMP_TO_EDGE;
+    GLenum mWrapT = GL_CLAMP_TO_EDGE;
 
     /**
-     * Last filters set on this texture. Defaults to GL_NEAREST.
+     * Last filters set on this texture.
      */
-    GLenum mMinFilter;
-    GLenum mMagFilter;
+    GLenum mMinFilter = GL_NEAREST;
+    GLenum mMagFilter = GL_NEAREST;
 
-    bool mFirstFilter;
-    bool mFirstWrap;
+    bool mFirstFilter = true;
+    bool mFirstWrap = true;
 
     Caches& mCaches;
 }; // struct Texture
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 63454d8..b911a0f 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -26,6 +26,7 @@
 
 #include "AssetAtlas.h"
 #include "Caches.h"
+#include "Texture.h"
 #include "TextureCache.h"
 #include "Properties.h"
 #include "utils/TraceUtils.h"
@@ -37,19 +38,21 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-TextureCache::TextureCache():
-        mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
-        mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE), mAssetAtlas(0) {
+TextureCache::TextureCache()
+        : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
+        , mSize(0)
+        , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE))
+        , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE)
+        , mAssetAtlas(nullptr) {
     char property[PROPERTY_VALUE_MAX];
-    if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) {
         INIT_LOGD("  Setting texture cache size to %sMB", property);
         setMaxSize(MB(atof(property)));
     } else {
         INIT_LOGD("  Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
     }
 
-    if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, NULL) > 0) {
+    if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, nullptr) > 0) {
         float flushRate = atof(property);
         INIT_LOGD("  Setting texture cache flush rate to %.2f%%", flushRate * 100.0f);
         setFlushRate(flushRate);
@@ -58,20 +61,6 @@
                 DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
     }
 
-    init();
-}
-
-TextureCache::TextureCache(uint32_t maxByteSize):
-        mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(maxByteSize), mAssetAtlas(0) {
-    init();
-}
-
-TextureCache::~TextureCache() {
-    mCache.clear();
-}
-
-void TextureCache::init() {
     mCache.setOnEntryRemovedListener(this);
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -80,6 +69,10 @@
     mDebugEnabled = readDebugLevel() & kDebugCaches;
 }
 
+TextureCache::~TextureCache() {
+    mCache.clear();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Size management
 ///////////////////////////////////////////////////////////////////////////////
@@ -159,7 +152,7 @@
 
     if (!texture) {
         if (!canMakeTextureFromBitmap(bitmap)) {
-            return NULL;
+            return nullptr;
         }
 
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
@@ -175,7 +168,7 @@
         }
 
         if (canCache) {
-            texture = new Texture();
+            texture = new Texture(Caches::getInstance());
             texture->bitmapSize = size;
             generateTexture(bitmap, texture, false);
 
@@ -209,11 +202,11 @@
 
     if (!texture) {
         if (!canMakeTextureFromBitmap(bitmap)) {
-            return NULL;
+            return nullptr;
         }
 
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
-        texture = new Texture();
+        texture = new Texture(Caches::getInstance());
         texture->bitmapSize = size;
         generateTexture(bitmap, texture, false);
         texture->cleanup = true;
@@ -223,7 +216,7 @@
 }
 
 Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
-    Texture* texture = new Texture();
+    Texture* texture = new Texture(Caches::getInstance());
     texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
     texture->cleanup = true;
 
@@ -232,11 +225,9 @@
     return texture;
 }
 
-void TextureCache::releaseTexture(const SkBitmap* bitmap) {
-    if (!bitmap || !bitmap->pixelRef()) return;
-
+void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
     Mutex::Autolock _l(mLock);
-    mGarbage.push(bitmap->pixelRef()->getStableID());
+    mGarbage.push(pixelRefStableID);
 }
 
 void TextureCache::clearGarbage() {
@@ -281,7 +272,7 @@
 
     // We could also enable mipmapping if both bitmap dimensions are powers
     // of 2 but we'd have to deal with size changes. Let's keep this simple
-    const bool canMipMap = Extensions::getInstance().hasNPot();
+    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
 
     // If the texture had mipmap enabled but not anymore,
     // force a glTexImage2D to discard the mipmap levels
@@ -297,23 +288,20 @@
     texture->width = bitmap->width();
     texture->height = bitmap->height();
 
-    Caches::getInstance().bindTexture(texture->id);
+    Caches::getInstance().textureState().bindTexture(texture->id);
 
     switch (bitmap->colorType()) {
     case kAlpha_8_SkColorType:
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
                 texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
         break;
     case kRGB_565_SkColorType:
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         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 kN32_SkColorType:
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         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
@@ -322,7 +310,6 @@
         break;
     case kARGB_4444_SkColorType:
     case kIndex_8_SkColorType:
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
         texture->blend = !bitmap->isOpaque();
         break;
@@ -351,7 +338,7 @@
     rgbaBitmap.eraseColor(0);
 
     SkCanvas canvas(rgbaBitmap);
-    canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
+    canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
 
     uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
             width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
@@ -359,7 +346,9 @@
 
 void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
         GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
-    const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
+    glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
+    const bool useStride = stride != width
+            && Caches::getInstance().extensions().hasUnpackRowLength();
     if ((stride == width) || useStride) {
         if (useStride) {
             glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index cf8d134..a2c6380 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -24,11 +24,12 @@
 #include <utils/Vector.h>
 
 #include "Debug.h"
-#include "Texture.h"
 
 namespace android {
 namespace uirenderer {
 
+class Texture;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
@@ -51,17 +52,16 @@
  * Any texture added to the cache causing the cache to grow beyond the maximum
  * allowed size will also cause the oldest texture to be kicked out.
  */
-class TextureCache: public OnEntryRemoved<uint32_t, Texture*> {
+class TextureCache : public OnEntryRemoved<uint32_t, Texture*> {
 public:
     TextureCache();
-    TextureCache(uint32_t maxByteSize);
     ~TextureCache();
 
     /**
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(uint32_t&, Texture*& texture);
+    void operator()(uint32_t&, Texture*& texture) override;
 
     /**
      * Resets all Textures to not be marked as in use
@@ -87,10 +87,10 @@
     Texture* getTransient(const SkBitmap* bitmap);
 
     /**
-     * Removes the texture associated with the specified bitmap. This is meant
+     * Removes the texture associated with the specified pixelRef. This is meant
      * to be called from threads that are not the EGL context thread.
      */
-    void releaseTexture(const SkBitmap* bitmap);
+    ANDROID_API void releaseTexture(uint32_t pixelRefStableID);
     /**
      * Process deferred removals.
      */
@@ -145,8 +145,6 @@
     void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
             GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
 
-    void init();
-
     LruCache<uint32_t, Texture*> mCache;
 
     uint32_t mSize;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index ae6ea94..0799c6c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -20,7 +20,6 @@
 
 #include <utils/Timers.h>
 
-#include "DamageAccumulator.h"
 #include "utils/Macros.h"
 
 namespace android {
@@ -30,6 +29,7 @@
 class CanvasContext;
 }
 
+class DamageAccumulator;
 class OpenGLRenderer;
 class RenderState;
 
@@ -59,11 +59,11 @@
         : mode(mode)
         , prepareTextures(mode == MODE_FULL)
         , runAnimations(true)
-        , damageAccumulator(NULL)
+        , damageAccumulator(nullptr)
         , renderState(renderState)
-        , renderer(NULL)
-        , errorHandler(NULL)
-        , canvasContext(NULL)
+        , renderer(nullptr)
+        , errorHandler(nullptr)
+        , canvasContext(nullptr)
     {}
 
     explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index aa6acc9..7c3f2fd 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_HWUI_VECTOR_H
 #define ANDROID_HWUI_VECTOR_H
 
+#include <math.h>
+#include <utils/Log.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 4ff0b18..11d0c4b 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,6 +19,8 @@
 
 #include "Vector.h"
 
+#include "utils/Macros.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -39,8 +41,8 @@
     float x, y;
 
     static inline void set(Vertex* vertex, float x, float y) {
-        vertex[0].x = x;
-        vertex[0].y = y;
+        vertex->x = x;
+        vertex->y = y;
     }
 
     static inline void set(Vertex* vertex, Vector2 val) {
@@ -53,6 +55,8 @@
 
 }; // struct Vertex
 
+REQUIRE_COMPATIBLE_LAYOUT(Vertex);
+
 /**
  * Simple structure to describe a vertex with a position and texture UV.
  */
@@ -61,10 +65,7 @@
     float u, v;
 
     static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
-        vertex[0].x = x;
-        vertex[0].y = y;
-        vertex[0].u = u;
-        vertex[0].v = v;
+        *vertex = { x, y, u, v };
     }
 
     static inline void setUV(TextureVertex* vertex, float u, float v) {
@@ -73,39 +74,43 @@
     }
 }; // struct TextureVertex
 
+REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
+
 /**
  * Simple structure to describe a vertex with a position, texture UV and ARGB color.
  */
-struct ColorTextureVertex : TextureVertex {
+struct ColorTextureVertex {
+    float x, y;
+    float u, v;
     float r, g, b, a;
 
     static inline void set(ColorTextureVertex* vertex, float x, float y,
             float u, float v, int color) {
-        TextureVertex::set(vertex, x, y, u, v);
 
-        const float a = ((color >> 24) & 0xff) / 255.0f;
-        vertex[0].r = a * ((color >> 16) & 0xff) / 255.0f;
-        vertex[0].g = a * ((color >>  8) & 0xff) / 255.0f;
-        vertex[0].b = a * ((color      ) & 0xff) / 255.0f;
-        vertex[0].a = a;
+        float a =     ((color >> 24) & 0xff) / 255.0f;
+        float r = a * ((color >> 16) & 0xff) / 255.0f;
+        float g = a * ((color >>  8) & 0xff) / 255.0f;
+        float b = a * ((color) & 0xff) / 255.0f;
+        *vertex = { x, y, u, v, r, g, b, a };
     }
 }; // struct ColorTextureVertex
 
+REQUIRE_COMPATIBLE_LAYOUT(ColorTextureVertex);
+
 /**
  * Simple structure to describe a vertex with a position and an alpha value.
  */
-struct AlphaVertex : Vertex {
+struct AlphaVertex {
+    float x, y;
     float alpha;
 
     static inline void set(AlphaVertex* vertex, float x, float y, float alpha) {
-        Vertex::set(vertex, x, y);
-        vertex[0].alpha = alpha;
+        *vertex = { x, y, alpha };
     }
 
     static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src,
             float x, float y) {
-        Vertex::set(vertex, src.x + x, src.y + y);
-        vertex[0].alpha = src.alpha;
+        AlphaVertex::set(vertex, src.x + x, src.y + y, src.alpha);
     }
 
     static inline void setColor(AlphaVertex* vertex, float alpha) {
@@ -113,6 +118,8 @@
     }
 }; // struct AlphaVertex
 
+REQUIRE_COMPATIBLE_LAYOUT(AlphaVertex);
+
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 8c3a272..9be4d84 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -24,25 +24,24 @@
 
 class VertexBuffer {
 public:
-    enum Mode {
-        kStandard = 0,
-        kOnePolyRingShadow = 1,
-        kTwoPolyRingShadow = 2,
-        kIndices = 3
+    enum MeshFeatureFlags {
+        kNone = 0,
+        kAlpha = 1 << 0,
+        kIndices = 1 << 1,
     };
 
     VertexBuffer()
-            : mBuffer(0)
-            , mIndices(0)
+            : mBuffer(nullptr)
+            , mIndices(nullptr)
             , mVertexCount(0)
             , mIndexCount(0)
             , mAllocatedVertexCount(0)
             , mAllocatedIndexCount(0)
             , mByteCount(0)
-            , mMode(kStandard)
-            , mReallocBuffer(0)
-            , mCleanupMethod(NULL)
-            , mCleanupIndexMethod(NULL)
+            , mMeshFeatureFlags(kNone)
+            , mReallocBuffer(nullptr)
+            , mCleanupMethod(nullptr)
+            , mCleanupIndexMethod(nullptr)
     {}
 
     ~VertexBuffer() {
@@ -135,10 +134,12 @@
     void updateVertexCount(unsigned int newCount)  {
         mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
     }
-    Mode getMode() const { return mMode; }
+    MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
+    void setMeshFeatureFlags(int flags) {
+        mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
+    }
 
     void setBounds(Rect bounds) { mBounds = bounds; }
-    void setMode(Mode mode) { mMode = mode; }
 
     template <class TYPE>
     void createDegenerateSeparators(int allocSize) {
@@ -166,7 +167,7 @@
     unsigned int mAllocatedIndexCount;
     unsigned int mByteCount;
 
-    Mode mMode;
+    MeshFeatureFlags mMeshFeatureFlags;
 
     void* mReallocBuffer; // used for multi-allocation
 
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 24ffb80..9314126 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -17,6 +17,7 @@
 #include <SkGlyph.h>
 
 #include "CacheTexture.h"
+#include "FontUtil.h"
 #include "../Caches.h"
 #include "../Debug.h"
 #include "../Extensions.h"
@@ -42,7 +43,7 @@
 #endif
 
     CacheBlock* currBlock = head;
-    CacheBlock* prevBlock = NULL;
+    CacheBlock* prevBlock = nullptr;
 
     while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
         if (newBlock->mWidth < currBlock->mWidth) {
@@ -109,9 +110,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
-            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
+            mTexture(nullptr), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
             mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
-            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
+            mMesh(nullptr), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
             mCaches(Caches::getInstance()) {
     mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
             mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
@@ -119,7 +120,7 @@
     // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
     // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
     // With OpenGL ES 2.0 we have to upload entire stripes instead.
-    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
+    mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength();
 }
 
 CacheTexture::~CacheTexture() {
@@ -130,7 +131,7 @@
 
 void CacheTexture::reset() {
     // Delete existing cache blocks
-    while (mCacheBlocks != NULL) {
+    while (mCacheBlocks != nullptr) {
         CacheBlock* tmpBlock = mCacheBlocks;
         mCacheBlocks = mCacheBlocks->mNext;
         delete tmpBlock;
@@ -153,10 +154,10 @@
 void CacheTexture::releaseTexture() {
     if (mTexture) {
         delete mTexture;
-        mTexture = NULL;
+        mTexture = nullptr;
     }
     if (mTextureId) {
-        mCaches.deleteTexture(mTextureId);
+        mCaches.textureState().deleteTexture(mTextureId);
         mTextureId = 0;
     }
     mDirty = false;
@@ -168,7 +169,7 @@
        mLinearFiltering = linearFiltering;
 
        const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
-       if (bind) mCaches.bindTexture(getTextureId());
+       if (bind) mCaches.textureState().bindTexture(getTextureId());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    }
@@ -188,11 +189,11 @@
     if (!mTextureId) {
         glGenTextures(1, &mTextureId);
 
-        mCaches.bindTexture(mTextureId);
+        mCaches.textureState().bindTexture(mTextureId);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         // Initialize texture dimensions
         glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
-                mFormat, GL_UNSIGNED_BYTE, 0);
+                mFormat, GL_UNSIGNED_BYTE, nullptr);
 
         const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 4cc4f22..5d3f959 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -23,7 +23,6 @@
 
 #include <utils/Log.h>
 
-#include "FontUtil.h"
 #include "../PixelBuffer.h"
 #include "../Rect.h"
 #include "../Vertex.h"
@@ -55,7 +54,7 @@
     CacheBlock* mPrev;
 
     CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height):
-            mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
+            mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {
     }
 
     static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
@@ -147,7 +146,7 @@
     }
 
     uint16_t* indices() const {
-        return (uint16_t*) 0;
+        return (uint16_t*) nullptr;
     }
 
     void resetMesh() {
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
index 6680a00..0642d59 100644
--- a/libs/hwui/font/CachedGlyphInfo.h
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -19,11 +19,11 @@
 
 #include <SkFixed.h>
 
-#include "CacheTexture.h"
-
 namespace android {
 namespace uirenderer {
 
+class CacheTexture;
+
 struct CachedGlyphInfo {
     // Has the cache been invalidated?
     bool mIsValid;
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index af39f16..b07a3c8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -22,6 +22,7 @@
 #include <utils/JenkinsHash.h>
 #include <utils/Trace.h>
 
+#include <SkDeviceProperties.h>
 #include <SkGlyph.h>
 #include <SkGlyphCache.h>
 #include <SkUtils.h>
@@ -41,9 +42,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
-        mState(state), mDescription(desc) {
-    mDeviceProperties = SkDeviceProperties::Make(SkDeviceProperties::Geometry::MakeDefault(), 1.0f);
-}
+        mState(state), mDescription(desc) { }
 
 Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& rasterMatrix)
         : mLookupTransform(rasterMatrix) {
@@ -285,7 +284,8 @@
     if (cachedGlyph) {
         // Is the glyph still in texture cache?
         if (!cachedGlyph->mIsValid) {
-            SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
+            SkDeviceProperties deviceProperties(kUnknown_SkPixelGeometry, 1.0f);
+            SkAutoGlyphCache autoCache(*paint, &deviceProperties, &mDescription.mLookupTransform);
             const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
             updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
         }
@@ -298,13 +298,13 @@
 
 void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
             int numGlyphs, int x, int y, const float* positions) {
-    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
-            0, 0, NULL, positions);
+    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, nullptr,
+            0, 0, nullptr, positions);
 }
 
 void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
         int numGlyphs, const SkPath* path, float hOffset, float vOffset) {
-    if (numGlyphs == 0 || text == NULL || len == 0) {
+    if (numGlyphs == 0 || text == nullptr || len == 0) {
         return;
     }
 
@@ -354,18 +354,18 @@
 
 void Font::measure(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
         int numGlyphs, Rect *bounds, const float* positions) {
-    if (bounds == NULL) {
+    if (bounds == nullptr) {
         ALOGE("No return rectangle provided to measure text");
         return;
     }
     bounds->set(1e6, -1e6, -1e6, 1e6);
-    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
+    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, nullptr, 0, 0, bounds, positions);
 }
 
 void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
     ATRACE_NAME("Precache Glyphs");
 
-    if (numGlyphs == 0 || text == NULL) {
+    if (numGlyphs == 0 || text == nullptr) {
         return;
     }
 
@@ -378,7 +378,7 @@
             break;
         }
 
-        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
+        getCachedGlyph(paint, glyph, true);
         glyphsCount++;
     }
 }
@@ -386,7 +386,7 @@
 void Font::render(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
         uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
-    if (numGlyphs == 0 || text == NULL || len == 0) {
+    if (numGlyphs == 0 || text == nullptr || len == 0) {
         return;
     }
 
@@ -403,8 +403,6 @@
     text += start;
     int glyphsCount = 0;
 
-    const SkPaint::Align align = paint->getTextAlign();
-
     while (glyphsCount < numGlyphs) {
         glyph_t glyph = GET_GLYPH(text);
 
@@ -477,7 +475,8 @@
     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
     mCachedGlyphs.add(glyph, newGlyph);
 
-    SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
+    SkDeviceProperties deviceProperties(kUnknown_SkPixelGeometry, 1.0f);
+    SkAutoGlyphCache autoCache(*paint, &deviceProperties, &mDescription.mLookupTransform);
     const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph);
     newGlyph->mIsValid = false;
     newGlyph->mGlyphIndex = skiaGlyph.fID;
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 0f10464..3119d73 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -22,13 +22,12 @@
 #include <utils/KeyedVector.h>
 
 #include <SkScalar.h>
-#include <SkDeviceProperties.h>
 #include <SkGlyphCache.h>
 #include <SkScalerContext.h>
 #include <SkPaint.h>
 #include <SkPathMeasure.h>
 
-#include "CachedGlyphInfo.h"
+#include "FontUtil.h"
 #include "../Rect.h"
 #include "../Matrix.h"
 
@@ -39,6 +38,8 @@
 // Font
 ///////////////////////////////////////////////////////////////////////////////
 
+struct CachedGlyphInfo;
+class CacheTexture;
 class FontRenderer;
 
 /**
@@ -119,7 +120,7 @@
     void measure(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
             int numGlyphs, Rect *bounds, const float* positions);
 
-    void invalidateTextureCache(CacheTexture* cacheTexture = NULL);
+    void invalidateTextureCache(CacheTexture* cacheTexture = nullptr);
 
     CachedGlyphInfo* cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching);
     void updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
@@ -150,7 +151,6 @@
     DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
 
     bool mIdentityTransform;
-    SkDeviceProperties mDeviceProperties;
 };
 
 inline int strictly_order_type(const Font::FontDescription& lhs,
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index c2fd5f5..4e5debe 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -30,9 +30,12 @@
 #define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
 #define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
 
-#define TEXTURE_BORDER_SIZE 1
-#if TEXTURE_BORDER_SIZE != 1
-# error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+#ifdef TEXTURE_BORDER_SIZE
+  #if TEXTURE_BORDER_SIZE != 1
+    #error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+  #endif
+#else
+  #define TEXTURE_BORDER_SIZE 1
 #endif
 
 #define CACHE_BLOCK_ROUNDING_SIZE 4
@@ -44,7 +47,7 @@
     #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
     #define IS_END_OF_STRING(glyph) false
 
-    static glyph_t nextGlyph(const uint16_t** srcPtr) {
+    static inline glyph_t nextGlyph(const uint16_t** srcPtr) {
         const uint16_t* src = *srcPtr;
         glyph_t g = *src++;
         *srcPtr = src;
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
new file mode 100644
index 0000000..29927ed
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <renderstate/Blend.h>
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure mapping Skia xfermodes to OpenGL blending factors.
+ */
+struct Blender {
+    SkXfermode::Mode mode;
+    GLenum src;
+    GLenum dst;
+};
+
+// In this array, the index of each Blender equals the value of the first
+// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
+const Blender kBlends[] = {
+    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
+    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
+};
+
+// This array contains the swapped version of each SkXfermode. For instance
+// this array's SrcOver blending mode is actually DstOver. You can refer to
+// createLayer() for more information on the purpose of this array.
+const Blender kBlendsSwap[] = {
+    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
+    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
+    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
+    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
+    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
+    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
+    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
+};
+
+Blend::Blend()
+    : mEnabled(false)
+    , mSrcMode(GL_ZERO)
+    , mDstMode(GL_ZERO) {
+    // gl blending off by default
+}
+
+void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) {
+    GLenum srcMode;
+    GLenum dstMode;
+    getFactors(mode, modeUsage, &srcMode, &dstMode);
+    setFactors(srcMode, dstMode);
+}
+
+void Blend::disable() {
+    if (mEnabled) {
+        glDisable(GL_BLEND);
+        mEnabled = false;
+    }
+}
+
+void Blend::invalidate() {
+    syncEnabled();
+    mSrcMode = mDstMode = GL_ZERO;
+}
+
+void Blend::syncEnabled() {
+    if (mEnabled) {
+        glEnable(GL_BLEND);
+    } else {
+        glDisable(GL_BLEND);
+    }
+}
+
+void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* outSrc, GLenum* outDst) {
+    *outSrc = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].src : kBlends[mode].src;
+    *outDst = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+}
+
+void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
+    if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
+        disable();
+    } else {
+        if (!mEnabled) {
+            glEnable(GL_BLEND);
+            mEnabled = true;
+        }
+
+        if (srcMode != mSrcMode || dstMode != mDstMode) {
+            glBlendFunc(srcMode, dstMode);
+            mSrcMode = srcMode;
+            mDstMode = dstMode;
+        }
+    }
+}
+
+void Blend::dump() {
+    ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
new file mode 100644
index 0000000..dcc681d
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_BLEND_H
+#define RENDERSTATE_BLEND_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Blend {
+    friend class RenderState;
+public:
+    // dictates whether to swap src/dst
+    enum class ModeOrderSwap {
+        NoSwap,
+        Swap,
+    };
+
+    void enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage);
+    void disable();
+    void syncEnabled();
+
+    static void getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage,
+            GLenum* outSrc, GLenum* outDst);
+    void setFactors(GLenum src, GLenum dst);
+
+    void dump();
+private:
+    Blend();
+    void invalidate();
+    bool mEnabled;
+    GLenum mSrcMode;
+    GLenum mDstMode;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
new file mode 100644
index 0000000..0521f65
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "renderstate/MeshState.h"
+
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+MeshState::MeshState()
+        : mCurrentIndicesBuffer(0)
+        , mCurrentPixelBuffer(0)
+        , mCurrentPositionPointer(this)
+        , mCurrentPositionStride(0)
+        , mCurrentTexCoordsPointer(this)
+        , mCurrentTexCoordsStride(0)
+        , mTexCoordsArrayEnabled(false)
+        , mQuadListIndices(0) {
+    glGenBuffers(1, &mUnitQuadBuffer);
+    glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
+
+    mCurrentBuffer = mUnitQuadBuffer;
+
+    uint16_t regionIndices[kMaxNumberOfQuads * 6];
+    for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
+        uint16_t quad = i * 4;
+        int index = i * 6;
+        regionIndices[index    ] = quad;       // top-left
+        regionIndices[index + 1] = quad + 1;   // top-right
+        regionIndices[index + 2] = quad + 2;   // bottom-left
+        regionIndices[index + 3] = quad + 2;   // bottom-left
+        regionIndices[index + 4] = quad + 1;   // top-right
+        regionIndices[index + 5] = quad + 3;   // bottom-right
+    }
+    glGenBuffers(1, &mQuadListIndices);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW);
+    mCurrentIndicesBuffer = mQuadListIndices;
+
+    // position attribute always enabled
+    glEnableVertexAttribArray(Program::kBindingPosition);
+}
+
+MeshState::~MeshState() {
+    glDeleteBuffers(1, &mUnitQuadBuffer);
+    mCurrentBuffer = 0;
+
+    glDeleteBuffers(1, &mQuadListIndices);
+    mQuadListIndices = 0;
+}
+
+void MeshState::dump() {
+    ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+    ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
+    ALOGD("MeshState vertices: vertex data %p, stride %d",
+            mCurrentPositionPointer, mCurrentPositionStride);
+    ALOGD("MeshState texCoord: data %p, stride %d",
+            mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Buffer Objects
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindMeshBuffer() {
+    return bindMeshBuffer(mUnitQuadBuffer);
+}
+
+bool MeshState::bindMeshBuffer(GLuint buffer) {
+    if (!buffer) buffer = mUnitQuadBuffer;
+    return bindMeshBufferInternal(buffer);
+}
+
+bool MeshState::unbindMeshBuffer() {
+    return bindMeshBufferInternal(0);
+}
+
+bool MeshState::bindMeshBufferInternal(GLuint buffer) {
+    if (mCurrentBuffer != buffer) {
+        glBindBuffer(GL_ARRAY_BUFFER, buffer);
+        mCurrentBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertices
+///////////////////////////////////////////////////////////////////////////////
+
+void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+        glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+        mCurrentPositionPointer = vertices;
+        mCurrentPositionStride = stride;
+    }
+}
+
+void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+    if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+        glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+        mCurrentTexCoordsPointer = vertices;
+        mCurrentTexCoordsStride = stride;
+    }
+}
+
+void MeshState::resetVertexPointers() {
+    mCurrentPositionPointer = this;
+    mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::resetTexCoordsVertexPointer() {
+    mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::enableTexCoordsVertexArray() {
+    if (!mTexCoordsArrayEnabled) {
+        glEnableVertexAttribArray(Program::kBindingTexCoords);
+        mCurrentTexCoordsPointer = this;
+        mTexCoordsArrayEnabled = true;
+    }
+}
+
+void MeshState::disableTexCoordsVertexArray() {
+    if (mTexCoordsArrayEnabled) {
+        glDisableVertexAttribArray(Program::kBindingTexCoords);
+        mTexCoordsArrayEnabled = false;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Indices
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+    if (mCurrentIndicesBuffer != buffer) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+        mCurrentIndicesBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+bool MeshState::bindQuadIndicesBuffer() {
+    return bindIndicesBufferInternal(mQuadListIndices);
+}
+
+bool MeshState::unbindIndicesBuffer() {
+    if (mCurrentIndicesBuffer) {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+        mCurrentIndicesBuffer = 0;
+        return true;
+    }
+    return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
new file mode 100644
index 0000000..e80f4d0
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_MESHSTATE_H
+#define RENDERSTATE_MESHSTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+
+// Maximum number of quads that pre-allocated meshes can draw
+const uint32_t kMaxNumberOfQuads = 2048;
+
+// This array is never used directly but used as a memcpy source in the
+// OpenGLRenderer constructor
+const TextureVertex kUnitQuadVertices[] = {
+        { 0, 0, 0, 0 },
+        { 1, 0, 1, 0 },
+        { 0, 1, 0, 1 },
+        { 1, 1, 1, 1 },
+};
+
+const GLsizei kVertexStride = sizeof(Vertex);
+const GLsizei kAlphaVertexStride = sizeof(AlphaVertex);
+const GLsizei kTextureVertexStride = sizeof(TextureVertex);
+const GLsizei kColorTextureVertexStride = sizeof(ColorTextureVertex);
+
+const GLsizei kMeshTextureOffset = 2 * sizeof(float);
+const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
+const GLsizei kVertexAAWidthOffset = 2 * sizeof(float);
+const GLsizei kVertexAALengthOffset = 3 * sizeof(float);
+const GLsizei kUnitQuadCount = 4;
+
+class MeshState {
+private:
+    friend class RenderState;
+
+public:
+    ~MeshState();
+    void dump();
+    ///////////////////////////////////////////////////////////////////////////////
+    // Buffer objects
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds the VBO used to render simple textured quads.
+     */
+    bool bindMeshBuffer();
+
+    /**
+     * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
+     */
+    bool bindMeshBuffer(GLuint buffer);
+
+    /**
+     * Unbinds the VBO used to render simple textured quads.
+     */
+    bool unbindMeshBuffer();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Vertices
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds an attrib to the specified float vertex pointer.
+     * Assumes a stride of gTextureVertexStride and a size of 2.
+     */
+    void bindPositionVertexPointer(bool force, const GLvoid* vertices,
+            GLsizei stride = kTextureVertexStride);
+
+    /**
+     * Binds an attrib to the specified float vertex pointer.
+     * Assumes a stride of gTextureVertexStride and a size of 2.
+     */
+    void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices,
+            GLsizei stride = kTextureVertexStride);
+
+    /**
+     * Resets the vertex pointers.
+     */
+    void resetVertexPointers();
+    void resetTexCoordsVertexPointer();
+
+    void enableTexCoordsVertexArray();
+    void disableTexCoordsVertexArray();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Indices
+    ///////////////////////////////////////////////////////////////////////////////
+    /**
+     * Binds a global indices buffer that can draw up to
+     * gMaxNumberOfQuads quads.
+     */
+    bool bindQuadIndicesBuffer();
+    bool unbindIndicesBuffer();
+
+    ///////////////////////////////////////////////////////////////////////////////
+    // Getters - for use in Glop building
+    ///////////////////////////////////////////////////////////////////////////////
+    GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
+    GLuint getQuadListIBO() { return mQuadListIndices; }
+private:
+    MeshState();
+    bool bindMeshBufferInternal(const GLuint buffer);
+    bool bindIndicesBufferInternal(const GLuint buffer);
+
+    GLuint mUnitQuadBuffer;
+
+    GLuint mCurrentBuffer;
+    GLuint mCurrentIndicesBuffer;
+    GLuint mCurrentPixelBuffer;
+
+    const void* mCurrentPositionPointer;
+    GLsizei mCurrentPositionStride;
+    const void* mCurrentTexCoordsPointer;
+    GLsizei mCurrentTexCoordsStride;
+
+    bool mTexCoordsArrayEnabled;
+
+    // Global index buffer
+    GLuint mQuadListIndices;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
new file mode 100644
index 0000000..c23af52
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "renderstate/PixelBufferState.h"
+
+namespace android {
+namespace uirenderer {
+
+PixelBufferState::PixelBufferState()
+        : mCurrentPixelBuffer(0) {
+}
+
+bool PixelBufferState::bind(GLuint buffer) {
+    if (mCurrentPixelBuffer != buffer) {
+        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
+        mCurrentPixelBuffer = buffer;
+        return true;
+    }
+    return false;
+}
+
+bool PixelBufferState::unbind() {
+    if (mCurrentPixelBuffer) {
+        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+        mCurrentPixelBuffer = 0;
+        return true;
+    }
+    return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
new file mode 100644
index 0000000..8dab21d
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_PIXELBUFFERSTATE_H
+#define RENDERSTATE_PIXELBUFFERSTATE_H
+
+#include <GLES3/gl3.h>
+
+namespace android {
+namespace uirenderer {
+
+class PixelBufferState {
+    friend class Caches; // TODO: move to RenderState
+public:
+    bool bind(GLuint buffer);
+    bool unbind();
+private:
+    PixelBufferState();
+    GLuint mCurrentPixelBuffer;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
new file mode 100644
index 0000000..7b44d6d
--- /dev/null
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -0,0 +1,354 @@
+/*
+ * 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 "renderstate/RenderState.h"
+
+#include "renderthread/CanvasContext.h"
+#include "renderthread/EglManager.h"
+#include "utils/GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+RenderState::RenderState(renderthread::RenderThread& thread)
+        : mRenderThread(thread)
+        , mViewportWidth(0)
+        , mViewportHeight(0)
+        , mFramebuffer(0) {
+    mThreadId = pthread_self();
+}
+
+RenderState::~RenderState() {
+    LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+            "State object lifecycle not managed correctly");
+}
+
+void RenderState::onGLContextCreated() {
+    LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+            "State object lifecycle not managed correctly");
+    mBlend = new Blend();
+    mMeshState = new MeshState();
+    mScissor = new Scissor();
+    mStencil = new Stencil();
+
+    // This is delayed because the first access of Caches makes GL calls
+    if (!mCaches) {
+        mCaches = &Caches::createInstance(*this);
+    }
+    mCaches->init();
+    mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+}
+
+static void layerLostGlContext(Layer* layer) {
+    layer->onGlContextLost();
+}
+
+void RenderState::onGLContextDestroyed() {
+/*
+    size_t size = mActiveLayers.size();
+    if (CC_UNLIKELY(size != 0)) {
+        ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d",
+                mRegisteredContexts.size(), size, mActiveLayers.empty());
+        mCaches->dumpMemoryUsage();
+        for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
+                cit != mRegisteredContexts.end(); cit++) {
+            renderthread::CanvasContext* context = *cit;
+            ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get());
+            ALOGE("  Prefeteched layers: %zu", context->mPrefetechedLayers.size());
+            for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin();
+                    pit != context->mPrefetechedLayers.end(); pit++) {
+                (*pit)->debugDumpLayers("    ");
+            }
+            context->mRootRenderNode->debugDumpLayers("  ");
+        }
+
+
+        if (mActiveLayers.begin() == mActiveLayers.end()) {
+            ALOGE("set has become empty. wat.");
+        }
+        for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
+             lit != mActiveLayers.end(); lit++) {
+            const Layer* layer = *(lit);
+            ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d",
+                    layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered);
+        }
+        LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
+    }
+*/
+
+    // TODO: reset all cached state in state objects
+    std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
+    mAssetAtlas.terminate();
+
+    mCaches->terminate();
+
+    delete mBlend;
+    mBlend = nullptr;
+    delete mMeshState;
+    mMeshState = nullptr;
+    delete mScissor;
+    mScissor = nullptr;
+    delete mStencil;
+    mStencil = nullptr;
+}
+
+void RenderState::setViewport(GLsizei width, GLsizei height) {
+    mViewportWidth = width;
+    mViewportHeight = height;
+    glViewport(0, 0, mViewportWidth, mViewportHeight);
+}
+
+
+void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
+    *outWidth = mViewportWidth;
+    *outHeight = mViewportHeight;
+}
+
+void RenderState::bindFramebuffer(GLuint fbo) {
+    if (mFramebuffer != fbo) {
+        mFramebuffer = fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+    }
+}
+
+void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
+    interruptForFunctorInvoke();
+    (*functor)(mode, info);
+    resumeFromFunctorInvoke();
+}
+
+void RenderState::interruptForFunctorInvoke() {
+    mCaches->setProgram(nullptr);
+    mCaches->textureState().resetActiveTexture();
+    meshState().unbindMeshBuffer();
+    meshState().unbindIndicesBuffer();
+    meshState().resetVertexPointers();
+    meshState().disableTexCoordsVertexArray();
+    debugOverdraw(false, false);
+}
+
+void RenderState::resumeFromFunctorInvoke() {
+    glViewport(0, 0, mViewportWidth, mViewportHeight);
+    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+    debugOverdraw(false, false);
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+    scissor().invalidate();
+    blend().invalidate();
+
+    mCaches->textureState().activateTexture(0);
+    mCaches->textureState().resetBoundTextures();
+}
+
+void RenderState::debugOverdraw(bool enable, bool clear) {
+    if (mCaches->debugOverdraw && mFramebuffer == 0) {
+        if (clear) {
+            scissor().setEnabled(false);
+            stencil().clear();
+        }
+        if (enable) {
+            stencil().enableDebugWrite();
+        } else {
+            stencil().disable();
+        }
+    }
+}
+
+void RenderState::requireGLContext() {
+    assertOnGLThread();
+    mRenderThread.eglManager().requireGlContext();
+}
+
+void RenderState::assertOnGLThread() {
+    pthread_t curr = pthread_self();
+    LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
+}
+
+class DecStrongTask : public renderthread::RenderTask {
+public:
+    DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
+
+    virtual void run() override {
+        mObject->decStrong(nullptr);
+        mObject = nullptr;
+        delete this;
+    }
+
+private:
+    VirtualLightRefBase* mObject;
+};
+
+void RenderState::postDecStrong(VirtualLightRefBase* object) {
+    mRenderThread.queue(new DecStrongTask(object));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Render
+///////////////////////////////////////////////////////////////////////////////
+
+void RenderState::render(const Glop& glop) {
+    const Glop::Mesh& mesh = glop.mesh;
+    const Glop::Mesh::Vertices& vertices = mesh.vertices;
+    const Glop::Mesh::Indices& indices = mesh.indices;
+    const Glop::Fill& fill = glop.fill;
+
+    // ---------------------------------------------
+    // ---------- Program + uniform setup ----------
+    // ---------------------------------------------
+    mCaches->setProgram(fill.program);
+
+    if (fill.colorEnabled) {
+        fill.program->setColor(fill.color);
+    }
+
+    fill.program->set(glop.transform.ortho,
+            glop.transform.modelView,
+            glop.transform.canvas,
+            glop.transform.fudgingOffset);
+
+    // Color filter uniforms
+    if (fill.filterMode == ProgramDescription::kColorBlend) {
+        const FloatColor& color = fill.filter.color;
+        glUniform4f(mCaches->program().getUniform("colorBlend"),
+                color.r, color.g, color.b, color.a);
+    } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
+        glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
+                fill.filter.matrix.matrix);
+        glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
+                fill.filter.matrix.vector);
+    }
+
+    // Round rect clipping uniforms
+    if (glop.roundRectClipState) {
+        // TODO: avoid query, and cache values (or RRCS ptr) in program
+        const RoundRectClipState* state = glop.roundRectClipState;
+        const Rect& innerRect = state->innerRect;
+        glUniform4f(fill.program->getUniform("roundRectInnerRectLTRB"),
+                innerRect.left, innerRect.top,
+                innerRect.right, innerRect.bottom);
+        glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
+                1, GL_FALSE, &state->matrix.data[0]);
+
+        // add half pixel to round out integer rect space to cover pixel centers
+        float roundedOutRadius = state->radius + 0.5f;
+        glUniform1f(fill.program->getUniform("roundRectRadius"),
+                roundedOutRadius);
+    }
+
+    // --------------------------------
+    // ---------- Mesh setup ----------
+    // --------------------------------
+    // vertices
+    const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
+            || (vertices.position != nullptr);
+    meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
+
+    // indices
+    meshState().bindIndicesBufferInternal(indices.bufferObject);
+
+    if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
+        const Glop::Fill::TextureData& texture = fill.texture;
+        // texture always takes slot 0, shader samplers increment from there
+        mCaches->textureState().activateTexture(0);
+
+        if (texture.clamp != GL_INVALID_ENUM) {
+            texture.texture->setWrap(texture.clamp, true);
+        }
+        if (texture.filter != GL_INVALID_ENUM) {
+            texture.texture->setFilter(texture.filter, true);
+        }
+
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id);
+        meshState().enableTexCoordsVertexArray();
+        meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
+
+        if (texture.textureTransform) {
+            glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
+                    GL_FALSE, &texture.textureTransform->data[0]);
+        }
+    } else {
+        meshState().disableTexCoordsVertexArray();
+    }
+    int colorLocation = -1;
+    if (vertices.attribFlags & VertexAttribFlags::kColor) {
+        colorLocation = fill.program->getAttrib("colors");
+        glEnableVertexAttribArray(colorLocation);
+        glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
+    }
+    int alphaLocation = -1;
+    if (vertices.attribFlags & VertexAttribFlags::kAlpha) {
+        // NOTE: alpha vertex position is computed assuming no VBO
+        const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
+        alphaLocation = fill.program->getAttrib("vtxAlpha");
+        glEnableVertexAttribArray(alphaLocation);
+        glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
+    }
+    // Shader uniforms
+    SkiaShader::apply(*mCaches, fill.skiaShaderData);
+
+    // ------------------------------------
+    // ---------- GL state setup ----------
+    // ------------------------------------
+    blend().setFactors(glop.blend.src, glop.blend.dst);
+
+    // ------------------------------------
+    // ---------- Actual drawing ----------
+    // ------------------------------------
+    if (indices.bufferObject == meshState().getQuadListIBO()) {
+        // Since the indexed quad list is of limited length, we loop over
+        // the glDrawXXX method while updating the vertex pointer
+        GLsizei elementsCount = mesh.elementCount;
+        const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
+        while (elementsCount > 0) {
+            GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+
+            // rebind pointers without forcing, since initial bind handled above
+            meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
+            if (vertices.attribFlags & VertexAttribFlags::kTextureCoord) {
+                meshState().bindTexCoordsVertexPointer(false,
+                        vertexData + kMeshTextureOffset, vertices.stride);
+            }
+
+            glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            elementsCount -= drawCount;
+            vertexData += (drawCount / 6) * 4 * vertices.stride;
+        }
+    } else if (indices.bufferObject || indices.indices) {
+        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+    } else {
+        glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
+    }
+
+    // -----------------------------------
+    // ---------- Mesh teardown ----------
+    // -----------------------------------
+    if (vertices.attribFlags & VertexAttribFlags::kAlpha) {
+        glDisableVertexAttribArray(alphaLocation);
+    }
+    if (vertices.attribFlags & VertexAttribFlags::kColor) {
+        glDisableVertexAttribArray(colorLocation);
+    }
+}
+
+void RenderState::dump() {
+    blend().dump();
+    meshState().dump();
+    scissor().dump();
+    stencil().dump();
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
new file mode 100644
index 0000000..4fd792c
--- /dev/null
+++ b/libs/hwui/renderstate/RenderState.h
@@ -0,0 +1,130 @@
+/*
+ * 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 RENDERSTATE_H
+#define RENDERSTATE_H
+
+#include <set>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <utils/Mutex.h>
+#include <utils/Functor.h>
+#include <utils/RefBase.h>
+#include <private/hwui/DrawGlInfo.h>
+#include <renderstate/Blend.h>
+
+#include "AssetAtlas.h"
+#include "Caches.h"
+#include "Glop.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/Scissor.h"
+#include "renderstate/Stencil.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+class Layer;
+
+namespace renderthread {
+class CanvasContext;
+class RenderThread;
+}
+
+// TODO: Replace Cache's GL state tracking with this. For now it's more a thin
+// wrapper of Caches for users to migrate to.
+class RenderState {
+    PREVENT_COPY_AND_ASSIGN(RenderState);
+public:
+    void onGLContextCreated();
+    void onGLContextDestroyed();
+
+    void setViewport(GLsizei width, GLsizei height);
+    void getViewport(GLsizei* outWidth, GLsizei* outHeight);
+
+    void bindFramebuffer(GLuint fbo);
+    GLint getFramebuffer() { return mFramebuffer; }
+
+    void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
+
+    void debugOverdraw(bool enable, bool clear);
+
+    void registerLayer(Layer* layer) {
+        mActiveLayers.insert(layer);
+    }
+    void unregisterLayer(Layer* layer) {
+        mActiveLayers.erase(layer);
+    }
+
+    void registerCanvasContext(renderthread::CanvasContext* context) {
+        mRegisteredContexts.insert(context);
+    }
+
+    void unregisterCanvasContext(renderthread::CanvasContext* context) {
+        mRegisteredContexts.erase(context);
+    }
+
+    void requireGLContext();
+
+    // TODO: This system is a little clunky feeling, this could use some
+    // more thinking...
+    void postDecStrong(VirtualLightRefBase* object);
+
+    void render(const Glop& glop);
+
+    AssetAtlas& assetAtlas() { return mAssetAtlas; }
+    Blend& blend() { return *mBlend; }
+    MeshState& meshState() { return *mMeshState; }
+    Scissor& scissor() { return *mScissor; }
+    Stencil& stencil() { return *mStencil; }
+
+    void dump();
+private:
+    friend class renderthread::RenderThread;
+    friend class Caches;
+
+    void interruptForFunctorInvoke();
+    void resumeFromFunctorInvoke();
+    void assertOnGLThread();
+
+    RenderState(renderthread::RenderThread& thread);
+    ~RenderState();
+
+
+    renderthread::RenderThread& mRenderThread;
+    Caches* mCaches = nullptr;
+
+    Blend* mBlend = nullptr;
+    MeshState* mMeshState = nullptr;
+    Scissor* mScissor = nullptr;
+    Stencil* mStencil = nullptr;
+
+    AssetAtlas mAssetAtlas;
+    std::set<Layer*> mActiveLayers;
+    std::set<renderthread::CanvasContext*> mRegisteredContexts;
+
+    GLsizei mViewportWidth;
+    GLsizei mViewportHeight;
+    GLuint mFramebuffer;
+
+    pthread_t mThreadId;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* RENDERSTATE_H */
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
new file mode 100644
index 0000000..95dcd18
--- /dev/null
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "renderstate/Scissor.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace uirenderer {
+
+Scissor::Scissor()
+    : mEnabled(false)
+    , mScissorX(0)
+    , mScissorY(0)
+    , mScissorWidth(0)
+    , mScissorHeight(0) {
+}
+
+bool Scissor::setEnabled(bool enabled) {
+    if (mEnabled != enabled) {
+        if (enabled) {
+            glEnable(GL_SCISSOR_TEST);
+        } else {
+            glDisable(GL_SCISSOR_TEST);
+        }
+        mEnabled = enabled;
+        return true;
+    }
+    return false;
+}
+
+bool Scissor::set(GLint x, GLint y, GLint width, GLint height) {
+    if (mEnabled && (x != mScissorX || y != mScissorY
+            || width != mScissorWidth || height != mScissorHeight)) {
+
+        if (x < 0) {
+            width += x;
+            x = 0;
+        }
+        if (y < 0) {
+            height += y;
+            y = 0;
+        }
+        if (width < 0) {
+            width = 0;
+        }
+        if (height < 0) {
+            height = 0;
+        }
+        glScissor(x, y, width, height);
+
+        mScissorX = x;
+        mScissorY = y;
+        mScissorWidth = width;
+        mScissorHeight = height;
+
+        return true;
+    }
+    return false;
+}
+
+void Scissor::reset() {
+    mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
+}
+
+void Scissor::invalidate() {
+    mEnabled = glIsEnabled(GL_SCISSOR_TEST);
+    setEnabled(true);
+    reset();
+}
+
+void Scissor::dump() {
+    ALOGD("Scissor: enabled %d, %d %d %d %d",
+            mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
new file mode 100644
index 0000000..b37ec58
--- /dev/null
+++ b/libs/hwui/renderstate/Scissor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_SCISSOR_H
+#define RENDERSTATE_SCISSOR_H
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace uirenderer {
+
+class Scissor {
+    friend class RenderState;
+public:
+    bool setEnabled(bool enabled);
+    bool set(GLint x, GLint y, GLint width, GLint height);
+    void reset();
+    bool isEnabled() { return mEnabled; }
+    void dump();
+private:
+    Scissor();
+    void invalidate();
+    bool mEnabled;
+    GLint mScissorX;
+    GLint mScissorY;
+    GLint mScissorWidth;
+    GLint mScissorHeight;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_SCISSOR_H
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
new file mode 100644
index 0000000..cedb233
--- /dev/null
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "renderstate/Stencil.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "Properties.h"
+
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace uirenderer {
+
+#if DEBUG_STENCIL
+#define STENCIL_WRITE_VALUE 0xff
+#define STENCIL_MASK_VALUE 0xff
+#else
+#define STENCIL_WRITE_VALUE 0x1
+#define STENCIL_MASK_VALUE 0x1
+#endif
+
+Stencil::Stencil()
+        : mState(kDisabled) {
+}
+
+uint8_t Stencil::getStencilSize() {
+    return STENCIL_BUFFER_SIZE;
+}
+
+GLenum Stencil::getSmallestStencilFormat() {
+#if !DEBUG_STENCIL
+    const Extensions& extensions = Caches::getInstance().extensions();
+    if (extensions.has1BitStencil()) {
+        return GL_STENCIL_INDEX1_OES;
+    } else if (extensions.has4BitStencil()) {
+        return GL_STENCIL_INDEX4_OES;
+    }
+#endif
+    return GL_STENCIL_INDEX8;
+}
+
+void Stencil::clear() {
+    glClearStencil(0);
+    glClear(GL_STENCIL_BUFFER_BIT);
+}
+
+void Stencil::enableTest(int incrementThreshold) {
+    if (mState != kTest) {
+        enable();
+        if (incrementThreshold > 0) {
+            glStencilFunc(GL_EQUAL, incrementThreshold, 0xff);
+        } else {
+            glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
+        }
+        // We only want to test, let's keep everything
+        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        glStencilMask(0);
+        mState = kTest;
+    }
+}
+
+void Stencil::enableWrite(int incrementThreshold) {
+    if (mState != kWrite) {
+        enable();
+        if (incrementThreshold > 0) {
+            glStencilFunc(GL_ALWAYS, 1, 0xff);
+            // The test always passes so the first two values are meaningless
+            glStencilOp(GL_INCR, GL_INCR, GL_INCR);
+        } else {
+            glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
+            // The test always passes so the first two values are meaningless
+            glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+        }
+        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+        glStencilMask(0xff);
+        mState = kWrite;
+    }
+}
+
+void Stencil::enableDebugTest(GLint value, bool greater) {
+    enable();
+    glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
+    // We only want to test, let's keep everything
+    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+    mState = kTest;
+}
+
+void Stencil::enableDebugWrite() {
+    if (mState != kWrite) {
+        enable();
+        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
+        // The test always passes so the first two values are meaningless
+        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+        mState = kWrite;
+    }
+}
+
+void Stencil::enable() {
+    if (mState == kDisabled) {
+        glEnable(GL_STENCIL_TEST);
+    }
+}
+
+void Stencil::disable() {
+    if (mState != kDisabled) {
+        glDisable(GL_STENCIL_TEST);
+        mState = kDisabled;
+    }
+}
+
+void Stencil::dump() {
+    ALOGD("Stencil: state %d", mState);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
new file mode 100644
index 0000000..e4f0f3f
--- /dev/null
+++ b/libs/hwui/renderstate/Stencil.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_STENCIL_H
+#define ANDROID_HWUI_STENCIL_H
+
+#ifndef LOG_TAG
+    #define LOG_TAG "OpenGLRenderer"
+#endif
+
+#include <GLES2/gl2.h>
+
+#include <cutils/compiler.h>
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stencil buffer management
+///////////////////////////////////////////////////////////////////////////////
+
+class ANDROID_API Stencil {
+public:
+    Stencil();
+
+    /**
+     * Returns the desired size for the stencil buffer. If the returned value
+     * is 0, then no stencil buffer is required.
+     */
+    ANDROID_API static uint8_t getStencilSize();
+
+    /**
+     * Returns the smallest stencil format accepted by render buffers.
+     */
+    static GLenum getSmallestStencilFormat();
+
+    /**
+     * Clears the stencil buffer.
+     */
+    void clear();
+
+    /**
+     * Enables stencil test. When the stencil test is enabled the stencil buffer is not written
+     * into. An increment threshold of zero causes the stencil to use a constant reference value
+     * and GL_EQUAL for the test. A non-zero increment threshold causes the stencil to use that
+     * value as the reference value and GL_EQUAL for the test.
+     */
+    void enableTest(int incrementThreshold);
+
+    /**
+     * Enables stencil write. When stencil write is enabled, the stencil
+     * test always succeeds and the value 0x1 is written in the stencil
+     * buffer for each fragment. An increment threshold of zero causes the stencil to use a constant
+     * reference value and GL_EQUAL for the test. A non-zero increment threshold causes the stencil
+     * to use that value as the reference value and GL_EQUAL for the test.
+     */
+    void enableWrite(int incrementThreshold);
+
+    /**
+     * The test passes only when equal to the specified value.
+     */
+    void enableDebugTest(GLint value, bool greater = false);
+
+    /**
+     * Used for debugging. The stencil test always passes and increments.
+     */
+    void enableDebugWrite();
+
+    /**
+     * Disables stencil test and write.
+     */
+    void disable();
+
+    /**
+     * Indicates whether either test or write is enabled.
+     */
+    bool isEnabled() {
+        return mState != kDisabled;
+    }
+
+    /**
+     * Indicates whether testing only is enabled.
+     */
+    bool isTestEnabled() {
+        return mState == kTest;
+    }
+
+    bool isWriteEnabled() {
+        return mState == kWrite;
+    }
+
+    void dump();
+
+private:
+    void enable();
+
+    enum StencilState {
+        kDisabled,
+        kTest,
+        kWrite
+    };
+
+    StencilState mState;
+
+}; // class Stencil
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_STENCIL_H
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
new file mode 100644
index 0000000..a211de7
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "renderstate/TextureState.h"
+
+namespace android {
+namespace uirenderer {
+
+// Must define as many texture units as specified by kTextureUnitsCount
+const GLenum kTextureUnits[] = {
+    GL_TEXTURE0,
+    GL_TEXTURE1,
+    GL_TEXTURE2
+};
+
+TextureState::TextureState()
+        : mTextureUnit(0) {
+    glActiveTexture(kTextureUnits[0]);
+    resetBoundTextures();
+
+    GLint maxTextureUnits;
+    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+    LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
+        "At least %d texture units are required!", kTextureUnitsCount);
+}
+
+void TextureState::activateTexture(GLuint textureUnit) {
+    if (mTextureUnit != textureUnit) {
+        glActiveTexture(kTextureUnits[textureUnit]);
+        mTextureUnit = textureUnit;
+    }
+}
+
+void TextureState::resetActiveTexture() {
+    mTextureUnit = -1;
+}
+
+void TextureState::bindTexture(GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(GL_TEXTURE_2D, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void TextureState::bindTexture(GLenum target, GLuint texture) {
+    if (target == GL_TEXTURE_2D) {
+        bindTexture(texture);
+    } else {
+        // GLConsumer directly calls glBindTexture() with
+        // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
+        // since the cached state could be stale
+        glBindTexture(target, texture);
+    }
+}
+
+void TextureState::deleteTexture(GLuint texture) {
+    // When glDeleteTextures() is called on a currently bound texture,
+    // OpenGL ES specifies that the texture is then considered unbound
+    // Consider the following series of calls:
+    //
+    // glGenTextures -> creates texture name 2
+    // glBindTexture(2)
+    // glDeleteTextures(2) -> 2 is now unbound
+    // glGenTextures -> can return 2 again
+    //
+    // If we don't call glBindTexture(2) after the second glGenTextures
+    // call, any texture operation will be performed on the default
+    // texture (name=0)
+
+    unbindTexture(texture);
+
+    glDeleteTextures(1, &texture);
+}
+
+void TextureState::resetBoundTextures() {
+    for (int i = 0; i < kTextureUnitsCount; i++) {
+        mBoundTextures[i] = 0;
+    }
+}
+
+void TextureState::unbindTexture(GLuint texture) {
+    for (int i = 0; i < kTextureUnitsCount; i++) {
+        if (mBoundTextures[i] == texture) {
+            mBoundTextures[i] = 0;
+        }
+    }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
new file mode 100644
index 0000000..5a57b9f
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_TEXTURESTATE_H
+#define RENDERSTATE_TEXTURESTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class TextureState {
+    friend class Caches; // TODO: move to RenderState
+public:
+    /**
+     * Activate the specified texture unit. The texture unit must
+     * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+     */
+    void activateTexture(GLuint textureUnit);
+
+    /**
+     * Invalidate the cached value of the active texture unit.
+     */
+    void resetActiveTexture();
+
+    /**
+     * Binds the specified texture as a GL_TEXTURE_2D texture.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLenum, GLuint).
+     */
+    void bindTexture(GLuint texture);
+
+    /**
+     * Binds the specified texture with the specified render target.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLuint).
+     */
+    void bindTexture(GLenum target, GLuint texture);
+
+    /**
+     * Deletes the specified texture and clears it from the cache
+     * of bound textures.
+     * All textures must be deleted using this method.
+     */
+    void deleteTexture(GLuint texture);
+
+    /**
+     * Signals that the cache of bound textures should be cleared.
+     * Other users of the context may have altered which textures are bound.
+     */
+    void resetBoundTextures();
+
+    /**
+     * Clear the cache of bound textures.
+     */
+    void unbindTexture(GLuint texture);
+private:
+    // total number of texture units available for use
+    static const int kTextureUnitsCount = 3;
+
+    TextureState();
+    GLuint mTextureUnit;
+
+    // Caches texture bindings for the GL_TEXTURE_2D target
+    GLuint mBoundTextures[kTextureUnitsCount];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 75bd067..9456073 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -16,19 +16,19 @@
 
 #include "CanvasContext.h"
 
-#include <algorithm>
-#include <private/hwui/DrawGlInfo.h>
-#include <strings.h>
-
 #include "EglManager.h"
 #include "RenderThread.h"
 #include "../AnimationContext.h"
 #include "../Caches.h"
 #include "../DeferredLayerUpdater.h"
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
+#include "../renderstate/Stencil.h"
 #include "../LayerRenderer.h"
 #include "../OpenGLRenderer.h"
-#include "../Stencil.h"
+
+#include <algorithm>
+#include <private/hwui/DrawGlInfo.h>
+#include <strings.h>
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
@@ -45,28 +45,29 @@
         , mBufferPreserved(false)
         , mSwapBehavior(kSwap_default)
         , mOpaque(!translucent)
-        , mCanvas(NULL)
+        , mCanvas(nullptr)
         , mHaveNewSurface(false)
-        , mRootRenderNode(rootRenderNode) {
-    mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord());
+        , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
+        , mRootRenderNode(rootRenderNode)
+        , mCurrentFrameInfo(nullptr) {
     mRenderThread.renderState().registerCanvasContext(this);
+    mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
 }
 
 CanvasContext::~CanvasContext() {
     destroy();
-    delete mAnimationContext;
     mRenderThread.renderState().unregisterCanvasContext(this);
 }
 
 void CanvasContext::destroy() {
     stopDrawing();
-    setSurface(NULL);
+    setSurface(nullptr);
     freePrefetechedLayers();
     destroyHardwareResources();
     mAnimationContext->destroy();
     if (mCanvas) {
         delete mCanvas;
-        mCanvas = 0;
+        mCanvas = nullptr;
     }
 }
 
@@ -96,7 +97,7 @@
 
 void CanvasContext::swapBuffers() {
     if (CC_UNLIKELY(!mEglManager.swapBuffers(mEglSurface))) {
-        setSurface(NULL);
+        setSurface(nullptr);
     }
     mHaveNewSurface = false;
 }
@@ -152,9 +153,13 @@
     }
 }
 
-void CanvasContext::prepareTree(TreeInfo& info) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo) {
     mRenderThread.removeFrameCallback(this);
 
+    mCurrentFrameInfo = &mFrames.next();
+    mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
+    mCurrentFrameInfo->markSyncStart();
+
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
     if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {
@@ -204,6 +209,7 @@
             "drawRenderNode called on a context with no canvas or surface!");
 
     profiler().markPlaybackStart();
+    mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -224,29 +230,35 @@
         profiler().unionDirty(&dirty);
     }
 
-    status_t status;
     if (!dirty.isEmpty()) {
-        status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
+        mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
                 dirty.fRight, dirty.fBottom, mOpaque);
     } else {
-        status = mCanvas->prepare(mOpaque);
+        mCanvas->prepare(mOpaque);
     }
 
     Rect outBounds;
-    status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
+    mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
 
     profiler().draw(mCanvas);
 
-    mCanvas->finish();
+    bool drew = mCanvas->finish();
 
     profiler().markPlaybackEnd();
 
-    if (status & DrawGlInfo::kStatusDrew) {
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    mCurrentFrameInfo->markSwapBuffers();
+
+    if (drew) {
         swapBuffers();
     } else {
         mEglManager.cancelFrame();
     }
 
+    // TODO: Use a fence for real completion?
+    mCurrentFrameInfo->markFrameCompleted();
+    mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
     profiler().finishFrame();
 }
 
@@ -259,9 +271,14 @@
     ATRACE_CALL();
 
     profiler().startFrame();
+    int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
+    UiFrameInfoBuilder(frameInfo)
+        .addFlag(FrameInfoFlags::kRTAnimation)
+        .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
+                mRenderThread.timeLord().latestVsync());
 
     TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
-    prepareTree(info);
+    prepareTree(info, frameInfo);
     if (info.out.canDrawThisFrame) {
         draw();
     }
@@ -275,19 +292,19 @@
         mode = DrawGlInfo::kModeProcess;
     }
 
-    thread.renderState().invokeFunctor(functor, mode, NULL);
+    thread.renderState().invokeFunctor(functor, mode, nullptr);
 }
 
 void CanvasContext::markLayerInUse(RenderNode* node) {
     if (mPrefetechedLayers.erase(node)) {
-        node->decStrong(0);
+        node->decStrong(nullptr);
     }
 }
 
 static void destroyPrefetechedNode(RenderNode* node) {
     ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
     node->destroyHardwareResources();
-    node->decStrong(0);
+    node->decStrong(nullptr);
 }
 
 void CanvasContext::freePrefetechedLayers() {
@@ -321,7 +338,7 @@
     mCanvas->markLayersAsBuildLayers();
     mCanvas->flushLayerUpdates();
 
-    node->incStrong(0);
+    node->incStrong(nullptr);
     mPrefetechedLayers.insert(node);
 }
 
@@ -374,6 +391,28 @@
     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
 }
 
+void CanvasContext::dumpFrames(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\n\n---PROFILEDATA---");
+    for (size_t i = 0; i < mFrames.size(); i++) {
+        FrameInfo& frame = mFrames[i];
+        if (frame[FrameInfoIndex::kSyncStart] == 0) {
+            continue;
+        }
+        fprintf(file, "\n");
+        for (int i = 0; i < static_cast<int>(FrameInfoIndex::kNumIndexes); i++) {
+            fprintf(file, "%" PRId64 ",", frame[i]);
+        }
+    }
+    fprintf(file, "\n---PROFILEDATA---\n\n");
+    fflush(file);
+}
+
+void CanvasContext::resetFrameStats() {
+    mFrames.clear();
+    mRenderThread.jankTracker().reset();
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0cc2c7c..c3904c2 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -17,7 +17,14 @@
 #ifndef CANVASCONTEXT_H_
 #define CANVASCONTEXT_H_
 
-#include <set>
+#include "DamageAccumulator.h"
+#include "DrawProfiler.h"
+#include "IContextFactory.h"
+#include "FrameInfo.h"
+#include "RenderNode.h"
+#include "utils/RingBuffer.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
@@ -25,14 +32,8 @@
 #include <utils/Functor.h>
 #include <utils/Vector.h>
 
-#include "../DamageAccumulator.h"
-#include "../DrawProfiler.h"
-#include "../IContextFactory.h"
-#include "../RenderNode.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#define FUNCTOR_PROCESS_DELAY 4
+#include <set>
+#include <string>
 
 namespace android {
 namespace uirenderer {
@@ -75,12 +76,12 @@
     void setOpaque(bool opaque);
     void makeCurrent();
     void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
-    void prepareTree(TreeInfo& info);
+    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo);
     void draw();
     void destroy();
 
     // IFrameCallback, Chroreographer-driven frame callback entry point
-    virtual void doFrame();
+    virtual void doFrame() override;
 
     void buildLayer(RenderNode* node);
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -103,6 +104,12 @@
 
     DrawProfiler& profiler() { return mProfiler; }
 
+    void dumpFrames(int fd);
+    void resetFrameStats();
+
+    void setName(const std::string&& name) { mName = name; }
+    const std::string& name() { return mName; }
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -128,11 +135,15 @@
     OpenGLRenderer* mCanvas;
     bool mHaveNewSurface;
     DamageAccumulator mDamageAccumulator;
-    AnimationContext* mAnimationContext;
+    std::unique_ptr<AnimationContext> mAnimationContext;
 
     const sp<RenderNode> mRootRenderNode;
 
     DrawProfiler mProfiler;
+    FrameInfo* mCurrentFrameInfo;
+    // Ring buffer large enough for 1 second worth of frames
+    RingBuffer<FrameInfo, 60> mFrames;
+    std::string mName;
 
     std::set<RenderNode*> mPrefetechedLayers;
 };
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 97b31a9..35391b2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -32,11 +32,8 @@
 namespace renderthread {
 
 DrawFrameTask::DrawFrameTask()
-        : mRenderThread(NULL)
-        , mContext(NULL)
-        , mFrameTimeNanos(0)
-        , mRecordDurationNanos(0)
-        , mDensity(1.0f) // safe enough default
+        : mRenderThread(nullptr)
+        , mContext(nullptr)
         , mSyncResult(kSync_OK) {
 }
 
@@ -68,18 +65,12 @@
     }
 }
 
-int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
+int DrawFrameTask::drawFrame() {
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
     mSyncResult = kSync_OK;
-    mFrameTimeNanos = frameTimeNanos;
-    mRecordDurationNanos = recordDurationNanos;
     postAndWait();
 
-    // Reset the single-frame data
-    mFrameTimeNanos = 0;
-    mRecordDurationNanos = 0;
-
     return mSyncResult;
 }
 
@@ -92,8 +83,7 @@
 void DrawFrameTask::run() {
     ATRACE_NAME("DrawFrame");
 
-    mContext->profiler().setDensity(mDensity);
-    mContext->profiler().startFrame(mRecordDurationNanos);
+    mContext->profiler().startFrame();
 
     bool canUnblockUiThread;
     bool canDrawThisFrame;
@@ -122,7 +112,8 @@
 
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     ATRACE_CALL();
-    mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
+    int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::kVsync)];
+    mRenderThread->timeLord().vsyncReceived(vsync);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
 
@@ -130,7 +121,7 @@
         mContext->processLayerUpdate(mLayers[i].get());
     }
     mLayers.clear();
-    mContext->prepareTree(info);
+    mContext->prepareTree(info, mFrameInfo);
 
     // This is after the prepareTree so that any pending operations
     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 28f6cb2..8039643 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -25,6 +25,7 @@
 #include "RenderTask.h"
 
 #include "../Rect.h"
+#include "../FrameInfo.h"
 #include "../TreeInfo.h"
 
 namespace android {
@@ -61,10 +62,11 @@
     void pushLayerUpdate(DeferredLayerUpdater* layer);
     void removeLayerUpdate(DeferredLayerUpdater* layer);
 
-    void setDensity(float density) { mDensity = density; }
-    int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
+    int drawFrame();
 
-    virtual void run();
+    int64_t* frameInfo() { return mFrameInfo; }
+
+    virtual void run() override;
 
 private:
     void postAndWait();
@@ -80,12 +82,11 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    nsecs_t mFrameTimeNanos;
-    nsecs_t mRecordDurationNanos;
-    float mDensity;
     std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
+
+    int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8fb1b10..3afca2f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,15 +16,19 @@
 
 #include "EglManager.h"
 
+#include "../Caches.h"
+#include "../renderstate/RenderState.h"
+#include "RenderThread.h"
+
 #include <cutils/log.h>
 #include <cutils/properties.h>
-
-#include "../RenderState.h"
-#include "RenderThread.h"
+#include <EGL/eglext.h>
 
 #define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
 #define GLES_VERSION 2
 
+#define WAIT_FOR_GPU_COMPLETION 0
+
 // Android-specific addition that is used to show when frames began in systrace
 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
 
@@ -67,12 +71,12 @@
 EglManager::EglManager(RenderThread& thread)
         : mRenderThread(thread)
         , mEglDisplay(EGL_NO_DISPLAY)
-        , mEglConfig(0)
+        , mEglConfig(nullptr)
         , mEglContext(EGL_NO_CONTEXT)
         , mPBufferSurface(EGL_NO_SURFACE)
         , mAllowPreserveBuffer(load_dirty_regions_property())
         , mCurrentSurface(EGL_NO_SURFACE)
-        , mAtlasMap(NULL)
+        , mAtlasMap(nullptr)
         , mAtlasMapSize(0)
         , mInFrame(false) {
     mCanSetPreserveBuffer = mAllowPreserveBuffer;
@@ -193,7 +197,7 @@
 
 EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
     initialize();
-    EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
+    EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
     LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
             "Failed to create EGLSurface for window %p, eglErr = %s",
             (void*) window, egl_error_str());
@@ -213,9 +217,6 @@
     if (mEglDisplay == EGL_NO_DISPLAY) return;
 
     usePBufferSurface();
-    if (Caches::hasInstance()) {
-        Caches::getInstance().terminate();
-    }
 
     mRenderThread.renderState().onGLContextDestroyed();
     eglDestroyContext(mEglDisplay, mEglContext);
@@ -262,6 +263,14 @@
 
 bool EglManager::swapBuffers(EGLSurface surface) {
     mInFrame = false;
+
+#if WAIT_FOR_GPU_COMPLETION
+    {
+        ATRACE_NAME("Finishing GPU work");
+        fence();
+    }
+#endif
+
     eglSwapBuffers(mEglDisplay, surface);
     EGLint err = eglGetError();
     if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -280,6 +289,13 @@
     return false;
 }
 
+void EglManager::fence() {
+    EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
+    eglClientWaitSyncKHR(mEglDisplay, fence,
+            EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+    eglDestroySyncKHR(mEglDisplay, fence);
+}
+
 void EglManager::cancelFrame() {
     mInFrame = false;
 }
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index e12db3a..b1a18a9 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -55,6 +55,8 @@
 
     void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
 
+    void fence();
+
 private:
     friend class RenderThread;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6d063a4..ea4216c 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,14 +16,14 @@
 
 #include "RenderProxy.h"
 
-#include "CanvasContext.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#include "../DeferredLayerUpdater.h"
-#include "../DisplayList.h"
-#include "../LayerRenderer.h"
-#include "../Rect.h"
+#include "DeferredLayerUpdater.h"
+#include "DisplayList.h"
+#include "LayerRenderer.h"
+#include "Rect.h"
+#include "renderthread/CanvasContext.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
@@ -52,6 +52,12 @@
     MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
     ARGS(method) *args = (ARGS(method) *) task->payload()
 
+enum class DumpFlags {
+        kFrameStats = 1 << 0,
+        kReset      = 1 << 1,
+};
+MAKE_FLAGS_ENUM(DumpFlags)
+
 CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
         RenderNode* rootRenderNode, IContextFactory* contextFactory) {
     return new CanvasContext(*args->thread, args->translucent,
@@ -60,7 +66,7 @@
 
 RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
         : mRenderThread(RenderThread::getInstance())
-        , mContext(0) {
+        , mContext(nullptr) {
     SETUP_TASK(createContext);
     args->translucent = translucent;
     args->rootRenderNode = rootRenderNode;
@@ -76,36 +82,24 @@
 
 CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
     delete args->context;
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::destroyContext() {
     if (mContext) {
         SETUP_TASK(destroyContext);
         args->context = mContext;
-        mContext = 0;
-        mDrawFrameTask.setContext(NULL, NULL);
+        mContext = nullptr;
+        mDrawFrameTask.setContext(nullptr, nullptr);
         // This is also a fence as we need to be certain that there are no
         // outstanding mDrawFrame tasks posted before it is destroyed
         postAndWait(task);
     }
 }
 
-CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
-    args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
-    return NULL;
-}
-
-void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
-    SETUP_TASK(setFrameInterval);
-    args->thread = &mRenderThread;
-    args->frameIntervalNanos = frameIntervalNanos;
-    post(task);
-}
-
 CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
     args->context->setSwapBehavior(args->swapBehavior);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
@@ -132,6 +126,18 @@
     return (bool) postAndWait(task);
 }
 
+CREATE_BRIDGE2(setName, CanvasContext* context, const char* name) {
+    args->context->setName(std::string(args->name));
+    return nullptr;
+}
+
+void RenderProxy::setName(const char* name) {
+    SETUP_TASK(setName);
+    args->context = mContext;
+    args->name = name;
+    post(task);
+}
+
 CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
     return (void*) args->context->initialize(args->window);
 }
@@ -145,7 +151,7 @@
 
 CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
     args->context->updateSurface(args->window);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
@@ -171,7 +177,7 @@
         uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
     args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius,
             args->ambientShadowAlpha, args->spotShadowAlpha);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
@@ -189,7 +195,7 @@
 
 CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
     args->context->setOpaque(args->opaque);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::setOpaque(bool opaque) {
@@ -199,15 +205,17 @@
     post(task);
 }
 
-int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-        float density) {
-    mDrawFrameTask.setDensity(density);
-    return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
+int64_t* RenderProxy::frameInfo() {
+    return mDrawFrameTask.frameInfo();
+}
+
+int RenderProxy::syncAndDrawFrame() {
+    return mDrawFrameTask.drawFrame();
 }
 
 CREATE_BRIDGE1(destroy, CanvasContext* context) {
     args->context->destroy();
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::destroy() {
@@ -221,7 +229,7 @@
 
 CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
     CanvasContext::invokeFunctor(*args->thread, args->functor);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
@@ -242,7 +250,7 @@
 
 CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
     args->context->runWithGlContext(args->task);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::runWithGlContext(RenderTask* gltask) {
@@ -254,7 +262,7 @@
 
 CREATE_BRIDGE2(createTextureLayer, RenderThread* thread, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
-    if (!layer) return 0;
+    if (!layer) return nullptr;
     return new DeferredLayerUpdater(*args->thread, layer);
 }
 
@@ -269,7 +277,7 @@
 
 CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
     args->context->buildLayer(args->node);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::buildLayer(RenderNode* node) {
@@ -303,7 +311,7 @@
 
 CREATE_BRIDGE1(detachSurfaceTexture, DeferredLayerUpdater* layer) {
     args->layer->detachSurfaceTexture();
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
@@ -314,7 +322,7 @@
 
 CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
     args->context->destroyHardwareResources();
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::destroyHardwareResources() {
@@ -325,7 +333,7 @@
 
 CREATE_BRIDGE2(timMemory, RenderThread* thread, int level) {
     CanvasContext::trimMemory(*args->thread, args->level);
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::trimMemory(int level) {
@@ -341,17 +349,21 @@
 
 CREATE_BRIDGE0(fence) {
     // Intentionally empty
-    return NULL;
+    return nullptr;
 }
 
+template <typename T>
+void UNUSED(T t) {}
+
 void RenderProxy::fence() {
     SETUP_TASK(fence);
+    UNUSED(args);
     postAndWait(task);
 }
 
 CREATE_BRIDGE1(stopDrawing, CanvasContext* context) {
     args->context->stopDrawing();
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::stopDrawing() {
@@ -362,7 +374,7 @@
 
 CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) {
     args->context->notifyFramePending();
-    return NULL;
+    return nullptr;
 }
 
 void RenderProxy::notifyFramePending() {
@@ -371,40 +383,58 @@
     mRenderThread.queueAtFront(task);
 }
 
-CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
+CREATE_BRIDGE3(dumpProfileInfo, CanvasContext* context, int fd, int dumpFlags) {
     args->context->profiler().dumpData(args->fd);
-    return NULL;
+    if (args->dumpFlags & DumpFlags::kFrameStats) {
+        args->context->dumpFrames(args->fd);
+    }
+    if (args->dumpFlags & DumpFlags::kReset) {
+        args->context->resetFrameStats();
+    }
+    return nullptr;
 }
 
-void RenderProxy::dumpProfileInfo(int fd) {
+void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
     SETUP_TASK(dumpProfileInfo);
     args->context = mContext;
     args->fd = fd;
+    args->dumpFlags = dumpFlags;
     postAndWait(task);
 }
 
-CREATE_BRIDGE1(outputLogBuffer, int fd) {
-    RenderNode::outputLogBuffer(args->fd);
-    return NULL;
+CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
+    args->thread->jankTracker().dump(args->fd);
+
+    FILE *file = fdopen(args->fd, "a");
+    if (Caches::hasInstance()) {
+        String8 cachesLog;
+        Caches::getInstance().dumpMemoryUsage(cachesLog);
+        fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
+    } else {
+        fprintf(file, "\nNo caches instance.\n");
+    }
+    fflush(file);
+    return nullptr;
 }
 
-void RenderProxy::outputLogBuffer(int fd) {
-    SETUP_TASK(outputLogBuffer);
+void RenderProxy::dumpGraphicsMemory(int fd) {
+    SETUP_TASK(dumpGraphicsMemory);
     args->fd = fd;
+    args->thread = &RenderThread::getInstance();
     staticPostAndWait(task);
 }
 
 CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
     CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
-    args->buffer->decStrong(0);
-    return NULL;
+    args->buffer->decStrong(nullptr);
+    return nullptr;
 }
 
 void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
     SETUP_TASK(setTextureAtlas);
     args->thread = &mRenderThread;
     args->buffer = buffer.get();
-    args->buffer->incStrong(0);
+    args->buffer->incStrong(nullptr);
     args->map = map;
     args->size = size;
     post(task);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index fd1fe05..43cbe07 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -62,10 +62,10 @@
     ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory);
     ANDROID_API virtual ~RenderProxy();
 
-    ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
     // Won't take effect until next EGLSurface creation
     ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
     ANDROID_API bool loadSystemProperties();
+    ANDROID_API void setName(const char* name);
 
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
@@ -73,8 +73,8 @@
     ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     ANDROID_API void setOpaque(bool opaque);
-    ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-            float density);
+    ANDROID_API int64_t* frameInfo();
+    ANDROID_API int syncAndDrawFrame();
     ANDROID_API void destroy();
 
     ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
@@ -95,8 +95,8 @@
     ANDROID_API void stopDrawing();
     ANDROID_API void notifyFramePending();
 
-    ANDROID_API void dumpProfileInfo(int fd);
-    ANDROID_API static void outputLogBuffer(int fd);
+    ANDROID_API void dumpProfileInfo(int fd, int dumpFlags);
+    ANDROID_API static void dumpGraphicsMemory(int fd);
 
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
 
diff --git a/libs/hwui/renderthread/RenderTask.cpp b/libs/hwui/renderthread/RenderTask.cpp
index 7ca61e4..b14f580 100644
--- a/libs/hwui/renderthread/RenderTask.cpp
+++ b/libs/hwui/renderthread/RenderTask.cpp
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "RenderTask"
-
 #include "RenderTask.h"
 
-#include <utils/Log.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index 1554a16..89c3a7d 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -47,7 +47,7 @@
 
 class ANDROID_API RenderTask {
 public:
-    ANDROID_API RenderTask() : mNext(0), mRunAt(0) {}
+    ANDROID_API RenderTask() : mNext(nullptr), mRunAt(0) {}
     ANDROID_API virtual ~RenderTask() {}
 
     ANDROID_API virtual void run() = 0;
@@ -61,7 +61,7 @@
     // Takes ownership of task, caller owns lock and signal
     SignalingRenderTask(RenderTask* task, Mutex* lock, Condition* signal)
             : mTask(task), mLock(lock), mSignal(signal) {}
-    virtual void run();
+    virtual void run() override;
 
 private:
     RenderTask* mTask;
@@ -74,12 +74,12 @@
 class MethodInvokeRenderTask : public RenderTask {
 public:
     MethodInvokeRenderTask(RunnableMethod method)
-        : mMethod(method), mReturnPtr(0) {}
+        : mMethod(method), mReturnPtr(nullptr) {}
 
     void* payload() { return mData; }
     void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
 
-    virtual void run() {
+    virtual void run() override {
         void* retval = mMethod(mData);
         if (mReturnPtr) {
             *mReturnPtr = retval;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 84826b7..3ac2976 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,17 +16,17 @@
 
 #include "RenderThread.h"
 
-#if defined(HAVE_PTHREADS)
-#include <sys/resource.h>
-#endif
-#include <gui/DisplayEventReceiver.h>
-#include <utils/Log.h>
-
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
 #include "CanvasContext.h"
 #include "EglManager.h"
 #include "RenderProxy.h"
 
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <sys/resource.h>
+#include <utils/Log.h>
+
 namespace android {
 using namespace uirenderer::renderthread;
 ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
@@ -42,16 +42,16 @@
 // Slight delay to give the UI time to push us a new frame before we replay
 static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
 
-TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
+TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
 
 RenderTask* TaskQueue::next() {
     RenderTask* ret = mHead;
     if (ret) {
         mHead = ret->mNext;
         if (!mHead) {
-            mTail = 0;
+            mTail = nullptr;
         }
-        ret->mNext = 0;
+        ret->mNext = nullptr;
     }
     return ret;
 }
@@ -71,7 +71,7 @@
             mTail = task;
         } else {
             // Need to find the proper insertion point
-            RenderTask* previous = 0;
+            RenderTask* previous = nullptr;
             RenderTask* next = mHead;
             while (next && next->mRunAt <= task->mRunAt) {
                 previous = next;
@@ -131,19 +131,19 @@
 public:
     DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
 
-    virtual void run() {
+    virtual void run() override {
         mRenderThread->dispatchFrameCallbacks();
     }
 };
 
 RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
         , mNextWakeup(LLONG_MAX)
-        , mDisplayEventReceiver(0)
+        , mDisplayEventReceiver(nullptr)
         , mVsyncRequested(false)
         , mFrameCallbackTaskPending(false)
-        , mFrameCallbackTask(0)
-        , mRenderState(NULL)
-        , mEglManager(NULL) {
+        , mFrameCallbackTask(nullptr)
+        , mRenderState(nullptr)
+        , mEglManager(nullptr) {
     mFrameCallbackTask = new DispatchFrameCallbacks(this);
     mLooper = new Looper(false);
     run("RenderThread");
@@ -166,9 +166,16 @@
 }
 
 void RenderThread::initThreadLocals() {
+    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain));
+    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
+    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
+    mTimeLord.setFrameInterval(frameIntervalNanos);
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
+    mJankTracker = new JankTracker(frameIntervalNanos);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
@@ -250,9 +257,7 @@
 }
 
 bool RenderThread::threadLoop() {
-#if defined(HAVE_PTHREADS)
     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
-#endif
     initThreadLocals();
 
     int timeoutMillis = -1;
@@ -350,7 +355,7 @@
         if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
             next = mQueue.next();
         } else {
-            next = 0;
+            next = nullptr;
         }
     }
     if (nextWakeup) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 99c2e15..8096099 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,16 +19,18 @@
 
 #include "RenderTask.h"
 
-#include <memory>
-#include <set>
+#include "../JankTracker.h"
+#include "TimeLord.h"
 
 #include <cutils/compiler.h>
+#include <ui/DisplayInfo.h>
 #include <utils/Looper.h>
 #include <utils/Mutex.h>
 #include <utils/Singleton.h>
 #include <utils/Thread.h>
 
-#include "TimeLord.h"
+#include <memory>
+#include <set>
 
 namespace android {
 
@@ -88,9 +90,12 @@
     TimeLord& timeLord() { return mTimeLord; }
     RenderState& renderState() { return *mRenderState; }
     EglManager& eglManager() { return *mEglManager; }
+    JankTracker& jankTracker() { return *mJankTracker; }
+
+    const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
 
 protected:
-    virtual bool threadLoop();
+    virtual bool threadLoop() override;
 
 private:
     friend class Singleton<RenderThread>;
@@ -118,6 +123,8 @@
     nsecs_t mNextWakeup;
     TaskQueue mQueue;
 
+    DisplayInfo mDisplayInfo;
+
     DisplayEventReceiver* mDisplayEventReceiver;
     bool mVsyncRequested;
     std::set<IFrameCallback*> mFrameCallbacks;
@@ -132,6 +139,8 @@
     TimeLord mTimeLord;
     RenderState* mRenderState;
     EglManager* mEglManager;
+
+    JankTracker* mJankTracker = nullptr;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index f187493..f846d6a 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -32,7 +32,7 @@
     return false;
 }
 
-nsecs_t TimeLord::computeFrameTimeMs() {
+nsecs_t TimeLord::computeFrameTimeNanos() {
     // Logic copied from Choreographer.java
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
     nsecs_t jitterNanos = now - mFrameTimeNanos;
@@ -40,7 +40,11 @@
         nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
         mFrameTimeNanos = now - lastFrameOffset;
     }
-    return nanoseconds_to_milliseconds(mFrameTimeNanos);
+    return mFrameTimeNanos;
+}
+
+nsecs_t TimeLord::computeFrameTimeMs() {
+    return nanoseconds_to_milliseconds(computeFrameTimeNanos());
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 7c155d2..5464399 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -29,9 +29,13 @@
 class TimeLord {
 public:
     void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+    nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
+
     // returns true if the vsync is newer, false if it was rejected for staleness
     bool vsyncReceived(nsecs_t vsync);
+    nsecs_t latestVsync() { return mFrameTimeNanos; }
     nsecs_t computeFrameTimeMs();
+    nsecs_t computeFrameTimeNanos();
 
 private:
     friend class RenderThread;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index 7bdce7f..51898d2 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -15,34 +15,9 @@
 #
 
 local_target_dir := $(TARGET_OUT_DATA)/local/tmp
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH:= $(call my-dir)/..
 include $(CLEAR_VARS)
 
-LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
-
-LOCAL_SRC_FILES:= \
-	TestContext.cpp \
-	main.cpp
-
-LOCAL_C_INCLUDES += \
-	$(LOCAL_PATH)/.. \
-	external/skia/src/core
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcutils \
-	libutils \
-	libskia \
-	libgui \
-	libui \
-	libhwui
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
-	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
 LOCAL_MODULE_PATH := $(local_target_dir)
 LOCAL_MODULE:= hwuitest
 LOCAL_MODULE_TAGS := tests
@@ -50,7 +25,25 @@
 LOCAL_MODULE_STEM_32 := hwuitest
 LOCAL_MODULE_STEM_64 := hwuitest64
 
-include external/stlport/libstlport.mk
+HWUI_NULL_GPU := false
+
+include $(LOCAL_PATH)/Android.common.mk
+
+LOCAL_SRC_FILES += \
+	tests/TestContext.cpp \
+	tests/main.cpp
+
 include $(BUILD_EXECUTABLE)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.common.mk
+LOCAL_MODULE := hwui_unit_tests
+LOCAL_MODULE_TAGS := tests
+
+include $(LOCAL_PATH)/Android.common.mk
+
+LOCAL_SRC_FILES += \
+	tests/ClipAreaTests.cpp \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/hwui/tests/ClipAreaTests.cpp b/libs/hwui/tests/ClipAreaTests.cpp
new file mode 100644
index 0000000..166d5b6
--- /dev/null
+++ b/libs/hwui/tests/ClipAreaTests.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+
+#include "ClipArea.h"
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/LinearAllocator.h"
+
+namespace android {
+namespace uirenderer {
+
+static Rect kViewportBounds(0, 0, 2048, 2048);
+
+static ClipArea createClipArea() {
+    ClipArea area;
+    area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight());
+    return area;
+}
+
+TEST(TransformedRectangle, basics) {
+    Rect r(0, 0, 100, 100);
+    Matrix4 minus90;
+    minus90.loadRotate(-90);
+    minus90.mapRect(r);
+    Rect r2(20, 40, 120, 60);
+
+    Matrix4 m90;
+    m90.loadRotate(90);
+    TransformedRectangle tr(r, m90);
+    EXPECT_TRUE(tr.canSimplyIntersectWith(tr));
+
+    Matrix4 m0;
+    TransformedRectangle tr0(r2, m0);
+    EXPECT_FALSE(tr.canSimplyIntersectWith(tr0));
+
+    Matrix4 m45;
+    m45.loadRotate(45);
+    TransformedRectangle tr2(r, m45);
+    EXPECT_FALSE(tr2.canSimplyIntersectWith(tr));
+}
+
+TEST(RectangleList, basics) {
+    RectangleList list;
+    EXPECT_TRUE(list.isEmpty());
+
+    Rect r(0, 0, 100, 100);
+    Matrix4 m45;
+    m45.loadRotate(45);
+    list.set(r, m45);
+    EXPECT_FALSE(list.isEmpty());
+
+    Rect r2(20, 20, 200, 200);
+    list.intersectWith(r2, m45);
+    EXPECT_FALSE(list.isEmpty());
+    EXPECT_EQ(1, list.getTransformedRectanglesCount());
+
+    Rect r3(20, 20, 200, 200);
+    Matrix4 m30;
+    m30.loadRotate(30);
+    list.intersectWith(r2, m30);
+    EXPECT_FALSE(list.isEmpty());
+    EXPECT_EQ(2, list.getTransformedRectanglesCount());
+
+    SkRegion clip;
+    clip.setRect(0, 0, 2000, 2000);
+    SkRegion rgn(list.convertToRegion(clip));
+    EXPECT_FALSE(rgn.isEmpty());
+}
+
+TEST(ClipArea, basics) {
+    ClipArea area(createClipArea());
+    EXPECT_FALSE(area.isEmpty());
+}
+
+TEST(ClipArea, paths) {
+    ClipArea area(createClipArea());
+    Matrix4 transform;
+    transform.loadIdentity();
+    SkPath path;
+    SkScalar r = 100;
+    path.addCircle(r, r, r);
+    area.clipPathWithTransform(path, &transform, SkRegion::kIntersect_Op);
+    EXPECT_FALSE(area.isEmpty());
+    EXPECT_FALSE(area.isSimple());
+    EXPECT_FALSE(area.isRectangleList());
+    Rect clipRect(area.getClipRect());
+    clipRect.dump("clipRect");
+    Rect expected(0, 0, r * 2, r * 2);
+    expected.dump("expected");
+    EXPECT_EQ(expected, clipRect);
+    SkRegion clipRegion(area.getClipRegion());
+    auto skRect(clipRegion.getBounds());
+    Rect regionBounds;
+    regionBounds.set(skRect);
+    EXPECT_EQ(expected, regionBounds);
+}
+}
+}
diff --git a/libs/hwui/tests/TestContext.cpp b/libs/hwui/tests/TestContext.cpp
index 35e402d..542bbae 100644
--- a/libs/hwui/tests/TestContext.cpp
+++ b/libs/hwui/tests/TestContext.cpp
@@ -16,30 +16,59 @@
 
 #include "TestContext.h"
 
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
+namespace android {
+namespace uirenderer {
+namespace test {
 
-using namespace android;
+static const int IDENT_DISPLAYEVENT = 1;
 
-DisplayInfo gDisplay;
-sp<SurfaceComposerClient> gSession;
-
-void createTestEnvironment() {
-    gSession = new SurfaceComposerClient();
+static DisplayInfo getBuiltInDisplay() {
+    DisplayInfo display;
     sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
-    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &gDisplay);
+            ISurfaceComposer::eDisplayIdMain));
+    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &display);
     LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+    return display;
 }
 
-sp<SurfaceControl> createWindow(int width, int height) {
-    sp<SurfaceControl> control = gSession->createSurface(String8("HwuiTest"),
-            width, height, PIXEL_FORMAT_RGBX_8888);
+android::DisplayInfo gDisplay = getBuiltInDisplay();
 
-    SurfaceComposerClient::openGlobalTransaction();
-    control->setLayer(0x7FFFFFF);
-    control->show();
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    return control;
+TestContext::TestContext() {
+    mLooper = new Looper(true);
+    mSurfaceComposerClient = new SurfaceComposerClient();
+    mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT,
+            Looper::EVENT_INPUT, nullptr, nullptr);
 }
+
+TestContext::~TestContext() {}
+
+sp<Surface> TestContext::surface() {
+    if (!mSurfaceControl.get()) {
+        mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
+                gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
+
+        SurfaceComposerClient::openGlobalTransaction();
+        mSurfaceControl->setLayer(0x7FFFFFF);
+        mSurfaceControl->show();
+        SurfaceComposerClient::closeGlobalTransaction();
+    }
+
+    return mSurfaceControl->getSurface();
+}
+
+void TestContext::waitForVsync() {
+    // Request vsync
+    mDisplayEventReceiver.requestNextVsync();
+
+    // Wait
+    mLooper->pollOnce(-1);
+
+    // Drain it
+    DisplayEventReceiver::Event buf[100];
+    while (mDisplayEventReceiver.getEvents(buf, 100) > 0) { }
+}
+
+} // namespace test
+} // namespace uirenderer
+} // namespace android
+
diff --git a/libs/hwui/tests/TestContext.h b/libs/hwui/tests/TestContext.h
index 8a5d530..7b30fc1 100644
--- a/libs/hwui/tests/TestContext.h
+++ b/libs/hwui/tests/TestContext.h
@@ -17,17 +17,39 @@
 #ifndef TESTCONTEXT_H
 #define TESTCONTEXT_H
 
-#include <ui/DisplayInfo.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
 #include <gui/SurfaceControl.h>
+#include <gui/Surface.h>
+#include <ui/DisplayInfo.h>
+#include <utils/Looper.h>
 
-extern android::DisplayInfo gDisplay;
-#define dp(x) ((x) * gDisplay.density)
+namespace android {
+namespace uirenderer {
+namespace test {
 
-// Initializes all the static globals that are shared across all contexts
-// such as display info
-void createTestEnvironment();
+extern DisplayInfo gDisplay;
+#define dp(x) ((x) * android::uirenderer::test::gDisplay.density)
 
-// Defaults to fullscreen
-android::sp<android::SurfaceControl> createWindow(int width = -1, int height = -1);
+class TestContext {
+public:
+    TestContext();
+    ~TestContext();
+
+    sp<Surface> surface();
+
+    void waitForVsync();
+
+private:
+    sp<SurfaceComposerClient> mSurfaceComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+    DisplayEventReceiver mDisplayEventReceiver;
+    sp<Looper> mLooper;
+};
+
+} // namespace test
+} // namespace uirenderer
+} // namespace android
 
 #endif
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index 2d99e9f..805989b 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -24,24 +24,27 @@
 #include <DisplayListRenderer.h>
 #include <RenderNode.h>
 #include <renderthread/RenderProxy.h>
+#include <renderthread/RenderTask.h>
 
 #include "TestContext.h"
 
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::renderthread;
+using namespace android::uirenderer::test;
 
 class ContextFactory : public IContextFactory {
 public:
-    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
+    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
         return new AnimationContext(clock);
     }
 };
 
 static DisplayListRenderer* startRecording(RenderNode* node) {
     DisplayListRenderer* renderer = new DisplayListRenderer();
-    renderer->setViewport(node->getWidth(), node->getHeight());
-    renderer->prepare(false);
+    renderer->setViewport(node->stagingProperties().getWidth(),
+            node->stagingProperties().getHeight());
+    renderer->prepare();
     return renderer;
 }
 
@@ -51,81 +54,210 @@
     delete renderer;
 }
 
-sp<RenderNode> createCard(int x, int y, int width, int height) {
-    sp<RenderNode> node = new RenderNode();
-    node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
-    node->mutateStagingProperties().setElevation(dp(16));
-    node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
-    node->mutateStagingProperties().mutableOutline().setShouldClip(true);
-    node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+class TreeContentAnimation {
+public:
+    virtual ~TreeContentAnimation() {}
+    virtual int getFrameCount() { return 150; }
+    virtual void createContent(int width, int height, DisplayListRenderer* renderer) = 0;
+    virtual void doFrame(int frameNr) = 0;
 
-    DisplayListRenderer* renderer = startRecording(node.get());
-    renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
-    endRecording(renderer, node.get());
+    template <class T>
+    static void run() {
+        T animation;
 
-    return node;
-}
+        TestContext testContext;
 
-int main(int argc, char* argv[]) {
-    createTestEnvironment();
+        // create the native surface
+        const int width = gDisplay.w;
+        const int height = gDisplay.h;
+        sp<Surface> surface = testContext.surface();
 
-    // create the native surface
-    const int width = gDisplay.w;
-    const int height = gDisplay.h;
-    sp<SurfaceControl> control = createWindow(width, height);
-    sp<Surface> surface = control->getSurface();
+        RenderNode* rootNode = new RenderNode();
+        rootNode->incStrong(nullptr);
+        rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
+        rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        rootNode->mutateStagingProperties().setClipToBounds(false);
+        rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 
-    RenderNode* rootNode = new RenderNode();
-    rootNode->incStrong(0);
-    rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
-    rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-    rootNode->mutateStagingProperties().setClipToBounds(false);
-    rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+        ContextFactory factory;
+        std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
+        proxy->loadSystemProperties();
+        proxy->initialize(surface);
+        float lightX = width / 2.0;
+        proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
+                dp(800.0f), 255 * 0.075, 255 * 0.15);
 
-    ContextFactory factory;
-    RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
-    proxy->loadSystemProperties();
-    proxy->initialize(surface);
-    float lightX = width / 2.0;
-    proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
-            dp(800.0f), 255 * 0.075, 255 * 0.15);
+        android::uirenderer::Rect DUMMY;
 
-    android::uirenderer::Rect DUMMY;
+        DisplayListRenderer* renderer = startRecording(rootNode);
+        animation.createContent(width, height, renderer);
+        endRecording(renderer, rootNode);
 
-    std::vector< sp<RenderNode> > cards;
+        for (int i = 0; i < animation.getFrameCount(); i++) {
+#if !HWUI_NULL_GPU
+            testContext.waitForVsync();
+#endif
 
-    DisplayListRenderer* renderer = startRecording(rootNode);
-    renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-    renderer->insertReorderBarrier(true);
-
-    for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
-        for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
-            sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
-            renderer->drawRenderNode(card.get(), DUMMY, 0);
-            cards.push_back(card);
+            ATRACE_NAME("UI-Draw Frame");
+            animation.doFrame(i);
+            proxy->syncAndDrawFrame();
         }
+
+        rootNode->decStrong(nullptr);
     }
+};
 
-    renderer->insertReorderBarrier(false);
-    endRecording(renderer, rootNode);
+class ShadowGridAnimation : public TreeContentAnimation {
+public:
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
 
-    for (int i = 0; i < 150; i++) {
-        ATRACE_NAME("UI-Draw Frame");
-        for (int ci = 0; ci < cards.size(); ci++) {
-            cards[ci]->mutateStagingProperties().setTranslationX(i);
-            cards[ci]->mutateStagingProperties().setTranslationY(i);
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
+
+        for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
+            for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
+                sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
+                renderer->drawRenderNode(card.get(), DUMMY, 0);
+                cards.push_back(card);
+            }
+        }
+
+        renderer->insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        for (size_t ci = 0; ci < cards.size(); ci++) {
+            cards[ci]->mutateStagingProperties().setTranslationX(frameNr);
+            cards[ci]->mutateStagingProperties().setTranslationY(frameNr);
             cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
         }
-        nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-        proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
-        usleep(12000);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->mutateStagingProperties().setElevation(dp(16));
+        node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+        node->mutateStagingProperties().mutableOutline().setShouldClip(true);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+
+        DisplayListRenderer* renderer = startRecording(node.get());
+        renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+class RectGridAnimation : public TreeContentAnimation {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
+
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
+
+        card = createCard(40, 40, 200, 200);
+        renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+        renderer->insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        card->mutateStagingProperties().setTranslationX(frameNr);
+        card->mutateStagingProperties().setTranslationY(frameNr);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+        DisplayListRenderer* renderer = startRecording(node.get());
+        renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
+
+        float rects[width * height];
+        int index = 0;
+        for (int xOffset = 0; xOffset < width; xOffset+=2) {
+            for (int yOffset = 0; yOffset < height; yOffset+=2) {
+                rects[index++] = xOffset;
+                rects[index++] = yOffset;
+                rects[index++] = xOffset + 1;
+                rects[index++] = yOffset + 1;
+            }
+        }
+        int count = width * height;
+
+        SkPaint paint;
+        paint.setColor(0xff00ffff);
+        renderer->drawRects(rects, count, &paint);
+
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+class OvalAnimation : public TreeContentAnimation {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, DisplayListRenderer* renderer) override {
+        android::uirenderer::Rect DUMMY;
+
+        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        renderer->insertReorderBarrier(true);
+
+        card = createCard(40, 40, 400, 400);
+        renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+        renderer->insertReorderBarrier(false);
     }
 
-    sleep(5);
+    void doFrame(int frameNr) override {
+        card->mutateStagingProperties().setTranslationX(frameNr);
+        card->mutateStagingProperties().setTranslationY(frameNr);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+private:
+    sp<RenderNode> createCard(int x, int y, int width, int height) {
+        sp<RenderNode> node = new RenderNode();
+        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-    delete proxy;
-    rootNode->decStrong(0);
+        DisplayListRenderer* renderer = startRecording(node.get());
 
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setColor(0xFF000000);
+        renderer->drawOval(0, 0, width, height, paint);
+
+        endRecording(renderer, node.get());
+        return node;
+    }
+};
+
+struct cstr_cmp {
+    bool operator()(const char *a, const char *b) const {
+        return std::strcmp(a, b) < 0;
+    }
+};
+
+typedef void (*testProc)();
+
+std::map<const char*, testProc, cstr_cmp> gTestMap {
+    {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
+    {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
+    {"oval", TreeContentAnimation::run<OvalAnimation> },
+};
+
+int main(int argc, char* argv[]) {
+    const char* testName = argc > 1 ? argv[1] : "shadowgrid";
+    testProc proc = gTestMap[testName];
+    if(!proc) {
+        printf("Error: couldn't find test %s\n", testName);
+        return 1;
+    }
+    proc();
     printf("Success!\n");
     return 0;
 }
diff --git a/libs/hwui/tests/nullegl.cpp b/libs/hwui/tests/nullegl.cpp
new file mode 100644
index 0000000..b6cc2f2
--- /dev/null
+++ b/libs/hwui/tests/nullegl.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static EGLDisplay gDisplay = (EGLDisplay) 1;
+
+typedef struct {
+    EGLSurface surface;
+    EGLContext context;
+} ThreadState;
+
+static pthread_key_t ThreadStateKey;
+static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;
+
+static void destroyThreadState(void* state) {
+    free(state);
+}
+
+static void makeThreadState() {
+    pthread_key_create(&ThreadStateKey, destroyThreadState);
+}
+
+ThreadState* getThreadState() {
+    ThreadState* ptr;
+    pthread_once(&ThreadStateSetupOnce, makeThreadState);
+    if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
+        ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+        ptr->context = EGL_NO_CONTEXT;
+        ptr->surface = EGL_NO_SURFACE;
+        pthread_setspecific(ThreadStateKey, ptr);
+    }
+    return ptr;
+}
+
+EGLint eglGetError(void) {
+    return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+    return gDisplay;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+    return EGL_TRUE;
+}
+
+const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+    return "";
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+               EGLConfig *configs, EGLint config_size,
+               EGLint *num_config) {
+    memset(configs, 9, sizeof(EGLConfig) * config_size);
+    *num_config = config_size;
+    return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+                  EGLNativeWindowType win,
+                  const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+                   const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+    free(surface);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+               EGLint attribute, EGLint *value) {
+    *value = 1000;
+    return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+                EGLint attribute, EGLint value) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+    return EGL_TRUE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                EGLContext share_context,
+                const EGLint *attrib_list) {
+    return (EGLContext) malloc(sizeof(void*));
+}
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+    free(ctx);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+              EGLSurface read, EGLContext ctx) {
+    ThreadState* state = getThreadState();
+    state->surface = draw;
+    state->context = ctx;
+    return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext(void) {
+    return getThreadState()->context;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+    return getThreadState()->surface;
+}
+
+EGLDisplay eglGetCurrentDisplay(void) {
+    return gDisplay;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+    return EGL_TRUE;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
+    return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
+    free(image);
+    return EGL_TRUE;
+}
+
+void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}
diff --git a/libs/hwui/tests/nullgles.cpp b/libs/hwui/tests/nullgles.cpp
new file mode 100644
index 0000000..8ca7598
--- /dev/null
+++ b/libs/hwui/tests/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright(C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+    GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+    static GLuint nextId = 0;
+    int i;
+    for(i = 0; i < n; i++) {
+        buffers[i] = ++nextId;
+    }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+    glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+    glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+    glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+    static GLuint nextProgram = 0;
+    return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+    static GLuint nextShader = 0;
+    return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_DELETE_STATUS:
+    case GL_LINK_STATUS:
+    case GL_VALIDATE_STATUS:
+        *params = GL_TRUE;
+        break;
+    case GL_INFO_LOG_LENGTH:
+        *params = 16;
+        break;
+    }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_COMPILE_STATUS:
+    case GL_DELETE_STATUS:
+        *params = GL_TRUE;
+    }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        gState.scissorEnabled = value;
+        break;
+    }
+}
+
+void glEnable(GLenum cap) {
+    setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+    setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        return gState.scissorEnabled;
+    default:
+        return GL_FALSE;
+    }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+    switch (pname) {
+    case GL_MAX_TEXTURE_SIZE:
+        *data = 2048;
+        break;
+    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *data = 4;
+        break;
+    default:
+        *data = 0;
+    }
+}
+
+const char* getString(GLenum name) {
+    switch (name) {
+    case GL_VENDOR:
+        return "android";
+    case GL_RENDERER:
+        return "null";
+    case GL_VERSION:
+        return "OpenGL ES 2.0 rev1";
+    case GL_SHADING_LANGUAGE_VERSION:
+        return "OpenGL ES GLSL ES 2.0 rev1";
+    case GL_EXTENSIONS:
+    default:
+        return "";
+    }
+}
+
+const GLubyte* glGetString(GLenum name) {
+    return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {}
+void glEndTilingQCOM(GLbitfield preserveMask) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+    return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+    return GL_FALSE;
+}
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index cb5401c..c69b2fd 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-#include <sys/sysinfo.h>
-#if defined(HAVE_PTHREADS)
 #include <sys/resource.h>
-#endif
+#include <sys/sysinfo.h>
 
 #include "TaskManager.h"
 #include "Task.h"
@@ -83,9 +81,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 status_t TaskManager::WorkerThread::readyToRun() {
-#if defined(HAVE_PTHREADS)
     setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
-#endif
     return NO_ERROR;
 }
 
@@ -109,6 +105,8 @@
 bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
     if (!isRunning()) {
         run(mName.string(), PRIORITY_DEFAULT);
+    } else if (exitPending()) {
+        return false;
     }
 
     Mutex::Autolock l(mLock);
@@ -124,10 +122,6 @@
 }
 
 void TaskManager::WorkerThread::exit() {
-    {
-        Mutex::Autolock l(mLock);
-        mTasks.clear();
-    }
     requestExit();
     mSignal.signal();
 }
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index 5a933ab..10e8b9e 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -84,8 +84,8 @@
         void exit();
 
     private:
-        virtual status_t readyToRun();
-        virtual bool threadLoop();
+        virtual status_t readyToRun() override;
+        virtual bool threadLoop() override;
 
         // Lock for the list of tasks
         mutable Mutex mLock;
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
index d1269f0..ec6519c 100644
--- a/libs/hwui/thread/TaskProcessor.h
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -30,9 +30,6 @@
     TaskProcessorBase() { }
     virtual ~TaskProcessorBase() { };
 
-private:
-    friend class TaskManager;
-
     virtual void process(const sp<TaskBase>& task) = 0;
 };
 
@@ -44,16 +41,15 @@
 
     bool add(const sp<Task<T> >& task);
 
-    virtual void onProcess(const sp<Task<T> >& task) = 0;
-
-private:
-    virtual void process(const sp<TaskBase>& task) {
+    virtual void process(const sp<TaskBase>& task) override {
         sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
         // This is the right way to do it but sp<> doesn't play nice
         // sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
         onProcess(realTask);
     }
 
+    virtual void onProcess(const sp<Task<T> >& task) = 0;
+
     TaskManager* mManager;
 };
 
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 5b7c87c..9f7ac1c 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -16,10 +16,12 @@
 #ifndef MACROS_H
 #define MACROS_H
 
+#include <type_traits>
+
 #define PREVENT_COPY_AND_ASSIGN(Type) \
     private: \
-        Type(const Type&); \
-        void operator=(const Type&)
+        Type(const Type&) = delete; \
+        void operator=(const Type&) = delete
 
 #define DESCRIPTION_TYPE(Type) \
         int compare(const Type& rhs) const { return memcmp(this, &rhs, sizeof(Type));} \
@@ -29,4 +31,34 @@
         friend inline int compare_type(const Type& lhs, const Type& rhs) { return lhs.compare(rhs); } \
         friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
 
+#define REQUIRE_COMPATIBLE_LAYOUT(Type) \
+        static_assert(std::is_standard_layout<Type>::value, \
+        #Type " must have standard layout")
+
+#define MAKE_FLAGS_ENUM(enumType) \
+        inline int operator|=(int lhs, enumType rhs) { \
+            return lhs | static_cast<int>(rhs); \
+        } \
+        inline int operator|(int lhs, enumType rhs) { \
+            return lhs | static_cast<int>(rhs); \
+        } \
+        inline int operator|(enumType lhs, int rhs) { \
+            return static_cast<int>(lhs) | rhs; \
+        } \
+        inline int operator|(enumType lhs, enumType rhs) { \
+            return static_cast<int>(lhs) | static_cast<int>(rhs); \
+        } \
+        inline int operator&=(int lhs, enumType rhs) { \
+            return lhs & static_cast<int>(rhs); \
+        } \
+        inline int operator&(int lhs, enumType rhs) { \
+            return lhs & static_cast<int>(rhs); \
+        } \
+        inline int operator&(enumType lhs, int rhs) { \
+            return static_cast<int>(lhs) & rhs; \
+        } \
+        inline int operator&(enumType lhs, enumType rhs) { \
+            return static_cast<int>(lhs) & static_cast<int>(rhs); \
+        }
+
 #endif /* MACROS_H */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
new file mode 100644
index 0000000..1a5cbf8
--- /dev/null
+++ b/libs/hwui/utils/PaintUtils.h
@@ -0,0 +1,81 @@
+/*
+ * 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 PAINT_UTILS_H
+#define PAINT_UTILS_H
+
+#include <SkColorFilter.h>
+#include <SkXfermode.h>
+
+namespace android {
+namespace uirenderer {
+
+class PaintUtils {
+public:
+
+   /**
+     * Safely retrieves the mode from the specified xfermode. If the specified
+     * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
+     */
+    static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
+        SkXfermode::Mode resultMode;
+        if (!SkXfermode::AsMode(mode, &resultMode)) {
+            resultMode = SkXfermode::kSrcOver_Mode;
+        }
+        return resultMode;
+    }
+
+    static inline GLenum getFilter(const SkPaint* paint) {
+        if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
+            return GL_LINEAR;
+        }
+        return GL_NEAREST;
+    }
+
+    // TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
+    static inline bool paintWillNotDraw(const SkPaint& paint) {
+        return paint.getAlpha() == 0
+                && !paint.getColorFilter()
+                && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
+    }
+
+    // TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
+    static inline bool paintWillNotDrawText(const SkPaint& paint) {
+        return paint.getAlpha() == 0
+                && paint.getLooper() == nullptr
+                && !paint.getColorFilter()
+                && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
+    }
+
+    static bool isBlendedShader(const SkShader* shader) {
+        if (shader == nullptr) {
+            return false;
+        }
+        return !shader->isOpaque();
+    }
+
+    static bool isBlendedColorFilter(const SkColorFilter* filter) {
+        if (filter == nullptr) {
+            return false;
+        }
+        return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
+    }
+
+}; // class PaintUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* PAINT_UTILS_H */
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
index 172606a..0db3aa3 100644
--- a/libs/hwui/utils/Pair.h
+++ b/libs/hwui/utils/Pair.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HWUI_PAIR_H
 #define ANDROID_HWUI_PAIR_H
 
+#include <utils/TypeHelpers.h>
+
 namespace android {
 namespace uirenderer {
 
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
new file mode 100644
index 0000000..fc9aec0
--- /dev/null
+++ b/libs/hwui/utils/RingBuffer.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+
+namespace android {
+namespace uirenderer {
+
+template<class T, size_t SIZE>
+class RingBuffer {
+    PREVENT_COPY_AND_ASSIGN(RingBuffer);
+
+public:
+    RingBuffer() {}
+    ~RingBuffer() {}
+
+    size_t capacity() { return SIZE; }
+    size_t size() { return mCount; }
+
+    T& next() {
+        mHead = (mHead + 1) % SIZE;
+        if (mCount < SIZE) {
+            mCount++;
+        }
+        return mBuffer[mHead];
+    }
+
+    T& front() {
+        return this[0];
+    }
+
+    T& back() {
+        return this[size() - 1];
+    }
+
+    T& operator[](size_t index) {
+        return mBuffer[(mHead + index + 1) % mCount];
+    }
+
+    void clear() {
+        mCount = 0;
+        mHead = -1;
+    }
+
+private:
+    T mBuffer[SIZE];
+    int mHead = -1;
+    size_t mCount = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif /* RINGBUFFER_H_ */
diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h
index 2fa890a..a2c8c52 100644
--- a/libs/hwui/utils/SortedList.h
+++ b/libs/hwui/utils/SortedList.h
@@ -93,13 +93,13 @@
     }
 
 protected:
-    virtual void do_construct(void* storage, size_t num) const;
-    virtual void do_destroy(void* storage, size_t num) const;
-    virtual void do_copy(void* dest, const void* from, size_t num) const;
-    virtual void do_splat(void* dest, const void* item, size_t num) const;
-    virtual void do_move_forward(void* dest, const void* from, size_t num) const;
-    virtual void do_move_backward(void* dest, const void* from, size_t num) const;
-    virtual int do_compare(const void* lhs, const void* rhs) const;
+    virtual void do_construct(void* storage, size_t num) const override;
+    virtual void do_destroy(void* storage, size_t num) const override;
+    virtual void do_copy(void* dest, const void* from, size_t num) const override;
+    virtual void do_splat(void* dest, const void* item, size_t num) const override;
+    virtual void do_move_forward(void* dest, const void* from, size_t num) const override;
+    virtual void do_move_backward(void* dest, const void* from, size_t num) const override;
+    virtual int do_compare(const void* lhs, const void* rhs) const override;
 }; // class SortedList
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h
index dc385b5..b101826 100644
--- a/libs/hwui/utils/SortedListImpl.h
+++ b/libs/hwui/utils/SortedListImpl.h
@@ -41,7 +41,7 @@
     virtual int do_compare(const void* lhs, const void* rhs) const = 0;
 
 private:
-    ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+    ssize_t _indexOrderOf(const void* item, size_t* order = nullptr) const;
 
     // these are made private, because they can't be used on a SortedVector
     // (they don't have an implementation either)
diff --git a/libs/hwui/utils/Timing.h b/libs/hwui/utils/Timing.h
index eced987..dd8847a 100644
--- a/libs/hwui/utils/Timing.h
+++ b/libs/hwui/utils/Timing.h
@@ -24,12 +24,12 @@
 public:
     MethodTimer(const char* name)
             : mMethodName(name) {
-        gettimeofday(&mStart, NULL);
+        gettimeofday(&mStart, nullptr);
     }
 
     ~MethodTimer() {
         struct timeval stop;
-        gettimeofday(&stop, NULL);
+        gettimeofday(&stop, nullptr);
         long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
                 + (stop.tv_usec - mStart.tv_usec);
         ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index a7fb0e2..2bbfdcc 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -27,14 +27,14 @@
     libskia \
     libgui \
     libui \
-	libinput \
-	libinputflinger
+    libinput \
+    libinputflinger
 
 LOCAL_C_INCLUDES := \
     frameworks/native/services
 
 
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 LOCAL_MODULE:= libinputservice
 
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 9af521b..1152737 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -25,11 +25,14 @@
 
 #include <cutils/log.h>
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkColor.h>
 #include <SkPaint.h>
 #include <SkXfermode.h>
+#pragma GCC diagnostic pop
 
 namespace android {
 
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index 5391393..0bc832a 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -24,11 +24,15 @@
 #include <utils/String8.h>
 #include <gui/Surface.h>
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkColor.h>
 #include <SkPaint.h>
 #include <SkXfermode.h>
+#pragma GCC diagnostic pop
+
 #include <android/native_window.h>
 
 namespace android {
diff --git a/libs/storage/Android.mk b/libs/storage/Android.mk
index 7a9dd6c..fae2bf7 100644
--- a/libs/storage/Android.mk
+++ b/libs/storage/Android.mk
@@ -9,4 +9,6 @@
 
 LOCAL_MODULE:= libstorage
 
+LOCAL_CFLAGS += -Wall -Werror
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index 621de18..c643ed0 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -64,7 +64,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
-        data.writeStrongBinder(listener->asBinder());
+        data.writeStrongBinder(IInterface::asBinder(listener));
         if (remote()->transact(TRANSACTION_registerListener, data, &reply) != NO_ERROR) {
             ALOGD("registerListener could not contact remote\n");
             return;
@@ -80,7 +80,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
-        data.writeStrongBinder(listener->asBinder());
+        data.writeStrongBinder(IInterface::asBinder(listener));
         if (remote()->transact(TRANSACTION_unregisterListener, data, &reply) != NO_ERROR) {
             ALOGD("unregisterListener could not contact remote\n");
             return;
@@ -207,12 +207,19 @@
             ALOGD("getStorageUsers caught exception %d\n", err);
             return err;
         }
-        const int32_t numUsers = reply.readInt32();
+        int32_t numUsersI = reply.readInt32();
+        uint32_t numUsers;
+        if (numUsersI < 0) {
+            ALOGW("Number of users is negative: %d\n", numUsersI);
+            numUsers = 0;
+        } else {
+            numUsers = static_cast<uint32_t>(numUsersI);
+        }
         *users = (int32_t*)malloc(sizeof(int32_t)*numUsers);
-        for (int i = 0; i < numUsers; i++) {
+        for (size_t i = 0; i < numUsers; i++) {
             **users++ = reply.readInt32();
         }
-        return numUsers;
+        return static_cast<int32_t>(numUsers);
     }
 
     int32_t getVolumeState(const String16& mountPoint)
@@ -406,7 +413,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
-        data.writeStrongBinder(observer->asBinder());
+        data.writeStrongBinder(IInterface::asBinder(observer));
         if (remote()->transact(TRANSACTION_shutdown, data, &reply) != NO_ERROR) {
             ALOGD("shutdown could not contact remote\n");
             return;
@@ -443,7 +450,7 @@
         data.writeString16(rawPath);
         data.writeString16(canonicalPath);
         data.writeString16(key);
-        data.writeStrongBinder(token->asBinder());
+        data.writeStrongBinder(IInterface::asBinder(token));
         data.writeInt32(nonce);
         if (remote()->transact(TRANSACTION_mountObb, data, &reply) != NO_ERROR) {
             ALOGD("mountObb could not contact remote\n");
@@ -463,7 +470,7 @@
         data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
         data.writeString16(filename);
         data.writeInt32(force ? 1 : 0);
-        data.writeStrongBinder(token->asBinder());
+        data.writeStrongBinder(IInterface::asBinder(token));
         data.writeInt32(nonce);
         if (remote()->transact(TRANSACTION_unmountObb, data, &reply) != NO_ERROR) {
             ALOGD("unmountObb could not contact remote\n");
@@ -546,8 +553,8 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MountService, "IMountService");
+IMPLEMENT_META_INTERFACE(MountService, "IMountService")
 
 // ----------------------------------------------------------------------
 
-};
+}
diff --git a/libs/storage/IMountServiceListener.cpp b/libs/storage/IMountServiceListener.cpp
index c98a424..11b53fd 100644
--- a/libs/storage/IMountServiceListener.cpp
+++ b/libs/storage/IMountServiceListener.cpp
@@ -34,7 +34,7 @@
             onUsbMassStorageConnectionChanged(connected);
             reply->writeNoException();
             return NO_ERROR;
-        } break;
+        }
         case TRANSACTION_onStorageStateChanged: {
             CHECK_INTERFACE(IMountServiceListener, data, reply);
             String16 path = data.readString16();
@@ -50,4 +50,4 @@
 }
 // ----------------------------------------------------------------------
 
-};
+}
diff --git a/libs/storage/IMountShutdownObserver.cpp b/libs/storage/IMountShutdownObserver.cpp
index 1a6fdee..a74a768 100644
--- a/libs/storage/IMountShutdownObserver.cpp
+++ b/libs/storage/IMountShutdownObserver.cpp
@@ -33,11 +33,11 @@
             onShutDownComplete(statusCode);
             reply->writeNoException();
             return NO_ERROR;
-        } break;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
 }
 // ----------------------------------------------------------------------
 
-};
+}
diff --git a/libs/storage/IObbActionListener.cpp b/libs/storage/IObbActionListener.cpp
index eaa211e..9656e65 100644
--- a/libs/storage/IObbActionListener.cpp
+++ b/libs/storage/IObbActionListener.cpp
@@ -30,10 +30,11 @@
         : BpInterface<IObbActionListener>(impl)
     { }
 
-    virtual void onObbResult(const String16& filename, const int32_t nonce, const int32_t state) { }
+    virtual void onObbResult(const String16& /* filename */, const int32_t /* nonce */,
+                             const int32_t /* state */) { }
 };
 
-IMPLEMENT_META_INTERFACE(ObbActionListener, "IObbActionListener");
+IMPLEMENT_META_INTERFACE(ObbActionListener, "IObbActionListener")
 
 // ----------------------------------------------------------------------
 
@@ -49,7 +50,7 @@
             onObbResult(filename, nonce, state);
             reply->writeNoException();
             return NO_ERROR;
-        } break;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
@@ -57,4 +58,4 @@
 
 // ----------------------------------------------------------------------
 
-};
+}
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/Android.mk b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
index 3e07155..51f2111 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
+++ b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
@@ -4,6 +4,7 @@
 ifeq ($(HOST_OS),linux)
 
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE_TAGS := optional
 
@@ -21,6 +22,7 @@
 
 # Build for device
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/location/java/android/location/GpsClock.java b/location/java/android/location/GpsClock.java
index 22ac1a9..4135a1c 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 /**
  * A class containing a GPS clock timestamp.
@@ -29,7 +28,6 @@
  */
 @SystemApi
 public class GpsClock implements Parcelable {
-    private static final String TAG = "GpsClock";
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -109,17 +107,7 @@
      * Sets the type of time reported.
      */
     public void setType(byte value) {
-        switch (value) {
-            case TYPE_UNKNOWN:
-            case TYPE_GPS_TIME:
-            case TYPE_LOCAL_HW_TIME:
-                mType = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'type': " + value);
-                mType = TYPE_UNKNOWN;
-                break;
-        }
+        mType = value;
     }
 
     /**
@@ -135,7 +123,7 @@
             case TYPE_LOCAL_HW_TIME:
                 return "LocalHwClock";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mType + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index 1c50181..05bcf79 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -19,7 +19,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 /**
  * A class representing a GPS satellite measurement, containing raw and computed information.
@@ -28,8 +27,6 @@
  */
 @SystemApi
 public class GpsMeasurement implements Parcelable {
-    private static final String TAG = "GpsMeasurement";
-
     private int mFlags;
     private byte mPrn;
     private double mTimeOffsetInNs;
@@ -140,6 +137,12 @@
     public static final short STATE_TOW_DECODED = (1<<3);
 
     /**
+     * All the GPS receiver state flags.
+     */
+    private static final short STATE_ALL =
+            STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC | STATE_TOW_DECODED;
+
+    /**
      * The state of the 'Accumulated Delta Range' is invalid or unknown.
      */
     public static final short ADR_STATE_UNKNOWN = 0;
@@ -159,6 +162,11 @@
      */
     public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
 
+    /**
+     * All the 'Accumulated Delta Range' flags.
+     */
+    private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+
     // End enumerations in sync with gps.h
 
     GpsMeasurement() {
@@ -263,19 +271,7 @@
      * Sets the sync state.
      */
     public void setState(short value) {
-        switch (value) {
-            case STATE_UNKNOWN:
-            case STATE_BIT_SYNC:
-            case STATE_CODE_LOCK:
-            case STATE_SUBFRAME_SYNC:
-            case STATE_TOW_DECODED:
-                mState = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'sync state': " + value);
-                mState = STATE_UNKNOWN;
-                break;
-        }
+        mState = value;
     }
 
     /**
@@ -283,20 +279,30 @@
      * For internal and logging use only.
      */
     private String getStateString() {
-        switch (mState) {
-            case STATE_UNKNOWN:
-                return "Unknown";
-            case STATE_BIT_SYNC:
-                return "BitSync";
-            case STATE_CODE_LOCK:
-                return "CodeLock";
-            case STATE_SUBFRAME_SYNC:
-                return "SubframeSync";
-            case STATE_TOW_DECODED:
-                return "TowDecoded";
-            default:
-                return "<Invalid>";
+        if (mState == STATE_UNKNOWN) {
+            return "Unknown";
         }
+        StringBuilder builder = new StringBuilder();
+        if ((mState & STATE_CODE_LOCK) == STATE_CODE_LOCK) {
+            builder.append("CodeLock|");
+        }
+        if ((mState & STATE_BIT_SYNC) == STATE_BIT_SYNC) {
+            builder.append("BitSync|");
+        }
+        if ((mState & STATE_SUBFRAME_SYNC) == STATE_SUBFRAME_SYNC) {
+            builder.append("SubframeSync|");
+        }
+        if ((mState & STATE_TOW_DECODED) == STATE_TOW_DECODED) {
+            builder.append("TowDecoded|");
+        }
+        int remainingStates = mState & ~STATE_ALL;
+        if (remainingStates > 0) {
+            builder.append("Other(");
+            builder.append(Integer.toBinaryString(remainingStates));
+            builder.append(")|");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        return builder.toString();
     }
 
     /**
@@ -395,18 +401,7 @@
      * Sets the 'Accumulated Delta Range' state.
      */
     public void setAccumulatedDeltaRangeState(short value) {
-        switch (value) {
-            case ADR_STATE_UNKNOWN:
-            case ADR_STATE_VALID:
-            case ADR_STATE_RESET:
-            case ADR_STATE_CYCLE_SLIP:
-                mAccumulatedDeltaRangeState = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'Accumulated Delta Range state': " + value);
-                mAccumulatedDeltaRangeState = ADR_STATE_UNKNOWN;
-                break;
-        }
+        mAccumulatedDeltaRangeState = value;
     }
 
     /**
@@ -414,18 +409,27 @@
      * For internal and logging use only.
      */
     private String getAccumulatedDeltaRangeStateString() {
-        switch (mAccumulatedDeltaRangeState) {
-            case ADR_STATE_UNKNOWN:
-                return "Unknown";
-            case ADR_STATE_VALID:
-                return "Valid";
-            case ADR_STATE_RESET:
-                return "Reset";
-            case ADR_STATE_CYCLE_SLIP:
-                return "CycleSlip";
-            default:
-                return "<Invalid>";
+        if (mAccumulatedDeltaRangeState == ADR_STATE_UNKNOWN) {
+            return "Unknown";
         }
+        StringBuilder builder = new StringBuilder();
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_VALID) == ADR_STATE_VALID) {
+            builder.append("Valid|");
+        }
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_RESET) == ADR_STATE_RESET) {
+            builder.append("Reset|");
+        }
+        if ((mAccumulatedDeltaRangeState & ADR_STATE_CYCLE_SLIP) == ADR_STATE_CYCLE_SLIP) {
+            builder.append("CycleSlip|");
+        }
+        int remainingStates = mAccumulatedDeltaRangeState & ~ADR_ALL;
+        if (remainingStates > 0) {
+            builder.append("Other(");
+            builder.append(Integer.toBinaryString(remainingStates));
+            builder.append(")|");
+        }
+        builder.deleteCharAt(builder.length() - 1);
+        return builder.toString();
     }
 
     /**
@@ -744,17 +748,7 @@
      * Sets the 'loss of lock' status.
      */
     public void setLossOfLock(byte value) {
-        switch (value) {
-            case LOSS_OF_LOCK_UNKNOWN:
-            case LOSS_OF_LOCK_OK:
-            case LOSS_OF_LOCK_CYCLE_SLIP:
-                mLossOfLock = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'loss of lock': " + value);
-                mLossOfLock = LOSS_OF_LOCK_UNKNOWN;
-                break;
-        }
+        mLossOfLock = value;
     }
 
     /**
@@ -770,7 +764,7 @@
             case LOSS_OF_LOCK_CYCLE_SLIP:
                 return "CycleSlip";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mLossOfLock + ">";
         }
     }
 
@@ -919,17 +913,7 @@
      * Sets the 'multi-path' indicator.
      */
     public void setMultipathIndicator(byte value) {
-        switch (value) {
-            case MULTIPATH_INDICATOR_UNKNOWN:
-            case MULTIPATH_INDICATOR_DETECTED:
-            case MULTIPATH_INDICATOR_NOT_USED:
-                mMultipathIndicator = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'muti-path indicator': " + value);
-                mMultipathIndicator = MULTIPATH_INDICATOR_UNKNOWN;
-                break;
-        }
+        mMultipathIndicator = value;
     }
 
     /**
@@ -945,7 +929,7 @@
             case MULTIPATH_INDICATOR_NOT_USED:
                 return "NotUsed";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mMultipathIndicator + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 42f8ee4..b893f3f 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -20,7 +20,6 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 import java.security.InvalidParameterException;
 
@@ -31,7 +30,7 @@
  */
 @SystemApi
 public class GpsNavigationMessage implements Parcelable {
-    private static final String TAG = "GpsNavigationMessage";
+
     private static final byte[] EMPTY_ARRAY = new byte[0];
 
     // The following enumerations must be in sync with the values declared in gps.h
@@ -102,19 +101,7 @@
      * Sets the type of the navigation message.
      */
     public void setType(byte value) {
-        switch (value) {
-            case TYPE_UNKNOWN:
-            case TYPE_L1CA:
-            case TYPE_L2CNAV:
-            case TYPE_L5CNAV:
-            case TYPE_CNAV2:
-                mType = value;
-                break;
-            default:
-                Log.d(TAG, "Sanitizing invalid 'type': " + value);
-                mType = TYPE_UNKNOWN;
-                break;
-        }
+        mType = value;
     }
 
     /**
@@ -134,7 +121,7 @@
             case TYPE_CNAV2:
                 return "CNAV-2";
             default:
-                return "<Invalid>";
+                return "<Invalid:" + mType + ">";
         }
     }
 
diff --git a/location/java/android/location/GpsSatellite.java b/location/java/android/location/GpsSatellite.java
index 17af4a6..820f5746 100644
--- a/location/java/android/location/GpsSatellite.java
+++ b/location/java/android/location/GpsSatellite.java
@@ -40,13 +40,17 @@
      * cached GpsStatus instance to the client's copy.
      */
     void setStatus(GpsSatellite satellite) {
-        mValid = satellite.mValid;
-        mHasEphemeris = satellite.mHasEphemeris;
-        mHasAlmanac = satellite.mHasAlmanac;
-        mUsedInFix = satellite.mUsedInFix;
-        mSnr = satellite.mSnr;
-        mElevation = satellite.mElevation;
-        mAzimuth = satellite.mAzimuth;
+        if (satellite == null) {
+            mValid = false;
+        } else {
+            mValid = satellite.mValid;
+            mHasEphemeris = satellite.mHasEphemeris;
+            mHasAlmanac = satellite.mHasAlmanac;
+            mUsedInFix = satellite.mUsedInFix;
+            mSnr = satellite.mSnr;
+            mElevation = satellite.mElevation;
+            mAzimuth = satellite.mAzimuth;
+        }
     }
 
     /**
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 4af55a6..323f326 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.util.SparseArray;
+
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
@@ -29,20 +31,24 @@
 
     /* These package private values are modified by the LocationManager class */
     private int mTimeToFirstFix;
-    private GpsSatellite mSatellites[] = new GpsSatellite[NUM_SATELLITES];
+    private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
     private final class SatelliteIterator implements Iterator<GpsSatellite> {
 
-        private GpsSatellite[] mSatellites;
-        int mIndex = 0;
+        private final SparseArray<GpsSatellite> mSatellites;
+        private final int mSatellitesCount;
 
-        SatelliteIterator(GpsSatellite[] satellites) {
+        private int mIndex = 0;
+
+        SatelliteIterator(SparseArray<GpsSatellite> satellites) {
             mSatellites = satellites;
+            mSatellitesCount = satellites.size();
         }
 
         public boolean hasNext() {
-            for (int i = mIndex; i < mSatellites.length; i++) {
-                if (mSatellites[i].mValid) {
+            for (; mIndex < mSatellitesCount; ++mIndex) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                if (satellite.mValid) {
                     return true;
                 }
             }
@@ -50,8 +56,9 @@
         }
 
         public GpsSatellite next() {
-            while (mIndex < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[mIndex++];
+            while (mIndex < mSatellitesCount) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                ++mIndex;
                 if (satellite.mValid) {
                     return satellite;
                 }
@@ -106,7 +113,7 @@
          * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
          * </ul>
          *
-         * When this method is called, the client should call 
+         * When this method is called, the client should call
          * {@link LocationManager#getGpsStatus} to get additional
          * status information.
          *
@@ -127,11 +134,8 @@
         void onNmeaReceived(long timestamp, String nmea);
     }
 
-    GpsStatus() {
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i] = new GpsSatellite(i + 1);
-        }
-    }
+    // For API-compat a public ctor() is not available
+    GpsStatus() {}
 
     /**
      * Used internally within {@link LocationManager} to copy GPS status
@@ -141,18 +145,17 @@
     synchronized void setStatus(int svCount, int[] prns, float[] snrs,
             float[] elevations, float[] azimuths, int ephemerisMask,
             int almanacMask, int usedInFixMask) {
-        int i;
+        clearSatellites();
+        for (int i = 0; i < svCount; i++) {
+            int prn = prns[i];
+            int prnShift = (1 << (prn - 1));
+            if (prn > 0 && prn <= NUM_SATELLITES) {
+                GpsSatellite satellite = mSatellites.get(prn);
+                if (satellite == null) {
+                    satellite = new GpsSatellite(prn);
+                    mSatellites.put(prn, satellite);
+                }
 
-        for (i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].mValid = false;
-        }
-        
-        for (i = 0; i < svCount; i++) {
-            int prn = prns[i] - 1;
-            int prnShift = (1 << prn);
-            if (prn >= 0 && prn < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[prn];
-    
                 satellite.mValid = true;
                 satellite.mSnr = snrs[i];
                 satellite.mElevation = elevations[i];
@@ -172,10 +175,38 @@
      */
     void setStatus(GpsStatus status) {
         mTimeToFirstFix = status.getTimeToFirstFix();
+        clearSatellites();
 
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].setStatus(status.mSatellites[i]);
-        } 
+        SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
+        int otherSatellitesCount = otherSatellites.size();
+        int satelliteIndex = 0;
+        // merge both sparse arrays, note that we have already invalidated the elements in the
+        // receiver array
+        for (int i = 0; i < otherSatellitesCount; ++i) {
+            GpsSatellite otherSatellite = otherSatellites.valueAt(i);
+            int otherSatellitePrn = otherSatellite.getPrn();
+
+            int satellitesCount = mSatellites.size();
+            while (satelliteIndex < satellitesCount
+                    && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
+                ++satelliteIndex;
+            }
+
+            if (satelliteIndex < mSatellites.size()) {
+                GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
+                if (satellite.getPrn() == otherSatellitePrn) {
+                    satellite.setStatus(otherSatellite);
+                } else {
+                    satellite = new GpsSatellite(otherSatellitePrn);
+                    satellite.setStatus(otherSatellite);
+                    mSatellites.put(otherSatellitePrn, satellite);
+                }
+            } else {
+                GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
+                satellite.setStatus(otherSatellite);
+                mSatellites.append(otherSatellitePrn, satellite);
+            }
+        }
     }
 
     void setTimeToFirstFix(int ttff) {
@@ -183,7 +214,7 @@
     }
 
     /**
-     * Returns the time required to receive the first fix since the most recent 
+     * Returns the time required to receive the first fix since the most recent
      * restart of the GPS engine.
      *
      * @return time to first fix in milliseconds
@@ -211,4 +242,12 @@
     public int getMaxSatellites() {
         return NUM_SATELLITES;
     }
+
+    private void clearSatellites() {
+        int satellitesCount = mSatellites.size();
+        for (int i = 0; i < satellitesCount; i++) {
+            GpsSatellite satellite = mSatellites.valueAt(i);
+            satellite.mValid = false;
+        }
+    }
 }
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index fcf222b..bf3387b 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -170,6 +170,9 @@
      * Converts a coordinate to a String representation. The outputType
      * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
      * The coordinate must be a valid double between -180.0 and 180.0.
+     * This conversion is performed in a method that is dependent on the
+     * default locale, and so is not guaranteed to round-trip with
+     * {@link #convert(String)}.
      *
      * @throws IllegalArgumentException if coordinate is less than
      * -180.0, greater than 180.0, or is not a number.
@@ -217,7 +220,9 @@
     /**
      * Converts a String in one of the formats described by
      * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a
-     * double.
+     * double. This conversion is performed in a locale agnostic
+     * method, and so is not guaranteed to round-trip with
+     * {@link #convert(double, int)}.
      *
      * @throws NullPointerException if coordinate is null
      * @throws IllegalArgumentException if the coordinate is not
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 271f2bb..65e7ced 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -212,6 +212,7 @@
                 switch (criteria.getPowerRequirement()) {
                     case Criteria.POWER_HIGH:
                         quality = POWER_HIGH;
+                        break;
                     default:
                         quality = POWER_LOW;
                 }
@@ -292,7 +293,7 @@
      * no location sources are available), or you may receive them
      * slower than requested. You may also receive them faster than
      * requested (if other applications are requesting location at a
-     * faster interval). The fastest rate that that you will receive
+     * faster interval). The fastest rate that you will receive
      * updates can be controlled with {@link #setFastestInterval}.
      *
      * <p>Applications with only the coarse location permission may have their
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index e9e475c..0a3e073 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -34,7 +34,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.R;
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
new file mode 100644
index 0000000..4808faf
--- /dev/null
+++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link GpsStatus}.
+ */
+@SmallTest
+public class GpsStatusTest extends TestCase {
+
+    private static final int MAX_VALUE = 250;
+
+    private final Random mRandom = new Random();
+
+    private GpsStatus mStatus;
+    private int mCount;
+    private int[] mPrns;
+    private float[] mSnrs;
+    private float[] mElevations;
+    private float[] mAzimuth;
+    private int mEphemerisMask;
+    private int mAlmanacMask;
+    private int mUsedInFixMask;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mStatus = createGpsStatus();
+        generateSatellitesData(generateInt());
+    }
+
+    public void testEmptyGpsStatus() throws Exception {
+        verifyIsEmpty(mStatus);
+    }
+
+    public void testGpsStatusIterator() throws Exception {
+        generateSatellitesData(2);
+        setSatellites(mStatus);
+        Iterator<GpsSatellite> iterator = mStatus.getSatellites().iterator();
+        assertTrue("hasNext(1)", iterator.hasNext());
+        assertTrue("hasNext(1) does not overflow", iterator.hasNext());
+        GpsSatellite satellite1 = iterator.next();
+        assertNotNull("satellite", satellite1);
+        assertTrue("hasNext(2)", iterator.hasNext());
+        assertTrue("hasNext(2) does not overflow", iterator.hasNext());
+        GpsSatellite satellite2 = iterator.next();
+        assertNotNull("satellite", satellite2);
+        assertFalse("hasNext() no elements", iterator.hasNext());
+    }
+
+    public void testTtff() throws Exception {
+        int testTtff = generateInt();
+        set(mStatus, testTtff);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testCopyTtff() throws Exception {
+        int testTtff = generateInt();
+        verifyTtff(mStatus, 0);
+
+        GpsStatus otherStatus = createGpsStatus();
+        set(otherStatus, testTtff);
+        verifyTtff(otherStatus, testTtff);
+
+        set(mStatus, otherStatus);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testSetSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testCopySatellites() throws Exception {
+        verifyIsEmpty(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testOverrideSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(mCount, true /* reusePrns */);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddSatellites() throws Exception {
+        int count = 10;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddMoreSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count * 2);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddLessSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count * 2);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    private static void verifyIsEmpty(GpsStatus status) {
+        verifySatelliteCount(status, 0);
+        verifyTtff(status, 0);
+    }
+
+    private static void verifySatelliteCount(GpsStatus status, int expectedCount) {
+        int satellites = 0;
+        for (GpsSatellite s : status.getSatellites()) {
+            ++satellites;
+        }
+        assertEquals("GpsStatus::SatelliteCount", expectedCount, satellites);
+    }
+
+    private void verifySatellites(GpsStatus status) {
+        verifySatelliteCount(status, mCount);
+        verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+                mAlmanacMask, mUsedInFixMask);
+    }
+
+    private static void verifySatellites(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) {
+        for (int i = 0; i < count; ++i) {
+            int prn = prns[i];
+            GpsSatellite satellite = getSatellite(status, prn);
+            assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
+            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Elevation"),
+                    elevations[i],
+                    satellite.getElevation());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Azimuth"),
+                    azimuth[i],
+                    satellite.getAzimuth());
+            int prnShift = 1 << (prn - 1);
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "ephemeris"),
+                    (ephemerisMask & prnShift) != 0,
+                    satellite.hasEphemeris());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "almanac"),
+                    (almanacMask & prnShift) != 0,
+                    satellite.hasAlmanac());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "usedInFix"),
+                    (usedInFixMask & prnShift) != 0,
+                    satellite.usedInFix());
+        }
+    }
+
+    private static void verifyTtff(GpsStatus status, int expectedTtff) {
+        assertEquals("GpsStatus::TTFF", expectedTtff, status.getTimeToFirstFix());
+    }
+
+    private static GpsStatus createGpsStatus() throws Exception {
+        Constructor<GpsStatus>  ctor = GpsStatus.class.getDeclaredConstructor();
+        ctor.setAccessible(true);
+        return ctor.newInstance();
+    }
+
+    private static void set(GpsStatus status, int ttff) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setTtff = statusClass.getDeclaredMethod("setTimeToFirstFix", Integer.TYPE);
+        setTtff.setAccessible(true);
+        setTtff.invoke(status, ttff);
+    }
+
+    private static void set(GpsStatus status, GpsStatus statusToSet) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setStatus = statusClass.getDeclaredMethod("setStatus", statusClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(status, statusToSet);
+    }
+
+    private void setSatellites(GpsStatus status) throws Exception {
+        set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+                mUsedInFixMask);
+    }
+
+    private static void set(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Class<?> intClass = Integer.TYPE;
+        Class<?> floatArrayClass = Class.forName("[F");
+        Method setStatus = statusClass.getDeclaredMethod(
+                "setStatus",
+                intClass,
+                Class.forName("[I"),
+                floatArrayClass,
+                floatArrayClass,
+                floatArrayClass,
+                intClass,
+                intClass,
+                intClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(
+                status,
+                count,
+                prns,
+                snrs,
+                elevations,
+                azimuth,
+                ephemerisMask,
+                almanacMask,
+                usedInFixMask);
+    }
+
+    private int generateInt() {
+        return mRandom.nextInt(MAX_VALUE) + 1;
+    }
+
+    private int[] generateIntArray(int count) {
+        Set<Integer> generatedPrns = new HashSet<>();
+        int[] array = new int[count];
+        for(int i = 0; i < count; ++i) {
+            int generated;
+            do {
+                generated = generateInt();
+            } while (generatedPrns.contains(generated));
+            array[i] = generated;
+            generatedPrns.add(generated);
+        }
+        return array;
+    }
+
+    private float[] generateFloatArray(int count) {
+        float[] array = new float[count];
+        for(int i = 0; i < count; ++i) {
+            array[i] = generateInt();
+        }
+        return array;
+    }
+
+    private int generateMask(int[] prns) {
+        int mask = 0;
+        int prnsLength = prns.length;
+        for (int i = 0; i < prnsLength; ++i) {
+            if (mRandom.nextBoolean()) {
+                mask |= 1 << (prns[i] - 1);
+            }
+        }
+        return mask;
+    }
+
+    private void generateSatellitesData(int count) {
+        generateSatellitesData(count, false /* reusePrns */);
+    }
+
+    private void generateSatellitesData(int count, boolean reusePrns) {
+        mCount = count;
+        if (!reusePrns) {
+            mPrns = generateIntArray(count);
+        }
+        mSnrs = generateFloatArray(count);
+        mElevations = generateFloatArray(count);
+        mAzimuth = generateFloatArray(count);
+        mEphemerisMask = generateMask(mPrns);
+        mAlmanacMask = generateMask(mPrns);
+        mUsedInFixMask = generateMask(mPrns);
+    }
+
+    private static GpsSatellite getSatellite(GpsStatus status, int prn) {
+        for (GpsSatellite satellite : status.getSatellites()) {
+            if (satellite.getPrn() == prn) {
+                return satellite;
+            }
+        }
+        return null;
+    }
+
+    private static String getSatelliteAssertInfo(int index, int prn, String param) {
+        return String.format("Satellite::%s [i=%d, prn=%d]", param, index, prn);
+    }
+}
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 14b199e..dd5f6ba 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.Uri;
 import android.os.PowerManager;
@@ -38,11 +39,11 @@
         Context context;
         Uri uri;
         boolean looping;
-        int stream;
+        AudioAttributes attributes;
         long requestTime;
 
         public String toString() {
-            return "{ code=" + code + " looping=" + looping + " stream=" + stream
+            return "{ code=" + code + " looping=" + looping + " attr=" + attributes
                     + " uri=" + uri + " }";
         }
     }
@@ -56,7 +57,7 @@
         try {
             if (mDebug) Log.d(mTag, "Starting playback");
             MediaPlayer player = new MediaPlayer();
-            player.setAudioStreamType(cmd.stream);
+            player.setAudioAttributes(cmd.attributes);
             player.setDataSource(cmd.context, cmd.uri);
             player.setLooping(cmd.looping);
             player.prepare();
@@ -159,21 +160,52 @@
      *          (see {@link MediaPlayer#setLooping(boolean)})
      * @param stream the AudioStream to use.
      *          (see {@link MediaPlayer#setAudioStreamType(int)})
+     * @deprecated use {@link #play(Context, Uri, boolean, AudioAttributes)} instead
      */
     public void play(Context context, Uri uri, boolean looping, int stream) {
+        if (context == null || uri == null) {
+            return;
+        }
+        try {
+            play(context, uri, looping,
+                    new AudioAttributes.Builder().setInternalLegacyStreamType(stream).build());
+        } catch (IllegalArgumentException e) {
+            Log.e(mTag, "Call to deprecated AsyncPlayer.play() method caused:", e);
+        }
+    }
+
+    /**
+     * Start playing the sound.  It will actually start playing at some
+     * point in the future.  There are no guarantees about latency here.
+     * Calling this before another audio file is done playing will stop
+     * that one and start the new one.
+     *
+     * @param context the non-null application's context.
+     * @param uri the non-null URI to play.  (see {@link MediaPlayer#setDataSource(Context, Uri)})
+     * @param looping whether the audio should loop forever.
+     *          (see {@link MediaPlayer#setLooping(boolean)})
+     * @param attributes the non-null {@link AudioAttributes} to use.
+     *          (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)})
+     * @throws IllegalArgumentException
+     */
+    public void play(@NonNull Context context, @NonNull Uri uri, boolean looping,
+            @NonNull AudioAttributes attributes) throws IllegalArgumentException {
+        if (context == null || uri == null || attributes == null) {
+            throw new IllegalArgumentException("Illegal null AsyncPlayer.play() argument");
+        }
         Command cmd = new Command();
         cmd.requestTime = SystemClock.uptimeMillis();
         cmd.code = PLAY;
         cmd.context = context;
         cmd.uri = uri;
         cmd.looping = looping;
-        cmd.stream = stream;
+        cmd.attributes = attributes;
         synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
         }
     }
-    
+
     /**
      * Stop a previously played sound.  It can't be played again or unpaused
      * at this point.  Calling this multiple times has no ill effects.
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 489f552..4526839 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -27,7 +27,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
 
@@ -209,8 +208,23 @@
     @SystemApi
     public final static int FLAG_HW_HOTWORD = 0x1 << 5;
 
+    /**
+     * @hide
+     * Flag requesting audible playback even under limited interruptions.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
+
+    /**
+     * @hide
+     * Flag requesting audible playback even when the underlying stream is muted.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
-            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD;
+            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
+            FLAG_BYPASS_MUTE;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
 
     private int mUsage = USAGE_UNKNOWN;
@@ -265,6 +279,7 @@
      * Internal use only
      * @return a combined mask of all flags
      */
+    @SystemApi
     public int getAllFlags() {
         return (mFlags & FLAG_ALL);
     }
@@ -527,14 +542,15 @@
         /**
          * @hide
          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
-         * REMOTE_SUBMIX and FM_TUNER.
+         * REMOTE_SUBMIX and RADIO_TUNER.
          * @param preset
          * @return the same Builder instance.
          */
+        @SystemApi
         public Builder setInternalCapturePreset(int preset) {
             if ((preset == MediaRecorder.AudioSource.HOTWORD)
                     || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)
-                    || (preset == MediaRecorder.AudioSource.FM_TUNER)) {
+                    || (preset == MediaRecorder.AudioSource.RADIO_TUNER)) {
                 mSource = preset;
             } else {
                 setCapturePreset(preset);
@@ -709,7 +725,13 @@
         }
     }
 
-    /** @hide */
+    /**
+     * @hide
+     * Only use to get which stream type should be used for volume control, NOT for audio playback
+     * (all audio playback APIs are supposed to take AudioAttributes as input parameters)
+     * @param aa non-null AudioAttributes.
+     * @return a valid stream type for volume control that matches the attributes.
+     */
     public static int toLegacyStreamType(AudioAttributes aa) {
         // flags to stream type mapping
         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
index b10736b..82da27d 100644
--- a/media/java/android/media/AudioDevicePort.java
+++ b/media/java/android/media/AudioDevicePort.java
@@ -36,12 +36,13 @@
     private final int mType;
     private final String mAddress;
 
-    AudioDevicePort(AudioHandle handle, int[] samplingRates, int[] channelMasks,
+    AudioDevicePort(AudioHandle handle, String deviceName,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains, int type, String address) {
         super(handle,
              (AudioManager.isInputDevice(type) == true)  ?
                         AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
-             samplingRates, channelMasks, formats, gains);
+             deviceName, samplingRates, channelMasks, formats, gains);
         mType = type;
         mAddress = address;
     }
diff --git a/media/java/android/media/AudioDevicesManager.java b/media/java/android/media/AudioDevicesManager.java
new file mode 100644
index 0000000..ee11eef
--- /dev/null
+++ b/media/java/android/media/AudioDevicesManager.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/** @hide
+ * API candidate
+ */
+public class AudioDevicesManager {
+    private static String TAG = "AudioDevicesManager";
+    private static boolean DEBUG = true;
+
+    private AudioManager mAudioManager = null;
+    private OnAmPortUpdateListener mPortListener = null;
+
+    /*
+     * Enum/Selection API
+     */
+    public AudioDevicesManager(Context context) {
+        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+        mPortListener = new OnAmPortUpdateListener();
+        mAudioManager.registerAudioPortUpdateListener(mPortListener);
+    }
+
+    /** @hide
+     * API candidate
+     */
+    //TODO Merge this class into android.media.AudioDevice
+    public class AudioDeviceInfo {
+        private AudioDevicePort mPort = null;
+
+        /** @hide */
+        /* package */ AudioDeviceInfo(AudioDevicePort port) {
+            mPort = port;
+        }
+
+        public int getId() { return mPort.handle().id(); }
+
+        public String getName() { return mPort.name(); }
+
+        public int getType() {
+            return mPort.type();
+        }
+
+        public String getAddress() {
+            return mPort.address();
+        }
+
+        public int getRole() { return mPort.role(); }
+
+        public int[] getSampleRates() { return mPort.samplingRates(); }
+
+        public int[] getChannelMasks() { return mPort.channelMasks(); }
+
+        public int[] getChannelCounts() {
+            int[] masks = getChannelMasks();
+            int[] counts = new int[masks.length];
+            for (int mask_index = 0; mask_index < masks.length; mask_index++) {
+                counts[mask_index] = getRole() == AudioPort.ROLE_SINK
+                        ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
+                        : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+            }
+            return counts;
+        }
+
+        /* The format IDs are in AudioFormat.java */
+        public int[] getFormats() { return mPort.formats(); }
+
+        public String toString() { return "" + getId() + " - " + getName(); }
+    }
+
+    /** @hide */
+    public static final int LIST_DEVICES_OUTPUTS   = 0x0001;
+    /** @hide */
+    public static final int LIST_DEVICES_INPUTS    = 0x0002;
+    /** @hide */
+    public static final int LIST_DEVICES_BUILTIN   = 0x0004;
+    /** @hide */
+    public static final int LIST_DEVICES_USB       = 0x0008;
+    // TODO implement the semantics for these.
+    /** @hide */
+    public static final int LIST_DEVICES_WIRED     = 0x0010;
+    /** @hide */
+    public static final int LIST_DEVICES_UNWIRED   = 0x0020;
+
+    /** @hide */
+    public static final int LIST_DEVICES_ALL = LIST_DEVICES_OUTPUTS | LIST_DEVICES_INPUTS;
+
+    private boolean checkFlags(AudioDevicePort port, int flags) {
+        // Inputs / Outputs
+        boolean passed =
+                port.role() == AudioPort.ROLE_SINK && (flags & LIST_DEVICES_OUTPUTS) != 0 ||
+                port.role() == AudioPort.ROLE_SOURCE && (flags & LIST_DEVICES_INPUTS) != 0;
+
+        // USB
+        if (passed && (flags & LIST_DEVICES_USB) != 0) {
+            int role = port.role();
+            int type = port.type();
+            Slog.i(TAG, "  role:" + role + " type:0x" + Integer.toHexString(type));
+            passed =
+                (role == AudioPort.ROLE_SINK && (type & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                (role == AudioPort.ROLE_SOURCE && (type & AudioSystem.DEVICE_IN_ALL_USB) != 0);
+        }
+
+        return passed;
+    }
+
+    /** @hide */
+    public ArrayList<AudioDeviceInfo> listDevices(int flags) {
+        Slog.i(TAG, "AudioManager.listDevices(" + Integer.toHexString(flags) + ")");
+
+        ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
+        int status = mAudioManager.listAudioDevicePorts(ports);
+
+        Slog.i(TAG, "  status:" + status + " numPorts:" + ports.size());
+
+        ArrayList<AudioDeviceInfo> deviceList = new ArrayList<AudioDeviceInfo>();
+
+        if (status == AudioManager.SUCCESS) {
+            deviceList = new ArrayList<AudioDeviceInfo>();
+             for (AudioDevicePort port : ports) {
+                if (checkFlags(port, flags)) {
+                    deviceList.add(new AudioDeviceInfo(port));
+                }
+            }
+        }
+        return deviceList;
+    }
+
+    private ArrayList<OnAudioDeviceConnectionListener> mDeviceConnectionListeners =
+            new ArrayList<OnAudioDeviceConnectionListener>();
+
+    private HashMap<Integer, AudioPort> mCurrentPortlist =
+            new HashMap<Integer, AudioPort>();
+
+    private ArrayList<AudioDeviceInfo> calcAddedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> addedDevices = new  ArrayList<AudioDeviceInfo>();
+        synchronized(mCurrentPortlist) {
+            for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    if (!mCurrentPortlist.containsKey(portList[portIndex].handle().id())) {
+                        addedDevices.add(new AudioDeviceInfo((AudioDevicePort)portList[portIndex]));
+                    }
+                }
+            }
+        }
+        return addedDevices;
+    }
+
+    private boolean hasPortId(AudioPort[] portList, int id) {
+        for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+            if (portList[portIndex].handle().id() == id) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private ArrayList<AudioDeviceInfo> calcRemovedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> removedDevices = new  ArrayList<AudioDeviceInfo>();
+
+        synchronized (mCurrentPortlist) {
+            Iterator it = mCurrentPortlist.entrySet().iterator();
+            while (it.hasNext()) {
+                HashMap.Entry pairs = (HashMap.Entry)it.next();
+                if (pairs.getValue() instanceof AudioDevicePort) {
+                    if (!hasPortId(portList, ((Integer)pairs.getKey()).intValue())) {
+                        removedDevices.add(new AudioDeviceInfo((AudioDevicePort)pairs.getValue()));
+                    }
+                }
+            }
+        }
+        return removedDevices;
+    }
+
+    private void buildCurrentDevicesList(AudioPort[] portList) {
+        synchronized (mCurrentPortlist) {
+            mCurrentPortlist.clear();
+            for (int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    mCurrentPortlist.put(portList[portIndex].handle().id(),
+                                         (AudioDevicePort)portList[portIndex]);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public void addDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.add(listener);
+        }
+    }
+
+    /** @hide */
+    public void removeDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.remove(listener);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
+        static final String TAG = "OnAmPortUpdateListener";
+        public void onAudioPortListUpdate(AudioPort[] portList) {
+            Slog.i(TAG, "onAudioPortListUpdate() " + portList.length + " ports.");
+            ArrayList<AudioDeviceInfo> addedDevices = calcAddedDevices(portList);
+            ArrayList<AudioDeviceInfo> removedDevices = calcRemovedDevices(portList);
+
+            ArrayList<OnAudioDeviceConnectionListener> listeners = null;
+            synchronized (mDeviceConnectionListeners) {
+                listeners =
+                        new ArrayList<OnAudioDeviceConnectionListener>(mDeviceConnectionListeners);
+            }
+
+            // Connect
+            if (addedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onConnect(addedDevices);
+                }
+            }
+
+            // Disconnect?
+            if (removedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onDisconnect(removedDevices);
+                }
+            }
+
+            buildCurrentDevicesList(portList);
+        }
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void onAudioPatchListUpdate(AudioPatch[] patchList) {
+            Slog.i(TAG, "onAudioPatchListUpdate() " + patchList.length + " patches.");
+        }
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void onServiceDied() {
+            Slog.i(TAG, "onServiceDied()");
+        }
+    }
+}
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index fbdda3c..540c328 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -45,8 +45,9 @@
      * @param gainRequest
      * @param lossReceived
      * @param flags
+     * @hide
      */
-    AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
+    public AudioFocusInfo(AudioAttributes aa, String clientId, String packageName,
             int gainRequest, int lossReceived, int flags) {
         mAttributes = aa == null ? new AudioAttributes.Builder().build() : aa;
         mClientId = clientId == null ? "" : clientId;
@@ -91,7 +92,7 @@
     public int getLossReceived() { return mLossReceived; }
 
     /** @hide */
-    void clearLossReceived() { mLossReceived = 0; }
+    public void clearLossReceived() { mLossReceived = 0; }
 
     /**
      * The flags set in the audio focus request.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 240faef..8c1ba05 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -26,9 +26,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.media.RemoteController.OnClientUpdateListener;
 import android.media.audiopolicy.AudioPolicy;
-import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
@@ -58,12 +56,10 @@
  */
 public class AudioManager {
 
-    private final Context mContext;
+    private final Context mApplicationContext;
     private long mVolumeKeyUpTime;
-    private final boolean mUseMasterVolume;
     private final boolean mUseVolumeKeySounds;
     private final boolean mUseFixedVolume;
-    private final Binder mToken = new Binder();
     private static String TAG = "AudioManager";
     private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
 
@@ -149,17 +145,6 @@
         "android.media.STREAM_MUTE_CHANGED_ACTION";
 
     /**
-     * @hide Broadcast intent when the master volume changes.
-     * Includes the new volume
-     *
-     * @see #EXTRA_MASTER_VOLUME_VALUE
-     * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String MASTER_VOLUME_CHANGED_ACTION =
-        "android.media.MASTER_VOLUME_CHANGED_ACTION";
-
-    /**
      * @hide Broadcast intent when the master mute state changes.
      * Includes the the new volume
      *
@@ -211,20 +196,6 @@
         "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
 
     /**
-     * @hide The new master volume value for the master volume changed intent.
-     * Value is integer between 0 and 100 inclusive.
-     */
-    public static final String EXTRA_MASTER_VOLUME_VALUE =
-        "android.media.EXTRA_MASTER_VOLUME_VALUE";
-
-    /**
-     * @hide The previous master volume value for the master volume changed intent.
-     * Value is integer between 0 and 100 inclusive.
-     */
-    public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
-        "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
-
-    /**
      * @hide The new master volume mute state for the master mute changed intent.
      * Value is boolean
      */
@@ -259,7 +230,7 @@
             "android.intent.action.HEADSET_PLUG";
 
     /**
-     * Broadcast Action: A sticky broadcast indicating an HMDI cable was plugged or unplugged
+     * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
      *
      * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
      * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
@@ -295,68 +266,6 @@
      */
     public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
 
-    /**
-     * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
-     *
-     * <p>The intent will have the following extra values:
-     * <ul>
-     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
-     *   <li><em>name</em> - Headset type, human readable string </li>
-     * </ul>
-     * </ul>
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG =
-            "android.media.action.ANALOG_AUDIO_DOCK_PLUG";
-
-    /**
-     * Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
-     *
-     * <p>The intent will have the following extra values:
-     * <ul>
-     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
-     *   <li><em>name</em> - Headset type, human readable string </li>
-     * </ul>
-     * </ul>
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG =
-            "android.media.action.DIGITAL_AUDIO_DOCK_PLUG";
-
-    /**
-     * Broadcast Action: A USB audio accessory was plugged in or unplugged.
-     *
-     * <p>The intent will have the following extra values:
-     * <ul>
-     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
-     *   <li><em>card</em> - ALSA card number (integer) </li>
-     *   <li><em>device</em> - ALSA device number (integer) </li>
-     * </ul>
-     * </ul>
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
-            "android.media.action.USB_AUDIO_ACCESSORY_PLUG";
-
-    /**
-     * Broadcast Action: A USB audio device was plugged in or unplugged.
-     *
-     * <p>The intent will have the following extra values:
-     * <ul>
-     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
-     *   <li><em>card</em> - ALSA card number (integer) </li>
-     *   <li><em>device</em> - ALSA device number (integer) </li>
-     * </ul>
-     * </ul>
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
-            "android.media.action.USB_AUDIO_DEVICE_PLUG";
-
     /** The audio stream for phone calls */
     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
     /** The audio stream for system sounds */
@@ -408,6 +317,31 @@
      */
     public static final int ADJUST_SAME = 0;
 
+    /**
+     * Mute the volume. Has no effect if the stream is already muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_MUTE = -100;
+
+    /**
+     * Unmute the volume. Has no effect if the stream is not muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_UNMUTE = 100;
+
+    /**
+     * Toggle the mute state. If muted the stream will be unmuted. If not muted
+     * the stream will be muted.
+     *
+     * @see #adjustVolume(int, int)
+     * @see #adjustStreamVolume(int, int, int)
+     */
+    public static final int ADJUST_TOGGLE_MUTE = 101;
+
     // Flags should be powers of 2!
 
     /**
@@ -641,12 +575,10 @@
      * @hide
      */
     public AudioManager(Context context) {
-        mContext = context;
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
-        mUseVolumeKeySounds = mContext.getResources().getBoolean(
+        mApplicationContext = context;
+        mUseVolumeKeySounds = mApplicationContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useVolumeKeySounds);
-        mUseFixedVolume = mContext.getResources().getBoolean(
+        mUseFixedVolume = mApplicationContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
         sAudioPortEventHandler.init();
     }
@@ -685,7 +617,7 @@
      *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
      */
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
         helper.sendMediaButtonEvent(keyEvent, false);
     }
 
@@ -700,18 +632,13 @@
         int keyCode = event.getKeyCode();
         if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
                 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
-                && mVolumeKeyUpTime + AudioService.PLAY_SOUND_DELAY
-                        > SystemClock.uptimeMillis()) {
+                && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
             /*
              * The user has hit another key during the delay (e.g., 300ms)
              * since the last volume key up, so cancel any sounds.
              */
-            if (mUseMasterVolume) {
-                adjustMasterVolume(ADJUST_SAME, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
-            } else {
-                adjustSuggestedStreamVolume(ADJUST_SAME,
-                        stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
-            }
+            adjustSuggestedStreamVolume(ADJUST_SAME,
+                    stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
         }
     }
 
@@ -727,26 +654,17 @@
                  * Adjust the volume in on key down since it is more
                  * responsive to the user.
                  */
-                int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
-
-                if (mUseMasterVolume) {
-                    adjustMasterVolume(
-                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                    ? ADJUST_RAISE
-                                    : ADJUST_LOWER,
-                            flags);
-                } else {
-                    adjustSuggestedStreamVolume(
-                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                    ? ADJUST_RAISE
-                                    : ADJUST_LOWER,
-                            stream,
-                            flags);
-                }
+                adjustSuggestedStreamVolume(
+                        keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                ? ADJUST_RAISE
+                                : ADJUST_LOWER,
+                        stream,
+                        FLAG_SHOW_UI | FLAG_VIBRATE);
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
                 if (event.getRepeatCount() == 0) {
-                    MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+                    MediaSessionLegacyHelper.getHelper(mApplicationContext)
+                            .sendVolumeKeyEvent(event, false);
                 }
                 break;
         }
@@ -765,20 +683,16 @@
                  * sound to play when a user holds down volume down to mute.
                  */
                 if (mUseVolumeKeySounds) {
-                    if (mUseMasterVolume) {
-                        adjustMasterVolume(ADJUST_SAME, FLAG_PLAY_SOUND);
-                    } else {
-                        int flags = FLAG_PLAY_SOUND;
-                        adjustSuggestedStreamVolume(
-                                ADJUST_SAME,
-                                stream,
-                                flags);
-                    }
+                    adjustSuggestedStreamVolume(
+                            ADJUST_SAME,
+                            stream,
+                            FLAG_PLAY_SOUND);
                 }
                 mVolumeKeyUpTime = SystemClock.uptimeMillis();
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
-                MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+                MediaSessionLegacyHelper.getHelper(mApplicationContext)
+                        .sendVolumeKeyEvent(event, false);
                 break;
         }
     }
@@ -822,12 +736,8 @@
     public void adjustStreamVolume(int streamType, int direction, int flags) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                service.adjustStreamVolume(streamType, direction, flags,
-                        mContext.getOpPackageName());
-            }
+            service.adjustStreamVolume(streamType, direction, flags,
+                    mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustStreamVolume", e);
         }
@@ -839,13 +749,17 @@
      * screen is showing. Another example, if music is playing in the background
      * and a call is not active, the music stream will be adjusted.
      * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
+     * <p>
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     *
      * @param direction The direction to adjust the volume. One of
-     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
-     *            {@link #ADJUST_SAME}.
+     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
+     *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
+     *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
      * @param flags One or more flags.
      * @see #adjustSuggestedStreamVolume(int, int, int)
      * @see #adjustStreamVolume(int, int, int)
@@ -853,33 +767,28 @@
      * @see #isVolumeFixed()
      */
     public void adjustVolume(int direction, int flags) {
-        IAudioService service = getService();
-        try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustVolume", e);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
+        helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
     }
 
     /**
      * Adjusts the volume of the most relevant stream, or the given fallback
      * stream.
      * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     *
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
+     * <p>
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     *
      * @param direction The direction to adjust the volume. One of
-     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
-     *            {@link #ADJUST_SAME}.
+     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
+     *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
+     *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
      * @param suggestedStreamType The stream type that will be used if there
-     *            isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is valid here.
+     *            isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
+     *            valid here.
      * @param flags One or more flags.
      * @see #adjustVolume(int, int)
      * @see #adjustStreamVolume(int, int, int)
@@ -887,34 +796,17 @@
      * @see #isVolumeFixed()
      */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
-        IAudioService service = getService();
-        try {
-            if (mUseMasterVolume) {
-                service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
-            } else {
-                MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-                helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
-        }
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
+        helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
     }
 
-    /**
-     * Adjusts the master volume for the device's audio amplifier.
-     * <p>
-     *
-     * @param steps The number of volume steps to adjust. A positive
-     *            value will raise the volume.
-     * @param flags One or more flags.
-     * @hide
-     */
-    public void adjustMasterVolume(int steps, int flags) {
+    /** @hide */
+    public void setMasterMute(boolean mute, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustMasterVolume(steps, flags, mContext.getOpPackageName());
+            service.setMasterMute(mute, flags, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustMasterVolume", e);
+            Log.e(TAG, "Dead object in setMasterMute", e);
         }
     }
 
@@ -966,11 +858,7 @@
     public int getStreamMaxVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getMasterMaxVolume();
-            } else {
-                return service.getStreamMaxVolume(streamType);
-            }
+            return service.getStreamMaxVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamMaxVolume", e);
             return 0;
@@ -978,6 +866,24 @@
     }
 
     /**
+     * Returns the minimum volume index for a particular stream.
+     *
+     * @param streamType The stream type whose minimum volume index is returned.
+     * @return The minimum valid volume index for the stream.
+     * @see #getStreamVolume(int)
+     * @hide
+     */
+    public int getStreamMinVolume(int streamType) {
+        IAudioService service = getService();
+        try {
+            return service.getStreamMinVolume(streamType);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getStreamMinVolume", e);
+            return 0;
+        }
+    }
+
+    /**
      * Returns the current volume index for a particular stream.
      *
      * @param streamType The stream type whose volume index is returned.
@@ -988,11 +894,7 @@
     public int getStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getMasterVolume();
-            } else {
-                return service.getStreamVolume(streamType);
-            }
+            return service.getStreamVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamVolume", e);
             return 0;
@@ -1007,11 +909,7 @@
     public int getLastAudibleStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                return service.getLastAudibleMasterVolume();
-            } else {
-                return service.getLastAudibleStreamVolume(streamType);
-            }
+            return service.getLastAudibleStreamVolume(streamType);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
             return 0;
@@ -1024,12 +922,12 @@
      * It is assumed that this stream type is also tied to ringer mode changes.
      * @hide
      */
-    public int getMasterStreamType() {
+    public int getUiSoundsStreamType() {
         IAudioService service = getService();
         try {
-            return service.getMasterStreamType();
+            return service.getUiSoundsStreamType();
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterStreamType", e);
+            Log.e(TAG, "Dead object in getUiSoundsStreamType", e);
             return STREAM_RING;
         }
     }
@@ -1053,7 +951,7 @@
         }
         IAudioService service = getService();
         try {
-            service.setRingerModeExternal(ringerMode, mContext.getOpPackageName());
+            service.setRingerModeExternal(ringerMode, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setRingerMode", e);
         }
@@ -1074,148 +972,79 @@
     public void setStreamVolume(int streamType, int index, int flags) {
         IAudioService service = getService();
         try {
-            if (mUseMasterVolume) {
-                service.setMasterVolume(index, flags, mContext.getOpPackageName());
-            } else {
-                service.setStreamVolume(streamType, index, flags, mContext.getOpPackageName());
-            }
+            service.setStreamVolume(streamType, index, flags, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setStreamVolume", e);
         }
     }
 
     /**
-     * Returns the maximum volume index for master volume.
-     *
-     * @hide
-     */
-    public int getMasterMaxVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getMasterMaxVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterMaxVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Returns the current volume index for master volume.
-     *
-     * @return The current volume index for master volume.
-     * @hide
-     */
-    public int getMasterVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getMasterVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getMasterVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Get last audible volume before master volume was muted.
-     *
-     * @hide
-     */
-    public int getLastAudibleMasterVolume() {
-        IAudioService service = getService();
-        try {
-            return service.getLastAudibleMasterVolume();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
-            return 0;
-        }
-    }
-
-    /**
-     * Sets the volume index for master volume.
-     *
-     * @param index The volume index to set. See
-     *            {@link #getMasterMaxVolume()} for the largest valid value.
-     * @param flags One or more flags.
-     * @see #getMasterMaxVolume()
-     * @see #getMasterVolume()
-     * @hide
-     */
-    public void setMasterVolume(int index, int flags) {
-        IAudioService service = getService();
-        try {
-            service.setMasterVolume(index, flags, mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterVolume", e);
-        }
-    }
-
-    /**
-     * Solo or unsolo a particular stream. All other streams are muted.
+     * Solo or unsolo a particular stream.
      * <p>
-     * The solo command is protected against client process death: if a process
-     * with an active solo request on a stream dies, all streams that were muted
-     * because of this request will be unmuted automatically.
-     * <p>
-     * The solo requests for a given stream are cumulative: the AudioManager
-     * can receive several solo requests from one or more clients and the stream
-     * will be unsoloed only when the same number of unsolo requests are received.
-     * <p>
-     * For a better user experience, applications MUST unsolo a soloed stream
-     * in onPause() and solo is again in onResume() if appropriate.
-     * <p>This method has no effect if the device implements a fixed volume policy
-     * as indicated by {@link #isVolumeFixed()}.
+     * Do not use. This method has been deprecated and is now a no-op.
+     * {@link #requestAudioFocus} should be used for exclusive audio playback.
      *
      * @param streamType The stream to be soloed/unsoloed.
-     * @param state The required solo state: true for solo ON, false for solo OFF
-     *
+     * @param state The required solo state: true for solo ON, false for solo
+     *            OFF
      * @see #isVolumeFixed()
+     * @deprecated Do not use. If you need exclusive audio playback use
+     *             {@link #requestAudioFocus}.
      */
+    @Deprecated
     public void setStreamSolo(int streamType, boolean state) {
-        IAudioService service = getService();
-        try {
-            service.setStreamSolo(streamType, state, mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setStreamSolo", e);
-        }
+        Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
     }
 
     /**
      * Mute or unmute an audio stream.
      * <p>
-     * The mute command is protected against client process death: if a process
-     * with an active mute request on a stream dies, this stream will be unmuted
-     * automatically.
+     * This method should only be used by applications that replace the
+     * platform-wide management of audio settings or the main telephony
+     * application.
      * <p>
-     * The mute requests for a given stream are cumulative: the AudioManager
-     * can receive several mute requests from one or more clients and the stream
-     * will be unmuted only when the same number of unmute requests are received.
-     * <p>
-     * For a better user experience, applications MUST unmute a muted stream
-     * in onPause() and mute is again in onResume() if appropriate.
-     * <p>
-     * This method should only be used by applications that replace the platform-wide
-     * management of audio settings or the main telephony application.
-     * <p>This method has no effect if the device implements a fixed volume policy
+     * This method has no effect if the device implements a fixed volume policy
      * as indicated by {@link #isVolumeFixed()}.
+     * <p>
+     * This method was deprecated in API level 22. Prior to API level 22 this
+     * method had significantly different behavior and should be used carefully.
+     * The following applies only to pre-22 platforms:
+     * <ul>
+     * <li>The mute command is protected against client process death: if a
+     * process with an active mute request on a stream dies, this stream will be
+     * unmuted automatically.</li>
+     * <li>The mute requests for a given stream are cumulative: the AudioManager
+     * can receive several mute requests from one or more clients and the stream
+     * will be unmuted only when the same number of unmute requests are
+     * received.</li>
+     * <li>For a better user experience, applications MUST unmute a muted stream
+     * in onPause() and mute is again in onResume() if appropriate.</li>
+     * </ul>
      *
      * @param streamType The stream to be muted/unmuted.
-     * @param state The required mute state: true for mute ON, false for mute OFF
-     *
+     * @param state The required mute state: true for mute ON, false for mute
+     *            OFF
      * @see #isVolumeFixed()
+     * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
+     *             {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
      */
+    @Deprecated
     public void setStreamMute(int streamType, boolean state) {
-        IAudioService service = getService();
-        try {
-            service.setStreamMute(streamType, state, mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setStreamMute", e);
+        Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
+        int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
+        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+            adjustSuggestedStreamVolume(direction, streamType, 0);
+        } else {
+            adjustStreamVolume(streamType, direction, 0);
         }
     }
 
     /**
-     * get stream mute state.
+     * Returns the current mute state for a particular stream.
      *
-     * @hide
+     * @param streamType The stream to get mute state for.
+     * @return The mute state for the given stream.
+     * @see #adjustStreamVolume(int, int, int)
      */
     public boolean isStreamMute(int streamType) {
         IAudioService service = getService();
@@ -1228,29 +1057,6 @@
     }
 
     /**
-     * set master mute state.
-     *
-     * @hide
-     */
-    public void setMasterMute(boolean state) {
-        setMasterMute(state, FLAG_SHOW_UI);
-    }
-
-    /**
-     * set master mute state with optional flags.
-     *
-     * @hide
-     */
-    public void setMasterMute(boolean state, int flags) {
-        IAudioService service = getService();
-        try {
-            service.setMasterMute(state, flags, mContext.getOpPackageName(), mICallBack);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in setMasterMute", e);
-        }
-    }
-
-    /**
      * get master mute state.
      *
      * @hide
@@ -1273,9 +1079,6 @@
      * @hide
      */
     public void forceVolumeControlStream(int streamType) {
-        if (mUseMasterVolume) {
-            return;
-        }
         IAudioService service = getService();
         try {
             service.forceVolumeControlStream(streamType, mICallBack);
@@ -1482,7 +1285,7 @@
      * @see #startBluetoothSco()
     */
     public boolean isBluetoothScoAvailableOffCall() {
-        return mContext.getResources().getBoolean(
+        return mApplicationContext.getResources().getBoolean(
                com.android.internal.R.bool.config_bluetooth_sco_off_call);
     }
 
@@ -1534,7 +1337,8 @@
     public void startBluetoothSco(){
         IAudioService service = getService();
         try {
-            service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion);
+            service.startBluetoothSco(mICallBack,
+                    mApplicationContext.getApplicationInfo().targetSdkVersion);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in startBluetoothSco", e);
         }
@@ -1682,7 +1486,7 @@
     public void setMicrophoneMute(boolean on){
         IAudioService service = getService();
         try {
-            service.setMicrophoneMute(on, mContext.getOpPackageName());
+            service.setMicrophoneMute(on, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMicrophoneMute", e);
         }
@@ -1715,7 +1519,7 @@
     public void setMode(int mode) {
         IAudioService service = getService();
         try {
-            service.setMode(mode, mICallBack);
+            service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMode", e);
         }
@@ -2113,7 +1917,7 @@
      * Settings has an in memory cache, so this is fast.
      */
     private boolean querySoundEffectsEnabled(int user) {
-        return Settings.System.getIntForUser(mContext.getContentResolver(),
+        return Settings.System.getIntForUser(mApplicationContext.getContentResolver(),
                 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
     }
 
@@ -2525,7 +2329,7 @@
         try {
             status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
                     mAudioFocusDispatcher, getIdForAudioFocusListener(l),
-                    mContext.getOpPackageName() /* package name */, flags,
+                    mApplicationContext.getOpPackageName() /* package name */, flags,
                     ap != null ? ap.cb() : null);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
@@ -2549,8 +2353,8 @@
             service.requestAudioFocus(new AudioAttributes.Builder()
                         .setInternalLegacyStreamType(streamType).build(),
                     durationHint, mICallBack, null,
-                    MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
-                    mContext.getOpPackageName(),
+                    AudioSystem.IN_VOICE_COMM_FOCUS_ID,
+                    mApplicationContext.getOpPackageName(),
                     AUDIOFOCUS_FLAG_LOCK,
                     null /* policy token */);
         } catch (RemoteException e) {
@@ -2567,7 +2371,7 @@
     public void abandonAudioFocusForCall() {
         IAudioService service = getService();
         try {
-            service.abandonAudioFocus(null, MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
+            service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
                     null /*AudioAttributes, legacy behavior*/);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService:", e);
@@ -2619,7 +2423,7 @@
         if (eventReceiver == null) {
             return;
         }
-        if (!eventReceiver.getPackageName().equals(mContext.getPackageName())) {
+        if (!eventReceiver.getPackageName().equals(mApplicationContext.getPackageName())) {
             Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
                     "receiver and context package names don't match");
             return;
@@ -2628,7 +2432,7 @@
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         //     the associated intent will be handled by the component being registered
         mediaButtonIntent.setComponent(eventReceiver);
-        PendingIntent pi = PendingIntent.getBroadcast(mContext,
+        PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
                 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
         registerMediaButtonIntent(pi, eventReceiver);
     }
@@ -2662,8 +2466,8 @@
             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
             return;
         }
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
-        helper.addMediaButtonListener(pi, eventReceiver, mContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
+        helper.addMediaButtonListener(pi, eventReceiver, mApplicationContext);
     }
 
     /**
@@ -2681,7 +2485,7 @@
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         //     the associated intent will be handled by the component being registered
         mediaButtonIntent.setComponent(eventReceiver);
-        PendingIntent pi = PendingIntent.getBroadcast(mContext,
+        PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
                 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
         unregisterMediaButtonIntent(pi);
     }
@@ -2704,7 +2508,7 @@
      * @hide
      */
     public void unregisterMediaButtonIntent(PendingIntent pi) {
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
         helper.removeMediaButtonListener(pi);
     }
 
@@ -2721,7 +2525,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
+        rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
     }
 
     /**
@@ -2736,7 +2540,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
+        rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
     }
 
     /**
@@ -2744,7 +2548,7 @@
      * metadata updates and playback state information from applications using
      * {@link RemoteControlClient}, and control their playback.
      * <p>
-     * Registration requires the {@link OnClientUpdateListener} listener to be
+     * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
      * one of the enabled notification listeners (see
      * {@link android.service.notification.NotificationListenerService}).
      *
@@ -3251,10 +3055,11 @@
      * @param name   device name
      * {@hide}
      */
-    public void setWiredDeviceConnectionState(int device, int state, String name) {
+    public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
         IAudioService service = getService();
         try {
-            service.setWiredDeviceConnectionState(device, state, name);
+            service.setWiredDeviceConnectionState(type, state, address, name,
+                    mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
         }
@@ -3383,9 +3188,22 @@
      * Only useful for volume controllers.
      * @hide
      */
+    public boolean isStreamAffectedByMute(int streamType) {
+        try {
+            return getService().isStreamAffectedByMute(streamType);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error calling isStreamAffectedByMute", e);
+            return false;
+        }
+    }
+
+    /**
+     * Only useful for volume controllers.
+     * @hide
+     */
     public void disableSafeMediaVolume() {
         try {
-            getService().disableSafeMediaVolume();
+            getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "Error disabling safe media volume", e);
         }
@@ -3397,7 +3215,7 @@
      */
     public void setRingerModeInternal(int ringerMode) {
         try {
-            getService().setRingerModeInternal(ringerMode, mContext.getOpPackageName());
+            getService().setRingerModeInternal(ringerMode, mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "Error calling setRingerModeInternal", e);
         }
@@ -3417,6 +3235,18 @@
     }
 
     /**
+     * Only useful for volume controllers.
+     * @hide
+     */
+    public void setVolumePolicy(VolumePolicy policy) {
+        try {
+            getService().setVolumePolicy(policy);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error calling setVolumePolicy", e);
+        }
+    }
+
+    /**
      * Set Hdmi Cec system audio mode.
      *
      * @param on whether to be on system audio mode
@@ -3495,14 +3325,14 @@
      * @see listAudioPorts(ArrayList<AudioPort>)
      * @hide
      */
-    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+    public int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
         int status = updateAudioPortCache(ports, null);
         if (status == SUCCESS) {
             devices.clear();
             for (int i = 0; i < ports.size(); i++) {
                 if (ports.get(i) instanceof AudioDevicePort) {
-                    devices.add(ports.get(i));
+                    devices.add((AudioDevicePort)ports.get(i));
                 }
             }
         }
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 616bdd1..abb4257 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -15,8 +15,6 @@
  */
 package android.media;
 
-import android.os.IBinder;
-
 import com.android.server.LocalServices;
 
 /**
@@ -29,8 +27,7 @@
 public abstract class AudioManagerInternal {
 
     public abstract void adjustSuggestedStreamVolumeForUid(int streamType, int direction,
-            int flags,
-            String callingPackage, int uid);
+            int flags, String callingPackage, int uid);
 
     public abstract void adjustStreamVolumeForUid(int streamType, int direction, int flags,
             String callingPackage, int uid);
@@ -38,25 +35,21 @@
     public abstract void setStreamVolumeForUid(int streamType, int direction, int flags,
             String callingPackage, int uid);
 
-    public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
-            int uid);
-
-    public abstract void setMasterMuteForUid(boolean state, int flags, String callingPackage,
-            IBinder cb, int uid);
-
     public abstract void setRingerModeDelegate(RingerModeDelegate delegate);
 
     public abstract int getRingerModeInternal();
 
     public abstract void setRingerModeInternal(int ringerMode, String caller);
 
+    public abstract int getVolumeControllerUid();
+
     public interface RingerModeDelegate {
         /** Called when external ringer mode is evaluated, returns the new internal ringer mode */
         int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
-                int ringerModeInternal);
+                int ringerModeInternal, VolumePolicy policy);
 
         /** Called when internal ringer mode is evaluated, returns the new external ringer mode */
         int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
-                int ringerModeExternal);
+                int ringerModeExternal, VolumePolicy policy);
     }
 }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
index 1500a43..9fac8d1 100644
--- a/media/java/android/media/AudioMixPort.java
+++ b/media/java/android/media/AudioMixPort.java
@@ -26,9 +26,10 @@
 
 public class AudioMixPort extends AudioPort {
 
-    AudioMixPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+    AudioMixPort(AudioHandle handle, int role, String deviceName,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains) {
-        super(handle, role, samplingRates, channelMasks, formats, gains);
+        super(handle, role, deviceName, samplingRates, channelMasks, formats, gains);
     }
 
     /**
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
index 1ab7e89..88e784a 100644
--- a/media/java/android/media/AudioPort.java
+++ b/media/java/android/media/AudioPort.java
@@ -16,7 +16,6 @@
 
 package android.media;
 
-
 /**
  * An audio port is a node of the audio framework or hardware that can be connected to or
  * disconnect from another audio node to create a specific audio routing configuration.
@@ -37,6 +36,7 @@
  * @hide
  */
 public class AudioPort {
+    private static final String TAG = "AudioPort";
 
     /**
      * For use by the audio framework.
@@ -68,16 +68,20 @@
 
     AudioHandle mHandle;
     protected final int mRole;
+    private final String mName;
     private final int[] mSamplingRates;
     private final int[] mChannelMasks;
     private final int[] mFormats;
     private final AudioGain[] mGains;
     private AudioPortConfig mActiveConfig;
 
-    AudioPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+    AudioPort(AudioHandle handle, int role, String name,
+            int[] samplingRates, int[] channelMasks,
             int[] formats, AudioGain[] gains) {
+
         mHandle = handle;
         mRole = role;
+        mName = name;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
         mFormats = formats;
@@ -96,6 +100,14 @@
     }
 
     /**
+     * Get the human-readable name of this port. Perhaps an internal
+     * designation or an physical device.
+     */
+    public String name() {
+        return mName;
+    }
+
+    /**
      * Get the list of supported sampling rates
      * Empty array if sampling rate is not relevant for this audio port
      */
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index ba2a59d..c05fd77 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -19,8 +19,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
-
 import java.util.ArrayList;
 import java.lang.ref.WeakReference;
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index de10ef9..259fe37 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,6 +20,7 @@
 import java.nio.ByteBuffer;
 import java.util.Iterator;
 
+import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -238,7 +239,6 @@
 
     /**
      * @hide
-     * CANDIDATE FOR PUBLIC API
      * Class constructor with {@link AudioAttributes} and {@link AudioFormat}.
      * @param attributes a non-null {@link AudioAttributes} instance. Use
      *     {@link AudioAttributes.Builder#setCapturePreset(int)} for configuring the capture
@@ -257,6 +257,7 @@
      *   construction.
      * @throws IllegalArgumentException
      */
+    @SystemApi
     public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
             int sessionId) throws IllegalArgumentException {
         mRecordingState = RECORDSTATE_STOPPED;
@@ -376,7 +377,7 @@
         // audio source
         if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) ||
              ((audioSource > MediaRecorder.getAudioSourceMax()) &&
-              (audioSource != MediaRecorder.AudioSource.FM_TUNER) &&
+              (audioSource != MediaRecorder.AudioSource.RADIO_TUNER) &&
               (audioSource != MediaRecorder.AudioSource.HOTWORD)) )  {
             throw new IllegalArgumentException("Invalid audio source.");
         }
diff --git a/media/java/android/media/AudioRoutesInfo.java b/media/java/android/media/AudioRoutesInfo.java
index df9fc06..6ae0d46 100644
--- a/media/java/android/media/AudioRoutesInfo.java
+++ b/media/java/android/media/AudioRoutesInfo.java
@@ -25,26 +25,27 @@
  * @hide
  */
 public class AudioRoutesInfo implements Parcelable {
-    static final int MAIN_SPEAKER = 0;
-    static final int MAIN_HEADSET = 1<<0;
-    static final int MAIN_HEADPHONES = 1<<1;
-    static final int MAIN_DOCK_SPEAKERS = 1<<2;
-    static final int MAIN_HDMI = 1<<3;
+    public static final int MAIN_SPEAKER = 0;
+    public static final int MAIN_HEADSET = 1<<0;
+    public static final int MAIN_HEADPHONES = 1<<1;
+    public static final int MAIN_DOCK_SPEAKERS = 1<<2;
+    public static final int MAIN_HDMI = 1<<3;
+    public static final int MAIN_USB = 1<<4;
 
-    CharSequence mBluetoothName;
-    int mMainType = MAIN_SPEAKER;
+    public CharSequence bluetoothName;
+    public int mainType = MAIN_SPEAKER;
 
     public AudioRoutesInfo() {
     }
 
     public AudioRoutesInfo(AudioRoutesInfo o) {
-        mBluetoothName = o.mBluetoothName;
-        mMainType = o.mMainType;
+        bluetoothName = o.bluetoothName;
+        mainType = o.mainType;
     }
 
     AudioRoutesInfo(Parcel src) {
-        mBluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
-        mMainType = src.readInt();
+        bluetoothName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+        mainType = src.readInt();
     }
 
     @Override
@@ -54,8 +55,8 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        TextUtils.writeToParcel(mBluetoothName, dest, flags);
-        dest.writeInt(mMainType);
+        TextUtils.writeToParcel(bluetoothName, dest, flags);
+        dest.writeInt(mainType);
     }
 
     public static final Parcelable.Creator<AudioRoutesInfo> CREATOR
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
deleted file mode 100644
index 38a5b40..0000000
--- a/media/java/android/media/AudioService.java
+++ /dev/null
@@ -1,6005 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
-import static android.media.AudioManager.RINGER_MODE_NORMAL;
-import static android.media.AudioManager.RINGER_MODE_SILENT;
-import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.AppOpsManager;
-import android.app.KeyguardManager;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.database.ContentObserver;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.HdmiPlaybackClient;
-import android.hardware.hdmi.HdmiTvClient;
-import android.hardware.usb.UsbManager;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.audiopolicy.AudioMix;
-import android.media.audiopolicy.AudioPolicy;
-import android.media.audiopolicy.AudioPolicyConfig;
-import android.media.audiopolicy.IAudioPolicyCallback;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.provider.Settings.System;
-import android.telecom.TelecomManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
-import android.view.KeyEvent;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.util.XmlUtils;
-import com.android.server.LocalServices;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * The implementation of the volume manager service.
- * <p>
- * This implementation focuses on delivering a responsive UI. Most methods are
- * asynchronous to external calls. For example, the task of setting a volume
- * will update our internal state, but in a separate thread will set the system
- * volume and later persist to the database. Similarly, setting the ringer mode
- * will update the state and broadcast a change and in a separate thread later
- * persist the ringer mode.
- *
- * @hide
- */
-public class AudioService extends IAudioService.Stub {
-
-    private static final String TAG = "AudioService";
-
-    /** Debug audio mode */
-    protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
-
-    /** Debug audio policy feature */
-    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
-
-    /** Debug volumes */
-    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
-
-    /** debug calls to media session apis */
-    private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
-
-    /** Allow volume changes to set ringer mode to silent? */
-    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
-
-    /** In silent mode, are volume adjustments (raises) prevented? */
-    private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
-
-    /** How long to delay before persisting a change in volume/ringer mode. */
-    private static final int PERSIST_DELAY = 500;
-
-    /**
-     * The delay before playing a sound. This small period exists so the user
-     * can press another key (non-volume keys, too) to have it NOT be audible.
-     * <p>
-     * PhoneWindow will implement this part.
-     */
-    public static final int PLAY_SOUND_DELAY = 300;
-
-    /**
-     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
-     */
-    private static final int FLAG_ADJUST_VOLUME = 1;
-
-    private final Context mContext;
-    private final ContentResolver mContentResolver;
-    private final AppOpsManager mAppOps;
-
-    // the platform has no specific capabilities
-    private static final int PLATFORM_DEFAULT = 0;
-    // the platform is voice call capable (a phone)
-    private static final int PLATFORM_VOICE = 1;
-    // the platform is a television or a set-top box
-    private static final int PLATFORM_TELEVISION = 2;
-    // the platform type affects volume and silent mode behavior
-    private final int mPlatformType;
-
-    private boolean isPlatformVoice() {
-        return mPlatformType == PLATFORM_VOICE;
-    }
-
-    private boolean isPlatformTelevision() {
-        return mPlatformType == PLATFORM_TELEVISION;
-    }
-
-    /** The controller for the volume UI. */
-    private final VolumeController mVolumeController = new VolumeController();
-
-    // sendMsg() flags
-    /** 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. */
-    private static final int SENDMSG_NOOP = 1;
-    /** If the msg is already queued, queue this one and leave the old. */
-    private static final int SENDMSG_QUEUE = 2;
-
-    // AudioHandler messages
-    private static final int MSG_SET_DEVICE_VOLUME = 0;
-    private static final int MSG_PERSIST_VOLUME = 1;
-    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
-    private static final int MSG_PERSIST_RINGER_MODE = 3;
-    private static final int MSG_MEDIA_SERVER_DIED = 4;
-    private static final int MSG_PLAY_SOUND_EFFECT = 5;
-    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
-    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
-    private static final int MSG_SET_FORCE_USE = 8;
-    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
-    private static final int MSG_SET_ALL_VOLUMES = 10;
-    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
-    private static final int MSG_REPORT_NEW_ROUTES = 12;
-    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
-    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
-    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
-    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
-    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
-    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
-    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
-    private static final int MSG_SYSTEM_READY = 21;
-    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
-    private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
-    // start of messages handled under wakelock
-    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
-    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
-    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
-    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
-    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
-    // end of messages handled under wakelock
-
-    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
-    // Timeout for connection to bluetooth headset service
-    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
-
-    /** @see AudioSystemThread */
-    private AudioSystemThread mAudioSystemThread;
-    /** @see AudioHandler */
-    private AudioHandler mAudioHandler;
-    /** @see VolumeStreamState */
-    private VolumeStreamState[] mStreamStates;
-    private SettingsObserver mSettingsObserver;
-
-    private int mMode = AudioSystem.MODE_NORMAL;
-    // protects mRingerMode
-    private final Object mSettingsLock = new Object();
-
-    private SoundPool mSoundPool;
-    private final Object mSoundEffectsLock = new Object();
-    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
-
-    // Internally master volume is a float in the 0.0 - 1.0 range,
-    // but to support integer based AudioManager API we translate it to 0 - 100
-    private static final int MAX_MASTER_VOLUME = 100;
-
-    // Maximum volume adjust steps allowed in a single batch call.
-    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
-
-    /* Sound effect file names  */
-    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
-    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
-
-    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
-     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
-     * uses soundpool (second column) */
-    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
-
-   /** @hide Maximum volume index values for audio streams */
-    private static int[] MAX_STREAM_VOLUME = new int[] {
-        5,  // STREAM_VOICE_CALL
-        7,  // STREAM_SYSTEM
-        7,  // STREAM_RING
-        15, // STREAM_MUSIC
-        7,  // STREAM_ALARM
-        7,  // STREAM_NOTIFICATION
-        15, // STREAM_BLUETOOTH_SCO
-        7,  // STREAM_SYSTEM_ENFORCED
-        15, // STREAM_DTMF
-        15  // STREAM_TTS
-    };
-
-    private static int[] DEFAULT_STREAM_VOLUME = new int[] {
-        4,  // STREAM_VOICE_CALL
-        7,  // STREAM_SYSTEM
-        5,  // STREAM_RING
-        11, // STREAM_MUSIC
-        6,  // STREAM_ALARM
-        5,  // STREAM_NOTIFICATION
-        7,  // STREAM_BLUETOOTH_SCO
-        7,  // STREAM_SYSTEM_ENFORCED
-        11, // STREAM_DTMF
-        11  // STREAM_TTS
-    };
-
-    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
-     * of another stream: This avoids multiplying the volume settings for hidden
-     * stream types that follow other stream behavior for volume settings
-     * NOTE: do not create loops in aliases!
-     * Some streams alias to different streams according to device category (phone or tablet) or
-     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
-     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
-     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
-     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
-    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
-        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
-        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
-        AudioSystem.STREAM_RING,            // STREAM_RING
-        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
-        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
-        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
-        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
-        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
-        AudioSystem.STREAM_RING,            // STREAM_DTMF
-        AudioSystem.STREAM_MUSIC            // STREAM_TTS
-    };
-    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
-        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
-        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
-        AudioSystem.STREAM_MUSIC,       // STREAM_RING
-        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
-        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
-        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
-        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
-        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
-        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
-        AudioSystem.STREAM_MUSIC        // STREAM_TTS
-    };
-    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
-        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
-        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
-        AudioSystem.STREAM_RING,            // STREAM_RING
-        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
-        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
-        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
-        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
-        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
-        AudioSystem.STREAM_RING,            // STREAM_DTMF
-        AudioSystem.STREAM_MUSIC            // STREAM_TTS
-    };
-    private int[] mStreamVolumeAlias;
-
-    /**
-     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
-     * after mapping through mStreamVolumeAlias.
-     */
-    private static final int[] STEAM_VOLUME_OPS = new int[] {
-        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
-        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
-        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
-        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
-        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
-        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
-        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
-        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
-        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
-        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
-    };
-
-    private final boolean mUseFixedVolume;
-
-    // stream names used by dumpStreamStates()
-    private static final String[] STREAM_NAMES = new String[] {
-            "STREAM_VOICE_CALL",
-            "STREAM_SYSTEM",
-            "STREAM_RING",
-            "STREAM_MUSIC",
-            "STREAM_ALARM",
-            "STREAM_NOTIFICATION",
-            "STREAM_BLUETOOTH_SCO",
-            "STREAM_SYSTEM_ENFORCED",
-            "STREAM_DTMF",
-            "STREAM_TTS"
-    };
-
-    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
-        public void onError(int error) {
-            switch (error) {
-            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
-                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
-                        SENDMSG_NOOP, 0, 0, null, 0);
-                break;
-            default:
-                break;
-            }
-        }
-    };
-
-    /**
-     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
-     * {@link AudioManager#RINGER_MODE_SILENT}, or
-     * {@link AudioManager#RINGER_MODE_VIBRATE}.
-     */
-    // protected by mSettingsLock
-    private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
-    private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)
-
-    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
-    private int mRingerModeAffectedStreams = 0;
-
-    // Streams currently muted by ringer mode
-    private int mRingerModeMutedStreams;
-
-    /** @see System#MUTE_STREAMS_AFFECTED */
-    private int mMuteAffectedStreams;
-
-    /**
-     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
-     * mVibrateSetting is just maintained during deprecation period but vibration policy is
-     * now only controlled by mHasVibrator and mRingerMode
-     */
-    private int mVibrateSetting;
-
-    // Is there a vibrator
-    private final boolean mHasVibrator;
-
-    // Broadcast receiver for device connections intent broadcasts
-    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
-
-    // Devices currently connected
-    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
-
-    // Forced device usage for communications
-    private int mForcedUseForComm;
-
-    // True if we have master volume support
-    private final boolean mUseMasterVolume;
-
-    private final int[] mMasterVolumeRamp;
-
-    // List of binder death handlers for setMode() client processes.
-    // The last process to have called setMode() is at the top of the list.
-    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
-
-    // List of clients having issued a SCO start request
-    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
-
-    // BluetoothHeadset API to control SCO connection
-    private BluetoothHeadset mBluetoothHeadset;
-
-    // Bluetooth headset device
-    private BluetoothDevice mBluetoothHeadsetDevice;
-
-    // Indicate if SCO audio connection is currently active and if the initiator is
-    // audio service (internal) or bluetooth headset (external)
-    private int mScoAudioState;
-    // SCO audio state is not active
-    private static final int SCO_STATE_INACTIVE = 0;
-    // SCO audio activation request waiting for headset service to connect
-    private static final int SCO_STATE_ACTIVATE_REQ = 1;
-    // SCO audio state is active or starting due to a request from AudioManager API
-    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
-    // SCO audio deactivation request waiting for headset service to connect
-    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
-
-    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
-    // in call audio)
-    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
-    // Deactivation request for all SCO connections (initiated by audio mode change)
-    // waiting for headset service to connect
-    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
-
-    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
-    // originated from an app targeting an API version before JB MR2 and raw audio after that.
-    private int mScoAudioMode;
-    // SCO audio mode is undefined
-    private static final int SCO_MODE_UNDEFINED = -1;
-    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
-    private static final int SCO_MODE_VIRTUAL_CALL = 0;
-    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
-    private static final int SCO_MODE_RAW = 1;
-    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
-    private static final int SCO_MODE_VR = 2;
-
-    private static final int SCO_MODE_MAX = 2;
-
-    // Current connection state indicated by bluetooth headset
-    private int mScoConnectionState;
-
-    // true if boot sequence has been completed
-    private boolean mSystemReady;
-    // listener for SoundPool sample load completion indication
-    private SoundPoolCallback mSoundPoolCallBack;
-    // thread for SoundPool listener
-    private SoundPoolListenerThread mSoundPoolListenerThread;
-    // message looper for SoundPool listener
-    private Looper mSoundPoolLooper = null;
-    // volume applied to sound played with playSoundEffect()
-    private static int sSoundEffectVolumeDb;
-    // previous volume adjustment direction received by checkForRingerModeChange()
-    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
-    // Keyguard manager proxy
-    private KeyguardManager mKeyguardManager;
-    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
-    // is controlled by Vol keys.
-    private int  mVolumeControlStream = -1;
-    private final Object mForceControlStreamLock = new Object();
-    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
-    // server process so in theory it is not necessary to monitor the client death.
-    // However it is good to be ready for future evolutions.
-    private ForceControlStreamClient mForceControlStreamClient = null;
-    // Used to play ringtones outside system_server
-    private volatile IRingtonePlayer mRingtonePlayer;
-
-    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-    private int mDeviceRotation = Surface.ROTATION_0;
-
-    // Request to override default use of A2DP for media.
-    private boolean mBluetoothA2dpEnabled;
-    private final Object mBluetoothA2dpEnabledLock = new Object();
-
-    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
-    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
-    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
-            = new RemoteCallbackList<IAudioRoutesObserver>();
-
-    // Devices for which the volume is fixed and VolumePanel slider should be disabled
-    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
-            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_HDMI_ARC |
-            AudioSystem.DEVICE_OUT_SPDIF |
-            AudioSystem.DEVICE_OUT_AUX_LINE;
-    int mFullVolumeDevices = 0;
-
-    // TODO merge orientation and rotation
-    private final boolean mMonitorOrientation;
-    private final boolean mMonitorRotation;
-
-    private boolean mDockAudioMediaEnabled = true;
-
-    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-
-    // Used when safe volume warning message display is requested by setStreamVolume(). In this
-    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
-    // and used later when/if disableSafeMediaVolume() is called.
-    private StreamVolumeCommand mPendingVolumeCommand;
-
-    private PowerManager.WakeLock mAudioEventWakeLock;
-
-    private final MediaFocusControl mMediaFocusControl;
-
-    // Reference to BluetoothA2dp to query for AbsoluteVolume.
-    private BluetoothA2dp mA2dp;
-    private final Object mA2dpAvrcpLock = new Object();
-    // If absolute volume is supported in AVRCP device
-    private boolean mAvrcpAbsVolSupported = false;
-
-    private AudioOrientationEventListener mOrientationListener;
-
-    private static Long mLastDeviceConnectMsgTime = new Long(0);
-
-    private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Construction
-    ///////////////////////////////////////////////////////////////////////////
-
-    /** @hide */
-    public AudioService(Context context) {
-        mContext = context;
-        mContentResolver = context.getContentResolver();
-        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_voice_capable)) {
-            mPlatformType = PLATFORM_VOICE;
-        } else if (context.getPackageManager().hasSystemFeature(
-                                                            PackageManager.FEATURE_LEANBACK)) {
-            mPlatformType = PLATFORM_TELEVISION;
-        } else {
-            mPlatformType = PLATFORM_DEFAULT;
-        }
-
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
-
-        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
-
-       // Intialized volume
-        int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
-                MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
-        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
-            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
-            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
-        }
-        maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
-                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
-        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
-            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
-            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
-        }
-
-        sSoundEffectVolumeDb = context.getResources().getInteger(
-                com.android.internal.R.integer.config_soundEffectVolumeDb);
-
-        mForcedUseForComm = AudioSystem.FORCE_NONE;
-
-        createAudioSystemThread();
-
-        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
-                mContext, mVolumeController, this);
-
-        AudioSystem.setErrorCallback(mAudioSystemCallback);
-
-        boolean cameraSoundForced = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_camera_sound_forced);
-        mCameraSoundForced = new Boolean(cameraSoundForced);
-        sendMsg(mAudioHandler,
-                MSG_SET_FORCE_USE,
-                SENDMSG_QUEUE,
-                AudioSystem.FOR_SYSTEM,
-                cameraSoundForced ?
-                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
-                null,
-                0);
-
-        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
-                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
-                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
-        // The default safe volume index read here will be replaced by the actual value when
-        // the mcc is read by onConfigureSafeVolume()
-        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
-
-        mUseFixedVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useFixedVolume);
-        mUseMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
-        mMasterVolumeRamp = context.getResources().getIntArray(
-                com.android.internal.R.array.config_masterVolumeRamp);
-
-        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
-        // array initialized by updateStreamVolumeAlias()
-        updateStreamVolumeAlias(false /*updateVolumes*/);
-        readPersistedSettings();
-        mSettingsObserver = new SettingsObserver();
-        createStreamStates();
-
-        readAndSetLowRamDevice();
-
-        // Call setRingerModeInt() to apply correct mute
-        // state on streams affected by ringer mode.
-        mRingerModeMutedStreams = 0;
-        setRingerModeInt(getRingerModeInternal(), false);
-
-        // Register for device connection intent broadcasts.
-        IntentFilter intentFilter =
-                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
-        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
-        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
-        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
-        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
-
-        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        // TODO merge orientation and rotation
-        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
-        if (mMonitorOrientation) {
-            Log.v(TAG, "monitoring device orientation");
-            // initialize orientation in AudioSystem
-            setOrientationForAudioSystem();
-        }
-        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
-        if (mMonitorRotation) {
-            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
-                    .getDefaultDisplay().getRotation();
-            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
-
-            mOrientationListener = new AudioOrientationEventListener(mContext);
-            mOrientationListener.enable();
-
-            // initialize rotation in AudioSystem
-            setRotationForAudioSystem();
-        }
-
-        context.registerReceiver(mReceiver, intentFilter);
-
-        restoreMasterVolume();
-
-        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
-    }
-
-    public void systemReady() {
-        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
-                0, 0, null, 0);
-    }
-
-    public void onSystemReady() {
-        mSystemReady = true;
-        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
-                0, 0, null, 0);
-
-        mKeyguardManager =
-                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
-        resetBluetoothSco();
-        getBluetoothHeadset();
-        //FIXME: this is to maintain compatibility with deprecated intent
-        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
-        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
-        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
-                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-        sendStickyBroadcastToAll(newIntent);
-
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                    BluetoothProfile.A2DP);
-        }
-
-        mHdmiManager =
-                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
-        if (mHdmiManager != null) {
-            synchronized (mHdmiManager) {
-                mHdmiTvClient = mHdmiManager.getTvClient();
-                if (mHdmiTvClient != null) {
-                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
-                }
-                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
-                mHdmiCecSink = false;
-            }
-        }
-
-        sendMsg(mAudioHandler,
-                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
-                SENDMSG_REPLACE,
-                0,
-                0,
-                null,
-                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
-
-        StreamOverride.init(mContext);
-    }
-
-    private void createAudioSystemThread() {
-        mAudioSystemThread = new AudioSystemThread();
-        mAudioSystemThread.start();
-        waitForAudioHandlerCreation();
-    }
-
-    /** Waits for the volume handler to be created by the other thread. */
-    private void waitForAudioHandlerCreation() {
-        synchronized(this) {
-            while (mAudioHandler == null) {
-                try {
-                    // Wait for mAudioHandler to be set by the other thread
-                    wait();
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "Interrupted while waiting on volume handler.");
-                }
-            }
-        }
-    }
-
-    private void checkAllAliasStreamVolumes() {
-        synchronized (VolumeStreamState.class) {
-            int numStreamTypes = AudioSystem.getNumStreamTypes();
-            for (int streamType = 0; streamType < numStreamTypes; streamType++) {
-                if (streamType != mStreamVolumeAlias[streamType]) {
-                    mStreamStates[streamType].
-                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
-                }
-                // apply stream volume
-                if (!mStreamStates[streamType].isMuted_syncVSS()) {
-                    mStreamStates[streamType].applyAllVolumes();
-                }
-            }
-        }
-    }
-
-    private void checkAllFixedVolumeDevices()
-    {
-        int numStreamTypes = AudioSystem.getNumStreamTypes();
-        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
-            mStreamStates[streamType].checkFixedVolumeDevices();
-        }
-    }
-
-    private void checkAllFixedVolumeDevices(int streamType) {
-        mStreamStates[streamType].checkFixedVolumeDevices();
-    }
-
-    private void createStreamStates() {
-        int numStreamTypes = AudioSystem.getNumStreamTypes();
-        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
-
-        for (int i = 0; i < numStreamTypes; i++) {
-            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
-        }
-
-        checkAllFixedVolumeDevices();
-        checkAllAliasStreamVolumes();
-    }
-
-    private void dumpStreamStates(PrintWriter pw) {
-        pw.println("\nStream volumes (device: index)");
-        int numStreamTypes = AudioSystem.getNumStreamTypes();
-        for (int i = 0; i < numStreamTypes; i++) {
-            pw.println("- "+STREAM_NAMES[i]+":");
-            mStreamStates[i].dump(pw);
-            pw.println("");
-        }
-        pw.print("\n- mute affected streams = 0x");
-        pw.println(Integer.toHexString(mMuteAffectedStreams));
-    }
-
-    /** @hide */
-    public static String streamToString(int stream) {
-        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
-        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
-        return "UNKNOWN_STREAM_" + stream;
-    }
-
-    private void updateStreamVolumeAlias(boolean updateVolumes) {
-        int dtmfStreamAlias;
-
-        switch (mPlatformType) {
-        case PLATFORM_VOICE:
-            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
-            dtmfStreamAlias = AudioSystem.STREAM_RING;
-            break;
-        case PLATFORM_TELEVISION:
-            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
-            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
-            break;
-        default:
-            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
-            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
-        }
-
-        if (isPlatformTelevision()) {
-            mRingerModeAffectedStreams = 0;
-        } else {
-            if (isInCommunication()) {
-                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
-                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
-            } else {
-                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
-            }
-        }
-
-        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
-        if (updateVolumes) {
-            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
-            // apply stream mute states according to new value of mRingerModeAffectedStreams
-            setRingerModeInt(getRingerModeInternal(), false);
-            sendMsg(mAudioHandler,
-                    MSG_SET_ALL_VOLUMES,
-                    SENDMSG_QUEUE,
-                    0,
-                    0,
-                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
-        }
-    }
-
-    private void readDockAudioSettings(ContentResolver cr)
-    {
-        mDockAudioMediaEnabled = Settings.Global.getInt(
-                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
-
-        if (mDockAudioMediaEnabled) {
-            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
-        } else {
-            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
-        }
-
-        sendMsg(mAudioHandler,
-                MSG_SET_FORCE_USE,
-                SENDMSG_QUEUE,
-                AudioSystem.FOR_DOCK,
-                mDockAudioMediaEnabled ?
-                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
-                null,
-                0);
-    }
-
-    private void readPersistedSettings() {
-        final ContentResolver cr = mContentResolver;
-
-        int ringerModeFromSettings =
-                Settings.Global.getInt(
-                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
-        int ringerMode = ringerModeFromSettings;
-        // sanity check in case the settings are restored from a device with incompatible
-        // ringer modes
-        if (!isValidRingerMode(ringerMode)) {
-            ringerMode = AudioManager.RINGER_MODE_NORMAL;
-        }
-        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
-            ringerMode = AudioManager.RINGER_MODE_SILENT;
-        }
-        if (ringerMode != ringerModeFromSettings) {
-            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
-        }
-        if (mUseFixedVolume || isPlatformTelevision()) {
-            ringerMode = AudioManager.RINGER_MODE_NORMAL;
-        }
-        synchronized(mSettingsLock) {
-            mRingerMode = ringerMode;
-            if (mRingerModeExternal == -1) {
-                mRingerModeExternal = mRingerMode;
-            }
-
-            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
-            // are still needed while setVibrateSetting() and getVibrateSetting() are being
-            // deprecated.
-            mVibrateSetting = getValueForVibrateSetting(0,
-                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
-                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
-                                                            : AudioManager.VIBRATE_SETTING_OFF);
-            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
-                                            AudioManager.VIBRATE_TYPE_RINGER,
-                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
-                                                            : AudioManager.VIBRATE_SETTING_OFF);
-
-            updateRingerModeAffectedStreams();
-            readDockAudioSettings(cr);
-        }
-
-        mMuteAffectedStreams = System.getIntForUser(cr,
-                System.MUTE_STREAMS_AFFECTED,
-                ((1 << AudioSystem.STREAM_MUSIC)|
-                 (1 << AudioSystem.STREAM_RING)|
-                 (1 << AudioSystem.STREAM_SYSTEM)),
-                 UserHandle.USER_CURRENT);
-
-        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
-                                                  0, UserHandle.USER_CURRENT) == 1;
-        if (mUseFixedVolume) {
-            masterMute = false;
-            AudioSystem.setMasterVolume(1.0f);
-        }
-        AudioSystem.setMasterMute(masterMute);
-        broadcastMasterMuteStatus(masterMute);
-
-        boolean microphoneMute =
-                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
-        AudioSystem.muteMicrophone(microphoneMute);
-
-        // Each stream will read its own persisted settings
-
-        // Broadcast the sticky intents
-        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
-        broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
-
-        // Broadcast vibrate settings
-        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
-        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
-
-        // Load settings for the volume controller
-        mVolumeController.loadSettings(cr);
-    }
-
-    private int rescaleIndex(int index, int srcStream, int dstStream) {
-        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
-    }
-
-    private class AudioOrientationEventListener
-            extends OrientationEventListener {
-        public AudioOrientationEventListener(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onOrientationChanged(int orientation) {
-            //Even though we're responding to phone orientation events,
-            //use display rotation so audio stays in sync with video/dialogs
-            int newRotation = ((WindowManager) mContext.getSystemService(
-                    Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
-            if (newRotation != mDeviceRotation) {
-                mDeviceRotation = newRotation;
-                setRotationForAudioSystem();
-            }
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // IPC methods
-    ///////////////////////////////////////////////////////////////////////////
-    /** @see AudioManager#adjustVolume(int, int) */
-    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage) {
-        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
-                Binder.getCallingUid());
-    }
-
-    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage, int uid) {
-        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
-                + ", flags=" + flags);
-        int streamType;
-        if (mVolumeControlStream != -1) {
-            streamType = mVolumeControlStream;
-        } else {
-            streamType = getActiveStreamType(suggestedStreamType);
-        }
-        final int resolvedStream = mStreamVolumeAlias[streamType];
-
-        // Play sounds on STREAM_RING only.
-        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
-                resolvedStream != AudioSystem.STREAM_RING) {
-            flags &= ~AudioManager.FLAG_PLAY_SOUND;
-        }
-
-        // For notifications/ring, show the ui before making any adjustments
-        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
-            direction = 0;
-            flags &= ~AudioManager.FLAG_PLAY_SOUND;
-            flags &= ~AudioManager.FLAG_VIBRATE;
-            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
-        }
-
-        adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
-    }
-
-    /** @see AudioManager#adjustStreamVolume(int, int, int) */
-    public void adjustStreamVolume(int streamType, int direction, int flags,
-            String callingPackage) {
-        adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    private void adjustStreamVolume(int streamType, int direction, int flags,
-            String callingPackage, int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
-                + ", flags="+flags);
-
-        ensureValidDirection(direction);
-        ensureValidStreamType(streamType);
-
-        // use stream type alias here so that streams with same alias have the same behavior,
-        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
-        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
-        int streamTypeAlias = mStreamVolumeAlias[streamType];
-        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
-
-        final int device = getDeviceForStream(streamTypeAlias);
-
-        int aliasIndex = streamState.getIndex(device);
-        boolean adjustVolume = true;
-        int step;
-
-        // skip a2dp absolute volume control request when the device
-        // is not an a2dp device
-        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
-            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
-            return;
-        }
-
-        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-
-        // reset any pending volume command
-        synchronized (mSafeMediaVolumeState) {
-            mPendingVolumeCommand = null;
-        }
-
-        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-               ((device & mFixedVolumeDevices) != 0)) {
-            flags |= AudioManager.FLAG_FIXED_VOLUME;
-
-            // Always toggle between max safe volume and 0 for fixed volume devices where safe
-            // volume is enforced, and max and 0 for the others.
-            // This is simulated by stepping by the full allowed volume range
-            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
-                    (device & mSafeMediaVolumeDevices) != 0) {
-                step = mSafeMediaVolumeIndex;
-            } else {
-                step = streamState.getMaxIndex();
-            }
-            if (aliasIndex != 0) {
-                aliasIndex = step;
-            }
-        } else {
-            // convert one UI step (+/-1) into a number of internal units on the stream alias
-            step = rescaleIndex(10, streamType, streamTypeAlias);
-        }
-
-        // If either the client forces allowing ringer modes for this adjustment,
-        // or the stream type is one that is affected by ringer modes
-        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                (streamTypeAlias == getMasterStreamType())) {
-            int ringerMode = getRingerModeInternal();
-            // do not vibrate if already in vibrate mode
-            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-                flags &= ~AudioManager.FLAG_VIBRATE;
-            }
-            // Check if the ringer mode changes with this volume adjustment. If
-            // it does, it will handle adjusting the volume, so we won't below
-            final int result = checkForRingerModeChange(aliasIndex, direction, step);
-            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
-            // If suppressing a volume adjustment in silent mode, display the UI hint
-            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
-                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
-            }
-            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
-            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
-                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
-            }
-        }
-
-        int oldIndex = mStreamStates[streamType].getIndex(device);
-
-        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
-
-            // Check if volume update should be send to AVRCP
-            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
-                synchronized (mA2dpAvrcpLock) {
-                    if (mA2dp != null && mAvrcpAbsVolSupported) {
-                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
-                    }
-                }
-            }
-
-            if ((direction == AudioManager.ADJUST_RAISE) &&
-                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
-                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
-                mVolumeController.postDisplaySafeVolumeWarning(flags);
-            } else if (streamState.adjustIndex(direction * step, device)) {
-                // Post message to set system volume (it in turn will post a message
-                // to persist). Do not change volume if stream is muted.
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        device,
-                        0,
-                        streamState,
-                        0);
-            }
-
-            // Check if volume update should be send to Hdmi system audio.
-            int newIndex = mStreamStates[streamType].getIndex(device);
-            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
-                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
-            }
-            if (mHdmiManager != null) {
-                synchronized (mHdmiManager) {
-                    // mHdmiCecSink true => mHdmiPlaybackClient != null
-                    if (mHdmiCecSink &&
-                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                            oldIndex != newIndex) {
-                        synchronized (mHdmiPlaybackClient) {
-                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
-                                                               KeyEvent.KEYCODE_VOLUME_UP;
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
-                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
-                        }
-                    }
-                }
-            }
-        }
-        int index = mStreamStates[streamType].getIndex(device);
-        sendVolumeUpdate(streamType, oldIndex, index, flags);
-    }
-
-    private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
-        if (mHdmiManager == null
-                || mHdmiTvClient == null
-                || oldVolume == newVolume
-                || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
-
-        // Sets the audio volume of AVR when we are in system audio mode. The new volume info
-        // is tranformed to HDMI-CEC commands and passed through CEC bus.
-        synchronized (mHdmiManager) {
-            if (!mHdmiSystemAudioSupported) return;
-            synchronized (mHdmiTvClient) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    mHdmiTvClient.setSystemAudioVolume(
-                            (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        }
-    }
-
-    /** @see AudioManager#adjustMasterVolume(int, int) */
-    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
-        adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        ensureValidSteps(steps);
-        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
-        int delta = 0;
-        int numSteps = Math.abs(steps);
-        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
-        for (int i = 0; i < numSteps; ++i) {
-            delta = findVolumeDelta(direction, volume);
-            volume += delta;
-        }
-
-        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
-        setMasterVolume(volume, flags, callingPackage, uid);
-    }
-
-    // StreamVolumeCommand contains the information needed to defer the process of
-    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
-    class StreamVolumeCommand {
-        public final int mStreamType;
-        public final int mIndex;
-        public final int mFlags;
-        public final int mDevice;
-
-        StreamVolumeCommand(int streamType, int index, int flags, int device) {
-            mStreamType = streamType;
-            mIndex = index;
-            mFlags = flags;
-            mDevice = device;
-        }
-
-        @Override
-        public String toString() {
-            return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
-                    .append(mIndex).append(",flags=").append(mFlags).append(",device=")
-                    .append(mDevice).append('}').toString();
-        }
-    };
-
-    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
-        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
-        // setting volume on master stream type also controls silent mode
-        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
-            int newRingerMode;
-            if (index == 0) {
-                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
-                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
-                        : AudioManager.RINGER_MODE_NORMAL;
-            } else {
-                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
-            }
-            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
-        }
-    }
-
-    /** @see AudioManager#setStreamVolume(int, int, int) */
-    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
-        setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
-            int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-
-        ensureValidStreamType(streamType);
-        int streamTypeAlias = mStreamVolumeAlias[streamType];
-        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
-
-        final int device = getDeviceForStream(streamType);
-        int oldIndex;
-
-        // skip a2dp absolute volume control request when the device
-        // is not an a2dp device
-        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
-            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
-            return;
-        }
-
-        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-
-        synchronized (mSafeMediaVolumeState) {
-            // reset any pending volume command
-            mPendingVolumeCommand = null;
-
-            oldIndex = streamState.getIndex(device);
-
-            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
-
-            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
-                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
-                synchronized (mA2dpAvrcpLock) {
-                    if (mA2dp != null && mAvrcpAbsVolSupported) {
-                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
-                    }
-                }
-            }
-
-            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
-                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
-            }
-
-            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-                    ((device & mFixedVolumeDevices) != 0)) {
-                flags |= AudioManager.FLAG_FIXED_VOLUME;
-
-                // volume is either 0 or max allowed for fixed volume devices
-                if (index != 0) {
-                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
-                            (device & mSafeMediaVolumeDevices) != 0) {
-                        index = mSafeMediaVolumeIndex;
-                    } else {
-                        index = streamState.getMaxIndex();
-                    }
-                }
-            }
-
-            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
-                mVolumeController.postDisplaySafeVolumeWarning(flags);
-                mPendingVolumeCommand = new StreamVolumeCommand(
-                                                    streamType, index, flags, device);
-            } else {
-                onSetStreamVolume(streamType, index, flags, device);
-                index = mStreamStates[streamType].getIndex(device);
-            }
-        }
-        sendVolumeUpdate(streamType, oldIndex, index, flags);
-    }
-
-    /** @see AudioManager#forceVolumeControlStream(int) */
-    public void forceVolumeControlStream(int streamType, IBinder cb) {
-        synchronized(mForceControlStreamLock) {
-            mVolumeControlStream = streamType;
-            if (mVolumeControlStream == -1) {
-                if (mForceControlStreamClient != null) {
-                    mForceControlStreamClient.release();
-                    mForceControlStreamClient = null;
-                }
-            } else {
-                mForceControlStreamClient = new ForceControlStreamClient(cb);
-            }
-        }
-    }
-
-    private class ForceControlStreamClient implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-
-        ForceControlStreamClient(IBinder cb) {
-            if (cb != null) {
-                try {
-                    cb.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    // Client has died!
-                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
-                    cb = null;
-                }
-            }
-            mCb = cb;
-        }
-
-        public void binderDied() {
-            synchronized(mForceControlStreamLock) {
-                Log.w(TAG, "SCO client died");
-                if (mForceControlStreamClient != this) {
-                    Log.w(TAG, "unregistered control stream client died");
-                } else {
-                    mForceControlStreamClient = null;
-                    mVolumeControlStream = -1;
-                }
-            }
-        }
-
-        public void release() {
-            if (mCb != null) {
-                mCb.unlinkToDeath(this, 0);
-                mCb = null;
-            }
-        }
-    }
-
-    private int findVolumeDelta(int direction, int volume) {
-        int delta = 0;
-        if (direction == AudioManager.ADJUST_RAISE) {
-            if (volume == MAX_MASTER_VOLUME) {
-                return 0;
-            }
-            // This is the default value if we make it to the end
-            delta = mMasterVolumeRamp[1];
-            // If we're raising the volume move down the ramp array until we
-            // find the volume we're above and use that groups delta.
-            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
-                if (volume >= mMasterVolumeRamp[i - 1]) {
-                    delta = mMasterVolumeRamp[i];
-                    break;
-                }
-            }
-        } else if (direction == AudioManager.ADJUST_LOWER){
-            if (volume == 0) {
-                return 0;
-            }
-            int length = mMasterVolumeRamp.length;
-            // This is the default value if we make it to the end
-            delta = -mMasterVolumeRamp[length - 1];
-            // If we're lowering the volume move up the ramp array until we
-            // find the volume we're below and use the group below it's delta
-            for (int i = 2; i < length; i += 2) {
-                if (volume <= mMasterVolumeRamp[i]) {
-                    delta = -mMasterVolumeRamp[i - 1];
-                    break;
-                }
-            }
-        }
-        return delta;
-    }
-
-    private void sendBroadcastToAll(Intent intent) {
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    private void sendStickyBroadcastToAll(Intent intent) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    // UI update and Broadcast Intent
-    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
-        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
-            streamType = AudioSystem.STREAM_NOTIFICATION;
-        }
-
-        if (streamType == AudioSystem.STREAM_MUSIC) {
-            flags = updateFlagsForSystemAudio(flags);
-        }
-        mVolumeController.postVolumeChanged(streamType, flags);
-
-        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
-            oldIndex = (oldIndex + 5) / 10;
-            index = (index + 5) / 10;
-            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
-            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
-            sendBroadcastToAll(intent);
-        }
-    }
-
-    // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
-    // receives volume notification from Audio Receiver.
-    private int updateFlagsForSystemAudio(int flags) {
-        if (mHdmiTvClient != null) {
-            synchronized (mHdmiTvClient) {
-                if (mHdmiSystemAudioSupported &&
-                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
-                    flags &= ~AudioManager.FLAG_SHOW_UI;
-                }
-            }
-        }
-        return flags;
-    }
-
-    // UI update and Broadcast Intent
-    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
-        mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
-
-        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
-        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
-        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
-        sendBroadcastToAll(intent);
-    }
-
-    // UI update and Broadcast Intent
-    private void sendMasterMuteUpdate(boolean muted, int flags) {
-        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
-        broadcastMasterMuteStatus(muted);
-    }
-
-    private void broadcastMasterMuteStatus(boolean muted) {
-        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
-        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        sendStickyBroadcastToAll(intent);
-    }
-
-    /**
-     * Sets the stream state's index, and posts a message to set system volume.
-     * This will not call out to the UI. Assumes a valid stream type.
-     *
-     * @param streamType Type of the stream
-     * @param index Desired volume index of the stream
-     * @param device the device whose volume must be changed
-     * @param force If true, set the volume even if the desired volume is same
-     * as the current volume.
-     */
-    private void setStreamVolumeInt(int streamType,
-                                    int index,
-                                    int device,
-                                    boolean force) {
-        VolumeStreamState streamState = mStreamStates[streamType];
-
-        if (streamState.setIndex(index, device) || force) {
-            // Post message to set system volume (it in turn will post a message
-            // to persist).
-            sendMsg(mAudioHandler,
-                    MSG_SET_DEVICE_VOLUME,
-                    SENDMSG_QUEUE,
-                    device,
-                    0,
-                    streamState,
-                    0);
-        }
-    }
-
-    /** @see AudioManager#setStreamSolo(int, boolean) */
-    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        int streamAlias = mStreamVolumeAlias[streamType];
-        for (int stream = 0; stream < mStreamStates.length; stream++) {
-            if (!isStreamAffectedByMute(streamAlias) || streamAlias == mStreamVolumeAlias[stream]) {
-                continue;
-            }
-            mStreamStates[stream].mute(cb, state);
-         }
-    }
-
-    /** @see AudioManager#setStreamMute(int, boolean) */
-    public void setStreamMute(int streamType, boolean state, IBinder cb) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-            streamType = getActiveStreamType(streamType);
-        }
-        int streamAlias = mStreamVolumeAlias[streamType];
-        if (isStreamAffectedByMute(streamAlias)) {
-            if (streamAlias == AudioSystem.STREAM_MUSIC) {
-                setSystemAudioMute(state);
-            }
-            for (int stream = 0; stream < mStreamStates.length; stream++) {
-                if (streamAlias == mStreamVolumeAlias[stream]) {
-                    mStreamStates[stream].mute(cb, state);
-
-                    Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
-                    intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
-                    intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
-                    sendBroadcastToAll(intent);
-                }
-            }
-        }
-    }
-
-    private void setSystemAudioMute(boolean state) {
-        if (mHdmiManager == null || mHdmiTvClient == null) return;
-        synchronized (mHdmiManager) {
-            if (!mHdmiSystemAudioSupported) return;
-            synchronized (mHdmiTvClient) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    mHdmiTvClient.setSystemAudioMute(state);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        }
-    }
-
-    /** get stream mute state. */
-    public boolean isStreamMute(int streamType) {
-        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-            streamType = getActiveStreamType(streamType);
-        }
-        synchronized (VolumeStreamState.class) {
-            return mStreamStates[streamType].isMuted_syncVSS();
-        }
-    }
-
-    private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mICallback; // To be notified of client's death
-
-        RmtSbmxFullVolDeathHandler(IBinder cb) {
-            mICallback = cb;
-            try {
-                cb.linkToDeath(this, 0/*flags*/);
-            } catch (RemoteException e) {
-                Log.e(TAG, "can't link to death", e);
-            }
-        }
-
-        boolean isHandlerFor(IBinder cb) {
-            return mICallback.equals(cb);
-        }
-
-        void forget() {
-            try {
-                mICallback.unlinkToDeath(this, 0/*flags*/);
-            } catch (NoSuchElementException e) {
-                Log.e(TAG, "error unlinking to death", e);
-            }
-        }
-
-        public void binderDied() {
-            Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
-            forceRemoteSubmixFullVolume(false, mICallback);
-        }
-    }
-
-    /**
-     * call must be synchronized on mRmtSbmxFullVolDeathHandlers
-     * @return true if there is a registered death handler, false otherwise */
-    private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
-        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
-        while (it.hasNext()) {
-            final RmtSbmxFullVolDeathHandler handler = it.next();
-            if (handler.isHandlerFor(cb)) {
-                handler.forget();
-                mRmtSbmxFullVolDeathHandlers.remove(handler);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /** call synchronized on mRmtSbmxFullVolDeathHandlers */
-    private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
-        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
-        while (it.hasNext()) {
-            if (it.next().isHandlerFor(cb)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private int mRmtSbmxFullVolRefCount = 0;
-    private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
-            new ArrayList<RmtSbmxFullVolDeathHandler>();
-
-    public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
-        if (cb == null) {
-            return;
-        }
-        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
-                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
-            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
-            return;
-        }
-        synchronized(mRmtSbmxFullVolDeathHandlers) {
-            boolean applyRequired = false;
-            if (startForcing) {
-                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
-                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
-                    if (mRmtSbmxFullVolRefCount == 0) {
-                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        applyRequired = true;
-                    }
-                    mRmtSbmxFullVolRefCount++;
-                }
-            } else {
-                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
-                    mRmtSbmxFullVolRefCount--;
-                    if (mRmtSbmxFullVolRefCount == 0) {
-                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
-                        applyRequired = true;
-                    }
-                }
-            }
-            if (applyRequired) {
-                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
-                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
-                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
-            }
-        }
-    }
-
-    /** @see AudioManager#setMasterMute(boolean, int) */
-    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
-        setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
-    }
-
-    private void setMasterMuteInternal(boolean state, int flags, String callingPackage, IBinder cb,
-            int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-        if (state != AudioSystem.getMasterMute()) {
-            setSystemAudioMute(state);
-            AudioSystem.setMasterMute(state);
-            // Post a persist master volume msg
-            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
-                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
-            sendMasterMuteUpdate(state, flags);
-
-            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
-            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
-            sendBroadcastToAll(intent);
-        }
-    }
-
-    /** get master mute state. */
-    public boolean isMasterMute() {
-        return AudioSystem.getMasterMute();
-    }
-
-    protected static int getMaxStreamVolume(int streamType) {
-        return MAX_STREAM_VOLUME[streamType];
-    }
-
-    public static int getDefaultStreamVolume(int streamType) {
-        return DEFAULT_STREAM_VOLUME[streamType];
-    }
-
-    /** @see AudioManager#getStreamVolume(int) */
-    public int getStreamVolume(int streamType) {
-        ensureValidStreamType(streamType);
-        int device = getDeviceForStream(streamType);
-        synchronized (VolumeStreamState.class) {
-            int index = mStreamStates[streamType].getIndex(device);
-
-            // by convention getStreamVolume() returns 0 when a stream is muted.
-            if (mStreamStates[streamType].isMuted_syncVSS()) {
-                index = 0;
-            }
-            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                    (device & mFixedVolumeDevices) != 0) {
-                index = mStreamStates[streamType].getMaxIndex();
-            }
-            return (index + 5) / 10;
-        }
-    }
-
-    @Override
-    public int getMasterVolume() {
-        if (isMasterMute()) return 0;
-        return getLastAudibleMasterVolume();
-    }
-
-    @Override
-    public void setMasterVolume(int volume, int flags, String callingPackage) {
-        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
-    }
-
-    public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
-        if (mUseFixedVolume) {
-            return;
-        }
-
-        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
-                != AppOpsManager.MODE_ALLOWED) {
-            return;
-        }
-
-        if (volume < 0) {
-            volume = 0;
-        } else if (volume > MAX_MASTER_VOLUME) {
-            volume = MAX_MASTER_VOLUME;
-        }
-        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
-    }
-
-    private void doSetMasterVolume(float volume, int flags) {
-        // don't allow changing master volume when muted
-        if (!AudioSystem.getMasterMute()) {
-            int oldVolume = getMasterVolume();
-            AudioSystem.setMasterVolume(volume);
-
-            int newVolume = getMasterVolume();
-            if (newVolume != oldVolume) {
-                // Post a persist master volume msg
-                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
-                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
-                setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
-            }
-            // Send the volume update regardless whether there was a change.
-            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
-        }
-    }
-
-    /** @see AudioManager#getStreamMaxVolume(int) */
-    public int getStreamMaxVolume(int streamType) {
-        ensureValidStreamType(streamType);
-        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
-    }
-
-    public int getMasterMaxVolume() {
-        return MAX_MASTER_VOLUME;
-    }
-
-    /** Get last audible volume before stream was muted. */
-    public int getLastAudibleStreamVolume(int streamType) {
-        ensureValidStreamType(streamType);
-        int device = getDeviceForStream(streamType);
-        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
-    }
-
-    /** Get last audible master volume before it was muted. */
-    public int getLastAudibleMasterVolume() {
-        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
-    }
-
-    /** @see AudioManager#getMasterStreamType()  */
-    public int getMasterStreamType() {
-        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
-    }
-
-    /** @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;
-        }
-        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
-            return;
-        }
-
-        AudioSystem.muteMicrophone(on);
-        // Post a persist microphone msg.
-        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
-                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
-    }
-
-    @Override
-    public int getRingerModeExternal() {
-        synchronized(mSettingsLock) {
-            return mRingerModeExternal;
-        }
-    }
-
-    @Override
-    public int getRingerModeInternal() {
-        synchronized(mSettingsLock) {
-            return mRingerMode;
-        }
-    }
-
-    private void ensureValidRingerMode(int ringerMode) {
-        if (!isValidRingerMode(ringerMode)) {
-            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
-        }
-    }
-
-    /** @see AudioManager#isValidRingerMode(int) */
-    public boolean isValidRingerMode(int ringerMode) {
-        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
-    }
-
-    public void setRingerModeExternal(int ringerMode, String caller) {
-        setRingerMode(ringerMode, caller, true /*external*/);
-    }
-
-    public void setRingerModeInternal(int ringerMode, String caller) {
-        enforceSelfOrSystemUI("setRingerModeInternal");
-        setRingerMode(ringerMode, caller, false /*external*/);
-    }
-
-    private void setRingerMode(int ringerMode, String caller, boolean external) {
-        if (mUseFixedVolume || isPlatformTelevision()) {
-            return;
-        }
-        if (caller == null || caller.length() == 0) {
-            throw new IllegalArgumentException("Bad caller: " + caller);
-        }
-        ensureValidRingerMode(ringerMode);
-        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
-            ringerMode = AudioManager.RINGER_MODE_SILENT;
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSettingsLock) {
-                final int ringerModeInternal = getRingerModeInternal();
-                final int ringerModeExternal = getRingerModeExternal();
-                if (external) {
-                    setRingerModeExt(ringerMode);
-                    if (mRingerModeDelegate != null) {
-                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
-                                ringerMode, caller, ringerModeInternal);
-                    }
-                    if (ringerMode != ringerModeInternal) {
-                        setRingerModeInt(ringerMode, true /*persist*/);
-                    }
-                } else /*internal*/ {
-                    if (ringerMode != ringerModeInternal) {
-                        setRingerModeInt(ringerMode, true /*persist*/);
-                    }
-                    if (mRingerModeDelegate != null) {
-                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
-                                ringerMode, caller, ringerModeExternal);
-                    }
-                    setRingerModeExt(ringerMode);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private void setRingerModeExt(int ringerMode) {
-        synchronized(mSettingsLock) {
-            if (ringerMode == mRingerModeExternal) return;
-            mRingerModeExternal = ringerMode;
-        }
-        // Send sticky broadcast
-        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
-    }
-
-    private void setRingerModeInt(int ringerMode, boolean persist) {
-        final boolean change;
-        synchronized(mSettingsLock) {
-            change = mRingerMode != ringerMode;
-            mRingerMode = ringerMode;
-        }
-
-        // Mute stream if not previously muted by ringer mode and ringer mode
-        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
-        // Unmute stream if previously muted by ringer mode and ringer mode
-        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
-        int numStreamTypes = AudioSystem.getNumStreamTypes();
-        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
-                || ringerMode == AudioManager.RINGER_MODE_SILENT;
-        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-            final boolean isMuted = isStreamMutedByRingerMode(streamType);
-            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
-            if (isMuted == shouldMute) continue;
-            if (!shouldMute) {
-                // unmute
-                // ring and notifications volume should never be 0 when not silenced
-                // on voice capable devices or devices that support vibration
-                if ((isPlatformVoice() || mHasVibrator) &&
-                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
-                    synchronized (VolumeStreamState.class) {
-                        Set set = mStreamStates[streamType].mIndex.entrySet();
-                        Iterator i = set.iterator();
-                        while (i.hasNext()) {
-                            Map.Entry entry = (Map.Entry)i.next();
-                            if ((Integer)entry.getValue() == 0) {
-                                entry.setValue(10);
-                            }
-                        }
-                    }
-                }
-                mStreamStates[streamType].mute(null, false);
-                mRingerModeMutedStreams &= ~(1 << streamType);
-            } else {
-                // mute
-                mStreamStates[streamType].mute(null, true);
-                mRingerModeMutedStreams |= (1 << streamType);
-            }
-        }
-
-        // Post a persist ringer mode msg
-        if (persist) {
-            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
-                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
-        }
-        if (change) {
-            // Send sticky broadcast
-            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
-        }
-    }
-
-    private void restoreMasterVolume() {
-        if (mUseFixedVolume) {
-            AudioSystem.setMasterVolume(1.0f);
-            return;
-        }
-        if (mUseMasterVolume) {
-            float volume = Settings.System.getFloatForUser(mContentResolver,
-                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
-            if (volume >= 0.0f) {
-                AudioSystem.setMasterVolume(volume);
-            }
-        }
-    }
-
-    /** @see AudioManager#shouldVibrate(int) */
-    public boolean shouldVibrate(int vibrateType) {
-        if (!mHasVibrator) return false;
-
-        switch (getVibrateSetting(vibrateType)) {
-
-            case AudioManager.VIBRATE_SETTING_ON:
-                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
-
-            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
-                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
-
-            case AudioManager.VIBRATE_SETTING_OFF:
-                // return false, even for incoming calls
-                return false;
-
-            default:
-                return false;
-        }
-    }
-
-    /** @see AudioManager#getVibrateSetting(int) */
-    public int getVibrateSetting(int vibrateType) {
-        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
-        return (mVibrateSetting >> (vibrateType * 2)) & 3;
-    }
-
-    /** @see AudioManager#setVibrateSetting(int, int) */
-    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
-
-        if (!mHasVibrator) return;
-
-        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
-
-        // Broadcast change
-        broadcastVibrateSetting(vibrateType);
-
-    }
-
-    /**
-     * @see #setVibrateSetting(int, int)
-     */
-    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
-            int vibrateSetting) {
-
-        // First clear the existing setting. Each vibrate type has two bits in
-        // the value. Note '3' is '11' in binary.
-        existingValue &= ~(3 << (vibrateType * 2));
-
-        // Set into the old value
-        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
-
-        return existingValue;
-    }
-
-    private class SetModeDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-        private int mPid;
-        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
-
-        SetModeDeathHandler(IBinder cb, int pid) {
-            mCb = cb;
-            mPid = pid;
-        }
-
-        public void binderDied() {
-            int newModeOwnerPid = 0;
-            synchronized(mSetModeDeathHandlers) {
-                Log.w(TAG, "setMode() client died");
-                int index = mSetModeDeathHandlers.indexOf(this);
-                if (index < 0) {
-                    Log.w(TAG, "unregistered setMode() client died");
-                } else {
-                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
-                }
-            }
-            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
-            // SCO connections not started by the application changing the mode
-            if (newModeOwnerPid != 0) {
-                final long ident = Binder.clearCallingIdentity();
-                disconnectBluetoothSco(newModeOwnerPid);
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        public int getPid() {
-            return mPid;
-        }
-
-        public void setMode(int mode) {
-            mMode = mode;
-        }
-
-        public int getMode() {
-            return mMode;
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-    /** @see AudioManager#setMode(int) */
-    public void setMode(int mode, IBinder cb) {
-        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
-        if (!checkAudioSettingsPermission("setMode()")) {
-            return;
-        }
-
-        if ( (mode == AudioSystem.MODE_IN_CALL) &&
-                (mContext.checkCallingOrSelfPermission(
-                        android.Manifest.permission.MODIFY_PHONE_STATE)
-                            != PackageManager.PERMISSION_GRANTED)) {
-            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
-            return;
-        }
-
-        int newModeOwnerPid = 0;
-        synchronized(mSetModeDeathHandlers) {
-            if (mode == AudioSystem.MODE_CURRENT) {
-                mode = mMode;
-            }
-            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
-        }
-        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
-        // SCO connections not started by the application changing the mode
-        if (newModeOwnerPid != 0) {
-             disconnectBluetoothSco(newModeOwnerPid);
-        }
-    }
-
-    // must be called synchronized on mSetModeDeathHandlers
-    // setModeInt() returns a valid PID if the audio mode was successfully set to
-    // any mode other than NORMAL.
-    private int setModeInt(int mode, IBinder cb, int pid) {
-        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
-        int newModeOwnerPid = 0;
-        if (cb == null) {
-            Log.e(TAG, "setModeInt() called with null binder");
-            return newModeOwnerPid;
-        }
-
-        SetModeDeathHandler hdlr = null;
-        Iterator iter = mSetModeDeathHandlers.iterator();
-        while (iter.hasNext()) {
-            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
-            if (h.getPid() == pid) {
-                hdlr = h;
-                // Remove from client list so that it is re-inserted at top of list
-                iter.remove();
-                hdlr.getBinder().unlinkToDeath(hdlr, 0);
-                break;
-            }
-        }
-        int status = AudioSystem.AUDIO_STATUS_OK;
-        do {
-            if (mode == AudioSystem.MODE_NORMAL) {
-                // get new mode from client at top the list if any
-                if (!mSetModeDeathHandlers.isEmpty()) {
-                    hdlr = mSetModeDeathHandlers.get(0);
-                    cb = hdlr.getBinder();
-                    mode = hdlr.getMode();
-                    if (DEBUG_MODE) {
-                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
-                                + hdlr.mPid);
-                    }
-                }
-            } else {
-                if (hdlr == null) {
-                    hdlr = new SetModeDeathHandler(cb, pid);
-                }
-                // Register for client death notification
-                try {
-                    cb.linkToDeath(hdlr, 0);
-                } catch (RemoteException e) {
-                    // Client has died!
-                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
-                }
-
-                // Last client to call setMode() is always at top of client list
-                // as required by SetModeDeathHandler.binderDied()
-                mSetModeDeathHandlers.add(0, hdlr);
-                hdlr.setMode(mode);
-            }
-
-            if (mode != mMode) {
-                status = AudioSystem.setPhoneState(mode);
-                if (status == AudioSystem.AUDIO_STATUS_OK) {
-                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
-                    mMode = mode;
-                } else {
-                    if (hdlr != null) {
-                        mSetModeDeathHandlers.remove(hdlr);
-                        cb.unlinkToDeath(hdlr, 0);
-                    }
-                    // force reading new top of mSetModeDeathHandlers stack
-                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
-                    mode = AudioSystem.MODE_NORMAL;
-                }
-            } else {
-                status = AudioSystem.AUDIO_STATUS_OK;
-            }
-        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
-
-        if (status == AudioSystem.AUDIO_STATUS_OK) {
-            if (mode != AudioSystem.MODE_NORMAL) {
-                if (mSetModeDeathHandlers.isEmpty()) {
-                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
-                } else {
-                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
-                }
-            }
-            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
-            int device = getDeviceForStream(streamType);
-            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
-            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
-
-            updateStreamVolumeAlias(true /*updateVolumes*/);
-        }
-        return newModeOwnerPid;
-    }
-
-    /** @see AudioManager#getMode() */
-    public int getMode() {
-        return mMode;
-    }
-
-    //==========================================================================================
-    // Sound Effects
-    //==========================================================================================
-
-    private static final String TAG_AUDIO_ASSETS = "audio_assets";
-    private static final String ATTR_VERSION = "version";
-    private static final String TAG_GROUP = "group";
-    private static final String ATTR_GROUP_NAME = "name";
-    private static final String TAG_ASSET = "asset";
-    private static final String ATTR_ASSET_ID = "id";
-    private static final String ATTR_ASSET_FILE = "file";
-
-    private static final String ASSET_FILE_VERSION = "1.0";
-    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
-
-    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
-
-    class LoadSoundEffectReply {
-        public int mStatus = 1;
-    };
-
-    private void loadTouchSoundAssetDefaults() {
-        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
-        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
-            SOUND_EFFECT_FILES_MAP[i][0] = 0;
-            SOUND_EFFECT_FILES_MAP[i][1] = -1;
-        }
-    }
-
-    private void loadTouchSoundAssets() {
-        XmlResourceParser parser = null;
-
-        // only load assets once.
-        if (!SOUND_EFFECT_FILES.isEmpty()) {
-            return;
-        }
-
-        loadTouchSoundAssetDefaults();
-
-        try {
-            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
-
-            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
-            String version = parser.getAttributeValue(null, ATTR_VERSION);
-            boolean inTouchSoundsGroup = false;
-
-            if (ASSET_FILE_VERSION.equals(version)) {
-                while (true) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (element.equals(TAG_GROUP)) {
-                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
-                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
-                            inTouchSoundsGroup = true;
-                            break;
-                        }
-                    }
-                }
-                while (inTouchSoundsGroup) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (element.equals(TAG_ASSET)) {
-                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
-                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
-                        int fx;
-
-                        try {
-                            Field field = AudioManager.class.getField(id);
-                            fx = field.getInt(null);
-                        } catch (Exception e) {
-                            Log.w(TAG, "Invalid touch sound ID: "+id);
-                            continue;
-                        }
-
-                        int i = SOUND_EFFECT_FILES.indexOf(file);
-                        if (i == -1) {
-                            i = SOUND_EFFECT_FILES.size();
-                            SOUND_EFFECT_FILES.add(file);
-                        }
-                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
-                    } else {
-                        break;
-                    }
-                }
-            }
-        } catch (Resources.NotFoundException e) {
-            Log.w(TAG, "audio assets file not found", e);
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "XML parser exception reading touch sound assets", e);
-        } catch (IOException e) {
-            Log.w(TAG, "I/O exception reading touch sound assets", e);
-        } finally {
-            if (parser != null) {
-                parser.close();
-            }
-        }
-    }
-
-    /** @see AudioManager#playSoundEffect(int) */
-    public void playSoundEffect(int effectType) {
-        playSoundEffectVolume(effectType, -1.0f);
-    }
-
-    /** @see AudioManager#playSoundEffect(int, float) */
-    public void playSoundEffectVolume(int effectType, float volume) {
-        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
-            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
-            return;
-        }
-
-        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
-                effectType, (int) (volume * 1000), null, 0);
-    }
-
-    /**
-     * Loads samples into the soundpool.
-     * This method must be called at first when sound effects are enabled
-     */
-    public boolean loadSoundEffects() {
-        int attempts = 3;
-        LoadSoundEffectReply reply = new LoadSoundEffectReply();
-
-        synchronized (reply) {
-            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
-            while ((reply.mStatus == 1) && (attempts-- > 0)) {
-                try {
-                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                } catch (InterruptedException e) {
-                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
-                }
-            }
-        }
-        return (reply.mStatus == 0);
-    }
-
-    /**
-     *  Unloads samples from the sound pool.
-     *  This method can be called to free some memory when
-     *  sound effects are disabled.
-     */
-    public void unloadSoundEffects() {
-        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
-    }
-
-    class SoundPoolListenerThread extends Thread {
-        public SoundPoolListenerThread() {
-            super("SoundPoolListenerThread");
-        }
-
-        @Override
-        public void run() {
-
-            Looper.prepare();
-            mSoundPoolLooper = Looper.myLooper();
-
-            synchronized (mSoundEffectsLock) {
-                if (mSoundPool != null) {
-                    mSoundPoolCallBack = new SoundPoolCallback();
-                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
-                }
-                mSoundEffectsLock.notify();
-            }
-            Looper.loop();
-        }
-    }
-
-    private final class SoundPoolCallback implements
-            android.media.SoundPool.OnLoadCompleteListener {
-
-        int mStatus = 1; // 1 means neither error nor last sample loaded yet
-        List<Integer> mSamples = new ArrayList<Integer>();
-
-        public int status() {
-            return mStatus;
-        }
-
-        public void setSamples(int[] samples) {
-            for (int i = 0; i < samples.length; i++) {
-                // do not wait ack for samples rejected upfront by SoundPool
-                if (samples[i] > 0) {
-                    mSamples.add(samples[i]);
-                }
-            }
-        }
-
-        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
-            synchronized (mSoundEffectsLock) {
-                int i = mSamples.indexOf(sampleId);
-                if (i >= 0) {
-                    mSamples.remove(i);
-                }
-                if ((status != 0) || mSamples. isEmpty()) {
-                    mStatus = status;
-                    mSoundEffectsLock.notify();
-                }
-            }
-        }
-    }
-
-    /** @see AudioManager#reloadAudioSettings() */
-    public void reloadAudioSettings() {
-        readAudioSettings(false /*userSwitch*/);
-    }
-
-    private void readAudioSettings(boolean userSwitch) {
-        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
-        readPersistedSettings();
-
-        // restore volume settings
-        int numStreamTypes = AudioSystem.getNumStreamTypes();
-        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
-            VolumeStreamState streamState = mStreamStates[streamType];
-
-            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
-                continue;
-            }
-
-            streamState.readSettings();
-            synchronized (VolumeStreamState.class) {
-                // unmute stream that was muted but is not affect by mute anymore
-                if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
-                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
-                    int size = streamState.mDeathHandlers.size();
-                    for (int i = 0; i < size; i++) {
-                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
-                        streamState.mDeathHandlers.get(i).mute_syncVSS(false);
-                    }
-                }
-            }
-        }
-
-        // apply new ringer mode before checking volume for alias streams so that streams
-        // muted by ringer mode have the correct volume
-        setRingerModeInt(getRingerModeInternal(), false);
-
-        checkAllFixedVolumeDevices();
-        checkAllAliasStreamVolumes();
-
-        synchronized (mSafeMediaVolumeState) {
-            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
-                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
-                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
-            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
-                enforceSafeMediaVolume();
-            }
-        }
-    }
-
-    /** @see AudioManager#setSpeakerphoneOn(boolean) */
-    public void setSpeakerphoneOn(boolean on){
-        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
-            return;
-        }
-
-        if (on) {
-            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
-                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
-            }
-            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
-        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
-        }
-
-        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
-                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
-    }
-
-    /** @see AudioManager#isSpeakerphoneOn() */
-    public boolean isSpeakerphoneOn() {
-        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
-    }
-
-    /** @see AudioManager#setBluetoothScoOn(boolean) */
-    public void setBluetoothScoOn(boolean on){
-        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
-            return;
-        }
-
-        if (on) {
-            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
-        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-            mForcedUseForComm = AudioSystem.FORCE_NONE;
-        }
-
-        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
-                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
-        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
-                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
-    }
-
-    /** @see AudioManager#isBluetoothScoOn() */
-    public boolean isBluetoothScoOn() {
-        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
-    }
-
-    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
-    public void setBluetoothA2dpOn(boolean on) {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            mBluetoothA2dpEnabled = on;
-            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
-                    AudioSystem.FOR_MEDIA,
-                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
-                    null, 0);
-        }
-    }
-
-    /** @see AudioManager#isBluetoothA2dpOn() */
-    public boolean isBluetoothA2dpOn() {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            return mBluetoothA2dpEnabled;
-        }
-    }
-
-    /** @see AudioManager#startBluetoothSco() */
-    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
-        int scoAudioMode =
-                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
-                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
-        startBluetoothScoInt(cb, scoAudioMode);
-    }
-
-    /** @see AudioManager#startBluetoothScoVirtualCall() */
-    public void startBluetoothScoVirtualCall(IBinder cb) {
-        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
-    }
-
-    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
-        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
-                !mSystemReady) {
-            return;
-        }
-        ScoClient client = getScoClient(cb, true);
-        // The calling identity must be cleared before calling ScoClient.incCount().
-        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
-        // and this must be done on behalf of system server to make sure permissions are granted.
-        // The caller identity must be cleared after getScoClient() because it is needed if a new
-        // client is created.
-        final long ident = Binder.clearCallingIdentity();
-        client.incCount(scoAudioMode);
-        Binder.restoreCallingIdentity(ident);
-    }
-
-    /** @see AudioManager#stopBluetoothSco() */
-    public void stopBluetoothSco(IBinder cb){
-        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
-                !mSystemReady) {
-            return;
-        }
-        ScoClient client = getScoClient(cb, false);
-        // The calling identity must be cleared before calling ScoClient.decCount().
-        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
-        // and this must be done on behalf of system server to make sure permissions are granted.
-        final long ident = Binder.clearCallingIdentity();
-        if (client != null) {
-            client.decCount();
-        }
-        Binder.restoreCallingIdentity(ident);
-    }
-
-
-    private class ScoClient implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-        private int mCreatorPid;
-        private int mStartcount; // number of SCO connections started by this client
-
-        ScoClient(IBinder cb) {
-            mCb = cb;
-            mCreatorPid = Binder.getCallingPid();
-            mStartcount = 0;
-        }
-
-        public void binderDied() {
-            synchronized(mScoClients) {
-                Log.w(TAG, "SCO client died");
-                int index = mScoClients.indexOf(this);
-                if (index < 0) {
-                    Log.w(TAG, "unregistered SCO client died");
-                } else {
-                    clearCount(true);
-                    mScoClients.remove(this);
-                }
-            }
-        }
-
-        public void incCount(int scoAudioMode) {
-            synchronized(mScoClients) {
-                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
-                if (mStartcount == 0) {
-                    try {
-                        mCb.linkToDeath(this, 0);
-                    } catch (RemoteException e) {
-                        // client has already died!
-                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
-                    }
-                }
-                mStartcount++;
-            }
-        }
-
-        public void decCount() {
-            synchronized(mScoClients) {
-                if (mStartcount == 0) {
-                    Log.w(TAG, "ScoClient.decCount() already 0");
-                } else {
-                    mStartcount--;
-                    if (mStartcount == 0) {
-                        try {
-                            mCb.unlinkToDeath(this, 0);
-                        } catch (NoSuchElementException e) {
-                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
-                        }
-                    }
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
-                }
-            }
-        }
-
-        public void clearCount(boolean stopSco) {
-            synchronized(mScoClients) {
-                if (mStartcount != 0) {
-                    try {
-                        mCb.unlinkToDeath(this, 0);
-                    } catch (NoSuchElementException e) {
-                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
-                    }
-                }
-                mStartcount = 0;
-                if (stopSco) {
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
-                }
-            }
-        }
-
-        public int getCount() {
-            return mStartcount;
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-
-        public int getPid() {
-            return mCreatorPid;
-        }
-
-        public int totalCount() {
-            synchronized(mScoClients) {
-                int count = 0;
-                int size = mScoClients.size();
-                for (int i = 0; i < size; i++) {
-                    count += mScoClients.get(i).getCount();
-                }
-                return count;
-            }
-        }
-
-        private void requestScoState(int state, int scoAudioMode) {
-            checkScoAudioState();
-            if (totalCount() == 0) {
-                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
-                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
-                    // the connection.
-                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
-                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
-                    // currently controlled by the same client process.
-                    synchronized(mSetModeDeathHandlers) {
-                        if ((mSetModeDeathHandlers.isEmpty() ||
-                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
-                                (mScoAudioState == SCO_STATE_INACTIVE ||
-                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
-                            if (mScoAudioState == SCO_STATE_INACTIVE) {
-                                mScoAudioMode = scoAudioMode;
-                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
-                                    if (mBluetoothHeadsetDevice != null) {
-                                        mScoAudioMode = new Integer(Settings.Global.getInt(
-                                                                mContentResolver,
-                                                                "bluetooth_sco_channel_"+
-                                                                mBluetoothHeadsetDevice.getAddress(),
-                                                                SCO_MODE_VIRTUAL_CALL));
-                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
-                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
-                                        }
-                                    } else {
-                                        mScoAudioMode = SCO_MODE_RAW;
-                                    }
-                                }
-                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    boolean status = false;
-                                    if (mScoAudioMode == SCO_MODE_RAW) {
-                                        status = mBluetoothHeadset.connectAudio();
-                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                                                            mBluetoothHeadsetDevice);
-                                    } else if (mScoAudioMode == SCO_MODE_VR) {
-                                        status = mBluetoothHeadset.startVoiceRecognition(
-                                                                           mBluetoothHeadsetDevice);
-                                    }
-
-                                    if (status) {
-                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                    } else {
-                                        broadcastScoConnectionState(
-                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                                    }
-                                } else if (getBluetoothHeadset()) {
-                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
-                                }
-                            } else {
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
-                            }
-                        } else {
-                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                        }
-                    }
-                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
-                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
-                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
-                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
-                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            boolean status = false;
-                            if (mScoAudioMode == SCO_MODE_RAW) {
-                                status = mBluetoothHeadset.disconnectAudio();
-                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                            } else if (mScoAudioMode == SCO_MODE_VR) {
-                                        status = mBluetoothHeadset.stopVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
-                            }
-
-                            if (!status) {
-                                mScoAudioState = SCO_STATE_INACTIVE;
-                                broadcastScoConnectionState(
-                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                            }
-                        } else if (getBluetoothHeadset()) {
-                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
-                        }
-                    } else {
-                        mScoAudioState = SCO_STATE_INACTIVE;
-                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                    }
-                }
-            }
-        }
-    }
-
-    private void checkScoAudioState() {
-        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
-                mScoAudioState == SCO_STATE_INACTIVE &&
-                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
-                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
-            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-        }
-    }
-
-    private ScoClient getScoClient(IBinder cb, boolean create) {
-        synchronized(mScoClients) {
-            ScoClient client = null;
-            int size = mScoClients.size();
-            for (int i = 0; i < size; i++) {
-                client = mScoClients.get(i);
-                if (client.getBinder() == cb)
-                    return client;
-            }
-            if (create) {
-                client = new ScoClient(cb);
-                mScoClients.add(client);
-            }
-            return client;
-        }
-    }
-
-    public void clearAllScoClients(int exceptPid, boolean stopSco) {
-        synchronized(mScoClients) {
-            ScoClient savedClient = null;
-            int size = mScoClients.size();
-            for (int i = 0; i < size; i++) {
-                ScoClient cl = mScoClients.get(i);
-                if (cl.getPid() != exceptPid) {
-                    cl.clearCount(stopSco);
-                } else {
-                    savedClient = cl;
-                }
-            }
-            mScoClients.clear();
-            if (savedClient != null) {
-                mScoClients.add(savedClient);
-            }
-        }
-    }
-
-    private boolean getBluetoothHeadset() {
-        boolean result = false;
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                    BluetoothProfile.HEADSET);
-        }
-        // If we could not get a bluetooth headset proxy, send a failure message
-        // without delay to reset the SCO audio state and clear SCO clients.
-        // If we could get a proxy, send a delayed failure message that will reset our state
-        // in case we don't receive onServiceConnected().
-        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
-                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
-        return result;
-    }
-
-    private void disconnectBluetoothSco(int exceptPid) {
-        synchronized(mScoClients) {
-            checkScoAudioState();
-            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
-                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
-                if (mBluetoothHeadsetDevice != null) {
-                    if (mBluetoothHeadset != null) {
-                        if (!mBluetoothHeadset.stopVoiceRecognition(
-                                mBluetoothHeadsetDevice)) {
-                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
-                                    SENDMSG_REPLACE, 0, 0, null, 0);
-                        }
-                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
-                            getBluetoothHeadset()) {
-                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
-                    }
-                }
-            } else {
-                clearAllScoClients(exceptPid, true);
-            }
-        }
-    }
-
-    private void resetBluetoothSco() {
-        synchronized(mScoClients) {
-            clearAllScoClients(0, false);
-            mScoAudioState = SCO_STATE_INACTIVE;
-            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-        }
-    }
-
-    private void broadcastScoConnectionState(int state) {
-        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
-                SENDMSG_QUEUE, state, 0, null, 0);
-    }
-
-    private void onBroadcastScoConnectionState(int state) {
-        if (state != mScoConnectionState) {
-            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
-            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
-            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
-                    mScoConnectionState);
-            sendStickyBroadcastToAll(newIntent);
-            mScoConnectionState = state;
-        }
-    }
-
-    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
-        new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            BluetoothDevice btDevice;
-            List<BluetoothDevice> deviceList;
-            switch(profile) {
-            case BluetoothProfile.A2DP:
-                synchronized (mA2dpAvrcpLock) {
-                    mA2dp = (BluetoothA2dp) proxy;
-                    deviceList = mA2dp.getConnectedDevices();
-                    if (deviceList.size() > 0) {
-                        btDevice = deviceList.get(0);
-                        synchronized (mConnectedDevices) {
-                            int state = mA2dp.getConnectionState(btDevice);
-                            int delay = checkSendBecomingNoisyIntent(
-                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
-                            queueMsgUnderWakeLock(mAudioHandler,
-                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
-                                    state,
-                                    0,
-                                    btDevice,
-                                    delay);
-                        }
-                    }
-                }
-                break;
-
-            case BluetoothProfile.A2DP_SINK:
-                deviceList = proxy.getConnectedDevices();
-                if (deviceList.size() > 0) {
-                    btDevice = deviceList.get(0);
-                    synchronized (mConnectedDevices) {
-                        int state = proxy.getConnectionState(btDevice);
-                        queueMsgUnderWakeLock(mAudioHandler,
-                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
-                                state,
-                                0,
-                                btDevice,
-                                0 /* delay */);
-                    }
-                }
-                break;
-
-            case BluetoothProfile.HEADSET:
-                synchronized (mScoClients) {
-                    // Discard timeout message
-                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
-                    mBluetoothHeadset = (BluetoothHeadset) proxy;
-                    deviceList = mBluetoothHeadset.getConnectedDevices();
-                    if (deviceList.size() > 0) {
-                        mBluetoothHeadsetDevice = deviceList.get(0);
-                    } else {
-                        mBluetoothHeadsetDevice = null;
-                    }
-                    // Refresh SCO audio state
-                    checkScoAudioState();
-                    // Continue pending action if any
-                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
-                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
-                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
-                        boolean status = false;
-                        if (mBluetoothHeadsetDevice != null) {
-                            switch (mScoAudioState) {
-                            case SCO_STATE_ACTIVATE_REQ:
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                if (mScoAudioMode == SCO_MODE_RAW) {
-                                    status = mBluetoothHeadset.connectAudio();
-                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                                } else if (mScoAudioMode == SCO_MODE_VR) {
-                                    status = mBluetoothHeadset.startVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
-                                }
-                                break;
-                            case SCO_STATE_DEACTIVATE_REQ:
-                                if (mScoAudioMode == SCO_MODE_RAW) {
-                                    status = mBluetoothHeadset.disconnectAudio();
-                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
-                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                                                        mBluetoothHeadsetDevice);
-                                } else if (mScoAudioMode == SCO_MODE_VR) {
-                                    status = mBluetoothHeadset.stopVoiceRecognition(
-                                                                      mBluetoothHeadsetDevice);
-                                }
-                                break;
-                            case SCO_STATE_DEACTIVATE_EXT_REQ:
-                                status = mBluetoothHeadset.stopVoiceRecognition(
-                                        mBluetoothHeadsetDevice);
-                            }
-                        }
-                        if (!status) {
-                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
-                                    SENDMSG_REPLACE, 0, 0, null, 0);
-                        }
-                    }
-                }
-                break;
-
-            default:
-                break;
-            }
-        }
-        public void onServiceDisconnected(int profile) {
-            switch(profile) {
-            case BluetoothProfile.A2DP:
-                synchronized (mA2dpAvrcpLock) {
-                    mA2dp = null;
-                    synchronized (mConnectedDevices) {
-                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
-                            makeA2dpDeviceUnavailableNow(
-                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
-                        }
-                    }
-                }
-                break;
-
-            case BluetoothProfile.A2DP_SINK:
-                synchronized (mConnectedDevices) {
-                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
-                        makeA2dpSrcUnavailable(
-                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
-                    }
-                }
-                break;
-
-            case BluetoothProfile.HEADSET:
-                synchronized (mScoClients) {
-                    mBluetoothHeadset = null;
-                }
-                break;
-
-            default:
-                break;
-            }
-        }
-    };
-
-    private void onCheckMusicActive() {
-        synchronized (mSafeMediaVolumeState) {
-            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
-                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-
-                if ((device & mSafeMediaVolumeDevices) != 0) {
-                    sendMsg(mAudioHandler,
-                            MSG_CHECK_MUSIC_ACTIVE,
-                            SENDMSG_REPLACE,
-                            0,
-                            0,
-                            null,
-                            MUSIC_ACTIVE_POLL_PERIOD_MS);
-                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
-                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
-                            (index > mSafeMediaVolumeIndex)) {
-                        // Approximate cumulative active music time
-                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
-                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
-                            setSafeMediaVolumeEnabled(true);
-                            mMusicActiveMs = 0;
-                        }
-                        saveMusicActiveMs();
-                    }
-                }
-            }
-        }
-    }
-
-    private void saveMusicActiveMs() {
-        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
-    }
-
-    private void onConfigureSafeVolume(boolean force) {
-        synchronized (mSafeMediaVolumeState) {
-            int mcc = mContext.getResources().getConfiguration().mcc;
-            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
-                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
-                boolean safeMediaVolumeEnabled =
-                        SystemProperties.getBoolean("audio.safemedia.force", false)
-                        || mContext.getResources().getBoolean(
-                                com.android.internal.R.bool.config_safe_media_volume_enabled);
-
-                // The persisted state is either "disabled" or "active": this is the state applied
-                // next time we boot and cannot be "inactive"
-                int persistedState;
-                if (safeMediaVolumeEnabled) {
-                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
-                    // The state can already be "inactive" here if the user has forced it before
-                    // the 30 seconds timeout for forced configuration. In this case we don't reset
-                    // it to "active".
-                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
-                        if (mMusicActiveMs == 0) {
-                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
-                            enforceSafeMediaVolume();
-                        } else {
-                            // We have existing playback time recorded, already confirmed.
-                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
-                        }
-                    }
-                } else {
-                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
-                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
-                }
-                mMcc = mcc;
-                sendMsg(mAudioHandler,
-                        MSG_PERSIST_SAFE_VOLUME_STATE,
-                        SENDMSG_QUEUE,
-                        persistedState,
-                        0,
-                        null,
-                        0);
-            }
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Internal methods
-    ///////////////////////////////////////////////////////////////////////////
-
-    /**
-     * Checks if the adjustment should change ringer mode instead of just
-     * adjusting volume. If so, this will set the proper ringer mode and volume
-     * indices on the stream states.
-     */
-    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
-        int result = FLAG_ADJUST_VOLUME;
-        int ringerMode = getRingerModeInternal();
-
-        switch (ringerMode) {
-        case RINGER_MODE_NORMAL:
-            if (direction == AudioManager.ADJUST_LOWER) {
-                if (mHasVibrator) {
-                    // "step" is the delta in internal index units corresponding to a
-                    // change of 1 in UI index units.
-                    // Because of rounding when rescaling from one stream index range to its alias
-                    // index range, we cannot simply test oldIndex == step:
-                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
-                    if (step <= oldIndex && oldIndex < 2 * step) {
-                        ringerMode = RINGER_MODE_VIBRATE;
-                    }
-                } else {
-                    // (oldIndex < step) is equivalent to (old UI index == 0)
-                    if ((oldIndex < step)
-                            && VOLUME_SETS_RINGER_MODE_SILENT
-                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
-                        ringerMode = RINGER_MODE_SILENT;
-                    }
-                }
-            }
-            break;
-        case RINGER_MODE_VIBRATE:
-            if (!mHasVibrator) {
-                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
-                        "but no vibrator is present");
-                break;
-            }
-            if ((direction == AudioManager.ADJUST_LOWER)) {
-                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
-                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
-                        ringerMode = RINGER_MODE_SILENT;
-                    } else {
-                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
-                    }
-                }
-            } else if (direction == AudioManager.ADJUST_RAISE) {
-                ringerMode = RINGER_MODE_NORMAL;
-            }
-            result &= ~FLAG_ADJUST_VOLUME;
-            break;
-        case RINGER_MODE_SILENT:
-            if (direction == AudioManager.ADJUST_RAISE) {
-                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
-                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
-                } else {
-                  if (mHasVibrator) {
-                      ringerMode = RINGER_MODE_VIBRATE;
-                  } else {
-                      ringerMode = RINGER_MODE_NORMAL;
-                  }
-                }
-            }
-            result &= ~FLAG_ADJUST_VOLUME;
-            break;
-        default:
-            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
-            break;
-        }
-
-        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
-
-        mPrevVolDirection = direction;
-
-        return result;
-    }
-
-    @Override
-    public boolean isStreamAffectedByRingerMode(int streamType) {
-        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
-    }
-
-    private boolean isStreamMutedByRingerMode(int streamType) {
-        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
-    }
-
-    boolean updateRingerModeAffectedStreams() {
-        int ringerModeAffectedStreams;
-        // make sure settings for ringer mode are consistent with device type: non voice capable
-        // devices (tablets) include media stream in silent mode whereas phones don't.
-        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
-                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
-                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
-                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
-                 UserHandle.USER_CURRENT);
-
-        // ringtone, notification and system streams are always affected by ringer mode
-        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
-                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
-                                        (1 << AudioSystem.STREAM_SYSTEM);
-
-        switch (mPlatformType) {
-            case PLATFORM_TELEVISION:
-                ringerModeAffectedStreams = 0;
-                break;
-            default:
-                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
-                break;
-        }
-
-        synchronized (mCameraSoundForced) {
-            if (mCameraSoundForced) {
-                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
-            } else {
-                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
-            }
-        }
-        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
-            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
-        } else {
-            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
-        }
-
-        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
-            Settings.System.putIntForUser(mContentResolver,
-                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
-                    ringerModeAffectedStreams,
-                    UserHandle.USER_CURRENT);
-            mRingerModeAffectedStreams = ringerModeAffectedStreams;
-            return true;
-        }
-        return false;
-    }
-
-    public boolean isStreamAffectedByMute(int streamType) {
-        return (mMuteAffectedStreams & (1 << streamType)) != 0;
-    }
-
-    private void ensureValidDirection(int direction) {
-        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
-            throw new IllegalArgumentException("Bad direction " + direction);
-        }
-    }
-
-    private void ensureValidSteps(int steps) {
-        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
-            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
-        }
-    }
-
-    private void ensureValidStreamType(int streamType) {
-        if (streamType < 0 || streamType >= mStreamStates.length) {
-            throw new IllegalArgumentException("Bad stream type " + streamType);
-        }
-    }
-
-    private boolean isInCommunication() {
-        boolean IsInCall = false;
-
-        TelecomManager telecomManager =
-                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-
-        final long ident = Binder.clearCallingIdentity();
-        IsInCall = telecomManager.isInCall();
-        Binder.restoreCallingIdentity(ident);
-
-        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
-    }
-
-    /**
-     * For code clarity for getActiveStreamType(int)
-     * @param delay_ms max time since last STREAM_MUSIC activity to consider
-     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
-     *     in the last "delay_ms" ms.
-     */
-    private boolean isAfMusicActiveRecently(int delay_ms) {
-        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
-                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
-    }
-
-    private int getActiveStreamType(int suggestedStreamType) {
-        switch (mPlatformType) {
-        case PLATFORM_VOICE:
-            if (isInCommunication()) {
-                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
-                        == AudioSystem.FORCE_BT_SCO) {
-                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
-                    return AudioSystem.STREAM_BLUETOOTH_SCO;
-                } else {
-                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
-                    return AudioSystem.STREAM_VOICE_CALL;
-                }
-            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
-                    if (DEBUG_VOL)
-                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
-                    return AudioSystem.STREAM_MUSIC;
-                    } else {
-                        if (DEBUG_VOL)
-                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
-                        return AudioSystem.STREAM_RING;
-                }
-            } else if (isAfMusicActiveRecently(0)) {
-                if (DEBUG_VOL)
-                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
-                return AudioSystem.STREAM_MUSIC;
-            }
-            break;
-        case PLATFORM_TELEVISION:
-            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                    // TV always defaults to STREAM_MUSIC
-                    return AudioSystem.STREAM_MUSIC;
-            }
-            break;
-        default:
-            if (isInCommunication()) {
-                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
-                        == AudioSystem.FORCE_BT_SCO) {
-                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
-                    return AudioSystem.STREAM_BLUETOOTH_SCO;
-                } else {
-                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
-                    return AudioSystem.STREAM_VOICE_CALL;
-                }
-            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
-                    StreamOverride.sDelayMs) ||
-                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
-                            StreamOverride.sDelayMs)) {
-                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
-                return AudioSystem.STREAM_NOTIFICATION;
-            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
-                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
-                    return AudioSystem.STREAM_MUSIC;
-                } else {
-                    if (DEBUG_VOL) Log.v(TAG,
-                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
-                    return AudioSystem.STREAM_NOTIFICATION;
-                }
-            }
-            break;
-        }
-        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
-                + suggestedStreamType);
-        return suggestedStreamType;
-    }
-
-    private void broadcastRingerMode(String action, int ringerMode) {
-        // Send sticky broadcast
-        Intent broadcast = new Intent(action);
-        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
-        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
-                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        sendStickyBroadcastToAll(broadcast);
-    }
-
-    private void broadcastVibrateSetting(int vibrateType) {
-        // Send broadcast
-        if (ActivityManagerNative.isSystemReady()) {
-            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
-            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
-            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
-            sendBroadcastToAll(broadcast);
-        }
-    }
-
-    // Message helper methods
-    /**
-     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
-     * Note that the wake lock needs to be released after the message has been handled.
-     */
-    private void queueMsgUnderWakeLock(Handler handler, int msg,
-            int arg1, int arg2, Object obj, int delay) {
-        final long ident = Binder.clearCallingIdentity();
-        // Always acquire the wake lock as AudioService because it is released by the
-        // message handler.
-        mAudioEventWakeLock.acquire();
-        Binder.restoreCallingIdentity(ident);
-        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
-    }
-
-    private static void sendMsg(Handler handler, int msg,
-            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
-
-        if (existingMsgPolicy == SENDMSG_REPLACE) {
-            handler.removeMessages(msg);
-        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
-            return;
-        }
-        synchronized (mLastDeviceConnectMsgTime) {
-            long time = SystemClock.uptimeMillis() + delay;
-            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
-            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
-                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
-                mLastDeviceConnectMsgTime = time;
-            }
-        }
-    }
-
-    boolean checkAudioSettingsPermission(String method) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
-                == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        String msg = "Audio Settings Permission Denial: " + method + " from pid="
-                + Binder.getCallingPid()
-                + ", uid=" + Binder.getCallingUid();
-        Log.w(TAG, msg);
-        return false;
-    }
-
-    private int getDeviceForStream(int stream) {
-        int device = AudioSystem.getDevicesForStream(stream);
-        if ((device & (device - 1)) != 0) {
-            // Multiple device selection is either:
-            //  - speaker + one other device: give priority to speaker in this case.
-            //  - one A2DP device + another device: happens with duplicated output. In this case
-            // retain the device on the A2DP output as the other must not correspond to an active
-            // selection if not the speaker.
-            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
-            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
-                device = AudioSystem.DEVICE_OUT_SPEAKER;
-            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
-                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
-            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
-                device = AudioSystem.DEVICE_OUT_SPDIF;
-            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
-                device = AudioSystem.DEVICE_OUT_AUX_LINE;
-            } else {
-                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
-            }
-        }
-        return device;
-    }
-
-    public void setWiredDeviceConnectionState(int device, int state, String name) {
-        synchronized (mConnectedDevices) {
-            int delay = checkSendBecomingNoisyIntent(device, state);
-            queueMsgUnderWakeLock(mAudioHandler,
-                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
-                    device,
-                    state,
-                    name,
-                    delay);
-        }
-    }
-
-    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
-    {
-        int delay;
-        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
-            throw new IllegalArgumentException("invalid profile " + profile);
-        }
-        synchronized (mConnectedDevices) {
-            if (profile == BluetoothProfile.A2DP) {
-                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
-            } else {
-                delay = 0;
-            }
-            queueMsgUnderWakeLock(mAudioHandler,
-                    (profile == BluetoothProfile.A2DP ?
-                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
-                    state,
-                    0,
-                    device,
-                    delay);
-        }
-        return delay;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // Inner classes
-    ///////////////////////////////////////////////////////////////////////////
-
-    // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
-    //  1 mScoclient OR mSafeMediaVolumeState
-    //  2   mSetModeDeathHandlers
-    //  3     mSettingsLock
-    //  4       VolumeStreamState.class
-    //  5         mCameraSoundForced
-    public class VolumeStreamState {
-        private final int mStreamType;
-
-        private String mVolumeIndexSettingName;
-        private int mIndexMax;
-        private final ConcurrentHashMap<Integer, Integer> mIndex =
-                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
-        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
-
-        private VolumeStreamState(String settingName, int streamType) {
-
-            mVolumeIndexSettingName = settingName;
-
-            mStreamType = streamType;
-            mIndexMax = MAX_STREAM_VOLUME[streamType];
-            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
-            mIndexMax *= 10;
-
-            // mDeathHandlers must be created before calling readSettings()
-            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
-
-            readSettings();
-        }
-
-        public String getSettingNameForDevice(int device) {
-            String name = mVolumeIndexSettingName;
-            String suffix = AudioSystem.getOutputDeviceName(device);
-            if (suffix.isEmpty()) {
-                return name;
-            }
-            return name + "_" + suffix;
-        }
-
-        public void readSettings() {
-            synchronized (VolumeStreamState.class) {
-                // force maximum volume on all streams if fixed volume property
-                // or master volume property is set
-                if (mUseFixedVolume || mUseMasterVolume) {
-                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
-                    return;
-                }
-                // do not read system stream volume from settings: this stream is always aliased
-                // to another stream type and its volume is never persisted. Values in settings can
-                // only be stale values
-                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
-                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
-                    int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
-                    synchronized (mCameraSoundForced) {
-                        if (mCameraSoundForced) {
-                            index = mIndexMax;
-                        }
-                    }
-                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
-                    return;
-                }
-
-                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
-
-                for (int i = 0; remainingDevices != 0; i++) {
-                    int device = (1 << i);
-                    if ((device & remainingDevices) == 0) {
-                        continue;
-                    }
-                    remainingDevices &= ~device;
-
-                    // retrieve current volume for device
-                    String name = getSettingNameForDevice(device);
-                    // if no volume stored for current stream and device, use default volume if default
-                    // device, continue otherwise
-                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
-                                            DEFAULT_STREAM_VOLUME[mStreamType] : -1;
-                    int index = Settings.System.getIntForUser(
-                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
-                    if (index == -1) {
-                        continue;
-                    }
-
-                    mIndex.put(device, getValidIndex(10 * index));
-                }
-            }
-        }
-
-        // must be called while synchronized VolumeStreamState.class
-        public void applyDeviceVolume_syncVSS(int device) {
-            int index;
-            if (isMuted_syncVSS()) {
-                index = 0;
-            } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
-                    || ((device & mFullVolumeDevices) != 0)) {
-                index = (mIndexMax + 5)/10;
-            } else {
-                index = (getIndex(device) + 5)/10;
-            }
-            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
-        }
-
-        public void applyAllVolumes() {
-            synchronized (VolumeStreamState.class) {
-                // apply default volume first: by convention this will reset all
-                // devices volumes in audio policy manager to the supplied value
-                int index;
-                if (isMuted_syncVSS()) {
-                    index = 0;
-                } else {
-                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
-                }
-                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
-                // then apply device specific volumes
-                Set set = mIndex.entrySet();
-                Iterator i = set.iterator();
-                while (i.hasNext()) {
-                    Map.Entry entry = (Map.Entry)i.next();
-                    int device = ((Integer)entry.getKey()).intValue();
-                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
-                        if (isMuted_syncVSS()) {
-                            index = 0;
-                        } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
-                                mAvrcpAbsVolSupported)
-                                    || ((device & mFullVolumeDevices) != 0))
-                        {
-                            index = (mIndexMax + 5)/10;
-                        } else {
-                            index = ((Integer)entry.getValue() + 5)/10;
-                        }
-                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
-                    }
-                }
-            }
-        }
-
-        public boolean adjustIndex(int deltaIndex, int device) {
-            return setIndex(getIndex(device) + deltaIndex,
-                            device);
-        }
-
-        public boolean setIndex(int index, int device) {
-            synchronized (VolumeStreamState.class) {
-                int oldIndex = getIndex(device);
-                index = getValidIndex(index);
-                synchronized (mCameraSoundForced) {
-                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
-                        index = mIndexMax;
-                    }
-                }
-                mIndex.put(device, index);
-
-                if (oldIndex != index) {
-                    // Apply change to all streams using this one as alias
-                    // if changing volume of current device, also change volume of current
-                    // device on aliased stream
-                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
-                    int numStreamTypes = AudioSystem.getNumStreamTypes();
-                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                        if (streamType != mStreamType &&
-                                mStreamVolumeAlias[streamType] == mStreamType) {
-                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
-                            mStreamStates[streamType].setIndex(scaledIndex,
-                                                               device);
-                            if (currentDevice) {
-                                mStreamStates[streamType].setIndex(scaledIndex,
-                                                                   getDeviceForStream(streamType));
-                            }
-                        }
-                    }
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-        }
-
-        public int getIndex(int device) {
-            synchronized (VolumeStreamState.class) {
-                Integer index = mIndex.get(device);
-                if (index == null) {
-                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
-                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
-                }
-                return index.intValue();
-            }
-        }
-
-        public int getMaxIndex() {
-            return mIndexMax;
-        }
-
-        public void setAllIndexes(VolumeStreamState srcStream) {
-            synchronized (VolumeStreamState.class) {
-                int srcStreamType = srcStream.getStreamType();
-                // apply default device volume from source stream to all devices first in case
-                // some devices are present in this stream state but not in source stream state
-                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
-                index = rescaleIndex(index, srcStreamType, mStreamType);
-                Set set = mIndex.entrySet();
-                Iterator i = set.iterator();
-                while (i.hasNext()) {
-                    Map.Entry entry = (Map.Entry)i.next();
-                    entry.setValue(index);
-                }
-                // Now apply actual volume for devices in source stream state
-                set = srcStream.mIndex.entrySet();
-                i = set.iterator();
-                while (i.hasNext()) {
-                    Map.Entry entry = (Map.Entry)i.next();
-                    int device = ((Integer)entry.getKey()).intValue();
-                    index = ((Integer)entry.getValue()).intValue();
-                    index = rescaleIndex(index, srcStreamType, mStreamType);
-
-                    setIndex(index, device);
-                }
-            }
-        }
-
-        public void setAllIndexesToMax() {
-            synchronized (VolumeStreamState.class) {
-                Set set = mIndex.entrySet();
-                Iterator i = set.iterator();
-                while (i.hasNext()) {
-                    Map.Entry entry = (Map.Entry)i.next();
-                    entry.setValue(mIndexMax);
-                }
-            }
-        }
-
-        public void mute(IBinder cb, boolean state) {
-            synchronized (VolumeStreamState.class) {
-                VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
-                if (handler == null) {
-                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
-                    return;
-                }
-                handler.mute_syncVSS(state);
-            }
-        }
-
-        public int getStreamType() {
-            return mStreamType;
-        }
-
-        public void checkFixedVolumeDevices() {
-            synchronized (VolumeStreamState.class) {
-                // ignore settings for fixed volume devices: volume should always be at max or 0
-                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
-                    Set set = mIndex.entrySet();
-                    Iterator i = set.iterator();
-                    while (i.hasNext()) {
-                        Map.Entry entry = (Map.Entry)i.next();
-                        int device = ((Integer)entry.getKey()).intValue();
-                        int index = ((Integer)entry.getValue()).intValue();
-                        if (((device & mFullVolumeDevices) != 0)
-                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
-                            entry.setValue(mIndexMax);
-                        }
-                        applyDeviceVolume_syncVSS(device);
-                    }
-                }
-            }
-        }
-
-        private int getValidIndex(int index) {
-            if (index < 0) {
-                return 0;
-            } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
-                return mIndexMax;
-            }
-
-            return index;
-        }
-
-        private class VolumeDeathHandler implements IBinder.DeathRecipient {
-            private IBinder mICallback; // To be notified of client's death
-            private int mMuteCount; // Number of active mutes for this client
-
-            VolumeDeathHandler(IBinder cb) {
-                mICallback = cb;
-            }
-
-            // must be called while synchronized VolumeStreamState.class
-            public void mute_syncVSS(boolean state) {
-                boolean updateVolume = false;
-                if (state) {
-                    if (mMuteCount == 0) {
-                        // Register for client death notification
-                        try {
-                            // mICallback can be 0 if muted by AudioService
-                            if (mICallback != null) {
-                                mICallback.linkToDeath(this, 0);
-                            }
-                            VolumeStreamState.this.mDeathHandlers.add(this);
-                            // If the stream is not yet muted by any client, set level to 0
-                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
-                                updateVolume = true;
-                            }
-                        } catch (RemoteException e) {
-                            // Client has died!
-                            binderDied();
-                            return;
-                        }
-                    } else {
-                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
-                    }
-                    mMuteCount++;
-                } else {
-                    if (mMuteCount == 0) {
-                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
-                    } else {
-                        mMuteCount--;
-                        if (mMuteCount == 0) {
-                            // Unregister from client death notification
-                            VolumeStreamState.this.mDeathHandlers.remove(this);
-                            // mICallback can be 0 if muted by AudioService
-                            if (mICallback != null) {
-                                mICallback.unlinkToDeath(this, 0);
-                            }
-                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
-                                updateVolume = true;
-                            }
-                        }
-                    }
-                }
-                if (updateVolume) {
-                    sendMsg(mAudioHandler,
-                            MSG_SET_ALL_VOLUMES,
-                            SENDMSG_QUEUE,
-                            0,
-                            0,
-                            VolumeStreamState.this, 0);
-                }
-            }
-
-            public void binderDied() {
-                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
-                synchronized (VolumeStreamState.class) {
-                    if (mMuteCount != 0) {
-                        // Reset all active mute requests from this client.
-                        mMuteCount = 1;
-                        mute_syncVSS(false);
-                    }
-                }
-            }
-        }
-
-        private int muteCount() {
-            int count = 0;
-            int size = mDeathHandlers.size();
-            for (int i = 0; i < size; i++) {
-                count += mDeathHandlers.get(i).mMuteCount;
-            }
-            return count;
-        }
-
-        // must be called while synchronized VolumeStreamState.class
-        private boolean isMuted_syncVSS() {
-            return muteCount() != 0;
-        }
-
-        // must be called while synchronized VolumeStreamState.class
-        private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
-            VolumeDeathHandler handler;
-            int size = mDeathHandlers.size();
-            for (int i = 0; i < size; i++) {
-                handler = mDeathHandlers.get(i);
-                if (cb == handler.mICallback) {
-                    return handler;
-                }
-            }
-            // If this is the first mute request for this client, create a new
-            // client death handler. Otherwise, it is an out of sequence unmute request.
-            if (state) {
-                handler = new VolumeDeathHandler(cb);
-            } else {
-                Log.w(TAG, "stream was not muted by this client");
-                handler = null;
-            }
-            return handler;
-        }
-
-        private void dump(PrintWriter pw) {
-            pw.print("   Mute count: ");
-            pw.println(muteCount());
-            pw.print("   Max: ");
-            pw.println((mIndexMax + 5) / 10);
-            pw.print("   Current: ");
-            Set set = mIndex.entrySet();
-            Iterator i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                final int device = (Integer) entry.getKey();
-                pw.print(Integer.toHexString(device));
-                final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
-                        : AudioSystem.getOutputDeviceName(device);
-                if (!deviceName.isEmpty()) {
-                    pw.print(" (");
-                    pw.print(deviceName);
-                    pw.print(")");
-                }
-                pw.print(": ");
-                final int index = (((Integer) entry.getValue()) + 5) / 10;
-                pw.print(index);
-                if (i.hasNext()) {
-                    pw.print(", ");
-                }
-            }
-        }
-    }
-
-    /** Thread that handles native AudioSystem control. */
-    private class AudioSystemThread extends Thread {
-        AudioSystemThread() {
-            super("AudioService");
-        }
-
-        @Override
-        public void run() {
-            // Set this thread up so the handler will work on it
-            Looper.prepare();
-
-            synchronized(AudioService.this) {
-                mAudioHandler = new AudioHandler();
-
-                // Notify that the handler has been created
-                AudioService.this.notify();
-            }
-
-            // Listen for volume change requests that are set by VolumePanel
-            Looper.loop();
-        }
-    }
-
-    /** Handles internal volume messages in separate volume thread. */
-    private class AudioHandler extends Handler {
-
-        private void setDeviceVolume(VolumeStreamState streamState, int device) {
-
-            synchronized (VolumeStreamState.class) {
-                // Apply volume
-                streamState.applyDeviceVolume_syncVSS(device);
-
-                // Apply change to all streams using this one as alias
-                int numStreamTypes = AudioSystem.getNumStreamTypes();
-                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                    if (streamType != streamState.mStreamType &&
-                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-                        // Make sure volume is also maxed out on A2DP device for aliased stream
-                        // that may have a different device selected
-                        int streamDevice = getDeviceForStream(streamType);
-                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
-                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
-                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
-                        }
-                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
-                    }
-                }
-            }
-            // Post a persist volume msg
-            sendMsg(mAudioHandler,
-                    MSG_PERSIST_VOLUME,
-                    SENDMSG_QUEUE,
-                    device,
-                    0,
-                    streamState,
-                    PERSIST_DELAY);
-
-        }
-
-        private void setAllVolumes(VolumeStreamState streamState) {
-
-            // Apply volume
-            streamState.applyAllVolumes();
-
-            // Apply change to all streams using this one as alias
-            int numStreamTypes = AudioSystem.getNumStreamTypes();
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (streamType != streamState.mStreamType &&
-                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-                    mStreamStates[streamType].applyAllVolumes();
-                }
-            }
-        }
-
-        private void persistVolume(VolumeStreamState streamState, int device) {
-            if (mUseFixedVolume) {
-                return;
-            }
-            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
-                return;
-            }
-            System.putIntForUser(mContentResolver,
-                      streamState.getSettingNameForDevice(device),
-                      (streamState.getIndex(device) + 5)/ 10,
-                      UserHandle.USER_CURRENT);
-        }
-
-        private void persistRingerMode(int ringerMode) {
-            if (mUseFixedVolume) {
-                return;
-            }
-            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
-        }
-
-        private boolean onLoadSoundEffects() {
-            int status;
-
-            synchronized (mSoundEffectsLock) {
-                if (!mSystemReady) {
-                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
-                    return false;
-                }
-
-                if (mSoundPool != null) {
-                    return true;
-                }
-
-                loadTouchSoundAssets();
-
-                mSoundPool = new SoundPool.Builder()
-                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
-                        .setAudioAttributes(new AudioAttributes.Builder()
-                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                            .build())
-                        .build();
-                mSoundPoolCallBack = null;
-                mSoundPoolListenerThread = new SoundPoolListenerThread();
-                mSoundPoolListenerThread.start();
-                int attempts = 3;
-                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
-                    try {
-                        // Wait for mSoundPoolCallBack to be set by the other thread
-                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                    } catch (InterruptedException e) {
-                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
-                    }
-                }
-
-                if (mSoundPoolCallBack == null) {
-                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
-                    if (mSoundPoolLooper != null) {
-                        mSoundPoolLooper.quit();
-                        mSoundPoolLooper = null;
-                    }
-                    mSoundPoolListenerThread = null;
-                    mSoundPool.release();
-                    mSoundPool = null;
-                    return false;
-                }
-                /*
-                 * poolId table: The value -1 in this table indicates that corresponding
-                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
-                 * Once loaded, the value in poolId is the sample ID and the same
-                 * sample can be reused for another effect using the same file.
-                 */
-                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
-                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
-                    poolId[fileIdx] = -1;
-                }
-                /*
-                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
-                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
-                 * this indicates we have a valid sample loaded for this effect.
-                 */
-
-                int numSamples = 0;
-                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                    // Do not load sample if this effect uses the MediaPlayer
-                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
-                        continue;
-                    }
-                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
-                        String filePath = Environment.getRootDirectory()
-                                + SOUND_EFFECTS_PATH
-                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
-                        int sampleId = mSoundPool.load(filePath, 0);
-                        if (sampleId <= 0) {
-                            Log.w(TAG, "Soundpool could not load file: "+filePath);
-                        } else {
-                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
-                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
-                            numSamples++;
-                        }
-                    } else {
-                        SOUND_EFFECT_FILES_MAP[effect][1] =
-                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
-                    }
-                }
-                // wait for all samples to be loaded
-                if (numSamples > 0) {
-                    mSoundPoolCallBack.setSamples(poolId);
-
-                    attempts = 3;
-                    status = 1;
-                    while ((status == 1) && (attempts-- > 0)) {
-                        try {
-                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                            status = mSoundPoolCallBack.status();
-                        } catch (InterruptedException e) {
-                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
-                        }
-                    }
-                } else {
-                    status = -1;
-                }
-
-                if (mSoundPoolLooper != null) {
-                    mSoundPoolLooper.quit();
-                    mSoundPoolLooper = null;
-                }
-                mSoundPoolListenerThread = null;
-                if (status != 0) {
-                    Log.w(TAG,
-                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
-                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
-                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                        }
-                    }
-
-                    mSoundPool.release();
-                    mSoundPool = null;
-                }
-            }
-            return (status == 0);
-        }
-
-        /**
-         *  Unloads samples from the sound pool.
-         *  This method can be called to free some memory when
-         *  sound effects are disabled.
-         */
-        private void onUnloadSoundEffects() {
-            synchronized (mSoundEffectsLock) {
-                if (mSoundPool == null) {
-                    return;
-                }
-
-                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
-                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
-                    poolId[fileIdx] = 0;
-                }
-
-                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
-                        continue;
-                    }
-                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
-                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
-                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
-                    }
-                }
-                mSoundPool.release();
-                mSoundPool = null;
-            }
-        }
-
-        private void onPlaySoundEffect(int effectType, int volume) {
-            synchronized (mSoundEffectsLock) {
-
-                onLoadSoundEffects();
-
-                if (mSoundPool == null) {
-                    return;
-                }
-                float volFloat;
-                // use default if volume is not specified by caller
-                if (volume < 0) {
-                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
-                } else {
-                    volFloat = volume / 1000.0f;
-                }
-
-                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
-                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
-                                        volFloat, volFloat, 0, 0, 1.0f);
-                } else {
-                    MediaPlayer mediaPlayer = new MediaPlayer();
-                    try {
-                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
-                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
-                        mediaPlayer.setDataSource(filePath);
-                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
-                        mediaPlayer.prepare();
-                        mediaPlayer.setVolume(volFloat);
-                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
-                            public void onCompletion(MediaPlayer mp) {
-                                cleanupPlayer(mp);
-                            }
-                        });
-                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
-                            public boolean onError(MediaPlayer mp, int what, int extra) {
-                                cleanupPlayer(mp);
-                                return true;
-                            }
-                        });
-                        mediaPlayer.start();
-                    } catch (IOException ex) {
-                        Log.w(TAG, "MediaPlayer IOException: "+ex);
-                    } catch (IllegalArgumentException ex) {
-                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
-                    } catch (IllegalStateException ex) {
-                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
-                    }
-                }
-            }
-        }
-
-        private void cleanupPlayer(MediaPlayer mp) {
-            if (mp != null) {
-                try {
-                    mp.stop();
-                    mp.release();
-                } catch (IllegalStateException ex) {
-                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
-                }
-            }
-        }
-
-        private void setForceUse(int usage, int config) {
-            AudioSystem.setForceUse(usage, config);
-        }
-
-        private void onPersistSafeVolumeState(int state) {
-            Settings.Global.putInt(mContentResolver,
-                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
-                    state);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-
-                case MSG_SET_DEVICE_VOLUME:
-                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
-                    break;
-
-                case MSG_SET_ALL_VOLUMES:
-                    setAllVolumes((VolumeStreamState) msg.obj);
-                    break;
-
-                case MSG_PERSIST_VOLUME:
-                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
-                    break;
-
-                case MSG_PERSIST_MASTER_VOLUME:
-                    if (mUseFixedVolume) {
-                        return;
-                    }
-                    Settings.System.putFloatForUser(mContentResolver,
-                                                    Settings.System.VOLUME_MASTER,
-                                                    msg.arg1 / (float)1000.0,
-                                                    UserHandle.USER_CURRENT);
-                    break;
-
-                case MSG_PERSIST_MASTER_VOLUME_MUTE:
-                    if (mUseFixedVolume) {
-                        return;
-                    }
-                    Settings.System.putIntForUser(mContentResolver,
-                                                 Settings.System.VOLUME_MASTER_MUTE,
-                                                 msg.arg1,
-                                                 msg.arg2);
-                    break;
-
-                case MSG_PERSIST_RINGER_MODE:
-                    // note that the value persisted is the current ringer mode, not the
-                    // value of ringer mode as of the time the request was made to persist
-                    persistRingerMode(getRingerModeInternal());
-                    break;
-
-                case MSG_MEDIA_SERVER_DIED:
-                    if (!mSystemReady ||
-                            (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
-                        Log.e(TAG, "Media server died.");
-                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
-                                null, 500);
-                        break;
-                    }
-                    Log.e(TAG, "Media server started.");
-
-                    // indicate to audio HAL that we start the reconfiguration phase after a media
-                    // server crash
-                    // Note that we only execute this when the media server
-                    // process restarts after a crash, not the first time it is started.
-                    AudioSystem.setParameters("restarting=true");
-
-                    readAndSetLowRamDevice();
-
-                    // Restore device connection states
-                    synchronized (mConnectedDevices) {
-                        Set set = mConnectedDevices.entrySet();
-                        Iterator i = set.iterator();
-                        while (i.hasNext()) {
-                            Map.Entry device = (Map.Entry)i.next();
-                            AudioSystem.setDeviceConnectionState(
-                                                            ((Integer)device.getKey()).intValue(),
-                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                            (String)device.getValue());
-                        }
-                    }
-                    // Restore call state
-                    AudioSystem.setPhoneState(mMode);
-
-                    // Restore forced usage for communcations and record
-                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
-                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
-                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
-                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
-
-                    // Restore stream volumes
-                    int numStreamTypes = AudioSystem.getNumStreamTypes();
-                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                        VolumeStreamState streamState = mStreamStates[streamType];
-                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
-
-                        streamState.applyAllVolumes();
-                    }
-
-                    // Restore ringer mode
-                    setRingerModeInt(getRingerModeInternal(), false);
-
-                    // Restore master volume
-                    restoreMasterVolume();
-
-                    // Reset device orientation (if monitored for this device)
-                    if (mMonitorOrientation) {
-                        setOrientationForAudioSystem();
-                    }
-                    if (mMonitorRotation) {
-                        setRotationForAudioSystem();
-                    }
-
-                    synchronized (mBluetoothA2dpEnabledLock) {
-                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
-                                mBluetoothA2dpEnabled ?
-                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
-                    }
-
-                    synchronized (mSettingsLock) {
-                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
-                                mDockAudioMediaEnabled ?
-                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
-                    }
-                    if (mHdmiManager != null) {
-                        synchronized (mHdmiManager) {
-                            if (mHdmiTvClient != null) {
-                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
-                            }
-                        }
-                    }
-
-                    synchronized (mAudioPolicies) {
-                        for(AudioPolicyProxy policy : mAudioPolicies.values()) {
-                            policy.connectMixes();
-                        }
-                    }
-
-                    // indicate the end of reconfiguration phase to audio HAL
-                    AudioSystem.setParameters("restarting=false");
-                    break;
-
-                case MSG_UNLOAD_SOUND_EFFECTS:
-                    onUnloadSoundEffects();
-                    break;
-
-                case MSG_LOAD_SOUND_EFFECTS:
-                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
-                    // can take several dozens of milliseconds to complete
-                    boolean loaded = onLoadSoundEffects();
-                    if (msg.obj != null) {
-                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
-                        synchronized (reply) {
-                            reply.mStatus = loaded ? 0 : -1;
-                            reply.notify();
-                        }
-                    }
-                    break;
-
-                case MSG_PLAY_SOUND_EFFECT:
-                    onPlaySoundEffect(msg.arg1, msg.arg2);
-                    break;
-
-                case MSG_BTA2DP_DOCK_TIMEOUT:
-                    // msg.obj  == address of BTA2DP device
-                    synchronized (mConnectedDevices) {
-                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
-                    }
-                    break;
-
-                case MSG_SET_FORCE_USE:
-                case MSG_SET_FORCE_BT_A2DP_USE:
-                    setForceUse(msg.arg1, msg.arg2);
-                    break;
-
-                case MSG_BT_HEADSET_CNCT_FAILED:
-                    resetBluetoothSco();
-                    break;
-
-                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
-                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
-                    mAudioEventWakeLock.release();
-                    break;
-
-                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
-                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
-                    mAudioEventWakeLock.release();
-                    break;
-
-                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
-                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
-                    mAudioEventWakeLock.release();
-                    break;
-
-                case MSG_REPORT_NEW_ROUTES: {
-                    int N = mRoutesObservers.beginBroadcast();
-                    if (N > 0) {
-                        AudioRoutesInfo routes;
-                        synchronized (mCurAudioRoutes) {
-                            routes = new AudioRoutesInfo(mCurAudioRoutes);
-                        }
-                        while (N > 0) {
-                            N--;
-                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
-                            try {
-                                obs.dispatchAudioRoutesChanged(routes);
-                            } catch (RemoteException e) {
-                            }
-                        }
-                    }
-                    mRoutesObservers.finishBroadcast();
-                    break;
-                }
-
-                case MSG_CHECK_MUSIC_ACTIVE:
-                    onCheckMusicActive();
-                    break;
-
-                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
-                    onSendBecomingNoisyIntent();
-                    break;
-
-                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
-                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
-                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
-                    break;
-                case MSG_PERSIST_SAFE_VOLUME_STATE:
-                    onPersistSafeVolumeState(msg.arg1);
-                    break;
-
-                case MSG_BROADCAST_BT_CONNECTION_STATE:
-                    onBroadcastScoConnectionState(msg.arg1);
-                    break;
-
-                case MSG_SYSTEM_READY:
-                    onSystemReady();
-                    break;
-
-                case MSG_PERSIST_MUSIC_ACTIVE_MS:
-                    final int musicActiveMs = msg.arg1;
-                    Settings.Secure.putIntForUser(mContentResolver,
-                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
-                            UserHandle.USER_CURRENT);
-                    break;
-                case MSG_PERSIST_MICROPHONE_MUTE:
-                    Settings.System.putIntForUser(mContentResolver,
-                                                 Settings.System.MICROPHONE_MUTE,
-                                                 msg.arg1,
-                                                 msg.arg2);
-                    break;
-            }
-        }
-    }
-
-    private class SettingsObserver extends ContentObserver {
-
-        SettingsObserver() {
-            super(new Handler());
-            mContentResolver.registerContentObserver(Settings.System.getUriFor(
-                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
-            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
-            //       However there appear to be some missing locks around mRingerModeMutedStreams
-            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
-            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
-            synchronized (mSettingsLock) {
-                if (updateRingerModeAffectedStreams()) {
-                    /*
-                     * Ensure all stream types that should be affected by ringer mode
-                     * are in the proper state.
-                     */
-                    setRingerModeInt(getRingerModeInternal(), false);
-                }
-                readDockAudioSettings(mContentResolver);
-            }
-        }
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceAvailable(String address) {
-        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
-        // audio policy manager
-        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
-                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
-        setBluetoothA2dpOnInt(true);
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address);
-        // Reset A2DP suspend state each time a new sink is connected
-        AudioSystem.setParameters("A2dpSuspended=false");
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
-                address);
-    }
-
-    private void onSendBecomingNoisyIntent() {
-        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceUnavailableNow(String address) {
-        synchronized (mA2dpAvrcpLock) {
-            mAvrcpAbsVolSupported = false;
-        }
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address);
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
-        synchronized (mCurAudioRoutes) {
-            // Remove A2DP routes as well
-            if (mCurAudioRoutes.mBluetoothName != null) {
-                mCurAudioRoutes.mBluetoothName = null;
-                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                        SENDMSG_NOOP, 0, 0, null, 0);
-            }
-        }
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceUnavailableLater(String address) {
-        // prevent any activity on the A2DP audio output to avoid unwanted
-        // reconnection of the sink.
-        AudioSystem.setParameters("A2dpSuspended=true");
-        // the device will be made unavailable later, so consider it disconnected right away
-        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
-        // send the delayed message to make the device unavailable later
-        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
-        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
-
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void makeA2dpSrcAvailable(String address) {
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE,
-                address);
-        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
-                address);
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void makeA2dpSrcUnavailable(String address) {
-        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                address);
-        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private void cancelA2dpDeviceTimeout() {
-        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
-    }
-
-    // must be called synchronized on mConnectedDevices
-    private boolean hasScheduledA2dpDockTimeout() {
-        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
-    }
-
-    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
-    {
-        if (DEBUG_VOL) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
-        }
-        if (btDevice == null) {
-            return;
-        }
-        String address = btDevice.getAddress();
-        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-            address = "";
-        }
-
-        synchronized (mConnectedDevices) {
-            boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
-
-            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
-                if (btDevice.isBluetoothDock()) {
-                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                        // introduction of a delay for transient disconnections of docks when
-                        // power is rapidly turned off/on, this message will be canceled if
-                        // we reconnect the dock under a preset delay
-                        makeA2dpDeviceUnavailableLater(address);
-                        // the next time isConnected is evaluated, it will be false for the dock
-                    }
-                } else {
-                    makeA2dpDeviceUnavailableNow(address);
-                }
-                synchronized (mCurAudioRoutes) {
-                    if (mCurAudioRoutes.mBluetoothName != null) {
-                        mCurAudioRoutes.mBluetoothName = null;
-                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                                SENDMSG_NOOP, 0, 0, null, 0);
-                    }
-                }
-            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
-                if (btDevice.isBluetoothDock()) {
-                    // this could be a reconnection after a transient disconnection
-                    cancelA2dpDeviceTimeout();
-                    mDockAddress = address;
-                } else {
-                    // this could be a connection of another A2DP device before the timeout of
-                    // a dock: cancel the dock timeout, and make the dock unavailable now
-                    if(hasScheduledA2dpDockTimeout()) {
-                        cancelA2dpDeviceTimeout();
-                        makeA2dpDeviceUnavailableNow(mDockAddress);
-                    }
-                }
-                makeA2dpDeviceAvailable(address);
-                synchronized (mCurAudioRoutes) {
-                    String name = btDevice.getAliasName();
-                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
-                        mCurAudioRoutes.mBluetoothName = name;
-                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                                SENDMSG_NOOP, 0, 0, null, 0);
-                    }
-                }
-            }
-        }
-    }
-
-    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
-    {
-        if (DEBUG_VOL) {
-            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
-        }
-        if (btDevice == null) {
-            return;
-        }
-        String address = btDevice.getAddress();
-        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-            address = "";
-        }
-
-        synchronized (mConnectedDevices) {
-                boolean isConnected =
-                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
-                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
-
-            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
-                makeA2dpSrcUnavailable(address);
-            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
-                makeA2dpSrcAvailable(address);
-            }
-        }
-    }
-
-    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
-        // address is not used for now, but may be used when multiple a2dp devices are supported
-        synchronized (mA2dpAvrcpLock) {
-            mAvrcpAbsVolSupported = support;
-            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
-                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
-                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
-            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
-                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
-                    mStreamStates[AudioSystem.STREAM_RING], 0);
-        }
-    }
-
-    private boolean handleDeviceConnection(boolean connected, int device, String params) {
-        synchronized (mConnectedDevices) {
-            boolean isConnected = (mConnectedDevices.containsKey(device) &&
-                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
-
-            if (isConnected && !connected) {
-                AudioSystem.setDeviceConnectionState(device,
-                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                                              mConnectedDevices.get(device));
-                 mConnectedDevices.remove(device);
-                 return true;
-            } else if (!isConnected && connected) {
-                 AudioSystem.setDeviceConnectionState(device,
-                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                      params);
-                 mConnectedDevices.put(new Integer(device), params);
-                 return true;
-            }
-        }
-        return false;
-    }
-
-    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
-    // sent if none of these devices is connected.
-    int mBecomingNoisyIntentDevices =
-            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
-            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
-            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
-            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
-
-    // must be called before removing the device from mConnectedDevices
-    private int checkSendBecomingNoisyIntent(int device, int state) {
-        int delay = 0;
-        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
-            int devices = 0;
-            for (int dev : mConnectedDevices.keySet()) {
-                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
-                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
-                   devices |= dev;
-                }
-            }
-            if (devices == device) {
-                sendMsg(mAudioHandler,
-                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        null,
-                        0);
-                delay = 1000;
-            }
-        }
-
-        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
-                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
-            synchronized (mLastDeviceConnectMsgTime) {
-                long time = SystemClock.uptimeMillis();
-                if (mLastDeviceConnectMsgTime > time) {
-                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
-                }
-            }
-        }
-        return delay;
-    }
-
-    private void sendDeviceConnectionIntent(int device, int state, String name)
-    {
-        Intent intent = new Intent();
-
-        intent.putExtra("state", state);
-        intent.putExtra("name", name);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-
-        int connType = 0;
-
-        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
-            connType = AudioRoutesInfo.MAIN_HEADSET;
-            intent.setAction(Intent.ACTION_HEADSET_PLUG);
-            intent.putExtra("microphone", 1);
-        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
-                   device == AudioSystem.DEVICE_OUT_LINE) {
-            /*do apps care about line-out vs headphones?*/
-            connType = AudioRoutesInfo.MAIN_HEADPHONES;
-            intent.setAction(Intent.ACTION_HEADSET_PLUG);
-            intent.putExtra("microphone", 0);
-        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
-            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
-            intent.setAction(AudioManager.ACTION_ANALOG_AUDIO_DOCK_PLUG);
-        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
-            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
-            intent.setAction(AudioManager.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
-        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
-                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
-            connType = AudioRoutesInfo.MAIN_HDMI;
-            configureHdmiPlugIntent(intent, state);
-        }
-
-        synchronized (mCurAudioRoutes) {
-            if (connType != 0) {
-                int newConn = mCurAudioRoutes.mMainType;
-                if (state != 0) {
-                    newConn |= connType;
-                } else {
-                    newConn &= ~connType;
-                }
-                if (newConn != mCurAudioRoutes.mMainType) {
-                    mCurAudioRoutes.mMainType = newConn;
-                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
-                            SENDMSG_NOOP, 0, 0, null, 0);
-                }
-            }
-        }
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    private void onSetWiredDeviceConnectionState(int device, int state, String name)
-    {
-        synchronized (mConnectedDevices) {
-            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
-                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
-                    (device == AudioSystem.DEVICE_OUT_LINE))) {
-                setBluetoothA2dpOnInt(true);
-            }
-            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
-                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
-                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
-            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
-            if (state != 0) {
-                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
-                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
-                    (device == AudioSystem.DEVICE_OUT_LINE)) {
-                    setBluetoothA2dpOnInt(false);
-                }
-                if ((device & mSafeMediaVolumeDevices) != 0) {
-                    sendMsg(mAudioHandler,
-                            MSG_CHECK_MUSIC_ACTIVE,
-                            SENDMSG_REPLACE,
-                            0,
-                            0,
-                            null,
-                            MUSIC_ACTIVE_POLL_PERIOD_MS);
-                }
-                // Television devices without CEC service apply software volume on HDMI output
-                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
-                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
-                    checkAllFixedVolumeDevices();
-                    if (mHdmiManager != null) {
-                        synchronized (mHdmiManager) {
-                            if (mHdmiPlaybackClient != null) {
-                                mHdmiCecSink = false;
-                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
-                            }
-                        }
-                    }
-                }
-            } else {
-                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
-                    if (mHdmiManager != null) {
-                        synchronized (mHdmiManager) {
-                            mHdmiCecSink = false;
-                        }
-                    }
-                }
-            }
-            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
-                sendDeviceConnectionIntent(device, state, name);
-            }
-        }
-    }
-
-    private void configureHdmiPlugIntent(Intent intent, int state) {
-        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
-        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
-        if (state == 1) {
-            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
-            int[] portGeneration = new int[1];
-            int status = AudioSystem.listAudioPorts(ports, portGeneration);
-            if (status == AudioManager.SUCCESS) {
-                for (AudioPort port : ports) {
-                    if (port instanceof AudioDevicePort) {
-                        final AudioDevicePort devicePort = (AudioDevicePort) port;
-                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
-                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
-                            // format the list of supported encodings
-                            int[] formats = devicePort.formats();
-                            if (formats.length > 0) {
-                                ArrayList<Integer> encodingList = new ArrayList(1);
-                                for (int format : formats) {
-                                    // a format in the list can be 0, skip it
-                                    if (format != AudioFormat.ENCODING_INVALID) {
-                                        encodingList.add(format);
-                                    }
-                                }
-                                int[] encodingArray = new int[encodingList.size()];
-                                for (int i = 0 ; i < encodingArray.length ; i++) {
-                                    encodingArray[i] = encodingList.get(i);
-                                }
-                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
-                            }
-                            // find the maximum supported number of channels
-                            int maxChannels = 0;
-                            for (int mask : devicePort.channelMasks()) {
-                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
-                                if (channelCount > maxChannels) {
-                                    maxChannels = channelCount;
-                                }
-                            }
-                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /* cache of the address of the last dock the device was connected to */
-    private String mDockAddress;
-
-    /**
-     * Receiver for misc intent broadcasts the Phone app cares about.
-     */
-    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            int outDevice;
-            int inDevice;
-            int state;
-
-            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
-                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
-                int config;
-                switch (dockState) {
-                    case Intent.EXTRA_DOCK_STATE_DESK:
-                        config = AudioSystem.FORCE_BT_DESK_DOCK;
-                        break;
-                    case Intent.EXTRA_DOCK_STATE_CAR:
-                        config = AudioSystem.FORCE_BT_CAR_DOCK;
-                        break;
-                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
-                        config = AudioSystem.FORCE_ANALOG_DOCK;
-                        break;
-                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
-                        config = AudioSystem.FORCE_DIGITAL_DOCK;
-                        break;
-                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
-                    default:
-                        config = AudioSystem.FORCE_NONE;
-                }
-                // Low end docks have a menu to enable or disable audio
-                // (see mDockAudioMediaEnabled)
-                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
-                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
-                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
-                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
-                }
-                mDockState = dockState;
-            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
-                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
-                                               BluetoothProfile.STATE_DISCONNECTED);
-                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-                String address = null;
-
-                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                if (btDevice == null) {
-                    return;
-                }
-
-                address = btDevice.getAddress();
-                BluetoothClass btClass = btDevice.getBluetoothClass();
-                if (btClass != null) {
-                    switch (btClass.getDeviceClass()) {
-                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
-                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-                        break;
-                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
-                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                        break;
-                    }
-                }
-
-                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-                    address = "";
-                }
-
-                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
-                boolean success = handleDeviceConnection(connected, outDevice, address) &&
-                                      handleDeviceConnection(connected, inDevice, address);
-                if (success) {
-                    synchronized (mScoClients) {
-                        if (connected) {
-                            mBluetoothHeadsetDevice = btDevice;
-                        } else {
-                            mBluetoothHeadsetDevice = null;
-                            resetBluetoothSco();
-                        }
-                    }
-                }
-            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
-                state = intent.getIntExtra("state", 0);
-
-                int alsaCard = intent.getIntExtra("card", -1);
-                int alsaDevice = intent.getIntExtra("device", -1);
-
-                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
-                                    : "card=" + alsaCard + ";device=" + alsaDevice);
-
-                // Playback Device
-                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
-                setWiredDeviceConnectionState(outDevice, state, params);
-            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {
-                // FIXME Does not yet handle the case where the setting is changed
-                // after device connection.  Ideally we should handle the settings change
-                // in SettingsObserver. Here we should log that a USB device is connected
-                // and disconnected with its address (card , device) and force the
-                // connection or disconnection when the setting changes.
-                int isDisabled = Settings.Secure.getInt(mContentResolver,
-                        Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
-                if (isDisabled != 0) {
-                    return;
-                }
-
-                state = intent.getIntExtra("state", 0);
-
-                int alsaCard = intent.getIntExtra("card", -1);
-                int alsaDevice = intent.getIntExtra("device", -1);
-                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
-                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
-                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
-
-                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
-                                    : "card=" + alsaCard + ";device=" + alsaDevice);
-
-                // Playback Device
-                if (hasPlayback) {
-                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
-                    setWiredDeviceConnectionState(outDevice, state, params);
-                }
-
-                // Capture Device
-                if (hasCapture) {
-                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
-                    setWiredDeviceConnectionState(inDevice, state, params);
-                }
-            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
-                boolean broadcast = false;
-                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
-                synchronized (mScoClients) {
-                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-                    // broadcast intent if the connection was initated by AudioService
-                    if (!mScoClients.isEmpty() &&
-                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
-                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
-                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
-                        broadcast = true;
-                    }
-                    switch (btState) {
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                        }
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
-                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
-                        mScoAudioState = SCO_STATE_INACTIVE;
-                        clearAllScoClients(0, false);
-                        break;
-                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
-                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
-                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
-                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
-                        }
-                    default:
-                        // do not broadcast CONNECTING or invalid state
-                        broadcast = false;
-                        break;
-                    }
-                }
-                if (broadcast) {
-                    broadcastScoConnectionState(scoAudioState);
-                    //FIXME: this is to maintain compatibility with deprecated intent
-                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
-                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
-                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
-                    sendStickyBroadcastToAll(newIntent);
-                }
-            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                if (mMonitorRotation) {
-                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
-                    mOrientationListener.enable();
-                }
-                AudioSystem.setParameters("screen_state=on");
-            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                if (mMonitorRotation) {
-                    //reduce wakeups (save current) by only listening when display is on
-                    mOrientationListener.disable();
-                }
-                AudioSystem.setParameters("screen_state=off");
-            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                handleConfigurationChanged(context);
-            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
-                // attempt to stop music playback for background user
-                sendMsg(mAudioHandler,
-                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        null,
-                        0);
-                // the current audio focus owner is no longer valid
-                mMediaFocusControl.discardAudioFocusOwner();
-
-                // load volume settings for new user
-                readAudioSettings(true /*userSwitch*/);
-                // preserve STREAM_MUSIC volume from one user to the next.
-                sendMsg(mAudioHandler,
-                        MSG_SET_ALL_VOLUMES,
-                        SENDMSG_QUEUE,
-                        0,
-                        0,
-                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
-            }
-        }
-    } // end class AudioServiceBroadcastReceiver
-
-    //==========================================================================================
-    // RemoteControlDisplay / RemoteControlClient / Remote info
-    //==========================================================================================
-    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
-    }
-
-    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
-    }
-
-    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
-    }
-
-    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
-    }
-
-    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
-            boolean wantsSync) {
-        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
-    }
-
-    @Override
-    public void setRemoteStreamVolume(int index) {
-        enforceSelfOrSystemUI("set the remote stream volume");
-        mMediaFocusControl.setRemoteStreamVolume(index);
-    }
-
-    //==========================================================================================
-    // Audio Focus
-    //==========================================================================================
-    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
-            IAudioPolicyCallback pcb) {
-        // permission checks
-        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
-            if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
-                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
-                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
-                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                }
-            } else {
-                // only a registered audio policy can be used to lock focus
-                synchronized (mAudioPolicies) {
-                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
-                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
-                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                    }
-                }
-            }
-        }
-
-        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
-                clientId, callingPackageName, flags);
-    }
-
-    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
-        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
-    }
-
-    public void unregisterAudioFocusClient(String clientId) {
-        mMediaFocusControl.unregisterAudioFocusClient(clientId);
-    }
-
-    public int getCurrentAudioFocus() {
-        return mMediaFocusControl.getCurrentAudioFocus();
-    }
-
-    //==========================================================================================
-    // Device orientation
-    //==========================================================================================
-    /**
-     * Handles device configuration changes that may map to a change in the orientation
-     * or orientation.
-     * Monitoring orientation and rotation is optional, and is defined by the definition and value
-     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
-     */
-    private void handleConfigurationChanged(Context context) {
-        try {
-            // reading new orientation "safely" (i.e. under try catch) in case anything
-            // goes wrong when obtaining resources and configuration
-            Configuration config = context.getResources().getConfiguration();
-            // TODO merge rotation and orientation
-            if (mMonitorOrientation) {
-                int newOrientation = config.orientation;
-                if (newOrientation != mDeviceOrientation) {
-                    mDeviceOrientation = newOrientation;
-                    setOrientationForAudioSystem();
-                }
-            }
-            sendMsg(mAudioHandler,
-                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
-                    SENDMSG_REPLACE,
-                    0,
-                    0,
-                    null,
-                    0);
-
-            boolean cameraSoundForced = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_camera_sound_forced);
-            synchronized (mSettingsLock) {
-                boolean cameraSoundForcedChanged = false;
-                synchronized (mCameraSoundForced) {
-                    if (cameraSoundForced != mCameraSoundForced) {
-                        mCameraSoundForced = cameraSoundForced;
-                        cameraSoundForcedChanged = true;
-                    }
-                }
-                if (cameraSoundForcedChanged) {
-                    if (!isPlatformTelevision()) {
-                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
-                        if (cameraSoundForced) {
-                            s.setAllIndexesToMax();
-                            mRingerModeAffectedStreams &=
-                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
-                        } else {
-                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
-                            mRingerModeAffectedStreams |=
-                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
-                        }
-                        // take new state into account for streams muted by ringer mode
-                        setRingerModeInt(getRingerModeInternal(), false);
-                    }
-
-                    sendMsg(mAudioHandler,
-                            MSG_SET_FORCE_USE,
-                            SENDMSG_QUEUE,
-                            AudioSystem.FOR_SYSTEM,
-                            cameraSoundForced ?
-                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
-                            null,
-                            0);
-
-                    sendMsg(mAudioHandler,
-                            MSG_SET_ALL_VOLUMES,
-                            SENDMSG_QUEUE,
-                            0,
-                            0,
-                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
-                }
-            }
-            mVolumeController.setLayoutDirection(config.getLayoutDirection());
-        } catch (Exception e) {
-            Log.e(TAG, "Error handling configuration change: ", e);
-        }
-    }
-
-    private void setOrientationForAudioSystem() {
-        switch (mDeviceOrientation) {
-            case Configuration.ORIENTATION_LANDSCAPE:
-                //Log.i(TAG, "orientation is landscape");
-                AudioSystem.setParameters("orientation=landscape");
-                break;
-            case Configuration.ORIENTATION_PORTRAIT:
-                //Log.i(TAG, "orientation is portrait");
-                AudioSystem.setParameters("orientation=portrait");
-                break;
-            case Configuration.ORIENTATION_SQUARE:
-                //Log.i(TAG, "orientation is square");
-                AudioSystem.setParameters("orientation=square");
-                break;
-            case Configuration.ORIENTATION_UNDEFINED:
-                //Log.i(TAG, "orientation is undefined");
-                AudioSystem.setParameters("orientation=undefined");
-                break;
-            default:
-                Log.e(TAG, "Unknown orientation");
-        }
-    }
-
-    private void setRotationForAudioSystem() {
-        switch (mDeviceRotation) {
-            case Surface.ROTATION_0:
-                AudioSystem.setParameters("rotation=0");
-                break;
-            case Surface.ROTATION_90:
-                AudioSystem.setParameters("rotation=90");
-                break;
-            case Surface.ROTATION_180:
-                AudioSystem.setParameters("rotation=180");
-                break;
-            case Surface.ROTATION_270:
-                AudioSystem.setParameters("rotation=270");
-                break;
-            default:
-                Log.e(TAG, "Unknown device rotation");
-        }
-    }
-
-
-    // Handles request to override default use of A2DP for media.
-    public void setBluetoothA2dpOnInt(boolean on) {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            mBluetoothA2dpEnabled = on;
-            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
-            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
-                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
-        }
-    }
-
-    @Override
-    public void setRingtonePlayer(IRingtonePlayer player) {
-        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
-        mRingtonePlayer = player;
-    }
-
-    @Override
-    public IRingtonePlayer getRingtonePlayer() {
-        return mRingtonePlayer;
-    }
-
-    @Override
-    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
-        synchronized (mCurAudioRoutes) {
-            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
-            mRoutesObservers.register(observer);
-            return routes;
-        }
-    }
-
-
-    //==========================================================================================
-    // Safe media volume management.
-    // MUSIC stream volume level is limited when headphones are connected according to safety
-    // regulation. When the user attempts to raise the volume above the limit, a warning is
-    // displayed and the user has to acknowlegde before the volume is actually changed.
-    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
-    // property. Platforms with a different limit must set this property accordingly in their
-    // overlay.
-    //==========================================================================================
-
-    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
-    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
-    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
-    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
-    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
-    // (when user opts out).
-    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
-    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
-    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
-    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
-    private Integer mSafeMediaVolumeState;
-
-    private int mMcc = 0;
-    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
-    private int mSafeMediaVolumeIndex;
-    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
-    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
-                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
-    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
-    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
-    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
-    private int mMusicActiveMs;
-    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
-    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
-    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
-
-    private void setSafeMediaVolumeEnabled(boolean on) {
-        synchronized (mSafeMediaVolumeState) {
-            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
-                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
-                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
-                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
-                    enforceSafeMediaVolume();
-                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
-                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
-                    mMusicActiveMs = 1;  // nonzero = confirmed
-                    saveMusicActiveMs();
-                    sendMsg(mAudioHandler,
-                            MSG_CHECK_MUSIC_ACTIVE,
-                            SENDMSG_REPLACE,
-                            0,
-                            0,
-                            null,
-                            MUSIC_ACTIVE_POLL_PERIOD_MS);
-                }
-            }
-        }
-    }
-
-    private void enforceSafeMediaVolume() {
-        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-        int devices = mSafeMediaVolumeDevices;
-        int i = 0;
-
-        while (devices != 0) {
-            int device = 1 << i++;
-            if ((device & devices) == 0) {
-                continue;
-            }
-            int index = streamState.getIndex(device);
-            if (index > mSafeMediaVolumeIndex) {
-                streamState.setIndex(mSafeMediaVolumeIndex, device);
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        device,
-                        0,
-                        streamState,
-                        0);
-            }
-            devices &= ~device;
-        }
-    }
-
-    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
-        synchronized (mSafeMediaVolumeState) {
-            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
-                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                    ((device & mSafeMediaVolumeDevices) != 0) &&
-                    (index > mSafeMediaVolumeIndex)) {
-                return false;
-            }
-            return true;
-        }
-    }
-
-    @Override
-    public void disableSafeMediaVolume() {
-        enforceSelfOrSystemUI("disable the safe media volume");
-        synchronized (mSafeMediaVolumeState) {
-            setSafeMediaVolumeEnabled(false);
-            if (mPendingVolumeCommand != null) {
-                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
-                                  mPendingVolumeCommand.mIndex,
-                                  mPendingVolumeCommand.mFlags,
-                                  mPendingVolumeCommand.mDevice);
-                mPendingVolumeCommand = null;
-            }
-        }
-    }
-
-    //==========================================================================================
-    // Hdmi Cec system audio mode.
-    // If Hdmi Cec's system audio mode is on, audio service should notify volume change
-    // to HdmiControlService so that audio recevier can handle volume change.
-    //==========================================================================================
-
-    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
-        public void onComplete(int status) {
-            if (mHdmiManager != null) {
-                synchronized (mHdmiManager) {
-                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
-                    // Television devices without CEC service apply software volume on HDMI output
-                    if (isPlatformTelevision() && !mHdmiCecSink) {
-                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
-                    }
-                    checkAllFixedVolumeDevices();
-                }
-            }
-        }
-    };
-
-    // If HDMI-CEC system audio is supported
-    private boolean mHdmiSystemAudioSupported = false;
-    // Set only when device is tv.
-    private HdmiTvClient mHdmiTvClient;
-    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
-    // cached HdmiControlManager interface
-    private HdmiControlManager mHdmiManager;
-    // Set only when device is a set-top box.
-    private HdmiPlaybackClient mHdmiPlaybackClient;
-    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
-    private boolean mHdmiCecSink;
-
-    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
-
-    @Override
-    public int setHdmiSystemAudioSupported(boolean on) {
-        int device = AudioSystem.DEVICE_NONE;
-        if (mHdmiManager != null) {
-            synchronized (mHdmiManager) {
-                if (mHdmiTvClient == null) {
-                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
-                    return device;
-                }
-
-                synchronized (mHdmiTvClient) {
-                    if (mHdmiSystemAudioSupported != on) {
-                        mHdmiSystemAudioSupported = on;
-                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
-                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
-                                     AudioSystem.FORCE_NONE);
-                    }
-                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
-                }
-            }
-        }
-        return device;
-    }
-
-    @Override
-    public boolean isHdmiSystemAudioSupported() {
-        return mHdmiSystemAudioSupported;
-    }
-
-    //==========================================================================================
-    // Accessibility: taking touch exploration into account for selecting the default
-    //   stream override timeout when adjusting volume
-    //==========================================================================================
-    private static class StreamOverride
-            implements AccessibilityManager.TouchExplorationStateChangeListener {
-
-        // AudioService.getActiveStreamType() will return:
-        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
-        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
-        // stopped
-        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
-        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
-
-        static int sDelayMs;
-
-        static void init(Context ctxt) {
-            AccessibilityManager accessibilityManager =
-                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
-            updateDefaultStreamOverrideDelay(
-                    accessibilityManager.isTouchExplorationEnabled());
-            accessibilityManager.addTouchExplorationStateChangeListener(
-                    new StreamOverride());
-        }
-
-        @Override
-        public void onTouchExplorationStateChanged(boolean enabled) {
-            updateDefaultStreamOverrideDelay(enabled);
-        }
-
-        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
-            if (touchExploreEnabled) {
-                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
-            } else {
-                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
-            }
-            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
-                    + " stream override delay is now " + sDelayMs + " ms");
-        }
-    }
-
-    //==========================================================================================
-    // Camera shutter sound policy.
-    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
-    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
-    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
-    //==========================================================================================
-
-    // cached value of com.android.internal.R.bool.config_camera_sound_forced
-    private Boolean mCameraSoundForced;
-
-    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
-    public boolean isCameraSoundForced() {
-        synchronized (mCameraSoundForced) {
-            return mCameraSoundForced;
-        }
-    }
-
-    private static final String[] RINGER_MODE_NAMES = new String[] {
-            "SILENT",
-            "VIBRATE",
-            "NORMAL"
-    };
-
-    private void dumpRingerMode(PrintWriter pw) {
-        pw.println("\nRinger mode: ");
-        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
-        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
-        pw.print("- ringer mode affected streams = 0x");
-        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
-        pw.print("- ringer mode muted streams = 0x");
-        pw.println(Integer.toHexString(mRingerModeMutedStreams));
-        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        mMediaFocusControl.dump(pw);
-        dumpStreamStates(pw);
-        dumpRingerMode(pw);
-        pw.println("\nAudio routes:");
-        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
-        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
-
-        pw.println("\nOther state:");
-        pw.print("  mVolumeController="); pw.println(mVolumeController);
-        pw.print("  mSafeMediaVolumeState=");
-        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
-        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
-        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
-        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
-        pw.print("  mMcc="); pw.println(mMcc);
-        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
-
-        dumpAudioPolicies(pw);
-    }
-
-    private static String safeMediaVolumeStateToString(Integer state) {
-        switch(state) {
-            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
-            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
-            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
-            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
-        }
-        return null;
-    }
-
-    // Inform AudioFlinger of our device's low RAM attribute
-    private static void readAndSetLowRamDevice()
-    {
-        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
-        if (status != 0) {
-            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
-        }
-    }
-
-    private void enforceSelfOrSystemUI(String action) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
-                "Only SystemUI can " + action);
-    }
-
-    @Override
-    public void setVolumeController(final IVolumeController controller) {
-        enforceSelfOrSystemUI("set the volume controller");
-
-        // return early if things are not actually changing
-        if (mVolumeController.isSameBinder(controller)) {
-            return;
-        }
-
-        // dismiss the old volume controller
-        mVolumeController.postDismiss();
-        if (controller != null) {
-            // we are about to register a new controller, listen for its death
-            try {
-                controller.asBinder().linkToDeath(new DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        if (mVolumeController.isSameBinder(controller)) {
-                            Log.w(TAG, "Current remote volume controller died, unregistering");
-                            setVolumeController(null);
-                        }
-                    }
-                }, 0);
-            } catch (RemoteException e) {
-                // noop
-            }
-        }
-        mVolumeController.setController(controller);
-        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
-    }
-
-    @Override
-    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
-        enforceSelfOrSystemUI("notify about volume controller visibility");
-
-        // return early if the controller is not current
-        if (!mVolumeController.isSameBinder(controller)) {
-            return;
-        }
-
-        mVolumeController.setVisible(visible);
-        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
-    }
-
-    public static class VolumeController {
-        private static final String TAG = "VolumeController";
-
-        private IVolumeController mController;
-        private boolean mVisible;
-        private long mNextLongPress;
-        private int mLongPressTimeout;
-
-        public void setController(IVolumeController controller) {
-            mController = controller;
-            mVisible = false;
-        }
-
-        public void loadSettings(ContentResolver cr) {
-            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
-                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
-        }
-
-        public boolean suppressAdjustment(int resolvedStream, int flags) {
-            boolean suppress = false;
-            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
-                final long now = SystemClock.uptimeMillis();
-                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
-                    // ui will become visible
-                    if (mNextLongPress < now) {
-                        mNextLongPress = now + mLongPressTimeout;
-                    }
-                    suppress = true;
-                } else if (mNextLongPress > 0) {  // in a long-press
-                    if (now > mNextLongPress) {
-                        // long press triggered, no more suppression
-                        mNextLongPress = 0;
-                    } else {
-                        // keep suppressing until the long press triggers
-                        suppress = true;
-                    }
-                }
-            }
-            return suppress;
-        }
-
-        public void setVisible(boolean visible) {
-            mVisible = visible;
-        }
-
-        public boolean isSameBinder(IVolumeController controller) {
-            return Objects.equals(asBinder(), binder(controller));
-        }
-
-        public IBinder asBinder() {
-            return binder(mController);
-        }
-
-        private static IBinder binder(IVolumeController controller) {
-            return controller == null ? null : controller.asBinder();
-        }
-
-        @Override
-        public String toString() {
-            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
-        }
-
-        public void postDisplaySafeVolumeWarning(int flags) {
-            if (mController == null)
-                return;
-            try {
-                mController.displaySafeVolumeWarning(flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
-            }
-        }
-
-        public void postVolumeChanged(int streamType, int flags) {
-            if (mController == null)
-                return;
-            try {
-                mController.volumeChanged(streamType, flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling volumeChanged", e);
-            }
-        }
-
-        public void postMasterVolumeChanged(int flags) {
-            if (mController == null)
-                return;
-            try {
-                mController.masterVolumeChanged(flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling masterVolumeChanged", e);
-            }
-        }
-
-        public void postMasterMuteChanged(int flags) {
-            if (mController == null)
-                return;
-            try {
-                mController.masterMuteChanged(flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling masterMuteChanged", e);
-            }
-        }
-
-        public void setLayoutDirection(int layoutDirection) {
-            if (mController == null)
-                return;
-            try {
-                mController.setLayoutDirection(layoutDirection);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling setLayoutDirection", e);
-            }
-        }
-
-        public void postDismiss() {
-            if (mController == null)
-                return;
-            try {
-                mController.dismiss();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error calling dismiss", e);
-            }
-        }
-    }
-
-    /**
-     * Interface for system components to get some extra functionality through
-     * LocalServices.
-     */
-    final class AudioServiceInternal extends AudioManagerInternal {
-        @Override
-        public void setRingerModeDelegate(RingerModeDelegate delegate) {
-            mRingerModeDelegate = delegate;
-            if (mRingerModeDelegate != null) {
-                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
-            }
-        }
-
-        @Override
-        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
-                String callingPackage, int uid) {
-            // direction and stream type swap here because the public
-            // adjustSuggested has a different order than the other methods.
-            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
-        }
-
-        @Override
-        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
-                String callingPackage, int uid) {
-            adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
-        }
-
-        @Override
-        public void setStreamVolumeForUid(int streamType, int direction, int flags,
-                String callingPackage, int uid) {
-            setStreamVolume(streamType, direction, flags, callingPackage, uid);
-        }
-
-        @Override
-        public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
-                int uid) {
-            adjustMasterVolume(steps, flags, callingPackage, uid);
-        }
-
-        @Override
-        public int getRingerModeInternal() {
-            return AudioService.this.getRingerModeInternal();
-        }
-
-        @Override
-        public void setRingerModeInternal(int ringerMode, String caller) {
-            AudioService.this.setRingerModeInternal(ringerMode, caller);
-        }
-
-        @Override
-        public void setMasterMuteForUid(boolean state, int flags, String callingPackage, IBinder cb,
-                int uid) {
-            setMasterMuteInternal(state, flags, callingPackage, cb, uid);
-        }
-    }
-
-    //==========================================================================================
-    // Audio policy management
-    //==========================================================================================
-    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
-            boolean hasFocusListener) {
-        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
-                + " with config:" + policyConfig);
-        String regId = null;
-        // error handling
-        boolean hasPermissionForPolicy =
-                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
-                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
-        if (!hasPermissionForPolicy) {
-            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
-                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
-            return null;
-        }
-
-        synchronized (mAudioPolicies) {
-            try {
-                if (mAudioPolicies.containsKey(pcb.asBinder())) {
-                    Slog.e(TAG, "Cannot re-register policy");
-                    return null;
-                }
-                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
-                pcb.asBinder().linkToDeath(app, 0/*flags*/);
-                regId = app.getRegistrationId();
-                mAudioPolicies.put(pcb.asBinder(), app);
-            } catch (RemoteException e) {
-                // audio policy owner has already died!
-                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
-                        " binder death", e);
-                return null;
-            }
-        }
-        return regId;
-    }
-
-    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
-        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
-        synchronized (mAudioPolicies) {
-            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
-            if (app == null) {
-                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
-                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
-                return;
-            } else {
-                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
-            }
-            app.release();
-        }
-        // TODO implement clearing mix attribute matching info in native audio policy
-    }
-
-    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
-        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
-                + " policy " +  pcb.asBinder());
-        // error handling
-        boolean hasPermissionForPolicy =
-                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
-                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
-        if (!hasPermissionForPolicy) {
-            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
-                    + Binder.getCallingPid() + " / uid "
-                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
-            return AudioManager.ERROR;
-        }
-
-        synchronized (mAudioPolicies) {
-            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
-                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
-                return AudioManager.ERROR;
-            }
-            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
-            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
-                // is there already one policy managing ducking?
-                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
-                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
-                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
-                        return AudioManager.ERROR;
-                    }
-                }
-            }
-            app.mFocusDuckBehavior = duckingBehavior;
-            mMediaFocusControl.setDuckingInExtPolicyAvailable(
-                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
-        }
-        return AudioManager.SUCCESS;
-    }
-
-    private void dumpAudioPolicies(PrintWriter pw) {
-        pw.println("\nAudio policies:");
-        synchronized (mAudioPolicies) {
-            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
-                pw.println(policy.toLogFriendlyString());
-            }
-        }
-    }
-
-    //======================
-    // Audio policy proxy
-    //======================
-    /**
-     * This internal class inherits from AudioPolicyConfig, each instance contains all the
-     * mixes of an AudioPolicy and their configurations.
-     */
-    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
-        private static final String TAG = "AudioPolicyProxy";
-        AudioPolicyConfig mConfig;
-        IAudioPolicyCallback mPolicyToken;
-        boolean mHasFocusListener;
-        /**
-         * Audio focus ducking behavior for an audio policy.
-         * This variable reflects the value that was successfully set in
-         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
-         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
-         * is handling ducking for audio focus.
-         */
-        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
-
-        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
-                boolean hasFocusListener) {
-            super(config);
-            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
-            mPolicyToken = token;
-            mHasFocusListener = hasFocusListener;
-            if (mHasFocusListener) {
-                mMediaFocusControl.addFocusFollower(mPolicyToken);
-            }
-            connectMixes();
-        }
-
-        public void binderDied() {
-            synchronized (mAudioPolicies) {
-                Log.i(TAG, "audio policy " + mPolicyToken + " died");
-                release();
-                mAudioPolicies.remove(mPolicyToken.asBinder());
-            }
-        }
-
-        String getRegistrationId() {
-            return getRegistration();
-        }
-
-        void release() {
-            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
-                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
-            }
-            if (mHasFocusListener) {
-                mMediaFocusControl.removeFocusFollower(mPolicyToken);
-            }
-            AudioSystem.registerPolicyMixes(mMixes, false);
-        }
-
-        void connectMixes() {
-            AudioSystem.registerPolicyMixes(mMixes, true);
-        }
-    };
-
-    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
-            new HashMap<IBinder, AudioPolicyProxy>();
-    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
-}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 46ab7e0..787320e 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.audiopolicy.AudioMix;
+
 import java.util.ArrayList;
 
 /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
@@ -65,6 +68,19 @@
     private static final int NUM_STREAM_TYPES = 10;
     public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
 
+    public static final String[] STREAM_NAMES = new String[] {
+        "STREAM_VOICE_CALL",
+        "STREAM_SYSTEM",
+        "STREAM_RING",
+        "STREAM_MUSIC",
+        "STREAM_ALARM",
+        "STREAM_NOTIFICATION",
+        "STREAM_BLUETOOTH_SCO",
+        "STREAM_SYSTEM_ENFORCED",
+        "STREAM_DTMF",
+        "STREAM_TTS"
+    };
+
     /*
      * Sets the microphone mute on or off.
      *
@@ -534,7 +550,8 @@
     public static final int SYNC_EVENT_NONE = 0;
     public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1;
 
-    public static native int setDeviceConnectionState(int device, int state, String device_address);
+    public static native int setDeviceConnectionState(int device, int state,
+                                                      String device_address, String device_name);
     public static native int getDeviceConnectionState(int device, String device_address);
     public static native int setPhoneState(int state);
     public static native int setForceUse(int usage, int config);
@@ -569,5 +586,93 @@
     public static native int getAudioHwSyncForSession(int sessionId);
 
     public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
+
+
+    // Items shared with audio service
+
+    /**
+     * The delay before playing a sound. This small period exists so the user
+     * can press another key (non-volume keys, too) to have it NOT be audible.
+     * <p>
+     * PhoneWindow will implement this part.
+     */
+    public static final int PLAY_SOUND_DELAY = 300;
+
+    /**
+     * Constant to identify a focus stack entry that is used to hold the focus while the phone
+     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+     * entering and exiting calls.
+     */
+    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+
+    /**
+     * @see AudioManager#setVibrateSetting(int, int)
+     */
+    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
+            int vibrateSetting) {
+
+        // First clear the existing setting. Each vibrate type has two bits in
+        // the value. Note '3' is '11' in binary.
+        existingValue &= ~(3 << (vibrateType * 2));
+
+        // Set into the old value
+        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
+
+        return existingValue;
+    }
+
+    public static int getDefaultStreamVolume(int streamType) {
+        return DEFAULT_STREAM_VOLUME[streamType];
+    }
+
+    public static int[] DEFAULT_STREAM_VOLUME = new int[] {
+        4,  // STREAM_VOICE_CALL
+        7,  // STREAM_SYSTEM
+        5,  // STREAM_RING
+        11, // STREAM_MUSIC
+        6,  // STREAM_ALARM
+        5,  // STREAM_NOTIFICATION
+        7,  // STREAM_BLUETOOTH_SCO
+        7,  // STREAM_SYSTEM_ENFORCED
+        11, // STREAM_DTMF
+        11  // STREAM_TTS
+    };
+
+    public static String streamToString(int stream) {
+        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
+        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
+        return "UNKNOWN_STREAM_" + stream;
+    }
+
+    /** The platform has no specific capabilities */
+    public static final int PLATFORM_DEFAULT = 0;
+    /** The platform is voice call capable (a phone) */
+    public static final int PLATFORM_VOICE = 1;
+    /** The platform is a television or a set-top box */
+    public static final int PLATFORM_TELEVISION = 2;
+
+    /**
+     * Return the platform type that this is running on. One of:
+     * <ul>
+     * <li>{@link #PLATFORM_VOICE}</li>
+     * <li>{@link #PLATFORM_TELEVISION}</li>
+     * <li>{@link #PLATFORM_DEFAULT}</li>
+     * </ul>
+     */
+    public static int getPlatformType(Context context) {
+        if (context.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+            return PLATFORM_VOICE;
+        } else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            return PLATFORM_TELEVISION;
+        } else {
+            return PLATFORM_DEFAULT;
+        }
+    }
+
+    public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
+            (1 << STREAM_MUSIC) |
+            (1 << STREAM_RING) |
+            (1 << STREAM_NOTIFICATION) |
+            (1 << STREAM_SYSTEM);
 }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 547d87e..93e2cbe 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -21,9 +21,6 @@
 import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.NioUtils;
-import java.util.Iterator;
-import java.util.Set;
-
 import android.annotation.IntDef;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
@@ -512,7 +509,7 @@
                 throw new IllegalArgumentException("Unsupported channel configuration.");
             }
             mChannels = channelConfig;
-            mChannelCount = Integer.bitCount(channelConfig);
+            mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
         }
 
         //--------------
@@ -546,7 +543,7 @@
             loge("Channel configuration features unsupported channels");
             return false;
         }
-        final int channelCount = Integer.bitCount(channelConfig);
+        final int channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
         if (channelCount > CHANNEL_COUNT_MAX) {
             loge("Channel configuration contains too many channels " +
                     channelCount + ">" + CHANNEL_COUNT_MAX);
@@ -763,7 +760,10 @@
      * unsigned 32-bits.  That is, the next position after 0x7FFFFFFF is (int) 0x80000000.
      * This is a continuously advancing counter.  It will wrap (overflow) periodically,
      * for example approximately once every 27:03:11 hours:minutes:seconds at 44.1 kHz.
-     * It is reset to zero by flush(), reload(), and stop().
+     * It is reset to zero by {@link #flush()}, {@link #reloadStaticData()}, and {@link #stop()}.
+     * If the track's creation mode is {@link #MODE_STATIC}, the return value indicates
+     * the total number of frames played since reset,
+     * <i>not</i> the current offset within the buffer.
      */
     public int getPlaybackHeadPosition() {
         return native_get_position();
@@ -825,7 +825,7 @@
                 loge("getMinBufferSize(): Invalid channel configuration.");
                 return ERROR_BAD_VALUE;
             } else {
-                channelCount = Integer.bitCount(channelConfig);
+                channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
             }
         }
 
@@ -1048,7 +1048,8 @@
 
     /**
      * Sets the period for the periodic notification event.
-     * @param periodInFrames update period expressed in frames
+     * @param periodInFrames update period expressed in frames.
+     * Zero period means no position updates.  A negative period is not allowed.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
      */
     public int setPositionNotificationPeriod(int periodInFrames) {
@@ -1060,12 +1061,19 @@
 
 
     /**
-     * Sets the playback head position.
+     * Sets the playback head position within the static buffer.
      * The track must be stopped or paused for the position to be changed,
      * and must use the {@link #MODE_STATIC} mode.
-     * @param positionInFrames playback head position expressed in frames
+     * @param positionInFrames playback head position within buffer, expressed in frames.
      * Zero corresponds to start of buffer.
      * The position must not be greater than the buffer size in frames, or negative.
+     * Though this method and {@link #getPlaybackHeadPosition()} have similar names,
+     * the position values have different meanings.
+     * <br>
+     * If looping is currently enabled and the new position is greater than or equal to the
+     * loop end marker, the behavior varies by API level: for API level 22 and above,
+     * the looping is first disabled and then the position is set.
+     * For earlier API levels, the behavior is unspecified.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
@@ -1085,17 +1093,29 @@
      * Similarly to setPlaybackHeadPosition,
      * the track must be stopped or paused for the loop points to be changed,
      * and must use the {@link #MODE_STATIC} mode.
-     * @param startInFrames loop start marker expressed in frames
+     * @param startInFrames loop start marker expressed in frames.
      * Zero corresponds to start of buffer.
      * The start marker must not be greater than or equal to the buffer size in frames, or negative.
-     * @param endInFrames loop end marker expressed in frames
+     * @param endInFrames loop end marker expressed in frames.
      * The total buffer size in frames corresponds to end of buffer.
      * The end marker must not be greater than the buffer size in frames.
      * For looping, the end marker must not be less than or equal to the start marker,
      * but to disable looping
      * it is permitted for start marker, end marker, and loop count to all be 0.
-     * @param loopCount the number of times the loop is looped.
+     * If any input parameters are out of range, this method returns {@link #ERROR_BAD_VALUE}.
+     * If the loop period (endInFrames - startInFrames) is too small for the implementation to
+     * support,
+     * {@link #ERROR_BAD_VALUE} is returned.
+     * The loop range is the interval [startInFrames, endInFrames).
+     * <br>
+     * For API level 22 and above, the position is left unchanged,
+     * unless it is greater than or equal to the loop end marker, in which case
+     * it is forced to the loop start marker.
+     * For earlier API levels, the effect on position is unspecified.
+     * @param loopCount the number of times the loop is looped; must be greater than or equal to -1.
      *    A value of -1 means infinite looping, and 0 disables looping.
+     *    A value of positive N means to "loop" (go back) N times.  For example,
+     *    a value of one means to play the region two times in total.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
      */
@@ -1131,7 +1151,12 @@
     //--------------------
     /**
      * Starts playing an AudioTrack.
-     * If track's creation mode is {@link #MODE_STATIC}, you must have called write() prior.
+     * If track's creation mode is {@link #MODE_STATIC}, you must have called one of
+     * the {@link #write(byte[], int, int)}, {@link #write(short[], int, int)},
+     * or {@link #write(float[], int, int, int)} methods.
+     * If the mode is {@link #MODE_STREAM}, you can optionally prime the
+     * output buffer by writing up to bufferSizeInBytes (from constructor) before starting.
+     * This priming will avoid an immediate underrun, but is not required.
      *
      * @throws IllegalStateException
      */
@@ -1150,6 +1175,9 @@
     }
 
     private boolean isRestricted() {
+        if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+            return false;
+        }
         try {
             final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType);
             final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage,
@@ -1209,8 +1237,14 @@
 
     /**
      * Flushes the audio data currently queued for playback. Any data that has
-     * not been played back will be discarded.  No-op if not stopped or paused,
+     * been written but not yet presented will be discarded.  No-op if not stopped or paused,
      * or if the track's creation mode is not {@link #MODE_STREAM}.
+     * <BR> Note that although data written but not yet presented is discarded, there is no
+     * guarantee that all of the buffer space formerly used by that data
+     * is available for a subsequent write.
+     * For example, a call to {@link #write(byte[], int, int)} with <code>sizeInBytes</code>
+     * less than or equal to the total buffer size
+     * may return a short actual transfer count.
      */
     public void flush() {
         if (mState == STATE_INITIALIZED) {
@@ -1449,9 +1483,17 @@
     }
 
     /**
-     * Notifies the native resource to reuse the audio data already loaded in the native
-     * layer, that is to rewind to start of buffer.
-     * The track's creation mode must be {@link #MODE_STATIC}.
+     * Sets the playback head position within the static buffer to zero,
+     * that is it rewinds to start of static buffer.
+     * The track must be stopped or paused, and
+     * the track's creation mode must be {@link #MODE_STATIC}.
+     * <p>
+     * For API level 22 and above, also resets the value returned by
+     * {@link #getPlaybackHeadPosition()} to zero.
+     * For earlier API levels, the reset behavior is unspecified.
+     * <p>
+     * {@link #setPlaybackHeadPosition(int)} to zero
+     * is recommended instead when the reset of {@link #getPlaybackHeadPosition} is not needed.
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *  {@link #ERROR_INVALID_OPERATION}
      */
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index d34b21b..e3680e9 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -154,6 +154,7 @@
 
     private int mMode = MODE_PAINT_ON;
     private int mRollUpSize = 4;
+    private int mPrevCtrlCode = INVALID;
 
     private CCMemory mDisplay = new CCMemory();
     private CCMemory mNonDisplay = new CCMemory();
@@ -260,6 +261,13 @@
 
     private boolean handleCtrlCode(CCData ccData) {
         int ctrlCode = ccData.getCtrlCode();
+
+        if (mPrevCtrlCode != INVALID && mPrevCtrlCode == ctrlCode) {
+            // discard double ctrl codes (but if there's a 3rd one, we still take that)
+            mPrevCtrlCode = INVALID;
+            return true;
+        }
+
         switch(ctrlCode) {
         case RCL:
             // select pop-on style
@@ -325,10 +333,12 @@
             break;
         case INVALID:
         default:
-            // not handled
+            mPrevCtrlCode = INVALID;
             return false;
         }
 
+        mPrevCtrlCode = ctrlCode;
+
         // handled
         return true;
     }
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
deleted file mode 100644
index bbe5fd2..0000000
--- a/media/java/android/media/FocusRequester.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.annotation.NonNull;
-import android.media.MediaFocusControl.AudioFocusDeathHandler;
-import android.os.IBinder;
-import android.util.Log;
-
-import java.io.PrintWriter;
-
-/**
- * @hide
- * Class to handle all the information about a user of audio focus. The lifecycle of each
- * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
- * stack to its release.
- */
-class FocusRequester {
-
-    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
-    private static final String TAG = "MediaFocusControl";
-    private static final boolean DEBUG = false;
-
-    private AudioFocusDeathHandler mDeathHandler;
-    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
-    private final IBinder mSourceRef;
-    private final String mClientId;
-    private final String mPackageName;
-    private final int mCallingUid;
-    private final MediaFocusControl mFocusController; // never null
-    /**
-     * the audio focus gain request that caused the addition of this object in the focus stack.
-     */
-    private final int mFocusGainRequest;
-    /**
-     * the flags associated with the gain request that qualify the type of grant (e.g. accepting
-     * delay vs grant must be immediate)
-     */
-    private final int mGrantFlags;
-    /**
-     * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
-     *  it never lost focus.
-     */
-    private int mFocusLossReceived;
-    /**
-     * the audio attributes associated with the focus request
-     */
-    private final AudioAttributes mAttributes;
-
-    /**
-     * Class constructor
-     * @param aa
-     * @param focusRequest
-     * @param grantFlags
-     * @param afl
-     * @param source
-     * @param id
-     * @param hdlr
-     * @param pn
-     * @param uid
-     * @param ctlr cannot be null
-     */
-    FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
-            IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
-            String pn, int uid, @NonNull MediaFocusControl ctlr) {
-        mAttributes = aa;
-        mFocusDispatcher = afl;
-        mSourceRef = source;
-        mClientId = id;
-        mDeathHandler = hdlr;
-        mPackageName = pn;
-        mCallingUid = uid;
-        mFocusGainRequest = focusRequest;
-        mGrantFlags = grantFlags;
-        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
-        mFocusController = ctlr;
-    }
-
-
-    boolean hasSameClient(String otherClient) {
-        try {
-            return mClientId.compareTo(otherClient) == 0;
-        } catch (NullPointerException e) {
-            return false;
-        }
-    }
-
-    boolean isLockedFocusOwner() {
-        return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
-    }
-
-    boolean hasSameBinder(IBinder ib) {
-        return (mSourceRef != null) && mSourceRef.equals(ib);
-    }
-
-    boolean hasSamePackage(String pack) {
-        try {
-            return mPackageName.compareTo(pack) == 0;
-        } catch (NullPointerException e) {
-            return false;
-        }
-    }
-
-    boolean hasSameUid(int uid) {
-        return mCallingUid == uid;
-    }
-
-    String getClientId() {
-        return mClientId;
-    }
-
-    int getGainRequest() {
-        return mFocusGainRequest;
-    }
-
-    int getGrantFlags() {
-        return mGrantFlags;
-    }
-
-    AudioAttributes getAudioAttributes() {
-        return mAttributes;
-    }
-
-
-    private static String focusChangeToString(int focus) {
-        switch(focus) {
-            case AudioManager.AUDIOFOCUS_NONE:
-                return "none";
-            case AudioManager.AUDIOFOCUS_GAIN:
-                return "GAIN";
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
-                return "GAIN_TRANSIENT";
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
-                return "GAIN_TRANSIENT_MAY_DUCK";
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
-                return "GAIN_TRANSIENT_EXCLUSIVE";
-            case AudioManager.AUDIOFOCUS_LOSS:
-                return "LOSS";
-            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                return "LOSS_TRANSIENT";
-            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
-                return "LOSS_TRANSIENT_CAN_DUCK";
-            default:
-                return "[invalid focus change" + focus + "]";
-        }
-    }
-
-    private String focusGainToString() {
-        return focusChangeToString(mFocusGainRequest);
-    }
-
-    private String focusLossToString() {
-        return focusChangeToString(mFocusLossReceived);
-    }
-
-    private static String flagsToString(int flags) {
-        String msg = new String();
-        if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) {
-            msg += "DELAY_OK";
-        }
-        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0)     {
-            if (!msg.isEmpty()) { msg += "|"; }
-            msg += "LOCK";
-        }
-        if ((flags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) {
-            if (!msg.isEmpty()) { msg += "|"; }
-            msg += "PAUSES_ON_DUCKABLE_LOSS";
-        }
-        return msg;
-    }
-
-    void dump(PrintWriter pw) {
-        pw.println("  source:" + mSourceRef
-                + " -- pack: " + mPackageName
-                + " -- client: " + mClientId
-                + " -- gain: " + focusGainToString()
-                + " -- flags: " + flagsToString(mGrantFlags)
-                + " -- loss: " + focusLossToString()
-                + " -- uid: " + mCallingUid
-                + " -- attr: " + mAttributes);
-    }
-
-
-    void release() {
-        try {
-            if (mSourceRef != null && mDeathHandler != null) {
-                mSourceRef.unlinkToDeath(mDeathHandler, 0);
-                mDeathHandler = null;
-            }
-        } catch (java.util.NoSuchElementException e) {
-            Log.e(TAG, "FocusRequester.release() hit ", e);
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        release();
-        super.finalize();
-    }
-
-    /**
-     * For a given audio focus gain request, return the audio focus loss type that will result
-     * from it, taking into account any previous focus loss.
-     * @param gainRequest
-     * @return the audio focus loss type that matches the gain request
-     */
-    private int focusLossForGainRequest(int gainRequest) {
-        switch(gainRequest) {
-            case AudioManager.AUDIOFOCUS_GAIN:
-                switch(mFocusLossReceived) {
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                    case AudioManager.AUDIOFOCUS_LOSS:
-                    case AudioManager.AUDIOFOCUS_NONE:
-                        return AudioManager.AUDIOFOCUS_LOSS;
-                }
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
-                switch(mFocusLossReceived) {
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                    case AudioManager.AUDIOFOCUS_NONE:
-                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                    case AudioManager.AUDIOFOCUS_LOSS:
-                        return AudioManager.AUDIOFOCUS_LOSS;
-                }
-            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
-                switch(mFocusLossReceived) {
-                    case AudioManager.AUDIOFOCUS_NONE:
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
-                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
-                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
-                    case AudioManager.AUDIOFOCUS_LOSS:
-                        return AudioManager.AUDIOFOCUS_LOSS;
-                }
-            default:
-                Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
-                        return AudioManager.AUDIOFOCUS_NONE;
-        }
-    }
-
-    /**
-     * Called synchronized on MediaFocusControl.mAudioFocusLock
-     */
-    void handleExternalFocusGain(int focusGain) {
-        int focusLoss = focusLossForGainRequest(focusGain);
-        handleFocusLoss(focusLoss);
-    }
-
-    /**
-     * Called synchronized on MediaFocusControl.mAudioFocusLock
-     */
-    void handleFocusGain(int focusGain) {
-        try {
-            mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
-            mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
-                    AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
-            if (mFocusDispatcher != null) {
-                if (DEBUG) {
-                    Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
-                        + mClientId);
-                }
-                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
-            }
-        } catch (android.os.RemoteException e) {
-            Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
-        }
-    }
-
-    /**
-     * Called synchronized on MediaFocusControl.mAudioFocusLock
-     */
-    void handleFocusLoss(int focusLoss) {
-        try {
-            if (focusLoss != mFocusLossReceived) {
-                mFocusLossReceived = focusLoss;
-                // before dispatching a focus loss, check if the following conditions are met:
-                // 1/ the framework is not supposed to notify the focus loser on a DUCK loss
-                // 2/ it is a DUCK loss
-                // 3/ the focus loser isn't flagged as pausing in a DUCK loss
-                // if they are, do not notify the focus loser
-                if (!mFocusController.mustNotifyFocusOwnerOnDuck()
-                        && mFocusLossReceived == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
-                        && (mGrantFlags
-                                & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) == 0) {
-                    if (DEBUG) {
-                        Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
-                                + " to " + mClientId + ", to be handled externally");
-                    }
-                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
-                            toAudioFocusInfo(), false /* wasDispatched */);
-                    return;
-                }
-                if (mFocusDispatcher != null) {
-                    if (DEBUG) {
-                        Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
-                            + mClientId);
-                    }
-                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
-                            toAudioFocusInfo(), true /* wasDispatched */);
-                    mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
-                }
-            }
-        } catch (android.os.RemoteException e) {
-            Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
-        }
-    }
-
-    AudioFocusInfo toAudioFocusInfo() {
-        return new AudioFocusInfo(mAttributes, mClientId, mPackageName,
-                mFocusGainRequest, mFocusLossReceived, mGrantFlags);
-    }
-}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fad3cec..8e962187 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -29,6 +29,7 @@
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.Rating;
+import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.net.Uri;
@@ -40,42 +41,30 @@
 interface IAudioService {
 
     void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
-            String callingPackage);
+            String callingPackage, String caller);
 
     void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
 
-    void adjustMasterVolume(int direction, int flags, String callingPackage);
-
     void setStreamVolume(int streamType, int index, int flags, String callingPackage);
 
     oneway void setRemoteStreamVolume(int index);
 
-    void setMasterVolume(int index, int flags, String callingPackage);
-
-    void setStreamSolo(int streamType, boolean state, IBinder cb);
-
-    void setStreamMute(int streamType, boolean state, IBinder cb);
-
     boolean isStreamMute(int streamType);
 
     void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
 
-    void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb);
-
     boolean isMasterMute();
 
+    void setMasterMute(boolean mute, int flags, String callingPackage);
+
     int getStreamVolume(int streamType);
 
-    int getMasterVolume();
+    int getStreamMinVolume(int streamType);
 
     int getStreamMaxVolume(int streamType);
 
-    int getMasterMaxVolume();
-
     int getLastAudibleStreamVolume(int streamType);
 
-    int getLastAudibleMasterVolume();
-
     void setMicrophoneMute(boolean on, String callingPackage);
 
     void setRingerModeExternal(int ringerMode, String caller);
@@ -94,7 +83,7 @@
 
     boolean shouldVibrate(int vibrateType);
 
-    void setMode(int mode, IBinder cb);
+    void setMode(int mode, IBinder cb, String callingPackage);
 
     int getMode();
 
@@ -193,9 +182,11 @@
 
     void setRingtonePlayer(IRingtonePlayer player);
     IRingtonePlayer getRingtonePlayer();
-    int getMasterStreamType();
+    int getUiSoundsStreamType();
 
-    void setWiredDeviceConnectionState(int device, int state, String name);
+    void setWiredDeviceConnectionState(int type, int state, String address, String name,
+            String caller);
+
     int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
 
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
@@ -208,15 +199,20 @@
 
     boolean isStreamAffectedByRingerMode(int streamType);
 
-    void disableSafeMediaVolume();
+    boolean isStreamAffectedByMute(int streamType);
+
+    void disableSafeMediaVolume(String callingPackage);
 
     int setHdmiSystemAudioSupported(boolean on);
 
     boolean isHdmiSystemAudioSupported();
 
-           String registerAudioPolicy(in AudioPolicyConfig policyConfig,
-                    in IAudioPolicyCallback pcb, boolean hasFocusListener);
+    String registerAudioPolicy(in AudioPolicyConfig policyConfig,
+            in IAudioPolicyCallback pcb, boolean hasFocusListener);
+
     oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
 
-           int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
+    int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
+
+    void setVolumePolicy(in VolumePolicy policy);
 }
diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl
index e3593a6..90ac416 100644
--- a/media/java/android/media/IVolumeController.aidl
+++ b/media/java/android/media/IVolumeController.aidl
@@ -27,8 +27,6 @@
 
     void volumeChanged(int streamType, int flags);
 
-    void masterVolumeChanged(int flags);
-
     void masterMuteChanged(int flags);
 
     void setLayoutDirection(int layoutDirection);
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8d6a588..824a7ad 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -483,6 +483,8 @@
             case ImageFormat.Y16:
             case ImageFormat.RAW_SENSOR:
             case ImageFormat.RAW10:
+            case ImageFormat.DEPTH16:
+            case ImageFormat.DEPTH_POINT_CLOUD:
                 return 1;
             default:
                 throw new UnsupportedOperationException(
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 8985b52..a7f33fa 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -19,7 +19,6 @@
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.media.Image;
-import android.media.Image.Plane;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 6984575..3c9ca4e 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -24,15 +24,12 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
 import static android.media.Utils.intersectSortedDistinctRanges;
 import static android.media.Utils.sortDistinctRanges;
-import static com.android.internal.util.Preconditions.checkArgumentPositive;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 /**
  * Provides information about a given media codec available on the device. You can
@@ -208,6 +205,7 @@
         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
         // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
         public static final int COLOR_FormatSurface                   = 0x7F000789;
+        public static final int COLOR_Format32BitRGBA8888             = 0x7F00A000;
         // This corresponds to YUV_420_888 format
         public static final int COLOR_FormatYUV420Flexible            = 0x7F420888;
         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
@@ -880,8 +878,8 @@
                         (int)(mAspectRatioRange.getUpper().doubleValue() * height));
                 return range;
             } catch (IllegalArgumentException e) {
-                // should not be here
-                Log.w(TAG, "could not get supported widths for " + height , e);
+                // height is not supported because there are no suitable widths
+                Log.v(TAG, "could not get supported widths for " + height);
                 throw new IllegalArgumentException("unsupported height");
             }
         }
@@ -924,8 +922,8 @@
                         (int)(width / mAspectRatioRange.getLower().doubleValue()));
                 return range;
             } catch (IllegalArgumentException e) {
-                // should not be here
-                Log.w(TAG, "could not get supported heights for " + width , e);
+                // width is not supported because there are no suitable heights
+                Log.v(TAG, "could not get supported heights for " + width);
                 throw new IllegalArgumentException("unsupported width");
             }
         }
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index bb848d9..7fd0186 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -19,8 +19,6 @@
 import android.util.Log;
 
 import android.media.MediaCodecInfo;
-import android.media.MediaCodecInfo.CodecCapabilities;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
index 4399c0d..ddbffc2 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/java/android/media/MediaDescription.java
@@ -1,22 +1,11 @@
 package android.media;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Size;
 
 /**
  * A simple set of metadata for a media item suitable for display. This can be
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 78a5abe..d7752b9 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -21,8 +21,6 @@
 import java.util.HashMap;
 import java.util.List;
 import android.annotation.SystemApi;
-import android.os.Binder;
-import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -277,6 +275,12 @@
      */
     public static final int EVENT_VENDOR_DEFINED = 4;
 
+    /**
+     * This event indicates that a session opened by the app has been reclaimed by the resource
+     * manager.
+     */
+    public static final int EVENT_SESSION_RECLAIMED = 5;
+
     private static final int DRM_EVENT = 200;
 
     private class EventHandler extends Handler
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
deleted file mode 100644
index 6518bd1..0000000
--- a/media/java/android/media/MediaFocusControl.java
+++ /dev/null
@@ -1,2197 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.app.PendingIntent.OnFinished;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.media.PlayerRecord.RemotePlaybackState;
-import android.media.audiopolicy.IAudioPolicyCallback;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.IBinder.DeathRecipient;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Stack;
-
-/**
- * @hide
- *
- */
-public class MediaFocusControl implements OnFinished {
-
-    private static final String TAG = "MediaFocusControl";
-
-    /** Debug remote control client/display feature */
-    protected static final boolean DEBUG_RC = false;
-    /** Debug volumes */
-    protected static final boolean DEBUG_VOL = false;
-
-    /** Used to alter media button redirection when the phone is ringing. */
-    private boolean mIsRinging = false;
-
-    private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final MediaEventHandler mEventHandler;
-    private final Context mContext;
-    private final ContentResolver mContentResolver;
-    private final AudioService.VolumeController mVolumeController;
-    private final AppOpsManager mAppOps;
-    private final KeyguardManager mKeyguardManager;
-    private final AudioService mAudioService;
-    private final NotificationListenerObserver mNotifListenerObserver;
-
-    protected MediaFocusControl(Looper looper, Context cntxt,
-            AudioService.VolumeController volumeCtrl, AudioService as) {
-        mEventHandler = new MediaEventHandler(looper);
-        mContext = cntxt;
-        mContentResolver = mContext.getContentResolver();
-        mVolumeController = volumeCtrl;
-        mAudioService = as;
-
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        mMainRemote = new RemotePlaybackState(-1,
-                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC),
-                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC));
-
-        // Register for phone state monitoring
-        TelephonyManager tmgr = (TelephonyManager)
-                mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
-        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
-        mKeyguardManager =
-                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mNotifListenerObserver = new NotificationListenerObserver();
-
-        mHasRemotePlayback = false;
-        mMainRemoteIsActive = false;
-
-        PlayerRecord.setMediaFocusControl(this);
-
-        postReevaluateRemote();
-    }
-
-    protected void dump(PrintWriter pw) {
-        dumpFocusStack(pw);
-        dumpRCStack(pw);
-        dumpRCCStack(pw);
-        dumpRCDList(pw);
-    }
-
-    //==========================================================================================
-    // Management of RemoteControlDisplay registration permissions
-    //==========================================================================================
-    private final static Uri ENABLED_NOTIFICATION_LISTENERS_URI =
-            Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
-    private class NotificationListenerObserver extends ContentObserver {
-
-        NotificationListenerObserver() {
-            super(mEventHandler);
-            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS), false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            if (!ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri) || selfChange) {
-                return;
-            }
-            if (DEBUG_RC) { Log.d(TAG, "NotificationListenerObserver.onChange()"); }
-            postReevaluateRemoteControlDisplays();
-        }
-    }
-
-    private final static int RCD_REG_FAILURE = 0;
-    private final static int RCD_REG_SUCCESS_PERMISSION = 1;
-    private final static int RCD_REG_SUCCESS_ENABLED_NOTIF = 2;
-
-    /**
-     * Checks a caller's authorization to register an IRemoteControlDisplay.
-     * Authorization is granted if one of the following is true:
-     * <ul>
-     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL permission</li>
-     * <li>the caller's listener is one of the enabled notification listeners</li>
-     * </ul>
-     * @return RCD_REG_FAILURE if it's not safe to proceed with the IRemoteControlDisplay
-     *     registration.
-     */
-    private int checkRcdRegistrationAuthorization(ComponentName listenerComp) {
-        // MEDIA_CONTENT_CONTROL permission check
-        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
-            if (DEBUG_RC) { Log.d(TAG, "ok to register Rcd: has MEDIA_CONTENT_CONTROL permission");}
-            return RCD_REG_SUCCESS_PERMISSION;
-        }
-
-        // ENABLED_NOTIFICATION_LISTENERS settings check
-        if (listenerComp != null) {
-            // this call is coming from an app, can't use its identity to read secure settings
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                final int currentUser = ActivityManager.getCurrentUser();
-                final String enabledNotifListeners = Settings.Secure.getStringForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                        currentUser);
-                if (enabledNotifListeners != null) {
-                    final String[] components = enabledNotifListeners.split(":");
-                    for (int i=0; i<components.length; i++) {
-                        final ComponentName component =
-                                ComponentName.unflattenFromString(components[i]);
-                        if (component != null) {
-                            if (listenerComp.equals(component)) {
-                                if (DEBUG_RC) { Log.d(TAG, "ok to register RCC: " + component +
-                                        " is authorized notification listener"); }
-                                return RCD_REG_SUCCESS_ENABLED_NOTIF;
-                            }
-                        }
-                    }
-                }
-                if (DEBUG_RC) { Log.d(TAG, "not ok to register RCD, " + listenerComp +
-                        " is not in list of ENABLED_NOTIFICATION_LISTENERS"); }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        return RCD_REG_FAILURE;
-    }
-
-    protected boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        int reg = checkRcdRegistrationAuthorization(listenerComp);
-        if (reg != RCD_REG_FAILURE) {
-            registerRemoteControlDisplay_int(rcd, w, h, listenerComp);
-            return true;
-        } else {
-            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
-                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
-                    " or be an enabled NotificationListenerService for registerRemoteController");
-            return false;
-        }
-    }
-
-    protected boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        int reg = checkRcdRegistrationAuthorization(null);
-        if (reg != RCD_REG_FAILURE) {
-            registerRemoteControlDisplay_int(rcd, w, h, null);
-            return true;
-        } else {
-            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
-                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
-                    " to register IRemoteControlDisplay");
-            return false;
-        }
-    }
-
-    private void postReevaluateRemoteControlDisplays() {
-        sendMsg(mEventHandler, MSG_REEVALUATE_RCD, SENDMSG_QUEUE, 0, 0, null, 0);
-    }
-
-    private void onReevaluateRemoteControlDisplays() {
-        if (DEBUG_RC) { Log.d(TAG, "onReevaluateRemoteControlDisplays()"); }
-        // read which components are enabled notification listeners
-        final int currentUser = ActivityManager.getCurrentUser();
-        final String enabledNotifListeners = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                currentUser);
-        if (DEBUG_RC) { Log.d(TAG, " > enabled list: " + enabledNotifListeners); }
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                // check whether the "enable" status of each RCD with a notification listener
-                // has changed
-                final String[] enabledComponents;
-                if (enabledNotifListeners == null) {
-                    enabledComponents = null;
-                } else {
-                    enabledComponents = enabledNotifListeners.split(":");
-                }
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di =
-                            displayIterator.next();
-                    if (di.mClientNotifListComp != null) {
-                        boolean wasEnabled = di.mEnabled;
-                        di.mEnabled = isComponentInStringArray(di.mClientNotifListComp,
-                                enabledComponents);
-                        if (wasEnabled != di.mEnabled){
-                            try {
-                                // tell the RCD whether it's enabled
-                                di.mRcDisplay.setEnabled(di.mEnabled);
-                                // tell the RCCs about the change for this RCD
-                                enableRemoteControlDisplayForClient_syncRcStack(
-                                        di.mRcDisplay, di.mEnabled);
-                                // when enabling, refresh the information on the display
-                                if (di.mEnabled) {
-                                    sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
-                                            di.mArtworkExpectedWidth /*arg1*/,
-                                            di.mArtworkExpectedHeight/*arg2*/,
-                                            di.mRcDisplay /*obj*/, 0/*delay*/);
-                                }
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Error en/disabling RCD: ", e);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * @param comp a non-null ComponentName
-     * @param enabledArray may be null
-     * @return
-     */
-    private boolean isComponentInStringArray(ComponentName comp, String[] enabledArray) {
-        if (enabledArray == null || enabledArray.length == 0) {
-            if (DEBUG_RC) { Log.d(TAG, " > " + comp + " is NOT enabled"); }
-            return false;
-        }
-        final String compString = comp.flattenToString();
-        for (int i=0; i<enabledArray.length; i++) {
-            if (compString.equals(enabledArray[i])) {
-                if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is enabled"); }
-                return true;
-            }
-        }
-        if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is NOT enabled"); }
-        return false;
-    }
-
-    //==========================================================================================
-    // Internal event handling
-    //==========================================================================================
-
-    // event handler messages
-    private static final int MSG_RCDISPLAY_CLEAR = 1;
-    private static final int MSG_RCDISPLAY_UPDATE = 2;
-    private static final int MSG_REEVALUATE_REMOTE = 3;
-    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
-    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
-    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 6;
-    private static final int MSG_RCC_SEEK_REQUEST = 7;
-    private static final int MSG_RCC_UPDATE_METADATA = 8;
-    private static final int MSG_RCDISPLAY_INIT_INFO = 9;
-    private static final int MSG_REEVALUATE_RCD = 10;
-    private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
-
-    // sendMsg() flags
-    /** 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. */
-    private static final int SENDMSG_NOOP = 1;
-    /** If the msg is already queued, queue this one and leave the old. */
-    private static final int SENDMSG_QUEUE = 2;
-
-    private static void sendMsg(Handler handler, int msg,
-            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
-
-        if (existingMsgPolicy == SENDMSG_REPLACE) {
-            handler.removeMessages(msg);
-        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
-            return;
-        }
-
-        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
-    }
-
-    private class MediaEventHandler extends Handler {
-        MediaEventHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case MSG_RCDISPLAY_CLEAR:
-                    onRcDisplayClear();
-                    break;
-
-                case MSG_RCDISPLAY_UPDATE:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayUpdate( (PlayerRecord) msg.obj, msg.arg1);
-                    break;
-
-                case MSG_REEVALUATE_REMOTE:
-                    onReevaluateRemote();
-                    break;
-
-                case MSG_RCC_NEW_VOLUME_OBS:
-                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
-                            (IRemoteVolumeObserver)msg.obj /* rvo */);
-                    break;
-
-                case MSG_RCDISPLAY_INIT_INFO:
-                    // msg.obj is guaranteed to be non null
-                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
-                            msg.arg1/*w*/, msg.arg2/*h*/);
-                    break;
-
-                case MSG_REEVALUATE_RCD:
-                    onReevaluateRemoteControlDisplays();
-                    break;
-
-                case MSG_UNREGISTER_MEDIABUTTONINTENT:
-                    unregisterMediaButtonIntent( (PendingIntent) msg.obj );
-                    break;
-            }
-        }
-    }
-
-
-    //==========================================================================================
-    // AudioFocus
-    //==========================================================================================
-
-    /**
-     * Constant to identify a focus stack entry that is used to hold the focus while the phone
-     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
-     * entering and exiting calls.
-     */
-    protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
-
-    private final static Object mAudioFocusLock = new Object();
-
-    private final static Object mRingingLock = new Object();
-
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onCallStateChanged(int state, String incomingNumber) {
-            if (state == TelephonyManager.CALL_STATE_RINGING) {
-                //Log.v(TAG, " CALL_STATE_RINGING");
-                synchronized(mRingingLock) {
-                    mIsRinging = true;
-                }
-            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
-                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
-                synchronized(mRingingLock) {
-                    mIsRinging = false;
-                }
-            }
-        }
-    };
-
-    /**
-     * Discard the current audio focus owner.
-     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
-     * focus), remove it from the stack, and clear the remote control display.
-     */
-    protected void discardAudioFocusOwner() {
-        synchronized(mAudioFocusLock) {
-            if (!mFocusStack.empty()) {
-                // notify the current focus owner it lost focus after removing it from stack
-                final FocusRequester exFocusOwner = mFocusStack.pop();
-                exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
-                exFocusOwner.release();
-            }
-        }
-    }
-
-    /**
-     * Called synchronized on mAudioFocusLock
-     */
-    private void notifyTopOfAudioFocusStack() {
-        // notify the top of the stack it gained focus
-        if (!mFocusStack.empty()) {
-            if (canReassignAudioFocus()) {
-                mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
-            }
-        }
-    }
-
-    /**
-     * Focus is requested, propagate the associated loss throughout the stack.
-     * @param focusGain the new focus gain that will later be added at the top of the stack
-     */
-    private void propagateFocusLossFromGain_syncAf(int focusGain) {
-        // going through the audio focus stack to signal new focus, traversing order doesn't
-        // matter as all entries respond to the same external focus gain
-        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
-        while(stackIterator.hasNext()) {
-            stackIterator.next().handleExternalFocusGain(focusGain);
-        }
-    }
-
-    private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the audio focus stack
-     */
-    private void dumpFocusStack(PrintWriter pw) {
-        pw.println("\nAudio Focus stack entries (last is top of stack):");
-        synchronized(mAudioFocusLock) {
-            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                stackIterator.next().dump(pw);
-            }
-        }
-        pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n");
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove a focus listener from the focus stack.
-     * @param clientToRemove the focus listener
-     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
-     *   focus, notify the next item in the stack it gained focus.
-     */
-    private void removeFocusStackEntry(String clientToRemove, boolean signal,
-            boolean notifyFocusFollowers) {
-        // is the current top of the focus stack abandoning focus? (because of request, not death)
-        if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
-        {
-            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
-            FocusRequester fr = mFocusStack.pop();
-            fr.release();
-            if (notifyFocusFollowers) {
-                final AudioFocusInfo afi = fr.toAudioFocusInfo();
-                afi.clearLossReceived();
-                notifyExtPolicyFocusLoss_syncAf(afi, false);
-            }
-            if (signal) {
-                // notify the new top of the stack it gained focus
-                notifyTopOfAudioFocusStack();
-            }
-        } else {
-            // focus is abandoned by a client that's not at the top of the stack,
-            // no need to update focus.
-            // (using an iterator on the stack so we can safely remove an entry after having
-            //  evaluated it, traversal order doesn't matter here)
-            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
-            while(stackIterator.hasNext()) {
-                FocusRequester fr = stackIterator.next();
-                if(fr.hasSameClient(clientToRemove)) {
-                    Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
-                            + clientToRemove);
-                    stackIterator.remove();
-                    fr.release();
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mAudioFocusLock
-     * Remove focus listeners from the focus stack for a particular client when it has died.
-     */
-    private void removeFocusStackEntryForClient(IBinder cb) {
-        // is the owner of the audio focus part of the client to remove?
-        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
-                mFocusStack.peek().hasSameBinder(cb);
-        // (using an iterator on the stack so we can safely remove an entry after having
-        //  evaluated it, traversal order doesn't matter here)
-        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
-        while(stackIterator.hasNext()) {
-            FocusRequester fr = stackIterator.next();
-            if(fr.hasSameBinder(cb)) {
-                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
-                stackIterator.remove();
-                // the client just died, no need to unlink to its death
-            }
-        }
-        if (isTopOfStackForClientToRemove) {
-            // we removed an entry at the top of the stack:
-            //  notify the new top of the stack it gained focus.
-            notifyTopOfAudioFocusStack();
-        }
-    }
-
-    /**
-     * Helper function:
-     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
-     * The implementation guarantees that a state where focus cannot be immediately reassigned
-     * implies that an "locked" focus owner is at the top of the focus stack.
-     * Modifications to the implementation that break this assumption will cause focus requests to
-     * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
-     */
-    private boolean canReassignAudioFocus() {
-        // focus requests are rejected during a phone call or when the phone is ringing
-        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
-        if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
-            return false;
-        }
-        return true;
-    }
-
-    private boolean isLockedFocusOwner(FocusRequester fr) {
-        return (fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
-    }
-
-    /**
-     * Helper function
-     * Pre-conditions: focus stack is not empty, there is one or more locked focus owner
-     *                 at the top of the focus stack
-     * Push the focus requester onto the audio focus stack at the first position immediately
-     * following the locked focus owners.
-     * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
-     *     {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
-     */
-    private int pushBelowLockedFocusOwners(FocusRequester nfr) {
-        int lastLockedFocusOwnerIndex = mFocusStack.size();
-        for (int index = mFocusStack.size()-1; index >= 0; index--) {
-            if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
-                lastLockedFocusOwnerIndex = index;
-            }
-        }
-        if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
-            // this should not happen, but handle it and log an error
-            Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
-                    new Exception());
-            // no exclusive owner, push at top of stack, focus is granted, propagate change
-            propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
-            mFocusStack.push(nfr);
-            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-        } else {
-            mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
-            return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
-        }
-    }
-
-    /**
-     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
-     * stack if necessary.
-     */
-    protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-
-        AudioFocusDeathHandler(IBinder cb) {
-            mCb = cb;
-        }
-
-        public void binderDied() {
-            synchronized(mAudioFocusLock) {
-                Log.w(TAG, "  AudioFocus   audio focus client died");
-                removeFocusStackEntryForClient(mCb);
-            }
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-    /**
-     * Indicates whether to notify an audio focus owner when it loses focus
-     * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck.
-     * This variable being false indicates an AudioPolicy has been registered and has signaled
-     * it will handle audio ducking.
-     */
-    private boolean mNotifyFocusOwnerOnDuck = true;
-
-    protected void setDuckingInExtPolicyAvailable(boolean available) {
-        mNotifyFocusOwnerOnDuck = !available;
-    }
-
-    boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; }
-
-    private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();
-
-    void addFocusFollower(IAudioPolicyCallback ff) {
-        if (ff == null) {
-            return;
-        }
-        synchronized(mAudioFocusLock) {
-            boolean found = false;
-            for (IAudioPolicyCallback pcb : mFocusFollowers) {
-                if (pcb.asBinder().equals(ff.asBinder())) {
-                    found = true;
-                    break;
-                }
-            }
-            if (found) {
-                return;
-            } else {
-                mFocusFollowers.add(ff);
-            }
-        }
-    }
-
-    void removeFocusFollower(IAudioPolicyCallback ff) {
-        if (ff == null) {
-            return;
-        }
-        synchronized(mAudioFocusLock) {
-            for (IAudioPolicyCallback pcb : mFocusFollowers) {
-                if (pcb.asBinder().equals(ff.asBinder())) {
-                    mFocusFollowers.remove(pcb);
-                    break;
-                }
-            }
-        }
-    }
-
-    /**
-     * Called synchronized on mAudioFocusLock
-     */
-    void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
-        for (IAudioPolicyCallback pcb : mFocusFollowers) {
-            try {
-                // oneway
-                pcb.notifyAudioFocusGrant(afi, requestResult);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
-                        + pcb.asBinder(), e);
-            }
-        }
-    }
-
-    /**
-     * Called synchronized on mAudioFocusLock
-     */
-    void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) {
-        for (IAudioPolicyCallback pcb : mFocusFollowers) {
-            try {
-                // oneway
-                pcb.notifyAudioFocusLoss(afi, wasDispatched);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
-                        + pcb.asBinder(), e);
-            }
-        }
-    }
-
-    protected int getCurrentAudioFocus() {
-        synchronized(mAudioFocusLock) {
-            if (mFocusStack.empty()) {
-                return AudioManager.AUDIOFOCUS_NONE;
-            } else {
-                return mFocusStack.peek().getGainRequest();
-            }
-        }
-    }
-
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
-    protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
-        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId + " req=" + focusChangeHint +
-                "flags=0x" + Integer.toHexString(flags));
-        // we need a valid binder callback for clients
-        if (!cb.pingBinder()) {
-            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
-            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
-                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
-            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-        }
-
-        synchronized(mAudioFocusLock) {
-            boolean focusGrantDelayed = false;
-            if (!canReassignAudioFocus()) {
-                if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
-                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                } else {
-                    // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
-                    // granted right now, so the requester will be inserted in the focus stack
-                    // to receive focus later
-                    focusGrantDelayed = true;
-                }
-            }
-
-            // handle the potential premature death of the new holder of the focus
-            // (premature death == death before abandoning focus)
-            // Register for client death notification
-            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
-            try {
-                cb.linkToDeath(afdh, 0);
-            } catch (RemoteException e) {
-                // client has already died!
-                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-            }
-
-            if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
-                // if focus is already owned by this client and the reason for acquiring the focus
-                // hasn't changed, don't do anything
-                final FocusRequester fr = mFocusStack.peek();
-                if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
-                    // unlink death handler so it can be gc'ed.
-                    // linkToDeath() creates a JNI global reference preventing collection.
-                    cb.unlinkToDeath(afdh, 0);
-                    notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
-                            AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
-                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-                }
-                // the reason for the audio focus request has changed: remove the current top of
-                // stack and respond as if we had a new focus owner
-                if (!focusGrantDelayed) {
-                    mFocusStack.pop();
-                    // the entry that was "popped" is the same that was "peeked" above
-                    fr.release();
-                }
-            }
-
-            // focus requester might already be somewhere below in the stack, remove it
-            removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
-
-            final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
-                    clientId, afdh, callingPackageName, Binder.getCallingUid(), this);
-            if (focusGrantDelayed) {
-                // focusGrantDelayed being true implies we can't reassign focus right now
-                // which implies the focus stack is not empty.
-                final int requestResult = pushBelowLockedFocusOwners(nfr);
-                if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
-                    notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
-                }
-                return requestResult;
-            } else {
-                // propagate the focus change through the stack
-                if (!mFocusStack.empty()) {
-                    propagateFocusLossFromGain_syncAf(focusChangeHint);
-                }
-
-                // push focus requester at the top of the audio focus stack
-                mFocusStack.push(nfr);
-            }
-            notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
-                    AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
-
-        }//synchronized(mAudioFocusLock)
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-    /**
-     * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
-     * */
-    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
-        // AudioAttributes are currently ignored, to be used for zones
-        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
-        try {
-            // this will take care of notifying the new focus owner if needed
-            synchronized(mAudioFocusLock) {
-                removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
-            }
-        } catch (java.util.ConcurrentModificationException cme) {
-            // Catching this exception here is temporary. It is here just to prevent
-            // a crash seen when the "Silent" notification is played. This is believed to be fixed
-            // but this try catch block is left just to be safe.
-            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
-            cme.printStackTrace();
-        }
-
-        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
-    }
-
-
-    protected void unregisterAudioFocusClient(String clientId) {
-        synchronized(mAudioFocusLock) {
-            removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/);
-        }
-    }
-
-
-    //==========================================================================================
-    // RemoteControl
-    //==========================================================================================
-    /**
-     * No-op if the key code for keyEvent is not a valid media key
-     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
-     * @param keyEvent the key event to send
-     */
-    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
-    }
-
-    /**
-     * No-op if the key code for keyEvent is not a valid media key
-     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
-     * @param keyEvent the key event to send
-     */
-    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
-        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
-    }
-
-    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        // sanity check on the incoming key event
-        if (!isValidMediaKeyEvent(keyEvent)) {
-            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
-            return;
-        }
-        // event filtering for telephony
-        synchronized(mRingingLock) {
-            synchronized(mPRStack) {
-                if ((mMediaReceiverForCalls != null) &&
-                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
-                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
-                    return;
-                }
-            }
-        }
-        // event filtering based on voice-based interactions
-        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
-            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
-        } else {
-            dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to the telephony package.
-     * Precondition: mMediaReceiverForCalls != null
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * Handles the dispatching of the media button events to one of the registered listeners,
-     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
-     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
-        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-        synchronized(mPRStack) {
-            if (!mPRStack.empty()) {
-                // send the intent that was registered by the client
-                try {
-                    mPRStack.peek().getMediaButtonIntent().send(mContext,
-                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
-                            keyIntent, this, mEventHandler);
-                } catch (CanceledException e) {
-                    Log.e(TAG, "Error sending pending intent " + mPRStack.peek());
-                    e.printStackTrace();
-                }
-            } else {
-                // legacy behavior when nobody registered their media button event receiver
-                //    through AudioManager
-                if (needWakeLock) {
-                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
-                }
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
-                            null, mKeyEventDone,
-                            mEventHandler, Activity.RESULT_OK, null, null);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        }
-    }
-
-    /**
-     * The different actions performed in response to a voice button key event.
-     */
-    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
-    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
-    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
-
-    private final Object mVoiceEventLock = new Object();
-    private boolean mVoiceButtonDown;
-    private boolean mVoiceButtonHandled;
-
-    /**
-     * Filter key events that may be used for voice-based interactions
-     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
-     *    media buttons that can be used to trigger voice-based interactions.
-     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
-     *     is dispatched.
-     */
-    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
-        if (DEBUG_RC) {
-            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
-        }
-
-        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
-        int keyAction = keyEvent.getAction();
-        synchronized (mVoiceEventLock) {
-            if (keyAction == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    // initial down
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled
-                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                    // long-press, start voice-based interactions
-                    mVoiceButtonHandled = true;
-                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
-                }
-            } else if (keyAction == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    // voice button up
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
-                    }
-                }
-            }
-        }//synchronized (mVoiceEventLock)
-
-        // take action after media button event filtering for voice-based interactions
-        switch (voiceButtonAction) {
-            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
-                break;
-            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
-                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
-                // then start the voice-based interactions
-                startVoiceBasedInteractions(needWakeLock);
-                break;
-            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
-                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
-                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
-                break;
-        }
-    }
-
-    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
-        // send DOWN event
-        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-        // send UP event
-        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
-        dispatchMediaKeyEvent(keyEvent, needWakeLock);
-
-    }
-
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        return KeyEvent.isMediaKey(keyEvent.getKeyCode());
-    }
-
-    /**
-     * Checks whether the given key code is one that can trigger the launch of voice-based
-     *   interactions.
-     * @param keyCode the key code associated with the key event
-     * @return true if the key is one of the supported voice-based interaction triggers
-     */
-    private static boolean isValidVoiceInputKeyCode(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Tell the system to start voice-based interactions / voice commands
-     */
-    private void startVoiceBasedInteractions(boolean needWakeLock) {
-        Intent voiceIntent = null;
-        // select which type of search to launch:
-        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
-        //    with EXTRA_SECURE set to true if the device is securely locked
-        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-        if (!isLocked && pm.isScreenOn()) {
-            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-        } else {
-            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                    isLocked && mKeyguardManager.isKeyguardSecure());
-            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-        }
-        // start the search activity
-        if (needWakeLock) {
-            mMediaEventWakeLock.acquire();
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (voiceIntent != null) {
-                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
-            }
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "No activity for search: " + e);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-            if (needWakeLock) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    }
-
-    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
-
-    // only set when wakelock was acquired, no need to check value when received
-    private static final String EXTRA_WAKELOCK_ACQUIRED =
-            "android.media.AudioService.WAKELOCK_ACQUIRED";
-
-    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
-            int resultCode, String resultData, Bundle resultExtras) {
-        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
-            mMediaEventWakeLock.release();
-        }
-    }
-
-    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            if (intent == null) {
-                return;
-            }
-            Bundle extras = intent.getExtras();
-            if (extras == null) {
-                return;
-            }
-            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
-                mMediaEventWakeLock.release();
-            }
-        }
-    };
-
-    /**
-     * Synchronization on mCurrentRcLock always inside a block synchronized on mPRStack
-     */
-    private final Object mCurrentRcLock = new Object();
-    /**
-     * The one remote control client which will receive a request for display information.
-     * This object may be null.
-     * Access protected by mCurrentRcLock.
-     */
-    private IRemoteControlClient mCurrentRcClient = null;
-    /**
-     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
-     * if mCurrentRcClient is null
-     */
-    private PendingIntent mCurrentRcClientIntent = null;
-
-    private final static int RC_INFO_NONE = 0;
-    private final static int RC_INFO_ALL =
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
-        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
-
-    /**
-     * A monotonically increasing generation counter for mCurrentRcClient.
-     * Only accessed with a lock on mCurrentRcLock.
-     * No value wrap-around issues as we only act on equal values.
-     */
-    private int mCurrentRcClientGen = 0;
-
-
-    /**
-     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
-     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
-     * every time we need this info.
-     */
-    private RemotePlaybackState mMainRemote;
-    /**
-     * Indicates whether the "main" RemoteControlClient is considered active.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mMainRemoteIsActive;
-    /**
-     * Indicates whether there is remote playback going on. True even if there is no "active"
-     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
-     * handles remote playback.
-     * Use synchronized on mMainRemote.
-     */
-    private boolean mHasRemotePlayback;
-
-    /**
-     * The stack of remote control event receivers.
-     * All read and write operations on mPRStack are synchronized.
-     */
-    private final Stack<PlayerRecord> mPRStack = new Stack<PlayerRecord>();
-
-    /**
-     * The component the telephony package can register so telephony calls have priority to
-     * handle media button events
-     */
-    private ComponentName mMediaReceiverForCalls = null;
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control focus stack
-     */
-    private void dumpRCStack(PrintWriter pw) {
-        pw.println("\nRemote Control stack entries (last is top of stack):");
-        synchronized(mPRStack) {
-            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while(stackIterator.hasNext()) {
-                stackIterator.next().dump(pw, true);
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the remote control stack, focusing
-     * on RemoteControlClient data
-     */
-    private void dumpRCCStack(PrintWriter pw) {
-        pw.println("\nRemote Control Client stack entries (last is top of stack):");
-        synchronized(mPRStack) {
-            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while(stackIterator.hasNext()) {
-                stackIterator.next().dump(pw, false);
-            }
-            synchronized(mCurrentRcLock) {
-                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
-            }
-        }
-        synchronized (mMainRemote) {
-            pw.println("\nRemote Volume State:");
-            pw.println("  has remote: " + mHasRemotePlayback);
-            pw.println("  is remote active: " + mMainRemoteIsActive);
-            pw.println("  rccId: " + mMainRemote.mRccId);
-            pw.println("  volume handling: "
-                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
-                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
-            pw.println("  volume: " + mMainRemote.mVolume);
-            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Display in the log the current entries in the list of remote control displays
-     */
-    private void dumpRCDList(PrintWriter pw) {
-        pw.println("\nRemote Control Display list entries:");
-        synchronized(mPRStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = displayIterator.next();
-                pw.println("  IRCD: " + di.mRcDisplay +
-                        "  -- w:" + di.mArtworkExpectedWidth +
-                        "  -- h:" + di.mArtworkExpectedHeight +
-                        "  -- wantsPosSync:" + di.mWantsPositionSync +
-                        "  -- " + (di.mEnabled ? "enabled" : "disabled"));
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Push the new media button receiver "near" the top of the PlayerRecord stack.
-     * "Near the top" is defined as:
-     *   - at the top if the current PlayerRecord at the top is not playing
-     *   - below the entries at the top of the stack that correspond to the playing PlayerRecord
-     *     otherwise
-     * Called synchronized on mPRStack
-     * precondition: mediaIntent != null
-     * @return true if the top of mPRStack was changed, false otherwise
-     */
-    private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
-            ComponentName target, IBinder token) {
-        if (mPRStack.empty()) {
-            mPRStack.push(new PlayerRecord(mediaIntent, target, token));
-            return true;
-        } else if (mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
-            // already at top of stack
-            return false;
-        }
-        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
-                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return false;
-        }
-        PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
-        boolean topChanged = false;
-        PlayerRecord prse = null;
-        int lastPlayingIndex = mPRStack.size();
-        int inStackIndex = -1;
-        try {
-            // go through the stack from the top to figure out who's playing, and the position
-            // of this media button receiver (note that it may not be in the stack)
-            for (int index = mPRStack.size()-1; index >= 0; index--) {
-                prse = mPRStack.elementAt(index);
-                if (prse.isPlaybackActive()) {
-                    lastPlayingIndex = index;
-                }
-                if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
-                    inStackIndex = index;
-                }
-            }
-
-            if (inStackIndex == -1) {
-                // is not in stack
-                prse = new PlayerRecord(mediaIntent, target, token);
-                // it's new so it's not playing (no RemoteControlClient to give a playstate),
-                // therefore it goes after the ones with active playback
-                mPRStack.add(lastPlayingIndex, prse);
-            } else {
-                // is in the stack
-                if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
-                    prse = mPRStack.elementAt(inStackIndex);
-                    // remove it from its old location in the stack
-                    mPRStack.removeElementAt(inStackIndex);
-                    if (prse.isPlaybackActive()) {
-                        // and put it at the top
-                        mPRStack.push(prse);
-                    } else {
-                        // and put it after the ones with active playback
-                        if (inStackIndex > lastPlayingIndex) {
-                            mPRStack.add(lastPlayingIndex, prse);
-                        } else {
-                            mPRStack.add(lastPlayingIndex - 1, prse);
-                        }
-                    }
-                }
-            }
-
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification or bad index
-            Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
-                    + " size=" + mPRStack.size()
-                    + " accessing media button stack", e);
-        }
-
-        return (topChanged);
-    }
-
-    /**
-     * Helper function:
-     * Remove the remote control receiver from the RC focus stack.
-     * Called synchronized on mPRStack
-     * precondition: pi != null
-     */
-    private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) {
-        try {
-            for (int index = mPRStack.size()-1; index >= 0; index--) {
-                final PlayerRecord prse = mPRStack.elementAt(index);
-                if (prse.hasMatchingMediaButtonIntent(pi)) {
-                    prse.destroy();
-                    // ok to remove element while traversing the stack since we're leaving the loop
-                    mPRStack.removeElementAt(index);
-                    break;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // not expected to happen, indicates improper concurrent modification
-            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     */
-    private boolean isCurrentRcController(PendingIntent pi) {
-        if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(pi)) {
-            return true;
-        }
-        return false;
-    }
-
-    //==========================================================================================
-    // Remote control display / client
-    //==========================================================================================
-    /**
-     * Update the remote control displays with the new "focused" client generation
-     */
-    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        synchronized(mPRStack) {
-            if (mRcDisplays.size() > 0) {
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    try {
-                        di.mRcDisplay.setCurrentClientId(
-                                newClientGeneration, newMediaIntent, clearing);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
-                        di.release();
-                        displayIterator.remove();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the remote control clients with the new "focused" client generation
-     */
-    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
-        // (using an iterator on the stack so we can safely remove an entry if needed,
-        //  traversal order doesn't matter here as we update all entries)
-        Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-        while(stackIterator.hasNext()) {
-            PlayerRecord se = stackIterator.next();
-            if ((se != null) && (se.getRcc() != null)) {
-                try {
-                    se.getRcc().setCurrentClientGenerationId(newClientGeneration);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
-                    stackIterator.remove();
-                    se.unlinkToRcClientDeath();
-                }
-            }
-        }
-    }
-
-    /**
-     * Update the displays and clients with the new "focused" client generation and name
-     * @param newClientGeneration the new generation value matching a client update
-     * @param newMediaIntent the media button event receiver associated with the client.
-     *    May be null, which implies there is no registered media button event receiver.
-     * @param clearing true if the new client generation value maps to a remote control update
-     *    where the display should be cleared.
-     */
-    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
-            PendingIntent newMediaIntent, boolean clearing) {
-        // send the new valid client generation ID to all displays
-        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
-        // send the new valid client generation ID to all clients
-        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_CLEAR event
-     */
-    private void onRcDisplayClear() {
-        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
-
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                mCurrentRcClientGen++;
-                // synchronously update the displays and clients with the new client generation
-                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                        null /*newMediaIntent*/, true /*clearing*/);
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_UPDATE event
-     */
-    private void onRcDisplayUpdate(PlayerRecord prse, int flags /* USED ?*/) {
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(prse.getRcc()))) {
-                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
-
-                    mCurrentRcClientGen++;
-                    // synchronously update the displays and clients with
-                    //      the new client generation
-                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
-                            prse.getMediaButtonIntent() /*newMediaIntent*/,
-                            false /*clearing*/);
-
-                    // tell the current client that it needs to send info
-                    try {
-                        //TODO change name to informationRequestForAllDisplays()
-                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Current valid remote client is dead: "+e);
-                        mCurrentRcClient = null;
-                    }
-                } else {
-                    // the remote control display owner has changed between the
-                    // the message to update the display was sent, and the time it
-                    // gets to be processed (now)
-                }
-            }
-        }
-    }
-
-    /**
-     * Called when processing MSG_RCDISPLAY_INIT_INFO event
-     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
-     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
-     */
-    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
-        synchronized(mPRStack) {
-            synchronized(mCurrentRcLock) {
-                if (mCurrentRcClient != null) {
-                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
-                    try {
-                        // synchronously update the new RCD with the current client generation
-                        // and matching PendingIntent
-                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
-                                false);
-
-                        // tell the current RCC that it needs to send info, but only to the new RCD
-                        try {
-                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Current valid remote client is dead: ", e);
-                            mCurrentRcClient = null;
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     */
-    private void clearRemoteControlDisplay_syncPrs() {
-        synchronized(mCurrentRcLock) {
-            mCurrentRcClient = null;
-        }
-        // will cause onRcDisplayClear() to be called in AudioService's handler thread
-        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
-    }
-
-    /**
-     * Helper function for code readability: only to be called from
-     *    checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for
-     *    this method.
-     * Preconditions:
-     *    - called synchronized on mPRStack
-     *    - mPRStack.isEmpty() is false
-     */
-    private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
-        PlayerRecord prse = mPRStack.peek();
-        int infoFlagsAboutToBeUsed = infoChangedFlags;
-        // this is where we enforce opt-in for information display on the remote controls
-        //   with the new AudioManager.registerRemoteControlClient() API
-        if (prse.getRcc() == null) {
-            //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncPrs();
-            return;
-        }
-        synchronized(mCurrentRcLock) {
-            if (!prse.getRcc().equals(mCurrentRcClient)) {
-                // new RC client, assume every type of information shall be queried
-                infoFlagsAboutToBeUsed = RC_INFO_ALL;
-            }
-            mCurrentRcClient = prse.getRcc();
-            mCurrentRcClientIntent = prse.getMediaButtonIntent();
-        }
-        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
-        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
-                infoFlagsAboutToBeUsed /* arg1 */, 0, prse /* obj, != null */) );
-    }
-
-    /**
-     * Helper function:
-     * Called synchronized on mPRStack
-     * Check whether the remote control display should be updated, triggers the update if required
-     * @param infoChangedFlags the flags corresponding to the remote control client information
-     *     that has changed, if applicable (checking for the update conditions might trigger a
-     *     clear, rather than an update event).
-     */
-    private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
-        // determine whether the remote control display should be refreshed
-        // if the player record stack is empty, there is nothing to display, so clear the RC display
-        if (mPRStack.isEmpty()) {
-            clearRemoteControlDisplay_syncPrs();
-            return;
-        }
-
-        // this is where more rules for refresh go
-
-        // refresh conditions were verified: update the remote controls
-        // ok to call: synchronized on mPRStack, mPRStack is not empty
-        updateRemoteControlDisplay_syncPrs(infoChangedFlags);
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
-     * precondition: mediaIntent != null
-     */
-    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
-            IBinder token) {
-        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mPRStack) {
-            if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) {
-                // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
-     * precondition: mediaIntent != null, eventReceiver != null
-     */
-    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
-    {
-        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
-
-        synchronized(mPRStack) {
-            boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
-            removeMediaButtonReceiver_syncPrs(mediaIntent);
-            if (topOfStackWillChange) {
-                // current RC client will change, assume every type of info needs to be queried
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-    protected void unregisterMediaButtonIntentAsync(final PendingIntent mediaIntent) {
-        mEventHandler.sendMessage(
-                mEventHandler.obtainMessage(MSG_UNREGISTER_MEDIABUTTONINTENT, 0, 0,
-                        mediaIntent));
-    }
-
-    /**
-     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
-     * precondition: c != null
-     */
-    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
-            return;
-        }
-        synchronized(mPRStack) {
-            mMediaReceiverForCalls = c;
-        }
-    }
-
-    /**
-     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
-     */
-    protected void unregisterMediaButtonEventReceiverForCalls() {
-        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
-                != PackageManager.PERMISSION_GRANTED) {
-            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
-            return;
-        }
-        synchronized(mPRStack) {
-            mMediaReceiverForCalls = null;
-        }
-    }
-
-    /**
-     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
-     * @return the unique ID of the PlayerRecord associated with the RemoteControlClient
-     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
-     *     without modifying the RC stack, but while still causing the display to refresh (will
-     *     become blank as a result of this)
-     */
-    protected int registerRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient, String callingPackageName) {
-        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized(mPRStack) {
-            // store the new display information
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
-                        prse.resetControllerInfoForRcc(rcClient, callingPackageName,
-                                Binder.getCallingUid());
-
-                        if (rcClient == null) {
-                            break;
-                        }
-
-                        rccId = prse.getRccId();
-
-                        // there is a new (non-null) client:
-                        //     give the new client the displays (if any)
-                        if (mRcDisplays.size() > 0) {
-                            plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc());
-                        }
-                        break;
-                    }
-                }//for
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-
-            // if the eventReceiver is at the top of the stack
-            // then check for potential refresh of the remote controls
-            if (isCurrentRcController(mediaIntent)) {
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }//synchronized(mPRStack)
-        return rccId;
-    }
-
-    /**
-     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
-     * rcClient is guaranteed non-null
-     */
-    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
-            IRemoteControlClient rcClient) {
-        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
-        synchronized(mPRStack) {
-            boolean topRccChange = false;
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
-                            && rcClient.equals(prse.getRcc())) {
-                        // we found the IRemoteControlClient to unregister
-                        prse.resetControllerInfoForNoRcc();
-                        topRccChange = (index == mPRStack.size()-1);
-                        // there can only be one matching RCC in the RC stack, we're done
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-            if (topRccChange) {
-                // no more RCC for the RCD, check for potential refresh of the remote controls
-                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
-            }
-        }
-    }
-
-
-    /**
-     * A class to encapsulate all the information about a remote control display.
-     * After instanciation, init() must always be called before the object is added in the list
-     * of displays.
-     * Before being removed from the list of displays, release() must always be called (otherwise
-     * it will leak death handlers).
-     */
-    private class DisplayInfoForServer implements IBinder.DeathRecipient {
-        /** may never be null */
-        private final IRemoteControlDisplay mRcDisplay;
-        private final IBinder mRcDisplayBinder;
-        private int mArtworkExpectedWidth = -1;
-        private int mArtworkExpectedHeight = -1;
-        private boolean mWantsPositionSync = false;
-        private ComponentName mClientNotifListComp;
-        private boolean mEnabled = true;
-
-        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
-            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
-            mRcDisplay = rcd;
-            mRcDisplayBinder = rcd.asBinder();
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
-        }
-
-        public boolean init() {
-            try {
-                mRcDisplayBinder.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                // remote control display is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
-                return false;
-            }
-            return true;
-        }
-
-        public void release() {
-            try {
-                mRcDisplayBinder.unlinkToDeath(this, 0);
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here, the display should have been unregistered anyway
-                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
-            }
-        }
-
-        public void binderDied() {
-            synchronized(mPRStack) {
-                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
-                // remove the display from the list
-                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-                while (displayIterator.hasNext()) {
-                    final DisplayInfoForServer di = displayIterator.next();
-                    if (di.mRcDisplay == mRcDisplay) {
-                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
-                        displayIterator.remove();
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * The remote control displays.
-     * Access synchronized on mPRStack
-     */
-    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
-
-    /**
-     * Plug each registered display into the specified client
-     * @param rcc, guaranteed non null
-     */
-    private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = displayIterator.next();
-            try {
-                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
-                        di.mArtworkExpectedHeight);
-                if (di.mWantsPositionSync) {
-                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
-            }
-        }
-    }
-
-    private void enableRemoteControlDisplayForClient_syncRcStack(IRemoteControlDisplay rcd,
-            boolean enabled) {
-        // let all the remote control clients know whether the given display is enabled
-        //   (so the remote control stack traversal order doesn't matter).
-        final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-        while(stackIterator.hasNext()) {
-            PlayerRecord prse = stackIterator.next();
-            if(prse.getRcc() != null) {
-                try {
-                    prse.getRcc().enableRemoteControlDisplay(rcd, enabled);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error connecting RCD to client: ", e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Is the remote control display interface already registered
-     * @param rcd
-     * @return true if the IRemoteControlDisplay is already in the list of displays
-     */
-    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
-        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-        while (displayIterator.hasNext()) {
-            final DisplayInfoForServer di = displayIterator.next();
-            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Register an IRemoteControlDisplay.
-     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
-     * at the top of the stack to update the new display with its information.
-     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay to register. No effect if null.
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param listenerComp the component for the listener interface, may be null if it's not needed
-     *   to verify it belongs to one of the enabled notification listeners
-     */
-    private void registerRemoteControlDisplay_int(IRemoteControlDisplay rcd, int w, int h,
-            ComponentName listenerComp) {
-        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
-        synchronized(mAudioFocusLock) {
-            synchronized(mPRStack) {
-                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
-                    return;
-                }
-                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
-                di.mEnabled = true;
-                di.mClientNotifListComp = listenerComp;
-                if (!di.init()) {
-                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
-                    return;
-                }
-                // add RCD to list of displays
-                mRcDisplays.add(di);
-
-                // let all the remote control clients know there is a new display (so the remote
-                //   control stack traversal order doesn't matter).
-                Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().plugRemoteControlDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error connecting RCD to client: ", e);
-                        }
-                    }
-                }
-
-                // we have a new display, of which all the clients are now aware: have it be
-                // initialized wih the current gen ID and the current client info, do not
-                // reset the information for the other (existing) displays
-                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
-                        w /*arg1*/, h /*arg2*/,
-                        rcd /*obj*/, 0/*delay*/);
-            }
-        }
-    }
-
-    /**
-     * Unregister an IRemoteControlDisplay.
-     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
-     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
-     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
-     */
-    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
-        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
-        synchronized(mPRStack) {
-            if (rcd == null) {
-                return;
-            }
-
-            boolean displayWasPluggedIn = false;
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext() && !displayWasPluggedIn) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    displayWasPluggedIn = true;
-                    di.release();
-                    displayIterator.remove();
-                }
-            }
-
-            if (displayWasPluggedIn) {
-                // disconnect this remote control display from all the clients, so the remote
-                //   control stack traversal order doesn't matter
-                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().unplugRemoteControlDisplay(rcd);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
-                        }
-                    }
-                }
-            } else {
-                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
-            }
-        }
-    }
-
-    /**
-     * Update the size of the artwork used by an IRemoteControlDisplay.
-     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
-     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
-     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
-     *   display doesn't need to receive artwork.
-     */
-    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
-        synchronized(mPRStack) {
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            boolean artworkSizeUpdate = false;
-            while (displayIterator.hasNext() && !artworkSizeUpdate) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
-                        di.mArtworkExpectedWidth = w;
-                        di.mArtworkExpectedHeight = h;
-                        artworkSizeUpdate = true;
-                    }
-                }
-            }
-            if (artworkSizeUpdate) {
-                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
-                // stack traversal order doesn't matter
-                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-                while(stackIterator.hasNext()) {
-                    final PlayerRecord prse = stackIterator.next();
-                    if(prse.getRcc() != null) {
-                        try {
-                            prse.getRcc().setBitmapSizeForDisplay(rcd, w, h);
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
-     * playback position to verify that the estimated position has not drifted from the actual
-     * position. By default the check is not performed.
-     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
-     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
-     *     or disabled. Not null.
-     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
-     *     to the framework will regularly compare the estimated playback position with the actual
-     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
-     *     detected.
-     */
-    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
-            boolean wantsSync) {
-        synchronized(mPRStack) {
-            boolean rcdRegistered = false;
-            // store the information about this display
-            // (display stack traversal order doesn't matter).
-            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
-            while (displayIterator.hasNext()) {
-                final DisplayInfoForServer di = displayIterator.next();
-                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
-                    di.mWantsPositionSync = wantsSync;
-                    rcdRegistered = true;
-                    break;
-                }
-            }
-            if (!rcdRegistered) {
-                return;
-            }
-            // notify all current RemoteControlClients
-            // (stack traversal order doesn't matter as we notify all RCCs)
-            final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
-            while (stackIterator.hasNext()) {
-                final PlayerRecord prse = stackIterator.next();
-                if (prse.getRcc() != null) {
-                    try {
-                        prse.getRcc().setWantsSyncForDisplay(rcd, wantsSync);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
-                    }
-                }
-            }
-        }
-    }
-
-    // handler for MSG_RCC_NEW_VOLUME_OBS
-    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
-        synchronized(mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if (prse.getRccId() == rccId) {
-                        prse.mRemoteVolumeObs = rvo;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-    }
-
-    /**
-     * Checks if a remote client is active on the supplied stream type. Update the remote stream
-     * volume state if found and playing
-     * @param streamType
-     * @return false if no remote playing is currently playing
-     */
-    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
-        synchronized(mPRStack) {
-            // iterating from top of stack as active playback is more likely on entries at the top
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    if ((prse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(prse.mPlaybackState.mState)
-                            && (prse.mPlaybackStream == streamType)) {
-                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
-                                + ", vol =" + prse.mPlaybackVolume);
-                        synchronized (mMainRemote) {
-                            mMainRemote.mRccId = prse.getRccId();
-                            mMainRemote.mVolume = prse.mPlaybackVolume;
-                            mMainRemote.mVolumeMax = prse.mPlaybackVolumeMax;
-                            mMainRemote.mVolumeHandling = prse.mPlaybackVolumeHandling;
-                            mMainRemoteIsActive = true;
-                        }
-                        return true;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
-            }
-        }
-        synchronized (mMainRemote) {
-            mMainRemoteIsActive = false;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the given playback state is considered "active", i.e. it describes a state
-     * where playback is happening, or about to
-     * @param playState the playback state to evaluate
-     * @return true if active, false otherwise (inactive or unknown)
-     */
-    protected static boolean isPlaystateActive(int playState) {
-        switch (playState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private void sendVolumeUpdateToRemote(int rccId, int direction) {
-        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
-        if (direction == 0) {
-            // only handling discrete events
-            return;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (prse.getRccId() == rccId) {
-                        rvo = prse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(direction, -1);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching relative volume update", e);
-            }
-        }
-    }
-
-    protected int getRemoteStreamMaxVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolumeMax;
-        }
-    }
-
-    protected int getRemoteStreamVolume() {
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return 0;
-            }
-            return mMainRemote.mVolume;
-        }
-    }
-
-    protected void setRemoteStreamVolume(int vol) {
-        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
-        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
-        synchronized (mMainRemote) {
-            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
-                return;
-            }
-            rccId = mMainRemote.mRccId;
-        }
-        IRemoteVolumeObserver rvo = null;
-        synchronized (mPRStack) {
-            // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
-            //  start iterating from the top.
-            try {
-                for (int index = mPRStack.size()-1; index >= 0; index--) {
-                    final PlayerRecord prse = mPRStack.elementAt(index);
-                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    if (prse.getRccId() == rccId) {
-                        rvo = prse.mRemoteVolumeObs;
-                        break;
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
-            }
-        }
-        if (rvo != null) {
-            try {
-                rvo.dispatchRemoteVolumeUpdate(0, vol);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error dispatching absolute volume update", e);
-            }
-        }
-    }
-
-    /**
-     * Call to make AudioService reevaluate whether it's in a mode where remote players should
-     * have their volume controlled. In this implementation this is only to reset whether
-     * VolumePanel should display remote volumes
-     */
-    protected void postReevaluateRemote() {
-        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
-    }
-
-    private void onReevaluateRemote() {
-        // TODO This was used to notify VolumePanel if there was remote playback
-        // in the stack. This is now in MediaSessionService. More code should be
-        // removed.
-    }
-
-}
diff --git a/media/java/android/media/MediaHTTPService.java b/media/java/android/media/MediaHTTPService.java
index 3b4703d..2348ab7 100644
--- a/media/java/android/media/MediaHTTPService.java
+++ b/media/java/android/media/MediaHTTPService.java
@@ -16,9 +16,7 @@
 
 package android.media;
 
-import android.os.Binder;
 import android.os.IBinder;
-import android.util.Log;
 
 /** @hide */
 public class MediaHTTPService extends IMediaHTTPService.Stub {
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 754da0e..39bcef5 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -30,7 +30,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.util.ArrayList;
 import java.util.Set;
 
 /**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 615dac2..d77fcd8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -16,14 +16,11 @@
 
 package android.media;
 
+import android.annotation.IntDef;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
-import android.app.Application;
-import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.AssetFileDescriptor;
 import android.net.Uri;
 import android.os.Handler;
@@ -64,8 +61,9 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.lang.Runnable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.InetSocketAddress;
 import java.util.Map;
 import java.util.Scanner;
@@ -477,6 +475,11 @@
  *     <td>{} </p></td>
  *     <td>This method can be called in any state and calling it does not change
  *         the object state.  </p></td></tr>
+ * <tr><td>setPlaybackRate</p></td>
+ *     <td>any </p></td>
+ *     <td>{} </p></td>
+ *     <td>This method can be called in any state and calling it does not change
+ *         the object state. </p></td></tr>
  * <tr><td>setVolume </p></td>
  *     <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
  *          PlaybackCompleted}</p></td>
@@ -604,6 +607,7 @@
     private final IAppOpsService mAppOps;
     private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
     private int mUsage = -1;
+    private boolean mBypassInterruptionPolicy;
 
     /**
      * Default constructor. Consider using one of the create() methods for
@@ -1169,6 +1173,9 @@
     private native void _start() throws IllegalStateException;
 
     private boolean isRestricted() {
+        if (mBypassInterruptionPolicy) {
+            return false;
+        }
         try {
             final int usage = mUsage != -1 ? mUsage
                     : AudioAttributes.usageForLegacyStreamType(getAudioStreamType());
@@ -1320,6 +1327,59 @@
     public native boolean isPlaying();
 
     /**
+     * Specifies resampling as audio mode for variable rate playback, i.e.,
+     * resample the waveform based on the requested playback rate to get
+     * a new waveform, and play back the new waveform at the original sampling
+     * frequency.
+     * When rate is larger than 1.0, pitch becomes higher.
+     * When rate is smaller than 1.0, pitch becomes lower.
+     */
+    public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0;
+
+    /**
+     * Specifies time stretching as audio mode for variable rate playback.
+     * Time stretching changes the duration of the audio samples without
+     * affecting its pitch.
+     * FIXME: implement time strectching.
+     * @hide
+     */
+    public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
+
+    /** @hide */
+    @IntDef(
+        value = {
+            PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
+            PLAYBACK_RATE_AUDIO_MODE_STRETCH })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PlaybackRateAudioMode {}
+
+    /**
+     * Sets playback rate and audio mode.
+     *
+     * <p> The supported audio modes are:
+     * <ul>
+     * <li> {@link #PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
+     * </ul>
+     *
+     * @param rate the ratio between desired playback rate and normal one.
+     * @param audioMode audio playback mode. Must be one of the supported
+     * audio modes.
+     *
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized.
+     * @throws IllegalArgumentException if audioMode is not supported.
+     */
+    public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
+        if (!isAudioPlaybackModeSupported(audioMode)) {
+            final String msg = "Audio playback mode " + audioMode + " is not supported";
+            throw new IllegalArgumentException(msg);
+        }
+        _setPlaybackRate(rate);
+    }
+
+    private native void _setPlaybackRate(float rate) throws IllegalStateException;
+
+    /**
      * Seeks to specified time position.
      *
      * @param msec the offset in milliseconds from the start to seek to
@@ -1560,6 +1620,8 @@
             throw new IllegalArgumentException(msg);
         }
         mUsage = attributes.getUsage();
+        mBypassInterruptionPolicy = (attributes.getFlags()
+                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
         Parcel pattributes = Parcel.obtain();
         attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
         setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
@@ -3077,6 +3139,14 @@
                 mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
     }
 
+    /*
+     * Test whether a given audio playback mode is supported.
+     * TODO query supported AudioPlaybackMode from player.
+     */
+    private boolean isAudioPlaybackModeSupported(int mode) {
+        return (mode == PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
+    }
+
     /** @hide */
     static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
             MediaTimeProvider {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 81d5afe..58c86f2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.hardware.Camera;
 import android.os.Handler;
@@ -222,12 +223,11 @@
         public static final int REMOTE_SUBMIX = 8;
 
         /**
-         * Audio source for FM, which is used to capture current FM tuner output by FMRadio app.
-         * There are two use cases, one is for record FM stream for later listening, another is
-         * for FM indirect mode(the routing except FM to headset(headphone) device routing).
+         * Audio source for capturing broadcast radio tuner output.
          * @hide
          */
-        public static final int FM_TUNER = 1998;
+        @SystemApi
+        public static final int RADIO_TUNER = 1998;
 
         /**
          * Audio source for preemptible, low-priority software hotword detection
@@ -240,7 +240,8 @@
          * This is a hidden audio source.
          * @hide
          */
-        protected static final int HOTWORD = 1999;
+        @SystemApi
+        public static final int HOTWORD = 1999;
     }
 
     /**
@@ -437,10 +438,7 @@
     public void setCaptureRate(double fps) {
         // Make sure that time lapse is enabled when this method is called.
         setParameter("time-lapse-enable=1");
-
-        double timeBetweenFrameCapture = 1 / fps;
-        long timeBetweenFrameCaptureUs = (long) (1000000 * timeBetweenFrameCapture);
-        setParameter("time-between-time-lapse-frame-capture=" + timeBetweenFrameCaptureUs);
+        setParameter("time-lapse-fps=" + fps);
     }
 
     /**
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 958ffab..b4c612a 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.Manifest;
+import android.annotation.DrawableRes;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -171,15 +172,15 @@
         }
 
         void updateAudioRoutes(AudioRoutesInfo newRoutes) {
-            if (newRoutes.mMainType != mCurAudioRoutesInfo.mMainType) {
-                mCurAudioRoutesInfo.mMainType = newRoutes.mMainType;
+            if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
+                mCurAudioRoutesInfo.mainType = newRoutes.mainType;
                 int name;
-                if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
-                        || (newRoutes.mMainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
+                if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
+                        || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_headphones;
-                } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
-                } else if ((newRoutes.mMainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
+                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
                     name = com.android.internal.R.string.default_media_route_name_hdmi;
                 } else {
                     name = com.android.internal.R.string.default_audio_route_name;
@@ -188,21 +189,21 @@
                 dispatchRouteChanged(sStatic.mDefaultAudioVideo);
             }
 
-            final int mainType = mCurAudioRoutesInfo.mMainType;
+            final int mainType = mCurAudioRoutesInfo.mainType;
 
-            if (!TextUtils.equals(newRoutes.mBluetoothName, mCurAudioRoutesInfo.mBluetoothName)) {
-                mCurAudioRoutesInfo.mBluetoothName = newRoutes.mBluetoothName;
-                if (mCurAudioRoutesInfo.mBluetoothName != null) {
+            if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+                mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+                if (mCurAudioRoutesInfo.bluetoothName != null) {
                     if (sStatic.mBluetoothA2dpRoute == null) {
                         final RouteInfo info = new RouteInfo(sStatic.mSystemCategory);
-                        info.mName = mCurAudioRoutesInfo.mBluetoothName;
+                        info.mName = mCurAudioRoutesInfo.bluetoothName;
                         info.mDescription = sStatic.mResources.getText(
                                 com.android.internal.R.string.bluetooth_a2dp_audio_route_name);
                         info.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO;
                         sStatic.mBluetoothA2dpRoute = info;
                         addRouteStatic(sStatic.mBluetoothA2dpRoute);
                     } else {
-                        sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.mBluetoothName;
+                        sStatic.mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
                         dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
                     }
                 } else if (sStatic.mBluetoothA2dpRoute != null) {
@@ -2083,7 +2084,7 @@
          *
          * @param resId Resource ID of an icon drawable to use to represent this route
          */
-        public void setIconResource(int resId) {
+        public void setIconResource(@DrawableRes int resId) {
             setIconDrawable(sStatic.mResources.getDrawable(resId));
         }
 
@@ -2393,7 +2394,7 @@
          *
          * @param resId Resource ID of an icon drawable to use to represent this group
          */
-        public void setIconResource(int resId) {
+        public void setIconResource(@DrawableRes int resId) {
             setIconDrawable(sStatic.mResources.getDrawable(resId));
         }
 
diff --git a/media/java/android/media/OnAudioDeviceConnectionListener.java b/media/java/android/media/OnAudioDeviceConnectionListener.java
new file mode 100644
index 0000000..4bdd4d0
--- /dev/null
+++ b/media/java/android/media/OnAudioDeviceConnectionListener.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * API candidate
+ */
+public abstract class OnAudioDeviceConnectionListener {
+    public void onConnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+    public void onDisconnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+}
diff --git a/media/java/android/media/PlayerRecord.java b/media/java/android/media/PlayerRecord.java
deleted file mode 100644
index 664ddcf..0000000
--- a/media/java/android/media/PlayerRecord.java
+++ /dev/null
@@ -1,357 +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.media;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.PrintWriter;
-
-/**
- * @hide
- * Class to handle all the information about a media player, encapsulating information
- * about its use RemoteControlClient, playback type and volume... The lifecycle of each
- * instance is managed by android.media.MediaFocusControl, from its addition to the player stack
- * stack to its release.
- */
-class PlayerRecord implements DeathRecipient {
-
-    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
-    private static final String TAG = "MediaFocusControl";
-    private static final boolean DEBUG = false;
-
-    /**
-     * A global counter for RemoteControlClient identifiers
-     */
-    private static int sLastRccId = 0;
-
-    public static MediaFocusControl sController;
-
-    /**
-     * The target for the ACTION_MEDIA_BUTTON events.
-     * Always non null. //FIXME verify
-     */
-    final private PendingIntent mMediaIntent;
-    /**
-     * The registered media button event receiver.
-     */
-    final private ComponentName mReceiverComponent;
-
-    private int mRccId = -1;
-
-    /**
-     * A non-null token implies this record tracks a "live" player whose death is being monitored.
-     */
-    private IBinder mToken;
-    private String mCallingPackageName;
-    private int mCallingUid;
-    /**
-     * Provides access to the information to display on the remote control.
-     * May be null (when a media button event receiver is registered,
-     *     but no remote control client has been registered) */
-    private IRemoteControlClient mRcClient;
-    private RcClientDeathHandler mRcClientDeathHandler;
-    /**
-     * Information only used for non-local playback
-     */
-    //FIXME private?
-    public int mPlaybackType;
-    public int mPlaybackVolume;
-    public int mPlaybackVolumeMax;
-    public int mPlaybackVolumeHandling;
-    public int mPlaybackStream;
-    public RccPlaybackState mPlaybackState;
-    public IRemoteVolumeObserver mRemoteVolumeObs;
-
-
-    protected static class RccPlaybackState {
-        public int mState;
-        public long mPositionMs;
-        public float mSpeed;
-
-        public RccPlaybackState(int state, long positionMs, float speed) {
-            mState = state;
-            mPositionMs = positionMs;
-            mSpeed = speed;
-        }
-
-        public void reset() {
-            mState = RemoteControlClient.PLAYSTATE_STOPPED;
-            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
-            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
-        }
-
-        @Override
-        public String toString() {
-            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
-        }
-
-        private String posToString() {
-            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
-                return "PLAYBACK_POSITION_INVALID";
-            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
-                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
-            } else {
-                return (String.valueOf(mPositionMs) + "ms");
-            }
-        }
-
-        private String stateToString() {
-            switch (mState) {
-                case RemoteControlClient.PLAYSTATE_NONE:
-                    return "PLAYSTATE_NONE";
-                case RemoteControlClient.PLAYSTATE_STOPPED:
-                    return "PLAYSTATE_STOPPED";
-                case RemoteControlClient.PLAYSTATE_PAUSED:
-                    return "PLAYSTATE_PAUSED";
-                case RemoteControlClient.PLAYSTATE_PLAYING:
-                    return "PLAYSTATE_PLAYING";
-                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                    return "PLAYSTATE_FAST_FORWARDING";
-                case RemoteControlClient.PLAYSTATE_REWINDING:
-                    return "PLAYSTATE_REWINDING";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                    return "PLAYSTATE_SKIPPING_FORWARDS";
-                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                    return "PLAYSTATE_SKIPPING_BACKWARDS";
-                case RemoteControlClient.PLAYSTATE_BUFFERING:
-                    return "PLAYSTATE_BUFFERING";
-                case RemoteControlClient.PLAYSTATE_ERROR:
-                    return "PLAYSTATE_ERROR";
-                default:
-                    return "[invalid playstate]";
-            }
-        }
-    }
-
-
-    /**
-     * Inner class to monitor remote control client deaths, and remove the client for the
-     * remote control stack if necessary.
-     */
-    private class RcClientDeathHandler implements IBinder.DeathRecipient {
-        final private IBinder mCb; // To be notified of client's death
-        //FIXME needed?
-        final private PendingIntent mMediaIntent;
-
-        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
-            mCb = cb;
-            mMediaIntent = pi;
-        }
-
-        public void binderDied() {
-            Log.w(TAG, "  RemoteControlClient died");
-            // remote control client died, make sure the displays don't use it anymore
-            //  by setting its remote control client to null
-            sController.registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
-            // the dead client was maybe handling remote playback, the controller should reevaluate
-            sController.postReevaluateRemote();
-        }
-
-        public IBinder getBinder() {
-            return mCb;
-        }
-    }
-
-
-    protected static class RemotePlaybackState {
-        int mRccId;
-        int mVolume;
-        int mVolumeMax;
-        int mVolumeHandling;
-
-        protected RemotePlaybackState(int id, int vol, int volMax) {
-            mRccId = id;
-            mVolume = vol;
-            mVolumeMax = volMax;
-            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        }
-    }
-
-
-    void dump(PrintWriter pw, boolean registrationInfo) {
-        if (registrationInfo) {
-            pw.println("  pi: " + mMediaIntent +
-                    " -- pack: " + mCallingPackageName +
-                    "  -- ercvr: " + mReceiverComponent +
-                    "  -- client: " + mRcClient +
-                    "  -- uid: " + mCallingUid +
-                    "  -- type: " + mPlaybackType +
-                    "  state: " + mPlaybackState);
-        } else {
-            // emphasis on state
-            pw.println("  uid: " + mCallingUid +
-                    "  -- id: " + mRccId +
-                    "  -- type: " + mPlaybackType +
-                    "  -- state: " + mPlaybackState +
-                    "  -- vol handling: " + mPlaybackVolumeHandling +
-                    "  -- vol: " + mPlaybackVolume +
-                    "  -- volMax: " + mPlaybackVolumeMax +
-                    "  -- volObs: " + mRemoteVolumeObs);
-        }
-    }
-
-
-    static protected void setMediaFocusControl(MediaFocusControl mfc) {
-        sController = mfc;
-    }
-
-    /** precondition: mediaIntent != null */
-    protected PlayerRecord(PendingIntent mediaIntent, ComponentName eventReceiver, IBinder token)
-    {
-        mMediaIntent = mediaIntent;
-        mReceiverComponent = eventReceiver;
-        mToken = token;
-        mCallingUid = -1;
-        mRcClient = null;
-        mRccId = ++sLastRccId;
-        mPlaybackState = new RccPlaybackState(
-                RemoteControlClient.PLAYSTATE_STOPPED,
-                RemoteControlClient.PLAYBACK_POSITION_INVALID,
-                RemoteControlClient.PLAYBACK_SPEED_1X);
-
-        resetPlaybackInfo();
-        if (mToken != null) {
-            try {
-                mToken.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                sController.unregisterMediaButtonIntentAsync(mMediaIntent);
-            }
-        }
-    }
-
-    //---------------------------------------------
-    // Accessors
-    protected int getRccId() {
-        return mRccId;
-    }
-
-    protected IRemoteControlClient getRcc() {
-        return mRcClient;
-    }
-
-    protected ComponentName getMediaButtonReceiver() {
-        return mReceiverComponent;
-    }
-
-    protected PendingIntent getMediaButtonIntent() {
-        return mMediaIntent;
-    }
-
-    protected boolean hasMatchingMediaButtonIntent(PendingIntent pi) {
-        if (mToken != null) {
-            return mMediaIntent.equals(pi);
-        } else {
-            if (mReceiverComponent != null) {
-                return mReceiverComponent.equals(pi.getIntent().getComponent());
-            } else {
-                return false;
-            }
-        }
-    }
-
-    protected boolean isPlaybackActive() {
-        return MediaFocusControl.isPlaystateActive(mPlaybackState.mState);
-    }
-
-    //---------------------------------------------
-    // Modify the records stored in the instance
-    protected void resetControllerInfoForRcc(IRemoteControlClient rcClient,
-            String callingPackageName, int uid) {
-        // already had a remote control client?
-        if (mRcClientDeathHandler != null) {
-            // stop monitoring the old client's death
-            unlinkToRcClientDeath();
-        }
-        // save the new remote control client
-        mRcClient = rcClient;
-        mCallingPackageName = callingPackageName;
-        mCallingUid = uid;
-        if (rcClient == null) {
-            // here mcse.mRcClientDeathHandler is null;
-            resetPlaybackInfo();
-        } else {
-            IBinder b = mRcClient.asBinder();
-            RcClientDeathHandler rcdh =
-                    new RcClientDeathHandler(b, mMediaIntent);
-            try {
-                b.linkToDeath(rcdh, 0);
-            } catch (RemoteException e) {
-                // remote control client is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
-                mRcClient = null;
-            }
-            mRcClientDeathHandler = rcdh;
-        }
-    }
-
-    protected void resetControllerInfoForNoRcc() {
-        // stop monitoring the RCC death
-        unlinkToRcClientDeath();
-        // reset the RCC-related fields
-        mRcClient = null;
-        mCallingPackageName = null;
-    }
-
-    public void resetPlaybackInfo() {
-        mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
-        mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-        mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
-        mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
-        mPlaybackStream = AudioManager.STREAM_MUSIC;
-        mPlaybackState.reset();
-        mRemoteVolumeObs = null;
-    }
-
-    //---------------------------------------------
-    public void unlinkToRcClientDeath() {
-        if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
-            try {
-                mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
-                mRcClientDeathHandler = null;
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here
-                Log.e(TAG, "Error in unlinkToRcClientDeath()", e);
-            }
-        }
-    }
-
-    // FIXME rename to "release"? (as in FocusRequester class)
-    public void destroy() {
-        unlinkToRcClientDeath();
-        if (mToken != null) {
-            mToken.unlinkToDeath(this, 0);
-            mToken = null;
-        }
-    }
-
-    @Override
-    public void binderDied() {
-        sController.unregisterMediaButtonIntentAsync(mMediaIntent);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        destroy(); // unlink exception handled inside method
-        super.finalize();
-    }
-}
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 1b6536f..c9a86d8 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -27,7 +27,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.Log;
 
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 4f74bdd..db6b38b 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -543,11 +543,6 @@
 
         public int load(String path, int priority)
         {
-            // pass network streams to player
-            if (path.startsWith("http:"))
-                return _load(path, priority);
-
-            // try local path
             int id = 0;
             try {
                 File f = new File(path);
@@ -562,6 +557,7 @@
             return id;
         }
 
+        @Override
         public int load(Context context, int resId, int priority) {
             AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
             int id = 0;
@@ -576,6 +572,7 @@
             return id;
         }
 
+        @Override
         public int load(AssetFileDescriptor afd, int priority) {
             if (afd != null) {
                 long len = afd.getLength();
@@ -588,16 +585,17 @@
             }
         }
 
+        @Override
         public int load(FileDescriptor fd, long offset, long length, int priority) {
             return _load(fd, offset, length, priority);
         }
 
-        private native final int _load(String uri, int priority);
-
         private native final int _load(FileDescriptor fd, long offset, long length, int priority);
 
+        @Override
         public native final boolean unload(int soundID);
 
+        @Override
         public final int play(int soundID, float leftVolume, float rightVolume,
                 int priority, int loop, float rate) {
             if (isRestricted()) {
@@ -610,6 +608,9 @@
                 int priority, int loop, float rate);
 
         private boolean isRestricted() {
+            if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+                return false;
+            }
             try {
                 final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
                         mAttributes.getUsage(),
@@ -620,16 +621,22 @@
             }
         }
 
+        @Override
         public native final void pause(int streamID);
 
+        @Override
         public native final void resume(int streamID);
 
+        @Override
         public native final void autoPause();
 
+        @Override
         public native final void autoResume();
 
+        @Override
         public native final void stop(int streamID);
 
+        @Override
         public final void setVolume(int streamID, float leftVolume, float rightVolume) {
             if (isRestricted()) {
                 return;
@@ -639,16 +646,21 @@
 
         private native final void _setVolume(int streamID, float leftVolume, float rightVolume);
 
+        @Override
         public void setVolume(int streamID, float volume) {
             setVolume(streamID, volume, volume);
         }
 
+        @Override
         public native final void setPriority(int streamID, int priority);
 
+        @Override
         public native final void setLoop(int streamID, int loop);
 
+        @Override
         public native final void setRate(int streamID, float rate);
 
+        @Override
         public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
         {
             synchronized(mLock) {
@@ -729,52 +741,69 @@
             return 0;
         }
 
+        @Override
         public int load(Context context, int resId, int priority) {
             return 0;
         }
 
+        @Override
         public int load(AssetFileDescriptor afd, int priority) {
             return 0;
         }
 
+        @Override
         public int load(FileDescriptor fd, long offset, long length, int priority) {
             return 0;
         }
 
+        @Override
         public final boolean unload(int soundID) {
             return true;
         }
 
+        @Override
         public final int play(int soundID, float leftVolume, float rightVolume,
                 int priority, int loop, float rate) {
             return 0;
         }
 
+        @Override
         public final void pause(int streamID) { }
 
+        @Override
         public final void resume(int streamID) { }
 
+        @Override
         public final void autoPause() { }
 
+        @Override
         public final void autoResume() { }
 
+        @Override
         public final void stop(int streamID) { }
 
+        @Override
         public final void setVolume(int streamID,
                 float leftVolume, float rightVolume) { }
 
+        @Override
         public void setVolume(int streamID, float volume) {
         }
 
+        @Override
         public final void setPriority(int streamID, int priority) { }
 
+        @Override
         public final void setLoop(int streamID, int loop) { }
 
+        @Override
         public final void setRate(int streamID, float rate) { }
 
+        @Override
         public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener) {
         }
 
+        @Override
         public final void release() { }
     }
 }
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
index 75133c9..9d587b9 100644
--- a/media/java/android/media/TtmlRenderer.java
+++ b/media/java/android/media/TtmlRenderer.java
@@ -17,27 +17,15 @@
 package android.media;
 
 import android.content.Context;
-import android.graphics.Color;
-import android.media.SubtitleTrack.RenderingWidget.OnChangedListener;
-import android.text.Layout.Alignment;
-import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.CaptioningManager;
-import android.view.accessibility.CaptioningManager.CaptionStyle;
-import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.internal.widget.SubtitleView;
-
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index df0daaf..9e01e65 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -26,8 +26,6 @@
 import java.util.Comparator;
 import java.util.Vector;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 // package private
 class Utils {
     private static final String TAG = "Utils";
diff --git a/media/java/android/media/VolumePolicy.aidl b/media/java/android/media/VolumePolicy.aidl
new file mode 100644
index 0000000..371f798
--- /dev/null
+++ b/media/java/android/media/VolumePolicy.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable VolumePolicy;
diff --git a/media/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
new file mode 100644
index 0000000..2d3376a
--- /dev/null
+++ b/media/java/android/media/VolumePolicy.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class VolumePolicy implements Parcelable {
+    public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true, 400);
+
+    /** Allow volume adjustments lower from vibrate to enter ringer mode = silent */
+    public final boolean volumeDownToEnterSilent;
+
+    /** Allow volume adjustments higher to exit ringer mode = silent */
+    public final boolean volumeUpToExitSilent;
+
+    /** Automatically enter do not disturb when ringer mode = silent */
+    public final boolean doNotDisturbWhenSilent;
+
+    /** Only allow volume adjustment from vibrate to silent after this
+        number of milliseconds since an adjustment from normal to vibrate. */
+    public final int vibrateToSilentDebounce;
+
+    public VolumePolicy(boolean volumeDownToEnterSilent, boolean volumeUpToExitSilent,
+            boolean doNotDisturbWhenSilent, int vibrateToSilentDebounce) {
+        this.volumeDownToEnterSilent = volumeDownToEnterSilent;
+        this.volumeUpToExitSilent = volumeUpToExitSilent;
+        this.doNotDisturbWhenSilent = doNotDisturbWhenSilent;
+        this.vibrateToSilentDebounce = vibrateToSilentDebounce;
+    }
+
+    @Override
+    public String toString() {
+        return "VolumePolicy[volumeDownToEnterSilent=" + volumeDownToEnterSilent
+                + ",volumeUpToExitSilent=" + volumeUpToExitSilent
+                + ",doNotDisturbWhenSilent=" + doNotDisturbWhenSilent
+                + ",vibrateToSilentDebounce=" + vibrateToSilentDebounce + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(volumeDownToEnterSilent ? 1 : 0);
+        dest.writeInt(volumeUpToExitSilent ? 1 : 0);
+        dest.writeInt(doNotDisturbWhenSilent ? 1 : 0);
+        dest.writeInt(vibrateToSilentDebounce);
+    }
+
+    public static final Parcelable.Creator<VolumePolicy> CREATOR
+            = new Parcelable.Creator<VolumePolicy>() {
+        @Override
+        public VolumePolicy createFromParcel(Parcel p) {
+            return new VolumePolicy(p.readInt() != 0,
+                    p.readInt() != 0,
+                    p.readInt() != 0,
+                    p.readInt());
+        }
+
+        @Override
+        public VolumePolicy[] newArray(int size) {
+            return new VolumePolicy[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 019309d..917e07b 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -16,12 +16,8 @@
 
 package android.media.audiopolicy;
 
-import android.media.AudioAttributes;
 import android.media.AudioFormat;
-import android.media.AudioManager;
 import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
-import android.os.Binder;
-import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index d260b05..ef8d169 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -33,6 +33,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.service.media.IMediaBrowserService;
 import android.service.media.IMediaBrowserServiceCallbacks;
@@ -291,15 +292,17 @@
      * the specified id and subscribes to receive updates when they change.
      * <p>
      * The list of subscriptions is maintained even when not connected and is
-     * restored after reconnection.  It is ok to subscribe while not connected
+     * restored after reconnection. It is ok to subscribe while not connected
      * but the results will not be returned until the connection completes.
-     * </p><p>
+     * </p>
+     * <p>
      * If the id is already subscribed with a different callback then the new
-     * callback will replace the previous one.
+     * callback will replace the previous one and the child data will be
+     * reloaded.
      * </p>
      *
      * @param parentId The id of the parent media item whose list of children
-     * will be subscribed.
+     *            will be subscribed.
      * @param callback The callback to receive the list of children.
      */
     public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
@@ -322,7 +325,7 @@
 
         // If we are connected, tell the service that we are watching.  If we aren't
         // connected, the service will be told when we connect.
-        if (mState == CONNECT_STATE_CONNECTED && newSubscription) {
+        if (mState == CONNECT_STATE_CONNECTED) {
             try {
                 mServiceBinder.addSubscription(parentId, mServiceCallbacks);
             } catch (RemoteException ex) {
@@ -345,8 +348,8 @@
      */
     public void unsubscribe(@NonNull String parentId) {
         // Check arguments.
-        if (parentId == null) {
-            throw new IllegalArgumentException("parentId is null");
+        if (TextUtils.isEmpty(parentId)) {
+            throw new IllegalArgumentException("parentId is empty.");
         }
 
         // Remove from our list.
@@ -365,6 +368,60 @@
     }
 
     /**
+     * Retrieves a specific {@link MediaItem} from the connected service. Not
+     * all services may support this, so falling back to subscribing to the
+     * parent's id should be used when unavailable.
+     *
+     * @param mediaId The id of the item to retrieve.
+     * @param cb The callback to receive the result on.
+     */
+    public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
+        if (TextUtils.isEmpty(mediaId)) {
+            throw new IllegalArgumentException("mediaId is empty.");
+        }
+        if (cb == null) {
+            throw new IllegalArgumentException("cb is null.");
+        }
+        if (mState != CONNECT_STATE_CONNECTED) {
+            Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    cb.onError();
+                }
+            });
+            return;
+        }
+        ResultReceiver receiver = new ResultReceiver(mHandler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode != 0 || resultData == null
+                        || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
+                    cb.onError();
+                    return;
+                }
+                Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
+                if (!(item instanceof MediaItem)) {
+                    cb.onError();
+                }
+                cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
+                        MediaBrowserService.KEY_MEDIA_ITEM));
+            }
+        };
+        try {
+            mServiceBinder.getMediaItem(mediaId, receiver);
+        } catch (RemoteException e) {
+            Log.i(TAG, "Remote error getting media item.");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    cb.onError();
+                }
+            });
+        }
+    }
+
+    /**
      * For debugging.
      */
     private static String getStateLabel(int state) {
@@ -688,6 +745,27 @@
     }
 
     /**
+     * Callback for receiving the result of {@link #getMediaItem}.
+     */
+    public static abstract class MediaItemCallback {
+
+        /**
+         * Called when the item has been returned by the browser service.
+         *
+         * @param item The item that was returned or null if it doesn't exist.
+         */
+        public void onMediaItemLoaded(MediaItem item) {
+        }
+
+        /**
+         * Called when the id doesn't exist or there was an error retrieving the
+         * item.
+         */
+        public void onError() {
+        }
+    }
+
+    /**
      * ServiceConnection to the other app.
      */
     private class MediaServiceConnection implements ServiceConnection {
diff --git a/media/java/android/media/midi/IMidiDeviceListener.aidl b/media/java/android/media/midi/IMidiDeviceListener.aidl
new file mode 100644
index 0000000..31c66e3
--- /dev/null
+++ b/media/java/android/media/midi/IMidiDeviceListener.aidl
@@ -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.
+ */
+
+package android.media.midi;
+
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceStatus;
+
+/** @hide */
+oneway interface IMidiDeviceListener
+{
+    void onDeviceAdded(in MidiDeviceInfo device);
+    void onDeviceRemoved(in MidiDeviceInfo device);
+    void onDeviceStatusChanged(in MidiDeviceStatus status);
+}
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
new file mode 100644
index 0000000..642078a
--- /dev/null
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IMidiDeviceServer
+{
+    ParcelFileDescriptor openInputPort(IBinder token, int portNumber);
+    ParcelFileDescriptor openOutputPort(IBinder token, int portNumber);
+    void closePort(IBinder token);
+
+    // connects the input port pfd to the specified output port
+    void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
+}
diff --git a/media/java/android/media/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl
new file mode 100644
index 0000000..74c63b4
--- /dev/null
+++ b/media/java/android/media/midi/IMidiManager.aidl
@@ -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.media.midi;
+
+import android.media.midi.IMidiDeviceListener;
+import android.media.midi.IMidiDeviceServer;
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceStatus;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/** @hide */
+interface IMidiManager
+{
+    MidiDeviceInfo[] getDeviceList();
+
+    // for device creation & removal notifications
+    void registerListener(IBinder token, in IMidiDeviceListener listener);
+    void unregisterListener(IBinder token, in IMidiDeviceListener listener);
+
+    // for opening built-in MIDI devices
+    IMidiDeviceServer openDevice(IBinder token, in MidiDeviceInfo device);
+
+    // for registering built-in MIDI devices
+    MidiDeviceInfo registerDeviceServer(in IMidiDeviceServer server, int numInputPorts,
+            int numOutputPorts, in String[] inputPortNames, in String[] outputPortNames,
+            in Bundle properties, int type);
+
+    // for unregistering built-in MIDI devices
+    void unregisterDeviceServer(in IMidiDeviceServer server);
+
+    // used by MidiDeviceService to access the MidiDeviceInfo that was created based on its
+    // manifest's meta-data
+    MidiDeviceInfo getServiceDeviceInfo(String packageName, String className);
+
+    // used for client's to retrieve a device's MidiDeviceStatus
+    MidiDeviceStatus getDeviceStatus(in MidiDeviceInfo deviceInfo);
+
+    // used by MIDI devices to report their status
+    // the token is used by MidiService for death notification
+    void setDeviceStatus(IBinder token, in MidiDeviceStatus status);
+}
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
new file mode 100644
index 0000000..569f7c6
--- /dev/null
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -0,0 +1,190 @@
+/*
+ * 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.midi;
+
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * This class is used for sending and receiving data to and from a MIDI device
+ * Instances of this class are created by {@link MidiManager#openDevice}.
+ *
+ * CANDIDATE FOR PUBLIC API
+ * @hide
+ */
+public final class MidiDevice implements Closeable {
+    private static final String TAG = "MidiDevice";
+
+    private final MidiDeviceInfo mDeviceInfo;
+    private final IMidiDeviceServer mDeviceServer;
+    private Context mContext;
+    private ServiceConnection mServiceConnection;
+
+
+    private final CloseGuard mGuard = CloseGuard.get();
+
+    public class MidiConnection implements Closeable {
+        private final IBinder mToken;
+        private final MidiInputPort mInputPort;
+
+        MidiConnection(IBinder token, MidiInputPort inputPort) {
+            mToken = token;
+            mInputPort = inputPort;
+        }
+
+        @Override
+        public void close() throws IOException {
+            try {
+                mDeviceServer.closePort(mToken);
+                IoUtils.closeQuietly(mInputPort);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in MidiConnection.close");
+            }
+        }
+    }
+
+    /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) {
+        this(deviceInfo, server, null, null);
+    }
+
+    /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server,
+            Context context, ServiceConnection serviceConnection) {
+        mDeviceInfo = deviceInfo;
+        mDeviceServer = server;
+        mContext = context;
+        mServiceConnection = serviceConnection;
+        mGuard.open("close");
+    }
+
+    /**
+     * Returns a {@link MidiDeviceInfo} object, which describes this device.
+     *
+     * @return the {@link MidiDeviceInfo} object
+     */
+    public MidiDeviceInfo getInfo() {
+        return mDeviceInfo;
+    }
+
+    /**
+     * Called to open a {@link MidiInputPort} for the specified port number.
+     *
+     * @param portNumber the number of the input port to open
+     * @return the {@link MidiInputPort}
+     */
+    public MidiInputPort openInputPort(int portNumber) {
+        try {
+            IBinder token = new Binder();
+            ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
+            if (pfd == null) {
+                return null;
+            }
+            return new MidiInputPort(mDeviceServer, token, pfd, portNumber);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in openInputPort");
+            return null;
+        }
+    }
+
+    /**
+     * Called to open a {@link MidiOutputPort} for the specified port number.
+     *
+     * @param portNumber the number of the output port to open
+     * @return the {@link MidiOutputPort}
+     */
+    public MidiOutputPort openOutputPort(int portNumber) {
+        try {
+            IBinder token = new Binder();
+            ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
+            if (pfd == null) {
+                return null;
+            }
+            return new MidiOutputPort(mDeviceServer, token, pfd, portNumber);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in openOutputPort");
+            return null;
+        }
+    }
+
+    /**
+     * Connects the supplied {@link MidiInputPort} to the output port of this device
+     * with the specified port number. Once the connection is made, the MidiInput port instance
+     * can no longer receive data via its {@link MidiReciever.receive} method.
+     * This method returns a {@link #MidiConnection} object, which can be used to close the connection
+     * @param inputPort the inputPort to connect
+     * @param outputPortNumber the port number of the output port to connect inputPort to.
+     * @return {@link #MidiConnection} object if the connection is successful, or null in case of failure
+     */
+    public MidiConnection connectPorts(MidiInputPort inputPort, int outputPortNumber) {
+        if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
+            throw new IllegalArgumentException("outputPortNumber out of range");
+        }
+
+        ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
+        if (pfd == null) {
+            return null;
+        }
+         try {
+            IBinder token = new Binder();
+            mDeviceServer.connectPorts(token, pfd, outputPortNumber);
+            // close our copy of the file descriptor
+            IoUtils.closeQuietly(pfd);
+            return new MidiConnection(token, inputPort);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in connectPorts");
+            return null;
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (mGuard) {
+            mGuard.close();
+            if (mContext != null && mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+                mContext = null;
+                mServiceConnection = null;
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return ("MidiDevice: " + mDeviceInfo.toString());
+    }
+}
diff --git a/media/java/android/media/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
new file mode 100644
index 0000000..f2f37a2
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.midi;
+
+parcelable MidiDeviceInfo;
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
new file mode 100644
index 0000000..f7fad3d
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -0,0 +1,321 @@
+/*
+ * 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.midi;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information to describe a MIDI device.
+ * For now we only have information that can be retrieved easily for USB devices,
+ * but we will probably expand this in the future.
+ *
+ * This class is just an immutable object to encapsulate the MIDI device description.
+ * Use the MidiDevice class to actually communicate with devices.
+ */
+public final class MidiDeviceInfo implements Parcelable {
+
+    private static final String TAG = "MidiDeviceInfo";
+
+    /**
+     * Constant representing USB MIDI devices for {@link #getType}
+     */
+    public static final int TYPE_USB = 1;
+
+    /**
+     * Constant representing virtual (software based) MIDI devices for {@link #getType}
+     */
+    public static final int TYPE_VIRTUAL = 2;
+
+    /**
+     * Bundle key for the device's user visible name property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
+     * For USB devices, this is a concatenation of the manufacturer and product names.
+     */
+    public static final String PROPERTY_NAME = "name";
+
+    /**
+     * Bundle key for the device's manufacturer name property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
+     * Matches the USB device manufacturer name string for USB MIDI devices.
+     */
+    public static final String PROPERTY_MANUFACTURER = "manufacturer";
+
+    /**
+     * Bundle key for the device's product name property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     * Matches the USB device product name string for USB MIDI devices.
+     */
+    public static final String PROPERTY_PRODUCT = "product";
+
+    /**
+     * Bundle key for the device's serial number property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     * Matches the USB device serial number for USB MIDI devices.
+     */
+    public static final String PROPERTY_SERIAL_NUMBER = "serial_number";
+
+    /**
+     * Bundle key for the device's {@link android.hardware.usb.UsbDevice}.
+     * Only set for USB MIDI devices.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     */
+    public static final String PROPERTY_USB_DEVICE = "usb_device";
+
+    /**
+     * Bundle key for the device's ALSA card number.
+     * Only set for USB MIDI devices.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
+     */
+    public static final String PROPERTY_ALSA_CARD = "alsa_card";
+
+    /**
+     * Bundle key for the device's ALSA device number.
+     * Only set for USB MIDI devices.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
+     */
+    public static final String PROPERTY_ALSA_DEVICE = "alsa_device";
+
+    /**
+     * {@link android.content.pm.ServiceInfo} for the service hosting the device implementation.
+     * Only set for Virtual MIDI devices.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     *
+     * @hide
+     */
+    public static final String PROPERTY_SERVICE_INFO = "service_info";
+
+    /**
+     * Contains information about an input or output port.
+     */
+    public static final class PortInfo {
+        /**
+         * Port type for input ports
+         */
+        public static final int TYPE_INPUT = 1;
+
+        /**
+         * Port type for output ports
+         */
+        public static final int TYPE_OUTPUT = 2;
+
+        private final int mPortType;
+        private final int mPortNumber;
+        private final String mName;
+
+        PortInfo(int type, int portNumber, String name) {
+            mPortType = type;
+            mPortNumber = portNumber;
+            mName = (name == null ? "" : name);
+        }
+
+        /**
+         * Returns the port type of the port (either {@link #TYPE_INPUT} or {@link #TYPE_OUTPUT})
+         * @return the port type
+         */
+        public int getType() {
+            return mPortType;
+        }
+
+        /**
+         * Returns the port number of the port
+         * @return the port number
+         */
+        public int getPortNumber() {
+            return mPortNumber;
+        }
+
+        /**
+         * Returns the name of the port, or empty string if the port has no name
+         * @return the port name
+         */
+        public String getName() {
+            return mName;
+        }
+    }
+
+    private final int mType;    // USB or virtual
+    private final int mId;      // unique ID generated by MidiService
+    private final int mInputPortCount;
+    private final int mOutputPortCount;
+    private final String[] mInputPortNames;
+    private final String[] mOutputPortNames;
+    private final Bundle mProperties;
+    private final boolean mIsPrivate;
+
+    /**
+     * MidiDeviceInfo should only be instantiated by MidiService implementation
+     * @hide
+     */
+    public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
+            String[] inputPortNames, String[] outputPortNames, Bundle properties,
+            boolean isPrivate) {
+        mType = type;
+        mId = id;
+        mInputPortCount = numInputPorts;
+        mOutputPortCount = numOutputPorts;
+        mInputPortNames = inputPortNames;
+        mOutputPortNames = outputPortNames;
+        mProperties = properties;
+        mIsPrivate = isPrivate;
+    }
+
+    /**
+     * Returns the type of the device.
+     *
+     * @return the device's type
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the ID of the device.
+     * This ID is generated by the MIDI service and is not persistent across device unplugs.
+     *
+     * @return the device's ID
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the device's number of input ports.
+     *
+     * @return the number of input ports
+     */
+    public int getInputPortCount() {
+        return mInputPortCount;
+    }
+
+    /**
+     * Returns the device's number of output ports.
+     *
+     * @return the number of output ports
+     */
+    public int getOutputPortCount() {
+        return mOutputPortCount;
+    }
+
+    /**
+     * Returns information about an input port.
+     *
+     * @param portNumber the number of the input port
+     * @return the input port's information object
+     */
+    public PortInfo getInputPortInfo(int portNumber) {
+        if (portNumber < 0 || portNumber >= mInputPortCount) {
+            throw new IllegalArgumentException("portNumber out of range");
+        }
+        return new PortInfo(PortInfo.TYPE_INPUT, portNumber, mInputPortNames[portNumber]);
+    }
+
+    /**
+     * Returns information about an output port.
+     *
+     * @param portNumber the number of the output port
+     * @return the output port's information object
+     */
+    public PortInfo getOutputPortInfo(int portNumber) {
+        if (portNumber < 0 || portNumber >= mOutputPortCount) {
+            throw new IllegalArgumentException("portNumber out of range");
+        }
+        return new PortInfo(PortInfo.TYPE_OUTPUT, portNumber, mOutputPortNames[portNumber]);
+    }
+
+    /**
+     * Returns the {@link android.os.Bundle} containing the device's properties.
+     *
+     * @return the device's properties
+     */
+    public Bundle getProperties() {
+        return mProperties;
+    }
+
+    /**
+     * Returns true if the device is private.  Private devices are only visible and accessible
+     * to clients with the same UID as the application that is hosting the device.
+     *
+     * @return true if the device is private
+     */
+    public boolean isPrivate() {
+        return mIsPrivate;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof MidiDeviceInfo) {
+            return (((MidiDeviceInfo)o).mId == mId);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
+    }
+
+    @Override
+    public String toString() {
+        return ("MidiDeviceInfo[mType=" + mType +
+                ",mInputPortCount=" + mInputPortCount +
+                ",mOutputPortCount=" + mOutputPortCount +
+                ",mProperties=" + mProperties +
+                ",mIsPrivate=" + mIsPrivate);
+    }
+
+    public static final Parcelable.Creator<MidiDeviceInfo> CREATOR =
+        new Parcelable.Creator<MidiDeviceInfo>() {
+        public MidiDeviceInfo createFromParcel(Parcel in) {
+            int type = in.readInt();
+            int id = in.readInt();
+            int inputPorts = in.readInt();
+            int outputPorts = in.readInt();
+            String[] inputPortNames = in.createStringArray();
+            String[] outputPortNames = in.createStringArray();
+            Bundle properties = in.readBundle();
+            boolean isPrivate = (in.readInt() == 1);
+            return new MidiDeviceInfo(type, id, inputPorts, outputPorts,
+                    inputPortNames, outputPortNames, properties, isPrivate);
+        }
+
+        public MidiDeviceInfo[] newArray(int size) {
+            return new MidiDeviceInfo[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeInt(mId);
+        parcel.writeInt(mInputPortCount);
+        parcel.writeInt(mOutputPortCount);
+        parcel.writeStringArray(mInputPortNames);
+        parcel.writeStringArray(mOutputPortNames);
+        parcel.writeBundle(mProperties);
+        parcel.writeInt(mIsPrivate ? 1 : 0);
+   }
+}
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
new file mode 100644
index 0000000..d27351f
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -0,0 +1,351 @@
+/*
+ * 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.midi;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.system.OsConstants;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Internal class used for providing an implementation for a MIDI device.
+ *
+ * @hide
+ */
+public final class MidiDeviceServer implements Closeable {
+    private static final String TAG = "MidiDeviceServer";
+
+    private final IMidiManager mMidiManager;
+
+    // MidiDeviceInfo for the device implemented by this server
+    private MidiDeviceInfo mDeviceInfo;
+    private final int mInputPortCount;
+    private final int mOutputPortCount;
+
+    // MidiReceivers for receiving data on our input ports
+    private final MidiReceiver[] mInputPortReceivers;
+
+    // MidiDispatchers for sending data on our output ports
+    private MidiDispatcher[] mOutputPortDispatchers;
+
+    // MidiOutputPorts for clients connected to our input ports
+    private final MidiOutputPort[] mInputPortOutputPorts;
+
+    // List of all MidiInputPorts we created
+    private final CopyOnWriteArrayList<MidiInputPort> mInputPorts
+            = new CopyOnWriteArrayList<MidiInputPort>();
+
+
+    // for reporting device status
+    private final IBinder mDeviceStatusToken = new Binder();
+    private final boolean[] mInputPortOpen;
+    private final int[] mOutputPortOpenCount;
+
+    private final CloseGuard mGuard = CloseGuard.get();
+    private boolean mIsClosed;
+
+    private final Callback mCallback;
+
+    public interface Callback {
+        /**
+         * Called to notify when an our device status has changed
+         * @param server the {@link MidiDeviceServer} that changed
+         * @param status the {@link MidiDeviceStatus} for the device
+         */
+        public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status);
+    }
+
+    abstract private class PortClient implements IBinder.DeathRecipient {
+        final IBinder mToken;
+
+        PortClient(IBinder token) {
+            mToken = token;
+
+            try {
+                token.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                close();
+            }
+        }
+
+        abstract void close();
+
+        @Override
+        public void binderDied() {
+            close();
+        }
+    }
+
+    private class InputPortClient extends PortClient {
+        private final MidiOutputPort mOutputPort;
+
+        InputPortClient(IBinder token, MidiOutputPort outputPort) {
+            super(token);
+            mOutputPort = outputPort;
+        }
+
+        @Override
+        void close() {
+            mToken.unlinkToDeath(this, 0);
+            synchronized (mInputPortOutputPorts) {
+                int portNumber = mOutputPort.getPortNumber();
+                mInputPortOutputPorts[portNumber] = null;
+                mInputPortOpen[portNumber] = false;
+                updateDeviceStatus();
+            }
+            IoUtils.closeQuietly(mOutputPort);
+        }
+    }
+
+    private class OutputPortClient extends PortClient {
+        private final MidiInputPort mInputPort;
+
+        OutputPortClient(IBinder token, MidiInputPort inputPort) {
+            super(token);
+            mInputPort = inputPort;
+        }
+
+        @Override
+        void close() {
+            mToken.unlinkToDeath(this, 0);
+            int portNumber = mInputPort.getPortNumber();
+            MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber];
+            synchronized (dispatcher) {
+                dispatcher.getSender().disconnect(mInputPort);
+                int openCount = dispatcher.getReceiverCount();
+                mOutputPortOpenCount[portNumber] = openCount;
+                updateDeviceStatus();
+           }
+
+            mInputPorts.remove(mInputPort);
+            IoUtils.closeQuietly(mInputPort);
+        }
+    }
+
+    private final HashMap<IBinder, PortClient> mPortClients = new HashMap<IBinder, PortClient>();
+
+    // Binder interface stub for receiving connection requests from clients
+    private final IMidiDeviceServer mServer = new IMidiDeviceServer.Stub() {
+
+        @Override
+        public ParcelFileDescriptor openInputPort(IBinder token, int portNumber) {
+            if (mDeviceInfo.isPrivate()) {
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException("Can't access private device from different UID");
+                }
+            }
+
+            if (portNumber < 0 || portNumber >= mInputPortCount) {
+                Log.e(TAG, "portNumber out of range in openInputPort: " + portNumber);
+                return null;
+            }
+
+            synchronized (mInputPortOutputPorts) {
+                if (mInputPortOutputPorts[portNumber] != null) {
+                    Log.d(TAG, "port " + portNumber + " already open");
+                    return null;
+                }
+
+                try {
+                    ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
+                                                        OsConstants.SOCK_SEQPACKET);
+                    MidiOutputPort outputPort = new MidiOutputPort(pair[0], portNumber);
+                    mInputPortOutputPorts[portNumber] = outputPort;
+                    outputPort.connect(mInputPortReceivers[portNumber]);
+                    InputPortClient client = new InputPortClient(token, outputPort);
+                    synchronized (mPortClients) {
+                        mPortClients.put(token, client);
+                    }
+                    mInputPortOpen[portNumber] = true;
+                    updateDeviceStatus();
+                    return pair[1];
+                } catch (IOException e) {
+                    Log.e(TAG, "unable to create ParcelFileDescriptors in openInputPort");
+                    return null;
+                }
+            }
+        }
+
+        @Override
+        public ParcelFileDescriptor openOutputPort(IBinder token, int portNumber) {
+            if (mDeviceInfo.isPrivate()) {
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException("Can't access private device from different UID");
+                }
+            }
+
+            if (portNumber < 0 || portNumber >= mOutputPortCount) {
+                Log.e(TAG, "portNumber out of range in openOutputPort: " + portNumber);
+                return null;
+            }
+
+            try {
+                ParcelFileDescriptor[] pair = ParcelFileDescriptor.createSocketPair(
+                                                    OsConstants.SOCK_SEQPACKET);
+                MidiInputPort inputPort = new MidiInputPort(pair[0], portNumber);
+                MidiDispatcher dispatcher = mOutputPortDispatchers[portNumber];
+                synchronized (dispatcher) {
+                    dispatcher.getSender().connect(inputPort);
+                    int openCount = dispatcher.getReceiverCount();
+                    mOutputPortOpenCount[portNumber] = openCount;
+                    updateDeviceStatus();
+                }
+
+                mInputPorts.add(inputPort);
+                OutputPortClient client = new OutputPortClient(token, inputPort);
+                synchronized (mPortClients) {
+                    mPortClients.put(token, client);
+                }
+                return pair[1];
+            } catch (IOException e) {
+                Log.e(TAG, "unable to create ParcelFileDescriptors in openOutputPort");
+                return null;
+            }
+        }
+
+        @Override
+        public void closePort(IBinder token) {
+            synchronized (mPortClients) {
+                PortClient client = mPortClients.remove(token);
+                if (client != null) {
+                    client.close();
+                }
+            }
+        }
+
+        @Override
+        public void connectPorts(IBinder token, ParcelFileDescriptor pfd,
+                int outputPortNumber) {
+            MidiInputPort inputPort = new MidiInputPort(pfd, outputPortNumber);
+            mOutputPortDispatchers[outputPortNumber].getSender().connect(inputPort);
+            mInputPorts.add(inputPort);
+            OutputPortClient client = new OutputPortClient(token, inputPort);
+            synchronized (mPortClients) {
+                mPortClients.put(token, client);
+            }
+        }
+    };
+
+    /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
+            int numOutputPorts, Callback callback) {
+        mMidiManager = midiManager;
+        mInputPortReceivers = inputPortReceivers;
+        mInputPortCount = inputPortReceivers.length;
+        mOutputPortCount = numOutputPorts;
+        mCallback = callback;
+
+        mInputPortOutputPorts = new MidiOutputPort[mInputPortCount];
+
+        mOutputPortDispatchers = new MidiDispatcher[numOutputPorts];
+        for (int i = 0; i < numOutputPorts; i++) {
+            mOutputPortDispatchers[i] = new MidiDispatcher();
+        }
+
+        mInputPortOpen = new boolean[mInputPortCount];
+        mOutputPortOpenCount = new int[numOutputPorts];
+
+        mGuard.open("close");
+    }
+
+    /* package */ IMidiDeviceServer getBinderInterface() {
+        return mServer;
+    }
+
+    /* package */ void setDeviceInfo(MidiDeviceInfo deviceInfo) {
+        if (mDeviceInfo != null) {
+            throw new IllegalStateException("setDeviceInfo should only be called once");
+        }
+        mDeviceInfo = deviceInfo;
+    }
+
+    private void updateDeviceStatus() {
+        // clear calling identity, since we may be in a Binder call from one of our clients
+        long identityToken = Binder.clearCallingIdentity();
+
+        MidiDeviceStatus status = new MidiDeviceStatus(mDeviceInfo, mInputPortOpen,
+                mOutputPortOpenCount);
+        if (mCallback != null) {
+            mCallback.onDeviceStatusChanged(this, status);
+        }
+        try {
+            mMidiManager.setDeviceStatus(mDeviceStatusToken, status);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in updateDeviceStatus");
+        } finally {
+            Binder.restoreCallingIdentity(identityToken);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (mGuard) {
+            if (mIsClosed) return;
+            mGuard.close();
+
+            for (int i = 0; i < mInputPortCount; i++) {
+                MidiOutputPort outputPort = mInputPortOutputPorts[i];
+                if (outputPort != null) {
+                    IoUtils.closeQuietly(outputPort);
+                    mInputPortOutputPorts[i] = null;
+                }
+            }
+            for (MidiInputPort inputPort : mInputPorts) {
+                IoUtils.closeQuietly(inputPort);
+            }
+            mInputPorts.clear();
+            try {
+                mMidiManager.unregisterDeviceServer(mServer);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in unregisterDeviceServer");
+            }
+            mIsClosed = true;
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Returns an array of {@link MidiReceiver} for the device's output ports.
+     * Clients can use these receivers to send data out the device's output ports.
+     * @return array of MidiReceivers
+     */
+    public MidiReceiver[] getOutputPortReceivers() {
+        MidiReceiver[] receivers = new MidiReceiver[mOutputPortCount];
+        System.arraycopy(mOutputPortDispatchers, 0, receivers, 0, mOutputPortCount);
+        return receivers;
+    }
+}
diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java
new file mode 100644
index 0000000..8b1de3e
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceService.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * A service that implements a virtual MIDI device.
+ * Subclasses must implement the {@link #onGetInputPortReceivers} method to provide a
+ * list of {@link MidiReceiver}s to receive data sent to the device's input ports.
+ * Similarly, subclasses can call {@link #getOutputPortReceivers} to fetch a list
+ * of {@link MidiReceiver}s for sending data out the output ports.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * an intent filter with the {@link #SERVICE_INTERFACE} action
+ * and meta-data to describe the virtual device.
+ For example:</p>
+ * <pre>
+ * &lt;service android:name=".VirtualDeviceService"
+ *          android:label="&#64;string/service_name">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.media.midi.MidiDeviceService" />
+ *     &lt;/intent-filter>
+ *           &lt;meta-data android:name="android.media.midi.MidiDeviceService"
+                android:resource="@xml/device_info" />
+ * &lt;/service></pre>
+ */
+abstract public class MidiDeviceService extends Service {
+    private static final String TAG = "MidiDeviceService";
+
+    public static final String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
+
+    private IMidiManager mMidiManager;
+    private MidiDeviceServer mServer;
+    private MidiDeviceInfo mDeviceInfo;
+
+    private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
+        @Override
+        public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
+            MidiDeviceService.this.onDeviceStatusChanged(status);
+        }
+    };
+
+    @Override
+    public void onCreate() {
+        mMidiManager = IMidiManager.Stub.asInterface(
+                    ServiceManager.getService(Context.MIDI_SERVICE));
+        MidiDeviceServer server;
+        try {
+            MidiDeviceInfo deviceInfo = mMidiManager.getServiceDeviceInfo(getPackageName(),
+                    this.getClass().getName());
+            if (deviceInfo == null) {
+                Log.e(TAG, "Could not find MidiDeviceInfo for MidiDeviceService " + this);
+                return;
+            }
+            mDeviceInfo = deviceInfo;
+            MidiReceiver[] inputPortReceivers = onGetInputPortReceivers();
+            if (inputPortReceivers == null) {
+                inputPortReceivers = new MidiReceiver[0];
+            }
+            server = new MidiDeviceServer(mMidiManager, inputPortReceivers,
+                    deviceInfo.getOutputPortCount(), mCallback);
+            server.setDeviceInfo(deviceInfo);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo");
+            server = null;
+        }
+        mServer = server;
+   }
+
+    /**
+     * Returns an array of {@link MidiReceiver} for the device's input ports.
+     * Subclasses must override this to provide the receivers which will receive
+     * data sent to the device's input ports. An empty array or null should be returned if
+     * the device has no input ports.
+     * @return array of MidiReceivers
+     */
+    abstract public MidiReceiver[] onGetInputPortReceivers();
+
+    /**
+     * Returns an array of {@link MidiReceiver} for the device's output ports.
+     * These can be used to send data out the device's output ports.
+     * @return array of MidiReceivers
+     */
+    public final MidiReceiver[] getOutputPortReceivers() {
+        if (mServer == null) {
+            return null;
+        } else {
+            return mServer.getOutputPortReceivers();
+        }
+    }
+
+    /**
+     * returns the {@link MidiDeviceInfo} instance for this service
+     * @return our MidiDeviceInfo
+     */
+    public final MidiDeviceInfo getDeviceInfo() {
+        return mDeviceInfo;
+    }
+
+    /**
+     * Called to notify when an our {@link MidiDeviceStatus} has changed
+     * @param status the number of the port that was opened
+     */
+    public void onDeviceStatusChanged(MidiDeviceStatus status) {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction()) && mServer != null) {
+             return mServer.getBinderInterface().asBinder();
+        } else {
+             return null;
+       }
+    }
+}
diff --git a/media/java/android/media/midi/MidiDeviceStatus.aidl b/media/java/android/media/midi/MidiDeviceStatus.aidl
new file mode 100644
index 0000000..1a848c0
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+parcelable MidiDeviceStatus;
diff --git a/media/java/android/media/midi/MidiDeviceStatus.java b/media/java/android/media/midi/MidiDeviceStatus.java
new file mode 100644
index 0000000..7522dcf
--- /dev/null
+++ b/media/java/android/media/midi/MidiDeviceStatus.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This is an immutable class that describes the current status of a MIDI device's ports.
+ */
+public final class MidiDeviceStatus implements Parcelable {
+
+    private static final String TAG = "MidiDeviceStatus";
+
+    private final MidiDeviceInfo mDeviceInfo;
+    // true if input ports are open
+    private final boolean mInputPortOpen[];
+    // open counts for output ports
+    private final int mOutputPortOpenCount[];
+
+    /**
+     * @hide
+     */
+    public MidiDeviceStatus(MidiDeviceInfo deviceInfo, boolean inputPortOpen[],
+            int outputPortOpenCount[]) {
+        // MidiDeviceInfo is immutable so we can share references
+        mDeviceInfo = deviceInfo;
+
+        // make copies of the arrays
+        mInputPortOpen = new boolean[inputPortOpen.length];
+        System.arraycopy(inputPortOpen, 0, mInputPortOpen, 0, inputPortOpen.length);
+        mOutputPortOpenCount = new int[outputPortOpenCount.length];
+        System.arraycopy(outputPortOpenCount, 0, mOutputPortOpenCount, 0,
+                outputPortOpenCount.length);
+    }
+
+    /**
+     * Creates a MidiDeviceStatus with zero for all port open counts
+     * @hide
+     */
+    public MidiDeviceStatus(MidiDeviceInfo deviceInfo) {
+        mDeviceInfo = deviceInfo;
+        mInputPortOpen = new boolean[deviceInfo.getInputPortCount()];
+        mOutputPortOpenCount = new int[deviceInfo.getOutputPortCount()];
+    }
+
+    /**
+     * Returns the {@link MidiDeviceInfo} of the device.
+     *
+     * @return the device info
+     */
+    public MidiDeviceInfo getDeviceInfo() {
+        return mDeviceInfo;
+    }
+
+    /**
+     * Returns true if an input port is open.
+     *
+     * @param portNumber the input port's port number
+     * @return input port open status
+     */
+    public boolean isInputPortOpen(int portNumber) {
+        return mInputPortOpen[portNumber];
+    }
+
+    /**
+     * Returns the open count for an output port.
+     *
+     * @param portNumber the output port's port number
+     * @return output port open count
+     */
+    public int getOutputPortOpenCount(int portNumber) {
+        return mOutputPortOpenCount[portNumber];
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(mDeviceInfo.toString());
+        int inputPortCount = mDeviceInfo.getInputPortCount();
+        int outputPortCount = mDeviceInfo.getOutputPortCount();
+        builder.append(" mInputPortOpen=[");
+        for (int i = 0; i < inputPortCount; i++) {
+            builder.append(mInputPortOpen[i]);
+            if (i < inputPortCount -1) {
+                builder.append(",");
+            }
+        }
+        builder.append("] mOutputPortOpenCount=[");
+        for (int i = 0; i < outputPortCount; i++) {
+            builder.append(mOutputPortOpenCount[i]);
+            if (i < outputPortCount -1) {
+                builder.append(",");
+            }
+        }
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public static final Parcelable.Creator<MidiDeviceStatus> CREATOR =
+        new Parcelable.Creator<MidiDeviceStatus>() {
+        public MidiDeviceStatus createFromParcel(Parcel in) {
+            ClassLoader classLoader = MidiDeviceInfo.class.getClassLoader();
+            MidiDeviceInfo deviceInfo = in.readParcelable(classLoader);
+            boolean[] inputPortOpen = in.createBooleanArray();
+            int[] outputPortOpenCount = in.createIntArray();
+            return new MidiDeviceStatus(deviceInfo, inputPortOpen, outputPortOpenCount);
+        }
+
+        public MidiDeviceStatus[] newArray(int size) {
+            return new MidiDeviceStatus[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeParcelable(mDeviceInfo, flags);
+        parcel.writeBooleanArray(mInputPortOpen);
+        parcel.writeIntArray(mOutputPortOpenCount);
+   }
+}
diff --git a/media/java/android/media/midi/MidiDispatcher.java b/media/java/android/media/midi/MidiDispatcher.java
new file mode 100644
index 0000000..0868346
--- /dev/null
+++ b/media/java/android/media/midi/MidiDispatcher.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.midi;
+
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Utility class for dispatching MIDI data to a list of {@link MidiReceiver}s.
+ * This class subclasses {@link MidiReceiver} and dispatches any data it receives
+ * to its receiver list. Any receivers that throw an exception upon receiving data will
+ * be automatically removed from the receiver list, but no IOException will be returned
+ * from the dispatcher's {@link #onReceive} in that case.
+ *
+ * @hide
+ */
+public final class MidiDispatcher extends MidiReceiver {
+
+    private final CopyOnWriteArrayList<MidiReceiver> mReceivers
+            = new CopyOnWriteArrayList<MidiReceiver>();
+
+    private final MidiSender mSender = new MidiSender() {
+        /**
+         * Called to connect a {@link MidiReceiver} to the sender
+         *
+         * @param receiver the receiver to connect
+         */
+        public void connect(MidiReceiver receiver) {
+            mReceivers.add(receiver);
+        }
+
+        /**
+         * Called to disconnect a {@link MidiReceiver} from the sender
+         *
+         * @param receiver the receiver to disconnect
+         */
+        public void disconnect(MidiReceiver receiver) {
+            mReceivers.remove(receiver);
+        }
+    };
+
+    /**
+     * Returns the number of {@link MidiReceiver}s this dispatcher contains.
+     * @return the number of receivers
+     */
+    public int getReceiverCount() {
+        return mReceivers.size();
+    }
+
+    /**
+     * Returns a {@link MidiSender} which is used to add and remove {@link MidiReceiver}s
+     * to the dispatcher's receiver list.
+     * @return the dispatcher's MidiSender
+     */
+    public MidiSender getSender() {
+        return mSender;
+    }
+
+    @Override
+    public void onReceive(byte[] msg, int offset, int count, long timestamp) throws IOException {
+       for (MidiReceiver receiver : mReceivers) {
+            try {
+                receiver.sendWithTimestamp(msg, offset, count, timestamp);
+            } catch (IOException e) {
+                // if the receiver fails we remove the receiver but do not propagate the exception
+                mReceivers.remove(receiver);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
new file mode 100644
index 0000000..1d3b37a
--- /dev/null
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -0,0 +1,146 @@
+/*
+ * 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.midi;
+
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This class is used for sending data to a port on a MIDI device
+ */
+public final class MidiInputPort extends MidiReceiver implements Closeable {
+    private static final String TAG = "MidiInputPort";
+
+    private IMidiDeviceServer mDeviceServer;
+    private final IBinder mToken;
+    private final int mPortNumber;
+    private ParcelFileDescriptor mParcelFileDescriptor;
+    private FileOutputStream mOutputStream;
+
+    private final CloseGuard mGuard = CloseGuard.get();
+    private boolean mIsClosed;
+
+    // buffer to use for sending data out our output stream
+    private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
+
+    /* package */ MidiInputPort(IMidiDeviceServer server, IBinder token,
+            ParcelFileDescriptor pfd, int portNumber) {
+        mDeviceServer = server;
+        mToken = token;
+        mParcelFileDescriptor = pfd;
+        mPortNumber = portNumber;
+        mOutputStream = new FileOutputStream(pfd.getFileDescriptor());
+        mGuard.open("close");
+    }
+
+    /* package */ MidiInputPort(ParcelFileDescriptor pfd, int portNumber) {
+        this(null, null, pfd, portNumber);
+    }
+
+    /**
+     * Returns the port number of this port
+     *
+     * @return the port's port number
+     */
+    public final int getPortNumber() {
+        return mPortNumber;
+    }
+
+    @Override
+    public void onReceive(byte[] msg, int offset, int count, long timestamp) throws IOException {
+        if (offset < 0 || count < 0 || offset + count > msg.length) {
+            throw new IllegalArgumentException("offset or count out of range");
+        }
+        if (count > MidiPortImpl.MAX_PACKET_DATA_SIZE) {
+            throw new IllegalArgumentException("count exceeds max message size");
+        }
+
+        synchronized (mBuffer) {
+            if (mOutputStream == null) {
+                throw new IOException("MidiInputPort is closed");
+            }
+            int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer);
+            mOutputStream.write(mBuffer, 0, length);
+        }
+    }
+
+    // used by MidiDevice.connectInputPort() to connect our socket directly to another device
+    /* package */ ParcelFileDescriptor claimFileDescriptor() {
+        synchronized (mBuffer) {
+            ParcelFileDescriptor pfd = mParcelFileDescriptor;
+            if (pfd != null) {
+                IoUtils.closeQuietly(mOutputStream);
+                mParcelFileDescriptor = null;
+                mOutputStream = null;
+            }
+            return pfd;
+        }
+    }
+
+    @Override
+    public int getMaxMessageSize() {
+        return MidiPortImpl.MAX_PACKET_DATA_SIZE;
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (mGuard) {
+            if (mIsClosed) return;
+            mGuard.close();
+            synchronized (mBuffer) {
+                if (mParcelFileDescriptor != null) {
+                    mParcelFileDescriptor.close();
+                    mParcelFileDescriptor = null;
+                }
+                if (mOutputStream != null) {
+                    mOutputStream.close();
+                    mOutputStream = null;
+                }
+            }
+            if (mDeviceServer != null) {
+                try {
+                    mDeviceServer.closePort(mToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in MidiInputPort.close()");
+                }
+            }
+            mIsClosed = true;
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            // not safe to make binder calls from finalize()
+            mDeviceServer = null;
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
new file mode 100644
index 0000000..1b98ca5
--- /dev/null
+++ b/media/java/android/media/midi/MidiManager.java
@@ -0,0 +1,299 @@
+/*
+ * 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.midi;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * This class is the public application interface to the MIDI service.
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
+ *
+ * {@samplecode
+ * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);}
+ *
+ * CANDIDATE FOR PUBLIC API
+ * @hide
+ */
+public final class MidiManager {
+    private static final String TAG = "MidiManager";
+
+    private final Context mContext;
+    private final IMidiManager mService;
+    private final IBinder mToken = new Binder();
+
+    private HashMap<DeviceCallback,DeviceListener> mDeviceListeners =
+        new HashMap<DeviceCallback,DeviceListener>();
+
+    // Binder stub for receiving device notifications from MidiService
+    private class DeviceListener extends IMidiDeviceListener.Stub {
+        private final DeviceCallback mCallback;
+        private final Handler mHandler;
+
+        public DeviceListener(DeviceCallback callback, Handler handler) {
+            mCallback = callback;
+            mHandler = handler;
+        }
+
+        @Override
+        public void onDeviceAdded(MidiDeviceInfo device) {
+            if (mHandler != null) {
+                final MidiDeviceInfo deviceF = device;
+                mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mCallback.onDeviceAdded(deviceF);
+                        }
+                    });
+            } else {
+                mCallback.onDeviceAdded(device);
+            }
+        }
+
+        @Override
+        public void onDeviceRemoved(MidiDeviceInfo device) {
+            if (mHandler != null) {
+                final MidiDeviceInfo deviceF = device;
+                mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mCallback.onDeviceRemoved(deviceF);
+                        }
+                    });
+            } else {
+                mCallback.onDeviceRemoved(device);
+            }
+        }
+
+        @Override
+        public void onDeviceStatusChanged(MidiDeviceStatus status) {
+            if (mHandler != null) {
+                final MidiDeviceStatus statusF = status;
+                mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mCallback.onDeviceStatusChanged(statusF);
+                        }
+                    });
+            } else {
+                mCallback.onDeviceStatusChanged(status);
+            }
+        }
+    }
+
+    /**
+     * Callback class used for clients to receive MIDI device added and removed notifications
+     */
+    public static class DeviceCallback {
+        /**
+         * Called to notify when a new MIDI device has been added
+         *
+         * @param device a {@link MidiDeviceInfo} for the newly added device
+         */
+        public void onDeviceAdded(MidiDeviceInfo device) {
+        }
+
+        /**
+         * Called to notify when a MIDI device has been removed
+         *
+         * @param device a {@link MidiDeviceInfo} for the removed device
+         */
+        public void onDeviceRemoved(MidiDeviceInfo device) {
+        }
+
+        /**
+         * Called to notify when the status of a MIDI device has changed
+         *
+         * @param device a {@link MidiDeviceStatus} for the changed device
+         */
+        public void onDeviceStatusChanged(MidiDeviceStatus status) {
+        }
+    }
+
+    /**
+     * Callback class used for receiving the results of {@link #openDevice}
+     */
+    abstract public static class DeviceOpenCallback {
+        /**
+         * Called to respond to a {@link #openDevice} request
+         *
+         * @param deviceInfo the {@link MidiDeviceInfo} for the device to open
+         * @param device a {@link MidiDevice} for opened device, or null if opening failed
+         */
+        abstract public void onDeviceOpened(MidiDeviceInfo deviceInfo, MidiDevice device);
+    }
+
+    /**
+     * @hide
+     */
+    public MidiManager(Context context, IMidiManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Registers a callback to receive notifications when MIDI devices are added and removed.
+     *
+     * @param callback a {@link DeviceCallback} for MIDI device notifications
+     * @param handler The {@link android.os.Handler Handler} that will be used for delivering the
+     *                device notifications. If handler is null, then the thread used for the
+     *                callback is unspecified.
+     */
+    public void registerDeviceCallback(DeviceCallback callback, Handler handler) {
+        DeviceListener deviceListener = new DeviceListener(callback, handler);
+        try {
+            mService.registerListener(mToken, deviceListener);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerDeviceListener");
+            return;
+        }
+        mDeviceListeners.put(callback, deviceListener);
+    }
+
+    /**
+     * Unregisters a {@link DeviceCallback}.
+      *
+     * @param callback a {@link DeviceCallback} to unregister
+     */
+    public void unregisterDeviceCallback(DeviceCallback callback) {
+        DeviceListener deviceListener = mDeviceListeners.remove(callback);
+        if (deviceListener != null) {
+            try {
+                mService.unregisterListener(mToken, deviceListener);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in unregisterDeviceListener");
+            }
+        }
+    }
+
+    /**
+     * Gets the list of all connected MIDI devices.
+     *
+     * @return an array of all MIDI devices
+     */
+    public MidiDeviceInfo[] getDeviceList() {
+        try {
+           return mService.getDeviceList();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getDeviceList");
+            return new MidiDeviceInfo[0];
+        }
+    }
+
+    private void sendOpenDeviceResponse(final MidiDeviceInfo deviceInfo, final MidiDevice device,
+            final DeviceOpenCallback callback, Handler handler) {
+        if (handler != null) {
+            handler.post(new Runnable() {
+                    @Override public void run() {
+                        callback.onDeviceOpened(deviceInfo, device);
+                    }
+                });
+        } else {
+            callback.onDeviceOpened(deviceInfo, device);
+        }
+    }
+
+    /**
+     * Opens a MIDI device for reading and writing.
+     *
+     * @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open
+     * @param callback a {@link #DeviceOpenCallback} to be called to receive the result
+     * @param handler the {@link android.os.Handler Handler} that will be used for delivering
+     *                the result. If handler is null, then the thread used for the
+     *                callback is unspecified.
+     */
+    public void openDevice(MidiDeviceInfo deviceInfo, DeviceOpenCallback callback,
+            Handler handler) {
+        MidiDevice device = null;
+        try {
+            IMidiDeviceServer server = mService.openDevice(mToken, deviceInfo);
+            if (server == null) {
+                ServiceInfo serviceInfo = (ServiceInfo)deviceInfo.getProperties().getParcelable(
+                        MidiDeviceInfo.PROPERTY_SERVICE_INFO);
+                if (serviceInfo == null) {
+                    Log.e(TAG, "no ServiceInfo for " + deviceInfo);
+                } else {
+                    Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
+                    intent.setComponent(new ComponentName(serviceInfo.packageName,
+                            serviceInfo.name));
+                    final MidiDeviceInfo deviceInfoF = deviceInfo;
+                    final DeviceOpenCallback callbackF = callback;
+                    final Handler handlerF = handler;
+                    if (mContext.bindService(intent,
+                        new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder binder) {
+                                IMidiDeviceServer server =
+                                        IMidiDeviceServer.Stub.asInterface(binder);
+                                MidiDevice device = new MidiDevice(deviceInfoF, server, mContext, this);
+                                sendOpenDeviceResponse(deviceInfoF, device, callbackF, handlerF);
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(ComponentName name) {
+                                // FIXME - anything to do here?
+                            }
+                        },
+                        Context.BIND_AUTO_CREATE))
+                    {
+                        // return immediately to avoid calling sendOpenDeviceResponse below
+                        return;
+                    } else {
+                        Log.e(TAG, "Unable to bind  service: " + intent);
+                    }
+                }
+            } else {
+                device = new MidiDevice(deviceInfo, server);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in openDevice");
+        }
+        sendOpenDeviceResponse(deviceInfo, device, callback, handler);
+    }
+
+    /** @hide */
+    public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers,
+            int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
+            Bundle properties, int type, MidiDeviceServer.Callback callback) {
+        try {
+            MidiDeviceServer server = new MidiDeviceServer(mService, inputPortReceivers,
+                    numOutputPorts, callback);
+            MidiDeviceInfo deviceInfo = mService.registerDeviceServer(server.getBinderInterface(),
+                    inputPortReceivers.length, numOutputPorts, inputPortNames, outputPortNames,
+                    properties, type);
+            if (deviceInfo == null) {
+                Log.e(TAG, "registerVirtualDevice failed");
+                return null;
+            }
+            server.setDeviceInfo(deviceInfo);
+            return server;
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in createVirtualDevice");
+            return null;
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
new file mode 100644
index 0000000..b8ed36f
--- /dev/null
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -0,0 +1,141 @@
+/*
+ * 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.midi;
+
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * This class is used for receiving data from a port on a MIDI device
+ */
+public final class MidiOutputPort extends MidiSender implements Closeable {
+    private static final String TAG = "MidiOutputPort";
+
+    private IMidiDeviceServer mDeviceServer;
+    private final IBinder mToken;
+    private final int mPortNumber;
+    private final FileInputStream mInputStream;
+    private final MidiDispatcher mDispatcher = new MidiDispatcher();
+
+    private final CloseGuard mGuard = CloseGuard.get();
+    private boolean mIsClosed;
+
+    // This thread reads MIDI events from a socket and distributes them to the list of
+    // MidiReceivers attached to this device.
+    private final Thread mThread = new Thread() {
+        @Override
+        public void run() {
+            byte[] buffer = new byte[MidiPortImpl.MAX_PACKET_SIZE];
+
+            try {
+                while (true) {
+                    // read next event
+                    int count = mInputStream.read(buffer);
+                    if (count < 0) {
+                        break;
+                        // FIXME - inform receivers here?
+                    }
+
+                    int offset = MidiPortImpl.getMessageOffset(buffer, count);
+                    int size = MidiPortImpl.getMessageSize(buffer, count);
+                    long timestamp = MidiPortImpl.getMessageTimeStamp(buffer, count);
+
+                    // dispatch to all our receivers
+                    mDispatcher.sendWithTimestamp(buffer, offset, size, timestamp);
+                }
+            } catch (IOException e) {
+                // FIXME report I/O failure?
+                Log.e(TAG, "read failed");
+            } finally {
+                IoUtils.closeQuietly(mInputStream);
+            }
+        }
+    };
+
+    /* package */ MidiOutputPort(IMidiDeviceServer server, IBinder token,
+            ParcelFileDescriptor pfd, int portNumber) {
+        mDeviceServer = server;
+        mToken = token;
+        mPortNumber = portNumber;
+        mInputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        mThread.start();
+        mGuard.open("close");
+    }
+
+    /* package */ MidiOutputPort(ParcelFileDescriptor pfd, int portNumber) {
+        this(null, null, pfd, portNumber);
+    }
+
+    /**
+     * Returns the port number of this port
+     *
+     * @return the port's port number
+     */
+    public final int getPortNumber() {
+        return mPortNumber;
+    }
+
+    @Override
+    public void connect(MidiReceiver receiver) {
+        mDispatcher.getSender().connect(receiver);
+    }
+
+    @Override
+    public void disconnect(MidiReceiver receiver) {
+        mDispatcher.getSender().disconnect(receiver);
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (mGuard) {
+            if (mIsClosed) return;
+
+            mGuard.close();
+            mInputStream.close();
+            if (mDeviceServer != null) {
+                try {
+                    mDeviceServer.closePort(mToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in MidiOutputPort.close()");
+                }
+            }
+            mIsClosed = true;
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mGuard.warnIfOpen();
+            // not safe to make binder calls from finalize()
+            mDeviceServer = null;
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiPortImpl.java b/media/java/android/media/midi/MidiPortImpl.java
new file mode 100644
index 0000000..5795045
--- /dev/null
+++ b/media/java/android/media/midi/MidiPortImpl.java
@@ -0,0 +1,100 @@
+/*
+ * 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.midi;
+
+/**
+ * This class contains utilities for socket communication between a
+ * MidiInputPort and MidiOutputPort
+ */
+/* package */ class MidiPortImpl {
+    private static final String TAG = "MidiPort";
+
+    /**
+     * Maximum size of a packet that can pass through our ParcelFileDescriptor.
+     */
+    public static final int MAX_PACKET_SIZE = 1024;
+
+    /**
+     * size of message timestamp in bytes
+     */
+    private static final int TIMESTAMP_SIZE = 8;
+
+    /**
+     * Maximum amount of MIDI data that can be included in a packet
+     */
+    public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+
+    /**
+     * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
+     *
+     * message byte array contains variable length MIDI message.
+     * messageSize is size of variable length MIDI message
+     * timestamp is message timestamp to pack
+     * dest is buffer to pack into
+     * returns size of packed message
+     */
+    public static int packMessage(byte[] message, int offset, int size, long timestamp,
+            byte[] dest) {
+        if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
+            size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+        }
+        // message data goes first
+        System.arraycopy(message, offset, dest, 0, size);
+
+        // followed by timestamp
+        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+            dest[size++] = (byte)timestamp;
+            timestamp >>= 8;
+        }
+
+        return size;
+    }
+
+    /**
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * returns the offset of the MIDI message in packed buffer
+     */
+    public static int getMessageOffset(byte[] buffer, int bufferLength) {
+        // message is at the beginning
+        return 0;
+    }
+
+    /**
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * returns size of MIDI data in packed buffer
+     */
+    public static int getMessageSize(byte[] buffer, int bufferLength) {
+        // message length is total buffer length minus size of the timestamp
+        return bufferLength - TIMESTAMP_SIZE;
+    }
+
+    /**
+     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * unpacks timestamp from packed buffer
+     */
+    public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+        // timestamp is at end of the packet
+        int offset = bufferLength;
+        long timestamp = 0;
+
+        for (int i = 0; i < TIMESTAMP_SIZE; i++) {
+            int b = (int)buffer[--offset] & 0xFF;
+            timestamp = (timestamp << 8) | b;
+        }
+        return timestamp;
+    }
+}
diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
new file mode 100644
index 0000000..6f4c266
--- /dev/null
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -0,0 +1,88 @@
+/*
+ * 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.midi;
+
+import java.io.IOException;
+
+/**
+ * Interface for sending and receiving data to and from a MIDI device.
+ */
+abstract public class MidiReceiver {
+    /**
+     * Called to pass MIDI data to the receiver.
+     * May fail if count exceeds {@link #getMaxMessageSize}.
+     *
+     * NOTE: the msg array parameter is only valid within the context of this call.
+     * The msg bytes should be copied by the receiver rather than retaining a reference
+     * to this parameter.
+     * Also, modifying the contents of the msg array parameter may result in other receivers
+     * in the same application receiving incorrect values in their {link #onReceive} method.
+     *
+     * @param msg a byte array containing the MIDI data
+     * @param offset the offset of the first byte of the data in the array to be processed
+     * @param count the number of bytes of MIDI data in the array to be processed
+     * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
+     * @throws IOException
+     */
+    abstract public void onReceive(byte[] msg, int offset, int count, long timestamp)
+            throws IOException;
+
+    /**
+     * Returns the maximum size of a message this receiver can receive.
+     * Defaults to {@link java.lang.Integer#MAX_VALUE} unless overridden.
+     * @return maximum message size
+     */
+    public int getMaxMessageSize() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Called to send MIDI data to the receiver
+     * Data will get split into multiple calls to {@link #onReceive} if count exceeds
+     * {@link #getMaxMessageSize}.
+     *
+     * @param msg a byte array containing the MIDI data
+     * @param offset the offset of the first byte of the data in the array to be sent
+     * @param count the number of bytes of MIDI data in the array to be sent
+     * @throws IOException
+     */
+    public void send(byte[] msg, int offset, int count) throws IOException {
+        sendWithTimestamp(msg, offset, count, System.nanoTime());
+    }
+
+    /**
+     * Called to send MIDI data to the receiver to be handled at a specified time in the future
+     * Data will get split into multiple calls to {@link #onReceive} if count exceeds
+     * {@link #getMaxMessageSize}.
+     *
+     * @param msg a byte array containing the MIDI data
+     * @param offset the offset of the first byte of the data in the array to be sent
+     * @param count the number of bytes of MIDI data in the array to be sent
+     * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
+     * @throws IOException
+     */
+    public void sendWithTimestamp(byte[] msg, int offset, int count, long timestamp)
+            throws IOException {
+        int messageSize = getMaxMessageSize();
+        while (count > 0) {
+            int length = (count > messageSize ? messageSize : count);
+            onReceive(msg, offset, length, timestamp);
+            offset += length;
+            count -= length;
+        }
+    }
+}
diff --git a/media/java/android/media/midi/MidiSender.java b/media/java/android/media/midi/MidiSender.java
new file mode 100644
index 0000000..f64fc3c
--- /dev/null
+++ b/media/java/android/media/midi/MidiSender.java
@@ -0,0 +1,37 @@
+/*
+ * 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.midi;
+
+/**
+ * Interface provided by a device to allow attaching
+ * MidiReceivers to a MIDI device.
+ */
+abstract public class MidiSender {
+    /**
+     * Called to connect a {@link MidiReceiver} to the sender
+     *
+     * @param receiver the receiver to connect
+     */
+    abstract public void connect(MidiReceiver receiver);
+
+    /**
+     * Called to disconnect a {@link MidiReceiver} from the sender
+     *
+     * @param receiver the receiver to disconnect
+     */
+    abstract public void disconnect(MidiReceiver receiver);
+}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index a6bde1d..e757f09 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,7 +25,6 @@
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionCallback;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index a1cfc35..f4a548b 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.projection.IMediaProjection;
-import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
diff --git a/media/java/android/media/routing/IMediaRouteClientCallback.aidl b/media/java/android/media/routing/IMediaRouteClientCallback.aidl
new file mode 100644
index 0000000..d90ea3b
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouteClientCallback.aidl
@@ -0,0 +1,41 @@
+/* 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.routing;
+
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.ParcelableConnectionInfo;
+import android.media.routing.ParcelableDestinationInfo;
+import android.media.routing.ParcelableRouteInfo;
+import android.os.IBinder;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IMediaRouteClientCallback {
+    void onDestinationFound(int seq, in ParcelableDestinationInfo destination,
+            in ParcelableRouteInfo[] routes);
+
+    void onDestinationLost(int seq, String id);
+
+    void onDiscoveryFailed(int seq, int error, in CharSequence message, in Bundle extras);
+
+    void onConnected(int seq, in ParcelableConnectionInfo connection);
+
+    void onDisconnected(int seq);
+
+    void onConnectionFailed(int seq, int error, in CharSequence message, in Bundle extras);
+}
diff --git a/media/java/android/media/routing/IMediaRouteService.aidl b/media/java/android/media/routing/IMediaRouteService.aidl
new file mode 100644
index 0000000..493ab6d
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouteService.aidl
@@ -0,0 +1,46 @@
+/* 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.routing;
+
+import android.media.routing.IMediaRouteClientCallback;
+import android.media.routing.MediaRouteSelector;
+import android.os.Bundle;
+
+/**
+ * Interface to an app's MediaRouteService.
+ * @hide
+ */
+oneway interface IMediaRouteService {
+    void registerClient(int clientUid, String clientPackageName,
+            in IMediaRouteClientCallback callback);
+
+    void unregisterClient(in IMediaRouteClientCallback callback);
+
+    void startDiscovery(in IMediaRouteClientCallback callback, int seq,
+            in List<MediaRouteSelector> selectors, int flags);
+
+    void stopDiscovery(in IMediaRouteClientCallback callback);
+
+    void connect(in IMediaRouteClientCallback callback, int seq,
+            String destinationId, String routeId, int flags, in Bundle extras);
+
+    void disconnect(in IMediaRouteClientCallback callback);
+
+    void pauseStream(in IMediaRouteClientCallback callback);
+
+    void resumeStream(in IMediaRouteClientCallback callback);
+}
+
diff --git a/media/java/android/media/routing/IMediaRouter.aidl b/media/java/android/media/routing/IMediaRouter.aidl
new file mode 100644
index 0000000..0abb258
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouter.aidl
@@ -0,0 +1,22 @@
+/* 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.routing;
+
+/** @hide */
+interface IMediaRouter {
+
+}
+
diff --git a/media/java/android/media/routing/IMediaRouterDelegate.aidl b/media/java/android/media/routing/IMediaRouterDelegate.aidl
new file mode 100644
index 0000000..35f84c8
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouterDelegate.aidl
@@ -0,0 +1,22 @@
+/* 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.routing;
+
+/** @hide */
+interface IMediaRouterDelegate {
+
+}
+
diff --git a/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl b/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl
new file mode 100644
index 0000000..173ae55
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouterRoutingCallback.aidl
@@ -0,0 +1,22 @@
+/* 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.routing;
+
+/** @hide */
+interface IMediaRouterRoutingCallback {
+
+}
+
diff --git a/media/java/android/media/routing/IMediaRouterStateCallback.aidl b/media/java/android/media/routing/IMediaRouterStateCallback.aidl
new file mode 100644
index 0000000..0299904
--- /dev/null
+++ b/media/java/android/media/routing/IMediaRouterStateCallback.aidl
@@ -0,0 +1,22 @@
+/* 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.routing;
+
+/** @hide */
+interface IMediaRouterStateCallback {
+
+}
+
diff --git a/media/java/android/media/routing/MediaRouteSelector.aidl b/media/java/android/media/routing/MediaRouteSelector.aidl
new file mode 100644
index 0000000..37bfa4a
--- /dev/null
+++ b/media/java/android/media/routing/MediaRouteSelector.aidl
@@ -0,0 +1,18 @@
+/* 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.media.routing;
+
+parcelable MediaRouteSelector;
diff --git a/media/java/android/media/routing/MediaRouteSelector.java b/media/java/android/media/routing/MediaRouteSelector.java
new file mode 100644
index 0000000..0bfc796
--- /dev/null
+++ b/media/java/android/media/routing/MediaRouteSelector.java
@@ -0,0 +1,356 @@
+/*
+ * 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.routing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.media.routing.MediaRouter.RouteFeatures;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A media route selector consists of a set of constraints that are used to select
+ * the routes to which an application would like to connect.  The constraints consist
+ * of a set of required or optional features and protocols.  The constraints may also
+ * require the use of a specific media route service package or additional characteristics
+ * that are described by a bundle of extra parameters.
+ * <p>
+ * The application will typically create several different selectors that express
+ * various combinations of characteristics that it would like to use together when
+ * it connects to a destination media device.  For each destination that is discovered,
+ * media route services will publish some number of routes and include information
+ * about which selector each route matches.  The application will then choose among
+ * these routes to determine which best satisfies its desired purpose and connect to it.
+ * </p>
+ */
+public final class MediaRouteSelector implements Parcelable {
+    private final int mRequiredFeatures;
+    private final int mOptionalFeatures;
+    private final List<String> mRequiredProtocols;
+    private final List<String> mOptionalProtocols;
+    private final String mServicePackageName;
+    private final Bundle mExtras;
+
+    MediaRouteSelector(int requiredFeatures, int optionalFeatures,
+            List<String> requiredProtocols, List<String> optionalProtocols,
+            String servicePackageName, Bundle extras) {
+        mRequiredFeatures = requiredFeatures;
+        mOptionalFeatures = optionalFeatures;
+        mRequiredProtocols = requiredProtocols;
+        mOptionalProtocols = optionalProtocols;
+        mServicePackageName = servicePackageName;
+        mExtras = extras;
+    }
+
+    /**
+     * Gets the set of required route features.
+     *
+     * @return A set of required route feature flags.
+     */
+    public @RouteFeatures int getRequiredFeatures() {
+        return mRequiredFeatures;
+    }
+
+    /**
+     * Gets the set of optional route features.
+     *
+     * @return A set of optional route feature flags.
+     */
+    public @RouteFeatures int getOptionalFeatures() {
+        return mOptionalFeatures;
+    }
+
+    /**
+     * Gets the list of route protocols that a route must support in order to be selected.
+     * <p>
+     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+     * for more information.
+     * </p>
+     *
+     * @return The list of fully qualified route protocol names.
+     */
+    public @NonNull List<String> getRequiredProtocols() {
+        return mRequiredProtocols;
+    }
+
+    /**
+     * Gets the list of optional route protocols that a client may use if they are available.
+     * <p>
+     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+     * for more information.
+     * </p>
+     *
+     * @return The list of optional fully qualified route protocol names.
+     */
+    public @NonNull List<String> getOptionalProtocols() {
+        return mOptionalProtocols;
+    }
+
+    /**
+     * Returns true if the selector includes a required or optional request for
+     * the specified protocol using its fully qualified class name.
+     * <p>
+     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+     * for more information.
+     * </p>
+     *
+     * @param clazz The protocol class.
+     * @return True if the protocol was requested.
+     */
+    public boolean containsProtocol(@NonNull Class<?> clazz) {
+        return containsProtocol(clazz.getName());
+    }
+
+    /**
+     * Returns true if the selector includes a required or optional request for
+     * the specified protocol.
+     * <p>
+     * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+     * for more information.
+     * </p>
+     *
+     * @param name The name of the protocol.
+     * @return True if the protocol was requested.
+     */
+    public boolean containsProtocol(@NonNull String name) {
+        return mRequiredProtocols.contains(name)
+                || mOptionalProtocols.contains(name);
+    }
+
+    /**
+     * Gets the package name of a specific media route service that this route selector
+     * requires.
+     *
+     * @return The required media route service package name, or null if none.
+     */
+    public @Nullable String getServicePackageName() {
+        return mServicePackageName;
+    }
+
+    /**
+     * Gets optional extras that may be used to select or configure routes for a
+     * particular purpose.  Some extras may be used by media route services to apply
+     * additional constraints or parameters for the routes to be discovered.
+     *
+     * @return The optional extras, or null if none.
+     */
+    public @Nullable Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public String toString() {
+        return "MediaRouteSelector{ "
+                + ", requiredFeatures=0x" + Integer.toHexString(mRequiredFeatures)
+                + ", optionalFeatures=0x" + Integer.toHexString(mOptionalFeatures)
+                + ", requiredProtocols=" + mRequiredProtocols
+                + ", optionalProtocols=" + mOptionalProtocols
+                + ", servicePackageName=" + mServicePackageName
+                + ", extras=" + mExtras + " }";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRequiredFeatures);
+        dest.writeInt(mOptionalFeatures);
+        dest.writeStringList(mRequiredProtocols);
+        dest.writeStringList(mOptionalProtocols);
+        dest.writeString(mServicePackageName);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Parcelable.Creator<MediaRouteSelector> CREATOR =
+            new Parcelable.Creator<MediaRouteSelector>() {
+        @Override
+        public MediaRouteSelector createFromParcel(Parcel source) {
+            int requiredFeatures = source.readInt();
+            int optionalFeatures = source.readInt();
+            ArrayList<String> requiredProtocols = new ArrayList<String>();
+            ArrayList<String> optionalProtocols = new ArrayList<String>();
+            source.readStringList(requiredProtocols);
+            source.readStringList(optionalProtocols);
+            return new MediaRouteSelector(requiredFeatures, optionalFeatures,
+                    requiredProtocols, optionalProtocols,
+                    source.readString(), source.readBundle());
+        }
+
+        @Override
+        public MediaRouteSelector[] newArray(int size) {
+            return new MediaRouteSelector[size];
+        }
+    };
+
+    /**
+     * Builder for {@link MediaRouteSelector} objects.
+     */
+    public static final class Builder {
+        private int mRequiredFeatures;
+        private int mOptionalFeatures;
+        private final ArrayList<String> mRequiredProtocols = new ArrayList<String>();
+        private final ArrayList<String> mOptionalProtocols = new ArrayList<String>();
+        private String mServicePackageName;
+        private Bundle mExtras;
+
+        /**
+         * Creates an initially empty selector builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the set of required route features.
+         *
+         * @param features A set of required route feature flags.
+         */
+        public @NonNull Builder setRequiredFeatures(@RouteFeatures int features) {
+            mRequiredFeatures = features;
+            return this;
+        }
+
+        /**
+         * Sets the set of optional route features.
+         *
+         * @param features A set of optional route feature flags.
+         */
+        public @NonNull Builder setOptionalFeatures(@RouteFeatures int features) {
+            mOptionalFeatures = features;
+            return this;
+        }
+
+        /**
+         * Adds a route protocol that a route must support in order to be selected
+         * using its fully qualified class name.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         *
+         * @param clazz The protocol class.
+         * @return this
+         */
+        public @NonNull Builder addRequiredProtocol(@NonNull Class<?> clazz) {
+            if (clazz == null) {
+                throw new IllegalArgumentException("clazz must not be null");
+            }
+            return addRequiredProtocol(clazz.getName());
+        }
+
+        /**
+         * Adds a route protocol that a route must support in order to be selected.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         *
+         * @param name The fully qualified name of the required protocol.
+         * @return this
+         */
+        public @NonNull Builder addRequiredProtocol(@NonNull String name) {
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name must not be null or empty");
+            }
+            mRequiredProtocols.add(name);
+            return this;
+        }
+
+        /**
+         * Adds an optional route protocol that a client may use if available
+         * using its fully qualified class name.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         *
+         * @param clazz The protocol class.
+         * @return this
+         */
+        public @NonNull Builder addOptionalProtocol(@NonNull Class<?> clazz) {
+            if (clazz == null) {
+                throw new IllegalArgumentException("clazz must not be null");
+            }
+            return addOptionalProtocol(clazz.getName());
+        }
+
+        /**
+         * Adds an optional route protocol that a client may use if available.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         *
+         * @param name The fully qualified name of the optional protocol.
+         * @return this
+         */
+        public @NonNull Builder addOptionalProtocol(@NonNull String name) {
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name must not be null or empty");
+            }
+            mOptionalProtocols.add(name);
+            return this;
+        }
+
+        /**
+         * Sets the package name of the media route service to which this selector
+         * appertains.
+         * <p>
+         * If a package name is specified here then this selector will only be
+         * passed to media route services from that package.  This has the effect
+         * of restricting the set of matching routes to just those that are offered
+         * by that package.
+         * </p>
+         *
+         * @param packageName The required service package name, or null if none.
+         * @return this
+         */
+        public @NonNull Builder setServicePackageName(@Nullable String packageName) {
+            mServicePackageName = packageName;
+            return this;
+        }
+
+        /**
+         * Sets optional extras that may be used to select or configure routes for a
+         * particular purpose.  Some extras may be used by route services to specify
+         * additional constraints or parameters for the routes to be discovered.
+         *
+         * @param extras The optional extras, or null if none.
+         * @return this
+         */
+        public @NonNull Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds the {@link MediaRouteSelector} object.
+         *
+         * @return The new media route selector instance.
+         */
+        public @NonNull MediaRouteSelector build() {
+            return new MediaRouteSelector(mRequiredFeatures, mOptionalFeatures,
+                    mRequiredProtocols, mOptionalProtocols, mServicePackageName, mExtras);
+        }
+    }
+}
diff --git a/media/java/android/media/routing/MediaRouteService.java b/media/java/android/media/routing/MediaRouteService.java
new file mode 100644
index 0000000..4d5a8a9
--- /dev/null
+++ b/media/java/android/media/routing/MediaRouteService.java
@@ -0,0 +1,1023 @@
+/*
+ * 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.routing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.routing.MediaRouter.ConnectionError;
+import android.media.routing.MediaRouter.ConnectionInfo;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.DiscoveryError;
+import android.media.routing.MediaRouter.DiscoveryRequest;
+import android.media.routing.MediaRouter.RouteInfo;
+import android.media.routing.MediaRouter.ServiceMetadata;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Media route services implement strategies for discovering
+ * and establishing connections to media devices and their routes.  These services
+ * are also known as media route providers.
+ * <p>
+ * Each media route service subclass is responsible for enabling applications
+ * and the system to interact with media devices of some kind.
+ * For example, one particular media route service implementation might
+ * offer support for discovering nearby wireless display devices and streaming
+ * video contents to them; another media route service implementation might
+ * offer support for discovering nearby speakers and streaming media appliances
+ * and sending commands to play content on request.
+ * </p><p>
+ * Subclasses must override the {@link #onCreateClientSession} method to return
+ * a {@link ClientSession} object that implements the {@link ClientSession#onStartDiscovery},
+ * {@link ClientSession#onStopDiscovery}, and {@link ClientSession#onConnect} methods
+ * to allow clients to discover and connect to media devices.
+ * </p><p>
+ * This object is not thread-safe.  All callbacks are invoked on the main looper.
+ * </p>
+ *
+ * <h3>Clients</h3>
+ * <p>
+ * The clients of this API are media applications that would like to discover
+ * and connect to media devices.  The client may also be the system, such as
+ * when the user initiates display mirroring via the Cast Screen function.
+ * </p><p>
+ * There may be multiple client sessions active at the same time.  Each client
+ * session can request discovery and connect to routes independently of any
+ * other client.  It is the responsibility of the media route service to maintain
+ * separate state for each client session and to ensure that clients cannot interfere
+ * with one another in harmful ways.
+ * </p><p>
+ * Notwithstanding the requirement to support any number of concurrent client
+ * sessions, the media route service may impose constraints on how many clients
+ * can connect to the same media device in a particular mode at the same time.
+ * In some cases, media devices may support connections from an arbitrary number
+ * of clients simultaneously but often it may be necessary to ensure that only
+ * one client is in control.  When this happens, the media route service should
+ * report a connection error unless the connection request specifies that the
+ * client should take control of the media device (and forcibly disconnect other
+ * clients that may be using it).
+ * </p>
+ *
+ * <h3>Destinations</h3>
+ * <p>
+ * The media devices to which an application may send media content are referred
+ * to in the API as destinations.  Each destination therefore represents a single
+ * independent device such as a speaker or TV set.  Destinations are given meaningful
+ * names and descriptions to help the user associate them with devices in their
+ * environment.
+ * </p><p>
+ * Destinations may be local or remote and may be accessed through various means,
+ * often wirelessly.  The user may install media route services to enable
+ * media applications to connect to a variety of destinations with different
+ * capabilities.
+ * </p>
+ *
+ * <h3>Routes</h3>
+ * <p>
+ * Routes represent possible usages or means of reaching and interacting with
+ * a destination.  Since destinations may support many different features, they may
+ * each offer multiple routes for applications to choose from based on their needs.
+ * For example, one route might express the ability to stream locally rendered audio
+ * and video to the device; another route might express the ability to send a URL for
+ * the destination to download from the network and play all by itself.
+ * </p><p>
+ * Routes are discovered according to the set of capabilities that
+ * an application or the system is seeking to use at a particular time.  For example,
+ * if an application wants to stream music to a destination then it will ask the
+ * {@link MediaRouter} to find routes to destinations can stream music and ignore
+ * all other destinations that cannot.
+ * </p><p>
+ * In general, the application will inspect the set of routes that have been
+ * offered then connect to the most appropriate route for its desired purpose.
+ * </p>
+ *
+ * <h3>Discovery</h3>
+ * <p>
+ * Discovery is the process of finding destinations based on a description of the
+ * kinds of routes that an application or the system would like to use.
+ * </p><p>
+ * Discovery begins when {@link ClientSession#onStartDiscovery} is called and ends when
+ * {@link ClientSession#onStopDiscovery} is called.  There may be multiple simultaneous
+ * discovery requests in progress at the same time from different clients.  It is up to
+ * the media route service to perform these requests in parallel or multiplex them
+ * as required.
+ * </p><p>
+ * Media route services are <em>strongly encouraged</em> to use the information
+ * in the discovery request to optimize discovery and avoid redundant work.
+ * In the case where no media device supported by the media route service
+ * could possibly offer the requested capabilities, the
+ * {@link ClientSession#onStartDiscovery} method should return <code>false</code> to
+ * let the system know that it can unbind from the media route service and
+ * release its resources.
+ * </p>
+ *
+ * <h3>Settings</h3>
+ * <p>
+ * Many kinds of devices can be discovered on demand simply by scanning the local network
+ * or using wireless protocols such as Bluetooth to find them.  However, in some cases
+ * it may be necessary for the user to manually configure destinations before they
+ * can be used (or to adjust settings later).  Actual user configuration of destinations
+ * is beyond the scope of this API but media route services may specify an activity
+ * in their manifest that the user can launch to perform these tasks.
+ * </p><p>
+ * Note that media route services that are installed from the store must be enabled
+ * by the user before they become available for applications to use.
+ * The {@link android.provider.Settings#ACTION_CAST_SETTINGS Settings.ACTION_CAST_SETTINGS}
+ * settings activity provides the ability for the user to configure media route services.
+ * </p>
+ *
+ * <h3>Manifest Declaration</h3>
+ * <p>
+ * Media route services must be declared in the manifest along with meta-data
+ * about the kinds of routes that they are capable of discovering.  The system
+ * uses this information to optimize the set of services to which it binds in
+ * order to satisfy a particular discovery request.
+ * </p><p>
+ * To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_MEDIA_ROUTE_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action.  You must
+ * also add meta-data to describe the kinds of routes that your service is capable
+ * of discovering.
+ * </p><p>
+ * For example:
+ * </p><pre>
+ * &lt;service android:name=".MediaRouteProvider"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.media.routing.MediaRouteService" />
+ *     &lt;/intent-filter>
+ *
+ *     TODO: INSERT METADATA DECLARATIONS HERE
+ *
+ * &lt;/service>
+ * </pre>
+ */
+public abstract class MediaRouteService extends Service {
+    private static final String TAG = "MediaRouteService";
+
+    private static final boolean DEBUG = true;
+
+    private final Handler mHandler;
+    private final BinderService mService;
+    private final ArrayMap<IBinder, ClientRecord> mClientRecords =
+            new ArrayMap<IBinder, ClientRecord>();
+
+    private ServiceMetadata mMetadata;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.media.routing.MediaRouteService";
+
+    /**
+     * Creates a media route service.
+     */
+    public MediaRouteService() {
+        mHandler = new Handler(true);
+        mService = new BinderService();
+    }
+
+    @Override
+    public @Nullable IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mService;
+        }
+        return null;
+    }
+
+    /**
+     * Creates a new client session on behalf of a client.
+     * <p>
+     * The implementation should return a {@link ClientSession} for the client
+     * to use.  The media route service must take care to manage the state of
+     * each client session independently from any others that might also be
+     * in use at the same time.
+     * </p>
+     *
+     * @param client Information about the client.
+     * @return The client session object, or null if the client is not allowed
+     * to interact with this media route service.
+     */
+    public abstract @Nullable ClientSession onCreateClientSession(@NonNull ClientInfo client);
+
+    /**
+     * Gets metadata about this service.
+     * <p>
+     * Use this method to obtain a {@link ServiceMetadata} object to provide when creating
+     * a {@link android.media.routing.MediaRouter.DestinationInfo.Builder}.
+     * </p>
+     *
+     * @return Metadata about this service.
+     */
+    public @NonNull ServiceMetadata getServiceMetadata() {
+        if (mMetadata == null) {
+            try {
+                mMetadata = new ServiceMetadata(this);
+            } catch (NameNotFoundException ex) {
+                Log.wtf(TAG, "Could not retrieve own service metadata!");
+            }
+        }
+        return mMetadata;
+    }
+
+    /**
+     * Enables a single client to access the functionality of the media route service.
+     */
+    public static abstract class ClientSession {
+        /**
+         * Starts discovery.
+         * <p>
+         * If the media route service is capable of discovering routes that satisfy
+         * the request then this method should start discovery and return true.
+         * Otherwise, this method should return false.  If false is returned,
+         * then the framework will not call {@link #onStopDiscovery} since discovery
+         * was never actually started.
+         * </p><p>
+         * There may already be other discovery requests in progress at the same time
+         * for other clients; the media route service must keep track of them all.
+         * </p>
+         *
+         * @param req The discovery request to start.
+         * @param callback A callback to receive discovery events related to this
+         * particular request.  The events that the service sends to this callback
+         * will be sent to the client that initiated the discovery request.
+         * @return True if discovery has started.  False if the media route service
+         * is unable to discover routes that satisfy the request.
+         */
+        public abstract boolean onStartDiscovery(@NonNull DiscoveryRequest req,
+                @NonNull DiscoveryCallback callback);
+
+        /**
+         * Stops discovery.
+         * <p>
+         * If {@link #onStartDiscovery} returned true, then this method will eventually
+         * be called when the framework no longer requires this discovery request
+         * to be performed.
+         * </p><p>
+         * There may still be other discovery requests in progress for other clients;
+         * they must keep working until they have each been stopped by their client.
+         * </p>
+         */
+        public abstract void onStopDiscovery();
+
+        /**
+         * Starts connecting to a route.
+         *
+         * @param req The connection request.
+         * @param callback A callback to receive events connection events related
+         * to this particular request.  The events that the service sends to this callback
+         * will be sent to the client that initiated the discovery request.
+         * @return True if the connection is in progress, or false if the client
+         * unable to connect to the requested route.
+         */
+        public abstract boolean onConnect(@NonNull ConnectionRequest req,
+                @NonNull ConnectionCallback callback);
+
+        /**
+         * Called when the client requests to disconnect from the route
+         * or abort a connection attempt in progress.
+         */
+        public abstract void onDisconnect();
+
+        /**
+         * Called when the client requests to pause streaming of content to
+         * live audio/video routes such as when it goes into the background.
+         * <p>
+         * The default implementation does nothing.
+         * </p>
+         */
+        public void onPauseStream() { }
+
+        /**
+         * Called when the application requests to resume streaming of content to
+         * live audio/video routes such as when it returns to the foreground.
+         * <p>
+         * The default implementation does nothing.
+         * </p>
+         */
+        public void onResumeStream() { }
+
+        /**
+         * Called when the client is releasing the session.
+         * <p>
+         * The framework automatically takes care of stopping discovery and
+         * terminating the connection politely before calling this method to release
+         * the session.
+         * </p><p>
+         * The default implementation does nothing.
+         * </p>
+         */
+        public void onRelease() { }
+    }
+
+    /**
+     * Provides events in response to a discovery request.
+     */
+    public final class DiscoveryCallback {
+        private final ClientRecord mRecord;
+
+        DiscoveryCallback(ClientRecord record) {
+            mRecord = record;
+        }
+
+        /**
+         * Called by the service when a destination is found that
+         * offers one or more routes that satisfy the discovery request.
+         * <p>
+         * This method should be called whenever the list of available routes
+         * at a destination changes or whenever the properties of the destination
+         * itself change.
+         * </p>
+         *
+         * @param destination The destination that was found.
+         * @param routes The list of that destination's routes that satisfy the
+         * discovery request.
+         */
+        public void onDestinationFound(final @NonNull DestinationInfo destination,
+                final @NonNull List<RouteInfo> routes) {
+            if (destination == null) {
+                throw new IllegalArgumentException("destination must not be null");
+            }
+            if (routes == null) {
+                throw new IllegalArgumentException("routes must not be null");
+            }
+            for (int i = 0; i < routes.size(); i++) {
+                if (routes.get(i).getDestination() != destination) {
+                    throw new IllegalArgumentException("routes must refer to the "
+                            + "destination");
+                }
+            }
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchDestinationFound(DiscoveryCallback.this,
+                            destination, routes);
+                }
+            });
+        }
+
+        /**
+         * Called by the service when a destination is no longer
+         * reachable or is no longer offering any routes that satisfy
+         * the discovery request.
+         *
+         * @param destination The destination that went away.
+         */
+        public void onDestinationLost(final @NonNull DestinationInfo destination) {
+            if (destination == null) {
+                throw new IllegalArgumentException("destination must not be null");
+            }
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchDestinationLost(DiscoveryCallback.this, destination);
+                }
+            });
+        }
+
+        /**
+         * Called by the service when a discovery has failed in a non-recoverable manner.
+         *
+         * @param error The error code: one of
+         * {@link MediaRouter#DISCOVERY_ERROR_UNKNOWN},
+         * {@link MediaRouter#DISCOVERY_ERROR_ABORTED},
+         * or {@link MediaRouter#DISCOVERY_ERROR_NO_CONNECTIVITY}.
+         * @param message The localized error message, or null if none.  This message
+         * may be shown to the user.
+         * @param extras Additional information about the error which a client
+         * may use, or null if none.
+         */
+        public void onDiscoveryFailed(final @DiscoveryError int error,
+                final @Nullable CharSequence message, final @Nullable Bundle extras) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchDiscoveryFailed(DiscoveryCallback.this,
+                            error, message, extras);
+                }
+            });
+        }
+    }
+
+    /**
+     * Provides events in response to a connection request.
+     */
+    public final class ConnectionCallback {
+        private final ClientRecord mRecord;
+
+        ConnectionCallback(ClientRecord record) {
+            mRecord = record;
+        }
+
+        /**
+         * Called by the service when the connection succeeds.
+         *
+         * @param connection Immutable information about the connection.
+         */
+        public void onConnected(final @NonNull ConnectionInfo connection) {
+            if (connection == null) {
+                throw new IllegalArgumentException("connection must not be null");
+            }
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchConnected(ConnectionCallback.this, connection);
+                }
+            });
+        }
+
+        /**
+         * Called by the service when the connection is terminated normally.
+         * <p>
+         * Abnormal termination is reported via {@link #onConnectionFailed}.
+         * </p>
+         */
+        public void onDisconnected() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchDisconnected(ConnectionCallback.this);
+                }
+            });
+        }
+
+        /**
+         * Called by the service when a connection attempt or connection in
+         * progress has failed in a non-recoverable manner.
+         *
+         * @param error The error code: one of
+         * {@link MediaRouter#CONNECTION_ERROR_ABORTED},
+         * {@link MediaRouter#CONNECTION_ERROR_UNAUTHORIZED},
+         * {@link MediaRouter#CONNECTION_ERROR_UNREACHABLE},
+         * {@link MediaRouter#CONNECTION_ERROR_BUSY},
+         * {@link MediaRouter#CONNECTION_ERROR_TIMEOUT},
+         * {@link MediaRouter#CONNECTION_ERROR_BROKEN},
+         * or {@link MediaRouter#CONNECTION_ERROR_BARGED}.
+         * @param message The localized error message, or null if none.  This message
+         * may be shown to the user.
+         * @param extras Additional information about the error which a client
+         * may use, or null if none.
+         */
+        public void onConnectionFailed(final @ConnectionError int error,
+                final @Nullable CharSequence message, final @Nullable Bundle extras) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mRecord.dispatchConnectionFailed(ConnectionCallback.this,
+                            error, message, extras);
+                }
+            });
+        }
+    }
+
+    /**
+     * Identifies a client of the media route service.
+     */
+    public static final class ClientInfo {
+        private final int mUid;
+        private final String mPackageName;
+
+        ClientInfo(int uid, String packageName) {
+            mUid = uid;
+            mPackageName = packageName;
+        }
+
+        /**
+         * Gets the UID of the client application.
+         */
+        public int getUid() {
+            return mUid;
+        }
+
+        /**
+         * Gets the package name of the client application.
+         */
+        public @NonNull String getPackageName() {
+            return mPackageName;
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "ClientInfo{ uid=" + mUid + ", package=" + mPackageName + " }";
+        }
+    }
+
+    private final class BinderService extends IMediaRouteService.Stub {
+        @Override
+        public void registerClient(final int clientUid, final String clientPackageName,
+                final IMediaRouteClientCallback callback) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientInfo client = new ClientInfo(clientUid, clientPackageName);
+                    if (DEBUG) {
+                        Log.d(TAG, "registerClient: client=" + client);
+                    }
+
+                    ClientSession session = onCreateClientSession(client);
+                    if (session == null) {
+                        // request refused by service
+                        Log.w(TAG, "Media route service refused to create session for client: "
+                                + "client=" + client);
+                        return;
+                    }
+
+                    ClientRecord record = new ClientRecord(callback, client, session);
+                    try {
+                        callback.asBinder().linkToDeath(record, 0);
+                    } catch (RemoteException ex) {
+                        // client died prematurely
+                        Log.w(TAG, "Client died prematurely while creating session: "
+                                + "client=" + client);
+                        record.release();
+                        return;
+                    }
+
+                    mClientRecords.put(callback.asBinder(), record);
+                }
+            });
+        }
+
+        @Override
+        public void unregisterClient(IMediaRouteClientCallback callback) {
+            unregisterClient(callback, false);
+        }
+
+        void unregisterClient(final IMediaRouteClientCallback callback,
+                final boolean died) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.remove(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "unregisterClient: client=" + record.getClientInfo()
+                                + ", died=" + died);
+                    }
+
+                    record.release();
+                    callback.asBinder().unlinkToDeath(record, 0);
+                }
+            });
+        }
+
+        @Override
+        public void startDiscovery(final IMediaRouteClientCallback callback,
+                final int seq, final List<MediaRouteSelector> selectors,
+                final int flags) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "startDiscovery: client=" + record.getClientInfo()
+                                + ", seq=" + seq + ", selectors=" + selectors
+                                + ", flags=0x" + Integer.toHexString(flags));
+                    }
+                    record.startDiscovery(seq, selectors, flags);
+                }
+            });
+        }
+
+        @Override
+        public void stopDiscovery(final IMediaRouteClientCallback callback) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "stopDiscovery: client=" + record.getClientInfo());
+                    }
+                    record.stopDiscovery();
+                }
+            });
+        }
+
+        @Override
+        public void connect(final IMediaRouteClientCallback callback,
+                final int seq, final String destinationId, final String routeId,
+                final int flags, final Bundle extras) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "connect: client=" + record.getClientInfo()
+                                + ", seq=" + seq + ", destinationId=" + destinationId
+                                + ", routeId=" + routeId
+                                + ", flags=0x" + Integer.toHexString(flags)
+                                + ", extras=" + extras);
+                    }
+                    record.connect(seq, destinationId, routeId, flags, extras);
+                }
+            });
+        }
+
+        @Override
+        public void disconnect(final IMediaRouteClientCallback callback) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "disconnect: client=" + record.getClientInfo());
+                    }
+                    record.disconnect();
+                }
+            });
+        }
+
+        @Override
+        public void pauseStream(final IMediaRouteClientCallback callback) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "pauseStream: client=" + record.getClientInfo());
+                    }
+                    record.pauseStream();
+                }
+            });
+        }
+
+        @Override
+        public void resumeStream(final IMediaRouteClientCallback callback) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    ClientRecord record = mClientRecords.get(callback.asBinder());
+                    if (record == null) {
+                        return; // spurious
+                    }
+
+                    if (DEBUG) {
+                        Log.d(TAG, "resumeStream: client=" + record.getClientInfo());
+                    }
+                    record.resumeStream();
+                }
+            });
+        }
+    }
+
+    // Must be accessed on handler
+    private final class ClientRecord implements IBinder.DeathRecipient {
+        private final IMediaRouteClientCallback mClientCallback;
+        private final ClientInfo mClient;
+        private final ClientSession mSession;
+
+        private int mDiscoverySeq;
+        private DiscoveryRequest mDiscoveryRequest;
+        private DiscoveryCallback mDiscoveryCallback;
+        private final ArrayMap<String, DestinationRecord> mDestinations =
+                new ArrayMap<String, DestinationRecord>();
+
+        private int mConnectionSeq;
+        private ConnectionRequest mConnectionRequest;
+        private ConnectionCallback mConnectionCallback;
+        private ConnectionInfo mConnection;
+        private boolean mConnectionPaused;
+
+        public ClientRecord(IMediaRouteClientCallback callback,
+                ClientInfo client, ClientSession session) {
+            mClientCallback = callback;
+            mClient = client;
+            mSession = session;
+        }
+
+        // Invoked on binder thread unlike all other methods in this class.
+        @Override
+        public void binderDied() {
+            mService.unregisterClient(mClientCallback, true);
+        }
+
+        public ClientInfo getClientInfo() {
+            return mClient;
+        }
+
+        public void release() {
+            stopDiscovery();
+            disconnect();
+        }
+
+        public void startDiscovery(int seq, List<MediaRouteSelector> selectors,
+                int flags) {
+            stopDiscovery();
+
+            mDiscoverySeq = seq;
+            mDiscoveryRequest = new DiscoveryRequest(selectors);
+            mDiscoveryRequest.setFlags(flags);
+            mDiscoveryCallback = new DiscoveryCallback(this);
+            boolean started = mSession.onStartDiscovery(mDiscoveryRequest, mDiscoveryCallback);
+            if (!started) {
+                dispatchDiscoveryFailed(mDiscoveryCallback,
+                        MediaRouter.DISCOVERY_ERROR_ABORTED, null, null);
+                clearDiscovery();
+            }
+        }
+
+        public void stopDiscovery() {
+            if (mDiscoveryRequest != null) {
+                mSession.onStopDiscovery();
+                clearDiscovery();
+            }
+        }
+
+        private void clearDiscovery() {
+            mDestinations.clear();
+            mDiscoveryRequest = null;
+            mDiscoveryCallback = null;
+        }
+
+        public void connect(int seq, String destinationId, String routeId,
+                int flags, Bundle extras) {
+            disconnect();
+
+            mConnectionSeq = seq;
+            mConnectionCallback = new ConnectionCallback(this);
+
+            DestinationRecord destinationRecord = mDestinations.get(destinationId);
+            if (destinationRecord == null) {
+                Log.w(TAG, "Aborting connection to route since no matching destination "
+                        + "was found in the list of known destinations: "
+                        + "destinationId=" + destinationId);
+                dispatchConnectionFailed(mConnectionCallback,
+                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
+                clearConnection();
+                return;
+            }
+
+            RouteInfo route = destinationRecord.getRoute(routeId);
+            if (route == null) {
+                Log.w(TAG, "Aborting connection to route since no matching route "
+                        + "was found in the list of known routes: "
+                        + "destination=" + destinationRecord.destination
+                        + ", routeId=" + routeId);
+                dispatchConnectionFailed(mConnectionCallback,
+                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
+                clearConnection();
+                return;
+            }
+
+            mConnectionRequest = new ConnectionRequest(route);
+            mConnectionRequest.setFlags(flags);
+            mConnectionRequest.setExtras(extras);
+            boolean started = mSession.onConnect(mConnectionRequest, mConnectionCallback);
+            if (!started) {
+                dispatchConnectionFailed(mConnectionCallback,
+                        MediaRouter.CONNECTION_ERROR_ABORTED, null, null);
+                clearConnection();
+            }
+        }
+
+        public void disconnect() {
+            if (mConnectionRequest != null) {
+                mSession.onDisconnect();
+                clearConnection();
+            }
+        }
+
+        private void clearConnection() {
+            mConnectionRequest = null;
+            mConnectionCallback = null;
+            if (mConnection != null) {
+                mConnection.close();
+                mConnection = null;
+            }
+            mConnectionPaused = false;
+        }
+
+        public void pauseStream() {
+            if (mConnectionRequest != null && !mConnectionPaused) {
+                mConnectionPaused = true;
+                mSession.onPauseStream();
+            }
+        }
+
+        public void resumeStream() {
+            if (mConnectionRequest != null && mConnectionPaused) {
+                mConnectionPaused = false;
+                mSession.onResumeStream();
+            }
+        }
+
+        public void dispatchDestinationFound(DiscoveryCallback callback,
+                DestinationInfo destination, List<RouteInfo> routes) {
+            if (callback == mDiscoveryCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "destinationFound: destination=" + destination
+                            + ", routes=" + routes);
+                }
+                mDestinations.put(destination.getId(),
+                        new DestinationRecord(destination, routes));
+
+                ParcelableDestinationInfo pdi = new ParcelableDestinationInfo();
+                pdi.id = destination.getId();
+                pdi.name = destination.getName();
+                pdi.description = destination.getDescription();
+                pdi.iconResourceId = destination.getIconResourceId();
+                pdi.extras = destination.getExtras();
+                ArrayList<ParcelableRouteInfo> pris = new ArrayList<ParcelableRouteInfo>();
+                for (RouteInfo route : routes) {
+                    int selectorIndex = mDiscoveryRequest.getSelectors().indexOf(
+                            route.getSelector());
+                    if (selectorIndex < 0) {
+                        Log.w(TAG, "Ignoring route because the selector does not match "
+                                + "any of those that were originally supplied by the "
+                                + "client's discovery request: destination=" + destination
+                                + ", route=" + route);
+                        continue;
+                    }
+
+                    ParcelableRouteInfo pri = new ParcelableRouteInfo();
+                    pri.id = route.getId();
+                    pri.selectorIndex = selectorIndex;
+                    pri.features = route.getFeatures();
+                    pri.protocols = route.getProtocols().toArray(
+                            new String[route.getProtocols().size()]);
+                    pri.extras = route.getExtras();
+                    pris.add(pri);
+                }
+                try {
+                    mClientCallback.onDestinationFound(mDiscoverySeq, pdi,
+                            pris.toArray(new ParcelableRouteInfo[pris.size()]));
+                } catch (RemoteException ex) {
+                    // binder death handled elsewhere
+                }
+            }
+        }
+
+        public void dispatchDestinationLost(DiscoveryCallback callback,
+                DestinationInfo destination) {
+            if (callback == mDiscoveryCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "destinationLost: destination=" + destination);
+                }
+
+                if (mDestinations.get(destination.getId()).destination == destination) {
+                    mDestinations.remove(destination.getId());
+                    try {
+                        mClientCallback.onDestinationLost(mDiscoverySeq, destination.getId());
+                    } catch (RemoteException ex) {
+                        // binder death handled elsewhere
+                    }
+                }
+            }
+        }
+
+        public void dispatchDiscoveryFailed(DiscoveryCallback callback,
+                int error, CharSequence message, Bundle extras) {
+            if (callback == mDiscoveryCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "discoveryFailed: error=" + error + ", message=" + message
+                            + ", extras=" + extras);
+                }
+
+                try {
+                    mClientCallback.onDiscoveryFailed(mDiscoverySeq, error, message, extras);
+                } catch (RemoteException ex) {
+                    // binder death handled elsewhere
+                }
+            }
+        }
+
+        public void dispatchConnected(ConnectionCallback callback, ConnectionInfo connection) {
+            if (callback == mConnectionCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "connected: connection=" + connection);
+                }
+                if (mConnection == null) {
+                    mConnection = connection;
+
+                    ParcelableConnectionInfo pci = new ParcelableConnectionInfo();
+                    pci.audioAttributes = connection.getAudioAttributes();
+                    pci.presentationDisplayId = connection.getPresentationDisplay() != null ?
+                            connection.getPresentationDisplay().getDisplayId() : -1;
+                    pci.protocolBinders = new IBinder[connection.getProtocols().size()];
+                    for (int i = 0; i < pci.protocolBinders.length; i++) {
+                        pci.protocolBinders[i] = connection.getProtocolBinder(i);
+                    }
+                    pci.extras = connection.getExtras();
+                    try {
+                        mClientCallback.onConnected(mConnectionSeq, pci);
+                    } catch (RemoteException ex) {
+                        // binder death handled elsewhere
+                    }
+                } else {
+                    Log.w(TAG, "Media route service called onConnected() while already "
+                            + "connected.");
+                }
+            }
+        }
+
+        public void dispatchDisconnected(ConnectionCallback callback) {
+            if (callback == mConnectionCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "disconnected");
+                }
+
+                if (mConnection != null) {
+                    mConnection.close();
+                    mConnection = null;
+
+                    try {
+                        mClientCallback.onDisconnected(mConnectionSeq);
+                    } catch (RemoteException ex) {
+                        // binder death handled elsewhere
+                    }
+                }
+            }
+        }
+
+        public void dispatchConnectionFailed(ConnectionCallback callback,
+                int error, CharSequence message, Bundle extras) {
+            if (callback == mConnectionCallback) {
+                if (DEBUG) {
+                    Log.d(TAG, "connectionFailed: error=" + error + ", message=" + message
+                            + ", extras=" + extras);
+                }
+
+                try {
+                    mClientCallback.onConnectionFailed(mConnectionSeq, error, message, extras);
+                } catch (RemoteException ex) {
+                    // binder death handled elsewhere
+                }
+            }
+        }
+    }
+
+    private static final class DestinationRecord {
+        public final DestinationInfo destination;
+        public final List<RouteInfo> routes;
+
+        public DestinationRecord(DestinationInfo destination, List<RouteInfo> routes) {
+            this.destination = destination;
+            this.routes = routes;
+        }
+
+        public RouteInfo getRoute(String routeId) {
+            final int count = routes.size();
+            for (int i = 0; i < count; i++) {
+                RouteInfo route = routes.get(i);
+                if (route.getId().equals(routeId)) {
+                    return route;
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/media/java/android/media/routing/MediaRouter.java b/media/java/android/media/routing/MediaRouter.java
new file mode 100644
index 0000000..4f6d324
--- /dev/null
+++ b/media/java/android/media/routing/MediaRouter.java
@@ -0,0 +1,1886 @@
+/*
+ * 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.routing;
+
+import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Presentation;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.VolumeProvider;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.view.Display;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Media router allows applications to discover, connect to, control,
+ * and send content to nearby media devices known as destinations.
+ * <p>
+ * There are generally two participants involved in media routing: an
+ * application that wants to send media content to a destination and a
+ * {@link MediaRouteService media route service} that provides the
+ * service of transporting that content where it needs to go on behalf of the
+ * application.
+ * </p><p>
+ * To send media content to a destination, the application must ask the system
+ * to discover available routes to destinations that provide certain capabilities,
+ * establish a connection to a route, then send messages through the connection to
+ * control the routing of audio and video streams, launch remote applications,
+ * and invoke other functions of the destination.
+ * </p><p>
+ * Media router objects are thread-safe.
+ * </p>
+ *
+ * <h3>Destinations</h3>
+ * <p>
+ * The media devices to which an application may send media content are referred
+ * to in the API as destinations.  Each destination therefore represents a single
+ * independent device such as a speaker or TV set.  Destinations are given meaningful
+ * names and descriptions to help the user associate them with devices in their
+ * environment.
+ * </p><p>
+ * Destinations may be local or remote and may be accessed through various means,
+ * often wirelessly.  The user may install media route services to enable
+ * media applications to connect to a variety of destinations with different
+ * capabilities.
+ * </p>
+ *
+ * <h3>Routes</h3>
+ * <p>
+ * Routes represent possible usages or means of reaching and interacting with
+ * a destination.  Since destinations may support many different features, they may
+ * each offer multiple routes for applications to choose from based on their needs.
+ * For example, one route might express the ability to stream locally rendered audio
+ * and video to the device; another route might express the ability to send a URL for
+ * the destination to download from the network and play all by itself.
+ * </p><p>
+ * Routes are discovered according to the set of capabilities that
+ * an application or the system is seeking to use at a particular time.  For example,
+ * if an application wants to stream music to a destination then it will ask the
+ * {@link MediaRouter} to find routes to destinations can stream music and ignore
+ * all other destinations that cannot.
+ * </p><p>
+ * In general, the application will inspect the set of routes that have been
+ * offered then connect to the most appropriate route for its desired purpose.
+ * </p>
+ *
+ * <h3>Route Selection</h3>
+ * <p>
+ * When the user open the media route chooser activity, the system will display
+ * a list of nearby media destinations which have been discovered.  After the
+ * choice is made the application may connect to one of the routes offered by
+ * this destination and begin communicating with the destination.
+ * </p><p>
+ * Destinations are located through a process called discovery.  During discovery,
+ * the system will start installed {@link MediaRouteService media route services}
+ * to scan the network for nearby devices that offer the kinds of capabilities that the
+ * application is seeking to use.  The application specifies the capabilities it requires by
+ * adding {@link MediaRouteSelector media route selectors} to the media router
+ * using the {@link #addSelector} method.  Only destinations that provide routes
+ * which satisfy at least one of these media route selectors will be discovered.
+ * </p><p>
+ * Once the user has selected a destination, the application will be given a chance
+ * to choose one of the routes to which it would like to connect.  The application
+ * may switch to a different route from the same destination at a later time but
+ * in order to connect to a new destination, the application must once again launch
+ * the media route chooser activity to ask the user to choose a destination.
+ * </p>
+ *
+ * <h3>Route Protocols</h3>
+ * <p>
+ * Route protocols express capabilities offered by routes.  Each media route selector
+ * must specify at least one required protocol by which the routes will be selected.
+ * </p><p>
+ * The framework provides several predefined <code>MediaRouteProtocols</code> which are
+ * defined in the <code>android-support-media-protocols.jar</code> support library.
+ * Applications must statically link this library to make use of these protocols.
+ * </p><p>
+ * The static library approach is used to enable ongoing extension and refinement
+ * of protocols in the SDK and interoperability with the media router implementation
+ * for older platform versions which is offered by the framework support library.
+ * </p><p>
+ * Media route services may also define custom media route protocols of their own
+ * to enable applications to access specialized capabilities of certain destinations
+ * assuming they have linked in the required protocol code.
+ * </p><p>
+ * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code> for more information.
+ * </p>
+ *
+ * <h3>Connections</h3>
+ * <p>
+ * After connecting to a media route, the application can send commands to
+ * the route using any of the protocols that it requested.  If the route supports live
+ * audio or video streaming then the application can create an {@link AudioTrack} or
+ * {@link Presentation} to route locally generated content to the destination.
+ * </p>
+ *
+ * <h3>Delegation</h3>
+ * <p>
+ * The creator of the media router is responsible for establishing the policy for
+ * discovering and connecting to destinations.  UI components may observe the state
+ * of the media router by {@link #createDelegate creating} a {@link Delegate}.
+ * </p><p>
+ * The media router should also be attached to the {@link MediaSession media session}
+ * that is handling media playback lifecycle.  This will allow
+ * authorized {@link MediaController media controllers}, possibly running in other
+ * processes, to provide UI to examine and change the media destination by
+ * {@link MediaController#createMediaRouterDelegate creating} a {@link Delegate}
+ * for the media router associated with the session.
+ * </p>
+ */
+public final class MediaRouter {
+    private final DisplayManager mDisplayManager;
+
+    private final Object mLock = new Object();
+
+    private RoutingCallback mRoutingCallback;
+    private Handler mRoutingCallbackHandler;
+
+    private boolean mReleased;
+    private int mDiscoveryState;
+    private int mConnectionState;
+    private final ArrayList<MediaRouteSelector> mSelectors =
+            new ArrayList<MediaRouteSelector>();
+    private final ArrayMap<DestinationInfo, List<RouteInfo>> mDiscoveredDestinations =
+            new ArrayMap<DestinationInfo, List<RouteInfo>>();
+    private RouteInfo mSelectedRoute;
+    private ConnectionInfo mConnection;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = { DISCOVERY_STATE_STOPPED, DISCOVERY_STATE_STARTED })
+    public @interface DiscoveryState { }
+
+    /**
+     * Discovery state: Discovery is not currently in progress.
+     */
+    public static final int DISCOVERY_STATE_STOPPED = 0;
+
+    /**
+     * Discovery state: Discovery is being performed.
+     */
+    public static final int DISCOVERY_STATE_STARTED = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = { DISCOVERY_FLAG_BACKGROUND })
+    public @interface DiscoveryFlags { }
+
+    /**
+     * Discovery flag: Indicates that the client has requested passive discovery in
+     * the background.  The media route service should try to use less power and rely
+     * more on its internal caches to minimize its impact.
+     */
+    public static final int DISCOVERY_FLAG_BACKGROUND = 1 << 0;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = { DISCOVERY_ERROR_UNKNOWN, DISCOVERY_ERROR_ABORTED,
+            DISCOVERY_ERROR_NO_CONNECTIVITY })
+    public @interface DiscoveryError { }
+
+    /**
+     * Discovery error: Unknown error; refer to the error message for details.
+     */
+    public static final int DISCOVERY_ERROR_UNKNOWN = 0;
+
+    /**
+     * Discovery error: The media router or media route service has decided not to
+     * handle the discovery request for some reason.
+     */
+    public static final int DISCOVERY_ERROR_ABORTED = 1;
+
+    /**
+     * Discovery error: The media route service is unable to perform discovery
+     * due to a lack of connectivity such as because the radio is disabled.
+     */
+    public static final int DISCOVERY_ERROR_NO_CONNECTIVITY = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = { CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
+            CONNECTION_STATE_CONNECTED })
+    public @interface ConnectionState { }
+
+    /**
+     * Connection state: No destination has been selected.  Media content should
+     * be sent to the default output.
+     */
+    public static final int CONNECTION_STATE_DISCONNECTED = 0;
+
+    /**
+     * Connection state: The application is in the process of connecting to
+     * a route offered by the selected destination.
+     */
+    public static final int CONNECTION_STATE_CONNECTING = 1;
+
+    /**
+     * Connection state: The application has connected to a route offered by
+     * the selected destination.
+     */
+    public static final int CONNECTION_STATE_CONNECTED = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = { CONNECTION_FLAG_BARGE })
+    public @interface ConnectionFlags { }
+
+    /**
+     * Connection flag: Indicates that the client has requested to barge in and evict
+     * other clients that might have already connected to the destination and that
+     * would otherwise prevent this client from connecting.  When this flag is not
+     * set, the media route service should be polite and report
+     * {@link MediaRouter#CONNECTION_ERROR_BUSY} in case the destination is
+     * already occupied and cannot accept additional connections.
+     */
+    public static final int CONNECTION_FLAG_BARGE = 1 << 0;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = { CONNECTION_ERROR_UNKNOWN, CONNECTION_ERROR_ABORTED,
+            CONNECTION_ERROR_UNAUTHORIZED, CONNECTION_ERROR_UNAUTHORIZED,
+            CONNECTION_ERROR_BUSY, CONNECTION_ERROR_TIMEOUT, CONNECTION_ERROR_BROKEN })
+    public @interface ConnectionError { }
+
+    /**
+     * Connection error: Unknown error; refer to the error message for details.
+     */
+    public static final int CONNECTION_ERROR_UNKNOWN = 0;
+
+    /**
+     * Connection error: The media router or media route service has decided not to
+     * handle the connection request for some reason.
+     */
+    public static final int CONNECTION_ERROR_ABORTED = 1;
+
+    /**
+     * Connection error: The device has refused the connection from this client.
+     * This error should be avoided because the media route service should attempt
+     * to filter out devices that the client cannot access as it performs discovery
+     * on behalf of that client.
+     */
+    public static final int CONNECTION_ERROR_UNAUTHORIZED = 2;
+
+    /**
+     * Connection error: The device is unreachable over the network.
+     */
+    public static final int CONNECTION_ERROR_UNREACHABLE = 3;
+
+    /**
+     * Connection error: The device is already busy serving another client and
+     * the connection request did not ask to barge in.
+     */
+    public static final int CONNECTION_ERROR_BUSY = 4;
+
+    /**
+     * Connection error: A timeout occurred during connection.
+     */
+    public static final int CONNECTION_ERROR_TIMEOUT = 5;
+
+    /**
+     * Connection error: The connection to the device was severed unexpectedly.
+     */
+    public static final int CONNECTION_ERROR_BROKEN = 6;
+
+    /**
+     * Connection error: The connection was terminated because a different client barged
+     * in and took control of the destination.
+     */
+    public static final int CONNECTION_ERROR_BARGED = 7;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = { DISCONNECTION_REASON_APPLICATION_REQUEST,
+            DISCONNECTION_REASON_USER_REQUEST, DISCONNECTION_REASON_ERROR })
+    public @interface DisconnectionReason { }
+
+    /**
+     * Disconnection reason: The application requested disconnection itself.
+     */
+    public static final int DISCONNECTION_REASON_APPLICATION_REQUEST = 0;
+
+    /**
+     * Disconnection reason: The user requested disconnection.
+     */
+    public static final int DISCONNECTION_REASON_USER_REQUEST = 1;
+
+    /**
+     * Disconnection reason: An error occurred.
+     */
+    public static final int DISCONNECTION_REASON_ERROR = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = { ROUTE_FEATURE_LIVE_AUDIO, ROUTE_FEATURE_LIVE_VIDEO })
+    public @interface RouteFeatures { }
+
+    /**
+     * Route feature: Live audio.
+     * <p>
+     * A route that supports live audio streams audio rendered by the application
+     * to the destination.
+     * </p><p>
+     * To take advantage of live audio routing, the application must render its
+     * media using the audio attributes specified by {@link #getPreferredAudioAttributes}.
+     * </p>
+     *
+     * @see #getPreferredAudioAttributes
+     * @see android.media.AudioAttributes
+     */
+    public static final int ROUTE_FEATURE_LIVE_AUDIO = 1 << 0;
+
+    /**
+     * Route feature: Live video.
+     * <p>
+     * A route that supports live video streams video rendered by the application
+     * to the destination.
+     * </p><p>
+     * To take advantage of live video routing, the application must render its
+     * media to a {@link android.app.Presentation presentation window} on the
+     * display specified by {@link #getPreferredPresentationDisplay}.
+     * </p>
+     *
+     * @see #getPreferredPresentationDisplay
+     * @see android.app.Presentation
+     */
+    public static final int ROUTE_FEATURE_LIVE_VIDEO = 1 << 1;
+
+    /**
+     * Creates a media router.
+     *
+     * @param context The context with which the router is associated.
+     */
+    public MediaRouter(@NonNull Context context) {
+        if (context == null) {
+            throw new IllegalArgumentException("context must not be null");
+        }
+
+        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+    }
+
+    /** @hide */
+    public IMediaRouter getBinder() {
+        // todo
+        return null;
+    }
+
+    /**
+     * Disconnects from the selected destination and releases the media router.
+     * <p>
+     * This method should be called by the application when it no longer requires
+     * the media router to ensure that all bound resources may be cleaned up.
+     * </p>
+     */
+    public void release() {
+        synchronized (mLock) {
+            mReleased = true;
+            // todo
+        }
+    }
+
+    /**
+     * Returns true if the media router has been released.
+     */
+    public boolean isReleased() {
+        synchronized (mLock) {
+            return mReleased;
+        }
+    }
+
+    /**
+     * Gets the current route discovery state.
+     *
+     * @return The current discovery state: one of {@link #DISCOVERY_STATE_STOPPED},
+     * {@link #DISCOVERY_STATE_STARTED}.
+     */
+    public @DiscoveryState int getDiscoveryState() {
+        synchronized (mLock) {
+            return mDiscoveryState;
+        }
+    }
+
+    /**
+     * Gets the current route connection state.
+     *
+     * @return The current state: one of {@link #CONNECTION_STATE_DISCONNECTED},
+     * {@link #CONNECTION_STATE_CONNECTING} or {@link #CONNECTION_STATE_CONNECTED}.
+     */
+    public @ConnectionState int getConnectionState() {
+        synchronized (mLock) {
+            return mConnectionState;
+        }
+    }
+
+    /**
+     * Creates a media router delegate through which the destination of the media
+     * router may be controlled.
+     * <p>
+     * This is the point of entry for UI code that initiates discovery and
+     * connection to routes.
+     * </p>
+     */
+    public @NonNull Delegate createDelegate() {
+        return null; // todo
+    }
+
+    /**
+     * Sets a callback to participate in route discovery, filtering, and connection
+     * establishment.
+     *
+     * @param callback The callback to set, or null if none.
+     * @param handler The handler to receive callbacks, or null to use the current thread.
+     */
+    public void setRoutingCallback(@Nullable RoutingCallback callback,
+            @Nullable Handler handler) {
+        synchronized (mLock) {
+            if (callback == null) {
+                mRoutingCallback = null;
+                mRoutingCallbackHandler = null;
+            } else {
+                mRoutingCallback = callback;
+                mRoutingCallbackHandler = handler != null ? handler : new Handler();
+            }
+        }
+    }
+
+    /**
+     * Adds a media route selector to use to find destinations that have
+     * routes with the specified capabilities during route discovery.
+     */
+    public void addSelector(@NonNull MediaRouteSelector selector) {
+        if (selector == null) {
+            throw new IllegalArgumentException("selector must not be null");
+        }
+
+        synchronized (mLock) {
+            if (!mSelectors.contains(selector)) {
+                mSelectors.add(selector);
+                // todo
+            }
+        }
+    }
+
+    /**
+     * Removes a media route selector.
+     */
+    public void removeSelector(@NonNull MediaRouteSelector selector) {
+        if (selector == null) {
+            throw new IllegalArgumentException("selector must not be null");
+        }
+
+        synchronized (mLock) {
+            if (mSelectors.remove(selector)) {
+                // todo
+            }
+        }
+    }
+
+    /**
+     * Removes all media route selectors.
+     * <p>
+     * Note that at least one selector must be added in order to perform discovery.
+     * </p>
+     */
+    public void clearSelectors() {
+        synchronized (mLock) {
+            if (!mSelectors.isEmpty()) {
+                mSelectors.clear();
+                // todo
+            }
+        }
+    }
+
+    /**
+     * Gets a list of all media route selectors to consider during discovery.
+     */
+    public @NonNull List<MediaRouteSelector> getSelectors() {
+        synchronized (mLock) {
+            return new ArrayList<MediaRouteSelector>(mSelectors);
+        }
+    }
+
+    /**
+     * Gets the connection to the currently selected route.
+     *
+     * @return The connection to the currently selected route, or null if not connected.
+     */
+    public @NonNull ConnectionInfo getConnection() {
+        synchronized (mLock) {
+            return mConnection;
+        }
+    }
+
+    /**
+     * Gets the list of discovered destinations.
+     * <p>
+     * This list is only valid while discovery is running and is null otherwise.
+     * </p>
+     *
+     * @return The list of discovered destinations, or null if discovery is not running.
+     */
+    public @NonNull List<DestinationInfo> getDiscoveredDestinations() {
+        synchronized (mLock) {
+            if (mDiscoveryState == DISCOVERY_STATE_STARTED) {
+                return new ArrayList<DestinationInfo>(mDiscoveredDestinations.keySet());
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Gets the list of discovered routes for a particular destination.
+     * <p>
+     * This list is only valid while discovery is running and is null otherwise.
+     * </p>
+     *
+     * @param destination The destination for which to get the list of discovered routes.
+     * @return The list of discovered routes for the destination, or null if discovery
+     * is not running.
+     */
+    public @NonNull List<RouteInfo> getDiscoveredRoutes(@NonNull DestinationInfo destination) {
+        if (destination == null) {
+            throw new IllegalArgumentException("destination must not be null");
+        }
+        synchronized (mLock) {
+            if (mDiscoveryState == DISCOVERY_STATE_STARTED) {
+                List<RouteInfo> routes = mDiscoveredDestinations.get(destination);
+                if (routes != null) {
+                    return new ArrayList<RouteInfo>(routes);
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Gets the destination that has been selected.
+     *
+     * @return The selected destination, or null if disconnected.
+     */
+    public @Nullable DestinationInfo getSelectedDestination() {
+        synchronized (mLock) {
+            return mSelectedRoute != null ? mSelectedRoute.getDestination() : null;
+        }
+    }
+
+    /**
+     * Gets the route that has been selected.
+     *
+     * @return The selected destination, or null if disconnected.
+     */
+    public @Nullable RouteInfo getSelectedRoute() {
+        synchronized (mLock) {
+            return mSelectedRoute;
+        }
+    }
+
+    /**
+     * Gets the preferred audio attributes that should be used to stream live audio content
+     * based on the connected route.
+     * <p>
+     * Use an {@link AudioTrack} to send audio content to the destination with these
+     * audio attributes.
+     * </p><p>
+     * The preferred audio attributes may change when a connection is established but it
+     * will remain constant until disconnected.
+     * </p>
+     *
+     * @return The preferred audio attributes to use.  When connected, returns the
+     * route's audio attributes or null if it does not support live audio streaming.
+     * Otherwise returns audio attributes associated with {@link AudioAttributes#USAGE_MEDIA}.
+     */
+    public @Nullable AudioAttributes getPreferredAudioAttributes() {
+        synchronized (mLock) {
+            if (mConnection != null) {
+                return mConnection.getAudioAttributes();
+            }
+            return new AudioAttributes.Builder()
+                    .setLegacyStreamType(AudioManager.STREAM_MUSIC)
+                    .build();
+        }
+    }
+
+    /**
+     * Gets the preferred presentation display that should be used to stream live video content
+     * based on the connected route.
+     * <p>
+     * Use a {@link Presentation} to send video content to the destination with this display.
+     * </p><p>
+     * The preferred presentation display may change when a connection is established but it
+     * will remain constant until disconnected.
+     * </p>
+     *
+     * @return The preferred presentation display to use.  When connected, returns
+     * the route's presentation display or null if it does not support live video
+     * streaming.  Otherwise returns the first available
+     * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION presentation display},
+     * such as a mirrored wireless or HDMI display or null if none.
+     */
+    public @Nullable Display getPreferredPresentationDisplay() {
+        synchronized (mLock) {
+            if (mConnection != null) {
+                return mConnection.getPresentationDisplay();
+            }
+            Display[] displays = mDisplayManager.getDisplays(
+                    DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
+            return displays.length != 0 ? displays[0] : null;
+        }
+    }
+
+    /**
+     * Gets the preferred volume provider that should be used to control the volume
+     * of content rendered on the currently selected route.
+     * <p>
+     * The preferred volume provider may change when a connection is established but it
+     * will remain the same until disconnected.
+     * </p>
+     *
+     * @return The preferred volume provider to use, or null if the currently
+     * selected route does not support remote volume adjustment or if the connection
+     * is not yet established.  If no route is selected, returns null to indicate
+     * that system volume control should be used.
+     */
+    public @Nullable VolumeProvider getPreferredVolumeProvider() {
+        synchronized (mLock) {
+            if (mConnection != null) {
+                return mConnection.getVolumeProvider();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Requests to pause streaming of live audio or video routes.
+     * Should be called when the application is going into the background and is
+     * no longer rendering content locally.
+     * <p>
+     * This method does nothing unless a connection has been established.
+     * </p>
+     */
+    public void pauseStream() {
+        // todo
+    }
+
+    /**
+     * Requests to resume streaming of live audio or video routes.
+     * May be called when the application is returning to the foreground and is
+     * about to resume rendering content locally.
+     * <p>
+     * This method does nothing unless a connection has been established.
+     * </p>
+     */
+    public void resumeStream() {
+        // todo
+    }
+
+    /**
+     * This class is used by UI components to let the user discover and
+     * select a destination to which the media router should connect.
+     * <p>
+     * This API has somewhat more limited functionality than the {@link MediaRouter}
+     * itself because it is designed to allow applications to control
+     * the destination of media router instances that belong to other processes.
+     * </p><p>
+     * To control the destination of your own media router, call
+     * {@link #createDelegate} to obtain a local delegate object.
+     * </p><p>
+     * To control the destination of a media router that belongs to another process,
+     * first obtain a {@link MediaController} that is associated with the media playback
+     * that is occurring in that process, then call
+     * {@link MediaController#createMediaRouterDelegate} to obtain an instance of
+     * its destination controls.  Note that special permissions may be required to
+     * obtain the {@link MediaController} instance in the first place.
+     * </p>
+     */
+    public static final class Delegate {
+        /**
+         * Returns true if the media router has been released.
+         */
+        public boolean isReleased() {
+            // todo
+            return false;
+        }
+
+        /**
+         * Gets the current route discovery state.
+         *
+         * @return The current discovery state: one of {@link #DISCOVERY_STATE_STOPPED},
+         * {@link #DISCOVERY_STATE_STARTED}.
+         */
+        public @DiscoveryState int getDiscoveryState() {
+            // todo
+            return -1;
+        }
+
+        /**
+         * Gets the current route connection state.
+         *
+         * @return The current state: one of {@link #CONNECTION_STATE_DISCONNECTED},
+         * {@link #CONNECTION_STATE_CONNECTING} or {@link #CONNECTION_STATE_CONNECTED}.
+         */
+        public @ConnectionState int getConnectionState() {
+            // todo
+            return -1;
+        }
+
+        /**
+         * Gets the currently selected destination.
+         *
+         * @return The destination information, or null if none.
+         */
+        public @Nullable DestinationInfo getSelectedDestination() {
+            return null;
+        }
+
+        /**
+         * Gets the list of discovered destinations.
+         * <p>
+         * This list is only valid while discovery is running and is null otherwise.
+         * </p>
+         *
+         * @return The list of discovered destinations, or null if discovery is not running.
+         */
+        public @NonNull List<DestinationInfo> getDiscoveredDestinations() {
+            return null;
+        }
+
+        /**
+         * Adds a callback to receive state changes.
+         *
+         * @param callback The callback to set, or null if none.
+         * @param handler The handler to receive callbacks, or null to use the current thread.
+         */
+        public void addStateCallback(@Nullable StateCallback callback,
+                @Nullable Handler handler) {
+            if (callback == null) {
+                throw new IllegalArgumentException("callback must not be null");
+            }
+            if (handler == null) {
+                handler = new Handler();
+            }
+            // todo
+        }
+
+        /**
+         * Removes a callback for state changes.
+         *
+         * @param callback The callback to set, or null if none.
+         */
+        public void removeStateCallback(@Nullable StateCallback callback) {
+            // todo
+        }
+
+        /**
+         * Starts performing discovery.
+         * <p>
+         * Performing discovery is expensive.  Make sure to call {@link #stopDiscovery}
+         * as soon as possible once a new destination has been selected to allow the system
+         * to stop services associated with discovery.
+         * </p>
+         *
+         * @param flags The discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
+         */
+        public void startDiscovery(@DiscoveryFlags int flags) {
+            // todo
+        }
+
+        /**
+         * Stops performing discovery.
+         */
+        public void stopDiscovery() {
+            // todo
+        }
+
+        /**
+         * Connects to a destination during route discovery.
+         * <p>
+         * This method may only be called while route discovery is active and the
+         * destination appears in the
+         * {@link #getDiscoveredDestinations list of discovered destinations}.
+         * If the media router is already connected to a route then it will first disconnect
+         * from the current route then connect to the new route.
+         * </p>
+         *
+         * @param destination The destination to which the media router should connect.
+         * @param flags The connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
+         */
+        public void connect(@NonNull DestinationInfo destination, @DiscoveryFlags int flags) {
+            // todo
+        }
+
+        /**
+         * Disconnects from the currently selected destination.
+         * <p>
+         * Does nothing if not currently connected.
+         * </p>
+         *
+         * @param reason The reason for the disconnection: one of
+         * {@link #DISCONNECTION_REASON_APPLICATION_REQUEST},
+         * {@link #DISCONNECTION_REASON_USER_REQUEST}, or {@link #DISCONNECTION_REASON_ERROR}.
+         */
+        public void disconnect(@DisconnectionReason int reason) {
+            // todo
+        }
+    }
+
+    /**
+     * Describes immutable properties of a connection to a route.
+     */
+    public static final class ConnectionInfo {
+        private final RouteInfo mRoute;
+        private final AudioAttributes mAudioAttributes;
+        private final Display mPresentationDisplay;
+        private final VolumeProvider mVolumeProvider;
+        private final IBinder[] mProtocolBinders;
+        private final Object[] mProtocolInstances;
+        private final Bundle mExtras;
+        private final ArrayList<Closeable> mCloseables;
+
+        private static final Class<?>[] MEDIA_ROUTE_PROTOCOL_CTOR_PARAMETERS =
+                new Class<?>[] { IBinder.class };
+
+        ConnectionInfo(RouteInfo route,
+                AudioAttributes audioAttributes, Display display,
+                VolumeProvider volumeProvider, IBinder[] protocolBinders,
+                Bundle extras, ArrayList<Closeable> closeables) {
+            mRoute = route;
+            mAudioAttributes = audioAttributes;
+            mPresentationDisplay = display;
+            mVolumeProvider = volumeProvider;
+            mProtocolBinders = protocolBinders;
+            mProtocolInstances = new Object[mProtocolBinders.length];
+            mExtras = extras;
+            mCloseables = closeables;
+        }
+
+        /**
+         * Gets the route that is connected.
+         */
+        public @NonNull RouteInfo getRoute() {
+            return mRoute;
+        }
+
+        /**
+         * Gets the audio attributes which the client should use to stream audio
+         * to the destination, or null if the route does not support live audio streaming.
+         */
+        public @Nullable AudioAttributes getAudioAttributes() {
+            return mAudioAttributes;
+        }
+
+        /**
+         * Gets the display which the client should use to stream video to the
+         * destination using a {@link Presentation}, or null if the route does not
+         * support live video streaming.
+         */
+        public @Nullable Display getPresentationDisplay() {
+            return mPresentationDisplay;
+        }
+
+        /**
+         * Gets the route's volume provider, or null if none.
+         */
+        public @Nullable VolumeProvider getVolumeProvider() {
+            return mVolumeProvider;
+        }
+
+        /**
+         * Gets the set of supported route features.
+         */
+        public @RouteFeatures int getFeatures() {
+            return mRoute.getFeatures();
+        }
+
+        /**
+         * Gets the list of supported route protocols.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         */
+        public @NonNull List<String> getProtocols() {
+            return mRoute.getProtocols();
+        }
+
+        /**
+         * Gets an instance of a route protocol object that wraps the protocol binder
+         * and provides easy access to the protocol's functionality.
+         * <p>
+         * This is a convenience method which invokes {@link #getProtocolBinder(String)}
+         * using the name of the provided class then passes the resulting {@link IBinder}
+         * to a single-argument constructor of that class.
+         * </p><p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         */
+        @SuppressWarnings("unchecked")
+        public @Nullable <T> T getProtocolObject(Class<T> clazz) {
+            int index = getProtocols().indexOf(clazz.getName());
+            if (index < 0) {
+                return null;
+            }
+            if (mProtocolInstances[index] == null && mProtocolBinders[index] != null) {
+                final Constructor<T> ctor;
+                try {
+                    ctor = clazz.getConstructor(MEDIA_ROUTE_PROTOCOL_CTOR_PARAMETERS);
+                } catch (NoSuchMethodException ex) {
+                    throw new RuntimeException("Could not find public constructor "
+                            + "with IBinder argument in protocol class: " + clazz.getName(), ex);
+                }
+                try {
+                    mProtocolInstances[index] = ctor.newInstance(mProtocolBinders[index]);
+                } catch (InstantiationException | IllegalAccessException
+                        | InvocationTargetException ex) {
+                    throw new RuntimeException("Could create instance of protocol class: "
+                            + clazz.getName(), ex);
+                }
+            }
+            return (T)mProtocolInstances[index];
+        }
+
+        /**
+         * Gets the {@link IBinder} that provides access to the specified route protocol
+         * or null if the protocol is not supported.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         */
+        public @Nullable IBinder getProtocolBinder(@NonNull String name) {
+            int index = getProtocols().indexOf(name);
+            return index >= 0 ? mProtocolBinders[index] : null;
+        }
+
+        /**
+         * Gets the {@link IBinder} that provides access to the specified route protocol
+         * at the given index in the protocol list or null if the protocol is not supported.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         */
+        public @Nullable IBinder getProtocolBinder(int index) {
+            return mProtocolBinders[index];
+        }
+
+        /**
+         * Gets optional extra media route service or protocol specific information about
+         * the connection.  Use the service or protocol name as the prefix for
+         * any extras to avoid namespace collisions.
+         */
+        public @Nullable Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Closes all closeables associated with the connection when the connection
+         * is being torn down.
+         */
+        void close() {
+            final int count = mCloseables.size();
+            for (int i = 0; i < count; i++) {
+                try {
+                    mCloseables.get(i).close();
+                } catch (IOException ex) {
+                }
+            }
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "ConnectionInfo{ route=" + mRoute
+                    + ", audioAttributes=" + mAudioAttributes
+                    + ", presentationDisplay=" + mPresentationDisplay
+                    + ", volumeProvider=" + mVolumeProvider
+                    + ", protocolBinders=" + mProtocolBinders + " }";
+        }
+
+        /**
+         * Builds {@link ConnectionInfo} objects.
+         */
+        public static final class Builder {
+            private final RouteInfo mRoute;
+            private AudioAttributes mAudioAttributes;
+            private Display mPresentationDisplay;
+            private VolumeProvider mVolumeProvider;
+            private final IBinder[] mProtocols;
+            private Bundle mExtras;
+            private final ArrayList<Closeable> mCloseables = new ArrayList<Closeable>();
+
+            /**
+             * Creates a builder for connection information.
+             *
+             * @param route The route that is connected.
+             */
+            public Builder(@NonNull RouteInfo route) {
+                if (route == null) {
+                    throw new IllegalArgumentException("route");
+                }
+                mRoute = route;
+                mProtocols = new IBinder[route.getProtocols().size()];
+            }
+
+            /**
+             * Sets the audio attributes which the client should use to stream audio
+             * to the destination, or null if the route does not support live audio streaming.
+             */
+            public @NonNull Builder setAudioAttributes(
+                    @Nullable AudioAttributes audioAttributes) {
+                mAudioAttributes = audioAttributes;
+                return this;
+            }
+
+            /**
+             * Sets the display which the client should use to stream video to the
+             * destination using a {@link Presentation}, or null if the route does not
+             * support live video streaming.
+             */
+            public @NonNull Builder setPresentationDisplay(@Nullable Display display) {
+                mPresentationDisplay = display;
+                return this;
+            }
+
+            /**
+             * Sets the route's volume provider, or null if none.
+             */
+            public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider provider) {
+                mVolumeProvider = provider;
+                return this;
+            }
+
+            /**
+             * Sets the binder stub of a supported route protocol using
+             * the protocol's fully qualified class name.  The protocol must be one
+             * of those that was indicated as being supported by the route.
+             * <p>
+             * If the stub implements {@link Closeable} then it will automatically
+             * be closed when the client disconnects from the route.
+             * </p><p>
+             * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+             * for more information.
+             * </p>
+             */
+            public @NonNull Builder setProtocolStub(@NonNull Class<?> clazz,
+                    @NonNull IInterface stub) {
+                if (clazz == null) {
+                    throw new IllegalArgumentException("clazz must not be null");
+                }
+                if (stub == null) {
+                    throw new IllegalArgumentException("stub must not be null");
+                }
+                if (stub instanceof Closeable) {
+                    mCloseables.add((Closeable)stub);
+                }
+                return setProtocolBinder(clazz.getName(), stub.asBinder());
+            }
+
+            /**
+             * Sets the binder interface of a supported route protocol by name.
+             * The protocol must be one of those that was indicated as being supported
+             * by the route.
+             * <p>
+             * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+             * for more information.
+             * </p>
+             */
+            public @NonNull Builder setProtocolBinder(@NonNull String name,
+                    @NonNull IBinder binder) {
+                if (TextUtils.isEmpty(name)) {
+                    throw new IllegalArgumentException("name must not be null or empty");
+                }
+                if (binder == null) {
+                    throw new IllegalArgumentException("binder must not be null");
+                }
+                int index = mRoute.getProtocols().indexOf(name);
+                if (index < 0) {
+                    throw new IllegalArgumentException("name must specify a protocol that "
+                            + "the route actually declared that it supports: "
+                            + "name=" + name + ", protocols=" + mRoute.getProtocols());
+                }
+                mProtocols[index] = binder;
+                return this;
+            }
+
+            /**
+             * Sets optional extra media route service or protocol specific information about
+             * the connection.  Use the service or protocol name as the prefix for
+             * any extras to avoid namespace collisions.
+             */
+            public @NonNull Builder setExtras(@Nullable Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Builds the {@link ConnectionInfo} object.
+             */
+            public @NonNull ConnectionInfo build() {
+                return new ConnectionInfo(mRoute,
+                        mAudioAttributes, mPresentationDisplay,
+                        mVolumeProvider, mProtocols, mExtras, mCloseables);
+            }
+        }
+    }
+
+    /**
+     * Describes one particular way of routing media content to a destination
+     * according to the capabilities specified by a media route selector on behalf
+     * of an application.
+     */
+    public static final class RouteInfo {
+        private final String mId;
+        private final DestinationInfo mDestination;
+        private final MediaRouteSelector mSelector;
+        private final int mFeatures;
+        private final ArrayList<String> mProtocols;
+        private final Bundle mExtras;
+
+        RouteInfo(String id, DestinationInfo destination, MediaRouteSelector selector,
+                int features, ArrayList<String> protocols, Bundle extras) {
+            mId = id;
+            mDestination = destination;
+            mSelector = selector;
+            mFeatures = features;
+            mProtocols = protocols;
+            mExtras = extras;
+        }
+
+        /**
+         * Gets the route's stable identifier.
+         * <p>
+         * The id is intended to uniquely identify the route among all routes that
+         * are offered by a particular destination in such a way that the client can
+         * refer to it at a later time.
+         * </p>
+         */
+        public @NonNull String getId() {
+            return mId;
+        }
+
+        /**
+         * Gets the destination that is offering this route.
+         */
+        public @NonNull DestinationInfo getDestination() {
+            return mDestination;
+        }
+
+        /**
+         * Gets the media route selector provided by the client for which this
+         * route was created.
+         * <p>
+         * It is implied that this route supports all of the required capabilities
+         * that were expressed in the selector.
+         * </p>
+         */
+        public @NonNull MediaRouteSelector getSelector() {
+            return mSelector;
+        }
+
+        /**
+         * Gets the set of supported route features.
+         */
+        public @RouteFeatures int getFeatures() {
+            return mFeatures;
+        }
+
+        /**
+         * Gets the list of supported route protocols.
+         * <p>
+         * Refer to <code>android.support.media.protocols.MediaRouteProtocol</code>
+         * for more information.
+         * </p>
+         */
+        public @NonNull List<String> getProtocols() {
+            return mProtocols;
+        }
+
+        /**
+         * Gets optional extra information about the route, or null if none.
+         */
+        public @Nullable Bundle getExtras() {
+            return mExtras;
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "RouteInfo{ id=" + mId + ", destination=" + mDestination
+                    + ", features=0x" + Integer.toHexString(mFeatures)
+                    + ", selector=" + mSelector + ", protocols=" + mProtocols
+                    + ", extras=" + mExtras + " }";
+        }
+
+        /**
+         * Builds {@link RouteInfo} objects.
+         */
+        public static final class Builder {
+            private final DestinationInfo mDestination;
+            private final String mId;
+            private final MediaRouteSelector mSelector;
+            private int mFeatures;
+            private final ArrayList<String> mProtocols = new ArrayList<String>();
+            private Bundle mExtras;
+
+            /**
+             * Creates a builder for route information.
+             *
+             * @param id The route's stable identifier.
+             * @param destination The destination of this route.
+             * @param selector The media route selector provided by the client for which
+             * this route was created.  This must be one of the selectors that was
+             * included in the discovery request.
+             */
+            public Builder(@NonNull String id, @NonNull DestinationInfo destination,
+                    @NonNull MediaRouteSelector selector) {
+                if (TextUtils.isEmpty(id)) {
+                    throw new IllegalArgumentException("id must not be null or empty");
+                }
+                if (destination == null) {
+                    throw new IllegalArgumentException("destination must not be null");
+                }
+                if (selector == null) {
+                    throw new IllegalArgumentException("selector must not be null");
+                }
+                mDestination = destination;
+                mId = id;
+                mSelector = selector;
+            }
+
+            /**
+             * Sets the set of supported route features.
+             */
+            public @NonNull Builder setFeatures(@RouteFeatures int features) {
+                mFeatures = features;
+                return this;
+            }
+
+            /**
+             * Adds a supported route protocol using its fully qualified class name.
+             * <p>
+             * If the protocol was not requested by the client in its selector
+             * then it will be silently discarded.
+             * </p>
+             */
+            public @NonNull <T extends IInterface> Builder addProtocol(@NonNull Class<T> clazz) {
+                if (clazz == null) {
+                    throw new IllegalArgumentException("clazz must not be null");
+                }
+                return addProtocol(clazz.getName());
+            }
+
+            /**
+             * Adds a supported route protocol by name.
+             * <p>
+             * If the protocol was not requested by the client in its selector
+             * then it will be silently discarded.
+             * </p>
+             */
+            public @NonNull Builder addProtocol(@NonNull String name) {
+                if (TextUtils.isEmpty(name)) {
+                    throw new IllegalArgumentException("name must not be null");
+                }
+                if (mSelector.containsProtocol(name)) {
+                    mProtocols.add(name);
+                }
+                return this;
+            }
+
+            /**
+             * Sets optional extra information about the route, or null if none.
+             */
+            public @NonNull Builder setExtras(@Nullable Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Builds the {@link RouteInfo} object.
+             * <p>
+             * Ensures that all required protocols have been supplied.
+             * </p>
+             */
+            public @NonNull RouteInfo build() {
+                int missingFeatures = mSelector.getRequiredFeatures() & ~mFeatures;
+                if (missingFeatures != 0) {
+                    throw new IllegalStateException("The media route selector "
+                            + "specified required features which this route does "
+                            + "not appear to support so it should not have been published: "
+                            + "missing 0x" + Integer.toHexString(missingFeatures));
+                }
+                for (String protocol : mSelector.getRequiredProtocols()) {
+                    if (!mProtocols.contains(protocol)) {
+                        throw new IllegalStateException("The media route selector "
+                                + "specified required protocols which this route "
+                                + "does not appear to support so it should not have "
+                                + "been published: missing " + protocol);
+                    }
+                }
+                return new RouteInfo(mId, mDestination, mSelector,
+                        mFeatures, mProtocols, mExtras);
+            }
+        }
+    }
+
+    /**
+     * Describes a destination for media content such as a device,
+     * an individual port on a device, or a group of devices.
+     */
+    public static final class DestinationInfo {
+        private final String mId;
+        private final ServiceMetadata mService;
+        private final CharSequence mName;
+        private final CharSequence mDescription;
+        private final int mIconResourceId;
+        private final Bundle mExtras;
+
+        DestinationInfo(String id, ServiceMetadata service,
+                CharSequence name, CharSequence description,
+                int iconResourceId, Bundle extras) {
+            mId = id;
+            mService = service;
+            mName = name;
+            mDescription = description;
+            mIconResourceId = iconResourceId;
+            mExtras = extras;
+        }
+
+        /**
+         * Gets the destination's stable identifier.
+         * <p>
+         * The id is intended to uniquely identify the destination among all destinations
+         * provided by the media route service in such a way that the client can
+         * refer to it at a later time.  Ideally, the id should be resilient to
+         * user-initiated actions such as changes to the name or description
+         * of the destination.
+         * </p>
+         */
+        public @NonNull String getId() {
+            return mId;
+        }
+
+        /**
+         * Gets metadata about the service that is providing access to this destination.
+         */
+        public @NonNull ServiceMetadata getServiceMetadata() {
+            return mService;
+        }
+
+        /**
+         * Gets the destination's name for display to the user.
+         */
+        public @NonNull CharSequence getName() {
+            return mName;
+        }
+
+        /**
+         * Gets the destination's description for display to the user, or null if none.
+         */
+        public @Nullable CharSequence getDescription() {
+            return mDescription;
+        }
+
+        /**
+         * Gets an icon resource from the service's package which is used
+         * to identify the destination, or -1 if none.
+         */
+        public @DrawableRes int getIconResourceId() {
+            return mIconResourceId;
+        }
+
+        /**
+         * Loads the icon drawable, or null if none.
+         */
+        public @Nullable Drawable loadIcon(@NonNull PackageManager pm) {
+            return mIconResourceId >= 0 ? mService.getDrawable(pm, mIconResourceId) : null;
+        }
+
+        /**
+         * Gets optional extra information about the destination, or null if none.
+         */
+        public @Nullable Bundle getExtras() {
+            return mExtras;
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "DestinationInfo{ id=" + mId + ", service=" + mService + ", name=" + mName
+                    + ", description=" + mDescription + ", iconResourceId=" + mIconResourceId
+                    + ", extras=" + mExtras + " }";
+        }
+
+        /**
+         * Builds {@link DestinationInfo} objects.
+         */
+        public static final class Builder {
+            private final String mId;
+            private final ServiceMetadata mService;
+            private final CharSequence mName;
+            private CharSequence mDescription;
+            private int mIconResourceId = -1;
+            private Bundle mExtras;
+
+            /**
+             * Creates a builder for destination information.
+             *
+             * @param id The destination's stable identifier.
+             * @param service Metatada about the service that is providing access to
+             * this destination.
+             * @param name The destination's name for display to the user.
+             */
+            public Builder(@NonNull String id, @NonNull ServiceMetadata service,
+                    @NonNull CharSequence name) {
+                if (TextUtils.isEmpty(id)) {
+                    throw new IllegalArgumentException("id must not be null or empty");
+                }
+                if (service == null) {
+                    throw new IllegalArgumentException("service must not be null");
+                }
+                if (TextUtils.isEmpty(name)) {
+                    throw new IllegalArgumentException("name must not be null or empty");
+                }
+                mId = id;
+                mService = service;
+                mName = name;
+            }
+
+            /**
+             * Sets the destination's description for display to the user, or null if none.
+             */
+            public @NonNull Builder setDescription(@Nullable CharSequence description) {
+                mDescription = description;
+                return this;
+            }
+
+            /**
+             * Sets an icon resource from this package used to identify the destination,
+             * or -1 if none.
+             */
+            public @NonNull Builder setIconResourceId(@DrawableRes int resid) {
+                mIconResourceId = resid;
+                return this;
+            }
+
+            /**
+             * Gets optional extra information about the destination, or null if none.
+             */
+            public @NonNull Builder setExtras(@Nullable Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Builds the {@link DestinationInfo} object.
+             */
+            public @NonNull DestinationInfo build() {
+                return new DestinationInfo(mId, mService, mName, mDescription,
+                        mIconResourceId, mExtras);
+            }
+        }
+    }
+
+    /**
+     * Describes metadata about a {@link MediaRouteService} which is providing
+     * access to certain kinds of destinations.
+     */
+    public static final class ServiceMetadata {
+        private final ServiceInfo mService;
+        private CharSequence mLabel;
+        private Drawable mIcon;
+
+        ServiceMetadata(Service service) throws NameNotFoundException {
+            mService = service.getPackageManager().getServiceInfo(
+                    new ComponentName(service, service.getClass()),
+                    PackageManager.GET_META_DATA);
+        }
+
+        ServiceMetadata(ServiceInfo service) {
+            mService = service;
+        }
+
+        /**
+         * Gets the service's component information including it name, label and icon.
+         */
+        public @NonNull ServiceInfo getService() {
+            return mService;
+        }
+
+        /**
+         * Gets the service's component name.
+         */
+        public @NonNull ComponentName getComponentName() {
+            return new ComponentName(mService.packageName, mService.name);
+        }
+
+        /**
+         * Gets the service's package name.
+         */
+        public @NonNull String getPackageName() {
+            return mService.packageName;
+        }
+
+        /**
+         * Gets the service's name for display to the user, or null if none.
+         */
+        public @NonNull CharSequence getLabel(@NonNull PackageManager pm) {
+            if (mLabel == null) {
+                mLabel = mService.loadLabel(pm);
+            }
+            return mLabel;
+        }
+
+        /**
+         * Gets the icon drawable, or null if none.
+         */
+        public @Nullable Drawable getIcon(@NonNull PackageManager pm) {
+            if (mIcon == null) {
+                mIcon = mService.loadIcon(pm);
+            }
+            return mIcon;
+        }
+
+        // TODO: add service metadata
+
+        Drawable getDrawable(PackageManager pm, int resid) {
+            return pm.getDrawable(getPackageName(), resid, mService.applicationInfo);
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "ServiceInfo{ service=" + getComponentName().toShortString() + " }";
+        }
+    }
+
+    /**
+     * Describes a request to discover routes on behalf of an application.
+     */
+    public static final class DiscoveryRequest {
+        private final ArrayList<MediaRouteSelector> mSelectors =
+                new ArrayList<MediaRouteSelector>();
+        private int mFlags;
+
+        DiscoveryRequest(@NonNull List<MediaRouteSelector> selectors) {
+            setSelectors(selectors);
+        }
+
+        /**
+         * Sets the list of media route selectors to consider during discovery.
+         */
+        public void setSelectors(@NonNull List<MediaRouteSelector> selectors) {
+            if (selectors == null) {
+                throw new IllegalArgumentException("selectors");
+            }
+            mSelectors.clear();
+            mSelectors.addAll(selectors);
+        }
+
+        /**
+         * Gets the list of media route selectors to consider during discovery.
+         */
+        public @NonNull List<MediaRouteSelector> getSelectors() {
+            return mSelectors;
+        }
+
+        /**
+         * Gets discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
+         */
+        public @DiscoveryFlags int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Sets discovery flags, such as {@link MediaRouter#DISCOVERY_FLAG_BACKGROUND}.
+         */
+        public void setFlags(@DiscoveryFlags int flags) {
+            mFlags = flags;
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "DiscoveryRequest{ selectors=" + mSelectors
+                    + ", flags=0x" + Integer.toHexString(mFlags)
+                    + " }";
+        }
+    }
+
+    /**
+     * Describes a request to connect to a previously discovered route on
+     * behalf of an application.
+     */
+    public static final class ConnectionRequest {
+        private RouteInfo mRoute;
+        private int mFlags;
+        private Bundle mExtras;
+
+        ConnectionRequest(@NonNull RouteInfo route) {
+            setRoute(route);
+        }
+
+        /**
+         * Gets the route to which to connect.
+         */
+        public @NonNull RouteInfo getRoute() {
+            return mRoute;
+        }
+
+        /**
+         * Sets the route to which to connect.
+         */
+        public void setRoute(@NonNull RouteInfo route) {
+            if (route == null) {
+                throw new IllegalArgumentException("route must not be null");
+            }
+            mRoute = route;
+        }
+
+        /**
+         * Gets connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
+         */
+        public @ConnectionFlags int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Sets connection flags, such as {@link MediaRouter#CONNECTION_FLAG_BARGE}.
+         */
+        public void setFlags(@ConnectionFlags int flags) {
+            mFlags = flags;
+        }
+
+        /**
+         * Gets optional extras supplied by the application as part of the call to
+         * connect, or null if none.  The media route service may use this
+         * information to configure the route during connection.
+         */
+        public @Nullable Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Sets optional extras supplied by the application as part of the call to
+         * connect, or null if none.  The media route service may use this
+         * information to configure the route during connection.
+         */
+        public void setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "ConnectionRequest{ route=" + mRoute
+                    + ", flags=0x" + Integer.toHexString(mFlags)
+                    + ", extras=" + mExtras + " }";
+        }
+    }
+
+    /**
+     * Callback interface to specify policy for route discovery, filtering,
+     * and connection establishment as well as observe media router state changes.
+     */
+    public static abstract class RoutingCallback extends StateCallback {
+        /**
+         * Called to prepare a discovery request object to specify the desired
+         * media route selectors when the media router has been asked to start discovery.
+         * <p>
+         * By default, the discovery request contains all of the selectors which
+         * have been added to the media router.  Subclasses may override the list of
+         * selectors by modifying the discovery request object before returning.
+         * </p>
+         *
+         * @param request The discovery request object which may be modified by
+         * this method to alter how discovery will be performed.
+         * @param selectors The immutable list of media route selectors which were
+         * added to the media router.
+         * @return True to allow discovery to proceed or false to abort it.
+         * By default, this methods returns true.
+         */
+        public boolean onPrepareDiscoveryRequest(@NonNull DiscoveryRequest request,
+                @NonNull List<MediaRouteSelector> selectors) {
+            return true;
+        }
+
+        /**
+         * Called to prepare a connection request object to specify the desired
+         * route and connection parameters when the media router has been asked to
+         * connect to a particular destination.
+         * <p>
+         * By default, the connection request specifies the first available route
+         * to the destination.  Subclasses may override the route and destination
+         * or set additional connection parameters by modifying the connection request
+         * object before returning.
+         * </p>
+         *
+         * @param request The connection request object which may be modified by
+         * this method to alter how the connection will be established.
+         * @param destination The destination to which the media router was asked
+         * to connect.
+         * @param routes The list of routes that belong to that destination sorted
+         * in the same order as their matching media route selectors which were
+         * used during discovery.
+         * @return True to allow the connection to proceed or false to abort it.
+         * By default, this methods returns true.
+         */
+        public boolean onPrepareConnectionRequest(
+                @NonNull ConnectionRequest request,
+                @NonNull DestinationInfo destination, @NonNull List<RouteInfo> routes) {
+            return true;
+        }
+    }
+
+    /**
+     * Callback class to receive events from a {@link MediaRouter.Delegate}.
+     */
+    public static abstract class StateCallback {
+        /**
+         * Called when the media router has been released.
+         */
+        public void onReleased() { }
+
+        /**
+         * Called when the discovery state has changed.
+         *
+         * @param state The new discovery state: one of
+         * {@link #DISCOVERY_STATE_STOPPED} or {@link #DISCOVERY_STATE_STARTED}.
+         */
+        public void onDiscoveryStateChanged(@DiscoveryState int state) { }
+
+        /**
+         * Called when the connection state has changed.
+         *
+         * @param state The new connection state: one of
+         * {@link #CONNECTION_STATE_DISCONNECTED}, {@link #CONNECTION_STATE_CONNECTING}
+         * or {@link #CONNECTION_STATE_CONNECTED}.
+         */
+        public void onConnectionStateChanged(@ConnectionState int state) { }
+
+        /**
+         * Called when the selected destination has changed.
+         *
+         * @param destination The new selected destination, or null if none.
+         */
+        public void onSelectedDestinationChanged(@Nullable DestinationInfo destination) { }
+
+        /**
+         * Called when route discovery has started.
+         */
+        public void onDiscoveryStarted() { }
+
+        /**
+         * Called when route discovery has stopped normally.
+         * <p>
+         * Abnormal termination is reported via {@link #onDiscoveryFailed}.
+         * </p>
+         */
+        public void onDiscoveryStopped() { }
+
+        /**
+         * Called when discovery has failed in a non-recoverable manner.
+         *
+         * @param error The error code: one of
+         * {@link MediaRouter#DISCOVERY_ERROR_UNKNOWN},
+         * {@link MediaRouter#DISCOVERY_ERROR_ABORTED},
+         * or {@link MediaRouter#DISCOVERY_ERROR_NO_CONNECTIVITY}.
+         * @param message The localized error message, or null if none.  This message
+         * may be shown to the user.
+         * @param extras Additional information about the error which a client
+         * may use, or null if none.
+         */
+        public void onDiscoveryFailed(@DiscoveryError int error, @Nullable CharSequence message,
+                @Nullable Bundle extras) { }
+
+        /**
+         * Called when a new destination is found or has changed during discovery.
+         * <p>
+         * Certain destinations may be omitted because they have been filtered
+         * out by the media router's routing callback.
+         * </p>
+         *
+         * @param destination The destination that was found.
+         */
+        public void onDestinationFound(@NonNull DestinationInfo destination) { }
+
+        /**
+         * Called when a destination is no longer reachable or is no longer
+         * offering any routes that satisfy the discovery request.
+         *
+         * @param destination The destination that went away.
+         */
+        public void onDestinationLost(@NonNull DestinationInfo destination) { }
+
+        /**
+         * Called when a connection attempt begins.
+         */
+        public void onConnecting() { }
+
+        /**
+         * Called when the connection succeeds.
+         */
+        public void onConnected() { }
+
+        /**
+         * Called when the connection is terminated normally.
+         * <p>
+         * Abnormal termination is reported via {@link #onConnectionFailed}.
+         * </p>
+         */
+        public void onDisconnected() { }
+
+        /**
+         * Called when a connection attempt or connection in
+         * progress has failed in a non-recoverable manner.
+         *
+         * @param error The error code: one of
+         * {@link MediaRouter#CONNECTION_ERROR_ABORTED},
+         * {@link MediaRouter#CONNECTION_ERROR_UNAUTHORIZED},
+         * {@link MediaRouter#CONNECTION_ERROR_UNREACHABLE},
+         * {@link MediaRouter#CONNECTION_ERROR_BUSY},
+         * {@link MediaRouter#CONNECTION_ERROR_TIMEOUT},
+         * {@link MediaRouter#CONNECTION_ERROR_BROKEN},
+         * or {@link MediaRouter#CONNECTION_ERROR_BARGED}.
+         * @param message The localized error message, or null if none.  This message
+         * may be shown to the user.
+         * @param extras Additional information about the error which a client
+         * may use, or null if none.
+         */
+        public void onConnectionFailed(@ConnectionError int error,
+                @Nullable CharSequence message, @Nullable Bundle extras) { }
+    }
+}
diff --git a/media/java/android/media/routing/ParcelableConnectionInfo.aidl b/media/java/android/media/routing/ParcelableConnectionInfo.aidl
new file mode 100644
index 0000000..4a9ec94
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableConnectionInfo.aidl
@@ -0,0 +1,18 @@
+/* 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.media.routing;
+
+parcelable ParcelableConnectionInfo;
diff --git a/media/java/android/media/routing/ParcelableConnectionInfo.java b/media/java/android/media/routing/ParcelableConnectionInfo.java
new file mode 100644
index 0000000..45cfe9f
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableConnectionInfo.java
@@ -0,0 +1,71 @@
+/*
+ * 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.routing;
+
+import android.media.AudioAttributes;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Internal parcelable representation of a media route connection.
+ */
+class ParcelableConnectionInfo implements Parcelable {
+    public AudioAttributes audioAttributes;
+    public int presentationDisplayId = -1;
+    // todo: volume
+    public IBinder[] protocolBinders;
+    public Bundle extras;
+
+    public static final Parcelable.Creator<ParcelableConnectionInfo> CREATOR =
+            new Parcelable.Creator<ParcelableConnectionInfo>() {
+        @Override
+        public ParcelableConnectionInfo createFromParcel(Parcel source) {
+            ParcelableConnectionInfo info = new ParcelableConnectionInfo();
+            if (source.readInt() != 0) {
+                info.audioAttributes = AudioAttributes.CREATOR.createFromParcel(source);
+            }
+            info.presentationDisplayId = source.readInt();
+            info.protocolBinders = source.createBinderArray();
+            info.extras = source.readBundle();
+            return info;
+        }
+
+        @Override
+        public ParcelableConnectionInfo[] newArray(int size) {
+            return new ParcelableConnectionInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (audioAttributes != null) {
+            dest.writeInt(1);
+            audioAttributes.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+        dest.writeInt(presentationDisplayId);
+        dest.writeBinderArray(protocolBinders);
+        dest.writeBundle(extras);
+    }
+}
diff --git a/media/java/android/media/routing/ParcelableDestinationInfo.aidl b/media/java/android/media/routing/ParcelableDestinationInfo.aidl
new file mode 100644
index 0000000..bf1c198
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableDestinationInfo.aidl
@@ -0,0 +1,18 @@
+/* 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.media.routing;
+
+parcelable ParcelableDestinationInfo;
diff --git a/media/java/android/media/routing/ParcelableDestinationInfo.java b/media/java/android/media/routing/ParcelableDestinationInfo.java
new file mode 100644
index 0000000..eca5eec
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableDestinationInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.routing;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Internal parcelable representation of a media destination.
+ */
+class ParcelableDestinationInfo implements Parcelable {
+    public String id;
+    public CharSequence name;
+    public CharSequence description;
+    public int iconResourceId;
+    public Bundle extras;
+
+    public static final Parcelable.Creator<ParcelableDestinationInfo> CREATOR =
+            new Parcelable.Creator<ParcelableDestinationInfo>() {
+        @Override
+        public ParcelableDestinationInfo createFromParcel(Parcel source) {
+            ParcelableDestinationInfo info = new ParcelableDestinationInfo();
+            info.id = source.readString();
+            info.name = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            info.description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+            info.iconResourceId = source.readInt();
+            info.extras = source.readBundle();
+            return info;
+        }
+
+        @Override
+        public ParcelableDestinationInfo[] newArray(int size) {
+            return new ParcelableDestinationInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(id);
+        TextUtils.writeToParcel(name, dest, flags);
+        TextUtils.writeToParcel(description, dest, flags);
+        dest.writeInt(iconResourceId);
+        dest.writeBundle(extras);
+    }
+}
diff --git a/media/java/android/media/routing/ParcelableRouteInfo.aidl b/media/java/android/media/routing/ParcelableRouteInfo.aidl
new file mode 100644
index 0000000..126afaa
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableRouteInfo.aidl
@@ -0,0 +1,18 @@
+/* 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.media.routing;
+
+parcelable ParcelableRouteInfo;
diff --git a/media/java/android/media/routing/ParcelableRouteInfo.java b/media/java/android/media/routing/ParcelableRouteInfo.java
new file mode 100644
index 0000000..fb1a547
--- /dev/null
+++ b/media/java/android/media/routing/ParcelableRouteInfo.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.routing;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Internal parcelable representation of a media route.
+ */
+class ParcelableRouteInfo implements Parcelable {
+    public String id;
+    public int selectorIndex; // index of selector within list used for discovery
+    public int features;
+    public String[] protocols;
+    public Bundle extras;
+
+    public static final Parcelable.Creator<ParcelableRouteInfo> CREATOR =
+            new Parcelable.Creator<ParcelableRouteInfo>() {
+        @Override
+        public ParcelableRouteInfo createFromParcel(Parcel source) {
+            ParcelableRouteInfo info = new ParcelableRouteInfo();
+            info.id = source.readString();
+            info.selectorIndex = source.readInt();
+            info.features = source.readInt();
+            info.protocols = source.createStringArray();
+            info.extras = source.readBundle();
+            return info;
+        }
+
+        @Override
+        public ParcelableRouteInfo[] newArray(int size) {
+            return new ParcelableRouteInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(id);
+        dest.writeInt(selectorIndex);
+        dest.writeInt(features);
+        dest.writeStringArray(protocols);
+        dest.writeBundle(extras);
+    }
+}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index bd0019f..af3b72e 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -19,6 +19,7 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
+import android.media.routing.IMediaRouter;
 import android.media.session.ISessionController;
 import android.media.session.PlaybackState;
 import android.media.session.MediaSession;
@@ -34,6 +35,7 @@
     ISessionController getController();
     void setFlags(int flags);
     void setActive(boolean active);
+    void setMediaRouter(in IMediaRouter router);
     void setMediaButtonReceiver(in PendingIntent mbr);
     void setLaunchPendingIntent(in PendingIntent pi);
     void destroy();
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index d684688..e2d06d3 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -20,6 +20,8 @@
 import android.content.pm.ParceledListSlice;
 import android.media.MediaMetadata;
 import android.media.Rating;
+import android.media.routing.IMediaRouterDelegate;
+import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISessionControllerCallback;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
@@ -49,6 +51,8 @@
     void adjustVolume(int direction, int flags, String packageName);
     void setVolumeTo(int value, int flags, String packageName);
 
+    IMediaRouterDelegate createMediaRouterDelegate(IMediaRouterStateCallback callback);
+
     // These commands are for the TransportControls
     void play();
     void playFromMediaId(String uri, in Bundle extras);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index dd6bd20..c23a139 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -26,6 +26,7 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.routing.MediaRouter;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -119,6 +120,17 @@
     }
 
     /**
+     * Creates a media router delegate through which the destination of the media
+     * router may be observed and controlled.
+     *
+     * @return The media router delegate, or null if the media session does
+     * not support media routing.
+     */
+    public @Nullable MediaRouter.Delegate createMediaRouterDelegate() {
+        return new MediaRouter.Delegate();
+    }
+
+    /**
      * Send the specified media button event to the session. Only media keys can
      * be sent by this method, other keys will be ignored.
      *
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index df4bc78..cc602c9 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -29,7 +29,7 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
-import android.net.Uri;
+import android.media.routing.MediaRouter;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -224,6 +224,23 @@
     }
 
     /**
+     * Associates a {@link MediaRouter} with this session to control the destination
+     * of media content.
+     * <p>
+     * A media router may only be associated with at most one session at a time.
+     * </p>
+     *
+     * @param router The media router, or null to remove the current association.
+     */
+    public void setMediaRouter(@Nullable MediaRouter router) {
+        try {
+            mBinder.setMediaRouter(router != null ? router.getBinder() : null);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+        }
+    }
+
+    /**
      * Set a pending intent for your media button receiver to allow restarting
      * playback after the session has been stopped. If your app is started in
      * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 7ea269b..3276f0c 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -30,12 +30,9 @@
 import android.media.MediaMetadataEditor;
 import android.media.MediaMetadataRetriever;
 import android.media.Rating;
-import android.media.RemoteControlClient;
-import android.media.RemoteControlClient.MetadataEditor;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -221,14 +218,10 @@
                 mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
                         direction, flags);
             } else if (isMute) {
-                if (down) {
-                    // We need to send two volume events on down, one to mute
-                    // and one to show the UI
+                if (down && keyEvent.getRepeatCount() == 0) {
                     mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                            MediaSessionManager.DIRECTION_MUTE, flags);
+                            AudioManager.ADJUST_TOGGLE_MUTE, flags);
                 }
-                mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                        0 /* direction, causes UI to show on down */, flags);
             }
         }
     }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index a4ef851..6ac0efb 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -29,7 +29,6 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -59,14 +58,6 @@
     private Context mContext;
 
     /**
-     * Special flag for sending the mute key to dispatchAdjustVolume used by the
-     * system.
-     *
-     * @hide
-     */
-    public static final int DIRECTION_MUTE = -99;
-
-    /**
      * @hide
      */
     public MediaSessionManager(Context context) {
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 54d0acd..6807e7f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -23,8 +23,6 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.text.TextUtils;
-import android.util.Log;
-
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5b92266..bc9722e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -756,8 +756,9 @@
          * </p><p>
          * Note that this sub-directory also supports opening the logo as an asset file in write
          * mode.  Callers can create or replace the primary logo associated with this channel by
-         * opening the asset file and writing the full-size photo contents into it.  When the file
-         * is closed, the image will be parsed, sized down if necessary, and stored.
+         * opening the asset file and writing the full-size photo contents into it. (Make sure there
+         * is no padding around the logo image.) When the file is closed, the image will be parsed,
+         * sized down if necessary, and stored.
          * </p><p>
          * Usage example:
          * <pre>
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index b7e766b..6607765 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -48,7 +48,6 @@
 import android.view.accessibility.CaptioningManager;
 import android.widget.FrameLayout;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 
 import java.util.ArrayList;
@@ -615,13 +614,16 @@
         public void onSetMain(boolean isMain) {
         }
 
-        /**
-         * Sets the {@link Surface} for the current input session on which the TV input renders
-         * video.
-         *
-         * @param surface {@link Surface} an application passes to this TV input session.
-         * @return {@code true} if the surface was set, {@code false} otherwise.
-         */
+    /**
+     * Sets the {@link Surface} for the current input session on which the TV input renders video.
+     * <p>
+     * When {@code setSurface(null)} is called, the implementation should stop using the Surface
+     * object previously given and release any references to it.
+     *
+     * @param surface possibly {@code null} {@link Surface} an application passes to this TV input
+     *        session.
+     * @return {@code true} if the surface was set, {@code false} otherwise.
+     */
         public abstract boolean onSetSurface(Surface surface);
 
         /**
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 5d9355a..3541fba 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -28,7 +28,6 @@
 import android.media.MediaScanner;
 import android.net.Uri;
 import android.os.BatteryManager;
-import android.os.BatteryStats;
 import android.os.RemoteException;
 import android.provider.MediaStore;
 import android.provider.MediaStore.Audio;
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index 01285ee..f01fc07 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -6,6 +6,7 @@
 import android.service.media.IMediaBrowserServiceCallbacks;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ResultReceiver;
 
 /**
  * Media API allows clients to browse through hierarchy of a user’s media collection,
@@ -18,4 +19,5 @@
 
     void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
     void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
+    void getMediaItem(String uri, in ResultReceiver cb);
 }
\ No newline at end of file
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 26aedbd..41156cb 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -16,7 +16,6 @@
 
 package android.service.media;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -32,8 +31,10 @@
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.service.media.IMediaBrowserService;
 import android.service.media.IMediaBrowserServiceCallbacks;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -74,6 +75,13 @@
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
 
+    /**
+     * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
+     *
+     * @hide
+     */
+    public static final String KEY_MEDIA_ITEM = "media_item";
+
     private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
     private final Handler mHandler = new Handler();
     private ServiceBinder mBinder;
@@ -261,6 +269,33 @@
                 }
             });
         }
+
+        @Override
+        public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
+            if (TextUtils.isEmpty(mediaId) || receiver == null) {
+                return;
+            }
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    final Result<MediaBrowser.MediaItem> result
+                            = new Result<MediaBrowser.MediaItem>(mediaId) {
+                        @Override
+                        void onResultSent(MediaBrowser.MediaItem item) {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(KEY_MEDIA_ITEM, item);
+                            receiver.send(0, bundle);
+                        }
+                    };
+                    try {
+                        MediaBrowserService.this.getMediaItem(mediaId, result);
+                    } catch (UnsupportedOperationException e) {
+                        receiver.send(-1, null);
+                    }
+                }
+            });
+        }
     }
 
     @Override
@@ -284,20 +319,21 @@
     /**
      * Called to get the root information for browsing by a particular client.
      * <p>
-     * The implementation should verify that the client package has
-     * permission to access browse media information before returning
-     * the root id; it should return null if the client is not
-     * allowed to access this information.
+     * The implementation should verify that the client package has permission
+     * to access browse media information before returning the root id; it
+     * should return null if the client is not allowed to access this
+     * information.
      * </p>
      *
-     * @param clientPackageName The package name of the application
-     * which is requesting access to browse media.
-     * @param clientUid The uid of the application which is requesting
-     * access to browse media.
+     * @param clientPackageName The package name of the application which is
+     *            requesting access to browse media.
+     * @param clientUid The uid of the application which is requesting access to
+     *            browse media.
      * @param rootHints An optional bundle of service-specific arguments to send
-     * to the media browse service when connecting and retrieving the root id
-     * for browsing, or null if none.  The contents of this bundle may affect
-     * the information returned when browsing.
+     *            to the media browse service when connecting and retrieving the
+     *            root id for browsing, or null if none. The contents of this
+     *            bundle may affect the information returned when browsing.
+     * @return The {@link BrowserRoot} for accessing this app's content or null.
      */
     public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
             int clientUid, @Nullable Bundle rootHints);
@@ -305,24 +341,51 @@
     /**
      * Called to get information about the children of a media item.
      * <p>
-     * Implementations must call result.{@link Result#sendResult result.sendResult} with the list
-     * of children. If loading the children will be an expensive operation that should be performed
-     * on another thread, result.{@link Result#detach result.detach} may be called before returning
-     * from this function, and then {@link Result#sendResult result.sendResult} called when
-     * the loading is complete.
+     * Implementations must call {@link Result#sendResult result.sendResult}
+     * with the list of children. If loading the children will be an expensive
+     * operation that should be performed on another thread,
+     * {@link Result#detach result.detach} may be called before returning from
+     * this function, and then {@link Result#sendResult result.sendResult}
+     * called when the loading is complete.
      *
-     * @param parentId The id of the parent media item whose
-     * children are to be queried.
-     * @return The list of children, or null if the id is invalid.
+     * @param parentId The id of the parent media item whose children are to be
+     *            queried.
+     * @param result The Result to send the list of children to, or null if the
+     *            id is invalid.
      */
     public abstract void onLoadChildren(@NonNull String parentId,
             @NonNull Result<List<MediaBrowser.MediaItem>> result);
 
     /**
+     * Called to get a specific media item. The mediaId should be the same id
+     * that would be returned for this item when it is in a list of child items.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}. If
+     * loading the item will be an expensive operation {@link Result#detach
+     * result.detach} may be called before returning from this function, and
+     * then {@link Result#sendResult result.sendResult} called when the item has
+     * been loaded.
+     * <p>
+     * The default implementation throws an exception.
+     *
+     * @param mediaId The id for the specific
+     *            {@link android.media.browse.MediaBrowser.MediaItem}.
+     * @param result The Result to send the item to, or null if the id is
+     *            invalid.
+     * @throws UnsupportedOperationException
+     */
+    public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
+            throws UnsupportedOperationException {
+        throw new UnsupportedOperationException("getMediaItem is not supported.");
+    }
+
+    /**
      * Call to set the media session.
      * <p>
      * This should be called as soon as possible during the service's startup.
      * It may only be called once.
+     *
+     * @param token The token for the service's {@link MediaSession}.
      */
     public void setSessionToken(final MediaSession.Token token) {
         if (token == null) {
@@ -405,12 +468,10 @@
      */
     private void addSubscription(String id, ConnectionRecord connection) {
         // Save the subscription
-        final boolean added = connection.subscriptions.add(id);
+        connection.subscriptions.add(id);
 
-        // If this is a new subscription, send the results
-        if (added) {
-            performLoadChildren(id, connection);
-        }
+        // send the results
+        performLoadChildren(id, connection);
     }
 
     /**
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 90fe695..4ebbe26 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -64,7 +64,7 @@
     $(PV_INCLUDES) \
     $(JNI_H_INCLUDE)
 
-LOCAL_CFLAGS +=
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 LOCAL_MODULE:= libmedia_jni
 
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index 3df6530..afb5d5c 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -50,7 +50,7 @@
 };
 
 static jlong android_media_AmrInputStream_GsmAmrEncoderNew
-        (JNIEnv *env, jclass clazz) {
+        (JNIEnv *env, jclass /* clazz */) {
     GsmAmrEncoderState* gae = new GsmAmrEncoderState();
     if (gae == NULL) {
         jniThrowRuntimeException(env, "Out of memory");
@@ -59,7 +59,7 @@
 }
 
 static void android_media_AmrInputStream_GsmAmrEncoderInitialize
-        (JNIEnv *env, jclass clazz, jlong gae) {
+        (JNIEnv *env, jclass /* clazz */, jlong gae) {
     GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae;
     int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false);
     if (nResult != OK) {
@@ -69,7 +69,7 @@
 }
 
 static jint android_media_AmrInputStream_GsmAmrEncoderEncode
-        (JNIEnv *env, jclass clazz,
+        (JNIEnv *env, jclass /* clazz */,
          jlong gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) {
 
     jbyte inBuf[BYTES_PER_FRAME];
@@ -105,7 +105,7 @@
 }
 
 static void android_media_AmrInputStream_GsmAmrEncoderCleanup
-        (JNIEnv *env, jclass clazz, jlong gae) {
+        (JNIEnv* /* env */, jclass /* clazz */, jlong gae) {
     GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae;
     AMREncodeExit(&state->mEncState, &state->mSidState);
     state->mEncState = NULL;
@@ -113,7 +113,7 @@
 }
 
 static void android_media_AmrInputStream_GsmAmrEncoderDelete
-        (JNIEnv *env, jclass clazz, jlong gae) {
+        (JNIEnv* /* env */, jclass /* clazz */, jlong gae) {
     delete (GsmAmrEncoderState*)gae;
 }
 
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 890b039..b247493 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -95,6 +95,9 @@
     void setBufferFormat(int format) { mFormat = format; }
     int getBufferFormat() { return mFormat; }
 
+    void setBufferDataspace(android_dataspace dataSpace) { mDataSpace = dataSpace; }
+    android_dataspace getBufferDataspace() { return mDataSpace; }
+
     void setBufferWidth(int width) { mWidth = width; }
     int getBufferWidth() { return mWidth; }
 
@@ -111,6 +114,7 @@
     jobject mWeakThiz;
     jclass mClazz;
     int mFormat;
+    android_dataspace mDataSpace;
     int mWidth;
     int mHeight;
 };
@@ -263,29 +267,6 @@
     env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer));
 }
 
-// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
-// graphics.h, need convert to the one defined in graphics.h here.
-static int Image_getPixelFormat(JNIEnv* env, int format)
-{
-    int jpegFormat;
-    jfieldID fid;
-
-    ALOGV("%s: format = 0x%x", __FUNCTION__, format);
-
-    jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
-    ALOG_ASSERT(imageFormatClazz != NULL);
-
-    fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
-    jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
-
-    // Translate the JPEG to BLOB for camera purpose.
-    if (format == jpegFormat) {
-        format = HAL_PIXEL_FORMAT_BLOB;
-    }
-
-    return format;
-}
-
 static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
 {
     ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
@@ -430,7 +411,7 @@
             pData = buffer->data;
             dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
             break;
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // Single plane 16bpp bayer data.
             bytesPerPixel = 2;
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -483,7 +464,7 @@
 }
 
 static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t readerFormat)
+        int32_t halReaderFormat)
 {
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
     ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
@@ -493,7 +474,7 @@
 
     int32_t fmt = buffer->flexFormat;
 
-    fmt = applyFormatOverrides(fmt, readerFormat);
+    fmt = applyFormatOverrides(fmt, halReaderFormat);
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
@@ -505,7 +486,6 @@
         case HAL_PIXEL_FORMAT_Y8:
             // Single plane 8bpp data.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-            pixelStride;
             break;
         case HAL_PIXEL_FORMAT_YV12:
             pixelStride = 1;
@@ -518,7 +498,7 @@
             pixelStride = 0;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
         case HAL_PIXEL_FORMAT_RGB_565:
             // Single plane 16bpp data.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -544,7 +524,7 @@
 }
 
 static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
-        int32_t readerFormat)
+        int32_t halReaderFormat)
 {
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
     ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
@@ -554,7 +534,7 @@
 
     int32_t fmt = buffer->flexFormat;
 
-    fmt = applyFormatOverrides(fmt, readerFormat);
+    fmt = applyFormatOverrides(fmt, halReaderFormat);
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
@@ -585,7 +565,7 @@
             rowStride = buffer->stride;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // In native side, strides are specified in pixels, not in bytes.
             // Single plane 16bpp bayer data. even width/height,
             // row stride multiple of 16 pixels (32 bytes)
@@ -683,11 +663,16 @@
 {
     status_t res;
     int nativeFormat;
+    android_dataspace nativeDataspace;
 
     ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
           __FUNCTION__, width, height, format, maxImages);
 
-    nativeFormat = Image_getPixelFormat(env, format);
+    PublicFormat publicFormat = static_cast<PublicFormat>(format);
+    nativeFormat = android_view_Surface_mapPublicFormatToHalFormat(
+        publicFormat);
+    nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
+        publicFormat);
 
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
@@ -711,10 +696,11 @@
     consumer->setFrameAvailableListener(ctx);
     ImageReader_setNativeContext(env, thiz, ctx);
     ctx->setBufferFormat(nativeFormat);
+    ctx->setBufferDataspace(nativeDataspace);
     ctx->setBufferWidth(width);
     ctx->setBufferHeight(height);
 
-    // Set the width/height/format to the CpuConsumer
+    // Set the width/height/format/dataspace to the CpuConsumer
     res = consumer->setDefaultBufferSize(width, height);
     if (res != OK) {
         jniThrowException(env, "java/lang/IllegalStateException",
@@ -726,6 +712,12 @@
         jniThrowException(env, "java/lang/IllegalStateException",
                           "Failed to set CpuConsumer buffer format");
     }
+    res = consumer->setDefaultBufferDataSpace(nativeDataspace);
+    if (res != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set CpuConsumer buffer dataSpace");
+    }
+
 }
 
 static void ImageReader_close(JNIEnv* env, jobject thiz)
@@ -885,6 +877,8 @@
 static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
 {
     int rowStride, pixelStride;
+    PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
+
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
 
     CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
@@ -894,10 +888,11 @@
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    readerFormat = Image_getPixelFormat(env, readerFormat);
+    int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
+        publicReaderFormat);
 
-    rowStride = Image_imageGetRowStride(env, buffer, idx, readerFormat);
-    pixelStride = Image_imageGetPixelStride(env, buffer, idx, readerFormat);
+    rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
+    pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
 
     jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
             gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
@@ -910,6 +905,7 @@
     uint8_t *base = NULL;
     uint32_t size = 0;
     jobject byteBuffer;
+    PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
 
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
 
@@ -919,10 +915,11 @@
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    readerFormat = Image_getPixelFormat(env, readerFormat);
+    int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
+            readerPublicFormat);
 
     // Create byteBuffer from native buffer
-    Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerFormat);
+    Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
 
     if (size > static_cast<uint32_t>(INT32_MAX)) {
         // Byte buffer have 'int capacity', so check the range
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 1cf589d..16758d0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -215,7 +215,7 @@
 status_t JMediaCodec::setCallback(jobject cb) {
     if (cb != NULL) {
         if (mCallbackNotification == NULL) {
-            mCallbackNotification = new AMessage(kWhatCallbackNotify, id());
+            mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
         }
     } else {
         mCallbackNotification.clear();
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 12eb7d2..f8c349b 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -42,7 +42,7 @@
 }
 
 static jint android_media_MediaCodecList_getCodecCount(
-        JNIEnv *env, jobject thiz) {
+        JNIEnv *env, jobject /* thiz */) {
     sp<IMediaCodecList> mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
@@ -52,7 +52,7 @@
 }
 
 static jstring android_media_MediaCodecList_getCodecName(
-        JNIEnv *env, jobject thiz, jint index) {
+        JNIEnv *env, jobject /* thiz */, jint index) {
     sp<IMediaCodecList> mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
@@ -70,7 +70,7 @@
 }
 
 static jint android_media_MediaCodecList_findCodecByName(
-        JNIEnv *env, jobject thiz, jstring name) {
+        JNIEnv *env, jobject /* thiz */, jstring name) {
     if (name == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return -ENOENT;
@@ -95,7 +95,7 @@
 }
 
 static jboolean android_media_MediaCodecList_isEncoder(
-        JNIEnv *env, jobject thiz, jint index) {
+        JNIEnv *env, jobject /* thiz */, jint index) {
     sp<IMediaCodecList> mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
@@ -112,7 +112,7 @@
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
-        JNIEnv *env, jobject thiz, jint index) {
+        JNIEnv *env, jobject /* thiz */, jint index) {
     sp<IMediaCodecList> mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
@@ -144,7 +144,7 @@
 }
 
 static jobject android_media_MediaCodecList_getCodecCapabilities(
-        JNIEnv *env, jobject thiz, jint index, jstring type) {
+        JNIEnv *env, jobject /* thiz */, jint index, jstring type) {
     if (type == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return NULL;
@@ -262,7 +262,7 @@
     return caps;
 }
 
-static void android_media_MediaCodecList_native_init(JNIEnv *env) {
+static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index a6f8dcd..d2216fb 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -224,7 +224,7 @@
 }
 
 static jboolean android_media_MediaCrypto_isCryptoSchemeSupportedNative(
-        JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
+        JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj) {
     jsize uuidLength = env->GetArrayLength(uuidObj);
 
     if (uuidLength != 16) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 8e07ec0..8302a34 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -92,6 +92,7 @@
     jint kEventKeyRequired;
     jint kEventKeyExpired;
     jint kEventVendorDefined;
+    jint kEventSessionReclaimed;
 } gEventTypes;
 
 struct KeyTypes {
@@ -194,6 +195,9 @@
         case DrmPlugin::kDrmPluginEventVendorDefined:
             jeventType = gEventTypes.kEventVendorDefined;
             break;
+        case DrmPlugin::kDrmPluginEventSessionReclaimed:
+            jeventType = gEventTypes.kEventSessionReclaimed;
+            break;
         default:
             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
             return;
@@ -438,9 +442,11 @@
     Entry e = s.next();
 */
 
-static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
+static KeyedVector<String8, String8> HashMapToKeyedVector(
+    JNIEnv *env, jobject &hashMap, bool* pIsOK) {
     jclass clazz = gFields.stringClassId;
     KeyedVector<String8, String8> keyedVector;
+    *pIsOK = true;
 
     jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
     if (entrySet) {
@@ -451,16 +457,22 @@
                 jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
                 if (entry) {
                     jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
-                    if (!env->IsInstanceOf(obj, clazz)) {
+                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
                         jniThrowException(env, "java/lang/IllegalArgumentException",
                                           "HashMap key is not a String");
+                        env->DeleteLocalRef(entry);
+                        *pIsOK = false;
+                        break;
                     }
                     jstring jkey = static_cast<jstring>(obj);
 
                     obj = env->CallObjectMethod(entry, gFields.entry.getValue);
-                    if (!env->IsInstanceOf(obj, clazz)) {
+                    if (obj == NULL || !env->IsInstanceOf(obj, clazz)) {
                         jniThrowException(env, "java/lang/IllegalArgumentException",
                                           "HashMap value is not a String");
+                        env->DeleteLocalRef(entry);
+                        *pIsOK = false;
+                        break;
                     }
                     jstring jvalue = static_cast<jstring>(obj);
 
@@ -565,6 +577,8 @@
     gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
     gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
+    gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
 
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
     gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
@@ -667,7 +681,7 @@
 }
 
 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
-    JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) {
+    JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
 
     if (uuidObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -763,7 +777,11 @@
 
     KeyedVector<String8, String8> optParams;
     if (joptParams != NULL) {
-        optParams = HashMapToKeyedVector(env, joptParams);
+        bool isOK;
+        optParams = HashMapToKeyedVector(env, joptParams, &isOK);
+        if (!isOK) {
+            return NULL;
+        }
     }
 
     Vector<uint8_t> request;
@@ -1173,7 +1191,7 @@
 }
 
 static void android_media_MediaDrm_setCipherAlgorithmNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jstring jalgorithm) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1197,7 +1215,7 @@
 }
 
 static void android_media_MediaDrm_setMacAlgorithmNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jstring jalgorithm) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1222,7 +1240,7 @@
 
 
 static jbyteArray android_media_MediaDrm_encryptNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1253,7 +1271,7 @@
 }
 
 static jbyteArray android_media_MediaDrm_decryptNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1283,7 +1301,7 @@
 }
 
 static jbyteArray android_media_MediaDrm_signNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jbyteArray jkeyId, jbyteArray jmessage) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1313,7 +1331,7 @@
 }
 
 static jboolean android_media_MediaDrm_verifyNative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
@@ -1342,7 +1360,7 @@
 
 
 static jbyteArray android_media_MediaDrm_signRSANative(
-    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    JNIEnv *env, jobject /* thiz */, jobject jdrm, jbyteArray jsessionId,
     jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
 
     sp<IDrm> drm = GetDrm(env, jdrm);
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 52e9910..c0795b6 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -93,7 +93,7 @@
         env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
         env->DeleteLocalRef(byteArrayObj);
         if (env->ExceptionCheck()) {
-            ALOGW("Exception occurred while reading %zu at %lld", size, offset);
+            ALOGW("Exception occurred while reading %zu at %lld", size, (long long)offset);
             LOGW_EX(env);
             env->ExceptionClear();
             return -1;
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index e5a0c16e..9f62506 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -30,7 +30,7 @@
 namespace android {
 
 struct IMediaHTTPService;
-struct MetaData;
+class MetaData;
 struct NuMediaExtractor;
 
 struct JMediaExtractor : public RefBase {
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 0e7d83e..7226ef5 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -128,7 +128,7 @@
         JNIEnv *env, jobject thiz) {
     sp<JMediaHTTPConnection> conn = getObject(env, thiz);
 
-    return javaObjectForIBinder(env, conn->getIMemory()->asBinder());
+    return javaObjectForIBinder(env, IInterface::asBinder(conn->getIMemory()));
 }
 
 static jint android_media_MediaHTTPConnection_native_readAt(
diff --git a/media/jni/android_media_MediaHTTPConnection.h b/media/jni/android_media_MediaHTTPConnection.h
index 62ff678..f87f1eb 100644
--- a/media/jni/android_media_MediaHTTPConnection.h
+++ b/media/jni/android_media_MediaHTTPConnection.h
@@ -24,8 +24,8 @@
 
 namespace android {
 
-struct IMemory;
-struct MemoryDealer;
+class IMemory;
+class MemoryDealer;
 
 struct JMediaHTTPConnection : public RefBase {
     enum {
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index fbe5340..2f6bbf4 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -33,13 +33,13 @@
 #include "android_media_Utils.h"
 #include "android_util_Binder.h"
 
+#include "android/graphics/GraphicsJNI.h"
 
 using namespace android;
 
 struct fields_t {
     jfieldID context;
     jclass bitmapClazz;  // Must be a global ref
-    jfieldID nativeBitmap;
     jmethodID createBitmapMethod;
     jmethodID createScaledBitmapMethod;
     jclass configClazz;  // Must be a global ref
@@ -77,7 +77,6 @@
 static void setRetriever(JNIEnv* env, jobject thiz, MediaMetadataRetriever* retriever)
 {
     // No lock is needed, since it is called internally by other methods that are protected
-    MediaMetadataRetriever *old = (MediaMetadataRetriever*) env->GetLongField(thiz, fields.context);
     env->SetLongField(thiz, fields.context, (jlong) retriever);
 }
 
@@ -229,7 +228,7 @@
 
 static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option)
 {
-    ALOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
+    ALOGV("getFrameAtTime: %lld us option: %d", (long long)timeUs, option);
     MediaMetadataRetriever* retriever = getRetriever(env, thiz);
     if (retriever == 0) {
         jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@@ -255,7 +254,7 @@
     jobject config = env->CallStaticObjectMethod(
                         fields.configClazz,
                         fields.createConfigMethod,
-                        SkBitmap::kRGB_565_Config);
+                        GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
 
     uint32_t width, height;
     bool swapWidthAndHeight = false;
@@ -282,8 +281,7 @@
         return NULL;
     }
 
-    SkBitmap *bitmap =
-            (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap);
+    SkBitmap *bitmap = GraphicsJNI::getSkBitmap(env, jBitmap);
 
     bitmap->lockPixels();
     rotate((uint16_t*)bitmap->getPixels(),
@@ -421,10 +419,6 @@
     if (fields.createScaledBitmapMethod == NULL) {
         return;
     }
-    fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "J");
-    if (fields.nativeBitmap == NULL) {
-        return;
-    }
 
     jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
     if (configClazz == NULL) {
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 3fef446f..ecb2ac8 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -41,7 +41,7 @@
 using namespace android;
 
 static jint android_media_MediaMuxer_addTrack(
-        JNIEnv *env, jclass clazz, jlong nativeObject, jobjectArray keys,
+        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jobjectArray keys,
         jobjectArray values) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer == NULL) {
@@ -71,7 +71,7 @@
 }
 
 static void android_media_MediaMuxer_writeSampleData(
-        JNIEnv *env, jclass clazz, jlong nativeObject, jint trackIndex,
+        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jint trackIndex,
         jobject byteBuf, jint offset, jint size, jlong timeUs, jint flags) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer == NULL) {
@@ -107,7 +107,7 @@
 
     if (dstSize < (offset + size)) {
         ALOGE("writeSampleData saw wrong dstSize %lld, size  %d, offset %d",
-              dstSize, size, offset);
+              (long long)dstSize, size, offset);
         if (byteArray != NULL) {
             env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
         }
@@ -146,7 +146,7 @@
 }
 
 static void android_media_MediaMuxer_setOrientationHint(
-        JNIEnv *env, jclass clazz, jlong nativeObject, jint degrees) {
+        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jint degrees) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
@@ -164,7 +164,7 @@
 }
 
 static void android_media_MediaMuxer_setLocation(
-        JNIEnv *env, jclass clazz, jlong nativeObject, jint latitude, jint longitude) {
+        JNIEnv *env, jclass /* clazz */, jlong nativeObject, jint latitude, jint longitude) {
     MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
 
     status_t res = muxer->setLocation(latitude, longitude);
@@ -175,7 +175,7 @@
     }
 }
 
-static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz,
+static void android_media_MediaMuxer_start(JNIEnv *env, jclass /* clazz */,
                                            jlong nativeObject) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer == NULL) {
@@ -193,7 +193,7 @@
 
 }
 
-static void android_media_MediaMuxer_stop(JNIEnv *env, jclass clazz,
+static void android_media_MediaMuxer_stop(JNIEnv *env, jclass /* clazz */,
                                           jlong nativeObject) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer == NULL) {
@@ -212,7 +212,7 @@
 }
 
 static void android_media_MediaMuxer_native_release(
-        JNIEnv *env, jclass clazz, jlong nativeObject) {
+        JNIEnv* /* env */, jclass clazz, jlong nativeObject) {
     sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
     if (muxer != NULL) {
         muxer->decStrong(clazz);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 73a924d..55643f7 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -402,6 +402,18 @@
 }
 
 static void
+android_media_MediaPlayer_setPlaybackRate(JNIEnv *env, jobject thiz, jfloat rate)
+{
+    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+    if (mp == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    ALOGV("setPlaybackRate: %f", rate);
+    process_media_player_call(env, thiz, mp->setPlaybackRate(rate), NULL, NULL);
+}
+
+static void
 android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec)
 {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
@@ -867,6 +879,7 @@
     {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
     {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
+    {"_setPlaybackRate",    "(F)V",                             (void *)android_media_MediaPlayer_setPlaybackRate},
     {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},
     {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
     {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
@@ -895,8 +908,6 @@
     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
 };
 
-static const char* const kClassPathName = "android/media/MediaPlayer";
-
 // This function only registers the native methods
 static int register_android_media_MediaPlayer(JNIEnv *env)
 {
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 007fc14..ca9db91 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -34,7 +34,7 @@
 // This function is called from a static block in MediaProfiles.java class,
 // which won't run until the first time an instance of this class is used.
 static void
-android_media_MediaProfiles_native_init(JNIEnv *env)
+android_media_MediaProfiles_native_init(JNIEnv* /* env */)
 {
     ALOGV("native_init");
     Mutex::Autolock lock(sLock);
@@ -45,14 +45,14 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_file_formats(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_file_formats(JNIEnv* /* env */, jobject /* thiz */)
 {
     ALOGV("native_get_num_file_formats");
     return (jint) sProfiles->getOutputFileFormats().size();
 }
 
 static jint
-android_media_MediaProfiles_native_get_file_format(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_file_format(JNIEnv *env, jobject /* thiz */, jint index)
 {
     ALOGV("native_get_file_format: %d", index);
     Vector<output_format> formats = sProfiles->getOutputFileFormats();
@@ -65,14 +65,15 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_video_encoders(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_video_encoders(JNIEnv* /* env */, jobject /* thiz */)
 {
     ALOGV("native_get_num_video_encoders");
     return sProfiles->getVideoEncoders().size();
 }
 
 static jobject
-android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject /* thiz */,
+                                                         jint index)
 {
     ALOGV("native_get_video_encoder_cap: %d", index);
     Vector<video_encoder> encoders = sProfiles->getVideoEncoders();
@@ -116,14 +117,15 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_audio_encoders(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_audio_encoders(JNIEnv* /* env */, jobject /* thiz */)
 {
     ALOGV("native_get_num_audio_encoders");
     return (jint) sProfiles->getAudioEncoders().size();
 }
 
 static jobject
-android_media_MediaProfiles_native_get_audio_encoder_cap(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_audio_encoder_cap(JNIEnv *env, jobject /* thiz */,
+                                                         jint index)
 {
     ALOGV("native_get_audio_encoder_cap: %d", index);
     Vector<audio_encoder> encoders = sProfiles->getAudioEncoders();
@@ -172,7 +174,8 @@
 }
 
 static jobject
-android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject thiz, jint id, jint quality)
+android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject /* thiz */, jint id,
+                                                         jint quality)
 {
     ALOGV("native_get_camcorder_profile: %d %d", id, quality);
     if (!isCamcorderQualityKnown(quality)) {
@@ -221,7 +224,8 @@
 }
 
 static jboolean
-android_media_MediaProfiles_native_has_camcorder_profile(JNIEnv *env, jobject thiz, jint id, jint quality)
+android_media_MediaProfiles_native_has_camcorder_profile(JNIEnv* /* env */, jobject /* thiz */,
+                                                         jint id, jint quality)
 {
     ALOGV("native_has_camcorder_profile: %d %d", id, quality);
     if (!isCamcorderQualityKnown(quality)) {
@@ -233,14 +237,15 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_video_decoders(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_video_decoders(JNIEnv* /* env */, jobject /* thiz */)
 {
     ALOGV("native_get_num_video_decoders");
     return (jint) sProfiles->getVideoDecoders().size();
 }
 
 static jint
-android_media_MediaProfiles_native_get_video_decoder_type(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_video_decoder_type(JNIEnv *env, jobject /* thiz */,
+                                                          jint index)
 {
     ALOGV("native_get_video_decoder_type: %d", index);
     Vector<video_decoder> decoders = sProfiles->getVideoDecoders();
@@ -254,14 +259,15 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_audio_decoders(JNIEnv *env, jobject thiz)
+android_media_MediaProfiles_native_get_num_audio_decoders(JNIEnv* /* env */, jobject /* thiz */)
 {
     ALOGV("native_get_num_audio_decoders");
     return (jint) sProfiles->getAudioDecoders().size();
 }
 
 static jint
-android_media_MediaProfiles_native_get_audio_decoder_type(JNIEnv *env, jobject thiz, jint index)
+android_media_MediaProfiles_native_get_audio_decoder_type(JNIEnv *env, jobject /* thiz */,
+                                                          jint index)
 {
     ALOGV("native_get_audio_decoder_type: %d", index);
     Vector<audio_decoder> decoders = sProfiles->getAudioDecoders();
@@ -275,14 +281,17 @@
 }
 
 static jint
-android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv *env, jobject thiz, jint cameraId)
+android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv* /* env */,
+                                                                         jobject /* thiz */,
+                                                                         jint cameraId)
 {
     ALOGV("native_get_num_image_encoding_quality_levels");
     return (jint) sProfiles->getImageEncodingQualityLevels(cameraId).size();
 }
 
 static jint
-android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject thiz, jint cameraId, jint index)
+android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject /* thiz */,
+                                                                    jint cameraId, jint index)
 {
     ALOGV("native_get_image_encoding_quality_level");
     Vector<int> levels = sProfiles->getImageEncodingQualityLevels(cameraId);
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index e9c80a0..8b7d40d 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -306,7 +306,7 @@
 android_media_MediaRecorder_setMaxFileSize(
         JNIEnv *env, jobject thiz, jlong max_filesize_bytes)
 {
-    ALOGV("setMaxFileSize(%lld)", max_filesize_bytes);
+    ALOGV("setMaxFileSize(%lld)", (long long)max_filesize_bytes);
     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
 
     char params[64];
@@ -462,11 +462,13 @@
     sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
     mr->setListener(listener);
 
-   // Convert client name jstring to String16
-    const char16_t *rawClientName = env->GetStringChars(packageName, NULL);
+    // Convert client name jstring to String16
+    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
+        env->GetStringChars(packageName, NULL));
     jsize rawClientNameLen = env->GetStringLength(packageName);
     String16 clientName(rawClientName, rawClientNameLen);
-    env->ReleaseStringChars(packageName, rawClientName);
+    env->ReleaseStringChars(packageName,
+                            reinterpret_cast<const jchar*>(rawClientName));
 
     // pass client package name for permissions tracking
     mr->setClientName(clientName);
@@ -508,8 +510,6 @@
     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
 };
 
-static const char* const kClassPathName = "android/media/MediaRecorder";
-
 // This function only registers the native methods, and is called from
 // JNI_OnLoad in android_media_MediaPlayer.cpp
 int register_android_media_MediaRecorder(JNIEnv *env)
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 321c2e3..1a9384e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -360,7 +360,6 @@
         env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
     }
 
-done:
     free(mediaAlbumArt);
     // if NewByteArray() returned NULL, an out-of-memory
     // exception will have been raised. I just want to
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index d5a4a17..1549a30 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -73,7 +73,7 @@
 static const int BUF_SIZE = 2048;
 
 
-static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass clazz,
+static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass /* clazz */,
          jbyteArray jIn,  jint jInOffset,
          jbyteArray jOut, jint jOutOffset,
          jint jNpoints) {
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 54c5e9b..e101709 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -136,8 +136,7 @@
     jstring keyObj = env->NewStringUTF(key);
     jobject valueObj = makeIntegerObject(env, value);
 
-    jobject res = env->CallObjectMethod(
-            hashMapObj, hashMapPutID, keyObj, valueObj);
+    env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj);
 
     env->DeleteLocalRef(valueObj); valueObj = NULL;
     env->DeleteLocalRef(keyObj); keyObj = NULL;
@@ -233,28 +232,28 @@
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-left", key).c_str(),
+                        AStringPrintf("%s-left", key).c_str(),
                         left);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-top", key).c_str(),
+                        AStringPrintf("%s-top", key).c_str(),
                         top);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-right", key).c_str(),
+                        AStringPrintf("%s-right", key).c_str(),
                         right);
 
                 SetMapInt32(
                         env,
                         hashMap,
                         hashMapPutID,
-                        StringPrintf("%s-bottom", key).c_str(),
+                        AStringPrintf("%s-bottom", key).c_str(),
                         bottom);
                 break;
             }
@@ -266,8 +265,7 @@
         if (valueObj != NULL) {
             jstring keyObj = env->NewStringUTF(key);
 
-            jobject res = env->CallObjectMethod(
-                    hashMap, hashMapPutID, keyObj, valueObj);
+            env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);
 
             env->DeleteLocalRef(keyObj); keyObj = NULL;
             env->DeleteLocalRef(valueObj); valueObj = NULL;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 8b2e203..713f28c 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -765,7 +765,7 @@
     return result;
 }
 
-static void foreachentry(ExifEntry *entry, void * /*user*/) {
+static void foreachentry(ExifEntry *entry, void* /* user */) {
     char buf[1024];
     ALOGI("entry %x, format %d, size %d: %s",
             entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
@@ -783,7 +783,6 @@
 
 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
                                             MtpObjectInfo& info) {
-    char            date[20];
     MtpString       path;
     int64_t         length;
     MtpObjectFormat format;
@@ -811,13 +810,15 @@
     info.mDateModified = longValues[1];
     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
 
-//    info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
-//                            MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
-//                            MTP_ASSOCIATION_TYPE_UNDEFINED);
+    if ((false)) {
+        info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
+                                MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
+                                MTP_ASSOCIATION_TYPE_UNDEFINED);
+    }
     info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
 
     jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
-    MtpString temp(str);
+    MtpString temp(reinterpret_cast<char16_t*>(str));
     info.mName = strdup((const char *)temp);
     env->ReleaseCharArrayElements(mStringBuffer, str, 0);
 
@@ -826,7 +827,9 @@
 
         ExifData *exifdata = exif_data_new_from_file(path);
         if (exifdata) {
-            //exif_data_foreach_content(exifdata, foreachcontent, NULL);
+            if ((false)) {
+                exif_data_foreach_content(exifdata, foreachcontent, NULL);
+            }
 
             // XXX get this from exif, or parse jpeg header instead?
             ExifEntry *w = exif_content_get_entry(
@@ -884,7 +887,8 @@
     }
 
     jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
-    outFilePath.setTo(str, strlen16(str));
+    outFilePath.setTo(reinterpret_cast<char16_t*>(str),
+                      strlen16(reinterpret_cast<char16_t*>(str)));
     env->ReleaseCharArrayElements(mStringBuffer, str, 0);
 
     jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
@@ -1179,8 +1183,6 @@
                                         (void *)android_mtp_MtpPropertyGroup_format_date_time},
 };
 
-static const char* const kClassPathName = "android/mtp/MtpDatabase";
-
 int register_android_mtp_MtpDatabase(JNIEnv *env)
 {
     jclass clazz;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 8e013a0..2dbd7dc 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -91,14 +91,6 @@
     return (MtpDevice*)env->GetLongField(javaDevice, field_context);
 }
 
-static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
-    if (env->ExceptionCheck()) {
-        ALOGE("An exception was thrown by callback '%s'.", methodName);
-        LOGE_EX(env);
-        env->ExceptionClear();
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static jboolean
@@ -425,8 +417,6 @@
                                         (void *)android_mtp_MtpDevice_import_file},
 };
 
-static const char* const kClassPathName = "android/mtp/MtpDevice";
-
 int register_android_mtp_MtpDevice(JNIEnv *env)
 {
     jclass clazz;
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 2f90dfe..2ce2a90 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -193,8 +193,6 @@
     {"native_remove_storage",       "(I)V", (void *)android_mtp_MtpServer_remove_storage},
 };
 
-static const char* const kClassPathName = "android/mtp/MtpServer";
-
 int register_android_mtp_MtpServer(JNIEnv *env)
 {
     jclass clazz;
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index 3b1fb19..5c22c9b 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -2,20 +2,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_AudioEffect.cpp \
-	android_media_Visualizer.cpp
+    android_media_AudioEffect.cpp \
+    android_media_Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcutils \
-	libutils \
-	libandroid_runtime \
-	libnativehelper \
-	libmedia
+    liblog \
+    libcutils \
+    libutils \
+    libandroid_runtime \
+    libnativehelper \
+    libmedia
 
 LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-effects)
+    $(call include-path-for, audio-effects)
 
 LOCAL_MODULE:= libaudioeffect_jni
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index b59a541..460277f 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -162,10 +162,6 @@
         uint8_t *fft,
         uint32_t samplingrate) {
 
-    int arg1 = 0;
-    int arg2 = 0;
-    size_t size;
-
     visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
@@ -486,7 +482,7 @@
 }
 
 static jintArray
-android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject thiz)
+android_media_visualizer_native_getCaptureSizeRange(JNIEnv *env, jobject /* thiz */)
 {
     jintArray jRange = env->NewIntArray(2);
     jint *nRange = env->GetIntArrayElements(jRange, NULL);
@@ -498,7 +494,7 @@
 }
 
 static jint
-android_media_visualizer_native_getMaxCaptureRate(JNIEnv *env, jobject thiz)
+android_media_visualizer_native_getMaxCaptureRate(JNIEnv* /* env */, jobject /* thiz */)
 {
     return (jint) Visualizer::getMaxCaptureRate();
 }
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index ed8d7c1..71ab013 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -2,16 +2,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	android_media_SoundPool_SoundPoolImpl.cpp
+    android_media_SoundPool_SoundPoolImpl.cpp \
+    SoundPool.cpp \
+    SoundPoolThread.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libcutils \
-	libutils \
-	libandroid_runtime \
-	libnativehelper \
-	libmedia
+    liblog \
+    libcutils \
+    libutils \
+    libandroid_runtime \
+    libnativehelper \
+    libmedia \
+    libmediandk \
+    libbinder
 
 LOCAL_MODULE:= libsoundpool
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
new file mode 100644
index 0000000..1205f9d
--- /dev/null
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool"
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+
+#define USE_SHARED_MEM_BUFFER
+
+#include <media/AudioTrack.h>
+#include <media/IMediaHTTPService.h>
+#include <media/mediaplayer.h>
+#include <media/stagefright/MediaExtractor.h>
+#include "SoundPool.h"
+#include "SoundPoolThread.h"
+#include <media/AudioPolicyHelper.h>
+#include <ndk/NdkMediaCodec.h>
+#include <ndk/NdkMediaExtractor.h>
+#include <ndk/NdkMediaFormat.h>
+
+namespace android
+{
+
+int kDefaultBufferCount = 4;
+uint32_t kMaxSampleRate = 48000;
+uint32_t kDefaultSampleRate = 44100;
+uint32_t kDefaultFrameCount = 1200;
+size_t kDefaultHeapSize = 1024 * 1024; // 1MB
+
+
+SoundPool::SoundPool(int maxChannels, const audio_attributes_t* pAttributes)
+{
+    ALOGV("SoundPool constructor: maxChannels=%d, attr.usage=%d, attr.flags=0x%x, attr.tags=%s",
+            maxChannels, pAttributes->usage, pAttributes->flags, pAttributes->tags);
+
+    // check limits
+    mMaxChannels = maxChannels;
+    if (mMaxChannels < 1) {
+        mMaxChannels = 1;
+    }
+    else if (mMaxChannels > 32) {
+        mMaxChannels = 32;
+    }
+    ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
+
+    mQuit = false;
+    mDecodeThread = 0;
+    memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
+    mAllocated = 0;
+    mNextSampleID = 0;
+    mNextChannelID = 0;
+
+    mCallback = 0;
+    mUserData = 0;
+
+    mChannelPool = new SoundChannel[mMaxChannels];
+    for (int i = 0; i < mMaxChannels; ++i) {
+        mChannelPool[i].init(this);
+        mChannels.push_back(&mChannelPool[i]);
+    }
+
+    // start decode thread
+    startThreads();
+}
+
+SoundPool::~SoundPool()
+{
+    ALOGV("SoundPool destructor");
+    mDecodeThread->quit();
+    quit();
+
+    Mutex::Autolock lock(&mLock);
+
+    mChannels.clear();
+    if (mChannelPool)
+        delete [] mChannelPool;
+    // clean up samples
+    ALOGV("clear samples");
+    mSamples.clear();
+
+    if (mDecodeThread)
+        delete mDecodeThread;
+}
+
+void SoundPool::addToRestartList(SoundChannel* channel)
+{
+    Mutex::Autolock lock(&mRestartLock);
+    if (!mQuit) {
+        mRestart.push_back(channel);
+        mCondition.signal();
+    }
+}
+
+void SoundPool::addToStopList(SoundChannel* channel)
+{
+    Mutex::Autolock lock(&mRestartLock);
+    if (!mQuit) {
+        mStop.push_back(channel);
+        mCondition.signal();
+    }
+}
+
+int SoundPool::beginThread(void* arg)
+{
+    SoundPool* p = (SoundPool*)arg;
+    return p->run();
+}
+
+int SoundPool::run()
+{
+    mRestartLock.lock();
+    while (!mQuit) {
+        mCondition.wait(mRestartLock);
+        ALOGV("awake");
+        if (mQuit) break;
+
+        while (!mStop.empty()) {
+            SoundChannel* channel;
+            ALOGV("Getting channel from stop list");
+            List<SoundChannel* >::iterator iter = mStop.begin();
+            channel = *iter;
+            mStop.erase(iter);
+            mRestartLock.unlock();
+            if (channel != 0) {
+                Mutex::Autolock lock(&mLock);
+                channel->stop();
+            }
+            mRestartLock.lock();
+            if (mQuit) break;
+        }
+
+        while (!mRestart.empty()) {
+            SoundChannel* channel;
+            ALOGV("Getting channel from list");
+            List<SoundChannel*>::iterator iter = mRestart.begin();
+            channel = *iter;
+            mRestart.erase(iter);
+            mRestartLock.unlock();
+            if (channel != 0) {
+                Mutex::Autolock lock(&mLock);
+                channel->nextEvent();
+            }
+            mRestartLock.lock();
+            if (mQuit) break;
+        }
+    }
+
+    mStop.clear();
+    mRestart.clear();
+    mCondition.signal();
+    mRestartLock.unlock();
+    ALOGV("goodbye");
+    return 0;
+}
+
+void SoundPool::quit()
+{
+    mRestartLock.lock();
+    mQuit = true;
+    mCondition.signal();
+    mCondition.wait(mRestartLock);
+    ALOGV("return from quit");
+    mRestartLock.unlock();
+}
+
+bool SoundPool::startThreads()
+{
+    createThreadEtc(beginThread, this, "SoundPool");
+    if (mDecodeThread == NULL)
+        mDecodeThread = new SoundPoolThread(this);
+    return mDecodeThread != NULL;
+}
+
+SoundChannel* SoundPool::findChannel(int channelID)
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        if (mChannelPool[i].channelID() == channelID) {
+            return &mChannelPool[i];
+        }
+    }
+    return NULL;
+}
+
+SoundChannel* SoundPool::findNextChannel(int channelID)
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        if (mChannelPool[i].nextChannelID() == channelID) {
+            return &mChannelPool[i];
+        }
+    }
+    return NULL;
+}
+
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
+{
+    ALOGV("load: fd=%d, offset=%" PRId64 ", length=%" PRId64 ", priority=%d",
+            fd, offset, length, priority);
+    Mutex::Autolock lock(&mLock);
+    sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
+    mSamples.add(sample->sampleID(), sample);
+    doLoad(sample);
+    return sample->sampleID();
+}
+
+void SoundPool::doLoad(sp<Sample>& sample)
+{
+    ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
+    sample->startLoad();
+    mDecodeThread->loadSample(sample->sampleID());
+}
+
+bool SoundPool::unload(int sampleID)
+{
+    ALOGV("unload: sampleID=%d", sampleID);
+    Mutex::Autolock lock(&mLock);
+    return mSamples.removeItem(sampleID);
+}
+
+int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
+        int priority, int loop, float rate)
+{
+    ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
+            sampleID, leftVolume, rightVolume, priority, loop, rate);
+    sp<Sample> sample;
+    SoundChannel* channel;
+    int channelID;
+
+    Mutex::Autolock lock(&mLock);
+
+    if (mQuit) {
+        return 0;
+    }
+    // is sample ready?
+    sample = findSample(sampleID);
+    if ((sample == 0) || (sample->state() != Sample::READY)) {
+        ALOGW("  sample %d not READY", sampleID);
+        return 0;
+    }
+
+    dump();
+
+    // allocate a channel
+    channel = allocateChannel_l(priority);
+
+    // no channel allocated - return 0
+    if (!channel) {
+        ALOGV("No channel allocated");
+        return 0;
+    }
+
+    channelID = ++mNextChannelID;
+
+    ALOGV("play channel %p state = %d", channel, channel->state());
+    channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
+    return channelID;
+}
+
+SoundChannel* SoundPool::allocateChannel_l(int priority)
+{
+    List<SoundChannel*>::iterator iter;
+    SoundChannel* channel = NULL;
+
+    // allocate a channel
+    if (!mChannels.empty()) {
+        iter = mChannels.begin();
+        if (priority >= (*iter)->priority()) {
+            channel = *iter;
+            mChannels.erase(iter);
+            ALOGV("Allocated active channel");
+        }
+    }
+
+    // update priority and put it back in the list
+    if (channel) {
+        channel->setPriority(priority);
+        for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+            if (priority < (*iter)->priority()) {
+                break;
+            }
+        }
+        mChannels.insert(iter, channel);
+    }
+    return channel;
+}
+
+// move a channel from its current position to the front of the list
+void SoundPool::moveToFront_l(SoundChannel* channel)
+{
+    for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+        if (*iter == channel) {
+            mChannels.erase(iter);
+            mChannels.push_front(channel);
+            break;
+        }
+    }
+}
+
+void SoundPool::pause(int channelID)
+{
+    ALOGV("pause(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->pause();
+    }
+}
+
+void SoundPool::autoPause()
+{
+    ALOGV("autoPause()");
+    Mutex::Autolock lock(&mLock);
+    for (int i = 0; i < mMaxChannels; ++i) {
+        SoundChannel* channel = &mChannelPool[i];
+        channel->autoPause();
+    }
+}
+
+void SoundPool::resume(int channelID)
+{
+    ALOGV("resume(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->resume();
+    }
+}
+
+void SoundPool::autoResume()
+{
+    ALOGV("autoResume()");
+    Mutex::Autolock lock(&mLock);
+    for (int i = 0; i < mMaxChannels; ++i) {
+        SoundChannel* channel = &mChannelPool[i];
+        channel->autoResume();
+    }
+}
+
+void SoundPool::stop(int channelID)
+{
+    ALOGV("stop(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->stop();
+    } else {
+        channel = findNextChannel(channelID);
+        if (channel)
+            channel->clearNextEvent();
+    }
+}
+
+void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
+{
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setVolume(leftVolume, rightVolume);
+    }
+}
+
+void SoundPool::setPriority(int channelID, int priority)
+{
+    ALOGV("setPriority(%d, %d)", channelID, priority);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setPriority(priority);
+    }
+}
+
+void SoundPool::setLoop(int channelID, int loop)
+{
+    ALOGV("setLoop(%d, %d)", channelID, loop);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setLoop(loop);
+    }
+}
+
+void SoundPool::setRate(int channelID, float rate)
+{
+    ALOGV("setRate(%d, %f)", channelID, rate);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setRate(rate);
+    }
+}
+
+// call with lock held
+void SoundPool::done_l(SoundChannel* channel)
+{
+    ALOGV("done_l(%d)", channel->channelID());
+    // if "stolen", play next event
+    if (channel->nextChannelID() != 0) {
+        ALOGV("add to restart list");
+        addToRestartList(channel);
+    }
+
+    // return to idle state
+    else {
+        ALOGV("move to front");
+        moveToFront_l(channel);
+    }
+}
+
+void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    mCallback = callback;
+    mUserData = user;
+}
+
+void SoundPool::notify(SoundPoolEvent event)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    if (mCallback != NULL) {
+        mCallback(event, this, mUserData);
+    }
+}
+
+void SoundPool::dump()
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        mChannelPool[i].dump();
+    }
+}
+
+
+Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
+{
+    init();
+    mSampleID = sampleID;
+    mFd = dup(fd);
+    mOffset = offset;
+    mLength = length;
+    ALOGV("create sampleID=%d, fd=%d, offset=%" PRId64 " length=%" PRId64,
+        mSampleID, mFd, mLength, mOffset);
+}
+
+void Sample::init()
+{
+    mSize = 0;
+    mRefCount = 0;
+    mSampleID = 0;
+    mState = UNLOADED;
+    mFd = -1;
+    mOffset = 0;
+    mLength = 0;
+}
+
+Sample::~Sample()
+{
+    ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
+    if (mFd > 0) {
+        ALOGV("close(%d)", mFd);
+        ::close(mFd);
+    }
+}
+
+static status_t decode(int fd, int64_t offset, int64_t length,
+        uint32_t *rate, int *numChannels, audio_format_t *audioFormat,
+        sp<MemoryHeapBase> heap, size_t *memsize) {
+
+    ALOGV("fd %d, offset %" PRId64 ", size %" PRId64, fd, offset, length);
+    AMediaExtractor *ex = AMediaExtractor_new();
+    status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
+
+    if (err != AMEDIA_OK) {
+        AMediaExtractor_delete(ex);
+        return err;
+    }
+
+    *audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+    size_t numTracks = AMediaExtractor_getTrackCount(ex);
+    for (size_t i = 0; i < numTracks; i++) {
+        AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
+        const char *mime;
+        if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
+            AMediaExtractor_delete(ex);
+            AMediaFormat_delete(format);
+            return UNKNOWN_ERROR;
+        }
+        if (strncmp(mime, "audio/", 6) == 0) {
+
+            AMediaCodec *codec = AMediaCodec_createDecoderByType(mime);
+            if (AMediaCodec_configure(codec, format,
+                    NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
+                || AMediaCodec_start(codec) != AMEDIA_OK
+                || AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
+                AMediaExtractor_delete(ex);
+                AMediaCodec_delete(codec);
+                AMediaFormat_delete(format);
+                return UNKNOWN_ERROR;
+            }
+
+            bool sawInputEOS = false;
+            bool sawOutputEOS = false;
+            uint8_t* writePos = static_cast<uint8_t*>(heap->getBase());
+            size_t available = heap->getSize();
+            size_t written = 0;
+
+            AMediaFormat_delete(format);
+            format = AMediaCodec_getOutputFormat(codec);
+
+            while (!sawOutputEOS) {
+                if (!sawInputEOS) {
+                    ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
+                    ALOGV("input buffer %zd", bufidx);
+                    if (bufidx >= 0) {
+                        size_t bufsize;
+                        uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
+                        int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
+                        ALOGV("read %d", sampleSize);
+                        if (sampleSize < 0) {
+                            sampleSize = 0;
+                            sawInputEOS = true;
+                            ALOGV("EOS");
+                        }
+                        int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
+
+                        AMediaCodec_queueInputBuffer(codec, bufidx,
+                                0 /* offset */, sampleSize, presentationTimeUs,
+                                sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
+                        AMediaExtractor_advance(ex);
+                    }
+                }
+
+                AMediaCodecBufferInfo info;
+                int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
+                ALOGV("dequeueoutput returned: %d", status);
+                if (status >= 0) {
+                    if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
+                        ALOGV("output EOS");
+                        sawOutputEOS = true;
+                    }
+                    ALOGV("got decoded buffer size %d", info.size);
+
+                    uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
+                    size_t dataSize = info.size;
+                    if (dataSize > available) {
+                        dataSize = available;
+                    }
+                    memcpy(writePos, buf + info.offset, dataSize);
+                    writePos += dataSize;
+                    written += dataSize;
+                    available -= dataSize;
+                    AMediaCodec_releaseOutputBuffer(codec, status, false /* render */);
+                    if (available == 0) {
+                        // there might be more data, but there's no space for it
+                        sawOutputEOS = true;
+                    }
+                } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
+                    ALOGV("output buffers changed");
+                } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+                    AMediaFormat_delete(format);
+                    format = AMediaCodec_getOutputFormat(codec);
+                    ALOGV("format changed to: %s", AMediaFormat_toString(format));
+                } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+                    ALOGV("no output buffer right now");
+                } else {
+                    ALOGV("unexpected info code: %d", status);
+                }
+            }
+
+            AMediaCodec_stop(codec);
+            AMediaCodec_delete(codec);
+            AMediaExtractor_delete(ex);
+            if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
+                    !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
+                AMediaFormat_delete(format);
+                return UNKNOWN_ERROR;
+            }
+            AMediaFormat_delete(format);
+            *memsize = written;
+            return OK;
+        }
+        AMediaFormat_delete(format);
+    }
+    AMediaExtractor_delete(ex);
+    return UNKNOWN_ERROR;
+}
+
+status_t Sample::doLoad()
+{
+    uint32_t sampleRate;
+    int numChannels;
+    audio_format_t format;
+    status_t status;
+    mHeap = new MemoryHeapBase(kDefaultHeapSize);
+
+    ALOGV("Start decode");
+    status = decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format,
+                                 mHeap, &mSize);
+    ALOGV("close(%d)", mFd);
+    ::close(mFd);
+    mFd = -1;
+    if (status != NO_ERROR) {
+        ALOGE("Unable to load sample");
+        goto error;
+    }
+    ALOGV("pointer = %p, size = %zu, sampleRate = %u, numChannels = %d",
+          mHeap->getBase(), mSize, sampleRate, numChannels);
+
+    if (sampleRate > kMaxSampleRate) {
+       ALOGE("Sample rate (%u) out of range", sampleRate);
+       status = BAD_VALUE;
+       goto error;
+    }
+
+    if ((numChannels < 1) || (numChannels > 8)) {
+        ALOGE("Sample channel count (%d) out of range", numChannels);
+        status = BAD_VALUE;
+        goto error;
+    }
+
+    mData = new MemoryBase(mHeap, 0, mSize);
+    mSampleRate = sampleRate;
+    mNumChannels = numChannels;
+    mFormat = format;
+    mState = READY;
+    return NO_ERROR;
+
+error:
+    mHeap.clear();
+    return status;
+}
+
+
+void SoundChannel::init(SoundPool* soundPool)
+{
+    mSoundPool = soundPool;
+}
+
+// call with sound pool lock held
+void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
+        float rightVolume, int priority, int loop, float rate)
+{
+    sp<AudioTrack> oldTrack;
+    sp<AudioTrack> newTrack;
+    status_t status;
+
+    { // scope for the lock
+        Mutex::Autolock lock(&mLock);
+
+        ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
+                " priority=%d, loop=%d, rate=%f",
+                this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
+                priority, loop, rate);
+
+        // if not idle, this voice is being stolen
+        if (mState != IDLE) {
+            ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
+            mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+            stop_l();
+            return;
+        }
+
+        // initialize track
+        size_t afFrameCount;
+        uint32_t afSampleRate;
+        audio_stream_type_t streamType = audio_attributes_to_stream_type(mSoundPool->attributes());
+        if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+            afFrameCount = kDefaultFrameCount;
+        }
+        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+            afSampleRate = kDefaultSampleRate;
+        }
+        int numChannels = sample->numChannels();
+        uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
+        size_t frameCount = 0;
+
+        if (loop) {
+            const audio_format_t format = sample->format();
+            const size_t frameSize = audio_is_linear_pcm(format)
+                    ? numChannels * audio_bytes_per_sample(format) : 1;
+            frameCount = sample->size() / frameSize;
+        }
+
+#ifndef USE_SHARED_MEM_BUFFER
+        uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
+        // Ensure minimum audio buffer size in case of short looped sample
+        if(frameCount < totalFrames) {
+            frameCount = totalFrames;
+        }
+#endif
+
+        // mToggle toggles each time a track is started on a given channel.
+        // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
+        // as callback user data. This enables the detection of callbacks received from the old
+        // audio track while the new one is being started and avoids processing them with
+        // wrong audio audio buffer size  (mAudioBufferSize)
+        unsigned long toggle = mToggle ^ 1;
+        void *userData = (void *)((unsigned long)this | toggle);
+        audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels);
+
+        // do not create a new audio track if current track is compatible with sample parameters
+#ifdef USE_SHARED_MEM_BUFFER
+        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+                channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
+#else
+        uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
+        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+                channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
+                bufferFrames);
+#endif
+        oldTrack = mAudioTrack;
+        status = newTrack->initCheck();
+        if (status != NO_ERROR) {
+            ALOGE("Error creating AudioTrack");
+            goto exit;
+        }
+        ALOGV("setVolume %p", newTrack.get());
+        newTrack->setVolume(leftVolume, rightVolume);
+        newTrack->setLoop(0, frameCount, loop);
+
+        // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
+        mToggle = toggle;
+        mAudioTrack = newTrack;
+        mPos = 0;
+        mSample = sample;
+        mChannelID = nextChannelID;
+        mPriority = priority;
+        mLoop = loop;
+        mLeftVolume = leftVolume;
+        mRightVolume = rightVolume;
+        mNumChannels = numChannels;
+        mRate = rate;
+        clearNextEvent();
+        mState = PLAYING;
+        mAudioTrack->start();
+        mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
+    }
+
+exit:
+    ALOGV("delete oldTrack %p", oldTrack.get());
+    if (status != NO_ERROR) {
+        mAudioTrack.clear();
+    }
+}
+
+void SoundChannel::nextEvent()
+{
+    sp<Sample> sample;
+    int nextChannelID;
+    float leftVolume;
+    float rightVolume;
+    int priority;
+    int loop;
+    float rate;
+
+    // check for valid event
+    {
+        Mutex::Autolock lock(&mLock);
+        nextChannelID = mNextEvent.channelID();
+        if (nextChannelID  == 0) {
+            ALOGV("stolen channel has no event");
+            return;
+        }
+
+        sample = mNextEvent.sample();
+        leftVolume = mNextEvent.leftVolume();
+        rightVolume = mNextEvent.rightVolume();
+        priority = mNextEvent.priority();
+        loop = mNextEvent.loop();
+        rate = mNextEvent.rate();
+    }
+
+    ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
+    play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+}
+
+void SoundChannel::callback(int event, void* user, void *info)
+{
+    SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
+
+    channel->process(event, info, (unsigned long)user & 1);
+}
+
+void SoundChannel::process(int event, void *info, unsigned long toggle)
+{
+    //ALOGV("process(%d)", mChannelID);
+
+    Mutex::Autolock lock(&mLock);
+
+    AudioTrack::Buffer* b = NULL;
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+       b = static_cast<AudioTrack::Buffer *>(info);
+    }
+
+    if (mToggle != toggle) {
+        ALOGV("process wrong toggle %p channel %d", this, mChannelID);
+        if (b != NULL) {
+            b->size = 0;
+        }
+        return;
+    }
+
+    sp<Sample> sample = mSample;
+
+//    ALOGV("SoundChannel::process event %d", event);
+
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+
+        // check for stop state
+        if (b->size == 0) return;
+
+        if (mState == IDLE) {
+            b->size = 0;
+            return;
+        }
+
+        if (sample != 0) {
+            // fill buffer
+            uint8_t* q = (uint8_t*) b->i8;
+            size_t count = 0;
+
+            if (mPos < (int)sample->size()) {
+                uint8_t* p = sample->data() + mPos;
+                count = sample->size() - mPos;
+                if (count > b->size) {
+                    count = b->size;
+                }
+                memcpy(q, p, count);
+//              ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
+//                      count);
+            } else if (mPos < mAudioBufferSize) {
+                count = mAudioBufferSize - mPos;
+                if (count > b->size) {
+                    count = b->size;
+                }
+                memset(q, 0, count);
+//              ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
+            }
+
+            mPos += count;
+            b->size = count;
+            //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
+        }
+    } else if (event == AudioTrack::EVENT_UNDERRUN || event == AudioTrack::EVENT_BUFFER_END) {
+        ALOGV("process %p channel %d event %s",
+              this, mChannelID, (event == AudioTrack::EVENT_UNDERRUN) ? "UNDERRUN" :
+                      "BUFFER_END");
+        mSoundPool->addToStopList(this);
+    } else if (event == AudioTrack::EVENT_LOOP_END) {
+        ALOGV("End loop %p channel %d", this, mChannelID);
+    } else if (event == AudioTrack::EVENT_NEW_IAUDIOTRACK) {
+        ALOGV("process %p channel %d NEW_IAUDIOTRACK", this, mChannelID);
+    } else {
+        ALOGW("SoundChannel::process unexpected event %d", event);
+    }
+}
+
+
+// call with lock held
+bool SoundChannel::doStop_l()
+{
+    if (mState != IDLE) {
+        setVolume_l(0, 0);
+        ALOGV("stop");
+        mAudioTrack->stop();
+        mSample.clear();
+        mState = IDLE;
+        mPriority = IDLE_PRIORITY;
+        return true;
+    }
+    return false;
+}
+
+// call with lock held and sound pool lock held
+void SoundChannel::stop_l()
+{
+    if (doStop_l()) {
+        mSoundPool->done_l(this);
+    }
+}
+
+// call with sound pool lock held
+void SoundChannel::stop()
+{
+    bool stopped;
+    {
+        Mutex::Autolock lock(&mLock);
+        stopped = doStop_l();
+    }
+
+    if (stopped) {
+        mSoundPool->done_l(this);
+    }
+}
+
+//FIXME: Pause is a little broken right now
+void SoundChannel::pause()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PLAYING) {
+        ALOGV("pause track");
+        mState = PAUSED;
+        mAudioTrack->pause();
+    }
+}
+
+void SoundChannel::autoPause()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PLAYING) {
+        ALOGV("pause track");
+        mState = PAUSED;
+        mAutoPaused = true;
+        mAudioTrack->pause();
+    }
+}
+
+void SoundChannel::resume()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PAUSED) {
+        ALOGV("resume track");
+        mState = PLAYING;
+        mAutoPaused = false;
+        mAudioTrack->start();
+    }
+}
+
+void SoundChannel::autoResume()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAutoPaused && (mState == PAUSED)) {
+        ALOGV("resume track");
+        mState = PLAYING;
+        mAutoPaused = false;
+        mAudioTrack->start();
+    }
+}
+
+void SoundChannel::setRate(float rate)
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAudioTrack != NULL && mSample != 0) {
+        uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
+        mAudioTrack->setSampleRate(sampleRate);
+        mRate = rate;
+    }
+}
+
+// call with lock held
+void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
+{
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    if (mAudioTrack != NULL)
+        mAudioTrack->setVolume(leftVolume, rightVolume);
+}
+
+void SoundChannel::setVolume(float leftVolume, float rightVolume)
+{
+    Mutex::Autolock lock(&mLock);
+    setVolume_l(leftVolume, rightVolume);
+}
+
+void SoundChannel::setLoop(int loop)
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAudioTrack != NULL && mSample != 0) {
+        uint32_t loopEnd = mSample->size()/mNumChannels/
+            ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+        mAudioTrack->setLoop(0, loopEnd, loop);
+        mLoop = loop;
+    }
+}
+
+SoundChannel::~SoundChannel()
+{
+    ALOGV("SoundChannel destructor %p", this);
+    {
+        Mutex::Autolock lock(&mLock);
+        clearNextEvent();
+        doStop_l();
+    }
+    // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
+    // callback thread to exit which may need to execute process() and acquire the mLock.
+    mAudioTrack.clear();
+}
+
+void SoundChannel::dump()
+{
+    ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
+            mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
+}
+
+void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
+            float rightVolume, int priority, int loop, float rate)
+{
+    mSample = sample;
+    mChannelID = channelID;
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    mPriority = priority;
+    mLoop = loop;
+    mRate =rate;
+}
+
+} // end namespace android
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
new file mode 100644
index 0000000..d19cd91
--- /dev/null
+++ b/media/jni/soundpool/SoundPool.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef SOUNDPOOL_H_
+#define SOUNDPOOL_H_
+
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioTrack.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
+
+namespace android {
+
+static const int IDLE_PRIORITY = -1;
+
+// forward declarations
+class SoundEvent;
+class SoundPoolThread;
+class SoundPool;
+
+// for queued events
+class SoundPoolEvent {
+public:
+    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
+        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
+    int         mMsg;
+    int         mArg1;
+    int         mArg2;
+    enum MessageType { INVALID, SAMPLE_LOADED };
+};
+
+// callback function prototype
+typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
+
+// tracks samples used by application
+class Sample  : public RefBase {
+public:
+    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
+    Sample(int sampleID, int fd, int64_t offset, int64_t length);
+    ~Sample();
+    int sampleID() { return mSampleID; }
+    int numChannels() { return mNumChannels; }
+    int sampleRate() { return mSampleRate; }
+    audio_format_t format() { return mFormat; }
+    size_t size() { return mSize; }
+    int state() { return mState; }
+    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
+    status_t doLoad();
+    void startLoad() { mState = LOADING; }
+    sp<IMemory> getIMemory() { return mData; }
+
+private:
+    void init();
+
+    size_t              mSize;
+    volatile int32_t    mRefCount;
+    uint16_t            mSampleID;
+    uint16_t            mSampleRate;
+    uint8_t             mState;
+    uint8_t             mNumChannels;
+    audio_format_t      mFormat;
+    int                 mFd;
+    int64_t             mOffset;
+    int64_t             mLength;
+    sp<IMemory>         mData;
+    sp<MemoryHeapBase>  mHeap;
+};
+
+// stores pending events for stolen channels
+class SoundEvent
+{
+public:
+    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
+            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
+    void set(const sp<Sample>& sample, int channelID, float leftVolume,
+            float rightVolume, int priority, int loop, float rate);
+    sp<Sample>      sample() { return mSample; }
+    int             channelID() { return mChannelID; }
+    float           leftVolume() { return mLeftVolume; }
+    float           rightVolume() { return mRightVolume; }
+    int             priority() { return mPriority; }
+    int             loop() { return mLoop; }
+    float           rate() { return mRate; }
+    void            clear() { mChannelID = 0; mSample.clear(); }
+
+protected:
+    sp<Sample>      mSample;
+    int             mChannelID;
+    float           mLeftVolume;
+    float           mRightVolume;
+    int             mPriority;
+    int             mLoop;
+    float           mRate;
+};
+
+// for channels aka AudioTracks
+class SoundChannel : public SoundEvent {
+public:
+    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
+    SoundChannel() : mState(IDLE), mNumChannels(1),
+            mPos(0), mToggle(0), mAutoPaused(false) {}
+    ~SoundChannel();
+    void init(SoundPool* soundPool);
+    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
+            int priority, int loop, float rate);
+    void setVolume_l(float leftVolume, float rightVolume);
+    void setVolume(float leftVolume, float rightVolume);
+    void stop_l();
+    void stop();
+    void pause();
+    void autoPause();
+    void resume();
+    void autoResume();
+    void setRate(float rate);
+    int state() { return mState; }
+    void setPriority(int priority) { mPriority = priority; }
+    void setLoop(int loop);
+    int numChannels() { return mNumChannels; }
+    void clearNextEvent() { mNextEvent.clear(); }
+    void nextEvent();
+    int nextChannelID() { return mNextEvent.channelID(); }
+    void dump();
+
+private:
+    static void callback(int event, void* user, void *info);
+    void process(int event, void *info, unsigned long toggle);
+    bool doStop_l();
+
+    SoundPool*          mSoundPool;
+    sp<AudioTrack>      mAudioTrack;
+    SoundEvent          mNextEvent;
+    Mutex               mLock;
+    int                 mState;
+    int                 mNumChannels;
+    int                 mPos;
+    int                 mAudioBufferSize;
+    unsigned long       mToggle;
+    bool                mAutoPaused;
+};
+
+// application object for managing a pool of sounds
+class SoundPool {
+    friend class SoundPoolThread;
+    friend class SoundChannel;
+public:
+    SoundPool(int maxChannels, const audio_attributes_t* pAttributes);
+    ~SoundPool();
+    int load(int fd, int64_t offset, int64_t length, int priority);
+    bool unload(int sampleID);
+    int play(int sampleID, float leftVolume, float rightVolume, int priority,
+            int loop, float rate);
+    void pause(int channelID);
+    void autoPause();
+    void resume(int channelID);
+    void autoResume();
+    void stop(int channelID);
+    void setVolume(int channelID, float leftVolume, float rightVolume);
+    void setPriority(int channelID, int priority);
+    void setLoop(int channelID, int loop);
+    void setRate(int channelID, float rate);
+    const audio_attributes_t* attributes() { return &mAttributes; }
+
+    // called from SoundPoolThread
+    void sampleLoaded(int sampleID);
+
+    // called from AudioTrack thread
+    void done_l(SoundChannel* channel);
+
+    // callback function
+    void setCallback(SoundPoolCallback* callback, void* user);
+    void* getUserData() { return mUserData; }
+
+private:
+    SoundPool() {} // no default constructor
+    bool startThreads();
+    void doLoad(sp<Sample>& sample);
+    sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
+    SoundChannel* findChannel (int channelID);
+    SoundChannel* findNextChannel (int channelID);
+    SoundChannel* allocateChannel_l(int priority);
+    void moveToFront_l(SoundChannel* channel);
+    void notify(SoundPoolEvent event);
+    void dump();
+
+    // restart thread
+    void addToRestartList(SoundChannel* channel);
+    void addToStopList(SoundChannel* channel);
+    static int beginThread(void* arg);
+    int run();
+    void quit();
+
+    Mutex                   mLock;
+    Mutex                   mRestartLock;
+    Condition               mCondition;
+    SoundPoolThread*        mDecodeThread;
+    SoundChannel*           mChannelPool;
+    List<SoundChannel*>     mChannels;
+    List<SoundChannel*>     mRestart;
+    List<SoundChannel*>     mStop;
+    DefaultKeyedVector< int, sp<Sample> >   mSamples;
+    int                     mMaxChannels;
+    audio_attributes_t      mAttributes;
+    int                     mAllocated;
+    int                     mNextSampleID;
+    int                     mNextChannelID;
+    bool                    mQuit;
+
+    // callback
+    Mutex                   mCallbackLock;
+    SoundPoolCallback*      mCallback;
+    void*                   mUserData;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOL_H_*/
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp
new file mode 100644
index 0000000..ba3b482
--- /dev/null
+++ b/media/jni/soundpool/SoundPoolThread.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPoolThread"
+#include "utils/Log.h"
+
+#include "SoundPoolThread.h"
+
+namespace android {
+
+void SoundPoolThread::write(SoundPoolMsg msg) {
+    Mutex::Autolock lock(&mLock);
+    while (mMsgQueue.size() >= maxMessages) {
+        mCondition.wait(mLock);
+    }
+
+    // if thread is quitting, don't add to queue
+    if (mRunning) {
+        mMsgQueue.push(msg);
+        mCondition.signal();
+    }
+}
+
+const SoundPoolMsg SoundPoolThread::read() {
+    Mutex::Autolock lock(&mLock);
+    while (mMsgQueue.size() == 0) {
+        mCondition.wait(mLock);
+    }
+    SoundPoolMsg msg = mMsgQueue[0];
+    mMsgQueue.removeAt(0);
+    mCondition.signal();
+    return msg;
+}
+
+void SoundPoolThread::quit() {
+    Mutex::Autolock lock(&mLock);
+    if (mRunning) {
+        mRunning = false;
+        mMsgQueue.clear();
+        mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
+        mCondition.signal();
+        mCondition.wait(mLock);
+    }
+    ALOGV("return from quit");
+}
+
+SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
+    mSoundPool(soundPool)
+{
+    mMsgQueue.setCapacity(maxMessages);
+    if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
+        mRunning = true;
+    }
+}
+
+SoundPoolThread::~SoundPoolThread()
+{
+    quit();
+}
+
+int SoundPoolThread::beginThread(void* arg) {
+    ALOGV("beginThread");
+    SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
+    return soundPoolThread->run();
+}
+
+int SoundPoolThread::run() {
+    ALOGV("run");
+    for (;;) {
+        SoundPoolMsg msg = read();
+        ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
+        switch (msg.mMessageType) {
+        case SoundPoolMsg::KILL:
+            ALOGV("goodbye");
+            return NO_ERROR;
+        case SoundPoolMsg::LOAD_SAMPLE:
+            doLoadSample(msg.mData);
+            break;
+        default:
+            ALOGW("run: Unrecognized message %d\n",
+                    msg.mMessageType);
+            break;
+        }
+    }
+}
+
+void SoundPoolThread::loadSample(int sampleID) {
+    write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
+}
+
+void SoundPoolThread::doLoadSample(int sampleID) {
+    sp <Sample> sample = mSoundPool->findSample(sampleID);
+    status_t status = -1;
+    if (sample != 0) {
+        status = sample->doLoad();
+    }
+    mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
+}
+
+} // end namespace android
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
new file mode 100644
index 0000000..d388388
--- /dev/null
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef SOUNDPOOLTHREAD_H_
+#define SOUNDPOOLTHREAD_H_
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <media/AudioTrack.h>
+
+#include "SoundPool.h"
+
+namespace android {
+
+class SoundPoolMsg {
+public:
+    enum MessageType { INVALID, KILL, LOAD_SAMPLE };
+    SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
+    SoundPoolMsg(MessageType MessageType, int data) :
+        mMessageType(MessageType), mData(data) {}
+    uint16_t         mMessageType;
+    uint16_t         mData;
+};
+
+/*
+ * This class handles background requests from the SoundPool
+ */
+class SoundPoolThread {
+public:
+    SoundPoolThread(SoundPool* SoundPool);
+    ~SoundPoolThread();
+    void loadSample(int sampleID);
+    void quit();
+    void write(SoundPoolMsg msg);
+
+private:
+    static const size_t maxMessages = 5;
+
+    static int beginThread(void* arg);
+    int run();
+    void doLoadSample(int sampleID);
+    const SoundPoolMsg read();
+
+    Mutex                   mLock;
+    Condition               mCondition;
+    Vector<SoundPoolMsg>    mMsgQueue;
+    SoundPool*              mSoundPool;
+    bool                    mRunning;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOLTHREAD_H_*/
diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
index 89b2893..b2333f8 100644
--- a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
+++ b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
@@ -23,7 +23,7 @@
 #include <nativehelper/jni.h>
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <media/SoundPool.h>
+#include "SoundPool.h"
 
 using namespace android;
 
@@ -45,20 +45,6 @@
 static audio_attributes_fields_t javaAudioAttrFields;
 
 // ----------------------------------------------------------------------------
-static jint
-android_media_SoundPool_SoundPoolImpl_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority)
-{
-    ALOGV("android_media_SoundPool_SoundPoolImpl_load_URL");
-    SoundPool *ap = MusterSoundPool(env, thiz);
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return 0;
-    }
-    const char* s = env->GetStringUTFChars(path, NULL);
-    int id = ap->load(s, priority);
-    env->ReleaseStringUTFChars(path, s);
-    return (jint) id;
-}
 
 static jint
 android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
@@ -231,14 +217,14 @@
     SoundPool *ap = MusterSoundPool(env, thiz);
     if (ap != NULL) {
 
-        // release weak reference
+        // release weak reference and clear callback
         jobject weakRef = (jobject) ap->getUserData();
+        ap->setCallback(NULL, NULL);
         if (weakRef != NULL) {
             env->DeleteGlobalRef(weakRef);
         }
 
-        // clear callback and native context
-        ap->setCallback(NULL, NULL);
+        // clear native context
         env->SetLongField(thiz, fields.mNativeContext, 0);
         delete ap;
     }
@@ -249,10 +235,6 @@
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {   "_load",
-        "(Ljava/lang/String;I)I",
-        (void *)android_media_SoundPool_SoundPoolImpl_load_URL
-    },
-    {   "_load",
         "(Ljava/io/FileDescriptor;JJI)I",
         (void *)android_media_SoundPool_SoundPoolImpl_load_FD
     },
@@ -312,7 +294,7 @@
 
 static const char* const kClassPathName = "android/media/SoundPool$SoundPoolImpl";
 
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
 {
     JNIEnv* env = NULL;
     jint result = -1;
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 2a9448d..334f4e2 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -22,6 +22,7 @@
 # Build main libfilterfw
 
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libfilterfw
 
@@ -30,7 +31,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
                                 libfilterfw_native
 
-LOCAL_SHARED_LIBRARIES := libstlport \
+LOCAL_SHARED_LIBRARIES := \
                           libGLESv2 \
                           libEGL \
                           libgui \
@@ -42,10 +43,4 @@
                           libjnigraphics \
                           libmedia
 
-# Don't prelink this library.  For more efficient code, you may want
-# to add this library to the prelink map and set this to true. However,
-# it's difficult to do this for applications that are not supplied as
-# part of a system image.
-LOCAL_PRELINK_MODULE := false
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
index 8207c72c..4682a0d 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
@@ -70,7 +70,7 @@
     }
 
     public float length() {
-        return (float)Math.sqrt(x*x + y*y);
+        return (float)Math.hypot(x, y);
     }
 
     public float distanceTo(Point p) {
diff --git a/media/mca/filterfw/jni/Android.mk b/media/mca/filterfw/jni/Android.mk
index 5aa5af1..cba4e7e 100644
--- a/media/mca/filterfw/jni/Android.mk
+++ b/media/mca/filterfw/jni/Android.mk
@@ -38,14 +38,9 @@
 
 # Also need the JNI headers.
 LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	$(LOCAL_PATH)/..
+    $(JNI_H_INCLUDE) \
+    $(LOCAL_PATH)/..
 
-# Don't prelink this library.  For more efficient code, you may want
-# to add this library to the prelink map and set this to true. However,
-# it's difficult to do this for applications that are not supplied as
-# part of a system image.
-LOCAL_PRELINK_MODULE := false
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-unused-parameter
 
 include $(BUILD_STATIC_LIBRARY)
-
diff --git a/media/mca/filterfw/jni/jni_gl_environment.cpp b/media/mca/filterfw/jni/jni_gl_environment.cpp
index 6da7b7c..5f00739 100644
--- a/media/mca/filterfw/jni/jni_gl_environment.cpp
+++ b/media/mca/filterfw/jni/jni_gl_environment.cpp
@@ -20,8 +20,8 @@
 
 #include "jni/jni_gl_environment.h"
 #include "jni/jni_util.h"
-#include <media/mediarecorder.h>
 #include "native/core/gl_env.h"
+#include <media/mediarecorder.h>
 
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
@@ -92,8 +92,8 @@
   return gl_env ? ToJBool(gl_env->IsContextActive()) : JNI_FALSE;
 }
 
-jboolean Java_android_filterfw_core_GLEnvironment_nativeIsAnyContextActive(JNIEnv* env,
-                                                                           jclass clazz) {
+jboolean Java_android_filterfw_core_GLEnvironment_nativeIsAnyContextActive(JNIEnv* /* env */,
+                                                                           jclass /* clazz */) {
   return ToJBool(GLEnv::IsAnyContextActive());
 }
 
diff --git a/media/mca/filterfw/jni/jni_init.cpp b/media/mca/filterfw/jni/jni_init.cpp
index 3b131f1..956a5a5 100644
--- a/media/mca/filterfw/jni/jni_init.cpp
+++ b/media/mca/filterfw/jni/jni_init.cpp
@@ -27,7 +27,7 @@
 
 JavaVM* g_current_java_vm_ = NULL;
 
-jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
   // Set the current vm pointer
   g_current_java_vm_ = vm;
 
diff --git a/media/mca/filterfw/jni/jni_util.h b/media/mca/filterfw/jni/jni_util.h
index 68ff653..11c0871 100644
--- a/media/mca/filterfw/jni/jni_util.h
+++ b/media/mca/filterfw/jni/jni_util.h
@@ -16,7 +16,7 @@
 
 #include <jni.h>
 
-#include <hash_map>
+#include <unordered_map>
 #include <string>
 
 #include "base/utilities.h"
@@ -188,8 +188,8 @@
         id_field_name_(id_fld_name),
         next_id_(0) { }
 
-    typedef std::hash_map<int, T*>    CObjMap;
-    typedef std::hash_map<int, bool>  FlagMap;
+    typedef std::unordered_map<int, T*>    CObjMap;
+    typedef std::unordered_map<int, bool>  FlagMap;
     static ObjectPool* instance_;
     std::string jclass_name_;
     std::string id_field_name_;
diff --git a/media/mca/filterfw/native/Android.mk b/media/mca/filterfw/native/Android.mk
index 46ee283..7c4703f 100644
--- a/media/mca/filterfw/native/Android.mk
+++ b/media/mca/filterfw/native/Android.mk
@@ -39,6 +39,8 @@
 # gcc should always be placed at the end.
 LOCAL_EXPORT_LDLIBS := -llog -lgcc
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 # TODO: Build a shared library as well?
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/media/mca/filterfw/native/core/shader_program.cpp b/media/mca/filterfw/native/core/shader_program.cpp
index d92eb31..1e573fb 100644
--- a/media/mca/filterfw/native/core/shader_program.cpp
+++ b/media/mca/filterfw/native/core/shader_program.cpp
@@ -30,9 +30,6 @@
 namespace android {
 namespace filterfw {
 
-// VBO attachment keys
-static const int kDefaultVboKey = 1;
-
 static const char* s_default_vertex_shader_source_ =
   "attribute vec4 a_position;\n"
   "attribute vec2 a_texcoord;\n"
@@ -55,10 +52,6 @@
   *yt = w0 * b[1] + w1 * b[3] + w2 * b[5] + w3 * b[7];
 }
 
-static inline float AdjustRatio(float current, float next) {
-  return (current + next) / 2.0;
-}
-
 // VertexAttrib implementation /////////////////////////////////////////////////
 ShaderProgram::VertexAttrib::VertexAttrib()
   : is_const(true),
@@ -318,15 +311,15 @@
       ALOGE("Problem compiling shader! Source:");
       ALOGE("%s", source);
       std::string src(source);
-      unsigned int cur_pos = 0;
-      unsigned int next_pos = 0;
-      int line_number = 1;
+      size_t cur_pos = 0;
+      size_t next_pos = 0;
+      size_t line_number = 1;
       while ( (next_pos = src.find_first_of('\n', cur_pos)) != std::string::npos) {
-        ALOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
+        ALOGE("%03zd : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
         cur_pos = next_pos + 1;
         line_number++;
       }
-      ALOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
+      ALOGE("%03zu : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
 
       GLint log_length = 0;
       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
@@ -442,7 +435,7 @@
     if (tex_var >= 0) {
       glUniform1i(tex_var, i);
     } else {
-      ALOGE("ShaderProgram: Shader does not seem to support %d number of "
+      ALOGE("ShaderProgram: Shader does not seem to support %zd number of "
            "inputs! Missing uniform 'tex_sampler_%d'!", textures.size(), i);
       return false;
     }
diff --git a/media/mca/filterfw/native/core/value.cpp b/media/mca/filterfw/native/core/value.cpp
index 04bf0ef..c0ea763 100644
--- a/media/mca/filterfw/native/core/value.cpp
+++ b/media/mca/filterfw/native/core/value.cpp
@@ -16,6 +16,7 @@
 
 #include <stddef.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "value.h"
 
diff --git a/media/mca/filterfw/native/core/vertex_frame.cpp b/media/mca/filterfw/native/core/vertex_frame.cpp
index 822573f..9fb9eaa 100644
--- a/media/mca/filterfw/native/core/vertex_frame.cpp
+++ b/media/mca/filterfw/native/core/vertex_frame.cpp
@@ -25,10 +25,6 @@
 namespace android {
 namespace filterfw {
 
-// GL Extensions that are dynamically looked up at runtime
-static PFNGLMAPBUFFEROESPROC    GLMapBufferOES    = NULL;
-static PFNGLUNMAPBUFFEROESPROC  GLUnmapBufferOES  = NULL;
-
 VertexFrame::VertexFrame(int size)
   : vbo_(0),
     size_(size) {
diff --git a/media/mca/filterfw/native/libfilterfw.mk b/media/mca/filterfw/native/libfilterfw.mk
index 4e88e6f..69227ce 100644
--- a/media/mca/filterfw/native/libfilterfw.mk
+++ b/media/mca/filterfw/native/libfilterfw.mk
@@ -18,9 +18,6 @@
 
 # Uncomment the requirements below, once we need them:
 
-# STLport
-include external/stlport/libstlport.mk
-
 # Neven FaceDetect SDK
 #LOCAL_C_INCLUDES += external/neven/FaceRecEm/common/src/b_FDSDK \
 #	external/neven/FaceRecEm/common/src \
diff --git a/media/mca/filterpacks/Android.mk b/media/mca/filterpacks/Android.mk
index 6e54f60..0ff7658 100644
--- a/media/mca/filterpacks/Android.mk
+++ b/media/mca/filterpacks/Android.mk
@@ -28,7 +28,7 @@
 
 LOCAL_CFLAGS := -DANDROID
 
-include external/stlport/libstlport.mk
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -48,6 +48,6 @@
 
 LOCAL_SHARED_LIBRARIES := liblog libutils libfilterfw
 
-LOCAL_PRELINK_MODULE := false
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/mca/filterpacks/native/imageproc/brightness.c b/media/mca/filterpacks/native/imageproc/brightness.c
index f4addf1..3c3652f 100644
--- a/media/mca/filterpacks/native/imageproc/brightness.c
+++ b/media/mca/filterpacks/native/imageproc/brightness.c
@@ -16,6 +16,7 @@
 
 #include <android/log.h>
 #include <stdlib.h>
+#include <string.h>
 
 #define  LOGI(...) __android_log_print(ANDROID_LOG_INFO, "MCA", __VA_ARGS__)
 #define  LOGW(...) __android_log_print(ANDROID_LOG_WARN, "MCA", __VA_ARGS__)
diff --git a/media/mca/filterpacks/native/imageproc/contrast.c b/media/mca/filterpacks/native/imageproc/contrast.c
index ea8c8d2..31c975c 100644
--- a/media/mca/filterpacks/native/imageproc/contrast.c
+++ b/media/mca/filterpacks/native/imageproc/contrast.c
@@ -16,6 +16,7 @@
 
 #include <android/log.h>
 #include <stdlib.h>
+#include <string.h>
 
 #define  LOGI(...) __android_log_print(ANDROID_LOG_INFO, "MCA", __VA_ARGS__)
 #define  LOGW(...) __android_log_print(ANDROID_LOG_WARN, "MCA", __VA_ARGS__)
diff --git a/media/mca/filterpacks/native/imageproc/invert.c b/media/mca/filterpacks/native/imageproc/invert.c
index 5938aac..f5f9e27 100644
--- a/media/mca/filterpacks/native/imageproc/invert.c
+++ b/media/mca/filterpacks/native/imageproc/invert.c
@@ -16,12 +16,14 @@
 
 #include <android/log.h>
 
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+
 int invert_process(const char** inputs,
                    const int* input_sizes,
                    int input_count,
                    char* output,
                    int output_size,
-                   void* user_data) {
+                   void* user_data ATTRIBUTE_UNUSED) {
   // Make sure we have exactly one input
   if (input_count != 1)
     return 0;
diff --git a/media/mca/filterpacks/native/imageproc/to_rgba.c b/media/mca/filterpacks/native/imageproc/to_rgba.c
index bf4db2a..80094c0 100644
--- a/media/mca/filterpacks/native/imageproc/to_rgba.c
+++ b/media/mca/filterpacks/native/imageproc/to_rgba.c
@@ -16,12 +16,14 @@
 
 #include <stdlib.h>
 
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+
 int gray_to_rgb_process(const char** inputs,
                         const int* input_sizes,
                         int input_count,
                         char* output,
                         int output_size,
-                        void* user_data) {
+                        void* user_data ATTRIBUTE_UNUSED) {
   // Make sure we have exactly one input
   if (input_count != 1)
     return 0;
@@ -52,7 +54,7 @@
                         int input_count,
                         char* output,
                         int output_size,
-                        void* user_data) {
+                        void* user_data ATTRIBUTE_UNUSED) {
   // Make sure we have exactly one input
   if (input_count != 1)
     return 0;
@@ -84,7 +86,7 @@
                          int input_count,
                          char* output,
                          int output_size,
-                         void* user_data) {
+                         void* user_data ATTRIBUTE_UNUSED) {
   // Make sure we have exactly one input
   if (input_count != 1)
     return 0;
@@ -116,7 +118,7 @@
                         int input_count,
                         char* output,
                         int output_size,
-                        void* user_data) {
+                        void* user_data ATTRIBUTE_UNUSED) {
   // Make sure we have exactly one input
   if (input_count != 1)
     return 0;
diff --git a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpActivity.java b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpActivity.java
index 46cb64e..b8f5704 100644
--- a/media/tests/MediaDump/src/com/android/mediadump/VideoDumpActivity.java
+++ b/media/tests/MediaDump/src/com/android/mediadump/VideoDumpActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.Context;
-import android.content.DialogInterface;;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
index e6f0aaf..d12ef2e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraFunctionalTest.java
@@ -37,7 +37,6 @@
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import com.android.mediaframeworktest.CameraStressTestRunner;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
index 61b708a..8f67598 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/camera/CameraPairwiseTest.java
@@ -24,7 +24,6 @@
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.util.FloatMath;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index cc50c43..362bbc4 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -316,6 +316,11 @@
                 throws RemoteException {
             Log.v(TAG, String.format("Camera %d has status changed to 0x%x", cameraId, status));
         }
+        public void onTorchStatusChanged(int status, String cameraId)
+                throws RemoteException {
+            Log.v(TAG, String.format("Camera %s has torch status changed to 0x%x",
+                    cameraId, status));
+        }
     }
 
     /**
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 3cae19d..d756d05 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -161,8 +161,7 @@
         assertFalse(request.isEmpty());
         assertFalse(metadata.isEmpty());
         if (needStream) {
-            int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20,
-                    /* ignored */30, mSurface);
+            int streamId = mCameraUser.createStream(mSurface);
             assertEquals(0, streamId);
             request.addTarget(mSurface);
         }
@@ -235,12 +234,11 @@
 
     @SmallTest
     public void testCreateStream() throws Exception {
-        int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30,
-                mSurface);
+        int streamId = mCameraUser.createStream(mSurface);
         assertEquals(0, streamId);
 
         assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+                mCameraUser.createStream(mSurface));
 
         assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
     }
@@ -257,20 +255,18 @@
     public void testCreateStreamTwo() throws Exception {
 
         // Create first stream
-        int streamId = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
-                mSurface);
+        int streamId = mCameraUser.createStream(mSurface);
         assertEquals(0, streamId);
 
         assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface));
+                mCameraUser.createStream(mSurface));
 
         // Create second stream with a different surface.
         SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
         surfaceTexture.setDefaultBufferSize(640, 480);
         Surface surface2 = new Surface(surfaceTexture);
 
-        int streamId2 = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0,
-                surface2);
+        int streamId2 = mCameraUser.createStream(surface2);
         assertEquals(1, streamId2);
 
         // Clean up streams
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
index 69f0bb5..794e7f22 100644
--- a/media/tests/audiotests/Android.mk
+++ b/media/tests/audiotests/Android.mk
@@ -1,21 +1,23 @@
-ifeq ($(TARGET_ARCH),arm)
 
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE:= shared_mem_test
+
 LOCAL_SRC_FILES := \
-		   shared_mem_test.cpp
+    shared_mem_test.cpp
+
 LOCAL_SHARED_LIBRARIES :=  \
-		libc \
-        libcutils \
-        libutils \
-        libbinder \
-        libhardware_legacy \
-		libmedia
+    libc \
+    libcutils \
+    libutils \
+    libbinder \
+    libhardware_legacy \
+    libmedia
+
 LOCAL_MODULE_TAGS := tests
 
-include $(BUILD_EXECUTABLE)
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
-endif
+include $(BUILD_EXECUTABLE)
diff --git a/media/tests/audiotests/shared_mem_test.cpp b/media/tests/audiotests/shared_mem_test.cpp
index 992c900..2f57499 100644
--- a/media/tests/audiotests/shared_mem_test.cpp
+++ b/media/tests/audiotests/shared_mem_test.cpp
@@ -133,12 +133,8 @@
 ************************************************************/
 void AudioTrackTest::Generate(short *buffer, long bufferSz, long amplitude, unsigned long &phi, long dPhi)
 {
-    long pi13 = 25736;   // 2^13*pi
     // fill buffer
     for(int i0=0; i0<bufferSz; i0++) {
-        long sample;
-        long l0, l1;
-
         buffer[i0] = ComputeSine( amplitude, phi);
         phi += dPhi;
     }
@@ -210,7 +206,7 @@
 *    global main
 *
 ************************************************************/
-int main(int argc, char *argv[]) {
+int main() {
 
     return android::main();
 }
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
index adf0d30..7ab6458 100644
--- a/media/tests/players/Android.mk
+++ b/media/tests/players/Android.mk
@@ -26,5 +26,6 @@
 LOCAL_MODULE:= invoke_mock_media_player
 LOCAL_MODULE_TAGS := tests eng
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index d1fed7bb..0d0c7ad 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -58,7 +58,7 @@
     virtual bool        hardwareOutput() {return true;}
 
     virtual status_t    setDataSource(
-            const sp<IMediaHTTPService> &httpService,
+            const sp<IMediaHTTPService>& /* httpService */,
             const char *url,
             const KeyedVector<String8, String8> *) {
         ALOGV("setDataSource %s", url);
@@ -69,24 +69,28 @@
         return OK;
     }
 
-    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) {return OK;}
+    virtual status_t    setDataSource(int /* fd */, int64_t /* offset */, int64_t /* length */) {
+        return OK;
+    }
     virtual status_t    setVideoSurfaceTexture(
-                                const sp<IGraphicBufferProducer>& bufferProducer) {return OK;}
-    virtual status_t    prepare() {return OK;}
-    virtual status_t    prepareAsync() {return OK;}
-    virtual status_t    start() {return OK;}
-    virtual status_t    stop() {return OK;}
-    virtual status_t    pause() {return OK;}
-    virtual bool        isPlaying() {return true;}
-    virtual status_t    seekTo(int msec) {return OK;}
-    virtual status_t    getCurrentPosition(int *msec) {return OK;}
-    virtual status_t    getDuration(int *msec) {return OK;}
+                                const sp<IGraphicBufferProducer>& /* bufferProducer */) {
+        return OK;
+    }
+    virtual status_t    prepare() { return OK; }
+    virtual status_t    prepareAsync() { return OK; }
+    virtual status_t    start() { return OK; }
+    virtual status_t    stop() { return OK; }
+    virtual status_t    pause() { return OK; }
+    virtual bool        isPlaying() { return true; }
+    virtual status_t    seekTo(int /* msec */) { return OK; }
+    virtual status_t    getCurrentPosition(int* /* msec */) { return OK; }
+    virtual status_t    getDuration(int* /* msec */) { return OK; }
     virtual status_t    reset() {return OK;}
-    virtual status_t    setLooping(int loop) {return OK;}
+    virtual status_t    setLooping(int /* loop */) { return OK; }
     virtual player_type playerType() {return TEST_PLAYER;}
     virtual status_t    invoke(const Parcel& request, Parcel *reply);
-    virtual status_t    setParameter(int key, const Parcel &request) {return OK;}
-    virtual status_t    getParameter(int key, Parcel *reply) {return OK;}
+    virtual status_t    setParameter(int /* key */, const Parcel& /* request */) { return OK; }
+    virtual status_t    getParameter(int /* key */, Parcel* /* reply */) { return OK; }
 
 
   private:
diff --git a/native/android/Android.mk b/native/android/Android.mk
index cda38e0..b3a74a8 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -34,6 +34,8 @@
     frameworks/base/native/include \
     frameworks/base/core/jni/android
 
-LOCAL_MODULE:= libandroid
+LOCAL_MODULE := libandroid
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 3154030..91c9ac6 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -6,27 +6,32 @@
 # setup for skia optimizations
 #
 ifneq ($(ARCH_ARM_HAVE_VFP),true)
-	LOCAL_CFLAGS += -DSK_SOFTWARE_FLOAT
+    LOCAL_CFLAGS += -DSK_SOFTWARE_FLOAT
 endif
 
 ifeq ($(ARCH_ARM_HAVE_NEON),true)
-	LOCAL_CFLAGS += -D__ARM_HAVE_NEON
+    LOCAL_CFLAGS += -D__ARM_HAVE_NEON
 endif
 
 # our source files
 #
 LOCAL_SRC_FILES:= \
-	bitmap.cpp
+    bitmap.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
     libskia
 
 LOCAL_C_INCLUDES += \
-	frameworks/base/native/include \
-	frameworks/base/core/jni/android/graphics
+    frameworks/base/native/include \
+    frameworks/base/core/jni/android/graphics
 
 LOCAL_MODULE:= libjnigraphics
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
+# TODO: This is to work around b/19059885. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp
index df0751d..ddb01a0 100644
--- a/native/graphics/jni/bitmap.cpp
+++ b/native/graphics/jni/bitmap.cpp
@@ -15,7 +15,11 @@
  */
 
 #include <android/bitmap.h>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <GraphicsJNI.h>
+#pragma GCC diagnostic pop
 
 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
                           AndroidBitmapInfo* info) {
@@ -23,7 +27,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
@@ -60,7 +64,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
@@ -83,7 +87,7 @@
         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
     }
 
-    SkBitmap* bm = GraphicsJNI::getNativeBitmap(env, jbitmap);
+    SkBitmap* bm = GraphicsJNI::getSkBitmap(env, jbitmap);
     if (NULL == bm) {
         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
     }
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index a9d33dd..4d890c9 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -29,14 +29,6 @@
 
 public final class GLUtils {
 
-    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets.
-     */
-    static {
-        nativeClassInit();
-    }
-
     private GLUtils() {
     }
 
@@ -275,8 +267,6 @@
      */
     native public static void setTracingLevel(int level);
 
-    native private static void nativeClassInit();
-
     native private static int native_getInternalFormat(Bitmap bitmap);
     native private static int native_getType(Bitmap bitmap);
     native private static int native_texImage2D(int target, int level, int internalformat,
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index d898555..2a9f59f 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -31,13 +31,11 @@
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.Window;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
diff --git a/packages/DefaultContainerService/jni/Android.mk b/packages/DefaultContainerService/jni/Android.mk
index ef4f699..7808ae1 100644
--- a/packages/DefaultContainerService/jni/Android.mk
+++ b/packages/DefaultContainerService/jni/Android.mk
@@ -18,8 +18,6 @@
 
 include $(CLEAR_VARS)
 
-
-
 LOCAL_SRC_FILES := \
     com_android_defcontainer_MeasurementUtils.cpp
 
@@ -37,4 +35,6 @@
 LOCAL_MODULE := libdefcontainer_jni
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/DefaultContainerService/jni/com_android_defcontainer_MeasurementUtils.cpp b/packages/DefaultContainerService/jni/com_android_defcontainer_MeasurementUtils.cpp
index 7390bb7..6be4849 100644
--- a/packages/DefaultContainerService/jni/com_android_defcontainer_MeasurementUtils.cpp
+++ b/packages/DefaultContainerService/jni/com_android_defcontainer_MeasurementUtils.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-static jlong native_measureDirectory(JNIEnv* env, jobject clazz, jstring directory) {
+static jlong native_measureDirectory(JNIEnv* env, jobject /* clazz */, jstring directory) {
     jlong ret = 0L;
 
     const char* path = env->GetStringUTFChars(directory, NULL);
@@ -65,7 +65,7 @@
 
 } // namespace android
 
-int JNI_OnLoad(JavaVM *jvm, void* reserved) {
+int JNI_OnLoad(JavaVM *jvm, void* /* reserved */) {
     JNIEnv *env;
 
     if (jvm->GetEnv((void**)&env, JNI_VERSION_1_6)) {
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index cabc956..8c490ea 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -20,7 +20,7 @@
     <string name="title_open" msgid="4353228937663917801">"Բացել այստեղից"</string>
     <string name="title_save" msgid="2433679664882857999">"Պահել այստեղ"</string>
     <string name="menu_create_dir" msgid="5947289605844398389">"Ստեղծել թղթապանակ"</string>
-    <string name="menu_grid" msgid="6878021334497835259">"Ցանցային տեսք"</string>
+    <string name="menu_grid" msgid="6878021334497835259">"Ցանցի տեսք"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ցուցակի տեսք"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Դասավորել ըստ"</string>
     <string name="menu_search" msgid="3816712084502856974">"Որոնել"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index 4f52a03d..4893652 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -17,9 +17,6 @@
 package com.android.documentsui;
 
 import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index 416aeb0..5378ea9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.provider.DocumentsContract.Document;
 import android.util.TypedValue;
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 7cee066..5e9ec10 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -97,14 +97,18 @@
 
     /** Called on mLooper thread */
     public void enable() {
-        mEnabled = true;
-        updateRequirements();
+        if (!mEnabled) {
+            mEnabled = true;
+            updateRequirements();
+        }
     }
 
     /** Called on mLooper thread */
     public void disable() {
-        mEnabled = false;
-        updateRequirements();
+        if (mEnabled) {
+            mEnabled = false;
+            updateRequirements();
+        }
     }
 
     /** Called on mLooper thread */
@@ -131,16 +135,14 @@
     private void enableProvider(String name, long minTime) {
         ProviderStats stats = mStats.get(name);
 
-        if (stats.available) {
-            if (!stats.requested) {
-                stats.requestTime = SystemClock.elapsedRealtime();
-                stats.requested = true;
-                stats.minTime = minTime;
-                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
-            } else if (stats.minTime != minTime) {
-                stats.minTime = minTime;
-                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
-            }
+        if (!stats.requested) {
+            stats.requestTime = SystemClock.elapsedRealtime();
+            stats.requested = true;
+            stats.minTime = minTime;
+            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
+        } else if (stats.minTime != minTime) {
+            stats.minTime = minTime;
+            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
         }
     }
 
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 04c19e3..40722f6 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -3,7 +3,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="8016145283189546017">"Eingabegeräte"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Android-Tastatur"</string>
-    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Englisch (Großbritannien)"</string>
+    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Englisch (Vereinigtes Königreich)"</string>
     <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Englisch (USA)"</string>
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Englisch (USA), international"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Englisch (USA), Colemak"</string>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 352317d..e19246c 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -40,6 +40,7 @@
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
+    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
 
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
diff --git a/packages/Keyguard/res/anim/keyguard_action_assist_enter.xml b/packages/Keyguard/res/anim/keyguard_action_assist_enter.xml
deleted file mode 100644
index f3333b7..0000000
--- a/packages/Keyguard/res/anim/keyguard_action_assist_enter.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?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" android:toAlpha="1.0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@android:interpolator/decelerate_cubic"
-            android:duration="300"/>
-
-    <translate android:fromYDelta="100%" android:toYDelta="0"
-            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-            android:interpolator="@android:interpolator/decelerate_cubic"
-            android:duration="300" />
-</set>
diff --git a/packages/Keyguard/res/anim/keyguard_action_assist_exit.xml b/packages/Keyguard/res/anim/keyguard_action_assist_exit.xml
deleted file mode 100644
index b4ed278..0000000
--- a/packages/Keyguard/res/anim/keyguard_action_assist_exit.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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.
-*/
--->
-
-<translate xmlns:android="http://schemas.android.com/apk/res/android"
-       android:interpolator="@android:anim/accelerate_interpolator"
-       android:fromXDelta="0" android:toXDelta="0"
-       android:duration="300" />
diff --git a/packages/Keyguard/res/anim/lock_screen_enter.xml b/packages/Keyguard/res/anim/lock_screen_enter.xml
deleted file mode 100644
index 4344cf9..0000000
--- a/packages/Keyguard/res/anim/lock_screen_enter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:interpolator/accelerate_cubic">
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@integer/config_activityDefaultDur" />
-</set>
diff --git a/packages/Keyguard/res/anim/lock_screen_exit.xml b/packages/Keyguard/res/anim/lock_screen_exit.xml
deleted file mode 100644
index c75b3cc..0000000
--- a/packages/Keyguard/res/anim/lock_screen_exit.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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.
-*/
--->
-
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    android:zAdjustment="top"
-    android:shareInterpolator="false">
-    <scale
-        android:fromXScale="1.0" android:toXScale="1.10"
-        android:fromYScale="1.0" android:toYScale="1.10"
-        android:pivotX="50%p" android:pivotY="50%p"
-        android:fillEnabled="true" android:fillAfter="true"
-        android:interpolator="@android:interpolator/accelerate_quint"
-        android:duration="@android:integer/config_shortAnimTime" />
-    <alpha
-        android:fromAlpha="1.0" android:toAlpha="0"
-        android:fillEnabled="true" android:fillAfter="true"
-        android:interpolator="@android:interpolator/accelerate_quad"
-        android:duration="@android:integer/config_shortAnimTime"/>
-</set>
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-hdpi/ic_facial_backup.png
deleted file mode 100644
index 2956109..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_facial_backup.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_activated.png
deleted file mode 100644
index 19c8eb2..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_normal.png
deleted file mode 100644
index c79a245..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_camera_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
deleted file mode 100644
index 460495a..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
deleted file mode 100644
index b0f7ae9..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index 983c45e..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_activated.png
deleted file mode 100644
index 2c4847c..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_focused.png
deleted file mode 100644
index d98557d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_normal.png
deleted file mode 100644
index 656f3ba..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_google_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index 1780ec0..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index 58a5f16..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_normal.png
deleted file mode 100644
index 732133c..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
deleted file mode 100644
index 0bbf62f..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_player_background.9.png
deleted file mode 100644
index fbb75b5..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_player_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_activated.png
deleted file mode 100644
index 0d2e2ef..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_normal.png
deleted file mode 100644
index 66d14ae..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_search_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_activated.png
deleted file mode 100644
index 7060d59..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_focused.png
deleted file mode 100644
index f9a8c7c..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_normal.png
deleted file mode 100644
index b47cd08..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_silent_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
deleted file mode 100644
index 88d0a9f..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
deleted file mode 100644
index 6e16e40..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
deleted file mode 100644
index 0dd81c0..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
deleted file mode 100644
index 374a62a..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
deleted file mode 100644
index 3960893..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_next.png b/packages/Keyguard/res/drawable-hdpi/ic_media_next.png
deleted file mode 100644
index 6e27b81..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_media_next.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_play.png b/packages/Keyguard/res/drawable-hdpi/ic_media_play.png
deleted file mode 100644
index 2746d17..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_media_play.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png
deleted file mode 100644
index 85b3766..0000000
--- a/packages/Keyguard/res/drawable-hdpi/ic_media_previous.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/intro_bg.png b/packages/Keyguard/res/drawable-hdpi/intro_bg.png
deleted file mode 100644
index a758e7d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/intro_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png
deleted file mode 100644
index 7456705..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget_disabled.png
deleted file mode 100644
index f24cf642..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_add_widget_disabled.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png
deleted file mode 100644
index 70a960d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-hdpi/kg_security_grip.9.png
deleted file mode 100644
index 1e40aef..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_security_grip.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock.png
deleted file mode 100644
index c3c94c4..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_security_lock.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png
deleted file mode 100644
index 9a82799..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 7ca995d..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index 476a826..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-hdpi/kg_widget_delete_drop_target.png
deleted file mode 100644
index 84549ff..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_widget_delete_drop_target.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-hdpi/lockscreen_protection_pattern.png
deleted file mode 100644
index 681d8be..0000000
--- a/packages/Keyguard/res/drawable-hdpi/lockscreen_protection_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/progress_bg_holo_light.9.png b/packages/Keyguard/res/drawable-hdpi/progress_bg_holo_light.9.png
deleted file mode 100644
index 2d79280..0000000
--- a/packages/Keyguard/res/drawable-hdpi/progress_bg_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/progress_primary_holo_light.9.png b/packages/Keyguard/res/drawable-hdpi/progress_primary_holo_light.9.png
deleted file mode 100644
index 543cb85..0000000
--- a/packages/Keyguard/res/drawable-hdpi/progress_primary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/progress_secondary_holo_light.9.png b/packages/Keyguard/res/drawable-hdpi/progress_secondary_holo_light.9.png
deleted file mode 100644
index 4497058..0000000
--- a/packages/Keyguard/res/drawable-hdpi/progress_secondary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_control_disabled_holo.png b/packages/Keyguard/res/drawable-hdpi/scrubber_control_disabled_holo.png
deleted file mode 100644
index ba77899..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_control_disabled_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_control_focused_holo.png b/packages/Keyguard/res/drawable-hdpi/scrubber_control_focused_holo.png
deleted file mode 100644
index 539ee22..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_control_focused_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_control_normal_holo.png b/packages/Keyguard/res/drawable-hdpi/scrubber_control_normal_holo.png
deleted file mode 100644
index 9a4ea2f..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_control_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_control_pressed_holo.png b/packages/Keyguard/res/drawable-hdpi/scrubber_control_pressed_holo.png
deleted file mode 100644
index e6b11de..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_control_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_primary_holo.9.png b/packages/Keyguard/res/drawable-hdpi/scrubber_primary_holo.9.png
deleted file mode 100644
index 822e8d11..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_secondary_holo.9.png b/packages/Keyguard/res/drawable-hdpi/scrubber_secondary_holo.9.png
deleted file mode 100644
index be4253e..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/scrubber_track_holo_light.9.png b/packages/Keyguard/res/drawable-hdpi/scrubber_track_holo_light.9.png
deleted file mode 100644
index 2334e14..0000000
--- a/packages/Keyguard/res/drawable-hdpi/scrubber_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-hdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-hdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index f1bcf48..0000000
--- a/packages/Keyguard/res/drawable-hdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png b/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png
deleted file mode 100644
index d7eff17..0000000
--- a/packages/Keyguard/res/drawable-ldpi/ic_input_delete.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_next.png b/packages/Keyguard/res/drawable-ldpi/ic_media_next.png
deleted file mode 100644
index 99927fd..0000000
--- a/packages/Keyguard/res/drawable-ldpi/ic_media_next.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_play.png b/packages/Keyguard/res/drawable-ldpi/ic_media_play.png
deleted file mode 100644
index e7c1972..0000000
--- a/packages/Keyguard/res/drawable-ldpi/ic_media_play.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png b/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png
deleted file mode 100644
index df04322..0000000
--- a/packages/Keyguard/res/drawable-ldpi/ic_media_previous.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-mdpi/ic_facial_backup.png
deleted file mode 100644
index 6ed1327..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_facial_backup.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_activated.png
deleted file mode 100644
index 862f33b..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_normal.png
deleted file mode 100644
index 30df0a3..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_camera_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
deleted file mode 100644
index cae795f..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
deleted file mode 100644
index 2867956..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index 056c3f17..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_activated.png
deleted file mode 100644
index 32a68e0..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_focused.png
deleted file mode 100644
index 3f96d03..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_normal.png
deleted file mode 100644
index 2f7efcf..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_google_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index 1d547e1..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index 0187a02..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_normal.png
deleted file mode 100644
index 30eb974..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
deleted file mode 100644
index aab2f6b..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_player_background.9.png
deleted file mode 100644
index 17d97c4..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_player_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_activated.png
deleted file mode 100644
index 73c6be6..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_normal.png
deleted file mode 100644
index 73c6be6..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_search_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_activated.png
deleted file mode 100644
index 2bc3f52..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_focused.png
deleted file mode 100644
index 6a5af9d..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_normal.png
deleted file mode 100644
index c288ce4..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_silent_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
deleted file mode 100644
index 637eec6..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
deleted file mode 100644
index db59b5f..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
deleted file mode 100644
index eb6ceed..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
deleted file mode 100644
index 68409c5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
deleted file mode 100644
index 52866f2..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_next.png b/packages/Keyguard/res/drawable-mdpi/ic_media_next.png
deleted file mode 100644
index fcd73d9..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_media_next.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_play.png b/packages/Keyguard/res/drawable-mdpi/ic_media_play.png
deleted file mode 100644
index 7966bbc..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_media_play.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png
deleted file mode 100644
index b653d05..0000000
--- a/packages/Keyguard/res/drawable-mdpi/ic_media_previous.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/intro_bg.png b/packages/Keyguard/res/drawable-mdpi/intro_bg.png
deleted file mode 100644
index 540da31..0000000
--- a/packages/Keyguard/res/drawable-mdpi/intro_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png
deleted file mode 100644
index 1cab0d9..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget_disabled.png
deleted file mode 100644
index 02e0f0e..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_add_widget_disabled.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png
deleted file mode 100644
index a68d4c1..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-mdpi/kg_security_grip.9.png
deleted file mode 100644
index 334a39b..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_security_grip.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock.png
deleted file mode 100644
index a39f380..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_security_lock.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png
deleted file mode 100644
index c3608f9..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 41715f5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index aa441de..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-mdpi/kg_widget_delete_drop_target.png
deleted file mode 100644
index 219f3e5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_widget_delete_drop_target.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-mdpi/lockscreen_protection_pattern.png
deleted file mode 100644
index 30bcea5..0000000
--- a/packages/Keyguard/res/drawable-mdpi/lockscreen_protection_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/progress_bg_holo_light.9.png b/packages/Keyguard/res/drawable-mdpi/progress_bg_holo_light.9.png
deleted file mode 100644
index ff40433..0000000
--- a/packages/Keyguard/res/drawable-mdpi/progress_bg_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/progress_primary_holo_light.9.png b/packages/Keyguard/res/drawable-mdpi/progress_primary_holo_light.9.png
deleted file mode 100644
index d5f874d..0000000
--- a/packages/Keyguard/res/drawable-mdpi/progress_primary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/progress_secondary_holo_light.9.png b/packages/Keyguard/res/drawable-mdpi/progress_secondary_holo_light.9.png
deleted file mode 100644
index f027007..0000000
--- a/packages/Keyguard/res/drawable-mdpi/progress_secondary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_control_disabled_holo.png b/packages/Keyguard/res/drawable-mdpi/scrubber_control_disabled_holo.png
deleted file mode 100644
index 981facd..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_control_disabled_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_control_focused_holo.png b/packages/Keyguard/res/drawable-mdpi/scrubber_control_focused_holo.png
deleted file mode 100644
index d432f42..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_control_focused_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_control_normal_holo.png b/packages/Keyguard/res/drawable-mdpi/scrubber_control_normal_holo.png
deleted file mode 100644
index 7bb749e..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_control_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_control_pressed_holo.png b/packages/Keyguard/res/drawable-mdpi/scrubber_control_pressed_holo.png
deleted file mode 100644
index 43d826e..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_control_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_primary_holo.9.png b/packages/Keyguard/res/drawable-mdpi/scrubber_primary_holo.9.png
deleted file mode 100644
index 98ac428..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_secondary_holo.9.png b/packages/Keyguard/res/drawable-mdpi/scrubber_secondary_holo.9.png
deleted file mode 100644
index d8b563b..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/scrubber_track_holo_light.9.png b/packages/Keyguard/res/drawable-mdpi/scrubber_track_holo_light.9.png
deleted file mode 100644
index 47c5dd9..0000000
--- a/packages/Keyguard/res/drawable-mdpi/scrubber_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-mdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index d5a7708..0000000
--- a/packages/Keyguard/res/drawable-mdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index f28fe38..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index 728fc67..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-hdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index 99e742f..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index c7da024..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-mdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index 75e4783..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index 534c10b..0000000
--- a/packages/Keyguard/res/drawable-sw600dp-xhdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_facial_backup.png b/packages/Keyguard/res/drawable-xhdpi/ic_facial_backup.png
deleted file mode 100644
index 942cf23..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_facial_backup.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
deleted file mode 100644
index 760ef2d..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
deleted file mode 100644
index 093bc05..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_camera_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
deleted file mode 100644
index a61f7a5..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
deleted file mode 100644
index dd5e481..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index cbd039a..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_activated.png
deleted file mode 100644
index d643f83..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_focused.png
deleted file mode 100644
index 51863f4..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_normal.png
deleted file mode 100644
index 9a9bf68..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_google_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_normal.png
deleted file mode 100644
index b09071b..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png
deleted file mode 100644
index 2d28009..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_handle_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
deleted file mode 100644
index c44a330..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
deleted file mode 100644
index 2264dc3..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_player_background.9.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
deleted file mode 100644
index 393bca6..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_player_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
deleted file mode 100644
index 2900045..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
deleted file mode 100644
index 5a93472..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
deleted file mode 100644
index 73f6a2e..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
deleted file mode 100644
index da2adc2..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
deleted file mode 100644
index 0485af0..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
deleted file mode 100644
index 6af5375..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
deleted file mode 100644
index 8a0331d..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
deleted file mode 100644
index 0422117..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png
deleted file mode 100644
index 4def965..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_media_next.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png
deleted file mode 100644
index ccfef18..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_media_play.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png b/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png
deleted file mode 100644
index c4472ae..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/ic_media_previous.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/intro_bg.png b/packages/Keyguard/res/drawable-xhdpi/intro_bg.png
deleted file mode 100644
index 00466c5..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/intro_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png
deleted file mode 100644
index d71905f..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_disabled.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_disabled.png
deleted file mode 100644
index 55fa1ac..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_disabled.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png
deleted file mode 100644
index edf7070..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_grip.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_grip.9.png
deleted file mode 100644
index c33b9d3..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_security_grip.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock.png
deleted file mode 100644
index 81d577e..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png
deleted file mode 100644
index db22016..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_focused.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png b/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png
deleted file mode 100644
index 186b6ff..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_security_lock_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index 6c372dd..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_widget_delete_drop_target.png b/packages/Keyguard/res/drawable-xhdpi/kg_widget_delete_drop_target.png
deleted file mode 100644
index d4965d9..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_widget_delete_drop_target.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/lockscreen_protection_pattern.png b/packages/Keyguard/res/drawable-xhdpi/lockscreen_protection_pattern.png
deleted file mode 100644
index c13afe2..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/lockscreen_protection_pattern.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/progress_bg_holo_light.9.png b/packages/Keyguard/res/drawable-xhdpi/progress_bg_holo_light.9.png
deleted file mode 100644
index dff0939..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/progress_bg_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/progress_primary_holo_light.9.png b/packages/Keyguard/res/drawable-xhdpi/progress_primary_holo_light.9.png
deleted file mode 100644
index 60b8198..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/progress_primary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/progress_secondary_holo_light.9.png b/packages/Keyguard/res/drawable-xhdpi/progress_secondary_holo_light.9.png
deleted file mode 100644
index 11b31be..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/progress_secondary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_disabled_holo.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_control_disabled_holo.png
deleted file mode 100644
index ffe913d..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_disabled_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_focused_holo.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_control_focused_holo.png
deleted file mode 100644
index 2fccb8f..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_focused_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_normal_holo.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_control_normal_holo.png
deleted file mode 100644
index a638501..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_pressed_holo.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_control_pressed_holo.png
deleted file mode 100644
index f0e65ea..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_control_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_primary_holo.9.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_primary_holo.9.png
deleted file mode 100644
index 04f6ae3..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_secondary_holo.9.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_secondary_holo.9.png
deleted file mode 100644
index 7fef98d..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/scrubber_track_holo_light.9.png b/packages/Keyguard/res/drawable-xhdpi/scrubber_track_holo_light.9.png
deleted file mode 100644
index a712169..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/scrubber_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/sym_keyboard_return_holo.png b/packages/Keyguard/res/drawable-xhdpi/sym_keyboard_return_holo.png
deleted file mode 100644
index 55174e0..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/sym_keyboard_return_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/kg_add_widget_pressed.png b/packages/Keyguard/res/drawable-xxhdpi/kg_add_widget_pressed.png
deleted file mode 100644
index 0c0838b..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/kg_add_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png b/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
deleted file mode 100644
index f4e398b..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/kg_widget_bg_padded.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/progress_bg_holo_light.9.png b/packages/Keyguard/res/drawable-xxhdpi/progress_bg_holo_light.9.png
deleted file mode 100644
index 60a8e22..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/progress_bg_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/progress_primary_holo_light.9.png b/packages/Keyguard/res/drawable-xxhdpi/progress_primary_holo_light.9.png
deleted file mode 100644
index 18384d3..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/progress_primary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/progress_secondary_holo_light.9.png b/packages/Keyguard/res/drawable-xxhdpi/progress_secondary_holo_light.9.png
deleted file mode 100644
index 82eb615..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/progress_secondary_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_disabled_holo.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_disabled_holo.png
deleted file mode 100644
index d1ac7ae..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_disabled_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_focused_holo.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_focused_holo.png
deleted file mode 100644
index 58a2976..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_focused_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_normal_holo.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_normal_holo.png
deleted file mode 100644
index 6f696fd..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_pressed_holo.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_pressed_holo.png
deleted file mode 100644
index faae4e3..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_control_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_primary_holo.9.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_primary_holo.9.png
deleted file mode 100644
index 82c2b7e..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_secondary_holo.9.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_secondary_holo.9.png
deleted file mode 100644
index 800d95e..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xxhdpi/scrubber_track_holo_light.9.png b/packages/Keyguard/res/drawable-xxhdpi/scrubber_track_holo_light.9.png
deleted file mode 100644
index 9991f7f..0000000
--- a/packages/Keyguard/res/drawable-xxhdpi/scrubber_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_camera.xml b/packages/Keyguard/res/drawable/ic_lockscreen_camera.xml
deleted file mode 100644
index 41277fe..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_camera.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_camera_normal" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_camera_activated" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="true"
-        android:drawable="@drawable/ic_lockscreen_camera_activated" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_handle.xml b/packages/Keyguard/res/drawable/ic_lockscreen_handle.xml
deleted file mode 100644
index e7b4a6e..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_handle.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_handle_normal" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_handle_pressed" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml b/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml
deleted file mode 100644
index 75bea70..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_outerring.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval"
-    >
-    <size android:height="@dimen/keyguard_lockscreen_outerring_diameter"
-          android:width="@dimen/keyguard_lockscreen_outerring_diameter" />
-    <solid android:color="#00000000" />
-    <stroke android:color="#1affffff" android:width="2dp" />
-</shape>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_silent.xml b/packages/Keyguard/res/drawable/ic_lockscreen_silent.xml
deleted file mode 100644
index df23278..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_silent.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_silent_normal" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_silent_activated" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="true"
-        android:drawable="@drawable/ic_lockscreen_silent_activated" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_soundon.xml b/packages/Keyguard/res/drawable/ic_lockscreen_soundon.xml
deleted file mode 100644
index b44c86c..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_soundon.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_soundon_normal" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_soundon_activated" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="true"
-        android:drawable="@drawable/ic_lockscreen_soundon_activated" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_unlock.xml b/packages/Keyguard/res/drawable/ic_lockscreen_unlock.xml
deleted file mode 100644
index bb1d0ee..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_unlock.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_unlock_normal" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_unlock_activated" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="true"
-        android:drawable="@drawable/ic_lockscreen_unlock_activated" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/ic_lockscreen_unlock_phantom.xml b/packages/Keyguard/res/drawable/ic_lockscreen_unlock_phantom.xml
deleted file mode 100644
index 83f0aed..0000000
--- a/packages/Keyguard/res/drawable/ic_lockscreen_unlock_phantom.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="false"
-        android:drawable="@color/transparent" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="true"
-        android:state_focused="false"
-        android:drawable="@drawable/ic_lockscreen_unlock_activated" />
-
-    <item
-        android:state_enabled="true"
-        android:state_active="false"
-        android:state_focused="true"
-        android:drawable="@drawable/ic_lockscreen_unlock_activated" />
-
-</selector>
diff --git a/packages/Keyguard/res/drawable/keyguard_add_widget_button.xml b/packages/Keyguard/res/drawable/keyguard_add_widget_button.xml
deleted file mode 100644
index c26f81d..0000000
--- a/packages/Keyguard/res/drawable/keyguard_add_widget_button.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/kg_add_widget_pressed" />
-    <item android:state_enabled="false" android:drawable="@drawable/kg_add_widget_disabled" />
-    <item android:drawable="@drawable/kg_add_widget" />
-</selector>
diff --git a/packages/Keyguard/res/drawable/keyguard_expand_challenge_handle.xml b/packages/Keyguard/res/drawable/keyguard_expand_challenge_handle.xml
deleted file mode 100644
index 3e0780b..0000000
--- a/packages/Keyguard/res/drawable/keyguard_expand_challenge_handle.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_focused="true" android:drawable="@drawable/kg_security_lock_focused" />
-    <item android:state_pressed="true" android:drawable="@drawable/kg_security_lock_pressed" />
-    <item android:drawable="@drawable/kg_security_lock_normal" />
-</selector>
diff --git a/packages/Keyguard/res/drawable/lockscreen_emergency_button.xml b/packages/Keyguard/res/drawable/lockscreen_emergency_button.xml
deleted file mode 100644
index 4ec6a96..0000000
--- a/packages/Keyguard/res/drawable/lockscreen_emergency_button.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true" android:drawable="@drawable/ic_lockscreen_emergencycall_normal" />
-    <item android:state_pressed="true" android:drawable="@drawable/ic_lockscreen_emergencycall_pressed" />
-    <item android:drawable="@drawable/ic_lockscreen_emergencycall_normal" />
-</selector>
diff --git a/packages/Keyguard/res/drawable/scrubber_control_selector_holo.xml b/packages/Keyguard/res/drawable/scrubber_control_selector_holo.xml
deleted file mode 100644
index d09b1a5..0000000
--- a/packages/Keyguard/res/drawable/scrubber_control_selector_holo.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:drawable="@drawable/scrubber_control_disabled_holo" />
-    <item android:state_pressed="true" android:drawable="@drawable/scrubber_control_pressed_holo" />
-    <item android:state_selected="true" android:drawable="@drawable/scrubber_control_focused_holo" />
-    <item android:drawable="@drawable/scrubber_control_normal_holo" />
-</selector>
diff --git a/packages/Keyguard/res/drawable/scrubber_progress_horizontal_holo_light.xml b/packages/Keyguard/res/drawable/scrubber_progress_horizontal_holo_light.xml
deleted file mode 100644
index f07c742..0000000
--- a/packages/Keyguard/res/drawable/scrubber_progress_horizontal_holo_light.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@android:id/background"
-            android:drawable="@drawable/scrubber_track_holo_light" />
-    <item android:id="@android:id/secondaryProgress">
-        <scale android:scaleWidth="100%"
-               android:drawable="@drawable/scrubber_secondary_holo" />
-    </item>
-    <item android:id="@android:id/progress">
-        <scale android:scaleWidth="100%"
-               android:drawable="@drawable/scrubber_primary_holo" />
-    </item>
-</layer-list>
diff --git a/packages/Keyguard/res/layout-land/keyguard_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
deleted file mode 100644
index 891910e..0000000
--- a/packages/Keyguard/res/layout-land/keyguard_host_view.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal"
-    android:clipChildren="false"
-    android:clipToPadding="false">
-
-    <com.android.keyguard.MultiPaneChallengeLayout
-        android:id="@+id/multi_pane_challenge"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="horizontal"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-
-        <include layout="@layout/keyguard_widget_remove_drop_target"
-            android:id="@+id/keyguard_widget_pager_delete_target"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            androidprv:layout_childType="pageDeleteDropTarget" />
-
-        <include layout="@layout/keyguard_widget_pager"
-            android:id="@+id/app_widget_container"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_centerWithinArea="0.55"
-            androidprv:layout_childType="widget"
-            androidprv:layout_maxWidth="480dp"
-            androidprv:layout_maxHeight="480dp" />
-        <include layout="@layout/keyguard_multi_user_selector"/>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            androidprv:layout_childType="challenge"
-            androidprv:layout_centerWithinArea="0.55">
-            <com.android.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingLeft="@dimen/keyguard_security_view_margin"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:paddingRight="@dimen/keyguard_security_view_margin"
-                android:paddingBottom="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.keyguard.KeyguardSecurityContainer>
-
-    </com.android.keyguard.MultiPaneChallengeLayout>
-</com.android.keyguard.KeyguardHostView>
-
diff --git a/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
deleted file mode 100644
index 50c2709..0000000
--- a/packages/Keyguard/res/layout-land/keyguard_widget_pager.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.keyguard.KeyguardWidgetCarousel
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:paddingLeft="25dp"
-    android:paddingRight="25dp"
-    android:paddingTop="25dp"
-    android:paddingBottom="25dp"
-    android:clipToPadding="false"
-    androidprv:pageSpacing="10dp">
-</com.android.keyguard.KeyguardWidgetCarousel>
diff --git a/packages/Keyguard/res/layout-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
deleted file mode 100644
index 1b8820b..0000000
--- a/packages/Keyguard/res/layout-port/keyguard_host_view.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center_horizontal"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="vertical">
-
-    <com.android.keyguard.SlidingChallengeLayout
-        android:id="@+id/sliding_layout"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            androidprv:layout_childType="pageDeleteDropTarget">
-            <include layout="@layout/keyguard_widget_remove_drop_target"
-                android:id="@+id/keyguard_widget_pager_delete_target"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="top|center_horizontal" />
-        </FrameLayout>
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_childType="widgets">
-            <include layout="@layout/keyguard_widget_pager"
-                android:id="@+id/app_widget_container"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_gravity="center"/>
-        </FrameLayout>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-            androidprv:layout_childType="challenge"
-            android:padding="0dp"
-            android:gravity="bottom|center_horizontal">
-            <com.android.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.keyguard.KeyguardSecurityContainer>
-
-        <ImageButton
-              android:layout_width="match_parent"
-              android:layout_height="@dimen/kg_widget_pager_bottom_padding"
-              androidprv:layout_childType="expandChallengeHandle"
-              android:focusable="true"
-              android:background="@null"
-              android:src="@drawable/keyguard_expand_challenge_handle"
-              android:scaleType="center"
-              android:contentDescription="@string/keyguard_accessibility_expand_lock_area" />
-
-    </com.android.keyguard.SlidingChallengeLayout>
-</com.android.keyguard.KeyguardHostView>
-
diff --git a/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml b/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
deleted file mode 100644
index 6d7d864..0000000
--- a/packages/Keyguard/res/layout-port/keyguard_widget_pager.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.keyguard.KeyguardWidgetPager
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/app_widget_container"
-    android:paddingLeft="25dp"
-    android:paddingRight="25dp"
-    android:paddingTop="25dp"
-    android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
-    android:clipToPadding="false"
-    androidprv:pageSpacing="10dp">
-</com.android.keyguard.KeyguardWidgetPager>
diff --git a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
deleted file mode 100644
index f2f3981..0000000
--- a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.keyguard.KeyguardHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal"
-    android:clipChildren="false"
-    android:clipToPadding="false">
-
-    <com.android.keyguard.MultiPaneChallengeLayout
-        android:id="@+id/multi_pane_challenge"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_widget_remove_drop_target"
-            android:id="@+id/keyguard_widget_pager_delete_target"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|center_horizontal"
-            androidprv:layout_childType="pageDeleteDropTarget" />
-
-        <include layout="@layout/keyguard_widget_pager"
-            android:id="@+id/app_widget_container"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            androidprv:layout_centerWithinArea="0.5"
-            androidprv:layout_childType="widget"
-            androidprv:layout_maxWidth="480dp"
-            androidprv:layout_maxHeight="480dp" />
-
-        <include layout="@layout/keyguard_multi_user_selector"/>
-
-        <View android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              androidprv:layout_childType="scrim"
-              android:background="#99000000" />
-
-        <com.android.keyguard.KeyguardSecurityContainer
-            android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            androidprv:layout_centerWithinArea="0.5"
-            androidprv:layout_childType="challenge"
-            android:layout_gravity="center_horizontal|bottom">
-            <com.android.keyguard.KeyguardSecurityViewFlipper
-                android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:paddingLeft="@dimen/keyguard_security_view_margin"
-                android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:paddingRight="@dimen/keyguard_security_view_margin"
-                android:paddingBottom="@dimen/keyguard_security_view_margin"
-                android:gravity="center">
-            </com.android.keyguard.KeyguardSecurityViewFlipper>
-        </com.android.keyguard.KeyguardSecurityContainer>
-
-    </com.android.keyguard.MultiPaneChallengeLayout>
-</com.android.keyguard.KeyguardHostView>
diff --git a/packages/Keyguard/res/layout-sw600dp/keyguard_glow_pad_container.xml b/packages/Keyguard/res/layout-sw600dp/keyguard_glow_pad_container.xml
deleted file mode 100644
index 930b14e..0000000
--- a/packages/Keyguard/res/layout-sw600dp/keyguard_glow_pad_container.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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.
-*/
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/keyguard_glow_pad_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center" />
-</merge>
\ No newline at end of file
diff --git a/packages/Keyguard/res/layout/keyguard_account_view.xml b/packages/Keyguard/res/layout/keyguard_account_view.xml
deleted file mode 100644
index bde2ec6..0000000
--- a/packages/Keyguard/res/layout/keyguard_account_view.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?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.
-*/
--->
-<com.android.keyguard.KeyguardAccountView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-	xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_account_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:orientation="vertical">
-
-    <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1">
-
-        <EditText
-            android:id="@+id/login"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:layout_marginStart="7dip"
-            android:layout_marginEnd="7dip"
-            android:layout_alignParentTop="true"
-            android:hint="@string/kg_login_username_hint"
-            android:inputType="textEmailAddress"
-            />
-
-        <EditText
-            android:id="@+id/password"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/login"
-            android:layout_toLeftOf="@+id/ok"
-            android:layout_marginTop="15dip"
-            android:layout_marginStart="7dip"
-            android:layout_marginEnd="7dip"
-            android:inputType="textPassword"
-            android:hint="@string/kg_login_password_hint"
-            android:nextFocusRight="@+id/ok"
-            android:nextFocusDown="@+id/ok"
-            />
-
-        <!-- ok below password, aligned to right of screen -->
-        <Button
-            android:id="@+id/ok"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_margin="7dip"
-            android:layout_alignParentEnd="true"
-            android:layout_below="@id/login"
-            android:text="@string/kg_login_submit_button"
-            />
-
-    </RelativeLayout>
-
-    <!--  no room for ECA on this screen right now
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
-    -->
-
-</com.android.keyguard.KeyguardAccountView>
diff --git a/packages/Keyguard/res/layout/keyguard_add_widget.xml b/packages/Keyguard/res/layout/keyguard_add_widget.xml
deleted file mode 100644
index 01b616c..0000000
--- a/packages/Keyguard/res/layout/keyguard_add_widget.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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.keyguard.KeyguardWidgetFrame
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_add_widget"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-    <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:contentDescription="@string/keyguard_accessibility_widget_empty_slot"
-            >
-        <ImageView
-            android:id="@+id/keyguard_add_widget_view"
-            android:clickable="true"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:padding="24dp"
-            android:src="@drawable/keyguard_add_widget_button"
-            android:contentDescription="@string/keyguard_accessibility_add_widget"/>
-    </FrameLayout>
-</com.android.keyguard.KeyguardWidgetFrame>
diff --git a/packages/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
index 296efb3..8c80e78 100644
--- a/packages/Keyguard/res/layout/keyguard_bouncer.xml
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -24,7 +24,7 @@
 
     <include
         style="@style/BouncerSecurityContainer"
-        layout="@layout/keyguard_simple_host_view"
+        layout="@layout/keyguard_host_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 </FrameLayout>
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index a083f89..7e09a5b 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -46,13 +46,11 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_marginTop="@dimen/eca_overlap"
-        android:drawableLeft="@drawable/lockscreen_emergency_button"
         android:text="@string/kg_emergency_call_label"
         style="?android:attr/buttonBarButtonStyle"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textSize="@dimen/kg_status_line_font_size"
         android:textColor="?android:attr/textColorSecondary"
-        android:drawablePadding="8dip"
         android:textAllCaps="@bool/kg_use_all_caps" />
 
 </com.android.keyguard.EmergencyCarrierArea>
diff --git a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
deleted file mode 100644
index 0c85dab..0000000
--- a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the screen that allows the user to unlock by showing their face.  -->
-<com.android.keyguard.KeyguardFaceUnlockView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_face_unlock_view"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:contentDescription="@string/keyguard_accessibility_face_unlock">
-
-    <include layout="@layout/keyguard_message_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-
-    <FrameLayout
-       android:id="@+id/keyguard_bouncer_frame"
-       android:layout_width="match_parent"
-       android:layout_height="0dp"
-       android:layout_weight="1"
-       >
-       <com.android.internal.widget.FaceUnlockView
-           android:id="@+id/face_unlock_area_view"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent"
-           android:layout_gravity="center_horizontal"
-           android:background="@drawable/intro_bg"
-           android:gravity="center">
-
-           <View
-               android:id="@+id/spotlightMask"
-               android:layout_width="match_parent"
-               android:layout_height="match_parent"
-               android:background="@color/facelock_spotlight_mask"
-           />
-
-           <ImageButton
-               android:id="@+id/face_unlock_cancel_button"
-               android:layout_width="wrap_content"
-               android:layout_height="wrap_content"
-               android:padding="5dip"
-               android:layout_alignParentTop="true"
-               android:layout_alignParentEnd="true"
-               android:background="#00000000"
-               android:src="@drawable/ic_facial_backup"
-           />
-       </com.android.internal.widget.FaceUnlockView>
-    </FrameLayout>
-
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
-</com.android.keyguard.KeyguardFaceUnlockView>
diff --git a/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml b/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml
deleted file mode 100644
index 07953b4..0000000
--- a/packages/Keyguard/res/layout/keyguard_glow_pad_container.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/keyguard_glow_pad_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginBottom="@dimen/glowpadcontainer_bottom_margin"/>
-</merge>
diff --git a/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml b/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml
deleted file mode 100644
index 2432336..0000000
--- a/packages/Keyguard/res/layout/keyguard_glow_pad_view.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.internal.widget.multiwaveview.GlowPadView
-    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/glow_pad_view"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:orientation="horizontal"
-    android:gravity="@integer/kg_selector_gravity"
-    android:contentDescription="@string/keyguard_accessibility_slide_area"
-    prvandroid:handleDrawable="@drawable/ic_lockscreen_handle"
-    prvandroid:outerRingDrawable="@drawable/ic_lockscreen_outerring"
-    prvandroid:outerRadius="@dimen/glowpadview_target_placement_radius"
-    prvandroid:innerRadius="@dimen/glowpadview_inner_radius"
-    prvandroid:snapMargin="@dimen/glowpadview_snap_margin"
-    prvandroid:firstItemOffset="@integer/kg_glowpad_rotation_offset"
-    prvandroid:magneticTargets="true"
-    prvandroid:feedbackCount="1"
-    prvandroid:vibrationDuration="20"
-    prvandroid:glowRadius="@dimen/glowpadview_glow_radius"
-    prvandroid:pointDrawable="@drawable/ic_lockscreen_glowdot"
-    prvandroid:allowScaling="true" />
diff --git a/packages/Keyguard/res/layout/keyguard_host_view.xml b/packages/Keyguard/res/layout/keyguard_host_view.xml
new file mode 100644
index 0000000..7291cd4
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_host_view.xml
@@ -0,0 +1,54 @@
+<?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.
+*/
+-->
+
+<!-- This is the host view that generally contains two sub views: the widget view
+    and the security view. -->
+<com.android.keyguard.KeyguardHostView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_host_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
+                                                  from this view when bouncer is shown -->
+
+    <com.android.keyguard.KeyguardSecurityContainer
+        android:id="@+id/keyguard_security_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:padding="0dp"
+        android:layout_gravity="center">
+        <com.android.keyguard.KeyguardSecurityViewFlipper
+            android:id="@+id/view_flipper"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:paddingTop="@dimen/keyguard_security_view_margin"
+            android:gravity="center">
+        </com.android.keyguard.KeyguardSecurityViewFlipper>
+    </com.android.keyguard.KeyguardSecurityContainer>
+
+</com.android.keyguard.KeyguardHostView>
+
diff --git a/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml b/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml
deleted file mode 100644
index 41b0be9..0000000
--- a/packages/Keyguard/res/layout/keyguard_multi_user_avatar.xml
+++ /dev/null
@@ -1,45 +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.
-*/
--->
-
-<!-- This is a view that shows general status information in Keyguard. -->
-<com.android.keyguard.KeyguardMultiUserAvatar
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/keyguard_avatar_size"
-    android:layout_height="@dimen/keyguard_avatar_size"
-    android:background="#00000000"
-    android:gravity="center_horizontal">
-    <ImageView
-        android:id="@+id/keyguard_user_avatar"
-        android:scaleType="center"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"/>
-    <TextView
-       android:id="@+id/keyguard_user_name"
-       android:layout_width="match_parent"
-       android:layout_height="wrap_content"
-       android:layout_gravity="bottom"
-       android:gravity="center"
-       android:textSize="@dimen/keyguard_avatar_name_size"
-       android:textColor="#ffffff"
-       android:singleLine="true"
-       android:ellipsize="end"
-       android:paddingLeft="2dp"
-       android:paddingRight="2dp" />
-</com.android.keyguard.KeyguardMultiUserAvatar>
diff --git a/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml b/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
deleted file mode 100644
index 83036ab..0000000
--- a/packages/Keyguard/res/layout/keyguard_multi_user_selector.xml
+++ /dev/null
@@ -1,39 +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.
-*/
--->
-<com.android.keyguard.KeyguardMultiUserSelectorView
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    androidprv:layout_childType="userSwitcher"
-    android:id="@+id/keyguard_user_selector"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="bottom"
-    android:contentDescription="@string/keyguard_accessibility_user_selector"
-    android:visibility="gone">
-
-    <com.android.keyguard.KeyguardLinearLayout
-        android:id="@+id/keyguard_users_grid"
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_marginBottom="@dimen/keyguard_muliuser_selector_margin"
-        android:layout_height="@dimen/keyguard_avatar_size"
-        android:layout_gravity="center|bottom" />
-
-</com.android.keyguard.KeyguardMultiUserSelectorView>
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index b1b2631..7dcaf6d 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -41,7 +41,6 @@
 
     <!-- Password entry field -->
       <FrameLayout
-         android:id="@+id/keyguard_bouncer_frame"
          android:layout_height="wrap_content"
          android:layout_width="280dp"
          android:layout_gravity="center_horizontal"
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index 1fb0420..61480650 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -41,6 +41,7 @@
         android:clipToPadding="false">
 
         <LinearLayout
+            android:id="@+id/container"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:orientation="vertical"
@@ -53,18 +54,10 @@
                 android:layout_height="wrap_content"
                />
 
-          <FrameLayout
-             android:id="@+id/keyguard_bouncer_frame"
-             android:layout_width="match_parent"
-             android:layout_height="0dp"
-             android:layout_weight="1"
-             android:clipChildren="false"
-             android:clipToPadding="false"
-             >
             <com.android.internal.widget.LockPatternView
                 android:id="@+id/lockPatternView"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
+                android:layout_height="0dp"
                 android:layout_weight="1"
                 android:layout_marginEnd="8dip"
                 android:layout_marginBottom="4dip"
@@ -74,7 +67,7 @@
                 android:contentDescription="@string/keyguard_accessibility_pattern_area"
                 android:clipChildren="false"
                 android:clipToPadding="false" />
-          </FrameLayout>
+
           <include layout="@layout/keyguard_eca"
               android:id="@+id/keyguard_selector_fade_container"
               android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout/keyguard_pin_view.xml b/packages/Keyguard/res/layout/keyguard_pin_view.xml
index 2e7464b..d3fb982 100644
--- a/packages/Keyguard/res/layout/keyguard_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pin_view.xml
@@ -33,7 +33,7 @@
              android:layout_height="wrap_content"
             />
     <LinearLayout
-            android:id="@+id/keyguard_bouncer_frame"
+            android:id="@+id/container"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:orientation="vertical"
diff --git a/packages/Keyguard/res/layout/keyguard_presentation.xml b/packages/Keyguard/res/layout/keyguard_presentation.xml
index ab676aa..920498f 100644
--- a/packages/Keyguard/res/layout/keyguard_presentation.xml
+++ b/packages/Keyguard/res/layout/keyguard_presentation.xml
@@ -29,8 +29,7 @@
         android:id="@+id/clock"
         android:orientation="vertical"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:contentDescription="@string/keyguard_accessibility_status">
+        android:layout_height="wrap_content">
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/packages/Keyguard/res/layout/keyguard_selector_view.xml b/packages/Keyguard/res/layout/keyguard_selector_view.xml
deleted file mode 100644
index 5330363..0000000
--- a/packages/Keyguard/res/layout/keyguard_selector_view.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the selector widget that allows the user to select an action. -->
-<com.android.keyguard.KeyguardSelectorView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_selector_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    androidprv:layout_maxWidth="420dp"
-    androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="vertical"
-    android:contentDescription="@string/keyguard_accessibility_slide_unlock">
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:gravity="center">
-
-        <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-        <View
-            android:id="@+id/keyguard_selector_view_frame"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginLeft="16dp"
-            android:layout_marginRight="16dp"/>
-
-        <include layout="@layout/keyguard_glow_pad_container" />
-
-        <include layout="@layout/keyguard_eca"
-            android:id="@+id/keyguard_selector_fade_container"
-            android:layout_width="match_parent"
-            android:layout_height="48dp"
-            android:layout_gravity="bottom|center_horizontal" />
-    </FrameLayout>
-
-</com.android.keyguard.KeyguardSelectorView>
-
diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
index 929fa09..b0a93e6 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
@@ -39,7 +39,6 @@
              android:layout_height="wrap_content"
             />
     <LinearLayout
-            android:id="@+id/keyguard_bouncer_frame"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:orientation="vertical"
diff --git a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
index 0cf802d..cf41bd3 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
@@ -40,7 +40,6 @@
              android:layout_height="wrap_content"
             />
     <LinearLayout
-            android:id="@+id/keyguard_bouncer_frame"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:orientation="vertical"
diff --git a/packages/Keyguard/res/layout/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout/keyguard_simple_host_view.xml
deleted file mode 100644
index 63e55d5..0000000
--- a/packages/Keyguard/res/layout/keyguard_simple_host_view.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?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.
-*/
--->
-
-<!-- This is the host view that generally contains two sub views: the widget view
-    and the security view. -->
-<com.android.keyguard.KeyguardSimpleHostView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_host_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
-                                                  from this view when bouncer is shown -->
-
-    <com.android.keyguard.KeyguardSecurityContainer
-        android:id="@+id/keyguard_security_container"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        androidprv:layout_maxHeight="@dimen/keyguard_security_max_height"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:padding="0dp"
-        android:layout_gravity="center">
-        <com.android.keyguard.KeyguardSecurityViewFlipper
-            android:id="@+id/view_flipper"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:paddingTop="@dimen/keyguard_security_view_margin"
-            android:gravity="center">
-        </com.android.keyguard.KeyguardSecurityViewFlipper>
-    </com.android.keyguard.KeyguardSecurityContainer>
-
-</com.android.keyguard.KeyguardSimpleHostView>
-
diff --git a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml b/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
deleted file mode 100644
index da82e40..0000000
--- a/packages/Keyguard/res/layout/keyguard_transport_control_view.xml
+++ /dev/null
@@ -1,151 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is a view to control music playback in keyguard. -->
-<com.android.keyguard.KeyguardTransportControlView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center_horizontal"
-    android:id="@+id/keyguard_transport_control">
-
-    <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:gravity="center">
-        <ImageView
-            android:id="@+id/badge"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:scaleType="fitCenter" />
-        <FrameLayout
-            android:id="@+id/info_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-            <LinearLayout
-                android:id="@+id/metadata_container"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center">
-                <TextView
-                    android:id="@+id/title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="16dip"
-                    android:layout_marginEnd="16dip"
-                    android:gravity="center_horizontal"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:fontFamily="sans-serif-light" />
-                <TextView
-                    android:id="@+id/artist_album"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="16dip"
-                    android:layout_marginEnd="16dip"
-                    android:gravity="center_horizontal"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary" />
-            </LinearLayout>
-            <RelativeLayout
-                android:id="@+id/transient_seek"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:visibility="invisible">
-                <SeekBar
-                    android:id="@+id/transient_seek_bar"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    style="@style/Widget.TransportControl.SeekBar" />
-                <TextView
-                    android:id="@+id/transient_seek_time_elapsed"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentStart="true"
-                    android:layout_below="@id/transient_seek_bar"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textSize="12dp" />
-                <TextView
-                    android:id="@+id/transient_seek_time_remaining"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentEnd="true"
-                    android:layout_below="@id/transient_seek_bar"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textSize="12dp" />
-            </RelativeLayout>
-        </FrameLayout>
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="4dp"
-            android:orientation="horizontal">
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageButton
-                    android:id="@+id/btn_prev"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:src="@drawable/ic_media_previous"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:minWidth="48dp"
-                    android:minHeight="48dp"
-                    android:contentDescription="@string/keyguard_accessibility_transport_prev_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageButton
-                    android:id="@+id/btn_play"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:src="@drawable/ic_media_play"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:minWidth="48dp"
-                    android:minHeight="48dp"
-                    android:contentDescription="@string/keyguard_accessibility_transport_play_description"/>
-            </FrameLayout>
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="1">
-                <ImageButton
-                    android:id="@+id/btn_next"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:src="@drawable/ic_media_next"
-                    android:background="?android:attr/selectableItemBackground"
-                    android:minWidth="48dp"
-                    android:minHeight="48dp"
-                    android:contentDescription="@string/keyguard_accessibility_transport_next_description"/>
-            </FrameLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-</com.android.keyguard.KeyguardTransportControlView>
diff --git a/packages/Keyguard/res/layout/keyguard_widget_remove_drop_target.xml b/packages/Keyguard/res/layout/keyguard_widget_remove_drop_target.xml
deleted file mode 100644
index 58b5b27..0000000
--- a/packages/Keyguard/res/layout/keyguard_widget_remove_drop_target.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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.
-*/
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:gravity="center"
-    android:padding="30dp"
-    android:paddingLeft="60dp"
-    android:paddingRight="60dp"
-    android:drawableLeft="@drawable/kg_widget_delete_drop_target"
-    android:drawablePadding="4dp"
-    android:text="@string/kg_reordering_delete_drop_target_text"
-    android:textColor="#FFF"
-    android:textSize="12dp"
-    android:shadowColor="#000"
-    android:shadowDy="1.0"
-    android:shadowRadius="1.0"
-    android:visibility="gone" />
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index 4bfd98e..e4b543b 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Voer wagwoord in om te ontsluit"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Voer PIN in om te ontsluit"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Verkeerde PIN-kode."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Om te ontsluit, druk Kieslys dan 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimum gesigontsluit-pogings oorskry"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Gelaai"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Laai tans"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Koppel jou herlaaier."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart is gesluit."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart is PUK-geslote."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ontsluit tans SIM-kaart…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Legstuk %2$d van %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Voeg legstuk by."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leeg"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ontsluitruimte uitgevou."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ontsluitruimte ingevou."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-legstuk."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Gebruikerkieser"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media-kontroles"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Herordening van legstuk begin."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Herordening van legstuk beëindig."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Legstuk <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> uitgevee."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Vou ontsluitruimte uit."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Sleep-ontsluit."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Patroon ontsluit."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Gesigslot."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN ontsluit."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-area"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-PIN-area"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-PUK-area"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Vorigesnit-knoppie"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Volgendesnit-knoppie"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Laatwag-knoppie"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Speel-knoppie"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop-knoppie"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Laaik baie"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Laaik niks"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hart"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Ontsluit om voort te gaan"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Begin gekanselleer"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Laat los <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> om uit te vee."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> sal nie uitgevee word nie."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Volgende wekker gestel vir <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselleer"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Vee uit"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Klaar"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modus verander"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invoersleutel"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Ontsluit"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Klank aan"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Gly af vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Gly links vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Gly regs vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Het jy die patroon vergeet?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Verkeerde patroon"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Voer weer die korrekte PUK-kode in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodes stem nie ooreen nie"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Om te ontsluit, meld met jou Google-rekening aan."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikernaam (e-pos)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wagwoord"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Meld aan"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikernaam of wagwoord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Het jy jou gebruikernaam of wagwoord vergeet?\nBesoek "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontroleer tans rekening..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Verkeerde SIM PIN-kode, jy sal nou jou diensverskaffer moet kontak om jou toestel te ontsluit."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Verkeerde SIM PIN-kode, jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende poging voordat jy jou diensverskaffer sal moet kontak om jou toestel te ontsluit."</item>
-    <item quantity="other" msgid="2215723361575359486">"Verkeerde SIM PIN-kode, jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende pogings."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
+      <item quantity="one">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_0">%d</xliff:g> poging oor voordat jy jou diensverskaffer moet kontak om jou toestel te ontsluit.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM is onbruikbaar. Kontak jou diensverskaffer."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Verkeerde SIM PUK-kode, jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende poging voordat SIM permanent onbruikbaar word."</item>
-    <item quantity="other" msgid="5477305226026342036">"Verkeerde SIM PUK-kode, jy het <xliff:g id="NUMBER">%d</xliff:g> oorblywende pogings voordat SIM permanent onbruikbaar word."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Verkeerde SIM-PUK-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor voordat SIM permanent onbruikbaar word.</item>
+      <item quantity="one">Verkeerde SIM-PUK-kode. Jy het <xliff:g id="NUMBER_0">%d</xliff:g> poging oor voordat SIM permanent onbruikbaar word.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN-bewerking het misluk!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK-bewerking het misluk!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode is aanvaar!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Vorigesnit-knoppie"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Volgendesnit-knoppie"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Laatwag-knoppie"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Speel-knoppie"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop-knoppie"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen diens nie."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 714a3eb..c54656e 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
     <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_plugged_in" msgid="9087497435553252863">"ኃይል በመሙላት ላይ"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"የኃይል መሙያዎን ይሰኩ።"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ሲም ካርድ ተዘግቷል።"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ሲም ካርድ በፒዩኬ ተዘግቷል።"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ሲም ካርዱን በመክፈት ላይ…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s። ምግብር %2$d ከ%3$d።"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ንዑስ ፕሮግራም አክል"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ባዶ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"የመክፈቻ አካባቢ ተስፋፍቷል።"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"የመክፈቻ አካባቢ ተሰብስቧል።"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"የ<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ንዑስ ፕሮግራም።"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ተጠቃሚ መራጭ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ካሜራ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"የሚዲያ መቆጣጠሪያዎች"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"የንዑስ ፕሮግራም ዳግም መደርደር ተጀምሯል።"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"የንዑስ ፕሮግራም ዳግም መደርደር አብቅቷል።"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ንዑስ ፕሮግራም <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ተሰርዟል።"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"የመክፈቻ አካባቢውን አስፋፋ።"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"በማንሸራተት ክፈት።"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"በስርዓተ-ጥለት መክፈት።"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"በፊት መክፈት።"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"በፒን መክፈት።"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"የፒን አካባቢ"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"የሲም ፒን አካባቢ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"የሲም PUK አካባቢ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"የቀዳሚ ትራክ አዝራር"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"የቀጣይ ትራክ አዝራር"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ለአፍታ አቁም አዝራር"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"የአጫውት አዝራር"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"አቁም አዝራር"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"አሪፍ"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ደባሪ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"ልብ"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ለመቀጠል ይክፈቱ"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ማስጀመር ተሰርዟል"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ለመሰረዝ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ን ጣል ያድርጉ።"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> አይሰርዝም።"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"ቀጣዩ ማንቂያ ለ<xliff:g id="ALARM">%1$s</xliff:g> ተዘጋጅቷል"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ቀይር"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"አስገባ"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ክፈት"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ካሜራ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ፀጥታ"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ድምፅ አብራ"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ታች አንሸራትት።"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ግራ አንሸራትት።"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ቀኝ አንሸራትት።"</string>
-    <string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"የአደጋ ጊዜ ጥሪ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ስርዓተ ጥለቱን እርሳ"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"የተሳሳተ ስርዓተ ጥለት"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"ለመክፈት በGoogle መለያዎ ይግቡ።"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"የተጠቃሚ ስም (ኢሜይል)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"የይለፍ ቃል"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ግባ"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ልክ ያልሆነ የተጠቃሚ ስም ወይም የይለፍ ቃል።"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"የተጠቃሚ ስምዎን ወይም የይለፍ ቃልዎን ረሱት?\n"<b>"google.com/accounts/recovery"</b>"ይጎብኙ።"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"መለያውን በማረጋገጥ ላይ…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።\n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"የመክፈቻ ስርዓተ ጥለትዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። \n\n ከ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊ ቱኮዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"አስወግድ"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ልክ ያልሆነ የሲም ኮድ። አሁን መሳሪያዎን ለማስከፈት ድምጸ ተያያዥ ሞደምዎን ማግኘት አለብዎ።"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ልክ ያልሆነ የሲም ፒን ኮድ፣ መሳሪያዎን ለማስከፈት ድምጸ ተያያዥ ሞደምዎን ማግኘት ግዴታዎ ሊሆን <xliff:g id="NUMBER">%d</xliff:g> ሙከራ ይቀርዎታል።"</item>
-    <item quantity="other" msgid="2215723361575359486">"ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER">%d</xliff:g> ሙከራዎች ይቀሩዎታል።"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀርዎታል።</item>
+      <item quantity="other">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀርዎታል።</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"ሲሙ ጥቅም ላይ መዋል እይችልም። የእርስዎን ድምጸ ተያያዥ ሞደም ያግኙ።"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ልክ ያልሆነ የሲም PUK ኮድ፣ ሲም ካርድዎ በቋሚነት ጥቅም ላይ መዋል የማይችል ሊሆን <xliff:g id="NUMBER">%d</xliff:g> ሙከራ ይቀርዎታል።"</item>
-    <item quantity="other" msgid="5477305226026342036">"ልክ ያልሆነ የሲም PUK ኮድ፣ ሲም ካርድዎ በቋሚነት ጥቅም ላይ መዋል የማይችል ሊሆን <xliff:g id="NUMBER">%d</xliff:g> ሙከራዎች ይቀሩዎታል።"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">ልክ ያልሆነ የሲም PUK ኮድ፣ ሲም ካርድዎ በቋሚነት ጥቅም ላይ መዋል የማይችል ሊሆን <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀሩዎታል።</item>
+      <item quantity="other">ልክ ያልሆነ የሲም PUK ኮድ፣ ሲም ካርድዎ በቋሚነት ጥቅም ላይ መዋል የማይችል ሊሆን <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀሩዎታል።</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"የሲም ፒን ክወና አልተሳካም!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"የሲም PUK ክወና አልተሳካም!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ኮዱ ተቀባይነት አግኝቷል!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"የቀዳሚ ትራክ አዝራር"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"የቀጣይ ትራክ አዝራር"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ለአፍታ አቁም አዝራር"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"የአጫውት አዝራር"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"አቁም አዝራር"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index 5a8d2bd..153f08e 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -29,37 +29,21 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"اكتب كلمة المرور لإلغاء التأمين"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"‏اكتب رمز PIN لإلغاء التأمين"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"‏رمز PIN غير صحيح."</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_plugged_in" msgid="9087497435553252863">"جارٍ الشحن"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"توصيل جهاز الشحن."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"اضغط على \"القائمة\" لإلغاء القفل."</string>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"الشبكة مؤمّنة"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"‏ليست هناك بطاقة SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"‏ليست هناك بطاقة SIM في الجهاز اللوحي."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"‏ليست هناك بطاقة SIM في الهاتف."</string>
-    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"‏أدخل بطاقة SIM."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"‏بطاقة SIM مفقودة أو غير قابلة للقراءة. أدخل بطاقة SIM."</string>
-    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"‏بطاقة SIM غير قابلة للاستخدام."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"‏تم تعطيل بطاقة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على بطاقة SIM أخرى."</string>
-    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"‏بطاقة SIM مؤمّنة."</string>
-    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"‏بطاقة SIM مؤمّنة بكود PUK."</string>
-    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"‏جارٍ إلغاء تأمين بطاقة SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"‏%1$s. الأداة %2$d من %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"إضافة أداة."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"فارغة"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"تم توسيع منطقة إلغاء القفل."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"تم تصغير منطقة إلغاء القفل."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"محدد المستخدم"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"الكاميرا"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"أدوات التحكم في الوسائط"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"بدأت إعادة ترتيب الأدوات."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"انتهت إعادة ترتيب الأدوات."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"تم حذف أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"توسيع منطقة إلغاء القفل."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"إلغاء القفل باستخدام التمرير."</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"‏ليست هناك شريحة SIM"</string>
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"‏ليست هناك شريحة SIM في الجهاز اللوحي."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"‏ليست هناك شريحة SIM في الهاتف."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"‏أدخل شريحة SIM."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"‏شريحة SIM مفقودة أو غير قابلة للقراءة. أدخل شريحة SIM."</string>
+    <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"‏شريحة SIM غير قابلة للاستخدام."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"‏تم تعطيل شريحة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على شريحة SIM أخرى."</string>
+    <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"‏شريحة SIM مؤمّنة."</string>
+    <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"‏شريحة SIM مؤمّنة بكود PUK."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"‏جارٍ إلغاء تأمين شريحة SIM…"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"إلغاء القفل باستخدام النقش."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"تأمين الجهاز بالوجه."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"‏إلغاء القفل باستخدام رمز PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"منطقة رقم التعريف الشخصي"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"‏منطقة رقم التعريف الشخصي لبطاقة SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"‏منطقة PUK لبطاقة SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"زر المقطع الصوتي السابق"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"زر المقطع الصوتي التالي"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"زر الإيقاف المؤقت"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"زر التشغيل"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"زر الإيقاف"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"رائعة"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"معارضة"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"قلب"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"إلغاء القفل للمتابعة"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"تم إلغاء التشغيل"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"أسقط <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> للحذف."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"لن يتم حذف <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"تم ضبط التنبيه التالي على <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ب ت ث"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"إلغاء"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"تم"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغيير الوضع"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"العالي"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"إلغاء تأمين"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"الكاميرا"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"صامت"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"تشغيل الصوت"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"تمرير لأسفل لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"تمرير لليسار لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"تمرير لليمين لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"الاتصال بالطوارئ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"نسيت النقش"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"نقش خاطئ"</string>
@@ -113,23 +67,16 @@
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"‏إدخال رقم التعريف الشخصي لبطاقة SIM التابعة للمشغل \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"‏أدخل رمز PIN"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"أدخل كلمة المرور"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"‏بطاقة SIM معطلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوال للاطلاع على التفاصيل."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"‏شريحة SIM معطلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوال للاطلاع على التفاصيل."</string>
     <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"‏SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" معطلة الآن. أدخل رمز PUK للمتابعة. واتصل بمشغل شبكة الجوال لمعرفة التفاصيل."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"‏إدخال رمز رمز PIN المراد"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"‏تأكيد رمز رمز PIN المراد"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"‏جارٍ إلغاء تأمين شريحة SIM…"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"‏اكتب رمز PIN المكون من 4 إلى 8 أرقام."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"‏يجب أن يتضمن رمز PUK‏ 8 أرقام أو أكثر."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل بطاقة SIM نهائيًا."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل شريحة SIM نهائيًا."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏لا يتطابق رمزا رمز PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"‏لإلغاء التأمين، سجّل الدخول بحسابك في Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"اسم المستخدم (البريد إلكتروني)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"كلمة المرور"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"تسجيل الدخول"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"اسم مستخدم غير صحيح أو كلمة مرور غير صالحة."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"‏هل نسيت اسم المستخدم أو كلمة المرور؟\nانتقل إلى "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"جارٍ فحص الحساب…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"‏لقد كتبت رمز PIN بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
@@ -147,24 +94,27 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بياناته."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"إزالة"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"‏رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"‏رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويتبقى لديك محاولة واحدة (<xliff:g id="NUMBER">%d</xliff:g>) يتعين عليك بعدها الاتصال بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</item>
-    <item quantity="other" msgid="2215723361575359486">"‏رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، يتبقى لديك <xliff:g id="NUMBER">%d</xliff:g> من المحاولات."</item>
-  </plurals>
-    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"‏بطاقة SIM غير صالحة للاستخدام. يُرجى الاتصال بمشغّل شبكة الجوّال."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"‏رمز PUK لبطاقة SIM غير صالح، ويتبقى لديك محاولة واحدة (<xliff:g id="NUMBER">%d</xliff:g>)، تصبح بعدها بطاقة SIM غير صالحة للاستخدام بشكل دائم."</item>
-    <item quantity="other" msgid="5477305226026342036">"‏رمز PUK لبطاقة SIM غير صالح، ويتبقى لديك <xliff:g id="NUMBER">%d</xliff:g> من المحاولات، تصبح بعدها بطاقة SIM غير صالحة للاستخدام بشكل دائم."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="zero">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
+      <item quantity="two">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ويتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
+      <item quantity="few">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات.</item>
+      <item quantity="many">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة.</item>
+      <item quantity="other">‏رمز رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات.</item>
+      <item quantity="one">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ويتبقى لديك محاولة واحدة (<xliff:g id="NUMBER_0">%d</xliff:g>) يتعين عليك بعدها الاتصال بمشغّل شبكة الجوّال لإلغاء قفل الجهاز.</item>
+    </plurals>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"‏شريحة SIM غير صالحة للاستخدام. يُرجى الاتصال بمشغّل شبكة الجوّال."</string>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="zero">‏رمز PUK لشريحة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="two">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك محاولتان (<xliff:g id="NUMBER_1">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="few">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولات تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="many">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> محاولة تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="other">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+      <item quantity="one">‏رمز PUK لشريحة SIM غير صحيح، ويتبقى لديك محاولة واحدة (<xliff:g id="NUMBER_0">%d</xliff:g>) تصبح بعدها شريحة SIM غير صالحة للاستخدام بشكل دائم.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"‏أخفقت عملية \"رقم التعريف الشخصي\" لبطاقة SIM!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏أخفقت عملية PUK لبطاقة SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"تم قبول الرمز!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"زر المقطع الصوتي السابق"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"زر المقطع الصوتي التالي"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"زر الإيقاف المؤقت"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"زر التشغيل"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"زر الإيقاف"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index bdfbdff..5dcb82c 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Въведете парола, за да отключите"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Въведете ПИН, за да отключите"</string>
     <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_plugged_in" msgid="9087497435553252863">"Зарежда се"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Свържете зарядното си устройство."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM картата е заключена."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картата е заключена с PUK код."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картата се отключва…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Приспособление %2$d от %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Добавяне на приспособление."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Празно"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Областта за отключване е разгъната."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Областта за отключване е свита."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Приспособление за <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Инструмент за избор на потребители"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроли за мултимедията"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Пренареждането на приспособленията започна."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Пренареждането на приспособленията завърши."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Приспособлението за <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> е изтрито."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Разгъване на областта за отключване."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Отключване с плъзгане."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Отключване с фигура."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Отключване с лице."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Отключване с ПИН код."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Област за ПИН кода"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Област за ПИН кода на SIM картата"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Област за PUK кода на SIM картата"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Бутон за предишния запис"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Бутон за следващия запис"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Бутон за пауза"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Бутон за пускане"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Бутон за спиране"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Харесва ми"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Не ми харесва"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Сърце"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Отключете, за да продължите"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Стартирането е анулирано"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Пуснете <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>, за да изтриете."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> няма да се изтрие."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Следващият будилник е зададен за <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отказ"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Изтриване"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Промяна на режима"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Отключване"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Тих режим"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Включване на звука"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Плъзнете надолу за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Плъзнете наляво за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Плъзнете надясно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Спешно обаждане"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забравена фигура"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Грешна фигура"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"За да отключите, влезте с профила си в Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Потребителско име (имейл)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Парола"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?\nПосетете "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Профилът се проверява…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Премахване"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Неправилен ПИН код за SIM картата – остава ви <xliff:g id="NUMBER">%d</xliff:g> опит, преди да трябва да се свържете с оператора си, за да отключите устройството."</item>
-    <item quantity="other" msgid="2215723361575359486">"Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER">%d</xliff:g> опита."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
+      <item quantity="one">Неправилен ПИН код за SIM картата – остава ви <xliff:g id="NUMBER_0">%d</xliff:g> опит, преди да трябва да се свържете с оператора си, за да отключите устройството.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM картата е неизползваема. Свържете се с оператора си."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Неправилен PUK код за SIM картата – остава ви <xliff:g id="NUMBER">%d</xliff:g> опит, преди SIM картата да стане неизползваема завинаги."</item>
-    <item quantity="other" msgid="5477305226026342036">"Неправилен PUK код за SIM картата – остават ви <xliff:g id="NUMBER">%d</xliff:g> опита, преди SIM картата да стане неизползваема завинаги."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Неправилен PUK код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита, преди тя да стане неизползваема завинаги.</item>
+      <item quantity="one">Неправилен PUK код за SIM картата – остава ви <xliff:g id="NUMBER_0">%d</xliff:g> опит, преди тя да стане неизползваема завинаги.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Операцията с ПИН кода за SIM картата не бе успешна!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Операцията с PUK кода за SIM картата не бе успешна!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодът е приет!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Бутон за предишния запис"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Бутон за следващия запис"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Бутон за пауза"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Бутон за пускане"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Бутон за спиране"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 77acaf80..2b13a07 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"আনলক করতে পাসওয়ার্ড লিখুন"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"আনলক করতে PIN লিখুন"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ভুল PIN কোড৷"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"আনলক করতে, মেনু টিপুন তারপর ০ টিপুন৷"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"মুখের সাহায্যে আনলক করার প্রচেষ্টা যতবার করা যায় তার সীমা পেরিয়ে গেছে"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"চার্জ হয়েছে"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"চার্জ হচ্ছে"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"আপনার চার্জার সংযুক্ত করুন৷"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"সিম কার্ড লক করা আছে৷"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"সিম কার্ডটি PUK কোড দিয়ে লক করা আছে৷"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"সিম কার্ড আনলক করা হচ্ছে…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s৷ %3$d এর %2$d উইজেট৷"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"উইজেট যোগ করুন"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"খালি"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"আনলক করার এলাকা প্রসারিত হয়েছে৷"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"আনলক করার এলাকা সঙ্কুচিত হয়েছে৷"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> উইজেট৷"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ব্যবহারকারী নির্বাচক"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ক্যামেরা"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"মিডিয়া নিয়ন্ত্রণগুলি"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"উইজেট রেকর্ড করা শুরু হয়েছে৷"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"উইজেট রেকর্ড করা শেষ হয়েছে৷"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> উইজেট মুছে ফেলা হয়েছে৷"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"আনলক এলাকা প্রসারিত করুন৷"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"স্লাইড দিয়ে আনলক৷"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"প্যাটার্ন দিয়ে আনলক৷"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"মুখের সাহায্যে আনলক করুন৷"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"পিন দিয়ে আনলক৷"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN অঞ্চল"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN অঞ্চল"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK অঞ্চল"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"পূর্ববর্তী ট্র্যাকে যাওয়ার বোতাম"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"পরবর্তী ট্র্যাকে যাওয়ার বোতাম"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"বিরাম বোতাম"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"প্লে বোতাম"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"বন্ধ করার বোতাম"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"অঙ্গুষ্ঠ উপরের দিকে করে"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"অঙ্গুষ্ঠ নীচের দিকে করে"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"হৃদয়"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"চালিয়ে যেতে আনলক করুন"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"লঞ্চ করা বাতিল করা হয়েছে"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"মুছে ফেলতে <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ছাড়ুন৷"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> মুছে ফেলা যাবে না৷"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> এ পরবর্তী অ্যালার্ম সেট করা হয়েছে"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?১২৩"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"বাতিল করুন"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মুছুন"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"সম্পন্ন"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"মোড পরিবর্তন করুন"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"আনলক করুন"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ক্যামেরা"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"নীরব"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"শব্দ চালু"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য নীচের দিকে স্লাইড করুন৷"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য বাম দিকে স্লাইড করুন৷"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> এর জন্য ডান দিকে স্লাইড করুন৷"</string>
-    <string name="user_switched" msgid="3768006783166984410">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"জরুরি কল"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"প্যাটার্ন ভুলে গেছেন"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"ভুল প্যাটার্ন"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"সঠিক PUK কোড পুনরায় লিখুন৷ বার বার প্রচেষ্টা করা হলে তা স্থায়ীভাবে সিমটিকে অক্ষম করে দেবে৷"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN কোডগুলি মিলছে না"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"বিভিন্ন প্যাটার্নের সাহায্যে খুব বেশি বার প্রচেষ্টা করা হয়ে গেছে"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"আনলক করতে আপনার Google অ্যাকাউন্টের মাধ্যমে সাইন ইন করুন৷"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ব্যবহারকারী নাম (ইমেল)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"পাসওয়ার্ড"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"সাইন ইন করুন"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"অবৈধ ব্যবহারকারী নাম অথবা পাসওয়ার্ড৷"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"আপনার ব্যবহারকারী নাম অথবা পাসওয়ার্ড ভুলে গেছেন?\n"<b>"google.com/accounts/recovery"</b>" এ যান৷"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"অ্যাকাউন্ট পরীক্ষা করা হচ্ছে..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপনি আপনার PIN টাইপ করতে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"আপনি আপনার পাসওয়ার্ড টাইপ করতে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ফোনটি আনলক করার চেষ্টা করেছেন৷ কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ট্যাবলেট আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"সরান"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ভুল সিম PIN কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ভুল সিম PIN কোড, আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে, তার পরে আপনার ডিভাইসটি আনলক করতে আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</item>
-    <item quantity="other" msgid="2215723361575359486">"ভুল সিম PIN কোড, আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">ভুল SIM PIN কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+      <item quantity="other">ভুল SIM PIN কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIMটি ব্যবহারের অযোগ্য৷ আপনার ক্যারিয়ারের সাথে যোগাযোগ করুন৷"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷"</item>
-    <item quantity="other" msgid="5477305226026342036">"ভুল সিম PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার সিম স্থায়ীভাবে অব্যবহারযোগ্য হবে৷"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+      <item quantity="other">ভুল SIM PUK কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে এটির পরেই আপনার SIM স্থায়ীভাবে অব্যবহারযোগ্য হবে৷</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"সিম PIN ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"সিম PUK ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"কোড স্বীকৃত হয়েছে!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"পূর্ববর্তী ট্র্যাকে যাওয়ার বোতাম"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"পরবর্তী ট্র্যাকে যাওয়ার বোতাম"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"বিরাম বোতাম"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"প্লে বোতাম"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"বন্ধ করার বোতাম"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"কোনো পরিষেবা নেই৷"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index ac745f1..e675c7a 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introdueix la contrasenya per desbloquejar"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introdueix la contrasenya per desbloquejar"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codi PIN incorrecte."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Per desbloquejar-lo, premeu Menú i després 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S\'ha superat el nombre màxim d\'intents de desbloqueig facial"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Carregada"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Carregant"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Connecta el carregador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La targeta SIM està bloquejada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La targeta SIM està bloquejada pel PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"S\'està desbloquejant la targeta SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Afegeix un widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Buit"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"S\'ha ampliat l\'àrea de desbloqueig."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"L\'àrea de desbloqueig està replegada."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector d\'usuaris"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Càmera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controls multimèdia"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"S\'ha iniciat la reorganització del widget."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ha finalitzat la reorganització del widget."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"S\'ha suprimit el widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Desplega l\'àrea de desbloqueig."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueig lliscant el dit"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueig mitjançant patró"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueig facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueig mitjançant PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Zona del PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zona del PIN de la SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zona del PUK de la SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botó de pista anterior"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botó de pista següent"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botó de pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botó de reproducció"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botó de parada"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"M\'agrada"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"No m\'agrada"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Cor"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloqueja per continuar"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"S\'ha cancel·lat l\'inici"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Deixa anar <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> per suprimir-lo."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"No se suprimirà <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"S\'ha definit la pròxima alarma per a les: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel·la"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Suprimeix"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fet"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Canvi de mode"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retorn"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloqueja"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Càmera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silenci"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Activa el so"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Fes lliscar el dit cap avall per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Fes lliscar el dit cap a l\'esquerra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Fes lliscar el dit cap a la dreta per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Trucada d\'emergència"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patró oblidat"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patró incorrecte"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Per desbloquejar el telèfon, inicia la sessió amb el compte de Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'usuari (correu electrònic)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contrasenya"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inicia la sessió"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'usuari o contrasenya no vàlids."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Has oblidat el teu nom d\'usuari o la contrasenya?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"S\'està comprovant el compte…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El codi PIN de la SIM no és correcte. Has de contactar amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"El codi PIN de la SIM no és correcte. Et queda <xliff:g id="NUMBER">%d</xliff:g> intent; si no l\'encertes, contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</item>
-    <item quantity="other" msgid="2215723361575359486">"El codi PIN de la SIM no és correcte. Et queden <xliff:g id="NUMBER">%d</xliff:g> intents."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">El codi PIN de la SIM no és correcte. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item>
+      <item quantity="one">El codi PIN de la SIM no és correcte. Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La SIM no es pot utilitzar. Contacta amb l\'operador de telefonia mòbil."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"El codi PUK de la SIM no és correcte. Et queda <xliff:g id="NUMBER">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir."</item>
-    <item quantity="other" msgid="5477305226026342036">"El codi PUK de la SIM no és correcte. Et queden <xliff:g id="NUMBER">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">El codi PUK de la SIM no és correcte. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir.</item>
+      <item quantity="one">El codi PUK de la SIM no és correcte. Et queda <xliff:g id="NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Hi ha hagut un problema en l\'operació del PIN de la SIM."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Hi ha hagut un problema en l\'operació del PUK de la SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"S\'ha acceptat el codi."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botó de pista anterior"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botó de pista següent"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botó de pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botó de reproducció"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botó de parada"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sense servei."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 141fe41..e1fa6f9 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Zadejte heslo pro odemknutí"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Zadejte kód PIN pro odemknutí"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávný kód PIN."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Překročili jste maximální povolený počet pokusů o odemknutí obličejem."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Nabito"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nabíjení"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Připojte dobíjecí zařízení."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM karta je zablokována."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM karta je zablokována pomocí kódu PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odblokování SIM karty…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d z %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Přidat widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prázdné"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblast odemknutí byla rozšířena."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblast odemknutí byla sbalena."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výběr uživatele"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparát"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládání médií"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Přeuspořádání widgetů bylo zahájeno."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Přeuspořádání widgetů bylo dokončeno."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> byl smazán."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozšířit oblast odemknutí"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odemknutí přejetím prstem."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odemknutí gestem."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odemknutí obličejem."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odemknutí kódem PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Oblast kódu PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Oblast kódu PIN SIM karty"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Oblast kódu PUK SIM karty"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačítko Předchozí stopa"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačítko Další stopa"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačítko Pozastavit"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tlačítko Přehrát"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tlačítko Zastavit"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Líbí se mi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nelíbí se mi"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Srdíčko"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Pokračujte odemknutím"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Spuštění zrušeno"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Uvolněním dotyku widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vymažete."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> nebude vymazán."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Další budík je nastaven na <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušit"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Smazat"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Hotovo"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Změna režimu"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Odemknout"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Zapnout zvuk"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Přejeďte prstem dolů: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Přejeďte prstem doleva: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Přejeďte prstem doprava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tísňové volání"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zapomenuté gesto"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávné gesto"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uživatelské jméno (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Přihlásit se"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné uživatelské jméno nebo heslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?\nPřejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontrola účtu…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Zadali jste nesprávný kód PIN SIM karty. Nyní musíte za účelem odemknutí zařízení kontaktovat svého operátora."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER">%d</xliff:g> pokus, poté budete muset o odemknutí zařízení požádat svého operátora."</item>
-    <item quantity="other" msgid="2215723361575359486">"Zadali jste nesprávný kód PIN SIM karty. Počet zbývajících pokusů: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="few">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
+      <item quantity="many">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusu.</item>
+      <item quantity="other">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusů.</item>
+      <item quantity="one">Zadali jste nesprávný PIN SIM karty. Zbývá <xliff:g id="NUMBER_0">%d</xliff:g> pokus, poté bude muset zařízení odemknout operátor.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM kartu nelze použít. Kontaktujte operátora."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Nesprávný kód PUK SIM karty. Máte ještě <xliff:g id="NUMBER">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována."</item>
-    <item quantity="other" msgid="5477305226026342036">"Zadali jste nesprávný kód PUK SIM karty. Počet zbývajících pokusů, po kterých bude SIM karta natrvalo zablokována: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="few">Nesprávný kód PUK SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy, poté bude SIM karta natrvalo zablokována.</item>
+      <item quantity="many">Nesprávný kód PUK SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusu, poté bude SIM karta natrvalo zablokována.</item>
+      <item quantity="other">Nesprávný kód PUK SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusů, poté bude SIM karta natrvalo zablokována.</item>
+      <item quantity="one">Nesprávný kód PUK SIM karty. Máte ještě <xliff:g id="NUMBER_0">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operace pomocí kódu PIN SIM karty se nezdařila!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operace pomocí kódu PUK SIM karty se nezdařila!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód byl přijat."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tlačítko Předchozí stopa"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tlačítko Další stopa"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tlačítko Pozastavit"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tlačítko Přehrát"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tlačítko Zastavit"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žádný signál."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index 93b5756..77e8ce3 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Indtast adgangskoden for at låse op"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Indtast pinkode for at låse op"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Forkert pinkode."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Tryk på Menu og dernæst på 0 for at låse op."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Det maksimale antal forsøg på at bruge Ansigtslås er overskredet"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Opladet"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Oplader"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Tilslut din oplader."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet er låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kort er låst med PUK-koden."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kortet låses op…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d af %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tilføj widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oplåsningsområdet er udvidet."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oplåsningsområdet er skjult."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget til <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Brugervælger"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediekontrolelementer"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Omrokering af widgets er påbegyndt."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Omrokering af widgets er afsluttet."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgetten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> er slettet."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Udvid oplåsningsområdet."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lås op ved at stryge."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lås op med mønster."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Lås op med ansigt."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lås op med pinkode."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Område for pinkoden"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Område for pinkoden til simkortet"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Område for PUK-koden til simkortet"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knap til forrige nummer"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knap til næste nummer"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knap"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Afspil-knap"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop-knap"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Synes om"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Synes ikke om"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hjerte"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Lås op for at gå videre"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Starten blev annulleret"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Slip <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> for at slette."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> slettes ikke."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Næste alarm er indstillet til <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuller"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slet"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Udfør"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ændring af tilstand"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Angiv"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Lås op"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Lydløs"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Lyd slået til"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Glid ned for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Glid til venstre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Glid til højre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødopkald"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Glemt mønster"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Forkert mønster"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Lås op ved at logge ind med din Google-konto."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brugernavn (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Adgangskode"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log ind"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontoen kontrolleres…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Forkert pinkode til SIM-kort. Du skal nu kontakte dit mobilselskab for at låse din enhed op."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage, før du skal kontakte dit mobilselskab for at låse din enhed op."</item>
-    <item quantity="other" msgid="2215723361575359486">"Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
+      <item quantity="other">Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortet er ubrugeligt. Kontakt dit mobilselskab."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Forkert PUK-kode til SIM-kort. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt."</item>
-    <item quantity="other" msgid="5477305226026342036">"Forkert PUK-kode til SIM-kort. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøg tilbage, før dit SIM-kort bliver permanent ubrugeligt."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Forkert PUK-kode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt.</item>
+      <item quantity="other">Forkert PUK-kode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Pinkoden til SIM-kortet blev afvist."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden til SIM-kortet blev afvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden blev accepteret."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knap til forrige nummer"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knap til næste nummer"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause-knap"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Afspil-knap"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop-knap"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index f6545a1..e21961d 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Passwort zum Entsperren eingeben"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"PIN zum Entsperren eingeben"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Falscher PIN-Code"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Die maximal zulässige Anzahl an Face Unlock-Versuchen wurde überschritten."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Aufgeladen"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Wird aufgeladen"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Bitte Ladegerät anschließen"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-Karte ist gesperrt."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-Karte wird entsperrt…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d von %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget hinzufügen"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leer"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Entsperr-Bereich maximiert"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Entsperr-Bereich mminimiert"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Nutzerauswahl"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediensteuerelemente"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Neuordnung der Widgets gestartet"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Neuordnung der Widgets abgeschlossen"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> gelöscht"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Entsperr-Bereich maximieren"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Entsperrung mit Fingerbewegung"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Entsperrung mit Muster"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face Unlock"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Entsperrung mit PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-Bereich"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-PIN-Bereich"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-PUK-Bereich"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Schaltfläche für vorherigen Titel"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Schaltfläche für nächsten Titel"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Schaltfläche für Pause"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Schaltfläche für Wiedergabe"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Schaltfläche für Stopp"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Mag ich"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Mag ich nicht"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Herz"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Zum Fortfahren entsperren"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Start abgebrochen"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Legen Sie <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> zum Löschen ab."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> wird nicht gelöscht."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Nächster Wecker gestellt für <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Abbrechen"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fertig"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusänderung"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Eingabetaste"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Entsperren"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Lautlos"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ton ein"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach unten schieben"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach rechts schieben"</string>
-    <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Notruf"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Muster vergessen"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nutzername (E-Mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passwort"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Anmelden"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ungültiger Nutzername oder ungültiges Passwort"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto wird geprüft…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Falscher PIN-Code der SIM-Karte. Bitte wenden Sie sich an Ihren Mobilfunkanbieter, damit er Ihr Gerät entsperrt."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuch, bevor Sie das Gerät von Ihrem Mobilfunkanbieter entsperren lassen müssen."</item>
-    <item quantity="other" msgid="2215723361575359486">"Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuche."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
+      <item quantity="one">Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Sie das Gerät von Ihrem Mobilfunkanbieter entsperren lassen müssen.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Die SIM-Karte kann nicht verwendet werden. Bitte wenden Sie sich an Ihren Mobilfunkanbieter."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuch, bevor Ihre SIM-Karte endgültig gesperrt wird."</item>
-    <item quantity="other" msgid="5477305226026342036">"Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER">%d</xliff:g> Versuche, bevor Ihre SIM-Karte endgültig gesperrt wird."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor Ihre SIM-Karte endgültig gesperrt wird.</item>
+      <item quantity="one">Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Ihre SIM-Karte endgültig gesperrt wird.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Fehler beim Entsperren mit der PIN der SIM-Karte"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Fehler beim Entsperren mithilfe des PUK-Codes der SIM-Karte"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code akzeptiert"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Schaltfläche für vorherigen Titel"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Schaltfläche für nächsten Titel"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Schaltfläche für Pause"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Schaltfläche für Wiedergabe"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Schaltfläche für Stopp"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Kein Dienst"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 9dbe709..7084c84 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Πληκτρολογήστε τον κωδικό πρόσβασης για ξεκλείδωμα"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Πληκτρολογήστε τον αριθμό PIN για ξεκλείδωμα"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Εσφαλμένος κωδικός PIN."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Για ξεκλείδωμα, πατήστε το πλήκτρο Menu και, στη συνέχεια, το πλήκτρο 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Έγινε υπέρβαση του μέγιστου αριθμού προσπαθειών Face Unlock"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Φορτίστηκε"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Φόρτιση"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Συνδέστε τον φορτιστή."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Η κάρτα SIM είναι κλειδωμένη."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Η κάρτα SIM είναι κλειδωμένη με κωδικό PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ξεκλείδωμα κάρτας SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Γραφικό στοιχείο %2$d από %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Προσθήκη γραφικού στοιχείου"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Κενή"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ανάπτυξη της περιοχής ξεκλειδώματος."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Σύμπτυξη της περιοχής ξεκλειδώματος."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Γραφικό στοιχείο <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Επιλογέας χρήστη"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Φωτογραφική μηχανή"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Στοιχεία ελέγχου μέσων"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Έχει ξεκινήσει η αναδιάταξη των γραφικών στοιχείων."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Έχει ολοκληρωθεί η αναδιάταξη των γραφικών στοιχείων."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Το γραφικό στοιχείο <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> έχει διαγραφεί."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ανάπτυξη περιοχής ξεκλειδώματος."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ξεκλείδωμα ολίσθησης."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ξεκλείδωμα μοτίβου."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ξεκλείδωμα κωδικού ασφαλείας"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Περιοχή PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Περιοχή PIN SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Περιοχή PUK SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Κουμπί προηγούμενου κομματιού"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Κουμπί επόμενου κομματιού"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Κουμπί παύσης"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Κουμπί αναπαραγωγής"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Κουμπί διακοπής"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Επιδοκιμασία"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Αποδοκιμασία"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Καρδιά"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Ξεκλειδώστε για να συνεχίσετε"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Η εκκίνηση ακυρώθηκε"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Αποθέστε <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> για διαγραφή."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> δεν θα διαγραφεί."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Το επόμενο ξυπνητήρι ορίστηκε στις <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ΑΒΓ"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ακύρωση"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Διαγραφή"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Τέλος"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Αλλαγή τρόπου"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Ξεκλείδωμα"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Φωτογραφική μηχανή"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Αθόρυβο"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ενεργοποίηση ήχου"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Κύλιση προς τα κάτω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Κύλιση προς τα αριστερά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Κύλιση προς τα δεξιά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Κλήσεις επείγουσας ανάγκης"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ξεχάσατε το μοτίβο"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Εσφαλμένο μοτίβο"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Δεν υπάρχει αντιστοιχία των κωδικών PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Πάρα πολλές προσπάθειες μοτίβου"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Για ξεκλείδωμα, συνδεθείτε με τον λογαριασμό σας Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Όνομα χρήστη (διεύθυνση ηλεκτρονικού ταχυδρομείου)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Κωδικός πρόσβασης"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Σύνδεση"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;\nΕπισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Έλεγχος λογαριασμού…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Έχετε πληκτρολογήσει εσφαλμένα τον κωδικό σας PIN <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλετπα."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Κατάργηση"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Εσφαλμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</item>
-    <item quantity="other" msgid="2215723361575359486">"Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες. </item>
+      <item quantity="one">Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER_0">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί. Επικοινωνήστε με τον πάροχο κινητής τηλεφωνίας σας."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια προτού δεν είναι πλέον δυνατή η χρήση της κάρτας SIM."</item>
-    <item quantity="other" msgid="5477305226026342036">"Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες προτού δεν είναι πλέον δυνατή η χρήση της κάρτας SIM."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM.</item>
+      <item quantity="one">Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER_0">%d</xliff:g> προσπάθεια προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Αποτυχία λειτουργίας κωδικού PIN κάρτας SIM!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Αποτυχία λειτουργίας κωδικού PUK κάρτας SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Αποδεκτός κωδικός!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Κουμπί προηγούμενου κομματιού"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Κουμπί επόμενου κομματιού"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Κουμπί παύσης"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Κουμπί αναπαραγωγής"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Κουμπί διακοπής"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index 6ac27be..ee5da13 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Type password to unlock"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Type PIN to unlock"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charging"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM card is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM card is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Unlocking SIM card…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d of %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Add widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Empty"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Unlock area expanded."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Unlock area collapsed."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"User selector"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media controls"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget reordering started."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget reordering ended."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> deleted."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expand unlock area."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Slide unlock."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pattern unlock."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin unlock."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN area"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN area"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK area"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Previous track button"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Next track button"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause button"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Play button"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop button"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Thumbs up"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Thumbs down"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Heart"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Unlock to continue"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Launch cancelled"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Drop <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> to delete."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> will not be deleted."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Done"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Unlock"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sound on"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Slide down for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Slide right for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Incorrect SIM PIN code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before you must contact your carrier to unlock your device."</item>
-    <item quantity="other" msgid="2215723361575359486">"Incorrect SIM PIN code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM is unusable. Contact your operator."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Incorrect SIM PUK code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM becomes permanently unusable."</item>
-    <item quantity="other" msgid="5477305226026342036">"Incorrect SIM PUK code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM becomes permanently unusable."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
+      <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN operation failed!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Previous track button"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Next track button"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause button"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Play button"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop button"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index 6ac27be..ee5da13 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Type password to unlock"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Type PIN to unlock"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Incorrect PIN code."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charging"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM card is locked."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM card is PUK-locked."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Unlocking SIM card…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d of %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Add widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Empty"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Unlock area expanded."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Unlock area collapsed."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"User selector"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media controls"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget reordering started."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget reordering ended."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> deleted."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expand unlock area."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Slide unlock."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pattern unlock."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin unlock."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN area"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN area"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK area"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Previous track button"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Next track button"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause button"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Play button"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop button"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Thumbs up"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Thumbs down"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Heart"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Unlock to continue"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Launch cancelled"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Drop <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> to delete."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> will not be deleted."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Done"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Unlock"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silent"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sound on"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Slide down for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Slide right for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?\nVisit "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Checking account…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Incorrect SIM PIN code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before you must contact your carrier to unlock your device."</item>
-    <item quantity="other" msgid="2215723361575359486">"Incorrect SIM PIN code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
+      <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before you must contact your operator to unlock your device.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM is unusable. Contact your operator."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Incorrect SIM PUK code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM becomes permanently unusable."</item>
-    <item quantity="other" msgid="5477305226026342036">"Incorrect SIM PUK code; you have <xliff:g id="NUMBER">%d</xliff:g> remaining attempt/s before SIM becomes permanently unusable."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.</item>
+      <item quantity="one">Incorrect SIM PUK code, you have <xliff:g id="NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN operation failed!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Previous track button"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Next track button"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause button"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Play button"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stop button"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index 80058ba..b34dd05 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ingresar contraseña para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ingresa el PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Cargando"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta tu cargador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La tarjeta SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La tarjeta SIM está bloqueada por código PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando tarjeta SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Agregar widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vacío"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área desbloqueada expandida."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"El área desbloqueada se contrajo."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cámara"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de medios"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Se comenzaron a reordenar los widgets."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Se terminaron de reordenar los widgets."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir el área desbloqueada"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueo por deslizamiento"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueo por patrón"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueo facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueo por PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área de PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área de PIN de SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área de PUK de SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de pista anterior"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de pista siguiente"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botón de reproducción"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botón de detención"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Votos a favor"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Votos en contra"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Corazón"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloquea para continuar."</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Se canceló el inicio."</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Suelta <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> para eliminarlo."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"No se eliminará <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Próxima alarma establecida: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Listo"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio de modo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayúscula"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ingresar"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Desliza el dedo hacia abajo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Desliza el dedo hacia la derecha para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, accede con tu cuenta de Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Acceder"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nombre de usuario o contraseña incorrectos"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?\nAccede a "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando la cuenta…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con el proveedor para desbloquear el dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"El código PIN de la tarjeta SIM es incorrecto. Te queda <xliff:g id="NUMBER">%d</xliff:g> intento antes de que debas comunicarte con el proveedor para desbloquear el dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"El código PIN de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
+      <item quantity="one">El código PIN de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_0">%d</xliff:g> intento más antes de que debas comunicarte con el proveedor para desbloquear el dispositivo.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La tarjeta SIM no se puede utilizar. Comunícate con el proveedor."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"El código PUK de la tarjeta SIM es incorrecto. Te queda <xliff:g id="NUMBER">%d</xliff:g> intento antes de que la tarjeta SIM quede inutilizable permanentemente."</item>
-    <item quantity="other" msgid="5477305226026342036">"El código PUK de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que la tarjeta SIM quede inutilizable permanentemente."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">El código PUK de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más antes de que la tarjeta SIM quede inutilizable de forma permanente.</item>
+      <item quantity="one">El código PUK de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_0">%d</xliff:g> intento más antes de que la tarjeta SIM quede inutilizable de forma permanente.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Error al desbloquear la tarjeta SIM con el PIN"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al desbloquear la tarjeta SIM con el PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de pista anterior"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de pista siguiente"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botón de pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botón de reproducción"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botón de detención"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 9d6cdc4..be3c113 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduce la contraseña para desbloquear."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduce el código PIN para desbloquear."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Cargando"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta el cargador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La tarjeta SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La tarjeta SIM está bloqueada con el código PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando tarjeta SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Añadir widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vacío"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueo ampliada"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueo contraída"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cámara"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles multimedia"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Se ha empezado a cambiar el orden de los widgets."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Se ha terminado de cambiar el orden de los widgets."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ampliar área de desbloqueo"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueo deslizando el dedo"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueo por patrón"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueo facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueo por PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área de PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área de PIN de SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área de PUK de SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de canción anterior"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de siguiente canción"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botón de reproducción"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botón para detener la reproducción"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Me gusta"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"No me gusta"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Corazón"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloquear para continuar"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Inicio cancelado"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Suelta <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> para eliminarlo."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> no se eliminará."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Próxima alarma: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Listo"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio de modo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayús"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Intro"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silencio"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sonido activado"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Desliza el dedo hacia abajo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Desliza el dedo hacia la derecha para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Has olvidado el patrón?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"El patrón es incorrecto"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear el teléfono, inicia sesión con tu cuenta de Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo electrónico)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sesión"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"El nombre de usuario o la contraseña no son válidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Si has olvidado tu nombre de usuario o tu contraseña,\naccede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando cuenta…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN de la tarjeta SIM incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Código PIN de la tarjeta SIM incorrecto. Queda <xliff:g id="NUMBER">%d</xliff:g> intento para tener que ponerte en contacto con tu operador para desbloquear el dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"Código PIN de la tarjeta SIM incorrecto. Quedan <xliff:g id="NUMBER">%d</xliff:g> intentos."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Código PIN de la tarjeta SIM incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
+      <item quantity="one">Código PIN de la tarjeta SIM incorrecto. Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para tener que ponerte en contacto con tu operador para desbloquear el dispositivo.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La tarjeta SIM no se puede utilizar. Ponte en contacto con tu operador."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Código PUK de la tarjeta SIM incorrecto. Te queda <xliff:g id="NUMBER">%d</xliff:g> intento para que la tarjeta SIM no se pueda utilizar de forma permanente."</item>
-    <item quantity="other" msgid="5477305226026342036">"Código PUK de la tarjeta SIM incorrecto. Quedan <xliff:g id="NUMBER">%d</xliff:g> intentos para que la tarjeta SIM no se pueda utilizar de forma permanente."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Código PUK de la tarjeta SIM incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos para que la tarjeta SIM no se pueda utilizar de forma permanente.</item>
+      <item quantity="one">Código PUK de la tarjeta SIM incorrecto. Te queda <xliff:g id="NUMBER_0">%d</xliff:g> intento para que la tarjeta SIM no se pueda utilizar de forma permanente.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Error al intentar desbloquear la tarjeta SIM con el código PIN"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al intentar desbloquear la tarjeta SIM con el código PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de canción anterior"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de siguiente canción"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botón de pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botón de reproducción"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botón para detener la reproducción"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index ab953e1..402fc14 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Laetud"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Laadimine"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Ühendage laadija."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kaart on lukus."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kaart on PUK-lukus."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kaardi avamine ..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidin %2$d/%3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidina lisamine."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tühi"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Avamisala on laiendatud."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Avamisala on ahendatud."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kasutaja valija"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kaamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meedia juhtnupud"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Vidina ümberkorraldamine algas."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Vidina ümberkorraldamine lõppes."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> on kustutatud."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Avamisala laiendamine."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lohistamisega avamine."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mustriga avamine."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Näoga avamine."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-koodiga avamine."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-koodi ala"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-kaardi PIN-koodi ala"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-kaardi PUK-koodi ala"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nupp Eelmine lugu"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nupp Järgmine lugu"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nupp Peata"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nupp Esita"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nupp Peata"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Meeldib"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Ei meeldi"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Süda"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Jätkamiseks tühistage lukustus"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Käivitamine on tühistatud"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Kustutamiseks laske vidin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> lahti."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Vidinat <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ei kustutata."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Järgmine alarm on määratud ajaks <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režiimi muutmine"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tõstuklahv"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sisestusklahv"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Luku avamine"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kaamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Lohistage alla: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Lohistage vasakule: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Lohistage paremale: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Avamiseks logige sisse oma Google\'i kontoga."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kasutajanimi (e-post)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?\nKülastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto kontrollimine ..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Vale SIM-i PIN-kood, seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Vale SIM-i PIN-kood, teil on jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katse, enne kui peate seadme avamiseks operaatoriga ühendust võtma."</item>
-    <item quantity="other" msgid="2215723361575359486">"Vale SIM-i PIN-kood, teil on jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katset."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Vale SIM-kaardi PIN-kood, teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
+      <item quantity="one">Vale SIM-kaardi PIN-kood, teil on jäänud veel <xliff:g id="NUMBER_0">%d</xliff:g> katse enne, kui peate seadme avamiseks operaatoriga ühendust võtma.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM ei ole kasutatav. Võtke ühendust operaatoriga."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Vale SIM-i PUK-kood, teil on jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katse, enne kui SIM püsivalt lukustatakse."</item>
-    <item quantity="other" msgid="5477305226026342036">"Vale SIM-i PUK-kood, teil on jäänud veel <xliff:g id="NUMBER">%d</xliff:g> katset, enne kui SIM püsivalt lukustatakse."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Vale SIM-kaardi PUK-kood, teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset enne, kui SIM-kaart püsivalt lukustatakse.</item>
+      <item quantity="one">Vale SIM-kaardi PUK-kood, teil on jäänud veel <xliff:g id="NUMBER_0">%d</xliff:g> katse enne, kui SIM-kaart püsivalt lukustatakse.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM-i PIN-koodi toiming ebaõnnestus."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-i PUK-koodi toiming ebaõnnestus."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kood on õige."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nupp Eelmine lugu"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nupp Järgmine lugu"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nupp Peata"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nupp Esita"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nupp Peata"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index ba2c931..86850bb 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Idatzi desblokeatzeko pasahitza"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Idatzi desblokeatzeko PIN kodea"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kode okerra."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Desblokeatzeko, sakatu Menua eta, ondoren, 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Aurpegiaren bidez desblokeatzeko saiakera muga gainditu da"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Kargatuta"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Kargatzen"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Konektatu kargagailura."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM txartela blokeatuta dago."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM txartela PUK bidez blokeatuta dago."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM txartela desblokeatzen…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d/%3$d widgeta."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Gehitu widgeta."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Hutsik"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Desblokeatzeko eremua zabaldu da."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Desblokeatzeko eremua tolestu da."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widgeta."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Erabiltzaile-hautatzailea"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia-kontrolak"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetak berrantolatzen hasi da."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetak berrantolatu dira."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widgeta ezabatu da."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Zabaldu desblokeatzeko eremua."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Hatza lerratuta desblokeatzea."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ereduaren bidez desblokeatzea."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Aurpegiaren bidez desblokeatzea."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN kodearen bidez desblokeatzea."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kodearen eremua"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM txartelaren PIN kodearen eremua"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM txartelaren PUK kodearen eremua"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Aurreko pistara joateko botoia"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Hurrengo pistara joateko botoia"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pausatzeko botoia"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Erreproduzitzeko botoia"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Gelditzeko botoia"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Gustatu zait"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Ez zait gustatu"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Bihotza"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Jarraitzeko, desblokeatu"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Abiaraztea bertan behera utzi da"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Ezabatzeko, jaregin <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Ez da <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ezabatuko."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Hurrengo alarmak ordu honetan joko du: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Utzi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ezabatu"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Eginda"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modu aldaketa"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maius"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sartu"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desblokeatu"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Isila"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Soinua aktibatuta"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"Bilatu"</string>
-    <string name="description_direction_up" msgid="7169032478259485180">"Lerratu gora hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_down" msgid="5087739728639014595">"Lerratu behera hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Lerratu ezkerrera hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Lerratu eskuinera hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Uneko erabiltzailea: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Larrialdi-deia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Eredua ahaztu zaizu"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Eredu okerra"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betirako desgaituko da SIMa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodeak ez datoz bat"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Eredua marrazteko saiakera gehiegi egin dira"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Desblokeatzeko, hasi saioa Google kontuarekin."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Erabiltzaile-izena (helbide elektronikoa)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Pasahitza"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Hasi saioa"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Erabiltzaile-izen edo pasahitz baliogabea."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nZoaz "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontua egiaztatzen…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kendu"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM txartelaren PIN kodea okerra da. Gailua desblokeatzeko, jarri operadorearekin harremanetan."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM txartelaren PIN kodea ez da zuzena; <xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizu. Saiakerak agortuz gero, operadoreari eskatu beharko diozu gailua desblokeatzeko."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM txartelaren PIN kodea ez da zuzena; <xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizkizu."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM txartelaren PIN kodea okerra da. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu gailua desblokeatzeko.</item>
+      <item quantity="one">SIM txartelaren PIN kodea okerra da. <xliff:g id="NUMBER_0">%d</xliff:g> saiakera geratzen zaizu gailua desblokeatzeko.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM txartela erabilgaitza da. Jarri operadorearekin harremanetan."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM txartelaren PUK kodea ez da zuzena; <xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik."</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM txartelaren PUK kodea ez da zuzena; <xliff:g id="NUMBER">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM txartelaren PUK kodea okerra da. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik.</item>
+      <item quantity="one">SIM txartelaren PUK kodea okerra da. <xliff:g id="NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM txartelaren PIN eragiketak huts egin du!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM txartelaren PUK eragiketak huts egin du!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodea onartu da!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Aurreko pistara joateko botoia"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Hurrengo pistara joateko botoia"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pausatzeko botoia"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Erreproduzitzeko botoia"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Gelditzeko botoia"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Zerbitzurik gabe."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index fea1f59..367c411 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -29,10 +29,8 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"برای بازکردن قفل، گذرواژه را وارد کنید"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"برای بازکردن قفل، پین را تایپ کنید"</string>
     <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">"‏دفعات تلاش برای Face Unlock از حداکثر مجاز بیشتر شد"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"شارژ شد"</string>
-    <string name="keyguard_plugged_in" msgid="9087497435553252863">"شارژ کردن"</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>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"شبکه قفل شد"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"سیم کارت قفل شد."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"‏سیم کارت با PUK قفل شده است."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"درحال بازگشایی قفل سیم کارت..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"‏%1$s. ابزارک %2$d از %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ابزارک اضافه کنید."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"خالی"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"منطقه بازگشایی گسترده شد."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"منطقه بازگشایی کوچک شد."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"ابزارک <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"انتخابگر کاربر"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"دوربین"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"کنترل‌های رسانه"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"مرتب سازی مجدد ابزارک آغاز شد."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"مرتب‌سازی مجدد ابزارک به پایان رسید."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ابزارک <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> حذف شد.‍"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"گسترده کردن منطقه بازگشایی شده."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"باز کردن قفل با کشیدن انگشت روی صفحه."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"باز کردن قفل با الگو."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"باز کردن قفل با چهره."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"باز کردن قفل با پین."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"قسمت پین"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"قسمت پین سیم‌کارت"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"‏قسمت PUK سیم‌کارت"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"دکمه تراک قبلی"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"دکمه تراک بعدی"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"دکمه توقف موقت"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"دکمه پخش"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"دکمه توقف"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"رأی موافق"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"رأی مخالف"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"قلب"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"برای ادامه قفل را باز کنید"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"راه‌اندازی لغو شد"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"جهت حذف، <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> را بکشید."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> پاک نخواهد شد."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"زنگ هشدار بعدی برای <xliff:g id="ALARM">%1$s</xliff:g> تنظیم شد"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"انجام شد"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغییر حالت"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"بازکردن قفل"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"دوربین"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ساکت"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"صدا روشن"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"لغزاندن به پایین برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"لغزاندن به راست برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"تماس اضطراری"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"الگو را فراموش کرده‌اید"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"الگوی اشتباه"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاش‌های مکرر به‌طور دائم سیم کارت را غیرفعال خواهد کرد."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"‏تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"‏برای بازگشایی قفل، با حساب Google خود وارد سیستم شوید."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"نام کاربری (ایمیل)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"گذرواژه"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ورود به سیستم"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"نام کاربری یا گذرواژه نامعتبر."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"‏نام کاربری یا گذرواژه خود را فراموش کردید؟\nاز "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"درحال بررسی حساب..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کار حذف می‌شود که با آن همه اطلاعات نمایه حذف می‌شود."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"حذف"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"کد پین سیم کارت اشتباه است، اکنون برای گشودن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"کد پین سیم کارت اشتباه است، <xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن برای گشودن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</item>
-    <item quantity="other" msgid="2215723361575359486">"کد پین سیم کارت اشتباه است، <xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">کد پین سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید.</item>
+      <item quantity="other">کد پین سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"سیم کارت غیر قابل استفاده است. با شرکت مخابراتی‌تان تماس بگیرید."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"‏کد PUK سیم کارت اشتباه است، <xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم کارت به صورت دائم غیر قابل استفاده می‌شود."</item>
-    <item quantity="other" msgid="5477305226026342036">"‏کد PUK سیم کارت اشتباه است، <xliff:g id="NUMBER">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم کارت به طور دائم غیر قابل استفاده می‌شود."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">‏کد PUK سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم‌کارت به صورت دائم غیر قابل استفاده می‌شود.</item>
+      <item quantity="other">‏کد PUK سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید و پس از آن سیم‌کارت به صورت دائم غیر قابل استفاده می‌شود.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"عملیات پین سیم کارت ناموفق بود!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏عملیات PUK سیم کارت ناموفق بود!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کد پذیرفته شد!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"دکمه تراک قبلی"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"دکمه تراک بعدی"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"دکمه توقف موقت"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"دکمه پخش"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"دکمه توقف"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index 6cbc029..68f7016 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Poista lukitus antamalla salasana"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Poista lukitus antamalla PIN-koodi"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN-koodi väärin."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Poista lukitus painamalla Valikko-painiketta ja 0-näppäintä."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Face Unlock -yrityksiä tehty suurin sallittu määrä."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Täynnä"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Ladataan"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Kytke laturi."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortti on lukittu."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortti on PUK-lukittu."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-kortin lukitusta poistetaan…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d/%3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Lisää widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tyhjä"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Lukituksen poiston alue laajennettu."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Lukituksen poiston alue tiivistetty."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Käyttäjävalitsin"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediaohjaimet"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetien järjestely aloitettu."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetien järjestely päättyi."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> poistettu."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Laajenna lukituksen poiston aluetta."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lukituksen poisto liu\'uttamalla."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lukituksen poisto salasanalla."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face Unlock"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lukituksen poisto PIN-koodilla."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-koodin alue"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-kortin PIN-koodin alue"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-kortin PUK-koodin alue"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Edellinen kappale -painike"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Seuraava kappale -painike"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tauko-painike"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Toista-painike"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Keskeytä-painike"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Tykkään"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"En tykkää"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Sydän"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Jatka poistamalla lukitus"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Käynnistys peruutettu"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Poista <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> pudottamalla."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Kohdetta <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ei poisteta."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Seuraava hälytys asetettu: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Peruuta"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Poista"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Valmis"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Tilan muutos"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Poista lukitus"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Äänetön"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ääni käytössä"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Liu\'uta alas ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Liu\'uta vasemmalle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Liu\'uta oikealle ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hätäpuhelu"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unohtunut kuvio"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Väärä kuvio"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodit eivät täsmää"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Poista lukitus kirjautumalla sisään Google-tililläsi."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Käyttäjänimi (sähköposti)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Salasana"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Kirjaudu sisään"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Virheellinen käyttäjänimi tai salasana."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Unohditko käyttäjänimesi tai salasanasi?\nKäy osoitteessa "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tarkistetaan tiliä..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Virheellinen SIM-kortin PIN-koodi. Sinun on nyt otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritys jäljellä, ennen kuin sinun on otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</item>
-    <item quantity="other" msgid="2215723361575359486">"Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritystä jäljellä."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item>
+      <item quantity="one">Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin sinun on otettava yhteyttä operaattoriin laitteen lukituksen avaamiseksi.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortti on käyttökelvoton. Ota yhteys operaattoriin."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Virheellinen SIM-kortin PUK-koodi. Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortista tulee pysyvästi käyttökelvoton."</item>
-    <item quantity="other" msgid="5477305226026342036">"Virheellinen SIM-kortin PUK-koodi. Sinulla on <xliff:g id="NUMBER">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortista tulee pysyvästi käyttökelvoton."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Virheellinen SIM-kortin PUK-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortista tulee pysyvästi käyttökelvoton.</item>
+      <item quantity="one">Virheellinen SIM-kortin PUK-koodi. Sinulla on <xliff:g id="NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortista tulee pysyvästi käyttökelvoton.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM-kortin PIN-toiminto epäonnistui!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-kortin PUK-toiminto epäonnistui!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koodi hyväksytty!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Edellinen kappale -painike"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Seuraava kappale -painike"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tauko-painike"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Toista-painike"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Keskeytä-painike"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ei yhteyttä."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index d5b62ee..2c24f7a 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Saisissez le mot de passe pour déverrouiller le clavier."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Saisissez le NIP pour déverrouiller le clavier."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"NIP erroné."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le téléphone, appuyez sur \"Menu\", puis sur 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charge en cours..."</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La carte SIM est verrouillée."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La carte SIM est verrouillée par clé PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Déverrouillage de la carte SIM en cours…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Développement de la zone de déverrouillage"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Réduction de la zone de déverrouillage"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Caméra"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Début de la réorganisation des widgets"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Fin de la réorganisation des widgets"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Le widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a été supprimé."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Développer la zone de déverrouillage"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Déverrouillage par schéma"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Déverrouillage par reconnaissance faciale"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Déverrouillage par NIP"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Zone du NIP"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zone du NIP de la carte SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zone du code PUK de la carte SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Bouton pour revenir au titre précédent"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Bouton pour atteindre le titre suivant"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Bouton de pause"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Bouton de lecture"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Bouton d\'arrêt"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"J\'aime"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Je n\'aime pas"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Cœur"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Déverrouiller pour continuer"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Lancement annulé"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Déposez <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> pour supprimer."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ne sera pas supprimé."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Heure de la prochaine alarme : <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminé"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Changement de mode"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Son activé"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Faire glisser le doigt vers le bas : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser votre doigt vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser votre doigt vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Pour déverrouiller l\'appareil, connectez-vous avec votre compte Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (courriel)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un NIP incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"NIP de carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative. Après cela, vous devrez communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</item>
-    <item quantity="other" msgid="2215723361575359486">"NIP de carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative(s)."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Le NIP de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
+      <item quantity="other">Le NIP de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La carte SIM est inutilisable. Communiquez avec votre fournisseur de services."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Code PUK de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable."</item>
-    <item quantity="other" msgid="5477305226026342036">"Code PUK de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative(s) avant que votre carte SIM devienne définitivement inutilisable."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Le code PUK de la carte SIM est incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable.</item>
+      <item quantity="other">Le code PUK de la carte SIM est incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM devienne définitivement inutilisable.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Le déverrouillage par NIP de la carte SIM a échoué."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Le déverrouillage de la carte SIM par code PUK a échoué."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Bouton pour revenir au titre précédent"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Bouton pour atteindre le titre suivant"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Bouton de pause"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Bouton de lecture"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Bouton d\'arrêt"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 5a62057..77a2d06 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Saisissez le mot de passe pour déverrouiller le clavier."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Saisissez le code PIN pour déverrouiller le clavier."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Le code PIN est erroné."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le clavier, appuyez sur \"Menu\" puis sur 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Batterie en charge…"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La carte SIM est verrouillée."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La carte SIM est verrouillée par clé PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Déverrouillage de la carte SIM en cours…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d sur %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ajouter un widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vide"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Zone de déverrouillage développée."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zone de déverrouillage réduite."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Sélecteur d\'utilisateur"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Caméra"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Commandes multimédias"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Début de la réorganisation des widgets"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Réorganisation des widgets terminée."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Le widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a été supprimé."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Développer la zone de déverrouillage"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Déverrouillage par schéma"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Déverrouillage par reconnaissance faciale"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Déverrouillage par code PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Champ du code PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Champ du code PIN de la carte SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Champ du code PUK de la carte SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Bouton pour revenir au titre précédent"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Bouton pour atteindre le titre suivant"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Bouton de pause"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Bouton de lecture"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Bouton d\'arrêt"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"J\'aime"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Je n\'aime pas"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Cœur"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Déverrouillez l\'appareil pour continuer."</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Lancement annulé."</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Relâchez le widget \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\" pour le supprimer."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Le widget \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\" ne va pas être supprimé."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Prochaine alarme définie à <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminé"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Changement de mode"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Déverrouiller"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Appareil photo"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Mode silencieux"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Son activé"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Faites glisser vers le bas pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Faites glisser vers la gauche pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Faites glisser vers la droite pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Pour déverrouiller le téléphone, veuillez vous connecter avec votre compte Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?\nRendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Vérification du compte en cours…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Code PIN de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative. Après cela, vous devrez contacter votre opérateur pour déverrouiller votre appareil."</item>
-    <item quantity="other" msgid="2215723361575359486">"Code PIN de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentatives."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Code PIN de la carte SIM erroné. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
+      <item quantity="other">Code PIN de la carte SIM erroné. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La carte SIM est inutilisable. Veuillez contacter votre opérateur."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Clé PUK de la carte SIM incorrecte. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable."</item>
-    <item quantity="other" msgid="5477305226026342036">"Clé PUK de la carte SIM incorrecte. Il vous reste <xliff:g id="NUMBER">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Clé PUK de la carte SIM erronée. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable.</item>
+      <item quantity="other">Clé PUK de la carte SIM erronée. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Échec du déverrouillage à l\'aide du code PIN de la carte SIM."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Bouton pour revenir au titre précédent"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Bouton pour atteindre le titre suivant"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Bouton de pause"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Bouton de lecture"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Bouton d\'arrêt"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
 </resources>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 4cd8ae0..8e8f5c5 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Escribe o contrasinal para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Escribe o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorrecto"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, preme Menú e, a continuación, 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Superouse o número máximo de intentos de desbloqueo facial"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Cargado"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Cargando"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta o cargador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"A tarxeta SIM está bloqueada."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"A tarxeta SIM está bloqueada mediante un PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando tarxeta SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Engadir widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Baleiro"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueo ampliada"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueo contraída"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector de usuarios"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cámara"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controis multimedia"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Reordenación de widget iniciada"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordenación de widget finalizada"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ampliar zona de desbloqueo."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueo pasando o dedo."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueo mediante padrón"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueo facial"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueo mediante PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN da tarxeta SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK da tarxeta SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botón de pista anterior"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botón de pista seguinte"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botón de pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botón de reprodución"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botón de parada"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Gustoume"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Non me gustou"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Corazón"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloquea para continuar"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Inicio cancelado"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Solta <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> para eliminalo."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Non se eliminará <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Próxima alarma definida para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Feito"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio de modo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayús"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Intro"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Cámara"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silencio"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Son activado"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
-    <string name="description_direction_up" msgid="7169032478259485180">"Pasa o dedo cara arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_down" msgid="5087739728639014595">"Pasa o dedo cara abaixo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Pasa o dedo cara a esquerda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Pasa o dedo cara a dereita para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Usuario actual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emerxencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueciches o padrón"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Padrón incorrecto"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Volve introducir o código PUK correcto. Se realizas intentos repetidos é posible que se desactive a tarxeta SIM permanentemente."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN non coinciden"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Tentaches debuxar o padrón moitas veces"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, inicia sesión coa túa conta de Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de usuario (correo electrónico)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contrasinal"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sesión"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"O nome de usuario ou o contrasinal non son válidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueciches o teu nome de usuario ou contrasinal?\nVisita a páxina "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Comprobando a conta..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"O código PIN da SIM non é correcto. Agora debes contactar co teu operador para desbloquear o dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"O código PIN da SIM non é correcto. Quédache <xliff:g id="NUMBER">%d</xliff:g> intento antes de que teñas que contactar co operador para desbloquear o dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"O código PIN da SIM non é correcto. Quédanche <xliff:g id="NUMBER">%d</xliff:g> intentos."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">O código PIN da SIM é incorrecto. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
+      <item quantity="one">O código PIN da SIM é incorrecto. Quédache <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que teñas que contactar co operador para desbloquear o dispositivo.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"A SIM está inutilizable. Contacta co teu operador."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"O código PUK da SIM non é correcto. Quédache <xliff:g id="NUMBER">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre."</item>
-    <item quantity="other" msgid="5477305226026342036">"O código PUK da SIM non é correcto. Quédanche <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">O código PUK da SIM é incorrecto. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre.</item>
+      <item quantity="one">O código PUK da SIM é incorrecto. Quédache <xliff:g id="NUMBER_0">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Erro ao tentar desbloquear a tarxeta SIM co código PIN."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Erro ao tentar desbloquar a tarxeta SIM co código PUK."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de pista anterior"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de pista seguinte"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botón de pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botón de reprodución"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botón de parada"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Non hai servizo."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index c1f2b6c..0cd65b8 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करने के लिए पासवर्ड लिखें"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करने के लिए पिन लिखें"</string>
     <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_plugged_in" msgid="9087497435553252863">"चार्ज हो रहा है"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"अपना चार्जर कनेक्‍ट करें."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"सिम कार्ड लॉक है."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"सिम कार्ड PUK द्वारा लॉक किया हुआ है."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"सिम कार्ड अनलॉक हो रहा है…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d विजेट में से %2$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोड़ें"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"खाली"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"अनलॉक क्षेत्र को विस्तृत कर दिया गया."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"अनलॉक क्षेत्र को संक्षिप्त कर दिया गया."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> विजेट."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"उपयोगकर्ता चयनकर्ता"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"कैमरा"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मीडिया नियंत्रण"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"विजेट फिर से क्रमित करना प्रारंभ."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट फिर से क्रमित करना समाप्त."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को हटा दिया गया."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करें."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलॉक."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"आकार अनलॉक."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलॉक."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"पिन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"सिम पिन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"सिम पिइउके क्षेत्र"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"पिछला ट्रैक बटन"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"अगला ट्रैक बटन"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"पॉज़ करें बटन"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"चलाएं बटन"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"रोकें बटन"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"पसंद"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"नापसंद"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"दिल"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"जारी रखने के लिए अनलॉक करें"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"लॉन्‍च रद्द कर दिया गया"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"हटाने के लिए <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> खींचें."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> को नहीं हटाया जाएगा."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"अगला अलार्म <xliff:g id="ALARM">%1$s</xliff:g> के लिए सेट किया गया"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रहने दें"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"अनलॉक करें"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"कैमरा"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"मौन"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ध्‍वनि चालू करें"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए नीचे स्‍लाइड करें."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्‍लाइड करें."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए दाएं स्‍लाइड करें."</string>
-    <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत आकार"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से प्रवेश करें."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"प्रवेश करें"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"निकालें"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"गलत सिम PIN कोड अपने डिवाइस को अनलॉक करने के लिए अब आपको अपने वाहक से संपर्क करना होगा."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"गलत सिम PIN कोड, अपने डिवाइस को अनलॉक करने के लिए अपने वाहक से संपर्क करने से पहले आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष है."</item>
-    <item quantity="other" msgid="2215723361575359486">"गलत सिम PIN कोड, आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष हैं."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">गलत सिम PIN कोड, आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+      <item quantity="other">गलत सिम PIN कोड, आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"सिम अनुपयोगी है. अपने वाहक से संपर्क करें."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"गलत सिम PUK कोड, सिम के स्थायी रूप से अनुपयोगी हो जाने से पहले आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष है."</item>
-    <item quantity="other" msgid="5477305226026342036">"गलत सिम PUK कोड, सिम के स्थायी रूप से अनुपयोगी हो जाने से पहले आपके पास <xliff:g id="NUMBER">%d</xliff:g> प्रयास शेष हैं."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">गलत सिम PUK कोड, सिम के स्थायी रूप से अनुपयोगी हो जाने से पहले आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+      <item quantity="other">गलत सिम PUK कोड, सिम के स्थायी रूप से अनुपयोगी हो जाने से पहले आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"सिम PIN की कार्यवाही विफल रही!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK की कार्यवाही विफल रही!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकार किया गया!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"पिछला ट्रैक बटन"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"अगला ट्रैक बटन"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"पॉज़ करें बटन"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"चलाएं बटन"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"रोकें बटन"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index 56c4bb1..71410c5 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite zaporku za otključavanje"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Netočan PIN kôd."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Za otključavanje pritisnite Izbornik pa 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je maksimalni broj Otključavanja licem"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Napunjeno"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Punjenje"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Priključite punjač."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kartica je zaključana."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kartica zaključana je PUK-om."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Otključavanje SIM kartice…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d od %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodavanje widgeta."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Područje za otključavanje prošireno je."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Područje za otključavanje sažeto je."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Birač korisnika"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparat"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Nadzor medija"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Pokrenuta je promjena redoslijeda widgeta."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Završena je promjena redoslijeda widgeta."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> izbrisan je."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Proširivanje područja za otključavanje."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Otključavanje klizanjem."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Uzorak za otključavanje."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje PIN-om."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Područje PIN-a"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Područje PIN-a za SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Područje PUK-a za SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb Prethodni zapis"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb Sljedeći zapis"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb Pauza"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Gumb Reprodukcija"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Gumb Zaustavi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Palac gore"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Palac dolje"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Srce"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Otključajte za nastavak"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Pokretanje je otkazano"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Ispustite widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> da biste ga izbrisali."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> neće se izbrisati."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Sljedeći alarm postavljen za <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Odustani"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotovo"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Promjena načina"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Otključaj"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Bešumno"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Zvuk je uključen"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Kliznite prema dolje za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Kliznite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Kliznite desno za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hitan poziv"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste obrazac"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan obrazac"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi nisu jednaki"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Za otključavanje prijavite se Google računom."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (e-pošta)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Zaporka"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili zaporka."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili zaporku?\nPosjetite "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Provjera računa..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -147,24 +94,21 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netočan PIN kôd SIM kartice; sada morate kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER">%d</xliff:g> pokušaj prije nego što budete morali kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</item>
-    <item quantity="other" msgid="2215723361575359486">"Netočan PIN kôd SIM kartice; imate još ovoliko preostalih pokušaja: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+      <item quantity="few">Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+      <item quantity="other">Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM kartica nije upotrebljiva. Kontaktirajte svog mobilnog operatera."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Netočan PUK kôd SIM kartice; imate još <xliff:g id="NUMBER">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva."</item>
-    <item quantity="other" msgid="5477305226026342036">"Netočan PUK kôd SIM kartice; imate još nekoliko preostalih pokušaja (<xliff:g id="NUMBER">%d</xliff:g>) prije nego što SIM kartica postane trajno neupotrebljiva."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Netočan PUK kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj prije nego što SIM kartica postane trajno neupotrebljiva.</item>
+      <item quantity="few">Netočan PUK kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva.</item>
+      <item quantity="other">Netočan PUK kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operacija PIN-a SIM kartice nije uspjela!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacija PUK-a SIM kartice nije uspjela!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Gumb Prethodni zapis"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Gumb Sljedeći zapis"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Gumb Pauza"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Gumb Reprodukcija"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Gumb Zaustavi"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 74a63bb..dd43dba 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"A feloldáshoz írja be a jelszót"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Feloldáshoz írja be a PIN kódot"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Helytelen PIN kód."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"A feloldáshoz nyomja meg a Menü, majd a 0 gombot."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Elérte az arcalapú feloldási kísérletek maximális számát"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Feltöltve"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Töltés"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Csatlakoztassa a töltőt."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"A SIM kártya le van zárva."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"A SIM kártya le van zárva a PUK kóddal."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM kártya feloldása..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Modul %3$d/%2$d"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Modul hozzáadása."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Üres"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Feloldási terület kiterjesztve."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Feloldási terület összecsukva."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> modul."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Felhasználóválasztó"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Médiaelemek vezérlője"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"A modulátrendezés elkezdődött."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"A modulátrendezés véget ért."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> modul törölve."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"A feloldási terület kiterjesztése."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Feloldás csúsztatással"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Feloldás mintával"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Arcalapú feloldás"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Feloldás PIN kóddal"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kód területe"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN kód területe"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK kód területe"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Előző szám gomb"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Következő szám gomb"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Szünet gomb"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Lejátszás gomb"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Leállítás gomb"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Tetszik"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nem tetszik"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Szív"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"A folytatáshoz oldja fel a billentyűzárat"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Indítás törölve"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Engedje el a(z) <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> törléséhez."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"A(z) <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> nem lesz törölve."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"A következő riasztás beállított ideje: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Mégse"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Kész"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mód váltása"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Feloldás"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Némítás"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Hang bekapcsolása"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa lefelé."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa balra."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa jobbra."</string>
-    <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Segélyhívás"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Elfelejtett minta"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Helytelen minta"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Adja meg újra a helyes PUK kódot. Az ismételt próbálkozással véglegesen letiltja a SIM kártyát."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"A PIN kódok nem egyeznek."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"A feloldáshoz jelentkezzen be Google-fiókjával."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Felhasználónév (e-mail cím)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Jelszó"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Bejelentkezés"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Érvénytelen felhasználónév vagy jelszó."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Elfelejtette a felhasználónevét vagy jelszavát?\nKeresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Fiók ellenőrzése..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\n Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja munkahelyi profilját, és összes profiladata törlődik."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Helytelen PIN kód a SIM kártyához; vegye fel a kapcsolatot szolgáltatójával az eszköz feloldásához."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Helytelen PIN kód a SIM kártyához; még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van, mielőtt fel kellene vennie a kapcsolatot szolgáltatójával az eszköz feloldásához."</item>
-    <item quantity="other" msgid="2215723361575359486">"Helytelen PIN kód a SIM kártyához; még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">A SIM kártya PIN kódja helytelen. <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozás maradt.</item>
+      <item quantity="one">A SIM kártya PIN kódja helytelen. <xliff:g id="NUMBER_0">%d</xliff:g> próbálkozás maradt. Utána a szolgáltatótól kell feloldást kérnie.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"A SIM kártya használhatatlan. Vegye fel a kapcsolatot szolgáltatójával."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Helytelen PUK kód a SIM kártyához; még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van, mielőtt a SIM kártya végleg használhatatlan lesz."</item>
-    <item quantity="other" msgid="5477305226026342036">"Helytelen PUK kód a SIM kártyához; még <xliff:g id="NUMBER">%d</xliff:g> próbálkozása van, mielőtt a SIM kártya végleg használhatatlan lesz."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Helytelen PUK kód a SIM kártyához. Még <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása van, mielőtt a SIM kártya végleg használhatatlanná válik.</item>
+      <item quantity="one">Helytelen PUK kód a SIM kártyához. Még <xliff:g id="NUMBER_0">%d</xliff:g> próbálkozása van, mielőtt a SIM kártya végleg használhatatlanná válik.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"A SIM kártya PIN-művelete sikertelen!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"A SIM kártya PUK-művelete sikertelen!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód elfogadva."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Előző szám gomb"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Következő szám gomb"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Szünet gomb"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Lejátszás gomb"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Leállítás gomb"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nincs szolgáltatás."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index e233d12..e56642a 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Մուտքագրեք գաղտնաբառը ապակողպման համար"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Մուտքագրեք PIN-ը ապակողպման համար"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Սխալ PIN ծածկագիր:"</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_plugged_in" msgid="9087497435553252863">"Լիցքավորում"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Միացրեք ձեր լիցքավորիչը:"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM քարտը կողպված է:"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM քարտը PUK-ով կողպված է:"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM քարտը ապակողպվում է..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Վիջեթ %2$d of %3$d:"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ավելացնել վիջեթ:"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Դատարկ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ապակողպման տարածքն ընդլայնված է:"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ապակողպման տարածքը ետ է ծալված:"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> վիջեթ:"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Օգտվողի ընտրիչ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Ֆոտոխցիկ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Մեդիա կարգավորումներ"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Վիջեթների վերադասավորումը մեկնարկել է:"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Վիջեթի վերադասավորումն ավարտվեց:"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Վիջեթ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-ը ջնջված է:"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ընդլայնել ապակողպման տարածությունը:"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Էջի ապակողպում:"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Սխեմայով ապակողպում:"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Դեմքով ապակողպում:"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin-ն ապակողպված է:"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN կոդի տարածք"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM քարտի PIN կոդի տարածք"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM քարտի PUK կոդի տարածք"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Նախորդ հետագծի կոճակը"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Հաջորդ հետագծի կոճակը"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Դադարի կոճակ"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Նվագարկման կոճակ"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Կանգի կոճակ"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Լավն է"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Լավը չէ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Սիրտ"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Շարունակելու համար ապակողպեք"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Գործարկումը չեղարկվեց"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> վիջեթը ջնջելու համար բաց թողեք այն այստեղ:"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> վիջեթը չի ջնջվի:"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Հաջորդ զարթուցիչը դրված է <xliff:g id="ALARM">%1$s</xliff:g>-ի վրա"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Չեղարկել"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ջնջել"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Կատարված է"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ռեժիմի փոփոխում"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Մուտք"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Ապակողպել"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Ֆոտոխցիկ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Լուռ"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ձայնը միացնել"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Սահեցրեք ցած <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Սահեցրեք ձախ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Սահեցրեք աջ` <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
-    <string name="user_switched" msgid="3768006783166984410">"Ներկայիս օգտվողը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Արտակարգ իրավիճակի հեռախոսազանգ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Սխալ սխեմա"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Օգտանուն (էլփոստ)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Գաղտնաբառը"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Մուտք գործել"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Սխալ օգտանուն կամ գաղտնաբառ:"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Մոռացե՞լ եք ձեր օգտանունը կամ գաղտնաբառը:\nԱյցելեք "<b>"google.com /accounts/recovery"</b>":"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Հաշիվը ստուգվում է..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք մուտքագրել ձեր PIN-ը: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման սխեման: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել ձեր գրասալիկը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Հեռացնել"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Սխալ SIM PIN կոդի պատճառով պետք է դիմեք ձեր օպերատորին՝ սարքն արգելաբացելու համար:"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ, որից հետո պետք է դիմեք ձեր օպերատորին՝ սարքն արգելաբացելու համար:"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ:"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
+      <item quantity="other">SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-ը հնարավոր չէ օգտագործել: Դիմեք ձեր օպերատորին:"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUK կոդը սխալ է: Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ՝ մինչև SIM-ի ընդմիշտ արգելափակումը:"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK կոդը սխալ է: Մնաց <xliff:g id="NUMBER">%d</xliff:g> փորձ՝ մինչև SIM-ի ընդմիշտ արգելափակումը:"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">SIM PUK կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել:</item>
+      <item quantity="other">SIM PUK կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել:</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN գործողությունը ձախողվեց:"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK գործողությունը ձախողվեց:"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Կոդն ընդունվեց:"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Նախորդ հետագծի կոճակ"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Հաջորդ հետագծի կոճակ"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Դադարի կոճակ"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Նվագարկման կոճակ"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Դադարի կոճակ"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index d637208..29a56ef 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ketik sandi untuk membuka kunci"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ketik PIN untuk membuka kunci"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kode PIN salah."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka, tekan Menu lalu 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Percobaan Face Unlock melebihi batas maksimum"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Terisi"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Mengisi daya"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Hubungkan pengisi daya."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kartu SIM terkunci."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kartu SIM terkunci PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kartu SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambahkan widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Area buka kunci diluaskan."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Area buka kunci diciutkan."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrol media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Pengurutan ulang widget dimulai."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Pengurutan ulang widget berakhir."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dihapus."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Luaskan area buka kunci."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci dengan menggeser."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci dengan pola."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Buka kunci dengan face unlock."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci dengan PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Bidang PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Bidang PIN SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Bidang PUK SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tombol lagu sebelumnya"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tombol lagu berikutnya"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tombol jeda"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tombol putar"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tombol hentikan"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Bagus"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Jelek"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hati"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Buka kunci untuk melanjutkan"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Peluncuran dibatalkan"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Jatuhkan <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> untuk menghapus."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> tidak akan dihapus."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Alarm berikutnya disetel untuk <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Hapus"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Pengubahan mode"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Membuka gembok"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Suara hidup"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Geser ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Geser ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Geser ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan darurat"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Pola?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pola Salah"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kode PIN tidak cocok"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, masuk dengan akun Google Anda."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama pengguna (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Sandi"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Masuk"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau sandi tidak valid."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?\nKunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Memeriksa akun…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Kode PIN SIM salah, sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan sebelum Anda harus menghubungi operator untuk membuka kunci perangkat."</item>
-    <item quantity="other" msgid="2215723361575359486">"Kode PIN SIM salah, sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Kode PIN SIM salah, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
+      <item quantity="one">Kode PIN SIM salah, sisa <xliff:g id="NUMBER_0">%d</xliff:g> percobaan sebelum Anda harus menghubungi operator untuk membuka kunci perangkat.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM tidak dapat digunakan. Hubungi operator Anda."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Kode PUK SIM salah, sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan selamanya."</item>
-    <item quantity="other" msgid="5477305226026342036">"Kode PUK SIM salah, sisa <xliff:g id="NUMBER">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan selamanya."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Kode PUK SIM salah, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan selamanya.</item>
+      <item quantity="one">Kode PUK SIM salah, sisa <xliff:g id="NUMBER_0">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan selamanya.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operasi PIN SIM gagal!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode Diterima!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tombol lagu sebelumnya"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tombol lagu berikutnya"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tombol jeda"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tombol putar"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tombol hentikan"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tidak ada layanan."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index d1d8dc2..5741cd0 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Sláðu inn aðgangsorðið til að opna"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Sláðu inn PIN-númer til að opna"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Rangt PIN-númer."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Til að taka úr lás ýtirðu á valmyndartakkann og síðan 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Hámarksfjölda tilrauna til að opna með andliti náð"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Fullhlaðið"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Í hleðslu"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Tengdu hleðslutækið."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortið er læst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortið er PUK-læst."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Tekur SIM-kort úr lás…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Græja %2$d af %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Bæta græju við."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Autt"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Opnunarsvæði stækkað."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Opnunarsvæði fellt saman."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Græjan <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Notandaval"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Myndavél"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Margmiðlunarstýringar"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Endurröðun græja hafin."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Endurröðun græja lokið."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Græjunni <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eytt."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Stækka opnunarsvæði."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Opnun með stroku."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Opnun með mynstri."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Opnun með andliti."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Opnun með PIN-númeri."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-svæði"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-svæði SIM-korts"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-svæði SIM-korts"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Hnappur fyrir fyrra lag"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Hnappur fyrir næsta lag"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Hnappur til að gera hlé"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Hnappur til að spila"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Hnappur til að stöðva"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Þumall upp"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Þumall niður"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hjarta"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Taktu úr lás til að halda áfram"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Hætt við ræsingu"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Slepptu <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> til að eyða."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> verður ekki eytt."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Næsti vekjari stilltur á <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hætta við"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eyða"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Lokið"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Breyta stillingu"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Taka úr lás"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Myndavél"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Hljóðlaust"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Kveikt á hljóði"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"Leita"</string>
-    <string name="description_direction_up" msgid="7169032478259485180">"Strjúktu upp til að <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_down" msgid="5087739728639014595">"Strjúktu niður til að <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Strjúktu til vinstri til að <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Strjúktu til hægri til að <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Núverandi notandi <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Neyðarsímtal"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Man ekki mynstrið"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Rangt mynstur"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Prófaðu aftur að setja inn rétt PUK-númer. Endurteknar tilraunir gera SIM-kortið varanlega óvirkt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-númerin stemma ekki"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Of margar tilraunir til að teikna mynstur"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Skráðu þig inn með Google reikningnum þínum til að opna."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Notandanafn (netfang)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Aðgangsorð"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Skrá inn"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ógilt notandanafn eða aðgangsorð."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Gleymdirðu notandanafninu eða aðgangsorðinu?\nFarðu á "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Athugar reikninginn…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjarlægja"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Rangt PIN-númer SIM-korts. Þú þarft núna að hafa samband við símafyrirtækið þitt til að taka tækið úr lás."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraun eftir áður en þú þarft að hafa samband við símafyrirtækið þitt til að taka tækið úr lás."</item>
-    <item quantity="other" msgid="2215723361575359486">"Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraunir eftir."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item>
+      <item quantity="other">Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraunir eftir.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortið er ónothæft. Hafðu samband við símafyrirtækið þitt."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Rangt PUK-númer SIM-korts. Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraun eftir áður en SIM-kortið verður ónothæft til frambúðar."</item>
-    <item quantity="other" msgid="5477305226026342036">"Rangt PUK-númer SIM-korts. Þú átt <xliff:g id="NUMBER">%d</xliff:g> tilraunir eftir áður en SIM-kortið verður ónothæft til frambúðar."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Rangt PUK-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir áður en SIM-kortið verður ónothæft til frambúðar.</item>
+      <item quantity="other">Rangt PUK-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraunir eftir áður en SIM-kortið verður ónothæft til frambúðar.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"PIN-aðgerð SIM-korts mistókst!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-aðgerð SIM-korts mistókst!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Númer samþykkt!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Hnappur fyrir fyrra lag"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Hnappur fyrir næsta lag"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Hnappur til að gera hlé"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Hnappur til að spila"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Hnappur til að stöðva"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ekkert símasamband."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index ac7de84..c5c476c 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Inserisci password per sbloccare"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Inserisci PIN per sbloccare"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Codice PIN errato."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Per sbloccare, premi Menu, poi 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Numero massimo di tentativi di Sblocco col sorriso superato"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Carico"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"In carica"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Collega il caricabatterie."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"La SIM è bloccata."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"La SIM è bloccata tramite PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Sblocco scheda SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d di %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Aggiungi widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vuoto"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Area di sblocco estesa."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Area di sblocco compressa."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selettore utente"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotocamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controlli media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Riordino dei widget iniziato."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Riordino dei widget terminato."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminato."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Espandi area di sblocco."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Sblocco con scorrimento."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Sblocco con sequenza."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Sblocco col sorriso."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Sblocco con PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Area PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Area PIN SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Area PUK SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Pulsante traccia precedente"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Pulsante traccia successiva"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pulsante Pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Pulsante Riproduci"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Pulsante di arresto"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Mi piace"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Pollice giù"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Cuore"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Sblocca per continuare"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Avvio annullato"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Rilascia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> per eliminarlo."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> non sarà eliminato."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Prossima sveglia impostata a: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annulla"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Canc"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Fine"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Cambio modalità"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maiuscolo"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invio"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Sblocca"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Fotocamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silenzioso"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Audio attivato"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Giù per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"A destra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chiamata di emergenza"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Sequenza dimenticata"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequenza sbagliata"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"I codici PIN non corrispondono"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Per sbloccare, accedi con il tuo account Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome utente (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Accedi"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome utente o password non validi."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Hai dimenticato il nome utente o la password?\nVisita "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Controllo account…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
+      <item quantity="one">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM inutilizzabile. Contatta il tuo operatore."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
-    <item quantity="other" msgid="5477305226026342036">"Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
+      <item quantity="one">Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operazione con PIN della SIM non riuscita."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operazione con PUK della SIM non riuscita."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Codice accettato."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Pulsante traccia precedente"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Pulsante traccia successiva"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pulsante Pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Pulsante Riproduci"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Pulsante di arresto"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nessun servizio."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 2d8f1bf..a856ccb 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"הקלד סיסמה לביטול הנעילה"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"‏הקלד קוד PIN לביטול הנעילה"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"‏קוד PIN שגוי"</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_plugged_in" msgid="9087497435553252863">"טוען"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"חבר את המטען."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"‏כרטיס ה-SIM נעול."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"‏כרטיס SIM נעול באמצעות PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"‏מבטל נעילה של כרטיס SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"‏%1$s. Widget %2$d מתוך %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"‏הוסף Widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ריק"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"אזור ביטול הנעילה הורחב."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"אזור ביטול הנעילה כווץ."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"‏Widget ‏<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"בוחר משתמשים"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"מצלמה"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"פקדי מדיה"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"‏סידור מחדש של Widgets התחיל."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"‏סידור מחדש של Widgets הסתיים."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"‏Widget ‏<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> נמחק."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"הרחב את אזור ביטול הנעילה."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ביטול נעילה באמצעות הסטה."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ביטול נעילה באמצעות ציור קו."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ביטול נעילה באמצעות זיהוי פנים."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"‏ביטול נעילה באמצעות מספר PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"‏אזור עבור קוד PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"‏אזור עבור קוד PIN של SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"‏אזור עבור קוד PUK של SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"לחצן \'הרצועה הקודמת\'"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"לחצן \'הרצועה הבאה\'"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"לחצן \'השהה\'"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"לחצן \'הפעל\'"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"לחצן \'הפסק\'"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"אהבתי"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"לא אהבתי"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"לב"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"בטל נעילה כדי להמשיך"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ההפעלה בוטלה"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"שחרר את <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> למחיקה."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> לא יימחק."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"ההתראה הבאה נקבעה לשעה <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"אבג"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ביטול"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"מחק"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"סיום"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"שינוי מצב"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"בטל נעילה"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"מצלמה"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"שקט"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"הקול פועל"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"הסט למטה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"הסט שמאלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"הסט ימינה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"שיחת חירום"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"שכחת את הקו"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"קו ביטול נעילה שגוי"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"‏הזן מחדש את קוד PUK הנכון. ניסיונות חוזרים ישביתו לצמיתות את כרטיס ה-SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏קודי ה-PIN אינם תואמים"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ניסיונות רבים מדי לשרטוט קו ביטול נעילה."</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"‏כדי לבטל את הנעילה, היכנס באמצעות חשבון Google שלך."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"שם משתמש (אימייל)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"סיסמה"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"היכנס"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"שם משתמש או סיסמה לא חוקיים."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"‏שכחת את שם המשתמש או הסיסמה?\nבקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"בודק חשבון…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"‏הקלדת מספר PIN שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"הסר"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"‏מספר PIN שגוי של כרטיס ה-SIM. עליך ליצור כעת קשר עם הספק על מנת לבטל את נעילת המכשיר."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"‏מספר PIN שגוי של כרטיס ה-SIM. נותר לך ניסיון <xliff:g id="NUMBER">%d</xliff:g> נוסף לפני שיהיה עליך ליצור קשר עם הספק על מנת לבטל את נעילת המכשיר."</item>
-    <item quantity="other" msgid="2215723361575359486">"‏מספר PIN שגוי של כרטיס ה-SIM. נותרו לך <xliff:g id="NUMBER">%d</xliff:g> ניסיונות נוספים."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="two">‏קוד PIN שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
+      <item quantity="many">‏קוד PIN שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
+      <item quantity="other">‏קוד PIN שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
+      <item quantity="one">‏קוד PIN שגוי של כרטיס SIM. נותר לך ניסיון <xliff:g id="NUMBER_0">%d</xliff:g> לפני שיהיה עליך ליצור קשר עם הספק כדי לבטל את נעילת המכשיר.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"‏לא ניתן להשתמש בכרטיס ה-SIM. צור קשר עם הספק."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"‏קוד PUK שגוי של כרטיס ה-SIM. נותר לך ניסיון <xliff:g id="NUMBER">%d</xliff:g> נוסף לפני שכרטיס ה-SIM ינעל לצמיתות."</item>
-    <item quantity="other" msgid="5477305226026342036">"‏קוד PUK שגוי של כרטיס ה-SIM. נותרו לך <xliff:g id="NUMBER">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="two">‏קוד PUK שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני שכרטיס ה-SIM יינעל לצמיתות.</item>
+      <item quantity="many">‏קוד PUK שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני שכרטיס ה-SIM יינעל לצמיתות.</item>
+      <item quantity="other">‏קוד PUK שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות לפני שכרטיס ה-SIM יינעל לצמיתות.</item>
+      <item quantity="one">‏קוד PUK שגוי של כרטיס SIM. נותר לך ניסיון <xliff:g id="NUMBER_0">%d</xliff:g> לפני שכרטיס ה-SIM יינעל לצמיתות.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"‏פעולת מספר ה-PIN של כרטיס ה-SIM נכשלה!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏פעולת קוד ה-PUK של כרטיס ה-SIM נכשלה!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"הקוד התקבל!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"לחצן \'הרצועה הקודמת\'"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"לחצן \'הרצועה הבאה\'"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"לחצן \'השהה\'"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"לחצן \'הפעל\'"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"לחצן \'הפסק\'"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index 39dc52e..5c76034 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ロックを解除するにはパスワードを入力"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ロックを解除するにはPINを入力"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PINコードが正しくありません。"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"MENU、0キーでロック解除"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"充電完了"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"充電してください。"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIMカードはロックされています。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIMカードはPUKでロックされています。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIMカードをロック解除しています…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。ウィジェット%2$d/%3$d。"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ウィジェットを追加します。"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"なし"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ロック解除エリアを拡大しました。"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ロック解除エリアを縮小しました。"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ウィジェットです。"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ユーザー切り替え"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"カメラ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"メディアコントロール"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ウィジェットの並べ替えを開始しました。"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ウィジェットの並べ替えを終了しました。"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ウィジェットを削除しました。"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ロック解除エリアを拡大します。"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"スライドロックを解除します。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"パターンロックを解除します。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"フェイスアンロックを行います。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PINロックを解除します。"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PINエリア"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PINエリア"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUKエリア"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"前のトラックボタン"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"次のトラックボタン"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"一時停止ボタン"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"再生ボタン"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"停止ボタン"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"グッド"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"イマイチ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"ハート"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"続行するにはロックを解除してください"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"起動をキャンセルしました"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"削除するには<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>をドロップしてください。"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>は削除されません。"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"次のアラームは<xliff:g id="ALARM">%1$s</xliff:g>に設定されました"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"キャンセル"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"削除"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完了"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"モードを変更"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ロックを解除"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"カメラ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"マナーモード"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"サウンドON"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"下にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"左にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"右にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
-    <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急通報"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"パターンを忘れた場合"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"パターンが正しくありません"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"正しいPUKコードを再入力してください。誤入力を繰り返すと、SIMが永久に無効になるおそれがあります。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PINコードが一致しません"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"パターンの入力を所定の回数以上間違えました。"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"ロックを解除するにはGoogleアカウントでログインしてください。"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ユーザー名(メール)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"パスワード"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ログイン"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ユーザー名またはパスワードが無効です。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ユーザー名またはパスワードを忘れた場合は\n "<b>"google.com/accounts/recovery"</b>" にアクセスしてください。"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"アカウントをチェックしています…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"パスワードの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"携帯電話のロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。ワークプロフィールが削除され、プロフィールのデータがすべて削除されます。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"削除"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PINコードが無効です。お使いの端末をロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。この回数を超えると、お使いの端末をロック解除するのに携帯通信会社にお問い合わせいただく必要があります。"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER_1">%d</xliff:g>回です。</item>
+      <item quantity="one">SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER_0">%d</xliff:g>回です。この回数を超えた場合は、携帯通信会社にお問い合わせください。</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIMは使用できません。携帯通信会社にお問い合わせください。"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUKコードが無効です。入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。この回数を超えるとSIMは完全に使用できなくなります。"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUKコードが無効です。入力できるのはあと<xliff:g id="NUMBER">%d</xliff:g>回です。この回数を超えるとSIMは完全に使用できなくなります。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUKコードが無効です。入力できるのはあと<xliff:g id="NUMBER_1">%d</xliff:g>回です。この回数を超えるとSIMは完全に使用できなくなります。</item>
+      <item quantity="one">SIM PUKコードが無効です。入力できるのはあと<xliff:g id="NUMBER_0">%d</xliff:g>回です。この回数を超えるとSIMは完全に使用できなくなります。</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN操作に失敗しました。"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK操作に失敗しました。"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"コードが承認されました。"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"前のトラックボタン"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"次のトラックボタン"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"一時停止ボタン"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"再生ボタン"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"停止ボタン"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index ccd6bea..e9c77fd 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"განსაბლოკად აკრიფეთ პაროლი"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"განსაბლოკად აკრიფეთ PIN კოდი"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"არასწორი PIN კოდი."</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_plugged_in" msgid="9087497435553252863">"მიმდინარეობს დატენვა"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"შეაერთეთ დამტენი."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM ბარათი დაბლოკილია."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM ბარათი დაბლოკილია PUK კოდით."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"მიმდინარეობს SIM ბარათის განბლოკვა…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ვიჯეტი %2$d of %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ვიჯეტის დამატება"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ცარიელი"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"განბლოკვის სივრცე გაშლილია."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"განბლოკვის სივრცე ჩაკეცილია."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ვიჯეტი."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"მომხმარებლის ამომრჩეველი"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"კამერა"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"მედიის მართვის ელემენტები"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"დაიწყო ვიჯეტის ხელახლა განლაგება."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ვიჯეტების გადახარისხება დასრულებულია."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ვიჯეტი <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> წაიშალა."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"განბლოკვის სივრცის გაშლა."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"გასრიალებით განბლოკვა"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"განბლოკვა ნიმუშით."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"განბლოკვა სახით"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"განბლოკვა Pin-ით."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-ის არე"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM-ის PIN-ის არე"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM-ის PUK-ის არე"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"წინა ჩანაწერის ღილაკი"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"შემდეგი ჩანაწერის ღილაკი"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"პაუზის ღილაკი"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"დაკვრის ღილაკი"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stop ღილაკი"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"ზევით აწეული ცერი"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ქვევით დახრილი ცერი"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"გული"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"განბლოკეთ გასაგრძელებლად"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"გამოძახება გაუქმდა"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ჩააგდეთ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> წასაშლელად."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> არ წაიშლება."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"შემდეგი მაღვიძარა დაყენებულია <xliff:g id="ALARM">%1$s</xliff:g>-ზე"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"გაუქმება"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"წაშლა"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"დასრულდა"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"რეჟიმის შეცვლა"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift-"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"შეყვანა"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"განბლოკვა"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"კამერა"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"უხმო"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ხმის ჩართვა"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"გაასრიალეთ ქვემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"გაასრიალეთ მარცხნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"გაასრიალეთ მარჯვნივ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
-    <string name="user_switched" msgid="3768006783166984410">"ამჟამინდელი მომხმარებელი <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"გადაუდებელი დახმარების ზარი"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"დაგავიწყდათ ნიმუში"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"არასწორი ნიმუში"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ხელახლა შეიყვანეთ სწორი PUK კოდი. რამდენიმე წარუმატებელი მცდელობა გამოიწვევს SIM ბარათის დაბლოკვას."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN კოდები არ ემთხვევა"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ნახატი ნიმუშის ძალიან ბევრი მცდელობა"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"განბლოკვისთვის გაიარეთ ავტორიზაცია თქვენი Google  ანგარიშით."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"მომხმარებლის სახელი (ელფოსტა)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"პაროლი"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"შესვლა"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"არასწორი სახელი, ან პაროლი."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"დაგავიწყდათ მომხმარებლის სახელი და პაროლი?\nეწვიეთ "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"მიმდინარეობს ანგარიშის შემოწმება…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად შეიყვანეთ PIN კოდი. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად დაბეჭდეთ თქვენი პაროლი. \n\nხელახლა სცადეთ <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ დახატეთ განბლოკვის ნიმუში. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. სამუშაო პროფილი ამოიშლება, რაც წაშლის პროფილის მთლიან მონაცემს."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ მოგთხოვთ ტაბლეტის განბლოკვას ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ამოშლა"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენ ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM-ის არასწორი PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ მოგიწევთ თქვენი მოწყობილობის განსაბლოკად ოპერატორთან დაკავშირება."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM-ის არასწორი PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM-ის PIN კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
+      <item quantity="one">SIM-ის PIN კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_0">%d</xliff:g> მცდელობა, სანამ მოგიწევთ თქვენი მოწყობილობის განსაბლოკად ოპერატორთან დაკავშირება.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM გამოუსადეგარია. დაუკავშირდით ოპერატორს."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"არასწორი SIM PUK კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდებოდეს."</item>
-    <item quantity="other" msgid="5477305226026342036">"არასწორი SIM PUK კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდებოდეს."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM-ის PUK კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება.</item>
+      <item quantity="one">SIM-ის PUK კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN ოპერაცია ჩაიშალა!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ოპერაცია ჩაიშალა!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"კოდი მიღებულია!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"წინა ჩანაწერზე გადასვლის ღილაკი"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"შემდეგი ჩანაწერის ღილაკი"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"პაუზის ღილაკი"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"დაკვრის ღილაკი"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"შეჩერების ღილაკი"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index 1663ca0..85443f6 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Бекітпесін ашу үшін құпия сөзді теріңіз"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Бекітпесін ашу үшін PIN кодын теріңіз"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Қате PIN код"</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_plugged_in" msgid="9087497435553252863">"Зарядтауда"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Зарядтау құрылғысын жалғаңыз."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM картасы бекітулі."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картасының PUK коды бекітілген."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картасының бекітпесін ашуда…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d виджет, барлығы %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Виджет қосу."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Бос"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ашу аймағы кеңейтілді."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ашу аймағы қирады."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджеті."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Пайдаланушы таңдаушы"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Meдиа басқарулары"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Виджетті қайта реттеу басталды."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Виджетті қайта реттеу аяқталды."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджеті жойылды."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ашу аймағын кеңейту."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Сырғыту арқылы ашу."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Кескін арқылы ашу."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Бет-әлпет арқылы ашу."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin арқылы ашу."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN аумағы"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN аумағы"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK аумағы"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Алдыңғы жол түймесі"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Келесі жол түймесі"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кідірту түймесі"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Ойнату түймесі"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Тоқтату түймесі"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Ұнайды"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Ұнамайды"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Жүрек"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Жалғастыру үшін ашу"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Қосу тоқтатылды"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> жою үшін тастаңыз"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> жойылмайды."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Келесі дабыл <xliff:g id="ALARM">%1$s</xliff:g> уақытына орнатылған"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Өшіру"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жою"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Орындалды"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Режим өзгерту"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Енгізу"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Бекітпесін ашу"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Үнсіз"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Дыбыс қосулы"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін төмен сырғыту."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін солға сырғыту."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үшін оңға жылжыту."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Ағымдағы пайдаланушы <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Төтенше қоңырау"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Кескінді ұмытып қалу"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Қате кескін"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Дұрыс PUK кодын қайта енгізіңіз. Әрекеттерді қайталау SIM картасының істен шығуына себеп болады."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN коды сәйкес емес."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Тым көп кескін әрекеттері"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Ашу үшін Google есептік жазбасы арқылы кіріңіз."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Пайдаланушы атауы (эл. пошта)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Кілтсөз"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Кіру"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Пайдаланушы атауы немесе кілтсөз жарамсыз."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Пайдаланушы атауын немесе кілтсөзді ұмытып қалдыңыз ба?\n"<b>"google.com/accounts/recovery"</b>" веб-сайтына кіріңіз."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Есептік жазбаны тексеруде…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN кодты <xliff:g id="NUMBER_0">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайта әркеттеніңіз."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Кілсөзді <xliff:g id="NUMBER_0">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Бекітпесін ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> қате сыздыңыз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайта әркеттеніңіз."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефон бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді есептік жазба арқылы ашу өтінішін аласыз.\n\n  <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Алып тастау"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN коды дұрыс емес, құрылғыны ашу үшін қызмет жабдықтаушыға  хабарласаңыз."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN коды дұрыс емес, құрылғыны жабу өтінішімен жабдықтаушыға хабарласуға дейін <xliff:g id="NUMBER">%d</xliff:g> рет әрекеттену мүмкіндігіңіз бар."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN коды дұрыс емес, <xliff:g id="NUMBER">%d</xliff:g> рет әрекеттену мүмкіндігіңіз қалды."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN коды дұрыс емес, <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
+      <item quantity="one">SIM PIN коды дұрыс емес, операторға құрылғы бекітпесін ашуы үшін хабарласуға дейін <xliff:g id="NUMBER_0">%d</xliff:g> әрекет қалды.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM қолданыстан шыққан. Қызмет жабдықтаушыға хабарласыңыз."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PIN коды дұрыс емес, <xliff:g id="NUMBER">%d</xliff:g> әрекеттен кейін SIM қолданыстан мүлдем шығады."</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK коды дұрыс емес, <xliff:g id="NUMBER">%d</xliff:g> әрекеттен кейін SIM қолданыстан мүлдем шығады."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK коды дұрыс емес, SIM біржола пайдалануға жарамсыз болуына <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
+      <item quantity="one">SIM PUK коды дұрыс емес, SIM біржола пайдалануға жарамсыз болуына <xliff:g id="NUMBER_0">%d</xliff:g> әрекет қалды.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN жұмысы орындалмады!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK жұмысы орындалмады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код қабылданды!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Алдыңғы жол түймесі"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Келесі жол түймесі"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кідірту түймесі"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Ойнату түймесі"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Тоқтату түймесі"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Қызмет көрсетілмейді."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index f4a73a8..be72fd6 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"បញ្ចូល​ពាក្យ​សម្ងាត់​ ​ដើម្បី​ដោះ​សោ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"បញ្ចូល​កូដ PIN ដើម្បី​ដោះ​សោ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"កូដ PIN មិន​ត្រឹមត្រូវ។"</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_plugged_in" msgid="9087497435553252863">"កំពុង​បញ្ចូល​ថ្ម"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"ភ្ជាប់​ឧបករណ៍​បញ្ចូល​ថ្ម​។"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ស៊ីម​កាត​​ជាប់​សោ។"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ស៊ីម​កាត​ជាប់​កូដ​​ PUK ។"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"កំពុង​ដោះ​សោ​ស៊ីម​កាត..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ធាតុ​ក្រាហ្វិក %2$d នៃ %3$d ។"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"បន្ថែម​ធាតុ​ក្រាហ្វិក​។"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ទទេ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"បាន​ពង្រីក​ផ្ទៃ​ដោះ​សោ។"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"បាន​បង្រួម​ផ្ទៃ​ដោះ​សោ។"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ធាតុ​ក្រាហ្វិក។"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ឧបករណ៍​ជ្រើស​អ្នក​ប្រើ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ម៉ាស៊ីន​ថត"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ពិនិត្យ​មេឌៀ"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"បាន​ចាប់ផ្ដើម​តម្រៀប​ធាតុ​ក្រាហ្វិក​ឡើងវិញ។"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"បាន​បញ្ចប់​ការ​បង្ហាញ​ធាតុ​ក្រាហ្វិក។"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"បាន​លុប​ធាតុ​ក្រាហ្វិក <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ។"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ពង្រីក​តំបន់​ដោះ​សោ។"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"រុញ​ដោះ​សោ។"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"លំនាំ​ដោះ​សោ​។"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ដោះ​សោ​តាម​​ទម្រង់​មុខ។"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"កូដ PIN ដោះ​សោ។"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"ប្រអប់លេខសម្ងាត់"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ប្រអប់លេខសម្ងាត់ស៊ីម"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ប្រអប់ PUK ស៊ីម"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ប៊ូតុង​បទ​មុន"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ប៊ូតុង​បទ​បន្ទាប់"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ប៊ូតុង​ផ្អាក"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ប៊ូតុង​ចាក់"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ប៊ូតុង​បញ្ឈប់"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"មេដៃ​ឡើង"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"មេដៃ​ចុះ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"បេះដូង"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ដោះ​សោ ​ដើម្បី​បន្ត"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"បាន​បោះបង់​ការ​ចាប់ផ្ដើម"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ទម្លាក់ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ដើម្បី​លុប។"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> នឹង​មិន​ត្រូវ​បាន​លុប​។"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"ការ​ជូន​ដំណឹង​បន្ទាប់​កំណត់​សម្រាប់ <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូរ​របៀប"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ដោះ​​សោ"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ម៉ាស៊ីន​ថត"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ស្ងាត់"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"បើក​សំឡេង"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"រុញ​ចុះក្រោម​សម្រាប់ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"រុញ​ទៅ​ឆ្វេង​ដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"រុញ​​ទៅ​ស្ដាំ​ដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
-    <string name="user_switched" msgid="3768006783166984410">"អ្នក​ប្រើ​បច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ការ​ហៅ​ពេល​អាសន្ន"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ភ្លេច​​លំនាំ"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"លំនាំ​មិន​ត្រឹមត្រូវ"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"បញ្ចូល​កូដ PUK ម្ដង​ទៀត។ ការ​ព្យាយាម​ដដែល​ច្រើន​ដឹង​នឹង​បិទ​ស៊ីម​កាត​ជា​អចិន្ត្រៃយ៍។"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"កូដ PIN មិន​ដូច​គ្នា"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បី​ដោះ​សោ ចូល​ក្នុង​គណនី Google ។"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះ​អ្នក​ប្រើ (អ៊ីមែល​)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ។"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេច​ឈ្មោះ​អ្នកប្រើ ឬ​ពាក្យ​សម្ងាត់​របស់​អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"កំពុង​ពិនិត្យ​មើល​គណនី..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"អ្នក​បាន​បញ្ចូល​កូដ PIN របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"អ្នក​បាន​បញ្ចូល​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"អ្នក​បាន​​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់របស់អ្នក។"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​មិន​ត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដង​មិន​ជោគជ័យ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម​មិន​ជោគជ័យ​​ច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង អ្នក​នឹង​ត្រូវ​បាន​​ស្នើ​ឲ្យ​ដោះ​សោ​ទូរស័ព្ទ​របស់​អ្នក​ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"លុប​ចេញ"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"លេខ​កូដ PIN ស៊ីម​មិន​ត្រឹមត្រូវ អ្នក​ត្រូវ​ទាក់ទង​ក្រុមហ៊ុន​បញ្ជូន​របស់​អ្នក​ឥឡូវ​នេះ ដើម្បី​ដោះ​សោ​ឧបករណ៍​របស់​អ្នក។"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"លេខ​កូដ PIN ស៊ីម​មិន​​ត្រឹមត្រូវ​, អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅសល់​មុន​ពេល​អ្នក​ត្រូវ​​ទាក់ទង​ក្រុម​ហ៊ុន​​​បញ្ជូន​របស់​អ្នក​​ ដើម្បី​​​ដោះ​សោ​ឧបករណ៍​របស់​អ្នក​។"</item>
-    <item quantity="other" msgid="2215723361575359486">"លេខ​កូដ​ PIN ស៊ីម​មិន​ត្រឹមត្រូវ​, អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅ​​សល់​។"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">លេខកូដសម្ងាត់ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត</item>
+      <item quantity="one">លេខកូដសម្ងាត់ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_0">%d</xliff:g> ដងទៀត មុនពេលពេលដែលអ្នកត្រូវទាក់ទងទៅអ្នកផ្តល់សេវាកម្មរបស់អ្នកដើម្បីដោះសោឧបករណ៍របស់អ្នក។</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"ស៊ីម​មិន​អាច​ប្រើ​បាន។ ទាក់ទង​ក្រុមហ៊ុន​បញ្ជូន​របស់​អ្នក។"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"លេខ​កូដ PUK ស៊ីម​មិន​ត្រឹមត្រូវ, អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅ​សល់ មុន​ពេល​ស៊ីម​​ក្លាយ​ជា​មិន​អាច​ប្រើ​បាន​ជា​អចិន្ត្រៃយ៍​។"</item>
-    <item quantity="other" msgid="5477305226026342036">"លេខ​កូដ PUK ស៊ីម​មិន​ត្រឹមត្រូវ, អ្នក​មាន <xliff:g id="NUMBER">%d</xliff:g> ការ​ព្យាយាម​ដែល​នៅ​សល់ មុន​ពេល​ស៊ីម​​ក្លាយ​ជា​មិន​អាច​ប្រើ​បាន​ជា​អចិន្ត្រៃយ៍​។"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">លេខកូដ PUK ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត មុនពេលស៊ីមរបស់អ្នកមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។</item>
+      <item quantity="one">លេខកូដ PUK ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_0">%d</xliff:g> ដងទៀត មុនពេលស៊ីមរបស់អ្នកមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"បាន​បរាជ័យ​ក្នុង​ការ​ប្រតិបត្តិ​លេខ​កូដ PIN ស៊ីម!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"បាន​បរាជ័យ​ក្នុង​ការ​ប្រតិបត្តិ​​លេខ​កូដ PUK ស៊ីម!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"បាន​ទទួល​យក​លេខ​កូដ​!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ប៊ូតុង​បទ​មុន"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ប៊ូតុង​បទ​បន្ទាប់"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ប៊ូតុង​ផ្អាក"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ប៊ូតុង​ចាក់"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ប៊ូតុង​បញ្ឈប់"</string>
-    <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា"</string>
+    <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា​"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index 6e2b4d0..cfa1ac0 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಿನ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
     <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_plugged_in" msgid="9087497435553252863">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"ನಿಮ್ಮ ಚಾರ್ಜರ್ ಸಂಪರ್ಕಗೊಳಿಸಿ."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಅನ್ನು PUK-ಲಾಕ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s.%3$d ರಲ್ಲಿ %2$d ವಿಜೆಟ್."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ವಿಜೆಟ್ ಸೇರಿಸು."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ಖಾಲಿ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ಅನ್‌ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ಅನ್‌ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ಸಂಕುಚಿಸಲಾಗಿದೆ."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ವಿಜೆಟ್."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ಬಳಕೆದಾರ ಆಯ್ಕೆಗಾರ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ಕ್ಯಾಮರಾ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ಮೀಡಿಯಾ ನಿಯಂತ್ರಣಗಳು"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ವಿಜೆಟ್ ಮರುಕ್ರಮ ಪ್ರಾರಂಭಗೊಂಡಿದೆ."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ವಿಜೆಟ್ ಮರುಕ್ರಮ ಕೊನೆಗೊಂಡಿದೆ."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ವಿಜೆಟ್ ಅಳಿಸಲಾಗಿದೆ."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ಅನ್‌ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ವಿಸ್ತರಿಸು."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ಸ್ಲೈಡ್ ಅನ್‌ಲಾಕ್."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ನಮೂನೆ ಅನ್‌ಲಾಕ್."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ಮುಖದ ಅನ್‌ಲಾಕ್."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ಪಿನ್ ಅನ್‌ಲಾಕ್."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"ಪಿನ್ ಪ್ರದೇಶ"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ಸಿಮ್ ಪಿನ್ ಪ್ರದೇಶ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ಸಿಮ್ PUK ಪ್ರದೇಶ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ಹಿಂದಿನ ಹಾಡಿನ ಬಟನ್"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ಮುಂದಿನ ಹಾಡಿನ ಬಟನ್"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ವಿರಾಮ ಬಟನ್"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ಪ್ಲೇ ಬಟನ್"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ನಿಲ್ಲಿಸು ಬಟನ್"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"ಥಂಬ್ಸ್ ಅಪ್"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ಥಂಬ್ಸ್ ಡೌನ್"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"ಹೃದಯ"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ಮುಂದುವರಿಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ಪ್ರಾರಂಭವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ಅಳಿಸಲು <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ಡ್ರಾಪ್ ಮಾಡಿ."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ಅನ್ನು ಅಳಿಸಲಾಗುವುದಿಲ್ಲ."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> ಗೆ ಮುಂದಿನ ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ರದ್ದುಮಾಡು"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ಅಳಿಸು"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ಮುಗಿದಿದೆ"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ಮೋಡ್ ಬದಲಾವಣೆ"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ನಮೂದಿಸು"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ಅನ್‌ಲಾಕ್"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ಕ್ಯಾಮರಾ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ಶಾಂತ"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ಧ್ವನಿ ಆನ್"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಕೆಳಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಎಡಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಬಲಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
-    <string name="user_switched" msgid="3768006783166984410">"ಪ್ರಸ್ತುತ ಬಳಕೆದಾರರು <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ತುರ್ತು ಕರೆ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಮರೆತಿರುವಿರಿ"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"ತಪ್ಪು ಪ್ಯಾಟರ್ನ್"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ಸರಿಯಾದ PUK ಕೋಡ್ ಅನ್ನು ಮರು-ನಮೂದಿಸಿ. ಸತತ ಪ್ರಯತ್ನಗಳು ಸಿಮ್‌ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ಪಿನ್‌ ಕೋಡ್‍ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ಹಲವಾರು ಪ್ಯಾಟರ್ನ್ ಪ್ರಯತ್ನಗಳು"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"ಅನ್‍ಲಾಕ್ ಮಾಡಲು, ನಿಮ್ಮ Google ಖಾತೆ ಬಳಸಿಕೊಂಡು ಸೈನ್ ಇನ್ ಮಾಡಿ."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ಬಳಕೆದಾರಹೆಸರು (ಇಮೇಲ್)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"ಪಾಸ್‌ವರ್ಡ್"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ಅಮಾನ್ಯ ಬಳಕೆದಾರಹೆಸರು ಅಥವಾ ಪಾಸ್‍ವರ್ಡ್."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ನಿಮ್ಮ ಬಳಕೆದಾರಹೆಸರು ಅಥವಾ ಪಾಸ್‍ವರ್ಡ್ ಮರೆತಿರುವಿರಾ?\n"<b>"google.com/accounts/recovery"</b>" ಗೆ ಭೇಟಿ ನೀಡಿ."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"ಖಾತೆಯನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ನಿಮ್ಮ ಪಿನ್‌ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ನಿಮ್ಮ ಪಾಸ್‍‍ವರ್ಡ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಚಿತ್ರಿಸಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ತೆಗೆದುಹಾಕು"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ಸಿಮ್‌ ಪಿನ್‌ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ ಪಿನ್‌ ಕೋಡ್, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡುವ ಸಲುವಾಗಿ ನಿಮ್ಮ ವಾಹಕವನ್ನು ನೀವು ಸಂಪರ್ಕಿಸುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ."</item>
-    <item quantity="other" msgid="2215723361575359486">"ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ ಪಿನ್‌ ಕೋಡ್, ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">ಸಿಮ್‌ ಪಿನ್ ಕೋಡ್‌ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+      <item quantity="other">ಸಿಮ್‌ ಪಿನ್ ಕೋಡ್‌ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"ಸಿಮ್‌ ನಿಷ್ಪ್ರಯೋಜಕವಾಗಿದೆ. ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ PUK ಕೋಡ್, ಸಿಮ್‌ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನ ಬಾಕಿ ಉಳಿದಿದೆ."</item>
-    <item quantity="other" msgid="5477305226026342036">"ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ PUK ಕೋಡ್, ಸಿಮ್‌ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ PUK ಕೋಡ್‌, ಸಿಮ್‌ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+      <item quantity="other">ತಪ್ಪಾಗಿರುವ ಸಿಮ್‌ PUK ಕೋಡ್‌, ಸಿಮ್‌ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವುದಕ್ಕೂ ಮೊದಲು ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"ಸಿಮ್‌ ಪಿನ್‌ ಕಾರ್ಯಾಚರಣೆ ವಿಫಲಗೊಂಡಿದೆ!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ಸಿಮ್‌ PUK ಕಾರ್ಯಾಚರಣೆ ವಿಫಲಗೊಂಡಿದೆ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ಕೋಡ್ ಅಂಗೀಕೃತವಾಗಿದೆ!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ಹಿಂದಿನ ಹಾಡಿನ ಬಟನ್"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ಮುಂದಿನ ಹಾಡು ಬಟನ್"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ವಿರಾಮ ಬಟನ್"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ಪ್ಲೇ ಬಟನ್"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ನಿಲ್ಲಿಸು ಬಟನ್"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index b60b159..1ef0c19 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"잠금 해제하려면 비밀번호 입력"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"잠금을 해제하려면 PIN 입력"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 코드가 잘못되었습니다."</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_plugged_in" msgid="9087497435553252863">"충전 중"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"충전기를 연결하세요."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 카드가 잠겨 있습니다."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 카드가 PUK 잠김 상태입니다."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM 카드 잠금해제 중..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d의 위젯 %2$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"위젯 추가"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"비어 있음"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"잠금 해제 영역 확장됨"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"잠금 해제 영역 축소됨"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> 위젯"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"사용자 선택기"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"카메라"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"미디어 조정"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"위젯 재정렬 시작됨"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"위젯 재정렬 완료됨"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> 위젯이 삭제됨"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"잠금 해제 영역 확장"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"슬라이드하여 잠금해제합니다."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"패턴을 사용하여 잠금해제합니다."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"얼굴 인식을 사용하여 잠금해제합니다."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"핀을 사용하여 잠금해제합니다."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN 영역"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN 영역"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 영역"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"이전 트랙 버튼"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"다음 트랙 버튼"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"일시중지 버튼"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"재생 버튼"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"중지 버튼"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"좋아요"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"싫어요"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"하트"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"계속하려면 잠금해제합니다."</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"실행 취소됨"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"삭제하려면 <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>을(를) 드롭합니다."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>은(는) 삭제되지 않습니다."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"다음 알람이 <xliff:g id="ALARM">%1$s</xliff:g>(으)로 설정되었습니다."</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 키"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"취소"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 키"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"완료"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"모드 변경"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 키"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 키"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"잠금 해제"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"카메라"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"무음"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"사운드 켜기"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 아래로 슬라이드"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 왼쪽으로 슬라이드"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 오른쪽으로 슬라이드"</string>
-    <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"긴급 통화"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"패턴을 잊음"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"잘못된 패턴"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM을 영구적으로 사용할 수 없게 됩니다."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 코드가 일치하지 않음"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"사용자 이름(이메일)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"비밀번호"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"로그인"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?\n"<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"계정 확인 중…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필이 삭제되며 모든 프로필 데이터가 삭제됩니다."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"삭제"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 코드가 잘못되었습니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER">%d</xliff:g>회 이상 실패할 경우 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER">%d</xliff:g>번의 기회가 남았습니다."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
+      <item quantity="one">SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER_0">%d</xliff:g>번 더 실패하면 이동통신사에 문의하여 기기를 잠금 해제해야 합니다.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM을 사용할 수 없습니다. 이동통신사에 문의하세요."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUK 코드가 잘못되었습니다. <xliff:g id="NUMBER">%d</xliff:g>회 이상 실패할 경우 SIM을 완전히 사용할 수 없습니다."</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK 코드가 잘못되었습니다. <xliff:g id="NUMBER">%d</xliff:g>회 이상 실패할 경우 SIM을 완전히 사용할 수 없습니다."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK 코드가 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다.</item>
+      <item quantity="one">SIM PUK 코드가 잘못되었습니다. <xliff:g id="NUMBER_0">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN 작업이 실패했습니다."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 작업이 실패했습니다."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"코드 승인 완료"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"이전 트랙 버튼"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"다음 트랙 버튼"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"일시중지 버튼"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"재생 버튼"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"중지 버튼"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index f90acb4..430c19a 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -29,9 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Кулпуну ачуу үчүн сырсөздү териңиз"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Кулпуну ачуу үчүн PIN кодду териңиз"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN-код туура эмес."</string>
-    <!-- no translation found for keyguard_label_text (861796461028298424) -->
-    <skip />
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Жүзүнөн таанып ачуу аракеттеринин чегинен аштыңыз"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Дүрмөттөлдү"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Кубатталууда"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Дүрмөттөөчү түзмөктү туташтырыңыз."</string>
@@ -47,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карта бөгөттөлгөн."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-карта PUK-бөгөттө."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-карта бөгөттөн чыгарылууда…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d ичинен %2$d виджет."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Виджет кошуу."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Бош"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Бөгөттөн чыгаруу аймагы жазылды."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Бөгөттөн чыгаруу аймагы жыйрылды."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджети."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Колдонуучуну тандагыч"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Медиа башкаруу"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Виджет иреттөө башталды."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Виджет иреттөө аяктады."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виждети жок кылынды."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Бөгөттөн чыгаруу аймагын кеңейтүү."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Жылмыштырып ачуу."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Үлгү менен ачуу."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Жүзүнөн таануу"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Пин код менен ачуу."</string>
@@ -70,42 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN аймагы"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN аймагы"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK аймагы"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Мурунку трек баскычы"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кийинки трек баскычы"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Тыныгуу баскычы"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Ойнотуу баскычы"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Токтотуу баскычы"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Жакты"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Жаккан жок"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Жүрөк"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Улантыш үчүн бөгөттөн чыгарыңыз"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Жүргүзүү токтотулду"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> жок кылыш үчүн, түшүрүңүз."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> жок кылынбайт."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Кийинки ойготкуч саат <xliff:g id="ALARM">%1$s</xliff:g> коюлган"</string>
-    <!-- no translation found for password_keyboard_label_symbol_key (992280756256536042) -->
-    <skip />
-    <!-- no translation found for password_keyboard_label_alpha_key (8001096175167485649) -->
-    <skip />
-    <!-- no translation found for password_keyboard_label_alt_key (1284820942620288678) -->
-    <skip />
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Айнуу"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жок кылуу"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Даяр"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Тартип алмаштыруу"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Кирүү"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Бөгөттөн чыгаруу"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Үнсүз"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Үн жандырылды"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн төмөн жылмыштырыңыз."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн солго жылмыштырыңыз."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> үчүн оңго жылмыштырыңыз."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Учурдагы колдонуучу <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Куткаруучуларга чалуу"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Үлгү унутулду"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Үлгү туура эмес"</string>
@@ -127,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Туура PUK-кодду кайрадан териңиз. Кайталанган аракеттер SIM-картаны биротоло жараксыз кылат."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коддор туура келбеди"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Өтө көп үлгү киргизүү аракети болду"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Бөгөттөн чыгарыш үчүн, Google эсебиңиз менен кириңиз."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Колдонуучунун аты (эмейл)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Сырсөз"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Кирүү"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Колдонуучу атыңыз же сырсөзүңүз туура эмес."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Колдонуучу атыңызды же сырсөзүңүздү унутуп калдыңызбы?\n"<b>"google.com/accounts/recovery"</b>" дарегине кайрылыңыз."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Эсеп текшерилүүдө…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Сиз PIN-кодуңузду <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Сиз сырсөзүңүздү <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
@@ -151,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефондун кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, планшетиңизди эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, телефонуңузду эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Алып салуу"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-карта PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгарыш үчүн операторуңузга кайрылышыңыз керек."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN-коду туура эмес, сиз түзмөктү бөгөттөн чыгарыш үчүн операторуңузга кайрылганга <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN-коду туура эмес, сизде <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
+      <item quantity="one">SIM PIN-коду туура эмес, сизде <xliff:g id="NUMBER_0">%d</xliff:g> аракет калды. Болбосо, түзмөктүн кулпусун ачуу үчүн операторуңузга кайрылышыңыз керек.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-карта жараксыз. Операторуңузга кайрылыңыз."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUK-коду туура эмес, SIM биротоло жарактан чыгаарына <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK-коду туура эмес, SIM биротоло жарактан чыгаарына <xliff:g id="NUMBER">%d</xliff:g> аракет калды."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK-коду туура эмес, SIM биротоло жарактан чыгаарынан мурун сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
+      <item quantity="one">SIM PUK-коду туура эмес, SIM биротоло жарактан чыгаарынан мурун сизде <xliff:g id="NUMBER_0">%d</xliff:g> аракет калды.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM-картанын PIN-кодун ачуу кыйрады!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-картанын PUK-кодун ачуу кыйрады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код кабыл алынды!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Мурунку трек баскычы"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кийинки трек баскычы"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Тыныгуу баскычы"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Ойнотуу баскычы"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Токтотуу баскычы"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-land/bools.xml b/packages/Keyguard/res/values-land/bools.xml
index a1dd2e4..bedf504 100644
--- a/packages/Keyguard/res/values-land/bools.xml
+++ b/packages/Keyguard/res/values-land/bools.xml
@@ -15,8 +15,5 @@
 -->
 
 <resources>
-    <bool name="kg_enable_camera_default_widget">false</bool>
-    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
-    <bool name="kg_share_status_area">false</bool>
     <bool name="kg_sim_puk_account_full_screen">false</bool>
 </resources>
diff --git a/packages/Keyguard/res/values-land/dimens.xml b/packages/Keyguard/res/values-land/dimens.xml
deleted file mode 100644
index bf30332..0000000
--- a/packages/Keyguard/res/values-land/dimens.xml
+++ /dev/null
@@ -1,40 +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.
-*/
--->
-
-<resources>
-    <!-- Shift emergency button from the left edge by this amount.  Used by landscape layout on
-         phones -->
-    <dimen name="kg_emergency_button_shift">30dp</dimen>
-
-    <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
-    <dimen name="kg_secure_padding_height">0dp</dimen>
-
-    <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
-
-    <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
-
-    <!-- If the height if keyguard drops below this threshold (most likely
-    due to the appearance of the IME), then drop the multiuser selector.
-    Landscape's layout allows this to be smaller than for portrait. -->
-    <dimen name="kg_squashed_layout_threshold">400dp</dimen>
-
-</resources>
diff --git a/packages/Keyguard/res/values-land/integers.xml b/packages/Keyguard/res/values-land/integers.xml
index 020fd23..0739c3a 100644
--- a/packages/Keyguard/res/values-land/integers.xml
+++ b/packages/Keyguard/res/values-land/integers.xml
@@ -20,7 +20,4 @@
     <!-- Gravity to make KeyguardSelectorView work in multiple orientations
         0x13 == "left|center_vertical" -->
     <integer name="kg_selector_gravity">0x13</integer>
-    <integer name="kg_widget_region_weight">45</integer>
-    <integer name="kg_security_flipper_weight">55</integer>
-    <integer name="kg_glowpad_rotation_offset">-90</integer>
 </resources>
diff --git a/packages/Keyguard/res/values-large/dimens.xml b/packages/Keyguard/res/values-large/dimens.xml
deleted file mode 100644
index 0b5d4ad..0000000
--- a/packages/Keyguard/res/values-large/dimens.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-    <!-- Minimum width of the search view text entry area. -->
-    <dimen name="search_view_text_min_width">192dip</dimen>
-
-    <item type="dimen" name="dialog_min_width_major">55%</item>
-    <item type="dimen" name="dialog_min_width_minor">80%</item>
-
-    <!-- Preference UI dimensions for larger screens. -->
-    <dimen name="preference_widget_width">56dp</dimen>
-</resources>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 40f1893..17c1c5b 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ພິມລະຫັດເພື່ອປົດລັອກ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ພິມລະຫັດ PIN ເພື່ອປົດລັອກ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ."</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_plugged_in" msgid="9087497435553252863">"ກຳລັງສາກໄຟ"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"ເຊື່ອມຕໍ່ອຸປະກອນສາກຂອງທ່ານ."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ຊິມກາດຖືກລັອກ."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ຊິມກາດຖືກລັອກດ້ວຍລະຫັດ PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ກຳລັງປົດລັອກຊິມກາດ..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. ວິດເຈັດ %2$d ຈາກທັງໝົດ %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ເພີ່ມວິດເຈັດ"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ຫວ່າງເປົ່າ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ຂະຫຍາຍພື້ນທີ່ປົດລັອກແລ້ວ."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ຫຍໍ້ພື້ນທີ່ປົດລັອກແລ້ວ."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ວິດເຈັດ."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ໂຕເລືອກຂອງຜູ່ໃຊ້"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ກ້ອງ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"ການຄວບຄຸມສື່"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ການຈັດຮຽງວິເຈັດໃໝ່ເລີ່ມຕົ້ນແລ້ວ."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ການຈັດຮຽງວິດເຈັດຄືນໃໝ່ສຳເລັດແລ້ວ."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ລຶບວິດເຈັດ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ແລ້ວ."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ຂະຫຍາຍຂອບເຂດປົດລັອກ."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ການປົດລັອກດ້ວຍການເລື່ອນ."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ປົດລັອກດ້ວຍຮູບແບບ."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ປົດລັອກດ້ວຍໜ້າ."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ປົດລັອກດ້ວຍ PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"ພື້ນ​ທີ່ PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"ພື້ນ​ທີ່ PIN ຂອງ SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"ພື້ນ​ທີ່ PUK ຂອງ SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ປຸ່ມເພງຕໍ່ໄປ"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ປຸ່ມຫຼິ້ນ"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ປຸ່ມຢຸດ"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"ເລື່ອນນິ້ວໂປ້ຂຶ້ນ"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ເລື່ອນນິ້ວໂປ້ລົງ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"ຫົວໃຈ"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ປົດລັອກເພື່ອດຳເນີນການຕໍ່"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ການເປີດໃຊ້ຖືກຍົກເລີກ"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ວາງ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ເພື່ອລຶບ."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ຈະບໍ່ຖືກລຶບອອກ"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"​ໂມງ​ປຸກ​ຕໍ່​ໄປ​ຖືກ​ຕັ້ງ​ໄວ້​ເວ​ລາ <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ຍົກເລີກ"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ລຶບ"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ແລ້ວໆ"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ປ່ຽນຮູບແບບ"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ປົດລັອກ"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ກ້ອງ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ປິດສຽງ"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ເປີດສຽງ"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"ເລື່ອນລົງເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"ເລື່ອນໄປທາງຊ້າຍເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"ເລື່ອນໄປທາງຂວາເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ການໂທສຸກເສີນ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ລືມຮູບແບບປົດລັອກ?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"ຮູບແບບຜິດ"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"ເພື່ອປົດລັອກ, ເຂົ້າສູ່ລະບົບດ້ວຍບັນຊີ Google ຂອງທ່ານ."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ຊື່ຜູ່ໃຊ້ (ອີເມວ)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"ລະຫັດຜ່ານ"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ເຂົ້າສູ່ລະບົບ"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ລືມຊື່ຜູ່ໃຊ້ ຫຼືລະຫັດຜ່ານຂອງທ່ານບໍ່?\nໄປທີ່ "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"ກຳລັງກວດສອບບັນຊີ..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ທ່ານພິມລະຫັດ PIN​ ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ທ່ານພິມລະຫັດຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ທ່ານ​ພະ​ຍາ​ຍາມ​ປົດ​ລ​ັອກ​ໂທ​ລະ​ສັບ​ບໍ່​ຖືກ​ຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປ​ຣ​ໄຟ​ລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຈະ​ຖືກ​ເອົາ​ອອກ​ໄປ, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນ​ໂປ​ຣ​ໄຟ​ລ໌."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ລຶບອອກ"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງທ່ານຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອກ່ອນທີ່ທ່ານຈະຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການຂອງທ່ານ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</item>
-    <item quantity="other" msgid="2215723361575359486">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ, ທ່ານຍັງພະຍາຍາມໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ.</item>
+      <item quantity="one">ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ທ່ານຈະຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການຂອງທ່ານ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM ໃຊ້ບໍ່ໄດ້ແລ້ວ. ກະລຸນາຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການຂອງທ່ານ."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ລະຫັດ PUK ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະໃຊ້ບໍ່ໄດ້ຢ່າງຖາວອນ."</item>
-    <item quantity="other" msgid="5477305226026342036">"ລະຫັດ PUK ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະໃຊ້ບໍ່ໄດ້ຢ່າງຖາວອນ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">ລະຫັດ PUK ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະໃຊ້ບໍ່ໄດ້ຢ່າງຖາວອນ.</item>
+      <item quantity="one">ລະຫັດ PUK ຂອງ SIM ບໍ່ຖືກຕ້ອງ, ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຂອງທ່ານຈະໃຊ້ບໍ່ໄດ້ຢ່າງຖາວອນ.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"PIN ຂອງ SIM ເຮັດວຽກລົ້ມເຫຼວ!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK ຂອງ SIM ເຮັດວຽກລົ້ມເຫຼວ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ລະ​ຫັດ​ຖືກຕອບຮັບແລ້ວ!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ປຸ່ມເພງກ່ອນໜ້າ"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ປຸ່ມເພງຕໍ່ໄປ"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ປຸ່ມຢຸດຊົ່ວຄາວ"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ປຸ່ມຫຼິ້ນ"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ປຸ່ມຢຸດ"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index eb9c910..6d7dcc7 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Jei norite atrakinti, įveskite slaptažodį"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Jei norite atrakinti, įveskite PIN kodą"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Neteisingas PIN kodas."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Jei norite atrakinti, paspauskite „Meniu“ ir 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Viršijote maksimalų atrakinimo pagal veidą bandymų skaičių"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Įkrauta"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Kraunama"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Prijunkite įkroviklį."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kortelė užrakinta."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kortelė užrakinta PUK kodu."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Atrakinama SIM kortelė…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d valdiklis iš %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pridėti valdiklį."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tuščia"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Atrakinimo sritis išplėsta."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Atrakinimo sritis sutraukta."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Valdiklis <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Naudotojo pasirinkimo valdiklis"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparatas"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medijos valdikliai"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Valdiklių pertvarkymas pradėtas."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Valdiklių pertvarkymas baigtas."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Valdiklis <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ištrintas."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Išplėsti atrakinimo sritį."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Atrakinimas slystant."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Atrakinimas pagal piešinį."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Atrakinimas pagal veidą."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Atrakinimas įvedus PIN kodą."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kodo sritis"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM kortelės PIN kodo sritis"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM kortelės PUK kodo sritis"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Ankstesnio takelio mygtukas"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kito takelio mygtukas"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pristabdymo mygtukas"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Paleidimo mygtukas"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Sustabdymo mygtukas"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Patinka"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nepatinka"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Širdis"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Jei norite tęsti, atrakinkite"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Paleidimas atšauktas"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Paleiskite „<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>“, kad jį ištrintumėte."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"„<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>“ nebus ištrintas."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Kitas nustatytas signalas: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atšaukti"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ištrinti"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Atlikta"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režimo keitimas"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Įvesti"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Atrakinti"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Vaizdo kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Begarsis"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Garsas įjungtas"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Slyskite žemyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Slyskite į kairę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Slyskite į dešinę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Skambutis pagalbos numeriu"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pamiršau atrakinimo piešinį"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Netinkamas atrakinimo piešinys"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Jei norite atrakinti, prisijunkite naudodami „Google“ paskyrą."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Naudotojo vardas (el. paštas)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Slaptažodis"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prisijungti"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Netinkamas naudotojo vardas ar slaptažodis."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Pamiršote naudotojo vardą ar slaptažodį?\nApsilankykite šiuo adresu: "<b>"google.com/accounts/recovery"</b></string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tikrinama paskyra…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netinkamas SIM kortelės PIN kodas. Reikės susisiekti su operatoriumi, kad atrakintų įrenginį."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Netinkamas SIM kortelės PIN kodas. Jums liko <xliff:g id="NUMBER">%d</xliff:g> band. Paskui reikės susisiekti su operatoriumi, kad jis atrakintų įrenginį."</item>
-    <item quantity="other" msgid="2215723361575359486">"Netinkamas SIM kortelės PIN kodas, liko <xliff:g id="NUMBER">%d</xliff:g> band."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
+      <item quantity="few">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymai.</item>
+      <item quantity="many">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymo.</item>
+      <item quantity="other">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymų.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Nebegalima naudoti SIM kortelės. Susisiekite su operatoriumi."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER">%d</xliff:g> band. Paskui visiškai nebegalėsite naudoti SIM kortelės."</item>
-    <item quantity="other" msgid="5477305226026342036">"Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER">%d</xliff:g> band. Paskui visiškai nebegalėsite naudoti SIM kortelės."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas. Tada nebegalėsite naudotis SIM kortele.</item>
+      <item quantity="few">Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymai. Tada nebegalėsite naudotis SIM kortele.</item>
+      <item quantity="many">Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymo. Tada nebegalėsite naudotis SIM kortele.</item>
+      <item quantity="other">Netinkamas SIM kortelės PUK kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymų. Tada nebegalėsite naudotis SIM kortele.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Nepavyko atlikti SIM kortelės PIN kodo operacijos."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nepavyko atlikti SIM kortelės PUK kodo operacijos."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodas priimtas."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Ankstesnio takelio mygtukas"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Kito takelio mygtukas"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pristabdymo mygtukas"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Paleidimo mygtukas"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Sustabdymo mygtukas"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nėra paslaugos."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 920a141..e1da889 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ievadiet paroli, lai atbloķētu."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Lai atbloķētu, ievadiet PIN."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kods nav pareizs."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Lai atbloķētu, nospiediet Izvēlne, pēc tam 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ir pārsniegts maksimālais Autorizācijas pēc sejas mēģinājumu skaits."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Uzlādēts"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Notiek uzlāde"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Pievienojiet uzlādes ierīci."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM karte ir bloķēta."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM karte ir bloķēta ar PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Notiek SIM kartes atbloķēšana..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %2$d. logrīks no %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pievienot logrīku."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tukšs"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Atbloķēšanas apgabals ir izvērsts."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Atbloķēšanas apgabals ir sakļauts."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Logrīks <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Lietotāju atlasītājs"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multivides vadīklas"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Logrīku pārkārtošana ir sākta."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Logrīku pārkārtošana ir pabeigta."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Logrīks <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ir izdzēsts."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Izvērst atbloķēšanas apgabalu."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Autorizācija, velkot ar pirkstu."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Autorizācija ar kombināciju."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Autorizācija pēc sejas."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Autorizācija ar PIN kodu."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN apgabals"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN apgabals"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK apgabals"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Iepriekšējā ieraksta poga"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nākamā ieraksta poga"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pārtraukšanas poga"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Atskaņošanas poga"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Apturēšanas poga"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Patīk"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nepatīk"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Sirds"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Atbloķējiet, lai turpinātu."</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Palaišana atcelta"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Velciet logrīku <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>, lai to izdzēstu."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Logrīks <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> netiks izdzēsts."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Signāls iestatīts uz: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alternēšanas taustiņš"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atcelt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Dzēšanas taustiņš"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gatavs"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Režīma maiņa"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Pārslēgšanas taustiņš"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ievadīšanas taustiņš"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Atbloķēt"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Klusums"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Skaņa ieslēgta"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Velciet uz leju, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Velciet pa kreisi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Velciet pa labi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Ārkārtas izsaukums"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Aizmirsu kombināciju"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nepareiza kombinācija"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodi neatbilst."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Lai atbloķētu, pierakstieties, izmantojot savu Google kontu."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Lietotājvārds (e-pasts)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parole"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Pierakstīties"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nederīgs lietotājvārds vai parole."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vai aizmirsāt lietotājvārdu vai paroli?\nApmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Notiek konta pārbaude…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
@@ -147,24 +94,21 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nepareizs SIM kartes PIN kods. Lai atbloķētu ierīci, sazinieties ar mobilo sakaru operatoru."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi. Kļūdas gadījumā būs jāsazinās ar mobilo sakaru operatoru, lai tas atbloķētu jūsu ierīci."</item>
-    <item quantity="other" msgid="2215723361575359486">"Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi(-es)."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="zero">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
+      <item quantity="one">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizi.</item>
+      <item quantity="other">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM karte nav izmantojama. Sazinieties ar mobilo sakaru operatoru."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Nepareizs SIM kartes PUK kods. Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi. Kļūdas gadījumā SIM karte kļūs neizmantojama."</item>
-    <item quantity="other" msgid="5477305226026342036">"Nepareizs SIM kartes PUK kods. Varat mēģināt vēl <xliff:g id="NUMBER">%d</xliff:g> reizi(-es). Kļūdas gadījumā SIM karte kļūs neizmantojama."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="zero">Nepareizs SIM kartes PUK kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes. Pēdējā mēģinājuma kļūdas gadījumā SIM karte kļūs neizmantojama.</item>
+      <item quantity="one">Nepareizs SIM kartes PUK kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizi. Pēdējā mēģinājuma kļūdas gadījumā SIM karte kļūs neizmantojama.</item>
+      <item quantity="other">Nepareizs SIM kartes PUK kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes. Pēdējā mēģinājuma kļūdas gadījumā SIM karte kļūs neizmantojama.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM kartes PIN koda ievadīšana neizdevās."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM kartes PUK koda ievadīšana neizdevās."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kods ir pieņemts!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Iepriekšējā ieraksta poga"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nākamā ieraksta poga"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pārtraukšanas poga"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Atskaņošanas poga"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Apturēšanas poga"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nav pakalpojuma."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index a94503b..717671b 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Впишете ја лозинката за да се отклучи"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Впишете ПИН за да се отклучи"</string>
     <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_plugged_in" msgid="9087497435553252863">"Се полни"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Поврзи го полначот."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"СИМ картичката е заклучена."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"СИМ картичката е заклучена со ПУК."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"СИМ картичката се отклучува..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виџет %2$d од %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Додај виџет."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Празно"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Областа за отклучување е проширена."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Областа за отклучување е собрана."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Избирач на корисник"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Фотоапарат"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроли на медиуми"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Прередувањето виџети започна."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Прередувањето виџети заврши."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Виџетот <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> е избришан."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Прошири отклучена област."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Отклучување со лизгање."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Отклучување со шема."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Отклучување со лик."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Отклучување со пин."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Поле за ПИН"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Поле за ПИН на СИМ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Поле за ПУК на СИМ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Копче „Претходна песна“"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Копче „Следна песна“"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Копче „Пауза“"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Копче „Репродукција“"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Копче „Запри“"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Палци нагоре"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Палци надолу"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Срце"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Отклучи за да продолжиш"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Стартувањето е откажано"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Пушти го <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> да се избрише."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> нема да се избрише."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Следниот аларм е поставен за <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Копче „Alt“"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Копче „Откажи“"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Копче „Избриши“"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Копче „Готово“"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Копче „Промени режим“"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Копче „Shift“"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Копче „Внеси“"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Отклучи"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Фотоапарат"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"На тивко"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Вклучи звук"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Лизгај надолу за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Лизгај налево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Лизгај надесно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Тековен корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Итен повик"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборавив шема"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешна шема"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно внесете го точниот ПУК код. Повторните обиди трајно ќе ја оневозможат СИМ картичката."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовите не се совпаѓаат"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Премногу обиди со шема"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"За да го отклучите, пријавете се со вашата сметка на Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (е-пошта)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави се"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважечко корисничко име или лозинка."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Го заборави своето корисничко име или лозинката?\nПосети"<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Сметката се проверува..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Погрешно сте го впишале вашиот ПИН <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Погрешно сте ја впишале вашата лозинка <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Погрешно сте ја употребиле вашата шема за отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите таблетот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Отстрани"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ПИН кодот за СИМ картичката е неточен. Контактирате со вашиот оператор да го отклучи уредот."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ПИН кодот за СИМ картичката е неточен. Ви преостанува уште <xliff:g id="NUMBER">%d</xliff:g> обид, а потоа ќе треба да контактирате со вашиот оператор да го отклучи уредот."</item>
-    <item quantity="other" msgid="2215723361575359486">"ПИН кодот за СИМ картичката е неточен. Ви преостануваат уште <xliff:g id="NUMBER">%d</xliff:g> обиди."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Погрешен ПИН-код за СИМ, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
+      <item quantity="other">Погрешен ПИН-код за СИМ, ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обиди.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"СМС картичката е неупотреблива. Контактирајте со вашиот оператор."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ПУК кодот за СИМ картичката е неточен. Ви преостанува уште <xliff:g id="NUMBER">%d</xliff:g> обид, а потоа СИМ картичката ќе стане трајно неупотреблива."</item>
-    <item quantity="other" msgid="5477305226026342036">"ПУК кодот за СИМ картичката е неточен. Ви преостануваат уште <xliff:g id="NUMBER">%d</xliff:g> обиди, а потоа СИМ картичката ќе стане трајно неупотреблива."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Погрешен ПУК-код за СИМ, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид пред СИМ-картичката да стане трајно неупотреблива.</item>
+      <item quantity="other">Погрешен ПУК-код за СИМ, ви преостануваат уште <xliff:g id="NUMBER_1">%d</xliff:g> обиди пред СИМ-картичката да стане трајно неупотреблива.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"СИМ картичката не се отклучи со ПИН кодот!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ картичката не се отклучи со ПУК кодот!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодот е прифатен!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Копче „Претходна песна“"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Копче „Следна песна“"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Копче „Пауза“"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Копче „Репродукција“"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Копче „Запри“"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нема услуга."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index 20c73a3..f39a6b7 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"അൺലോക്കുചെയ്യുന്നതിന് പാസ്‌വേഡ് ടൈപ്പുചെയ്യുക"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"അൺലോക്കുചെയ്യുന്നതിന് പിൻ ടൈപ്പുചെയ്യുക"</string>
     <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_plugged_in" msgid="9087497435553252863">"ചാർജ്ജുചെയ്യുന്നു"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"നിങ്ങളുടെ ചാർജ്ജർ കണക്റ്റുചെയ്യുക."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"സിം കാർഡ് ലോക്കുചെയ്‌തു."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"സിം കാർഡ് PUK-ലോക്ക് ചെയ്‌തതാണ്."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"സിം കാർഡ് അൺലോക്കുചെയ്യുന്നു…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. വിജറ്റ് %2$d / %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"വിജറ്റ് ചേർക്കുക."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ശൂന്യം"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"അൺലോക്ക് ഏരിയ വിപുലീകരിച്ചു."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"അൺലോക്ക് ഏരിയ ചുരുക്കി."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> വിജറ്റ്."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ഉപയോക്തൃ സെലക്‌ടർ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ക്യാമറ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"മീഡിയ നിയന്ത്രണങ്ങൾ"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"വിജറ്റ് പുനഃക്രമീകരണം ആരംഭിച്ചു."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"വിജറ്റ് പുനഃക്രമീകരണം അവസാനിച്ചു."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"വിജറ്റ് <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ഇല്ലാതാക്കി."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"അൺലോക്ക് ഏരിയ വിപുലീകരിക്കുക."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"സ്ലൈഡ് അൺലോക്ക്."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"പാറ്റേൺ അൺലോക്ക്."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക്."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"പിൻ അൺലോക്ക്."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN ഏരിയ"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN ഏരിയ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK ഏരിയ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"മുമ്പത്തെ ട്രാക്ക് ബട്ടൺ"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"പുതിയ ട്രാക്ക് ബട്ടൺ"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"താൽക്കാലികമായി നിർത്തുക ബട്ടൺ"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"പ്ലേ ബട്ടൺ"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"നിർത്തുക ബട്ടൺ"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"തംബ്‌സ് അപ്പ്"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"തംബ്‌സ് ഡൗൺ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"ഹൃദയം"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"തുടരാൻ അൺലോക്കുചെയ്യുക"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"സമാരംഭിക്കൽ റദ്ദാക്കി."</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ഇല്ലാതാക്കാൻ ഡ്രോപ്പുചെയ്യുക."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ഇല്ലാതാക്കില്ല."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g>-ന് അടുത്ത അലാറം സജ്ജീകരിച്ചു"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"റദ്ദാക്കുക"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ഇല്ലാതാക്കുക"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"പൂർത്തിയായി"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"മോഡ് മാറ്റം"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"അണ്‍ലോക്ക് ചെയ്യുക"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ക്യാമറ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"നിശബ്‌ദം"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ശബ്ദം ഓണ്‍ ചെയ്യുക"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായ് താഴേക്ക് സ്ലൈഡുചെയ്യുക."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി ഇടത്തേയ്‌ക്ക് സ്ലൈഡുചെയ്യുക."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി വലത്തേയ്‌ക്ക് സ്ലൈഡുചെയ്യുക."</string>
-    <string name="user_switched" msgid="3768006783166984410">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="NAME">%1$s</xliff:g> ആണ്."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"അടിയന്തര കോൾ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"പാറ്റേൺ മറന്നു"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"പാറ്റേൺ തെറ്റാണ്"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ശരിയായ PUK കോഡ് വീണ്ടും നൽകുക. ആവർത്തിച്ചുള്ള ശ്രമങ്ങൾ സിം ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കും."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"വളരെയധികം പാറ്റേൺ ശ്രമങ്ങൾ"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"അൺലോക്കുചെയ്യുന്നതിന്, നിങ്ങളുടെ Google അക്കൗണ്ട് ഉപയോഗിച്ച് സൈൻ ഇൻ ചെയ്യുക."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ഉപയോക്തൃനാമം (ഇമെയിൽ)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"പാസ്‌വേഡ്"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"സൈൻ ഇൻ ചെയ്യുക"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ഉപയോക്തൃനാമമോ പാസ്‌വേഡോ അസാധുവാണ്."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"നിങ്ങളുടെ ഉപയോക്തൃനാമമോ പാസ്‌വേഡോ മറന്നുപോയോ?\n"<b>"google.com/accounts/recovery"</b>" സന്ദർശിക്കുക."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"അക്കൗണ്ട് പരിശോധിക്കുന്നു…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"നിങ്ങളുടെ പിൻ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"നിങ്ങളുടെ പാസ്‌വേഡ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"നിങ്ങളുടെ പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"നീക്കംചെയ്യുക"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇപ്പോൾ നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"തെറ്റായ സിം പിൻ കോഡ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ സേവനദാതാവുമായി ബന്ധപ്പെടുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമം കൂടി ബാക്കിയുണ്ട്."</item>
-    <item quantity="other" msgid="2215723361575359486">"തെറ്റായ സിം പിൻ കോഡ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ബാക്കിയുണ്ട്."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN കോഡ് തെറ്റാണ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
+      <item quantity="one">SIM PIN കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ കാരിയറെ ബന്ധപ്പെടേണ്ടതിന് മുമ്പായി <xliff:g id="NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"സിം ഉപയോഗശൂന്യമാണ്. നിങ്ങളുടെ കാരിയറെ ബന്ധപ്പെടുക."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"തെറ്റായ സിം PUK കോഡ്, സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമം കൂടി ബാക്കിയുണ്ട്."</item>
-    <item quantity="other" msgid="5477305226026342036">"തെറ്റായ സിം PUK കോഡ്, സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ബാക്കിയുണ്ട്."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK കോഡ് തെറ്റാണ്, SIM ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
+      <item quantity="one">SIM PUK കോഡ് തെറ്റാണ്, SIM ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി നിങ്ങൾക്ക് <xliff:g id="NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"സിം പിൻ പ്രവർത്തനം പരാജയപ്പെട്ടു!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"സിം PUK പ്രവർത്തനം പരാജയപ്പെട്ടു!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"കോഡ് അംഗികരിച്ചു!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"മുമ്പത്തെ ട്രാക്ക് ബട്ടൺ"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"പുതിയ ട്രാക്ക് ബട്ടൺ"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"താൽക്കാലികമായി നിർത്തുക ബട്ടൺ"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"പ്ലേ ബട്ടൺ"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"നിർത്തുക ബട്ടൺ"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"സേവനമൊന്നുമില്ല."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index f2d6f8c..2f24901 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Тайлах нууц үгийг бичнэ үү"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Тайлах PIN-г оруулна уу"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Буруу PIN код."</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_plugged_in" msgid="9087497435553252863">"Цэнэглэж байна"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Цэнэглэгчээ холбоно уу."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM карт түгжигдсэн."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картны PUK-түгжигдсэн."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM картны түгжээг гаргаж байна…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d. -н %2$d виджет"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Виджет нэмэх."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Хоосон"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Тайлах хэсэг нээгдсэн."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Тайлах хэсэг хаагдсан."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Хэрэглэгч сонгоч"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камер"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Медиа контрол"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Виджет дахин эрэмбэлж эхлэв."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Виджетийг дахин эрэмбэлж дуусав."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> виджет устсан."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Түгжээгүй хэсгийг өргөсгөх."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Тайлах гулсуулалт."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Тайлах хээ."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Нүүрээр тайлах"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Тайлах пин."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN талбар"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN талбар"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK талбар"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Өмнөх бичлэг товч"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Дараагийн бичлэг товч"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Түр зогсоох товч"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Тоглуулах товч"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Зогсоох товч"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Сайн"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Онцгүй"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Зүрх"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Үргэлжлүүлэхийн тулд түгжээг тайлна уу"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Эхлүүлэхийг цуцалсан"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Устгахын тулд <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-г тавина уу."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> устахгүй."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Дараагийн сэрүүлгийг <xliff:g id="ALARM">%1$s</xliff:g>-д тохируулсан"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Цуцлах"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Устгах"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Дуусгах"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Горим өөрчлөх"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Шифт"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Оруулах"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Тайлах"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камер"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Чимээгүй"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Дуунууд идэвхтэй"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол доош гулсуулах."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх зүүнлүү гулсуулах."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> хийх бол баруунлуу гулсуулах."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Яаралтай дуудлага"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Хээг мартсан"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Буруу хээ"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Зөв PUK кодыг дахин оруулна уу. Давтан оролдвол SIM нь бүрмөсөн идэвхгүй болгоно."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодууд таарахгүй байна"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Хээ оруулах оролдлого хэт олон"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Түгжээг тайлах бол Google акаунтаараа нэвтэрнэ үү."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Хэрэглэгчийн нэр (имэйл)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Нууц үг"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Нэвтрэх"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Хэрэглэгчийн нэр эсвэл нууц үг буруу."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Хэрэглэгчийн нэр нууц үгээ мартсан уу?\n"<b>"google.com/accounts/recovery"</b>"-д зочилно уу."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Акаунт шалгаж байна…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Ажлын профайл устгагдаж, улмаар профайлын бүх мэдээлэл устах болно."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл акаунт шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"СИМ ПИН код буруу, та төхөөрөмжийн түгжээг тайлахын тулд оператор компанитай холбоо барих шаардлагатай."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"СИМ ПИН код буруу байна, танд мобайл оператор компанитай холбогдохгүйгээр төхөөрөмжийн түгжээг тайлахад <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдсэн байна."</item>
-    <item quantity="other" msgid="2215723361575359486">"СИМ ПИН код буруу байна, танд <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдлээ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">СИМ-ны ПИН код буруу байна. Та <xliff:g id="NUMBER_1">%d</xliff:g> удаа оролдлого хийх боломжтой байна.</item>
+      <item quantity="one">СИМ-ны ПИН код буруу байна. Танд мобайл оператортойгоо холбогдохгүйгээр төхөөрөмжийн түгжээг тайлахад <xliff:g id="NUMBER_0">%d</xliff:g> оролдлого хийх боломж үлдсэн байна.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"СИМ ашиглах боломжгүй. Өөрийн оператор компанитай холбоо барина уу."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"СИМ ПҮК код буруу, таны СИМ бүрмөсөн ашиглалтгүй болохоос өмнө <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдлээ."</item>
-    <item quantity="other" msgid="5477305226026342036">"СИМ ПҮК код буруу, таны СИМ бүрмөсөн ашиглалтгүй болохоос өмнө <xliff:g id="NUMBER">%d</xliff:g> оролдлого хийх боломж үлдлээ."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">]СИМ-ны PUK код буруу байна. Таны СИМ хаагдах хүртэл төхөөрөмжийн түгжээг тайлахад <xliff:g id="NUMBER_1">%d</xliff:g> .оролдлого хийх боломж үлдсэн байна.</item>
+      <item quantity="one">СИМ-ны PUK код буруу байна. Таны СИМ хаагдах хүртэл төхөөрөмжийн түгжээг тайлахад <xliff:g id="NUMBER_0">%d</xliff:g> оролдлого хийх боломж үлдсэн байна.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"СИМ ПИН ажиллуулах амжилтгүй боллоо!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ ПҮК ажиллуулах амжилтгүй боллоо!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код зөвшөөрөгдлөө!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Өмнөх дуу товч"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Дараагийн дуу товч"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Түр зогсох товч"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Тоглуулах товч"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Зогсоох товч"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index 47b6ebb..a86bf60 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करण्यासाठी पिन टाइप करा"</string>
     <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_plugged_in" msgid="9087497435553252863">"चार्ज होत आहे"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"आपले चार्जर कनेक्ट करा."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"सिम कार्ड लॉक झाले आहे."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"सिम कार्ड PUK-लॉक केलेले आहे."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"सिम कार्ड अनलॉक करत आहे…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d पैकी %2$d विजेट."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट जोडा."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"रिक्त"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"अनलॉक क्षेत्र विस्‍तृत केले."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"अनलॉक क्षेत्र संकुचित केले."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> विजेट."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"वापरकर्ता निवडकर्ता"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"कॅमेरा"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मीडिया नियंत्रणे"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"विजेट पुनर्क्रमित करणे प्रारंभ झाले."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट पुनर्क्रमित करणे समाप्त झाले."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> हटविले."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलॉक क्षेत्र विस्तृत करा."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्‍लाइड अनलॉक."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"नमुना अनलॉक."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"चेहरा अनलॉक."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"पिन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"सिम पिन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"सिम PUK क्षेत्र"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"मागील ट्रॅक बटण"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"पुढील ट्रॅक बटण"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"विराम बटण"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"प्ले बटण"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"थांबवा बटण"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"उत्तम"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"वाईट"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"हृदय"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"सुरु ठेवण्‍यासाठी अनलॉक करा"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"लाँच रद्द केले"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"हटविण्‍यासाठी <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ड्रॉप करा."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> हटविली जाणार नाही."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"पुढील अलार्म <xliff:g id="ALARM">%1$s</xliff:g> साठी सेट केला"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द करा"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटवा"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण झाले"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"मोड बदल"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"प्रविष्ट करा"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"अनलॉक करा"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"कॅमेरा"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"मूक"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ध्वनी सुरु"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी खाली स्लाइड करा."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी डावीकडे स्लाइड करा."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी उजवीकडे स्लाइड करा."</string>
-    <string name="user_switched" msgid="3768006783166984410">"वर्तमान वापरकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"आणीबाणीचा कॉल"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"नमुना विसरलात"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"चुकीचा नमुना"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"योग्य PUK कोड पुन्हा-प्रविष्ट करा. परत प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड जुळत नाहीत"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बरेच नमुना प्रयत्न"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करण्यासाठी, आपल्या Google खात्यासह साइन इन करा."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"वापरकर्तानाव (ईमेल)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"संकेतशब्द"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करा"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"अवैध वापरकर्तानाव किंवा संकेतशब्द."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"आपले वापरकर्तानाव किंवा संकेतशब्द विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते तपासत आहे…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने काढला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"काढा"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"सिम पिन कोड चुकीचा आहे आपण आता आपले डिव्‍हाइस अनलॉक करण्‍यासाठी आपल्‍या वाहकाशी संपर्क साधावा."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"सिम पिन कोड चुकीचा आहे, आपण आपले डिव्‍हाइस अनलॉक करण्‍यासाठी आपल्‍या वाहकाशी संपर्क साधण्‍यापूर्वी आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहेत."</item>
-    <item quantity="other" msgid="2215723361575359486">"सिम पिन कोड चुकीचा आहे, आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहेत."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">सिम पिन चुकीचा आहे, आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहे.</item>
+      <item quantity="other">सिम पिन चुकीचा आहे, आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहेत.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"सिम निरुपयोगी आहे. आपल्या वाहकाशी संपर्क साधा."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"सिम PUK कोड चुकीचा आहे, सिम कायमचे निरूपयोगी होण्‍यापूर्वी आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहे."</item>
-    <item quantity="other" msgid="5477305226026342036">"सिम PUK कोड चुकीचा आहे, सिम कायमचे निरूपयोगी होण्‍यापूर्वी आपल्‍याकडे <xliff:g id="NUMBER">%d</xliff:g> प्रयत्न उर्वरित आहेत."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">सिम PUK कोड चुकीचा आहे, सिम कायमचे निरूपयोगी होण्यापूर्वी आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहे.</item>
+      <item quantity="other">सिम PUK कोड चुकीचा आहे, सिम कायमचे निरूपयोगी होण्यापूर्वी आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहेत.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"सिम पिन कार्य अयशस्‍वी झाले!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK कार्य अयशस्‍वी झाले!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्‍वीकारला!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"मागील ट्रॅक बटण"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"पुढील ट्रॅक बटण"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"विराम बटण"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"प्ले बटण"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"थांबवा बटण"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"सेवा नाही."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 8f46081..3d4dee4 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Taip kata laluan untuk membuka kunci"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Taip PIN untuk membuka kunci"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Kod PIN salah."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka kunci, tekan Menu, kemudian 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Telah melepasi had cubaan Buka Kunci Wajah"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Sudah dicas"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Mengecas"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Sambungkan pengecas anda."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kad SIM dikunci."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kad SIM dikunci dengan PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Membuka kunci kad SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d dari %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Tambah widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Kosong"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Bahagian buka kunci dikembangkan."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Bahagian buka kunci diruntuhkan."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Pemilih pengguna"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kawalan media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Penyusunan semula widget dimulakan."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Penyusunan semula widget tamat."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> dipadamkan."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kembangkan bahagian buka kunci."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Buka kunci luncur."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Buka kunci corak."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Wajah Buka Kunci"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Buka kunci pin."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Kawasan PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Kawasan PIN SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Kawasan PUK SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butang lagu sebelumnya"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butang lagu seterusnya"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butang jeda"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butang main"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butang berhenti"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Menyukai"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Tidak diterima"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Jantung"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Buka kunci untuk meneruskan"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Pelancaran dibatalkan"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Jatuhkan <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> untuk memadam."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> tidak akan dipadamkan."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Penggera seterusnya ditetapkan pada <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Selesai"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Perubahan mod"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Masuk"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Buka kunci"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Senyap"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Bunyi dihidupkan"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Luncurkan ke bawah untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Luncurkan ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Luncurkan ke kanan untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?\nLawati"<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Menyemak akaun…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kod PIN SIM tidak betul, jadi anda harus menghubungi pembawa anda untuk membuka kunci peranti."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Kod PIN SIM tidak betul. Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum anda harus menghubungi pembawa anda untuk membuka kunci peranti."</item>
-    <item quantity="other" msgid="2215723361575359486">"Kod PIN SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Kod PIN SIM salah, anda ada <xliff:g id="NUMBER_1">%d</xliff:g> cubaan lagi.</item>
+      <item quantity="one">Kod PIN SIM tidak betul. Anda ada <xliff:g id="NUMBER_0">%d</xliff:g> cubaan lagi sebelum anda harus menghubungi pembawa anda untuk membuka kunci peranti.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM tidak boleh digunakan. Hubungi pembawa anda."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM tidak boleh digunakan secara kekal."</item>
-    <item quantity="other" msgid="5477305226026342036">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM tidak boleh digunakan secara kekal."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Kod PUK SIM tidak betul, anda ada <xliff:g id="NUMBER_1">%d</xliff:g> cubaan lagi sebelum SIM tidak boleh digunakan secara kekal.</item>
+      <item quantity="one">Kod PUK SIM tidak betul, anda ada <xliff:g id="NUMBER_0">%d</xliff:g> cubaan lagi sebelum SIM tidak boleh digunakan secara kekal.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operasi PIN SIM gagal!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Diterima!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butang lagu sebelumnya"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butang lagu seterusnya"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butang jeda"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butang main"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butang berhenti"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index a7ba0e5..4432ceb 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -20,17 +20,15 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="719438068451601849">"သော့ချက် စောင့်ပေးသူ"</string>
-    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN ကုဒ် ရိုက်ထည့်ပါ"</string>
+    <string name="app_name" msgid="719438068451601849">"သော့ချက် စောင့်ပေးသူ"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN ကုဒ် ရိုက်ထည့်ပါ"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"ဆင်းမ်ကဒ် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် နှင့် လျို့ဝှက်နံပါတ်သစ် ရိုက်ထည့်ပါ"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"ဆင်းမ်ကဒ် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် နံပါတ်"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"ဆင်းမ်ကဒ် လျို့ဝှက်ပင်နံပါတ် အသစ်သွင်းရန်"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"စကားဝှက် ရိုက်ရန် ထိပါ"</font></string>
-    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"သော့ဖွင့်ရန် စကားဝှက်ကို ရိုက်ထည့်ပါ"</string>
-    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"သော့ဖွင့်ရန် PIN ကို ရိုက်ထည့်ပါ"</string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"သော့ဖွင့်ရန် စကားဝှက်ကို ရိုက်ထည့်ပါ"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"သော့ဖွင့်ရန် PIN ကို ရိုက်ထည့်ပါ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ပင်နံပါတ်မှားနေပါသည်"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"သော့ဖွင့်ရန် Menu ထိုနောက်0ကိုနှိပ်ပါ"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"မျက်မှာမှတ် သော့ဖွင့်ခြင်း ခွင့်ပြုသော အကြိမ်ရေထက် ကျော်လွန်သွားပါပြီ"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"အားသွင်းနေပါသည်"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"အားသွင်းနေ"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"အားသွင်းကြိုးဖြင့် ဆက်သွယ်ပါ"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ဆင်းမ်ကဒ် သော့ကျနေပါသည်"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ဆင်းမ်ကဒ် ရဲ့ ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် သော့ကျနေပါသည်"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"ဆင်းမ်ကဒ် ကို သော့ဖွင့်နေပါသည်"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$d ရဲ့ဝဒ်ဂျက် %2$d"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ဝဒ်ဂျက်ထည့်ရန်"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"အလွတ်"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"သောဖွင့်ထားသော နေရာကို ချဲ့လိုက်ခြင်း"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"သောဖွင့်ထားသော နေရာကို ချုံ့လိုက်ခြင်း"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ဝဒ်ဂျက်"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"အသုံးပြုသူ ရွေးချယ်ရာ"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"ကင်မရာ"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"မီဒီယာ ထိန်းချုပ်မှုများ"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ဝဒ်ဂျက်များ နေရာစီခြင်း စတင်ပါပြီ"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ဝဒ်ဂျက်များကို နေရာ ပြန်စီပြီးပါပြီ"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ဝဒ်ဂျက်ကို ဖျက်လိုက်ပြီးပါပြီ"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"သော့မချထားသာ နယ်ပယ်ကို ချဲ့ပါ"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ဘေးတိုက်ပွတ်ဆွဲ၍ သော့ဖွင့်ခြင်း"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ပုံစံဖြင့် သော့ဖွင့်ခြင်း"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"မျက်နှာမှတ် သော့ဖွင့်ခြင်း"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"ပင်နံပါတ်ဖြင့် သော့ဖွင့်ခြင်း"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN နေရာ"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN နေရာ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK နေရာ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ပြီးခဲ့သော အပုဒ်အတွက် ခလုတ်"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"နောက်တစ်ပုဒ် ခလုတ်"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ခဏရပ်ရန် ခလုတ်"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ဖွင့်ရန် ခလုတ်"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ရပ်ရန် ခလုတ်"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"လက်မထောင်"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"လက်မချ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"နှလုံးသား"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ရှေ့ဆက်လုပ်ရန် သော့ဖွင့်ပါ"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ဖွင့်တာကို ပယ်ဖျက်ပါ"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ကို ဖျက်ပစ်ရန် ချ လိုက်ပါ"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ကို ဖျက်ပစ်မည် မဟုတ်ပါ"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> အတွက် နောက် သတိပေးရန် သတ်မှတ်ချက်"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Altခလုတ်"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ပယ်ဖျက်ရန်ခလုတ်"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ဖျက်ရန်ခလုတ်"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ပြီးဆုံးသည့်ခလုတ်"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"စနစ်ပြောင်းခြင်းခလုတ်"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shiftခလုတ်"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enterခလုတ်"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ဖွင့်ရန်"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"ကင်မရာ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"အသံတိတ်ရန်"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"အသံဖွင့်သည်"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> အတွက် အောက်ကို ပွတ်ဆွဲပါ"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> အတွက် ဖယ်ဘက်ကို ပွတ်ဆွဲပါ"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> အတွက် ညာဖက်ကို ပွတ်ဆွဲပါ"</string>
-    <string name="user_switched" msgid="3768006783166984410">"လက်ရှိအသုံးပြုနေသူ <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"အရေးပေါ် ခေါ်ဆိုမှု"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ပုံဖော်မှုအား မေ့လျော့ခြင်း"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"ပုံဆွဲအမှား"</string>
@@ -110,11 +64,11 @@
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်ကြိုးစားပါ"</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"သင့်ရဲ့ သော့ဖွင့်သော ပုံစံကို ဆွဲပါ"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ဆင်းမ်ကဒ် ပင် နံပါတ် ရိုက်ထည့်ပါ"</string>
-    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" အတွက် ဆင်းမ် ပင်နံပါတ် ရိုက်ထည့်ပါ။"</string>
+    <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" အတွက် ဆင်းမ် ပင်နံပါတ် ရိုက်ထည့်ပါ။"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"ပင်နံပါတ် ရိုက်ထည့်ပါ"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"လျို့ဝှက်နံပါတ် ရိုက်ထည့်ပါ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ ဆက်လက် လုပ်ဆောင်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ရိုက်ထည့်ပါ။ ပိုမိုသိချင်လျင် ဖုန်းဝန်ဆောင်မှု ပေးသောဌာန အားဆက်သွယ်နိုင်ပါသည်။"</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"ဆင်းမ် \"<xliff:g id="CARRIER">%1$s</xliff:g>\" သည် ယခု အလုပ်မလုပ်တော့ပါ။ ဆက်လက်သွားရန် PUK ကုဒ် ရိုက်ထည့်ပါ၊။အသေးစိတ်သိရရန် ဖုန်းဝန်ဆောင်မှုလုပ်ငန်းအား ဆက်သွယ်ပါ။"</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"ဆင်းမ် \"<xliff:g id="CARRIER">%1$s</xliff:g>\" သည် ယခု အလုပ်မလုပ်တော့ပါ။ ဆက်လက်သွားရန် PUK ကုဒ် ရိုက်ထည့်ပါ၊။အသေးစိတ်သိရရန် ဖုန်းဝန်ဆောင်မှုလုပ်ငန်းအား ဆက်သွယ်ပါ။"</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"လိုချင်သော ပင်နံပါတ်ကို ရိုက်ထည့်ပါ"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"လိုချင်သော ပင်နံပါတ်ကို အတည်ပြုရန်"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ဆင်းမ်ကဒ် ကို သော့ဖွင့်နေပါသည်"</string>
@@ -123,48 +77,36 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ပြန်လည် ရိုက်ထည့်ပါ.။ ထပ်ခါ ထပ်ခါ ကြိုးစားခြင်းသည် ဆင်းမ်ကဒ်ကို အသုံးပြုမရအောင် ဖြစ်နေနိုင်ပါသည်။"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ပင် နံပါတ် မတူညီပါ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"မြောက်မြားစွာ ပုံစံဆွဲ သော့ဖွင့်မှု"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"သော့ဖွင့်ရန် သင့်ရဲ့ ဂူဂယ်လ် အကောင့်ဖြင့် ဝင်ပါ"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"သုံးစွဲသူအမည် (အီးမေးလ်)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"စကားဝှက်"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ဝင်ပါ"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"အသုံးပြုသူ အမည် သို့  စကားဝှက်မမှန်ကန်ပါ"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"သင် သုံးစွဲသူ အမည် သို့ စကားဝှက်အားမေ့နေပါသလား။\n"<b>"google.com/accounts/recovery"</b>" သို့ သွားရောက်ပါ"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"အကောင့်ကို စစ်ဆေးနေစဉ်..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"သင် ပင် နံပါတ်ကို အမှားကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ရိုက်ထည့်ပြီးပါပြီ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့် အကြာတွင် ပြန်လည်ကြိုးစားပါ"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"သင်သည် စကားဝှက်ကို  <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် မှားရိုက်ပြီးပါပြီ။ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာ ပြန်လည်ကြိုးစားပါ"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"သင် ပုံစံဆွဲ သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ်မြောက် မအောင်မြင်ပါ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤတက်ဘလက်အား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤတက်ဘလက်အား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို  <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။  နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်တက်ဘလက်အား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ဖယ်ရှားရန်"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ဆင်းကဒ် လျှို့ဝှက် အမှတ် မှားယွင်းပါသည်, ဖုန်းလိုင်းဌာနကို ဆက်သွယ်ရမည် ဖြစ်ပါတယ်"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"ဆင်းမ်ကဒ်၏ လျှို့ဝှက်နံပါတ် မှားနေပါသည်၊ သင်၏ စက်ပစ္စည်းကို သော့ဖွင့်ရန်  ဖုန်းလိုင်းဌာနသို့ မဆက်သွယ်မီ သင့်တွင် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။"</item>
-    <item quantity="other" msgid="2215723361575359486">"ဆင်းမ်ကဒ်၏ လျှို့ဝှက်နံပါတ် မှားနေပါသည်၊ သင့်တွင် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">ဆင်းမ်ကဒ်၏ ပင်နံပါတ် မှားနေပါသည်၊ သင့်တွင်<xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+      <item quantity="one">ဆင်းမ်ကဒ်၏ ပင်နံပါတ် မှားနေပါသည်၊ သင့်ကိရိယာကို ဖွင့်ရန်  မိုဘိုင်းဖုန်းဆက်သွယ်ရေးဝန်ဆောင်မှုဌာနသို့ မဆက်သွယ်မီ သင့်တွင် <xliff:g id="NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"ဆင်းမ်ကဒ်သုံးလို့မရတော့ပါ. ဖုန်းလိုင်းဌာနကို ဆက်သွယ်ပါ"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"ဆင်းမ်ကဒ်၏ ပင်နံပါတ်ပြန်ဖွင့်သည့်ကုဒ်နံပါတ် မှားနေပါသည်။ နောက်ထပ် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစား၍ မအောင်မြင်ံပါက ဆင်းမ်ကဒ် ဆက်မသုံးနိုင်အောင် ပျက်စီးသွားမည် ဖြစ်ပါသည်"</item>
-    <item quantity="other" msgid="5477305226026342036">"ဆင်းမ်ကဒ်၏ ပင်နံပါတ်ပြန်ဖွင့်သည့် ကုဒ်နံပါတ် မှားနေပါသည်။ နောက်ထပ် <xliff:g id="NUMBER">%d</xliff:g> ခါ ကြိုးစား၍ မအောင်မြင်ံပါက ဆင်းမ်ကဒ် ဆက်မသုံးနိုင်အောင် ပျက်စီးသွားမည် ဖြစ်ပါသည်"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">ဆင်းမ်ကဒ်၏ ပင်နံပါတ်ပြန်ဖွင့်သည့် ကုဒ် (PUK) မမှန်ပါ၊ ဆင်းမ်ကဒ်သည် ဆက်လက်အသုံးမပြုနိုင်အောင် မဖြစ်လာခင် သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g>ခါ ကြိုးစားခွင့်များကျန်ပါသေးသည်။</item>
+      <item quantity="one">ဆင်းမ်ကဒ်၏ ပင်နံပါတ်ပြန်ဖွင့်သည့် ကုဒ် (PUK) မမှန်ပါ၊ ဆင်းမ်ကဒ်သည် ဆက်လက်အသုံးမပြုနိုင်အောင် မဖြစ်လာခင် သင့်တွင် <xliff:g id="NUMBER_0">%d</xliff:g> ခါ ကြိုးစားခွင့်ကျန်ပါသေးသည်။</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"ဆင်းမ်ကဒ် ပင် လုပ်ဆောင်မှု မအောင်မြင်ပါ"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် လုပ်ဆောင်မှု မအောင်မြင်ပါ"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ကုဒ်နံပါတ်ကို လက်ခံလိုက်ပါသည်"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ပြီးခဲ့သော အပုဒ်အတွက် ခလုတ်"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"နောက် သီချင်းပုဒ် ခလုတ်"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ခဏရပ်ရန် ခလုတ်"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ဖွင့်ရန် ခလုတ်"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ရပ်ရန် ခလုတ်"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ဆားဗစ် မရှိပါ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 0f7fa66..efc25cf 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Skriv inn passord for å låse opp"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Skriv inn PIN-kode for å låse opp"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Feil personlig kode."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"For å låse opp, trykk på menyknappen og deretter 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har overskredet grensen for opplåsingsforsøk med Ansiktslås"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Oppladet"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Lader"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Koble til laderen."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet er låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortet er PUK-låst."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Låser opp SIM-kortet ..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Modul %2$d av %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Legg til modul."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Opplåsingsfeltet vises."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Opplåsingsfeltet skjules."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>-modul."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Brukervelgeren"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediekontroll"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Endring av modulplasseringen har startet."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Endringen av modulplasseringen er ferdig."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Modulen <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ble slettet."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Vis opplåsingsfeltet."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Opplåsning ved å dra med fingeren."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mønsteropplåsning."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Ansiktsopplåsning."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-opplåsning."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-området"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-området for SIM-kortet"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-området for SIM-kortet"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Forrige spor-knapp"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Neste spor-knapp"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pause-knapp"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Avspillingsknapp"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stopp-knapp"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Likt av meg"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Sanger du ikke liker"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hjerte"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Lås opp for å fortsette"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Starten ble kansellert"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Slipp <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> for å slette den."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> blir ikke slettet."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Neste alarm er innstilt for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slett"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Ferdig"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modusendring"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Lås opp"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Stille"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Lyd på"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Dra ned for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Dra til venstre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Dra til høyre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødnummer"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glemt mønsteret?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Feil mønster"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Logg på med Google-kontoen din for å låse opp."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brukernavn (e-postadresse)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passord"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?\nGå til "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Sjekker kontoen ..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten."</item>
-    <item quantity="other" msgid="2215723361575359486">"Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item>
+      <item quantity="one">Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER_0">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortet er ubrukelig. Kontakt operatøren din."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
-    <item quantity="other" msgid="5477305226026342036">"Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig.</item>
+      <item quantity="one">Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"PIN-koden for SIM-kortet ble avvist."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden for SIM-kortet ble avvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden er godkjent."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Forrige spor-knapp"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Neste spor-knapp"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pause-knapp"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Avspillingsknapp"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stopp-knappen"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjeneste."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 00b9ece..7f6843a 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलक गर्न पासवर्ड टाइप गर्नुहोस्।"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलक गर्न PIN कोड टाइप गर्नुहोस्"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत PIN कोड।"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"अनलक गर्न मेनु थिच्नुहोस् र त्यसपछि ० थिच्नुहोस्।"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"अत्याधिक मोहडा खोल्ने प्रयासहरू बढी भए।"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज भयो"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"चार्ज हुँदै"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"तपाईँको चार्जर जोड्नुहोस्।"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM कार्ड लक गरियो।"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM कार्ड PUK-लक छ।"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM कार्ड अनलक हुँदै…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. विजेट %2$d of %3$d।"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"विजेट थप गर्नुहोस्।"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"खाली"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"अनलक क्षेत्र विस्तार भयो।"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"अनलक क्षेत्र भत्कियो।"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> विजेट।"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"प्रयोगकर्ता छनौटकर्ता"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"क्यामेरा"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"मिडिया नियन्त्रणहरू"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"विजेट पुनःक्रम गर्ने सुरु भयो।"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"विजेट पुनःक्रम समाप्त भएको छ।"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"विजेट <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> मेटाइयो।"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"अनलक क्षेत्र बढाउनुहोस्।"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"स्लाइड अनलक।"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"ढाँचा अनलक।"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"फेस अनलक"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin अनलक"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"पीन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM पिन क्षेत्र"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM पुक क्षेत्र"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"अघिल्लो पथ बटन"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"अर्को पथ बटन"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"रोक्ने बटन"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"बजाउने बटन"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"बटन रोक्नुहोस्"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"मन परेको"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"मन परेन"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"मुटु"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"जारी राख्न अनलक गर्नुहोस्"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"सुरुवात रद्द गरियो"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"मेट्नको लागि <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ड्रप गर्नुहोस्"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> मेटिने छैन।"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> को लागि अर्को चेतावनी सेट"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?१२३"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द गर्नुहोस्"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"मेट्नुहोस्"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"भयो"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"मोड परिवर्तन गर्नुहोस्"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"प्रविष्टि गर्नुहोस्"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"अनलक गर्नुहोस्"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"क्यामेरा"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"मौन"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"आवाज चालू"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> को लागि तल स्लाइड गर्नुहोस्।"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"स्लाइड <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि बायाँ।"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"स्लाइड <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि दायाँ।"</string>
-    <string name="user_switched" msgid="3768006783166984410">"अहिलेको प्रयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>।"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"आपतकालीन कल"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ढाँचा बिर्सनु भयो"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत ढाँचा"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"PUK कोड पुन:प्रदान गर्नुहोस्। धेरै पुन:प्रयासहरूले SIMलाई स्थायी रूपमा निष्क्रिय गरिदिने छ।"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN कोडहरू मेल खाएन"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"निकै धेरै ढाँचा कोसिसहरू"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"अनलक गर्नको लागि, तपाईँको Google खाताको साथ साइन इन गर्नुहोस्।"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"प्रयोगकर्ता नाम (इमेल)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन गर्नुहोस्"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य प्रयोगकर्तानाम वा पासवर्ड।"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"के तपाईँले उपयोगकर्ता नाम वा पासवर्ड बिर्सनुभयो?\n"<b>"google.com/accounts/recovery"</b>" मा जानुहोस्।"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"खाता जाँच हुँदै…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"तपाईँले गलत तरिकाले तपाईँको PIN <xliff:g id="NUMBER_0">%d</xliff:g> पटक टाइप गर्नु भएको छ। \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"तपाईँले तपाईँक पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> पटक गलत टाइप गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%d</xliff:g> पटक खिच्नु भएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण प्रोफाइल डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डहरूमा।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"हटाउनुहोस्"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN कोड गलत छ। अब तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दर।"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN कोड गलत छ, तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दछ यस अघि तपाईंसँग <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयास छ।"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN कोड गलत छ, तपाईंसँग <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयासहरू छन्।"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other"> गलत SIM PIN कोड, तपाईं सँग <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+      <item quantity="one">SIM PIN कोड गलत छ, तपाईंले अाफ्नो यन्त्र खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्न अघि तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM प्रयोग बिहिन छ। तपाईंको वाहकलाई सम्पर्क गर्नुहोस्।"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUK कोड गलत छ, तपाईंसँग SIM स्थायी रूपमा काम नलाग्ने हुनु अघि <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयास छ।"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK कोड गलत छ, तपाईंसँग SIM स्थायी रूपमा काम नलाग्ने हुनु अघि <xliff:g id="NUMBER">%d</xliff:g> बाँकी प्रयासहरू छन्।"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK कोड गलत छ, तपाईंसँग SIM स्थायी रूपमा काम नलाग्ने हुनु अघि <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+      <item quantity="one">SIM PUK कोड गलत छ, तपाईंसँग SIM स्थायी रूपमा काम नलाग्ने हुनु अघि <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN राख्‍ने कार्य बिफल भयो!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK राख्‍ने कार्य बिफल भयो!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकृत!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"अघिल्लो ट्रयाक बटन"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"अर्को ट्रयाक बटन"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"रोक्ने बटन"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"बटन बजाउनुहोस्"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"बटन रोक्नुहोस्"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कुनै सेवा छैन।"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 518a1e1..3a8d91c 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Typ het wachtwoord om te ontgrendelen"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Typ pincode om te ontgrendelen"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Onjuiste pincode."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximaal aantal pogingen voor Ontgrendelen via gezichtsherkenning overschreden"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Opgeladen"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Opladen"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Sluit de oplader aan."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Simkaart is vergrendeld."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Simkaart is vergrendeld met PUK-code."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Simkaart ontgrendelen…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d van %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget toevoegen."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Leeg"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Ontgrendelingsgebied uitgevouwen."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Ontgrendelingsgebied samengevouwen."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Gebruikersselectie"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediabediening"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Opnieuw indelen van widget gestart."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Opnieuw indelen van widget beëindigd."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> verwijderd."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Ontgrendelingsgebied uitvouwen."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ontgrendeling via schuiven."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ontgrendeling via patroon."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Ontgrendelen via gezichtsherkenning"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ontgrendeling via pincode."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Gebied voor pincode"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Gebied voor sim-pincode"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Gebied voor sim-pukcode"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knop voor vorig nummer"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knop voor volgend nummer"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Knop voor onderbreken"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Knop voor afspelen"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Knop voor stoppen"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Leuk"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Niet leuk"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hart"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Ontgrendel om door te gaan"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Start geannuleerd"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Zet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> neer om te verwijderen."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> wordt niet verwijderd."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Volgende alarm ingesteld voor <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"Alt"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuleren"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gereed"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modus wijzigen"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Ontgrendelen"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Stil"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Geluid aan"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Veeg omlaag voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Veeg naar rechts voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patroon vergeten"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Onjuist patroon"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u inloggen op uw Google-account."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikersnaam (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inloggen"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?\nGa naar "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Account controleren…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met uw provider om uw apparaat te ontgrendelen."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER">%d</xliff:g> poging over voordat u contact met uw provider moet opnemen om uw apparaat te ontgrendelen."</item>
-    <item quantity="other" msgid="2215723361575359486">"Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER">%d</xliff:g> pogingen over."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
+      <item quantity="one">Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat u contact met uw provider moet opnemen om uw apparaat te ontgrendelen.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Simkaart is onbruikbaar. Neem contact op met uw provider."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt."</item>
-    <item quantity="other" msgid="5477305226026342036">"Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt.</item>
+      <item quantity="one">Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Bewerking met pincode voor simkaart mislukt."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Bewerking met pukcode voor simkaart is mislukt."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code geaccepteerd."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knop voor vorig nummer"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knop voor volgend nummer"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Knop voor onderbreken"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Knop voor afspelen"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Knop voor stoppen"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 623c8ca..40cd5e6 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Wpisz hasło, aby odblokować."</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Wpisz kod PIN, aby odblokować."</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Błędny kod PIN"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Przekroczono maksymalną liczbę prób rozpoznania twarzy."</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Naładowana"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Ładowanie"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Podłącz ładowarkę."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Karta SIM jest zablokowana."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Karta SIM jest zablokowana za pomocą kodu PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odblokowuję kartę SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widżet %2$d z %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodaj widżet."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Puste"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Rozwinięto obszar odblokowania."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zwinięto obszar odblokowania."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widżet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Wybór użytkownika"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Aparat"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Elementy sterujące multimediów"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Rozpoczęto zmienianie kolejności widżetów."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Zakończono zmienianie kolejności widżetów."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Usunięto widżet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozwiń obszar odblokowania."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odblokowanie przesunięciem."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odblokowanie wzorem."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Rozpoznanie twarzy"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odblokowanie kodem PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Miejsce na PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Miejsce na PIN do karty SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Miejsce na PUK do karty SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Przycisk poprzedniego utworu"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Przycisk następnego utworu"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Przycisk wstrzymania"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Przycisk odtwarzania"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Przycisk zatrzymania"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Podoba mi się"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nie podoba mi się"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Serce"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Odblokuj, by kontynuować"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Uruchomienie anulowane"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Upuść <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>, by usunąć."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> nie zostanie usunięty."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Następny alarm ustawiono na <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anuluj"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotowe"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Zmiana trybu"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Odblokuj"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Aparat"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Wyciszenie"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Włącz dźwięk"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Przesuń w dół: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Przesuń w lewo: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Przesuń w prawo: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Połączenie alarmowe"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nie pamiętam wzoru"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nieprawidłowy wzór"</string>
@@ -123,16 +77,9 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponownie podaj poprawny kod PUK. Nieudane próby spowodują trwałe wyłączenie karty SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kody PIN nie pasują"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Aby odblokować, zaloguj się na konto Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nazwa użytkownika (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Hasło"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Zaloguj się"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nieprawidłowa nazwa użytkownika lub hasło."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nie pamiętasz nazwy użytkownika lub hasła?\nWejdź na "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Sprawdzam konto"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> razy narysowałeś nieprawidłowy wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nieprawidłowy kod PIN karty SIM. Musisz teraz skontaktować się z operatorem, by odblokował Twoje urządzenie."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> próbę, zanim będziesz musiał skontaktować się z operatorem, by odblokował Twoje urządzenie."</item>
-    <item quantity="other" msgid="2215723361575359486">"Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> prób(y)."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="few">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
+      <item quantity="many">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> prób.</item>
+      <item quantity="other">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
+      <item quantity="one">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_0">%d</xliff:g> próbę, zanim będziesz musiał skontaktować się z operatorem, by odblokować swoje urządzenie.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Karta SIM została trwale zablokowana. Skontaktuj się z operatorem."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana."</item>
-    <item quantity="other" msgid="5477305226026342036">"Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER">%d</xliff:g> prób(y), zanim karta SIM zostanie trwale zablokowana."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="few">Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana.</item>
+      <item quantity="many">Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> prób, zanim karta SIM zostanie trwale zablokowana.</item>
+      <item quantity="other">Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana.</item>
+      <item quantity="one">Nieprawidłowy kod PUK karty SIM. Masz jeszcze <xliff:g id="NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operacja z kodem PIN karty SIM nie udała się."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacja z kodem PUK karty SIM nie udała się."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod został zaakceptowany."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Przycisk poprzedniego utworu"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Przycisk następnego utworu"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Przycisk wstrzymania"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Przycisk odtwarzania"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Przycisk zatrzymania"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Brak usługi."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-port/bools.xml b/packages/Keyguard/res/values-port/bools.xml
index 1e2a4f2..fdb8ebc 100644
--- a/packages/Keyguard/res/values-port/bools.xml
+++ b/packages/Keyguard/res/values-port/bools.xml
@@ -15,7 +15,5 @@
 -->
 
 <resources>
-    <bool name="action_bar_embed_tabs">false</bool>
-    <bool name="kg_share_status_area">true</bool>
     <bool name="kg_sim_puk_account_full_screen">true</bool>
 </resources>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 0556812..9068898 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Escreva a palavra-passe para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Escreva o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, prima Menu e, em seguida, 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Excedido o n.º máximo de tentativas de Desbloqueio Através do Rosto"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Carregado"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"A carregar"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Ligue o carregador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"O cartão SIM está bloqueado."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"O cartão SIM está bloqueado por PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"A desbloquear o cartão SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adicionar widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vazio"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueio expandida."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueio minimizada."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de utilizadores"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Câmara"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controlos de multimédia"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Reordenação de widgets iniciada."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordenação de widgets concluída."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> eliminado."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir área de desbloqueio."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueio através de deslize."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio através de sequência."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio através do rosto."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio através de PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN do SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK do SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão Faixa anterior"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão Faixa seguinte"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão Pausa"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botão Reproduzir"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botão Parar"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Gosto"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Não gosto"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Coração"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloquear para continuar"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Lançamento cancelado"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Largue <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> para eliminar."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> não será eliminado."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Próximo alarme definido para as <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Concluído"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Alteração do modo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Câmara"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Deslize para baixo para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Deslize para a esquerda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Deslize para a direita para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueceu-se da Sequência"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequência Incorreta"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não correspondem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, inicie sessão com a sua Conta do Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de utilizador (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Palavra-passe"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sessão"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de utilizador ou palavra-passe inválidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu-se do nome de utilizador ou da palavra-passe?\nAceda a "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"A verificar a conta…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativa antes de necessitar de contactar o seu operador para desbloquear o dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativas."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+      <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de necessitar de contactar o seu operador para desbloquear o dispositivo.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Cartão SIM inutilizável. Contacte o seu operador."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável."</item>
-    <item quantity="other" msgid="5477305226026342036">"Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
+      <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Falha ao introduzir o PIN do cartão SIM!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha ao introduzir o PUK do cartão SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceite!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botão Faixa anterior"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botão Faixa seguinte"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botão Pausa"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botão Reproduzir"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botão Parar"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 154eaa7..690b693 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Digite a senha para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Insira o PIN para desbloquear"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Código PIN incorreto."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Carregado"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Carregando"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Conecte seu carregador."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"O cartão SIM está bloqueado."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"O cartão SIM está bloqueado pelo PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Desbloqueando o cartão SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d de %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adicionar widget"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Vazio"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Área de desbloqueio expandida."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Área de desbloqueio recolhida."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget de <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Seletor de usuários"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Câmera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Controles de mídia"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Reordenação de widgets iniciada."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordenação de widgets concluída."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> excluído."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandir a área de desbloqueio."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Desbloqueio com deslize."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desbloqueio com padrão."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Desbloqueio facial."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Desbloqueio com PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Área do PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Área do PIN SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Área do PUK SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Botão \"Faixa anterior\""</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Botão \"Próxima faixa\""</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Botão \"Pausar\""</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Botão \"Reproduzir\""</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Botão \"Parar\""</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Gostei"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Não gostei"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Coração"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Desbloqueie para continuar"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Inicialização cancelada"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Solte <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> para excluir."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> não será excluído."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Excluir"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Concluído"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Alteração do modo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Desbloquear"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Câmera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silencioso"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Som ativado"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para baixo."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a esquerda."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para a direita."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueci o padrão"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Padrão incorreto"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de usuário (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Senha"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Fazer login"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de usuário ou senha inválidos."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?\nAcesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Verificando a conta..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g>. Caso o código correto não seja digitado, será necessário entrar em contato com a operadora para desbloquear o dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+      <item quantity="other">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"O SIM está inutilizável. Entre em contato com a operadora."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g> Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável."</item>
-    <item quantity="other" msgid="5477305226026342036">"Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER">%d</xliff:g>. Caso o código correto não seja digitado, o SIM se tornará permanentemente inutilizável."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM não poderá mais ser usado.</item>
+      <item quantity="other">Código PUK do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>. Caso o código correto não seja digitado, o SIM não poderá mais ser usado.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Falha na operação de PIN do SIM."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha na operação de PUK do SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceito."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botão \"Faixa anterior\""</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botão \"Próxima faixa\""</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Botão \"Pausar\""</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Botão \"Reproduzir\""</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Botão \"Parar\""</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index dd3fe2f..1e6fc00 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Introduceţi parola pentru a debloca"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Încărcată"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Se încarcă"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Conectați încărcătorul."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Cardul SIM este blocat."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Cardul SIM este blocat cu codul PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Se deblochează cardul SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d din %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Adăugaţi un widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Gol"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Zona de deblocare a fost extinsă."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Zona de deblocare a fost restrânsă."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Selector utilizator"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Cameră foto"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Comenzi media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"A început reordonarea widgeturilor."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Reordonarea widgeturilor s-a încheiat."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgetul <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> a fost eliminat."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Extindeţi zona de deblocare."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Deblocare prin glisare."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Deblocare cu model."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Deblocare facială."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Deblocare cu PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Zona codului PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Zona codului PIN al cardului SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Zona codului PUK al cardului SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Butonul Melodia anterioară"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Butonul Melodia următoare"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Butonul Întrerupeți"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Butonul Redați"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Butonul Opriți"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Vot pozitiv"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Vot negativ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Inimă"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Deblocați pentru a continua"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Lansare anulată"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Eliberați <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> pentru a șterge."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Widgetul <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> nu va fi șters."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Următoarea alarmă este setată la <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulaţi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminat"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Schimbarea modului"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Deblocaţi"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Cameră foto"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Silenţios"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sunet activat"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Glisaţi în jos pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Glisaţi spre stânga pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Glisaţi spre dreapta pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Apel de urgenţă"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Conectaţi-vă"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?\nAccesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Se verifică contul…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
@@ -147,24 +94,21 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Codul PIN pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul."</item>
-    <item quantity="other" msgid="2215723361575359486">"Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="few">Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item>
+      <item quantity="other">Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări.</item>
+      <item quantity="one">Codul PIN pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Cardul SIM nu poate fi utilizat. Contactați operatorul."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Codul PUK pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv."</item>
-    <item quantity="other" msgid="5477305226026342036">"Codul PUK pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări până când cardul SIM va deveni inutilizabil definitiv."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="few">Codul PUK pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până când cardul SIM va deveni inutilizabil definitiv.</item>
+      <item quantity="other">Codul PUK pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări până când cardul SIM va deveni inutilizabil definitiv.</item>
+      <item quantity="one">Codul PUK pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Deblocarea cu ajutorul codului PIN pentru cardul SIM nu a reușit!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Cod acceptat!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Butonul Melodia anterioară"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Butonul Melodia următoare"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Butonul Întrerupeți"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Butonul Redați"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Butonul Opriți"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Fără serviciu."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 1edfba5..48fd4f6 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Введите пароль"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Введите PIN-код"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неверный PIN-код."</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_plugged_in" msgid="9087497435553252863">"Зарядка батареи"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Подключите зарядное устройство."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карта заблокирована"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Для разблокировки SIM-карты требуется PUK-код."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Разблокировка SIM-карты…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виджет %2$d из %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Добавить виджет"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Пусто"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Область разблокировки развернута"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Область разблокировки свернута"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Виджет \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\""</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Выбор аккаунта"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Управление блокировкой"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Начато переопределение порядка виджетов"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Порядок виджетов определен"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Виджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> удален"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Развернуть области разблокировки"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Прокрутка"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Графический ключ"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фейсконтроль"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN-код"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-код"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-код SIM-карты"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-код SIM-карты"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Кнопка перехода к предыдущему треку"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кнопка перехода к следующему треку"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кнопка паузы"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Кнопка воспроизведения"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Кнопка выключения"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Нравится"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Не нравится"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Рейтинг"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Разблокируйте экран, чтобы продолжить."</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Запуск отменен."</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Отпустите виджет \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\", чтобы удалить его."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Виджет \"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>\" не будет удален."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Будильник сработает в <xliff:g id="ALARM">%1$s</xliff:g>."</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"АБВ"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Клавиша ALT"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отмена"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Клавиша удаления"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Клавиша смены режима"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Клавиша смены регистра"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Клавиша ввода"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Разблокировать"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Без звука"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Включить звук"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Проведите вниз, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Проведите влево, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Проведите вправо, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстренный вызов"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забыли графический ключ?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильный графический ключ"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не совпадают"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Чтобы разблокировать устройство, войдите в свой аккаунт Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Имя пользователя (эл. почта)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Войти"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неверное имя пользователя или пароль."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?\nПерейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Проверка данных…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. \n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Удалить"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неверный PIN-код. Обратитесь к оператору связи, чтобы разблокировать SIM-карту."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Неверный PIN-код. Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи."</item>
-    <item quantity="other" msgid="2215723361575359486">"Неверный PIN-код. Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Неверный PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
+      <item quantity="few">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
+      <item quantity="many">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
+      <item quantity="other">Неверный PIN-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-карта заблокирована навсегда. Обратитесь к оператору связи."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Неверный PUK-код. Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>. После этого SIM-карта будет заблокирована навсегда."</item>
-    <item quantity="other" msgid="5477305226026342036">"Неверный PUK-код. Осталось попыток: <xliff:g id="NUMBER">%d</xliff:g>. После этого SIM-карта будет заблокирована навсегда."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Неверный PUK-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована навсегда.</item>
+      <item quantity="few">Неверный PUK-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда.</item>
+      <item quantity="many">Неверный PUK-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда.</item>
+      <item quantity="other">Неверный PUK-код. Осталось <xliff:g id="NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Не удалось разблокировать SIM-карту"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Не удалось разблокировать SIM-карту"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код принят"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Кнопка перехода к предыдущему треку"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кнопка перехода к следующему треку"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кнопка паузы"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Кнопка воспроизведения"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Кнопка выключения"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 6527874..740b0ea 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"අගුළු ඇරීමට මුරපදය ටයිප් කරන්න"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"අගුළු හැරීමට PIN එක ටයිප් කරන්න"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"වැරදි PIN කේතයකි."</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_plugged_in" msgid="9087497435553252863">"ආරෝපණය වෙමින්"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"ඔබගේ ආරෝපකයට සම්බන්ධ කරන්න."</string>
@@ -46,22 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM පත අගුළු දමා ඇත."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM පත PUK අගුළු ලා ඇත."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM පත අගුළු හරිමින්..."</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
-    <skip />
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"විජටය එකතු කරන්න."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"හිස්"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"අගුළු අරින ප්‍රදේශය විදහා ඇත."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"අගුළු අරින ප්‍රදේශය හැකිලී ඇත."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> විජට්."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"පරිශීලක තෝරන්නා"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"කැමරාව"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"මාධ්‍ය පාලක"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"විජටය නැවත අනුපිළිවෙළට සැකසිම ඇරඹුණි."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"විජට් නැවත අනුපිළිවෙලට සැකසීම අවසානය."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> විජටය මැකී ඇත."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"අගුළු නොදැමූ ප්‍රදේශය පුළුල් කරන්න."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"සර්පණ අගුළු ඇරීම."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"රටා අගුළු ඇරීම."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"මුහුණ භාවිතයෙන් අඟුළු හැරීම."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN අගුළු ඇරීම."</string>
@@ -71,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN කොටස"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN කොටස"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK කොටස"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"පෙර ගීත බොත්තම"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ඉදිරි ගීත බොත්තම"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"විරාම බොත්තම"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ධාවක බොත්තම"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"නැවතීමේ බොත්තම"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"ලකුණක් ඉහළට"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ලකුණක් පහළට"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"හදවත"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"දිගටම පවත්වා ගෙන යෑම සඳහා අගුල අරින්න"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"දියත් කිරීම අවලංගු කර ඇත"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"මැකීමට <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> හෙලන්න."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> මකා දමා නැත."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"<xliff:g id="ALARM">%1$s</xliff:g> ට ඊළඟ සීනුව සකස් කර ඇත"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"අවලංගු කරන්න"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"මකන්න"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"හරි"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ආකාරය වෙනස් කරන්න"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ඇතුල් කරන්න"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"අඟුල අරින්න"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"කැමරාව"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"නිහඬ"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ශබ්ද සක්‍රීය කරන්න"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා පහලට සර්පණය කරන්න."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා වමට සර්පණය කරන්න."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> සඳහා දකුණට සර්පණය කරන්න."</string>
-    <string name="user_switched" msgid="3768006783166984410">"දැනට සිටින පරිශීලකයා <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"හදිසි ඇමතුම"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"රටාව අමතකයි"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"වැරදි රටාවකි"</string>
@@ -125,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"නිවැරදි PUK කේතය නැවත ඇතුලත් කරන්න. නැවත නැවත උත්සාහ කිරීමෙන් SIM එක ස්ථිරවම අබල කරයි."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN කේත ගැලපී නැත"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"රටා උත්සාහ කිරීම් වැඩිය"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"අගුළු ඇරීමට, ඔබගේ Google ගිණුම සමග පුරනය වන්න."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"පරිශීලක නාමය (ඊ-තැපෑල)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"මුරපදය"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"පුරනය වන්න"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"වලංගු නොවන පරිශීලක නාමයක් හෝ මුරපදයක්."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ඔබගේ පරිශීලක නාමය හෝ මුරපදය අමතකද?\n "<b>"google.com/accounts/recovery"</b>" වෙත යන්න."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"ගිණුම පරීක්ෂා කරමින්…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ඔබ PIN අංකය <xliff:g id="NUMBER_0">%d</xliff:g> වාරයක් වැරදියට ටයිප් කොට ඇත.\n\n තත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ මුරපදය ඔබ වැරදියට ටයිප් කර ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ට පසුව නැවත උත්සහ කරන්න."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ඔබ <xliff:g id="NUMBER_0">%d</xliff:g> වාරයක් අගුළු ඇරීමේ රටාව වැරදියට ඇඳ ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
@@ -149,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පැතිකඩ දත්ත මකා දමමින්, කාර්යාල පැතිකඩ මකා දැමෙනු ඇත."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> කින් උත්සාහ කරන්න."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ඉවත් කරන්න"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා සම්බන්ධ කරගැනීමට පෙර ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ඉතිරිව ඇත."</item>
-    <item quantity="other" msgid="2215723361575359486">"වැරදී SIM PIN කේතයකි, ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ඉතිරිව ඇත."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">වැරදි SIM PIN කේතයකි, ඔබට උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
+      <item quantity="other">වැරදි SIM PIN කේතයකි, ඔබට උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM කාඩ් පත භාවිතා කළ නොහැක. ඔබගේ වාහකය සම්බන්ධ කරගන්න."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"වැරදී SIM PUK කේතයකි, SIM කාඩ් පත සදාකාලිකව භාවිතා කළ නොහැකි තත්ත්වයට පත්වීමට  ඔබට තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ඉතිරිව ඇත."</item>
-    <item quantity="other" msgid="5477305226026342036">"වැරදී SIM PUK කේතයකි, SIM කාඩ් පත සදාකාලිකව භාවිතා කළ නොහැකි තත්ත්වයට පත්වීමට  ඔබට තවත් උත්සාහයන් <xliff:g id="NUMBER">%d</xliff:g> ඉතිරිව ඇත."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">වැරදී SIM PUK කේතයකි, SIM කාඩ් පත ස්ථිරවම පාවිච්චි කළ නොහැකි ලෙසට  පත්වීමට පෙර ඔබට තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ඉතිරිව ඇත.</item>
+      <item quantity="other">වැරදී SIM PUK කේතයකි, SIM කාඩ් පත ස්ථිරවම පාවිච්චි කළ නොහැකි ලෙසට  පත්වීමට පෙර ඔබට තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ඉතිරිව ඇත.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN ක්‍රියාවලිය අපොහොසත් විය!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ක්‍රියාවලිය අපොහොසත් විය!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"කේතය පිළිගැණුනි!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"පෙර ගීත බොත්තම"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ඉදිරි ගීත යතුර"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"විරාම බොත්තම"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ධාවන බොත්තම"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"නැවතුම් බොත්තම"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"සේවාව නැත."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index c8c05f2..2fbe838 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Zadajte heslo na odomknutie"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Zadajte kód PIN na odomknutie"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Nesprávny kód PIN."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Ak chcete telefón odomknúť, stlačte Menu a následne 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Prekročili ste maximálny povolený počet pokusov o odomknutie tvárou"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Batéria je nabitá"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nabíja sa"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Pripojte nabíjačku."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Karta SIM je uzamknutá."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Karta SIM je uzamknutá pomocou kódu PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Prebieha odomykanie karty SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Miniaplikácia %2$d z %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Pridať miniaplikáciu."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prázdne"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblasť na odomknutie bola rozšírená."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblasť na odomknutie bola zúžená."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Výber používateľa"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparát"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Ovládacie prvky médií"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Zmena usporiadania miniaplikácií sa začala."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Zmena usporiadania miniaplikácií sa skončila."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> bola odstránená."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Rozšíriť oblasť na odomknutie."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odomknutie prejdením prstom."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odomknutie vzorom."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odomknutie tvárou."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odomknutie kódom PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Oblasť kódu PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Oblasť kódu PIN SIM karty"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Oblasť kódu PUK SIM karty"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Tlačidlo Predchádzajúca stopa"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Tlačidlo Ďalšia stopa"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Tlačidlo Pozastaviť"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Tlačidlo Prehrať"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Tlačidlo Zastaviť"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Páči sa mi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Nepáči sa mi"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Srdce"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Odomknite zariadenie a pokračujte"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Spustenie bolo zrušené"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Uvoľnením dotyku miniaplikáciu <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> odstránite."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> nebude odstránená."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Nasledujúci budík je nastavený na <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušiť"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Odstrániť"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Hotovo"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Zmena režimu"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Odomknúť"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparát"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Tichý"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Zapnúť zvuk"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Prejdite prstom nadol: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Prejdite prstom doľava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Prejdite prstom doprava: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nepamätám si vzor"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávny vzor"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znova zadajte správny kód PUK. Opakované pokusy zakážu kartu SIM natrvalo."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Ak chcete telefón odomknúť, prihláste sa pomocou svojho účtu Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Používateľské meno (e-mail)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prihlásiť sa"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné používateľské meno alebo heslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?\n Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Prebieha kontrola účtu..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nesprávny kód PIN karty SIM. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Nesprávny kód PIN karty SIM. Zostáva vám <xliff:g id="NUMBER">%d</xliff:g> pokus, inak budete musieť kontaktovať svojho operátora, aby vám odomkol zariadenie."</item>
-    <item quantity="other" msgid="2215723361575359486">"Nesprávny kód PIN karty SIM. Počet zostávajúcich pokusov: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="few">Nesprávny kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
+      <item quantity="many">Nesprávny kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusu.</item>
+      <item quantity="other">Nesprávny kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusov.</item>
+      <item quantity="one">Nesprávny kód PIN SIM karty. Zostáva vám <xliff:g id="NUMBER_0">%d</xliff:g> pokus, potom budete musieť kontaktovať svojho operátora, aby vám odomkol zariadenie.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Karta SIM je nepoužiteľná. Kontaktujte svojho operátora."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Nesprávny kód PUK karty SIM. Zostáva vám <xliff:g id="NUMBER">%d</xliff:g> pokus, inak sa vaša karta SIM natrvalo zablokuje."</item>
-    <item quantity="other" msgid="5477305226026342036">"Nesprávny kód PUK karty SIM. Počet zostávajúcich pokusov pred trvalým zablokovaním karty SIM: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="few">Nesprávny kód PUK SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy, potom sa SIM karta natrvalo zablokuje.</item>
+      <item quantity="many">Nesprávny kód PUK SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusu, potom sa SIM karta natrvalo zablokuje.</item>
+      <item quantity="other">Nesprávny kód PUK SIM karty. Zostáva vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusov, potom sa SIM karta natrvalo zablokuje.</item>
+      <item quantity="one">Nesprávny kód PUK SIM karty. Zostáva vám <xliff:g id="NUMBER_0">%d</xliff:g> pokus, potom sa SIM karta natrvalo zablokuje.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operácia kódu PIN karty SIM zlyhala!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operácia kódu PUK karty SIM zlyhala!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód bol prijatý!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Tlačidlo Predchádzajúca stopa"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Tlačidlo Ďalšia stopa"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Tlačidlo Pozastaviť"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Tlačidlo Prehrať"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Tlačidlo Zastaviť"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žiadny signál"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index 81acafb..a79d99a 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Vnesite geslo za odklepanje"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Vnesite PIN za odklepanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Napačna koda PIN."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Če želite telefon odkleniti, pritisnite meni in nato 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Presegli ste dovoljeno število poskusov odklepanja z obrazom"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Napolnjeno"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Polnjenje"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Priključite napajalnik."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Kartica SIM je zaklenjena."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Kartica SIM je zaklenjena s kodo PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Odklepanje kartice SIM …"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Pripomoček %2$d za %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodajanje pripomočka."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Območje odklepanja razširjeno."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Območje odklepanja strnjeno."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Izbirnik uporabnika"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Fotoaparat"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrolniki predstavnosti"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Prerazporejanje pripomočkov začeto."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Prerazporejanje pripomočkov končano."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> izbrisan."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Razširitev območja odklepanja."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Odklepanje s podrsanjem."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Odklepanje z vzorcem."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Odklepanje z obrazom."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Odklepanje s kodo PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Območje za kodo PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Območje za kodo PIN za SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Območje za kodo PUK za SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Gumb za prejšnjo skladbo"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Gumb za naslednjo skladbo"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Gumb za začasno ustavitev"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Gumb za predvajanje"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Gumb za ustavitev"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Všeč mi je"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Ni mi všeč"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Srce"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Za nadaljevanje odklenite"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Zagon je preklican"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Izpustite pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>, da ga izbrišete."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Pripomoček <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ne bo izbrisan."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Naslednji alarm je nastavljen za <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Tipka Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekliči"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tipka Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Končano"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Sprememba načina"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tipka Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Tipka Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Odkleni"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Fotoaparat"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Tiho"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Vklopljen zvok"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Povlecite navzdol za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Povlecite v levo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Povlecite v desno za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Klic v sili"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pozabljen vzorec"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Napačen vzorec"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodi PIN se ne ujemata"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Če želite odkleniti napravo, se prijavite z Google Računom."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uporabniško ime (e-pošta)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Geslo"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neveljavno uporabniško ime ali geslo."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ali ste pozabili uporabniško ime ali geslo?\nObiščite "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Preverjanje računa ..."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se boste morali za odklenitev naprave obrniti na operaterja."</item>
-    <item quantity="other" msgid="2215723361575359486">"Napačna koda PIN kartice SIM. Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item>
+      <item quantity="two">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusa.</item>
+      <item quantity="few">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskuse.</item>
+      <item quantity="other">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusov.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Kartica SIM ni več uporabna. Obrnite se na operaterja."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem bo kartica SIM postala trajno neuporabna."</item>
-    <item quantity="other" msgid="5477305226026342036">"Napačna koda PUK kartice SIM. Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat. Potem bo kartica SIM postala trajno neuporabna."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus. Potem bo kartica SIM postala trajno neuporabna.</item>
+      <item quantity="two">Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusa. Potem bo kartica SIM postala trajno neuporabna.</item>
+      <item quantity="few">Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskuse. Potem bo kartica SIM postala trajno neuporabna.</item>
+      <item quantity="other">Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskusov. Potem bo kartica SIM postala trajno neuporabna.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Postopek za odklepanje s kodo PIN kartice SIM ni uspel."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Postopek za odklepanje s kodo PUK kartice SIM ni uspel."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koda je sprejeta."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Gumb za prejšnjo skladbo"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Gumb za naslednjo skladbo"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Gumb za začasno ustavitev"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Gumb za predvajanje"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Gumb za ustavitev"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ni storitve."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index d7ae794..b7c439b 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Откуцајте лозинку да бисте откључали"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Унесите PIN за откључавање"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN кôд је нетачан."</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_plugged_in" msgid="9087497435553252863">"Пуњење"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Повежите пуњач."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM картица је закључана."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM картица је закључана PUK кодом."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Откључавање SIM картице…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Виџет %2$d од %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Додај виџет."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Празно"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Област откључавања је проширена."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Област откључавања је скупљена."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Избор корисника"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Контроле за медије"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Започела је промена редоследа виџета."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Промена редоследа виџета је завршена."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> је избрисан."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Прошири област откључавања."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Откључавање превлачењем."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Откључавање шаблоном."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Откључавање лицем."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Откључавање PIN-ом."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Област за PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Област за PIN за SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Област за PUK за SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Дугме за претходну песму"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Дугме за следећу песму"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Дугме за паузу"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Дугме за репродукцију"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Дугме за заустављање"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Свиђа ми се"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Не свиђа ми се"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Срце"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Откључајте да бисте наставили"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Покретање је отказано"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Отпустите виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> да бисте га избрисали."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Виџет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> неће бити избрисан."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Следећи аларм је подешен за <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Откажи"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Избриши"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Промена режима"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Откључај"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Нечујно"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Укључи звук"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Превуците надоле за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Превуците улево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Превуците удесно за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитан позив"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Поново унесите исправни PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте PIN неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте лозинку неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
@@ -147,24 +94,21 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Нетачан SIM PIN кôд. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER">%d</xliff:g> покушај, а онда морате да контактирате мобилног оператера да бисте откључали уређај."</item>
-    <item quantity="other" msgid="2215723361575359486">"Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER">%d</xliff:g> покушаја."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
+      <item quantity="few">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја.</item>
+      <item quantity="other">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM картица је неупотребљива. Контактирајте мобилног оператера."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Нетачан SIM PUK кôд. Имате још <xliff:g id="NUMBER">%d</xliff:g> покушај пре него што SIM картица постане трајно неупотребљива."</item>
-    <item quantity="other" msgid="5477305226026342036">"Нетачан SIM PUK кôд. Имате још <xliff:g id="NUMBER">%d</xliff:g> покушаја пре него што SIM картица постане трајно неупотребљива."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Нетачан SIM PUK кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај пре него што SIM картица постане трајно неупотребљива.</item>
+      <item quantity="few">Нетачан SIM PUK кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја пре него што SIM картица постане трајно неупотребљива.</item>
+      <item quantity="other">Нетачан SIM PUK кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушаја пре него што SIM картица постане трајно неупотребљива.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Радња са SIM PIN кодом није успела!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Радња са SIM PUK кодом није успела!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кôд је прихваћен!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Дугме за претходну песму"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Дугме за следећу песму"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Дугме за паузу"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Дугме за репродукцију"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Дугме за заустављање"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index a86b489..75adc2c 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ange lösenord för att låsa upp"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ange PIN-kod för att låsa upp"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Fel PIN-kod."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Tryck på Menu och sedan på 0 om du vill låsa upp."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har försökt låsa upp med Ansiktslås för många gånger"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Batteriet har laddats"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Laddar"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Anslut din laddare."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-kortet är låst."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-kortet är PUK-låst."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Låser upp SIM-kort …"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d av %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Lägg till en widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tom"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Expanderad upplåsningsyta."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Komprimerad upplåsningsyta."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Widget för <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Användarväljare"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mediereglage"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Ändring av widgetarnas ordning har påbörjats."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ändring av widgetarnas ordning har avslutats."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Widgeten <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> har tagits bort."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Expandera upplåsningsytan."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Lås upp genom att dra."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Lås upp med grafiskt lösenord."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Lås upp med Ansiktslås."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Lås upp med PIN-kod."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Pinkodsområde"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Pinkodsområde för SIM-kort"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-kodsområde för SIM-kort"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Knapp för föregående spår"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Knapp för nästa spår"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pausknappen"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Uppspelningsknappen"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Stoppknappen"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Gillar"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Tummen ned"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Hjärta"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Lås upp om du vill fortsätta"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Lanseringen har avbrutits"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Ta bort genom att släppa <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> här."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> kommer inte att tas bort."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Nästa alarm är inställt på <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Klar"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Funktionsändring"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Skift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retur"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Lås upp"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Tyst"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ljud på"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Dra nedåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Dra åt höger för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nödsamtal"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glömt ditt grafiska lösenord?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Fel grafiskt lösenord"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koderna stämmer inte överens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Logga in med ditt Google-konto om du vill låsa upp."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Användarnamn (e-post)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Lösenord"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logga in"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ogiltigt användarnamn eller lösenord."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glömt ditt användarnamn eller lösenord?\nBesök "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Kontot kontrolleras …"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Du angav fel pinkod för SIM-kortet och måste nu kontakta operatören för att låsa upp enheten."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER">%d</xliff:g> försök återstår innan du måste kontakta operatören för att låsa upp enheten."</item>
-    <item quantity="other" msgid="2215723361575359486">"Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER">%d</xliff:g> försök återstår."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item>
+      <item quantity="one">Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER_0">%d</xliff:g> försök återstår innan du måste kontakta operatören för att låsa upp enheten.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortet är obrukbart. Kontakta operatören."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Du angav fel PUK-kod för SIM-kortet. <xliff:g id="NUMBER">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart."</item>
-    <item quantity="other" msgid="5477305226026342036">"Du angav fel PUK-kod för SIM-kortet. <xliff:g id="NUMBER">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Du angav fel PUK-kod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart.</item>
+      <item quantity="one">Du angav fel PUK-kod för SIM-kortet. <xliff:g id="NUMBER_0">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Det gick inte att låsa upp med pinkoden för SIM-kortet."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Det gick inte att låsa upp med PUK-koden för SIM-kortet."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden godkändes!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Knapp för föregående spår"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Knapp för nästa spår"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pausknappen"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Uppspelningsknappen"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Stoppknappen"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjänst."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 2e67ff7..886c22e 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Charaza nenosiri ili kufungua"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ingiza PIN ili kufungua"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Msimbo wa PIN usio sahihi."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Ili kufungua, bofya Menyu kisha 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Majaribio ya Juu ya Kufungua Uso yamezidishwa"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Betri imejaa"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Inachaji"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Unganisha chaja yako."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kadi imefungwa."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kadi imefungwa na PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Inafungua SIM kadi..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Wijeti %2$d ya %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Ongeza wijeti."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Tupu"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Eneo la kufungua limepanuliwa."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Eneo la kufungua limekunjwa."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ya wiji."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kiteuzi cha mtumiaji"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Vidhibiti vya media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Upangaji upya wa wijeti umeanza."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Upangaji upya wa wiji umekamilika."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Wiji <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> imefutwa."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Panua eneo la kufungua."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Kufungua slaidi."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Kufungua kwa ruwaza."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Kufungua kwa uso."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Kufungua kwa PIN."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Eneo la PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Eneo la PIN ya SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Eneo la PUK ya SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Kitufe cha wimbo uliotangulia"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Kitufe cha wimbo unaofuata"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Kitufe cha kusitisha"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Kitufe cha kucheza"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Kitufe cha kusitisha"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Bomba"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Si bomba"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Moyo"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Fungua ili uendelee"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Uzinduzi umeghairiwa"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Dondosha <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ili ufute."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> haitafutwa."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Kengele inayofuata imewekwa ilie saa <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Nimemaliza"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Fungua"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Kimya"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Sauti imewashwa"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Sogeza chini kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Sogeza kushoto kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Sogeza kulika kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro huo si sahihi"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Ili kufungua, ingia kwa Akaunti yako ya Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Jina la mtumiaji (barua pepe)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Nenosiri"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ingia"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Jina la mtumiaji au nenosiri batili."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Je, umesahau jina lako la mtumiaji au nenosiri?\nTembela "<b>"Bgoogle.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Inakagua akaunti…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ondoa"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Msimbo wa PIN ya SIM usiosahihi sasa lazima uwasiliane na mtoa huduma wako ili ufungue kifaa chako."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Msimbo wa PIN ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ulazimike kuwasiliana na mtoa huduma wako ili ufungue kifaa chako."</item>
-    <item quantity="other" msgid="2215723361575359486">"Msimbo wa PIN ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Msimbo wa PIN ya SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+      <item quantity="one">Msimbo wa PIN ya SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_0">%d</xliff:g> kabla ya kulazimika kuwasiliana na mtoa huduma wako ili afungue kifaa chako.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM haiwezi kutumika. Wasiliana na mtoa huduma wako."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Msimbo wa PUK ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kuacha kutumika kabisa."</item>
-    <item quantity="other" msgid="5477305226026342036">"Msimbo wa PUK ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kuacha kutumika kabisa."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Msimbo wa PUK ya SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_1">%d</xliff:g> kabla SIM haijafungwa kabisa.</item>
+      <item quantity="one">Msimbo wa PUK ya  SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_0">%d</xliff:g> kabla SIM haijfungwa kabisa.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Utendakazi wa PIN ya SIM umeshindwa!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Utendakazi wa PUK ya SIM umeshindwa!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Msimbo Umekubaliwa!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Kitufe cha wimbo wa awali"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Kitufe cha wimbo unaofuata"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Kitufe cha kusitisha"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Kitufe cha kucheza"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Kitufe cha kusimamisha"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hakuna huduma."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sw360dp/dimens.xml b/packages/Keyguard/res/values-sw360dp/dimens.xml
index 6e39a42..38658ca 100644
--- a/packages/Keyguard/res/values-sw360dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw360dp/dimens.xml
@@ -22,8 +22,4 @@
     <!-- Height of the sliding KeyguardSecurityContainer (includes 2x
          keyguard_security_view_margin) -->
     <dimen name="keyguard_security_height">400dp</dimen>
-
-    <!-- The bottom margin for the GlowPadView container -->
-    <dimen name="glowpadcontainer_bottom_margin">-48dp</dimen>
-
 </resources>
diff --git a/packages/Keyguard/res/values-sw380dp-land/dimens.xml b/packages/Keyguard/res/values-sw380dp-land/dimens.xml
deleted file mode 100644
index 20eb1be..0000000
--- a/packages/Keyguard/res/values-sw380dp-land/dimens.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/dimens.xml
-**
-** 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.
-*/
--->
-<resources>
-    <!-- Top margin for the clock view --> 
-    <dimen name="kg_clock_top_margin">48dp</dimen>
-</resources>
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index 89252cf..a487644 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -18,11 +18,6 @@
 */
 -->
 <resources>
-    <!-- Top margin for the clock view --> 
-    <dimen name="kg_clock_top_margin">85dp</dimen>
-
-    <!-- Size of margin on the right of keyguard's status view -->
-    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
 
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">100dp</dimen>
diff --git a/packages/Keyguard/res/values-sw600dp-land/integers.xml b/packages/Keyguard/res/values-sw600dp-land/integers.xml
deleted file mode 100644
index b724c90..0000000
--- a/packages/Keyguard/res/values-sw600dp-land/integers.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <integer name="kg_widget_region_weight">50</integer>
-    <integer name="kg_security_flipper_weight">50</integer>
-    <integer name="kg_glowpad_rotation_offset">0</integer>
-</resources>
diff --git a/packages/Keyguard/res/values-sw600dp-port/integers.xml b/packages/Keyguard/res/values-sw600dp-port/integers.xml
deleted file mode 100644
index 65b854a..0000000
--- a/packages/Keyguard/res/values-sw600dp-port/integers.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <integer name="kg_widget_region_weight">46</integer>
-    <integer name="kg_security_flipper_weight">54</integer>
-</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/bools.xml b/packages/Keyguard/res/values-sw600dp/bools.xml
index 00f45c1..654821a 100644
--- a/packages/Keyguard/res/values-sw600dp/bools.xml
+++ b/packages/Keyguard/res/values-sw600dp/bools.xml
@@ -15,12 +15,5 @@
 -->
 
 <resources>
-    <bool name="target_honeycomb_needs_options_menu">false</bool>
-    <bool name="show_ongoing_ime_switcher">true</bool>
-    <bool name="kg_share_status_area">false</bool>
     <bool name="kg_sim_puk_account_full_screen">false</bool>
-    <!-- No camera for you, tablet user -->
-    <bool name="kg_enable_camera_default_widget">false</bool>
-    <bool name="kg_center_small_widgets_vertically">true</bool>
-    <bool name="kg_top_align_page_shrink_on_bouncer_visible">false</bool>
 </resources>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index 74be1ff..5de1d11 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -18,50 +18,13 @@
 */
 -->
 <resources>
-    <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
-    <dimen name="keyguard_lockscreen_outerring_diameter">364dp</dimen>
-
-    <!-- Height of FaceUnlock view in keyguard -->
-    <dimen name="face_unlock_height">430dip</dimen>
-
-    <!-- target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
-    <dimen name="glowpadview_target_placement_radius">182dip</dimen>
-
-    <!-- Size of status line font in LockScreen. -->
-    <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
-
-    <!-- Keyguard dimensions -->
-    <!-- Size of the clock font in keyguard's status view -->
-    <dimen name="kg_status_clock_font_size">120dp</dimen>
 
     <!-- Size of the generic status lines keyguard's status view  -->
     <dimen name="kg_status_line_font_size">16sp</dimen>
 
-    <!-- Top margin for the clock view --> 
-    <dimen name="kg_clock_top_margin">0dp</dimen>
-
-    <!-- Size of margin on the right of keyguard's status view -->
-    <dimen name="kg_status_line_font_right_margin">50dp</dimen>
-
-    <!-- Horizontal padding for the widget pager -->
-    <dimen name="kg_widget_pager_horizontal_padding">24dp</dimen>
-
-    <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
-
-    <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
-
-    <!-- Top margin for the runway lights. We add a negative margin in large
-        devices to account for the widget pager padding -->
-    <dimen name="kg_runway_lights_top_margin">-10dp</dimen>
-
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_margin">12dp</dimen>
 
-    <!-- Margin around the various security views -->
-    <dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
-
     <!-- Overload default clock widget parameters -->
     <dimen name="widget_big_font_size">140dp</dimen>
     <dimen name="widget_label_font_size">16sp</dimen>
diff --git a/packages/Keyguard/res/values-sw600dp/integers.xml b/packages/Keyguard/res/values-sw600dp/integers.xml
deleted file mode 100644
index de9829c..0000000
--- a/packages/Keyguard/res/values-sw600dp/integers.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <integer name="kg_carousel_angle">60</integer>
-</resources>
diff --git a/packages/Keyguard/res/values-sw720dp-land/dimens.xml b/packages/Keyguard/res/values-sw720dp-land/dimens.xml
deleted file mode 100644
index 731bb64..0000000
--- a/packages/Keyguard/res/values-sw720dp-land/dimens.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/dimens.xml
-**
-** 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.
-*/
--->
-<resources>
-    <!-- Top margin for the clock view --> 
-    <dimen name="kg_clock_top_margin">174dp</dimen>
-
-    <!-- Size of margin on the right of keyguard's status view -->
-    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
-
-    <!-- Horizontal padding for the widget pager -->
-    <dimen name="kg_widget_pager_horizontal_padding">32dp</dimen>
-
-    <dimen name="widget_big_font_size">150dp</dimen>
-</resources>
diff --git a/packages/Keyguard/res/values-sw720dp-port/integers.xml b/packages/Keyguard/res/values-sw720dp-port/integers.xml
deleted file mode 100644
index 5f85f71..0000000
--- a/packages/Keyguard/res/values-sw720dp-port/integers.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <integer name="kg_widget_region_weight">48</integer>
-    <integer name="kg_security_flipper_weight">52</integer>
-</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 86d155e..428c18e 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -17,40 +17,6 @@
 */
 -->
 <resources>
-    <!-- Keyguard dimensions -->
-    <!-- Size of the clock font in keyguard's status view -->
-    <dimen name="kg_status_clock_font_size">140dp</dimen>
-
-    <!-- Top margin for the clock view --> 
-    <dimen name="kg_clock_top_margin">0dp</dimen>
-
-    <!-- Size of margin on the right of keyguard's status view -->
-    <dimen name="kg_status_line_font_right_margin">32dp</dimen>
-
-    <!-- Horizontal padding for the widget pager -->
-    <dimen name="kg_widget_pager_horizontal_padding">80dp</dimen>
-
-    <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
-
-    <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
-
-    <!-- Top margin for the runway lights. We add a negative margin in large
-        devices to account for the widget pager padding -->
-    <dimen name="kg_runway_lights_top_margin">-30dp</dimen>
-
-    <!-- Margin around the various security views -->
-    <dimen name="keyguard_muliuser_selector_margin">24dp</dimen>
-
-    <!-- Stroke width of the frame for the circular avatars. -->
-    <dimen name="keyguard_avatar_frame_stroke_width">3dp</dimen>
-
-    <!-- Size of the avator on the multiuser lockscreen. -->
-    <dimen name="keyguard_avatar_size">88dp</dimen>
-
-    <!-- Size of the text under the avator on the multiuser lockscreen. -->
-    <dimen name="keyguard_avatar_name_size">12sp</dimen>
 
     <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
     <dimen name="keyguard_security_width">420dp</dimen>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 19a02b9..89c1480 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"திறக்க, கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"திறக்க, பின்னை உள்ளிடவும்"</string>
     <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_plugged_in" msgid="9087497435553252863">"சார்ஜாகிறது"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"உங்கள் சார்ஜரை இணைக்கவும்."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"சிம் கார்டு பூட்டப்பட்டுள்ளது."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"சிம் கார்டு PUK ஆல் பூட்டப்பட்டது."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"சிம் கார்டின் தடையைநீக்குகிறது..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. விட்ஜெட் %2$d / %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"விட்ஜெட்டைச் சேர்க்கவும்."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"காலியானது"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"திறக்கும் பகுதி விரிவாக்கப்பட்டது."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"திறக்கும் பகுதி சுருக்கப்பட்டது."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> விட்ஜெட்."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"பயனர் தேர்வி"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"கேமரா"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"மீடியா கட்டுப்பாடுகள்"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"விட்ஜெட்டை மீண்டும் வரிசைப்படுத்துவது தொடங்கியது."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"விட்ஜெட்டை மீண்டும் வரிசைப்படுத்துவது முடிந்தது."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"விட்ஜெட் <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> நீக்கப்பட்டது."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"திறப்பதற்கான பகுதியை விவரிக்கவும்."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"ஸ்லைடு மூலம் திறத்தல்."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"வடிவம் மூலம் திறத்தல்."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"முகத்தால் திறத்தல்."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin மூலம் திறத்தல்."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN பகுதி"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"சிம் PIN பகுதி"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"சிம் PUK பகுதி"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"முந்தைய டிராக்கிற்கான பொத்தான்"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"அடுத்த டிராக்கிற்கான பொத்தான்"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"இடைநிறுத்த பொத்தான்"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"இயக்கு பொத்தான்"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"நிறுத்து பொத்தான்"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"நன்று"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"சரியில்லை"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"இதயம்"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"தொடர திறக்கவும்"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"துவக்குவது ரத்துசெய்யப்பட்டது"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"நீக்குவதற்கு <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ஐ இழுக்கவும்."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> நீக்கப்படாது."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"அடுத்த அலாரம் <xliff:g id="ALARM">%1$s</xliff:g>க்கு அமைக்கப்பட்டது"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ரத்துசெய்"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"நீக்கு"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"முடிந்தது"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"முறையை மாற்று"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ஷிஃப்டு"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"உள்ளிடு"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"தடைநீக்கு"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"கேமரா"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"நிசப்தம்"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ஒலியை இயக்கு"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> க்குக் கீழாக இழுக்கவும்."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> க்கு இடதுபக்கமாக இழுக்கவும்."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> க்கு வலதுபக்கமாக இழுக்கவும்."</string>
-    <string name="user_switched" msgid="3768006783166984410">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"அவசரகால அழைப்பு"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"வடிவத்தை மறந்துவிட்டீர்களா"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"தவறான வடிவம்"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம் ஐ நிரந்தரமாக முடக்கிவிடும்."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"பின் குறியீடுகள் பொருந்தவில்லை"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"அதிகமான வடிவ முயற்சிகள்"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"திறக்க, உங்கள் Google கணக்கு மூலம் உள்நுழையவும்."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"பயனர்பெயர் (மின்னஞ்சல்)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"கடவுச்சொல்"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"உள்நுழைக"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"தவறான பயனர்பெயர் அல்லது கடவுச்சொல்."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"உங்கள் பயனர்பெயர் அல்லது கடவுச்சொல்லை மறந்துவிட்டீர்களா?\n"<b>"google.com/accounts/recovery"</b>" ஐப் பார்வையிடவும்."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"கணக்கைச் சரிபார்க்கிறது…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் டேப்லெட்டைத் திறக்க கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"அகற்று"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"சிம் பின் குறியீடு தவறானது, உங்கள் சாதனத்தின் தடையை நீக்க, உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"சிம் பின் குறியீடு தவறானது, உங்கள் சாதனத்தைத் திறக்க, உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளும் முன், மேலும் <xliff:g id="NUMBER">%d</xliff:g> முறை முயர்ச்சிக்கலாம்."</item>
-    <item quantity="other" msgid="2215723361575359486">"சிம் பின் குறியீடு தவறானது, மேலும் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">சிம்மின் பின் குறியீடு தவறானது, உங்களிடம் <xliff:g id="NUMBER_1">%d</xliff:g> முயற்சிகள் மீதமுள்ளன.</item>
+      <item quantity="one">சிம்மின் பின் குறியீடு தவறானது, மேலும் <xliff:g id="NUMBER_0">%d</xliff:g> முயற்சிக்குப் பின்னர், சாதனத்தைத் திறக்க, கண்டிப்பாக உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"சிம் பயன்பாட்டிற்கு உகந்தது அல்ல. உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"சிம் PUK குறியீடு தவறானது, சிம் நிரந்தரமாகப் பயன்படுத்த முடியாமல் போவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயர்ச்சிக்கலாம்."</item>
-    <item quantity="other" msgid="5477305226026342036">"சிம் PUK குறியீடு தவறானது, சிம் நிரந்தரமாகப் பயன்படுத்த முடியாமல் போவதற்கு முன், நீங்கள் <xliff:g id="NUMBER">%d</xliff:g> முறை முயற்சிக்கலாம்."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">சிம் PUK குறியீடு தவறானது, நிரந்தரமாக சிம் முடக்கப்படும் முன், நீங்கள் <xliff:g id="NUMBER_1">%d</xliff:g> முறை முயற்சிக்கலாம்.</item>
+      <item quantity="one">சிம்மின் PUK குறியீடு தவறானது, நிரந்தரமாக சிம் முடக்கப்படும் முன், நீங்கள் <xliff:g id="NUMBER_0">%d</xliff:g> முறை முயற்சிக்கலாம்.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"சிம் பின் செயல்பாடு தோல்வி!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"சிம் PUK செயல்பாடு தோல்வி!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"குறியீடு ஏற்கப்பட்டது!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"முந்தைய டிராக்கிற்கான பொத்தான்"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"அடுத்த டிராக்கிற்கான பொத்தான்"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"இடைநிறுத்த பொத்தான்"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"இயக்கு பொத்தான்"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"நிறுத்து பொத்தான்"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"சேவை இல்லை."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index 30173b0..2f51742 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"అన్‌లాక్ చేయడానికి పాస్‌వర్డ్‌ను టైప్ చేయండి"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"అన్‌లాక్ చేయడానికి పిన్‌ను టైప్ చేయండి"</string>
     <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_plugged_in" msgid="9087497435553252863">"ఛార్జ్ అవుతోంది"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"మీ ఛార్జర్‌ను కనెక్ట్ చేయండి."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"సిమ్ కార్డు లాక్ చేయబడింది."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"సిమ్ కార్డు PUK లాక్ చేయబడింది."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"సిమ్ కార్డును అన్‌లాక్ చేస్తోంది…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. %3$dలో విడ్జెట్ %2$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"విడ్జెట్‌ను జోడించండి."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ఖాళీ"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"అన్‌లాక్ ప్రాంతం విస్తరించబడింది."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"అన్‌లాక్ ప్రాంతం కుదించబడింది."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> విడ్జెట్."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"వినియోగదారు ఎంపికకర్త"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"కెమెరా"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"మీడియా నియంత్రణలు"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"విడ్జెట్ పునఃక్రమం ప్రారంభించబడింది."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"విడ్జెట్ పునఃక్రమం ముగిసింది."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"విడ్జెట్ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> తొలగించబడింది."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"అన్‌లాక్ ప్రాంతాన్ని విస్తరింపజేయండి."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"స్లయిడ్ అన్‌లాక్."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"నమూనా అన్‌లాక్."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"ముఖంతో అన్‌లాక్."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"పిన్ అన్‌లాక్."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN ప్రాంతం"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN ప్రాంతం"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK ప్రాంతం"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"మునుపటి ట్రాక్ బటన్"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"తదుపరి ట్రాక్ బటన్"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"పాజ్ బటన్"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ప్లే బటన్"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ఆపివేత బటన్"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"బాగుంది"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"బాగాలేదు"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"హృదయ చిహ్నం"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"కొనసాగడానికి అన్‌లాక్ చేయండి"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ప్రారంభం రద్దయింది"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"తొలగించడానికి <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ను వదలండి."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> తొలగించబడదు."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"తదుపరి అలారం <xliff:g id="ALARM">%1$s</xliff:g>కి సెట్ చేయబడింది"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"రద్దు చేయి"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"తొలగించు"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"పూర్తయింది"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"మోడ్ మార్పు"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"అన్‌లాక్ చేయండి"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"కెమెరా"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"నిశ్శబ్దం చేయండి"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"ధ్వని ఆన్‌లో ఉంది"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> కోసం క్రిందికి స్లైడ్ చేయండి."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> కోసం ఎడమవైపుకు స్లైడ్ చేయండి."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> కోసం కుడివైపుకు స్లైడ్ చేయండి."</string>
-    <string name="user_switched" msgid="3768006783166984410">"ప్రస్తుత వినియోగదారు <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"అత్యవసర కాల్"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"నమూనాను మర్చిపోయాను"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"నమూనా తప్పు"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. పునరావృత ప్రయత్నాల వలన సిమ్ శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"పిన్‌ కోడ్‌లు సరిపోలలేదు"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"చాలా ఎక్కువ నమూనా ప్రయత్నాలు చేసారు"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"అన్‌లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"వినియోగదారు పేరు (ఇమెయిల్)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"పాస్‌వర్డ్"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"సైన్ ఇన్ చేయి"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"చెల్లని వినియోగదారు పేరు లేదా పాస్‌వర్డ్."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"మీ వినియోగదారు పేరు లేదా పాస్‌వర్డ్‌ను మర్చిపోయారా?\n"<b>"google.com/accounts/recovery"</b>"ని సందర్శించండి."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"ఖాతాను తనిఖీ చేస్తోంది…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"తీసివేయి"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"సిమ్ పిన్ కోడ్ చెల్లదు, మీరు ఇప్పుడు మీ పరికరాన్ని అన్‌లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించండి."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"సిమ్ పిన్ కోడ్ చెల్లదు, మీరు మీ పరికరాన్ని అన్‌లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించాల్సిన పరిస్థితి ఏర్పడకుండా ఉండటానికి మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది."</item>
-    <item quantity="other" msgid="2215723361575359486">"సిమ్ పిన్ కోడ్ చెల్లదు, మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN కోడ్ చెల్లదు, మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
+      <item quantity="one">SIM PIN కోడ్ చెల్లదు, మీరు మీ పరికరాన్ని అన్‌లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించడానికి ముందు మీకు <xliff:g id="NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"సిమ్ నిరుపయోగమైనది. మీ క్యారియర్‌ను సంప్రదించండి."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"సిమ్ PUK కోడ్ చెల్లదు, సిమ్ శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది."</item>
-    <item quantity="other" msgid="5477305226026342036">"సిమ్ PUK కోడ్ చెల్లదు, సిమ్ శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK కోడ్ చెల్లదు, SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
+      <item quantity="one">SIM PUK కోడ్ చెల్లదు, SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"సిమ్ పిన్ చర్య విఫలమైంది!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"సిమ్ PUK చర్య విఫలమైంది!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"కోడ్ ఆమోదించబడింది!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"మునుపటి ట్రాక్ బటన్"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"తదుపరి ట్రాక్ బటన్"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"పాజ్ బటన్"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ప్లే బటన్"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ఆపివేత బటన్"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"సేవ లేదు."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 1d7bc66..6d0d026 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"พิมพ์รหัสผ่านเพื่อปลดล็อก"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"พิมพ์ PIN เพื่อปลดล็อก"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"รหัส PIN ไม่ถูกต้อง"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"หากต้องการปลดล็อก กด เมนู ตามด้วย 0"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"มีความพยายามที่จะใช้ Face Unlock เกินขีดจำกัด"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"ชาร์จแล้ว"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"กำลังชาร์จ"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"เสียบที่ชาร์จของคุณ"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"ซิมการ์ดถูกล็อก"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"ซิมการ์ดถูกล็อกด้วย PUK"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"กำลังปลดล็อกซิมการ์ด…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s วิดเจ็ต %2$d ของ %3$d"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"เพิ่มวิดเจ็ต"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"ว่าง"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"ขยายพื้นที่ปลดล็อกแล้ว"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"ยุบพื้นที่ปลดล็อกแล้ว"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"วิดเจ็ต <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"ตัวเลือกผู้ใช้"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"กล้องถ่ายรูป"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"การควบคุมสื่อ"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"เริ่มเรียงลำดับวิดเจ็ตใหม่"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"เรียงลำดับวิดเจ็ตใหม่เสร็จแล้ว"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ลบวิดเจ็ต <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> แล้ว"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"ขยายพื้นที่ปลดล็อก"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"การปลดล็อกด้วยการเลื่อน"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"การปลดล็อกด้วยรูปแบบ"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"การปลดล็อกด้วยใบหน้า"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"การปลดล็อกด้วย PIN"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"พื้นที่ PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"พื้นที่ PIN ของซิม"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"พื้นที่ PUK ของซิม"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"ปุ่มแทร็กก่อนหน้า"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"ปุ่มแทร็กถัดไป"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"ปุ่มหยุดชั่วคราว"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"ปุ่มเล่น"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"ปุ่มหยุด"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"สุดยอด"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"ไม่ชอบ"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"หัวใจ"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"ปลดล็อกเพื่อดำเนินการต่อ"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"ยกเลิกการเปิดใช้งานแล้ว"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"ลาก <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> เพื่อลบ"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> จะไม่ถูกลบ"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"ตั้งเวลาปลุกครั้งถัดไปไว้ที่ <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ยกเลิก"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ลบ"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"เสร็จสิ้น"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"เปลี่ยนโหมด"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ป้อน"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"ปลดล็อก"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"กล้อง"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"ปิดเสียง"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"เปิดเสียง"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"เลื่อนลงเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"เลื่อนไปทางซ้ายเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"เลื่อนไปทางขวาเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
-    <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"หมายเลขฉุกเฉิน"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ลืมรูปแบบใช่หรือไม่"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"รูปแบบไม่ถูกต้อง"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"หากต้องการปลดล็อก ให้ลงชื่อเข้าใช้ด้วยบัญชี Google ของคุณ"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"ชื่อผู้ใช้ (อีเมล)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"รหัสผ่าน"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"ลงชื่อเข้าใช้"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน\nโปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"กำลังตรวจสอบบัญชี…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ลบ"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่จะต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</item>
-    <item quantity="other" msgid="2215723361575359486">"รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้ง"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
+      <item quantity="one">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งก่อนที่จะต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"ซิมไม่สามารถใช้งานได้ ติดต่อผู้ให้บริการของคุณ"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร"</item>
-    <item quantity="other" msgid="5477305226026342036">"รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร</item>
+      <item quantity="one">รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"การปลดล็อกด้วย PIN ของซิมล้มเหลว!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"การปลดล็อกด้วย PUK ของซิมล้มเหลว!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"รหัสได้รับการยอมรับ!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ปุ่มแทร็กก่อนหน้า"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ปุ่มแทร็กถัดไป"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"ปุ่มหยุดชั่วคราว"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"ปุ่มเล่น"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"ปุ่มหยุด"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index fb03d07..8125efe 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"I-type ang password upang i-unlock"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"I-type ang PIN upang i-unlock"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Maling PIN code."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Upang i-unlock, pindutin ang Menu pagkatapos ay 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nalagpasan na ang maximum na mga pagtatangka sa Face Unlock"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Na-charge"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nagtsa-charge"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Ikonekta ang iyong charger."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Naka-lock ang SIM card."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Naka-lock ang SIM card gamit ang PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ina-unlock ang SIM card…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d ng %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Magdagdag ng widget."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Walang laman"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Pinalaki ang bahagi ng pag-unlock."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Pinaliit ang bahagi ng pag-unlock."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Tagapili ng user"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Camera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Mga kontrol ng media"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Nagsimula na ang pagbabago ng ayos ng widget."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Natapos na ang pagbabago ng ayos ng widget."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Tinanggal ang widget na <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Palakihin ang bahagi ng pag-unlock."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Pag-unlock ng slide."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Pag-unlock ng pattern."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Face unlock."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pag-unlock ng pin."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Lugar ng PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Lugar ng PIN ng SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Lugar ng PUK ng SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Button na Nakaraang track"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Button na Susunod na track"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Button na I-pause"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Button na I-play"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Button na Ihinto"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Thumbs up"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Thumbs down"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Heart"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"I-unlock upang magpatuloy"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Nakansela ang paglunsad"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"I-drop ang <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> upang tanggalin."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"Hindi tatanggalin ang <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Nakatakda ang susunod na alarm para sa <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselahin"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tanggalin"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Tapos na"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Pagbabago ng Mode"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"I-unlock"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Camera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Tahimik"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"I-on ang tunog"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Mag-slide pababa para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Mag-slide pakaliwa para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Mag-slide pakanan para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency na tawag"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nakalimutan ang Pattern"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Maling Pattern"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Muling ilagay ang tamang PUK code. Permanenteng hindi pagaganahin ang SIM ng mga paulit-ulit na pagtatangka."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Hindi tumutugma ang mga PIN code"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Upang i-unlock, mag-sign in gamit ang iyong Google account."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Mag-sign in"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Di-wastong username o password."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nakalimutan ang iyong username o password?\nBisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Tinitingnan ang account…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Maling PIN code ng SIM, dapat ka nang makipag-ugnay sa iyong carrier upang i-unlock ang iyong device."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok bago ka dapat makipag-ugnay sa iyong carrier upang i-unlock ang iyong device."</item>
-    <item quantity="other" msgid="2215723361575359486">"Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
+      <item quantity="other">Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> na natitirang pagsubok.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Hindi magagamit ang SIM. Makipag-ugnay sa iyong carrier."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Maling PUK code ng SIM, mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok bago maging permanenteng hindi magagamit ang SIM."</item>
-    <item quantity="other" msgid="5477305226026342036">"Maling PUK code ng SIM, mayroon kang <xliff:g id="NUMBER">%d</xliff:g> (na) natitirang pagsubok bago maging permanenteng hindi magagamit ang SIM."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Maling PUK code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok bago tuluyang hindi magamit ang SIM.</item>
+      <item quantity="other">Maling PUK code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> na natitirang pagsubok bago tuluyang hindi magamit ang SIM.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Nabigo ang operasyon ng SIM PIN!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nabigo ang operasyon ng SIM PUK!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Tinanggap ang Code!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Button na Nakaraang track"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Button na Susunod na track"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Button na I-pause"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Button na I-play"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Button na Ihinto"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Walang serbisyo."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 3bc4860..aa32baa 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Kilidi açmak için şifreyi yazın"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Kilidi açmak için PIN kodunu yazın"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Yanlış PIN kodu."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Yüz Tanıma Kilidi için maksimum deneme sayısı aşıldı"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Şarj oldu"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Şarj oluyor"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Şarj cihazınızı takın."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kart kilitli."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kart PUK kilidi devrede."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM kart kilidi açılıyor…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Widget %2$d / %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Widget ekleyin."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Boş"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Kilit açma alanı genişletildi."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Kilit açma alanı daraltıldı."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget\'ı."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Kullanıcı seçici"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Medya denetimleri"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widget\'ları yeniden sıralama işlemi başladı."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widget\'ları yeniden sıralama işlemi bitti."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget\'ı silindi."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Kilit açma alanını genişletin."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Kaydırarak kilit açma."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Desenle kilit açma."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Yüzle kilit açma."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin koduyla kilit açma."</string>
@@ -69,45 +53,15 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN alanı"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN alanı"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK alanı"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Önceki parça düğmesi"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Sonraki parça düğmesi"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Duraklat düğmesi"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Oynat düğmesi"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Durdur düğmesi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Beğen"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Beğenme"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Kalp"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Devam etmek için kilidini açın"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Başlatma iptal edildi"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Silmek için <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widget\'ını bırakın."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> silinmeyecek."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Sonraki alarm <xliff:g id="ALARM">%1$s</xliff:g> için ayarlandı"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"İptal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Sil"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Bitti"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mod değiştirme"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ÜstKrkt"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Giriş"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Kilidi aç"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Sessiz"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ses açık"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için aşağı kaydırın."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sola kaydırın."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için sağa kaydırın."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Acil durum çağrısı"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Deseni Unuttunuz mu?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Yanlış Desen"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Yanlış Şifre"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Yanlış PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Deseninizi çizin"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" için SIM PIN\'ini girin"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları eşleşmiyor"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Kilidi açmak için Google hesabınızla oturum açın."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kullanıcı adı (e-posta)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Şifre"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Oturum aç"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Geçersiz kullanıcı adı veya şifre."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?\n"<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Hesap denetleniyor…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için artık operatörünüzle bağlantı kurmanız gerekiyor."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Yanlış SIM PIN kodu. Cihazının kilidini açmak için operatörünüzle bağlantı kurmak zorunda kalmadan önce <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-    <item quantity="other" msgid="2215723361575359486">"Yanlış SIM PIN kodu. <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
+      <item quantity="one">Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için operatörünüzle bağlantı kurmak zorunda kalmadan önce <xliff:g id="NUMBER_0">%d</xliff:g> deneme hakkınız kaldı.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM kullanılamaz. Operatörünüzle bağlantı kurun."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Yanlış SIM PUK kodu. SIM kalıcı olarak kullanılmaz hale gelmeden önce <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-    <item quantity="other" msgid="5477305226026342036">"Yanlış SIM PUK kodu. SIM kalıcı olarak kullanılmaz hale gelmeden önce <xliff:g id="NUMBER">%d</xliff:g> deneme hakkınız kaldı."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Yanlış SIM PUK kodu, SIM kalıcı olarak kullanılmaz hale gelmeden önce <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
+      <item quantity="one">Yanlış SIM PUK kodu, SIM kalıcı olarak kullanılmaz hale gelmeden önce <xliff:g id="NUMBER_0">%d</xliff:g> deneme hakkınız kaldı.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN işlemi başarısız oldu!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK işlemi başarısız oldu!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Kabul Edildi!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Önceki parça düğmesi"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Sonraki parça düğmesi"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Duraklat düğmesi"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Oynat düğmesi"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Durdur düğmesi"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hizmet yok."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 3cb0b89..9e52283 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Введіть пароль, щоб розблокувати"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Введіть PIN-код, щоб розблокувати"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Неправильний PIN-код."</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_plugged_in" msgid="9087497435553252863">"Заряджається"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Підключіть зарядний пристрій."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-карту заблоковано."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-карту заблоковано PUK-кодом."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Розблокування SIM-карти…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Віджет %2$d з %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Додати віджет."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Порожня область"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Область розблокування розгорнуто."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Область розблокування згорнуто."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Віджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Вибір користувача"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Камера"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Елементи керування носієм"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Змінення порядку віджетів розпочато."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Змінення порядку віджетів закінчено."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Віджет <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> видалено."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Розгорнути область розблокування."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Розблокування повзунком."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Розблокування ключем."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Фейсконтроль"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Розблокування PIN-кодом."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN-код"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"PIN-код SIM-карти"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"PUK-код SIM-карти"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Кнопка \"Попередня композиція\""</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Кнопка \"Наступна композиція\""</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Кнопка \"Призупинити\""</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Кнопка \"Відтворити\""</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Кнопка \"Зупинити\""</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Подобається"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Не подобається"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Рейтинг"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Розблокуйте, щоб продовжити"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Запуск скасовано"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Відпустіть <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>, щоб видалити."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> не буде видалено."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Наступний сигнал: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Скасувати"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Готово"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Зміна режиму"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Розблокувати"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Камера"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Без звуку"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Увімкнути звук"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Проведіть пальцем униз, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Проведіть пальцем праворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Екстрений виклик"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Не пам’ятаю ключ"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильний ключ"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коди не збігаються"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Забагато спроб намалювати ключ"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Щоб розблокувати, увійдіть, використовуючи дані облікового запису Google."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Ім’я користувача (електронна адреса)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увійти"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Недійсне ім’я користувача чи пароль."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Не пам’ятаєте ім’я користувача чи пароль?\nВідвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Перевірка облікового запису…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
@@ -147,24 +94,23 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Вилучити"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неправильний PIN-код SIM-карти. Зв’яжіться зі своїм оператором, щоб розблокувати пристрій."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Неправильний PIN-код SIM-карти. У вас залишилась <xliff:g id="NUMBER">%d</xliff:g> спроба. Після цього потрібно буде зв’язатися з оператором, щоб розблокувати пристрій."</item>
-    <item quantity="other" msgid="2215723361575359486">"Неправильний PIN-код SIM-карти. У вас залишилося стільки спроб: <xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Неправильний PIN-код SIM-карти. У вас залишилась <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
+      <item quantity="few">Неправильний PIN-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби.</item>
+      <item quantity="many">Неправильний PIN-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроб.</item>
+      <item quantity="other">Неправильний PIN-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-карту заблоковано. Зв’яжіться з оператором."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Неправильний PUK-код SIM-карти. У вас залишилась <xliff:g id="NUMBER">%d</xliff:g> спроба. Після цього SIM-карту буде назавжди заблоковано."</item>
-    <item quantity="other" msgid="5477305226026342036">"Неправильний PUK-код SIM-карти. У вас залишилося стільки спроб: <xliff:g id="NUMBER">%d</xliff:g>. Після цього SIM-карту буде назавжди заблоковано."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Неправильний PUK-код SIM-карти. У вас залишилася <xliff:g id="NUMBER_1">%d</xliff:g> спроба. Після цього SIM-карту буде назавжди заблоковано.</item>
+      <item quantity="few">Неправильний PUK-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано.</item>
+      <item quantity="many">Неправильний PUK-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде назавжди заблоковано.</item>
+      <item quantity="other">Неправильний PUK-код SIM-карти. У вас залишилося <xliff:g id="NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Помилка введення PIN-коду SIM-карти."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Помилка введення PUK-коду SIM-карти."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код прийнято."</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Кнопка \"Попередня композиція\""</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Кнопка \"Наступна композиція\""</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Кнопка \"Призупинити\""</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Кнопка \"Відтворити\""</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Кнопка \"Зупинити\""</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index f4e4eeb..5cd54c0 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"غیر مقفل کرنے کیلئے پاس ورڈ ٹائپ کریں"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"‏غیر مقفل کرنے کیلئے PIN ٹائپ کریں"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"‏غلط PIN کوڈ۔"</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_plugged_in" msgid="9087497435553252863">"چارج ہو رہی ہے"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"اپنا چارجر مربوط کریں۔"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"‏SIM کارڈ مقفل ہے۔"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"‏SIM کارڈ PUK-مقفل ہے۔"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"‏SIM کارڈ غیر مقفل کیا جا رہا ہے…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"‏%1$s۔ ویجیٹ ‎%2$d از ‎%3$d۔"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ویجیٹ شامل کریں"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"خالی"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"غیر مقفل کرنے کا علاقہ پھیلا دیا گیا۔"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"غیر مقفل کرنے کا علاقہ سکیڑ دیا گیا۔"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ویجیٹ۔"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"صارف کا انتخاب کار"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"کیمرا"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"میڈیا کنٹرولز"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"ویجیٹ دوبارہ ترتیب دینا شروع ہو گیا۔"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"ویجیٹ دوبارہ ترتیب دینا ختم ہو گیا۔"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"ویجیٹ <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> کو حذف کر دیا گیا۔"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"غیر مقفل کرنے والے علاقے کو پھیلائیں۔"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"سلائیڈ کے ذریعے غیر مقفل کریں۔"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"پیٹرن کے ذریعے غیر مقفل کریں۔"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"چہرے کے ذریعے غیر مقفل کریں۔"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"پن کے ذریعے غیر مقفل کریں۔"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"‏PIN کا علاقہ"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"‏SIM PIN کا علاقہ"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"‏SIM PUK کا علاقہ"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"سابقہ ٹریک بٹن"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"اگلا ٹریک بٹن"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"موقوف کرنے کا بٹن"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"چلائیں بٹن"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"روکیں بٹن"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"بہت اچھا"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"بہت خراب"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"دل"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"جاری رکھنے کیلئے غیر مقفل کریں"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"شروعات کو منسوخ کر دیا گیا"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"حذف کرنے کیلئے <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> کو ڈراپ کریں۔"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> کو حذف نہیں کیا جائے گا۔"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"اگلا الارم <xliff:g id="ALARM">%1$s</xliff:g> کیلئے سیٹ ہے"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"‎?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"منسوخ کریں"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف کریں"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ہو گیا"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"وضع میں تبدیلی"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"غیر مقفل کریں"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"کیمرہ"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"خاموش کریں"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"آواز آن ہے"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> کیلئے نیچے سلائیڈ کریں۔"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> کیلئے بائیں سلائیڈ کریں۔"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> کیلئے دائیں سلائیڈ کریں۔"</string>
-    <string name="user_switched" msgid="3768006783166984410">"موجودہ صارف <xliff:g id="NAME">%1$s</xliff:g>۔"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ہنگامی کال"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"پیٹرن بھول گئے"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"غلط پیٹرن"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"‏صحیح PUK کوڈ دوبارہ درج کریں۔ بار بار کی کوششیں SIM کو مستقل طور پر غیر فعال کر دیں گی۔"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"‏PIN کوڈز مماثل نہیں ہیں"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"پیٹرن کی بہت ساری کوششیں"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"‏غیر مقفل کرنے کیلئے، اپنے Google اکاؤنٹ کے ساتھ سائن ان کریں۔"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"صارف نام (ای میل)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"پاس ورڈ"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"سائن ان کریں"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"غلط صارف نام یا پاس ورڈ۔"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"‏اپنا صارف نام یا پاس ورڈ بھول گئے؟\n"<b>"google.com/accounts/recovery"</b>" ملاحظہ کریں۔"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"اکاؤنٹ چیک کیا جا رہا ہے…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"‏آپ نے اپنا PIN <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"آپ نے اپنا پاس ورڈ <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ہٹائیں"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"‏غلط SIM PIN کوڈ اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کرنا چاہئے۔"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"‏غلط SIM PIN کوڈ، اس سے پہلے کہ آپ اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کریں آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوشش بچی ہے۔"</item>
-    <item quantity="other" msgid="2215723361575359486">"‏غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوششیں بچی ہیں۔"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">‏غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item>
+      <item quantity="one">‏غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_0">%d</xliff:g> کوشش بچی ہے، اس کے بعد آپ کو اپنا آلہ غیر مقفل کرنے کیلئے اپنے کریئر سے رابطہ کرنا ہوگا۔</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"‏SIM ناقابل استعمال ہے۔ اپنے کیریئر رابطہ کریں۔"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"‏غلط SIM PUK کوڈ، SIM مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوشش بچی ہے۔"</item>
-    <item quantity="other" msgid="5477305226026342036">"‏غلط SIM PUK کوڈ، SIM مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="NUMBER">%d</xliff:g> کوششیں بچی ہیں۔"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">‏غلط SIM PUK کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں، اس کے بعد SIM مستقل طور پر ناقابل استعمال ہو جائے گا۔</item>
+      <item quantity="one">‏SIM کا غلط PUK کوڈ، آپ ک پاس <xliff:g id="NUMBER_0">%d</xliff:g> کوشش بچی ہے، اس کے بعد SIM مستقل طور پر ناقابل استعمال ہو جائے گا۔</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"‏SIM PIN کارروائی ناکام ہو گئی!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏SIM PUK کارروائی ناکام ہو گئی!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کوڈ قبول کر لیا گیا!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"سابقہ ٹریک بٹن"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"اگلا ٹریک بٹن"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"موقوف کرنے کا بٹن"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"چلائیں بٹن"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"روکیں بٹن"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"کوئی سروس نہیں ہے۔"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index cc891b2..a6852a7 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Qulfni ochish uchun parolni kiriting"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Qulfni ochish uchun PIN-kodni kiriting"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Noto‘g‘ri PIN kod."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Qulfni ochish uchun avval \"Menu\"ni, so‘ngra 0 raqamini bosing."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Yuzni tanitib qulfni ochishga urinish miqdoridan oshib ketdi"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Zaryad to‘ldi"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Quvvat olmoqda"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Zaryadlagichni ulang."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM karta qulflangan."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM karta PUK kod bilan qulflangan."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM karta qulfi ochilmoqda…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidjet %2$d / %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Vidjet qo‘shish."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Bo‘sh"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Qulfni ochish maydoni kengaytirildi."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Qulfni ochish maydoni yig‘ildi."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vidjeti."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Foydalanuvchi tanlagichi"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Media boshqaruvlari"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Vidjetlarni saralashni boshlandi."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Vidjetlarni saralash tugatildi."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vidjeti o‘chirildi."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Qulfni ochish maydonini kengaytirish."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Qulfni silab ochish"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Chizmali qulfni ochish."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Qulfni yuzni tanitib ochish"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Pin qulfini ochish."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN kod maydoni"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM karta PIN kodi maydoni"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM karta PUK kodi maydoni"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Avvalgi qo‘shiq tugmasi"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Keyingi qo‘shiq tugmasi"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Pauza tugmasi"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Ijro etish tugmasi"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"To‘xtatish tugmasi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Yoqdi"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Yoqmadi"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Yurak"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Avval qulfni oching"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Ishga tushirish bekor qilindi"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"O‘chirish uchun <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>ni pastga tashlang."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> o‘chirilmaydi."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Keyingi uyg‘otkich <xliff:g id="ALARM">%1$s</xliff:g> uchun o‘rnatildi"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Bekor qilish"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"O‘chirish"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Tayyor"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Usulni o‘zgartirish"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Kiritish"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Qulfni ochish"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Kamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Ovozsiz"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Ovoz yoqib qo‘yilgan"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string>
-    <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string>
-    <string name="description_direction_down" msgid="5087739728639014595">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun pastga suring."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun o‘ngga suring."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Joriy foydalanuvchi <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Favqulodda qo‘ng‘iroq"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Chizmali parol unutilgan"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Xato chizma paroli"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"To‘g‘ri PUK kodni qayta kiriting. Qayta-qayta urinishlar SIM kartani butunlay o‘chirib qo‘yadi."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodlar bir xil emas"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Qulfni ochish uchun Google hisobingiz bilan kiring."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Foydalanuvchi nomi (e-pochta)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parol"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Hisobga kirish"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Foydalanuvchi nomi yoki parol xato."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Foydalanuvchi nomingiz yoki parolingizni unutdingizmi?\n "<b>"google.com/accounts/recovery"</b>"ga tashrif buyuring."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Hisob tekshirilmoqda…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodingizni <xliff:g id="NUMBER_0">%d</xliff:g> marta xato kiritdingiz. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qaytadan urinib ko‘ring."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Parolingizni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qaytadan urinib ko‘ring."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Chizmali parolingizni <xliff:g id="NUMBER_0">%d</xliff:g> marta xato chizdingiz. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qaytadan urinib ko‘ring."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Chizmali parolni  <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Chizmali parolni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"O‘chirish"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM karta PIN kodi noto‘g‘ri. Qurilma qulfini ochish uchun aloqa operatoringiz bilan bog‘laning."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM karta PIN kodi noto‘g‘ri terildi, yana <xliff:g id="NUMBER">%d</xliff:g> marta uirinib ko‘rishingiz mumkin, urinishlar tugagandan keyin qurilmangizni qulfdan chiqarish uchun aloqa operatoringiz bilan bog‘lanishingiz kerak."</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM karta PIN kodi noto‘g‘ri terildi, yana <xliff:g id="NUMBER">%d</xliff:g> marta urinib ko‘rishingiz mumkin."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM kartaning PIN kodi noto‘g‘ri. Sizda yana <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish qoldi.</item>
+      <item quantity="one">SIM kartaning PIN kodi noto‘g‘ri. Qurilmani qulfdan chiqarish uchun sizda yana <xliff:g id="NUMBER_0">%d</xliff:g> ta urinish qoldi.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM kartadan foydalanib bo‘lmaydi. Aloqa operatoringiz bilan bog‘laning."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM karta PUK kodi noto‘g‘ri terildi, yana <xliff:g id="NUMBER">%d</xliff:g> marta urinib ko‘rganingizdan so‘ng, SIM kartadan umuman foydalanib bo‘lmaydi."</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM karta PUK kodi noto‘g‘ri terildi, yana <xliff:g id="NUMBER">%d</xliff:g> marta urinib ko‘rganingizdan so‘ng, SIM kartadan umuman foydalanib bo‘lmaydi."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM kartaning PUK kodi noto‘g‘ri kiritildi. Yana <xliff:g id="NUMBER_1">%d</xliff:g> ta muvaffaqiyatsiz urinishdan so‘ng SIM karta butunlay ishdan chiqadi.</item>
+      <item quantity="one">SIM kartaning PUK kodi noto‘g‘ri kiritildi. Yana <xliff:g id="NUMBER_0">%d</xliff:g> ta muvaffaqiyatsiz urinishdan so‘ng SIM karta butunlay ishdan chiqadi.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM karta PIN jarayoni amalga oshmadi!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM karta PUK jarayoni amalga oshmadi!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod qabul qilindi!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Avvalgi qo‘shiq tugmasi"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Keyingi qo‘shiq tugmasi"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Pauza tugmasi"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Ijro etish tugmasi"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"To‘xtatish tugmasi"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aloqa yo‘q."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 0190f1c..5727900 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Nhập mật khẩu để mở khóa"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Nhập mã PIN để mở khóa"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Mã PIN không chính xác."</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Để mở khóa, hãy nhấn vào Menu sau đó nhấn 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Đã vượt quá số lần Mở khóa bằng khuôn mặt tối đa"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Pin đầy"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Đang sạc"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Kết nối bộ sạc của bạn."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Thẻ SIM đã bị khóa."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Thẻ SIM đã bị khóa PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Đang mở khóa thẻ SIM…"</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Tiện ích %2$d trong số %3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Thêm tiện ích."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Trống"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Đã mở rộng vùng khóa."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Đã thu gọn vùng khóa."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> tiện ích."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Bộ chọn người dùng"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Máy ảnh"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Điều khiển phương tiện"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Đã bắt đầu xắp xếp lại tiện ích."</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Đã kết thúc sắp xếp lại tiện ích."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Đã xóa tiện ích <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Mở rộng vùng khóa."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Mở khóa bằng cách trượt."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Mở khóa bằng hình."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Mở khóa bằng khuôn mặt."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Mở khóa bằng mã pin."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Khu vực mã PIN"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Khu vực mã PIN của SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Khu vực PUK của SIM"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Nút bản nhạc trước"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Nút bản nhạc tiếp theo"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Nút tạm dừng"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Nút phát"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Nút dừng"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Bài hát được đánh dấu thích"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Bài hát được đánh dấu không thích"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Trái tim"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Mở khóa để tiếp tục"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Quá trình chạy bị hủy"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Thả <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> để xóa."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> sẽ không bị xóa."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Báo thức tiếp theo được đặt cho <xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hủy"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Xóa"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Xong"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Thay đổi chế độ"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Mở khóa"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Máy ảnh"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Im lặng"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Bật âm thanh"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Trượt xuống để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Trượt sang trái để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Trượt sang phải để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Cuộc gọi khẩn cấp"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Đã quên hình"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Hình sai"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Mã PIN không khớp"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Để mở khóa, hãy đăng nhập bằng tài khoản Google của bạn."</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Tên người dùng (email)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mật khẩu"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Đăng nhập"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?\nHãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Đang kiểm tra tài khoản…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy \n\nthử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Mã PIN của SIM không chính xác, bây giờ bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của bạn."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Mã PIN của SIM không chính xác, bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử trước khi bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của bạn."</item>
-    <item quantity="other" msgid="2215723361575359486">"Mã PIN của SIM không chính xác, bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">Mã PIN của SIM không chính xác, bạn còn  <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item>
+      <item quantity="one">Mã PIN của SIM không chính xác, bạn còn  <xliff:g id="NUMBER_0">%d</xliff:g> lần thử trước khi bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của mình.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM không thể sử dụng được. Liên hệ với nhà cung cấp dịch vụ của bạn."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Mã PUK của SIM không chính xác, bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được."</item>
-    <item quantity="other" msgid="5477305226026342036">"Mã PUK của SIM không chính xác, bạn còn <xliff:g id="NUMBER">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">Mã PUK của SIM không chính xác, bạn còn  <xliff:g id="NUMBER_1">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không sử dụng được.</item>
+      <item quantity="one">Mã PUK của SIM không chính xác, bạn còn  <xliff:g id="NUMBER_0">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Thao tác mã PIN của SIM không thành công!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Thao tác mã PUK của SIM không thành công!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Mã được chấp nhận!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Nút bản nhạc trước"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Nút bản nhạc tiếp theo"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Nút tạm dừng"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Nút phát"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Nút dừng"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Không có dịch vụ."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 449cc1e..a93b54b 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -29,14 +29,12 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"输入密码以解锁"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"输入PIN码进行解锁"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN码有误。"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</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>
     <string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无SIM卡"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无 SIM 卡"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有SIM卡。"</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有SIM卡。"</string>
     <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入SIM卡。"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM卡已被锁定。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM卡已被PUK码锁定。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解锁SIM卡..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。%3$d的小部件%2$d。"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"添加小部件。"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"已展开解锁区域。"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"已折叠解锁区域。"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小部件。"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"用户选择器"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相机"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒体控制"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已开始将小部件重新排序。"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"已完成小部件重新排序。"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"已删除小部件<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>。"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展开解锁区域。"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑动解锁。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"图案解锁。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人脸解锁。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN码解锁。"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN 码区域"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM 卡 PIN 码区域"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM 卡 PUK 码区域"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"上一曲按钮"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"下一曲按钮"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"暂停按钮"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"播放按钮"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"停止按钮"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"我喜欢"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"不喜欢"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"爱心"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"解锁即可继续"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"启动已取消"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"放下<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>即可将其删除。"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>将不会被删除。"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"下次闹钟时间已设置为<xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式更改"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"解锁"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"相机"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"静音"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"打开声音"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"向下滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"向左滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"向右滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"紧急呼救"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"图案错误"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的Google帐户。"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"用户名(电子邮件地址)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"密码"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"登录"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"用户名或密码无效。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?\n请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"正在检查帐户…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%d</xliff:g>秒后重试。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,则必须联系运营商帮您解锁设备。"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM卡PIN码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM 卡 PIN 码不正确,您还可尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+      <item quantity="one">SIM 卡 PIN 码不正确,您还可尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,则需要联系运营商帮您解锁设备。</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM卡无法使用,请与您的运营商联系。"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM卡PUK码不正确,您还有<xliff:g id="NUMBER">%d</xliff:g>次尝试机会。如果仍然失败,SIM卡将永远无法使用。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM 卡 PUK 码不正确,您还可尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。如果仍不正确,SIM 卡将永远无法使用。</item>
+      <item quantity="one">SIM 卡 PUK 码不正确,您还可尝试 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍不正确,SIM 卡将永远无法使用。</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM卡PIN码操作失败!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"“上一曲”按钮"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"“下一曲”按钮"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"“暂停”按钮"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"“播放”按钮"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"“停止”按钮"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index be19441..55a6a5e 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"輸入密碼即可解鎖"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"輸入 PIN 碼即可解鎖"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</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_plugged_in" msgid="9087497435553252863">"充電中"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"請連接充電器。"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態。"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解開上鎖的 SIM 卡..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"使用者選取工具"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始為小工具重新排列次序。"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"已完成為小工具重新排列次序。"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖案解鎖。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"臉容解鎖。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN 區域"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM PIN 區域"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM PUK 區域"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"[上一首曲目] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"[下一首曲目] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"[暫停] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"[播放] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"[停止] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"喜歡"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"不喜歡"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"心形"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"請解鎖以繼續"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"已取消啟動"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"拖放「<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>」即可刪除。"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"「<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>」將不會被刪除。"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"已設定下一個鬧鐘時間:<xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"刪除"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式更改"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"解鎖"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"相機"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"音效已開啟"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="user_switched" msgid="3768006783166984410">"目前的使用者是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖案錯誤"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"請重新輸入正確的 PUK 碼。如果嘗試輸入的次數過多,SIM 卡將永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖案嘗試次數過多"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"如要解鎖,請以 Google 帳戶登入。"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"使用者名稱 (電子郵件)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"無效的使用者名稱或密碼。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘記使用者名稱或密碼?\n請瀏覽 "<b>"google.com/accounts/recovery"</b>"。"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM PIN 碼不正確,您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,您必須聯絡流動網絡供應商為您的裝置解鎖。"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM PIN 碼不正確,您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會輸入。</item>
+      <item quantity="one">SIM PIN 碼不正確,您還有 <xliff:g id="NUMBER_0">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,您必須聯絡流動網絡供應商為您的裝置解鎖。</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM 無法使用,請聯絡您的流動網絡供應商。"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM PUK 碼不正確,您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。如果仍然輪入錯誤,SIM 將永久無法使用。"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM PUK 碼不正確,您剩下 <xliff:g id="NUMBER">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 將永久無法使用。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM PUK 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 卡將永久無法使用。</item>
+      <item quantity="one">SIM PUK 碼不正確,您還有 <xliff:g id="NUMBER_0">%d</xliff:g> 次機會輸入。如果仍然輸入錯誤,SIM 卡將永久無法使用。</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM PIN 碼操作失敗!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"[上一首曲目] 按鈕"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"[下一首曲目] 按鈕"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"[暫停] 按鈕"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"[播放] 按鈕"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"[停止] 按鈕"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 82ef9d1..66c665f 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"輸入密碼即可解鎖"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"輸入 PIN 即可解鎖"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN 碼不正確。"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按 Menu 鍵,然後按 0。"</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過人臉解鎖嘗試次數上限"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"充電完成"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"連接充電器。"</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解除 SIM 卡鎖定..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s。第 %2$d 個小工具,共 %3$d 個。"</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"解鎖區域已展開。"</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"解鎖區域已收合。"</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具。"</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"使用者選取工具"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"相機"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"媒體控制項"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"已開始將小工具重新排序。"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"小工具重新排序已完成。"</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖形解鎖。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人臉解鎖。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"PIN 區"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"SIM 卡 PIN 區"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"SIM 卡 PUK 區"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"[上一首曲目] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"[下一首曲目] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"[暫停] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"[播放] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"[停止] 按鈕"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"喜歡"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"不喜歡"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"愛心"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"先解鎖才能繼續操作"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"已取消啟動"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"拖放「<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>」即可將其刪除。"</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"「<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>」將不會遭到刪除。"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"已設定下一個鬧鐘時間:<xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 鍵"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 鍵"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"完成"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"模式變更"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"解除鎖定"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"相機"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"靜音"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"開啟音效"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"向下滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"向右滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
-    <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖形"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖形錯誤"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會永久停用。"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖形嘗試次數過多"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"如要解除鎖定,請使用 Google 帳戶登入。"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"使用者名稱 (電子郵件)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"使用者名稱或密碼無效。"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘了使用者名稱或密碼?\n請前往 "<b>"google.com/accounts/recovery"</b>"。"</string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM 卡的 PIN 碼輸入錯誤,您現在必須請行動通訊業者為裝置解鎖。"</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。如果仍然失敗,就必須請行動通訊業者為裝置解鎖。"</item>
-    <item quantity="other" msgid="2215723361575359486">"SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="other">SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
+      <item quantity="one">SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,就必須請行動通訊業者為裝置解鎖。</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM 卡無法使用,請與您的行動通訊業者聯絡。"</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"SIM 卡的 PUK 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。如果仍然失敗,SIM 卡將永久無法使用。"</item>
-    <item quantity="other" msgid="5477305226026342036">"SIM 卡的 PUK 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER">%d</xliff:g> 次。如果仍然失敗,SIM 卡將永久無法使用。"</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="other">SIM 卡的 PUK 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。如果仍然失敗,SIM 卡將永久無法使用。</item>
+      <item quantity="one">SIM 卡的 PUK 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_0">%d</xliff:g> 次。如果仍然失敗,SIM 卡將永久無法使用。</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"SIM 卡 PIN 碼操作失敗!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM 卡 PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"[上一首曲目] 按鈕"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"[下一首曲目] 按鈕"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"[暫停] 按鈕"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"[播放] 按鈕"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"[停止] 按鈕"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index f8c8f53..be8900a 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -29,8 +29,6 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Bhala iphasiwedi ukuze kuvuleke"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Faka i-PIN ukuvula"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Ikhodi ye-PIN engalungile!"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Ukuvula, chofoza Menyu bese 0."</string>
-    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ukuzama Kokuvula Ubuso Okuningi kudluliwe"</string>
     <string name="keyguard_charged" msgid="3272223906073492454">"Kushajiwe"</string>
     <string name="keyguard_plugged_in" msgid="9087497435553252863">"Iyashaja"</string>
     <string name="keyguard_low_battery" msgid="8143808018719173859">"Xhuma ishaja yakho."</string>
@@ -46,20 +44,6 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Ikhadi le-SIM likhiyiwe."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Ikhadi le-SIM likhiywe nge-PUK."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Ivula ikhadi le-SIM..."</string>
-    <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. iwijethi %2$d ye-%3$d."</string>
-    <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Engeza iwijethi."</string>
-    <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Akunalutho"</string>
-    <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Indawo yokuvula inwetshisiwe."</string>
-    <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Indawo yokuvula inciphisiwe."</string>
-    <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> iwijethi."</string>
-    <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Isikhethi somsebenzisi"</string>
-    <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Ikhamera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Izilawuli zemidiya"</string>
-    <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Ukuhlelwa kabusha kwewijethi kuqalile"</string>
-    <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Ukuhlelwa kabusha kwewijethi kuphelile."</string>
-    <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Iwijethi <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> isusiwe."</string>
-    <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Nwebisa indawo yokuvula."</string>
-    <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Ukuvula ngokuslayida."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Ukuvula ngephethini."</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Vula ngobuso"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Ukuvula ngephinikhodi."</string>
@@ -69,39 +53,9 @@
     <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Indawo yephinikhodi"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Indawo yephinikhodi ye-SIM"</string>
     <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Indawo ye-SIM PUK"</string>
-    <string name="keyguard_accessibility_transport_prev_description" msgid="1337286538318543555">"Inkinombo yethrekhi yangaphambilini"</string>
-    <string name="keyguard_accessibility_transport_next_description" msgid="7073928300444909320">"Inkinobho yethrekhi elandelayo"</string>
-    <string name="keyguard_accessibility_transport_pause_description" msgid="8455979545295224302">"Inkinobho yokumiswa isikhashana"</string>
-    <string name="keyguard_accessibility_transport_play_description" msgid="8146417789511154044">"Inkinobho yokudlala"</string>
-    <string name="keyguard_accessibility_transport_stop_description" msgid="7656358482980912216">"Inkinobho yokumisa"</string>
-    <string name="keyguard_accessibility_transport_thumbs_up_description" msgid="4535938129663903194">"Okushaphu"</string>
-    <string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Akulungile"</string>
-    <string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Inhliziyo"</string>
-    <string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Vula ukuze uqhubeke"</string>
-    <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Ukuqalisa kukhanseliwe"</string>
-    <string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Lahla i-<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ukuze uyisuse."</string>
-    <string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> ngeke isuswe."</string>
     <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"I-alamu elandelayo esethelwe i-<xliff:g id="ALARM">%1$s</xliff:g>"</string>
-    <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
-    <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
-    <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
-    <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"i-ALT"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Khansela"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Susa"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Kwenziwe"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Ukushintsha kwendlela esetshenziswayo"</string>
-    <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Beka kwenye indawo"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Faka"</string>
-    <string name="description_target_unlock" msgid="2228524900439801453">"Vula"</string>
-    <string name="description_target_camera" msgid="969071997552486814">"Ikhamera"</string>
-    <string name="description_target_silent" msgid="893551287746522182">"Thulile"</string>
-    <string name="description_target_soundon" msgid="30052466675500172">"Umsindo uvuliwe"</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>
-    <string name="description_direction_down" msgid="5087739728639014595">"Shelelisela ngezansi ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_left" msgid="7207478719805562165">"Shelelisela ngakwesokunxele ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="description_direction_right" msgid="8034433242579600980">"Shelelisela ngakwesokudla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Ucingo lwezimo eziphuthumayo"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ukhohlwe iphethini?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Iphatheni engalungile"</string>
@@ -123,13 +77,6 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Iphinikhodi ayifani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Ukuvula, ngena ngemvume kwi-akhawunti ye-Google"</string>
-    <string name="kg_login_username_hint" msgid="5718534272070920364">"Igama lomsebenzisi (i-imeyli)"</string>
-    <string name="kg_login_password_hint" msgid="9057289103827298549">"Iphasiwedi"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ngena ngemvume"</string>
-    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?\nVakashela"<b>"google.com/accounts/recovery"</b></string>
-    <string name="kg_login_checking_password" msgid="1052685197710252395">"Ukuhlola i-akhawunti…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
@@ -147,24 +94,19 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
-    <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Ikhodi yephinikhodi ye-SIM engalungile manje kumele uxhumane nenkampini yenethiwekhi yakho ukuvula idivayisi yakho."</string>
-  <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Ikhodi yephinikhodi ye-SIM engalungile, unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> esele ngaphambi kokuba uxhumane nenkampini yenethiwekhi."</item>
-    <item quantity="other" msgid="2215723361575359486">"Ikhodi yephinikhodi ye-SIM engalungile, unemizamo esele engu-<xliff:g id="NUMBER">%d</xliff:g>."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+      <item quantity="one">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
+      <item quantity="other">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
+    </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"I-SIM ayisebenziseki. Xhumana nemkampini yenethiwekhi yakho."</string>
-  <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Ikhodi ye-PUK ye-SIM engalungile, unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> esele ngaphambi kokuba i-SIM ibe engasebenziseki unaphakade."</item>
-    <item quantity="other" msgid="5477305226026342036">"Ikhodi ye-PUK ye-SIM engalungile, unemizamo engu-<xliff:g id="NUMBER">%d</xliff:g> esele ngaphambi kokuba i-SIM iba engasebenziseki unaphakade."</item>
-  </plurals>
+    <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+      <item quantity="one">Ikhodi ye-PUK ye-SIM engalungile, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasasebenziseki unaphakade.</item>
+      <item quantity="other">Ikhodi ye-PUK ye-SIM engalungile, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasasebenziseki unaphakade.</item>
+    </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Umsebenzi wephinikhodi ye-SIM wehlulekile!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Umsebenzi we-PUK ye-SIM wehlulekile!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Ikhodi yamukelwe!"</string>
-    <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Inkinombo yethrekhi yangaphambilini"</string>
-    <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Inkinobho yethrekhi elandelayo"</string>
-    <string name="keyguard_transport_pause_description" msgid="5093073338238310224">"Inkinobho yokumiswa isikhashana"</string>
-    <string name="keyguard_transport_play_description" msgid="2924628863741150956">"Inkinobho yokudlala"</string>
-    <string name="keyguard_transport_stop_description" msgid="3084179324810575787">"Inkinobho yokumisa"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ayikho isevisi."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
 </resources>
diff --git a/packages/Keyguard/res/values/alias.xml b/packages/Keyguard/res/values/alias.xml
index 09e9591..f06b450 100644
--- a/packages/Keyguard/res/values/alias.xml
+++ b/packages/Keyguard/res/values/alias.xml
@@ -22,18 +22,6 @@
     <!-- Alias used to reference framework color for transparency. -->
     <item type="color" name="transparent">@android:color/transparent</item>
 
-    <!-- Alias used to reference framework drawable in keyguard. -->
-    <item type="drawable" name="stat_sys_warning">@android:drawable/stat_sys_warning</item>
-
-    <!-- Alias used to reference framework drawable in keyguard. -->
-    <item type="drawable" name="ic_media_pause">@android:drawable/ic_media_pause</item>
-
-    <!-- Alias used to reference framework drawable in keyguard. -->
-    <item type="drawable" name="ic_media_stop">@*android:drawable/ic_media_stop</item>
-
-    <!-- Alias used to reference framework drawable in keyguard. -->
-    <item type="drawable" name="ic_contact_picture">@*android:drawable/ic_contact_picture</item>
-
     <!-- Alias used to reference framework "OK" string in keyguard.  -->
     <item type="string" name="ok">@*android:string/ok</item>
 
diff --git a/packages/Keyguard/res/values/attrs.xml b/packages/Keyguard/res/values/attrs.xml
index 9100140..96a5bcc 100644
--- a/packages/Keyguard/res/values/attrs.xml
+++ b/packages/Keyguard/res/values/attrs.xml
@@ -20,113 +20,9 @@
 -->
 
 <resources>
-    <!-- Standard gravity constant that a child supplies to its parent.
-         Defines how the child view should be positioned, on both the X and Y axes, within its enclosing layout. -->
-    <attr name="layout_gravity">
-        <!-- Push object to the top of its container, not changing its size. -->
-        <flag name="top" value="0x30" />
-        <!-- Push object to the bottom of its container, not changing its size. -->
-        <flag name="bottom" value="0x50" />
-        <!-- Push object to the left of its container, not changing its size. -->
-        <flag name="left" value="0x03" />
-        <!-- Push object to the right of its container, not changing its size. -->
-        <flag name="right" value="0x05" />
-        <!-- Place object in the vertical center of its container, not changing its size. -->
-        <flag name="center_vertical" value="0x10" />
-        <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
-        <flag name="fill_vertical" value="0x70" />
-        <!-- Place object in the horizontal center of its container, not changing its size. -->
-        <flag name="center_horizontal" value="0x01" />
-        <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
-        <flag name="fill_horizontal" value="0x07" />
-        <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
-        <flag name="center" value="0x11" />
-        <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
-        <flag name="fill" value="0x77" />
-        <!-- Additional option that can be set to have the top and/or bottom edges of
-             the child clipped to its container's bounds.
-             The clip will be based on the vertical gravity: a top gravity will clip the bottom
-             edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
-        <flag name="clip_vertical" value="0x80" />
-        <!-- Additional option that can be set to have the left and/or right edges of
-             the child clipped to its container's bounds.
-             The clip will be based on the horizontal gravity: a left gravity will clip the right
-             edge, a right gravity will clip the left edge, and neither will clip both edges. -->
-        <flag name="clip_horizontal" value="0x08" />
-        <!-- Push object to the beginning of its container, not changing its size. -->
-        <flag name="start" value="0x00800003" />
-        <!-- Push object to the end of its container, not changing its size. -->
-        <flag name="end" value="0x00800005" />
-    </attr>
-
-
-    <!-- PagedView specific attributes. These attributes are used to customize
-         a PagedView view in XML files. -->
-    <declare-styleable name="PagedView">
-        <!-- The space between adjacent pages of the PagedView. -->
-        <attr name="pageSpacing" format="dimension" />
-        <!-- The padding for the scroll indicator area -->
-        <attr name="scrollIndicatorPaddingLeft" format="dimension" />
-        <attr name="scrollIndicatorPaddingRight" format="dimension" />
-    </declare-styleable>
-
-    <declare-styleable name="KeyguardGlowStripView">
-        <attr name="dotSize" format="dimension" />
-        <attr name="numDots" format="integer" />
-        <attr name="glowDot" format="reference" />
-        <attr name="leftToRight" format="boolean" />
-    </declare-styleable>
-
-    <!-- Some child types have special behavior. -->
-    <attr name="layout_childType">
-        <!-- No special behavior. Layout will proceed as normal. -->
-        <enum name="none" value="0" />
-        <!-- Widget container.
-             This will be resized in response to certain events. -->
-        <enum name="widget" value="1" />
-        <!-- Security challenge container.
-             This will be dismissed/shown in response to certain events,
-             possibly obscuring widget elements. -->
-        <enum name="challenge" value="2" />
-        <!-- User switcher.
-             This will consume space from the total layout area. -->
-        <enum name="userSwitcher" value="3" />
-        <!-- Scrim. This will block access to child views that
-             come before it in the child list in bouncer mode. -->
-        <enum name="scrim" value="4" />
-        <!-- The home for widgets. All widgets will be descendents of this. -->
-        <enum name="widgets" value="5" />
-        <!-- This is a handle that is used for expanding the
-             security challenge container when it is collapsed. -->
-        <enum name="expandChallengeHandle" value="6" />
-        <!-- Delete drop target.  This will be the drop target to delete pages. -->
-        <enum name="pageDeleteDropTarget" value="7" />
-    </attr>
-
-    <declare-styleable name="SlidingChallengeLayout_Layout">
-        <attr name="layout_childType" />
-        <attr name="layout_maxHeight" format="dimension" />
-    </declare-styleable>
-
-    <declare-styleable name="MultiPaneChallengeLayout">
-        <!-- Influences how layout_centerWithinArea behaves -->
-        <attr name="android:orientation" />
-    </declare-styleable>
-
-    <declare-styleable name="MultiPaneChallengeLayout_Layout">
-        <!-- Percentage of the screen this child should consume or center within.
-             If 0/default, the view will be measured by standard rules
-             as if this were a FrameLayout. -->
-        <attr name="layout_centerWithinArea" format="float" />
-        <attr name="layout_childType" />
-        <attr name="layout_gravity" />
-        <attr name="layout_maxWidth" format="dimension" />
-        <attr name="layout_maxHeight" />
-    </declare-styleable>
-
     <declare-styleable name="KeyguardSecurityViewFlipper_Layout">
-        <attr name="layout_maxWidth" />
-        <attr name="layout_maxHeight" />
+        <attr name="layout_maxWidth" format="dimension"/>
+        <attr name="layout_maxHeight" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="NumPadKey">
diff --git a/packages/Keyguard/res/values/bools.xml b/packages/Keyguard/res/values/bools.xml
index 5e842d7..2b83787 100644
--- a/packages/Keyguard/res/values/bools.xml
+++ b/packages/Keyguard/res/values/bools.xml
@@ -15,9 +15,6 @@
 -->
 
 <resources>
-    <bool name="kg_enable_camera_default_widget">true</bool>
-    <bool name="kg_center_small_widgets_vertically">false</bool>
-    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
     <bool name="kg_show_ime_at_screen_on">true</bool>
     <bool name="kg_use_all_caps">true</bool>
 </resources>
diff --git a/packages/Keyguard/res/values/colors.xml b/packages/Keyguard/res/values/colors.xml
index 4e28eff..3b741ea 100644
--- a/packages/Keyguard/res/values/colors.xml
+++ b/packages/Keyguard/res/values/colors.xml
@@ -14,15 +14,6 @@
      limitations under the License.
 -->
 <resources>
-    <!-- Keyguard colors -->
-    <color name="keyguard_avatar_frame_color">#ffffffff</color>
-    <color name="keyguard_avatar_frame_shadow_color">#80000000</color>
-    <color name="keyguard_avatar_nick_color">#ffffffff</color>
-    <color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
-    <color name="kg_widget_pager_gradient">#ffffffff</color>
-
-    <!-- FaceLock -->
-    <color name="facelock_spotlight_mask">#CC000000</color>
 
     <!-- Clock -->
     <color name="clock_white">#ffffffff</color>
diff --git a/packages/Keyguard/res/values/config.xml b/packages/Keyguard/res/values/config.xml
index de17c4b..8d9d6ee 100644
--- a/packages/Keyguard/res/values/config.xml
+++ b/packages/Keyguard/res/values/config.xml
@@ -20,13 +20,6 @@
 <!-- These resources are around just to allow their values to be customized -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
-    <string name="widget_default_package_name"></string>
-
-    <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
-    <string name="widget_default_class_name"></string>
-
     <!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
     <bool name="config_disableMenuKeyInLockScreen">false</bool>
-
 </resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 8326d75..9290236 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -18,101 +18,10 @@
 */
 -->
 <resources>
-    <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
-    <dimen name="keyguard_lockscreen_outerring_diameter">270dp</dimen>
-
-    <!-- The bottom margin for the GlowPadView container -->
-    <dimen name="glowpadcontainer_bottom_margin">-80dp</dimen>
-
-    <!-- Default target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
-    <dimen name="glowpadview_target_placement_radius">135dip</dimen>
-
-    <!-- Default glow radius for GlowPadView -->
-    <dimen name="glowpadview_glow_radius">75dip</dimen>
-
-    <!-- Default distance beyond which GlowPadView snaps to the matching target -->
-    <dimen name="glowpadview_snap_margin">40dip</dimen>
-
-    <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
-    <dimen name="glowpadview_inner_radius">15dip</dimen>
-
-    <!-- Size of status line font on Unsecure unlock LockScreen. -->
-    <dimen name="keyguard_lockscreen_status_line_font_size">14dip</dimen>
-
-    <!-- Size of right margin on Unsecure unlock LockScreen -->
-    <dimen name="keyguard_lockscreen_status_line_font_right_margin">42dip</dimen>
-
-    <!-- Size of top margin on Clock font to edge on unlock LockScreen -->
-    <dimen name="keyguard_lockscreen_status_line_clockfont_top_margin">22dip</dimen>
-
-    <!-- Size of top margin on Clock font to edge on unlock LockScreen -->
-    <dimen name="keyguard_lockscreen_status_line_clockfont_bottom_margin">12dip</dimen>
-
-    <!-- Padding on left margin of PIN text entry field to center it when del button is showing -->
-    <dimen name="keyguard_lockscreen_pin_margin_left">40dip</dimen>
-
-    <!-- Height of FaceUnlock view in keyguard -->
-    <dimen name="face_unlock_height">330dip</dimen>
-
-    <!-- Keyguard dimensions -->
-    <!-- TEMP -->
-    <dimen name="kg_security_panel_height">600dp</dimen>
-
-    <!-- Height of security view in keyguard. -->
-    <dimen name="kg_security_view_height">480dp</dimen>
-
-    <!-- Width of widget view in keyguard. -->
-    <dimen name="kg_widget_view_width">0dp</dimen>
-
-    <!-- Height of widget view in keyguard. -->
-    <dimen name="kg_widget_view_height">0dp</dimen>
-
-    <!-- Size of the clock font in keyguard's status view -->
-    <dimen name="kg_status_clock_font_size">75dp</dimen>
 
     <!-- Size of the generic status lines keyguard's status view  -->
     <dimen name="kg_status_line_font_size">14sp</dimen>
 
-    <!-- Size of margin on the right of keyguard's status view -->
-    <dimen name="kg_status_line_font_right_margin">16dp</dimen>
-
-    <!-- Top margin for the clock view -->
-    <dimen name="kg_clock_top_margin">-16dp</dimen>
-
-    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
-    <dimen name="kg_key_horizontal_gap">0dp</dimen>
-
-    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
-    <dimen name="kg_key_vertical_gap">0dp</dimen>
-
-    <!-- Horizontal gap between keys in PIN and SIM PIN numeric keyboards in keyguard -->
-    <dimen name="kg_pin_key_height">60dp</dimen>
-
-    <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
-    <dimen name="kg_secure_padding_height">46dp</dimen>
-
-    <!-- The height of the runway lights strip -->
-    <dimen name="kg_runway_lights_height">7dp</dimen>
-
-    <!-- The height of the runway lights strip -->
-    <dimen name="kg_runway_lights_vertical_padding">2dp</dimen>
-
-    <!-- Horizontal padding for the widget pager -->
-    <dimen name="kg_widget_pager_horizontal_padding">16dp</dimen>
-
-    <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
-
-    <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">64dp</dimen>
-
-    <!-- Top margin for the runway lights. We add a negative margin in large
-        devices to account for the widget pager padding -->
-    <dimen name="kg_runway_lights_top_margin">0dp</dimen>
-
-    <!-- Touch slop for the global toggle accessibility gesture -->
-    <dimen name="accessibility_touch_slop">80dip</dimen>
-
     <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
     <dimen name="keyguard_security_width">320dp</dimen>
 
@@ -125,44 +34,14 @@
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_margin">8dp</dimen>
 
-    <!-- Margin around the various security views -->
-    <dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
-
-    <!-- Stroke width of the frame for the circular avatars. -->
-    <dimen name="keyguard_avatar_frame_stroke_width">2dp</dimen>
-
-    <!-- Shadow radius under the frame for the circular avatars. -->
-    <dimen name="keyguard_avatar_frame_shadow_radius">1dp</dimen>
-
-    <!-- Size of the avator on hte multiuser lockscreen. -->
-    <dimen name="keyguard_avatar_size">66dp</dimen>
-
-    <!-- Size of the text under the avator on the multiuser lockscreen. -->
-    <dimen name="keyguard_avatar_name_size">10sp</dimen>
-
-    <!-- Size of the region along the edge of the screen that will accept
-         swipes to scroll the widget area. -->
-    <dimen name="kg_edge_swipe_region_size">24dp</dimen>
-
-    <!-- If the height if keyguard drops below this threshold (most likely
-    due to the appearance of the IME), then drop the multiuser selector. -->
-    <dimen name="kg_squashed_layout_threshold">600dp</dimen>
-
-    <!-- The height of widgets which do not support vertical resizing. This is only
-    used on tablets; on phones, this size is determined by the space left by the
-    security mode. -->
-    <dimen name="kg_small_widget_height">160dp</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">-10dip</dimen>
 
     <!-- Default clock parameters -->
     <dimen name="bottom_text_spacing_digital">-10dp</dimen>
-    <dimen name="label_font_size">14dp</dimen>
     <dimen name="widget_label_font_size">16sp</dimen>
     <dimen name="widget_big_font_size">88dp</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>
diff --git a/packages/Keyguard/res/values/integers.xml b/packages/Keyguard/res/values/integers.xml
deleted file mode 100644
index dc90bbf..0000000
--- a/packages/Keyguard/res/values/integers.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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.
-*/
--->
-<resources>
-    <integer name="kg_carousel_angle">75</integer>
-    <integer name="kg_glowpad_rotation_offset">0</integer>
-</resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 5990647..5047330 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -48,12 +48,6 @@
          to unlock the keyguard.  Displayed in one line in a large font.  -->
     <string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
 
-    <!-- Instructions telling the user how to unlock the phone. -->
-    <string name="keyguard_label_text">To unlock, press Menu then 0.</string>
-
-    <!-- Shown when face unlock failed multiple times so we're just using the backup -->
-    <string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string>
-
     <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
          charged, say that it is charged. -->
     <string name="keyguard_charged">Charged</string>
@@ -101,35 +95,6 @@
     <!-- Time format strings for fall-back clock widget -->
     <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
 
-    <!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string>
-    <!-- Accessibility description of the add widget button. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_add_widget">Add widget.</string>
-    <!-- Accessibility description of the empty sidget slot (place holder for a new widget). [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget_empty_slot">Empty</string>
-    <!-- Accessibility description of the event of expanding an unlock area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_unlock_area_expanded">Unlock area expanded.</string>
-    <!-- Accessibility description of the event of collapsing an unlock area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_unlock_area_collapsed">Unlock area collapsed.</string>
-    <!-- Accessibility description of a lock screen widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
-    <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_user_selector">User selector</string>
-    <!-- Accessibility description of the camera widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_camera">Camera</string>
-    <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
-    <string name="keygaurd_accessibility_media_controls">Media controls</string>
-    <!-- Accessibility description of widget reordering start. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget_reorder_start">Widget reordering started.</string>
-    <!-- Accessibility description of widget reordering end. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget_reorder_end">Widget reordering ended.</string>
-    <!-- Accessibility description of the a widget deletion event. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget_deleted">Widget <xliff:g id="widget_index">%1$s</xliff:g> deleted.</string>
-    <!-- Accessibility description of the button to expand the lock area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_expand_lock_area">Expand unlock area.</string>
-    <!-- Accessibility description of the slide unlock. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_slide_unlock">Slide unlock.</string>
-    <!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
     <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_face_unlock">Face unlock.</string>
@@ -148,88 +113,15 @@
     <!-- Accessibility description of the SIM PUK password view. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_sim_puk_area">SIM PUK area</string>
 
-    <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
-    <string name="keyguard_accessibility_transport_prev_description">Previous track button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button goes to next track. -->
-    <string name="keyguard_accessibility_transport_next_description">Next track button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_accessibility_transport_pause_description">Pause button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_accessibility_transport_play_description">Play button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_accessibility_transport_stop_description">Stop button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button rates the track as "thumbs up." -->
-    <string name="keyguard_accessibility_transport_thumbs_up_description">Thumbs up</string>
-    <!-- Shown on transport control of lockscreen. Pressing button rates the track as "thumbs down." -->
-    <string name="keyguard_accessibility_transport_thumbs_down_description">Thumbs down</string>
-    <!-- Shown on transport control of lockscreen. Pressing button toggles the "heart" rating. -->
-    <string name="keyguard_accessibility_transport_heart_description">Heart</string>
-
-
-    <!-- Accessibility description for when the device prompts the user to dismiss keyguard
-         in order to complete an action. This will be followed by a message about the current
-         security option (e.g. "Pattern unlock."). [CHAR LIMIT=NONE] -->
-    <string name="keyguard_accessibility_show_bouncer">Unlock to continue</string>
-
-    <!-- Accessibility description for when the bouncer prompt is dismissed. [CHAR LIMIT=NONE] -->
-    <string name="keyguard_accessibility_hide_bouncer">Launch canceled</string>
-
-    <!-- Accessibility description announced when user drags widget over the delete drop target [CHAR LIMIT=NONE] -->
-    <string name="keyguard_accessibility_delete_widget_start">Drop <xliff:g id="widget_index">%1$s</xliff:g> to delete.</string>
-
-    <!-- Accessibility description announced when user drags widget away from delete drop target [CHAR LIMIT=NONE] -->
-    <string name="keyguard_accessibility_delete_widget_end"><xliff:g id="widget_index">%1$s</xliff:g> will not be deleted.</string>
-
     <!-- Accessibility description for the text view that indicates when the next alarm is set (not shown on screen). [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_next_alarm">Next alarm set for <xliff:g id="alarm" example="Fri 8:30 AM">%1$s</xliff:g></string>
 
-    <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
-    <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
-    <string name="password_keyboard_label_symbol_key">\?123</string>
-    <!-- Label for "switch to alphabetic" key.  Must be short to fit on key! -->
-    <string name="password_keyboard_label_alpha_key">ABC</string>
-    <!-- Label for ALT modifier key.  Must be short to fit on key! -->
-    <string name="password_keyboard_label_alt_key">ALT</string>
-
-    <!-- KeyboardView - accessibility support --><skip />
-    <!-- Description of the Alt button in a KeyboardView. [CHAR LIMIT=NONE] -->
-    <string name="keyboardview_keycode_alt">Alt</string>
-    <!-- Description of the Cancel button in a KeyboardView. [CHAR LIMIT=NONE] -->
-    <string name="keyboardview_keycode_cancel">Cancel</string>
+    <!-- KeyguardPinView - accessibility support --><skip />
     <!-- Description of the Delete button in a KeyboardView. [CHAR LIMIT=NONE] -->
     <string name="keyboardview_keycode_delete">Delete</string>
-    <!-- Description of the Done button in a KeyboardView. [CHAR LIMIT=NONE] -->
-    <string name="keyboardview_keycode_done">Done</string>
-    <!-- Description of the Mode change button in a KeyboardView. [CHAR LIMIT=NONE] -->
-    <string name="keyboardview_keycode_mode_change">Mode change</string>
-    <!-- Description of the Shift button in a KeyboardView. [CHAR LIMIT=NONE] -->
-    <string name="keyboardview_keycode_shift">Shift</string>
     <!-- Description of the Enter button in a KeyboardView. [CHAR LIMIT=NONE] -->
     <string name="keyboardview_keycode_enter">Enter</string>
 
-    <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_target_unlock">Unlock</string>
-    <!-- Description of the camera target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_target_camera">Camera</string>
-    <!-- Description of the silent target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_target_silent">Silent</string>
-    <!-- Description of the sound on target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_target_soundon">Sound on</string>
-    <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_target_search">Search</string>
-
-    <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
-    <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_down">Slide down for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
-    <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
-    <!-- Description of the right direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_right">Slide right for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
-
-    <!-- Text spoken when the current user is switched if accessibility is enabled. [CHAR LIMIT=none] -->
-    <string name="user_switched">Current user <xliff:g id="name" example="Bob">%1$s</xliff:g>.</string>
-
     <!-- Label shown on emergency call button in keyguard -->
     <string name="kg_emergency_call_label">Emergency call</string>
     <!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
@@ -272,20 +164,6 @@
     <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
     <!-- Message shown when the user exceeds the maximum number of pattern attempts -->
     <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
-    <!-- Instructions show in account unlock screen allowing user to enter their email password -->
-    <string name="kg_login_instructions">To unlock, sign in with your Google account.</string>
-    <!-- Hint shown in TextView in account unlock screen of keyguard -->
-    <string name="kg_login_username_hint">Username (email)</string>
-    <!-- Hint shown in TextView in account unlock screen of keyguard -->
-    <string name="kg_login_password_hint">Password</string>
-    <!-- Label shown on sign in button on account unlock screen of keyguard -->
-    <string name="kg_login_submit_button">Sign in</string>
-    <!-- Message shown when the user enters an invalid username/password combination in account unlock screen of keyguard -->
-    <string name="kg_login_invalid_input">Invalid username or password.</string>
-    <!-- Hint text shown when user has too many failed password attempts in account unlock screen of keyguard -->
-    <string name="kg_login_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
-    <!-- Message shown while device checks username/password in account unlock screen of keyguard -->
-    <string name="kg_login_checking_password">Checking account\u2026</string>
     <!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
     <string name="kg_too_many_failed_pin_attempts_dialog_message">
         You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
@@ -386,8 +264,6 @@
        you will be asked to unlock your phone using an email account.\n\n
        Try again in <xliff:g id="number">%d</xliff:g> seconds.
     </string>
-    <!-- The delete-widget drop target button text -->
-    <string name="kg_reordering_delete_drop_target_text">Remove</string>
 
     <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
          Displayed in a dialog box.  -->
@@ -417,18 +293,6 @@
     <!-- Notification telling the user that the PIN1 they entered is valid -->
     <string name="kg_pin_accepted">Code Accepted!</string>
 
-    <!-- Transport control strings -->
-    <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. -->
-    <string name="keyguard_transport_prev_description">Previous track button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button goes to next track. -->
-    <string name="keyguard_transport_next_description">Next track button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_transport_pause_description">Pause button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_transport_play_description">Play button</string>
-    <!-- Shown on transport control of lockscreen. Pressing button pauses playback -->
-    <string name="keyguard_transport_stop_description">Stop button</string>
-
     <!-- On the keyguard screen, it shows the carrier the phone is connected to.
         This is displayed if the phone is not connected to a carrier.-->
     <string name="keyguard_carrier_default">No service.</string>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index 7d161af..404a17e 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -35,36 +35,13 @@
         <item name="android:paddingBottom">0dp</item>
     </style>
 
-    <!-- Standard animations for a non-full-screen window or activity. -->
-    <style name="Animation.LockScreen" parent="@android:style/Animation">
-        <item name="android:windowEnterAnimation">@anim/lock_screen_enter</item>
-        <item name="android:windowExitAnimation">@anim/lock_screen_exit</item>
-    </style>
-
     <!-- Built-in clock widget stuff -->
     <style name="widget_label">
         <item name="android:textSize">@dimen/widget_label_font_size</item>
     </style>
-    <style name="big_thin">
-        <item name="android:textSize">@dimen/big_font_size</item>
-        <item name="android:fontFamily">sans-serif-thin</item>
-    </style>
-    <style name="widget_big_thin" parent="big_thin">
+    <style name="widget_big_thin">
         <item name="android:textSize">@dimen/widget_big_font_size</item>
-    </style>
-
-    <style name="Widget.TransportControl.SeekBar" parent="@android:style/Widget.DeviceDefault.Light.SeekBar">
-        <item name="android:indeterminateOnly">false</item>
-        <item name="android:progressDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
-        <item name="android:indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
-        <item name="android:minHeight">13dip</item>
-        <item name="android:maxHeight">13dip</item>
-        <item name="android:thumb">@drawable/scrubber_control_selector_holo</item>
-        <item name="android:thumbOffset">16dip</item>
-        <item name="android:focusable">true</item>
-        <item name="android:paddingStart">16dip</item>
-        <item name="android:paddingEnd">16dip</item>
-        <item name="android:mirrorForRtl">true</item>
+        <item name="android:fontFamily">sans-serif-thin</item>
     </style>
 
     <style name="BouncerSecurityContainer">
diff --git a/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedImageButton.java b/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedImageButton.java
index eda790f..58c79b4 100644
--- a/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedImageButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedImageButton.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.widget.ImageButton;
-import android.widget.RelativeLayout;
 
 /**
  * A frame layout which does not have overlapping renderings commands and therefore does not need a
diff --git a/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedLinearLayout.java b/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedLinearLayout.java
index 36da6f1..2c6c4fa 100644
--- a/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedLinearLayout.java
+++ b/packages/Keyguard/src/com/android/keyguard/AlphaOptimizedLinearLayout.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.View;
 import android.widget.LinearLayout;
 
 /**
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
index 3ff2cc0..e4706b6 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
@@ -16,7 +16,6 @@
 
 package com.android.keyguard;
 
-import android.animation.Animator;
 import android.view.animation.Interpolator;
 
 /**
diff --git a/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java b/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java
deleted file mode 100644
index 230ef81..0000000
--- a/packages/Keyguard/src/com/android/keyguard/BiometricSensorUnlock.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.View;
-
-interface BiometricSensorUnlock {
-    /**
-     * Initializes the view provided for the biometric unlock UI to work within.  The provided area
-     * completely covers the backup unlock mechanism.
-     * @param biometricUnlockView View provided for the biometric unlock UI.
-     */
-    public void initializeView(View biometricUnlockView);
-
-    /**
-     * Indicates whether the biometric unlock is running.  Before
-     * {@link BiometricSensorUnlock#start} is called, isRunning() returns false.  After a successful
-     * call to {@link BiometricSensorUnlock#start}, isRunning() returns true until the biometric
-     * unlock completes, {@link BiometricSensorUnlock#stop} has been called, or an error has
-     * forced the biometric unlock to stop.
-     * @return whether the biometric unlock is currently running.
-     */
-    public boolean isRunning();
-
-    /**
-     * Stops and removes the biometric unlock and shows the backup unlock
-     */
-    public void stopAndShowBackup();
-
-    /**
-     * Binds to the biometric unlock service and starts the unlock procedure.  Called on the UI
-     * thread.
-     * @return false if it can't be started or the backup should be used.
-     */
-    public boolean start();
-
-    /**
-     * Stops the biometric unlock procedure and unbinds from the service.  Called on the UI thread.
-     * @return whether the biometric unlock was running when called.
-     */
-    public boolean stop();
-
-    /**
-     * Cleans up any resources used by the biometric unlock.
-     */
-    public void cleanUp();
-
-    /**
-     * Gets the Device Policy Manager quality of the biometric unlock sensor
-     * (e.g., PASSWORD_QUALITY_BIOMETRIC_WEAK).
-     * @return biometric unlock sensor quality, as defined by Device Policy Manager.
-     */
-    public int getQuality();
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
deleted file mode 100644
index 2bf74ea..0000000
--- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-
-import com.android.keyguard.KeyguardActivityLauncher.CameraWidgetInfo;
-
-public class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
-    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final int WIDGET_ANIMATION_DURATION = 250; // ms
-    private static final int WIDGET_WAIT_DURATION = 400; // ms
-    private static final int RECOVERY_DELAY = 1000; // ms
-
-    interface Callbacks {
-        void onLaunchingCamera();
-        void onCameraLaunchedSuccessfully();
-        void onCameraLaunchedUnsuccessfully();
-    }
-
-    private final Handler mHandler = new Handler();
-    private final KeyguardActivityLauncher mActivityLauncher;
-    private final Callbacks mCallbacks;
-    private final CameraWidgetInfo mWidgetInfo;
-    private final WindowManager mWindowManager;
-    private final Point mRenderedSize = new Point();
-    private final int[] mTmpLoc = new int[2];
-
-    private long mLaunchCameraStart;
-    private boolean mActive;
-    private boolean mTransitioning;
-    private boolean mDown;
-
-    private final Rect mInsets = new Rect();
-
-    private FixedSizeFrameLayout mPreview;
-    private View mFullscreenPreview;
-    private View mFakeNavBar;
-    private boolean mUseFastTransition;
-
-    private final Runnable mTransitionToCameraRunnable = new Runnable() {
-        @Override
-        public void run() {
-            transitionToCamera();
-        }};
-
-    private final Runnable mTransitionToCameraEndAction = new Runnable() {
-        @Override
-        public void run() {
-            if (!mTransitioning)
-                return;
-            Handler worker =  getWorkerHandler() != null ? getWorkerHandler() : mHandler;
-            mLaunchCameraStart = SystemClock.uptimeMillis();
-            if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
-            mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
-        }};
-
-    private final Runnable mPostTransitionToCameraEndAction = new Runnable() {
-        @Override
-        public void run() {
-            mHandler.post(mTransitionToCameraEndAction);
-        }};
-
-    private final Runnable mRecoverRunnable = new Runnable() {
-        @Override
-        public void run() {
-            recover();
-        }};
-
-    private final Runnable mRenderRunnable = new Runnable() {
-        @Override
-        public void run() {
-            render();
-        }};
-
-    private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
-        @Override
-        public void run() {
-            onSecureCameraActivityStarted();
-        }
-    };
-
-    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
-        private boolean mShowing;
-
-        @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            if (mShowing == showing)
-                return;
-            mShowing = showing;
-            CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing);
-        }
-    };
-
-    private static final class FixedSizeFrameLayout extends FrameLayout {
-        int width;
-        int height;
-
-        FixedSizeFrameLayout(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            measureChildren(
-                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-            setMeasuredDimension(width, height);
-        }
-    }
-
-    private CameraWidgetFrame(Context context, Callbacks callbacks,
-            KeyguardActivityLauncher activityLauncher,
-            CameraWidgetInfo widgetInfo, View previewWidget) {
-        super(context);
-        mCallbacks = callbacks;
-        mActivityLauncher = activityLauncher;
-        mWidgetInfo = widgetInfo;
-        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback);
-
-        mPreview = new FixedSizeFrameLayout(context);
-        mPreview.addView(previewWidget);
-        addView(mPreview);
-
-        View clickBlocker = new View(context);
-        clickBlocker.setBackgroundColor(Color.TRANSPARENT);
-        clickBlocker.setOnClickListener(this);
-        addView(clickBlocker);
-
-        setContentDescription(context.getString(R.string.keyguard_accessibility_camera));
-        if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId());
-    }
-
-    public static CameraWidgetFrame create(Context context, Callbacks callbacks,
-            KeyguardActivityLauncher launcher) {
-        if (context == null || callbacks == null || launcher == null)
-            return null;
-
-        CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
-        if (widgetInfo == null)
-            return null;
-        View previewWidget = getPreviewWidget(context, widgetInfo);
-        if (previewWidget == null)
-            return null;
-
-        return new CameraWidgetFrame(context, callbacks, launcher, widgetInfo, previewWidget);
-    }
-
-    private static View getPreviewWidget(Context context, CameraWidgetInfo widgetInfo) {
-        return widgetInfo.layoutId > 0 ?
-                inflateWidgetView(context, widgetInfo) :
-                inflateGenericWidgetView(context);
-    }
-
-    private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
-        if (DEBUG) Log.d(TAG, "inflateWidgetView: " + widgetInfo.contextPackage);
-        View widgetView = null;
-        Exception exception = null;
-        try {
-            Context cameraContext = context.createPackageContext(
-                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
-            LayoutInflater cameraInflater = (LayoutInflater)
-                    cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            cameraInflater = cameraInflater.cloneInContext(cameraContext);
-            widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false);
-        } catch (NameNotFoundException e) {
-            exception = e;
-        } catch (RuntimeException e) {
-            exception = e;
-        }
-        if (exception != null) {
-            Log.w(TAG, "Error creating camera widget view", exception);
-        }
-        return widgetView;
-    }
-
-    private static View inflateGenericWidgetView(Context context) {
-        if (DEBUG) Log.d(TAG, "inflateGenericWidgetView");
-        ImageView iv = new ImageView(context);
-        iv.setImageResource(R.drawable.ic_lockscreen_camera);
-        iv.setScaleType(ScaleType.CENTER);
-        iv.setBackgroundColor(Color.argb(127, 0, 0, 0));
-        return iv;
-    }
-
-    private void render() {
-        final View root = getRootView();
-        final int width = root.getWidth() - mInsets.right;    // leave room
-        final int height = root.getHeight() - mInsets.bottom; // for bars
-        if (mRenderedSize.x == width && mRenderedSize.y == height) {
-            if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s %d%%",
-                    width, height, (int)(100*mPreview.getScaleX())));
-            return;
-        }
-        if (width == 0 || height == 0) {
-            return;
-        }
-
-        mPreview.width = width;
-        mPreview.height = height;
-        mPreview.requestLayout();
-
-        final int thisWidth = getWidth() - getPaddingLeft() - getPaddingRight();
-        final int thisHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-
-        final float pvScaleX = (float) thisWidth / width;
-        final float pvScaleY = (float) thisHeight / height;
-        final float pvScale = Math.min(pvScaleX, pvScaleY);
-
-        final int pvWidth = (int) (pvScale * width);
-        final int pvHeight = (int) (pvScale * height);
-
-        final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0;
-        final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0;
-
-        final boolean isRtl = mPreview.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        mPreview.setPivotX(isRtl ? mPreview.width : 0);
-        mPreview.setPivotY(0);
-        mPreview.setScaleX(pvScale);
-        mPreview.setScaleY(pvScale);
-        mPreview.setTranslationX((isRtl ? -1 : 1) * pvTransX);
-        mPreview.setTranslationY(pvTransY);
-
-        mRenderedSize.set(width, height);
-        if (DEBUG) Log.d(TAG, String.format("Rendered camera widget size=%sx%s %d%% instance=%s",
-                width, height, (int)(100*mPreview.getScaleX()), instanceId()));
-    }
-
-    private void transitionToCamera() {
-        if (mTransitioning || mDown) return;
-
-        mTransitioning = true;
-
-        enableWindowExitAnimation(false);
-
-        final int navHeight = mInsets.bottom;
-        final int navWidth = mInsets.right;
-
-        mPreview.getLocationInWindow(mTmpLoc);
-        final float pvHeight = mPreview.getHeight() * mPreview.getScaleY();
-        final float pvCenter = mTmpLoc[1] + pvHeight / 2f;
-
-        final ViewGroup root = (ViewGroup) getRootView();
-
-        if (DEBUG) {
-            Log.d(TAG, "root = " + root.getLeft() + "," + root.getTop() + " "
-                    + root.getWidth() + "x" + root.getHeight());
-        }
-
-        if (mFullscreenPreview == null) {
-            mFullscreenPreview = getPreviewWidget(mContext, mWidgetInfo);
-            mFullscreenPreview.setClickable(false);
-            root.addView(mFullscreenPreview, new FrameLayout.LayoutParams(
-                        root.getWidth() - navWidth,
-                        root.getHeight() - navHeight));
-        }
-
-        final float fsHeight = root.getHeight() - navHeight;
-        final float fsCenter = root.getTop() + fsHeight / 2;
-
-        final float fsScaleY = mPreview.getScaleY();
-        final float fsTransY = pvCenter - fsCenter;
-        final float fsScaleX = fsScaleY;
-
-        mPreview.setVisibility(View.GONE);
-        mFullscreenPreview.setVisibility(View.VISIBLE);
-        mFullscreenPreview.setTranslationY(fsTransY);
-        mFullscreenPreview.setScaleX(fsScaleX);
-        mFullscreenPreview.setScaleY(fsScaleY);
-        mFullscreenPreview
-            .animate()
-            .scaleX(1)
-            .scaleY(1)
-            .translationX(0)
-            .translationY(0)
-            .setDuration(WIDGET_ANIMATION_DURATION)
-            .withEndAction(mPostTransitionToCameraEndAction)
-            .start();
-
-        if (navHeight > 0 || navWidth > 0) {
-            final boolean atBottom = navHeight > 0;
-            if (mFakeNavBar == null) {
-                mFakeNavBar = new View(mContext);
-                mFakeNavBar.setBackgroundColor(Color.BLACK);
-                root.addView(mFakeNavBar, new FrameLayout.LayoutParams(
-                            atBottom ? FrameLayout.LayoutParams.MATCH_PARENT
-                                     : navWidth,
-                            atBottom ? navHeight
-                                     : FrameLayout.LayoutParams.MATCH_PARENT,
-                            atBottom ? Gravity.BOTTOM|Gravity.FILL_HORIZONTAL
-                                     : Gravity.RIGHT|Gravity.FILL_VERTICAL));
-                mFakeNavBar.setPivotY(navHeight);
-                mFakeNavBar.setPivotX(navWidth);
-            }
-            mFakeNavBar.setAlpha(0f);
-            if (atBottom) {
-                mFakeNavBar.setScaleY(0.5f);
-            } else {
-                mFakeNavBar.setScaleX(0.5f);
-            }
-            mFakeNavBar.setVisibility(View.VISIBLE);
-            mFakeNavBar.animate()
-                .alpha(1f)
-                .scaleY(1f)
-                .scaleY(1f)
-                .setDuration(WIDGET_ANIMATION_DURATION)
-                .start();
-        }
-        mCallbacks.onLaunchingCamera();
-    }
-
-    private void recover() {
-        if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
-        mCallbacks.onCameraLaunchedUnsuccessfully();
-        reset();
-    }
-
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        // ignore
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (DEBUG) Log.d(TAG, "clicked");
-        if (mTransitioning) return;
-        if (mActive) {
-            cancelTransitionToCamera();
-            transitionToCamera();
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (DEBUG) Log.d(TAG, "onDetachedFromWindow: instance " + instanceId()
-                + " at " + SystemClock.uptimeMillis());
-        super.onDetachedFromWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
-        cancelTransitionToCamera();
-        mHandler.removeCallbacks(mRecoverRunnable);
-    }
-
-    @Override
-    public void onActive(boolean isActive) {
-        mActive = isActive;
-        if (mActive) {
-            rescheduleTransitionToCamera();
-        } else {
-            reset();
-        }
-    }
-
-    @Override
-    public boolean onUserInteraction(MotionEvent event) {
-        if (mTransitioning) {
-            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
-            return true;
-        }
-
-        getLocationOnScreen(mTmpLoc);
-        int rawBottom = mTmpLoc[1] + getHeight();
-        if (event.getRawY() > rawBottom) {
-            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
-            return true;
-        }
-
-        int action = event.getAction();
-        mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
-        if (mActive) {
-            rescheduleTransitionToCamera();
-        }
-        if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
-        return false;
-    }
-
-    @Override
-    protected void onFocusLost() {
-        if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
-        cancelTransitionToCamera();
-        super.onFocusLost();
-    }
-
-    public void onScreenTurnedOff() {
-        if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
-        reset();
-    }
-
-    private void rescheduleTransitionToCamera() {
-        if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
-        mHandler.removeCallbacks(mTransitionToCameraRunnable);
-        final long duration = mUseFastTransition ? 0 : WIDGET_WAIT_DURATION;
-        mHandler.postDelayed(mTransitionToCameraRunnable, duration);
-    }
-
-    private void cancelTransitionToCamera() {
-        if (DEBUG) Log.d(TAG, "cancelTransitionToCamera at " + SystemClock.uptimeMillis());
-        mHandler.removeCallbacks(mTransitionToCameraRunnable);
-    }
-
-    private void onCameraLaunched() {
-        mCallbacks.onCameraLaunchedSuccessfully();
-        reset();
-    }
-
-    private void reset() {
-        if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
-        mLaunchCameraStart = 0;
-        mTransitioning = false;
-        mDown = false;
-        cancelTransitionToCamera();
-        mHandler.removeCallbacks(mRecoverRunnable);
-        mPreview.setVisibility(View.VISIBLE);
-        if (mFullscreenPreview != null) {
-            mFullscreenPreview.animate().cancel();
-            mFullscreenPreview.setVisibility(View.GONE);
-        }
-        if (mFakeNavBar != null) {
-            mFakeNavBar.animate().cancel();
-            mFakeNavBar.setVisibility(View.GONE);
-        }
-        enableWindowExitAnimation(true);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
-                w, h, oldw, oldh, SystemClock.uptimeMillis()));
-        if ((w != oldw && oldw > 0) || (h != oldh && oldh > 0)) {
-            // we can't trust the old geometry anymore; force a re-render
-            mRenderedSize.x = mRenderedSize.y = -1;
-        }
-        mHandler.post(mRenderRunnable);
-        super.onSizeChanged(w, h, oldw, oldh);
-    }
-
-    @Override
-    public void onBouncerShowing(boolean showing) {
-        if (showing) {
-            mTransitioning = false;
-            mHandler.post(mRecoverRunnable);
-        }
-    }
-
-    private void enableWindowExitAnimation(boolean isEnabled) {
-        View root = getRootView();
-        ViewGroup.LayoutParams lp = root.getLayoutParams();
-        if (!(lp instanceof WindowManager.LayoutParams))
-            return;
-        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
-        int newWindowAnimations = isEnabled ? R.style.Animation_LockScreen : 0;
-        if (newWindowAnimations != wlp.windowAnimations) {
-            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
-                    + " at " + SystemClock.uptimeMillis());
-            wlp.windowAnimations = newWindowAnimations;
-            mWindowManager.updateViewLayout(root, wlp);
-        }
-    }
-
-    private void onKeyguardVisibilityChanged(boolean showing) {
-        if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing
-                + " at " + SystemClock.uptimeMillis());
-        if (mTransitioning && !showing) {
-            mTransitioning = false;
-            mHandler.removeCallbacks(mRecoverRunnable);
-            if (mLaunchCameraStart > 0) {
-                long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
-                if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
-                mLaunchCameraStart = 0;
-                onCameraLaunched();
-            }
-        }
-    }
-
-    private void onSecureCameraActivityStarted() {
-        if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
-        mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
-    }
-
-    private String instanceId() {
-        return Integer.toHexString(hashCode());
-    }
-
-    public void setInsets(Rect insets) {
-        if (DEBUG) Log.d(TAG, "setInsets: " + insets);
-        mInsets.set(insets);
-    }
-
-    public void setUseFastTransition(boolean useFastTransition) {
-        mUseFastTransition = useFastTransition;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index b9263bf..7d0b81d 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -25,7 +25,6 @@
 import android.content.res.TypedArray;
 import android.net.ConnectivityManager;
 import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.text.method.SingleLineTransformationMethod;
 import android.util.AttributeSet;
@@ -36,7 +35,6 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.widget.LockPatternUtils;
 
 public class CarrierText extends TextView {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -44,7 +42,8 @@
 
     private static CharSequence mSeparator;
 
-    private LockPatternUtils mLockPatternUtils;
+    private final boolean mIsEmergencyCallCapable;
+
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@@ -81,7 +80,8 @@
 
     public CarrierText(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(mContext);
+        mIsEmergencyCallCapable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
         boolean useAllCaps;
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 attrs, R.styleable.CarrierText, 0, 0);
@@ -242,7 +242,7 @@
      */
     private CharSequence makeCarrierStringOnEmergencyCapable(
             CharSequence simMessage, CharSequence emergencyCallMessage) {
-        if (mLockPatternUtils.isEmergencyCallCapable()) {
+        if (mIsEmergencyCallCapable) {
             return concatenate(simMessage, emergencyCallMessage);
         }
         return simMessage;
diff --git a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
deleted file mode 100644
index 2ee21acd..0000000
--- a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-/**
- * Interface implemented by ViewGroup-derived layouts that implement
- * special logic for presenting security challenges to the user.
- */
-public interface ChallengeLayout {
-    /**
-     * @return true if the security challenge area of this layout is currently visible
-     */
-    boolean isChallengeShowing();
-
-    /**
-     * @return true if the challenge area significantly overlaps other content
-     */
-    boolean isChallengeOverlapping();
-
-    /**
-     * Show or hide the challenge layout.
-     *
-     * If you want to show the challenge layout in bouncer mode where applicable,
-     * use {@link #showBouncer()} instead.
-     *
-     * @param b true to show, false to hide
-     */
-    void showChallenge(boolean show);
-
-    /**
-     * Show the bouncer challenge. This may block access to other child views.
-     */
-    void showBouncer();
-
-    /**
-     * Hide the bouncer challenge if it is currently showing.
-     * This may restore previously blocked access to other child views.
-     */
-    void hideBouncer();
-
-    /**
-     * Returns true if the challenge is currently in bouncer mode,
-     * potentially blocking access to other child views.
-     */
-    boolean isBouncing();
-
-    /**
-     * Returns the duration of the bounce animation.
-     */
-    int getBouncerAnimationDuration();
-
-    /**
-     * Set a listener that will respond to changes in bouncer state.
-     *
-     * @param listener listener to register
-     */
-    void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener);
-
-    /**
-     * Listener interface that reports changes in bouncer state.
-     * The bouncer is
-     */
-    public interface OnBouncerStateChangedListener {
-        /**
-         * Called when the bouncer state changes.
-         * The bouncer is activated when the user must pass a security challenge
-         * to proceed with the requested action.
-         *
-         * <p>This differs from simply showing or hiding the security challenge
-         * as the bouncer will prevent interaction with other elements of the UI.
-         * If the user attempts to escape from the bouncer, it will be dismissed,
-         * this method will be called with false as the parameter, and the action
-         * should be canceled. If the security component reports a successful
-         * authentication and the containing code calls hideBouncer() as a result,
-         * this method will also be called with a false parameter. It is up to the
-         * caller of hideBouncer to be ready for this.</p>
-         *
-         * @param bouncerActive true if the bouncer is now active,
-         *                      false if the bouncer was dismissed.
-         */
-        public void onBouncerStateChanged(boolean bouncerActive);
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java b/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java
deleted file mode 100644
index 52e7cd5..0000000
--- a/packages/Keyguard/src/com/android/keyguard/CheckLongPressHelper.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-
-public class CheckLongPressHelper {
-    private View mView;
-    private boolean mHasPerformedLongPress;
-    private CheckForLongPress mPendingCheckForLongPress;
-    private float mDownX, mDownY;
-    private int mLongPressTimeout;
-    private int mScaledTouchSlop;
-
-    class CheckForLongPress implements Runnable {
-        public void run() {
-            if ((mView.getParent() != null) && mView.hasWindowFocus()
-                    && !mHasPerformedLongPress) {
-                if (mView.performLongClick()) {
-                    mView.setPressed(false);
-                    mHasPerformedLongPress = true;
-                }
-            }
-        }
-    }
-
-    public CheckLongPressHelper(View v) {
-        mScaledTouchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
-        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
-        mView = v;
-    }
-
-    public void postCheckForLongPress(MotionEvent ev) {
-        mDownX = ev.getX();
-        mDownY = ev.getY();
-        mHasPerformedLongPress = false;
-
-        if (mPendingCheckForLongPress == null) {
-            mPendingCheckForLongPress = new CheckForLongPress();
-        }
-        mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
-    }
-
-    public void onMove(MotionEvent ev) {
-        float x = ev.getX();
-        float y = ev.getY();
-        boolean xMoved = Math.abs(mDownX - x) > mScaledTouchSlop;
-        boolean yMoved = Math.abs(mDownY - y) > mScaledTouchSlop;
-
-        if (xMoved || yMoved) {
-            cancelLongPress();
-        }
-    }
-
-    public void cancelLongPress() {
-        mHasPerformedLongPress = false;
-        if (mPendingCheckForLongPress != null) {
-            mView.removeCallbacks(mPendingCheckForLongPress);
-            mPendingCheckForLongPress = null;
-        }
-    }
-
-    public boolean hasPerformedLongPress() {
-        return mHasPerformedLongPress;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
index 6fff0ba..517d96a 100644
--- a/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
+++ b/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
@@ -17,7 +17,6 @@
 package com.android.keyguard;
 
 import android.content.Context;
-import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 50ac261..3627e3e 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -21,7 +21,7 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.telephony.TelephonyManager;
+import android.telecom.TelecomManager;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
@@ -50,8 +50,17 @@
             updateEmergencyCallButton();
         }
     };
+
+    public interface EmergencyButtonCallback {
+        public void onEmergencyButtonClickedWhenInCall();
+    }
+
     private LockPatternUtils mLockPatternUtils;
     private PowerManager mPowerManager;
+    private EmergencyButtonCallback mEmergencyButtonCallback;
+
+    private final boolean mIsVoiceCapable;
+    private final boolean mEnableEmergencyCallWhileSimLocked;
 
     public EmergencyButton(Context context) {
         this(context, null);
@@ -59,6 +68,10 @@
 
     public EmergencyButton(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mIsVoiceCapable = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_voice_capable);
+        mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
     }
 
     @Override
@@ -93,8 +106,11 @@
         // TODO: implement a shorter timeout once new PowerManager API is ready.
         // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
         mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
-        if (mLockPatternUtils.isInCall()) {
-            mLockPatternUtils.resumeCall();
+        if (isInCall()) {
+            resumeCall();
+            if (mEmergencyButtonCallback != null) {
+                mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
+            }
         } else {
             final boolean bypassHandler = true;
             KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
@@ -107,21 +123,57 @@
     }
 
     private void updateEmergencyCallButton() {
-        boolean enabled = false;
-        if (mLockPatternUtils.isInCall()) {
-            enabled = true; // always show "return to call" if phone is off-hook
-        } else if (mLockPatternUtils.isEmergencyCallCapable()) {
-            final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimPinVoiceSecure();
-            if (simLocked) {
-                // Some countries can't handle emergency calls while SIM is locked.
-                enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
+        boolean visible = false;
+        if (mIsVoiceCapable) {
+            // Emergency calling requires voice capability.
+            if (isInCall()) {
+                visible = true; // always show "return to call" if phone is off-hook
             } else {
-                // True if we need to show a secure screen (pin/pattern/SIM pin/SIM puk);
-                // hides emergency button on "Slide" screen if device is not secure.
-                enabled = mLockPatternUtils.isSecure();
+                final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext)
+                        .isSimPinVoiceSecure();
+                if (simLocked) {
+                    // Some countries can't handle emergency calls while SIM is locked.
+                    visible = mEnableEmergencyCallWhileSimLocked;
+                } else {
+                    // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
+                    visible = mLockPatternUtils.isSecure();
+                }
             }
         }
-        mLockPatternUtils.updateEmergencyCallButtonState(this, enabled, false);
+        if (visible) {
+            setVisibility(View.VISIBLE);
+
+            int textId;
+            if (isInCall()) {
+                textId = com.android.internal.R.string.lockscreen_return_to_call;
+            } else {
+                textId = com.android.internal.R.string.lockscreen_emergency_call;
+            }
+            setText(textId);
+        } else {
+            setVisibility(View.GONE);
+        }
     }
 
+    public void setCallback(EmergencyButtonCallback callback) {
+        mEmergencyButtonCallback = callback;
+    }
+
+    /**
+     * Resumes a call in progress.
+     */
+    private void resumeCall() {
+        getTelecommManager().showInCallScreen(false);
+    }
+
+    /**
+     * @return {@code true} if there is a call currently in progress.
+     */
+    private boolean isInCall() {
+        return getTelecommManager().isInCall();
+    }
+
+    private TelecomManager getTelecommManager() {
+        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
deleted file mode 100644
index 8d13ac2..0000000
--- a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import com.android.internal.policy.IFaceLockCallback;
-import com.android.internal.policy.IFaceLockInterface;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.View;
-
-public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
-
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final String TAG = "FULLockscreen";
-    private static final String FACE_LOCK_PACKAGE = "com.android.facelock";
-
-    private final Context mContext;
-    private final LockPatternUtils mLockPatternUtils;
-
-    // TODO: is mServiceRunning needed or can we just use mIsRunning or check if mService is null?
-    private boolean mServiceRunning = false;
-    // TODO: now that the code has been restructure to do almost all operations from a handler, this
-    // lock may no longer be necessary.
-    private final Object mServiceRunningLock = new Object();
-    private IFaceLockInterface mService;
-    private boolean mBoundToService = false;
-    private View mFaceUnlockView;
-
-    private Handler mHandler;
-    private final int MSG_SERVICE_CONNECTED = 0;
-    private final int MSG_SERVICE_DISCONNECTED = 1;
-    private final int MSG_UNLOCK = 2;
-    private final int MSG_CANCEL = 3;
-    private final int MSG_REPORT_FAILED_ATTEMPT = 4;
-    private final int MSG_POKE_WAKELOCK = 5;
-
-    // TODO: This was added for the purpose of adhering to what the biometric interface expects
-    // the isRunning() function to return.  However, it is probably not necessary to have both
-    // mRunning and mServiceRunning.  I'd just rather wait to change that logic.
-    private volatile boolean mIsRunning = false;
-
-    KeyguardSecurityCallback mKeyguardScreenCallback;
-
-    /**
-     * Stores some of the structures that Face Unlock will need to access and creates the handler
-     * will be used to execute messages on the UI thread.
-     */
-    public FaceUnlock(Context context) {
-        mContext = context;
-        mLockPatternUtils = new LockPatternUtils(context);
-        mHandler = new Handler(this);
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback) {
-        mKeyguardScreenCallback = keyguardScreenCallback;
-    }
-
-    /**
-     * Stores and displays the view that Face Unlock is allowed to draw within.
-     * TODO: since the layout object will eventually be shared by multiple biometric unlock
-     * methods, we will have to add our other views (background, cancel button) here.
-     */
-    public void initializeView(View biometricUnlockView) {
-        Log.d(TAG, "initializeView()");
-        mFaceUnlockView = biometricUnlockView;
-    }
-
-    /**
-     * Indicates whether Face Unlock is currently running.
-     */
-    public boolean isRunning() {
-        return mIsRunning;
-    }
-
-    /**
-     * Dismisses face unlock and goes to the backup lock
-     */
-    public void stopAndShowBackup() {
-        if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
-        mHandler.sendEmptyMessage(MSG_CANCEL);
-    }
-
-    /**
-     * Binds to the Face Unlock service.  Face Unlock will be started when the bind completes.  The
-     * Face Unlock view is displayed to hide the backup lock while the service is starting up.
-     * Called on the UI thread.
-     */
-    public boolean start() {
-        if (DEBUG) Log.d(TAG, "start()");
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            Log.e(TAG, "start() called off of the UI thread");
-        }
-
-        if (mIsRunning) {
-            Log.w(TAG, "start() called when already running");
-        }
-
-        if (!mBoundToService) {
-            Log.d(TAG, "Binding to Face Unlock service for user="
-                    + mLockPatternUtils.getCurrentUser());
-            mContext.bindServiceAsUser(
-                    new Intent(IFaceLockInterface.class.getName()).setPackage(FACE_LOCK_PACKAGE),
-                    mConnection,
-                    Context.BIND_AUTO_CREATE,
-                    new UserHandle(mLockPatternUtils.getCurrentUser()));
-            mBoundToService = true;
-        } else {
-            Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
-        }
-
-        mIsRunning = true;
-        return true;
-    }
-
-    /**
-     * Stops Face Unlock and unbinds from the service.  Called on the UI thread.
-     */
-    public boolean stop() {
-        if (DEBUG) Log.d(TAG, "stop()");
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            Log.e(TAG, "stop() called from non-UI thread");
-        }
-
-        // Clearing any old service connected messages.
-        mHandler.removeMessages(MSG_SERVICE_CONNECTED);
-
-        boolean mWasRunning = mIsRunning;
-
-        stopUi();
-
-        if (mBoundToService) {
-            if (mService != null) {
-                try {
-                    mService.unregisterCallback(mFaceUnlockCallback);
-                } catch (RemoteException e) {
-                    // Not much we can do
-                }
-            }
-            Log.d(TAG, "Unbinding from Face Unlock service");
-            mContext.unbindService(mConnection);
-            mBoundToService = false;
-        } else {
-            // This is usually not an error when this happens.  Sometimes we will tell it to
-            // unbind multiple times because it's called from both onWindowFocusChanged and
-            // onDetachedFromWindow.
-            if (DEBUG) Log.d(TAG, "Attempt to unbind from Face Unlock when not bound");
-        }
-        mIsRunning = false;
-        return mWasRunning;
-    }
-
-    /**
-     * Frees up resources used by Face Unlock and stops it if it is still running.
-     */
-    public void cleanUp() {
-        if (DEBUG) Log.d(TAG, "cleanUp()");
-        if (mService != null) {
-            try {
-                mService.unregisterCallback(mFaceUnlockCallback);
-            } catch (RemoteException e) {
-                // Not much we can do
-            }
-            stopUi();
-            mService = null;
-        }
-    }
-
-    /**
-     * Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.
-     */
-    public int getQuality() {
-        return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
-    }
-
-    /**
-     * Handles messages such that everything happens on the UI thread in a deterministic order.
-     * Calls from the Face Unlock service come from binder threads.  Calls from lockscreen typically
-     * come from the UI thread.  This makes sure there are no race conditions between those calls.
-     */
-    public boolean handleMessage(Message msg) {
-        switch (msg.what) {
-            case MSG_SERVICE_CONNECTED:
-                handleServiceConnected();
-                break;
-            case MSG_SERVICE_DISCONNECTED:
-                handleServiceDisconnected();
-                break;
-            case MSG_UNLOCK:
-                handleUnlock(msg.arg1);
-                break;
-            case MSG_CANCEL:
-                handleCancel();
-                break;
-            case MSG_REPORT_FAILED_ATTEMPT:
-                handleReportFailedAttempt();
-                break;
-            case MSG_POKE_WAKELOCK:
-                handlePokeWakelock(msg.arg1);
-                break;
-            default:
-                Log.e(TAG, "Unhandled message");
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * Tells the service to start its UI via an AIDL interface.  Called when the
-     * onServiceConnected() callback is received.
-     */
-    void handleServiceConnected() {
-        Log.d(TAG, "handleServiceConnected()");
-
-        // It is possible that an unbind has occurred in the time between the bind and when this
-        // function is reached.  If an unbind has already occurred, proceeding on to call startUi()
-        // can result in a fatal error.  Note that the onServiceConnected() callback is
-        // asynchronous, so this possibility would still exist if we executed this directly in
-        // onServiceConnected() rather than using a handler.
-        if (!mBoundToService) {
-            Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
-            return;
-        }
-
-        try {
-            mService.registerCallback(mFaceUnlockCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
-            mService = null;
-            mBoundToService = false;
-            mIsRunning = false;
-            return;
-        }
-
-        if (mFaceUnlockView != null) {
-            IBinder windowToken = mFaceUnlockView.getWindowToken();
-            if (windowToken != null) {
-                // When switching between portrait and landscape view while Face Unlock is running,
-                // the screen will eventually go dark unless we poke the wakelock when Face Unlock
-                // is restarted.
-                mKeyguardScreenCallback.userActivity();
-
-                int[] position;
-                position = new int[2];
-                mFaceUnlockView.getLocationInWindow(position);
-                startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
-                        mFaceUnlockView.getHeight());
-            } else {
-                Log.e(TAG, "windowToken is null in handleServiceConnected()");
-            }
-        }
-    }
-
-    /**
-     * Called when the onServiceDisconnected() callback is received.  This should not happen during
-     * normal operation.  It indicates an error has occurred.
-     */
-    void handleServiceDisconnected() {
-        Log.e(TAG, "handleServiceDisconnected()");
-        // TODO: this lock may no longer be needed now that everything is being called from a
-        // handler
-        synchronized (mServiceRunningLock) {
-            mService = null;
-            mServiceRunning = false;
-        }
-        mBoundToService = false;
-        mIsRunning = false;
-    }
-
-    /**
-     * Stops the Face Unlock service and tells the device to grant access to the user.
-     */
-    void handleUnlock(int authenticatedUserId) {
-        if (DEBUG) Log.d(TAG, "handleUnlock()");
-        stop();
-        int currentUserId = mLockPatternUtils.getCurrentUser();
-        if (authenticatedUserId == currentUserId) {
-            if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
-            mKeyguardScreenCallback.reportUnlockAttempt(true);
-            mKeyguardScreenCallback.dismiss(true);
-        } else {
-            Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
-                    ") because the current user is " + currentUserId);
-        }
-    }
-
-    /**
-     * Stops the Face Unlock service and goes to the backup lock.
-     */
-    void handleCancel() {
-        if (DEBUG) Log.d(TAG, "handleCancel()");
-        // We are going to the backup method, so we don't want to see Face Unlock again until the
-        // next time the user visits keyguard.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
-
-        mKeyguardScreenCallback.showBackupSecurity();
-        stop();
-        mKeyguardScreenCallback.userActivity();
-    }
-
-    /**
-     * Increments the number of failed Face Unlock attempts.
-     */
-    void handleReportFailedAttempt() {
-        if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
-        // We are going to the backup method, so we don't want to see Face Unlock again until the
-        // next time the user visits keyguard.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);
-
-        mKeyguardScreenCallback.reportUnlockAttempt(false);
-    }
-
-    /**
-     * If the screen is on, pokes the wakelock to keep the screen alive and active for a specific
-     * amount of time.
-     */
-    void handlePokeWakelock(int millis) {
-      PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-      if (powerManager.isScreenOn()) {
-        mKeyguardScreenCallback.userActivity();
-      }
-    }
-
-    /**
-     * Implements service connection methods.
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-        /**
-         * Called when the Face Unlock service connects after calling bind().
-         */
-        public void onServiceConnected(ComponentName className, IBinder iservice) {
-            Log.d(TAG, "Connected to Face Unlock service");
-            mService = IFaceLockInterface.Stub.asInterface(iservice);
-            mHandler.sendEmptyMessage(MSG_SERVICE_CONNECTED);
-        }
-
-        /**
-         * Called if the Face Unlock service unexpectedly disconnects.  This indicates an error.
-         */
-        public void onServiceDisconnected(ComponentName className) {
-            Log.e(TAG, "Unexpected disconnect from Face Unlock service");
-            mHandler.sendEmptyMessage(MSG_SERVICE_DISCONNECTED);
-        }
-    };
-
-    /**
-     * Tells the Face Unlock service to start displaying its UI and start processing.
-     */
-    private void startUi(IBinder windowToken, int x, int y, int w, int h) {
-        if (DEBUG) Log.d(TAG, "startUi()");
-        synchronized (mServiceRunningLock) {
-            if (!mServiceRunning) {
-                Log.d(TAG, "Starting Face Unlock");
-                try {
-                    mService.startUi(windowToken, x, y, w, h,
-                            mLockPatternUtils.isBiometricWeakLivelinessEnabled());
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
-                    return;
-                }
-                mServiceRunning = true;
-            } else {
-                Log.w(TAG, "startUi() attempted while running");
-            }
-        }
-    }
-
-    /**
-     * Tells the Face Unlock service to stop displaying its UI and stop processing.
-     */
-    private void stopUi() {
-        if (DEBUG) Log.d(TAG, "stopUi()");
-        // Note that attempting to stop Face Unlock when it's not running is not an issue.
-        // Face Unlock can return, which stops it and then we try to stop it when the
-        // screen is turned off.  That's why we check.
-        synchronized (mServiceRunningLock) {
-            if (mServiceRunning) {
-                Log.d(TAG, "Stopping Face Unlock");
-                try {
-                    mService.stopUi();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
-                }
-                mServiceRunning = false;
-            } else {
-                // This is usually not an error when this happens.  Sometimes we will tell it to
-                // stop multiple times because it's called from both onWindowFocusChanged and
-                // onDetachedFromWindow.
-                if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
-            }
-        }
-    }
-
-    /**
-     * Implements the AIDL biometric unlock service callback interface.
-     */
-    private final IFaceLockCallback mFaceUnlockCallback = new IFaceLockCallback.Stub() {
-        /**
-         * Called when Face Unlock wants to grant access to the user.
-         */
-        public void unlock() {
-            if (DEBUG) Log.d(TAG, "unlock()");
-            Message message = mHandler.obtainMessage(MSG_UNLOCK, UserHandle.getCallingUserId(), -1);
-            mHandler.sendMessage(message);
-        }
-
-        /**
-         * Called when Face Unlock wants to go to the backup.
-         */
-        public void cancel() {
-            if (DEBUG) Log.d(TAG, "cancel()");
-            mHandler.sendEmptyMessage(MSG_CANCEL);
-        }
-
-        /**
-         * Called when Face Unlock wants to increment the number of failed attempts.
-         */
-        public void reportFailedAttempt() {
-            if (DEBUG) Log.d(TAG, "reportFailedAttempt()");
-            mHandler.sendEmptyMessage(MSG_REPORT_FAILED_ATTEMPT);
-        }
-
-        /**
-         * Called when Face Unlock wants to keep the screen alive and active for a specific amount
-         * of time.
-         */
-        public void pokeWakelock(int millis) {
-            if (DEBUG) Log.d(TAG, "pokeWakelock() for " + millis + "ms");
-            Message message = mHandler.obtainMessage(MSG_POKE_WAKELOCK, millis, -1);
-            mHandler.sendMessage(message);
-        }
-
-    };
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a411df3..322be91 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -17,7 +17,6 @@
 package com.android.keyguard;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -32,12 +31,11 @@
  * Base class for PIN and password unlock screens.
  */
 public abstract class KeyguardAbsKeyInputView extends LinearLayout
-        implements KeyguardSecurityView {
+        implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
     protected KeyguardSecurityCallback mCallback;
     protected LockPatternUtils mLockPatternUtils;
     protected SecurityMessageDisplay mSecurityMessageDisplay;
     protected View mEcaView;
-    private Drawable mBouncerFrame;
     protected boolean mEnableHaptics;
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
@@ -86,12 +84,17 @@
         mLockPatternUtils = new LockPatternUtils(mContext);
         mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
+
+        EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
+        if (button != null) {
+            button.setCallback(this);
         }
     }
 
+    public void onEmergencyButtonClickedWhenInCall() {
+        mCallback.reset();
+    }
+
     /*
      * Override this if you have a different string for "wrong password"
      *
@@ -183,18 +186,6 @@
     }
 
     @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
     public boolean startDisappearAnimation(Runnable finishRunnable) {
         return false;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
deleted file mode 100644
index 5cb3b9b..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.LoginFilter;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import java.io.IOException;
-
-/**
- * When the user forgets their password a bunch of times, we fall back on their
- * account's login/password to unlock the phone (and reset their lock pattern).
- */
-public class KeyguardAccountView extends LinearLayout implements KeyguardSecurityView,
-        View.OnClickListener, TextWatcher {
-    private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
-    private static final String LOCK_PATTERN_CLASS = LOCK_PATTERN_PACKAGE + ".ChooseLockGeneric";
-
-    private KeyguardSecurityCallback mCallback;
-    private LockPatternUtils mLockPatternUtils;
-    private EditText mLogin;
-    private EditText mPassword;
-    private Button mOk;
-    public boolean mEnableFallback;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-
-    /**
-     * Shown while making asynchronous check of password.
-     */
-    private ProgressDialog mCheckingDialog;
-
-    public KeyguardAccountView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardAccountView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardAccountView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mLockPatternUtils = new LockPatternUtils(getContext());
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mLogin = (EditText) findViewById(R.id.login);
-        mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
-        mLogin.addTextChangedListener(this);
-
-        mPassword = (EditText) findViewById(R.id.password);
-        mPassword.addTextChangedListener(this);
-
-        mOk = (Button) findViewById(R.id.ok);
-        mOk.setOnClickListener(this);
-
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        reset();
-    }
-
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-
-    public void afterTextChanged(Editable s) {
-    }
-
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-    }
-
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-        if (mCallback != null) {
-            mCallback.userActivity();
-        }
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction,
-            Rect previouslyFocusedRect) {
-        // send focus to the login field
-        return mLogin.requestFocus(direction, previouslyFocusedRect);
-    }
-
-    public boolean needsInput() {
-        return true;
-    }
-
-    public void reset() {
-        // start fresh
-        mLogin.setText("");
-        mPassword.setText("");
-        mLogin.requestFocus();
-        boolean permLocked = mLockPatternUtils.isPermanentlyLocked();
-        mSecurityMessageDisplay.setMessage(permLocked ? R.string.kg_login_too_many_attempts :
-            R.string.kg_login_instructions, permLocked ? true : false);
-    }
-
-    /** {@inheritDoc} */
-    public void cleanUp() {
-        if (mCheckingDialog != null) {
-            mCheckingDialog.hide();
-        }
-        mCallback = null;
-        mLockPatternUtils = null;
-    }
-
-    public void onClick(View v) {
-        mCallback.userActivity();
-        if (v == mOk) {
-            asyncCheckPassword();
-        }
-    }
-
-    private void postOnCheckPasswordResult(final boolean success) {
-        // ensure this runs on UI thread
-        mLogin.post(new Runnable() {
-            public void run() {
-                if (success) {
-                    // clear out forgotten password
-                    mLockPatternUtils.setPermanentlyLocked(false);
-                    mLockPatternUtils.setLockPatternEnabled(false);
-                    mLockPatternUtils.saveLockPattern(null);
-
-                    // launch the 'choose lock pattern' activity so
-                    // the user can pick a new one if they want to
-                    Intent intent = new Intent();
-                    intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivityAsUser(intent,
-                            new UserHandle(mLockPatternUtils.getCurrentUser()));
-                    mCallback.reportUnlockAttempt(true);
-
-                    // dismiss keyguard
-                    mCallback.dismiss(true);
-                } else {
-                    mSecurityMessageDisplay.setMessage(R.string.kg_login_invalid_input, true);
-                    mPassword.setText("");
-                    mCallback.reportUnlockAttempt(false);
-                }
-            }
-        });
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-            if (mLockPatternUtils.isPermanentlyLocked()) {
-                mCallback.dismiss(false);
-            } else {
-                // TODO: mCallback.forgotPattern(false);
-            }
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /**
-     * Given the string the user entered in the 'username' field, find
-     * the stored account that they probably intended.  Prefer, in order:
-     *
-     *   - an exact match for what was typed, or
-     *   - a case-insensitive match for what was typed, or
-     *   - if they didn't include a domain, an exact match of the username, or
-     *   - if they didn't include a domain, a case-insensitive
-     *     match of the username.
-     *
-     * If there is a tie for the best match, choose neither --
-     * the user needs to be more specific.
-     *
-     * @return an account name from the database, or null if we can't
-     * find a single best match.
-     */
-    private Account findIntendedAccount(String username) {
-        Account[] accounts = AccountManager.get(mContext).getAccountsByTypeAsUser("com.google",
-                new UserHandle(mLockPatternUtils.getCurrentUser()));
-
-        // Try to figure out which account they meant if they
-        // typed only the username (and not the domain), or got
-        // the case wrong.
-
-        Account bestAccount = null;
-        int bestScore = 0;
-        for (Account a: accounts) {
-            int score = 0;
-            if (username.equals(a.name)) {
-                score = 4;
-            } else if (username.equalsIgnoreCase(a.name)) {
-                score = 3;
-            } else if (username.indexOf('@') < 0) {
-                int i = a.name.indexOf('@');
-                if (i >= 0) {
-                    String aUsername = a.name.substring(0, i);
-                    if (username.equals(aUsername)) {
-                        score = 2;
-                    } else if (username.equalsIgnoreCase(aUsername)) {
-                        score = 1;
-                    }
-                }
-            }
-            if (score > bestScore) {
-                bestAccount = a;
-                bestScore = score;
-            } else if (score == bestScore) {
-                bestAccount = null;
-            }
-        }
-        return bestAccount;
-    }
-
-    private void asyncCheckPassword() {
-        mCallback.userActivity();
-        final String login = mLogin.getText().toString();
-        final String password = mPassword.getText().toString();
-        Account account = findIntendedAccount(login);
-        if (account == null) {
-            postOnCheckPasswordResult(false);
-            return;
-        }
-        getProgressDialog().show();
-        Bundle options = new Bundle();
-        options.putString(AccountManager.KEY_PASSWORD, password);
-        AccountManager.get(mContext).confirmCredentialsAsUser(account, options, null /* activity */,
-                new AccountManagerCallback<Bundle>() {
-            public void run(AccountManagerFuture<Bundle> future) {
-                try {
-                    mCallback.userActivity();
-                    final Bundle result = future.getResult();
-                    final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
-                    postOnCheckPasswordResult(verified);
-                } catch (OperationCanceledException e) {
-                    postOnCheckPasswordResult(false);
-                } catch (IOException e) {
-                    postOnCheckPasswordResult(false);
-                } catch (AuthenticatorException e) {
-                    postOnCheckPasswordResult(false);
-                } finally {
-                    mLogin.post(new Runnable() {
-                        public void run() {
-                            getProgressDialog().hide();
-                        }
-                    });
-                }
-            }
-        }, null /* handler */, new UserHandle(mLockPatternUtils.getCurrentUser()));
-    }
-
-    private Dialog getProgressDialog() {
-        if (mCheckingDialog == null) {
-            mCheckingDialog = new ProgressDialog(mContext);
-            mCheckingDialog.setMessage(
-                    mContext.getString(R.string.kg_login_checking_password));
-            mCheckingDialog.setIndeterminate(true);
-            mCheckingDialog.setCancelable(false);
-            mCheckingDialog.getWindow().setType(
-                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        }
-        return mCheckingDialog;
-    }
-
-    @Override
-    public void onPause() {
-
-    }
-
-    @Override
-    public void onResume(int reason) {
-        reset();
-    }
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-    }
-
-    @Override
-    public void startAppearAnimation() {
-        // TODO.
-    }
-
-    @Override
-    public boolean startDisappearAnimation(Runnable finishRunnable) {
-        return false;
-    }
-}
-
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
deleted file mode 100644
index 1978ded..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
-import android.app.IActivityManager.WaitResult;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
-
-import java.util.List;
-
-public abstract class KeyguardActivityLauncher {
-    private static final String TAG = KeyguardActivityLauncher.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final String META_DATA_KEYGUARD_LAYOUT = "com.android.keyguard.layout";
-    private static final Intent SECURE_CAMERA_INTENT =
-            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
-                    .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-    private static final Intent INSECURE_CAMERA_INTENT =
-            new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
-
-    abstract Context getContext();
-
-    abstract LockPatternUtils getLockPatternUtils();
-
-    abstract void setOnDismissAction(OnDismissAction action);
-
-    abstract void requestDismissKeyguard();
-
-    public static class CameraWidgetInfo {
-        public String contextPackage;
-        public int layoutId;
-    }
-
-    public CameraWidgetInfo getCameraWidgetInfo() {
-        CameraWidgetInfo info = new CameraWidgetInfo();
-        Intent intent = getCameraIntent();
-        PackageManager packageManager = getContext().getPackageManager();
-        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        if (appList.size() == 0) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Nothing found");
-            return null;
-        }
-        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                getLockPatternUtils().getCurrentUser());
-        if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): resolved: " + resolved);
-        if (wouldLaunchResolverActivity(resolved, appList)) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): Would launch resolver");
-            return info;
-        }
-        if (resolved == null || resolved.activityInfo == null) {
-            return null;
-        }
-        if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no metadata found");
-            return info;
-        }
-        int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
-        if (layoutId == 0) {
-            if (DEBUG) Log.d(TAG, "getCameraWidgetInfo(): no layout specified");
-            return info;
-        }
-        info.contextPackage = resolved.activityInfo.packageName;
-        info.layoutId = layoutId;
-        return info;
-    }
-
-    public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
-        LockPatternUtils lockPatternUtils = getLockPatternUtils();
-
-        // Workaround to avoid camera release/acquisition race when resuming face unlock
-        // after showing lockscreen camera (bug 11063890).
-        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
-        updateMonitor.setAlternateUnlockEnabled(false);
-
-        if (mustLaunchSecurely()) {
-            // Launch the secure version of the camera
-            if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
-                // TODO: Show disambiguation dialog instead.
-                // For now, we'll treat this like launching any other app from secure keyguard.
-                // When they do, user sees the system's ResolverActivity which lets them choose
-                // which secure camera to use.
-                launchActivity(SECURE_CAMERA_INTENT, false, false, null, null);
-            } else {
-                launchActivity(SECURE_CAMERA_INTENT, true, false, worker, onSecureCameraStarted);
-            }
-        } else {
-            // Launch the normal camera
-            launchActivity(INSECURE_CAMERA_INTENT, false, false, null, null);
-        }
-    }
-
-    private boolean mustLaunchSecurely() {
-        LockPatternUtils lockPatternUtils = getLockPatternUtils();
-        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(getContext());
-        int currentUser = lockPatternUtils.getCurrentUser();
-        return lockPatternUtils.isSecure() && !updateMonitor.getUserHasTrust(currentUser);
-    }
-
-    public void launchWidgetPicker(int appWidgetId) {
-        Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
-
-        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
-                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
-
-        Bundle options = new Bundle();
-        options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
-        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
-        pickIntent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
-        launchActivity(pickIntent, false, false, null, null);
-    }
-
-    /**
-     * Launches the said intent for the current foreground user.
-     *
-     * @param intent
-     * @param showsWhileLocked true if the activity can be run on top of keyguard.
-     *   See {@link WindowManager#FLAG_SHOW_WHEN_LOCKED}
-     * @param useDefaultAnimations true if default transitions should be used, else suppressed.
-     * @param worker if supplied along with onStarted, used to launch the blocking activity call.
-     * @param onStarted if supplied along with worker, called after activity is started.
-     */
-    public void launchActivity(final Intent intent,
-            boolean showsWhileLocked,
-            boolean useDefaultAnimations,
-            final Handler worker,
-            final Runnable onStarted) {
-
-        final Context context = getContext();
-        final Bundle animation = useDefaultAnimations ? null
-                : ActivityOptions.makeCustomAnimation(context, 0, 0).toBundle();
-        launchActivityWithAnimation(intent, showsWhileLocked, animation, worker, onStarted);
-    }
-
-    public void launchActivityWithAnimation(final Intent intent,
-            boolean showsWhileLocked,
-            final Bundle animation,
-            final Handler worker,
-            final Runnable onStarted) {
-
-        LockPatternUtils lockPatternUtils = getLockPatternUtils();
-        intent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        boolean mustLaunchSecurely = mustLaunchSecurely();
-        if (!mustLaunchSecurely || showsWhileLocked) {
-            if (!mustLaunchSecurely) {
-                dismissKeyguardOnNextActivity();
-            }
-            try {
-                if (DEBUG) Log.d(TAG, String.format("Starting activity for intent %s at %s",
-                        intent, SystemClock.uptimeMillis()));
-                startActivityForCurrentUser(intent, animation, worker, onStarted);
-            } catch (ActivityNotFoundException e) {
-                Log.w(TAG, "Activity not found for intent + " + intent.getAction());
-            }
-        } else {
-            // Create a runnable to start the activity and ask the user to enter their
-            // credentials.
-            setOnDismissAction(new OnDismissAction() {
-                @Override
-                public boolean onDismiss() {
-                    dismissKeyguardOnNextActivity();
-                    startActivityForCurrentUser(intent, animation, worker, onStarted);
-                    return true;
-                }
-            });
-            requestDismissKeyguard();
-        }
-    }
-
-    private void dismissKeyguardOnNextActivity() {
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error dismissing keyguard", e);
-        }
-    }
-
-    private void startActivityForCurrentUser(final Intent intent, final Bundle options,
-            Handler worker, final Runnable onStarted) {
-        final UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
-        if (worker == null || onStarted == null) {
-            getContext().startActivityAsUser(intent, options, user);
-            return;
-        }
-        // if worker + onStarted are supplied, run blocking activity launch call in the background
-        worker.post(new Runnable(){
-            @Override
-            public void run() {
-                try {
-                    WaitResult result = ActivityManagerNative.getDefault().startActivityAndWait(
-                            null /*caller*/,
-                            null /*caller pkg*/,
-                            intent,
-                            intent.resolveTypeIfNeeded(getContext().getContentResolver()),
-                            null /*resultTo*/,
-                            null /*resultWho*/,
-                            0 /*requestCode*/,
-                            Intent.FLAG_ACTIVITY_NEW_TASK,
-                            null /*profilerInfo*/,
-                            options,
-                            user.getIdentifier());
-                    if (DEBUG) Log.d(TAG, String.format("waitResult[%s,%s,%s,%s] at %s",
-                            result.result, result.thisTime, result.totalTime, result.who,
-                            SystemClock.uptimeMillis()));
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Error starting activity", e);
-                    return;
-                }
-                try {
-                    onStarted.run();
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onStarted callback", t);
-                }
-            }});
-    }
-
-    private Intent getCameraIntent() {
-        return mustLaunchSecurely() ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
-    }
-
-    private boolean wouldLaunchResolverActivity(Intent intent) {
-        PackageManager packageManager = getContext().getPackageManager();
-        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
-                PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY, getLockPatternUtils().getCurrentUser());
-        return wouldLaunchResolverActivity(resolved, appList);
-    }
-
-    private boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) {
-        // If the list contains the above resolved activity, then it can't be
-        // ResolverActivity itself.
-        for (int i = 0; i < appList.size(); i++) {
-            ResolveInfo tmp = appList.get(i);
-            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
-                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
-                return false;
-            }
-        }
-        return true;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java b/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java
deleted file mode 100644
index 0e08cf4..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardCircleFramedDrawable.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-
-class KeyguardCircleFramedDrawable extends Drawable {
-
-    private final Bitmap mBitmap;
-    private final int mSize;
-    private final Paint mPaint;
-    private final float mShadowRadius;
-    private final float mStrokeWidth;
-    private final int mFrameColor;
-    private final int mHighlightColor;
-    private final int mFrameShadowColor;
-
-    private float mScale;
-    private Path mFramePath;
-    private Rect mSrcRect;
-    private RectF mDstRect;
-    private RectF mFrameRect;
-    private boolean mPressed;
-
-    public KeyguardCircleFramedDrawable(Bitmap bitmap, int size,
-            int frameColor, float strokeWidth,
-            int frameShadowColor, float shadowRadius,
-            int highlightColor) {
-        super();
-        mSize = size;
-        mShadowRadius = shadowRadius;
-        mFrameColor = frameColor;
-        mFrameShadowColor = frameShadowColor;
-        mStrokeWidth = strokeWidth;
-        mHighlightColor = highlightColor;
-
-        mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(mBitmap);
-
-        final int width = bitmap.getWidth();
-        final int height = bitmap.getHeight();
-        final int square = Math.min(width, height);
-
-        final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square);
-        final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
-        circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
-        circleRect.inset(mShadowRadius, mShadowRadius);
-
-        final Path fillPath = new Path();
-        fillPath.addArc(circleRect, 0f, 360f);
-
-        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
-
-        // opaque circle matte
-        mPaint = new Paint();
-        mPaint.setAntiAlias(true);
-        mPaint.setColor(Color.BLACK);
-        mPaint.setStyle(Paint.Style.FILL);
-        canvas.drawPath(fillPath, mPaint);
-
-        // mask in the icon where the bitmap is opaque
-        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
-        canvas.drawBitmap(bitmap, cropRect, circleRect, mPaint);
-
-        // prepare paint for frame drawing
-        mPaint.setXfermode(null);
-
-        mScale = 1f;
-
-        mSrcRect = new Rect(0, 0, mSize, mSize);
-        mDstRect = new RectF(0, 0, mSize, mSize);
-        mFrameRect = new RectF(mDstRect);
-        mFramePath = new Path();
-    }
-
-    public void reset() {
-        mScale = 1f;
-        mPressed = false;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        // clear background
-        final float outside = Math.min(canvas.getWidth(), canvas.getHeight());
-        final float inside = mScale * outside;
-        final float pad = (outside - inside) / 2f;
-
-        mDstRect.set(pad, pad, outside - pad, outside - pad);
-        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
-
-        mFrameRect.set(mDstRect);
-        mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f);
-        mFrameRect.inset(mShadowRadius, mShadowRadius);
-
-        mFramePath.reset();
-        mFramePath.addArc(mFrameRect, 0f, 360f);
-
-        // white frame
-        if (mPressed) {
-            mPaint.setStyle(Paint.Style.FILL);
-            mPaint.setColor(Color.argb((int) (0.33f * 255),
-                            Color.red(mHighlightColor),
-                            Color.green(mHighlightColor),
-                            Color.blue(mHighlightColor)));
-            canvas.drawPath(mFramePath, mPaint);
-        }
-        mPaint.setStrokeWidth(mStrokeWidth);
-        mPaint.setStyle(Paint.Style.STROKE);
-        mPaint.setColor(mPressed ? mHighlightColor : mFrameColor);
-        mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor);
-        canvas.drawPath(mFramePath, mPaint);
-    }
-
-    public void setScale(float scale) {
-        mScale = scale;
-    }
-
-    public float getScale() {
-        return mScale;
-    }
-
-    public void setPressed(boolean pressed) {
-        mPressed = pressed;
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-    }
-
-    public boolean verifyParams(float iconSize, int frameColor, float stroke,
-            int frameShadowColor, float shadowRadius, int highlightColor) {
-        return mSize == iconSize
-                && mFrameColor == frameColor
-                && mStrokeWidth == stroke
-                && mFrameShadowColor == frameShadowColor
-                && mShadowRadius == shadowRadius
-                && mHighlightColor == highlightColor;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
deleted file mode 100644
index b3e9f77..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import java.lang.Math;
-
-public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
-
-    private static final String TAG = "FULKeyguardFaceUnlockView";
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private KeyguardSecurityCallback mKeyguardSecurityCallback;
-    private LockPatternUtils mLockPatternUtils;
-    private BiometricSensorUnlock mBiometricUnlock;
-    private View mFaceUnlockAreaView;
-    private ImageButton mCancelButton;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-    private View mEcaView;
-    private Drawable mBouncerFrame;
-
-    private boolean mIsBouncerVisibleToUser = false;
-    private final Object mIsBouncerVisibleToUserLock = new Object();
-
-    private int mLastRotation;
-    private boolean mWatchingRotation;
-    private final IWindowManager mWindowManager =
-            IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
-
-    private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
-        public void onRotationChanged(int rotation) {
-            if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
-
-            // If the difference between the new rotation value and the previous rotation value is
-            // equal to 2, the rotation change was 180 degrees.  This stops the biometric unlock
-            // and starts it in the new position.  This is not performed for 90 degree rotations
-            // since a 90 degree rotation is a configuration change, which takes care of this for
-            // us.
-            if (Math.abs(rotation - mLastRotation) == 2) {
-                if (mBiometricUnlock != null) {
-                    mBiometricUnlock.stop();
-                    maybeStartBiometricUnlock();
-                }
-            }
-            mLastRotation = rotation;
-        }
-    };
-
-    public KeyguardFaceUnlockView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardFaceUnlockView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        initializeBiometricUnlockView();
-
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
-        }
-    }
-
-    @Override
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mKeyguardSecurityCallback = callback;
-        // TODO: formalize this in the interface or factor it out
-        ((FaceUnlock)mBiometricUnlock).setKeyguardCallback(callback);
-    }
-
-    @Override
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    @Override
-    public void reset() {
-
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
-        if (mBiometricUnlock != null) {
-            mBiometricUnlock.stop();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
-        if (mWatchingRotation) {
-            try {
-                mWindowManager.removeRotationWatcher(mRotationWatcher);
-                mWatchingRotation = false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when removing rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public void onPause() {
-        if (DEBUG) Log.d(TAG, "onPause()");
-        if (mBiometricUnlock != null) {
-            mBiometricUnlock.stop();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
-        if (mWatchingRotation) {
-            try {
-                mWindowManager.removeRotationWatcher(mRotationWatcher);
-                mWatchingRotation = false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when removing rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public void onResume(int reason) {
-        if (DEBUG) Log.d(TAG, "onResume()");
-        synchronized (mIsBouncerVisibleToUserLock) {
-            mIsBouncerVisibleToUser = isBouncerVisibleToUser();
-        }
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
-
-        // Registers a callback which handles stopping the biometric unlock and restarting it in
-        // the new position for a 180 degree rotation change.
-        if (!mWatchingRotation) {
-            try {
-                mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
-                mWatchingRotation = true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Remote exception when adding rotation watcher");
-            }
-        }
-    }
-
-    @Override
-    public boolean needsInput() {
-        return false;
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mKeyguardSecurityCallback;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        mBiometricUnlock.initializeView(mFaceUnlockAreaView);
-    }
-
-    private void initializeBiometricUnlockView() {
-        if (DEBUG) Log.d(TAG, "initializeBiometricUnlockView()");
-        mFaceUnlockAreaView = findViewById(R.id.face_unlock_area_view);
-        if (mFaceUnlockAreaView != null) {
-            mBiometricUnlock = new FaceUnlock(mContext);
-
-            mCancelButton = (ImageButton) findViewById(R.id.face_unlock_cancel_button);
-            mCancelButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mBiometricUnlock.stopAndShowBackup();
-                }
-            });
-        } else {
-            Log.w(TAG, "Couldn't find biometric unlock view");
-        }
-    }
-
-    /**
-     * Starts the biometric unlock if it should be started based on a number of factors.  If it
-     * should not be started, it either goes to the back up, or remains showing to prepare for
-     * it being started later.
-     */
-    private void maybeStartBiometricUnlock() {
-        if (DEBUG) Log.d(TAG, "maybeStartBiometricUnlock()");
-        if (mBiometricUnlock != null) {
-            KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-            final boolean backupIsTimedOut = (
-                    monitor.getFailedUnlockAttempts() >=
-                    LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
-
-            boolean isBouncerVisibleToUser;
-            synchronized(mIsBouncerVisibleToUserLock) {
-                isBouncerVisibleToUser = mIsBouncerVisibleToUser;
-            }
-
-            // Don't start it if the bouncer is not showing, but keep this view up because we want
-            // it here and ready for when the bouncer does show.
-            if (!isBouncerVisibleToUser) {
-                mBiometricUnlock.stop(); // It shouldn't be running but calling this can't hurt.
-                return;
-            }
-
-            // Although these same conditions are handled in KeyguardSecurityModel, they are still
-            // necessary here.  When a tablet is rotated 90 degrees, a configuration change is
-            // triggered and everything is torn down and reconstructed.  That means
-            // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
-            // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
-            // However, for a 180 degree rotation, no configuration change is triggered, so only
-            // the logic here is capable of suppressing Face Unlock.
-            if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
-                    && monitor.isAlternateUnlockEnabled()
-                    && !monitor.getMaxBiometricUnlockAttemptsReached()
-                    && !backupIsTimedOut) {
-                mBiometricUnlock.start();
-            } else {
-                mBiometricUnlock.stopAndShowBackup();
-            }
-        }
-    }
-
-    // Returns true if the device is currently in a state where the user is seeing the bouncer.
-    // This requires isKeyguardBouncer() to be true, but that doesn't imply that the screen is on or
-    // the keyguard visibility is set to true, so we must check those conditions as well.
-    private boolean isBouncerVisibleToUser() {
-        KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-        return updateMonitor.isKeyguardBouncer() && updateMonitor.isKeyguardVisible() &&
-                updateMonitor.isScreenOn();
-    }
-
-    // Starts the biometric unlock if the bouncer was not previously visible to the user, but is now
-    // visibile to the user.  Stops the biometric unlock if the bouncer was previously visible to
-    // the user, but is no longer visible to the user.
-    private void handleBouncerUserVisibilityChanged() {
-        boolean wasBouncerVisibleToUser;
-        synchronized(mIsBouncerVisibleToUserLock) {
-            wasBouncerVisibleToUser = mIsBouncerVisibleToUser;
-            mIsBouncerVisibleToUser = isBouncerVisibleToUser();
-        }
-
-        if (mBiometricUnlock != null) {
-            if (wasBouncerVisibleToUser && !mIsBouncerVisibleToUser) {
-                mBiometricUnlock.stop();
-            } else if (!wasBouncerVisibleToUser && mIsBouncerVisibleToUser) {
-                maybeStartBiometricUnlock();
-            }
-        }
-    }
-
-    KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
-        // We need to stop the biometric unlock when a phone call comes in
-        @Override
-        public void onPhoneStateChanged(int phoneState) {
-            if (DEBUG) Log.d(TAG, "onPhoneStateChanged(" + phoneState + ")");
-            if (phoneState == TelephonyManager.CALL_STATE_RINGING) {
-                if (mBiometricUnlock != null) {
-                    mBiometricUnlock.stopAndShowBackup();
-                }
-            }
-        }
-
-        @Override
-        public void onUserSwitching(int userId) {
-            if (DEBUG) Log.d(TAG, "onUserSwitched(" + userId + ")");
-            if (mBiometricUnlock != null) {
-                mBiometricUnlock.stop();
-            }
-            // No longer required; static value set by KeyguardViewMediator
-            // mLockPatternUtils.setCurrentUser(userId);
-        }
-
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            if (DEBUG) Log.d(TAG, "onUserSwitchComplete(" + userId + ")");
-            if (mBiometricUnlock != null) {
-                maybeStartBiometricUnlock();
-            }
-        }
-
-        @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
-            handleBouncerUserVisibilityChanged();
-        }
-
-        @Override
-        public void onKeyguardBouncerChanged(boolean bouncer) {
-            if (DEBUG) Log.d(TAG, "onKeyguardBouncerChanged(" + bouncer + ")");
-            handleBouncerUserVisibilityChanged();
-        }
-
-        @Override
-        public void onScreenTurnedOn() {
-            if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
-            handleBouncerUserVisibilityChanged();
-        }
-
-        @Override
-        public void onScreenTurnedOff(int why) {
-            if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
-            handleBouncerUserVisibilityChanged();
-        }
-
-        @Override
-        public void onEmergencyCallAction() {
-            if (mBiometricUnlock != null) {
-                mBiometricUnlock.stop();
-            }
-        }
-    };
-
-    @Override
-    public void showUsabilityHint() {
-    }
-
-    @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void startAppearAnimation() {
-        // TODO.
-    }
-
-    @Override
-    public boolean startDisappearAnimation(Runnable finishRunnable) {
-        return false;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java
deleted file mode 100644
index 98a44a6..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardGlowStripView.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.LinearLayout;
-
-/**
- * A layout which animates a strip of horizontal, pulsing dots on request. This is used
- * to indicate the presence of pages to the left / right.
- */
-public class KeyguardGlowStripView extends LinearLayout {
-    private static final int DURATION = 500;
-
-    private static final float SLIDING_WINDOW_SIZE = 0.4f;
-    private int mDotStripTop;
-    private int mHorizontalDotGap;
-
-    private int mDotSize;
-    private int mNumDots;
-    private Drawable mDotDrawable;
-    private boolean mLeftToRight = true;
-
-    private float mAnimationProgress = 0f;
-    private boolean mDrawDots = false;
-    private ValueAnimator mAnimator;
-    private Interpolator mDotAlphaInterpolator = new DecelerateInterpolator(0.5f);
-
-    public KeyguardGlowStripView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardGlowStripView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardGlowStripView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyguardGlowStripView);
-        mDotSize = a.getDimensionPixelSize(R.styleable.KeyguardGlowStripView_dotSize, mDotSize);
-        mNumDots = a.getInt(R.styleable.KeyguardGlowStripView_numDots, mNumDots);
-        mDotDrawable = a.getDrawable(R.styleable.KeyguardGlowStripView_glowDot);
-        mLeftToRight = a.getBoolean(R.styleable.KeyguardGlowStripView_leftToRight, mLeftToRight);
-    }
-
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        int availableWidth = w - getPaddingLeft() - getPaddingRight();
-        mHorizontalDotGap = (availableWidth - mDotSize * mNumDots) /  (mNumDots - 1);
-        mDotStripTop = getPaddingTop();
-        invalidate();
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        if (!mDrawDots) return;
-
-        int xOffset = getPaddingLeft();
-        mDotDrawable.setBounds(0, 0, mDotSize, mDotSize);
-
-        for (int i = 0; i < mNumDots; i++) {
-            // We fudge the relative position to provide a fade in of the first dot and a fade
-            // out of the final dot.
-            float relativeDotPosition = SLIDING_WINDOW_SIZE / 2 + ((1.0f * i) / (mNumDots - 1)) *
-                    (1 - SLIDING_WINDOW_SIZE);
-            float distance = Math.abs(relativeDotPosition - mAnimationProgress);
-            float alpha = Math.max(0, 1 - distance / (SLIDING_WINDOW_SIZE / 2));
-
-            alpha = mDotAlphaInterpolator.getInterpolation(alpha);
-
-            canvas.save();
-            canvas.translate(xOffset, mDotStripTop);
-            mDotDrawable.setAlpha((int) (alpha * 255));
-            mDotDrawable.draw(canvas);
-            canvas.restore();
-            xOffset += mDotSize + mHorizontalDotGap;
-        }
-    }
-
-    public void makeEmGo() {
-        if (mAnimator != null) {
-            mAnimator.cancel();
-        }
-        float from = mLeftToRight ? 0f : 1f;
-        float to = mLeftToRight ? 1f : 0f;
-        mAnimator = ValueAnimator.ofFloat(from, to);
-        mAnimator.setDuration(DURATION);
-        mAnimator.setInterpolator(new LinearInterpolator());
-        mAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mDrawDots = false;
-                // make sure we draw one frame at the end with everything gone.
-                invalidate();
-            }
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mDrawDots = true;
-            }
-        });
-        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mAnimationProgress = (Float) animation.getAnimatedValue();
-                invalidate();
-            }
-        });
-        mAnimator.start();
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index ab18271..a88497c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 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.
@@ -16,101 +16,36 @@
 
 package com.android.keyguard;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
-
+import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.admin.DevicePolicyManager;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
-import android.graphics.Rect;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
+import android.graphics.Canvas;
+import android.media.AudioManager;
+import android.os.SystemClock;
+import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.RemoteViews.OnClickHandler;
+import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
 
-import java.lang.ref.WeakReference;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 
-public class KeyguardHostView extends KeyguardViewBase {
-    private static final String TAG = "KeyguardHostView";
-    public static boolean DEBUG = KeyguardConstants.DEBUG;
-    public static boolean DEBUGXPORT = true; // debug music transport control
+import java.io.File;
 
-    // Transport control states.
-    static final int TRANSPORT_GONE = 0;
-    static final int TRANSPORT_INVISIBLE = 1;
-    static final int TRANSPORT_VISIBLE = 2;
-
-    private int mTransportState = TRANSPORT_GONE;
-
-    // Found in KeyguardAppWidgetPickActivity.java
-    static final int APPWIDGET_HOST_ID = 0x4B455947;
-    private final int MAX_WIDGETS = 5;
-
-    private AppWidgetHost mAppWidgetHost;
-    private AppWidgetManager mAppWidgetManager;
-    private KeyguardWidgetPager mAppWidgetContainer;
-    // TODO remove transport control references, these don't exist anymore
-    private KeyguardTransportControlView mTransportControl;
-    private int mAppWidgetToShow;
-
-    protected int mFailedAttempts;
-
-    private KeyguardViewStateManager mViewStateManager;
-
-    private Rect mTempRect = new Rect();
-    private int mDisabledFeatures;
-    private boolean mCameraDisabled;
-    private boolean mSafeModeEnabled;
-    private boolean mUserSetupCompleted;
-
-    // User for whom this host view was created.  Final because we should never change the
-    // id without reconstructing an instance of KeyguardHostView. See note below...
-    private final int mUserId;
-
-    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
-
-    protected int mClientGeneration;
-
-    protected boolean mShowSecurityWhenReturn;
-
-    private final Rect mInsets = new Rect();
-
-    private MyOnClickHandler mOnClickHandler = new MyOnClickHandler(this);
-
-    private Runnable mPostBootCompletedRunnable;
-
-    /*package*/ interface UserSwitcherCallback {
-        void hideSecurityView(int duration);
-        void showSecurityView();
-        void showUnlockHint();
-        void userActivity();
-    }
-
-    interface TransportControlCallback {
-        void userActivity();
-    }
+/**
+ * Base class for keyguard view.  {@link #reset} is where you should
+ * reset the state of your view.  Use the {@link KeyguardViewCallback} via
+ * {@link #getCallback()} to send information back (such as poking the wake lock,
+ * or finishing the keyguard).
+ *
+ * Handles intercepting of media keys that still work when the keyguard is
+ * showing.
+ */
+public class KeyguardHostView extends FrameLayout implements SecurityCallback {
 
     public interface OnDismissAction {
         /**
@@ -119,361 +54,154 @@
         boolean onDismiss();
     }
 
+    private AudioManager mAudioManager;
+    private TelephonyManager mTelephonyManager = null;
+    protected ViewMediatorCallback mViewMediatorCallback;
+    protected LockPatternUtils mLockPatternUtils;
+    private OnDismissAction mDismissAction;
+
+    private final KeyguardUpdateMonitorCallback mUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+
+        @Override
+        public void onUserSwitchComplete(int userId) {
+            getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
+        }
+
+        @Override
+        public void onTrustInitiatedByUser(int userId) {
+            if (userId != mLockPatternUtils.getCurrentUser()) return;
+            if (!isAttachedToWindow()) return;
+
+            if (isVisibleToUser()) {
+                dismiss(false /* authenticated */);
+            } else {
+                mViewMediatorCallback.playTrustedSound();
+            }
+        }
+    };
+
+    // Whether the volume keys should be handled by keyguard. If true, then
+    // they will be handled here for specific media types such as music, otherwise
+    // the audio service will bring up the volume dialog.
+    private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+    public static final boolean DEBUG = KeyguardConstants.DEBUG;
+    private static final String TAG = "KeyguardViewBase";
+
+    private KeyguardSecurityContainer mSecurityContainer;
+
     public KeyguardHostView(Context context) {
         this(context, null);
     }
 
     public KeyguardHostView(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        if (DEBUG) Log.e(TAG, "KeyguardHostView()");
-
-        mLockPatternUtils = new LockPatternUtils(context);
-
-        // Note: This depends on KeyguardHostView getting reconstructed every time the
-        // user switches, since mUserId will be used for the entire session.
-        // Once created, keyguard should *never* re-use this instance with another user.
-        // In other words, mUserId should never change - hence it's marked final.
-        mUserId = mLockPatternUtils.getCurrentUser();
-
-        DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-            mDisabledFeatures = getDisabledFeatures(dpm);
-            mCameraDisabled = dpm.getCameraDisabled(null);
-        }
-
-        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
-
-        // These need to be created with the user context...
-        Context userContext = null;
-        try {
-            final String packageName = "system";
-            userContext = mContext.createPackageContextAsUser(packageName, 0,
-                    new UserHandle(mUserId));
-
-        } catch (NameNotFoundException e) {
-            e.printStackTrace();
-            // This should never happen, but it's better to have no widgets than to crash.
-            userContext = context;
-        }
-
-        mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
-                Looper.myLooper());
-
-        mAppWidgetManager = AppWidgetManager.getInstance(userContext);
-
-        mViewStateManager = new KeyguardViewStateManager(this);
-
-        mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
-
-        // Ensure we have the current state *before* we call showAppropriateWidgetPage()
-        getInitialTransportState();
-
-        if (mSafeModeEnabled) {
-            Log.v(TAG, "Keyguard widgets disabled by safe mode");
-        }
-        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
-            Log.v(TAG, "Keyguard widgets disabled by DPM");
-        }
-        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
-            Log.v(TAG, "Keyguard secure camera disabled by DPM");
-        }
+        KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateCallback);
     }
 
-    private void getInitialTransportState() {
-        DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
-                .getCachedDisplayClientState();
-        mTransportState = (dcs.clearing ? TRANSPORT_GONE :
-            (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
-
-        if (DEBUGXPORT) Log.v(TAG, "Initial transport state: "
-                + mTransportState + ", pbstate=" + dcs.playbackState);
-    }
-
-    private void cleanupAppWidgetIds() {
-        if (mSafeModeEnabled || widgetsDisabled()) return;
-
-        // Clean up appWidgetIds that are bound to lockscreen, but not actually used
-        // This is only to clean up after another bug: we used to not call
-        // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
-        // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
-        // that are triggered by deleteAppWidgetId, which is why we're doing this
-        int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
-        int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
-        for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
-            int appWidgetId = appWidgetIdsBoundToHost[i];
-            if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
-                Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
-                        + appWidgetId);
-                mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-            }
-        }
-    }
-
-    private static boolean contains(int[] array, int target) {
-        for (int value : array) {
-            if (value == target) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
-            new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onBootCompleted() {
-            if (mPostBootCompletedRunnable != null) {
-                mPostBootCompletedRunnable.run();
-                mPostBootCompletedRunnable = null;
-            }
-        }
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            if (mKeyguardMultiUserSelectorView != null) {
-                mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
-            }
-        }
-    };
-
-    private static final boolean isMusicPlaying(int playbackState) {
-        // This should agree with the list in AudioService.isPlaystateActive()
-        switch (playbackState) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private SlidingChallengeLayout mSlidingChallengeLayout;
-    private MultiPaneChallengeLayout mMultiPaneChallengeLayout;
-
     @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean result = super.onTouchEvent(ev);
-        mTempRect.set(0, 0, 0, 0);
-        offsetRectIntoDescendantCoords(getSecurityContainer(), mTempRect);
-        ev.offsetLocation(mTempRect.left, mTempRect.top);
-        result = getSecurityContainer().dispatchTouchEvent(ev) || result;
-        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
-        return result;
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.keyguardDoneDrawing();
+        }
     }
 
-    private int getWidgetPosition(int id) {
-        final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
-        final int children = appWidgetContainer.getChildCount();
-        for (int i = 0; i < children; i++) {
-            final View content = appWidgetContainer.getWidgetPageAt(i).getContent();
-            if (content != null && content.getId() == id) {
-                return i;
-            } else if (content == null) {
-                // Attempt to track down bug #8886916
-                Log.w(TAG, "*** Null content at " + "i=" + i + ",id=" + id + ",N=" + children);
-            }
-        }
-        return -1;
+    /**
+     * Sets an action to run when keyguard finishes.
+     *
+     * @param action
+     */
+    public void setOnDismissAction(OnDismissAction action) {
+        mDismissAction = action;
     }
 
     @Override
     protected void onFinishInflate() {
-        super.onFinishInflate();
+        mSecurityContainer =
+                (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
+        mLockPatternUtils = new LockPatternUtils(mContext);
+        mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
+        mSecurityContainer.setSecurityCallback(this);
+        mSecurityContainer.showPrimarySecurityScreen(false);
+        // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
+    }
 
-        // Grab instances of and make any necessary changes to the main layouts. Create
-        // view state manager and wire up necessary listeners / callbacks.
-        View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
-        mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
-        mAppWidgetContainer.setVisibility(VISIBLE);
-        mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
-        mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
-        mAppWidgetContainer.setMinScale(0.5f);
+    /**
+     * Called when the view needs to be shown.
+     */
+    public void showPrimarySecurityScreen() {
+        if (DEBUG) Log.d(TAG, "show()");
+        mSecurityContainer.showPrimarySecurityScreen(false);
+    }
 
-        mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-        if (mSlidingChallengeLayout != null) {
-            mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
+    /**
+     *  Dismisses the keyguard by going to the next screen or making it gone.
+     *
+     *  @return True if the keyguard is done.
+     */
+    public boolean dismiss() {
+        return dismiss(false);
+    }
+
+    public boolean handleBackKey() {
+        if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
+            mSecurityContainer.dismiss(false);
+            return true;
         }
-        mAppWidgetContainer.setViewStateManager(mViewStateManager);
-        mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
+        return false;
+    }
 
-        mMultiPaneChallengeLayout =
-                (MultiPaneChallengeLayout) findViewById(R.id.multi_pane_challenge);
-        ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
-                mMultiPaneChallengeLayout;
-        challenge.setOnBouncerStateChangedListener(mViewStateManager);
-        mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
-        mViewStateManager.setPagedView(mAppWidgetContainer);
-        mViewStateManager.setChallengeLayout(challenge);
-
-        mViewStateManager.setSecurityViewContainer(getSecurityContainer());
-
-        if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            updateAndAddWidgets();
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+            event.getText().add(mSecurityContainer.getCurrentSecurityModeContentDescription());
+            return true;
         } else {
-            // We can't add widgets until after boot completes because AppWidgetHost may try
-            // to contact the providers.  Do it later.
-            mPostBootCompletedRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    updateAndAddWidgets();
-                }
-            };
-        }
-
-        getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
-        enableUserSelectorIfNecessary();
-    }
-
-    private void updateAndAddWidgets() {
-        cleanupAppWidgetIds();
-        addDefaultWidgets();
-        addWidgetsFromSettings();
-        maybeEnableAddButton();
-        checkAppWidgetConsistency();
-
-        // Don't let the user drag the challenge down if widgets are disabled.
-        if (mSlidingChallengeLayout != null) {
-            mSlidingChallengeLayout.setEnableChallengeDragging(!widgetsDisabled());
-        }
-
-        // Select the appropriate page
-        mSwitchPageRunnable.run();
-
-        // This needs to be called after the pages are all added.
-        mViewStateManager.showUsabilityHints();
-    }
-
-    private void maybeEnableAddButton() {
-        if (!shouldEnableAddWidget()) {
-            mAppWidgetContainer.setAddWidgetEnabled(false);
+            return super.dispatchPopulateAccessibilityEvent(event);
         }
     }
 
-    private boolean shouldEnableAddWidget() {
-        return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
+    protected KeyguardSecurityContainer getSecurityContainer() {
+        return mSecurityContainer;
     }
 
     @Override
     public boolean dismiss(boolean authenticated) {
-        boolean finished = super.dismiss(authenticated);
-        if (!finished) {
-            mViewStateManager.showBouncer(true);
+        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
+    }
 
-            // Enter full screen mode if we're in SIM or Account screen
-            SecurityMode securityMode = getSecurityContainer().getSecurityMode();
-            boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
-            boolean isSimOrAccount = securityMode == SecurityMode.SimPin
-                    || securityMode == SecurityMode.SimPuk
-                    || securityMode == SecurityMode.Account;
-            mAppWidgetContainer.setVisibility(
-                    isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE);
-
-            // Don't show camera or search in navbar when SIM or Account screen is showing
-            setSystemUiVisibility(isSimOrAccount ?
-                    (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
-                    : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
-
-            if (mSlidingChallengeLayout != null) {
-                mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen);
+    /**
+     * Authentication has happened and it's time to dismiss keyguard. This function
+     * should clean up and inform KeyguardViewMediator.
+     */
+    @Override
+    public void finish() {
+        // If there's a pending runnable because the user interacted with a widget
+        // and we're leaving keyguard, then run it.
+        boolean deferKeyguardDone = false;
+        if (mDismissAction != null) {
+            deferKeyguardDone = mDismissAction.onDismiss();
+            mDismissAction = null;
+        }
+        if (mViewMediatorCallback != null) {
+            if (deferKeyguardDone) {
+                mViewMediatorCallback.keyguardDonePending();
+            } else {
+                mViewMediatorCallback.keyguardDone(true);
             }
         }
-        return finished;
-    }
-
-    private int getDisabledFeatures(DevicePolicyManager dpm) {
-        int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
-        if (dpm != null) {
-            final int currentUser = mLockPatternUtils.getCurrentUser();
-            disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
-        }
-        return disabledFeatures;
-    }
-
-    private boolean widgetsDisabled() {
-        boolean disabledByLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-        boolean disabledByDpm =
-                (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
-        boolean disabledByUser = !mLockPatternUtils.getWidgetsEnabled();
-        return disabledByLowRamDevice || disabledByDpm || disabledByUser;
-    }
-
-    private boolean cameraDisabledByDpm() {
-        return mCameraDisabled
-                || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
     }
 
     @Override
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        super.setLockPatternUtils(utils);
-        getSecurityContainer().updateSecurityViews(mViewStateManager.isBouncing());
+    public void reset() {
+        mViewMediatorCallback.resetKeyguard();
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mAppWidgetHost.startListening();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mAppWidgetHost.stopListening();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
-    }
-
-    void addWidget(AppWidgetHostView view, int pageIndex) {
-        mAppWidgetContainer.addWidget(view, pageIndex);
-    }
-
-    private KeyguardWidgetPager.Callbacks mWidgetCallbacks
-            = new KeyguardWidgetPager.Callbacks() {
-        @Override
-        public void userActivity() {
-            KeyguardHostView.this.userActivity();
-        }
-
-        @Override
-        public void onUserActivityTimeoutChanged() {
-            KeyguardHostView.this.onUserActivityTimeoutChanged();
-        }
-
-        @Override
-        public void onAddView(View v) {
-            if (!shouldEnableAddWidget()) {
-                mAppWidgetContainer.setAddWidgetEnabled(false);
-            }
-        }
-
-        @Override
-        public void onRemoveView(View v, boolean deletePermanently) {
-            if (deletePermanently) {
-                final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
-                        appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                }
-            }
-        }
-
-        @Override
-        public void onRemoveViewAnimationCompleted() {
-            if (shouldEnableAddWidget()) {
-                mAppWidgetContainer.setAddWidgetEnabled(true);
-            }
-        }
-    };
-
-    @Override
-    public void onUserSwitching(boolean switching) {
-        if (!switching && mKeyguardMultiUserSelectorView != null) {
-            mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
+    public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+        if (mViewMediatorCallback != null) {
+            mViewMediatorCallback.setNeedsInput(needsInput);
         }
     }
 
@@ -483,631 +211,223 @@
         }
     }
 
-    public void onUserActivityTimeoutChanged() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.onUserActivityTimeoutChanged();
+    /**
+     * Called when the Keyguard is not actively shown anymore on the screen.
+     */
+    public void onPause() {
+        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
+                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+        mSecurityContainer.showPrimarySecurityScreen(true);
+        mSecurityContainer.onPause();
+        clearFocus();
+    }
+
+    /**
+     * Called when the Keyguard is actively shown on the screen.
+     */
+    public void onResume() {
+        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+        mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
+        requestFocus();
+    }
+
+    /**
+     * Starts the animation when the Keyguard gets shown.
+     */
+    public void startAppearAnimation() {
+        mSecurityContainer.startAppearAnimation();
+    }
+
+    public void startDisappearAnimation(Runnable finishRunnable) {
+        if (!mSecurityContainer.startDisappearAnimation(finishRunnable) && finishRunnable != null) {
+            finishRunnable.run();
         }
     }
 
+    /**
+     * Verify that the user can get past the keyguard securely.  This is called,
+     * for example, when the phone disables the keyguard but then wants to launch
+     * something else that requires secure access.
+     *
+     * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
+     */
+    public void verifyUnlock() {
+        SecurityMode securityMode = mSecurityContainer.getSecurityMode();
+        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(true);
+            }
+        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
+                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
+                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
+            // can only verify unlock when in pattern/password mode
+            if (mViewMediatorCallback != null) {
+                mViewMediatorCallback.keyguardDone(false);
+            }
+        } else {
+            // otherwise, go to the unlock screen, see if they can verify it
+            mSecurityContainer.verifyUnlock();
+        }
+    }
+
+    /**
+     * Called before this view is being removed.
+     */
+    public void cleanUp() {
+        getSecurityContainer().onPause();
+    }
+
     @Override
-    public long getUserActivityTimeout() {
-        // Currently only considering user activity timeouts needed by widgets.
-        // Could also take into account longer timeouts for certain security views.
-        if (mAppWidgetContainer != null) {
-            return mAppWidgetContainer.getUserActivityTimeout();
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (interceptMediaKey(event)) {
+            return true;
         }
-        return -1;
+        return super.dispatchKeyEvent(event);
     }
 
-    private static class MyOnClickHandler extends OnClickHandler {
+    /**
+     * Allows the media keys to work when the keyguard is showing.
+     * The media keys should be of no interest to the actual keyguard view(s),
+     * so intercepting them here should not be of any harm.
+     * @param event The key event
+     * @return whether the event was consumed as a media key.
+     */
+    public boolean interceptMediaKey(KeyEvent event) {
+        final int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
+                     * in-call to avoid music playback */
+                    if (mTelephonyManager == null) {
+                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
+                                Context.TELEPHONY_SERVICE);
+                    }
+                    if (mTelephonyManager != null &&
+                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+                        return true;  // suppress key event
+                    }
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
+                }
 
-        // weak reference to the hostView to avoid keeping a live reference
-        // due to Binder GC linkages to AppWidgetHost. By the same token,
-        // this click handler should not keep references to any large
-        // objects.
-        WeakReference<KeyguardHostView> mKeyguardHostView;
-
-        MyOnClickHandler(KeyguardHostView hostView) {
-            mKeyguardHostView = new WeakReference<KeyguardHostView>(hostView);
-        }
-
-        @Override
-        public boolean onClickHandler(final View view,
-                final android.app.PendingIntent pendingIntent,
-                final Intent fillInIntent) {
-            KeyguardHostView hostView = mKeyguardHostView.get();
-            if (hostView == null) {
-                return false;
-            }
-            if (pendingIntent.isActivity()) {
-                hostView.setOnDismissAction(new OnDismissAction() {
-                    public boolean onDismiss() {
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            Context context = view.getContext();
-                            ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
-                                    0, 0,
-                                    view.getMeasuredWidth(), view.getMeasuredHeight());
-                            context.startIntentSender(
-                                    pendingIntent.getIntentSender(), fillInIntent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(TAG, "Cannot send pending intent: ", e);
-                        } catch (Exception e) {
-                            android.util.Log.e(TAG, "Cannot send pending intent due to " +
-                                    "unknown exception: ", e);
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                    if (KEYGUARD_MANAGES_VOLUME) {
+                        synchronized (this) {
+                            if (mAudioManager == null) {
+                                mAudioManager = (AudioManager) getContext().getSystemService(
+                                        Context.AUDIO_SERVICE);
+                            }
                         }
+                        // Volume buttons should only function for music (local or remote).
+                        // TODO: Actually handle MUTE.
+                        mAudioManager.adjustSuggestedStreamVolume(
+                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                        ? AudioManager.ADJUST_RAISE
+                                        : AudioManager.ADJUST_LOWER /* direction */,
+                                AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
+                        // Don't execute default volume behavior
+                        return true;
+                    } else {
                         return false;
                     }
-                });
-
-                if (hostView.mViewStateManager.isChallengeShowing()) {
-                    hostView.mViewStateManager.showBouncer(true);
-                } else {
-                    hostView.dismiss();
-                }
-                return true;
-            } else {
-                return super.onClickHandler(view, pendingIntent, fillInIntent);
-            }
-        };
-    };
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mViewStateManager != null) {
-            mViewStateManager.showUsabilityHints();
-        }
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
-        // turns off we reset that behavior
-        clearAppWidgetToShow();
-        if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            checkAppWidgetConsistency();
-        }
-        CameraWidgetFrame cameraPage = findCameraPage();
-        if (cameraPage != null) {
-            cameraPage.onScreenTurnedOff();
-        }
-    }
-
-    public void clearAppWidgetToShow() {
-        mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-    }
-
-    private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
-        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
-        if (appWidgetInfo != null) {
-            AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
-            addWidget(view, pageIndex);
-            return true;
-        } else {
-            if (updateDbIfFailed) {
-                Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + "  was null for user"
-                        + mUserId + ", deleting");
-                mAppWidgetHost.deleteAppWidgetId(appId);
-                mLockPatternUtils.removeAppWidget(appId);
-            }
-            return false;
-        }
-    }
-
-    private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks =
-        new CameraWidgetFrame.Callbacks() {
-            @Override
-            public void onLaunchingCamera() {
-                setSliderHandleAlpha(0);
-            }
-
-            @Override
-            public void onCameraLaunchedSuccessfully() {
-                if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) {
-                    mAppWidgetContainer.scrollLeft();
-                }
-                setSliderHandleAlpha(1);
-                mShowSecurityWhenReturn = true;
-            }
-
-            @Override
-            public void onCameraLaunchedUnsuccessfully() {
-                setSliderHandleAlpha(1);
-            }
-
-            private void setSliderHandleAlpha(float alpha) {
-                SlidingChallengeLayout slider =
-                        (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-                if (slider != null) {
-                    slider.setHandleAlpha(alpha);
                 }
             }
-        };
-
-    private int numWidgets() {
-        final int childCount = mAppWidgetContainer.getChildCount();
-        int widgetCount = 0;
-        for (int i = 0; i < childCount; i++) {
-            if (mAppWidgetContainer.isWidgetPage(i)) {
-                widgetCount++;
-            }
-        }
-        return widgetCount;
-    }
-
-    private void addDefaultWidgets() {
-        if (!mSafeModeEnabled && !widgetsDisabled()) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
-            mAppWidgetContainer.addWidget(addWidget, 0);
-            View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
-            addWidgetButton.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    // Pass in an invalid widget id... the picker will allocate an ID for us
-                    getActivityLauncher().launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
-                }
-            });
-        }
-
-        // We currently disable cameras in safe mode because we support loading 3rd party
-        // cameras we can't trust.  TODO: plumb safe mode into camera creation code and only
-        // inflate system-provided camera?
-        if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
-                && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
-            View cameraWidget = CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks,
-                    getActivityLauncher());
-            if (cameraWidget != null) {
-                mAppWidgetContainer.addWidget(cameraWidget);
-            }
-        }
-    }
-
-    /**
-     * Create KeyguardTransportControlView on demand.
-     * @return
-     */
-    private KeyguardTransportControlView getOrCreateTransportControl() {
-        if (mTransportControl == null) {
-            LayoutInflater inflater = LayoutInflater.from(mContext);
-            mTransportControl = (KeyguardTransportControlView)
-                    inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
-            mTransportControl.setTransportControlCallback(new TransportControlCallback() {
-                public void userActivity() {
-                    mViewMediatorCallback.userActivity();
-                }
-            });
-        }
-        return mTransportControl;
-    }
-
-    private int getInsertPageIndex() {
-        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
-        int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
-        if (insertionIndex < 0) {
-            insertionIndex = 0; // no add widget page found
-        } else {
-            insertionIndex++; // place after add widget
-        }
-        return insertionIndex;
-    }
-
-    private void addDefaultStatusWidget(int index) {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
-        mAppWidgetContainer.addWidget(statusWidget, index);
-    }
-
-    private void addWidgetsFromSettings() {
-        if (mSafeModeEnabled || widgetsDisabled()) {
-            addDefaultStatusWidget(0);
-            return;
-        }
-
-        int insertionIndex = getInsertPageIndex();
-
-        // Add user-selected widget
-        final int[] widgets = mLockPatternUtils.getAppWidgets();
-
-        if (widgets == null) {
-            Log.d(TAG, "Problem reading widgets");
-        } else {
-            for (int i = widgets.length -1; i >= 0; i--) {
-                if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    addDefaultStatusWidget(insertionIndex);
-                } else {
-                    // We add the widgets from left to right, starting after the first page after
-                    // the add page. We count down, since the order will be persisted from right
-                    // to left, starting after camera.
-                    addWidget(widgets[i], insertionIndex, true);
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
                 }
             }
         }
-    }
-
-    private int allocateIdForDefaultAppWidget() {
-        int appWidgetId;
-        Resources res = getContext().getResources();
-        ComponentName defaultAppWidget = new ComponentName(
-                res.getString(R.string.widget_default_package_name),
-                res.getString(R.string.widget_default_class_name));
-
-        // Note: we don't support configuring the widget
-        appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
-        try {
-            mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
-            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-            appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        return appWidgetId;
-    }
-
-    public void checkAppWidgetConsistency() {
-        final int childCount = mAppWidgetContainer.getChildCount();
-        boolean widgetPageExists = false;
-        for (int i = 0; i < childCount; i++) {
-            if (mAppWidgetContainer.isWidgetPage(i)) {
-                widgetPageExists = true;
-                break;
-            }
-        }
-        if (!widgetPageExists) {
-            final int insertPageIndex = getInsertPageIndex();
-
-            final boolean userAddedWidgetsEnabled = !widgetsDisabled();
-
-            boolean addedDefaultAppWidget = false;
-
-            if (!mSafeModeEnabled) {
-                if (userAddedWidgetsEnabled) {
-                    int appWidgetId = allocateIdForDefaultAppWidget();
-                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true);
-                    }
-                } else {
-                    // note: even if widgetsDisabledByDpm() returns true, we still bind/create
-                    // the default appwidget if possible
-                    int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId();
-                    if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        appWidgetId = allocateIdForDefaultAppWidget();
-                        if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                            mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId);
-                        }
-                    }
-                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false);
-                        if (!addedDefaultAppWidget) {
-                            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                            mLockPatternUtils.writeFallbackAppWidgetId(
-                                    AppWidgetManager.INVALID_APPWIDGET_ID);
-                        }
-                    }
-                }
-            }
-
-            // Use the built-in status/clock view if we can't inflate the default widget
-            if (!addedDefaultAppWidget) {
-                addDefaultStatusWidget(insertPageIndex);
-            }
-
-            // trigger DB updates only if user-added widgets are enabled
-            if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
-                mAppWidgetContainer.onAddView(
-                        mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
-            }
-        }
-    }
-
-    private final Runnable mSwitchPageRunnable = new Runnable() {
-        @Override
-        public void run() {
-           showAppropriateWidgetPage();
-        }
-    };
-
-    static class SavedState extends BaseSavedState {
-        int transportState;
-        int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-        Rect insets = new Rect();
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            this.transportState = in.readInt();
-            this.appWidgetToShow = in.readInt();
-            this.insets = in.readParcelable(null);
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(this.transportState);
-            out.writeInt(this.appWidgetToShow);
-            out.writeParcelable(insets, 0);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState);
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        // If the transport is showing, force it to show it on restore.
-        final boolean showing = mTransportControl != null
-                && mAppWidgetContainer.getWidgetPageIndex(mTransportControl) >= 0;
-        ss.transportState =  showing ? TRANSPORT_VISIBLE : mTransportState;
-        ss.appWidgetToShow = mAppWidgetToShow;
-        ss.insets.set(mInsets);
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        mTransportState = (ss.transportState);
-        mAppWidgetToShow = ss.appWidgetToShow;
-        setInsets(ss.insets);
-        if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState);
-        mSwitchPageRunnable.run();
-    }
-
-    @Override
-    protected boolean fitSystemWindows(Rect insets) {
-        setInsets(insets);
-        return true;
-    }
-
-    private void setInsets(Rect insets) {
-        mInsets.set(insets);
-        if (mSlidingChallengeLayout != null) mSlidingChallengeLayout.setInsets(mInsets);
-        if (mMultiPaneChallengeLayout != null) mMultiPaneChallengeLayout.setInsets(mInsets);
-
-        final CameraWidgetFrame cameraWidget = findCameraPage();
-        if (cameraWidget != null) cameraWidget.setInsets(mInsets);
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-        if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
-        if (hasWindowFocus && mShowSecurityWhenReturn) {
-            SlidingChallengeLayout slider =
-                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
-            if (slider != null) {
-                slider.setHandleAlpha(1);
-                slider.showChallenge(true);
-            }
-            mShowSecurityWhenReturn = false;
-        }
-    }
-
-    private void showAppropriateWidgetPage() {
-        final int state = mTransportState;
-        final boolean transportAdded = ensureTransportPresentOrRemoved(state);
-        final int pageToShow = getAppropriateWidgetPage(state);
-        if (!transportAdded) {
-            mAppWidgetContainer.setCurrentPage(pageToShow);
-        } else if (state == TRANSPORT_VISIBLE) {
-            // If the transport was just added, we need to wait for layout to happen before
-            // we can set the current page.
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    mAppWidgetContainer.setCurrentPage(pageToShow);
-                }
-            });
-        }
-    }
-
-    /**
-     * Examines the current state and adds the transport to the widget pager when the state changes.
-     *
-     * Showing the initial transport and keeping it around is a bit tricky because the signals
-     * coming from music players aren't always clear. Here's how the states are handled:
-     *
-     * {@link TRANSPORT_GONE} means we have no reason to show the transport - remove it if present.
-     *
-     * {@link TRANSPORT_INVISIBLE} means we have potential to show the transport because a music
-     * player is registered but not currently playing music (or we don't know the state yet). The
-     * code adds it conditionally on play state.
-     *
-     * {@link #TRANSPORT_VISIBLE} means a music player is active and transport should be showing.
-     *
-     * Once the transport is showing, we always show it until keyguard is dismissed. This state is
-     * maintained by onSave/RestoreInstanceState(). This state is cleared in
-     * {@link KeyguardViewManager#hide} when keyguard is dismissed, which causes the transport to be
-     * gone when keyguard is restarted until we get an update with the current state.
-     *
-     * @param state
-     */
-    private boolean ensureTransportPresentOrRemoved(int state) {
-        final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1;
-        final boolean visible = state == TRANSPORT_VISIBLE;
-        final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state);
-        if (!showing && (visible || shouldBeVisible)) {
-            // insert to left of camera if it exists, otherwise after right-most widget
-            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
-            int position = 0; // handle no widget case
-            if (lastWidget >= 0) {
-                position = mAppWidgetContainer.isCameraPage(lastWidget) ?
-                        lastWidget : lastWidget + 1;
-            }
-            if (DEBUGXPORT) Log.v(TAG, "add transport at " + position);
-            mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position);
-            return true;
-        } else if (showing && state == TRANSPORT_GONE) {
-            if (DEBUGXPORT) Log.v(TAG, "remove transport");
-            mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
-            mTransportControl = null;
-            KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
-        }
         return false;
     }
 
-    private CameraWidgetFrame findCameraPage() {
-        for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
-            if (mAppWidgetContainer.isCameraPage(i)) {
-                return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i);
+    private void handleMediaKeyEvent(KeyEvent keyEvent) {
+        synchronized (this) {
+            if (mAudioManager == null) {
+                mAudioManager = (AudioManager) getContext().getSystemService(
+                        Context.AUDIO_SERVICE);
             }
         }
-        return null;
-    }
-
-    boolean isMusicPage(int pageIndex) {
-        return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
-    }
-
-    private int getAppropriateWidgetPage(int musicTransportState) {
-        // assumes at least one widget (besides camera + add)
-        if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
-            final int childCount = mAppWidgetContainer.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId()
-                        == mAppWidgetToShow) {
-                    return i;
-                }
-            }
-            mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        // if music playing, show transport
-        if (musicTransportState == TRANSPORT_VISIBLE) {
-            if (DEBUG) Log.d(TAG, "Music playing, show transport");
-            return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl());
-        }
-
-        // else show the right-most widget (except for camera)
-        int rightMost = mAppWidgetContainer.getChildCount() - 1;
-        if (mAppWidgetContainer.isCameraPage(rightMost)) {
-            rightMost--;
-        }
-        if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost);
-        return rightMost;
-    }
-
-    private void enableUserSelectorIfNecessary() {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um == null) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Log.e(TAG, "user service is null.", t);
-            return;
-        }
-
-        // if there are multiple users, we need to enable to multi-user switcher
-        if (!um.isUserSwitcherEnabled()) {
-            return;
-        }
-
-        final View multiUserView = findViewById(R.id.keyguard_user_selector);
-        if (multiUserView == null) {
-            if (DEBUG) Log.d(TAG, "can't find user_selector in layout.");
-            return;
-        }
-
-        if (multiUserView instanceof KeyguardMultiUserSelectorView) {
-            mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
-            mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
-            mKeyguardMultiUserSelectorView.addUsers(um.getUsers(true));
-            UserSwitcherCallback callback = new UserSwitcherCallback() {
-                @Override
-                public void hideSecurityView(int duration) {
-                    getSecurityContainer().animate().alpha(0).setDuration(duration);
-                }
-
-                @Override
-                public void showSecurityView() {
-                    getSecurityContainer().setAlpha(1.0f);
-                }
-
-                @Override
-                public void showUnlockHint() {
-                    if (getSecurityContainer() != null) {
-                        getSecurityContainer().showUsabilityHint();
-                    }
-                }
-
-                @Override
-                public void userActivity() {
-                    if (mViewMediatorCallback != null) {
-                        mViewMediatorCallback.userActivity();
-                    }
-                }
-            };
-            mKeyguardMultiUserSelectorView.setCallback(callback);
-        } else {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            if (multiUserView == null) {
-                Log.e(TAG, "could not find the user_selector.", t);
-            } else {
-                Log.e(TAG, "user_selector is the wrong type.", t);
-            }
-        }
+        mAudioManager.dispatchMediaKeyEvent(keyEvent);
     }
 
     @Override
-    public void cleanUp() {
-        // Make sure we let go of all widgets and their package contexts promptly. If we don't do
-        // this, and the associated application is uninstalled, it can cause a soft reboot.
-        int count = mAppWidgetContainer.getChildCount();
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i);
-            frame.removeAllViews();
-        }
-        getSecurityContainer().onPause(); // clean up any actions in progress
-    }
+    public void dispatchSystemUiVisibilityChanged(int visibility) {
+        super.dispatchSystemUiVisibilityChanged(visibility);
 
-    public void goToWidget(int appWidgetId) {
-        mAppWidgetToShow = appWidgetId;
-        mSwitchPageRunnable.run();
-    }
-
-    @Override
-    protected void showBouncer(boolean show) {
-        super.showBouncer(show);
-        mViewStateManager.showBouncer(show);
-    }
-
-    @Override
-    public void onExternalMotionEvent(MotionEvent event) {
-        mAppWidgetContainer.handleExternalCameraEvent(event);
-    }
-
-    @Override
-    protected void onCreateOptions(Bundle options) {
-        if (options != null) {
-            int widgetToShow = options.getInt(LockPatternUtils.KEYGUARD_SHOW_APPWIDGET,
-                    AppWidgetManager.INVALID_APPWIDGET_ID);
-            if (widgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                goToWidget(widgetToShow);
-            }
+        if (!(mContext instanceof Activity)) {
+            setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
         }
     }
 
+    /**
+     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+     * some cases where we wish to disable it, notably when the menu button placement or technology
+     * is prone to false positives.
+     *
+     * @return true if the menu key should be enabled
+     */
+    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+    private boolean shouldEnableMenuKey() {
+        final Resources res = getResources();
+        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+        return !configDisabled || isTestHarness || fileOverride;
+    }
+
+    public boolean handleMenuKey() {
+        // The following enables the MENU key to work for testing automation
+        if (shouldEnableMenuKey()) {
+            dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
+        mViewMediatorCallback = viewMediatorCallback;
+        // Update ViewMediator with the current input method requirements
+        mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
+    }
+
+    public void setLockPatternUtils(LockPatternUtils utils) {
+        mLockPatternUtils = utils;
+        mSecurityContainer.setLockPatternUtils(utils);
+    }
+
+    public SecurityMode getSecurityMode() {
+        return mSecurityContainer.getSecurityMode();
+    }
+
+    public SecurityMode getCurrentSecurityMode() {
+        return mSecurityContainer.getCurrentSecurityMode();
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java b/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java
deleted file mode 100644
index 343fdcb..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardLinearLayout.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-/**
- * A layout that arranges its children into a special type of grid.
- */
-public class KeyguardLinearLayout extends LinearLayout {
-    int mTopChild = 0;
-
-    public KeyguardLinearLayout(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardLinearLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardLinearLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public void setTopChild(View child) {
-        int top = indexOfChild(child);
-        mTopChild = top;
-        invalidate();
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
index 236cbf68..7ddeab4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -19,9 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
deleted file mode 100644
index 3aec55c..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserAvatar.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.os.UserManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-class KeyguardMultiUserAvatar extends FrameLayout {
-    private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName();
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-
-    private ImageView mUserImage;
-    private TextView mUserName;
-    private UserInfo mUserInfo;
-    private static final float ACTIVE_ALPHA = 1.0f;
-    private static final float INACTIVE_ALPHA = 1.0f;
-    private static final float ACTIVE_SCALE = 1.5f;
-    private static final float ACTIVE_TEXT_ALPHA = 0f;
-    private static final float INACTIVE_TEXT_ALPHA = 0.5f;
-    private static final int SWITCH_ANIMATION_DURATION = 150;
-
-    private final float mActiveAlpha;
-    private final float mActiveScale;
-    private final float mActiveTextAlpha;
-    private final float mInactiveAlpha;
-    private final float mInactiveTextAlpha;
-    private final float mShadowRadius;
-    private final float mStroke;
-    private final float mIconSize;
-    private final int mFrameColor;
-    private final int mFrameShadowColor;
-    private final int mTextColor;
-    private final int mHighlightColor;
-
-    private boolean mTouched;
-
-    private boolean mActive;
-    private boolean mInit = true;
-    private KeyguardMultiUserSelectorView mUserSelector;
-    private KeyguardCircleFramedDrawable mFramed;
-    private boolean mPressLock;
-    private UserManager mUserManager;
-
-    public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
-            KeyguardMultiUserSelectorView userSelector, UserInfo info) {
-        KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar)
-                LayoutInflater.from(context).inflate(resId, userSelector, false);
-
-        icon.init(info, userSelector);
-        return icon;
-    }
-
-    public KeyguardMultiUserAvatar(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        Resources res = mContext.getResources();
-        mTextColor = res.getColor(R.color.keyguard_avatar_nick_color);
-        mIconSize = res.getDimension(R.dimen.keyguard_avatar_size);
-        mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width);
-        mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius);
-        mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color);
-        mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color);
-        mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color);
-        mActiveTextAlpha = ACTIVE_TEXT_ALPHA;
-        mInactiveTextAlpha = INACTIVE_TEXT_ALPHA;
-        mActiveScale = ACTIVE_SCALE;
-        mActiveAlpha = ACTIVE_ALPHA;
-        mInactiveAlpha = INACTIVE_ALPHA;
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        mTouched = false;
-
-        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-    }
-
-    protected String rewriteIconPath(String path) {
-        return path;
-    }
-
-    public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
-        mUserInfo = user;
-        mUserSelector = userSelector;
-
-        mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
-        mUserName = (TextView) findViewById(R.id.keyguard_user_name);
-
-        mFramed = (KeyguardCircleFramedDrawable)
-                MultiUserAvatarCache.getInstance().get(user.id);
-
-        // If we can't find it or the params don't match, create the drawable again
-        if (mFramed == null
-                || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor,
-                        mShadowRadius, mHighlightColor)) {
-            Bitmap icon = null;
-            try {
-                icon = mUserManager.getUserIcon(user.id);
-            } catch (Exception e) {
-                if (DEBUG) Log.d(TAG, "failed to get profile icon " + user, e);
-            }
-
-            if (icon == null) {
-                icon = BitmapFactory.decodeResource(mContext.getResources(),
-                        com.android.internal.R.drawable.ic_contact_picture);
-            }
-
-            mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
-                    mFrameShadowColor, mShadowRadius, mHighlightColor);
-            MultiUserAvatarCache.getInstance().put(user.id, mFramed);
-        }
-
-        mFramed.reset();
-
-        mUserImage.setImageDrawable(mFramed);
-        mUserName.setText(mUserInfo.name);
-        setOnClickListener(mUserSelector);
-        mInit = false;
-    }
-
-    public void setActive(boolean active, boolean animate, final Runnable onComplete) {
-        if (mActive != active || mInit) {
-            mActive = active;
-
-            if (active) {
-                KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent();
-                parent.setTopChild(this);
-                // TODO: Create an appropriate asset when string changes are possible.
-                setContentDescription(mUserName.getText()
-                        + ". " + mContext.getString(R.string.user_switched, ""));
-            } else {
-                setContentDescription(mUserName.getText());
-            }
-        }
-        updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete);
-    }
-
-    void updateVisualsForActive(boolean active, boolean animate, int duration,
-            final Runnable onComplete) {
-        final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha;
-        final float initAlpha = active ? mInactiveAlpha : mActiveAlpha;
-        final float finalScale = active ? 1f : 1f / mActiveScale;
-        final float initScale = mFramed.getScale();
-        final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) :
-                (int) (mInactiveTextAlpha * 255);
-        final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) :
-                (int) (mActiveTextAlpha * 255);
-        int textColor = mTextColor;
-        mUserName.setTextColor(textColor);
-
-        if (animate && mTouched) {
-            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-            va.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float r = animation.getAnimatedFraction();
-                    float scale = (1 - r) * initScale + r * finalScale;
-                    float alpha = (1 - r) * initAlpha + r * finalAlpha;
-                    int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha);
-                    mFramed.setScale(scale);
-                    mUserImage.setAlpha(alpha);
-                    mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255));
-                    mUserImage.invalidate();
-                }
-            });
-            va.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (onComplete != null) {
-                        onComplete.run();
-                    }
-                }
-            });
-            va.setDuration(duration);
-            va.start();
-        } else {
-            mFramed.setScale(finalScale);
-            mUserImage.setAlpha(finalAlpha);
-            mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255));
-            if (onComplete != null) {
-                post(onComplete);
-            }
-        }
-
-        mTouched = true;
-    }
-
-    @Override
-    public void setPressed(boolean pressed) {
-        if (mPressLock && !pressed) {
-            return;
-        }
-
-        if (mPressLock || !pressed || isClickable()) {
-            super.setPressed(pressed);
-            mFramed.setPressed(pressed);
-            mUserImage.invalidate();
-        }
-    }
-
-    public void lockPressed(boolean pressed) {
-        mPressLock = pressed;
-        setPressed(pressed);
-    }
-
-    public UserInfo getUserInfo() {
-        return mUserInfo;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
deleted file mode 100644
index 06815e1..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-
-public class KeyguardMultiUserSelectorView extends FrameLayout implements View.OnClickListener {
-    private static final String TAG = "KeyguardMultiUserSelectorView";
-
-    private ViewGroup mUsersGrid;
-    private KeyguardMultiUserAvatar mActiveUserAvatar;
-    private KeyguardHostView.UserSwitcherCallback mCallback;
-    private static final int FADE_OUT_ANIMATION_DURATION = 100;
-
-    public KeyguardMultiUserSelectorView(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    protected void onFinishInflate () {
-        mUsersGrid = (ViewGroup) findViewById(R.id.keyguard_users_grid);
-        mUsersGrid.removeAllViews();
-        setClipChildren(false);
-        setClipToPadding(false);
-
-    }
-
-    public void setCallback(KeyguardHostView.UserSwitcherCallback callback) {
-        mCallback = callback;
-    }
-
-    public void addUsers(Collection<UserInfo> userList) {
-        UserInfo activeUser;
-        try {
-            activeUser = ActivityManagerNative.getDefault().getCurrentUser();
-        } catch (RemoteException re) {
-            activeUser = null;
-        }
-
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>(userList);
-        Collections.sort(users, mOrderAddedComparator);
-
-        for (UserInfo user: users) {
-            if (user.supportsSwitchTo()) {
-                KeyguardMultiUserAvatar uv = createAndAddUser(user);
-                if (user.id == activeUser.id) {
-                    mActiveUserAvatar = uv;
-                }
-                uv.setActive(false, false, null);
-            }
-        }
-        mActiveUserAvatar.lockPressed(true);
-    }
-
-    public void finalizeActiveUserView(boolean animate) {
-        if (animate) {
-            getHandler().postDelayed(new Runnable() {
-                    @Override
-                        public void run() {
-                        finalizeActiveUserNow(true);
-                    }
-                }, 500);
-        } else {
-            finalizeActiveUserNow(animate);
-        }
-    }
-
-    void finalizeActiveUserNow(boolean animate) {
-        mActiveUserAvatar.lockPressed(false);
-        mActiveUserAvatar.setActive(true, animate, null);
-    }
-
-    Comparator<UserInfo> mOrderAddedComparator = new Comparator<UserInfo>() {
-        @Override
-        public int compare(UserInfo lhs, UserInfo rhs) {
-            return (lhs.serialNumber - rhs.serialNumber);
-        }
-    };
-
-    private KeyguardMultiUserAvatar createAndAddUser(UserInfo user) {
-        KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
-                R.layout.keyguard_multi_user_avatar, mContext, this, user);
-        mUsersGrid.addView(uv);
-        return uv;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if(event.getActionMasked() != MotionEvent.ACTION_CANCEL && mCallback != null) {
-            mCallback.userActivity();
-        }
-        return false;
-    }
-
-    private void setAllClickable(boolean clickable)
-    {
-        for(int i = 0; i < mUsersGrid.getChildCount(); i++) {
-            View v = mUsersGrid.getChildAt(i);
-            v.setClickable(clickable);
-            v.setPressed(false);
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (!(v instanceof KeyguardMultiUserAvatar)) return;
-        final KeyguardMultiUserAvatar avatar = (KeyguardMultiUserAvatar) v;
-        if (avatar.isClickable()) { // catch race conditions
-            if (mActiveUserAvatar == avatar) {
-                // If they click the currently active user, show the unlock hint
-                mCallback.showUnlockHint();
-                return;
-            } else {
-                // Reset the previously active user to appear inactive
-                mCallback.hideSecurityView(FADE_OUT_ANIMATION_DURATION);
-                setAllClickable(false);
-                avatar.lockPressed(true);
-                mActiveUserAvatar.setActive(false, true, new Runnable() {
-                    @Override
-                    public void run() {
-                        mActiveUserAvatar = avatar;
-                        try {
-                            ActivityManagerNative.getDefault()
-                                    .switchUser(avatar.getUserInfo().id);
-                        } catch (RemoteException re) {
-                            Log.e(TAG, "Couldn't switch user " + re);
-                        }
-                    }
-                });
-            }
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 04ef57e..d0be855 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -29,7 +29,7 @@
 
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
-    private ViewGroup mKeyguardBouncerFrame;
+    private ViewGroup mContainer;
     private ViewGroup mRow0;
     private ViewGroup mRow1;
     private ViewGroup mRow2;
@@ -55,11 +55,7 @@
 
     protected void resetState() {
         super.resetState();
-        if (KeyguardUpdateMonitor.getInstance(mContext).getMaxBiometricUnlockAttemptsReached()) {
-            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
-        } else {
-            mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false);
-        }
+        mSecurityMessageDisplay.setMessage(R.string.kg_pin_instructions, false);
     }
 
     @Override
@@ -71,7 +67,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame);
+        mContainer = (ViewGroup) findViewById(R.id.container);
         mRow0 = (ViewGroup) findViewById(R.id.row0);
         mRow1 = (ViewGroup) findViewById(R.id.row1);
         mRow2 = (ViewGroup) findViewById(R.id.row2);
@@ -150,8 +146,8 @@
     }
 
     private void enableClipping(boolean enable) {
-        mKeyguardBouncerFrame.setClipToPadding(enable);
-        mKeyguardBouncerFrame.setClipChildren(enable);
+        mContainer.setClipToPadding(enable);
+        mContainer.setClipChildren(enable);
         mRow1.setClipToPadding(enable);
         mRow2.setClipToPadding(enable);
         mRow3.setClipToPadding(enable);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 0dfe1dc..9aa5729 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -20,7 +20,6 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
 import android.text.TextUtils;
@@ -39,7 +38,8 @@
 import java.util.List;
 
 public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
-        AppearAnimationCreator<LockPatternView.CellState> {
+        AppearAnimationCreator<LockPatternView.CellState>,
+        EmergencyButton.EmergencyButtonCallback {
 
     private static final String TAG = "SecurityPatternView";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -81,8 +81,7 @@
     private Rect mTempRect = new Rect();
     private SecurityMessageDisplay mSecurityMessageDisplay;
     private View mEcaView;
-    private Drawable mBouncerFrame;
-    private ViewGroup mKeyguardBouncerFrame;
+    private ViewGroup mContainer;
     private KeyguardMessageArea mHelpMessage;
     private int mDisappearYTranslation;
 
@@ -140,13 +139,17 @@
 
         mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
-        View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame);
-        if (bouncerFrameView != null) {
-            mBouncerFrame = bouncerFrameView.getBackground();
-        }
-
-        mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame);
+        mContainer = (ViewGroup) findViewById(R.id.container);
         mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area);
+
+        EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
+        if (button != null) {
+            button.setCallback(this);
+        }
+    }
+
+    public void onEmergencyButtonClickedWhenInCall() {
+        mCallback.reset();
     }
 
     @Override
@@ -182,11 +185,7 @@
     }
 
     private void displayDefaultSecurityMessage() {
-        if (mKeyguardUpdateMonitor.getMaxBiometricUnlockAttemptsReached()) {
-            mSecurityMessageDisplay.setMessage(R.string.faceunlock_multiple_failures, true);
-        } else {
-            mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false);
-        }
+        mSecurityMessageDisplay.setMessage(R.string.kg_pattern_instructions, false);
     }
 
     @Override
@@ -288,18 +287,6 @@
     }
 
     @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                showBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewHelper.
-                hideBouncer(mSecurityMessageDisplay, mEcaView, mBouncerFrame, duration);
-    }
-
-    @Override
     public void startAppearAnimation() {
         enableClipping(false);
         setAlpha(1f);
@@ -359,8 +346,8 @@
 
     private void enableClipping(boolean enable) {
         setClipChildren(enable);
-        mKeyguardBouncerFrame.setClipToPadding(enable);
-        mKeyguardBouncerFrame.setClipChildren(enable);
+        mContainer.setClipToPadding(enable);
+        mContainer.setClipChildren(enable);
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
index f361b5c..5877bc8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -41,8 +41,7 @@
     void reportUnlockAttempt(boolean success);
 
     /**
-     * Shows the backup security for the current method.  If none available, this call is a no-op.
+     * Resets the keyguard view.
      */
-    void showBackupSecurity();
-
+    void reset();
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 559b112..41ec3b0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -20,7 +20,6 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
@@ -41,13 +40,11 @@
     private static final int USER_TYPE_SECONDARY_USER = 3;
 
     private KeyguardSecurityModel mSecurityModel;
-    private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
     private LockPatternUtils mLockPatternUtils;
 
     private KeyguardSecurityViewFlipper mSecurityViewFlipper;
     private boolean mIsVerifyUnlockOnly;
     private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
-    private boolean mIsBouncing;
     private SecurityCallback mSecurityCallback;
 
     private final KeyguardUpdateMonitor mUpdateMonitor;
@@ -58,6 +55,7 @@
         public void userActivity();
         public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
         public void finish();
+        public void reset();
     }
 
     public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
@@ -107,13 +105,6 @@
         return false;
     }
 
-    void updateSecurityViews(boolean isBouncing) {
-        int children = mSecurityViewFlipper.getChildCount();
-        for (int i = 0; i < children; i++) {
-            updateSecurityView(mSecurityViewFlipper.getChildAt(i), isBouncing);
-        }
-    }
-
     public void announceCurrentSecurityMethod() {
         View v = (View) getSecurityView(mCurrentSecuritySelection);
         if (v != null) {
@@ -145,24 +136,18 @@
             if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
             View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
             mSecurityViewFlipper.addView(v);
-            updateSecurityView(v, mIsBouncing);
+            updateSecurityView(v);
             view = (KeyguardSecurityView)v;
         }
 
         return view;
     }
 
-    private void updateSecurityView(View view, boolean isBouncing) {
-        mIsBouncing = isBouncing;
+    private void updateSecurityView(View view) {
         if (view instanceof KeyguardSecurityView) {
             KeyguardSecurityView ksv = (KeyguardSecurityView) view;
             ksv.setKeyguardCallback(mCallback);
             ksv.setLockPatternUtils(mLockPatternUtils);
-            if (isBouncing) {
-                ksv.showBouncer(0);
-            } else {
-                ksv.hideBouncer(0);
-            }
         } else {
             Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
         }
@@ -206,8 +191,6 @@
                 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
                 break;
             // These don't have timeout dialogs.
-            case Account:
-            case Biometric:
             case Invalid:
             case None:
             case SimPin:
@@ -314,17 +297,6 @@
         } else {
             showTimeout =
                 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
-            if (usingPattern && mEnableFallback) {
-                if (failedAttempts == failedAttemptWarning) {
-                    showAlmostAtAccountLoginDialog();
-                    showTimeout = false; // don't show both dialogs
-                } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
-                    mLockPatternUtils.setPermanentlyLocked(true);
-                    showSecurityScreen(SecurityMode.Account);
-                    // don't show timeout dialog because we show account unlock screen next
-                    showTimeout = false;
-                }
-            }
         }
         monitor.reportFailedUnlockAttempt();
         mLockPatternUtils.reportFailedPasswordAttempt();
@@ -341,30 +313,12 @@
     void showPrimarySecurityScreen(boolean turningOff) {
         SecurityMode securityMode = mSecurityModel.getSecurityMode();
         if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
-        if (!turningOff &&
-                KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) {
-            // If we're not turning off, then allow biometric alternate.
-            // We'll reload it when the device comes back on.
-            securityMode = mSecurityModel.getAlternateFor(securityMode);
-        }
         showSecurityScreen(securityMode);
     }
 
     /**
-     * Shows the backup security screen for the current security mode.  This could be used for
-     * password recovery screens but is currently only used for pattern unlock to show the
-     * account unlock screen and biometric unlock to show the user's normal unlock.
-     */
-    private void showBackupSecurityScreen() {
-        if (DEBUG) Log.d(TAG, "showBackupSecurity()");
-        SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection);
-        showSecurityScreen(backup);
-    }
-
-    /**
      * Shows the next security screen if there is one.
      * @param authenticated true if the user entered the correct authentication
-     * @param authenticated
      * @return true if keyguard is done
      */
     boolean showNextSecurityScreenOrFinish(boolean authenticated) {
@@ -374,8 +328,6 @@
             finish = true;
         } else if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode();
-            // Allow an alternate, such as biometric unlock
-            securityMode = mSecurityModel.getAlternateFor(securityMode);
             if (SecurityMode.None == securityMode) {
                 finish = true; // no security required
             } else {
@@ -386,8 +338,6 @@
                 case Pattern:
                 case Password:
                 case PIN:
-                case Account:
-                case Biometric:
                     finish = true;
                     break;
 
@@ -464,22 +414,7 @@
         return null;
     }
 
-    public void showBouncer(int duration) {
-        KeyguardSecurityViewFlipper flipper = getFlipper();
-        if (flipper != null) {
-            flipper.showBouncer(duration);
-        }
-    }
-
-    public void hideBouncer(int duration) {
-        KeyguardSecurityViewFlipper flipper = getFlipper();
-        if (flipper != null) {
-            flipper.hideBouncer(duration);
-        }
-    }
-
     private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
-
         public void userActivity() {
             if (mSecurityCallback != null) {
                 mSecurityCallback.userActivity();
@@ -500,19 +435,13 @@
                 monitor.clearFailedUnlockAttempts();
                 mLockPatternUtils.reportSuccessfulPasswordAttempt();
             } else {
-                if (mCurrentSecuritySelection == SecurityMode.Biometric) {
-                    monitor.reportFailedBiometricUnlockAttempt();
-                } else {
-                    KeyguardSecurityContainer.this.reportFailedUnlockAttempt();
-                }
+                KeyguardSecurityContainer.this.reportFailedUnlockAttempt();
             }
         }
 
-        @Override
-        public void showBackupSecurity() {
-            KeyguardSecurityContainer.this.showBackupSecurityScreen();
+        public void reset() {
+            mSecurityCallback.reset();
         }
-
     };
 
     // The following is used to ignore callbacks from SecurityViews that are no longer current
@@ -522,13 +451,13 @@
         @Override
         public void userActivity() { }
         @Override
-        public void showBackupSecurity() { }
-        @Override
         public void reportUnlockAttempt(boolean success) { }
         @Override
         public boolean isVerifyUnlockOnly() { return false; }
         @Override
         public void dismiss(boolean securityVerified) { }
+        @Override
+        public void reset() {}
     };
 
     private int getSecurityViewIdForMode(SecurityMode securityMode) {
@@ -536,8 +465,6 @@
             case Pattern: return R.id.keyguard_pattern_view;
             case PIN: return R.id.keyguard_pin_view;
             case Password: return R.id.keyguard_password_view;
-            case Biometric: return R.id.keyguard_face_unlock_view;
-            case Account: return R.id.keyguard_account_view;
             case SimPin: return R.id.keyguard_sim_pin_view;
             case SimPuk: return R.id.keyguard_sim_puk_view;
         }
@@ -549,8 +476,6 @@
             case Pattern: return R.layout.keyguard_pattern_view;
             case PIN: return R.layout.keyguard_pin_view;
             case Password: return R.layout.keyguard_password_view;
-            case Biometric: return R.layout.keyguard_face_unlock_view;
-            case Account: return R.layout.keyguard_account_view;
             case SimPin: return R.layout.keyguard_sim_pin_view;
             case SimPuk: return R.layout.keyguard_sim_puk_view;
             default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 1e2a233..3eb31ad 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -17,20 +17,16 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.widget.LockPatternUtils;
 
-import java.util.List;
-
 public class KeyguardSecurityModel {
 
     /**
-     * The different types of security available for {@link Mode#UnlockScreen}.
-     * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
+     * The different types of security available.
+     * @see KeyguardSecurityContainer#showSecurityScreen
      */
     public enum SecurityMode {
         Invalid, // NULL state
@@ -38,117 +34,57 @@
         Pattern, // Unlock by drawing a pattern.
         Password, // Unlock by entering an alphanumeric password
         PIN, // Strictly numeric password
-        Biometric, // Unlock with a biometric key (e.g. finger print or face unlock)
-        Account, // Unlock by entering an account's login and password.
         SimPin, // Unlock by entering a sim pin.
         SimPuk // Unlock by entering a sim puk
     }
 
-    private Context mContext;
+    private final Context mContext;
+    private final boolean mIsPukScreenAvailable;
+
     private LockPatternUtils mLockPatternUtils;
 
     KeyguardSecurityModel(Context context) {
         mContext = context;
         mLockPatternUtils = new LockPatternUtils(context);
+        mIsPukScreenAvailable = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enable_puk_unlock_screen);
     }
 
     void setLockPatternUtils(LockPatternUtils utils) {
         mLockPatternUtils = utils;
     }
 
-    /**
-     * Returns true if biometric unlock is installed and selected.  If this returns false there is
-     * no need to even construct the biometric unlock.
-     */
-    boolean isBiometricUnlockEnabled() {
-        return mLockPatternUtils.usingBiometricWeak()
-                && mLockPatternUtils.isBiometricWeakInstalled();
-    }
-
-    /**
-     * Returns true if a condition is currently suppressing the biometric unlock.  If this returns
-     * true there is no need to even construct the biometric unlock.
-     */
-    private boolean isBiometricUnlockSuppressed() {
-        KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final boolean backupIsTimedOut = monitor.getFailedUnlockAttempts() >=
-                LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-        return monitor.getMaxBiometricUnlockAttemptsReached() || backupIsTimedOut
-                || !monitor.isAlternateUnlockEnabled()
-                || monitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE;
-    }
-
     SecurityMode getSecurityMode() {
         KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        SecurityMode mode = SecurityMode.None;
+
         if (SubscriptionManager.isValidSubscriptionId(
                 monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
-            mode = SecurityMode.SimPin;
-        } else if (SubscriptionManager.isValidSubscriptionId(
-                    monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))
-                && mLockPatternUtils.isPukUnlockScreenEnable()) {
-            mode = SecurityMode.SimPuk;
-        } else {
-            final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
-            switch (security) {
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.PIN : SecurityMode.None;
-                    break;
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
-                    mode = mLockPatternUtils.isLockPasswordEnabled() ?
-                            SecurityMode.Password : SecurityMode.None;
-                    break;
-
-                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
-                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-                    if (mLockPatternUtils.isLockPatternEnabled()) {
-                        mode = mLockPatternUtils.isPermanentlyLocked() ?
-                            SecurityMode.Account : SecurityMode.Pattern;
-                    }
-                    break;
-
-                default:
-                    throw new IllegalStateException("Unknown security quality:" + security);
-            }
+            return SecurityMode.SimPin;
         }
-        return mode;
-    }
 
-    /**
-     * Some unlock methods can have an alternate, such as biometric unlocks (e.g. face unlock).
-     * This function decides if an alternate unlock is available and returns it. Otherwise,
-     * returns @param mode.
-     *
-     * @param mode the mode we want the alternate for
-     * @return alternate or the given mode
-     */
-    SecurityMode getAlternateFor(SecurityMode mode) {
-        if (isBiometricUnlockEnabled() && !isBiometricUnlockSuppressed()
-                && (mode == SecurityMode.Password
-                        || mode == SecurityMode.PIN
-                        || mode == SecurityMode.Pattern)) {
-            return SecurityMode.Biometric;
+        if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
+                monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))) {
+            return SecurityMode.SimPuk;
         }
-        return mode; // no alternate, return what was given
-    }
 
-    /**
-     * Some unlock methods can have a backup which gives the user another way to get into
-     * the device. This is currently only supported for Biometric and Pattern unlock.
-     *
-     * @return backup method or current security mode
-     */
-    SecurityMode getBackupSecurityMode(SecurityMode mode) {
-        switch(mode) {
-            case Biometric:
-                return getSecurityMode();
-            case Pattern:
-                return SecurityMode.Account;
+        final int security = mLockPatternUtils.getActivePasswordQuality();
+        switch (security) {
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
+                return SecurityMode.PIN;
+
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+                return SecurityMode.Password;
+
+            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
+                return SecurityMode.Pattern;
+            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
+                return SecurityMode.None;
+
+            default:
+                throw new IllegalStateException("Unknown security quality:" + security);
         }
-        return mode; // no backup, return current security mode
     }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
index 78fcb9f..5b50236 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -72,20 +72,6 @@
     void showUsabilityHint();
 
     /**
-     * Place the security view into bouncer mode.
-     * Animate transisiton if duration is non-zero.
-     * @param duration millisends for the transisiton animation.
-     */
-    void showBouncer(int duration);
-
-    /**
-     * Place the security view into non-bouncer mode.
-     * Animate transisiton if duration is non-zero.
-     * @param duration millisends for the transisiton animation.
-     */
-    void hideBouncer(int duration);
-
-    /**
      * Starts the animation which should run when the security view appears.
      */
     void startAppearAnimation();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index ea5c304..b5eda90 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -135,30 +135,6 @@
     }
 
     @Override
-    public void showBouncer(int duration) {
-        KeyguardSecurityView active = getSecurityView();
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof KeyguardSecurityView) {
-                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
-                ksv.showBouncer(ksv == active ? duration : 0);
-            }
-        }
-    }
-
-    @Override
-    public void hideBouncer(int duration) {
-        KeyguardSecurityView active = getSecurityView();
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof KeyguardSecurityView) {
-                KeyguardSecurityView ksv = (KeyguardSecurityView) child;
-                ksv.hideBouncer(ksv == active ? duration : 0);
-            }
-        }
-    }
-
-    @Override
     public void startAppearAnimation() {
         KeyguardSecurityView ksv = getSecurityView();
         if (ksv != null) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java
deleted file mode 100644
index 67a6f52..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewHelper.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.graphics.drawable.Drawable;
-import android.view.View;
-
-/**
- * Some common functions that are useful for KeyguardSecurityViews.
- */
-public class KeyguardSecurityViewHelper {
-
-    public static void showBouncer(SecurityMessageDisplay securityMessageDisplay,
-            final View ecaView, Drawable bouncerFrame, int duration) {
-        if (securityMessageDisplay != null) {
-            securityMessageDisplay.showBouncer(duration);
-        }
-        if (ecaView != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 0f);
-                anim.setDuration(duration);
-                anim.addListener(new AnimatorListenerAdapter() {
-                    private boolean mCanceled;
-                    @Override
-                    public void onAnimationCancel(Animator animation) {
-                        // Fail safe and show the emergency button in onAnimationEnd()
-                        mCanceled = true;
-                        ecaView.setAlpha(1f);
-                    }
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        ecaView.setVisibility(mCanceled ? View.VISIBLE : View.INVISIBLE);
-                    }
-                });
-                anim.start();
-            } else {
-                ecaView.setAlpha(0f);
-                ecaView.setVisibility(View.INVISIBLE);
-            }
-        }
-        if (bouncerFrame != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 0, 255);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                bouncerFrame.setAlpha(255);
-            }
-        }
-    }
-
-    public static void hideBouncer(SecurityMessageDisplay securityMessageDisplay,
-            View ecaView, Drawable bouncerFrame, int duration) {
-        if (securityMessageDisplay != null) {
-            securityMessageDisplay.hideBouncer(duration);
-        }
-        if (ecaView != null) {
-            ecaView.setVisibility(View.VISIBLE);
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofFloat(ecaView, "alpha", 1f);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                ecaView.setAlpha(1f);
-            }
-        }
-        if (bouncerFrame != null) {
-            if (duration > 0) {
-                Animator anim = ObjectAnimator.ofInt(bouncerFrame, "alpha", 255, 0);
-                anim.setDuration(duration);
-                anim.start();
-            } else {
-                bouncerFrame.setAlpha(0);
-            }
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
deleted file mode 100644
index 828c921..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
+++ /dev/null
@@ -1,84 +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.keyguard;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-
-public class KeyguardSimpleHostView extends KeyguardViewBase {
-
-    public KeyguardSimpleHostView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateCallback);
-    }
-
-    @Override
-    protected void showBouncer(boolean show) {
-        super.showBouncer(show);
-        if (show) {
-            getSecurityContainer().showBouncer(250);
-        } else {
-            getSecurityContainer().hideBouncer(250);
-        }
-    }
-
-    @Override
-    public void cleanUp() {
-        getSecurityContainer().onPause();
-    }
-
-    @Override
-    public long getUserActivityTimeout() {
-        return -1; // not used
-    }
-
-    @Override
-    protected void onUserSwitching(boolean switching) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    protected void onCreateOptions(Bundle options) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    protected void onExternalMotionEvent(MotionEvent event) {
-        // TODO Auto-generated method stub
-    }
-
-    private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
-        }
-
-        @Override
-        public void onTrustInitiatedByUser(int userId) {
-            if (userId != mLockPatternUtils.getCurrentUser()) return;
-            if (!isAttachedToWindow()) return;
-
-            if (isVisibleToUser()) {
-                dismiss(false /* authenticated */);
-            } else {
-                mViewMediatorCallback.playTrustedSound();
-            }
-        }
-    };
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index c8d9fe2..af6360a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -22,7 +22,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.provider.AlarmClock;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
@@ -42,7 +42,8 @@
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final String TAG = "KeyguardStatusView";
 
-    private LockPatternUtils mLockPatternUtils;
+    private final LockPatternUtils mLockPatternUtils;
+    private final AlarmManager mAlarmManager;
 
     private TextView mAlarmStatusView;
     private TextClock mDateView;
@@ -92,6 +93,8 @@
 
     public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mLockPatternUtils = new LockPatternUtils(getContext());
     }
 
     private void setEnableMarquee(boolean enabled) {
@@ -109,7 +112,7 @@
         mDateView.setShowCurrentUserTime(true);
         mClockView.setShowCurrentUserTime(true);
         mOwnerInfo = (TextView) findViewById(R.id.owner_info);
-        mLockPatternUtils = new LockPatternUtils(getContext());
+
         final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
         setEnableMarquee(screenOn);
         refresh();
@@ -140,7 +143,8 @@
     }
 
     private void refresh() {
-        AlarmManager.AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm();
+        AlarmManager.AlarmClockInfo nextAlarm =
+                mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
         Patterns.update(mContext, nextAlarm != null);
 
         refreshTime();
@@ -193,10 +197,6 @@
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
     }
 
-    public int getAppWidgetId() {
-        return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET;
-    }
-
     private String getOwnerInfo() {
         ContentResolver res = getContext().getContentResolver();
         String info = null;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusViewManager.java
deleted file mode 100644
index e69de29..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusViewManager.java
+++ /dev/null
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
deleted file mode 100644
index 0d472ae..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.MediaMetadataEditor;
-import android.media.MediaMetadataRetriever;
-import android.media.RemoteControlClient;
-import android.media.RemoteController;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.transition.ChangeBounds;
-import android.transition.ChangeText;
-import android.transition.Fade;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * This is the widget responsible for showing music controls in keyguard.
- */
-public class KeyguardTransportControlView extends FrameLayout {
-
-    private static final int RESET_TO_METADATA_DELAY = 5000;
-    protected static final boolean DEBUG = KeyguardConstants.DEBUG;
-    protected static final String TAG = "TransportControlView";
-
-    private static final boolean ANIMATE_TRANSITIONS = true;
-    protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000;
-
-    private ViewGroup mMetadataContainer;
-    private ViewGroup mInfoContainer;
-    private TextView mTrackTitle;
-    private TextView mTrackArtistAlbum;
-
-    private View mTransientSeek;
-    private SeekBar mTransientSeekBar;
-    private TextView mTransientSeekTimeElapsed;
-    private TextView mTransientSeekTimeTotal;
-
-    private ImageView mBtnPrev;
-    private ImageView mBtnPlay;
-    private ImageView mBtnNext;
-    private Metadata mMetadata = new Metadata();
-    private int mTransportControlFlags;
-    private int mCurrentPlayState;
-    private AudioManager mAudioManager;
-    private RemoteController mRemoteController;
-
-    private ImageView mBadge;
-
-    private boolean mSeekEnabled;
-    private java.text.DateFormat mFormat;
-
-    private Date mTempDate = new Date();
-
-    /**
-     * The metadata which should be populated into the view once we've been attached
-     */
-    private RemoteController.MetadataEditor mPopulateMetadataWhenAttached = null;
-
-    private RemoteController.OnClientUpdateListener mRCClientUpdateListener =
-            new RemoteController.OnClientUpdateListener() {
-        @Override
-        public void onClientChange(boolean clearing) {
-            if (clearing) {
-                clearMetadata();
-            }
-        }
-
-        @Override
-        public void onClientPlaybackStateUpdate(int state) {
-            updatePlayPauseState(state);
-        }
-
-        @Override
-        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
-                long currentPosMs, float speed) {
-            updatePlayPauseState(state);
-            if (DEBUG) Log.d(TAG, "onClientPlaybackStateUpdate(state=" + state +
-                    ", stateChangeTimeMs=" + stateChangeTimeMs + ", currentPosMs=" + currentPosMs +
-                    ", speed=" + speed + ")");
-
-            removeCallbacks(mUpdateSeekBars);
-            // Since the music client may be responding to historical events that cause the
-            // playback state to change dramatically, wait until things become quiescent before
-            // resuming automatic scrub position update.
-            if (mTransientSeek.getVisibility() == View.VISIBLE
-                    && playbackPositionShouldMove(mCurrentPlayState)) {
-                postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR);
-            }
-        }
-
-        @Override
-        public void onClientTransportControlUpdate(int transportControlFlags) {
-            updateTransportControls(transportControlFlags);
-        }
-
-        @Override
-        public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) {
-            updateMetadata(metadataEditor);
-        }
-    };
-
-    private class UpdateSeekBarRunnable implements  Runnable {
-        public void run() {
-            boolean seekAble = updateOnce();
-            if (seekAble) {
-                removeCallbacks(this);
-                postDelayed(this, 1000);
-            }
-        }
-        public boolean updateOnce() {
-            return updateSeekBars();
-        }
-    };
-
-    private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable();
-
-    private final Runnable mResetToMetadata = new Runnable() {
-        public void run() {
-            resetToMetadata();
-        }
-    };
-
-    private final OnClickListener mTransportCommandListener = new OnClickListener() {
-        public void onClick(View v) {
-            int keyCode = -1;
-            if (v == mBtnPrev) {
-                keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
-            } else if (v == mBtnNext) {
-                keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
-            } else if (v == mBtnPlay) {
-                keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
-            }
-            if (keyCode != -1) {
-                sendMediaButtonClick(keyCode);
-                delayResetToMetadata(); // if the scrub bar is showing, keep showing it.
-            }
-        }
-    };
-
-    private final OnLongClickListener mTransportShowSeekBarListener = new OnLongClickListener() {
-        @Override
-        public boolean onLongClick(View v) {
-            if (mSeekEnabled) {
-                return tryToggleSeekBar();
-            }
-            return false;
-        }
-    };
-
-    // This class is here to throttle scrub position updates to the music client
-    class FutureSeekRunnable implements Runnable {
-        private int mProgress;
-        private boolean mPending;
-
-        public void run() {
-            scrubTo(mProgress);
-            mPending = false;
-        }
-
-        void setProgress(int progress) {
-            mProgress = progress;
-            if (!mPending) {
-                mPending = true;
-                postDelayed(this, 30);
-            }
-        }
-    };
-
-    // This is here because RemoteControlClient's method isn't visible :/
-    private final static boolean playbackPositionShouldMove(int playstate) {
-        switch(playstate) {
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-            case RemoteControlClient.PLAYSTATE_ERROR:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                return false;
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            default:
-                return true;
-        }
-    }
-
-    private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable();
-
-    private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener =
-            new SeekBar.OnSeekBarChangeListener() {
-        @Override
-        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-            if (fromUser) {
-                mFutureSeekRunnable.setProgress(progress);
-                delayResetToMetadata();
-                mTempDate.setTime(progress);
-                mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
-            } else {
-                updateSeekDisplay();
-            }
-        }
-
-        @Override
-        public void onStartTrackingTouch(SeekBar seekBar) {
-            delayResetToMetadata();
-            removeCallbacks(mUpdateSeekBars); // don't update during user interaction
-        }
-
-        @Override
-        public void onStopTrackingTouch(SeekBar seekBar) {
-        }
-    };
-
-    private static final int TRANSITION_DURATION = 200;
-    private final TransitionSet mMetadataChangeTransition;
-
-    KeyguardHostView.TransportControlCallback mTransportControlCallback;
-
-    private final KeyguardUpdateMonitorCallback mUpdateMonitor
-            = new KeyguardUpdateMonitorCallback() {
-        public void onScreenTurnedOff(int why) {
-            setEnableMarquee(false);
-        }
-        public void onScreenTurnedOn() {
-            setEnableMarquee(true);
-        }
-    };
-
-    public KeyguardTransportControlView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (DEBUG) Log.v(TAG, "Create TCV " + this);
-        mAudioManager = new AudioManager(mContext);
-        mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
-        mRemoteController = new RemoteController(context, mRCClientUpdateListener);
-
-        final DisplayMetrics dm = context.getResources().getDisplayMetrics();
-        final int dim = Math.max(dm.widthPixels, dm.heightPixels);
-        mRemoteController.setArtworkConfiguration(true, dim, dim);
-
-        final ChangeText tc = new ChangeText();
-        tc.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN);
-        final TransitionSet inner = new TransitionSet();
-        inner.addTransition(tc).addTransition(new ChangeBounds());
-        final TransitionSet tg = new TransitionSet();
-        tg.addTransition(new Fade(Fade.OUT)).addTransition(inner).
-                addTransition(new Fade(Fade.IN));
-        tg.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
-        tg.setDuration(TRANSITION_DURATION);
-        mMetadataChangeTransition = tg;
-    }
-
-    private void updateTransportControls(int transportControlFlags) {
-        mTransportControlFlags = transportControlFlags;
-        setSeekBarsEnabled(
-                (transportControlFlags & RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE) != 0);
-    }
-
-    void setSeekBarsEnabled(boolean enabled) {
-        if (enabled == mSeekEnabled) return;
-
-        mSeekEnabled = enabled;
-        if (mTransientSeek.getVisibility() == VISIBLE && !enabled) {
-            mTransientSeek.setVisibility(INVISIBLE);
-            mMetadataContainer.setVisibility(VISIBLE);
-            cancelResetToMetadata();
-        }
-    }
-
-    public void setTransportControlCallback(KeyguardHostView.TransportControlCallback
-            transportControlCallback) {
-        mTransportControlCallback = transportControlCallback;
-    }
-
-    private void setEnableMarquee(boolean enabled) {
-        if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
-        if (mTrackTitle != null) mTrackTitle.setSelected(enabled);
-        if (mTrackArtistAlbum != null) mTrackTitle.setSelected(enabled);
-    }
-
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        mInfoContainer = (ViewGroup) findViewById(R.id.info_container);
-        mMetadataContainer = (ViewGroup) findViewById(R.id.metadata_container);
-        mBadge = (ImageView) findViewById(R.id.badge);
-        mTrackTitle = (TextView) findViewById(R.id.title);
-        mTrackArtistAlbum = (TextView) findViewById(R.id.artist_album);
-        mTransientSeek = findViewById(R.id.transient_seek);
-        mTransientSeekBar = (SeekBar) findViewById(R.id.transient_seek_bar);
-        mTransientSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
-        mTransientSeekTimeElapsed = (TextView) findViewById(R.id.transient_seek_time_elapsed);
-        mTransientSeekTimeTotal = (TextView) findViewById(R.id.transient_seek_time_remaining);
-        mBtnPrev = (ImageView) findViewById(R.id.btn_prev);
-        mBtnPlay = (ImageView) findViewById(R.id.btn_play);
-        mBtnNext = (ImageView) findViewById(R.id.btn_next);
-        final View buttons[] = { mBtnPrev, mBtnPlay, mBtnNext };
-        for (View view : buttons) {
-            view.setOnClickListener(mTransportCommandListener);
-            view.setOnLongClickListener(mTransportShowSeekBarListener);
-        }
-        final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
-        setEnableMarquee(screenOn);
-        // Allow long-press anywhere else in this view to show the seek bar
-        setOnLongClickListener(mTransportShowSeekBarListener);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (DEBUG) Log.v(TAG, "onAttachToWindow()");
-        if (mPopulateMetadataWhenAttached != null) {
-            updateMetadata(mPopulateMetadataWhenAttached);
-            mPopulateMetadataWhenAttached = null;
-        }
-        if (DEBUG) Log.v(TAG, "Registering TCV " + this);
-        mMetadata.clear();
-        mAudioManager.registerRemoteController(mRemoteController);
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitor);
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
-        final int dim = Math.max(dm.widthPixels, dm.heightPixels);
-        mRemoteController.setArtworkConfiguration(true, dim, dim);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        if (DEBUG) Log.v(TAG, "onDetachFromWindow()");
-        super.onDetachedFromWindow();
-        if (DEBUG) Log.v(TAG, "Unregistering TCV " + this);
-        mAudioManager.unregisterRemoteController(mRemoteController);
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor);
-        mMetadata.clear();
-        removeCallbacks(mUpdateSeekBars);
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        SavedState ss = new SavedState(super.onSaveInstanceState());
-        ss.artist = mMetadata.artist;
-        ss.trackTitle = mMetadata.trackTitle;
-        ss.albumTitle = mMetadata.albumTitle;
-        ss.duration = mMetadata.duration;
-        ss.bitmap = mMetadata.bitmap;
-        return ss;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        mMetadata.artist = ss.artist;
-        mMetadata.trackTitle = ss.trackTitle;
-        mMetadata.albumTitle = ss.albumTitle;
-        mMetadata.duration = ss.duration;
-        mMetadata.bitmap = ss.bitmap;
-        populateMetadata();
-    }
-
-    void setBadgeIcon(Drawable bmp) {
-        mBadge.setImageDrawable(bmp);
-
-        final ColorMatrix cm = new ColorMatrix();
-        cm.setSaturation(0);
-        mBadge.setColorFilter(new ColorMatrixColorFilter(cm));
-        mBadge.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
-        mBadge.setImageAlpha(0xef);
-    }
-
-    class Metadata {
-        private String artist;
-        private String trackTitle;
-        private String albumTitle;
-        private Bitmap bitmap;
-        private long duration;
-
-        public void clear() {
-            artist = null;
-            trackTitle = null;
-            albumTitle = null;
-            bitmap = null;
-            duration = -1;
-        }
-
-        public String toString() {
-            return "Metadata[artist=" + artist + " trackTitle=" + trackTitle +
-                    " albumTitle=" + albumTitle + " duration=" + duration + "]";
-        }
-    }
-
-    void clearMetadata() {
-        mPopulateMetadataWhenAttached = null;
-        mMetadata.clear();
-        populateMetadata();
-    }
-
-    void updateMetadata(RemoteController.MetadataEditor data) {
-        if (isAttachedToWindow()) {
-            mMetadata.artist = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-                    mMetadata.artist);
-            mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE,
-                    mMetadata.trackTitle);
-            mMetadata.albumTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
-                    mMetadata.albumTitle);
-            mMetadata.duration = data.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION, -1);
-            mMetadata.bitmap = data.getBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK,
-                    mMetadata.bitmap);
-            populateMetadata();
-        } else {
-            mPopulateMetadataWhenAttached = data;
-        }
-    }
-
-    /**
-     * Populates the given metadata into the view
-     */
-    private void populateMetadata() {
-        if (ANIMATE_TRANSITIONS && isLaidOut() && mMetadataContainer.getVisibility() == VISIBLE) {
-            TransitionManager.beginDelayedTransition(mMetadataContainer, mMetadataChangeTransition);
-        }
-
-        final String remoteClientPackage = mRemoteController.getRemoteControlClientPackageName();
-        Drawable badgeIcon = null;
-        try {
-            badgeIcon = getContext().getPackageManager().getApplicationIcon(remoteClientPackage);
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "Couldn't get remote control client package icon", e);
-        }
-        setBadgeIcon(badgeIcon);
-        mTrackTitle.setText(!TextUtils.isEmpty(mMetadata.trackTitle)
-                ? mMetadata.trackTitle : null);
-
-        final StringBuilder sb = new StringBuilder();
-        if (!TextUtils.isEmpty(mMetadata.artist)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.artist);
-        }
-        if (!TextUtils.isEmpty(mMetadata.albumTitle)) {
-            if (sb.length() != 0) {
-                sb.append(" - ");
-            }
-            sb.append(mMetadata.albumTitle);
-        }
-
-        final String trackArtistAlbum = sb.toString();
-        mTrackArtistAlbum.setText(!TextUtils.isEmpty(trackArtistAlbum) ?
-                trackArtistAlbum : null);
-
-        if (mMetadata.duration >= 0) {
-            setSeekBarsEnabled(true);
-            setSeekBarDuration(mMetadata.duration);
-
-            final String skeleton;
-
-            if (mMetadata.duration >= 86400000) {
-                skeleton = "DDD kk mm ss";
-            } else if (mMetadata.duration >= 3600000) {
-                skeleton = "kk mm ss";
-            } else {
-                skeleton = "mm ss";
-            }
-            mFormat = new SimpleDateFormat(DateFormat.getBestDateTimePattern(
-                    getContext().getResources().getConfiguration().locale,
-                    skeleton));
-            mFormat.setTimeZone(TimeZone.getTimeZone("GMT+0"));
-        } else {
-            setSeekBarsEnabled(false);
-        }
-
-        KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(mMetadata.bitmap);
-        final int flags = mTransportControlFlags;
-        setVisibilityBasedOnFlag(mBtnPrev, flags, RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS);
-        setVisibilityBasedOnFlag(mBtnNext, flags, RemoteControlClient.FLAG_KEY_MEDIA_NEXT);
-        setVisibilityBasedOnFlag(mBtnPlay, flags,
-                RemoteControlClient.FLAG_KEY_MEDIA_PLAY
-                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
-                | RemoteControlClient.FLAG_KEY_MEDIA_STOP);
-
-        updatePlayPauseState(mCurrentPlayState);
-    }
-
-    void updateSeekDisplay() {
-        if (mMetadata != null && mRemoteController != null && mFormat != null) {
-            mTempDate.setTime(mRemoteController.getEstimatedMediaPosition());
-            mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
-            mTempDate.setTime(mMetadata.duration);
-            mTransientSeekTimeTotal.setText(mFormat.format(mTempDate));
-
-            if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate +
-                    " duration=" + mMetadata.duration);
-        }
-    }
-
-    boolean tryToggleSeekBar() {
-        if (ANIMATE_TRANSITIONS) {
-            TransitionManager.beginDelayedTransition(mInfoContainer);
-        }
-        if (mTransientSeek.getVisibility() == VISIBLE) {
-            mTransientSeek.setVisibility(INVISIBLE);
-            mMetadataContainer.setVisibility(VISIBLE);
-            cancelResetToMetadata();
-            removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible
-        } else {
-            mTransientSeek.setVisibility(VISIBLE);
-            mMetadataContainer.setVisibility(INVISIBLE);
-            delayResetToMetadata();
-            if (playbackPositionShouldMove(mCurrentPlayState)) {
-                mUpdateSeekBars.run();
-            } else {
-                mUpdateSeekBars.updateOnce();
-            }
-        }
-        mTransportControlCallback.userActivity();
-        return true;
-    }
-
-    void resetToMetadata() {
-        if (ANIMATE_TRANSITIONS) {
-            TransitionManager.beginDelayedTransition(mInfoContainer);
-        }
-        if (mTransientSeek.getVisibility() == VISIBLE) {
-            mTransientSeek.setVisibility(INVISIBLE);
-            mMetadataContainer.setVisibility(VISIBLE);
-        }
-        // TODO Also hide ratings, if applicable
-    }
-
-    void delayResetToMetadata() {
-        removeCallbacks(mResetToMetadata);
-        postDelayed(mResetToMetadata, RESET_TO_METADATA_DELAY);
-    }
-
-    void cancelResetToMetadata() {
-        removeCallbacks(mResetToMetadata);
-    }
-
-    void setSeekBarDuration(long duration) {
-        mTransientSeekBar.setMax((int) duration);
-    }
-
-    void scrubTo(int progress) {
-        mRemoteController.seekTo(progress);
-        mTransportControlCallback.userActivity();
-    }
-
-    private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
-        if ((flags & flag) != 0) {
-            view.setVisibility(View.VISIBLE);
-        } else {
-            view.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    private void updatePlayPauseState(int state) {
-        if (DEBUG) Log.v(TAG,
-                "updatePlayPauseState(), old=" + mCurrentPlayState + ", state=" + state);
-        if (state == mCurrentPlayState) {
-            return;
-        }
-        final int imageResId;
-        final int imageDescId;
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                imageResId = R.drawable.stat_sys_warning;
-                // TODO use more specific image description string for warning, but here the "play"
-                //      message is still valid because this button triggers a play command.
-                imageDescId = R.string.keyguard_transport_play_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-                imageResId = R.drawable.ic_media_pause;
-                imageDescId = R.string.keyguard_transport_pause_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                imageResId = R.drawable.ic_media_stop;
-                imageDescId = R.string.keyguard_transport_stop_description;
-                break;
-
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            default:
-                imageResId = R.drawable.ic_media_play;
-                imageDescId = R.string.keyguard_transport_play_description;
-                break;
-        }
-
-        boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0;
-        setSeekBarsEnabled(clientSupportsSeek);
-
-        mBtnPlay.setImageResource(imageResId);
-        mBtnPlay.setContentDescription(getResources().getString(imageDescId));
-        mCurrentPlayState = state;
-    }
-
-    boolean updateSeekBars() {
-        final int position = (int) mRemoteController.getEstimatedMediaPosition();
-        if (DEBUG) Log.v(TAG, "Estimated time:" + position);
-        if (position >= 0) {
-            mTransientSeekBar.setProgress(position);
-            return true;
-        }
-        Log.w(TAG, "Updating seek bars; received invalid estimated media position (" +
-                position + "). Disabling seek.");
-        setSeekBarsEnabled(false);
-        return false;
-    }
-
-    static class SavedState extends BaseSavedState {
-        boolean clientPresent;
-        String artist;
-        String trackTitle;
-        String albumTitle;
-        long duration;
-        Bitmap bitmap;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            clientPresent = in.readInt() != 0;
-            artist = in.readString();
-            trackTitle = in.readString();
-            albumTitle = in.readString();
-            duration = in.readLong();
-            bitmap = Bitmap.CREATOR.createFromParcel(in);
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(clientPresent ? 1 : 0);
-            out.writeString(artist);
-            out.writeString(trackTitle);
-            out.writeString(albumTitle);
-            out.writeLong(duration);
-            bitmap.writeToParcel(out, flags);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    private void sendMediaButtonClick(int keyCode) {
-        // TODO We should think about sending these up/down events accurately with touch up/down
-        // on the buttons, but in the near term this will interfere with the long press behavior.
-        mRemoteController.sendMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
-        mRemoteController.sendMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
-
-        mTransportControlCallback.userActivity();
-    }
-
-    public boolean providesClock() {
-        return false;
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 64fb24b..396fe4f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -51,8 +51,6 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
 import android.service.fingerprint.FingerprintManager;
 import android.service.fingerprint.FingerprintManagerReceiver;
 import android.service.fingerprint.FingerprintUtils;
@@ -86,7 +84,6 @@
     private static final String TAG = "KeyguardUpdateMonitor";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
-    private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
     private static final int LOW_BATTERY_THRESHOLD = 20;
 
     private static final String ACTION_FACE_UNLOCK_STARTED
@@ -104,12 +101,9 @@
     private static final int MSG_DEVICE_PROVISIONED = 308;
     private static final int MSG_DPM_STATE_CHANGED = 309;
     private static final int MSG_USER_SWITCHING = 310;
-    private static final int MSG_USER_REMOVED = 311;
     private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
     private static final int MSG_BOOT_COMPLETED = 313;
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
-    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
-    private static final int MSG_SET_PLAYBACK_STATE = 316;
     private static final int MSG_USER_INFO_CHANGED = 317;
     private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
     private static final int MSG_SCREEN_TURNED_ON = 319;
@@ -139,9 +133,6 @@
 
     // Password attempts
     private int mFailedAttempts = 0;
-    private int mFailedBiometricUnlockAttempts = 0;
-
-    private boolean mAlternateUnlockEnabled;
 
     private boolean mClockVisible;
 
@@ -189,9 +180,6 @@
                 case MSG_USER_SWITCH_COMPLETE:
                     handleUserSwitchComplete(msg.arg1);
                     break;
-                case MSG_USER_REMOVED:
-                    handleUserRemoved(msg.arg1);
-                    break;
                 case MSG_KEYGUARD_VISIBILITY_CHANGED:
                     handleKeyguardVisibilityChanged(msg.arg1);
                     break;
@@ -383,24 +371,11 @@
     }
 
     private boolean isTrustDisabled(int userId) {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-                // TODO once UI is finalized
-                final boolean disabledByGlobalActions = false;
-                final boolean disabledBySettings = false;
-
-                // Don't allow trust agent if device is secured with a SIM PIN. This is here
-                // mainly because there's no other way to prompt the user to enter their SIM PIN
-                // once they get past the keyguard screen.
-                final boolean disabledBySimPin = isSimPinSecure();
-
-                final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId)
-                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
-                return disabledByDpm || disabledByGlobalActions || disabledBySettings
-                        || disabledBySimPin;
-        }
-        return false;
+        // Don't allow trust agent if device is secured with a SIM PIN. This is here
+        // mainly because there's no other way to prompt the user to enter their SIM PIN
+        // once they get past the keyguard screen.
+        final boolean disabledBySimPin = isSimPinSecure();
+        return disabledBySimPin;
     }
 
     private boolean isFingerprintDisabled(int userId) {
@@ -462,9 +437,6 @@
             } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
                 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
-            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
-                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
             } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
                 dispatchBootCompleted();
             }
@@ -692,7 +664,6 @@
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        filter.addAction(Intent.ACTION_USER_REMOVED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
         final IntentFilter bootCompleteFilter = new IntentFilter();
@@ -845,18 +816,6 @@
     }
 
     /**
-     * Handle {@link #MSG_USER_REMOVED}
-     */
-    protected void handleUserRemoved(int userId) {
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onUserRemoved(userId);
-            }
-        }
-    }
-
-    /**
      * Handle {@link #MSG_DEVICE_PROVISIONED}
      */
     protected void handleDeviceProvisioned() {
@@ -1190,7 +1149,6 @@
 
     public void clearFailedUnlockAttempts() {
         mFailedAttempts = 0;
-        mFailedBiometricUnlockAttempts = 0;
     }
 
     public void clearFingerprintRecognized() {
@@ -1209,22 +1167,6 @@
         return mPhoneState;
     }
 
-    public void reportFailedBiometricUnlockAttempt() {
-        mFailedBiometricUnlockAttempts++;
-    }
-
-    public boolean getMaxBiometricUnlockAttemptsReached() {
-        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
-    }
-
-    public boolean isAlternateUnlockEnabled() {
-        return mAlternateUnlockEnabled;
-    }
-
-    public void setAlternateUnlockEnabled(boolean enabled) {
-        mAlternateUnlockEnabled = enabled;
-    }
-
     public boolean isSimPinVoiceSecure() {
         // TODO: only count SIMs that handle voice
         return isSimPinSecure();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c2f355a..f0e2389 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -15,7 +15,6 @@
  */
 package com.android.keyguard;
 
-import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
@@ -123,11 +122,6 @@
     public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { }
 
     /**
-     * Called when a user is removed.
-     */
-    public void onUserRemoved(int userId) { }
-
-    /**
      * Called when the user's info changed.
      */
     public void onUserInfoChanged(int userId) { }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
deleted file mode 100644
index fc17909..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.SearchManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.media.AudioManager;
-import android.media.IAudioService;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView.OnDismissAction;
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-
-import java.io.File;
-
-/**
- * Base class for keyguard view.  {@link #reset} is where you should
- * reset the state of your view.  Use the {@link KeyguardViewCallback} via
- * {@link #getCallback()} to send information back (such as poking the wake lock,
- * or finishing the keyguard).
- *
- * Handles intercepting of media keys that still work when the keyguard is
- * showing.
- */
-public abstract class KeyguardViewBase extends FrameLayout implements SecurityCallback {
-
-    private AudioManager mAudioManager;
-    private TelephonyManager mTelephonyManager = null;
-    protected ViewMediatorCallback mViewMediatorCallback;
-    protected LockPatternUtils mLockPatternUtils;
-    private OnDismissAction mDismissAction;
-
-    // Whether the volume keys should be handled by keyguard. If true, then
-    // they will be handled here for specific media types such as music, otherwise
-    // the audio service will bring up the volume dialog.
-    private static final boolean KEYGUARD_MANAGES_VOLUME = false;
-    public static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final String TAG = "KeyguardViewBase";
-
-    private KeyguardSecurityContainer mSecurityContainer;
-
-    public KeyguardViewBase(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardViewBase(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.keyguardDoneDrawing();
-        }
-    }
-
-    /**
-     * Sets an action to run when keyguard finishes.
-     *
-     * @param action
-     */
-    public void setOnDismissAction(OnDismissAction action) {
-        mDismissAction = action;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mSecurityContainer =
-                (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container);
-        mLockPatternUtils = new LockPatternUtils(mContext);
-        mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
-        mSecurityContainer.setSecurityCallback(this);
-        mSecurityContainer.showPrimarySecurityScreen(false);
-        // mSecurityContainer.updateSecurityViews(false /* not bouncing */);
-    }
-
-    /**
-     * Called when the view needs to be shown.
-     */
-    public void showPrimarySecurityScreen() {
-        if (DEBUG) Log.d(TAG, "show()");
-        mSecurityContainer.showPrimarySecurityScreen(false);
-    }
-
-    /**
-     *  Dismisses the keyguard by going to the next screen or making it gone.
-     *
-     *  @return True if the keyguard is done.
-     */
-    public boolean dismiss() {
-        return dismiss(false);
-    }
-
-    protected void showBouncer(boolean show) {
-        CharSequence what = getContext().getResources().getText(
-                show ? R.string.keyguard_accessibility_show_bouncer
-                        : R.string.keyguard_accessibility_hide_bouncer);
-        announceForAccessibility(what);
-        announceCurrentSecurityMethod();
-    }
-
-    public boolean handleBackKey() {
-        if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) {
-            // go back to primary screen
-            mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/);
-            return true;
-        }
-        if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
-            mSecurityContainer.dismiss(false);
-            return true;
-        }
-        return false;
-    }
-
-    protected void announceCurrentSecurityMethod() {
-        mSecurityContainer.announceCurrentSecurityMethod();
-    }
-
-    @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-            event.getText().add(mSecurityContainer.getCurrentSecurityModeContentDescription());
-            return true;
-        } else {
-            return super.dispatchPopulateAccessibilityEvent(event);
-        }
-    }
-
-    protected KeyguardSecurityContainer getSecurityContainer() {
-        return mSecurityContainer;
-    }
-
-    @Override
-    public boolean dismiss(boolean authenticated) {
-        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
-    }
-
-    /**
-     * Authentication has happened and it's time to dismiss keyguard. This function
-     * should clean up and inform KeyguardViewMediator.
-     */
-    @Override
-    public void finish() {
-        // If the alternate unlock was suppressed, it can now be safely
-        // enabled because the user has left keyguard.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-
-        // If there's a pending runnable because the user interacted with a widget
-        // and we're leaving keyguard, then run it.
-        boolean deferKeyguardDone = false;
-        if (mDismissAction != null) {
-            deferKeyguardDone = mDismissAction.onDismiss();
-            mDismissAction = null;
-        }
-        if (mViewMediatorCallback != null) {
-            if (deferKeyguardDone) {
-                mViewMediatorCallback.keyguardDonePending();
-            } else {
-                mViewMediatorCallback.keyguardDone(true);
-            }
-        }
-    }
-
-    @Override
-    public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.setNeedsInput(needsInput);
-        }
-    }
-
-    public void userActivity() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.userActivity();
-        }
-    }
-
-    protected void onUserActivityTimeoutChanged() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.onUserActivityTimeoutChanged();
-        }
-    }
-
-    /**
-     * Called when the Keyguard is not actively shown anymore on the screen.
-     */
-    public void onPause() {
-        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
-                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
-        // Once the screen turns off, we no longer consider this to be first boot and we want the
-        // biometric unlock to start next time keyguard is shown.
-        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
-        mSecurityContainer.showPrimarySecurityScreen(true);
-        mSecurityContainer.onPause();
-        clearFocus();
-    }
-
-    /**
-     * Called when the Keyguard is actively shown on the screen.
-     */
-    public void onResume() {
-        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
-        mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-        requestFocus();
-    }
-
-    /**
-     * Starts the animation when the Keyguard gets shown.
-     */
-    public void startAppearAnimation() {
-        mSecurityContainer.startAppearAnimation();
-    }
-
-    public void startDisappearAnimation(Runnable finishRunnable) {
-        if (!mSecurityContainer.startDisappearAnimation(finishRunnable) && finishRunnable != null) {
-            finishRunnable.run();
-        }
-    }
-
-    /**
-     * Verify that the user can get past the keyguard securely.  This is called,
-     * for example, when the phone disables the keyguard but then wants to launch
-     * something else that requires secure access.
-     *
-     * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
-     */
-    public void verifyUnlock() {
-        SecurityMode securityMode = mSecurityContainer.getSecurityMode();
-        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(true);
-            }
-        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
-                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
-                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
-            // can only verify unlock when in pattern/password mode
-            if (mViewMediatorCallback != null) {
-                mViewMediatorCallback.keyguardDone(false);
-            }
-        } else {
-            // otherwise, go to the unlock screen, see if they can verify it
-            mSecurityContainer.verifyUnlock();
-        }
-    }
-
-    /**
-     * Called before this view is being removed.
-     */
-    abstract public void cleanUp();
-
-    /**
-     * Gets the desired user activity timeout in milliseconds, or -1 if the
-     * default should be used.
-     */
-    abstract public long getUserActivityTimeout();
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (interceptMediaKey(event)) {
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /**
-     * Allows the media keys to work when the keyguard is showing.
-     * The media keys should be of no interest to the actual keyguard view(s),
-     * so intercepting them here should not be of any harm.
-     * @param event The key event
-     * @return whether the event was consumed as a media key.
-     */
-    public boolean interceptMediaKey(KeyEvent event) {
-        final int keyCode = event.getKeyCode();
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
-                     * in-call to avoid music playback */
-                    if (mTelephonyManager == null) {
-                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
-                                Context.TELEPHONY_SERVICE);
-                    }
-                    if (mTelephonyManager != null &&
-                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
-                        return true;  // suppress key event
-                    }
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-
-                case KeyEvent.KEYCODE_VOLUME_UP:
-                case KeyEvent.KEYCODE_VOLUME_DOWN:
-                case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                    if (KEYGUARD_MANAGES_VOLUME) {
-                        synchronized (this) {
-                            if (mAudioManager == null) {
-                                mAudioManager = (AudioManager) getContext().getSystemService(
-                                        Context.AUDIO_SERVICE);
-                            }
-                        }
-                        // Volume buttons should only function for music (local or remote).
-                        // TODO: Actually handle MUTE.
-                        mAudioManager.adjustSuggestedStreamVolume(
-                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                        ? AudioManager.ADJUST_RAISE
-                                        : AudioManager.ADJUST_LOWER /* direction */,
-                                AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
-                        // Don't execute default volume behavior
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private void handleMediaKeyEvent(KeyEvent keyEvent) {
-        synchronized (this) {
-            if (mAudioManager == null) {
-                mAudioManager = (AudioManager) getContext().getSystemService(
-                        Context.AUDIO_SERVICE);
-            }
-        }
-        mAudioManager.dispatchMediaKeyEvent(keyEvent);
-    }
-
-    @Override
-    public void dispatchSystemUiVisibilityChanged(int visibility) {
-        super.dispatchSystemUiVisibilityChanged(visibility);
-
-        if (!(mContext instanceof Activity)) {
-            setSystemUiVisibility(STATUS_BAR_DISABLE_BACK);
-        }
-    }
-
-    /**
-     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
-     * some cases where we wish to disable it, notably when the menu button placement or technology
-     * is prone to false positives.
-     *
-     * @return true if the menu key should be enabled
-     */
-    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-    private boolean shouldEnableMenuKey() {
-        final Resources res = getResources();
-        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
-        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
-        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
-        return !configDisabled || isTestHarness || fileOverride;
-    }
-
-    public boolean handleMenuKey() {
-        // The following enables the MENU key to work for testing automation
-        if (shouldEnableMenuKey()) {
-            dismiss();
-            return true;
-        }
-        return false;
-    }
-
-    public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
-        mViewMediatorCallback = viewMediatorCallback;
-        // Update ViewMediator with the current input method requirements
-        mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
-    }
-
-    protected KeyguardActivityLauncher getActivityLauncher() {
-        return mActivityLauncher;
-    }
-
-    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
-        @Override
-        Context getContext() {
-            return mContext;
-        }
-
-        @Override
-        void setOnDismissAction(OnDismissAction action) {
-            KeyguardViewBase.this.setOnDismissAction(action);
-        }
-
-        @Override
-        LockPatternUtils getLockPatternUtils() {
-            return mLockPatternUtils;
-        }
-
-        @Override
-        void requestDismissKeyguard() {
-            KeyguardViewBase.this.dismiss(false);
-        }
-    };
-
-    public void showAssistant() {
-        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-
-        if (intent == null) return;
-
-        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
-                getHandler(), null);
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null);
-    }
-
-    public void launchCamera() {
-        mActivityLauncher.launchCamera(getHandler(), null);
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-        mSecurityContainer.setLockPatternUtils(utils);
-    }
-
-    public SecurityMode getSecurityMode() {
-        return mSecurityContainer.getSecurityMode();
-    }
-
-    public SecurityMode getCurrentSecurityMode() {
-        return mSecurityContainer.getCurrentSecurityMode();
-    }
-
-    protected abstract void onUserSwitching(boolean switching);
-
-    protected abstract void onCreateOptions(Bundle options);
-
-    protected abstract void onExternalMotionEvent(MotionEvent event);
-
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
deleted file mode 100644
index e47edf3..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.os.Handler;
-import android.os.Looper;
-import android.view.View;
-
-public class KeyguardViewStateManager implements
-        SlidingChallengeLayout.OnChallengeScrolledListener,
-        ChallengeLayout.OnBouncerStateChangedListener {
-
-    private static final String TAG = "KeyguardViewStateManager";
-    private KeyguardWidgetPager mKeyguardWidgetPager;
-    private ChallengeLayout mChallengeLayout;
-    private KeyguardHostView mKeyguardHostView;
-    private int[] mTmpPoint = new int[2];
-    private int[] mTmpLoc = new int[2];
-
-    private KeyguardSecurityView mKeyguardSecurityContainer;
-    private static final int SCREEN_ON_HINT_DURATION = 1000;
-    private static final int SCREEN_ON_RING_HINT_DELAY = 300;
-    private static final boolean SHOW_INITIAL_PAGE_HINTS = false;
-    Handler mMainQueue = new Handler(Looper.myLooper());
-
-    int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
-
-    // Paged view state
-    private int mPageListeningToSlider = -1;
-    private int mCurrentPage = -1;
-    private int mPageIndexOnPageBeginMoving = -1;
-
-    int mChallengeTop = 0;
-
-    private final AnimatorListener mPauseListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animation) {
-            mKeyguardSecurityContainer.onPause();
-        }
-    };
-
-    private final AnimatorListener mResumeListener = new AnimatorListenerAdapter() {
-        public void onAnimationEnd(Animator animation) {
-            if (((View)mKeyguardSecurityContainer).isShown()) {
-                mKeyguardSecurityContainer.onResume(0);
-            }
-        }
-    };
-
-    public KeyguardViewStateManager(KeyguardHostView hostView) {
-        mKeyguardHostView = hostView;
-    }
-
-    public void setPagedView(KeyguardWidgetPager pagedView) {
-        mKeyguardWidgetPager = pagedView;
-        updateEdgeSwiping();
-    }
-
-    public void setChallengeLayout(ChallengeLayout layout) {
-        mChallengeLayout = layout;
-        updateEdgeSwiping();
-    }
-
-    private void updateEdgeSwiping() {
-        if (mChallengeLayout != null && mKeyguardWidgetPager != null) {
-            if (mChallengeLayout.isChallengeOverlapping()) {
-                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(true);
-            } else {
-                mKeyguardWidgetPager.setOnlyAllowEdgeSwipes(false);
-            }
-        }
-    }
-
-    public boolean isChallengeShowing() {
-        if (mChallengeLayout != null) {
-            return mChallengeLayout.isChallengeShowing();
-        }
-        return false;
-    }
-
-    public boolean isChallengeOverlapping() {
-        if (mChallengeLayout != null) {
-            return mChallengeLayout.isChallengeOverlapping();
-        }
-        return false;
-    }
-
-    public void setSecurityViewContainer(KeyguardSecurityView container) {
-        mKeyguardSecurityContainer = container;
-    }
-
-    public void showBouncer(boolean show) {
-        mChallengeLayout.showBouncer();
-    }
-
-    public boolean isBouncing() {
-        return mChallengeLayout.isBouncing();
-    }
-
-    public void fadeOutSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration)
-                .setListener(mPauseListener);
-    }
-
-    public void fadeInSecurity(int duration) {
-        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration)
-                .setListener(mResumeListener);
-    }
-
-    public void onPageBeginMoving() {
-        if (mChallengeLayout.isChallengeOverlapping() &&
-                mChallengeLayout instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.fadeOutChallenge();
-            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
-        }
-        // We use mAppWidgetToShow to show a particular widget after you add it--
-        // once the user swipes a page we clear that behavior
-        if (mKeyguardHostView != null) {
-            mKeyguardHostView.clearAppWidgetToShow();
-            mKeyguardHostView.setOnDismissAction(null);
-        }
-        if (mHideHintsRunnable != null) {
-            mMainQueue.removeCallbacks(mHideHintsRunnable);
-            mHideHintsRunnable = null;
-        }
-    }
-
-    public void onPageEndMoving() {
-        mPageIndexOnPageBeginMoving = -1;
-    }
-
-    public void onPageSwitching(View newPage, int newPageIndex) {
-        if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
-            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
-            if (isCameraPage) {
-                CameraWidgetFrame camera = (CameraWidgetFrame) newPage;
-                camera.setUseFastTransition(mKeyguardWidgetPager.isWarping());
-            }
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.setChallengeInteractive(!isCameraPage);
-            final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
-            final int newFlags = isCameraPage ? (currentFlags | View.STATUS_BAR_DISABLE_SEARCH)
-                    : (currentFlags & ~View.STATUS_BAR_DISABLE_SEARCH);
-            mKeyguardWidgetPager.setSystemUiVisibility(newFlags);
-        }
-
-        // If the page we're settling to is the same as we started on, and the action of
-        // moving the page hid the security, we restore it immediately.
-        if (mPageIndexOnPageBeginMoving == mKeyguardWidgetPager.getNextPage() &&
-                mChallengeLayout instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            scl.fadeInChallenge();
-            mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(-1);
-        }
-        mPageIndexOnPageBeginMoving = -1;
-    }
-
-    public void onPageSwitched(View newPage, int newPageIndex) {
-        // Reset the previous page size and ensure the current page is sized appropriately.
-        // We only modify the page state if it is not currently under control by the slider.
-        // This prevents conflicts.
-
-        // If the page hasn't switched, don't bother with any of this
-        if (mCurrentPage == newPageIndex) return;
-
-        if (mKeyguardWidgetPager != null && mChallengeLayout != null) {
-            KeyguardWidgetFrame prevPage = mKeyguardWidgetPager.getWidgetPageAt(mCurrentPage);
-            if (prevPage != null && mCurrentPage != mPageListeningToSlider && mCurrentPage
-                    != mKeyguardWidgetPager.getWidgetToResetOnPageFadeOut()) {
-                prevPage.resetSize();
-            }
-
-            KeyguardWidgetFrame newCurPage = mKeyguardWidgetPager.getWidgetPageAt(newPageIndex);
-            boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
-            if (challengeOverlapping && !newCurPage.isSmall()
-                    && mPageListeningToSlider != newPageIndex) {
-                newCurPage.shrinkWidget(true);
-            }
-        }
-
-        mCurrentPage = newPageIndex;
-    }
-
-    public void onPageBeginWarp() {
-        fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
-        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
-        ((KeyguardWidgetFrame)frame).showFrame(this);
-    }
-
-    public void onPageEndWarp() {
-        fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
-        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
-        ((KeyguardWidgetFrame)frame).hideFrame(this);
-    }
-
-    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
-        mTmpPoint[0] = 0;
-        mTmpPoint[1] = top;
-        mapPoint((View) mChallengeLayout, frame, mTmpPoint);
-        return mTmpPoint[1];
-    }
-
-    /**
-     * Simple method to map a point from one view's coordinates to another's. Note: this method
-     * doesn't account for transforms, so if the views will be transformed, this should not be used.
-     *
-     * @param fromView The view to which the point is relative
-     * @param toView The view into which the point should be mapped
-     * @param pt The point
-     */
-    private void mapPoint(View fromView, View toView, int pt[]) {
-        fromView.getLocationInWindow(mTmpLoc);
-
-        int x = mTmpLoc[0];
-        int y = mTmpLoc[1];
-
-        toView.getLocationInWindow(mTmpLoc);
-        int vX = mTmpLoc[0];
-        int vY = mTmpLoc[1];
-
-        pt[0] += x - vX;
-        pt[1] += y - vY;
-    }
-
-    private void userActivity() {
-        if (mKeyguardHostView != null) {
-            mKeyguardHostView.onUserActivityTimeoutChanged();
-            mKeyguardHostView.userActivity();
-        }
-    }
-
-    @Override
-    public void onScrollStateChanged(int scrollState) {
-        if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
-
-        boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
-
-        if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
-            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-            if (frame == null) return;
-
-            if (!challengeOverlapping) {
-                if (!mKeyguardWidgetPager.isPageMoving()) {
-                    frame.resetSize();
-                    userActivity();
-                } else {
-                    mKeyguardWidgetPager.setWidgetToResetOnPageFadeOut(mPageListeningToSlider);
-                }
-            }
-            if (frame.isSmall()) {
-                // This is to make sure that if the scroller animation gets cut off midway
-                // that the frame doesn't stay in a partial down position.
-                frame.setFrameHeight(frame.getSmallFrameHeight());
-            }
-            if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-                frame.hideFrame(this);
-            }
-            updateEdgeSwiping();
-
-            if (mChallengeLayout.isChallengeShowing()) {
-                mKeyguardSecurityContainer.onResume(KeyguardSecurityView.VIEW_REVEALED);
-            } else {
-                mKeyguardSecurityContainer.onPause();
-            }
-            mPageListeningToSlider = -1;
-        } else if (mLastScrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
-            // Whether dragging or settling, if the last state was idle, we use this signal
-            // to update the current page who will receive events from the sliding challenge.
-            // We resize the frame as appropriate.
-            mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-            KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-            if (frame == null) return;
-
-            // Skip showing the frame and shrinking the widget if we are
-            if (!mChallengeLayout.isBouncing()) {
-                if (scrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-                    frame.showFrame(this);
-                }
-
-                // As soon as the security begins sliding, the widget becomes small (if it wasn't
-                // small to begin with).
-                if (!frame.isSmall()) {
-                    // We need to fetch the final page, in case the pages are in motion.
-                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-                    frame.shrinkWidget(false);
-                }
-            } else {
-                if (!frame.isSmall()) {
-                    // We need to fetch the final page, in case the pages are in motion.
-                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-                }
-            }
-
-            // View is on the move.  Pause the security view until it completes.
-            mKeyguardSecurityContainer.onPause();
-        }
-        mLastScrollState = scrollState;
-    }
-
-    @Override
-    public void onScrollPositionChanged(float scrollPosition, int challengeTop) {
-        mChallengeTop = challengeTop;
-        KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
-        if (frame != null && mLastScrollState != SlidingChallengeLayout.SCROLL_STATE_FADING) {
-            frame.adjustFrame(getChallengeTopRelativeToFrame(frame, mChallengeTop));
-        }
-    }
-
-    private Runnable mHideHintsRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mKeyguardWidgetPager != null) {
-                mKeyguardWidgetPager.hideOutlinesAndSidePages();
-            }
-        }
-    };
-
-    public void showUsabilityHints() {
-        mMainQueue.postDelayed( new Runnable() {
-            @Override
-            public void run() {
-                mKeyguardSecurityContainer.showUsabilityHint();
-            }
-        } , SCREEN_ON_RING_HINT_DELAY);
-        if (SHOW_INITIAL_PAGE_HINTS) {
-            mKeyguardWidgetPager.showInitialPageHints();
-        }
-        if (mHideHintsRunnable != null) {
-            mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
-        }
-    }
-
-    // ChallengeLayout.OnBouncerStateChangedListener
-    @Override
-    public void onBouncerStateChanged(boolean bouncerActive) {
-        if (bouncerActive) {
-            mKeyguardWidgetPager.zoomOutToBouncer();
-        } else {
-            mKeyguardWidgetPager.zoomInFromBouncer();
-            if (mKeyguardHostView != null) {
-                mKeyguardHostView.setOnDismissAction(null);
-            }
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java
deleted file mode 100644
index 98b31b7..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetCarousel.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import java.util.ArrayList;
-
-public class KeyguardWidgetCarousel extends KeyguardWidgetPager {
-
-    private float mAdjacentPagesAngle;
-    private static float MAX_SCROLL_PROGRESS = 1.3f;
-    private static float CAMERA_DISTANCE = 10000;
-    protected AnimatorSet mChildrenTransformsAnimator;
-    float[] mTmpTransform = new float[3];
-
-    public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetCarousel(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle);
-    }
-
-    protected float getMaxScrollProgress() {
-        return MAX_SCROLL_PROGRESS;
-    }
-
-    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        View child = getChildAt(index);
-        if (child == null) return 0f;
-
-        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
-        float scrollProgress = getScrollProgress(screenCenter, child, index);
-
-        if (isOverScrollChild(index, scrollProgress)) {
-            return 1.0f;
-        } else if ((showSidePages && inVisibleRange) || index == getNextPage()) {
-            scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
-            float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
-            return alpha;
-        } else {
-            return 0f;
-        }
-    }
-
-    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        boolean inVisibleRange = index >= getNextPage() - 1 && index <= getNextPage() + 1;
-        if (inVisibleRange) {
-            return super.getOutlineAlphaForPage(screenCenter, index, showSidePages);
-        } else {
-            return 0f;
-        }
-    }
-
-    private void updatePageAlphaValues(int screenCenter) {
-        if (mChildrenOutlineFadeAnimation != null) {
-            mChildrenOutlineFadeAnimation.cancel();
-            mChildrenOutlineFadeAnimation = null;
-        }
-        boolean showSidePages = mShowingInitialHints || isPageMoving();
-        if (!isReordering(false)) {
-            for (int i = 0; i < getChildCount(); i++) {
-                KeyguardWidgetFrame child = getWidgetPageAt(i);
-                if (child != null) {
-                    float outlineAlpha = getOutlineAlphaForPage(screenCenter, i, showSidePages);
-                    float contentAlpha = getAlphaForPage(screenCenter, i,showSidePages);
-                    child.setBackgroundAlpha(outlineAlpha);
-                    child.setContentAlpha(contentAlpha);
-                }
-            }
-        }
-    }
-
-    public void showInitialPageHints() {
-        mShowingInitialHints = true;
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            boolean inVisibleRange = i >= getNextPage() - 1 && i <= getNextPage() + 1;
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            if (inVisibleRange) {
-                child.setBackgroundAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-                child.setContentAlpha(1f);
-            } else {
-                child.setBackgroundAlpha(0f);
-                child.setContentAlpha(0f);
-            }
-        }
-    }
-
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        mScreenCenter = screenCenter;
-        updatePageAlphaValues(screenCenter);
-        if (isReordering(false)) return;
-        for (int i = 0; i < getChildCount(); i++) {
-            KeyguardWidgetFrame v = getWidgetPageAt(i);
-            float scrollProgress = getScrollProgress(screenCenter, v, i);
-            float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
-            if (v == mDragView || v == null) continue;
-            v.setCameraDistance(CAMERA_DISTANCE);
-
-            if (isOverScrollChild(i, scrollProgress)) {
-                v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
-                v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
-            } else {
-                int width = v.getMeasuredWidth();
-                float pivotX = (width / 2f) + boundedProgress * (width / 2f);
-                float pivotY = v.getMeasuredHeight() / 2;
-                float rotationY = - mAdjacentPagesAngle * boundedProgress;
-                v.setPivotX(pivotX);
-                v.setPivotY(pivotY);
-                v.setRotationY(rotationY);
-                v.setOverScrollAmount(0f, false);
-            }
-            float alpha = v.getAlpha();
-            // If the view has 0 alpha, we set it to be invisible so as to prevent
-            // it from accepting touches
-            if (alpha == 0) {
-                v.setVisibility(INVISIBLE);
-            } else if (v.getVisibility() != VISIBLE) {
-                v.setVisibility(VISIBLE);
-            }
-        }
-    }
-
-    void animatePagesToNeutral() {
-        if (mChildrenTransformsAnimator != null) {
-            mChildrenTransformsAnimator.cancel();
-            mChildrenTransformsAnimator = null;
-        }
-
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        PropertyValuesHolder outlineAlpha;
-        PropertyValuesHolder rotationY;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
-            if (!inVisibleRange) {
-                child.setRotationY(0f);
-            }
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
-            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
-                    KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-            rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
-            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
-            child.setVisibility(VISIBLE);
-            if (!inVisibleRange) {
-                a.setInterpolator(mSlowFadeInterpolator);
-            }
-            anims.add(a);
-        }
-
-        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
-        mChildrenTransformsAnimator = new AnimatorSet();
-        mChildrenTransformsAnimator.playTogether(anims);
-
-        mChildrenTransformsAnimator.setDuration(duration);
-        mChildrenTransformsAnimator.start();
-    }
-
-    private void getTransformForPage(int screenCenter, int index, float[] transform) {
-        View child = getChildAt(index);
-        float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
-        float rotationY = - mAdjacentPagesAngle * boundedProgress;
-        int width = child.getMeasuredWidth();
-        float pivotX = (width / 2f) + boundedProgress * (width / 2f);
-        float pivotY = child.getMeasuredHeight() / 2;
-
-        transform[0] = pivotX;
-        transform[1] = pivotY;
-        transform[2] = rotationY;
-    }
-
-    Interpolator mFastFadeInterpolator = new Interpolator() {
-        Interpolator mInternal = new DecelerateInterpolator(1.5f);
-        float mFactor = 2.5f;
-        @Override
-        public float getInterpolation(float input) {
-            return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
-        }
-    };
-
-    Interpolator mSlowFadeInterpolator = new Interpolator() {
-        Interpolator mInternal = new AccelerateInterpolator(1.5f);
-        float mFactor = 1.3f;
-        @Override
-        public float getInterpolation(float input) {
-            input -= (1 - 1 / mFactor);
-            input = mFactor * Math.max(input, 0f);
-            return mInternal.getInterpolation(input);
-        }
-    };
-
-    void animatePagesToCarousel() {
-        if (mChildrenTransformsAnimator != null) {
-            mChildrenTransformsAnimator.cancel();
-            mChildrenTransformsAnimator = null;
-        }
-
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        PropertyValuesHolder outlineAlpha;
-        PropertyValuesHolder rotationY;
-        PropertyValuesHolder pivotX;
-        PropertyValuesHolder pivotY;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            float finalAlpha = getAlphaForPage(mScreenCenter, i, true);
-            float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i, true);
-            getTransformForPage(mScreenCenter, i, mTmpTransform);
-
-            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
-
-            ObjectAnimator a;
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
-            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
-            pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
-            pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
-            rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
-
-            if (inVisibleRange) {
-                // for the central pages we animate into a rotated state
-                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
-                        pivotX, pivotY, rotationY);
-            } else {
-                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
-                a.setInterpolator(mFastFadeInterpolator);
-            }
-            anims.add(a);
-        }
-
-        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
-        mChildrenTransformsAnimator = new AnimatorSet();
-        mChildrenTransformsAnimator.playTogether(anims);
-
-        mChildrenTransformsAnimator.setDuration(duration);
-        mChildrenTransformsAnimator.start();
-    }
-
-    protected void reorderStarting() {
-        mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
-        animatePagesToNeutral();
-    }
-
-    protected boolean zoomIn(final Runnable onCompleteRunnable) {
-        animatePagesToCarousel();
-        return super.zoomIn(onCompleteRunnable);
-    }
-
-    @Override
-    protected void onEndReordering() {
-        super.onEndReordering();
-        mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
deleted file mode 100644
index 8ee9b61..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-public class KeyguardWidgetFrame extends FrameLayout {
-    private final static PorterDuffXfermode sAddBlendMode =
-            new PorterDuffXfermode(PorterDuff.Mode.ADD);
-
-    static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f;
-    static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000;
-
-    // Temporarily disable this for the time being until we know why the gfx is messing up
-    static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true;
-
-    private int mGradientColor;
-    private LinearGradient mForegroundGradient;
-    private LinearGradient mLeftToRightGradient;
-    private LinearGradient mRightToLeftGradient;
-    private Paint mGradientPaint = new Paint();
-    boolean mLeftToRight = true;
-
-    private float mOverScrollAmount = 0f;
-    private final Rect mForegroundRect = new Rect();
-    private int mForegroundAlpha = 0;
-    private CheckLongPressHelper mLongPressHelper;
-    private Animator mFrameFade;
-    private boolean mIsSmall = false;
-    private Handler mWorkerHandler;
-
-    private float mBackgroundAlpha;
-    private float mContentAlpha;
-    private float mBackgroundAlphaMultiplier = 1.0f;
-    private Drawable mBackgroundDrawable;
-    private Rect mBackgroundRect = new Rect();
-
-    // These variables are all needed in order to size things properly before we're actually
-    // measured.
-    private int mSmallWidgetHeight;
-    private int mSmallFrameHeight;
-    private boolean mWidgetLockedSmall = false;
-    private int mMaxChallengeTop = -1;
-    private int mFrameStrokeAdjustment;
-    private boolean mPerformAppWidgetSizeUpdateOnBootComplete;
-
-    // This will hold the width value before we've actually been measured
-    private int mFrameHeight;
-
-    private boolean mIsHoveringOverDeleteDropTarget;
-
-    // Multiple callers may try and adjust the alpha of the frame. When a caller shows
-    // the outlines, we give that caller control, and nobody else can fade them out.
-    // This prevents animation conflicts.
-    private Object mBgAlphaController;
-
-    public KeyguardWidgetFrame(Context context) {
-        this(context, null, 0);
-    }
-
-    public KeyguardWidgetFrame(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetFrame(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mLongPressHelper = new CheckLongPressHelper(this);
-
-        Resources res = context.getResources();
-        // TODO: this padding should really correspond to the padding embedded in the background
-        // drawable (ie. outlines).
-        float density = res.getDisplayMetrics().density;
-        int padding = (int) (res.getDisplayMetrics().density * 8);
-        setPadding(padding, padding, padding, padding);
-
-        mFrameStrokeAdjustment = 2 + (int) (2 * density);
-
-        // This will be overriden on phones based on the current security mode, however on tablets
-        // we need to specify a height.
-        mSmallWidgetHeight =
-                res.getDimensionPixelSize(R.dimen.kg_small_widget_height);
-        mBackgroundDrawable = res.getDrawable(R.drawable.kg_widget_bg_padded);
-        mGradientColor = res.getColor(R.color.kg_widget_pager_gradient);
-        mGradientPaint.setXfermode(sAddBlendMode);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        cancelLongPress();
-        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
-
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
-    }
-
-    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
-            new KeyguardUpdateMonitorCallback() {
-        @Override
-        public void onBootCompleted() {
-            if (mPerformAppWidgetSizeUpdateOnBootComplete) {
-                performAppWidgetSizeCallbacksIfNecessary();
-                mPerformAppWidgetSizeUpdateOnBootComplete = false;
-            }
-        }
-    };
-
-    void setIsHoveringOverDeleteDropTarget(boolean isHovering) {
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            if (mIsHoveringOverDeleteDropTarget != isHovering) {
-                mIsHoveringOverDeleteDropTarget = isHovering;
-                int resId = isHovering ? R.string.keyguard_accessibility_delete_widget_start
-                        : R.string.keyguard_accessibility_delete_widget_end;
-                String text = getContext().getResources().getString(resId, getContentDescription());
-                announceForAccessibility(text);
-                invalidate();
-            }
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mLongPressHelper.postCheckForLongPress(ev);
-                break;
-            case MotionEvent.ACTION_MOVE:
-                mLongPressHelper.onMove(ev);
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mLongPressHelper.cancelLongPress();
-                break;
-        }
-
-        // Otherwise continue letting touch events fall through to children
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_MOVE:
-                mLongPressHelper.onMove(ev);
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN:
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mLongPressHelper.cancelLongPress();
-                break;
-        }
-
-        // We return true here to ensure that we will get cancel / up signal
-        // even if none of our children have requested touch.
-        return true;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        super.requestDisallowInterceptTouchEvent(disallowIntercept);
-        cancelLongPress();
-    }
-
-    @Override
-    public void cancelLongPress() {
-        super.cancelLongPress();
-        mLongPressHelper.cancelLongPress();
-    }
-
-
-    private void drawGradientOverlay(Canvas c) {
-        mGradientPaint.setShader(mForegroundGradient);
-        mGradientPaint.setAlpha(mForegroundAlpha);
-        c.drawRect(mForegroundRect, mGradientPaint);
-    }
-
-    private void drawHoveringOverDeleteOverlay(Canvas c) {
-        if (mIsHoveringOverDeleteDropTarget) {
-            c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR);
-        }
-    }
-
-    protected void drawBg(Canvas canvas) {
-        if (mBackgroundAlpha > 0.0f) {
-            Drawable bg = mBackgroundDrawable;
-
-            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
-            bg.setBounds(mBackgroundRect);
-            bg.draw(canvas);
-        }
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            canvas.save();
-        }
-        drawBg(canvas);
-        super.dispatchDraw(canvas);
-        drawGradientOverlay(canvas);
-        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
-            drawHoveringOverDeleteOverlay(canvas);
-            canvas.restore();
-        }
-    }
-
-    /**
-     * Because this view has fading outlines, it is essential that we enable hardware
-     * layers on the content (child) so that updating the alpha of the outlines doesn't
-     * result in the content layer being recreated.
-     */
-    public void enableHardwareLayersForContent() {
-        View widget = getContent();
-        if (widget != null && widget.isHardwareAccelerated()) {
-            widget.setLayerType(LAYER_TYPE_HARDWARE, null);
-        }
-    }
-
-    /**
-     * Because this view has fading outlines, it is essential that we enable hardware
-     * layers on the content (child) so that updating the alpha of the outlines doesn't
-     * result in the content layer being recreated.
-     */
-    public void disableHardwareLayersForContent() {
-        View widget = getContent();
-        if (widget != null) {
-            widget.setLayerType(LAYER_TYPE_NONE, null);
-        }
-    }
-
-    public View getContent() {
-        return getChildAt(0);
-    }
-
-    public int getContentAppWidgetId() {
-        View content = getContent();
-        if (content instanceof AppWidgetHostView) {
-            return ((AppWidgetHostView) content).getAppWidgetId();
-        } else if (content instanceof KeyguardStatusView) {
-            return ((KeyguardStatusView) content).getAppWidgetId();
-        } else {
-            return AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-    }
-
-    public float getBackgroundAlpha() {
-        return mBackgroundAlpha;
-    }
-
-    public void setBackgroundAlphaMultiplier(float multiplier) {
-        if (Float.compare(mBackgroundAlphaMultiplier, multiplier) != 0) {
-            mBackgroundAlphaMultiplier = multiplier;
-            invalidate();
-        }
-    }
-
-    public float getBackgroundAlphaMultiplier() {
-        return mBackgroundAlphaMultiplier;
-    }
-
-    public void setBackgroundAlpha(float alpha) {
-        if (Float.compare(mBackgroundAlpha, alpha) != 0) {
-            mBackgroundAlpha = alpha;
-            invalidate();
-        }
-    }
-
-    public float getContentAlpha() {
-        return mContentAlpha;
-    }
-
-    public void setContentAlpha(float alpha) {
-        mContentAlpha = alpha;
-        View content = getContent();
-        if (content != null) {
-            content.setAlpha(alpha);
-        }
-    }
-
-    /**
-     * Depending on whether the security is up, the widget size needs to change
-     *
-     * @param height The height of the widget, -1 for full height
-     */
-    private void setWidgetHeight(int height) {
-        boolean needLayout = false;
-        View widget = getContent();
-        if (widget != null) {
-            LayoutParams lp = (LayoutParams) widget.getLayoutParams();
-            if (lp.height != height) {
-                needLayout = true;
-                lp.height = height;
-            }
-        }
-        if (needLayout) {
-            requestLayout();
-        }
-    }
-
-    public void setMaxChallengeTop(int top) {
-        boolean dirty = mMaxChallengeTop != top;
-        mMaxChallengeTop = top;
-        mSmallWidgetHeight = top - getPaddingTop();
-        mSmallFrameHeight = top + getPaddingBottom();
-        if (dirty && mIsSmall) {
-            setWidgetHeight(mSmallWidgetHeight);
-            setFrameHeight(mSmallFrameHeight);
-        } else if (dirty && mWidgetLockedSmall) {
-            setWidgetHeight(mSmallWidgetHeight);
-        }
-    }
-
-    public boolean isSmall() {
-        return mIsSmall;
-    }
-
-    public void adjustFrame(int challengeTop) {
-        int frameHeight = challengeTop + getPaddingBottom();
-        setFrameHeight(frameHeight);
-    }
-
-    public void shrinkWidget(boolean alsoShrinkFrame) {
-        mIsSmall = true;
-        setWidgetHeight(mSmallWidgetHeight);
-
-        if (alsoShrinkFrame) {
-            setFrameHeight(mSmallFrameHeight);
-        }
-    }
-
-    public int getSmallFrameHeight() {
-        return mSmallFrameHeight;
-    }
-
-    public void setWidgetLockedSmall(boolean locked) {
-        if (locked) {
-            setWidgetHeight(mSmallWidgetHeight);
-        }
-        mWidgetLockedSmall = locked;
-    }
-
-    public void resetSize() {
-        mIsSmall = false;
-        if (!mWidgetLockedSmall) {
-            setWidgetHeight(LayoutParams.MATCH_PARENT);
-        }
-        setFrameHeight(getMeasuredHeight());
-    }
-
-    public void setFrameHeight(int height) {
-        mFrameHeight = height;
-        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight()));
-        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,getMeasuredWidth() -
-                mFrameStrokeAdjustment, Math.min(getMeasuredHeight(), mFrameHeight) -
-                mFrameStrokeAdjustment);
-        updateGradient();
-        invalidate();
-    }
-
-    public void hideFrame(Object caller) {
-        fadeFrame(caller, false, 0f, KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_OUT_DURATION);
-    }
-
-    public void showFrame(Object caller) {
-        fadeFrame(caller, true, OUTLINE_ALPHA_MULTIPLIER,
-                KeyguardWidgetPager.CHILDREN_OUTLINE_FADE_IN_DURATION);
-    }
-
-    public void fadeFrame(Object caller, boolean takeControl, float alpha, int duration) {
-        if (takeControl) {
-            mBgAlphaController = caller;
-        }
-
-        if (mBgAlphaController != caller && mBgAlphaController != null) {
-            return;
-        }
-
-        if (mFrameFade != null) {
-            mFrameFade.cancel();
-            mFrameFade = null;
-        }
-        PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", alpha);
-        mFrameFade = ObjectAnimator.ofPropertyValuesHolder(this, bgAlpha);
-        mFrameFade.setDuration(duration);
-        mFrameFade.start();
-    }
-
-    private void updateGradient() {
-        float x0 = mLeftToRight ? 0 : mForegroundRect.width();
-        float x1 = mLeftToRight ? mForegroundRect.width(): 0;
-        mLeftToRightGradient = new LinearGradient(x0, 0f, x1, 0f,
-                mGradientColor, 0, Shader.TileMode.CLAMP);
-        mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
-                mGradientColor, 0, Shader.TileMode.CLAMP);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        if (!mIsSmall) {
-            mFrameHeight = h;
-        }
-
-        // mFrameStrokeAdjustment is a cludge to prevent the overlay from drawing outside the
-        // rounded rect background.
-        mForegroundRect.set(mFrameStrokeAdjustment, mFrameStrokeAdjustment,
-                w - mFrameStrokeAdjustment, Math.min(h, mFrameHeight) - mFrameStrokeAdjustment);
-
-        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight));
-        updateGradient();
-        invalidate();
-    }
-
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        performAppWidgetSizeCallbacksIfNecessary();
-    }
-
-    private void performAppWidgetSizeCallbacksIfNecessary() {
-        View content = getContent();
-        if (!(content instanceof AppWidgetHostView)) return;
-
-        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
-            mPerformAppWidgetSizeUpdateOnBootComplete = true;
-            return;
-        }
-
-        // TODO: there's no reason to force the AppWidgetHostView to catch duplicate size calls.
-        // We can do that even more cheaply here. It's not an issue right now since we're in the
-        // system process and hence no binder calls.
-        AppWidgetHostView awhv = (AppWidgetHostView) content;
-        float density = getResources().getDisplayMetrics().density;
-
-        int width = (int) (content.getMeasuredWidth() / density);
-        int height = (int) (content.getMeasuredHeight() / density);
-        awhv.updateAppWidgetSize(null, width, height, width, height, true);
-    }
-
-    void setOverScrollAmount(float r, boolean left) {
-        if (Float.compare(mOverScrollAmount, r) != 0) {
-            mOverScrollAmount = r;
-            mForegroundGradient = left ? mLeftToRightGradient : mRightToLeftGradient;
-            mForegroundAlpha = (int) Math.round((0.5f * r * 255));
-
-            // We bump up the alpha of the outline to hide the fact that the overlay is drawing
-            // over the rounded part of the frame.
-            float bgAlpha = Math.min(OUTLINE_ALPHA_MULTIPLIER + r * (1 - OUTLINE_ALPHA_MULTIPLIER),
-                    1f);
-            setBackgroundAlpha(bgAlpha);
-            invalidate();
-        }
-    }
-
-    public void onActive(boolean isActive) {
-        // hook for subclasses
-    }
-
-    public boolean onUserInteraction(MotionEvent event) {
-        // hook for subclasses
-        return false;
-    }
-
-    public void onBouncerShowing(boolean showing) {
-        // hook for subclasses
-    }
-
-    public void setWorkerHandler(Handler workerHandler) {
-        mWorkerHandler = workerHandler;
-    }
-
-    public Handler getWorkerHandler() {
-        return mWorkerHandler;
-    }
-
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
deleted file mode 100644
index 6120127..0000000
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.text.format.DateFormat;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-import android.widget.TextClock;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import java.util.ArrayList;
-import java.util.TimeZone;
-
-public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
-        OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
-
-    ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
-    private static float CAMERA_DISTANCE = 10000;
-    protected static float OVERSCROLL_MAX_ROTATION = 30;
-    private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
-
-    private static final int FLAG_HAS_LOCAL_HOUR = 0x1;
-    private static final int FLAG_HAS_LOCAL_MINUTE = 0x2;
-
-    protected KeyguardViewStateManager mViewStateManager;
-    private LockPatternUtils mLockPatternUtils;
-
-    // Related to the fading in / out background outlines
-    public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
-    public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
-    protected AnimatorSet mChildrenOutlineFadeAnimation;
-    protected int mScreenCenter;
-    private boolean mHasMeasure = false;
-    boolean showHintsAfterLayout = false;
-
-    private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
-    private static final String TAG = "KeyguardWidgetPager";
-    private boolean mCenterSmallWidgetsVertically;
-
-    private int mPage = 0;
-    private Callbacks mCallbacks;
-
-    private int mWidgetToResetAfterFadeOut;
-    protected boolean mShowingInitialHints = false;
-
-    // A temporary handle to the Add-Widget view
-    private View mAddWidgetView;
-    private int mLastWidthMeasureSpec;
-    private int mLastHeightMeasureSpec;
-
-    // Bouncer
-    private int mBouncerZoomInOutDuration = 250;
-    private float BOUNCER_SCALE_FACTOR = 0.67f;
-
-    // Background worker thread: used here for persistence, also made available to widget frames
-    private final HandlerThread mBackgroundWorkerThread;
-    private final Handler mBackgroundWorkerHandler;
-    private boolean mCameraEventInProgress;
-
-    public KeyguardWidgetPager(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardWidgetPager(Context context) {
-        this(null, null, 0);
-    }
-
-    public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        setPageSwitchListener(this);
-
-        mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker");
-        mBackgroundWorkerThread.start();
-        mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper());
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        // Clean up the worker thread
-        mBackgroundWorkerThread.quit();
-    }
-
-    public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
-        mViewStateManager = viewStateManager;
-    }
-
-    public void setLockPatternUtils(LockPatternUtils l) {
-        mLockPatternUtils = l;
-    }
-
-    @Override
-    public void onPageSwitching(View newPage, int newPageIndex) {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageSwitching(newPage, newPageIndex);
-        }
-    }
-
-    @Override
-    public void onPageSwitched(View newPage, int newPageIndex) {
-        boolean showingClock = false;
-        if (newPage instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) newPage;
-            if (vg.getChildAt(0) instanceof KeyguardStatusView) {
-                showingClock = true;
-            }
-        }
-
-        if (newPage != null &&
-                findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) {
-            showingClock = true;
-        }
-
-        // Disable the status bar clock if we're showing the default status widget
-        if (showingClock) {
-            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
-        } else {
-            setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
-        }
-
-        // Extend the display timeout if the user switches pages
-        if (mPage != newPageIndex) {
-            int oldPageIndex = mPage;
-            mPage = newPageIndex;
-            userActivity();
-            KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex);
-            if (oldWidgetPage != null) {
-                oldWidgetPage.onActive(false);
-            }
-            KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex);
-            if (newWidgetPage != null) {
-                newWidgetPage.onActive(true);
-                newWidgetPage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-                newWidgetPage.requestAccessibilityFocus();
-            }
-            if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) {
-                AccessibilityEvent event = AccessibilityEvent.obtain(
-                        AccessibilityEvent.TYPE_VIEW_SCROLLED);
-                onInitializeAccessibilityEvent(event);
-                onPopulateAccessibilityEvent(event);
-                mParent.requestSendAccessibilityEvent(this, event);
-            }
-        }
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageSwitched(newPage, newPageIndex);
-        }
-    }
-
-    @Override
-    public void onPageBeginWarp() {
-        showOutlinesAndSidePages();
-        mViewStateManager.onPageBeginWarp();
-    }
-
-    @Override
-    public void onPageEndWarp() {
-        // if we're moving to the warp page, then immediately hide the other widgets.
-        int duration = getPageWarpIndex() == getNextPage() ? 0 : -1;
-        animateOutlinesAndSidePages(false, duration);
-        mViewStateManager.onPageEndWarp();
-    }
-
-    @Override
-    public void sendAccessibilityEvent(int eventType) {
-        if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) {
-            super.sendAccessibilityEvent(eventType);
-        }
-    }
-
-    private void updateWidgetFramesImportantForAccessibility() {
-        final int pageCount = getPageCount();
-        for (int i = 0; i < pageCount; i++) {
-            KeyguardWidgetFrame frame = getWidgetPageAt(i);
-            updateWidgetFrameImportantForAccessibility(frame);
-        }
-    }
-
-    private void updateWidgetFrameImportantForAccessibility(KeyguardWidgetFrame frame) {
-        if (frame.getContentAlpha() <= 0) {
-            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-        } else {
-            frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-    }
-
-    private void userActivity() {
-        if (mCallbacks != null) {
-            mCallbacks.onUserActivityTimeoutChanged();
-            mCallbacks.userActivity();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return captureUserInteraction(ev) || super.onTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev);
-    }
-
-    private boolean captureUserInteraction(MotionEvent ev) {
-        KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
-        return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev);
-    }
-
-    public void showPagingFeedback() {
-        // Nothing yet.
-    }
-
-    public long getUserActivityTimeout() {
-        View page = getPageAt(mPage);
-        if (page instanceof ViewGroup) {
-            ViewGroup vg = (ViewGroup) page;
-            View view = vg.getChildAt(0);
-            if (!(view instanceof KeyguardStatusView)
-                    && !(view instanceof KeyguardMultiUserSelectorView)) {
-                return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
-            }
-        }
-        return -1;
-    }
-
-    public void setCallbacks(Callbacks callbacks) {
-        mCallbacks = callbacks;
-    }
-
-    public interface Callbacks {
-        public void userActivity();
-        public void onUserActivityTimeoutChanged();
-        public void onAddView(View v);
-        public void onRemoveView(View v, boolean deletePermanently);
-        public void onRemoveViewAnimationCompleted();
-    }
-
-    public void addWidget(View widget) {
-        addWidget(widget, -1);
-    }
-
-    public void onRemoveView(View v, final boolean deletePermanently) {
-        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        if (mCallbacks != null) {
-            mCallbacks.onRemoveView(v, deletePermanently);
-        }
-        mBackgroundWorkerHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mLockPatternUtils.removeAppWidget(appWidgetId);
-            }
-        });
-    }
-
-    @Override
-    public void onRemoveViewAnimationCompleted() {
-        if (mCallbacks != null) {
-            mCallbacks.onRemoveViewAnimationCompleted();
-        }
-    }
-
-    public void onAddView(View v, final int index) {
-        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        final int[] pagesRange = new int[mTempVisiblePagesRange.length];
-        getVisiblePages(pagesRange);
-        boundByReorderablePages(true, pagesRange);
-        if (mCallbacks != null) {
-            mCallbacks.onAddView(v);
-        }
-        // Subtract from the index to take into account pages before the reorderable
-        // pages (e.g. the "add widget" page)
-        mBackgroundWorkerHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
-            }
-        });
-    }
-
-    /*
-     * We wrap widgets in a special frame which handles drawing the over scroll foreground.
-     */
-    public void addWidget(View widget, int pageIndex) {
-        KeyguardWidgetFrame frame;
-        // All views contained herein should be wrapped in a KeyguardWidgetFrame
-        if (!(widget instanceof KeyguardWidgetFrame)) {
-            frame = new KeyguardWidgetFrame(getContext());
-            FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
-                    LayoutParams.MATCH_PARENT);
-            lp.gravity = Gravity.TOP;
-
-            // The framework adds a default padding to AppWidgetHostView. We don't need this padding
-            // for the Keyguard, so we override it to be 0.
-            widget.setPadding(0,  0, 0, 0);
-            frame.addView(widget, lp);
-
-            // We set whether or not this widget supports vertical resizing.
-            if (widget instanceof AppWidgetHostView) {
-                AppWidgetHostView awhv = (AppWidgetHostView) widget;
-                AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
-                if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
-                    frame.setWidgetLockedSmall(false);
-                } else {
-                    // Lock the widget to be small.
-                    frame.setWidgetLockedSmall(true);
-                    if (mCenterSmallWidgetsVertically) {
-                        lp.gravity = Gravity.CENTER;
-                    }
-                }
-            }
-        } else {
-            frame = (KeyguardWidgetFrame) widget;
-        }
-
-        ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-        frame.setOnLongClickListener(this);
-        frame.setWorkerHandler(mBackgroundWorkerHandler);
-
-        if (pageIndex == -1) {
-            addView(frame, pageLp);
-        } else {
-            addView(frame, pageIndex, pageLp);
-        }
-
-        // Update the frame content description.
-        View content = (widget == frame) ?  frame.getContent() : widget;
-        if (content != null) {
-            String contentDescription = mContext.getString(
-                R.string.keyguard_accessibility_widget,
-                content.getContentDescription());
-            frame.setContentDescription(contentDescription);
-        }
-        updateWidgetFrameImportantForAccessibility(frame);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int index) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, index);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int width, int height) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, width, height);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, LayoutParams params) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, params);
-    }
-
-    /**
-     * Use addWidget() instead.
-     * @deprecated
-     */
-    @Override
-    public void addView(View child, int index, LayoutParams params) {
-        enforceKeyguardWidgetFrame(child);
-        super.addView(child, index, params);
-    }
-
-    private void enforceKeyguardWidgetFrame(View child) {
-        if (!(child instanceof KeyguardWidgetFrame)) {
-            throw new IllegalArgumentException(
-                    "KeyguardWidgetPager children must be KeyguardWidgetFrames");
-        }
-    }
-
-    public KeyguardWidgetFrame getWidgetPageAt(int index) {
-        // This is always a valid cast as we've guarded the ability to
-        return (KeyguardWidgetFrame) getChildAt(index);
-    }
-
-    protected void onUnhandledTap(MotionEvent ev) {
-        showPagingFeedback();
-    }
-
-    @Override
-    protected void onPageBeginMoving() {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageBeginMoving();
-        }
-        if (!isReordering(false)) {
-            showOutlinesAndSidePages();
-        }
-        userActivity();
-    }
-
-    @Override
-    protected void onPageEndMoving() {
-        if (mViewStateManager != null) {
-            mViewStateManager.onPageEndMoving();
-        }
-
-        // In the reordering case, the pages will be faded appropriately on completion
-        // of the zoom in animation.
-        if (!isReordering(false)) {
-            hideOutlinesAndSidePages();
-        }
-    }
-
-    protected void enablePageContentLayers() {
-        int children = getChildCount();
-        for (int i = 0; i < children; i++) {
-            getWidgetPageAt(i).enableHardwareLayersForContent();
-        }
-    }
-
-    protected void disablePageContentLayers() {
-        int children = getChildCount();
-        for (int i = 0; i < children; i++) {
-            getWidgetPageAt(i).disableHardwareLayersForContent();
-        }
-    }
-
-    /*
-     * This interpolator emulates the rate at which the perceived scale of an object changes
-     * as its distance from a camera increases. When this interpolator is applied to a scale
-     * animation on a view, it evokes the sense that the object is shrinking due to moving away
-     * from the camera.
-     */
-    static class ZInterpolator implements TimeInterpolator {
-        private float focalLength;
-
-        public ZInterpolator(float foc) {
-            focalLength = foc;
-        }
-
-        public float getInterpolation(float input) {
-            return (1.0f - focalLength / (focalLength + input)) /
-                (1.0f - focalLength / (focalLength + 1.0f));
-        }
-    }
-
-    @Override
-    protected void overScroll(float amount) {
-        acceleratedOverScroll(amount);
-    }
-
-    float backgroundAlphaInterpolator(float r) {
-        return Math.min(1f, r);
-    }
-
-    private void updatePageAlphaValues(int screenCenter) {
-    }
-
-    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        if (isWarping()) {
-            return index == getPageWarpIndex() ? 1.0f : 0.0f;
-        }
-        if (showSidePages) {
-            return 1f;
-        } else {
-            return index == mCurrentPage ? 1.0f : 0f;
-        }
-    }
-
-    public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
-        if (showSidePages) {
-            return getAlphaForPage(screenCenter, index, showSidePages)
-                    * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
-        } else {
-            return 0f;
-        }
-    }
-
-    protected boolean isOverScrollChild(int index, float scrollProgress) {
-        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
-        return (isInOverscroll && (index == 0 && scrollProgress < 0 ||
-                index == getChildCount() - 1 && scrollProgress > 0));
-    }
-
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        mScreenCenter = screenCenter;
-        updatePageAlphaValues(screenCenter);
-        for (int i = 0; i < getChildCount(); i++) {
-            KeyguardWidgetFrame v = getWidgetPageAt(i);
-            if (v == mDragView) continue;
-            if (v != null) {
-                float scrollProgress = getScrollProgress(screenCenter, v, i);
-
-                v.setCameraDistance(mDensity * CAMERA_DISTANCE);
-
-                if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) {
-                    float pivotX = v.getMeasuredWidth() / 2;
-                    float pivotY = v.getMeasuredHeight() / 2;
-                    v.setPivotX(pivotX);
-                    v.setPivotY(pivotY);
-                    v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
-                    v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
-                } else {
-                    v.setRotationY(0f);
-                    v.setOverScrollAmount(0, false);
-                }
-
-                float alpha = v.getAlpha();
-                // If the view has 0 alpha, we set it to be invisible so as to prevent
-                // it from accepting touches
-                if (alpha == 0) {
-                    v.setVisibility(INVISIBLE);
-                } else if (v.getVisibility() != VISIBLE) {
-                    v.setVisibility(VISIBLE);
-                }
-            }
-        }
-    }
-
-    public boolean isWidgetPage(int pageIndex) {
-        if (pageIndex < 0 || pageIndex >= getChildCount()) {
-            return false;
-        }
-        View v = getChildAt(pageIndex);
-        if (v != null && v instanceof KeyguardWidgetFrame) {
-            KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
-            return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
-        }
-        return false;
-    }
-
-    /**
-     * Returns the bounded set of pages that are re-orderable.  The range is fully inclusive.
-     */
-    @Override
-    void boundByReorderablePages(boolean isReordering, int[] range) {
-        if (isReordering) {
-            // Remove non-widget pages from the range
-            while (range[1] >= range[0] && !isWidgetPage(range[1])) {
-                range[1]--;
-            }
-            while (range[0] <= range[1] && !isWidgetPage(range[0])) {
-                range[0]++;
-            }
-        }
-    }
-
-    protected void reorderStarting() {
-        showOutlinesAndSidePages();
-    }
-
-    @Override
-    protected void onStartReordering() {
-        super.onStartReordering();
-        enablePageContentLayers();
-        reorderStarting();
-    }
-
-    @Override
-    protected void onEndReordering() {
-        super.onEndReordering();
-        hideOutlinesAndSidePages();
-    }
-
-    void showOutlinesAndSidePages() {
-        animateOutlinesAndSidePages(true);
-    }
-
-    void hideOutlinesAndSidePages() {
-        animateOutlinesAndSidePages(false);
-    }
-
-    void updateChildrenContentAlpha(float sidePageAlpha) {
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-            if (i != mCurrentPage) {
-                child.setBackgroundAlpha(sidePageAlpha);
-                child.setContentAlpha(0f);
-            } else {
-                child.setBackgroundAlpha(0f);
-                child.setContentAlpha(1f);
-            }
-        }
-    }
-
-    public void showInitialPageHints() {
-        mShowingInitialHints = true;
-        updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
-    }
-
-    @Override
-    void setCurrentPage(int currentPage) {
-        super.setCurrentPage(currentPage);
-        updateChildrenContentAlpha(0.0f);
-        updateWidgetFramesImportantForAccessibility();
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mHasMeasure = false;
-    }
-
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        mLastWidthMeasureSpec = widthMeasureSpec;
-        mLastHeightMeasureSpec = heightMeasureSpec;
-
-        int maxChallengeTop = -1;
-        View parent = (View) getParent();
-        boolean challengeShowing = false;
-        // Widget pages need to know where the top of the sliding challenge is so that they
-        // now how big the widget should be when the challenge is up. We compute it here and
-        // then propagate it to each of our children.
-        if (parent.getParent() instanceof SlidingChallengeLayout) {
-            SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent();
-            int top = scl.getMaxChallengeTop();
-
-            // This is a bit evil, but we need to map a coordinate relative to the SCL into a
-            // coordinate relative to our children, hence we subtract the top padding.s
-            maxChallengeTop = top - getPaddingTop();
-            challengeShowing = scl.isChallengeShowing();
-
-            int count = getChildCount();
-            for (int i = 0; i < count; i++) {
-                KeyguardWidgetFrame frame = getWidgetPageAt(i);
-                frame.setMaxChallengeTop(maxChallengeTop);
-                // On the very first measure pass, if the challenge is showing, we need to make sure
-                // that the widget on the current page is small.
-                if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
-                    frame.shrinkWidget(true);
-                }
-            }
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mHasMeasure = true;
-    }
-
-    void animateOutlinesAndSidePages(final boolean show) {
-        animateOutlinesAndSidePages(show, -1);
-    }
-
-    public void setWidgetToResetOnPageFadeOut(int widget) {
-        mWidgetToResetAfterFadeOut = widget;
-    }
-
-    public int getWidgetToResetOnPageFadeOut() {
-        return mWidgetToResetAfterFadeOut;
-    }
-
-    void animateOutlinesAndSidePages(final boolean show, int duration) {
-        if (mChildrenOutlineFadeAnimation != null) {
-            mChildrenOutlineFadeAnimation.cancel();
-            mChildrenOutlineFadeAnimation = null;
-        }
-        int count = getChildCount();
-        PropertyValuesHolder alpha;
-        ArrayList<Animator> anims = new ArrayList<Animator>();
-
-        if (duration == -1) {
-            duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
-                CHILDREN_OUTLINE_FADE_OUT_DURATION;
-        }
-
-        int curPage = getNextPage();
-        for (int i = 0; i < count; i++) {
-            float finalContentAlpha;
-            if (show) {
-                finalContentAlpha = getAlphaForPage(mScreenCenter, i, true);
-            } else if (!show && i == curPage) {
-                finalContentAlpha = 1f;
-            } else {
-                finalContentAlpha = 0f;
-            }
-            KeyguardWidgetFrame child = getWidgetPageAt(i);
-
-            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha);
-            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha);
-            anims.add(a);
-
-            float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f;
-            child.fadeFrame(this, show, finalOutlineAlpha, duration);
-        }
-
-        mChildrenOutlineFadeAnimation = new AnimatorSet();
-        mChildrenOutlineFadeAnimation.playTogether(anims);
-
-        mChildrenOutlineFadeAnimation.setDuration(duration);
-        mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (show) {
-                    enablePageContentLayers();
-                }
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!show) {
-                    disablePageContentLayers();
-                    KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut);
-                    if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) &&
-                            mViewStateManager.isChallengeOverlapping())) {
-                        frame.resetSize();
-                    }
-                    mWidgetToResetAfterFadeOut = -1;
-                    mShowingInitialHints = false;
-                }
-                updateWidgetFramesImportantForAccessibility();
-            }
-        });
-        mChildrenOutlineFadeAnimation.start();
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        // Disallow long pressing to reorder if the challenge is showing
-        boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
-                mViewStateManager.isChallengeOverlapping();
-        if (!isChallengeOverlapping && startReordering()) {
-            return true;
-        }
-        return false;
-    }
-
-    public void removeWidget(View view) {
-        if (view instanceof KeyguardWidgetFrame) {
-            removeView(view);
-        } else {
-            // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
-            // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
-            int pos = getWidgetPageIndex(view);
-            if (pos != -1) {
-                KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
-                frame.removeView(view);
-                removeView(frame);
-            } else {
-                Slog.w(TAG, "removeWidget() can't find:" + view);
-            }
-        }
-    }
-
-    public int getWidgetPageIndex(View view) {
-        if (view instanceof KeyguardWidgetFrame) {
-            return indexOfChild(view);
-        } else {
-            // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
-            return indexOfChild((KeyguardWidgetFrame)view.getParent());
-        }
-    }
-
-    @Override
-    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
-        KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
-        child.setIsHoveringOverDeleteDropTarget(isHovering);
-    }
-
-    // ChallengeLayout.OnBouncerStateChangedListener
-    @Override
-    public void onBouncerStateChanged(boolean bouncerActive) {
-        if (bouncerActive) {
-            zoomOutToBouncer();
-        } else {
-            zoomInFromBouncer();
-        }
-    }
-
-    void setBouncerAnimationDuration(int duration) {
-        mBouncerZoomInOutDuration = duration;
-    }
-
-    // Zoom in after the bouncer is dismissed
-    void zoomInFromBouncer() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        final View currentPage = getPageAt(getCurrentPage());
-        if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(currentPage, "scaleX", 1f),
-                    ObjectAnimator.ofFloat(currentPage , "scaleY", 1f));
-            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
-            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-            mZoomInOutAnim.start();
-        }
-        if (currentPage instanceof KeyguardWidgetFrame) {
-            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false);
-        }
-    }
-
-    // Zoom out after the bouncer is initiated
-    void zoomOutToBouncer() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        int curPage = getCurrentPage();
-        View currentPage = getPageAt(curPage);
-        if (shouldSetTopAlignedPivotForWidget(curPage)) {
-            currentPage.setPivotY(0);
-            // Note: we are working around the issue that setting the x-pivot to the same value as it
-            //       was does not actually work.
-            currentPage.setPivotX(0);
-            currentPage.setPivotX(currentPage.getMeasuredWidth() / 2);
-        }
-        if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR),
-                    ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR));
-            mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
-            mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-            mZoomInOutAnim.start();
-        }
-        if (currentPage instanceof KeyguardWidgetFrame) {
-            ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true);
-        }
-    }
-
-    void setAddWidgetEnabled(boolean enabled) {
-        if (mAddWidgetView != null && enabled) {
-            addView(mAddWidgetView, 0);
-            // We need to force measure the PagedView so that the calls to update the scroll
-            // position below work
-            measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);
-            // Bump up the current page to account for the addition of the new page
-            setCurrentPage(mCurrentPage + 1);
-            mAddWidgetView = null;
-        } else if (mAddWidgetView == null && !enabled) {
-            View addWidget = findViewById(R.id.keyguard_add_widget);
-            if (addWidget != null) {
-                mAddWidgetView = addWidget;
-                removeView(addWidget);
-            }
-        }
-    }
-
-    boolean isAddPage(int pageIndex) {
-        View v = getChildAt(pageIndex);
-        return v != null && v.getId() == R.id.keyguard_add_widget;
-    }
-
-    boolean isCameraPage(int pageIndex) {
-        View v = getChildAt(pageIndex);
-        return v != null && v instanceof CameraWidgetFrame;
-    }
-
-    @Override
-    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
-        return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex);
-    }
-
-    /**
-     * Search given {@link View} hierarchy for {@link TextClock} instances that
-     * show various time components. Returns combination of
-     * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}.
-     */
-    private static int findClockInHierarchy(View view) {
-        if (view instanceof TextClock) {
-            return getClockFlags((TextClock) view);
-        } else if (view instanceof ViewGroup) {
-            int flags = 0;
-            final ViewGroup group = (ViewGroup) view;
-            final int size = group.getChildCount();
-            for (int i = 0; i < size; i++) {
-                flags |= findClockInHierarchy(group.getChildAt(i));
-            }
-            return flags;
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and
-     * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described
-     * by the given {@link TextClock}.
-     */
-    private static int getClockFlags(TextClock clock) {
-        int flags = 0;
-
-        final String timeZone = clock.getTimeZone();
-        if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) {
-            // Ignore clocks showing another timezone
-            return 0;
-        }
-
-        final CharSequence format = clock.getFormat();
-        final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY
-                : DateFormat.HOUR;
-
-        if (DateFormat.hasDesignator(format, hour)) {
-            flags |= FLAG_HAS_LOCAL_HOUR;
-        }
-        if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) {
-            flags |= FLAG_HAS_LOCAL_MINUTE;
-        }
-
-        return flags;
-    }
-
-    public void handleExternalCameraEvent(MotionEvent event) {
-        beginCameraEvent();
-        int cameraPage = getPageCount() - 1;
-        boolean endWarp = false;
-        if (isCameraPage(cameraPage) || mCameraEventInProgress) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    // Once we start dispatching camera events, we must continue to do so
-                    // to keep event dispatch happy.
-                    mCameraEventInProgress = true;
-                    userActivity();
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    mCameraEventInProgress = false;
-                    break;
-            }
-            dispatchTouchEvent(event);
-        }
-        endCameraEvent();
-    }
-
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java
deleted file mode 100644
index 340a4d5..0000000
--- a/packages/Keyguard/src/com/android/keyguard/MultiPaneChallengeLayout.java
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-public class MultiPaneChallengeLayout extends ViewGroup implements ChallengeLayout {
-    private static final String TAG = "MultiPaneChallengeLayout";
-
-    final int mOrientation;
-    private boolean mIsBouncing;
-
-    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
-    public static final int VERTICAL = LinearLayout.VERTICAL;
-    public static final int ANIMATE_BOUNCE_DURATION = 350;
-
-    private KeyguardSecurityContainer mChallengeView;
-    private View mUserSwitcherView;
-    private View mScrimView;
-    private OnBouncerStateChangedListener mBouncerListener;
-
-    private final Rect mTempRect = new Rect();
-    private final Rect mZeroPadding = new Rect();
-    private final Rect mInsets = new Rect();
-
-    private final DisplayMetrics mDisplayMetrics;
-
-    private final OnClickListener mScrimClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            hideBouncer();
-        }
-    };
-
-    public MultiPaneChallengeLayout(Context context) {
-        this(context, null);
-    }
-
-    public MultiPaneChallengeLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        final TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
-        mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_android_orientation,
-                HORIZONTAL);
-        a.recycle();
-
-        final Resources res = getResources();
-        mDisplayMetrics = res.getDisplayMetrics();
-
-        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-    }
-
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-    }
-
-    @Override
-    public boolean isChallengeShowing() {
-        return true;
-    }
-
-    @Override
-    public boolean isChallengeOverlapping() {
-        return false;
-    }
-
-    @Override
-    public void showChallenge(boolean b) {
-    }
-
-    @Override
-    public int getBouncerAnimationDuration() {
-        return ANIMATE_BOUNCE_DURATION;
-    }
-
-    @Override
-    public void showBouncer() {
-        if (mIsBouncing) return;
-        mIsBouncing = true;
-        if (mScrimView != null) {
-            if (mChallengeView != null) {
-                mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION);
-            }
-
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
-            anim.setDuration(ANIMATE_BOUNCE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mScrimView.setVisibility(VISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(true);
-        }
-    }
-
-    @Override
-    public void hideBouncer() {
-        if (!mIsBouncing) return;
-        mIsBouncing = false;
-        if (mScrimView != null) {
-            if (mChallengeView != null) {
-                mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION);
-            }
-
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
-            anim.setDuration(ANIMATE_BOUNCE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mScrimView.setVisibility(INVISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(false);
-        }
-    }
-
-    @Override
-    public boolean isBouncing() {
-        return mIsBouncing;
-    }
-
-    @Override
-    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
-        mBouncerListener = listener;
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        if (mIsBouncing && child != mChallengeView) {
-            // Clear out of the bouncer if the user tries to move focus outside of
-            // the security challenge view.
-            hideBouncer();
-        }
-        super.requestChildFocus(child, focused);
-    }
-
-    void setScrimView(View scrim) {
-        if (mScrimView != null) {
-            mScrimView.setOnClickListener(null);
-        }
-        mScrimView = scrim;
-        if (mScrimView != null) {
-            mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
-            mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
-            mScrimView.setFocusable(true);
-            mScrimView.setOnClickListener(mScrimClickListener);
-        }
-    }
-
-    private int getVirtualHeight(LayoutParams lp, int height, int heightUsed) {
-        int virtualHeight = height;
-        final View root = getRootView();
-        if (root != null) {
-            // This calculation is super dodgy and relies on several assumptions.
-            // Specifically that the root of the window will be padded in for insets
-            // and that the window is LAYOUT_IN_SCREEN.
-            virtualHeight = mDisplayMetrics.heightPixels - root.getPaddingTop() - mInsets.top;
-        }
-        if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
-            // Always measure the user switcher as if there were no IME insets
-            // on the window.
-            return virtualHeight - heightUsed;
-        } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
-            return height;
-        }
-        return Math.min(virtualHeight - heightUsed, height);
-    }
-
-    @Override
-    protected void onMeasure(final int widthSpec, final int heightSpec) {
-        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
-                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
-            throw new IllegalArgumentException(
-                    "MultiPaneChallengeLayout must be measured with an exact size");
-        }
-
-        final int width = MeasureSpec.getSize(widthSpec);
-        final int height = MeasureSpec.getSize(heightSpec);
-        setMeasuredDimension(width, height);
-
-        final int insetHeight = height - mInsets.top - mInsets.bottom;
-        final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
-
-        int widthUsed = 0;
-        int heightUsed = 0;
-
-        // First pass. Find the challenge view and measure the user switcher,
-        // which consumes space in the layout.
-        mChallengeView = null;
-        mUserSwitcherView = null;
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                if (mChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child of type challenge");
-                }
-                if (!(child instanceof KeyguardSecurityContainer)) {
-                    throw new IllegalArgumentException(
-                            "Challenge must be a KeyguardSecurityContainer");
-                }
-                mChallengeView = (KeyguardSecurityContainer) child;
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
-                if (mUserSwitcherView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child of type userSwitcher");
-                }
-                mUserSwitcherView = child;
-
-                if (child.getVisibility() == GONE) continue;
-
-                int adjustedWidthSpec = widthSpec;
-                int adjustedHeightSpec = insetHeightSpec;
-                if (lp.maxWidth >= 0) {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxWidth, width), MeasureSpec.EXACTLY);
-                }
-                if (lp.maxHeight >= 0) {
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxHeight, insetHeight), MeasureSpec.EXACTLY);
-                }
-                // measureChildWithMargins will resolve layout direction for the LayoutParams
-                measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-
-                // Only subtract out space from one dimension. Favor vertical.
-                // Offset by 1.5x to add some balance along the other edge.
-                if (Gravity.isVertical(lp.gravity)) {
-                    heightUsed += child.getMeasuredHeight() * 1.5f;
-                } else if (Gravity.isHorizontal(lp.gravity)) {
-                    widthUsed += child.getMeasuredWidth() * 1.5f;
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                setScrimView(child);
-                child.measure(widthSpec, heightSpec);
-            }
-        }
-
-        // Second pass. Measure everything that's left.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER ||
-                    lp.childType == LayoutParams.CHILD_TYPE_SCRIM ||
-                    child.getVisibility() == GONE) {
-                // Don't need to measure GONE children, and the user switcher was already measured.
-                continue;
-            }
-
-            final int virtualHeight = getVirtualHeight(lp, insetHeight, heightUsed);
-
-            int adjustedWidthSpec;
-            int adjustedHeightSpec;
-            if (lp.centerWithinArea > 0) {
-                if (mOrientation == HORIZONTAL) {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            (int) ((width - widthUsed) * lp.centerWithinArea + 0.5f),
-                            MeasureSpec.EXACTLY);
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            virtualHeight, MeasureSpec.EXACTLY);
-                } else {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            width - widthUsed, MeasureSpec.EXACTLY);
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            (int) (virtualHeight * lp.centerWithinArea + 0.5f),
-                            MeasureSpec.EXACTLY);
-                }
-            } else {
-                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                        width - widthUsed, MeasureSpec.EXACTLY);
-                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                        virtualHeight, MeasureSpec.EXACTLY);
-            }
-            if (lp.maxWidth >= 0) {
-                adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(lp.maxWidth, MeasureSpec.getSize(adjustedWidthSpec)),
-                        MeasureSpec.EXACTLY);
-            }
-            if (lp.maxHeight >= 0) {
-                adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(lp.maxHeight, MeasureSpec.getSize(adjustedHeightSpec)),
-                        MeasureSpec.EXACTLY);
-            }
-
-            measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final Rect padding = mTempRect;
-        padding.left = getPaddingLeft();
-        padding.top = getPaddingTop();
-        padding.right = getPaddingRight();
-        padding.bottom = getPaddingBottom();
-        final int width = r - l;
-        final int height = b - t;
-        final int insetHeight = height - mInsets.top - mInsets.bottom;
-
-        // Reserve extra space in layout for the user switcher by modifying
-        // local padding during this layout pass
-        if (mUserSwitcherView != null && mUserSwitcherView.getVisibility() != GONE) {
-            layoutWithGravity(width, insetHeight, mUserSwitcherView, padding, true);
-        }
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            // We did the user switcher above if we have one.
-            if (child == mUserSwitcherView || child.getVisibility() == GONE) continue;
-
-            if (child == mScrimView) {
-                child.layout(0, 0, width, height);
-                continue;
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_PAGE_DELETE_DROP_TARGET) {
-                layoutWithGravity(width, insetHeight, child, mZeroPadding, false);
-                continue;
-            }
-
-            layoutWithGravity(width, insetHeight, child, padding, false);
-        }
-    }
-
-    private void layoutWithGravity(int width, int height, View child, Rect padding,
-            boolean adjustPadding) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-        final int heightUsed = padding.top + padding.bottom - getPaddingTop() - getPaddingBottom();
-        height = getVirtualHeight(lp, height, heightUsed);
-
-        final int gravity = Gravity.getAbsoluteGravity(lp.gravity, getLayoutDirection());
-
-        final boolean fixedLayoutSize = lp.centerWithinArea > 0;
-        final boolean fixedLayoutHorizontal = fixedLayoutSize && mOrientation == HORIZONTAL;
-        final boolean fixedLayoutVertical = fixedLayoutSize && mOrientation == VERTICAL;
-
-        final int adjustedWidth;
-        final int adjustedHeight;
-        if (fixedLayoutHorizontal) {
-            final int paddedWidth = width - padding.left - padding.right;
-            adjustedWidth = (int) (paddedWidth * lp.centerWithinArea + 0.5f);
-            adjustedHeight = height;
-        } else if (fixedLayoutVertical) {
-            final int paddedHeight = height - getPaddingTop() - getPaddingBottom();
-            adjustedWidth = width;
-            adjustedHeight = (int) (paddedHeight * lp.centerWithinArea + 0.5f);
-        } else {
-            adjustedWidth = width;
-            adjustedHeight = height;
-        }
-
-        final boolean isVertical = Gravity.isVertical(gravity);
-        final boolean isHorizontal = Gravity.isHorizontal(gravity);
-        final int childWidth = child.getMeasuredWidth();
-        final int childHeight = child.getMeasuredHeight();
-
-        int left = padding.left;
-        int top = padding.top;
-        int right = left + childWidth;
-        int bottom = top + childHeight;
-        switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.TOP:
-                top = fixedLayoutVertical ?
-                        padding.top + (adjustedHeight - childHeight) / 2 : padding.top;
-                bottom = top + childHeight;
-                if (adjustPadding && isVertical) {
-                    padding.top = bottom;
-                    padding.bottom += childHeight / 2;
-                }
-                break;
-            case Gravity.BOTTOM:
-                bottom = fixedLayoutVertical
-                        ? padding.top + height - (adjustedHeight - childHeight) / 2
-                        : padding.top + height;
-                top = bottom - childHeight;
-                if (adjustPadding && isVertical) {
-                    padding.bottom = height - top;
-                    padding.top += childHeight / 2;
-                }
-                break;
-            case Gravity.CENTER_VERTICAL:
-                top = padding.top + (height - childHeight) / 2;
-                bottom = top + childHeight;
-                break;
-        }
-        switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.LEFT:
-                left = fixedLayoutHorizontal ?
-                        padding.left + (adjustedWidth - childWidth) / 2 : padding.left;
-                right = left + childWidth;
-                if (adjustPadding && isHorizontal && !isVertical) {
-                    padding.left = right;
-                    padding.right += childWidth / 2;
-                }
-                break;
-            case Gravity.RIGHT:
-                right = fixedLayoutHorizontal
-                        ? width - padding.right - (adjustedWidth - childWidth) / 2
-                        : width - padding.right;
-                left = right - childWidth;
-                if (adjustPadding && isHorizontal && !isVertical) {
-                    padding.right = width - left;
-                    padding.left += childWidth / 2;
-                }
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-                final int paddedWidth = width - padding.left - padding.right;
-                left = (paddedWidth - childWidth) / 2;
-                right = left + childWidth;
-                break;
-        }
-        top += mInsets.top;
-        bottom += mInsets.top;
-        child.layout(left, top, right, bottom);
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs, this);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
-                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
-                new LayoutParams(p);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    public static class LayoutParams extends MarginLayoutParams {
-
-        public float centerWithinArea = 0;
-
-        public int childType = 0;
-
-        public static final int CHILD_TYPE_NONE = 0;
-        public static final int CHILD_TYPE_WIDGET = 1;
-        public static final int CHILD_TYPE_CHALLENGE = 2;
-        public static final int CHILD_TYPE_USER_SWITCHER = 3;
-        public static final int CHILD_TYPE_SCRIM = 4;
-        public static final int CHILD_TYPE_PAGE_DELETE_DROP_TARGET = 7;
-
-        public int gravity = Gravity.NO_GRAVITY;
-
-        public int maxWidth = -1;
-        public int maxHeight = -1;
-
-        public LayoutParams() {
-            this(WRAP_CONTENT, WRAP_CONTENT);
-        }
-
-        LayoutParams(Context c, AttributeSet attrs, MultiPaneChallengeLayout parent) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.MultiPaneChallengeLayout_Layout);
-
-            centerWithinArea = a.getFloat(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_centerWithinArea, 0);
-            childType = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_childType,
-                    CHILD_TYPE_NONE);
-            gravity = a.getInt(R.styleable.MultiPaneChallengeLayout_Layout_layout_gravity,
-                    Gravity.NO_GRAVITY);
-            maxWidth = a.getDimensionPixelSize(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxWidth, -1);
-            maxHeight = a.getDimensionPixelSize(
-                    R.styleable.MultiPaneChallengeLayout_Layout_layout_maxHeight, -1);
-
-            // Default gravity settings based on type and parent orientation
-            if (gravity == Gravity.NO_GRAVITY) {
-                if (parent.mOrientation == HORIZONTAL) {
-                    switch (childType) {
-                        case CHILD_TYPE_WIDGET:
-                            gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
-                            break;
-                        case CHILD_TYPE_CHALLENGE:
-                            gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
-                            break;
-                        case CHILD_TYPE_USER_SWITCHER:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                    }
-                } else {
-                    switch (childType) {
-                        case CHILD_TYPE_WIDGET:
-                            gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
-                            break;
-                        case CHILD_TYPE_CHALLENGE:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                        case CHILD_TYPE_USER_SWITCHER:
-                            gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-                            break;
-                    }
-                }
-            }
-
-            a.recycle();
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(LayoutParams source) {
-            this((MarginLayoutParams) source);
-
-            centerWithinArea = source.centerWithinArea;
-            childType = source.childType;
-            gravity = source.gravity;
-            maxWidth = source.maxWidth;
-            maxHeight = source.maxHeight;
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java b/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
deleted file mode 100644
index 7128211..0000000
--- a/packages/Keyguard/src/com/android/keyguard/MultiUserAvatarCache.java
+++ /dev/null
@@ -1,51 +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.keyguard;
-
-import android.graphics.drawable.Drawable;
-
-import java.util.HashMap;
-
-public class MultiUserAvatarCache {
-
-    private static MultiUserAvatarCache sInstance;
-
-    private final HashMap<Integer, Drawable> mCache;
-
-    private MultiUserAvatarCache() {
-        mCache = new HashMap<Integer, Drawable>();
-    }
-
-    public static MultiUserAvatarCache getInstance() {
-        if (sInstance == null) {
-            sInstance = new MultiUserAvatarCache();
-        }
-        return sInstance;
-    }
-
-    public void clear(int userId) {
-        mCache.remove(userId);
-    }
-
-    public Drawable get(int userId) {
-        return mCache.get(userId);
-    }
-
-    public void put(int userId, Drawable image) {
-        mCache.put(userId, image);
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
index 681db80..ef8bb0b 100644
--- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -18,17 +18,13 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.os.Debug;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.TextView;
 
 import com.android.internal.widget.LockPatternUtils;
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
deleted file mode 100644
index b42a085..0000000
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ /dev/null
@@ -1,2845 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.*;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.Scroller;
-
-import java.util.ArrayList;
-
-/**
- * An abstraction of the original Workspace which supports browsing through a
- * sequential list of "pages"
- */
-public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
-    private static final int WARP_SNAP_DURATION = 160;
-    private static final String TAG = "WidgetPagedView";
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final boolean DEBUG_WARP = false;
-    protected static final int INVALID_PAGE = -1;
-    private static final int WARP_PEEK_ANIMATION_DURATION = 150;
-    private static final float WARP_ANIMATE_AMOUNT = -75.0f; // in dip
-
-    // the min drag distance for a fling to register, to prevent random page shifts
-    private static final int MIN_LENGTH_FOR_FLING = 25;
-
-    protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
-    protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
-    protected static final float NANOTIME_DIV = 1000000000.0f;
-
-    private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
-    private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
-
-    private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
-    // The page is moved more than halfway, automatically move to the next page on touch up.
-    private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.5f;
-
-    // The following constants need to be scaled based on density. The scaled versions will be
-    // assigned to the corresponding member variables below.
-    private static final int FLING_THRESHOLD_VELOCITY = 1500;
-    private static final int MIN_SNAP_VELOCITY = 1500;
-    private static final int MIN_FLING_VELOCITY = 500;
-
-    // We are disabling touch interaction of the widget region for factory ROM.
-    private static final boolean DISABLE_TOUCH_INTERACTION = false;
-    private static final boolean DISABLE_TOUCH_SIDE_PAGES = true;
-    private static final boolean DISABLE_FLING_TO_DELETE = false;
-
-    static final int AUTOMATIC_PAGE_SPACING = -1;
-
-    protected int mFlingThresholdVelocity;
-    protected int mMinFlingVelocity;
-    protected int mMinSnapVelocity;
-
-    protected float mDensity;
-    protected float mSmoothingTime;
-    protected float mTouchX;
-
-    protected boolean mFirstLayout = true;
-
-    protected int mCurrentPage;
-    protected int mChildCountOnLastMeasure;
-
-    protected int mNextPage = INVALID_PAGE;
-    protected int mMaxScrollX;
-    protected Scroller mScroller;
-    private VelocityTracker mVelocityTracker;
-
-    private float mParentDownMotionX;
-    private float mParentDownMotionY;
-    private float mDownMotionX;
-    private float mDownMotionY;
-    private float mDownScrollX;
-    protected float mLastMotionX;
-    protected float mLastMotionXRemainder;
-    protected float mLastMotionY;
-    protected float mTotalMotionX;
-    private int mLastScreenCenter = -1;
-    private int[] mChildOffsets;
-    private int[] mChildRelativeOffsets;
-    private int[] mChildOffsetsWithLayoutScale;
-    private String mDeleteString; // Accessibility announcement when widget is deleted
-
-    protected final static int TOUCH_STATE_REST = 0;
-    protected final static int TOUCH_STATE_SCROLLING = 1;
-    protected final static int TOUCH_STATE_PREV_PAGE = 2;
-    protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-    protected final static int TOUCH_STATE_REORDERING = 4;
-    protected final static int TOUCH_STATE_READY = 5; // when finger is down
-
-    protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
-    protected final static float TOUCH_SLOP_SCALE = 1.0f;
-
-    protected int mTouchState = TOUCH_STATE_REST;
-    protected boolean mForceScreenScrolled = false;
-
-    protected OnLongClickListener mLongClickListener;
-
-    protected int mTouchSlop;
-    private int mPagingTouchSlop;
-    private int mMaximumVelocity;
-    private int mMinimumWidth;
-    protected int mPageSpacing;
-    protected int mCellCountX = 0;
-    protected int mCellCountY = 0;
-    protected boolean mAllowOverScroll = true;
-    protected int mUnboundedScrollX;
-    protected int[] mTempVisiblePagesRange = new int[2];
-    protected boolean mForceDrawAllChildrenNextFrame;
-
-    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
-    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
-    // the screens from continuing to translate beyond the normal bounds.
-    protected int mOverScrollX;
-
-    // parameter that adjusts the layout to be optimized for pages with that scale factor
-    protected float mLayoutScale = 1.0f;
-
-    protected static final int INVALID_POINTER = -1;
-
-    protected int mActivePointerId = INVALID_POINTER;
-
-    private PageSwitchListener mPageSwitchListener;
-
-    protected ArrayList<Boolean> mDirtyPageContent;
-
-    // If true, syncPages and syncPageItems will be called to refresh pages
-    protected boolean mContentIsRefreshable = true;
-
-    // If true, modify alpha of neighboring pages as user scrolls left/right
-    protected boolean mFadeInAdjacentScreens = false;
-
-    // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
-    // to switch to a new page
-    protected boolean mUsePagingTouchSlop = true;
-
-    // If true, the subclass should directly update scrollX itself in its computeScroll method
-    // (SmoothPagedView does this)
-    protected boolean mDeferScrollUpdate = false;
-
-    protected boolean mIsPageMoving = false;
-
-    // All syncs and layout passes are deferred until data is ready.
-    protected boolean mIsDataReady = true;
-
-    // Scrolling indicator
-    private ValueAnimator mScrollIndicatorAnimator;
-    private View mScrollIndicator;
-    private int mScrollIndicatorPaddingLeft;
-    private int mScrollIndicatorPaddingRight;
-    private boolean mShouldShowScrollIndicator = false;
-    private boolean mShouldShowScrollIndicatorImmediately = false;
-    protected static final int sScrollIndicatorFadeInDuration = 150;
-    protected static final int sScrollIndicatorFadeOutDuration = 650;
-    protected static final int sScrollIndicatorFlashDuration = 650;
-
-    // The viewport whether the pages are to be contained (the actual view may be larger than the
-    // viewport)
-    private Rect mViewport = new Rect();
-
-    // Reordering
-    // We use the min scale to determine how much to expand the actually PagedView measured
-    // dimensions such that when we are zoomed out, the view is not clipped
-    private int REORDERING_DROP_REPOSITION_DURATION = 200;
-    protected int REORDERING_REORDER_REPOSITION_DURATION = 300;
-    protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
-    private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300;
-    private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
-    private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
-    private float mMinScale = 1f;
-    protected View mDragView;
-    protected AnimatorSet mZoomInOutAnim;
-    private Runnable mSidePageHoverRunnable;
-    private int mSidePageHoverIndex = -1;
-    // This variable's scope is only for the duration of startReordering() and endReordering()
-    private boolean mReorderingStarted = false;
-    // This variable's scope is for the duration of startReordering() and after the zoomIn()
-    // animation after endReordering()
-    private boolean mIsReordering;
-    // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition
-    private int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2;
-    private int mPostReorderingPreZoomInRemainingAnimationCount;
-    private Runnable mPostReorderingPreZoomInRunnable;
-
-    // Edge swiping
-    private boolean mOnlyAllowEdgeSwipes = false;
-    private boolean mDownEventOnEdge = false;
-    private int mEdgeSwipeRegionSize = 0;
-
-    // Convenience/caching
-    private Matrix mTmpInvMatrix = new Matrix();
-    private float[] mTmpPoint = new float[2];
-    private Rect mTmpRect = new Rect();
-    private Rect mAltTmpRect = new Rect();
-
-    // Fling to delete
-    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
-    private float FLING_TO_DELETE_FRICTION = 0.035f;
-    // The degrees specifies how much deviation from the up vector to still consider a fling "up"
-    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
-    protected int mFlingToDeleteThresholdVelocity = -1400;
-    // Drag to delete
-    private boolean mDeferringForDelete = false;
-    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
-    private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
-
-    // Drop to delete
-    private View mDeleteDropTarget;
-
-    // Bouncer
-    private boolean mTopAlignPageWhenShrinkingForBouncer = false;
-
-    // Page warping
-    private int mPageSwapIndex = -1; // the page we swapped out if needed
-    private int mPageWarpIndex = -1; // the page we intend to warp
-
-    private boolean mWarpPageExposed;
-    private ViewPropertyAnimator mWarpAnimation;
-
-    private boolean mIsCameraEvent;
-    private float mWarpPeekAmount;
-    private boolean mOnPageEndWarpCalled;
-    private boolean mOnPageBeginWarpCalled;
-
-    public interface PageSwitchListener {
-        void onPageSwitching(View newPage, int newPageIndex);
-        void onPageSwitched(View newPage, int newPageIndex);
-    }
-
-    public PagedView(Context context) {
-        this(context, null);
-    }
-
-    public PagedView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.PagedView, defStyle, 0);
-        setPageSpacing(a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0));
-        mScrollIndicatorPaddingLeft =
-            a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingLeft, 0);
-        mScrollIndicatorPaddingRight =
-                a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
-        a.recycle();
-
-        Resources r = getResources();
-        mEdgeSwipeRegionSize = r.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
-        mTopAlignPageWhenShrinkingForBouncer =
-                r.getBoolean(R.bool.kg_top_align_page_shrink_on_bouncer_visible);
-
-        setHapticFeedbackEnabled(false);
-        init();
-    }
-
-    /**
-     * Initializes various states for this workspace.
-     */
-    protected void init() {
-        mDirtyPageContent = new ArrayList<Boolean>();
-        mDirtyPageContent.ensureCapacity(32);
-        mScroller = new Scroller(getContext(), new ScrollInterpolator());
-        mCurrentPage = 0;
-
-        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
-        mTouchSlop = configuration.getScaledTouchSlop();
-        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
-        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mDensity = getResources().getDisplayMetrics().density;
-        mWarpPeekAmount = mDensity * WARP_ANIMATE_AMOUNT;
-
-        // Scale the fling-to-delete threshold by the density
-        mFlingToDeleteThresholdVelocity = (int) (mFlingToDeleteThresholdVelocity * mDensity);
-
-        mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
-        mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
-        mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
-        setOnHierarchyChangeListener(this);
-    }
-
-    void setDeleteDropTarget(View v) {
-        mDeleteDropTarget = v;
-    }
-
-    // Convenience methods to map points from self to parent and vice versa
-    float[] mapPointFromViewToParent(View v, float x, float y) {
-        mTmpPoint[0] = x;
-        mTmpPoint[1] = y;
-        v.getMatrix().mapPoints(mTmpPoint);
-        mTmpPoint[0] += v.getLeft();
-        mTmpPoint[1] += v.getTop();
-        return mTmpPoint;
-    }
-    float[] mapPointFromParentToView(View v, float x, float y) {
-        mTmpPoint[0] = x - v.getLeft();
-        mTmpPoint[1] = y - v.getTop();
-        v.getMatrix().invert(mTmpInvMatrix);
-        mTmpInvMatrix.mapPoints(mTmpPoint);
-        return mTmpPoint;
-    }
-
-    void updateDragViewTranslationDuringDrag() {
-        float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX;
-        float y = mLastMotionY - mDownMotionY;
-        mDragView.setTranslationX(x);
-        mDragView.setTranslationY(y);
-
-        if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y);
-    }
-
-    public void setMinScale(float f) {
-        mMinScale = f;
-        requestLayout();
-    }
-
-    @Override
-    public void setScaleX(float scaleX) {
-        super.setScaleX(scaleX);
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
-        }
-    }
-
-    // Convenience methods to get the actual width/height of the PagedView (since it is measured
-    // to be larger to account for the minimum possible scale)
-    int getViewportWidth() {
-        return mViewport.width();
-    }
-    int getViewportHeight() {
-        return mViewport.height();
-    }
-
-    // Convenience methods to get the offset ASSUMING that we are centering the pages in the
-    // PagedView both horizontally and vertically
-    int getViewportOffsetX() {
-        return (getMeasuredWidth() - getViewportWidth()) / 2;
-    }
-    int getViewportOffsetY() {
-        return (getMeasuredHeight() - getViewportHeight()) / 2;
-    }
-
-    public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
-        mPageSwitchListener = pageSwitchListener;
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
-        }
-    }
-
-    /**
-     * Called by subclasses to mark that data is ready, and that we can begin loading and laying
-     * out pages.
-     */
-    protected void setDataIsReady() {
-        mIsDataReady = true;
-    }
-
-    protected boolean isDataReady() {
-        return mIsDataReady;
-    }
-
-    /**
-     * Returns the index of the currently displayed page.
-     *
-     * @return The index of the currently displayed page.
-     */
-    int getCurrentPage() {
-        return mCurrentPage;
-    }
-
-    int getNextPage() {
-        return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-    }
-
-    int getPageCount() {
-        return getChildCount();
-    }
-
-    View getPageAt(int index) {
-        return getChildAt(index);
-    }
-
-    protected int indexToPage(int index) {
-        return index;
-    }
-
-    /**
-     * Updates the scroll of the current page immediately to its final scroll position.  We use this
-     * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
-     * the previous tab page.
-     */
-    protected void updateCurrentPageScroll() {
-        int offset = getChildOffset(mCurrentPage);
-        int relOffset = getRelativeChildOffset(mCurrentPage);
-        int newX = offset - relOffset;
-        scrollTo(newX, 0);
-        mScroller.setFinalX(newX);
-        mScroller.forceFinished(true);
-    }
-
-    /**
-     * Sets the current page.
-     */
-    void setCurrentPage(int currentPage) {
-        notifyPageSwitching(currentPage);
-        if (!mScroller.isFinished()) {
-            mScroller.abortAnimation();
-        }
-        // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
-        // the default
-        if (getChildCount() == 0) {
-            return;
-        }
-
-        mForceScreenScrolled = true;
-        mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
-        updateCurrentPageScroll();
-        updateScrollingIndicator();
-        notifyPageSwitched();
-        invalidate();
-    }
-
-    public void setOnlyAllowEdgeSwipes(boolean enable) {
-        mOnlyAllowEdgeSwipes = enable;
-    }
-
-    protected void notifyPageSwitching(int whichPage) {
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
-        }
-    }
-
-    protected void notifyPageSwitched() {
-        if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
-        }
-    }
-
-    protected void pageBeginMoving() {
-        if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
-        if (!mIsPageMoving) {
-            mIsPageMoving = true;
-            if (isWarping()) {
-                dispatchOnPageBeginWarp();
-            }
-            onPageBeginMoving();
-        }
-    }
-
-    private void dispatchOnPageBeginWarp() {
-        if (!mOnPageBeginWarpCalled) {
-            onPageBeginWarp();
-            mOnPageBeginWarpCalled = true;
-        }
-        mOnPageEndWarpCalled = false;
-    }
-
-    private void dispatchOnPageEndWarp() {
-        if (!mOnPageEndWarpCalled) {
-            onPageEndWarp();
-            mOnPageEndWarpCalled = true;
-        }
-        mOnPageBeginWarpCalled = false;
-    }
-
-    protected void pageEndMoving() {
-        if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
-        if (mIsPageMoving) {
-            mIsPageMoving = false;
-            if (isWarping()) {
-                dispatchOnPageEndWarp();
-                mWarpPageExposed = false;
-            }
-            onPageEndMoving();
-        }
-    }
-
-    protected boolean isPageMoving() {
-        return mIsPageMoving;
-    }
-
-    // a method that subclasses can override to add behavior
-    protected void onPageBeginMoving() {
-    }
-
-    // a method that subclasses can override to add behavior
-    protected void onPageEndMoving() {
-    }
-
-    /**
-     * Registers the specified listener on each page contained in this workspace.
-     *
-     * @param l The listener used to respond to long clicks.
-     */
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        mLongClickListener = l;
-        final int count = getPageCount();
-        for (int i = 0; i < count; i++) {
-            getPageAt(i).setOnLongClickListener(l);
-        }
-    }
-
-    @Override
-    public void scrollBy(int x, int y) {
-        scrollTo(mUnboundedScrollX + x, getScrollY() + y);
-    }
-
-    @Override
-    public void scrollTo(int x, int y) {
-        mUnboundedScrollX = x;
-
-        if (x < 0) {
-            super.scrollTo(0, y);
-            if (mAllowOverScroll) {
-                overScroll(x);
-            }
-        } else if (x > mMaxScrollX) {
-            super.scrollTo(mMaxScrollX, y);
-            if (mAllowOverScroll) {
-                overScroll(x - mMaxScrollX);
-            }
-        } else {
-            mOverScrollX = x;
-            super.scrollTo(x, y);
-        }
-
-        mTouchX = x;
-        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-
-        // Update the last motion events when scrolling
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
-        }
-    }
-
-    // we moved this functionality to a helper function so SmoothPagedView can reuse it
-    protected boolean computeScrollHelper() {
-        if (mScroller.computeScrollOffset()) {
-            // Don't bother scrolling if the page does not need to be moved
-            if (getScrollX() != mScroller.getCurrX()
-                || getScrollY() != mScroller.getCurrY()
-                || mOverScrollX != mScroller.getCurrX()) {
-                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
-            }
-            invalidate();
-            return true;
-        } else if (mNextPage != INVALID_PAGE) {
-            mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
-            mNextPage = INVALID_PAGE;
-            notifyPageSwitched();
-
-            // We don't want to trigger a page end moving unless the page has settled
-            // and the user has stopped scrolling
-            if (mTouchState == TOUCH_STATE_REST) {
-                pageEndMoving();
-            }
-
-            onPostReorderingAnimationCompleted();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void computeScroll() {
-        computeScrollHelper();
-    }
-
-    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
-        return mTopAlignPageWhenShrinkingForBouncer;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (!mIsDataReady || getChildCount() == 0) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        // We measure the dimensions of the PagedView to be larger than the pages so that when we
-        // zoom out (and scale down), the view is still contained in the parent
-        View parent = (View) getParent();
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-        // NOTE: We multiply by 1.5f to account for the fact that depending on the offset of the
-        // viewport, we can be at most one and a half screens offset once we scale down
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int maxSize = Math.max(dm.widthPixels, dm.heightPixels);
-        int parentWidthSize = (int) (1.5f * maxSize);
-        int parentHeightSize = maxSize;
-        int scaledWidthSize = (int) (parentWidthSize / mMinScale);
-        int scaledHeightSize = (int) (parentHeightSize / mMinScale);
-        mViewport.set(0, 0, widthSize, heightSize);
-
-        if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        // Return early if we aren't given a proper dimension
-        if (widthSize <= 0 || heightSize <= 0) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
-        /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
-         * of the All apps view on XLarge displays to not take up more space then it needs. Width
-         * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
-         * each page to have the same width.
-         */
-        final int verticalPadding = getPaddingTop() + getPaddingBottom();
-        final int horizontalPadding = getPaddingLeft() + getPaddingRight();
-
-        // The children are given the same width and height as the workspace
-        // unless they were set to WRAP_CONTENT
-        if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.scaledSize: " + scaledWidthSize + ", " + scaledHeightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.parentSize: " + parentWidthSize + ", " + parentHeightSize);
-        if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding);
-        if (DEBUG) Log.d(TAG, "PagedView.verticalPadding: " + verticalPadding);
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            // disallowing padding in paged view (just pass 0)
-            final View child = getPageAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            int childWidthMode;
-            if (lp.width == LayoutParams.WRAP_CONTENT) {
-                childWidthMode = MeasureSpec.AT_MOST;
-            } else {
-                childWidthMode = MeasureSpec.EXACTLY;
-            }
-
-            int childHeightMode;
-            if (lp.height == LayoutParams.WRAP_CONTENT) {
-                childHeightMode = MeasureSpec.AT_MOST;
-            } else {
-                childHeightMode = MeasureSpec.EXACTLY;
-            }
-
-            final int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
-            final int childHeightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
-
-            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-        }
-        setMeasuredDimension(scaledWidthSize, scaledHeightSize);
-
-        // We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
-        // We also wait until we set the measured dimensions before flushing the cache as well, to
-        // ensure that the cache is filled with good values.
-        invalidateCachedOffsets();
-
-        if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
-            setCurrentPage(mCurrentPage);
-        }
-        mChildCountOnLastMeasure = getChildCount();
-
-        if (childCount > 0) {
-            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getViewportWidth() + ", "
-                    + getChildWidth(0));
-
-            // Calculate the variable page spacing if necessary
-            if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
-                // The gap between pages in the PagedView should be equal to the gap from the page
-                // to the edge of the screen (so it is not visible in the current screen).  To
-                // account for unequal padding on each side of the paged view, we take the maximum
-                // of the left/right gap and use that as the gap between each page.
-                int offset = getRelativeChildOffset(0);
-                int spacing = Math.max(offset, widthSize - offset -
-                        getChildAt(0).getMeasuredWidth());
-                setPageSpacing(spacing);
-            }
-        }
-
-        updateScrollingIndicatorPosition();
-
-        if (childCount > 0) {
-            mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
-        } else {
-            mMaxScrollX = 0;
-        }
-    }
-
-    public void setPageSpacing(int pageSpacing) {
-        mPageSpacing = pageSpacing;
-        invalidateCachedOffsets();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (!mIsDataReady || getChildCount() == 0) {
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
-        final int childCount = getChildCount();
-
-        int offsetX = getViewportOffsetX();
-        int offsetY = getViewportOffsetY();
-
-        // Update the viewport offsets
-        mViewport.offset(offsetX,  offsetY);
-
-        int childLeft = offsetX + getRelativeChildOffset(0);
-        for (int i = 0; i < childCount; i++) {
-            final View child = getPageAt(i);
-            int childTop = offsetY + getPaddingTop();
-            if (child.getVisibility() != View.GONE) {
-                final int childWidth = getScaledMeasuredWidth(child);
-                final int childHeight = child.getMeasuredHeight();
-
-                if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
-                child.layout(childLeft, childTop,
-                        childLeft + child.getMeasuredWidth(), childTop + childHeight);
-                childLeft += childWidth + mPageSpacing;
-            }
-        }
-
-        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
-            setHorizontalScrollBarEnabled(false);
-            updateCurrentPageScroll();
-            setHorizontalScrollBarEnabled(true);
-            mFirstLayout = false;
-        }
-    }
-
-    protected void screenScrolled(int screenCenter) {
-    }
-
-    @Override
-    public void onChildViewAdded(View parent, View child) {
-        // This ensures that when children are added, they get the correct transforms / alphas
-        // in accordance with any scroll effects.
-        mForceScreenScrolled = true;
-        invalidate();
-        invalidateCachedOffsets();
-    }
-
-    @Override
-    public void onChildViewRemoved(View parent, View child) {
-        mForceScreenScrolled = true;
-        invalidate();
-        invalidateCachedOffsets();
-    }
-
-    protected void invalidateCachedOffsets() {
-        int count = getChildCount();
-        if (count == 0) {
-            mChildOffsets = null;
-            mChildRelativeOffsets = null;
-            mChildOffsetsWithLayoutScale = null;
-            return;
-        }
-
-        mChildOffsets = new int[count];
-        mChildRelativeOffsets = new int[count];
-        mChildOffsetsWithLayoutScale = new int[count];
-        for (int i = 0; i < count; i++) {
-            mChildOffsets[i] = -1;
-            mChildRelativeOffsets[i] = -1;
-            mChildOffsetsWithLayoutScale[i] = -1;
-        }
-    }
-
-    protected int getChildOffset(int index) {
-        if (index < 0 || index > getChildCount() - 1) return 0;
-
-        int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
-                mChildOffsets : mChildOffsetsWithLayoutScale;
-
-        if (childOffsets != null && childOffsets[index] != -1) {
-            return childOffsets[index];
-        } else {
-            if (getChildCount() == 0)
-                return 0;
-
-            int offset = getRelativeChildOffset(0);
-            for (int i = 0; i < index; ++i) {
-                offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
-            }
-            if (childOffsets != null) {
-                childOffsets[index] = offset;
-            }
-            return offset;
-        }
-    }
-
-    protected int getRelativeChildOffset(int index) {
-        if (index < 0 || index > getChildCount() - 1) return 0;
-
-        if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
-            return mChildRelativeOffsets[index];
-        } else {
-            final int padding = getPaddingLeft() + getPaddingRight();
-            final int offset = getPaddingLeft() +
-                    (getViewportWidth() - padding - getChildWidth(index)) / 2;
-            if (mChildRelativeOffsets != null) {
-                mChildRelativeOffsets[index] = offset;
-            }
-            return offset;
-        }
-    }
-
-    protected int getScaledMeasuredWidth(View child) {
-        // This functions are called enough times that it actually makes a difference in the
-        // profiler -- so just inline the max() here
-        final int measuredWidth = child.getMeasuredWidth();
-        final int minWidth = mMinimumWidth;
-        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
-        return (int) (maxWidth * mLayoutScale + 0.5f);
-    }
-
-    void boundByReorderablePages(boolean isReordering, int[] range) {
-        // Do nothing
-    }
-
-    // TODO: Fix this
-    protected void getVisiblePages(int[] range) {
-        range[0] = 0;
-        range[1] = getPageCount() - 1;
-
-        /*
-        final int pageCount = getChildCount();
-
-        if (pageCount > 0) {
-            final int screenWidth = getViewportWidth();
-            int leftScreen = 0;
-            int rightScreen = 0;
-            int offsetX = getViewportOffsetX() + getScrollX();
-            View currPage = getPageAt(leftScreen);
-            while (leftScreen < pageCount - 1 &&
-                    currPage.getX() + currPage.getWidth() -
-                    currPage.getPaddingRight() < offsetX) {
-                leftScreen++;
-                currPage = getPageAt(leftScreen);
-            }
-            rightScreen = leftScreen;
-            currPage = getPageAt(rightScreen + 1);
-            while (rightScreen < pageCount - 1 &&
-                    currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) {
-                rightScreen++;
-                currPage = getPageAt(rightScreen + 1);
-            }
-
-            // TEMP: this is a hacky way to ensure that animations to new pages are not clipped
-            // because we don't draw them while scrolling?
-            range[0] = Math.max(0, leftScreen - 1);
-            range[1] = Math.min(rightScreen + 1, getChildCount() - 1);
-        } else {
-            range[0] = -1;
-            range[1] = -1;
-        }
-        */
-    }
-
-    protected boolean shouldDrawChild(View child) {
-        return child.getAlpha() > 0;
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        int halfScreenSize = getViewportWidth() / 2;
-        // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
-        // Otherwise it is equal to the scaled overscroll position.
-        int screenCenter = mOverScrollX + halfScreenSize;
-
-        if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
-            // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
-            // set it for the next frame
-            mForceScreenScrolled = false;
-            screenScrolled(screenCenter);
-            mLastScreenCenter = screenCenter;
-        }
-
-        // Find out which screens are visible; as an optimization we only call draw on them
-        final int pageCount = getChildCount();
-        if (pageCount > 0) {
-            getVisiblePages(mTempVisiblePagesRange);
-            final int leftScreen = mTempVisiblePagesRange[0];
-            final int rightScreen = mTempVisiblePagesRange[1];
-            if (leftScreen != -1 && rightScreen != -1) {
-                final long drawingTime = getDrawingTime();
-                // Clip to the bounds
-                canvas.save();
-                canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
-                        getScrollY() + getBottom() - getTop());
-
-                // Draw all the children, leaving the drag view for last
-                for (int i = pageCount - 1; i >= 0; i--) {
-                    final View v = getPageAt(i);
-                    if (v == mDragView) continue;
-                    if (mForceDrawAllChildrenNextFrame ||
-                               (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
-                        drawChild(canvas, v, drawingTime);
-                    }
-                }
-                // Draw the drag view on top (if there is one)
-                if (mDragView != null) {
-                    drawChild(canvas, mDragView, drawingTime);
-                }
-
-                mForceDrawAllChildrenNextFrame = false;
-                canvas.restore();
-            }
-        }
-    }
-
-    @Override
-    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
-        int page = indexToPage(indexOfChild(child));
-        if (page != mCurrentPage || !mScroller.isFinished()) {
-            snapToPage(page);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        int focusablePage;
-        if (mNextPage != INVALID_PAGE) {
-            focusablePage = mNextPage;
-        } else {
-            focusablePage = mCurrentPage;
-        }
-        View v = getPageAt(focusablePage);
-        if (v != null) {
-            return v.requestFocus(direction, previouslyFocusedRect);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean dispatchUnhandledMove(View focused, int direction) {
-        if (direction == View.FOCUS_LEFT) {
-            if (getCurrentPage() > 0) {
-                snapToPage(getCurrentPage() - 1);
-                return true;
-            }
-        } else if (direction == View.FOCUS_RIGHT) {
-            if (getCurrentPage() < getPageCount() - 1) {
-                snapToPage(getCurrentPage() + 1);
-                return true;
-            }
-        }
-        return super.dispatchUnhandledMove(focused, direction);
-    }
-
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
-            getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
-        }
-        if (direction == View.FOCUS_LEFT) {
-            if (mCurrentPage > 0) {
-                getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode);
-            }
-        } else if (direction == View.FOCUS_RIGHT){
-            if (mCurrentPage < getPageCount() - 1) {
-                getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode);
-            }
-        }
-    }
-
-    /**
-     * If one of our descendant views decides that it could be focused now, only
-     * pass that along if it's on the current page.
-     *
-     * This happens when live folders requery, and if they're off page, they
-     * end up calling requestFocus, which pulls it on page.
-     */
-    @Override
-    public void focusableViewAvailable(View focused) {
-        View current = getPageAt(mCurrentPage);
-        View v = focused;
-        while (true) {
-            if (v == current) {
-                super.focusableViewAvailable(focused);
-                return;
-            }
-            if (v == this) {
-                return;
-            }
-            ViewParent parent = v.getParent();
-            if (parent instanceof View) {
-                v = (View)v.getParent();
-            } else {
-                return;
-            }
-        }
-    }
-
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the previous page.
-     */
-    protected boolean hitsPreviousPage(float x, float y) {
-        return (x < getViewportOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing);
-    }
-
-    /**
-     * Return true if a tap at (x, y) should trigger a flip to the next page.
-     */
-    protected boolean hitsNextPage(float x, float y) {
-        return  (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
-    }
-
-    /** Returns whether x and y originated within the buffered viewport */
-    private boolean isTouchPointInViewportWithBuffer(int x, int y) {
-        mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
-                mViewport.right + mViewport.width() / 2, mViewport.bottom);
-        return mTmpRect.contains(x, y);
-    }
-
-    /** Returns whether x and y originated within the current page view bounds */
-    private boolean isTouchPointInCurrentPage(int x, int y) {
-        View v = getPageAt(getCurrentPage());
-        if (v != null) {
-            mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()),
-                    v.getBottom());
-            return mTmpRect.contains(x, y);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
-        /*
-         * This method JUST determines whether we want to intercept the motion.
-         * If we return true, onTouchEvent will be called and we do the actual
-         * scrolling there.
-         */
-        acquireVelocityTrackerAndAddMovement(ev);
-
-        // Skip touch handling if there are no pages to swipe
-        if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
-
-        /*
-         * Shortcut the most recurring case: the user is in the dragging
-         * state and he is moving his finger.  We want to intercept this
-         * motion.
-         */
-        final int action = ev.getAction();
-        if ((action == MotionEvent.ACTION_MOVE) &&
-                (mTouchState == TOUCH_STATE_SCROLLING)) {
-            return true;
-        }
-
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_MOVE: {
-                /*
-                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
-                 * whether the user has moved far enough from his original down touch.
-                 */
-                if (mActivePointerId != INVALID_POINTER) {
-                    if (mIsCameraEvent || determineScrollingStart(ev)) {
-                        startScrolling(ev);
-                    }
-                    break;
-                }
-                // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
-                // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
-                // i.e. fall through to the next case (don't break)
-                // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
-                // while it's small- this was causing a crash before we checked for INVALID_POINTER)
-
-                break;
-            }
-
-            case MotionEvent.ACTION_DOWN: {
-                if (mIsCameraEvent) {
-                    animateWarpPageOnScreen("interceptTouch(): DOWN");
-                }
-                // Remember where the motion event started
-                saveDownState(ev);
-
-                /*
-                 * If being flinged and user touches the screen, initiate drag;
-                 * otherwise don't.  mScroller.isFinished should be false when
-                 * being flinged.
-                 */
-                final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
-                final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
-                if (finishedScrolling) {
-                    setTouchState(TOUCH_STATE_REST);
-                    mScroller.abortAnimation();
-                } else {
-                    if (mIsCameraEvent || isTouchPointInViewportWithBuffer(
-                            (int) mDownMotionX, (int) mDownMotionY)) {
-                        setTouchState(TOUCH_STATE_SCROLLING);
-                    } else {
-                        setTouchState(TOUCH_STATE_REST);
-                    }
-                }
-
-                // check if this can be the beginning of a tap on the side of the pages
-                // to scroll the current page
-                if (!DISABLE_TOUCH_SIDE_PAGES) {
-                    if (mTouchState != TOUCH_STATE_PREV_PAGE
-                            && mTouchState != TOUCH_STATE_NEXT_PAGE) {
-                        if (getChildCount() > 0) {
-                            float x = ev.getX();
-                            float y = ev.getY();
-                            if (hitsPreviousPage(x, y)) {
-                                setTouchState(TOUCH_STATE_PREV_PAGE);
-                            } else if (hitsNextPage(x, y)) {
-                                setTouchState(TOUCH_STATE_NEXT_PAGE);
-                            }
-                        }
-                    }
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                resetTouchState();
-                // Just intercept the touch event on up if we tap outside the strict viewport
-                if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) {
-                    return true;
-                }
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                onSecondaryPointerUp(ev);
-                releaseVelocityTracker();
-                break;
-        }
-
-        /*
-         * The only time we want to intercept motion events is if we are in the
-         * drag mode.
-         */
-        return mTouchState != TOUCH_STATE_REST;
-    }
-
-    private void setTouchState(int touchState) {
-        if (mTouchState != touchState) {
-            if (DEBUG_WARP) Log.v(TAG, "mTouchState changing to " + touchState);
-            onTouchStateChanged(touchState);
-            mTouchState = touchState;
-        }
-    }
-
-    void onTouchStateChanged(int newTouchState) {
-        if (DEBUG) {
-            Log.v(TAG, "onTouchStateChanged(old="+ mTouchState + ", new=" + newTouchState + ")");
-        }
-    }
-
-    /**
-     * Save the state when we get {@link MotionEvent#ACTION_DOWN}
-     * @param ev
-     */
-    private void saveDownState(MotionEvent ev) {
-        // Remember where the motion event started
-        mDownMotionX = mLastMotionX = ev.getX();
-        mDownMotionY = mLastMotionY = ev.getY();
-        mDownScrollX = getScrollX();
-        float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-        mParentDownMotionX = p[0];
-        mParentDownMotionY = p[1];
-        mLastMotionXRemainder = 0;
-        mTotalMotionX = 0;
-        mActivePointerId = ev.getPointerId(0);
-
-        // Determine if the down event is within the threshold to be an edge swipe
-        int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
-        int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
-        if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
-            mDownEventOnEdge = true;
-        }
-    }
-
-    private boolean isHorizontalCameraScroll(MotionEvent ev) {
-        // Disallow scrolling if we don't have a valid pointer index
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        if (pointerIndex == -1) return false;
-
-        // If we're only allowing edge swipes, we break out early if the down event wasn't
-        // at the edge.
-        if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
-
-        final float x = ev.getX(pointerIndex);
-        final int xDiff = (int) Math.abs(x - mDownMotionX);
-
-        final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
-        boolean xPaged = xDiff > mPagingTouchSlop;
-        boolean xMoved = xDiff > touchSlop;
-
-        return mIsCameraEvent && (mUsePagingTouchSlop ? xPaged : xMoved);
-    }
-
-    /*
-     * Determines if we should change the touch state to start scrolling after the
-     * user moves their touch point too far.
-     */
-    protected boolean determineScrollingStart(MotionEvent ev) {
-        // Disallow scrolling if we don't have a valid pointer index
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        if (pointerIndex == -1) return false;
-
-        // Disallow scrolling if we started the gesture from outside the viewport
-        final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return false;
-
-        // If we're only allowing edge swipes, we break out early if the down event wasn't
-        // at the edge.
-        if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
-
-        final int xDiff = (int) Math.abs(x - mLastMotionX);
-
-        final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
-        boolean xPaged = xDiff > mPagingTouchSlop;
-        boolean xMoved = xDiff > touchSlop;
-
-        return mUsePagingTouchSlop ? xPaged : xMoved;
-    }
-
-    private void startScrolling(MotionEvent ev) {
-        // Ignore if we don't have a valid pointer index
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        if (pointerIndex == -1) return;
-
-        final float x = ev.getX(pointerIndex);
-        setTouchState(TOUCH_STATE_SCROLLING);
-        mTotalMotionX += Math.abs(mLastMotionX - x);
-        mLastMotionX = x;
-        mLastMotionXRemainder = 0;
-        mTouchX = getViewportOffsetX() + getScrollX();
-        mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-        pageBeginMoving();
-    }
-
-    protected float getMaxScrollProgress() {
-        return 1.0f;
-    }
-
-    protected float getBoundedScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
-
-        screenCenter = Math.min(mScrollX + halfScreenSize, screenCenter);
-        screenCenter = Math.max(halfScreenSize,  screenCenter);
-
-        return getScrollProgress(screenCenter, v, page);
-    }
-
-    protected float getScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
-
-        int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
-        int delta = screenCenter - (getChildOffset(page) -
-                getRelativeChildOffset(page) + halfScreenSize);
-
-        float scrollProgress = delta / (totalDistance * 1.0f);
-        scrollProgress = Math.min(scrollProgress, getMaxScrollProgress());
-        scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress());
-        return scrollProgress;
-    }
-
-    // This curve determines how the effect of scrolling over the limits of the page dimishes
-    // as the user pulls further and further from the bounds
-    private float overScrollInfluenceCurve(float f) {
-        f -= 1.0f;
-        return f * f * f + 1.0f;
-    }
-
-    protected void acceleratedOverScroll(float amount) {
-        int screenSize = getViewportWidth();
-
-        // We want to reach the max over scroll effect when the user has
-        // over scrolled half the size of the screen
-        float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
-
-        if (f == 0) return;
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-
-        int overScrollAmount = (int) Math.round(f * screenSize);
-        if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(0, getScrollY());
-        } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mMaxScrollX, getScrollY());
-        }
-        invalidate();
-    }
-
-    protected void dampedOverScroll(float amount) {
-        int screenSize = getViewportWidth();
-
-        float f = (amount / screenSize);
-
-        if (f == 0) return;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-
-        int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
-        if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(0, getScrollY());
-        } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mMaxScrollX, getScrollY());
-        }
-        invalidate();
-    }
-
-    protected void overScroll(float amount) {
-        dampedOverScroll(amount);
-    }
-
-    protected float maxOverScroll() {
-        // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
-        // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
-        float f = 1.0f;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-        return OVERSCROLL_DAMP_FACTOR * f;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
-        // Skip touch handling if there are no pages to swipe
-        if (getChildCount() <= 0) return super.onTouchEvent(ev);
-
-        acquireVelocityTrackerAndAddMovement(ev);
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN:
-            /*
-             * If being flinged and user touches, stop the fling. isFinished
-             * will be false if being flinged.
-             */
-            if (!mScroller.isFinished()) {
-                mScroller.abortAnimation();
-            }
-
-            // Remember where the motion event started
-            saveDownState(ev);
-
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                pageBeginMoving();
-            } else {
-                setTouchState(TOUCH_STATE_READY);
-            }
-
-            if (mIsCameraEvent) {
-                animateWarpPageOnScreen("onTouch(): DOWN");
-            }
-            break;
-
-        case MotionEvent.ACTION_MOVE:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                // Scroll to follow the motion event
-                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-
-                if (pointerIndex == -1) return true;
-
-                final float x = ev.getX(pointerIndex);
-                final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
-
-                mTotalMotionX += Math.abs(deltaX);
-
-                // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
-                // keep the remainder because we are actually testing if we've moved from the last
-                // scrolled position (which is discrete).
-                if (Math.abs(deltaX) >= 1.0f) {
-                    mTouchX += deltaX;
-                    mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-                    if (isWarping()) {
-                        KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-                        v.setTranslationX(v.getTranslationX() - deltaX);
-                    } else if (!mDeferScrollUpdate) {
-                        scrollBy((int) deltaX, 0);
-                        if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
-                    } else {
-                        invalidate();
-                    }
-                    mLastMotionX = x;
-                    mLastMotionXRemainder = deltaX - (int) deltaX;
-                } else {
-                    awakenScrollBars();
-                }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-
-                // Find the closest page to the touch point
-                final int dragViewIndex = indexOfChild(mDragView);
-                int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
-                    getViewportWidth());
-                int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
-                        + bufferSize);
-                int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
-                        - bufferSize);
-
-                // Change the drag view if we are hovering over the drop target
-                boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
-                        (int) mParentDownMotionX, (int) mParentDownMotionY);
-                setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
-
-                if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
-                if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
-                if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
-                if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
-
-                float parentX = mParentDownMotionX;
-                int pageIndexToSnapTo = -1;
-                if (parentX < leftBufferEdge && dragViewIndex > 0) {
-                    pageIndexToSnapTo = dragViewIndex - 1;
-                } else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
-                    pageIndexToSnapTo = dragViewIndex + 1;
-                }
-
-                final int pageUnderPointIndex = pageIndexToSnapTo;
-                if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
-                    mTempVisiblePagesRange[0] = 0;
-                    mTempVisiblePagesRange[1] = getPageCount() - 1;
-                    boundByReorderablePages(true, mTempVisiblePagesRange);
-                    if (mTempVisiblePagesRange[0] <= pageUnderPointIndex &&
-                            pageUnderPointIndex <= mTempVisiblePagesRange[1] &&
-                            pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
-                        mSidePageHoverIndex = pageUnderPointIndex;
-                        mSidePageHoverRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                // Update the down scroll position to account for the fact that the
-                                // current page is moved
-                                mDownScrollX = getChildOffset(pageUnderPointIndex)
-                                        - getRelativeChildOffset(pageUnderPointIndex);
-
-                                // Setup the scroll to the correct page before we swap the views
-                                snapToPage(pageUnderPointIndex);
-
-                                // For each of the pages between the paged view and the drag view,
-                                // animate them from the previous position to the new position in
-                                // the layout (as a result of the drag view moving in the layout)
-                                int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
-                                int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
-                                        dragViewIndex + 1 : pageUnderPointIndex;
-                                int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
-                                        dragViewIndex - 1 : pageUnderPointIndex;
-                                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                                    View v = getChildAt(i);
-                                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                                    // drag view all subsequent views to pageUnderPointIndex will
-                                    // shift down.
-                                    int oldX = getViewportOffsetX() + getChildOffset(i);
-                                    int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
-
-                                    // Animate the view translation from its old position to its new
-                                    // position
-                                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                                    if (anim != null) {
-                                        anim.cancel();
-                                    }
-
-                                    v.setTranslationX(oldX - newX);
-                                    anim = new AnimatorSet();
-                                    anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
-                                    anim.playTogether(
-                                            ObjectAnimator.ofFloat(v, "translationX", 0f));
-                                    anim.start();
-                                    v.setTag(anim);
-                                }
-
-                                removeView(mDragView);
-                                onRemoveView(mDragView, false);
-                                addView(mDragView, pageUnderPointIndex);
-                                onAddView(mDragView, pageUnderPointIndex);
-                                mSidePageHoverIndex = -1;
-                            }
-                        };
-                        postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
-                    }
-                } else {
-                    removeCallbacks(mSidePageHoverRunnable);
-                    mSidePageHoverIndex = -1;
-                }
-            } else if (determineScrollingStart(ev)) {
-                startScrolling(ev);
-            } else if (isHorizontalCameraScroll(ev)) {
-                startScrolling(ev);
-                // we need to cancel the camera animation
-                KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-                v.animate().cancel();
-            }
-            break;
-
-        case MotionEvent.ACTION_UP:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                final int activePointerId = mActivePointerId;
-                final int pointerIndex = ev.findPointerIndex(activePointerId);
-
-                if (pointerIndex == -1) return true;
-
-                final float x = ev.getX(pointerIndex);
-                final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
-                final int deltaX = (int) (x - mDownMotionX);
-                final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
-                boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
-                        SIGNIFICANT_MOVE_THRESHOLD;
-
-                mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
-
-                boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
-                        Math.abs(velocityX) > mFlingThresholdVelocity;
-
-                // In the case that the page is moved far to one direction and then is flung
-                // in the opposite direction, we use a threshold to determine whether we should
-                // just return to the starting page, or if we should skip one further.
-                boolean returnToOriginalPage = false;
-                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
-                        Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
-                    returnToOriginalPage = true;
-                }
-
-                int finalPage;
-                // We give flings precedence over large moves, which is why we short-circuit our
-                // test for a large move if a fling has been registered. That is, a large
-                // move to the left and fling to the right will register as a fling to the right.
-                if (((isSignificantMove && deltaX > 0 && !isFling) ||
-                        (isFling && velocityX > 0)) && mCurrentPage > 0) {
-                    finalPage = returnToOriginalPage || isWarping()
-                            ? mCurrentPage : mCurrentPage - 1;
-                    snapToPageWithVelocity(finalPage, velocityX);
-                } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
-                        (isFling && velocityX < 0)) &&
-                        mCurrentPage < getChildCount() - 1) {
-                    finalPage = returnToOriginalPage ? mCurrentPage :
-                            isWarping() ? getPageWarpIndex() : mCurrentPage + 1;
-                    snapToPageWithVelocity(finalPage, velocityX);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
-                // at this point we have not moved beyond the touch slop
-                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
-                // we can just page
-                int nextPage = Math.max(0, mCurrentPage - 1);
-                if (nextPage != mCurrentPage) {
-                    snapToPage(nextPage);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
-                // at this point we have not moved beyond the touch slop
-                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
-                // we can just page
-                int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
-                if (nextPage != mCurrentPage) {
-                    snapToPage(nextPage);
-                } else {
-                    snapToDestination();
-                }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-                boolean handledFling = false;
-                if (!DISABLE_FLING_TO_DELETE) {
-                    // Check the velocity and see if we are flinging-to-delete
-                    PointF flingToDeleteVector = isFlingingToDelete();
-                    if (flingToDeleteVector != null) {
-                        onFlingToDelete(flingToDeleteVector);
-                        handledFling = true;
-                    }
-                }
-                if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
-                        (int) mParentDownMotionY)) {
-                    onDropToDelete();
-                }
-            } else {
-                if (DEBUG_WARP) Log.v(TAG, "calling onUnhandledTap()");
-                if (mWarpPageExposed && !isAnimatingWarpPage()) {
-                    animateWarpPageOffScreen("unhandled tap", true);
-                }
-                onUnhandledTap(ev);
-            }
-
-            // Remove the callback to wait for the side page hover timeout
-            removeCallbacks(mSidePageHoverRunnable);
-            // End any intermediate reordering states
-            resetTouchState();
-            break;
-
-        case MotionEvent.ACTION_CANCEL:
-            if (mTouchState == TOUCH_STATE_SCROLLING) {
-                snapToDestination();
-            }
-            resetTouchState();
-            break;
-
-        case MotionEvent.ACTION_POINTER_UP:
-            onSecondaryPointerUp(ev);
-            break;
-        }
-
-        return true;
-    }
-
-    //public abstract void onFlingToDelete(View v);
-    public abstract void onRemoveView(View v, boolean deletePermanently);
-    public abstract void onRemoveViewAnimationCompleted();
-    public abstract void onAddView(View v, int index);
-
-    private void resetTouchState() {
-        releaseVelocityTracker();
-        endReordering();
-        setTouchState(TOUCH_STATE_REST);
-        mActivePointerId = INVALID_POINTER;
-        mDownEventOnEdge = false;
-    }
-
-    protected void onUnhandledTap(MotionEvent ev) {}
-
-    @Override
-    public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_SCROLL: {
-                    // Handle mouse (or ext. device) by shifting the page depending on the scroll
-                    final float vscroll;
-                    final float hscroll;
-                    if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
-                        vscroll = 0;
-                        hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                    } else {
-                        vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
-                        hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
-                    }
-                    if (hscroll != 0 || vscroll != 0) {
-                        if (hscroll > 0 || vscroll > 0) {
-                            scrollRight();
-                        } else {
-                            scrollLeft();
-                        }
-                        return true;
-                    }
-                }
-            }
-        }
-        return super.onGenericMotionEvent(event);
-    }
-
-    private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-    }
-
-    private void releaseVelocityTracker() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    private void onSecondaryPointerUp(MotionEvent ev) {
-        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
-                MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-        final int pointerId = ev.getPointerId(pointerIndex);
-        if (pointerId == mActivePointerId) {
-            // This was our active pointer going up. Choose a new
-            // active pointer and adjust accordingly.
-            // TODO: Make this decision more intelligent.
-            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-            mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
-            mLastMotionY = ev.getY(newPointerIndex);
-            mLastMotionXRemainder = 0;
-            mActivePointerId = ev.getPointerId(newPointerIndex);
-            if (mVelocityTracker != null) {
-                mVelocityTracker.clear();
-            }
-        }
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        super.requestChildFocus(child, focused);
-        int page = indexToPage(indexOfChild(child));
-        if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
-            snapToPage(page);
-        }
-    }
-
-    protected int getChildIndexForRelativeOffset(int relativeOffset) {
-        final int childCount = getChildCount();
-        int left;
-        int right;
-        for (int i = 0; i < childCount; ++i) {
-            left = getRelativeChildOffset(i);
-            right = (left + getScaledMeasuredWidth(getPageAt(i)));
-            if (left <= relativeOffset && relativeOffset <= right) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    protected int getChildWidth(int index) {
-        // This functions are called enough times that it actually makes a difference in the
-        // profiler -- so just inline the max() here
-        final int measuredWidth = getPageAt(index).getMeasuredWidth();
-        final int minWidth = mMinimumWidth;
-        return (minWidth > measuredWidth) ? minWidth : measuredWidth;
-    }
-
-    int getPageNearestToPoint(float x) {
-        int index = 0;
-        for (int i = 0; i < getChildCount(); ++i) {
-            if (x < getChildAt(i).getRight() - getScrollX()) {
-                return index;
-            } else {
-                index++;
-            }
-        }
-        return Math.min(index, getChildCount() - 1);
-    }
-
-    int getPageNearestToCenterOfScreen() {
-        int minDistanceFromScreenCenter = Integer.MAX_VALUE;
-        int minDistanceFromScreenCenterIndex = -1;
-        int screenCenter = getViewportOffsetX() + getScrollX() + (getViewportWidth() / 2);
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; ++i) {
-            View layout = (View) getPageAt(i);
-            int childWidth = getScaledMeasuredWidth(layout);
-            int halfChildWidth = (childWidth / 2);
-            int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth;
-            int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
-            if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
-                minDistanceFromScreenCenter = distanceFromScreenCenter;
-                minDistanceFromScreenCenterIndex = i;
-            }
-        }
-        return minDistanceFromScreenCenterIndex;
-    }
-
-    protected void snapToDestination() {
-        final int newPage = getPageNearestToCenterOfScreen();
-        if (isWarping()) {
-            cancelWarpAnimation("snapToDestination", mCurrentPage != newPage);
-        }
-        snapToPage(newPage, getPageSnapDuration());
-    }
-
-    private int getPageSnapDuration() {
-        return isWarping() ? WARP_SNAP_DURATION : PAGE_SNAP_ANIMATION_DURATION;
-    }
-
-    private static class ScrollInterpolator implements Interpolator {
-        public ScrollInterpolator() {
-        }
-
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t*t*t*t*t + 1;
-        }
-    }
-
-    // We want the duration of the page snap animation to be influenced by the distance that
-    // the screen has to travel, however, we don't want this duration to be effected in a
-    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
-    // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    protected void snapToPageWithVelocity(int whichPage, int velocity) {
-        whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
-        int halfScreenSize = getViewportWidth() / 2;
-
-        if (isWarping()) {
-            cancelWarpAnimation("snapToPageWithVelocity", mCurrentPage != whichPage);
-        }
-
-        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
-        if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
-                + getViewportWidth() + ", " + getChildWidth(whichPage));
-        final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
-        int delta = newX - mUnboundedScrollX;
-        int duration = 0;
-
-        if (Math.abs(velocity) < mMinFlingVelocity) {
-            // If the velocity is low enough, then treat this more as an automatic page advance
-            // as opposed to an apparent physical response to flinging
-            snapToPage(whichPage, getPageSnapDuration());
-            return;
-        }
-
-        // Here we compute a "distance" that will be used in the computation of the overall
-        // snap duration. This is a function of the actual distance that needs to be traveled;
-        // we keep this value close to half screen size in order to reduce the variance in snap
-        // duration as a function of the distance the page needs to travel.
-        float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize));
-        float distance = halfScreenSize + halfScreenSize *
-                distanceInfluenceForSnapDuration(distanceRatio);
-
-        velocity = Math.abs(velocity);
-        velocity = Math.max(mMinSnapVelocity, velocity);
-
-        // we want the page's snap velocity to approximately match the velocity at which the
-        // user flings, so we scale the duration by a value near to the derivative of the scroll
-        // interpolator at zero, ie. 5. We use 4 to make it a little slower.
-        duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-
-        snapToPage(whichPage, delta, duration);
-    }
-
-    protected void snapToPage(int whichPage) {
-        snapToPage(whichPage, getPageSnapDuration());
-    }
-    protected void snapToPageImmediately(int whichPage) {
-        snapToPage(whichPage, getPageSnapDuration(), true);
-    }
-
-    protected void snapToPage(int whichPage, int duration) {
-        snapToPage(whichPage, duration, false);
-    }
-    protected void snapToPage(int whichPage, int duration, boolean immediate) {
-        whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
-
-        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
-        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getViewportWidth() + ", "
-                + getChildWidth(whichPage));
-        int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
-        final int sX = mUnboundedScrollX;
-        final int delta = newX - sX;
-        snapToPage(whichPage, delta, duration, immediate);
-    }
-
-    protected void snapToPage(int whichPage, int delta, int duration) {
-        snapToPage(whichPage, delta, duration, false);
-    }
-
-    protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
-        if (isWarping() && whichPage == mCurrentPage+1) {
-            mNextPage = getPageWarpIndex(); // jump to the warp page
-            if (DEBUG_WARP) Log.v(TAG, "snapToPage(" + whichPage + ") : reset mPageSwapIndex");
-        } else {
-            mNextPage = whichPage;
-        }
-
-        if(mWarpPageExposed) {
-            dispatchOnPageEndWarp();
-            mWarpPageExposed = false;
-        }
-        notifyPageSwitching(whichPage);
-
-
-        View focusedChild = getFocusedChild();
-        if (focusedChild != null && whichPage != mCurrentPage &&
-                focusedChild == getPageAt(mCurrentPage)) {
-            focusedChild.clearFocus();
-        }
-
-        pageBeginMoving();
-        awakenScrollBars(duration);
-        if (immediate) {
-            duration = 0;
-        } else if (duration == 0) {
-            duration = Math.abs(delta);
-        }
-
-        if (!mScroller.isFinished()) mScroller.abortAnimation();
-        mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
-
-        notifyPageSwitched();
-
-        // Trigger a compute() to finish switching pages if necessary
-        if (immediate) {
-            computeScroll();
-        }
-
-        mForceScreenScrolled = true;
-        invalidate();
-    }
-
-    protected boolean isWarping() {
-        return mWarpPageExposed;
-    }
-
-    public void scrollLeft() {
-        if (mScroller.isFinished()) {
-            if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
-        } else {
-            if (mNextPage > 0) snapToPage(mNextPage - 1);
-        }
-    }
-
-    public void scrollRight() {
-        if (mScroller.isFinished()) {
-            if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
-        } else {
-            if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
-        }
-    }
-
-    public int getPageForView(View v) {
-        int result = -1;
-        if (v != null) {
-            ViewParent vp = v.getParent();
-            int count = getChildCount();
-            for (int i = 0; i < count; i++) {
-                if (vp == getPageAt(i)) {
-                    return i;
-                }
-            }
-        }
-        return result;
-    }
-
-    public static class SavedState extends BaseSavedState {
-        int currentPage = -1;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            currentPage = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(currentPage);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR =
-                new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    protected View getScrollingIndicator() {
-        return null;
-    }
-
-    protected boolean isScrollingIndicatorEnabled() {
-        return false;
-    }
-
-    Runnable hideScrollingIndicatorRunnable = new Runnable() {
-        @Override
-        public void run() {
-            hideScrollingIndicator(false);
-        }
-    };
-
-    protected void flashScrollingIndicator(boolean animated) {
-        removeCallbacks(hideScrollingIndicatorRunnable);
-        showScrollingIndicator(!animated);
-        postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration);
-    }
-
-    protected void showScrollingIndicator(boolean immediately) {
-        mShouldShowScrollIndicator = true;
-        mShouldShowScrollIndicatorImmediately = true;
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        mShouldShowScrollIndicator = false;
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            // Fade the indicator in
-            updateScrollingIndicatorPosition();
-            mScrollIndicator.setVisibility(View.VISIBLE);
-            cancelScrollingIndicatorAnimations();
-            if (immediately) {
-                mScrollIndicator.setAlpha(1f);
-            } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
-                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
-                mScrollIndicatorAnimator.start();
-            }
-        }
-    }
-
-    protected void cancelScrollingIndicatorAnimations() {
-        if (mScrollIndicatorAnimator != null) {
-            mScrollIndicatorAnimator.cancel();
-        }
-    }
-
-    protected void hideScrollingIndicator(boolean immediately) {
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            // Fade the indicator out
-            updateScrollingIndicatorPosition();
-            cancelScrollingIndicatorAnimations();
-            if (immediately) {
-                mScrollIndicator.setVisibility(View.INVISIBLE);
-                mScrollIndicator.setAlpha(0f);
-            } else {
-                mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
-                mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
-                mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
-                    private boolean cancelled = false;
-                    @Override
-                    public void onAnimationCancel(android.animation.Animator animation) {
-                        cancelled = true;
-                    }
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        if (!cancelled) {
-                            mScrollIndicator.setVisibility(View.INVISIBLE);
-                        }
-                    }
-                });
-                mScrollIndicatorAnimator.start();
-            }
-        }
-    }
-
-    /**
-     * To be overridden by subclasses to determine whether the scroll indicator should stretch to
-     * fill its space on the track or not.
-     */
-    protected boolean hasElasticScrollIndicator() {
-        return true;
-    }
-
-    private void updateScrollingIndicator() {
-        if (getChildCount() <= 1) return;
-        if (!isScrollingIndicatorEnabled()) return;
-
-        getScrollingIndicator();
-        if (mScrollIndicator != null) {
-            updateScrollingIndicatorPosition();
-        }
-        if (mShouldShowScrollIndicator) {
-            showScrollingIndicator(mShouldShowScrollIndicatorImmediately);
-        }
-    }
-
-    private void updateScrollingIndicatorPosition() {
-        if (!isScrollingIndicatorEnabled()) return;
-        if (mScrollIndicator == null) return;
-        int numPages = getChildCount();
-        int pageWidth = getViewportWidth();
-        int lastChildIndex = Math.max(0, getChildCount() - 1);
-        int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
-        int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
-        int indicatorWidth = mScrollIndicator.getMeasuredWidth() -
-                mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight();
-
-        float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX));
-        int indicatorSpace = trackWidth / numPages;
-        int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
-        if (hasElasticScrollIndicator()) {
-            if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) {
-                mScrollIndicator.getLayoutParams().width = indicatorSpace;
-                mScrollIndicator.requestLayout();
-            }
-        } else {
-            int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2;
-            indicatorPos += indicatorCenterOffset;
-        }
-        mScrollIndicator.setTranslationX(indicatorPos);
-    }
-
-    // Animate the drag view back to the original position
-    void animateDragViewToOriginalPosition() {
-        if (mDragView != null) {
-            AnimatorSet anim = new AnimatorSet();
-            anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
-            anim.playTogether(
-                    ObjectAnimator.ofFloat(mDragView, "translationX", 0f),
-                    ObjectAnimator.ofFloat(mDragView, "translationY", 0f));
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onPostReorderingAnimationCompleted();
-                }
-            });
-            anim.start();
-        }
-    }
-
-    // "Zooms out" the PagedView to reveal more side pages
-    protected boolean zoomOut() {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-
-        if (!(getScaleX() < 1f || getScaleY() < 1f)) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
-                    ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
-            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    // Show the delete drop target
-                    if (mDeleteDropTarget != null) {
-                        mDeleteDropTarget.setVisibility(View.VISIBLE);
-                        mDeleteDropTarget.animate().alpha(1f)
-                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationStart(Animator animation) {
-                                    mDeleteDropTarget.setAlpha(0f);
-                                }
-                            });
-                    }
-                }
-            });
-            mZoomInOutAnim.start();
-            return true;
-        }
-        return false;
-    }
-
-    protected void onStartReordering() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            announceForAccessibility(mContext.getString(
-                    R.string.keyguard_accessibility_widget_reorder_start));
-        }
-
-        // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
-        setTouchState(TOUCH_STATE_REORDERING);
-        mIsReordering = true;
-
-        // Mark all the non-widget pages as invisible
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-        for (int i = 0; i < getPageCount(); ++i) {
-            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
-                getPageAt(i).setAlpha(0f);
-            }
-        }
-
-        // We must invalidate to trigger a redraw to update the layers such that the drag view
-        // is always drawn on top
-        invalidate();
-    }
-
-    private void onPostReorderingAnimationCompleted() {
-        // Trigger the callback when reordering has settled
-        --mPostReorderingPreZoomInRemainingAnimationCount;
-        if (mPostReorderingPreZoomInRunnable != null &&
-                mPostReorderingPreZoomInRemainingAnimationCount == 0) {
-            mPostReorderingPreZoomInRunnable.run();
-            mPostReorderingPreZoomInRunnable = null;
-        }
-    }
-
-    protected void onEndReordering() {
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            if (mDeleteString != null) {
-                announceForAccessibility(mDeleteString);
-                mDeleteString = null;
-            } else {
-                announceForAccessibility(mContext.getString(
-                        R.string.keyguard_accessibility_widget_reorder_end));
-            }
-        }
-        mIsReordering = false;
-
-        // Mark all the non-widget pages as visible again
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-        for (int i = 0; i < getPageCount(); ++i) {
-            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
-                getPageAt(i).setAlpha(1f);
-            }
-        }
-    }
-
-    public boolean startReordering() {
-        int dragViewIndex = getPageNearestToCenterOfScreen();
-        mTempVisiblePagesRange[0] = 0;
-        mTempVisiblePagesRange[1] = getPageCount() - 1;
-        boundByReorderablePages(true, mTempVisiblePagesRange);
-
-        // Check if we are within the reordering range
-        if (mTempVisiblePagesRange[0] <= dragViewIndex &&
-                dragViewIndex <= mTempVisiblePagesRange[1]) {
-            mReorderingStarted = true;
-            if (zoomOut()) {
-                // Find the drag view under the pointer
-                mDragView = getChildAt(dragViewIndex);
-
-                onStartReordering();
-            }
-            return true;
-        }
-        return false;
-    }
-
-    boolean isReordering(boolean testTouchState) {
-        boolean state = mIsReordering;
-        if (testTouchState) {
-            state &= (mTouchState == TOUCH_STATE_REORDERING);
-        }
-        return state;
-    }
-    void endReordering() {
-        // For simplicity, we call endReordering sometimes even if reordering was never started.
-        // In that case, we don't want to do anything.
-        if (!mReorderingStarted) return;
-        mReorderingStarted = false;
-
-        // If we haven't flung-to-delete the current child, then we just animate the drag view
-        // back into position
-        final Runnable onCompleteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                onEndReordering();
-            }
-        };
-        if (!mDeferringForDelete) {
-            mPostReorderingPreZoomInRunnable = new Runnable() {
-                public void run() {
-                    zoomIn(onCompleteRunnable);
-                };
-            };
-
-            mPostReorderingPreZoomInRemainingAnimationCount =
-                    NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
-            // Snap to the current page
-            snapToPage(indexOfChild(mDragView), 0);
-            // Animate the drag view back to the front position
-            animateDragViewToOriginalPosition();
-        } else {
-            // Handled in post-delete-animation-callbacks
-        }
-    }
-
-    // "Zooms in" the PagedView to highlight the current page
-    protected boolean zoomIn(final Runnable onCompleteRunnable) {
-        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
-            mZoomInOutAnim.cancel();
-        }
-        if (getScaleX() < 1f || getScaleY() < 1f) {
-            mZoomInOutAnim = new AnimatorSet();
-            mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
-            mZoomInOutAnim.playTogether(
-                    ObjectAnimator.ofFloat(this, "scaleX", 1f),
-                    ObjectAnimator.ofFloat(this, "scaleY", 1f));
-            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    // Hide the delete drop target
-                    if (mDeleteDropTarget != null) {
-                        mDeleteDropTarget.animate().alpha(0f)
-                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationEnd(Animator animation) {
-                                    mDeleteDropTarget.setVisibility(View.GONE);
-                                }
-                            });
-                    }
-                }
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mDragView = null;
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mDragView = null;
-                    if (onCompleteRunnable != null) {
-                        onCompleteRunnable.run();
-                    }
-                }
-            });
-            mZoomInOutAnim.start();
-            return true;
-        } else {
-            if (onCompleteRunnable != null) {
-                onCompleteRunnable.run();
-            }
-        }
-        return false;
-    }
-
-    /*
-     * Flinging to delete - IN PROGRESS
-     */
-    private PointF isFlingingToDelete() {
-        ViewConfiguration config = ViewConfiguration.get(getContext());
-        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
-
-        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
-            // Do a quick dot product test to ensure that we are flinging upwards
-            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
-                    mVelocityTracker.getYVelocity());
-            PointF upVec = new PointF(0f, -1f);
-            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
-                    (vel.length() * upVec.length()));
-            if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
-                return vel;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Creates an animation from the current drag view along its current velocity vector.
-     * For this animation, the alpha runs for a fixed duration and we update the position
-     * progressively.
-     */
-    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private View mDragView;
-        private PointF mVelocity;
-        private Rect mFrom;
-        private long mPrevTime;
-        private float mFriction;
-
-        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
-        public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from,
-                long startTime, float friction) {
-            mDragView = dragView;
-            mVelocity = vel;
-            mFrom = from;
-            mPrevTime = startTime;
-            mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction);
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            float t = ((Float) animation.getAnimatedValue()).floatValue();
-            long curTime = AnimationUtils.currentAnimationTimeMillis();
-
-            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
-            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
-            mDragView.setTranslationX(mFrom.left);
-            mDragView.setTranslationY(mFrom.top);
-            mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
-            mVelocity.x *= mFriction;
-            mVelocity.y *= mFriction;
-            mPrevTime = curTime;
-        }
-    };
-
-    private Runnable createPostDeleteAnimationRunnable(final View dragView) {
-        return new Runnable() {
-            @Override
-            public void run() {
-                int dragViewIndex = indexOfChild(dragView);
-
-                // For each of the pages around the drag view, animate them from the previous
-                // position to the new position in the layout (as a result of the drag view moving
-                // in the layout)
-                // NOTE: We can make an assumption here because we have side-bound pages that we
-                //       will always have pages to animate in from the left
-                getVisiblePages(mTempVisiblePagesRange);
-                boundByReorderablePages(true, mTempVisiblePagesRange);
-                boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
-                boolean slideFromLeft = (isLastWidgetPage ||
-                        dragViewIndex > mTempVisiblePagesRange[0]);
-
-                // Setup the scroll to the correct page before we swap the views
-                if (slideFromLeft) {
-                    snapToPageImmediately(dragViewIndex - 1);
-                }
-
-                int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
-                int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
-                int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
-                int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
-                ArrayList<Animator> animations = new ArrayList<Animator>();
-                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                    View v = getChildAt(i);
-                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                    // drag view all subsequent views to pageUnderPointIndex will
-                    // shift down.
-                    int oldX = 0;
-                    int newX = 0;
-                    if (slideFromLeft) {
-                        if (i == 0) {
-                            // Simulate the page being offscreen with the page spacing
-                            oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
-                                    - mPageSpacing;
-                        } else {
-                            oldX = getViewportOffsetX() + getChildOffset(i - 1);
-                        }
-                        newX = getViewportOffsetX() + getChildOffset(i);
-                    } else {
-                        oldX = getChildOffset(i) - getChildOffset(i - 1);
-                        newX = 0;
-                    }
-
-                    // Animate the view translation from its old position to its new
-                    // position
-                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                    if (anim != null) {
-                        anim.cancel();
-                    }
-
-                    // Note: Hacky, but we want to skip any optimizations to not draw completely
-                    // hidden views
-                    v.setAlpha(Math.max(v.getAlpha(), 0.01f));
-                    v.setTranslationX(oldX - newX);
-                    anim = new AnimatorSet();
-                    anim.playTogether(
-                            ObjectAnimator.ofFloat(v, "translationX", 0f),
-                            ObjectAnimator.ofFloat(v, "alpha", 1f));
-                    animations.add(anim);
-                    v.setTag(anim);
-                }
-
-                AnimatorSet slideAnimations = new AnimatorSet();
-                slideAnimations.playTogether(animations);
-                slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
-                slideAnimations.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        final Runnable onCompleteRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                mDeferringForDelete = false;
-                                onEndReordering();
-                                onRemoveViewAnimationCompleted();
-                            }
-                        };
-                        zoomIn(onCompleteRunnable);
-                    }
-                });
-                slideAnimations.start();
-
-                removeView(dragView);
-                onRemoveView(dragView, true);
-            }
-        };
-    }
-
-    public void onFlingToDelete(PointF vel) {
-        final long startTime = AnimationUtils.currentAnimationTimeMillis();
-
-        // NOTE: Because it takes time for the first frame of animation to actually be
-        // called and we expect the animation to be a continuation of the fling, we have
-        // to account for the time that has elapsed since the fling finished.  And since
-        // we don't have a startDelay, we will always get call to update when we call
-        // start() (which we want to ignore).
-        final TimeInterpolator tInterpolator = new TimeInterpolator() {
-            private int mCount = -1;
-            private long mStartTime;
-            private float mOffset;
-            /* Anonymous inner class ctor */ {
-                mStartTime = startTime;
-            }
-
-            @Override
-            public float getInterpolation(float t) {
-                if (mCount < 0) {
-                    mCount++;
-                } else if (mCount == 0) {
-                    mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
-                            mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
-                    mCount++;
-                }
-                return Math.min(1f, mOffset + t);
-            }
-        };
-
-        final Rect from = new Rect();
-        final View dragView = mDragView;
-        from.left = (int) dragView.getTranslationX();
-        from.top = (int) dragView.getTranslationY();
-        AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
-                from, startTime, FLING_TO_DELETE_FRICTION);
-
-        mDeleteString = getContext().getResources()
-                .getString(R.string.keyguard_accessibility_widget_deleted,
-                        mDragView.getContentDescription());
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        // Create and start the animation
-        ValueAnimator mDropAnim = new ValueAnimator();
-        mDropAnim.setInterpolator(tInterpolator);
-        mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
-        mDropAnim.setFloatValues(0f, 1f);
-        mDropAnim.addUpdateListener(updateCb);
-        mDropAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        mDropAnim.start();
-        mDeferringForDelete = true;
-    }
-
-    /* Drag to delete */
-    private boolean isHoveringOverDeleteDropTarget(int x, int y) {
-        if (mDeleteDropTarget != null) {
-            mAltTmpRect.set(0, 0, 0, 0);
-            View parent = (View) mDeleteDropTarget.getParent();
-            if (parent != null) {
-                parent.getGlobalVisibleRect(mAltTmpRect);
-            }
-            mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
-            mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top);
-            return mTmpRect.contains(x, y);
-        }
-        return false;
-    }
-
-    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
-
-    private void onDropToDelete() {
-        final View dragView = mDragView;
-
-        final float toScale = 0f;
-        final float toAlpha = 0f;
-
-        // Create and start the complex animation
-        ArrayList<Animator> animations = new ArrayList<Animator>();
-        AnimatorSet motionAnim = new AnimatorSet();
-        motionAnim.setInterpolator(new DecelerateInterpolator(2));
-        motionAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
-                ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
-        animations.add(motionAnim);
-
-        AnimatorSet alphaAnim = new AnimatorSet();
-        alphaAnim.setInterpolator(new LinearInterpolator());
-        alphaAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
-        animations.add(alphaAnim);
-
-        mDeleteString = getContext().getResources()
-                .getString(R.string.keyguard_accessibility_widget_deleted,
-                        mDragView.getContentDescription());
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        AnimatorSet anim = new AnimatorSet();
-        anim.playTogether(animations);
-        anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        anim.start();
-
-        mDeferringForDelete = true;
-    }
-
-    /* Accessibility */
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setScrollable(getPageCount() > 1);
-        if (getCurrentPage() < getPageCount() - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-        }
-        if (getCurrentPage() > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
-        }
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
-        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            event.setFromIndex(mCurrentPage);
-            event.setToIndex(mCurrentPage);
-            event.setItemCount(getChildCount());
-        }
-    }
-
-    @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
-            return true;
-        }
-        switch (action) {
-            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (getCurrentPage() < getPageCount() - 1) {
-                    scrollRight();
-                    return true;
-                }
-            } break;
-            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (getCurrentPage() > 0) {
-                    scrollLeft();
-                    return true;
-                }
-            } break;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onHoverEvent(android.view.MotionEvent event) {
-        return true;
-    }
-
-    void beginCameraEvent() {
-        mIsCameraEvent = true;
-    }
-
-    void endCameraEvent() {
-        mIsCameraEvent = false;
-    }
-
-    AnimatorListenerAdapter mOnScreenAnimationListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mWarpAnimation = null;
-            if (mTouchState != TOUCH_STATE_SCROLLING && mTouchState != TOUCH_STATE_READY) {
-                animateWarpPageOffScreen("onScreen end", true);
-            }
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            super.onAnimationCancel(animation);
-            mWarpAnimation = null;
-        }
-    };
-
-    AnimatorListenerAdapter mOffScreenAnimationListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mWarpAnimation = null;
-            mWarpPageExposed = false;
-            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-            v.setTranslationX(0.0f);
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            super.onAnimationCancel(animation);
-            mWarpAnimation = null;
-        }
-    };
-
-    private void cancelWarpAnimation(String msg, boolean abortAnimation) {
-        if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ",abort=" + abortAnimation + ")");
-        if (abortAnimation) {
-            // We're done with the animation and moving to a new page.  Let the scroller
-            // take over the animation.
-            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-            v.animate().cancel();
-            // Make the scroll amount match the current warp position.
-            scrollBy(Math.round(-v.getTranslationX()), 0);
-            v.setTranslationX(0);
-        } else {
-            animateWarpPageOffScreen("canceled", true);
-        }
-    }
-
-    private boolean isAnimatingWarpPage() {
-        return mWarpAnimation != null;
-    }
-
-    private void animateWarpPageOnScreen(String reason) {
-        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen(" + reason + ")");
-        if (!mWarpPageExposed) {
-            mWarpPageExposed = true;
-            dispatchOnPageBeginWarp();
-            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-            if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX());
-            DecelerateInterpolator interp = new DecelerateInterpolator(1.5f);
-            int totalOffset = getCurrentWarpOffset();
-            v.setTranslationX(totalOffset);
-            mWarpAnimation = v.animate();
-            mWarpAnimation.translationX(mWarpPeekAmount+totalOffset)
-                    .setInterpolator(interp)
-                    .setDuration(WARP_PEEK_ANIMATION_DURATION)
-                    .setListener(mOnScreenAnimationListener);
-        }
-    }
-
-    private int getCurrentWarpOffset() {
-        if (mCurrentPage == getPageWarpIndex()) {
-            return 0;
-        }
-        View viewRight = getPageAt(mCurrentPage + 1);
-        View warpView = getPageAt(getPageWarpIndex());
-        if (viewRight != warpView && viewRight != null && warpView != null) {
-            return viewRight.getLeft() - warpView.getLeft();
-        }
-        return 0;
-    }
-
-    private void animateWarpPageOffScreen(String reason, boolean animate) {
-        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen(" + reason + " anim:" + animate + ")");
-        if (mWarpPageExposed) {
-            dispatchOnPageEndWarp();
-            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
-            if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX());
-            AccelerateInterpolator interp = new AccelerateInterpolator(1.5f);
-            int totalOffset = getCurrentWarpOffset();
-            v.animate().translationX(totalOffset)
-                    .setInterpolator(interp)
-                    .setDuration(animate ? WARP_PEEK_ANIMATION_DURATION : 0)
-                    .setListener(mOffScreenAnimationListener);
-        } else {
-            if (DEBUG_WARP) Log.e(TAG, "animateWarpPageOffScreen(): not warping", new Exception());
-        }
-    }
-
-    /**
-     * Swaps the position of the views by setting the left and right edges appropriately.
-     */
-    void swapPages(int indexA, int indexB) {
-        View viewA = getPageAt(indexA);
-        View viewB = getPageAt(indexB);
-        if (viewA != viewB && viewA != null && viewB != null) {
-            int deltaX = viewA.getLeft() - viewB.getLeft();
-            viewA.offsetLeftAndRight(-deltaX);
-            viewB.offsetLeftAndRight(deltaX);
-        }
-    }
-
-    public void startPageWarp(int pageIndex) {
-        if (DEBUG_WARP) Log.v(TAG, "START WARP");
-        if (pageIndex != mCurrentPage + 1) {
-            mPageSwapIndex = mCurrentPage + 1;
-        }
-        mPageWarpIndex = pageIndex;
-    }
-
-    protected int getPageWarpIndex() {
-        return getPageCount() - 1;
-    }
-
-    public void stopPageWarp() {
-        if (DEBUG_WARP) Log.v(TAG, "END WARP");
-        // mPageSwapIndex is reset in snapToPage() after the scroll animation completes
-    }
-
-    public void onPageBeginWarp() {
-
-    }
-
-    public void onPageEndWarp() {
-
-    }
-
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
deleted file mode 100644
index ab9286b..0000000
--- a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
+++ /dev/null
@@ -1,1290 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.FloatProperty;
-import android.util.Log;
-import android.util.Property;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-/**
- * This layout handles interaction with the sliding security challenge views
- * that overlay/resize other keyguard contents.
- */
-public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout {
-    private static final String TAG = "SlidingChallengeLayout";
-    private static final boolean DEBUG = KeyguardConstants.DEBUG;
-
-    // The drag handle is measured in dp above & below the top edge of the
-    // challenge view; these parameters change based on whether the challenge
-    // is open or closed.
-    private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
-    private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
-    private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
-    private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
-
-    private static final int HANDLE_ANIMATE_DURATION = 250; // ms
-
-    // Drawn to show the drag handle in closed state; crossfades to the challenge view
-    // when challenge is fully visible
-    private boolean mEdgeCaptured;
-
-    private DisplayMetrics mDisplayMetrics;
-
-    // Initialized during measurement from child layoutparams
-    private View mExpandChallengeView;
-    private KeyguardSecurityContainer mChallengeView;
-    private View mScrimView;
-    private View mWidgetsView;
-
-    // Range: 0 (fully hidden) to 1 (fully visible)
-    private float mChallengeOffset = 1.f;
-    private boolean mChallengeShowing = true;
-    private boolean mChallengeShowingTargetState = true;
-    private boolean mWasChallengeShowing = true;
-    private boolean mIsBouncing = false;
-
-    private final Scroller mScroller;
-    private ObjectAnimator mFader;
-    private int mScrollState;
-    private OnChallengeScrolledListener mScrollListener;
-    private OnBouncerStateChangedListener mBouncerListener;
-    private boolean mEnableChallengeDragging;
-
-    public static final int SCROLL_STATE_IDLE = 0;
-    public static final int SCROLL_STATE_DRAGGING = 1;
-    public static final int SCROLL_STATE_SETTLING = 2;
-    public static final int SCROLL_STATE_FADING = 3;
-
-    public static final int CHALLENGE_FADE_OUT_DURATION = 100;
-    public static final int CHALLENGE_FADE_IN_DURATION = 160;
-
-    private static final int MAX_SETTLE_DURATION = 600; // ms
-
-    // ID of the pointer in charge of a current drag
-    private int mActivePointerId = INVALID_POINTER;
-    private static final int INVALID_POINTER = -1;
-
-    // True if the user is currently dragging the slider
-    private boolean mDragging;
-    // True if the user may not drag until a new gesture begins
-    private boolean mBlockDrag;
-
-    private VelocityTracker mVelocityTracker;
-    private int mMinVelocity;
-    private int mMaxVelocity;
-    private float mGestureStartX, mGestureStartY; // where did you first touch the screen?
-    private int mGestureStartChallengeBottom; // where was the challenge at that time?
-
-    private int mDragHandleClosedBelow; // handle hitrect extension into the challenge view
-    private int mDragHandleClosedAbove; // extend the handle's hitrect this far above the line
-    private int mDragHandleOpenBelow; // handle hitrect extension into the challenge view
-    private int mDragHandleOpenAbove; // extend the handle's hitrect this far above the line
-
-    private int mDragHandleEdgeSlop;
-    private int mChallengeBottomBound; // Number of pixels from the top of the challenge view
-                                       // that should remain on-screen
-
-    private int mTouchSlop;
-    private int mTouchSlopSquare;
-
-    float mHandleAlpha;
-    float mFrameAlpha;
-    float mFrameAnimationTarget = Float.MIN_VALUE;
-    private ObjectAnimator mHandleAnimation;
-    private ObjectAnimator mFrameAnimation;
-
-    private boolean mHasGlowpad;
-    private final Rect mInsets = new Rect();
-
-    // We have an internal and external version, and we and them together.
-    private boolean mChallengeInteractiveExternal = true;
-    private boolean mChallengeInteractiveInternal = true;
-
-    static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
-            new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
-        @Override
-        public void setValue(SlidingChallengeLayout view, float value) {
-            view.mHandleAlpha = value;
-            view.invalidate();
-        }
-
-        @Override
-        public Float get(SlidingChallengeLayout view) {
-            return view.mHandleAlpha;
-        }
-    };
-
-    // True if at least one layout pass has happened since the view was attached.
-    private boolean mHasLayout;
-
-    private static final Interpolator sMotionInterpolator = new Interpolator() {
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t * t * t * t * t + 1.0f;
-        }
-    };
-
-    private static final Interpolator sHandleFadeInterpolator = new Interpolator() {
-        public float getInterpolation(float t) {
-            return t * t;
-        }
-    };
-
-    private final Runnable mEndScrollRunnable = new Runnable () {
-        public void run() {
-            completeChallengeScroll();
-        }
-    };
-
-    private final OnClickListener mScrimClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            hideBouncer();
-        }
-    };
-
-    private final OnClickListener mExpandChallengeClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (!isChallengeShowing()) {
-                showChallenge(true);
-            }
-        }
-    };
-
-    /**
-     * Listener interface that reports changes in scroll state of the challenge area.
-     */
-    public interface OnChallengeScrolledListener {
-        /**
-         * The scroll state itself changed.
-         *
-         * <p>scrollState will be one of the following:</p>
-         *
-         * <ul>
-         * <li><code>SCROLL_STATE_IDLE</code> - The challenge area is stationary.</li>
-         * <li><code>SCROLL_STATE_DRAGGING</code> - The user is actively dragging
-         * the challenge area.</li>
-         * <li><code>SCROLL_STATE_SETTLING</code> - The challenge area is animating
-         * into place.</li>
-         * </ul>
-         *
-         * <p>Do not perform expensive operations (e.g. layout)
-         * while the scroll state is not <code>SCROLL_STATE_IDLE</code>.</p>
-         *
-         * @param scrollState The new scroll state of the challenge area.
-         */
-        public void onScrollStateChanged(int scrollState);
-
-        /**
-         * The precise position of the challenge area has changed.
-         *
-         * <p>NOTE: It is NOT safe to modify layout or call any View methods that may
-         * result in a requestLayout anywhere in your view hierarchy as a result of this call.
-         * It may be called during drawing.</p>
-         *
-         * @param scrollPosition New relative position of the challenge area.
-         *                       1.f = fully visible/ready to be interacted with.
-         *                       0.f = fully invisible/inaccessible to the user.
-         * @param challengeTop Position of the top edge of the challenge view in px in the
-         *                     SlidingChallengeLayout's coordinate system.
-         */
-        public void onScrollPositionChanged(float scrollPosition, int challengeTop);
-    }
-
-    public SlidingChallengeLayout(Context context) {
-        this(context, null);
-    }
-
-    public SlidingChallengeLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SlidingChallengeLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mScroller = new Scroller(context, sMotionInterpolator);
-
-        final ViewConfiguration vc = ViewConfiguration.get(context);
-        mMinVelocity = vc.getScaledMinimumFlingVelocity();
-        mMaxVelocity = vc.getScaledMaximumFlingVelocity();
-
-        final Resources res = getResources();
-        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
-
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mTouchSlopSquare = mTouchSlop * mTouchSlop;
-
-        mDisplayMetrics = res.getDisplayMetrics();
-        final float density = mDisplayMetrics.density;
-
-        // top half of the lock icon, plus another 25% to be sure
-        mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
-        mDragHandleClosedBelow = (int) (DRAG_HANDLE_CLOSED_BELOW * density + 0.5f);
-        mDragHandleOpenAbove = (int) (DRAG_HANDLE_OPEN_ABOVE * density + 0.5f);
-        mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
-
-        // how much space to account for in the handle when closed
-        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
-
-        setWillNotDraw(false);
-        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-    }
-
-    public void setEnableChallengeDragging(boolean enabled) {
-        mEnableChallengeDragging = enabled;
-    }
-
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-    }
-
-    public void setHandleAlpha(float alpha) {
-        if (mExpandChallengeView != null) {
-            mExpandChallengeView.setAlpha(alpha);
-        }
-    }
-
-    public void setChallengeInteractive(boolean interactive) {
-        mChallengeInteractiveExternal = interactive;
-        if (mExpandChallengeView != null) {
-            mExpandChallengeView.setEnabled(interactive);
-        }
-    }
-
-    void animateHandle(boolean visible) {
-        if (mHandleAnimation != null) {
-            mHandleAnimation.cancel();
-            mHandleAnimation = null;
-        }
-        final float targetAlpha = visible ? 1.f : 0.f;
-        if (targetAlpha == mHandleAlpha) {
-            return;
-        }
-        mHandleAnimation = ObjectAnimator.ofFloat(this, HANDLE_ALPHA, targetAlpha);
-        mHandleAnimation.setInterpolator(sHandleFadeInterpolator);
-        mHandleAnimation.setDuration(HANDLE_ANIMATE_DURATION);
-        mHandleAnimation.start();
-    }
-
-    private void sendInitialListenerUpdates() {
-        if (mScrollListener != null) {
-            int challengeTop = mChallengeView != null ? mChallengeView.getTop() : 0;
-            mScrollListener.onScrollPositionChanged(mChallengeOffset, challengeTop);
-            mScrollListener.onScrollStateChanged(mScrollState);
-        }
-    }
-
-    public void setOnChallengeScrolledListener(OnChallengeScrolledListener listener) {
-        mScrollListener = listener;
-        if (mHasLayout) {
-            sendInitialListenerUpdates();
-        }
-    }
-
-    public void setOnBouncerStateChangedListener(OnBouncerStateChangedListener listener) {
-        mBouncerListener = listener;
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        mHasLayout = false;
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        removeCallbacks(mEndScrollRunnable);
-        mHasLayout = false;
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        if (mIsBouncing && child != mChallengeView) {
-            // Clear out of the bouncer if the user tries to move focus outside of
-            // the security challenge view.
-            hideBouncer();
-        }
-        super.requestChildFocus(child, focused);
-    }
-
-    // We want the duration of the page snap animation to be influenced by the distance that
-    // the screen has to travel, however, we don't want this duration to be effected in a
-    // purely linear fashion. Instead, we use this method to moderate the effect that the distance
-    // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
-        f -= 0.5f; // center the values about 0.
-        f *= 0.3f * Math.PI / 2.0f;
-        return (float) Math.sin(f);
-    }
-
-    void setScrollState(int state) {
-        if (mScrollState != state) {
-            mScrollState = state;
-
-            animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
-            if (mScrollListener != null) {
-                mScrollListener.onScrollStateChanged(state);
-            }
-        }
-    }
-
-    void completeChallengeScroll() {
-        setChallengeShowing(mChallengeShowingTargetState);
-        mChallengeOffset = mChallengeShowing ? 1.f : 0.f;
-        setScrollState(SCROLL_STATE_IDLE);
-        mChallengeInteractiveInternal = true;
-        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    void setScrimView(View scrim) {
-        if (mScrimView != null) {
-            mScrimView.setOnClickListener(null);
-        }
-        mScrimView = scrim;
-        if (mScrimView != null) {
-            mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
-            mScrimView.setFocusable(true);
-            mScrimView.setOnClickListener(mScrimClickListener);
-        }
-    }
-
-    /**
-     * Animate the bottom edge of the challenge view to the given position.
-     *
-     * @param y desired final position for the bottom edge of the challenge view in px
-     * @param velocity velocity in
-     */
-    void animateChallengeTo(int y, int velocity) {
-        if (mChallengeView == null) {
-            // Nothing to do.
-            return;
-        }
-
-        cancelTransitionsInProgress();
-
-        mChallengeInteractiveInternal = false;
-        enableHardwareLayerForChallengeView();
-        final int sy = mChallengeView.getBottom();
-        final int dy = y - sy;
-        if (dy == 0) {
-            completeChallengeScroll();
-            return;
-        }
-
-        setScrollState(SCROLL_STATE_SETTLING);
-
-        final int childHeight = mChallengeView.getHeight();
-        final int halfHeight = childHeight / 2;
-        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dy) / childHeight);
-        final float distance = halfHeight + halfHeight *
-                distanceInfluenceForSnapDuration(distanceRatio);
-
-        int duration = 0;
-        velocity = Math.abs(velocity);
-        if (velocity > 0) {
-            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
-        } else {
-            final float childDelta = (float) Math.abs(dy) / childHeight;
-            duration = (int) ((childDelta + 1) * 100);
-        }
-        duration = Math.min(duration, MAX_SETTLE_DURATION);
-
-        mScroller.startScroll(0, sy, 0, dy, duration);
-        postInvalidateOnAnimation();
-    }
-
-    private void setChallengeShowing(boolean showChallenge) {
-        if (mChallengeShowing == showChallenge) {
-            return;
-        }
-        mChallengeShowing = showChallenge;
-
-        if (mExpandChallengeView == null || mChallengeView == null) {
-            // These might not be here yet if we haven't been through layout.
-            // If we haven't, the first layout pass will set everything up correctly
-            // based on mChallengeShowing as set above.
-            return;
-        }
-
-        if (mChallengeShowing) {
-            mExpandChallengeView.setVisibility(View.INVISIBLE);
-            mChallengeView.setVisibility(View.VISIBLE);
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                mChallengeView.requestAccessibilityFocus();
-                mChallengeView.announceForAccessibility(mContext.getString(
-                        R.string.keyguard_accessibility_unlock_area_expanded));
-            }
-        } else {
-            mExpandChallengeView.setVisibility(View.VISIBLE);
-            mChallengeView.setVisibility(View.INVISIBLE);
-            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-                mExpandChallengeView.requestAccessibilityFocus();
-                mChallengeView.announceForAccessibility(mContext.getString(
-                        R.string.keyguard_accessibility_unlock_area_collapsed));
-            }
-        }
-    }
-
-    /**
-     * @return true if the challenge is at all visible.
-     */
-    public boolean isChallengeShowing() {
-        return mChallengeShowing;
-    }
-
-    @Override
-    public boolean isChallengeOverlapping() {
-        return mChallengeShowing;
-    }
-
-    @Override
-    public boolean isBouncing() {
-        return mIsBouncing;
-    }
-
-    @Override
-    public int getBouncerAnimationDuration() {
-        return HANDLE_ANIMATE_DURATION;
-    }
-
-    @Override
-    public void showBouncer() {
-        if (mIsBouncing) return;
-        setSystemUiVisibility(getSystemUiVisibility() | STATUS_BAR_DISABLE_SEARCH);
-        mWasChallengeShowing = mChallengeShowing;
-        mIsBouncing = true;
-        showChallenge(true);
-        if (mScrimView != null) {
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
-            anim.setDuration(HANDLE_ANIMATE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mScrimView.setVisibility(VISIBLE);
-                }
-            });
-            anim.start();
-        }
-        if (mChallengeView != null) {
-            mChallengeView.showBouncer(HANDLE_ANIMATE_DURATION);
-        }
-
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(true);
-        }
-    }
-
-    @Override
-    public void hideBouncer() {
-        if (!mIsBouncing) return;
-        setSystemUiVisibility(getSystemUiVisibility() & ~STATUS_BAR_DISABLE_SEARCH);
-        if (!mWasChallengeShowing) showChallenge(false);
-        mIsBouncing = false;
-
-        if (mScrimView != null) {
-            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
-            anim.setDuration(HANDLE_ANIMATE_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mScrimView.setVisibility(GONE);
-                }
-            });
-            anim.start();
-        }
-        if (mChallengeView != null) {
-            mChallengeView.hideBouncer(HANDLE_ANIMATE_DURATION);
-        }
-        if (mBouncerListener != null) {
-            mBouncerListener.onBouncerStateChanged(false);
-        }
-    }
-
-    private int getChallengeMargin(boolean expanded) {
-        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
-    }
-
-    private float getChallengeAlpha() {
-        float x = mChallengeOffset - 1;
-        return x * x * x + 1.f;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
-        // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
-        // If there are one or more pointers in the challenge view before we take over
-        // touch events, onInterceptTouchEvent will set mBlockDrag.
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mGestureStartX = ev.getX();
-                mGestureStartY = ev.getY();
-                mBlockDrag = false;
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                final int count = ev.getPointerCount();
-                for (int i = 0; i < count; i++) {
-                    final float x = ev.getX(i);
-                    final float y = ev.getY(i);
-                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
-                                && (crossedDragHandle(x, y, mGestureStartY)
-                                        && shouldEnableChallengeDragging()
-                                        || (isInChallengeView(x, y) &&
-                                        mScrollState == SCROLL_STATE_SETTLING))) {
-                        mActivePointerId = ev.getPointerId(i);
-                        mGestureStartX = x;
-                        mGestureStartY = y;
-                        mGestureStartChallengeBottom = getChallengeBottom();
-                        mDragging = true;
-                        enableHardwareLayerForChallengeView();
-                    } else if (mChallengeShowing && isInChallengeView(x, y)
-                            && shouldEnableChallengeDragging()) {
-                        mBlockDrag = true;
-                    }
-                }
-                break;
-        }
-
-        if (mBlockDrag || isChallengeInteractionBlocked()) {
-            mActivePointerId = INVALID_POINTER;
-            mDragging = false;
-        }
-
-        return mDragging;
-    }
-
-    private boolean shouldEnableChallengeDragging() {
-        return mEnableChallengeDragging || !mChallengeShowing;
-    }
-
-    private boolean isChallengeInteractionBlocked() {
-        return !mChallengeInteractiveExternal || !mChallengeInteractiveInternal;
-    }
-
-    private void resetTouch() {
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-        mActivePointerId = INVALID_POINTER;
-        mDragging = mBlockDrag = false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mBlockDrag = false;
-                mGestureStartX = ev.getX();
-                mGestureStartY = ev.getY();
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                if (mDragging && !isChallengeInteractionBlocked()) {
-                    showChallenge(0);
-                }
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_POINTER_UP:
-                if (mActivePointerId != ev.getPointerId(ev.getActionIndex())) {
-                    break;
-                }
-            case MotionEvent.ACTION_UP:
-                if (mDragging && !isChallengeInteractionBlocked()) {
-                    mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
-                    showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
-                }
-                resetTouch();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (!mDragging && !mBlockDrag && !mIsBouncing) {
-                    final int count = ev.getPointerCount();
-                    for (int i = 0; i < count; i++) {
-                        final float x = ev.getX(i);
-                        final float y = ev.getY(i);
-
-                        if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
-                                (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
-                                && mActivePointerId == INVALID_POINTER
-                                && !isChallengeInteractionBlocked()) {
-                            mGestureStartX = x;
-                            mGestureStartY = y;
-                            mActivePointerId = ev.getPointerId(i);
-                            mGestureStartChallengeBottom = getChallengeBottom();
-                            mDragging = true;
-                            enableHardwareLayerForChallengeView();
-                            break;
-                        }
-                    }
-                }
-                // Not an else; this can be set above.
-                if (mDragging) {
-                    // No-op if already in this state, but set it here in case we arrived
-                    // at this point from either intercept or the above.
-                    setScrollState(SCROLL_STATE_DRAGGING);
-
-                    final int index = ev.findPointerIndex(mActivePointerId);
-                    if (index < 0) {
-                        // Oops, bogus state. We lost some touch events somewhere.
-                        // Just drop it with no velocity and let things settle.
-                        resetTouch();
-                        showChallenge(0);
-                        return true;
-                    }
-                    final float y = ev.getY(index);
-                    final float pos = Math.min(y - mGestureStartY,
-                            getLayoutBottom() - mChallengeBottomBound);
-
-                    moveChallengeTo(mGestureStartChallengeBottom + (int) pos);
-                }
-                break;
-        }
-        return true;
-    }
-
-    /**
-     * The lifecycle of touch events is subtle and it's very easy to do something
-     * that will cause bugs that will be nasty to track when overriding this method.
-     * Normally one should always override onInterceptTouchEvent instead.
-     *
-     * To put it another way, don't try this at home.
-     */
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        final int action = ev.getActionMasked();
-        boolean handled = false;
-        if (action == MotionEvent.ACTION_DOWN) {
-            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
-            mEdgeCaptured = false;
-        }
-        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
-            // Normally we would need to do a lot of extra stuff here.
-            // We can only get away with this because we haven't padded in
-            // the widget pager or otherwise transformed it during layout.
-            // We also don't support things like splitting MotionEvents.
-
-            // We set handled to captured even if dispatch is returning false here so that
-            // we don't send a different view a busted or incomplete event stream.
-            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
-        }
-
-        if (!handled && !mEdgeCaptured) {
-            handled = super.dispatchTouchEvent(ev);
-        }
-
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            mEdgeCaptured = false;
-        }
-
-        return handled;
-    }
-
-    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
-        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
-            return false;
-        }
-
-        final float x = ev.getX();
-        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
-    }
-
-    /**
-     * We only want to add additional vertical space to the drag handle when the panel is fully
-     * closed.
-     */
-    private int getDragHandleSizeAbove() {
-        return isChallengeShowing() ? mDragHandleOpenAbove : mDragHandleClosedAbove;
-    }
-    private int getDragHandleSizeBelow() {
-        return isChallengeShowing() ? mDragHandleOpenBelow : mDragHandleClosedBelow;
-    }
-
-    private boolean isInChallengeView(float x, float y) {
-        return isPointInView(x, y, mChallengeView);
-    }
-
-    private boolean isInDragHandle(float x, float y) {
-        return isPointInView(x, y, mExpandChallengeView);
-    }
-
-    private boolean isPointInView(float x, float y, View view) {
-        if (view == null) {
-            return false;
-        }
-        return x >= view.getLeft() && y >= view.getTop()
-                && x < view.getRight() && y < view.getBottom();
-    }
-
-    private boolean crossedDragHandle(float x, float y, float initialY) {
-
-        final int challengeTop = mChallengeView.getTop();
-        final boolean horizOk = x >= 0 && x < getWidth();
-
-        final boolean vertOk;
-        if (mChallengeShowing) {
-            vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
-                    y > challengeTop + getDragHandleSizeBelow();
-        } else {
-            vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
-                    y < challengeTop - getDragHandleSizeAbove();
-        }
-        return horizOk && vertOk;
-    }
-
-    private int makeChildMeasureSpec(int maxSize, int childDimen) {
-        final int mode;
-        final int size;
-        switch (childDimen) {
-            case LayoutParams.WRAP_CONTENT:
-                mode = MeasureSpec.AT_MOST;
-                size = maxSize;
-                break;
-            case LayoutParams.MATCH_PARENT:
-                mode = MeasureSpec.EXACTLY;
-                size = maxSize;
-                break;
-            default:
-                mode = MeasureSpec.EXACTLY;
-                size = Math.min(maxSize, childDimen);
-                break;
-        }
-        return MeasureSpec.makeMeasureSpec(size, mode);
-    }
-
-    @Override
-    protected void onMeasure(int widthSpec, int heightSpec) {
-        if (MeasureSpec.getMode(widthSpec) != MeasureSpec.EXACTLY ||
-                MeasureSpec.getMode(heightSpec) != MeasureSpec.EXACTLY) {
-            throw new IllegalArgumentException(
-                    "SlidingChallengeLayout must be measured with an exact size");
-        }
-        final int width = MeasureSpec.getSize(widthSpec);
-        final int height = MeasureSpec.getSize(heightSpec);
-        setMeasuredDimension(width, height);
-
-        final int insetHeight = height - mInsets.top - mInsets.bottom;
-        final int insetHeightSpec = MeasureSpec.makeMeasureSpec(insetHeight, MeasureSpec.EXACTLY);
-
-        // Find one and only one challenge view.
-        final View oldChallengeView = mChallengeView;
-        final View oldExpandChallengeView = mChallengeView;
-        mChallengeView = null;
-        mExpandChallengeView = null;
-        final int count = getChildCount();
-
-        // First iteration through the children finds special children and sets any associated
-        // state.
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                if (mChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child with layout_isChallenge=\"true\"");
-                }
-                if (!(child instanceof KeyguardSecurityContainer)) {
-                            throw new IllegalArgumentException(
-                                    "Challenge must be a KeyguardSecurityContainer");
-                }
-                mChallengeView = (KeyguardSecurityContainer) child;
-                if (mChallengeView != oldChallengeView) {
-                    mChallengeView.setVisibility(mChallengeShowing ? VISIBLE : INVISIBLE);
-                }
-                // We're going to play silly games with the frame's background drawable later.
-                if (!mHasLayout) {
-                    // Set up the margin correctly based on our content for the first run.
-                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
-                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
-                if (mExpandChallengeView != null) {
-                    throw new IllegalStateException(
-                            "There may only be one child with layout_childType"
-                            + "=\"expandChallengeHandle\"");
-                }
-                mExpandChallengeView = child;
-                if (mExpandChallengeView != oldExpandChallengeView) {
-                    mExpandChallengeView.setVisibility(mChallengeShowing ? INVISIBLE : VISIBLE);
-                    mExpandChallengeView.setOnClickListener(mExpandChallengeClickListener);
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                setScrimView(child);
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
-                mWidgetsView = child;
-            }
-        }
-
-        // We want to measure the challenge view first, since the KeyguardWidgetPager
-        // needs to do things its measure pass that are dependent on the challenge view
-        // having been measured.
-        if (mChallengeView != null && mChallengeView.getVisibility() != View.GONE) {
-            // This one's a little funny. If the IME is present - reported in the form
-            // of insets on the root view - we only give the challenge the space it would
-            // have had if the IME wasn't there in order to keep the rest of the layout stable.
-            // We base this on the layout_maxHeight on the challenge view. If it comes out
-            // negative or zero, either we didn't have a maxHeight or we're totally out of space,
-            // so give up and measure as if this rule weren't there.
-            int challengeHeightSpec = insetHeightSpec;
-            final View root = getRootView();
-            if (root != null) {
-                final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
-                final int windowHeight = mDisplayMetrics.heightPixels
-                        - root.getPaddingTop() - mInsets.top;
-                final int diff = windowHeight - insetHeight;
-                final int maxChallengeHeight = lp.maxHeight - diff;
-                if (maxChallengeHeight > 0) {
-                    challengeHeightSpec = makeChildMeasureSpec(maxChallengeHeight, lp.height);
-                }
-            }
-            measureChildWithMargins(mChallengeView, widthSpec, 0, challengeHeightSpec, 0);
-        }
-
-        // Measure the rest of the children
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-            // Don't measure the challenge view twice!
-            if (child == mChallengeView) continue;
-
-            // Measure children. Widget frame measures special, so that we can ignore
-            // insets for the IME.
-            int parentWidthSpec = widthSpec, parentHeightSpec = insetHeightSpec;
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
-                final View root = getRootView();
-                if (root != null) {
-                    // This calculation is super dodgy and relies on several assumptions.
-                    // Specifically that the root of the window will be padded in for insets
-                    // and that the window is LAYOUT_IN_SCREEN.
-                    final int windowWidth = mDisplayMetrics.widthPixels;
-                    final int windowHeight = mDisplayMetrics.heightPixels
-                            - root.getPaddingTop() - mInsets.top;
-                    parentWidthSpec = MeasureSpec.makeMeasureSpec(
-                            windowWidth, MeasureSpec.EXACTLY);
-                    parentHeightSpec = MeasureSpec.makeMeasureSpec(
-                            windowHeight, MeasureSpec.EXACTLY);
-                }
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                // Allow scrim views to extend into the insets
-                parentWidthSpec = widthSpec;
-                parentHeightSpec = heightSpec;
-            }
-            measureChildWithMargins(child, parentWidthSpec, 0, parentHeightSpec, 0);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int paddingLeft = getPaddingLeft();
-        final int paddingTop = getPaddingTop();
-        final int paddingRight = getPaddingRight();
-        final int paddingBottom = getPaddingBottom();
-        final int width = r - l;
-        final int height = b - t;
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == GONE) continue;
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp.childType == LayoutParams.CHILD_TYPE_CHALLENGE) {
-                // Challenge views pin to the bottom, offset by a portion of their height,
-                // and center horizontally.
-                final int center = (paddingLeft + width - paddingRight) / 2;
-                final int childWidth = child.getMeasuredWidth();
-                final int childHeight = child.getMeasuredHeight();
-                final int left = center - childWidth / 2;
-                final int layoutBottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
-                // We use the top of the challenge view to position the handle, so
-                // we never want less than the handle size showing at the bottom.
-                final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
-                        * (1 - mChallengeOffset));
-                child.setAlpha(getChallengeAlpha());
-                child.layout(left, bottom - childHeight, left + childWidth, bottom);
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_EXPAND_CHALLENGE_HANDLE) {
-                final int center = (paddingLeft + width - paddingRight) / 2;
-                final int left = center - child.getMeasuredWidth() / 2;
-                final int right = left + child.getMeasuredWidth();
-                final int bottom = height - paddingBottom - lp.bottomMargin - mInsets.bottom;
-                final int top = bottom - child.getMeasuredHeight();
-                child.layout(left, top, right, bottom);
-            } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
-                // Scrim views use the entire area, including padding & insets
-                child.layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
-            } else {
-                // Non-challenge views lay out from the upper left, layered.
-                child.layout(paddingLeft + lp.leftMargin,
-                        paddingTop + lp.topMargin + mInsets.top,
-                        paddingLeft + child.getMeasuredWidth(),
-                        paddingTop + child.getMeasuredHeight() + mInsets.top);
-            }
-        }
-
-        if (!mHasLayout) {
-            mHasLayout = true;
-        }
-    }
-
-    @Override
-    public void draw(Canvas c) {
-        super.draw(c);
-        if (DEBUG) {
-            final Paint debugPaint = new Paint();
-            debugPaint.setColor(0x40FF00CC);
-            // show the isInDragHandle() rect
-            c.drawRect(mDragHandleEdgeSlop,
-                    mChallengeView.getTop() - getDragHandleSizeAbove(),
-                    getWidth() - mDragHandleEdgeSlop,
-                    mChallengeView.getTop() + getDragHandleSizeBelow(),
-                    debugPaint);
-        }
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        // Focus security fileds before widgets.
-        if (mChallengeView != null &&
-                mChallengeView.requestFocus(direction, previouslyFocusedRect)) {
-            return true;
-        }
-        return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
-    }
-
-    public void computeScroll() {
-        super.computeScroll();
-
-        if (!mScroller.isFinished()) {
-            if (mChallengeView == null) {
-                // Can't scroll if the view is missing.
-                Log.e(TAG, "Challenge view missing in computeScroll");
-                mScroller.abortAnimation();
-                return;
-            }
-
-            mScroller.computeScrollOffset();
-            moveChallengeTo(mScroller.getCurrY());
-
-            if (mScroller.isFinished()) {
-                post(mEndScrollRunnable);
-            }
-        }
-    }
-
-    private void cancelTransitionsInProgress() {
-        if (!mScroller.isFinished()) {
-            mScroller.abortAnimation();
-            completeChallengeScroll();
-        }
-        if (mFader != null) {
-            mFader.cancel();
-        }
-    }
-
-    public void fadeInChallenge() {
-        fadeChallenge(true);
-    }
-
-    public void fadeOutChallenge() {
-        fadeChallenge(false);
-    }
-
-    public void fadeChallenge(final boolean show) {
-        if (mChallengeView != null) {
-
-            cancelTransitionsInProgress();
-            float alpha = show ? 1f : 0f;
-            int duration = show ? CHALLENGE_FADE_IN_DURATION : CHALLENGE_FADE_OUT_DURATION;
-            mFader = ObjectAnimator.ofFloat(mChallengeView, "alpha", alpha);
-            mFader.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    onFadeStart(show);
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onFadeEnd(show);
-                }
-            });
-            mFader.setDuration(duration);
-            mFader.start();
-        }
-    }
-
-    private int getMaxChallengeBottom() {
-        if (mChallengeView == null) return 0;
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getMeasuredHeight();
-
-        return (layoutBottom + challengeHeight - mChallengeBottomBound);
-    }
-
-    private int getMinChallengeBottom() {
-        return getLayoutBottom();
-    }
-
-
-    private void onFadeStart(boolean show) {
-        mChallengeInteractiveInternal = false;
-        enableHardwareLayerForChallengeView();
-
-        if (show) {
-            moveChallengeTo(getMinChallengeBottom());
-        }
-
-        setScrollState(SCROLL_STATE_FADING);
-    }
-
-    private void enableHardwareLayerForChallengeView() {
-        if (mChallengeView.isHardwareAccelerated()) {
-            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-        }
-    }
-
-    private void onFadeEnd(boolean show) {
-        mChallengeInteractiveInternal = true;
-        setChallengeShowing(show);
-
-        if (!show) {
-            moveChallengeTo(getMaxChallengeBottom());
-        }
-
-        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
-        mFader = null;
-        setScrollState(SCROLL_STATE_IDLE);
-    }
-
-    public int getMaxChallengeTop() {
-        if (mChallengeView == null) return 0;
-
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getMeasuredHeight();
-        return layoutBottom - challengeHeight - mInsets.top;
-    }
-
-    /**
-     * Move the bottom edge of mChallengeView to a new position and notify the listener
-     * if it represents a change in position. Changes made through this method will
-     * be stable across layout passes. If this method is called before first layout of
-     * this SlidingChallengeLayout it will have no effect.
-     *
-     * @param bottom New bottom edge in px in this SlidingChallengeLayout's coordinate system.
-     * @return true if the challenge view was moved
-     */
-    private boolean moveChallengeTo(int bottom) {
-        if (mChallengeView == null || !mHasLayout) {
-            return false;
-        }
-
-        final int layoutBottom = getLayoutBottom();
-        final int challengeHeight = mChallengeView.getHeight();
-
-        bottom = Math.max(getMinChallengeBottom(),
-                Math.min(bottom, getMaxChallengeBottom()));
-
-        float offset = 1.f - (float) (bottom - layoutBottom) /
-                (challengeHeight - mChallengeBottomBound);
-        mChallengeOffset = offset;
-        if (offset > 0 && !mChallengeShowing) {
-            setChallengeShowing(true);
-        }
-
-        mChallengeView.layout(mChallengeView.getLeft(),
-                bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
-
-        mChallengeView.setAlpha(getChallengeAlpha());
-        if (mScrollListener != null) {
-            mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
-        }
-        postInvalidateOnAnimation();
-        return true;
-    }
-
-    /**
-     * The bottom edge of this SlidingChallengeLayout's coordinate system; will coincide with
-     * the bottom edge of mChallengeView when the challenge is fully opened.
-     */
-    private int getLayoutBottom() {
-        final int bottomMargin = (mChallengeView == null)
-                ? 0
-                : ((LayoutParams) mChallengeView.getLayoutParams()).bottomMargin;
-        final int layoutBottom = getMeasuredHeight() - getPaddingBottom() - bottomMargin
-                - mInsets.bottom;
-        return layoutBottom;
-    }
-
-    /**
-     * The bottom edge of mChallengeView; essentially, where the sliding challenge 'is'.
-     */
-    private int getChallengeBottom() {
-        if (mChallengeView == null) return 0;
-
-        return mChallengeView.getBottom();
-    }
-
-    /**
-     * Show or hide the challenge view, animating it if necessary.
-     * @param show true to show, false to hide
-     */
-    public void showChallenge(boolean show) {
-        showChallenge(show, 0);
-        if (!show) {
-            // Block any drags in progress so that callers can use this to disable dragging
-            // for other touch interactions.
-            mBlockDrag = true;
-        }
-    }
-
-    private void showChallenge(int velocity) {
-        boolean show = false;
-        if (Math.abs(velocity) > mMinVelocity) {
-            show = velocity < 0;
-        } else {
-            show = mChallengeOffset >= 0.5f;
-        }
-        showChallenge(show, velocity);
-    }
-
-    private void showChallenge(boolean show, int velocity) {
-        if (mChallengeView == null) {
-            setChallengeShowing(false);
-            return;
-        }
-
-        if (mHasLayout) {
-            mChallengeShowingTargetState = show;
-            final int layoutBottom = getLayoutBottom();
-            animateChallengeTo(show ? layoutBottom :
-                    layoutBottom + mChallengeView.getHeight() - mChallengeBottomBound, velocity);
-        }
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams ? new LayoutParams((LayoutParams) p) :
-                p instanceof MarginLayoutParams ? new LayoutParams((MarginLayoutParams) p) :
-                new LayoutParams(p);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    public static class LayoutParams extends MarginLayoutParams {
-        public int childType = CHILD_TYPE_NONE;
-        public static final int CHILD_TYPE_NONE = 0;
-        public static final int CHILD_TYPE_CHALLENGE = 2;
-        public static final int CHILD_TYPE_SCRIM = 4;
-        public static final int CHILD_TYPE_WIDGETS = 5;
-        public static final int CHILD_TYPE_EXPAND_CHALLENGE_HANDLE = 6;
-
-        public int maxHeight;
-
-        public LayoutParams() {
-            this(MATCH_PARENT, WRAP_CONTENT);
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(LayoutParams source) {
-            super(source);
-
-            childType = source.childType;
-        }
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.SlidingChallengeLayout_Layout);
-            childType = a.getInt(R.styleable.SlidingChallengeLayout_Layout_layout_childType,
-                    CHILD_TYPE_NONE);
-            maxHeight = a.getDimensionPixelSize(
-                    R.styleable.SlidingChallengeLayout_Layout_layout_maxHeight, 0);
-            a.recycle();
-        }
-    }
-}
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index ab69a0c..5bbcc8c 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -47,12 +47,6 @@
     void setNeedsInput(boolean needsInput);
 
     /**
-     * Tell view mediator that the keyguard view's desired user activity timeout
-     * has changed and needs to be reapplied to the window.
-     */
-    void onUserActivityTimeoutChanged();
-
-    /**
      * Report that the keyguard is dismissable, pending the next keyguardDone call.
      */
     void keyguardDonePending();
@@ -68,6 +62,11 @@
     void readyForKeyguardDone();
 
     /**
+     * Reset the keyguard and bouncer.
+     */
+    void resetKeyguard();
+
+    /**
      * Play the "device trusted" sound.
      */
     void playTrustedSound();
diff --git a/packages/PrintSpooler/jni/Android.mk b/packages/PrintSpooler/jni/Android.mk
index fe7d06b..9fd4c84 100644
--- a/packages/PrintSpooler/jni/Android.mk
+++ b/packages/PrintSpooler/jni/Android.mk
@@ -16,4 +16,6 @@
 LOCAL_MODULE := libprintspooler_jni
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index 57281c8..b5d9138 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -79,7 +79,7 @@
     throwException(env, className, message);
 }
 
-static void readBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+static void readBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, jint fd) {
     // Read the info.
     AndroidBitmapInfo readInfo;
     bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo));
@@ -127,7 +127,7 @@
     }
 }
 
-static void writeBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+static void writeBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, jint fd) {
     // Get the info.
     AndroidBitmapInfo info;
     int result = AndroidBitmap_getInfo(env, jbitmap, &info);
diff --git a/packages/PrintSpooler/res/layout/print_activity_controls.xml b/packages/PrintSpooler/res/layout/print_activity_controls.xml
index 0bf64aa..a87afe0 100644
--- a/packages/PrintSpooler/res/layout/print_activity_controls.xml
+++ b/packages/PrintSpooler/res/layout/print_activity_controls.xml
@@ -159,6 +159,34 @@
                 android:layout_marginEnd="16dip"
                 android:orientation="vertical">
 
+                <!-- Duplex -->
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dip"
+                    android:layout_marginStart="12dip"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:labelFor="@+id/duplex_spinner"
+                    android:text="@string/label_duplex">
+                </TextView>
+
+                <Spinner
+                    android:id="@+id/duplex_spinner"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="4dip">
+                </Spinner>
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="16dip"
+                android:layout_marginEnd="16dip"
+                android:orientation="vertical">
+
                 <!-- Range options -->
 
                 <TextView
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 1a840e3..482bd22 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oriëntasie"</string>
     <string name="label_pages" msgid="7768589729282182230">"Bladsye"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Al <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Voeg drukker by"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Kies drukker"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Vergeet drukker"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> drukker gekry"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> drukkers gekry"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> drukkers gevind</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> drukker gevind</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Kies drukdiens"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Geen drukkers gekry nie"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukker het <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeer"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>-uitdruktaak"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>-uitdruktake"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-druktake</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>-druktaak</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Kanselleer"</string>
     <string name="restart" msgid="2472034227037808749">"Herbegin"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Swart en wit"</item>
     <item msgid="2762241247228983754">"Kleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Geen"</item>
+    <item msgid="7296563835355641719">"Lang rand"</item>
+    <item msgid="79513688117503758">"Kort rand"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Landskap"</item>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index 683d585..588c337 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"አቀማመጠ ገፅ"</string>
     <string name="label_pages" msgid="7768589729282182230">"ገፆች"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ሁሉም <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -33,7 +34,7 @@
     <string name="install_for_print_preview" msgid="6366303997385509332">"ለቅድመ-እይታ የፒ ዲ ኤፍ መመልከቻ ይጫኑ"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"የአታሚ መተግበሪያ ተበላሽቷል"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"የህትመት ስራን በማመንጨት ላይ"</string>
-    <string name="save_as_pdf" msgid="5718454119847596853">"እንደ ፒዲኤፍ አስቀምጥ"</string>
+    <string name="save_as_pdf" msgid="5718454119847596853">"እንደ PDF አስቀምጥ"</string>
     <string name="all_printers" msgid="5018829726861876202">"ሁሉም አታሚዎች…"</string>
     <string name="print_dialog" msgid="32628687461331979">"የህትመት መገናኛ"</string>
     <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"አታሚ አክል"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"አታሚ ምረጥ"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"አታሚ እርሳ"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚ ተገኝቷል"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚዎች ተገኝተዋል"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"የህትመት አገልግሎት ይምረጡ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ምንም አታሚዎች አልተገኙም"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"አታሚ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን አግዷል"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራ"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራዎች"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ይቅር"</string>
     <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ጥቁር እና ነጭ"</item>
     <item msgid="2762241247228983754">"ቀለም"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ምንም"</item>
+    <item msgid="7296563835355641719">"ረጅም ጠርዝ"</item>
+    <item msgid="79513688117503758">"አጭር ጠርዝ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"የቁም"</item>
     <item msgid="3199660090246166812">"የወርድ"</item>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 0a7d301..83d5994 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"مزدوج"</string>
     <string name="label_orientation" msgid="2853142581990496477">"الاتجاه"</string>
     <string name="label_pages" msgid="7768589729282182230">"الصفحات"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"جميع الصفحات وعددها <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,14 @@
     <string name="print_add_printer" msgid="1088656468360653455">"إضافة طابعة"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> طابعة"</item>
-    <item quantity="other" msgid="6533817036607128241">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> من الطابعات"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="zero">لم يتم العثور على أية طابعة (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+      <item quantity="two">تم العثور على طابعتين (<xliff:g id="COUNT_1">%1$s</xliff:g>)</item>
+      <item quantity="few">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعات</item>
+      <item quantity="many">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> طابعة</item>
+      <item quantity="other">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> من الطابعات</item>
+      <item quantity="one">تم العثور على طابعة واحدة (<xliff:g id="COUNT_0">%1$s</xliff:g>)</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"اختر خدمة طباعة"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"لم يتم العثور على طابعات"</string>
@@ -64,10 +69,14 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"رفضت الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> مهمة طباعة"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> من مهام الطباعة"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item>
+      <item quantity="two">مهمتا طباعة (<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>)</item>
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهام طباعة</item>
+      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> من مهام الطباعة</item>
+      <item quantity="one">مهمة طباعة واحدة (<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>)</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"إلغاء"</string>
     <string name="restart" msgid="2472034227037808749">"إعادة تشغيل"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"لا يوجد اتصال بالطابعة"</string>
@@ -77,6 +86,11 @@
     <item msgid="7602948745415174937">"أبيض وأسود"</item>
     <item msgid="2762241247228983754">"ملونة"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"لا شيء"</item>
+    <item msgid="7296563835355641719">"حافة طويلة"</item>
+    <item msgid="79513688117503758">"حافة قصيرة"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"عمودي"</item>
     <item msgid="3199660090246166812">"أفقي"</item>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 8792349..5df95cb 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Двустранен режим"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страници"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Всички <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Добавяне на принтер"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Избиране на принтер"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Забравяне на принтера"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Намерен е <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
-    <item quantity="other" msgid="6533817036607128241">"Намерени са <xliff:g id="COUNT">%1$s</xliff:g> принтера"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Намерени са <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+      <item quantity="one">Намерен е <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Избиране на услуга за отпечатване"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Търсят се принтери"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Няма намерени принтери"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтерът блокира при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Задание за отпечатване: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Задания за отпечатване: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Задания за отпечатване: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Задание за отпечатване: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Отказ"</string>
     <string name="restart" msgid="2472034227037808749">"Рестартиране"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Няма връзка с принтера"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Черно-бяло"</item>
     <item msgid="2762241247228983754">"Цветно"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Без"</item>
+    <item msgid="7296563835355641719">"Дълъг ръб"</item>
+    <item msgid="79513688117503758">"Къс ръб"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Вертикално"</item>
     <item msgid="3199660090246166812">"Хоризонтално"</item>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 5c5fabf..cf6ed72 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"দ্বৈত"</string>
     <string name="label_orientation" msgid="2853142581990496477">"সজ্জা"</string>
     <string name="label_pages" msgid="7768589729282182230">"পৃষ্ঠাগুলি"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"সমস্ত <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"মুদ্রক যোগ করুন"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"মুদ্রক নির্বাচন করুন"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"মুদ্রকটিকে সরিয়ে দিন"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"মুদ্রণ পরিষেবা চয়ন করুন"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"কোনো মুদ্রক পাওয়া যায়নি"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> মুদ্রণ কার্য"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> মুদ্রণ কার্যগুলি"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"বাতিল করুন"</string>
     <string name="restart" msgid="2472034227037808749">"পুনর্সূচনা"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"মুদ্রকে কোনো সংযোগ নেই"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"কালো এবং সাদা"</item>
     <item msgid="2762241247228983754">"রঙ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"কোনো কিছুই নয়"</item>
+    <item msgid="7296563835355641719">"দীর্ঘ প্রান্ত"</item>
+    <item msgid="79513688117503758">"সংক্ষিপ্ত প্রান্ত"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"প্রতিকৃতি"</item>
     <item msgid="3199660090246166812">"ভূদৃশ্য"</item>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index 6d66b86..04c3b90 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -24,12 +24,13 @@
     <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_duplex" msgid="1263181386446435253">"Dúplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientació"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pàgines"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Totes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
     <string name="template_page_range" msgid="428638530038286328">"Interval de: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"p. ex. 1-5, 8, 11-13"</string>
-    <string name="print_preview" msgid="8010217796057763343">"Visualització prèvia impressió"</string>
+    <string name="print_preview" msgid="8010217796057763343">"Previsualització impressió"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"Instal·la un lector de PDF per a visualitz. prèvia"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"L\'aplicació d\'impressió ha fallat"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"Generant tasca impressió"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Afegeix una impressora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esborra la impressora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"S\'ha trobat <xliff:g id="COUNT">%1$s</xliff:g> impressora"</item>
-    <item quantity="other" msgid="6533817036607128241">"S\'han trobat <xliff:g id="COUNT">%1$s</xliff:g> impressores"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
+      <item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Selecció del servei d\'impressió"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Cerca d\'impressores"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No s\'ha trobat cap impressora"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impressora bloquejada <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tasca d\'impressió per a <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tasques d\'impressió per a <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tasques d\'impressió</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tasca d\'impressió</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel·la"</string>
     <string name="restart" msgid="2472034227037808749">"Reinicia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanc i negre"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Cap"</item>
+    <item msgid="7296563835355641719">"Costat llarg"</item>
+    <item msgid="79513688117503758">"Costat curt"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horitzontal"</item>
@@ -85,5 +91,5 @@
     <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionat. Torna-ho a provar."</string>
     <string name="print_error_retry" msgid="1426421728784259538">"Torna-ho a provar"</string>
     <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ara mateix, aquesta impressora no està disponible."</string>
-    <string name="print_preparing_preview" msgid="3939930735671364712">"S\'està preparant la visualització prèvia..."</string>
+    <string name="print_preparing_preview" msgid="3939930735671364712">"S\'està preparant la previsualització..."</string>
 </resources>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 791e485..ca528c1 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Oboustranně"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientace"</string>
     <string name="label_pages" msgid="7768589729282182230">"Stránky"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Vše: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Přidat tiskárnu"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Vybrat tiskárnu"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Odstranit tiskárnu"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-    <item quantity="other" msgid="6533817036607128241">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="few">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="many">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="other">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="one">Nalezené tiskárny: <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Zvolte službu tisku"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhledávání tiskáren"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nebyly nalezeny žádné tiskárny"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskárna blokuje úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Počet tiskových úloh: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Počet tiskových úloh: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="few">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="many">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Zrušit"</string>
     <string name="restart" msgid="2472034227037808749">"Restartovat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Černobíle"</item>
     <item msgid="2762241247228983754">"Barevně"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Žádné"</item>
+    <item msgid="7296563835355641719">"Dlouhý okraj"</item>
+    <item msgid="79513688117503758">"Krátký okraj"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Na výšku"</item>
     <item msgid="3199660090246166812">"Na šířku"</item>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index c4a383e..6b539d7 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sider"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Tilføj printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Vælg printer"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Glem printer"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
-    <item quantity="other" msgid="6533817036607128241">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printere"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+      <item quantity="other">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Vælg udskriftstjeneste"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Der blev ikke fundet nogen printere"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeren har blokeret <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>-udskriftsjob"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>-udskriftsjobs"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuller"</string>
     <string name="restart" msgid="2472034227037808749">"Genstart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Sort/hvid"</item>
     <item msgid="2762241247228983754">"Farve"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Den lange led"</item>
+    <item msgid="79513688117503758">"Den korte led"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggende"</item>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 43be3dc..e3894c4 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ausrichtung"</string>
     <string name="label_pages" msgid="7768589729282182230">"Seiten"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Drucker hinzufügen"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Drucker auswählen"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Drucker wieder vergessen"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> Drucker gefunden</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> Drucker gefunden</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Druckdienst auswählen"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Keine Drucker gefunden"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drucker hat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blockiert."</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Druckauftrag \"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>\""</item>
-    <item quantity="other" msgid="8746611264734222865">"Druckaufträge \"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>\""</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Druckaufträge \"<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>\"</item>
+      <item quantity="one">Druckauftrag \"<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>\"</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Abbrechen"</string>
     <string name="restart" msgid="2472034227037808749">"Neu starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Schwarz-weiß"</item>
     <item msgid="2762241247228983754">"Farbe"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ohne"</item>
+    <item msgid="7296563835355641719">"Lange Seite"</item>
+    <item msgid="79513688117503758">"Kurze Seite"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Hochformat"</item>
     <item msgid="3199660090246166812">"Querformat"</item>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 25f609b..ff2fe4e 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Δύο πλευρές"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Προσανατολισμός"</string>
     <string name="label_pages" msgid="7768589729282182230">"Σελίδες"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Και οι <xliff:g id="PAGE_COUNT">%1$s</xliff:g> σελίδες"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Προσθήκη εκτυπωτή"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Επιλογή εκτυπωτή"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Διαγραφή εκτυπωτή"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Βρέθηκε <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτής"</item>
-    <item quantity="other" msgid="6533817036607128241">"Βρέθηκαν <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτές"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Βρέθηκαν <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
+      <item quantity="one">Βρέθηκε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτής</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Επιλέξτε υπηρεσία εκτύπωσης"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Δεν βρέθηκαν εκτυπωτές"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Ο εκτυπωτής απέκλεισε <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"εργασία εκτύπωσης <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"εργασίες εκτύπωσης <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> εργασίες εκτύπωσης</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> εργασία εκτύπωσης</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Ακύρωση"</string>
     <string name="restart" msgid="2472034227037808749">"Επανεκκίνηση"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Δεν υπάρχει σύνδεση με εκτυπωτή"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Ασπρόμαυρο"</item>
     <item msgid="2762241247228983754">"Χρώμα"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Κανένα"</item>
+    <item msgid="7296563835355641719">"Μεγάλη πλευρά"</item>
+    <item msgid="79513688117503758">"Μικρή πλευρά"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Πορτραίτο"</item>
     <item msgid="3199660090246166812">"Οριζόντια"</item>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 2198c7a..e5721b2 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
     <string name="label_color" msgid="1108690305218188969">"Colour"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"All <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> print job"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> print jobs"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel"</string>
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Colour"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"None"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 2198c7a..e5721b2 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
     <string name="label_color" msgid="1108690305218188969">"Colour"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"All <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> print job"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> print jobs"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel"</string>
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Colour"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"None"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index e194f55..cc275de 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Doble faz"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Agregar impresora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Se encontró <xliff:g id="COUNT">%1$s</xliff:g> impresora."</item>
-    <item quantity="other" msgid="6533817036607128241">"Se encontraron <xliff:g id="COUNT">%1$s</xliff:g> impresoras."</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
+      <item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Elegir servicio de impresión"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora bloqueó <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>."</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Trabajo de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Trabajos de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Trabajos de impresión: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Trabajo de impresión: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanco y negro"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ninguno"</item>
+    <item msgid="7296563835355641719">"Borde largo"</item>
+    <item msgid="79513688117503758">"Borde corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index b0ab529..13417a4 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Doble cara"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Añadir impresora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Borrar impresora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Se ha encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresora"</item>
-    <item quantity="other" msgid="6533817036607128241">"Se han encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresoras"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+      <item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Seleccionar servicio de impresión"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora ha bloqueado <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Trabajo de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Trabajos de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Trabajos de impresión <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Trabajo de impresión <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Volver a empezar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Blanco y negro"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ninguna"</item>
+    <item msgid="7296563835355641719">"Borde largo"</item>
+    <item msgid="79513688117503758">"Borde corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 6e75bbb..dde4f3b 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dupleksrežiim"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suund"</string>
     <string name="label_pages" msgid="7768589729282182230">"Lehed"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kõik <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Lisa printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Printeri valimine"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Printeri unustamine"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
-    <item quantity="other" msgid="6533817036607128241">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printerit"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Leiti <xliff:g id="COUNT_1">%1$s</xliff:g> printerit</item>
+      <item quantity="one">Leiti <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Prinditeenuse valimine"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Printereid ei leitud"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blokeeris töö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Prinditööd <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prinditööd</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> prinditöö</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Tühista"</string>
     <string name="restart" msgid="2472034227037808749">"Taaskäivita"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Mustvalge"</item>
     <item msgid="2762241247228983754">"Värv"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Puudub"</item>
+    <item msgid="7296563835355641719">"Pikk serv"</item>
+    <item msgid="79513688117503758">"Lühike serv"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertikaalpaigutus"</item>
     <item msgid="3199660090246166812">"Horisontaalpaigutus"</item>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 4f0f8fc..3cc1b64 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Paperaren tamaina"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Paperaren tamaina:"</string>
     <string name="label_color" msgid="1108690305218188969">"Koloretan"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Bikoitza"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientazioa"</string>
     <string name="label_pages" msgid="7768589729282182230">"Orriak"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> orriak"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Gehitu inprimagailua"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Hautatu inprimagailua"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Ahaztu inprimagailua"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> inprimagailu aurkitu da"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> inprimagailu aurkitu dira"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitu dira</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitu da</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Aukeratu inprimatze-zerbitzua"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ez da inprimagailurik aurkitu"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Inprimag. <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blokeatu du"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> inprimatze-lana"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> inprimatze-lanak"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> inprimatze-lanak</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> inprimatze-lana</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Utzi"</string>
     <string name="restart" msgid="2472034227037808749">"Berrabiarazi"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Inprimagailua ez dago konektatuta"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Zuri-beltza"</item>
     <item msgid="2762241247228983754">"Koloretakoa"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Bat ere ez"</item>
+    <item msgid="7296563835355641719">"Ertz luzetik"</item>
+    <item msgid="79513688117503758">"Ertz laburretik"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Bertikala"</item>
     <item msgid="3199660090246166812">"Horizontala"</item>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index d35a063..c47a75a 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"دوبلکس"</string>
     <string name="label_orientation" msgid="2853142581990496477">"جهت"</string>
     <string name="label_pages" msgid="7768589729282182230">"صفحه‌ها"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"همه <xliff:g id="PAGE_COUNT">%1$s</xliff:g> صفحه"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"افزودن چاپگر"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"انتخاب چاپگر"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"فراموش کردن چاپگر"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"انتخاب سرویس چاپ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"در حال جستجو برای چاپگرها"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"هیچ چاپگری یافت نشد"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"چاپگر، کار <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> را مسدود کرد"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"کار چاپ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"کارهای چاپ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"لغو"</string>
     <string name="restart" msgid="2472034227037808749">"راه‌اندازی مجدد"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"اتصال با چاپگر برقرار نیست"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"سیاه و سفید"</item>
     <item msgid="2762241247228983754">"رنگی"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"هیچ‌کدام"</item>
+    <item msgid="7296563835355641719">"طول"</item>
+    <item msgid="79513688117503758">"عرض"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"عمودی"</item>
     <item msgid="3199660090246166812">"افقی"</item>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 8e540f9..6c88534 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Suunta"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sivut"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kaikki <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Lisää tulostin"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Valitse tulostin"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Unohda tulostin"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostin"</item>
-    <item quantity="other" msgid="6533817036607128241">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostinta"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta löydetty</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> tulostin löydetty</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Valitse tulostuspalvelu"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tulostimia ei löydy"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tulostin esti työn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tulostustyö <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tulostustyöt <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tulostustyötä</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tulostustyö</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Peruuta"</string>
     <string name="restart" msgid="2472034227037808749">"Käynnistä uudelleen"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Mustavalkoinen"</item>
     <item msgid="2762241247228983754">"Väri"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ei mitään"</item>
+    <item msgid="7296563835355641719">"Pitkä reuna"</item>
+    <item msgid="79513688117503758">"Lyhyt reuna"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pysty"</item>
     <item msgid="3199660090246166812">"Vaaka"</item>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 279a467..dbc1ea3 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toutes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours..."</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> » bloquée"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tâche d\'impression <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tâches d\'impression <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuler"</string>
     <string name="restart" msgid="2472034227037808749">"Recommencer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Noir et blanc"</item>
     <item msgid="2762241247228983754">"Couleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Aucune"</item>
+    <item msgid="7296563835355641719">"Bord long"</item>
+    <item msgid="79513688117503758">"Bord court"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Paysage"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index ebfd5de..cc0c352 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Recto verso"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pages"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toutes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée."</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées."</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" bloquée"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> tâche d\'impression"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> tâches d\'impression"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuler"</string>
     <string name="restart" msgid="2472034227037808749">"Redémarrer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Noir et blanc"</item>
     <item msgid="2762241247228983754">"Couleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Aucun"</item>
+    <item msgid="7296563835355641719">"Bord long"</item>
+    <item msgid="79513688117503758">"Bord court"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Paysage"</item>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 6e542ea..0e3d9f5 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Tamaño do papel"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño do papel:"</string>
     <string name="label_color" msgid="1108690305218188969">"Cor"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Dobre cara"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páxinas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"As <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Engadir impresora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impresora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Encontrouse <xliff:g id="COUNT">%1$s</xliff:g> impresora"</item>
-    <item quantity="other" msgid="6533817036607128241">"Encontráronse <xliff:g id="COUNT">%1$s</xliff:g> impresoras"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Encontráronse <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
+      <item quantity="one">Encontrouse <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Escoller servizo de impresión"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Busca de impresoras"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Non se atopou ningunha impresora"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impresora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Traballo de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Traballos de impresión <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> traballos de impresión</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> traballo de impresión</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Non hai conexión coa impresora"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Branco e negro"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ningún"</item>
+    <item msgid="7296563835355641719">"Bordo longo"</item>
+    <item msgid="79513688117503758">"Bordo curto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index a3f7fef..5d8c3c6 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"डुप्‍लेक्‍स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिविन्‍यास"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सभी <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"प्रिंटर जोड़ें"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"प्रिंटर चुनें"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"प्रिंटर को भूल जाएं"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिला"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिले"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"प्रिंट सेवा चुनें"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कोई प्रिंटर नहीं मिले"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटर अवरोधित <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> प्रिंट कार्य"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> प्रिंट कार्य"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"रहने दें"</string>
     <string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"श्याम और श्वेत"</item>
     <item msgid="2762241247228983754">"रंग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"कोई नहीं"</item>
+    <item msgid="7296563835355641719">"लंबा सिरा"</item>
+    <item msgid="79513688117503758">"छोटा सिरा"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोर्ट्रेट"</item>
     <item msgid="3199660090246166812">"लैंडस्केप"</item>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 8132d21..79eb2eb 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Obostrano"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
     <string name="label_pages" msgid="7768589729282182230">"Stranice"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Sve stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,11 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj pisač"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Odaberite pisač"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravite pisač"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Pronađen je <xliff:g id="COUNT">%1$s</xliff:g> pisač"</item>
-    <item quantity="other" msgid="6533817036607128241">"Pronađen je sljedeći broj pisača: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Pronađen je <xliff:g id="COUNT_1">%1$s</xliff:g> pisač</item>
+      <item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+      <item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Odaberite uslugu ispisa"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje pisača"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan pisač"</string>
@@ -64,10 +66,11 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pisač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Zadatak ispisa <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Broj zadataka ispisa: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatak ispisa</item>
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatka ispisa</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadataka ispisa</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Odustani"</string>
     <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string>
@@ -77,6 +80,11 @@
     <item msgid="7602948745415174937">"Crno-bijelo"</item>
     <item msgid="2762241247228983754">"U boji"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ništa"</item>
+    <item msgid="7296563835355641719">"Dulji rub"</item>
+    <item msgid="79513688117503758">"Kraći rub"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Pejzaž"</item>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 3ebc450..91182cf 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Kétoldalas"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Tájolás"</string>
     <string name="label_pages" msgid="7768589729282182230">"Oldalak"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Összes (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Nyomtató hozzáadása"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Nyomtató kiválasztása"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Nyomtató elfelejtése"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató észlelve</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató észlelve</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Nyomtatási szolgáltatás kiválasztása"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Nyomtatók keresése"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nem található nyomtató"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> letiltva."</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> – nyomtatási feladat"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> – nyomtatási feladatok"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> nyomtatási feladat</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> nyomtatási feladat</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Mégse"</string>
     <string name="restart" msgid="2472034227037808749">"Újraindítás"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Fekete-fehér"</item>
     <item msgid="2762241247228983754">"Szín"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nincs"</item>
+    <item msgid="7296563835355641719">"Hosszabb él"</item>
+    <item msgid="79513688117503758">"Rövidebb él"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Álló"</item>
     <item msgid="3199660090246166812">"Fekvő"</item>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 5ef15a5c..5babfe1 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Երկակի"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Դիրքավորում"</string>
     <string name="label_pages" msgid="7768589729282182230">"Էջեր"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Բոլորը՝ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Ավելացնել տպիչ"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Ընտրել տպիչ"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Մոռանալ տպիչը"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
+      <item quantity="other">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Ընտրեք տպելու ծառայությունը"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Տպիչներ չեն գտնվել"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Տպիչն արգելափակել է <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> տպման աշխատանք"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> տպման աշխատանքներ"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Չեղարկել"</string>
     <string name="restart" msgid="2472034227037808749">"Վերագործարկել"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Տպիչի հետ կապ չկա"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Սև ու սպիտակ"</item>
     <item msgid="2762241247228983754">"Գույնը"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ոչ մեկը"</item>
+    <item msgid="7296563835355641719">"Լայնեզր"</item>
+    <item msgid="79513688117503758">"Կարճեզր"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Դիմանկար"</item>
     <item msgid="3199660090246166812">"Լանդշաֆտ"</item>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 9714b0f..d6d505d 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="7768589729282182230">"Halaman"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Semua dari <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Tambahkan printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Pilih printer"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan printer"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer ditemukan</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer ditemukan</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Pilih layanan cetak"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tidak ditemukan printer"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer memblokir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tugas cetak <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tugas cetak <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Tugas cetak <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Tugas cetak <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Batal"</string>
     <string name="restart" msgid="2472034227037808749">"Mulai Ulang"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Hitam &amp; Putih"</item>
     <item msgid="2762241247228983754">"Warna"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Tidak ada"</item>
+    <item msgid="7296563835355641719">"Tepi panjang"</item>
+    <item msgid="79513688117503758">"Tepi pendek"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Potret"</item>
     <item msgid="3199660090246166812">"Lanskap"</item>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 41a047d..dbe05bc 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Pappírsstærð"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Pappírsstærð:"</string>
     <string name="label_color" msgid="1108690305218188969">"Litur"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Tvíhliða"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Stefna"</string>
     <string name="label_pages" msgid="7768589729282182230">"Síður"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Allar <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Bæta við prentara"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Veldu prentara"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Gleyma prentara"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> prentari fannst"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> prentarar fundust"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> prentari fannst</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> prentarar fundust</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Veldu prentþjónustu"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Engir prentarar fundust"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Prentari útilokaði <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> prentverk"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> prentverk"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Hætta við"</string>
     <string name="restart" msgid="2472034227037808749">"Endurræsa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Engin tenging við prentara"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svarthvítt"</item>
     <item msgid="2762241247228983754">"Í lit"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ekki í boði"</item>
+    <item msgid="7296563835355641719">"Langhlið"</item>
+    <item msgid="79513688117503758">"Skammhlið"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Skammsnið"</item>
     <item msgid="3199660090246166812">"Langsnið"</item>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 3653c56..ff388ca 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Due tonalità (Duplex)"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientamento"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagine"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Tutte e <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Aggiungi stampante"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> stampante trovata"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> stampanti trovate"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Scegli servizio di stampa"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Ricerca di stampanti"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nessuna stampante trovata"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La stampante ha bloccato <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Processo di stampa <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Processi di stampa <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> processi di stampa</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> processo di stampa</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annulla"</string>
     <string name="restart" msgid="2472034227037808749">"Riavvia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Bianco e nero"</item>
     <item msgid="2762241247228983754">"A colori"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nessuno"</item>
+    <item msgid="7296563835355641719">"Lato lungo"</item>
+    <item msgid="79513688117503758">"Lato corto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Verticale"</item>
     <item msgid="3199660090246166812">"Orizzontale"</item>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index ba293a0..b103e2b 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"דו-צדדי"</string>
     <string name="label_orientation" msgid="2853142581990496477">"כיוון"</string>
     <string name="label_pages" msgid="7768589729282182230">"עמודים"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"הכל <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"הוסף מדפסת"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"בחר מדפסת"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"שכח את המדפסת"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"נמצאה מדפסת <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-    <item quantity="other" msgid="6533817036607128241">"נמצאו <xliff:g id="COUNT">%1$s</xliff:g> מדפסות"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="two">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="many">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="other">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
+      <item quantity="one">נמצאה מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"בחר שירות הדפסה"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"לא נמצאו מדפסות"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"המדפסת חסמה את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"עבודת הדפסה <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> עבודות הדפסה"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="two"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="many"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one"> עבודת הדפסה <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"בטל"</string>
     <string name="restart" msgid="2472034227037808749">"הפעל מחדש"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"אין חיבור למדפסת"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"שחור ולבן"</item>
     <item msgid="2762241247228983754">"צבע"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ללא"</item>
+    <item msgid="7296563835355641719">"צד ארוך"</item>
+    <item msgid="79513688117503758">"צד קצר"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"לאורך"</item>
     <item msgid="3199660090246166812">"לרוחב"</item>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index f3fed3b..d782a16 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"両面印刷"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"ページ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ページすべて"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"プリンタを追加"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"プリンタを選択"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"プリンタを切断"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>台のプリンタが見つかりました</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>台のプリンタが見つかりました</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"印刷サービスの選択"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"プリンタが見つかりません"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をブロックしました"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>の印刷ジョブ"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>の印刷ジョブ"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>の印刷ジョブ</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>の印刷ジョブ</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"キャンセル"</string>
     <string name="restart" msgid="2472034227037808749">"再試行"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"プリンタに接続されていません"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"モノクロ"</item>
     <item msgid="2762241247228983754">"カラー"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"なし"</item>
+    <item msgid="7296563835355641719">"長辺"</item>
+    <item msgid="79513688117503758">"短辺"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"縦向き"</item>
     <item msgid="3199660090246166812">"横向き"</item>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 061e9fb..928ab6f 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"დუპლექსი"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ორიენტაცია"</string>
     <string name="label_pages" msgid="7768589729282182230">"გვერდები"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ყველა <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"პრინტერის დამატება"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"პრინტერის არჩევა"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"პრინტერის დავიწყება"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
-    <item quantity="other" msgid="6533817036607128241">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"აირჩიეთ ბეჭდვის სერვისი"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"პრინტერები ვერ მოიძებნა"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"პრინტერმა დაბლოკა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"ბეჭდვის <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> დავალება"</item>
-    <item quantity="other" msgid="8746611264734222865">"ბეჭდვის <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> დავალება"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ბეჭდვის დავალება</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ბეჭდვის დავალება</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"გაუქმება"</string>
     <string name="restart" msgid="2472034227037808749">"გადატვირთვა"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"პრინტერთან კავშირი არ არის"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"შავ-თეთრი"</item>
     <item msgid="2762241247228983754">"ფერი"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"არც ერთი"</item>
+    <item msgid="7296563835355641719">"გრძელი კიდე"</item>
+    <item msgid="79513688117503758">"მოკლე კიდე"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"პორტრეტი"</item>
     <item msgid="3199660090246166812">"პეიზაჟის რეჟიმი"</item>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index b02714b..8548048 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Дуплексті"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Бағыты"</string>
     <string name="label_pages" msgid="7768589729282182230">"Беттер"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Барлық <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Принтер қосу"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Принтер таңдау"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Принтерді ұмытып кету"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер табылды"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтерлер табылды"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Принтер қызметін таңдау"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ешқандай принтер табылмады"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын бөгеді"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> басып шығару жұмысы"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> басып шығару жұмыстары"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> баспа тапсырмасы</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> баспа тапсырмасы</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Тоқтату"</string>
     <string name="restart" msgid="2472034227037808749">"Қайта бастау"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтермен байланыс жоқ"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Қара &amp; Ақ"</item>
     <item msgid="2762241247228983754">"Түс"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ешқандай"</item>
+    <item msgid="7296563835355641719">"Ұзын жиек"</item>
+    <item msgid="79513688117503758">"Қысқа жиек"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Портреттік"</item>
     <item msgid="3199660090246166812">"Ландшафт"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 63d710a..b600916 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ឌុប"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ទិស"</string>
     <string name="label_pages" msgid="7768589729282182230">"ទំព័រ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> ទាំងអស់"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"បន្ថែម​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"ជ្រើស​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"ភ្លេច​​ម៉ាស៊ីន​បោះពុម្ព"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-    <item quantity="other" msgid="6533817036607128241">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
+      <item quantity="one">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"ជ្រើស​សេវា​បោះពុម្ព"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ស្វែងរក​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"រក​មិន​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការ​បោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុស​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ម៉ាស៊ីន​បោះពុម្ព​បាន​ទប់ស្កាត់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"ការងារ​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"ការងារ​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"បោះបង់"</string>
     <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើម​ឡើងវិញ"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព​"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ស &amp; ខ្មៅ"</item>
     <item msgid="2762241247228983754">"ពណ៌"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"គ្មាន"</item>
+    <item msgid="7296563835355641719">"គែម​វែង"</item>
+    <item msgid="79513688117503758">"គែម​ខ្លី"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"បញ្ឈរ"</item>
     <item msgid="3199660090246166812">"ផ្ដេក"</item>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 3950866..67b0e58 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ಡ್ಯೂಪ್ಲೆಕ್ಸ್"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ಓರಿಯಂಟೇಶನ್"</string>
     <string name="label_pages" msgid="7768589729282182230">"ಪುಟಗಳು"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ಎಲ್ಲಾ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"ಮುದ್ರಕವನ್ನು ಸೇರಿಸು"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"ಮುದ್ರಕವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"ಮುದ್ರಕವನ್ನು ಮರೆತುಬಿಡು"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> ಮುದ್ರಕ ಕಂಡುಬಂದಿದೆ"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> ಮುದ್ರಕಗಳು ಕಂಡುಬಂದಿವೆ"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್‌ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"ಮುದ್ರಣ ಸೇವೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ಮುದ್ರಕಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ಯಾವುದೇ ಮುದ್ರಕಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ಮುದ್ರಕವು <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ನಿರ್ಬಂಧಿಸಿದೆ"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯ"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ರದ್ದುಮಾಡು"</string>
     <string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ಮುದ್ರಕಕ್ಕೆ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ಕಪ್ಪು &amp; ಬಿಳುಪು"</item>
     <item msgid="2762241247228983754">"ಬಣ್ಣ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ಯಾವುದೂ ಇಲ್ಲ"</item>
+    <item msgid="7296563835355641719">"ಉದ್ದವಾದ ಅಂಚು"</item>
+    <item msgid="79513688117503758">"ಚಿಕ್ಕದಾದ ಅಂಚು"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ಪೋಟ್ರೇಟ್"</item>
     <item msgid="3199660090246166812">"ಲ್ಯಾಂಡ್‌ಸ್ಕೇಪ್"</item>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index f1a4869..7d03c44 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"양면"</string>
     <string name="label_orientation" msgid="2853142581990496477">"방향"</string>
     <string name="label_pages" msgid="7768589729282182230">"페이지"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>페이지 모두"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"프린터 추가"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"프린터 선택"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"프린터 삭제"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
-    <item quantity="other" msgid="6533817036607128241">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">프린터 <xliff:g id="COUNT_1">%1$s</xliff:g>대 검색됨</item>
+      <item quantity="one">프린터 <xliff:g id="COUNT_0">%1$s</xliff:g>대 검색됨</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"인쇄 서비스 선택"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"프린터 없음"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"차단된 프린터: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 인쇄 작업"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 인쇄 작업"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 인쇄 작업</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 인쇄 작업</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"취소"</string>
     <string name="restart" msgid="2472034227037808749">"다시 시작"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"프린터와 연결되지 않음"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"흑백"</item>
     <item msgid="2762241247228983754">"컬러"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"없음"</item>
+    <item msgid="7296563835355641719">"옆으로 넘김"</item>
+    <item msgid="79513688117503758">"위로 넘김"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"세로"</item>
     <item msgid="3199660090246166812">"가로"</item>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 602f6605..9053529 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Кош тараптуу"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Багыттоо"</string>
     <string name="label_pages" msgid="7768589729282182230">"Баракчалар"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Бардыгы <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Принтер кошуу"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Принтер тандоо"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Принтерди унутуу"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер табылды"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтер табылды"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Принтер кызматын тандоо"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтерлер табылган жок"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер бөгөттөдү: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> басуу тапшырмасы"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> басуу тапшырмалары"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> басуу тапшырмасы</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> басуу тапшырмасы</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Айнуу"</string>
     <string name="restart" msgid="2472034227037808749">"Кайра баштоо"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер менен байланыш жок"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Кара-ак"</item>
     <item msgid="2762241247228983754">"Түстүү"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Эч бири"</item>
+    <item msgid="7296563835355641719">"Узун кыр"</item>
+    <item msgid="79513688117503758">"Кыска кыр"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Тикесинен"</item>
     <item msgid="3199660090246166812">"Туурасынан"</item>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 3a3f6bb..c8aed29 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ສອງ​ໜ້າ"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ລວງ"</string>
     <string name="label_pages" msgid="7768589729282182230">"ໜ້າ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ທັງ​ໝົດ <xliff:g id="PAGE_COUNT">%1$s</xliff:g> ໜ້າ"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"ເພີ່ມເຄື່ອງພິມ"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"ເລືອກເຄື່ອງພິມ"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"ລືມເຄື່ອງພິມ"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
-    <item quantity="other" msgid="6533817036607128241">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງ​ພິມ​ຖືກ​ພົບ​ແລ້ວ</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງ​ພິມ​ຖືກ​ພົບ​ແລ້ວ</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"ເລືອກບໍລິການການພິມ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ບໍ່ພົບເຄື່ອງພິມ"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ເຄື່ອງພິມຖືກບລອກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"ງານພິມ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"ງານພິມ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ງານ​ພິມ</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ງານ​ພິມ</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ຍົກເລີກ"</string>
     <string name="restart" msgid="2472034227037808749">"ປິດເປີດໃໝ່"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ບໍ່ມີການເຊື່ອມຕໍ່ຫາເຄື່ອງພິມ"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ຂາວດຳ"</item>
     <item msgid="2762241247228983754">"ສີ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ບໍ່ມີ"</item>
+    <item msgid="7296563835355641719">"ຂອບຍາວ"</item>
+    <item msgid="79513688117503758">"ຂອບສັ້ນ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ລວງຕັ້ງ"</item>
     <item msgid="3199660090246166812">"ລວງນອນ"</item>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 6262a15..f2ca5b7 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dvipusis"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacija"</string>
     <string name="label_pages" msgid="7768589729282182230">"Puslapiai"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Visi <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Pridėti spausdintuvą"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Pasirinkti spausdintuvą"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Pamiršti spausdintuvą"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-    <item quantity="other" msgid="6533817036607128241">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Rastas <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvas</item>
+      <item quantity="few">Rasti <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvai</item>
+      <item quantity="many">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
+      <item quantity="other">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Pasirinkite spausdinimo paslaugą"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nerasta spausdintuvų"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Spausdintuvas užblokavo: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Spausdinimo užduotis: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Spausdinimo užduotys: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotis</item>
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotys</item>
+      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduoties</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduočių</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Atšaukti"</string>
     <string name="restart" msgid="2472034227037808749">"Paleisti iš naujo"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Nespalvotas"</item>
     <item msgid="2762241247228983754">"Spalva"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nėra"</item>
+    <item msgid="7296563835355641719">"Ilgasis kraštas"</item>
+    <item msgid="79513688117503758">"Trumpasis kraštas"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stačias"</item>
     <item msgid="3199660090246166812">"Gulsčias"</item>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3a60ee5..cc49244f 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dubults"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Virziens"</string>
     <string name="label_pages" msgid="7768589729282182230">"Lapas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Visas <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,11 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Pievienot printeri"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Atlasīt printeri"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Neatcerēties printeri"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Atrasts <xliff:g id="COUNT">%1$s</xliff:g> printeris"</item>
-    <item quantity="other" msgid="6533817036607128241">"Atrasti <xliff:g id="COUNT">%1$s</xliff:g> printeri"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="zero">Atrasti <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
+      <item quantity="one">Atrasts <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
+      <item quantity="other">Atrasti <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Izvēlieties drukāšanas pakalpojumu"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Netika atrasts neviens printeris."</string>
@@ -64,10 +66,11 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeris bloķēja darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Drukas darbs <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Drukas darbi <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbs</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Atcelt"</string>
     <string name="restart" msgid="2472034227037808749">"Restartēt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string>
@@ -77,6 +80,11 @@
     <item msgid="7602948745415174937">"Melnbalts"</item>
     <item msgid="2762241247228983754">"Krāsa"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nav"</item>
+    <item msgid="7296563835355641719">"Garā mala"</item>
+    <item msgid="79513688117503758">"Īsā mala"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrets"</item>
     <item msgid="3199660090246166812">"Ainava"</item>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index 91b5763..43c7c56 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Двострано"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентација"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страници"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Сите <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Додај печатач"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Избери печатач"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Заборави го печатачот"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Пронајден е <xliff:g id="COUNT">%1$s</xliff:g> печатач"</item>
-    <item quantity="other" msgid="6533817036607128241">"Пронајдени се <xliff:g id="COUNT">%1$s</xliff:g> печатачи"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
+      <item quantity="other">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Избери услуга печатење"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Не се пронајдени печатачи"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Печатачот го блокираше <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Печати <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Печати <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работа за печатење</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работи за печатење</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Откажи"</string>
     <string name="restart" msgid="2472034227037808749">"Рестартирај"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема поврзување со печатач"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Црно-бела"</item>
     <item msgid="2762241247228983754">"Во боја"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Нема"</item>
+    <item msgid="7296563835355641719">"Долг раб"</item>
+    <item msgid="79513688117503758">"Краток раб"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Портрет"</item>
     <item msgid="3199660090246166812">"Пејзаж"</item>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index a06ca7d..9b577a0 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"രണ്ടുഭാഗങ്ങളുള്ളത്"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ഓറിയന്‍റേഷന്‍‌"</string>
     <string name="label_pages" msgid="7768589729282182230">"പേജുകൾ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"എല്ലാ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"പ്രിന്റർ ചേർക്കുക"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"പ്രിന്റർ തിരഞ്ഞെടുക്കുക"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"പ്രിന്റർ മറന്നു"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തി"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തി"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തി</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തി</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"പ്രിന്റ് സേവനം തിരഞ്ഞെടുക്കുക"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"പ്രിന്ററുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"പ്രിന്റർ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> തടഞ്ഞു"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> പ്രിന്റ് ജോലി"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> പ്രിന്റ് ജോലികൾ"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> പ്രിന്റ് ജോലികൾ</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> പ്രിന്റ് ജോലി</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"റദ്ദാക്കുക"</string>
     <string name="restart" msgid="2472034227037808749">"പുനരാരംഭിക്കുക"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"പ്രിന്ററിൽ കണക്ഷനൊന്നുമില്ല"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"കറുപ്പ് &amp; വെള്ള"</item>
     <item msgid="2762241247228983754">"നിറം"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ഒന്നുമില്ല"</item>
+    <item msgid="7296563835355641719">"നീളമുള്ള അരിക്"</item>
+    <item msgid="79513688117503758">"ഹ്രസ്വ അരിക്"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"പോർട്രെയ്‌റ്റ്"</item>
     <item msgid="3199660090246166812">"ലാൻഡ്‌സ്‌കേപ്പ്"</item>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 022adda..c36eacc 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Хоёр талд нь хэвлэх"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Чиглэл"</string>
     <string name="label_pages" msgid="7768589729282182230">"Хуудас"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Нийт <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Принтер нэмэх"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Принтер сонгох"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Принтерийг мартах"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олдсон байна</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олдсон байна</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Хэвлэх үйлчилгээг сонгох"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтер олдсонгүй"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер хориглогдсон <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> хэвлэх ажил"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> хэвлэх ажлууд"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ажлыг хэвлэх</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ажлыг хэвлэх</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Цуцлах"</string>
     <string name="restart" msgid="2472034227037808749">"Дахин эхлүүлэх"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер холбогдоогүй байна"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Хар &amp; Цагаан"</item>
     <item msgid="2762241247228983754">"Өнгө"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Хоосон"</item>
+    <item msgid="7296563835355641719">"Урт ирмэг"</item>
+    <item msgid="79513688117503758">"Богино ирмэг"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Босоо"</item>
     <item msgid="3199660090246166812">"Хэвтээ"</item>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 1fade66..c79b5d3 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"डुप्लेक्स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिमुखता"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठे"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सर्व <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"प्रिंटर जोडा"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"प्रिंटर निवडा"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"प्रिंटर विसरा"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर आढळला"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर आढळले"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळला</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळले</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"मुद्रण सेवा निवडा"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कोणतेही प्रिंटर आढळले नाही"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> मुद्रण कार्य"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> मुद्रण कार्ये"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्य</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्ये</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"रद्द करा"</string>
     <string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्‍शन नाही"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"कृष्‍ण धवल"</item>
     <item msgid="2762241247228983754">"रंग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"काहीही नाही"</item>
+    <item msgid="7296563835355641719">"दीर्घ किनार"</item>
+    <item msgid="79513688117503758">"लघु किनार"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोट्रेट"</item>
     <item msgid="3199660090246166812">"भूदृश्य"</item>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index a392b76..5111beb 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
     <string name="label_pages" msgid="7768589729282182230">"Halaman"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Semua <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Tambah pencetak"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Pilih pencetak"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan pencetak"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> pencetak ditemui</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> pencetak ditemui</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Pilih perkhidmatan cetak"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tiada pencetak ditemui"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pencetak disekat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Kerja cetakan <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Kerja cetakan <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Batal"</string>
     <string name="restart" msgid="2472034227037808749">"Mulakan semula"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Hitam &amp; Putih"</item>
     <item msgid="2762241247228983754">"Warna"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Tiada"</item>
+    <item msgid="7296563835355641719">"Sisi panjang"</item>
+    <item msgid="79513688117503758">"Sisi pendek"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Potret"</item>
     <item msgid="3199660090246166812">"Landskap"</item>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index d6eb380..fc0c28e 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ဂျူးပလက်စ်"</string>
     <string name="label_orientation" msgid="2853142581990496477">"အနေအထား"</string>
     <string name="label_pages" msgid="7768589729282182230">"စာမျက်နှာများ"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"အားလုံး <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"စာထုတ်စက်ကို ထည့်ပါ"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"စာထုတ်စက်ကို ရွေးရန်"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"စာထုတ်စက်ကို မေ့လိုက်ရန်"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> စာထုတ်စက် တွေ့ရှိပါသည်"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> စာထုတ်စက်များ တွေ့ရှိပါသည်"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> စာထုတ်စက်များ တွေ့ရှိပါသည်</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>စာထုတ်စက် တွေ့ရှိပါသည်</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"စာထုတ်ရန် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"စာထုတ်စက် တစ်ခုမှ မတွေ့ရှိပါ"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ကိုစာထုတ်စက်ကငြင်းလိုက်သည်"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> စာထုတ်စရာ"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> စာထုတ်စရာများ"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> စာထုတ်စရာများ</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>စာထုတ်စရာ</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ပယ်ဖျက်"</string>
     <string name="restart" msgid="2472034227037808749">"အစက ပြန်စရန်"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"အဖြူ အမည်း"</item>
     <item msgid="2762241247228983754">"ရောင်စုံ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"မရှိ"</item>
+    <item msgid="7296563835355641719">"အနားသတ် အရှည်"</item>
+    <item msgid="79513688117503758">"အနားသတ် အတို"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ထောင်လိုက်"</item>
     <item msgid="3199660090246166812">"အလျားလိုက်"</item>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index bf11068..390a3d7 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sider"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Legg til skriver"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Velg skriver"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Glem skriveren"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skriver ble funnet"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivere ble funnet"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivere ble funnet</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skriver ble funnet</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Velg utskriftstjeneste"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Søker etter skrivere"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Fant ingen skrivere"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skriveren blokkerte <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Utskriftsjobb for <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Utskriftsjobber for <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobber</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Avbryt"</string>
     <string name="restart" msgid="2472034227037808749">"Start på nytt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svart og hvitt"</item>
     <item msgid="2762241247228983754">"Farge"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Langsiden"</item>
+    <item msgid="79513688117503758">"Kortsiden"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggende"</item>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index eb97530..7c4ecb0 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"डुप्लेक्स"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिमुखिकरण"</string>
     <string name="label_pages" msgid="7768589729282182230">"पृष्ठहरू"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सबै <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"प्रिन्टर थप्नुहोस्"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"प्रिन्टर चयन गर्नुहोस्"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"प्रिन्टर बिर्सनुहोस्"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिन्टर भेटाइयो"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिन्टरहरू भेटाइयो"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू भेटिए</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर भेटियो</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"प्रिन्ट सेवा छनौट गर्नुहोस्"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"कुनै प्रिन्टरहरू भेटाइएन"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिन्टर ब्लक गरियो <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> प्रिन्ट कार्य"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> प्रिन्ट कार्यहरु"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> कार्यहरू प्रिन्ट गर्नुहोस्</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> कार्य प्रिन्ट गर्नुहोस्</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"रद्द गर्नुहोस्"</string>
     <string name="restart" msgid="2472034227037808749">"पुनःस्टार्ट गर्नुहोस्"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिन्टरमा कुनै जडान छैन"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"कालो &amp; सेतो"</item>
     <item msgid="2762241247228983754">"रङ्ग"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"कुनै पनि होइन"</item>
+    <item msgid="7296563835355641719">"लामो किनारा"</item>
+    <item msgid="79513688117503758">"छोटो किनारा"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"पोट्रेट"</item>
     <item msgid="3199660090246166812">"परिदृश्य"</item>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 5ea52a0..44ec72c 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Stand"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagina\'s"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alle <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Printer toevoegen"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Printer selecteren"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Printer vergeten"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer gevonden"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers gevonden"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers gevonden</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer gevonden</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Afdrukservice kiezen"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Geen printers gevonden"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeerd door printer"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> afdruktaak"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> afdruktaken"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> afdruktaken</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> afdruktaak</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuleren"</string>
     <string name="restart" msgid="2472034227037808749">"Opnieuw starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Zwart-wit"</item>
     <item msgid="2762241247228983754">"Kleur"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Geen"</item>
+    <item msgid="7296563835355641719">"Lange zijde"</item>
+    <item msgid="79513688117503758">"Korte zijde"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Landschap"</item>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 609e6e9..0365e1d 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dupleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientacja"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strony"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Wszystkie <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj drukarkę"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Wybierz drukarkę"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Nie zapamiętuj drukarki"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Znaleziono <xliff:g id="COUNT">%1$s</xliff:g> drukarkę"</item>
-    <item quantity="other" msgid="6533817036607128241">"Znalezione drukarki: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="few">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+      <item quantity="many">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarek</item>
+      <item quantity="other">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
+      <item quantity="one">Znaleziono <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Wybierz usługę drukowania"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nie znaleziono drukarek"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukarka zablokowała <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> zadanie drukowania"</item>
-    <item quantity="other" msgid="8746611264734222865">"Zadania drukowania: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item>
+      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadań drukowania</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> zadanie drukowania</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Anuluj"</string>
     <string name="restart" msgid="2472034227037808749">"Od nowa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Czarno-białe"</item>
     <item msgid="2762241247228983754">"Kolor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Brak"</item>
+    <item msgid="7296563835355641719">"Długa krawędź"</item>
+    <item msgid="79513688117503758">"Krótka krawędź"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pionowa"</item>
     <item msgid="3199660090246166812">"Pozioma"</item>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 7b47f4c..9f6ccdb 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Frente e verso"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas as <xliff:g id="PAGE_COUNT">%1$s</xliff:g> páginas"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Escolher o serviço de impressão"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"A procurar impressoras"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tarefa de impressão: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tarefas de impressão: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tarefas de impressão</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tarefa de impressão</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Preto e branco"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nenhum"</item>
+    <item msgid="7296563835355641719">"Limite grande"</item>
+    <item msgid="79513688117503758">"Limite curto"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Vertical"</item>
     <item msgid="3199660090246166812">"Horizontal"</item>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 3038a7f..31a24ea 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
     <string name="label_pages" msgid="7768589729282182230">"Páginas"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Todas as <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Trabalho de impressão <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Trabalhos de impressão <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Preto e branco"</item>
     <item msgid="2762241247228983754">"Cor"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Nenhum"</item>
+    <item msgid="7296563835355641719">"Borda longa"</item>
+    <item msgid="79513688117503758">"Borda curta"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Retrato"</item>
     <item msgid="3199660090246166812">"Paisagem"</item>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 1446a53..efcfc75 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientare"</string>
     <string name="label_pages" msgid="7768589729282182230">"Pagini"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Toate cele <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,11 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Adăugați o imprimantă"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Selectați imprimanta"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Omiteți imprimanta"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantă găsită"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (de) imprimante găsite"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante găsite</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante găsite</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă găsită</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Alegeți serviciul de printare"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nu au fost găsite imprimante"</string>
@@ -64,10 +66,11 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printare blocată: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Sarcină de printare <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Sarcini de printare <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> activități de printare</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> de activități de printare</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> activitate de printare</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Anulați"</string>
     <string name="restart" msgid="2472034227037808749">"Reporniți"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string>
@@ -77,6 +80,11 @@
     <item msgid="7602948745415174937">"Alb-negru"</item>
     <item msgid="2762241247228983754">"Color"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Fără"</item>
+    <item msgid="7296563835355641719">"Latura lungă"</item>
+    <item msgid="79513688117503758">"Latura scurtă"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portret"</item>
     <item msgid="3199660090246166812">"Peisaj"</item>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index c2a19bb..4c8dfdc 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Двусторонняя печать"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="7768589729282182230">"Страницы"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Все <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Добавить принтер"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Выбрать принтер"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Удалить принтер"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Найден <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
-    <item quantity="other" msgid="6533817036607128241">"Найдено принтеров: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Найден <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+      <item quantity="few">Найдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+      <item quantity="many">Найдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
+      <item quantity="other">Найдены <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Ничего не найдено"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Задание \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблокировано"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Задание печати: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Задания печати: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="few">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="many">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Отмена"</string>
     <string name="restart" msgid="2472034227037808749">"Повторить"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нет связи с принтером"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Черно-белая"</item>
     <item msgid="2762241247228983754">"Цветная"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Нет"</item>
+    <item msgid="7296563835355641719">"Длинный край"</item>
+    <item msgid="79513688117503758">"Короткий край"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Книга"</item>
     <item msgid="3199660090246166812">"Альбом"</item>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 386ce8d..855dcd1 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ඩුප්ලෙක්ස්"</string>
     <string name="label_orientation" msgid="2853142581990496477">"දිශානතිය"</string>
     <string name="label_pages" msgid="7768589729282182230">"පිටු"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"සියලුම <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"මුද්‍රණ යන්ත්‍ර එකතු කරන්න"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"මුද්‍රකය තේරීම"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"මුද්‍රකය අමතක කිරීම"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT">%1$s</xliff:g> ක් සොයා ගැනිණි"</item>
-    <item quantity="other" msgid="6533817036607128241">"මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT">%1$s</xliff:g> ක් සොයා ගැනිණි"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
+      <item quantity="other">මුද්‍රණ යන්ත්‍ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"මුද්‍රණ සේවාව තෝරන්න"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"මුද්‍රණ යන්ත්‍ර සොයමින්"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"මුද්‍රණ යන්ත්‍ර සොයා නොගැනුණි"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්‍රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"මුද්‍රණ යන්ත්‍රය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> අවුරා ඇති"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> මුද්‍රණ කාර්යය"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> මුද්‍රණ කාර්යයන්"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one">මුද්‍රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">මුද්‍රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"අවලංගු කරන්න"</string>
     <string name="restart" msgid="2472034227037808749">"යළි අරඹන්න"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"මුද්‍රණ යන්ත්‍රය වෙත සම්බන්ධය නැත"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"කළු සහ සුදු"</item>
     <item msgid="2762241247228983754">"වර්ණය"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"කිසිවක් නැත"</item>
+    <item msgid="7296563835355641719">"දිගු දාරය"</item>
+    <item msgid="79513688117503758">"කෙටි දාරය"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"ප්‍රතිමුර්ති"</item>
     <item msgid="3199660090246166812">"තිරස් දර්ශනය"</item>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 5be2034..a5ff4a9 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientácia"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strany"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Všetky: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Pridať tlačiareň"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Vybrať tlačiareň"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Odstrániť tlačiareň"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Našla sa <xliff:g id="COUNT">%1$s</xliff:g> tlačiareň"</item>
-    <item quantity="other" msgid="6533817036607128241">"Počet nájdených tlačiarní: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="few">Našli sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+      <item quantity="many">Našlo sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarne</item>
+      <item quantity="other">Našlo sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
+      <item quantity="one">Našla sa <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Výber tlačovej služby"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhľadávanie tlačiarní"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nenašli sa žiadne tlačiarne"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tlačiareň zablok. úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Počet tlačových úloh: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Počet tlačových úloh: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačové úlohy</item>
+      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačovej úlohy</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačových úloh</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tlačová úloha</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Zrušiť"</string>
     <string name="restart" msgid="2472034227037808749">"Spustiť znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Čiernobiele"</item>
     <item msgid="2762241247228983754">"Farba"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Žiadne"</item>
+    <item msgid="7296563835355641719">"Dlhý okraj"</item>
+    <item msgid="79513688117503758">"Krátky okraj"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Na výšku"</item>
     <item msgid="3199660090246166812">"Na šírku"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index ee15103..e6d7358 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Obojestransko"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Postavitev"</string>
     <string name="label_pages" msgid="7768589729282182230">"Strani"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Vse (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Dodajanje tiskalnika"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Izbira tiskalnika"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Odstranitev tiskalnika"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Najden <xliff:g id="COUNT">%1$s</xliff:g> tiskalnik"</item>
-    <item quantity="other" msgid="6533817036607128241">"Število najdenih tiskalnikov: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> najden tiskalnik</item>
+      <item quantity="two"><xliff:g id="COUNT_1">%1$s</xliff:g> najdena tiskalnika</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> najdeni tiskalniki</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> najdenih tiskalnikov</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Izberite tiskalno storitev"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Tiskalnikov ni mogoče najti"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskalnik je blokiral <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Tiskalno opravilo: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Tiskalna opravila: <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalno opravilo</item>
+      <item quantity="two"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalni opravili</item>
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalna opravila</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalnih opravil</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Prekliči"</string>
     <string name="restart" msgid="2472034227037808749">"Začni znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Črno-belo"</item>
     <item msgid="2762241247228983754">"Barvno"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Brez"</item>
+    <item msgid="7296563835355641719">"Dolgi rob"</item>
+    <item msgid="79513688117503758">"Kratki rob"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Pokončno"</item>
     <item msgid="3199660090246166812">"Ležeče"</item>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 6ca94aa..677d5e1 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Обострани режим"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Положај"</string>
     <string name="label_pages" msgid="7768589729282182230">"Странице"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Све странице (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,11 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Додај штампач"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Изабери штампач"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Заборави штампач"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Пронађен је <xliff:g id="COUNT">%1$s</xliff:g> штампач"</item>
-    <item quantity="other" msgid="6533817036607128241">"Пронађено је <xliff:g id="COUNT">%1$s</xliff:g> штампача"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Пронађен је <xliff:g id="COUNT_1">%1$s</xliff:g> штампач</item>
+      <item quantity="few">Пронађена су <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+      <item quantity="other">Пронађено је <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Изаберите услугу штампања"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Није пронађен ниједан штампач"</string>
@@ -64,10 +66,11 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Штампач је блокирао <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Задатак штампања <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Задаци штампања <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="few">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="other">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Откажи"</string>
     <string name="restart" msgid="2472034227037808749">"Поново покрени"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема везе са штампачем"</string>
@@ -77,6 +80,11 @@
     <item msgid="7602948745415174937">"Црно-бело"</item>
     <item msgid="2762241247228983754">"Боја"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ништа"</item>
+    <item msgid="7296563835355641719">"Дуга ивица"</item>
+    <item msgid="79513688117503758">"Кратка ивица"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Усправно"</item>
     <item msgid="3199660090246166812">"Водоравно"</item>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 4c439be..cda72e2 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dubbelsidigt"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Orientering"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sidor"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Alla <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Lägg till skrivare"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Välj en skrivare"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Ta bort en skrivare"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivare hittades</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skrivare hittades</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Välj utskriftstjänst"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Det gick inte att hitta några skrivare"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skrivaren har blockerat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Utskriftsjobb – <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Utskriftsjobb – <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobb</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Avbryt"</string>
     <string name="restart" msgid="2472034227037808749">"Starta om"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Svartvit"</item>
     <item msgid="2762241247228983754">"Färg"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Ingen"</item>
+    <item msgid="7296563835355641719">"Långsidan"</item>
+    <item msgid="79513688117503758">"Kortsidan"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Stående"</item>
     <item msgid="3199660090246166812">"Liggande"</item>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index e454704..d784ab6 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Maradufu"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Mkao"</string>
     <string name="label_pages" msgid="7768589729282182230">"Kurasa"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Kurasa zote <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Ongeza printa"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Chagua printa"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Sahau printa"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Printa <xliff:g id="COUNT">%1$s</xliff:g> imepatikana"</item>
-    <item quantity="other" msgid="6533817036607128241">"Printa <xliff:g id="COUNT">%1$s</xliff:g> zimepatikana"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Printa <xliff:g id="COUNT_1">%1$s</xliff:g> zimepatikana</item>
+      <item quantity="one">Printa <xliff:g id="COUNT_0">%1$s</xliff:g> imepatikana</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Chagua huduma ya printa"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Hakuna printa zilizopatikana"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printa imefungwa <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Kazi za kuchapisha za <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> </item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Ghairi"</string>
     <string name="restart" msgid="2472034227037808749">"Anzisha upya"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
     <item msgid="2762241247228983754">"Rangi"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Hamna"</item>
+    <item msgid="7296563835355641719">"Ukingo mrefu"</item>
+    <item msgid="79513688117503758">"Ukingo mfupi"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Wima"</item>
     <item msgid="3199660090246166812">"Mlalo"</item>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index 0421bd6..6f29851 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"டியூப்ளெக்ஸ்"</string>
     <string name="label_orientation" msgid="2853142581990496477">"திசையமைப்பு"</string>
     <string name="label_pages" msgid="7768589729282182230">"பக்கங்கள்"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"எல்லாம்: <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"பிரிண்டரைச் சேர்"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"பிரிண்டரைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"பிரிண்டரை நீக்கு"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> பிரிண்டர் உள்ளது"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> பிரிண்டர்கள் உள்ளன"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்கள் உள்ளன</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டர் உள்ளது</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"அச்சுப் பொறியைத் தேர்வுசெய்யவும்"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"பிரிண்டர்கள் எதுவுமில்லை"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"பிரிண்டர் <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐத் தடுத்தது"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> அச்சுப் பணி"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> அச்சுப் பணிகள்"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> அச்சுப் பணிகள்</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> அச்சுப் பணி</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ரத்துசெய்"</string>
     <string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"அச்சுப்பொறியுடன் இணைக்கப்படவில்லை"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"கருப்பு &amp; வெள்ளை"</item>
     <item msgid="2762241247228983754">"வண்ணம்"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ஏதுமில்லை"</item>
+    <item msgid="7296563835355641719">"லாங் எட்ஜ்"</item>
+    <item msgid="79513688117503758">"ஷார்ட் எட்ஜ்"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"உறுவப்படம்"</item>
     <item msgid="3199660090246166812">"நிலத்தோற்றம்"</item>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index edb6e60..88c83da 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"డూప్లెక్స్"</string>
     <string name="label_orientation" msgid="2853142581990496477">"దృగ్విన్యాసం"</string>
     <string name="label_pages" msgid="7768589729282182230">"పేజీలు"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"మొత్తం <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"ప్రింటర్‌ను జోడించు"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"ప్రింటర్‌ను ఎంచుకోండి"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"ప్రింటర్‌ను విస్మరించు"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> ప్రింటర్ కనుగొనబడింది"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> ప్రింటర్‌లు కనుగొనబడ్డాయి"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్‌లు కనుగొనబడ్డాయి</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్ కనుగొనబడింది</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"ముద్రణ సేవను ఎంచుకోండి"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్‌ల కోసం శోధిస్తోంది"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ప్రింటర్‌లు కనుగొనబడలేదు"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ప్రింటర్ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను బ్లాక్ చేసింది"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> ముద్రణ జాబ్"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> ముద్రణ జాబ్‌లు"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ముద్రణ జాబ్‌లు</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ముద్రణ జాబ్</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"రద్దు చేయి"</string>
     <string name="restart" msgid="2472034227037808749">"పునఃప్రారంభించు"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ప్రింటర్‌కు కనెక్షన్ లేదు"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"నలుపు &amp; తెలుపు"</item>
     <item msgid="2762241247228983754">"రంగు"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ఏదీ వద్దు"</item>
+    <item msgid="7296563835355641719">"పొడవైన అంచు"</item>
+    <item msgid="79513688117503758">"చిన్న అంచు"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"పోర్ట్రెయిట్"</item>
     <item msgid="3199660090246166812">"ల్యాండ్‌స్కేప్"</item>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index cfffa0b..7731a7d 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ดูเพล็กซ์"</string>
     <string name="label_orientation" msgid="2853142581990496477">"การวางแนว"</string>
     <string name="label_pages" msgid="7768589729282182230">"หน้า"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"ทั้ง <xliff:g id="PAGE_COUNT">%1$s</xliff:g> หน้า"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"เพิ่มเครื่องพิมพ์"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"เลือกเครื่องพิมพ์"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"ไม่ต้องจำเครื่องพิมพ์"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
-    <item quantity="other" msgid="6533817036607128241">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">พบเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
+      <item quantity="one">พบเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"เลือกบริการพิมพ์"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"ไม่พบเครื่องพิมพ์"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"เครื่องพิมพ์ได้บล็อก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"งานพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"งานพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> งานพิมพ์</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> งานพิมพ์</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ยกเลิก"</string>
     <string name="restart" msgid="2472034227037808749">"เริ่มต้นใหม่"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ไม่มีการเชื่อมต่อไปยังเครื่องพิมพ์"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"ขาวดำ"</item>
     <item msgid="2762241247228983754">"สี"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"ไม่มี"</item>
+    <item msgid="7296563835355641719">"ขอบยาว"</item>
+    <item msgid="79513688117503758">"ขอบสั้น"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"แนวตั้ง"</item>
     <item msgid="3199660090246166812">"แนวนอน"</item>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index dfb0450..b4bda0c 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Oryentasyon"</string>
     <string name="label_pages" msgid="7768589729282182230">"Mga Page"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Lahat ng <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Magdagdag ng printer"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Piliin ang printer"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Kalimutan ang printer"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ang nakita"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (na) printer ang nakita"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> nakitang printer</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> na nakitang printer</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Pumili ng serbisyo ng pag-print"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Naghahanap ng mga printer"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Walang mga printer na nakita"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Naka-block ang Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Pag-print ng <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Mga pag-print ng <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ipi-print</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> na ipi-print</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Kanselahin"</string>
     <string name="restart" msgid="2472034227037808749">"I-restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Black &amp; White"</item>
     <item msgid="2762241247228983754">"Kulay"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Wala"</item>
+    <item msgid="7296563835355641719">"Long edge"</item>
+    <item msgid="79513688117503758">"Short edge"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Portrait"</item>
     <item msgid="3199660090246166812">"Landscape"</item>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 50befba..9fa7d8e 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Dubleks"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Sayfa yönü"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sayfa"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> sayfanın tamamı"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Yazıcı ekle"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Yazıcı seç"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Yazıcıyı unut"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcı bulundu</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcı bulundu</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Yazdırma hizmetini seçin"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Yazıcılar aranıyor"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Yazıcı bulunamadı"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Yazıcı <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> işini engelledi"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> yazdırma işi"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> yazdırma işleri"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> yazdırma işi</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> yazdırma işi</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"İptal"</string>
     <string name="restart" msgid="2472034227037808749">"Yeniden başlat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Siyah Beyaz"</item>
     <item msgid="2762241247228983754">"Renkli"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Yok"</item>
+    <item msgid="7296563835355641719">"Uzun kenar"</item>
+    <item msgid="79513688117503758">"Kısa kenar"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Dikey"</item>
     <item msgid="3199660090246166812">"Yatay"</item>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 8a924e6..0b283b9 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Двосторонній друк"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Орієнтація"</string>
     <string name="label_pages" msgid="7768589729282182230">"Сторінки"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Усі <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,12 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Додати принтер"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Вибрати принтер"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Ігнорувати принтер"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-    <item quantity="other" msgid="6533817036607128241">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтер</item>
+      <item quantity="few">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтери</item>
+      <item quantity="many">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
+      <item quantity="other">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Принтери не знайдено"</string>
@@ -64,10 +67,12 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблоковано"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Завдання друку <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Завдання друку <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item>
+      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item>
+      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Скасувати"</string>
     <string name="restart" msgid="2472034227037808749">"Перезапустити"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Немає з’єднання з принтером"</string>
@@ -77,6 +82,11 @@
     <item msgid="7602948745415174937">"Чорно-білий"</item>
     <item msgid="2762241247228983754">"Колір"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Немає"</item>
+    <item msgid="7296563835355641719">"Довгий край"</item>
+    <item msgid="79513688117503758">"Короткий край"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Книжкова"</item>
     <item msgid="3199660090246166812">"Альбомна"</item>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 722d027..2b138c1 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"ڈوپلیکس"</string>
     <string name="label_orientation" msgid="2853142581990496477">"سمت بندی"</string>
     <string name="label_pages" msgid="7768589729282182230">"صفحات"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"سبھی <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"پرنٹر شامل کریں"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"پرنٹر منتخب کریں"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"پرنٹر کو بھول جائیں"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> پرنٹر ملا"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> پرنٹرز ملے"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز ملے</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر ملا</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"پرنٹ سروس منتخب کریں"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"کوئی پرنٹرز نہيں ملے"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"پرنٹر نے <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو مسدود کر دیا"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> پرنٹ جاب"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> پرنٹ جابز"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> پرنٹ جابز</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> پرنٹ جاب</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"منسوخ کریں"</string>
     <string name="restart" msgid="2472034227037808749">"دوبارہ شروع کریں"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"پرنٹر کے ساتھ کوئی کنکشن نہیں ہے"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"سیاہ و سفید"</item>
     <item msgid="2762241247228983754">"رنگ"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"کوئی نہیں"</item>
+    <item msgid="7296563835355641719">"طویل کنارہ"</item>
+    <item msgid="79513688117503758">"مختصر کنارہ"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"پورٹریٹ"</item>
     <item msgid="3199660090246166812">"لینڈ اسکیپ"</item>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index f62728f..26b5c9f 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -24,6 +24,7 @@
     <string name="label_paper_size" msgid="908654383827777759">"Qog‘oz o‘lchami"</string>
     <string name="label_paper_size_summary" msgid="5668204981332138168">"Qog‘oz o‘lchami:"</string>
     <string name="label_color" msgid="1108690305218188969">"Rang"</string>
+    <string name="label_duplex" msgid="1263181386446435253">"Ikki tomonlama"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Joylashuv"</string>
     <string name="label_pages" msgid="7768589729282182230">"Sahifalar"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Barchasi (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Printer qo‘shish"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Printerni tanlang"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Printerni unutish"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>ta printer topildi"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>ta printer topildi"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printer topildi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printer topildi</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Chop etish xizmatini tanlang"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Printerlarni izlash"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Printerlar topilmadi"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ni taqiqladi"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> chop etish buyrug‘i"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> chop etish buyruqlari"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> chop qilish vazifalari</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> chop qilish vazifasi</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Bekor qilish"</string>
     <string name="restart" msgid="2472034227037808749">"Qayta boshlash"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printer ulanmagan"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Oq &amp; qora"</item>
     <item msgid="2762241247228983754">"Rang"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Hech biri"</item>
+    <item msgid="7296563835355641719">"Uzun tomoni"</item>
+    <item msgid="79513688117503758">"Qisqa tomoni"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Bo‘yiga"</item>
     <item msgid="3199660090246166812">"Eniga"</item>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index fa0d26e..d6ef07c 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Hai mặt"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Hướng"</string>
     <string name="label_pages" msgid="7768589729282182230">"Trang"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Tất cả <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Thêm máy in"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Chọn máy in"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Bỏ qua máy in"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
-    <item quantity="other" msgid="6533817036607128241">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">Đã tìm thấy <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
+      <item quantity="one">Đã tìm thấy <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Chọn dịch vụ in"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Đang tìm kiếm máy in"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Không tìm thấy máy in"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Máy in đã chặn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"Lệnh in <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-    <item quantity="other" msgid="8746611264734222865">"Lệnh in <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">Lệnh in <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+      <item quantity="one">Lệnh in <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Hủy"</string>
     <string name="restart" msgid="2472034227037808749">"Bắt đầu lại"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Đen trắng"</item>
     <item msgid="2762241247228983754">"Màu"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Không có"</item>
+    <item msgid="7296563835355641719">"Cạnh dài"</item>
+    <item msgid="79513688117503758">"Cạnh ngắn"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Dọc"</item>
     <item msgid="3199660090246166812">"Ngang"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 77ecb21..b6ab6b5 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"双面模式"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"页数"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部<xliff:g id="PAGE_COUNT">%1$s</xliff:g>页"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"添加打印机"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"选择打印机"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"取消保存打印机"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
-    <item quantity="other" msgid="6533817036607128241">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
+      <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"选择打印服务"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到打印机"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印机拒绝打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"“<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>”打印作业"</item>
-    <item quantity="other" msgid="8746611264734222865">"“<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g>”打印作业"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other">“<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>”打印作业</item>
+      <item quantity="one">“<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>”打印作业</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新开始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"未与打印机建立连接"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"无"</item>
+    <item msgid="7296563835355641719">"长边"</item>
+    <item msgid="79513688117503758">"短边"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"纵向"</item>
     <item msgid="3199660090246166812">"横向"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index d2fa629..8f8bf13a 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"雙面列印"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"頁數"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部 <xliff:g id="PAGE_COUNT">%1$s</xliff:g> 頁"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"新增打印機"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"選取打印機"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"移除打印機"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
-    <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">已找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 部打印機</item>
+      <item quantity="one">已找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 部打印機</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到打印機"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印機已封鎖 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"一項 <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 列印工作"</item>
-    <item quantity="other" msgid="8746611264734222865">"多項 <xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 列印工作"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 項列印工作</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 項列印工作</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新開始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與打印機連線"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"無"</item>
+    <item msgid="7296563835355641719">"長邊"</item>
+    <item msgid="79513688117503758">"短邊"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"直向"</item>
     <item msgid="3199660090246166812">"橫向"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 3e26a5e..7872d24 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"雙面"</string>
     <string name="label_orientation" msgid="2853142581990496477">"方向"</string>
     <string name="label_pages" msgid="7768589729282182230">"頁面"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"全部 <xliff:g id="PAGE_COUNT">%1$s</xliff:g> 頁"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"新增印表機"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"選取印表機"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"移除印表機"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
-    <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台印表機</item>
+      <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台印表機</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"找不到印表機"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"印表機封鎖了 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 個列印工作"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> 個列印工作"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 個列印工作</item>
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 個列印工作</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新開始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與印表機建立連線"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"黑白"</item>
     <item msgid="2762241247228983754">"彩色"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"無"</item>
+    <item msgid="7296563835355641719">"長邊"</item>
+    <item msgid="79513688117503758">"短邊"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"縱向"</item>
     <item msgid="3199660090246166812">"橫向"</item>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f8a27bc..ddb953b 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -24,6 +24,7 @@
     <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_duplex" msgid="1263181386446435253">"Duplex"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Umumo"</string>
     <string name="label_pages" msgid="7768589729282182230">"Amakhasi"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"Konke <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
@@ -53,10 +54,10 @@
     <string name="print_add_printer" msgid="1088656468360653455">"Engeza iphrinta"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"Khetha iphrinta"</string>
     <string name="print_forget_printer" msgid="5035287497291910766">"Khohlwa iphrinta"</string>
-  <plurals name="print_search_result_count_utterance">
-    <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> iphrinta itholiwe"</item>
-    <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> amaphrinta atholiwe"</item>
-  </plurals>
+    <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
+    </plurals>
     <string name="choose_print_service" msgid="3740309762324459694">"Khetha isevisi yephrinta"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Awekho amaphrinta atholiwe"</string>
@@ -64,10 +65,10 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Iphrinta engu-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ivinjelwe"</string>
-  <plurals name="composite_notification_title_template">
-    <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> umsebenzi wokuphrinta"</item>
-    <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> imisebenzi yokuphrinta"</item>
-  </plurals>
+    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item>
+      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item>
+    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Khansela"</string>
     <string name="restart" msgid="2472034227037808749">"Qala kabusha"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string>
@@ -77,6 +78,11 @@
     <item msgid="7602948745415174937">"Okumnyama nokumhlophe"</item>
     <item msgid="2762241247228983754">"Umbala"</item>
   </string-array>
+  <string-array name="duplex_mode_labels">
+    <item msgid="3882302912790928315">"Lutho"</item>
+    <item msgid="7296563835355641719">"Emaphethelweni amade"</item>
+    <item msgid="79513688117503758">"Emaphethelweni amafushane"</item>
+  </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"Ukuma ngobude"</item>
     <item msgid="3199660090246166812">"Ukwakheka kwezwe"</item>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index ab633ea..9d67ccc 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -40,6 +40,9 @@
     <!-- Label of the color mode widget. [CHAR LIMIT=20] -->
     <string name="label_color">Color</string>
 
+    <!-- Label of the duplex mode widget. [CHAR LIMIT=20] -->
+    <string name="label_duplex">Duplex</string>
+
     <!-- Label of the orientation widget. [CHAR LIMIT=20] -->
     <string name="label_orientation">Orientation</string>
 
@@ -188,12 +191,22 @@
 
     <!-- Color mode labels. -->
     <string-array name="color_mode_labels">
-        <!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
+        <!-- Color mode label: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
         <item>Black &amp; White</item>
         <!-- Color mode label: Color color scheme, e.g. many colors are used. [CHAR LIMIT=20] -->
         <item>Color</item>
     </string-array>
 
+    <!-- Duplex mode labels. -->
+    <string-array name="duplex_mode_labels">
+        <!-- Duplex mode label: No duplex supported. [CHAR LIMIT=20] -->
+        <item>None</item>
+        <!-- Duplex mode label: Turn page sideways along the long edge like a book. [CHAR LIMIT=20] -->
+        <item>Long edge</item>
+        <!-- Duplex mode label: Turn page upwards along the short edge like a notepad. [CHAR LIMIT=20] -->
+        <item>Short edge</item>
+    </string-array>
+
     <!-- Orientation labels. -->
     <string-array name="orientation_labels">
         <!-- Orientation label: Portrait page orientation. [CHAR LIMIT=30] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
index 8537d6c..06723c3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
@@ -20,9 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.os.Debug;
 import android.os.IBinder;
-import android.util.Log;
 
 public class PrintSpoolerProvider implements ServiceConnection {
     private final Context mContext;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 2cc5e04..377d2d5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -695,6 +695,7 @@
         private static final String TAG_MARGINS = "margins";
 
         private static final String ATTR_COLOR_MODE = "colorMode";
+        private static final String ATTR_DUPLEX_MODE = "duplexMode";
 
         private static final String ATTR_LOCAL_ID = "localId";
         private static final String ATTR_SERVICE_NAME = "serviceName";
@@ -823,6 +824,10 @@
                         serializer.attribute(null, ATTR_COLOR_MODE,
                                 String.valueOf(colorMode));
 
+                        final int duplexMode = attributes.getDuplexMode();
+                        serializer.attribute(null, ATTR_DUPLEX_MODE,
+                                String.valueOf(duplexMode));
+
                         MediaSize mediaSize = attributes.getMediaSize();
                         if (mediaSize != null) {
                             serializer.startTag(null, TAG_MEDIA_SIZE);
@@ -1057,6 +1062,12 @@
                 String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
                 builder.setColorMode(Integer.parseInt(colorMode));
 
+                String duplexMode = parser.getAttributeValue(null, ATTR_DUPLEX_MODE);
+                // Duplex mode was added later, so null check is needed.
+                if (duplexMode != null) {
+                    builder.setDuplexMode(Integer.parseInt(duplexMode));
+                }
+
                 parser.next();
 
                 skipEmptyTextTags(parser);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f3a5c95..4ba04e5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -184,6 +184,9 @@
     private Spinner mColorModeSpinner;
     private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
 
+    private Spinner mDuplexModeSpinner;
+    private ArrayAdapter<SpinnerItem<Integer>> mDuplexModeSpinnerAdapter;
+
     private Spinner mOrientationSpinner;
     private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
 
@@ -767,6 +770,21 @@
                     }
                 }
             }
+
+            // Take the duplex mode only if the current printer supports it.
+            final int currDuplexMode = currAttributes.getDuplexMode();
+            final int newDuplexMode = newAttributes.getDuplexMode();
+            if (currDuplexMode != newDuplexMode) {
+                final int duplexModeCount = mDuplexModeSpinner.getCount();
+                for (int i = 0; i < duplexModeCount; i++) {
+                    final int supportedDuplexMode = mDuplexModeSpinnerAdapter.getItem(i).value;
+                    if (supportedDuplexMode == newDuplexMode) {
+                        currAttributes.setDuplexMode(newDuplexMode);
+                        mDuplexModeSpinner.setSelection(i);
+                        break;
+                    }
+                }
+            }
         }
 
         // Handle selected page changes making sure they are in the doc.
@@ -985,6 +1003,12 @@
             attributes.setColorMode(defaults.getColorMode());
         }
 
+        // Duplex mode.
+        final int duplexMode = attributes.getDuplexMode();
+        if ((capabilities.getDuplexModes() & duplexMode) == 0) {
+            attributes.setDuplexMode(defaults.getDuplexMode());
+        }
+
         // Resolution
         Resolution resolution = attributes.getResolution();
         if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
@@ -1111,6 +1135,13 @@
         mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
         mColorModeSpinner.setOnItemSelectedListener(itemSelectedListener);
 
+        // Duplex mode.
+        mDuplexModeSpinnerAdapter = new ArrayAdapter<>(
+                this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1);
+        mDuplexModeSpinner = (Spinner) findViewById(R.id.duplex_spinner);
+        mDuplexModeSpinner.setAdapter(mDuplexModeSpinnerAdapter);
+        mDuplexModeSpinner.setOnItemSelectedListener(itemSelectedListener);
+
         // Orientation
         mOrientationSpinnerAdapter = new ArrayAdapter<>(
                 this, android.R.layout.simple_spinner_dropdown_item, android.R.id.text1);
@@ -1187,6 +1218,7 @@
             mCopiesEditText.setFocusable(false);
             mMediaSizeSpinner.setEnabled(false);
             mColorModeSpinner.setEnabled(false);
+            mDuplexModeSpinner.setEnabled(false);
             mOrientationSpinner.setEnabled(false);
             mRangeOptionsSpinner.setEnabled(false);
             mPageRangeEditText.setEnabled(false);
@@ -1202,6 +1234,7 @@
             mCopiesEditText.setFocusable(false);
             mMediaSizeSpinner.setEnabled(false);
             mColorModeSpinner.setEnabled(false);
+            mDuplexModeSpinner.setEnabled(false);
             mOrientationSpinner.setEnabled(false);
             mRangeOptionsSpinner.setEnabled(false);
             mPageRangeEditText.setEnabled(false);
@@ -1317,7 +1350,7 @@
                 final int colorMode = 1 << colorBitOffset;
                 if (colorMode == oldColorMode) {
                     // Update the index of the old selection.
-                    oldColorModeNewIndex = colorBitOffset;
+                    oldColorModeNewIndex = mColorModeSpinnerAdapter.getCount();
                 }
                 remainingColorModes &= ~colorMode;
                 mColorModeSpinnerAdapter.add(new SpinnerItem<>(colorMode,
@@ -1339,11 +1372,81 @@
                             mColorModeSpinner.setSelection(i);
                         }
                         attributes.setColorMode(selectedColorMode);
+                        break;
                     }
                 }
             }
         }
 
+        // Duplex mode.
+        mDuplexModeSpinner.setEnabled(true);
+        final int duplexModes = capabilities.getDuplexModes();
+
+        // If the duplex modes changed, we update the adapter and the spinner.
+        // Note that we use bit count +1 to account for the no duplex option.
+        boolean duplexModesChanged = false;
+        if (Integer.bitCount(duplexModes) != mDuplexModeSpinnerAdapter.getCount()) {
+            duplexModesChanged = true;
+        } else {
+            int remainingDuplexModes = duplexModes;
+            int adapterIndex = 0;
+            while (remainingDuplexModes != 0) {
+                final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes);
+                final int duplexMode = 1 << duplexBitOffset;
+                remainingDuplexModes &= ~duplexMode;
+                if (duplexMode != mDuplexModeSpinnerAdapter.getItem(adapterIndex).value) {
+                    duplexModesChanged = true;
+                    break;
+                }
+                adapterIndex++;
+            }
+        }
+        if (duplexModesChanged) {
+            // Remember the old duplex mode to try selecting it again. Also the fallback
+            // is no duplexing which is always the first item in the dropdown.
+            int oldDuplexModeNewIndex = AdapterView.INVALID_POSITION;
+            final int oldDuplexMode = attributes.getDuplexMode();
+
+            // Rebuild the adapter data.
+            mDuplexModeSpinnerAdapter.clear();
+            String[] duplexModeLabels = getResources().getStringArray(R.array.duplex_mode_labels);
+            int remainingDuplexModes = duplexModes;
+            while (remainingDuplexModes != 0) {
+                final int duplexBitOffset = Integer.numberOfTrailingZeros(remainingDuplexModes);
+                final int duplexMode = 1 << duplexBitOffset;
+                if (duplexMode == oldDuplexMode) {
+                    // Update the index of the old selection.
+                    oldDuplexModeNewIndex = mDuplexModeSpinnerAdapter.getCount();
+                }
+                remainingDuplexModes &= ~duplexMode;
+                mDuplexModeSpinnerAdapter.add(new SpinnerItem<>(duplexMode,
+                        duplexModeLabels[duplexBitOffset]));
+            }
+
+            if (oldDuplexModeNewIndex != AdapterView.INVALID_POSITION) {
+                // Select the old duplex mode - nothing really changed.
+                if (mDuplexModeSpinner.getSelectedItemPosition() != oldDuplexModeNewIndex) {
+                    mDuplexModeSpinner.setSelection(oldDuplexModeNewIndex);
+                }
+            } else {
+                // Select the default.
+                final int selectedDuplexMode = defaultAttributes.getDuplexMode();
+                final int itemCount = mDuplexModeSpinnerAdapter.getCount();
+                for (int i = 0; i < itemCount; i++) {
+                    SpinnerItem<Integer> item = mDuplexModeSpinnerAdapter.getItem(i);
+                    if (selectedDuplexMode == item.value) {
+                        if (mDuplexModeSpinner.getSelectedItemPosition() != i) {
+                            mDuplexModeSpinner.setSelection(i);
+                        }
+                        attributes.setDuplexMode(selectedDuplexMode);
+                        break;
+                    }
+                }
+            }
+        }
+
+        mDuplexModeSpinner.setEnabled(mDuplexModeSpinnerAdapter.getCount() > 1);
+
         // Orientation
         mOrientationSpinner.setEnabled(true);
         MediaSize mediaSize = attributes.getMediaSize();
@@ -2173,6 +2276,9 @@
             } else if (spinner == mColorModeSpinner) {
                 SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
                 mPrintJob.getAttributes().setColorMode(colorModeItem.value);
+            } else if (spinner == mDuplexModeSpinner) {
+                SpinnerItem<Integer> duplexModeItem = mDuplexModeSpinnerAdapter.getItem(position);
+                mPrintJob.getAttributes().setDuplexMode(duplexModeItem.value);
             } else if (spinner == mOrientationSpinner) {
                 SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
                 PrintAttributes attributes = mPrintJob.getAttributes();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
index feb0316..6a6f1d3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PreviewPageFrame.java
@@ -48,16 +48,19 @@
     }
 
     @Override
+    public CharSequence getAccessibilityClassName() {
+        return CompoundButton.class.getName();
+    }
+
+    @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        event.setClassName(CompoundButton.class.getName());
         event.setChecked(isSelected());
     }
 
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(CompoundButton.class.getName());
         info.setSelected(false);
         info.setCheckable(true);
         info.setChecked(isSelected());
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
new file mode 100644
index 0000000..0245ed3
--- /dev/null
+++ b/packages/SettingsLib/Android.mk
@@ -0,0 +1,9 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SettingsLib
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml
new file mode 100644
index 0000000..eacafd5
--- /dev/null
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.settingslib">
+</manifest>
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
new file mode 100644
index 0000000..b017047
--- /dev/null
+++ b/packages/SettingsLib/common.mk
@@ -0,0 +1,18 @@
+#
+# Include this make file to build your application against this module.
+#
+# Make sure to include it after you've set all your desired LOCAL variables.
+# Note that you must explicitly set your LOCAL_RESOURCE_DIR before including
+# this file.
+#
+# For example:
+#
+#   LOCAL_RESOURCE_DIR := \
+#        $(LOCAL_PATH)/res
+#
+#   include frameworks/base/packages/SettingsLib/common.mk
+#
+
+LOCAL_RESOURCE_DIR += $(call my-dir)/res
+LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.settingslib
+LOCAL_STATIC_JAVA_LIBRARIES += SettingsLib
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..6e29d23
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..6110e9e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..6cca225
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..6445f2a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..78c0294
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..2fcc3b0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..70d35bf
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..2d9b75e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..b6ebe34
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..8b67b91
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..1fa0a3d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..175bd78
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..05b27e8
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..6e9f8ae
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..5f3371f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..539d77f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..3216776
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..4f381ba
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..c67127d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..d3b356b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..2d38129
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..fb76575
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..d8b68eb
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..02cc3af
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..7805b7a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..8127774
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..84b8085
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..289d6ac
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..72bc804
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..e31ce2b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..f23b0e7
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..1e12f96
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..8b547d9
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..03c5033
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..b9a9923
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..989e1ab
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..de8c389
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..2eb8a92
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
new file mode 100644
index 0000000..a52ed69
--- /dev/null
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Wi-Fi settings -->
+
+    <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
+    <!-- Wi-Fi settings. The status messages when the network is unknown. -->
+    <string-array name="wifi_status">
+        <!-- Status message of Wi-Fi when it is idle. -->
+        <item></item>
+        <!-- Status message of Wi-Fi when it is scanning. -->
+        <item>Scanning\u2026</item>
+        <!-- Status message of Wi-Fi when it is connecting. -->
+        <item>Connecting\u2026</item>
+        <!-- Status message of Wi-Fi when it is authenticating. -->
+        <item>Authenticating\u2026</item>
+        <!-- Status message of Wi-Fi when it is obtaining IP address. -->
+        <item>Obtaining IP address\u2026</item>
+        <!-- Status message of Wi-Fi when it is connected. -->
+        <item>Connected</item>
+        <!-- Status message of Wi-Fi when it is suspended. -->
+        <item>Suspended</item>
+        <!-- Status message of Wi-Fi when it is disconnecting. -->
+        <item>Disconnecting\u2026</item>
+        <!-- Status message of Wi-Fi when it is disconnected. -->
+        <item>Disconnected</item>
+        <!-- Status message of Wi-Fi when it is a failure. -->
+        <item>Unsuccessful</item>
+        <!-- Status message of Wi-Fi when it is blocked. -->
+        <item>Blocked</item>
+        <!-- Status message of Wi-Fi when connectiong is being verified. -->
+        <item>Temporarily avoiding poor connection</item>
+    </string-array>
+
+    <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />
+    <!-- Wi-Fi settings. The status messages when the network is known. -->
+    <string-array name="wifi_status_with_ssid">
+        <!-- Status message of Wi-Fi when it is idle. -->
+        <item></item>
+        <!-- Status message of Wi-Fi when it is scanning. -->
+        <item>Scanning\u2026</item>
+        <!-- Status message of Wi-Fi when it is connecting to a network. -->
+        <item>Connecting to <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is authenticating with a network. -->
+        <item>Authenticating with <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is obtaining IP address from a network. -->
+        <item>Obtaining IP address from <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is connected to a network. -->
+        <item>Connected to <xliff:g id="network_name">%1$s</xliff:g></item>
+        <!-- Status message of Wi-Fi when it is suspended. -->
+        <item>Suspended</item>
+        <!-- Status message of Wi-Fi when it is disconnecting from a network. -->
+        <item>Disconnecting from <xliff:g id="network_name">%1$s</xliff:g>\u2026</item>
+        <!-- Status message of Wi-Fi when it is disconnected. -->
+        <item>Disconnected</item>
+        <!-- Status message of Wi-Fi when it is a failure. -->
+        <item>Unsuccessful</item>
+        <!-- Status message of Wi-Fi when it is blocked. -->
+        <item>Blocked</item>
+        <!-- Status message of Wi-Fi when connectiong is being verified. -->
+        <item>Temporarily avoiding poor connection</item>
+    </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
new file mode 100644
index 0000000..b5e49ce
--- /dev/null
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Toast message when Wi-Fi cannot scan for networks -->
+    <string name="wifi_fail_to_scan">Can\'t scan for networks</string>
+    <!-- Do not translate.  Concise terminology for wifi with WEP security -->
+    <string name="wifi_security_short_wep">WEP</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA security -->
+    <string name="wifi_security_short_wpa">WPA</string>
+    <!-- Do not translate.  Concise terminology for wifi with WPA2 security -->
+    <string name="wifi_security_short_wpa2">WPA2</string>
+    <!-- Do not translate.  Concise terminology for wifi with both WPA/WPA2 security -->
+    <string name="wifi_security_short_wpa_wpa2">WPA/WPA2</string>
+    <!-- Do not translate.  Concise terminology for wifi with unknown PSK type -->
+    <string name="wifi_security_short_psk_generic">@string/wifi_security_short_wpa_wpa2</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
+    <string name="wifi_security_short_eap">802.1x</string>
+
+    <!-- Used in Wi-Fi settings dialogs when Wi-Fi does not have any security. -->
+    <string name="wifi_security_none">None</string>
+
+    <!-- Do not translate.  Terminology for wifi with WEP security -->
+    <string name="wifi_security_wep">WEP</string>
+    <!-- Do not translate.  Terminology for wifi with WPA security -->
+    <string name="wifi_security_wpa">WPA PSK</string>
+    <!-- Do not translate.  Terminology for wifi with WPA2 security -->
+    <string name="wifi_security_wpa2">WPA2 PSK</string>
+    <!-- Do not translate.  Terminology for wifi with both WPA/WPA2 security, or unknown -->
+    <string name="wifi_security_wpa_wpa2">WPA/WPA2 PSK</string>
+    <!-- Do not translate.  Terminology for wifi with unknown PSK type -->
+    <string name="wifi_security_psk_generic">@string/wifi_security_wpa_wpa2</string>
+    <!-- Do not translate.  Concise terminology for wifi with 802.1x EAP security -->
+    <string name="wifi_security_eap">802.1x EAP</string>
+
+    <!-- Summary for the remembered network. -->
+    <string name="wifi_remembered">Saved</string>
+    <!-- Status for networks disabled for unknown reason -->
+    <string name="wifi_disabled_generic">Disabled</string>
+    <!-- Status for networked disabled from a DNS or DHCP failure -->
+    <string name="wifi_disabled_network_failure">IP Configuration Failure</string>
+    <!-- Status for networked disabled from a wifi association failure -->
+    <string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
+    <!-- Status for networks disabled from authentication failure (wrong password
+         or certificate). -->
+    <string name="wifi_disabled_password_failure">Authentication problem</string>
+    <!-- Summary for the remembered network but currently not in range. -->
+    <string name="wifi_not_in_range">Not in range</string>
+    <!-- Summary for the remembered network but no internet connection was detected. -->
+    <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string>
+
+    <!-- Status message of Wi-Fi when it is connected by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
+    <string name="connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
+
+    <!-- Bluetooth settings.  Message when a device is disconnected -->
+    <string name="bluetooth_disconnected">Disconnected</string>
+    <!-- Bluetooth settings.  Message when disconnecting from a device -->
+    <string name="bluetooth_disconnecting">Disconnecting\u2026</string>
+     <!-- Bluetooth settings.  Message when connecting to a device -->
+    <string name="bluetooth_connecting">Connecting\u2026</string>
+    <!-- Bluetooth settings.  Message when connected to a device. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected">Connected</string>
+    <!--Bluetooth settings screen, summary text under individual Bluetooth devices when pairing -->
+    <string name="bluetooth_pairing">Pairing\u2026</string>
+
+    <!-- Bluetooth settings.  Message when connected to a device, except for phone audio. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected_no_headset">Connected (no phone)</string>
+    <!-- Bluetooth settings.  Message when connected to a device, except for media audio. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected_no_a2dp">Connected (no media)</string>
+    <!-- Bluetooth settings.  Message when connected to a device, except for map. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected_no_map">Connected (no message access)</string>
+    <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)</string>
+
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
+    <string name="bluetooth_profile_a2dp">Media audio</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the headset or handsfree profile. -->
+    <string name="bluetooth_profile_headset">Phone audio</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the OPP profile. -->
+    <string name="bluetooth_profile_opp">File transfer</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the HID profile. -->
+    <string name="bluetooth_profile_hid">Input device</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (accessing Internet through remote device). [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pan">Internet access</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pbap">Contact sharing</string>
+    <!-- Bluetooth settings. The user-visible summary string that is used whenever referring to the PBAP profile (sharing contacts). [CHAR LIMIT=60] -->
+    <string name="bluetooth_profile_pbap_summary">Use for contact sharing</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (sharing this device's Internet connection). [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pan_nap">Internet connection sharing</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the map profile. -->
+    <string name="bluetooth_profile_map">Message Access</string>
+
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the A2DP checkbox preference when A2DP is connected. -->
+    <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the headset checkbox preference when headset is connected. -->
+    <string name="bluetooth_headset_profile_summary_connected">Connected to phone audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference when OPP is connected. -->
+    <string name="bluetooth_opp_profile_summary_connected">Connected to file transfer server</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the map checkbox preference when map is connected. -->
+    <string name="bluetooth_map_profile_summary_connected">Connected to map</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference when OPP is not connected. -->
+    <string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the HID checkbox preference when HID is connected. -->
+    <string name="bluetooth_hid_profile_summary_connected">Connected to input device</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (user role). [CHAR LIMIT=25]-->
+    <string name="bluetooth_pan_user_profile_summary_connected">Connected to device for Internet access</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (NAP role). [CHAR LIMIT=25]-->
+    <string name="bluetooth_pan_nap_profile_summary_connected">Sharing local Internet connection with device</string>
+
+    <!-- Bluetooth settings. Connection options screen. The summary
+         for the PAN checkbox preference that describes how checking it
+         will set the PAN profile as preferred. -->
+    <string name="bluetooth_pan_profile_summary_use_for">Use for Internet access</string>
+    <!-- Bluetooth settings. Connection options screen.  The summary for the map checkbox preference that describes how checking it will set the map profile as preferred. -->
+    <string name="bluetooth_map_profile_summary_use_for">Use for map</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the A2DP checkbox preference that describes how checking it will set the A2DP profile as preferred. -->
+    <string name="bluetooth_a2dp_profile_summary_use_for">Use for media audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the headset checkbox preference that describes how checking it will set the headset profile as preferred. -->
+    <string name="bluetooth_headset_profile_summary_use_for">Use for phone audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference that describes how checking it will set the OPP profile as preferred. -->
+    <string name="bluetooth_opp_profile_summary_use_for">Use for file transfer</string>
+    <!-- Bluetooth settings. Connection options screen. The summary
+         for the HID checkbox preference that describes how checking it
+         will set the HID profile as preferred. -->
+    <string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+
+    <!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_accept">Pair</string>
+    <!-- Button text for accepting an incoming pairing request in all caps. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_accept_all_caps">PAIR</string>
+    <!-- Button text for declining an incoming pairing request. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_decline">Cancel</string>
+
+    <!-- Message in pairing dialogs.  [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_pairing_will_share_phonebook">Pairing grants access to your contacts and call history when connected.</string>
+    <!-- Message for the error dialog when BT pairing fails generically. -->
+    <string name="bluetooth_pairing_error_message">Couldn\'t pair with <xliff:g id="device_name">%1$s</xliff:g>.</string>
+
+    <!-- Message for the error dialog when BT pairing fails because the PIN /
+    Passkey entered is incorrect. -->
+    <string name="bluetooth_pairing_pin_error_message">Couldn\'t pair with <xliff:g id="device_name">%1$s</xliff:g> because of an incorrect PIN or passkey.</string>
+    <!-- Message for the error dialog when BT pairing fails because the other device is down. -->
+    <string name="bluetooth_pairing_device_down_error_message">Can\'t communicate with <xliff:g id="device_name">%1$s</xliff:g>.</string>
+    <!-- Message for the error dialog when BT pairing fails because the other device rejected the pairing. -->
+    <string name="bluetooth_pairing_rejected_error_message">Pairing rejected by <xliff:g id="device_name">%1$s</xliff:g>.</string>
+
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
new file mode 100644
index 0000000..58e5e29a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+public class TetherUtil {
+
+    // Types of tethering.
+    public static final int TETHERING_INVALID   = -1;
+    public static final int TETHERING_WIFI      = 0;
+    public static final int TETHERING_USB       = 1;
+    public static final int TETHERING_BLUETOOTH = 2;
+
+    // Extras used for communicating with the TetherService.
+    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+    public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+    /**
+     * Tells the service to run a provision check now.
+     */
+    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+    /**
+     * Enables wifi tethering if the provision check is successful. Used by
+     * QS to enable tethering.
+     */
+    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
+
+    public static ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
+            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
+
+    public static boolean setWifiTethering(boolean enable, Context context) {
+        final WifiManager wifiManager =
+                (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        final ContentResolver cr = context.getContentResolver();
+        /**
+         * Disable Wifi if enabling tethering
+         */
+        int wifiState = wifiManager.getWifiState();
+        if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
+                    (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
+            wifiManager.setWifiEnabled(false);
+            Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
+        }
+
+        boolean success = wifiManager.setWifiApEnabled(null, enable);
+        /**
+         *  If needed, restore Wifi on tether disable
+         */
+        if (!enable) {
+            int wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+            if (wifiSavedState == 1) {
+                wifiManager.setWifiEnabled(true);
+                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+            }
+        }
+        return success;
+    }
+
+    public static boolean isWifiTetherEnabled(Context context) {
+        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
+    }
+
+    public static boolean isProvisioningNeeded(Context context) {
+        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
+        // ConnectivityManager#enforceTetherChangePermission
+        String[] provisionApp = context.getResources().getStringArray(
+                com.android.internal.R.array.config_mobile_hotspot_provision_app);
+        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
+                || provisionApp == null) {
+            return false;
+        }
+        return (provisionApp.length == 2);
+    }
+
+    public static boolean isTetheringSupported(Context context) {
+        final ConnectivityManager cm =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
+        return !isSecondaryUser && cm.isTetheringSupported();
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java b/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java
new file mode 100644
index 0000000..0346a77
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/WirelessUtils.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib;
+
+import android.content.Context;
+import android.provider.Settings;
+
+public class WirelessUtils {
+
+    public static boolean isRadioAllowed(Context context, String type) {
+        if (!isAirplaneModeOn(context)) {
+            return true;
+        }
+        String toggleable = Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        return toggleable != null && toggleable.contains(type);
+    }
+
+    public static boolean isAirplaneModeOn(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
new file mode 100755
index 0000000..9608daa
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class A2dpProfile implements LocalBluetoothProfile {
+    private static final String TAG = "A2dpProfile";
+    private static boolean V = false;
+
+    private BluetoothA2dp mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SINK_UUIDS = {
+        BluetoothUuid.AudioSink,
+        BluetoothUuid.AdvAudioDist,
+    };
+
+    static final String NAME = "A2DP";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 1;
+
+    // These callbacks run on the main thread.
+    private final class A2dpServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothA2dp) proxy;
+            // We just bound to the service, so refresh the UI for any connected A2DP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "A2dpProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    A2dpProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(),
+                BluetoothProfile.A2DP);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                mService.disconnect(sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        // Downgrade priority as user is disconnecting the headset.
+        if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+            mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+        }
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+    boolean isA2dpPlaying() {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (!sinks.isEmpty()) {
+            if (mService.isA2dpPlaying(sinks.get(0))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_a2dp;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headphones_a2dp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up A2DP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
new file mode 100644
index 0000000..4c41b49
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+
+/**
+ * BluetoothCallback provides a callback interface for the settings
+ * UI to receive events from {@link BluetoothEventManager}.
+ */
+public interface BluetoothCallback {
+    void onBluetoothStateChanged(int bluetoothState);
+    void onScanningStateChanged(boolean started);
+    void onDeviceAdded(CachedBluetoothDevice cachedDevice);
+    void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
+    void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
+    void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
new file mode 100644
index 0000000..8dec86a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+/**
+ * BluetoothDeviceFilter contains a static method that returns a
+ * Filter object that returns whether or not the BluetoothDevice
+ * passed to it matches the specified filter type constant from
+ * {@link android.bluetooth.BluetoothDevicePicker}.
+ */
+public final class BluetoothDeviceFilter {
+    private static final String TAG = "BluetoothDeviceFilter";
+
+    /** The filter interface to external classes. */
+    public interface Filter {
+        boolean matches(BluetoothDevice device);
+    }
+
+    /** All filter singleton (referenced directly). */
+    public static final Filter ALL_FILTER = new AllFilter();
+
+    /** Bonded devices only filter (referenced directly). */
+    public static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter();
+
+    /** Unbonded devices only filter (referenced directly). */
+    public static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter();
+
+    /** Table of singleton filter objects. */
+    private static final Filter[] FILTERS = {
+            ALL_FILTER,             // FILTER_TYPE_ALL
+            new AudioFilter(),      // FILTER_TYPE_AUDIO
+            new TransferFilter(),   // FILTER_TYPE_TRANSFER
+            new PanuFilter(),       // FILTER_TYPE_PANU
+            new NapFilter()         // FILTER_TYPE_NAP
+    };
+
+    /** Private constructor. */
+    private BluetoothDeviceFilter() {
+    }
+
+    /**
+     * Returns the singleton {@link Filter} object for the specified type,
+     * or {@link #ALL_FILTER} if the type value is out of range.
+     *
+     * @param filterType a constant from BluetoothDevicePicker
+     * @return a singleton object implementing the {@link Filter} interface.
+     */
+    public static Filter getFilter(int filterType) {
+        if (filterType >= 0 && filterType < FILTERS.length) {
+            return FILTERS[filterType];
+        } else {
+            Log.w(TAG, "Invalid filter type " + filterType + " for device picker");
+            return ALL_FILTER;
+        }
+    }
+
+    /** Filter that matches all devices. */
+    private static final class AllFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return true;
+        }
+    }
+
+    /** Filter that matches only bonded devices. */
+    private static final class BondedDeviceFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return device.getBondState() == BluetoothDevice.BOND_BONDED;
+        }
+    }
+
+    /** Filter that matches only unbonded devices. */
+    private static final class UnbondedDeviceFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return device.getBondState() != BluetoothDevice.BOND_BONDED;
+        }
+    }
+
+    /** Parent class of filters based on UUID and/or Bluetooth class. */
+    private abstract static class ClassUuidFilter implements Filter {
+        abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass);
+
+        public boolean matches(BluetoothDevice device) {
+            return matches(device.getUuids(), device.getBluetoothClass());
+        }
+    }
+
+    /** Filter that matches devices that support AUDIO profiles. */
+    private static final class AudioFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) {
+                    return true;
+                }
+                if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) {
+                    return true;
+                }
+            } else if (btClass != null) {
+                if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
+                        btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /** Filter that matches devices that support Object Transfer. */
+    private static final class TransferFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP);
+        }
+    }
+
+    /** Filter that matches devices that support PAN User (PANU) profile. */
+    private static final class PanuFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU);
+        }
+    }
+
+    /** Filter that matches devices that support NAP profile. */
+    private static final class NapFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
new file mode 100644
index 0000000..69b45e5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+/* Required to handle timeout notification when phone is suspended */
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+
+public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
+    private static final String TAG = "BluetoothDiscoverableTimeoutReceiver";
+
+    private static final String INTENT_DISCOVERABLE_TIMEOUT =
+        "android.bluetooth.intent.DISCOVERABLE_TIMEOUT";
+
+    public static void setDiscoverableAlarm(Context context, long alarmTime) {
+        Log.d(TAG, "setDiscoverableAlarm(): alarmTime = " + alarmTime);
+
+        Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
+        intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
+        PendingIntent pending = PendingIntent.getBroadcast(
+            context, 0, intent, 0);
+        AlarmManager alarmManager =
+              (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
+
+        if (pending != null) {
+            // Cancel any previous alarms that do the same thing.
+            alarmManager.cancel(pending);
+            Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm");
+        }
+        pending = PendingIntent.getBroadcast(
+            context, 0, intent, 0);
+
+        alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending);
+    }
+
+    public static void cancelDiscoverableAlarm(Context context) {
+        Log.d(TAG, "cancelDiscoverableAlarm(): Enter");
+
+        Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
+        intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
+        PendingIntent pending = PendingIntent.getBroadcast(
+            context, 0, intent, PendingIntent.FLAG_NO_CREATE);
+        if (pending != null) {
+            // Cancel any previous alarms that do the same thing.
+            AlarmManager alarmManager =
+              (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
+
+            alarmManager.cancel(pending);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance();
+
+         if(localBluetoothAdapter != null  &&
+            localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
+            Log.d(TAG, "Disable discoverable...");
+
+            localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+         } else {
+            Log.e(TAG, "localBluetoothAdapter is NULL!!");
+        }
+    }
+};
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
new file mode 100755
index 0000000..5d6b2f1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth
+ * API and dispatches the event on the UI thread to the right class in the
+ * Settings.
+ */
+public final class BluetoothEventManager {
+    private static final String TAG = "BluetoothEventManager";
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private LocalBluetoothProfileManager mProfileManager;
+    private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;
+    private final Map<String, Handler> mHandlerMap;
+    private Context mContext;
+
+    private final Collection<BluetoothCallback> mCallbacks =
+            new ArrayList<BluetoothCallback>();
+
+    interface Handler {
+        void onReceive(Context context, Intent intent, BluetoothDevice device);
+    }
+
+    void addHandler(String action, Handler handler) {
+        mHandlerMap.put(action, handler);
+        mAdapterIntentFilter.addAction(action);
+    }
+
+    void addProfileHandler(String action, Handler handler) {
+        mHandlerMap.put(action, handler);
+        mProfileIntentFilter.addAction(action);
+    }
+
+    // Set profile manager after construction due to circular dependency
+    void setProfileManager(LocalBluetoothProfileManager manager) {
+        mProfileManager = manager;
+    }
+
+    BluetoothEventManager(LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager, Context context) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mAdapterIntentFilter = new IntentFilter();
+        mProfileIntentFilter = new IntentFilter();
+        mHandlerMap = new HashMap<String, Handler>();
+        mContext = context;
+
+        // Bluetooth on/off broadcasts
+        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
+        // Generic connected/not broadcast
+        addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
+                new ConnectionStateChangedHandler());
+
+        // Discovery broadcasts
+        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
+        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
+        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
+        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
+        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
+
+        // Pairing broadcasts
+        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
+        addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
+
+        // Fine-grained state broadcasts
+        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
+        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
+
+        // Dock event broadcasts
+        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
+
+        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
+    }
+
+    void registerProfileIntentReceiver() {
+        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
+    }
+
+    /** Register to start receiving callbacks for Bluetooth events. */
+    public void registerCallback(BluetoothCallback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    /** Unregister to stop receiving callbacks for Bluetooth events. */
+    public void unregisterCallback(BluetoothCallback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            BluetoothDevice device = intent
+                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+            Handler handler = mHandlerMap.get(action);
+            if (handler != null) {
+                handler.onReceive(context, intent, device);
+            }
+        }
+    };
+
+    private class AdapterStateChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                                    BluetoothAdapter.ERROR);
+            // update local profiles and get paired devices
+            mLocalAdapter.setBluetoothStateInt(state);
+            // send callback to update UI and possibly start scanning
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onBluetoothStateChanged(state);
+                }
+            }
+            // Inform CachedDeviceManager that the adapter state has changed
+            mDeviceManager.onBluetoothStateChanged(state);
+        }
+    }
+
+    private class ScanningStateChangedHandler implements Handler {
+        private final boolean mStarted;
+
+        ScanningStateChangedHandler(boolean started) {
+            mStarted = started;
+        }
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onScanningStateChanged(mStarted);
+                }
+            }
+            mDeviceManager.onScanningStateChanged(mStarted);
+        }
+    }
+
+    private class DeviceFoundHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
+            BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
+            String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+            // TODO Pick up UUID. They should be available for 2.1 devices.
+            // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+                Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+                        + cachedDevice);
+            }
+            cachedDevice.setRssi(rssi);
+            cachedDevice.setBtClass(btClass);
+            cachedDevice.setNewName(name);
+            cachedDevice.setVisible(true);
+        }
+    }
+
+    private class ConnectionStateChangedHandler implements Handler {
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
+                    BluetoothAdapter.ERROR);
+            dispatchConnectionStateChanged(cachedDevice, state);
+        }
+    }
+
+    private void dispatchConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+        synchronized (mCallbacks) {
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onConnectionStateChanged(cachedDevice, state);
+            }
+        }
+    }
+
+    void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
+        synchronized (mCallbacks) {
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onDeviceAdded(cachedDevice);
+            }
+        }
+    }
+
+    private class DeviceDisappearedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
+                return;
+            }
+            if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) {
+                synchronized (mCallbacks) {
+                    for (BluetoothCallback callback : mCallbacks) {
+                        callback.onDeviceDeleted(cachedDevice);
+                    }
+                }
+            }
+        }
+    }
+
+    private class NameChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onDeviceNameUpdated(device);
+        }
+    }
+
+    private class BondStateChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            if (device == null) {
+                Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
+                return;
+            }
+            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                                               BluetoothDevice.ERROR);
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "CachedBluetoothDevice for device " + device +
+                        " not found, calling readPairedDevices().");
+                if (!readPairedDevices()) {
+                    Log.e(TAG, "Got bonding state changed for " + device +
+                            ", but we have no record of that device.");
+                    return;
+                }
+                cachedDevice = mDeviceManager.findDevice(device);
+                if (cachedDevice == null) {
+                    Log.e(TAG, "Got bonding state changed for " + device +
+                            ", but device not added in cache.");
+                    return;
+                }
+            }
+
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onDeviceBondStateChanged(cachedDevice, bondState);
+                }
+            }
+            cachedDevice.onBondingStateChanged(bondState);
+
+            if (bondState == BluetoothDevice.BOND_NONE) {
+                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+                        BluetoothDevice.ERROR);
+
+                showUnbondMessage(context, cachedDevice.getName(), reason);
+            }
+        }
+
+        /**
+         * Called when we have reached the unbonded state.
+         *
+         * @param reason one of the error reasons from
+         *            BluetoothDevice.UNBOND_REASON_*
+         */
+        private void showUnbondMessage(Context context, String name, int reason) {
+            int errorMsg;
+
+            switch(reason) {
+            case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
+                errorMsg = R.string.bluetooth_pairing_pin_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
+                errorMsg = R.string.bluetooth_pairing_rejected_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
+                errorMsg = R.string.bluetooth_pairing_device_down_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
+            case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
+            case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
+            case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
+                errorMsg = R.string.bluetooth_pairing_error_message;
+                break;
+            default:
+                Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
+                return;
+            }
+            Utils.showError(context, name, errorMsg);
+        }
+    }
+
+    private class ClassChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onBtClassChanged(device);
+        }
+    }
+
+    private class UuidChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onUuidChanged(device);
+        }
+    }
+
+    private class PairingCancelHandler implements Handler {
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            if (device == null) {
+                Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
+                return;
+            }
+            int errorMsg = R.string.bluetooth_pairing_error_message;
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            Utils.showError(context, cachedDevice.getName(), errorMsg);
+        }
+    }
+
+    private class DockEventHandler implements Handler {
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            // Remove if unpair device upon undocking
+            int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
+            int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
+            if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
+                    CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+                    if (cachedDevice != null) {
+                        cachedDevice.setVisible(false);
+                    }
+                }
+            }
+        }
+    }
+    boolean readPairedDevices() {
+        Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
+        if (bondedDevices == null) {
+            return false;
+        }
+
+        boolean deviceAdded = false;
+        for (BluetoothDevice device : bondedDevices) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+                dispatchDeviceAdded(cachedDevice);
+                deviceAdded = true;
+            }
+        }
+
+        return deviceAdded;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
new file mode 100755
index 0000000..e1cb878
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.ParcelUuid;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+import android.bluetooth.BluetoothAdapter;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * CachedBluetoothDevice represents a remote Bluetooth device. It contains
+ * attributes of the device (such as the address, name, RSSI, etc.) and
+ * functionality that can be performed on the device (connect, pair, disconnect,
+ * etc.).
+ */
+public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
+    private static final String TAG = "CachedBluetoothDevice";
+    private static final boolean DEBUG = Utils.V;
+
+    private final Context mContext;
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final LocalBluetoothProfileManager mProfileManager;
+    private final BluetoothDevice mDevice;
+    private String mName;
+    private short mRssi;
+    private BluetoothClass mBtClass;
+    private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
+
+    private final List<LocalBluetoothProfile> mProfiles =
+            new ArrayList<LocalBluetoothProfile>();
+
+    // List of profiles that were previously in mProfiles, but have been removed
+    private final List<LocalBluetoothProfile> mRemovedProfiles =
+            new ArrayList<LocalBluetoothProfile>();
+
+    // Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
+    private boolean mLocalNapRoleConnected;
+
+    private boolean mVisible;
+
+    private int mPhonebookPermissionChoice;
+
+    private int mMessagePermissionChoice;
+
+    private int mMessageRejectionCount;
+
+    private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
+
+    // Following constants indicate the user's choices of Phone book/message access settings
+    // User hasn't made any choice or settings app has wiped out the memory
+    public final static int ACCESS_UNKNOWN = 0;
+    // User has accepted the connection and let Settings app remember the decision
+    public final static int ACCESS_ALLOWED = 1;
+    // User has rejected the connection and let Settings app remember the decision
+    public final static int ACCESS_REJECTED = 2;
+
+    // How many times user should reject the connection to make the choice persist.
+    private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
+
+    private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
+
+    /**
+     * When we connect to multiple profiles, we only want to display a single
+     * error even if they all fail. This tracks that state.
+     */
+    private boolean mIsConnectingErrorPossible;
+
+    /**
+     * Last time a bt profile auto-connect was attempted.
+     * If an ACTION_UUID intent comes in within
+     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
+     * again with the new UUIDs
+     */
+    private long mConnectAttempted;
+
+    // See mConnectAttempted
+    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+
+    /** Auto-connect after pairing only if locally initiated. */
+    private boolean mConnectAfterPairing;
+
+    /**
+     * Describes the current device and profile for logging.
+     *
+     * @param profile Profile to describe
+     * @return Description of the device and profile
+     */
+    private String describe(LocalBluetoothProfile profile) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Address:").append(mDevice);
+        if (profile != null) {
+            sb.append(" Profile:").append(profile);
+        }
+
+        return sb.toString();
+    }
+
+    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
+        if (Utils.D) {
+            Log.d(TAG, "onProfileStateChanged: profile " + profile +
+                    " newProfileState " + newProfileState);
+        }
+        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
+        {
+            if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
+            return;
+        }
+        mProfileConnectionState.put(profile, newProfileState);
+        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
+            if (profile instanceof MapProfile) {
+                profile.setPreferred(mDevice, true);
+            } else if (!mProfiles.contains(profile)) {
+                mRemovedProfiles.remove(profile);
+                mProfiles.add(profile);
+                if (profile instanceof PanProfile &&
+                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
+                    // Device doesn't support NAP, so remove PanProfile on disconnect
+                    mLocalNapRoleConnected = true;
+                }
+            }
+        } else if (profile instanceof MapProfile &&
+                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
+            profile.setPreferred(mDevice, false);
+        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
+                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
+                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
+            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
+            mProfiles.remove(profile);
+            mRemovedProfiles.add(profile);
+            mLocalNapRoleConnected = false;
+        }
+    }
+
+    CachedBluetoothDevice(Context context,
+                          LocalBluetoothAdapter adapter,
+                          LocalBluetoothProfileManager profileManager,
+                          BluetoothDevice device) {
+        mContext = context;
+        mLocalAdapter = adapter;
+        mProfileManager = profileManager;
+        mDevice = device;
+        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
+        fillData();
+    }
+
+    public void disconnect() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            disconnect(profile);
+        }
+        // Disconnect  PBAP server in case its connected
+        // This is to ensure all the profiles are disconnected as some CK/Hs do not
+        // disconnect  PBAP connection when HF connection is brought down
+        PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
+        if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
+        {
+            PbapProfile.disconnect(mDevice);
+        }
+    }
+
+    public void disconnect(LocalBluetoothProfile profile) {
+        if (profile.disconnect(mDevice)) {
+            if (Utils.D) {
+                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
+            }
+        }
+    }
+
+    public void connect(boolean connectAllProfiles) {
+        if (!ensurePaired()) {
+            return;
+        }
+
+        mConnectAttempted = SystemClock.elapsedRealtime();
+        connectWithoutResettingTimer(connectAllProfiles);
+    }
+
+    void onBondingDockConnect() {
+        // Attempt to connect if UUIDs are available. Otherwise,
+        // we will connect when the ACTION_UUID intent arrives.
+        connect(false);
+    }
+
+    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
+        // Try to initialize the profiles if they were not.
+        if (mProfiles.isEmpty()) {
+            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
+            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
+            // from bluetooth stack but ACTION.uuid is not sent yet.
+            // Eventually ACTION.uuid will be received which shall trigger the connection of the
+            // various profiles
+            // If UUIDs are not available yet, connect will be happen
+            // upon arrival of the ACTION_UUID intent.
+            Log.d(TAG, "No profiles. Maybe we will connect later");
+            return;
+        }
+
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+
+        int preferredProfiles = 0;
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+                if (profile.isPreferred(mDevice)) {
+                    ++preferredProfiles;
+                    connectInt(profile);
+                }
+            }
+        }
+        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
+
+        if (preferredProfiles == 0) {
+            connectAutoConnectableProfiles();
+        }
+    }
+
+    private void connectAutoConnectableProfiles() {
+        if (!ensurePaired()) {
+            return;
+        }
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (profile.isAutoConnectable()) {
+                profile.setPreferred(mDevice, true);
+                connectInt(profile);
+            }
+        }
+    }
+
+    /**
+     * Connect this device to the specified profile.
+     *
+     * @param profile the profile to use with the remote device
+     */
+    public void connectProfile(LocalBluetoothProfile profile) {
+        mConnectAttempted = SystemClock.elapsedRealtime();
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+        connectInt(profile);
+        // Refresh the UI based on profile.connect() call
+        refresh();
+    }
+
+    synchronized void connectInt(LocalBluetoothProfile profile) {
+        if (!ensurePaired()) {
+            return;
+        }
+        if (profile.connect(mDevice)) {
+            if (Utils.D) {
+                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
+            }
+            return;
+        }
+        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
+    }
+
+    private boolean ensurePaired() {
+        if (getBondState() == BluetoothDevice.BOND_NONE) {
+            startPairing();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public boolean startPairing() {
+        // Pairing is unreliable while scanning, so cancel discovery
+        if (mLocalAdapter.isDiscovering()) {
+            mLocalAdapter.cancelDiscovery();
+        }
+
+        if (!mDevice.createBond()) {
+            return false;
+        }
+
+        mConnectAfterPairing = true;  // auto-connect after pairing
+        return true;
+    }
+
+    /**
+     * Return true if user initiated pairing on this device. The message text is
+     * slightly different for local vs. remote initiated pairing dialogs.
+     */
+    boolean isUserInitiatedPairing() {
+        return mConnectAfterPairing;
+    }
+
+    public void unpair() {
+        int state = getBondState();
+
+        if (state == BluetoothDevice.BOND_BONDING) {
+            mDevice.cancelBondProcess();
+        }
+
+        if (state != BluetoothDevice.BOND_NONE) {
+            final BluetoothDevice dev = mDevice;
+            if (dev != null) {
+                final boolean successful = dev.removeBond();
+                if (successful) {
+                    if (Utils.D) {
+                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
+                    }
+                } else if (Utils.V) {
+                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
+                            describe(null));
+                }
+            }
+        }
+    }
+
+    public int getProfileConnectionState(LocalBluetoothProfile profile) {
+        if (mProfileConnectionState == null ||
+                mProfileConnectionState.get(profile) == null) {
+            // If cache is empty make the binder call to get the state
+            int state = profile.getConnectionStatus(mDevice);
+            mProfileConnectionState.put(profile, state);
+        }
+        return mProfileConnectionState.get(profile);
+    }
+
+    public void clearProfileConnectionState ()
+    {
+        if (Utils.D) {
+            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
+        }
+        for (LocalBluetoothProfile profile :getProfiles()) {
+            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
+        }
+    }
+
+    // TODO: do any of these need to run async on a background thread?
+    private void fillData() {
+        fetchName();
+        fetchBtClass();
+        updateProfiles();
+        migratePhonebookPermissionChoice();
+        migrateMessagePermissionChoice();
+        fetchMessageRejectionCount();
+
+        mVisible = false;
+        dispatchAttributesChanged();
+    }
+
+    public BluetoothDevice getDevice() {
+        return mDevice;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Populate name from BluetoothDevice.ACTION_FOUND intent
+     */
+    void setNewName(String name) {
+        if (mName == null) {
+            mName = name;
+            if (mName == null || TextUtils.isEmpty(mName)) {
+                mName = mDevice.getAddress();
+            }
+            dispatchAttributesChanged();
+        }
+    }
+
+    /**
+     * user changes the device name
+     */
+    public void setName(String name) {
+        if (!mName.equals(name)) {
+            mName = name;
+            mDevice.setAlias(name);
+            dispatchAttributesChanged();
+        }
+    }
+
+    void refreshName() {
+        fetchName();
+        dispatchAttributesChanged();
+    }
+
+    private void fetchName() {
+        mName = mDevice.getAliasName();
+
+        if (TextUtils.isEmpty(mName)) {
+            mName = mDevice.getAddress();
+            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
+        }
+    }
+
+    void refresh() {
+        dispatchAttributesChanged();
+    }
+
+    public boolean isVisible() {
+        return mVisible;
+    }
+
+    public void setVisible(boolean visible) {
+        if (mVisible != visible) {
+            mVisible = visible;
+            dispatchAttributesChanged();
+        }
+    }
+
+    public int getBondState() {
+        return mDevice.getBondState();
+    }
+
+    void setRssi(short rssi) {
+        if (mRssi != rssi) {
+            mRssi = rssi;
+            dispatchAttributesChanged();
+        }
+    }
+
+    /**
+     * Checks whether we are connected to this device (any profile counts).
+     *
+     * @return Whether it is connected.
+     */
+    public boolean isConnected() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            int status = getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTED) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean isConnectedProfile(LocalBluetoothProfile profile) {
+        int status = getProfileConnectionState(profile);
+        return status == BluetoothProfile.STATE_CONNECTED;
+
+    }
+
+    public boolean isBusy() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            int status = getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTING
+                    || status == BluetoothProfile.STATE_DISCONNECTING) {
+                return true;
+            }
+        }
+        return getBondState() == BluetoothDevice.BOND_BONDING;
+    }
+
+    /**
+     * Fetches a new value for the cached BT class.
+     */
+    private void fetchBtClass() {
+        mBtClass = mDevice.getBluetoothClass();
+    }
+
+    private boolean updateProfiles() {
+        ParcelUuid[] uuids = mDevice.getUuids();
+        if (uuids == null) return false;
+
+        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+        if (localUuids == null) return false;
+
+        /**
+         * Now we know if the device supports PBAP, update permissions...
+         */
+        processPhonebookAccess();
+
+        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles,
+                                       mLocalNapRoleConnected, mDevice);
+
+        if (DEBUG) {
+            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
+            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
+
+            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
+            Log.v(TAG, "UUID:");
+            for (ParcelUuid uuid : uuids) {
+                Log.v(TAG, "  " + uuid);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Refreshes the UI for the BT class, including fetching the latest value
+     * for the class.
+     */
+    void refreshBtClass() {
+        fetchBtClass();
+        dispatchAttributesChanged();
+    }
+
+    /**
+     * Refreshes the UI when framework alerts us of a UUID change.
+     */
+    void onUuidChanged() {
+        updateProfiles();
+
+        if (DEBUG) {
+            Log.e(TAG, "onUuidChanged: Time since last connect"
+                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
+        }
+
+        /*
+         * If a connect was attempted earlier without any UUID, we will do the
+         * connect now.
+         */
+        if (!mProfiles.isEmpty()
+                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
+                        .elapsedRealtime()) {
+            connectWithoutResettingTimer(false);
+        }
+        dispatchAttributesChanged();
+    }
+
+    void onBondingStateChanged(int bondState) {
+        if (bondState == BluetoothDevice.BOND_NONE) {
+            mProfiles.clear();
+            mConnectAfterPairing = false;  // cancel auto-connect
+            setPhonebookPermissionChoice(ACCESS_UNKNOWN);
+            setMessagePermissionChoice(ACCESS_UNKNOWN);
+            mMessageRejectionCount = 0;
+            saveMessageRejectionCount();
+        }
+
+        refresh();
+
+        if (bondState == BluetoothDevice.BOND_BONDED) {
+            if (mDevice.isBluetoothDock()) {
+                onBondingDockConnect();
+            } else if (mConnectAfterPairing) {
+                connect(false);
+            }
+            mConnectAfterPairing = false;
+        }
+    }
+
+    void setBtClass(BluetoothClass btClass) {
+        if (btClass != null && mBtClass != btClass) {
+            mBtClass = btClass;
+            dispatchAttributesChanged();
+        }
+    }
+
+    public BluetoothClass getBtClass() {
+        return mBtClass;
+    }
+
+    public List<LocalBluetoothProfile> getProfiles() {
+        return Collections.unmodifiableList(mProfiles);
+    }
+
+    public List<LocalBluetoothProfile> getConnectableProfiles() {
+        List<LocalBluetoothProfile> connectableProfiles =
+                new ArrayList<LocalBluetoothProfile>();
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (profile.isConnectable()) {
+                connectableProfiles.add(profile);
+            }
+        }
+        return connectableProfiles;
+    }
+
+    public List<LocalBluetoothProfile> getRemovedProfiles() {
+        return mRemovedProfiles;
+    }
+
+    public void registerCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    public void unregisterCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    private void dispatchAttributesChanged() {
+        synchronized (mCallbacks) {
+            for (Callback callback : mCallbacks) {
+                callback.onDeviceAttributesChanged();
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return mDevice.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
+            return false;
+        }
+        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
+    }
+
+    @Override
+    public int hashCode() {
+        return mDevice.getAddress().hashCode();
+    }
+
+    // This comparison uses non-final fields so the sort order may change
+    // when device attributes change (such as bonding state). Settings
+    // will completely refresh the device list when this happens.
+    public int compareTo(CachedBluetoothDevice another) {
+        // Connected above not connected
+        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Paired above not paired
+        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
+            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Visible above not visible
+        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Stronger signal above weaker signal
+        comparison = another.mRssi - mRssi;
+        if (comparison != 0) return comparison;
+
+        // Fallback on name
+        return mName.compareTo(another.mName);
+    }
+
+    public interface Callback {
+        void onDeviceAttributesChanged();
+    }
+
+    public int getPhonebookPermissionChoice() {
+        int permission = mDevice.getPhonebookAccessPermission();
+        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
+            return ACCESS_ALLOWED;
+        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
+            return ACCESS_REJECTED;
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    public void setPhonebookPermissionChoice(int permissionChoice) {
+        int permission = BluetoothDevice.ACCESS_UNKNOWN;
+        if (permissionChoice == ACCESS_ALLOWED) {
+            permission = BluetoothDevice.ACCESS_ALLOWED;
+        } else if (permissionChoice == ACCESS_REJECTED) {
+            permission = BluetoothDevice.ACCESS_REJECTED;
+        }
+        mDevice.setPhonebookAccessPermission(permission);
+    }
+
+    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
+    // app's shared preferences).
+    private void migratePhonebookPermissionChoice() {
+        SharedPreferences preferences = mContext.getSharedPreferences(
+                "bluetooth_phonebook_permission", Context.MODE_PRIVATE);
+        if (!preferences.contains(mDevice.getAddress())) {
+            return;
+        }
+
+        if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
+            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
+            if (oldPermission == ACCESS_ALLOWED) {
+                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
+            } else if (oldPermission == ACCESS_REJECTED) {
+                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
+            }
+        }
+
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.remove(mDevice.getAddress());
+        editor.commit();
+    }
+
+    public int getMessagePermissionChoice() {
+        int permission = mDevice.getMessageAccessPermission();
+        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
+            return ACCESS_ALLOWED;
+        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
+            return ACCESS_REJECTED;
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    public void setMessagePermissionChoice(int permissionChoice) {
+        int permission = BluetoothDevice.ACCESS_UNKNOWN;
+        if (permissionChoice == ACCESS_ALLOWED) {
+            permission = BluetoothDevice.ACCESS_ALLOWED;
+        } else if (permissionChoice == ACCESS_REJECTED) {
+            permission = BluetoothDevice.ACCESS_REJECTED;
+        }
+        mDevice.setMessageAccessPermission(permission);
+    }
+
+    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
+    // app's shared preferences).
+    private void migrateMessagePermissionChoice() {
+        SharedPreferences preferences = mContext.getSharedPreferences(
+                "bluetooth_message_permission", Context.MODE_PRIVATE);
+        if (!preferences.contains(mDevice.getAddress())) {
+            return;
+        }
+
+        if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
+            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
+            if (oldPermission == ACCESS_ALLOWED) {
+                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
+            } else if (oldPermission == ACCESS_REJECTED) {
+                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
+            }
+        }
+
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.remove(mDevice.getAddress());
+        editor.commit();
+    }
+
+    /**
+     * @return Whether this rejection should persist.
+     */
+    public boolean checkAndIncreaseMessageRejectionCount() {
+        if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
+            mMessageRejectionCount++;
+            saveMessageRejectionCount();
+        }
+        return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
+    }
+
+    private void fetchMessageRejectionCount() {
+        SharedPreferences preference = mContext.getSharedPreferences(
+                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
+        mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
+    }
+
+    private void saveMessageRejectionCount() {
+        SharedPreferences.Editor editor = mContext.getSharedPreferences(
+                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
+        if (mMessageRejectionCount == 0) {
+            editor.remove(mDevice.getAddress());
+        } else {
+            editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
+        }
+        editor.commit();
+    }
+
+    private void processPhonebookAccess() {
+        if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return;
+
+        ParcelUuid[] uuids = mDevice.getUuids();
+        if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) {
+            // The pairing dialog now warns of phone-book access for paired devices.
+            // No separate prompt is displayed after pairing.
+            setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
+        }
+    }
+
+    public int getMaxConnectionState() {
+        int maxState = BluetoothProfile.STATE_DISCONNECTED;
+        for (LocalBluetoothProfile profile : getProfiles()) {
+            int connectionStatus = getProfileConnectionState(profile);
+            if (connectionStatus > maxState) {
+                maxState = connectionStatus;
+            }
+        }
+        return maxState;
+    }
+
+    /**
+     * @return resource for string that discribes the connection state of this device.
+     */
+    public int getConnectionSummary() {
+        boolean profileConnected = false;       // at least one profile is connected
+        boolean a2dpNotConnected = false;       // A2DP is preferred but not connected
+        boolean headsetNotConnected = false;    // Headset is preferred but not connected
+
+        for (LocalBluetoothProfile profile : getProfiles()) {
+            int connectionStatus = getProfileConnectionState(profile);
+
+            switch (connectionStatus) {
+                case BluetoothProfile.STATE_CONNECTING:
+                case BluetoothProfile.STATE_DISCONNECTING:
+                    return Utils.getConnectionStateSummary(connectionStatus);
+
+                case BluetoothProfile.STATE_CONNECTED:
+                    profileConnected = true;
+                    break;
+
+                case BluetoothProfile.STATE_DISCONNECTED:
+                    if (profile.isProfileReady()) {
+                        if (profile instanceof A2dpProfile) {
+                            a2dpNotConnected = true;
+                        } else if (profile instanceof HeadsetProfile) {
+                            headsetNotConnected = true;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        if (profileConnected) {
+            if (a2dpNotConnected && headsetNotConnected) {
+                return R.string.bluetooth_connected_no_headset_no_a2dp;
+            } else if (a2dpNotConnected) {
+                return R.string.bluetooth_connected_no_a2dp;
+            } else if (headsetNotConnected) {
+                return R.string.bluetooth_connected_no_headset;
+            } else {
+                return R.string.bluetooth_connected;
+            }
+        }
+
+        return getBondState() == BluetoothDevice.BOND_BONDING ? R.string.bluetooth_pairing : 0;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
new file mode 100755
index 0000000..a9f4bd3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
+ */
+public final class CachedBluetoothDeviceManager {
+    private static final String TAG = "CachedBluetoothDeviceManager";
+    private static final boolean DEBUG = Utils.D;
+
+    private Context mContext;
+    private final List<CachedBluetoothDevice> mCachedDevices =
+            new ArrayList<CachedBluetoothDevice>();
+    private final LocalBluetoothManager mBtManager;
+
+    CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
+        mContext = context;
+        mBtManager = localBtManager;
+    }
+
+    public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
+        return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
+    }
+
+    public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
+        cachedDevice.setVisible(false);
+        return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
+    }
+
+    public void onDeviceNameUpdated(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.refreshName();
+        }
+    }
+
+    /**
+     * Search for existing {@link CachedBluetoothDevice} or return null
+     * if this device isn't in the cache. Use {@link #addDevice}
+     * to create and return a new {@link CachedBluetoothDevice} for
+     * a newly discovered {@link BluetoothDevice}.
+     *
+     * @param device the address of the Bluetooth device
+     * @return the cached device object for this device, or null if it has
+     *   not been previously seen
+     */
+    public CachedBluetoothDevice findDevice(BluetoothDevice device) {
+        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+            if (cachedDevice.getDevice().equals(device)) {
+                return cachedDevice;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create and return a new {@link CachedBluetoothDevice}. This assumes
+     * that {@link #findDevice} has already been called and returned null.
+     * @param device the address of the new Bluetooth device
+     * @return the newly created CachedBluetoothDevice object
+     */
+    public CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
+            LocalBluetoothProfileManager profileManager,
+            BluetoothDevice device) {
+        CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
+            profileManager, device);
+        synchronized (mCachedDevices) {
+            mCachedDevices.add(newDevice);
+            mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
+        }
+        return newDevice;
+    }
+
+    /**
+     * Attempts to get the name of a remote device, otherwise returns the address.
+     *
+     * @param device The remote device.
+     * @return The name, or if unavailable, the address.
+     */
+    public String getName(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            return cachedDevice.getName();
+        }
+
+        String name = device.getAliasName();
+        if (name != null) {
+            return name;
+        }
+
+        return device.getAddress();
+    }
+
+    public synchronized void clearNonBondedDevices() {
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                mCachedDevices.remove(i);
+            }
+        }
+    }
+
+    public synchronized void onScanningStateChanged(boolean started) {
+        if (!started) return;
+
+        // If starting a new scan, clear old visibility
+        // Iterate in reverse order since devices may be removed.
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            cachedDevice.setVisible(false);
+        }
+    }
+
+    public synchronized void onBtClassChanged(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.refreshBtClass();
+        }
+    }
+
+    public synchronized void onUuidChanged(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.onUuidChanged();
+        }
+    }
+
+    public synchronized void onBluetoothStateChanged(int bluetoothState) {
+        // When Bluetooth is turning off, we need to clear the non-bonded devices
+        // Otherwise, they end up showing up on the next BT enable
+        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
+            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                    cachedDevice.setVisible(false);
+                    mCachedDevices.remove(i);
+                } else {
+                    // For bonded devices, we need to clear the connection status so that
+                    // when BT is enabled next time, device connection status shall be retrieved
+                    // by making a binder call.
+                    cachedDevice.clearProfileConnectionState();
+                }
+            }
+        }
+    }
+    private void log(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
new file mode 100755
index 0000000..5529866
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * HeadsetProfile handles Bluetooth HFP and Headset profiles.
+ */
+public final class HeadsetProfile implements LocalBluetoothProfile {
+    private static final String TAG = "HeadsetProfile";
+    private static boolean V = true;
+
+    private BluetoothHeadset mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final ParcelUuid[] UUIDS = {
+        BluetoothUuid.HSP,
+        BluetoothUuid.Handsfree,
+    };
+
+    static final String NAME = "HEADSET";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 0;
+
+    // These callbacks run on the main thread.
+    private final class HeadsetServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothHeadset) proxy;
+            // We just bound to the service, so refresh the UI for any connected HFP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "HeadsetProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(HeadsetProfile.this,
+                        BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+
+            mProfileManager.callServiceConnectedListeners();
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mProfileManager.callServiceDisconnectedListeners();
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(),
+                BluetoothProfile.HEADSET);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                Log.d(TAG,"Not disconnecting device = " + sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty()) {
+            for (BluetoothDevice dev : deviceList) {
+                if (dev.equals(device)) {
+                    if (V) Log.d(TAG,"Downgrade priority as user" +
+                                        "is disconnecting the headset");
+                    // Downgrade priority as user is disconnecting the headset.
+                    if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                        mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+                    }
+                    return mService.disconnect(device);
+                }
+            }
+        }
+        return false;
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty()){
+            for (BluetoothDevice dev : deviceList) {
+                if (dev.equals(device)) {
+                    return mService.getConnectionState(device);
+                }
+            }
+        }
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_headset;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_headset_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_headset_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headset_hfp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up HID proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
new file mode 100755
index 0000000..a9e8db5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.List;
+
+/**
+ * HidProfile handles Bluetooth HID profile.
+ */
+public final class HidProfile implements LocalBluetoothProfile {
+    private static final String TAG = "HidProfile";
+    private static boolean V = true;
+
+    private BluetoothInputDevice mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final String NAME = "HID";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 3;
+
+    // These callbacks run on the main thread.
+    private final class InputDeviceServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothInputDevice) proxy;
+            // We just bound to the service, so refresh the UI for any connected HID devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "HidProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    HidProfile(Context context, LocalBluetoothAdapter adapter,
+        CachedBluetoothDeviceManager deviceManager,
+        LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        adapter.getProfileProxy(context, new InputDeviceServiceListener(),
+                BluetoothProfile.INPUT_DEVICE);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+
+        return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+                ? mService.getConnectionState(device)
+                : BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        // TODO: distinguish between keyboard and mouse?
+        return R.string.bluetooth_profile_hid;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_hid_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_hid_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        if (btClass == null) {
+            return R.drawable.ic_lockscreen_ime;
+        }
+        return getHidClassDrawable(btClass);
+    }
+
+    public static int getHidClassDrawable(BluetoothClass btClass) {
+        switch (btClass.getDeviceClass()) {
+            case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
+            case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
+                return R.drawable.ic_lockscreen_ime;
+            case BluetoothClass.Device.PERIPHERAL_POINTING:
+                return R.drawable.ic_bt_pointing_hid;
+            default:
+                return R.drawable.ic_bt_misc_hid;
+        }
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up HID proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
new file mode 100644
index 0000000..e3d2a99
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Set;
+
+/**
+ * LocalBluetoothAdapter provides an interface between the Settings app
+ * and the functionality of the local {@link BluetoothAdapter}, specifically
+ * those related to state transitions of the adapter itself.
+ *
+ * <p>Connection and bonding state changes affecting specific devices
+ * are handled by {@link CachedBluetoothDeviceManager},
+ * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
+ */
+public final class LocalBluetoothAdapter {
+    private static final String TAG = "LocalBluetoothAdapter";
+
+    /** This class does not allow direct access to the BluetoothAdapter. */
+    private final BluetoothAdapter mAdapter;
+
+    private LocalBluetoothProfileManager mProfileManager;
+
+    private static LocalBluetoothAdapter sInstance;
+
+    private int mState = BluetoothAdapter.ERROR;
+
+    private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
+
+    private long mLastScan;
+
+    private LocalBluetoothAdapter(BluetoothAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    void setProfileManager(LocalBluetoothProfileManager manager) {
+        mProfileManager = manager;
+    }
+
+    /**
+     * Get the singleton instance of the LocalBluetoothAdapter. If this device
+     * doesn't support Bluetooth, then null will be returned. Callers must be
+     * prepared to handle a null return value.
+     * @return the LocalBluetoothAdapter object, or null if not supported
+     */
+    static synchronized LocalBluetoothAdapter getInstance() {
+        if (sInstance == null) {
+            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+            if (adapter != null) {
+                sInstance = new LocalBluetoothAdapter(adapter);
+            }
+        }
+
+        return sInstance;
+    }
+
+    // Pass-through BluetoothAdapter methods that we can intercept if necessary
+
+    public void cancelDiscovery() {
+        mAdapter.cancelDiscovery();
+    }
+
+    public boolean enable() {
+        return mAdapter.enable();
+    }
+
+    public boolean disable() {
+        return mAdapter.disable();
+    }
+
+    void getProfileProxy(Context context,
+            BluetoothProfile.ServiceListener listener, int profile) {
+        mAdapter.getProfileProxy(context, listener, profile);
+    }
+
+    public Set<BluetoothDevice> getBondedDevices() {
+        return mAdapter.getBondedDevices();
+    }
+
+    public String getName() {
+        return mAdapter.getName();
+    }
+
+    public int getScanMode() {
+        return mAdapter.getScanMode();
+    }
+
+    public int getState() {
+        return mAdapter.getState();
+    }
+
+    public ParcelUuid[] getUuids() {
+        return mAdapter.getUuids();
+    }
+
+    public boolean isDiscovering() {
+        return mAdapter.isDiscovering();
+    }
+
+    public boolean isEnabled() {
+        return mAdapter.isEnabled();
+    }
+
+    public int getConnectionState() {
+        return mAdapter.getConnectionState();
+    }
+
+    public void setDiscoverableTimeout(int timeout) {
+        mAdapter.setDiscoverableTimeout(timeout);
+    }
+
+    public void setName(String name) {
+        mAdapter.setName(name);
+    }
+
+    public void setScanMode(int mode) {
+        mAdapter.setScanMode(mode);
+    }
+
+    public boolean setScanMode(int mode, int duration) {
+        return mAdapter.setScanMode(mode, duration);
+    }
+
+    public void startScanning(boolean force) {
+        // Only start if we're not already scanning
+        if (!mAdapter.isDiscovering()) {
+            if (!force) {
+                // Don't scan more than frequently than SCAN_EXPIRATION_MS,
+                // unless forced
+                if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
+                    return;
+                }
+
+                // If we are playing music, don't scan unless forced.
+                A2dpProfile a2dp = mProfileManager.getA2dpProfile();
+                if (a2dp != null && a2dp.isA2dpPlaying()) {
+                    return;
+                }
+            }
+
+            if (mAdapter.startDiscovery()) {
+                mLastScan = System.currentTimeMillis();
+            }
+        }
+    }
+
+    public void stopScanning() {
+        if (mAdapter.isDiscovering()) {
+            mAdapter.cancelDiscovery();
+        }
+    }
+
+    public synchronized int getBluetoothState() {
+        // Always sync state, in case it changed while paused
+        syncBluetoothState();
+        return mState;
+    }
+
+    synchronized void setBluetoothStateInt(int state) {
+        mState = state;
+
+        if (state == BluetoothAdapter.STATE_ON) {
+            // if mProfileManager hasn't been constructed yet, it will
+            // get the adapter UUIDs in its constructor when it is.
+            if (mProfileManager != null) {
+                mProfileManager.setBluetoothStateOn();
+            }
+        }
+    }
+
+    // Returns true if the state changed; false otherwise.
+    boolean syncBluetoothState() {
+        int currentState = mAdapter.getState();
+        if (currentState != mState) {
+            setBluetoothStateInt(mAdapter.getState());
+            return true;
+        }
+        return false;
+    }
+
+    public void setBluetoothEnabled(boolean enabled) {
+        boolean success = enabled
+                ? mAdapter.enable()
+                : mAdapter.disable();
+
+        if (success) {
+            setBluetoothStateInt(enabled
+                ? BluetoothAdapter.STATE_TURNING_ON
+                : BluetoothAdapter.STATE_TURNING_OFF);
+        } else {
+            if (Utils.V) {
+                Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
+                        "success for enabled: " + enabled);
+            }
+
+            syncBluetoothState();
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
new file mode 100644
index 0000000..623ccc3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * LocalBluetoothManager provides a simplified interface on top of a subset of
+ * the Bluetooth API. Note that {@link #getInstance} will return null
+ * if there is no Bluetooth adapter on this device, and callers must be
+ * prepared to handle this case.
+ */
+public final class LocalBluetoothManager {
+    private static final String TAG = "LocalBluetoothManager";
+
+    /** Singleton instance. */
+    private static LocalBluetoothManager sInstance;
+
+    private final Context mContext;
+
+    /** If a BT-related activity is in the foreground, this will be it. */
+    private Context mForegroundActivity;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+
+    private final CachedBluetoothDeviceManager mCachedDeviceManager;
+
+    /** The Bluetooth profile manager. */
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    /** The broadcast receiver event manager. */
+    private final BluetoothEventManager mEventManager;
+
+    public static synchronized LocalBluetoothManager getInstance(Context context,
+            BluetoothManagerCallback onInitCallback) {
+        if (sInstance == null) {
+            LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
+            if (adapter == null) {
+                return null;
+            }
+            // This will be around as long as this process is
+            Context appContext = context.getApplicationContext();
+            sInstance = new LocalBluetoothManager(adapter, appContext);
+            if (onInitCallback != null) {
+                onInitCallback.onBluetoothManagerInitialized(appContext, sInstance);
+            }
+        }
+
+        return sInstance;
+    }
+
+    private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
+        mContext = context;
+        mLocalAdapter = adapter;
+
+        mCachedDeviceManager = new CachedBluetoothDeviceManager(context, this);
+        mEventManager = new BluetoothEventManager(mLocalAdapter,
+                mCachedDeviceManager, context);
+        mProfileManager = new LocalBluetoothProfileManager(context,
+                mLocalAdapter, mCachedDeviceManager, mEventManager);
+    }
+
+    public LocalBluetoothAdapter getBluetoothAdapter() {
+        return mLocalAdapter;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public Context getForegroundActivity() {
+        return mForegroundActivity;
+    }
+
+    public boolean isForegroundActivity() {
+        return mForegroundActivity != null;
+    }
+
+    public synchronized void setForegroundActivity(Context context) {
+        if (context != null) {
+            Log.d(TAG, "setting foreground activity to non-null context");
+            mForegroundActivity = context;
+        } else {
+            if (mForegroundActivity != null) {
+                Log.d(TAG, "setting foreground activity to null");
+                mForegroundActivity = null;
+            }
+        }
+    }
+
+    public CachedBluetoothDeviceManager getCachedDeviceManager() {
+        return mCachedDeviceManager;
+    }
+
+    public BluetoothEventManager getEventManager() {
+        return mEventManager;
+    }
+
+    public LocalBluetoothProfileManager getProfileManager() {
+        return mProfileManager;
+    }
+
+    public interface BluetoothManagerCallback {
+        void onBluetoothManagerInitialized(Context appContext,
+                LocalBluetoothManager bluetoothManager);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
new file mode 100755
index 0000000..abcb989
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * LocalBluetoothProfile is an interface defining the basic
+ * functionality related to a Bluetooth profile.
+ */
+public interface LocalBluetoothProfile {
+
+    /**
+     * Returns true if the user can initiate a connection, false otherwise.
+     */
+    boolean isConnectable();
+
+    /**
+     * Returns true if the user can enable auto connection for this profile.
+     */
+    boolean isAutoConnectable();
+
+    boolean connect(BluetoothDevice device);
+
+    boolean disconnect(BluetoothDevice device);
+
+    int getConnectionStatus(BluetoothDevice device);
+
+    boolean isPreferred(BluetoothDevice device);
+
+    int getPreferred(BluetoothDevice device);
+
+    void setPreferred(BluetoothDevice device, boolean preferred);
+
+    boolean isProfileReady();
+
+    /** Display order for device profile settings. */
+    int getOrdinal();
+
+    /**
+     * Returns the string resource ID for the localized name for this profile.
+     * @param device the Bluetooth device (to distinguish between PAN roles)
+     */
+    int getNameResource(BluetoothDevice device);
+
+    /**
+     * Returns the string resource ID for the summary text for this profile
+     * for the specified device, e.g. "Use for media audio" or
+     * "Connected to media audio".
+     * @param device the device to query for profile connection status
+     * @return a string resource ID for the profile summary text
+     */
+    int getSummaryResourceForDevice(BluetoothDevice device);
+
+    int getDrawableResource(BluetoothClass btClass);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
new file mode 100644
index 0000000..8f5e1f1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelUuid;
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
+ * objects for the available Bluetooth profiles.
+ */
+public final class LocalBluetoothProfileManager {
+    private static final String TAG = "LocalBluetoothProfileManager";
+    private static final boolean DEBUG = Utils.D;
+    /** Singleton instance. */
+    private static LocalBluetoothProfileManager sInstance;
+
+    /**
+     * An interface for notifying BluetoothHeadset IPC clients when they have
+     * been connected to the BluetoothHeadset service.
+     * Only used by com.android.settings.bluetooth.DockService.
+     */
+    public interface ServiceListener {
+        /**
+         * Called to notify the client when this proxy object has been
+         * connected to the BluetoothHeadset service. Clients must wait for
+         * this callback before making IPC calls on the BluetoothHeadset
+         * service.
+         */
+        void onServiceConnected();
+
+        /**
+         * Called to notify the client that this proxy object has been
+         * disconnected from the BluetoothHeadset service. Clients must not
+         * make IPC calls on the BluetoothHeadset service after this callback.
+         * This callback will currently only occur if the application hosting
+         * the BluetoothHeadset service, but may be called more often in future.
+         */
+        void onServiceDisconnected();
+    }
+
+    private final Context mContext;
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final BluetoothEventManager mEventManager;
+
+    private A2dpProfile mA2dpProfile;
+    private HeadsetProfile mHeadsetProfile;
+    private MapProfile mMapProfile;
+    private final HidProfile mHidProfile;
+    private OppProfile mOppProfile;
+    private final PanProfile mPanProfile;
+    private final PbapServerProfile mPbapProfile;
+
+    /**
+     * Mapping from profile name, e.g. "HEADSET" to profile object.
+     */
+    private final Map<String, LocalBluetoothProfile>
+            mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
+
+    LocalBluetoothProfileManager(Context context,
+            LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            BluetoothEventManager eventManager) {
+        mContext = context;
+
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mEventManager = eventManager;
+        // pass this reference to adapter and event manager (circular dependency)
+        mLocalAdapter.setProfileManager(this);
+        mEventManager.setProfileManager(this);
+
+        ParcelUuid[] uuids = adapter.getUuids();
+
+        // uuids may be null if Bluetooth is turned off
+        if (uuids != null) {
+            updateLocalProfiles(uuids);
+        }
+
+        // Always add HID and PAN profiles
+        mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
+        addProfile(mHidProfile, HidProfile.NAME,
+                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
+
+        mPanProfile = new PanProfile(context);
+        addPanProfile(mPanProfile, PanProfile.NAME,
+                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+
+        if(DEBUG) Log.d(TAG, "Adding local MAP profile");
+        mMapProfile = new MapProfile(mContext, mLocalAdapter,
+                mDeviceManager, this);
+        addProfile(mMapProfile, MapProfile.NAME,
+                BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
+
+       //Create PBAP server profile, but do not add it to list of profiles
+       // as we do not need to monitor the profile as part of profile list
+        mPbapProfile = new PbapServerProfile(context);
+
+        if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
+    }
+
+    /**
+     * Initialize or update the local profile objects. If a UUID was previously
+     * present but has been removed, we print a warning but don't remove the
+     * profile object as it might be referenced elsewhere, or the UUID might
+     * come back and we don't want multiple copies of the profile objects.
+     * @param uuids
+     */
+    void updateLocalProfiles(ParcelUuid[] uuids) {
+        // A2DP
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
+            if (mA2dpProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
+                mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
+                addProfile(mA2dpProfile, A2dpProfile.NAME,
+                        BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mA2dpProfile != null) {
+            Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
+        }
+
+        // Headset / Handsfree
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
+            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
+            if (mHeadsetProfile == null) {
+                if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
+                mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
+                        mDeviceManager, this);
+                addProfile(mHeadsetProfile, HeadsetProfile.NAME,
+                        BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mHeadsetProfile != null) {
+            Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
+        }
+
+        // OPP
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+            if (mOppProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local OPP profile");
+                mOppProfile = new OppProfile();
+                // Note: no event handler for OPP, only name map.
+                mProfileNameMap.put(OppProfile.NAME, mOppProfile);
+            }
+        } else if (mOppProfile != null) {
+            Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
+        }
+        mEventManager.registerProfileIntentReceiver();
+
+        // There is no local SDP record for HID and Settings app doesn't control PBAP
+    }
+
+    private final Collection<ServiceListener> mServiceListeners =
+            new ArrayList<ServiceListener>();
+
+    private void addProfile(LocalBluetoothProfile profile,
+            String profileName, String stateChangedAction) {
+        mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
+        mProfileNameMap.put(profileName, profile);
+    }
+
+    private void addPanProfile(LocalBluetoothProfile profile,
+            String profileName, String stateChangedAction) {
+        mEventManager.addProfileHandler(stateChangedAction,
+                new PanStateChangedHandler(profile));
+        mProfileNameMap.put(profileName, profile);
+    }
+
+    public LocalBluetoothProfile getProfileByName(String name) {
+        return mProfileNameMap.get(name);
+    }
+
+    // Called from LocalBluetoothAdapter when state changes to ON
+    void setBluetoothStateOn() {
+        ParcelUuid[] uuids = mLocalAdapter.getUuids();
+        if (uuids != null) {
+            updateLocalProfiles(uuids);
+        }
+        mEventManager.readPairedDevices();
+    }
+
+    /**
+     * Generic handler for connection state change events for the specified profile.
+     */
+    private class StateChangedHandler implements BluetoothEventManager.Handler {
+        final LocalBluetoothProfile mProfile;
+
+        StateChangedHandler(LocalBluetoothProfile profile) {
+            mProfile = profile;
+        }
+
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "StateChangedHandler found new device: " + device);
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
+                        LocalBluetoothProfileManager.this, device);
+            }
+            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+                    oldState == BluetoothProfile.STATE_CONNECTING) {
+                Log.i(TAG, "Failed to connect " + mProfile + " device");
+            }
+
+            cachedDevice.onProfileStateChanged(mProfile, newState);
+            cachedDevice.refresh();
+        }
+    }
+
+    /** State change handler for NAP and PANU profiles. */
+    private class PanStateChangedHandler extends StateChangedHandler {
+
+        PanStateChangedHandler(LocalBluetoothProfile profile) {
+            super(profile);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            PanProfile panProfile = (PanProfile) mProfile;
+            int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
+            panProfile.setLocalRole(device, role);
+            super.onReceive(context, intent, device);
+        }
+    }
+
+    // called from DockService
+    public void addServiceListener(ServiceListener l) {
+        mServiceListeners.add(l);
+    }
+
+    // called from DockService
+    public void removeServiceListener(ServiceListener l) {
+        mServiceListeners.remove(l);
+    }
+
+    // not synchronized: use only from UI thread! (TODO: verify)
+    void callServiceConnectedListeners() {
+        for (ServiceListener l : mServiceListeners) {
+            l.onServiceConnected();
+        }
+    }
+
+    // not synchronized: use only from UI thread! (TODO: verify)
+    void callServiceDisconnectedListeners() {
+        for (ServiceListener listener : mServiceListeners) {
+            listener.onServiceDisconnected();
+        }
+    }
+
+    // This is called by DockService, so check Headset and A2DP.
+    public synchronized boolean isManagerReady() {
+        // Getting just the headset profile is fine for now. Will need to deal with A2DP
+        // and others if they aren't always in a ready state.
+        LocalBluetoothProfile profile = mHeadsetProfile;
+        if (profile != null) {
+            return profile.isProfileReady();
+        }
+        profile = mA2dpProfile;
+        if (profile != null) {
+            return profile.isProfileReady();
+        }
+        return false;
+    }
+
+    public A2dpProfile getA2dpProfile() {
+        return mA2dpProfile;
+    }
+
+    public HeadsetProfile getHeadsetProfile() {
+        return mHeadsetProfile;
+    }
+
+    public PbapServerProfile getPbapProfile(){
+        return mPbapProfile;
+    }
+
+    public MapProfile getMapProfile(){
+        return mMapProfile;
+    }
+
+    /**
+     * Fill in a list of LocalBluetoothProfile objects that are supported by
+     * the local device and the remote device.
+     *
+     * @param uuids of the remote device
+     * @param localUuids UUIDs of the local device
+     * @param profiles The list of profiles to fill
+     * @param removedProfiles list of profiles that were removed
+     */
+    synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
+            Collection<LocalBluetoothProfile> profiles,
+            Collection<LocalBluetoothProfile> removedProfiles,
+            boolean isPanNapConnected, BluetoothDevice device) {
+        // Copy previous profile list into removedProfiles
+        removedProfiles.clear();
+        removedProfiles.addAll(profiles);
+        profiles.clear();
+
+        if (uuids == null) {
+            return;
+        }
+
+        if (mHeadsetProfile != null) {
+            if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
+                    BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
+                    (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
+                            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+                profiles.add(mHeadsetProfile);
+                removedProfiles.remove(mHeadsetProfile);
+            }
+        }
+
+        if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
+            mA2dpProfile != null) {
+            profiles.add(mA2dpProfile);
+            removedProfiles.remove(mA2dpProfile);
+        }
+
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
+            mOppProfile != null) {
+            profiles.add(mOppProfile);
+            removedProfiles.remove(mOppProfile);
+        }
+
+        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
+             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
+            mHidProfile != null) {
+            profiles.add(mHidProfile);
+            removedProfiles.remove(mHidProfile);
+        }
+
+        if(isPanNapConnected)
+            if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
+        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
+            mPanProfile != null) || isPanNapConnected) {
+            profiles.add(mPanProfile);
+            removedProfiles.remove(mPanProfile);
+        }
+
+        if ((mMapProfile != null) &&
+            (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
+            profiles.add(mMapProfile);
+            removedProfiles.remove(mMapProfile);
+            mMapProfile.setPreferred(device, true);
+        }
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
new file mode 100644
index 0000000..e6a152f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * MapProfile handles Bluetooth MAP profile.
+ */
+public final class MapProfile implements LocalBluetoothProfile {
+    private static final String TAG = "MapProfile";
+    private static boolean V = true;
+
+    private BluetoothMap mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final ParcelUuid[] UUIDS = {
+        BluetoothUuid.MAP,
+        BluetoothUuid.MNS,
+        BluetoothUuid.MAS,
+    };
+
+    static final String NAME = "MAP";
+
+    // Order of this profile in device profiles list
+
+    // These callbacks run on the main thread.
+    private final class MapServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothMap) proxy;
+            // We just bound to the service, so refresh the UI for any connected MAP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "MapProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(MapProfile.this,
+                        BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+
+            mProfileManager.callServiceConnectedListeners();
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mProfileManager.callServiceDisconnectedListeners();
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+        return mIsProfileReady;
+    }
+
+    MapProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new MapServiceListener(),
+                BluetoothProfile.MAP);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if(V)Log.d(TAG,"connect() - should not get called");
+        return false; // MAP never connects out
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
+            if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+            return mService.disconnect(device);
+        } else {
+            return false;
+        }
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device));
+
+        return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+                ? mService.getConnectionState(device)
+                : BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return BluetoothProfile.MAP;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_map;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_map_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_map_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up MAP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
new file mode 100755
index 0000000..31e675c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import com.android.settingslib.R;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+
+/**
+ * OppProfile handles Bluetooth OPP.
+ */
+final class OppProfile implements LocalBluetoothProfile {
+
+    static final String NAME = "OPP";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 2;
+
+    public boolean isConnectable() {
+        return false;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        return false;
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    }
+
+    public boolean isProfileReady() {
+        return true;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_opp;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return 0;   // OPP profile not displayed in UI
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return 0;   // no icon for OPP
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
new file mode 100755
index 0000000..3af89e6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * PanProfile handles Bluetooth PAN profile (NAP and PANU).
+ */
+final class PanProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PanProfile";
+    private static boolean V = true;
+
+    private BluetoothPan mService;
+    private boolean mIsProfileReady;
+
+    // Tethering direction for each device
+    private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap =
+            new HashMap<BluetoothDevice, Integer>();
+
+    static final String NAME = "PAN";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 4;
+
+    // These callbacks run on the main thread.
+    private final class PanServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothPan) proxy;
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PanProfile(Context context) {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        adapter.getProfileProxy(context, new PanServiceListener(),
+                BluetoothProfile.PAN);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                mService.disconnect(sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        // return current connection status so profile checkbox is set correctly
+        return getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return -1;
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        // ignore: isPreferred is always true for PAN
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        if (isLocalRoleNap(device)) {
+            return R.string.bluetooth_profile_pan_nap;
+        } else {
+            return R.string.bluetooth_profile_pan;
+        }
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_pan_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                if (isLocalRoleNap(device)) {
+                    return R.string.bluetooth_pan_nap_profile_summary_connected;
+                } else {
+                    return R.string.bluetooth_pan_user_profile_summary_connected;
+                }
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_network_pan;
+    }
+
+    // Tethering direction determines UI strings.
+    void setLocalRole(BluetoothDevice device, int role) {
+        mDeviceRoleMap.put(device, role);
+    }
+
+    boolean isLocalRoleNap(BluetoothDevice device) {
+        if (mDeviceRoleMap.containsKey(device)) {
+            return mDeviceRoleMap.get(device) == BluetoothPan.LOCAL_NAP_ROLE;
+        } else {
+            return false;
+        }
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PAN proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
new file mode 100755
index 0000000..9e76933
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPbap;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+/**
+ * PBAPServer Profile
+ */
+public final class PbapServerProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PbapServerProfile";
+    private static boolean V = true;
+
+    private BluetoothPbap mService;
+    private boolean mIsProfileReady;
+
+    static final String NAME = "PBAP Server";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 6;
+
+    // The UUIDs indicate that remote device might access pbap server
+    static final ParcelUuid[] PBAB_CLIENT_UUIDS = {
+        BluetoothUuid.HSP,
+        BluetoothUuid.Handsfree,
+        BluetoothUuid.PBAP_PCE
+    };
+
+    // These callbacks run on the main thread.
+    private final class PbapServiceListener
+            implements BluetoothPbap.ServiceListener {
+
+        public void onServiceConnected(BluetoothPbap proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothPbap) proxy;
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected() {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PbapServerProfile(Context context) {
+        BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        /*Can't connect from server */
+        return false;
+
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect();
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        if (mService.isConnected(device))
+            return BluetoothProfile.STATE_CONNECTED;
+        else
+            return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return -1;
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        // ignore: isPreferred is always true for PBAP
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap_summary;
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                mService.close();
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PBAP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
new file mode 100644
index 0000000..c919426
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
@@ -0,0 +1,43 @@
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.R;
+
+public class Utils {
+    public static final boolean V = false; // verbose logging
+    public static final boolean D = true;  // regular logging
+
+    private static ErrorListener sErrorListener;
+
+    public static int getConnectionStateSummary(int connectionState) {
+        switch (connectionState) {
+        case BluetoothProfile.STATE_CONNECTED:
+            return R.string.bluetooth_connected;
+        case BluetoothProfile.STATE_CONNECTING:
+            return R.string.bluetooth_connecting;
+        case BluetoothProfile.STATE_DISCONNECTED:
+            return R.string.bluetooth_disconnected;
+        case BluetoothProfile.STATE_DISCONNECTING:
+            return R.string.bluetooth_disconnecting;
+        default:
+            return 0;
+        }
+    }
+
+    static void showError(Context context, String name, int messageResId) {
+        if (sErrorListener != null) {
+            sErrorListener.onShowError(context, name, messageResId);
+        }
+    }
+
+    public static void setErrorListener(ErrorListener listener) {
+        sErrorListener = listener;
+    }
+
+    public interface ErrorListener {
+        void onShowError(Context context, String name, int messageResId);
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
new file mode 100644
index 0000000..e8ab220
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkInfo.State;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.LruCache;
+
+import com.android.settingslib.R;
+
+import java.util.Map;
+
+
+public class AccessPoint implements Comparable<AccessPoint> {
+    static final String TAG = "SettingsLib.AccessPoint";
+
+    /**
+     * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels
+     */
+    public static final int LOWER_FREQ_24GHZ = 2400;
+
+    /**
+     * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels
+     */
+    public static final int HIGHER_FREQ_24GHZ = 2500;
+
+    /**
+     * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
+     */
+    public static final int LOWER_FREQ_5GHZ = 4900;
+
+    /**
+     * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
+     */
+    public static final int HIGHER_FREQ_5GHZ = 5900;
+
+
+    /**
+     * Experimental: we should be able to show the user the list of BSSIDs and bands
+     *  for that SSID.
+     *  For now this data is used only with Verbose Logging so as to show the band and number
+     *  of BSSIDs on which that network is seen.
+     */
+    public LruCache<String, ScanResult> mScanResultCache;
+    private static final String KEY_NETWORKINFO = "key_networkinfo";
+    private static final String KEY_WIFIINFO = "key_wifiinfo";
+    private static final String KEY_SCANRESULT = "key_scanresult";
+    private static final String KEY_CONFIG = "key_config";
+
+    /**
+     * These values are matched in string arrays -- changes must be kept in sync
+     */
+    public static final int SECURITY_NONE = 0;
+    public static final int SECURITY_WEP = 1;
+    public static final int SECURITY_PSK = 2;
+    public static final int SECURITY_EAP = 3;
+
+    private static final int PSK_UNKNOWN = 0;
+    private static final int PSK_WPA = 1;
+    private static final int PSK_WPA2 = 2;
+    private static final int PSK_WPA_WPA2 = 3;
+
+    private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
+    private final Context mContext;
+
+    private String ssid;
+    private int security;
+    private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
+
+    private int pskType = PSK_UNKNOWN;
+
+    private WifiConfiguration mConfig;
+    private ScanResult mScanResult;
+
+    private int mRssi = Integer.MAX_VALUE;
+    private long mSeen = 0;
+
+    private WifiInfo mInfo;
+    private NetworkInfo mNetworkInfo;
+    private AccessPointListener mAccessPointListener;
+
+    private Object mTag;
+
+    public AccessPoint(Context context, Bundle savedState) {
+        mContext = context;
+        mConfig = savedState.getParcelable(KEY_CONFIG);
+        if (mConfig != null) {
+            loadConfig(mConfig);
+        }
+        mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
+        if (mScanResult != null) {
+            loadResult(mScanResult);
+        }
+        mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
+        if (savedState.containsKey(KEY_NETWORKINFO)) {
+            mNetworkInfo = savedState.getParcelable(KEY_NETWORKINFO);
+        }
+        update(mInfo, mNetworkInfo);
+    }
+
+    AccessPoint(Context context, ScanResult result) {
+        mContext = context;
+        loadResult(result);
+    }
+
+    AccessPoint(Context context, WifiConfiguration config) {
+        mContext = context;
+        loadConfig(config);
+    }
+
+    @Override
+    public int compareTo(AccessPoint other) {
+        // Active one goes first.
+        if (isActive() && !other.isActive()) return -1;
+        if (!isActive() && other.isActive()) return 1;
+
+        // Reachable one goes before unreachable one.
+        if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
+        if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
+
+        // Configured one goes before unconfigured one.
+        if (networkId != WifiConfiguration.INVALID_NETWORK_ID
+                && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
+        if (networkId == WifiConfiguration.INVALID_NETWORK_ID
+                && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
+
+        // Sort by signal strength.
+        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+        if (difference != 0) {
+            return difference;
+        }
+        // Sort by ssid.
+        return ssid.compareToIgnoreCase(other.ssid);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof AccessPoint)) return false;
+        return (this.compareTo((AccessPoint) other) == 0);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 0;
+        if (mInfo != null) result += 13 * mInfo.hashCode();
+        result += 19 * mRssi;
+        result += 23 * networkId;
+        result += 29 * ssid.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder().append("AccessPoint(")
+                .append(ssid);
+        if (isSaved()) {
+            builder.append(',').append("saved");
+        }
+        if (isActive()) {
+            builder.append(',').append("active");
+        }
+        if (isEphemeral()) {
+            builder.append(',').append("ephemeral");
+        }
+        if (isConnectable()) {
+            builder.append(',').append("connectable");
+        }
+        if (security != SECURITY_NONE) {
+            builder.append(',').append(securityToString(security, pskType));
+        }
+        return builder.append(')').toString();
+    }
+
+    public boolean matches(ScanResult result) {
+        return ssid.equals(result.SSID) && security == getSecurity(result);
+    }
+
+    public boolean matches(WifiConfiguration config) {
+        return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
+    }
+
+    public WifiConfiguration getConfig() {
+        return mConfig;
+    }
+
+    public void clearConfig() {
+        mConfig = null;
+        networkId = WifiConfiguration.INVALID_NETWORK_ID;
+    }
+
+    public WifiInfo getInfo() {
+        return mInfo;
+    }
+
+    public int getLevel() {
+        if (mRssi == Integer.MAX_VALUE) {
+            return -1;
+        }
+        return WifiManager.calculateSignalLevel(mRssi, 4);
+    }
+
+    public NetworkInfo getNetworkInfo() {
+        return mNetworkInfo;
+    }
+
+    public int getSecurity() {
+        return security;
+    }
+
+    public String getSecurityString(boolean concise) {
+        Context context = mContext;
+        switch(security) {
+            case SECURITY_EAP:
+                return concise ? context.getString(R.string.wifi_security_short_eap) :
+                    context.getString(R.string.wifi_security_eap);
+            case SECURITY_PSK:
+                switch (pskType) {
+                    case PSK_WPA:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa) :
+                            context.getString(R.string.wifi_security_wpa);
+                    case PSK_WPA2:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa2) :
+                            context.getString(R.string.wifi_security_wpa2);
+                    case PSK_WPA_WPA2:
+                        return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) :
+                            context.getString(R.string.wifi_security_wpa_wpa2);
+                    case PSK_UNKNOWN:
+                    default:
+                        return concise ? context.getString(R.string.wifi_security_short_psk_generic)
+                                : context.getString(R.string.wifi_security_psk_generic);
+                }
+            case SECURITY_WEP:
+                return concise ? context.getString(R.string.wifi_security_short_wep) :
+                    context.getString(R.string.wifi_security_wep);
+            case SECURITY_NONE:
+            default:
+                return concise ? "" : context.getString(R.string.wifi_security_none);
+        }
+    }
+
+    public String getSsid() {
+        return ssid;
+    }
+
+    public DetailedState getDetailedState() {
+        return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
+    }
+
+    public String getSummary() {
+        // Update to new summary
+        StringBuilder summary = new StringBuilder();
+
+        if (isActive()) { // This is the active connection
+            summary.append(getSummary(mContext, getDetailedState(),
+                    networkId == WifiConfiguration.INVALID_NETWORK_ID));
+        } else if (mConfig != null
+                && mConfig.hasNoInternetAccess()) {
+            summary.append(mContext.getString(R.string.wifi_no_internet));
+        } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
+                mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
+               || mConfig.autoJoinStatus
+                >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
+            if (mConfig.autoJoinStatus
+                    >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
+                if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
+                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) {
+                    summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
+                } else {
+                    summary.append(mContext.getString(R.string.wifi_disabled_wifi_failure));
+                }
+            } else {
+                switch (mConfig.disableReason) {
+                    case WifiConfiguration.DISABLED_AUTH_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
+                        break;
+                    case WifiConfiguration.DISABLED_DHCP_FAILURE:
+                    case WifiConfiguration.DISABLED_DNS_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                        break;
+                    case WifiConfiguration.DISABLED_UNKNOWN_REASON:
+                    case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
+                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
+                        break;
+                }
+            }
+        } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
+            summary.append(mContext.getString(R.string.wifi_not_in_range));
+        } else { // In range, not disabled.
+            if (mConfig != null) { // Is saved network
+                summary.append(mContext.getString(R.string.wifi_remembered));
+            }
+        }
+
+        if (WifiTracker.sVerboseLogging > 0) {
+            // Add RSSI/band information for this config, what was seen up to 6 seconds ago
+            // verbose WiFi Logging is only turned on thru developers settings
+            if (mInfo != null && mNetworkInfo != null) { // This is the active connection
+                summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
+            }
+            summary.append(" " + getVisibilityStatus());
+            if (mConfig != null && mConfig.autoJoinStatus > 0) {
+                summary.append(" (" + mConfig.autoJoinStatus);
+                if (mConfig.blackListTimestamp > 0) {
+                    long now = System.currentTimeMillis();
+                    long diff = (now - mConfig.blackListTimestamp)/1000;
+                    long sec = diff%60; //seconds
+                    long min = (diff/60)%60; //minutes
+                    long hour = (min/60)%60; //hours
+                    summary.append(", ");
+                    if (hour > 0) summary.append(Long.toString(hour) + "h ");
+                    summary.append( Long.toString(min) + "m ");
+                    summary.append( Long.toString(sec) + "s ");
+                }
+                summary.append(")");
+            }
+            if (mConfig != null && mConfig.numIpConfigFailures > 0) {
+                summary.append(" ipf=").append(mConfig.numIpConfigFailures);
+            }
+            if (mConfig != null && mConfig.numConnectionFailures > 0) {
+                summary.append(" cf=").append(mConfig.numConnectionFailures);
+            }
+            if (mConfig != null && mConfig.numAuthFailures > 0) {
+                summary.append(" authf=").append(mConfig.numAuthFailures);
+            }
+            if (mConfig != null && mConfig.numNoInternetAccessReports > 0) {
+                summary.append(" noInt=").append(mConfig.numNoInternetAccessReports);
+            }
+        }
+        return summary.toString();
+    }
+
+    /**
+     * Returns the visibility status of the WifiConfiguration.
+     *
+     * @return autojoin debugging information
+     * TODO: use a string formatter
+     * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
+     * For instance [-40,5/-30,2]
+     */
+    private String getVisibilityStatus() {
+        StringBuilder visibility = new StringBuilder();
+        StringBuilder scans24GHz = null;
+        StringBuilder scans5GHz = null;
+        String bssid = null;
+
+        long now = System.currentTimeMillis();
+
+        if (mInfo != null) {
+            bssid = mInfo.getBSSID();
+            if (bssid != null) {
+                visibility.append(" ").append(bssid);
+            }
+            visibility.append(" rssi=").append(mInfo.getRssi());
+            visibility.append(" ");
+            visibility.append(" score=").append(mInfo.score);
+            visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
+            visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
+            visibility.append(String.format("%.1f ", mInfo.txBadRate));
+            visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate));
+        }
+
+        if (mScanResultCache != null) {
+            int rssi5 = WifiConfiguration.INVALID_RSSI;
+            int rssi24 = WifiConfiguration.INVALID_RSSI;
+            int num5 = 0;
+            int num24 = 0;
+            int numBlackListed = 0;
+            int n24 = 0; // Number scan results we included in the string
+            int n5 = 0; // Number scan results we included in the string
+            Map<String, ScanResult> list = mScanResultCache.snapshot();
+            // TODO: sort list by RSSI or age
+            for (ScanResult result : list.values()) {
+                if (result.seen == 0)
+                    continue;
+
+                if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
+
+                if (result.frequency >= LOWER_FREQ_5GHZ
+                        && result.frequency <= HIGHER_FREQ_5GHZ) {
+                    // Strictly speaking: [4915, 5825]
+                    // number of known BSSID on 5GHz band
+                    num5 = num5 + 1;
+                } else if (result.frequency >= LOWER_FREQ_24GHZ
+                        && result.frequency <= HIGHER_FREQ_24GHZ) {
+                    // Strictly speaking: [2412, 2482]
+                    // number of known BSSID on 2.4Ghz band
+                    num24 = num24 + 1;
+                }
+
+                // Ignore results seen, older than 20 seconds
+                if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
+
+                if (result.frequency >= LOWER_FREQ_5GHZ
+                        && result.frequency <= HIGHER_FREQ_5GHZ) {
+                    if (result.level > rssi5) {
+                        rssi5 = result.level;
+                    }
+                    if (n5 < 4) {
+                        if (scans5GHz == null) scans5GHz = new StringBuilder();
+                        scans5GHz.append(" \n{").append(result.BSSID);
+                        if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
+                        scans5GHz.append("=").append(result.frequency);
+                        scans5GHz.append(",").append(result.level);
+                        if (result.autoJoinStatus != 0) {
+                            scans5GHz.append(",st=").append(result.autoJoinStatus);
+                        }
+                        if (result.numIpConfigFailures != 0) {
+                            scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
+                        }
+                        scans5GHz.append("}");
+                        n5++;
+                    }
+                } else if (result.frequency >= LOWER_FREQ_24GHZ
+                        && result.frequency <= HIGHER_FREQ_24GHZ) {
+                    if (result.level > rssi24) {
+                        rssi24 = result.level;
+                    }
+                    if (n24 < 4) {
+                        if (scans24GHz == null) scans24GHz = new StringBuilder();
+                        scans24GHz.append(" \n{").append(result.BSSID);
+                        if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
+                        scans24GHz.append("=").append(result.frequency);
+                        scans24GHz.append(",").append(result.level);
+                        if (result.autoJoinStatus != 0) {
+                            scans24GHz.append(",st=").append(result.autoJoinStatus);
+                        }
+                        if (result.numIpConfigFailures != 0) {
+                            scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
+                        }
+                        scans24GHz.append("}");
+                        n24++;
+                    }
+                }
+            }
+            visibility.append(" [");
+            if (num24 > 0) {
+                visibility.append("(").append(num24).append(")");
+                if (n24 <= 4) {
+                    if (scans24GHz != null) {
+                        visibility.append(scans24GHz.toString());
+                    }
+                } else {
+                    visibility.append("max=").append(rssi24);
+                    if (scans24GHz != null) {
+                        visibility.append(",").append(scans24GHz.toString());
+                    }
+                }
+            }
+            visibility.append(";");
+            if (num5 > 0) {
+                visibility.append("(").append(num5).append(")");
+                if (n5 <= 4) {
+                    if (scans5GHz != null) {
+                        visibility.append(scans5GHz.toString());
+                    }
+                } else {
+                    visibility.append("max=").append(rssi5);
+                    if (scans5GHz != null) {
+                        visibility.append(",").append(scans5GHz.toString());
+                    }
+                }
+            }
+            if (numBlackListed > 0)
+                visibility.append("!").append(numBlackListed);
+            visibility.append("]");
+        } else {
+            if (mRssi != Integer.MAX_VALUE) {
+                visibility.append(" rssi=");
+                visibility.append(mRssi);
+                if (mScanResult != null) {
+                    visibility.append(", f=");
+                    visibility.append(mScanResult.frequency);
+                }
+            }
+        }
+
+        return visibility.toString();
+    }
+
+    /**
+     * Return whether this is the active connection.
+     * For ephemeral connections (networkId is invalid), this returns false if the network is
+     * disconnected.
+     */
+    public boolean isActive() {
+        return mNetworkInfo != null &&
+                (networkId != WifiConfiguration.INVALID_NETWORK_ID ||
+                 mNetworkInfo.getState() != State.DISCONNECTED);
+    }
+
+    public boolean isConnectable() {
+        return getLevel() != -1 && getDetailedState() == null;
+    }
+
+    public boolean isEphemeral() {
+        return !isSaved() && mNetworkInfo != null && mNetworkInfo.getState() != State.DISCONNECTED;
+    }
+
+    /** Return whether the given {@link WifiInfo} is for this access point. */
+    private boolean isInfoForThisAccessPoint(WifiInfo info) {
+        if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
+            return networkId == info.getNetworkId();
+        } else {
+            // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
+            // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
+            // TODO: Handle hex string SSIDs.
+            return ssid.equals(removeDoubleQuotes(info.getSSID()));
+        }
+    }
+
+    public boolean isSaved() {
+        return networkId != WifiConfiguration.INVALID_NETWORK_ID;
+    }
+
+    public Object getTag() {
+        return mTag;
+    }
+
+    public void setTag(Object tag) {
+        mTag = tag;
+    }
+
+    /**
+     * Generate and save a default wifiConfiguration with common values.
+     * Can only be called for unsecured networks.
+     */
+    public void generateOpenNetworkConfig() {
+        if (security != SECURITY_NONE)
+            throw new IllegalStateException();
+        if (mConfig != null)
+            return;
+        mConfig = new WifiConfiguration();
+        mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
+        mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
+    }
+
+    void loadConfig(WifiConfiguration config) {
+        ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
+        security = getSecurity(config);
+        networkId = config.networkId;
+        mConfig = config;
+    }
+
+    private void loadResult(ScanResult result) {
+        ssid = result.SSID;
+        security = getSecurity(result);
+        if (security == SECURITY_PSK)
+            pskType = getPskType(result);
+        mRssi = result.level;
+        mScanResult = result;
+        if (result.seen > mSeen) {
+            mSeen = result.seen;
+        }
+    }
+
+    public void saveWifiState(Bundle savedState) {
+        savedState.putParcelable(KEY_CONFIG, mConfig);
+        savedState.putParcelable(KEY_SCANRESULT, mScanResult);
+        savedState.putParcelable(KEY_WIFIINFO, mInfo);
+        if (mNetworkInfo != null) {
+            savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
+        }
+    }
+
+    public void setListener(AccessPointListener listener) {
+        mAccessPointListener = listener;
+    }
+
+    boolean update(ScanResult result) {
+        if (result.seen > mSeen) {
+            mSeen = result.seen;
+        }
+        if (WifiTracker.sVerboseLogging > 0) {
+            if (mScanResultCache == null) {
+                mScanResultCache = new LruCache<String, ScanResult>(32);
+            }
+            mScanResultCache.put(result.BSSID, result);
+        }
+
+        if (ssid.equals(result.SSID) && security == getSecurity(result)) {
+            if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
+                int oldLevel = getLevel();
+                mRssi = result.level;
+                if (getLevel() != oldLevel && mAccessPointListener != null) {
+                    mAccessPointListener.onLevelChanged(this);
+                }
+            }
+            // This flag only comes from scans, is not easily saved in config
+            if (security == SECURITY_PSK) {
+                pskType = getPskType(result);
+            }
+            mScanResult = result;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    boolean update(WifiInfo info, NetworkInfo networkInfo) {
+        boolean reorder = false;
+        if (info != null && isInfoForThisAccessPoint(info)) {
+            reorder = (mInfo == null);
+            mRssi = info.getRssi();
+            mInfo = info;
+            mNetworkInfo = networkInfo;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+        } else if (mInfo != null) {
+            reorder = true;
+            mInfo = null;
+            mNetworkInfo = null;
+            if (mAccessPointListener != null) {
+                mAccessPointListener.onAccessPointChanged(this);
+            }
+        }
+        return reorder;
+    }
+
+    public static String getSummary(Context context, String ssid, DetailedState state,
+            boolean isEphemeral) {
+        if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) {
+            // Special case for connected + ephemeral networks.
+            return context.getString(R.string.connected_via_wfa);
+        }
+
+        String[] formats = context.getResources().getStringArray((ssid == null)
+                ? R.array.wifi_status : R.array.wifi_status_with_ssid);
+        int index = state.ordinal();
+
+        if (index >= formats.length || formats[index].length() == 0) {
+            return null;
+        }
+        return String.format(formats[index], ssid);
+    }
+
+    public static String getSummary(Context context, DetailedState state, boolean isEphemeral) {
+        return getSummary(context, null, state, isEphemeral);
+    }
+
+    public static String convertToQuotedString(String string) {
+        return "\"" + string + "\"";
+    }
+
+    private static int getPskType(ScanResult result) {
+        boolean wpa = result.capabilities.contains("WPA-PSK");
+        boolean wpa2 = result.capabilities.contains("WPA2-PSK");
+        if (wpa2 && wpa) {
+            return PSK_WPA_WPA2;
+        } else if (wpa2) {
+            return PSK_WPA2;
+        } else if (wpa) {
+            return PSK_WPA;
+        } else {
+            Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
+            return PSK_UNKNOWN;
+        }
+    }
+
+    private static int getSecurity(ScanResult result) {
+        if (result.capabilities.contains("WEP")) {
+            return SECURITY_WEP;
+        } else if (result.capabilities.contains("PSK")) {
+            return SECURITY_PSK;
+        } else if (result.capabilities.contains("EAP")) {
+            return SECURITY_EAP;
+        }
+        return SECURITY_NONE;
+    }
+
+    static int getSecurity(WifiConfiguration config) {
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+            return SECURITY_PSK;
+        }
+        if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+                config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+            return SECURITY_EAP;
+        }
+        return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
+    }
+
+    public static String securityToString(int security, int pskType) {
+        if (security == SECURITY_WEP) {
+            return "WEP";
+        } else if (security == SECURITY_PSK) {
+            if (pskType == PSK_WPA) {
+                return "WPA";
+            } else if (pskType == PSK_WPA2) {
+                return "WPA2";
+            } else if (pskType == PSK_WPA_WPA2) {
+                return "WPA_WPA2";
+            }
+            return "PSK";
+        } else if (security == SECURITY_EAP) {
+            return "EAP";
+        }
+        return "NONE";
+    }
+
+    static String removeDoubleQuotes(String string) {
+        int length = string.length();
+        if ((length > 1) && (string.charAt(0) == '"')
+                && (string.charAt(length - 1) == '"')) {
+            return string.substring(1, length - 1);
+        }
+        return string;
+    }
+
+    public interface AccessPointListener {
+        void onAccessPointChanged(AccessPoint accessPoint);
+        void onLevelChanged(AccessPoint accessPoint);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
new file mode 100644
index 0000000..2eb7abf
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+import android.widget.Toast;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tracks saved or available wifi networks and their state.
+ */
+public class WifiTracker {
+    private static final String TAG = "WifiTracker";
+
+    /** verbose logging flag. this flag is set thru developer debugging options
+     * and used so as to assist with in-the-field WiFi connectivity debugging  */
+    public static int sVerboseLogging = 0;
+
+    // TODO: Allow control of this?
+    // Combo scans can take 5-6s to complete - set to 10s.
+    private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
+
+    private final Context mContext;
+    private final WifiManager mWifiManager;
+    private final IntentFilter mFilter;
+
+    private final AtomicBoolean mConnected = new AtomicBoolean(false);
+    private final WifiListener mListener;
+    private final boolean mIncludeSaved;
+    private final boolean mIncludeScans;
+
+    private boolean mSavedNetworksExist;
+    private boolean mRegistered;
+    private ArrayList<AccessPoint> mAccessPoints = new ArrayList<>();
+    private ArrayList<AccessPoint> mCachedAccessPoints = new ArrayList<>();
+
+    private NetworkInfo mLastNetworkInfo;
+    private WifiInfo mLastInfo;
+
+    @VisibleForTesting
+    Scanner mScanner;
+
+    public WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
+            boolean includeScans) {
+        this(context, wifiListener, includeSaved, includeScans,
+                (WifiManager) context.getSystemService(Context.WIFI_SERVICE));
+    }
+
+    @VisibleForTesting
+    WifiTracker(Context context, WifiListener wifiListener, boolean includeSaved,
+            boolean includeScans, WifiManager wifiManager) {
+        if (!includeSaved && !includeScans) {
+            throw new IllegalArgumentException("Must include either saved or scans");
+        }
+        mContext = context;
+        mWifiManager = wifiManager;
+        mIncludeSaved = includeSaved;
+        mIncludeScans = includeScans;
+        mListener = wifiListener;
+
+        // check if verbose logging has been turned on or off
+        sVerboseLogging = mWifiManager.getVerboseLoggingLevel();
+
+        mFilter = new IntentFilter();
+        mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+    }
+
+    /**
+     * Forces an update of the wifi networks when not scanning.
+     */
+    public void forceUpdate() {
+        updateAccessPoints();
+    }
+
+    /**
+     * Force a scan for wifi networks to happen now.
+     */
+    public void forceScan() {
+        if (mWifiManager.isWifiEnabled() && mScanner != null) {
+            mScanner.forceScan();
+        }
+    }
+
+    /**
+     * Temporarily stop scanning for wifi networks.
+     */
+    public void pauseScanning() {
+        if (mScanner != null) {
+            mScanner.pause();
+            mScanner = null;
+        }
+    }
+
+    /**
+     * Resume scanning for wifi networks after it has been paused.
+     */
+    public void resumeScanning() {
+        if (mScanner == null) {
+            mScanner = new Scanner();
+        }
+        if (mWifiManager.isWifiEnabled()) {
+            mScanner.resume();
+        }
+        updateAccessPoints();
+    }
+
+    /**
+     * Start tracking wifi networks.
+     * Registers listeners and starts scanning for wifi networks. If this is not called
+     * then forceUpdate() must be called to populate getAccessPoints().
+     */
+    public void startTracking() {
+        resumeScanning();
+        if (!mRegistered) {
+            mContext.registerReceiver(mReceiver, mFilter);
+            mRegistered = true;
+        }
+    }
+
+    /**
+     * Stop tracking wifi networks.
+     * Unregisters all listeners and stops scanning for wifi networks. This should always
+     * be called when done with a WifiTracker (if startTracking was called) to ensure
+     * proper cleanup.
+     */
+    public void stopTracking() {
+        if (mRegistered) {
+            mContext.unregisterReceiver(mReceiver);
+            mRegistered = false;
+        }
+        pauseScanning();
+    }
+
+    /**
+     * Gets the current list of access points.
+     */
+    public List<AccessPoint> getAccessPoints() {
+        return mAccessPoints;
+    }
+
+    public WifiManager getManager() {
+        return mWifiManager;
+    }
+
+    public boolean isWifiEnabled() {
+        return mWifiManager.isWifiEnabled();
+    }
+
+    /**
+     * @return true when there are saved networks on the device, regardless
+     * of whether the WifiTracker is tracking saved networks.
+     */
+    public boolean doSavedNetworksExist() {
+        return mSavedNetworksExist;
+    }
+
+    public boolean isConnected() {
+        return mConnected.get();
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("  - wifi tracker ------");
+        for (AccessPoint accessPoint : mAccessPoints) {
+            pw.println("  " + accessPoint);
+        }
+    }
+
+    private void updateAccessPoints() {
+        // Swap the current access points into a cached list.
+        ArrayList<AccessPoint> tmpSwp = mAccessPoints;
+        mAccessPoints = mCachedAccessPoints;
+        mCachedAccessPoints = tmpSwp;
+        // Clear out the configs so we don't think something is saved when it isn't.
+        for (AccessPoint accessPoint : mCachedAccessPoints) {
+            accessPoint.clearConfig();
+        }
+
+        mAccessPoints.clear();
+
+        /** Lookup table to more quickly update AccessPoints by only considering objects with the
+         * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
+        Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
+
+        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        if (configs != null) {
+            mSavedNetworksExist = configs.size() != 0;
+            for (WifiConfiguration config : configs) {
+                if (config.selfAdded && config.numAssociation == 0) {
+                    continue;
+                }
+                AccessPoint accessPoint = getCachedOrCreate(config);
+                if (mLastInfo != null && mLastNetworkInfo != null) {
+                    accessPoint.update(mLastInfo, mLastNetworkInfo);
+                }
+                if (mIncludeSaved) {
+                    mAccessPoints.add(accessPoint);
+                    apMap.put(accessPoint.getSsid(), accessPoint);
+                } else {
+                    // If we aren't using saved networks, drop them into the cache so that
+                    // we have access to their saved info.
+                    mCachedAccessPoints.add(accessPoint);
+                }
+            }
+        }
+
+        final List<ScanResult> results = mWifiManager.getScanResults();
+        if (results != null) {
+            for (ScanResult result : results) {
+                // Ignore hidden and ad-hoc networks.
+                if (result.SSID == null || result.SSID.length() == 0 ||
+                        result.capabilities.contains("[IBSS]")) {
+                    continue;
+                }
+
+                boolean found = false;
+                for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
+                    if (accessPoint.update(result)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found && mIncludeScans) {
+                    AccessPoint accessPoint = getCachedOrCreate(result);
+                    if (mLastInfo != null && mLastNetworkInfo != null) {
+                        accessPoint.update(mLastInfo, mLastNetworkInfo);
+                    }
+                    mAccessPoints.add(accessPoint);
+                    apMap.put(accessPoint.getSsid(), accessPoint);
+                }
+            }
+        }
+
+        // Pre-sort accessPoints to speed preference insertion
+        Collections.sort(mAccessPoints);
+        if (mListener != null) {
+            mListener.onAccessPointsChanged();
+        }
+    }
+
+    private AccessPoint getCachedOrCreate(ScanResult result) {
+        final int N = mCachedAccessPoints.size();
+        for (int i = 0; i < N; i++) {
+            if (mCachedAccessPoints.get(i).matches(result)) {
+                AccessPoint ret = mCachedAccessPoints.remove(i);
+                ret.update(result);
+                return ret;
+            }
+        }
+        return new AccessPoint(mContext, result);
+    }
+
+    private AccessPoint getCachedOrCreate(WifiConfiguration config) {
+        final int N = mCachedAccessPoints.size();
+        for (int i = 0; i < N; i++) {
+            if (mCachedAccessPoints.get(i).matches(config)) {
+                AccessPoint ret = mCachedAccessPoints.remove(i);
+                ret.loadConfig(config);
+                return ret;
+            }
+        }
+        return new AccessPoint(mContext, config);
+    }
+
+    private void updateNetworkInfo(NetworkInfo networkInfo) {
+        /* sticky broadcasts can call this when wifi is disabled */
+        if (!mWifiManager.isWifiEnabled()) {
+            mScanner.pause();
+            return;
+        }
+
+        if (networkInfo != null &&
+                networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
+            mScanner.pause();
+        } else {
+            mScanner.resume();
+        }
+
+        mLastInfo = mWifiManager.getConnectionInfo();
+        if (networkInfo != null) {
+            mLastNetworkInfo = networkInfo;
+        }
+
+        boolean reorder = false;
+        for (int i = mAccessPoints.size() - 1; i >= 0; --i) {
+            if (mAccessPoints.get(i).update(mLastInfo, mLastNetworkInfo)) {
+                reorder = true;
+            }
+        }
+        if (reorder) {
+            Collections.sort(mAccessPoints);
+            if (mListener != null) {
+                mListener.onAccessPointsChanged();
+            }
+        }
+    }
+
+    private void updateWifiState(int state) {
+        if (state == WifiManager.WIFI_STATE_ENABLED) {
+            if (mScanner != null) {
+                // We only need to resume if mScanner isn't null because
+                // that means we want to be scanning.
+                mScanner.resume();
+            }
+        } else {
+            mLastInfo = null;
+            mLastNetworkInfo = null;
+            if (mScanner != null) {
+                mScanner.pause();
+            }
+        }
+        if (mListener != null) {
+            mListener.onWifiStateChanged(state);
+        }
+    }
+
+    public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
+            boolean includeScans) {
+        WifiTracker tracker = new WifiTracker(context, null, includeSaved, includeScans);
+        tracker.forceUpdate();
+        return tracker.getAccessPoints();
+    }
+
+    @VisibleForTesting
+    final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+                updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                        WifiManager.WIFI_STATE_UNKNOWN));
+            } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
+                    WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
+                    WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
+                updateAccessPoints();
+            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+                NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
+                        WifiManager.EXTRA_NETWORK_INFO);
+                mConnected.set(info.isConnected());
+                if (mListener != null) {
+                    mListener.onConnectedChanged();
+                }
+                updateAccessPoints();
+                updateNetworkInfo(info);
+            } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
+                updateNetworkInfo(null);
+            }
+        }
+    };
+
+    @VisibleForTesting
+    class Scanner extends Handler {
+        private static final int MSG_SCAN = 0;
+
+        private int mRetry = 0;
+
+        void resume() {
+            if (!hasMessages(MSG_SCAN)) {
+                sendEmptyMessage(MSG_SCAN);
+            }
+        }
+
+        void forceScan() {
+            removeMessages(MSG_SCAN);
+            sendEmptyMessage(MSG_SCAN);
+        }
+
+        void pause() {
+            mRetry = 0;
+            removeMessages(MSG_SCAN);
+        }
+
+        @VisibleForTesting
+        boolean isScanning() {
+            return hasMessages(MSG_SCAN);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what != MSG_SCAN) return;
+            if (mWifiManager.startScan()) {
+                mRetry = 0;
+            } else if (++mRetry >= 3) {
+                mRetry = 0;
+                if (mContext != null) {
+                    Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
+                }
+                return;
+            }
+            sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
+        }
+    }
+
+    /** A restricted multimap for use in constructAccessPoints */
+    private static class Multimap<K,V> {
+        private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
+        /** retrieve a non-null list of values with key K */
+        List<V> getAll(K key) {
+            List<V> values = store.get(key);
+            return values != null ? values : Collections.<V>emptyList();
+        }
+
+        void put(K key, V val) {
+            List<V> curVals = store.get(key);
+            if (curVals == null) {
+                curVals = new ArrayList<V>(3);
+                store.put(key, curVals);
+            }
+            curVals.add(val);
+        }
+    }
+
+    public interface WifiListener {
+        /**
+         * Called when the state of Wifi has changed, the state will be one of
+         * the following.
+         *
+         * <li>{@link WifiManager#WIFI_STATE_DISABLED}</li>
+         * <li>{@link WifiManager#WIFI_STATE_ENABLED}</li>
+         * <li>{@link WifiManager#WIFI_STATE_DISABLING}</li>
+         * <li>{@link WifiManager#WIFI_STATE_ENABLING}</li>
+         * <li>{@link WifiManager#WIFI_STATE_UNKNOWN}</li>
+         * <p>
+         *
+         * @param state The new state of wifi.
+         */
+        void onWifiStateChanged(int state);
+
+        /**
+         * Called when the connection state of wifi has changed and isConnected
+         * should be called to get the updated state.
+         */
+        void onConnectedChanged();
+
+        /**
+         * Called to indicate the list of AccessPoints has been updated and
+         * getAccessPoints should be called to get the latest information.
+         */
+        void onAccessPointsChanged();
+    }
+}
diff --git a/packages/SettingsLib/tests/Android.mk b/packages/SettingsLib/tests/Android.mk
new file mode 100644
index 0000000..d3ffffa
--- /dev/null
+++ b/packages/SettingsLib/tests/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+
+LOCAL_PACKAGE_NAME := SettingsLibTests
+
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+
+include frameworks/base/packages/SettingsLib/common.mk
+
+include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/tests/AndroidManifest.xml b/packages/SettingsLib/tests/AndroidManifest.xml
new file mode 100644
index 0000000..00d16fc
--- /dev/null
+++ b/packages/SettingsLib/tests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.settingslib">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.settingslib"
+        android:label="Tests for SettingsLib">
+    </instrumentation>
+</manifest>
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java
new file mode 100644
index 0000000..04a568e
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/BaseTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib;
+
+import android.test.AndroidTestCase;
+
+public class BaseTest extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Mockito stuff.
+        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+    }
+
+}
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
new file mode 100644
index 0000000..4ac461d
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.wifi;
+
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+
+import com.android.settingslib.BaseTest;
+import com.android.settingslib.wifi.AccessPoint.AccessPointListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+// TODO: Add some coverage
+public class AccessPointTest extends BaseTest {
+
+    private static final String TEST_SSID = "TestSsid";
+    private static final int NETWORK_ID = 0;
+
+    private AccessPointListener mAccessPointListener;
+    private AccessPoint mAccessPoint;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAccessPointListener = Mockito.mock(AccessPointListener.class);
+
+        WifiConfiguration wifiConfig = new WifiConfiguration();
+        wifiConfig.networkId = NETWORK_ID;
+        wifiConfig.SSID = TEST_SSID;
+
+        mAccessPoint = new AccessPoint(mContext, wifiConfig);
+        mAccessPoint.setListener(mAccessPointListener);
+    }
+
+    public void testOnLevelChanged() {
+        ScanResult result = new ScanResult();
+        result.capabilities = "";
+        result.SSID = TEST_SSID;
+
+        // Give it a level.
+        result.level = WifiTrackerTest.levelToRssi(1);
+        mAccessPoint.update(result);
+        verifyOnLevelChangedCallback(1);
+
+        // Give it a better level.
+        result.level = WifiTrackerTest.levelToRssi(2);
+        mAccessPoint.update(result);
+        verifyOnLevelChangedCallback(1);
+    }
+
+    public void testOnAccessPointChangedCallback() {
+        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
+        Mockito.when(wifiInfo.getNetworkId()).thenReturn(NETWORK_ID);
+
+        mAccessPoint.update(wifiInfo, null);
+        verifyOnAccessPointsCallback(1);
+
+        mAccessPoint.update(null, null);
+        verifyOnAccessPointsCallback(2);
+
+        ScanResult result = new ScanResult();
+        result.capabilities = "";
+        result.SSID = TEST_SSID;
+        mAccessPoint.update(result);
+        verifyOnAccessPointsCallback(3);
+    }
+
+    private void verifyOnLevelChangedCallback(int num) {
+        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
+        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
+                .onLevelChanged(accessPoint.capture());
+        assertEquals(mAccessPoint, accessPoint.getValue());
+    }
+
+    private void verifyOnAccessPointsCallback(int num) {
+        ArgumentCaptor<AccessPoint> accessPoint = ArgumentCaptor.forClass(AccessPoint.class);
+        Mockito.verify(mAccessPointListener, Mockito.atLeast(num))
+                .onAccessPointChanged(accessPoint.capture());
+        assertEquals(mAccessPoint, accessPoint.getValue());
+    }
+
+}
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
new file mode 100644
index 0000000..8eb1ca4
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.wifi;
+
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.State;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.util.Log;
+
+import com.android.settingslib.BaseTest;
+import com.android.settingslib.wifi.WifiTracker.WifiListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class WifiTrackerTest extends BaseTest {
+
+    private static final String TAG = "WifiTrackerTest";
+
+    private static final String[] TEST_SSIDS = new String[] {
+        "TEST_SSID_1",
+        "TEST_SSID_2",
+        "TEST_SSID_3",
+        "TEST_SSID_4",
+        "TEST_SSID_5",
+    };
+    private static final int NUM_NETWORKS = 5;
+
+    private WifiManager mWifiManager;
+    private WifiListener mWifiListener;
+
+    private WifiTracker mWifiTracker;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mWifiManager = Mockito.mock(WifiManager.class);
+        mWifiListener = Mockito.mock(WifiListener.class);
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, true, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(true);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        mWifiTracker.dump(pw);
+        pw.flush();
+        Log.d(TAG, sw.toString());
+        super.tearDown();
+    }
+
+    public void testAccessPointsCallback() {
+        sendScanResultsAvailable();
+
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onAccessPointsChanged();
+    }
+
+    public void testConnectedCallback() {
+        sendConnected();
+
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce()).onConnectedChanged();
+        assertEquals(true, mWifiTracker.isConnected());
+    }
+
+    public void testWifiStateCallback() {
+        final int TEST_WIFI_STATE = WifiManager.WIFI_STATE_ENABLED;
+
+        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, TEST_WIFI_STATE);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+
+        ArgumentCaptor<Integer> wifiState = ArgumentCaptor.forClass(Integer.class);
+        Mockito.verify(mWifiListener, Mockito.atLeastOnce())
+                .onWifiStateChanged(wifiState.capture());
+        assertEquals(TEST_WIFI_STATE, (int) wifiState.getValue());
+    }
+
+    public void testScanner() {
+        // TODO: Figure out how to verify more of the Scanner functionality.
+        // Make scans be successful.
+        Mockito.when(mWifiManager.startScan()).thenReturn(true);
+
+        mWifiTracker.mScanner.handleMessage(null);
+        Mockito.verify(mWifiManager, Mockito.atLeastOnce()).startScan();
+    }
+
+    public void testNetworkSorting() {
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS, accessPoints.size());
+        for (int i = 0; i < NUM_NETWORKS; i++) {
+            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
+        }
+    }
+
+    public void testSavedOnly() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, true, false, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        // Only expect the first two to come back in the results.
+        assertEquals("Expected number of results", 2, accessPoints.size());
+        assertEquals(TEST_SSIDS[1], accessPoints.get(0).getSsid());
+        assertEquals(TEST_SSIDS[0], accessPoints.get(1).getSsid());
+    }
+
+    public void testAvailableOnly() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, false, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, true);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+
+        // Expect the last one (sorted order) to be left off since its only saved.
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
+        for (int i = 0; i < NUM_NETWORKS - 1; i++) {
+            assertEquals("Verifying slot " + i, expectedSsids[i], accessPoints.get(i).getSsid());
+        }
+    }
+
+    public void testNonEphemeralConnected() {
+        mWifiTracker = new WifiTracker(mContext, mWifiListener, false, true, mWifiManager);
+        mWifiTracker.mScanner = mWifiTracker.new Scanner();
+
+        List<WifiConfiguration> wifiConfigs = new ArrayList<WifiConfiguration>();
+        List<ScanResult> scanResults = new ArrayList<ScanResult>();
+        String[] expectedSsids = generateTestNetworks(wifiConfigs, scanResults, false);
+
+        // Tell WifiTracker we are connected now.
+        sendConnected();
+
+        // Send all of the configs and scan results to the tracker.
+        Mockito.when(mWifiManager.getConfiguredNetworks()).thenReturn(wifiConfigs);
+        Mockito.when(mWifiManager.getScanResults()).thenReturn(scanResults);
+        sendScanResultsAvailable();
+        // Do this twice to catch a bug that was happening in the caching, making things ephemeral.
+        sendScanResultsAvailable();
+
+        List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
+        assertEquals("Expected number of results", NUM_NETWORKS - 1, accessPoints.size());
+        assertFalse("Connection is not ephemeral", accessPoints.get(0).isEphemeral());
+        assertTrue("Connected to wifi", accessPoints.get(0).isActive());
+    }
+
+    public void testEnableResumeScanning() {
+        mWifiTracker.mScanner = null;
+
+        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        // Make sure disable/enable cycle works with no scanner (no crashing).
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+
+        Mockito.when(mWifiManager.isWifiEnabled()).thenReturn(false);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        // Now enable scanning while wifi is off, it shouldn't start.
+        mWifiTracker.resumeScanning();
+        assertFalse(mWifiTracker.mScanner.isScanning());
+
+        // Turn on wifi and make sure scanning starts.
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+        assertTrue(mWifiTracker.mScanner.isScanning());
+    }
+
+    private String[] generateTestNetworks(List<WifiConfiguration> wifiConfigs,
+            List<ScanResult> scanResults, boolean connectedIsEphemeral) {
+        String[] expectedSsids = new String[NUM_NETWORKS];
+
+        // First is just saved;
+        addConfig(wifiConfigs, TEST_SSIDS[0]);
+        // This should come last since its not available.
+        expectedSsids[4] = TEST_SSIDS[0];
+
+        // Second is saved and available.
+        addConfig(wifiConfigs, TEST_SSIDS[1]);
+        addResult(scanResults, TEST_SSIDS[1], 0);
+        // This one is going to have a couple extra results, to verify de-duplication.
+        addResult(scanResults, TEST_SSIDS[1], 2);
+        addResult(scanResults, TEST_SSIDS[1], 1);
+        // This should come second since it is available and saved but not connected.
+        expectedSsids[1] = TEST_SSIDS[1];
+
+        // Third is just available, but higher rssi.
+        addResult(scanResults, TEST_SSIDS[2], 3);
+        // This comes after the next one since it has a lower rssi.
+        expectedSsids[3] = TEST_SSIDS[2];
+
+        // Fourth also just available but with even higher rssi.
+        addResult(scanResults, TEST_SSIDS[3], 4);
+        // This is the highest rssi but not saved so it should be after the saved+availables.
+        expectedSsids[2] = TEST_SSIDS[3];
+
+        // Last is going to be connected.
+        int netId = WifiConfiguration.INVALID_NETWORK_ID;
+        if (!connectedIsEphemeral) {
+            netId = addConfig(wifiConfigs, TEST_SSIDS[4]);
+        }
+        addResult(scanResults, TEST_SSIDS[4], 2);
+        // Setup wifi connection to be this one.
+        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
+        Mockito.when(wifiInfo.getSSID()).thenReturn(TEST_SSIDS[4]);
+        Mockito.when(wifiInfo.getNetworkId()).thenReturn(netId);
+        Mockito.when(mWifiManager.getConnectionInfo()).thenReturn(wifiInfo);
+        // This should come first since it is connected.
+        expectedSsids[0] = TEST_SSIDS[4];
+
+        return expectedSsids;
+    }
+
+    private void addResult(List<ScanResult> results, String ssid, int level) {
+        results.add(new ScanResult(WifiSsid.createFromAsciiEncoded(ssid),
+                ssid, ssid, levelToRssi(level), AccessPoint.LOWER_FREQ_24GHZ, 0));
+    }
+
+    public static int levelToRssi(int level) {
+        // Reverse level to rssi calculation based off from WifiManager.calculateSignalLevel.
+        final int MAX_RSSI = -55;
+        final int MIN_RSSI = -100;
+        final int NUM_LEVELS = 4;
+        return level * (MAX_RSSI - MIN_RSSI) / (NUM_LEVELS - 1) + MIN_RSSI;
+    }
+
+    private int addConfig(List<WifiConfiguration> configs, String ssid) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = configs.size();
+        config.SSID = '"' + ssid + '"';
+        configs.add(config);
+        return config.networkId;
+    }
+
+    private void sendConnected() {
+        NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
+        Mockito.when(networkInfo.isConnected()).thenReturn(true);
+        Mockito.when(networkInfo.getState()).thenReturn(State.CONNECTED);
+        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+        mWifiTracker.mReceiver.onReceive(mContext, intent);
+    }
+
+    private void sendScanResultsAvailable() {
+        Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        mWifiTracker.mReceiver.onReceive(mContext, i);
+    }
+
+}
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index c16f7b6..2b833b2 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -3,7 +3,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+    src/com/android/providers/settings/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := telephony-common ims-common
 
diff --git a/packages/SettingsProvider/res/values-tl/strings.xml b/packages/SettingsProvider/res/values-tl/strings.xml
index 19219ec..0fe535e 100644
--- a/packages/SettingsProvider/res/values-tl/strings.xml
+++ b/packages/SettingsProvider/res/values-tl/strings.xml
@@ -19,5 +19,5 @@
 
 <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="4567566098528588863">"Imbakan ng Mga Setting"</string>
+    <string name="app_label" msgid="4567566098528588863">"Storage ng Mga Setting"</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 175b424..729efcb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -28,8 +28,8 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
+import android.media.AudioSystem;
 import android.media.AudioManager;
-import android.media.AudioService;
 import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Environment;
@@ -58,6 +58,7 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Database helper class for {@link SettingsProvider}.
@@ -78,6 +79,9 @@
 
     private static final HashSet<String> mValidTables = new HashSet<String>();
 
+    private static final String DATABASE_JOURNAL_SUFFIX = "-journal";
+    private static final String DATABASE_BACKUP_SUFFIX = "-backup";
+
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
@@ -86,13 +90,13 @@
         mValidTables.add(TABLE_SYSTEM);
         mValidTables.add(TABLE_SECURE);
         mValidTables.add(TABLE_GLOBAL);
-        mValidTables.add("bluetooth_devices");
-        mValidTables.add("bookmarks");
 
         // These are old.
+        mValidTables.add("bluetooth_devices");
+        mValidTables.add("bookmarks");
         mValidTables.add("favorites");
-        mValidTables.add("gservices");
         mValidTables.add("old_favorites");
+        mValidTables.add("android_metadata");
     }
 
     static String dbNameForUser(final int userHandle) {
@@ -118,6 +122,33 @@
         return mValidTables.contains(name);
     }
 
+    public void dropDatabase() {
+        close();
+        File databaseFile = mContext.getDatabasePath(getDatabaseName());
+        if (databaseFile.exists()) {
+            databaseFile.delete();
+        }
+        File databaseJournalFile = mContext.getDatabasePath(getDatabaseName()
+                + DATABASE_JOURNAL_SUFFIX);
+        if (databaseJournalFile.exists()) {
+            databaseJournalFile.delete();
+        }
+    }
+
+    public void backupDatabase() {
+        close();
+        File databaseFile = mContext.getDatabasePath(getDatabaseName());
+        if (!databaseFile.exists()) {
+            return;
+        }
+        File backupFile = mContext.getDatabasePath(getDatabaseName()
+                + DATABASE_BACKUP_SUFFIX);
+        if (backupFile.exists()) {
+            return;
+        }
+        databaseFile.renameTo(backupFile);
+    }
+
     private void createSecureTable(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE secure (" +
                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
@@ -568,7 +599,7 @@
                 stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                         + " VALUES(?,?);");
                 loadSetting(stmt, Settings.System.VOLUME_BLUETOOTH_SCO,
-                        AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+                        AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
                 db.setTransactionSuccessful();
             } finally {
                 db.endTransaction();
@@ -1221,9 +1252,11 @@
                     // Migrate now-global settings. Note that this happens before
                     // new users can be created.
                     createGlobalTable(db);
-                    String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+                    String[] settingsToMove = setToStringArray(
+                            SettingsProvider.sSystemMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, false);
-                    settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+                    settingsToMove = setToStringArray(
+                            SettingsProvider.sSecureMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, false);
 
                     db.setTransactionSuccessful();
@@ -1489,9 +1522,11 @@
                 db.beginTransaction();
                 try {
                     // Migrate now-global settings
-                    String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+                    String[] settingsToMove = setToStringArray(
+                            SettingsProvider.sSystemMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
-                    settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+                    settingsToMove = setToStringArray(
+                            SettingsProvider.sSecureMovedToGlobalSettings);
                     moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
 
                     db.setTransactionSuccessful();
@@ -1855,7 +1890,8 @@
                 try {
                     stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
                             + " VALUES(?,?);");
-                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                            ImsConfig.FeatureValueConstants.ON);
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
@@ -1895,34 +1931,50 @@
             }
             upgradeVersion = 118;
         }
+
+        /**
+         * IMPORTANT: Do not add any more upgrade steps here as the global,
+         * secure, and system settings are no longer stored in a database
+         * but are kept in memory and persisted to XML. The correct places
+         * for adding upgrade steps are:
+         *
+         * Global: SettingsProvider.UpgradeController#onUpgradeGlobalSettings
+         * Secure: SettingsProvider.UpgradeController#onUpgradeSecureSettings
+         * System: SettingsProvider.UpgradeController#onUpgradeSystemSettings
+         */
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
-            Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
-                    + ", must wipe the settings provider");
-            db.execSQL("DROP TABLE IF EXISTS global");
-            db.execSQL("DROP TABLE IF EXISTS globalIndex1");
-            db.execSQL("DROP TABLE IF EXISTS system");
-            db.execSQL("DROP INDEX IF EXISTS systemIndex1");
-            db.execSQL("DROP TABLE IF EXISTS secure");
-            db.execSQL("DROP INDEX IF EXISTS secureIndex1");
-            db.execSQL("DROP TABLE IF EXISTS gservices");
-            db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
-            db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
-            db.execSQL("DROP TABLE IF EXISTS bookmarks");
-            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
-            db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
-            db.execSQL("DROP TABLE IF EXISTS favorites");
-            onCreate(db);
-
-            // Added for diagnosing settings.db wipes after the fact
-            String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
-            db.execSQL("INSERT INTO secure(name,value) values('" +
-                    "wiped_db_reason" + "','" + wipeReason + "');");
+            recreateDatabase(db, oldVersion, upgradeVersion, currentVersion);
         }
     }
 
-    private String[] hashsetToStringArray(HashSet<String> set) {
+    public void recreateDatabase(SQLiteDatabase db, int oldVersion,
+            int upgradeVersion, int currentVersion) {
+        db.execSQL("DROP TABLE IF EXISTS global");
+        db.execSQL("DROP TABLE IF EXISTS globalIndex1");
+        db.execSQL("DROP TABLE IF EXISTS system");
+        db.execSQL("DROP INDEX IF EXISTS systemIndex1");
+        db.execSQL("DROP TABLE IF EXISTS secure");
+        db.execSQL("DROP INDEX IF EXISTS secureIndex1");
+        db.execSQL("DROP TABLE IF EXISTS gservices");
+        db.execSQL("DROP INDEX IF EXISTS gservicesIndex1");
+        db.execSQL("DROP TABLE IF EXISTS bluetooth_devices");
+        db.execSQL("DROP TABLE IF EXISTS bookmarks");
+        db.execSQL("DROP INDEX IF EXISTS bookmarksIndex1");
+        db.execSQL("DROP INDEX IF EXISTS bookmarksIndex2");
+        db.execSQL("DROP TABLE IF EXISTS favorites");
+
+        onCreate(db);
+
+        // Added for diagnosing settings.db wipes after the fact
+        String wipeReason = oldVersion + "/" + upgradeVersion + "/" + currentVersion;
+        db.execSQL("INSERT INTO secure(name,value) values('" +
+                "wiped_db_reason" + "','" + wipeReason + "');");
+    }
+
+    private String[] setToStringArray(Set<String> set) {
         String[] array = new String[set.size()];
         return set.toArray(array);
     }
@@ -2051,11 +2103,11 @@
         int vibrateSetting = getIntValueFromSystem(db, Settings.System.VIBRATE_ON, 0);
         // If the ringer vibrate value is invalid, set it to the default
         if ((vibrateSetting & 3) == AudioManager.VIBRATE_SETTING_OFF) {
-            vibrateSetting = AudioService.getValueForVibrateSetting(0,
+            vibrateSetting = AudioSystem.getValueForVibrateSetting(0,
                     AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
         }
         // Apply the same setting to the notification vibrate value
-        vibrateSetting = AudioService.getValueForVibrateSetting(vibrateSetting,
+        vibrateSetting = AudioSystem.getValueForVibrateSetting(vibrateSetting,
                 AudioManager.VIBRATE_TYPE_NOTIFICATION, vibrateSetting);
 
         SQLiteStatement stmt = null;
@@ -2199,25 +2251,25 @@
                     + " VALUES(?,?);");
 
             loadSetting(stmt, Settings.System.VOLUME_MUSIC,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_MUSIC));
             loadSetting(stmt, Settings.System.VOLUME_RING,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_RING));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_RING));
             loadSetting(stmt, Settings.System.VOLUME_SYSTEM,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_VOICE,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL));
             loadSetting(stmt, Settings.System.VOLUME_ALARM,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_ALARM));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_NOTIFICATION,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION));
             loadSetting(
                     stmt,
                     Settings.System.VOLUME_BLUETOOTH_SCO,
-                    AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
+                    AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
 
             // By default:
             // - ringtones, notification, system and music streams are affected by ringer mode
@@ -2236,10 +2288,7 @@
                     ringerModeAffectedStreams);
 
             loadSetting(stmt, Settings.System.MUTE_STREAMS_AFFECTED,
-                    ((1 << AudioManager.STREAM_MUSIC) |
-                     (1 << AudioManager.STREAM_RING) |
-                     (1 << AudioManager.STREAM_NOTIFICATION) |
-                     (1 << AudioManager.STREAM_SYSTEM)));
+                    AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED);
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2259,10 +2308,10 @@
 
             // Vibrate on by default for ringer, on for notification
             int vibrate = 0;
-            vibrate = AudioService.getValueForVibrateSetting(vibrate,
+            vibrate = AudioSystem.getValueForVibrateSetting(vibrate,
                     AudioManager.VIBRATE_TYPE_NOTIFICATION,
                     AudioManager.VIBRATE_SETTING_ONLY_SILENT);
-            vibrate |= AudioService.getValueForVibrateSetting(vibrate,
+            vibrate |= AudioSystem.getValueForVibrateSetting(vibrate,
                     AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
             loadSetting(stmt, Settings.System.VIBRATE_ON, vibrate);
         } finally {
@@ -2642,7 +2691,8 @@
 
             loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
                     R.bool.def_guest_user_enabled);
-            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON);
+            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                    ImsConfig.FeatureValueConstants.ON);
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
new file mode 100644
index 0000000..298d776
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags
@@ -0,0 +1,5 @@
+# See system/core/logcat/e for a description of the format of this file.
+
+option java_package com.android.providers.settings;
+
+52100 unsupported_settings_query (uri|3),(selection|3),(whereArgs|3)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b4d8c63..eac83d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -32,14 +32,18 @@
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.internal.widget.LockPatternUtils;
+
 import libcore.io.IoUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.CharArrayReader;
 import java.io.DataInputStream;
@@ -76,10 +80,11 @@
     private static final String KEY_SECURE = "secure";
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
+    private static final String KEY_LOCK_SETTINGS = "lock_settings";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 3;
+    private static final int STATE_VERSION = 4;
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
@@ -89,20 +94,23 @@
     private static final int STATE_WIFI_SUPPLICANT = 3;
     private static final int STATE_WIFI_CONFIG     = 4;
     private static final int STATE_GLOBAL          = 5;
+    private static final int STATE_LOCK_SETTINGS   = 6;
 
-    private static final int STATE_SIZE            = 6; // The current number of state items
+    private static final int STATE_SIZE            = 7; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
         0,
         4,              // version 1
         5,              // version 2 added STATE_WIFI_CONFIG
-        STATE_SIZE      // version 3 added STATE_GLOBAL
+        6,              // version 3 added STATE_GLOBAL
+        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
     };
 
     // Versioning of the 'full backup' format
-    private static final int FULL_BACKUP_VERSION = 2;
+    private static final int FULL_BACKUP_VERSION = 3;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
+    private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -110,11 +118,7 @@
 
     private static final String TAG = "SettingsBackupAgent";
 
-    private static final int COLUMN_NAME = 1;
-    private static final int COLUMN_VALUE = 2;
-
     private static final String[] PROJECTION = {
-        Settings.NameValueTable._ID,
         Settings.NameValueTable.NAME,
         Settings.NameValueTable.VALUE
     };
@@ -128,6 +132,10 @@
     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
     private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
 
+    // Keys within the lock settings section
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
+
     // Name of the temporary file we use during full backup/restore.  This is
     // stored in the full-backup tarfile as well, so should not be changed.
     private static final String STAGE_FILE = "flattened-data";
@@ -371,6 +379,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -391,6 +400,9 @@
         stateChecksums[STATE_WIFI_CONFIG] =
             writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
                     data);
+        stateChecksums[STATE_LOCK_SETTINGS] =
+            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                    lockSettingsData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -473,8 +485,8 @@
             ParcelFileDescriptor newState) throws IOException {
 
         HashSet<String> movedToGlobal = new HashSet<String>();
-        Settings.System.getMovedKeys(movedToGlobal);
-        Settings.Secure.getMovedKeys(movedToGlobal);
+        Settings.System.getMovedToGlobalSettings(movedToGlobal);
+        Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
 
         while (data.readNextHeader()) {
             final String key = data.getKey();
@@ -496,6 +508,8 @@
             } else if (KEY_WIFI_CONFIG.equals(key)) {
                 initWifiRestoreIfNecessary();
                 mWifiRestore.incorporateWifiConfigFile(data);
+            } else if (KEY_LOCK_SETTINGS.equals(key)) {
+                restoreLockSettings(data);
              } else {
                 data.skipEntityData();
             }
@@ -517,6 +531,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -551,6 +566,9 @@
             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
             out.writeInt(wifiConfigData.length);
             out.write(wifiConfigData);
+            if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
+            out.writeInt(lockSettingsData.length);
+            out.write(lockSettingsData);
 
             out.flush();    // also flushes downstream
 
@@ -577,8 +595,8 @@
         if (version <= FULL_BACKUP_VERSION) {
             // Generate the moved-to-global lookup table
             HashSet<String> movedToGlobal = new HashSet<String>();
-            Settings.System.getMovedKeys(movedToGlobal);
-            Settings.Secure.getMovedKeys(movedToGlobal);
+            Settings.System.getMovedToGlobalSettings(movedToGlobal);
+            Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
 
             // system settings data first
             int nBytes = in.readInt();
@@ -633,6 +651,16 @@
             in.readFully(buffer, 0, nBytes);
             restoreFileData(mWifiConfigFile, buffer, nBytes);
 
+            if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreLockSettings(buffer, nBytes);
+                }
+            }
+
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -662,7 +690,7 @@
     private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
             throws IOException {
         DataOutputStream dataOutput = new DataOutputStream(
-                new FileOutputStream(newState.getFileDescriptor()));
+                new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
 
         dataOutput.writeInt(STATE_VERSION);
         for (int i = 0; i < STATE_SIZE; i++) {
@@ -680,6 +708,9 @@
             return oldChecksum;
         }
         try {
+            if (DEBUG_BACKUP) {
+                Log.v(TAG, "Writing entity " + key + " of size " + data.length);
+            }
             output.writeEntityHeader(key, data.length);
             output.writeEntityData(data, data.length);
         } catch (IOException ioe) {
@@ -718,6 +749,31 @@
         }
     }
 
+    /**
+     * Serialize the owner info settings
+     */
+    private byte[] getLockSettings() {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+        final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled();
+        final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        try {
+            out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
+            out.writeUTF(ownerInfoEnabled ? "1" : "0");
+            if (ownerInfo != null) {
+                out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
+                out.writeUTF(ownerInfo != null ? ownerInfo : "");
+            }
+            // End marker
+            out.writeUTF("");
+            out.flush();
+        } catch (IOException ioe) {
+        }
+        return baos.toByteArray();
+    }
+
     private void restoreSettings(BackupDataInput data, Uri contentUri,
             HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
@@ -801,6 +857,50 @@
     }
 
     /**
+     * Restores the owner info enabled and owner info settings in LockSettings.
+     *
+     * @param buffer
+     * @param nBytes
+     */
+    private void restoreLockSettings(byte[] buffer, int nBytes) {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
+        DataInputStream in = new DataInputStream(bais);
+        try {
+            String key;
+            // Read until empty string marker
+            while ((key = in.readUTF()).length() > 0) {
+                final String value = in.readUTF();
+                if (DEBUG_BACKUP) {
+                    Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
+                }
+                switch (key) {
+                    case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
+                        lockPatternUtils.setOwnerInfoEnabled("1".equals(value));
+                        break;
+                    case KEY_LOCK_SETTINGS_OWNER_INFO:
+                        lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
+                        break;
+                }
+            }
+            in.close();
+        } catch (IOException ioe) {
+        }
+    }
+
+    private void restoreLockSettings(BackupDataInput data) {
+        final byte[] settings = new byte[data.getDataSize()];
+        try {
+            data.readEntityData(settings, 0, settings.length);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Couldn't read entity data");
+            return;
+        }
+        restoreLockSettings(settings, settings.length);
+    }
+
+    /**
      * Given a cursor and a set of keys, extract the required keys and
      * values and write them to a byte array.
      *
@@ -824,11 +924,14 @@
             String key = settings[i];
             String value = cachedEntries.remove(key);
 
+            final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+            final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
             // If the value not cached, let us look it up.
             if (value == null) {
                 while (!cursor.isAfterLast()) {
-                    String cursorKey = cursor.getString(COLUMN_NAME);
-                    String cursorValue = cursor.getString(COLUMN_VALUE);
+                    String cursorKey = cursor.getString(nameColumnIndex);
+                    String cursorValue = cursor.getString(valueColumnIndex);
                     cursor.moveToNext();
                     if (key.equals(cursorKey)) {
                         value = cursorValue;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6828301..2c63647 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,1211 +16,463 @@
 
 package com.android.providers.settings;
 
-import java.io.FileNotFoundException;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
-import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.database.AbstractCursor;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteQueryBuilder;
+import android.hardware.camera2.utils.ArrayUtils;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.DropBoxManager;
-import android.os.FileObserver;
+import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.text.TextUtils;
-import android.util.Log;
-import android.util.LruCache;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
 
+import com.android.providers.settings.SettingsState.Setting;
+
+/**
+ * <p>
+ * This class is a content provider that publishes the system settings.
+ * It can be accessed via the content provider APIs or via custom call
+ * commands. The latter is a bit faster and is the preferred way to access
+ * the platform settings.
+ * </p>
+ * <p>
+ * There are three settings types, global (with signature level protection
+ * and shared across users), secure (with signature permission level
+ * protection and per user), and system (with dangerous permission level
+ * protection and per user). Global settings are stored under the device owner.
+ * Each of these settings is represented by a {@link
+ * com.android.providers.settings.SettingsState} object mapped to an integer
+ * key derived from the setting type in the most significant bits and user
+ * id in the least significant bits. Settings are synchronously loaded on
+ * instantiation of a SettingsState and asynchronously persisted on mutation.
+ * Settings are stored in the user specific system directory.
+ * </p>
+ * <p>
+ * Apps targeting APIs Lollipop MR1 and lower can add custom settings entries
+ * and get a warning. Targeting higher API version prohibits this as the
+ * system settings are not a place for apps to save their state. When a package
+ * is removed the settings it added are deleted. Apps cannot delete system
+ * settings added by the platform. System settings values are validated to
+ * ensure the clients do not put bad values. Global and secure settings are
+ * changed only by trusted parties, therefore no validation is performed. Also
+ * there is a limit on the amount of app specific settings that can be added
+ * to prevent unlimited growth of the system process memory footprint.
+ * </p>
+ */
+@SuppressWarnings("deprecation")
 public class SettingsProvider extends ContentProvider {
-    private static final String TAG = "SettingsProvider";
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean DEBUG = false;
 
-    private static final boolean USER_CHECK_THROWS = true;
+    private static final boolean DROP_DATABASE_ON_MIGRATION = !Build.IS_DEBUGGABLE;
+
+    private static final String LOG_TAG = "SettingsProvider";
 
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
+
+    // Old tables no longer exist.
     private static final String TABLE_FAVORITES = "favorites";
     private static final String TABLE_OLD_FAVORITES = "old_favorites";
+    private static final String TABLE_BLUETOOTH_DEVICES = "bluetooth_devices";
+    private static final String TABLE_BOOKMARKS = "bookmarks";
+    private static final String TABLE_ANDROID_METADATA = "android_metadata";
 
-    private static final String[] COLUMN_VALUE = new String[] { "value" };
-
-    // Caches for each user's settings, access-ordered for acting as LRU.
-    // Guarded by themselves.
-    private static final int MAX_CACHE_ENTRIES = 200;
-    private static final SparseArray<SettingsCache> sSystemCaches
-            = new SparseArray<SettingsCache>();
-    private static final SparseArray<SettingsCache> sSecureCaches
-            = new SparseArray<SettingsCache>();
-    private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL);
-
-    // The count of how many known (handled by SettingsProvider)
-    // database mutations are currently being handled for this user.
-    // Used by file observers to not reload the database when it's ourselves
-    // modifying it.
-    private static final SparseArray<AtomicInteger> sKnownMutationsInFlight
-            = new SparseArray<AtomicInteger>();
-
-    // Each defined user has their own settings
-    protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
-
-    // Keep the list of managed profiles synced here
-    private List<UserInfo> mManagedProfiles = null;
-
-    // Over this size we don't reject loading or saving settings but
-    // we do consider them broken/malicious and don't keep them in
-    // memory at least:
-    private static final int MAX_CACHE_ENTRY_SIZE = 500;
-
-    private static final Bundle NULL_SETTING = Bundle.forPair("value", null);
-
-    // Used as a sentinel value in an instance equality test when we
-    // want to cache the existence of a key, but not store its value.
-    private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
-
-    private UserManager mUserManager;
-    private BackupManager mBackupManager;
-
-    /**
-     * Settings which need to be treated as global/shared in multi-user environments.
-     */
-    static final HashSet<String> sSecureGlobalKeys;
-    static final HashSet<String> sSystemGlobalKeys;
-
-    // Settings that cannot be modified if associated user restrictions are enabled.
-    static final Map<String, String> sRestrictedKeys;
-
-    private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
-
-    static final HashSet<String> sSecureCloneToManagedKeys;
-    static final HashSet<String> sSystemCloneToManagedKeys;
-
+    // The set of removed legacy tables.
+    private static final Set<String> REMOVED_LEGACY_TABLES = new ArraySet<>();
     static {
-        // Keys (name column) from the 'secure' table that are now in the owner user's 'global'
-        // table, shared across all users
-        // These must match Settings.Secure.MOVED_TO_GLOBAL
-        sSecureGlobalKeys = new HashSet<String>();
-        Settings.Secure.getMovedKeys(sSecureGlobalKeys);
+        REMOVED_LEGACY_TABLES.add(TABLE_FAVORITES);
+        REMOVED_LEGACY_TABLES.add(TABLE_OLD_FAVORITES);
+        REMOVED_LEGACY_TABLES.add(TABLE_BLUETOOTH_DEVICES);
+        REMOVED_LEGACY_TABLES.add(TABLE_BOOKMARKS);
+        REMOVED_LEGACY_TABLES.add(TABLE_ANDROID_METADATA);
+    }
 
-        // Keys from the 'system' table now moved to 'global'
-        // These must match Settings.System.MOVED_TO_GLOBAL
-        sSystemGlobalKeys = new HashSet<String>();
-        Settings.System.getNonLegacyMovedKeys(sSystemGlobalKeys);
+    private static final int MUTATION_OPERATION_INSERT = 1;
+    private static final int MUTATION_OPERATION_DELETE = 2;
+    private static final int MUTATION_OPERATION_UPDATE = 3;
 
-        sRestrictedKeys = new HashMap<String, String>();
-        sRestrictedKeys.put(Settings.Secure.LOCATION_MODE, UserManager.DISALLOW_SHARE_LOCATION);
-        sRestrictedKeys.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+    private static final String[] ALL_COLUMNS = new String[] {
+            Settings.NameValueTable._ID,
+            Settings.NameValueTable.NAME,
+            Settings.NameValueTable.VALUE
+    };
+
+    private static final Bundle NULL_SETTING = Bundle.forPair(Settings.NameValueTable.VALUE, null);
+
+    // Per user settings that cannot be modified if associated user restrictions are enabled.
+    private static final Map<String, String> sSettingToUserRestrictionMap = new ArrayMap<>();
+    static {
+        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_MODE,
                 UserManager.DISALLOW_SHARE_LOCATION);
-        sRestrictedKeys.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
+        sSettingToUserRestrictionMap.put(Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                UserManager.DISALLOW_SHARE_LOCATION);
+        sSettingToUserRestrictionMap.put(Settings.Secure.INSTALL_NON_MARKET_APPS,
                 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-        sRestrictedKeys.put(Settings.Global.ADB_ENABLED, UserManager.DISALLOW_DEBUGGING_FEATURES);
-        sRestrictedKeys.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
+        sSettingToUserRestrictionMap.put(Settings.Global.ADB_ENABLED,
+                UserManager.DISALLOW_DEBUGGING_FEATURES);
+        sSettingToUserRestrictionMap.put(Settings.Global.PACKAGE_VERIFIER_ENABLE,
                 UserManager.ENSURE_VERIFY_APPS);
-        sRestrictedKeys.put(Settings.Global.PREFERRED_NETWORK_MODE,
+        sSettingToUserRestrictionMap.put(Settings.Global.PREFERRED_NETWORK_MODE,
                 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-
-        sSecureCloneToManagedKeys = new HashSet<String>();
-        for (int i = 0; i < Settings.Secure.CLONE_TO_MANAGED_PROFILE.length; i++) {
-            sSecureCloneToManagedKeys.add(Settings.Secure.CLONE_TO_MANAGED_PROFILE[i]);
-        }
-        sSystemCloneToManagedKeys = new HashSet<String>();
-        for (int i = 0; i < Settings.System.CLONE_TO_MANAGED_PROFILE.length; i++) {
-            sSystemCloneToManagedKeys.add(Settings.System.CLONE_TO_MANAGED_PROFILE[i]);
-        }
     }
 
-    private boolean settingMovedToGlobal(final String name) {
-        return sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name);
+    // Per user secure settings that moved to the for all users global settings.
+    static final Set<String> sSecureMovedToGlobalSettings = new ArraySet<>();
+    static {
+        Settings.Secure.getMovedToGlobalSettings(sSecureMovedToGlobalSettings);
     }
 
-    /**
-     * Decode a content URL into the table, projection, and arguments
-     * used to access the corresponding database rows.
-     */
-    private static class SqlArguments {
-        public String table;
-        public final String where;
-        public final String[] args;
-
-        /** Operate on existing rows. */
-        SqlArguments(Uri url, String where, String[] args) {
-            if (url.getPathSegments().size() == 1) {
-                // of the form content://settings/secure, arbitrary where clause
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                this.where = where;
-                this.args = args;
-            } else if (url.getPathSegments().size() != 2) {
-                throw new IllegalArgumentException("Invalid URI: " + url);
-            } else if (!TextUtils.isEmpty(where)) {
-                throw new UnsupportedOperationException("WHERE clause not supported: " + url);
-            } else {
-                // of the form content://settings/secure/element_name, no where clause
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table) ||
-                    TABLE_GLOBAL.equals(this.table)) {
-                    this.where = Settings.NameValueTable.NAME + "=?";
-                    final String name = url.getPathSegments().get(1);
-                    this.args = new String[] { name };
-                    // Rewrite the table for known-migrated names
-                    if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table)) {
-                        if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
-                            this.table = TABLE_GLOBAL;
-                        }
-                    }
-                } else {
-                    // of the form content://bookmarks/19
-                    this.where = "_id=" + ContentUris.parseId(url);
-                    this.args = null;
-                }
-            }
-        }
-
-        /** Insert new rows (no where clause allowed). */
-        SqlArguments(Uri url) {
-            if (url.getPathSegments().size() == 1) {
-                this.table = url.getPathSegments().get(0);
-                if (!DatabaseHelper.isValidTable(this.table)) {
-                    throw new IllegalArgumentException("Bad root path: " + this.table);
-                }
-                this.where = null;
-                this.args = null;
-            } else {
-                throw new IllegalArgumentException("Invalid URI: " + url);
-            }
-        }
+    // Per user system settings that moved to the for all users global settings.
+    static final Set<String> sSystemMovedToGlobalSettings = new ArraySet<>();
+    static {
+        Settings.System.getMovedToGlobalSettings(sSystemMovedToGlobalSettings);
     }
 
-    /**
-     * Get the content URI of a row added to a table.
-     * @param tableUri of the entire table
-     * @param values found in the row
-     * @param rowId of the row
-     * @return the content URI for this particular row
-     */
-    private Uri getUriFor(Uri tableUri, ContentValues values, long rowId) {
-        if (tableUri.getPathSegments().size() != 1) {
-            throw new IllegalArgumentException("Invalid URI: " + tableUri);
-        }
-        String table = tableUri.getPathSegments().get(0);
-        if (TABLE_SYSTEM.equals(table) ||
-                TABLE_SECURE.equals(table) ||
-                TABLE_GLOBAL.equals(table)) {
-            String name = values.getAsString(Settings.NameValueTable.NAME);
-            return Uri.withAppendedPath(tableUri, name);
-        } else {
-            return ContentUris.withAppendedId(tableUri, rowId);
-        }
+    // Per user system settings that moved to the per user secure settings.
+    static final Set<String> sSystemMovedToSecureSettings = new ArraySet<>();
+    static {
+        Settings.System.getMovedToSecureSettings(sSystemMovedToSecureSettings);
     }
 
-    /**
-     * Send a notification when a particular content URI changes.
-     * Modify the system property used to communicate the version of
-     * this table, for tables which have such a property.  (The Settings
-     * contract class uses these to provide client-side caches.)
-     * @param uri to send notifications for
-     */
-    private void sendNotify(Uri uri, int userHandle) {
-        // Update the system property *first*, so if someone is listening for
-        // a notification and then using the contract class to get their data,
-        // the system property will be updated and they'll get the new data.
-
-        boolean backedUpDataChanged = false;
-        String property = null, table = uri.getPathSegments().get(0);
-        final boolean isGlobal = table.equals(TABLE_GLOBAL);
-        if (table.equals(TABLE_SYSTEM)) {
-            property = Settings.System.SYS_PROP_SETTING_VERSION;
-            backedUpDataChanged = true;
-        } else if (table.equals(TABLE_SECURE)) {
-            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
-            backedUpDataChanged = true;
-        } else if (isGlobal) {
-            property = Settings.Global.SYS_PROP_SETTING_VERSION;    // this one is global
-            backedUpDataChanged = true;
-        }
-
-        if (property != null) {
-            long version = SystemProperties.getLong(property, 0) + 1;
-            if (LOCAL_LOGV) Log.v(TAG, "property: " + property + "=" + version);
-            SystemProperties.set(property, Long.toString(version));
-        }
-
-        // Inform the backup manager about a data change
-        if (backedUpDataChanged) {
-            mBackupManager.dataChanged();
-        }
-        // Now send the notification through the content framework.
-
-        String notify = uri.getQueryParameter("notify");
-        if (notify == null || "true".equals(notify)) {
-            final int notifyTarget = isGlobal ? UserHandle.USER_ALL : userHandle;
-            final long oldId = Binder.clearCallingIdentity();
-            try {
-                getContext().getContentResolver().notifyChange(uri, null, true, notifyTarget);
-            } finally {
-                Binder.restoreCallingIdentity(oldId);
-            }
-            if (LOCAL_LOGV) Log.v(TAG, "notifying for " + notifyTarget + ": " + uri);
-        } else {
-            if (LOCAL_LOGV) Log.v(TAG, "notification suppressed: " + uri);
-        }
+    // Per all users global settings that moved to the per user secure settings.
+    static final Set<String> sGlobalMovedToSecureSettings = new ArraySet<>();
+    static {
+        Settings.Global.getMovedToSecureSettings(sGlobalMovedToSecureSettings);
     }
 
-    /**
-     * Make sure the caller has permission to write this data.
-     * @param args supplied by the caller
-     * @throws SecurityException if the caller is forbidden to write.
-     */
-    private void checkWritePermissions(SqlArguments args) {
-        if ((TABLE_SECURE.equals(args.table) || TABLE_GLOBAL.equals(args.table)) &&
-            getContext().checkCallingOrSelfPermission(
-                    android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
-            PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    String.format("Permission denial: writing to secure settings requires %1$s",
-                                  android.Manifest.permission.WRITE_SECURE_SETTINGS));
-        }
+    // Per user secure settings that are cloned for the managed profiles of the user.
+    private static final Set<String> sSecureCloneToManagedSettings = new ArraySet<>();
+    static {
+        Settings.Secure.getCloneToManagedProfileSettings(sSecureCloneToManagedSettings);
     }
 
-    private void checkUserRestrictions(String setting, int userId) {
-        String userRestriction = sRestrictedKeys.get(setting);
-        if (!TextUtils.isEmpty(userRestriction)
-            && mUserManager.hasUserRestriction(userRestriction, new UserHandle(userId))) {
-            throw new SecurityException(
-                    "Permission denial: user is restricted from changing this setting.");
-        }
+    // Per user system settings that are cloned for the managed profiles of the user.
+    private static final Set<String> sSystemCloneToManagedSettings = new ArraySet<>();
+    static {
+        Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
     }
 
-    // FileObserver for external modifications to the database file.
-    // Note that this is for platform developers only with
-    // userdebug/eng builds who should be able to tinker with the
-    // sqlite database out from under the SettingsProvider, which is
-    // normally the exclusive owner of the database.  But we keep this
-    // enabled all the time to minimize development-vs-user
-    // differences in testing.
-    private static SparseArray<SettingsFileObserver> sObserverInstances
-            = new SparseArray<SettingsFileObserver>();
-    private class SettingsFileObserver extends FileObserver {
-        private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
-        private final int mUserHandle;
-        private final String mPath;
+    private final Object mLock = new Object();
 
-        public SettingsFileObserver(int userHandle, String path) {
-            super(path, FileObserver.CLOSE_WRITE |
-                  FileObserver.CREATE | FileObserver.DELETE |
-                  FileObserver.MOVED_TO | FileObserver.MODIFY);
-            mUserHandle = userHandle;
-            mPath = path;
-        }
+    @GuardedBy("mLock")
+    private SettingsRegistry mSettingsRegistry;
 
-        public void onEvent(int event, String path) {
-            final AtomicInteger mutationCount;
-            synchronized (SettingsProvider.this) {
-                mutationCount = sKnownMutationsInFlight.get(mUserHandle);
-            }
-            if (mutationCount != null && mutationCount.get() > 0) {
-                // our own modification.
-                return;
-            }
-            Log.d(TAG, "User " + mUserHandle + " external modification to " + mPath
-                    + "; event=" + event);
-            if (!mIsDirty.compareAndSet(false, true)) {
-                // already handled. (we get a few update events
-                // during an sqlite write)
-                return;
-            }
-            Log.d(TAG, "User " + mUserHandle + " updating our caches for " + mPath);
-            fullyPopulateCaches(mUserHandle);
-            mIsDirty.set(false);
-        }
-    }
+    @GuardedBy("mLock")
+    private UserManager mUserManager;
+
+    @GuardedBy("mLock")
+    private AppOpsManager mAppOpsManager;
+
+    @GuardedBy("mLock")
+    private PackageManager mPackageManager;
 
     @Override
     public boolean onCreate() {
-        mBackupManager = new BackupManager(getContext());
-        mUserManager = UserManager.get(getContext());
-
-        setAppOps(AppOpsManager.OP_NONE, AppOpsManager.OP_WRITE_SETTINGS);
-        establishDbTracking(UserHandle.USER_OWNER);
-
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_ADDED);
-        getContext().registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_OWNER);
-                if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
-                    onUserRemoved(userHandle);
-                } else if (intent.getAction().equals(Intent.ACTION_USER_ADDED)) {
-                    onProfilesChanged();
-                }
-            }
-        }, userFilter);
-
-        onProfilesChanged();
-
+        synchronized (mLock) {
+            mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+            mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+            mPackageManager = getContext().getPackageManager();
+            mSettingsRegistry = new SettingsRegistry();
+        }
+        registerBroadcastReceivers();
         return true;
     }
 
-    void onUserRemoved(int userHandle) {
-        synchronized (this) {
-            // the db file itself will be deleted automatically, but we need to tear down
-            // our caches and other internal bookkeeping.
-            FileObserver observer = sObserverInstances.get(userHandle);
-            if (observer != null) {
-                observer.stopWatching();
-                sObserverInstances.delete(userHandle);
-            }
-
-            mOpenHelpers.delete(userHandle);
-            sSystemCaches.delete(userHandle);
-            sSecureCaches.delete(userHandle);
-            sKnownMutationsInFlight.delete(userHandle);
-            onProfilesChanged();
-        }
-    }
-
-    /**
-     * Updates the list of managed profiles. It assumes that only the primary user
-     * can have managed profiles. Modify this code if that changes in the future.
-     */
-    void onProfilesChanged() {
-        synchronized (this) {
-            mManagedProfiles = mUserManager.getProfiles(UserHandle.USER_OWNER);
-            if (mManagedProfiles != null) {
-                // Remove the primary user from the list
-                for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                    if (mManagedProfiles.get(i).id == UserHandle.USER_OWNER) {
-                        mManagedProfiles.remove(i);
-                    }
-                }
-                // If there are no managed profiles, reset the variable
-                if (mManagedProfiles.size() == 0) {
-                    mManagedProfiles = null;
-                }
-            }
-            if (LOCAL_LOGV) {
-                Slog.d(TAG, "Managed Profiles = " + mManagedProfiles);
-            }
-        }
-    }
-
-    private void establishDbTracking(int userHandle) {
-        if (LOCAL_LOGV) {
-            Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle);
-        }
-
-        DatabaseHelper dbhelper;
-
-        synchronized (this) {
-            dbhelper = mOpenHelpers.get(userHandle);
-            if (dbhelper == null) {
-                dbhelper = new DatabaseHelper(getContext(), userHandle);
-                mOpenHelpers.append(userHandle, dbhelper);
-
-                sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM));
-                sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE));
-                sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0));
-            }
-        }
-
-        // Initialization of the db *outside* the locks.  It's possible that racing
-        // threads might wind up here, the second having read the cache entries
-        // written by the first, but that's benign: the SQLite helper implementation
-        // manages concurrency itself, and it's important that we not run the db
-        // initialization with any of our own locks held, so we're fine.
-        SQLiteDatabase db = dbhelper.getWritableDatabase();
-
-        // Watch for external modifications to the database files,
-        // keeping our caches in sync.  We synchronize the observer set
-        // separately, and of course it has to run after the db file
-        // itself was set up by the DatabaseHelper.
-        synchronized (sObserverInstances) {
-            if (sObserverInstances.get(userHandle) == null) {
-                SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath());
-                sObserverInstances.append(userHandle, observer);
-                observer.startWatching();
-            }
-        }
-
-        ensureAndroidIdIsSet(userHandle);
-
-        startAsyncCachePopulation(userHandle);
-    }
-
-    class CachePrefetchThread extends Thread {
-        private int mUserHandle;
-
-        CachePrefetchThread(int userHandle) {
-            super("populate-settings-caches");
-            mUserHandle = userHandle;
-        }
-
-        @Override
-        public void run() {
-            fullyPopulateCaches(mUserHandle);
-        }
-    }
-
-    private void startAsyncCachePopulation(int userHandle) {
-        new CachePrefetchThread(userHandle).start();
-    }
-
-    private void fullyPopulateCaches(final int userHandle) {
-        DatabaseHelper dbHelper;
-        synchronized (this) {
-            dbHelper = mOpenHelpers.get(userHandle);
-        }
-        if (dbHelper == null) {
-            // User is gone.
-            return;
-        }
-        // Only populate the globals cache once, for the owning user
-        if (userHandle == UserHandle.USER_OWNER) {
-            fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache);
-        }
-        fullyPopulateCache(dbHelper, TABLE_SECURE, sSecureCaches.get(userHandle));
-        fullyPopulateCache(dbHelper, TABLE_SYSTEM, sSystemCaches.get(userHandle));
-    }
-
-    // Slurp all values (if sane in number & size) into cache.
-    private void fullyPopulateCache(DatabaseHelper dbHelper, String table, SettingsCache cache) {
-        SQLiteDatabase db = dbHelper.getReadableDatabase();
-        Cursor c = db.query(
-            table,
-            new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
-            null, null, null, null, null,
-            "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
-        try {
-            synchronized (cache) {
-                cache.evictAll();
-                cache.setFullyMatchesDisk(true);  // optimistic
-                int rows = 0;
-                while (c.moveToNext()) {
-                    rows++;
-                    String name = c.getString(0);
-                    String value = c.getString(1);
-                    cache.populate(name, value);
-                }
-                if (rows > MAX_CACHE_ENTRIES) {
-                    // Somewhat redundant, as removeEldestEntry() will
-                    // have already done this, but to be explicit:
-                    cache.setFullyMatchesDisk(false);
-                    Log.d(TAG, "row count exceeds max cache entries for table " + table);
-                }
-                if (LOCAL_LOGV) Log.d(TAG, "cache for settings table '" + table
-                        + "' rows=" + rows + "; fullycached=" + cache.fullyMatchesDisk());
-            }
-        } finally {
-            c.close();
-        }
-    }
-
-    private boolean ensureAndroidIdIsSet(int userHandle) {
-        final Cursor c = queryForUser(Settings.Secure.CONTENT_URI,
-                new String[] { Settings.NameValueTable.VALUE },
-                Settings.NameValueTable.NAME + "=?",
-                new String[] { Settings.Secure.ANDROID_ID }, null,
-                userHandle);
-        try {
-            final String value = c.moveToNext() ? c.getString(0) : null;
-            if (value == null) {
-                // sanity-check the user before touching the db
-                final UserInfo user = mUserManager.getUserInfo(userHandle);
-                if (user == null) {
-                    // can happen due to races when deleting users; treat as benign
-                    return false;
+    @Override
+    public Bundle call(String method, String name, Bundle args) {
+        synchronized (mLock) {
+            final int requestingUserId = getRequestingUserId(args);
+            switch (method) {
+                case Settings.CALL_METHOD_GET_GLOBAL: {
+                    Setting setting = getGlobalSettingLocked(name);
+                    return packageValueForCallResult(setting);
                 }
 
-                final SecureRandom random = new SecureRandom();
-                final String newAndroidIdValue = Long.toHexString(random.nextLong());
-                final ContentValues values = new ContentValues();
-                values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
-                values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
-                final Uri uri = insertForUser(Settings.Secure.CONTENT_URI, values, userHandle);
-                if (uri == null) {
-                    Slog.e(TAG, "Unable to generate new ANDROID_ID for user " + userHandle);
-                    return false;
+                case Settings.CALL_METHOD_GET_SECURE: {
+                    Setting setting = getSecureSettingLocked(name, requestingUserId);
+                    return packageValueForCallResult(setting);
                 }
-                Slog.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue
-                        + "] for user " + userHandle);
-                // Write a dropbox entry if it's a restricted profile
-                if (user.isRestricted()) {
-                    DropBoxManager dbm = (DropBoxManager)
-                            getContext().getSystemService(Context.DROPBOX_SERVICE);
-                    if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
-                        dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
-                                + ",restricted_profile_ssaid,"
-                                + newAndroidIdValue + "\n");
-                    }
+
+                case Settings.CALL_METHOD_GET_SYSTEM: {
+                    Setting setting = getSystemSettingLocked(name, requestingUserId);
+                    return packageValueForCallResult(setting);
                 }
-            }
-            return true;
-        } finally {
-            c.close();
-        }
-    }
 
-    // Lazy-initialize the settings caches for non-primary users
-    private SettingsCache getOrConstructCache(int callingUser, SparseArray<SettingsCache> which) {
-        getOrEstablishDatabase(callingUser); // ignore return value; we don't need it
-        return which.get(callingUser);
-    }
+                case Settings.CALL_METHOD_PUT_GLOBAL: {
+                    String value = getSettingValue(args);
+                    insertGlobalSettingLocked(name, value, requestingUserId);
+                } break;
 
-    // Lazy initialize the database helper and caches for this user, if necessary
-    private DatabaseHelper getOrEstablishDatabase(int callingUser) {
-        if (callingUser >= Process.SYSTEM_UID) {
-            if (USER_CHECK_THROWS) {
-                throw new IllegalArgumentException("Uid rather than user handle: " + callingUser);
-            } else {
-                Slog.wtf(TAG, "establish db for uid rather than user: " + callingUser);
-            }
-        }
+                case Settings.CALL_METHOD_PUT_SECURE: {
+                    String value = getSettingValue(args);
+                    insertSecureSettingLocked(name, value, requestingUserId);
+                } break;
 
-        long oldId = Binder.clearCallingIdentity();
-        try {
-            DatabaseHelper dbHelper;
-            synchronized (this) {
-                dbHelper = mOpenHelpers.get(callingUser);
-            }
-            if (null == dbHelper) {
-                establishDbTracking(callingUser);
-                synchronized (this) {
-                    dbHelper = mOpenHelpers.get(callingUser);
-                }
-            }
-            return dbHelper;
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
-        }
-    }
+                case Settings.CALL_METHOD_PUT_SYSTEM: {
+                    String value = getSettingValue(args);
+                    insertSystemSettingLocked(name, value, requestingUserId);
+                } break;
 
-    public SettingsCache cacheForTable(final int callingUser, String tableName) {
-        if (TABLE_SYSTEM.equals(tableName)) {
-            return getOrConstructCache(callingUser, sSystemCaches);
-        }
-        if (TABLE_SECURE.equals(tableName)) {
-            return getOrConstructCache(callingUser, sSecureCaches);
-        }
-        if (TABLE_GLOBAL.equals(tableName)) {
-            return sGlobalCache;
+                default: {
+                    Slog.w(LOG_TAG, "call() with invalid method: " + method);
+                } break;
+            }
         }
         return null;
     }
 
-    /**
-     * Used for wiping a whole cache on deletes when we're not
-     * sure what exactly was deleted or changed.
-     */
-    public void invalidateCache(final int callingUser, String tableName) {
-        SettingsCache cache = cacheForTable(callingUser, tableName);
-        if (cache == null) {
-            return;
-        }
-        synchronized (cache) {
-            cache.evictAll();
-            cache.mCacheFullyMatchesDisk = false;
-        }
-    }
-
-    /**
-     * Checks if the calling user is a managed profile of the primary user.
-     * Currently only the primary user (USER_OWNER) can have managed profiles.
-     * @param callingUser the user trying to read/write settings
-     * @return true if it is a managed profile of the primary user
-     */
-    private boolean isManagedProfile(int callingUser) {
-        synchronized (this) {
-            if (mManagedProfiles == null) return false;
-            for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                if (mManagedProfiles.get(i).id == callingUser) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Fast path that avoids the use of chatty remoted Cursors.
-     */
     @Override
-    public Bundle call(String method, String request, Bundle args) {
-        int callingUser = UserHandle.getCallingUserId();
-        if (args != null) {
-            int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
-            if (reqUser != callingUser) {
-                callingUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                        Binder.getCallingUid(), reqUser, false, true,
-                        "get/set setting for user", null);
-                if (LOCAL_LOGV) Slog.v(TAG, "   access setting for user " + callingUser);
-            }
-        }
-
-        // Note: we assume that get/put operations for moved-to-global names have already
-        // been directed to the new location on the caller side (otherwise we'd fix them
-        // up here).
-        DatabaseHelper dbHelper;
-        SettingsCache cache;
-
-        // Get methods
-        if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
-            // Check if this request should be (re)directed to the primary user's db
-            if (callingUser != UserHandle.USER_OWNER
-                    && shouldShadowParentProfile(callingUser, sSystemCloneToManagedKeys, request)) {
-                callingUser = UserHandle.USER_OWNER;
-            }
-            dbHelper = getOrEstablishDatabase(callingUser);
-            cache = sSystemCaches.get(callingUser);
-            return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
-        }
-        if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
-            // Check if this is a setting to be copied from the primary user
-            if (shouldShadowParentProfile(callingUser, sSecureCloneToManagedKeys, request)) {
-                // If the request if for location providers and there's a restriction, return none
-                if (Secure.LOCATION_PROVIDERS_ALLOWED.equals(request)
-                        && mUserManager.hasUserRestriction(
-                                UserManager.DISALLOW_SHARE_LOCATION, new UserHandle(callingUser))) {
-                    return sSecureCaches.get(callingUser).putIfAbsent(request, "");
-                }
-                callingUser = UserHandle.USER_OWNER;
-            }
-            dbHelper = getOrEstablishDatabase(callingUser);
-            cache = sSecureCaches.get(callingUser);
-            return lookupValue(dbHelper, TABLE_SECURE, cache, request);
-        }
-        if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
-            if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
-            // fast path: owner db & cache are immutable after onCreate() so we need not
-            // guard on the attempt to look them up
-            return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
-                    sGlobalCache, request);
-        }
-
-        // Put methods - new value is in the args bundle under the key named by
-        // the Settings.NameValueTable.VALUE static.
-        final String newValue = (args == null)
-                ? null : args.getString(Settings.NameValueTable.VALUE);
-
-        // Framework can't do automatic permission checking for calls, so we need
-        // to do it here.
-        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    String.format("Permission denial: writing to settings requires %1$s",
-                                  android.Manifest.permission.WRITE_SETTINGS));
-        }
-
-        // Also need to take care of app op.
-        if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SETTINGS, Binder.getCallingUid(),
-                getCallingPackage()) != AppOpsManager.MODE_ALLOWED) {
-            return null;
-        }
-
-        final ContentValues values = new ContentValues();
-        values.put(Settings.NameValueTable.NAME, request);
-        values.put(Settings.NameValueTable.VALUE, newValue);
-        if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
-                    sSystemCloneToManagedKeys, request)) {
-                // Don't write these settings, as they are cloned from the parent profile
-                return null;
-            }
-            insertForUser(Settings.System.CONTENT_URI, values, callingUser);
-            // Clone the settings to the managed profiles so that notifications can be sent out
-            if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
-                    && sSystemCloneToManagedKeys.contains(request)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                        if (LOCAL_LOGV) {
-                            Slog.v(TAG, "putting to additional user "
-                                    + mManagedProfiles.get(i).id);
-                        }
-                        insertForUser(Settings.System.CONTENT_URI, values,
-                                mManagedProfiles.get(i).id);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            // Extra check for USER_OWNER to optimize for the 99%
-            if (callingUser != UserHandle.USER_OWNER && shouldShadowParentProfile(callingUser,
-                    sSecureCloneToManagedKeys, request)) {
-                // Don't write these settings, as they are cloned from the parent profile
-                return null;
-            }
-            insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
-            // Clone the settings to the managed profiles so that notifications can be sent out
-            if (callingUser == UserHandle.USER_OWNER && mManagedProfiles != null
-                    && sSecureCloneToManagedKeys.contains(request)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    for (int i = mManagedProfiles.size() - 1; i >= 0; i--) {
-                        if (LOCAL_LOGV) {
-                            Slog.v(TAG, "putting to additional user "
-                                    + mManagedProfiles.get(i).id);
-                        }
-                        try {
-                            insertForUser(Settings.Secure.CONTENT_URI, values,
-                                    mManagedProfiles.get(i).id);
-                        } catch (SecurityException e) {
-                            // Temporary fix, see b/17450158
-                            Slog.w(TAG, "Cannot clone request '" + request + "' with value '"
-                                    + newValue + "' to managed profile (id "
-                                    + mManagedProfiles.get(i).id + ")", e);
-                        }
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
-            if (LOCAL_LOGV) {
-                Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for "
-                        + callingUser);
-            }
-            insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
-        } else {
-            Slog.w(TAG, "call() with invalid method: " + method);
-        }
-
-        return null;
-    }
-
-    /**
-     * Check if the user is a managed profile and name is one of the settings to be cloned
-     * from the parent profile.
-     */
-    private boolean shouldShadowParentProfile(int userId, HashSet<String> keys, String name) {
-        return isManagedProfile(userId) && keys.contains(name);
-    }
-
-    // Looks up value 'key' in 'table' and returns either a single-pair Bundle,
-    // possibly with a null value, or null on failure.
-    private Bundle lookupValue(DatabaseHelper dbHelper, String table,
-            final SettingsCache cache, String key) {
-        if (cache == null) {
-           Slog.e(TAG, "cache is null for user " + UserHandle.getCallingUserId() + " : key=" + key);
-           return null;
-        }
-        synchronized (cache) {
-            Bundle value = cache.get(key);
-            if (value != null) {
-                if (value != TOO_LARGE_TO_CACHE_MARKER) {
-                    return value;
-                }
-                // else we fall through and read the value from disk
-            } else if (cache.fullyMatchesDisk()) {
-                // Fast path (very common).  Don't even try touch disk
-                // if we know we've slurped it all in.  Trying to
-                // touch the disk would mean waiting for yaffs2 to
-                // give us access, which could takes hundreds of
-                // milliseconds.  And we're very likely being called
-                // from somebody's UI thread...
-                return NULL_SETTING;
-            }
-        }
-
-        SQLiteDatabase db = dbHelper.getReadableDatabase();
-        Cursor cursor = null;
-        try {
-            cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key},
-                              null, null, null, null);
-            if (cursor != null && cursor.getCount() == 1) {
-                cursor.moveToFirst();
-                return cache.putIfAbsent(key, cursor.getString(0));
-            }
-        } catch (SQLiteException e) {
-            Log.w(TAG, "settings lookup error", e);
-            return null;
-        } finally {
-            if (cursor != null) cursor.close();
-        }
-        cache.putIfAbsent(key, null);
-        return NULL_SETTING;
-    }
-
-    @Override
-    public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
-        return queryForUser(url, select, where, whereArgs, sort, UserHandle.getCallingUserId());
-    }
-
-    private Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
-            String sort, int forUser) {
-        if (LOCAL_LOGV) Slog.v(TAG, "query(" + url + ") for user " + forUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        DatabaseHelper dbH;
-        dbH = getOrEstablishDatabase(
-                TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : forUser);
-        SQLiteDatabase db = dbH.getReadableDatabase();
-
-        // The favorites table was moved from this provider to a provider inside Home
-        // Home still need to query this table to upgrade from pre-cupcake builds
-        // However, a cupcake+ build with no data does not contain this table which will
-        // cause an exception in the SQL stack. The following line is a special case to
-        // let the caller of the query have a chance to recover and avoid the exception
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return null;
-        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
-            args.table = TABLE_FAVORITES;
-            Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
-            if (cursor != null) {
-                boolean exists = cursor.getCount() > 0;
-                cursor.close();
-                if (!exists) return null;
-            } else {
-                return null;
-            }
-        }
-
-        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-        qb.setTables(args.table);
-
-        Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
-        // the default Cursor interface does not support per-user observation
-        try {
-            AbstractCursor c = (AbstractCursor) ret;
-            c.setNotificationUri(getContext().getContentResolver(), url, forUser);
-        } catch (ClassCastException e) {
-            // details of the concrete Cursor implementation have changed and this code has
-            // not been updated to match -- complain and fail hard.
-            Log.wtf(TAG, "Incompatible cursor derivation!");
-            throw e;
-        }
-        return ret;
-    }
-
-    @Override
-    public String getType(Uri url) {
-        // If SqlArguments supplies a where clause, then it must be an item
-        // (because we aren't supplying our own where clause).
-        SqlArguments args = new SqlArguments(url, null, null);
-        if (TextUtils.isEmpty(args.where)) {
+    public String getType(Uri uri) {
+        Arguments args = new Arguments(uri, null, null, true);
+        if (TextUtils.isEmpty(args.name)) {
             return "vnd.android.cursor.dir/" + args.table;
         } else {
-            return "vnd.android.cursor.item/" + args.table;
+                return "vnd.android.cursor.item/" + args.table;
         }
     }
 
     @Override
-    public int bulkInsert(Uri uri, ContentValues[] values) {
-        final int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "bulkInsert() for user " + callingUser);
-        SqlArguments args = new SqlArguments(uri);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        }
-        checkWritePermissions(args);
-        SettingsCache cache = cacheForTable(callingUser, args.table);
-
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
-        }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(
-                TABLE_GLOBAL.equals(args.table) ? UserHandle.USER_OWNER : callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        db.beginTransaction();
-        try {
-            int numValues = values.length;
-            for (int i = 0; i < numValues; i++) {
-                checkUserRestrictions(values[i].getAsString(Settings.Secure.NAME), callingUser);
-                if (db.insert(args.table, null, values[i]) < 0) return 0;
-                SettingsCache.populate(cache, values[i]);
-                if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + values[i]);
-            }
-            db.setTransactionSuccessful();
-        } finally {
-            db.endTransaction();
-            if (mutationCount != null) {
-                mutationCount.decrementAndGet();
-            }
+    public Cursor query(Uri uri, String[] projection, String where, String[] whereArgs,
+            String order) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "query() for user: " + UserHandle.getCallingUserId());
         }
 
-        sendNotify(uri, callingUser);
-        return values.length;
-    }
+        Arguments args = new Arguments(uri, where, whereArgs, true);
+        String[] normalizedProjection = normalizeProjection(projection);
 
-    /*
-     * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
-     * This setting contains a list of the currently enabled location providers.
-     * But helper functions in android.providers.Settings can enable or disable
-     * a single provider by using a "+" or "-" prefix before the provider name.
-     *
-     * @returns whether the database needs to be updated or not, also modifying
-     *     'initialValues' if needed.
-     */
-    private boolean parseProviderList(Uri url, ContentValues initialValues, int desiredUser) {
-        String value = initialValues.getAsString(Settings.Secure.VALUE);
-        String newProviders = null;
-        if (value != null && value.length() > 1) {
-            char prefix = value.charAt(0);
-            if (prefix == '+' || prefix == '-') {
-                // skip prefix
-                value = value.substring(1);
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return new MatrixCursor(normalizedProjection, 0);
+        }
 
-                // read list of enabled providers into "providers"
-                String providers = "";
-                String[] columns = {Settings.Secure.VALUE};
-                String where = Settings.Secure.NAME + "=\'" + Settings.Secure.LOCATION_PROVIDERS_ALLOWED + "\'";
-                Cursor cursor = queryForUser(url, columns, where, null, null, desiredUser);
-                if (cursor != null && cursor.getCount() == 1) {
-                    try {
-                        cursor.moveToFirst();
-                        providers = cursor.getString(0);
-                    } finally {
-                        cursor.close();
-                    }
-                }
-
-                int index = providers.indexOf(value);
-                int end = index + value.length();
-                // check for commas to avoid matching on partial string
-                if (index > 0 && providers.charAt(index - 1) != ',') index = -1;
-                if (end < providers.length() && providers.charAt(end) != ',') index = -1;
-
-                if (prefix == '+' && index < 0) {
-                    // append the provider to the list if not present
-                    if (providers.length() == 0) {
-                        newProviders = value;
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    if (args.name != null) {
+                        Setting setting = getGlobalSettingLocked(args.name);
+                        return packageSettingForQuery(setting, normalizedProjection);
                     } else {
-                        newProviders = providers + ',' + value;
+                        return getAllGlobalSettingsLocked(projection);
                     }
-                } else if (prefix == '-' && index >= 0) {
-                    // remove the provider from the list if present
-                    // remove leading or trailing comma
-                    if (index > 0) {
-                        index--;
-                    } else if (end < providers.length()) {
-                        end++;
-                    }
-
-                    newProviders = providers.substring(0, index);
-                    if (end < providers.length()) {
-                        newProviders += providers.substring(end);
-                    }
-                } else {
-                    // nothing changed, so no need to update the database
-                    return false;
                 }
 
-                if (newProviders != null) {
-                    initialValues.put(Settings.Secure.VALUE, newProviders);
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    if (args.name != null) {
+                        Setting setting = getSecureSettingLocked(args.name, userId);
+                        return packageSettingForQuery(setting, normalizedProjection);
+                    } else {
+                        return getAllSecureSettingsLocked(userId, projection);
+                    }
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    if (args.name != null) {
+                        Setting setting = getSystemSettingLocked(args.name, userId);
+                        return packageSettingForQuery(setting, normalizedProjection);
+                    } else {
+                        return getAllSystemSettingsLocked(userId, projection);
+                    }
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
                 }
             }
         }
-
-        return true;
     }
 
     @Override
-    public Uri insert(Uri url, ContentValues initialValues) {
-        return insertForUser(url, initialValues, UserHandle.getCallingUserId());
-    }
-
-    // Settings.put*ForUser() always winds up here, so this is where we apply
-    // policy around permission to write settings for other users.
-    private Uri insertForUser(Uri url, ContentValues initialValues, int desiredUserHandle) {
-        final int callingUser = UserHandle.getCallingUserId();
-        if (callingUser != desiredUserHandle) {
-            getContext().enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "Not permitted to access settings for other users");
+    public Uri insert(Uri uri, ContentValues values) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insert() for user: " + UserHandle.getCallingUserId());
         }
 
-        if (LOCAL_LOGV) Slog.v(TAG, "insert(" + url + ") for user " + desiredUserHandle
-                + " by " + callingUser);
+        String table = getValidTableOrThrow(uri);
 
-        SqlArguments args = new SqlArguments(url);
-        if (TABLE_FAVORITES.equals(args.table)) {
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(table)) {
             return null;
         }
 
-        // Special case LOCATION_PROVIDERS_ALLOWED.
-        // Support enabling/disabling a single provider (using "+" or "-" prefix)
-        String name = initialValues.getAsString(Settings.Secure.NAME);
-        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
-            if (!parseProviderList(url, initialValues, desiredUserHandle)) return null;
+        String name = values.getAsString(Settings.Secure.NAME);
+        if (TextUtils.isEmpty(name)) {
+            return null;
         }
 
-        // If this is an insert() of a key that has been migrated to the global store,
-        // redirect the operation to that store
-        if (name != null) {
-            if (sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name)) {
-                if (!TABLE_GLOBAL.equals(args.table)) {
-                    if (LOCAL_LOGV) Slog.i(TAG, "Rewrite of insert() of now-global key " + name);
+        String value = values.getAsString(Settings.Secure.VALUE);
+
+        synchronized (mLock) {
+            switch (table) {
+                case TABLE_GLOBAL: {
+                    if (insertGlobalSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
+                    }
+                } break;
+
+                case TABLE_SECURE: {
+                    if (insertSecureSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+                    }
+                } break;
+
+                case TABLE_SYSTEM: {
+                    if (insertSystemSettingLocked(name, value, UserHandle.getCallingUserId())) {
+                        return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
+                    }
+                } break;
+
+                default: {
+                    throw new IllegalArgumentException("Bad Uri path:" + uri);
                 }
-                args.table = TABLE_GLOBAL;  // next condition will rewrite the user handle
             }
         }
 
-        // Check write permissions only after determining which table the insert will touch
-        checkWritePermissions(args);
-
-        checkUserRestrictions(name, desiredUserHandle);
-
-        // The global table is stored under the owner, always
-        if (TABLE_GLOBAL.equals(args.table)) {
-            desiredUserHandle = UserHandle.USER_OWNER;
-        }
-
-        SettingsCache cache = cacheForTable(desiredUserHandle, args.table);
-        String value = initialValues.getAsString(Settings.NameValueTable.VALUE);
-        if (SettingsCache.isRedundantSetValue(cache, name, value)) {
-            return Uri.withAppendedPath(url, name);
-        }
-
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
-        }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(desiredUserHandle);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        final long rowId = db.insert(args.table, null, initialValues);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
-        }
-        if (rowId <= 0) return null;
-
-        SettingsCache.populate(cache, initialValues);  // before we notify
-
-        if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues
-                + " for user " + desiredUserHandle);
-        // Note that we use the original url here, not the potentially-rewritten table name
-        url = getUriFor(url, initialValues, rowId);
-        sendNotify(url, desiredUserHandle);
-        return url;
+        return null;
     }
 
     @Override
-    public int delete(Uri url, String where, String[] whereArgs) {
-        int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "delete() for user " + callingUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
-            args.table = TABLE_FAVORITES;
-        } else if (TABLE_GLOBAL.equals(args.table)) {
-            callingUser = UserHandle.USER_OWNER;
+    public int bulkInsert(Uri uri, ContentValues[] allValues) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "bulkInsert() for user: " + UserHandle.getCallingUserId());
         }
-        checkWritePermissions(args);
 
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
+        int insertionCount = 0;
+        final int valuesCount = allValues.length;
+        for (int i = 0; i < valuesCount; i++) {
+            ContentValues values = allValues[i];
+            if (insert(uri, values) != null) {
+                insertionCount++;
+            }
         }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
-        }
-        DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        int count = db.delete(args.table, args.where, args.args);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
-        }
-        if (count > 0) {
-            invalidateCache(callingUser, args.table);  // before we notify
-            sendNotify(url, callingUser);
-        }
-        startAsyncCachePopulation(callingUser);
-        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
-        return count;
+
+        return insertionCount;
     }
 
     @Override
-    public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
-        // NOTE: update() is never called by the front-end Settings API, and updates that
-        // wind up affecting rows in Secure that are globally shared will not have the
-        // intended effect (the update will be invisible to the rest of the system).
-        // This should have no practical effect, since writes to the Secure db can only
-        // be done by system code, and that code should be using the correct API up front.
-        int callingUser = UserHandle.getCallingUserId();
-        if (LOCAL_LOGV) Slog.v(TAG, "update() for user " + callingUser);
-        SqlArguments args = new SqlArguments(url, where, whereArgs);
-        if (TABLE_FAVORITES.equals(args.table)) {
-            return 0;
-        } else if (TABLE_GLOBAL.equals(args.table)) {
-            callingUser = UserHandle.USER_OWNER;
+    public int delete(Uri uri, String where, String[] whereArgs) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "delete() for user: " + UserHandle.getCallingUserId());
         }
-        checkWritePermissions(args);
-        checkUserRestrictions(initialValues.getAsString(Settings.Secure.NAME), callingUser);
 
-        final AtomicInteger mutationCount;
-        synchronized (this) {
-            mutationCount = sKnownMutationsInFlight.get(callingUser);
+        Arguments args = new Arguments(uri, where, whereArgs, false);
+
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return 0;
         }
-        if (mutationCount != null) {
-            mutationCount.incrementAndGet();
+
+        if (TextUtils.isEmpty(args.name)) {
+            return 0;
         }
-        DatabaseHelper dbH = getOrEstablishDatabase(callingUser);
-        SQLiteDatabase db = dbH.getWritableDatabase();
-        int count = db.update(args.table, initialValues, args.where, args.args);
-        if (mutationCount != null) {
-            mutationCount.decrementAndGet();
+
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteGlobalSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteSecureSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return deleteSystemSettingLocked(args.name, userId) ? 1 : 0;
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Bad Uri path:" + uri);
+                }
+            }
         }
-        if (count > 0) {
-            invalidateCache(callingUser, args.table);  // before we notify
-            sendNotify(url, callingUser);
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "update() for user: " + UserHandle.getCallingUserId());
         }
-        startAsyncCachePopulation(callingUser);
-        if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
-        return count;
+
+        Arguments args = new Arguments(uri, where, whereArgs, false);
+
+        // If a legacy table that is gone, done.
+        if (REMOVED_LEGACY_TABLES.contains(args.table)) {
+            return 0;
+        }
+
+        String value = values.getAsString(Settings.Secure.VALUE);
+        if (TextUtils.isEmpty(value)) {
+            return 0;
+        }
+
+        synchronized (mLock) {
+            switch (args.table) {
+                case TABLE_GLOBAL: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateGlobalSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                case TABLE_SECURE: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateSecureSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                case TABLE_SYSTEM: {
+                    final int userId = UserHandle.getCallingUserId();
+                    return updateSystemSettingLocked(args.name, value, userId) ? 1 : 0;
+                }
+
+                default: {
+                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
+                }
+            }
+        }
     }
 
     @Override
@@ -1229,102 +481,1418 @@
                 + "ringtone playback is available through android.media.Ringtone");
     }
 
-    /**
-     * In-memory LRU Cache of system and secure settings, along with
-     * associated helper functions to keep cache coherent with the
-     * database.
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mLock) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                List<UserInfo> users = mUserManager.getUsers(true);
+                final int userCount = users.size();
+                for (int i = 0; i < userCount; i++) {
+                    UserInfo user = users.get(i);
+                    dumpForUser(user.id, pw);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private void dumpForUser(int userId, PrintWriter pw) {
+        if (userId == UserHandle.USER_OWNER) {
+            pw.println("GLOBAL SETTINGS (user " + userId + ")");
+            Cursor globalCursor = getAllGlobalSettingsLocked(ALL_COLUMNS);
+            dumpSettings(globalCursor, pw);
+            pw.println();
+        }
+
+        pw.println("SECURE SETTINGS (user " + userId + ")");
+        Cursor secureCursor = getAllSecureSettingsLocked(userId, ALL_COLUMNS);
+        dumpSettings(secureCursor, pw);
+        pw.println();
+
+        pw.println("SYSTEM SETTINGS (user " + userId + ")");
+        Cursor systemCursor = getAllSystemSettingsLocked(userId, ALL_COLUMNS);
+        dumpSettings(systemCursor, pw);
+        pw.println();
+    }
+
+    private void dumpSettings(Cursor cursor, PrintWriter pw) {
+        if (!cursor.moveToFirst()) {
+            return;
+        }
+
+        final int idColumnIdx = cursor.getColumnIndex(Settings.NameValueTable._ID);
+        final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+        final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
+        do {
+            pw.append("_id:").append(cursor.getString(idColumnIdx));
+            pw.append(" name:").append(cursor.getString(nameColumnIdx));
+            pw.append(" value:").append(cursor.getString(valueColumnIdx));
+            pw.println();
+        } while (cursor.moveToNext());
+    }
+
+    private void registerBroadcastReceivers() {
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_STOPPED);
+
+        getContext().registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_OWNER);
+
+                switch (intent.getAction()) {
+                    case Intent.ACTION_USER_REMOVED: {
+                        mSettingsRegistry.removeUserStateLocked(userId, true);
+                    } break;
+
+                    case Intent.ACTION_USER_STOPPED: {
+                        mSettingsRegistry.removeUserStateLocked(userId, false);
+                    } break;
+                }
+            }
+        }, userFilter);
+
+        PackageMonitor monitor = new PackageMonitor() {
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                synchronized (mLock) {
+                    mSettingsRegistry.onPackageRemovedLocked(packageName,
+                            UserHandle.getUserId(uid));
+                }
+            }
+        };
+
+        // package changes
+        monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
+                UserHandle.ALL, true);
+    }
+
+    private Cursor getAllGlobalSettingsLocked(String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllGlobalSettingsLocked()");
+        }
+
+        // Get the settings.
+        SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+                SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+
+        List<String> names = settingsState.getSettingNamesLocked();
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        // Anyone can get the global settings, so no security checks.
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+            Setting setting = settingsState.getSettingLocked(name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getGlobalSettingLocked(String name) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
+        }
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                UserHandle.USER_OWNER, name);
+    }
+
+    private boolean updateGlobalSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateGlobalSettingLocked(" + name + ", " + value + ")");
+        }
+        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean insertGlobalSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertGlobalSettingLocked(" + name + ", " + value + ")");
+        }
+        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteGlobalSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
+        }
+        return mutateGlobalSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean mutateGlobalSettingLocked(String name, String value, int requestingUserId,
+            int operation) {
+        // Make sure the caller can change the settings - treated as secure.
+        enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // If this is a setting that is currently restricted for this user, done.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+            return false;
+        }
+
+        // Perform the mutation.
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT: {
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                        UserHandle.USER_OWNER, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private Cursor getAllSecureSettingsLocked(int userId, String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+
+            // Determine the owning user as some profile settings are cloned from the parent.
+            final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+            // Special case for location (sigh).
+            if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+                return null;
+            }
+
+            Setting setting = mSettingsRegistry.getSettingLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getSecureSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+        // Special case for location (sigh).
+        if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+            return null;
+        }
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                owningUserId, name);
+    }
+
+    private boolean insertSecureSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertSecureSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteSecureSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteSecureSettingLocked(" + name + ", " + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean updateSecureSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateSecureSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean mutateSecureSettingLocked(String name, String value, int requestingUserId,
+            int operation) {
+        // Make sure the caller can change the settings.
+        enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // If this is a setting that is currently restricted for this user, done.
+        if (isGlobalOrSecureSettingRestrictedForUser(name, callingUserId)) {
+            return false;
+        }
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+
+        // Only the owning user can change the setting.
+        if (owningUserId != callingUserId) {
+            return false;
+        }
+
+        // Special cases for location providers (sigh).
+        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
+            return updateLocationProvidersAllowedLocked(value, owningUserId);
+        }
+
+        // Mutate the value.
+        switch(operation) {
+            case MUTATION_OPERATION_INSERT: {
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                        owningUserId, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private Cursor getAllSystemSettingsLocked(int userId, String[] projection) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getAllSecureSystemLocked(" + userId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
+
+        final int nameCount = names.size();
+
+        String[] normalizedProjection = normalizeProjection(projection);
+        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+
+        for (int i = 0; i < nameCount; i++) {
+            String name = names.get(i);
+
+            // Determine the owning user as some profile settings are cloned from the parent.
+            final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+            Setting setting = mSettingsRegistry.getSettingLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
+            appendSettingToCursor(result, setting);
+        }
+
+        return result;
+    }
+
+    private Setting getSystemSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
+        }
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+        // Get the value.
+        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                owningUserId, name);
+    }
+
+    private boolean insertSystemSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertSystemSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteSystemSettingLocked(String name, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "deleteSystemSettingLocked(" + name + ", " + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+    }
+
+    private boolean updateSystemSettingLocked(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "updateSystemSettingLocked(" + name + ", " + value + ", "
+                    + requestingUserId + ")");
+        }
+
+        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+    }
+
+    private boolean mutateSystemSettingLocked(String name, String value, int runAsUserId,
+            int operation) {
+        // Make sure the caller can change the settings.
+        enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
+
+        // Verify whether this operation is allowed for the calling package.
+        if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
+            return false;
+        }
+
+        // Enforce what the calling package can mutate in the system settings.
+        enforceRestrictedSystemSettingsMutationForCallingPackageLocked(operation, name);
+
+        // Resolve the userId on whose behalf the call is made.
+        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
+
+        // Determine the owning user as some profile settings are cloned from the parent.
+        final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+
+        // Only the owning user id can change the setting.
+        if (owningUserId != callingUserId) {
+            return false;
+        }
+
+        // Mutate the value.
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT: {
+                validateSystemSettingValue(name, value);
+                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name, value, getCallingPackage());
+            }
+
+            case MUTATION_OPERATION_DELETE: {
+                return mSettingsRegistry.deleteSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name);
+            }
+
+            case MUTATION_OPERATION_UPDATE: {
+                validateSystemSettingValue(name, value);
+                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                        owningUserId, name, value, getCallingPackage());
+            }
+        }
+
+        return false;
+    }
+
+    private void validateSystemSettingValue(String name, String value) {
+        Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
+        if (validator != null && !validator.validate(value)) {
+            throw new IllegalArgumentException("Invalid value: " + value
+                    + " for setting: " + name);
+        }
+    }
+
+    private boolean isLocationProvidersAllowedRestricted(String name, int callingUserId,
+            int owningUserId) {
+        // Optimization - location providers are restricted only for managed profiles.
+        if (callingUserId == owningUserId) {
+            return false;
+        }
+        if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)
+                && mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+                new UserHandle(callingUserId))) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isGlobalOrSecureSettingRestrictedForUser(String setting, int userId) {
+        String restriction = sSettingToUserRestrictionMap.get(setting);
+        if (restriction == null) {
+            return false;
+        }
+        return mUserManager.hasUserRestriction(restriction, new UserHandle(userId));
+    }
+
+    private int resolveOwningUserIdForSecureSettingLocked(int userId, String setting) {
+        return resolveOwningUserIdLocked(userId, sSecureCloneToManagedSettings, setting);
+    }
+
+    private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
+        return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
+    }
+
+    private int resolveOwningUserIdLocked(int userId, Set<String> keys, String name) {
+        final int parentId = getGroupParentLocked(userId);
+        if (parentId != userId && keys.contains(name)) {
+            return parentId;
+        }
+        return userId;
+    }
+
+    private void enforceRestrictedSystemSettingsMutationForCallingPackageLocked(int operation,
+            String name) {
+        // System/root/shell can mutate whatever secure settings they want.
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid == android.os.Process.SYSTEM_UID
+                || callingUid == Process.SHELL_UID
+                || callingUid == Process.ROOT_UID) {
+            return;
+        }
+
+        switch (operation) {
+            case MUTATION_OPERATION_INSERT:
+                // Insert updates.
+            case MUTATION_OPERATION_UPDATE: {
+                if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
+                    return;
+                }
+
+                // The calling package is already verified.
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+                // Privileged apps can do whatever they want.
+                if ((packageInfo.applicationInfo.privateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                    return;
+                }
+
+                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+                        packageInfo.applicationInfo.targetSdkVersion, name);
+            } break;
+
+            case MUTATION_OPERATION_DELETE: {
+                if (Settings.System.PUBLIC_SETTINGS.contains(name)
+                        || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                    throw new IllegalArgumentException("You cannot delete system defined"
+                            + " secure settings.");
+                }
+
+                // The calling package is already verified.
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+
+                // Privileged apps can do whatever they want.
+                if ((packageInfo.applicationInfo.privateFlags &
+                        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
+                    return;
+                }
+
+                warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+                        packageInfo.applicationInfo.targetSdkVersion, name);
+            } break;
+        }
+    }
+
+    private PackageInfo getCallingPackageInfoOrThrow() {
+        try {
+            return mPackageManager.getPackageInfo(getCallingPackage(), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Calling package doesn't exist");
+        }
+    }
+
+    private int getGroupParentLocked(int userId) {
+        // Most frequent use case.
+        if (userId == UserHandle.USER_OWNER) {
+            return userId;
+        }
+        // We are in the same process with the user manager and the returned
+        // user info is a cached instance, so just look up instead of cache.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            UserInfo userInfo = mUserManager.getProfileParent(userId);
+            return (userInfo != null) ? userInfo.id : userId;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private boolean isAppOpWriteSettingsAllowedForCallingPackage() {
+        final int callingUid = Binder.getCallingUid();
+
+        mAppOpsManager.checkPackage(Binder.getCallingUid(), getCallingPackage());
+
+        return mAppOpsManager.noteOp(AppOpsManager.OP_WRITE_SETTINGS, callingUid,
+                getCallingPackage()) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    private void enforceWritePermission(String permission) {
+        if (getContext().checkCallingOrSelfPermission(permission)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Permission denial: writing to settings requires:"
+                    + permission);
+        }
+    }
+
+    /*
+     * Used to parse changes to the value of Settings.Secure.LOCATION_PROVIDERS_ALLOWED.
+     * This setting contains a list of the currently enabled location providers.
+     * But helper functions in android.providers.Settings can enable or disable
+     * a single provider by using a "+" or "-" prefix before the provider name.
+     *
+     * @returns whether the enabled location providers changed.
      */
-    private static final class SettingsCache extends LruCache<String, Bundle> {
-
-        private final String mCacheName;
-        private boolean mCacheFullyMatchesDisk = false;  // has the whole database slurped.
-
-        public SettingsCache(String name) {
-            super(MAX_CACHE_ENTRIES);
-            mCacheName = name;
+    private boolean updateLocationProvidersAllowedLocked(String value, int owningUserId) {
+        if (TextUtils.isEmpty(value)) {
+            return false;
         }
 
-        /**
-         * Is the whole database table slurped into this cache?
-         */
-        public boolean fullyMatchesDisk() {
-            synchronized (this) {
-                return mCacheFullyMatchesDisk;
+        final char prefix = value.charAt(0);
+        if (prefix != '+' && prefix != '-') {
+            return false;
+        }
+
+        // skip prefix
+        value = value.substring(1);
+
+        Setting settingValue = getSecureSettingLocked(
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
+
+        String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
+
+        int index = oldProviders.indexOf(value);
+        int end = index + value.length();
+
+        // check for commas to avoid matching on partial string
+        if (index > 0 && oldProviders.charAt(index - 1) != ',') {
+            index = -1;
+        }
+
+        // check for commas to avoid matching on partial string
+        if (end < oldProviders.length() && oldProviders.charAt(end) != ',') {
+            index = -1;
+        }
+
+        String newProviders;
+
+        if (prefix == '+' && index < 0) {
+            // append the provider to the list if not present
+            if (oldProviders.length() == 0) {
+                newProviders = value;
+            } else {
+                newProviders = oldProviders + ',' + value;
+            }
+        } else if (prefix == '-' && index >= 0) {
+            // remove the provider from the list if present
+            // remove leading or trailing comma
+            if (index > 0) {
+                index--;
+            } else if (end < oldProviders.length()) {
+                end++;
+            }
+
+            newProviders = oldProviders.substring(0, index);
+            if (end < oldProviders.length()) {
+                newProviders += oldProviders.substring(end);
+            }
+        } else {
+            // nothing changed, so no need to update the database
+            return false;
+        }
+
+        return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                owningUserId, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, newProviders,
+                getCallingPackage());
+    }
+
+    private void sendNotify(Uri uri, int userId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            getContext().getContentResolver().notifyChange(uri, null, true, userId);
+            if (DEBUG) {
+                Slog.v(LOG_TAG, "Notifying for " + userId + ": " + uri);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
+            int targetSdkVersion, String name) {
+        // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash.
+        if (targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+            if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                Slog.w(LOG_TAG, "You shouldn't not change private system settings."
+                        + " This will soon become an error.");
+            } else {
+                Slog.w(LOG_TAG, "You shouldn't keep your settings in the secure settings."
+                        + " This will soon become an error.");
+            }
+        } else {
+            if (Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                throw new IllegalArgumentException("You cannot change private secure settings.");
+            } else {
+                throw new IllegalArgumentException("You cannot keep your settings in"
+                        + " the secure settings.");
+            }
+        }
+    }
+
+    private static int resolveCallingUserIdEnforcingPermissionsLocked(int requestingUserId) {
+        if (requestingUserId == UserHandle.getCallingUserId()) {
+            return requestingUserId;
+        }
+        return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), requestingUserId, false, true,
+                "get/set setting for user", null);
+    }
+
+    private static Bundle packageValueForCallResult(Setting setting) {
+        if (setting == null) {
+            return NULL_SETTING;
+        }
+        return Bundle.forPair(Settings.NameValueTable.VALUE, setting.getValue());
+    }
+
+    private static int getRequestingUserId(Bundle args) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        return (args != null) ? args.getInt(Settings.CALL_METHOD_USER_KEY, callingUserId)
+                : callingUserId;
+    }
+
+    private static String getSettingValue(Bundle args) {
+        return (args != null) ? args.getString(Settings.NameValueTable.VALUE) : null;
+    }
+
+    private static String getValidTableOrThrow(Uri uri) {
+        if (uri.getPathSegments().size() > 0) {
+            String table = uri.getPathSegments().get(0);
+            if (DatabaseHelper.isValidTable(table)) {
+                return table;
+            }
+            throw new IllegalArgumentException("Bad root path: " + table);
+        }
+        throw new IllegalArgumentException("Invalid URI:" + uri);
+    }
+
+    private static MatrixCursor packageSettingForQuery(Setting setting, String[] projection) {
+        if (setting == null) {
+            return new MatrixCursor(projection, 0);
+        }
+        MatrixCursor cursor = new MatrixCursor(projection, 1);
+        appendSettingToCursor(cursor, setting);
+        return cursor;
+    }
+
+    private static String[] normalizeProjection(String[] projection) {
+        if (projection == null) {
+            return ALL_COLUMNS;
+        }
+
+        final int columnCount = projection.length;
+        for (int i = 0; i < columnCount; i++) {
+            String column = projection[i];
+            if (!ArrayUtils.contains(ALL_COLUMNS, column)) {
+                throw new IllegalArgumentException("Invalid column: " + column);
             }
         }
 
-        public void setFullyMatchesDisk(boolean value) {
-            synchronized (this) {
-                mCacheFullyMatchesDisk = value;
+        return projection;
+    }
+
+    private static void appendSettingToCursor(MatrixCursor cursor, Setting setting) {
+        final int columnCount = cursor.getColumnCount();
+
+        String[] values =  new String[columnCount];
+
+        for (int i = 0; i < columnCount; i++) {
+            String column = cursor.getColumnName(i);
+
+            switch (column) {
+                case Settings.NameValueTable._ID: {
+                    values[i] = setting.getId();
+                } break;
+
+                case Settings.NameValueTable.NAME: {
+                    values[i] = setting.getName();
+                } break;
+
+                case Settings.NameValueTable.VALUE: {
+                    values[i] = setting.getValue();
+                } break;
             }
         }
 
-        @Override
-        protected void entryRemoved(boolean evicted, String key, Bundle oldValue, Bundle newValue) {
-            if (evicted) {
-                mCacheFullyMatchesDisk = false;
-            }
-        }
+        cursor.addRow(values);
+    }
 
-        /**
-         * Atomic cache population, conditional on size of value and if
-         * we lost a race.
-         *
-         * @returns a Bundle to send back to the client from call(), even
-         *     if we lost the race.
-         */
-        public Bundle putIfAbsent(String key, String value) {
-            Bundle bundle = (value == null) ? NULL_SETTING : Bundle.forPair("value", value);
-            if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
-                synchronized (this) {
-                    if (get(key) == null) {
-                        put(key, bundle);
+    private static final class Arguments {
+        private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
+                Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_WITH_PARAM_IN_BRACKETS =
+                Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*\\?[\\s]*\\)[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_NO_PARAM_IN_BRACKETS =
+                Pattern.compile("[\\s]*\\([\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*\\)[\\s]*");
+
+        private static final Pattern WHERE_PATTERN_NO_PARAM_NO_BRACKETS =
+                Pattern.compile("[\\s]*name[\\s]*=[\\s]*['\"].*['\"][\\s]*");
+
+        public final String table;
+        public final String name;
+
+        public Arguments(Uri uri, String where, String[] whereArgs, boolean supportAll) {
+            final int segmentSize = uri.getPathSegments().size();
+            switch (segmentSize) {
+                case 1: {
+                    if (where != null
+                            && (WHERE_PATTERN_WITH_PARAM_NO_BRACKETS.matcher(where).matches()
+                                || WHERE_PATTERN_WITH_PARAM_IN_BRACKETS.matcher(where).matches())
+                            && whereArgs.length == 1) {
+                        name = whereArgs[0];
+                        table = computeTableForSetting(uri, name);
+                        return;
+                    } else if (where != null
+                            && (WHERE_PATTERN_NO_PARAM_NO_BRACKETS.matcher(where).matches()
+                                || WHERE_PATTERN_NO_PARAM_IN_BRACKETS.matcher(where).matches())) {
+                        final int startIndex = Math.max(where.indexOf("'"),
+                                where.indexOf("\"")) + 1;
+                        final int endIndex = Math.max(where.lastIndexOf("'"),
+                                where.lastIndexOf("\""));
+                        name = where.substring(startIndex, endIndex);
+                        table = computeTableForSetting(uri, name);
+                        return;
+                    } else if (supportAll && where == null && whereArgs == null) {
+                        name = null;
+                        table = computeTableForSetting(uri, null);
+                        return;
                     }
+                } break;
+
+                case 2: {
+                    if (where == null && whereArgs == null) {
+                        name = uri.getPathSegments().get(1);
+                        table = computeTableForSetting(uri, name);
+                        return;
+                    }
+                } break;
+            }
+
+            EventLogTags.writeUnsupportedSettingsQuery(
+                    uri.toSafeString(), where, Arrays.toString(whereArgs));
+            String message = String.format( "Supported SQL:\n"
+                    + "  uri content://some_table/some_property with null where and where args\n"
+                    + "  uri content://some_table with query name=? and single name as arg\n"
+                    + "  uri content://some_table with query name=some_name and null args\n"
+                    + "  but got - uri:%1s, where:%2s whereArgs:%3s", uri, where,
+                    Arrays.toString(whereArgs));
+            throw new IllegalArgumentException(message);
+        }
+
+        private static String computeTableForSetting(Uri uri, String name) {
+            String table = getValidTableOrThrow(uri);
+
+            if (name != null) {
+                if (sSystemMovedToSecureSettings.contains(name)) {
+                    table = TABLE_SECURE;
+                }
+
+                if (sSystemMovedToGlobalSettings.contains(name)) {
+                    table = TABLE_GLOBAL;
+                }
+
+                if (sSecureMovedToGlobalSettings.contains(name)) {
+                    table = TABLE_GLOBAL;
+                }
+
+                if (sGlobalMovedToSecureSettings.contains(name)) {
+                    table = TABLE_SECURE;
                 }
             }
-            return bundle;
+
+            return table;
+        }
+    }
+
+    final class SettingsRegistry {
+        private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";
+
+        private static final int SETTINGS_TYPE_GLOBAL = 0;
+        private static final int SETTINGS_TYPE_SYSTEM = 1;
+        private static final int SETTINGS_TYPE_SECURE = 2;
+
+        private static final int SETTINGS_TYPE_MASK = 0xF0000000;
+        private static final int SETTINGS_TYPE_SHIFT = 28;
+
+        private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
+        private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
+        private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
+
+        private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
+
+        private final BackupManager mBackupManager;
+
+        public SettingsRegistry() {
+            mBackupManager = new BackupManager(getContext());
+            migrateAllLegacySettingsIfNeeded();
         }
 
-        /**
-         * Populates a key in a given (possibly-null) cache.
-         */
-        public static void populate(SettingsCache cache, ContentValues contentValues) {
-            if (cache == null) {
-                return;
-            }
-            String name = contentValues.getAsString(Settings.NameValueTable.NAME);
-            if (name == null) {
-                Log.w(TAG, "null name populating settings cache.");
-                return;
-            }
-            String value = contentValues.getAsString(Settings.NameValueTable.VALUE);
-            cache.populate(name, value);
+        public List<String> getSettingsNamesLocked(int type, int userId) {
+            final int key = makeKey(type, userId);
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            return settingsState.getSettingNamesLocked();
         }
 
-        public void populate(String name, String value) {
-            synchronized (this) {
-                if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
-                    put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
+        public SettingsState getSettingsLocked(int type, int userId) {
+            final int key = makeKey(type, userId);
+            return peekSettingsStateLocked(key);
+        }
+
+        public void ensureSettingsForUserLocked(int userId) {
+            // Migrate the setting for this user if needed.
+            migrateLegacySettingsForUserIfNeededLocked(userId);
+
+            // Ensure global settings loaded if owner.
+            if (userId == UserHandle.USER_OWNER) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                ensureSettingsStateLocked(globalKey);
+            }
+
+            // Ensure secure settings loaded.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            ensureSettingsStateLocked(secureKey);
+
+            // Make sure the secure settings have an Android id set.
+            SettingsState secureSettings = getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+            ensureSecureSettingAndroidIdSetLocked(secureSettings);
+
+            // Ensure system settings loaded.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            ensureSettingsStateLocked(systemKey);
+
+            // Upgrade the settings to the latest version.
+            UpgradeController upgrader = new UpgradeController(userId);
+            upgrader.upgradeIfNeededLocked();
+        }
+
+        private void ensureSettingsStateLocked(int key) {
+            if (mSettingsStates.get(key) == null) {
+                final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
+                SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
+                        maxBytesPerPackage);
+                mSettingsStates.put(key, settingsState);
+            }
+        }
+
+        public void removeUserStateLocked(int userId, boolean permanently) {
+            // We always keep the global settings in memory.
+
+            // Nuke system settings.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            final SettingsState systemSettingsState = mSettingsStates.get(systemKey);
+            if (systemSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(systemKey);
+                    systemSettingsState.destroyLocked(null);
                 } else {
-                    put(name, TOO_LARGE_TO_CACHE_MARKER);
+                    systemSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(systemKey);
+                        }
+                    });
+                }
+            }
+
+            // Nuke secure settings.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            final SettingsState secureSettingsState = mSettingsStates.get(secureKey);
+            if (secureSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(secureKey);
+                    secureSettingsState.destroyLocked(null);
+                } else {
+                    secureSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(secureKey);
+                        }
+                    });
                 }
             }
         }
 
-        /**
-         * For suppressing duplicate/redundant settings inserts early,
-         * checking our cache first (but without faulting it in),
-         * before going to sqlite with the mutation.
-         */
-        public static boolean isRedundantSetValue(SettingsCache cache, String name, String value) {
-            if (cache == null) return false;
-            synchronized (cache) {
-                Bundle bundle = cache.get(name);
-                if (bundle == null) return false;
-                String oldValue = bundle.getPairValue();
-                if (oldValue == null && value == null) return true;
-                if ((oldValue == null) != (value == null)) return false;
-                return oldValue.equals(value);
+        public boolean insertSettingLocked(int type, int userId, String name, String value,
+                String packageName) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.insertSettingLocked(name, value, packageName);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+            return success;
+        }
+
+        public boolean deleteSettingLocked(int type, int userId, String name) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.deleteSettingLocked(name);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+            return success;
+        }
+
+        public Setting getSettingLocked(int type, int userId, String name) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            return settingsState.getSettingLocked(name);
+        }
+
+        public boolean updateSettingLocked(int type, int userId, String name, String value,
+                String packageName) {
+            final int key = makeKey(type, userId);
+
+            SettingsState settingsState = peekSettingsStateLocked(key);
+            final boolean success = settingsState.updateSettingLocked(name, value, packageName);
+
+            if (success) {
+                notifyForSettingsChange(key, name);
+            }
+
+            return success;
+        }
+
+        public void onPackageRemovedLocked(String packageName, int userId) {
+            final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+            SettingsState globalSettings = mSettingsStates.get(globalKey);
+            globalSettings.onPackageRemovedLocked(packageName);
+
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            SettingsState secureSettings = mSettingsStates.get(secureKey);
+            secureSettings.onPackageRemovedLocked(packageName);
+
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            SettingsState systemSettings = mSettingsStates.get(systemKey);
+            systemSettings.onPackageRemovedLocked(packageName);
+        }
+
+        private SettingsState peekSettingsStateLocked(int key) {
+            SettingsState settingsState = mSettingsStates.get(key);
+            if (settingsState != null) {
+                return settingsState;
+            }
+
+            ensureSettingsForUserLocked(getUserIdFromKey(key));
+            return mSettingsStates.get(key);
+        }
+
+        private void migrateAllLegacySettingsIfNeeded() {
+            synchronized (mLock) {
+                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                File globalFile = getSettingsFile(key);
+                if (globalFile.exists()) {
+                    return;
+                }
+
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    List<UserInfo> users = mUserManager.getUsers(true);
+
+                    final int userCount = users.size();
+                    for (int i = 0; i < userCount; i++) {
+                        final int userId = users.get(i).id;
+
+                        DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+                        SQLiteDatabase database = dbHelper.getWritableDatabase();
+                        migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+
+                        // Upgrade to the latest version.
+                        UpgradeController upgrader = new UpgradeController(userId);
+                        upgrader.upgradeIfNeededLocked();
+
+                        // Drop from memory if not a running user.
+                        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
+                            removeUserStateLocked(userId, false);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        private void migrateLegacySettingsForUserIfNeededLocked(int userId) {
+            // Every user has secure settings and if no file we need to migrate.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            File secureFile = getSettingsFile(secureKey);
+            if (secureFile.exists()) {
+                return;
+            }
+
+            DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
+            SQLiteDatabase database = dbHelper.getWritableDatabase();
+
+            migrateLegacySettingsForUserLocked(dbHelper, database, userId);
+        }
+
+        private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
+                SQLiteDatabase database, int userId) {
+            // Move over the global settings if owner.
+            if (userId == UserHandle.USER_OWNER) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
+                ensureSettingsStateLocked(globalKey);
+                SettingsState globalSettings = mSettingsStates.get(globalKey);
+                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
+                globalSettings.persistSyncLocked();
+            }
+
+            // Move over the secure settings.
+            final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
+            ensureSettingsStateLocked(secureKey);
+            SettingsState secureSettings = mSettingsStates.get(secureKey);
+            migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
+            ensureSecureSettingAndroidIdSetLocked(secureSettings);
+            secureSettings.persistSyncLocked();
+
+            // Move over the system settings.
+            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
+            ensureSettingsStateLocked(systemKey);
+            SettingsState systemSettings = mSettingsStates.get(systemKey);
+            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
+            systemSettings.persistSyncLocked();
+
+            // Drop the database as now all is moved and persisted.
+            if (DROP_DATABASE_ON_MIGRATION) {
+                dbHelper.dropDatabase();
+            } else {
+                dbHelper.backupDatabase();
+            }
+        }
+
+        private void migrateLegacySettingsLocked(SettingsState settingsState,
+                SQLiteDatabase database, String table) {
+            SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
+            queryBuilder.setTables(table);
+
+            Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
+                    null, null, null, null, null);
+
+            if (cursor == null) {
+                return;
+            }
+
+            try {
+                if (!cursor.moveToFirst()) {
+                    return;
+                }
+
+                final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+                final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+
+                settingsState.setVersionLocked(database.getVersion());
+
+                while (!cursor.isAfterLast()) {
+                    String name = cursor.getString(nameColumnIdx);
+                    String value = cursor.getString(valueColumnIdx);
+                    settingsState.insertSettingLocked(name, value,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                    cursor.moveToNext();
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        private void ensureSecureSettingAndroidIdSetLocked(SettingsState secureSettings) {
+            Setting value = secureSettings.getSettingLocked(Settings.Secure.ANDROID_ID);
+
+            if (value != null) {
+                return;
+            }
+
+            final int userId = getUserIdFromKey(secureSettings.mKey);
+
+            final UserInfo user;
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                user = mUserManager.getUserInfo(userId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            if (user == null) {
+                // Can happen due to races when deleting users - treat as benign.
+                return;
+            }
+
+            String androidId = Long.toHexString(new SecureRandom().nextLong());
+            secureSettings.insertSettingLocked(Settings.Secure.ANDROID_ID, androidId,
+                    SettingsState.SYSTEM_PACKAGE_NAME);
+
+            Slog.d(LOG_TAG, "Generated and saved new ANDROID_ID [" + androidId
+                    + "] for user " + userId);
+
+            // Write a drop box entry if it's a restricted profile
+            if (user.isRestricted()) {
+                DropBoxManager dbm = (DropBoxManager) getContext().getSystemService(
+                        Context.DROPBOX_SERVICE);
+                if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
+                    dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
+                            + "," + DROPBOX_TAG_USERLOG + "," + androidId + "\n");
+                }
+            }
+        }
+
+        private void notifyForSettingsChange(int key, String name) {
+            // Update the system property *first*, so if someone is listening for
+            // a notification and then using the contract class to get their data,
+            // the system property will be updated and they'll get the new data.
+
+            boolean backedUpDataChanged = false;
+            String property = null;
+            if (isGlobalSettingsKey(key)) {
+                property = Settings.Global.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            } else if (isSecureSettingsKey(key)) {
+                property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            } else if (isSystemSettingsKey(key)) {
+                property = Settings.System.SYS_PROP_SETTING_VERSION;
+                backedUpDataChanged = true;
+            }
+
+            if (property != null) {
+                final long version = SystemProperties.getLong(property, 0) + 1;
+                SystemProperties.set(property, Long.toString(version));
+                if (DEBUG) {
+                    Slog.v(LOG_TAG, "System property " + property + "=" + version);
+                }
+            }
+
+            // Inform the backup manager about a data change
+            if (backedUpDataChanged) {
+                mBackupManager.dataChanged();
+            }
+
+            // Now send the notification through the content framework.
+
+            final int userId = getUserIdFromKey(key);
+            Uri uri = getNotificationUriFor(key, name);
+
+            sendNotify(uri, userId);
+        }
+
+        private int makeKey(int type, int userId) {
+            return (type << SETTINGS_TYPE_SHIFT) | userId;
+        }
+
+        private int getTypeFromKey(int key) {
+            return key >> SETTINGS_TYPE_SHIFT;
+        }
+
+        private int getUserIdFromKey(int key) {
+            return key & ~SETTINGS_TYPE_MASK;
+        }
+
+        private boolean isGlobalSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
+        }
+
+        private boolean isSystemSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SYSTEM;
+        }
+
+        private boolean isSecureSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
+        }
+
+        private File getSettingsFile(int key) {
+            if (isGlobalSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_GLOBAL);
+            } else if (isSystemSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SYSTEM);
+            } else if (isSecureSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SECURE);
+            } else {
+                throw new IllegalArgumentException("Invalid settings key:" + key);
+            }
+        }
+
+        private Uri getNotificationUriFor(int key, String name) {
+            if (isGlobalSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
+                        : Settings.Global.CONTENT_URI;
+            } else if (isSecureSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name)
+                        : Settings.Secure.CONTENT_URI;
+            } else if (isSystemSettingsKey(key)) {
+                return (name != null) ? Uri.withAppendedPath(Settings.System.CONTENT_URI, name)
+                        : Settings.System.CONTENT_URI;
+            } else {
+                throw new IllegalArgumentException("Invalid settings key:" + key);
+            }
+        }
+
+        private int getMaxBytesPerPackageForType(int type) {
+            switch (type) {
+                case SETTINGS_TYPE_GLOBAL:
+                case SETTINGS_TYPE_SECURE: {
+                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
+                }
+
+                default: {
+                    return SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED;
+                }
+            }
+        }
+
+        private final class UpgradeController {
+            private static final int SETTINGS_VERSION = 118;
+
+            private final int mUserId;
+
+            public UpgradeController(int userId) {
+                mUserId = userId;
+            }
+
+            public void upgradeIfNeededLocked() {
+                // The version of all settings for a user is the same (all users have secure).
+                SettingsState secureSettings = getSettingsLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SECURE, mUserId);
+
+                // Try an update from the current state.
+                final int oldVersion = secureSettings.getVersionLocked();
+                final int newVersion = SETTINGS_VERSION;
+
+                // If up do data - done.
+                if (oldVersion == newVersion) {
+                    return;
+                }
+
+                // Try to upgrade.
+                final int curVersion = onUpgradeLocked(mUserId, oldVersion, newVersion);
+
+                // If upgrade failed start from scratch and upgrade.
+                if (curVersion != newVersion) {
+                    // Drop state we have for this user.
+                    removeUserStateLocked(mUserId, true);
+
+                    // Recreate the database.
+                    DatabaseHelper dbHelper = new DatabaseHelper(getContext(), mUserId);
+                    SQLiteDatabase database = dbHelper.getWritableDatabase();
+                    dbHelper.recreateDatabase(database, newVersion, curVersion, oldVersion);
+
+                    // Migrate the settings for this user.
+                    migrateLegacySettingsForUserLocked(dbHelper, database, mUserId);
+
+                    // Now upgrade should work fine.
+                    onUpgradeLocked(mUserId, oldVersion, newVersion);
+                }
+
+                // Set the global settings version if owner.
+                if (mUserId == UserHandle.USER_OWNER) {
+                    SettingsState globalSettings = getSettingsLocked(
+                            SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
+                    globalSettings.setVersionLocked(newVersion);
+                }
+
+                // Set the secure settings version.
+                secureSettings.setVersionLocked(newVersion);
+
+                // Set the system settings version.
+                SettingsState systemSettings = getSettingsLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SYSTEM, mUserId);
+                systemSettings.setVersionLocked(newVersion);
+            }
+
+            private SettingsState getGlobalSettingsLocked() {
+                return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+            }
+
+            private SettingsState getSecureSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
+            }
+
+            private SettingsState getSystemSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
+            }
+
+            private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
+                if (DEBUG) {
+                    Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
+                            + oldVersion + " to version: " + newVersion);
+                }
+
+                // You must perform all necessary mutations to bring the settings
+                // for this user from the old to the new version. When you add a new
+                // upgrade step you *must* update SETTINGS_VERSION.
+
+                /**
+                 * This is an example of moving a setting from secure to global.
+                 *
+                 * int currentVersion = oldVersion;
+                 * if (currentVersion == 118) {
+                 *     // Remove from the secure settings.
+                 *     SettingsState secureSettings = getSecureSettingsLocked(userId);
+                 *     String name = "example_setting_to_move";
+                 *     String value = secureSettings.getSetting(name);
+                 *     secureSettings.deleteSetting(name);
+                 *
+                 *     // Add to the global settings.
+                 *     SettingsState globalSettings = getGlobalSettingsLocked();
+                 *     globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
+                 *
+                 *     // Update the current version.
+                 *     currentVersion = 119;
+                 * }
+                 *
+                 * // Return the current version.
+                 * return currentVersion;
+                 */
+
+                return SettingsState.VERSION_UNDEFINED;
             }
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
new file mode 100644
index 0000000..84e66ff
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+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.List;
+
+/**
+ * This class contains the state for one type of settings. It is responsible
+ * for saving the state asynchronously to an XML file after a mutation and
+ * loading the from an XML file on construction.
+ * <p>
+ * This class uses the same lock as the settings provider to ensure that
+ * multiple changes made by the settings provider, e,g, upgrade, bulk insert,
+ * etc, are atomically persisted since the asynchronous persistence is using
+ * the same lock to grab the current state to write to disk.
+ * </p>
+ */
+final class SettingsState {
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_PERSISTENCE = false;
+
+    private static final String LOG_TAG = "SettingsState";
+
+    private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;
+    private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;
+
+    public static final int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1;
+    public static final int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000;
+
+    public static final String SYSTEM_PACKAGE_NAME = "android";
+
+    public static final int VERSION_UNDEFINED = -1;
+
+    private static final String TAG_SETTINGS = "settings";
+    private static final String TAG_SETTING = "setting";
+    private static final String ATTR_PACKAGE = "package";
+
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_ID = "id";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_VALUE = "value";
+
+    private static final String NULL_VALUE = "null";
+
+    private final Object mLock;
+
+    private final Handler mHandler = new MyHandler();
+
+    @GuardedBy("mLock")
+    private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();
+
+    @GuardedBy("mLock")
+    private final ArrayMap<String, Integer> mPackageToMemoryUsage;
+
+    @GuardedBy("mLock")
+    private final int mMaxBytesPerAppPackage;
+
+    @GuardedBy("mLock")
+    private final File mStatePersistFile;
+
+    public final int mKey;
+
+    @GuardedBy("mLock")
+    private int mVersion = VERSION_UNDEFINED;
+
+    @GuardedBy("mLock")
+    private long mLastNotWrittenMutationTimeMillis;
+
+    @GuardedBy("mLock")
+    private boolean mDirty;
+
+    @GuardedBy("mLock")
+    private boolean mWriteScheduled;
+
+    @GuardedBy("mLock")
+    private long mNextId;
+
+    public SettingsState(Object lock, File file, int key, int maxBytesPerAppPackage) {
+        // It is important that we use the same lock as the settings provider
+        // to ensure multiple mutations on this state are atomicaly persisted
+        // as the async persistence should be blocked while we make changes.
+        mLock = lock;
+        mStatePersistFile = file;
+        mKey = key;
+        if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {
+            mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+            mPackageToMemoryUsage = new ArrayMap<>();
+        } else {
+            mMaxBytesPerAppPackage = maxBytesPerAppPackage;
+            mPackageToMemoryUsage = null;
+        }
+        synchronized (mLock) {
+            readStateSyncLocked();
+        }
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public int getVersionLocked() {
+        return mVersion;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void setVersionLocked(int version) {
+        if (version == mVersion) {
+            return;
+        }
+        mVersion = version;
+
+        scheduleWriteIfNeededLocked();
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void onPackageRemovedLocked(String packageName) {
+        boolean removedSomething = false;
+
+        final int settingCount = mSettings.size();
+        for (int i = settingCount - 1; i >= 0; i--) {
+            String name = mSettings.keyAt(i);
+            // Settings defined by us are never dropped.
+            if (Settings.System.PUBLIC_SETTINGS.contains(name)
+                    || Settings.System.PRIVATE_SETTINGS.contains(name)) {
+                continue;
+            }
+            Setting setting = mSettings.valueAt(i);
+            if (packageName.equals(setting.packageName)) {
+                mSettings.removeAt(i);
+                removedSomething = true;
+            }
+        }
+
+        if (removedSomething) {
+            scheduleWriteIfNeededLocked();
+        }
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public List<String> getSettingNamesLocked() {
+        ArrayList<String> names = new ArrayList<>();
+        final int settingsCount = mSettings.size();
+        for (int i = 0; i < settingsCount; i++) {
+            String name = mSettings.keyAt(i);
+            names.add(name);
+        }
+        return names;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public Setting getSettingLocked(String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+        return mSettings.get(name);
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean updateSettingLocked(String name, String value, String packageName) {
+        if (!hasSettingLocked(name)) {
+            return false;
+        }
+
+        return insertSettingLocked(name, value, packageName);
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean insertSettingLocked(String name, String value, String packageName) {
+        if (TextUtils.isEmpty(name)) {
+            return false;
+        }
+
+        Setting oldState = mSettings.get(name);
+        String oldValue = (oldState != null) ? oldState.value : null;
+
+        if (oldState != null) {
+            if (!oldState.update(value, packageName)) {
+                return false;
+            }
+        } else {
+            Setting state = new Setting(name, value, packageName);
+            mSettings.put(name, state);
+        }
+
+        updateMemoryUsagePerPackageLocked(packageName, oldValue, value);
+
+        scheduleWriteIfNeededLocked();
+
+        return true;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void persistSyncLocked() {
+        mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+        doWriteState();
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public boolean deleteSettingLocked(String name) {
+        if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {
+            return false;
+        }
+
+        Setting oldState = mSettings.remove(name);
+
+        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value, null);
+
+        scheduleWriteIfNeededLocked();
+
+        return true;
+    }
+
+    // The settings provider must hold its lock when calling here.
+    public void destroyLocked(Runnable callback) {
+        mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+        if (callback != null) {
+            if (mDirty) {
+                // Do it without a delay.
+                mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS,
+                        callback).sendToTarget();
+                return;
+            }
+            callback.run();
+        }
+    }
+
+    private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,
+            String newValue) {
+        if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {
+            return;
+        }
+
+        if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
+            return;
+        }
+
+        final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;
+        final int newValueSize = (newValue != null) ? newValue.length() : 0;
+        final int deltaSize = newValueSize - oldValueSize;
+
+        Integer currentSize = mPackageToMemoryUsage.get(packageName);
+        final int newSize = Math.max((currentSize != null)
+                ? currentSize + deltaSize : deltaSize, 0);
+
+        if (newSize > mMaxBytesPerAppPackage) {
+            throw new IllegalStateException("You are adding too many system settings. "
+                    + "You should stop using system settings for app specific data"
+                    + " package: " + packageName);
+        }
+
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "Settings for package: " + packageName
+                    + " size: " + newSize + " bytes.");
+        }
+
+        mPackageToMemoryUsage.put(packageName, newSize);
+    }
+
+    private boolean hasSettingLocked(String name) {
+        return mSettings.indexOfKey(name) >= 0;
+    }
+
+    private void scheduleWriteIfNeededLocked() {
+        // If dirty then we have a write already scheduled.
+        if (!mDirty) {
+            mDirty = true;
+            writeStateAsyncLocked();
+        }
+    }
+
+    private void writeStateAsyncLocked() {
+        final long currentTimeMillis = SystemClock.uptimeMillis();
+
+        if (mWriteScheduled) {
+            mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);
+
+            // If enough time passed, write without holding off anymore.
+            final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+                    - mLastNotWrittenMutationTimeMillis;
+            if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) {
+                mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget();
+                return;
+            }
+
+            // Hold off a bit more as settings are frequently changing.
+            final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis
+                    + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0);
+            final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis);
+
+            Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+            mHandler.sendMessageDelayed(message, writeDelayMillis);
+        } else {
+            mLastNotWrittenMutationTimeMillis = currentTimeMillis;
+            Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);
+            mHandler.sendMessageDelayed(message, WRITE_SETTINGS_DELAY_MILLIS);
+            mWriteScheduled = true;
+        }
+    }
+
+    private void doWriteState() {
+        if (DEBUG_PERSISTENCE) {
+            Slog.i(LOG_TAG, "[PERSIST START]");
+        }
+
+        AtomicFile destination = new AtomicFile(mStatePersistFile);
+
+        final int version;
+        final ArrayMap<String, Setting> settings;
+
+        synchronized (mLock) {
+            version = mVersion;
+            settings = new ArrayMap<>(mSettings);
+            mDirty = false;
+            mWriteScheduled = false;
+        }
+
+        FileOutputStream out = null;
+        try {
+            out = destination.startWrite();
+
+            XmlSerializer serializer = Xml.newSerializer();
+            serializer.setOutput(out, "utf-8");
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+            serializer.startDocument(null, true);
+            serializer.startTag(null, TAG_SETTINGS);
+            serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
+
+            final int settingCount = settings.size();
+            for (int i = 0; i < settingCount; i++) {
+                Setting setting = settings.valueAt(i);
+
+                serializer.startTag(null, TAG_SETTING);
+                serializer.attribute(null, ATTR_ID, setting.getId());
+                serializer.attribute(null, ATTR_NAME, setting.getName());
+                serializer.attribute(null, ATTR_VALUE, packValue(setting.getValue()));
+                serializer.attribute(null, ATTR_PACKAGE, packValue(setting.getPackageName()));
+                serializer.endTag(null, TAG_SETTING);
+
+                if (DEBUG_PERSISTENCE) {
+                    Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());
+                }
+            }
+
+            serializer.endTag(null, TAG_SETTINGS);
+            serializer.endDocument();
+            destination.finishWrite(out);
+
+            if (DEBUG_PERSISTENCE) {
+                Slog.i(LOG_TAG, "[PERSIST END]");
+            }
+
+        } catch (IOException e) {
+            Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", e);
+            destination.failWrite(out);
+        } finally {
+            IoUtils.closeQuietly(out);
+        }
+    }
+
+    private void readStateSyncLocked() {
+        FileInputStream in;
+        if (!mStatePersistFile.exists()) {
+            return;
+        }
+        try {
+            in = new FileInputStream(mStatePersistFile);
+        } catch (FileNotFoundException fnfe) {
+            Slog.i(LOG_TAG, "No settings state");
+            return;
+        }
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(in, null);
+            parseStateLocked(parser);
+        } catch (XmlPullParserException | IOException ise) {
+            throw new IllegalStateException("Failed parsing settings file: "
+                    + mStatePersistFile , ise);
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    private void parseStateLocked(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        parser.next();
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.START_TAG, TAG_SETTINGS);
+
+        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+
+        parser.next();
+
+        while (parseSettingLocked(parser)) {
+            parser.next();
+        }
+
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.END_TAG, TAG_SETTINGS);
+    }
+
+    private boolean parseSettingLocked(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        skipEmptyTextTags(parser);
+        if (!accept(parser, XmlPullParser.START_TAG, TAG_SETTING)) {
+            return false;
+        }
+
+        String id = parser.getAttributeValue(null, ATTR_ID);
+        String name = parser.getAttributeValue(null, ATTR_NAME);
+        String value = parser.getAttributeValue(null, ATTR_VALUE);
+        String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+        mSettings.put(name, new Setting(name, unpackValue(value),
+                unpackValue(packageName), id));
+
+        if (DEBUG_PERSISTENCE) {
+            Slog.i(LOG_TAG, "[RESTORED] " + name + "=" + value);
+        }
+
+        parser.next();
+
+        skipEmptyTextTags(parser);
+        expect(parser, XmlPullParser.END_TAG, TAG_SETTING);
+
+        return true;
+    }
+
+    private void expect(XmlPullParser parser, int type, String tag)
+            throws IOException, XmlPullParserException {
+        if (!accept(parser, type, tag)) {
+            throw new XmlPullParserException("Expected event: " + type
+                    + " and tag: " + tag + " but got event: " + parser.getEventType()
+                    + " and tag:" + parser.getName());
+        }
+    }
+
+    private void skipEmptyTextTags(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        while (accept(parser, XmlPullParser.TEXT, null)
+                && parser.isWhitespace()) {
+            parser.next();
+        }
+    }
+
+    private boolean accept(XmlPullParser parser, int type, String tag)
+            throws IOException, XmlPullParserException {
+        if (parser.getEventType() != type) {
+            return false;
+        }
+        if (tag != null) {
+            if (!tag.equals(parser.getName())) {
+                return false;
+            }
+        } else if (parser.getName() != null) {
+            return false;
+        }
+        return true;
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_PERSIST_SETTINGS = 1;
+
+        public MyHandler() {
+            super(PersistThread.getInstance().getLooper());
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_PERSIST_SETTINGS: {
+                    Runnable callback = (Runnable) message.obj;
+                    doWriteState();
+                    if (callback != null) {
+                        callback.run();
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    private static String packValue(String value) {
+        if (value == null) {
+            return NULL_VALUE;
+        }
+        return value;
+    }
+
+    private static String unpackValue(String value) {
+        if (NULL_VALUE.equals(value)) {
+            return null;
+        }
+        return value;
+    }
+
+    public final class Setting {
+        private String name;
+        private String value;
+        private String packageName;
+        private String id;
+
+        public Setting(String name, String value, String packageName) {
+            init(name, value, packageName, String.valueOf(mNextId++));
+        }
+
+        public Setting(String name, String value, String packageName, String id) {
+            mNextId = Math.max(mNextId, Long.valueOf(id) + 1);
+            init(name, value, packageName, id);
+        }
+
+        private void init(String name, String value, String packageName, String id) {
+            this.name = name;
+            this.value = value;
+            this.packageName = packageName;
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public boolean update(String value, String packageName) {
+            if (Objects.equal(value, this.value)) {
+                return false;
+            }
+            this.value = value;
+            this.packageName = packageName;
+            this.id = String.valueOf(mNextId++);
+            return true;
+        }
+    }
+
+    private static final class PersistThread extends HandlerThread {
+        private static final Object sLock = new Object();
+
+        private static PersistThread sInstance;
+
+        private PersistThread() {
+            super("settings.persist");
+        }
+
+        public static PersistThread getInstance() {
+            synchronized (sLock) {
+                if (sInstance == null) {
+                    sInstance = new PersistThread();
+                    sInstance.start();
+                }
+                return sInstance;
+            }
+        }
+    }
+}
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
new file mode 100644
index 0000000..01c6ccf
--- /dev/null
+++ b/packages/SettingsProvider/test/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SettingsProviderTest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
new file mode 100644
index 0000000..7a86b5f
--- /dev/null
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.providers.setting.test">
+
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.providers.setting.test"
+        android:label="Settings Provider Tests" />
+</manifest>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
new file mode 100644
index 0000000..8473db4
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for the SettingContentProvider tests.
+ */
+abstract class BaseSettingsProviderTest extends AndroidTestCase {
+    protected static final int SETTING_TYPE_GLOBAL = 1;
+    protected static final int SETTING_TYPE_SECURE = 2;
+    protected static final int SETTING_TYPE_SYSTEM = 3;
+
+    protected static final String FAKE_SETTING_NAME = "fake_setting_name";
+    protected static final String FAKE_SETTING_NAME_1 = "fake_setting_name1";
+    protected static final String FAKE_SETTING_VALUE = "fake_setting_value";
+    protected static final String FAKE_SETTING_VALUE_1 = "fake_setting_value_1";
+
+    private static final String[] NAME_VALUE_COLUMNS = new String[] {
+            Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+    };
+
+    protected int mSecondaryUserId = UserHandle.USER_OWNER;
+
+    @Override
+    public void setContext(Context context) {
+        super.setContext(context);
+
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        List<UserInfo> users = userManager.getUsers();
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            UserInfo user = users.get(i);
+            if (!user.isPrimary() && !user.isManagedProfile()) {
+                mSecondaryUserId = user.id;
+                break;
+            }
+        }
+    }
+
+    protected void setStringViaFrontEndApiSetting(int type, String name, String value, int userId) {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                Settings.Global.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            case SETTING_TYPE_SECURE: {
+                Settings.Secure.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            case SETTING_TYPE_SYSTEM: {
+                Settings.System.putStringForUser(contentResolver, name, value, userId);
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected String getStringViaFrontEndApiSetting(int type, String name, int userId) {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                return Settings.Global.getStringForUser(contentResolver, name, userId);
+            }
+
+            case SETTING_TYPE_SECURE: {
+                return Settings.Secure.getStringForUser(contentResolver, name, userId);
+            }
+
+            case SETTING_TYPE_SYSTEM: {
+                return Settings.System.getStringForUser(contentResolver, name, userId);
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+
+    protected Uri insertStringViaProviderApi(int type, String name, String value,
+            boolean withTableRowUri) {
+        Uri uri = getBaseUriForType(type);
+        if (withTableRowUri) {
+            uri = Uri.withAppendedPath(uri, name);
+        }
+        ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, name);
+        values.put(Settings.NameValueTable.VALUE, value);
+
+        return getContext().getContentResolver().insert(uri, values);
+    }
+
+    protected int deleteStringViaProviderApi(int type, String name) {
+        Uri uri = getBaseUriForType(type);
+        return getContext().getContentResolver().delete(uri, "name=?", new String[]{name});
+    }
+
+    protected int updateStringViaProviderApiSetting(int type, String name, String value) {
+        Uri uri = getBaseUriForType(type);
+        ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, name);
+        values.put(Settings.NameValueTable.VALUE, value);
+        return getContext().getContentResolver().update(uri, values, "name=?",
+                new String[]{name});
+    }
+
+    protected String queryStringViaProviderApi(int type, String name) {
+        return queryStringViaProviderApi(type, name, false, false);
+    }
+
+    protected String queryStringViaProviderApi(int type, String name, boolean queryStringInQuotes,
+            boolean appendNameToUri) {
+        final Uri uri;
+        final String queryString;
+        final String[] queryArgs;
+
+        if (appendNameToUri) {
+            uri = Uri.withAppendedPath(getBaseUriForType(type), name);
+            queryString = null;
+            queryArgs = null;
+        } else {
+            uri = getBaseUriForType(type);
+            queryString = queryStringInQuotes ? "(name=?)" : "name=?";
+            queryArgs = new String[]{name};
+        }
+
+        Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+                queryString, queryArgs, null);
+
+        if (cursor == null) {
+            return null;
+        }
+
+        try {
+            if (cursor.moveToFirst()) {
+                final int valueColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
+                return cursor.getString(valueColumnIdx);
+            }
+        } finally {
+            cursor.close();
+        }
+
+        return null;
+    }
+
+    protected static Uri getBaseUriForType(int type) {
+        switch (type) {
+            case SETTING_TYPE_GLOBAL: {
+                return Settings.Global.CONTENT_URI;
+            }
+
+            case SETTING_TYPE_SECURE: {
+                return Settings.Secure.CONTENT_URI;
+            }
+
+            case SETTING_TYPE_SYSTEM: {
+                return Settings.System.CONTENT_URI;
+            }
+
+            default: {
+                throw new IllegalArgumentException("Invalid type: " + type);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
new file mode 100644
index 0000000..d581f3b
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+* Performance tests for the SettingContentProvider.
+*/
+public class SettingsProviderPerformanceTest extends BaseSettingsProviderTest {
+    private static final String LOG_TAG = "SettingsProviderPerformanceTest";
+
+    private static final int ITERATION_COUNT = 100;
+
+    private static final int MICRO_SECONDS_IN_MILLISECOND = 1000;
+
+    private static final long MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS = 20;
+
+    public void testSetAndGetPerformanceForGlobalViaFrontEndApi() throws Exception {
+        // Start with a clean slate.
+        insertStringViaProviderApi(SETTING_TYPE_GLOBAL,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+
+        final long startTimeMicro = SystemClock.currentTimeMicro();
+
+        try {
+            for (int i = 0; i < ITERATION_COUNT; i++) {
+                // Set the setting to its first value.
+                updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE);
+
+                // Make sure the setting changed.
+                String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+                // Set the setting to its second value.
+                updateStringViaProviderApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE_1);
+
+                // Make sure the setting changed.
+                String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+            }
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+
+        final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+        final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+                / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+        Log.i(LOG_TAG, "Average time to set and get setting via provider APIs: "
+                + averageTimePerIterationMillis + " ms");
+
+        assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+                < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+    }
+
+    public void testSetAndGetPerformanceForGlobalViaProviderApi() throws Exception {
+        // Start with a clean slate.
+        deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+
+        final long startTimeMicro = SystemClock.currentTimeMicro();
+
+        try {
+            for (int i = 0; i < ITERATION_COUNT; i++) {
+                // Set the setting to its first value.
+                setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE, UserHandle.USER_OWNER);
+
+                // Make sure the setting changed.
+                String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
+
+                // Set the setting to its second value.
+                setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
+                        FAKE_SETTING_VALUE_1, UserHandle.USER_OWNER);
+
+                // Make sure the setting changed.
+                String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
+                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
+            }
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+
+        final long elapsedTimeMicro = SystemClock.currentTimeMicro() - startTimeMicro;
+
+        final long averageTimePerIterationMillis = (long) ((((float) elapsedTimeMicro)
+                / ITERATION_COUNT) / MICRO_SECONDS_IN_MILLISECOND);
+
+        Log.i(LOG_TAG, "Average time to set and get setting via front-eng APIs: "
+                + averageTimePerIterationMillis + " ms");
+
+        assertTrue("Setting and getting a settings takes too long.", averageTimePerIterationMillis
+                < MAX_AVERAGE_SET_AND_GET_SETTING_DURATION_MILLIS);
+    }
+}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
new file mode 100644
index 0000000..b89fb10
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.settings;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Tests for the SettingContentProvider.
+ *
+ * Before you run this test you must add a secondary user.
+ */
+public class SettingsProviderTest extends BaseSettingsProviderTest {
+    private static final String LOG_TAG = "SettingsProviderTest";
+
+    private static final long WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
+
+    private static final String[] NAME_VALUE_COLUMNS = new String[]{
+            Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
+    };
+
+    private final Object mLock = new Object();
+
+    public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
+    }
+
+    public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
+    }
+
+    public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER);
+    }
+
+    public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+            Log.w(LOG_TAG, "No secondary user. Skipping "
+                    + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser");
+            return;
+        }
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
+    }
+
+    public void testSetAndGetGlobalViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testSetAndGetSecureViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SECURE);
+    }
+
+    public void testSetAndGetSystemViaProviderApi() throws Exception {
+        performSetAndGetSettingTestViaProviderApi(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testSelectAllGlobalViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_GLOBAL,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_GLOBAL,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testSelectAllSecureViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SECURE,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SECURE,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_SECURE, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testSelectAllSystemViaProviderApi() throws Exception {
+        setSettingViaProviderApiAndAssertSuccessfulChange(SETTING_TYPE_SYSTEM,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, true);
+        try {
+            queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(SETTING_TYPE_SYSTEM,
+                    FAKE_SETTING_NAME);
+        } finally {
+            deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+        }
+    }
+
+    public void testQueryUpdateDeleteGlobalViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testQueryUpdateDeleteSecureViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testQueryUpdateDeleteSystemViaProviderApi() throws Exception {
+        doTestQueryUpdateDeleteGlobalViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testBulkInsertGlobalViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testBulkInsertSystemViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testBulkInsertSecureViaProviderApi() throws Exception {
+        toTestBulkInsertViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testAppCannotRunsSystemOutOfMemoryWritingSystemSettings() throws Exception {
+        int insertedCount = 0;
+        try {
+            for (; insertedCount < 1200; insertedCount++) {
+                Log.w(LOG_TAG, "Adding app specific setting: " + insertedCount);
+                insertStringViaProviderApi(SETTING_TYPE_SYSTEM,
+                        String.valueOf(insertedCount), FAKE_SETTING_VALUE, false);
+            }
+            fail("Adding app specific settings must be bound.");
+        } catch (Exception e) {
+            for (; insertedCount >= 0; insertedCount--) {
+                Log.w(LOG_TAG, "Removing app specific setting: " + insertedCount);
+                deleteStringViaProviderApi(SETTING_TYPE_SYSTEM,
+                        String.valueOf(insertedCount));
+            }
+        }
+    }
+
+    public void testQueryStringInBracketsGlobalViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_GLOBAL);
+    }
+
+    public void testQueryStringInBracketsSecureViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SECURE);
+    }
+
+    public void testQueryStringInBracketsSystemViaProviderApiForType() throws Exception {
+        doTestQueryStringInBracketsViaProviderApiForType(SETTING_TYPE_SYSTEM);
+    }
+
+    public void testQueryStringWithAppendedNameToUriViaProviderApi() throws Exception {
+        // Make sure we have a clean slate.
+        deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+
+        try {
+            // Insert the setting.
+            final Uri uri = insertStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, false);
+            Uri expectUri = Uri.withAppendedPath(getBaseUriForType(SETTING_TYPE_SYSTEM),
+                    FAKE_SETTING_NAME);
+            assertEquals("Did not get expected Uri.", expectUri, uri);
+
+            // Make sure the first setting is there.
+            String firstValue = queryStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME,
+                    false, true);
+            assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(SETTING_TYPE_SYSTEM, FAKE_SETTING_NAME);
+        }
+    }
+
+    private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
+        // Make sure we have a clean slate.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+        try {
+            // Insert the setting.
+            final Uri uri = insertStringViaProviderApi(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, false);
+            Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+            assertEquals("Did not get expected Uri.", expectUri, uri);
+
+            // Make sure the first setting is there.
+            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME, true, false);
+            assertEquals("Setting must be present", FAKE_SETTING_VALUE, firstValue);
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+        }
+    }
+
+    private void toTestBulkInsertViaProviderApiForType(int type) {
+        // Make sure we have a clean slate.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+
+        try {
+            Uri uri = getBaseUriForType(type);
+            ContentValues[] allValues = new ContentValues[2];
+
+            // Insert the first setting.
+            ContentValues firstValues = new ContentValues();
+            firstValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME);
+            firstValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE);
+            allValues[0] = firstValues;
+
+            // Insert the first setting.
+            ContentValues secondValues = new ContentValues();
+            secondValues.put(Settings.NameValueTable.NAME, FAKE_SETTING_NAME_1);
+            secondValues.put(Settings.NameValueTable.VALUE, FAKE_SETTING_VALUE_1);
+            allValues[1] = secondValues;
+
+            // Verify insertion count.
+            final int insertCount = getContext().getContentResolver().bulkInsert(uri, allValues);
+            assertSame("Couldn't insert both values", 2, insertCount);
+
+            // Make sure the first setting is there.
+            String firstValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+            assertEquals("First setting must be present", FAKE_SETTING_VALUE, firstValue);
+
+            // Make sure the second setting is there.
+            String secondValue = queryStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+            assertEquals("Second setting must be present", FAKE_SETTING_VALUE_1, secondValue);
+        } finally {
+            // Clean up.
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+            deleteStringViaProviderApi(type, FAKE_SETTING_NAME_1);
+        }
+    }
+
+    private void doTestQueryUpdateDeleteGlobalViaProviderApiForType(int type) throws Exception {
+        // Make sure it is not there.
+        deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
+
+        // Now selection should return nothing.
+        String value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertNull("Setting should not be present.", value);
+
+        // Insert the setting.
+        Uri uri = insertStringViaProviderApi(type,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE, false);
+        Uri expectUri = Uri.withAppendedPath(getBaseUriForType(type), FAKE_SETTING_NAME);
+        assertEquals("Did not get expected Uri.", expectUri, uri);
+
+        // Now selection should return the setting.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertEquals("Setting should be present.", FAKE_SETTING_VALUE, value);
+
+        // Update the setting.
+        final int changeCount = updateStringViaProviderApiSetting(type,
+                FAKE_SETTING_NAME, FAKE_SETTING_VALUE_1);
+        assertEquals("Did not get expected change count.", 1, changeCount);
+
+        // Now selection should return the new setting.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertEquals("Setting should be present.", FAKE_SETTING_VALUE_1, value);
+
+        // Delete the setting.
+        final int deletedCount = deleteStringViaProviderApi(type,
+                FAKE_SETTING_NAME);
+        assertEquals("Did not get expected deleted count", 1, deletedCount);
+
+        // Now selection should return nothing.
+        value = queryStringViaProviderApi(type, FAKE_SETTING_NAME);
+        assertNull("Setting should not be present.", value);
+    }
+
+    private void performSetAndGetSettingTestViaFrontEndApi(int type, int userId)
+            throws Exception {
+        try {
+            // Change the setting and assert a successful change.
+            setSettingViaFrontEndApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, userId);
+        } finally {
+            // Remove the setting.
+            setStringViaFrontEndApiSetting(type, FAKE_SETTING_NAME, null, userId);
+        }
+    }
+
+    private void performSetAndGetSettingTestViaProviderApi(int type)
+            throws Exception {
+        try {
+            // Change the setting and assert a successful change.
+            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME,
+                    FAKE_SETTING_VALUE, true);
+        } finally {
+            // Remove the setting.
+            setSettingViaProviderApiAndAssertSuccessfulChange(type, FAKE_SETTING_NAME, null,
+                    true);
+        }
+    }
+
+    private void setSettingViaFrontEndApiAndAssertSuccessfulChange(final int type,
+            final String name, final String value, final int userId) throws Exception {
+        setSettingAndAssertSuccessfulChange(new Runnable() {
+            @Override
+            public void run() {
+                setStringViaFrontEndApiSetting(type, name, value, userId);
+            }
+        }, type, name, value, userId);
+    }
+
+    private void setSettingViaProviderApiAndAssertSuccessfulChange(final int type,
+            final String name, final String value, final boolean withTableRowUri)
+            throws Exception {
+        setSettingAndAssertSuccessfulChange(new Runnable() {
+            @Override
+            public void run() {
+                insertStringViaProviderApi(type, name, value, withTableRowUri);
+            }
+        }, type, name, value, UserHandle.USER_OWNER);
+    }
+
+    private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
+            final String name, final String value, final int userId) throws Exception {
+        ContentResolver contentResolver = getContext().getContentResolver();
+
+        final Uri settingUri = getBaseUriForType(type);
+
+        final AtomicBoolean success = new AtomicBoolean();
+
+        ContentObserver contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+            public void onChange(boolean selfChange, Uri changeUri, int changeId) {
+                Log.i(LOG_TAG, "onChange(" + selfChange + ", " + changeUri + ", " + changeId + ")");
+                assertEquals("Wrong change Uri", changeUri, settingUri);
+                assertEquals("Wrong user id", userId, changeId);
+                String changeValue = getStringViaFrontEndApiSetting(type, name, userId);
+                assertEquals("Wrong setting value", value, changeValue);
+
+                success.set(true);
+
+                synchronized (mLock) {
+                    mLock.notifyAll();
+                }
+            }
+        };
+
+        contentResolver.registerContentObserver(settingUri, false, contentObserver, userId);
+
+        try {
+            setCommand.run();
+
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            synchronized (mLock) {
+                if (success.get()) {
+                    return;
+                }
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+                    fail("Could not change setting for "
+                            + WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
+                }
+                final long remainingTimeMillis = WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS
+                        - elapsedTimeMillis;
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            contentResolver.unregisterContentObserver(contentObserver);
+        }
+    }
+
+    private void queryAllSettingsViaProviderApiSettingAndAssertSettingPresent(int type,
+            String name) {
+        Uri uri = getBaseUriForType(type);
+
+        Cursor cursor = getContext().getContentResolver().query(uri, NAME_VALUE_COLUMNS,
+                null, null, null);
+
+        if (cursor == null || !cursor.moveToFirst()) {
+            fail("Nothing selected");
+        }
+
+        try {
+            final int nameColumnIdx = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+
+            while (cursor.moveToNext()) {
+                String currentName = cursor.getString(nameColumnIdx);
+                if (name.equals(currentName)) {
+                    return;
+                }
+            }
+
+            fail("Not found setting: " + name);
+        } finally {
+            cursor.close();
+        }
+    }
+}
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 2904cbb..0c42cab 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -17,9 +17,9 @@
 <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="3701846017049540910">"Shell-interfazea"</string>
-    <string name="bugreport_finished_title" msgid="2293711546892863898">"Programa-akatsen txostena jaso da"</string>
+    <string name="bugreport_finished_title" msgid="2293711546892863898">"Akatsen txostena jaso da"</string>
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Programa-akatsen txostena partekatzeko, pasatu hatza ezkerrera"</string>
-    <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Programa-akatsen txostena partekatzeko, ukitu"</string>
-    <string name="bugreport_confirm" msgid="5130698467795669780">"Programa-akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Programa-akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
+    <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
+    <string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Erakutsi mezu hau hurrengoan"</string>
 </resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index 2e95b4e..ed0697e 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -21,5 +21,5 @@
     <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Hata raporunuzu paylaşmak için hızlıca sola kaydırın"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
-    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu mesajı göster"</string>
+    <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
 </resources>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 69c6159..47ef42a 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -20,6 +20,10 @@
     $(LOCAL_PATH)/res
 LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard
 
+include frameworks/base/packages/SettingsLib/common.mk
+
 include $(BUILD_PACKAGE)
 
-include $(call all-makefiles-under,$(LOCAL_PATH))
+ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
+    include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b606a6f..158e133 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -47,6 +47,7 @@
     <!-- Networking and telephony -->
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -103,6 +104,7 @@
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
+    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
 
     <!-- Recents -->
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
@@ -173,18 +175,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <activity android:name=".recent.RecentsActivity"
-                android:label="@string/accessibility_desc_recent_apps"
-                android:theme="@style/RecentsStyle"
-                android:excludeFromRecents="true"
-                android:launchMode="singleInstance"
-                android:resumeWhilePausing="true"
-                android:exported="true">
-          <intent-filter>
-            <action android:name="com.android.systemui.TOGGLE_RECENTS" />
-          </intent-filter>
-        </activity>
-
         <receiver
             android:name=".recent.RecentsPreloadReceiver"
             android:exported="false">
diff --git a/packages/SystemUI/res/anim/notification_buttons_in.xml b/packages/SystemUI/res/anim/notification_buttons_in.xml
deleted file mode 100644
index 630fd72..0000000
--- a/packages/SystemUI/res/anim/notification_buttons_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
diff --git a/packages/SystemUI/res/anim/notification_buttons_out.xml b/packages/SystemUI/res/anim/notification_buttons_out.xml
deleted file mode 100644
index 4717e47..0000000
--- a/packages/SystemUI/res/anim/notification_buttons_out.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
diff --git a/packages/SystemUI/res/anim/notification_icons_in.xml b/packages/SystemUI/res/anim/notification_icons_in.xml
deleted file mode 100644
index 630fd72..0000000
--- a/packages/SystemUI/res/anim/notification_icons_in.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
diff --git a/packages/SystemUI/res/anim/notification_icons_out.xml b/packages/SystemUI/res/anim/notification_icons_out.xml
deleted file mode 100644
index 4717e47..0000000
--- a/packages/SystemUI/res/anim/notification_icons_out.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
-        android:duration="@android:integer/config_longAnimTime" 
-        />
-</set>
diff --git a/packages/SystemUI/res/anim/recent_appear.xml b/packages/SystemUI/res/anim/recent_appear.xml
deleted file mode 100644
index 4400d9d..0000000
--- a/packages/SystemUI/res/anim/recent_appear.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:fromAlpha="0.0" android:toAlpha="1.0"
-    android:duration="@android:integer/config_shortAnimTime"
-    />
diff --git a/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png
deleted file mode 100644
index 5bbfa4f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/bottom_divider_glow.png b/packages/SystemUI/res/drawable-hdpi/bottom_divider_glow.png
deleted file mode 100644
index d1948d6..0000000
--- a/packages/SystemUI/res/drawable-hdpi/bottom_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lockscreen_glowdot.png b/packages/SystemUI/res/drawable-hdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index 983c45e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png
deleted file mode 100644
index c100353..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_alarm_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png
deleted file mode 100644
index 1fdaaf9..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_certificate_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png
deleted file mode 100644
index e3b3eeb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png
deleted file mode 100644
index cfa539f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png
deleted file mode 100644
index c3f4729..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_usb_device.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-hdpi/notification_panel_bg.9.png
deleted file mode 100644
index ff0bd4c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
deleted file mode 100644
index d000f7e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png
deleted file mode 100644
index 8b45500..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
deleted file mode 100644
index cbcb3e3..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png
deleted file mode 100644
index 267e7ba..0000000
--- a/packages/SystemUI/res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
deleted file mode 100644
index 8f17b72..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png
deleted file mode 100644
index 2dc2b17..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
deleted file mode 100644
index ece3450..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_tty_mode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png
deleted file mode 100644
index 6feb622..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
deleted file mode 100644
index 42c773d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/top_divider_glow.png b/packages/SystemUI/res/drawable-hdpi/top_divider_glow.png
deleted file mode 100644
index a540efb1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/top_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png
deleted file mode 100644
index 1a58144..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png
deleted file mode 100644
index a12519e..0000000
--- a/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png
deleted file mode 100644
index ce41454..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png
deleted file mode 100644
index b0b4561..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png
deleted file mode 100644
index 54afe32..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png
deleted file mode 100644
index 2495830..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png
deleted file mode 100644
index 0d5b50c..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png
deleted file mode 100644
index 07f16c3..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_default_user.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png
deleted file mode 100644
index 2856e09..0000000
--- a/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/bottom_divider_glow.png b/packages/SystemUI/res/drawable-mdpi/bottom_divider_glow.png
deleted file mode 100644
index ba25f65..0000000
--- a/packages/SystemUI/res/drawable-mdpi/bottom_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lockscreen_glowdot.png b/packages/SystemUI/res/drawable-mdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index 056c3f17..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png
deleted file mode 100644
index 27f08dd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_alarm_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png
deleted file mode 100644
index 3b49472..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_certificate_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png
deleted file mode 100644
index cc81794..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png
deleted file mode 100644
index e6237eb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png
deleted file mode 100644
index 19b95dd..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_usb_device.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-mdpi/notification_panel_bg.9.png
deleted file mode 100644
index 2bbb2c6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
deleted file mode 100644
index f19dc93..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png
deleted file mode 100644
index 4b7de52..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
deleted file mode 100644
index 3ac7c40..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png
deleted file mode 100644
index db51f6b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
deleted file mode 100644
index cb38896..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png
deleted file mode 100644
index ad5b2ff..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
deleted file mode 100644
index b4db0bb..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_tty_mode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png
deleted file mode 100644
index bd1cd12..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
deleted file mode 100644
index 20c8785..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/top_divider_glow.png b/packages/SystemUI/res/drawable-mdpi/top_divider_glow.png
deleted file mode 100644
index 53d85de..0000000
--- a/packages/SystemUI/res/drawable-mdpi/top_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/bugdroid.png b/packages/SystemUI/res/drawable-nodpi/bugdroid.png
deleted file mode 100644
index b90675c..0000000
--- a/packages/SystemUI/res/drawable-nodpi/bugdroid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/notify_item_glow_bottom.png b/packages/SystemUI/res/drawable-nodpi/notify_item_glow_bottom.png
deleted file mode 100644
index e7828c9..0000000
--- a/packages/SystemUI/res/drawable-nodpi/notify_item_glow_bottom.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/notification_panel_bg.9.png
deleted file mode 100644
index e7caeda..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/notification_panel_bg.9.png
deleted file mode 100644
index ae07083..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-tvdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-tvdpi/notification_panel_bg.9.png
deleted file mode 100644
index 727ee49..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-tvdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/notification_panel_bg.9.png
deleted file mode 100644
index 8423ef9..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png
deleted file mode 100644
index 8703e1d..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-tvdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-tvdpi/notification_panel_bg.9.png
deleted file mode 100644
index c3a105c..0000000
--- a/packages/SystemUI/res/drawable-tvdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png
deleted file mode 100644
index 72269f2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/bottom_divider_glow.png b/packages/SystemUI/res/drawable-xhdpi/bottom_divider_glow.png
deleted file mode 100644
index 0b012b4..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/bottom_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lockscreen_glowdot.png b/packages/SystemUI/res/drawable-xhdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index cbd039a..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png
deleted file mode 100644
index 3c0eac1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_alarm_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png
deleted file mode 100644
index b3de2ce..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_certificate_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png
deleted file mode 100644
index 65d15b5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png
deleted file mode 100644
index 208089d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png
deleted file mode 100644
index 86de480..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_usb_device.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/notification_panel_bg.9.png
deleted file mode 100644
index 932e0ef..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
deleted file mode 100644
index 80fc849..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png
deleted file mode 100644
index c57ec67..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
deleted file mode 100644
index 78a69f5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png
deleted file mode 100644
index 8d22ce2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png
deleted file mode 100644
index f0c2f05..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_roaming_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png
deleted file mode 100644
index 75b002d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png
deleted file mode 100644
index 8c48af4..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_tty_mode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png
deleted file mode 100644
index 1fed081..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
deleted file mode 100644
index b4e129c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/top_divider_glow.png b/packages/SystemUI/res/drawable-xhdpi/top_divider_glow.png
deleted file mode 100644
index d4526c0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/top_divider_glow.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png
deleted file mode 100644
index efc9b04..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lockscreen_glowdot.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lockscreen_glowdot.png
deleted file mode 100644
index c0edd91..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_lockscreen_glowdot.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png
deleted file mode 100644
index 1e8509b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_alarm_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png
deleted file mode 100644
index 5d6f6c7..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_certificate_info.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png
deleted file mode 100644
index 1a5d26a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png
deleted file mode 100644
index 452942e..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_settings.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png
deleted file mode 100644
index 99abb6a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_usb_device.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png
deleted file mode 100644
index adcdcb7..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
deleted file mode 100644
index a446448..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png
deleted file mode 100644
index a446448..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
deleted file mode 100644
index 1fa1e62..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png b/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png
deleted file mode 100644
index 29fb50f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png
deleted file mode 100644
index 1c544c4..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_roaming_cdma_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png
deleted file mode 100644
index 99b2fff..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png
deleted file mode 100644
index 075208a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_tty_mode.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png
deleted file mode 100644
index d50ff85..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png
deleted file mode 100644
index 5d27ccd..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_collapse_children.xml b/packages/SystemUI/res/drawable/ic_collapse_children.xml
new file mode 100644
index 0000000..b0ce1e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_collapse_children.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetTop="2dp"
+       android:drawable="@drawable/ic_expand_less"/>
diff --git a/packages/SystemUI/res/drawable/ic_expand_children.xml b/packages/SystemUI/res/drawable/ic_expand_children.xml
new file mode 100644
index 0000000..1762be4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_expand_children.xml
@@ -0,0 +1,18 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetTop="2dp"
+       android:drawable="@drawable/ic_expand_more"/>
diff --git a/packages/SystemUI/res/drawable/ic_expand_less.xml b/packages/SystemUI/res/drawable/ic_expand_less.xml
new file mode 100644
index 0000000..e968013
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_expand_less.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M12.000000,8.000000l-6.000000,6.000000 1.400000,1.400000 4.600000,-4.599999 4.600000,4.599999 1.400000,-1.400000z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_expand_more.xml b/packages/SystemUI/res/drawable/ic_expand_more.xml
new file mode 100644
index 0000000..72e98ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_expand_more.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
new file mode 100644
index 0000000..28d2e26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -0,0 +1,41 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:alpha=".3"
+    android:width="64dp" >
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.8,11.1L17.0,11.1l0.0,2.0l-1.2,0.0l4.5,4.5c1.1,-1.6 1.7,-3.5 1.7,-5.5c0.0,-5.5 -4.5,-10.0 -10.0,-10.0c-2.0,0.0 -3.9,0.6 -5.5,1.7L13.8,11.1z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.0,13.1L7.0,13.1l0.0,-2.0l4.0,0.0L4.9,5.0C3.1,6.8 2.0,9.3 2.0,12.1c0.0,5.5 4.5,10.0 10.0,10.0c2.8,0.0 5.3,-1.1 7.1,-2.9L13.0,13.1z" />
+
+    <group
+        android:pivotX="12.0"
+        android:pivotY="12.0"
+        android:rotation="45.0"
+        android:translateX="0.5"
+        android:translateY="0.5" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M-2.8,11.8l28.3,0.0l0.0,2.0l-28.3,0.0z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
new file mode 100644
index 0000000..7617ec4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64dp"
+        android:height="64dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
deleted file mode 100644
index 689dbf0..0000000
--- a/packages/SystemUI/res/drawable/navbar_search_outerring.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <size android:height="@dimen/navbar_search_outerring_diameter"
-        android:width="@dimen/navbar_search_outerring_diameter" />
-    <solid android:color="#00000000" />
-    <stroke android:color="#40ffffff" android:width="2dp" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/notification_list_shadow.xml b/packages/SystemUI/res/drawable/notification_list_shadow.xml
deleted file mode 100644
index 7f33153..0000000
--- a/packages/SystemUI/res/drawable/notification_list_shadow.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    >
-    <gradient
-        android:angle="90"
-        android:endColor="@color/notification_list_shadow_top"
-        android:startColor="#00000000"
-        android:type="linear"
-        />
-</shape>
diff --git a/packages/SystemUI/res/drawable/notification_scrim.xml b/packages/SystemUI/res/drawable/notification_scrim.xml
deleted file mode 100644
index 53ba213..0000000
--- a/packages/SystemUI/res/drawable/notification_scrim.xml
+++ /dev/null
@@ -1,22 +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
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#08000000" />
-    <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml b/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
deleted file mode 100644
index c209055..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_fg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_selected="true" />
-    <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
-    <item android:drawable="@drawable/recents_thumbnail_no_press"/>
-</selector>
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml b/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml
deleted file mode 100644
index be07b2c..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_no_press.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<color xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="#00000000" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
new file mode 100644
index 0000000..9361bc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+            android:width="17dp"
+            android:height="17dp"
+            android:viewportWidth="48.0"
+            android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
new file mode 100644
index 0000000..36e6cef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+        android:insetLeft="3dp"
+        android:insetRight="3dp">
+    <vector android:width="18dp"
+            android:height="18dp"
+            android:viewportWidth="48.0"
+            android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M23.000000,44.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000l-8.000000,0.000000C19.000000,42.200001 20.799999,44.000000 23.000000,44.000000zM36.000000,21.000000c0.000000,-6.100000 -4.300000,-11.300000 -10.000000,-12.600000L26.000000,7.000000c0.000000,-1.700000 -1.300000,-3.000000 -3.000000,-3.000000c-1.700000,0.000000 -3.000000,1.300000 -3.000000,3.000000l0.000000,1.400000c-1.000000,0.200000 -2.000000,0.600000 -2.900000,1.100000L36.000000,28.400000L36.000000,21.000000zM35.500000,38.000000l4.000000,4.000000l2.500000,-2.500000L8.500000,6.000000L6.000000,8.500000l5.800000,5.800000C10.700000,16.299999 10.000000,18.600000 10.000000,21.000000l0.000000,11.000000l-4.000000,4.000000l0.000000,2.000000L35.500000,38.000000z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_tty_mode.xml b/packages/SystemUI/res/drawable/stat_sys_tty_mode.xml
new file mode 100644
index 0000000..1607185
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_tty_mode.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="21.0dp"
+        android:height="21.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M22.1,4.2L1.9,4.2C1.0,4.2 0.2,5.0 0.2,5.9l0.0,12.1c0.0,1.0 0.8,1.8 1.8,1.8l20.1,0.0c1.0,0.0 1.8,-0.8 1.8,-1.8L23.9,5.9C23.8,5.0 23.0,4.2 22.1,4.2zM8.0,9.3L5.5,9.3L5.5,16.0L3.9,16.0L3.9,9.3L1.5,9.3L1.5,8.1L8.0,8.1L8.0,9.3zM15.3,9.3l-2.5,0.0l0.0,6.6l-1.6,0.0L11.2,9.3L8.7,9.3L8.7,8.1l6.5,0.0L15.2,9.3zM19.7,13.2L19.7,16.0l-1.6,0.0l0.0,-2.8l-2.7,-5.0l1.7,0.0l1.7,3.7l1.7,-3.7l1.7,0.0L19.7,13.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/status_bar_close.xml b/packages/SystemUI/res/drawable/status_bar_close.xml
deleted file mode 100644
index 2efc3c3a..0000000
--- a/packages/SystemUI/res/drawable/status_bar_close.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-         android:drawable="@drawable/status_bar_close_on" />
-    <item
-         android:drawable="@drawable/status_bar_close_off" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/status_bar_recents_background.xml b/packages/SystemUI/res/drawable/status_bar_recents_background.xml
deleted file mode 100644
index ea0b75c..0000000
--- a/packages/SystemUI/res/drawable/status_bar_recents_background.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2011, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <gradient name="status_bar_recents_background"
-        android:startColor="#E0000000"
-        android:endColor="#99000000"
-        android:angle="@integer/status_bar_recents_bg_gradient_degrees"
-        />
-</shape>
diff --git a/packages/SystemUI/res/drawable/status_bar_settings_slider_disabled.xml b/packages/SystemUI/res/drawable/status_bar_settings_slider_disabled.xml
deleted file mode 100644
index 17d48b7..0000000
--- a/packages/SystemUI/res/drawable/status_bar_settings_slider_disabled.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@android:id/background"
-            android:drawable="@*android:drawable/scrubber_track_holo_dark" />
-    <item android:id="@android:id/secondaryProgress">
-        <scale android:scaleWidth="100%"
-                android:drawable="@*android:drawable/scrubber_track_holo_dark" />
-    </item>
-    <item android:id="@android:id/progress">
-        <scale android:scaleWidth="100%"
-                android:drawable="@*android:drawable/scrubber_track_holo_dark" />
-    </item>
-</layer-list>
-
diff --git a/packages/SystemUI/res/drawable/status_bar_toggle_button.xml b/packages/SystemUI/res/drawable/status_bar_toggle_button.xml
deleted file mode 100644
index e17c62f..0000000
--- a/packages/SystemUI/res/drawable/status_bar_toggle_button.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true"
-         android:drawable="@*android:drawable/scrubber_primary_holo" />
-    <item
-         android:drawable="@*android:drawable/scrubber_track_holo_dark" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/system_bar_notification_header_bg.xml b/packages/SystemUI/res/drawable/system_bar_notification_header_bg.xml
deleted file mode 100644
index 85f1ea2..0000000
--- a/packages/SystemUI/res/drawable/system_bar_notification_header_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"  android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
-    <item                               android:drawable="@*android:drawable/list_selector_disabled_holo_dark" />
-</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
deleted file mode 100644
index 1257641..0000000
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="match_parent"
-    android:layout_width="wrap_content"
-    android:paddingStart="@dimen/status_bar_recents_item_padding"
-    android:paddingEnd="@dimen/status_bar_recents_item_padding"
-    android:importantForAccessibility="no"
-    android:clipChildren="false">
-
-    <RelativeLayout android:id="@+id/recent_item"
-        android:layout_gravity="center_vertical"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:paddingTop="@*android:dimen/status_bar_height"
-        android:clipChildren="false"
-        android:clipToPadding="false">
-
-        <FrameLayout android:id="@+id/app_thumbnail"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentStart="true"
-            android:layout_alignParentTop="true"
-            android:layout_marginTop="@dimen/status_bar_recents_thumbnail_top_margin"
-            android:layout_marginStart="@dimen/status_bar_recents_thumbnail_left_margin"
-            android:background="@drawable/recents_thumbnail_bg"
-            android:foreground="@drawable/recents_thumbnail_fg"
-            android:visibility="invisible">
-            <ImageView android:id="@+id/app_thumbnail_image"
-                android:layout_width="@dimen/status_bar_recents_thumbnail_width"
-                android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-            />
-        </FrameLayout>
-
-        <ImageView android:id="@+id/app_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-            android:layout_marginStart="@dimen/status_bar_recents_app_icon_left_margin"
-            android:layout_alignParentStart="true"
-            android:layout_alignParentTop="true"
-            android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
-            android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
-            android:scaleType="centerInside"
-            android:adjustViewBounds="true"
-            android:visibility="invisible"
-        />
-
-        <TextView android:id="@+id/app_label"
-            android:layout_width="@dimen/status_bar_recents_app_label_width"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/status_bar_recents_app_label_text_size"
-            android:fadingEdge="horizontal"
-            android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-            android:scrollHorizontally="true"
-            android:layout_alignStart="@id/app_thumbnail"
-            android:layout_below="@id/app_thumbnail"
-            android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-            android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:textColor="@color/status_bar_recents_app_label_color"
-            android:importantForAccessibility="no"
-        />
-
-        <TextView android:id="@+id/app_description"
-            android:layout_width="@dimen/status_bar_recents_app_label_width"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/status_bar_recents_app_description_text_size"
-            android:fadingEdge="horizontal"
-            android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-            android:scrollHorizontally="true"
-            android:layout_alignStart="@id/app_thumbnail"
-            android:layout_below="@id/app_label"
-            android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-        />
-
-    </RelativeLayout>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
deleted file mode 100644
index b5d2f86..0000000
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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.
-*/
--->
-
-<com.android.systemui.recent.RecentsPanelView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/recents_root"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:foreground="@drawable/bg_protect"
-    systemui:recentItemLayout="@layout/status_bar_recent_item"
-    >
-    <FrameLayout
-        android:id="@+id/recents_bg_protect"
-        android:background="@drawable/status_bar_recents_background"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentBottom="true"
-        android:clipToPadding="false"
-        android:clipChildren="false">
-
-        <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:fadingEdge="horizontal"
-            android:scrollbars="none"
-            android:layout_gravity="right"
-            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length">
-
-            <LinearLayout android:id="@+id/recents_linear_layout"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layoutDirection="ltr"
-                android:layout_gravity="left"
-                android:orientation="horizontal"
-                android:fitsSystemWindows="true">
-            </LinearLayout>
-
-        </com.android.systemui.recent.RecentsHorizontalScrollView>
-
-    </FrameLayout>
-
-    <include layout="@layout/status_bar_no_recent_apps"
-        android:id="@+id/recents_no_apps"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="invisible" />
-
-</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout-sw600dp/carrier_label.xml b/packages/SystemUI/res/layout-sw600dp/carrier_label.xml
deleted file mode 100644
index b33caf8..0000000
--- a/packages/SystemUI/res/layout-sw600dp/carrier_label.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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.
-*/
--->
-
-<Space
-    xmlns:android="http://schemas.android.com/apk/res/android"    
-    android:visibility="gone"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/carrier_label.xml b/packages/SystemUI/res/layout/carrier_label.xml
deleted file mode 100644
index 41a1fff..0000000
--- a/packages/SystemUI/res/layout/carrier_label.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.
-*/
--->
-
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"    
-    android:id="@+id/carrier_label"
-    android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network"
-    android:layout_height="@dimen/carrier_label_height"
-    android:layout_width="match_parent"
-    android:layout_gravity="bottom"
-    android:layout_marginBottom="@dimen/close_handle_height"
-    android:gravity="center"
-    android:visibility="invisible"
-    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 4cf4f52d..01b2713 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -21,7 +21,8 @@
     android:id="@+id/keyguard_bottom_area"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    >
+    android:outlineProvider="none"
+    android:elevation="5dp" > <!-- Put it above the status bar header -->
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
diff --git a/packages/SystemUI/res/layout/notification_children_container.xml b/packages/SystemUI/res/layout/notification_children_container.xml
new file mode 100644
index 0000000..ac6a000
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_children_container.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.systemui.statusbar.stack.NotificationChildrenContainer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml
new file mode 100644
index 0000000..f011afe
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_children_divider.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.systemui.statusbar.AlphaOptimizedView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_more_divider"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_children_divider_height"
+    android:background="@*android:drawable/notification_template_divider" />
diff --git a/packages/SystemUI/res/layout/notification_collapse_button.xml b/packages/SystemUI/res/layout/notification_collapse_button.xml
new file mode 100644
index 0000000..3ec5f63
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_collapse_button.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_bottom_decor_height">
+    <TextView
+        android:id="@+id/notification_expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_bottom_decor_height"
+        android:background="@null"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="center_vertical|center_horizontal"
+        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+        android:text="@string/notification_collapse_button_text"
+        android:drawableEnd="@drawable/ic_collapse_children"
+        android:drawablePadding="1dp"
+        />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_expand_button.xml b/packages/SystemUI/res/layout/notification_expand_button.xml
new file mode 100644
index 0000000..3c478f7
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_expand_button.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_bottom_decor_height">
+    <TextView
+        android:id="@+id/notification_expand_button"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_bottom_decor_height"
+        android:background="@null"
+        android:layout_gravity="top|center_horizontal"
+        android:gravity="center_vertical|center_horizontal"
+        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+        android:text="@string/notification_expand_button_text"
+        android:drawableEnd="@drawable/ic_expand_children"
+        android:drawablePadding="1dp"
+        />
+    <com.android.systemui.statusbar.AlphaOptimizedView
+        android:id="@+id/notification_expand_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_gravity="top|center"
+        android:background="@*android:drawable/notification_template_divider" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_public_default.xml b/packages/SystemUI/res/layout/notification_public_default.xml
index acfc4bb..044ba09 100644
--- a/packages/SystemUI/res/layout/notification_public_default.xml
+++ b/packages/SystemUI/res/layout/notification_public_default.xml
@@ -16,12 +16,9 @@
   -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="64dp"
-    internal:layout_minHeight="64dp"
-    internal:layout_maxHeight="64dp"
     >
     <ImageView android:id="@+id/icon"
         android:layout_width="40dp"
@@ -37,7 +34,7 @@
         android:layout_height="wrap_content"
         android:layout_marginEnd="8dp"
         android:layout_alignParentEnd="true"
-        android:layout_alignBaseline="@id/title"
+        android:layout_alignBaseline="@+id/title"
         android:singleLine="true"
         android:gravity="center"
         android:paddingStart="8dp"
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8f367a6..26523f9 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -15,7 +15,7 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" 
+    android:layout_width="match_parent"
     android:layout_height="match_parent">
     <!-- Status Bar Scrim View -->
     <ImageView
@@ -29,9 +29,16 @@
     <!-- Recents View -->
     <com.android.systemui.recents.views.RecentsView
         android:id="@+id/recents_view"
-        android:layout_width="match_parent" 
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:focusable="true" />
+        android:focusable="true">
+        <!-- MultiStack Debug View -->
+        <ViewStub android:id="@+id/multistack_debug_view_stub"
+               android:layout="@layout/recents_multistack_debug"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="left|bottom" />
+    </com.android.systemui.recents.views.RecentsView>
 
     <!-- Empty View -->
     <ViewStub android:id="@+id/empty_view_stub"
diff --git a/packages/SystemUI/res/layout/recents_dismiss_button.xml b/packages/SystemUI/res/layout/recents_dismiss_button.xml
new file mode 100644
index 0000000..6a2f782
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_dismiss_button.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Extends Framelayout -->
+<com.android.systemui.statusbar.DismissView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/recents_dismiss_all_button_size"
+        android:visibility="gone"
+        android:clipChildren="false"
+        android:clipToPadding="false">
+    <com.android.systemui.statusbar.DismissViewButton
+            android:id="@+id/dismiss_text"
+            android:layout_width="@dimen/recents_dismiss_all_button_size"
+            android:layout_height="@dimen/recents_dismiss_all_button_size"
+            android:layout_gravity="end"
+            android:alpha="1.0"
+            android:background="@drawable/recents_button_bg"
+            android:contentDescription="@string/recents_dismiss_all_message"/>
+</com.android.systemui.statusbar.DismissView>
diff --git a/packages/SystemUI/res/layout/recents_multistack_debug.xml b/packages/SystemUI/res/layout/recents_multistack_debug.xml
new file mode 100644
index 0000000..6524a54
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_multistack_debug.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="left|bottom"
+    android:orientation="vertical">
+    <Button
+        android:id="@+id/add_stack"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:padding="8dp"
+        android:textSize="20sp"
+        android:textColor="#ffffffff"
+        android:text="@string/recents_multistack_add_stack"
+        android:fontFamily="sans-serif"
+        android:background="#000000"
+        android:alpha="0.5" />
+    <Button
+        android:id="@+id/resize_stack"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:padding="8dp"
+        android:textSize="20sp"
+        android:textColor="#ffffffff"
+        android:text="@string/recents_multistack_resize_stack"
+        android:fontFamily="sans-serif"
+        android:background="#000000"
+        android:alpha="0.5" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml b/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
new file mode 100644
index 0000000..36e54a0
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:padding="16dp"
+    android:orientation="vertical"
+    android:descendantFocusability="beforeDescendants"
+    android:focusableInTouchMode="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <EditText
+            android:id="@+id/inset_left"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Left"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_top"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Top"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_right"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Right"
+            android:singleLine="true"
+            android:imeOptions="actionNext"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+        <EditText
+            android:id="@+id/inset_bottom"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:hint="Bottom"
+            android:singleLine="true"
+            android:imeOptions="actionDone"
+            android:inputType="number"
+            android:selectAllOnFocus="true" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index f1d8ad0..53047a3 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -43,6 +43,16 @@
         android:ellipsize="marquee"
         android:fadingEdge="horizontal" />
     <com.android.systemui.recents.views.FixedSizeImageView
+        android:id="@+id/move_task"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginEnd="52dp"
+        android:layout_gravity="center_vertical|end"
+        android:padding="12dp"
+        android:background="@drawable/recents_button_bg"
+        android:src="@drawable/star"
+        android:visibility="gone" />
+    <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/dismiss_task"
         android:layout_width="48dp"
         android:layout_height="48dp"
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
new file mode 100644
index 0000000..8ca5634
--- /dev/null
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<!-- FrameLayout -->
+<com.android.systemui.statusbar.policy.RemoteInputView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:theme="@style/systemui_theme_light"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:paddingStart="4dp"
+        android:paddingEnd="2dp"
+        android:paddingBottom="4dp"
+        android:paddingTop="2dp">
+
+    <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
+            android:id="@+id/remote_input_text"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:singleLine="true"
+            android:imeOptions="actionSend" />
+
+    <ProgressBar
+            android:id="@+id/remote_input_progress"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
+            android:visibility="invisible"
+            android:indeterminate="true"
+            style="?android:attr/progressBarStyleHorizontal" />
+
+</com.android.systemui.statusbar.policy.RemoteInputView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 245c128..3118d08 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -97,12 +97,4 @@
         </com.android.keyguard.AlphaOptimizedLinearLayout>
     </LinearLayout>
 
-    <ViewStub
-        android:id="@+id/ticker_stub"
-        android:inflatedId="@+id/ticker"
-        android:layout="@layout/status_bar_ticker"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-
 </com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 5c41436..f7bbce0 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -28,28 +28,10 @@
     >
 
     <include
-        layout="@layout/carrier_label"
-        android:layout_height="@dimen/carrier_label_height"
-        android:layout_width="match_parent"
-        android:layout_marginBottom="@dimen/close_handle_height"
-        android:layout_gravity="bottom"
-        />
-
-    <include
         layout="@layout/keyguard_status_view"
         android:layout_height="wrap_content"
         android:visibility="gone" />
 
-    <TextView
-        android:id="@+id/emergency_calls_only"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:padding="4dp"
-        android:gravity="center"
-        android:visibility="gone"
-        />
-
     <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index e9d86d6..ea7ce96 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -53,6 +53,22 @@
         />
 
     <ViewStub
+        android:layout="@layout/notification_children_container"
+        android:id="@+id/child_container_stub"
+        android:inflatedId="@+id/notification_children_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+
+    <ViewStub
+        android:layout="@layout/notification_expand_button"
+        android:id="@+id/more_button_stub"
+        android:inflatedId="@+id/notification_more_button_container"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/notification_bottom_decor_height"
+        />
+
+    <ViewStub
         android:layout="@layout/notification_guts"
         android:id="@+id/notification_guts_stub"
         android:inflatedId="@+id/notification_guts"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_item.xml b/packages/SystemUI/res/layout/status_bar_recent_item.xml
deleted file mode 100644
index 6290bb3..0000000
--- a/packages/SystemUI/res/layout/status_bar_recent_item.xml
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:paddingTop="@dimen/status_bar_recents_item_padding"
-    android:paddingBottom="@dimen/status_bar_recents_item_padding"
-    android:clipChildren="false"
-    android:importantForAccessibility="no">
-
-    <RelativeLayout android:id="@+id/recent_item"
-        android:layout_gravity="center_horizontal"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:clipChildren="false">
-
-        <TextView android:id="@+id/app_label"
-            android:layout_width="@dimen/status_bar_recents_app_label_width"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/status_bar_recents_app_label_text_size"
-            android:fadingEdge="horizontal"
-            android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-            android:scrollHorizontally="true"
-            android:layout_alignParentStart="true"
-            android:layout_alignTop="@+id/app_icon"
-            android:paddingTop="2dp"
-            android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:textColor="@color/status_bar_recents_app_label_color"
-            android:importantForAccessibility="no"
-            android:textAlignment="viewStart"
-        />
-        <FrameLayout android:id="@+id/app_thumbnail"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_toEndOf="@id/app_label"
-            android:layout_marginStart="@dimen/status_bar_recents_thumbnail_left_margin"
-            android:background="@drawable/recents_thumbnail_bg"
-            android:foreground="@drawable/recents_thumbnail_fg"
-            android:visibility="invisible">
-            <ImageView android:id="@+id/app_thumbnail_image"
-                android:layout_width="@dimen/status_bar_recents_thumbnail_width"
-                android:layout_height="@dimen/status_bar_recents_thumbnail_height"
-            />
-        </FrameLayout>
-        <View android:id="@+id/recents_callout_line"
-            android:layout_width="@dimen/status_bar_recents_app_label_width"
-            android:layout_height="1dip"
-            android:layout_alignParentStart="true"
-            android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-            android:layout_toStartOf="@id/app_thumbnail"
-            android:layout_below="@id/app_label"
-            android:layout_marginEnd="3dip"
-            android:layout_marginTop="3dip"
-            android:background="@drawable/recents_callout_line"
-        />
-
-        <ImageView android:id="@id/app_icon"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_toEndOf="@id/app_label"
-            android:layout_marginStart="@dimen/status_bar_recents_app_icon_left_margin"
-            android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-            android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
-            android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
-            android:scaleType="centerInside"
-            android:adjustViewBounds="true"
-            android:visibility="invisible"
-        />
-
-        <TextView android:id="@+id/app_description"
-            android:layout_width="@dimen/status_bar_recents_app_label_width"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/status_bar_recents_app_description_text_size"
-            android:fadingEdge="horizontal"
-            android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
-            android:scrollHorizontally="true"
-            android:layout_alignParentStart="true"
-            android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
-            android:layout_below="@id/recents_callout_line"
-            android:layout_marginTop="3dip"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:textAlignment="viewStart"
-        />
-
-    </RelativeLayout>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
deleted file mode 100644
index 588873a..0000000
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** 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.
-*/
--->
-
-<com.android.systemui.recent.RecentsPanelView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/recents_root"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:foreground="@drawable/bg_protect"
-    systemui:recentItemLayout="@layout/status_bar_recent_item"
-    >
-    <FrameLayout
-        android:id="@+id/recents_bg_protect"
-        android:background="@drawable/status_bar_recents_background"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentBottom="true">
-
-        <com.android.systemui.recent.RecentsVerticalScrollView
-            android:id="@+id/recents_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginEnd="0dp"
-            android:divider="@null"
-            android:stackFromBottom="true"
-            android:fadingEdge="vertical"
-            android:scrollbars="none"
-            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
-            android:layout_gravity="bottom|start"
-            android:clipToPadding="false"
-            android:clipChildren="false">
-
-            <LinearLayout android:id="@+id/recents_linear_layout"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:fitsSystemWindows="true"
-                android:clipToPadding="false"
-                android:clipChildren="false">
-            </LinearLayout>
-
-        </com.android.systemui.recent.RecentsVerticalScrollView>
-
-    </FrameLayout>
-
-    <include layout="@layout/status_bar_no_recent_apps"
-        android:id="@+id/recents_no_apps"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="invisible" />
-
-</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar_ticker.xml b/packages/SystemUI/res/layout/status_bar_ticker.xml
deleted file mode 100644
index dd9b3ef..0000000
--- a/packages/SystemUI/res/layout/status_bar_ticker.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  - 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.
-  -->
-<LinearLayout android:id="@+id/ticker"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:paddingStart="6dip"
-    android:animationCache="false"
-    android:orientation="horizontal">
-
-    <ImageSwitcher android:id="@+id/tickerIcon"
-        android:layout_width="@dimen/status_bar_icon_size"
-        android:layout_height="@dimen/status_bar_icon_size"
-        android:layout_marginEnd="4dip"
-        >
-        <com.android.systemui.statusbar.AnimatedImageView
-            android:layout_width="@dimen/status_bar_icon_size"
-            android:layout_height="@dimen/status_bar_icon_size"
-            android:scaleType="center"
-            />
-        <com.android.systemui.statusbar.AnimatedImageView
-            android:layout_width="@dimen/status_bar_icon_size"
-            android:layout_height="@dimen/status_bar_icon_size"
-            android:scaleType="center"
-            />
-    </ImageSwitcher>
-    <com.android.systemui.statusbar.phone.TickerView android:id="@+id/tickerText"
-        android:layout_width="0dip"
-        android:layout_weight="1"
-        android:layout_height="wrap_content"
-        android:paddingTop="2dip"
-        android:paddingEnd="10dip">
-        <TextView
-            android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            />
-        <TextView
-            android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            />
-    </com.android.systemui.statusbar.phone.TickerView>
-</LinearLayout>
-
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 27353ff..33c1899 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,6 +40,16 @@
             android:clipChildren="false" />
     </FrameLayout>
 
+    <View
+        android:id="@+id/zen_embedded_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:visibility="gone"
+        android:layout_marginStart="@dimen/qs_panel_padding"
+        android:layout_marginEnd="@dimen/qs_panel_padding"
+        android:layout_marginBottom="@dimen/qs_panel_padding"
+        android:background="#4dffffff" />
+
     <RelativeLayout
         android:id="@+id/zen_subhead"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/menu/recent_popup_menu.xml b/packages/SystemUI/res/menu/recent_popup_menu.xml
deleted file mode 100644
index eecfb9a..0000000
--- a/packages/SystemUI/res/menu/recent_popup_menu.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/recent_remove_item" android:title="@string/status_bar_recent_remove_item_title" />
-    <item android:id="@+id/recent_inspect_item" android:title="@string/status_bar_recent_inspect_item_title" />
-</menu>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d32539b..1bebed2 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Program Info"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Jou onlangse skerms verskyn hier"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Maak onlangse programme toe"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 skerm in Oorsig"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skerms in Oorsig"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d skerms in Oorsig</item>
+      <item quantity="one">1 skerm in Oorsig</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ontsluit"</string>
     <string name="phone_label" msgid="2320074140205331708">"maak foon oop"</string>
     <string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Maak <xliff:g id="APP">%s</xliff:g> toe."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwerp."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle onlangse programme is toegemaak."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Begin tans <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Kennisgewing is toegemaak."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Kennisgewingskerm."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegtuigmodus aan."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegtuigmodus afgeskakel."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus aangeskakel."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Moenie steur nie aan, net prioriteit."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Moenie steur nie aan, geen onderbrekings nie."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Moenie steur nie af."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Moenie steur nie is afgeskakel."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Moenie steur nie is aangeskakel."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth af."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth aan."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth koppel tans."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiele warmkol aangeskakel."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Uitsaai van skerm gestaak."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skermhelderheid"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G-data is af"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data is af"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Sellulêre data is af"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is af"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Jou toestel het data afgeskakel, want dit het die limiet bereik wat jy gestel het.\n\nAs dit weer aangeskakel word, kan dit tot heffings van jou diensverskaffer af lei."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Skakel data aan"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data is laat wag"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die gestelde dataperk bereik is, het die toestel datagebruik vir die res van hierdie siklus onderbreek.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Soek vir GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sluimer"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Moenie steur nie"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Net prioriteit"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekings nie"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> toestelle)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth af"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Klaar"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Gekoppel"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Gekoppel via Wi-Fi-assistent"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Koppel tans …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"USB-verbinding"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Warmkol"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skermvaspen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Maak alle programme toe"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Dit sal verskyn die volgende keer wanneer jy dit in instellings aanskakel."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Versteek"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil die volumedialoog wees."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Laat toe"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weier"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is die volumedialoog"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Raak om die oorspronklike terug te stel."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 5bc7d59..bb77467 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"የትግበራ መረጃ"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"የቅርብ ጊዜ ማያ ገጾችዎ እዚህ ይታያሉ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"የቅርብ ጊዜ መተግበሪያዎችን ሰርዝ"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ማያ ገጽ በአጠቃላይ እይታ ውስጥ"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ማያ ገጾች በአጠቃላይ እይታ ውስጥ"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d ማያ ገጾች በአጠቃላይ እይታ ውስጥ</item>
+      <item quantity="other">%d ማያ ገጾች በአጠቃላይ እይታ ውስጥ</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ክፈት"</string>
     <string name="phone_label" msgid="2320074140205331708">"ስልክ ክፈት"</string>
     <string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> አስወግድ።"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ተሰናብቷል::"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ሁሉም የቅርብ ጊዜ ማመልከቻዎች ተሰናብተዋል።"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> በመጀመር ላይ።"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ማሳወቂያ ተወግዷል።"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"የማሳወቂያ ጥላ።"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"የአውሮፕላን ሁነታ በርቷል።"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"የአውሮፕላን ሁነታ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"የአውሮፕላን ሁነታ በርቷል።"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"አትረብሽ በርቷል፣ ቅድሚያ የሚሰጠው ብቻ።"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"አትረብሽ በርቷል፣ ምንም ማቋረጦች የሉም።"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"አትረብሽ ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"አትረብሽ ጠፍቷል።"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"አትረብሽ በርቷል።"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ብሉቱዝ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ብሉቱዝ በርቷል።"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ብሉቱዝ በመገናኘት ላይ።"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"የተንቀሳቃሽ ስልክ መገናኛ ነጥብ በርቷል።"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ማያ ገጽ መውሰድ ቆሟል።"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ብሩህነት ያሳዩ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2ጂ-3ጂ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4ጂ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"የተንቀሳቃሽ ስልክ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"መሳሪያዎ እርስዎ ያዘጋጁት ገደብ ላይ ስለደረሰ ውሂብን አጥፍቷል።\n\nመልሰው ማብራት ከአገልግሎት አቅራቢዎ ክፍያዎችን ሊያስከትል ይችላል።"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ውሂብ ያብሩ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2ጂ-3ጂ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"የቀን ህልም"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ኤተርኔት"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"የአውሮፕላን ሁነታ"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"አትረብሽ"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ቅድሚያ የሚሰጠው ብቻ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ምንም ማቋረጦች የሉም"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ብሉቱዝ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ብሉቱዝ (<xliff:g id="NUMBER">%d</xliff:g> መሣሪያዎች)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ብሉቱዝ ጠፍቷል"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ተጨማሪ ቅንብሮች"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ተከናውኗል"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ተገናኝቷል"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"በማገናኘት ላይ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"በማገናኘት ላይ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"መገናኛ ነጥብ"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ማያ ገጽ መሰካት"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ሁሉንም ማመልከቻዎች አሰናብት"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"በቅንብሮች ውስጥ በሚቀጥለው ጊዜ እንዲበራ በሚያደርጉበት ጊዜ ዳግመኛ ብቅ ይላል።"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ደብቅ"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> የድምጽ መጠን መገናኛው መሆን ይፈልጋል።"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ፍቀድ"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ከልክል"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> የድምጽ መጠን መገናኛው ነው"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"የመጀመሪያውን ወደነበረበት ለመመለስ ይንኩ።"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8a23713..3143414 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -25,10 +25,14 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"معلومات التطبيق"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"تظهر شاشاتك المعروضة مؤخرًا هنا"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"إزالة التطبيقات الحديثة"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"شاشة واحدة في النظرة عامة"</item>
-    <item quantity="other" msgid="5523506463832158203">"‏%d من الشاشات في النظرة عامة"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="zero">‏ لا توجد أية شاشات (%d) في النظرة العامة</item>
+      <item quantity="two">‏شاشتان (%d) في النظرة العامة</item>
+      <item quantity="few">‏%d شاشات في النظرة العامة</item>
+      <item quantity="many">‏%d شاشة في النظرة العامة</item>
+      <item quantity="other">‏%d من الشاشات في النظرة العامة</item>
+      <item quantity="one">شاشة واحدة في النظرة العامة</item>
+    </plurals>
     <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>
@@ -88,7 +92,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"إلغاء القفل"</string>
     <string name="phone_label" msgid="2320074140205331708">"فتح الهاتف"</string>
     <string name="camera_label" msgid="7261107956054836961">"فتح الكاميرا"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"تم توصيل البلوتوث."</string>
@@ -143,7 +146,7 @@
     <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"تجوال"</string>
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
-    <string name="accessibility_no_sim" msgid="8274017118472455155">"‏ليست هناك بطاقة SIM."</string>
+    <string name="accessibility_no_sim" msgid="8274017118472455155">"‏ليست هناك شريحة SIM."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ربط البلوتوث."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"وضع الطائرة."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"مستوى البطارية <xliff:g id="NUMBER">%d</xliff:g> في المائة."</string>
@@ -159,6 +162,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"إزالة <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"تمت إزالة <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"تم تجاهل كل التطبيقات المستخدمة مؤخرًا."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"جارٍ بدء <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مركز الإشعارات."</string>
@@ -176,6 +180,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"تشغيل وضع الطائرة."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"تم إيقاف وضع الطائرة."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"تم تشغيل وضع الطائرة."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"تم تشغيل الرجاء عدم الإزعاج، الأولوية فقط."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"تم تشغيل \"الرجاء عدم الإزعاج\"، ممنوع الإزعاج."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"تم تشغيل \"الرجاء عدم الإزعاج\"."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"إيقاف البلوتوث."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"تشغيل البلوتوث."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"جارٍ توصيل البلوتوث."</string>
@@ -200,12 +209,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"تم تشغيل نقطة اتصال الجوّال."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"توقف إرسال الشاشة."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"سطوع الشاشة"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2-3 غيغابايت من البيانات المعطلة"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4 غيغابايت من البيانات المعطلة"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"البيانات الخلوية معطلة"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"البيانات معطلة"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"عطل جهازك البيانات نظرًا لبلوغها الحد الذي تم تعيينه.\n\nعلمًا بأن إعادتها قد يؤدي إلى تحمل رسوم من قبل مشغّل شبكة الجوّال."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"تشغيل البيانات"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"بيانات شبكات الجيل الثاني والثالث متوقفة مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏جارٍ البحث عن GPS"</string>
@@ -224,6 +233,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"حلم اليقظة"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"وضع الطائرة"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"الرجاء عدم الإزعاج"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"الأولوية فقط"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"عدم الإزعاج"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث (<xliff:g id="NUMBER">%d</xliff:g> من الأجهزة)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"إيقاف البلوتوث"</string>
@@ -261,7 +273,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"المزيد من الإعدادات"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"تم"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"جارٍ الاتصال..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"النطاق"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطة اتصال"</string>
@@ -279,6 +290,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"تثبيت الشاشة"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"تجاهل كل التطبيقات"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</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>
@@ -362,4 +380,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"سيظهر مرة أخرى عند تمكينه في الإعدادات المرة التالية."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"إخفاء"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"يريد <xliff:g id="APP_NAME">%1$s</xliff:g> أن يكون مربع حوار مستوى الصوت."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"سماح"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"رفض"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> هو مربع حوار مستوى الصوت"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"المس لاستعادة الإعداد الأصلي."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 120a49b..68da9ea 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Информация за приложението"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Скорошните ви екрани се показват тук"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Отхвърляне на скорошните приложения"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 екран в панела за общ преглед"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d екрана в панела за общ преглед"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d екрана в панела за общ преглед</item>
+      <item quantity="one">1 екран в панела за общ преглед</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"отключване"</string>
     <string name="phone_label" msgid="2320074140205331708">"отваряне на телефона"</string>
     <string name="camera_label" msgid="7261107956054836961">"отваряне на камерата"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е включен."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отхвърляне на <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложението <xliff:g id="APP">%s</xliff:g> е отхвърлено."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Всички скорошни приложения са отхвърлени."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> се стартира."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Падащ панел с известия."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Самолетният режим е включен."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Самолетният режим се изключи."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Самолетният режим се включи."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Настройката „Не безпокойте“ е включена – само с приоритет."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Настройката „Не безпокойте“ е включена – без прекъсвания."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Настройката „Не безпокойте“ е изключена."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Настройката „Не безпокойте“ е изключена."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Настройката „Не безпокойте“ е включена."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Функцията за Bluetooth е изключена."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Функцията за Bluetooth е включена."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Установява се връзка през Bluetooth."</string>
@@ -190,22 +195,22 @@
     <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Затваряне на панела."</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
-    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Светкавицата е изключена."</string>
-    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Светкавицата е включена."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Светкавицата се изключи."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Светкавицата се включи."</string>
+    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
+    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Функцията за инвертиране на цветовете се изключи."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Функцията за инвертиране на цветовете се включи."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Мобилната точка за достъп се изключи."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка за достъп се включи."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Предаването на съдържанието от екрана спря."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркост на екрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Данните от 2G – 3G са изключени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Данните от 4G са изключени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилните данни са изключени"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Данните са изключени"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Устройството ви изключи данните, защото зададеното от вас ограничение бе достигнато.\n\nПовторното им включване може да доведе до таксуване от оператора ви."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Включване на данните"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Данните от 2G – 3G са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Мечта"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Самолетен режим"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не безпокойте"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само с приоритет"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекъсвания"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> устройства)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth е изключен"</string>
@@ -261,12 +269,11 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Още настройки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Установена е връзка"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Установена е връзка чрез помощника за Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Установява се връзка..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетъринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка за достъп"</string>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Известия"</string>
-    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Светкавица"</string>
+    <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Фенерче"</string>
     <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Мобилни данни"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Пренос на данни"</string>
     <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Оставащи данни"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"фиксиране на екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Отхвърляне на всички приложения"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Бързите настройки ще се покажат отново следващия път, когато ги включите от „Настройки“."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Скриване"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска да изпълнява ролята на диалоговия прозорец за силата на звука."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Разрешаване"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Отказване"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> изпълнява ролята на диалоговия прозорец за силата на звука"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Докоснете, за да възстановите оригинала."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index cfc6b3e..049552c 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"অ্যাপ্লিকেশানের তথ্য"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"আপনার সাম্প্রতিক স্ক্রীনগুলো এখানে দেখা যাবে"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"সাম্প্রতিক অ্যাপ্লিকেশানগুলি খারিজ করুন"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"এক নজরে-এ ১টি স্ক্রীন"</item>
-    <item quantity="other" msgid="5523506463832158203">"এক নজরে-এ %dটি স্ক্রীন"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">ওভারভিউ-এ %dটি স্ক্রীন</item>
+      <item quantity="other">ওভারভিউ-এ %dটি স্ক্রীন</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"আনলক করুন"</string>
     <string name="phone_label" msgid="2320074140205331708">"ফোন খুলুন"</string>
     <string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth সংযুক্ত হয়েছে৷"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> খারিজ করুন।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> খারিজ করা হয়েছে৷"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"সমস্ত সাম্প্রতিক অ্যাপ্লিকেশন খারিজ করা হয়েছে।"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> তারাঙ্কিত করা হচ্ছে।"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"বিজ্ঞপ্তি শেড৷"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"বিমান মোড চালু আছে।"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"বিমান মোড বন্ধ হয়েছে।"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"বিমান মোড চালু হয়েছে।"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"“বিরক্ত করবেন না” চালু করবেন, শুধুমাত্র অগ্রাধিকার৷"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"“বিরক্ত করবেন না” চালু করবেন, কোন বাধা নয়"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"“বিরক্ত করবেন না” বন্ধ৷"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"বিরক্ত করবেন না বন্ধ রয়েছে৷"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"বিরক্ত করবেন না চালু রয়েছে৷"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth বন্ধ আছে।"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth চালু আছে।"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth সংযুক্ত হচ্ছে।"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"মোবাইল হটস্পট চালু হয়েছে।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"স্ক্রীন কাস্ট করা থেমেছে।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"প্রদর্শনের উজ্জ্বলতা"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"সেলুলার ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"আপনার সেট করা ডেটা সীমায় পৌঁছে যাওয়ায় আপনার ডিভাইসটি ডেটা বন্ধ করে দিয়েছে।\n\nএটি চালু করে দিলে আপনাকে পরিষেবা প্রদানকারীর করা চার্জ বহন করতে হতে পারে।"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ডেটা চালু করুন"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi সংযুক্ত হয়েছে"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS এর জন্য অনুসন্ধান করা হচ্ছে"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"স্ক্রিনসেভার"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ইথারনেট"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"বিমান মোড"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"বিরক্ত করবেন না"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"শুধুমাত্র অগ্রাধিকার"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"কোনো বাধা নয়"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> টি ডিভাইস)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth বন্ধ"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"আরো সেটিংস"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"সম্পন্ন হয়েছে"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"সংযুক্ত হয়েছে"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"সংযুক্ত হচ্ছে..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"টেদারিং"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"হটস্পট"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"স্ক্রীন পিন করা"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"সমস্ত অ্যাপ্লিকেশন খারিজ করুন"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"আপনি পরের বার সেটিংস-এ এটি চালু করলে এটি উপস্থিত হবে"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"লুকান"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ভলিউম ডায়লগ হতে চায়৷"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"মঞ্জুরি দিন"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"প্রত্যাখ্যান করুন"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> হল ভলিউম ডায়লগ"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"আসলটি পুনঃস্থাপন করতে স্পর্শ করুন৷"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0236dfe..c2af030 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informació de l\'aplicació"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Aquí es mostren les teves pantalles recents."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Omet les aplicacions recents"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 pantalla a Visió general"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d pantalles a Visió general"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d pantalles en la visió general</item>
+      <item quantity="one">1 pantalla en la visió general</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloqueja"</string>
     <string name="phone_label" msgid="2320074140205331708">"obre el telèfon"</string>
     <string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descarta <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"S\'ha omès <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"S\'han descartat totes les aplicacions recents."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"S\'està iniciant <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificació omesa."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Àrea de notificacions"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"El Mode d\'avió està activat."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"S\'ha desactivat el Mode d\'avió."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"S\'ha activat el Mode d\'avió."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"El mode No molesteu està activat (només amb prioritat)."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"El mode No molesteu està activat (cap interrupció)."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"El mode No molesteu està desactivat."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"S\'ha desactivat el mode No molesteu."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"S\'ha activat el mode No molesteu."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"El Bluetooth està desactivat."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"El Bluetooth està activat."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"S\'està connectant el Bluetooth."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"El punt d\'accés mòbil està activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"S\'ha aturat l\'emissió de la pantalla."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillantor de la pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"L\'ús de dades 2G-3G està desactivat"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"L\'ús de dades 4G està desactivat"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Les dades mòbils estan desactivades"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Les dades estan desactivades"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"S\'han desactivat les dades del dispositiu perquè ha arribat al límit que has definit.\n\nSi les tornes a activar, l\'operador de telefonia mòbil et pot aplicar càrrecs."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activa les dades"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Les dades 2G-3G estan aturades"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Estalvi de pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode d\'avió"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molesteu"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Només amb prioritat"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Cap interrupció"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositius)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivat"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Més opcions"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fet"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connectat"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"S\'està connectant..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ancoratge a xarxa"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixació de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Descarta totes les aplicacions"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tornarà a mostrar-se la propera vegada que l\'activis a la configuració."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Amaga"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> vol passar a ser el diàleg del volum."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permet"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denega"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 791ae1b..f4ff102 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informace o aplikaci"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Zde budou zobrazeny vaše poslední obrazovky"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Zavřít nové aplikace"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 obrazovka v Přehledu"</item>
-    <item quantity="other" msgid="5523506463832158203">"Počet obrazovek v Přehledu: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="few">%d obrazovky v Přehledu</item>
+      <item quantity="many">%d obrazovky v Přehledu</item>
+      <item quantity="other">%d obrazovek v Přehledu</item>
+      <item quantity="one">1 obrazovka v Přehledu</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odemknout"</string>
     <string name="phone_label" msgid="2320074140205331708">"otevřít telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
@@ -161,6 +162,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zavřít aplikaci <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikace <xliff:g id="APP">%s</xliff:g> byla odebrána."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všechny naposledy použité aplikace byly odstraněny."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spouštění aplikace <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel oznámení."</string>
@@ -178,6 +180,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Režim Letadlo je zapnutý."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Režim Letadlo je vypnutý."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Režim Letadlo je zapnutý."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stav Nerušit je zapnutý – pouze prioritní vyrušení."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stav Nerušit je zapnutý – žádná vyrušení."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stav Nerušit je vypnutý."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stav Nerušit je vypnutý"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stav Nerušit je zapnutý."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Rozhraní Bluetooth je vypnuto."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Rozhraní Bluetooth je zapnuto."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Probíhá připojování rozhraní Bluetooth."</string>
@@ -202,12 +209,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Odesílání obrazovky zastaveno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeje"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G a 3G jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilní data jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Zařízení datové přenosy vypnulo, protože dosáhlo limitu, který jste nastavili.\n\nJejich opětovné zapnutí může vézt k účtování poplatků operátorem."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Zapnout data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G a 3G jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhledávání satelitů GPS"</string>
@@ -226,6 +233,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Spořič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim Letadlo"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nerušit"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Pouze prioritní"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Žádná vyrušení"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> zařízení)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhraní Bluetooth je vypnuto"</string>
@@ -263,7 +273,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Další nastavení"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Připojeno"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Připojování..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Sdílení datového připojení"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -281,6 +290,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"připnutí obrazovky"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odstranit všechny aplikace"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</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>
@@ -364,4 +380,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tato položka se znovu zobrazí, až ji v nastavení znovu zapnete."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skrýt"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> chce být dialogem hlasitosti."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Povolit"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmítnout"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialog hlasitosti"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5be774e..a565263 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Oplysninger om appen"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Dine seneste skærme vises her"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Luk de seneste apps"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Ét skærmbillede i Oversigt"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skærmbilleder i Oversigt"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d skærmbilleder i Oversigt</item>
+      <item quantity="other">%d skærmbilleder i Oversigt</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås op"</string>
     <string name="phone_label" msgid="2320074140205331708">"åbn telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Afvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> er annulleret."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle de seneste applikationer er lukket."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> startes."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Underretningspanel."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flytilstand er slået til."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flytilstand er slået fra."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flytilstand er slået til."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Vil ikke forstyrres\" er slået til, kun prioritet."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Vil ikke forstyrres\" er slået til, ingen afbrydelser."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Vil ikke forstyrres\" er slået fra."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Vil ikke forstyrres\" er slået fra."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Vil ikke forstyrres\" er slået til."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth er slået fra."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth er slået til."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Opretter forbindelse til Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casting af din skærm er stoppet."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skærmens lysstyrke"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G-data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildata er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Enheden har deaktiveret data, fordi den grænse, du har angivet, er nået.\n\nHvis du aktiverer dataforbrug igen, kan mobilselskabet pålægge gebyrer."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktivér data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Vil ikke forstyrres"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ingen afbrydelser"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth slået fra"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Udført"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Forbindelse via Wi-Fi-assistent"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"bliv i app"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Luk alle applikationer"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igen, næste gang du aktiverer den i indstillingerne."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ønsker at være dialogboksen for lydstyrke."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Tillad"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afvis"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er dialogboksen for lydstyrke"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryk for at gendanne originalen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4bc932b..4f9ea15 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-Info"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Hier sehen Sie Ihre zuletzt geöffneten Apps."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Kürzlich geöffnete Apps schließen"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 Bildschirm in der Übersicht"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d Bildschirme in der Übersicht"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d Bildschirme in der Übersicht</item>
+      <item quantity="one">1 Bildschirm in der Übersicht</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"Entsperren"</string>
     <string name="phone_label" msgid="2320074140205331708">"Telefon öffnen"</string>
     <string name="camera_label" msgid="7261107956054836961">"Kamera öffnen"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Mit Bluetooth verbunden"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> beenden"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> entfernt"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle kürzlich verwendeten Apps wurden entfernt."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> wird gestartet."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Benachrichtigungsleiste"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flugmodus aktiviert"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Der Flugmodus ist deaktiviert."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Der Flugmodus ist aktiviert."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Nicht stören\" an, nur wichtige Unterbrechungen"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Nicht stören\" an, keine Unterbrechungen"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Nicht stören\" aus"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Nicht stören\" deaktiviert"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Nicht stören\" aktiviert"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth deaktiviert"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth aktiviert"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Verbindung mit Bluetooth wird hergestellt."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Der mobile Hotspot ist aktiviert."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Die Bildschirmübertragung wurde angehalten."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helligkeit des Displays"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Datennutzung wurde auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Funktion erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Daten aktivieren"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-/3G-Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da Ihr festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn Sie diese fortsetzen, können möglicherweise Kosten bei Ihrem Mobilfunkanbieter entstehen."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugmodus"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nicht stören"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Nur wichtige Unterbrechungen"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Keine Unterbrechungen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fertig"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Verbunden"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Über WLAN-Assistenten verbunden"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Verbindung wird hergestellt…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Bildschirmfixierung"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Alle Apps entfernen"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Sie wird wieder eingeblendet, wenn Sie sie in den Einstellungen erneut aktivieren."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ausblenden"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> will die Lautstärke regeln."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Zulassen"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ablehnen"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Zum Wiederherstellen des Originals hier tippen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index e131037..f9e83ce 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Πληροφορίες εφαρμογής"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Οι πρόσφατες οθόνες σας εμφανίζονται εδώ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Παράβλεψη πρόσφατων εφαρμογών"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 οθόνη στην Επισκόπηση"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d οθόνες στην Επισκόπηση"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d οθόνες στην Επισκόπηση</item>
+      <item quantity="one">1 οθόνη στην Επισκόπηση</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ξεκλείδωμα"</string>
     <string name="phone_label" msgid="2320074140205331708">"άνοιγμα τηλεφώνου"</string>
     <string name="camera_label" msgid="7261107956054836961">"άνοιγμα φωτογραφικής μηχανής"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Το Bluetooth είναι συνδεδεμένο."</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Παράβλεψη <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Απορρίφθηκαν <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Έγινε παράβλεψη όλων των πρόσφατων εφαρμογών."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Έναρξη <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Η ειδοποίηση έχει απορριφθεί."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ενεργή λειτουργία πτήσης."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Η λειτουργία πτήσης απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ενεργή λειτουργία πτήσης."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε, μόνο προτεραιότητας."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε, χωρίς διακοπές."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Η λειτουργία \"Μην ενοχλείτε\" απενεργοποιήθηκε."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Η λειτουργία \"Μην ενοχλείτε\" απενεργοποιήθηκε."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Ανενεργό Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Ενεργό Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Σύνδεση Bluetooth."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Το σημείο πρόσβασης κινητής συσκευής ενεργοποιήθηκε."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Η μετάδοση της οθόνης διακόπηκε."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Φωτεινότητα οθόνης"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Τα δεδομένα 2G-3G είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Τα δεδομένα 4G είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Τα δεδομένα κινητής τηλεφωνίας είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Τα δεδομένα είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Τα δεδομένα απενεργοποιήθηκαν στη συσκευή σας, επειδή εξαντλήσατε το όριο που ορίσατε.\n\nΗ επανενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ενεργοποίηση δεδομένων"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Τα δεδομένα 2G-3G τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Λειτουργία πτήσης"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Μην ενοχλείτε"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Μόνο προτεραιότητας"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Χωρίς διακοπές"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> συσκευές)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Απενεργοποιημένο Bluetooth"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Τέλος"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Συνδέθηκε"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Σύνδεση…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Πρόσδεση"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Σημείο πρόσβασης Wi-Fi"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Παράβλεψη όλων των εφαρμογών"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Απόκρυψη <xliff:g id="TILE_LABEL">%1$s</xliff:g>;"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Θα εμφανιστεί ξανά την επόμενη φορά που θα το ενεργοποιήσετε στις ρυθμίσεις."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Απόκρυψη"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θέλει να γίνει το παράθυρο διαλόγου ελέγχου έντασης"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Να επιτραπεί"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Απόρριψη"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> αποτελεί το παράθυρο διαλόγου ελέγχου έντασης"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Αγγίξτε για επαναφορά αρχικού."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f61724d..7edf0b9 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App info"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Your recent screens appear here"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Dismiss recent apps"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 screen in Overview"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d screens in Overview"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d screens in Overview</item>
+      <item quantity="one">1 screen in Overview</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"open phone"</string>
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Aeroplane mode on."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Aeroplane mode turned off."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Aeroplane mode turned on."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'Do not disturb\' on, priority only."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'Do not disturb\' on, no interruptions."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'Do not disturb\' off."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'Do not disturb\' turned off."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'Do not disturb\' turned on."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth off."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth on."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth connecting."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot turned on."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Screen casting stopped."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G data is off"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G data is off"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobile data is off"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is off"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Your device turned off data because it reached the limit you set.\n\nTurning it back on may lead to charges from your operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Turn on data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"No interruptions"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connected via Wi‑Fi assistant"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dismiss all applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wants to be the volume dialogue."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Allow"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Deny"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is the volume dialogue"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Touch to restore the original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f61724d..7edf0b9 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App info"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Your recent screens appear here"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Dismiss recent apps"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 screen in Overview"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d screens in Overview"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d screens in Overview</item>
+      <item quantity="one">1 screen in Overview</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"open phone"</string>
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Dismiss <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> dismissed."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification dismissed."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Aeroplane mode on."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Aeroplane mode turned off."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Aeroplane mode turned on."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'Do not disturb\' on, priority only."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'Do not disturb\' on, no interruptions."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'Do not disturb\' off."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'Do not disturb\' turned off."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'Do not disturb\' turned on."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth off."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth on."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth connecting."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot turned on."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Screen casting stopped."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G data is off"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G data is off"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobile data is off"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is off"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Your device turned off data because it reached the limit you set.\n\nTurning it back on may lead to charges from your operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Turn on data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"No interruptions"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connected via Wi‑Fi assistant"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"screen pinning"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dismiss all applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wants to be the volume dialogue."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Allow"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Deny"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is the volume dialogue"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Touch to restore the original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c70c8e8..c8753ea 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Las pantallas recientes aparecen aquí."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Rechazar aplicaciones recientes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 pantalla en Recientes"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d pantallas en Recientes"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d pantallas en Recientes</item>
+      <item quantity="one">1 pantalla en Recientes</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rechazar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartada."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se descartaron todas las aplicaciones recientes."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pantalla de notificaciones"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modo de avión: activado"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modo de avión desactivado"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo de avión activado"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"No molestar activado (solo prioridad)"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"No molestar activado (sin interrupciones)"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"No molestar desactivado"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"No molestar desactivado"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"No molestar activado"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desactivado"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activado"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth conectándose"</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona móvil activada"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisión de pantalla detenida"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datos 2G-3G desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datos 4G desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datos móviles desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datos desactivados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"El dispositivo desactivó los datos porque alcanzó el límite establecido.\n\nSi los vuelves a activar, podrían aplicarse cargos del proveedor."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Activar protector"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molestar"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo prioridad"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sin interrupciones"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más configuraciones"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conexión por asistente de Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Descartar todas las aplicaciones"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá a aparecer la próxima vez que se active en la configuración."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> quiere ser el cuadro de diálogo de volumen."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar el original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4a05367..ea77484 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información de la aplicación"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Aquí aparecerán tus pantallas recientes"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ignorar aplicaciones recientes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 pantalla en Visión general"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d pantallas en Visión general"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d pantallas en Visión general</item>
+      <item quantity="one">1 pantalla en Visión general</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Se ha eliminado <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Se han ignorado todas las aplicaciones recientes."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pantalla de notificaciones"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modo avión activado."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modo avión desactivado."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo avión activado."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"No molestar activado (solo prioritarias)."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"No molestar activado (sin interrupciones)."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"No molestar desactivado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"No molestar desactivado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"No molestar activado."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desactivado."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activado."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Conectando Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Punto de acceso móvil activado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Envío de pantalla detenido."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datos 2G-3G desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datos 4G desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datos móviles desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Conexión de datos desactivada"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Se ha desactivado la conexión de datos del dispositivo porque se ha alcanzado el límite establecido.\n\nSi se vuelve a activar, se podrían aplicar cargos del operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar conexión de datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Salvapantallas"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molestar"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo prioritarias"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sin interrupciones"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Más opciones"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado a través de asistente Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ignorar todas las aplicaciones"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá a aparecer la próxima vez que actives esta opción en Ajustes."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> quiere ser el cuadro de diálogo de volumen."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar la versión original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index fc5b18c..07db861 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Rakenduse teave"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Teie viimane ekraanikuva ilmub siia"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Loobu hiljutistest rakendustest"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ekraan jaotises Ülevaade"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ekraanikuva jaotises Ülevaade"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d ekraani jaotises Ülevaade</item>
+      <item quantity="one">1 ekraan jaotises Ülevaade</item>
+    </plurals>
     <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">"Märguanded"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ava lukk"</string>
     <string name="phone_label" msgid="2320074140205331708">"ava telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"ava kaamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth on ühendatud."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rakendusest <xliff:g id="APP">%s</xliff:g> loobumine."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Loobusite rakendusest <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kõikidest hiljutistest rakendustest on loobutud"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Rakenduse <xliff:g id="APP">%s</xliff:g> käivitamine."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Märguandest on loobutud."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Märguande vari."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Lennukirežiim on sees."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Lennukirežiim on välja lülitatud."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lennukirežiim on sisse lülitatud."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Funktsioon Mitte segada on sisse lülitatud (ainult prioriteetsed)."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Funktsioon Mitte segada on sisse lülitatud (mitte ühtegi katkestust)."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Funktsioon Mitte segada on välja lülitatud."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Funktsioon Mitte segada on välja lülitatud."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Funktsioon Mitte segada on sisse lülitatud."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth on väljas."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth on sees."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetoothi ühendatakse."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiilside leviala on sisse lülitatud."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekraanikuva ülekandmine on peatatud."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekraani heledus"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mob. andmeside väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Seade lülitas andmeside välja, sest teie määratud limiit on täis.\n\nKui lülitate andmeside uuesti sisse, siis võivad lisanduda operaatori tasud."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Lülita andmeside sisse"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Unistus"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lennurežiim"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Mitte segada"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Ainult prioriteetsed"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Mitte ühtegi katkestust"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> seadet)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth on väljas"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Rohkem seadeid"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ühendatud"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ühendatud WiFi-abi kaudu"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ühenduse loomine ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jagamine"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Leviala"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekraanikuva kinnitamine"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Loobu kõikidest rakendustest"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"See kuvatakse uuesti järgmisel korral, kui selle seadetes sisse lülitate."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Peida"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> tahab olla helitugevuse dialoog."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Luba"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Keela"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on helitugevuse dialoog"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Originaali taastamiseks puudutage."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d284b470..317056c 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Aplikazioaren informazioa"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ikusitako azken pantailak erakusten dira hemen"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Baztertu azken aplikazioak"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Pantaila bat dago ikuspegi orokorrean"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d pantaila daude ikuspegi orokorrean"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d pantaila daude ikuspegi orokorrean</item>
+      <item quantity="one">Pantaila bat dago ikuspegi orokorrean</item>
+    </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ez dago jakinarazpenik"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Abian"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Jakinarazpenak"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desblokeatu"</string>
     <string name="phone_label" msgid="2320074140205331708">"ireki telefonoan"</string>
     <string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Baztertu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> baztertu da."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Azken aplikazio guztiak baztertu da."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> hasten."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Jakinarazpena baztertu da."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Jakinarazpenen panela."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Hegaldi modua aktibatuta dago."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Hegaldi modua desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Hegaldi modua aktibatu egin da."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Ez molestatu\" aukera aktibatuta dago, lehentasunezkoak soilik."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Ez molestatu\" aukera aktibatuta dago, etenaldirik gabe."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Ez molestatu\" aukera desaktibatuta dago."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Ez molestatu\" aukera desaktibatuta dago."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Ez molestatu\" aukera aktibatuta dago."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth konexioa desaktibatuta dago."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth konexioa aktibatuta dago."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth bidez konektatzen ari da."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Konexioa partekatzeko aukera aktibatu egin da."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Pantaila igortzeari utzi zaio."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bistaratu distira"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datu mugikorrak desaktibatuta daude"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Gailuak datu-konexioa desaktibatu du, ezarritako mugara iritsi delako.\n\nBerriro aktibatuz gero, operadoreak zerbait kobratuko dizu agian."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktibatu datu-konexioa"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS seinalearen bila"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Pantaila-babeslea"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hegaldi modua"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ez molestatu"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Lehentasunezkoak soilik"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Etenaldirik gabe"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetootha desaktibatuta"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Ezarpen gehiago"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Eginda"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Konektatuta"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Baztertu aplikazio guztiak"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ezarpenetan aktibatzen duzun hurrengoan agertuko da berriro."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ezkutatu"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> bolumenaren leihoa izan nahian ari da."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Baimendu"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ukatu"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> da bolumenaren leihoa"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Ukitu jatorrizkora leheneratzeko"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 37aab03..0806a01 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"اطلاعات برنامه"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"صفحه‌های اخیر شما اینجا نمایان می‌شوند"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"رد کردن برنامه‌های اخیر"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"۱ صفحه در نمای کلی"</item>
-    <item quantity="other" msgid="5523506463832158203">"‏%d صفحه در نمای کلی"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">‏%d صفحه در نمای کلی</item>
+      <item quantity="other">‏%d صفحه در نمای کلی</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"بازکردن قفل"</string>
     <string name="phone_label" msgid="2320074140205331708">"باز کردن تلفن"</string>
     <string name="camera_label" msgid="7261107956054836961">"باز کردن دوربین"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحه‌های کوچک تا بزرگ."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوتوث متصل است."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"رد کردن <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> نادیده گرفته شد."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"همه برنامه‌های اخیر رد شدند."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> در حال شروع به کار است."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مجموعه اعلان."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"حالت هواپیما روشن است."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"حالت هواپیما خاموش شد."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"حالت هواپیما روشن شد."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"«مزاحم نشوید» روشن است، فقط اولویت‌دار."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"«مزاحم نشوید» روشن است، وقفه ایجاد نشود."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"«مزاحم نشوید» خاموش است."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"«مزاحم نشوید» خاموش شد."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"«مزاحم نشوید» روشن شد."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"بلوتوث خاموش است."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"بلوتوث روشن است."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"بلوتوث در حال اتصال است."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"نقطه اتصال دستگاه همراه روشن شد."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"فرستادن صفحه نمایش متوقف شد."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"روشنایی نمایشگر"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏داده 2G-3G خاموش است"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏داده 4G خاموش است"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"داده شبکه سلولی خاموش است"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"داده خاموش است"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"دستگاه شما خاموش شد زیرا به حد تنظیم شده توسط شما رسید.\n\nروشن کردن مجدد آن می‌تواند به هزینه‌هایی از طرف شرکت مخابراتی شما منجر شود."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"روشن کردن داده"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏داده 2G-3G موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی وجود ندارد"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏جستجو برای GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"رویاپردازی"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"اترنت"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"حالت هواپیما"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"مزاحم نشوید"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"فقط اولویت‌دار"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"وقفه ایجاد نشود"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث ( <xliff:g id="NUMBER">%d</xliff:g> دستگاه)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوتوث خاموش"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"انجام شد"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏متصل شده از طریق دستیار Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"در حال اتصال..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"نقطه اتصال"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"پین کردن صفحه"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"رد کردن همه برنامه‌ها"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> مخفی شود؟"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"دفعه بعد که آن را روشن کنید، در تنظیمات نشان داده می‌شود."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"پنهان کردن"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> می‌خواهد کنترل‌کننده صدا باشد."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"مجاز"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"رد کردن"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> کنترل‌کننده صدا است"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"برای بازیابی کنترل‌کننده اصلی، لمس کنید."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index fb8b0d78..4f8a315 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Sovelluksen tiedot"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Äskettäin käytetyt ruudut näkyvät tässä"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Hylkää viimeaikaiset sovellukset"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 näyttö Viimeisimmät-kohdassa"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d näyttöä Viimeisimmät-kohdassa"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d näyttöä Yleistä-kohdassa</item>
+      <item quantity="one">1 näyttö Yleistä-kohdassa</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"avaa lukitus"</string>
     <string name="phone_label" msgid="2320074140205331708">"avaa puhelin"</string>
     <string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hylätään <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> hylättiin."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Kaikki viimeisimmät sovellukset on hylätty."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Käynnistetään <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ilmoitusalue."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Lentokonetila on päällä."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Lentokonetila poistettiin käytöstä."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lentokonetila otettiin käyttöön."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Älä häiritse -tila on päällä, vain tärkeät."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Älä häiritse -tila on päällä, ei keskeytyksiä."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Älä häiritse -tila on pois päältä."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Älä häiritse -tila on pois päältä."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Älä häiritse -tila on päällä."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth on pois päältä."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth on päällä."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetoothia yhdistetään."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiiliyhteyden hotspot otettiin käyttöön."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ruudun lähetys pysäytettiin."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Näytön kirkkaus"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G-tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiilitiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Laitteesi poisti tiedonsiirron käytöstä, koska se saavutti asettamasi rajan.\n\nOperaattorisi saattaa veloittaa sinulta lisämaksuja, jos otat sen uudelleen käyttöön."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ota tiedonsiirto käyttöön"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G-tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Haetaan GPS-yhteyttä"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Unelmat"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lentokonetila"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Älä häiritse"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Vain tärkeät"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ei häiriöitä"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> laitetta)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth pois käytöstä"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lisäasetukset"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Yhdistetty"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Yhdistetään…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"näytön kiinnitys"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Hylkää kaikki sovellukset"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Se tulee takaisin näkyviin, kun seuraavan kerran otat sen käyttöön asetuksissa."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Piilota"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> haluaa olla äänenvoimakkuusvalinta."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Salli"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Estä"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on äänenvoimakkuusvalinta."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Palauta alkuperäinen koskettamalla."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 10b6a2d..8c03ea8 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informations sur l\'application"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Vos écrans récents s\'affichent ici"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Masquer les applications récentes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 écran dans Aperçu"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d écrans dans Aperçu"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">Aperçu de %d écran</item>
+      <item quantity="other">Aperçu de %d écrans</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
     <string name="phone_label" msgid="2320074140205331708">"Ouvrir le téléphone"</string>
     <string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Mode Avion : activé"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Le mode Avion est désactivé."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Le mode Avion est activé."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Mode « Ne pas déranger » activé, interruptions prioritaires uniquement."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Mode « Ne pas déranger » activé, sans interruption."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Mode « Ne pas déranger » désactivé."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Le mode « Ne pas déranger » a bien été désactivé."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Le mode « Ne pas déranger » a bien été activé."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth désactivé."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activé."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Connexion Bluetooth en cours..."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran arrêtée."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'écran"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Données 2G/3G désactivées"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Données 4G désactivées"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Données cellulaire désactivées"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Votre appareil a désactivé les données, car il a atteint la limite définie.\n\nSi vous les réactivez, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activer les données"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G/3G désactivées"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode Avion"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne pas déranger"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priorités seulement"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Aucune interruption"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"BLUETOOTH DÉSACTIVÉ"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Terminé"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Supprimer toutes les applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> souhaite être la boîte de dialogue du volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Autoriser"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Touchez pour restaurer l\'original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 05ca6dc..71cf95d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informations sur l\'application"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Vos écrans récents s\'affichent ici"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Masquer les applications récentes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 écran dans Aperçu"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d écrans dans Aperçu"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d écran dans Aperçu</item>
+      <item quantity="other">%d écrans dans Aperçu</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
     <string name="phone_label" msgid="2320074140205331708">"ouvrir le téléphone"</string>
     <string name="camera_label" msgid="7261107956054836961">"ouvrir l\'appareil photo"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Lancement de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Mode Avion activé"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Le mode Avion est désactivé."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Le mode Avion est activé."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Mode \"Ne pas déranger\" activé, interruptions prioritaires uniquement"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Mode \"Ne pas déranger\" activé, sans interruption"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Mode \"Ne pas déranger\" désactivé"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Le mode \"Ne pas déranger\" a bien été désactivé."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Le mode \"Ne pas déranger\" a bien été activé."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth désactivé."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activé."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Connexion Bluetooth en cours..."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran interrompue."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'affichage"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Données 2G-3G désactivées"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Données 4G désactivées"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Données mobiles désactivées"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Votre appareil a désactivé les données, car il a atteint la limite que vous avez définie.\n\nSi vous les réactivez, votre opérateur risque de vous facturer des frais supplémentaires."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activer les données"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G-3G désactivées"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille interactif"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne pas déranger"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Prioritaires uniquement"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Aucune interruption"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth désactivé"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"OK"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connecté via l\'assistant Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Supprimer toutes les applications"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> souhaite être la boîte de dialogue du volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Autoriser"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Appuyez pour restaurer l\'interface d\'origine."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index f97e226..cb6292e 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Información da aplicación"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"As túas pantallas recentes aparecen aquí"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Rexeitar aplicacións recentes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 pantalla en Visión xeral"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d pantallas en Visión xeral"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d pantallas en visión xeral</item>
+      <item quantity="one">Unha pantalla en visión xeral</item>
+    </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Non hai notificacións"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En curso"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacións"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidade"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilidade co tamaño da pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Rexeitar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Rexeitouse <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Rexeitáronse todas as aplicacións recentes."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación rexeitada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Sombra de notificación"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modo avión activado."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Desactivouse o modo avión."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Activouse o modo avión."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Non molestar activado, só prioridade."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Non molestar activado, sen interrupcións."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"A opción Non molestar está desactivada."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Desactivouse a opción Non molestar."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Activouse a opción Non molestar."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desactivado."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activado."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth conectando."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Activouse a zona interactiva móbil."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Detívose a emisión en pantalla."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os datos 2G-3G están desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os datos 4G están desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os datos móbiles están desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os datos están desactivados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O teu dispositivo desactivou os datos porque alcanzou o límite establecido.\n\nActivalos de novo pode supoñer gastos adicionais do teu operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os datos 2G-3G están en pausa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Protector pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Non molestar"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Só prioridade"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sen interrupcións"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Máis opcións"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Feito"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado ao asistente de wifi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ancoraxe á rede"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona wifi"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Rexeitar todas as aplicacións"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</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 completar a carga"</string>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá aparecer a próxima vez que se active na configuración."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> quere ser o cadro de diálogo de volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denegar"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é o cadro de diálogo de volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar o orixinal."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 924fece..fde6fd2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ऐप्स की जानकारी"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"आपकी हाल की स्‍क्रीन यहां दिखाई देती हैं"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"हाल ही के ऐप्स  खारिज करें"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"अवलोकन मेें 1 स्क्रीन"</item>
-    <item quantity="other" msgid="5523506463832158203">"अवलोकन में %d स्क्रीन"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">अवलोकन में %d स्‍क्रीन</item>
+      <item quantity="other">अवलोकन में %d स्‍क्रीन</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"अनलॉक करें"</string>
     <string name="phone_label" msgid="2320074140205331708">"फ़ोन खोलें"</string>
     <string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> को ख़ारिज करें."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खा़रिज कर दिया गया."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"हाल ही के सभी ऐप्लिकेशन ख़ारिज कर दिए गए."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ हो रहा है."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"नोटिफिकेशन खारिज की गई."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"नोटिफिकेशन शेड."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"हवाई जहाज़ मोड चालू है."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"हवाई जहाज़ मोड को बंद किया गया."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"हवाई जहाज़ मोड को चालू किया गया."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"परेशान ना करें चालू, केवल प्राथमिकता."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"परेशान ना करें चालू है, कोई बाधा नहीं."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"परेशान ना करें बंद."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"परेशान ना करें बंद किया गया."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"परेशान ना करें चालू किया गया."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ब्लूटूथ बंद है."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ब्लूटूथ चालू है."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ब्लूटूथ कनेक्‍ट हो रहा है."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हॉटस्‍पॉट को चालू किया गया."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्‍क्रीन कास्‍ट करना रुक गया."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"स्क्रीन की स्क्रीन की रोशनी"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेल्युलर डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"आपके डिवाइस ने डेटा बंद कर दिया है क्योंकि आपके द्वारा सेट की गई सीमा पार हो गई है.\n\nइसे फिर से चालू करने से आपका वाहक शुल्क ले सकता है."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा चालू करें"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई  कनेक्‍ट किया गया"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS को खोजा जा रहा है"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"स्क्रीनसेवर"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ईथरनेट"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाई जहाज़ मोड"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"परेशान ना करें"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"केवल प्राथमिकता"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कोई मेसज और कॉल को नहीं रोका गया"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटूथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लूटूथ (<xliff:g id="NUMBER">%d</xliff:g> डिवाइस)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब्लूटूथ बंद"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"और सेटिंग"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट है"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट हो रहा है..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रीन पिन करना"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सभी ऐप्लिकेशन ख़ारिज करें"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्‍टम रूप से विभाजित करें"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"जब आप उसे अगली बार सेटिंग में चालू करेंगे तो वह फिर से दिखाई देगी."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"छिपाएं"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद होना चाहता है."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमति दें"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार करें"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल वॉल्यूम को फिर से लाने के लिए स्पर्श करें."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 38723c4..5623bb3 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -25,10 +25,11 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacije o aplikaciji"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ovdje se pojavljuju vaši nedavni zasloni"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Odbaci nedavne aplikacije"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 zaslon u Pregledu"</item>
-    <item quantity="other" msgid="5523506463832158203">"Broj zaslona u Pregledu: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d zaslon u Pregledu</item>
+      <item quantity="few">%d zaslona u Pregledu</item>
+      <item quantity="other">%d zaslona u Pregledu</item>
+    </plurals>
     <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>
@@ -88,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"otključavanje"</string>
     <string name="phone_label" msgid="2320074140205331708">"otvaranje telefona"</string>
     <string name="camera_label" msgid="7261107956054836961">"otvaranje fotoaparata"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth povezan."</string>
@@ -159,6 +159,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacivanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> odbačena je."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Odbačene su sve nedavne aplikacije."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon obavijesti."</string>
@@ -176,6 +177,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Način rada u zrakoplovu uključen."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Način rada u zrakoplovu isključen."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način rada u zrakoplovu uključen."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Ne ometaj\" uključeno, samo prioritetno."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Ne ometaj\" uključeno, bez prekida."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Ne ometaj\" isključeno."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Ne ometaj\" isključeno."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Ne ometaj\" uključeno."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth isključen."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth uključen."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth se povezuje."</string>
@@ -200,12 +206,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna žarišna točka uključena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Emitiranje zaslona zaustavljeno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svjetlina zaslona"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilni podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Podaci su isključeni"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Uređaj je isključio podatke jer je dosegnuo ograničenje koje ste postavili.\n\nAko ih ponovno uključite, mogući su dodatni troškovi za mobilne usluge."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Uključi podatke"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G – 3G podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS-a"</string>
@@ -224,6 +230,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način rada u zrakoplovu"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne ometaj"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetno"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez prekida"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <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>
@@ -261,7 +270,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Više  postavki"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Povezano"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Povezani putem pomoćnika za Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Žarišna točka"</string>
@@ -279,6 +287,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikvačivanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odbaci sve aplikacije"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</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>
@@ -362,4 +377,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ponovo će se pojaviti kada je sljedeći put uključite u postavkama."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> želi biti dijaloški okvir za upravljanje glasnoćom."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dopusti"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> predstavlja dijaloški okvir za upravljanje glasnoćom"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da biste vratili izvorno."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b4e0601..2eee0f5 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Alkalmazásinformáció"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"A legutóbbi képernyők itt jelennek meg"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Újabb alkalmazások elvetése"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 képernyő Áttekintés alatt"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d képernyő Áttekintés alatt"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d képernyő áttekintés alatt</item>
+      <item quantity="one">1 képernyő áttekintés alatt</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"feloldás"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefon megnyitása"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamera megnyitása"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth csatlakoztatva."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"A(z) <xliff:g id="APP">%s</xliff:g> elvetése."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eltávolítva."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Az összes alkalmazás eltávolítva a nemrég használtak közül."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A(z) <xliff:g id="APP">%s</xliff:g> indítása."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Értesítési felület."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Repülős üzemmód bekapcsolva."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Repülős üzemmód kikapcsolva."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Repülős üzemmód bekapcsolva."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"A „Ne zavarjanak” mód bekapcsolva. Csak prioritásos."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"A „Ne zavarjanak” mód bekapcsolva. Nincsenek értesítések."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"A „Ne zavarjanak” mód kikapcsolva."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"A „Ne zavarjanak” mód kikapcsolva."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"A „Ne zavarjanak” mód bekapcsolva."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth kikapcsolva."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth bekapcsolva."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth csatlakoztatása folyamatban."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"A mobil hotspot bekapcsolva."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A képernyő átküldése leállítva."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"A kijelző fényereje"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"A 2G-s és 3G-s adatkapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"A 4G-s adatkapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"A mobiladat-kapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Az adatkapcsolat ki van kapcsolva"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Eszköze leállította az adatkapcsolatot, mert Ön elérte a beállított adatkorlátot.\n\nAz adatkapcsolat újbóli bekapcsolása után szolgáltatója többletköltséget számíthat fel."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Adatkapcsolat engedélyezése"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"A 2G és 3G adatforgalom szünetel."</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS keresése"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Álmodozás"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Repülőgép üzemmód"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne zavarjanak"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Csak prioritásos"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ne zavarjon"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> eszköz)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth kikapcsolva"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"További beállítások"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Kész"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Csatlakoztatva"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Csatlakozva Wi‑Fi-segéddel"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Csatlakozás…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Megosztás"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"képernyő rögzítése"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Összes alkalmazás elvetése"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</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>
@@ -323,7 +337,7 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalomjegyzék elrejtve"</string>
+    <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Újból megjelenik majd, amikor ismét engedélyezi a beállítások között."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Elrejtés"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás szeretné kezelni a hangerőt."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Engedélyezés"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Elutasítás"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás kezeli a hangerőt"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Érintse meg az eredeti érték visszaállításához."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index ea00568..86493aa 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Տեղեկություններ ծրագրի մասին"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ձեր վերջին էկրանները տեսանելի են այստեղ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Անտեսել վերջին ծրագրերը"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Համատեսքում ցուցադրված է 1 էկրան:"</item>
-    <item quantity="other" msgid="5523506463832158203">"Համատեսքում ցուցադրված է %d էկրան"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">Համատեսքում ցուցադրված է %d էկրան</item>
+      <item quantity="other">Համատեսքում ցուցադրված է %d էկրան</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ապակողպել"</string>
     <string name="phone_label" msgid="2320074140205331708">"բացել հեռախոսը"</string>
     <string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Անտեսել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>-ը անտեսված է:"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Բոլոր վերջին հավելվածները հեռացվել են ցուցակից:"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Մեկնարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ծանուցումը անտեսվեց:"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ծանուցումների վահանակ:"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ինքնաթիռային ռեժիմը միացված է:"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ինքնաթիռային ռեժիմն անջատվեց:"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռային ռեժիմը միացավ:"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Չխանգարելու ընտրանքը միացված է: Ընդհատել միայն կարևոր ծանուցումների դեպքում:"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Չխանգարելու ընտրանքը միացված է: Չընդհատել:"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Չխանգարելու ընտրանքն անջատված է:"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Չխանգարելու ընտրանքն անջատվեց:"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Չխանգարելու ընտրանքը միացվեց:"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth-ն անջատված է:"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth-ը միացված է:"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth-ը միանում է:"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Շարժական կապի WiFi ցրիչը միացավ:"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Էկրանի հեռարձակումն ընդհատվեց:"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ցուցադրել պայծառությունը"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Բջջային տվյալներն անջատված են"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Տվյալների կապը ձեր սարքում անջատվեց, քանի որ դուք հատել եք նշված սահմանաչափը:\n\nԱյն հետ միացնելուց հետո հնարավոր են հավելյալ վճարներ ձեր օպերատորից:"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Միացնել տվյալների կապը"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2Գ-3Գ տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ցերեկային ռեժիմ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ինքնաթիռային ռեժիմ"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Չխանգարել"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Միայն կարևոր ծանուցումների դեպքում"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Չընդհատել"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> սարք)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth-ն անջատված է"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Հավելյալ կարգավորումներ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Պատրաստ է"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Կապակցված է"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Միանում է..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Միացում"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Թեժ կետ"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"էկրանի ամրակցում"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Հեռացնել բոլոր հավելվածները"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Թաքցնել"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ցանկանում է երկխոսության հավելվածը դառնալ:"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Թույլատրել"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Մերժել"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ձայնի ուժգնության երկխոսության հավելված է"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Դիպչեք՝ սկզբնօրինակը վերականգնելու համար:"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1674c3f..194f289 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info apl"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Layar terkini Anda muncul di sini"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Tutup aplikasi terbaru"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 layar dalam Ringkasan"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d layar dalam Ringkasan"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d layar dalam Ringkasan</item>
+      <item quantity="one">1 layar dalam Ringkasan</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
     <string name="phone_label" msgid="2320074140205331708">"buka ponsel"</string>
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tersambung."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Menyingkirkan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> disingkirkan."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaru telah ditutup."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulai <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan disingkirkan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bayangan pemberitahuan."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Mode pesawat aktif."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Mode pesawat dinonaktifkan."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Mode pesawat diaktifkan."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Status \"Jangan ganggu\" aktif, hanya untuk prioritas."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Status \"Jangan ganggu\" aktif, tanpa gangguan."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Status \"Jangan ganggu\" nonaktif."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Status \"Jangan ganggu\" dinonaktifkan."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Status \"Jangan ganggu\" diaktifkan."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth nonaktif."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth aktif."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth menyambung."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot seluler diaktifkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisi layar berhenti."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan tampilan"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G nonaktif"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G nonaktif"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data seluler nonaktif"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data nonaktif"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Perangkat Anda menonaktifkan data karena data mencapai batas yang Anda setel.\n\nMengaktifkan kembali data dapat membuat Anda terkena biaya dari operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktifkan data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Lamunan"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Jangan ganggu"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Hanya untuk prioritas"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tanpa gangguan"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Mati"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tersambung"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Terhubung melalui Asisten Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pin ke layar"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Tutup semua aplikasi"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ini akan muncul kembali saat Anda mengaktifkannya dalam setelan."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sembunyikan"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ingin menjadi dialog volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Izinkan"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> adalah dialog volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan aslinya."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 9ba0b54..ad57267 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Upplýsingar um forrit"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Nýlegar skjámyndir birtast hér"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Hunsa nýleg forrit"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Ein skjámynd í yfirliti"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skjámyndir í yfirliti"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d skjámynd í yfirliti</item>
+      <item quantity="other">%d skjámyndir í yfirliti</item>
+    </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Engar tilkynningar"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Áframhaldandi"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Tilkynningar"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"taka úr lás"</string>
     <string name="phone_label" msgid="2320074140205331708">"opna síma"</string>
     <string name="camera_label" msgid="7261107956054836961">"opna myndavél"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Hnappur fyrir samhæfisaðdrátt."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aðlaga forrit fyrir lítinn skjá að stærri skjá."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tengt."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Hunsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> vísað frá."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Öll nýleg forrit fjarlægð."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Ræsir <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Tilkynningu lokað."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Tilkynningasvæði."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Kveikt á flugstillingu."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Slökkt á flugstillingu."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Kveikt á flugstillingu."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Kveikt á „Ónáðið ekki“, aðeins forgangur."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Kveikt á „Ónáðið ekki“, engar truflanir."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Slökkt á „Ónáðið ekki“."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Slökkt á „Ónáðið ekki“."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Kveikt á „Ónáðið ekki“."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Slökkt á Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Kveikt á Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth tengist."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Kveikt á farsímaaðgangsstað."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjáútsendingu hætt."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Birtustig skjás"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Slökkt er á 2G- og 3G-gögnum"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Slökkt er á 4G-gögnum"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Slökkt er á farsímagögnum"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Slökkt er á gagnaflutningi"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Slökkt var á gagnaflutningi í tækinu vegna þess að hámarkinu sem þú valdir var náð.\n\nSímafyrirtækið þitt kann að taka gjald ef þú kveikir á honum aftur."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Kveikja á gagnaflutningi"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Slökkt er á 2G- og 3G-gögnum"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Leitar að GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Skjávari"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugstilling"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ónáðið ekki"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Aðeins forgangur"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Engar truflanir"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> tæki)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Slökkt á Bluetooth"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Fleiri stillingar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Lokið"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tengt"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Tengt í gegnum Wi-Fi aðstoð"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Tengist..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tjóðrun"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Heitur reitur"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skjáfesting"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Fjarlægja öll forrit"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Í hleðslu"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> þar til fullri hleðslu er náð"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Þetta birtist aftur næst þegar þú kveikir á því í stillingunum."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fela"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> vill vera hljóðstyrksvalmyndin."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Leyfa"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Hafna"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er hljóðstyrksvalmyndin"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Snertu til að færa í upprunalegt horf."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 052678a..2d21c98 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informazioni applicazione"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Le tue schermate recenti vengono visualizzate in questa sezione"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ignora app recenti"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 schermata in Panoramica"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d schermate in Panoramica"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d schermate in Panoramica</item>
+      <item quantity="one">1 schermata in Panoramica</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"sblocca"</string>
     <string name="phone_label" msgid="2320074140205331708">"apri telefono"</string>
     <string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Elimina <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> eliminata."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tutte le applicazioni recenti sono state rimosse."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Avvio di <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifica eliminata."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Area notifiche."</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modalità aereo attiva."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modalità aereo disattivata."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modalità aereo attivata."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Non disturbare\" attivo, solo con priorità."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Non disturbare\" attivo, nessuna interruzione."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Non disturbare\" non attivo."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Non disturbare\" non attivo."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Non disturbare\" attivo."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth non attivo."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth attivo."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Collegamento Bluetooth."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot mobile attivato."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Trasmissione dello schermo interrotta."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosità dello schermo"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dati 2G-3G disattivati"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dati 4G disattivati"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Rete dati disattivata"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dati disattivati"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Il tuo dispositivo ha disattivato il traffico dati perché hai raggiunto il limite prestabilito.\n\nLa riattivazione potrebbe comportare l\'applicazione di costi aggiuntivi da parte del tuo operatore."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Attiva i dati"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dati 2G-3G sospesi"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ricerca del GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modalità aereo"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Non disturbare"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo con priorità"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Nessuna interruzione"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivi)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth spento"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Altre impostazioni"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Fine"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Connesso"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Connesso tramite assistente Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connessione..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"blocco su schermo"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Rimuovi tutte le applicazioni"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Verranno visualizzate di nuovo quando le riattiverai nelle impostazioni."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Nascondi"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> desidera fungere da finestra di dialogo relativa al volume"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Consenti"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Nega"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> rappresenta la finestra di dialogo relativa al volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Tocca per ripristinare l\'originale."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 88af947..c1bfc3e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"פרטי אפליקציה"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"המסכים האחרונים מופיעים כאן"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"סגור אפליקציות אחרונות"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"מסך אחד ב\'סקירה\'"</item>
-    <item quantity="other" msgid="5523506463832158203">"‏%d מסכים ב\'סקירה\'"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="two">‏%d מסכים ב’סקירה‘</item>
+      <item quantity="many">‏%d מסכים ב’סקירה‘</item>
+      <item quantity="other">‏%d מסכים ב’סקירה‘</item>
+      <item quantity="one">מסך אחד ב’סקירה‘</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"בטל את הנעילה"</string>
     <string name="phone_label" msgid="2320074140205331708">"פתח את הטלפון"</string>
     <string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‏Bluetooth מחובר."</string>
@@ -159,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"סגור את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> נדחה."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"כל האפליקציות האחרונות נסגרו."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"מפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"לוח הודעות."</string>
@@ -176,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"מצב טיסה מופעל."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"מצב טיסה נכבה."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"מצב טיסה הופעל."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'נא לא להפריע\' פועל. הודעות בעדיפות בלבד."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'נא לא להפריע\' פועל. ללא הפרעות."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'נא לא להפריע\' כבוי."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'נא לא להפריע\' כבוי."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'נא לא להפריע\' פועל."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"‏Bluetooth כבוי."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"‏Bluetooth מופעל."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"‏Bluetooth מתחבר."</string>
@@ -200,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"נקודה לשיתוף אינטרנט בנייד מופעלת."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"העברת המסך הופסקה."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"בהירות תצוגה"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏נתונים בחיבור 2G-3G כובו"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏נתונים בחיבור 4G כובו"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"נתונים בחיבור סלולרי כובו"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"חיבור הנתונים כובה"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"המכשיר שלך כיבה את חיבור הנתונים מפני שהוא הגיע למגבלה שהגדרת.\n\nהפעלה מחדש עשויה להוביל לחיובים על ידי הספק."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"הפעל חיבור נתונים"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏השימוש בנתוני 2G-3G מושהה"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi מחובר"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏מחפש GPS"</string>
@@ -224,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"חלום בהקיץ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"מצב טיסה"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"נא לא להפריע"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"עדיפות בלבד"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ללא הפרעות"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"‏Bluetooth ‏(<xliff:g id="NUMBER">%d</xliff:g> מכשירים)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"‏Bluetooth מופסק"</string>
@@ -261,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"הגדרות נוספות"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"בוצע"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"מחובר"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"מתחבר..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"שיתוף אינטרנט בין ניידים"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"נקודה לשיתוף אינטרנט"</string>
@@ -279,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"הצמדת מסך"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"סגור את כל האפליקציות"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</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>
@@ -297,7 +313,7 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"הודעות בדחיפות נמוכה יותר בהמשך"</string>
     <string name="notification_tap_again" msgid="8524949573675922138">"גע שוב כדי לפתוח"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string>
-    <string name="phone_hint" msgid="3101468054914424646">"החלק ימינה להפעלת הטלפון"</string>
+    <string name="phone_hint" msgid="3101468054914424646">"כדי להפעיל את הטלפון, החלק שמאלה"</string>
     <string name="camera_hint" msgid="5241441720959174226">"החלק ימינה להפעלת המצלמה"</string>
     <string name="interruption_level_none" msgid="3831278883136066646">"ללא"</string>
     <string name="interruption_level_priority" msgid="6517366750688942030">"עדיפות"</string>
@@ -362,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"יופיע מחדש בפעם הבאה שתפעיל את האפשרות בהגדרות."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"הסתר"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> מנסה לפעול בתור תיבת הדו-שיח של עוצמת הקול."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"התר"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"דחה"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> הוא תיבת הדו-שיח של עוצמת הקול"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"גע כדי לשחזר את עוצמת הקול המקורית."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d581e73..a66dd37 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"アプリ情報"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"ここに最近の画面が表示されます"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"最近使ったアプリをクリア"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"[最近]に1個の画面があります"</item>
-    <item quantity="other" msgid="5523506463832158203">"[最近]に%d個の画面があります"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">[最近]に%d個の画面があります</item>
+      <item quantity="one">[最近]に1個の画面があります</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ロック解除"</string>
     <string name="phone_label" msgid="2320074140205331708">"電話を起動"</string>
     <string name="camera_label" msgid="7261107956054836961">"カメラを起動"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetoothに接続済み。"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>を削除します。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>は削除されました。"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近のアプリケーションをすべて消去しました。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>を開始しています。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知シェード"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"機内モードがONです。"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"機内モードをOFFにしました。"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"機内モードをONにしました。"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"[通知を非表示]はONで、重要な通知のみです。"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"[通知を非表示]はONで、サイレントです。"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"[通知を非表示]はOFFです。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"[通知を非表示]をOFFにしました。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"[通知を非表示]をONにしました。"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"BluetoothがOFFです。"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"BluetoothがONです。"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetoothに接続しています。"</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"モバイルアクセスポイントをONにしました。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"画面のキャストが停止しました。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ディスプレイの明るさ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G~3Gデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Gデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"モバイルデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"データが無効になりました"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"設定された上限に達したため、端末のデータ接続が無効になりました。\n\n有効に戻すと、携帯通信会社から課金される可能性があります。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"データ接続を有効にする"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G~3Gデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"スクリーンセーバー"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"機内モード"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"通知を非表示"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"重要な通知のみ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"サイレント"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth(端末数<xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth OFF"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"詳細設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完了"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"接続済み"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fiアシスタント経由で接続"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"接続しています..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"テザリング"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"アクセスポイント"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"すべてのアプリケーションを消去"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>を非表示にしますか?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"次回、設定でONにすると再表示されます。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"非表示"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>が音量ダイアログとして機能します。"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"許可"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"許可しない"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>を音量ダイアログとして使用"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"タップすると元の音量ダイアログが復元されます。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index e5f8f36..ee110da 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"აპის შესახებ"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"თქვენი ბოლო ეკრანები აქ გამოჩნდება"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ბოლო აპების გაუქმება"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"ნაჩვენებია 1 ეკრანი"</item>
-    <item quantity="other" msgid="5523506463832158203">"ნაჩვენებია %d ეკრანი"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d ეკრანი მიმოხილვაში</item>
+      <item quantity="one">1 ეკრანი მიმოხილვაში</item>
+    </plurals>
     <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>
@@ -80,7 +80,7 @@
     <string name="accessibility_back" msgid="567011538994429120">"უკან"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"საწყისი"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"მენიუ"</string>
-    <string name="accessibility_recent" msgid="5208608566793607626">"გადახედვა"</string>
+    <string name="accessibility_recent" msgid="5208608566793607626">"მიმოხილვა"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
     <string name="accessibility_phone_button" msgid="6738112589538563574">"ტელეფონი"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"განბლოკვა"</string>
     <string name="phone_label" msgid="2320074140205331708">"ტელეფონის გახსნა"</string>
     <string name="camera_label" msgid="7261107956054836961">"კამერის გახსნა"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string>
@@ -159,13 +158,14 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-ის უგულებელყოფა."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ამოშლილია სიიდან."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ყველა ბოლო აპლიკაცია გაუქმდა."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> იწყება."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"შეტყობინება წაიშალა."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"შეტყობინებების ფარდა"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"სწრაფი პარამეტრები"</string>
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ეკრანის დაბლოკვა."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"პარამეტრები"</string>
-    <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"გადახედვა."</string>
+    <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"მიმოხილვა"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"მომხმარებელი: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi გამორთულია."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"თვითმფრინავის რეჟიმი ჩართულია."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"თვითმფრინავის რეჟიმი გამოირთო."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"თვითმფრინავის რეჟიმი ჩაირთო."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ჩართულია რეჟიმი „არ შემაწუხოთ\", მხოლოდ პრიორიტეტები."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ჩართულია რეჟიმი „არ შემაწუხოთ\", შეწყვეტის გარეშე."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"„არ შემაწუხოთ“ გამორთულია"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"„არ შემაწუხოთ\" რეჟიმი გამორთულია."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"„არ შემაწუხოთ\" რეჟიმი ჩართულია."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth გამორთულია."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth ჩართულია."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"მიმდინარეობს Bluetooth-თან დაკავშირება."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"მობილური ქსელის წერტილი ჩაირთო."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ეკრანის გადაცემა შეჩერებულია."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ეკრანის სიკაშკაშე"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G მონაც. გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G მონაც. გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ფიჭური ინტერნეტი გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"მონაცემთა გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"თქვენმა მოწყობილობამ მონაცემები გამორთო, რადგან თქვენ მიერ დაყენებულ ლიმიტს მიაღწია.\n\nმისი კვლავ გააქტიურებით შესაძლოა დაგეკისროთ გადასახადი თქვენი ოპერატორისგან."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"მონაცემთა ჩართვა"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ეთერნეტი"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"თვითმფრინავის რეჟიმი"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"არ შემაწუხოთ"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"მხოლოდ პრიორიტეტული"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"შეფერხებების გაეშე"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> მოწყობილობა)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth გამორთულია"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"დამატებითი პარამეტრები"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"დასრულდა"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"დაკავშირებულია"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"დაკავშირებული Wi-Fi თანაშემწით"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"დაკავშირება..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"მოდემის რეჟიმი"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"წვდომის წერტილი"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ეკრანზე ჩამაგრება"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ყველა აპლიკაციის გაუქმება"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ის კვლავ გამოჩნდება, როდესაც პარამეტრებში ჩართავთ"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"დამალვა"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> სურს იყოს ხმოვან დიალოგში."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"უფლების მიცემა"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"უარყოფა"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ხმოვან დიალოგშია"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ორიგინალის აღდგენისათვის, შეეხეთ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 838d94d..da4223d 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Қолданба ақпараты"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Мұнда жақындағы экрандар көрсетіледі"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Жуықта қолданылған қолданбаларды қоспау"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"«Шолу» ішінде 1 экран"</item>
-    <item quantity="other" msgid="5523506463832158203">"«Шолу» ішінде %d экран"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">«Шолу» ішінде %d экран</item>
+      <item quantity="one">«Шолу» ішінде 1 экран</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"бекітпесін ашу"</string>
     <string name="phone_label" msgid="2320074140205331708">"телефонды ашу"</string>
     <string name="camera_label" msgid="7261107956054836961">"камераны ашу"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Үйлесімділік ұлғайту түймесі."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Үлкендеу экранда кішірейту."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth қосылған."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> қолданбасынан бас тарту."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> алынып тасталған."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Барлық жақындағы қабылданбаған қолданбалар."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> іске қосылуда."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Хабар алынып тасталды."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Хабарландыру тақтасы"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ұшақ режимі қосулы."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ұшақ режимі өшірілді."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ұшақ режимі қосылды."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Мазаламау режимі қосулы, тек басымдық"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Мазаламау режимі қосулы, үзілістерсіз"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Мазаламау режимі өшірулі"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Мазаламау режимі өшірілді."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Мазаламау режимі қосылды."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth өшірулі."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth қосулы."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth қосылуда."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобильді хотспот қосылды."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Экранды трансляциялау тоқтатылды."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дисплей жарықтығы"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G деректері өшірулі"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G деректері өшірулі"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Ұялы деректер өшірулі"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Деректер өшірулі"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Құрылғыңыз сіз орнатқан шекке жеткендіктен деректерді өшірді.\n\nОны қайтадан қосу оператордың ақылар алуына әкелуі мүмкін."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Деректерді қосу"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G деректері кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS қызметін іздеуде"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Қалғу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ұшақ режимі"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Мазаламау"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Тек басымдық"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Үзулерсіз"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth өшірулі"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Қосымша параметрлер"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Дайын"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Қосылды"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Қосылуда…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетеринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хот-спот"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Барлық қолданбаларды қабылдамау"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ол сіз оны параметрлерде келесі қосқанда қайта пайда болады."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Жасыру"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> көлем диалогтық терезесі болғысы келеді."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Рұқсат беру"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Өшіру"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> — көлем диалогтық терезесі"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнұсқаны қалпына келтіру үшін түртіңіз."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index ab8cfa0..c995637 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"អេក្រង់​បច្ចុប្បន្ន​របស់​អ្នក​បង្ហាញ​នៅ​ទីនេះ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"បដិសេធ​កម្មវិធី​ថ្មីៗ"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"អេក្រង់​ 1 ក្នុង​ទិដ្ឋភាព"</item>
-    <item quantity="other" msgid="5523506463832158203">"អេក្រង់ %d ក្នុង​ទិដ្ឋភាព"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">អេក្រង់ %d ក្នុងទិដ្ឋភាព</item>
+      <item quantity="one">អេក្រង់ 1 ក្នុងទិដ្ឋភាព</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ដោះ​សោ"</string>
     <string name="phone_label" msgid="2320074140205331708">"បើក​ទូរស័ព្ទ"</string>
     <string name="camera_label" msgid="7261107956054836961">"បើក​ម៉ាស៊ីន​ថត"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បាន​តភ្ជាប់​ប៊្លូធូស។"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"បោះបង់ <xliff:g id="APP">%s</xliff:g> ។"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"កម្មវិធីថ្មីៗទាំងអស់ត្រូវបានបោះបង់។"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ។"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"បាន​បដិសេធ​ការ​ជូនដំណឹង"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ពណ៌​ការ​ជូន​ដំណឹង"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"បើក​របៀប​ជិះ​យន្តហោះ។"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"បាន​បិទ​របៀប​ជិះ​យន្តហោះ។"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"បាន​បើក​របៀប​ជិះ​យន្តហោះ។"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"បានបើកមុខងារកុំរំខាន (អាទិភាពប៉ុណ្ណោះ)។"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"បានបើកមុខងារកុំរំខាន សូមកុំរំខាន"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"បានបិទមុខងារកុំរំខាន។"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"បានបិទមុខងារកុំរំខាន។"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"បានបើកមុខងារកុំរំខាន។"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"បិទ​ប៊្លូធូស។"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"បើក​ប៊្លូធូស។"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ការ​​​ភ្ជាប់​ប៊្លូធូស។"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"បាន​បើក​ហតស្ប៉ត​ចល័ត។"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"បាន​បញ្ឈប់​ការ​ចាត់​ថ្នាក់​អេក្រង់។"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ពន្លឺ​ការ​បង្ហាញ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ទិន្នន័យ 2G-3G បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ទិន្នន័យ 4G បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ទិន្នន័យ​ចល័ត​បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ទិន្នន័យ​បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ឧបករណ៍​របស់​អ្នក​បាន​បិទ​ទិន្នន័យ ព្រោះ​វា​បាន​ដល់​​កម្រិត​​ដែល​អ្នក​បាន​កំណត់។\n\nបើក​វា​ឡើង​វិញ​អាច​គិត​លុយ​ពី​ក្រុមហ៊ុន​បញ្ជូន​របស់​អ្នក។"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"បើក​ទិន្នន័យ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ទិន្នន័យ 2G-3G ត្រូវបានផ្អាក"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ដោយសារទិន្នន័យរបស់អ្នកបានឈានដល់កំណត់ ឧបករណ៍នេះបានផ្អាកការប្រើប្រាស់ទិន្នន័យសម្រាប់ការរំលឹកនៃវគ្គនេះ។\n\nការបន្តប្រើប្រាស់អាចនាំឲ្យមានការគិតប្រាក់ពីក្រុមហ៊ុនផ្តល់សេវាកម្ម។"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បាន​ភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ស្វែងរក GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"ធាតុ​រក្សា​អេក្រង់"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"អ៊ីសឺរណិត"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"របៀបពេល​​ជិះ​យន្តហោះ"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"កុំរំខាន"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"អាទិភាពប៉ុណ្ណោះ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"សូមកុំរំខាន"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ប៊្លូធូស"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ប៊្លូធូស (ឧបករណ៍ <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"​ប៊្លូធូស​បាន​បិទ"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ការ​កំណត់​ច្រើន​ទៀត"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"រួចរាល់"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"បាន​ភ្ជាប់"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"កំពុង​តភ្ជាប់..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ការ​ភ្ជាប់"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ហតស្ប៉ត"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ការ​ភ្ជាប់​អេក្រង់"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"បោះបង់កម្មវិធីទាំងអស់"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"វា​នឹង​បង្ហាញ​ពេល​ក្រោយ​ ពេល​ដែល​អ្នក​បើក​ក្នុង​ការ​កំណត់។"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"លាក់"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ចង់ក្លាយជាប្រអប់សម្លេង។"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"អនុញ្ញាត"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"បដិសេធ"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> គឺជាប្រអប់សម្លេង"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ប៉ះដើម្បីស្តារច្បាប់ដើម។"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 181706f..64d4ff9 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"ನಿಮ್ಮ ಇತ್ತೀಚಿನ ಪರದೆಗಳು ಇಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸು"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"ಸಮಗ್ರ ನೋಟದಲ್ಲಿರುವ 1 ಪರದೆ"</item>
-    <item quantity="other" msgid="5523506463832158203">"ಸಮಗ್ರ ನೋಟದಲ್ಲಿರುವ %d ಪರದೆಗಳು"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">ಸಮಗ್ರ ನೋಟದಲ್ಲಿರುವ %d ಪರದೆಗಳು</item>
+      <item quantity="other">ಸಮಗ್ರ ನೋಟದಲ್ಲಿರುವ %d ಪರದೆಗಳು</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ಅನ್‌ಲಾಕ್ ಮಾಡು"</string>
     <string name="phone_label" msgid="2320074140205331708">"ಫೋನ್ ತೆರೆಯಿರಿ"</string>
     <string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸು."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ಇತ್ತೀಚಿನ ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್, ಆದ್ಯತೆ ಮಾತ್ರ."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ, ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆಫ್ ಆಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ತೊಂದರೆ ಮಾಡಬೇಡಿ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ಬ್ಲೂಟೂತ್ ಆಫ್ ಆಗಿದೆ."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ಬ್ಲೂಟೂತ್ ಆನ್ ಆಗಿದೆ."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಪಡಿಸಲಾಗುತ್ತಿದೆ."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ಸ್ಕ್ರೀನ್ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ಹೊಳಪನ್ನು ಪ್ರದರ್ಶಿಸಿ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ನೀವು ಹೊಂದಿಸಿದ ಮಿತಿಯನ್ನು ತಲುಪಿರುವ ಕಾರಣ ನಿಮ್ಮ ಸಾಧನವು ಡೇಟಾವನ್ನು ಆಫ್ ಮಾಡಿದೆ.\n\nಆನ್ ಮಾಡುವುದರಿಂದ ನಿಮ್ಮ ವಾಹಕದಲ್ಲಿ ಶುಲ್ಕಕ್ಕೆ ಕಾರಣವಾಗಬಹುದು."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ಡೇಟಾ ಆನ್ ಮಾಡಿ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ಡೇಟಾವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"ಡೇಡ್ರೀಮ್"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ಇಥರ್ನೆಟ್"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ಆದ್ಯತೆ ಮಾತ್ರ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ಬ್ಲೂಟೂತ್‌"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ಬ್ಲೂಟೂತ್‌ (<xliff:g id="NUMBER">%d</xliff:g> ಸಾಧನಗಳು)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ಬ್ಲೂಟೂತ್‌ ಆಫ್"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ಮುಗಿದಿದೆ"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ಟೆಥರಿಂಗ್‌"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ಸ್ಕ್ರೀನ್ ಪಿನ್ನಿಂಗ್"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ಎಲ್ಲಾ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ನೀವು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅದನ್ನು ಆನ್ ಮಾಡಿದಾಗ ಅದು ಮರುಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ಮರೆಮಾಡಿ"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಲು ಬಯಸುತ್ತದೆ."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ಅನುಮತಿಸು"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ನಿರಾಕರಿಸು"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಿದೆ"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ಮೂಲ ಮರುಸ್ಥಾಪಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 054c192..e30bc2a 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"앱 정보"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"여기에 최근 화면이 표시됩니다."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"최근에 사용한 앱 숨기기"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"최근 사용에 화면 1개"</item>
-    <item quantity="other" msgid="5523506463832158203">"최근 사용에 화면 %d개"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">최근 사용에 화면 %d개 있음</item>
+      <item quantity="one">최근 사용에 화면 1개 있음</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"잠금 해제"</string>
     <string name="phone_label" msgid="2320074140205331708">"휴대전화 열기"</string>
     <string name="camera_label" msgid="7261107956054836961">"카메라 열기"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"블루투스가 연결되었습니다."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>을(를) 숨깁니다."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>이(가) 제거되었습니다."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"최근 사용한 애플리케이션을 모두 닫았습니다."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>을(를) 시작하는 중입니다."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"알림 세부정보"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"비행기 모드: 사용"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"비행기 모드가 사용 중지되었습니다."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"비행기 모드를 사용합니다."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"알림 일시중지 사용, 중요 알림만 수신"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"알림 일시중지 사용, 방해 금지"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"알림 일시중지 사용 중지"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"알림 일시중지가 사용 중지되었습니다."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"알림 일시중지를 사용합니다."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"블루투스: 사용 안함"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"블루투스: 사용"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"블루투스에 연결 중입니다."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"모바일 핫스팟을 사용합니다."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"화면 전송이 중지되었습니다."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"디스플레이 밝기"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"이동통신 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"데이터가 설정 한도에 도달하여 사용 중지되었습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"데이터 사용 설정"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"화면 보호기"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"이더넷"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"비행기 모드"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"알림 일시중지"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"중요 알림만"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"방해 금지"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"블루투스"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"블루투스(<xliff:g id="NUMBER">%d</xliff:g>개의 기기)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"블루투스 사용 안함"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"설정 더보기"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"완료"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"연결됨"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi 도우미를 통해 연결됨"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"연결 중..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"테더링"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"핫스팟"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"화면 고정"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"모든 애플리케이션 닫기"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"다음번에 설정에서 사용 설정하면 다시 표시됩니다."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"숨기기"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 볼륨 대화가 되려고 합니다."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"허용"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"거부"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"원본을 복원하려면 터치하세요."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index fed9f25..5899a87 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -27,10 +27,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Колдонмо тууралуу"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Акыркы экрандарыңыз бул жерден көрүнөт"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Акыркы колдонмолорду жок кылуу"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 экран Көз жүгүртүүдө"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d экран Көз жүгүртүүдө"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d экран Көз жүгүртүүдө</item>
+      <item quantity="one">1 экран Көз жүгүртүүдө</item>
+    </plurals>
     <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
     <skip />
     <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
@@ -113,7 +113,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"кулпуну ачуу"</string>
     <string name="phone_label" msgid="2320074140205331708">"телефонду ачуу"</string>
     <string name="camera_label" msgid="7261107956054836961">"камераны ачуу"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Масштабды сыйыштыруу баскычы."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Кичинекейди чоң экранга масштабдоо."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth байланышта"</string>
@@ -184,6 +183,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> этибарга албоо."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> жок болду."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Акыркы колдонмолордун баары көз жаздымда калтырылды."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> иштеп баштоодо."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Эскертме жок кылынды."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Эскертмелер көшөгөсү."</string>
@@ -201,6 +201,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Учак режими күйүк."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Учак режими өчүрүлдү."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Учак режими күйгүзүлдү."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Тынчымды алба деген күйүк, артыкчылыктуулар гана."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Тынчымды алба деген күйүк, үзгүлтүккө учуратуулар жок."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Тынчымды алба деген өчүк."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Тынчымды алба деген өчүрүлдү."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Тынчымды алба деген күйгүзүлдү."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth өчүк."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth күйүк."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth туташууда."</string>
@@ -225,12 +230,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилдик байланыш түйүнү күйгүзүлдү."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Тышкы экранга чыгаруу аракети токтотулду."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Жарыктыгын көрсөтүү"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2Гб-3Гб көлөмдөгү дайындар өчүрүлдү."</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Гб көлөмдөгү дайындар өчүрүлдү"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Уюктук дайындар тармагы өчүк"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дайындарды кабыл алуу өчүрүлгөн."</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Белгиленген эң жогорку чекке жеткендиктен, түзмөгүңүз дайындарды кабыл алууну токтотту.\n\nДайындарды кабыл алууну улантам десеңиз, операторго акы төлөп калышыңыз мүмкүн."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Дайындарды алууну иштетүү"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дайындары тындырылды."</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS издөө"</string>
@@ -249,6 +254,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Кыялдануу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Учак тартиби"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Тынчымды алба"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Артыкчылык гана"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Үзгүлтүксүз"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> түзмөк)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth өчүк"</string>
@@ -286,7 +294,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Дагы жөндөөлөр"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Аткарылды"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Туташкан"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Туташууда…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Тетеринг"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Туташуу чекити"</string>
@@ -304,6 +311,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экран кадоо"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Бардык колдонмолорду көз жаздымда калтыруу"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</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>
@@ -387,4 +401,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Бул кийинки жолу жөндөөлөрдөн күйгүзүлгөндө кайра көрүнөт."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Жашыруу"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> үндү катуулатуу диалогу болгусу келет."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Уруксат берүү"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Жок"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> үндү катуулатуу диалогу"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнусканы калыбына келтирүү үчүн тийип коюңуз."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 1342b41..455d361 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ຂໍ້ມູນແອັບຯ"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Your recent screens appear here"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ປິດແອັບຯຫຼ້າສຸດທີ່ໃຊ້"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ​ໜ້າ​ຈໍ​ຢູ່​ໃນ​ພາບ​ຮວມ"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ​ໜ້າ​ຈໍ​ຢູ່​ໃນ​ພາບ​ຮວມ"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d ໜ້າ​ຈໍ​ຢູ່​ໃນ​ພາບ​ລວມ</item>
+      <item quantity="one">1 ​ໜ້າ​ຈໍ​ຢູ່​ໃນ​ພາບ​ລວມ</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ປົດລັອກ"</string>
     <string name="phone_label" msgid="2320074140205331708">"​ເປີດ​​ແປ້ນ​ໂທ​ລະ​ສັບ"</string>
     <string name="camera_label" msgid="7261107956054836961">"ເປີດ​ກ້ອງ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ປິດ <xliff:g id="APP">%s</xliff:g> ໄວ້."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"ປິດ <xliff:g id="APP">%s</xliff:g> ແລ້ວ."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ທຸກ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ດົນ​ມາ​ນີ້​ຖືກ​ປ່ອຍ​ໄປ."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"ກຳ​ລັງ​ເປີດ <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"ໜ້າຈໍແຈ້ງເຕືອນ."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ເປີດ​ໂໝດ​ຢູ່​ໃນ​ຍົນ."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ປິດ​ໂໝດ​ຢູ່​ໃນ​ຍົນ​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ເປີດ​ໂໝດ​ຢູ່​ໃນ​ຍົນ​ແລ້ວ."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ຫ້າມ​ລະ​ກວນ​ເປີດ​ຢູ່, ບຸ​ລິ​ມະ​ສິດ​ເທົ່າ​ນັ້ນ."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ຫ້າມ​ລະ​ກວນ​ເປີດ​ຢູ່, ບໍ່​ມີ​ການ​ຂັດ​ຈັງ​ຫວະ."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ຫ້າມ​ລົບ​ກວນປິດຢູ່."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ຢ່າ​ລົບ​ກວນ​ປິດ​ແລ້ວ."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ຢ່າ​ລົບ​ກວນ​ເປີດ​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth ປິດ."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth ເປີດ."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ກຳ​ລັງ​ເຊື່ອມ​ຕໍ່ Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ເປີດ​ຮັອດ​ສະ​ປອດ​ເຄື່ອນ​ທີ່​ແລ້ວ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ຢຸດ​ການ​ສົ່ງ​​ພາບ​ໜ້າ​ຈໍ​ແລ້ວ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"​ຄວາມ​ແຈ້ງ​​ຂອງ​ຈໍ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ຂໍ້​ມູນ 2G-3G ​ແມ່ນ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ຂໍ້​ມູນ 4G ແມ່ນ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ຂໍ້​ມູ​ນມ​ື​ຖື​ຖືກ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ຂໍ້​ມູນ​ຖື​ກ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ປິດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ເນື່ອງ​ຈາກ​ມັນ​ໃຊ້​ຮອດ​ຈຳ​ນວນ​ທີ່​ທ່ານ​ກຳ​ນົດ​ໄວ້​ແລ້ວ.\n\nການ​ເປີດ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ຄືນ​ອາດ​ເຮັດ​ໃຫ​້​ຜູ່​ໃຫ້​ບໍ​ລິ​ການ​ຮຽກ​ເກັບ​ເງິນ​ທ່ານ​ເພີ່ມ​ໄດ້."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"​ເປີດ​ນຳ​ໃຊ້​ຂໍ້​ມູນ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ຂໍ້​ມູນ 2G​-3G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້​ມູນເຊວ​ລູ​ລາຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້​ມູນ​ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງ​ຈາກວ່າ​ຮອດ​ຂີດ​ຈຳ​ກັດ​ຂໍ້​ມູນ​ທີ່​ຕັ້ງ​ໄວ້​ຂອ​ງ​ທ່ານ​ແລ້ວ, ອຸ​ປະ​ກອນ​ຢຸດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ສຳ​ລັບ​ສ່ວນ​ທີ່​ຍັງ​ເຫຼືອ​ຂອງ​ຮອບ​ວຽນ​ນີ້.\n\nການ​ເລີ່ມ​ຕໍ່​ອາດ​ຈະ​ນຳ​ໄປ​ສູ່​ການ​ປ່ຽນ​ແປງ​ຈາກ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມ​ຕໍ່ Wi-​-Fi ແລ້ວ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ກຳລັງຊອກຫາ GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ໂໝດຢູ່ໃນຍົນ"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ຫ້າມ​ລົບ​ກວນ"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ບຸ​ລິ​ມະ​ສິດເທົ່າ​ນັ້ນ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ບໍ່​ມີ​ການ​ລົບກວນ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ອຸປະກອນ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth ປິດ"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ແລ້ວໆ"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ເຊື່ອມ​ຕໍ່ແລ້ວ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ກຳລັງເຊື່ອມຕໍ່..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"​ການ​ປ່ອນ​ສັນ​ຍານ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"​ຮັອດ​ສະ​ປອດ"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່​ສາ​ມາດ​ເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ປ່ອຍ​ທຸກ​ແອັບ​ພ​ລິ​ເຄ"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼື​ບໍ່?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"​ມັນ​ຈະ​ສະ​ແດງ​ຄືນ​ໃໝ່​ເມື່ອ​ທ່ານ​ເປີດ​ນຳ​ໃຊ້​ມັນ​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ຄັ້ງ​ຕໍ່​ໄປ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ເຊື່ອງ"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຕ້ອງ​ການໃຫ້​ເປັນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ອະນຸຍາດ"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ປະຕິເສດ"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ສໍາ​ຜັດ​ເພື່ອກູ້​ຄືນ​ຕົ້ນ​ສະ​ບັບ​."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a8dd63c..a96d51e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Programos informacija"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Čia rodomi naujausi ekranai"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Atsisakyti naujausių programų"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Ekranų apžvalga: 1"</item>
-    <item quantity="other" msgid="5523506463832158203">"Ekranų apžvalga: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d ekrano apžvalga</item>
+      <item quantity="few">%d ekranų apžvalga</item>
+      <item quantity="many">%d ekrano apžvalga</item>
+      <item quantity="other">%d ekranų apžvalga</item>
+    </plurals>
     <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">"Pranešimai"</string>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"atrakinti"</string>
     <string name="phone_label" msgid="2320074140205331708">"atidaryti telefoną"</string>
     <string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"„Bluetooth“ prijungtas."</string>
@@ -159,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Atsisakyti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Atsisakyta programos „<xliff:g id="APP">%s</xliff:g>“."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Atsisakyta visų naujausių programų."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Paleidžiama <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pranešimo atsisakyta."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pranešimų gaubtas."</string>
@@ -176,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Lėktuvo režimas įjungtas."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Lėktuvo režimas išjungtas."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lėktuvo režimas įjungtas."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Funkcija „Netrukdyti“ įjungta. Tik prioritetiniai įvykiai."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Funkcija „Netrukdyti“ įjungta. Jokių pertraukčių."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Funkcija „Netrukdyti“ išjungta."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Funkcija „Netrukdyti“ išjungta."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Funkcija „Netrukdyti“ įjungta."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"„Bluetooth“ išjungtas."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"„Bluetooth“ įjungtas."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Prijungiamas „Bluetooth“."</string>
@@ -200,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiliojo ryšio viešosios interneto prieigos taškas įjungtas."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrano perdavimas sustabdytas."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrano šviesumas"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiliojo ryšio duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Įrenginys išjungė duomenis, nes buvo pasiektas nustatytas limitas.\n\nVėl juos įjungus gali būti taikomi operatoriaus mokesčiai."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Įjungti duomenis"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string>
@@ -224,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Svajonė"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Eternetas"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lėktuvo režimas"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Netrukdyti"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tik prioritetiniai įvykiai"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Jokių pertraukčių"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"„Bluetooth“ (<xliff:g id="NUMBER">%d</xliff:g> įreng.)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
@@ -261,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Daugiau nustatymų"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Atlikta"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Prijungtas"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Prisijungiama..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Susiejimas"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Viešosios interneto prieigos taškas"</string>
@@ -279,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekrano prisegimas"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Atsisakyti visų programų"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</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>
@@ -362,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tai bus vėl parodyta, kai kitą kartą įjungsite tai nustatymuose."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Slėpti"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ nori būti garsumo valdymo dialogo langu."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Leisti"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Atmesti"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ yra garsumo valdymo dialogo langas"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Palieskite, kad atkurtumėte originalą."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5fc3b0b..6ac122c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -25,10 +25,11 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Lietotnes informācija"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Jūsu pēdējie ekrāni tiek rādīti šeit."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Nerādīt nesen izmantotās lietotnes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ekrāns sadaļā “Pārskats”"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ekrāni sadaļā “Pārskats”"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="zero">%d ekrānu sadaļā Kopsavilkums</item>
+      <item quantity="one">%d ekrāns sadaļā Kopsavilkums</item>
+      <item quantity="other">%d ekrāni sadaļā Kopsavilkums</item>
+    </plurals>
     <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>
@@ -88,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"atbloķēt"</string>
     <string name="phone_label" msgid="2320074140205331708">"atvērt tālruni"</string>
     <string name="camera_label" msgid="7261107956054836961">"atvērt kameru"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth savienojums ir izveidots."</string>
@@ -159,6 +159,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Nerādīt lietotni <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Lietotne <xliff:g id="APP">%s</xliff:g> vairs netiek rādīta."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Visas nesen izmantotās lietojumprogrammas tika noņemtas."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Notiek lietotnes <xliff:g id="APP">%s</xliff:g> palaišana."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Paziņojums netiek rādīts."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Paziņojumu panelis"</string>
@@ -176,6 +177,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Lidojuma režīms ir ieslēgts."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Lidojuma režīms ir izslēgts."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lidojuma režīms ir ieslēgts."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Statuss Netraucēt ir ieslēgts, izvēlēts iestatījums Tikai prioritārie."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Statuss Netraucēt ir ieslēgts, izvēlēts iestatījums Bez pārtraukumiem."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Statuss Netraucēt ir izslēgts."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Statuss Netraucēt tika izslēgts."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Statuss Netraucēt tika ieslēgts."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth savienojums ir izslēgts."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth savienojums ir ieslēgts."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Notiek Bluetooth savienojuma izveide."</string>
@@ -200,12 +206,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilais tīklājs ir ieslēgts."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrāna apraidīšana ir apturēta."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrāna spilgtums"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilie dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Jūsu ierīcē tika atslēgta datu lietošana, jo tika sasniegts jūsu noteiktais ierobežojums.\n\nJa atkal ieslēgsiet datu lietošanu, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ieslēgt datus"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string>
@@ -224,6 +230,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ekrānsaudzētājs"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Tīkls Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lidojuma režīms"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Netraucēt"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tikai prioritārie"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez pārtraukumiem"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ierīce(-es))"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth savienojums ir izslēgts."</string>
@@ -261,7 +270,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Vairāk iestatījumu"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gatavs"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Pievienota"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Notiek savienojuma izveide…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Piesaiste"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tīklājs"</string>
@@ -279,6 +287,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Piespraust ekrānu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Noņemt visas lietojumprogrammas"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</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>
@@ -362,4 +377,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tas tiks atkārtoti parādīts, kad nākamreiz ieslēgsiet to iestatījumos."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Paslēpt"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> vēlas pārvaldīt skaļuma dialoglodziņu."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Atļaut"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neatļaut"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ir skaļuma dialoglodziņš"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Pieskarieties, lai atjaunotu sākotnējo."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 1a0f59e..e33d88e 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Информации за апликацијата"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Вашите неодамнешни екрани се појавуваат тука"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Отфрли ги скорешните апликации"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 екран во Краток преглед"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d екрани во Краток преглед"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d екран во Краток преглед</item>
+      <item quantity="other">%d екрани во Краток преглед</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"отклучи"</string>
     <string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Отфрли <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> е отфрлена."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Сите неодамнешни апликации се отфрлени."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Се стартува <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известувањето е отфрлено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панел за известување"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Авионскиот режим е вклучен."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Авионскиот режим е исклучен."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Авионскиот режим е вклучен."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"„Не вознемирувај“ е вклучено, само приоритетни."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"„Не вознемирувај“ е вклучено, без прекини."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"„Не вознемирувај“ е исклучено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"„Не вознемирувај“ е исклучено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"„Не вознемирувај“ е вклучено."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth е исклучен."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth е вклучен."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth се поврзува."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка на пристап е вклучена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Емитувањето на екранот запре."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветленост на екранот"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Податоците 2G-3G се исклучени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Податоците 4G се исклучени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилните податоци се исклучени"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Податоците се исклучени"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Вашиот уред ги исклучи податоците затоа што го достигнаа лимитот што го поставивте.\n\nСо повторно вклучување, операторот може да ви наплати за тоа."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Вклучи податоци"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Податоците 2G-3G се паузирани"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Се пребарува за ГПС"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим на работа во авион"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не вознемирувај"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само приоритетно"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекини"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уреди)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth е исклучен"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Повеќе поставки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Поврзано"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Поврзано преку помошник за Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Се поврзува..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Поврзување"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка на пристап"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"прикачување екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Отфрли ги сите апликации"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"22°"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"22°"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"22°"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сокриј"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> сака да биде дијалог за јачина на звук."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Овозможи"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> е дијалог за јачина на звук"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Допрете за да го вратите оригиналот."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 357af5d..ff0fae1 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"അപ്ലിക്കേഷൻ വിവരം"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"നിങ്ങളുടെ പുതിയ സ്ക്രീനുകൾ ഇവിടെ ദൃശ്യമാകുന്നു"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"സമീപകാല അപ്ലിക്കേഷനുകൾ നിരസിക്കുക"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"കാഴ്ചയിലെ ഒരു സ്‌ക്രീൻ"</item>
-    <item quantity="other" msgid="5523506463832158203">"കാഴ്ചയിലെ %d സ്‌ക്രീനുകൾ"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">ചുരുക്കവിവരണത്തിലെ %d സ്‌ക്രീനുകൾ</item>
+      <item quantity="one">ചുരുക്കവിവരണത്തിലെ ഒരു സ്‌ക്രീൻ</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"അൺലോക്കുചെയ്യുക"</string>
     <string name="phone_label" msgid="2320074140205331708">"ഫോൺ തുറക്കുക"</string>
     <string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്‌ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> നിരസിക്കുക."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> നിരസിച്ചു."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"അടുത്തിടെയുള്ള എല്ലാ അപ്ലിക്കേഷനും നിരസിച്ചു."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കുന്നു."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"അറിയിപ്പ് നിരസിച്ചു."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"അറിയിപ്പ് ഷെയ്‌ഡ്."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ഫ്ലൈറ്റ് മോഡ് ഓണാണ്."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ഫ്ലൈറ്റ് മോഡ് ഓഫാക്കി."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ഫ്ലൈറ്റ് മോഡ് ഓണാക്കി."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാണ്, മുൻഗണന മാത്രം."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാണ്, തടസ്സങ്ങളൊന്നുമില്ല."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ശല്ല്യപ്പെടുത്തരുത് എന്നത് ഓഫാണ്."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓഫാക്കി."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാക്കി."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ബ്ലൂടൂത്ത് ഓഫാണ്."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ബ്ലൂടൂത്ത് ഓണാണ്."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്യുന്നു."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"മൊബൈൽ ഹോട്ട്‌സ്‌പോട്ട് ഓണാക്കി."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"സ്ക്രീൻ കാസ്‌റ്റുചെയ്യൽ നിർത്തി."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ഡിസ്പ്ലേ തെളിച്ചം"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"സെല്ലുലാർ ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"നിങ്ങൾ സജ്ജീകരിച്ചിരിക്കുന്ന പരിധിയിൽ എത്തിച്ചേർന്നിരിക്കുന്നതിനാൽ ഉപകരണം ഡാറ്റ ഓഫുചെയ്‌തു.\n\nഅത് തിരികെ ഓണാക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കീടാക്കുന്നതിന് ഇടയാക്കാം."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ഡാറ്റ ഓണാക്കുക"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങൾ നേരത്തെ ക്രമീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗം, ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾക്ക് ഇടയാക്കാം."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-നായി തിരയുന്നു"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"ഡേഡ്രീം"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ഇതർനെറ്റ്"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ഫ്ലൈറ്റ് മോഡ്"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ശല്ല്യപ്പെടുത്തരുത്"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"മുൻഗണന മാത്രം"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"തടസ്സങ്ങളൊന്നുമില്ല"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ബ്ലൂടൂത്ത്"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ബ്ലൂടൂത്ത് (<xliff:g id="NUMBER">%d</xliff:g> ഉപകരണങ്ങൾ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ബ്ലൂടൂത്ത് ഓഫുചെയ്യുക"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"പൂർത്തിയാക്കി"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"കണക്‌റ്റുചെയ്‌തു"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"കണക്റ്റുചെയ്യുന്നു..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ടെതറിംഗ്"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ഹോട്ട്‌സ്‌പോട്ട്"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"സ്ക്രീൻ പിൻ ചെയ്യൽ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"എല്ലാ അപ്ലിക്കേഷനുകളും നിരസിക്കുക"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്‌ക്കണോ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"അടുത്ത തവണ നിങ്ങൾ അത് ക്രമീകരണങ്ങളിൽ ഓണാക്കുമ്പോൾ അത് വീണ്ടും ദൃശ്യമാകും."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"മറയ്‌ക്കുക"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗ് ആകാൻ താൽപ്പര്യപ്പെടുന്നു."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"അനുവദിക്കുക"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"നിരസിക്കുക"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ആദ്യത്തേത് പുനഃസ്ഥാപിക്കാൻ സ്‌പർശിക്കുക."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index b215ac7..4c32722 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -25,10 +25,8 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Апп мэдээлэл"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Таны саяхны дэлгэц энд харагдах болно"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Сүүлийн апп-уудыг хаах"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Тойм дээр 1 дэлгэц"</item>
-    <item quantity="other" msgid="5523506463832158203">"Тойм дээрх %d дэлгэц"</item>
-  </plurals>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for status_bar_accessibility_recent_apps (9138535907802238759) -->
     <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>
@@ -88,7 +86,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"тайлах"</string>
     <string name="phone_label" msgid="2320074140205331708">"утас нээх"</string>
     <string name="camera_label" msgid="7261107956054836961">"камер нээх"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Блютүүт холбогдсон."</string>
@@ -159,6 +156,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>-г хаах."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> байхгүй."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Хамгийн сүүлийн бүх програмыг арилгасан байна."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж байна."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Мэдэгдэл хаагдсан."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Мэдэгдлийн хураангуй самбар"</string>
@@ -176,6 +174,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Нислэгийн горим идэвхтэй."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Нислэгийн горимыг унтраасан."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Нислэгийн горимыг асаасан."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Бүү саад болно уу.Зөвхөн чухал зүйлст."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Бүү саад болно уу. Аливаа саад учруулахгүй байна уу."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Бүү саад бол."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Идэвхгүй болгох үйлдэлд бүү саад бол."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Идэвхжүүлэх үйлдэлд бүү саад бол."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Блютүүт идэвхгүй."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Блютүүт идэвхтэй."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Блютүүтийг холбож байна."</string>
@@ -200,12 +203,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобайл хотспотыг асаасан."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Дэлгэц дамжуулалт зогссон."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дэлгэцийн гэрэлтэлт"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Үүрэн дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Таны тогтоосон хязгаарт хүрсэн учир төхөөрөмж датаг унтраасан.\n\nҮүнийг асааснаар таны төлбөр нэмэгдэхэд хүргэж болзошгүй."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Датаг асаах"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS хайж байна"</string>
@@ -224,6 +227,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Нислэгийн горим"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Бүү саад бол"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Зөвхөн чухал зүйлс"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Аливаа саад байхгүй байх"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Блютүүт"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Блютүүт (<xliff:g id="NUMBER">%d</xliff:g> төхөөрөмж)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Блютүүт унтраалттай"</string>
@@ -261,7 +267,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Өөр тохиргоо"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Дууссан"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Холбогдсон"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Холбогдож байна..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Модем болгох"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Сүлжээний цэг"</string>
@@ -279,6 +284,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"дэлгэц тогтоох"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Бүх програмыг арилгах"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</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>
@@ -362,4 +374,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Тохируулгын хэсэгт үүнийг асаахад энэ дахин харагдана."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Нуух"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог болохыг хүсч байна."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Зөвшөөрөх"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Татгалзах"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Анхны хувилбарыг эргүүлэн хадгалахыг хүсвэл хүрнэ үү."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index e7ecaa4..544d3d2 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"अॅप माहिती"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"आपल्या अलीकडील स्क्रीन येथे दिसतात"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"अलीकडील अॅप्स डिसमिस करा"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"विहंगावलोकनात 1 स्क्रीन"</item>
-    <item quantity="other" msgid="5523506463832158203">"विहंगावलोकनात %d स्क्रीन"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">विहंगावलोकनात %d स्क्रीन</item>
+      <item quantity="other">विहंगावलोकनात %d स्क्रीन</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"अनलॉक करा"</string>
     <string name="phone_label" msgid="2320074140205331708">"फोन उघडा"</string>
     <string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्‍या स्‍क्रीनवर झूम करा."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब कनेक्‍ट केले."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> डिसमिस करा."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अनुप्रयोग डिसमिस झाले."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"विमान मोड चालू."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"विमान मोड बंद केला."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"विमान मोड चालू केला."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"व्यत्यय आणू नका चालू, केवळ प्राधान्य."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"व्यत्यय आणू नका चालू, कोणताही व्यत्यय नाही."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"व्यत्यय आणू नका बंद."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"व्यत्यय आणू नका बंद करा"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"व्यत्यय आणू नका चालू करा"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ब बंद."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ब चालू."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ब कनेक्ट करत आहे."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाईल हॉटस्पॉट चालू केला."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रीन कास्ट करणे थांबले."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेल्युलर डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"डेटाने आपण सेट  केलेली मर्यादा गाठल्‍यामुळे आपल्‍या डिव्‍हाइसने तो बंद केला.\n\n तो पुन्‍हा चालू केल्‍यास आपल्‍या वाहकाकडील शुल्‍क लागू शकेल."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा चालू करा"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS शोधत आहे"</string>
@@ -224,7 +229,10 @@
     <string name="start_dreams" msgid="7219575858348719790">"डेड्रीम"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"इथरनेट"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"विमान मोड"</string>
-    <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"व्यत्यय आणू नका"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"केवळ प्राधान्य"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कोणतेही व्यत्यय नाही"</string>
+    <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब (<xliff:g id="NUMBER">%d</xliff:g> डिव्हाइसेस)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब बंद"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"कोणतेही जोडलेले डिव्हाइसेस उपलब्ध नाहीत"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"अधिक सेटिंग्ज"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण झाले"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट केलेले"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करीत आहे..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्‍क्रीन पिन करणे"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सर्व अनुप्रयोग डिसमिस करा"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"आपण सेटिंग्जमध्ये ते पुढील वेळी चालू कराल तेव्हा ते पुन्हा दिसेल."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लपवा"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद होऊ इच्छितो."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमती द्या"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"नकार द्या"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद आहे"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूळ पुनर्संचयित करण्यासाठी स्पर्श करा."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 67c23d6..968624a 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Maklumat aplikasi"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Skrin terbaru anda terpapar di sini"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Buang aplikasi terbaharu"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 skrin dalam Ikhtisar"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skrin dalam Ikhtisar"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d skrin dalam Gambaran Keseluruhan</item>
+      <item quantity="one">1 skrin dalam Gambaran Keseluruhan</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
     <string name="phone_label" msgid="2320074140205331708">"buka telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth disambungkan."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ketepikan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ditolak."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Semua aplikasi terbaharu diketepikan."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Memulakan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bidai pemberitahuan."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Mod pesawat dihidupkan."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Mod pesawat dimatikan."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Mod pesawat dihidupkan."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Jangan ganggu dihidupkan, perkara penting sahaja."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Jangan ganggu dihidupkan, tiada gangguan."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Jangan ganggu dimatikan."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Jangan ganggu dimatikan."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Jangan ganggu dihidupkan."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth dimatikan."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth dihidupkan."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth menyambung."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Tempat liputan mudah alih bergerak dihidupkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Penghantaran skrin dihentikan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan paparan"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G dimatikan"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G dimatikan"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data selular dimatikan"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data dimatikan"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Peranti anda mematikan data kerana telah mencapai had yang anda tetapkan.\n\nMenghidupkan data semula boleh menyebabkan anda dikenakan caj oleh pembawa anda."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Hidupkan data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Lamun"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod kapal terbang"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Jangan ganggu"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Keutamaan sahaja"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tiada gangguan"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Peranti)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Dimatikan"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Lagi tetapan"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Disambungkan"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Disambungkan melalui Pembantu Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Penambatan"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tempat liputan"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"penyematan skrin"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ketepikan semua aplikasi"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Mesej itu akan terpapar semula pada kali seterusnya anda menghidupkan apl dalam tetapan."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sembunyikan"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> mahu menjadi dialog kelantangan."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Benarkan"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ialah dialog kelantangan"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan yang asal."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 1b425ef..9e03b40 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"အပ်ပလီကေးရှင်း အချက်အလက်များ"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"သင်၏ မကြာမီက မျက်နှာပြင်များ ဒီမှာ ပေါ်လာကြမည်"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"လတ်တလောအပ်ပလီကေးရှင်းများအား ဖယ်ထုတ်မည်"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"ခြုံကြည့်မှု ထဲက မျက်နှာပြင် ၁ ခု"</item>
-    <item quantity="other" msgid="5523506463832158203">"ခြုံကြည့်မှု ထဲက မျက်နှာပြင် %d ခု"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">ခြုံကြည့်မှုထဲမှ မျက်နှာပြင် %d ခု</item>
+      <item quantity="one">ခြုံကြည့်မှုထဲမှ မျက်နှာပြင် 1 ခု</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"သော့ဖွင့်ရန်"</string>
     <string name="phone_label" msgid="2320074140205331708">"ဖုန်းကို ဖွင့်ရန်"</string>
     <string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံ့ဝင်သောချုံ့ချဲ့ခလုတ်"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ချဲ့ခြင်း"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ကို ပယ်လိုက်ရန်"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ထုတ်ထားသည်။"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"မကြာသေးမီက အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်ပြီးပါပြီ။"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ကို စတင်နေသည်။"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"အ​ကြောင်းကြားစာအကွက်"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"လေယာဉ် မုဒ်ကို ဖွင့်ထား။"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"လေယာဉ် မုဒ်ကို ပိတ်ထားလိုက်ပြီ။"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"လေယာဉ် မုဒ်ကို ဖွင့်ထားလိုက်ပြီ။"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"မနှောင့်ယှက်ပါနှင့် ဖွင့်ထားသည်၊ ဦးစားပေးများသာ။"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"မနှောင့်ယှက်ပါနှင့် ဖွင့်ထားသည်၊ အနှောင့်အယှက်များ မရှိပါ။"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"မနှောင့်ယှက်ပါနှင့် ကိုပိတ်ထားသည်။"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"မနှောင့်ယှက်ပါနှင့် ကိုပိတ်ထားသည်။"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"မနှောင့်ယှက်ပါနှင့်ကို ဖွင့်ထားသည်။"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ဘလူးတုသ် ပိတ်ထား."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ဘလူးတုသ် ဖွင့်ထား။"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ဘလူးတုသ် ချိတ်ဆက်နေ။"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"မိုဘိုင်း ဟော့စပေါ့ ဖွင့်ထား။"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"မျက်နှာပြင် ကာစ်တင် လုပ်မှု ရပ်လိုက်ပြီ။"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"တောက်ပမှုကို ပြရန်"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ဆယ်လူလာ ဒေတာကို ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"သင်၏ ကိရိယာသည် သင်က သတ်မှတ်ခဲ့သည့် ကန့်သတ်ချက်ကို ပြည့်မီသွား၍ ပိတ်သွားသည်။ \n\n၎င်းကို ပြန်ပြီး ဖွင့်မှုအတွက် သင်၏ စီမံပေးသူ ထံမှ ငွေတောင်းခံ လာနိုင်ပါသည်။"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ဒေတာ ဖွင့်ပေးရန်"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSအားရှာဖွေသည်"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"ဒေးဒရင်းမ်"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"အီသာနက်"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"လေယာဥ်ပျံပေါ်အသုံးပြုသောစနစ်"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"မနှောက်ယှက်ပါနှင့်"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ဦးစားပေးများသာ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ကြားဖြတ်ဝင်မှု ခွင့်မပြုရန်"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ဘလူးတု"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ဘလူးတု (<xliff:g id="NUMBER">%d</xliff:g> စက်များ)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ဘလူးတု ပိတ်ထားရန်"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"လုပ်ပြီး"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"ချိတ်ဆက်ထား"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်ပြီး၏"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"ဆက်သွယ်နေ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"တွဲချီပေးခြင်း"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ဟော့စပေါ့"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"မျက်နှာပြင် ပင်ထိုးမှု"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"အပလီကေးရှင်းများအားလုံး ဖယ်ထုတ်မည်"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"−"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"..."</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"နောက်တစ်ကြိမ်သင် ချိန်ညှိချက်များဖွင့်လျှင် ၎င်းပေါ်လာပါမည်။"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ဖျောက်ထားမည်"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည်အသံဒိုင်ယာလော့ခ်ဖြစ်လိုပါသည်။"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ခွင့်ပြုသည်"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ငြင်းပယ်သည်"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အသံဒိုင်ယာလော့ခ်ဖြစ်သည်"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"မူရင်းအားပြန်လည်သိမ်းဆည်းရန် ထိပါ။"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a99b3d0..a4c6a8e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info om appen"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"De sist brukte skjermene dine vises her"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Avvis nylige apper"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 skjerm i Oversikten"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skjermer i Oversikten"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d skjermer i oversikten</item>
+      <item quantity="one">1 skjerm i oversikten</item>
+    </plurals>
     <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">"Varsler"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås opp"</string>
     <string name="phone_label" msgid="2320074140205331708">"åpne telefonen"</string>
     <string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Avvis <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> avvist."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle nylig brukte apper er avvist."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starter <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Varselet ble skjult."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Varselskygge."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flymodus er på."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flymodus er slått av."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flymodus er slått på."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"«Ikke forstyrr» er på – bare prioritert."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"«Ikke forstyrr» er på – ingen avbrytelser."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"«Ikke forstyrr» er av."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"«Ikke forstyrr» er slått av."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"«Ikke forstyrr» er slått på."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth er av."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth er på."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth kobler til."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil Wi-Fi-sone er slått på."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjermcastingen er stoppet."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Lysstyrken på skjermen"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G- og 3G-data er slått av"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-datatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildatatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Datatrafikk er slått av på enheten din fordi du har nådd den angitte grensen.\n\nHvis du slår datatrafikken på igjen, kan det føre til belastninger fra operatøren din."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Slå på datatrafikk"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- og 3G-data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flymodus"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"«Ikke forstyrr»"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Bare prioritet"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ingen forstyrrelser"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth er slått av"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Flere innstillinger"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Ferdig"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Tilkoblet"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Koblet til via en Wi-Fi-assistent"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Kobler til …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tilknytning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Wi-Fi-sone"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"én-appsmodus"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Avvis alle apper"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igjen neste gang du slår den på i innstillingene."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ønsker å være volumdialogen."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Tillat"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ikke tillat"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er volumdialogen"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Trykk for å gå tilbake til den opprinnelige volumdialogen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index e30f49f..a6869a5 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"अनुप्रयोगको जानकारी"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"तपाईँको हालको स्क्रिन यहाँ प्रकट हुन्छ"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"नयाँ अनुप्रयोगहरू खारेज गर्नुहोस्"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"सारांशमा 1 पर्दा"</item>
-    <item quantity="other" msgid="5523506463832158203">"सारांशमा %d पर्दाहरू"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other"> अवलोकनमा %d स्क्रिनहरू</item>
+      <item quantity="one">अवलोकनमा 1 स्क्रिन</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"खोल्नुहोस्"</string>
     <string name="phone_label" msgid="2320074140205331708">"फोन खोल्नुहोस्"</string>
     <string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> खारेज गर्नुहोस्।"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> खारेज गरिएको छ।"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"सबै हालका अनुप्रयोगहरू खारेज गरियो।"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>सुरु गर्दै।"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारेज।"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना कक्ष।"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"हवाइजहाज मोड खुला।"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"हवाइजहाज मोड बन्द छ।"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"हवाइजहाज मोड खोलियो।"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"प्राथमिकतालाई मात्र बाधा नपुर्‍याउनुहोस्।"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"बाधा नपुर्याउँनुहोस्, कुनै पनि अवरोध छैनन्।"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"निष्क्रियलाई बाधा नपुर्‍याउनुहोस्"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"निष्क्रिय गरिएकालाई अवरोध नपुर्‍याउनुहोस्।"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"सक्रिय रहेकोलाई अवरोध नपुर्‍याउनुहोस्।"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"ब्लुटुथ बन्द छ।"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"ब्लुटुथ खुला छ।"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"ब्लुटुथ जोडीदै।"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हटस्पट खुला गरियो।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रिन कास्टिङ रोकियो।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेलुलर डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"तपाईंले सेट गर्नु भएको सीमा पुगेको हुनाले तपाईंको उपकरणले डेटा बंद गर्यो।\n\n यसलाई फिर्ता गर्दा आफ्नो वाहक बाट शुल्क लिन सक्छ।"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा खोल्नुहोस्"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डेटाको सीमा पुगेकाले, यन्त्रले यस चक्रको बाँकी भागका लागि डेटा प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइफाइ जडित"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"दिवासपना"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाइजहाज मोड"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"बाधा नपुर्याउँनुहोस्"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"प्राथमिकता मात्र"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कुनै अवरोधहरू छैन"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लुटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लुटुथ (<xliff:g id="NUMBER">%d</xliff:g> उपकरणहरू)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ब्लुटुथ बन्द"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"थप सेटिङहरू"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"भयो"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"जोडिएको"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi-Fi सहायक द्वारा जोडिएको"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"जडान हुँदै..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदर गर्दै"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हटस्पट"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"स्क्रिन पिन गर्दै"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"सबै अनुप्रयोगहरू खारेज गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अनुकूलन विभाजन गर्नुहोस्"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"यो तपाईं सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लुकाउनुहोस्"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> भोल्यूम संवाद बन्न चाहन्छ।"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमति दिनुहोस्"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार गर्नुहोस्"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> भोल्यूम संवाद हो"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल पुनर्स्थापना गर्न छुनुहोस्।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 060b1c5..d69cf29 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-info"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Uw recente schermen worden hier weergegeven"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Recente apps negeren"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 scherm in Overzicht"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d schermen in Overzicht"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d schermen in Overzicht</item>
+      <item quantity="one">1 scherm in Overzicht</item>
+    </plurals>
     <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>
@@ -44,7 +44,7 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Accubesparing inschakelen"</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>
+    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPEN"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ontgrendelen"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefoon openen"</string>
     <string name="camera_label" msgid="7261107956054836961">"camera openen"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-verbinding ingesteld."</string>
@@ -145,7 +144,7 @@
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wifi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Geen simkaart."</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-tethering."</string>
-    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegmodus."</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Vliegtuigmodus."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Accu: <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systeeminstellingen."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Meldingen."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> sluiten."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> verwijderd."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alle recente apps gesloten."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> starten."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Melding verwijderd."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Meldingenpaneel."</string>
@@ -172,10 +172,15 @@
     <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi ingeschakeld."</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobiel <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Accu: <xliff:g id="STATE">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegmodus uit."</string>
-    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegmodus aan."</string>
-    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegmodus uitgeschakeld."</string>
-    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegmodus ingeschakeld."</string>
+    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Vliegtuigmodus uit."</string>
+    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Vliegtuigmodus aan."</string>
+    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Vliegtuigmodus uitgeschakeld."</string>
+    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus ingeschakeld."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Niet storen aan, alleen prioriteit."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Niet storen aan, geen onderbrekingen."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Niet storen uit."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Niet storen uitgeschakeld."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Niet storen ingeschakeld."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth uit."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth aan."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth-verbinding wordt gemaakt."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiele hotspot ingeschakeld."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casten van scherm gestopt."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiele data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Gegevens zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Uw apparaat heeft gegevens uitgeschakeld omdat de ingestelde limiet is bereikt.\n\nAls u gegevens weer inschakelt, kan uw provider kosten in rekening brengen."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Gegevens inschakelen"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan uw provider kosten in rekening brengen."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar GPS"</string>
@@ -223,7 +228,10 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertshowcase"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdroom"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegmodus"</string>
+    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Niet storen"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Alleen prioriteit"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekingen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> apparaten)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth uit"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellingen"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gereed"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Verbonden"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Verbonden via wifi-assistent"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Verbinding maken…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"scherm vastzetten"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Alle apps sluiten"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Deze wordt opnieuw weergegeven zodra u de instelling weer inschakelt."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Verbergen"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil het volumedialoogvenster zijn."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Toestaan"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a68d076..4e43853 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacje o aplikacji"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Tutaj pojawią się ostatnie ekrany"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ukryj ostatnie aplikacje"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ekran w widoku przeglądu"</item>
-    <item quantity="other" msgid="5523506463832158203">"Ekrany w widoku przeglądu: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="few">%d ekrany w widoku przeglądu</item>
+      <item quantity="many">%d ekranów w widoku przeglądu</item>
+      <item quantity="other">%d ekranu w widoku przeglądu</item>
+      <item quantity="one">1 ekran w widoku przeglądu</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odblokuj"</string>
     <string name="phone_label" msgid="2320074140205331708">"otwórz telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"otwórz aparat"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth połączony."</string>
@@ -159,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Usuń stąd <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g>: zamknięto."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Wszystkie ostatnie aplikacje zostały zamknięte."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Uruchamiam <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Obszar powiadomień."</string>
@@ -176,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Tryb samolotowy jest włączony."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Tryb samolotowy został wyłączony."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Tryb samolotowy został włączony."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Nie przeszkadzać (włączone, tylko priorytetowe)."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Nie przeszkadzać (włączone, bez przeszkadzania)."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Nie przeszkadzać (wyłączone)."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Nieprzeszkadzanie wyłączone."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Nieprzeszkadzanie włączone."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth wyłączony."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth włączony."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Nawiązywanie połączenia Bluetooth."</string>
@@ -200,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilny hotspot został włączony."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Zatrzymano przesyłanie ekranu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jasność wyświetlacza"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Połączenie danych 2G-3G wyłączone"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Połączenie danych 4G wyłączone"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Komórkowe połączenie danych jest wyłączone"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Połączenie danych jest wyłączone"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Połączenie danych na Twoim urządzeniu zostało wyłączone, ponieważ osiągnęło ustalony limit.\n\nJeśli włączysz je ponownie, operator może naliczyć opłaty."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Włącz połączenie danych"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Transmisja danych 2G-3G została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
@@ -224,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Wygaszacz ekranu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nie przeszkadzać"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tylko priorytetowe"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez przeszkadzania"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (urządzenia: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth wył."</string>
@@ -249,7 +259,7 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi wyłączone"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Brak dostępnych zapisanych sieci"</string>
-    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Przesyłaj ekran"</string>
+    <string name="quick_settings_cast_title" msgid="1893629685050355115">"Prześlij ekran"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Przesyłam"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Urządzenie bez nazwy"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Wszystko gotowe do przesyłania"</string>
@@ -261,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Więcej ustawień"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Gotowe"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Połączono"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Połączono przez Asystenta Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Łączę..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Powiązanie"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Punkt dostępu"</string>
@@ -279,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"przypinanie ekranu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Zamknij wszystkie aplikacje"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładowanie"</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>
@@ -362,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Pojawi się ponownie, gdy następnym włączysz go w ustawieniach."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ukryj"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> chce sterować głośnością."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Zezwól"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmów"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> steruje głośnością"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotknij, by przywrócić pierwotną."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index db1528e..ff7d2d6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informações da aplicação"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Os ecrãs recentes aparecem aqui"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ignorar aplicações recentes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ecrã na Visão geral"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ecrãs na Visão geral"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d ecrãs na Vista geral</item>
+      <item quantity="one">1 ecrã na Vista geral</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir telemóvel"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ignorar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ignorado."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todas as aplicações recentes foram ignoradas."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"A iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação ignorada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Painel de notificações."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modo de avião ligado."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modo de avião desligado."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo de avião ligado."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Não incomodar ligado, apenas prioridade."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Não incomodar ligado, sem interrupções."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Não incomodar desligado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Não incomodar desligado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Não incomodar ligado."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desligado."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth ligado."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"A ligar o Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona Wi-Fi móvel ligada."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmissão do ecrã interrompida."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho do visor"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dados 2G-3G desligados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dados 4G desligados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dados de rede móvel desligados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dados desligados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desligou os dados porque atingiu o limite definido.\n\nVoltar a ligá-los pode resultar em cobranças por parte do operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ligar dados"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dados 2G-3G em pausa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avião"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Não incomodar"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Apenas prioridade"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sem interrupções"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desat."</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais definições"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ligado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ligado através do Assistente de Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"A ligar..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Associação"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação no ecrã"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ignorar todas as aplicações"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Reaparecerá da próxima vez que a funcionalidade for ativada nas definições."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> pretende ser a caixa de diálogo do volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Recusar"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo do volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 87eb2db..1acdace 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informações do app"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Suas telas recentes aparecem aqui"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Dispensar apps recentes"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 tela em \"Visão geral\""</item>
-    <item quantity="other" msgid="5523506463832158203">"%d telas em \"Visão geral\""</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d telas em \"Visão geral\"</item>
+      <item quantity="other">%d telas em \"Visão geral\"</item>
+    </plurals>
     <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>
@@ -86,9 +86,8 @@
     <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefone"</string>
     <string name="accessibility_unlock_button" msgid="128158454631118828">"Desbloquear"</string>
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
-    <string name="phone_label" msgid="2320074140205331708">"abrir smartphone"</string>
+    <string name="phone_label" msgid="2320074140205331708">"abrir telefone"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Descartar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> descartado."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Todos os apps recentes foram dispensados."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iniciando <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Aba de notificações."</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modo avião ativado."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"O modo avião foi desativado."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"O modo avião foi ativado."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Não perturbe\" ativado, somente prioridade."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Não perturbe\" ativado, sem interrupções."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Não perturbe\" desativado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Não perturbe\" desativado."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Não perturbe\" ativado."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desativado."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth ativado."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Conectando Bluetooth."</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A transmissão de tela foi interrompida."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os dados 2G-3G foram desativados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os dados 4G foram desativados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os dados da rede celular foram desativados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os dados foram desativados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desativou os dados porque o limite definido foi atingido.\n\nAtivá-los novamente poderá resultar em cobranças de sua operadora."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ativar dados"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avião"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Não perturbe"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Só prioridade"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sem interrupções"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desativado"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mais configurações"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conectado via assistente de Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Dispensar todos os apps"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</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>
@@ -299,8 +313,8 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
     <string name="notification_tap_again" msgid="8524949573675922138">"Toque novamente para abrir"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
-    <string name="phone_hint" msgid="3101468054914424646">"Deslize para a direita para usar o telefone"</string>
-    <string name="camera_hint" msgid="5241441720959174226">"Deslize para a esquerda para usar a câmera"</string>
+    <string name="phone_hint" msgid="3101468054914424646">"Deslize à direita p/ usar o telefone"</string>
+    <string name="camera_hint" msgid="5241441720959174226">"Deslize à esquerda p/ usar a câmera"</string>
     <string name="interruption_level_none" msgid="3831278883136066646">"Nenhum"</string>
     <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridade"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ela reaparecerá na próxima vez que você ativá-la nas configurações."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> deseja ser a caixa de diálogo referente ao volume."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Negar"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo referente ao volume"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 76a33c5..71137b0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -25,10 +25,11 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informaţii despre aplicaţie"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ecranele dvs. recente apar aici"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Renunţaţi la aplicaţiile recente"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 ecran în Vizualizare generală"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d ecrane în Vizualizare generală"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="few">%d ecrane în Recente</item>
+      <item quantity="other">%d de ecrane în Recente</item>
+      <item quantity="one">Un ecran în Recente</item>
+    </plurals>
     <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>
@@ -88,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"deblocați"</string>
     <string name="phone_label" msgid="2320074140205331708">"deschideți telefonul"</string>
     <string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
@@ -159,6 +159,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Închideți <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> a fost eliminată."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toate aplicațiile recente au fost închise."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Se inițiază <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Fereastră pentru notificări."</string>
@@ -176,6 +177,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modul Avion este activat."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modul Avion este dezactivat."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modul Avion este activat."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Setarea „Nu deranja” este activată – numai prioritare."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Setarea „Nu deranja” este activată – fără întreruperi."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Setarea „Nu deranja” este dezactivată."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Setarea „Nu deranja” a fost dezactivată."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Setarea „Nu deranja” a fost activată."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Conexiunea prin Bluetooth este dezactivată."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Conexiunea prin Bluetooth este activată."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Se conectează prin Bluetooth."</string>
@@ -200,12 +206,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspotul mobil este activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmiterea ecranului a fost oprită."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminozitatea ecranului"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datele 2G-3G sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datele 4G sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datele mobile sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datele sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Dispozitivul dvs. a dezactivat conexiunea de date deoarece s-a atins limita pe care ați setat-o.\n\nReactivarea conexiunii poate genera aplicarea de taxe de către operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activați datele"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Conexiunea de date 2G – 3G este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string>
@@ -224,6 +230,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod Avion"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nu deranja"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Numai cu prioritate"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Fără întreruperi"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispozitive)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth dezactivat"</string>
@@ -261,7 +270,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mai multe setări"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Terminat"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Conectat"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Conexiune realizată printr-un asistent Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Se conectează..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +287,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Închideți toate aplicațiile"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</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>
@@ -362,4 +377,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Va reapărea la următoarea activare în setări."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ascundeți"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> dorește să afișeze caseta de dialog pentru volum."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permiteți"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuzați"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> afișează caseta de dialog pentru volum"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Atingeți pentru a reveni la setarea inițială."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index eeb9583..4ca33f6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -19,16 +19,18 @@
 
 <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="7164937344850004466">"Графический интерфейс системы"</string>
+    <string name="app_label" msgid="7164937344850004466">"Интерфейс системы"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Очистить"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Удалить из списка"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"О приложении"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Здесь будут показаны недавние приложения."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Закрыть недавние приложения"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"В обзоре 1 экран."</item>
-    <item quantity="other" msgid="5523506463832158203">"Экранов в обзоре: %d."</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">Показан %d экран</item>
+      <item quantity="few">Показано %d экрана</item>
+      <item quantity="many">Показано %d экранов</item>
+      <item quantity="other">Показано %d экранов</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"Разблокировать."</string>
     <string name="phone_label" msgid="2320074140205331708">"Открыть телефон."</string>
     <string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string>
@@ -161,6 +162,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Удаление приложения <xliff:g id="APP">%s</xliff:g> из списка."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" удалено из списка."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Все недавние приложения закрыты."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск приложения <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель уведомлений"</string>
@@ -178,6 +180,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Режим полета включен."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Режим полета отключен."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим полета включен."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не беспокоить\" включен. Будут показаны только важные оповещения."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Включен режим \"Не беспокоить\". Все оповещения отключены."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Режим \"Не беспокоить\" выключен."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Режим \"Не беспокоить\" выключен."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Режим \"Не беспокоить\" включен."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Модуль Bluetooth отключен."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Модуль Bluetooth включен."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth-соединение устанавливается."</string>
@@ -202,12 +209,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Точка доступа включена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляция прекращена."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркость экрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Передача данных 2G/3G отключена"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Передача данных 4G отключена"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Передача мобильных данных отключена"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Передача данных отключена"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Передача данных отключена, поскольку достигнут установленный вами лимит.\n\nВы можете снова включить ее, однако за переданные данные оператор может взимать дополнительную плату."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Включить передачу данных"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передача данных 2G и 3G приостановлена"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string>
@@ -226,6 +233,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не беспокоить"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Только важные"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без оповещений"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выкл."</string>
@@ -260,10 +270,9 @@
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Инвертировать"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"Коррекция цвета"</string>
-    <string name="quick_settings_more_settings" msgid="326112621462813682">"Дополнительные настройки"</string>
+    <string name="quick_settings_more_settings" msgid="326112621462813682">"Настройки"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Подключено"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Установлено подключение через Ассистента Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Соединение..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступа"</string>
@@ -281,6 +290,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Заблокировать в приложении"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Закрыть все приложения"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"–"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</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>
@@ -298,8 +314,8 @@
     <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="8524949573675922138">"Нажмите ещё раз, чтобы открыть"</string>
-    <string name="keyguard_unlock" msgid="8043466894212841998">"Для разблокировки проведите пальцем по экрану"</string>
-    <string name="phone_hint" msgid="3101468054914424646">"Чтобы открыть приложение \"Телефон\", пролистните вправо"</string>
+    <string name="keyguard_unlock" msgid="8043466894212841998">"Проведите вверх, чтобы разблокировать"</string>
+    <string name="phone_hint" msgid="3101468054914424646">"Чтобы позвонить, пролистните вправо"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string>
     <string name="interruption_level_none" msgid="3831278883136066646">"Не беспокоить"</string>
     <string name="interruption_level_priority" msgid="6517366750688942030">"Важные"</string>
@@ -364,4 +380,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Этот параметр появится в следующий раз, когда вы включите его."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Скрыть"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"Назначить приложение <xliff:g id="APP_NAME">%1$s</xliff:g> регулятором громкости?"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Да"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Нет"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> назначено регулятором громкости"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Нажмите, чтобы восстановить приложение по умолчанию."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 0256a66..003b784 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"යෙදුම් තොරතුරු"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"මෙහි ඔබගේ මෑතක තිර පෙන්නුම් කරයි"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"මෑත යෙදුම් ඉවතලන්න"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"දළ විශ්ලේෂණය තුළ 1 තීරයයි"</item>
-    <item quantity="other" msgid="5523506463832158203">"දළ විශ්ලේෂණය තුළ තීරයෙන් %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">විශ්ලේෂණය තුළ තිර %d යි</item>
+      <item quantity="other">විශ්ලේෂණය තුළ තිර %d</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"අඟුල අරින්න"</string>
     <string name="phone_label" msgid="2320074140205331708">"දුරකථනය විවෘත කරන්න"</string>
     <string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ඉවතලන්න."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> අස් කර ඇත."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"සියලුම මෑත යෙඳුම් අස් කරන ලදි."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කරමින්."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"දැනුම්දීම නිෂ්ප්‍රභා කරඇත."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"දැනුම්දීම් ආවරණය."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"අහස්යානා අකාරය අක්‍රියයි."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"බාධා නොකරන්න ක්‍රියාත්මකයි, ප්‍රමුඛතා පමණි."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"බාධා නොකරන්න ක්‍රියාත්මකයි, බාධා කිරීම් නැත."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"බාධා නොකරන්න ක්‍රියා විරහිතයි."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"බාධා නොකරන්න ක්‍රියා විරහිත කරන ලදි."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"බාධා නොකරන්න ක්‍රියාත්මක කරන ලදි"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"බ්ලූටූත් අක්‍රියයි."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"බ්ලූටූත් සක්‍රියයි."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"බ්ලූටූත් සම්බන්ධවෙමින්."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ජංගම හොට්ස්පොටය සක්‍රිය කරන ලදි."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"තිරය විකාශය කිරීම නැවත් වන ලදි."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"සෙලියුලර් දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ඔබ සකසන ලද දත්ත සීමාවට එය ළඟාවී ඇති නිසා ඔබගේ උපාංගයේ දත්ත අක්‍රිය කර ඇත.\n\nඑය නැවත සක්‍රිය කිරීමෙන් ඔබගේ වාහකය ඇතැම් විට අය කර ගැනීමට හේතු වේ."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"දත්ත සක්‍රිය කරන්න"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්‍රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම් වලට පොළඹවනු ඇත."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"දවල් හීනය"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"අහස්යානා ආකාරය"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"බාධා නොකරන්න"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ප්‍රමුඛතාව පමණයි"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"බාධා කිරීම් නැත"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"බ්ලූටූත් අක්‍රියයි"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"තව සැකසීම්"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"නිමයි"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"සම්බන්ධිත"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"සම්බන්ධ වෙමින්..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ටෙදරින්"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"හොට්ස්පොට්"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"සියලුම යෙදුම් අස් කරන්න"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> සඟවන්නද?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ඊළඟ අවස්ථාවේ සැකසීම් තුළ ඔබ එය සක්‍රිය කළ විට එය නැවත දිසිවේ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"සඟවන්න"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> හට ධාරිතා සංවාදය වීමට අවශ්‍යයි"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ඉඩ දෙන්න"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ප්‍රතික්ෂේප කරන්න"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"මුල් තත්ත්වය නැවත ප්‍රතිසාධනය කිරීමට ස්පර්ශ කරන්න."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0a27b91..fa68d55 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informácie o aplikácii"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Vaše nedávne obrazovky sa zobrazia tu."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Zatvoriť nedávne aplikácie"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Počet obrazoviek v Prehľade: 1"</item>
-    <item quantity="other" msgid="5523506463832158203">"Počet obrazoviek v Prehľade: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="few">%d obrazovky v Prehľade</item>
+      <item quantity="many">%d obrazovky v Prehľade</item>
+      <item quantity="other">%d obrazoviek v Prehľade</item>
+      <item quantity="one">1 obrazovka v Prehľade</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odomknúť"</string>
     <string name="phone_label" msgid="2320074140205331708">"otvoriť telefón"</string>
     <string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth pripojené."</string>
@@ -161,6 +162,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Zrušiť aplikáciu <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikácia <xliff:g id="APP">%s</xliff:g> bola zrušená."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Všetky nedávne aplikácie boli odmietnuté."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Spúšťa sa aplikácia <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel upozornení."</string>
@@ -178,6 +180,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Režim v lietadle je zapnutý."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Režim v lietadle je vypnutý."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Režim v lietadle je zapnutý."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stav Nerušiť je zapnutý, iba prioritné."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stav Nerušiť je zapnutý, žiadne prerušenia."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stav Nerušiť je vypnutý."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stav Nerušiť je vypnutý."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stav Nerušiť je zapnutý."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Rozhranie Bluetooth je vypnuté."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Rozhranie Bluetooth je zapnuté."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Rozhranie Bluetooth sa pripája."</string>
@@ -202,12 +209,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilný hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Prenášanie bolo zastavené."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeja"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"dáta 2G–3G sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"dáta 4G sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilné dáta sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dáta sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Zariadenie vyplo dáta, pretože dosiahlo limit, ktorý ste nastavili.\n\nAk ich znova zapnete, môže to viesť k účtovaniu poplatkov operátora."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Zapnúť dáta"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dátové prenosy 2G a 3G sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string>
@@ -226,6 +233,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Šetrič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim v lietadle"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nerušiť"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Iba prioritné"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Žiadne prerušenia"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Rozhranie Bluetooth (počet zariadení: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhranie Bluetooth je vypnuté"</string>
@@ -263,7 +273,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Ďalšie nastavenia"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Pripojené"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Pripojené pomocou Asistenta Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Pripája sa..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Zdieľanie dátového pripojenia"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -281,6 +290,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripnutie k obrazovke"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Odmietnuť všetky aplikácie"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</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>
@@ -364,4 +380,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Táto položka sa znova zobrazí, keď ju v nastaveniach opätovne zapnete."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skryť"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> chce byť dialógom hlasitosti"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Povoliť"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmietnuť"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialóg hlasitosti"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4bd5ddd..d70ca47 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Podatki o aplikaciji"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Vaši nedavni zasloni so prikazani tu"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Zapre nedavne aplikacije"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"En zaslon v Pregledu"</item>
-    <item quantity="other" msgid="5523506463832158203">"Št. zaslonov v Pregledu: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d zaslon v pregledu</item>
+      <item quantity="two">%d zaslona v pregledu</item>
+      <item quantity="few">%d zasloni v pregledu</item>
+      <item quantity="other">%d zaslonov v pregledu</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odkleni"</string>
     <string name="phone_label" msgid="2320074140205331708">"odpri telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"odpri fotoaparat"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Povezava Bluetooth vzpostavljena."</string>
@@ -159,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Opusti aplikacijo <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je bila odstranjena."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Vse nedavne aplikacije so bile opuščene."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Zaganjanje aplikacije <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon z obvestili."</string>
@@ -176,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Način za letalo je vklopljen."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Način za letalo je izklopljen."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način za letalo je vklopljen."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Način »ne moti« je vklopljen, samo prednostno."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Način »ne moti« je vklopljen, ni prekinitev."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Način »ne moti« je izklopljen."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Način »ne moti« je izklopljen."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Način »ne moti« je vklopljen."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth je izklopljen."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth je vklopljen."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Povezava Bluetooth se vzpostavlja."</string>
@@ -200,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna dostopna točka je vklopljena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Predvajanje zaslona je ustavljeno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svetlost zaslona"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Prenos podatkov v omrežjih 2G/3G je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Prenos podatkov v omrežjih 4G je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Prenos podatkov v mobilnih omrežjih je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Prenos podatkov je izklopljen"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Naprava je izklopila prenos podatkov, ker je bila dosežena omejitev, ki ste jo nastavili.\n\nČe prenos spet vklopite, vam bo operater morda zaračunal stroške."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Vklopi prenos podatkov"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Prenos podatkov v omrežju 2G/3G je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string>
@@ -224,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarjenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način za letalo"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne moti"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prednostno"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Brez prekinitev"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (št. naprav: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth izklopljen"</string>
@@ -261,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Več nastavitev"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Končano"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Povezava je vzpostavljena"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Vzpostavljanje povezave ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internet prek mobilne naprave"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Dostopna točka"</string>
@@ -279,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripenjanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Opusti vse aplikacije"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</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>
@@ -362,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Znova se bo pojavila, ko jo naslednjič vklopite v nastavitvah."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skrij"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> želi biti pogovorno okno glede prostornine."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dovoli"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Zavrni"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pogovorno okno glede prostornine"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotaknite se, če želite obnoviti izvirnik."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8a15b9f..ca87db0 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -25,10 +25,11 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Информације о апликацији"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Недавни екрани се појављују овде"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Одбаци недавне апликације"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 екран у Прегледу"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d екрана у Прегледу"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d екран у Прегледу</item>
+      <item quantity="few">%d екрана у Прегледу</item>
+      <item quantity="other">%d екрана у Прегледу</item>
+    </plurals>
     <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>
@@ -88,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"откључај"</string>
     <string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"отвори камеру"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth је прикључен."</string>
@@ -159,6 +159,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Одбаците <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Апликација <xliff:g id="APP">%s</xliff:g> је одбачена."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Све недавно коришћене апликације су одбачене."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Покрећемо <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Прозор са обавештењима."</string>
@@ -176,6 +177,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Режим рада у авиону је укључен."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Режим рада у авиону је искључен."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим рада у авиону је укључен."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Подешавање Не узнемиравај је укључено, само приоритетни прекиди."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Подешавање Не узнемиравај је укључено, без прекида."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Подешавање Не узнемиравај је искључено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Подешавање Не узнемиравај је искључено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Подешавање Не узнемиравај је укључено."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth је искључен."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth је укључен."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth се повезује."</string>
@@ -200,12 +206,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилни хотспот је укључен."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Пребацивање екрана је заустављено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветљеност екрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G подаци су искључени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G подаци су искључени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилни пренос података је искључен"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Пренос података је искључен"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Уређај је искључио пренос података јер је достигао ограничење које сте поставили.\n\nАко га поново укључите, можда ће вам мобилни оператер наплатити трошкове."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Укључи пренос података"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Тражи се GPS"</string>
@@ -224,6 +230,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Сањарење"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим рада у авиону"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не узнемиравај"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само приоритетни прекиди"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекида"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уређаја)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth искључен"</string>
@@ -261,7 +270,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Још подешавања"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Повезан"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Повезано преко Wi‑Fi помоћника"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Повезује се..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Повезивање"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Хотспот"</string>
@@ -279,6 +287,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"качење екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Одбаци све апликације"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</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>
@@ -362,4 +377,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Желите ли да сакријете <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ово ће се поново појавити када га следећи пут будете укључили у подешавањима."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сакриј"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> жели да буде дијалог за јачину звука."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Дозволи"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> је дијалог за јачину звука"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Додирните да бисте вратили оригинал."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ea2c07a..07e0ef7 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Info om appen"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Dina senaste skärmar visas här"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Avvisa nya appar"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"En skärm i Översikten"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d skärmar i Översikten"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d skärmar i översikten</item>
+      <item quantity="one">En skärm i översikten</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås upp"</string>
     <string name="phone_label" msgid="2320074140205331708">"öppna mobilen"</string>
     <string name="camera_label" msgid="7261107956054836961">"öppna kameran"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ansluten."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ta bort <xliff:g id="APP">%s</xliff:g> från listan."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> togs bort permanent."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Alla appar har tagits bort från listan Senaste."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Startar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Meddelandepanel."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flygplansläge på."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flygplansläget har inaktiverats."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flygplansläget har aktiverats."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stör ej har aktiverats. Endast prioriterade."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stör ej har aktiverats. Inga avbrott."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stör ej av."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stör ej har inaktiverats."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stör ej har aktiverats."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth av."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth på."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Ansluter Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Den mobila trådlösa surfzonen har aktiverats."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Castningen av skärmen har stoppats."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skärmens ljusstyrka"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-/3G-data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildata har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Data har stängts av på enheten eftersom den angivna gränsen har uppnåtts.\n\nOm du aktiverar den igen kan avgifter från operatören tillkomma."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktivera uppgifter"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- och 3G-data har pausats"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Dagdröm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flygplansläge"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Stör ej"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Endast prioriterade"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Inga avbrott"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth av"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Fler inställningar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Klart"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ansluten"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ansluten via Wi-Fi-assistent"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ansluter ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internetdelning"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Trådlös surfzon"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fästa skärmen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ta bort alla appar"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</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>
@@ -289,7 +303,7 @@
     <string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Inga avbrott. Inte ens alarm."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Inga avbrott"</string>
-    <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade avbrott"</string>
+    <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade samtal och aviseringar"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Nästa alarm är kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nästa alarm är <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Alarmet kommer inte att höras kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den visas på nytt nästa gång du aktiverar den i inställningarna."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Dölj"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> försöker överta funktionen som volymkontroll."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Tillåt"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neka"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> används som volymkontroll"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryck här om du vill återställa den ursprungliga appen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 6b4d4af..70764d9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Taarifa za programu-matumizi"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Skrini zako za hivi majuzi huonekana hapa"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha programu za hivi karibuni"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Skrini 1 katika Muhtasari"</item>
-    <item quantity="other" msgid="5523506463832158203">"Skrini %d katika Muhtasari"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">Skrini %d katika Muhtasari</item>
+      <item quantity="one">Skrini 1 katika Muhtasari</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"fungua"</string>
     <string name="phone_label" msgid="2320074140205331708">"fungua simu"</string>
     <string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Ondoa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> imeondolewa."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Programu za hivi majuzi zimeondolewa."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Inaanzisha <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Arifa imetupwa."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Kivuli cha arifa."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Hali ya ndegeni imewashwa."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Hali ya ndegeni imezimwa."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Hali ya ndegeni imewashwa."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Kipengee cha usinisumbue kimewashwa, kipaumbele pekee."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Kipengee cha usinisumbue kimewashwa, hakuna kukatizwa."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Kipengee cha usinisumbue kimezimwa."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Kipengee cha usinisumbue kimezimwa."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Kipengee cha usinisumbue kimewashwa."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth imezimwa."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth imewashwa."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth inaunganishwa."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mtandao-hewa unaoweza kuhamishika umewashwa."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Utumaji wa skrini umesitishwa."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ung\'aavu wa skrini"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data ya 2G-3G imezimwa"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data ya 4G imezimwa"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data ya simu ya mkononi imezimwa"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data imezimwa"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKuwasha data tena kunaweza kusababisha matozo kutoka kwa mtoa huduma wako."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Washa matumizi ya data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data ya 2G-3G imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Inatafuta GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Hali Tulivu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hali ya ndege"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Usinisumbue"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kipaumbele tu"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Hakuna kukatizwa"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (Vifaa <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Imezimwa"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Mipangilio zaidi"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Nimemaliza"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Imeunganishwa"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Inaunganisha..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Kusambaza mtandao"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Mtandao-hewa"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kudumisha programu moja"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Ondoa programu zote"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</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">"Imebakisha <xliff:g id="CHARGING_TIME">%s</xliff:g> ijae"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Itaonekana tena wakati mwingine utakapoiwasha katika mipangilio."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ficha"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> inataka kuwa mazungumzo ya sauti."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Ruhusu"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Kataa"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ni mazungumzo ya sauti"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Gusa ili urejeshe ya awali."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 27c2c6d..782a16f 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"பயன்பாட்டுத் தகவல்"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"சமீபத்திய திரைகள் இங்கு தோன்றும்"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"சமீபத்திய பயன்பாடுகளை நிராகரி"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"மேலோட்டப் பார்வையில் 1 திரை"</item>
-    <item quantity="other" msgid="5523506463832158203">"மேலோட்டப் பார்வையில் %d திரைகள்"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">மேலோட்டப் பார்வையில் %d திரைகள்</item>
+      <item quantity="one">மேலோட்டப் பார்வையில் 1 திரை</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"திற"</string>
     <string name="phone_label" msgid="2320074140205331708">"ஃபோனைத் திற"</string>
     <string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> ஐ நிராகரி."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> விலக்கப்பட்டது."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"எல்லா சமீபத்திய பயன்பாடுகளும் விலக்கப்பட்டன."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ஐத் தொடங்குகிறது."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"அறிவிப்பு விவரம்."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"விமானப் பயன்முறை இயக்கத்தில்."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"விமானப் பயன்முறை முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"விமானப் பயன்முறை இயக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது, முதன்மை மட்டும்."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது, குறுக்கீடுகள் இல்லை."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"தொந்தரவு செய்ய வேண்டாம் என்பது முடக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"தொந்தரவு செய்ய வேண்டாம் என்பது முடக்கப்பட்டது."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"புளூடூத் முடக்கத்தில்."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"புளூடூத் இயக்கத்தில்."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"புளூடூத் இணைக்கப்படுகிறது."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"மொபைல் ஹாட்ஸ்பாட் இயக்கப்பட்டது."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"திரையை அனுப்புதல் நிறுத்தப்பட்டது."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"திரை பிரகாசம்"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"செல்லுலார் தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"தரவு இணைப்பு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"அமைத்த வரம்பை மீறிவிட்டதால், சாதனம் தரவு இணைப்பை முடக்கியது.\n\nஇதை மீண்டும் இயக்கினால், மொபைல் நிறுவனம் விதிக்கும் கட்டணங்கள் பொருந்தலாம்."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"தரவு இணைப்பை இயக்கு"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G டேட்டா இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ஐத் தேடுகிறது"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"பகல்கனா"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ஈதர்நெட்"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"விமானப் பயன்முறை"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"தொந்தரவு செய்ய வேண்டாம்"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"முதன்மை மட்டும்"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"குறுக்கீடுகள் வேண்டாம்"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"புளூடூத்"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"புளூடூத் (<xliff:g id="NUMBER">%d</xliff:g> சாதனங்கள்)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"புளூடூத் ஐ முடக்கு"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"அமைப்பில் மாற்று"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"முடிந்தது"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"இணைக்கப்பட்டது"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"இணைக்கிறது..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"டெதெரிங்"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ஹாட்ஸ்பாட்"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"திரையை பின் செய்தல்"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"எல்லா பயன்பாடுகளையும் விலக்கு"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"அடுத்த முறை அமைப்புகளில் மீண்டும் இயக்கும்போது, இது மீண்டும் தோன்றும்."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"மறை"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>, ஒலியளவு செய்தியாகச் செயல்பட விரும்புகிறது."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"அனுமதி"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"நிராகரி"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"ஒலியளவு செய்தி: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"அசலை மீட்டமைக்கத் தொடவும்."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index bc7edb2..5014213 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"అనువర్తన సమాచారం"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"మీ ఇటీవలి స్క్రీన్‌లు ఇక్కడ కనిపిస్తాయి"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ఇటీవలి అనువర్తనాలను తీసివేయండి"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"అవలోకనంలో 1 స్క్రీన్ ఉంది"</item>
-    <item quantity="other" msgid="5523506463832158203">"అవలోకనంలో %d స్క్రీన్‌లు ఉన్నాయి"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">స్థూలదృష్టిలో %d స్క్రీన్‌లు ఉన్నాయి</item>
+      <item quantity="one">స్థూలదృష్టిలో 1 స్క్రీన్ ఉంది</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"అన్‌లాక్ చేయి"</string>
     <string name="phone_label" msgid="2320074140205331708">"ఫోన్‌ను తెరువు"</string>
     <string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g>ని తీసివేయండి."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> తీసివేయబడింది."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"అన్ని ఇటీవలి అనువర్తనాలు తీసివేయబడ్డాయి."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభిస్తోంది."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"నోటిఫికేషన్ తీసివేయబడింది."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"నోటిఫికేషన్ షేడ్."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ఎయిర్‌ప్లైన్ మోడ్ ఆన్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ఎయిర్‌ప్లైన్ మోడ్ ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ఎయిర్‌ప్లైన్ మోడ్ ఆన్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"అంతరాయం కలిగించవద్దు ఆన్‌లో ఉంది, ప్రాధాన్యత మాత్రమే."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"అంతరాయం కలిగించవద్దు ఆన్‌లో ఉంది, అంతరాయాలు ఉండవు."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"అంతరాయం కలిగించవద్దు ఆఫ్‌లో ఉంది."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"అంతరాయం కలిగించవద్దు ఆఫ్ చేయబడింది."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"బ్లూటూత్ ఆఫ్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"బ్లూటూత్ ఆన్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"బ్లూటూత్ కనెక్ట్ అవుతోంది."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"మొబైల్ హాట్‌స్పాట్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"స్క్రీన్ ప్రసారం ఆపివేయబడింది."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ప్రదర్శన ప్రకాశం"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"సెల్యూలార్ డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"మీ పరికరం మీరు సెట్ చేసిన పరిమితిని చేరుకున్నందున డేటాను ఆఫ్ చేసింది.\n\nదీన్ని తిరిగి ఆన్ చేయడం వలన మీ క్యారియర్‌ను బట్టి ఛార్జీలు పడవచ్చు."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"డేటాను ఆన్ చేయి"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్‌లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS కోసం శోధిస్తోంది"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"డేడ్రీమ్"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ఈథర్‌నెట్"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ఎయిర్‌ప్లేన్ మోడ్"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"అంతరాయం కలిగించవద్దు"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ప్రాధాన్యత మాత్రమే"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"అంతరాయాలు ఉండవు"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"బ్లూటూత్"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"బ్లూటూత్ (<xliff:g id="NUMBER">%d</xliff:g> పరికరాలు)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"బ్లూటూత్ ఆఫ్‌లో ఉంది"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"పూర్తయింది"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"కనెక్ట్ చేయబడినది"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"కనెక్ట్ అవుతోంది..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"టీథరింగ్"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"హాట్‌స్పాట్"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"స్క్రీన్ పిన్నింగ్"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"అన్ని అనువర్తనాలను తీసివేయి"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"మీరు సెట్టింగ్‌ల్లో దీన్ని ఆన్ చేసిన తదుపరిసారి ఇది కనిపిస్తుంది."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"దాచు"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్‌గా ఉండాలనుకుంటోంది."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"అనుమతించు"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"తిరస్కరించు"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"అసలుదాన్ని పునరుద్ధరించడానికి తాకండి."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c5e0e6a..5331df8 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ข้อมูลแอปพลิเคชัน"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"หน้าจอล่าสุดของคุณแสดงที่นี่"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"ปิดแอปพลิเคชันล่าสุด"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 หน้าจอในภาพรวม"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d หน้าจอในภาพรวม"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d หน้าจอในภาพรวม</item>
+      <item quantity="one">1 หน้าจอในภาพรวม</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ปลดล็อก"</string>
     <string name="phone_label" msgid="2320074140205331708">"เปิดโทรศัพท์"</string>
     <string name="camera_label" msgid="7261107956054836961">"เปิดกล้อง"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"เชื่อมต่อบลูทูธแล้ว"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"ยกเลิก <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ถูกลบไปแล้ว"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"ปิดแอปพลิเคชันล่าสุดทั้งหมดแล้ว"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"กำลังเริ่มต้น <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"หน้าต่างแจ้งเตือน"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"โหมดบนเครื่องบินเปิดอยู่"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ปิดโหมดบนเครื่องบินแล้ว"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"เปิดโหมดบนเครื่องบินแล้ว"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"การห้ามรบกวนเปิดอยู่ เฉพาะเรื่องสำคัญเท่านั้น"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"การห้ามรบกวนเปิดอยู่ ห้ามรบกวน"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"การห้ามรบกวนปิดอยู่"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ปิดการห้ามรบกวนแล้ว"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"เปิดการห้ามรบกวนแล้ว"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"บลูทูธปิดอยู่"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"บลูทูธเปิดอยู่"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"กำลังเชื่อมต่อบลูทูธ"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"เปิดฮอตสปอตเคลื่อนที่แล้ว"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"หยุดการส่งหน้าจอแล้ว"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ความสว่างของหน้าจอ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ข้อมูล 2G-3G ปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ข้อมูล 4G ปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ข้อมูลมือถือปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ข้อมูลปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"อุปกรณ์ของคุณปิดการใช้ข้อมูลเนื่องจากถึงขีดจำกัดที่คุณตั้งค่าไว้\n\nผู้ให้บริการอาจเรียกเก็บเงินหากเปิดใช้อีกครั้ง"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"เปิดใช้ข้อมูล"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"หยุดการใช้ข้อมูล 2G-3G ชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"กำลังค้นหา GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"เดย์ดรีม"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"อีเทอร์เน็ต"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"โหมดใช้บนเครื่องบิน"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ห้ามรบกวน"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"เฉพาะเรื่องสำคัญ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ไม่มีการรบกวน"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"บลูทูธ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"บลูทูธ (<xliff:g id="NUMBER">%d</xliff:g> อุปกรณ์)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ปิดบลูทูธ"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"การตั้งค่าเพิ่มเติม"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"เสร็จสิ้น"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"เชื่อมต่อ"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"กำลังเชื่อมต่อ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"การปล่อยสัญญาณ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ฮอตสปอต"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"การตรึงหน้าจอ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"ปิดแอปพลิเคชันทั้งหมด"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ซ่อน <xliff:g id="TILE_LABEL">%1$s</xliff:g> ไหม"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"จะปรากฏอีกครั้งเมื่อคุณเปิดใช้ในการตั้งค่าครั้งถัดไป"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ซ่อน"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ต้องการเป็่นช่องโต้ตอบระดับเสียง"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"อนุญาต"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ปฏิเสธ"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> เป็นช่องโต้ตอบระดับเสียง"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"แตะเพื่อคืนค่าดั้งเดิม"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b870c7a..e7a0ca5 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Impormasyon ng app"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Lumalabas dito ang iyong kamakailang screen"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Huwag pansinin ang kamakailang apps"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 screen sa Overview"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d (na) screen sa Overview"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d screen sa Pangkalahatang-ideya</item>
+      <item quantity="other">%d na screen sa Pangkalahatang-ideya</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"i-unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"buksan ang telepono"</string>
     <string name="camera_label" msgid="7261107956054836961">"buksan ang camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Nakakonekta ang Bluetooth."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"I-dismiss ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Hindi pinansin ang <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Na-dismiss ang lahat ng kamakailang application."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Sinisimulan ang <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Naka-on ang Airplane mode."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Na-off ang Airplane mode."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Na-on ang Airplane mode."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Naka-on ang huwag istorbohin, priyoridad lang."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Naka-on ang huwag istorbohin, walang mga paggambala."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Naka-off ang huwag istorbohin."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Na-off na ang huwag istorbohin"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Na-on na ang huwag istorbohin."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Naka-off ang Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Naka-on ang Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Kumokonekta ang Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Na-on ang mobile hotspot."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Itinigil ang pagka-cast sa screen."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Liwanag ng display"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Naka-off ang 2G-3G data"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Naka-off ang 4G data"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Naka-off ang cellular data"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Naka-off ang data"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Ini-off ng device mo ang data dahil naabot na nito ang limitasyong iyong itinakda.\n\nAng muling pag-o-on dito ay maaaring humantong sa mga singiling magmumula sa iyong carrier."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"I-on ang data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Naka-pause ang 2G-3G data"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Naghahanap ng GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Airplane mode"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Huwag istorbohin"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priyoridad lang"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Walang mga paggambala"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> (na) Device)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Naka-off ang Bluetooth"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Marami pang setting"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Tapos na"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Nakakonekta"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Kumokonekta..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Nagte-tether"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pagpi-pin sa screen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"I-dismiss ang lahat ng application"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Lalabas itong muli sa susunod na pagkakataon na i-on mo ito sa mga setting."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Itago"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"Gusto ng <xliff:g id="APP_NAME">%1$s</xliff:g> na maging volume dialog."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Payagan"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tanggihan"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ang volume dialog"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Pindutin upang ibalik ang orihinal."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 03ddc46..b6396d9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Uygulama bilgileri"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Son ekranlarınız burada görünür"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Son uygulamaları kapat"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Genel Bakış\'ta 1 ekran"</item>
-    <item quantity="other" msgid="5523506463832158203">"Genel Bakış\'ta %d ekran"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">Genel Bakış\'ta %d ekran</item>
+      <item quantity="one">Genel Bakış\'ta 1 ekran</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"kilidi aç"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefonu aç"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string>
@@ -144,7 +143,7 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Kablosuz"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"SIM kart yok."</string>
-    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth İnternet paylaşımı"</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth tethering"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Uçak modu."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Pil yüzdesi: <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistem ayarları."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> uygulamasını kapat."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> kaldırıldı."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Tüm son uygulamalar kapatıldı."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> başlatılıyor."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bildirim gölgesi."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Uçak modu açık."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Uçak modu kapatıldı."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Uçak modu açıldı."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Rahatsız etmeyin ayarı açık, yalnızca öncelikliler."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Rahatsız etmeyin ayarı açık, kesme yok."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Rahatsız etmeyin\" ayarı kapalı."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Rahatsız etmeyin\" ayarı kapalı."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Rahatsız etmeyin\" ayarı açık."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth kapalı."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth açık."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth bağlanıyor."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil hotspot açıldı."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekran yayını durduruldu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran parlaklığı"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Hücresel veri kapalı"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Ayarladığınız sınıra erişildiğinden cihazınız veri kullanımını kapattı.\n\nVeri kullanımını tekrar açmanız operatörünüzün ek ödemeler almasına neden olabilir."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Veri kullanımını aç"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Hafif uyku"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Uçak modu"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Rahatsız etmeyin"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Yalnızca öncelikliler"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Kesme yok"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Kapalı"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Diğer ayarlar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Bitti"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Bağlı"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Bağlanılıyor..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sabitleme"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Tüm uygulamaları kapat"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizle"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olmak istiyor."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"İzin ver"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Reddet"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Orijinali geri yüklemek için dokunun."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 133954e..a384785 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -25,10 +25,12 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Про додаток"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Ваші останні екрани відображаються тут"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Відхилити останні програми"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"Показано 1 екран"</item>
-    <item quantity="other" msgid="5523506463832158203">"Показано екранів: %d"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">На панелі огляду %d екран</item>
+      <item quantity="few">На панелі огляду %d екрани</item>
+      <item quantity="many">На панелі огляду %d екранів</item>
+      <item quantity="other">На панелі огляду %d екрана</item>
+    </plurals>
     <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>
@@ -88,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"розблокувати"</string>
     <string name="phone_label" msgid="2320074140205331708">"відкрити телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
@@ -159,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Видалити додаток <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Програму <xliff:g id="APP">%s</xliff:g> закрито."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Усі останні додатки закрито."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Запуск додатка <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель сповіщень."</string>
@@ -176,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Режим польоту ввімк."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Режим польоту вимкнено."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим польоту ввімкнено."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не турбувати\" ввімкнено, лише пріоритетні."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Режим \"Не турбувати\" ввімкнено, без сповіщень."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Режим \"Не турбувати\" вимкнено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Режим \"Не турбувати\" вимкнено."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Режим \"Не турбувати\" ввімкнено."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth вимк."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth увімк."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Під’єднання Bluetooth."</string>
@@ -200,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобільну точку доступу ввімкнено."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляцію екрана зупинено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яскравість дисплея"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Дані 2G–3G вимкнено"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Дані 4G вимкнено"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобільні дані вимкнено"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дані вимкнено"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки перевищено встановлений вами ліміт.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати додаткову плату."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Увімкнути дані"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передавання даних 2G–3G призупинено"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string>
@@ -224,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим польоту"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не турбувати"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Лише пріоритетні"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без сповіщень"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (пристроїв: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth вимкнено"</string>
@@ -261,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Більше налаштувань"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Під’єднано"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"З’єднання…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступу"</string>
@@ -279,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"закріпити екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Закрити всі додатки"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</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>
@@ -362,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сховати"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"Призначити додаток <xliff:g id="APP_NAME">%1$s</xliff:g> регулятором гучності?"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Дозволити"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Відхилити"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> призначено регулятором гучності"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Торкніться, щоб відновити оригінал."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index f34a685..ae10600 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"ایپ کی معلومات"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"آپ کی حالیہ اسکرینز یہاں ظاہر ہوتی ہیں"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"حالیہ ایپس برخاست کریں"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"مجموعی جائزہ میں 1 اسکرین"</item>
-    <item quantity="other" msgid="5523506463832158203">"‏مجموعی جائزہ میں ‎%d اسکرینز"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">‏عمومی جائزہ میں ‎%d اسکرینز</item>
+      <item quantity="one">عمومی جائزہ میں 1 اسکرین</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"غیر مقفل کریں"</string>
     <string name="phone_label" msgid="2320074140205331708">"فون کھولیں"</string>
     <string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"<xliff:g id="APP">%s</xliff:g> کو مسترد کریں۔"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> کو ہٹا دیا گیا۔"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"سبھی حالیہ ایپلیکیشنز کو برخاست کر دیا گیا۔"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> شروع ہو رہی ہے۔"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اطلاع مسترد ہوگئی۔"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"اطلاعاتی شیڈ۔"</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"ہوائی جہاز وضع آن ہے۔"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"ہوائی جہاز وضع کو آف کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ہوائی جہاز وضع کو آن کر دیا گیا۔"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ڈسٹرب نہ کریں آن ہے، صرف ترجیحی۔"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ڈسٹرب نہ کریں آن ہے، کوئی مداخلتیں نہیں۔"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ڈسٹرب نہ کریں آف ہے۔"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ڈسٹرب نہ کریں کو آف کر دیا گیا۔"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ڈسٹرب نہ کریں کو آن کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"بلوٹوتھ آف ہے۔"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"بلوٹوتھ آن ہے۔"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"بلوٹوتھ منسلک ہو رہا ہے۔"</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"موبائل ہاٹ اسپاٹ کو آن کر دیا گیا۔"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"اسکرین کو کاسٹ کرنا بند کر دیا۔"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ڈسپلے کی چمک"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏2G-3G ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏4G ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"سیلولر ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کی متعینہ حد کو پہنچ گیا۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ڈیٹا آن کریں"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏2G-3G ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏GPS کی تلاش کر رہا ہے"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ایتھرنیٹ"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ہوائی جہاز طرز"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ڈسٹرب نہ کریں"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"صرف ترجیحی"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"کوئی مداخلتیں نہیں"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوٹوتھ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوٹوتھ (<xliff:g id="NUMBER">%d</xliff:g> آلات)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوٹوتھ آف ہے"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"مزید ترتیبات"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"ہو گیا"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"مربوط"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"مربوط ہو رہا ہے…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"مربوط کرنا"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ہاٹ اسپاٹ"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"اسکرین کو پن کرنا"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"سبھی ایپلیکیشنز کو برخاست کریں"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"چھپائیں"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ بننا چاہتی ہے۔"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"اجازت دیں"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"مسترد کریں"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"اصل کو بحال کرنے کیلئے ٹچ کریں۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 8b8fedc..d83ab3a 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Ilova xaqida"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Yaqinda ish-gan ilovalar bu yerda ko‘rinadi"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"So‘nggi dasturlarni tozalash"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"“Umumiy nazar” oynasida 1 ta ekran bor"</item>
-    <item quantity="other" msgid="5523506463832158203">"“Umumiy nazar” oynasida %d ta ekran bor"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">Umumiy ma’lumot bo‘limida %d ta ekran bor</item>
+      <item quantity="one">Umumiy ma’lumot bo‘limida 1 ta ekran bor</item>
+    </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Eslatmalar - yo‘q"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Joriy"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Eslatmalar"</string>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"qulfdan chiqarish"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefonni ochish"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Olib tashlash: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> olib tashlangan."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Yaqinda ishlatilgan barcha ilovalar olib tashlandi."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> ishga tushirilmoqda."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Xabarnoma e‘tiborsiz qoldirildi."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Xabarnoma soyasi."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Parvoz rejimi yoqilgan."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Parvoz rejimi o‘chirildi."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Parvoz rejimi yoqildi."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"“Bezovta qilinmasin” funksiyasi yoqilgan, faqat muhim bildirishnomalar ko‘rsatiladi."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"“Bezovta qilinmasin” funksiyasi yoqilgan, bezovta qilinmaydi."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"“Bezovta qilinmasin” funksiyasi o‘chirilgan."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"“Bezovta qilinmasin” funksiyasi o‘chirildi."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"“Bezovta qilinmasin” funksiyasi yoqildi."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth o‘chirilgan."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth yoqilgan."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth ulanmoqda."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil ulanish nuqtasi yoqildi."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekranni translatsiya qilish to‘xtadi."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran yorqinligi"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobil internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Siz o‘rnatgan chegaraga yetib kelgani tufayli qurilmangizda internet o‘chirib qo‘yildi.\n\nUni qayta yoqishingiz mumkin, biroq buning uchun aloqa operatoringiz qo‘shimcha haq olishi mumkin."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Internetni yoqish"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G internet to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS qidirilmoqda"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Tush kurish"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Parvoz rejimi"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Bezovta qilinmasin"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Faqat muhimlari"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tanaffuslarsiz"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>ta qurilma)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth o‘chirilgan"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Boshqa sozlamalar"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Tayyor"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ulangan"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Wi‑Fi yordamchisi orqali ulangan"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ulanmoqda…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Modem rejimi"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ulanish nuqtasi"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekranni qadab qo‘yish"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Barcha ilovalarni olib tashlash"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Quvvat olmoqda"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Berkitish"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ovoz balandligini boshqarmoqchi."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Ruxsat berish"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rad etish"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ovoz balandligini boshqaradi"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Aslini tiklash uchun bosing."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f92116d..781e8d0 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Thông tin về ứng dụng"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Màn hình gần đây của bạn sẽ xuất hiện tại đây"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Loại bỏ các ứng dụng gần đây"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 màn hình trong Tổng quan"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d màn hình trong Tổng quan"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">%d màn hình trong Tổng quan</item>
+      <item quantity="one">1 màn hình trong Tổng quan</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"mở khóa"</string>
     <string name="phone_label" msgid="2320074140205331708">"mở điện thoại"</string>
     <string name="camera_label" msgid="7261107956054836961">"mở máy ảnh"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Đã kết nối bluetooth."</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Xóa bỏ <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> đã bị loại bỏ."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Đã bỏ qua tất cả các ứng dụng gần đây."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Bắt đầu <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bóng thông báo."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Chế độ trên máy bay bật."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Đã tắt chế độ trên máy bay."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Đã bật chế độ trên máy bay."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Bật tính năng không làm phiền, chỉ ưu tiên."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Bật tính năng không làm phiền, không có gián đoạn."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Tắt tính năng không làm phiền."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Đã tắt tính năng không làm phiền."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Đã bật tính năng không làm phiền."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth tắt."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth bật."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Đang kết nối Bluetooth."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Đã bật điểm phát sóng di động."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Đã ngừng truyền màn hình."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Độ sáng màn hình"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dữ liệu 2G-3G bị tắt"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dữ liệu 4G bị tắt"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dữ liệu di động bị tắt"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dữ liệu bị tắt"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn đã tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Bật dữ liệu"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Đã tạm dừng dữ liệu 2G-3G"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vì bạn đã đạt tới giới hạn dữ liệu thiết lập nên thiết bị đã tạm dừng sử dụng dữ liệu cho phần còn lại của chu kỳ này.\n\nTiếp tục có thể dẫn tới nhà cung cấp dịch vụ của bạn sẽ tính phí."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Chế độ ngủ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Chế độ trên máy bay"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Không làm phiền"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Chỉ ưu tiên"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Không có gián đoạn nào"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> thiết bị)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Đã tắt Bluetooth"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Cài đặt khác"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Xong"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Đã kết nối"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Đang kết nối..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Đang dùng làm điểm truy cập Internet"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Điểm phát sóng"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"khóa màn hình"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Bỏ qua tất cả các ứng dụng"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Thông báo này sẽ xuất hiện lại vào lần tiếp theo bạn bật thông báo trong cài đặt."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ẩn"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> muốn trở thành hộp thoại khối lượng."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Cho phép"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Từ chối"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> là hộp thoại khối lượng"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Chạm để khôi phục bản gốc."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c3811f8..d12e309 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"应用信息"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"您最近浏览过的屏幕会显示在此处"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"关闭最近运行的应用"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"概览中有 1 个屏幕"</item>
-    <item quantity="other" msgid="5523506463832158203">"概览中有 %d 个屏幕"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">概览中有 %d 个屏幕</item>
+      <item quantity="one">概览中有 1 个屏幕</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解锁"</string>
     <string name="phone_label" msgid="2320074140205331708">"打开电话"</string>
     <string name="camera_label" msgid="7261107956054836961">"打开相机"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"蓝牙已连接。"</string>
@@ -143,7 +142,7 @@
     <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"漫游中"</string>
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"EDGE"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"WLAN"</string>
-    <string name="accessibility_no_sim" msgid="8274017118472455155">"无SIM卡。"</string>
+    <string name="accessibility_no_sim" msgid="8274017118472455155">"无 SIM 卡。"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"蓝牙网络共享。"</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"飞行模式。"</string>
     <!-- String.format failed for translation -->
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"移除<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"已删除<xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"已关闭所有最近用过的应用。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在启动<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知栏。"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"飞行模式开启。"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"飞行模式已关闭。"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飞行模式已开启。"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"勿扰模式已开启,仅限优先打扰。"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"勿扰模式已开启,禁止打扰。"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"勿扰模式关闭。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已关闭勿扰模式。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已开启勿扰模式。"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"蓝牙关闭。"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"蓝牙开启。"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"蓝牙连接中。"</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"移动热点已开启。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"屏幕投射已停止。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"屏幕亮度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"移动数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"由于数据流量已达到您所设置的上限,因此您的设备已关闭数据网络。\n\n如果重新开启数据网络,那么您的运营商可能会向您收取相应费用。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"开启数据网络"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"互动屏保"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"有线网络"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飞行模式"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"勿扰"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"仅限优先打扰"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"禁止打扰"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"蓝牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已连接"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已连接(通过 WLAN 助手)"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"正在连接…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"网络共享"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"热点"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"固定屏幕"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"关闭所有应用"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下次在设置中将其开启后,此快捷设置条目将会重新显示。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隐藏"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”请求用作音量控制对话框。"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允许"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒绝"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"触摸即可恢复原始设置。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7532520..aeb7111 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資訊"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"您最近的螢幕顯示在這裡"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"關閉最近使用的應用程式"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"概覽中有 1 個畫面"</item>
-    <item quantity="other" msgid="5523506463832158203">"概覽中有 %d 個畫面"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">概覽中有 %d 個畫面</item>
+      <item quantity="one">概覽中有 1 個畫面</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解鎖"</string>
     <string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
     <string name="camera_label" msgid="7261107956054836961">"開啟相機"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"所有最近使用的應用程式均已關閉。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知已關閉。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"飛行模式已開啟。"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"飛行模式已關閉。"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飛行模式已開啟。"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"開啟「請勿騷擾」,僅限優先。"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"開啟「請勿騷擾」,不允許干擾。"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"「請勿騷擾」關閉"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已關閉「請勿騷擾」。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已開啟「請勿騷擾」。"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"藍牙已關閉。"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"藍牙已開啟。"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"正在建立藍牙連線。"</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"流動熱點已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"顯示光暗度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"流動數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"數據流量已達到您所設定的上限,因此裝置關閉了數據連線。\n\n若重新開啟數據連線,流動網絡供應商可能會向您收費。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"開啟數據連線"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。\n\n如恢復使用數據,流動網絡供應商可能會向您收取費用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"以太網"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛行模式"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"請勿騷擾"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"僅限優先"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"不允許干擾"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 部裝置)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"藍牙關閉"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已透過 Wi-Fi 小幫手連線"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"正在連線…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網絡共享"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"熱點"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"關閉所有應用程式"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下一次您在設定開啟它時,它將再次出現。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」想成為音量對話框。"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允許"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸即可復原。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 082a92e..b7079f8 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資訊"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"您最近的螢幕會顯示在這裡"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"關閉最近使用的應用程式"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"總覽中有 1 個畫面"</item>
-    <item quantity="other" msgid="5523506463832158203">"總覽中有 %d 個畫面"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="other">總覽中有 %d 個畫面</item>
+      <item quantity="one">總覽中有 1 個畫面</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解除鎖定"</string>
     <string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
     <string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -161,6 +160,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"關閉「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"「<xliff:g id="APP">%s</xliff:g>」已關閉。"</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"最近使用的應用程式已全部關閉。"</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"正在啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
@@ -178,6 +178,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"飛航模式已開啟。"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"飛航模式已關閉。"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飛航模式已開啟。"</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"「零打擾」設定為開啟,只會顯示優先通知。"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"「零打擾」設定為開啟,不接受任何干擾。"</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"「零打擾」設定為關閉。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已停用「零打擾」設定。"</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已啟用「零打擾」設定。"</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"藍牙已關閉。"</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"藍牙已開啟。"</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"正在建立藍牙連線。"</string>
@@ -202,12 +207,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"可攜式無線基地台已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"螢幕亮度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"行動數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"數據流量已達您所設定的上限,因此裝置關閉了數據連線。\n\n如果重新開啟數據連線,行動通訊業者可能會向您收費。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"開啟數據連線"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據連線"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取額外的連線費用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
@@ -226,6 +231,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"休眠模式"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"乙太網路"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛航模式"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"零打擾"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"僅顯示優先通知"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"無干擾"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 個裝置)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"關閉藍牙"</string>
@@ -263,7 +271,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"已透過 Wi‑Fi 小幫手連線"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"連線中..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網路共用"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"無線基地台"</string>
@@ -281,6 +288,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"螢幕固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"關閉所有應用程式"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</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>
@@ -364,4 +378,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」要求成為預設的音量控制對話方塊。"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允許"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸這裡即可恢復原始設定。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b3572a2..51ba633 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -25,10 +25,10 @@
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Ulwazi lwensiza"</string>
     <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Izikrini zakho zakamuva zivela lapha"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Susa izinhlelo zokusebenza zakamumva"</string>
-  <plurals name="status_bar_accessibility_recent_apps">
-    <item quantity="one" msgid="3969335317929254918">"1 isikrini esiku-Buka konke"</item>
-    <item quantity="other" msgid="5523506463832158203">"%d wezikrini eziku-Buka konke"</item>
-  </plurals>
+    <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+      <item quantity="one">%d izikrini eziku-Buka konke</item>
+      <item quantity="other">%d izikrini eziku-Buka konke</item>
+    </plurals>
     <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>
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"vula"</string>
     <string name="phone_label" msgid="2320074140205331708">"vula ifoni"</string>
     <string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string>
@@ -159,6 +158,7 @@
     <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Cashisa i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> ivaliwe."</string>
+    <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Zonke izinhlelo zokusebenza zakamuva zicashisiwe."</string>
     <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Iqala i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Isaziso sichithiwe."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Umthunzi wesaziso."</string>
@@ -176,6 +176,11 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Imodi yendiza ivuliwe."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Imodi yendiza ivaliwe."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Imodi yendiza ivuliwe."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Ukungaphazamisi kuvuliwe, okubalulekile kuphela."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Ungaphazamisi, akukho ukuphazamiseka."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Ukungaphazamisi kuvaliwe."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Ukungaphazamisi kuvaliwe."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Ukungaphazamisi kuvuliwe."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"I-Bluetooth ivaliwe."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"I-Bluetooth ivuliwe."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"I-Bluetooth iyaxhuma."</string>
@@ -200,12 +205,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"I-hotspot ivuliwe."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ukusakaza kwesikrini kumisiwe."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bonisa ukukhanya"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Idatha ye-2G-3G ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Idatha ye-4G ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Idatha yeselula ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Idatha ivaliwe"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Idivayisi yakho ivale idatha ngoba ifinyelele umkhawulo owubekile.\n\nUkuyivula futhi kungaholela ezindlekweni kusuka kunkampani yakho yenethiwekhi."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Vula idatha"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Isesha i-GPS"</string>
@@ -224,6 +229,9 @@
     <string name="start_dreams" msgid="7219575858348719790">"Ukuphupha emini"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"I-Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Isimo sendiza"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ungaphazamisi"</string>
+    <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Okubalulekile kuphela"</string>
+    <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Azikho iziphazamiso"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"I-Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"I-Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> amadivayisi)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"I-Bluetooth ivaliwe"</string>
@@ -261,7 +269,6 @@
     <string name="quick_settings_more_settings" msgid="326112621462813682">"Izilungiselelo eziningi"</string>
     <string name="quick_settings_done" msgid="3402999958839153376">"Kwenziwe"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"Ixhunyiwe"</string>
-    <string name="quick_settings_connected_via_wfa" msgid="1587051627194895715">"Ixhunywe ngomsizi we-Wi-FI"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"Iyaxhuma..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ukusebenzisa njengemodemu"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"I-Hotspot"</string>
@@ -279,6 +286,13 @@
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ukuphina isikrini"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
+    <string name="recents_dismiss_all_message" msgid="8495275386693095768">"Cashisa zonke izinhlelo zokusebenza"</string>
+    <string name="recents_multistack_add_stack" msgid="5044995965068125420">"+"</string>
+    <string name="recents_multistack_remove_stack" msgid="3014058144068028841">"-"</string>
+    <string name="recents_multistack_resize_stack" msgid="5511174284568497822">"[]"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</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>
@@ -362,4 +376,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Izovela ngesikhathi esilandelayo uma uvule lesi silungiselelo."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fihla"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ifuna ukuba yingxoxo yevolumu."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Vumela"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Phika"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> yingxoxo yevolumu"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Thinta ukuze ubuyisele kokwangempela."</string>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a7783fc..d4aeab6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,7 +30,7 @@
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
+    <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
@@ -42,7 +42,8 @@
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
     <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
-    <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200-->
+    <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200 -->
+    <color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
     <color name="qs_detail_transition">#66FFFFFF</color>
     <color name="qs_detail_progress_track">#99009688</color><!-- 60% deep teal 500 -->
     <color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
@@ -129,4 +130,5 @@
     <color name="segmented_button_selected">#FFFFFFFF</color>
     <color name="segmented_button_unselected">#B3B0BEC5</color><!-- 70% blue grey 200 -->
     <color name="volume_panel_divider">#1FFFFFFF</color><!-- 12% white -->
+    <color name="light_mode_icon_color">#FF616161</color><!-- grey 700 -->
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a7a1cc5..2e9e9f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -118,7 +118,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
+        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
     </string>
 
     <!-- The tiles to display in QuickSettings -->
@@ -146,6 +146,9 @@
      before the app can interrupt again. -->
     <integer name="heads_up_default_snooze_length_ms">60000</integer>
 
+    <!-- Minimum display time for a heads up notification, in milliseconds. -->
+    <integer name="heads_up_notification_minimum_time">3000</integer>
+
     <!-- milliseconds before the heads up notification accepts touches. -->
     <integer name="heads_up_sensitivity_delay">700</integer>
 
@@ -222,11 +225,6 @@
          be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
     <string name="velocity_tracker_impl" translatable="false">platform</string>
 
-    <!-- Set to true to enable the classic notification ticker that scrolls
-         Notification.tickerText across the status bar for what seems like an
-         eternity. -->
-    <bool name="enable_ticker">false</bool>
-
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">false</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 44330e8..c24cd64 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -257,9 +257,8 @@
     <!-- The top offset for the task stack. -->
     <dimen name="recents_stack_top_padding">16dp</dimen>
 
-    <!-- Used to calculate the translation animation duration, the expected amount of movement 
-         in dps over one second of time. -->
-    <dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
+    <!-- The dimesnsions of the dismiss all recents button. -->
+    <dimen name="recents_dismiss_all_button_size">48dp</dimen>
 
     <!-- The min alpha to apply to a task affiliation group color. -->
     <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
@@ -377,6 +376,18 @@
     <!-- radius of the corners of the material rounded rect background but negative-->
     <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
 
+    <!-- height of the bottom decor below the notification if present (eg. an expand action) -->
+    <dimen name="notification_bottom_decor_height">48dp</dimen>
+
+    <!-- The padding between notification children -->
+    <dimen name="notification_children_padding">2dp</dimen>
+
+    <!-- The height of the divider between the notfication children -->
+    <dimen name="notification_children_divider_height">1dp</dimen>
+
+    <!-- The vertical distance from which the notification appear when children are expanded -->
+    <dimen name="notification_appear_distance">140dp</dimen>
+
     <!-- end margin for multi user switch in expanded quick settings -->
     <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
 
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 4a9eb55..3fc75d2 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -36,5 +36,16 @@
     <item type="id" name="height_animator_start_value_tag"/>
     <item type="id" name="doze_saved_filter_tag"/>
     <item type="id" name="qs_icon_tag"/>
+    <item type="id" name="scrim"/>
+    <item type="id" name="notification_power"/>
+    <item type="id" name="notification_screenshot"/>
+    <item type="id" name="notification_hidden"/>
+    <item type="id" name="notification_volumeui"/>
+
+    <!-- Whether the icon is from a notification for which targetSdk < L -->
+    <item type="id" name="icon_is_pre_L"/>
+
+    <!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
+    <item type="id" name="icon_is_grayscale" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 558d90a..d9aff44 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -392,6 +392,8 @@
     <string name="accessibility_recents_item_will_be_dismissed">Dismiss <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description to tell the user an application has been removed from recents -->
     <string name="accessibility_recents_item_dismissed"><xliff:g id="app" example="Calendar">%s</xliff:g> dismissed.</string>
+    <!-- Content description to tell the user all applications has been removed from recents -->
+    <string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
     <!-- Content description to tell the user an application has been launched from recents -->
     <string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Content description to tell the user a notification has been removed from the notification shade -->
@@ -428,6 +430,16 @@
     <string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
     <!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+     <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
+    <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+    <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
     <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -479,17 +491,17 @@
     <string name="accessibility_brightness">Display brightness</string>
 
     <!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
-    <string name="data_usage_disabled_dialog_3g_title">2G-3G data is off</string>
+    <string name="data_usage_disabled_dialog_3g_title">2G-3G data is paused</string>
     <!-- Title of dialog shown when 4G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
-    <string name="data_usage_disabled_dialog_4g_title">4G data is off</string>
+    <string name="data_usage_disabled_dialog_4g_title">4G data is paused</string>
     <!-- Title of dialog shown when mobile data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
-    <string name="data_usage_disabled_dialog_mobile_title">Cellular data is off</string>
+    <string name="data_usage_disabled_dialog_mobile_title">Cellular data is paused</string>
     <!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
-    <string name="data_usage_disabled_dialog_title">Data is off</string>
+    <string name="data_usage_disabled_dialog_title">Data is paused</string>
     <!-- Body of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=NONE] -->
-    <string name="data_usage_disabled_dialog">Your device turned off data because it reached the limit you set.\n\nTurning it back on may lead to charges from your carrier.</string>
+    <string name="data_usage_disabled_dialog">Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your carrier.</string>
     <!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
-    <string name="data_usage_disabled_dialog_enable">Turn on data</string>
+    <string name="data_usage_disabled_dialog_enable">Resume</string>
 
     <!-- Text to display underneath the graphical signal strength meter when
          no connection is available. [CHAR LIMIT=20] -->
@@ -552,6 +564,12 @@
 
     <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
     <string name="quick_settings_airplane_mode_label">Airplane mode</string>
+    <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_label">Do not disturb</string>
+    <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_priority_label">Priority only</string>
+    <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_none_label">No interruptions</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
     <string name="quick_settings_bluetooth_label">Bluetooth</string>
     <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
@@ -626,8 +644,6 @@
     <string name="quick_settings_done">Done</string>
     <!-- QuickSettings: Control panel: Label for connected device. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_connected">Connected</string>
-    <!-- QuickSettings: Control panel: Label for a connected Wi-Fi access point when the connection is established by a Wi-Fi assistant application. [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_connected_via_wfa">Connected via Wi\u2011Fi assistant</string>
     <!-- QuickSettings: Control panel: Label for connecting device. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_connecting">Connecting...</string>
     <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
@@ -663,7 +679,21 @@
     <string name="recents_search_bar_label">search</string>
     <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+    <!-- Recents: Dismiss all button. [CHAR LIMIT=NONE] -->
+    <string name="recents_dismiss_all_message">Dismiss all applications</string>
 
+    <!-- Recents: MultiStack add stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack">+</string>
+    <!-- Recents: MultiStack remove stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_remove_stack">-</string>
+    <!-- Recents: MultiStack resize stack button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_resize_stack">[]</string>
+    <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
+    <!-- Recents: MultiStack add stack split vertical radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
+    <!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
+    <string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
 
     <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
     <string name="expanded_header_battery_charged">Charged</string>
@@ -894,6 +924,12 @@
     <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
     <string name="hidden_notifications_setup">Set up</string>
 
+    <!-- Text for the button to expand the notifications to show notification children [CHAR LIMIT=20] -->
+    <string name="notification_expand_button_text">See all</string>
+
+    <!-- Text for the button to expand the notifications to hide notification children [CHAR LIMIT=20] -->
+    <string name="notification_collapse_button_text">Hide all</string>
+
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
@@ -916,4 +952,19 @@
 
     <!-- Hide quick settings tile confirmation button -->
     <string name="quick_settings_reset_confirmation_button">Hide</string>
+
+    <!-- VolumeUI activation dialog: warning message -->
+    <string name="volumeui_prompt_message"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> wants to be the volume dialog.</string>
+
+    <!-- VolumeUI activation dialog: allow button label -->
+    <string name="volumeui_prompt_allow">Allow</string>
+
+    <!-- VolumeUI activation dialog: deny button label -->
+    <string name="volumeui_prompt_deny">Deny</string>
+
+    <!-- VolumeUI restoration notification: title -->
+    <string name="volumeui_notification_title"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> is the volume dialog</string>
+
+    <!-- VolumeUI restoration notification: text -->
+    <string name="volumeui_notification_text">Touch to restore the original.</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 09b240b..07fcb82 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -20,7 +20,7 @@
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
     </style>
 
-    <style name="RecentsTheme" parent="@android:style/Theme">
+    <style name="RecentsTheme" parent="@android:style/Theme.Material.Light">
         <!-- NoTitle -->
         <item name="android:windowNoTitle">true</item>
         <!-- Misc -->
@@ -109,13 +109,6 @@
     <style name="TextAppearance.StatusBar.Expanded.ChargingInfo"
             parent="TextAppearance.StatusBar.Expanded.AboveDateTime" />
 
-    <style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date">
-        <item name="android:textColor">#999999</item>
-	</style>
-
-    <style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly">
-    </style>
-
     <style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
         <item name="android:textSize">16sp</item>
         <item name="android:textStyle">normal</item>
@@ -152,6 +145,7 @@
 
     <style name="TextAppearance.QS.DetailButton">
         <item name="android:textSize">@dimen/qs_detail_button_text_size</item>
+        <item name="android:textColor">@color/qs_detail_button</item>
         <item name="android:textAllCaps">true</item>
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:gravity">center</item>
@@ -212,13 +206,12 @@
         <item name="android:windowExitAnimation">@anim/heads_up_exit</item>
     </style>
 
-    <style name="TextAppearance.StatusBar.PhoneTicker"
-        parent="@*android:style/TextAppearance.StatusBar.Ticker">
-        <!-- Note: must be dp to fit in status bar -->
-        <item name="android:textSize">14dp</item>
+    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorPrimary">@color/system_primary_color</item>
+        <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
 
-    <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault">
+    <style name="systemui_theme_light" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorPrimary">@color/system_primary_color</item>
         <item name="android:colorControlActivated">@color/system_accent_color</item>
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 7bdbd0a..9bb626d 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -23,8 +23,11 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.os.BatteryManager;
@@ -56,12 +59,13 @@
     private float mSubpixelSmoothingRight;
     private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
     private float mTextHeight, mWarningTextHeight;
+    private int mIconTint = Color.WHITE;
 
     private int mHeight;
     private int mWidth;
     private String mWarningString;
     private final int mCriticalLevel;
-    private final int mChargeColor;
+    private int mChargeColor;
     private final float[] mBoltPoints;
     private final Path mBoltPath = new Path();
 
@@ -292,11 +296,27 @@
         for (int i=0; i<mColors.length; i+=2) {
             thresh = mColors[i];
             color = mColors[i+1];
-            if (percent <= thresh) return color;
+            if (percent <= thresh) {
+
+                // Respect tinting for "normal" level
+                if (i == mColors.length-2) {
+                    return mIconTint;
+                } else {
+                    return color;
+                }
+            }
         }
         return color;
     }
 
+    public void setIconTint(int tint) {
+        mIconTint = tint;
+        mFramePaint.setColorFilter(new PorterDuffColorFilter(tint, PorterDuff.Mode.SRC_ATOP));
+        mBoltPaint.setColor(tint);
+        mChargeColor = tint;
+        invalidate();
+    }
+
     @Override
     public void draw(Canvas c) {
         BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index d42ac61..bc7f745 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -22,7 +22,6 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.media.AudioAttributes;
-import android.media.AudioManager;
 import android.os.Vibrator;
 import android.util.Log;
 import android.view.Gravity;
@@ -147,14 +146,14 @@
         }
         public void setHeight(float h) {
             if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h);
-            mView.setActualHeight((int) h);
+            mView.setContentHeight((int) h);
             mCurrentHeight = h;
         }
         public float getHeight() {
-            return mView.getActualHeight();
+            return mView.getContentHeight();
         }
         public int getNaturalHeight(int maximum) {
-            return Math.min(maximum, mView.getMaxHeight());
+            return Math.min(maximum, mView.getMaxContentHeight());
         }
     }
 
@@ -387,7 +386,8 @@
     }
 
     private boolean isFullyExpanded(ExpandableView underFocus) {
-        return underFocus.getIntrinsicHeight() == underFocus.getMaxHeight();
+        return underFocus.areChildrenExpanded() || underFocus.getIntrinsicHeight()
+                - underFocus.getBottomDecorHeight() == underFocus.getMaxContentHeight();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 7c725b3..6888d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -21,10 +21,8 @@
 
 import android.app.ActivityManager;
 import android.app.WallpaperManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Point;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index b3f90d7..e302c98 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -41,7 +41,7 @@
      */
     private final Class<?>[] SERVICES = new Class[] {
             com.android.systemui.keyguard.KeyguardViewMediator.class,
-            com.android.systemui.recent.Recents.class,
+            com.android.systemui.recents.Recents.class,
             com.android.systemui.volume.VolumeUI.class,
             com.android.systemui.statusbar.SystemBars.class,
             com.android.systemui.usb.StorageNotification.class,
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index 2ff8f8a..eddf2b1 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -26,8 +26,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
 /**
  * Helper to invert the colors of views and fade between the states.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java b/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java
index b9f8106..50221d3 100644
--- a/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/egg/LLandActivity.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
 import android.widget.TextView;
 
 import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e66934e..275a6be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -63,7 +63,6 @@
 import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.MultiUserAvatarCache;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -173,7 +172,7 @@
     private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
 
     /** The stream type that the lock sounds are tied to. */
-    private int mMasterStreamType;
+    private int mUiSoundsStreamType;
 
     private AlarmManager mAlarmManager;
     private AudioManager mAudioManager;
@@ -314,9 +313,6 @@
                 resetKeyguardDonePendingLocked();
                 resetStateLocked();
                 adjustStatusBarLocked();
-                // When we switch users we want to bring the new user to the biometric unlock even
-                // if the current user has gone to the backup.
-                KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
             }
         }
 
@@ -333,14 +329,7 @@
         }
 
         @Override
-        public void onUserRemoved(int userId) {
-            mLockPatternUtils.removeUser(userId);
-            MultiUserAvatarCache.getInstance().clear(userId);
-        }
-
-        @Override
         public void onUserInfoChanged(int userId) {
-            MultiUserAvatarCache.getInstance().clear(userId);
         }
 
         @Override
@@ -450,6 +439,8 @@
         public void onFingerprintRecognized(int userId) {
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mViewMediatorCallback.keyguardDone(true);
+            } else {
+                mStatusBarKeyguardViewManager.animateCollapsePanels();
             }
         };
 
@@ -477,11 +468,6 @@
         }
 
         @Override
-        public void onUserActivityTimeoutChanged() {
-            mStatusBarKeyguardViewManager.updateUserActivityTimeout();
-        }
-
-        @Override
         public void keyguardDonePending() {
             mKeyguardDonePending = true;
             mHideAnimationRun = true;
@@ -505,6 +491,11 @@
         }
 
         @Override
+        public void resetKeyguard() {
+            resetStateLocked();
+        }
+
+        @Override
         public void playTrustedSound() {
             KeyguardViewMediator.this.playTrustedSound();
         }
@@ -597,23 +588,6 @@
             mSystemReady = true;
             mUpdateMonitor.registerCallback(mUpdateCallback);
 
-            // Suppress biometric unlock right after boot until things have settled if it is the
-            // selected security method, otherwise unsuppress it.  It must be unsuppressed if it is
-            // not the selected security method for the following reason:  if the user starts
-            // without a screen lock selected, the biometric unlock would be suppressed the first
-            // time they try to use it.
-            //
-            // Note that the biometric unlock will still not show if it is not the selected method.
-            // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the
-            // selected method.
-            if (mLockPatternUtils.usingBiometricWeak()
-                    && mLockPatternUtils.isBiometricWeakInstalled()) {
-                if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
-                mUpdateMonitor.setAlternateUnlockEnabled(false);
-            } else {
-                mUpdateMonitor.setAlternateUnlockEnabled(true);
-            }
-
             doKeyguardLocked(null);
         }
         // Most services aren't available until the system reaches the ready state, so we
@@ -1270,10 +1244,10 @@
             if (mAudioManager == null) {
                 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
                 if (mAudioManager == null) return;
-                mMasterStreamType = mAudioManager.getMasterStreamType();
+                mUiSoundsStreamType = mAudioManager.getUiSoundsStreamType();
             }
             // If the stream is muted, don't play the sound
-            if (mAudioManager.isStreamMute(mMasterStreamType)) return;
+            if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
 
             mLockSoundStreamId = mLockSounds.play(soundId,
                     mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
@@ -1328,6 +1302,8 @@
         @Override
         public void run() {
             try {
+                mStatusBarKeyguardViewManager.keyguardGoingAway();
+
                 // Don't actually hide the Keyguard at the moment, wait for window
                 // manager until it tells us it's safe to do so with
                 // startKeyguardExitAnimation.
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index c23f45d..88d0997 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -18,8 +18,6 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -32,16 +30,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
-import android.view.LayoutInflater;
 import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
-import android.widget.TextView;
-
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 public class MediaProjectionPermissionActivity extends Activity
         implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener,
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 4391bfc..63dd17f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -50,7 +50,6 @@
     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 SHOWING_NOTHING = 0;
     private static final int SHOWING_WARNING = 1;
@@ -145,7 +144,7 @@
             showSaverNotification();
             mShowing = SHOWING_SAVER;
         } else {
-            mNoMan.cancelAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, UserHandle.ALL);
+            mNoMan.cancelAsUser(TAG_NOTIFICATION, R.id.notification_power, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
         }
     }
@@ -166,7 +165,7 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
     }
 
     private void showWarningNotification() {
@@ -204,7 +203,7 @@
         if (n.headsUpContentView != null) {
             n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
     }
 
     private void showSaverNotification() {
@@ -221,7 +220,7 @@
         if (hasSaverSettings()) {
             nb.setContentIntent(pendingActivity(mOpenSaverSettings));
         }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.ALL);
+        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL);
     }
 
     private void addStopSaverAction(Notification.Builder nb) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index a0b6e82..0ab644a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -18,12 +18,10 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.Configuration;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4dacacf..f4fd6a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -26,7 +26,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -253,12 +252,6 @@
             @Override
             public void onStateChanged(QSTile.State state) {
                 int visibility = state.visible ? VISIBLE : GONE;
-                if (state.visible && !mGridContentVisible) {
-
-                    // We don't want to show it if the content is hidden,
-                    // then we just set it to invisible, to ensure that it gets visible again
-                    visibility = INVISIBLE;
-                }
                 setTileVisibility(r.tileView, visibility);
                 r.tileView.onStateChanged(state);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index c15566f..b42b5f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
@@ -23,13 +25,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.BluetoothController.PairedDevice;
 
+import java.util.Collection;
 import java.util.Set;
 
 /** Quick settings tile: Bluetooth **/
@@ -143,7 +146,7 @@
             refreshState();
         }
         @Override
-        public void onBluetoothPairedDevicesChanged() {
+        public void onBluetoothDevicesChanged() {
             mUiHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -199,19 +202,21 @@
         private void updateItems() {
             if (mItems == null) return;
             Item[] items = null;
-            final Set<PairedDevice> devices = mController.getPairedDevices();
+            final Collection<CachedBluetoothDevice> devices = mController.getDevices();
             if (devices != null) {
-                items = new Item[devices.size()];
+                items = new Item[getBondedCount(devices)];
                 int i = 0;
-                for (PairedDevice device : devices) {
+                for (CachedBluetoothDevice device : devices) {
+                    if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
                     final Item item = new Item();
                     item.icon = R.drawable.ic_qs_bluetooth_on;
-                    item.line1 = device.name;
-                    if (device.state == PairedDevice.STATE_CONNECTED) {
+                    item.line1 = device.getName();
+                    int state = device.getMaxConnectionState();
+                    if (state == BluetoothProfile.STATE_CONNECTED) {
                         item.icon = R.drawable.ic_qs_bluetooth_connected;
                         item.line2 = mContext.getString(R.string.quick_settings_connected);
                         item.canDisconnect = true;
-                    } else if (device.state == PairedDevice.STATE_CONNECTING) {
+                    } else if (state == BluetoothProfile.STATE_CONNECTING) {
                         item.icon = R.drawable.ic_qs_bluetooth_connecting;
                         item.line2 = mContext.getString(R.string.quick_settings_connecting);
                     }
@@ -222,11 +227,22 @@
             mItems.setItems(items);
         }
 
+        private int getBondedCount(Collection<CachedBluetoothDevice> devices) {
+            int ct = 0;
+            for (CachedBluetoothDevice device : devices) {
+                if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+                    ct++;
+                }
+            }
+            return ct;
+        }
+
         @Override
         public void onDetailItemClick(Item item) {
             if (item == null || item.tag == null) return;
-            final PairedDevice device = (PairedDevice) item.tag;
-            if (device != null && device.state == PairedDevice.STATE_DISCONNECTED) {
+            final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+            if (device != null && device.getMaxConnectionState()
+                    == BluetoothProfile.STATE_DISCONNECTED) {
                 mController.connect(device);
             }
         }
@@ -234,7 +250,7 @@
         @Override
         public void onDetailItemDisconnect(Item item) {
             if (item == null || item.tag == null) return;
-            final PairedDevice device = (PairedDevice) item.tag;
+            final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
             if (device != null) {
                 mController.disconnect(device);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
new file mode 100644
index 0000000..79600f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Do not disturb **/
+public class DndTile extends QSTile<QSTile.BooleanState> {
+    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
+    private static final String EXTRA_VISIBLE = "visible";
+    private static final String PREF_KEY_VISIBLE = "DndTileVisible";
+
+    private final ZenModeController mController;
+    private final DndDetailAdapter mDetailAdapter;
+
+    private boolean mListening;
+    private boolean mVisible;
+    private boolean mShowingDetail;
+
+    public DndTile(Host host) {
+        super(host);
+        mController = host.getZenModeController();
+        mDetailAdapter = new DndDetailAdapter();
+        mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
+        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+    }
+
+    public static void setVisible(Context context, boolean visible) {
+        context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
+                .putExtra(DndTile.EXTRA_VISIBLE, visible));
+    }
+
+    public static boolean isVisible(Context context) {
+        return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+    }
+
+    @Override
+    public DetailAdapter getDetailAdapter() {
+        return mDetailAdapter;
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleClick() {
+        if (mState.value) {
+            mController.setZen(Global.ZEN_MODE_OFF);
+        } else {
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
+        state.value = zen != Global.ZEN_MODE_OFF;
+        state.visible = mVisible;
+        switch (zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_priority_on);
+                break;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_none_on);
+                break;
+            default:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
+                state.label = mContext.getString(R.string.quick_settings_dnd_label);
+                state.contentDescription =  mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_off);
+                break;
+        }
+        if (mShowingDetail && !state.value) {
+            showDetail(false);
+        }
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
+        } else {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
+        }
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (mListening == listening) return;
+        mListening = listening;
+        if (mListening) {
+            mController.addCallback(mZenCallback);
+        } else {
+            mController.removeCallback(mZenCallback);
+        }
+    }
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        public void onZenChanged(int zen) {
+            refreshState(zen);
+        }
+    };
+
+    private static SharedPreferences getSharedPrefs(Context context) {
+        return context.getSharedPreferences(context.getPackageName(), 0);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+            getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+            refreshState();
+        }
+    };
+
+    private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
+
+        @Override
+        public int getTitle() {
+            return R.string.quick_settings_dnd_label;
+        }
+
+        @Override
+        public Boolean getToggleState() {
+            return mState.value;
+        }
+
+        @Override
+        public Intent getSettingsIntent() {
+            return ZEN_SETTINGS;
+        }
+
+        @Override
+        public void setToggleState(boolean state) {
+            if (!state) {
+                mController.setZen(Global.ZEN_MODE_OFF);
+                showDetail(false);
+            }
+        }
+
+        @Override
+        public View createDetailView(Context context, View convertView, ViewGroup parent) {
+            final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
+                    : (ZenModePanel) LayoutInflater.from(context).inflate(
+                            R.layout.zen_mode_panel, parent, false);
+            if (convertView == null) {
+                zmp.init(mController);
+                zmp.setEmbedded(true);
+                zmp.addOnAttachStateChangeListener(this);
+            }
+            return zmp;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+            mShowingDetail = true;
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mShowingDetail = false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index c55cbccb..21c5c96 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -28,7 +28,6 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
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 e09024b..70746c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import java.util.List;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -24,16 +26,15 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.SignalTileView;
-import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.policy.NetworkController.AccessPointController.AccessPoint;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 
 /** Quick settings tile: Wifi **/
@@ -282,10 +283,10 @@
         }
 
         @Override
-        public void onAccessPointsChanged(final AccessPoint[] accessPoints) {
-            mAccessPoints = accessPoints;
+        public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
+            mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
             updateItems();
-            if (accessPoints != null && accessPoints.length > 0) {
+            if (accessPoints != null && accessPoints.size() > 0) {
                 fireScanStateChanged(false);
             }
         }
@@ -299,7 +300,7 @@
         public void onDetailItemClick(Item item) {
             if (item == null || item.tag == null) return;
             final AccessPoint ap = (AccessPoint) item.tag;
-            if (!ap.isConnected) {
+            if (!ap.isActive()) {
                 if (mWifiController.connect(ap)) {
                     mHost.collapsePanels();
                 }
@@ -326,16 +327,10 @@
                     final AccessPoint ap = mAccessPoints[i];
                     final Item item = new Item();
                     item.tag = ap;
-                    item.icon = ap.iconId;
-                    item.line1 = ap.ssid;
-                    if (ap.isConnected) {
-                        item.line2 = mContext.getString(ap.isConfigured ?
-                                R.string.quick_settings_connected :
-                                R.string.quick_settings_connected_via_wfa);
-                    } else if (ap.networkId >= 0) {
-                        // TODO: Set line 2 to wifi saved string here.
-                    }
-                    item.overlay = ap.hasSecurity
+                    item.icon = mWifiController.getIcon(ap);
+                    item.line1 = ap.getSsid();
+                    item.line2 = ap.getSummary();
+                    item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
                             ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
                             : null;
                     items[i] = item;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
deleted file mode 100644
index b4d3edd..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
+++ /dev/null
@@ -1,40 +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.systemui.recent;
-
-import android.graphics.drawable.ColorDrawable;
-
-public class ColorDrawableWithDimensions extends ColorDrawable {
-    private int mWidth;
-    private int mHeight;
-
-    public ColorDrawableWithDimensions(int color, int width, int height) {
-        super(color);
-        mWidth = width;
-        mHeight = height;
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mWidth;
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mHeight;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Constants.java b/packages/SystemUI/src/com/android/systemui/recent/Constants.java
deleted file mode 100644
index 8252a9f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/Constants.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-public class Constants {
-    static final int MAX_ESCAPE_ANIMATION_DURATION = 500; // in ms
-    static final int SNAP_BACK_DURATION = 250; // in ms
-    static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it in dp/s
-    public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width where fade starts
-    static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width beyond which alpha->0
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
deleted file mode 100644
index 59f7a80..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Shader;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-
-public class FadedEdgeDrawHelper {
-    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
-    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
-    private View mScrollView;
-
-    private int mFadingEdgeLength;
-    private boolean mIsVertical;
-    private boolean mSoftwareRendered = false;
-    private Paint mBlackPaint;
-    private Paint mFadePaint;
-    private Matrix mFadeMatrix;
-    private LinearGradient mFade;
-
-    public static FadedEdgeDrawHelper create(Context context,
-            AttributeSet attrs, View scrollView, boolean isVertical) {
-        boolean isTablet = context.getResources().
-                getBoolean(R.bool.config_recents_interface_for_tablets);
-        if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
-            return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
-        } else {
-            return null;
-        }
-    }
-
-    public FadedEdgeDrawHelper(Context context,
-            AttributeSet attrs, View scrollView, boolean isVertical) {
-        mScrollView = scrollView;
-        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
-        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
-                ViewConfiguration.get(context).getScaledFadingEdgeLength());
-        mIsVertical = isVertical;
-    }
-
-    public void onAttachedToWindowCallback(
-            LinearLayout layout, boolean hardwareAccelerated) {
-        mSoftwareRendered = !hardwareAccelerated;
-        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
-                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
-            mScrollView.setVerticalFadingEdgeEnabled(false);
-            mScrollView.setHorizontalFadingEdgeEnabled(false);
-        }
-    }
-
-    public void addViewCallback(View newLinearLayoutChild) {
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            final RecentsPanelView.ViewHolder holder =
-                    (RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
-            holder.labelView.setDrawingCacheEnabled(true);
-            holder.labelView.buildDrawingCache();
-        }
-    }
-
-    public void drawCallback(Canvas canvas,
-            int left, int right, int top, int bottom, int scrollX, int scrollY,
-            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
-            float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
-
-        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
-                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
-            if (mFadePaint == null) {
-                mFadePaint = new Paint();
-                mFadeMatrix = new Matrix();
-                // use use a height of 1, and then wack the matrix each time we
-                // actually use it.
-                mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
-                // PULL OUT THIS CONSTANT
-                mFadePaint.setShader(mFade);
-            }
-
-            // draw the fade effect
-            boolean drawTop = false;
-            boolean drawBottom = false;
-            boolean drawLeft = false;
-            boolean drawRight = false;
-
-            float topFadeStrength = 0.0f;
-            float bottomFadeStrength = 0.0f;
-            float leftFadeStrength = 0.0f;
-            float rightFadeStrength = 0.0f;
-
-            final float fadeHeight = mFadingEdgeLength;
-            int length = (int) fadeHeight;
-
-            // clip the fade length if top and bottom fades overlap
-            // overlapping fades produce odd-looking artifacts
-            if (mIsVertical && (top + length > bottom - length)) {
-                length = (bottom - top) / 2;
-            }
-
-            // also clip horizontal fades if necessary
-            if (!mIsVertical && (left + length > right - length)) {
-                length = (right - left) / 2;
-            }
-
-            if (mIsVertical) {
-                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
-                drawTop = topFadeStrength * fadeHeight > 1.0f;
-                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
-                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
-            }
-
-            if (!mIsVertical) {
-                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
-                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
-                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
-                drawRight = rightFadeStrength * fadeHeight > 1.0f;
-            }
-
-            if (drawTop) {
-                mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
-                mFadeMatrix.postTranslate(left, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                mFadePaint.setShader(mFade);
-                canvas.drawRect(left, top, right, top + length, mFadePaint);
-
-                if (mBlackPaint == null) {
-                    // Draw under the status bar at the top
-                    mBlackPaint = new Paint();
-                    mBlackPaint.setColor(0xFF000000);
-                }
-                canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
-            }
-
-            if (drawBottom) {
-                mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
-                mFadeMatrix.postRotate(180);
-                mFadeMatrix.postTranslate(left, bottom);
-                mFade.setLocalMatrix(mFadeMatrix);
-                mFadePaint.setShader(mFade);
-                canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
-            }
-
-            if (drawLeft) {
-                mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
-                mFadeMatrix.postRotate(-90);
-                mFadeMatrix.postTranslate(left, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                mFadePaint.setShader(mFade);
-                canvas.drawRect(left, top, left + length, bottom, mFadePaint);
-            }
-
-            if (drawRight) {
-                mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
-                mFadeMatrix.postRotate(90);
-                mFadeMatrix.postTranslate(right, top);
-                mFade.setLocalMatrix(mFadeMatrix);
-                mFadePaint.setShader(mFade);
-                canvas.drawRect(right - length, top, right, bottom, mFadePaint);
-            }
-        }
-    }
-
-    public int getVerticalFadingEdgeLength() {
-        return mFadingEdgeLength;
-    }
-
-    public int getHorizontalFadingEdgeLength() {
-        return mFadingEdgeLength;
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
deleted file mode 100644
index 84d13cf..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
+++ /dev/null
@@ -1,134 +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.systemui.recent;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewTreeObserver;
-
-/*
- *  This is a helper class that listens to updates from the corresponding animation.
- *  For the first two frames, it adjusts the current play time of the animation to
- *  prevent jank at the beginning of the animation
- */
-public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
-    implements ValueAnimator.AnimatorUpdateListener {
-    private static final boolean DEBUG = false;
-    private static final int MAX_DELAY = 1000;
-    private static final int IDEAL_FRAME_DURATION = 16;
-    private View mTarget;
-    private long mStartFrame;
-    private long mStartTime = -1;
-    private boolean mHandlingOnAnimationUpdate;
-    private boolean mAdjustedSecondFrameTime;
-
-    private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
-    private static long sGlobalFrameCounter;
-
-    public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
-        mTarget = target;
-        animator.addUpdateListener(this);
-    }
-
-    public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
-        mTarget = target;
-        vpa.setListener(this);
-    }
-
-    // only used for ViewPropertyAnimators
-    public void onAnimationStart(Animator animation) {
-        final ValueAnimator va = (ValueAnimator) animation;
-        va.addUpdateListener(FirstFrameAnimatorHelper.this);
-        onAnimationUpdate(va);
-    }
-
-    public static void initializeDrawListener(View view) {
-        if (sGlobalDrawListener != null) {
-            view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
-        }
-        sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
-                private long mTime = System.currentTimeMillis();
-                public void onDraw() {
-                    sGlobalFrameCounter++;
-                    if (DEBUG) {
-                        long newTime = System.currentTimeMillis();
-                        Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
-                        mTime = newTime;
-                    }
-                }
-            };
-        view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
-    }
-
-    public void onAnimationUpdate(final ValueAnimator animation) {
-        final long currentTime = System.currentTimeMillis();
-        if (mStartTime == -1) {
-            mStartFrame = sGlobalFrameCounter;
-            mStartTime = currentTime;
-        }
-
-        if (!mHandlingOnAnimationUpdate &&
-            // If the current play time exceeds the duration, the animation
-            // will get finished, even if we call setCurrentPlayTime -- therefore
-            // don't adjust the animation in that case
-            animation.getCurrentPlayTime() < animation.getDuration()) {
-            mHandlingOnAnimationUpdate = true;
-            long frameNum = sGlobalFrameCounter - mStartFrame;
-            // If we haven't drawn our first frame, reset the time to t = 0
-            // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
-            // are no longer in the foreground and no frames are being rendered ever)
-            if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY) {
-                // The first frame on animations doesn't always trigger an invalidate...
-                // force an invalidate here to make sure the animation continues to advance
-                mTarget.getRootView().invalidate();
-                animation.setCurrentPlayTime(0);
-
-            // For the second frame, if the first frame took more than 16ms,
-            // adjust the start time and pretend it took only 16ms anyway. This
-            // prevents a large jump in the animation due to an expensive first frame
-            } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
-                       !mAdjustedSecondFrameTime &&
-                       currentTime > mStartTime + IDEAL_FRAME_DURATION) {
-                animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
-                mAdjustedSecondFrameTime = true;
-            } else {
-                if (frameNum > 1) {
-                    mTarget.post(new Runnable() {
-                            public void run() {
-                                animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
-                            }
-                        });
-                }
-                if (DEBUG) print(animation);
-            }
-            mHandlingOnAnimationUpdate = false;
-        } else {
-            if (DEBUG) print(animation);
-        }
-    }
-
-    public void print(ValueAnimator animation) {
-        float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
-        Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter +
-              "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
-              mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
deleted file mode 100644
index 34430d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.app.ActivityManager;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.systemui.R;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public class RecentTasksLoader implements View.OnTouchListener {
-    static final String TAG = "RecentTasksLoader";
-    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
-
-    private static final int DISPLAY_TASKS = 20;
-    private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
-
-    private Context mContext;
-    private RecentsPanelView mRecentsPanel;
-
-    private Object mFirstTaskLock = new Object();
-    private TaskDescription mFirstTask;
-    private boolean mFirstTaskLoaded;
-
-    private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
-    private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
-    private Handler mHandler;
-
-    private int mIconDpi;
-    private ColorDrawableWithDimensions mDefaultThumbnailBackground;
-    private ColorDrawableWithDimensions mDefaultIconBackground;
-    private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
-
-    private boolean mFirstScreenful;
-    private ArrayList<TaskDescription> mLoadedTasks;
-
-    private enum State { LOADING, LOADED, CANCELLED };
-    private State mState = State.CANCELLED;
-
-
-    private static RecentTasksLoader sInstance;
-    public static RecentTasksLoader getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new RecentTasksLoader(context);
-        }
-        return sInstance;
-    }
-
-    private RecentTasksLoader(Context context) {
-        mContext = context;
-        mHandler = new Handler();
-
-        final Resources res = context.getResources();
-
-        // get the icon size we want -- on tablets, we use bigger icons
-        boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
-        if (isTablet) {
-            ActivityManager activityManager =
-                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-            mIconDpi = activityManager.getLauncherLargeIconDensity();
-        } else {
-            mIconDpi = res.getDisplayMetrics().densityDpi;
-        }
-
-        // Render default icon (just a blank image)
-        int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
-        int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
-        mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
-
-        // Render the default thumbnail background
-        int thumbnailWidth =
-                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-        int thumbnailHeight =
-                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
-        int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
-
-        mDefaultThumbnailBackground =
-                new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
-    }
-
-    public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
-        // Only allow clearing mRecentsPanel if the caller is the current recentsPanel
-        if (newRecentsPanel != null || mRecentsPanel == caller) {
-            mRecentsPanel = newRecentsPanel;
-            if (mRecentsPanel != null) {
-                mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
-            }
-        }
-    }
-
-    public Drawable getDefaultThumbnail() {
-        return mDefaultThumbnailBackground;
-    }
-
-    public Drawable getDefaultIcon() {
-        return mDefaultIconBackground;
-    }
-
-    public ArrayList<TaskDescription> getLoadedTasks() {
-        return mLoadedTasks;
-    }
-
-    public void remove(TaskDescription td) {
-        mLoadedTasks.remove(td);
-    }
-
-    public boolean isFirstScreenful() {
-        return mFirstScreenful;
-    }
-
-    private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) {
-        if (homeInfo == null) {
-            final PackageManager pm = mContext.getPackageManager();
-            homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
-                .resolveActivityInfo(pm, 0);
-        }
-        return homeInfo != null
-            && homeInfo.packageName.equals(component.getPackageName())
-            && homeInfo.name.equals(component.getClassName());
-    }
-
-    // Create an TaskDescription, returning null if the title or icon is null
-    TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
-            ComponentName origActivity, CharSequence description, int userId) {
-        Intent intent = new Intent(baseIntent);
-        if (origActivity != null) {
-            intent.setComponent(origActivity);
-        }
-        final PackageManager pm = mContext.getPackageManager();
-        final IPackageManager ipm = AppGlobals.getPackageManager();
-        intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
-                | Intent.FLAG_ACTIVITY_NEW_TASK);
-        ResolveInfo resolveInfo = null;
-        try {
-            resolveInfo = ipm.resolveIntent(intent, null, 0, userId);
-        } catch (RemoteException re) {
-        }
-        if (resolveInfo != null) {
-            final ActivityInfo info = resolveInfo.activityInfo;
-            final String title = info.loadLabel(pm).toString();
-
-            if (title != null && title.length() > 0) {
-                if (DEBUG) Log.v(TAG, "creating activity desc for id="
-                        + persistentTaskId + ", label=" + title);
-
-                TaskDescription item = new TaskDescription(taskId,
-                        persistentTaskId, resolveInfo, baseIntent, info.packageName,
-                        description, userId);
-                item.setLabel(title);
-
-                return item;
-            } else {
-                if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId);
-            }
-        }
-        return null;
-    }
-
-    void loadThumbnailAndIcon(TaskDescription td) {
-        final ActivityManager am = (ActivityManager)
-                mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        final PackageManager pm = mContext.getPackageManager();
-        final Bitmap thumbnail = SystemServicesProxy.getThumbnail(am, td.persistentTaskId);
-        Drawable icon = getFullResIcon(td.resolveInfo, pm);
-        if (td.userId != UserHandle.myUserId()) {
-            // Need to badge the icon
-            icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(td.userId));
-        }
-        if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
-                + td + ": " + thumbnail);
-        synchronized (td) {
-            if (thumbnail != null) {
-                td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
-            } else {
-                td.setThumbnail(mDefaultThumbnailBackground);
-            }
-            if (icon != null) {
-                td.setIcon(icon);
-            }
-            td.setLoaded(true);
-        }
-    }
-
-    Drawable getFullResDefaultActivityIcon() {
-        return getFullResIcon(Resources.getSystem(),
-                com.android.internal.R.mipmap.sym_def_app_icon);
-    }
-
-    Drawable getFullResIcon(Resources resources, int iconId) {
-        try {
-            return resources.getDrawableForDensity(iconId, mIconDpi);
-        } catch (Resources.NotFoundException e) {
-            return getFullResDefaultActivityIcon();
-        }
-    }
-
-    private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
-        Resources resources;
-        try {
-            resources = packageManager.getResourcesForApplication(
-                    info.activityInfo.applicationInfo);
-        } catch (PackageManager.NameNotFoundException e) {
-            resources = null;
-        }
-        if (resources != null) {
-            int iconId = info.activityInfo.getIconResource();
-            if (iconId != 0) {
-                return getFullResIcon(resources, iconId);
-            }
-        }
-        return getFullResDefaultActivityIcon();
-    }
-
-    Runnable mPreloadTasksRunnable = new Runnable() {
-            public void run() {
-                loadTasksInBackground();
-            }
-        };
-
-    // additional optimization when we have software system buttons - start loading the recent
-    // tasks on touch down
-    @Override
-    public boolean onTouch(View v, MotionEvent ev) {
-        int action = ev.getAction() & MotionEvent.ACTION_MASK;
-        if (action == MotionEvent.ACTION_DOWN) {
-            preloadRecentTasksList();
-        } else if (action == MotionEvent.ACTION_CANCEL) {
-            cancelPreloadingRecentTasksList();
-        } else if (action == MotionEvent.ACTION_UP) {
-            // Remove the preloader if we haven't called it yet
-            mHandler.removeCallbacks(mPreloadTasksRunnable);
-            if (!v.isPressed()) {
-                cancelLoadingThumbnailsAndIcons();
-            }
-
-        }
-        return false;
-    }
-
-    public void preloadRecentTasksList() {
-        mHandler.post(mPreloadTasksRunnable);
-    }
-
-    public void cancelPreloadingRecentTasksList() {
-        cancelLoadingThumbnailsAndIcons();
-        mHandler.removeCallbacks(mPreloadTasksRunnable);
-    }
-
-    public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
-        // Only oblige this request if it comes from the current RecentsPanel
-        // (eg when you rotate, the old RecentsPanel request should be ignored)
-        if (mRecentsPanel == caller) {
-            cancelLoadingThumbnailsAndIcons();
-        }
-    }
-
-
-    private void cancelLoadingThumbnailsAndIcons() {
-        if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-            return;
-        }
-
-        if (mTaskLoader != null) {
-            mTaskLoader.cancel(false);
-            mTaskLoader = null;
-        }
-        if (mThumbnailLoader != null) {
-            mThumbnailLoader.cancel(false);
-            mThumbnailLoader = null;
-        }
-        mLoadedTasks = null;
-        if (mRecentsPanel != null) {
-            mRecentsPanel.onTaskLoadingCancelled();
-        }
-        mFirstScreenful = false;
-        mState = State.CANCELLED;
-    }
-
-    private void clearFirstTask() {
-        synchronized (mFirstTaskLock) {
-            mFirstTask = null;
-            mFirstTaskLoaded = false;
-        }
-    }
-
-    public void preloadFirstTask() {
-        Thread bgLoad = new Thread() {
-            public void run() {
-                TaskDescription first = loadFirstTask();
-                synchronized(mFirstTaskLock) {
-                    if (mCancelPreloadingFirstTask) {
-                        clearFirstTask();
-                    } else {
-                        mFirstTask = first;
-                        mFirstTaskLoaded = true;
-                    }
-                    mPreloadingFirstTask = false;
-                }
-            }
-        };
-        synchronized(mFirstTaskLock) {
-            if (!mPreloadingFirstTask) {
-                clearFirstTask();
-                mPreloadingFirstTask = true;
-                bgLoad.start();
-            }
-        }
-    }
-
-    public void cancelPreloadingFirstTask() {
-        synchronized(mFirstTaskLock) {
-            if (mPreloadingFirstTask) {
-                mCancelPreloadingFirstTask = true;
-            } else {
-                clearFirstTask();
-            }
-        }
-    }
-
-    boolean mPreloadingFirstTask;
-    boolean mCancelPreloadingFirstTask;
-    public TaskDescription getFirstTask() {
-        while(true) {
-            synchronized(mFirstTaskLock) {
-                if (mFirstTaskLoaded) {
-                    return mFirstTask;
-                } else if (!mFirstTaskLoaded && !mPreloadingFirstTask) {
-                    mFirstTask = loadFirstTask();
-                    mFirstTaskLoaded = true;
-                    return mFirstTask;
-                }
-            }
-            try {
-                Thread.sleep(3);
-            } catch (InterruptedException e) {
-            }
-        }
-    }
-
-    public TaskDescription loadFirstTask() {
-        final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-
-        final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(1,
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
-                UserHandle.CURRENT.getIdentifier());
-        TaskDescription item = null;
-        if (recentTasks.size() > 0) {
-            ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
-
-            Intent intent = new Intent(recentInfo.baseIntent);
-            if (recentInfo.origActivity != null) {
-                intent.setComponent(recentInfo.origActivity);
-            }
-
-            // Don't load the current home activity.
-            if (isCurrentHomeActivity(intent.getComponent(), null)) {
-                return null;
-            }
-
-            // Don't load ourselves
-            if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
-                return null;
-            }
-
-            item = createTaskDescription(recentInfo.id,
-                    recentInfo.persistentId, recentInfo.baseIntent,
-                    recentInfo.origActivity, recentInfo.description,
-                    recentInfo.userId);
-            if (item != null) {
-                loadThumbnailAndIcon(item);
-            }
-            return item;
-        }
-        return null;
-    }
-
-    public void loadTasksInBackground() {
-        loadTasksInBackground(false);
-    }
-    public void loadTasksInBackground(final boolean zeroeth) {
-        if (mState != State.CANCELLED) {
-            return;
-        }
-        mState = State.LOADING;
-        mFirstScreenful = true;
-
-        final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
-                new LinkedBlockingQueue<TaskDescription>();
-        mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
-            @Override
-            protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
-                if (!isCancelled()) {
-                    ArrayList<TaskDescription> newTasks = values[0];
-                    // do a callback to RecentsPanelView to let it know we have more values
-                    // how do we let it know we're all done? just always call back twice
-                    if (mRecentsPanel != null) {
-                        mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
-                    }
-                    if (mLoadedTasks == null) {
-                        mLoadedTasks = new ArrayList<TaskDescription>();
-                    }
-                    mLoadedTasks.addAll(newTasks);
-                    mFirstScreenful = false;
-                }
-            }
-            @Override
-            protected Void doInBackground(Void... params) {
-                // We load in two stages: first, we update progress with just the first screenful
-                // of items. Then, we update with the rest of the items
-                final int origPri = Process.getThreadPriority(Process.myTid());
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                final PackageManager pm = mContext.getPackageManager();
-                final ActivityManager am = (ActivityManager)
-                mContext.getSystemService(Context.ACTIVITY_SERVICE);
-
-                final List<ActivityManager.RecentTaskInfo> recentTasks =
-                        am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
-                        | ActivityManager.RECENT_INCLUDE_PROFILES);
-                int numTasks = recentTasks.size();
-                ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
-                        .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
-
-                boolean firstScreenful = true;
-                ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
-
-                // skip the first task - assume it's either the home screen or the current activity.
-                final int first = 0;
-                for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
-                    if (isCancelled()) {
-                        break;
-                    }
-                    final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
-
-                    Intent intent = new Intent(recentInfo.baseIntent);
-                    if (recentInfo.origActivity != null) {
-                        intent.setComponent(recentInfo.origActivity);
-                    }
-
-                    // Don't load the current home activity.
-                    if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
-                        continue;
-                    }
-
-                    // Don't load ourselves
-                    if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
-                        continue;
-                    }
-
-                    TaskDescription item = createTaskDescription(recentInfo.id,
-                            recentInfo.persistentId, recentInfo.baseIntent,
-                            recentInfo.origActivity, recentInfo.description,
-                            recentInfo.userId);
-
-                    if (item != null) {
-                        while (true) {
-                            try {
-                                tasksWaitingForThumbnails.put(item);
-                                break;
-                            } catch (InterruptedException e) {
-                            }
-                        }
-                        tasks.add(item);
-                        if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
-                            publishProgress(tasks);
-                            tasks = new ArrayList<TaskDescription>();
-                            firstScreenful = false;
-                            //break;
-                        }
-                        ++index;
-                    }
-                }
-
-                if (!isCancelled()) {
-                    publishProgress(tasks);
-                    if (firstScreenful) {
-                        // always should publish two updates
-                        publishProgress(new ArrayList<TaskDescription>());
-                    }
-                }
-
-                while (true) {
-                    try {
-                        tasksWaitingForThumbnails.put(new TaskDescription());
-                        break;
-                    } catch (InterruptedException e) {
-                    }
-                }
-
-                Process.setThreadPriority(origPri);
-                return null;
-            }
-        };
-        mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-        loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
-    }
-
-    private void loadThumbnailsAndIconsInBackground(
-            final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
-        // continually read items from tasksWaitingForThumbnails and load
-        // thumbnails and icons for them. finish thread when cancelled or there
-        // is a null item in tasksWaitingForThumbnails
-        mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
-            @Override
-            protected void onProgressUpdate(TaskDescription... values) {
-                if (!isCancelled()) {
-                    TaskDescription td = values[0];
-                    if (td.isNull()) { // end sentinel
-                        mState = State.LOADED;
-                    } else {
-                        if (mRecentsPanel != null) {
-                            mRecentsPanel.onTaskThumbnailLoaded(td);
-                        }
-                    }
-                }
-            }
-            @Override
-            protected Void doInBackground(Void... params) {
-                final int origPri = Process.getThreadPriority(Process.myTid());
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
-                while (true) {
-                    if (isCancelled()) {
-                        break;
-                    }
-                    TaskDescription td = null;
-                    while (td == null) {
-                        try {
-                            td = tasksWaitingForThumbnails.take();
-                        } catch (InterruptedException e) {
-                        }
-                    }
-                    if (td.isNull()) { // end sentinel
-                        publishProgress(td);
-                        break;
-                    }
-                    loadThumbnailAndIcon(td);
-
-                    publishProgress(td);
-                }
-
-                Process.setThreadPriority(origPri);
-                return null;
-            }
-        };
-        mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
deleted file mode 100644
index e9f3cf9..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ /dev/null
@@ -1,326 +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.systemui.recent;
-
-import android.app.ActivityOptions;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.SystemUI;
-import com.android.systemui.recents.AlternateRecentsComponent;
-
-
-public class Recents extends SystemUI implements RecentsComponent {
-    private static final String TAG = "Recents";
-    private static final boolean DEBUG = true;
-
-    // Which recents to use
-    boolean mUseAlternateRecents = true;
-    boolean mBootCompleted = false;
-    static AlternateRecentsComponent sAlternateRecents;
-
-    /** Returns the Recents component, creating a new one in-process if necessary. */
-    public static AlternateRecentsComponent getRecentsComponent(Context context,
-            boolean forceInitialize) {
-        if (sAlternateRecents == null) {
-            sAlternateRecents = new AlternateRecentsComponent(context);
-            if (forceInitialize) {
-                sAlternateRecents.onStart();
-                sAlternateRecents.onBootCompleted();
-            }
-        }
-        return sAlternateRecents;
-    }
-
-    @Override
-    public void start() {
-        if (mUseAlternateRecents) {
-            if (sAlternateRecents == null) {
-                sAlternateRecents = getRecentsComponent(mContext, false);
-            }
-            sAlternateRecents.onStart();
-        }
-
-        putComponent(RecentsComponent.class, this);
-    }
-
-    @Override
-    protected void onBootCompleted() {
-        if (mUseAlternateRecents) {
-            if (sAlternateRecents != null) {
-                sAlternateRecents.onBootCompleted();
-            }
-        }
-        mBootCompleted = true;
-    }
-
-    @Override
-    public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onShowRecents(triggeredFromAltTab);
-        }
-    }
-
-    @Override
-    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onHideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-        } else {
-            Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
-            intent.setPackage("com.android.systemui");
-            sendBroadcastSafely(intent);
-
-            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
-        }
-    }
-
-    @Override
-    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
-        if (mUseAlternateRecents) {
-            // Launch the alternate recents if required
-            sAlternateRecents.onToggleRecents();
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "toggle recents panel");
-        try {
-            TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
-
-            Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
-            intent.setClassName("com.android.systemui",
-                    "com.android.systemui.recent.RecentsActivity");
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
-            if (firstTask == null) {
-                if (RecentsActivity.forceOpaqueBackground(mContext)) {
-                    ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_from_launcher_enter,
-                            R.anim.recents_launch_from_launcher_exit);
-                    mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
-                            UserHandle.USER_CURRENT));
-                } else {
-                    // The correct window animation will be applied via the activity's style
-                    mContext.startActivityAsUser(intent, new UserHandle(
-                            UserHandle.USER_CURRENT));
-                }
-
-            } else {
-                Bitmap first = null;
-                if (firstTask.getThumbnail() instanceof BitmapDrawable) {
-                    first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
-                } else {
-                    first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-                    Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
-                    d.draw(new Canvas(first));
-                }
-                final Resources res = mContext.getResources();
-
-                float thumbWidth = res
-                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
-                float thumbHeight = res
-                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
-                if (first == null) {
-                    throw new RuntimeException("Recents thumbnail is null");
-                }
-                if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
-                    first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
-                            true);
-                    if (first == null) {
-                        throw new RuntimeException("Recents thumbnail is null");
-                    }
-                }
-
-
-                DisplayMetrics dm = new DisplayMetrics();
-                display.getMetrics(dm);
-                // calculate it here, but consider moving it elsewhere
-                // first, determine which orientation you're in.
-                final Configuration config = res.getConfiguration();
-                int x, y;
-
-                if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                    float appLabelLeftMargin = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_label_left_margin);
-                    float appLabelWidth = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_label_width);
-                    float thumbLeftMargin = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_thumbnail_left_margin);
-                    float thumbBgPadding = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_thumbnail_bg_padding);
-
-                    float width = appLabelLeftMargin +
-                            +appLabelWidth
-                            + thumbLeftMargin
-                            + thumbWidth
-                            + 2 * thumbBgPadding;
-
-                    x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
-                            + thumbBgPadding + thumbLeftMargin);
-                    y = (int) (dm.heightPixels
-                            - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height)
-                            - thumbBgPadding);
-                    if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
-                        x = dm.widthPixels - x - res.getDimensionPixelSize(
-                                R.dimen.status_bar_recents_thumbnail_width);
-                    }
-
-                } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-                    float thumbTopMargin = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_thumbnail_top_margin);
-                    float thumbBgPadding = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_thumbnail_bg_padding);
-                    float textPadding = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_text_description_padding);
-                    float labelTextSize = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_label_text_size);
-                    Paint p = new Paint();
-                    p.setTextSize(labelTextSize);
-                    float labelTextHeight = p.getFontMetricsInt().bottom
-                            - p.getFontMetricsInt().top;
-                    float descriptionTextSize = res.getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_description_text_size);
-                    p.setTextSize(descriptionTextSize);
-                    float descriptionTextHeight = p.getFontMetricsInt().bottom
-                            - p.getFontMetricsInt().top;
-
-                    float statusBarHeight = res.getDimensionPixelSize(
-                            com.android.internal.R.dimen.status_bar_height);
-                    float recentsItemTopPadding = statusBarHeight;
-
-                    float height = thumbTopMargin
-                            + thumbHeight
-                            + 2 * thumbBgPadding + textPadding + labelTextHeight
-                            + recentsItemTopPadding + textPadding + descriptionTextHeight;
-                    float recentsItemRightPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
-                    float recentsScrollViewRightPadding = res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
-                    x = (int) (dm.widthPixels - res
-                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
-                            - thumbBgPadding - recentsItemRightPadding
-                            - recentsScrollViewRightPadding);
-                    y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
-                            + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
-                }
-
-                ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
-                        statusBarView,
-                        first, x, y,
-                        new ActivityOptions.OnAnimationStartedListener() {
-                            public void onAnimationStarted() {
-                                Intent intent =
-                                        new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
-                                intent.setPackage("com.android.systemui");
-                                sendBroadcastSafely(intent);
-                            }
-                        });
-                intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
-                startActivitySafely(intent, opts.toBundle());
-            }
-        } catch (ActivityNotFoundException e) {
-            Log.e(TAG, "Failed to launch RecentAppsIntent", e);
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onConfigurationChanged(newConfig);
-        }
-    }
-
-    @Override
-    public void preloadRecents() {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onPreloadRecents();
-        } else {
-            Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
-            intent.setClassName("com.android.systemui",
-                    "com.android.systemui.recent.RecentsPreloadReceiver");
-            sendBroadcastSafely(intent);
-
-            RecentTasksLoader.getInstance(mContext).preloadFirstTask();
-        }
-    }
-
-    @Override
-    public void cancelPreloadingRecents() {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onCancelPreloadingRecents();
-        } else {
-            Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
-            intent.setClassName("com.android.systemui",
-                    "com.android.systemui.recent.RecentsPreloadReceiver");
-            sendBroadcastSafely(intent);
-
-            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
-        }
-    }
-
-    @Override
-    public void showNextAffiliatedTask() {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onShowNextAffiliatedTask();
-        }
-    }
-
-    @Override
-    public void showPrevAffiliatedTask() {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.onShowPrevAffiliatedTask();
-        }
-    }
-
-    @Override
-    public void setCallback(Callbacks cb) {
-        if (mUseAlternateRecents) {
-            sAlternateRecents.setRecentsComponentCallback(cb);
-        }
-    }
-
-    /**
-     * Send broadcast only if BOOT_COMPLETED
-     */
-    private void sendBroadcastSafely(Intent intent) {
-        if (!mBootCompleted) return;
-        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-    }
-
-    /**
-     * Start activity only if BOOT_COMPLETED
-     */
-    private void startActivitySafely(Intent intent, Bundle opts) {
-        if (!mBootCompleted) return;
-        mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT));
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
deleted file mode 100644
index 7ab40b0..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.WallpaperManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarPanel;
-
-import java.util.List;
-
-public class RecentsActivity extends Activity {
-    public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.recent.action.TOGGLE_RECENTS";
-    public static final String PRELOAD_INTENT = "com.android.systemui.recent.action.PRELOAD";
-    public static final String CANCEL_PRELOAD_INTENT = "com.android.systemui.recent.CANCEL_PRELOAD";
-    public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.recent.action.CLOSE";
-    public static final String WINDOW_ANIMATION_START_INTENT = "com.android.systemui.recent.action.WINDOW_ANIMATION_START";
-    public static final String PRELOAD_PERMISSION = "com.android.systemui.recent.permission.PRELOAD";
-    public static final String WAITING_FOR_WINDOW_ANIMATION_PARAM = "com.android.systemui.recent.WAITING_FOR_WINDOW_ANIMATION";
-    private static final String WAS_SHOWING = "was_showing";
-
-    private RecentsPanelView mRecentsPanel;
-    private IntentFilter mIntentFilter;
-    private boolean mShowing;
-    private boolean mForeground;
-
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (CLOSE_RECENTS_INTENT.equals(intent.getAction())) {
-                if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-                    if (mShowing && !mForeground) {
-                        // Captures the case right before we transition to another activity
-                        mRecentsPanel.show(false);
-                    }
-                }
-            } else if (WINDOW_ANIMATION_START_INTENT.equals(intent.getAction())) {
-                if (mRecentsPanel != null) {
-                    mRecentsPanel.onWindowAnimationStart();
-                }
-            }
-        }
-    };
-
-    public class TouchOutsideListener implements View.OnTouchListener {
-        private StatusBarPanel mPanel;
-
-        public TouchOutsideListener(StatusBarPanel panel) {
-            mPanel = panel;
-        }
-
-        public boolean onTouch(View v, MotionEvent ev) {
-            final int action = ev.getAction();
-            if (action == MotionEvent.ACTION_OUTSIDE
-                    || (action == MotionEvent.ACTION_DOWN
-                    && !mPanel.isInContentArea((int) ev.getX(), (int) ev.getY()))) {
-                dismissAndGoHome();
-                return true;
-            }
-            return false;
-        }
-    }
-
-    @Override
-    public void onPause() {
-        overridePendingTransition(
-                R.anim.recents_return_to_launcher_enter,
-                R.anim.recents_return_to_launcher_exit);
-        mForeground = false;
-        super.onPause();
-    }
-
-    @Override
-    public void onStop() {
-        mShowing = false;
-        if (mRecentsPanel != null) {
-            mRecentsPanel.onUiHidden();
-        }
-        super.onStop();
-    }
-
-    private void updateWallpaperVisibility(boolean visible) {
-        int wpflags = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
-        int curflags = getWindow().getAttributes().flags
-                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        if (wpflags != curflags) {
-            getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
-        }
-    }
-
-    public static boolean forceOpaqueBackground(Context context) {
-        return WallpaperManager.getInstance(context).getWallpaperInfo() != null;
-    }
-
-    @Override
-    public void onStart() {
-        // Hide wallpaper if it's not a static image
-        if (forceOpaqueBackground(this)) {
-            updateWallpaperVisibility(false);
-        } else {
-            updateWallpaperVisibility(true);
-        }
-        mShowing = true;
-        if (mRecentsPanel != null) {
-            // Call and refresh the recent tasks list in case we didn't preload tasks
-            // or in case we don't get an onNewIntent
-            mRecentsPanel.refreshRecentTasksList();
-            mRecentsPanel.refreshViews();
-        }
-        super.onStart();
-    }
-
-    @Override
-    public void onResume() {
-        mForeground = true;
-        super.onResume();
-    }
-
-    @Override
-    public void onBackPressed() {
-        dismissAndGoBack();
-    }
-
-    public void dismissAndGoHome() {
-        if (mRecentsPanel != null) {
-            Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
-            homeIntent.addCategory(Intent.CATEGORY_HOME);
-            homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-            startActivityAsUser(homeIntent, new UserHandle(UserHandle.USER_CURRENT));
-            mRecentsPanel.show(false);
-        }
-    }
-
-    public void dismissAndGoBack() {
-        if (mRecentsPanel != null) {
-            final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-
-            final List<ActivityManager.RecentTaskInfo> recentTasks =
-                    am.getRecentTasks(2,
-                            ActivityManager.RECENT_WITH_EXCLUDED |
-                            ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                            ActivityManager.RECENT_INCLUDE_PROFILES);
-            if (recentTasks.size() > 1 &&
-                    mRecentsPanel.simulateClick(recentTasks.get(1).persistentId)) {
-                // recents panel will take care of calling show(false) through simulateClick
-                return;
-            }
-            mRecentsPanel.show(false);
-        }
-        finish();
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        getWindow().addPrivateFlags(
-                WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR);
-        setContentView(R.layout.status_bar_recent_panel);
-        mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
-        mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
-        mRecentsPanel.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-
-        final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
-        recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
-        mRecentsPanel.setMinSwipeAlpha(
-                getResources().getInteger(R.integer.config_recent_item_min_alpha) / 100f);
-
-        if (savedInstanceState == null ||
-                savedInstanceState.getBoolean(WAS_SHOWING)) {
-            handleIntent(getIntent(), (savedInstanceState == null));
-        }
-        mIntentFilter = new IntentFilter();
-        mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
-        mIntentFilter.addAction(WINDOW_ANIMATION_START_INTENT);
-        registerReceiver(mIntentReceiver, mIntentFilter);
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        outState.putBoolean(WAS_SHOWING, mRecentsPanel.isShowing());
-    }
-
-    @Override
-    protected void onDestroy() {
-        RecentTasksLoader.getInstance(this).setRecentsPanel(null, mRecentsPanel);
-        unregisterReceiver(mIntentReceiver);
-        super.onDestroy();
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        handleIntent(intent, true);
-    }
-
-    private void handleIntent(Intent intent, boolean checkWaitingForAnimationParam) {
-        super.onNewIntent(intent);
-
-        if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
-            if (mRecentsPanel != null) {
-                if (mRecentsPanel.isShowing()) {
-                    dismissAndGoBack();
-                } else {
-                    final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
-                    boolean waitingForWindowAnimation = checkWaitingForAnimationParam &&
-                            intent.getBooleanExtra(WAITING_FOR_WINDOW_ANIMATION_PARAM, false);
-                    mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
-                            recentTasksLoader.isFirstScreenful(), waitingForWindowAnimation);
-                }
-            }
-        }
-    }
-
-    boolean isForeground() {
-        return mForeground;
-    }
-
-    boolean isActivityShowing() {
-         return mShowing;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
deleted file mode 100644
index deb5670..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.view.View;
-
-public interface RecentsCallback {
-    static final int SWIPE_LEFT = 0;
-    static final int SWIPE_RIGHT = 1;
-    static final int SWIPE_UP = 2;
-    static final int SWIPE_DOWN = 3;
-
-    void handleOnClick(View selectedView);
-    void handleSwipe(View selectedView);
-    void handleLongPress(View selectedView, View anchorView, View thumbnailView);
-    void dismiss();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
deleted file mode 100644
index 330333a..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.FloatMath;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
-
-import java.util.HashSet;
-import java.util.Iterator;
-
-public class RecentsHorizontalScrollView extends HorizontalScrollView
-        implements SwipeHelper.Callback, RecentsPanelView.RecentsScrollView {
-    private static final String TAG = RecentsPanelView.TAG;
-    private static final boolean DEBUG = RecentsPanelView.DEBUG;
-    private LinearLayout mLinearLayout;
-    private TaskDescriptionAdapter mAdapter;
-    private RecentsCallback mCallback;
-    protected int mLastScrollPosition;
-    private SwipeHelper mSwipeHelper;
-    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
-    private HashSet<View> mRecycledViews;
-    private int mNumItemsInOneScreenful;
-    private Runnable mOnScrollListener;
-
-    public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs, 0);
-        mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, context);
-        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
-        mRecycledViews = new HashSet<View>();
-    }
-
-    public void setMinSwipeAlpha(float minAlpha) {
-        mSwipeHelper.setMinSwipeProgress(minAlpha);
-    }
-
-    private int scrollPositionOfMostRecent() {
-        return mLinearLayout.getWidth() - getWidth();
-    }
-
-    private void addToRecycledViews(View v) {
-        if (mRecycledViews.size() < mNumItemsInOneScreenful) {
-            mRecycledViews.add(v);
-        }
-    }
-
-    public View findViewForTask(int persistentTaskId) {
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View v = mLinearLayout.getChildAt(i);
-            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
-            if (holder.taskDescription.persistentTaskId == persistentTaskId) {
-                return v;
-            }
-        }
-        return null;
-    }
-
-    private void update() {
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View v = mLinearLayout.getChildAt(i);
-            addToRecycledViews(v);
-            mAdapter.recycleView(v);
-        }
-        LayoutTransition transitioner = getLayoutTransition();
-        setLayoutTransition(null);
-
-        mLinearLayout.removeAllViews();
-        Iterator<View> recycledViews = mRecycledViews.iterator();
-        for (int i = 0; i < mAdapter.getCount(); i++) {
-            View old = null;
-            if (recycledViews.hasNext()) {
-                old = recycledViews.next();
-                recycledViews.remove();
-                old.setVisibility(VISIBLE);
-            }
-
-            final View view = mAdapter.getView(i, old, mLinearLayout);
-
-            if (mFadedEdgeDrawHelper != null) {
-                mFadedEdgeDrawHelper.addViewCallback(view);
-            }
-
-            OnTouchListener noOpListener = new OnTouchListener() {
-                @Override
-                public boolean onTouch(View v, MotionEvent event) {
-                    return true;
-                }
-            };
-
-            view.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.dismiss();
-                }
-            });
-            // We don't want a click sound when we dimiss recents
-            view.setSoundEffectsEnabled(false);
-
-            OnClickListener launchAppListener = new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.handleOnClick(view);
-                }
-            };
-
-            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
-            final View thumbnailView = holder.thumbnailView;
-            OnLongClickListener longClickListener = new OnLongClickListener() {
-                public boolean onLongClick(View v) {
-                    final View anchorView = view.findViewById(R.id.app_description);
-                    mCallback.handleLongPress(view, anchorView, thumbnailView);
-                    return true;
-                }
-            };
-            thumbnailView.setClickable(true);
-            thumbnailView.setOnClickListener(launchAppListener);
-            thumbnailView.setOnLongClickListener(longClickListener);
-
-            // We don't want to dismiss recents if a user clicks on the app title
-            // (we also don't want to launch the app either, though, because the
-            // app title is a small target and doesn't have great click feedback)
-            final View appTitle = view.findViewById(R.id.app_label);
-            appTitle.setContentDescription(" ");
-            appTitle.setOnTouchListener(noOpListener);
-            mLinearLayout.addView(view);
-        }
-        setLayoutTransition(transitioner);
-
-        // Scroll to end after initial layout.
-
-        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
-                public void onGlobalLayout() {
-                    mLastScrollPosition = scrollPositionOfMostRecent();
-                    scrollTo(mLastScrollPosition, 0);
-                    final ViewTreeObserver observer = getViewTreeObserver();
-                    if (observer.isAlive()) {
-                        observer.removeOnGlobalLayoutListener(this);
-                    }
-                }
-            };
-        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
-    }
-
-    @Override
-    public void removeViewInLayout(final View view) {
-        dismissChild(view);
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        return mSwipeHelper.onInterceptTouchEvent(ev) ||
-            super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return mSwipeHelper.onTouchEvent(ev) ||
-            super.onTouchEvent(ev);
-    }
-
-    public boolean canChildBeDismissed(View v) {
-        return true;
-    }
-
-    @Override
-    public boolean isAntiFalsingNeeded() {
-        return false;
-    }
-
-    @Override
-    public float getFalsingThresholdFactor() {
-        return 1.0f;
-    }
-
-    public void dismissChild(View v) {
-        mSwipeHelper.dismissChild(v, 0);
-    }
-
-    public void onChildDismissed(View v) {
-        addToRecycledViews(v);
-        mLinearLayout.removeView(v);
-        mCallback.handleSwipe(v);
-        // Restore the alpha/translation parameters to what they were before swiping
-        // (for when these items are recycled)
-        View contentView = getChildContentView(v);
-        contentView.setAlpha(1f);
-        contentView.setTranslationY(0);
-    }
-
-    public void onBeginDrag(View v) {
-        // We do this so the underlying ScrollView knows that it won't get
-        // the chance to intercept events anymore
-        requestDisallowInterceptTouchEvent(true);
-    }
-
-    public void onDragCancelled(View v) {
-    }
-
-    @Override
-    public void onChildSnappedBack(View animView) {
-    }
-
-    @Override
-    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
-        return false;
-    }
-
-    public View getChildAtPosition(MotionEvent ev) {
-        final float x = ev.getX() + getScrollX();
-        final float y = ev.getY() + getScrollY();
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View item = mLinearLayout.getChildAt(i);
-            if (x >= item.getLeft() && x < item.getRight()
-                && y >= item.getTop() && y < item.getBottom()) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    public View getChildContentView(View v) {
-        return v.findViewById(R.id.recent_item);
-    }
-
-    @Override
-    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
-        if (mFadedEdgeDrawHelper != null) {
-
-            mFadedEdgeDrawHelper.drawCallback(canvas,
-                    left, right, top, bottom, getScrollX(), getScrollY(),
-                    0, 0,
-                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), getPaddingTop());
-        }
-    }
-
-    @Override
-    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-       super.onScrollChanged(l, t, oldl, oldt);
-       if (mOnScrollListener != null) {
-           mOnScrollListener.run();
-       }
-    }
-
-    public void setOnScrollListener(Runnable listener) {
-        mOnScrollListener = listener;
-    }
-
-    @Override
-    public int getVerticalFadingEdgeLength() {
-        if (mFadedEdgeDrawHelper != null) {
-            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
-        } else {
-            return super.getVerticalFadingEdgeLength();
-        }
-    }
-
-    @Override
-    public int getHorizontalFadingEdgeLength() {
-        if (mFadedEdgeDrawHelper != null) {
-            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
-        } else {
-            return super.getHorizontalFadingEdgeLength();
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        setScrollbarFadingEnabled(true);
-        mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-        final int leftPadding = getContext().getResources()
-            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
-        setOverScrollEffectPadding(leftPadding, 0);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        if (mFadedEdgeDrawHelper != null) {
-            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        float densityScale = getResources().getDisplayMetrics().density;
-        mSwipeHelper.setDensityScale(densityScale);
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
-    }
-
-    private void setOverScrollEffectPadding(int leftPadding, int i) {
-        // TODO Add to (Vertical)ScrollView
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        // Skip this work if a transition is running; it sets the scroll values independently
-        // and should not have those animated values clobbered by this logic
-        LayoutTransition transition = mLinearLayout.getLayoutTransition();
-        if (transition != null && transition.isRunning()) {
-            return;
-        }
-        // Keep track of the last visible item in the list so we can restore it
-        // to the bottom when the orientation changes.
-        mLastScrollPosition = scrollPositionOfMostRecent();
-
-        // This has to happen post-layout, so run it "in the future"
-        post(new Runnable() {
-            public void run() {
-                // Make sure we're still not clobbering the transition-set values, since this
-                // runnable launches asynchronously
-                LayoutTransition transition = mLinearLayout.getLayoutTransition();
-                if (transition == null || !transition.isRunning()) {
-                    scrollTo(mLastScrollPosition, 0);
-                }
-            }
-        });
-    }
-
-    public void setAdapter(TaskDescriptionAdapter adapter) {
-        mAdapter = adapter;
-        mAdapter.registerDataSetObserver(new DataSetObserver() {
-            public void onChanged() {
-                update();
-            }
-
-            public void onInvalidated() {
-                update();
-            }
-        });
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
-        int childheightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
-        View child = mAdapter.createView(mLinearLayout);
-        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-        mNumItemsInOneScreenful =
-                (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
-        addToRecycledViews(child);
-
-        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
-            addToRecycledViews(mAdapter.createView(mLinearLayout));
-        }
-    }
-
-    public int numItemsInOneScreenful() {
-        return mNumItemsInOneScreenful;
-    }
-
-    @Override
-    public void setLayoutTransition(LayoutTransition transition) {
-        // The layout transition applies to our embedded LinearLayout
-        mLinearLayout.setLayoutTransition(transition);
-    }
-
-    public void setCallback(RecentsCallback callback) {
-        mCallback = callback;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
deleted file mode 100644
index 4c3460e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.animation.Animator;
-import android.animation.LayoutTransition;
-import android.animation.TimeInterpolator;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
-import android.app.TaskStackBuilder;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Shader.TileMode;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewRootImpl;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.PopupMenu;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.StatusBarPanel;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-import java.util.ArrayList;
-
-public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
-        StatusBarPanel, Animator.AnimatorListener {
-    static final String TAG = "RecentsPanelView";
-    static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
-    private PopupMenu mPopup;
-    private View mRecentsScrim;
-    private View mRecentsNoApps;
-    private RecentsScrollView mRecentsContainer;
-
-    private boolean mShowing;
-    private boolean mWaitingToShow;
-    private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
-    private boolean mAnimateIconOfFirstTask;
-    private boolean mWaitingForWindowAnimation;
-    private long mWindowAnimationStartTime;
-    private boolean mCallUiHiddenBeforeNextReload;
-
-    private RecentTasksLoader mRecentTasksLoader;
-    private ArrayList<TaskDescription> mRecentTaskDescriptions;
-    private TaskDescriptionAdapter mListAdapter;
-    private int mThumbnailWidth;
-    private boolean mFitThumbnailToXY;
-    private int mRecentItemLayoutId;
-    private boolean mHighEndGfx;
-
-    public static interface RecentsScrollView {
-        public int numItemsInOneScreenful();
-        public void setAdapter(TaskDescriptionAdapter adapter);
-        public void setCallback(RecentsCallback callback);
-        public void setMinSwipeAlpha(float minAlpha);
-        public View findViewForTask(int persistentTaskId);
-        public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
-        public void setOnScrollListener(Runnable listener);
-    }
-
-    private final class OnLongClickDelegate implements View.OnLongClickListener {
-        View mOtherView;
-        OnLongClickDelegate(View other) {
-            mOtherView = other;
-        }
-        public boolean onLongClick(View v) {
-            return mOtherView.performLongClick();
-        }
-    }
-
-    /* package */ final static class ViewHolder {
-        View thumbnailView;
-        ImageView thumbnailViewImage;
-        Drawable thumbnailViewDrawable;
-        ImageView iconView;
-        TextView labelView;
-        TextView descriptionView;
-        View calloutLine;
-        TaskDescription taskDescription;
-        boolean loadedThumbnailAndIcon;
-    }
-
-    /* package */ final class TaskDescriptionAdapter extends BaseAdapter {
-        private LayoutInflater mInflater;
-
-        public TaskDescriptionAdapter(Context context) {
-            mInflater = LayoutInflater.from(context);
-        }
-
-        public int getCount() {
-            return mRecentTaskDescriptions != null ? mRecentTaskDescriptions.size() : 0;
-        }
-
-        public Object getItem(int position) {
-            return position; // we only need the index
-        }
-
-        public long getItemId(int position) {
-            return position; // we just need something unique for this position
-        }
-
-        public View createView(ViewGroup parent) {
-            View convertView = mInflater.inflate(mRecentItemLayoutId, parent, false);
-            ViewHolder holder = new ViewHolder();
-            holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
-            holder.thumbnailViewImage =
-                    (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
-            // If we set the default thumbnail now, we avoid an onLayout when we update
-            // the thumbnail later (if they both have the same dimensions)
-            updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-            holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
-            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
-            holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
-            holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
-            holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
-
-            convertView.setTag(holder);
-            return convertView;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = createView(parent);
-            }
-            final ViewHolder holder = (ViewHolder) convertView.getTag();
-
-            // index is reverse since most recent appears at the bottom...
-            final int index = mRecentTaskDescriptions.size() - position - 1;
-
-            final TaskDescription td = mRecentTaskDescriptions.get(index);
-
-            holder.labelView.setText(td.getLabel());
-            holder.thumbnailView.setContentDescription(td.getLabel());
-            holder.loadedThumbnailAndIcon = td.isLoaded();
-            if (td.isLoaded()) {
-                updateThumbnail(holder, td.getThumbnail(), true, false);
-                updateIcon(holder, td.getIcon(), true, false);
-            }
-            if (index == 0) {
-                if (mAnimateIconOfFirstTask) {
-                    ViewHolder oldHolder = mItemToAnimateInWhenWindowAnimationIsFinished;
-                    if (oldHolder != null) {
-                        oldHolder.iconView.setAlpha(1f);
-                        oldHolder.iconView.setTranslationX(0f);
-                        oldHolder.iconView.setTranslationY(0f);
-                        oldHolder.labelView.setAlpha(1f);
-                        oldHolder.labelView.setTranslationX(0f);
-                        oldHolder.labelView.setTranslationY(0f);
-                        if (oldHolder.calloutLine != null) {
-                            oldHolder.calloutLine.setAlpha(1f);
-                            oldHolder.calloutLine.setTranslationX(0f);
-                            oldHolder.calloutLine.setTranslationY(0f);
-                        }
-                    }
-                    mItemToAnimateInWhenWindowAnimationIsFinished = holder;
-                    int translation = -getResources().getDimensionPixelSize(
-                            R.dimen.status_bar_recents_app_icon_translate_distance);
-                    final Configuration config = getResources().getConfiguration();
-                    if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                        if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-                            translation = -translation;
-                        }
-                        holder.iconView.setAlpha(0f);
-                        holder.iconView.setTranslationX(translation);
-                        holder.labelView.setAlpha(0f);
-                        holder.labelView.setTranslationX(translation);
-                        holder.calloutLine.setAlpha(0f);
-                        holder.calloutLine.setTranslationX(translation);
-                    } else {
-                        holder.iconView.setAlpha(0f);
-                        holder.iconView.setTranslationY(translation);
-                    }
-                    if (!mWaitingForWindowAnimation) {
-                        animateInIconOfFirstTask();
-                    }
-                }
-            }
-
-            holder.thumbnailView.setTag(td);
-            holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
-            holder.taskDescription = td;
-            return convertView;
-        }
-
-        public void recycleView(View v) {
-            ViewHolder holder = (ViewHolder) v.getTag();
-            updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
-            holder.iconView.setVisibility(INVISIBLE);
-            holder.iconView.animate().cancel();
-            holder.labelView.setText(null);
-            holder.labelView.animate().cancel();
-            holder.thumbnailView.setContentDescription(null);
-            holder.thumbnailView.setTag(null);
-            holder.thumbnailView.setOnLongClickListener(null);
-            holder.thumbnailView.setVisibility(INVISIBLE);
-            holder.iconView.setAlpha(1f);
-            holder.iconView.setTranslationX(0f);
-            holder.iconView.setTranslationY(0f);
-            holder.labelView.setAlpha(1f);
-            holder.labelView.setTranslationX(0f);
-            holder.labelView.setTranslationY(0f);
-            if (holder.calloutLine != null) {
-                holder.calloutLine.setAlpha(1f);
-                holder.calloutLine.setTranslationX(0f);
-                holder.calloutLine.setTranslationY(0f);
-                holder.calloutLine.animate().cancel();
-            }
-            holder.taskDescription = null;
-            holder.loadedThumbnailAndIcon = false;
-        }
-    }
-
-    public RecentsPanelView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        updateValuesFromResources();
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecentsPanelView,
-                defStyle, 0);
-
-        mRecentItemLayoutId = a.getResourceId(R.styleable.RecentsPanelView_recentItemLayout, 0);
-        mRecentTasksLoader = RecentTasksLoader.getInstance(context);
-        a.recycle();
-    }
-
-    public int numItemsInOneScreenful() {
-        return mRecentsContainer.numItemsInOneScreenful();
-    }
-
-    private boolean pointInside(int x, int y, View v) {
-        final int l = v.getLeft();
-        final int r = v.getRight();
-        final int t = v.getTop();
-        final int b = v.getBottom();
-        return x >= l && x < r && y >= t && y < b;
-    }
-
-    public boolean isInContentArea(int x, int y) {
-        return pointInside(x, y, (View) mRecentsContainer);
-    }
-
-    public void show(boolean show) {
-        show(show, null, false, false);
-    }
-
-    public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
-            boolean firstScreenful, boolean animateIconOfFirstTask) {
-        if (show && mCallUiHiddenBeforeNextReload) {
-            onUiHidden();
-            recentTaskDescriptions = null;
-            mAnimateIconOfFirstTask = false;
-            mWaitingForWindowAnimation = false;
-        } else {
-            mAnimateIconOfFirstTask = animateIconOfFirstTask;
-            mWaitingForWindowAnimation = animateIconOfFirstTask;
-        }
-        if (show) {
-            mWaitingToShow = true;
-            refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
-            showIfReady();
-        } else {
-            showImpl(false);
-        }
-    }
-
-    private void showIfReady() {
-        // mWaitingToShow => there was a touch up on the recents button
-        // mRecentTaskDescriptions != null => we've created views for the first screenful of items
-        if (mWaitingToShow && mRecentTaskDescriptions != null) {
-            showImpl(true);
-        }
-    }
-
-    static void sendCloseSystemWindows(Context context, String reason) {
-        if (ActivityManagerNative.isSystemReady()) {
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    private void showImpl(boolean show) {
-        sendCloseSystemWindows(getContext(), BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
-
-        mShowing = show;
-
-        if (show) {
-            // if there are no apps, bring up a "No recent apps" message
-            boolean noApps = mRecentTaskDescriptions != null
-                    && (mRecentTaskDescriptions.size() == 0);
-            mRecentsNoApps.setAlpha(1f);
-            mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
-
-            onAnimationEnd(null);
-            setFocusable(true);
-            setFocusableInTouchMode(true);
-            requestFocus();
-        } else {
-            mWaitingToShow = false;
-            // call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
-            mCallUiHiddenBeforeNextReload = true;
-            if (mPopup != null) {
-                mPopup.dismiss();
-            }
-        }
-    }
-
-    protected void onAttachedToWindow () {
-        super.onAttachedToWindow();
-        final ViewRootImpl root = getViewRootImpl();
-        if (root != null) {
-            root.setDrawDuringWindowsAnimating(true);
-        }
-    }
-
-    public void onUiHidden() {
-        mCallUiHiddenBeforeNextReload = false;
-        if (!mShowing && mRecentTaskDescriptions != null) {
-            onAnimationEnd(null);
-            clearRecentTasksList();
-        }
-    }
-
-    public void dismiss() {
-        ((RecentsActivity) getContext()).dismissAndGoHome();
-    }
-
-    public void dismissAndGoBack() {
-        ((RecentsActivity) getContext()).dismissAndGoBack();
-    }
-
-    public void onAnimationCancel(Animator animation) {
-    }
-
-    public void onAnimationEnd(Animator animation) {
-        if (mShowing) {
-            final LayoutTransition transitioner = new LayoutTransition();
-            ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
-            createCustomAnimations(transitioner);
-        } else {
-            ((ViewGroup)mRecentsContainer).setLayoutTransition(null);
-        }
-    }
-
-    public void onAnimationRepeat(Animator animation) {
-    }
-
-    public void onAnimationStart(Animator animation) {
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-
-    /**
-     * Whether the panel is showing, or, if it's animating, whether it will be
-     * when the animation is done.
-     */
-    public boolean isShowing() {
-        return mShowing;
-    }
-
-    public void setRecentTasksLoader(RecentTasksLoader loader) {
-        mRecentTasksLoader = loader;
-    }
-
-    public void updateValuesFromResources() {
-        final Resources res = getContext().getResources();
-        mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
-        mFitThumbnailToXY = res.getBoolean(R.bool.config_recents_thumbnail_image_fits_to_xy);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
-        mRecentsContainer.setOnScrollListener(new Runnable() {
-            public void run() {
-                // need to redraw the faded edges
-                invalidate();
-            }
-        });
-        mListAdapter = new TaskDescriptionAdapter(getContext());
-        mRecentsContainer.setAdapter(mListAdapter);
-        mRecentsContainer.setCallback(this);
-
-        mRecentsScrim = findViewById(R.id.recents_bg_protect);
-        mRecentsNoApps = findViewById(R.id.recents_no_apps);
-
-        if (mRecentsScrim != null) {
-            mHighEndGfx = ActivityManager.isHighEndGfx();
-            if (!mHighEndGfx) {
-                mRecentsScrim.setBackground(null);
-            } else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
-                // In order to save space, we make the background texture repeat in the Y direction
-                ((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
-            }
-        }
-    }
-
-    public void setMinSwipeAlpha(float minAlpha) {
-        mRecentsContainer.setMinSwipeAlpha(minAlpha);
-    }
-
-    private void createCustomAnimations(LayoutTransition transitioner) {
-        transitioner.setDuration(200);
-        transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
-        transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
-    }
-
-    private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
-        if (icon != null) {
-            h.iconView.setImageDrawable(icon);
-            if (show && h.iconView.getVisibility() != View.VISIBLE) {
-                if (anim) {
-                    h.iconView.setAnimation(
-                            AnimationUtils.loadAnimation(getContext(), R.anim.recent_appear));
-                }
-                h.iconView.setVisibility(View.VISIBLE);
-            }
-        }
-    }
-
-    private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
-        if (thumbnail != null) {
-            // Should remove the default image in the frame
-            // that this now covers, to improve scrolling speed.
-            // That can't be done until the anim is complete though.
-            h.thumbnailViewImage.setImageDrawable(thumbnail);
-
-            // scale the image to fill the full width of the ImageView. do this only if
-            // we haven't set a bitmap before, or if the bitmap size has changed
-            if (h.thumbnailViewDrawable == null ||
-                h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
-                h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
-                if (mFitThumbnailToXY) {
-                    h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
-                } else {
-                    Matrix scaleMatrix = new Matrix();
-                    float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
-                    scaleMatrix.setScale(scale, scale);
-                    h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
-                    h.thumbnailViewImage.setImageMatrix(scaleMatrix);
-                }
-            }
-            if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
-                if (anim) {
-                    h.thumbnailView.setAnimation(
-                            AnimationUtils.loadAnimation(getContext(), R.anim.recent_appear));
-                }
-                h.thumbnailView.setVisibility(View.VISIBLE);
-            }
-            h.thumbnailViewDrawable = thumbnail;
-        }
-    }
-
-    void onTaskThumbnailLoaded(TaskDescription td) {
-        synchronized (td) {
-            if (mRecentsContainer != null) {
-                ViewGroup container = (ViewGroup) mRecentsContainer;
-                if (container instanceof RecentsScrollView) {
-                    container = (ViewGroup) container.findViewById(
-                            R.id.recents_linear_layout);
-                }
-                // Look for a view showing this thumbnail, to update.
-                for (int i=0; i < container.getChildCount(); i++) {
-                    View v = container.getChildAt(i);
-                    if (v.getTag() instanceof ViewHolder) {
-                        ViewHolder h = (ViewHolder)v.getTag();
-                        if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
-                            // only fade in the thumbnail if recents is already visible-- we
-                            // show it immediately otherwise
-                            //boolean animateShow = mShowing &&
-                            //    mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
-                            boolean animateShow = false;
-                            updateIcon(h, td.getIcon(), true, animateShow);
-                            updateThumbnail(h, td.getThumbnail(), true, animateShow);
-                            h.loadedThumbnailAndIcon = true;
-                        }
-                    }
-                }
-            }
-        }
-        showIfReady();
-    }
-
-    private void animateInIconOfFirstTask() {
-        if (mItemToAnimateInWhenWindowAnimationIsFinished != null &&
-                !mRecentTasksLoader.isFirstScreenful()) {
-            int timeSinceWindowAnimation =
-                    (int) (System.currentTimeMillis() - mWindowAnimationStartTime);
-            final int minStartDelay = 150;
-            final int startDelay = Math.max(0, Math.min(
-                    minStartDelay - timeSinceWindowAnimation, minStartDelay));
-            final int duration = 250;
-            final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
-            final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
-            FirstFrameAnimatorHelper.initializeDrawListener(holder.iconView);
-            for (View v :
-                new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
-                if (v != null) {
-                    ViewPropertyAnimator vpa = v.animate().translationX(0).translationY(0)
-                            .alpha(1f).setStartDelay(startDelay)
-                            .setDuration(duration).setInterpolator(cubic);
-                    FirstFrameAnimatorHelper h = new FirstFrameAnimatorHelper(vpa, v);
-                }
-            }
-            mItemToAnimateInWhenWindowAnimationIsFinished = null;
-            mAnimateIconOfFirstTask = false;
-        }
-    }
-
-    public void onWindowAnimationStart() {
-        mWaitingForWindowAnimation = false;
-        mWindowAnimationStartTime = System.currentTimeMillis();
-        animateInIconOfFirstTask();
-    }
-
-    public void clearRecentTasksList() {
-        // Clear memory used by screenshots
-        if (mRecentTaskDescriptions != null) {
-            mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(this);
-            onTaskLoadingCancelled();
-        }
-    }
-
-    public void onTaskLoadingCancelled() {
-        // Gets called by RecentTasksLoader when it's cancelled
-        if (mRecentTaskDescriptions != null) {
-            mRecentTaskDescriptions = null;
-            mListAdapter.notifyDataSetInvalidated();
-        }
-    }
-
-    public void refreshViews() {
-        mListAdapter.notifyDataSetInvalidated();
-        updateUiElements();
-        showIfReady();
-    }
-
-    public void refreshRecentTasksList() {
-        refreshRecentTasksList(null, false);
-    }
-
-    private void refreshRecentTasksList(
-            ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
-        if (mRecentTaskDescriptions == null && recentTasksList != null) {
-            onTasksLoaded(recentTasksList, firstScreenful);
-        } else {
-            mRecentTasksLoader.loadTasksInBackground();
-        }
-    }
-
-    public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
-        if (mRecentTaskDescriptions == null) {
-            mRecentTaskDescriptions = new ArrayList<TaskDescription>(tasks);
-        } else {
-            mRecentTaskDescriptions.addAll(tasks);
-        }
-        if (((RecentsActivity) getContext()).isActivityShowing()) {
-            refreshViews();
-        }
-    }
-
-    private void updateUiElements() {
-        final int items = mRecentTaskDescriptions != null
-                ? mRecentTaskDescriptions.size() : 0;
-
-        ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
-
-        // Set description for accessibility
-        int numRecentApps = mRecentTaskDescriptions != null
-                ? mRecentTaskDescriptions.size() : 0;
-        String recentAppsAccessibilityDescription;
-        if (numRecentApps == 0) {
-            recentAppsAccessibilityDescription =
-                getResources().getString(R.string.status_bar_no_recent_apps);
-        } else {
-            recentAppsAccessibilityDescription = getResources().getQuantityString(
-                R.plurals.status_bar_accessibility_recent_apps, numRecentApps, numRecentApps);
-        }
-        setContentDescription(recentAppsAccessibilityDescription);
-    }
-
-    public boolean simulateClick(int persistentTaskId) {
-        View v = mRecentsContainer.findViewForTask(persistentTaskId);
-        if (v != null) {
-            handleOnClick(v);
-            return true;
-        }
-        return false;
-    }
-
-    public void handleOnClick(View view) {
-        ViewHolder holder = (ViewHolder) view.getTag();
-        TaskDescription ad = holder.taskDescription;
-        final Context context = view.getContext();
-        final ActivityManager am = (ActivityManager)
-                context.getSystemService(Context.ACTIVITY_SERVICE);
-
-        Bitmap bm = null;
-        boolean usingDrawingCache = true;
-        if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
-            bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
-            if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
-                    bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
-                usingDrawingCache = false;
-            }
-        }
-        if (usingDrawingCache) {
-            holder.thumbnailViewImage.setDrawingCacheEnabled(true);
-            bm = holder.thumbnailViewImage.getDrawingCache();
-        }
-        Bundle opts = (bm == null) ?
-                null :
-                ActivityOptions.makeThumbnailScaleUpAnimation(
-                        holder.thumbnailViewImage, bm, 0, 0, null).toBundle();
-
-        show(false);
-        if (ad.taskId >= 0) {
-            // This is an active task; it should just go to the foreground.
-            am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
-                    opts);
-        } else {
-            Intent intent = ad.intent;
-            intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
-                    | Intent.FLAG_ACTIVITY_TASK_ON_HOME
-                    | Intent.FLAG_ACTIVITY_NEW_TASK);
-            if (DEBUG) Log.v(TAG, "Starting activity " + intent);
-            try {
-                context.startActivityAsUser(intent, opts,
-                        new UserHandle(ad.userId));
-            } catch (SecurityException e) {
-                Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
-            } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "Error launching activity " + intent, e);
-            }
-        }
-        if (usingDrawingCache) {
-            holder.thumbnailViewImage.setDrawingCacheEnabled(false);
-        }
-    }
-
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        handleOnClick(view);
-    }
-
-    public void handleSwipe(View view) {
-        TaskDescription ad = ((ViewHolder) view.getTag()).taskDescription;
-        if (ad == null) {
-            Log.v(TAG, "Not able to find activity description for swiped task; view=" + view +
-                    " tag=" + view.getTag());
-            return;
-        }
-        if (DEBUG) Log.v(TAG, "Jettison " + ad.getLabel());
-        mRecentTaskDescriptions.remove(ad);
-        mRecentTasksLoader.remove(ad);
-
-        // Handled by widget containers to enable LayoutTransitions properly
-        // mListAdapter.notifyDataSetChanged();
-
-        if (mRecentTaskDescriptions.size() == 0) {
-            dismissAndGoBack();
-        }
-
-        // Currently, either direction means the same thing, so ignore direction and remove
-        // the task.
-        final ActivityManager am = (ActivityManager)
-                getContext().getSystemService(Context.ACTIVITY_SERVICE);
-        if (am != null) {
-            am.removeTask(ad.persistentTaskId);
-
-            // Accessibility feedback
-            setContentDescription(
-                    getContext().getString(R.string.accessibility_recents_item_dismissed, ad.getLabel()));
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            setContentDescription(null);
-        }
-    }
-
-    private void startApplicationDetailsActivity(String packageName, int userId) {
-        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
-                Uri.fromParts("package", packageName, null));
-        intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
-        TaskStackBuilder.create(getContext())
-                .addNextIntentWithParentStack(intent).startActivities(null, new UserHandle(userId));
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (mPopup != null) {
-            return true;
-        } else {
-            return super.onInterceptTouchEvent(ev);
-        }
-    }
-
-    public void handleLongPress(
-            final View selectedView, final View anchorView, final View thumbnailView) {
-        thumbnailView.setSelected(true);
-        final PopupMenu popup =
-            new PopupMenu(getContext(), anchorView == null ? selectedView : anchorView);
-        mPopup = popup;
-        popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
-        popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                if (item.getItemId() == R.id.recent_remove_item) {
-                    ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
-                } else if (item.getItemId() == R.id.recent_inspect_item) {
-                    ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
-                    if (viewHolder != null) {
-                        final TaskDescription ad = viewHolder.taskDescription;
-                        startApplicationDetailsActivity(ad.packageName, ad.userId);
-                        show(false);
-                    } else {
-                        throw new IllegalStateException("Oops, no tag on view " + selectedView);
-                    }
-                } else {
-                    return false;
-                }
-                return true;
-            }
-        });
-        popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
-            public void onDismiss(PopupMenu menu) {
-                thumbnailView.setSelected(false);
-                mPopup = null;
-            }
-        });
-        popup.show();
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        int paddingLeft = getPaddingLeft();
-        final boolean offsetRequired = isPaddingOffsetRequired();
-        if (offsetRequired) {
-            paddingLeft += getLeftPaddingOffset();
-        }
-
-        int left = getScrollX() + paddingLeft;
-        int right = left + getRight() - getLeft() - getPaddingRight() - paddingLeft;
-        int top = getScrollY() + getFadeTop(offsetRequired);
-        int bottom = top + getFadeHeight(offsetRequired);
-
-        if (offsetRequired) {
-            right += getRightPaddingOffset();
-            bottom += getBottomPaddingOffset();
-        }
-        mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
deleted file mode 100644
index eb5892007..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class RecentsPreloadReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (RecentsActivity.PRELOAD_INTENT.equals(intent.getAction())) {
-            RecentTasksLoader.getInstance(context).preloadRecentTasksList();
-        } else if (RecentsActivity.CANCEL_PRELOAD_INTENT.equals(intent.getAction())){
-            RecentTasksLoader.getInstance(context).cancelPreloadingRecentTasksList();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
deleted file mode 100644
index 1e247be..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.FloatMath;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
-import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
-
-import java.util.HashSet;
-import java.util.Iterator;
-
-public class RecentsVerticalScrollView extends ScrollView
-        implements SwipeHelper.Callback, RecentsPanelView.RecentsScrollView {
-    private static final String TAG = RecentsPanelView.TAG;
-    private static final boolean DEBUG = RecentsPanelView.DEBUG;
-    private LinearLayout mLinearLayout;
-    private TaskDescriptionAdapter mAdapter;
-    private RecentsCallback mCallback;
-    protected int mLastScrollPosition;
-    private SwipeHelper mSwipeHelper;
-    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
-    private HashSet<View> mRecycledViews;
-    private int mNumItemsInOneScreenful;
-    private Runnable mOnScrollListener;
-
-    public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
-        super(context, attrs, 0);
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context);
-
-        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
-        mRecycledViews = new HashSet<View>();
-    }
-
-    public void setMinSwipeAlpha(float minAlpha) {
-        mSwipeHelper.setMinSwipeProgress(minAlpha);
-    }
-
-    private int scrollPositionOfMostRecent() {
-        return mLinearLayout.getHeight() - getHeight() + getPaddingTop();
-    }
-
-    private void addToRecycledViews(View v) {
-        if (mRecycledViews.size() < mNumItemsInOneScreenful) {
-            mRecycledViews.add(v);
-        }
-    }
-
-    public View findViewForTask(int persistentTaskId) {
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View v = mLinearLayout.getChildAt(i);
-            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
-            if (holder.taskDescription.persistentTaskId == persistentTaskId) {
-                return v;
-            }
-        }
-        return null;
-    }
-
-    private void update() {
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View v = mLinearLayout.getChildAt(i);
-            addToRecycledViews(v);
-            mAdapter.recycleView(v);
-        }
-        LayoutTransition transitioner = getLayoutTransition();
-        setLayoutTransition(null);
-
-        mLinearLayout.removeAllViews();
-
-        // Once we can clear the data associated with individual item views,
-        // we can get rid of the removeAllViews() and the code below will
-        // recycle them.
-        Iterator<View> recycledViews = mRecycledViews.iterator();
-        for (int i = 0; i < mAdapter.getCount(); i++) {
-            View old = null;
-            if (recycledViews.hasNext()) {
-                old = recycledViews.next();
-                recycledViews.remove();
-                old.setVisibility(VISIBLE);
-            }
-            final View view = mAdapter.getView(i, old, mLinearLayout);
-
-            if (mFadedEdgeDrawHelper != null) {
-                mFadedEdgeDrawHelper.addViewCallback(view);
-            }
-
-            OnTouchListener noOpListener = new OnTouchListener() {
-                @Override
-                public boolean onTouch(View v, MotionEvent event) {
-                    return true;
-                }
-            };
-
-            view.setOnClickListener(new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.dismiss();
-                }
-            });
-            // We don't want a click sound when we dimiss recents
-            view.setSoundEffectsEnabled(false);
-
-            OnClickListener launchAppListener = new OnClickListener() {
-                public void onClick(View v) {
-                    mCallback.handleOnClick(view);
-                }
-            };
-
-            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
-            final View thumbnailView = holder.thumbnailView;
-            OnLongClickListener longClickListener = new OnLongClickListener() {
-                public boolean onLongClick(View v) {
-                    final View anchorView = view.findViewById(R.id.app_description);
-                    mCallback.handleLongPress(view, anchorView, thumbnailView);
-                    return true;
-                }
-            };
-            thumbnailView.setClickable(true);
-            thumbnailView.setOnClickListener(launchAppListener);
-            thumbnailView.setOnLongClickListener(longClickListener);
-
-            // We don't want to dismiss recents if a user clicks on the app title
-            // (we also don't want to launch the app either, though, because the
-            // app title is a small target and doesn't have great click feedback)
-            final View appTitle = view.findViewById(R.id.app_label);
-            appTitle.setContentDescription(" ");
-            appTitle.setOnTouchListener(noOpListener);
-            final View calloutLine = view.findViewById(R.id.recents_callout_line);
-            if (calloutLine != null) {
-                calloutLine.setOnTouchListener(noOpListener);
-            }
-
-            mLinearLayout.addView(view);
-        }
-        setLayoutTransition(transitioner);
-
-        // Scroll to end after initial layout.
-        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
-                public void onGlobalLayout() {
-                    mLastScrollPosition = scrollPositionOfMostRecent();
-                    scrollTo(0, mLastScrollPosition);
-                    final ViewTreeObserver observer = getViewTreeObserver();
-                    if (observer.isAlive()) {
-                        observer.removeOnGlobalLayoutListener(this);
-                    }
-                }
-            };
-        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
-    }
-
-    @Override
-    public void removeViewInLayout(final View view) {
-        dismissChild(view);
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        return mSwipeHelper.onInterceptTouchEvent(ev) ||
-            super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        return mSwipeHelper.onTouchEvent(ev) ||
-            super.onTouchEvent(ev);
-    }
-
-    public boolean canChildBeDismissed(View v) {
-        return true;
-    }
-
-    @Override
-    public boolean isAntiFalsingNeeded() {
-        return false;
-    }
-
-    @Override
-    public float getFalsingThresholdFactor() {
-        return 1.0f;
-    }
-
-    public void dismissChild(View v) {
-        mSwipeHelper.dismissChild(v, 0);
-    }
-
-    public void onChildDismissed(View v) {
-        addToRecycledViews(v);
-        mLinearLayout.removeView(v);
-        mCallback.handleSwipe(v);
-        // Restore the alpha/translation parameters to what they were before swiping
-        // (for when these items are recycled)
-        View contentView = getChildContentView(v);
-        contentView.setAlpha(1f);
-        contentView.setTranslationX(0);
-    }
-
-    public void onBeginDrag(View v) {
-        // We do this so the underlying ScrollView knows that it won't get
-        // the chance to intercept events anymore
-        requestDisallowInterceptTouchEvent(true);
-    }
-
-    public void onDragCancelled(View v) {
-    }
-
-    @Override
-    public void onChildSnappedBack(View animView) {
-    }
-
-    @Override
-    public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
-        return false;
-    }
-
-    public View getChildAtPosition(MotionEvent ev) {
-        final float x = ev.getX() + getScrollX();
-        final float y = ev.getY() + getScrollY();
-        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-            View item = mLinearLayout.getChildAt(i);
-            if (item.getVisibility() == View.VISIBLE
-                    && x >= item.getLeft() && x < item.getRight()
-                    && y >= item.getTop() && y < item.getBottom()) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    public View getChildContentView(View v) {
-        return v.findViewById(R.id.recent_item);
-    }
-
-    @Override
-    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
-        if (mFadedEdgeDrawHelper != null) {
-            final boolean offsetRequired = isPaddingOffsetRequired();
-            mFadedEdgeDrawHelper.drawCallback(canvas,
-                    left, right, top + getFadeTop(offsetRequired), bottom, getScrollX(), getScrollY(),
-                    getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
-                    0, 0, getPaddingTop());
-        }
-    }
-
-    @Override
-    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
-       super.onScrollChanged(l, t, oldl, oldt);
-       if (mOnScrollListener != null) {
-           mOnScrollListener.run();
-       }
-    }
-
-    public void setOnScrollListener(Runnable listener) {
-        mOnScrollListener = listener;
-    }
-
-    @Override
-    public int getVerticalFadingEdgeLength() {
-        if (mFadedEdgeDrawHelper != null) {
-            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
-        } else {
-            return super.getVerticalFadingEdgeLength();
-        }
-    }
-
-    @Override
-    public int getHorizontalFadingEdgeLength() {
-        if (mFadedEdgeDrawHelper != null) {
-            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
-        } else {
-            return super.getHorizontalFadingEdgeLength();
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        setScrollbarFadingEnabled(true);
-        mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-        final int leftPadding = getContext().getResources()
-            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
-        setOverScrollEffectPadding(leftPadding, 0);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        if (mFadedEdgeDrawHelper != null) {
-            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        float densityScale = getResources().getDisplayMetrics().density;
-        mSwipeHelper.setDensityScale(densityScale);
-        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
-        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
-    }
-
-    private void setOverScrollEffectPadding(int leftPadding, int i) {
-        // TODO Add to (Vertical)ScrollView
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        // Skip this work if a transition is running; it sets the scroll values independently
-        // and should not have those animated values clobbered by this logic
-        LayoutTransition transition = mLinearLayout.getLayoutTransition();
-        if (transition != null && transition.isRunning()) {
-            return;
-        }
-        // Keep track of the last visible item in the list so we can restore it
-        // to the bottom when the orientation changes.
-        mLastScrollPosition = scrollPositionOfMostRecent();
-
-        // This has to happen post-layout, so run it "in the future"
-        post(new Runnable() {
-            public void run() {
-                // Make sure we're still not clobbering the transition-set values, since this
-                // runnable launches asynchronously
-                LayoutTransition transition = mLinearLayout.getLayoutTransition();
-                if (transition == null || !transition.isRunning()) {
-                    scrollTo(0, mLastScrollPosition);
-                }
-            }
-        });
-    }
-
-    public void setAdapter(TaskDescriptionAdapter adapter) {
-        mAdapter = adapter;
-        mAdapter.registerDataSetObserver(new DataSetObserver() {
-            public void onChanged() {
-                update();
-            }
-
-            public void onInvalidated() {
-                update();
-            }
-        });
-
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
-        int childheightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
-        View child = mAdapter.createView(mLinearLayout);
-        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-        mNumItemsInOneScreenful =
-                (int) FloatMath.ceil(dm.heightPixels / (float) child.getMeasuredHeight());
-        addToRecycledViews(child);
-
-        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
-            addToRecycledViews(mAdapter.createView(mLinearLayout));
-        }
-    }
-
-    public int numItemsInOneScreenful() {
-        return mNumItemsInOneScreenful;
-    }
-
-    @Override
-    public void setLayoutTransition(LayoutTransition transition) {
-        // The layout transition applies to our embedded LinearLayout
-        mLinearLayout.setLayoutTransition(transition);
-    }
-
-    public void setCallback(RecentsCallback callback) {
-        mCallback = callback;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recent/ScreenPinningRequest.java
deleted file mode 100644
index 2fa0b58..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/ScreenPinningRequest.java
+++ /dev/null
@@ -1,283 +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.recent;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-
-import java.util.ArrayList;
-
-public class ScreenPinningRequest implements View.OnClickListener {
-    private final Context mContext;
-
-    private final AccessibilityManager mAccessibilityService;
-    private final WindowManager mWindowManager;
-
-    private RequestWindowView mRequestWindow;
-
-    public ScreenPinningRequest(Context context) {
-        mContext = context;
-        mAccessibilityService = (AccessibilityManager)
-                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        mWindowManager = (WindowManager)
-                mContext.getSystemService(Context.WINDOW_SERVICE);
-    }
-
-    public void clearPrompt() {
-        if (mRequestWindow != null) {
-            mWindowManager.removeView(mRequestWindow);
-            mRequestWindow = null;
-        }
-    }
-
-    public void showPrompt(boolean allowCancel) {
-        clearPrompt();
-
-        mRequestWindow = new RequestWindowView(mContext, allowCancel);
-
-        mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-
-        // show the confirmation
-        WindowManager.LayoutParams lp = getWindowLayoutParams();
-        mWindowManager.addView(mRequestWindow, lp);
-    }
-
-    public void onConfigurationChanged() {
-        if (mRequestWindow != null) {
-            mRequestWindow.onConfigurationChanged();
-        }
-    }
-
-    private WindowManager.LayoutParams getWindowLayoutParams() {
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                0
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                ,
-                PixelFormat.TRANSLUCENT);
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        lp.setTitle("ScreenPinningConfirmation");
-        lp.gravity = Gravity.FILL;
-        return lp;
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
-            try {
-                ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();
-            } catch (RemoteException e) {}
-        }
-        clearPrompt();
-    }
-
-    public FrameLayout.LayoutParams getRequestLayoutParams(boolean isLandscape) {
-        return new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                isLandscape ? (Gravity.CENTER_VERTICAL | Gravity.RIGHT)
-                            : (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
-    }
-
-    private class RequestWindowView extends FrameLayout {
-        private static final int OFFSET_DP = 96;
-
-        private final ColorDrawable mColor = new ColorDrawable(0);
-        private ValueAnimator mColorAnim;
-        private ViewGroup mLayout;
-        private boolean mShowCancel;
-
-        public RequestWindowView(Context context, boolean showCancel) {
-            super(context);
-            setClickable(true);
-            setOnClickListener(ScreenPinningRequest.this);
-            setBackground(mColor);
-            mShowCancel = showCancel;
-        }
-
-        @Override
-        public void onAttachedToWindow() {
-            DisplayMetrics metrics = new DisplayMetrics();
-            mWindowManager.getDefaultDisplay().getMetrics(metrics);
-            float density = metrics.density;
-            boolean isLandscape = isLandscapePhone(mContext);
-
-            inflateView(isLandscape);
-            int bgColor = mContext.getResources().getColor(
-                    R.color.screen_pinning_request_window_bg);
-            if (ActivityManager.isHighEndGfx()) {
-                mLayout.setAlpha(0f);
-                if (isLandscape) {
-                    mLayout.setTranslationX(OFFSET_DP * density);
-                } else {
-                    mLayout.setTranslationY(OFFSET_DP * density);
-                }
-                mLayout.animate()
-                        .alpha(1f)
-                        .translationX(0)
-                        .translationY(0)
-                        .setDuration(300)
-                        .setInterpolator(new DecelerateInterpolator())
-                        .start();
-
-                mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, bgColor);
-                mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        final int c = (Integer) animation.getAnimatedValue();
-                        mColor.setColor(c);
-                    }
-                });
-                mColorAnim.setDuration(1000);
-                mColorAnim.start();
-            } else {
-                mColor.setColor(bgColor);
-            }
-
-            IntentFilter filter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
-            filter.addAction(Intent.ACTION_SCREEN_OFF);
-            mContext.registerReceiver(mReceiver, filter);
-        }
-
-        private boolean isLandscapePhone(Context context) {
-            Configuration config = mContext.getResources().getConfiguration();
-            return config.orientation == Configuration.ORIENTATION_LANDSCAPE
-                    && config.smallestScreenWidthDp < 600;
-        }
-
-        private void inflateView(boolean isLandscape) {
-            // We only want this landscape orientation on <600dp, so rather than handle
-            // resource overlay for -land and -sw600dp-land, just inflate this
-            // other view for this single case.
-            mLayout = (ViewGroup) View.inflate(getContext(), isLandscape
-                    ? R.layout.screen_pinning_request_land_phone : R.layout.screen_pinning_request,
-                    null);
-            // Catch touches so they don't trigger cancel/activate, like outside does.
-            mLayout.setClickable(true);
-            // Status bar is always on the right.
-            mLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
-            // Buttons and text do switch sides though.
-            View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
-            buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
-            mLayout.findViewById(R.id.screen_pinning_text_area)
-                    .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
-            swapChildrenIfRtlAndVertical(buttons);
-
-            ((Button) mLayout.findViewById(R.id.screen_pinning_ok_button))
-                    .setOnClickListener(ScreenPinningRequest.this);
-            if (mShowCancel) {
-                ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
-                        .setOnClickListener(ScreenPinningRequest.this);
-            } else {
-                ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
-                        .setVisibility(View.INVISIBLE);
-            }
-
-            final int description = mAccessibilityService.isEnabled()
-                    ? R.string.screen_pinning_description_accessible
-                    : R.string.screen_pinning_description;
-            ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
-                    .setText(description);
-            final int backBgVisibility =
-                    mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
-            mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
-            mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
-
-            addView(mLayout, getRequestLayoutParams(isLandscape));
-        }
-
-        private void swapChildrenIfRtlAndVertical(View group) {
-            if (mContext.getResources().getConfiguration().getLayoutDirection()
-                    != View.LAYOUT_DIRECTION_RTL) {
-                return;
-            }
-            LinearLayout linearLayout = (LinearLayout) group;
-            if (linearLayout.getOrientation() == LinearLayout.VERTICAL) {
-                int childCount = linearLayout.getChildCount();
-                ArrayList<View> childList = new ArrayList<>(childCount);
-                for (int i = 0; i < childCount; i++) {
-                    childList.add(linearLayout.getChildAt(i));
-                }
-                linearLayout.removeAllViews();
-                for (int i = childCount - 1; i >= 0; i--) {
-                    linearLayout.addView(childList.get(i));
-                }
-            }
-        }
-
-        @Override
-        public void onDetachedFromWindow() {
-            mContext.unregisterReceiver(mReceiver);
-        }
-
-        protected void onConfigurationChanged() {
-            removeAllViews();
-            inflateView(isLandscapePhone(mContext));
-        }
-
-        private final Runnable mUpdateLayoutRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if (mLayout != null && mLayout.getParent() != null) {
-                    mLayout.setLayoutParams(getRequestLayoutParams(isLandscapePhone(mContext)));
-                }
-            }
-        };
-
-        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                    post(mUpdateLayoutRunnable);
-                } else if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)
-                        || intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
-                    clearPrompt();
-                }
-            }
-        };
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
deleted file mode 100644
index 5ad965f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recent;
-
-import android.os.UserHandle;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-
-public final class TaskDescription {
-    final ResolveInfo resolveInfo;
-    final int taskId; // application task id for curating apps
-    final int persistentTaskId; // persistent id
-    final Intent intent; // launch intent for application
-    final String packageName; // used to override animations (see onClick())
-    final CharSequence description;
-    final int userId;
-
-    private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
-    private Drawable mIcon; // application package icon
-    private CharSequence mLabel; // application package label
-    private boolean mLoaded;
-
-    public TaskDescription(int _taskId, int _persistentTaskId,
-            ResolveInfo _resolveInfo, Intent _intent,
-            String _packageName, CharSequence _description, int _userId) {
-        resolveInfo = _resolveInfo;
-        intent = _intent;
-        taskId = _taskId;
-        persistentTaskId = _persistentTaskId;
-
-        description = _description;
-        packageName = _packageName;
-        userId = _userId;
-    }
-
-    public TaskDescription() {
-        resolveInfo = null;
-        intent = null;
-        taskId = -1;
-        persistentTaskId = -1;
-
-        description = null;
-        packageName = null;
-        userId = UserHandle.USER_NULL;
-    }
-
-    public void setLoaded(boolean loaded) {
-        mLoaded = loaded;
-    }
-
-    public boolean isLoaded() {
-        return mLoaded;
-    }
-
-    public boolean isNull() {
-        return resolveInfo == null;
-    }
-
-    // mark all these as locked?
-    public CharSequence getLabel() {
-        return mLabel;
-    }
-
-    public void setLabel(CharSequence label) {
-        mLabel = label;
-    }
-
-    public Drawable getIcon() {
-        return mIcon;
-    }
-
-    public void setIcon(Drawable icon) {
-        mIcon = icon;
-    }
-
-    public void setThumbnail(Drawable thumbnail) {
-        mThumbnail = thumbnail;
-    }
-
-    public Drawable getThumbnail() {
-        return mThumbnail;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
deleted file mode 100644
index 910a57e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ /dev/null
@@ -1,784 +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.recents;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ActivityNotFoundException;
-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.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskGrouping;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.TaskStackView;
-import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
-import com.android.systemui.recents.views.TaskViewHeader;
-import com.android.systemui.recents.views.TaskViewTransform;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Annotation for a method that is only called from the primary user's SystemUI process and will be
- * proxied to the current user.
- */
-@interface ProxyFromPrimaryToCurrentUser {}
-/**
- * Annotation for a method that may be called from any user's SystemUI process and will be proxied
- * to the primary user.
- */
-@interface ProxyFromAnyToPrimaryUser {}
-
-/** A proxy implementation for the recents component */
-public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
-
-    final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
-    final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
-    final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility";
-
-    // Owner proxy events
-    final public static String ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER =
-            "action_notify_recents_visibility_change";
-
-    final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
-    final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
-    final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
-
-    final static int sMinToggleDelay = 350;
-
-    final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
-    public final static String sRecentsPackage = "com.android.systemui";
-    public final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
-
-    /**
-     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
-     * task stacks and update recents accordingly.
-     */
-    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
-        Handler mHandler;
-
-        public TaskStackListenerImpl(Handler handler) {
-            mHandler = handler;
-        }
-
-        @Override
-        public void onTaskStackChanged() {
-            // Debounce any task stack changes
-            mHandler.removeCallbacks(this);
-            mHandler.post(this);
-        }
-
-        /** Preloads the next task */
-        public void run() {
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
-            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
-                RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                SystemServicesProxy ssp = loader.getSystemServicesProxy();
-                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
-
-                // Load the next task only if we aren't svelte
-                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-                loader.preloadTasks(plan, true /* isTopTaskHome */);
-                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-                // This callback is made when a new activity is launched and the old one is paused
-                // so ignore the current activity and try and preload the thumbnail for the
-                // previous one.
-                if (runningTaskInfo != null) {
-                    launchOpts.runningTaskId = runningTaskInfo.id;
-                }
-                launchOpts.numVisibleTasks = 2;
-                launchOpts.numVisibleTaskThumbnails = 2;
-                launchOpts.onlyLoadForCache = true;
-                launchOpts.onlyLoadPausedActivities = true;
-                loader.loadTasks(mContext, plan, launchOpts);
-            }
-        }
-    }
-
-    /**
-     * A proxy for Recents events which happens strictly for the owner.
-     */
-    class RecentsOwnerEventProxyReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            switch (intent.getAction()) {
-                case ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER:
-                    visibilityChanged(intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false));
-                    break;
-            }
-        }
-    }
-
-    static RecentsComponent.Callbacks sRecentsComponentCallbacks;
-    static RecentsTaskLoadPlan sInstanceLoadPlan;
-
-    Context mContext;
-    LayoutInflater mInflater;
-    SystemServicesProxy mSystemServicesProxy;
-    Handler mHandler;
-    TaskStackListenerImpl mTaskStackListener;
-    RecentsOwnerEventProxyReceiver mProxyBroadcastReceiver;
-    boolean mBootCompleted;
-    boolean mStartAnimationTriggered;
-    boolean mCanReuseTaskStackViews = true;
-
-    // Task launching
-    RecentsConfiguration mConfig;
-    Rect mWindowRect = new Rect();
-    Rect mTaskStackBounds = new Rect();
-    Rect mSystemInsets = new Rect();
-    TaskViewTransform mTmpTransform = new TaskViewTransform();
-    int mStatusBarHeight;
-    int mNavBarHeight;
-    int mNavBarWidth;
-
-    // Header (for transition)
-    TaskViewHeader mHeaderBar;
-    TaskStackView mDummyStackView;
-
-    // Variables to keep track of if we need to start recents after binding
-    boolean mTriggeredFromAltTab;
-    long mLastToggleTime;
-
-    public AlternateRecentsComponent(Context context) {
-        RecentsTaskLoader.initialize(context);
-        mInflater = LayoutInflater.from(context);
-        mContext = context;
-        mSystemServicesProxy = new SystemServicesProxy(context);
-        mHandler = new Handler();
-        mTaskStackBounds = new Rect();
-
-        // Register the task stack listener
-        mTaskStackListener = new TaskStackListenerImpl(mHandler);
-        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
-
-        // Only the owner has the callback to update the SysUI visibility flags, so all non-owner
-        // instances of AlternateRecentsComponent needs to notify the owner when the visibility
-        // changes.
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(AlternateRecentsComponent.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
-            mContext.registerReceiverAsUser(mProxyBroadcastReceiver, UserHandle.CURRENT, filter,
-                    null, mHandler);
-        }
-    }
-
-    /** Creates a new broadcast intent */
-    static Intent createLocalBroadcastIntent(Context context, String action) {
-        Intent intent = new Intent(action);
-        intent.setPackage(context.getPackageName());
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
-                Intent.FLAG_RECEIVER_FOREGROUND);
-        return intent;
-    }
-
-    /** Initializes the Recents. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onStart() {
-        // Initialize some static datastructures
-        TaskStackViewLayoutAlgorithm.initializeCurve();
-        // Load the header bar layout
-        reloadHeaderBarLayout(true);
-
-        // When we start, preload the data associated with the previous recent tasks.
-        // We can use a new plan since the caches will be the same.
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, true /* isTopTaskHome */);
-        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-        launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
-        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
-        launchOpts.onlyLoadForCache = true;
-        loader.loadTasks(mContext, plan, launchOpts);
-    }
-
-    public void onBootCompleted() {
-        mBootCompleted = true;
-    }
-
-    /** Shows the Recents. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onShowRecents(boolean triggeredFromAltTab) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            showRecents(triggeredFromAltTab);
-        } else {
-            Intent intent = createLocalBroadcastIntent(mContext,
-                    RecentsUserEventProxyReceiver.ACTION_PROXY_SHOW_RECENTS_TO_USER);
-            intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-        }
-    }
-    void showRecents(boolean triggeredFromAltTab) {
-        mTriggeredFromAltTab = triggeredFromAltTab;
-
-        try {
-            startRecentsActivity();
-        } catch (ActivityNotFoundException e) {
-            Console.logRawError("Failed to launch RecentAppsIntent", e);
-        }
-    }
-
-    /** Hides the Recents. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onHideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-        } else {
-            Intent intent = createLocalBroadcastIntent(mContext,
-                    RecentsUserEventProxyReceiver.ACTION_PROXY_HIDE_RECENTS_TO_USER);
-            intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
-            intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-        }
-    }
-    void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        if (mBootCompleted) {
-            ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
-            if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, null)) {
-                // Notify recents to hide itself
-                Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY);
-                intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
-                intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
-                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-            }
-        }
-    }
-
-    /** Toggles the Recents activity. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onToggleRecents() {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            toggleRecents();
-        } else {
-            Intent intent = createLocalBroadcastIntent(mContext,
-                    RecentsUserEventProxyReceiver.ACTION_PROXY_TOGGLE_RECENTS_TO_USER);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-        }
-    }
-    void toggleRecents() {
-        mTriggeredFromAltTab = false;
-
-        try {
-            toggleRecentsActivity();
-        } catch (ActivityNotFoundException e) {
-            Console.logRawError("Failed to launch RecentAppsIntent", e);
-        }
-    }
-
-    /** Preloads info for the Recents activity. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onPreloadRecents() {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            preloadRecents();
-        } else {
-            Intent intent = createLocalBroadcastIntent(mContext,
-                    RecentsUserEventProxyReceiver.ACTION_PROXY_PRELOAD_RECENTS_TO_USER);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-        }
-    }
-    void preloadRecents() {
-        // Preload only the raw task list into a new load plan (which will be consumed by the
-        // RecentsActivity)
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        sInstanceLoadPlan = loader.createLoadPlan(mContext);
-        sInstanceLoadPlan.preloadRawTasks(true);
-    }
-
-    public void onCancelPreloadingRecents() {
-        // Do nothing
-    }
-
-    void showRelativeAffiliatedTask(boolean showNextTask) {
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, true /* isTopTaskHome */);
-        TaskStack stack = plan.getTaskStack();
-
-        // Return early if there are no tasks
-        if (stack.getTaskCount() == 0) return;
-
-        ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
-        // Return early if there is no running task (can't determine affiliated tasks in this case)
-        if (runningTask == null) return;
-        // Return early if the running task is in the home stack (optimization)
-        if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
-
-        // Find the task in the recents list
-        ArrayList<Task> tasks = stack.getTasks();
-        Task toTask = null;
-        ActivityOptions launchOpts = null;
-        int taskCount = tasks.size();
-        int numAffiliatedTasks = 0;
-        for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (task.key.id == runningTask.id) {
-                TaskGrouping group = task.group;
-                Task.TaskKey toTaskKey;
-                if (showNextTask) {
-                    toTaskKey = group.getNextTaskInGroup(task);
-                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_next_affiliated_task_target,
-                            R.anim.recents_launch_next_affiliated_task_source);
-                } else {
-                    toTaskKey = group.getPrevTaskInGroup(task);
-                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
-                            R.anim.recents_launch_prev_affiliated_task_target,
-                            R.anim.recents_launch_prev_affiliated_task_source);
-                }
-                if (toTaskKey != null) {
-                    toTask = stack.findTaskWithId(toTaskKey.id);
-                }
-                numAffiliatedTasks = group.getTaskCount();
-                break;
-            }
-        }
-
-        // Return early if there is no next task
-        if (toTask == null) {
-            if (numAffiliatedTasks > 1) {
-                if (showNextTask) {
-                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
-                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
-                                    R.anim.recents_launch_next_affiliated_task_bounce));
-                } else {
-                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
-                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
-                                    R.anim.recents_launch_prev_affiliated_task_bounce));
-                }
-            }
-            return;
-        }
-
-        // Launch the task
-        if (toTask.isActive) {
-            // Bring an active task to the foreground
-            mSystemServicesProxy.moveTaskToFront(toTask.key.id, launchOpts);
-        } else {
-            mSystemServicesProxy.startActivityFromRecents(mContext, toTask.key.id,
-                    toTask.activityLabel, launchOpts);
-        }
-    }
-
-    public void onShowNextAffiliatedTask() {
-        showRelativeAffiliatedTask(true);
-    }
-
-    public void onShowPrevAffiliatedTask() {
-        showRelativeAffiliatedTask(false);
-    }
-
-    /** Updates on configuration change. */
-    @ProxyFromPrimaryToCurrentUser
-    public void onConfigurationChanged(Configuration newConfig) {
-        if (mSystemServicesProxy.isForegroundUserOwner()) {
-            configurationChanged();
-        } else {
-            Intent intent = createLocalBroadcastIntent(mContext,
-                    RecentsUserEventProxyReceiver.ACTION_PROXY_CONFIG_CHANGE_TO_USER);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-        }
-    }
-    void configurationChanged() {
-        // Don't reuse task stack views if the configuration changes
-        mCanReuseTaskStackViews = false;
-        // Reload the header bar layout
-        reloadHeaderBarLayout(false);
-    }
-
-    /** Prepares the header bar layout. */
-    void reloadHeaderBarLayout(boolean reloadWidget) {
-        Resources res = mContext.getResources();
-        mWindowRect = mSystemServicesProxy.getWindowRect();
-        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
-        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-        mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
-        mConfig.updateOnConfigurationChange();
-        if (reloadWidget) {
-            // Reload the widget id before we get the task stack bounds
-            reloadSearchBarAppWidget(mContext, mSystemServicesProxy);
-        }
-        mConfig.getTaskStackBounds(mWindowRect.width(), mWindowRect.height(), mStatusBarHeight,
-                (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), mTaskStackBounds);
-        if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
-            mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
-        } else {
-            mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
-        }
-
-        // Inflate the header bar layout so that we can rebind and draw it for the transition
-        TaskStack stack = new TaskStack();
-        mDummyStackView = new TaskStackView(mContext, stack);
-        TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
-        Rect taskStackBounds = new Rect(mTaskStackBounds);
-        taskStackBounds.bottom -= mSystemInsets.bottom;
-        algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
-        Rect taskViewSize = algo.getUntransformedTaskViewSize();
-        int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
-                false);
-        mHeaderBar.measure(
-                View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
-        mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
-    }
-
-    /** Prepares the search bar app widget */
-    void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) {
-        // Try and pre-emptively bind the search widget on startup to ensure that we
-        // have the right thumbnail bounds to animate to.
-        if (Constants.DebugFlags.App.EnableSearchLayout) {
-            // If there is no id, then bind a new search app widget
-            if (mConfig.searchBarAppWidgetId < 0) {
-                AppWidgetHost host = new RecentsAppWidgetHost(context,
-                        Constants.Values.App.AppWidgetHostId);
-                Pair<Integer, AppWidgetProviderInfo> widgetInfo = ssp.bindSearchAppWidget(host);
-                if (widgetInfo != null) {
-                    // Save the app widget id into the settings
-                    mConfig.updateSearchBarAppWidgetId(context, widgetInfo.first);
-                }
-            }
-        }
-    }
-
-    /** Toggles the recents activity */
-    void toggleRecentsActivity() {
-        // If the user has toggled it too quickly, then just eat up the event here (it's better than
-        // showing a janky screenshot).
-        // NOTE: Ideally, the screenshot mechanism would take the window transform into account
-        if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
-            return;
-        }
-
-        // If Recents is the front most activity, then we should just communicate with it directly
-        // to launch the first task or dismiss itself
-        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
-        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
-        if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
-            // Notify recents to toggle itself
-            Intent intent = createLocalBroadcastIntent(mContext, ACTION_TOGGLE_RECENTS_ACTIVITY);
-            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-            mLastToggleTime = SystemClock.elapsedRealtime();
-            return;
-        } else {
-            // Otherwise, start the recents activity
-            startRecentsActivity(topTask, isTopTaskHome.get());
-        }
-    }
-
-    /** Starts the recents activity if it is not already running */
-    void startRecentsActivity() {
-        // Check if the top task is in the home stack, and start the recents activity
-        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
-        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
-        if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
-            startRecentsActivity(topTask, isTopTaskHome.get());
-        }
-    }
-
-    /**
-     * Creates the activity options for a unknown state->recents transition.
-     */
-    ActivityOptions getUnknownTransitionActivityOptions() {
-        mStartAnimationTriggered = false;
-        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(boolean fromSearchHome) {
-        mStartAnimationTriggered = false;
-        if (fromSearchHome) {
-            return ActivityOptions.makeCustomAnimation(mContext,
-                    R.anim.recents_from_search_launcher_enter,
-                    R.anim.recents_from_search_launcher_exit,
-                    mHandler, this);
-        }
-        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.
-     */
-    ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
-            TaskStack stack, TaskStackView stackView) {
-        // Update the destination rect
-        Task toTask = new Task();
-        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                topTask.id, toTask);
-        if (toTransform != null && toTask.key != null) {
-            Rect toTaskRect = toTransform.rect;
-            int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
-            int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
-            Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
-                    Bitmap.Config.ARGB_8888);
-            if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
-                thumbnail.eraseColor(0xFFff0000);
-            } else {
-                Canvas c = new Canvas(thumbnail);
-                c.scale(toTransform.scale, toTransform.scale);
-                mHeaderBar.rebindToTask(toTask);
-                mHeaderBar.draw(c);
-                c.setBitmap(null);
-            }
-
-            mStartAnimationTriggered = false;
-            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
-                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
-                    toTaskRect.height(), mHandler, this);
-        }
-
-        // If both the screenshot and thumbnail fails, then just fall back to the default transition
-        return getUnknownTransitionActivityOptions();
-    }
-
-    /** Returns the transition rect for the given task id. */
-    TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, TaskStackView stackView,
-            int runningTaskId, Task runningTaskOut) {
-        // Find the running task in the TaskStack
-        Task task = null;
-        ArrayList<Task> tasks = stack.getTasks();
-        if (runningTaskId != -1) {
-            // Otherwise, try and find the task with the
-            int taskCount = tasks.size();
-            for (int i = taskCount - 1; i >= 0; i--) {
-                Task t = tasks.get(i);
-                if (t.key.id == runningTaskId) {
-                    task = t;
-                    runningTaskOut.copyFrom(t);
-                    break;
-                }
-            }
-        }
-        if (task == null) {
-            // If no task is specified or we can not find the task just use the front most one
-            task = tasks.get(tasks.size() - 1);
-        }
-
-        // Get the transform for the running task
-        stackView.getScroller().setStackScrollToInitialState();
-        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
-                stackView.getScroller().getStackScroll(), mTmpTransform, null);
-        return mTmpTransform;
-    }
-
-    /** Starts the recents activity */
-    void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
-
-        if (sInstanceLoadPlan == null) {
-            // Create a new load plan if onPreloadRecents() was never triggered
-            sInstanceLoadPlan = loader.createLoadPlan(mContext);
-        }
-        loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
-        TaskStack stack = sInstanceLoadPlan.getTaskStack();
-
-        // Prepare the dummy stack for the transition
-        mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
-        TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
-                mDummyStackView.computeStackVisibilityReport();
-        boolean hasRecentTasks = stack.getTaskCount() > 0;
-        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
-
-        if (useThumbnailTransition) {
-            // Ensure that we load the running task's icon
-            RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-            launchOpts.runningTaskId = topTask.id;
-            launchOpts.loadThumbnails = false;
-            launchOpts.onlyLoadForCache = true;
-            loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts);
-
-            // Try starting with a thumbnail transition
-            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
-                    mDummyStackView);
-            if (opts != null) {
-                startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
-                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
-            } else {
-                // Fall through below to the non-thumbnail transition
-                useThumbnailTransition = false;
-            }
-        }
-
-        if (!useThumbnailTransition) {
-            // 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) {
-                // Get the home activity info
-                String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
-                // Get the search widget info
-                AppWidgetProviderInfo searchWidget = null;
-                String searchWidgetPackage = null;
-                if (mConfig.hasSearchBarAppWidget()) {
-                    searchWidget = mSystemServicesProxy.getAppWidgetInfo(
-                            mConfig.searchBarAppWidgetId);
-                } else {
-                    searchWidget = mSystemServicesProxy.resolveSearchAppWidget();
-                }
-                if (searchWidget != null && searchWidget.provider != null) {
-                    searchWidgetPackage = searchWidget.provider.getPackageName();
-                }
-                // Determine whether we are coming from a search owned home activity
-                boolean fromSearchHome = false;
-                if (homeActivityPackage != null && searchWidgetPackage != null &&
-                        homeActivityPackage.equals(searchWidgetPackage)) {
-                    fromSearchHome = true;
-                }
-
-                ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
-                startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
-                        false /* fromThumbnail */, stackVr);
-            } else {
-                // Otherwise we do the normal fade from an unknown source
-                ActivityOptions opts = getUnknownTransitionActivityOptions();
-                startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
-                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
-            }
-        }
-        mLastToggleTime = SystemClock.elapsedRealtime();
-    }
-
-    /** Starts the recents activity */
-    void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-            ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
-            TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
-        // Update the configuration based on the launch options
-        mConfig.launchedFromHome = fromSearchHome || fromHome;
-        mConfig.launchedFromSearchHome = fromSearchHome;
-        mConfig.launchedFromAppWithThumbnail = fromThumbnail;
-        mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
-        mConfig.launchedWithAltTab = mTriggeredFromAltTab;
-        mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
-        mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
-        mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
-        mConfig.launchedHasConfigurationChanged = false;
-
-        Intent intent = new Intent(sToggleRecentsAction);
-        intent.setClassName(sRecentsPackage, sRecentsActivity);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-        if (opts != null) {
-            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
-        } else {
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
-        }
-        mCanReuseTaskStackViews = true;
-    }
-
-    /** Sets the RecentsComponent callbacks. */
-    public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) {
-        sRecentsComponentCallbacks = cb;
-    }
-
-    /** Notifies the callbacks that the visibility of Recents has changed. */
-    @ProxyFromAnyToPrimaryUser
-    public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,
-            boolean visible) {
-        if (ssp.isForegroundUserOwner()) {
-            visibilityChanged(visible);
-        } else {
-            Intent intent = createLocalBroadcastIntent(context,
-                    ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
-            intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible);
-            context.sendBroadcastAsUser(intent, UserHandle.OWNER);
-        }
-    }
-    static void visibilityChanged(boolean visible) {
-        if (sRecentsComponentCallbacks != null) {
-            sRecentsComponentCallbacks.onVisibilityChanged(visible);
-        }
-    }
-
-    /**
-     * Returns the preloaded load plan and invalidates it.
-     */
-    public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
-        RecentsTaskLoadPlan plan = sInstanceLoadPlan;
-        sInstanceLoadPlan = null;
-        return plan;
-    }
-
-    /**** OnAnimationStartedListener Implementation ****/
-
-    @Override
-    public void onAnimationStarted() {
-        // Notify recents to start the enter animation
-        if (!mStartAnimationTriggered) {
-            // There can be a race condition between the start animation callback and
-            // the start of the new activity (where we register the receiver that listens
-            // to this broadcast, so we add our own receiver and if that gets called, then
-            // we know the activity has not yet started and we can retry sending the broadcast.
-            BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (getResultCode() == Activity.RESULT_OK) {
-                        mStartAnimationTriggered = true;
-                        return;
-                    }
-
-                    // Schedule for the broadcast to be sent again after some time
-                    mHandler.postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            onAnimationStarted();
-                        }
-                    }, 25);
-                }
-            };
-
-            // Send the broadcast to notify Recents that the animation has started
-            Intent intent = createLocalBroadcastIntent(mContext, ACTION_START_ENTER_ANIMATION);
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
-                    fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 0a1718d..192acc6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,18 +29,18 @@
             public static final boolean EnableTransitionThumbnailDebugMode = false;
             // Enables the filtering of tasks according to their grouping
             public static final boolean EnableTaskFiltering = false;
-            // Enables clipping of tasks against each other
-            public static final boolean EnableTaskStackClipping = true;
-            // Enables tapping on the TaskBar to launch the task
-            public static final boolean EnableTaskBarTouchEvents = true;
             // Enables app-info pane on long-pressing the icon
             public static final boolean EnableDevAppInfoOnLongPress = true;
+            // Enables dismiss-all
+            public static final boolean EnableDismissAll = false;
             // Enables debug mode
             public static final boolean EnableDebugMode = false;
             // Enables the search bar layout
             public static final boolean EnableSearchLayout = true;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
+            // Enables all system stacks to show up in the same recents stack
+            public static final boolean EnableMultiStackToSingleStack = true;
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // Enables the simulated task affiliations
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
new file mode 100644
index 0000000..9dd82fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ITaskStackListener;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Pair;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.RecentsComponent;
+import com.android.systemui.SystemUI;
+import com.android.systemui.recents.misc.Console;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskGrouping;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
+import com.android.systemui.recents.views.TaskViewHeader;
+import com.android.systemui.recents.views.TaskViewTransform;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Annotation for a method that is only called from the primary user's SystemUI process and will be
+ * proxied to the current user.
+ */
+@interface ProxyFromPrimaryToCurrentUser {}
+/**
+ * Annotation for a method that may be called from any user's SystemUI process and will be proxied
+ * to the primary user.
+ */
+@interface ProxyFromAnyToPrimaryUser {}
+
+/** A proxy implementation for the recents component */
+public class Recents extends SystemUI
+        implements ActivityOptions.OnAnimationStartedListener, RecentsComponent {
+
+    final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
+    final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
+    final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility";
+
+    // Owner proxy events
+    final public static String ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER =
+            "action_notify_recents_visibility_change";
+
+    final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
+    final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
+    final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity";
+
+    final static int sMinToggleDelay = 350;
+
+    public final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
+    public final static String sRecentsPackage = "com.android.systemui";
+    public final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
+
+    /**
+     * An implementation of ITaskStackListener, that allows us to listen for changes to the system
+     * task stacks and update recents accordingly.
+     */
+    class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
+        Handler mHandler;
+
+        public TaskStackListenerImpl(Handler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void onTaskStackChanged() {
+            // Debounce any task stack changes
+            mHandler.removeCallbacks(this);
+            mHandler.post(this);
+        }
+
+        /** Preloads the next task */
+        public void run() {
+            // Temporarily skip this if multi stack is enabled
+            if (mConfig.multiStackEnabled) return;
+
+            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+                RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+                SystemServicesProxy ssp = loader.getSystemServicesProxy();
+                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
+
+                // Load the next task only if we aren't svelte
+                RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+                loader.preloadTasks(plan, true /* isTopTaskHome */);
+                RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+                // This callback is made when a new activity is launched and the old one is paused
+                // so ignore the current activity and try and preload the thumbnail for the
+                // previous one.
+                if (runningTaskInfo != null) {
+                    launchOpts.runningTaskId = runningTaskInfo.id;
+                }
+                launchOpts.numVisibleTasks = 2;
+                launchOpts.numVisibleTaskThumbnails = 2;
+                launchOpts.onlyLoadForCache = true;
+                launchOpts.onlyLoadPausedActivities = true;
+                loader.loadTasks(mContext, plan, launchOpts);
+            }
+        }
+    }
+
+    /**
+     * A proxy for Recents events which happens strictly for the owner.
+     */
+    class RecentsOwnerEventProxyReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER:
+                    visibilityChanged(intent.getBooleanExtra(EXTRA_RECENTS_VISIBILITY, false));
+                    break;
+            }
+        }
+    }
+
+    static RecentsComponent.Callbacks sRecentsComponentCallbacks;
+    static RecentsTaskLoadPlan sInstanceLoadPlan;
+    static Recents sInstance;
+
+    LayoutInflater mInflater;
+    SystemServicesProxy mSystemServicesProxy;
+    Handler mHandler;
+    TaskStackListenerImpl mTaskStackListener;
+    RecentsOwnerEventProxyReceiver mProxyBroadcastReceiver;
+    boolean mBootCompleted;
+    boolean mStartAnimationTriggered;
+    boolean mCanReuseTaskStackViews = true;
+
+    // Task launching
+    RecentsConfiguration mConfig;
+    Rect mWindowRect = new Rect();
+    Rect mTaskStackBounds = new Rect();
+    Rect mSystemInsets = new Rect();
+    TaskViewTransform mTmpTransform = new TaskViewTransform();
+    int mStatusBarHeight;
+    int mNavBarHeight;
+    int mNavBarWidth;
+
+    // Header (for transition)
+    TaskViewHeader mHeaderBar;
+    TaskStackView mDummyStackView;
+
+    // Variables to keep track of if we need to start recents after binding
+    boolean mTriggeredFromAltTab;
+    long mLastToggleTime;
+
+    public Recents() {
+    }
+
+    /**
+     * Gets the singleton instance and starts it if needed. On the primary user on the device, this
+     * component gets started as a normal {@link SystemUI} component. On a secondary user, this
+     * lifecycle doesn't exist, so we need to start it manually here if needed.
+     */
+    public static Recents getInstanceAndStartIfNeeded(Context ctx) {
+        if (sInstance == null) {
+            sInstance = new Recents();
+            sInstance.mContext = ctx;
+            sInstance.start();
+            sInstance.onBootCompleted();
+        }
+        return sInstance;
+    }
+
+    /** Creates a new broadcast intent */
+    static Intent createLocalBroadcastIntent(Context context, String action) {
+        Intent intent = new Intent(action);
+        intent.setPackage(context.getPackageName());
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                Intent.FLAG_RECEIVER_FOREGROUND);
+        return intent;
+    }
+
+    /** Initializes the Recents. */
+    @ProxyFromPrimaryToCurrentUser
+    @Override
+    public void start() {
+        if (sInstance == null) {
+            sInstance = this;
+        }
+        RecentsTaskLoader.initialize(mContext);
+        mInflater = LayoutInflater.from(mContext);
+        mSystemServicesProxy = new SystemServicesProxy(mContext);
+        mHandler = new Handler();
+        mTaskStackBounds = new Rect();
+
+        // Register the task stack listener
+        mTaskStackListener = new TaskStackListenerImpl(mHandler);
+        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+
+        // Only the owner has the callback to update the SysUI visibility flags, so all non-owner
+        // instances of AlternateRecentsComponent needs to notify the owner when the visibility
+        // changes.
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Recents.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
+            mContext.registerReceiverAsUser(mProxyBroadcastReceiver, UserHandle.CURRENT, filter,
+                    null, mHandler);
+        }
+
+        // Initialize some static datastructures
+        TaskStackViewLayoutAlgorithm.initializeCurve();
+        // Load the header bar layout
+        reloadHeaderBarLayout(true);
+
+        // When we start, preload the data associated with the previous recent tasks.
+        // We can use a new plan since the caches will be the same.
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+        loader.preloadTasks(plan, true /* isTopTaskHome */);
+        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+        launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
+        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
+        launchOpts.onlyLoadForCache = true;
+        loader.loadTasks(mContext, plan, launchOpts);
+        putComponent(Recents.class, this);
+    }
+
+    @Override
+    public void onBootCompleted() {
+        mBootCompleted = true;
+    }
+
+    /** Shows the Recents. */
+    @ProxyFromPrimaryToCurrentUser
+    @Override
+    public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            showRecentsInternal(triggeredFromAltTab);
+        } else {
+            Intent intent = createLocalBroadcastIntent(mContext,
+                    RecentsUserEventProxyReceiver.ACTION_PROXY_SHOW_RECENTS_TO_USER);
+            intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+        }
+    }
+
+    void showRecentsInternal(boolean triggeredFromAltTab) {
+        mTriggeredFromAltTab = triggeredFromAltTab;
+
+        try {
+            startRecentsActivity();
+        } catch (ActivityNotFoundException e) {
+            Console.logRawError("Failed to launch RecentAppsIntent", e);
+        }
+    }
+
+    /** Hides the Recents. */
+    @ProxyFromPrimaryToCurrentUser
+    @Override
+    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            hideRecentsInternal(triggeredFromAltTab, triggeredFromHomeKey);
+        } else {
+            Intent intent = createLocalBroadcastIntent(mContext,
+                    RecentsUserEventProxyReceiver.ACTION_PROXY_HIDE_RECENTS_TO_USER);
+            intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
+            intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+        }
+    }
+
+    void hideRecentsInternal(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        if (mBootCompleted) {
+            ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+            if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, null)) {
+                // Notify recents to hide itself
+                Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY);
+                intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
+                intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
+                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+            }
+        }
+    }
+
+    /** Toggles the Recents activity. */
+    @ProxyFromPrimaryToCurrentUser
+    @Override
+    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            toggleRecentsInternal();
+        } else {
+            Intent intent = createLocalBroadcastIntent(mContext,
+                    RecentsUserEventProxyReceiver.ACTION_PROXY_TOGGLE_RECENTS_TO_USER);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+        }
+    }
+
+    void toggleRecentsInternal() {
+        mTriggeredFromAltTab = false;
+
+        try {
+            toggleRecentsActivity();
+        } catch (ActivityNotFoundException e) {
+            Console.logRawError("Failed to launch RecentAppsIntent", e);
+        }
+    }
+
+    /** Preloads info for the Recents activity. */
+    @ProxyFromPrimaryToCurrentUser
+    @Override
+    public void preloadRecents() {
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            preloadRecentsInternal();
+        } else {
+            Intent intent = createLocalBroadcastIntent(mContext,
+                    RecentsUserEventProxyReceiver.ACTION_PROXY_PRELOAD_RECENTS_TO_USER);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+        }
+    }
+
+    void preloadRecentsInternal() {
+        // Preload only the raw task list into a new load plan (which will be consumed by the
+        // RecentsActivity)
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        sInstanceLoadPlan = loader.createLoadPlan(mContext);
+        sInstanceLoadPlan.preloadRawTasks(true);
+    }
+
+    @Override
+    public void cancelPreloadingRecents() {
+        // Do nothing
+    }
+
+    void showRelativeAffiliatedTask(boolean showNextTask) {
+        // Return early if there is no focused stack
+        int focusedStackId = mSystemServicesProxy.getFocusedStack();
+        TaskStack focusedStack = null;
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+        loader.preloadTasks(plan, true /* isTopTaskHome */);
+        if (mConfig.multiStackEnabled) {
+            if (focusedStackId < 0) return;
+            focusedStack = plan.getTaskStack(focusedStackId);
+        } else {
+            focusedStack = plan.getAllTaskStacks().get(0);
+        }
+
+        // Return early if there are no tasks in the focused stack
+        if (focusedStack.getTaskCount() == 0) return;
+
+        ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
+        // Return early if there is no running task (can't determine affiliated tasks in this case)
+        if (runningTask == null) return;
+        // Return early if the running task is in the home stack (optimization)
+        if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
+
+        // Find the task in the recents list
+        ArrayList<Task> tasks = focusedStack.getTasks();
+        Task toTask = null;
+        ActivityOptions launchOpts = null;
+        int taskCount = tasks.size();
+        int numAffiliatedTasks = 0;
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.key.id == runningTask.id) {
+                TaskGrouping group = task.group;
+                Task.TaskKey toTaskKey;
+                if (showNextTask) {
+                    toTaskKey = group.getNextTaskInGroup(task);
+                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_next_affiliated_task_target,
+                            R.anim.recents_launch_next_affiliated_task_source);
+                } else {
+                    toTaskKey = group.getPrevTaskInGroup(task);
+                    launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_prev_affiliated_task_target,
+                            R.anim.recents_launch_prev_affiliated_task_source);
+                }
+                if (toTaskKey != null) {
+                    toTask = focusedStack.findTaskWithId(toTaskKey.id);
+                }
+                numAffiliatedTasks = group.getTaskCount();
+                break;
+            }
+        }
+
+        // Return early if there is no next task
+        if (toTask == null) {
+            if (numAffiliatedTasks > 1) {
+                if (showNextTask) {
+                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
+                                    R.anim.recents_launch_next_affiliated_task_bounce));
+                } else {
+                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+                            ActivityOptions.makeCustomInPlaceAnimation(mContext,
+                                    R.anim.recents_launch_prev_affiliated_task_bounce));
+                }
+            }
+            return;
+        }
+
+        // Launch the task
+        if (toTask.isActive) {
+            // Bring an active task to the foreground
+            mSystemServicesProxy.moveTaskToFront(toTask.key.id, launchOpts);
+        } else {
+            mSystemServicesProxy.startActivityFromRecents(mContext, toTask.key.id,
+                    toTask.activityLabel, launchOpts);
+        }
+    }
+
+    @Override
+    public void showNextAffiliatedTask() {
+        showRelativeAffiliatedTask(true);
+    }
+
+    @Override
+    public void showPrevAffiliatedTask() {
+        showRelativeAffiliatedTask(false);
+    }
+
+    /** Updates on configuration change. */
+    @ProxyFromPrimaryToCurrentUser
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (mSystemServicesProxy.isForegroundUserOwner()) {
+            configurationChanged();
+        } else {
+            Intent intent = createLocalBroadcastIntent(mContext,
+                    RecentsUserEventProxyReceiver.ACTION_PROXY_CONFIG_CHANGE_TO_USER);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+        }
+    }
+    void configurationChanged() {
+        // Don't reuse task stack views if the configuration changes
+        mCanReuseTaskStackViews = false;
+        // Reload the header bar layout
+        reloadHeaderBarLayout(false);
+    }
+
+    /** Prepares the header bar layout. */
+    void reloadHeaderBarLayout(boolean reloadWidget) {
+        Resources res = mContext.getResources();
+        mWindowRect = mSystemServicesProxy.getWindowRect();
+        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
+        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
+        mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+        mConfig.updateOnConfigurationChange();
+        if (reloadWidget) {
+            // Reload the widget id before we get the task stack bounds
+            reloadSearchBarAppWidget(mContext, mSystemServicesProxy);
+        }
+        mConfig.getAvailableTaskStackBounds(mWindowRect.width(), mWindowRect.height(),
+                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+                mTaskStackBounds);
+        if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
+            mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
+        } else {
+            mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
+        }
+
+        // Inflate the header bar layout so that we can rebind and draw it for the transition
+        TaskStack stack = new TaskStack();
+        mDummyStackView = new TaskStackView(mContext, stack);
+        TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
+        Rect taskStackBounds = new Rect(mTaskStackBounds);
+        taskStackBounds.bottom -= mSystemInsets.bottom;
+        algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
+        Rect taskViewSize = algo.getUntransformedTaskViewSize();
+        int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
+        mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
+                false);
+        mHeaderBar.measure(
+                View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
+        mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
+    }
+
+    /** Prepares the search bar app widget */
+    void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) {
+        // Try and pre-emptively bind the search widget on startup to ensure that we
+        // have the right thumbnail bounds to animate to.
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
+            // If there is no id, then bind a new search app widget
+            if (mConfig.searchBarAppWidgetId < 0) {
+                AppWidgetHost host = new RecentsAppWidgetHost(context,
+                        Constants.Values.App.AppWidgetHostId);
+                Pair<Integer, AppWidgetProviderInfo> widgetInfo = ssp.bindSearchAppWidget(host);
+                if (widgetInfo != null) {
+                    // Save the app widget id into the settings
+                    mConfig.updateSearchBarAppWidgetId(context, widgetInfo.first);
+                }
+            }
+        }
+    }
+
+    /** Toggles the recents activity */
+    void toggleRecentsActivity() {
+        // If the user has toggled it too quickly, then just eat up the event here (it's better than
+        // showing a janky screenshot).
+        // NOTE: Ideally, the screenshot mechanism would take the window transform into account
+        if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+            return;
+        }
+
+        // If Recents is the front most activity, then we should just communicate with it directly
+        // to launch the first task or dismiss itself
+        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
+        if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
+            // Notify recents to toggle itself
+            Intent intent = createLocalBroadcastIntent(mContext, ACTION_TOGGLE_RECENTS_ACTIVITY);
+            mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+            mLastToggleTime = SystemClock.elapsedRealtime();
+            return;
+        } else {
+            // Otherwise, start the recents activity
+            startRecentsActivity(topTask, isTopTaskHome.get());
+        }
+    }
+
+    /** Starts the recents activity if it is not already running */
+    void startRecentsActivity() {
+        // Check if the top task is in the home stack, and start the recents activity
+        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
+        if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
+            startRecentsActivity(topTask, isTopTaskHome.get());
+        }
+    }
+
+    /**
+     * Creates the activity options for a unknown state->recents transition.
+     */
+    ActivityOptions getUnknownTransitionActivityOptions() {
+        mStartAnimationTriggered = false;
+        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(boolean fromSearchHome) {
+        mStartAnimationTriggered = false;
+        if (fromSearchHome) {
+            return ActivityOptions.makeCustomAnimation(mContext,
+                    R.anim.recents_from_search_launcher_enter,
+                    R.anim.recents_from_search_launcher_exit,
+                    mHandler, this);
+        }
+        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.
+     */
+    ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
+            TaskStack stack, TaskStackView stackView) {
+        // Update the destination rect
+        Task toTask = new Task();
+        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+                topTask.id, toTask);
+        if (toTransform != null && toTask.key != null) {
+            Rect toTaskRect = toTransform.rect;
+            int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
+            int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+            Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
+                    Bitmap.Config.ARGB_8888);
+            if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
+                thumbnail.eraseColor(0xFFff0000);
+            } else {
+                Canvas c = new Canvas(thumbnail);
+                c.scale(toTransform.scale, toTransform.scale);
+                mHeaderBar.rebindToTask(toTask);
+                mHeaderBar.draw(c);
+                c.setBitmap(null);
+            }
+
+            mStartAnimationTriggered = false;
+            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
+                    toTaskRect.height(), mHandler, this);
+        }
+
+        // If both the screenshot and thumbnail fails, then just fall back to the default transition
+        return getUnknownTransitionActivityOptions();
+    }
+
+    /** Returns the transition rect for the given task id. */
+    TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, TaskStackView stackView,
+            int runningTaskId, Task runningTaskOut) {
+        // Find the running task in the TaskStack
+        Task task = null;
+        ArrayList<Task> tasks = stack.getTasks();
+        if (runningTaskId != -1) {
+            // Otherwise, try and find the task with the
+            int taskCount = tasks.size();
+            for (int i = taskCount - 1; i >= 0; i--) {
+                Task t = tasks.get(i);
+                if (t.key.id == runningTaskId) {
+                    task = t;
+                    runningTaskOut.copyFrom(t);
+                    break;
+                }
+            }
+        }
+        if (task == null) {
+            // If no task is specified or we can not find the task just use the front most one
+            task = tasks.get(tasks.size() - 1);
+        }
+
+        // Get the transform for the running task
+        stackView.getScroller().setStackScrollToInitialState();
+        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
+                stackView.getScroller().getStackScroll(), mTmpTransform, null);
+        return mTmpTransform;
+    }
+
+    /** Starts the recents activity */
+    void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+
+        if (sInstanceLoadPlan == null) {
+            // Create a new load plan if onPreloadRecents() was never triggered
+            sInstanceLoadPlan = loader.createLoadPlan(mContext);
+        }
+
+        // Temporarily skip the transition (use a dummy fade) if multi stack is enabled.
+        // For multi-stack we need to figure out where each of the tasks are going.
+        if (mConfig.multiStackEnabled) {
+            loader.preloadTasks(sInstanceLoadPlan, true);
+            ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
+            TaskStack stack = stacks.get(0);
+            mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
+            TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
+                    mDummyStackView.computeStackVisibilityReport();
+            ActivityOptions opts = getUnknownTransitionActivityOptions();
+            startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+                    false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
+            return;
+        }
+
+        loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
+        ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
+        TaskStack stack = stacks.get(0);
+
+        // Prepare the dummy stack for the transition
+        mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
+        TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
+                mDummyStackView.computeStackVisibilityReport();
+        boolean hasRecentTasks = stack.getTaskCount() > 0;
+        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+
+        if (useThumbnailTransition) {
+            // Ensure that we load the running task's icon
+            RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+            launchOpts.runningTaskId = topTask.id;
+            launchOpts.loadThumbnails = false;
+            launchOpts.onlyLoadForCache = true;
+            loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+
+            // Try starting with a thumbnail transition
+            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
+                    mDummyStackView);
+            if (opts != null) {
+                startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
+                        false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
+            } else {
+                // Fall through below to the non-thumbnail transition
+                useThumbnailTransition = false;
+            }
+        }
+
+        if (!useThumbnailTransition) {
+            // 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) {
+                // Get the home activity info
+                String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
+                // Get the search widget info
+                AppWidgetProviderInfo searchWidget = null;
+                String searchWidgetPackage = null;
+                if (mConfig.hasSearchBarAppWidget()) {
+                    searchWidget = mSystemServicesProxy.getAppWidgetInfo(
+                            mConfig.searchBarAppWidgetId);
+                } else {
+                    searchWidget = mSystemServicesProxy.resolveSearchAppWidget();
+                }
+                if (searchWidget != null && searchWidget.provider != null) {
+                    searchWidgetPackage = searchWidget.provider.getPackageName();
+                }
+                // Determine whether we are coming from a search owned home activity
+                boolean fromSearchHome = false;
+                if (homeActivityPackage != null && searchWidgetPackage != null &&
+                        homeActivityPackage.equals(searchWidgetPackage)) {
+                    fromSearchHome = true;
+                }
+
+                ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
+                startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+                        false /* fromThumbnail */, stackVr);
+            } else {
+                // Otherwise we do the normal fade from an unknown source
+                ActivityOptions opts = getUnknownTransitionActivityOptions();
+                startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+                        false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
+            }
+        }
+        mLastToggleTime = SystemClock.elapsedRealtime();
+    }
+
+    /** Starts the recents activity */
+    void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+            ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
+            TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+        // Update the configuration based on the launch options
+        mConfig.launchedFromHome = fromSearchHome || fromHome;
+        mConfig.launchedFromSearchHome = fromSearchHome;
+        mConfig.launchedFromAppWithThumbnail = fromThumbnail;
+        mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        mConfig.launchedWithAltTab = mTriggeredFromAltTab;
+        mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+        mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
+        mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+        mConfig.launchedHasConfigurationChanged = false;
+
+        Intent intent = new Intent(sToggleRecentsAction);
+        intent.setClassName(sRecentsPackage, sRecentsActivity);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+        if (opts != null) {
+            mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
+        } else {
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        }
+        mCanReuseTaskStackViews = true;
+    }
+
+    /** Sets the RecentsComponent callbacks. */
+    @Override
+    public void setCallback(RecentsComponent.Callbacks cb) {
+        sRecentsComponentCallbacks = cb;
+    }
+
+    /** Notifies the callbacks that the visibility of Recents has changed. */
+    @ProxyFromAnyToPrimaryUser
+    public static void notifyVisibilityChanged(Context context, SystemServicesProxy ssp,
+            boolean visible) {
+        if (ssp.isForegroundUserOwner()) {
+            visibilityChanged(visible);
+        } else {
+            Intent intent = createLocalBroadcastIntent(context,
+                    ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
+            intent.putExtra(EXTRA_RECENTS_VISIBILITY, visible);
+            context.sendBroadcastAsUser(intent, UserHandle.OWNER);
+        }
+    }
+    static void visibilityChanged(boolean visible) {
+        if (sRecentsComponentCallbacks != null) {
+            sRecentsComponentCallbacks.onVisibilityChanged(visible);
+        }
+    }
+
+    /**
+     * Returns the preloaded load plan and invalidates it.
+     */
+    public static RecentsTaskLoadPlan consumeInstanceLoadPlan() {
+        RecentsTaskLoadPlan plan = sInstanceLoadPlan;
+        sInstanceLoadPlan = null;
+        return plan;
+    }
+
+    /**** OnAnimationStartedListener Implementation ****/
+
+    @Override
+    public void onAnimationStarted() {
+        // Notify recents to start the enter animation
+        if (!mStartAnimationTriggered) {
+            // There can be a race condition between the start animation callback and
+            // the start of the new activity (where we register the receiver that listens
+            // to this broadcast, so we add our own receiver and if that gets called, then
+            // we know the activity has not yet started and we can retry sending the broadcast.
+            BroadcastReceiver fallbackReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (getResultCode() == Activity.RESULT_OK) {
+                        mStartAnimationTriggered = true;
+                        return;
+                    }
+
+                    // Schedule for the broadcast to be sent again after some time
+                    mHandler.postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            onAnimationStarted();
+                        }
+                    }, 25);
+                }
+            };
+
+            // Send the broadcast to notify Recents that the animation has started
+            Intent intent = createLocalBroadcastIntent(mContext, ACTION_START_ENTER_ANIMATION);
+            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+                    fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index cb1baeb..1561f70 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -43,7 +43,6 @@
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.DebugOverlayView;
@@ -75,6 +74,9 @@
     View mEmptyView;
     DebugOverlayView mDebugOverlay;
 
+    // MultiStack debug
+    RecentsMultiStackDialog mMultiStackDebugDialog;
+
     // Search AppWidget
     RecentsAppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
@@ -129,20 +131,20 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
-                if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
+            if (action.equals(Recents.ACTION_HIDE_RECENTS_ACTIVITY)) {
+                if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
                     // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
                     dismissRecentsToFocusedTaskOrHome(false);
-                } else if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
+                } else if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
                     // Otherwise, dismiss Recents to Home
                     dismissRecentsToHome(true);
                 } else {
                     // Do nothing, another activity is being launched on top of Recents
                 }
-            } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
+            } else if (action.equals(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // If we are toggling Recents, then first unfilter any filtered stacks first
                 dismissRecentsToFocusedTaskOrHome(true);
-            } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) {
+            } else if (action.equals(Recents.ACTION_START_ENTER_ANIMATION)) {
                 // Trigger the enter animation
                 onEnterAnimationTriggered();
                 // Notify the fallback receiver that we have successfully got the broadcast
@@ -180,17 +182,17 @@
     });
 
     /** Updates the set of recent tasks */
-    void updateRecentsTasks(Intent launchIntent) {
+    void updateRecentsTasks() {
         // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
         // reconstructing the task stack
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        RecentsTaskLoadPlan plan = AlternateRecentsComponent.consumeInstanceLoadPlan();
+        RecentsTaskLoadPlan plan = Recents.consumeInstanceLoadPlan();
         if (plan == null) {
             plan = loader.createLoadPlan(this);
         }
 
         // Start loading tasks according to the load plan
-        if (plan.getTaskStack() == null) {
+        if (!plan.hasTasks()) {
             loader.preloadTasks(plan, mConfig.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
@@ -199,13 +201,11 @@
         loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
-        SpaceNode root = plan.getSpaceNode();
-        ArrayList<TaskStack> stacks = root.getStacks();
-        boolean hasTasks = root.hasTasks();
-        if (hasTasks) {
+        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
+        mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
+        if (!mConfig.launchedWithNoRecentTasks) {
             mRecentsView.setTaskStacks(stacks);
         }
-        mConfig.launchedWithNoRecentTasks = !hasTasks;
 
         // Create the home intent runnable
         Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
@@ -432,20 +432,20 @@
         super.onStart();
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
-        AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true);
+        Recents.notifyVisibilityChanged(this, ssp, true);
 
         // Register the broadcast receiver to handle messages from our service
         IntentFilter filter = new IntentFilter();
-        filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
-        filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
-        filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
+        filter.addAction(Recents.ACTION_HIDE_RECENTS_ACTIVITY);
+        filter.addAction(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY);
+        filter.addAction(Recents.ACTION_START_ENTER_ANIMATION);
         registerReceiver(mServiceBroadcastReceiver, filter);
 
         // Register any broadcast receivers for the task loader
         loader.registerReceivers(this, mRecentsView);
 
         // Update the recent tasks
-        updateRecentsTasks(getIntent());
+        updateRecentsTasks();
 
         // If this is a new instance from a configuration change, then we have to manually trigger
         // the enter animation state
@@ -459,7 +459,7 @@
         super.onStop();
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
-        AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, false);
+        Recents.notifyVisibilityChanged(this, ssp, false);
 
         // Notify the views that we are no longer visible
         mRecentsView.onRecentsHidden();
@@ -591,6 +591,40 @@
         }
     }
 
+
+    /**** RecentsMultiStackDialog ****/
+
+    private RecentsMultiStackDialog getMultiStackDebugDialog() {
+        if (mMultiStackDebugDialog == null) {
+            mMultiStackDebugDialog = new RecentsMultiStackDialog(getFragmentManager());
+        }
+        return mMultiStackDebugDialog;
+    }
+
+    @Override
+    public void onMultiStackAddStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showAddStackDialog();
+    }
+
+    @Override
+    public void onMultiStackResizeStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showResizeStackDialog();
+    }
+
+    @Override
+    public void onMultiStackRemoveStack() {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showRemoveStackDialog();
+    }
+
+    @Override
+    public void onMultiStackMoveTask(Task t) {
+        RecentsMultiStackDialog dialog = getMultiStackDebugDialog();
+        dialog.showMoveTaskDialog(t);
+    }
+
     /**** RecentsView.RecentsViewCallbacks Implementation ****/
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 52e7e7f..1736c77 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -24,7 +24,6 @@
 import android.graphics.Rect;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import com.android.systemui.R;
@@ -50,9 +49,6 @@
     // Disable all thumbnail loading.
     public static final int SVELTE_DISABLE_LOADING = 3;
 
-    /** Animations */
-    public float animationPxMovementPerSecond;
-
     /** Interpolators */
     public Interpolator fastOutSlowInInterpolator;
     public Interpolator fastOutLinearInInterpolator;
@@ -83,6 +79,7 @@
     public int taskStackScrollDuration;
     public int taskStackMaxDim;
     public int taskStackTopPaddingPx;
+    public int dismissAllButtonSizePx;
     public float taskStackWidthPaddingPct;
     public float taskStackOverscrollPct;
 
@@ -137,6 +134,7 @@
     public boolean fakeShadows;
 
     /** Dev options and global settings */
+    public boolean multiStackEnabled;
     public boolean lockToAppEnabled;
     public boolean developerOptionsEnabled;
     public boolean debugModeEnabled;
@@ -197,10 +195,6 @@
         // Insets
         displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
 
-        // Animations
-        animationPxMovementPerSecond =
-                res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
-
         // Filtering
         filteringCurrentViewsAnimDuration =
                 res.getInteger(R.integer.recents_filter_animate_current_views_duration);
@@ -217,14 +211,11 @@
         // Task stack
         taskStackScrollDuration =
                 res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
-        TypedValue widthPaddingPctValue = new TypedValue();
-        res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
-        taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
-        TypedValue stackOverscrollPctValue = new TypedValue();
-        res.getValue(R.dimen.recents_stack_overscroll_percentage, stackOverscrollPctValue, true);
-        taskStackOverscrollPct = stackOverscrollPctValue.getFloat();
+        taskStackWidthPaddingPct = res.getFloat(R.dimen.recents_stack_width_padding_percentage);
+        taskStackOverscrollPct = res.getFloat(R.dimen.recents_stack_overscroll_percentage);
         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
+        dismissAllButtonSizePx = res.getDimensionPixelSize(R.dimen.recents_dismiss_all_button_size);
 
         // Transition
         transitionEnterFromAppDelay =
@@ -254,22 +245,19 @@
         taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
         taskViewAffiliateGroupEnterOffsetPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
-        TypedValue thumbnailAlphaValue = new TypedValue();
-        res.getValue(R.dimen.recents_task_view_thumbnail_alpha, thumbnailAlphaValue, true);
-        taskViewThumbnailAlpha = thumbnailAlphaValue.getFloat();
+        taskViewThumbnailAlpha = res.getFloat(R.dimen.recents_task_view_thumbnail_alpha);
 
         // Task bar colors
         taskBarViewDefaultBackgroundColor =
-                res.getColor(R.color.recents_task_bar_default_background_color);
+                res.getColor(R.color.recents_task_bar_default_background_color, null);
         taskBarViewLightTextColor =
-                res.getColor(R.color.recents_task_bar_light_text_color);
+                res.getColor(R.color.recents_task_bar_light_text_color, null);
         taskBarViewDarkTextColor =
-                res.getColor(R.color.recents_task_bar_dark_text_color);
+                res.getColor(R.color.recents_task_bar_dark_text_color, null);
         taskBarViewHighlightColor =
-                res.getColor(R.color.recents_task_bar_highlight_color);
-        TypedValue affMinAlphaPctValue = new TypedValue();
-        res.getValue(R.dimen.recents_task_affiliation_color_min_alpha_percentage, affMinAlphaPctValue, true);
-        taskBarViewAffiliationColorMinAlpha = affMinAlphaPctValue.getFloat();
+                res.getColor(R.color.recents_task_bar_highlight_color, null);
+        taskBarViewAffiliationColorMinAlpha = res.getFloat(
+                R.dimen.recents_task_affiliation_color_min_alpha_percentage);
 
         // Task bar size & animations
         taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
@@ -307,6 +295,7 @@
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
         lockToAppEnabled = ssp.getSystemSetting(context,
                 Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        multiStackEnabled = "1".equals(ssp.getSystemProperty("overview.enableMultiStack"));
     }
 
     /** Called when the configuration has changed, and we want to reset any configuration specific
@@ -344,17 +333,12 @@
         return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
     }
 
-    /** Returns whether the current layout is horizontal. */
-    public boolean hasHorizontalLayout() {
-        return isLandscape && hasTransposedSearchBar;
-    }
-
     /**
      * Returns the task stack bounds in the current orientation. These bounds do not account for
      * the system insets.
      */
-    public void getTaskStackBounds(int windowWidth, int windowHeight, int topInset, int rightInset,
-                                   Rect taskStackBounds) {
+    public void getAvailableTaskStackBounds(int windowWidth, int windowHeight, int topInset,
+            int rightInset, Rect taskStackBounds) {
         Rect searchBarBounds = new Rect();
         getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds);
         if (isLandscape && hasTransposedSearchBar) {
@@ -371,7 +355,7 @@
      * the system insets.
      */
     public void getSearchBarBounds(int windowWidth, int windowHeight, int topInset,
-                                   Rect searchBarSpaceBounds) {
+            Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
         int searchBarSize = searchBarSpaceHeightPx;
         if (!Constants.DebugFlags.App.EnableSearchLayout || !hasSearchBarAppWidget()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java
new file mode 100644
index 0000000..fdf9d39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsMultiStackDialog.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.MutableInt;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+import com.android.systemui.R;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+
+import java.util.List;
+
+/**
+ * A helper for the dialogs that show when multistack debugging is on.
+ */
+public class RecentsMultiStackDialog extends DialogFragment {
+
+    static final String TAG = "RecentsMultiStackDialog";
+
+    public static final int ADD_STACK_DIALOG = 0;
+    public static final int ADD_STACK_PICK_APP_DIALOG = 1;
+    public static final int REMOVE_STACK_DIALOG = 2;
+    public static final int RESIZE_STACK_DIALOG = 3;
+    public static final int RESIZE_STACK_PICK_STACK_DIALOG = 4;
+    public static final int MOVE_TASK_DIALOG = 5;
+
+    FragmentManager mFragmentManager;
+    int mCurrentDialogType;
+    MutableInt mTargetStackIndex = new MutableInt(0);
+    Task mTaskToMove;
+    SparseArray<ActivityManager.StackInfo> mStacks;
+    List<ResolveInfo> mLauncherActivities;
+    Rect mAddStackRect;
+    Intent mAddStackIntent;
+
+    View mAddStackDialogContent;
+
+    public RecentsMultiStackDialog() {}
+
+    public RecentsMultiStackDialog(FragmentManager mgr) {
+        mFragmentManager = mgr;
+    }
+
+    /** Shows the add-stack dialog. */
+    void showAddStackDialog() {
+        mCurrentDialogType = ADD_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new add-stack dialog. */
+    private void createAddStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        builder.setTitle("Add Stack - Enter new dimensions");
+        mAddStackDialogContent =
+                inflater.inflate(R.layout.recents_multistack_stack_size_dialog, null, false);
+        Rect windowRect = ssp.getWindowRect();
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_left, windowRect.left);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_top, windowRect.top);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_right, windowRect.right);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_bottom, windowRect.bottom);
+        builder.setView(mAddStackDialogContent);
+        builder.setPositiveButton("Add Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                int left = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_left);
+                int top = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_top);
+                int right = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_right);
+                int bottom = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_bottom);
+                if (bottom <= top || right <= left) {
+                    Toast.makeText(context, "Invalid dimensions", Toast.LENGTH_SHORT).show();
+                    dismiss();
+                    return;
+                }
+
+                // Prompt the user for the app to start
+                dismiss();
+                mCurrentDialogType = ADD_STACK_PICK_APP_DIALOG;
+                mAddStackRect = new Rect(left, top, right, bottom);
+                show(mFragmentManager, TAG);
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Creates a new add-stack pick-app dialog. */
+    private void createAddStackPickAppDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mLauncherActivities = ssp.getLauncherApps();
+        mAddStackIntent = null;
+        int activityCount = mLauncherActivities.size();
+        CharSequence[] activityNames = new CharSequence[activityCount];
+        for (int i = 0; i < activityCount; i++) {
+            activityNames[i] = ssp.getActivityLabel(mLauncherActivities.get(i).activityInfo);
+        }
+        builder.setTitle("Add Stack - Pick starting app");
+        builder.setSingleChoiceItems(activityNames, -1,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        ActivityInfo ai = mLauncherActivities.get(which).activityInfo;
+                        mAddStackIntent = new Intent(Intent.ACTION_MAIN);
+                        mAddStackIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+                        mAddStackIntent.setComponent(new ComponentName(ai.packageName, ai.name));
+                    }
+                });
+        builder.setPositiveButton("Add Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                // Display 0 = default display
+                ssp.createNewStack(0, mAddStackRect, mAddStackIntent);
+            }
+        });
+        builder.setNegativeButton("Skip", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                // Display 0 = default display
+                ssp.createNewStack(0, mAddStackRect, null);
+            }
+        });
+    }
+
+    /** Shows the resize-stack dialog. */
+    void showResizeStackDialog() {
+        mCurrentDialogType = RESIZE_STACK_PICK_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new resize-stack pick-stack dialog. */
+    private void createResizeStackPickStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mStacks = ssp.getAllStackInfos();
+        mTargetStackIndex.value = -1;
+        CharSequence[] stackNames = getAllStacksDescriptions(mStacks, -1, null);
+        builder.setTitle("Resize Stack - Pick stack");
+        builder.setSingleChoiceItems(stackNames, mTargetStackIndex.value,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        mTargetStackIndex.value = which;
+                    }
+                });
+        builder.setPositiveButton("Resize Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (mTargetStackIndex.value != -1) {
+                    // Prompt the user for the new dimensions
+                    dismiss();
+                    mCurrentDialogType = RESIZE_STACK_DIALOG;
+                    show(mFragmentManager, TAG);
+                }
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Creates a new resize-stack dialog. */
+    private void createResizeStackDialog(final Context context, LayoutInflater inflater,
+            AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        builder.setTitle("Resize Stack - Enter new dimensions");
+        final ActivityManager.StackInfo stack = mStacks.valueAt(mTargetStackIndex.value);
+        mAddStackDialogContent =
+                inflater.inflate(R.layout.recents_multistack_stack_size_dialog, null, false);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_left, stack.bounds.left);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_top, stack.bounds.top);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_right, stack.bounds.right);
+        setDimensionInEditText(mAddStackDialogContent, R.id.inset_bottom, stack.bounds.bottom);
+        builder.setView(mAddStackDialogContent);
+        builder.setPositiveButton("Resize Stack", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                int left = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_left);
+                int top = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_top);
+                int right = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_right);
+                int bottom = getDimensionFromEditText(mAddStackDialogContent, R.id.inset_bottom);
+                if (bottom <= top || right <= left) {
+                    Toast.makeText(context, "Invalid dimensions", Toast.LENGTH_SHORT).show();
+                    dismiss();
+                    return;
+                }
+                ssp.resizeStack(stack.stackId, new Rect(left, top, right, bottom));
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Shows the remove-stack dialog. */
+    void showRemoveStackDialog() {
+        mCurrentDialogType = REMOVE_STACK_DIALOG;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Shows the move-task dialog. */
+    void showMoveTaskDialog(Task task) {
+        mCurrentDialogType = MOVE_TASK_DIALOG;
+        mTaskToMove = task;
+        show(mFragmentManager, TAG);
+    }
+
+    /** Creates a new move-stack dialog. */
+    private void createMoveTaskDialog(final Context context, LayoutInflater inflater,
+                                AlertDialog.Builder builder, final SystemServicesProxy ssp) {
+        mStacks = ssp.getAllStackInfos();
+        mTargetStackIndex.value = -1;
+        CharSequence[] stackNames = getAllStacksDescriptions(mStacks, mTaskToMove.key.stackId,
+                mTargetStackIndex);
+        builder.setTitle("Move Task to Stack");
+        builder.setSingleChoiceItems(stackNames, mTargetStackIndex.value,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        mTargetStackIndex.value = which;
+                    }
+                });
+        builder.setPositiveButton("Move Task", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if (mTargetStackIndex.value != -1) {
+                    ActivityManager.StackInfo toStack = mStacks.valueAt(mTargetStackIndex.value);
+                    if (toStack.stackId != mTaskToMove.key.stackId) {
+                        ssp.moveTaskToStack(mTaskToMove.key.id, toStack.stackId, true);
+                        mTaskToMove.setStackId(toStack.stackId);
+                    }
+                }
+            }
+        });
+        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dismiss();
+            }
+        });
+    }
+
+    /** Helper to get an integer value from an edit text. */
+    private int getDimensionFromEditText(View container, int id) {
+        String text = ((EditText) container.findViewById(id)).getText().toString();
+        if (text.trim().length() != 0) {
+            return Integer.parseInt(text.trim());
+        }
+        return 0;
+    }
+
+    /** Helper to set an integer value to an edit text. */
+    private void setDimensionInEditText(View container, int id, int value) {
+        ((EditText) container.findViewById(id)).setText("" + value);
+    }
+
+    /** Gets a list of all the stacks. */
+    private CharSequence[] getAllStacksDescriptions(SparseArray<ActivityManager.StackInfo> stacks,
+            int targetStackId, MutableInt indexOfTargetStackId) {
+        int stackCount = stacks.size();
+        CharSequence[] stackNames = new CharSequence[stackCount];
+        for (int i = 0; i < stackCount; i++) {
+            ActivityManager.StackInfo stack = stacks.valueAt(i);
+            Rect b = stack.bounds;
+            String desc = "Stack " + stack.stackId + " / " +
+                    "" + (stack.taskIds.length > 0 ? stack.taskIds.length : "No") + " tasks\n" +
+                    "(" + b.left + ", " + b.top + ")-(" + b.right + ", " + b.bottom + ")\n";
+            stackNames[i] = desc;
+            if (targetStackId != -1 && stack.stackId == targetStackId) {
+                indexOfTargetStackId.value = i;
+            }
+        }
+        return stackNames;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle args) {
+        final Context context = this.getActivity();
+        final SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        switch(mCurrentDialogType) {
+            case ADD_STACK_DIALOG:
+                createAddStackDialog(context, inflater, builder, ssp);
+                break;
+            case ADD_STACK_PICK_APP_DIALOG:
+                createAddStackPickAppDialog(context, inflater, builder, ssp);
+                break;
+            case MOVE_TASK_DIALOG:
+                createMoveTaskDialog(context, inflater, builder, ssp);
+                break;
+            case RESIZE_STACK_PICK_STACK_DIALOG:
+                createResizeStackPickStackDialog(context, inflater, builder, ssp);
+                break;
+            case RESIZE_STACK_DIALOG:
+                createResizeStackDialog(context, inflater, builder, ssp);
+                break;
+        }
+        return builder.create();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java
index 236da5d..5eefbc7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsUserEventProxyReceiver.java
@@ -19,8 +19,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import com.android.systemui.recent.Recents;
-
 
 /**
  * A proxy for Recents events which happens strictly for non-owner users.
@@ -39,28 +37,27 @@
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        AlternateRecentsComponent recents = Recents.getRecentsComponent(
-                context.getApplicationContext(), true);
+        Recents recents = Recents.getInstanceAndStartIfNeeded(context);
         switch (intent.getAction()) {
             case ACTION_PROXY_SHOW_RECENTS_TO_USER: {
                 boolean triggeredFromAltTab = intent.getBooleanExtra(
-                        AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
-                recents.showRecents(triggeredFromAltTab);
+                        Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
+                recents.showRecentsInternal(triggeredFromAltTab);
                 break;
             }
             case ACTION_PROXY_HIDE_RECENTS_TO_USER: {
                 boolean triggeredFromAltTab = intent.getBooleanExtra(
-                        AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
+                        Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
                 boolean triggeredFromHome = intent.getBooleanExtra(
-                        AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false);
-                recents.hideRecents(triggeredFromAltTab, triggeredFromHome);
+                        Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false);
+                recents.hideRecentsInternal(triggeredFromAltTab, triggeredFromHome);
                 break;
             }
             case ACTION_PROXY_TOGGLE_RECENTS_TO_USER:
-                recents.toggleRecents();
+                recents.toggleRecentsInternal();
                 break;
             case ACTION_PROXY_PRELOAD_RECENTS_TO_USER:
-                recents.preloadRecents();
+                recents.preloadRecentsInternal();
                 break;
             case ACTION_PROXY_CONFIG_CHANGE_TO_USER:
                 recents.configurationChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
new file mode 100644
index 0000000..502862e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -0,0 +1,282 @@
+/*
+ * 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.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+public class ScreenPinningRequest implements View.OnClickListener {
+    private final Context mContext;
+
+    private final AccessibilityManager mAccessibilityService;
+    private final WindowManager mWindowManager;
+
+    private RequestWindowView mRequestWindow;
+
+    public ScreenPinningRequest(Context context) {
+        mContext = context;
+        mAccessibilityService = (AccessibilityManager)
+                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        mWindowManager = (WindowManager)
+                mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
+
+    public void clearPrompt() {
+        if (mRequestWindow != null) {
+            mWindowManager.removeView(mRequestWindow);
+            mRequestWindow = null;
+        }
+    }
+
+    public void showPrompt(boolean allowCancel) {
+        clearPrompt();
+
+        mRequestWindow = new RequestWindowView(mContext, allowCancel);
+
+        mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+        // show the confirmation
+        WindowManager.LayoutParams lp = getWindowLayoutParams();
+        mWindowManager.addView(mRequestWindow, lp);
+    }
+
+    public void onConfigurationChanged() {
+        if (mRequestWindow != null) {
+            mRequestWindow.onConfigurationChanged();
+        }
+    }
+
+    private WindowManager.LayoutParams getWindowLayoutParams() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                0
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                ,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.setTitle("ScreenPinningConfirmation");
+        lp.gravity = Gravity.FILL;
+        return lp;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
+            try {
+                ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();
+            } catch (RemoteException e) {}
+        }
+        clearPrompt();
+    }
+
+    public FrameLayout.LayoutParams getRequestLayoutParams(boolean isLandscape) {
+        return new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                isLandscape ? (Gravity.CENTER_VERTICAL | Gravity.RIGHT)
+                            : (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
+    }
+
+    private class RequestWindowView extends FrameLayout {
+        private static final int OFFSET_DP = 96;
+
+        private final ColorDrawable mColor = new ColorDrawable(0);
+        private ValueAnimator mColorAnim;
+        private ViewGroup mLayout;
+        private boolean mShowCancel;
+
+        public RequestWindowView(Context context, boolean showCancel) {
+            super(context);
+            setClickable(true);
+            setOnClickListener(ScreenPinningRequest.this);
+            setBackground(mColor);
+            mShowCancel = showCancel;
+        }
+
+        @Override
+        public void onAttachedToWindow() {
+            DisplayMetrics metrics = new DisplayMetrics();
+            mWindowManager.getDefaultDisplay().getMetrics(metrics);
+            float density = metrics.density;
+            boolean isLandscape = isLandscapePhone(mContext);
+
+            inflateView(isLandscape);
+            int bgColor = mContext.getResources().getColor(
+                    R.color.screen_pinning_request_window_bg);
+            if (ActivityManager.isHighEndGfx()) {
+                mLayout.setAlpha(0f);
+                if (isLandscape) {
+                    mLayout.setTranslationX(OFFSET_DP * density);
+                } else {
+                    mLayout.setTranslationY(OFFSET_DP * density);
+                }
+                mLayout.animate()
+                        .alpha(1f)
+                        .translationX(0)
+                        .translationY(0)
+                        .setDuration(300)
+                        .setInterpolator(new DecelerateInterpolator())
+                        .start();
+
+                mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, bgColor);
+                mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        final int c = (Integer) animation.getAnimatedValue();
+                        mColor.setColor(c);
+                    }
+                });
+                mColorAnim.setDuration(1000);
+                mColorAnim.start();
+            } else {
+                mColor.setColor(bgColor);
+            }
+
+            IntentFilter filter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
+            filter.addAction(Intent.ACTION_USER_SWITCHED);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            mContext.registerReceiver(mReceiver, filter);
+        }
+
+        private boolean isLandscapePhone(Context context) {
+            Configuration config = mContext.getResources().getConfiguration();
+            return config.orientation == Configuration.ORIENTATION_LANDSCAPE
+                    && config.smallestScreenWidthDp < 600;
+        }
+
+        private void inflateView(boolean isLandscape) {
+            // We only want this landscape orientation on <600dp, so rather than handle
+            // resource overlay for -land and -sw600dp-land, just inflate this
+            // other view for this single case.
+            mLayout = (ViewGroup) View.inflate(getContext(), isLandscape
+                    ? R.layout.screen_pinning_request_land_phone : R.layout.screen_pinning_request,
+                    null);
+            // Catch touches so they don't trigger cancel/activate, like outside does.
+            mLayout.setClickable(true);
+            // Status bar is always on the right.
+            mLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+            // Buttons and text do switch sides though.
+            View buttons = mLayout.findViewById(R.id.screen_pinning_buttons);
+            buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
+            mLayout.findViewById(R.id.screen_pinning_text_area)
+                    .setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE);
+            swapChildrenIfRtlAndVertical(buttons);
+
+            ((Button) mLayout.findViewById(R.id.screen_pinning_ok_button))
+                    .setOnClickListener(ScreenPinningRequest.this);
+            if (mShowCancel) {
+                ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
+                        .setOnClickListener(ScreenPinningRequest.this);
+            } else {
+                ((Button) mLayout.findViewById(R.id.screen_pinning_cancel_button))
+                        .setVisibility(View.INVISIBLE);
+            }
+
+            final int description = mAccessibilityService.isEnabled()
+                    ? R.string.screen_pinning_description_accessible
+                    : R.string.screen_pinning_description;
+            ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
+                    .setText(description);
+            final int backBgVisibility =
+                    mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
+            mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
+            mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility);
+
+            addView(mLayout, getRequestLayoutParams(isLandscape));
+        }
+
+        private void swapChildrenIfRtlAndVertical(View group) {
+            if (mContext.getResources().getConfiguration().getLayoutDirection()
+                    != View.LAYOUT_DIRECTION_RTL) {
+                return;
+            }
+            LinearLayout linearLayout = (LinearLayout) group;
+            if (linearLayout.getOrientation() == LinearLayout.VERTICAL) {
+                int childCount = linearLayout.getChildCount();
+                ArrayList<View> childList = new ArrayList<>(childCount);
+                for (int i = 0; i < childCount; i++) {
+                    childList.add(linearLayout.getChildAt(i));
+                }
+                linearLayout.removeAllViews();
+                for (int i = childCount - 1; i >= 0; i--) {
+                    linearLayout.addView(childList.get(i));
+                }
+            }
+        }
+
+        @Override
+        public void onDetachedFromWindow() {
+            mContext.unregisterReceiver(mReceiver);
+        }
+
+        protected void onConfigurationChanged() {
+            removeAllViews();
+            inflateView(isLandscapePhone(mContext));
+        }
+
+        private final Runnable mUpdateLayoutRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mLayout != null && mLayout.getParent() != null) {
+                    mLayout.setLayoutParams(getRequestLayoutParams(isLandscapePhone(mContext)));
+                }
+            }
+        };
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                    post(mUpdateLayoutRunnable);
+                } else if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)
+                        || intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+                    clearPrompt();
+                }
+            }
+        };
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 90b099c..72040fe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityContainer;
 import android.app.IActivityManager;
 import android.app.ITaskStackListener;
 import android.app.SearchManager;
@@ -49,21 +50,25 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 import com.android.systemui.R;
-import com.android.systemui.recents.AlternateRecentsComponent;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
@@ -214,7 +219,7 @@
     }
 
     /** Returns a list of the running tasks */
-    public List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
+    private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
         if (mAm == null) return null;
         return mAm.getRunningTasks(numTasks);
     }
@@ -228,6 +233,23 @@
         return null;
     }
 
+    /** Returns a list of all the launcher apps sorted by name. */
+    public List<ResolveInfo> getLauncherApps() {
+        if (mPm == null) return new ArrayList<ResolveInfo>();
+
+        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        List<ResolveInfo> activities = mPm.queryIntentActivities(mainIntent, 0 /* flags */);
+        Collections.sort(activities, new Comparator<ResolveInfo>() {
+            @Override
+            public int compare(ResolveInfo o1, ResolveInfo o2) {
+                return getActivityLabel(o1.activityInfo).compareTo(
+                        getActivityLabel(o2.activityInfo));
+            }
+        });
+        return activities;
+    }
+
     /** Returns whether the recents is currently running */
     public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
             AtomicBoolean isHomeTopMost) {
@@ -235,8 +257,8 @@
             ComponentName topActivity = topTask.topActivity;
 
             // Check if the front most activity is recents
-            if (topActivity.getPackageName().equals(AlternateRecentsComponent.sRecentsPackage) &&
-                    topActivity.getClassName().equals(AlternateRecentsComponent.sRecentsActivity)) {
+            if (topActivity.getPackageName().equals(Recents.sRecentsPackage) &&
+                    topActivity.getClassName().equals(Recents.sRecentsActivity)) {
                 if (isHomeTopMost != null) {
                     isHomeTopMost.set(false);
                 }
@@ -250,6 +272,64 @@
         return false;
     }
 
+    /** Create a new stack. */
+    public void createNewStack(int displayId, Rect bounds, Intent activity) {
+        try {
+            IActivityContainer container = mIam.createStackOnDisplay(displayId);
+            if (container != null) {
+                // Resize the stack
+                resizeStack(container.getStackId(), bounds);
+                // Start the new activity on that stack
+                container.startActivity(activity);
+            }
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /** Resizes a stack. */
+    public void resizeStack(int stackId, Rect bounds) {
+        if (mIam == null) return;
+
+        try {
+            mIam.resizeStack(stackId, bounds);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /** Returns the stack info for all stacks. */
+    public SparseArray<ActivityManager.StackInfo> getAllStackInfos() {
+        if (mIam == null) return new SparseArray<ActivityManager.StackInfo>();
+
+        try {
+            SparseArray<ActivityManager.StackInfo> stacks =
+                    new SparseArray<ActivityManager.StackInfo>();
+            List<ActivityManager.StackInfo> infos = mIam.getAllStackInfos();
+            int stackCount = infos.size();
+            for (int i = 0; i < stackCount; i++) {
+                ActivityManager.StackInfo info = infos.get(i);
+                stacks.put(info.stackId, info);
+            }
+            return stacks;
+        } catch (RemoteException e) {
+            e.printStackTrace();
+            return new SparseArray<ActivityManager.StackInfo>();
+        }
+    }
+
+    /** Returns the focused stack id. */
+    public int getFocusedStack() {
+        if (mIam == null) return -1;
+
+        try {
+            return mIam.getFocusedStackId();
+        } catch (RemoteException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
     /** Returns whether the specified task is in the home stack */
     public boolean isInHomeStack(int taskId) {
         if (mAm == null) return false;
@@ -313,7 +393,7 @@
         return thumbnail;
     }
 
-    /** Moves a task to the front with the specified activity options */
+    /** Moves a task to the front with the specified activity options. */
     public void moveTaskToFront(int taskId, ActivityOptions opts) {
         if (mAm == null) return;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
@@ -326,6 +406,18 @@
         }
     }
 
+    /** Moves a task to another stack. */
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        if (mIam == null) return;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+        try {
+            mIam.moveTaskToStack(taskId, stackId, toTop);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
     /** Removes the task */
     public void removeTask(int taskId) {
         if (mAm == null) return;
@@ -524,6 +616,13 @@
     }
 
     /**
+     * Returns a system property.
+     */
+    public String getSystemProperty(String key) {
+        return SystemProperties.get(key);
+    }
+
+    /**
      * Returns the window rect.
      */
     public Rect getWindowRect() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index e1179fa..84544ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -21,7 +21,6 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.view.View;
-import com.android.systemui.recents.RecentsConfiguration;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -34,7 +33,7 @@
     private static Method sPropertyMethod;
     static {
         try {
-            Class<?> c = Class.forName("android.view.GLES20Canvas");
+            Class<?> c = Class.forName("android.view.DisplayListCanvas");
             sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
             if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
         } catch (ClassNotFoundException e) {
@@ -44,19 +43,6 @@
         }
     }
 
-    /**
-     * Calculates a consistent animation duration (ms) for all animations depending on the movement
-     * of the object being animated.
-     */
-    public static int calculateTranslationAnimationDuration(int distancePx) {
-        return calculateTranslationAnimationDuration(distancePx, 100);
-    }
-    public static int calculateTranslationAnimationDuration(int distancePx, int minDuration) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        return Math.max(minDuration, (int) (1000f /* ms/s */ *
-                (Math.abs(distancePx) / config.animationPxMovementPerSecond)));
-    }
-
     /** Scales a rect about its centroid */
     public static void scaleRectAboutCenter(Rect r, float scale) {
         if (scale != 1.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 0e1c01a..5d98dda 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -20,9 +20,12 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.SparseArray;
+import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -34,11 +37,11 @@
 
 /**
  * This class stores the loading state as it goes through multiple stages of loading:
- *   - preloadRawTasks() will load the raw set of recents tasks from the system
- *   - preloadPlan() will construct a new task stack with all metadata and only icons and thumbnails
- *     that are currently in the cache
- *   - executePlan() will actually load and fill in the icons and thumbnails according to the load
- *     options specified, such that we can transition into the Recents activity seamlessly
+ *   1) preloadRawTasks() will load the raw set of recents tasks from the system
+ *   2) preloadPlan() will construct a new task stack with all metadata and only icons and
+ *      thumbnails that are currently in the cache
+ *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
+ *      options specified, such that we can transition into the Recents activity seamlessly
  */
 public class RecentsTaskLoadPlan {
     static String TAG = "RecentsTaskLoadPlan";
@@ -60,7 +63,7 @@
     SystemServicesProxy mSystemServicesProxy;
 
     List<ActivityManager.RecentTaskInfo> mRawTasks;
-    TaskStack mStack;
+    SparseArray<TaskStack> mStacks = new SparseArray<>();
     HashMap<Task.ComponentNameKey, ActivityInfoHandle> mActivityInfoCache =
             new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
 
@@ -90,21 +93,28 @@
     synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
         if (DEBUG) Log.d(TAG, "preloadPlan");
 
+        // This activity info cache will be used for both preloadPlan() and executePlan()
         mActivityInfoCache.clear();
-        mStack = new TaskStack();
+
+        // TODO (multi-display): Currently assume the primary display
+        Rect displayBounds = mSystemServicesProxy.getWindowRect();
 
         Resources res = mContext.getResources();
-        ArrayList<Task> loadedTasks = new ArrayList<Task>();
+        SparseArray<ArrayList<Task>> stacksTasks = new SparseArray<>();
         if (mRawTasks == null) {
             preloadRawTasks(isTopTaskHome);
         }
+        int firstStackId = -1;
         int taskCount = mRawTasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+            if (firstStackId < 0) {
+                firstStackId = t.stackId;
+            }
 
             // Compose the task key
-            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
-                    t.firstActiveTime, t.lastActiveTime);
+            Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
+                    t.userId, t.firstActiveTime, t.lastActiveTime);
 
             // Get an existing activity info handle if possible
             Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
@@ -143,14 +153,43 @@
                     iconFilename);
             task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
             if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
-            loadedTasks.add(task);
-        }
-        mStack.setTasks(loadedTasks);
-        mStack.createAffiliatedGroupings(mConfig);
 
-        // Assertion
-        if (mStack.getTaskCount() != mRawTasks.size()) {
-            throw new RuntimeException("Loading failed");
+            if (!mConfig.multiStackEnabled ||
+                    Constants.DebugFlags.App.EnableMultiStackToSingleStack) {
+                firstStackId = 0;
+                ArrayList<Task> stackTasks = stacksTasks.get(firstStackId);
+                if (stackTasks == null) {
+                    stackTasks = new ArrayList<Task>();
+                    stacksTasks.put(firstStackId, stackTasks);
+                }
+                stackTasks.add(task);
+            } else {
+                ArrayList<Task> stackTasks = stacksTasks.get(t.stackId);
+                if (stackTasks == null) {
+                    stackTasks = new ArrayList<Task>();
+                    stacksTasks.put(t.stackId, stackTasks);
+                }
+                stackTasks.add(task);
+            }
+        }
+
+        // Initialize the stacks
+        SparseArray<ActivityManager.StackInfo> stackInfos = mSystemServicesProxy.getAllStackInfos();
+        mStacks.clear();
+        int stackCount = stacksTasks.size();
+        for (int i = 0; i < stackCount; i++) {
+            int stackId = stacksTasks.keyAt(i);
+            ActivityManager.StackInfo info = stackInfos.get(stackId);
+            ArrayList<Task> stackTasks = stacksTasks.valueAt(i);
+            TaskStack stack = new TaskStack(stackId);
+            if (Constants.DebugFlags.App.EnableMultiStackToSingleStack) {
+                stack.setBounds(displayBounds, displayBounds);
+            } else {
+                stack.setBounds(info.bounds, displayBounds);
+            }
+            stack.setTasks(stackTasks);
+            stack.createAffiliatedGroupings(mConfig);
+            mStacks.put(stackId, stack);
         }
     }
 
@@ -166,72 +205,93 @@
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
-        ArrayList<Task> tasks = mStack.getTasks();
-        int taskCount = tasks.size();
-        for (int i = 0; i < taskCount; i++) {
-            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
-            Task task = tasks.get(i);
-            Task.TaskKey taskKey = task.key;
+        int stackCount = mStacks.size();
+        for (int j = 0; j < stackCount; j++) {
+            ArrayList<Task> tasks = mStacks.valueAt(j).getTasks();
+            int taskCount = tasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
+                Task task = tasks.get(i);
+                Task.TaskKey taskKey = task.key;
 
-            // Get an existing activity info handle if possible
-            Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
-            ActivityInfoHandle infoHandle;
-            boolean hadCachedActivityInfo = false;
-            if (mActivityInfoCache.containsKey(cnKey)) {
-                infoHandle = mActivityInfoCache.get(cnKey);
-                hadCachedActivityInfo = true;
-            } else {
-                infoHandle = new ActivityInfoHandle();
-            }
-
-            boolean isRunningTask = (task.key.id == opts.runningTaskId);
-            boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
-            boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
-
-            // If requested, skip the running task
-            if (opts.onlyLoadPausedActivities && isRunningTask) {
-                continue;
-            }
-
-            if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
-                if (task.activityIcon == null) {
-                    if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
-                    task.activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
-                            mSystemServicesProxy, res, infoHandle, true);
+                // Get an existing activity info handle if possible
+                Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
+                ActivityInfoHandle infoHandle;
+                boolean hadCachedActivityInfo = false;
+                if (mActivityInfoCache.containsKey(cnKey)) {
+                    infoHandle = mActivityInfoCache.get(cnKey);
+                    hadCachedActivityInfo = true;
+                } else {
+                    infoHandle = new ActivityInfoHandle();
                 }
-            }
-            if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
-                if (task.thumbnail == null || isRunningTask) {
-                    if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
-                    if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy,
-                                true);
-                    } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
-                        loadQueue.addTask(task);
+
+                boolean isRunningTask = (task.key.id == opts.runningTaskId);
+                boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
+                boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
+
+                // If requested, skip the running task
+                if (opts.onlyLoadPausedActivities && isRunningTask) {
+                    continue;
+                }
+
+                if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
+                    if (task.activityIcon == null) {
+                        if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
+                        task.activityIcon = loader.getAndUpdateActivityIcon(taskKey,
+                                t.taskDescription, mSystemServicesProxy, res, infoHandle, true);
                     }
                 }
-            }
+                if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
+                    if (task.thumbnail == null || isRunningTask) {
+                        if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
+                        if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+                            task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
+                                    mSystemServicesProxy, true);
+                        } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
+                            loadQueue.addTask(task);
+                        }
+                    }
+                }
 
-            // Update the activity info cache
-            if (!hadCachedActivityInfo && infoHandle.info != null) {
-                mActivityInfoCache.put(cnKey, infoHandle);
+                // Update the activity info cache
+                if (!hadCachedActivityInfo && infoHandle.info != null) {
+                    mActivityInfoCache.put(cnKey, infoHandle);
+                }
             }
         }
     }
 
     /**
-     * Composes and returns a TaskStack from the preloaded list of recent tasks.
+     * Returns all TaskStacks from the preloaded list of recent tasks.
      */
-    public TaskStack getTaskStack() {
-        return mStack;
+    public ArrayList<TaskStack> getAllTaskStacks() {
+        ArrayList<TaskStack> stacks = new ArrayList<TaskStack>();
+        int stackCount = mStacks.size();
+        for (int i = 0; i < stackCount; i++) {
+            stacks.add(mStacks.valueAt(i));
+        }
+        // Ensure that we have at least one stack
+        if (stacks.isEmpty()) {
+            stacks.add(new TaskStack());
+        }
+        return stacks;
     }
 
     /**
-     * Composes and returns a SpaceNode from the preloaded list of recent tasks.
+     * Returns a specific TaskStack from the preloaded list of recent tasks.
      */
-    public SpaceNode getSpaceNode() {
-        SpaceNode node = new SpaceNode();
-        node.setStack(mStack);
-        return node;
+    public TaskStack getTaskStack(int stackId) {
+        return mStacks.get(stackId);
+    }
+
+    /** Returns whether there are any tasks in any stacks. */
+    public boolean hasTasks() {
+        int stackCount = mStacks.size();
+        for (int i = 0; i < stackCount; i++) {
+            if (mStacks.valueAt(i).getTaskCount() > 0) {
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ba2903a..3192fe6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -33,7 +33,6 @@
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
-import java.util.Collection;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 
@@ -47,18 +46,6 @@
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
 
     /** Adds a new task to the load queue */
-    void addTasks(Collection<Task> tasks) {
-        for (Task t : tasks) {
-            if (!mQueue.contains(t)) {
-                mQueue.add(t);
-            }
-        }
-        synchronized(this) {
-            notifyAll();
-        }
-    }
-
-    /** Adds a new task to the load queue */
     void addTask(Task t) {
         if (!mQueue.contains(t)) {
             mQueue.add(t);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
deleted file mode 100644
index 831698a..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
+++ /dev/null
@@ -1,82 +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.recents.model;
-
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-
-
-/**
- * The full recents space is partitioned using a BSP into various nodes that define where task
- * stacks should be placed.
- */
-public class SpaceNode {
-    /* BSP node callbacks */
-    public interface SpaceNodeCallbacks {
-        /** Notifies when a node is added */
-        public void onSpaceNodeAdded(SpaceNode node);
-        /** Notifies when a node is measured */
-        public void onSpaceNodeMeasured(SpaceNode node, Rect rect);
-    }
-
-    SpaceNode mStartNode;
-    SpaceNode mEndNode;
-
-    TaskStack mStack;
-
-    public SpaceNode() {
-        // Do nothing
-    }
-
-    /** Sets the current stack for this space node */
-    public void setStack(TaskStack stack) {
-        mStack = stack;
-    }
-
-    /** Returns the task stack (not null if this is a leaf) */
-    TaskStack getStack() {
-        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);
-    }
-
-    /** Returns all the descendent task stacks */
-    private void getStacksRec(ArrayList<TaskStack> stacks) {
-        if (isLeafNode()) {
-            stacks.add(mStack);
-        } else {
-            mStartNode.getStacksRec(stacks);
-            mEndNode.getStacksRec(stacks);
-        }
-    }
-    public ArrayList<TaskStack> getStacks() {
-        ArrayList<TaskStack> stacks = new ArrayList<TaskStack>();
-        getStacksRec(stacks);
-        return stacks;
-    }
-}
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 55dfe45..0cd55d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -36,6 +36,9 @@
         public void onTaskDataLoaded();
         /* Notifies when a task has been unbound */
         public void onTaskDataUnloaded();
+
+        /* Notifies when a task's stack id has changed. */
+        public void onMultiStackDebugTaskStackIdChanged();
     }
 
     /** The ComponentNameKey represents the unique primary key for a component
@@ -68,14 +71,17 @@
     public static class TaskKey {
         final ComponentNameKey mComponentNameKey;
         public final int id;
+        public int stackId;
         public final Intent baseIntent;
         public final int userId;
         public long firstActiveTime;
         public long lastActiveTime;
 
-        public TaskKey(int id, Intent intent, int userId, long firstActiveTime, long lastActiveTime) {
+        public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime,
+                long lastActiveTime) {
             mComponentNameKey = new ComponentNameKey(intent.getComponent(), userId);
             this.id = id;
+            this.stackId = stackId;
             this.baseIntent = intent;
             this.userId = userId;
             this.firstActiveTime = firstActiveTime;
@@ -92,18 +98,19 @@
             if (!(o instanceof TaskKey)) {
                 return false;
             }
-            return id == ((TaskKey) o).id
-                    && userId == ((TaskKey) o).userId;
+            TaskKey otherKey = (TaskKey) o;
+            return id == otherKey.id && stackId == otherKey.stackId && userId == otherKey.userId;
         }
 
         @Override
         public int hashCode() {
-            return (id << 5) + userId;
+            return Objects.hash(id, stackId, userId);
         }
 
         @Override
         public String toString() {
             return "Task.Key: " + id + ", "
+                    + "s: " + stackId + ", "
                     + "u: " + userId + ", "
                     + "lat: " + lastActiveTime + ", "
                     + baseIntent.getComponent().getPackageName();
@@ -180,6 +187,14 @@
         this.group = group;
     }
 
+    /** Updates the stack id of this task. */
+    public void setStackId(int stackId) {
+        key.stackId = stackId;
+        if (mCb != null) {
+            mCb.onMultiStackDebugTaskStackIdChanged();
+        }
+    }
+
     /** Notifies the callback listeners that this task has been loaded */
     public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
         this.applicationIcon = applicationIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 81f0cef..5aaea15 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.model;
 
 import android.graphics.Color;
+import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
@@ -165,39 +166,46 @@
         public void onStackTaskAdded(TaskStack stack, Task t);
         /* Notifies when a task has been removed from the stack */
         public void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask);
+        /* Notifies when all task has been removed from the stack */
+        public void onStackAllTasksRemoved(TaskStack stack, ArrayList<Task> removedTasks);
         /** Notifies when the stack was filtered */
         public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
         /** Notifies when the stack was un-filtered */
         public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
     }
 
-    /** A pair of indices representing the group and task positions in the stack and group. */
-    public static class GroupTaskIndex {
-        public int groupIndex; // Index in the stack
-        public int taskIndex;  // Index in the group
-
-        public GroupTaskIndex() {}
-
-        public GroupTaskIndex(int gi, int ti) {
-            groupIndex = gi;
-            taskIndex = ti;
-        }
-    }
-
     // The task offset to apply to a task id as a group affiliation
     static final int IndividualTaskIdOffset = 1 << 16;
 
+    public final int id;
+    public final Rect stackBounds = new Rect();
+    public final Rect displayBounds = new Rect();
+
     FilteredTaskList mTaskList = new FilteredTaskList();
     TaskStackCallbacks mCb;
 
     ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
     HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<Integer, TaskGrouping>();
 
-    /** Sets the callbacks for this task stack */
+    public TaskStack() {
+        this(0);
+    }
+
+    public TaskStack(int stackId) {
+        id = stackId;
+    }
+
+    /** Sets the callbacks for this task stack. */
     public void setCallbacks(TaskStackCallbacks cb) {
         mCb = cb;
     }
 
+    /** Sets the bounds of this stack. */
+    public void setBounds(Rect stackBounds, Rect displayBounds) {
+        this.stackBounds.set(stackBounds);
+        this.displayBounds.set(displayBounds);
+    }
+
     /** Resets this TaskStack. */
     public void reset() {
         mCb = null;
@@ -214,19 +222,24 @@
         }
     }
 
+    /** Does the actual work associated with removing the task. */
+    void removeTaskImpl(Task t) {
+        // Remove the task from the list
+        mTaskList.remove(t);
+        // Remove it from the group as well, and if it is empty, remove the group
+        TaskGrouping group = t.group;
+        group.removeTask(t);
+        if (group.getTaskCount() == 0) {
+            removeGroup(group);
+        }
+        // Update the lock-to-app state
+        t.lockToThisTask = false;
+    }
+
     /** Removes a task */
     public void removeTask(Task t) {
         if (mTaskList.contains(t)) {
-            // Remove the task from the list
-            mTaskList.remove(t);
-            // Remove it from the group as well, and if it is empty, remove the group
-            TaskGrouping group = t.group;
-            group.removeTask(t);
-            if (group.getTaskCount() == 0) {
-                removeGroup(group);
-            }
-            // Update the lock-to-app state
-            t.lockToThisTask = false;
+            removeTaskImpl(t);
             Task newFrontMostTask = getFrontMostTask();
             if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
                 newFrontMostTask.lockToThisTask = true;
@@ -238,22 +251,27 @@
         }
     }
 
+    /** Removes all tasks */
+    public void removeAllTasks() {
+        ArrayList<Task> taskList = new ArrayList<Task>(mTaskList.getTasks());
+        int taskCount = taskList.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            Task t = taskList.get(i);
+            removeTaskImpl(t);
+        }
+        if (mCb != null) {
+            // Notify that all tasks have been removed
+            mCb.onStackAllTasksRemoved(this, taskList);
+        }
+    }
+
     /** Sets a few tasks in one go */
     public void setTasks(List<Task> tasks) {
         ArrayList<Task> taskList = mTaskList.getTasks();
         int taskCount = taskList.size();
-        for (int i = 0; i < taskCount; i++) {
+        for (int i = taskCount - 1; i >= 0; i--) {
             Task t = taskList.get(i);
-            // Remove the task from the list
-            mTaskList.remove(t);
-            // Remove it from the group as well, and if it is empty, remove the group
-            TaskGrouping group = t.group;
-            group.removeTask(t);
-            if (group.getTaskCount() == 0) {
-                removeGroup(group);
-            }
-            // Update the lock-to-app state
-            t.lockToThisTask = false;
+            removeTaskImpl(t);
             if (mCb != null) {
                 // Notify that a task has been removed
                 mCb.onStackTaskRemoved(this, t, null);
@@ -482,4 +500,4 @@
         }
         return str;
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 72f9001..509ad1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -159,9 +159,9 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
-        mCornerShadowPaint.setColorFilter(cf);
-        mEdgeShadowPaint.setColorFilter(cf);
+    public void setColorFilter(ColorFilter colorFilter) {
+        mCornerShadowPaint.setColorFilter(colorFilter);
+        mEdgeShadowPaint.setColorFilter(colorFilter);
     }
 
     @Override
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 427ffe5..d46e41b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -29,9 +29,10 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
-
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -41,6 +42,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
@@ -56,13 +58,22 @@
         public void onAllTaskViewsDismissed();
         public void onExitToHomeAnimationTriggered();
         public void onScreenPinningRequest();
+
+        public void onMultiStackAddStack();
+        public void onMultiStackResizeStack();
+        public void onMultiStackRemoveStack();
+        public void onMultiStackMoveTask(Task t);
     }
 
     RecentsConfiguration mConfig;
     LayoutInflater mInflater;
     DebugOverlayView mDebugOverlay;
+    ViewStub mMultiStackDebugStub;
+    View mMultiStackDebugView;
+    RecentsViewLayoutAlgorithm mLayoutAlgorithm;
 
     ArrayList<TaskStack> mStacks;
+    List<TaskStackView> mTaskStackViews = new ArrayList<>();
     View mSearchBar;
     RecentsViewCallbacks mCb;
 
@@ -82,6 +93,29 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
+        mLayoutAlgorithm = new RecentsViewLayoutAlgorithm(mConfig);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        if (!mConfig.multiStackEnabled) return;
+
+        mMultiStackDebugStub = (ViewStub) findViewById(R.id.multistack_debug_view_stub);
+        if (mMultiStackDebugView == null) {
+            mMultiStackDebugView = mMultiStackDebugStub.inflate();
+            mMultiStackDebugView.findViewById(R.id.add_stack).setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mCb.onMultiStackAddStack();
+                }
+            });
+            mMultiStackDebugView.findViewById(R.id.resize_stack).setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mCb.onMultiStackResizeStack();
+                }
+            });
+        }
     }
 
     /** Sets the callbacks */
@@ -98,29 +132,18 @@
     public void setTaskStacks(ArrayList<TaskStack> stacks) {
         int numStacks = stacks.size();
 
-        // Make a list of the stack view children only
-        ArrayList<TaskStackView> stackViews = new ArrayList<TaskStackView>();
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                stackViews.add((TaskStackView) child);
-            }
-        }
-
         // Remove all/extra stack views
         int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout
         if (mConfig.launchedReuseTaskStackViews) {
-            numTaskStacksToKeep = Math.min(childCount, numStacks);
+            numTaskStacksToKeep = Math.min(mTaskStackViews.size(), numStacks);
         }
-        for (int i = stackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
-            removeView(stackViews.get(i));
-            stackViews.remove(i);
+        for (int i = mTaskStackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
+            removeView(mTaskStackViews.remove(i));
         }
 
         // Update the stack views that we are keeping
         for (int i = 0; i < numTaskStacksToKeep; i++) {
-            TaskStackView tsv = stackViews.get(i);
+            TaskStackView tsv = mTaskStackViews.get(i);
             // If onRecentsHidden is not triggered, we need to the stack view again here
             tsv.reset();
             tsv.setStack(stacks.get(i));
@@ -128,46 +151,53 @@
 
         // Add remaining/recreate stack views
         mStacks = stacks;
-        for (int i = stackViews.size(); i < numStacks; i++) {
+        for (int i = mTaskStackViews.size(); i < numStacks; i++) {
             TaskStack stack = stacks.get(i);
             TaskStackView stackView = new TaskStackView(getContext(), stack);
             stackView.setCallbacks(this);
             addView(stackView);
+            mTaskStackViews.add(stackView);
         }
 
         // Enable debug mode drawing on all the stacks if necessary
         if (mConfig.debugModeEnabled) {
-            for (int i = childCount - 1; i >= 0; i--) {
-                View v = getChildAt(i);
-                if (v != mSearchBar) {
-                    TaskStackView stackView = (TaskStackView) v;
-                    stackView.setDebugOverlay(mDebugOverlay);
-                }
+            for (int i = mTaskStackViews.size() - 1; i >= 0; i--) {
+                TaskStackView stackView = mTaskStackViews.get(i);
+                stackView.setDebugOverlay(mDebugOverlay);
             }
         }
 
+        // Bring the debug view to the front
+        if (mMultiStackDebugView != null) {
+            mMultiStackDebugView.bringToFront();
+        }
+
         // Trigger a new layout
         requestLayout();
     }
 
+    /** Gets the list of task views */
+    List<TaskStackView> getTaskStackViews() {
+        return mTaskStackViews;
+    }
+
     /** Launches the focused task from the first stack if possible */
     public boolean launchFocusedTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                TaskStack stack = stackView.mStack;
-                // Iterate the stack views and try and find the focused task
-                int taskCount = stackView.getChildCount();
-                for (int j = 0; j < taskCount; j++) {
-                    TaskView tv = (TaskView) stackView.getChildAt(j);
-                    Task task = tv.getTask();
-                    if (tv.isFocusedTask()) {
-                        onTaskViewClicked(stackView, tv, stack, task, false);
-                        return true;
-                    }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            TaskStack stack = stackView.getStack();
+            // Iterate the stack views and try and find the focused task
+            List<TaskView> taskViews = stackView.getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int j = 0; j < taskViewCount; j++) {
+                TaskView tv = taskViews.get(j);
+                Task task = tv.getTask();
+                if (tv.isFocusedTask()) {
+                    onTaskViewClicked(stackView, tv, stack, task, false);
+                    return true;
                 }
             }
         }
@@ -177,24 +207,22 @@
     /** Launches the task that Recents was launched from, if possible */
     public boolean launchPreviousTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                TaskStack stack = stackView.mStack;
-                ArrayList<Task> tasks = stack.getTasks();
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            TaskStack stack = stackView.getStack();
+            ArrayList<Task> tasks = stack.getTasks();
 
-                // Find the launch task in the stack
-                if (!tasks.isEmpty()) {
-                    int taskCount = tasks.size();
-                    for (int j = 0; j < taskCount; j++) {
-                        if (tasks.get(j).isLaunchTarget) {
-                            Task task = tasks.get(j);
-                            TaskView tv = stackView.getChildViewForTask(task);
-                            onTaskViewClicked(stackView, tv, stack, task, false);
-                            return true;
-                        }
+            // Find the launch task in the stack
+            if (!tasks.isEmpty()) {
+                int taskCount = tasks.size();
+                for (int j = 0; j < taskCount; j++) {
+                    if (tasks.get(j).isLaunchTarget) {
+                        Task task = tasks.get(j);
+                        TaskView tv = stackView.getChildViewForTask(task);
+                        onTaskViewClicked(stackView, tv, stack, task, false);
+                        return true;
                     }
                 }
             }
@@ -208,13 +236,11 @@
         // to ensure that it runs
         ctx.postAnimationTrigger.increment();
 
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.startEnterRecentsAnimation(ctx);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.startEnterRecentsAnimation(ctx);
         }
         ctx.postAnimationTrigger.decrement();
     }
@@ -224,13 +250,11 @@
         // We have to increment/decrement the post animation trigger in case there are no children
         // to ensure that it runs
         ctx.postAnimationTrigger.increment();
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.startExitToHomeAnimation(ctx);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.startExitToHomeAnimation(ctx);
         }
         ctx.postAnimationTrigger.decrement();
 
@@ -286,22 +310,31 @@
         }
 
         Rect taskStackBounds = new Rect();
-        mConfig.getTaskStackBounds(width, height, mConfig.systemInsets.top,
+        mConfig.getAvailableTaskStackBounds(width, height, mConfig.systemInsets.top,
                 mConfig.systemInsets.right, taskStackBounds);
 
-        // Measure each TaskStackView with the full width and height of the window since the 
+        // Measure each TaskStackView with the full width and height of the window since the
         // transition view is a child of that stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar && child.getVisibility() != GONE) {
-                TaskStackView tsv = (TaskStackView) child;
-                // Set the insets to be the top/left inset + search bounds
-                tsv.setStackInsetRect(taskStackBounds);
-                tsv.measure(widthMeasureSpec, heightMeasureSpec);
+        List<TaskStackView> stackViews = getTaskStackViews();
+        List<Rect> stackViewsBounds = mLayoutAlgorithm.computeStackRects(stackViews,
+                taskStackBounds);
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            if (stackView.getVisibility() != GONE) {
+                // We are going to measure the TaskStackView with the whole RecentsView dimensions,
+                // but the actual stack is going to be inset to the bounds calculated by the layout
+                // algorithm
+                stackView.setStackInsetRect(stackViewsBounds.get(i));
+                stackView.measure(widthMeasureSpec, heightMeasureSpec);
             }
         }
 
+        // Measure the multistack debug view
+        if (mMultiStackDebugView != null) {
+            mMultiStackDebugView.measure(width, height);
+        }
+
         setMeasuredDimension(width, height);
     }
 
@@ -321,14 +354,27 @@
 
         // Layout each TaskStackView with the full width and height of the window since the 
         // transition view is a child of that stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar && child.getVisibility() != GONE) {
-                child.layout(left, top, left + child.getMeasuredWidth(),
-                        top + child.getMeasuredHeight());
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            if (stackView.getVisibility() != GONE) {
+                stackView.layout(left, top, left + stackView.getMeasuredWidth(),
+                        top + stackView.getMeasuredHeight());
             }
         }
+
+        // Layout the multistack debug view
+        if (mMultiStackDebugView != null) {
+            Rect taskStackBounds = new Rect();
+            mConfig.getAvailableTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(),
+                    mConfig.systemInsets.top, mConfig.systemInsets.right, taskStackBounds);
+            mMultiStackDebugView.layout(left,
+                    taskStackBounds.bottom - mConfig.systemInsets.bottom -
+                            mMultiStackDebugView.getMeasuredHeight(),
+                    left + mMultiStackDebugView.getMeasuredWidth(),
+                    taskStackBounds.bottom - mConfig.systemInsets.bottom);
+        }
     }
 
     @Override
@@ -342,41 +388,29 @@
     /** Notifies each task view of the user interaction. */
     public void onUserInteraction() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onUserInteraction();
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onUserInteraction();
         }
     }
 
     /** Focuses the next task in the first stack view */
     public void focusNextTask(boolean forward) {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.focusNextTask(forward, true);
-                break;
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        if (!stackViews.isEmpty()) {
+            stackViews.get(0).focusNextTask(forward, true);
         }
     }
 
     /** Dismisses the focused task. */
     public void dismissFocusedTask() {
         // Get the first stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.dismissFocusedTask();
-                break;
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        if (!stackViews.isEmpty()) {
+            stackViews.get(0).dismissFocusedTask();
         }
     }
 
@@ -475,9 +509,16 @@
                     }
                 };
             }
-            opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
-                    b, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
-                    sourceView.getHandler(), animStartedListener);
+            if (mConfig.multiStackEnabled) {
+                opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
+                        R.anim.recents_from_unknown_enter,
+                        R.anim.recents_from_unknown_exit,
+                        sourceView.getHandler(), animStartedListener);
+            } else {
+                opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
+                        b, offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+                        sourceView.getHandler(), animStartedListener);
+            }
         }
 
         final ActivityOptions launchOpts = opts;
@@ -546,20 +587,25 @@
     }
 
     @Override
-    public void onAllTaskViewsDismissed() {
+    public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks) {
+        if (removedTasks != null) {
+            int taskCount = removedTasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                onTaskViewDismissed(removedTasks.get(i));
+            }
+        }
+
         mCb.onAllTaskViewsDismissed();
     }
 
     /** Final callback after Recents is finally hidden. */
     public void onRecentsHidden() {
         // Notify each task stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onRecentsHidden();
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onRecentsHidden();
         }
     }
 
@@ -591,18 +637,23 @@
         }
     }
 
+    @Override
+    public void onMultiStackMoveTask(Task t) {
+        if (mCb != null) {
+            mCb.onMultiStackMoveTask(t);
+        }
+    }
+
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
     public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
         // Propagate this event down to each task stack view
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = getChildAt(i);
-            if (child != mSearchBar) {
-                TaskStackView stackView = (TaskStackView) child;
-                stackView.onPackagesChanged(monitor, packageName, userId);
-            }
+        List<TaskStackView> stackViews = getTaskStackViews();
+        int stackCount = stackViews.size();
+        for (int i = 0; i < stackCount; i++) {
+            TaskStackView stackView = stackViews.get(i);
+            stackView.onPackagesChanged(monitor, packageName, userId);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
new file mode 100644
index 0000000..eea273c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewLayoutAlgorithm.java
@@ -0,0 +1,59 @@
+/*
+ * 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.RecentsConfiguration;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/* The layout logic for the RecentsView. */
+public class RecentsViewLayoutAlgorithm {
+
+    RecentsConfiguration mConfig;
+
+    public RecentsViewLayoutAlgorithm(RecentsConfiguration config) {
+        mConfig = config;
+    }
+
+    /** Return the relative coordinate given coordinates in another size. */
+    private int getRelativeCoordinate(int availableOffset, int availableSize, int otherCoord, int otherSize) {
+        float relPos = (float) otherCoord / otherSize;
+        return availableOffset + (int) (relPos * availableSize);
+    }
+
+    /**
+     * Computes and returns the bounds that each of the stack views should take up.
+     */
+    List<Rect> computeStackRects(List<TaskStackView> stackViews, Rect availableBounds) {
+        ArrayList<Rect> bounds = new ArrayList<Rect>(stackViews.size());
+        int stackViewsCount = stackViews.size();
+        for (int i = 0; i < stackViewsCount; i++) {
+            TaskStack stack = stackViews.get(i).getStack();
+            Rect sb = stack.stackBounds;
+            Rect db = stack.displayBounds;
+            Rect ab = availableBounds;
+            bounds.add(new Rect(getRelativeCoordinate(ab.left, ab.width(), sb.left, db.width()),
+                    getRelativeCoordinate(ab.top, ab.height(), sb.top, db.height()),
+                    getRelativeCoordinate(ab.left, ab.width(), sb.right, db.width()),
+                    getRelativeCoordinate(ab.top, ab.height(), sb.bottom, db.height())));
+        }
+        return bounds;
+    }
+}
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 169683f..21975b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -36,11 +36,14 @@
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.statusbar.DismissView;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 
 
 /* The visual representation of a task stack view */
@@ -54,9 +57,11 @@
                                       boolean lockToTask);
         public void onTaskViewAppInfoClicked(Task t);
         public void onTaskViewDismissed(Task t);
-        public void onAllTaskViewsDismissed();
+        public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks);
         public void onTaskStackFilterTriggered();
         public void onTaskStackUnfilterTriggered();
+
+        public void onMultiStackMoveTask(Task t);
     }
 
     RecentsConfiguration mConfig;
@@ -72,6 +77,8 @@
     DozeTrigger mUIDozeTrigger;
     DebugOverlayView mDebugOverlay;
     Rect mTaskStackBounds = new Rect();
+    DismissView mDismissAllButton;
+    boolean mDismissAllButtonAnimating;
     int mFocusedTaskIndex = -1;
     int mPrevAccessibilityFocusedIndex = -1;
 
@@ -89,6 +96,8 @@
     Rect mTmpRect = new Rect();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
     HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>();
+    ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>();
+    List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>();
     LayoutInflater mInflater;
 
     // A convenience update listener to request updating clipping of tasks
@@ -116,9 +125,10 @@
             @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);
+                List<TaskView> taskViews = getTaskViews();
+                int taskViewCount = taskViews.size();
+                for (int i = 0; i < taskViewCount; i++) {
+                    TaskView tv = taskViews.get(i);
                     tv.startNoUserInteractionAnimation();
                 }
             }
@@ -141,21 +151,44 @@
         requestLayout();
     }
 
+    /** Returns the task stack. */
+    TaskStack getStack() {
+        return mStack;
+    }
+
     /** Sets the debug overlay */
     public void setDebugOverlay(DebugOverlayView overlay) {
         mDebugOverlay = overlay;
     }
 
+    /** Updates the list of task views */
+    void updateTaskViewsList() {
+        mTaskViews.clear();
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View v = getChildAt(i);
+            if (v instanceof TaskView) {
+                mTaskViews.add((TaskView) v);
+            }
+        }
+        mImmutableTaskViews = Collections.unmodifiableList(mTaskViews);
+    }
+
+    /** Gets the list of task views */
+    List<TaskView> getTaskViews() {
+        return mImmutableTaskViews;
+    }
+
     /** Resets this TaskStackView for reuse. */
     void reset() {
         // Reset the focused task
         resetFocusedTask();
 
         // Return all the views to the pool
-        int childCount = getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            TaskView tv = (TaskView) getChildAt(i);
-            mViewPool.returnViewToPool(tv);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            mViewPool.returnViewToPool(taskViews.get(i));
         }
 
         // Mark each task view for relayout
@@ -209,9 +242,10 @@
 
     /** Finds the child view given a specific task. */
     public TaskView getChildViewForTask(Task t) {
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
             if (tv.getTask() == t) {
                 return tv;
             }
@@ -299,17 +333,36 @@
                 mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]");
             }
 
+            // Inflate and add the dismiss button if necessary
+            if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) {
+                mDismissAllButton = (DismissView)
+                        mInflater.inflate(R.layout.recents_dismiss_button, this, false);
+                mDismissAllButton.setOnButtonClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        mStack.removeAllTasks();
+                    }
+                });
+                addView(mDismissAllButton, 0);
+            }
+
             // Return all the invisible children to the pool
             mTmpTaskViewMap.clear();
-            int childCount = getChildCount();
-            for (int i = childCount - 1; i >= 0; i--) {
-                TaskView tv = (TaskView) getChildAt(i);
+            List<TaskView> taskViews = getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int i = taskViewCount - 1; i >= 0; i--) {
+                TaskView tv = taskViews.get(i);
                 Task task = tv.getTask();
                 int taskIndex = mStack.indexOfTask(task);
                 if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) {
                     mTmpTaskViewMap.put(task, tv);
                 } else {
                     mViewPool.returnViewToPool(tv);
+
+                    // Hide the dismiss button if the front most task is invisible
+                    if (task == mStack.getFrontMostTask()) {
+                        hideDismissAllButton(null);
+                    }
                 }
             }
 
@@ -333,6 +386,12 @@
                         }
                         tv.updateViewPropertiesToTaskTransform(mTmpTransform, 0);
                     }
+
+                    // If we show the front most task view then ensure that the dismiss button
+                    // is visible too.
+                    if (!mAwaitingFirstLayout && (task == mStack.getFrontMostTask())) {
+                        showDismissAllButton();
+                    }
                 }
 
                 // Animate the task into place
@@ -341,9 +400,10 @@
 
                 // Request accessibility focus on the next view if we removed the task
                 // that previously held accessibility focus
-                childCount = getChildCount();
-                if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
-                    TaskView atv = (TaskView) getChildAt(childCount - 1);
+                taskViews = getTaskViews();
+                taskViewCount = taskViews.size();
+                if (taskViewCount > 0 && ssp.isTouchExplorationEnabled()) {
+                    TaskView atv = taskViews.get(taskViewCount - 1);
                     int indexOfTask = mStack.indexOfTask(atv.getTask());
                     if (mPrevAccessibilityFocusedIndex != indexOfTask) {
                         tv.requestAccessibilityFocus();
@@ -364,44 +424,43 @@
     /** Updates the clip for each of the task views. */
     void clipTaskViews() {
         // Update the clip on each task child
-        if (Constants.DebugFlags.App.EnableTaskStackClipping) {
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount - 1; i++) {
-                TaskView tv = (TaskView) getChildAt(i);
-                TaskView nextTv = null;
-                TaskView tmpTv = null;
-                int clipBottom = 0;
-                if (tv.shouldClipViewInStack()) {
-                    // Find the next view to clip against
-                    int nextIndex = i;
-                    while (nextIndex < getChildCount()) {
-                        tmpTv = (TaskView) getChildAt(++nextIndex);
-                        if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
-                            nextTv = tmpTv;
-                            break;
-                        }
-                    }
-
-                    // Clip against the next view, this is just an approximation since we are
-                    // stacked and we can make assumptions about the visibility of the this
-                    // task relative to the ones in front of it.
-                    if (nextTv != null) {
-                        // Map the top edge of next task view into the local space of the current
-                        // task view to find the clip amount in local space
-                        mTmpCoord[0] = mTmpCoord[1] = 0;
-                        Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
-                        Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
-                        clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
-                                - nextTv.getPaddingTop() - 1);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount - 1; i++) {
+            TaskView tv = taskViews.get(i);
+            TaskView nextTv = null;
+            TaskView tmpTv = null;
+            int clipBottom = 0;
+            if (tv.shouldClipViewInStack()) {
+                // Find the next view to clip against
+                int nextIndex = i;
+                while (nextIndex < (taskViewCount - 1)) {
+                    tmpTv = taskViews.get(++nextIndex);
+                    if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
+                        nextTv = tmpTv;
+                        break;
                     }
                 }
-                tv.getViewBounds().setClipBottom(clipBottom);
+
+                // Clip against the next view, this is just an approximation since we are
+                // stacked and we can make assumptions about the visibility of the this
+                // task relative to the ones in front of it.
+                if (nextTv != null) {
+                    // Map the top edge of next task view into the local space of the current
+                    // task view to find the clip amount in local space
+                    mTmpCoord[0] = mTmpCoord[1] = 0;
+                    Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
+                    Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
+                    clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
+                            - nextTv.getPaddingTop() - 1);
+                }
             }
-            if (getChildCount() > 0) {
-                // The front most task should never be clipped
-                TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
-                tv.getViewBounds().setClipBottom(0);
-            }
+            tv.getViewBounds().setClipBottom(clipBottom);
+        }
+        if (taskViewCount > 0) {
+            // The front most task should never be clipped
+            TaskView tv = taskViews.get(taskViewCount - 1);
+            tv.getViewBounds().setClipBottom(0);
         }
         mStackViewsClipDirty = false;
     }
@@ -479,9 +538,10 @@
             // of the screen and use that as the currently focused task
             int x = mLayoutAlgorithm.mStackVisibleRect.centerX();
             int y = mLayoutAlgorithm.mStackVisibleRect.centerY();
-            int childCount = getChildCount();
-            for (int i = childCount - 1; i >= 0; i--) {
-                TaskView tv = (TaskView) getChildAt(i);
+            List<TaskView> taskViews = getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int i = taskViewCount - 1; i >= 0; i--) {
+                TaskView tv = taskViews.get(i);
                 tv.getHitRect(mTmpRect);
                 if (mTmpRect.contains(x, y)) {
                     mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
@@ -489,8 +549,8 @@
                 }
             }
             // If we can't find the center task, then use the front most index
-            if (mFocusedTaskIndex < 0 && childCount > 0) {
-                mFocusedTaskIndex = childCount - 1;
+            if (mFocusedTaskIndex < 0 && taskViewCount > 0) {
+                mFocusedTaskIndex = taskViewCount - 1;
             }
         }
         return mFocusedTaskIndex >= 0;
@@ -543,10 +603,11 @@
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        int childCount = getChildCount();
-        if (childCount > 0) {
-            TaskView backMostTask = (TaskView) getChildAt(0);
-            TaskView frontMostTask = (TaskView) getChildAt(childCount - 1);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        if (taskViewCount > 0) {
+            TaskView backMostTask = taskViews.get(0);
+            TaskView frontMostTask = taskViews.get(taskViewCount - 1);
             event.setFromIndex(mStack.indexOfTask(backMostTask.getTask()));
             event.setToIndex(mStack.indexOfTask(frontMostTask.getTask()));
             event.setContentDescription(frontMostTask.getTask().activityLabel);
@@ -571,12 +632,18 @@
         return mTouchHandler.onGenericMotionEvent(ev);
     }
 
+    /** Returns the region that touch gestures can be started in. */
+    Rect getTouchableRegion() {
+        return mTaskStackBounds;
+    }
+
     @Override
     public void computeScroll() {
         mStackScroller.computeScroll();
         // Synchronize the views
         synchronizeStackViewsWithModel();
         clipTaskViews();
+        updateDismissButtonPosition();
         // Notify accessibility
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
     }
@@ -633,9 +700,10 @@
         }
 
         // Measure each of the TaskViews
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
             if (tv.getBackground() != null) {
                 tv.getBackground().getPadding(mTmpRect);
             } else {
@@ -650,6 +718,14 @@
                         MeasureSpec.EXACTLY));
         }
 
+        // Measure the dismiss button
+        if (mDismissAllButton != null) {
+            int taskRectWidth = mLayoutAlgorithm.mTaskRect.width();
+            mDismissAllButton.measure(
+                MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY));
+        }
+
         setMeasuredDimension(width, height);
     }
 
@@ -661,9 +737,10 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         // Layout each of the children
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
             if (tv.getBackground() != null) {
                 tv.getBackground().getPadding(mTmpRect);
             } else {
@@ -675,6 +752,15 @@
                     mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom);
         }
 
+        // Layout the dismiss button at the top of the screen, and just translate it accordingly
+        // when synchronizing the views with the model to attach it to the bottom of the front-most
+        // task view
+        if (mDismissAllButton != null) {
+            mDismissAllButton.layout(mLayoutAlgorithm.mTaskRect.left, 0,
+                    mLayoutAlgorithm.mTaskRect.left + mDismissAllButton.getMeasuredWidth(),
+                    mDismissAllButton.getMeasuredHeight());
+        }
+
         if (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
             onFirstLayout();
@@ -688,9 +774,10 @@
 
         // Find the launch target task
         Task launchTargetTask = null;
-        int childCount = getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            TaskView tv = (TaskView) getChildAt(i);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
             if (task.isLaunchTarget) {
                 launchTargetTask = task;
@@ -699,8 +786,8 @@
         }
 
         // Prepare the first view for its enter animation
-        for (int i = childCount - 1; i >= 0; i--) {
-            TaskView tv = (TaskView) getChildAt(i);
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
             boolean occludesLaunchTarget = (launchTargetTask != null) &&
                     launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
@@ -743,9 +830,10 @@
         if (mStack.getTaskCount() > 0) {
             // Find the launch target task
             Task launchTargetTask = null;
-            int childCount = getChildCount();
-            for (int i = childCount - 1; i >= 0; i--) {
-                TaskView tv = (TaskView) getChildAt(i);
+            List<TaskView> taskViews = getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int i = taskViewCount - 1; i >= 0; i--) {
+                TaskView tv = taskViews.get(i);
                 Task task = tv.getTask();
                 if (task.isLaunchTarget) {
                     launchTargetTask = task;
@@ -754,12 +842,12 @@
             }
 
             // Animate all the task views into view
-            for (int i = childCount - 1; i >= 0; i--) {
-                TaskView tv = (TaskView) getChildAt(i);
+            for (int i = taskViewCount - 1; i >= 0; i--) {
+                TaskView tv = taskViews.get(i);
                 Task task = tv.getTask();
                 ctx.currentTaskTransform = new TaskViewTransform();
                 ctx.currentStackViewIndex = i;
-                ctx.currentStackViewCount = childCount;
+                ctx.currentStackViewCount = taskViewCount;
                 ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
                 ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
                         launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
@@ -778,11 +866,12 @@
 
                     RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
                     SystemServicesProxy ssp = loader.getSystemServicesProxy();
-                    int childCount = getChildCount();
-                    if (childCount > 0) {
+                    List<TaskView> taskViews = getTaskViews();
+                    int taskViewCount = taskViews.size();
+                    if (taskViewCount > 0) {
                         // Focus the first view if accessibility is enabled
                         if (ssp.isTouchExplorationEnabled()) {
-                            TaskView tv = ((TaskView) getChildAt(childCount - 1));
+                            TaskView tv = taskViews.get(taskViewCount - 1);
                             tv.requestAccessibilityFocus();
                             mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
                         }
@@ -790,17 +879,20 @@
 
                     // Start the focus animation when alt-tabbing
                     if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
-                        View tv = getChildAt(mFocusedTaskIndex);
+                        TaskView tv = getChildViewForTask(mStack.getTasks().get(mFocusedTaskIndex));
                         if (tv != null) {
-                            ((TaskView) tv).setFocusedTask(true);
+                            tv.setFocusedTask(true);
                         }
                     }
+
+                    // Show the dismiss button
+                    showDismissAllButton();
                 }
             });
         }
     }
 
-    /** Requests this task stacks to start it's exit-recents animation. */
+    /** Requests this task stack to start it's exit-recents animation. */
     public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
         // Stop any scrolling
         mStackScroller.stopScroller();
@@ -808,19 +900,44 @@
         // Animate all the task views out of view
         ctx.offscreenTranslationY = mLayoutAlgorithm.mViewRect.bottom -
                 (mLayoutAlgorithm.mTaskRect.top - mLayoutAlgorithm.mViewRect.top);
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) getChildAt(i);
+        // Animate the dismiss-all button
+        hideDismissAllButton(null);
+
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
             tv.startExitToHomeAnimation(ctx);
         }
     }
 
+    /** Requests this task stack to start it's dismiss-all animation. */
+    public void startDismissAllAnimation(final Runnable postAnimationRunnable) {
+        // Clear the focused task
+        resetFocusedTask();
+        // Animate the dismiss-all button
+        hideDismissAllButton(new Runnable() {
+            @Override
+            public void run() {
+                List<TaskView> taskViews = getTaskViews();
+                int taskViewCount = taskViews.size();
+                int count = 0;
+                for (int i = taskViewCount - 1; i >= 0; i--) {
+                    TaskView tv = taskViews.get(i);
+                    tv.startDeleteTaskAnimation(i > 0 ? null : postAnimationRunnable, count * 50);
+                    count++;
+                }
+            }
+        });
+    }
+
     /** Animates a task view in this stack as it launches. */
     public void startLaunchTaskAnimation(TaskView tv, Runnable r, boolean lockToTask) {
         Task launchTargetTask = tv.getTask();
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView t = (TaskView) getChildAt(i);
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView t = taskViews.get(i);
             if (t == tv) {
                 t.setClipViewInStack(false);
                 t.startLaunchTaskAnimation(r, true, true, lockToTask);
@@ -832,6 +949,69 @@
         }
     }
 
+    /** Shows the dismiss button */
+    void showDismissAllButton() {
+        if (mDismissAllButton == null) return;
+
+        if (mDismissAllButtonAnimating || mDismissAllButton.getVisibility() != View.VISIBLE ||
+                Float.compare(mDismissAllButton.getAlpha(), 0f) == 0) {
+            mDismissAllButtonAnimating = true;
+            mDismissAllButton.setVisibility(View.VISIBLE);
+            mDismissAllButton.showClearButton();
+            mDismissAllButton.findViewById(R.id.dismiss_text).setAlpha(1f);
+            mDismissAllButton.setAlpha(0f);
+            mDismissAllButton.animate()
+                    .alpha(1f)
+                    .setDuration(250)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mDismissAllButtonAnimating = false;
+                        }
+                    })
+                    .start();
+        }
+    }
+
+    /** Hides the dismiss button */
+    void hideDismissAllButton(final Runnable postAnimRunnable) {
+        if (mDismissAllButton == null) return;
+
+        mDismissAllButtonAnimating = true;
+        mDismissAllButton.animate()
+                .alpha(0f)
+                .setDuration(200)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mDismissAllButtonAnimating = false;
+                        mDismissAllButton.setVisibility(View.GONE);
+                        if (postAnimRunnable != null) {
+                            postAnimRunnable.run();
+                        }
+                    }
+                })
+                .start();
+    }
+
+    /** Updates the dismiss button position */
+    void updateDismissButtonPosition() {
+        if (mDismissAllButton == null) return;
+
+        // Update the position of the clear-all button to hang it off the first task view
+        if (mStack.getTaskCount() > 0) {
+            mTmpCoord[0] = mTmpCoord[1] = 0;
+            TaskView tv = getChildViewForTask(mStack.getFrontMostTask());
+            TaskViewTransform transform = mCurrentTaskTransforms.get(mStack.getTaskCount() - 1);
+            if (tv != null && transform.visible) {
+                Utilities.mapCoordInDescendentToSelf(tv, this, mTmpCoord, false);
+                mDismissAllButton.setTranslationY(mTmpCoord[1] + (tv.getScaleY() * tv.getHeight()));
+                mDismissAllButton.setTranslationX(-(mLayoutAlgorithm.mStackRect.width() -
+                        transform.rect.width()) / 2f);
+            }
+        }
+    }
+
     /** Final callback after Recents is finally hidden. */
     void onRecentsHidden() {
         reset();
@@ -908,12 +1088,30 @@
                 shouldFinishActivity = (mStack.getTaskCount() == 0);
             }
             if (shouldFinishActivity) {
-                mCb.onAllTaskViewsDismissed();
+                mCb.onAllTaskViewsDismissed(null);
             }
+        } else {
+            // Fade the dismiss button back in
+            showDismissAllButton();
         }
     }
 
     @Override
+    public void onStackAllTasksRemoved(TaskStack stack, final ArrayList<Task> removedTasks) {
+        // Announce for accessibility
+        String msg = getContext().getString(R.string.accessibility_recents_all_items_dismissed);
+        announceForAccessibility(msg);
+
+        startDismissAllAnimation(new Runnable() {
+            @Override
+            public void run() {
+                // Notify that all tasks have been removed
+                mCb.onAllTaskViewsDismissed(removedTasks);
+            }
+        });
+    }
+
+    @Override
     public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curTasks,
                                 Task filteredTask) {
         /*
@@ -998,6 +1196,8 @@
 
         // Detach the view from the hierarchy
         detachViewFromParent(tv);
+        // Update the task views list after removing the task view
+        updateTaskViewsList();
 
         // Reset the view properties
         tv.resetViewProperties();
@@ -1032,11 +1232,14 @@
         int insertIndex = -1;
         int taskIndex = mStack.indexOfTask(task);
         if (taskIndex != -1) {
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                Task tvTask = ((TaskView) getChildAt(i)).getTask();
+
+            List<TaskView> taskViews = getTaskViews();
+            int taskViewCount = taskViews.size();
+            for (int i = 0; i < taskViewCount; i++) {
+                Task tvTask = taskViews.get(i).getTask();
                 if (taskIndex < mStack.indexOfTask(tvTask)) {
-                    insertIndex = i;
+                    // Offset by 1 if we have a dismiss-all button
+                    insertIndex = i + (Constants.DebugFlags.App.EnableDismissAll ? 1 : 0);
                     break;
                 }
             }
@@ -1051,6 +1254,8 @@
                 tv.requestLayout();
             }
         }
+        // Update the task views list after adding the new task view
+        updateTaskViewsList();
 
         // Set the new state for this view, including the callbacks and view clipping
         tv.setCallbacks(this);
@@ -1133,6 +1338,13 @@
         }
     }
 
+    @Override
+    public void onMultiStackMoveTask(TaskView tv) {
+        if (mCb != null) {
+            mCb.onMultiStackMoveTask(tv.getTask());
+        }
+    }
+
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
@@ -1163,7 +1375,7 @@
                         public void run() {
                             mStack.removeTask(t);
                         }
-                    });
+                    }, 0);
                 } else {
                     // Otherwise, remove the task from the stack immediately
                     mStack.removeTask(t);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index 9cd5ae4..614ca53 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -22,6 +22,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /* The layout logic for a TaskStackView */
 public class TaskStackViewFilterAlgorithm {
@@ -142,9 +143,10 @@
         // the new stack) or to their final positions in the new stack
         int offset = 0;
         int movement = 0;
-        int childCount = mStackView.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TaskView tv = (TaskView) mStackView.getChildAt(i);
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
             int taskIndex = tasks.indexOf(task);
             TaskViewTransform toTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 49b9129..f6df881 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.graphics.Rect;
+import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -131,6 +132,11 @@
         float pNavBarOffset = pAtBottomOfStackRect -
                 screenYToCurveProgress(mStackVisibleRect.bottom - (mStackVisibleRect.bottom -
                         mStackRect.bottom));
+        float pDismissAllButtonOffset = 0f;
+        if (Constants.DebugFlags.App.EnableDismissAll) {
+            pDismissAllButtonOffset = pAtBottomOfStackRect -
+                screenYToCurveProgress(mStackVisibleRect.bottom - mConfig.dismissAllButtonSizePx);
+        }
 
         // Update the task offsets
         float pAtBackMostCardTop = 0.5f;
@@ -148,7 +154,8 @@
             }
         }
 
-        mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset));
+        mMaxScrollP = pAtFrontMostCardTop + pDismissAllButtonOffset -
+                ((1f - pTaskHeightOffset - pNavBarOffset));
         mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f;
         if (launchedWithAltTab && launchedFromHome) {
             // Center the top most task, since that will be focused first
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index f7067be..fabc86d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -96,23 +96,13 @@
         }
         return false;
     }
-    /** Bounds the current scroll if necessary, but does not synchronize the stack view with the model. */
-    public boolean boundScrollRaw() {
-        float curScroll = getStackScroll();
-        float newScroll = getBoundedStackScroll(curScroll);
-        if (Float.compare(newScroll, curScroll) != 0) {
-            setStackScrollRaw(newScroll);
-            return true;
-        }
-        return false;
-    }
 
     /** Returns the bounded stack scroll */
     float getBoundedStackScroll(float scroll) {
         return Math.max(mLayoutAlgorithm.mMinScrollP, Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
     }
 
-    /** Returns the amount that the aboslute value of how much the scroll is out of bounds. */
+    /** Returns the amount that the absolute value of how much the scroll is out of bounds. */
     float getScrollAmountOutOfBounds(float scroll) {
         if (scroll < mLayoutAlgorithm.mMinScrollP) {
             return Math.abs(scroll - mLayoutAlgorithm.mMinScrollP);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 59e38f4..6cdddc5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -26,6 +26,8 @@
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 
+import java.util.List;
+
 /* Handles touch events for a TaskStackView. */
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
     static int INACTIVE_POINTER_ID = -1;
@@ -93,9 +95,10 @@
 
     /** Returns the view at the specified coordinates */
     TaskView findViewAtPoint(int x, int y) {
-        int childCount = mSv.getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            TaskView tv = (TaskView) mSv.getChildAt(i);
+        List<TaskView> taskViews = mSv.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
             if (tv.getVisibility() == View.VISIBLE) {
                 if (mSv.isTransformedTouchPointInView(x, y, tv)) {
                     return tv;
@@ -115,11 +118,21 @@
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         // Return early if we have no children
-        boolean hasChildren = (mSv.getChildCount() > 0);
-        if (!hasChildren) {
+        boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
+        if (!hasTaskViews) {
             return false;
         }
 
+        int action = ev.getAction();
+        if (mConfig.multiStackEnabled) {
+            // Check if we are within the bounds of the stack view contents
+            if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
+                if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
+                    return false;
+                }
+            }
+        }
+
         // Pass through to swipe helper if we are swiping
         mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
         if (mInterceptedBySwipeHelper) {
@@ -128,7 +141,6 @@
 
         boolean wasScrolling = mScroller.isScrolling() ||
                 (mScroller.mScrollAnimator != null && mScroller.mScrollAnimator.isRunning());
-        int action = ev.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 // Save the touch down info
@@ -190,11 +202,21 @@
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
         // Short circuit if we have no children
-        boolean hasChildren = (mSv.getChildCount() > 0);
-        if (!hasChildren) {
+        boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
+        if (!hasTaskViews) {
             return false;
         }
 
+        int action = ev.getAction();
+        if (mConfig.multiStackEnabled) {
+            // Check if we are within the bounds of the stack view contents
+            if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
+                if (!mSv.getTouchableRegion().contains((int) ev.getX(), (int) ev.getY())) {
+                    return false;
+                }
+            }
+        }
+
         // Pass through to swipe helper if we are swiping
         if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
             return true;
@@ -203,7 +225,6 @@
         // Update the velocity tracker
         initVelocityTrackerIfNotExists();
 
-        int action = ev.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 // Save the touch down info
@@ -279,7 +300,7 @@
                     float overscrollRangePct = Math.abs((float) velocity / mMaximumVelocity);
                     int overscrollRange = (int) (Math.min(1f, overscrollRangePct) *
                             (Constants.Values.TaskStackView.TaskStackMaxOverscrollRange -
-                            Constants.Values.TaskStackView.TaskStackMinOverscrollRange));
+                                    Constants.Values.TaskStackView.TaskStackMinOverscrollRange));
                     mScroller.mScroller.fling(0,
                             mScroller.progressToScrollRange(mScroller.getStackScroll()),
                             0, velocity,
@@ -378,6 +399,8 @@
         if (parent != null) {
             parent.requestDisallowInterceptTouchEvent(true);
         }
+        // Fade out the dismiss button
+        mSv.hideDismissAllButton(null);
     }
 
     @Override
@@ -403,6 +426,8 @@
         tv.setClipViewInStack(true);
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
+        // Restore the dismiss button
+        mSv.showDismissAllButton();
     }
 
     @Override
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 faa728d..098f2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -45,6 +45,8 @@
         public void onTaskViewDismissed(TaskView tv);
         public void onTaskViewClipStateChanged(TaskView tv);
         public void onTaskViewFocusChanged(TaskView tv, boolean focused);
+
+        public void onMultiStackMoveTask(TaskView tv);
     }
 
     RecentsConfiguration mConfig;
@@ -381,6 +383,11 @@
         ctx.postAnimationTrigger.increment();
     }
 
+    /** Animates this task view away when dismissing all tasks. */
+    void startDismissAllAnimation() {
+        dismissTask();
+    }
+
     /** Animates this task view as it exits recents */
     void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
             boolean occludesLaunchTarget, boolean lockToTask) {
@@ -428,25 +435,22 @@
     }
 
     /** Animates the deletion of this task view */
-    void startDeleteTaskAnimation(final Runnable r) {
+    void startDeleteTaskAnimation(final Runnable r, int delay) {
         // Disabling clipping with the stack while the view is animating away
         setClipViewInStack(false);
 
         animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
             .alpha(0f)
-            .setStartDelay(0)
+            .setStartDelay(delay)
             .setUpdateListener(null)
             .setInterpolator(mConfig.fastOutSlowInInterpolator)
             .setDuration(mConfig.taskViewRemoveAnimDuration)
             .withEndAction(new Runnable() {
                 @Override
                 public void run() {
-                    // 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();
+                    if (r != null) {
+                        r.run();
+                    }
 
                     // Re-enable clipping with the stack (we will reuse this view)
                     setClipViewInStack(true);
@@ -455,6 +459,11 @@
             .start();
     }
 
+    /** Enables/disables handling touch on this task view. */
+    void setTouchEnabled(boolean enabled) {
+        setOnClickListener(enabled ? this : null);
+    }
+
     /** Animates this task view if the user does not interact with the stack after a certain time. */
     void startNoUserInteractionAnimation() {
         mHeaderView.startNoUserInteractionAnimation();
@@ -481,7 +490,7 @@
                     mCb.onTaskViewDismissed(tv);
                 }
             }
-        });
+        }, 0);
     }
 
     /**
@@ -665,6 +674,9 @@
             // Rebind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(this);
             mHeaderView.mDismissButton.setOnClickListener(this);
+            if (mConfig.multiStackEnabled) {
+                mHeaderView.mMoveTaskButton.setOnClickListener(this);
+            }
             mActionButtonView.setOnClickListener(this);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 if (mConfig.developerOptionsEnabled) {
@@ -685,6 +697,9 @@
             // Unbind any listeners
             mHeaderView.mApplicationIcon.setOnClickListener(null);
             mHeaderView.mDismissButton.setOnClickListener(null);
+            if (mConfig.multiStackEnabled) {
+                mHeaderView.mMoveTaskButton.setOnClickListener(null);
+            }
             mActionButtonView.setOnClickListener(null);
             if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
                 mHeaderView.mApplicationIcon.setOnLongClickListener(null);
@@ -693,9 +708,9 @@
         mTaskDataLoaded = false;
     }
 
-    /** Enables/disables handling touch on this task view. */
-    void setTouchEnabled(boolean enabled) {
-        setOnClickListener(enabled ? this : null);
+    @Override
+    public void onMultiStackDebugTaskStackIdChanged() {
+        mHeaderView.rebindToTask(mTask);
     }
 
     /**** View.OnClickListener Implementation ****/
@@ -715,6 +730,10 @@
                         }
                     } else if (v == mHeaderView.mDismissButton) {
                         dismissTask();
+                    } else if (v == mHeaderView.mMoveTaskButton) {
+                        if (mCb != null) {
+                            mCb.onMultiStackMoveTask(tv);
+                        }
                     }
                 }
             }, 125);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 05f6f40..ca08319 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -24,7 +24,6 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
-import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Outline;
@@ -32,12 +31,10 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.widget.FrameLayout;
@@ -56,6 +53,7 @@
     RecentsConfiguration mConfig;
 
     // Header views
+    ImageView mMoveTaskButton;
     ImageView mDismissButton;
     ImageView mApplicationIcon;
     TextView mActivityDescription;
@@ -103,11 +101,10 @@
         });
 
         // Load the dismiss resources
-        Resources res = context.getResources();
-        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
-        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
+        mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
         mDismissContentDescription =
-                res.getString(R.string.accessibility_recents_item_will_be_dismissed);
+                context.getString(R.string.accessibility_recents_item_will_be_dismissed);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
@@ -121,19 +118,15 @@
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        // We ignore taps on the task bar except on the filter and dismiss buttons
-        if (!Constants.DebugFlags.App.EnableTaskBarTouchEvents) return true;
-
-        return super.onTouchEvent(event);
-    }
-
-    @Override
     protected void onFinishInflate() {
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+        mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
+        if (mConfig.multiStackEnabled) {
+            mMoveTaskButton.setVisibility(View.VISIBLE);
+        }
 
         // Hide the backgrounds if they are ripple drawables
         if (!Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -196,12 +189,14 @@
             mApplicationIcon.setImageDrawable(t.applicationIcon);
         }
         mApplicationIcon.setContentDescription(t.activityLabel);
-        if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
+        // Always update when multi stack debugging is enabled as the stack id can change
+        if (mConfig.multiStackEnabled) {
+            mActivityDescription.setText("[" + t.key.stackId + "] " + t.activityLabel);
+        } else if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
             mActivityDescription.setText(t.activityLabel);
         }
         // Try and apply the system ui tint
-        int existingBgColor = (getBackground() instanceof ColorDrawable) ?
-                ((ColorDrawable) getBackground()).getColor() : 0;
+        int existingBgColor = getBackgroundColor();
         if (existingBgColor != t.colorPrimary) {
             mBackgroundColorDrawable.setColor(t.colorPrimary);
             mBackgroundColor = t.colorPrimary;
@@ -284,23 +279,26 @@
         }
 
         if (focused) {
+            int currentColor = mBackgroundColor;
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
+                    new int[] {},
                     new int[] { android.R.attr.state_enabled },
                     new int[] { android.R.attr.state_pressed }
             };
             int[] newStates = new int[]{
+                    0,
                     android.R.attr.state_enabled,
                     android.R.attr.state_pressed
             };
             int[] colors = new int[] {
+                    currentColor,
                     secondaryColor,
                     secondaryColor
             };
             mBackground.setColor(new ColorStateList(states, colors));
             mBackground.setState(newStates);
             // Pulse the background color
-            int currentColor = mBackgroundColor;
             int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
                     currentColor, lightPrimaryColor);
@@ -327,7 +325,7 @@
 
             mFocusAnimator = new AnimatorSet();
             mFocusAnimator.playTogether(backgroundColor, translation);
-            mFocusAnimator.setStartDelay(750);
+            mFocusAnimator.setStartDelay(150);
             mFocusAnimator.setDuration(750);
             mFocusAnimator.start();
         } else {
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 42c0f9f..bba7682 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -21,7 +21,6 @@
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
-import com.android.systemui.recents.Constants;
 
 
 /* The transform state for a task view */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index d9fea47..1b71668 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -341,7 +341,6 @@
 class GlobalScreenshot {
     private static final String TAG = "GlobalScreenshot";
 
-    private static final int SCREENSHOT_NOTIFICATION_ID = 789;
     private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
     private static final int SCREENSHOT_DROP_IN_DURATION = 430;
     private static final int SCREENSHOT_DROP_OUT_DELAY = 500;
@@ -464,7 +463,7 @@
             mSaveInBgTask.cancel(false);
         }
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
-                SCREENSHOT_NOTIFICATION_ID).execute(data);
+                R.id.notification_screenshot).execute(data);
     }
 
     /**
@@ -731,6 +730,6 @@
             new Notification.BigTextStyle(b)
                 .bigText(r.getString(R.string.screenshot_failed_text))
                 .build();
-        nManager.notify(SCREENSHOT_NOTIFICATION_ID, n);
+        nManager.notify(R.id.notification_screenshot, n);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index a1704ff..74267a5 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -17,11 +17,7 @@
 package com.android.systemui.settings;
 
 import android.app.Activity;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.Handler;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.Window;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 465a141..0e5fd94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -94,7 +94,7 @@
             = new PathInterpolator(0, 0, 0.5f, 1);
     private final int mTintedRippleColor;
     private final int mLowPriorityRippleColor;
-    private final int mNormalRippleColor;
+    protected final int mNormalRippleColor;
 
     private boolean mDimmed;
     private boolean mDark;
@@ -115,7 +115,7 @@
     private OnActivatedListener mOnActivatedListener;
 
     private final Interpolator mLinearOutSlowInInterpolator;
-    private final Interpolator mFastOutSlowInInterpolator;
+    protected final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mSlowOutFastInInterpolator;
     private final Interpolator mSlowOutLinearInInterpolator;
     private final Interpolator mLinearInterpolator;
@@ -388,7 +388,7 @@
     }
 
     private void updateBackgroundTint() {
-        int color = getBackgroundColor();
+        int color = getBgColor();
         int rippleColor = getRippleColor();
         if (color == mNormalColor) {
             // We don't need to tint a normal notification
@@ -652,7 +652,7 @@
     }
 
     private void updateAppearAnimationAlpha() {
-        int backgroundColor = getBackgroundColor();
+        int backgroundColor = getBgColor();
         if (backgroundColor != -1) {
             float contentAlphaProgress = mAppearAnimationFraction;
             contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
@@ -666,7 +666,7 @@
         }
     }
 
-    private int getBackgroundColor() {
+    private int getBgColor() {
         if (mBgTint != 0) {
             return mBgTint;
         } else if (mShowingLegacyBackground) {
@@ -678,7 +678,7 @@
         }
     }
 
-    private int getRippleColor() {
+    protected int getRippleColor() {
         if (mBgTint != 0) {
             return mTintedRippleColor;
         } else if (mShowingLegacyBackground) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java
new file mode 100644
index 0000000..87c12c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * A Button which doesn't have overlapping drawing commands
+ */
+public class AlphaOptimizedButton extends Button {
+    public AlphaOptimizedButton(Context context) {
+        super(context);
+    }
+
+    public AlphaOptimizedButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java
index a835c0e..359272e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedFrameLayout.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 
 /**
  * A frame layout which does not have overlapping renderings commands and therefore does not need a
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
index 094161d..858c118 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.View;
 import android.widget.ImageView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8a03a2b..fab7409 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -24,6 +24,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.RemoteInput;
 import android.app.TaskStackBuilder;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -49,6 +50,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -71,7 +73,6 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
-import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
@@ -92,11 +93,14 @@
 import com.android.systemui.SearchPanelView;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.SystemUI;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
 import com.android.systemui.statusbar.policy.PreviewInflater;
+import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
@@ -116,6 +120,11 @@
     // STOPSHIP disable once we resolve b/18102199
     private static final boolean NOTIFICATION_CLICK_DEBUG = true;
 
+    public static final boolean ENABLE_REMOTE_INPUT =
+            Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.enable_remote_input", false);
+    public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
+                    && SystemProperties.getBoolean("debug.child_notifs", false);
+
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
     protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
@@ -127,7 +136,6 @@
     protected static final int MSG_SHOW_HEADS_UP = 1028;
     protected static final int MSG_HIDE_HEADS_UP = 1029;
     protected static final int MSG_ESCALATE_HEADS_UP = 1030;
-    protected static final int MSG_DECAY_HEADS_UP = 1031;
 
     protected static final boolean ENABLE_HEADS_UP = true;
     // scores above this threshold should be displayed in heads up mode.
@@ -137,10 +145,6 @@
     // Should match the value in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
 
-    public static final int EXPANDED_LEAVE_ALONE = -10000;
-    public static final int EXPANDED_FULL_OPEN = -10001;
-
-    private static final int HIDDEN_NOTIFICATION_ID = 10000;
     private static final String BANNER_ACTION_CANCEL =
             "com.android.systemui.statusbar.banner_action_cancel";
     private static final String BANNER_ACTION_SETUP =
@@ -154,6 +158,8 @@
     protected NotificationData mNotificationData;
     protected NotificationStackScrollLayout mStackScroller;
 
+    protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
+
     // for heads up notifications
     protected HeadsUpNotificationView mHeadsUpNotificationView;
     protected int mHeadsUpNotificationDecay;
@@ -387,7 +393,7 @@
             } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
                 NotificationManager noMan = (NotificationManager)
                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-                noMan.cancel(HIDDEN_NOTIFICATION_ID);
+                noMan.cancel(R.id.notification_hidden);
 
                 Settings.Secure.putInt(mContext.getContentResolver(),
                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -414,7 +420,7 @@
                 @Override
                 public void run() {
                     for (StatusBarNotification sbn : notifications) {
-                        addNotification(sbn, currentRanking);
+                        addNotification(sbn, currentRanking, null /* oldEntry */);
                     }
                 }
             });
@@ -424,61 +430,69 @@
         public void onNotificationPosted(final StatusBarNotification sbn,
                 final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    Notification n = sbn.getNotification();
-                    boolean isUpdate = mNotificationData.get(sbn.getKey()) != null
-                            || isHeadsUp(sbn.getKey());
+            if (sbn != null) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        processForRemoteInput(sbn.getNotification());
+                        Notification n = sbn.getNotification();
+                        boolean isUpdate = mNotificationData.get(sbn.getKey()) != null
+                                || isHeadsUp(sbn.getKey());
 
-                    // Ignore children of notifications that have a summary, since we're not
-                    // going to show them anyway. This is true also when the summary is canceled,
-                    // because children are automatically canceled by NoMan in that case.
-                    if (n.isGroupChild() &&
-                            mNotificationData.isGroupWithSummary(sbn.getGroupKey())) {
-                        if (DEBUG) {
-                            Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
+                        // In case we don't allow child notifications, we ignore children of
+                        // notifications that have a summary, since we're not going to show them
+                        // anyway. This is true also when the summary is canceled,
+                        // because children are automatically canceled by NoMan in that case.
+                        if (!ENABLE_CHILD_NOTIFICATIONS
+                            && mGroupManager.isChildInGroupWithSummary(sbn)) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
+                            }
+
+                            // Remove existing notification to avoid stale data.
+                            if (isUpdate) {
+                                removeNotification(sbn.getKey(), rankingMap);
+                            } else {
+                                mNotificationData.updateRanking(rankingMap);
+                            }
+                            return;
                         }
-
-                        // Remove existing notification to avoid stale data.
                         if (isUpdate) {
-                            removeNotification(sbn.getKey(), rankingMap);
+                            updateNotification(sbn, rankingMap);
                         } else {
-                            mNotificationData.updateRanking(rankingMap);
+                            addNotification(sbn, rankingMap, null /* oldEntry */);
                         }
-                        return;
                     }
-                    if (isUpdate) {
-                        updateNotification(sbn, rankingMap);
-                    } else {
-                        addNotification(sbn, rankingMap);
-                    }
-                }
-            });
+                });
+            }
         }
 
         @Override
-        public void onNotificationRemoved(final StatusBarNotification sbn,
+        public void onNotificationRemoved(StatusBarNotification sbn,
                 final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    removeNotification(sbn.getKey(), rankingMap);
-                }
-            });
+            if (sbn != null) {
+                final String key = sbn.getKey();
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        removeNotification(key, rankingMap);
+                    }
+                });
+            }
         }
 
         @Override
         public void onNotificationRankingUpdate(final RankingMap rankingMap) {
             if (DEBUG) Log.d(TAG, "onRankingUpdate");
+            if (rankingMap != null) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     updateNotificationRanking(rankingMap);
                 }
             });
-        }
+        }                            }
 
     };
 
@@ -511,7 +525,6 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mSettingsObserver.onChange(false); // set up
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
                 mSettingsObserver);
@@ -532,7 +545,7 @@
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
-        mRecents = getComponent(RecentsComponent.class);
+        mRecents = getComponent(Recents.class);
         mRecents.setCallback(this);
 
         final Configuration currentConfig = mContext.getResources().getConfiguration();
@@ -561,6 +574,7 @@
 
         createAndAddWindows();
 
+        mSettingsObserver.onChange(false); // set up
         disable(switches[0], false /* animate */);
         setSystemUiVisibility(switches[1], 0xffffffff);
         topAppWindowChanged(switches[2] != 0);
@@ -658,7 +672,7 @@
 
             NotificationManager noMan =
                     (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-            noMan.notify(HIDDEN_NOTIFICATION_ID, note.build());
+            noMan.notify(R.id.notification_hidden, note.build());
         }
     }
 
@@ -698,6 +712,11 @@
         return null;
     }
 
+    @Override
+    public NotificationGroupManager getGroupManager() {
+        return mGroupManager;
+    }
+
     /**
      * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
      * @param action A dismiss action that is called if it's safe to start the activity.
@@ -777,11 +796,7 @@
         }
 
         if (entry.icon != null) {
-            if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP) {
-                entry.icon.setColorFilter(mContext.getResources().getColor(android.R.color.white));
-            } else {
-                entry.icon.setColorFilter(null);
-            }
+            entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
         }
     }
 
@@ -834,16 +849,13 @@
         }, false /* afterKeyguardGone */);
     }
 
-    private void inflateGuts(ExpandableNotificationRow row) {
-        ViewStub stub = (ViewStub) row.findViewById(R.id.notification_guts_stub);
-        if (stub != null) {
-            stub.inflate();
-        }
+    private void bindGuts(ExpandableNotificationRow row) {
+        row.inflateGuts();
         final StatusBarNotification sbn = row.getStatusBarNotification();
         PackageManager pmUser = getPackageManagerForUser(
                 sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
-        final View guts = row.findViewById(R.id.notification_guts);
+        final View guts = row.getGuts();
         final String pkg = sbn.getPackageName();
         String appname = pkg;
         Drawable pkgicon = null;
@@ -921,11 +933,11 @@
                     return false;
                 }
 
-                inflateGuts((ExpandableNotificationRow) v);
+                ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+                bindGuts(row);
 
                 // Assume we are a status_bar_notification_row
-                final NotificationGuts guts = (NotificationGuts) v.findViewById(
-                        R.id.notification_guts);
+                final NotificationGuts guts = row.getGuts();
                 if (guts == null) {
                     // This view has no guts. Examples are the more card or the dismiss all view
                     return false;
@@ -1161,7 +1173,7 @@
         // Do nothing
     }
 
-    public abstract void resetHeadsUpDecayTimer();
+    public abstract void scheduleHeadsUpDecay(long delay);
 
     public abstract void scheduleHeadsUpOpen();
 
@@ -1190,14 +1202,15 @@
         }
 
         if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
-            final boolean allowed = 0 != Settings.Secure.getIntForUser(
+            final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
             final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
                     userHandle);
             final boolean allowedByDpm = (dpmFlags
                     & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
-            mUsersAllowingPrivateNotifications.append(userHandle, allowed && allowedByDpm);
+            final boolean allowed = allowedByUser && allowedByDpm;
+            mUsersAllowingPrivateNotifications.append(userHandle, allowed);
             return allowed;
         }
 
@@ -1285,12 +1298,12 @@
     protected void workAroundBadLayerDrawableOpacity(View v) {
     }
 
-    private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+    protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
             return inflateViews(entry, parent, false);
     }
 
     protected boolean inflateViewsForHeadsUp(NotificationData.Entry entry, ViewGroup parent) {
-            return inflateViews(entry, parent, true);
+        return inflateViews(entry, parent, true);
     }
 
     private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
@@ -1331,6 +1344,7 @@
             hasUserChangedExpansion = row.hasUserChangedExpansion();
             userExpanded = row.isUserExpanded();
             userLocked = row.isUserLocked();
+            entry.row.setHeadsUp(isHeadsUp);
             entry.reset();
             if (hasUserChangedExpansion) {
                 row.setUserExpanded(userExpanded);
@@ -1342,6 +1356,7 @@
             row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
                     parent, false);
             row.setExpansionLogger(this, entry.notification.getKey());
+            row.setGroupManager(mGroupManager);
         }
 
         workAroundBadLayerDrawableOpacity(row);
@@ -1358,11 +1373,13 @@
                 (NotificationContentView) row.findViewById(R.id.expandedPublic);
 
         row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        if (ENABLE_REMOTE_INPUT) {
+            row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        }
 
         PendingIntent contentIntent = sbn.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
-                    isHeadsUp);
+            final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey());
             row.setOnClickListener(listener);
         } else {
             row.setOnClickListener(null);
@@ -1520,23 +1537,114 @@
         }
         row.setUserLocked(userLocked);
         row.setStatusBarNotification(entry.notification);
+        applyRemoteInput(entry);
         return true;
     }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
-            boolean forHun) {
-        return new NotificationClicker(intent, notificationKey, forHun);
+    /**
+     * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
+     * via first-class API.
+     *
+     * TODO: Remove once enough apps specify remote inputs on their own.
+     */
+    private void processForRemoteInput(Notification n) {
+        if (!ENABLE_REMOTE_INPUT) return;
+
+        if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
+                (n.actions == null || n.actions.length == 0)) {
+            Notification.Action viableAction = null;
+            Notification.WearableExtender we = new Notification.WearableExtender(n);
+
+            List<Notification.Action> actions = we.getActions();
+            final int numActions = actions.size();
+
+            for (int i = 0; i < numActions; i++) {
+                Notification.Action action = actions.get(i);
+                RemoteInput[] remoteInputs = action.getRemoteInputs();
+                for (RemoteInput ri : action.getRemoteInputs()) {
+                    if (ri.getAllowFreeFormInput()) {
+                        viableAction = action;
+                        break;
+                    }
+                }
+                if (viableAction != null) {
+                    break;
+                }
+            }
+
+            if (viableAction != null) {
+                Notification stripped = n.clone();
+                Notification.Builder.stripForDelivery(stripped);
+                stripped.actions = new Notification.Action[] { viableAction };
+                stripped.extras.putBoolean("android.rebuild.contentView", true);
+                stripped.contentView = null;
+                stripped.extras.putBoolean("android.rebuild.bigView", true);
+                stripped.bigContentView = null;
+
+                // Don't create the HUN input view for now because input doesn't work there yet.
+                // TODO: Enable once HUNs can take remote input correctly.
+                if (false) {
+                    stripped.extras.putBoolean("android.rebuild.hudView", true);
+                    stripped.headsUpContentView = null;
+                }
+
+                Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
+
+                n.actions = rebuilt.actions;
+                n.bigContentView = rebuilt.bigContentView;
+                n.headsUpContentView = rebuilt.headsUpContentView;
+                n.publicVersion = rebuilt.publicVersion;
+            }
+        }
+    }
+
+    private void applyRemoteInput(final Entry entry) {
+        if (!ENABLE_REMOTE_INPUT) return;
+
+        RemoteInput remoteInput = null;
+
+        // See if the notification has exactly one action and this action allows free-form input
+        // TODO: relax restrictions once we support more than one remote input action.
+        Notification.Action[] actions = entry.notification.getNotification().actions;
+        if (actions != null && actions.length == 1) {
+            if (actions[0].getRemoteInputs() != null) {
+                for (RemoteInput ri : actions[0].getRemoteInputs()) {
+                    if (ri.getAllowFreeFormInput()) {
+                        remoteInput = ri;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // See if we have somewhere to put that remote input
+        ViewGroup actionContainer = null;
+        if (remoteInput != null && entry.expandedBig != null) {
+            View actionContainerCandidate = entry.expandedBig
+                    .findViewById(com.android.internal.R.id.actions);
+            if (actionContainerCandidate instanceof ViewGroup) {
+                actionContainer = (ViewGroup) actionContainerCandidate;
+            }
+        }
+
+        if (actionContainer != null) {
+            actionContainer.removeAllViews();
+            actionContainer.addView(
+                    RemoteInputView.inflate(mContext, actionContainer, actions[0], remoteInput));
+        }
+    }
+
+    public NotificationClicker makeClicker(PendingIntent intent, String notificationKey) {
+        return new NotificationClicker(intent, notificationKey);
     }
 
     protected class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
         private final String mNotificationKey;
-        private boolean mIsHeadsUp;
 
-        public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
+        public NotificationClicker(PendingIntent intent, String notificationKey) {
             mIntent = intent;
             mNotificationKey = notificationKey;
-            mIsHeadsUp = forHun;
         }
 
         public void onClick(final View v) {
@@ -1549,12 +1657,12 @@
                             mCurrentUserId);
             dismissKeyguardThenExecute(new OnDismissAction() {
                 public boolean onDismiss() {
-                    if (mIsHeadsUp) {
+                    if (mNotificationKey.equals(mHeadsUpNotificationView.getKey())) {
                         // Release the HUN notification to the shade.
                         //
                         // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
                         // become canceled shortly by NoMan, but we can't assume that.
-                        mHeadsUpNotificationView.releaseAndClose();
+                        mHeadsUpNotificationView.releaseImmediately();
                     }
                     new Thread() {
                         @Override
@@ -1693,6 +1801,21 @@
         if (DEBUG) {
             Log.d(TAG, "createNotificationViews(notification=" + sbn);
         }
+        final StatusBarIconView iconView = createIcon(sbn);
+        if (iconView == null) {
+            return null;
+        }
+
+        // Construct the expanded view.
+        NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
+        if (!inflateViews(entry, mStackScroller)) {
+            handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
+            return null;
+        }
+        return entry;
+    }
+
+    protected StatusBarIconView createIcon(StatusBarNotification sbn) {
         // Construct the icon.
         Notification n = sbn.getNotification();
         final StatusBarIconView iconView = new StatusBarIconView(mContext,
@@ -1709,13 +1832,7 @@
             handleNotificationError(sbn, "Couldn't create icon: " + ic);
             return null;
         }
-        // Construct the expanded view.
-        NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
-        if (!inflateViews(entry, mStackScroller)) {
-            handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
-            return null;
-        }
-        return entry;
+        return iconView;
     }
 
     protected void addNotificationViews(Entry entry, RankingMap ranking) {
@@ -1755,22 +1872,25 @@
                     entry.row.setSystemExpanded(top);
                 }
             }
+            boolean isInvisibleChild = !mGroupManager.isVisible(entry.notification);
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
             if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
                     (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
-                            || !showOnKeyguard))) {
+                            || !showOnKeyguard || isInvisibleChild))) {
                 entry.row.setVisibility(View.GONE);
-                if (onKeyguard && showOnKeyguard) {
+                if (onKeyguard && showOnKeyguard && !isInvisibleChild) {
                     mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
                 }
             } else {
                 boolean wasGone = entry.row.getVisibility() == View.GONE;
                 entry.row.setVisibility(View.VISIBLE);
-                if (wasGone) {
-                    // notify the scroller of a child addition
-                    mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
+                if (!isInvisibleChild) {
+                    if (wasGone) {
+                        // notify the scroller of a child addition
+                        mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
+                    }
+                    visibleNotifications++;
                 }
-                visibleNotifications++;
             }
         }
 
@@ -1813,15 +1933,12 @@
         setShowLockscreenNotifications(show && allowedByDpm);
     }
 
-    protected abstract void haltTicker();
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotifications();
-    protected abstract void tick(StatusBarNotification n, boolean firstTime);
-    protected abstract void updateExpandedViewPos(int expandedPosition);
     protected abstract boolean shouldDisableNavbarGestures();
 
     public abstract void addNotification(StatusBarNotification notification,
-            RankingMap ranking);
+            RankingMap ranking, Entry oldEntry);
     protected abstract void updateNotificationRanking(RankingMap ranking);
     public abstract void removeNotification(String key, RankingMap ranking);
 
@@ -1902,17 +2019,15 @@
                         && oldPublicContentView.getPackage() != null
                         && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
                         && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
-        boolean updateTicker = n.tickerText != null
-                && !TextUtils.equals(n.tickerText,
-                oldEntry.notification.getNotification().tickerText);
 
         final boolean shouldInterrupt = shouldInterrupt(notification);
-        final boolean alertAgain = alertAgain(oldEntry, n);
+        final boolean alertAgain = shouldInterrupt && alertAgain(oldEntry, n);
         boolean updateSuccessful = false;
         if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
                 && publicUnchanged) {
             if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
             oldEntry.notification = notification;
+            mGroupManager.onEntryUpdated(oldEntry, oldNotification);
             try {
                 if (oldEntry.icon != null) {
                     // Update the icon
@@ -1930,20 +2045,20 @@
                 }
 
                 if (wasHeadsUp) {
-                    if (shouldInterrupt) {
-                        updateHeadsUpViews(oldEntry, notification);
-                        if (alertAgain) {
-                            resetHeadsUpDecayTimer();
-                        }
-                    } else {
+                    // Release may hang on to the views for a bit, so we should always update them.
+                    updateHeadsUpViews(oldEntry, notification);
+                    mHeadsUpNotificationView.updateNotification(oldEntry, alertAgain);
+                    if (!shouldInterrupt) {
                         // we updated the notification above, so release to build a new shade entry
-                        mHeadsUpNotificationView.releaseAndClose();
+                        mHeadsUpNotificationView.release();
                         return;
                     }
                 } else {
                     if (shouldInterrupt && alertAgain) {
+                        mStackScroller.setRemoveAnimationEnabled(false);
                         removeNotificationViews(key, ranking);
-                        addNotification(notification, ranking);  //this will pop the headsup
+                        mStackScroller.setRemoveAnimationEnabled(true);
+                        addNotification(notification, ranking, oldEntry);  //this will pop the headsup
                     } else {
                         updateNotificationViews(oldEntry, notification);
                     }
@@ -1960,33 +2075,32 @@
         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());
-                    }
+                if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
+                ViewGroup holder = mHeadsUpNotificationView.getHolder();
+                if (inflateViewsForHeadsUp(oldEntry, holder)) {
+                    mHeadsUpNotificationView.updateNotification(oldEntry, alertAgain);
                 } else {
+                    Log.w(TAG, "Couldn't create new updated headsup for package "
+                            + contentView.getPackage());
+                }
+                if (!shouldInterrupt) {
                     if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
                     oldEntry.notification = notification;
-                    mHeadsUpNotificationView.releaseAndClose();
+                    mGroupManager.onEntryUpdated(oldEntry, oldNotification);
+                    mHeadsUpNotificationView.release();
                     return;
                 }
             } else {
                 if (shouldInterrupt && alertAgain) {
                     if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key);
+                    mStackScroller.setRemoveAnimationEnabled(false);
                     removeNotificationViews(key, ranking);
-                    addNotification(notification, ranking);  //this will pop the headsup
+                    mStackScroller.setRemoveAnimationEnabled(true);
+                    addNotification(notification, ranking, oldEntry);  //this will pop the headsup
                 } else {
                     if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
                     oldEntry.notification = notification;
+                    mGroupManager.onEntryUpdated(oldEntry, oldNotification);
                     final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
                             notification.getUser(),
                             n.icon,
@@ -2010,15 +2124,8 @@
         boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
         if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
 
-        // Restart the ticker if it's still running
-        if (updateTicker && isForCurrentUser) {
-            haltTicker();
-            tick(notification, false);
-        }
-
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
     private void updateNotificationViews(NotificationData.Entry entry,
@@ -2053,8 +2160,7 @@
         // update the contentIntent
         final PendingIntent contentIntent = notification.getNotification().contentIntent;
         if (contentIntent != null) {
-            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
-                    isHeadsUp);
+            final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey());
             entry.row.setOnClickListener(listener);
         } else {
             entry.row.setOnClickListener(null);
@@ -2062,6 +2168,8 @@
         entry.row.setStatusBarNotification(notification);
         entry.row.notifyContentUpdated();
         entry.row.resetHeight();
+
+        applyRemoteInput(entry);
     }
 
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0b1b883..8f88e73d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.util.Pair;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -57,6 +58,9 @@
     private static final int MSG_NOTIFICATION_LIGHT_OFF     = 16 << MSG_SHIFT;
     private static final int MSG_NOTIFICATION_LIGHT_PULSE   = 17 << MSG_SHIFT;
     private static final int MSG_SHOW_SCREEN_PIN_REQUEST    = 18 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_PENDING     = 19 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_CANCELLED   = 20 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_STARTING    = 21 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -99,6 +103,9 @@
         public void notificationLightOff();
         public void notificationLightPulse(int argb, int onMillis, int offMillis);
         public void showScreenPinningRequest();
+        public void appTransitionPending();
+        public void appTransitionCancelled();
+        public void appTransitionStarting(long startTime, long duration);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -246,6 +253,28 @@
         }
     }
 
+    public void appTransitionPending() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+        }
+    }
+
+    public void appTransitionCancelled() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+        }
+    }
+
+    public void appTransitionStarting(long startTime, long duration) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
+            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
+                    .sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -328,6 +357,16 @@
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
                     mCallbacks.showScreenPinningRequest();
                     break;
+                case MSG_APP_TRANSITION_PENDING:
+                    mCallbacks.appTransitionPending();
+                    break;
+                case MSG_APP_TRANSITION_CANCELLED:
+                    mCallbacks.appTransitionCancelled();
+                    break;
+                case MSG_APP_TRANSITION_STARTING:
+                    Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
+                    mCallbacks.appTransitionStarting(data.first, data.second);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
index f2a5673..00665f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java
@@ -21,12 +21,9 @@
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.view.Choreographer;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRootImpl;
 import android.widget.Button;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index c9f0260..15a092c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -162,20 +162,20 @@
                 ? RUBBERBAND_FACTOR_EXPANDABLE
                 : RUBBERBAND_FACTOR_STATIC;
         float rubberband = heightDelta * rubberbandFactor;
-        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxHeight()) {
-            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxHeight();
+        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxContentHeight()) {
+            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxContentHeight();
             overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
             rubberband -= overshoot;
         }
-        child.setActualHeight((int) (child.getMinHeight() + rubberband));
+        child.setContentHeight((int) (child.getMinHeight() + rubberband));
     }
 
     private void cancelExpansion(final ExpandableView child) {
-        if (child.getActualHeight() == child.getMinHeight()) {
+        if (child.getContentHeight() == child.getMinHeight()) {
             return;
         }
-        ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
-                child.getActualHeight(), child.getMinHeight());
+        ObjectAnimator anim = ObjectAnimator.ofInt(child, "contentHeight",
+                child.getContentHeight(), child.getMinHeight());
         anim.setInterpolator(mInterpolator);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 0825aa3..5db0699 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -20,11 +20,9 @@
 import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.Interpolator;
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 public class EmptyShadeView extends StackScrollerDecorView {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8ad8406..06a174e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,9 +16,13 @@
 
 package com.android.systemui.statusbar;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
@@ -26,12 +30,25 @@
 import android.view.View;
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.LinearInterpolator;
 import android.widget.ImageView;
+
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.stack.StackScrollState;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.statusbar.stack.StackViewState;
+
+import java.util.List;
 
 public class ExpandableNotificationRow extends ActivatableNotificationView {
+
+    private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
+    private static final int COLORED_DIVIDER_ALPHA = 0x7B;
+    private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
     private int mRowMinHeight;
-    private int mRowMaxHeight;
 
     /** Does this row contain layouts that can adapt to row expansion */
     private boolean mExpandable;
@@ -70,6 +87,27 @@
 
     private StatusBarNotification mStatusBarNotification;
     private boolean mIsHeadsUp;
+    private View mExpandButton;
+    private View mExpandButtonDivider;
+    private ViewStub mExpandButtonStub;
+    private ViewStub mChildrenContainerStub;
+    private NotificationGroupManager mGroupManager;
+    private View mExpandButtonContainer;
+    private boolean mChildrenExpanded;
+    private NotificationChildrenContainer mChildrenContainer;
+    private ValueAnimator mChildExpandAnimator;
+    private float mChildrenExpandProgress;
+    private float mExpandButtonStart;
+    private ViewStub mGutsStub;
+    private boolean mHasExpandAction;
+    private boolean mIsSystemChildExpanded;
+    private OnClickListener mExpandClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mGroupManager.setGroupExpanded(mStatusBarNotification,
+                    !mChildrenExpanded);
+        }
+    };
 
     public void setIconAnimationRunning(boolean running) {
         setIconAnimationRunning(running, mPublicLayout);
@@ -119,6 +157,7 @@
     public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
         mStatusBarNotification = statusBarNotification;
         updateVetoButton();
+        updateExpandButton();
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -129,6 +168,101 @@
         mIsHeadsUp = isHeadsUp;
     }
 
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        mGroupManager = groupManager;
+    }
+
+    public void addChildNotification(ExpandableNotificationRow row) {
+        addChildNotification(row, -1);
+    }
+
+    /**
+     * Add a child notification to this view.
+     *
+     * @param row the row to add
+     * @param childIndex the index to add it at, if -1 it will be added at the end
+     */
+    public void addChildNotification(ExpandableNotificationRow row, int childIndex) {
+        if (mChildrenContainer == null) {
+            mChildrenContainerStub.inflate();
+        }
+        mChildrenContainer.addNotification(row, childIndex);
+    }
+
+    public void removeChildNotification(ExpandableNotificationRow row) {
+        if (mChildrenContainer != null) {
+            mChildrenContainer.removeNotification(row);
+        }
+    }
+
+    @Override
+    public boolean areChildrenExpanded() {
+        return mChildrenExpanded;
+    }
+
+    public List<ExpandableNotificationRow> getNotificationChildren() {
+        return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
+    }
+
+    /**
+     * Apply the order given in the list to the children.
+     *
+     * @param childOrder the new list order
+     * @return whether the list order has changed
+     */
+    public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
+        return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder);
+    }
+
+    public void getChildrenStates(StackScrollState resultState) {
+        if (mChildrenExpanded) {
+            StackViewState parentState = resultState.getViewStateForView(this);
+            mChildrenContainer.getState(resultState, parentState);
+        }
+    }
+
+    public void applyChildrenState(StackScrollState state) {
+        if (mChildrenExpanded) {
+            mChildrenContainer.applyState(state);
+        }
+    }
+
+    public void prepareExpansionChanged(StackScrollState state) {
+        if (mChildrenExpanded) {
+            mChildrenContainer.prepareExpansionChanged(state);
+        }
+    }
+
+    public void startChildAnimation(StackScrollState finalState,
+            StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
+        if (mChildrenExpanded) {
+            mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
+                    duration);
+        }
+    }
+
+    public ExpandableNotificationRow getViewAtPosition(float y) {
+        if (!mChildrenExpanded) {
+            return this;
+        } else {
+            ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
+            return view == null ? this : view;
+        }
+    }
+
+    public NotificationGuts getGuts() {
+        return mGuts;
+    }
+
+    protected int calculateContentHeightFromActualHeight(int actualHeight) {
+        int realActualHeight = actualHeight;
+        if (hasBottomDecor()) {
+            realActualHeight -= getBottomDecorHeight();
+        }
+        realActualHeight = Math.max(getMinHeight(), realActualHeight);
+        return realActualHeight;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -145,7 +279,7 @@
         super.reset();
         mRowMinHeight = 0;
         final boolean wasExpanded = isExpanded();
-        mRowMaxHeight = 0;
+        mMaxViewHeight = 0;
         mExpandable = false;
         mHasUserChangedExpansion = false;
         mUserLocked = false;
@@ -180,21 +314,97 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-        ViewStub gutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
-        gutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+        mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
+        mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
             @Override
             public void onInflate(ViewStub stub, View inflated) {
                 mGuts = (NotificationGuts) inflated;
                 mGuts.setClipTopAmount(getClipTopAmount());
                 mGuts.setActualHeight(getActualHeight());
+                mGutsStub = null;
+            }
+        });
+        mExpandButtonStub = (ViewStub) findViewById(R.id.more_button_stub);
+        mExpandButtonStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+
+            @Override
+            public void onInflate(ViewStub stub, View inflated) {
+                mExpandButtonContainer = inflated;
+                mExpandButton = inflated.findViewById(R.id.notification_expand_button);
+                mExpandButtonDivider = inflated.findViewById(R.id.notification_expand_divider);
+                mExpandButtonContainer.setOnClickListener(mExpandClickListener);
+            }
+        });
+        mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
+        mChildrenContainerStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+
+            @Override
+            public void onInflate(ViewStub stub, View inflated) {
+                mChildrenContainer = (NotificationChildrenContainer) inflated;
+                mChildrenContainer.setCollapseClickListener(mExpandClickListener);
+                updateChildrenVisibility(false);
             }
         });
         mVetoButton = findViewById(R.id.veto);
     }
 
+    public void inflateGuts() {
+        if (mGuts == null) {
+            mGutsStub.inflate();
+        }
+    }
+
+    private void updateChildrenVisibility(boolean animated) {
+        if (mChildrenContainer == null) {
+            return;
+        }
+        if (mChildExpandAnimator != null) {
+            mChildExpandAnimator.cancel();
+        }
+        float targetProgress = mChildrenExpanded ? 1.0f : 0.0f;
+        if (animated) {
+            if (mChildrenExpanded) {
+                mChildrenContainer.setVisibility(VISIBLE);
+            }
+            mExpandButtonStart = mExpandButtonContainer.getTranslationY();
+            mChildExpandAnimator = ValueAnimator.ofFloat(mChildrenExpandProgress, targetProgress);
+            mChildExpandAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    setChildrenExpandProgress((float) animation.getAnimatedValue());
+                }
+            });
+            mChildExpandAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mChildExpandAnimator = null;
+                    if (!mChildrenExpanded) {
+                        mChildrenContainer.setVisibility(INVISIBLE);
+                    }
+                }
+            });
+            mChildExpandAnimator.setInterpolator(mLinearInterpolator);
+            mChildExpandAnimator.setDuration(
+                    StackStateAnimator.ANIMATION_DURATION_EXPAND_CLICKED);
+            mChildExpandAnimator.start();
+        } else {
+            setChildrenExpandProgress(targetProgress);
+            mChildrenContainer.setVisibility(mChildrenExpanded ? VISIBLE : INVISIBLE);
+        }
+    }
+
+    private void setChildrenExpandProgress(float progress) {
+        mChildrenExpandProgress = progress;
+        updateExpandButtonAppearance();
+        NotificationContentView showingLayout = getShowingLayout();
+        float alpha = 1.0f - mChildrenExpandProgress;
+        alpha = PhoneStatusBar.ALPHA_OUT.getInterpolation(alpha);
+        showingLayout.setAlpha(alpha);
+    }
+
     @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (super.onRequestSendAccessibilityEvent(child, event)) {
+    public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEventInternal(child, event)) {
             // Add a record for the entire layout since its content is somehow small.
             // The event comes from a leaf view that is interacted with.
             AccessibilityEvent record = AccessibilityEvent.obtain();
@@ -217,7 +427,7 @@
 
     public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
         mRowMinHeight = rowMinHeight;
-        mRowMaxHeight = rowMaxHeight;
+        mMaxViewHeight = rowMaxHeight;
     }
 
     public boolean isExpandable() {
@@ -281,7 +491,7 @@
         if (expand != mIsSystemExpanded) {
             final boolean wasExpanded = isExpanded();
             mIsSystemExpanded = expand;
-            notifyHeightChanged();
+            notifyHeightChanged(false /* needsAnimation */);
             logExpansionEvent(false, wasExpanded);
         }
     }
@@ -295,7 +505,7 @@
             mExpansionDisabled = expansionDisabled;
             logExpansionEvent(false, wasExpanded);
             if (wasExpanded != isExpanded()) {
-                notifyHeightChanged();
+                notifyHeightChanged(false  /* needsAnimation */);
             }
         }
     }
@@ -313,9 +523,9 @@
     public void applyExpansionToLayout() {
         boolean expand = isExpanded();
         if (expand && mExpandable) {
-            setActualHeight(mMaxExpandHeight);
+            setContentHeight(mMaxExpandHeight);
         } else {
-            setActualHeight(mRowMinHeight);
+            setContentHeight(mRowMinHeight);
         }
     }
 
@@ -325,12 +535,26 @@
             return getActualHeight();
         }
         boolean inExpansionState = isExpanded();
-        if (!inExpansionState) {
-            // not expanded, so we return the collapsed size
-            return mRowMinHeight;
+        int maxContentHeight;
+        if ((!inExpansionState && !mChildrenExpanded) || mShowingPublicForIntrinsicHeight) {
+            maxContentHeight = mRowMinHeight;
+        } else if (mChildrenExpanded) {
+            maxContentHeight = mChildrenContainer.getIntrinsicHeight();
+        } else {
+            maxContentHeight = getMaxExpandHeight();
         }
+        return maxContentHeight + getBottomDecorHeight();
+    }
 
-        return mShowingPublicForIntrinsicHeight ? mRowMinHeight : getMaxExpandHeight();
+    @Override
+    protected boolean hasBottomDecor() {
+        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
+                && !mIsHeadsUp && mGroupManager.hasGroupChildren(mStatusBarNotification);
+    }
+
+    @Override
+    protected boolean canHaveBottomDecor() {
+        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && !mIsHeadsUp;
     }
 
     /**
@@ -343,7 +567,16 @@
      */
     private boolean isExpanded() {
         return !mExpansionDisabled
-                && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded());
+                && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
+                || isUserExpanded());
+    }
+
+    private boolean isSystemChildExpanded() {
+        return mIsSystemChildExpanded;
+    }
+
+    public void setSystemChildExpanded(boolean expanded) {
+        mIsSystemChildExpanded = expanded;
     }
 
     @Override
@@ -357,11 +590,20 @@
         mWasReset = false;
     }
 
+    @Override
+    protected boolean isChildInvisible(View child) {
+
+        // We don't want to layout the ChildrenContainer if this is a heads-up view, otherwise the
+        // view will get too high and the shadows will be off.
+        boolean isInvisibleChildContainer = child == mChildrenContainer && mIsHeadsUp;
+        return super.isChildInvisible(child) || isInvisibleChildContainer;
+    }
+
     private void updateMaxExpandHeight() {
         int intrinsicBefore = getIntrinsicHeight();
         mMaxExpandHeight = mPrivateLayout.getMaxHeight();
         if (intrinsicBefore != getIntrinsicHeight()) {
-            notifyHeightChanged();
+            notifyHeightChanged(false  /* needsAnimation */);
         }
     }
 
@@ -428,8 +670,127 @@
         mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
     }
 
+    public void setChildrenExpanded(boolean expanded, boolean animate) {
+        mChildrenExpanded = expanded;
+        updateChildrenVisibility(animate);
+    }
+
+    public void updateExpandButton() {
+        boolean hasExpand = hasBottomDecor();
+        if (hasExpand != mHasExpandAction) {
+            if (hasExpand) {
+                if (mExpandButtonContainer == null) {
+                    mExpandButtonStub.inflate();
+                }
+                mExpandButtonContainer.setVisibility(View.VISIBLE);
+                updateExpandButtonAppearance();
+                updateExpandButtonColor();
+            } else if (mExpandButtonContainer != null) {
+                mExpandButtonContainer.setVisibility(View.GONE);
+            }
+            notifyHeightChanged(true  /* needsAnimation */);
+        }
+        mHasExpandAction = hasExpand;
+    }
+
+    private void updateExpandButtonAppearance() {
+        if (mExpandButtonContainer == null) {
+            return;
+        }
+        float expandButtonAlpha = 0.0f;
+        float expandButtonTranslation = 0.0f;
+        float containerTranslation = 0.0f;
+        int minHeight = getMinHeight();
+        if (!mChildrenExpanded || mChildExpandAnimator != null) {
+            int expandActionHeight = getBottomDecorHeight();
+            int translationY = getActualHeight() - expandActionHeight;
+            if (translationY > minHeight) {
+                containerTranslation = translationY;
+                expandButtonAlpha = 1.0f;
+                expandButtonTranslation = 0.0f;
+            } else {
+                containerTranslation = minHeight;
+                float progress = expandActionHeight != 0
+                        ? (minHeight - translationY) / (float) expandActionHeight
+                        : 1.0f;
+                expandButtonTranslation = -progress * expandActionHeight * 0.7f;
+                float alphaProgress = Math.min(progress / 0.7f, 1.0f);
+                alphaProgress = PhoneStatusBar.ALPHA_OUT.getInterpolation(alphaProgress);
+                expandButtonAlpha = 1.0f - alphaProgress;
+            }
+        }
+        if (mChildExpandAnimator != null || mChildrenExpanded) {
+            expandButtonAlpha = (1.0f - mChildrenExpandProgress)
+                    * expandButtonAlpha;
+            expandButtonTranslation = (1.0f - mChildrenExpandProgress)
+                    * expandButtonTranslation;
+            float newTranslation = -getBottomDecorHeight();
+
+            // We don't want to take the actual height of the view as this is already
+            // interpolated by a custom interpolator leading to a confusing animation. We want
+            // to have a stable end value to interpolate in between
+            float collapsedHeight = !mChildrenExpanded
+                    ? Math.max(StackStateAnimator.getFinalActualHeight(this)
+                            - getBottomDecorHeight(), minHeight)
+                    : mExpandButtonStart;
+            float translationProgress = mFastOutSlowInInterpolator.getInterpolation(
+                    mChildrenExpandProgress);
+            containerTranslation = (1.0f - translationProgress) * collapsedHeight
+                    + translationProgress * newTranslation;
+        }
+        mExpandButton.setAlpha(expandButtonAlpha);
+        mExpandButtonDivider.setAlpha(expandButtonAlpha);
+        mExpandButton.setTranslationY(expandButtonTranslation);
+        mExpandButtonContainer.setTranslationY(containerTranslation);
+        NotificationContentView showingLayout = getShowingLayout();
+        float layoutTranslation =
+                mExpandButtonContainer.getTranslationY() - showingLayout.getContentHeight();
+        layoutTranslation = Math.min(layoutTranslation, 0);
+        if (!mChildrenExpanded && mChildExpandAnimator == null) {
+            // Needed for the DragDownHelper in order not to jump there, as the position
+            // can be negative for a short time.
+            layoutTranslation = 0;
+        }
+        showingLayout.setTranslationY(layoutTranslation);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setTranslationY(
+                    mExpandButtonContainer.getTranslationY() + getBottomDecorHeight());
+        }
+    }
+
+    private void updateExpandButtonColor() {
+        // TODO: This needs some more baking, currently only the divider is colored according to
+        // the tint, but legacy black doesn't work yet perfectly for the button etc.
+        int color = getRippleColor();
+        if (color == mNormalRippleColor) {
+            color = 0;
+        }
+        if (mExpandButtonDivider != null) {
+            applyTint(mExpandButtonDivider, color);
+        }
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setTintColor(color);
+        }
+    }
+
+    public static void applyTint(View v, int color) {
+        int alpha;
+        if (color != 0) {
+            alpha = COLORED_DIVIDER_ALPHA;
+        } else {
+            color = 0xff000000;
+            alpha = DEFAULT_DIVIDER_ALPHA;
+        }
+        if (v.getBackground() instanceof ColorDrawable) {
+            ColorDrawable background = (ColorDrawable) v.getBackground();
+            background.mutate();
+            background.setColor(color);
+            background.setAlpha(alpha);
+        }
+    }
+
     public int getMaxExpandHeight() {
-        return mShowingPublicForIntrinsicHeight ? mRowMinHeight : mMaxExpandHeight;
+        return mMaxExpandHeight;
     }
 
     @Override
@@ -440,17 +801,19 @@
 
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
-        mPrivateLayout.setActualHeight(height);
-        mPublicLayout.setActualHeight(height);
+        super.setActualHeight(height, notifyListeners);
+        int contentHeight = calculateContentHeightFromActualHeight(height);
+        mPrivateLayout.setContentHeight(contentHeight);
+        mPublicLayout.setContentHeight(contentHeight);
         if (mGuts != null) {
             mGuts.setActualHeight(height);
         }
         invalidate();
-        super.setActualHeight(height, notifyListeners);
+        updateExpandButtonAppearance();
     }
 
     @Override
-    public int getMaxHeight() {
+    public int getMaxContentHeight() {
         NotificationContentView showingLayout = getShowingLayout();
         return showingLayout.getMaxHeight();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index ebc663c..7ae0d6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -33,24 +33,32 @@
  */
 public abstract class ExpandableView extends FrameLayout {
 
-    private final int mMaxNotificationHeight;
-
-    private OnHeightChangedListener mOnHeightChangedListener;
+    private final int mBottomDecorHeight;
+    protected OnHeightChangedListener mOnHeightChangedListener;
+    protected int mMaxViewHeight;
     private int mActualHeight;
     protected int mClipTopAmount;
     private boolean mActualHeightInitialized;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
+    private int mClipTopOptimization;
+    private static Rect mClipRect = new Rect();
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mMaxNotificationHeight = getResources().getDimensionPixelSize(
+        mMaxViewHeight = getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
+        mBottomDecorHeight = resolveBottomDecorHeight();
+    }
+
+    protected int resolveBottomDecorHeight() {
+        return getResources().getDimensionPixelSize(
+                R.dimen.notification_bottom_decor_height);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int ownMaxHeight = mMaxNotificationHeight;
+        int ownMaxHeight = mMaxViewHeight;
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
         boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
@@ -63,6 +71,9 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
+            if (child.getVisibility() == GONE || isChildInvisible(child)) {
+                continue;
+            }
             int childHeightSpec = newHeightSpec;
             ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
             if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
@@ -81,7 +92,8 @@
                 mMatchParentViews.add(child);
             }
         }
-        int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight;
+        int ownHeight = hasFixedHeight ? ownMaxHeight :
+                isHeightLimited ? Math.min(ownMaxHeight, maxChildHeight) : maxChildHeight;
         newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
         for (View child : mMatchParentViews) {
             child.measure(getChildMeasureSpec(
@@ -90,6 +102,10 @@
         }
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
+        if (canHaveBottomDecor()) {
+            // We always account for the expandAction as well.
+            ownHeight += mBottomDecorHeight;
+        }
         setMeasuredDimension(width, ownHeight);
     }
 
@@ -99,7 +115,7 @@
         if (!mActualHeightInitialized && mActualHeight == 0) {
             int initialHeight = getInitialHeight();
             if (initialHeight != 0) {
-                setActualHeight(initialHeight);
+                setContentHeight(initialHeight);
             }
         }
     }
@@ -140,13 +156,14 @@
     public void setActualHeight(int actualHeight, boolean notifyListeners) {
         mActualHeightInitialized = true;
         mActualHeight = actualHeight;
+        updateClipping();
         if (notifyListeners) {
-            notifyHeightChanged();
+            notifyHeightChanged(false  /* needsAnimation */);
         }
     }
 
-    public void setActualHeight(int actualHeight) {
-        setActualHeight(actualHeight, true);
+    public void setContentHeight(int contentHeight) {
+        setActualHeight(contentHeight + getBottomDecorHeight(), true);
     }
 
     /**
@@ -159,14 +176,39 @@
     }
 
     /**
+     * This view may have a bottom decor which will be placed below the content. If it has one, this
+     * view will be layouted higher than just the content by {@link #mBottomDecorHeight}.
+     * @return the height of the decor if it currently has one
+     */
+    public int getBottomDecorHeight() {
+        return hasBottomDecor() ? mBottomDecorHeight : 0;
+    }
+
+    /**
+     * @return whether this view may have a bottom decor at all. This will force the view to layout
+     *         itself higher than just it's content
+     */
+    protected boolean canHaveBottomDecor() {
+        return false;
+    }
+
+    /**
+     * @return whether this view has a decor view below it's content. This will make the intrinsic
+     *         height from {@link #getIntrinsicHeight()} higher as well
+     */
+    protected boolean hasBottomDecor() {
+        return false;
+    }
+
+    /**
      * @return The maximum height of this notification.
      */
-    public int getMaxHeight() {
+    public int getMaxContentHeight() {
         return getHeight();
     }
 
     /**
-     * @return The minimum height of this notification.
+     * @return The minimum content height of this notification.
      */
     public int getMinHeight() {
         return getHeight();
@@ -245,9 +287,9 @@
         return false;
     }
 
-    public void notifyHeightChanged() {
+    public void notifyHeightChanged(boolean needsAnimation) {
         if (mOnHeightChangedListener != null) {
-            mOnHeightChangedListener.onHeightChanged(this);
+            mOnHeightChangedListener.onHeightChanged(this, needsAnimation);
         }
     }
 
@@ -298,6 +340,41 @@
         outRect.top += getTranslationY() + getClipTopAmount();
     }
 
+    public int getContentHeight() {
+        return mActualHeight - getBottomDecorHeight();
+    }
+
+    /**
+     * @return whether the given child can be ignored for layouting and measuring purposes
+     */
+    protected boolean isChildInvisible(View child) {
+        return false;
+    }
+
+    public boolean areChildrenExpanded() {
+        return false;
+    }
+
+    private void updateClipping() {
+        mClipRect.set(0, mClipTopOptimization, getWidth(), getActualHeight());
+        setClipBounds(mClipRect);
+    }
+
+    public int getClipTopOptimization() {
+        return mClipTopOptimization;
+    }
+
+    /**
+     * Set that the view will be clipped by a given amount from the top. Contrary to
+     * {@link #setClipTopAmount} this amount doesn't effect shadows and the background.
+     *
+     * @param clipTopOptimization the amount to clip from the top
+     */
+    public void setClipTopOptimization(int clipTopOptimization) {
+        mClipTopOptimization = clipTopOptimization;
+        updateClipping();
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
@@ -306,8 +383,9 @@
         /**
          * @param view the view for which the height changed, or {@code null} if just the top
          *             padding or the padding between the elements changed
+         * @param needsAnimation whether the view height needs to be animated
          */
-        void onHeightChanged(ExpandableView view);
+        void onHeightChanged(ExpandableView view, boolean needsAnimation);
 
         /**
          * Called when the view is reset and therefore the height will change abruptly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 9f0f84e..0fa088b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar;
 
 import android.animation.Animator;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.AnimationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 0fc46e9..01aa8d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -44,7 +44,7 @@
     }
 
     private void draw(Canvas canvas, Drawable drawable) {
-        if (drawable != null) {
+        if (drawable != null && mActualHeight > mClipTopAmount) {
             drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
             drawable.draw(canvas);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 914b3d8..745e75d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,21 +17,16 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import com.android.systemui.R;
 
 /**
@@ -52,7 +47,7 @@
 
     private int mSmallHeight;
     private int mClipTopAmount;
-    private int mActualHeight;
+    private int mContentHeight;
 
     private final Interpolator mLinearInterpolator = new LinearInterpolator();
 
@@ -102,7 +97,7 @@
         mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         mContractedVisible = true;
         if (resetActualHeight) {
-            mActualHeight = mSmallHeight;
+            mContentHeight = mSmallHeight;
         }
     }
 
@@ -159,12 +154,17 @@
         }
     }
 
-    public void setActualHeight(int actualHeight) {
-        mActualHeight = actualHeight;
+    public void setContentHeight(int contentHeight) {
+        contentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
+        mContentHeight = contentHeight;
         selectLayout(mAnimate /* animate */, false /* force */);
         updateClipping();
     }
 
+    public int getContentHeight() {
+        return mContentHeight;
+    }
+
     public int getMaxHeight() {
 
         // The maximum height is just the laid out height.
@@ -181,7 +181,7 @@
     }
 
     private void updateClipping() {
-        mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight);
+        mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
         setClipBounds(mClipBounds);
     }
 
@@ -240,7 +240,7 @@
     }
 
     private boolean showContractedChild() {
-        return mActualHeight <= mSmallHeight || mExpandedChild == null;
+        return mContentHeight <= mSmallHeight || mExpandedChild == null;
     }
 
     public void notifyContentUpdated() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 34c458a..912f414 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -22,9 +22,10 @@
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.view.View;
 
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -91,10 +92,12 @@
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
     private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
-    private ArraySet<String> mGroupsWithSummaries = new ArraySet<>();
+
+    private NotificationGroupManager mGroupManager;
 
     private RankingMap mRankingMap;
     private final Ranking mTmpRanking = new Ranking();
+
     private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
         private final Ranking mRankingA = new Ranking();
         private final Ranking mRankingB = new Ranking();
@@ -141,6 +144,7 @@
 
     public NotificationData(Environment environment) {
         mEnvironment = environment;
+        mGroupManager = environment.getGroupManager();
     }
 
     /**
@@ -163,12 +167,14 @@
     public void add(Entry entry, RankingMap ranking) {
         mEntries.put(entry.notification.getKey(), entry);
         updateRankingAndSort(ranking);
+        mGroupManager.onEntryAdded(entry);
     }
 
     public Entry remove(String key, RankingMap ranking) {
         Entry removed = mEntries.remove(key);
         if (removed == null) return null;
         updateRankingAndSort(ranking);
+        mGroupManager.onEntryRemoved(removed);
         return removed;
     }
 
@@ -203,7 +209,6 @@
     // anything changed, and this class should call back the UI so it updates itself.
     public void filterAndSort() {
         mSortedAndFiltered.clear();
-        mGroupsWithSummaries.clear();
 
         final int N = mEntries.size();
         for (int i = 0; i < N; i++) {
@@ -214,32 +219,12 @@
                 continue;
             }
 
-            if (sbn.getNotification().isGroupSummary()) {
-                mGroupsWithSummaries.add(sbn.getGroupKey());
-            }
             mSortedAndFiltered.add(entry);
         }
 
-        // Second pass: Filter out group children with summary.
-        if (!mGroupsWithSummaries.isEmpty()) {
-            final int M = mSortedAndFiltered.size();
-            for (int i = M - 1; i >= 0; i--) {
-                Entry ent = mSortedAndFiltered.get(i);
-                StatusBarNotification sbn = ent.notification;
-                if (sbn.getNotification().isGroupChild() &&
-                        mGroupsWithSummaries.contains(sbn.getGroupKey())) {
-                    mSortedAndFiltered.remove(i);
-                }
-            }
-        }
-
         Collections.sort(mSortedAndFiltered, mRankingComparator);
     }
 
-    public boolean isGroupWithSummary(String groupKey) {
-        return mGroupsWithSummaries.contains(groupKey);
-    }
-
     boolean shouldFilterOut(StatusBarNotification sbn) {
         if (!(mEnvironment.isDeviceProvisioned() ||
                 showNotificationEvenIfUnprovisioned(sbn))) {
@@ -254,6 +239,11 @@
                 mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
             return true;
         }
+
+        if (!BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
+                && mGroupManager.isChildInGroupWithSummary(sbn)) {
+            return true;
+        }
         return false;
     }
 
@@ -328,5 +318,6 @@
         public boolean isDeviceProvisioned();
         public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
         public String getCurrentMediaNotificationKey();
+        public NotificationGroupManager getGroupManager();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index bfa3aa5..5fa7070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -62,4 +62,13 @@
     public NotificationOverflowIconsView getIconsView() {
         return mIconsView;
     }
+
+    protected int getContentHeightFromActualHeight(int actualHeight) {
+        int realActualHeight = actualHeight;
+        if (hasBottomDecor()) {
+            realActualHeight -= getBottomDecorHeight();
+        }
+        realActualHeight = Math.max(getMinHeight(), realActualHeight);
+        return realActualHeight;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index c4c9dac..da8ef3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -18,7 +18,6 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.PorterDuff;
 import android.util.AttributeSet;
 import android.widget.ImageView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 78b9739..44e8b85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -19,8 +19,6 @@
 import android.content.Context;
 import android.view.View;
 
-import com.android.internal.R;
-
 /**
  * Wraps the actual notification content view; used to implement behaviors which are different for
  * the individual templates and custom views.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
index aea9ec6..602989a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
@@ -177,6 +177,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
@@ -196,13 +197,14 @@
                 + " extras=" + bundleToString(intent.getExtras()));
         if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
             mHandler.sendEmptyMessage(MSG_START_SERVICE);
-        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
-            PackageManager pm = mContext.getPackageManager();
-            boolean serviceEnabled =
-                    pm.getApplicationEnabledSetting(mServiceName.getPackageName())
-                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+                || Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+            final PackageManager pm = mContext.getPackageManager();
+            final boolean serviceEnabled = isPackageAvailable()
+                    && pm.getApplicationEnabledSetting(mServiceName.getPackageName())
+                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                     && pm.getComponentEnabledSetting(mServiceName)
-                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
             if (mBound && !serviceEnabled) {
                 stopService();
                 scheduleCheckBound();
@@ -279,4 +281,25 @@
         }
         return sb.append('}').toString();
     }
+
+    public ComponentName getComponent() {
+        return getComponentNameFromSetting();
+    }
+
+    public void setComponent(ComponentName component) {
+        final String setting = component == null ? null : component.flattenToShortString();
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                mSettingKey, setting, UserHandle.USER_CURRENT);
+    }
+
+    public boolean isPackageAvailable() {
+        final ComponentName component = getComponent();
+        if (component == null) return false;
+        try {
+            return mContext.getPackageManager().isPackageAvailable(component.getPackageName());
+        } catch (RuntimeException e) {
+            Log.w(mTag, "Error checking package availability", e);
+            return false;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 8e35ee99..7286907 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -17,6 +17,9 @@
 package com.android.systemui.statusbar;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.telephony.SubscriptionInfo;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -55,6 +58,7 @@
     private int mAirplaneContentDescription;
     private String mWifiDescription;
     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
+    private int mIconTint = Color.WHITE;
 
     ViewGroup mWifiGroup;
     ImageView mVpn, mWifi, mAirplane, mNoSims;
@@ -121,6 +125,7 @@
         }
 
         apply();
+        applyIconTint();
     }
 
     @Override
@@ -187,6 +192,9 @@
         for (int i = 0; i < n; i++) {
             inflatePhoneState(subs.get(i).getSubscriptionId());
         }
+        if (isAttachedToWindow()) {
+            applyIconTint();
+        }
     }
 
     private PhoneState getOrInflateState(int subId) {
@@ -217,7 +225,7 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         // Standard group layout onPopulateAccessibilityEvent() implementations
         // ignore content description, so populate manually
         if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
@@ -225,7 +233,7 @@
         for (PhoneState state : mPhoneStates) {
             state.populateAccessibilityEvent(event);
         }
-        return super.dispatchPopulateAccessibilityEvent(event);
+        return super.dispatchPopulateAccessibilityEventInternal(event);
     }
 
     @Override
@@ -315,6 +323,29 @@
         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
     }
 
+    public void setIconTint(int tint) {
+        boolean changed = tint != mIconTint;
+        mIconTint = tint;
+        if (changed && isAttachedToWindow()) {
+            applyIconTint();
+        }
+    }
+
+    private void applyIconTint() {
+        setTint(mVpn, mIconTint);
+        setTint(mWifi, mIconTint);
+        setTint(mNoSims, mIconTint);
+        setTint(mAirplane, mIconTint);
+        for (int i = 0; i < mPhoneStates.size(); i++) {
+            mPhoneStates.get(i).setIconTint(mIconTint);
+        }
+    }
+
+    private void setTint(ImageView v, int tint) {
+        v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
+        v.setImageTintList(ColorStateList.valueOf(tint));
+    }
+
     private class PhoneState {
         private final int mSubId;
         private boolean mMobileVisible = false;
@@ -369,6 +400,11 @@
                 event.getText().add(mMobileGroup.getContentDescription());
             }
         }
+
+        public void setIconTint(int tint) {
+            setTint(mMobile, tint);
+            setTint(mMobileType, tint);
+        }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 20dd3e7..d02cd17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -147,6 +147,9 @@
     }
 
     private boolean updateDrawable(boolean withClear) {
+        if (mIcon == null) {
+            return false;
+        }
         Drawable drawable = getIcon(mIcon);
         if (drawable == null) {
             Log.w(TAG, "No icon for slot " + mSlot);
@@ -226,6 +229,12 @@
     }
 
     @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        updateDrawable();
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index e89e15d..2d76645 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -160,7 +160,7 @@
         }
 
         @Override
-        public void setColorFilter(ColorFilter cf) {
+        public void setColorFilter(ColorFilter colorFilter) {
             // noop
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 6cb5bcc..44168bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -90,24 +90,12 @@
                         : 0;
                 updateSlot("alarm_clock", null, iconId);
             }
-            String sync = args.getString("sync");
-            if (sync != null) {
-                int iconId = sync.equals("show") ? R.drawable.stat_sys_sync
-                        : 0;
-                updateSlot("sync_active", null, iconId);
-            }
             String tty = args.getString("tty");
             if (tty != null) {
                 int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode
                         : 0;
                 updateSlot("tty", null, iconId);
             }
-            String eri = args.getString("eri");
-            if (eri != null) {
-                int iconId = eri.equals("show") ? R.drawable.stat_sys_roaming_cdma_0
-                        : 0;
-                updateSlot("cdma_eri", null, iconId);
-            }
             String mute = args.getString("mute");
             if (mute != null) {
                 int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index d0fe32e..262d955 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -25,10 +25,9 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardViewBase;
+import com.android.keyguard.KeyguardHostView;
 import com.android.keyguard.R;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -43,7 +42,7 @@
     private LockPatternUtils mLockPatternUtils;
     private ViewGroup mContainer;
     private StatusBarWindowManager mWindowManager;
-    private KeyguardViewBase mKeyguardView;
+    private KeyguardHostView mKeyguardView;
     private ViewGroup mRoot;
     private boolean mShowingSoon;
     private Choreographer mChoreographer = Choreographer.getInstance();
@@ -140,16 +139,6 @@
         }
     }
 
-    public long getUserActivityTimeout() {
-        if (mKeyguardView != null) {
-            long timeout = mKeyguardView.getUserActivityTimeout();
-            if (timeout >= 0) {
-                return timeout;
-            }
-        }
-        return KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
-    }
-
     public boolean isShowing() {
         return mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE);
     }
@@ -171,7 +160,7 @@
     private void inflateView() {
         removeView();
         mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
-        mKeyguardView = (KeyguardViewBase) mRoot.findViewById(R.id.keyguard_host_view);
+        mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
         mKeyguardView.setLockPatternUtils(mLockPatternUtils);
         mKeyguardView.setViewMediatorCallback(mCallback);
         mContainer.addView(mRoot, mContainer.getChildCount());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java
index 7579039..076e5f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPreviewContainer.java
@@ -20,7 +20,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.WindowInsets;
@@ -47,7 +46,7 @@
         }
 
         @Override
-        public void setColorFilter(ColorFilter cf) {
+        public void setColorFilter(ColorFilter colorFilter) {
             // noop
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 40c9134..13b3898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.animation.LayoutTransition;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 7ec84da..a712d29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -26,12 +26,9 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 
 public final class NavigationBarTransitions extends BarTransitions {
 
-    private static final int CONTENT_FADE_DURATION = 200;
-
     private final NavigationBarView mView;
     private final IStatusBarService mBarService;
 
@@ -78,48 +75,11 @@
     }
 
     private void applyMode(int mode, boolean animate, boolean force) {
-        // apply to key buttons
-        final float alpha = alphaForMode(mode);
-        setKeyButtonViewQuiescentAlpha(mView.getHomeButton(), alpha, animate);
-        setKeyButtonViewQuiescentAlpha(mView.getRecentsButton(), alpha, animate);
-        setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
-        setKeyButtonViewQuiescentAlpha(mView.getImeSwitchButton(), alpha, animate);
-
-        applyBackButtonQuiescentAlpha(mode, animate);
 
         // apply to lights out
         applyLightsOut(isLightsOut(mode), animate, force);
     }
 
-    private float alphaForMode(int mode) {
-        final boolean isOpaque = mode == MODE_OPAQUE || mode == MODE_LIGHTS_OUT;
-        return isOpaque ? KeyButtonView.DEFAULT_QUIESCENT_ALPHA : 1f;
-    }
-
-    public void applyBackButtonQuiescentAlpha(int mode, boolean animate) {
-        float backAlpha = 0;
-        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton());
-        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton());
-        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton());
-        backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getImeSwitchButton());
-        if (backAlpha > 0) {
-            setKeyButtonViewQuiescentAlpha(mView.getBackButton(), backAlpha, animate);
-        }
-    }
-
-    private static float maxVisibleQuiescentAlpha(float max, View v) {
-        if ((v instanceof KeyButtonView) && v.isShown()) {
-            return Math.max(max, ((KeyButtonView)v).getQuiescentAlpha());
-        }
-        return max;
-    }
-
-    private void setKeyButtonViewQuiescentAlpha(View button, float alpha, boolean animate) {
-        if (button instanceof KeyButtonView) {
-            ((KeyButtonView) button).setQuiescentAlpha(alpha, animate);
-        }
-    }
-
     private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
         if (!force && lightsOut == mLightsOut) return;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 1e4dfb4..12ff399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -50,8 +50,6 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.DelegateViewHelper;
 import com.android.systemui.statusbar.policy.DeadZone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -369,8 +367,6 @@
         getBackButton()   .setVisibility(disableBack       ? View.INVISIBLE : View.VISIBLE);
         getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
-
-        mBarTransitions.applyBackButtonQuiescentAlpha(mBarTransitions.getMode(), true /*animate*/);
     }
 
     private boolean inLockTask() {
@@ -662,10 +658,6 @@
                     + " " + visibilityToString(button.getVisibility())
                     + " alpha=" + button.getAlpha()
                     );
-            if (button instanceof KeyButtonView) {
-                pw.print(" drawingAlpha=" + ((KeyButtonView)button).getDrawingAlpha());
-                pw.print(" quiescentAlpha=" + ((KeyButtonView)button).getQuiescentAlpha());
-            }
         }
         pw.println();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
new file mode 100644
index 0000000..7072dcb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.app.Notification;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.StatusBarState;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class to handle notifications and their corresponding groups.
+ */
+public class NotificationGroupManager {
+
+    private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
+    private OnGroupChangeListener mListener;
+    private int mBarState = -1;
+
+    public void setOnGroupChangeListener(OnGroupChangeListener listener) {
+        mListener = listener;
+    }
+
+    public boolean isGroupExpanded(StatusBarNotification sbn) {
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null) {
+            return false;
+        }
+        return group.expanded;
+    }
+
+    public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null) {
+            return;
+        }
+        setGroupExpanded(group, expanded);
+    }
+
+    private void setGroupExpanded(NotificationGroup group, boolean expanded) {
+        group.expanded = expanded;
+        if (group.summary != null) {
+            mListener.onGroupExpansionChanged(group.summary.row, expanded);
+        }
+    }
+
+    public void onEntryRemoved(NotificationData.Entry removed) {
+        onEntryRemovedInternal(removed, removed.notification);
+    }
+
+    /**
+     * An entry was removed.
+     *
+     * @param removed the removed entry
+     * @param sbn the notification the entry has, which doesn't need to be the same as it's internal
+     *            notification
+     */
+    private void onEntryRemovedInternal(NotificationData.Entry removed,
+            final StatusBarNotification sbn) {
+        Notification notif = sbn.getNotification();
+        String groupKey = sbn.getGroupKey();
+        final NotificationGroup group = mGroupMap.get(groupKey);
+        if (notif.isGroupSummary()) {
+            group.summary = null;
+        } else {
+            group.children.remove(removed);
+        }
+        if (group.children.isEmpty()) {
+            if (group.summary == null) {
+                mGroupMap.remove(groupKey);
+            } else {
+                if (group.expanded) {
+                    // only the summary is left. Change it to unexpanded in a few ms. We do this to
+                    // avoid raceconditions
+                    removed.row.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (group.children.isEmpty()) {
+                                setGroupExpanded(sbn, false);
+                            }
+                        }
+                    });
+                } else {
+                    group.summary.row.updateExpandButton();
+                }
+            }
+        }
+    }
+
+    public void onEntryAdded(NotificationData.Entry added) {
+        StatusBarNotification sbn = added.notification;
+        Notification notif = sbn.getNotification();
+        String groupKey = sbn.getGroupKey();
+        NotificationGroup group = mGroupMap.get(groupKey);
+        if (group == null) {
+            group = new NotificationGroup();
+            mGroupMap.put(groupKey, group);
+        }
+        if (notif.isGroupSummary()) {
+            group.summary = added;
+            group.expanded = added.row.areChildrenExpanded();
+            if (!group.children.isEmpty()) {
+                mListener.onGroupCreatedFromChildren(group);
+            }
+        } else {
+            group.children.add(added);
+            if (group.summary != null && group.children.size() == 1 && !group.expanded) {
+                group.summary.row.updateExpandButton();
+            }
+        }
+    }
+
+    public void onEntryUpdated(NotificationData.Entry entry,
+            StatusBarNotification oldNotification) {
+        if (mGroupMap.get(oldNotification.getGroupKey()) != null) {
+            onEntryRemovedInternal(entry, oldNotification);
+        }
+        onEntryAdded(entry);
+    }
+
+    public boolean isVisible(StatusBarNotification sbn) {
+        if (!sbn.getNotification().isGroupChild()) {
+            return true;
+        }
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group != null && group.expanded) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean hasGroupChildren(StatusBarNotification sbn) {
+        if (areGroupsProhibited()) {
+            return false;
+        }
+        if (!sbn.getNotification().isGroupSummary()) {
+            return false;
+        }
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null) {
+            return false;
+        }
+        return !group.children.isEmpty();
+    }
+
+    public void setStatusBarState(int newState) {
+        if (mBarState == newState) {
+            return;
+        }
+        boolean prohibitedBefore = areGroupsProhibited();
+        mBarState = newState;
+        boolean nowProhibited = areGroupsProhibited();
+        if (nowProhibited != prohibitedBefore) {
+            if (nowProhibited) {
+                for (NotificationGroup group : mGroupMap.values()) {
+                    if (group.expanded) {
+                        setGroupExpanded(group, false);
+                    }
+                }
+            }
+            mListener.onGroupsProhibitedChanged();
+        }
+    }
+
+    private boolean areGroupsProhibited() {
+        return mBarState == StatusBarState.KEYGUARD;
+    }
+
+    /**
+     * @return whether a given notification is a child in a group which has a summary
+     */
+    public boolean isChildInGroupWithSummary(StatusBarNotification sbn) {
+        if (!sbn.getNotification().isGroupChild()) {
+            return false;
+        }
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null || group.summary == null) {
+            return false;
+        }
+        return true;
+    }
+
+    public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        return group == null ? null
+                : group.summary == null ? null
+                : group.summary.row;
+    }
+
+    public static class NotificationGroup {
+        public final HashSet<NotificationData.Entry> children = new HashSet<>();
+        public NotificationData.Entry summary;
+        public boolean expanded;
+    }
+
+    public interface OnGroupChangeListener {
+        /**
+         * The expansion of a group has changed.
+         *
+         * @param changedRow the row for which the expansion has changed, which is also the summary
+         * @param expanded a boolean indicating the new expanded state
+         */
+        void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded);
+
+        /**
+         * Children group policy has changed and children may no be prohibited or allowed.
+         */
+        void onGroupsProhibitedChanged();
+
+        /**
+         * A group of children just received a summary notification and should therefore become
+         * children of it.
+         *
+         * @param group the group created
+         */
+        void onGroupCreatedFromChildren(NotificationGroup group);
+    }
+}
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 0ae34bb..195da46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -112,6 +112,7 @@
     private boolean mQsFullyExpanded;
     private boolean mKeyguardShowing;
     private boolean mDozing;
+    private boolean mDozingOnDown;
     private int mStatusBarState;
     private float mInitialHeightOnTouch;
     private float mInitialTouchX;
@@ -163,7 +164,7 @@
     private Runnable mLaunchAnimationEndRunnable;
     private boolean mOnlyAffordanceInThisMotion;
     private boolean mKeyguardStatusViewAnimating;
-    private boolean mHeaderAnimatingIn;
+    private boolean mHeaderAnimating;
     private ObjectAnimator mQsContainerAnimator;
     private ValueAnimator mQsSizeChangeAnimator;
 
@@ -222,9 +223,8 @@
         // recompute internal state when qspanel height changes
         mQsContainer.addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
-            public void onLayoutChange(View v, int left, int top, int right,
-                    int bottom, int oldLeft, int oldTop, int oldRight,
-                    int oldBottom) {
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 final int height = bottom - top;
                 final int oldHeight = oldBottom - oldTop;
                 if (height != oldHeight) {
@@ -493,14 +493,14 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
             event.getText().add(getKeyguardOrLockScreenString());
             mLastAnnouncementWasQuickSettings = false;
             return true;
         }
 
-        return super.dispatchPopulateAccessibilityEvent(event);
+        return super.dispatchPopulateAccessibilityEventInternal(event);
     }
 
     @Override
@@ -508,7 +508,7 @@
         if (mBlockTouches) {
             return false;
         }
-        resetDownStates(event);
+        initDownStates(event);
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
             pointerIndex = 0;
@@ -594,10 +594,11 @@
                 && x < stackScrollerX + mNotificationStackScroller.getWidth();
     }
 
-    private void resetDownStates(MotionEvent event) {
+    private void initDownStates(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             mOnlyAffordanceInThisMotion = false;
             mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
+            mDozingOnDown = isDozing();
         }
     }
 
@@ -642,7 +643,7 @@
         if (mBlockTouches) {
             return false;
         }
-        resetDownStates(event);
+        initDownStates(event);
         if ((!mIsExpanding || mHintAnimationRunning)
                 && !mQsExpanded
                 && mStatusBar.getBarState() != StatusBarState.SHADE) {
@@ -873,26 +874,28 @@
 
     public void setBarState(int statusBarState, boolean keyguardFadingAway,
             boolean goingToFullShade) {
-        boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD
-                || statusBarState == StatusBarState.SHADE_LOCKED;
-        if (!mKeyguardShowing && keyguardShowing) {
-            setQsTranslation(mQsExpansionHeight);
-            mHeader.setTranslationY(0f);
-        }
+        int oldState = mStatusBarState;
+        boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD;
         setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
         setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
-        if (goingToFullShade) {
+
+        mStatusBarState = statusBarState;
+        mKeyguardShowing = keyguardShowing;
+
+        if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
+                && statusBarState == StatusBarState.SHADE_LOCKED)) {
             animateKeyguardStatusBarOut();
+            animateHeaderSlidingIn();
+        } else if (oldState == StatusBarState.SHADE_LOCKED
+                && statusBarState == StatusBarState.KEYGUARD) {
+            animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            animateHeaderSlidingOut();
         } else {
             mKeyguardStatusBar.setAlpha(1f);
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
         }
-        mStatusBarState = statusBarState;
-        mKeyguardShowing = keyguardShowing;
+
         updateQsState();
-        if (goingToFullShade) {
-            animateHeaderSlidingIn();
-        }
     }
 
     private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
@@ -914,7 +917,7 @@
             = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mHeaderAnimatingIn = false;
+            mHeaderAnimating = false;
             mQsContainerAnimator = null;
             mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
         }
@@ -942,10 +945,13 @@
         @Override
         public boolean onPreDraw() {
             getViewTreeObserver().removeOnPreDrawListener(this);
+            long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+                    ? 0
+                    : mStatusBar.calculateGoingToFullShadeDelay();
             mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
             mHeader.animate()
                     .translationY(0f)
-                    .setStartDelay(mStatusBar.calculateGoingToFullShadeDelay())
+                    .setStartDelay(delay)
                     .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
                     .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
@@ -954,7 +960,7 @@
                     mQsContainer.getTranslationY(),
                     mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
                             - mQsContainer.getTop());
-            mQsContainerAnimator.setStartDelay(mStatusBar.calculateGoingToFullShadeDelay());
+            mQsContainerAnimator.setStartDelay(delay);
             mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
             mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
             mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
@@ -963,11 +969,33 @@
             return true;
         }
     };
-    
-    private void animateHeaderSlidingIn() {
-        mHeaderAnimatingIn = true;
-        getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
 
+    private void animateHeaderSlidingIn() {
+        mHeaderAnimating = true;
+        getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+    }
+
+    private void animateHeaderSlidingOut() {
+        mHeaderAnimating = true;
+        mHeader.animate().y(-mHeader.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mHeader.animate().setListener(null);
+                        mHeaderAnimating = false;
+                        updateQsState();
+                    }
+                })
+                .start();
+        mQsContainer.animate()
+                .y(-mQsContainer.getHeight())
+                .setStartDelay(0)
+                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .start();
     }
 
     private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@@ -982,8 +1010,12 @@
     private void animateKeyguardStatusBarOut() {
         mKeyguardStatusBar.animate()
                 .alpha(0f)
-                .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
-                .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
+                .setStartDelay(mStatusBar.isKeyguardFadingAway()
+                        ? mStatusBar.getKeyguardFadingAwayDelay()
+                        : 0)
+                .setDuration(mStatusBar.isKeyguardFadingAway()
+                        ? mStatusBar.getKeyguardFadingAwayDuration() / 2
+                        : StackStateAnimator.ANIMATION_DURATION_STANDARD)
                 .setInterpolator(PhoneStatusBar.ALPHA_OUT)
                 .setUpdateListener(mStatusBarAnimateAlphaListener)
                 .withEndAction(mAnimateKeyguardStatusBarInvisibleEndRunnable)
@@ -998,13 +1030,13 @@
         }
     };
 
-    private void animateKeyguardStatusBarIn() {
+    private void animateKeyguardStatusBarIn(long duration) {
         mKeyguardStatusBar.setVisibility(View.VISIBLE);
         mKeyguardStatusBar.setAlpha(0f);
         mKeyguardStatusBar.animate()
                 .alpha(1f)
                 .setStartDelay(0)
-                .setDuration(DOZE_ANIMATION_DURATION)
+                .setDuration(duration)
                 .setInterpolator(mDozeAnimationInterpolator)
                 .setUpdateListener(mStatusBarAnimateAlphaListener)
                 .start();
@@ -1084,9 +1116,12 @@
     }
 
     private void updateQsState() {
-        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling;
-        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing) ? View.VISIBLE : View.INVISIBLE);
-        mHeader.setExpanded(mKeyguardShowing || (mQsExpanded && !mStackScrollerOverscrolling));
+        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+                ? View.VISIBLE
+                : View.INVISIBLE);
+        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+                || (mQsExpanded && !mStackScrollerOverscrolling));
         mNotificationStackScroller.setScrollingEnabled(
                 mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
                         || mQsExpansionFromOverscroll));
@@ -1124,6 +1159,10 @@
         if (mKeyguardShowing) {
             updateHeaderKeyguard();
         }
+        if (mStatusBarState == StatusBarState.SHADE_LOCKED
+                || mStatusBarState == StatusBarState.KEYGUARD) {
+            updateKeyguardBottomAreaAlpha();
+        }
         if (mStatusBarState == StatusBarState.SHADE && mQsExpanded
                 && !mStackScrollerOverscrolling && mQsScrimEnabled) {
             mQsNavbarScrim.setAlpha(getQsExpansionFraction());
@@ -1164,10 +1203,10 @@
     }
 
     private void setQsTranslation(float height) {
-        if (!mHeaderAnimatingIn) {
+        if (!mHeaderAnimating) {
             mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
         }
-        if (mKeyguardShowing) {
+        if (mKeyguardShowing && !mHeaderAnimating) {
             mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
         }
     }
@@ -1479,8 +1518,7 @@
      * Hides the header when notifications are colliding with it.
      */
     private void updateHeader() {
-        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
+        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             updateHeaderKeyguard();
         } else {
             updateHeaderShade();
@@ -1489,15 +1527,14 @@
     }
 
     private void updateHeaderShade() {
-        if (!mHeaderAnimatingIn) {
+        if (!mHeaderAnimating) {
             mHeader.setTranslationY(getHeaderTranslation());
         }
         setQsTranslation(mQsExpansionHeight);
     }
 
     private float getHeaderTranslation() {
-        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
+        if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             return 0;
         }
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
@@ -1510,30 +1547,42 @@
         return Math.min(0, mNotificationStackScroller.getTranslationY()) / HEADER_RUBBERBAND_FACTOR;
     }
 
-    private void updateHeaderKeyguard() {
-        float alphaNotifications;
+    /**
+     * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
+     *         during swiping up
+     */
+    private float getKeyguardContentsAlpha() {
+        float alpha;
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
 
             // When on Keyguard, we hide the header as soon as the top card of the notification
             // stack scroller is close enough (collision distance) to the bottom of the header.
-            alphaNotifications = getNotificationsTopY()
+            alpha = getNotificationsTopY()
                     /
                     (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance);
         } else {
 
             // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
             // soon as we start translating the stack.
-            alphaNotifications = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
+            alpha = getNotificationsTopY() / mKeyguardStatusBar.getHeight();
         }
-        alphaNotifications = MathUtils.constrain(alphaNotifications, 0, 1);
-        alphaNotifications = (float) Math.pow(alphaNotifications, 0.75);
+        alpha = MathUtils.constrain(alpha, 0, 1);
+        alpha = (float) Math.pow(alpha, 0.75);
+        return alpha;
+    }
+
+    private void updateHeaderKeyguard() {
         float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
-        mKeyguardStatusBar.setAlpha(Math.min(alphaNotifications, alphaQsExpansion)
+        mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
                 * mKeyguardStatusBarAnimateAlpha);
-        mKeyguardBottomArea.setAlpha(Math.min(1 - getQsExpansionFraction(), alphaNotifications));
         setQsTranslation(mQsExpansionHeight);
     }
 
+    private void updateKeyguardBottomAreaAlpha() {
+        mKeyguardBottomArea.setAlpha(
+                Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction()));
+    }
+
     private float getNotificationsTopY() {
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
             return getExpandedHeight();
@@ -1631,7 +1680,7 @@
     }
 
     @Override
-    public void onHeightChanged(ExpandableView view) {
+    public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
 
         // Block update if we are in quick settings and just the top padding changed
         // (i.e. view == null).
@@ -1764,6 +1813,7 @@
         mSecureCameraLaunchManager.onSwipingStarted();
         requestDisallowInterceptTouchEvent(true);
         mOnlyAffordanceInThisMotion = true;
+        mQsTracking = false;
     }
 
     @Override
@@ -1905,7 +1955,7 @@
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardStatusBar.setVisibility(View.VISIBLE);
             if (animate) {
-                animateKeyguardStatusBarIn();
+                animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
                 mKeyguardBottomArea.startFinishDozeAnimation();
             }
         }
@@ -1955,6 +2005,32 @@
         onEmptySpaceClick(x);
     }
 
+    protected boolean onMiddleClicked() {
+        switch (mStatusBar.getBarState()) {
+            case StatusBarState.KEYGUARD:
+                if (!mDozingOnDown) {
+                    EventLogTags.writeSysuiLockscreenGesture(
+                            EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT,
+                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+                    startUnlockHintAnimation();
+                }
+                return true;
+            case StatusBarState.SHADE_LOCKED:
+                if (!mQsExpanded) {
+                    mStatusBar.goToKeyguard();
+                }
+                return true;
+            case StatusBarState.SHADE:
+
+                // This gets called in the middle of the touch handling, where the state is still
+                // that we are tracking the panel. Collapse the panel after this is done.
+                post(mPostCollapseRunnable);
+                return false;
+            default:
+                return true;
+        }
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index e7b0c4c..a03c297 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewStub;
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 d86ccee..47034e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -100,7 +100,6 @@
     private boolean mCollapseAfterPeek;
     private boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
-    private boolean mDozingOnDown;
     private Runnable mPeekRunnable = new Runnable() {
         @Override
         public void run() {
@@ -247,7 +246,6 @@
                 mUpdateFlingOnLayout = false;
                 mPeekTouching = mPanelClosedOnDown;
                 mTouchAboveFalsingThreshold = false;
-                mDozingOnDown = isDozing();
                 if (mVelocityTracker == null) {
                     initVelocityTracker();
                 }
@@ -431,7 +429,6 @@
                 mHasLayoutedSinceDown = false;
                 mUpdateFlingOnLayout = false;
                 mTouchAboveFalsingThreshold = false;
-                mDozingOnDown = isDozing();
                 initVelocityTracker();
                 trackMovement(event);
                 break;
@@ -942,35 +939,14 @@
         }
     }
 
-    private final Runnable mPostCollapseRunnable = new Runnable() {
+    protected final Runnable mPostCollapseRunnable = new Runnable() {
         @Override
         public void run() {
             collapse(false /* delayed */);
         }
     };
-    private boolean onMiddleClicked() {
-        switch (mStatusBar.getBarState()) {
-            case StatusBarState.KEYGUARD:
-                if (!mDozingOnDown) {
-                    EventLogTags.writeSysuiLockscreenGesture(
-                            EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT,
-                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
-                    startUnlockHintAnimation();
-                }
-                return true;
-            case StatusBarState.SHADE_LOCKED:
-                mStatusBar.goToKeyguard();
-                return true;
-            case StatusBarState.SHADE:
 
-                // This gets called in the middle of the touch handling, where the state is still
-                // that we are tracking the panel. Collapse the panel after this is done.
-                post(mPostCollapseRunnable);
-                return false;
-            default:
-                return true;
-        }
-    }
+    protected abstract boolean onMiddleClicked();
 
     protected abstract void onEdgeClicked(boolean right);
 
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 f227107..f3ec34a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -32,7 +32,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -50,6 +49,7 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -82,14 +82,12 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
-import android.view.HardwareCanvas;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -97,23 +95,16 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -123,13 +114,12 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.recent.ScreenPinningRequest;
+import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -172,8 +162,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
-import com.android.systemui.statusbar.stack.StackScrollAlgorithm;
-import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.statusbar.stack.StackViewState;
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -181,6 +170,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -199,9 +189,6 @@
     // additional instrumentation for testing purposes; intended to be left on during development
     public static final boolean CHATTY = DEBUG;
 
-    public static final String ACTION_STATUSBAR_START
-            = "com.android.internal.policy.statusbar.START";
-
     public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
 
     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
@@ -215,9 +202,6 @@
 
     private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
-    private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
-
     private static final int STATUS_OR_NAV_TRANSIENT =
             View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
     private static final long AUTOHIDE_TIMEOUT_MS = 3000;
@@ -241,6 +225,8 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
+    private int mLightModeIconColor;
+
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
@@ -264,8 +250,7 @@
     AccessibilityController mAccessibilityController;
 
     int mNaturalBarHeight = -1;
-    int mIconSize = -1;
-    int mIconHPadding = -1;
+
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
 
@@ -281,34 +266,14 @@
     int mPixelFormat;
     Object mQueueLock = new Object();
 
-    // viewgroup containing the normal contents of the statusbar
-    LinearLayout mStatusBarContents;
-
-    // right-hand icons
-    LinearLayout mSystemIconArea;
-    LinearLayout mSystemIcons;
-
-    // left-hand icons
-    LinearLayout mStatusIcons;
-    LinearLayout mStatusIconsKeyguard;
-
-    // the icons themselves
-    IconMerger mNotificationIcons;
-    View mNotificationIconArea;
-
-    // [+>
-    View mMoreIcon;
+    StatusBarIconController mIconController;
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     View mExpandedContents;
-    int mNotificationPanelGravity;
-    int mNotificationPanelMarginBottomPx;
-    float mNotificationPanelMinHeightFrac;
     TextView mNotificationPanelDebugText;
 
     // settings
-    View mFlipSettingsView;
     private QSPanel mQSPanel;
 
     // top bar
@@ -325,16 +290,6 @@
 
     int mKeyguardMaxNotificationCount;
 
-    // carrier/wifi label
-    private TextView mCarrierLabel;
-    private boolean mCarrierLabelVisible = false;
-    private int mCarrierLabelHeight;
-    private int mStatusBarHeaderHeight;
-
-    private boolean mShowCarrierInPanel = false;
-
-    // position
-    int[] mPositionTmp = new int[2];
     boolean mExpandedVisible;
 
     private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -342,12 +297,6 @@
     // the tracker view
     int mTrackingPosition; // the position of the top of the tracking view.
 
-    // ticker
-    private boolean mTickerEnabled;
-    private Ticker mTicker;
-    private View mTickerView;
-    private boolean mTicking;
-
     // Tracking finger for opening/closing.
     int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
     boolean mTracking;
@@ -411,7 +360,7 @@
                 if (!mUseHeadsUp) {
                     Log.d(TAG, "dismissing any existing heads up notification on disable event");
                     setHeadsUpVisibility(false);
-                    mHeadsUpNotificationView.release();
+                    mHeadsUpNotificationView.releaseImmediately();
                     removeHeadsUpView();
                 } else {
                     addHeadsUpView();
@@ -442,7 +391,6 @@
     private boolean mDozing;
     private boolean mScrimSrcModeEnabled;
 
-    private Interpolator mLinearOutSlowIn;
     private Interpolator mLinearInterpolator = new LinearInterpolator();
     private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
     public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
@@ -498,10 +446,10 @@
     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
     private int mLastLoggedStateFingerprint;
 
-    private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
-            | ViewState.LOCATION_TOP_STACK_PEEKING
-            | ViewState.LOCATION_MAIN_AREA
-            | ViewState.LOCATION_BOTTOM_STACK_PEEKING;
+    private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
+            | StackViewState.LOCATION_TOP_STACK_PEEKING
+            | StackViewState.LOCATION_MAIN_AREA
+            | StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
 
     private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
             new OnChildLocationsChangedListener() {
@@ -577,6 +525,8 @@
             goToLockedShade(null);
         }
     };
+    private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
+            = new HashMap<>();
 
     @Override
     public void start() {
@@ -585,6 +535,9 @@
         updateDisplaySize();
         mScrimSrcModeEnabled = mContext.getResources().getBoolean(
                 R.bool.config_status_bar_scrim_behind_use_src);
+        mLightModeIconColor = mContext.getResources().getColor(R.color.light_mode_icon_color,
+                mContext.getTheme());
+
         super.start(); // calls createAndAddWindows()
 
         mMediaSessionManager
@@ -633,8 +586,6 @@
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
 
-        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
-
         mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                 R.layout.super_status_bar, null);
         mStatusBarWindow.mService = this;
@@ -712,19 +663,12 @@
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
 
-        mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
-        mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
-        mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
-        mNotificationIconArea = mStatusBarView.findViewById(R.id.notification_icon_area_inner);
-        mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
-        mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
-        mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
-
         mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                 R.id.notification_stack_scroller);
         mStackScroller.setLongPressListener(getNotificationLongClicker());
         mStackScroller.setPhoneStatusBar(this);
+        mStackScroller.setGroupManager(mGroupManager);
+        mGroupManager.setOnGroupChangeListener(mStackScroller);
 
         mKeyguardIconOverflowContainer =
                 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
@@ -764,7 +708,6 @@
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
         mHeader.setActivityStarter(this);
         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
-        mStatusIconsKeyguard = (LinearLayout) mKeyguardStatusBar.findViewById(R.id.statusIcons);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
@@ -774,23 +717,14 @@
                         R.id.keyguard_indication_text));
         mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
 
-        mTickerEnabled = res.getBoolean(R.bool.enable_ticker);
-        if (mTickerEnabled) {
-            final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub);
-            if (tickerStub != null) {
-                mTickerView = tickerStub.inflate();
-                mTicker = new MyTicker(context, mStatusBarView);
-
-                TickerView tickerView = (TickerView) mStatusBarView.findViewById(R.id.tickerText);
-                tickerView.mTicker = mTicker;
-            }
-        }
-
         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
 
         // set the inital view visibility
         setAreThereNotifications();
 
+        mIconController = new StatusBarIconController(
+                mContext, mStatusBarView, mKeyguardStatusBar, this);
+
         // Background thread for any controllers that need it.
         mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
         mHandlerThread.start();
@@ -849,27 +783,6 @@
             });
         }
 
-        mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
-        mShowCarrierInPanel = (mCarrierLabel != null);
-        if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel);
-        if (mShowCarrierInPanel) {
-            mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE);
-
-            mNetworkController.addCarrierLabel(new NetworkControllerImpl.CarrierLabelListener() {
-                @Override
-                public void setCarrierLabel(String label) {
-                    mCarrierLabel.setText(label);
-                    if (mNetworkController.hasMobileDataFeature()) {
-                        if (TextUtils.isEmpty(label)) {
-                            mCarrierLabel.setVisibility(View.GONE);
-                        } else {
-                            mCarrierLabel.setVisibility(View.VISIBLE);
-                        }
-                    }
-                }
-            });
-        }
-
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
         mKeyguardBottomArea.setPhoneStatusBar(this);
@@ -936,7 +849,6 @@
         // listen for USER_SETUP_COMPLETE setting (per-user)
         resetUserSetupObserver();
 
-        startGlyphRasterizeHack();
         return mStatusBarView;
     }
 
@@ -948,9 +860,20 @@
         final ArrayList<View> viewsToHide = new ArrayList<View>(numChildren);
         for (int i = 0; i < numChildren; i++) {
             final View child = mStackScroller.getChildAt(i);
-            if (mStackScroller.canChildBeDismissed(child)) {
-                if (child.getVisibility() == View.VISIBLE) {
-                    viewsToHide.add(child);
+            if (child instanceof ExpandableNotificationRow) {
+                if (mStackScroller.canChildBeDismissed(child)) {
+                    if (child.getVisibility() == View.VISIBLE) {
+                        viewsToHide.add(child);
+                    }
+                }
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                List<ExpandableNotificationRow> children = row.getNotificationChildren();
+                if (row.areChildrenExpanded() && children != null) {
+                    for (ExpandableNotificationRow childRow : children) {
+                        if (childRow.getVisibility() == View.VISIBLE) {
+                            viewsToHide.add(childRow);
+                        }
+                    }
                 }
             }
         }
@@ -1007,30 +930,6 @@
         }
     }
 
-    /**
-     * Hack to improve glyph rasterization for scaled text views.
-     */
-    private void startGlyphRasterizeHack() {
-        mStatusBarView.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
-            @Override
-            public boolean onPreDraw() {
-                if (mDrawCount == 1) {
-                    mStatusBarView.getViewTreeObserver().removeOnPreDrawListener(this);
-                    HardwareCanvas.setProperty("extraRasterBucket",
-                            Float.toString(StackScrollAlgorithm.DIMMED_SCALE));
-                    HardwareCanvas.setProperty("extraRasterBucket", Float.toString(
-                            mContext.getResources().getDimensionPixelSize(
-                                    R.dimen.qs_time_collapsed_size)
-                            / mContext.getResources().getDimensionPixelSize(
-                                    R.dimen.qs_time_expanded_size)));
-                }
-                mDrawCount++;
-                return true;
-            }
-        });
-    }
-
     @Override
     protected void setZenMode(int mode) {
         super.setZenMode(mode);
@@ -1258,49 +1157,17 @@
         mWindowManager.removeView(mHeadsUpNotificationView);
     }
 
-    public void refreshAllStatusBarIcons() {
-        refreshAllIconsForLayout(mStatusIcons);
-        refreshAllIconsForLayout(mStatusIconsKeyguard);
-        refreshAllIconsForLayout(mNotificationIcons);
-    }
-
-    private void refreshAllIconsForLayout(LinearLayout ll) {
-        final int count = ll.getChildCount();
-        for (int n = 0; n < count; n++) {
-            View child = ll.getChildAt(n);
-            if (child instanceof StatusBarIconView) {
-                ((StatusBarIconView) child).updateDrawable();
-            }
-        }
-    }
-
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        if (SPEW) Log.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " icon=" + icon);
-        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
-        view.set(icon);
-        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT, mIconSize));
-        view = new StatusBarIconView(mContext, slot, null);
-        view.set(icon);
-        mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT, mIconSize));
+        mIconController.addSystemIcon(slot, index, viewIndex, icon);
     }
 
     public void updateIcon(String slot, int index, int viewIndex,
             StatusBarIcon old, StatusBarIcon icon) {
-        if (SPEW) Log.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex
-                + " old=" + old + " icon=" + icon);
-        StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
-        view.set(icon);
-        view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
-        view.set(icon);
+        mIconController.updateSystemIcon(slot, index, viewIndex, old, icon);
     }
 
     public void removeIcon(String slot, int index, int viewIndex) {
-        if (SPEW) Log.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex);
-        mStatusIcons.removeViewAt(viewIndex);
-        mStatusIconsKeyguard.removeViewAt(viewIndex);
+        mIconController.removeSystemIcon(slot, index, viewIndex);
     }
 
     public UserHandle getCurrentUserHandle() {
@@ -1308,11 +1175,19 @@
     }
 
     @Override
-    public void addNotification(StatusBarNotification notification, RankingMap ranking) {
+    public void addNotification(StatusBarNotification notification, RankingMap ranking,
+            Entry oldEntry) {
         if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
         if (mUseHeadsUp && shouldInterrupt(notification)) {
             if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
-            Entry interruptionCandidate = new Entry(notification, null);
+            Entry interruptionCandidate = oldEntry;
+            if (interruptionCandidate == null) {
+                final StatusBarIconView iconView = createIcon(notification);
+                if (iconView == null) {
+                    return;
+                }
+                interruptionCandidate = new Entry(notification, iconView);
+            }
             ViewGroup holder = mHeadsUpNotificationView.getHolder();
             if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
                 // 1. Populate mHeadsUpNotificationView
@@ -1341,58 +1216,22 @@
                 notification.getNotification().fullScreenIntent.send();
             } catch (PendingIntent.CanceledException e) {
             }
-        } else {
-            // usual case: status bar visible & not immersive
-
-            // show the ticker if there isn't already a heads up
-            if (mHeadsUpNotificationView.getEntry() == null) {
-                tick(notification, true);
-            }
         }
         addNotificationViews(shadeEntry, ranking);
         // Recalculate the position of the sliding windows and the titles.
         setAreThereNotifications();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
     }
 
-    public void displayNotificationFromHeadsUp(StatusBarNotification notification) {
-        NotificationData.Entry shadeEntry = createNotificationViews(notification);
-        if (shadeEntry == null) {
-            return;
-        }
+    public void displayNotificationFromHeadsUp(Entry shadeEntry) {
+
+        // The notification comes from the headsup, let's inflate the normal layout again
+        inflateViews(shadeEntry, mStackScroller);
         shadeEntry.setInterruption();
+        shadeEntry.row.setHeadsUp(false);
 
         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_DECAY_HEADS_UP);
-        if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
-                && mHeadsUpNotificationView.isClearable()) {
-            mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay);
-        }
-    }
-
-    @Override
-    public void scheduleHeadsUpOpen() {
-        mHandler.removeMessages(MSG_SHOW_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
-    }
-
-    @Override
-    public void scheduleHeadsUpClose() {
-        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
-    }
-
-    @Override
-    public void scheduleHeadsUpEscalation() {
-        mHandler.removeMessages(MSG_ESCALATE_HEADS_UP);
-        mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
     }
 
     @Override
@@ -1403,23 +1242,14 @@
 
     @Override
     public void removeNotification(String key, RankingMap ranking) {
-        if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
-                && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
-            mHeadsUpNotificationView.clear();
+        if (ENABLE_HEADS_UP) {
+            mHeadsUpNotificationView.removeNotification(key);
         }
 
         StatusBarNotification old = removeNotificationViews(key, ranking);
         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
 
         if (old != null) {
-            // Cancel the ticker if it's still running
-            if (mTickerEnabled) {
-                mTicker.removeEntry(old);
-            }
-
-            // Recalculate the position of the sliding windows and the titles.
-            updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-
             if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
                 if (mState == StatusBarState.SHADE) {
@@ -1437,7 +1267,6 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setLayoutDirection(layoutDirection);
         }
-        refreshAllStatusBarIcons();
     }
 
     private void updateShowSearchHoldoff() {
@@ -1483,10 +1312,23 @@
                     ent.row.setShowingLegacyBackground(true);
                 }
             }
-            toShow.add(ent.row);
+            if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
+                ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
+                        ent.row.getStatusBarNotification());
+                List<ExpandableNotificationRow> orderedChildren =
+                        mTmpChildOrderMap.get(summary);
+                if (orderedChildren == null) {
+                    orderedChildren = new ArrayList<>();
+                    mTmpChildOrderMap.put(summary, orderedChildren);
+                }
+                orderedChildren.add(ent.row);
+            } else {
+                toShow.add(ent.row);
+            }
+
         }
 
-        ArrayList<View> toRemove = new ArrayList<View>();
+        ArrayList<View> toRemove = new ArrayList<>();
         for (int i=0; i< mStackScroller.getChildCount(); i++) {
             View child = mStackScroller.getChildAt(i);
             if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
@@ -1515,17 +1357,22 @@
                 continue;
             }
 
-            if (child == toShow.get(j)) {
-                // Everything is well, advance both lists.
-                j++;
-                continue;
+            ExpandableNotificationRow targetChild = toShow.get(j);
+            if (child != targetChild) {
+                // Oops, wrong notification at this position. Put the right one
+                // here and advance both lists.
+                mStackScroller.changeViewPosition(targetChild, i);
             }
-
-            // Oops, wrong notification at this position. Put the right one
-            // here and advance both lists.
-            mStackScroller.changeViewPosition(toShow.get(j), i);
             j++;
+
         }
+
+        // lets handle the child notifications now
+        updateNotificationShadeForChildren();
+
+        // clear the map again for the next usage
+        mTmpChildOrderMap.clear();
+
         updateRowStates();
         updateSpeedbump();
         updateClearAll();
@@ -1540,6 +1387,52 @@
         mShadeUpdates.check();
     }
 
+    private void updateNotificationShadeForChildren() {
+        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
+        boolean orderChanged = false;
+        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+            View view = mStackScroller.getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                // We don't care about non-notification views.
+                continue;
+            }
+
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
+            // lets first remove all undesired children
+            if (children != null) {
+                toRemove.clear();
+                for (ExpandableNotificationRow childRow : children) {
+                    if (orderedChildren == null || !orderedChildren.contains(childRow)) {
+                        toRemove.add(childRow);
+                    }
+                }
+                for (ExpandableNotificationRow remove : toRemove) {
+                    parent.removeChildNotification(remove);
+                    mStackScroller.notifyGroupChildRemoved(remove);
+                }
+            }
+
+            // We now add all the children which are not in there already
+            for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size();
+                    childIndex++) {
+                ExpandableNotificationRow childView = orderedChildren.get(childIndex);
+                if (children == null || !children.contains(childView)) {
+                    parent.addChildNotification(childView, childIndex);
+                    mStackScroller.notifyGroupChildAdded(childView);
+                }
+            }
+
+            // Finally after removing and adding has been beformed we can apply the order.
+            orderChanged |= parent.applyChildOrder(orderedChildren);
+        }
+        if (orderChanged) {
+            mStackScroller.generateChildOrderChangedEvent();
+        }
+    }
+
     private boolean packageHasVisibilityOverride(String key) {
         return mNotificationData.getVisibilityOverride(key)
                 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
@@ -1566,6 +1459,10 @@
         final int N = activeNotifications.size();
         for (int i = 0; i < N; i++) {
             Entry entry = activeNotifications.get(i);
+            boolean isChild = !isTopLevelChild(entry);
+            if (isChild) {
+                continue;
+            }
             if (entry.row.getVisibility() != View.GONE &&
                     mNotificationData.isAmbient(entry.key)) {
                 speedbumpIndex = currentIndex;
@@ -1576,71 +1473,16 @@
         mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
     }
 
+    public static boolean isTopLevelChild(Entry entry) {
+        return entry.row.getParent() instanceof NotificationStackScrollLayout;
+    }
+
     @Override
     protected void updateNotifications() {
-        // TODO: Move this into updateNotificationIcons()?
-        if (mNotificationIcons == null) return;
-
         mNotificationData.filterAndSort();
 
         updateNotificationShade();
-        updateNotificationIcons();
-    }
-
-    private void updateNotificationIcons() {
-        final LinearLayout.LayoutParams params
-            = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);
-
-        ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
-        final int N = activeNotifications.size();
-        ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
-
-        // Filter out notifications with low scores.
-        for (int i = 0; i < N; i++) {
-            Entry ent = activeNotifications.get(i);
-            if (ent.notification.getScore() < HIDE_ICONS_BELOW_SCORE &&
-                    !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
-                continue;
-            }
-            toShow.add(ent.icon);
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "refreshing icons: " + toShow.size() +
-                    " notifications, mNotificationIcons=" + mNotificationIcons);
-        }
-
-        ArrayList<View> toRemove = new ArrayList<View>();
-        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
-            View child = mNotificationIcons.getChildAt(i);
-            if (!toShow.contains(child)) {
-                toRemove.add(child);
-            }
-        }
-
-        final int toRemoveCount = toRemove.size();
-        for (int i = 0; i < toRemoveCount; i++) {
-            mNotificationIcons.removeView(toRemove.get(i));
-        }
-
-        for (int i=0; i<toShow.size(); i++) {
-            View v = toShow.get(i);
-            if (v.getParent() == null) {
-                mNotificationIcons.addView(v, i, params);
-            }
-        }
-
-        // Resort notification icons
-        final int childCount = mNotificationIcons.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View actual = mNotificationIcons.getChildAt(i);
-            StatusBarIconView expected = toShow.get(i);
-            if (actual == expected) {
-                continue;
-            }
-            mNotificationIcons.removeView(expected);
-            mNotificationIcons.addView(expected, i);
-        }
+        mIconController.updateNotificationIcons(mNotificationData);
     }
 
     @Override
@@ -1649,53 +1491,6 @@
         mNotificationPanel.notifyVisibleChildrenChanged();
     }
 
-    protected void updateCarrierLabelVisibility(boolean force) {
-        // TODO: Handle this for the notification stack scroller as well
-        if (!mShowCarrierInPanel) return;
-        // The idea here is to only show the carrier label when there is enough room to see it,
-        // i.e. when there aren't enough notifications to fill the panel.
-        if (SPEW) {
-            Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d",
-                    mStackScroller.getHeight(), mStackScroller.getHeight(),
-                    mCarrierLabelHeight));
-        }
-
-        // Emergency calls only is shown in the expanded header now.
-        final boolean emergencyCallsShownElsewhere = true;
-        final boolean makeVisible =
-            !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
-            && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
-                    - mCarrierLabelHeight - mStatusBarHeaderHeight)
-            && mStackScroller.getVisibility() == View.VISIBLE
-            && mState != StatusBarState.KEYGUARD;
-
-        if (force || mCarrierLabelVisible != makeVisible) {
-            mCarrierLabelVisible = makeVisible;
-            if (DEBUG) {
-                Log.d(TAG, "making carrier label " + (makeVisible?"visible":"invisible"));
-            }
-            mCarrierLabel.animate().cancel();
-            if (makeVisible) {
-                mCarrierLabel.setVisibility(View.VISIBLE);
-            }
-            mCarrierLabel.animate()
-                .alpha(makeVisible ? 1f : 0f)
-                //.setStartDelay(makeVisible ? 500 : 0)
-                //.setDuration(makeVisible ? 750 : 100)
-                .setDuration(150)
-                .setListener(makeVisible ? null : new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        if (!mCarrierLabelVisible) { // race
-                            mCarrierLabel.setVisibility(View.INVISIBLE);
-                            mCarrierLabel.setAlpha(0f);
-                        }
-                    }
-                })
-                .start();
-        }
-    }
-
     @Override
     protected void setAreThereNotifications() {
 
@@ -1728,8 +1523,6 @@
         }
 
         findAndUpdateMediaNotifications();
-
-        updateCarrierLabelVisibility(false);
     }
 
     public void findAndUpdateMediaNotifications() {
@@ -1973,14 +1766,6 @@
         }
     }
 
-    public void showClock(boolean show) {
-        if (mStatusBarView == null) return;
-        View clock = mStatusBarView.findViewById(R.id.clock);
-        if (clock != null) {
-            clock.setVisibility(show ? View.VISIBLE : View.GONE);
-        }
-    }
-
     private int adjustDisableFlags(int state) {
         if (!mLaunchTransitionFadingAway
                 && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
@@ -2029,17 +1814,16 @@
         Log.d(TAG, flagdbg.toString());
 
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-            mSystemIconArea.animate().cancel();
             if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
-                animateStatusBarHide(mSystemIconArea, animate);
+                mIconController.hideSystemIconArea(animate);
             } else {
-                animateStatusBarShow(mSystemIconArea, animate);
+                mIconController.showSystemIconArea(animate);
             }
         }
 
         if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
-            boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
-            showClock(show);
+            boolean visible = (state & StatusBarManager.DISABLE_CLOCK) == 0;
+            mIconController.setClockVisibility(visible);
         }
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
@@ -2063,12 +1847,9 @@
 
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                if (mTicking) {
-                    haltTicker();
-                }
-                animateStatusBarHide(mNotificationIconArea, animate);
+                mIconController.hideNotificationIconArea(animate);
             } else {
-                animateStatusBarShow(mNotificationIconArea, animate);
+                mIconController.showNotificationIconArea(animate);
             }
         }
 
@@ -2079,60 +1860,6 @@
         }
     }
 
-    /**
-     * Animates {@code v}, a view that is part of the status bar, out.
-     */
-    private void animateStatusBarHide(final View v, boolean animate) {
-        v.animate().cancel();
-        if (!animate) {
-            v.setAlpha(0f);
-            v.setVisibility(View.INVISIBLE);
-            return;
-        }
-        v.animate()
-                .alpha(0f)
-                .setDuration(160)
-                .setStartDelay(0)
-                .setInterpolator(ALPHA_OUT)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        v.setVisibility(View.INVISIBLE);
-                    }
-                });
-    }
-
-    /**
-     * Animates {@code v}, a view that is part of the status bar, in.
-     */
-    private void animateStatusBarShow(View v, boolean animate) {
-        v.animate().cancel();
-        v.setVisibility(View.VISIBLE);
-        if (!animate) {
-            v.setAlpha(1f);
-            return;
-        }
-        v.animate()
-                .alpha(1f)
-                .setDuration(320)
-                .setInterpolator(ALPHA_IN)
-                .setStartDelay(50)
-
-                // We need to clean up any pending end action from animateStatusBarHide if we call
-                // both hide and show in the same frame before the animation actually gets started.
-                // cancel() doesn't really remove the end action.
-                .withEndAction(null);
-
-        // Synchronize the motion with the Keyguard fading if necessary.
-        if (mKeyguardFadingAway) {
-            v.animate()
-                    .setDuration(mKeyguardFadingAwayDuration)
-                    .setInterpolator(mLinearOutSlowIn)
-                    .setStartDelay(mKeyguardFadingAwayDelay)
-                    .start();
-        }
-    }
-
     @Override
     protected BaseStatusBar.H createHandler() {
         return new PhoneStatusBar.H();
@@ -2143,10 +1870,6 @@
         startActivityDismissingKeyguard(intent, false, dismissShade);
     }
 
-    public ScrimController getScrimController() {
-        return mScrimController;
-    }
-
     public void setQsExpanded(boolean expanded) {
         mStatusBarWindowManager.setQsExpanded(expanded);
     }
@@ -2213,16 +1936,10 @@
                 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:
                     escalateHeadsUp();
+                case MSG_HIDE_HEADS_UP:
+                    mHeadsUpNotificationView.releaseImmediately();
                     setHeadsUpVisibility(false);
                     break;
                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
@@ -2232,11 +1949,41 @@
         }
     }
 
+    @Override
+    public void scheduleHeadsUpDecay(long delay) {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        if (mHeadsUpNotificationView.isClearable()) {
+            mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, delay);
+        }
+    }
+
+    @Override
+    public void scheduleHeadsUpOpen() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        mHandler.removeMessages(MSG_SHOW_HEADS_UP);
+        mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+    }
+
+    @Override
+    public void scheduleHeadsUpClose() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        if (mHeadsUpNotificationView.getVisibility() != View.GONE) {
+            mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+        }
+    }
+
+    @Override
+    public void scheduleHeadsUpEscalation() {
+        mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+        mHandler.removeMessages(MSG_ESCALATE_HEADS_UP);
+        mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+    }
+
     /**  if the interrupting notification had a fullscreen intent, fire it now.  */
     private void escalateHeadsUp() {
         if (mHeadsUpNotificationView.getEntry() != null) {
             final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
-            mHeadsUpNotificationView.release();
+            mHeadsUpNotificationView.releaseImmediately();
             final Notification notification = sbn.getNotification();
             if (notification.fullScreenIntent != null) {
                 if (DEBUG)
@@ -2251,14 +1998,6 @@
         }
     }
 
-    View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
-        public void onFocusChange(View v, boolean hasFocus) {
-            // Because 'v' is a ViewGroup, all its children will be (un)selected
-            // too, which allows marqueeing to work.
-            v.setSelected(hasFocus);
-        }
-    };
-
     boolean panelsEnabled() {
         return (mDisabled & StatusBarManager.DISABLE_EXPAND) == 0;
     }
@@ -2273,10 +2012,6 @@
         if (mNavigationBarView != null)
             mNavigationBarView.setSlippery(true);
 
-        updateCarrierLabelVisibility(true);
-
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
-
         // Expand the window to encompass the full screen in anticipation of the drag.
         // This is only possible to do atomically because the status bar is at the top of the screen!
         mStatusBarWindowManager.setStatusBarExpanded(true);
@@ -2348,50 +2083,6 @@
         mPostCollapseRunnables.clear();
     }
 
-    public ViewPropertyAnimator setVisibilityWhenDone(
-            final ViewPropertyAnimator a, final View v, final int vis) {
-        a.setListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                v.setVisibility(vis);
-                a.setListener(null); // oneshot
-            }
-        });
-        return a;
-    }
-
-    public Animator setVisibilityWhenDone(
-            final Animator a, final View v, final int vis) {
-        a.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                v.setVisibility(vis);
-            }
-        });
-        return a;
-    }
-
-    public Animator interpolator(TimeInterpolator ti, Animator a) {
-        a.setInterpolator(ti);
-        return a;
-    }
-
-    public Animator startDelay(int d, Animator a) {
-        a.setStartDelay(d);
-        return a;
-    }
-
-    public Animator start(Animator a) {
-        a.start();
-        return a;
-    }
-
-    final TimeInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
-    final TimeInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
-    final int FLIP_DURATION_OUT = 125;
-    final int FLIP_DURATION_IN = 225;
-    final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
-
     Animator mScrollViewAnim, mClearButtonAnim;
 
     @Override
@@ -2439,9 +2130,6 @@
         mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
         // reset things to their proper state
-        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
-        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
         mStackScroller.setVisibility(View.VISIBLE);
         mNotificationPanel.setVisibility(View.GONE);
 
@@ -2587,9 +2275,6 @@
                 final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
                 if (lightsOut) {
                     animateCollapsePanels();
-                    if (mTicking) {
-                        haltTicker();
-                    }
                 }
 
                 setAreThereNotifications();
@@ -2634,6 +2319,16 @@
                 mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
             }
 
+            if ((diff & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0 || sbModeChanged) {
+                boolean isTransparentBar = (mStatusBarMode == MODE_TRANSPARENT
+                        || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
+                boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
+                boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+
+                mIconController.setIconTint(
+                        (allowLight && light) ? mLightModeIconColor : Color.WHITE);
+
+            }
             // restore the recents bit
             if (wasRecentsVisible) {
                 mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
@@ -2805,90 +2500,6 @@
         setNavigationIconHints(flags);
     }
 
-    @Override
-    protected void tick(StatusBarNotification n, boolean firstTime) {
-        if (!mTickerEnabled) return;
-
-        // no ticking in lights-out mode
-        if (!areLightsOn()) return;
-
-        // no ticking in Setup
-        if (!isDeviceProvisioned()) return;
-
-        // not for you
-        if (!isNotificationForCurrentProfiles(n)) return;
-
-        // Show the ticker if one is requested. Also don't do this
-        // until status bar window is attached to the window manager,
-        // because...  well, what's the point otherwise?  And trying to
-        // run a ticker without being attached will crash!
-        if (n.getNotification().tickerText != null && mStatusBarWindow != null
-                && mStatusBarWindow.getWindowToken() != null) {
-            if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
-                    | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
-                mTicker.addEntry(n);
-            }
-        }
-    }
-
-    private class MyTicker extends Ticker {
-        MyTicker(Context context, View sb) {
-            super(context, sb);
-            if (!mTickerEnabled) {
-                Log.w(TAG, "MyTicker instantiated with mTickerEnabled=false", new Throwable());
-            }
-        }
-
-        @Override
-        public void tickerStarting() {
-            if (!mTickerEnabled) return;
-            mTicking = true;
-            mStatusBarContents.setVisibility(View.GONE);
-            mTickerView.setVisibility(View.VISIBLE);
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));
-            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));
-        }
-
-        @Override
-        public void tickerDone() {
-            if (!mTickerEnabled) return;
-            mStatusBarContents.setVisibility(View.VISIBLE);
-            mTickerView.setVisibility(View.GONE);
-            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
-            mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,
-                        mTickingDoneListener));
-        }
-
-        public void tickerHalting() {
-            if (!mTickerEnabled) return;
-            if (mStatusBarContents.getVisibility() != View.VISIBLE) {
-                mStatusBarContents.setVisibility(View.VISIBLE);
-                mStatusBarContents
-                        .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
-            }
-            mTickerView.setVisibility(View.GONE);
-            // we do not animate the ticker away at this point, just get rid of it (b/6992707)
-        }
-    }
-
-    Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {;
-        public void onAnimationEnd(Animation animation) {
-            mTicking = false;
-        }
-        public void onAnimationRepeat(Animation animation) {
-        }
-        public void onAnimationStart(Animation animation) {
-        }
-    };
-
-    private Animation loadAnim(int id, Animation.AnimationListener listener) {
-        Animation anim = AnimationUtils.loadAnimation(mContext, id);
-        if (listener != null) {
-            anim.setAnimationListener(listener);
-        }
-        return anim;
-    }
-
     public static String viewInfo(View v) {
         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
@@ -2899,11 +2510,6 @@
             pw.println("Current Status Bar state:");
             pw.println("  mExpandedVisible=" + mExpandedVisible
                     + ", mTrackingPosition=" + mTrackingPosition);
-            pw.println("  mTickerEnabled=" + mTickerEnabled);
-            if (mTickerEnabled) {
-                pw.println("  mTicking=" + mTicking);
-                pw.println("  mTickerView: " + viewInfo(mTickerView));
-            }
             pw.println("  mTracking=" + mTracking);
             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mStackScroller: " + viewInfo(mStackScroller));
@@ -2972,12 +2578,7 @@
                 mNotificationData.dump(pw, "  ");
             }
 
-            int N = mStatusIcons.getChildCount();
-            pw.println("  system icons: " + N);
-            for (int i=0; i<N; i++) {
-                StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
-                pw.println("    [" + i + "] icon=" + ic);
-            }
+            mIconController.dump(pw);
 
             if (false) {
                 pw.println("see the logcat for a dump of the views we have created.");
@@ -3020,6 +2621,12 @@
         if (mSecurityController != null) {
             mSecurityController.dump(fd, pw, args);
         }
+        if (mHeadsUpNotificationView != null) {
+            mHeadsUpNotificationView.dump(fd, pw, args);
+        } else {
+            pw.println("  mHeadsUpNotificationView: null");
+        }
+
         pw.println("SharedPreferences:");
         for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(),
                 Context.MODE_PRIVATE).getAll().entrySet()) {
@@ -3049,25 +2656,6 @@
         mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
     }
 
-    static final float saturate(float a) {
-        return a < 0f ? 0f : (a > 1f ? 1f : a);
-    }
-
-    @Override
-    public void updateExpandedViewPos(int thingy) {
-        if (SPEW) Log.v(TAG, "updateExpandedViewPos");
-
-        // on larger devices, the notification panel is propped open a bit
-        mNotificationPanel.setMinimumHeight(
-                (int)(mNotificationPanelMinHeightFrac * mCurrentDisplaySize.y));
-
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
-        lp.gravity = mNotificationPanelGravity;
-        mNotificationPanel.setLayoutParams(lp);
-
-        updateCarrierLabelVisibility(false);
-    }
-
     // called by makeStatusbar and also by PhoneStatusBarView
     void updateDisplaySize() {
         mDisplay.getMetrics(mDisplayMetrics);
@@ -3195,11 +2783,10 @@
         updateDisplaySize(); // populates mDisplayMetrics
 
         updateResources();
-        updateClockSize();
         repositionNavigationBar();
-        updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
         updateShowSearchHoldoff();
         updateRowStates();
+        mIconController.updateResources();
         mScreenPinningRequest.onConfigurationChanged();
     }
 
@@ -3225,8 +2812,7 @@
         mUserSetupObserver.onChange(false);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
-                mUserSetupObserver,
-                mCurrentUserId);
+                mUserSetupObserver, mCurrentUserId);
     }
 
     private void setHeadsUpVisibility(boolean vis) {
@@ -3238,10 +2824,6 @@
         mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
     }
 
-    public void onHeadsUpDismissed() {
-        mHeadsUpNotificationView.dismiss();
-    }
-
     /**
      * Reload some of our resources when the configuration changes.
      *
@@ -3256,8 +2838,6 @@
         }
 
         loadDimens();
-        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
-                mContext, android.R.interpolator.linear_out_slow_in);
 
         if (mNotificationPanel != null) {
             mNotificationPanel.updateResources();
@@ -3270,47 +2850,14 @@
         }
     }
 
-    private void updateClockSize() {
-        if (mStatusBarView == null) return;
-        TextView clock = (TextView) mStatusBarView.findViewById(R.id.clock);
-        if (clock != null) {
-            FontSizeUtils.updateFontSize(clock, R.dimen.status_bar_clock_size);
-        }
-    }
     protected void loadDimens() {
         final Resources res = mContext.getResources();
 
         mNaturalBarHeight = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
 
-        int newIconSize = res.getDimensionPixelSize(
-            com.android.internal.R.dimen.status_bar_icon_size);
-        int newIconHPadding = res.getDimensionPixelSize(
-            R.dimen.status_bar_icon_padding);
-
-        if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) {
-//            Log.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding);
-            mIconHPadding = newIconHPadding;
-            mIconSize = newIconSize;
-            //reloadAllNotificationIcons(); // reload the tray
-        }
-
         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
 
-        mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
-        if (mNotificationPanelGravity <= 0) {
-            mNotificationPanelGravity = Gravity.START | Gravity.TOP;
-        }
-
-        mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
-        mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
-
-        mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
-        if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
-            mNotificationPanelMinHeightFrac = 0f;
-        }
-
-        mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay);
         mRowMinHeight =  res.getDimensionPixelSize(R.dimen.notification_min_height);
         mRowMaxHeight =  res.getDimensionPixelSize(R.dimen.notification_max_height);
 
@@ -3443,13 +2990,6 @@
     };
 
     @Override
-    protected void haltTicker() {
-        if (mTickerEnabled) {
-            mTicker.halt();
-        }
-    }
-
-    @Override
     protected boolean shouldDisableNavbarGestures() {
         return !isDeviceProvisioned()
                 || mExpandedVisible
@@ -3486,7 +3026,7 @@
         }
 
         @Override
-        public void setColorFilter(ColorFilter cf) {
+        public void setColorFilter(ColorFilter colorFilter) {
         }
 
         @Override
@@ -3523,7 +3063,6 @@
 
     private boolean mDemoModeAllowed;
     private boolean mDemoMode;
-    private DemoStatusIcons mDemoStatusIcons;
 
     @Override
     public void dispatchDemoCommand(String command, Bundle args) {
@@ -3552,10 +3091,8 @@
             dispatchDemoCommandToView(command, args, R.id.battery);
         }
         if (modeChange || command.equals(COMMAND_STATUS)) {
-            if (mDemoStatusIcons == null) {
-                mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
-            }
-            mDemoStatusIcons.dispatchDemoCommand(command, args);
+            mIconController.dispatchDemoCommand(command, args);
+
         }
         if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) {
             mNetworkController.dispatchDemoCommand(command, args);
@@ -3625,7 +3162,7 @@
         mLeaveOpenOnKeyguardHide = false;
         if (mDraggedDownRow != null) {
             mDraggedDownRow.setUserLocked(false);
-            mDraggedDownRow.notifyHeightChanged();
+            mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
             mDraggedDownRow = null;
         }
     }
@@ -3675,6 +3212,8 @@
                                 mLaunchTransitionFadingAway = false;
                             }
                         });
+                mIconController.appTransitionStarting(SystemClock.uptimeMillis(),
+                        StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
             }
         };
         if (mNotificationPanel.isLaunchTransitionRunning()) {
@@ -3742,16 +3281,31 @@
     }
 
     /**
+     * Notifies the status bar that Keyguard is going away very soon.
+     */
+    public void keyguardGoingAway() {
+
+        // Treat Keyguard exit animation as an app transition to achieve nice transition for status
+        // bar.
+        mIconController.appTransitionPending();
+    }
+
+    /**
      * Notifies the status bar the Keyguard is fading away with the specified timings.
      *
-     * @param delay the animation delay in miliseconds
+     * @param startTime the start time of the animations in uptime millis
+     * @param delay the precalculated animation delay in miliseconds
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
      */
-    public void setKeyguardFadingAway(long delay, long fadeoutDuration) {
+    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
         mKeyguardFadingAway = true;
         mKeyguardFadingAwayDelay = delay;
         mKeyguardFadingAwayDuration = fadeoutDuration;
         mWaitingForKeyguardExit = false;
+        mIconController.appTransitionStarting(
+                startTime + fadeoutDuration
+                        - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
+                StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
         disable(mDisabledUnmodified, true /* animate */);
     }
 
@@ -3767,8 +3321,9 @@
     }
 
     private void updatePublicMode() {
-        setLockscreenPublicMode(mStatusBarKeyguardViewManager.isShowing()
-                && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId));
+        setLockscreenPublicMode(
+                mStatusBarKeyguardViewManager.isShowing() && mStatusBarKeyguardViewManager
+                        .isSecure(mCurrentUserId));
     }
 
     private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -3792,7 +3347,6 @@
         updateStackScrollerState(goingToFullShade);
         updateNotifications();
         checkBarModes();
-        updateCarrierLabelVisibility(false);
         updateMediaMetaData(false);
         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
                 mStatusBarKeyguardViewManager.isSecure());
@@ -3913,6 +3467,7 @@
             }
         }
         mState = state;
+        mGroupManager.setStatusBarState(state);
         mStatusBarWindowManager.setStatusBarState(state);
     }
 
@@ -4046,13 +3601,6 @@
         }
     }
 
-    /**
-     * @return a ViewGroup that spans the entire panel which contains the quick settings
-     */
-    public ViewGroup getQuickSettingsOverlayParent() {
-        return mNotificationPanel;
-    }
-
     public long getKeyguardFadingAwayDelay() {
         return mKeyguardFadingAwayDelay;
     }
@@ -4061,14 +3609,6 @@
         return mKeyguardFadingAwayDuration;
     }
 
-    public LinearLayout getSystemIcons() {
-        return mSystemIcons;
-    }
-
-    public LinearLayout getSystemIconArea() {
-        return mSystemIconArea;
-    }
-
     @Override
     public void setBouncerShowing(boolean bouncerShowing) {
         super.setBouncerShowing(bouncerShowing);
@@ -4211,6 +3751,31 @@
         }
     }
 
+    @Override
+    public void appTransitionPending() {
+
+        // Use own timings when Keyguard is going away, see keyguardGoingAway and
+        // setKeyguardFadingAway
+        if (!mKeyguardFadingAway) {
+            mIconController.appTransitionPending();
+        }
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+        mIconController.appTransitionCancelled();
+    }
+
+    @Override
+    public void appTransitionStarting(long startTime, long duration) {
+
+        // Use own timings when Keyguard is going away, see keyguardGoingAway and
+        // setKeyguardFadingAway
+        if (!mKeyguardFadingAway) {
+            mIconController.appTransitionStarting(startTime, duration);
+        }
+    }
+
     private final class ShadeUpdates {
         private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
         private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5c254a26..2236aae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -46,16 +47,12 @@
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final boolean SHOW_SYNC_ICON = false;
-
-    private static final String SLOT_SYNC_ACTIVE = "sync_active";
     private static final String SLOT_CAST = "cast";
     private static final String SLOT_HOTSPOT = "hotspot";
     private static final String SLOT_BLUETOOTH = "bluetooth";
     private static final String SLOT_TTY = "tty";
     private static final String SLOT_ZEN = "zen";
     private static final String SLOT_VOLUME = "volume";
-    private static final String SLOT_CDMA_ERI = "cdma_eri";
     private static final String SLOT_ALARM_CLOCK = "alarm_clock";
 
     private final Context mContext;
@@ -83,9 +80,6 @@
             if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
                 updateAlarm();
             }
-            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
-                updateSyncState(intent);
-            }
             else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
                     action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
                 updateBluetooth();
@@ -115,7 +109,6 @@
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
-        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -129,10 +122,6 @@
         mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
         mService.setIconVisibility(SLOT_TTY, false);
 
-        // Cdma Roaming Indicator, ERI
-        mService.setIcon(SLOT_CDMA_ERI, R.drawable.stat_sys_roaming_cdma_0, 0, null);
-        mService.setIconVisibility(SLOT_CDMA_ERI, false);
-
         // bluetooth status
         updateBluetooth();
 
@@ -140,11 +129,6 @@
         mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null);
         mService.setIconVisibility(SLOT_ALARM_CLOCK, false);
 
-        // Sync state
-        mService.setIcon(SLOT_SYNC_ACTIVE, R.drawable.stat_sys_sync, 0, null);
-        mService.setIconVisibility(SLOT_SYNC_ACTIVE, false);
-        // "sync_failing" is obsolete: b/1297963
-
         // zen
         mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null);
         mService.setIconVisibility(SLOT_ZEN, false);
@@ -172,16 +156,10 @@
 
     private void updateAlarm() {
         AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-	boolean alarmSet = alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT) != null;
+        boolean alarmSet = alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT) != null;
         mService.setIconVisibility(SLOT_ALARM_CLOCK, alarmSet);
     }
 
-    private final void updateSyncState(Intent intent) {
-        if (!SHOW_SYNC_ICON) return;
-        boolean isActive = intent.getBooleanExtra("active", false);
-        mService.setIconVisibility(SLOT_SYNC_ACTIVE, isActive);
-    }
-
     private final void updateSimState(Intent intent) {
         String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
@@ -221,7 +199,11 @@
         int volumeIconId = 0;
         String volumeDescription = null;
 
-        if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+        if (DndTile.isVisible(mContext)) {
+            zenVisible = mZen != Global.ZEN_MODE_OFF;
+            zenIconId = R.drawable.stat_sys_dnd;
+            zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+        } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_zen_none;
             zenDescription = mContext.getString(R.string.zen_no_interruptions);
@@ -231,7 +213,12 @@
             zenDescription = mContext.getString(R.string.zen_important_interruptions);
         }
 
-        if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
+        if (DndTile.isVisible(mContext)
+                && audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
+            volumeVisible = true;
+            volumeIconId = R.drawable.stat_sys_ringer_silent;
+            volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
+        } else if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
                 audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_vibrate;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 7cbf13f..aa499ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -77,8 +77,8 @@
     }
 
     @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        if (super.onRequestSendAccessibilityEvent(child, event)) {
+    public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEventInternal(child, event)) {
             // The status bar is very small so augment the view that the user is touching
             // with the content of the status bar a whole. This way an accessibility service
             // may announce the current item as well as the entire content if appropriate.
@@ -177,6 +177,5 @@
     public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) {
         super.panelExpansionChanged(panel, frac, expanded);
         mScrimController.setPanelExpansion(frac);
-        mBar.updateCarrierLabelVisibility(false);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 45a1386..954eb10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.tiles.LocationTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -256,6 +257,7 @@
         else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
         else if (tileSpec.equals("cell")) return new CellularTile(this);
         else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
+        else if (tileSpec.equals("dnd")) return new DndTile(this);
         else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
         else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
         else if (tileSpec.equals("location")) return new LocationTile(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
new file mode 100644
index 0000000..c49f620
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.StatusBarIconView;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls everything regarding the icons in the status bar and on Keyguard, including, but not
+ * limited to: notification icons, signal cluster, additional status icons, and clock in the status
+ * bar.
+ */
+public class StatusBarIconController {
+
+    public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
+
+    private Context mContext;
+    private PhoneStatusBar mPhoneStatusBar;
+    private Interpolator mLinearOutSlowIn;
+    private Interpolator mFastOutSlowIn;
+    private DemoStatusIcons mDemoStatusIcons;
+    private NotificationColorUtil mNotificationColorUtil;
+
+    private LinearLayout mSystemIconArea;
+    private LinearLayout mStatusIcons;
+    private SignalClusterView mSignalCluster;
+    private LinearLayout mStatusIconsKeyguard;
+    private IconMerger mNotificationIcons;
+    private View mNotificationIconArea;
+    private ImageView mMoreIcon;
+    private BatteryMeterView mBatteryMeterView;
+    private TextView mClock;
+
+    private int mIconSize;
+    private int mIconHPadding;
+
+    private int mIconTint = Color.WHITE;
+
+    private boolean mTransitionPending;
+    private boolean mTintChangePending;
+    private int mPendingIconTint;
+    private ValueAnimator mTintAnimator;
+
+    private final Handler mHandler;
+    private boolean mTransitionDeferring;
+    private long mTransitionDeferringStartTime;
+    private long mTransitionDeferringDuration;
+
+    private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mTransitionDeferring = false;
+        }
+    };
+
+    public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
+            PhoneStatusBar phoneStatusBar) {
+        mContext = context;
+        mPhoneStatusBar = phoneStatusBar;
+        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+        mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
+        mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
+        mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
+        mNotificationIconArea = statusBar.findViewById(R.id.notification_icon_area_inner);
+        mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons);
+        mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon);
+        mNotificationIcons.setOverflowIndicator(mMoreIcon);
+        mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
+        mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
+        mClock = (TextView) statusBar.findViewById(R.id.clock);
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_slow_in);
+        mHandler = new Handler();
+        updateResources();
+    }
+
+    public void updateResources() {
+        mIconSize = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_icon_size);
+        mIconHPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.status_bar_icon_padding);
+        FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size);
+    }
+
+    public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
+        view.set(icon);
+        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+        view = new StatusBarIconView(mContext, slot, null);
+        view.set(icon);
+        mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+        applyIconTint();
+    }
+
+    public void updateSystemIcon(String slot, int index, int viewIndex,
+            StatusBarIcon old, StatusBarIcon icon) {
+        StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
+        view.set(icon);
+        view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
+        view.set(icon);
+        applyIconTint();
+    }
+
+    public void removeSystemIcon(String slot, int index, int viewIndex) {
+        mStatusIcons.removeViewAt(viewIndex);
+        mStatusIconsKeyguard.removeViewAt(viewIndex);
+    }
+
+    public void updateNotificationIcons(NotificationData notificationData) {
+        final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                mIconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight());
+
+        ArrayList<NotificationData.Entry> activeNotifications =
+                notificationData.getActiveNotifications();
+        final int N = activeNotifications.size();
+        ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
+
+        // Filter out ambient notifications and notification children.
+        for (int i = 0; i < N; i++) {
+            NotificationData.Entry ent = activeNotifications.get(i);
+            if (notificationData.isAmbient(ent.key)
+                    && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
+                continue;
+            }
+            if (!PhoneStatusBar.isTopLevelChild(ent)) {
+                continue;
+            }
+            toShow.add(ent.icon);
+        }
+
+        ArrayList<View> toRemove = new ArrayList<>();
+        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
+            View child = mNotificationIcons.getChildAt(i);
+            if (!toShow.contains(child)) {
+                toRemove.add(child);
+            }
+        }
+
+        final int toRemoveCount = toRemove.size();
+        for (int i = 0; i < toRemoveCount; i++) {
+            mNotificationIcons.removeView(toRemove.get(i));
+        }
+
+        for (int i=0; i<toShow.size(); i++) {
+            View v = toShow.get(i);
+            if (v.getParent() == null) {
+                mNotificationIcons.addView(v, i, params);
+            }
+        }
+
+        // Resort notification icons
+        final int childCount = mNotificationIcons.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View actual = mNotificationIcons.getChildAt(i);
+            StatusBarIconView expected = toShow.get(i);
+            if (actual == expected) {
+                continue;
+            }
+            mNotificationIcons.removeView(expected);
+            mNotificationIcons.addView(expected, i);
+        }
+
+        applyNotificationIconsTint();
+    }
+
+    public void hideSystemIconArea(boolean animate) {
+        animateHide(mSystemIconArea, animate);
+    }
+
+    public void showSystemIconArea(boolean animate) {
+        animateShow(mSystemIconArea, animate);
+    }
+
+    public void hideNotificationIconArea(boolean animate) {
+        animateHide(mNotificationIconArea, animate);
+    }
+
+    public void showNotificationIconArea(boolean animate) {
+        animateShow(mNotificationIconArea, animate);
+    }
+
+    public void setClockVisibility(boolean visible) {
+        mClock.setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    public void dump(PrintWriter pw) {
+        int N = mStatusIcons.getChildCount();
+        pw.println("  system icons: " + N);
+        for (int i=0; i<N; i++) {
+            StatusBarIconView ic = (StatusBarIconView) mStatusIcons.getChildAt(i);
+            pw.println("    [" + i + "] icon=" + ic);
+        }
+    }
+
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (mDemoStatusIcons == null) {
+            mDemoStatusIcons = new DemoStatusIcons(mStatusIcons, mIconSize);
+        }
+        mDemoStatusIcons.dispatchDemoCommand(command, args);
+    }
+
+    /**
+     * Hides a view.
+     */
+    private void animateHide(final View v, boolean animate) {
+        v.animate().cancel();
+        if (!animate) {
+            v.setAlpha(0f);
+            v.setVisibility(View.INVISIBLE);
+            return;
+        }
+        v.animate()
+                .alpha(0f)
+                .setDuration(160)
+                .setStartDelay(0)
+                .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        v.setVisibility(View.INVISIBLE);
+                    }
+                });
+    }
+
+    /**
+     * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
+     */
+    private void animateShow(View v, boolean animate) {
+        v.animate().cancel();
+        v.setVisibility(View.VISIBLE);
+        if (!animate) {
+            v.setAlpha(1f);
+            return;
+        }
+        v.animate()
+                .alpha(1f)
+                .setDuration(320)
+                .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                .setStartDelay(50)
+
+                // We need to clean up any pending end action from animateHide if we call
+                // both hide and show in the same frame before the animation actually gets started.
+                // cancel() doesn't really remove the end action.
+                .withEndAction(null);
+
+        // Synchronize the motion with the Keyguard fading if necessary.
+        if (mPhoneStatusBar.isKeyguardFadingAway()) {
+            v.animate()
+                    .setDuration(mPhoneStatusBar.getKeyguardFadingAwayDuration())
+                    .setInterpolator(mLinearOutSlowIn)
+                    .setStartDelay(mPhoneStatusBar.getKeyguardFadingAwayDelay())
+                    .start();
+        }
+    }
+
+    public void setIconTint(int tint) {
+        if (mTransitionPending) {
+            deferIconTintChange(tint);
+        } else if (mTransitionDeferring) {
+            animateIconTint(tint,
+                    Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
+                    mTransitionDeferringDuration);
+        } else {
+            animateIconTint(tint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+        }
+    }
+
+    private void animateIconTint(int targetTint, long delay, long duration) {
+        if (mTintAnimator != null) {
+            mTintAnimator.cancel();
+        }
+        if (mIconTint == targetTint) {
+            return;
+        }
+        mTintAnimator = ValueAnimator.ofArgb(mIconTint, targetTint);
+        mTintAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setIconTintInternal((Integer) animation.getAnimatedValue());
+            }
+        });
+        mTintAnimator.setDuration(duration);
+        mTintAnimator.setStartDelay(delay);
+        mTintAnimator.setInterpolator(mFastOutSlowIn);
+        mTintAnimator.start();
+    }
+    private void setIconTintInternal(int tint) {
+        mIconTint = tint;
+        applyIconTint();
+    }
+
+    private void deferIconTintChange(int tint) {
+        if (mTintChangePending && tint == mPendingIconTint) {
+            return;
+        }
+        mTintChangePending = true;
+        mPendingIconTint = tint;
+    }
+
+    private void applyIconTint() {
+        for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
+            v.setImageTintList(ColorStateList.valueOf(mIconTint));
+        }
+        mSignalCluster.setIconTint(mIconTint);
+        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        mBatteryMeterView.setIconTint(mIconTint);
+        mClock.setTextColor(mIconTint);
+        applyNotificationIconsTint();
+    }
+
+    private void applyNotificationIconsTint() {
+        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
+            boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
+            boolean colorize = !isPreL || isGrayscale(v);
+            if (colorize) {
+                v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
+                v.setImageTintList(ColorStateList.valueOf(mIconTint));
+            }
+        }
+    }
+
+    private boolean isGrayscale(StatusBarIconView v) {
+        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
+        if (isGrayscale != null) {
+            return Boolean.TRUE.equals(isGrayscale);
+        }
+        boolean grayscale = mNotificationColorUtil.isGrayscaleIcon(v.getDrawable());
+        v.setTag(R.id.icon_is_grayscale, grayscale);
+        return grayscale;
+    }
+
+    public void appTransitionPending() {
+        mTransitionPending = true;
+    }
+
+    public void appTransitionCancelled() {
+        if (mTransitionPending && mTintChangePending) {
+            mTintChangePending = false;
+            animateIconTint(mPendingIconTint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+        }
+        mTransitionPending = false;
+    }
+
+    public void appTransitionStarting(long startTime, long duration) {
+        if (mTransitionPending && mTintChangePending) {
+            mTintChangePending = false;
+            animateIconTint(mPendingIconTint,
+                    Math.max(0, startTime - SystemClock.uptimeMillis()),
+                    duration);
+
+        } else if (mTransitionPending) {
+
+            // If we don't have a pending tint change yet, the change might come in the future until
+            // startTime is reached.
+            mTransitionDeferring = true;
+            mTransitionDeferringStartTime = startTime;
+            mTransitionDeferringDuration = duration;
+            mHandler.removeCallbacks(mTransitionDeferringDoneRunnable);
+            mHandler.postAtTime(mTransitionDeferringDoneRunnable, startTime);
+        }
+        mTransitionPending = false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 1724e70..6369d5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,6 +31,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.statusbar.CommandQueue;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 
@@ -187,10 +188,6 @@
         mStatusBarWindowManager.setKeyguardNeedsInput(needsInput);
     }
 
-    public void updateUserActivityTimeout() {
-        mStatusBarWindowManager.setKeyguardUserActivityTimeout(mBouncer.getUserActivityTimeout());
-    }
-
     public void setOccluded(boolean occluded) {
         if (occluded && !mOccluded && mShowing) {
             if (mPhoneStatusBar.isInLaunchTransition()) {
@@ -261,7 +258,7 @@
                 }
             });
         } else {
-            mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
+            mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
             boolean staying = mPhoneStatusBar.hideKeyguard();
             if (!staying) {
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
@@ -439,4 +436,12 @@
     public boolean isInputRestricted() {
         return mViewMediatorCallback.isInputRestricted();
     }
+
+    public void keyguardGoingAway() {
+        mPhoneStatusBar.keyguardGoingAway();
+    }
+
+    public void animateCollapsePanels() {
+        mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 0dbdca1..63bbf97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -27,6 +27,7 @@
 import android.view.WindowManager;
 
 import com.android.keyguard.R;
+import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.StatusBarState;
 
@@ -114,7 +115,8 @@
 
     private void applyFocusableFlag(State state) {
         if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
-                && state.bouncerShowing) {
+                && state.bouncerShowing
+                || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
@@ -144,7 +146,7 @@
         if (state.isKeyguardShowingAndNotOccluded()
                 && state.statusBarState == StatusBarState.KEYGUARD
                 && !state.qsExpanded) {
-            mLpChanged.userActivityTimeout = state.keyguardUserActivityTimeout;
+            mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
         } else {
             mLpChanged.userActivityTimeout = -1;
         }
@@ -201,11 +203,6 @@
         apply(mCurrentState);
     }
 
-    public void setKeyguardUserActivityTimeout(long timeout) {
-        mCurrentState.keyguardUserActivityTimeout = timeout;
-        apply(mCurrentState);
-    }
-
     public void setBouncerShowing(boolean showing) {
         mCurrentState.bouncerShowing = showing;
         apply(mCurrentState);
@@ -235,7 +232,6 @@
         boolean keyguardNeedsInput;
         boolean statusBarExpanded;
         boolean statusBarFocusable;
-        long keyguardUserActivityTimeout;
         boolean bouncerShowing;
         boolean keyguardFadingAway;
         boolean qsExpanded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
deleted file mode 100644
index a6ce288..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.service.notification.StatusBarNotification;
-import android.text.Layout.Alignment;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageSwitcher;
-import android.widget.TextSwitcher;
-import android.widget.TextView;
-
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarIconView;
-
-import java.util.ArrayList;
-
-public abstract class Ticker {
-    private static final int TICKER_SEGMENT_DELAY = 3000;
-
-    private Context mContext;
-    private Handler mHandler = new Handler();
-    private ArrayList<Segment> mSegments = new ArrayList();
-    private TextPaint mPaint;
-    private View mTickerView;
-    private ImageSwitcher mIconSwitcher;
-    private TextSwitcher mTextSwitcher;
-    private float mIconScale;
-
-    public static boolean isGraphicOrEmoji(char c) {
-        int gc = Character.getType(c);
-        return     gc != Character.CONTROL
-                && gc != Character.FORMAT
-                && gc != Character.UNASSIGNED
-                && gc != Character.LINE_SEPARATOR
-                && gc != Character.PARAGRAPH_SEPARATOR
-                && gc != Character.SPACE_SEPARATOR;
-    }
-
-    private final class Segment {
-        StatusBarNotification notification;
-        Drawable icon;
-        CharSequence text;
-        int current;
-        int next;
-        boolean first;
-
-        StaticLayout getLayout(CharSequence substr) {
-            int w = mTextSwitcher.getWidth() - mTextSwitcher.getPaddingLeft()
-                    - mTextSwitcher.getPaddingRight();
-            return new StaticLayout(substr, mPaint, w, Alignment.ALIGN_NORMAL, 1, 0, true);
-        }
-
-        CharSequence rtrim(CharSequence substr, int start, int end) {
-            while (end > start && !isGraphicOrEmoji(substr.charAt(end-1))) {
-                end--;
-            }
-            if (end > start) {
-                return substr.subSequence(start, end);
-            }
-            return null;
-        }
-
-        /** returns null if there is no more text */
-        CharSequence getText() {
-            if (this.current > this.text.length()) {
-                return null;
-            }
-            CharSequence substr = this.text.subSequence(this.current, this.text.length());
-            StaticLayout l = getLayout(substr);
-            int lineCount = l.getLineCount();
-            if (lineCount > 0) {
-                int start = l.getLineStart(0);
-                int end = l.getLineEnd(0);
-                this.next = this.current + end;
-                return rtrim(substr, start, end);
-            } else {
-                throw new RuntimeException("lineCount=" + lineCount + " current=" + current +
-                        " text=" + text);
-            }
-        }
-
-        /** returns null if there is no more text */
-        CharSequence advance() {
-            this.first = false;
-            int index = this.next;
-            final int len = this.text.length();
-            while (index < len && !isGraphicOrEmoji(this.text.charAt(index))) {
-                index++;
-            }
-            if (index >= len) {
-                return null;
-            }
-
-            CharSequence substr = this.text.subSequence(index, this.text.length());
-            StaticLayout l = getLayout(substr);
-            final int lineCount = l.getLineCount();
-            int i;
-            for (i=0; i<lineCount; i++) {
-                int start = l.getLineStart(i);
-                int end = l.getLineEnd(i);
-                if (i == lineCount-1) {
-                    this.next = len;
-                } else {
-                    this.next = index + l.getLineStart(i+1);
-                }
-                CharSequence result = rtrim(substr, start, end);
-                if (result != null) {
-                    this.current = index + start;
-                    return result;
-                }
-            }
-            this.current = len;
-            return null;
-        }
-
-        Segment(StatusBarNotification n, Drawable icon, CharSequence text) {
-            this.notification = n;
-            this.icon = icon;
-            this.text = text;
-            int index = 0;
-            final int len = text.length();
-            while (index < len && !isGraphicOrEmoji(text.charAt(index))) {
-                index++;
-            }
-            this.current = index;
-            this.next = index;
-            this.first = true;
-        }
-    };
-
-    public Ticker(Context context, View sb) {
-        mContext = context;
-        final Resources res = context.getResources();
-        final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
-        final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
-        mIconScale = (float)imageBounds / (float)outerBounds;
-
-        mTickerView = sb.findViewById(R.id.ticker);
-
-        mIconSwitcher = (ImageSwitcher)sb.findViewById(R.id.tickerIcon);
-        mIconSwitcher.setInAnimation(
-                    AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_in));
-        mIconSwitcher.setOutAnimation(
-                    AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_out));
-        mIconSwitcher.setScaleX(mIconScale);
-        mIconSwitcher.setScaleY(mIconScale);
-
-        mTextSwitcher = (TextSwitcher)sb.findViewById(R.id.tickerText);
-        mTextSwitcher.setInAnimation(
-                    AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_in));
-        mTextSwitcher.setOutAnimation(
-                    AnimationUtils.loadAnimation(context, com.android.internal.R.anim.push_up_out));
-
-        // Copy the paint style of one of the TextSwitchers children to use later for measuring
-        TextView text = (TextView)mTextSwitcher.getChildAt(0);
-        mPaint = text.getPaint();
-    }
-
-
-    public void addEntry(StatusBarNotification n) {
-        int initialCount = mSegments.size();
-
-        // If what's being displayed has the same text and icon, just drop it
-        // (which will let the current one finish, this happens when apps do
-        // a notification storm).
-        if (initialCount > 0) {
-            final Segment seg = mSegments.get(0);
-            if (n.getPackageName().equals(seg.notification.getPackageName())
-                    && n.getNotification().icon == seg.notification.getNotification().icon
-                    && n.getNotification().iconLevel == seg.notification.getNotification().iconLevel
-                    && charSequencesEqual(seg.notification.getNotification().tickerText,
-                        n.getNotification().tickerText)) {
-                return;
-            }
-        }
-
-        final Drawable icon = StatusBarIconView.getIcon(mContext,
-                new StatusBarIcon(n.getPackageName(), n.getUser(), n.getNotification().icon, n.getNotification().iconLevel, 0,
-                        n.getNotification().tickerText));
-        final CharSequence text = n.getNotification().tickerText;
-        final Segment newSegment = new Segment(n, icon, text);
-
-        // If there's already a notification schedule for this package and id, remove it.
-        for (int i=0; i<mSegments.size(); i++) {
-            Segment seg = mSegments.get(i);
-            if (n.getId() == seg.notification.getId() && n.getPackageName().equals(seg.notification.getPackageName())) {
-                // just update that one to use this new data instead
-                mSegments.remove(i--); // restart iteration here
-            }
-        }
-
-        mSegments.add(newSegment);
-
-        if (initialCount == 0 && mSegments.size() > 0) {
-            Segment seg = mSegments.get(0);
-            seg.first = false;
-
-            mIconSwitcher.setAnimateFirstView(false);
-            mIconSwitcher.reset();
-            mIconSwitcher.setImageDrawable(seg.icon);
-
-            mTextSwitcher.setAnimateFirstView(false);
-            mTextSwitcher.reset();
-            mTextSwitcher.setText(seg.getText());
-
-            tickerStarting();
-            scheduleAdvance();
-        }
-    }
-
-    private static boolean charSequencesEqual(CharSequence a, CharSequence b) {
-        if (a.length() != b.length()) {
-            return false;
-        }
-
-        int length = a.length();
-        for (int i = 0; i < length; i++) {
-            if (a.charAt(i) != b.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public void removeEntry(StatusBarNotification n) {
-        for (int i=mSegments.size()-1; i>=0; i--) {
-            Segment seg = mSegments.get(i);
-            if (n.getId() == seg.notification.getId() && n.getPackageName().equals(seg.notification.getPackageName())) {
-                mSegments.remove(i);
-            }
-        }
-    }
-
-    public void halt() {
-        mHandler.removeCallbacks(mAdvanceTicker);
-        mSegments.clear();
-        tickerHalting();
-    }
-
-    public void reflowText() {
-        if (mSegments.size() > 0) {
-            Segment seg = mSegments.get(0);
-            CharSequence text = seg.getText();
-            mTextSwitcher.setCurrentText(text);
-        }
-    }
-
-    private Runnable mAdvanceTicker = new Runnable() {
-        public void run() {
-            while (mSegments.size() > 0) {
-                Segment seg = mSegments.get(0);
-
-                if (seg.first) {
-                    // this makes the icon slide in for the first one for a given
-                    // notification even if there are two notifications with the
-                    // same icon in a row
-                    mIconSwitcher.setImageDrawable(seg.icon);
-                }
-                CharSequence text = seg.advance();
-                if (text == null) {
-                    mSegments.remove(0);
-                    continue;
-                }
-                mTextSwitcher.setText(text);
-
-                scheduleAdvance();
-                break;
-            }
-            if (mSegments.size() == 0) {
-                tickerDone();
-            }
-        }
-    };
-
-    private void scheduleAdvance() {
-        mHandler.postDelayed(mAdvanceTicker, TICKER_SEGMENT_DELAY);
-    }
-
-    public abstract void tickerStarting();
-    public abstract void tickerDone();
-    public abstract void tickerHalting();
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
deleted file mode 100644
index bf13751..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.TextSwitcher;
-
-
-public class TickerView extends TextSwitcher
-{
-    Ticker mTicker;
-
-    public TickerView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        if (mTicker != null) mTicker.reflowText();
-    }
-
-    public void setTicker(Ticker t) {
-        mTicker = t;
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index b89aa8f..56c1e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -120,7 +120,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
+    public void setColorFilter(ColorFilter colorFilter) {
         throw new UnsupportedOperationException("not implemented");
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java
index 4f43b4d..e153b85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java
@@ -20,8 +20,6 @@
 
 import com.android.systemui.R;
 
-import static android.util.Pools.SynchronizedPool;
-
 /**
  * A class to generate {@link VelocityTrackerInterface}, depending on the configuration.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index ad4c211..18983ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -17,35 +17,25 @@
 package com.android.systemui.statusbar.policy;
 
 import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.ActionListener;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTracker.WifiListener;
 import com.android.systemui.R;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
-
-// TODO: Unify this logic with platform settings (see WifiSettings and AccessPoint). There is a
-// fair amount of complexity here in statuses and logic beyond just connected/disconnected.
-public class AccessPointControllerImpl implements NetworkController.AccessPointController {
+public class AccessPointControllerImpl
+        implements NetworkController.AccessPointController, WifiListener {
     private static final String TAG = "AccessPointController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -63,25 +53,18 @@
 
     private final Context mContext;
     private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
-    private final WifiManager mWifiManager;
+    private final WifiTracker mWifiTracker;
     private final UserManager mUserManager;
-    private final Receiver mReceiver = new Receiver();
 
-    private NetworkControllerImpl mNetworkController;
-    private boolean mScanning;
     private int mCurrentUser;
 
     public AccessPointControllerImpl(Context context) {
         mContext = context;
-        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mWifiTracker = new WifiTracker(context, this, false, true);
         mCurrentUser = ActivityManager.getCurrentUser();
     }
 
-    void setNetworkController(NetworkControllerImpl networkController) {
-        mNetworkController = networkController;
-    }
-
     public boolean canConfigWifi() {
         return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI,
                 new UserHandle(mCurrentUser));
@@ -96,7 +79,9 @@
         if (callback == null || mCallbacks.contains(callback)) return;
         if (DEBUG) Log.d(TAG, "addCallback " + callback);
         mCallbacks.add(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        if (mCallbacks.size() == 1) {
+            mWifiTracker.startTracking();
+        }
     }
 
     @Override
@@ -104,37 +89,40 @@
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
         mCallbacks.remove(callback);
-        mReceiver.setListening(!mCallbacks.isEmpty());
+        if (mCallbacks.isEmpty()) {
+            mWifiTracker.stopTracking();
+        }
     }
 
     @Override
     public void scanForAccessPoints() {
-        if (mScanning) return;
         if (DEBUG) Log.d(TAG, "scan!");
-        mScanning = mWifiManager.startScan();
-        // Grab current networks immediately while we wait for scan.
-        updateAccessPoints();
+        mWifiTracker.forceScan();
+    }
+
+    @Override
+    public int getIcon(AccessPoint ap) {
+        int level = ap.getLevel();
+        return ICONS[level >= 0 ? level : 0];
     }
 
     public boolean connect(AccessPoint ap) {
         if (ap == null) return false;
-        if (DEBUG) Log.d(TAG, "connect networkId=" + ap.networkId);
-        if (ap.networkId < 0) {
+        if (DEBUG) Log.d(TAG, "connect networkId=" + ap.getConfig().networkId);
+        if (ap.isSaved()) {
+            mWifiTracker.getManager().connect(ap.getConfig().networkId, mConnectListener);
+        } else {
             // Unknown network, need to add it.
-            if (ap.hasSecurity) {
+            if (ap.getSecurity() != AccessPoint.SECURITY_NONE) {
                 Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
-                intent.putExtra(EXTRA_START_CONNECT_SSID, ap.ssid);
+                intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsid());
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 fireSettingsIntentCallback(intent);
                 return true;
             } else {
-                WifiConfiguration config = new WifiConfiguration();
-                config.SSID = "\"" + ap.ssid + "\"";
-                config.allowedKeyManagement.set(KeyMgmt.NONE);
-                mWifiManager.connect(config, mConnectListener);
+                ap.generateOpenNetworkConfig();
+                mWifiTracker.getManager().connect(ap.getConfig(), mConnectListener);
             }
-        } else {
-            mWifiManager.connect(ap.networkId, mConnectListener);
         }
         return false;
     }
@@ -145,76 +133,28 @@
         }
     }
 
-    private void fireAcccessPointsCallback(AccessPoint[] aps) {
+    private void fireAcccessPointsCallback(List<AccessPoint> aps) {
         for (AccessPointCallback callback : mCallbacks) {
             callback.onAccessPointsChanged(aps);
         }
     }
 
-    private static String trimDoubleQuotes(String v) {
-        return v != null && v.length() >= 2 && v.charAt(0) == '\"'
-                && v.charAt(v.length() - 1) == '\"' ? v.substring(1, v.length() - 1) : v;
+    public void dump(PrintWriter pw) {
+        mWifiTracker.dump(pw);
     }
 
-    private int getConnectedNetworkId(WifiInfo wifiInfo) {
-        return wifiInfo != null ? wifiInfo.getNetworkId() : AccessPoint.NO_NETWORK;
+    @Override
+    public void onWifiStateChanged(int state) {
     }
 
-    private ArrayMap<String, WifiConfiguration> getConfiguredNetworksBySsid() {
-        final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
-        if (configs == null || configs.size() == 0) return ArrayMap.EMPTY;
-        final ArrayMap<String, WifiConfiguration> rt = new ArrayMap<String, WifiConfiguration>();
-        for (WifiConfiguration config : configs) {
-            rt.put(trimDoubleQuotes(config.SSID), config);
-        }
-        return rt;
+    @Override
+    public void onConnectedChanged() {
+        fireAcccessPointsCallback(mWifiTracker.getAccessPoints());
     }
 
-    private void updateAccessPoints() {
-        final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-        final int connectedNetworkId = getConnectedNetworkId(wifiInfo);
-        if (DEBUG) Log.d(TAG, "connectedNetworkId: " + connectedNetworkId);
-        final List<ScanResult> scanResults = mWifiManager.getScanResults();
-        final ArrayMap<String, WifiConfiguration> configured = getConfiguredNetworksBySsid();
-        if (DEBUG) Log.d(TAG, "scanResults: " + scanResults);
-        final List<AccessPoint> aps = new ArrayList<AccessPoint>(scanResults.size());
-        final ArraySet<String> ssids = new ArraySet<String>();
-        for (ScanResult scanResult : scanResults) {
-            if (scanResult == null) {
-                continue;
-            }
-            final String ssid = scanResult.SSID;
-            if (TextUtils.isEmpty(ssid) || ssids.contains(ssid)) continue;
-            ssids.add(ssid);
-            final WifiConfiguration config = configured.get(ssid);
-            final int level = WifiManager.calculateSignalLevel(scanResult.level, ICONS.length);
-            final AccessPoint ap = new AccessPoint();
-            ap.isConfigured = config != null;
-            ap.networkId = config != null ? config.networkId : AccessPoint.NO_NETWORK;
-            ap.ssid = ssid;
-            // Connected if either:
-            // -The network ID in the active WifiInfo matches this network's ID.
-            // -The network is ephemeral (no configuration) but the SSID matches.
-            ap.isConnected = (ap.networkId != AccessPoint.NO_NETWORK
-                    && ap.networkId == connectedNetworkId) ||
-                    (ap.networkId == WifiConfiguration.INVALID_NETWORK_ID && wifiInfo != null &&
-                    ap.ssid.equals(trimDoubleQuotes(wifiInfo.getSSID())));
-            if (ap.isConnected && mNetworkController != null) {
-                // Ensure we have the connected network's RSSI.
-                ap.level = mNetworkController.getConnectedWifiLevel();
-            } else {
-                ap.level = level;
-            }
-            ap.iconId = ICONS[ap.level];
-            // Based on Settings AccessPoint#getSecurity, keep up to date
-            // with better methods of determining no security or not.
-            ap.hasSecurity = scanResult.capabilities.contains("WEP")
-                    || scanResult.capabilities.contains("PSK")
-                    || scanResult.capabilities.contains("EAP");
-            aps.add(ap);
-        }
-        Collections.sort(aps, mByStrength);
-        fireAcccessPointsCallback(aps.toArray(new AccessPoint[aps.size()]));
+    @Override
+    public void onAccessPointsChanged() {
+        fireAcccessPointsCallback(mWifiTracker.getAccessPoints());
     }
 
     private final ActionListener mConnectListener = new ActionListener() {
@@ -228,49 +168,4 @@
             if (DEBUG) Log.d(TAG, "connect failure reason=" + reason);
         }
     };
-
-    private final Comparator<AccessPoint> mByStrength = new Comparator<AccessPoint> () {
-        @Override
-        public int compare(AccessPoint lhs, AccessPoint rhs) {
-            return -Integer.compare(score(lhs), score(rhs));
-        }
-
-        private int score(AccessPoint ap) {
-            return ap.level + (ap.isConnected ? 20 : 0) + (ap.isConfigured ? 10 : 0);
-        }
-    };
-
-    private final class Receiver extends BroadcastReceiver {
-        private boolean mRegistered;
-
-        public void setListening(boolean listening) {
-            if (listening && !mRegistered) {
-                if (DEBUG) Log.d(TAG, "Registering receiver");
-                final IntentFilter filter = new IntentFilter();
-                filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
-                filter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
-                filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
-                filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-                filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-                filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
-                mContext.registerReceiver(this, filter);
-                mRegistered = true;
-            } else if (!listening && mRegistered) {
-                if (DEBUG) Log.d(TAG, "Unregistering receiver");
-                mContext.unregisterReceiver(this);
-                mRegistered = false;
-            }
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
-            if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
-                updateAccessPoints();
-                mScanning = false;
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityController.java
index 89ed787..cc431dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityController.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.policy;
 
 import android.content.Context;
-import android.util.Log;
 import android.view.accessibility.AccessibilityManager;
 
 import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index cbdd138..cbe4c4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar.policy;
 
-import java.util.Set;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import java.util.Collection;
 
 public interface BluetoothController {
     void addStateChangedCallback(Callback callback);
@@ -28,32 +30,12 @@
     boolean isBluetoothConnecting();
     String getLastDeviceName();
     void setBluetoothEnabled(boolean enabled);
-    Set<PairedDevice> getPairedDevices();
-    void connect(PairedDevice device);
-    void disconnect(PairedDevice device);
+    Collection<CachedBluetoothDevice> getDevices();
+    void connect(CachedBluetoothDevice device);
+    void disconnect(CachedBluetoothDevice device);
 
     public interface Callback {
         void onBluetoothStateChange(boolean enabled, boolean connecting);
-        void onBluetoothPairedDevicesChanged();
-    }
-
-    public static final class PairedDevice {
-        public static int STATE_DISCONNECTED = 0;
-        public static int STATE_CONNECTING = 1;
-        public static int STATE_CONNECTED = 2;
-        public static int STATE_DISCONNECTING = 3;
-
-        public String id;
-        public String name;
-        public int state = STATE_DISCONNECTED;
-        public Object tag;
-
-        public static String stateToString(int state) {
-            if (state == STATE_DISCONNECTED) return "STATE_DISCONNECTED";
-            if (state == STATE_CONNECTING) return "STATE_CONNECTING";
-            if (state == STATE_CONNECTED) return "STATE_CONNECTED";
-            if (state == STATE_DISCONNECTING) return "STATE_DISCONNECTING";
-            return "UNKNOWN";
-        }
+        void onBluetoothDevicesChanged();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 81e1e45..8d4f302 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,138 +16,57 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static android.bluetooth.BluetoothAdapter.ERROR;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.connectionStateToString;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.deviceToString;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.profileToString;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToProfile;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToString;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidsToString;
-
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothA2dpSink;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothInputDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothMap;
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelUuid;
-import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
-import android.util.SparseArray;
 
-import com.android.systemui.statusbar.policy.BluetoothUtil.Profile;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Set;
+import java.util.Collection;
 
-public class BluetoothControllerImpl implements BluetoothController {
+public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
+        CachedBluetoothDevice.Callback {
     private static final String TAG = "BluetoothController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    // This controls the order in which we check the states.  Since a device can only have
-    // one state on screen, but can have multiple profiles, the later states override the
-    // value of earlier states.  So if a device has a profile in CONNECTING and one in
-    // CONNECTED, it will show as CONNECTED, theoretically this shouldn't really happen often,
-    // but seemed worth noting.
-    private static final int[] CONNECTION_STATES = {
-        BluetoothProfile.STATE_DISCONNECTED,
-        BluetoothProfile.STATE_DISCONNECTING,
-        BluetoothProfile.STATE_CONNECTING,
-        BluetoothProfile.STATE_CONNECTED,
-    };
-    // Update all the BT device states.
-    private static final int MSG_UPDATE_CONNECTION_STATES = 1;
-    // Update just one BT device.
-    private static final int MSG_UPDATE_SINGLE_CONNECTION_STATE = 2;
-    // Update whether devices are bonded or not.
-    private static final int MSG_UPDATE_BONDED_DEVICES = 3;
 
-    private static final int MSG_ADD_PROFILE = 4;
-    private static final int MSG_REM_PROFILE = 5;
-
-    private final Context mContext;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
-    private final BluetoothAdapter mAdapter;
-    private final Receiver mReceiver = new Receiver();
-    private final ArrayMap<BluetoothDevice, DeviceInfo> mDeviceInfo = new ArrayMap<>();
-    private final SparseArray<BluetoothProfile> mProfiles = new SparseArray<>();
-
-    private final H mHandler;
+    private final LocalBluetoothManager mLocalBluetoothManager;
 
     private boolean mEnabled;
     private boolean mConnecting;
-    private BluetoothDevice mLastDevice;
+    private CachedBluetoothDevice mLastDevice;
 
     public BluetoothControllerImpl(Context context, Looper bgLooper) {
-        mContext = context;
-        mHandler = new H(bgLooper);
-
-        final BluetoothManager bluetoothManager =
-                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
-        mAdapter = bluetoothManager.getAdapter();
-        if (mAdapter == null) {
-            Log.w(TAG, "Default BT adapter not found");
-            return;
+        mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, null);
+        if (mLocalBluetoothManager != null) {
+            mLocalBluetoothManager.getEventManager().registerCallback(this);
+            onBluetoothStateChanged(
+                    mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
         }
-
-        mReceiver.register();
-        setAdapterState(mAdapter.getState());
-        updateBondedDevices();
-        bindAllProfiles();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("BluetoothController state:");
-        pw.print("  mAdapter="); pw.println(mAdapter);
+        pw.print("  mLocalBluetoothManager="); pw.println(mLocalBluetoothManager);
         pw.print("  mEnabled="); pw.println(mEnabled);
         pw.print("  mConnecting="); pw.println(mConnecting);
         pw.print("  mLastDevice="); pw.println(mLastDevice);
         pw.print("  mCallbacks.size="); pw.println(mCallbacks.size());
-        pw.print("  mProfiles="); pw.println(profilesToString(mProfiles));
-        pw.print("  mDeviceInfo.size="); pw.println(mDeviceInfo.size());
-        for (int i = 0; i < mDeviceInfo.size(); i++) {
-            final BluetoothDevice device = mDeviceInfo.keyAt(i);
-            final DeviceInfo info = mDeviceInfo.valueAt(i);
-            pw.print("    "); pw.print(deviceToString(device));
-            pw.print('('); pw.print(uuidsToString(device)); pw.print(')');
-            pw.print("    "); pw.println(infoToString(info));
+        pw.println("  Bluetooth Devices:");
+        for (CachedBluetoothDevice device :
+                mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
+            pw.println("    " + getDeviceString(device));
         }
     }
 
-    private static String infoToString(DeviceInfo info) {
-        return info == null ? null : ("connectionState=" +
-                connectionStateToString(CONNECTION_STATES[info.connectionStateIndex])
-                + ",bonded=" + info.bonded + ",profiles="
-                + profilesToString(info.connectedProfiles));
-    }
-
-    private static String profilesToString(SparseArray<?> profiles) {
-        final int N = profiles.size();
-        final StringBuffer buffer = new StringBuffer();
-        buffer.append('[');
-        for (int i = 0; i < N; i++) {
-            if (i != 0) {
-                buffer.append(',');
-            }
-            buffer.append(BluetoothUtil.profileToString(profiles.keyAt(i)));
-        }
-        buffer.append(']');
-        return buffer.toString();
+    private String getDeviceString(CachedBluetoothDevice device) {
+        return device.getName() + " " + device.getBondState() + " " + device.isConnected();
     }
 
     public void addStateChangedCallback(Callback cb) {
@@ -162,266 +81,63 @@
 
     @Override
     public boolean isBluetoothEnabled() {
-        return mAdapter != null && mAdapter.isEnabled();
+        return mEnabled;
     }
 
     @Override
     public boolean isBluetoothConnected() {
-        return mAdapter != null
-                && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+        return mLocalBluetoothManager != null
+                && mLocalBluetoothManager.getBluetoothAdapter().getConnectionState()
+                == BluetoothAdapter.STATE_CONNECTED;
     }
 
     @Override
     public boolean isBluetoothConnecting() {
-        return mAdapter != null
-                && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTING;
+        return mConnecting;
     }
 
     @Override
     public void setBluetoothEnabled(boolean enabled) {
-        if (mAdapter != null) {
-            if (enabled) {
-                mAdapter.enable();
-            } else {
-                mAdapter.disable();
-            }
+        if (mLocalBluetoothManager != null) {
+            mLocalBluetoothManager.getBluetoothAdapter().setBluetoothEnabled(enabled);
         }
     }
 
     @Override
     public boolean isBluetoothSupported() {
-        return mAdapter != null;
+        return mLocalBluetoothManager != null;
     }
 
     @Override
-    public ArraySet<PairedDevice> getPairedDevices() {
-        final ArraySet<PairedDevice> rt = new ArraySet<>();
-        for (int i = 0; i < mDeviceInfo.size(); i++) {
-            final BluetoothDevice device = mDeviceInfo.keyAt(i);
-            final DeviceInfo info = mDeviceInfo.valueAt(i);
-            if (!info.bonded) continue;
-            final PairedDevice paired = new PairedDevice();
-            paired.id = device.getAddress();
-            paired.tag = device;
-            paired.name = device.getAliasName();
-            paired.state = connectionStateToPairedDeviceState(info.connectionStateIndex);
-            rt.add(paired);
-        }
-        return rt;
-    }
-
-    private static int connectionStateToPairedDeviceState(int index) {
-        int state = CONNECTION_STATES[index];
-        if (state == BluetoothAdapter.STATE_CONNECTED) return PairedDevice.STATE_CONNECTED;
-        if (state == BluetoothAdapter.STATE_CONNECTING) return PairedDevice.STATE_CONNECTING;
-        if (state == BluetoothAdapter.STATE_DISCONNECTING) return PairedDevice.STATE_DISCONNECTING;
-        return PairedDevice.STATE_DISCONNECTED;
+    public void connect(final CachedBluetoothDevice device) {
+        if (mLocalBluetoothManager == null || device == null) return;
+        device.connect(true);
     }
 
     @Override
-    public void connect(final PairedDevice pd) {
-        connect(pd, true);
-    }
-
-    @Override
-    public void disconnect(PairedDevice pd) {
-        connect(pd, false);
-    }
-
-    private void connect(PairedDevice pd, final boolean connect) {
-        if (mAdapter == null || pd == null || pd.tag == null) return;
-        final BluetoothDevice device = (BluetoothDevice) pd.tag;
-        final DeviceInfo info = mDeviceInfo.get(device);
-        final String action = connect ? "connect" : "disconnect";
-        if (DEBUG) Log.d(TAG, action + " " + deviceToString(device));
-        final ParcelUuid[] uuids = device.getUuids();
-        if (uuids == null) {
-            Log.w(TAG, "No uuids returned, aborting " + action + " for " + deviceToString(device));
-            return;
-        }
-        SparseArray<Boolean> profiles = new SparseArray<>();
-        if (connect) {
-            // When connecting add every profile we can recognize by uuid.
-            for (ParcelUuid uuid : uuids) {
-                final int profile = uuidToProfile(uuid);
-                if (profile == 0) {
-                    Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: "
-                            + uuidToString(uuid));
-                    continue;
-                }
-                final boolean connected = info.connectedProfiles.get(profile, false);
-                if (!connected) {
-                    profiles.put(profile, true);
-                }
-            }
-        } else {
-            // When disconnecting, just add every profile we know they are connected to.
-            profiles = info.connectedProfiles;
-        }
-        for (int i = 0; i < profiles.size(); i++) {
-            final int profile = profiles.keyAt(i);
-            if (mProfiles.indexOfKey(profile) >= 0) {
-                final Profile p = BluetoothUtil.getProfile(mProfiles.get(profile));
-                final boolean ok = connect ? p.connect(device) : p.disconnect(device);
-                if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " "
-                        + (ok ? "succeeded" : "failed"));
-            } else {
-                Log.w(TAG, "Unable get get Profile for " + profileToString(profile));
-            }
-        }
+    public void disconnect(CachedBluetoothDevice device) {
+        if (mLocalBluetoothManager == null || device == null) return;
+        device.disconnect();
     }
 
     @Override
     public String getLastDeviceName() {
-        return mLastDevice != null ? mLastDevice.getAliasName() : null;
+        return mLastDevice != null ? mLastDevice.getName() : null;
     }
 
-    private void updateBondedDevices() {
-        mHandler.removeMessages(MSG_UPDATE_BONDED_DEVICES);
-        mHandler.sendEmptyMessage(MSG_UPDATE_BONDED_DEVICES);
-    }
-
-    private void updateConnectionStates() {
-        mHandler.removeMessages(MSG_UPDATE_CONNECTION_STATES);
-        mHandler.removeMessages(MSG_UPDATE_SINGLE_CONNECTION_STATE);
-        mHandler.sendEmptyMessage(MSG_UPDATE_CONNECTION_STATES);
-    }
-
-    private void updateConnectionState(BluetoothDevice device, int profile, int state) {
-        if (mHandler.hasMessages(MSG_UPDATE_CONNECTION_STATES)) {
-            // If we are about to update all the devices, then we don't need to update this one.
-            return;
-        }
-        mHandler.obtainMessage(MSG_UPDATE_SINGLE_CONNECTION_STATE, profile, state, device)
-                .sendToTarget();
-    }
-
-    private void handleUpdateBondedDevices() {
-        if (mAdapter == null) return;
-        final Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
-        for (DeviceInfo info : mDeviceInfo.values()) {
-            info.bonded = false;
-        }
-        int bondedCount = 0;
-        BluetoothDevice lastBonded = null;
-        if (bondedDevices != null) {
-            for (BluetoothDevice bondedDevice : bondedDevices) {
-                final boolean bonded = bondedDevice.getBondState() != BluetoothDevice.BOND_NONE;
-                updateInfo(bondedDevice).bonded = bonded;
-                if (bonded) {
-                    bondedCount++;
-                    lastBonded = bondedDevice;
-                }
-            }
-        }
-        if (mLastDevice == null && bondedCount == 1) {
-            mLastDevice = lastBonded;
-        }
-        updateConnectionStates();
-        firePairedDevicesChanged();
-    }
-
-    private void handleUpdateConnectionStates() {
-        final int N = mDeviceInfo.size();
-        for (int i = 0; i < N; i++) {
-            BluetoothDevice device = mDeviceInfo.keyAt(i);
-            DeviceInfo info = updateInfo(device);
-            info.connectionStateIndex = 0;
-            info.connectedProfiles.clear();
-            for (int j = 0; j < mProfiles.size(); j++) {
-                int state = mProfiles.valueAt(j).getConnectionState(device);
-                handleUpdateConnectionState(device, mProfiles.keyAt(j), state);
-            }
-        }
-        handleConnectionChange();
-        firePairedDevicesChanged();
-    }
-
-    private void handleUpdateConnectionState(BluetoothDevice device, int profile, int state) {
-        if (DEBUG) Log.d(TAG, "updateConnectionState " + BluetoothUtil.deviceToString(device)
-                + " " + BluetoothUtil.profileToString(profile)
-                + " " + BluetoothUtil.connectionStateToString(state));
-        DeviceInfo info = updateInfo(device);
-        int stateIndex = 0;
-        for (int i = 0; i < CONNECTION_STATES.length; i++) {
-            if (CONNECTION_STATES[i] == state) {
-                stateIndex = i;
-                break;
-            }
-        }
-        info.profileStates.put(profile, stateIndex);
-
-        info.connectionStateIndex = 0;
-        final int N = info.profileStates.size();
-        for (int i = 0; i < N; i++) {
-            if (info.profileStates.valueAt(i) > info.connectionStateIndex) {
-                info.connectionStateIndex = info.profileStates.valueAt(i);
-            }
-        }
-        if (state == BluetoothProfile.STATE_CONNECTED) {
-            info.connectedProfiles.put(profile, true);
-        } else {
-            info.connectedProfiles.remove(profile);
-        }
-    }
-
-    private void handleConnectionChange() {
-        // If we are no longer connected to the current device, see if we are connected to
-        // something else, so we don't display a name we aren't connected to.
-        if (mLastDevice != null &&
-                CONNECTION_STATES[mDeviceInfo.get(mLastDevice).connectionStateIndex]
-                        != BluetoothProfile.STATE_CONNECTED) {
-            // Make sure we don't keep this device while it isn't connected.
-            mLastDevice = null;
-            // Look for anything else connected.
-            final int size = mDeviceInfo.size();
-            for (int i = 0; i < size; i++) {
-                BluetoothDevice device = mDeviceInfo.keyAt(i);
-                DeviceInfo info = mDeviceInfo.valueAt(i);
-                if (CONNECTION_STATES[info.connectionStateIndex]
-                        == BluetoothProfile.STATE_CONNECTED) {
-                    mLastDevice = device;
-                    break;
-                }
-            }
-        }
-    }
-
-    private void bindAllProfiles() {
-        // Note: This needs to contain all of the types that can be returned by BluetoothUtil
-        // otherwise we can't find the profiles we need when we connect/disconnect.
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP_SINK);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.AVRCP_CONTROLLER);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET_CLIENT);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.INPUT_DEVICE);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.MAP);
-        mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.PAN);
-        // Note Health is not in this list because health devices aren't 'connected'.
-        // If profiles are expanded to use more than just connection state and connect/disconnect
-        // then it should be added.
+    @Override
+    public Collection<CachedBluetoothDevice> getDevices() {
+        return mLocalBluetoothManager != null
+                ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
+                : null;
     }
 
     private void firePairedDevicesChanged() {
         for (Callback cb : mCallbacks) {
-            cb.onBluetoothPairedDevicesChanged();
+            cb.onBluetoothDevicesChanged();
         }
     }
 
-    private void setAdapterState(int adapterState) {
-        final boolean enabled = adapterState == BluetoothAdapter.STATE_ON;
-        if (mEnabled == enabled) return;
-        mEnabled = enabled;
-        fireStateChange();
-    }
-
-    private void setConnecting(boolean connecting) {
-        if (mConnecting == connecting) return;
-        mConnecting = connecting;
-        fireStateChange();
-    }
-
     private void fireStateChange() {
         for (Callback cb : mCallbacks) {
             fireStateChange(cb);
@@ -432,141 +148,59 @@
         cb.onBluetoothStateChange(mEnabled, mConnecting);
     }
 
-    private static int getProfileFromAction(String action) {
-        if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.A2DP;
-        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.HEADSET;
-        } else if (BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.A2DP_SINK;
-        } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.HEADSET_CLIENT;
-        } else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.INPUT_DEVICE;
-        } else if (BluetoothMap.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.MAP;
-        } else if (BluetoothPan.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
-            return BluetoothProfile.PAN;
+    private void updateConnected() {
+        if (mLastDevice != null && mLastDevice.isConnected()) {
+            // Our current device is still valid.
+            return;
         }
-        if (DEBUG) Log.d(TAG, "Unknown action " + action);
-        return -1;
-    }
-
-    private final ServiceListener mProfileListener = new ServiceListener() {
-        @Override
-        public void onServiceDisconnected(int profile) {
-            if (DEBUG) Log.d(TAG, "Disconnected from " + BluetoothUtil.profileToString(profile));
-            // We lost a profile, don't do any updates until it gets removed.
-            mHandler.removeMessages(MSG_UPDATE_CONNECTION_STATES);
-            mHandler.removeMessages(MSG_UPDATE_SINGLE_CONNECTION_STATE);
-            mHandler.obtainMessage(MSG_REM_PROFILE, profile, 0).sendToTarget();
-        }
-
-        @Override
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (DEBUG) Log.d(TAG, "Connected to " + BluetoothUtil.profileToString(profile));
-            mHandler.obtainMessage(MSG_ADD_PROFILE, profile, 0, proxy).sendToTarget();
-        }
-    };
-
-    private final class Receiver extends BroadcastReceiver {
-        public void register() {
-            final IntentFilter filter = new IntentFilter();
-            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-            filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
-            filter.addAction(BluetoothDevice.ACTION_ALIAS_CHANGED);
-            filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
-            filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
-            mContext.registerReceiver(this, filter);
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
-            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-                setAdapterState(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, ERROR));
-                updateBondedDevices();
-                if (DEBUG) Log.d(TAG, "ACTION_STATE_CHANGED " + mEnabled);
-            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
-                updateInfo(device);
-                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
-                        ERROR);
+        for (CachedBluetoothDevice device : getDevices()) {
+            if (device.isConnected()) {
                 mLastDevice = device;
-                if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED "
-                        + connectionStateToString(state) + " " + deviceToString(device));
-                setConnecting(state == BluetoothAdapter.STATE_CONNECTING);
-            } else if (action.equals(BluetoothDevice.ACTION_ALIAS_CHANGED)) {
-                updateInfo(device);
-                mLastDevice = device;
-            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
-                if (DEBUG) Log.d(TAG, "ACTION_BOND_STATE_CHANGED " + device);
-                updateBondedDevices();
-            } else {
-                int profile = getProfileFromAction(intent.getAction());
-                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-                if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGE "
-                        + BluetoothUtil.profileToString(profile)
-                        + " " + BluetoothUtil.connectionStateToString(state));
-                if ((profile != -1) && (state != -1)) {
-                    updateConnectionState(device, profile, state);
-                }
             }
         }
     }
 
-    private DeviceInfo updateInfo(BluetoothDevice device) {
-        DeviceInfo info = mDeviceInfo.get(device);
-        info = info != null ? info : new DeviceInfo();
-        mDeviceInfo.put(device, info);
-        return info;
+    @Override
+    public void onBluetoothStateChanged(int bluetoothState) {
+        mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
+        fireStateChange();
     }
 
-    private class H extends Handler {
-        public H(Looper l) {
-            super(l);
-        }
+    @Override
+    public void onScanningStateChanged(boolean started) {
+        // Don't care.
+    }
 
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_CONNECTION_STATES:
-                    handleUpdateConnectionStates();
-                    firePairedDevicesChanged();
-                    break;
-                case MSG_UPDATE_SINGLE_CONNECTION_STATE:
-                    handleUpdateConnectionState((BluetoothDevice) msg.obj, msg.arg1, msg.arg2);
-                    handleConnectionChange();
-                    firePairedDevicesChanged();
-                    break;
-                case MSG_UPDATE_BONDED_DEVICES:
-                    handleUpdateBondedDevices();
-                    firePairedDevicesChanged();
-                    break;
-                case MSG_ADD_PROFILE:
-                    mProfiles.put(msg.arg1, (BluetoothProfile) msg.obj);
-                    handleUpdateConnectionStates();
-                    firePairedDevicesChanged();
-                    break;
-                case MSG_REM_PROFILE:
-                    mProfiles.remove(msg.arg1);
-                    handleUpdateConnectionStates();
-                    firePairedDevicesChanged();
-                    break;
-            }
-        };
-    };
+    @Override
+    public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
+        cachedDevice.registerCallback(this);
+        updateConnected();
+        firePairedDevicesChanged();
+    }
 
-    private static class DeviceInfo {
-        int connectionStateIndex = 0;
-        boolean bonded;  // per getBondedDevices
-        SparseArray<Boolean> connectedProfiles = new SparseArray<>();
-        SparseArray<Integer> profileStates = new SparseArray<>();
+    @Override
+    public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+        updateConnected();
+        firePairedDevicesChanged();
+    }
+
+    @Override
+    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+        updateConnected();
+        firePairedDevicesChanged();
+    }
+
+    @Override
+    public void onDeviceAttributesChanged() {
+        updateConnected();
+        firePairedDevicesChanged();
+    }
+
+    @Override
+    public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+        mConnecting = state == BluetoothAdapter.STATE_CONNECTING;
+        mLastDevice = cachedDevice;
+        updateConnected();
+        fireStateChange();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java
deleted file mode 100644
index ed8ac2c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java
+++ /dev/null
@@ -1,234 +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.policy;
-
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothA2dpSink;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothInputDevice;
-import android.bluetooth.BluetoothMap;
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothUuid;
-import android.os.ParcelUuid;
-import android.text.TextUtils;
-
-public class BluetoothUtil {
-
-    public static String profileToString(int profile) {
-        if (profile == BluetoothProfile.HEADSET) return "HEADSET";
-        if (profile == BluetoothProfile.A2DP) return "A2DP";
-        if (profile == BluetoothProfile.AVRCP_CONTROLLER) return "AVRCP_CONTROLLER";
-        if (profile == BluetoothProfile.PAN) return "PAN";
-        if (profile == BluetoothProfile.INPUT_DEVICE) return "INPUT_DEVICE";
-        if (profile == BluetoothProfile.MAP) return "MAP";
-        return "UNKNOWN(" + profile + ")";
-    }
-
-    public static String profileStateToString(int state) {
-        if (state == BluetoothProfile.STATE_CONNECTED) return "STATE_CONNECTED";
-        if (state == BluetoothProfile.STATE_CONNECTING) return "STATE_CONNECTING";
-        if (state == BluetoothProfile.STATE_DISCONNECTED) return "STATE_DISCONNECTED";
-        if (state == BluetoothProfile.STATE_DISCONNECTING) return "STATE_DISCONNECTING";
-        return "STATE_UNKNOWN";
-    }
-
-    public static String uuidToString(ParcelUuid uuid) {
-        if (BluetoothUuid.AudioSink.equals(uuid)) return "AudioSink";
-        if (BluetoothUuid.AudioSource.equals(uuid)) return "AudioSource";
-        if (BluetoothUuid.AdvAudioDist.equals(uuid)) return "AdvAudioDist";
-        if (BluetoothUuid.HSP.equals(uuid)) return "HSP";
-        if (BluetoothUuid.HSP_AG.equals(uuid)) return "HSP_AG";
-        if (BluetoothUuid.Handsfree.equals(uuid)) return "Handsfree";
-        if (BluetoothUuid.Handsfree_AG.equals(uuid)) return "Handsfree_AG";
-        if (BluetoothUuid.AvrcpController.equals(uuid)) return "AvrcpController";
-        if (BluetoothUuid.AvrcpTarget.equals(uuid)) return "AvrcpTarget";
-        if (BluetoothUuid.ObexObjectPush.equals(uuid)) return "ObexObjectPush";
-        if (BluetoothUuid.Hid.equals(uuid)) return "Hid";
-        if (BluetoothUuid.Hogp.equals(uuid)) return "Hogp";
-        if (BluetoothUuid.PANU.equals(uuid)) return "PANU";
-        if (BluetoothUuid.NAP.equals(uuid)) return "NAP";
-        if (BluetoothUuid.BNEP.equals(uuid)) return "BNEP";
-        if (BluetoothUuid.PBAP_PSE.equals(uuid)) return "PBAP_PSE";
-        if (BluetoothUuid.MAP.equals(uuid)) return "MAP";
-        if (BluetoothUuid.MNS.equals(uuid)) return "MNS";
-        if (BluetoothUuid.MAS.equals(uuid)) return "MAS";
-        return uuid != null ? uuid.toString() : null;
-    }
-
-    public static String connectionStateToString(int connectionState) {
-        if (connectionState == BluetoothAdapter.STATE_DISCONNECTED) return "STATE_DISCONNECTED";
-        if (connectionState == BluetoothAdapter.STATE_CONNECTED) return "STATE_CONNECTED";
-        if (connectionState == BluetoothAdapter.STATE_DISCONNECTING) return "STATE_DISCONNECTING";
-        if (connectionState == BluetoothAdapter.STATE_CONNECTING) return "STATE_CONNECTING";
-        return "ERROR";
-    }
-
-    public static String deviceToString(BluetoothDevice device) {
-        return device == null ? null : (device.getAddress() + '[' + device.getAliasName() + ']');
-    }
-
-    public static String uuidsToString(BluetoothDevice device) {
-        if (device == null) return null;
-        final ParcelUuid[] ids = device.getUuids();
-        if (ids == null) return null;
-        final String[] tokens = new String[ids.length];
-        for (int i = 0; i < tokens.length; i++) {
-            tokens[i] = uuidToString(ids[i]);
-        }
-        return TextUtils.join(",", tokens);
-    }
-
-    public static int uuidToProfile(ParcelUuid uuid) {
-        if (BluetoothUuid.AudioSink.equals(uuid)) return BluetoothProfile.A2DP;
-        if (BluetoothUuid.AdvAudioDist.equals(uuid)) return BluetoothProfile.A2DP;
-
-        if (BluetoothUuid.HSP.equals(uuid)) return BluetoothProfile.HEADSET;
-        if (BluetoothUuid.Handsfree.equals(uuid)) return BluetoothProfile.HEADSET;
-
-        if (BluetoothUuid.MAP.equals(uuid)) return BluetoothProfile.MAP;
-        if (BluetoothUuid.MNS.equals(uuid)) return BluetoothProfile.MAP;
-        if (BluetoothUuid.MAS.equals(uuid)) return BluetoothProfile.MAP;
-
-        if (BluetoothUuid.AvrcpController.equals(uuid)) return BluetoothProfile.AVRCP_CONTROLLER;
-
-        if (BluetoothUuid.Hid.equals(uuid)) return BluetoothProfile.INPUT_DEVICE;
-        if (BluetoothUuid.Hogp.equals(uuid)) return BluetoothProfile.INPUT_DEVICE;
-
-        if (BluetoothUuid.NAP.equals(uuid)) return BluetoothProfile.PAN;
-
-        return 0;
-    }
-
-    public static Profile getProfile(BluetoothProfile p) {
-        if (p instanceof BluetoothA2dp) return newProfile((BluetoothA2dp) p);
-        if (p instanceof BluetoothHeadset) return newProfile((BluetoothHeadset) p);
-        if (p instanceof BluetoothA2dpSink) return newProfile((BluetoothA2dpSink) p);
-        if (p instanceof BluetoothHeadsetClient) return newProfile((BluetoothHeadsetClient) p);
-        if (p instanceof BluetoothInputDevice) return newProfile((BluetoothInputDevice) p);
-        if (p instanceof BluetoothMap) return newProfile((BluetoothMap) p);
-        if (p instanceof BluetoothPan) return newProfile((BluetoothPan) p);
-        return null;
-    }
-
-    private static Profile newProfile(final BluetoothA2dp a2dp) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return a2dp.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return a2dp.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothHeadset headset) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return headset.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return headset.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothA2dpSink sink) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return sink.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return sink.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothHeadsetClient client) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return client.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return client.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothInputDevice input) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return input.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return input.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothMap map) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return map.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return map.disconnect(device);
-            }
-        };
-    }
-
-    private static Profile newProfile(final BluetoothPan pan) {
-        return new Profile() {
-            @Override
-            public boolean connect(BluetoothDevice device) {
-                return pan.connect(device);
-            }
-
-            @Override
-            public boolean disconnect(BluetoothDevice device) {
-                return pan.disconnect(device);
-            }
-        };
-    }
-
-    // common abstraction for supported profiles
-    public interface Profile {
-        boolean connect(BluetoothDevice device);
-        boolean disconnect(BluetoothDevice device);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 779ff52..04c626b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -152,7 +152,7 @@
         final char MAGIC2 = '\uEF01';
 
         SimpleDateFormat sdf;
-        String format = is24 ? d.timeFormat24 : d.timeFormat12;
+        String format = is24 ? d.timeFormat_Hm : d.timeFormat_hm;
         if (!format.equals(mClockFormatString)) {
             /*
              * Search for an unquoted "a" in the format string, so we can
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 33f7aff..c9ba8f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -28,7 +28,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
-import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
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 2e3e67a..6c1cdcd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -36,6 +36,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
@@ -44,7 +45,8 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
-import java.util.ArrayList;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
         ViewTreeObserver.OnComputeInternalInsetsListener {
@@ -56,6 +58,9 @@
     Rect mTmpRect = new Rect();
     int[] mTmpTwoArray = new int[2];
 
+    private final int mHeadsUpNotificationDecay;
+    private final int mMinimumDisplayTime;
+
     private final int mTouchSensitivityDelay;
     private final float mMaxAlpha = 1f;
     private final ArrayMap<String, Long> mSnoozedPackages;
@@ -66,6 +71,7 @@
 
     private PhoneStatusBar mBar;
 
+    private long mLingerUntilMs;
     private long mStartTouchTime;
     private ViewGroup mContentHolder;
     private int mSnoozeLengthMs;
@@ -74,6 +80,14 @@
     private NotificationData.Entry mHeadsUp;
     private int mUser;
     private String mMostRecentPackageName;
+    private boolean mTouched;
+    private Clock mClock;
+
+    public static class Clock {
+        public long currentTimeMillis() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
 
     public HeadsUpNotificationView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -87,6 +101,24 @@
         mSnoozedPackages = new ArrayMap<>();
         mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
         mSnoozeLengthMs = mDefaultSnoozeLengthMs;
+        mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
+        mHeadsUpNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
+        mClock = new Clock();
+    }
+
+    @VisibleForTesting
+    public HeadsUpNotificationView(Context context, Clock clock, SwipeHelper swipeHelper,
+            EdgeSwipeHelper edgeSwipeHelper, int headsUpNotificationDecay, int minimumDisplayTime,
+            int touchSensitivityDelay, int snoozeLength) {
+        super(context, null);
+        mClock = clock;
+        mSwipeHelper = swipeHelper;
+        mEdgeSwipeHelper = edgeSwipeHelper;
+        mMinimumDisplayTime = minimumDisplayTime;
+        mHeadsUpNotificationDecay = headsUpNotificationDecay;
+        mTouchSensitivityDelay = touchSensitivityDelay;
+        mSnoozedPackages = new ArrayMap<>();
+        mDefaultSnoozeLengthMs = snoozeLength;
     }
 
     public void updateResources() {
@@ -102,90 +134,152 @@
         mBar = bar;
     }
 
+    public PhoneStatusBar getBar() {
+        return mBar;
+    }
+
     public ViewGroup getHolder() {
         return mContentHolder;
     }
 
-    public boolean showNotification(NotificationData.Entry headsUp) {
-        if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) {
+    /**
+     * Called when posting a new notification to the heads up.
+     */
+    public void showNotification(NotificationData.Entry headsUp) {
+        if (DEBUG) Log.v(TAG, "showNotification");
+        if (mHeadsUp != null) {
             // bump any previous heads up back to the shade
-            release();
+            releaseImmediately();
+        }
+        mTouched = false;
+        updateNotification(headsUp, true);
+        mLingerUntilMs = mClock.currentTimeMillis() + mMinimumDisplayTime;
+    }
+
+    /**
+     * Called when updating or posting a notification to the heads up.
+     */
+    public void updateNotification(NotificationData.Entry headsUp, boolean alert) {
+        if (DEBUG) Log.v(TAG, "updateNotification");
+
+        if (alert) {
+            mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay);
+        }
+        invalidate();
+
+        if (mHeadsUp == headsUp) {
+            resetViewForHeadsup();
+            // This is an in-place update.  Noting more to do.
+            return;
         }
 
         mHeadsUp = headsUp;
+
         if (mContentHolder != null) {
             mContentHolder.removeAllViews();
         }
 
         if (mHeadsUp != null) {
             mMostRecentPackageName = mHeadsUp.notification.getPackageName();
-            mHeadsUp.row.setSystemExpanded(true);
-            mHeadsUp.row.setSensitive(false);
-            mHeadsUp.row.setHeadsUp(true);
-            mHeadsUp.row.setHideSensitive(
-                    false, false /* animated */, 0 /* delay */, 0 /* duration */);
-            if (mContentHolder == null) {
-                // too soon!
-                return false;
+            if (mHeadsUp.row != null) {
+                resetViewForHeadsup();
             }
-            mContentHolder.setX(0);
-            mContentHolder.setVisibility(View.VISIBLE);
-            mContentHolder.setAlpha(mMaxAlpha);
-            mContentHolder.addView(mHeadsUp.row);
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
 
-            mSwipeHelper.snapChild(mContentHolder, 1f);
             mStartTouchTime = SystemClock.elapsedRealtime() + mTouchSensitivityDelay;
+            if (mContentHolder != null) {  // only null in tests and before we are attached to a window
+                mContentHolder.setX(0);
+                mContentHolder.setVisibility(View.VISIBLE);
+                mContentHolder.setAlpha(mMaxAlpha);
+                mContentHolder.addView(mHeadsUp.row);
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+
+                mSwipeHelper.snapChild(mContentHolder, 1f);
+            }
 
             mHeadsUp.setInterruption();
 
-            // 2. Animate mHeadsUpNotificationView in
+            // Make sure the heads up window is open.
             mBar.scheduleHeadsUpOpen();
-
-            // 3. Set alarm to age the notification off
-            mBar.resetHeadsUpDecayTimer();
         }
-        return true;
+    }
+
+    private void resetViewForHeadsup() {
+        if (mHeadsUp.row.areChildrenExpanded()) {
+            mHeadsUp.row.setChildrenExpanded(false /* expanded */, false /* animated */);
+        }
+        mHeadsUp.row.setSystemExpanded(true);
+        mHeadsUp.row.setSensitive(false);
+        mHeadsUp.row.setHeadsUp(true);
+        mHeadsUp.row.setTranslationY(0);
+        mHeadsUp.row.setTranslationZ(0);
+        mHeadsUp.row.setHideSensitive(
+                false, false /* animated */, 0 /* delay */, 0 /* duration */);
+    }
+
+    /**
+     * Possibly enter the lingering state by delaying the closing of the window.
+     *
+     * @return true if the notification has entered the lingering state.
+     */
+    private boolean startLingering(boolean removed) {
+        final long now = mClock.currentTimeMillis();
+        if (!mTouched && mHeadsUp != null && now < mLingerUntilMs) {
+            if (removed) {
+                mHeadsUp = null;
+            }
+            mBar.scheduleHeadsUpDecay(mLingerUntilMs - now);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * React to the removal of the notification in the heads up.
+     */
+    public void removeNotification(String key) {
+        if (DEBUG) Log.v(TAG, "remove");
+        if (mHeadsUp == null || !mHeadsUp.key.equals(key)) {
+            return;
+        }
+        if (!startLingering(/* removed */ true)) {
+            mHeadsUp = null;
+            releaseImmediately();
+        }
+    }
+
+    /**
+     * Ask for any current Heads Up notification to be pushed down into the shade.
+     */
+    public void release() {
+        if (DEBUG) Log.v(TAG, "release");
+        if (!startLingering(/* removed */ false)) {
+            releaseImmediately();
+        }
+    }
+
+    /**
+     * Push any current Heads Up notification down into the shade.
+     */
+    public void releaseImmediately() {
+        if (DEBUG) Log.v(TAG, "releaseImmediately");
+        if (mHeadsUp != null) {
+            mContentHolder.removeView(mHeadsUp.row);
+            mBar.displayNotificationFromHeadsUp(mHeadsUp);
+        }
+        mHeadsUp = null;
+        mBar.scheduleHeadsUpClose();
     }
 
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
+        if (DEBUG) Log.v(TAG, "onVisibilityChanged: " + visibility);
         if (changedView.getVisibility() == VISIBLE) {
+            mStartTouchTime = mClock.currentTimeMillis() + mTouchSensitivityDelay;
             sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         }
     }
 
-    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 boolean isSnoozed(String packageName) {
         final String key = snoozeKey(packageName, mUser);
         Long snoozedUntil = mSnoozedPackages.get(key);
@@ -204,16 +298,15 @@
             mSnoozedPackages.put(snoozeKey(mMostRecentPackageName, mUser),
                     SystemClock.elapsedRealtime() + mSnoozeLengthMs);
         }
-        releaseAndClose();
+        releaseImmediately();
     }
 
     private static String snoozeKey(String packageName, int user) {
         return user + "," + packageName;
     }
 
-    public void releaseAndClose() {
-        release();
-        mBar.scheduleHeadsUpClose();
+    public boolean isShowing(String key) {
+        return mHeadsUp != null && mHeadsUp.key.equals(key);
     }
 
     public NotificationData.Entry getEntry() {
@@ -226,19 +319,19 @@
 
     // ViewGroup methods
 
-    private static final ViewOutlineProvider CONTENT_HOLDER_OUTLINE_PROVIDER =
-            new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            int outlineLeft = view.getPaddingLeft();
-            int outlineTop = view.getPaddingTop();
+private static final ViewOutlineProvider CONTENT_HOLDER_OUTLINE_PROVIDER =
+        new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                int outlineLeft = view.getPaddingLeft();
+                int outlineTop = view.getPaddingTop();
 
-            // Apply padding to shadow.
-            outline.setRect(outlineLeft, outlineTop,
-                    view.getWidth() - outlineLeft - view.getPaddingRight(),
-                    view.getHeight() - outlineTop - view.getPaddingBottom());
-        }
-    };
+                // Apply padding to shadow.
+                outline.setRect(outlineLeft, outlineTop,
+                        view.getWidth() - outlineLeft - view.getPaddingRight(),
+                        view.getHeight() - outlineTop - view.getPaddingBottom());
+            }
+        };
 
     @Override
     public void onAttachedToWindow() {
@@ -246,7 +339,7 @@
         float touchSlop = viewConfiguration.getScaledTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
         mSwipeHelper.setMaxSwipeProgress(mMaxAlpha);
-        mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop);
+        mEdgeSwipeHelper = new EdgeSwipeHelper(this, touchSlop);
 
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
@@ -280,6 +373,7 @@
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
+
     @Override
     protected void onDetachedFromWindow() {
         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
@@ -288,11 +382,13 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        if (SystemClock.elapsedRealtime() < mStartTouchTime) {
+        if (mClock.currentTimeMillis() < mStartTouchTime) {
             return true;
         }
+        mTouched = true;
         return mEdgeSwipeHelper.onInterceptTouchEvent(ev)
                 || mSwipeHelper.onInterceptTouchEvent(ev)
+                || mHeadsUp == null // lingering
                 || super.onInterceptTouchEvent(ev);
     }
 
@@ -314,12 +410,17 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (SystemClock.elapsedRealtime() < mStartTouchTime) {
+        if (mClock.currentTimeMillis() < mStartTouchTime) {
             return false;
         }
-        mBar.resetHeadsUpDecayTimer();
+
+        final boolean wasRemoved = mHeadsUp == null;
+        if (!wasRemoved) {
+            mBar.scheduleHeadsUpDecay(mHeadsUpNotificationDecay);
+        }
         return mEdgeSwipeHelper.onTouchEvent(ev)
                 || mSwipeHelper.onTouchEvent(ev)
+                || wasRemoved
                 || super.onTouchEvent(ev);
     }
 
@@ -388,7 +489,11 @@
     @Override
     public void onChildDismissed(View v) {
         Log.v(TAG, "User swiped heads up to dismiss");
-        mBar.onHeadsUpDismissed();
+        if (mHeadsUp != null && mHeadsUp.notification.isClearable()) {
+            mBar.onNotificationClear(mHeadsUp.notification);
+            mHeadsUp = null;
+        }
+        releaseImmediately();
     }
 
     @Override
@@ -442,14 +547,39 @@
         mUser = user;
     }
 
-    private class EdgeSwipeHelper implements Gefingerpoken {
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("HeadsUpNotificationView state:");
+        pw.print("  mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay);
+        pw.print("  mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
+        pw.print("  mLingerUntilMs="); pw.println(mLingerUntilMs);
+        pw.print("  mTouched="); pw.println(mTouched);
+        pw.print("  mMostRecentPackageName="); pw.println(mMostRecentPackageName);
+        pw.print("  mStartTouchTime="); pw.println(mStartTouchTime);
+        pw.print("  now="); pw.println(SystemClock.elapsedRealtime());
+        pw.print("  mUser="); pw.println(mUser);
+        if (mHeadsUp == null) {
+            pw.println("  mHeadsUp=null");
+        } else {
+            pw.print("  mHeadsUp="); pw.println(mHeadsUp.notification.getKey());
+        }
+        int N = mSnoozedPackages.size();
+        pw.println("  snoozed packages: " + N);
+        for (int i = 0; i < N; i++) {
+            pw.print("    "); pw.print(mSnoozedPackages.valueAt(i));
+            pw.print(", "); pw.println(mSnoozedPackages.keyAt(i));
+        }
+    }
+
+    public static class EdgeSwipeHelper implements Gefingerpoken {
         private static final boolean DEBUG_EDGE_SWIPE = false;
         private final float mTouchSlop;
+        private final HeadsUpNotificationView mHeadsUpView;
         private boolean mConsuming;
         private float mFirstY;
         private float mFirstX;
 
-        public EdgeSwipeHelper(float touchSlop) {
+        public EdgeSwipeHelper(HeadsUpNotificationView headsUpView, float touchSlop) {
+            mHeadsUpView = headsUpView;
             mTouchSlop = touchSlop;
         }
 
@@ -469,10 +599,10 @@
                     final float daX = Math.abs(ev.getX() - mFirstX);
                     final float daY = Math.abs(dY);
                     if (!mConsuming && daX < daY && daY > mTouchSlop) {
-                        snooze();
+                        mHeadsUpView.snooze();
                         if (dY > 0) {
                             if (DEBUG_EDGE_SWIPE) Log.d(TAG, "found an open");
-                            mBar.animateExpandNotificationsPanel();
+                            mHeadsUpView.getBar().animateExpandNotificationsPanel();
                         }
                         mConsuming = true;
                     }
@@ -480,7 +610,7 @@
 
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
-                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done" );
+                    if (DEBUG_EDGE_SWIPE) Log.d(TAG, "action done");
                     mConsuming = false;
                     break;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 0863c86..7ca91a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,7 +22,6 @@
     boolean isHotspotEnabled();
     boolean isHotspotSupported();
     void setHotspotEnabled(boolean enabled);
-    boolean isProvisioningNeeded();
 
     public interface Callback {
         void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5eff5a6..4bfd528 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,45 +16,38 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 
+import com.android.settingslib.TetherUtil;
+
 import java.util.ArrayList;
 
 public class HotspotControllerImpl implements HotspotController {
 
     private static final String TAG = "HotspotController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    // Keep these in sync with Settings TetherService.java
-    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
-    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
-    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
-    // Keep this in sync with Settings TetherSettings.java
-    public static final int WIFI_TETHERING = 0;
+    private static final Intent TETHER_SERVICE_INTENT = new Intent()
+            .putExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE, TetherUtil.TETHERING_WIFI)
+            .putExtra(TetherUtil.EXTRA_SET_ALARM, true)
+            .putExtra(TetherUtil.EXTRA_RUN_PROVISION, true)
+            .putExtra(TetherUtil.EXTRA_ENABLE_WIFI_TETHER, true)
+            .setComponent(TetherUtil.TETHER_SERVICE);
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final Receiver mReceiver = new Receiver();
     private final Context mContext;
     private final WifiManager mWifiManager;
-    private final ConnectivityManager mConnectivityManager;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        mConnectivityManager = (ConnectivityManager)
-                mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
     public void addCallback(Callback callback) {
@@ -78,54 +71,17 @@
 
     @Override
     public boolean isHotspotSupported() {
-        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
-        return !isSecondaryUser && mConnectivityManager.isTetheringSupported();
-    }
-
-    @Override
-    public boolean isProvisioningNeeded() {
-        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
-        // TetherSettings#isProvisioningNeeded and
-        // ConnectivityManager#enforceTetherChangePermission
-        String[] provisionApp = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
-        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
-                || provisionApp == null) {
-            return false;
-        }
-        return (provisionApp.length == 2);
+        return TetherUtil.isTetheringSupported(mContext);
     }
 
     @Override
     public void setHotspotEnabled(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
         // Call provisioning app which is called when enabling Tethering from Settings
-        if (enabled) {
-            if (isProvisioningNeeded()) {
-                String tetherEnable = mContext.getResources().getString(
-                        com.android.internal.R.string.config_wifi_tether_enable);
-                Intent intent = new Intent();
-                intent.putExtra(EXTRA_ADD_TETHER_TYPE, WIFI_TETHERING);
-                intent.putExtra(EXTRA_SET_ALARM, true);
-                intent.putExtra(EXTRA_RUN_PROVISION, true);
-                intent.putExtra(EXTRA_ENABLE_WIFI_TETHER, true);
-                intent.setComponent(ComponentName.unflattenFromString(tetherEnable));
-                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
-            } else {
-                int wifiState = mWifiManager.getWifiState();
-                if ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
-                        (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
-                    mWifiManager.setWifiEnabled(false);
-                    Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
-                }
-                mWifiManager.setWifiApEnabled(null, true);
-            }
+        if (enabled && TetherUtil.isProvisioningNeeded(mContext)) {
+            mContext.startServiceAsUser(TETHER_SERVICE_INTENT, UserHandle.CURRENT);
         } else {
-            mWifiManager.setWifiApEnabled(null, false);
-            if (Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0) == 1) {
-                mWifiManager.setWifiEnabled(true);
-                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-            }
+            TetherUtil.setWifiTethering(enabled, mContext);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 6998791..a3ebb09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -118,7 +118,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
+    public void setColorFilter(ColorFilter colorFilter) {
         // Not supported.
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index b9cc0f9..a18daed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -26,7 +24,6 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
@@ -45,20 +42,12 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
 public class KeyButtonView extends ImageView {
-    private static final String TAG = "StatusBar.KeyButtonView";
-    private static final boolean DEBUG = false;
-
-    // TODO: Get rid of this
-    public static final float DEFAULT_QUIESCENT_ALPHA = 1f;
 
     private long mDownTime;
     private int mCode;
     private int mTouchSlop;
-    private float mDrawingAlpha = 1f;
-    private float mQuiescentAlpha = DEFAULT_QUIESCENT_ALPHA;
     private boolean mSupportsLongpress = true;
     private AudioManager mAudioManager;
-    private Animator mAnimateToQuiescent = new ObjectAnimator();
 
     private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
@@ -89,9 +78,6 @@
 
         mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
 
-
-        setDrawingAlpha(mQuiescentAlpha);
-
         a.recycle();
 
         setClickable(true);
@@ -121,7 +107,7 @@
     }
 
     @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
         if (action == ACTION_CLICK && mCode != 0) {
             sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
             sendEvent(KeyEvent.ACTION_UP, 0);
@@ -134,38 +120,7 @@
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
             return true;
         }
-        return super.performAccessibilityAction(action, arguments);
-    }
-
-    public void setQuiescentAlpha(float alpha, boolean animate) {
-        mAnimateToQuiescent.cancel();
-        alpha = Math.min(Math.max(alpha, 0), 1);
-        if (alpha == mQuiescentAlpha && alpha == mDrawingAlpha) return;
-        mQuiescentAlpha = alpha;
-        if (DEBUG) Log.d(TAG, "New quiescent alpha = " + mQuiescentAlpha);
-        if (animate) {
-            mAnimateToQuiescent = animateToQuiescent();
-            mAnimateToQuiescent.start();
-        } else {
-            setDrawingAlpha(mQuiescentAlpha);
-        }
-    }
-
-    private ObjectAnimator animateToQuiescent() {
-        return ObjectAnimator.ofFloat(this, "drawingAlpha", mQuiescentAlpha);
-    }
-
-    public float getQuiescentAlpha() {
-        return mQuiescentAlpha;
-    }
-
-    public float getDrawingAlpha() {
-        return mDrawingAlpha;
-    }
-
-    public void setDrawingAlpha(float x) {
-        setImageAlpha((int) (x * 255));
-        mDrawingAlpha = x;
+        return super.performAccessibilityActionInternal(action, arguments);
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
index a5fc2fe..2d04d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -19,7 +19,6 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.LightingColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.RadialGradient;
@@ -77,7 +76,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter cf) {
+    public void setColorFilter(ColorFilter colorFilter) {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
new file mode 100644
index 0000000..ba938cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkCapabilities;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+
+
+public class MobileSignalController extends SignalController<
+        MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
+    private final TelephonyManager mPhone;
+    private final String mNetworkNameDefault;
+    private final String mNetworkNameSeparator;
+    @VisibleForTesting
+    final PhoneStateListener mPhoneStateListener;
+    // Save entire info for logging, we only use the id.
+    private final SubscriptionInfo mSubscriptionInfo;
+
+    // @VisibleForDemoMode
+    final SparseArray<MobileIconGroup> mNetworkToIconLookup;
+
+    // Since some pieces of the phone state are interdependent we store it locally,
+    // this could potentially become part of MobileState for simplification/complication
+    // of code.
+    private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private int mDataState = TelephonyManager.DATA_DISCONNECTED;
+    private ServiceState mServiceState;
+    private SignalStrength mSignalStrength;
+    private MobileIconGroup mDefaultIcons;
+    private Config mConfig;
+
+    // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
+    // need listener lists anymore.
+    public MobileSignalController(Context context, Config config, boolean hasMobileData,
+            TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks,
+            List<SignalCluster> signalClusters, NetworkControllerImpl networkController,
+            SubscriptionInfo info) {
+        super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
+                NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters,
+                networkController);
+        mNetworkToIconLookup = new SparseArray<>();
+        mConfig = config;
+        mPhone = phone;
+        mSubscriptionInfo = info;
+        mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId());
+        mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
+        mNetworkNameDefault = getStringIfExists(
+                com.android.internal.R.string.lockscreen_carrier_default);
+
+        mapIconSets();
+
+        mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault;
+        mLastState.enabled = mCurrentState.enabled = hasMobileData;
+        mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
+        // Get initial data sim state.
+        updateDataSim();
+    }
+
+    public void setConfiguration(Config config) {
+        mConfig = config;
+        mapIconSets();
+        updateTelephony();
+    }
+
+    public int getDataContentDescription() {
+        return getIcons().mDataContentDescription;
+    }
+
+    public void setAirplaneMode(boolean airplaneMode) {
+        mCurrentState.airplaneMode = airplaneMode;
+        notifyListenersIfNecessary();
+    }
+
+    public void setInetCondition(int inetCondition, int inetConditionForNetwork) {
+        // For mobile data, use general inet condition for phone signal indexing,
+        // and network specific for data indexing (I think this might be a bug, but
+        // keeping for now).
+        // TODO: Update with explanation of why.
+        mCurrentState.inetForNetwork = inetConditionForNetwork;
+        setInetCondition(inetCondition);
+    }
+
+    /**
+     * Start listening for phone state changes.
+     */
+    public void registerListener() {
+        mPhone.listen(mPhoneStateListener,
+                PhoneStateListener.LISTEN_SERVICE_STATE
+                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+                        | PhoneStateListener.LISTEN_CALL_STATE
+                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+                        | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+    }
+
+    /**
+     * Stop listening for phone state changes.
+     */
+    public void unregisterListener() {
+        mPhone.listen(mPhoneStateListener, 0);
+    }
+
+    /**
+     * Produce a mapping of data network types to icon groups for simple and quick use in
+     * updateTelephony.
+     */
+    private void mapIconSets() {
+        mNetworkToIconLookup.clear();
+
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
+
+        if (!mConfig.showAtLeast3G) {
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    TelephonyIcons.UNKNOWN);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
+
+            mDefaultIcons = TelephonyIcons.G;
+        } else {
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+                    TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
+                    TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
+                    TelephonyIcons.THREE_G);
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
+                    TelephonyIcons.THREE_G);
+            mDefaultIcons = TelephonyIcons.THREE_G;
+        }
+
+        MobileIconGroup hGroup = TelephonyIcons.THREE_G;
+        if (mConfig.hspaDataDistinguishable) {
+            hGroup = TelephonyIcons.H;
+        }
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
+        mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
+
+        if (mConfig.show4gForLte) {
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+        } else {
+            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+        }
+    }
+
+    @Override
+    public void notifyListeners() {
+        MobileIconGroup icons = getIcons();
+
+        String contentDescription = getStringIfExists(getContentDescription());
+        String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
+
+        boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0
+                || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+
+        // Only send data sim callbacks to QS.
+        if (mCurrentState.dataSim) {
+            int qsTypeIcon = showDataIcon ? icons.mQsDataType[mCurrentState.inetForNetwork] : 0;
+            int length = mSignalsChangedCallbacks.size();
+            for (int i = 0; i < length; i++) {
+                mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled
+                        && !mCurrentState.isEmergency,
+                        getQsCurrentIconId(), contentDescription,
+                        qsTypeIcon,
+                        mCurrentState.dataConnected && mCurrentState.activityIn,
+                        mCurrentState.dataConnected && mCurrentState.activityOut,
+                        dataContentDescription,
+                        mCurrentState.isEmergency ? null : mCurrentState.networkName,
+                        // Only wide if actually showing something.
+                        icons.mIsWide && qsTypeIcon != 0);
+            }
+        }
+        int typeIcon = showDataIcon ? icons.mDataType : 0;
+        int signalClustersLength = mSignalClusters.size();
+        for (int i = 0; i < signalClustersLength; i++) {
+            mSignalClusters.get(i).setMobileDataIndicators(
+                    mCurrentState.enabled && !mCurrentState.airplaneMode,
+                    getCurrentIconId(),
+                    typeIcon,
+                    contentDescription,
+                    dataContentDescription,
+                    // Only wide if actually showing something.
+                    icons.mIsWide && typeIcon != 0,
+                    mSubscriptionInfo.getSubscriptionId());
+        }
+    }
+
+    @Override
+    protected MobileState cleanState() {
+        return new MobileState();
+    }
+
+    private boolean hasService() {
+        if (mServiceState != null) {
+            // Consider the device to be in service if either voice or data
+            // service is available. Some SIM cards are marketed as data-only
+            // and do not support voice service, and on these SIM cards, we
+            // want to show signal bars for data service as well as the "no
+            // service" or "emergency calls only" text that indicates that voice
+            // is not available.
+            switch (mServiceState.getVoiceRegState()) {
+                case ServiceState.STATE_POWER_OFF:
+                    return false;
+                case ServiceState.STATE_OUT_OF_SERVICE:
+                case ServiceState.STATE_EMERGENCY_ONLY:
+                    return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+                default:
+                    return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isCdma() {
+        return (mSignalStrength != null) && !mSignalStrength.isGsm();
+    }
+
+    public boolean isEmergencyOnly() {
+        return (mServiceState != null && mServiceState.isEmergencyOnly());
+    }
+
+    private boolean isRoaming() {
+        if (isCdma()) {
+            final int iconMode = mServiceState.getCdmaEriIconMode();
+            return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
+                    && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+                        || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
+        } else {
+            return mServiceState != null && mServiceState.getRoaming();
+        }
+    }
+
+    public void handleBroadcast(Intent intent) {
+        String action = intent.getAction();
+        if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
+            updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
+                    intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+                    intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
+                    intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
+            notifyListenersIfNecessary();
+        } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+            updateDataSim();
+        }
+    }
+
+    private void updateDataSim() {
+        int defaultDataSub = SubscriptionManager.getDefaultDataSubId();
+        if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
+            mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
+        } else {
+            // There doesn't seem to be a data sim selected, however if
+            // there isn't a MobileSignalController with dataSim set, then
+            // QS won't get any callbacks and will be blank.  Instead
+            // lets just assume we are the data sim (which will basically
+            // show one at random) in QS until one is selected.  The user
+            // should pick one soon after, so we shouldn't be in this state
+            // for long.
+            mCurrentState.dataSim = true;
+        }
+        notifyListenersIfNecessary();
+    }
+
+    /**
+     * Updates the network's name based on incoming spn and plmn.
+     */
+    void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+        if (CHATTY) {
+            Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+                    + " showPlmn=" + showPlmn + " plmn=" + plmn);
+        }
+        StringBuilder str = new StringBuilder();
+        if (showPlmn && plmn != null) {
+            str.append(plmn);
+        }
+        if (showSpn && spn != null) {
+            if (str.length() != 0) {
+                str.append(mNetworkNameSeparator);
+            }
+            str.append(spn);
+        }
+        if (str.length() != 0) {
+            mCurrentState.networkName = str.toString();
+        } else {
+            mCurrentState.networkName = mNetworkNameDefault;
+        }
+    }
+
+    /**
+     * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
+     * mDataState, and mSimState.  It should be called any time one of these is updated.
+     * This will call listeners if necessary.
+     */
+    private final void updateTelephony() {
+        if (DEBUG) {
+            Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
+                    + " ss=" + mSignalStrength);
+        }
+        mCurrentState.connected = hasService() && mSignalStrength != null;
+        if (mCurrentState.connected) {
+            if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
+                mCurrentState.level = mSignalStrength.getCdmaLevel();
+            } else {
+                mCurrentState.level = mSignalStrength.getLevel();
+            }
+        }
+        if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
+            mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
+        } else {
+            mCurrentState.iconGroup = mDefaultIcons;
+        }
+        mCurrentState.dataConnected = mCurrentState.connected
+                && mDataState == TelephonyManager.DATA_CONNECTED;
+
+        if (isRoaming()) {
+            mCurrentState.iconGroup = TelephonyIcons.ROAMING;
+        }
+        if (isEmergencyOnly() != mCurrentState.isEmergency) {
+            mCurrentState.isEmergency = isEmergencyOnly();
+            mNetworkController.recalculateEmergency();
+        }
+        // Fill in the network name if we think we have it.
+        if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
+                && mServiceState.getOperatorAlphaShort() != null) {
+            mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
+        }
+        notifyListenersIfNecessary();
+    }
+
+    @VisibleForTesting
+    void setActivity(int activity) {
+        mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || activity == TelephonyManager.DATA_ACTIVITY_IN;
+        mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
+                || activity == TelephonyManager.DATA_ACTIVITY_OUT;
+        notifyListenersIfNecessary();
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        super.dump(pw);
+        pw.println("  mSubscription=" + mSubscriptionInfo + ",");
+        pw.println("  mServiceState=" + mServiceState + ",");
+        pw.println("  mSignalStrength=" + mSignalStrength + ",");
+        pw.println("  mDataState=" + mDataState + ",");
+        pw.println("  mDataNetType=" + mDataNetType + ",");
+    }
+
+    class MobilePhoneStateListener extends PhoneStateListener {
+        public MobilePhoneStateListener(int subId) {
+            super(subId);
+        }
+
+        @Override
+        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+            if (DEBUG) {
+                Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+                        ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
+            }
+            mSignalStrength = signalStrength;
+            updateTelephony();
+        }
+
+        @Override
+        public void onServiceStateChanged(ServiceState state) {
+            if (DEBUG) {
+                Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+                        + " dataState=" + state.getDataRegState());
+            }
+            mServiceState = state;
+            updateTelephony();
+        }
+
+        @Override
+        public void onDataConnectionStateChanged(int state, int networkType) {
+            if (DEBUG) {
+                Log.d(mTag, "onDataConnectionStateChanged: state=" + state
+                        + " type=" + networkType);
+            }
+            mDataState = state;
+            mDataNetType = networkType;
+            updateTelephony();
+        }
+
+        @Override
+        public void onDataActivity(int direction) {
+            if (DEBUG) {
+                Log.d(mTag, "onDataActivity: direction=" + direction);
+            }
+            setActivity(direction);
+        }
+    };
+
+    static class MobileIconGroup extends SignalController.IconGroup {
+        final int mDataContentDescription; // mContentDescriptionDataType
+        final int mDataType;
+        final boolean mIsWide;
+        final int[] mQsDataType;
+
+        public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
+                int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
+                int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
+                int[] qsDataType) {
+            super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
+                    qsDiscState, discContentDesc);
+            mDataContentDescription = dataContentDesc;
+            mDataType = dataType;
+            mIsWide = isWide;
+            mQsDataType = qsDataType;
+        }
+    }
+
+    static class MobileState extends SignalController.State {
+        String networkName;
+        boolean dataSim;
+        boolean dataConnected;
+        boolean isEmergency;
+        boolean airplaneMode;
+        int inetForNetwork;
+
+        @Override
+        public void copyFrom(State s) {
+            super.copyFrom(s);
+            MobileState state = (MobileState) s;
+            dataSim = state.dataSim;
+            networkName = state.networkName;
+            dataConnected = state.dataConnected;
+            inetForNetwork = state.inetForNetwork;
+            isEmergency = state.isEmergency;
+            airplaneMode = state.airplaneMode;
+        }
+
+        @Override
+        protected void toString(StringBuilder builder) {
+            super.toString(builder);
+            builder.append(',');
+            builder.append("dataSim=").append(dataSim).append(',');
+            builder.append("networkName=").append(networkName).append(',');
+            builder.append("dataConnected=").append(dataConnected).append(',');
+            builder.append("inetForNetwork=").append(inetForNetwork).append(',');
+            builder.append("isEmergency=").append(isEmergency).append(',');
+            builder.append("airplaneMode=").append(airplaneMode);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return super.equals(o)
+                    && Objects.equals(((MobileState) o).networkName, networkName)
+                    && ((MobileState) o).dataSim == dataSim
+                    && ((MobileState) o).dataConnected == dataConnected
+                    && ((MobileState) o).isEmergency == isEmergency
+                    && ((MobileState) o).airplaneMode == airplaneMode
+                    && ((MobileState) o).inetForNetwork == inetForNetwork;
+        }
+    }
+}
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 3cffc85..9212837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -18,6 +18,10 @@
 
 import android.content.Intent;
 
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.List;
+
 public interface NetworkController {
 
     boolean hasMobileDataFeature();
@@ -50,25 +54,14 @@
         void addAccessPointCallback(AccessPointCallback callback);
         void removeAccessPointCallback(AccessPointCallback callback);
         void scanForAccessPoints();
+        int getIcon(AccessPoint ap);
         boolean connect(AccessPoint ap);
         boolean canConfigWifi();
 
         public interface AccessPointCallback {
-            void onAccessPointsChanged(AccessPoint[] accessPoints);
+            void onAccessPointsChanged(List<AccessPoint> accessPoints);
             void onSettingsActivityTriggered(Intent settingsIntent);
         }
-
-        public static class AccessPoint {
-            public static final int NO_NETWORK = -1;  // see WifiManager
-
-            public int networkId;
-            public int iconId;
-            public String ssid;
-            public boolean isConnected;
-            public boolean isConfigured;
-            public boolean hasSecurity;
-            public int level;  // 0 - 5
-        }
     }
 
     /**
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 9a7f21e..bb3eb7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -17,10 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -28,34 +25,20 @@
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
 import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.text.format.DateFormat;
 import android.util.Log;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.internal.util.AsyncChannel;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
@@ -69,7 +52,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Objects;
 
 /** Platform implementation of the network controller. **/
 public class NetworkControllerImpl extends BroadcastReceiver
@@ -79,12 +61,6 @@
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     // additional diagnostics, but not logspew
     static final boolean CHATTY =  Log.isLoggable(TAG + ".Chat", Log.DEBUG);
-    // Save the previous SignalController.States of all SignalControllers for dumps.
-    static final boolean RECORD_HISTORY = true;
-    // If RECORD_HISTORY how many to save, must be a power of 2.
-    static final int HISTORY_SIZE = 16;
-
-    private static final int INET_CONDITION_THRESHOLD = 50;
 
     private final Context mContext;
     private final TelephonyManager mPhone;
@@ -106,12 +82,6 @@
     private final AccessPointControllerImpl mAccessPoints;
     private final MobileDataControllerImpl mMobileDataController;
 
-    // Network types that replace the carrier label if the device does not support mobile data.
-    private boolean mBluetoothTethered = false;
-    private boolean mEthernetConnected = false;
-
-    // state of inet connection
-    private boolean mConnected = false;
     private boolean mInetCondition; // Used for Logging and demo.
 
     // BitSets indicating which network transport types (e.g., TRANSPORT_WIFI, TRANSPORT_MOBILE) are
@@ -129,8 +99,6 @@
 
     // All the callbacks.
     private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>();
-    private ArrayList<CarrierLabelListener> mCarrierListeners =
-            new ArrayList<CarrierLabelListener>();
     private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
     private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
             new ArrayList<NetworkSignalChangedCallback>();
@@ -188,7 +156,6 @@
 
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
-        mAccessPoints.setNetworkController(this);
     }
 
     private void registerListeners() {
@@ -244,11 +211,6 @@
         listener.setEmergencyCallsOnly(isEmergencyOnly());
     }
 
-    public void addCarrierLabel(CarrierLabelListener listener) {
-        mCarrierListeners.add(listener);
-        refreshCarrierLabel();
-    }
-
     private void notifyMobileDataEnabled(boolean enabled) {
         final int length = mSignalsChangedCallbacks.size();
         for (int i = 0; i < length; i++) {
@@ -310,9 +272,6 @@
         for (int i = 0; i < length; i++) {
             mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly);
         }
-        // If the emergency has a chance to change, then so does the carrier
-        // label.
-        refreshCarrierLabel();
     }
 
     public void addSignalCluster(SignalCluster cluster) {
@@ -364,7 +323,6 @@
         mCurrentUserId = newUserId;
         mAccessPoints.onUserSwitched(newUserId);
         updateConnectivity();
-        refreshCarrierLabel();
     }
 
     @Override
@@ -376,14 +334,12 @@
         if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE) ||
                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
             updateConnectivity();
-            refreshCarrierLabel();
         } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
             mConfig = Config.readConfig(mContext);
             handleConfigurationChanged();
         } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
             refreshLocale();
             updateAirplaneMode(false);
-            refreshCarrierLabel();
         } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
             // We are using different subs now, we might be able to make calls.
             recalculateEmergency();
@@ -419,7 +375,6 @@
             mobileSignalController.setConfiguration(mConfig);
         }
         refreshLocale();
-        refreshCarrierLabel();
     }
 
     private void updateMobileControllers() {
@@ -525,7 +480,6 @@
                 mobileSignalController.setAirplaneMode(mAirplaneMode);
             }
             notifyListeners();
-            refreshCarrierLabel();
         }
     }
 
@@ -589,10 +543,7 @@
             Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
         }
 
-        mConnected = !mConnectedTransports.isEmpty();
         mInetCondition = !mValidatedTransports.isEmpty();
-        mBluetoothTethered = mConnectedTransports.get(TRANSPORT_BLUETOOTH);
-        mEthernetConnected = mConnectedTransports.get(TRANSPORT_ETHERNET);
 
         pushConnectivityToSignals();
     }
@@ -611,59 +562,6 @@
                 mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0);
     }
 
-    /**
-     * Recalculate and update the carrier label.
-     */
-    void refreshCarrierLabel() {
-        Context context = mContext;
-
-        WifiSignalController.WifiState wifiState = mWifiSignalController.getState();
-        String label = "";
-        for (MobileSignalController controller : mMobileSignalControllers.values()) {
-            label = controller.getLabel(label, mConnected, mHasMobileDataFeature);
-        }
-
-        // TODO Simplify this ugliness, some of the flows below shouldn't be possible anymore
-        // but stay for the sake of history.
-        if (mBluetoothTethered && !mHasMobileDataFeature) {
-            label = mContext.getString(R.string.bluetooth_tethered);
-        }
-
-        if (mEthernetConnected && !mHasMobileDataFeature) {
-            label = context.getString(R.string.ethernet_label);
-        }
-
-        if (mAirplaneMode && !isEmergencyOnly()) {
-            // combined values from connected wifi take precedence over airplane mode
-            if (wifiState.connected && mHasMobileDataFeature) {
-                // Suppress "No internet connection." from mobile if wifi connected.
-                label = "";
-            } else {
-                 if (!mHasMobileDataFeature) {
-                      label = context.getString(
-                              R.string.status_bar_settings_signal_meter_disconnected);
-                 }
-            }
-        } else if (!isMobileDataConnected() && !wifiState.connected && !mBluetoothTethered &&
-                 !mEthernetConnected && !mHasMobileDataFeature) {
-            // Pretty much no connection.
-            label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-        }
-
-        // for mobile devices, we always show mobile connection info here (SPN/PLMN)
-        // for other devices, we show whatever network is connected
-        // This is determined above by references to mHasMobileDataFeature.
-        int length = mCarrierListeners.size();
-        for (int i = 0; i < length; i++) {
-            mCarrierListeners.get(i).setCarrierLabel(label);
-        }
-    }
-
-    private boolean isMobileDataConnected() {
-        MobileSignalController controller = getDataController();
-        return controller != null ? controller.getState().dataConnected : false;
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NetworkController state:");
 
@@ -671,10 +569,6 @@
         pw.print("  hasVoiceCallingFeature()=");
         pw.println(hasVoiceCallingFeature());
 
-        pw.println("  - Bluetooth ----");
-        pw.print("  mBtReverseTethered=");
-        pw.println(mBluetoothTethered);
-
         pw.println("  - connectivity ------");
         pw.print("  mConnectedTransports=");
         pw.println(mConnectedTransports);
@@ -691,6 +585,8 @@
             mobileSignalController.dump(pw);
         }
         mWifiSignalController.dump(pw);
+
+        mAccessPoints.dump(pw);
     }
 
     private boolean mDemoMode;
@@ -717,7 +613,6 @@
             mWifiSignalController.resetLastState();
             registerListeners();
             notifyAllListeners();
-            refreshCarrierLabel();
         } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
             String airplane = args.getString("airplane");
             if (airplane != null) {
@@ -809,7 +704,6 @@
                 controller.getState().enabled = show;
                 controller.notifyListeners();
             }
-            refreshCarrierLabel();
         }
     }
 
@@ -821,965 +715,6 @@
         };
     };
 
-    // TODO: Move to its own file.
-    static class WifiSignalController extends
-            SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
-        private final WifiManager mWifiManager;
-        private final AsyncChannel mWifiChannel;
-        private final boolean mHasMobileData;
-
-        public WifiSignalController(Context context, boolean hasMobileData,
-                List<NetworkSignalChangedCallback> signalCallbacks,
-                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
-            super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
-                    signalCallbacks, signalClusters, networkController);
-            mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-            mHasMobileData = hasMobileData;
-            Handler handler = new WifiHandler();
-            mWifiChannel = new AsyncChannel();
-            Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
-            if (wifiMessenger != null) {
-                mWifiChannel.connect(context, handler, wifiMessenger);
-            }
-            // WiFi only has one state.
-            mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
-                    "Wi-Fi Icons",
-                    WifiIcons.WIFI_SIGNAL_STRENGTH,
-                    WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
-                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
-                    WifiIcons.WIFI_NO_NETWORK,
-                    WifiIcons.QS_WIFI_NO_NETWORK,
-                    WifiIcons.WIFI_NO_NETWORK,
-                    WifiIcons.QS_WIFI_NO_NETWORK,
-                    AccessibilityContentDescriptions.WIFI_NO_CONNECTION
-                    );
-        }
-
-        @Override
-        protected WifiState cleanState() {
-            return new WifiState();
-        }
-
-        @Override
-        public void notifyListeners() {
-            // only show wifi in the cluster if connected or if wifi-only
-            boolean wifiVisible = mCurrentState.enabled
-                    && (mCurrentState.connected || !mHasMobileData);
-            String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
-            boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
-            String contentDescription = getStringIfExists(getContentDescription());
-            int length = mSignalsChangedCallbacks.size();
-            for (int i = 0; i < length; i++) {
-                mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled,
-                        mCurrentState.connected, getQsCurrentIconId(),
-                        ssidPresent && mCurrentState.activityIn,
-                        ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc);
-            }
-
-            int signalClustersLength = mSignalClusters.size();
-            for (int i = 0; i < signalClustersLength; i++) {
-                mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(),
-                        contentDescription);
-            }
-        }
-
-        /**
-         * Extract wifi state directly from broadcasts about changes in wifi state.
-         */
-        public void handleBroadcast(Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                final NetworkInfo networkInfo = (NetworkInfo)
-                        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
-                mCurrentState.connected = networkInfo != null && networkInfo.isConnected();
-                // If Connected grab the signal strength and ssid.
-                if (mCurrentState.connected) {
-                    // try getting it out of the intent first
-                    WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
-                            ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
-                            : mWifiManager.getConnectionInfo();
-                    if (info != null) {
-                        mCurrentState.ssid = getSsid(info);
-                    } else {
-                        mCurrentState.ssid = null;
-                    }
-                } else if (!mCurrentState.connected) {
-                    mCurrentState.ssid = null;
-                }
-            } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
-                // Default to -200 as its below WifiManager.MIN_RSSI.
-                mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
-                mCurrentState.level = WifiManager.calculateSignalLevel(
-                        mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT);
-            }
-
-            notifyListenersIfNecessary();
-        }
-
-        private String getSsid(WifiInfo info) {
-            String ssid = info.getSSID();
-            if (ssid != null) {
-                return ssid;
-            }
-            // OK, it's not in the connectionInfo; we have to go hunting for it
-            List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
-            int length = networks.size();
-            for (int i = 0; i < length; i++) {
-                if (networks.get(i).networkId == info.getNetworkId()) {
-                    return networks.get(i).SSID;
-                }
-            }
-            return null;
-        }
-
-        @VisibleForTesting
-        void setActivity(int wifiActivity) {
-            mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                    || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
-            mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
-                    || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
-            notifyListenersIfNecessary();
-        }
-
-        /**
-         * Handler to receive the data activity on wifi.
-         */
-        class WifiHandler extends Handler {
-            @Override
-            public void handleMessage(Message msg) {
-                switch (msg.what) {
-                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
-                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                            mWifiChannel.sendMessage(Message.obtain(this,
-                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
-                        } else {
-                            Log.e(mTag, "Failed to connect to wifi");
-                        }
-                        break;
-                    case WifiManager.DATA_ACTIVITY_NOTIFICATION:
-                        setActivity(msg.arg1);
-                        break;
-                    default:
-                        // Ignore
-                        break;
-                }
-            }
-        }
-
-        static class WifiState extends SignalController.State {
-            String ssid;
-
-            @Override
-            public void copyFrom(State s) {
-                super.copyFrom(s);
-                WifiState state = (WifiState) s;
-                ssid = state.ssid;
-            }
-
-            @Override
-            protected void toString(StringBuilder builder) {
-                super.toString(builder);
-                builder.append(',').append("ssid=").append(ssid);
-            }
-
-            @Override
-            public boolean equals(Object o) {
-                return super.equals(o)
-                        && Objects.equals(((WifiState) o).ssid, ssid);
-            }
-        }
-    }
-
-    // TODO: Move to its own file.
-    public static class MobileSignalController extends SignalController<
-            MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> {
-        private final TelephonyManager mPhone;
-        private final String mNetworkNameDefault;
-        private final String mNetworkNameSeparator;
-        @VisibleForTesting
-        final PhoneStateListener mPhoneStateListener;
-        // Save entire info for logging, we only use the id.
-        private final SubscriptionInfo mSubscriptionInfo;
-
-        // @VisibleForDemoMode
-        final SparseArray<MobileIconGroup> mNetworkToIconLookup;
-
-        // Since some pieces of the phone state are interdependent we store it locally,
-        // this could potentially become part of MobileState for simplification/complication
-        // of code.
-        private IccCardConstants.State mSimState = IccCardConstants.State.READY;
-        private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        private int mDataState = TelephonyManager.DATA_DISCONNECTED;
-        private ServiceState mServiceState;
-        private SignalStrength mSignalStrength;
-        private MobileIconGroup mDefaultIcons;
-        private Config mConfig;
-
-        // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
-        // need listener lists anymore.
-        public MobileSignalController(Context context, Config config, boolean hasMobileData,
-                TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks,
-                List<SignalCluster> signalClusters, NetworkControllerImpl networkController,
-                SubscriptionInfo info) {
-            super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
-                    NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters,
-                    networkController);
-            mNetworkToIconLookup = new SparseArray<>();
-            mConfig = config;
-            mPhone = phone;
-            mSubscriptionInfo = info;
-            mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId());
-            mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
-            mNetworkNameDefault = getStringIfExists(
-                    com.android.internal.R.string.lockscreen_carrier_default);
-
-            mapIconSets();
-
-            mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault;
-            mLastState.enabled = mCurrentState.enabled = hasMobileData;
-            mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
-            // Get initial data sim state.
-            updateDataSim();
-        }
-
-        public void setConfiguration(Config config) {
-            mConfig = config;
-            mapIconSets();
-            updateTelephony();
-        }
-
-        /**
-         * Get (the mobile parts of) the carrier string.
-         *
-         * @param currentLabel can be used for concatenation, currently just empty
-         * @param connected whether the device has connection to the internet at all
-         * @param isMobileLabel whether to always return the network or just when data is connected
-         */
-        public String getLabel(String currentLabel, boolean connected, boolean isMobileLabel) {
-            if (!mCurrentState.enabled) {
-                return "";
-            } else {
-                String mobileLabel = "";
-                // We want to show the carrier name if in service and either:
-                // - We are connected to mobile data, or
-                // - We are not connected to mobile data, as long as the *reason* packets are not
-                //   being routed over that link is that we have better connectivity via wifi.
-                // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
-                // is connected, we show nothing.
-                // Otherwise (nothing connected) we show "No internet connection".
-                if (mCurrentState.dataConnected) {
-                    mobileLabel = mCurrentState.networkName;
-                } else if (connected || mCurrentState.isEmergency) {
-                    if (mCurrentState.connected || mCurrentState.isEmergency) {
-                        // The isEmergencyOnly test covers the case of a phone with no SIM
-                        mobileLabel = mCurrentState.networkName;
-                    }
-                } else {
-                    mobileLabel = mContext.getString(
-                            R.string.status_bar_settings_signal_meter_disconnected);
-                }
-
-                if (currentLabel.length() != 0) {
-                    currentLabel = currentLabel + mNetworkNameSeparator;
-                }
-                // Now for things that should only be shown when actually using mobile data.
-                if (isMobileLabel) {
-                    return currentLabel + mobileLabel;
-                } else {
-                    return currentLabel
-                            + (mCurrentState.dataConnected ? mobileLabel : currentLabel);
-                }
-            }
-        }
-
-        public int getDataContentDescription() {
-            return getIcons().mDataContentDescription;
-        }
-
-        public void setAirplaneMode(boolean airplaneMode) {
-            mCurrentState.airplaneMode = airplaneMode;
-            notifyListenersIfNecessary();
-        }
-
-        public void setInetCondition(int inetCondition, int inetConditionForNetwork) {
-            // For mobile data, use general inet condition for phone signal indexing,
-            // and network specific for data indexing (I think this might be a bug, but
-            // keeping for now).
-            // TODO: Update with explanation of why.
-            mCurrentState.inetForNetwork = inetConditionForNetwork;
-            setInetCondition(inetCondition);
-        }
-
-        /**
-         * Start listening for phone state changes.
-         */
-        public void registerListener() {
-            mPhone.listen(mPhoneStateListener,
-                    PhoneStateListener.LISTEN_SERVICE_STATE
-                            | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
-                            | PhoneStateListener.LISTEN_CALL_STATE
-                            | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
-                            | PhoneStateListener.LISTEN_DATA_ACTIVITY);
-        }
-
-        /**
-         * Stop listening for phone state changes.
-         */
-        public void unregisterListener() {
-            mPhone.listen(mPhoneStateListener, 0);
-        }
-
-        /**
-         * Produce a mapping of data network types to icon groups for simple and quick use in
-         * updateTelephony.
-         */
-        private void mapIconSets() {
-            mNetworkToIconLookup.clear();
-
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
-
-            if (!mConfig.showAtLeast3G) {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                        TelephonyIcons.UNKNOWN);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
-
-                mDefaultIcons = TelephonyIcons.G;
-            } else {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                        TelephonyIcons.THREE_G);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
-                        TelephonyIcons.THREE_G);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
-                        TelephonyIcons.THREE_G);
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
-                        TelephonyIcons.THREE_G);
-                mDefaultIcons = TelephonyIcons.THREE_G;
-            }
-
-            MobileIconGroup hGroup = TelephonyIcons.THREE_G;
-            if (mConfig.hspaDataDistinguishable) {
-                hGroup = TelephonyIcons.H;
-            }
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
-            mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup);
-
-            if (mConfig.show4gForLte) {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
-            } else {
-                mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
-            }
-        }
-
-        @Override
-        public void notifyListeners() {
-            MobileIconGroup icons = getIcons();
-
-            String contentDescription = getStringIfExists(getContentDescription());
-            String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
-
-            boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0
-                    || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
-
-            // Only send data sim callbacks to QS.
-            if (mCurrentState.dataSim) {
-                int qsTypeIcon = showDataIcon ? icons.mQsDataType[mCurrentState.inetForNetwork] : 0;
-                int length = mSignalsChangedCallbacks.size();
-                for (int i = 0; i < length; i++) {
-                    mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled
-                            && !mCurrentState.isEmergency,
-                            getQsCurrentIconId(), contentDescription,
-                            qsTypeIcon,
-                            mCurrentState.dataConnected && mCurrentState.activityIn,
-                            mCurrentState.dataConnected && mCurrentState.activityOut,
-                            dataContentDescription,
-                            mCurrentState.isEmergency ? null : mCurrentState.networkName,
-                            // Only wide if actually showing something.
-                            icons.mIsWide && qsTypeIcon != 0);
-                }
-            }
-            int typeIcon = showDataIcon ? icons.mDataType : 0;
-            int signalClustersLength = mSignalClusters.size();
-            for (int i = 0; i < signalClustersLength; i++) {
-                mSignalClusters.get(i).setMobileDataIndicators(
-                        mCurrentState.enabled && !mCurrentState.airplaneMode,
-                        getCurrentIconId(),
-                        typeIcon,
-                        contentDescription,
-                        dataContentDescription,
-                        // Only wide if actually showing something.
-                        icons.mIsWide && typeIcon != 0,
-                        mSubscriptionInfo.getSubscriptionId());
-            }
-        }
-
-        @Override
-        protected MobileState cleanState() {
-            return new MobileState();
-        }
-
-        private boolean hasService() {
-            if (mServiceState != null) {
-                // Consider the device to be in service if either voice or data
-                // service is available. Some SIM cards are marketed as data-only
-                // and do not support voice service, and on these SIM cards, we
-                // want to show signal bars for data service as well as the "no
-                // service" or "emergency calls only" text that indicates that voice
-                // is not available.
-                switch (mServiceState.getVoiceRegState()) {
-                    case ServiceState.STATE_POWER_OFF:
-                        return false;
-                    case ServiceState.STATE_OUT_OF_SERVICE:
-                    case ServiceState.STATE_EMERGENCY_ONLY:
-                        return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
-                    default:
-                        return true;
-                }
-            } else {
-                return false;
-            }
-        }
-
-        private boolean isCdma() {
-            return (mSignalStrength != null) && !mSignalStrength.isGsm();
-        }
-
-        public boolean isEmergencyOnly() {
-            return (mServiceState != null && mServiceState.isEmergencyOnly());
-        }
-
-        private boolean isRoaming() {
-            if (isCdma()) {
-                final int iconMode = mServiceState.getCdmaEriIconMode();
-                return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF
-                        && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
-                            || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH);
-            } else {
-                return mServiceState != null && mServiceState.getRoaming();
-            }
-        }
-
-        public void handleBroadcast(Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
-                updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
-                        intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
-                        intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
-                notifyListenersIfNecessary();
-            } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
-                updateDataSim();
-            }
-        }
-
-        private void updateDataSim() {
-            int defaultDataSub = SubscriptionManager.getDefaultDataSubId();
-            if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) {
-                mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId();
-            } else {
-                // There doesn't seem to be a data sim selected, however if
-                // there isn't a MobileSignalController with dataSim set, then
-                // QS won't get any callbacks and will be blank.  Instead
-                // lets just assume we are the data sim (which will basically
-                // show one at random) in QS until one is selected.  The user
-                // should pick one soon after, so we shouldn't be in this state
-                // for long.
-                mCurrentState.dataSim = true;
-            }
-            notifyListenersIfNecessary();
-        }
-
-        /**
-         * Updates the network's name based on incoming spn and plmn.
-         */
-        void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
-            if (CHATTY) {
-                Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
-                        + " showPlmn=" + showPlmn + " plmn=" + plmn);
-            }
-            StringBuilder str = new StringBuilder();
-            if (showPlmn && plmn != null) {
-                str.append(plmn);
-            }
-            if (showSpn && spn != null) {
-                if (str.length() != 0) {
-                    str.append(mNetworkNameSeparator);
-                }
-                str.append(spn);
-            }
-            if (str.length() != 0) {
-                mCurrentState.networkName = str.toString();
-            } else {
-                mCurrentState.networkName = mNetworkNameDefault;
-            }
-        }
-
-        /**
-         * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
-         * mDataState, and mSimState.  It should be called any time one of these is updated.
-         * This will call listeners if necessary.
-         */
-        private final void updateTelephony() {
-            if (DEBUG) {
-                Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService()
-                        + " ss=" + mSignalStrength);
-            }
-            mCurrentState.connected = hasService() && mSignalStrength != null;
-            if (mCurrentState.connected) {
-                if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
-                    mCurrentState.level = mSignalStrength.getCdmaLevel();
-                } else {
-                    mCurrentState.level = mSignalStrength.getLevel();
-                }
-            }
-            if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
-                mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
-            } else {
-                mCurrentState.iconGroup = mDefaultIcons;
-            }
-            mCurrentState.dataConnected = mCurrentState.connected
-                    && mDataState == TelephonyManager.DATA_CONNECTED;
-
-            if (isRoaming()) {
-                mCurrentState.iconGroup = TelephonyIcons.ROAMING;
-            }
-            if (isEmergencyOnly() != mCurrentState.isEmergency) {
-                mCurrentState.isEmergency = isEmergencyOnly();
-                mNetworkController.recalculateEmergency();
-            }
-            // Fill in the network name if we think we have it.
-            if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null
-                    && mServiceState.getOperatorAlphaShort() != null) {
-                mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
-            }
-            notifyListenersIfNecessary();
-        }
-
-        @VisibleForTesting
-        void setActivity(int activity) {
-            mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
-                    || activity == TelephonyManager.DATA_ACTIVITY_IN;
-            mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT
-                    || activity == TelephonyManager.DATA_ACTIVITY_OUT;
-            notifyListenersIfNecessary();
-        }
-
-        @Override
-        public void dump(PrintWriter pw) {
-            super.dump(pw);
-            pw.println("  mSubscription=" + mSubscriptionInfo + ",");
-            pw.println("  mServiceState=" + mServiceState + ",");
-            pw.println("  mSignalStrength=" + mSignalStrength + ",");
-            pw.println("  mDataState=" + mDataState + ",");
-            pw.println("  mDataNetType=" + mDataNetType + ",");
-        }
-
-        class MobilePhoneStateListener extends PhoneStateListener {
-            public MobilePhoneStateListener(int subId) {
-                super(subId);
-            }
-
-            @Override
-            public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-                if (DEBUG) {
-                    Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength +
-                            ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
-                }
-                mSignalStrength = signalStrength;
-                updateTelephony();
-            }
-
-            @Override
-            public void onServiceStateChanged(ServiceState state) {
-                if (DEBUG) {
-                    Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
-                            + " dataState=" + state.getDataRegState());
-                }
-                mServiceState = state;
-                updateTelephony();
-            }
-
-            @Override
-            public void onDataConnectionStateChanged(int state, int networkType) {
-                if (DEBUG) {
-                    Log.d(mTag, "onDataConnectionStateChanged: state=" + state
-                            + " type=" + networkType);
-                }
-                mDataState = state;
-                mDataNetType = networkType;
-                updateTelephony();
-            }
-
-            @Override
-            public void onDataActivity(int direction) {
-                if (DEBUG) {
-                    Log.d(mTag, "onDataActivity: direction=" + direction);
-                }
-                setActivity(direction);
-            }
-        };
-
-        static class MobileIconGroup extends SignalController.IconGroup {
-            final int mDataContentDescription; // mContentDescriptionDataType
-            final int mDataType;
-            final boolean mIsWide;
-            final int[] mQsDataType;
-
-            public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
-                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
-                    int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
-                    int[] qsDataType) {
-                super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState,
-                        qsDiscState, discContentDesc);
-                mDataContentDescription = dataContentDesc;
-                mDataType = dataType;
-                mIsWide = isWide;
-                mQsDataType = qsDataType;
-            }
-        }
-
-        static class MobileState extends SignalController.State {
-            String networkName;
-            boolean dataSim;
-            boolean dataConnected;
-            boolean isEmergency;
-            boolean airplaneMode;
-            int inetForNetwork;
-
-            @Override
-            public void copyFrom(State s) {
-                super.copyFrom(s);
-                MobileState state = (MobileState) s;
-                dataSim = state.dataSim;
-                networkName = state.networkName;
-                dataConnected = state.dataConnected;
-                inetForNetwork = state.inetForNetwork;
-                isEmergency = state.isEmergency;
-                airplaneMode = state.airplaneMode;
-            }
-
-            @Override
-            protected void toString(StringBuilder builder) {
-                super.toString(builder);
-                builder.append(',');
-                builder.append("dataSim=").append(dataSim).append(',');
-                builder.append("networkName=").append(networkName).append(',');
-                builder.append("dataConnected=").append(dataConnected).append(',');
-                builder.append("inetForNetwork=").append(inetForNetwork).append(',');
-                builder.append("isEmergency=").append(isEmergency).append(',');
-                builder.append("airplaneMode=").append(airplaneMode);
-            }
-
-            @Override
-            public boolean equals(Object o) {
-                return super.equals(o)
-                        && Objects.equals(((MobileState) o).networkName, networkName)
-                        && ((MobileState) o).dataSim == dataSim
-                        && ((MobileState) o).dataConnected == dataConnected
-                        && ((MobileState) o).isEmergency == isEmergency
-                        && ((MobileState) o).airplaneMode == airplaneMode
-                        && ((MobileState) o).inetForNetwork == inetForNetwork;
-            }
-        }
-    }
-
-    /**
-     * Common base class for handling signal for both wifi and mobile data.
-     */
-    static abstract class SignalController<T extends SignalController.State,
-            I extends SignalController.IconGroup> {
-        protected final String mTag;
-        protected final T mCurrentState;
-        protected final T mLastState;
-        protected final int mTransportType;
-        protected final Context mContext;
-        // The owner of the SignalController (i.e. NetworkController will maintain the following
-        // lists and call notifyListeners whenever the list has changed to ensure everyone
-        // is aware of current state.
-        protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks;
-        protected final List<SignalCluster> mSignalClusters;
-        protected final NetworkControllerImpl mNetworkController;
-
-        // Save the previous HISTORY_SIZE states for logging.
-        private final State[] mHistory;
-        // Where to copy the next state into.
-        private int mHistoryIndex;
-
-        public SignalController(String tag, Context context, int type,
-                List<NetworkSignalChangedCallback> signalCallbacks,
-                List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
-            mTag = TAG + "." + tag;
-            mNetworkController = networkController;
-            mTransportType = type;
-            mContext = context;
-            mSignalsChangedCallbacks = signalCallbacks;
-            mSignalClusters = signalClusters;
-            mCurrentState = cleanState();
-            mLastState = cleanState();
-            if (RECORD_HISTORY) {
-                mHistory = new State[HISTORY_SIZE];
-                for (int i = 0; i < HISTORY_SIZE; i++) {
-                    mHistory[i] = cleanState();
-                }
-            }
-        }
-
-        public T getState() {
-            return mCurrentState;
-        }
-
-        public int getTransportType() {
-            return mTransportType;
-        }
-
-        public void setInetCondition(int inetCondition) {
-            mCurrentState.inetCondition = inetCondition;
-            notifyListenersIfNecessary();
-        }
-
-        /**
-         * Used at the end of demo mode to clear out any ugly state that it has created.
-         * Since we haven't had any callbacks, then isDirty will not have been triggered,
-         * so we can just take the last good state directly from there.
-         *
-         * Used for demo mode.
-         */
-        void resetLastState() {
-            mCurrentState.copyFrom(mLastState);
-        }
-
-        /**
-         * Determines if the state of this signal controller has changed and
-         * needs to trigger callbacks related to it.
-         */
-        public boolean isDirty() {
-            if (!mLastState.equals(mCurrentState)) {
-                if (DEBUG) {
-                    Log.d(mTag, "Change in state from: " + mLastState + "\n"
-                            + "\tto: " + mCurrentState);
-                }
-                return true;
-            }
-            return false;
-        }
-
-        public void saveLastState() {
-            if (RECORD_HISTORY) {
-                recordLastState();
-            }
-            // Updates the current time.
-            mCurrentState.time = System.currentTimeMillis();
-            mLastState.copyFrom(mCurrentState);
-        }
-
-        /**
-         * Gets the signal icon for QS based on current state of connected, enabled, and level.
-         */
-        public int getQsCurrentIconId() {
-            if (mCurrentState.connected) {
-                return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level];
-            } else if (mCurrentState.enabled) {
-                return getIcons().mQsDiscState;
-            } else {
-                return getIcons().mQsNullState;
-            }
-        }
-
-        /**
-         * Gets the signal icon for SB based on current state of connected, enabled, and level.
-         */
-        public int getCurrentIconId() {
-            if (mCurrentState.connected) {
-                return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level];
-            } else if (mCurrentState.enabled) {
-                return getIcons().mSbDiscState;
-            } else {
-                return getIcons().mSbNullState;
-            }
-        }
-
-        /**
-         * Gets the content description id for the signal based on current state of connected and
-         * level.
-         */
-        public int getContentDescription() {
-            if (mCurrentState.connected) {
-                return getIcons().mContentDesc[mCurrentState.level];
-            } else {
-                return getIcons().mDiscContentDesc;
-            }
-        }
-
-        public void notifyListenersIfNecessary() {
-            if (isDirty()) {
-                saveLastState();
-                notifyListeners();
-                mNetworkController.refreshCarrierLabel();
-            }
-        }
-
-        /**
-         * Returns the resource if resId is not 0, and an empty string otherwise.
-         */
-        protected String getStringIfExists(int resId) {
-            return resId != 0 ? mContext.getString(resId) : "";
-        }
-
-        protected I getIcons() {
-            return (I) mCurrentState.iconGroup;
-        }
-
-        /**
-         * Saves the last state of any changes, so we can log the current
-         * and last value of any state data.
-         */
-        protected void recordLastState() {
-            mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState);
-        }
-
-        public void dump(PrintWriter pw) {
-            pw.println("  - " + mTag + " -----");
-            pw.println("  Current State: " + mCurrentState);
-            if (RECORD_HISTORY) {
-                // Count up the states that actually contain time stamps, and only display those.
-                int size = 0;
-                for (int i = 0; i < HISTORY_SIZE; i++) {
-                    if (mHistory[i].time != 0) size++;
-                }
-                // Print out the previous states in ordered number.
-                for (int i = mHistoryIndex + HISTORY_SIZE - 1;
-                        i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
-                    pw.println("  Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + ": "
-                            + mHistory[i & (HISTORY_SIZE - 1)]);
-                }
-            }
-        }
-
-        /**
-         * Trigger callbacks based on current state.  The callbacks should be completely
-         * based on current state, and only need to be called in the scenario where
-         * mCurrentState != mLastState.
-         */
-        public abstract void notifyListeners();
-
-        /**
-         * Generate a blank T.
-         */
-        protected abstract T cleanState();
-
-        /*
-         * Holds icons for a given state. Arrays are generally indexed as inet
-         * state (full connectivity or not) first, and second dimension as
-         * signal strength.
-         */
-        static class IconGroup {
-            final int[][] mSbIcons;
-            final int[][] mQsIcons;
-            final int[] mContentDesc;
-            final int mSbNullState;
-            final int mQsNullState;
-            final int mSbDiscState;
-            final int mQsDiscState;
-            final int mDiscContentDesc;
-            // For logging.
-            final String mName;
-
-            public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
-                    int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
-                    int discContentDesc) {
-                mName = name;
-                mSbIcons = sbIcons;
-                mQsIcons = qsIcons;
-                mContentDesc = contentDesc;
-                mSbNullState = sbNullState;
-                mQsNullState = qsNullState;
-                mSbDiscState = sbDiscState;
-                mQsDiscState = qsDiscState;
-                mDiscContentDesc = discContentDesc;
-            }
-
-            @Override
-            public String toString() {
-                return "IconGroup(" + mName + ")";
-            }
-        }
-
-        static class State {
-            boolean connected;
-            boolean enabled;
-            boolean activityIn;
-            boolean activityOut;
-            int level;
-            IconGroup iconGroup;
-            int inetCondition;
-            int rssi; // Only for logging.
-
-            // Not used for comparison, just used for logging.
-            long time;
-
-            public void copyFrom(State state) {
-                connected = state.connected;
-                enabled = state.enabled;
-                level = state.level;
-                iconGroup = state.iconGroup;
-                inetCondition = state.inetCondition;
-                activityIn = state.activityIn;
-                activityOut = state.activityOut;
-                rssi = state.rssi;
-                time = state.time;
-            }
-
-            @Override
-            public String toString() {
-                if (time != 0) {
-                    StringBuilder builder = new StringBuilder();
-                    toString(builder);
-                    return builder.toString();
-                } else {
-                    return "Empty " + getClass().getSimpleName();
-                }
-            }
-
-            protected void toString(StringBuilder builder) {
-                builder.append("connected=").append(connected).append(',')
-                        .append("enabled=").append(enabled).append(',')
-                        .append("level=").append(level).append(',')
-                        .append("inetCondition=").append(inetCondition).append(',')
-                        .append("iconGroup=").append(iconGroup).append(',')
-                        .append("activityIn=").append(activityIn).append(',')
-                        .append("activityOut=").append(activityOut).append(',')
-                        .append("rssi=").append(rssi).append(',')
-                        .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time));
-            }
-
-            @Override
-            public boolean equals(Object o) {
-                if (!o.getClass().equals(getClass())) {
-                    return false;
-                }
-                State other = (State) o;
-                return other.connected == connected
-                        && other.enabled == enabled
-                        && other.level == level
-                        && other.inetCondition == inetCondition
-                        && other.iconGroup == iconGroup
-                        && other.activityIn == activityIn
-                        && other.activityOut == activityOut
-                        && other.rssi == rssi;
-            }
-        }
-    }
-
     public interface SignalCluster {
         void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 030cd6d..34068fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
new file mode 100644
index 0000000..7d721c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.R;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+/**
+ * Host for the remote input.
+ */
+public class RemoteInputView extends FrameLayout implements View.OnClickListener {
+
+    private static final String TAG = "RemoteInput";
+
+    private RemoteEditText mEditText;
+    private ProgressBar mProgressBar;
+    private PendingIntent mPendingIntent;
+    private RemoteInput mRemoteInput;
+    private Notification.Action mAction;
+
+    public RemoteInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mProgressBar = (ProgressBar) findViewById(R.id.remote_input_progress);
+
+        mEditText = (RemoteEditText) getChildAt(0);
+        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+
+                // Check if this was the result of hitting the enter key
+                final boolean isSoftImeEvent = event == null
+                        && (actionId == EditorInfo.IME_ACTION_DONE
+                        || actionId == EditorInfo.IME_ACTION_NEXT
+                        || actionId == EditorInfo.IME_ACTION_SEND);
+                final boolean isKeyboardEnterKey = event != null
+                        && KeyEvent.isConfirmKey(event.getKeyCode())
+                        && event.getAction() == KeyEvent.ACTION_DOWN;
+
+                if (isSoftImeEvent || isKeyboardEnterKey) {
+                    sendRemoteInput();
+                    return true;
+                }
+                return false;
+            }
+        });
+        mEditText.setOnClickListener(this);
+        mEditText.setInnerFocusable(false);
+    }
+
+    private void sendRemoteInput() {
+        Bundle results = new Bundle();
+        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
+        Intent fillInIntent = new Intent();
+        RemoteInput.addResultsToIntent(mAction.getRemoteInputs(), fillInIntent,
+                results);
+
+        mEditText.setEnabled(false);
+        mProgressBar.setVisibility(VISIBLE);
+
+        try {
+            mPendingIntent.send(mContext, 0, fillInIntent);
+        } catch (PendingIntent.CanceledException e) {
+            Log.i(TAG, "Unable to send remote input result", e);
+        }
+    }
+
+    public static RemoteInputView inflate(Context context, ViewGroup root,
+            Notification.Action action, RemoteInput remoteInput) {
+        RemoteInputView v = (RemoteInputView)
+                LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
+
+        v.mEditText.setHint(action.title);
+        v.mPendingIntent = action.actionIntent;
+        v.mRemoteInput = remoteInput;
+        v.mAction = action;
+
+        return v;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mEditText) {
+            if (!mEditText.isFocusable()) {
+                mEditText.setInnerFocusable(true);
+                InputMethodManager imm = InputMethodManager.getInstance();
+                if (imm != null) {
+                    imm.viewClicked(mEditText);
+                    imm.showSoftInput(mEditText, 0);
+                }
+            }
+        }
+    }
+
+    /**
+     * An EditText that changes appearance based on whether it's focusable and becomes
+     * un-focusable whenever the user navigates away from it or it becomes invisible.
+     */
+    public static class RemoteEditText extends EditText {
+
+        private final Drawable mBackground;
+
+        public RemoteEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mBackground = getBackground();
+        }
+
+        private void defocusIfNeeded() {
+            if (isFocusable() && isEnabled()) {
+                setInnerFocusable(false);
+            }
+        }
+
+        @Override
+        protected void onVisibilityChanged(View changedView, int visibility) {
+            super.onVisibilityChanged(changedView, visibility);
+
+            if (!isShown()) {
+                defocusIfNeeded();
+            }
+        }
+
+        @Override
+        protected void onFocusLost() {
+            super.onFocusLost();
+            defocusIfNeeded();
+        }
+
+        @Override
+        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                defocusIfNeeded();
+            }
+            return super.onKeyPreIme(keyCode, event);
+        }
+
+
+        void setInnerFocusable(boolean focusable) {
+            setFocusableInTouchMode(focusable);
+            setFocusable(focusable);
+            setCursorVisible(focusable);
+
+            if (focusable) {
+                requestFocus();
+                setBackground(mBackground);
+            } else {
+                setBackground(null);
+            }
+
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
new file mode 100644
index 0000000..1d96c6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import static com.android.systemui.statusbar.policy.NetworkControllerImpl.TAG;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.util.Log;
+
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+
+/**
+ * Common base class for handling signal for both wifi and mobile data.
+ */
+public abstract class SignalController<T extends SignalController.State,
+        I extends SignalController.IconGroup> {
+    // Save the previous SignalController.States of all SignalControllers for dumps.
+    static final boolean RECORD_HISTORY = true;
+    // If RECORD_HISTORY how many to save, must be a power of 2.
+    static final int HISTORY_SIZE = 64;
+
+    protected static final boolean DEBUG = NetworkControllerImpl.DEBUG;
+    protected static final boolean CHATTY = NetworkControllerImpl.CHATTY;
+
+    protected final String mTag;
+    protected final T mCurrentState;
+    protected final T mLastState;
+    protected final int mTransportType;
+    protected final Context mContext;
+    // The owner of the SignalController (i.e. NetworkController will maintain the following
+    // lists and call notifyListeners whenever the list has changed to ensure everyone
+    // is aware of current state.
+    protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks;
+    protected final List<SignalCluster> mSignalClusters;
+    protected final NetworkControllerImpl mNetworkController;
+
+    // Save the previous HISTORY_SIZE states for logging.
+    private final State[] mHistory;
+    // Where to copy the next state into.
+    private int mHistoryIndex;
+
+    public SignalController(String tag, Context context, int type,
+            List<NetworkSignalChangedCallback> signalCallbacks,
+            List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+        mTag = TAG + "." + tag;
+        mNetworkController = networkController;
+        mTransportType = type;
+        mContext = context;
+        mSignalsChangedCallbacks = signalCallbacks;
+        mSignalClusters = signalClusters;
+        mCurrentState = cleanState();
+        mLastState = cleanState();
+        if (RECORD_HISTORY) {
+            mHistory = new State[HISTORY_SIZE];
+            for (int i = 0; i < HISTORY_SIZE; i++) {
+                mHistory[i] = cleanState();
+            }
+        }
+    }
+
+    public T getState() {
+        return mCurrentState;
+    }
+
+    public int getTransportType() {
+        return mTransportType;
+    }
+
+    public void setInetCondition(int inetCondition) {
+        mCurrentState.inetCondition = inetCondition;
+        notifyListenersIfNecessary();
+    }
+
+    /**
+     * Used at the end of demo mode to clear out any ugly state that it has created.
+     * Since we haven't had any callbacks, then isDirty will not have been triggered,
+     * so we can just take the last good state directly from there.
+     *
+     * Used for demo mode.
+     */
+    public void resetLastState() {
+        mCurrentState.copyFrom(mLastState);
+    }
+
+    /**
+     * Determines if the state of this signal controller has changed and
+     * needs to trigger callbacks related to it.
+     */
+    public boolean isDirty() {
+        if (!mLastState.equals(mCurrentState)) {
+            if (DEBUG) {
+                Log.d(mTag, "Change in state from: " + mLastState + "\n"
+                        + "\tto: " + mCurrentState);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void saveLastState() {
+        if (RECORD_HISTORY) {
+            recordLastState();
+        }
+        // Updates the current time.
+        mCurrentState.time = System.currentTimeMillis();
+        mLastState.copyFrom(mCurrentState);
+    }
+
+    /**
+     * Gets the signal icon for QS based on current state of connected, enabled, and level.
+     */
+    public int getQsCurrentIconId() {
+        if (mCurrentState.connected) {
+            return getIcons().mQsIcons[mCurrentState.inetCondition][mCurrentState.level];
+        } else if (mCurrentState.enabled) {
+            return getIcons().mQsDiscState;
+        } else {
+            return getIcons().mQsNullState;
+        }
+    }
+
+    /**
+     * Gets the signal icon for SB based on current state of connected, enabled, and level.
+     */
+    public int getCurrentIconId() {
+        if (mCurrentState.connected) {
+            return getIcons().mSbIcons[mCurrentState.inetCondition][mCurrentState.level];
+        } else if (mCurrentState.enabled) {
+            return getIcons().mSbDiscState;
+        } else {
+            return getIcons().mSbNullState;
+        }
+    }
+
+    /**
+     * Gets the content description id for the signal based on current state of connected and
+     * level.
+     */
+    public int getContentDescription() {
+        if (mCurrentState.connected) {
+            return getIcons().mContentDesc[mCurrentState.level];
+        } else {
+            return getIcons().mDiscContentDesc;
+        }
+    }
+
+    public void notifyListenersIfNecessary() {
+        if (isDirty()) {
+            saveLastState();
+            notifyListeners();
+        }
+    }
+
+    /**
+     * Returns the resource if resId is not 0, and an empty string otherwise.
+     */
+    protected String getStringIfExists(int resId) {
+        return resId != 0 ? mContext.getString(resId) : "";
+    }
+
+    protected I getIcons() {
+        return (I) mCurrentState.iconGroup;
+    }
+
+    /**
+     * Saves the last state of any changes, so we can log the current
+     * and last value of any state data.
+     */
+    protected void recordLastState() {
+        mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)].copyFrom(mLastState);
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("  - " + mTag + " -----");
+        pw.println("  Current State: " + mCurrentState);
+        if (RECORD_HISTORY) {
+            // Count up the states that actually contain time stamps, and only display those.
+            int size = 0;
+            for (int i = 0; i < HISTORY_SIZE; i++) {
+                if (mHistory[i].time != 0) size++;
+            }
+            // Print out the previous states in ordered number.
+            for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+                    i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+                pw.println("  Previous State(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
+                        + mHistory[i & (HISTORY_SIZE - 1)]);
+            }
+        }
+    }
+
+    /**
+     * Trigger callbacks based on current state.  The callbacks should be completely
+     * based on current state, and only need to be called in the scenario where
+     * mCurrentState != mLastState.
+     */
+    public abstract void notifyListeners();
+
+    /**
+     * Generate a blank T.
+     */
+    protected abstract T cleanState();
+
+    /*
+     * Holds icons for a given state. Arrays are generally indexed as inet
+     * state (full connectivity or not) first, and second dimension as
+     * signal strength.
+     */
+    static class IconGroup {
+        final int[][] mSbIcons;
+        final int[][] mQsIcons;
+        final int[] mContentDesc;
+        final int mSbNullState;
+        final int mQsNullState;
+        final int mSbDiscState;
+        final int mQsDiscState;
+        final int mDiscContentDesc;
+        // For logging.
+        final String mName;
+
+        public IconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
+                int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
+                int discContentDesc) {
+            mName = name;
+            mSbIcons = sbIcons;
+            mQsIcons = qsIcons;
+            mContentDesc = contentDesc;
+            mSbNullState = sbNullState;
+            mQsNullState = qsNullState;
+            mSbDiscState = sbDiscState;
+            mQsDiscState = qsDiscState;
+            mDiscContentDesc = discContentDesc;
+        }
+
+        @Override
+        public String toString() {
+            return "IconGroup(" + mName + ")";
+        }
+    }
+
+    static class State {
+        boolean connected;
+        boolean enabled;
+        boolean activityIn;
+        boolean activityOut;
+        int level;
+        IconGroup iconGroup;
+        int inetCondition;
+        int rssi; // Only for logging.
+
+        // Not used for comparison, just used for logging.
+        long time;
+
+        public void copyFrom(State state) {
+            connected = state.connected;
+            enabled = state.enabled;
+            level = state.level;
+            iconGroup = state.iconGroup;
+            inetCondition = state.inetCondition;
+            activityIn = state.activityIn;
+            activityOut = state.activityOut;
+            rssi = state.rssi;
+            time = state.time;
+        }
+
+        @Override
+        public String toString() {
+            if (time != 0) {
+                StringBuilder builder = new StringBuilder();
+                toString(builder);
+                return builder.toString();
+            } else {
+                return "Empty " + getClass().getSimpleName();
+            }
+        }
+
+        protected void toString(StringBuilder builder) {
+            builder.append("connected=").append(connected).append(',')
+                    .append("enabled=").append(enabled).append(',')
+                    .append("level=").append(level).append(',')
+                    .append("inetCondition=").append(inetCondition).append(',')
+                    .append("iconGroup=").append(iconGroup).append(',')
+                    .append("activityIn=").append(activityIn).append(',')
+                    .append("activityOut=").append(activityOut).append(',')
+                    .append("rssi=").append(rssi).append(',')
+                    .append("lastModified=").append(DateFormat.format("MM-dd hh:mm:ss", time));
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!o.getClass().equals(getClass())) {
+                return false;
+            }
+            State other = (State) o;
+            return other.connected == connected
+                    && other.enabled == enabled
+                    && other.level == level
+                    && other.inetCondition == inetCondition
+                    && other.iconGroup == iconGroup
+                    && other.activityIn == activityIn
+                    && other.activityOut == activityOut
+                    && other.rssi == rssi;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 4091619..d266ed8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController.MobileIconGroup;
+import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
 
 class TelephonyIcons {
     //***** Signal strength icons
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
new file mode 100644
index 0000000..a97ca50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AsyncChannel;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+
+import java.util.List;
+import java.util.Objects;
+
+
+public class WifiSignalController extends
+        SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
+    private final WifiManager mWifiManager;
+    private final AsyncChannel mWifiChannel;
+    private final boolean mHasMobileData;
+
+    public WifiSignalController(Context context, boolean hasMobileData,
+            List<NetworkSignalChangedCallback> signalCallbacks,
+            List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+        super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
+                signalCallbacks, signalClusters, networkController);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mHasMobileData = hasMobileData;
+        Handler handler = new WifiHandler();
+        mWifiChannel = new AsyncChannel();
+        Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+        if (wifiMessenger != null) {
+            mWifiChannel.connect(context, handler, wifiMessenger);
+        }
+        // WiFi only has one state.
+        mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
+                "Wi-Fi Icons",
+                WifiIcons.WIFI_SIGNAL_STRENGTH,
+                WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
+                AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
+                WifiIcons.WIFI_NO_NETWORK,
+                WifiIcons.QS_WIFI_NO_NETWORK,
+                WifiIcons.WIFI_NO_NETWORK,
+                WifiIcons.QS_WIFI_NO_NETWORK,
+                AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+                );
+    }
+
+    @Override
+    protected WifiState cleanState() {
+        return new WifiState();
+    }
+
+    @Override
+    public void notifyListeners() {
+        // only show wifi in the cluster if connected or if wifi-only
+        boolean wifiVisible = mCurrentState.enabled
+                && (mCurrentState.connected || !mHasMobileData);
+        String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
+        boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
+        String contentDescription = getStringIfExists(getContentDescription());
+        int length = mSignalsChangedCallbacks.size();
+        for (int i = 0; i < length; i++) {
+            mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled,
+                    mCurrentState.connected, getQsCurrentIconId(),
+                    ssidPresent && mCurrentState.activityIn,
+                    ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc);
+        }
+
+        int signalClustersLength = mSignalClusters.size();
+        for (int i = 0; i < signalClustersLength; i++) {
+            mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(),
+                    contentDescription);
+        }
+    }
+
+    /**
+     * Extract wifi state directly from broadcasts about changes in wifi state.
+     */
+    public void handleBroadcast(Intent intent) {
+        String action = intent.getAction();
+        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+            mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+            final NetworkInfo networkInfo = (NetworkInfo)
+                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+            mCurrentState.connected = networkInfo != null && networkInfo.isConnected();
+            // If Connected grab the signal strength and ssid.
+            if (mCurrentState.connected) {
+                // try getting it out of the intent first
+                WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
+                        ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
+                        : mWifiManager.getConnectionInfo();
+                if (info != null) {
+                    mCurrentState.ssid = getSsid(info);
+                } else {
+                    mCurrentState.ssid = null;
+                }
+            } else if (!mCurrentState.connected) {
+                mCurrentState.ssid = null;
+            }
+        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+            // Default to -200 as its below WifiManager.MIN_RSSI.
+            mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+            mCurrentState.level = WifiManager.calculateSignalLevel(
+                    mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT);
+        }
+
+        notifyListenersIfNecessary();
+    }
+
+    private String getSsid(WifiInfo info) {
+        String ssid = info.getSSID();
+        if (ssid != null) {
+            return ssid;
+        }
+        // OK, it's not in the connectionInfo; we have to go hunting for it
+        List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+        int length = networks.size();
+        for (int i = 0; i < length; i++) {
+            if (networks.get(i).networkId == info.getNetworkId()) {
+                return networks.get(i).SSID;
+            }
+        }
+        return null;
+    }
+
+    @VisibleForTesting
+    void setActivity(int wifiActivity) {
+        mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
+        mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+                || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
+        notifyListenersIfNecessary();
+    }
+
+    /**
+     * Handler to receive the data activity on wifi.
+     */
+    private class WifiHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        mWifiChannel.sendMessage(Message.obtain(this,
+                                AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
+                    } else {
+                        Log.e(mTag, "Failed to connect to wifi");
+                    }
+                    break;
+                case WifiManager.DATA_ACTIVITY_NOTIFICATION:
+                    setActivity(msg.arg1);
+                    break;
+                default:
+                    // Ignore
+                    break;
+            }
+        }
+    }
+
+    static class WifiState extends SignalController.State {
+        String ssid;
+
+        @Override
+        public void copyFrom(State s) {
+            super.copyFrom(s);
+            WifiState state = (WifiState) s;
+            ssid = state.ssid;
+        }
+
+        @Override
+        protected void toString(StringBuilder builder) {
+            super.toString(builder);
+            builder.append(',').append("ssid=").append(ssid);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return super.equals(o)
+                    && Objects.equals(((WifiState) o).ssid, ssid);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 600b750..0e21457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -31,6 +31,7 @@
     void setUserId(int userId);
     boolean isZenAvailable();
     ComponentName getEffectsSuppressor();
+    boolean isCountdownConditionSupported();
 
     public static class Callback {
         public void onZenChanged(int zen) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 37ed7d8..bea0c86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.policy;
 
 import android.app.AlarmManager;
-import android.app.INotificationManager;
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -28,8 +27,6 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -53,7 +50,7 @@
     private final Context mContext;
     private final GlobalSetting mModeSetting;
     private final GlobalSetting mConfigSetting;
-    private final INotificationManager mNoMan;
+    private final NotificationManager mNoMan;
     private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
     private final AlarmManager mAlarmManager;
     private final SetupObserver mSetupObserver;
@@ -78,8 +75,7 @@
         };
         mModeSetting.setListening(true);
         mConfigSetting.setListening(true);
-        mNoMan = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mSetupObserver = new SetupObserver(handler);
         mSetupObserver.register();
@@ -113,11 +109,7 @@
     @Override
     public void requestConditions(boolean request) {
         mRequesting = request;
-        try {
-            mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
-        } catch (RemoteException e) {
-            // noop
-        }
+        mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
         if (!mRequesting) {
             mConditions.clear();
         }
@@ -125,24 +117,12 @@
 
     @Override
     public void setExitCondition(Condition exitCondition) {
-        try {
-            mNoMan.setZenModeCondition(exitCondition);
-        } catch (RemoteException e) {
-            // noop
-        }
+        mNoMan.setZenModeCondition(exitCondition);
     }
 
     @Override
     public Condition getExitCondition() {
-        try {
-            final ZenModeConfig config = mNoMan.getZenModeConfig();
-            if (config != null) {
-                return config.exitCondition;
-            }
-        } catch (RemoteException e) {
-            // noop
-        }
-        return null;
+        return mNoMan.getZenModeCondition();
     }
 
     @Override
@@ -169,6 +149,12 @@
         return NotificationManager.from(mContext).getEffectsSuppressor();
     }
 
+    @Override
+    public boolean isCountdownConditionSupported() {
+        return NotificationManager.from(mContext)
+                .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
+    }
+
     private void fireNextAlarmChanged() {
         for (Callback cb : mCallbacks) {
             cb.onNextAlarmChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
new file mode 100644
index 0000000..3c9e8cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A container containing child notifications
+ */
+public class NotificationChildrenContainer extends ViewGroup {
+
+    private final int mChildPadding;
+    private final int mDividerHeight;
+    private final int mMaxNotificationHeight;
+    private final List<View> mDividers = new ArrayList<>();
+    private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
+    private final View mCollapseButton;
+    private final View mCollapseDivider;
+    private final int mCollapseButtonHeight;
+    private final int mNotificationAppearDistance;
+
+    public NotificationChildrenContainer(Context context) {
+        this(context, null);
+    }
+
+    public NotificationChildrenContainer(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mChildPadding = getResources().getDimensionPixelSize(
+                R.dimen.notification_children_padding);
+        mDividerHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_children_divider_height);
+        mMaxNotificationHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_max_height);
+        mNotificationAppearDistance = getResources().getDimensionPixelSize(
+                R.dimen.notification_appear_distance);
+        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+        mCollapseButton = inflater.inflate(R.layout.notification_collapse_button, this,
+                false);
+        mCollapseButtonHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_bottom_decor_height);
+        addView(mCollapseButton);
+        mCollapseDivider = inflateDivider();
+        addView(mCollapseDivider);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int childCount = mChildren.size();
+        boolean firstChild = true;
+        for (int i = 0; i < childCount; i++) {
+            View child = mChildren.get(i);
+            boolean viewGone = child.getVisibility() == View.GONE;
+            if (i != 0) {
+                View divider = mDividers.get(i - 1);
+                int dividerVisibility = divider.getVisibility();
+                int newVisibility = viewGone ? INVISIBLE : VISIBLE;
+                if (dividerVisibility != newVisibility) {
+                    divider.setVisibility(newVisibility);
+                }
+            }
+            if (viewGone) {
+                continue;
+            }
+            child.layout(0, 0, getWidth(), child.getMeasuredHeight());
+            if (!firstChild) {
+                mDividers.get(i - 1).layout(0, 0, getWidth(), mDividerHeight);
+            } else {
+                firstChild = false;
+            }
+        }
+        mCollapseButton.layout(0, 0, getWidth(), mCollapseButtonHeight);
+        mCollapseDivider.layout(0, mCollapseButtonHeight - mDividerHeight, getWidth(),
+                mCollapseButtonHeight);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int ownMaxHeight = mMaxNotificationHeight;
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
+        boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
+        if (hasFixedHeight || isHeightLimited) {
+            int size = MeasureSpec.getSize(heightMeasureSpec);
+            ownMaxHeight = Math.min(ownMaxHeight, size);
+        }
+        int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+        int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
+        int collapseButtonHeightSpec = MeasureSpec.makeMeasureSpec(mCollapseButtonHeight,
+                MeasureSpec.EXACTLY);
+        mCollapseButton.measure(widthMeasureSpec, collapseButtonHeightSpec);
+        mCollapseDivider.measure(widthMeasureSpec, dividerHeightSpec);
+        int height = mCollapseButtonHeight;
+        int childCount = mChildren.size();
+        boolean firstChild = true;
+        for (int i = 0; i < childCount; i++) {
+            View child = mChildren.get(i);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            child.measure(widthMeasureSpec, newHeightSpec);
+            height += child.getMeasuredHeight();
+            if (!firstChild) {
+                // layout the divider
+                View divider = mDividers.get(i - 1);
+                divider.measure(widthMeasureSpec, dividerHeightSpec);
+                height += mChildPadding;
+            } else {
+                firstChild = false;
+            }
+        }
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        height = hasFixedHeight ? ownMaxHeight
+                : isHeightLimited ? Math.min(ownMaxHeight, height)
+                : height;
+        setMeasuredDimension(width, height);
+    }
+
+    /**
+     * Add a child notification to this view.
+     *
+     * @param row the row to add
+     * @param childIndex the index to add it at, if -1 it will be added at the end
+     */
+    public void addNotification(ExpandableNotificationRow row, int childIndex) {
+        int newIndex = childIndex < 0 ? mChildren.size() : childIndex;
+        mChildren.add(newIndex, row);
+        addView(row);
+        if (mChildren.size() != 1) {
+            View divider = inflateDivider();
+            addView(divider);
+            mDividers.add(Math.max(newIndex - 1, 0), divider);
+        }
+        // TODO: adapt background corners
+        // TODO: fix overdraw
+    }
+
+    public void removeNotification(ExpandableNotificationRow row) {
+        int childIndex = mChildren.indexOf(row);
+        mChildren.remove(row);
+        removeView(row);
+        if (!mDividers.isEmpty()) {
+            View divider = mDividers.remove(Math.max(childIndex - 1, 0));
+            removeView(divider);
+        }
+        row.setSystemChildExpanded(false);
+        // TODO: adapt background corners
+    }
+
+    private View inflateDivider() {
+        return LayoutInflater.from(mContext).inflate(
+                R.layout.notification_children_divider, this, false);
+    }
+
+    public List<ExpandableNotificationRow> getNotificationChildren() {
+        return mChildren;
+    }
+
+    /**
+     * Apply the order given in the list to the children.
+     *
+     * @param childOrder the new list order
+     * @return whether the list order has changed
+     */
+    public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) {
+        if (childOrder == null) {
+            return false;
+        }
+        boolean result = false;
+        for (int i = 0; i < mChildren.size() && i < childOrder.size(); i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            ExpandableNotificationRow desiredChild = childOrder.get(i);
+            if (child != desiredChild) {
+                mChildren.remove(desiredChild);
+                mChildren.add(i, desiredChild);
+                result = true;
+            }
+        }
+
+        // Let's make the first child expanded!
+        boolean first = true;
+        for (int i = 0; i < childOrder.size(); i++) {
+            ExpandableNotificationRow child = childOrder.get(i);
+            child.setSystemChildExpanded(first);
+            first = false;
+        }
+        return result;
+    }
+
+    public int getIntrinsicHeight() {
+        int childCount = mChildren.size();
+        int intrinsicHeight = 0;
+        int visibleChildren = 0;
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            intrinsicHeight += child.getIntrinsicHeight();
+            visibleChildren++;
+        }
+        if (visibleChildren > 0) {
+            intrinsicHeight += (visibleChildren - 1) * mDividerHeight;
+        }
+        return intrinsicHeight;
+    }
+
+    /**
+     * Update the state of all its children based on a linear layout algorithm.
+     *
+     * @param resultState the state to update
+     * @param parentState the state of the parent
+     */
+    public void getState(StackScrollState resultState, StackViewState parentState) {
+        int childCount = mChildren.size();
+        int yPosition = mCollapseButtonHeight;
+        boolean firstChild = true;
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            if (!firstChild) {
+                // There's a divider
+                yPosition += mChildPadding;
+            } else {
+                firstChild = false;
+            }
+            StackViewState childState = resultState.getViewStateForView(child);
+            int intrinsicHeight = child.getIntrinsicHeight();
+            childState.yTranslation = yPosition;
+            childState.zTranslation = 0;
+            childState.height = intrinsicHeight;
+            childState.dimmed = parentState.dimmed;
+            childState.dark = parentState.dark;
+            childState.hideSensitive = parentState.hideSensitive;
+            childState.belowSpeedBump = parentState.belowSpeedBump;
+            childState.scale =  parentState.scale;
+            childState.clipTopAmount = 0;
+            childState.topOverLap = 0;
+            childState.location = parentState.location;
+            yPosition += intrinsicHeight;
+        }
+    }
+
+    public void applyState(StackScrollState state) {
+        int childCount = mChildren.size();
+        boolean firstChild = true;
+        ViewState dividerState = new ViewState();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            StackViewState viewState = state.getViewStateForView(child);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            if (!firstChild) {
+                // layout the divider
+                View divider = mDividers.get(i - 1);
+                dividerState.initFrom(divider);
+                dividerState.yTranslation = (int) (viewState.yTranslation
+                        - (mChildPadding + mDividerHeight) / 2.0f);
+                dividerState.alpha = 1;
+                state.applyViewState(divider, dividerState);
+            } else {
+                firstChild = false;
+            }
+            state.applyState(child, viewState);
+        }
+    }
+
+    public void setCollapseClickListener(OnClickListener collapseClickListener) {
+        mCollapseButton.setOnClickListener(collapseClickListener);
+    }
+
+    /**
+     * This is called when the children expansion has changed and positions the children properly
+     * for an appear animation.
+     *
+     * @param state the new state we animate to
+     */
+    public void prepareExpansionChanged(StackScrollState state) {
+        int childCount = mChildren.size();
+        boolean firstChild = true;
+        StackViewState sourceState = new StackViewState();
+        ViewState dividerState = new ViewState();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            StackViewState viewState = state.getViewStateForView(child);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            if (!firstChild) {
+                // layout the divider
+                View divider = mDividers.get(i - 1);
+                dividerState.initFrom(divider);
+                dividerState.yTranslation = viewState.yTranslation
+                        - (mChildPadding + mDividerHeight) / 2.0f + mNotificationAppearDistance;
+                dividerState.alpha = 0;
+                state.applyViewState(divider, dividerState);
+            } else {
+                firstChild = false;
+            }
+            sourceState.copyFrom(viewState);
+            sourceState.alpha = 0;
+            sourceState.yTranslation += mNotificationAppearDistance;
+            state.applyState(child, sourceState);
+        }
+        mCollapseButton.setAlpha(0);
+        mCollapseDivider.setAlpha(0);
+        mCollapseDivider.setTranslationY(mNotificationAppearDistance / 4);
+    }
+
+    public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
+            boolean withDelays, long baseDelay, long duration) {
+        int childCount = mChildren.size();
+        boolean firstChild = true;
+        ViewState dividerState = new ViewState();
+        int notGoneIndex = 0;
+        for (int i = 0; i < childCount; i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            StackViewState viewState = state.getViewStateForView(child);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
+                    notGoneIndex + 1);
+            long delay = withDelays
+                    ? difference * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN
+                    : 0;
+            delay += baseDelay;
+            if (!firstChild) {
+                // layout the divider
+                View divider = mDividers.get(i - 1);
+                dividerState.initFrom(divider);
+                dividerState.yTranslation = viewState.yTranslation
+                        - (mChildPadding + mDividerHeight) / 2.0f;
+                dividerState.alpha = 1;
+                stateAnimator.startViewAnimations(divider, dividerState, delay, duration);
+            } else {
+                firstChild = false;
+            }
+            stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
+            notGoneIndex++;
+        }
+        dividerState.initFrom(mCollapseButton);
+        dividerState.alpha = 1.0f;
+        stateAnimator.startViewAnimations(mCollapseButton, dividerState, baseDelay, duration);
+        dividerState.initFrom(mCollapseDivider);
+        dividerState.alpha = 1.0f;
+        dividerState.yTranslation = 0.0f;
+        stateAnimator.startViewAnimations(mCollapseDivider, dividerState, baseDelay, duration);
+    }
+
+    public ExpandableNotificationRow getViewAtPosition(float y) {
+        // find the view under the pointer, accounting for GONE views
+        final int count = mChildren.size();
+        for (int childIdx = 0; childIdx < count; childIdx++) {
+            ExpandableNotificationRow slidingChild = mChildren.get(childIdx);
+            float childTop = slidingChild.getTranslationY();
+            float top = childTop + slidingChild.getClipTopAmount();
+            float bottom = childTop + slidingChild.getActualHeight();
+            if (y >= top && y <= bottom) {
+                return slidingChild;
+            }
+        }
+        return null;
+    }
+
+    public void setTintColor(int color) {
+        ExpandableNotificationRow.applyTint(mCollapseDivider, color);
+    }
+}
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 6dcbed6..2eafd57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -41,12 +41,13 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
-import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -56,7 +57,7 @@
  */
 public class NotificationStackScrollLayout extends ViewGroup
         implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
-        ExpandableView.OnHeightChangedListener {
+        ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
 
     private static final String TAG = "NotificationStackScrollLayout";
     private static final boolean DEBUG = false;
@@ -119,6 +120,7 @@
      */
     private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
     private AmbientState mAmbientState = new AmbientState();
+    private NotificationGroupManager mGroupManager;
     private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
     private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
     private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
@@ -181,6 +183,7 @@
     private boolean mDontReportNextOverScroll;
     private boolean mRequestViewResizeAnimationOnLayout;
     private boolean mNeedViewResizeAnimation;
+    private View mExpandedGroupView;
     private boolean mEverythingNeedsAnimation;
 
     /**
@@ -214,6 +217,8 @@
     };
     private PhoneStatusBar mPhoneStatusBar;
     private int[] mTempInt2 = new int[2];
+    private boolean mGenerateChildOrderChangedEvent;
+    private boolean mRemoveAnimationEnabled;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -309,7 +314,7 @@
 
     private void notifyHeightChangeListener(ExpandableView view) {
         if (mOnHeightChangedListener != null) {
-            mOnHeightChangedListener.onHeightChanged(view);
+            mOnHeightChangedListener.onHeightChanged(view, false /* needsAnimation */);
         }
     }
 
@@ -329,6 +334,9 @@
         float centerX = getWidth() / 2.0f;
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
             float width = child.getMeasuredWidth();
             float height = child.getMeasuredHeight();
             child.layout((int) (centerX - width / 2.0f),
@@ -339,16 +347,18 @@
         setMaxLayoutHeight(getHeight());
         updateContentHeight();
         clampScrollPosition();
-        requestAnimationOnViewResize();
+        if (mRequestViewResizeAnimationOnLayout) {
+            requestAnimationOnViewResize();
+            mRequestViewResizeAnimationOnLayout = false;
+        }
         requestChildrenUpdate();
     }
 
     private void requestAnimationOnViewResize() {
-        if (mRequestViewResizeAnimationOnLayout && mIsExpanded && mAnimationsEnabled) {
+        if (mIsExpanded && mAnimationsEnabled) {
             mNeedViewResizeAnimation = true;
             mNeedsAnimation = true;
         }
-        mRequestViewResizeAnimationOnLayout = false;
     }
 
     public void updateSpeedBumpIndex(int newIndex) {
@@ -375,15 +385,15 @@
      * Returns the location the given child is currently rendered at.
      *
      * @param child the child to get the location for
-     * @return one of {@link ViewState}'s <code>LOCATION_*</code> constants
+     * @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants
      */
     public int getChildLocation(View child) {
-        ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+        StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
         if (childViewState == null) {
-            return ViewState.LOCATION_UNKNOWN;
+            return StackViewState.LOCATION_UNKNOWN;
         }
         if (childViewState.gone) {
-            return ViewState.LOCATION_GONE;
+            return StackViewState.LOCATION_GONE;
         }
         return childViewState.location;
     }
@@ -645,6 +655,10 @@
             int right = getWidth();
 
             if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
+                if (slidingChild instanceof ExpandableNotificationRow) {
+                    ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
+                    return row.getViewAtPosition(touchY - childTop);
+                }
                 return slidingChild;
             }
         }
@@ -723,7 +737,6 @@
     }
 
     public void dismissViewAnimated(View child, Runnable endRunnable, int delay, long duration) {
-        child.setClipBounds(null);
         mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration);
     }
 
@@ -1544,6 +1557,14 @@
     @Override
     protected void onViewRemoved(View child) {
         super.onViewRemoved(child);
+        // we only call our internal methods if this is actually a removal and not just a
+        // notification which becomes a child notification
+        if (!isChildInGroup(child)) {
+            onViewRemovedInternal(child);
+        }
+    }
+
+    private void onViewRemovedInternal(View child) {
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         if (mChangePositionInProgress) {
             // This is only a position change, don't do anything special
@@ -1552,16 +1573,27 @@
         ((ExpandableView) child).setOnHeightChangedListener(null);
         mCurrentStackScrollState.removeViewStateForView(child);
         updateScrollStateForRemovedChild(child);
-        boolean animationGenerated = generateRemoveAnimation(child);
-        if (animationGenerated && !mSwipedOutViews.contains(child)) {
-            // Add this view to an overlay in order to ensure that it will still be temporary
-            // drawn when removed
-            getOverlay().add(child);
+        if (mRemoveAnimationEnabled) {
+            boolean animationGenerated = generateRemoveAnimation(child);
+            if (animationGenerated && !mSwipedOutViews.contains(child)) {
+                // Add this view to an overlay in order to ensure that it will still be temporary
+                // drawn when removed
+                getOverlay().add(child);
+            }
+        } else {
+            // TODO: handle this more cleanly when HEADS-up and the shade are merged
+            requestAnimateEverything();
         }
         updateAnimationState(false, child);
 
         // Make sure the clipRect we might have set is removed
-        child.setClipBounds(null);
+        ((ExpandableView) child).setClipTopOptimization(0);
+    }
+
+    private boolean isChildInGroup(View child) {
+        return child instanceof ExpandableNotificationRow
+                && mGroupManager.isChildInGroupWithSummary(
+                        ((ExpandableNotificationRow) child).getStatusBarNotification());
     }
 
     /**
@@ -1571,7 +1603,7 @@
      * @return Whether an animation was generated.
      */
     private boolean generateRemoveAnimation(View child) {
-        if (mIsExpanded && mAnimationsEnabled) {
+        if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 // Generate Animations
                 mChildrenToRemoveAnimated.add(child);
@@ -1587,6 +1619,23 @@
     }
 
     /**
+     * @param child the child to query
+     * @return whether a view is not a top level child but a child notification and that group is
+     *         not expanded
+     */
+    private boolean isChildInInvisibleGroup(View child) {
+        if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            ExpandableNotificationRow groupSummary =
+                    mGroupManager.getGroupSummary(row.getStatusBarNotification());
+            if (groupSummary != null && groupSummary != row) {
+                return !groupSummary.areChildrenExpanded();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Updates the scroll position when a child was removed
      *
      * @param removedChild the removed child
@@ -1634,6 +1683,10 @@
     @Override
     protected void onViewAdded(View child) {
         super.onViewAdded(child);
+        onViewAddedInternal(child);
+    }
+
+    private void onViewAddedInternal(View child) {
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         ((ExpandableView) child).setOnHeightChangedListener(this);
         generateAddAnimation(child, false /* fromMoreCard */);
@@ -1646,6 +1699,14 @@
         }
     }
 
+    public void notifyGroupChildRemoved(View row) {
+        onViewRemovedInternal(row);
+    }
+
+    public void notifyGroupChildAdded(View row) {
+        onViewAddedInternal(row);
+    }
+
     public void setAnimationsEnabled(boolean animationsEnabled) {
         mAnimationsEnabled = animationsEnabled;
         updateNotificationAnimationStates();
@@ -1741,10 +1802,20 @@
         generateDarkEvent();
         generateGoToFullShadeEvent();
         generateViewResizeEvent();
+        generateGroupExpansionEvent();
         generateAnimateEverythingEvent();
         mNeedsAnimation = false;
     }
 
+    private void generateGroupExpansionEvent() {
+        // Generate a group expansion/collapsing event if there is such a group at all
+        if (mExpandedGroupView != null) {
+            mAnimationEvents.add(new AnimationEvent(mExpandedGroupView,
+                    AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED));
+            mExpandedGroupView = null;
+        }
+    }
+
     private void generateViewResizeEvent() {
         if (mNeedViewResizeAnimation) {
             mAnimationEvents.add(
@@ -1791,6 +1862,11 @@
                     AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION));
         }
         mChildrenChangingPositions.clear();
+        if (mGenerateChildOrderChangedEvent) {
+            mAnimationEvents.add(new AnimationEvent(null,
+                    AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION));
+            mGenerateChildOrderChangedEvent = false;
+        }
     }
 
     private void generateChildAdditionEvents() {
@@ -2059,11 +2135,14 @@
     }
 
     @Override
-    public void onHeightChanged(ExpandableView view) {
+    public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
         updateContentHeight();
         updateScrollPositionOnExpandInBottom(view);
         clampScrollPosition();
         notifyHeightChangeListener(view);
+        if (needsAnimation) {
+            requestAnimationOnViewResize();
+        }
         requestChildrenUpdate();
     }
 
@@ -2338,6 +2417,20 @@
     public void setDismissAllInProgress(boolean dismissAllInProgress) {
         mDismissAllInProgress = dismissAllInProgress;
         mDismissView.setDismissAllInProgress(dismissAllInProgress);
+        if (dismissAllInProgress) {
+            disableClipOptimization();
+        }
+    }
+
+    private void disableClipOptimization() {
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            child.setClipTopOptimization(0);
+        }
     }
 
     public boolean isDismissViewNotGone() {
@@ -2392,28 +2485,97 @@
         this.mPhoneStatusBar = phoneStatusBar;
     }
 
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        this.mGroupManager = groupManager;
+    }
+
     public void onGoToKeyguard() {
+        requestAnimateEverything();
+    }
+
+    private void requestAnimateEverything() {
         if (mIsExpanded && mAnimationsEnabled) {
             mEverythingNeedsAnimation = true;
+            mNeedsAnimation = true;
             requestChildrenUpdate();
         }
     }
 
     private boolean isBelowLastNotification(float touchX, float touchY) {
-        ExpandableView lastChildNotGone = (ExpandableView) getLastChildNotGone();
-        if (lastChildNotGone == null) {
-            return touchY > mIntrinsicPadding;
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                float childTop = child.getY();
+                if (childTop > touchY) {
+                    // we are above a notification entirely let's abort
+                    return false;
+                }
+                boolean belowChild = touchY > childTop + child.getActualHeight();
+                if (child == mDismissView) {
+                    if(!belowChild && !mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
+                                    touchY - childTop)) {
+                        // We clicked on the dismiss button
+                        return false;
+                    }
+                } else if (child == mEmptyShadeView) {
+                    // We arrived at the empty shade view, for which we accept all clicks
+                    return true;
+                } else if (!belowChild){
+                    // We are on a child
+                    return false;
+                }
+            }
         }
-        if (lastChildNotGone != mDismissView && lastChildNotGone != mEmptyShadeView) {
-            return touchY > lastChildNotGone.getY() + lastChildNotGone.getActualHeight();
-        } else if (lastChildNotGone == mEmptyShadeView) {
-            return touchY > mEmptyShadeView.getY();
-        } else {
-            float dismissY = mDismissView.getY();
-            boolean belowDismissView = touchY > dismissY + mDismissView.getActualHeight();
-            return belowDismissView || (touchY > dismissY
-                    && mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
-                    touchY - dismissY));
+        return touchY > mIntrinsicPadding;
+    }
+
+    public void setRemoveAnimationEnabled(boolean enabled) {
+        mRemoveAnimationEnabled = enabled;
+    }
+
+    private void updateExpandButtons() {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                row.updateExpandButton();
+            }
+        }
+    }
+
+    @Override
+    public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
+        boolean animated = mAnimationsEnabled && mIsExpanded;
+        if (animated) {
+            mExpandedGroupView = changedRow;
+            mNeedsAnimation = true;
+        }
+        changedRow.setChildrenExpanded(expanded, animated);
+        onHeightChanged(changedRow, false /* needsAnimation */);
+    }
+
+    @Override
+    public void onGroupsProhibitedChanged() {
+        updateExpandButtons();
+    }
+
+    @Override
+    public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
+        for (NotificationData.Entry entry : group.children) {
+            ExpandableNotificationRow row = entry.row;
+            if (indexOfChild(row) != -1) {
+                removeView(row);
+                group.summary.row.addChildNotification(row);
+            }
+        }
+    }
+
+    public void generateChildOrderChangedEvent() {
+        if (mIsExpanded && mAnimationsEnabled) {
+            mGenerateChildOrderChangedEvent = true;
+            mNeedsAnimation = true;
+            requestChildrenUpdate();
         }
     }
 
@@ -2553,6 +2715,14 @@
                         .animateY()
                         .animateZ(),
 
+                // ANIMATION_TYPE_GROUP_EXPANSION_CHANGED
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateTopInset()
+                        .animateY()
+                        .animateZ(),
+
                 // ANIMATION_TYPE_EVERYTHING
                 new AnimationFilter()
                         .animateAlpha()
@@ -2607,6 +2777,9 @@
                 // ANIMATION_TYPE_VIEW_RESIZE
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
+                // ANIMATION_TYPE_GROUP_EXPANSION_CHANGED
+                StackStateAnimator.ANIMATION_DURATION_EXPAND_CLICKED,
+
                 // ANIMATION_TYPE_EVERYTHING
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
         };
@@ -2624,7 +2797,8 @@
         static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 10;
         static final int ANIMATION_TYPE_HIDE_SENSITIVE = 11;
         static final int ANIMATION_TYPE_VIEW_RESIZE = 12;
-        static final int ANIMATION_TYPE_EVERYTHING = 13;
+        static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 13;
+        static final int ANIMATION_TYPE_EVERYTHING = 14;
 
         static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
         static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
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 ddc4251..e7bf47b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -27,6 +27,7 @@
 import com.android.systemui.statusbar.ExpandableView;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The Algorithm of the {@link com.android.systemui.statusbar.stack
@@ -171,6 +172,19 @@
         updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
         updateClipping(resultState, algorithmState);
         updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
+        getNotificationChildrenStates(resultState, algorithmState);
+    }
+
+    private void getNotificationChildrenStates(StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState) {
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            ExpandableView v = algorithmState.visibleChildren.get(i);
+            if (v instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+                row.getChildrenStates(resultState);
+            }
+        }
     }
 
     private void updateSpeedBumpState(StackScrollState resultState,
@@ -178,7 +192,7 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            StackViewState childViewState = resultState.getViewStateForView(child);
 
             // The speed bump can also be gone, so equality needs to be taken when comparing
             // indices.
@@ -194,7 +208,7 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState state = resultState.getViewStateForView(child);
+            StackViewState state = resultState.getViewStateForView(child);
             float newYTranslation = state.yTranslation + state.height * (1f - state.scale) / 2f;
             float newHeight = state.height * state.scale;
             // apply clipping and shadow
@@ -242,8 +256,8 @@
      * @param backgroundHeight the desired background height. The shadows of the view will be
      *                         based on this height and the content will be clipped from the top
      */
-    private void updateChildClippingAndBackground(StackScrollState.ViewState state,
-            float realHeight, float clipHeight, float backgroundHeight) {
+    private void updateChildClippingAndBackground(StackViewState state, float realHeight,
+            float clipHeight, float backgroundHeight) {
         if (realHeight > clipHeight) {
             // Rather overlap than create a hole.
             state.topOverLap = (int) Math.floor((realHeight - clipHeight) / state.scale);
@@ -270,7 +284,7 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            StackViewState childViewState = resultState.getViewStateForView(child);
             childViewState.dimmed = dimmed;
             childViewState.dark = dark;
             childViewState.hideSensitive = hideSensitive;
@@ -297,14 +311,14 @@
                 if (!draggedViews.contains(nextChild)) {
                     // only if the view is not dragged itself we modify its state to be fully
                     // visible
-                    StackScrollState.ViewState viewState = resultState.getViewStateForView(
+                    StackViewState viewState = resultState.getViewStateForView(
                             nextChild);
                     // The child below the dragged one must be fully visible
                     viewState.alpha = 1;
                 }
 
                 // Lets set the alpha to the one it currently has, as its currently being dragged
-                StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView);
+                StackViewState viewState = resultState.getViewStateForView(draggedView);
                 // The dragged child should keep the set alpha
                 viewState.alpha = draggedView.getAlpha();
             }
@@ -320,12 +334,31 @@
         int childCount = hostView.getChildCount();
         state.visibleChildren.clear();
         state.visibleChildren.ensureCapacity(childCount);
+        int notGoneIndex = 0;
         for (int i = 0; i < childCount; i++) {
             ExpandableView v = (ExpandableView) hostView.getChildAt(i);
             if (v.getVisibility() != View.GONE) {
-                StackScrollState.ViewState viewState = resultState.getViewStateForView(v);
-                viewState.notGoneIndex = state.visibleChildren.size();
+                StackViewState viewState = resultState.getViewStateForView(v);
+                viewState.notGoneIndex = notGoneIndex;
                 state.visibleChildren.add(v);
+                notGoneIndex++;
+
+                // handle the notgoneIndex for the children as well
+                if (v instanceof ExpandableNotificationRow) {
+                    ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+                    List<ExpandableNotificationRow> children =
+                            row.getNotificationChildren();
+                    if (row.areChildrenExpanded() && children != null) {
+                        for (ExpandableNotificationRow childRow : children) {
+                            if (childRow.getVisibility() != View.GONE) {
+                                StackViewState childState
+                                        = resultState.getViewStateForView(childRow);
+                                childState.notGoneIndex = notGoneIndex;
+                                notGoneIndex++;
+                            }
+                        }
+                    }
+                }
             }
         }
     }
@@ -355,8 +388,8 @@
         int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
-            childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
+            StackViewState childViewState = resultState.getViewStateForView(child);
+            childViewState.location = StackViewState.LOCATION_UNKNOWN;
             int childHeight = getMaxAllowedChildHeight(child);
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
@@ -413,7 +446,7 @@
             } else {
                 // Case 3:
                 // We are in the regular scroll area.
-                childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+                childViewState.location = StackViewState.LOCATION_MAIN_AREA;
                 clampYTranslation(childViewState, childHeight);
             }
 
@@ -427,9 +460,9 @@
                             bottomPeekStart - mCollapseSecondCardPadding
                                     - childViewState.yTranslation, mCollapsedSize);
                 }
-                childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
+                childViewState.location = StackViewState.LOCATION_FIRST_CARD;
             }
-            if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
+            if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
                 Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
             }
             currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
@@ -445,7 +478,7 @@
      * @param childViewState the view state of the child
      * @param childHeight the height of this child
      */
-    private void clampYTranslation(StackScrollState.ViewState childViewState, int childHeight) {
+    private void clampYTranslation(StackViewState childViewState, int childHeight) {
         clampPositionToBottomStackStart(childViewState, childHeight);
         clampPositionToTopStackEnd(childViewState, childHeight);
     }
@@ -457,7 +490,7 @@
      * @param childViewState the view state of the child
      * @param childHeight the height of this child
      */
-    private void clampPositionToBottomStackStart(StackScrollState.ViewState childViewState,
+    private void clampPositionToBottomStackStart(StackViewState childViewState,
             int childHeight) {
         childViewState.yTranslation = Math.min(childViewState.yTranslation,
                 mInnerHeight - mBottomStackPeekSize - mCollapseSecondCardPadding - childHeight);
@@ -470,7 +503,7 @@
      * @param childViewState the view state of the child
      * @param childHeight the height of this child
      */
-    private void clampPositionToTopStackEnd(StackScrollState.ViewState childViewState,
+    private void clampPositionToTopStackEnd(StackViewState childViewState,
             int childHeight) {
         childViewState.yTranslation = Math.max(childViewState.yTranslation,
                 mCollapsedSize - childHeight);
@@ -489,7 +522,7 @@
 
     private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
             float transitioningPositionStart, float bottomPeakStart, float currentYPosition,
-            StackScrollState.ViewState childViewState, int childHeight) {
+            StackViewState childViewState, int childHeight) {
 
         // This is the transitioning element on top of bottom stack, calculate how far we are in.
         algorithmState.partialInBottom = 1.0f - (
@@ -510,11 +543,11 @@
 
         // We want at least to be at the end of the top stack when collapsing
         clampPositionToTopStackEnd(childViewState, newHeight);
-        childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+        childViewState.location = StackViewState.LOCATION_MAIN_AREA;
     }
 
     private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
-            float transitioningPositionStart, StackScrollState.ViewState childViewState,
+            float transitioningPositionStart, StackViewState childViewState,
             int childHeight) {
 
         float currentYPosition;
@@ -524,7 +557,7 @@
             currentYPosition = transitioningPositionStart
                     + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
                     - mPaddingBetweenElements;
-            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
+            childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
         } else {
             // we are fully inside the stack
             if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -533,7 +566,7 @@
                     > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
                 childViewState.alpha = 1.0f - algorithmState.partialInBottom;
             }
-            childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
+            childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             currentYPosition = mInnerHeight;
         }
         childViewState.yTranslation = currentYPosition - childHeight;
@@ -542,7 +575,7 @@
 
     private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
             int numberOfElementsCompletelyIn, int i, int childHeight,
-            StackScrollState.ViewState childViewState, float scrollOffset) {
+            StackViewState childViewState, float scrollOffset) {
 
 
         // First we calculate the index relative to the current stack window of size at most
@@ -574,7 +607,7 @@
                         - mTopStackIndentationFunctor.getValue(numItemsBefore);
                 childViewState.yTranslation = currentChildEndY - childHeight;
             }
-            childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+            childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING;
         } else {
             if (paddedIndex == -1) {
                 childViewState.alpha = 1.0f - algorithmState.partialInTop;
@@ -583,7 +616,7 @@
                 childViewState.alpha = 0.0f;
             }
             childViewState.yTranslation = mCollapsedSize - childHeight;
-            childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+            childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN;
         }
 
 
@@ -605,7 +638,7 @@
         // find the number of elements in the top stack.
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            StackViewState childViewState = resultState.getViewStateForView(child);
             int childHeight = getMaxAllowedChildHeight(child);
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
@@ -676,7 +709,7 @@
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
-            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            StackViewState childViewState = resultState.getViewStateForView(child);
             if (i < algorithmState.itemsInTopStack) {
                 float stackIndex = algorithmState.itemsInTopStack - i;
 
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 0b1ce8f..feae590 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.stack;
 
-import android.graphics.Rect;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -24,10 +23,12 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -39,13 +40,12 @@
     private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
 
     private final ViewGroup mHostView;
-    private Map<ExpandableView, ViewState> mStateMap;
-    private final Rect mClipRect = new Rect();
+    private Map<ExpandableView, StackViewState> mStateMap;
     private final int mClearAllTopPadding;
 
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
-        mStateMap = new HashMap<ExpandableView, ViewState>();
+        mStateMap = new HashMap<ExpandableView, StackViewState>();
         mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
                 R.dimen.clear_all_padding_top);
     }
@@ -58,20 +58,36 @@
         int numChildren = mHostView.getChildCount();
         for (int i = 0; i < numChildren; i++) {
             ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
-            ViewState viewState = mStateMap.get(child);
-            if (viewState == null) {
-                viewState = new ViewState();
-                mStateMap.put(child, viewState);
+            resetViewState(child);
+
+            // handling reset for child notifications
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                List<ExpandableNotificationRow> children =
+                        row.getNotificationChildren();
+                if (row.areChildrenExpanded() && children != null) {
+                    for (ExpandableNotificationRow childRow : children) {
+                        resetViewState(childRow);
+                    }
+                }
             }
-            // initialize with the default values of the view
-            viewState.height = child.getIntrinsicHeight();
-            viewState.gone = child.getVisibility() == View.GONE;
-            viewState.alpha = 1;
-            viewState.notGoneIndex = -1;
         }
     }
 
-    public ViewState getViewStateForView(View requestedView) {
+    private void resetViewState(ExpandableView view) {
+        StackViewState viewState = mStateMap.get(view);
+        if (viewState == null) {
+            viewState = new StackViewState();
+            mStateMap.put(view, viewState);
+        }
+        // initialize with the default values of the view
+        viewState.height = view.getIntrinsicHeight();
+        viewState.gone = view.getVisibility() == View.GONE;
+        viewState.alpha = 1;
+        viewState.notGoneIndex = -1;
+    }
+
+    public StackViewState getViewStateForView(View requestedView) {
         return mStateMap.get(requestedView);
     }
 
@@ -87,126 +103,139 @@
         int numChildren = mHostView.getChildCount();
         for (int i = 0; i < numChildren; i++) {
             ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
-            ViewState state = mStateMap.get(child);
-            if (state == null) {
-                Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
-                        "to the hostView");
+            StackViewState state = mStateMap.get(child);
+            if (!applyState(child, state)) {
                 continue;
             }
-            if (!state.gone) {
-                float alpha = child.getAlpha();
-                float yTranslation = child.getTranslationY();
-                float xTranslation = child.getTranslationX();
-                float zTranslation = child.getTranslationZ();
-                float scale = child.getScaleX();
-                int height = child.getActualHeight();
-                float newAlpha = state.alpha;
-                float newYTranslation = state.yTranslation;
-                float newZTranslation = state.zTranslation;
-                float newScale = state.scale;
-                int newHeight = state.height;
-                boolean becomesInvisible = newAlpha == 0.0f;
-                if (alpha != newAlpha && xTranslation == 0) {
-                    // apply layer type
-                    boolean becomesFullyVisible = newAlpha == 1.0f;
-                    boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible;
-                    int layerType = child.getLayerType();
-                    int newLayerType = newLayerTypeIsHardware
-                            ? View.LAYER_TYPE_HARDWARE
-                            : View.LAYER_TYPE_NONE;
-                    if (layerType != newLayerType) {
-                        child.setLayerType(newLayerType, null);
-                    }
-
-                    // apply alpha
-                    child.setAlpha(newAlpha);
-                }
-
-                // apply visibility
-                int oldVisibility = child.getVisibility();
-                int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
-                if (newVisibility != oldVisibility) {
-                    child.setVisibility(newVisibility);
-                }
-
-                // apply yTranslation
-                if (yTranslation != newYTranslation) {
-                    child.setTranslationY(newYTranslation);
-                }
-
-                // apply zTranslation
-                if (zTranslation != newZTranslation) {
-                    child.setTranslationZ(newZTranslation);
-                }
-
-                // apply scale
-                if (scale != newScale) {
-                    child.setScaleX(newScale);
-                    child.setScaleY(newScale);
-                }
-
-                // apply height
-                if (height != newHeight) {
-                    child.setActualHeight(newHeight, false /* notifyListeners */);
-                }
-
-                // apply dimming
-                child.setDimmed(state.dimmed, false /* animate */);
-
-                // apply dark
-                child.setDark(state.dark, false /* animate */, 0 /* delay */);
-
-                // apply hiding sensitive
-                child.setHideSensitive(
-                        state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
-
-                // apply speed bump state
-                child.setBelowSpeedBump(state.belowSpeedBump);
-
-                // apply clipping
-                float oldClipTopAmount = child.getClipTopAmount();
-                if (oldClipTopAmount != state.clipTopAmount) {
-                    child.setClipTopAmount(state.clipTopAmount);
-                }
-                updateChildClip(child, newHeight, state.topOverLap);
-
-                if(child instanceof SpeedBumpView) {
-                    performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
-                } else if (child instanceof DismissView) {
-                    DismissView dismissView = (DismissView) child;
-                    boolean visible = state.topOverLap < mClearAllTopPadding;
-                    dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
-                } else if (child instanceof EmptyShadeView) {
-                    EmptyShadeView emptyShadeView = (EmptyShadeView) child;
-                    boolean visible = state.topOverLap <= 0;
-                    emptyShadeView.performVisibilityAnimation(
-                            visible && !emptyShadeView.willBeGone());
-                }
+            if(child instanceof SpeedBumpView) {
+                performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
+            } else if (child instanceof DismissView) {
+                DismissView dismissView = (DismissView) child;
+                boolean visible = state.topOverLap < mClearAllTopPadding;
+                dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
+            } else if (child instanceof EmptyShadeView) {
+                EmptyShadeView emptyShadeView = (EmptyShadeView) child;
+                boolean visible = state.topOverLap <= 0;
+                emptyShadeView.performVisibilityAnimation(
+                        visible && !emptyShadeView.willBeGone());
             }
         }
     }
 
     /**
-     * Updates the clipping of a view
+     * Applies a  {@link StackViewState} to an  {@link ExpandableView}.
      *
-     * @param child the view to update
-     * @param height the currently applied height of the view
-     * @param clipInset how much should this view be clipped from the top
+     * @return whether the state was applied correctly
      */
-    private void updateChildClip(View child, int height, int clipInset) {
-        mClipRect.set(0,
-                clipInset,
-                child.getWidth(),
-                height);
-        child.setClipBounds(mClipRect);
+    public boolean applyState(ExpandableView view, StackViewState state) {
+        if (state == null) {
+            Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
+                    "to the hostView");
+            return false;
+        }
+        if (state.gone) {
+            return false;
+        }
+        applyViewState(view, state);
+
+        int height = view.getActualHeight();
+        int newHeight = state.height;
+
+        // apply height
+        if (height != newHeight) {
+            view.setActualHeight(newHeight, false /* notifyListeners */);
+        }
+
+        // apply dimming
+        view.setDimmed(state.dimmed, false /* animate */);
+
+        // apply dark
+        view.setDark(state.dark, false /* animate */, 0 /* delay */);
+
+        // apply hiding sensitive
+        view.setHideSensitive(
+                state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
+        // apply speed bump state
+        view.setBelowSpeedBump(state.belowSpeedBump);
+
+        // apply clipping
+        float oldClipTopAmount = view.getClipTopAmount();
+        if (oldClipTopAmount != state.clipTopAmount) {
+            view.setClipTopAmount(state.clipTopAmount);
+        }
+        float oldClipTopOptimization = view.getClipTopOptimization();
+        if (oldClipTopOptimization != state.topOverLap) {
+            view.setClipTopOptimization(state.topOverLap);
+        }
+        if (view instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            row.applyChildrenState(this);
+        }
+        return true;
     }
 
-    public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, ViewState state,
+    /**
+     * Applies a  {@link ViewState} to a normal view.
+     */
+    public void applyViewState(View view, ViewState state) {
+        float alpha = view.getAlpha();
+        float yTranslation = view.getTranslationY();
+        float xTranslation = view.getTranslationX();
+        float zTranslation = view.getTranslationZ();
+        float scale = view.getScaleX();
+        float newAlpha = state.alpha;
+        float newYTranslation = state.yTranslation;
+        float newZTranslation = state.zTranslation;
+        float newScale = state.scale;
+        boolean becomesInvisible = newAlpha == 0.0f;
+        if (alpha != newAlpha && xTranslation == 0) {
+            // apply layer type
+            boolean becomesFullyVisible = newAlpha == 1.0f;
+            boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
+                    && view.hasOverlappingRendering();
+            int layerType = view.getLayerType();
+            int newLayerType = newLayerTypeIsHardware
+                    ? View.LAYER_TYPE_HARDWARE
+                    : View.LAYER_TYPE_NONE;
+            if (layerType != newLayerType) {
+                view.setLayerType(newLayerType, null);
+            }
+
+            // apply alpha
+            view.setAlpha(newAlpha);
+        }
+
+        // apply visibility
+        int oldVisibility = view.getVisibility();
+        int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
+        if (newVisibility != oldVisibility) {
+            view.setVisibility(newVisibility);
+        }
+
+        // apply yTranslation
+        if (yTranslation != newYTranslation) {
+            view.setTranslationY(newYTranslation);
+        }
+
+        // apply zTranslation
+        if (zTranslation != newZTranslation) {
+            view.setTranslationZ(newZTranslation);
+        }
+
+        // apply scale
+        if (scale != newScale) {
+            view.setScaleX(newScale);
+            view.setScaleY(newScale);
+        }
+    }
+
+    public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, StackViewState state,
             long delay) {
         View nextChild = getNextChildNotGone(i);
         if (nextChild != null) {
             float lineEnd = state.yTranslation + state.height / 2;
-            ViewState nextState = getViewStateForView(nextChild);
+            StackViewState nextState = getViewStateForView(nextChild);
             boolean startIsAboveNext = nextState.yTranslation > lineEnd;
             speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */);
         }
@@ -223,53 +252,4 @@
         return null;
     }
 
-    public static class ViewState {
-
-        // These are flags such that we can create masks for filtering.
-
-        public static final int LOCATION_UNKNOWN = 0x00;
-        public static final int LOCATION_FIRST_CARD = 0x01;
-        public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
-        public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
-        public static final int LOCATION_MAIN_AREA = 0x08;
-        public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
-        public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
-        /** The view isn't layouted at all. */
-        public static final int LOCATION_GONE = 0x40;
-
-        float alpha;
-        float yTranslation;
-        float zTranslation;
-        int height;
-        boolean gone;
-        float scale;
-        boolean dimmed;
-        boolean dark;
-        boolean hideSensitive;
-        boolean belowSpeedBump;
-
-        /**
-         * The amount which the view should be clipped from the top. This is calculated to
-         * perceive consistent shadows.
-         */
-        int clipTopAmount;
-
-        /**
-         * How much does the child overlap with the previous view on the top? Can be used for
-         * a clipping optimization
-         */
-        int topOverLap;
-
-        /**
-         * The index of the view, only accounting for views not equal to GONE
-         */
-        int notGoneIndex;
-
-        /**
-         * The location this view is currently rendered at.
-         *
-         * <p>See <code>LOCATION_</code> flags.</p>
-         */
-        int location;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index b027787..b249fbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -26,6 +26,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
 
@@ -42,12 +43,15 @@
     public static final int ANIMATION_DURATION_STANDARD = 360;
     public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
     public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
+    public static final int ANIMATION_DURATION_EXPAND_CLICKED = 360;
     public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
     public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
+    public static final int ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN = 54;
     public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
     public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
     public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
-    private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
+    public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
+    public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN = 3;
 
     private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
     private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
@@ -85,6 +89,7 @@
 
     private ValueAnimator mTopOverScrollAnimator;
     private ValueAnimator mBottomOverScrollAnimator;
+    private ExpandableNotificationRow mChildExpandingView;
 
     public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
         mHostLayout = hostLayout;
@@ -113,13 +118,13 @@
         for (int i = 0; i < childCount; i++) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
 
-            StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
+            StackViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null || child.getVisibility() == View.GONE) {
                 continue;
             }
 
-            child.setClipBounds(null);
-            startAnimations(child, viewState, finalState, i);
+            child.setClipTopOptimization(0);
+            startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */);
         }
         if (!isRunning()) {
             // no child has preformed any animation, lets finish
@@ -127,6 +132,7 @@
         }
         mNewEvents.clear();
         mNewAddChildren.clear();
+        mChildExpandingView = null;
     }
 
     private int findLastNotAddedIndex(StackScrollState finalState) {
@@ -134,7 +140,7 @@
         for (int i = childCount - 1; i >= 0; i--) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
 
-            StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
+            StackViewState viewState = finalState.getViewStateForView(child);
             if (viewState == null || child.getVisibility() == View.GONE) {
                 continue;
             }
@@ -145,18 +151,29 @@
         return -1;
     }
 
-    /**
-     * Start an animation to the given viewState
-     */
-    private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
-            StackScrollState finalState, int i) {
-        int childVisibility = child.getVisibility();
-        boolean wasVisible = childVisibility == View.VISIBLE;
-        final float alpha = viewState.alpha;
-        if (!wasVisible && alpha != 0 && !viewState.gone) {
-            child.setVisibility(View.VISIBLE);
-        }
 
+    /**
+     * Start an animation to the given  {@link StackViewState}.
+     *
+     * @param child the child to start the animation on
+     * @param viewState the {@link StackViewState} of the view to animate to
+     * @param finalState the final state after the animation
+     * @param i the index of the view; only relevant if the view is the speed bump and is
+     *          ignored otherwise
+     * @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated
+     */
+    public void startStackAnimations(final ExpandableView child, StackViewState viewState,
+            StackScrollState finalState, int i, long fixedDelay) {
+        final float alpha = viewState.alpha;
+        boolean wasAdded = mNewAddChildren.contains(child);
+        long duration = mCurrentLength;
+        if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+            child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+            float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+            longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+            duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+                    (long) (100 * longerDurationFactor);
+        }
         boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
         boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
         boolean scaleChanging = child.getScaleX() != viewState.scale;
@@ -164,94 +181,40 @@
         boolean heightChanging = viewState.height != child.getActualHeight();
         boolean darkChanging = viewState.dark != child.isDark();
         boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
-        boolean wasAdded = mNewAddChildren.contains(child);
         boolean hasDelays = mAnimationFilter.hasDelays;
         boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
                 alphaChanging || heightChanging || topInsetChanging || darkChanging;
-        boolean noAnimation = wasAdded;
         long delay = 0;
-        long duration = mCurrentLength;
-        if (hasDelays && isDelayRelevant || wasAdded) {
+        if (fixedDelay != -1) {
+            delay = fixedDelay;
+        } else if (hasDelays && isDelayRelevant || wasAdded) {
             delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
         }
 
-        if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
-            child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
-            yTranslationChanging = true;
-            float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
-            longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
-            duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
-                    (long) (100 * longerDurationFactor);
-        }
-
-        // start translationY animation
-        if (yTranslationChanging) {
-            if (noAnimation && !mAnimationFilter.hasGoToFullShadeEvent) {
-                child.setTranslationY(viewState.yTranslation);
-            } else {
-                startYTranslationAnimation(child, viewState, duration, delay);
-            }
-        }
-
-        // start translationZ animation
-        if (zTranslationChanging) {
-            if (noAnimation) {
-                child.setTranslationZ(viewState.zTranslation);
-            } else {
-                startZTranslationAnimation(child, viewState, duration, delay);
-            }
-        }
-
-        // start scale animation
-        if (scaleChanging) {
-            if (noAnimation) {
-                child.setScaleX(viewState.scale);
-                child.setScaleY(viewState.scale);
-            } else {
-                startScaleAnimation(child, viewState, duration);
-            }
-        }
-
-        // start alpha animation
-        if (alphaChanging && child.getTranslationX() == 0) {
-            if (noAnimation) {
-                child.setAlpha(viewState.alpha);
-            } else {
-                startAlphaAnimation(child, viewState, duration, delay);
-            }
-        }
+        startViewAnimations(child, viewState, delay, duration);
 
         // start height animation
         if (heightChanging && child.getActualHeight() != 0) {
-            if (noAnimation) {
-                child.setActualHeight(viewState.height, false);
-            } else {
-                startHeightAnimation(child, viewState, duration, delay);
-            }
+            startHeightAnimation(child, viewState, duration, delay);
         }
 
         // start top inset animation
         if (topInsetChanging) {
-            if (noAnimation) {
-                child.setClipTopAmount(viewState.clipTopAmount);
-            } else {
-                startInsetAnimation(child, viewState, duration, delay);
-            }
+            startInsetAnimation(child, viewState, duration, delay);
         }
 
         // start dimmed animation
-        child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed && !wasAdded
-                && !noAnimation);
+        child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
 
         // start dark animation
-        child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation, delay);
+        child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
 
         // apply speed bump state
         child.setBelowSpeedBump(viewState.belowSpeedBump);
 
         // start hiding sensitive animation
-        child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive &&
-                !wasAdded && !noAnimation, delay, duration);
+        child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive,
+                delay, duration);
 
         if (wasAdded) {
             child.performAddAnimation(delay, mCurrentLength);
@@ -259,10 +222,55 @@
         if (child instanceof SpeedBumpView) {
             finalState.performSpeedBumpAnimation(i, (SpeedBumpView) child, viewState,
                     delay + duration);
+        } else if (child instanceof ExpandableNotificationRow) {
+            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+            row.startChildAnimation(finalState, this, child == mChildExpandingView, delay,
+                    duration);
         }
     }
 
-    private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
+    /**
+     * Start an animation to a new {@link ViewState}.
+     *
+     * @param child the child to start the animation on
+     * @param viewState the  {@link StackViewState} of the view to animate to
+     * @param delay a fixed delay
+     * @param duration the duration of the animation
+     */
+    public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
+        boolean wasVisible = child.getVisibility() == View.VISIBLE;
+        final float alpha = viewState.alpha;
+        if (!wasVisible && alpha != 0 && !viewState.gone) {
+            child.setVisibility(View.VISIBLE);
+        }
+        boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
+        boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
+        boolean scaleChanging = child.getScaleX() != viewState.scale;
+        float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha();
+        boolean alphaChanging = viewState.alpha != childAlpha;
+
+        // start translationY animation
+        if (yTranslationChanging) {
+            startYTranslationAnimation(child, viewState, duration, delay);
+        }
+
+        // start translationZ animation
+        if (zTranslationChanging) {
+            startZTranslationAnimation(child, viewState, duration, delay);
+        }
+
+        // start scale animation
+        if (scaleChanging) {
+            startScaleAnimation(child, viewState, duration);
+        }
+
+        // start alpha animation
+        if (alphaChanging && child.getTranslationX() == 0) {
+            startAlphaAnimation(child, viewState, duration, delay);
+        }
+    }
+
+    private long calculateChildAnimationDelay(StackViewState viewState,
             StackScrollState finalState) {
         if (mAnimationFilter.hasDarkEvent) {
             return calculateDelayDark(viewState);
@@ -314,7 +322,7 @@
         return minDelay;
     }
 
-    private long calculateDelayDark(StackScrollState.ViewState viewState) {
+    private long calculateDelayDark(StackViewState viewState) {
         int referenceIndex;
         if (mAnimationFilter.darkAnimationOriginIndex ==
                 NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) {
@@ -328,14 +336,14 @@
         return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK;
     }
 
-    private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) {
+    private long calculateDelayGoToFullShade(StackViewState viewState) {
         float index = viewState.notGoneIndex;
         index = (float) Math.pow(index, 0.7f);
         return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
     }
 
     private void startHeightAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, long duration, long delay) {
+            StackViewState viewState, long duration, long delay) {
         Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
         Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
         int newEndValue = viewState.height;
@@ -394,7 +402,7 @@
     }
 
     private void startInsetAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, long duration, long delay) {
+            StackViewState viewState, long duration, long delay) {
         Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
         Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
         int newEndValue = viewState.clipTopAmount;
@@ -451,8 +459,8 @@
         child.setTag(TAG_END_TOP_INSET, newEndValue);
     }
 
-    private void startAlphaAnimation(final ExpandableView child,
-            final StackScrollState.ViewState viewState, long duration, long delay) {
+    private void startAlphaAnimation(final View child,
+            final ViewState viewState, long duration, long delay) {
         Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
         Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
         final float newEndValue = viewState.alpha;
@@ -525,8 +533,8 @@
         child.setTag(TAG_END_ALPHA, newEndValue);
     }
 
-    private void startZTranslationAnimation(final ExpandableView child,
-            final StackScrollState.ViewState viewState, long duration, long delay) {
+    private void startZTranslationAnimation(final View child,
+            final ViewState viewState, long duration, long delay) {
         Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
         Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
         float newEndValue = viewState.zTranslation;
@@ -577,8 +585,8 @@
         child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
     }
 
-    private void startYTranslationAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, long duration, long delay) {
+    private void startYTranslationAnimation(final View child,
+            ViewState viewState, long duration, long delay) {
         Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
         Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
         float newEndValue = viewState.yTranslation;
@@ -630,8 +638,8 @@
         child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
     }
 
-    private void startScaleAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, long duration) {
+    private void startScaleAnimation(final View child,
+            ViewState viewState, long duration) {
         Float previousStartValue = getChildTag(child, TAG_START_SCALE);
         Float previousEndValue = getChildTag(child, TAG_END_SCALE);
         float newEndValue = viewState.scale;
@@ -765,7 +773,7 @@
                     NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
 
                 // This item is added, initialize it's properties.
-                StackScrollState.ViewState viewState = finalState
+                StackViewState viewState = finalState
                         .getViewStateForView(changingView);
                 if (viewState == null) {
                     // The position for this child was never generated, let's continue.
@@ -776,10 +784,7 @@
                     finalState.removeViewStateForView(changingView);
                     continue;
                 }
-                changingView.setAlpha(viewState.alpha);
-                changingView.setTranslationY(viewState.yTranslation);
-                changingView.setTranslationZ(viewState.zTranslation);
-                changingView.setActualHeight(viewState.height, false);
+                finalState.applyState(changingView, viewState);
                 mNewAddChildren.add(changingView);
 
             } else if (event.animationType ==
@@ -791,7 +796,7 @@
 
                 // Find the amount to translate up. This is needed in order to understand the
                 // direction of the remove animation (either downwards or upwards)
-                StackScrollState.ViewState viewState = finalState
+                StackViewState viewState = finalState
                         .getViewStateForView(event.viewAfterChangingView);
                 int actualHeight = changingView.getActualHeight();
                 // upwards by default
@@ -813,11 +818,16 @@
                         mHostLayout.getOverlay().remove(changingView);
                     }
                 });
-            }  else if (event.animationType ==
+            } else if (event.animationType ==
                 NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
                 // A race condition can trigger the view to be added to the overlay even though
                 // it is swiped out. So let's remove it
                 mHostLayout.getOverlay().remove(changingView);
+            } else if (event.animationType == NotificationStackScrollLayout
+                    .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) event.changingView;
+                row.prepareExpansionChanged(finalState);
+                mChildExpandingView = row;
             }
             mNewEvents.add(event);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
new file mode 100644
index 0000000..55ef440
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.view.View;
+
+import com.android.systemui.statusbar.ExpandableView;
+
+/**
+* A state of an expandable view
+*/
+public class StackViewState extends ViewState {
+
+    // These are flags such that we can create masks for filtering.
+
+    public static final int LOCATION_UNKNOWN = 0x00;
+    public static final int LOCATION_FIRST_CARD = 0x01;
+    public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
+    public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
+    public static final int LOCATION_MAIN_AREA = 0x08;
+    public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
+    public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+    /** The view isn't layouted at all. */
+    public static final int LOCATION_GONE = 0x40;
+
+    public int height;
+    public boolean dimmed;
+    public boolean dark;
+    public boolean hideSensitive;
+    public boolean belowSpeedBump;
+
+    /**
+     * The amount which the view should be clipped from the top. This is calculated to
+     * perceive consistent shadows.
+     */
+    public int clipTopAmount;
+
+    /**
+     * How much does the child overlap with the previous view on the top? Can be used for
+     * a clipping optimization
+     */
+    public int topOverLap;
+
+    /**
+     * The index of the view, only accounting for views not equal to GONE
+     */
+    public int notGoneIndex;
+
+    /**
+     * The location this view is currently rendered at.
+     *
+     * <p>See <code>LOCATION_</code> flags.</p>
+     */
+    public int location;
+
+    @Override
+    public void copyFrom(ViewState viewState) {
+        super.copyFrom(viewState);
+        if (viewState instanceof StackViewState) {
+            StackViewState svs = (StackViewState) viewState;
+            height = svs.height;
+            dimmed = svs.dimmed;
+            dark = svs.dark;
+            hideSensitive = svs.hideSensitive;
+            belowSpeedBump = svs.belowSpeedBump;
+            clipTopAmount = svs.clipTopAmount;
+            topOverLap = svs.topOverLap;
+            notGoneIndex = svs.notGoneIndex;
+            location = svs.location;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
new file mode 100644
index 0000000..3e538df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.stack;
+
+import android.view.View;
+
+/**
+ * A state of a view. This can be used to apply a set of view properties to a view with
+ * {@link com.android.systemui.statusbar.stack.StackScrollState} or start animations with
+ * {@link com.android.systemui.statusbar.stack.StackStateAnimator}.
+*/
+public class ViewState {
+
+    public float alpha;
+    public float yTranslation;
+    public float zTranslation;
+    public boolean gone;
+    public float scale;
+
+    public void copyFrom(ViewState viewState) {
+        alpha = viewState.alpha;
+        yTranslation = viewState.yTranslation;
+        zTranslation = viewState.zTranslation;
+        gone = viewState.gone;
+        scale = viewState.scale;
+    }
+
+    public void initFrom(View view) {
+        alpha = view.getVisibility() == View.INVISIBLE ? 0.0f : view.getAlpha();
+        yTranslation = view.getTranslationY();
+        zTranslation = view.getTranslationZ();
+        gone = view.getVisibility() == View.GONE;
+        scale = view.getScaleX();
+    }
+}
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 08732e5..d1e1b71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -26,6 +26,7 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.NotificationData;
 
 /*
  * Status bar implementation for "large screen" products that mostly present no on-screen nav
@@ -47,7 +48,8 @@
     }
 
     @Override
-    public void addNotification(StatusBarNotification notification, RankingMap ranking) {
+    public void addNotification(StatusBarNotification notification, RankingMap ranking,
+            NotificationData.Entry entry) {
     }
 
     @Override
@@ -110,10 +112,6 @@
     }
 
     @Override
-    protected void haltTicker() {
-    }
-
-    @Override
     protected void setAreThereNotifications() {
     }
 
@@ -122,14 +120,6 @@
     }
 
     @Override
-    protected void tick(StatusBarNotification n, boolean firstTime) {
-    }
-
-    @Override
-    protected void updateExpandedViewPos(int expandedPosition) {
-    }
-
-    @Override
     protected boolean shouldDisableNavbarGestures() {
         return true;
     }
@@ -139,7 +129,7 @@
     }
 
     @Override
-    public void resetHeadsUpDecayTimer() {
+    public void scheduleHeadsUpDecay(long delay) {
     }
 
     @Override
@@ -182,4 +172,16 @@
     @Override
     public void showScreenPinningRequest() {
     }
+
+    @Override
+    public void appTransitionPending() {
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+    }
+
+    @Override
+    public void appTransitionStarting(long startTime, long duration) {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index dce5c37..f804736 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -28,6 +28,7 @@
 import android.os.UserHandle;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.provider.Settings;
 import android.util.Log;
 
@@ -198,6 +199,8 @@
              */
             Intent intent = new Intent();
             intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+            intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME,
+                    getVolumeByPath(mStorageManager.getVolumeList(), path));
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
 
             setMediaStorageNotification(
@@ -212,6 +215,8 @@
              */
             Intent intent = new Intent();
             intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+            intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME,
+                    getVolumeByPath(mStorageManager.getVolumeList(), path));
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
 
             setMediaStorageNotification(
@@ -247,6 +252,19 @@
     }
 
     /**
+     * Get the corresponding StorageVolume object for a specific path.
+     */
+    private final StorageVolume getVolumeByPath(StorageVolume[] volumes, String path) {
+        for (StorageVolume volume : volumes) {
+            if (volume.getPath().equals(path)) {
+                return volume;
+            }
+        }
+        Log.w(TAG, "No storage found");
+        return null;
+    }
+
+    /**
      * Update the state of the USB mass storage notification
      */
     void updateUsbMassStorageNotification(boolean available) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index acdcfc1..d16b818 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -37,7 +37,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
-import android.media.AudioService;
 import android.media.AudioSystem;
 import android.media.RingtoneManager;
 import android.media.ToneGenerator;
@@ -88,7 +87,7 @@
     private static final String TAG = "VolumePanel";
     private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
+    private static final int PLAY_SOUND_DELAY = AudioSystem.PLAY_SOUND_DELAY;
 
     /**
      * The delay before vibrating. This small period exists so if the user is
@@ -126,8 +125,6 @@
     private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15;
     private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 16;
 
-    // Pseudo stream type for master volume
-    private static final int STREAM_MASTER = -100;
     // Pseudo stream type for remote volume
     private static final int STREAM_REMOTE_MUSIC = -200;
 
@@ -155,10 +152,6 @@
     private int mLastRingerProgress = 0;
     private int mDemoIcon;
 
-    // True if we want to play tones on the system stream when the master stream is specified.
-    private final boolean mPlayMasterStreamTones;
-
-
     /** Volume panel content view */
     private final View mView;
     /** Dialog hosting the panel */
@@ -214,12 +207,6 @@
                 com.android.systemui.R.drawable.ic_ringer_audible,
                 com.android.systemui.R.drawable.ic_ringer_mute,
                 true),
-        // for now, use media resources for master volume
-        MasterStream(STREAM_MASTER,
-                R.string.volume_icon_description_media, //FIXME should have its own description
-                IC_AUDIO_VOL,
-                IC_AUDIO_VOL_MUTE,
-                false),
         RemoteStream(STREAM_REMOTE_MUSIC,
                 R.string.volume_icon_description_media, //FIXME should have its own description
                 com.android.systemui.R.drawable.ic_audio_remote,
@@ -250,7 +237,6 @@
         StreamResources.MediaStream,
         StreamResources.NotificationStream,
         StreamResources.AlarmStream,
-        StreamResources.MasterStream,
         StreamResources.RemoteStream
     };
 
@@ -267,6 +253,7 @@
         int iconRes;
         int iconMuteRes;
         int iconSuppressedRes;
+        int minVolume;
     }
 
     // Synchronize when accessing this
@@ -351,6 +338,17 @@
         };
     }
 
+    protected LayoutParams getDialogLayoutParams(Window window, Resources res) {
+        final LayoutParams lp = window.getAttributes();
+        lp.token = null;
+        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
+        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+        lp.setTitle(TAG);
+        return lp;
+    }
+
     public VolumePanel(Context context, ZenModeController zenController) {
         mTag = String.format("%s.%08x", TAG, hashCode());
         mContext = context;
@@ -361,15 +359,6 @@
         mSecondaryIconTransition = new SecondaryIconTransition();
         mIconPulser = new IconPulser(context);
 
-        // For now, only show master volume if master volume is supported
-        final Resources res = context.getResources();
-        final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
-        if (useMasterVolume) {
-            for (int i = 0; i < STREAMS.length; i++) {
-                StreamResources streamRes = STREAMS[i];
-                streamRes.show = (streamRes.streamType == STREAM_MASTER);
-            }
-        }
         if (LOGD) Log.d(mTag, "new VolumePanel");
 
         mDisabledAlpha = 0.5f;
@@ -409,14 +398,8 @@
 
         mDialog.create();
 
-        final LayoutParams lp = window.getAttributes();
-        lp.token = null;
-        lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
-        lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
-        lp.format = PixelFormat.TRANSLUCENT;
-        lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
-        lp.setTitle(TAG);
-        window.setAttributes(lp);
+        final Resources res = context.getResources();
+        window.setAttributes(getDialogLayoutParams(window, res));
 
         updateWidth();
 
@@ -444,16 +427,12 @@
         mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
-        if (mZenController != null && !useMasterVolume) {
+        if (mZenController != null) {
             mZenModeAvailable = mZenController.isZenAvailable();
             mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
             mZenController.addCallback(mZenCallback);
         }
 
-        final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
-        final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
-        mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
-
         registerReceiver();
     }
 
@@ -486,7 +465,6 @@
         pw.print("  mDisabledAlpha="); pw.println(mDisabledAlpha);
         pw.print("  mLastRingerMode="); pw.println(mLastRingerMode);
         pw.print("  mLastRingerProgress="); pw.println(mLastRingerProgress);
-        pw.print("  mPlayMasterStreamTones="); pw.println(mPlayMasterStreamTones);
         pw.print("  isShowing()="); pw.println(isShowing());
         pw.print("  mCallback="); pw.println(mCallback);
         pw.print("  sConfirmSafeVolumeDialog=");
@@ -573,9 +551,7 @@
     }
 
     private boolean isMuted(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.isMasterMute();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             // TODO do we need to support a distinct mute property for remote?
             return false;
         } else {
@@ -583,10 +559,16 @@
         }
     }
 
+    private int getStreamMinVolume(int streamType) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
+            return 0;
+        } else {
+            return mAudioManager.getStreamMinVolume(streamType);
+        }
+    }
+
     private int getStreamMaxVolume(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.getMasterMaxVolume();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
@@ -601,9 +583,7 @@
     }
 
     private int getStreamVolume(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            return mAudioManager.getMasterVolume();
-        } else if (streamType == STREAM_REMOTE_MUSIC) {
+        if (streamType == STREAM_REMOTE_MUSIC) {
             if (mStreamControls != null) {
                 StreamControl sc = mStreamControls.get(streamType);
                 if (sc != null && sc.controller != null) {
@@ -613,7 +593,7 @@
             }
             return -1;
         } else {
-            return mAudioManager.getStreamVolume(streamType);
+            return mAudioManager.getLastAudibleStreamVolume(streamType);
         }
     }
 
@@ -625,11 +605,7 @@
                 Log.w(mTag, "Adjusting remote volume without a controller!");
             }
         } else if (getStreamVolume(sc.streamType) != index) {
-            if (sc.streamType == STREAM_MASTER) {
-                mAudioManager.setMasterVolume(index, flags);
-            } else {
-                mAudioManager.setStreamVolume(sc.streamType, index, flags);
-            }
+            mAudioManager.setStreamVolume(sc.streamType, index, flags);
         }
     }
 
@@ -694,9 +670,8 @@
                     }
                 });
             }
-            final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
-                    streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
-            sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
+            sc.minVolume = getStreamMinVolume(streamType);
+            sc.seekbarView.setMax(getStreamMaxVolume(streamType) - sc.minVolume);
             sc.seekbarView.setOnSeekBarChangeListener(mSeekListener);
             sc.seekbarView.setTag(sc);
             mStreamControls.put(streamType, sc);
@@ -739,7 +714,7 @@
         if (progress < 0) {
             progress = getStreamVolume(sc.streamType);
         }
-        sc.seekbarView.setProgress(progress);
+        sc.seekbarView.setProgress(progress - sc.minVolume);
         if (isRinger) {
             mLastRingerProgress = progress;
         }
@@ -830,7 +805,7 @@
             sc.icon.setAlpha(mDisabledAlpha);
             sc.icon.setClickable(false);
         } else if (fixedVolume ||
-                (sc.streamType != mAudioManager.getMasterStreamType() && !isRinger && muted) ||
+                (sc.streamType != mAudioManager.getUiSoundsStreamType() && !isRinger && muted) ||
                 (sSafetyWarning != null)) {
             sc.seekbarView.setEnabled(false);
         } else {
@@ -974,10 +949,6 @@
         obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget();
     }
 
-    public void postMasterVolumeChanged(int flags) {
-        postVolumeChanged(STREAM_MASTER, flags);
-    }
-
     public void postMuteChanged(int streamType, int flags) {
         if (hasMessages(MSG_VOLUME_CHANGED)) return;
         synchronized (this) {
@@ -989,10 +960,6 @@
         obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
     }
 
-    public void postMasterMuteChanged(int flags) {
-        postMuteChanged(STREAM_MASTER, flags);
-    }
-
     public void postDisplaySafeVolumeWarning(int flags) {
         if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
         obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget();
@@ -1012,7 +979,7 @@
     }
 
     private static String streamToString(int stream) {
-        return AudioService.streamToString(stream);
+        return AudioSystem.streamToString(stream);
     }
 
     /**
@@ -1075,7 +1042,7 @@
 
         // get max volume for progress bar
 
-        int max = getStreamMaxVolume(streamType);
+        int max = getStreamMaxVolume(streamType) - getStreamMinVolume(streamType);
         StreamControl sc = mStreamControls.get(streamType);
 
         switch (streamType) {
@@ -1102,17 +1069,6 @@
                 break;
             }
 
-            case AudioManager.STREAM_VOICE_CALL: {
-                /*
-                 * For in-call voice call volume, there is no inaudible volume.
-                 * Rescale the UI control so the progress bar doesn't go all
-                 * the way to zero and don't show the mute icon.
-                 */
-                index++;
-                max++;
-                break;
-            }
-
             case AudioManager.STREAM_ALARM: {
                 break;
             }
@@ -1126,17 +1082,6 @@
                 break;
             }
 
-            case AudioManager.STREAM_BLUETOOTH_SCO: {
-                /*
-                 * For in-call voice call volume, there is no inaudible volume.
-                 * Rescale the UI control so the progress bar doesn't go all
-                 * the way to zero and don't show the mute icon.
-                 */
-                index++;
-                max++;
-                break;
-            }
-
             case STREAM_REMOTE_MUSIC: {
                 if (controller == null && sc != null) {
                     // If we weren't passed one try using the last one set.
@@ -1189,9 +1134,7 @@
         if (!isShowing()) {
             int stream = (streamType == STREAM_REMOTE_MUSIC) ? -1 : streamType;
             // when the stream is for remote playback, use -1 to reset the stream type evaluation
-            if (stream != STREAM_MASTER) {
-                mAudioManager.forceVolumeControlStream(stream);
-            }
+            mAudioManager.forceVolumeControlStream(stream);
             mDialog.show();
             if (mCallback != null) {
                 mCallback.onVisible(true);
@@ -1357,16 +1300,6 @@
      * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
      */
     private ToneGenerator getOrCreateToneGenerator(int streamType) {
-        if (streamType == STREAM_MASTER) {
-            // For devices that use the master volume setting only but still want to
-            // play a volume-changed tone, direct the master volume pseudostream to
-            // the system stream's tone generator.
-            if (mPlayMasterStreamTones) {
-                streamType = AudioManager.STREAM_SYSTEM;
-            } else {
-                return null;
-            }
-        }
         synchronized (this) {
             if (mToneGenerators[streamType] == null) {
                 try {
@@ -1546,7 +1479,7 @@
             final Object tag = seekBar.getTag();
             if (fromUser && tag instanceof StreamControl) {
                 StreamControl sc = (StreamControl) tag;
-                setStreamVolume(sc, progress,
+                setStreamVolume(sc, progress + sc.minVolume,
                         AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
             }
             resetTimeout();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 7102c2a..687452d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -1,31 +1,3 @@
-package com.android.systemui.volume;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.IRemoteVolumeController;
-import android.media.IVolumeController;
-import android.media.session.ISessionController;
-import android.media.session.MediaController;
-import android.media.session.MediaSessionManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
 /*
  * Copyright (C) 2014 The Android Open Source Project
  *
@@ -42,19 +14,62 @@
  * limitations under the License.
  */
 
+package com.android.systemui.volume;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.media.IRemoteVolumeController;
+import android.media.IVolumeController;
+import android.media.VolumePolicy;
+import android.media.session.ISessionController;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.ServiceMonitor;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class VolumeUI extends SystemUI {
     private static final String TAG = "VolumeUI";
-    private static final String SETTING = "systemui_volume_controller";  // for testing
-    private static final Uri SETTING_URI = Settings.Global.getUriFor(SETTING);
-    private static final int DEFAULT = 1;  // enabled by default
+    private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Handler mHandler = new Handler();
+    private final Receiver mReceiver = new Receiver();
+    private final RestorationNotification mRestorationNotification = new RestorationNotification();
 
     private boolean mEnabled;
     private AudioManager mAudioManager;
+    private NotificationManager mNotificationManager;
     private MediaSessionManager mMediaSessionManager;
     private VolumeController mVolumeController;
     private RemoteVolumeController mRemoteVolumeController;
+    private ServiceMonitor mVolumeControllerService;
 
     private VolumePanel mPanel;
     private int mDismissDelay;
@@ -64,14 +79,19 @@
         mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
         if (!mEnabled) return;
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mNotificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mMediaSessionManager = (MediaSessionManager) mContext
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         initPanel();
         mVolumeController = new VolumeController();
         mRemoteVolumeController = new RemoteVolumeController();
         putComponent(VolumeComponent.class, mVolumeController);
-        updateController();
-        mContext.getContentResolver().registerContentObserver(SETTING_URI, false, mObserver);
+        mReceiver.start();
+        mVolumeControllerService = new ServiceMonitor(TAG, LOGD,
+                mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
+                new ServiceMonitorCallbacks());
+        mVolumeControllerService.start();
     }
 
     @Override
@@ -85,18 +105,21 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mEnabled="); pw.println(mEnabled);
+        pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent());
         if (mPanel != null) {
             mPanel.dump(fd, pw, args);
         }
     }
 
-    private void updateController() {
-        if (Settings.Global.getInt(mContext.getContentResolver(), SETTING, DEFAULT) != 0) {
-            Log.d(TAG, "Registering volume controller");
+    private void setVolumeController(boolean register) {
+        if (register) {
+            if (LOGD) Log.d(TAG, "Registering default volume controller");
             mAudioManager.setVolumeController(mVolumeController);
+            mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
             mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+            DndTile.setVisible(mContext, false);
         } else {
-            Log.d(TAG, "Unregistering volume controller");
+            if (LOGD) Log.d(TAG, "Unregistering default volume controller");
             mAudioManager.setVolumeController(null);
             mMediaSessionManager.setRemoteVolumeController(null);
         }
@@ -129,13 +152,32 @@
         });
     }
 
-    private final ContentObserver mObserver = new ContentObserver(mHandler) {
-        public void onChange(boolean selfChange, Uri uri) {
-            if (SETTING_URI.equals(uri)) {
-                updateController();
+    private String getAppLabel(ComponentName component) {
+        final String pkg = component.getPackageName();
+        try {
+            final ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(pkg, 0);
+            final String rt = mContext.getPackageManager().getApplicationLabel(ai).toString();
+            if (!TextUtils.isEmpty(rt)) {
+                return rt;
             }
+        } catch (Exception e) {
+            Log.w(TAG, "Error loading app label", e);
         }
-    };
+        return pkg;
+    }
+
+    private void showServiceActivationDialog(final ComponentName component) {
+        final SystemUIDialog d = new SystemUIDialog(mContext);
+        d.setMessage(mContext.getString(R.string.volumeui_prompt_message, getAppLabel(component)));
+        d.setPositiveButton(R.string.volumeui_prompt_allow, new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mVolumeControllerService.setComponent(component);
+            }
+        });
+        d.setNegativeButton(R.string.volumeui_prompt_deny, null);
+        d.show();
+    }
 
     private final Runnable mStartZenSettings = new Runnable() {
         @Override
@@ -161,13 +203,8 @@
         }
 
         @Override
-        public void masterVolumeChanged(int flags) throws RemoteException {
-            mPanel.postMasterVolumeChanged(flags);
-        }
-
-        @Override
         public void masterMuteChanged(int flags) throws RemoteException {
-            mPanel.postMasterMuteChanged(flags);
+            // no-op
         }
 
         @Override
@@ -213,4 +250,89 @@
             // than by remoteVolumeChanged.
         }
     }
+
+    private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks {
+        @Override
+        public void onNoService() {
+            if (LOGD) Log.d(TAG, "onNoService");
+            setVolumeController(true);
+            mRestorationNotification.hide();
+            if (!mVolumeControllerService.isPackageAvailable()) {
+                mVolumeControllerService.setComponent(null);
+            }
+        }
+
+        @Override
+        public long onServiceStartAttempt() {
+            if (LOGD) Log.d(TAG, "onServiceStartAttempt");
+            // poke the setting to update the uid
+            mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
+            setVolumeController(false);
+            mVolumeController.dismissNow();
+            mRestorationNotification.show();
+            return 0;
+        }
+    }
+
+    private final class Receiver extends BroadcastReceiver {
+        private static final String ENABLE = "com.android.systemui.vui.ENABLE";
+        private static final String DISABLE = "com.android.systemui.vui.DISABLE";
+        private static final String EXTRA_COMPONENT = "component";
+
+        public void start() {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(ENABLE);
+            filter.addAction(DISABLE);
+            mContext.registerReceiver(this, filter, null, mHandler);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
+            final boolean current = component.equals(mVolumeControllerService.getComponent());
+            if (ENABLE.equals(action) && component != null) {
+                if (!current) {
+                    showServiceActivationDialog(component);
+                }
+            }
+            if (DISABLE.equals(action) && component != null) {
+                if (current) {
+                    mVolumeControllerService.setComponent(null);
+                }
+            }
+        }
+    }
+
+    private final class RestorationNotification {
+        public void hide() {
+            mNotificationManager.cancel(R.id.notification_volumeui);
+        }
+
+        public void show() {
+            final ComponentName component = mVolumeControllerService.getComponent();
+            if (component == null) {
+                Log.w(TAG, "Not showing restoration notification, component not active");
+                return;
+            }
+            final Intent intent =  new Intent(Receiver.DISABLE)
+                    .putExtra(Receiver.EXTRA_COMPONENT, component);
+            mNotificationManager.notify(R.id.notification_volumeui,
+                    new Notification.Builder(mContext)
+                            .setSmallIcon(R.drawable.ic_ringer_audible)
+                            .setWhen(0)
+                            .setShowWhen(false)
+                            .setOngoing(true)
+                            .setContentTitle(mContext.getString(
+                                    R.string.volumeui_notification_title, getAppLabel(component)))
+                            .setContentText(mContext.getString(R.string.volumeui_notification_text))
+                            .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
+                                    PendingIntent.FLAG_UPDATE_CURRENT))
+                            .setPriority(Notification.PRIORITY_MIN)
+                            .setVisibility(Notification.VISIBILITY_PUBLIC)
+                            .setColor(mContext.getResources().getColor(
+                                    com.android.internal.R.color.system_notification_accent_color))
+                            .build());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index d40a2c0..6cecc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -19,7 +19,6 @@
 import android.animation.LayoutTransition;
 import android.animation.LayoutTransition.TransitionListener;
 import android.app.ActivityManager;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -85,24 +84,26 @@
     private final int mSubheadWarningColor;
     private final int mSubheadColor;
     private final Interpolator mInterpolator;
-    private final int mMaxConditions;
-    private final int mMaxOptionalConditions;
-    private final boolean mCountdownConditionSupported;
-    private final int mFirstConditionIndex;
     private final TransitionHelper mTransitionHelper = new TransitionHelper();
     private final Uri mForeverId;
 
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
     private SegmentedButtons mZenButtons;
+    private ViewGroup mZenButtonsContainer;
     private View mZenSubhead;
     private TextView mZenSubheadCollapsed;
     private TextView mZenSubheadExpanded;
+    private View mZenEmbeddedDivider;
     private View mMoreSettings;
     private LinearLayout mZenConditions;
 
     private Callback mCallback;
     private ZenModeController mController;
+    private boolean mCountdownConditionSupported;
+    private int mMaxConditions;
+    private int mMaxOptionalConditions;
+    private int mFirstConditionIndex;
     private boolean mRequestingConditions;
     private Condition mExitCondition;
     private String mExitConditionText;
@@ -115,6 +116,7 @@
     private Condition mSessionExitCondition;
     private Condition[] mConditions;
     private Condition mTimeCondition;
+    private boolean mEmbedded;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -127,14 +129,6 @@
         mSubheadColor = res.getColor(R.color.qs_subhead);
         mInterpolator = AnimationUtils.loadInterpolator(mContext,
                 com.android.internal.R.interpolator.fast_out_slow_in);
-        mCountdownConditionSupported = NotificationManager.from(mContext)
-                .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
-        final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
-        mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
-        final int minConditions = 1 /*forever*/ + countdownDelta;
-        mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions),
-                minConditions, 100);
-        mMaxOptionalConditions = mMaxConditions - minConditions;
         mForeverId = Condition.newId(mContext).appendPath("forever").build();
         if (DEBUG) Log.d(mTag, "new ZenModePanel");
     }
@@ -149,9 +143,25 @@
         pw.print("  mExpanded="); pw.println(mExpanded);
         pw.print("  mSessionZen="); pw.println(mSessionZen);
         pw.print("  mAttachedZen="); pw.println(mAttachedZen);
+        pw.print("  mEmbedded="); pw.println(mEmbedded);
         mTransitionHelper.dump(fd, pw, args);
     }
 
+    public void setEmbedded(boolean embedded) {
+        if (mEmbedded == embedded) return;
+        mEmbedded = embedded;
+        mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+        if (mEmbedded) {
+            mZenButtonsContainer.setBackground(null);
+        } else {
+            mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
+        }
+        mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+        mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
+        setExpanded(mEmbedded);
+        updateWidgets();
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -165,10 +175,11 @@
                 Global.ZEN_MODE_OFF);
         mZenButtons.setCallback(mZenButtonsCallback);
 
-        final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
-        zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+        mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+        mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
 
         mZenSubhead = findViewById(R.id.zen_subhead);
+        mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
 
         mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
         mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
@@ -192,9 +203,6 @@
         Interaction.register(mMoreSettings, mInteractionCallback);
 
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
-        for (int i = 0; i < mMaxConditions; i++) {
-            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
-        }
 
         setLayoutTransition(newLayoutTransition(mTransitionHelper));
     }
@@ -234,7 +242,9 @@
         mAttachedZen = -1;
         mSessionZen = -1;
         setSessionExitCondition(null);
-        setExpanded(false);
+        if (!mEmbedded) {
+            setExpanded(false);
+        }
         setRequestingConditions(false);
         mTransitionHelper.clear();
     }
@@ -306,6 +316,16 @@
 
     public void init(ZenModeController controller) {
         mController = controller;
+        mCountdownConditionSupported = mController.isCountdownConditionSupported();
+        final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
+        mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
+        final int minConditions = 1 /*forever*/ + countdownDelta;
+        mMaxConditions = MathUtils.constrain(mContext.getResources()
+                .getInteger(R.integer.zen_mode_max_conditions), minConditions, 100);
+        mMaxOptionalConditions = mMaxConditions - minConditions;
+        for (int i = 0; i < mMaxConditions; i++) {
+            mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+        }
         setExitCondition(mController.getExitCondition());
         refreshExitConditionText();
         mSessionZen = getSelectedZen(-1);
@@ -363,7 +383,7 @@
 
     private void handleUpdateZen(int zen) {
         if (mSessionZen != -1 && mSessionZen != zen) {
-            setExpanded(zen != Global.ZEN_MODE_OFF);
+            setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
             mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
@@ -405,7 +425,7 @@
         final boolean expanded = !mHidden && mExpanded;
 
         mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
-        mZenSubhead.setVisibility(!mHidden && !zenOff ? VISIBLE : GONE);
+        mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
         mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 5a90324..6a7201c 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -36,4 +36,6 @@
 # UI it doesn't own. This is necessary to allow screenshots to be taken
 LOCAL_CERTIFICATE := platform
 
+include frameworks/base/packages/SettingsLib/common.mk
+
 include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
new file mode 100644
index 0000000..3fdb3d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Base class that does System UI specific setup.
+ */
+public class SysuiTestCase extends AndroidTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Mockito stuff.
+        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
new file mode 100644
index 0000000..e8a80d9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.policy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.*;
+import android.service.notification.StatusBarNotification;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test the Heads Up Notification.
+ *
+ * Specifically the policy that a notificaiton must remain visibile for a minimum period of time.
+ */
+public class HeadsUpNotificationTest extends SysuiTestCase {
+    private static final String TAG = "HeadsUpNotificationTest";
+
+    private static int TOUCH_SENSITIVITY = 100;
+    private static int NOTIFICATION_DECAY = 10000;
+    private static int MINIMUM_DISPLAY_TIME = 3000;
+    private static int SNOOZE_TIME = 60000;
+    private static long TOO_SOON = 1000L;  // less than MINIMUM_DISPLAY_TIME
+    private static long LATER = 5000L;  // more than MINIMUM_DISPLAY_TIME
+    private static long REMAINING_VISIBILITY = MINIMUM_DISPLAY_TIME - TOO_SOON;
+
+    protected HeadsUpNotificationView mHeadsUp;
+
+    @Mock protected PhoneStatusBar mMockStatusBar;
+    @Mock private HeadsUpNotificationView.Clock mClock;
+    @Mock private SwipeHelper mMockSwipeHelper;
+    @Mock private HeadsUpNotificationView.EdgeSwipeHelper mMockEdgeSwipeHelper;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        MockitoAnnotations.initMocks(this);
+
+        mHeadsUp = new HeadsUpNotificationView(mContext,
+                mClock, mMockSwipeHelper, mMockEdgeSwipeHelper,
+                NOTIFICATION_DECAY, MINIMUM_DISPLAY_TIME, TOUCH_SENSITIVITY, SNOOZE_TIME);
+        mHeadsUp.setBar(mMockStatusBar);
+    }
+
+    private NotificationData.Entry makeNotification(String key) {
+        StatusBarNotification sbn = mock(StatusBarNotification.class);
+        when(sbn.getKey()).thenReturn(key);
+        return new NotificationData.Entry(sbn, null);
+    }
+
+    public void testPostAndDecay() {
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpOpen();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+        // New notification gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndDeleteTooSoon() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.removeNotification(a.key);
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+        // Leave the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndDeleteLater() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        mHeadsUp.removeNotification(a.key);
+        // Delete closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    // This is a bad test.  It should not care that there is a call to scheduleHeadsUpClose(),
+    // but it happens that there will be one, so it is important that it happen before the
+    // call to scheduleHeadsUpOpen(), so that the final state is open.
+    // Maybe mMockStatusBar should instead be a fake that tracks the open/closed state.
+    public void testPostAndReplaceTooSoon() {
+        InOrder callOrder = inOrder(mMockStatusBar);
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry b = makeNotification("b");
+        mHeadsUp.showNotification(b);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // New notification gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+
+        // Make sure close was called before open, so that the heads up stays open.
+        callOrder.verify(mMockStatusBar).scheduleHeadsUpClose();
+        callOrder.verify(mMockStatusBar).scheduleHeadsUpOpen();
+    }
+
+    public void testPostAndUpdateAlertAgain() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.updateNotification(a, true);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Alert again gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateAlertAgainFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, true);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Alert again gets a full decay time.
+        assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateNoAlertAgain() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.updateNotification(a, false);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateNoAlertAgainFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateLowPriorityTooSoon() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        mHeadsUp.release();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Down grade on update leaves the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateLowPriorityTooSoonFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        mHeadsUp.release();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+        ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+        // Down grade on update leaves the window up for the balance of the minumum time.
+        assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+    }
+
+    public void testPostAndUpdateLowPriorityLater() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        mHeadsUp.release();
+        // Down grade on update closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+
+    public void testPostAndUpdateLowPriorityLaterFastFail() {
+        when(mClock.currentTimeMillis()).thenReturn(0L);
+        NotificationData.Entry a = makeNotification("a");
+        mHeadsUp.showNotification(a);
+        reset(mMockStatusBar);
+
+        when(mClock.currentTimeMillis()).thenReturn(LATER);
+        NotificationData.Entry a_prime = makeNotification("a");
+        mHeadsUp.updateNotification(a_prime, false);
+        mHeadsUp.release();
+        // Down grade on update closes immediately if the minimum time window is satisfied.
+        Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+        Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index d85b059..5d88407 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -1,17 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.systemui.statusbar.policy;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
-
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
@@ -22,15 +29,24 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.cdma.EriInfo;
+import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
 
-public class NetworkControllerBaseTest extends AndroidTestCase {
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NetworkControllerBaseTest extends SysuiTestCase {
     private static final String TAG = "NetworkControllerBaseTest";
     protected static final int DEFAULT_LEVEL = 2;
     protected static final int DEFAULT_SIGNAL_STRENGTH =
@@ -41,6 +57,7 @@
     protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_ICON_3G;
 
     protected NetworkControllerImpl mNetworkController;
+    protected MobileSignalController mMobileSignalController;
     protected PhoneStateListener mPhoneStateListener;
     protected SignalCluster mSignalCluster;
     protected NetworkSignalChangedCallback mNetworkSignalChangedCallback;
@@ -52,14 +69,13 @@
     protected TelephonyManager mMockTm;
     protected Config mConfig;
 
+    protected int mSubId;
+
     private NetworkCapabilities mNetCapabilities;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        // Mockito stuff.
-        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
-        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
         mMockWm = mock(WifiManager.class);
         mMockTm = mock(TelephonyManager.class);
@@ -83,20 +99,33 @@
 
     protected void setupNetworkController() {
         // For now just pretend to be the data sim, so we can test that too.
-        final int subId = SubscriptionManager.getDefaultDataSubId();
+        mSubId = SubscriptionManager.getDefaultDataSubId();
         SubscriptionInfo subscription = mock(SubscriptionInfo.class);
         List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>();
-        when(subscription.getSubscriptionId()).thenReturn(subId);
+        when(subscription.getSubscriptionId()).thenReturn(mSubId);
         subs.add(subscription);
         mNetworkController.setCurrentSubscriptions(subs);
-        mPhoneStateListener =
-                mNetworkController.mMobileSignalControllers.get(subId).mPhoneStateListener;
+        mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
+        mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
         mSignalCluster = mock(SignalCluster.class);
         mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
         mNetworkController.addSignalCluster(mSignalCluster);
         mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback);
     }
 
+    protected NetworkControllerImpl setUpNoMobileData() {
+      when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
+      NetworkControllerImpl networkControllerNoMobile
+              = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
+                        mConfig, mock(AccessPointControllerImpl.class),
+                        mock(MobileDataControllerImpl.class));
+
+      setupNetworkController();
+
+      return networkControllerNoMobile;
+
+    }
+
     @Override
     protected void tearDown() throws Exception {
         StringWriter sw = new StringWriter();
@@ -260,4 +289,8 @@
         assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
         assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue());
     }
+
+   protected void assertNetworkNameEquals(String expected) {
+       assertEquals("Network name", expected, mNetworkController.getMobileNetworkName());
+   }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 525dd20..aefb1bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -1,12 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.android.systemui.statusbar.policy;
 
 import static org.mockito.Mockito.mock;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.mockito.Mockito;
-
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.telephony.ServiceState;
@@ -14,9 +24,15 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.MobileSignalController;
+
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
 
@@ -232,10 +248,152 @@
         }
     }
 
+    public void testHistorySize() {
+        // Verify valid history size, otherwise it gits printed out the wrong order and whatnot.
+        assertEquals(0, SignalController.HISTORY_SIZE & (SignalController.HISTORY_SIZE - 1));
+    }
+
     private void setCdma() {
         setIsGsm(false);
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_CDMA);
         setCdmaRoaming(false);
     }
+
+    public void testOnReceive_stringsUpdatedAction_spn() {
+        String expectedMNetworkName = "Test";
+        Intent intent = createStringsUpdatedIntent(true /* showSpn */,
+                expectedMNetworkName /* spn */,
+                false /* showPlmn */,
+                "NotTest" /* plmn */);
+
+        mNetworkController.onReceive(mContext, intent);
+
+        assertNetworkNameEquals(expectedMNetworkName);
+    }
+
+    public void testOnReceive_stringsUpdatedAction_plmn() {
+        String expectedMNetworkName = "Test";
+
+        Intent intent = createStringsUpdatedIntent(false /* showSpn */,
+                "NotTest" /* spn */,
+                true /* showPlmn */,
+                expectedMNetworkName /* plmn */);
+
+        mNetworkController.onReceive(mContext, intent);
+
+        assertNetworkNameEquals(expectedMNetworkName);
+    }
+
+    public void testOnReceive_stringsUpdatedAction_bothFalse() {
+        Intent intent = createStringsUpdatedIntent(false /* showSpn */,
+              "Irrelevant" /* spn */,
+              false /* showPlmn */,
+              "Irrelevant" /* plmn */);
+
+        mNetworkController.onReceive(mContext, intent);
+
+        String defaultNetworkName = mMobileSignalController
+            .getStringIfExists(
+                com.android.internal.R.string.lockscreen_carrier_default);
+        assertNetworkNameEquals(defaultNetworkName);
+    }
+
+    public void testOnReceive_stringsUpdatedAction_bothTrueAndNull() {
+        Intent intent = createStringsUpdatedIntent(true /* showSpn */,
+            null /* spn */,
+            true /* showPlmn */,
+            null /* plmn */);
+
+        mNetworkController.onReceive(mContext, intent);
+
+        String defaultNetworkName = mMobileSignalController.getStringIfExists(
+                com.android.internal.R.string.lockscreen_carrier_default);
+        assertNetworkNameEquals(defaultNetworkName);
+    }
+
+    public void testOnReceive_stringsUpdatedAction_bothTrueAndNonNull() {
+        String spn = "Test1";
+        String plmn = "Test2";
+
+        Intent intent = createStringsUpdatedIntent(true /* showSpn */,
+            spn /* spn */,
+            true /* showPlmn */,
+            plmn /* plmn */);
+
+        mNetworkController.onReceive(mContext, intent);
+
+        assertNetworkNameEquals(plmn
+                + mMobileSignalController.getStringIfExists(
+                        R.string.status_bar_network_name_separator)
+                + spn);
+    }
+
+    private Intent createStringsUpdatedIntent(boolean showSpn, String spn,
+            boolean showPlmn, String plmn) {
+
+        Intent intent = new Intent();
+        intent.setAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+
+        intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
+        intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
+
+        intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
+        intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
+        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mSubId);
+
+        return intent;
+    }
+
+    public void testOnUpdateDataActivity_dataIn() {
+        setupDefaultSignal();
+
+        updateDataActivity(TelephonyManager.DATA_ACTIVITY_IN);
+
+        verifyLastQsMobileDataIndicators(true /* visible */,
+                TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+                DEFAULT_QS_ICON /* typeIcon */,
+                true /* dataIn */,
+                false /* dataOut */);
+
+    }
+
+    public void testOnUpdateDataActivity_dataOut() {
+      setupDefaultSignal();
+
+      updateDataActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+
+      verifyLastQsMobileDataIndicators(true /* visible */,
+              TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+              DEFAULT_QS_ICON /* typeIcon */,
+              false /* dataIn */,
+              true /* dataOut */);
+
+    }
+
+    public void testOnUpdateDataActivity_dataInOut() {
+      setupDefaultSignal();
+
+      updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+
+      verifyLastQsMobileDataIndicators(true /* visible */,
+              TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+              DEFAULT_QS_ICON /* typeIcon */,
+              true /* dataIn */,
+              true /* dataOut */);
+
+    }
+
+    public void testOnUpdateDataActivity_dataActivityNone() {
+      setupDefaultSignal();
+
+      updateDataActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+
+      verifyLastQsMobileDataIndicators(true /* visible */,
+              TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL] /* icon */,
+              DEFAULT_QS_ICON /* typeIcon */,
+              false /* dataIn */,
+              false /* dataOut */);
+
+    }
 }
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 897c96cf..ea8b2ec 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -18,13 +18,8 @@
 
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.net.IConnectivityManager;
-import android.net.VpnService;
 import android.os.ServiceManager;
 import android.text.Html;
 import android.text.Html.ImageGetter;
@@ -36,8 +31,6 @@
 import com.android.internal.app.AlertActivity;
 import com.android.internal.net.VpnConfig;
 
-import java.util.List;
-
 public class ConfirmDialog extends AlertActivity
         implements DialogInterface.OnClickListener, ImageGetter {
     private static final String TAG = "VpnConfirm";
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
index a671ed2..4e276db 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/common/BitmapUtils.java
@@ -23,7 +23,6 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.os.Build;
-import android.util.FloatMath;
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
@@ -72,7 +71,7 @@
                 && minSideLength == UNCONSTRAINED) return 1;
 
         int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
-                (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
+                (int) Math.ceil(Math.sqrt((double) (w * h) / maxNumOfPixels));
 
         if (minSideLength == UNCONSTRAINED) {
             return lowerBound;
@@ -96,7 +95,7 @@
 
     // Find the min x that 1 / x >= scale
     public static int computeSampleSizeLarger(float scale) {
-        int initialSize = (int) FloatMath.floor(1f / scale);
+        int initialSize = (int) Math.floor(1 / scale);
         if (initialSize <= 1) return 1;
 
         return initialSize <= 8
@@ -107,7 +106,7 @@
     // Find the max x that 1 / x <= scale.
     public static int computeSampleSize(float scale) {
         Utils.assertTrue(scale > 0);
-        int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
+        int initialSize = Math.max(1, (int) Math.ceil(1 / scale));
         return initialSize <= 8
                 ? Utils.nextPowerOf2(initialSize)
                 : (initialSize + 7) / 8 * 8;
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
index c3ef302..4405207 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/CropView.java
@@ -21,7 +21,6 @@
 import android.graphics.Point;
 import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -300,12 +299,12 @@
                     adjustment[0] = (edges.right - getWidth()) / scale;
                 }
                 if (edges.top > 0) {
-                    adjustment[1] = FloatMath.ceil(edges.top / scale);
+                    adjustment[1] = (float) Math.ceil(edges.top / scale);
                 } else if (edges.bottom < getHeight()) {
                     adjustment[1] = (edges.bottom - getHeight()) / scale;
                 }
                 for (int dim = 0; dim <= 1; dim++) {
-                    if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]);
+                    if (coef[dim] > 0) adjustment[dim] = (float) Math.ceil(adjustment[dim]);
                 }
 
                 mInverseRotateMatrix.mapPoints(adjustment);
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 57b0731..a319beb 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -21,7 +21,6 @@
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
diff --git a/packages/services/PacProcessor/jni/Android.mk b/packages/services/PacProcessor/jni/Android.mk
index f16c90b..254cbc2 100644
--- a/packages/services/PacProcessor/jni/Android.mk
+++ b/packages/services/PacProcessor/jni/Android.mk
@@ -36,6 +36,6 @@
 LOCAL_MODULE := libjni_pacprocessor
 LOCAL_MODULE_TAGS := optional
 
-include external/stlport/libstlport.mk
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index c5aa13b..2727338 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -48,7 +48,8 @@
 
 String16 jstringToString16(JNIEnv* env, jstring jstr) {
     const jchar* str = env->GetStringCritical(jstr, 0);
-    String16 str16(str, env->GetStringLength(jstr));
+    String16 str16(reinterpret_cast<const char16_t*>(str),
+                   env->GetStringLength(jstr));
     env->ReleaseStringCritical(jstr, str);
     return str16;
 }
@@ -57,10 +58,10 @@
     const char16_t* str = string.string();
     size_t len = string.size();
 
-    return env->NewString(str, len);
+    return env->NewString(reinterpret_cast<const jchar*>(str), len);
 }
 
-static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* env, 
+static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver == NULL) {
         logger = new ProxyErrorLogger();
@@ -72,7 +73,7 @@
     return JNI_TRUE;
 }
 
-static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* env, 
+static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver != NULL) {
         delete logger;
diff --git a/packages/services/PacProcessor/jni/jni_init.cpp b/packages/services/PacProcessor/jni/jni_init.cpp
index bda33fb..de844c8 100644
--- a/packages/services/PacProcessor/jni/jni_init.cpp
+++ b/packages/services/PacProcessor/jni/jni_init.cpp
@@ -25,7 +25,7 @@
 
 using namespace android;
 
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
     JNIEnv *env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
         ALOGE("ERROR: GetEnv failed");
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index c6b76f1..74391eb 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -72,16 +72,22 @@
         @Override
         public String resolvePacFile(String host, String url) throws RemoteException {
             try {
+                if (host == null) {
+                    throw new IllegalArgumentException("The host must not be null");
+                }
+                if (url == null) {
+                    throw new IllegalArgumentException("The URL must not be null");
+                }
                 // Check for characters that could be used for an injection attack.
                 new URL(url);
                 for (char c : host.toCharArray()) {
                     if (!Character.isLetterOrDigit(c) && (c != '.') && (c != '-')) {
-                        throw new RemoteException("Invalid host was passed");
+                        throw new IllegalArgumentException("Invalid host was passed");
                     }
                 }
                 return mPacNative.makeProxyRequest(url, host);
             } catch (MalformedURLException e) {
-                throw new RemoteException("Invalid URL was passed");
+                throw new IllegalArgumentException("Invalid URL was passed");
             }
         }
 
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index edb1630..ac40222 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -20,6 +20,7 @@
 
 import com.android.net.IProxyPortListener;
 import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -33,6 +34,7 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -46,6 +48,10 @@
 
     private static final String TAG = "ProxyServer";
 
+    // HTTP Headers
+    private static final String HEADER_CONNECTION = "connection";
+    private static final String HEADER_PROXY_CONNECTION = "proxy-connection";
+
     private ExecutorService threadExecutor;
 
     public boolean mIsRunning = false;
@@ -65,10 +71,6 @@
         public void run() {
             try {
                 String requestLine = getLine(connection.getInputStream());
-                if (requestLine == null) {
-                    connection.close();
-                    return;
-                }
                 String[] splitLine = requestLine.split(" ");
                 if (splitLine.length < 3) {
                     connection.close();
@@ -76,22 +78,30 @@
                 }
                 String requestType = splitLine[0];
                 String urlString = splitLine[1];
+                String httpVersion = splitLine[2];
 
-                String host = "";
-                int port = 80;
+                URI url = null;
+                String host;
+                int port;
 
                 if (requestType.equals(CONNECT)) {
                     String[] hostPortSplit = urlString.split(":");
                     host = hostPortSplit[0];
-                    try {
-                        port = Integer.parseInt(hostPortSplit[1]);
-                    } catch (NumberFormatException nfe) {
+                    // Use default SSL port if not specified. Parse it otherwise
+                    if (hostPortSplit.length < 2) {
                         port = 443;
+                    } else {
+                        try {
+                            port = Integer.parseInt(hostPortSplit[1]);
+                        } catch (NumberFormatException nfe) {
+                            connection.close();
+                            return;
+                        }
                     }
                     urlString = "Https://" + host + ":" + port;
                 } else {
                     try {
-                        URI url = new URI(urlString);
+                        url = new URI(urlString);
                         host = url.getHost();
                         port = url.getPort();
                         if (port < 0) {
@@ -122,44 +132,99 @@
                         } else {
                             server = new Socket(host, port);
                             if (requestType.equals(CONNECT)) {
-                                while (getLine(connection.getInputStream()).length() != 0);
+                                skipToRequestBody(connection);
                                 // No proxy to respond so we must.
                                 sendLine(connection, HTTP_OK);
                             } else {
-                                sendLine(server, requestLine);
+                                // Proxying the request directly to the origin server.
+                                sendAugmentedRequestToHost(connection, server,
+                                        requestType, url, httpVersion);
                             }
                         }
                     } catch (IOException ioe) {
-
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "Unable to connect to proxy " + proxy, ioe);
+                        }
                     }
                     if (server != null) {
                         break;
                     }
                 }
-                if (server == null) {
+                if (list.isEmpty()) {
                     server = new Socket(host, port);
                     if (requestType.equals(CONNECT)) {
-                        while (getLine(connection.getInputStream()).length() != 0);
+                        skipToRequestBody(connection);
                         // No proxy to respond so we must.
                         sendLine(connection, HTTP_OK);
                     } else {
-                        sendLine(server, requestLine);
+                        // Proxying the request directly to the origin server.
+                        sendAugmentedRequestToHost(connection, server,
+                                requestType, url, httpVersion);
                     }
                 }
                 // Pass data back and forth until complete.
-                SocketConnect.connect(connection, server);
-            } catch (IOException e) {
+                if (server != null) {
+                    SocketConnect.connect(connection, server);
+                }
+            } catch (Exception e) {
                 Log.d(TAG, "Problem Proxying", e);
             }
             try {
                 connection.close();
             } catch (IOException ioe) {
-
+                // Do nothing
             }
         }
 
+        /**
+         * Sends HTTP request-line (i.e. the first line in the request)
+         * that contains absolute path of a given absolute URI.
+         *
+         * @param server server to send the request to.
+         * @param requestType type of the request, a.k.a. HTTP method.
+         * @param absoluteUri absolute URI which absolute path should be extracted.
+         * @param httpVersion version of HTTP, e.g. HTTP/1.1.
+         * @throws IOException if the request-line cannot be sent.
+         */
+        private void sendRequestLineWithPath(Socket server, String requestType,
+                URI absoluteUri, String httpVersion) throws IOException {
+
+            String absolutePath = getAbsolutePathFromAbsoluteURI(absoluteUri);
+            String outgoingRequestLine = String.format("%s %s %s",
+                    requestType, absolutePath, httpVersion);
+            sendLine(server, outgoingRequestLine);
+        }
+
+        /**
+         * Extracts absolute path form a given URI. E.g., passing
+         * <code>http://google.com:80/execute?query=cat#top</code>
+         * will result in <code>/execute?query=cat#top</code>.
+         *
+         * @param uri URI which absolute path has to be extracted,
+         * @return the absolute path of the URI,
+         */
+        private String getAbsolutePathFromAbsoluteURI(URI uri) {
+            String rawPath = uri.getRawPath();
+            String rawQuery = uri.getRawQuery();
+            String rawFragment = uri.getRawFragment();
+            StringBuilder absolutePath = new StringBuilder();
+
+            if (rawPath != null) {
+                absolutePath.append(rawPath);
+            } else {
+                absolutePath.append("/");
+            }
+            if (rawQuery != null) {
+                absolutePath.append("?").append(rawQuery);
+            }
+            if (rawFragment != null) {
+                absolutePath.append("#").append(rawFragment);
+            }
+            return absolutePath.toString();
+        }
+
         private String getLine(InputStream inputStream) throws IOException {
-            StringBuffer buffer = new StringBuffer();
+            StringBuilder buffer = new StringBuilder();
             int byteBuffer = inputStream.read();
             if (byteBuffer < 0) return "";
             do {
@@ -179,6 +244,79 @@
             os.write('\n');
             os.flush();
         }
+
+        /**
+         * Reads from socket until an empty line is read which indicates the end of HTTP headers.
+         *
+         * @param socket socket to read from.
+         * @throws IOException if an exception took place during the socket read.
+         */
+        private void skipToRequestBody(Socket socket) throws IOException {
+            while (getLine(socket.getInputStream()).length() != 0);
+        }
+
+        /**
+         * Sends an augmented request to the final host (DIRECT connection).
+         *
+         * @param src socket to read HTTP headers from.The socket current position should point
+         *            to the beginning of the HTTP header section.
+         * @param dst socket to write the augmented request to.
+         * @param httpMethod original request http method.
+         * @param uri original request absolute URI.
+         * @param httpVersion original request http version.
+         * @throws IOException if an exception took place during socket reads or writes.
+         */
+        private void sendAugmentedRequestToHost(Socket src, Socket dst,
+                String httpMethod, URI uri, String httpVersion) throws IOException {
+
+            sendRequestLineWithPath(dst, httpMethod, uri, httpVersion);
+            filterAndForwardRequestHeaders(src, dst);
+
+            // Currently the proxy does not support keep-alive connections; therefore,
+            // the proxy has to request the destination server to close the connection
+            // after the destination server sent the response.
+            sendLine(dst, "Connection: close");
+
+            // Sends and empty line that indicates termination of the header section.
+            sendLine(dst, "");
+        }
+
+        /**
+         * Forwards original request headers filtering out the ones that have to be removed.
+         *
+         * @param src source socket that contains original request headers.
+         * @param dst destination socket to send the filtered headers to.
+         * @throws IOException if the data cannot be read from or written to the sockets.
+         */
+        private void filterAndForwardRequestHeaders(Socket src, Socket dst) throws IOException {
+            String line;
+            do {
+                line = getLine(src.getInputStream());
+                if (line.length() > 0 && !shouldRemoveHeaderLine(line)) {
+                    sendLine(dst, line);
+                }
+            } while (line.length() > 0);
+        }
+
+        /**
+         * Returns true if a given header line has to be removed from the original request.
+         *
+         * @param line header line that should be analysed.
+         * @return true if the header line should be removed and not forwarded to the destination.
+         */
+        private boolean shouldRemoveHeaderLine(String line) {
+            int colIndex = line.indexOf(":");
+            if (colIndex != -1) {
+                String headerName = line.substring(0, colIndex).trim();
+                if (headerName.regionMatches(true, 0, HEADER_CONNECTION, 0,
+                                                      HEADER_CONNECTION.length())
+                        || headerName.regionMatches(true, 0, HEADER_PROXY_CONNECTION,
+                                                          0, HEADER_PROXY_CONNECTION.length())) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     public ProxyServer() {
@@ -192,23 +330,21 @@
         try {
             serverSocket = new ServerSocket(0);
 
-            if (serverSocket != null) {
-                setPort(serverSocket.getLocalPort());
+            setPort(serverSocket.getLocalPort());
 
-                while (mIsRunning) {
-                    try {
-                        Socket socket = serverSocket.accept();
-                        // Only receive local connections.
-                        if (socket.getInetAddress().isLoopbackAddress()) {
-                            ProxyConnection parser = new ProxyConnection(socket);
+            while (mIsRunning) {
+                try {
+                    Socket socket = serverSocket.accept();
+                    // Only receive local connections.
+                    if (socket.getInetAddress().isLoopbackAddress()) {
+                        ProxyConnection parser = new ProxyConnection(socket);
 
-                            threadExecutor.execute(parser);
-                        } else {
-                            socket.close();
-                        }
-                    } catch (IOException e) {
-                        e.printStackTrace();
+                        threadExecutor.execute(parser);
+                    } else {
+                        socket.close();
                     }
+                } catch (IOException e) {
+                    e.printStackTrace();
                 }
             }
         } catch (SocketException e) {
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
index cbea188..970fdc7 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyService.java
@@ -33,8 +33,6 @@
     /** Keep these values up-to-date with PacManager.java */
     public static final String KEY_PROXY = "keyProxy";
     public static final String HOST = "localhost";
-    // STOPSHIP This being a static port means it can be hijacked by other apps.
-    public static final int PORT = 8182;
     public static final String EXCL_LIST = "";
 
     @Override
diff --git a/policy/Android.mk b/policy/Android.mk
deleted file mode 100644
index 47d8fb8..0000000
--- a/policy/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-            
-LOCAL_MODULE := android.policy
-
-include $(BUILD_JAVA_LIBRARY)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
deleted file mode 100644
index bfbd60d..0000000
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ /dev/null
@@ -1,284 +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.internal.policy.impl;
-
-import android.app.StatusBarManager;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManagerPolicy.WindowState;
-
-import com.android.internal.statusbar.IStatusBarService;
-
-import java.io.PrintWriter;
-
-/**
- * Controls state/behavior specific to a system bar window.
- */
-public class BarController {
-    private static final boolean DEBUG = false;
-
-    private static final int TRANSIENT_BAR_NONE = 0;
-    private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
-    private static final int TRANSIENT_BAR_SHOWING = 2;
-    private static final int TRANSIENT_BAR_HIDING = 3;
-
-    private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
-
-    private final String mTag;
-    private final int mTransientFlag;
-    private final int mUnhideFlag;
-    private final int mTranslucentFlag;
-    private final int mStatusBarManagerId;
-    private final int mTranslucentWmFlag;
-    private final Handler mHandler;
-    private final Object mServiceAquireLock = new Object();
-    private IStatusBarService mStatusBarService;
-
-    private WindowState mWin;
-    private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
-    private int mTransientBarState;
-    private boolean mPendingShow;
-    private long mLastTranslucent;
-
-    public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
-            int statusBarManagerId, int translucentWmFlag) {
-        mTag = "BarController." + tag;
-        mTransientFlag = transientFlag;
-        mUnhideFlag = unhideFlag;
-        mTranslucentFlag = translucentFlag;
-        mStatusBarManagerId = statusBarManagerId;
-        mTranslucentWmFlag = translucentWmFlag;
-        mHandler = new Handler();
-    }
-
-    public void setWindow(WindowState win) {
-        mWin = win;
-    }
-
-    public void showTransient() {
-        if (mWin != null) {
-            setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
-        }
-    }
-
-    public boolean isTransientShowing() {
-        return mTransientBarState == TRANSIENT_BAR_SHOWING;
-    }
-
-    public boolean isTransientShowRequested() {
-        return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
-    }
-
-    public boolean wasRecentlyTranslucent() {
-        return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
-    }
-
-    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
-        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
-                (vis & mTransientFlag) == 0) {
-            // sysui requests hide
-            setTransientBarState(TRANSIENT_BAR_HIDING);
-            setBarShowingLw(false);
-        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
-            // sysui ready to unhide
-            setBarShowingLw(true);
-        }
-    }
-
-    public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
-        if (mWin != null) {
-            if (win != null && (win.getAttrs().privateFlags
-                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
-                int fl = PolicyControl.getWindowFlags(win, null);
-                if ((fl & mTranslucentWmFlag) != 0) {
-                    vis |= mTranslucentFlag;
-                } else {
-                    vis &= ~mTranslucentFlag;
-                }
-                if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
-                    vis |= View.SYSTEM_UI_TRANSPARENT;
-                } else {
-                    vis &= ~View.SYSTEM_UI_TRANSPARENT;
-                }
-            } else {
-                vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
-                vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
-            }
-        }
-        return vis;
-    }
-
-    public boolean setBarShowingLw(final boolean show) {
-        if (mWin == null) return false;
-        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
-            mPendingShow = true;
-            return false;
-        }
-        final boolean wasVis = mWin.isVisibleLw();
-        final boolean wasAnim = mWin.isAnimatingLw();
-        final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
-        final int state = computeStateLw(wasVis, wasAnim, mWin, change);
-        final boolean stateChanged = updateStateLw(state);
-        return change || stateChanged;
-    }
-
-    private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
-        if (win.hasDrawnLw()) {
-            final boolean vis = win.isVisibleLw();
-            final boolean anim = win.isAnimatingLw();
-            if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
-                return StatusBarManager.WINDOW_STATE_HIDDEN;
-            } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) {
-                return StatusBarManager.WINDOW_STATE_SHOWING;
-            } else if (change) {
-                if (wasVis && vis && !wasAnim && anim) {
-                    return StatusBarManager.WINDOW_STATE_HIDING;
-                } else {
-                    return StatusBarManager.WINDOW_STATE_SHOWING;
-                }
-            }
-        }
-        return mState;
-    }
-
-    private boolean updateStateLw(final int state) {
-        if (state != mState) {
-            mState = state;
-            if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        IStatusBarService statusbar = getStatusBarService();
-                        if (statusbar != null) {
-                            statusbar.setWindowState(mStatusBarManagerId, state);
-                        }
-                    } catch (RemoteException e) {
-                        if (DEBUG) Slog.w(mTag, "Error posting window state", e);
-                        // re-acquire status bar service next time it is needed.
-                        mStatusBarService = null;
-                    }
-                }
-            });
-            return true;
-        }
-        return false;
-    }
-
-    public boolean checkHiddenLw() {
-        if (mWin != null && mWin.hasDrawnLw()) {
-            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
-                updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
-            }
-            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
-                // Finished animating out, clean up and reset style
-                setTransientBarState(TRANSIENT_BAR_NONE);
-                if (mPendingShow) {
-                    setBarShowingLw(true);
-                    mPendingShow = false;
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean checkShowTransientBarLw() {
-        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
-            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
-            return false;
-        } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
-            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
-            return false;
-        } else if (mWin == null) {
-            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
-            return false;
-        } else if (mWin.isDisplayedLw()) {
-            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
-        if (mWin == null) return vis;
-        if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
-            if (transientAllowed) {
-                vis |= mTransientFlag;
-                if ((oldVis & mTransientFlag) == 0) {
-                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
-                }
-                setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
-            } else {
-                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
-            }
-        }
-        if (mTransientBarState != TRANSIENT_BAR_NONE) {
-            vis |= mTransientFlag;  // ignore clear requests until transition completes
-            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
-        }
-        if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
-                ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
-            mLastTranslucent = SystemClock.uptimeMillis();
-        }
-        return vis;
-    }
-
-    private void setTransientBarState(int state) {
-        if (mWin != null && state != mTransientBarState) {
-            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
-                mLastTranslucent = SystemClock.uptimeMillis();
-            }
-            mTransientBarState = state;
-            if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
-        }
-    }
-
-    private IStatusBarService getStatusBarService() {
-        synchronized (mServiceAquireLock) {
-            if (mStatusBarService == null) {
-                mStatusBarService = IStatusBarService.Stub.asInterface(
-                        ServiceManager.getService("statusbar"));
-            }
-            return mStatusBarService;
-        }
-    }
-
-    private static String transientBarStateToString(int state) {
-        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
-        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
-        if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
-        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
-        throw new IllegalArgumentException("Unknown state " + state);
-    }
-
-    public void dump(PrintWriter pw, String prefix) {
-        if (mWin != null) {
-            pw.print(prefix); pw.println(mTag);
-            pw.print(prefix); pw.print("  "); pw.print("mState"); pw.print('=');
-            pw.println(StatusBarManager.windowStateToString(mState));
-            pw.print(prefix); pw.print("  "); pw.print("mTransientBar"); pw.print('=');
-            pw.println(transientBarStateToString(mTransientBarState));
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java b/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
deleted file mode 100644
index 6f79f58..0000000
--- a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2012 Google 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.policy.impl;
-
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.tts.TextToSpeech;
-import android.util.MathUtils;
-import android.view.IWindowManager;
-import android.view.MotionEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-public class EnableAccessibilityController {
-
-    private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
-    private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
-
-    public static final int MESSAGE_SPEAK_WARNING = 1;
-    public static final int MESSAGE_SPEAK_ENABLE_CANCELED = 2;
-    public static final int MESSAGE_ENABLE_ACCESSIBILITY = 3;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case MESSAGE_SPEAK_WARNING: {
-                    String text = mContext.getString(R.string.continue_to_enable_accessibility);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_SPEAK_ENABLE_CANCELED: {
-                    String text = mContext.getString(R.string.enable_accessibility_canceled);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_ENABLE_ACCESSIBILITY: {
-                    enableAccessibility();
-                    mTone.play();
-                    mTts.speak(mContext.getString(R.string.accessibility_enabled),
-                            TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-            }
-        }
-    };
-
-    private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
-            ServiceManager.getService("window"));
-
-    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
-            .Stub.asInterface(ServiceManager.getService("accessibility"));
-
-
-    private final Context mContext;
-    private final Runnable mOnAccessibilityEnabledCallback;
-    private final UserManager mUserManager;
-    private final TextToSpeech mTts;
-    private final Ringtone mTone;
-
-    private final float mTouchSlop;
-
-    private boolean mDestroyed;
-    private boolean mCanceled;
-
-    private float mFirstPointerDownX;
-    private float mFirstPointerDownY;
-    private float mSecondPointerDownX;
-    private float mSecondPointerDownY;
-
-    public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
-        mContext = context;
-        mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
-            @Override
-            public void onInit(int status) {
-                if (mDestroyed) {
-                    mTts.shutdown();
-                }
-            }
-        });
-        mTone = RingtoneManager.getRingtone(context, Settings.System.DEFAULT_NOTIFICATION_URI);
-        mTone.setStreamType(AudioManager.STREAM_MUSIC);
-        mTouchSlop = context.getResources().getDimensionPixelSize(
-                R.dimen.accessibility_touch_slop);
-    }
-
-    public static boolean canEnableAccessibilityViaGesture(Context context) {
-        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
-        // Accessibility is enabled and there is an enabled speaking
-        // accessibility service, then we have nothing to do.
-        if (accessibilityManager.isEnabled()
-                && !accessibilityManager.getEnabledAccessibilityServiceList(
-                        AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()) {
-            return false;
-        }
-        // If the global gesture is enabled and there is a speaking service
-        // installed we are good to go, otherwise there is nothing to do.
-        return Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1
-                && !getInstalledSpeakingAccessibilityServices(context).isEmpty();
-    }
-
-    private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
-            Context context) {
-        List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
-        services.addAll(AccessibilityManager.getInstance(context)
-                .getInstalledAccessibilityServiceList());
-        Iterator<AccessibilityServiceInfo> iterator = services.iterator();
-        while (iterator.hasNext()) {
-            AccessibilityServiceInfo service = iterator.next();
-            if ((service.feedbackType & AccessibilityServiceInfo.FEEDBACK_SPOKEN) == 0) {
-                iterator.remove();
-            }
-        }
-        return services;
-    }
-
-    public void onDestroy() {
-        mDestroyed = true;
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
-                && event.getPointerCount() == 2) {
-            mFirstPointerDownX = event.getX(0);
-            mFirstPointerDownY = event.getY(0);
-            mSecondPointerDownX = event.getX(1);
-            mSecondPointerDownY = event.getY(1);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_SPEAK_WARNING,
-                    SPEAK_WARNING_DELAY_MILLIS);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_ENABLE_ACCESSIBILITY,
-                   ENABLE_ACCESSIBILITY_DELAY_MILLIS);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean onTouchEvent(MotionEvent event) {
-        final int pointerCount = event.getPointerCount();
-        final int action = event.getActionMasked();
-        if (mCanceled) {
-            if (action == MotionEvent.ACTION_UP) {
-                mCanceled = false;
-            }
-            return true;
-        }
-        switch (action) {
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                if (pointerCount > 2) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_MOVE: {
-                final float firstPointerMove = MathUtils.dist(event.getX(0),
-                        event.getY(0), mFirstPointerDownX, mFirstPointerDownY);
-                if (Math.abs(firstPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-                final float secondPointerMove = MathUtils.dist(event.getX(1),
-                        event.getY(1), mSecondPointerDownX, mSecondPointerDownY);
-                if (Math.abs(secondPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                cancel();
-            } break;
-        }
-        return true;
-    }
-
-    private void cancel() {
-        mCanceled = true;
-        if (mHandler.hasMessages(MESSAGE_SPEAK_WARNING)) {
-            mHandler.removeMessages(MESSAGE_SPEAK_WARNING);
-        } else if (mHandler.hasMessages(MESSAGE_ENABLE_ACCESSIBILITY)) {
-            mHandler.sendEmptyMessage(MESSAGE_SPEAK_ENABLE_CANCELED);
-        }
-        mHandler.removeMessages(MESSAGE_ENABLE_ACCESSIBILITY);
-    }
-
-    private void enableAccessibility() {
-        List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
-                mContext);
-        if (services.isEmpty()) {
-            return;
-        }
-        boolean keyguardLocked = false;
-        try {
-            keyguardLocked = mWindowManager.isKeyguardLocked();
-        } catch (RemoteException re) {
-            /* ignore */
-        }
-
-        final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;
-
-        AccessibilityServiceInfo service = services.get(0);
-        boolean enableTouchExploration = (service.flags
-                & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
-        // Try to find a service supporting explore by touch.
-        if (!enableTouchExploration) {
-            final int serviceCount = services.size();
-            for (int i = 1; i < serviceCount; i++) {
-                AccessibilityServiceInfo candidate = services.get(i);
-                if ((candidate.flags & AccessibilityServiceInfo
-                        .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
-                    enableTouchExploration = true;
-                    service = candidate;
-                    break;
-                }
-            }
-        }
-
-        ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
-        ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
-        if (!keyguardLocked || !hasMoreThanOneUser) {
-            final int userId = ActivityManager.getCurrentUser();
-            String enabledServiceString = componentName.flattenToString();
-            ContentResolver resolver = mContext.getContentResolver();
-            // Enable one speaking accessibility service.
-            Settings.Secure.putStringForUser(resolver,
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                    enabledServiceString, userId);
-            // Allow the services we just enabled to toggle touch exploration.
-            Settings.Secure.putStringForUser(resolver,
-                    Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
-                    enabledServiceString, userId);
-            // Enable touch exploration.
-            if (enableTouchExploration) {
-                Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
-                        1, userId);
-            }
-            // Enable accessibility script injection (AndroidVox) for web content.
-            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
-                    1, userId);
-            // Turn on accessibility mode last.
-            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
-                    1, userId);
-        } else if (keyguardLocked) {
-            try {
-                mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
-                        componentName, enableTouchExploration);
-            } catch (RemoteException re) {
-                /* ignore */
-            }
-        }
-
-        mOnAccessibilityEnabledCallback.run();
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
deleted file mode 100644
index b0b2886..0000000
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.app.AlertController;
-import com.android.internal.app.AlertController.AlertParams;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.ConnectivityManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerPolicy.WindowManagerFuncs;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Helper to show the global actions dialog.  Each item is an {@link Action} that
- * may show depending on whether the keyguard is showing, and whether the device
- * is provisioned.
- */
-class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
-
-    private static final String TAG = "GlobalActions";
-
-    private static final boolean SHOW_SILENT_TOGGLE = true;
-
-    /* Valid settings for global actions keys.
-     * see config.xml config_globalActionList */
-    private static final String GLOBAL_ACTION_KEY_POWER = "power";
-    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
-    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
-    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
-    private static final String GLOBAL_ACTION_KEY_USERS = "users";
-    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
-    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
-
-    private final Context mContext;
-    private final WindowManagerFuncs mWindowManagerFuncs;
-    private final AudioManager mAudioManager;
-    private final IDreamManager mDreamManager;
-
-    private ArrayList<Action> mItems;
-    private GlobalActionsDialog mDialog;
-
-    private Action mSilentModeAction;
-    private ToggleAction mAirplaneModeOn;
-
-    private MyAdapter mAdapter;
-
-    private boolean mKeyguardShowing = false;
-    private boolean mDeviceProvisioned = false;
-    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
-    private boolean mIsWaitingForEcmExit = false;
-    private boolean mHasTelephony;
-    private boolean mHasVibrator;
-    private final boolean mShowSilentToggle;
-
-    /**
-     * @param context everything needs a context :(
-     */
-    public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
-        mContext = context;
-        mWindowManagerFuncs = windowManagerFuncs;
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.getService(DreamService.DREAM_SERVICE));
-
-        // receive broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter);
-
-        ConnectivityManager cm = (ConnectivityManager)
-                context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
-        // get notified of phone state changes
-        TelephonyManager telephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
-                mAirplaneModeObserver);
-        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator != null && vibrator.hasVibrator();
-
-        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useFixedVolume);
-    }
-
-    /**
-     * Show the global actions dialog (creating if necessary)
-     * @param keyguardShowing True if keyguard is showing
-     */
-    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
-        mKeyguardShowing = keyguardShowing;
-        mDeviceProvisioned = isDeviceProvisioned;
-        if (mDialog != null) {
-            mDialog.dismiss();
-            mDialog = null;
-            // Show delayed, so that the dismiss of the previous dialog completes
-            mHandler.sendEmptyMessage(MESSAGE_SHOW);
-        } else {
-            handleShow();
-        }
-    }
-
-    private void awakenIfNecessary() {
-        if (mDreamManager != null) {
-            try {
-                if (mDreamManager.isDreaming()) {
-                    mDreamManager.awaken();
-                }
-            } catch (RemoteException e) {
-                // we tried
-            }
-        }
-    }
-
-    private void handleShow() {
-        awakenIfNecessary();
-        mDialog = createDialog();
-        prepareDialog();
-
-        // If we only have 1 item and it's a simple press action, just do this action.
-        if (mAdapter.getCount() == 1
-                && mAdapter.getItem(0) instanceof SinglePressAction
-                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
-            ((SinglePressAction) mAdapter.getItem(0)).onPress();
-        } else {
-            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
-            attrs.setTitle("GlobalActions");
-            mDialog.getWindow().setAttributes(attrs);
-            mDialog.show();
-            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
-        }
-    }
-
-    /**
-     * Create the global actions dialog.
-     * @return A new dialog.
-     */
-    private GlobalActionsDialog createDialog() {
-        // Simple toggle style if there's no vibrator, otherwise use a tri-state
-        if (!mHasVibrator) {
-            mSilentModeAction = new SilentModeToggleAction();
-        } else {
-            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
-        }
-        mAirplaneModeOn = new ToggleAction(
-                R.drawable.ic_lock_airplane_mode,
-                R.drawable.ic_lock_airplane_mode_off,
-                R.string.global_actions_toggle_airplane_mode,
-                R.string.global_actions_airplane_mode_on_status,
-                R.string.global_actions_airplane_mode_off_status) {
-
-            void onToggle(boolean on) {
-                if (mHasTelephony && Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
-                    mIsWaitingForEcmExit = true;
-                    // Launch ECM exit dialog
-                    Intent ecmDialogIntent =
-                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
-                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivity(ecmDialogIntent);
-                } else {
-                    changeAirplaneModeSystemSetting(on);
-                }
-            }
-
-            @Override
-            protected void changeStateFromPress(boolean buttonOn) {
-                if (!mHasTelephony) return;
-
-                // In ECM mode airplane state cannot be changed
-                if (!(Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
-                    mState = buttonOn ? State.TurningOn : State.TurningOff;
-                    mAirplaneState = mState;
-                }
-            }
-
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-        };
-        onAirplaneModeChanged();
-
-        mItems = new ArrayList<Action>();
-        String[] defaultActions = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_globalActionsList);
-
-        ArraySet<String> addedKeys = new ArraySet<String>();
-        for (int i = 0; i < defaultActions.length; i++) {
-            String actionKey = defaultActions[i];
-            if (addedKeys.contains(actionKey)) {
-                // If we already have added this, don't add it again.
-                continue;
-            }
-            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
-                mItems.add(new PowerAction());
-            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
-                mItems.add(mAirplaneModeOn);
-            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
-                if (Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
-                    mItems.add(getBugReportAction());
-                }
-            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
-                if (mShowSilentToggle) {
-                    mItems.add(mSilentModeAction);
-                }
-            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
-                if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
-                    addUsersToMenu(mItems);
-                }
-            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
-                mItems.add(getSettingsAction());
-            } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
-                mItems.add(getLockdownAction());
-            } else {
-                Log.e(TAG, "Invalid global action key " + actionKey);
-            }
-            // Add here so we don't add more than one.
-            addedKeys.add(actionKey);
-        }
-
-        mAdapter = new MyAdapter();
-
-        AlertParams params = new AlertParams(mContext);
-        params.mAdapter = mAdapter;
-        params.mOnClickListener = this;
-        params.mForceInverseBackground = true;
-
-        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
-        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
-
-        dialog.getListView().setItemsCanFocus(true);
-        dialog.getListView().setLongClickable(true);
-        dialog.getListView().setOnItemLongClickListener(
-                new AdapterView.OnItemLongClickListener() {
-                    @Override
-                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
-                            long id) {
-                        final Action action = mAdapter.getItem(position);
-                        if (action instanceof LongPressAction) {
-                            return ((LongPressAction) action).onLongPress();
-                        }
-                        return false;
-                    }
-        });
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-
-        dialog.setOnDismissListener(this);
-
-        return dialog;
-    }
-
-    private final class PowerAction extends SinglePressAction implements LongPressAction {
-        private PowerAction() {
-            super(com.android.internal.R.drawable.ic_lock_power_off,
-                R.string.global_action_power_off);
-        }
-
-        @Override
-        public boolean onLongPress() {
-            mWindowManagerFuncs.rebootSafeMode(true);
-            return true;
-        }
-
-        @Override
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        @Override
-        public boolean showBeforeProvisioning() {
-            return true;
-        }
-
-        @Override
-        public void onPress() {
-            // shutdown by making sure radio and power are handled accordingly.
-            mWindowManagerFuncs.shutdown(false /* confirm */);
-        }
-    }
-
-    private Action getBugReportAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
-                R.string.bugreport_title) {
-
-            public void onPress() {
-                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-                builder.setTitle(com.android.internal.R.string.bugreport_title);
-                builder.setMessage(com.android.internal.R.string.bugreport_message);
-                builder.setNegativeButton(com.android.internal.R.string.cancel, null);
-                builder.setPositiveButton(com.android.internal.R.string.report,
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                // don't actually trigger the bugreport if we are running stability
-                                // tests via monkey
-                                if (ActivityManager.isUserAMonkey()) {
-                                    return;
-                                }
-                                // Add a little delay before executing, to give the
-                                // dialog a chance to go away before it takes a
-                                // screenshot.
-                                mHandler.postDelayed(new Runnable() {
-                                    @Override public void run() {
-                                        try {
-                                            ActivityManagerNative.getDefault()
-                                                    .requestBugReport();
-                                        } catch (RemoteException e) {
-                                        }
-                                    }
-                                }, 500);
-                            }
-                        });
-                AlertDialog dialog = builder.create();
-                dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                dialog.show();
-            }
-
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-
-            @Override
-            public String getStatus() {
-                return mContext.getString(
-                        com.android.internal.R.string.bugreport_status,
-                        Build.VERSION.RELEASE,
-                        Build.ID);
-            }
-        };
-    }
-
-    private Action getSettingsAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
-                R.string.global_action_settings) {
-
-            @Override
-            public void onPress() {
-                Intent intent = new Intent(Settings.ACTION_SETTINGS);
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivity(intent);
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return true;
-            }
-        };
-    }
-
-    private Action getLockdownAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
-                R.string.global_action_lockdown) {
-
-            @Override
-            public void onPress() {
-                new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
-                try {
-                    WindowManagerGlobal.getWindowManagerService().lockNow(null);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error while trying to lock device.", e);
-                }
-            }
-
-            @Override
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            @Override
-            public boolean showBeforeProvisioning() {
-                return false;
-            }
-        };
-    }
-
-    private UserInfo getCurrentUser() {
-        try {
-            return ActivityManagerNative.getDefault().getCurrentUser();
-        } catch (RemoteException re) {
-            return null;
-        }
-    }
-
-    private boolean isCurrentUserOwner() {
-        UserInfo currentUser = getCurrentUser();
-        return currentUser == null || currentUser.isPrimary();
-    }
-
-    private void addUsersToMenu(ArrayList<Action> items) {
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.isUserSwitcherEnabled()) {
-            List<UserInfo> users = um.getUsers();
-            UserInfo currentUser = getCurrentUser();
-            for (final UserInfo user : users) {
-                if (user.supportsSwitchTo()) {
-                    boolean isCurrentUser = currentUser == null
-                            ? user.id == 0 : (currentUser.id == user.id);
-                    Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
-                            : null;
-                    SinglePressAction switchToUser = new SinglePressAction(
-                            com.android.internal.R.drawable.ic_menu_cc, icon,
-                            (user.name != null ? user.name : "Primary")
-                            + (isCurrentUser ? " \u2714" : "")) {
-                        public void onPress() {
-                            try {
-                                ActivityManagerNative.getDefault().switchUser(user.id);
-                            } catch (RemoteException re) {
-                                Log.e(TAG, "Couldn't switch user " + re);
-                            }
-                        }
-
-                        public boolean showDuringKeyguard() {
-                            return true;
-                        }
-
-                        public boolean showBeforeProvisioning() {
-                            return false;
-                        }
-                    };
-                    items.add(switchToUser);
-                }
-            }
-        }
-    }
-
-    private void prepareDialog() {
-        refreshSilentMode();
-        mAirplaneModeOn.updateState(mAirplaneState);
-        mAdapter.notifyDataSetChanged();
-        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        if (mShowSilentToggle) {
-            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            mContext.registerReceiver(mRingerModeReceiver, filter);
-        }
-    }
-
-    private void refreshSilentMode() {
-        if (!mHasVibrator) {
-            final boolean silentModeOn =
-                    mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
-            ((ToggleAction)mSilentModeAction).updateState(
-                    silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void onDismiss(DialogInterface dialog) {
-        if (mShowSilentToggle) {
-            try {
-                mContext.unregisterReceiver(mRingerModeReceiver);
-            } catch (IllegalArgumentException ie) {
-                // ignore this
-                Log.w(TAG, ie);
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void onClick(DialogInterface dialog, int which) {
-        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
-            dialog.dismiss();
-        }
-        mAdapter.getItem(which).onPress();
-    }
-
-    /**
-     * The adapter used for the list within the global actions dialog, taking
-     * into account whether the keyguard is showing via
-     * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
-     * via {@link GlobalActions#mDeviceProvisioned}.
-     */
-    private class MyAdapter extends BaseAdapter {
-
-        public int getCount() {
-            int count = 0;
-
-            for (int i = 0; i < mItems.size(); i++) {
-                final Action action = mItems.get(i);
-
-                if (mKeyguardShowing && !action.showDuringKeyguard()) {
-                    continue;
-                }
-                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
-                    continue;
-                }
-                count++;
-            }
-            return count;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            return getItem(position).isEnabled();
-        }
-
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        public Action getItem(int position) {
-
-            int filteredPos = 0;
-            for (int i = 0; i < mItems.size(); i++) {
-                final Action action = mItems.get(i);
-                if (mKeyguardShowing && !action.showDuringKeyguard()) {
-                    continue;
-                }
-                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
-                    continue;
-                }
-                if (filteredPos == position) {
-                    return action;
-                }
-                filteredPos++;
-            }
-
-            throw new IllegalArgumentException("position " + position
-                    + " out of range of showable actions"
-                    + ", filtered count=" + getCount()
-                    + ", keyguardshowing=" + mKeyguardShowing
-                    + ", provisioned=" + mDeviceProvisioned);
-        }
-
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            Action action = getItem(position);
-            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
-        }
-    }
-
-    // note: the scheme below made more sense when we were planning on having
-    // 8 different things in the global actions dialog.  seems overkill with
-    // only 3 items now, but may as well keep this flexible approach so it will
-    // be easy should someone decide at the last minute to include something
-    // else, such as 'enable wifi', or 'enable bluetooth'
-
-    /**
-     * What each item in the global actions dialog must be able to support.
-     */
-    private interface Action {
-        /**
-         * @return Text that will be announced when dialog is created.  null
-         *     for none.
-         */
-        CharSequence getLabelForAccessibility(Context context);
-
-        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
-
-        void onPress();
-
-        /**
-         * @return whether this action should appear in the dialog when the keygaurd
-         *    is showing.
-         */
-        boolean showDuringKeyguard();
-
-        /**
-         * @return whether this action should appear in the dialog before the
-         *   device is provisioned.
-         */
-        boolean showBeforeProvisioning();
-
-        boolean isEnabled();
-    }
-
-    /**
-     * An action that also supports long press.
-     */
-    private interface LongPressAction extends Action {
-        boolean onLongPress();
-    }
-
-    /**
-     * A single press action maintains no state, just responds to a press
-     * and takes an action.
-     */
-    private static abstract class SinglePressAction implements Action {
-        private final int mIconResId;
-        private final Drawable mIcon;
-        private final int mMessageResId;
-        private final CharSequence mMessage;
-
-        protected SinglePressAction(int iconResId, int messageResId) {
-            mIconResId = iconResId;
-            mMessageResId = messageResId;
-            mMessage = null;
-            mIcon = null;
-        }
-
-        protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
-            mIconResId = iconResId;
-            mMessageResId = 0;
-            mMessage = message;
-            mIcon = icon;
-        }
-
-        protected SinglePressAction(int iconResId, CharSequence message) {
-            mIconResId = iconResId;
-            mMessageResId = 0;
-            mMessage = message;
-            mIcon = null;
-        }
-
-        public boolean isEnabled() {
-            return true;
-        }
-
-        public String getStatus() {
-            return null;
-        }
-
-        abstract public void onPress();
-
-        public CharSequence getLabelForAccessibility(Context context) {
-            if (mMessage != null) {
-                return mMessage;
-            } else {
-                return context.getString(mMessageResId);
-            }
-        }
-
-        public View create(
-                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
-            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
-
-            ImageView icon = (ImageView) v.findViewById(R.id.icon);
-            TextView messageView = (TextView) v.findViewById(R.id.message);
-
-            TextView statusView = (TextView) v.findViewById(R.id.status);
-            final String status = getStatus();
-            if (!TextUtils.isEmpty(status)) {
-                statusView.setText(status);
-            } else {
-                statusView.setVisibility(View.GONE);
-            }
-            if (mIcon != null) {
-                icon.setImageDrawable(mIcon);
-                icon.setScaleType(ScaleType.CENTER_CROP);
-            } else if (mIconResId != 0) {
-                icon.setImageDrawable(context.getDrawable(mIconResId));
-            }
-            if (mMessage != null) {
-                messageView.setText(mMessage);
-            } else {
-                messageView.setText(mMessageResId);
-            }
-
-            return v;
-        }
-    }
-
-    /**
-     * A toggle action knows whether it is on or off, and displays an icon
-     * and status message accordingly.
-     */
-    private static abstract class ToggleAction implements Action {
-
-        enum State {
-            Off(false),
-            TurningOn(true),
-            TurningOff(true),
-            On(false);
-
-            private final boolean inTransition;
-
-            State(boolean intermediate) {
-                inTransition = intermediate;
-            }
-
-            public boolean inTransition() {
-                return inTransition;
-            }
-        }
-
-        protected State mState = State.Off;
-
-        // prefs
-        protected int mEnabledIconResId;
-        protected int mDisabledIconResid;
-        protected int mMessageResId;
-        protected int mEnabledStatusMessageResId;
-        protected int mDisabledStatusMessageResId;
-
-        /**
-         * @param enabledIconResId The icon for when this action is on.
-         * @param disabledIconResid The icon for when this action is off.
-         * @param essage The general information message, e.g 'Silent Mode'
-         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
-         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
-         */
-        public ToggleAction(int enabledIconResId,
-                int disabledIconResid,
-                int message,
-                int enabledStatusMessageResId,
-                int disabledStatusMessageResId) {
-            mEnabledIconResId = enabledIconResId;
-            mDisabledIconResid = disabledIconResid;
-            mMessageResId = message;
-            mEnabledStatusMessageResId = enabledStatusMessageResId;
-            mDisabledStatusMessageResId = disabledStatusMessageResId;
-        }
-
-        /**
-         * Override to make changes to resource IDs just before creating the
-         * View.
-         */
-        void willCreate() {
-
-        }
-
-        @Override
-        public CharSequence getLabelForAccessibility(Context context) {
-            return context.getString(mMessageResId);
-        }
-
-        public View create(Context context, View convertView, ViewGroup parent,
-                LayoutInflater inflater) {
-            willCreate();
-
-            View v = inflater.inflate(R
-                            .layout.global_actions_item, parent, false);
-
-            ImageView icon = (ImageView) v.findViewById(R.id.icon);
-            TextView messageView = (TextView) v.findViewById(R.id.message);
-            TextView statusView = (TextView) v.findViewById(R.id.status);
-            final boolean enabled = isEnabled();
-
-            if (messageView != null) {
-                messageView.setText(mMessageResId);
-                messageView.setEnabled(enabled);
-            }
-
-            boolean on = ((mState == State.On) || (mState == State.TurningOn));
-            if (icon != null) {
-                icon.setImageDrawable(context.getDrawable(
-                        (on ? mEnabledIconResId : mDisabledIconResid)));
-                icon.setEnabled(enabled);
-            }
-
-            if (statusView != null) {
-                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
-                statusView.setVisibility(View.VISIBLE);
-                statusView.setEnabled(enabled);
-            }
-            v.setEnabled(enabled);
-
-            return v;
-        }
-
-        public final void onPress() {
-            if (mState.inTransition()) {
-                Log.w(TAG, "shouldn't be able to toggle when in transition");
-                return;
-            }
-
-            final boolean nowOn = !(mState == State.On);
-            onToggle(nowOn);
-            changeStateFromPress(nowOn);
-        }
-
-        public boolean isEnabled() {
-            return !mState.inTransition();
-        }
-
-        /**
-         * Implementations may override this if their state can be in on of the intermediate
-         * states until some notification is received (e.g airplane mode is 'turning off' until
-         * we know the wireless connections are back online
-         * @param buttonOn Whether the button was turned on or off
-         */
-        protected void changeStateFromPress(boolean buttonOn) {
-            mState = buttonOn ? State.On : State.Off;
-        }
-
-        abstract void onToggle(boolean on);
-
-        public void updateState(State state) {
-            mState = state;
-        }
-    }
-
-    private class SilentModeToggleAction extends ToggleAction {
-        public SilentModeToggleAction() {
-            super(R.drawable.ic_audio_vol_mute,
-                    R.drawable.ic_audio_vol,
-                    R.string.global_action_toggle_silent_mode,
-                    R.string.global_action_silent_mode_on_status,
-                    R.string.global_action_silent_mode_off_status);
-        }
-
-        void onToggle(boolean on) {
-            if (on) {
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
-            } else {
-                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-            }
-        }
-
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        public boolean showBeforeProvisioning() {
-            return false;
-        }
-    }
-
-    private static class SilentModeTriStateAction implements Action, View.OnClickListener {
-
-        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
-
-        private final AudioManager mAudioManager;
-        private final Handler mHandler;
-        private final Context mContext;
-
-        SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
-            mAudioManager = audioManager;
-            mHandler = handler;
-            mContext = context;
-        }
-
-        private int ringerModeToIndex(int ringerMode) {
-            // They just happen to coincide
-            return ringerMode;
-        }
-
-        private int indexToRingerMode(int index) {
-            // They just happen to coincide
-            return index;
-        }
-
-        @Override
-        public CharSequence getLabelForAccessibility(Context context) {
-            return null;
-        }
-
-        public View create(Context context, View convertView, ViewGroup parent,
-                LayoutInflater inflater) {
-            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
-
-            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
-            for (int i = 0; i < 3; i++) {
-                View itemView = v.findViewById(ITEM_IDS[i]);
-                itemView.setSelected(selectedIndex == i);
-                // Set up click handler
-                itemView.setTag(i);
-                itemView.setOnClickListener(this);
-            }
-            return v;
-        }
-
-        public void onPress() {
-        }
-
-        public boolean showDuringKeyguard() {
-            return true;
-        }
-
-        public boolean showBeforeProvisioning() {
-            return false;
-        }
-
-        public boolean isEnabled() {
-            return true;
-        }
-
-        void willCreate() {
-        }
-
-        public void onClick(View v) {
-            if (!(v.getTag() instanceof Integer)) return;
-
-            int index = (Integer) v.getTag();
-            mAudioManager.setRingerMode(indexToRingerMode(index));
-            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
-        }
-    }
-
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
-                if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
-                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
-                }
-            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
-                // Airplane mode can be changed after ECM exits if airplane toggle button
-                // is pressed during ECM mode
-                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
-                        mIsWaitingForEcmExit) {
-                    mIsWaitingForEcmExit = false;
-                    changeAirplaneModeSystemSetting(true);
-                }
-            }
-        }
-    };
-
-    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onServiceStateChanged(ServiceState serviceState) {
-            if (!mHasTelephony) return;
-            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
-            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
-            mAirplaneModeOn.updateState(mAirplaneState);
-            mAdapter.notifyDataSetChanged();
-        }
-    };
-
-    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
-                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
-            }
-        }
-    };
-
-    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            onAirplaneModeChanged();
-        }
-    };
-
-    private static final int MESSAGE_DISMISS = 0;
-    private static final int MESSAGE_REFRESH = 1;
-    private static final int MESSAGE_SHOW = 2;
-    private static final int DIALOG_DISMISS_DELAY = 300; // ms
-
-    private Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-            case MESSAGE_DISMISS:
-                if (mDialog != null) {
-                    mDialog.dismiss();
-                    mDialog = null;
-                }
-                break;
-            case MESSAGE_REFRESH:
-                refreshSilentMode();
-                mAdapter.notifyDataSetChanged();
-                break;
-            case MESSAGE_SHOW:
-                handleShow();
-                break;
-            }
-        }
-    };
-
-    private void onAirplaneModeChanged() {
-        // Let the service state callbacks handle the state.
-        if (mHasTelephony) return;
-
-        boolean airplaneModeOn = Settings.Global.getInt(
-                mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON,
-                0) == 1;
-        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
-        mAirplaneModeOn.updateState(mAirplaneState);
-    }
-
-    /**
-     * Change the airplane mode system setting
-     */
-    private void changeAirplaneModeSystemSetting(boolean on) {
-        Settings.Global.putInt(
-                mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON,
-                on ? 1 : 0);
-        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.putExtra("state", on);
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-        if (!mHasTelephony) {
-            mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
-        }
-    }
-
-    private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
-        private final Context mContext;
-        private final int mWindowTouchSlop;
-        private final AlertController mAlert;
-        private final MyAdapter mAdapter;
-
-        private EnableAccessibilityController mEnableAccessibilityController;
-
-        private boolean mIntercepted;
-        private boolean mCancelOnUp;
-
-        public GlobalActionsDialog(Context context, AlertParams params) {
-            super(context, getDialogTheme(context));
-            mContext = context;
-            mAlert = new AlertController(mContext, this, getWindow());
-            mAdapter = (MyAdapter) params.mAdapter;
-            mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
-            params.apply(mAlert);
-        }
-
-        private static int getDialogTheme(Context context) {
-            TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
-                    outValue, true);
-            return outValue.resourceId;
-        }
-
-        @Override
-        protected void onStart() {
-            // If global accessibility gesture can be performed, we will take care
-            // of dismissing the dialog on touch outside. This is because the dialog
-            // is dismissed on the first down while the global gesture is a long press
-            // with two fingers anywhere on the screen.
-            if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
-                mEnableAccessibilityController = new EnableAccessibilityController(mContext,
-                        new Runnable() {
-                    @Override
-                    public void run() {
-                        dismiss();
-                    }
-                });
-                super.setCanceledOnTouchOutside(false);
-            } else {
-                mEnableAccessibilityController = null;
-                super.setCanceledOnTouchOutside(true);
-            }
-
-            super.onStart();
-        }
-
-        @Override
-        protected void onStop() {
-            if (mEnableAccessibilityController != null) {
-                mEnableAccessibilityController.onDestroy();
-            }
-            super.onStop();
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent event) {
-            if (mEnableAccessibilityController != null) {
-                final int action = event.getActionMasked();
-                if (action == MotionEvent.ACTION_DOWN) {
-                    View decor = getWindow().getDecorView();
-                    final int eventX = (int) event.getX();
-                    final int eventY = (int) event.getY();
-                    if (eventX < -mWindowTouchSlop
-                            || eventY < -mWindowTouchSlop
-                            || eventX >= decor.getWidth() + mWindowTouchSlop
-                            || eventY >= decor.getHeight() + mWindowTouchSlop) {
-                        mCancelOnUp = true;
-                    }
-                }
-                try {
-                    if (!mIntercepted) {
-                        mIntercepted = mEnableAccessibilityController.onInterceptTouchEvent(event);
-                        if (mIntercepted) {
-                            final long now = SystemClock.uptimeMillis();
-                            event = MotionEvent.obtain(now, now,
-                                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-                            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
-                            mCancelOnUp = true;
-                        }
-                    } else {
-                        return mEnableAccessibilityController.onTouchEvent(event);
-                    }
-                } finally {
-                    if (action == MotionEvent.ACTION_UP) {
-                        if (mCancelOnUp) {
-                            cancel();
-                        }
-                        mCancelOnUp = false;
-                        mIntercepted = false;
-                    }
-                }
-            }
-            return super.dispatchTouchEvent(event);
-        }
-
-        public ListView getListView() {
-            return mAlert.getListView();
-        }
-
-        @Override
-        protected void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mAlert.installContent();
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-                for (int i = 0; i < mAdapter.getCount(); ++i) {
-                    CharSequence label =
-                            mAdapter.getItem(i).getLabelForAccessibility(getContext());
-                    if (label != null) {
-                        event.getText().add(label);
-                    }
-                }
-            }
-            return super.dispatchPopulateAccessibilityEvent(event);
-        }
-
-        @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            if (mAlert.onKeyDown(keyCode, event)) {
-                return true;
-            }
-            return super.onKeyDown(keyCode, event);
-        }
-
-        @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            if (mAlert.onKeyUp(keyCode, event)) {
-                return true;
-            }
-            return super.onKeyUp(keyCode, event);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
deleted file mode 100644
index fc65793..0000000
--- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.policy.impl;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyEvent;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-/**
- * Stores a mapping of global keys.
- * <p>
- * A global key will NOT go to the foreground application and instead only ever be sent via targeted
- * broadcast to the specified component. The action of the intent will be
- * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with
- * {@link Intent#EXTRA_KEY_EVENT}.
- */
-final class GlobalKeyManager {
-
-    private static final String TAG = "GlobalKeyManager";
-
-    private static final String TAG_GLOBAL_KEYS = "global_keys";
-    private static final String ATTR_VERSION = "version";
-    private static final String TAG_KEY = "key";
-    private static final String ATTR_KEY_CODE = "keyCode";
-    private static final String ATTR_COMPONENT = "component";
-
-    private static final int GLOBAL_KEY_FILE_VERSION = 1;
-
-    private SparseArray<ComponentName> mKeyMapping;
-
-    public GlobalKeyManager(Context context) {
-        mKeyMapping = new SparseArray<ComponentName>();
-        loadGlobalKeys(context);
-    }
-
-    /**
-     * Broadcasts an intent if the keycode is part of the global key mapping.
-     *
-     * @param context context used to broadcast the event
-     * @param keyCode keyCode which triggered this function
-     * @param event keyEvent which trigged this function
-     * @return {@code true} if this was handled
-     */
-    boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
-        if (mKeyMapping.size() > 0) {
-            ComponentName component = mKeyMapping.get(keyCode);
-            if (component != null) {
-                Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
-                        .setComponent(component)
-                        .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(Intent.EXTRA_KEY_EVENT, event);
-                context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns {@code true} if the key will be handled globally.
-     */
-    boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) {
-        return mKeyMapping.get(keyCode) != null;
-    }
-
-    private void loadGlobalKeys(Context context) {
-        XmlResourceParser parser = null;
-        try {
-            parser = context.getResources().getXml(com.android.internal.R.xml.global_keys);
-            XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS);
-            int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
-            if (GLOBAL_KEY_FILE_VERSION == version) {
-                while (true) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (TAG_KEY.equals(element)) {
-                        String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
-                        String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
-                        int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
-                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
-                            mKeyMapping.put(keyCode, ComponentName.unflattenFromString(
-                                    componentName));
-                        }
-                    }
-                }
-            }
-        } catch (Resources.NotFoundException e) {
-            Log.w(TAG, "global keys file not found", e);
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "XML parser exception reading global keys file", e);
-        } catch (IOException e) {
-            Log.w(TAG, "I/O exception reading global keys file", e);
-        } finally {
-            if (parser != null) {
-                parser.close();
-            }
-        }
-    }
-
-    public void dump(String prefix, PrintWriter pw) {
-        final int numKeys = mKeyMapping.size();
-        if (numKeys == 0) {
-            pw.print(prefix); pw.println("mKeyMapping.size=0");
-            return;
-        }
-        pw.print(prefix); pw.println("mKeyMapping={");
-        for (int i = 0; i < numKeys; ++i) {
-            pw.print("  ");
-            pw.print(prefix);
-            pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i)));
-            pw.print("=");
-            pw.println(mKeyMapping.valueAt(i).flattenToString());
-        }
-        pw.print(prefix); pw.println("}");
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java
deleted file mode 100644
index 82f26ad..0000000
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.ColorMatrix;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.TableMaskFilter;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.content.res.Resources;
-import android.content.Context;
-
-/**
- * Various utilities shared amongst the Launcher's classes.
- */
-final class IconUtilities {
-    private static final String TAG = "IconUtilities";
-
-    private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
-
-    private int mIconWidth = -1;
-    private int mIconHeight = -1;
-    private int mIconTextureWidth = -1;
-    private int mIconTextureHeight = -1;
-
-    private final Paint mPaint = new Paint();
-    private final Paint mBlurPaint = new Paint();
-    private final Paint mGlowColorPressedPaint = new Paint();
-    private final Paint mGlowColorFocusedPaint = new Paint();
-    private final Rect mOldBounds = new Rect();
-    private final Canvas mCanvas = new Canvas();
-    private final DisplayMetrics mDisplayMetrics;
-
-    private int mColorIndex = 0;
-
-    public IconUtilities(Context context) {
-        final Resources resources = context.getResources();
-        DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics();
-        final float density = metrics.density;
-        final float blurPx = 5 * density;
-
-        mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
-        mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
-
-        mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
-
-        TypedValue value = new TypedValue();
-        mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
-                android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
-        mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-        mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
-                android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
-        mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-
-        ColorMatrix cm = new ColorMatrix();
-        cm.setSaturation(0.2f);
-
-        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
-                Paint.FILTER_BITMAP_FLAG));
-    }
-
-    public Drawable createIconDrawable(Drawable src) {
-        Bitmap scaled = createIconBitmap(src);
-
-        StateListDrawable result = new StateListDrawable();
-
-        result.addState(new int[] { android.R.attr.state_focused },
-                new BitmapDrawable(createSelectedBitmap(scaled, false)));
-        result.addState(new int[] { android.R.attr.state_pressed },
-                new BitmapDrawable(createSelectedBitmap(scaled, true)));
-        result.addState(new int[0], new BitmapDrawable(scaled));
-
-        result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight);
-        return result;
-    }
-
-    /**
-     * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
-     * of two sized ARGB_8888 bitmap that can be used as a gl texture.
-     */
-    private Bitmap createIconBitmap(Drawable icon) {
-        int width = mIconWidth;
-        int height = mIconHeight;
-
-        if (icon instanceof PaintDrawable) {
-            PaintDrawable painter = (PaintDrawable) icon;
-            painter.setIntrinsicWidth(width);
-            painter.setIntrinsicHeight(height);
-        } else if (icon instanceof BitmapDrawable) {
-            // Ensure the bitmap has a density.
-            BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
-            Bitmap bitmap = bitmapDrawable.getBitmap();
-            if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
-                bitmapDrawable.setTargetDensity(mDisplayMetrics);
-            }
-        }
-        int sourceWidth = icon.getIntrinsicWidth();
-        int sourceHeight = icon.getIntrinsicHeight();
-
-        if (sourceWidth > 0 && sourceHeight > 0) {
-            // There are intrinsic sizes.
-            if (width < sourceWidth || height < sourceHeight) {
-                // It's too big, scale it down.
-                final float ratio = (float) sourceWidth / sourceHeight;
-                if (sourceWidth > sourceHeight) {
-                    height = (int) (width / ratio);
-                } else if (sourceHeight > sourceWidth) {
-                    width = (int) (height * ratio);
-                }
-            } else if (sourceWidth < width && sourceHeight < height) {
-                // It's small, use the size they gave us.
-                width = sourceWidth;
-                height = sourceHeight;
-            }
-        }
-
-        // no intrinsic size --> use default size
-        int textureWidth = mIconTextureWidth;
-        int textureHeight = mIconTextureHeight;
-
-        final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
-                Bitmap.Config.ARGB_8888);
-        final Canvas canvas = mCanvas;
-        canvas.setBitmap(bitmap);
-
-        final int left = (textureWidth-width) / 2;
-        final int top = (textureHeight-height) / 2;
-
-        if (false) {
-            // draw a big box for the icon for debugging
-            canvas.drawColor(sColors[mColorIndex]);
-            if (++mColorIndex >= sColors.length) mColorIndex = 0;
-            Paint debugPaint = new Paint();
-            debugPaint.setColor(0xffcccc00);
-            canvas.drawRect(left, top, left+width, top+height, debugPaint);
-        }
-
-        mOldBounds.set(icon.getBounds());
-        icon.setBounds(left, top, left+width, top+height);
-        icon.draw(canvas);
-        icon.setBounds(mOldBounds);
-
-        return bitmap;
-    }
-
-    private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) {
-        final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight,
-                Bitmap.Config.ARGB_8888);
-        final Canvas dest = new Canvas(result);
-
-        dest.drawColor(0, PorterDuff.Mode.CLEAR);
-
-        int[] xy = new int[2];
-        Bitmap mask = src.extractAlpha(mBlurPaint, xy);
-
-        dest.drawBitmap(mask, xy[0], xy[1],
-                pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint);
-
-        mask.recycle();
-
-        dest.drawBitmap(src, 0, 0, mPaint);
-        dest.setBitmap(null);
-
-        return result;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
deleted file mode 100644
index 8fc4647..0000000
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ /dev/null
@@ -1,347 +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.internal.policy.impl;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.Button;
-import android.widget.FrameLayout;
-
-import com.android.internal.R;
-
-/**
- *  Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
- *  entering immersive mode.
- */
-public class ImmersiveModeConfirmation {
-    private static final String TAG = "ImmersiveModeConfirmation";
-    private static final boolean DEBUG = false;
-    private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
-    private static final String CONFIRMED = "confirmed";
-
-    private final Context mContext;
-    private final H mHandler;
-    private final long mShowDelayMs;
-    private final long mPanicThresholdMs;
-    private final SparseBooleanArray mUserPanicResets = new SparseBooleanArray();
-
-    private boolean mConfirmed;
-    private ClingWindowView mClingWindow;
-    private long mPanicTime;
-    private WindowManager mWindowManager;
-    private int mCurrentUserId;
-
-    public ImmersiveModeConfirmation(Context context) {
-        mContext = context;
-        mHandler = new H();
-        mShowDelayMs = getNavBarExitDuration() * 3;
-        mPanicThresholdMs = context.getResources()
-                .getInteger(R.integer.config_immersive_mode_confirmation_panic);
-        mWindowManager = (WindowManager)
-                mContext.getSystemService(Context.WINDOW_SERVICE);
-    }
-
-    private long getNavBarExitDuration() {
-        Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit);
-        return exit != null ? exit.getDuration() : 0;
-    }
-
-    public void loadSetting(int currentUserId) {
-        mConfirmed = false;
-        mCurrentUserId = currentUserId;
-        if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s",
-                mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false)));
-        String value = null;
-        try {
-            value = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
-                    UserHandle.USER_CURRENT);
-            mConfirmed = CONFIRMED.equals(value);
-            if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed);
-        } catch (Throwable t) {
-            Slog.w(TAG, "Error loading confirmations, value=" + value, t);
-        }
-    }
-
-    private void saveSetting() {
-        if (DEBUG) Slog.d(TAG, "saveSetting()");
-        try {
-            final String value = mConfirmed ? CONFIRMED : null;
-            Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
-                    value,
-                    UserHandle.USER_CURRENT);
-            if (DEBUG) Slog.d(TAG, "Saved value=" + value);
-        } catch (Throwable t) {
-            Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t);
-        }
-    }
-
-    public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
-            boolean userSetupComplete) {
-        mHandler.removeMessages(H.SHOW);
-        if (isImmersiveMode) {
-            final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
-            if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
-                    disabled, mConfirmed));
-            if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) {
-                mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
-            }
-        } else {
-            mHandler.sendEmptyMessage(H.HIDE);
-        }
-    }
-
-    public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
-        if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
-            // turning the screen back on within the panic threshold
-            mHandler.sendEmptyMessage(H.PANIC);
-            return mClingWindow == null;
-        }
-        if (isScreenOn && inImmersiveMode) {
-            // turning the screen off, remember if we were in immersive mode
-            mPanicTime = time;
-        } else {
-            mPanicTime = 0;
-        }
-        return false;
-    }
-
-    public void confirmCurrentPrompt() {
-        if (mClingWindow != null) {
-            if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()");
-            mHandler.post(mConfirm);
-        }
-    }
-
-    private void handlePanic() {
-        if (DEBUG) Slog.d(TAG, "handlePanic()");
-        if (mUserPanicResets.get(mCurrentUserId, false)) return;  // already reset for panic
-        mUserPanicResets.put(mCurrentUserId, true);
-        mConfirmed = false;
-        saveSetting();
-    }
-
-    private void handleHide() {
-        if (mClingWindow != null) {
-            if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
-            mWindowManager.removeView(mClingWindow);
-            mClingWindow = null;
-        }
-    }
-
-    public WindowManager.LayoutParams getClingWindowLayoutParams() {
-        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_TOAST,
-                0
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                ,
-                PixelFormat.TRANSLUCENT);
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        lp.setTitle("ImmersiveModeConfirmation");
-        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
-        lp.gravity = Gravity.FILL;
-        return lp;
-    }
-
-    public FrameLayout.LayoutParams getBubbleLayoutParams() {
-        return new FrameLayout.LayoutParams(
-                mContext.getResources().getDimensionPixelSize(
-                        R.dimen.immersive_mode_cling_width),
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
-    }
-
-    private class ClingWindowView extends FrameLayout {
-        private static final int BGCOLOR = 0x80000000;
-        private static final int OFFSET_DP = 48;
-
-        private final Runnable mConfirm;
-        private final ColorDrawable mColor = new ColorDrawable(0);
-        private ValueAnimator mColorAnim;
-        private ViewGroup mClingLayout;
-
-        private Runnable mUpdateLayoutRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if (mClingLayout != null && mClingLayout.getParent() != null) {
-                    mClingLayout.setLayoutParams(getBubbleLayoutParams());
-                }
-            }
-        };
-
-        private BroadcastReceiver mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                    post(mUpdateLayoutRunnable);
-                }
-            }
-        };
-
-        public ClingWindowView(Context context, Runnable confirm) {
-            super(context);
-            mConfirm = confirm;
-            setClickable(true);
-            setBackground(mColor);
-        }
-
-        @Override
-        public void onAttachedToWindow() {
-            super.onAttachedToWindow();
-
-            DisplayMetrics metrics = new DisplayMetrics();
-            mWindowManager.getDefaultDisplay().getMetrics(metrics);
-            float density = metrics.density;
-
-            // create the confirmation cling
-            mClingLayout = (ViewGroup)
-                    View.inflate(getContext(), R.layout.immersive_mode_cling, null);
-
-            final Button ok = (Button) mClingLayout.findViewById(R.id.ok);
-            ok.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    mConfirm.run();
-                }
-            });
-            addView(mClingLayout, getBubbleLayoutParams());
-
-            if (ActivityManager.isHighEndGfx()) {
-                final View bubble = mClingLayout.findViewById(R.id.text);
-                bubble.setAlpha(0f);
-                bubble.setTranslationY(-OFFSET_DP*density);
-                bubble.animate()
-                        .alpha(1f)
-                        .translationY(0)
-                        .setDuration(300)
-                        .setInterpolator(new DecelerateInterpolator())
-                        .start();
-
-                ok.setAlpha(0f);
-                ok.setTranslationY(-OFFSET_DP*density);
-                ok.animate().alpha(1f)
-                        .translationY(0)
-                        .setDuration(300)
-                        .setStartDelay(200)
-                        .setInterpolator(new DecelerateInterpolator())
-                        .start();
-
-                mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR);
-                mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        final int c = (Integer) animation.getAnimatedValue();
-                        mColor.setColor(c);
-                    }
-                });
-                mColorAnim.setDuration(1000);
-                mColorAnim.start();
-            } else {
-                mColor.setColor(BGCOLOR);
-            }
-
-            mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
-        }
-
-        @Override
-        public void onDetachedFromWindow() {
-            mContext.unregisterReceiver(mReceiver);
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent motion) {
-            return true;
-        }
-    }
-
-    private void handleShow() {
-        if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
-
-        mClingWindow = new ClingWindowView(mContext, mConfirm);
-
-        // we will be hiding the nav bar, so layout as if it's already hidden
-        mClingWindow.setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-              | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-
-        // show the confirmation
-        WindowManager.LayoutParams lp = getClingWindowLayoutParams();
-        mWindowManager.addView(mClingWindow, lp);
-    }
-
-    private final Runnable mConfirm = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Slog.d(TAG, "mConfirm.run()");
-            if (!mConfirmed) {
-                mConfirmed = true;
-                saveSetting();
-            }
-            handleHide();
-        }
-    };
-
-    private final class H extends Handler {
-        private static final int SHOW = 1;
-        private static final int HIDE = 2;
-        private static final int PANIC = 3;
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch(msg.what) {
-                case SHOW:
-                    handleShow();
-                    break;
-                case HIDE:
-                    handleHide();
-                    break;
-                case PANIC:
-                    handlePanic();
-                    break;
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java b/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
deleted file mode 100644
index 1f3e1de..0000000
--- a/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.internal.policy.impl;
-
-import android.view.animation.Interpolator;
-
-public class LogDecelerateInterpolator implements Interpolator {
-
-    private int mBase;
-    private int mDrift;
-    private final float mLogScale;
-
-    public LogDecelerateInterpolator(int base, int drift) {
-        mBase = base;
-        mDrift = drift;
-
-        mLogScale = 1f / computeLog(1, mBase, mDrift);
-    }
-
-    private static float computeLog(float t, int base, int drift) {
-        return (float) -Math.pow(base, -t) + 1 + (drift * t);
-    }
-
-    @Override
-    public float getInterpolation(float t) {
-        return computeLog(t, mBase, mDrift) * mLogScale;
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
deleted file mode 100644
index f291e89..0000000
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.KeyguardManager;
-import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.media.AudioManager;
-import android.media.IAudioService;
-import android.media.session.MediaSessionLegacyHelper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.Slog;
-import android.view.View;
-import android.view.HapticFeedbackConstants;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-
-public class PhoneFallbackEventHandler implements FallbackEventHandler {
-    private static String TAG = "PhoneFallbackEventHandler";
-    private static final boolean DEBUG = false;
-
-    Context mContext;
-    View mView;
-
-    AudioManager mAudioManager;
-    KeyguardManager mKeyguardManager;
-    SearchManager mSearchManager;
-    TelephonyManager mTelephonyManager;
-
-    public PhoneFallbackEventHandler(Context context) {
-        mContext = context;
-    }
-
-    public void setView(View v) {
-        mView = v;
-    }
-
-    public void preDispatchKeyEvent(KeyEvent event) {
-        getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
-    }
-
-    public boolean dispatchKeyEvent(KeyEvent event) {
-
-        final int action = event.getAction();
-        final int keyCode = event.getKeyCode();
-
-        if (action == KeyEvent.ACTION_DOWN) {
-            return onKeyDown(keyCode, event);
-        } else {
-            return onKeyUp(keyCode, event);
-        }
-    }
-
-    boolean onKeyDown(int keyCode, KeyEvent event) {
-        /* ****************************************************************************
-         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
-         * See the comment in PhoneWindow.onKeyDown
-         * ****************************************************************************/
-        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
-                return true;
-            }
-
-
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
-                 * to avoid music playback */
-                if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) {
-                    return true;  // suppress key event
-                }
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                handleMediaKeyEvent(event);
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_CALL: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
-                    break;
-                }
-                if (event.getRepeatCount() == 0) {
-                    dispatcher.startTracking(event, this);
-                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
-                    dispatcher.performedLongPress(event);
-                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    // launch the VoiceDialer
-                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        sendCloseSystemWindows();
-                        mContext.startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
-                        startCallActivity();
-                    }
-                }
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_CAMERA: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
-                    break;
-                }
-                if (event.getRepeatCount() == 0) {
-                    dispatcher.startTracking(event, this);
-                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
-                    dispatcher.performedLongPress(event);
-                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    sendCloseSystemWindows();
-                    // Broadcast an intent that the Camera button was longpressed
-                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
-                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
-                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
-                            null, null, null, 0, null, null);
-                }
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_SEARCH: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
-                    break;
-                }
-                if (event.getRepeatCount() == 0) {
-                    dispatcher.startTracking(event, this);
-                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
-                    Configuration config = mContext.getResources().getConfiguration();
-                    if (config.keyboard == Configuration.KEYBOARD_NOKEYS
-                            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
-                        // launch the search activity
-                        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
-                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                            sendCloseSystemWindows();
-                            getSearchManager().stopSearch();
-                            mContext.startActivity(intent);
-                            // Only clear this if we successfully start the
-                            // activity; otherwise we will allow the normal short
-                            // press action to be performed.
-                            dispatcher.performedLongPress(event);
-                            return true;
-                        } catch (ActivityNotFoundException e) {
-                            // Ignore
-                        }
-                    }
-                }
-                break;
-            }
-        }
-        return false;
-    }
-
-    boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (DEBUG) {
-            Slog.d(TAG, "up " + keyCode);
-        }
-        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
-        if (dispatcher != null) {
-            dispatcher.handleUpEvent(event);
-        }
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                if (!event.isCanceled()) {
-                    MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
-                }
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                handleMediaKeyEvent(event);
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_CAMERA: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
-                    break;
-                }
-                if (event.isTracking() && !event.isCanceled()) {
-                    // Add short press behavior here if desired
-                }
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_CALL: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
-                    break;
-                }
-                if (event.isTracking() && !event.isCanceled()) {
-                    startCallActivity();
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void startCallActivity() {
-        sendCloseSystemWindows();
-        Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        try {
-            mContext.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
-        }
-    }
-
-    SearchManager getSearchManager() {
-        if (mSearchManager == null) {
-            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        }
-        return mSearchManager;
-    }
-
-    TelephonyManager getTelephonyManager() {
-        if (mTelephonyManager == null) {
-            mTelephonyManager = (TelephonyManager)mContext.getSystemService(
-                    Context.TELEPHONY_SERVICE);
-        }
-        return mTelephonyManager;
-    }
-
-    KeyguardManager getKeyguardManager() {
-        if (mKeyguardManager == null) {
-            mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        }
-        return mKeyguardManager;
-    }
-
-    AudioManager getAudioManager() {
-        if (mAudioManager == null) {
-            mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
-        }
-        return mAudioManager;
-    }
-
-    void sendCloseSystemWindows() {
-        PhoneWindowManager.sendCloseSystemWindows(mContext, null);
-    }
-
-    private void handleMediaKeyEvent(KeyEvent keyEvent) {
-        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
deleted file mode 100644
index df6fca4c..0000000
--- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.policy.impl;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.LayoutInflater;
-
-public class PhoneLayoutInflater extends LayoutInflater {
-    private static final String[] sClassPrefixList = {
-        "android.widget.",
-        "android.webkit.",
-        "android.app."
-    };
-    
-    /**
-     * Instead of instantiating directly, you should retrieve an instance
-     * through {@link Context#getSystemService}
-     * 
-     * @param context The Context in which in which to find resources and other
-     *                application-specific things.
-     * 
-     * @see Context#getSystemService
-     */
-    public PhoneLayoutInflater(Context context) {
-        super(context);
-    }
-    
-    protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
-        super(original, newContext);
-    }
-    
-    /** Override onCreateView to instantiate names that correspond to the
-        widgets known to the Widget factory. If we don't find a match,
-        call through to our super class.
-    */
-    @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
-        for (String prefix : sClassPrefixList) {
-            try {
-                View view = createView(name, prefix, attrs);
-                if (view != null) {
-                    return view;
-                }
-            } catch (ClassNotFoundException e) {
-                // In this case we want to let the base class take a crack
-                // at it.
-            }
-        }
-
-        return super.onCreateView(name, attrs);
-    }
-    
-    public LayoutInflater cloneInContext(Context newContext) {
-        return new PhoneLayoutInflater(this, newContext);
-    }
-}
-
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
deleted file mode 100644
index b4811da..0000000
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ /dev/null
@@ -1,4780 +0,0 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.policy.impl;
-
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.getMode;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.*;
-
-import android.app.SearchManager;
-import android.os.UserHandle;
-import com.android.internal.R;
-import com.android.internal.view.RootViewSurfaceTaker;
-import com.android.internal.view.StandaloneActionMode;
-import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.IconMenuPresenter;
-import com.android.internal.view.menu.ListMenuPresenter;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuPresenter;
-import com.android.internal.view.menu.MenuView;
-import com.android.internal.widget.ActionBarContextView;
-import com.android.internal.widget.BackgroundFallback;
-import com.android.internal.widget.DecorContentParent;
-import com.android.internal.widget.SwipeDismissLayout;
-
-import android.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.session.MediaController;
-import android.media.session.MediaSessionLegacyHelper;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.transition.Scene;
-import android.transition.Transition;
-import android.transition.TransitionInflater;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.util.AndroidRuntimeException;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.TypedValue;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.InputEvent;
-import android.view.InputQueue;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.ViewParent;
-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;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * Android-specific Window.
- * <p>
- * todo: need to pull the generic functionality out into a base class
- * in android.widget.
- */
-public class PhoneWindow extends Window implements MenuBuilder.Callback {
-
-    private final static String TAG = "PhoneWindow";
-
-    private final static boolean SWEEP_OPEN_MENU = false;
-
-    private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
-
-    private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
-            (1 << FEATURE_CUSTOM_TITLE) |
-            (1 << FEATURE_CONTENT_TRANSITIONS) |
-            (1 << FEATURE_ACTIVITY_TRANSITIONS) |
-            (1 << FEATURE_ACTION_MODE_OVERLAY);
-
-    private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
-
-    /**
-     * Simple callback used by the context menu and its submenus. The options
-     * menu submenus do not use this (their behavior is more complex).
-     */
-    final DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU);
-
-    final TypedValue mMinWidthMajor = new TypedValue();
-    final TypedValue mMinWidthMinor = new TypedValue();
-    TypedValue mFixedWidthMajor;
-    TypedValue mFixedWidthMinor;
-    TypedValue mFixedHeightMajor;
-    TypedValue mFixedHeightMinor;
-    TypedValue mOutsetBottom;
-
-    // This is the top-level view of the window, containing the window decor.
-    private DecorView mDecor;
-
-    // This is the view in which the window contents are placed. It is either
-    // mDecor itself, or a child of mDecor where the contents go.
-    private ViewGroup mContentParent;
-
-    private ViewGroup mContentRoot;
-
-    SurfaceHolder.Callback2 mTakeSurfaceCallback;
-
-    InputQueue.Callback mTakeInputQueueCallback;
-
-    private boolean mIsFloating;
-
-    private LayoutInflater mLayoutInflater;
-
-    private TextView mTitleView;
-
-    private DecorContentParent mDecorContentParent;
-    private ActionMenuPresenterCallback mActionMenuPresenterCallback;
-    private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
-
-    private TransitionManager mTransitionManager;
-    private Scene mContentScene;
-
-    // The icon resource has been explicitly set elsewhere
-    // and should not be overwritten with a default.
-    static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
-
-    // The logo resource has been explicitly set elsewhere
-    // and should not be overwritten with a default.
-    static final int FLAG_RESOURCE_SET_LOGO = 1 << 1;
-
-    // The icon resource is currently configured to use the system fallback
-    // as no default was previously specified. Anything can override this.
-    static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2;
-
-    int mResourcesSetFlags;
-    int mIconRes;
-    int mLogoRes;
-
-    private DrawableFeatureState[] mDrawables;
-
-    private PanelFeatureState[] mPanels;
-
-    /**
-     * The panel that is prepared or opened (the most recent one if there are
-     * multiple panels). Shortcuts will go to this panel. It gets set in
-     * {@link #preparePanel} and cleared in {@link #closePanel}.
-     */
-    private PanelFeatureState mPreparedPanel;
-
-    /**
-     * The keycode that is currently held down (as a modifier) for chording. If
-     * this is 0, there is no key held down.
-     */
-    private int mPanelChordingKey;
-
-    private ImageView mLeftIconView;
-
-    private ImageView mRightIconView;
-
-    private ProgressBar mCircularProgressBar;
-
-    private ProgressBar mHorizontalProgressBar;
-
-    private int mBackgroundResource = 0;
-    private int mBackgroundFallbackResource = 0;
-
-    private Drawable mBackgroundDrawable;
-
-    private float mElevation;
-
-    /** Whether window content should be clipped to the background outline. */
-    private boolean mClipToOutline;
-
-    private int mFrameResource = 0;
-
-    private int mTextColor = 0;
-    private int mStatusBarColor = 0;
-    private int mNavigationBarColor = 0;
-    private boolean mForcedStatusBarColor = false;
-    private boolean mForcedNavigationBarColor = false;
-
-    private CharSequence mTitle = null;
-
-    private int mTitleColor = 0;
-
-    private boolean mAlwaysReadCloseOnTouchAttr = false;
-
-    private ContextMenuBuilder mContextMenu;
-    private MenuDialogHelper mContextMenuHelper;
-    private boolean mClosingActionMenu;
-
-    private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
-    private MediaController mMediaController;
-
-    private AudioManager mAudioManager;
-    private KeyguardManager mKeyguardManager;
-
-    private int mUiOptions = 0;
-
-    private boolean mInvalidatePanelMenuPosted;
-    private int mInvalidatePanelMenuFeatures;
-    private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
-        @Override public void run() {
-            for (int i = 0; i <= FEATURE_MAX; i++) {
-                if ((mInvalidatePanelMenuFeatures & 1 << i) != 0) {
-                    doInvalidatePanelMenu(i);
-                }
-            }
-            mInvalidatePanelMenuPosted = false;
-            mInvalidatePanelMenuFeatures = 0;
-        }
-    };
-
-    private Transition mEnterTransition = null;
-    private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
-    private Transition mExitTransition = null;
-    private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
-    private Transition mSharedElementEnterTransition = null;
-    private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
-    private Transition mSharedElementExitTransition = null;
-    private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION;
-    private Boolean mAllowReturnTransitionOverlap;
-    private Boolean mAllowEnterTransitionOverlap;
-    private long mBackgroundFadeDurationMillis = -1;
-    private Boolean mSharedElementsUseOverlay;
-
-    private Rect mTempRect;
-
-    static class WindowManagerHolder {
-        static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService("window"));
-    }
-
-    static final RotationWatcher sRotationWatcher = new RotationWatcher();
-
-    public PhoneWindow(Context context) {
-        super(context);
-        mLayoutInflater = LayoutInflater.from(context);
-    }
-
-    @Override
-    public final void setContainer(Window container) {
-        super.setContainer(container);
-    }
-
-    @Override
-    public boolean requestFeature(int featureId) {
-        if (mContentParent != null) {
-            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
-        }
-        final int features = getFeatures();
-        final int newFeatures = features | (1 << featureId);
-        if ((newFeatures & (1 << FEATURE_CUSTOM_TITLE)) != 0 &&
-                (newFeatures & ~CUSTOM_TITLE_COMPATIBLE_FEATURES) != 0) {
-            // Another feature is enabled and the user is trying to enable the custom title feature
-            // or custom title feature is enabled and the user is trying to enable another feature
-            throw new AndroidRuntimeException(
-                    "You cannot combine custom titles with other title features");
-        }
-        if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) {
-            return false; // Ignore. No title dominates.
-        }
-        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_NO_TITLE) {
-            // Remove the action bar feature if we have no title. No title dominates.
-            removeFeature(FEATURE_ACTION_BAR);
-        }
-
-        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
-            throw new AndroidRuntimeException(
-                    "You cannot combine swipe dismissal and the action bar.");
-        }
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
-            throw new AndroidRuntimeException(
-                    "You cannot combine swipe dismissal and the action bar.");
-        }
-
-        if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
-                getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
-        }
-        return super.requestFeature(featureId);
-    }
-
-    @Override
-    public void setUiOptions(int uiOptions) {
-        mUiOptions = uiOptions;
-    }
-
-    @Override
-    public void setUiOptions(int uiOptions, int mask) {
-        mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
-    }
-
-    @Override
-    public TransitionManager getTransitionManager() {
-        return mTransitionManager;
-    }
-
-    @Override
-    public void setTransitionManager(TransitionManager tm) {
-        mTransitionManager = tm;
-    }
-
-    @Override
-    public Scene getContentScene() {
-        return mContentScene;
-    }
-
-    @Override
-    public void setContentView(int layoutResID) {
-        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
-        // decor, when theme attributes and the like are crystalized. Do not check the feature
-        // before this happens.
-        if (mContentParent == null) {
-            installDecor();
-        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
-            mContentParent.removeAllViews();
-        }
-
-        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
-            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
-                    getContext());
-            transitionTo(newScene);
-        } else {
-            mLayoutInflater.inflate(layoutResID, mContentParent);
-        }
-        final Callback cb = getCallback();
-        if (cb != null && !isDestroyed()) {
-            cb.onContentChanged();
-        }
-    }
-
-    @Override
-    public void setContentView(View view) {
-        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-    }
-
-    @Override
-    public void setContentView(View view, ViewGroup.LayoutParams params) {
-        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
-        // decor, when theme attributes and the like are crystalized. Do not check the feature
-        // before this happens.
-        if (mContentParent == null) {
-            installDecor();
-        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
-            mContentParent.removeAllViews();
-        }
-
-        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
-            view.setLayoutParams(params);
-            final Scene newScene = new Scene(mContentParent, view);
-            transitionTo(newScene);
-        } else {
-            mContentParent.addView(view, params);
-        }
-        final Callback cb = getCallback();
-        if (cb != null && !isDestroyed()) {
-            cb.onContentChanged();
-        }
-    }
-
-    @Override
-    public void addContentView(View view, ViewGroup.LayoutParams params) {
-        if (mContentParent == null) {
-            installDecor();
-        }
-        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
-            // TODO Augment the scenes/transitions API to support this.
-            Log.v(TAG, "addContentView does not support content transitions");
-        }
-        mContentParent.addView(view, params);
-        final Callback cb = getCallback();
-        if (cb != null && !isDestroyed()) {
-            cb.onContentChanged();
-        }
-    }
-
-    private void transitionTo(Scene scene) {
-        if (mContentScene == null) {
-            scene.enter();
-        } else {
-            mTransitionManager.transitionTo(scene);
-        }
-        mContentScene = scene;
-    }
-
-    @Override
-    public View getCurrentFocus() {
-        return mDecor != null ? mDecor.findFocus() : null;
-    }
-
-    @Override
-    public void takeSurface(SurfaceHolder.Callback2 callback) {
-        mTakeSurfaceCallback = callback;
-    }
-
-    public void takeInputQueue(InputQueue.Callback callback) {
-        mTakeInputQueueCallback = callback;
-    }
-
-    @Override
-    public boolean isFloating() {
-        return mIsFloating;
-    }
-
-    /**
-     * Return a LayoutInflater instance that can be used to inflate XML view layout
-     * resources for use in this Window.
-     *
-     * @return LayoutInflater The shared LayoutInflater.
-     */
-    @Override
-    public LayoutInflater getLayoutInflater() {
-        return mLayoutInflater;
-    }
-
-    @Override
-    public void setTitle(CharSequence title) {
-        if (mTitleView != null) {
-            mTitleView.setText(title);
-        } else if (mDecorContentParent != null) {
-            mDecorContentParent.setWindowTitle(title);
-        }
-        mTitle = title;
-    }
-
-    @Override
-    @Deprecated
-    public void setTitleColor(int textColor) {
-        if (mTitleView != null) {
-            mTitleView.setTextColor(textColor);
-        }
-        mTitleColor = textColor;
-    }
-
-    /**
-     * Prepares the panel to either be opened or chorded. This creates the Menu
-     * instance for the panel and populates it via the Activity callbacks.
-     *
-     * @param st The panel state to prepare.
-     * @param event The event that triggered the preparing of the panel.
-     * @return Whether the panel was prepared. If the panel should not be shown,
-     *         returns false.
-     */
-    public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
-        if (isDestroyed()) {
-            return false;
-        }
-
-        // Already prepared (isPrepared will be reset to false later)
-        if (st.isPrepared) {
-            return true;
-        }
-
-        if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
-            // Another Panel is prepared and possibly open, so close it
-            closePanel(mPreparedPanel, false);
-        }
-
-        final Callback cb = getCallback();
-
-        if (cb != null) {
-            st.createdPanelView = cb.onCreatePanelView(st.featureId);
-        }
-
-        final boolean isActionBarMenu =
-                (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
-
-        if (isActionBarMenu && mDecorContentParent != null) {
-            // Enforce ordering guarantees around events so that the action bar never
-            // dispatches menu-related events before the panel is prepared.
-            mDecorContentParent.setMenuPrepared();
-        }
-
-        if (st.createdPanelView == null) {
-            // Init the panel state's menu--return false if init failed
-            if (st.menu == null || st.refreshMenuContent) {
-                if (st.menu == null) {
-                    if (!initializePanelMenu(st) || (st.menu == null)) {
-                        return false;
-                    }
-                }
-
-                if (isActionBarMenu && mDecorContentParent != null) {
-                    if (mActionMenuPresenterCallback == null) {
-                        mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
-                    }
-                    mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
-                }
-
-                // Call callback, and return if it doesn't want to display menu.
-
-                // Creating the panel menu will involve a lot of manipulation;
-                // don't dispatch change events to presenters until we're done.
-                st.menu.stopDispatchingItemsChanged();
-                if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
-                    // Ditch the menu created above
-                    st.setMenu(null);
-
-                    if (isActionBarMenu && mDecorContentParent != null) {
-                        // Don't show it in the action bar either
-                        mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
-                    }
-
-                    return false;
-                }
-
-                st.refreshMenuContent = false;
-            }
-
-            // Callback and return if the callback does not want to show the menu
-
-            // Preparing the panel menu can involve a lot of manipulation;
-            // don't dispatch change events to presenters until we're done.
-            st.menu.stopDispatchingItemsChanged();
-
-            // Restore action view state before we prepare. This gives apps
-            // an opportunity to override frozen/restored state in onPrepare.
-            if (st.frozenActionViewState != null) {
-                st.menu.restoreActionViewStates(st.frozenActionViewState);
-                st.frozenActionViewState = null;
-            }
-
-            if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
-                if (isActionBarMenu && mDecorContentParent != null) {
-                    // The app didn't want to show the menu for now but it still exists.
-                    // Clear it out of the action bar.
-                    mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
-                }
-                st.menu.startDispatchingItemsChanged();
-                return false;
-            }
-
-            // Set the proper keymap
-            KeyCharacterMap kmap = KeyCharacterMap.load(
-                    event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
-            st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
-            st.menu.setQwertyMode(st.qwertyMode);
-            st.menu.startDispatchingItemsChanged();
-        }
-
-        // Set other state
-        st.isPrepared = true;
-        st.isHandled = false;
-        mPreparedPanel = st;
-
-        return true;
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        // Action bars handle their own menu state
-        if (mDecorContentParent == null) {
-            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-            if ((st != null) && (st.menu != null)) {
-                if (st.isOpen) {
-                    // Freeze state
-                    final Bundle state = new Bundle();
-                    if (st.iconMenuPresenter != null) {
-                        st.iconMenuPresenter.saveHierarchyState(state);
-                    }
-                    if (st.listMenuPresenter != null) {
-                        st.listMenuPresenter.saveHierarchyState(state);
-                    }
-
-                    // Remove the menu views since they need to be recreated
-                    // according to the new configuration
-                    clearMenuViews(st);
-
-                    // Re-open the same menu
-                    reopenMenu(false);
-
-                    // Restore state
-                    if (st.iconMenuPresenter != null) {
-                        st.iconMenuPresenter.restoreHierarchyState(state);
-                    }
-                    if (st.listMenuPresenter != null) {
-                        st.listMenuPresenter.restoreHierarchyState(state);
-                    }
-
-                } else {
-                    // Clear menu views so on next menu opening, it will use
-                    // the proper layout
-                    clearMenuViews(st);
-                }
-            }
-        }
-    }
-
-    private static void clearMenuViews(PanelFeatureState st) {
-        // This can be called on config changes, so we should make sure
-        // the views will be reconstructed based on the new orientation, etc.
-
-        // Allow the callback to create a new panel view
-        st.createdPanelView = null;
-
-        // Causes the decor view to be recreated
-        st.refreshDecorView = true;
-
-        st.clearMenuPresenters();
-    }
-
-    @Override
-    public final void openPanel(int featureId, KeyEvent event) {
-        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
-                mDecorContentParent.canShowOverflowMenu() &&
-                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-            mDecorContentParent.showOverflowMenu();
-        } else {
-            openPanel(getPanelState(featureId, true), event);
-        }
-    }
-
-    private void openPanel(final PanelFeatureState st, KeyEvent event) {
-        // System.out.println("Open panel: isOpen=" + st.isOpen);
-
-        // Already open, return
-        if (st.isOpen || isDestroyed()) {
-            return;
-        }
-
-        // Don't open an options panel for honeycomb apps on xlarge devices.
-        // (The app should be using an action bar for menu items.)
-        if (st.featureId == FEATURE_OPTIONS_PANEL) {
-            Context context = getContext();
-            Configuration config = context.getResources().getConfiguration();
-            boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) ==
-                    Configuration.SCREENLAYOUT_SIZE_XLARGE;
-            boolean isHoneycombApp = context.getApplicationInfo().targetSdkVersion >=
-                    android.os.Build.VERSION_CODES.HONEYCOMB;
-
-            if (isXLarge && isHoneycombApp) {
-                return;
-            }
-        }
-
-        Callback cb = getCallback();
-        if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
-            // Callback doesn't want the menu to open, reset any state
-            closePanel(st, true);
-            return;
-        }
-
-        final WindowManager wm = getWindowManager();
-        if (wm == null) {
-            return;
-        }
-
-        // Prepare panel (should have been done before, but just in case)
-        if (!preparePanel(st, event)) {
-            return;
-        }
-
-        int width = WRAP_CONTENT;
-        if (st.decorView == null || st.refreshDecorView) {
-            if (st.decorView == null) {
-                // Initialize the panel decor, this will populate st.decorView
-                if (!initializePanelDecor(st) || (st.decorView == null))
-                    return;
-            } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
-                // Decor needs refreshing, so remove its views
-                st.decorView.removeAllViews();
-            }
-
-            // This will populate st.shownPanelView
-            if (!initializePanelContent(st) || !st.hasPanelItems()) {
-                return;
-            }
-
-            ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
-            if (lp == null) {
-                lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-            }
-
-            int backgroundResId;
-            if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
-                // If the contents is fill parent for the width, set the
-                // corresponding background
-                backgroundResId = st.fullBackground;
-                width = MATCH_PARENT;
-            } else {
-                // Otherwise, set the normal panel background
-                backgroundResId = st.background;
-            }
-            st.decorView.setWindowBackground(getContext().getDrawable(
-                    backgroundResId));
-
-            ViewParent shownPanelParent = st.shownPanelView.getParent();
-            if (shownPanelParent != null && shownPanelParent instanceof ViewGroup) {
-                ((ViewGroup) shownPanelParent).removeView(st.shownPanelView);
-            }
-            st.decorView.addView(st.shownPanelView, lp);
-
-            /*
-             * Give focus to the view, if it or one of its children does not
-             * already have it.
-             */
-            if (!st.shownPanelView.hasFocus()) {
-                st.shownPanelView.requestFocus();
-            }
-        } else if (!st.isInListMode()) {
-            width = MATCH_PARENT;
-        } else if (st.createdPanelView != null) {
-            // If we already had a panel view, carry width=MATCH_PARENT through
-            // as we did above when it was created.
-            ViewGroup.LayoutParams lp = st.createdPanelView.getLayoutParams();
-            if (lp != null && lp.width == ViewGroup.LayoutParams.MATCH_PARENT) {
-                width = MATCH_PARENT;
-            }
-        }
-
-        st.isHandled = false;
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                width, WRAP_CONTENT,
-                st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
-                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                st.decorView.mDefaultOpacity);
-
-        if (st.isCompact) {
-            lp.gravity = getOptionsPanelGravity();
-            sRotationWatcher.addWindow(this);
-        } else {
-            lp.gravity = st.gravity;
-        }
-
-        lp.windowAnimations = st.windowAnimations;
-
-        wm.addView(st.decorView, lp);
-        st.isOpen = true;
-        // Log.v(TAG, "Adding main menu to window manager.");
-    }
-
-    @Override
-    public final void closePanel(int featureId) {
-        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
-                mDecorContentParent.canShowOverflowMenu() &&
-                !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-            mDecorContentParent.hideOverflowMenu();
-        } else if (featureId == FEATURE_CONTEXT_MENU) {
-            closeContextMenu();
-        } else {
-            closePanel(getPanelState(featureId, true), true);
-        }
-    }
-
-    /**
-     * Closes the given panel.
-     *
-     * @param st The panel to be closed.
-     * @param doCallback Whether to notify the callback that the panel was
-     *            closed. If the panel is in the process of re-opening or
-     *            opening another panel (e.g., menu opening a sub menu), the
-     *            callback should not happen and this variable should be false.
-     *            In addition, this method internally will only perform the
-     *            callback if the panel is open.
-     */
-    public final void closePanel(PanelFeatureState st, boolean doCallback) {
-        // System.out.println("Close panel: isOpen=" + st.isOpen);
-        if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
-                mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
-            checkCloseActionMenu(st.menu);
-            return;
-        }
-
-        final ViewManager wm = getWindowManager();
-        if ((wm != null) && st.isOpen) {
-            if (st.decorView != null) {
-                wm.removeView(st.decorView);
-                // Log.v(TAG, "Removing main menu from window manager.");
-                if (st.isCompact) {
-                    sRotationWatcher.removeWindow(this);
-                }
-            }
-
-            if (doCallback) {
-                callOnPanelClosed(st.featureId, st, null);
-            }
-        }
-
-        st.isPrepared = false;
-        st.isHandled = false;
-        st.isOpen = false;
-
-        // This view is no longer shown, so null it out
-        st.shownPanelView = null;
-
-        if (st.isInExpandedMode) {
-            // Next time the menu opens, it should not be in expanded mode, so
-            // force a refresh of the decor
-            st.refreshDecorView = true;
-            st.isInExpandedMode = false;
-        }
-
-        if (mPreparedPanel == st) {
-            mPreparedPanel = null;
-            mPanelChordingKey = 0;
-        }
-    }
-
-    void checkCloseActionMenu(Menu menu) {
-        if (mClosingActionMenu) {
-            return;
-        }
-
-        mClosingActionMenu = true;
-        mDecorContentParent.dismissPopups();
-        Callback cb = getCallback();
-        if (cb != null && !isDestroyed()) {
-            cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
-        }
-        mClosingActionMenu = false;
-    }
-
-    @Override
-    public final void togglePanel(int featureId, KeyEvent event) {
-        PanelFeatureState st = getPanelState(featureId, true);
-        if (st.isOpen) {
-            closePanel(st, true);
-        } else {
-            openPanel(st, event);
-        }
-    }
-
-    @Override
-    public void invalidatePanelMenu(int featureId) {
-        mInvalidatePanelMenuFeatures |= 1 << featureId;
-
-        if (!mInvalidatePanelMenuPosted && mDecor != null) {
-            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
-            mInvalidatePanelMenuPosted = true;
-        }
-    }
-
-    void doPendingInvalidatePanelMenu() {
-        if (mInvalidatePanelMenuPosted) {
-            mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
-            mInvalidatePanelMenuRunnable.run();
-        }
-    }
-
-    void doInvalidatePanelMenu(int featureId) {
-        PanelFeatureState st = getPanelState(featureId, false);
-        if (st == null) {
-            return;
-        }
-        Bundle savedActionViewStates = null;
-        if (st.menu != null) {
-            savedActionViewStates = new Bundle();
-            st.menu.saveActionViewStates(savedActionViewStates);
-            if (savedActionViewStates.size() > 0) {
-                st.frozenActionViewState = savedActionViewStates;
-            }
-            // This will be started again when the panel is prepared.
-            st.menu.stopDispatchingItemsChanged();
-            st.menu.clear();
-        }
-        st.refreshMenuContent = true;
-        st.refreshDecorView = true;
-
-        // Prepare the options panel if we have an action bar
-        if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
-                && mDecorContentParent != null) {
-            st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
-            if (st != null) {
-                st.isPrepared = false;
-                preparePanel(st, null);
-            }
-        }
-    }
-
-    /**
-     * Called when the panel key is pushed down.
-     * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
-     * @param event The key event.
-     * @return Whether the key was handled.
-     */
-    public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
-        final int keyCode = event.getKeyCode();
-
-        if (event.getRepeatCount() == 0) {
-            // The panel key was pushed, so set the chording key
-            mPanelChordingKey = keyCode;
-
-            PanelFeatureState st = getPanelState(featureId, false);
-            if (st != null && !st.isOpen) {
-                return preparePanel(st, event);
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Called when the panel key is released.
-     * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
-     * @param event The key event.
-     */
-    public final void onKeyUpPanel(int featureId, KeyEvent event) {
-        // The panel key was released, so clear the chording key
-        if (mPanelChordingKey != 0) {
-            mPanelChordingKey = 0;
-
-            final PanelFeatureState st = getPanelState(featureId, false);
-
-            if (event.isCanceled() || (mDecor != null && mDecor.mActionMode != null) ||
-                    (st == null)) {
-                return;
-            }
-
-            boolean playSoundEffect = false;
-            if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
-                    mDecorContentParent.canShowOverflowMenu() &&
-                    !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-                if (!mDecorContentParent.isOverflowMenuShowing()) {
-                    if (!isDestroyed() && preparePanel(st, event)) {
-                        playSoundEffect = mDecorContentParent.showOverflowMenu();
-                    }
-                } else {
-                    playSoundEffect = mDecorContentParent.hideOverflowMenu();
-                }
-            } else {
-                if (st.isOpen || st.isHandled) {
-
-                    // Play the sound effect if the user closed an open menu (and not if
-                    // they just released a menu shortcut)
-                    playSoundEffect = st.isOpen;
-
-                    // Close menu
-                    closePanel(st, true);
-
-                } else if (st.isPrepared) {
-                    boolean show = true;
-                    if (st.refreshMenuContent) {
-                        // Something may have invalidated the menu since we prepared it.
-                        // Re-prepare it to refresh.
-                        st.isPrepared = false;
-                        show = preparePanel(st, event);
-                    }
-
-                    if (show) {
-                        // Write 'menu opened' to event log
-                        EventLog.writeEvent(50001, 0);
-
-                        // Show menu
-                        openPanel(st, event);
-
-                        playSoundEffect = true;
-                    }
-                }
-            }
-
-            if (playSoundEffect) {
-                AudioManager audioManager = (AudioManager) getContext().getSystemService(
-                        Context.AUDIO_SERVICE);
-                if (audioManager != null) {
-                    audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
-                } else {
-                    Log.w(TAG, "Couldn't get audio manager");
-                }
-            }
-        }
-    }
-
-    @Override
-    public final void closeAllPanels() {
-        final ViewManager wm = getWindowManager();
-        if (wm == null) {
-            return;
-        }
-
-        final PanelFeatureState[] panels = mPanels;
-        final int N = panels != null ? panels.length : 0;
-        for (int i = 0; i < N; i++) {
-            final PanelFeatureState panel = panels[i];
-            if (panel != null) {
-                closePanel(panel, true);
-            }
-        }
-
-        closeContextMenu();
-    }
-
-    /**
-     * Closes the context menu. This notifies the menu logic of the close, along
-     * with dismissing it from the UI.
-     */
-    private synchronized void closeContextMenu() {
-        if (mContextMenu != null) {
-            mContextMenu.close();
-            dismissContextMenu();
-        }
-    }
-
-    /**
-     * Dismisses just the context menu UI. To close the context menu, use
-     * {@link #closeContextMenu()}.
-     */
-    private synchronized void dismissContextMenu() {
-        mContextMenu = null;
-
-        if (mContextMenuHelper != null) {
-            mContextMenuHelper.dismiss();
-            mContextMenuHelper = null;
-        }
-    }
-
-    @Override
-    public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
-        return performPanelShortcut(getPanelState(featureId, false), keyCode, event, flags);
-    }
-
-    private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
-            int flags) {
-        if (event.isSystem() || (st == null)) {
-            return false;
-        }
-
-        boolean handled = false;
-
-        // Only try to perform menu shortcuts if preparePanel returned true (possible false
-        // return value from application not wanting to show the menu).
-        if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
-            // The menu is prepared now, perform the shortcut on it
-            handled = st.menu.performShortcut(keyCode, event, flags);
-        }
-
-        if (handled) {
-            // Mark as handled
-            st.isHandled = true;
-
-            // Only close down the menu if we don't have an action bar keeping it open.
-            if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
-                closePanel(st, true);
-            }
-        }
-
-        return handled;
-    }
-
-    @Override
-    public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
-
-        PanelFeatureState st = getPanelState(featureId, true);
-        if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
-            return false;
-        }
-        if (st.menu == null) {
-            return false;
-        }
-
-        boolean res = st.menu.performIdentifierAction(id, flags);
-
-        // Only close down the menu if we don't have an action bar keeping it open.
-        if (mDecorContentParent == null) {
-            closePanel(st, true);
-        }
-
-        return res;
-    }
-
-    public PanelFeatureState findMenuPanel(Menu menu) {
-        final PanelFeatureState[] panels = mPanels;
-        final int N = panels != null ? panels.length : 0;
-        for (int i = 0; i < N; i++) {
-            final PanelFeatureState panel = panels[i];
-            if (panel != null && panel.menu == menu) {
-                return panel;
-            }
-        }
-        return null;
-    }
-
-    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-        final Callback cb = getCallback();
-        if (cb != null && !isDestroyed()) {
-            final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
-            if (panel != null) {
-                return cb.onMenuItemSelected(panel.featureId, item);
-            }
-        }
-        return false;
-    }
-
-    public void onMenuModeChange(MenuBuilder menu) {
-        reopenMenu(true);
-    }
-
-    private void reopenMenu(boolean toggleMenuMode) {
-        if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
-                (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
-                        mDecorContentParent.isOverflowMenuShowPending())) {
-            final Callback cb = getCallback();
-            if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
-                if (cb != null && !isDestroyed()) {
-                    // If we have a menu invalidation pending, do it now.
-                    if (mInvalidatePanelMenuPosted &&
-                            (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
-                        mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
-                        mInvalidatePanelMenuRunnable.run();
-                    }
-
-                    final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-
-                    // If we don't have a menu or we're waiting for a full content refresh,
-                    // forget it. This is a lingering event that no longer matters.
-                    if (st != null && st.menu != null && !st.refreshMenuContent &&
-                            cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
-                        cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
-                        mDecorContentParent.showOverflowMenu();
-                    }
-                }
-            } else {
-                mDecorContentParent.hideOverflowMenu();
-                final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-                if (st != null && cb != null && !isDestroyed()) {
-                    cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
-                }
-            }
-            return;
-        }
-
-        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-
-        if (st == null) {
-            return;
-        }
-
-        // Save the future expanded mode state since closePanel will reset it
-        boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
-
-        st.refreshDecorView = true;
-        closePanel(st, false);
-
-        // Set the expanded mode state
-        st.isInExpandedMode = newExpandedMode;
-
-        openPanel(st, null);
-    }
-
-    /**
-     * Initializes the menu associated with the given panel feature state. You
-     * must at the very least set PanelFeatureState.menu to the Menu to be
-     * associated with the given panel state. The default implementation creates
-     * a new menu for the panel state.
-     *
-     * @param st The panel whose menu is being initialized.
-     * @return Whether the initialization was successful.
-     */
-    protected boolean initializePanelMenu(final PanelFeatureState st) {
-        Context context = getContext();
-
-        // If we have an action bar, initialize the menu with the right theme.
-        if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
-                mDecorContentParent != null) {
-            final TypedValue outValue = new TypedValue();
-            final Theme baseTheme = context.getTheme();
-            baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
-
-            Theme widgetTheme = null;
-            if (outValue.resourceId != 0) {
-                widgetTheme = context.getResources().newTheme();
-                widgetTheme.setTo(baseTheme);
-                widgetTheme.applyStyle(outValue.resourceId, true);
-                widgetTheme.resolveAttribute(
-                        R.attr.actionBarWidgetTheme, outValue, true);
-            } else {
-                baseTheme.resolveAttribute(
-                        R.attr.actionBarWidgetTheme, outValue, true);
-            }
-
-            if (outValue.resourceId != 0) {
-                if (widgetTheme == null) {
-                    widgetTheme = context.getResources().newTheme();
-                    widgetTheme.setTo(baseTheme);
-                }
-                widgetTheme.applyStyle(outValue.resourceId, true);
-            }
-
-            if (widgetTheme != null) {
-                context = new ContextThemeWrapper(context, 0);
-                context.getTheme().setTo(widgetTheme);
-            }
-        }
-
-        final MenuBuilder menu = new MenuBuilder(context);
-        menu.setCallback(this);
-        st.setMenu(menu);
-
-        return true;
-    }
-
-    /**
-     * Perform initial setup of a panel. This should at the very least set the
-     * style information in the PanelFeatureState and must set
-     * PanelFeatureState.decor to the panel's window decor view.
-     *
-     * @param st The panel being initialized.
-     */
-    protected boolean initializePanelDecor(PanelFeatureState st) {
-        st.decorView = new DecorView(getContext(), st.featureId);
-        st.gravity = Gravity.CENTER | Gravity.BOTTOM;
-        st.setStyle(getContext());
-        TypedArray a = getContext().obtainStyledAttributes(null,
-                R.styleable.Window, 0, st.listPresenterTheme);
-        final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
-        if (elevation != 0) {
-            st.decorView.setElevation(elevation);
-        }
-        a.recycle();
-
-        return true;
-    }
-
-    /**
-     * Determine the gravity value for the options panel. This can
-     * differ in compact mode.
-     *
-     * @return gravity value to use for the panel window
-     */
-    private int getOptionsPanelGravity() {
-        try {
-            return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity();
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
-            return Gravity.CENTER | Gravity.BOTTOM;
-        }
-    }
-
-    void onOptionsPanelRotationChanged() {
-        final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-        if (st == null) return;
-
-        final WindowManager.LayoutParams lp = st.decorView != null ?
-                (WindowManager.LayoutParams) st.decorView.getLayoutParams() : null;
-        if (lp != null) {
-            lp.gravity = getOptionsPanelGravity();
-            final ViewManager wm = getWindowManager();
-            if (wm != null) {
-                wm.updateViewLayout(st.decorView, lp);
-            }
-        }
-    }
-
-    /**
-     * Initializes the panel associated with the panel feature state. You must
-     * at the very least set PanelFeatureState.panel to the View implementing
-     * its contents. The default implementation gets the panel from the menu.
-     *
-     * @param st The panel state being initialized.
-     * @return Whether the initialization was successful.
-     */
-    protected boolean initializePanelContent(PanelFeatureState st) {
-        if (st.createdPanelView != null) {
-            st.shownPanelView = st.createdPanelView;
-            return true;
-        }
-
-        if (st.menu == null) {
-            return false;
-        }
-
-        if (mPanelMenuPresenterCallback == null) {
-            mPanelMenuPresenterCallback = new PanelMenuPresenterCallback();
-        }
-
-        MenuView menuView = st.isInListMode()
-                ? st.getListMenuView(getContext(), mPanelMenuPresenterCallback)
-                : st.getIconMenuView(getContext(), mPanelMenuPresenterCallback);
-
-        st.shownPanelView = (View) menuView;
-
-        if (st.shownPanelView != null) {
-            // Use the menu View's default animations if it has any
-            final int defaultAnimations = menuView.getWindowAnimations();
-            if (defaultAnimations != 0) {
-                st.windowAnimations = defaultAnimations;
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public boolean performContextMenuIdentifierAction(int id, int flags) {
-        return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
-    }
-
-    @Override
-    public final void setElevation(float elevation) {
-        mElevation = elevation;
-        if (mDecor != null) {
-            mDecor.setElevation(elevation);
-        }
-        dispatchWindowAttributesChanged(getAttributes());
-    }
-
-    @Override
-    public final void setClipToOutline(boolean clipToOutline) {
-        mClipToOutline = clipToOutline;
-        if (mDecor != null) {
-            mDecor.setClipToOutline(clipToOutline);
-        }
-    }
-
-    @Override
-    public final void setBackgroundDrawable(Drawable drawable) {
-        if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
-            mBackgroundResource = 0;
-            mBackgroundDrawable = drawable;
-            if (mDecor != null) {
-                mDecor.setWindowBackground(drawable);
-            }
-            if (mBackgroundFallbackResource != 0) {
-                mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
-            }
-        }
-    }
-
-    @Override
-    public final void setFeatureDrawableResource(int featureId, int resId) {
-        if (resId != 0) {
-            DrawableFeatureState st = getDrawableState(featureId, true);
-            if (st.resid != resId) {
-                st.resid = resId;
-                st.uri = null;
-                st.local = getContext().getDrawable(resId);
-                updateDrawable(featureId, st, false);
-            }
-        } else {
-            setFeatureDrawable(featureId, null);
-        }
-    }
-
-    @Override
-    public final void setFeatureDrawableUri(int featureId, Uri uri) {
-        if (uri != null) {
-            DrawableFeatureState st = getDrawableState(featureId, true);
-            if (st.uri == null || !st.uri.equals(uri)) {
-                st.resid = 0;
-                st.uri = uri;
-                st.local = loadImageURI(uri);
-                updateDrawable(featureId, st, false);
-            }
-        } else {
-            setFeatureDrawable(featureId, null);
-        }
-    }
-
-    @Override
-    public final void setFeatureDrawable(int featureId, Drawable drawable) {
-        DrawableFeatureState st = getDrawableState(featureId, true);
-        st.resid = 0;
-        st.uri = null;
-        if (st.local != drawable) {
-            st.local = drawable;
-            updateDrawable(featureId, st, false);
-        }
-    }
-
-    @Override
-    public void setFeatureDrawableAlpha(int featureId, int alpha) {
-        DrawableFeatureState st = getDrawableState(featureId, true);
-        if (st.alpha != alpha) {
-            st.alpha = alpha;
-            updateDrawable(featureId, st, false);
-        }
-    }
-
-    protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
-        DrawableFeatureState st = getDrawableState(featureId, true);
-        if (st.def != drawable) {
-            st.def = drawable;
-            updateDrawable(featureId, st, false);
-        }
-    }
-
-    @Override
-    public final void setFeatureInt(int featureId, int value) {
-        // XXX Should do more management (as with drawable features) to
-        // deal with interactions between multiple window policies.
-        updateInt(featureId, value, false);
-    }
-
-    /**
-     * Update the state of a drawable feature. This should be called, for every
-     * drawable feature supported, as part of onActive(), to make sure that the
-     * contents of a containing window is properly updated.
-     *
-     * @see #onActive
-     * @param featureId The desired drawable feature to change.
-     * @param fromActive Always true when called from onActive().
-     */
-    protected final void updateDrawable(int featureId, boolean fromActive) {
-        final DrawableFeatureState st = getDrawableState(featureId, false);
-        if (st != null) {
-            updateDrawable(featureId, st, fromActive);
-        }
-    }
-
-    /**
-     * Called when a Drawable feature changes, for the window to update its
-     * graphics.
-     *
-     * @param featureId The feature being changed.
-     * @param drawable The new Drawable to show, or null if none.
-     * @param alpha The new alpha blending of the Drawable.
-     */
-    protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
-        ImageView view;
-        if (featureId == FEATURE_LEFT_ICON) {
-            view = getLeftIconView();
-        } else if (featureId == FEATURE_RIGHT_ICON) {
-            view = getRightIconView();
-        } else {
-            return;
-        }
-
-        if (drawable != null) {
-            drawable.setAlpha(alpha);
-            view.setImageDrawable(drawable);
-            view.setVisibility(View.VISIBLE);
-        } else {
-            view.setVisibility(View.GONE);
-        }
-    }
-
-    /**
-     * Called when an int feature changes, for the window to update its
-     * graphics.
-     *
-     * @param featureId The feature being changed.
-     * @param value The new integer value.
-     */
-    protected void onIntChanged(int featureId, int value) {
-        if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
-            updateProgressBars(value);
-        } else if (featureId == FEATURE_CUSTOM_TITLE) {
-            FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
-            if (titleContainer != null) {
-                mLayoutInflater.inflate(value, titleContainer);
-            }
-        }
-    }
-
-    /**
-     * Updates the progress bars that are shown in the title bar.
-     *
-     * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
-     *            {@link Window#PROGRESS_VISIBILITY_OFF},
-     *            {@link Window#PROGRESS_INDETERMINATE_ON},
-     *            {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
-     *            starting at {@link Window#PROGRESS_START} through
-     *            {@link Window#PROGRESS_END} for setting the default
-     *            progress (if {@link Window#PROGRESS_END} is given,
-     *            the progress bar widgets in the title will be hidden after an
-     *            animation), a value between
-     *            {@link Window#PROGRESS_SECONDARY_START} -
-     *            {@link Window#PROGRESS_SECONDARY_END} for the
-     *            secondary progress (if
-     *            {@link Window#PROGRESS_SECONDARY_END} is given, the
-     *            progress bar widgets will still be shown with the secondary
-     *            progress bar will be completely filled in.)
-     */
-    private void updateProgressBars(int value) {
-        ProgressBar circularProgressBar = getCircularProgressBar(true);
-        ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
-
-        final int features = getLocalFeatures();
-        if (value == PROGRESS_VISIBILITY_ON) {
-            if ((features & (1 << FEATURE_PROGRESS)) != 0) {
-                if (horizontalProgressBar != null) {
-                    int level = horizontalProgressBar.getProgress();
-                    int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
-                            View.VISIBLE : View.INVISIBLE;
-                    horizontalProgressBar.setVisibility(visibility);
-                } else {
-                    Log.e(TAG, "Horizontal progress bar not located in current window decor");
-                }
-            }
-            if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
-                if (circularProgressBar != null) {
-                    circularProgressBar.setVisibility(View.VISIBLE);
-                } else {
-                    Log.e(TAG, "Circular progress bar not located in current window decor");
-                }
-            }
-        } else if (value == PROGRESS_VISIBILITY_OFF) {
-            if ((features & (1 << FEATURE_PROGRESS)) != 0) {
-                if (horizontalProgressBar != null) {
-                    horizontalProgressBar.setVisibility(View.GONE);
-                } else {
-                    Log.e(TAG, "Horizontal progress bar not located in current window decor");
-                }
-            }
-            if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
-                if (circularProgressBar != null) {
-                    circularProgressBar.setVisibility(View.GONE);
-                } else {
-                    Log.e(TAG, "Circular progress bar not located in current window decor");
-                }
-            }
-        } else if (value == PROGRESS_INDETERMINATE_ON) {
-            if (horizontalProgressBar != null) {
-                horizontalProgressBar.setIndeterminate(true);
-            } else {
-                Log.e(TAG, "Horizontal progress bar not located in current window decor");
-            }
-        } else if (value == PROGRESS_INDETERMINATE_OFF) {
-            if (horizontalProgressBar != null) {
-                horizontalProgressBar.setIndeterminate(false);
-            } else {
-                Log.e(TAG, "Horizontal progress bar not located in current window decor");
-            }
-        } else if (PROGRESS_START <= value && value <= PROGRESS_END) {
-            // We want to set the progress value before testing for visibility
-            // so that when the progress bar becomes visible again, it has the
-            // correct level.
-            if (horizontalProgressBar != null) {
-                horizontalProgressBar.setProgress(value - PROGRESS_START);
-            } else {
-                Log.e(TAG, "Horizontal progress bar not located in current window decor");
-            }
-
-            if (value < PROGRESS_END) {
-                showProgressBars(horizontalProgressBar, circularProgressBar);
-            } else {
-                hideProgressBars(horizontalProgressBar, circularProgressBar);
-            }
-        } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
-            if (horizontalProgressBar != null) {
-                horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
-            } else {
-                Log.e(TAG, "Horizontal progress bar not located in current window decor");
-            }
-
-            showProgressBars(horizontalProgressBar, circularProgressBar);
-        }
-
-    }
-
-    private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
-        final int features = getLocalFeatures();
-        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
-                spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.INVISIBLE) {
-            spinnyProgressBar.setVisibility(View.VISIBLE);
-        }
-        // Only show the progress bars if the primary progress is not complete
-        if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
-                horizontalProgressBar.getProgress() < 10000) {
-            horizontalProgressBar.setVisibility(View.VISIBLE);
-        }
-    }
-
-    private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
-        final int features = getLocalFeatures();
-        Animation anim = AnimationUtils.loadAnimation(getContext(), R.anim.fade_out);
-        anim.setDuration(1000);
-        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
-                spinnyProgressBar != null &&
-                spinnyProgressBar.getVisibility() == View.VISIBLE) {
-            spinnyProgressBar.startAnimation(anim);
-            spinnyProgressBar.setVisibility(View.INVISIBLE);
-        }
-        if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null &&
-                horizontalProgressBar.getVisibility() == View.VISIBLE) {
-            horizontalProgressBar.startAnimation(anim);
-            horizontalProgressBar.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    @Override
-    public void setIcon(int resId) {
-        mIconRes = resId;
-        mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
-        mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
-        if (mDecorContentParent != null) {
-            mDecorContentParent.setIcon(resId);
-        }
-    }
-
-    @Override
-    public void setDefaultIcon(int resId) {
-        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0) {
-            return;
-        }
-        mIconRes = resId;
-        if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
-                (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
-            if (resId != 0) {
-                mDecorContentParent.setIcon(resId);
-                mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
-            } else {
-                mDecorContentParent.setIcon(
-                        getContext().getPackageManager().getDefaultActivityIcon());
-                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
-            }
-        }
-    }
-
-    @Override
-    public void setLogo(int resId) {
-        mLogoRes = resId;
-        mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
-        if (mDecorContentParent != null) {
-            mDecorContentParent.setLogo(resId);
-        }
-    }
-
-    @Override
-    public void setDefaultLogo(int resId) {
-        if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0) {
-            return;
-        }
-        mLogoRes = resId;
-        if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
-            mDecorContentParent.setLogo(resId);
-        }
-    }
-
-    @Override
-    public void setLocalFocus(boolean hasFocus, boolean inTouchMode) {
-        getViewRootImpl().windowFocusChanged(hasFocus, inTouchMode);
-
-    }
-
-    @Override
-    public void injectInputEvent(InputEvent event) {
-        getViewRootImpl().dispatchInputEvent(event);
-    }
-
-    private ViewRootImpl getViewRootImpl() {
-        if (mDecor != null) {
-            ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
-            if (viewRootImpl != null) {
-                return viewRootImpl;
-            }
-        }
-        throw new IllegalStateException("view not added");
-    }
-
-    /**
-     * Request that key events come to this activity. Use this if your activity
-     * has no views with focus, but the activity still wants a chance to process
-     * key events.
-     */
-    @Override
-    public void takeKeyEvents(boolean get) {
-        mDecor.setFocusable(get);
-    }
-
-    @Override
-    public boolean superDispatchKeyEvent(KeyEvent event) {
-        return mDecor.superDispatchKeyEvent(event);
-    }
-
-    @Override
-    public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
-        return mDecor.superDispatchKeyShortcutEvent(event);
-    }
-
-    @Override
-    public boolean superDispatchTouchEvent(MotionEvent event) {
-        return mDecor.superDispatchTouchEvent(event);
-    }
-
-    @Override
-    public boolean superDispatchTrackballEvent(MotionEvent event) {
-        return mDecor.superDispatchTrackballEvent(event);
-    }
-
-    @Override
-    public boolean superDispatchGenericMotionEvent(MotionEvent event) {
-        return mDecor.superDispatchGenericMotionEvent(event);
-    }
-
-    /**
-     * A key was pressed down and not handled by anything else in the window.
-     *
-     * @see #onKeyUp
-     * @see android.view.KeyEvent
-     */
-    protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
-        /* ****************************************************************************
-         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
-         *
-         * If your key handling must happen before the app gets a crack at the event,
-         * it goes in PhoneWindowManager.
-         *
-         * If your key handling should happen in all windows, and does not depend on
-         * the state of the current application, other than that the current
-         * application can override the behavior by handling the event itself, it
-         * should go in PhoneFallbackEventHandler.
-         *
-         * Only if your handling depends on the window, and the fact that it has
-         * a DecorView, should it go here.
-         * ****************************************************************************/
-
-        final KeyEvent.DispatcherState dispatcher =
-                mDecor != null ? mDecor.getKeyDispatcherState() : null;
-        //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
-        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN: {
-                int direction = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE
-                        : AudioManager.ADJUST_LOWER;
-                // If we have a session send it the volume command, otherwise
-                // use the suggested stream.
-                if (mMediaController != null) {
-                    mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
-                } else {
-                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
-                            mVolumeControlStreamType, direction,
-                            AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
-                }
-                return true;
-            }
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
-                return true;
-            }
-            // These are all the recognized media key codes in
-            // KeyEvent.isMediaKey()
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
-                if (mMediaController != null) {
-                    if (mMediaController.dispatchMediaButtonEvent(event)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            case KeyEvent.KEYCODE_MENU: {
-                onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_BACK: {
-                if (event.getRepeatCount() > 0) break;
-                if (featureId < 0) break;
-                // Currently don't do anything with long press.
-                if (dispatcher != null) {
-                    dispatcher.startTracking(event, this);
-                }
-                return true;
-            }
-
-        }
-
-        return false;
-    }
-
-    private KeyguardManager getKeyguardManager() {
-        if (mKeyguardManager == null) {
-            mKeyguardManager = (KeyguardManager) getContext().getSystemService(
-                    Context.KEYGUARD_SERVICE);
-        }
-        return mKeyguardManager;
-    }
-
-    AudioManager getAudioManager() {
-        if (mAudioManager == null) {
-            mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
-        }
-        return mAudioManager;
-    }
-
-    /**
-     * A key was released and not handled by anything else in the window.
-     *
-     * @see #onKeyDown
-     * @see android.view.KeyEvent
-     */
-    protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
-        final KeyEvent.DispatcherState dispatcher =
-                mDecor != null ? mDecor.getKeyDispatcherState() : null;
-        if (dispatcher != null) {
-            dispatcher.handleUpEvent(event);
-        }
-        //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
-        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN: {
-                // If we have a session send it the volume command, otherwise
-                // use the suggested stream.
-                if (mMediaController != null) {
-                    mMediaController.adjustVolume(0, AudioManager.FLAG_PLAY_SOUND
-                            | AudioManager.FLAG_VIBRATE);
-                } else {
-                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(
-                            mVolumeControlStreamType, 0,
-                            AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE);
-                }
-                return true;
-            }
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                // Similar code is in PhoneFallbackEventHandler in case the window
-                // doesn't have one of these.  In this case, we execute it here and
-                // eat the event instead, because we have mVolumeControlStreamType
-                // and they don't.
-                getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
-                return true;
-            }
-            // These are all the recognized media key codes in
-            // KeyEvent.isMediaKey()
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
-                if (mMediaController != null) {
-                    if (mMediaController.dispatchMediaButtonEvent(event)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            case KeyEvent.KEYCODE_MENU: {
-                onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
-                        event);
-                return true;
-            }
-
-            case KeyEvent.KEYCODE_BACK: {
-                if (featureId < 0) break;
-                if (event.isTracking() && !event.isCanceled()) {
-                    if (featureId == FEATURE_OPTIONS_PANEL) {
-                        PanelFeatureState st = getPanelState(featureId, false);
-                        if (st != null && st.isInExpandedMode) {
-                            // If the user is in an expanded menu and hits back, it
-                            // should go back to the icon menu
-                            reopenMenu(true);
-                            return true;
-                        }
-                    }
-                    closePanel(featureId);
-                    return true;
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_SEARCH: {
-                /*
-                 * Do this in onKeyUp since the Search key is also used for
-                 * chording quick launch shortcuts.
-                 */
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
-                    break;
-                }
-                if (event.isTracking() && !event.isCanceled()) {
-                    launchDefaultSearch();
-                }
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    protected void onActive() {
-    }
-
-    @Override
-    public final View getDecorView() {
-        if (mDecor == null) {
-            installDecor();
-        }
-        return mDecor;
-    }
-
-    @Override
-    public final View peekDecorView() {
-        return mDecor;
-    }
-
-    static private final String FOCUSED_ID_TAG = "android:focusedViewId";
-    static private final String VIEWS_TAG = "android:views";
-    static private final String PANELS_TAG = "android:Panels";
-    static private final String ACTION_BAR_TAG = "android:ActionBar";
-
-    /** {@inheritDoc} */
-    @Override
-    public Bundle saveHierarchyState() {
-        Bundle outState = new Bundle();
-        if (mContentParent == null) {
-            return outState;
-        }
-
-        SparseArray<Parcelable> states = new SparseArray<Parcelable>();
-        mContentParent.saveHierarchyState(states);
-        outState.putSparseParcelableArray(VIEWS_TAG, states);
-
-        // save the focused view id
-        View focusedView = mContentParent.findFocus();
-        if (focusedView != null) {
-            if (focusedView.getId() != View.NO_ID) {
-                outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
-            } else {
-                if (false) {
-                    Log.d(TAG, "couldn't save which view has focus because the focused view "
-                            + focusedView + " has no id.");
-                }
-            }
-        }
-
-        // save the panels
-        SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
-        savePanelState(panelStates);
-        if (panelStates.size() > 0) {
-            outState.putSparseParcelableArray(PANELS_TAG, panelStates);
-        }
-
-        if (mDecorContentParent != null) {
-            SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
-            mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
-            outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
-        }
-
-        return outState;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void restoreHierarchyState(Bundle savedInstanceState) {
-        if (mContentParent == null) {
-            return;
-        }
-
-        SparseArray<Parcelable> savedStates
-                = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
-        if (savedStates != null) {
-            mContentParent.restoreHierarchyState(savedStates);
-        }
-
-        // restore the focused view
-        int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
-        if (focusedViewId != View.NO_ID) {
-            View needsFocus = mContentParent.findViewById(focusedViewId);
-            if (needsFocus != null) {
-                needsFocus.requestFocus();
-            } else {
-                Log.w(TAG,
-                        "Previously focused view reported id " + focusedViewId
-                                + " during save, but can't be found during restore.");
-            }
-        }
-
-        // restore the panels
-        SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
-        if (panelStates != null) {
-            restorePanelState(panelStates);
-        }
-
-        if (mDecorContentParent != null) {
-            SparseArray<Parcelable> actionBarStates =
-                    savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
-            if (actionBarStates != null) {
-                doPendingInvalidatePanelMenu();
-                mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
-            } else {
-                Log.w(TAG, "Missing saved instance states for action bar views! " +
-                        "State will not be restored.");
-            }
-        }
-    }
-
-    /**
-     * Invoked when the panels should freeze their state.
-     *
-     * @param icicles Save state into this. This is usually indexed by the
-     *            featureId. This will be given to {@link #restorePanelState} in the
-     *            future.
-     */
-    private void savePanelState(SparseArray<Parcelable> icicles) {
-        PanelFeatureState[] panels = mPanels;
-        if (panels == null) {
-            return;
-        }
-
-        for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
-            if (panels[curFeatureId] != null) {
-                icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
-            }
-        }
-    }
-
-    /**
-     * Invoked when the panels should thaw their state from a previously frozen state.
-     *
-     * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
-     */
-    private void restorePanelState(SparseArray<Parcelable> icicles) {
-        PanelFeatureState st;
-        int curFeatureId;
-        for (int i = icicles.size() - 1; i >= 0; i--) {
-            curFeatureId = icicles.keyAt(i);
-            st = getPanelState(curFeatureId, false /* required */);
-            if (st == null) {
-                // The panel must not have been required, and is currently not around, skip it
-                continue;
-            }
-
-            st.onRestoreInstanceState(icicles.get(curFeatureId));
-            invalidatePanelMenu(curFeatureId);
-        }
-
-        /*
-         * Implementation note: call openPanelsAfterRestore later to actually open the
-         * restored panels.
-         */
-    }
-
-    /**
-     * Opens the panels that have had their state restored. This should be
-     * called sometime after {@link #restorePanelState} when it is safe to add
-     * to the window manager.
-     */
-    private void openPanelsAfterRestore() {
-        PanelFeatureState[] panels = mPanels;
-
-        if (panels == null) {
-            return;
-        }
-
-        PanelFeatureState st;
-        for (int i = panels.length - 1; i >= 0; i--) {
-            st = panels[i];
-            // We restore the panel if it was last open; we skip it if it
-            // now is open, to avoid a race condition if the user immediately
-            // opens it when we are resuming.
-            if (st != null) {
-                st.applyFrozenState();
-                if (!st.isOpen && st.wasLastOpen) {
-                    st.isInExpandedMode = st.wasLastExpanded;
-                    openPanel(st, null);
-                }
-            }
-        }
-    }
-
-    private class PanelMenuPresenterCallback implements MenuPresenter.Callback {
-        @Override
-        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-            final Menu parentMenu = menu.getRootMenu();
-            final boolean isSubMenu = parentMenu != menu;
-            final PanelFeatureState panel = findMenuPanel(isSubMenu ? parentMenu : menu);
-            if (panel != null) {
-                if (isSubMenu) {
-                    callOnPanelClosed(panel.featureId, panel, parentMenu);
-                    closePanel(panel, true);
-                } else {
-                    // Close the panel and only do the callback if the menu is being
-                    // closed completely, not if opening a sub menu
-                    closePanel(panel, allMenusAreClosing);
-                }
-            }
-        }
-
-        @Override
-        public boolean onOpenSubMenu(MenuBuilder subMenu) {
-            if (subMenu == null && hasFeature(FEATURE_ACTION_BAR)) {
-                Callback cb = getCallback();
-                if (cb != null && !isDestroyed()) {
-                    cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
-                }
-            }
-
-            return true;
-        }
-    }
-
-    private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
-        @Override
-        public boolean onOpenSubMenu(MenuBuilder subMenu) {
-            Callback cb = getCallback();
-            if (cb != null) {
-                cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-            checkCloseActionMenu(menu);
-        }
-    }
-
-    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
-
-        /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
-
-        /** The feature ID of the panel, or -1 if this is the application's DecorView */
-        private final int mFeatureId;
-
-        private final Rect mDrawingBounds = new Rect();
-
-        private final Rect mBackgroundPadding = new Rect();
-
-        private final Rect mFramePadding = new Rect();
-
-        private final Rect mFrameOffsets = new Rect();
-
-        private boolean mChanging;
-
-        private Drawable mMenuBackground;
-        private boolean mWatchingForMenu;
-        private int mDownY;
-
-        private ActionMode mActionMode;
-        private ActionBarContextView mActionModeView;
-        private PopupWindow mActionModePopup;
-        private Runnable mShowActionModePopup;
-
-        // View added at runtime to draw under the status bar area
-        private View mStatusGuard;
-        // View added at runtime to draw under the navigation bar area
-        private View mNavigationGuard;
-
-        private final ColorViewState mStatusColorViewState = new ColorViewState(
-                SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
-                Gravity.TOP,
-                STATUS_BAR_BACKGROUND_TRANSITION_NAME,
-                com.android.internal.R.id.statusBarBackground,
-                FLAG_FULLSCREEN);
-        private final ColorViewState mNavigationColorViewState = new ColorViewState(
-                SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
-                Gravity.BOTTOM,
-                NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
-                com.android.internal.R.id.navigationBarBackground,
-                0 /* hideWindowFlag */);
-
-        private final Interpolator mShowInterpolator;
-        private final Interpolator mHideInterpolator;
-        private final int mBarEnterExitDuration;
-
-        private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
-
-        private int mLastTopInset = 0;
-        private int mLastBottomInset = 0;
-        private int mLastRightInset = 0;
-        private boolean mLastHasTopStableInset = false;
-        private boolean mLastHasBottomStableInset = false;
-        private int mLastWindowFlags = 0;
-
-        private int mRootScrollY = 0;
-
-        public DecorView(Context context, int featureId) {
-            super(context);
-            mFeatureId = featureId;
-
-            mShowInterpolator = AnimationUtils.loadInterpolator(context,
-                    android.R.interpolator.linear_out_slow_in);
-            mHideInterpolator = AnimationUtils.loadInterpolator(context,
-                    android.R.interpolator.fast_out_linear_in);
-
-            mBarEnterExitDuration = context.getResources().getInteger(
-                    R.integer.dock_enter_exit_duration);
-        }
-
-        public void setBackgroundFallback(int resId) {
-            mBackgroundFallback.setDrawable(resId != 0 ? getContext().getDrawable(resId) : null);
-            setWillNotDraw(getBackground() == null && !mBackgroundFallback.hasFallback());
-        }
-
-        @Override
-        public void onDraw(Canvas c) {
-            super.onDraw(c);
-            mBackgroundFallback.draw(mContentRoot, c, mContentParent);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            final int keyCode = event.getKeyCode();
-            final int action = event.getAction();
-            final boolean isDown = action == KeyEvent.ACTION_DOWN;
-
-            if (isDown && (event.getRepeatCount() == 0)) {
-                // First handle chording of panel key: if a panel key is held
-                // but not released, try to execute a shortcut in it.
-                if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
-                    boolean handled = dispatchKeyShortcutEvent(event);
-                    if (handled) {
-                        return true;
-                    }
-                }
-
-                // If a panel is open, perform a shortcut on it without the
-                // chorded panel key
-                if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
-                    if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
-                        return true;
-                    }
-                }
-            }
-
-            if (!isDestroyed()) {
-                final Callback cb = getCallback();
-                final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
-                        : super.dispatchKeyEvent(event);
-                if (handled) {
-                    return true;
-                }
-            }
-
-            return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
-                    : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
-        }
-
-        @Override
-        public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
-            // If the panel is already prepared, then perform the shortcut using it.
-            boolean handled;
-            if (mPreparedPanel != null) {
-                handled = performPanelShortcut(mPreparedPanel, ev.getKeyCode(), ev,
-                        Menu.FLAG_PERFORM_NO_CLOSE);
-                if (handled) {
-                    if (mPreparedPanel != null) {
-                        mPreparedPanel.isHandled = true;
-                    }
-                    return true;
-                }
-            }
-
-            // Shortcut not handled by the panel.  Dispatch to the view hierarchy.
-            final Callback cb = getCallback();
-            handled = cb != null && !isDestroyed() && mFeatureId < 0
-                    ? cb.dispatchKeyShortcutEvent(ev) : super.dispatchKeyShortcutEvent(ev);
-            if (handled) {
-                return true;
-            }
-
-            // If the panel is not prepared, then we may be trying to handle a shortcut key
-            // combination such as Control+C.  Temporarily prepare the panel then mark it
-            // unprepared again when finished to ensure that the panel will again be prepared
-            // the next time it is shown for real.
-            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-            if (st != null && mPreparedPanel == null) {
-                preparePanel(st, ev);
-                handled = performPanelShortcut(st, ev.getKeyCode(), ev,
-                        Menu.FLAG_PERFORM_NO_CLOSE);
-                st.isPrepared = false;
-                if (handled) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent ev) {
-            final Callback cb = getCallback();
-            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)
-                    : super.dispatchTouchEvent(ev);
-        }
-
-        @Override
-        public boolean dispatchTrackballEvent(MotionEvent ev) {
-            final Callback cb = getCallback();
-            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev)
-                    : super.dispatchTrackballEvent(ev);
-        }
-
-        @Override
-        public boolean dispatchGenericMotionEvent(MotionEvent ev) {
-            final Callback cb = getCallback();
-            return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchGenericMotionEvent(ev)
-                    : super.dispatchGenericMotionEvent(ev);
-        }
-
-        public boolean superDispatchKeyEvent(KeyEvent event) {
-            // Give priority to closing action modes if applicable.
-            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-                final int action = event.getAction();
-                // Back cancels action modes first.
-                if (mActionMode != null) {
-                    if (action == KeyEvent.ACTION_UP) {
-                        mActionMode.finish();
-                    }
-                    return true;
-                }
-            }
-
-            return super.dispatchKeyEvent(event);
-        }
-
-        public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
-            return super.dispatchKeyShortcutEvent(event);
-        }
-
-        public boolean superDispatchTouchEvent(MotionEvent event) {
-            return super.dispatchTouchEvent(event);
-        }
-
-        public boolean superDispatchTrackballEvent(MotionEvent event) {
-            return super.dispatchTrackballEvent(event);
-        }
-
-        public boolean superDispatchGenericMotionEvent(MotionEvent event) {
-            return super.dispatchGenericMotionEvent(event);
-        }
-
-        @Override
-        public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
-            if (mOutsetBottom != null) {
-                final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
-                int bottom = (int) mOutsetBottom.getDimension(metrics);
-                WindowInsets newInsets = insets.replaceSystemWindowInsets(
-                        insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
-                        insets.getSystemWindowInsetRight(), bottom);
-                return super.dispatchApplyWindowInsets(newInsets);
-            } else {
-                return super.dispatchApplyWindowInsets(insets);
-            }
-        }
-
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            return onInterceptTouchEvent(event);
-        }
-
-        private boolean isOutOfBounds(int x, int y) {
-            return x < -5 || y < -5 || x > (getWidth() + 5)
-                    || y > (getHeight() + 5);
-        }
-
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent event) {
-            int action = event.getAction();
-            if (mFeatureId >= 0) {
-                if (action == MotionEvent.ACTION_DOWN) {
-                    int x = (int)event.getX();
-                    int y = (int)event.getY();
-                    if (isOutOfBounds(x, y)) {
-                        closePanel(mFeatureId);
-                        return true;
-                    }
-                }
-            }
-
-            if (!SWEEP_OPEN_MENU) {
-                return false;
-            }
-
-            if (mFeatureId >= 0) {
-                if (action == MotionEvent.ACTION_DOWN) {
-                    Log.i(TAG, "Watchiing!");
-                    mWatchingForMenu = true;
-                    mDownY = (int) event.getY();
-                    return false;
-                }
-
-                if (!mWatchingForMenu) {
-                    return false;
-                }
-
-                int y = (int)event.getY();
-                if (action == MotionEvent.ACTION_MOVE) {
-                    if (y > (mDownY+30)) {
-                        Log.i(TAG, "Closing!");
-                        closePanel(mFeatureId);
-                        mWatchingForMenu = false;
-                        return true;
-                    }
-                } else if (action == MotionEvent.ACTION_UP) {
-                    mWatchingForMenu = false;
-                }
-
-                return false;
-            }
-
-            //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
-            //        + " (in " + getHeight() + ")");
-
-            if (action == MotionEvent.ACTION_DOWN) {
-                int y = (int)event.getY();
-                if (y >= (getHeight()-5) && !hasChildren()) {
-                    Log.i(TAG, "Watchiing!");
-                    mWatchingForMenu = true;
-                }
-                return false;
-            }
-
-            if (!mWatchingForMenu) {
-                return false;
-            }
-
-            int y = (int)event.getY();
-            if (action == MotionEvent.ACTION_MOVE) {
-                if (y < (getHeight()-30)) {
-                    Log.i(TAG, "Opening!");
-                    openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
-                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
-                    mWatchingForMenu = false;
-                    return true;
-                }
-            } else if (action == MotionEvent.ACTION_UP) {
-                mWatchingForMenu = false;
-            }
-
-            return false;
-        }
-
-        @Override
-        public void sendAccessibilityEvent(int eventType) {
-            if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
-                return;
-            }
-
-            // if we are showing a feature that should be announced and one child
-            // make this child the event source since this is the feature itself
-            // otherwise the callback will take over and announce its client
-            if ((mFeatureId == FEATURE_OPTIONS_PANEL ||
-                    mFeatureId == FEATURE_CONTEXT_MENU ||
-                    mFeatureId == FEATURE_PROGRESS ||
-                    mFeatureId == FEATURE_INDETERMINATE_PROGRESS)
-                    && getChildCount() == 1) {
-                getChildAt(0).sendAccessibilityEvent(eventType);
-            } else {
-                super.sendAccessibilityEvent(eventType);
-            }
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            final Callback cb = getCallback();
-            if (cb != null && !isDestroyed()) {
-                if (cb.dispatchPopulateAccessibilityEvent(event)) {
-                    return true;
-                }
-            }
-            return super.dispatchPopulateAccessibilityEvent(event);
-        }
-
-        @Override
-        protected boolean setFrame(int l, int t, int r, int b) {
-            boolean changed = super.setFrame(l, t, r, b);
-            if (changed) {
-                final Rect drawingBounds = mDrawingBounds;
-                getDrawingRect(drawingBounds);
-
-                Drawable fg = getForeground();
-                if (fg != null) {
-                    final Rect frameOffsets = mFrameOffsets;
-                    drawingBounds.left += frameOffsets.left;
-                    drawingBounds.top += frameOffsets.top;
-                    drawingBounds.right -= frameOffsets.right;
-                    drawingBounds.bottom -= frameOffsets.bottom;
-                    fg.setBounds(drawingBounds);
-                    final Rect framePadding = mFramePadding;
-                    drawingBounds.left += framePadding.left - frameOffsets.left;
-                    drawingBounds.top += framePadding.top - frameOffsets.top;
-                    drawingBounds.right -= framePadding.right - frameOffsets.right;
-                    drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
-                }
-
-                Drawable bg = getBackground();
-                if (bg != null) {
-                    bg.setBounds(drawingBounds);
-                }
-
-                if (SWEEP_OPEN_MENU) {
-                    if (mMenuBackground == null && mFeatureId < 0
-                            && getAttributes().height
-                            == WindowManager.LayoutParams.MATCH_PARENT) {
-                        mMenuBackground = getContext().getDrawable(
-                                R.drawable.menu_background);
-                    }
-                    if (mMenuBackground != null) {
-                        mMenuBackground.setBounds(drawingBounds.left,
-                                drawingBounds.bottom-6, drawingBounds.right,
-                                drawingBounds.bottom+20);
-                    }
-                }
-            }
-            return changed;
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
-            final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
-
-            final int widthMode = getMode(widthMeasureSpec);
-            final int heightMode = getMode(heightMeasureSpec);
-
-            boolean fixedWidth = false;
-            if (widthMode == AT_MOST) {
-                final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
-                if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
-                    final int w;
-                    if (tvw.type == TypedValue.TYPE_DIMENSION) {
-                        w = (int) tvw.getDimension(metrics);
-                    } else if (tvw.type == TypedValue.TYPE_FRACTION) {
-                        w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
-                    } else {
-                        w = 0;
-                    }
-
-                    if (w > 0) {
-                        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-                        widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                                Math.min(w, widthSize), EXACTLY);
-                        fixedWidth = true;
-                    }
-                }
-            }
-
-            if (heightMode == AT_MOST) {
-                final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
-                if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
-                    final int h;
-                    if (tvh.type == TypedValue.TYPE_DIMENSION) {
-                        h = (int) tvh.getDimension(metrics);
-                    } else if (tvh.type == TypedValue.TYPE_FRACTION) {
-                        h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
-                    } else {
-                        h = 0;
-                    }
-                    if (h > 0) {
-                        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-                        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                                Math.min(h, heightSize), EXACTLY);
-                    }
-                }
-            }
-
-            if (mOutsetBottom != null) {
-                int mode = MeasureSpec.getMode(heightMeasureSpec);
-                if (mode != MeasureSpec.UNSPECIFIED) {
-                    int outset = (int) mOutsetBottom.getDimension(metrics);
-                    int height = MeasureSpec.getSize(heightMeasureSpec);
-                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
-                }
-            }
-
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-            int width = getMeasuredWidth();
-            boolean measure = false;
-
-            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
-
-            if (!fixedWidth && widthMode == AT_MOST) {
-                final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
-                if (tv.type != TypedValue.TYPE_NULL) {
-                    final int min;
-                    if (tv.type == TypedValue.TYPE_DIMENSION) {
-                        min = (int)tv.getDimension(metrics);
-                    } else if (tv.type == TypedValue.TYPE_FRACTION) {
-                        min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
-                    } else {
-                        min = 0;
-                    }
-
-                    if (width < min) {
-                        widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
-                        measure = true;
-                    }
-                }
-            }
-
-            // TODO: Support height?
-
-            if (measure) {
-                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            }
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            super.draw(canvas);
-
-            if (mMenuBackground != null) {
-                mMenuBackground.draw(canvas);
-            }
-        }
-
-
-        @Override
-        public boolean showContextMenuForChild(View originalView) {
-            // Reuse the context menu builder
-            if (mContextMenu == null) {
-                mContextMenu = new ContextMenuBuilder(getContext());
-                mContextMenu.setCallback(mContextMenuCallback);
-            } else {
-                mContextMenu.clearAll();
-            }
-
-            final MenuDialogHelper helper = mContextMenu.show(originalView,
-                    originalView.getWindowToken());
-            if (helper != null) {
-                helper.setPresenterCallback(mContextMenuCallback);
-            } else if (mContextMenuHelper != null) {
-                // No menu to show, but if we have a menu currently showing it just became blank.
-                // Close it.
-                mContextMenuHelper.dismiss();
-            }
-            mContextMenuHelper = helper;
-            return helper != null;
-        }
-
-        @Override
-        public ActionMode startActionModeForChild(View originalView,
-                ActionMode.Callback callback) {
-            // originalView can be used here to be sure that we don't obscure
-            // relevant content with the context mode UI.
-            return startActionMode(callback);
-        }
-
-        @Override
-        public ActionMode startActionMode(ActionMode.Callback callback) {
-            if (mActionMode != null) {
-                mActionMode.finish();
-            }
-
-            final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
-            ActionMode mode = null;
-            if (getCallback() != null && !isDestroyed()) {
-                try {
-                    mode = getCallback().onWindowStartingActionMode(wrappedCallback);
-                } catch (AbstractMethodError ame) {
-                    // Older apps might not implement this callback method.
-                }
-            }
-            if (mode != null) {
-                mActionMode = mode;
-            } else {
-                if (mActionModeView == null) {
-                    if (isFloating()) {
-                        // Use the action bar theme.
-                        final TypedValue outValue = new TypedValue();
-                        final Theme baseTheme = mContext.getTheme();
-                        baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
-
-                        final Context actionBarContext;
-                        if (outValue.resourceId != 0) {
-                            final Theme actionBarTheme = mContext.getResources().newTheme();
-                            actionBarTheme.setTo(baseTheme);
-                            actionBarTheme.applyStyle(outValue.resourceId, true);
-
-                            actionBarContext = new ContextThemeWrapper(mContext, 0);
-                            actionBarContext.getTheme().setTo(actionBarTheme);
-                        } else {
-                            actionBarContext = mContext;
-                        }
-
-                        mActionModeView = new ActionBarContextView(actionBarContext);
-                        mActionModePopup = new PopupWindow(actionBarContext, null,
-                                R.attr.actionModePopupWindowStyle);
-                        mActionModePopup.setWindowLayoutType(
-                                WindowManager.LayoutParams.TYPE_APPLICATION);
-                        mActionModePopup.setContentView(mActionModeView);
-                        mActionModePopup.setWidth(MATCH_PARENT);
-
-                        actionBarContext.getTheme().resolveAttribute(
-                                R.attr.actionBarSize, outValue, true);
-                        final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
-                                actionBarContext.getResources().getDisplayMetrics());
-                        mActionModeView.setContentHeight(height);
-                        mActionModePopup.setHeight(WRAP_CONTENT);
-                        mShowActionModePopup = new Runnable() {
-                            public void run() {
-                                mActionModePopup.showAtLocation(
-                                        mActionModeView.getApplicationWindowToken(),
-                                        Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
-                            }
-                        };
-                    } else {
-                        ViewStub stub = (ViewStub) findViewById(
-                                R.id.action_mode_bar_stub);
-                        if (stub != null) {
-                            mActionModeView = (ActionBarContextView) stub.inflate();
-                        }
-                    }
-                }
-
-                if (mActionModeView != null) {
-                    mActionModeView.killMode();
-                    mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView,
-                            wrappedCallback, mActionModePopup == null);
-                    if (callback.onCreateActionMode(mode, mode.getMenu())) {
-                        mode.invalidate();
-                        mActionModeView.initForMode(mode);
-                        mActionModeView.setVisibility(View.VISIBLE);
-                        mActionMode = mode;
-                        if (mActionModePopup != null) {
-                            post(mShowActionModePopup);
-                        }
-                        mActionModeView.sendAccessibilityEvent(
-                                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-                    } else {
-                        mActionMode = null;
-                    }
-                }
-            }
-            if (mActionMode != null && getCallback() != null && !isDestroyed()) {
-                try {
-                    getCallback().onActionModeStarted(mActionMode);
-                } catch (AbstractMethodError ame) {
-                    // Older apps might not implement this callback method.
-                }
-            }
-            return mActionMode;
-        }
-
-        public void startChanging() {
-            mChanging = true;
-        }
-
-        public void finishChanging() {
-            mChanging = false;
-            drawableChanged();
-        }
-
-        public void setWindowBackground(Drawable drawable) {
-            if (getBackground() != drawable) {
-                setBackgroundDrawable(drawable);
-                if (drawable != null) {
-                    drawable.getPadding(mBackgroundPadding);
-                } else {
-                    mBackgroundPadding.setEmpty();
-                }
-                drawableChanged();
-            }
-        }
-
-        @Override
-        public void setBackgroundDrawable(Drawable d) {
-            super.setBackgroundDrawable(d);
-            if (getWindowToken() != null) {
-                updateWindowResizeState();
-            }
-        }
-
-        public void setWindowFrame(Drawable drawable) {
-            if (getForeground() != drawable) {
-                setForeground(drawable);
-                if (drawable != null) {
-                    drawable.getPadding(mFramePadding);
-                } else {
-                    mFramePadding.setEmpty();
-                }
-                drawableChanged();
-            }
-        }
-
-        @Override
-        public void onWindowSystemUiVisibilityChanged(int visible) {
-            updateColorViews(null /* insets */, true /* animate */);
-        }
-
-        @Override
-        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-            mFrameOffsets.set(insets.getSystemWindowInsets());
-            insets = updateColorViews(insets, true /* animate */);
-            insets = updateStatusGuard(insets);
-            updateNavigationGuard(insets);
-            if (getForeground() != null) {
-                drawableChanged();
-            }
-            return insets;
-        }
-
-        @Override
-        public boolean isTransitionGroup() {
-            return false;
-        }
-
-        private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
-            WindowManager.LayoutParams attrs = getAttributes();
-            int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
-
-            if (!mIsFloating && ActivityManager.isHighEndGfx()) {
-                boolean disallowAnimate = !isLaidOut();
-                disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
-                        & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
-                mLastWindowFlags = attrs.flags;
-
-                if (insets != null) {
-                    mLastTopInset = Math.min(insets.getStableInsetTop(),
-                            insets.getSystemWindowInsetTop());
-                    mLastBottomInset = Math.min(insets.getStableInsetBottom(),
-                            insets.getSystemWindowInsetBottom());
-                    mLastRightInset = Math.min(insets.getStableInsetRight(),
-                            insets.getSystemWindowInsetRight());
-
-                    // Don't animate if the presence of stable insets has changed, because that
-                    // indicates that the window was either just added and received them for the
-                    // first time, or the window size or position has changed.
-                    boolean hasTopStableInset = insets.getStableInsetTop() != 0;
-                    disallowAnimate |= (hasTopStableInset != mLastHasTopStableInset);
-                    mLastHasTopStableInset = hasTopStableInset;
-
-                    boolean hasBottomStableInset = insets.getStableInsetBottom() != 0;
-                    disallowAnimate |= (hasBottomStableInset != mLastHasBottomStableInset);
-                    mLastHasBottomStableInset = hasBottomStableInset;
-                }
-
-                updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
-                        mLastTopInset, animate && !disallowAnimate);
-                updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
-                        mLastBottomInset, animate && !disallowAnimate);
-            }
-
-            // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
-            // to ensure that the rest of the view hierarchy doesn't notice it, unless they've
-            // explicitly asked for it.
-
-            boolean consumingNavBar =
-                    (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
-                            && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
-                            && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
-
-            int consumedRight = consumingNavBar ? mLastRightInset : 0;
-            int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
-
-            if (mContentRoot != null
-                    && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
-                MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
-                if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
-                    lp.rightMargin = consumedRight;
-                    lp.bottomMargin = consumedBottom;
-                    mContentRoot.setLayoutParams(lp);
-
-                    if (insets == null) {
-                        // The insets have changed, but we're not currently in the process
-                        // of dispatching them.
-                        requestApplyInsets();
-                    }
-                }
-                if (insets != null) {
-                    insets = insets.replaceSystemWindowInsets(
-                            insets.getSystemWindowInsetLeft(),
-                            insets.getSystemWindowInsetTop(),
-                            insets.getSystemWindowInsetRight() - consumedRight,
-                            insets.getSystemWindowInsetBottom() - consumedBottom);
-                }
-            }
-
-            if (insets != null) {
-                insets = insets.consumeStableInsets();
-            }
-            return insets;
-        }
-
-        private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
-                int height, boolean animate) {
-            boolean show = height > 0 && (sysUiVis & state.systemUiHideFlag) == 0
-                    && (getAttributes().flags & state.hideWindowFlag) == 0
-                    && (getAttributes().flags & state.translucentFlag) == 0
-                    && (color & Color.BLACK) != 0
-                    && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
-
-            boolean visibilityChanged = false;
-            View view = state.view;
-
-            if (view == null) {
-                if (show) {
-                    state.view = view = new View(mContext);
-                    view.setBackgroundColor(color);
-                    view.setTransitionName(state.transitionName);
-                    view.setId(state.id);
-                    visibilityChanged = true;
-                    view.setVisibility(INVISIBLE);
-                    state.targetVisibility = VISIBLE;
-
-                    addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
-                            Gravity.START | state.verticalGravity));
-                    updateColorViewTranslations();
-                }
-            } else {
-                int vis = show ? VISIBLE : INVISIBLE;
-                visibilityChanged = state.targetVisibility != vis;
-                state.targetVisibility = vis;
-                if (show) {
-                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
-                    if (lp.height != height) {
-                        lp.height = height;
-                        view.setLayoutParams(lp);
-                    }
-                    view.setBackgroundColor(color);
-                }
-            }
-            if (visibilityChanged) {
-                view.animate().cancel();
-                if (animate) {
-                    if (show) {
-                        if (view.getVisibility() != VISIBLE) {
-                            view.setVisibility(VISIBLE);
-                            view.setAlpha(0.0f);
-                        }
-                        view.animate().alpha(1.0f).setInterpolator(mShowInterpolator).
-                                setDuration(mBarEnterExitDuration);
-                    } else {
-                        view.animate().alpha(0.0f).setInterpolator(mHideInterpolator)
-                                .setDuration(mBarEnterExitDuration)
-                                .withEndAction(new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        state.view.setAlpha(1.0f);
-                                        state.view.setVisibility(INVISIBLE);
-                                    }
-                                });
-                    }
-                } else {
-                    view.setAlpha(1.0f);
-                    view.setVisibility(show ? VISIBLE : INVISIBLE);
-                }
-            }
-        }
-
-        private void updateColorViewTranslations() {
-            // Put the color views back in place when they get moved off the screen
-            // due to the the ViewRootImpl panning.
-            int rootScrollY = mRootScrollY;
-            if (mStatusColorViewState.view != null) {
-                mStatusColorViewState.view.setTranslationY(rootScrollY > 0 ? rootScrollY : 0);
-            }
-            if (mNavigationColorViewState.view != null) {
-                mNavigationColorViewState.view.setTranslationY(rootScrollY < 0 ? rootScrollY : 0);
-            }
-        }
-
-        private WindowInsets updateStatusGuard(WindowInsets insets) {
-            boolean showStatusGuard = false;
-            // Show the status guard when the non-overlay contextual action bar is showing
-            if (mActionModeView != null) {
-                if (mActionModeView.getLayoutParams() instanceof MarginLayoutParams) {
-                    // Insets are magic!
-                    final MarginLayoutParams mlp = (MarginLayoutParams)
-                            mActionModeView.getLayoutParams();
-                    boolean mlpChanged = false;
-                    if (mActionModeView.isShown()) {
-                        if (mTempRect == null) {
-                            mTempRect = new Rect();
-                        }
-                        final Rect rect = mTempRect;
-
-                        // If the parent doesn't consume the insets, manually
-                        // apply the default system window insets.
-                        mContentParent.computeSystemWindowInsets(insets, rect);
-                        final int newMargin = rect.top == 0 ? insets.getSystemWindowInsetTop() : 0;
-                        if (mlp.topMargin != newMargin) {
-                            mlpChanged = true;
-                            mlp.topMargin = insets.getSystemWindowInsetTop();
-
-                            if (mStatusGuard == null) {
-                                mStatusGuard = new View(mContext);
-                                mStatusGuard.setBackgroundColor(mContext.getResources()
-                                        .getColor(R.color.input_method_navigation_guard));
-                                addView(mStatusGuard, indexOfChild(mStatusColorViewState.view),
-                                        new LayoutParams(LayoutParams.MATCH_PARENT,
-                                                mlp.topMargin, Gravity.START | Gravity.TOP));
-                            } else {
-                                final LayoutParams lp = (LayoutParams)
-                                        mStatusGuard.getLayoutParams();
-                                if (lp.height != mlp.topMargin) {
-                                    lp.height = mlp.topMargin;
-                                    mStatusGuard.setLayoutParams(lp);
-                                }
-                            }
-                        }
-
-                        // The action mode's theme may differ from the app, so
-                        // always show the status guard above it if we have one.
-                        showStatusGuard = mStatusGuard != null;
-
-                        // We only need to consume the insets if the action
-                        // mode is overlaid on the app content (e.g. it's
-                        // sitting in a FrameLayout, see
-                        // screen_simple_overlay_action_mode.xml).
-                        final boolean nonOverlay = (getLocalFeatures()
-                                & (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0;
-                        insets = insets.consumeSystemWindowInsets(
-                                false, nonOverlay && showStatusGuard /* top */, false, false);
-                    } else {
-                        // reset top margin
-                        if (mlp.topMargin != 0) {
-                            mlpChanged = true;
-                            mlp.topMargin = 0;
-                        }
-                    }
-                    if (mlpChanged) {
-                        mActionModeView.setLayoutParams(mlp);
-                    }
-                }
-            }
-            if (mStatusGuard != null) {
-                mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE);
-            }
-            return 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
-                if (mContentParent != null) {
-                    if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
-                        MarginLayoutParams mlp =
-                                (MarginLayoutParams) mContentParent.getLayoutParams();
-                        mlp.bottomMargin = insets.getSystemWindowInsetBottom();
-                        mContentParent.setLayoutParams(mlp);
-                    }
-                }
-                // position the navigation guard view, creating it if necessary
-                if (mNavigationGuard == null) {
-                    mNavigationGuard = new View(mContext);
-                    mNavigationGuard.setBackgroundColor(mContext.getResources()
-                            .getColor(R.color.input_method_navigation_guard));
-                    addView(mNavigationGuard, indexOfChild(mNavigationColorViewState.view),
-                            new LayoutParams(LayoutParams.MATCH_PARENT,
-                                    insets.getSystemWindowInsetBottom(),
-                                    Gravity.START | Gravity.BOTTOM));
-                } else {
-                    LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
-                    lp.height = insets.getSystemWindowInsetBottom();
-                    mNavigationGuard.setLayoutParams(lp);
-                }
-            }
-        }
-
-        private void drawableChanged() {
-            if (mChanging) {
-                return;
-            }
-
-            setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
-                    + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
-                    mFramePadding.bottom + mBackgroundPadding.bottom);
-            requestLayout();
-            invalidate();
-
-            int opacity = PixelFormat.OPAQUE;
-            // Note: if there is no background, we will assume opaque. The
-            // common case seems to be that an application sets there to be
-            // no background so it can draw everything itself. For that,
-            // we would like to assume OPAQUE and let the app force it to
-            // the slower TRANSLUCENT mode if that is really what it wants.
-            Drawable bg = getBackground();
-            Drawable fg = getForeground();
-            if (bg != null) {
-                if (fg == null) {
-                    opacity = bg.getOpacity();
-                } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
-                        && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
-                    // If the frame padding is zero, then we can be opaque
-                    // if either the frame -or- the background is opaque.
-                    int fop = fg.getOpacity();
-                    int bop = bg.getOpacity();
-                    if (false)
-                        Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
-                    if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
-                        opacity = PixelFormat.OPAQUE;
-                    } else if (fop == PixelFormat.UNKNOWN) {
-                        opacity = bop;
-                    } else if (bop == PixelFormat.UNKNOWN) {
-                        opacity = fop;
-                    } else {
-                        opacity = Drawable.resolveOpacity(fop, bop);
-                    }
-                } else {
-                    // For now we have to assume translucent if there is a
-                    // frame with padding... there is no way to tell if the
-                    // frame and background together will draw all pixels.
-                    if (false)
-                        Log.v(TAG, "Padding: " + mFramePadding);
-                    opacity = PixelFormat.TRANSLUCENT;
-                }
-            }
-
-            if (false)
-                Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
-            if (false)
-                Log.v(TAG, "Selected default opacity: " + opacity);
-
-            mDefaultOpacity = opacity;
-            if (mFeatureId < 0) {
-                setDefaultWindowFormat(opacity);
-            }
-        }
-
-        @Override
-        public void onWindowFocusChanged(boolean hasWindowFocus) {
-            super.onWindowFocusChanged(hasWindowFocus);
-
-            // If the user is chording a menu shortcut, release the chord since
-            // this window lost focus
-            if (hasFeature(FEATURE_OPTIONS_PANEL) && !hasWindowFocus && mPanelChordingKey != 0) {
-                closePanel(FEATURE_OPTIONS_PANEL);
-            }
-
-            final Callback cb = getCallback();
-            if (cb != null && !isDestroyed() && mFeatureId < 0) {
-                cb.onWindowFocusChanged(hasWindowFocus);
-            }
-        }
-
-        void updateWindowResizeState() {
-            Drawable bg = getBackground();
-            hackTurnOffWindowResizeAnim(bg == null || bg.getOpacity()
-                    != PixelFormat.OPAQUE);
-        }
-
-        @Override
-        protected void onAttachedToWindow() {
-            super.onAttachedToWindow();
-
-            updateWindowResizeState();
-
-            final Callback cb = getCallback();
-            if (cb != null && !isDestroyed() && mFeatureId < 0) {
-                cb.onAttachedToWindow();
-            }
-
-            if (mFeatureId == -1) {
-                /*
-                 * The main window has been attached, try to restore any panels
-                 * that may have been open before. This is called in cases where
-                 * an activity is being killed for configuration change and the
-                 * menu was open. When the activity is recreated, the menu
-                 * should be shown again.
-                 */
-                openPanelsAfterRestore();
-            }
-        }
-
-        @Override
-        protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-
-            final Callback cb = getCallback();
-            if (cb != null && mFeatureId < 0) {
-                cb.onDetachedFromWindow();
-            }
-
-            if (mDecorContentParent != null) {
-                mDecorContentParent.dismissPopups();
-            }
-
-            if (mActionModePopup != null) {
-                removeCallbacks(mShowActionModePopup);
-                if (mActionModePopup.isShowing()) {
-                    mActionModePopup.dismiss();
-                }
-                mActionModePopup = null;
-            }
-
-            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-            if (st != null && st.menu != null && mFeatureId < 0) {
-                st.menu.close();
-            }
-        }
-
-        @Override
-        public void onCloseSystemDialogs(String reason) {
-            if (mFeatureId >= 0) {
-                closeAllPanels();
-            }
-        }
-
-        public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
-            return mFeatureId < 0 ? mTakeSurfaceCallback : null;
-        }
-
-        public InputQueue.Callback willYouTakeTheInputQueue() {
-            return mFeatureId < 0 ? mTakeInputQueueCallback : null;
-        }
-
-        public void setSurfaceType(int type) {
-            PhoneWindow.this.setType(type);
-        }
-
-        public void setSurfaceFormat(int format) {
-            PhoneWindow.this.setFormat(format);
-        }
-
-        public void setSurfaceKeepScreenOn(boolean keepOn) {
-            if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-            else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        }
-
-        @Override
-        public void onRootViewScrollYChanged(int rootScrollY) {
-            mRootScrollY = rootScrollY;
-            updateColorViewTranslations();
-        }
-
-        /**
-         * Clears out internal reference when the action mode is destroyed.
-         */
-        private class ActionModeCallbackWrapper implements ActionMode.Callback {
-            private ActionMode.Callback mWrapped;
-
-            public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
-                mWrapped = wrapped;
-            }
-
-            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-                return mWrapped.onCreateActionMode(mode, menu);
-            }
-
-            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-                requestFitSystemWindows();
-                return mWrapped.onPrepareActionMode(mode, menu);
-            }
-
-            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
-                return mWrapped.onActionItemClicked(mode, item);
-            }
-
-            public void onDestroyActionMode(ActionMode mode) {
-                mWrapped.onDestroyActionMode(mode);
-                if (mActionModePopup != null) {
-                    removeCallbacks(mShowActionModePopup);
-                    mActionModePopup.dismiss();
-                } else if (mActionModeView != null) {
-                    mActionModeView.setVisibility(GONE);
-                }
-                if (mActionModeView != null) {
-                    mActionModeView.removeAllViews();
-                }
-                if (getCallback() != null && !isDestroyed()) {
-                    try {
-                        getCallback().onActionModeFinished(mActionMode);
-                    } catch (AbstractMethodError ame) {
-                        // Older apps might not implement this callback method.
-                    }
-                }
-                mActionMode = null;
-                requestFitSystemWindows();
-            }
-        }
-    }
-
-    protected DecorView generateDecor() {
-        return new DecorView(getContext(), -1);
-    }
-
-    protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
-            int drawableAttr, int alphaAttr) {
-        Drawable d = attrs.getDrawable(drawableAttr);
-        if (d != null) {
-            requestFeature(featureId);
-            setFeatureDefaultDrawable(featureId, d);
-        }
-        if ((getFeatures() & (1 << featureId)) != 0) {
-            int alpha = attrs.getInt(alphaAttr, -1);
-            if (alpha >= 0) {
-                setFeatureDrawableAlpha(featureId, alpha);
-            }
-        }
-    }
-
-    protected ViewGroup generateLayout(DecorView decor) {
-        // Apply data from current theme.
-
-        TypedArray a = getWindowStyle();
-
-        if (false) {
-            System.out.println("From style:");
-            String s = "Attrs:";
-            for (int i = 0; i < R.styleable.Window.length; i++) {
-                s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
-                        + a.getString(i);
-            }
-            System.out.println(s);
-        }
-
-        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
-        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
-                & (~getForcedWindowFlags());
-        if (mIsFloating) {
-            setLayout(WRAP_CONTENT, WRAP_CONTENT);
-            setFlags(0, flagsToUpdate);
-        } else {
-            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
-            requestFeature(FEATURE_NO_TITLE);
-        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
-            // Don't allow an action bar if there is no title.
-            requestFeature(FEATURE_ACTION_BAR);
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
-            requestFeature(FEATURE_ACTION_BAR_OVERLAY);
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
-            requestFeature(FEATURE_ACTION_MODE_OVERLAY);
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
-            requestFeature(FEATURE_SWIPE_TO_DISMISS);
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
-            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
-                false)) {
-            setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
-                    & (~getForcedWindowFlags()));
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
-                false)) {
-            setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
-                    & (~getForcedWindowFlags()));
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
-            setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
-            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
-        }
-
-        if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
-                getContext().getApplicationInfo().targetSdkVersion
-                        >= android.os.Build.VERSION_CODES.HONEYCOMB)) {
-            setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
-        }
-
-        a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
-        a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
-        if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
-            if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
-            a.getValue(R.styleable.Window_windowFixedWidthMajor,
-                    mFixedWidthMajor);
-        }
-        if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
-            if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
-            a.getValue(R.styleable.Window_windowFixedWidthMinor,
-                    mFixedWidthMinor);
-        }
-        if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
-            if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
-            a.getValue(R.styleable.Window_windowFixedHeightMajor,
-                    mFixedHeightMajor);
-        }
-        if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
-            if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
-            a.getValue(R.styleable.Window_windowFixedHeightMinor,
-                    mFixedHeightMinor);
-        }
-        if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
-            requestFeature(FEATURE_CONTENT_TRANSITIONS);
-        }
-        if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
-            requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
-        }
-
-        final WindowManager windowService = (WindowManager) getContext().getSystemService(
-                Context.WINDOW_SERVICE);
-        if (windowService != null) {
-            final Display display = windowService.getDefaultDisplay();
-            final boolean shouldUseBottomOutset =
-                    display.getDisplayId() == Display.DEFAULT_DISPLAY
-                            || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0;
-            if (shouldUseBottomOutset && a.hasValue(R.styleable.Window_windowOutsetBottom)) {
-                if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
-                a.getValue(R.styleable.Window_windowOutsetBottom,
-                        mOutsetBottom);
-            }
-        }
-
-        final Context context = getContext();
-        final int targetSdk = context.getApplicationInfo().targetSdkVersion;
-        final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
-        final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
-        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
-        final boolean targetHcNeedsOptions = context.getResources().getBoolean(
-                R.bool.target_honeycomb_needs_options_menu);
-        final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
-
-        if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
-            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE);
-        } else {
-            setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE);
-        }
-
-        // Non-floating windows on high end devices must put up decor beneath the system bars and
-        // therefore must know about visibility changes of those.
-        if (!mIsFloating && ActivityManager.isHighEndGfx()) {
-            if (!targetPreL && a.getBoolean(
-                    R.styleable.Window_windowDrawsSystemBarBackgrounds,
-                    false)) {
-                setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                        FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
-            }
-        }
-        if (!mForcedStatusBarColor) {
-            mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
-        }
-        if (!mForcedNavigationBarColor) {
-            mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
-        }
-
-        if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
-                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
-            if (a.getBoolean(
-                    R.styleable.Window_windowCloseOnTouchOutside,
-                    false)) {
-                setCloseOnTouchOutsideIfNotSet(true);
-            }
-        }
-
-        WindowManager.LayoutParams params = getAttributes();
-
-        if (!hasSoftInputMode()) {
-            params.softInputMode = a.getInt(
-                    R.styleable.Window_windowSoftInputMode,
-                    params.softInputMode);
-        }
-
-        if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
-                mIsFloating)) {
-            /* All dialogs should have the window dimmed */
-            if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
-                params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-            }
-            if (!haveDimAmount()) {
-                params.dimAmount = a.getFloat(
-                        android.R.styleable.Window_backgroundDimAmount, 0.5f);
-            }
-        }
-
-        if (params.windowAnimations == 0) {
-            params.windowAnimations = a.getResourceId(
-                    R.styleable.Window_windowAnimationStyle, 0);
-        }
-
-        // The rest are only done if this window is not embedded; otherwise,
-        // the values are inherited from our container.
-        if (getContainer() == null) {
-            if (mBackgroundDrawable == null) {
-                if (mBackgroundResource == 0) {
-                    mBackgroundResource = a.getResourceId(
-                            R.styleable.Window_windowBackground, 0);
-                }
-                if (mFrameResource == 0) {
-                    mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
-                }
-                mBackgroundFallbackResource = a.getResourceId(
-                        R.styleable.Window_windowBackgroundFallback, 0);
-                if (false) {
-                    System.out.println("Background: "
-                            + Integer.toHexString(mBackgroundResource) + " Frame: "
-                            + Integer.toHexString(mFrameResource));
-                }
-            }
-            mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
-            mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
-            mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
-        }
-
-        // Inflate the window decor.
-
-        int layoutResource;
-        int features = getLocalFeatures();
-        // System.out.println("Features: 0x" + Integer.toHexString(features));
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            layoutResource = R.layout.screen_swipe_dismiss;
-        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
-            if (mIsFloating) {
-                TypedValue res = new TypedValue();
-                getContext().getTheme().resolveAttribute(
-                        R.attr.dialogTitleIconsDecorLayout, res, true);
-                layoutResource = res.resourceId;
-            } else {
-                layoutResource = R.layout.screen_title_icons;
-            }
-            // XXX Remove this once action bar supports these features.
-            removeFeature(FEATURE_ACTION_BAR);
-            // System.out.println("Title Icons!");
-        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
-                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
-            // Special case for a window with only a progress bar (and title).
-            // XXX Need to have a no-title version of embedded windows.
-            layoutResource = R.layout.screen_progress;
-            // System.out.println("Progress!");
-        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
-            // Special case for a window with a custom title.
-            // If the window is floating, we need a dialog layout
-            if (mIsFloating) {
-                TypedValue res = new TypedValue();
-                getContext().getTheme().resolveAttribute(
-                        R.attr.dialogCustomTitleDecorLayout, res, true);
-                layoutResource = res.resourceId;
-            } else {
-                layoutResource = R.layout.screen_custom_title;
-            }
-            // XXX Remove this once action bar supports these features.
-            removeFeature(FEATURE_ACTION_BAR);
-        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
-            // If no other features and not embedded, only need a title.
-            // If the window is floating, we need a dialog layout
-            if (mIsFloating) {
-                TypedValue res = new TypedValue();
-                getContext().getTheme().resolveAttribute(
-                        R.attr.dialogTitleDecorLayout, res, true);
-                layoutResource = res.resourceId;
-            } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
-                layoutResource = a.getResourceId(
-                        R.styleable.Window_windowActionBarFullscreenDecorLayout,
-                        R.layout.screen_action_bar);
-            } else {
-                layoutResource = R.layout.screen_title;
-            }
-            // System.out.println("Title!");
-        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
-            layoutResource = R.layout.screen_simple_overlay_action_mode;
-        } else {
-            // Embedded, so no decoration is needed.
-            layoutResource = R.layout.screen_simple;
-            // System.out.println("Simple!");
-        }
-
-        mDecor.startChanging();
-
-        View in = mLayoutInflater.inflate(layoutResource, null);
-        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-        mContentRoot = (ViewGroup) in;
-
-        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
-        if (contentParent == null) {
-            throw new RuntimeException("Window couldn't find content container view");
-        }
-
-        if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
-            ProgressBar progress = getCircularProgressBar(false);
-            if (progress != null) {
-                progress.setIndeterminate(true);
-            }
-        }
-
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            registerSwipeCallbacks();
-        }
-
-        // Remaining setup -- of background and title -- that only applies
-        // to top-level windows.
-        if (getContainer() == null) {
-            final Drawable background;
-            if (mBackgroundResource != 0) {
-                background = getContext().getDrawable(mBackgroundResource);
-            } else {
-                background = mBackgroundDrawable;
-            }
-            mDecor.setWindowBackground(background);
-
-            final Drawable frame;
-            if (mFrameResource != 0) {
-                frame = getContext().getDrawable(mFrameResource);
-            } else {
-                frame = null;
-            }
-            mDecor.setWindowFrame(frame);
-
-            mDecor.setElevation(mElevation);
-            mDecor.setClipToOutline(mClipToOutline);
-
-            if (mTitle != null) {
-                setTitle(mTitle);
-            }
-
-            if (mTitleColor == 0) {
-                mTitleColor = mTextColor;
-            }
-            setTitleColor(mTitleColor);
-        }
-
-        mDecor.finishChanging();
-
-        return contentParent;
-    }
-
-    /** @hide */
-    public void alwaysReadCloseOnTouchAttr() {
-        mAlwaysReadCloseOnTouchAttr = true;
-    }
-
-    private void installDecor() {
-        if (mDecor == null) {
-            mDecor = generateDecor();
-            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-            mDecor.setIsRootNamespace(true);
-            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
-                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
-            }
-        }
-        if (mContentParent == null) {
-            mContentParent = generateLayout(mDecor);
-
-            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
-            mDecor.makeOptionalFitsSystemWindows();
-
-            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
-                    R.id.decor_content_parent);
-
-            if (decorContentParent != null) {
-                mDecorContentParent = decorContentParent;
-                mDecorContentParent.setWindowCallback(getCallback());
-                if (mDecorContentParent.getTitle() == null) {
-                    mDecorContentParent.setWindowTitle(mTitle);
-                }
-
-                final int localFeatures = getLocalFeatures();
-                for (int i = 0; i < FEATURE_MAX; i++) {
-                    if ((localFeatures & (1 << i)) != 0) {
-                        mDecorContentParent.initFeature(i);
-                    }
-                }
-
-                mDecorContentParent.setUiOptions(mUiOptions);
-
-                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
-                        (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
-                    mDecorContentParent.setIcon(mIconRes);
-                } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
-                        mIconRes == 0 && !mDecorContentParent.hasIcon()) {
-                    mDecorContentParent.setIcon(
-                            getContext().getPackageManager().getDefaultActivityIcon());
-                    mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
-                }
-                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
-                        (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
-                    mDecorContentParent.setLogo(mLogoRes);
-                }
-
-                // Invalidate if the panel menu hasn't been created before this.
-                // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
-                // being called in the middle of onCreate or similar.
-                // A pending invalidation will typically be resolved before the posted message
-                // would run normally in order to satisfy instance state restoration.
-                PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-                if (!isDestroyed() && (st == null || st.menu == null)) {
-                    invalidatePanelMenu(FEATURE_ACTION_BAR);
-                }
-            } else {
-                mTitleView = (TextView)findViewById(R.id.title);
-                if (mTitleView != null) {
-                    mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
-                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
-                        View titleContainer = findViewById(
-                                R.id.title_container);
-                        if (titleContainer != null) {
-                            titleContainer.setVisibility(View.GONE);
-                        } else {
-                            mTitleView.setVisibility(View.GONE);
-                        }
-                        if (mContentParent instanceof FrameLayout) {
-                            ((FrameLayout)mContentParent).setForeground(null);
-                        }
-                    } else {
-                        mTitleView.setText(mTitle);
-                    }
-                }
-            }
-
-            if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
-                mDecor.setBackgroundFallback(mBackgroundFallbackResource);
-            }
-
-            // Only inflate or create a new TransitionManager if the caller hasn't
-            // already set a custom one.
-            if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
-                if (mTransitionManager == null) {
-                    final int transitionRes = getWindowStyle().getResourceId(
-                            R.styleable.Window_windowContentTransitionManager,
-                            0);
-                    if (transitionRes != 0) {
-                        final TransitionInflater inflater = TransitionInflater.from(getContext());
-                        mTransitionManager = inflater.inflateTransitionManager(transitionRes,
-                                mContentParent);
-                    } else {
-                        mTransitionManager = new TransitionManager();
-                    }
-                }
-
-                mEnterTransition = getTransition(mEnterTransition, null,
-                        R.styleable.Window_windowEnterTransition);
-                mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
-                        R.styleable.Window_windowReturnTransition);
-                mExitTransition = getTransition(mExitTransition, null,
-                        R.styleable.Window_windowExitTransition);
-                mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
-                        R.styleable.Window_windowReenterTransition);
-                mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
-                        R.styleable.Window_windowSharedElementEnterTransition);
-                mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
-                        USE_DEFAULT_TRANSITION,
-                        R.styleable.Window_windowSharedElementReturnTransition);
-                mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
-                        R.styleable.Window_windowSharedElementExitTransition);
-                mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
-                        USE_DEFAULT_TRANSITION,
-                        R.styleable.Window_windowSharedElementReenterTransition);
-                if (mAllowEnterTransitionOverlap == null) {
-                    mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
-                            R.styleable.Window_windowAllowEnterTransitionOverlap, true);
-                }
-                if (mAllowReturnTransitionOverlap == null) {
-                    mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
-                            R.styleable.Window_windowAllowReturnTransitionOverlap, true);
-                }
-                if (mBackgroundFadeDurationMillis < 0) {
-                    mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
-                            R.styleable.Window_windowTransitionBackgroundFadeDuration,
-                            DEFAULT_BACKGROUND_FADE_DURATION_MS);
-                }
-                if (mSharedElementsUseOverlay == null) {
-                    mSharedElementsUseOverlay = getWindowStyle().getBoolean(
-                            R.styleable.Window_windowSharedElementsUseOverlay, true);
-                }
-            }
-        }
-    }
-
-    private Transition getTransition(Transition currentValue, Transition defaultValue, int id) {
-        if (currentValue != defaultValue) {
-            return currentValue;
-        }
-        int transitionId = getWindowStyle().getResourceId(id, -1);
-        Transition transition = defaultValue;
-        if (transitionId != -1 && transitionId != R.transition.no_transition) {
-            TransitionInflater inflater = TransitionInflater.from(getContext());
-            transition = inflater.inflateTransition(transitionId);
-            if (transition instanceof TransitionSet &&
-                    ((TransitionSet)transition).getTransitionCount() == 0) {
-                transition = null;
-            }
-        }
-        return transition;
-    }
-
-    private Drawable loadImageURI(Uri uri) {
-        try {
-            return Drawable.createFromStream(
-                    getContext().getContentResolver().openInputStream(uri), null);
-        } catch (Exception e) {
-            Log.w(TAG, "Unable to open content: " + uri);
-        }
-        return null;
-    }
-
-    private DrawableFeatureState getDrawableState(int featureId, boolean required) {
-        if ((getFeatures() & (1 << featureId)) == 0) {
-            if (!required) {
-                return null;
-            }
-            throw new RuntimeException("The feature has not been requested");
-        }
-
-        DrawableFeatureState[] ar;
-        if ((ar = mDrawables) == null || ar.length <= featureId) {
-            DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
-            if (ar != null) {
-                System.arraycopy(ar, 0, nar, 0, ar.length);
-            }
-            mDrawables = ar = nar;
-        }
-
-        DrawableFeatureState st = ar[featureId];
-        if (st == null) {
-            ar[featureId] = st = new DrawableFeatureState(featureId);
-        }
-        return st;
-    }
-
-    /**
-     * Gets a panel's state based on its feature ID.
-     *
-     * @param featureId The feature ID of the panel.
-     * @param required Whether the panel is required (if it is required and it
-     *            isn't in our features, this throws an exception).
-     * @return The panel state.
-     */
-    private PanelFeatureState getPanelState(int featureId, boolean required) {
-        return getPanelState(featureId, required, null);
-    }
-
-    /**
-     * Gets a panel's state based on its feature ID.
-     *
-     * @param featureId The feature ID of the panel.
-     * @param required Whether the panel is required (if it is required and it
-     *            isn't in our features, this throws an exception).
-     * @param convertPanelState Optional: If the panel state does not exist, use
-     *            this as the panel state.
-     * @return The panel state.
-     */
-    private PanelFeatureState getPanelState(int featureId, boolean required,
-            PanelFeatureState convertPanelState) {
-        if ((getFeatures() & (1 << featureId)) == 0) {
-            if (!required) {
-                return null;
-            }
-            throw new RuntimeException("The feature has not been requested");
-        }
-
-        PanelFeatureState[] ar;
-        if ((ar = mPanels) == null || ar.length <= featureId) {
-            PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
-            if (ar != null) {
-                System.arraycopy(ar, 0, nar, 0, ar.length);
-            }
-            mPanels = ar = nar;
-        }
-
-        PanelFeatureState st = ar[featureId];
-        if (st == null) {
-            ar[featureId] = st = (convertPanelState != null)
-                    ? convertPanelState
-                    : new PanelFeatureState(featureId);
-        }
-        return st;
-    }
-
-    @Override
-    public final void setChildDrawable(int featureId, Drawable drawable) {
-        DrawableFeatureState st = getDrawableState(featureId, true);
-        st.child = drawable;
-        updateDrawable(featureId, st, false);
-    }
-
-    @Override
-    public final void setChildInt(int featureId, int value) {
-        updateInt(featureId, value, false);
-    }
-
-    @Override
-    public boolean isShortcutKey(int keyCode, KeyEvent event) {
-        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-        return st != null && st.menu != null && st.menu.isShortcutKey(keyCode, event);
-    }
-
-    private void updateDrawable(int featureId, DrawableFeatureState st, boolean fromResume) {
-        // Do nothing if the decor is not yet installed... an update will
-        // need to be forced when we eventually become active.
-        if (mContentParent == null) {
-            return;
-        }
-
-        final int featureMask = 1 << featureId;
-
-        if ((getFeatures() & featureMask) == 0 && !fromResume) {
-            return;
-        }
-
-        Drawable drawable = null;
-        if (st != null) {
-            drawable = st.child;
-            if (drawable == null)
-                drawable = st.local;
-            if (drawable == null)
-                drawable = st.def;
-        }
-        if ((getLocalFeatures() & featureMask) == 0) {
-            if (getContainer() != null) {
-                if (isActive() || fromResume) {
-                    getContainer().setChildDrawable(featureId, drawable);
-                }
-            }
-        } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
-            // System.out.println("Drawable changed: old=" + st.cur
-            // + ", new=" + drawable);
-            st.cur = drawable;
-            st.curAlpha = st.alpha;
-            onDrawableChanged(featureId, drawable, st.alpha);
-        }
-    }
-
-    private void updateInt(int featureId, int value, boolean fromResume) {
-
-        // Do nothing if the decor is not yet installed... an update will
-        // need to be forced when we eventually become active.
-        if (mContentParent == null) {
-            return;
-        }
-
-        final int featureMask = 1 << featureId;
-
-        if ((getFeatures() & featureMask) == 0 && !fromResume) {
-            return;
-        }
-
-        if ((getLocalFeatures() & featureMask) == 0) {
-            if (getContainer() != null) {
-                getContainer().setChildInt(featureId, value);
-            }
-        } else {
-            onIntChanged(featureId, value);
-        }
-    }
-
-    private ImageView getLeftIconView() {
-        if (mLeftIconView != null) {
-            return mLeftIconView;
-        }
-        if (mContentParent == null) {
-            installDecor();
-        }
-        return (mLeftIconView = (ImageView)findViewById(R.id.left_icon));
-    }
-
-    @Override
-    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
-        super.dispatchWindowAttributesChanged(attrs);
-        if (mDecor != null) {
-            mDecor.updateColorViews(null /* insets */, true /* animate */);
-        }
-    }
-
-    private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
-        if (mCircularProgressBar != null) {
-            return mCircularProgressBar;
-        }
-        if (mContentParent == null && shouldInstallDecor) {
-            installDecor();
-        }
-        mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
-        if (mCircularProgressBar != null) {
-            mCircularProgressBar.setVisibility(View.INVISIBLE);
-        }
-        return mCircularProgressBar;
-    }
-
-    private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
-        if (mHorizontalProgressBar != null) {
-            return mHorizontalProgressBar;
-        }
-        if (mContentParent == null && shouldInstallDecor) {
-            installDecor();
-        }
-        mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
-        if (mHorizontalProgressBar != null) {
-            mHorizontalProgressBar.setVisibility(View.INVISIBLE);
-        }
-        return mHorizontalProgressBar;
-    }
-
-    private ImageView getRightIconView() {
-        if (mRightIconView != null) {
-            return mRightIconView;
-        }
-        if (mContentParent == null) {
-            installDecor();
-        }
-        return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
-    }
-
-    private void registerSwipeCallbacks() {
-        SwipeDismissLayout swipeDismiss =
-                (SwipeDismissLayout) findViewById(R.id.content);
-        swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
-            @Override
-            public void onDismissed(SwipeDismissLayout layout) {
-                dispatchOnWindowDismissed();
-            }
-        });
-        swipeDismiss.setOnSwipeProgressChangedListener(
-                new SwipeDismissLayout.OnSwipeProgressChangedListener() {
-                    private static final float ALPHA_DECREASE = 0.5f;
-                    private boolean mIsTranslucent = false;
-                    @Override
-                    public void onSwipeProgressChanged(
-                            SwipeDismissLayout layout, float progress, float translate) {
-                        WindowManager.LayoutParams newParams = getAttributes();
-                        newParams.x = (int) translate;
-                        newParams.alpha = 1 - (progress * ALPHA_DECREASE);
-                        setAttributes(newParams);
-
-                        int flags = 0;
-                        if (newParams.x == 0) {
-                            flags = FLAG_FULLSCREEN;
-                        } else {
-                            flags = FLAG_LAYOUT_NO_LIMITS;
-                        }
-                        setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
-                    }
-
-                    @Override
-                    public void onSwipeCancelled(SwipeDismissLayout layout) {
-                        WindowManager.LayoutParams newParams = getAttributes();
-                        newParams.x = 0;
-                        newParams.alpha = 1;
-                        setAttributes(newParams);
-                        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
-                    }
-                });
-    }
-
-    /**
-     * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
-     * callback. This method will grab whatever extra state is needed for the
-     * callback that isn't given in the parameters. If the panel is not open,
-     * this will not perform the callback.
-     *
-     * @param featureId Feature ID of the panel that was closed. Must be given.
-     * @param panel Panel that was closed. Optional but useful if there is no
-     *            menu given.
-     * @param menu The menu that was closed. Optional, but give if you have.
-     */
-    private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
-        final Callback cb = getCallback();
-        if (cb == null)
-            return;
-
-        // Try to get a menu
-        if (menu == null) {
-            // Need a panel to grab the menu, so try to get that
-            if (panel == null) {
-                if ((featureId >= 0) && (featureId < mPanels.length)) {
-                    panel = mPanels[featureId];
-                }
-            }
-
-            if (panel != null) {
-                // menu still may be null, which is okay--we tried our best
-                menu = panel.menu;
-            }
-        }
-
-        // If the panel is not open, do not callback
-        if ((panel != null) && (!panel.isOpen))
-            return;
-
-        if (!isDestroyed()) {
-            cb.onPanelClosed(featureId, menu);
-        }
-    }
-
-    /**
-     * Helper method for adding launch-search to most applications. Opens the
-     * search window using default settings.
-     *
-     * @return true if search window opened
-     */
-    private boolean launchDefaultSearch() {
-        boolean result;
-        final Callback cb = getCallback();
-        if (cb == null || isDestroyed()) {
-            result = false;
-        } else {
-            sendCloseSystemWindows("search");
-            result = cb.onSearchRequested();
-        }
-        if (!result && (getContext().getResources().getConfiguration().uiMode
-                & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) {
-            // On TVs, if the app doesn't implement search, we want to launch assist.
-            return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE))
-                    .launchAssistAction(0, null, UserHandle.myUserId());
-        }
-        return result;
-    }
-
-    @Override
-    public void setVolumeControlStream(int streamType) {
-        mVolumeControlStreamType = streamType;
-    }
-
-    @Override
-    public int getVolumeControlStream() {
-        return mVolumeControlStreamType;
-    }
-
-    @Override
-    public void setMediaController(MediaController controller) {
-        mMediaController = controller;
-    }
-
-    @Override
-    public MediaController getMediaController() {
-        return mMediaController;
-    }
-
-    private boolean isTranslucent() {
-        TypedArray a = getWindowStyle();
-        return a.getBoolean(a.getResourceId(
-                R.styleable.Window_windowIsTranslucent, 0), false);
-    }
-
-    @Override
-    public void setEnterTransition(Transition enterTransition) {
-        mEnterTransition = enterTransition;
-    }
-
-    @Override
-    public void setReturnTransition(Transition transition) {
-        mReturnTransition = transition;
-    }
-
-    @Override
-    public void setExitTransition(Transition exitTransition) {
-        mExitTransition = exitTransition;
-    }
-
-    @Override
-    public void setReenterTransition(Transition transition) {
-        mReenterTransition = transition;
-    }
-
-    @Override
-    public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
-        mSharedElementEnterTransition = sharedElementEnterTransition;
-    }
-
-    @Override
-    public void setSharedElementReturnTransition(Transition transition) {
-        mSharedElementReturnTransition = transition;
-    }
-
-    @Override
-    public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
-        mSharedElementExitTransition = sharedElementExitTransition;
-    }
-
-    @Override
-    public void setSharedElementReenterTransition(Transition transition) {
-        mSharedElementReenterTransition = transition;
-    }
-
-    @Override
-    public Transition getEnterTransition() {
-        return mEnterTransition;
-    }
-
-    @Override
-    public Transition getReturnTransition() {
-        return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
-                : mReturnTransition;
-    }
-
-    @Override
-    public Transition getExitTransition() {
-        return mExitTransition;
-    }
-
-    @Override
-    public Transition getReenterTransition() {
-        return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
-                : mReenterTransition;
-    }
-
-    @Override
-    public Transition getSharedElementEnterTransition() {
-        return mSharedElementEnterTransition;
-    }
-
-    @Override
-    public Transition getSharedElementReturnTransition() {
-        return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION
-                ? getSharedElementEnterTransition() : mSharedElementReturnTransition;
-    }
-
-    @Override
-    public Transition getSharedElementExitTransition() {
-        return mSharedElementExitTransition;
-    }
-
-    @Override
-    public Transition getSharedElementReenterTransition() {
-        return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION
-                ? getSharedElementExitTransition() : mSharedElementReenterTransition;
-    }
-
-    @Override
-    public void setAllowEnterTransitionOverlap(boolean allow) {
-        mAllowEnterTransitionOverlap = allow;
-    }
-
-    @Override
-    public boolean getAllowEnterTransitionOverlap() {
-        return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
-    }
-
-    @Override
-    public void setAllowReturnTransitionOverlap(boolean allowExitTransitionOverlap) {
-        mAllowReturnTransitionOverlap = allowExitTransitionOverlap;
-    }
-
-    @Override
-    public boolean getAllowReturnTransitionOverlap() {
-        return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
-    }
-
-    @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;
-    }
-
-    @Override
-    public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
-        mSharedElementsUseOverlay = sharedElementsUseOverlay;
-    }
-
-    @Override
-    public boolean getSharedElementsUseOverlay() {
-        return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
-    }
-
-    private static final class DrawableFeatureState {
-        DrawableFeatureState(int _featureId) {
-            featureId = _featureId;
-        }
-
-        final int featureId;
-
-        int resid;
-
-        Uri uri;
-
-        Drawable local;
-
-        Drawable child;
-
-        Drawable def;
-
-        Drawable cur;
-
-        int alpha = 255;
-
-        int curAlpha = 255;
-    }
-
-    private static final class PanelFeatureState {
-
-        /** Feature ID for this panel. */
-        int featureId;
-
-        // Information pulled from the style for this panel.
-
-        int background;
-
-        /** The background when the panel spans the entire available width. */
-        int fullBackground;
-
-        int gravity;
-
-        int x;
-
-        int y;
-
-        int windowAnimations;
-
-        /** Dynamic state of the panel. */
-        DecorView decorView;
-
-        /** The panel that was returned by onCreatePanelView(). */
-        View createdPanelView;
-
-        /** The panel that we are actually showing. */
-        View shownPanelView;
-
-        /** Use {@link #setMenu} to set this. */
-        MenuBuilder menu;
-
-        IconMenuPresenter iconMenuPresenter;
-        ListMenuPresenter listMenuPresenter;
-
-        /** true if this menu will show in single-list compact mode */
-        boolean isCompact;
-
-        /** Theme resource ID for list elements of the panel menu */
-        int listPresenterTheme;
-
-        /**
-         * Whether the panel has been prepared (see
-         * {@link PhoneWindow#preparePanel}).
-         */
-        boolean isPrepared;
-
-        /**
-         * Whether an item's action has been performed. This happens in obvious
-         * scenarios (user clicks on menu item), but can also happen with
-         * chording menu+(shortcut key).
-         */
-        boolean isHandled;
-
-        boolean isOpen;
-
-        /**
-         * True if the menu is in expanded mode, false if the menu is in icon
-         * mode
-         */
-        boolean isInExpandedMode;
-
-        public boolean qwertyMode;
-
-        boolean refreshDecorView;
-
-        boolean refreshMenuContent;
-
-        boolean wasLastOpen;
-
-        boolean wasLastExpanded;
-
-        /**
-         * Contains the state of the menu when told to freeze.
-         */
-        Bundle frozenMenuState;
-
-        /**
-         * Contains the state of associated action views when told to freeze.
-         * These are saved across invalidations.
-         */
-        Bundle frozenActionViewState;
-
-        PanelFeatureState(int featureId) {
-            this.featureId = featureId;
-
-            refreshDecorView = false;
-        }
-
-        public boolean isInListMode() {
-            return isInExpandedMode || isCompact;
-        }
-
-        public boolean hasPanelItems() {
-            if (shownPanelView == null) return false;
-            if (createdPanelView != null) return true;
-
-            if (isCompact || isInExpandedMode) {
-                return listMenuPresenter.getAdapter().getCount() > 0;
-            } else {
-                return ((ViewGroup) shownPanelView).getChildCount() > 0;
-            }
-        }
-
-        /**
-         * Unregister and free attached MenuPresenters. They will be recreated as needed.
-         */
-        public void clearMenuPresenters() {
-            if (menu != null) {
-                menu.removeMenuPresenter(iconMenuPresenter);
-                menu.removeMenuPresenter(listMenuPresenter);
-            }
-            iconMenuPresenter = null;
-            listMenuPresenter = null;
-        }
-
-        void setStyle(Context context) {
-            TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
-            background = a.getResourceId(
-                    R.styleable.Theme_panelBackground, 0);
-            fullBackground = a.getResourceId(
-                    R.styleable.Theme_panelFullBackground, 0);
-            windowAnimations = a.getResourceId(
-                    R.styleable.Theme_windowAnimationStyle, 0);
-            isCompact = a.getBoolean(
-                    R.styleable.Theme_panelMenuIsCompact, false);
-            listPresenterTheme = a.getResourceId(
-                    R.styleable.Theme_panelMenuListTheme,
-                    R.style.Theme_ExpandedMenu);
-            a.recycle();
-        }
-
-        void setMenu(MenuBuilder menu) {
-            if (menu == this.menu) return;
-
-            if (this.menu != null) {
-                this.menu.removeMenuPresenter(iconMenuPresenter);
-                this.menu.removeMenuPresenter(listMenuPresenter);
-            }
-            this.menu = menu;
-            if (menu != null) {
-                if (iconMenuPresenter != null) menu.addMenuPresenter(iconMenuPresenter);
-                if (listMenuPresenter != null) menu.addMenuPresenter(listMenuPresenter);
-            }
-        }
-
-        MenuView getListMenuView(Context context, MenuPresenter.Callback cb) {
-            if (menu == null) return null;
-
-            if (!isCompact) {
-                getIconMenuView(context, cb); // Need this initialized to know where our offset goes
-            }
-
-            if (listMenuPresenter == null) {
-                listMenuPresenter = new ListMenuPresenter(
-                        R.layout.list_menu_item_layout, listPresenterTheme);
-                listMenuPresenter.setCallback(cb);
-                listMenuPresenter.setId(R.id.list_menu_presenter);
-                menu.addMenuPresenter(listMenuPresenter);
-            }
-
-            if (iconMenuPresenter != null) {
-                listMenuPresenter.setItemIndexOffset(
-                        iconMenuPresenter.getNumActualItemsShown());
-            }
-            MenuView result = listMenuPresenter.getMenuView(decorView);
-
-            return result;
-        }
-
-        MenuView getIconMenuView(Context context, MenuPresenter.Callback cb) {
-            if (menu == null) return null;
-
-            if (iconMenuPresenter == null) {
-                iconMenuPresenter = new IconMenuPresenter(context);
-                iconMenuPresenter.setCallback(cb);
-                iconMenuPresenter.setId(R.id.icon_menu_presenter);
-                menu.addMenuPresenter(iconMenuPresenter);
-            }
-
-            MenuView result = iconMenuPresenter.getMenuView(decorView);
-
-            return result;
-        }
-
-        Parcelable onSaveInstanceState() {
-            SavedState savedState = new SavedState();
-            savedState.featureId = featureId;
-            savedState.isOpen = isOpen;
-            savedState.isInExpandedMode = isInExpandedMode;
-
-            if (menu != null) {
-                savedState.menuState = new Bundle();
-                menu.savePresenterStates(savedState.menuState);
-            }
-
-            return savedState;
-        }
-
-        void onRestoreInstanceState(Parcelable state) {
-            SavedState savedState = (SavedState) state;
-            featureId = savedState.featureId;
-            wasLastOpen = savedState.isOpen;
-            wasLastExpanded = savedState.isInExpandedMode;
-            frozenMenuState = savedState.menuState;
-
-            /*
-             * A LocalActivityManager keeps the same instance of this class around.
-             * The first time the menu is being shown after restoring, the
-             * Activity.onCreateOptionsMenu should be called. But, if it is the
-             * same instance then menu != null and we won't call that method.
-             * We clear any cached views here. The caller should invalidatePanelMenu.
-             */
-            createdPanelView = null;
-            shownPanelView = null;
-            decorView = null;
-        }
-
-        void applyFrozenState() {
-            if (menu != null && frozenMenuState != null) {
-                menu.restorePresenterStates(frozenMenuState);
-                frozenMenuState = null;
-            }
-        }
-
-        private static class SavedState implements Parcelable {
-            int featureId;
-            boolean isOpen;
-            boolean isInExpandedMode;
-            Bundle menuState;
-
-            public int describeContents() {
-                return 0;
-            }
-
-            public void writeToParcel(Parcel dest, int flags) {
-                dest.writeInt(featureId);
-                dest.writeInt(isOpen ? 1 : 0);
-                dest.writeInt(isInExpandedMode ? 1 : 0);
-
-                if (isOpen) {
-                    dest.writeBundle(menuState);
-                }
-            }
-
-            private static SavedState readFromParcel(Parcel source) {
-                SavedState savedState = new SavedState();
-                savedState.featureId = source.readInt();
-                savedState.isOpen = source.readInt() == 1;
-                savedState.isInExpandedMode = source.readInt() == 1;
-
-                if (savedState.isOpen) {
-                    savedState.menuState = source.readBundle();
-                }
-
-                return savedState;
-            }
-
-            public static final Parcelable.Creator<SavedState> CREATOR
-                    = new Parcelable.Creator<SavedState>() {
-                public SavedState createFromParcel(Parcel in) {
-                    return readFromParcel(in);
-                }
-
-                public SavedState[] newArray(int size) {
-                    return new SavedState[size];
-                }
-            };
-        }
-
-    }
-
-    static class RotationWatcher extends IRotationWatcher.Stub {
-        private Handler mHandler;
-        private final Runnable mRotationChanged = new Runnable() {
-            public void run() {
-                dispatchRotationChanged();
-            }
-        };
-        private final ArrayList<WeakReference<PhoneWindow>> mWindows =
-                new ArrayList<WeakReference<PhoneWindow>>();
-        private boolean mIsWatching;
-
-        @Override
-        public void onRotationChanged(int rotation) throws RemoteException {
-            mHandler.post(mRotationChanged);
-        }
-
-        public void addWindow(PhoneWindow phoneWindow) {
-            synchronized (mWindows) {
-                if (!mIsWatching) {
-                    try {
-                        WindowManagerHolder.sWindowManager.watchRotation(this);
-                        mHandler = new Handler();
-                        mIsWatching = true;
-                    } catch (RemoteException ex) {
-                        Log.e(TAG, "Couldn't start watching for device rotation", ex);
-                    }
-                }
-                mWindows.add(new WeakReference<PhoneWindow>(phoneWindow));
-            }
-        }
-
-        public void removeWindow(PhoneWindow phoneWindow) {
-            synchronized (mWindows) {
-                int i = 0;
-                while (i < mWindows.size()) {
-                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
-                    final PhoneWindow win = ref.get();
-                    if (win == null || win == phoneWindow) {
-                        mWindows.remove(i);
-                    } else {
-                        i++;
-                    }
-                }
-            }
-        }
-
-        void dispatchRotationChanged() {
-            synchronized (mWindows) {
-                int i = 0;
-                while (i < mWindows.size()) {
-                    final WeakReference<PhoneWindow> ref = mWindows.get(i);
-                    final PhoneWindow win = ref.get();
-                    if (win != null) {
-                        win.onOptionsPanelRotationChanged();
-                        i++;
-                    } else {
-                        mWindows.remove(i);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Simple implementation of MenuBuilder.Callback that:
-     * <li> Opens a submenu when selected.
-     * <li> Calls back to the callback's onMenuItemSelected when an item is
-     * selected.
-     */
-    private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
-        private int mFeatureId;
-        private MenuDialogHelper mSubMenuHelper;
-
-        public DialogMenuCallback(int featureId) {
-            mFeatureId = featureId;
-        }
-
-        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-            if (menu.getRootMenu() != menu) {
-                onCloseSubMenu(menu);
-            }
-
-            if (allMenusAreClosing) {
-                Callback callback = getCallback();
-                if (callback != null && !isDestroyed()) {
-                    callback.onPanelClosed(mFeatureId, menu);
-                }
-
-                if (menu == mContextMenu) {
-                    dismissContextMenu();
-                }
-
-                // Dismiss the submenu, if it is showing
-                if (mSubMenuHelper != null) {
-                    mSubMenuHelper.dismiss();
-                    mSubMenuHelper = null;
-                }
-            }
-        }
-
-        public void onCloseSubMenu(MenuBuilder menu) {
-            Callback callback = getCallback();
-            if (callback != null && !isDestroyed()) {
-                callback.onPanelClosed(mFeatureId, menu.getRootMenu());
-            }
-        }
-
-        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-            Callback callback = getCallback();
-            return (callback != null && !isDestroyed())
-                    && callback.onMenuItemSelected(mFeatureId, item);
-        }
-
-        public void onMenuModeChange(MenuBuilder menu) {
-        }
-
-        public boolean onOpenSubMenu(MenuBuilder subMenu) {
-            if (subMenu == null) return false;
-
-            // Set a simple callback for the submenu
-            subMenu.setCallback(this);
-
-            // The window manager will give us a valid window token
-            mSubMenuHelper = new MenuDialogHelper(subMenu);
-            mSubMenuHelper.show(null);
-
-            return true;
-        }
-    }
-
-    private static class ColorViewState {
-        View view = null;
-        int targetVisibility = View.INVISIBLE;
-
-        final int id;
-        final int systemUiHideFlag;
-        final int translucentFlag;
-        final int verticalGravity;
-        final String transitionName;
-        final int hideWindowFlag;
-
-        ColorViewState(int systemUiHideFlag,
-                int translucentFlag, int verticalGravity,
-                String transitionName, int id, int hideWindowFlag) {
-            this.id = id;
-            this.systemUiHideFlag = systemUiHideFlag;
-            this.translucentFlag = translucentFlag;
-            this.verticalGravity = verticalGravity;
-            this.transitionName = transitionName;
-            this.hideWindowFlag = hideWindowFlag;
-        }
-    }
-
-    void sendCloseSystemWindows() {
-        PhoneWindowManager.sendCloseSystemWindows(getContext(), null);
-    }
-
-    void sendCloseSystemWindows(String reason) {
-        PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
-    }
-
-    @Override
-    public int getStatusBarColor() {
-        return mStatusBarColor;
-    }
-
-    @Override
-    public void setStatusBarColor(int color) {
-        mStatusBarColor = color;
-        mForcedStatusBarColor = true;
-        if (mDecor != null) {
-            mDecor.updateColorViews(null, false /* animate */);
-        }
-    }
-
-    @Override
-    public int getNavigationBarColor() {
-        return mNavigationBarColor;
-    }
-
-    @Override
-    public void setNavigationBarColor(int color) {
-        mNavigationBarColor = color;
-        mForcedNavigationBarColor = true;
-        if (mDecor != null) {
-            mDecor.updateColorViews(null, false /* animate */);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
deleted file mode 100644
index e855cf1..0000000
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ /dev/null
@@ -1,6392 +0,0 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.policy.impl;
-
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.AppOpsManager;
-import android.app.IUiModeManager;
-import android.app.ProgressDialog;
-import android.app.SearchManager;
-import android.app.StatusBarManager;
-import android.app.UiModeManager;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.IAudioService;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.media.session.MediaSessionLegacyHelper;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.FactoryTest;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UEventObserver;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.MediaStore;
-import android.provider.Settings;
-import android.service.dreams.DreamManagerInternal;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
-import android.speech.RecognizerIntent;
-import android.telecom.TelecomManager;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
-import android.view.IApplicationToken;
-import android.view.IWindowManager;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.KeyCharacterMap;
-import android.view.KeyCharacterMap.FallbackAction;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.WindowManagerPolicy;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnimationUtils;
-
-import com.android.internal.R;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
-import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.widget.PointerLocationView;
-import com.android.server.LocalServices;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.HashSet;
-import java.util.List;
-
-import static android.view.WindowManager.LayoutParams.*;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
-
-/**
- * WindowManagerPolicy implementation for the Android phone UI.  This
- * introduces a new method suffix, Lp, for an internal lock of the
- * PhoneWindowManager.  This is used to protect some internal state, and
- * can be acquired with either the Lw and Li lock held, so has the restrictions
- * of both of those when held.
- */
-public class PhoneWindowManager implements WindowManagerPolicy {
-    static final String TAG = "WindowManager";
-    static final boolean DEBUG = false;
-    static final boolean localLOGV = false;
-    static final boolean DEBUG_INPUT = false;
-    static final boolean DEBUG_KEYGUARD = false;
-    static final boolean DEBUG_LAYOUT = false;
-    static final boolean DEBUG_STARTING_WINDOW = false;
-    static final boolean DEBUG_WAKEUP = false;
-    static final boolean SHOW_STARTING_ANIMATIONS = true;
-    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
-
-    // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
-    // No longer recommended for desk docks; still useful in car docks.
-    static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
-    static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
-
-    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;
-    static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
-
-    static final int LONG_PRESS_POWER_NOTHING = 0;
-    static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
-    static final int LONG_PRESS_POWER_SHUT_OFF = 2;
-    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
-
-    static final int MULTI_PRESS_POWER_NOTHING = 0;
-    static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
-    static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
-
-    // These need to match the documentation/constant in
-    // core/res/res/values/config.xml
-    static final int LONG_PRESS_HOME_NOTHING = 0;
-    static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 1;
-    static final int LONG_PRESS_HOME_ASSIST = 2;
-
-    static final int DOUBLE_TAP_HOME_NOTHING = 0;
-    static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
-
-    static final int APPLICATION_MEDIA_SUBLAYER = -2;
-    static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
-    static final int APPLICATION_PANEL_SUBLAYER = 1;
-    static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
-    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
-    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
-    static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
-    static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
-    static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
-
-    /**
-     * These are the system UI flags that, when changing, can cause the layout
-     * of the screen to change.
-     */
-    static final int SYSTEM_UI_CHANGING_LAYOUT =
-              View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
-            | View.SYSTEM_UI_FLAG_FULLSCREEN
-            | View.STATUS_BAR_TRANSLUCENT
-            | View.NAVIGATION_BAR_TRANSLUCENT
-            | View.SYSTEM_UI_TRANSPARENT;
-
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
-    /**
-     * Keyguard stuff
-     */
-    private WindowState mKeyguardScrim;
-    private boolean mKeyguardHidden;
-    private boolean mKeyguardDrawnOnce;
-
-    /* Table of Application Launch keys.  Maps from key codes to intent categories.
-     *
-     * These are special keys that are used to launch particular kinds of applications,
-     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
-     * usage page.  We don't support quite that many yet...
-     */
-    static SparseArray<String> sApplicationLaunchKeyCategories;
-    static {
-        sApplicationLaunchKeyCategories = new SparseArray<String>();
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
-        sApplicationLaunchKeyCategories.append(
-                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
-    }
-
-    /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
-    static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
-
-    /**
-     * Lock protecting internal state.  Must not call out into window
-     * manager with lock held.  (This lock will be acquired in places
-     * where the window manager is calling in with its own lock held.)
-     */
-    private final Object mLock = new Object();
-
-    Context mContext;
-    IWindowManager mWindowManager;
-    WindowManagerFuncs mWindowManagerFuncs;
-    WindowManagerInternal mWindowManagerInternal;
-    PowerManager mPowerManager;
-    DreamManagerInternal mDreamManagerInternal;
-    IStatusBarService mStatusBarService;
-    boolean mPreloadedRecentApps;
-    final Object mServiceAquireLock = new Object();
-    Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
-    SearchManager mSearchManager;
-    AccessibilityManager mAccessibilityManager;
-
-    // Vibrator pattern for haptic feedback of a long press.
-    long[] mLongPressVibePattern;
-
-    // Vibrator pattern for haptic feedback of virtual key press.
-    long[] mVirtualKeyVibePattern;
-
-    // Vibrator pattern for a short vibration.
-    long[] mKeyboardTapVibePattern;
-
-    // Vibrator pattern for a short vibration when tapping on an hour/minute tick of a Clock.
-    long[] mClockTickVibePattern;
-
-    // Vibrator pattern for a short vibration when tapping on a day/month/year date of a Calendar.
-    long[] mCalendarDateVibePattern;
-
-    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
-    long[] mSafeModeDisabledVibePattern;
-
-    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
-    long[] mSafeModeEnabledVibePattern;
-
-    /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
-    boolean mEnableShiftMenuBugReports = false;
-
-    boolean mSafeMode;
-    WindowState mStatusBar = null;
-    int mStatusBarHeight;
-    WindowState mNavigationBar = null;
-    boolean mHasNavigationBar = false;
-    boolean mCanHideNavigationBar = false;
-    boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
-    boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*?
-    int[] mNavigationBarHeightForRotation = new int[4];
-    int[] mNavigationBarWidthForRotation = new int[4];
-
-    boolean mBootMessageNeedsHiding;
-    KeyguardServiceDelegate mKeyguardDelegate;
-    final Runnable mWindowManagerDrawCallback = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
-            mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);
-        }
-    };
-    final ShowListener mKeyguardDelegateCallback = new ShowListener() {
-        @Override
-        public void onShown(IBinder windowToken) {
-            if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onShown.");
-            mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
-        }
-    };
-
-    GlobalActions mGlobalActions;
-    Handler mHandler;
-    WindowState mLastInputMethodWindow = null;
-    WindowState mLastInputMethodTargetWindow = null;
-
-    // FIXME This state is shared between the input reader and handler thread.
-    // Technically it's broken and buggy but it has been like this for many years
-    // and we have not yet seen any problems.  Someday we'll rewrite this logic
-    // so that only one thread is involved in handling input policy.  Unfortunately
-    // it's on a critical path for power management so we can't just post the work to the
-    // handler thread.  We'll need to resolve this someday by teaching the input dispatcher
-    // to hold wakelocks during dispatch and eliminating the critical path.
-    volatile boolean mPowerKeyHandled;
-    volatile boolean mBeganFromNonInteractive;
-    volatile int mPowerKeyPressCounter;
-    volatile boolean mEndCallKeyHandled;
-
-    boolean mRecentsVisible;
-    int mRecentAppsHeldModifiers;
-    boolean mLanguageSwitchKeyPressed;
-
-    int mLidState = LID_ABSENT;
-    int mCameraLensCoverState = CAMERA_LENS_COVER_ABSENT;
-    boolean mHaveBuiltInKeyboard;
-
-    boolean mSystemReady;
-    boolean mSystemBooted;
-    boolean mHdmiPlugged;
-    IUiModeManager mUiModeManager;
-    int mUiMode;
-    int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    int mLidOpenRotation;
-    int mCarDockRotation;
-    int mDeskDockRotation;
-    int mUndockedHdmiRotation;
-    int mDemoHdmiRotation;
-    boolean mDemoHdmiRotationLock;
-    int mDemoRotation;
-    boolean mDemoRotationLock;
-
-    boolean mWakeGestureEnabledSetting;
-    MyWakeGestureListener mWakeGestureListener;
-
-    // Default display does not rotate, apps that require non-default orientation will have to
-    // have the orientation emulated.
-    private boolean mForceDefaultOrientation = false;
-
-    int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
-    int mUserRotation = Surface.ROTATION_0;
-    boolean mAccelerometerDefault;
-
-    boolean mSupportAutoRotation;
-    int mAllowAllRotations = -1;
-    boolean mCarDockEnablesAccelerometer;
-    boolean mDeskDockEnablesAccelerometer;
-    int mLidKeyboardAccessibility;
-    int mLidNavigationAccessibility;
-    boolean mLidControlsSleep;
-    int mShortPressOnPowerBehavior;
-    int mLongPressOnPowerBehavior;
-    int mDoublePressOnPowerBehavior;
-    int mTriplePressOnPowerBehavior;
-    boolean mAwake;
-    boolean mScreenOnEarly;
-    boolean mScreenOnFully;
-    ScreenOnListener mScreenOnListener;
-    boolean mKeyguardDrawComplete;
-    boolean mWindowManagerDrawComplete;
-    boolean mOrientationSensorEnabled = false;
-    int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-    boolean mHasSoftInput = false;
-    boolean mTranslucentDecorEnabled = true;
-
-    int mPointerLocationMode = 0; // guarded by mLock
-
-    // The last window we were told about in focusChanged.
-    WindowState mFocusedWindow;
-    IApplicationToken mFocusedApp;
-
-    PointerLocationView mPointerLocationView;
-
-    // The current size of the screen; really; extends into the overscan area of
-    // the screen and doesn't account for any system elements like the status bar.
-    int mOverscanScreenLeft, mOverscanScreenTop;
-    int mOverscanScreenWidth, mOverscanScreenHeight;
-    // The current visible size of the screen; really; (ir)regardless of whether the status
-    // bar can be hidden but not extending into the overscan area.
-    int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
-    int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
-    // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate.
-    int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop;
-    int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight;
-    // The current size of the screen; these may be different than (0,0)-(dw,dh)
-    // if the status bar can't be hidden; in that case it effectively carves out
-    // that area of the display from all other windows.
-    int mRestrictedScreenLeft, mRestrictedScreenTop;
-    int mRestrictedScreenWidth, mRestrictedScreenHeight;
-    // During layout, the current screen borders accounting for any currently
-    // visible system UI elements.
-    int mSystemLeft, mSystemTop, mSystemRight, mSystemBottom;
-    // For applications requesting stable content insets, these are them.
-    int mStableLeft, mStableTop, mStableRight, mStableBottom;
-    // For applications requesting stable content insets but have also set the
-    // fullscreen window flag, these are the stable dimensions without the status bar.
-    int mStableFullscreenLeft, mStableFullscreenTop;
-    int mStableFullscreenRight, mStableFullscreenBottom;
-    // During layout, the current screen borders with all outer decoration
-    // (status bar, input method dock) accounted for.
-    int mCurLeft, mCurTop, mCurRight, mCurBottom;
-    // During layout, the frame in which content should be displayed
-    // to the user, accounting for all screen decoration except for any
-    // space they deem as available for other content.  This is usually
-    // the same as mCur*, but may be larger if the screen decor has supplied
-    // content insets.
-    int mContentLeft, mContentTop, mContentRight, mContentBottom;
-    // During layout, the frame in which voice content should be displayed
-    // to the user, accounting for all screen decoration except for any
-    // space they deem as available for other content.
-    int mVoiceContentLeft, mVoiceContentTop, mVoiceContentRight, mVoiceContentBottom;
-    // During layout, the current screen borders along which input method
-    // windows are placed.
-    int mDockLeft, mDockTop, mDockRight, mDockBottom;
-    // During layout, the layer at which the doc window is placed.
-    int mDockLayer;
-    // During layout, this is the layer of the status bar.
-    int mStatusBarLayer;
-    int mLastSystemUiFlags;
-    // Bits that we are in the process of clearing, so we want to prevent
-    // them from being set by applications until everything has been updated
-    // to have them clear.
-    int mResettingSystemUiFlags = 0;
-    // Bits that we are currently always keeping cleared.
-    int mForceClearedSystemUiFlags = 0;
-    // What we last reported to system UI about whether the compatibility
-    // menu needs to be displayed.
-    boolean mLastFocusNeedsMenu = false;
-
-    FakeWindow mHideNavFakeWindow = null;
-
-    static final Rect mTmpParentFrame = new Rect();
-    static final Rect mTmpDisplayFrame = new Rect();
-    static final Rect mTmpOverscanFrame = new Rect();
-    static final Rect mTmpContentFrame = new Rect();
-    static final Rect mTmpVisibleFrame = new Rect();
-    static final Rect mTmpDecorFrame = new Rect();
-    static final Rect mTmpStableFrame = new Rect();
-    static final Rect mTmpNavigationFrame = new Rect();
-
-    WindowState mTopFullscreenOpaqueWindowState;
-    HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
-    HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
-    boolean mTopIsFullscreen;
-    boolean mForceStatusBar;
-    boolean mForceStatusBarFromKeyguard;
-    boolean mHideLockScreen;
-    boolean mForcingShowNavBar;
-    int mForcingShowNavBarLayer;
-
-    // States of keyguard dismiss.
-    private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
-    private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
-    private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
-    int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
-
-    /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
-     * 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;
-    boolean mKeyguardSecure;
-    boolean mKeyguardSecureIncludingHidden;
-    volatile boolean mKeyguardOccluded;
-    boolean mHomePressed;
-    boolean mHomeConsumed;
-    boolean mHomeDoubleTapPending;
-    Intent mHomeIntent;
-    Intent mCarDockIntent;
-    Intent mDeskDockIntent;
-    boolean mSearchKeyShortcutPending;
-    boolean mConsumeSearchKeyUp;
-    boolean mAssistKeyLongPressed;
-    boolean mPendingMetaAction;
-
-    // support for activating the lock screen while the screen is on
-    boolean mAllowLockscreenWhenOn;
-    int mLockScreenTimeout;
-    boolean mLockScreenTimerActive;
-
-    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
-    int mEndcallBehavior;
-
-    // Behavior of POWER button while in-call and screen on.
-    // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
-    int mIncallPowerBehavior;
-
-    Display mDisplay;
-
-    int mLandscapeRotation = 0;  // default landscape rotation
-    int mSeascapeRotation = 0;   // "other" landscape rotation, 180 degrees from mLandscapeRotation
-    int mPortraitRotation = 0;   // default portrait rotation
-    int mUpsideDownRotation = 0; // "other" portrait rotation
-
-    int mOverscanLeft = 0;
-    int mOverscanTop = 0;
-    int mOverscanRight = 0;
-    int mOverscanBottom = 0;
-
-    // What we do when the user long presses on home
-    private int mLongPressOnHomeBehavior;
-
-    // What we do when the user double-taps on home
-    private int mDoubleTapOnHomeBehavior;
-
-    // Allowed theater mode wake actions
-    private boolean mAllowTheaterModeWakeFromKey;
-    private boolean mAllowTheaterModeWakeFromPowerKey;
-    private boolean mAllowTheaterModeWakeFromMotion;
-    private boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming;
-    private boolean mAllowTheaterModeWakeFromCameraLens;
-    private boolean mAllowTheaterModeWakeFromLidSwitch;
-    private boolean mAllowTheaterModeWakeFromWakeGesture;
-
-    // Whether to go to sleep entering theater mode from power button
-    private boolean mGoToSleepOnButtonPressTheaterMode;
-
-    // Screenshot trigger states
-    // Time to volume and power must be pressed within this interval of each other.
-    private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
-    // Increase the chord delay when taking a screenshot from the keyguard
-    private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
-    private boolean mScreenshotChordEnabled;
-    private boolean mScreenshotChordVolumeDownKeyTriggered;
-    private long mScreenshotChordVolumeDownKeyTime;
-    private boolean mScreenshotChordVolumeDownKeyConsumed;
-    private boolean mScreenshotChordVolumeUpKeyTriggered;
-    private boolean mScreenshotChordPowerKeyTriggered;
-    private long mScreenshotChordPowerKeyTime;
-
-    /* The number of steps between min and max brightness */
-    private static final int BRIGHTNESS_STEPS = 10;
-
-    SettingsObserver mSettingsObserver;
-    ShortcutManager mShortcutManager;
-    PowerManager.WakeLock mBroadcastWakeLock;
-    PowerManager.WakeLock mPowerKeyWakeLock;
-    boolean mHavePendingMediaKeyRepeatWithWakeLock;
-
-    private int mCurrentUserId;
-
-    // Maps global key codes to the components that will handle them.
-    private GlobalKeyManager mGlobalKeyManager;
-
-    // Fallback actions by key code.
-    private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
-            new SparseArray<KeyCharacterMap.FallbackAction>();
-
-    private final LogDecelerateInterpolator mLogDecelerateInterpolator
-            = new LogDecelerateInterpolator(100, 0);
-
-    private static final int MSG_ENABLE_POINTER_LOCATION = 1;
-    private static final int MSG_DISABLE_POINTER_LOCATION = 2;
-    private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
-    private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
-    private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
-    private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6;
-    private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7;
-    private static final int MSG_DISPATCH_SHOW_RECENTS = 9;
-    private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
-    private static final int MSG_HIDE_BOOT_MESSAGE = 11;
-    private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
-    private static final int MSG_POWER_DELAYED_PRESS = 13;
-    private static final int MSG_POWER_LONG_PRESS = 14;
-
-    private class PolicyHandler extends Handler {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ENABLE_POINTER_LOCATION:
-                    enablePointerLocation();
-                    break;
-                case MSG_DISABLE_POINTER_LOCATION:
-                    disablePointerLocation();
-                    break;
-                case MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK:
-                    dispatchMediaKeyWithWakeLock((KeyEvent)msg.obj);
-                    break;
-                case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
-                    dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
-                    break;
-                case MSG_DISPATCH_SHOW_RECENTS:
-                    showRecentApps(false);
-                    break;
-                case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
-                    showGlobalActionsInternal();
-                    break;
-                case MSG_KEYGUARD_DRAWN_COMPLETE:
-                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete");
-                    finishKeyguardDrawn();
-                    break;
-                case MSG_KEYGUARD_DRAWN_TIMEOUT:
-                    Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
-                    finishKeyguardDrawn();
-                    break;
-                case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
-                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
-                    finishWindowsDrawn();
-                    break;
-                case MSG_HIDE_BOOT_MESSAGE:
-                    handleHideBootMessage();
-                    break;
-                case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
-                    launchVoiceAssistWithWakeLock(msg.arg1 != 0);
-                    break;
-                case MSG_POWER_DELAYED_PRESS:
-                    powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
-                    finishPowerKeyPress();
-                    break;
-                case MSG_POWER_LONG_PRESS:
-                    powerLongPress();
-                    break;
-            }
-        }
-    }
-
-    private UEventObserver mHDMIObserver = new UEventObserver() {
-        @Override
-        public void onUEvent(UEventObserver.UEvent event) {
-            setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
-        }
-    };
-
-    class SettingsObserver extends ContentObserver {
-        SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        void observe() {
-            // Observe all users' changes
-            ContentResolver resolver = mContext.getContentResolver();
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.END_BUTTON_BEHAVIOR), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.ACCELEROMETER_ROTATION), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.USER_ROTATION), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.SCREEN_OFF_TIMEOUT), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.POINTER_LOCATION), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
-                    UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.POLICY_CONTROL), false, this,
-                    UserHandle.USER_ALL);
-            updateSettings();
-        }
-
-        @Override public void onChange(boolean selfChange) {
-            updateSettings();
-            updateRotation(false);
-        }
-    }
-
-    class MyWakeGestureListener extends WakeGestureListener {
-        MyWakeGestureListener(Context context, Handler handler) {
-            super(context, handler);
-        }
-
-        @Override
-        public void onWakeUp() {
-            synchronized (mLock) {
-                if (shouldEnableWakeGestureLp()) {
-                    performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-                    wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture);
-                }
-            }
-        }
-    }
-
-    class MyOrientationListener extends WindowOrientationListener {
-        MyOrientationListener(Context context, Handler handler) {
-            super(context, handler);
-        }
-
-        @Override
-        public void onProposedRotationChanged(int rotation) {
-            if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
-            updateRotation(false);
-        }
-    }
-    MyOrientationListener mOrientationListener;
-
-    private final BarController mStatusBarController = new BarController("StatusBar",
-            View.STATUS_BAR_TRANSIENT,
-            View.STATUS_BAR_UNHIDE,
-            View.STATUS_BAR_TRANSLUCENT,
-            StatusBarManager.WINDOW_STATUS_BAR,
-            WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
-    private final BarController mNavigationBarController = new BarController("NavigationBar",
-            View.NAVIGATION_BAR_TRANSIENT,
-            View.NAVIGATION_BAR_UNHIDE,
-            View.NAVIGATION_BAR_TRANSLUCENT,
-            StatusBarManager.WINDOW_NAVIGATION_BAR,
-            WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-
-    private ImmersiveModeConfirmation mImmersiveModeConfirmation;
-
-    private SystemGesturesPointerEventListener mSystemGestures;
-
-    IStatusBarService getStatusBarService() {
-        synchronized (mServiceAquireLock) {
-            if (mStatusBarService == null) {
-                mStatusBarService = IStatusBarService.Stub.asInterface(
-                        ServiceManager.getService("statusbar"));
-            }
-            return mStatusBarService;
-        }
-    }
-
-    /*
-     * We always let the sensor be switched on by default except when
-     * the user has explicitly disabled sensor based rotation or when the
-     * screen is switched off.
-     */
-    boolean needSensorRunningLp() {
-        if (mSupportAutoRotation) {
-            if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
-                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
-                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
-                // If the application has explicitly requested to follow the
-                // orientation, then we need to turn the sensor on.
-                return true;
-            }
-        }
-        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
-                (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
-                        || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
-                        || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
-            // enable accelerometer if we are docked in a dock that enables accelerometer
-            // orientation management,
-            return true;
-        }
-        if (mUserRotationMode == USER_ROTATION_LOCKED) {
-            // If the setting for using the sensor by default is enabled, then
-            // we will always leave it on.  Note that the user could go to
-            // a window that forces an orientation that does not use the
-            // sensor and in theory we could turn it off... however, when next
-            // turning it on we won't have a good value for the current
-            // orientation for a little bit, which can cause orientation
-            // changes to lag, so we'd like to keep it always on.  (It will
-            // still be turned off when the screen is off.)
-            return false;
-        }
-        return mSupportAutoRotation;
-    }
-
-    /*
-     * Various use cases for invoking this function
-     * screen turning off, should always disable listeners if already enabled
-     * screen turned on and current app has sensor based orientation, enable listeners
-     * if not already enabled
-     * screen turned on and current app does not have sensor orientation, disable listeners if
-     * already enabled
-     * screen turning on and current app has sensor based orientation, enable listeners if needed
-     * screen turning on and current app has nosensor based orientation, do nothing
-     */
-    void updateOrientationListenerLp() {
-        if (!mOrientationListener.canDetectOrientation()) {
-            // If sensor is turned off or nonexistent for some reason
-            return;
-        }
-        //Could have been invoked due to screen turning on or off or
-        //change of the currently visible window's orientation
-        if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly
-                + ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation
-                + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled);
-        boolean disable = true;
-        if (mScreenOnEarly && mAwake) {
-            if (needSensorRunningLp()) {
-                disable = false;
-                //enable listener if not already enabled
-                if (!mOrientationSensorEnabled) {
-                    mOrientationListener.enable();
-                    if(localLOGV) Slog.v(TAG, "Enabling listeners");
-                    mOrientationSensorEnabled = true;
-                }
-            }
-        }
-        //check if sensors need to be disabled
-        if (disable && mOrientationSensorEnabled) {
-            mOrientationListener.disable();
-            if(localLOGV) Slog.v(TAG, "Disabling listeners");
-            mOrientationSensorEnabled = false;
-        }
-    }
-
-    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
-        // Hold a wake lock until the power key is released.
-        if (!mPowerKeyWakeLock.isHeld()) {
-            mPowerKeyWakeLock.acquire();
-        }
-
-        // Cancel multi-press detection timeout.
-        if (mPowerKeyPressCounter != 0) {
-            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
-        }
-
-        // Detect user pressing the power button in panic when an application has
-        // taken over the whole screen.
-        boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
-                event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
-        if (panic) {
-            mHandler.post(mRequestTransientNav);
-        }
-
-        // Latch power key state to detect screenshot chord.
-        if (interactive && !mScreenshotChordPowerKeyTriggered
-                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-            mScreenshotChordPowerKeyTriggered = true;
-            mScreenshotChordPowerKeyTime = event.getDownTime();
-            interceptScreenshotChord();
-        }
-
-        // Stop ringing or end call if configured to do so when power is pressed.
-        TelecomManager telecomManager = getTelecommService();
-        boolean hungUp = false;
-        if (telecomManager != null) {
-            if (telecomManager.isRinging()) {
-                // Pressing Power while there's a ringing incoming
-                // call should silence the ringer.
-                telecomManager.silenceRinger();
-            } else if ((mIncallPowerBehavior
-                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                    && telecomManager.isInCall() && interactive) {
-                // Otherwise, if "Power button ends call" is enabled,
-                // the Power button will hang up any current active call.
-                hungUp = telecomManager.endCall();
-            }
-        }
-
-        // If the power key has still not yet been handled, then detect short
-        // press, long press, or multi press and decide what to do.
-        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
-                || mScreenshotChordVolumeUpKeyTriggered;
-        if (!mPowerKeyHandled) {
-            if (interactive) {
-                // When interactive, we're already awake.
-                // Wait for a long press or for the button to be released to decide what to do.
-                if (hasLongPressOnPowerBehavior()) {
-                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
-                    msg.setAsynchronous(true);
-                    mHandler.sendMessageDelayed(msg,
-                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
-                }
-            } else {
-                wakeUpFromPowerKey(event.getDownTime());
-                final int maxCount = getMaxMultiPressPowerCount();
-
-                if (maxCount <= 1) {
-                    mPowerKeyHandled = true;
-                } else {
-                    mBeganFromNonInteractive = true;
-                }
-            }
-        }
-    }
-
-    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
-        final boolean handled = canceled || mPowerKeyHandled;
-        mScreenshotChordPowerKeyTriggered = false;
-        cancelPendingScreenshotChordAction();
-        cancelPendingPowerKeyAction();
-
-        if (!handled) {
-            // Figure out how to handle the key now that it has been released.
-            mPowerKeyPressCounter += 1;
-
-            final int maxCount = getMaxMultiPressPowerCount();
-            final long eventTime = event.getDownTime();
-            if (mPowerKeyPressCounter < maxCount) {
-                // This could be a multi-press.  Wait a little bit longer to confirm.
-                // Continue holding the wake lock.
-                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
-                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
-                return;
-            }
-
-            // No other actions.  Handle it immediately.
-            powerPress(eventTime, interactive, mPowerKeyPressCounter);
-        }
-
-        // Done.  Reset our state.
-        finishPowerKeyPress();
-    }
-
-    private void finishPowerKeyPress() {
-        mBeganFromNonInteractive = false;
-        mPowerKeyPressCounter = 0;
-        if (mPowerKeyWakeLock.isHeld()) {
-            mPowerKeyWakeLock.release();
-        }
-    }
-
-    private void cancelPendingPowerKeyAction() {
-        if (!mPowerKeyHandled) {
-            mPowerKeyHandled = true;
-            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
-        }
-    }
-
-    private void powerPress(long eventTime, boolean interactive, int count) {
-        if (mScreenOnEarly && !mScreenOnFully) {
-            Slog.i(TAG, "Suppressed redundant power key press while "
-                    + "already in the process of turning the screen on.");
-            return;
-        }
-
-        if (count == 2) {
-            powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
-        } else if (count == 3) {
-            powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
-        } else if (interactive && !mBeganFromNonInteractive) {
-            switch (mShortPressOnPowerBehavior) {
-                case SHORT_PRESS_POWER_NOTHING:
-                    break;
-                case SHORT_PRESS_POWER_GO_TO_SLEEP:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                    break;
-                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
-                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-                    break;
-                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
-                    mPowerManager.goToSleep(eventTime,
-                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
-                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-                    launchHomeFromHotKey();
-                    break;
-            }
-        }
-    }
-
-    private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) {
-        switch (behavior) {
-            case MULTI_PRESS_POWER_NOTHING:
-                break;
-            case MULTI_PRESS_POWER_THEATER_MODE:
-                if (isTheaterModeEnabled()) {
-                    Slog.i(TAG, "Toggling theater mode off.");
-                    Settings.Global.putInt(mContext.getContentResolver(),
-                            Settings.Global.THEATER_MODE_ON, 0);
-                    if (!interactive) {
-                        wakeUpFromPowerKey(eventTime);
-                    }
-                } else {
-                    Slog.i(TAG, "Toggling theater mode on.");
-                    Settings.Global.putInt(mContext.getContentResolver(),
-                            Settings.Global.THEATER_MODE_ON, 1);
-
-                    if (mGoToSleepOnButtonPressTheaterMode && interactive) {
-                        mPowerManager.goToSleep(eventTime,
-                                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                    }
-                }
-                break;
-            case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
-                Slog.i(TAG, "Starting brightness boost.");
-                if (!interactive) {
-                    wakeUpFromPowerKey(eventTime);
-                }
-                mPowerManager.boostScreenBrightness(eventTime);
-                break;
-        }
-    }
-
-    private int getMaxMultiPressPowerCount() {
-        if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
-            return 3;
-        }
-        if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
-            return 2;
-        }
-        return 1;
-    }
-
-    private void powerLongPress() {
-        final int behavior = getResolvedLongPressOnPowerBehavior();
-        switch (behavior) {
-        case LONG_PRESS_POWER_NOTHING:
-            break;
-        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-            mPowerKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
-            showGlobalActionsInternal();
-            break;
-        case LONG_PRESS_POWER_SHUT_OFF:
-        case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
-            mPowerKeyHandled = true;
-            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
-            break;
-        }
-    }
-
-    private int getResolvedLongPressOnPowerBehavior() {
-        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
-            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
-        }
-        return mLongPressOnPowerBehavior;
-    }
-
-    private boolean hasLongPressOnPowerBehavior() {
-        return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
-    }
-
-    private void interceptScreenshotChord() {
-        if (mScreenshotChordEnabled
-                && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
-                && !mScreenshotChordVolumeUpKeyTriggered) {
-            final long now = SystemClock.uptimeMillis();
-            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
-                    && now <= mScreenshotChordPowerKeyTime
-                            + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
-                mScreenshotChordVolumeDownKeyConsumed = true;
-                cancelPendingPowerKeyAction();
-
-                mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
-            }
-        }
-    }
-
-    private long getScreenshotChordLongPressDelay() {
-        if (mKeyguardDelegate.isShowing()) {
-            // Double the time it takes to take a screenshot from the keyguard
-            return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
-                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
-        }
-        return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
-    }
-
-    private void cancelPendingScreenshotChordAction() {
-        mHandler.removeCallbacks(mScreenshotRunnable);
-    }
-
-    private final Runnable mEndCallLongPress = new Runnable() {
-        @Override
-        public void run() {
-            mEndCallKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
-            showGlobalActionsInternal();
-        }
-    };
-
-    private final Runnable mScreenshotRunnable = new Runnable() {
-        @Override
-        public void run() {
-            takeScreenshot();
-        }
-    };
-
-    @Override
-    public void showGlobalActions() {
-        mHandler.removeMessages(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
-        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
-    }
-
-    void showGlobalActionsInternal() {
-        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-        if (mGlobalActions == null) {
-            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
-        }
-        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
-        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
-        if (keyguardShowing) {
-            // since it took two seconds of long press to bring this up,
-            // poke the wake lock so they have some time to see the dialog.
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
-        }
-    }
-
-    boolean isDeviceProvisioned() {
-        return Settings.Global.getInt(
-                mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-    }
-
-    boolean isUserSetupComplete() {
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
-    }
-
-    private void handleShortPressOnHome() {
-        // If there's a dream running then use home to escape the dream
-        // but don't actually go home.
-        if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
-            mDreamManagerInternal.stopDream(false /*immediate*/);
-            return;
-        }
-
-        // Go home!
-        launchHomeFromHotKey();
-    }
-
-    private void handleLongPressOnHome() {
-        if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
-            mHomeConsumed = true;
-            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-
-            if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
-                toggleRecentApps();
-            } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST) {
-                launchAssistAction();
-            }
-        }
-    }
-
-    private void handleDoubleTapOnHome() {
-        if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
-            mHomeConsumed = true;
-            toggleRecentApps();
-        }
-    }
-
-    private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (mHomeDoubleTapPending) {
-                mHomeDoubleTapPending = false;
-                handleShortPressOnHome();
-            }
-        }
-    };
-
-    /** {@inheritDoc} */
-    @Override
-    public void init(Context context, IWindowManager windowManager,
-            WindowManagerFuncs windowManagerFuncs) {
-        mContext = context;
-        mWindowManager = windowManager;
-        mWindowManagerFuncs = windowManagerFuncs;
-        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-        mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
-
-        mHandler = new PolicyHandler();
-        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
-        mOrientationListener = new MyOrientationListener(mContext, mHandler);
-        try {
-            mOrientationListener.setCurrentRotation(windowManager.getRotation());
-        } catch (RemoteException ex) { }
-        mSettingsObserver = new SettingsObserver(mHandler);
-        mSettingsObserver.observe();
-        mShortcutManager = new ShortcutManager(context, mHandler);
-        mShortcutManager.observe();
-        mUiMode = context.getResources().getInteger(
-                com.android.internal.R.integer.config_defaultUiModeType);
-        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
-        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
-        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
-        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
-        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
-        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
-        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                "PhoneWindowManager.mBroadcastWakeLock");
-        mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                "PhoneWindowManager.mPowerKeyWakeLock");
-        mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
-        mSupportAutoRotation = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_supportAutoRotation);
-        mLidOpenRotation = readRotation(
-                com.android.internal.R.integer.config_lidOpenRotation);
-        mCarDockRotation = readRotation(
-                com.android.internal.R.integer.config_carDockRotation);
-        mDeskDockRotation = readRotation(
-                com.android.internal.R.integer.config_deskDockRotation);
-        mUndockedHdmiRotation = readRotation(
-                com.android.internal.R.integer.config_undockedHdmiRotation);
-        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
-        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
-        mLidKeyboardAccessibility = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lidKeyboardAccessibility);
-        mLidNavigationAccessibility = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_lidNavigationAccessibility);
-        mLidControlsSleep = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_lidControlsSleep);
-        mTranslucentDecorEnabled = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableTranslucentDecor);
-
-        mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
-        mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey
-                || mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
-        mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
-        mAllowTheaterModeWakeFromMotionWhenNotDreaming = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming);
-        mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
-        mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
-        mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
-
-        mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
-
-        mShortPressOnPowerBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_shortPressOnPowerBehavior);
-        mLongPressOnPowerBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_longPressOnPowerBehavior);
-        mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_doublePressOnPowerBehavior);
-        mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_triplePressOnPowerBehavior);
-
-        readConfigurationDependentBehaviors();
-
-        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
-                Context.ACCESSIBILITY_SERVICE);
-
-        // register for dock events
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
-        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE);
-        filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
-        filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
-        filter.addAction(Intent.ACTION_DOCK_EVENT);
-        Intent intent = context.registerReceiver(mDockReceiver, filter);
-        if (intent != null) {
-            // Retrieve current sticky dock event broadcast.
-            mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
-        }
-
-        // register for dream-related broadcasts
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_DREAMING_STARTED);
-        filter.addAction(Intent.ACTION_DREAMING_STOPPED);
-        context.registerReceiver(mDreamReceiver, filter);
-
-        // register for multiuser-relevant broadcasts
-        filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiver(mMultiuserReceiver, filter);
-
-        // monitor for system gestures
-        mSystemGestures = new SystemGesturesPointerEventListener(context,
-                new SystemGesturesPointerEventListener.Callbacks() {
-                    @Override
-                    public void onSwipeFromTop() {
-                        if (mStatusBar != null) {
-                            requestTransientBars(mStatusBar);
-                        }
-                    }
-                    @Override
-                    public void onSwipeFromBottom() {
-                        if (mNavigationBar != null && mNavigationBarOnBottom) {
-                            requestTransientBars(mNavigationBar);
-                        }
-                    }
-                    @Override
-                    public void onSwipeFromRight() {
-                        if (mNavigationBar != null && !mNavigationBarOnBottom) {
-                            requestTransientBars(mNavigationBar);
-                        }
-                    }
-                    @Override
-                    public void onDebug() {
-                        // no-op
-                    }
-                });
-        mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
-        mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
-
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
-        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_longPressVibePattern);
-        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_virtualKeyVibePattern);
-        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_keyboardTapVibePattern);
-        mClockTickVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_clockTickVibePattern);
-        mCalendarDateVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_calendarDateVibePattern);
-        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_safeModeDisabledVibePattern);
-        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
-                com.android.internal.R.array.config_safeModeEnabledVibePattern);
-
-        mScreenshotChordEnabled = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableScreenshotChord);
-
-        mGlobalKeyManager = new GlobalKeyManager(mContext);
-
-        // Controls rotation and the like.
-        initializeHdmiState();
-
-        // Match current screen state.
-        if (!mPowerManager.isInteractive()) {
-            goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-        }
-    }
-
-    /**
-     * Read values from config.xml that may be overridden depending on
-     * the configuration of the device.
-     * eg. Disable long press on home goes to recents on sw600dp.
-     */
-    private void readConfigurationDependentBehaviors() {
-        mLongPressOnHomeBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_longPressOnHomeBehavior);
-        if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
-                mLongPressOnHomeBehavior > LONG_PRESS_HOME_ASSIST) {
-            mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
-        }
-
-        mDoubleTapOnHomeBehavior = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_doubleTapOnHomeBehavior);
-        if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING ||
-                mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
-            mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
-        }
-    }
-
-    @Override
-    public void setInitialDisplaySize(Display display, int width, int height, int density) {
-        // This method might be called before the policy has been fully initialized
-        // or for other displays we don't care about.
-        if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
-            return;
-        }
-        mDisplay = display;
-
-        final Resources res = mContext.getResources();
-        int shortSize, longSize;
-        if (width > height) {
-            shortSize = height;
-            longSize = width;
-            mLandscapeRotation = Surface.ROTATION_0;
-            mSeascapeRotation = Surface.ROTATION_180;
-            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
-                mPortraitRotation = Surface.ROTATION_90;
-                mUpsideDownRotation = Surface.ROTATION_270;
-            } else {
-                mPortraitRotation = Surface.ROTATION_270;
-                mUpsideDownRotation = Surface.ROTATION_90;
-            }
-        } else {
-            shortSize = width;
-            longSize = height;
-            mPortraitRotation = Surface.ROTATION_0;
-            mUpsideDownRotation = Surface.ROTATION_180;
-            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
-                mLandscapeRotation = Surface.ROTATION_270;
-                mSeascapeRotation = Surface.ROTATION_90;
-            } else {
-                mLandscapeRotation = Surface.ROTATION_90;
-                mSeascapeRotation = Surface.ROTATION_270;
-            }
-        }
-
-        mStatusBarHeight =
-                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-
-        // Height of the navigation bar when presented horizontally at bottom
-        mNavigationBarHeightForRotation[mPortraitRotation] =
-        mNavigationBarHeightForRotation[mUpsideDownRotation] =
-                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
-        mNavigationBarHeightForRotation[mLandscapeRotation] =
-        mNavigationBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_height_landscape);
-
-        // Width of the navigation bar when presented vertically along one side
-        mNavigationBarWidthForRotation[mPortraitRotation] =
-        mNavigationBarWidthForRotation[mUpsideDownRotation] =
-        mNavigationBarWidthForRotation[mLandscapeRotation] =
-        mNavigationBarWidthForRotation[mSeascapeRotation] =
-                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-
-        // SystemUI (status bar) layout policy
-        int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
-        int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;
-
-        // Allow the navigation bar to move on small devices (phones).
-        mNavigationBarCanMove = shortSizeDp < 600;
-
-        mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
-        // Allow a system property to override this. Used by the emulator.
-        // See also hasNavigationBar().
-        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
-        if ("1".equals(navBarOverride)) {
-            mHasNavigationBar = false;
-        } else if ("0".equals(navBarOverride)) {
-            mHasNavigationBar = true;
-        }
-
-        // For demo purposes, allow the rotation of the HDMI display to be controlled.
-        // By default, HDMI locks rotation to landscape.
-        if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
-            mDemoHdmiRotation = mPortraitRotation;
-        } else {
-            mDemoHdmiRotation = mLandscapeRotation;
-        }
-        mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
-
-        // For demo purposes, allow the rotation of the remote display to be controlled.
-        // By default, remote display locks rotation to landscape.
-        if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
-            mDemoRotation = mPortraitRotation;
-        } else {
-            mDemoRotation = mLandscapeRotation;
-        }
-        mDemoRotationLock = SystemProperties.getBoolean(
-                "persist.demo.rotationlock", false);
-
-        // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
-        // http://developer.android.com/guide/practices/screens_support.html#range
-        mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 &&
-                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
-                // For debug purposes the next line turns this feature off with:
-                // $ adb shell setprop config.override_forced_orient true
-                // $ adb shell wm size reset
-                !"true".equals(SystemProperties.get("config.override_forced_orient"));
-    }
-
-    /**
-     * @return whether the navigation bar can be hidden, e.g. the device has a
-     *         navigation bar and touch exploration is not enabled
-     */
-    private boolean canHideNavigationBar() {
-        return mHasNavigationBar
-                && !mAccessibilityManager.isTouchExplorationEnabled();
-    }
-
-    @Override
-    public boolean isDefaultOrientationForced() {
-        return mForceDefaultOrientation;
-    }
-
-    @Override
-    public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
-        if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
-            mOverscanLeft = left;
-            mOverscanTop = top;
-            mOverscanRight = right;
-            mOverscanBottom = bottom;
-        }
-    }
-
-    public void updateSettings() {
-        ContentResolver resolver = mContext.getContentResolver();
-        boolean updateRotation = false;
-        synchronized (mLock) {
-            mEndcallBehavior = Settings.System.getIntForUser(resolver,
-                    Settings.System.END_BUTTON_BEHAVIOR,
-                    Settings.System.END_BUTTON_BEHAVIOR_DEFAULT,
-                    UserHandle.USER_CURRENT);
-            mIncallPowerBehavior = Settings.Secure.getIntForUser(resolver,
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
-                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
-                    UserHandle.USER_CURRENT);
-
-            // Configure wake gesture.
-            boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
-                    Settings.Secure.WAKE_GESTURE_ENABLED, 0,
-                    UserHandle.USER_CURRENT) != 0;
-            if (mWakeGestureEnabledSetting != wakeGestureEnabledSetting) {
-                mWakeGestureEnabledSetting = wakeGestureEnabledSetting;
-                updateWakeGestureListenerLp();
-            }
-
-            // Configure rotation lock.
-            int userRotation = Settings.System.getIntForUser(resolver,
-                    Settings.System.USER_ROTATION, Surface.ROTATION_0,
-                    UserHandle.USER_CURRENT);
-            if (mUserRotation != userRotation) {
-                mUserRotation = userRotation;
-                updateRotation = true;
-            }
-            int userRotationMode = Settings.System.getIntForUser(resolver,
-                    Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
-                            WindowManagerPolicy.USER_ROTATION_FREE :
-                                    WindowManagerPolicy.USER_ROTATION_LOCKED;
-            if (mUserRotationMode != userRotationMode) {
-                mUserRotationMode = userRotationMode;
-                updateRotation = true;
-                updateOrientationListenerLp();
-            }
-
-            if (mSystemReady) {
-                int pointerLocation = Settings.System.getIntForUser(resolver,
-                        Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
-                if (mPointerLocationMode != pointerLocation) {
-                    mPointerLocationMode = pointerLocation;
-                    mHandler.sendEmptyMessage(pointerLocation != 0 ?
-                            MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
-                }
-            }
-            // use screen off timeout setting as the timeout for the lockscreen
-            mLockScreenTimeout = Settings.System.getIntForUser(resolver,
-                    Settings.System.SCREEN_OFF_TIMEOUT, 0, UserHandle.USER_CURRENT);
-            String imId = Settings.Secure.getStringForUser(resolver,
-                    Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.USER_CURRENT);
-            boolean hasSoftInput = imId != null && imId.length() > 0;
-            if (mHasSoftInput != hasSoftInput) {
-                mHasSoftInput = hasSoftInput;
-                updateRotation = true;
-            }
-            if (mImmersiveModeConfirmation != null) {
-                mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
-            }
-            PolicyControl.reloadFromSetting(mContext);
-        }
-        if (updateRotation) {
-            updateRotation(true);
-        }
-    }
-
-    private void updateWakeGestureListenerLp() {
-        if (shouldEnableWakeGestureLp()) {
-            mWakeGestureListener.requestWakeUpTrigger();
-        } else {
-            mWakeGestureListener.cancelWakeUpTrigger();
-        }
-    }
-
-    private boolean shouldEnableWakeGestureLp() {
-        return mWakeGestureEnabledSetting && !mAwake
-                && (!mLidControlsSleep || mLidState != LID_CLOSED)
-                && mWakeGestureListener.isSupported();
-    }
-
-    private void enablePointerLocation() {
-        if (mPointerLocationView == null) {
-            mPointerLocationView = new PointerLocationView(mContext);
-            mPointerLocationView.setPrintCoords(false);
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    WindowManager.LayoutParams.MATCH_PARENT,
-                    WindowManager.LayoutParams.MATCH_PARENT);
-            lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-            lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-            if (ActivityManager.isHighEndGfx()) {
-                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-                lp.privateFlags |=
-                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
-            }
-            lp.format = PixelFormat.TRANSLUCENT;
-            lp.setTitle("PointerLocation");
-            WindowManager wm = (WindowManager)
-                    mContext.getSystemService(Context.WINDOW_SERVICE);
-            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-            wm.addView(mPointerLocationView, lp);
-            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
-        }
-    }
-
-    private void disablePointerLocation() {
-        if (mPointerLocationView != null) {
-            mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
-            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-            wm.removeView(mPointerLocationView);
-            mPointerLocationView = null;
-        }
-    }
-
-    private int readRotation(int resID) {
-        try {
-            int rotation = mContext.getResources().getInteger(resID);
-            switch (rotation) {
-                case 0:
-                    return Surface.ROTATION_0;
-                case 90:
-                    return Surface.ROTATION_90;
-                case 180:
-                    return Surface.ROTATION_180;
-                case 270:
-                    return Surface.ROTATION_270;
-            }
-        } catch (Resources.NotFoundException e) {
-            // fall through
-        }
-        return -1;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
-        int type = attrs.type;
-
-        outAppOp[0] = AppOpsManager.OP_NONE;
-
-        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
-                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
-                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
-            return WindowManagerGlobal.ADD_INVALID_TYPE;
-        }
-
-        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
-            // Window manager will make sure these are okay.
-            return WindowManagerGlobal.ADD_OKAY;
-        }
-        String permission = null;
-        switch (type) {
-            case TYPE_TOAST:
-                // XXX right now the app process has complete control over
-                // this...  should introduce a token to let the system
-                // monitor/control what they are doing.
-                outAppOp[0] = AppOpsManager.OP_TOAST_WINDOW;
-                break;
-            case TYPE_DREAM:
-            case TYPE_INPUT_METHOD:
-            case TYPE_WALLPAPER:
-            case TYPE_PRIVATE_PRESENTATION:
-            case TYPE_VOICE_INTERACTION:
-            case TYPE_ACCESSIBILITY_OVERLAY:
-                // The window manager will check these.
-                break;
-            case TYPE_PHONE:
-            case TYPE_PRIORITY_PHONE:
-            case TYPE_SYSTEM_ALERT:
-            case TYPE_SYSTEM_ERROR:
-            case TYPE_SYSTEM_OVERLAY:
-                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
-                outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-                break;
-            default:
-                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
-        }
-        if (permission != null) {
-            if (mContext.checkCallingOrSelfPermission(permission)
-                    != PackageManager.PERMISSION_GRANTED) {
-                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
-            }
-        }
-        return WindowManagerGlobal.ADD_OKAY;
-    }
-
-    @Override
-    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
-
-        // If this switch statement is modified, modify the comment in the declarations of
-        // the type in {@link WindowManager.LayoutParams} as well.
-        switch (attrs.type) {
-            default:
-                // These are the windows that by default are shown only to the user that created
-                // them. If this needs to be overridden, set
-                // {@link WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS} in
-                // {@link WindowManager.LayoutParams}. Note that permission
-                // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
-                if ((attrs.privateFlags & PRIVATE_FLAG_SHOW_FOR_ALL_USERS) == 0) {
-                    return true;
-                }
-                break;
-
-            // These are the windows that by default are shown to all users. However, to
-            // protect against spoofing, check permissions below.
-            case TYPE_APPLICATION_STARTING:
-            case TYPE_BOOT_PROGRESS:
-            case TYPE_DISPLAY_OVERLAY:
-            case TYPE_HIDDEN_NAV_CONSUMER:
-            case TYPE_KEYGUARD_SCRIM:
-            case TYPE_KEYGUARD_DIALOG:
-            case TYPE_MAGNIFICATION_OVERLAY:
-            case TYPE_NAVIGATION_BAR:
-            case TYPE_NAVIGATION_BAR_PANEL:
-            case TYPE_PHONE:
-            case TYPE_POINTER:
-            case TYPE_PRIORITY_PHONE:
-            case TYPE_SEARCH_BAR:
-            case TYPE_STATUS_BAR:
-            case TYPE_STATUS_BAR_PANEL:
-            case TYPE_STATUS_BAR_SUB_PANEL:
-            case TYPE_SYSTEM_DIALOG:
-            case TYPE_UNIVERSE_BACKGROUND:
-            case TYPE_VOLUME_OVERLAY:
-            case TYPE_PRIVATE_PRESENTATION:
-                break;
-        }
-
-        // Check if third party app has set window to system window type.
-        return mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
-                        != PackageManager.PERMISSION_GRANTED;
-    }
-
-    @Override
-    public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
-        switch (attrs.type) {
-            case TYPE_SYSTEM_OVERLAY:
-            case TYPE_SECURE_SYSTEM_OVERLAY:
-                // These types of windows can't receive input events.
-                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-                attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-                break;
-            case TYPE_STATUS_BAR:
-
-                // If the Keyguard is in a hidden state (occluded by another window), we force to
-                // remove the wallpaper and keyguard flag so that any change in-flight after setting
-                // the keyguard as occluded wouldn't set these flags again.
-                // See {@link #processKeyguardSetHiddenResultLw}.
-                if (mKeyguardHidden) {
-                    attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-                    attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-                }
-                break;
-        }
-
-        if (attrs.type != TYPE_STATUS_BAR) {
-            // The status bar is the only window allowed to exhibit keyguard behavior.
-            attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-        }
-
-        if (ActivityManager.isHighEndGfx()
-                && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
-            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-        }
-    }
-
-    void readLidState() {
-        mLidState = mWindowManagerFuncs.getLidState();
-    }
-
-    private void readCameraLensCoverState() {
-        mCameraLensCoverState = mWindowManagerFuncs.getCameraLensCoverState();
-    }
-
-    private boolean isHidden(int accessibilityMode) {
-        switch (accessibilityMode) {
-            case 1:
-                return mLidState == LID_CLOSED;
-            case 2:
-                return mLidState == LID_OPEN;
-            default:
-                return false;
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void adjustConfigurationLw(Configuration config, int keyboardPresence,
-            int navigationPresence) {
-        mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0;
-
-        readConfigurationDependentBehaviors();
-        readLidState();
-        applyLidSwitchState();
-
-        if (config.keyboard == Configuration.KEYBOARD_NOKEYS
-                || (keyboardPresence == PRESENCE_INTERNAL
-                        && isHidden(mLidKeyboardAccessibility))) {
-            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
-            if (!mHasSoftInput) {
-                config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
-            }
-        }
-
-        if (config.navigation == Configuration.NAVIGATION_NONAV
-                || (navigationPresence == PRESENCE_INTERNAL
-                        && isHidden(mLidNavigationAccessibility))) {
-            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int windowTypeToLayerLw(int type) {
-        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
-            return 2;
-        }
-        switch (type) {
-        case TYPE_UNIVERSE_BACKGROUND:
-            return 1;
-        case TYPE_PRIVATE_PRESENTATION:
-            return 2;
-        case TYPE_WALLPAPER:
-            // wallpaper is at the bottom, though the window manager may move it.
-            return 2;
-        case TYPE_PHONE:
-            return 3;
-        case TYPE_SEARCH_BAR:
-            return 4;
-        case TYPE_VOICE_INTERACTION:
-            // voice interaction layer is almost immediately above apps.
-            return 5;
-        case TYPE_SYSTEM_DIALOG:
-            return 6;
-        case TYPE_TOAST:
-            // toasts and the plugged-in battery thing
-            return 7;
-        case TYPE_PRIORITY_PHONE:
-            // SIM errors and unlock.  Not sure if this really should be in a high layer.
-            return 8;
-        case TYPE_DREAM:
-            // used for Dreams (screensavers with TYPE_DREAM windows)
-            return 9;
-        case TYPE_SYSTEM_ALERT:
-            // like the ANR / app crashed dialogs
-            return 10;
-        case TYPE_INPUT_METHOD:
-            // on-screen keyboards and other such input method user interfaces go here.
-            return 11;
-        case TYPE_INPUT_METHOD_DIALOG:
-            // on-screen keyboards and other such input method user interfaces go here.
-            return 12;
-        case TYPE_KEYGUARD_SCRIM:
-            // the safety window that shows behind keyguard while keyguard is starting
-            return 13;
-        case TYPE_STATUS_BAR_SUB_PANEL:
-            return 14;
-        case TYPE_STATUS_BAR:
-            return 15;
-        case TYPE_STATUS_BAR_PANEL:
-            return 16;
-        case TYPE_KEYGUARD_DIALOG:
-            return 17;
-        case TYPE_VOLUME_OVERLAY:
-            // the on-screen volume indicator and controller shown when the user
-            // changes the device volume
-            return 18;
-        case TYPE_SYSTEM_OVERLAY:
-            // the on-screen volume indicator and controller shown when the user
-            // changes the device volume
-            return 19;
-        case TYPE_NAVIGATION_BAR:
-            // the navigation bar, if available, shows atop most things
-            return 20;
-        case TYPE_NAVIGATION_BAR_PANEL:
-            // some panels (e.g. search) need to show on top of the navigation bar
-            return 21;
-        case TYPE_SYSTEM_ERROR:
-            // system-level error dialogs
-            return 22;
-        case TYPE_MAGNIFICATION_OVERLAY:
-            // used to highlight the magnified portion of a display
-            return 23;
-        case TYPE_DISPLAY_OVERLAY:
-            // used to simulate secondary display devices
-            return 24;
-        case TYPE_DRAG:
-            // the drag layer: input for drag-and-drop is associated with this window,
-            // which sits above all other focusable windows
-            return 25;
-        case TYPE_ACCESSIBILITY_OVERLAY:
-            // overlay put by accessibility services to intercept user interaction
-            return 26;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
-            return 27;
-        case TYPE_BOOT_PROGRESS:
-            return 28;
-        case TYPE_POINTER:
-            // the (mouse) pointer layer
-            return 29;
-        case TYPE_HIDDEN_NAV_CONSUMER:
-            return 30;
-        }
-        Log.e(TAG, "Unknown window type: " + type);
-        return 2;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int subWindowTypeToLayerLw(int type) {
-        switch (type) {
-        case TYPE_APPLICATION_PANEL:
-        case TYPE_APPLICATION_ATTACHED_DIALOG:
-            return APPLICATION_PANEL_SUBLAYER;
-        case TYPE_APPLICATION_MEDIA:
-            return APPLICATION_MEDIA_SUBLAYER;
-        case TYPE_APPLICATION_MEDIA_OVERLAY:
-            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
-        case TYPE_APPLICATION_SUB_PANEL:
-            return APPLICATION_SUB_PANEL_SUBLAYER;
-        }
-        Log.e(TAG, "Unknown sub-window type: " + type);
-        return 0;
-    }
-
-    @Override
-    public int getMaxWallpaperLayer() {
-        return windowTypeToLayerLw(TYPE_STATUS_BAR);
-    }
-
-    @Override
-    public int getAboveUniverseLayer() {
-        return windowTypeToLayerLw(TYPE_SYSTEM_ERROR);
-    }
-
-    @Override
-    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
-        if (mHasNavigationBar) {
-            // For a basic navigation bar, when we are in landscape mode we place
-            // the navigation bar to the side.
-            if (mNavigationBarCanMove && fullWidth > fullHeight) {
-                return fullWidth - mNavigationBarWidthForRotation[rotation];
-            }
-        }
-        return fullWidth;
-    }
-
-    @Override
-    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
-        if (mHasNavigationBar) {
-            // For a basic navigation bar, when we are in portrait mode we place
-            // the navigation bar to the bottom.
-            if (!mNavigationBarCanMove || fullWidth < fullHeight) {
-                return fullHeight - mNavigationBarHeightForRotation[rotation];
-            }
-        }
-        return fullHeight;
-    }
-
-    @Override
-    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
-        return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation);
-    }
-
-    @Override
-    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
-        // There is a separate status bar at the top of the display.  We don't count that as part
-        // of the fixed decor, since it can hide; however, for purposes of configurations,
-        // we do want to exclude it since applications can't generally use that part
-        // of the screen.
-        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
-    }
-
-    @Override
-    public boolean isForceHiding(WindowManager.LayoutParams attrs) {
-        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                (isKeyguardHostWindow(attrs) &&
-                        (mKeyguardDelegate != null && mKeyguardDelegate.isShowing())) ||
-                (attrs.type == TYPE_KEYGUARD_SCRIM);
-    }
-
-    @Override
-    public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
-        return attrs.type == TYPE_STATUS_BAR;
-    }
-
-    @Override
-    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
-        switch (attrs.type) {
-            case TYPE_STATUS_BAR:
-            case TYPE_NAVIGATION_BAR:
-            case TYPE_WALLPAPER:
-            case TYPE_DREAM:
-            case TYPE_UNIVERSE_BACKGROUND:
-            case TYPE_KEYGUARD_SCRIM:
-                return false;
-            default:
-                return true;
-        }
-    }
-
-    @Override
-    public WindowState getWinShowWhenLockedLw() {
-        return mWinShowWhenLocked;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public View addStartingWindow(IBinder appToken, String packageName, int theme,
-            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
-            int icon, int logo, int windowFlags) {
-        if (!SHOW_STARTING_ANIMATIONS) {
-            return null;
-        }
-        if (packageName == null) {
-            return null;
-        }
-
-        WindowManager wm = null;
-        View view = null;
-
-        try {
-            Context context = mContext;
-            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName
-                    + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
-                    + Integer.toHexString(theme));
-            if (theme != context.getThemeResId() || labelRes != 0) {
-                try {
-                    context = context.createPackageContext(packageName, 0);
-                    context.setTheme(theme);
-                } catch (PackageManager.NameNotFoundException e) {
-                    // Ignore
-                }
-            }
-
-            Window win = PolicyManager.makeNewWindow(context);
-            final TypedArray ta = win.getWindowStyle();
-            if (ta.getBoolean(
-                        com.android.internal.R.styleable.Window_windowDisablePreview, false)
-                || ta.getBoolean(
-                        com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {
-                return null;
-            }
-
-            Resources r = context.getResources();
-            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
-
-            win.setType(
-                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
-            // Force the window flags: this is a fake window, so it is not really
-            // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
-            // flag because we do know that the next window will take input
-            // focus, so we want to get the IME window up on top of us right away.
-            win.setFlags(
-                windowFlags|
-                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
-                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                windowFlags|
-                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
-                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
-            win.setDefaultIcon(icon);
-            win.setDefaultLogo(logo);
-
-            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
-                    WindowManager.LayoutParams.MATCH_PARENT);
-
-            final WindowManager.LayoutParams params = win.getAttributes();
-            params.token = appToken;
-            params.packageName = packageName;
-            params.windowAnimations = win.getWindowStyle().getResourceId(
-                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-            params.privateFlags |=
-                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
-            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-
-            if (!compatInfo.supportsScreen()) {
-                params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-            }
-
-            params.setTitle("Starting " + packageName);
-
-            wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-            view = win.getDecorView();
-
-            if (win.isFloating()) {
-                // Whoops, there is no way to display an animation/preview
-                // of such a thing!  After all that work...  let's skip it.
-                // (Note that we must do this here because it is in
-                // getDecorView() where the theme is evaluated...  maybe
-                // we should peek the floating attribute from the theme
-                // earlier.)
-                return null;
-            }
-
-            if (DEBUG_STARTING_WINDOW) Slog.d(
-                TAG, "Adding starting window for " + packageName
-                + " / " + appToken + ": "
-                + (view.getParent() != null ? view : null));
-
-            wm.addView(view, params);
-
-            // Only return the view if it was successfully added to the
-            // window manager... which we can tell by it having a parent.
-            return view.getParent() != null ? view : null;
-        } catch (WindowManager.BadTokenException e) {
-            // ignore
-            Log.w(TAG, appToken + " already running, starting window not displayed. " +
-                    e.getMessage());
-        } catch (RuntimeException e) {
-            // don't crash if something else bad happens, for example a
-            // failure loading resources because we are loading from an app
-            // on external storage that has been unmounted.
-            Log.w(TAG, appToken + " failed creating starting window", e);
-        } finally {
-            if (view != null && view.getParent() == null) {
-                Log.w(TAG, "view not successfully added to wm, removing view");
-                wm.removeViewImmediate(view);
-            }
-        }
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void removeStartingWindow(IBinder appToken, View window) {
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": "
-                + window + " Callers=" + Debug.getCallers(4));
-
-        if (window != null) {
-            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-            wm.removeView(window);
-        }
-    }
-
-    /**
-     * Preflight adding a window to the system.
-     *
-     * Currently enforces that three window types are singletons:
-     * <ul>
-     * <li>STATUS_BAR_TYPE</li>
-     * <li>KEYGUARD_TYPE</li>
-     * </ul>
-     *
-     * @param win The window to be added
-     * @param attrs Information about the window to be added
-     *
-     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
-     * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
-     */
-    @Override
-    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
-        switch (attrs.type) {
-            case TYPE_STATUS_BAR:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                if (mStatusBar != null) {
-                    if (mStatusBar.isAlive()) {
-                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                    }
-                }
-                mStatusBar = win;
-                mStatusBarController.setWindow(win);
-                break;
-            case TYPE_NAVIGATION_BAR:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                if (mNavigationBar != null) {
-                    if (mNavigationBar.isAlive()) {
-                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                    }
-                }
-                mNavigationBar = win;
-                mNavigationBarController.setWindow(win);
-                if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
-                break;
-            case TYPE_NAVIGATION_BAR_PANEL:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                break;
-            case TYPE_STATUS_BAR_PANEL:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                break;
-            case TYPE_STATUS_BAR_SUB_PANEL:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                break;
-            case TYPE_KEYGUARD_SCRIM:
-                if (mKeyguardScrim != null) {
-                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                }
-                mKeyguardScrim = win;
-                break;
-        }
-        return WindowManagerGlobal.ADD_OKAY;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void removeWindowLw(WindowState win) {
-        if (mStatusBar == win) {
-            mStatusBar = null;
-            mStatusBarController.setWindow(null);
-            mKeyguardDelegate.showScrim();
-        } else if (mKeyguardScrim == win) {
-            Log.v(TAG, "Removing keyguard scrim");
-            mKeyguardScrim = null;
-        } if (mNavigationBar == win) {
-            mNavigationBar = null;
-            mNavigationBarController.setWindow(null);
-        }
-    }
-
-    static final boolean PRINT_ANIM = false;
-
-    /** {@inheritDoc} */
-    @Override
-    public int selectAnimationLw(WindowState win, int transit) {
-        if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
-              + ": transit=" + transit);
-        if (win == mStatusBar) {
-            boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
-            if (transit == TRANSIT_EXIT
-                    || transit == TRANSIT_HIDE) {
-                return isKeyguard ? -1 : R.anim.dock_top_exit;
-            } else if (transit == TRANSIT_ENTER
-                    || transit == TRANSIT_SHOW) {
-                return isKeyguard ? -1 : R.anim.dock_top_enter;
-            }
-        } else if (win == mNavigationBar) {
-            // This can be on either the bottom or the right.
-            if (mNavigationBarOnBottom) {
-                if (transit == TRANSIT_EXIT
-                        || transit == TRANSIT_HIDE) {
-                    return R.anim.dock_bottom_exit;
-                } else if (transit == TRANSIT_ENTER
-                        || transit == TRANSIT_SHOW) {
-                    return R.anim.dock_bottom_enter;
-                }
-            } else {
-                if (transit == TRANSIT_EXIT
-                        || transit == TRANSIT_HIDE) {
-                    return R.anim.dock_right_exit;
-                } else if (transit == TRANSIT_ENTER
-                        || transit == TRANSIT_SHOW) {
-                    return R.anim.dock_right_enter;
-                }
-            }
-        }
-
-        if (transit == TRANSIT_PREVIEW_DONE) {
-            if (win.hasAppShownWindows()) {
-                if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
-                return com.android.internal.R.anim.app_starting_exit;
-            }
-        } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
-                && transit == TRANSIT_ENTER) {
-            // Special case: we are animating in a dream, while the keyguard
-            // is shown.  We don't want an animation on the dream, because
-            // we need it shown immediately with the keyguard animating away
-            // to reveal it.
-            return -1;
-        }
-
-        return 0;
-    }
-
-    @Override
-    public void selectRotationAnimationLw(int anim[]) {
-        if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
-                + mTopFullscreenOpaqueWindowState + " rotationAnimation="
-                + (mTopFullscreenOpaqueWindowState == null ?
-                        "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation));
-        if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) {
-            switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) {
-                case ROTATION_ANIMATION_CROSSFADE:
-                    anim[0] = R.anim.rotation_animation_xfade_exit;
-                    anim[1] = R.anim.rotation_animation_enter;
-                    break;
-                case ROTATION_ANIMATION_JUMPCUT:
-                    anim[0] = R.anim.rotation_animation_jump_exit;
-                    anim[1] = R.anim.rotation_animation_enter;
-                    break;
-                case ROTATION_ANIMATION_ROTATE:
-                default:
-                    anim[0] = anim[1] = 0;
-                    break;
-            }
-        } else {
-            anim[0] = anim[1] = 0;
-        }
-    }
-
-    @Override
-    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
-            boolean forceDefault) {
-        switch (exitAnimId) {
-            case R.anim.rotation_animation_xfade_exit:
-            case R.anim.rotation_animation_jump_exit:
-                // These are the only cases that matter.
-                if (forceDefault) {
-                    return false;
-                }
-                int anim[] = new int[2];
-                selectRotationAnimationLw(anim);
-                return (exitAnimId == anim[0] && enterAnimId == anim[1]);
-            default:
-                return true;
-        }
-    }
-
-    @Override
-    public Animation createForceHideEnterAnimation(boolean onWallpaper,
-            boolean goingToNotificationShade) {
-        if (goingToNotificationShade) {
-            return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
-        }
-
-        AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ?
-                    R.anim.lock_screen_behind_enter_wallpaper :
-                    R.anim.lock_screen_behind_enter);
-
-        // TODO: Use XML interpolators when we have log interpolators available in XML.
-        final List<Animation> animations = set.getAnimations();
-        for (int i = animations.size() - 1; i >= 0; --i) {
-            animations.get(i).setInterpolator(mLogDecelerateInterpolator);
-        }
-
-        return set;
-    }
-
-
-    @Override
-    public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
-        if (goingToNotificationShade) {
-            return null;
-        } else {
-            return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_wallpaper_exit);
-        }
-    }
-
-    private static void awakenDreams() {
-        IDreamManager dreamManager = getDreamManager();
-        if (dreamManager != null) {
-            try {
-                dreamManager.awaken();
-            } catch (RemoteException e) {
-                // fine, stay asleep then
-            }
-        }
-    }
-
-    static IDreamManager getDreamManager() {
-        return IDreamManager.Stub.asInterface(
-                ServiceManager.checkService(DreamService.DREAM_SERVICE));
-    }
-
-    TelecomManager getTelecommService() {
-        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-    }
-
-    static IAudioService getAudioService() {
-        IAudioService audioService = IAudioService.Stub.asInterface(
-                ServiceManager.checkService(Context.AUDIO_SERVICE));
-        if (audioService == null) {
-            Log.w(TAG, "Unable to find IAudioService interface.");
-        }
-        return audioService;
-    }
-
-    boolean keyguardOn() {
-        return isKeyguardShowingAndNotOccluded() || inKeyguardRestrictedKeyInputMode();
-    }
-
-    private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
-            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
-            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
-        };
-
-    /** {@inheritDoc} */
-    @Override
-    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
-        final boolean keyguardOn = keyguardOn();
-        final int keyCode = event.getKeyCode();
-        final int repeatCount = event.getRepeatCount();
-        final int metaState = event.getMetaState();
-        final int flags = event.getFlags();
-        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-        final boolean canceled = event.isCanceled();
-
-        if (DEBUG_INPUT) {
-            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
-                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
-                    + " canceled=" + canceled);
-        }
-
-        // If we think we might have a volume down & power key chord on the way
-        // but we're not sure, then tell the dispatcher to wait a little while and
-        // try again later before dispatching.
-        if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
-            if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
-                final long now = SystemClock.uptimeMillis();
-                final long timeoutTime = mScreenshotChordVolumeDownKeyTime
-                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
-                if (now < timeoutTime) {
-                    return timeoutTime - now;
-                }
-            }
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                    && mScreenshotChordVolumeDownKeyConsumed) {
-                if (!down) {
-                    mScreenshotChordVolumeDownKeyConsumed = false;
-                }
-                return -1;
-            }
-        }
-
-        // Cancel any pending meta actions if we see any other keys being pressed between the down
-        // of the meta key and its corresponding up.
-        if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
-            mPendingMetaAction = false;
-        }
-
-        // First we always handle the home key here, so applications
-        // can never break it, although if keyguard is on, we do let
-        // it handle it, because that gives us the correct 5 second
-        // timeout.
-        if (keyCode == KeyEvent.KEYCODE_HOME) {
-
-            // If we have released the home key, and didn't do anything else
-            // while it was pressed, then it is time to go home!
-            if (!down) {
-                cancelPreloadRecentApps();
-
-                mHomePressed = false;
-                if (mHomeConsumed) {
-                    mHomeConsumed = false;
-                    return -1;
-                }
-
-                if (canceled) {
-                    Log.i(TAG, "Ignoring HOME; event canceled.");
-                    return -1;
-                }
-
-                // If an incoming call is ringing, HOME is totally disabled.
-                // (The user is already on the InCallUI at this point,
-                // and his ONLY options are to answer or reject the call.)
-                TelecomManager telecomManager = getTelecommService();
-                if (telecomManager != null && telecomManager.isRinging()) {
-                    Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
-                    return -1;
-                }
-
-                // Delay handling home if a double-tap is possible.
-                if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
-                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
-                    mHomeDoubleTapPending = true;
-                    mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
-                            ViewConfiguration.getDoubleTapTimeout());
-                    return -1;
-                }
-
-                handleShortPressOnHome();
-                return -1;
-            }
-
-            // If a system window has focus, then it doesn't make sense
-            // right now to interact with applications.
-            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
-            if (attrs != null) {
-                final int type = attrs.type;
-                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
-                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
-                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    // the "app" is keyguard, so give it the key
-                    return 0;
-                }
-                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
-                for (int i=0; i<typeCount; i++) {
-                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
-                        // don't do anything, but also don't pass it to the app
-                        return -1;
-                    }
-                }
-            }
-
-            // Remember that home is pressed and handle special actions.
-            if (repeatCount == 0) {
-                mHomePressed = true;
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
-                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
-                    handleDoubleTapOnHome();
-                } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI
-                        || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
-                    preloadRecentApps();
-                }
-            } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
-                if (!keyguardOn) {
-                    handleLongPressOnHome();
-                }
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
-            // Hijack modified menu keys for debugging features
-            final int chordBug = KeyEvent.META_SHIFT_ON;
-
-            if (down && repeatCount == 0) {
-                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
-                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
-                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
-                            null, null, null, 0, null, null);
-                    return -1;
-                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
-                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
-                    Intent service = new Intent();
-                    service.setClassName(mContext, "com.android.server.LoadAverageService");
-                    ContentResolver res = mContext.getContentResolver();
-                    boolean shown = Settings.Global.getInt(
-                            res, Settings.Global.SHOW_PROCESSES, 0) != 0;
-                    if (!shown) {
-                        mContext.startService(service);
-                    } else {
-                        mContext.stopService(service);
-                    }
-                    Settings.Global.putInt(
-                            res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
-                    return -1;
-                }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
-            if (down) {
-                if (repeatCount == 0) {
-                    mSearchKeyShortcutPending = true;
-                    mConsumeSearchKeyUp = false;
-                }
-            } else {
-                mSearchKeyShortcutPending = false;
-                if (mConsumeSearchKeyUp) {
-                    mConsumeSearchKeyUp = false;
-                    return -1;
-                }
-            }
-            return 0;
-        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
-            if (!keyguardOn) {
-                if (down && repeatCount == 0) {
-                    preloadRecentApps();
-                } else if (!down) {
-                    toggleRecentApps();
-                }
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
-            if (down) {
-                if (repeatCount == 0) {
-                    mAssistKeyLongPressed = false;
-                } else if (repeatCount == 1) {
-                    mAssistKeyLongPressed = true;
-                    if (!keyguardOn) {
-                         launchAssistLongPressAction();
-                    }
-                }
-            } else {
-                if (mAssistKeyLongPressed) {
-                    mAssistKeyLongPressed = false;
-                } else {
-                    if (!keyguardOn) {
-                        launchAssistAction();
-                    }
-                }
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
-            if (!down) {
-                Intent voiceIntent;
-                if (!keyguardOn) {
-                    voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
-                } else {
-                    voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-                    voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
-                }
-                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
-            if (down && repeatCount == 0) {
-                mHandler.post(mScreenshotRunnable);
-            }
-            return -1;
-        } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
-                || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) {
-            if (down) {
-                int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
-
-                // Disable autobrightness if it's on
-                int auto = Settings.System.getIntForUser(
-                        mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS_MODE,
-                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
-                        UserHandle.USER_CURRENT_OR_SELF);
-                if (auto != 0) {
-                    Settings.System.putIntForUser(mContext.getContentResolver(),
-                            Settings.System.SCREEN_BRIGHTNESS_MODE,
-                            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
-                            UserHandle.USER_CURRENT_OR_SELF);
-                }
-
-                int min = mPowerManager.getMinimumScreenBrightnessSetting();
-                int max = mPowerManager.getMaximumScreenBrightnessSetting();
-                int step = (max - min + BRIGHTNESS_STEPS - 1) / BRIGHTNESS_STEPS * direction;
-                int brightness = Settings.System.getIntForUser(mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS,
-                        mPowerManager.getDefaultScreenBrightnessSetting(),
-                        UserHandle.USER_CURRENT_OR_SELF);
-                brightness += step;
-                // Make sure we don't go beyond the limits.
-                brightness = Math.min(max, brightness);
-                brightness = Math.max(min, brightness);
-
-                Settings.System.putIntForUser(mContext.getContentResolver(),
-                        Settings.System.SCREEN_BRIGHTNESS, brightness,
-                        UserHandle.USER_CURRENT_OR_SELF);
-                mContext.startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
-                        UserHandle.CURRENT_OR_SELF);
-            }
-            return -1;
-        } else if (KeyEvent.isMetaKey(keyCode)) {
-            if (down) {
-                mPendingMetaAction = true;
-            } else if (mPendingMetaAction) {
-                launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD);
-            }
-            return -1;
-        }
-
-        // Shortcuts are invoked through Search+key, so intercept those here
-        // Any printing key that is chorded with Search should be consumed
-        // even if no shortcut was invoked.  This prevents text from being
-        // inadvertently inserted when using a keyboard that has built-in macro
-        // shortcut keys (that emit Search+x) and some of them are not registered.
-        if (mSearchKeyShortcutPending) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                mConsumeSearchKeyUp = true;
-                mSearchKeyShortcutPending = false;
-                if (down && repeatCount == 0 && !keyguardOn) {
-                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
-                    if (shortcutIntent != null) {
-                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                        } catch (ActivityNotFoundException ex) {
-                            Slog.w(TAG, "Dropping shortcut key combination because "
-                                    + "the activity to which it is registered was not found: "
-                                    + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex);
-                        }
-                    } else {
-                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
-                                + "SEARCH+" + KeyEvent.keyCodeToString(keyCode));
-                    }
-                }
-                return -1;
-            }
-        }
-
-        // Invoke shortcuts using Meta.
-        if (down && repeatCount == 0 && !keyguardOn
-                && (metaState & KeyEvent.META_META_ON) != 0) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            if (kcm.isPrintingKey(keyCode)) {
-                Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
-                        metaState & ~(KeyEvent.META_META_ON
-                                | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
-                if (shortcutIntent != null) {
-                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
-                    } catch (ActivityNotFoundException ex) {
-                        Slog.w(TAG, "Dropping shortcut key combination because "
-                                + "the activity to which it is registered was not found: "
-                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
-                    }
-                    return -1;
-                }
-            }
-        }
-
-        // Handle application launch keys.
-        if (down && repeatCount == 0 && !keyguardOn) {
-            String category = sApplicationLaunchKeyCategories.get(keyCode);
-            if (category != null) {
-                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                try {
-                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
-                } catch (ActivityNotFoundException ex) {
-                    Slog.w(TAG, "Dropping application launch key because "
-                            + "the activity to which it is registered was not found: "
-                            + "keyCode=" + keyCode + ", category=" + category, ex);
-                }
-                return -1;
-            }
-        }
-
-        // Display task switcher for ALT-TAB.
-        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
-            if (mRecentAppsHeldModifiers == 0 && !keyguardOn) {
-                final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
-                if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
-                    mRecentAppsHeldModifiers = shiftlessModifiers;
-                    showRecentApps(true);
-                    return -1;
-                }
-            }
-        } else if (!down && mRecentAppsHeldModifiers != 0
-                && (metaState & mRecentAppsHeldModifiers) == 0) {
-            mRecentAppsHeldModifiers = 0;
-            hideRecentApps(true, false);
-        }
-
-        // Handle keyboard language switching.
-        if (down && repeatCount == 0
-                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
-                        || (keyCode == KeyEvent.KEYCODE_SPACE
-                                && (metaState & KeyEvent.META_CTRL_MASK) != 0))) {
-            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
-            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
-            return -1;
-        }
-        if (mLanguageSwitchKeyPressed && !down
-                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
-                        || keyCode == KeyEvent.KEYCODE_SPACE)) {
-            mLanguageSwitchKeyPressed = false;
-            return -1;
-        }
-
-        if (isValidGlobalKey(keyCode)
-                && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
-            return -1;
-        }
-
-        // Reserve all the META modifier combos for system behavior
-        if ((metaState & KeyEvent.META_META_ON) != 0) {
-            return -1;
-        }
-
-        // Let the application handle the key.
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
-        // Note: This method is only called if the initial down was unhandled.
-        if (DEBUG_INPUT) {
-            Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
-                    + ", flags=" + event.getFlags()
-                    + ", keyCode=" + event.getKeyCode()
-                    + ", scanCode=" + event.getScanCode()
-                    + ", metaState=" + event.getMetaState()
-                    + ", repeatCount=" + event.getRepeatCount()
-                    + ", policyFlags=" + policyFlags);
-        }
-
-        KeyEvent fallbackEvent = null;
-        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-            final KeyCharacterMap kcm = event.getKeyCharacterMap();
-            final int keyCode = event.getKeyCode();
-            final int metaState = event.getMetaState();
-            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
-                    && event.getRepeatCount() == 0;
-
-            // Check for fallback actions specified by the key character map.
-            final FallbackAction fallbackAction;
-            if (initialDown) {
-                fallbackAction = kcm.getFallbackAction(keyCode, metaState);
-            } else {
-                fallbackAction = mFallbackActions.get(keyCode);
-            }
-
-            if (fallbackAction != null) {
-                if (DEBUG_INPUT) {
-                    Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode
-                            + " metaState=" + Integer.toHexString(fallbackAction.metaState));
-                }
-
-                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
-                fallbackEvent = KeyEvent.obtain(
-                        event.getDownTime(), event.getEventTime(),
-                        event.getAction(), fallbackAction.keyCode,
-                        event.getRepeatCount(), fallbackAction.metaState,
-                        event.getDeviceId(), event.getScanCode(),
-                        flags, event.getSource(), null);
-
-                if (!interceptFallback(win, fallbackEvent, policyFlags)) {
-                    fallbackEvent.recycle();
-                    fallbackEvent = null;
-                }
-
-                if (initialDown) {
-                    mFallbackActions.put(keyCode, fallbackAction);
-                } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                    mFallbackActions.remove(keyCode);
-                    fallbackAction.recycle();
-                }
-            }
-        }
-
-        if (DEBUG_INPUT) {
-            if (fallbackEvent == null) {
-                Slog.d(TAG, "No fallback.");
-            } else {
-                Slog.d(TAG, "Performing fallback: " + fallbackEvent);
-            }
-        }
-        return fallbackEvent;
-    }
-
-    private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
-        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
-        if ((actions & ACTION_PASS_TO_USER) != 0) {
-            long delayMillis = interceptKeyBeforeDispatching(
-                    win, fallbackEvent, policyFlags);
-            if (delayMillis == 0) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void launchAssistLongPressAction() {
-        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-
-        // launch the search activity
-        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        try {
-            // TODO: This only stops the factory-installed search manager.
-            // Need to formalize an API to handle others
-            SearchManager searchManager = getSearchManager();
-            if (searchManager != null) {
-                searchManager.stopSearch();
-            }
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
-        } catch (ActivityNotFoundException e) {
-            Slog.w(TAG, "No activity to handle assist long press action.", e);
-        }
-    }
-
-    private void launchAssistAction() {
-        launchAssistAction(null);
-    }
-
-    private void launchAssistAction(String hint) {
-        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-        if (intent != null) {
-            if (hint != null) {
-                intent.putExtra(hint, true);
-            }
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            try {
-                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
-            } catch (ActivityNotFoundException e) {
-                Slog.w(TAG, "No activity to handle assist action.", e);
-            }
-        }
-    }
-
-    private SearchManager getSearchManager() {
-        if (mSearchManager == null) {
-            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        }
-        return mSearchManager;
-    }
-
-    private void preloadRecentApps() {
-        mPreloadedRecentApps = true;
-        try {
-            IStatusBarService statusbar = getStatusBarService();
-            if (statusbar != null) {
-                statusbar.preloadRecentApps();
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when preloading recent apps", e);
-            // re-acquire status bar service next time it is needed.
-            mStatusBarService = null;
-        }
-    }
-
-    private void cancelPreloadRecentApps() {
-        if (mPreloadedRecentApps) {
-            mPreloadedRecentApps = false;
-            try {
-                IStatusBarService statusbar = getStatusBarService();
-                if (statusbar != null) {
-                    statusbar.cancelPreloadRecentApps();
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "RemoteException when cancelling recent apps preload", e);
-                // re-acquire status bar service next time it is needed.
-                mStatusBarService = null;
-            }
-        }
-    }
-
-    private void toggleRecentApps() {
-        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
-        try {
-            IStatusBarService statusbar = getStatusBarService();
-            if (statusbar != null) {
-                statusbar.toggleRecentApps();
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when toggling recent apps", e);
-            // re-acquire status bar service next time it is needed.
-            mStatusBarService = null;
-        }
-    }
-
-    @Override
-    public void showRecentApps() {
-        mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS);
-        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS);
-    }
-
-    private void showRecentApps(boolean triggeredFromAltTab) {
-        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
-        try {
-            IStatusBarService statusbar = getStatusBarService();
-            if (statusbar != null) {
-                statusbar.showRecentApps(triggeredFromAltTab);
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when showing recent apps", e);
-            // re-acquire status bar service next time it is needed.
-            mStatusBarService = null;
-        }
-    }
-
-    private void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHome) {
-        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
-        try {
-            IStatusBarService statusbar = getStatusBarService();
-            if (statusbar != null) {
-                statusbar.hideRecentApps(triggeredFromAltTab, triggeredFromHome);
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when closing recent apps", e);
-            // re-acquire status bar service next time it is needed.
-            mStatusBarService = null;
-        }
-    }
-
-    /**
-     * A home key -> launch home action was detected.  Take the appropriate action
-     * given the situation with the keyguard.
-     */
-    void launchHomeFromHotKey() {
-        if (isKeyguardShowingAndNotOccluded()) {
-            // don't launch home if keyguard showing
-        } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
-            // when in keyguard restricted mode, must first verify unlock
-            // before launching home
-            mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
-                @Override
-                public void onKeyguardExitResult(boolean success) {
-                    if (success) {
-                        try {
-                            ActivityManagerNative.getDefault().stopAppSwitches();
-                        } catch (RemoteException e) {
-                        }
-                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                        startDockOrHome();
-                    }
-                }
-            });
-        } else {
-            // no keyguard stuff to worry about, just launch home!
-            try {
-                ActivityManagerNative.getDefault().stopAppSwitches();
-            } catch (RemoteException e) {
-            }
-            if (mRecentsVisible) {
-                // Hide Recents and notify it to launch Home
-                awakenDreams();
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                hideRecentApps(false, true);
-            } else {
-                // Otherwise, just launch Home
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                startDockOrHome();
-            }
-        }
-    }
-
-    private final Runnable mClearHideNavigationFlag = new Runnable() {
-        @Override
-        public void run() {
-            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-                // Clear flags.
-                mForceClearedSystemUiFlags &=
-                        ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-            }
-            mWindowManagerFuncs.reevaluateStatusBarVisibility();
-        }
-    };
-
-    /**
-     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
-     * to determine when the nav bar should be shown and prevent applications from
-     * receiving those touches.
-     */
-    final class HideNavInputEventReceiver extends InputEventReceiver {
-        public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper);
-        }
-
-        @Override
-        public void onInputEvent(InputEvent event) {
-            boolean handled = false;
-            try {
-                if (event instanceof MotionEvent
-                        && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    final MotionEvent motionEvent = (MotionEvent)event;
-                    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
-                        // When the user taps down, we re-show the nav bar.
-                        boolean changed = false;
-                        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-                            // Any user activity always causes us to show the
-                            // navigation controls, if they had been hidden.
-                            // We also clear the low profile and only content
-                            // flags so that tapping on the screen will atomically
-                            // restore all currently hidden screen decorations.
-                            int newVal = mResettingSystemUiFlags |
-                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                                    View.SYSTEM_UI_FLAG_LOW_PROFILE |
-                                    View.SYSTEM_UI_FLAG_FULLSCREEN;
-                            if (mResettingSystemUiFlags != newVal) {
-                                mResettingSystemUiFlags = newVal;
-                                changed = true;
-                            }
-                            // We don't allow the system's nav bar to be hidden
-                            // again for 1 second, to prevent applications from
-                            // spamming us and keeping it from being shown.
-                            newVal = mForceClearedSystemUiFlags |
-                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-                            if (mForceClearedSystemUiFlags != newVal) {
-                                mForceClearedSystemUiFlags = newVal;
-                                changed = true;
-                                mHandler.postDelayed(mClearHideNavigationFlag, 1000);
-                            }
-                        }
-                        if (changed) {
-                            mWindowManagerFuncs.reevaluateStatusBarVisibility();
-                        }
-                    }
-                }
-            } finally {
-                finishInputEvent(event, handled);
-            }
-        }
-    }
-    final InputEventReceiver.Factory mHideNavInputEventReceiverFactory =
-            new InputEventReceiver.Factory() {
-        @Override
-        public InputEventReceiver createInputEventReceiver(
-                InputChannel inputChannel, Looper looper) {
-            return new HideNavInputEventReceiver(inputChannel, looper);
-        }
-    };
-
-    @Override
-    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.
-        mResettingSystemUiFlags &= visibility;
-        // Clear any bits in the new visibility that are currently being
-        // force cleared, before reporting it.
-        return visibility & ~mResettingSystemUiFlags
-                & ~mForceClearedSystemUiFlags;
-    }
-
-    @Override
-    public void getInsetHintLw(WindowManager.LayoutParams attrs, Rect outContentInsets,
-            Rect outStableInsets) {
-        final int fl = PolicyControl.getWindowFlags(null, attrs);
-        final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
-        final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
-
-        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
-                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
-            int availRight, availBottom;
-            if (canHideNavigationBar() &&
-                    (systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
-                availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-            } else {
-                availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
-                availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
-            }
-            if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-                if ((fl & FLAG_FULLSCREEN) != 0) {
-                    outContentInsets.set(mStableFullscreenLeft, mStableFullscreenTop,
-                            availRight - mStableFullscreenRight,
-                            availBottom - mStableFullscreenBottom);
-                } else {
-                    outContentInsets.set(mStableLeft, mStableTop,
-                            availRight - mStableRight, availBottom - mStableBottom);
-                }
-            } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
-                outContentInsets.setEmpty();
-            } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
-                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
-                outContentInsets.set(mCurLeft, mCurTop,
-                        availRight - mCurRight, availBottom - mCurBottom);
-            } else {
-                outContentInsets.set(mCurLeft, mCurTop,
-                        availRight - mCurRight, availBottom - mCurBottom);
-            }
-
-            outStableInsets.set(mStableLeft, mStableTop,
-                    availRight - mStableRight, availBottom - mStableBottom);
-            return;
-        }
-        outContentInsets.setEmpty();
-        outStableInsets.setEmpty();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
-                              int displayRotation) {
-        final int overscanLeft, overscanTop, overscanRight, overscanBottom;
-        if (isDefaultDisplay) {
-            switch (displayRotation) {
-                case Surface.ROTATION_90:
-                    overscanLeft = mOverscanTop;
-                    overscanTop = mOverscanRight;
-                    overscanRight = mOverscanBottom;
-                    overscanBottom = mOverscanLeft;
-                    break;
-                case Surface.ROTATION_180:
-                    overscanLeft = mOverscanRight;
-                    overscanTop = mOverscanBottom;
-                    overscanRight = mOverscanLeft;
-                    overscanBottom = mOverscanTop;
-                    break;
-                case Surface.ROTATION_270:
-                    overscanLeft = mOverscanBottom;
-                    overscanTop = mOverscanLeft;
-                    overscanRight = mOverscanTop;
-                    overscanBottom = mOverscanRight;
-                    break;
-                default:
-                    overscanLeft = mOverscanLeft;
-                    overscanTop = mOverscanTop;
-                    overscanRight = mOverscanRight;
-                    overscanBottom = mOverscanBottom;
-                    break;
-            }
-        } else {
-            overscanLeft = 0;
-            overscanTop = 0;
-            overscanRight = 0;
-            overscanBottom = 0;
-        }
-        mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
-        mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
-        mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
-        mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
-        mSystemLeft = 0;
-        mSystemTop = 0;
-        mSystemRight = displayWidth;
-        mSystemBottom = displayHeight;
-        mUnrestrictedScreenLeft = overscanLeft;
-        mUnrestrictedScreenTop = overscanTop;
-        mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
-        mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
-        mRestrictedScreenLeft = mUnrestrictedScreenLeft;
-        mRestrictedScreenTop = mUnrestrictedScreenTop;
-        mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
-        mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
-        mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
-                = mCurLeft = mUnrestrictedScreenLeft;
-        mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
-                = mCurTop = mUnrestrictedScreenTop;
-        mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
-                = mCurRight = displayWidth - overscanRight;
-        mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
-                = mCurBottom = displayHeight - overscanBottom;
-        mDockLayer = 0x10000000;
-        mStatusBarLayer = -1;
-
-        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
-        final Rect pf = mTmpParentFrame;
-        final Rect df = mTmpDisplayFrame;
-        final Rect of = mTmpOverscanFrame;
-        final Rect vf = mTmpVisibleFrame;
-        final Rect dcf = mTmpDecorFrame;
-        pf.left = df.left = of.left = vf.left = mDockLeft;
-        pf.top = df.top = of.top = vf.top = mDockTop;
-        pf.right = df.right = of.right = vf.right = mDockRight;
-        pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
-        dcf.setEmpty();  // Decor frame N/A for system bars.
-
-        if (isDefaultDisplay) {
-            // For purposes of putting out fake window up to steal focus, we will
-            // drive nav being hidden only by whether it is requested.
-            final int sysui = mLastSystemUiFlags;
-            boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
-            boolean navTranslucent = (sysui
-                    & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
-            boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
-            boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
-            boolean navAllowedHidden = immersive || immersiveSticky;
-            navTranslucent &= !immersiveSticky;  // transient trumps translucent
-            boolean isKeyguardShowing = isStatusBarKeyguard() && !mHideLockScreen;
-            if (!isKeyguardShowing) {
-                navTranslucent &= areTranslucentBarsAllowed();
-            }
-
-            // When the navigation bar isn't visible, we put up a fake
-            // input window to catch all touch events.  This way we can
-            // detect when the user presses anywhere to bring back the nav
-            // bar and ensure the application doesn't see the event.
-            if (navVisible || navAllowedHidden) {
-                if (mHideNavFakeWindow != null) {
-                    mHideNavFakeWindow.dismiss();
-                    mHideNavFakeWindow = null;
-                }
-            } else if (mHideNavFakeWindow == null) {
-                mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
-                        mHandler.getLooper(), mHideNavInputEventReceiverFactory,
-                        "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0,
-                        0, false, false, true);
-            }
-
-            // For purposes of positioning and showing the nav bar, if we have
-            // decided that it can't be hidden (because of the screen aspect ratio),
-            // then take that into account.
-            navVisible |= !canHideNavigationBar();
-
-            boolean updateSysUiVisibility = false;
-            if (mNavigationBar != null) {
-                boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
-                // Force the navigation bar to its appropriate place and
-                // size.  We need to do this directly, instead of relying on
-                // it to bubble up from the nav bar, because this needs to
-                // change atomically with screen rotations.
-                mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
-                if (mNavigationBarOnBottom) {
-                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
-                    int top = displayHeight - overscanBottom
-                            - mNavigationBarHeightForRotation[displayRotation];
-                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
-                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
-                    if (transientNavBarShowing) {
-                        mNavigationBarController.setBarShowingLw(true);
-                    } else if (navVisible) {
-                        mNavigationBarController.setBarShowingLw(true);
-                        mDockBottom = mTmpNavigationFrame.top;
-                        mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
-                        mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
-                    } else {
-                        // We currently want to hide the navigation UI.
-                        mNavigationBarController.setBarShowingLw(false);
-                    }
-                    if (navVisible && !navTranslucent && !navAllowedHidden
-                            && !mNavigationBar.isAnimatingLw()
-                            && !mNavigationBarController.wasRecentlyTranslucent()) {
-                        // If the opaque nav bar is currently requested to be visible,
-                        // and not in the process of animating on or off, then
-                        // we can tell the app that it is covered by it.
-                        mSystemBottom = mTmpNavigationFrame.top;
-                    }
-                } else {
-                    // Landscape screen; nav bar goes to the right.
-                    int left = displayWidth - overscanRight
-                            - mNavigationBarWidthForRotation[displayRotation];
-                    mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
-                    mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
-                    if (transientNavBarShowing) {
-                        mNavigationBarController.setBarShowingLw(true);
-                    } else if (navVisible) {
-                        mNavigationBarController.setBarShowingLw(true);
-                        mDockRight = mTmpNavigationFrame.left;
-                        mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
-                        mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
-                    } else {
-                        // We currently want to hide the navigation UI.
-                        mNavigationBarController.setBarShowingLw(false);
-                    }
-                    if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw()
-                            && !mNavigationBarController.wasRecentlyTranslucent()) {
-                        // If the nav bar is currently requested to be visible,
-                        // and not in the process of animating on or off, then
-                        // we can tell the app that it is covered by it.
-                        mSystemRight = mTmpNavigationFrame.left;
-                    }
-                }
-                // Make sure the content and current rectangles are updated to
-                // account for the restrictions from the navigation bar.
-                mContentTop = mVoiceContentTop = mCurTop = mDockTop;
-                mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
-                mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
-                mContentRight = mVoiceContentRight = mCurRight = mDockRight;
-                mStatusBarLayer = mNavigationBar.getSurfaceLayer();
-                // And compute the final frame.
-                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                        mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
-                        mTmpNavigationFrame);
-                if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
-                if (mNavigationBarController.checkHiddenLw()) {
-                    updateSysUiVisibility = true;
-                }
-            }
-            if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
-                    mDockLeft, mDockTop, mDockRight, mDockBottom));
-
-            // decide where the status bar goes ahead of time
-            if (mStatusBar != null) {
-                // apply any navigation bar insets
-                pf.left = df.left = of.left = mUnrestrictedScreenLeft;
-                pf.top = df.top = of.top = mUnrestrictedScreenTop;
-                pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
-                pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
-                        + mUnrestrictedScreenTop;
-                vf.left = mStableLeft;
-                vf.top = mStableTop;
-                vf.right = mStableRight;
-                vf.bottom = mStableBottom;
-
-                mStatusBarLayer = mStatusBar.getSurfaceLayer();
-
-                // Let the status bar determine its size.
-                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf);
-
-                // For layout, the status bar is always at the top with our fixed height.
-                mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
-                boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
-                boolean statusBarTranslucent = (sysui
-                        & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
-                if (!isKeyguardShowing) {
-                    statusBarTranslucent &= areTranslucentBarsAllowed();
-                }
-
-                // If the status bar is hidden, we don't want to cause
-                // windows behind it to scroll.
-                if (mStatusBar.isVisibleLw() && !statusBarTransient) {
-                    // Status bar may go away, so the screen area it occupies
-                    // is available to apps but just covering them when the
-                    // status bar is visible.
-                    mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
-                    mContentTop = mVoiceContentTop = mCurTop = mDockTop;
-                    mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
-                    mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
-                    mContentRight = mVoiceContentRight = mCurRight = mDockRight;
-
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
-                        String.format(
-                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
-                            mDockLeft, mDockTop, mDockRight, mDockBottom,
-                            mContentLeft, mContentTop, mContentRight, mContentBottom,
-                            mCurLeft, mCurTop, mCurRight, mCurBottom));
-                }
-                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
-                        && !statusBarTransient && !statusBarTranslucent
-                        && !mStatusBarController.wasRecentlyTranslucent()) {
-                    // If the opaque status bar is currently requested to be visible,
-                    // and not in the process of animating on or off, then
-                    // we can tell the app that it is covered by it.
-                    mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
-                }
-                if (mStatusBarController.checkHiddenLw()) {
-                    updateSysUiVisibility = true;
-                }
-            }
-            if (updateSysUiVisibility) {
-                updateSystemUiVisibilityLw();
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getSystemDecorLayerLw() {
-        if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
-        if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
-        return 0;
-    }
-
-    @Override
-    public void getContentRectLw(Rect r) {
-        r.set(mContentLeft, mContentTop, mContentRight, mContentBottom);
-    }
-
-    void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
-            boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
-        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
-            // Here's a special case: if this attached window is a panel that is
-            // above the dock window, and the window it is attached to is below
-            // the dock window, then the frames we computed for the window it is
-            // attached to can not be used because the dock is effectively part
-            // of the underlying window and the attached window is floating on top
-            // of the whole thing.  So, we ignore the attached window and explicitly
-            // compute the frames that would be appropriate without the dock.
-            df.left = of.left = cf.left = vf.left = mDockLeft;
-            df.top = of.top = cf.top = vf.top = mDockTop;
-            df.right = of.right = cf.right = vf.right = mDockRight;
-            df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
-        } else {
-            // The effective display frame of the attached window depends on
-            // whether it is taking care of insetting its content.  If not,
-            // we need to use the parent's content frame so that the entire
-            // window is positioned within that content.  Otherwise we can use
-            // the overscan frame and let the attached window take care of
-            // positioning its content appropriately.
-            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                // Set the content frame of the attached window to the parent's decor frame
-                // (same as content frame when IME isn't present) if specifically requested by
-                // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
-                // Otherwise, use the overscan frame.
-                cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
-                        ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
-            } else {
-                // If the window is resizing, then we want to base the content
-                // frame on our attached content frame to resize...  however,
-                // things can be tricky if the attached window is NOT in resize
-                // mode, in which case its content frame will be larger.
-                // Ungh.  So to deal with that, make sure the content frame
-                // we end up using is not covering the IM dock.
-                cf.set(attached.getContentFrameLw());
-                if (attached.isVoiceInteraction()) {
-                    if (cf.left < mVoiceContentLeft) cf.left = mVoiceContentLeft;
-                    if (cf.top < mVoiceContentTop) cf.top = mVoiceContentTop;
-                    if (cf.right > mVoiceContentRight) cf.right = mVoiceContentRight;
-                    if (cf.bottom > mVoiceContentBottom) cf.bottom = mVoiceContentBottom;
-                } else if (attached.getSurfaceLayer() < mDockLayer) {
-                    if (cf.left < mContentLeft) cf.left = mContentLeft;
-                    if (cf.top < mContentTop) cf.top = mContentTop;
-                    if (cf.right > mContentRight) cf.right = mContentRight;
-                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
-                }
-            }
-            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
-            of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
-            vf.set(attached.getVisibleFrameLw());
-        }
-        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
-        // window should be positioned relative to its parent or the entire
-        // screen.
-        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
-                ? attached.getFrameLw() : df);
-    }
-
-    private void applyStableConstraints(int sysui, int fl, Rect r) {
-        if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
-            // If app is requesting a stable layout, don't let the
-            // content insets go below the stable values.
-            if ((fl & FLAG_FULLSCREEN) != 0) {
-                if (r.left < mStableFullscreenLeft) r.left = mStableFullscreenLeft;
-                if (r.top < mStableFullscreenTop) r.top = mStableFullscreenTop;
-                if (r.right > mStableFullscreenRight) r.right = mStableFullscreenRight;
-                if (r.bottom > mStableFullscreenBottom) r.bottom = mStableFullscreenBottom;
-            } else {
-                if (r.left < mStableLeft) r.left = mStableLeft;
-                if (r.top < mStableTop) r.top = mStableTop;
-                if (r.right > mStableRight) r.right = mStableRight;
-                if (r.bottom > mStableBottom) r.bottom = mStableBottom;
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void layoutWindowLw(WindowState win, WindowState attached) {
-        // we've already done the status bar
-        final WindowManager.LayoutParams attrs = win.getAttrs();
-        if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) ||
-                win == mNavigationBar) {
-            return;
-        }
-        final boolean isDefaultDisplay = win.isDefaultDisplay();
-        final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
-                (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
-        if (needsToOffsetInputMethodTarget) {
-            if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
-            offsetInputMethodWindowLw(mLastInputMethodWindow);
-        }
-
-        final int fl = PolicyControl.getWindowFlags(win, attrs);
-        final int sim = attrs.softInputMode;
-        final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
-
-        final Rect pf = mTmpParentFrame;
-        final Rect df = mTmpDisplayFrame;
-        final Rect of = mTmpOverscanFrame;
-        final Rect cf = mTmpContentFrame;
-        final Rect vf = mTmpVisibleFrame;
-        final Rect dcf = mTmpDecorFrame;
-        final Rect sf = mTmpStableFrame;
-        dcf.setEmpty();
-
-        final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
-                && mNavigationBar != null && mNavigationBar.isVisibleLw());
-
-        final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
-
-        if (isDefaultDisplay) {
-            sf.set(mStableLeft, mStableTop, mStableRight, mStableBottom);
-        } else {
-            sf.set(mOverscanLeft, mOverscanTop, mOverscanRight, mOverscanBottom);
-        }
-
-        if (!isDefaultDisplay) {
-            if (attached != null) {
-                // If this window is attached to another, our display
-                // frame is the same as the one we are attached to.
-                setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
-            } else {
-                // Give the window full screen.
-                pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
-                pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
-                pf.right = df.right = of.right = cf.right
-                        = mOverscanScreenLeft + mOverscanScreenWidth;
-                pf.bottom = df.bottom = of.bottom = cf.bottom
-                        = mOverscanScreenTop + mOverscanScreenHeight;
-            }
-        } else  if (attrs.type == TYPE_INPUT_METHOD) {
-            pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
-            pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
-            pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
-            // IM dock windows layout below the nav bar...
-            pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-            // ...with content insets above the nav bar
-            cf.bottom = vf.bottom = mStableBottom;
-            // IM dock windows always go to the bottom of the screen.
-            attrs.gravity = Gravity.BOTTOM;
-            mDockLayer = win.getSurfaceLayer();
-        } else if (win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-            pf.left = df.left = of.left = mUnrestrictedScreenLeft;
-            pf.top = df.top = of.top = mUnrestrictedScreenTop;
-            pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
-            pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
-            cf.left = vf.left = mStableLeft;
-            cf.top = vf.top = mStableTop;
-            cf.right = vf.right = mStableRight;
-            vf.bottom = mStableBottom;
-            cf.bottom = mContentBottom;
-        } else {
-
-            // Default policy decor for the default display
-            dcf.left = mSystemLeft;
-            dcf.top = mSystemTop;
-            dcf.right = mSystemRight;
-            dcf.bottom = mSystemBottom;
-            final boolean inheritTranslucentDecor = (attrs.privateFlags
-                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
-            final boolean isAppWindow =
-                    attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW &&
-                    attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-            final boolean topAtRest =
-                    win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
-            if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
-                if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
-                        && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
-                        && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0
-                        && (fl & WindowManager.LayoutParams.
-                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
-                    // Ensure policy decor includes status bar
-                    dcf.top = mStableTop;
-                }
-                if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0
-                        && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
-                        && (fl & WindowManager.LayoutParams.
-                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
-                    // Ensure policy decor includes navigation bar
-                    dcf.bottom = mStableBottom;
-                    dcf.right = mStableRight;
-                }
-            }
-
-            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
-                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
-                            + "): IN_SCREEN, INSET_DECOR");
-                // This is the case for a normal activity window: we want it
-                // to cover all of the screen space, and it can take care of
-                // moving its contents to account for screen decorations that
-                // intrude into that space.
-                if (attached != null) {
-                    // If this window is attached to another, our display
-                    // frame is the same as the one we are attached to.
-                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
-                } else {
-                    if (attrs.type == TYPE_STATUS_BAR_PANEL
-                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
-                        // Status bar panels are the only windows who can go on top of
-                        // the status bar.  They are protected by the STATUS_BAR_SERVICE
-                        // permission, so they have the same privileges as the status
-                        // bar itself.
-                        //
-                        // However, they should still dodge the navigation bar if it exists.
-
-                        pf.left = df.left = of.left = hasNavBar
-                                ? mDockLeft : mUnrestrictedScreenLeft;
-                        pf.top = df.top = of.top = mUnrestrictedScreenTop;
-                        pf.right = df.right = of.right = hasNavBar
-                                ? mRestrictedScreenLeft+mRestrictedScreenWidth
-                                : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                        pf.bottom = df.bottom = of.bottom = hasNavBar
-                                ? mRestrictedScreenTop+mRestrictedScreenHeight
-                                : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-
-                        if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                        "Laying out status bar window: (%d,%d - %d,%d)",
-                                        pf.left, pf.top, pf.right, pf.bottom));
-                    } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
-                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-                        // Asking to layout into the overscan region, so give it that pure
-                        // unrestricted area.
-                        pf.left = df.left = of.left = mOverscanScreenLeft;
-                        pf.top = df.top = of.top = mOverscanScreenTop;
-                        pf.right = df.right = of.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                        pf.bottom = df.bottom = of.bottom = mOverscanScreenTop
-                                + mOverscanScreenHeight;
-                    } else if (canHideNavigationBar()
-                            && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
-                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-                        // Asking for layout as if the nav bar is hidden, lets the
-                        // application extend into the unrestricted overscan screen area.  We
-                        // only do this for application windows to ensure no window that
-                        // can be above the nav bar can do this.
-                        pf.left = df.left = mOverscanScreenLeft;
-                        pf.top = df.top = mOverscanScreenTop;
-                        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
-                        // We need to tell the app about where the frame inside the overscan
-                        // is, so it can inset its content by that amount -- it didn't ask
-                        // to actually extend itself into the overscan region.
-                        of.left = mUnrestrictedScreenLeft;
-                        of.top = mUnrestrictedScreenTop;
-                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                    } else {
-                        pf.left = df.left = mRestrictedOverscanScreenLeft;
-                        pf.top = df.top = mRestrictedOverscanScreenTop;
-                        pf.right = df.right = mRestrictedOverscanScreenLeft
-                                + mRestrictedOverscanScreenWidth;
-                        pf.bottom = df.bottom = mRestrictedOverscanScreenTop
-                                + mRestrictedOverscanScreenHeight;
-                        // We need to tell the app about where the frame inside the overscan
-                        // is, so it can inset its content by that amount -- it didn't ask
-                        // to actually extend itself into the overscan region.
-                        of.left = mUnrestrictedScreenLeft;
-                        of.top = mUnrestrictedScreenTop;
-                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                    }
-
-                    if ((fl & FLAG_FULLSCREEN) == 0) {
-                        if (win.isVoiceInteraction()) {
-                            cf.left = mVoiceContentLeft;
-                            cf.top = mVoiceContentTop;
-                            cf.right = mVoiceContentRight;
-                            cf.bottom = mVoiceContentBottom;
-                        } else {
-                            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                                cf.left = mDockLeft;
-                                cf.top = mDockTop;
-                                cf.right = mDockRight;
-                                cf.bottom = mDockBottom;
-                            } else {
-                                cf.left = mContentLeft;
-                                cf.top = mContentTop;
-                                cf.right = mContentRight;
-                                cf.bottom = mContentBottom;
-                            }
-                        }
-                    } else {
-                        // Full screen windows are always given a layout that is as if the
-                        // status bar and other transient decors are gone.  This is to avoid
-                        // bad states when moving from a window that is not hding the
-                        // status bar to one that is.
-                        cf.left = mRestrictedScreenLeft;
-                        cf.top = mRestrictedScreenTop;
-                        cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
-                        cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
-                    }
-                    applyStableConstraints(sysUiFl, fl, cf);
-                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
-                        vf.left = mCurLeft;
-                        vf.top = mCurTop;
-                        vf.right = mCurRight;
-                        vf.bottom = mCurBottom;
-                    } else {
-                        vf.set(cf);
-                    }
-                }
-            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
-                    & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
-                        "): IN_SCREEN");
-                // A window that has requested to fill the entire screen just
-                // gets everything, period.
-                if (attrs.type == TYPE_STATUS_BAR_PANEL
-                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
-                    pf.left = df.left = of.left = cf.left = hasNavBar
-                            ? mDockLeft : mUnrestrictedScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = of.right = cf.right = hasNavBar
-                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
-                                        : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar
-                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
-                                          : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
-                                    pf.left, pf.top, pf.right, pf.bottom));
-                } else if (attrs.type == TYPE_NAVIGATION_BAR
-                        || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
-                    // The navigation bar has Real Ultimate Power.
-                    pf.left = df.left = of.left = mUnrestrictedScreenLeft;
-                    pf.top = df.top = of.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = of.right = mUnrestrictedScreenLeft
-                            + mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop
-                            + mUnrestrictedScreenHeight;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
-                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
-                                    pf.left, pf.top, pf.right, pf.bottom));
-                } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
-                                || attrs.type == TYPE_BOOT_PROGRESS)
-                        && ((fl & FLAG_FULLSCREEN) != 0)) {
-                    // Fullscreen secure system overlays get what they ask for.
-                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
-                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
-                            + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
-                            + mOverscanScreenHeight;
-                } else if (attrs.type == TYPE_BOOT_PROGRESS
-                        || attrs.type == TYPE_UNIVERSE_BACKGROUND) {
-                    // Boot progress screen always covers entire display.
-                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
-                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
-                            + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
-                            + mOverscanScreenHeight;
-                } else if (attrs.type == TYPE_WALLPAPER) {
-                    // The wallpaper also has Real Ultimate Power, but we want to tell
-                    // it about the overscan area.
-                    pf.left = df.left = mOverscanScreenLeft;
-                    pf.top = df.top = mOverscanScreenTop;
-                    pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
-                    of.left = cf.left = mUnrestrictedScreenLeft;
-                    of.top = cf.top = mUnrestrictedScreenTop;
-                    of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                    of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
-                        && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                        && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-                    // Asking to layout into the overscan region, so give it that pure
-                    // unrestricted area.
-                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
-                    pf.right = df.right = of.right = cf.right
-                            = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom
-                            = mOverscanScreenTop + mOverscanScreenHeight;
-                } else if (canHideNavigationBar()
-                        && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
-                        && (attrs.type == TYPE_STATUS_BAR
-                            || attrs.type == TYPE_TOAST
-                            || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
-                    // Asking for layout as if the nav bar is hidden, lets the
-                    // application extend into the unrestricted screen area.  We
-                    // only do this for application windows (or toasts) to ensure no window that
-                    // can be above the nav bar can do this.
-                    // XXX This assumes that an app asking for this will also
-                    // ask for layout in only content.  We can't currently figure out
-                    // what the screen would be if only laying out to hide the nav bar.
-                    pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
-                    pf.right = df.right = of.right = cf.right = mUnrestrictedScreenLeft
-                            + mUnrestrictedScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
-                            + mUnrestrictedScreenHeight;
-                } else {
-                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
-                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
-                            + mRestrictedScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
-                            + mRestrictedScreenHeight;
-                }
-
-                applyStableConstraints(sysUiFl, fl, cf);
-
-                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
-                    vf.left = mCurLeft;
-                    vf.top = mCurTop;
-                    vf.right = mCurRight;
-                    vf.bottom = mCurBottom;
-                } else {
-                    vf.set(cf);
-                }
-            } else if (attached != null) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
-                        "): attached to " + attached);
-                // A child window should be placed inside of the same visible
-                // frame that its parent had.
-                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf);
-            } else {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
-                        "): normal window");
-                // Otherwise, a normal window must be placed inside the content
-                // of all screen decorations.
-                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
-                    // Status bar panels are the only windows who can go on top of
-                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
-                    // permission, so they have the same privileges as the status
-                    // bar itself.
-                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
-                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
-                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
-                            + mRestrictedScreenWidth;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
-                            + mRestrictedScreenHeight;
-                } else if (attrs.type == TYPE_TOAST || attrs.type == TYPE_SYSTEM_ALERT
-                        || attrs.type == TYPE_VOLUME_OVERLAY) {
-                    // These dialogs are stable to interim decor changes.
-                    pf.left = df.left = of.left = cf.left = mStableLeft;
-                    pf.top = df.top = of.top = cf.top = mStableTop;
-                    pf.right = df.right = of.right = cf.right = mStableRight;
-                    pf.bottom = df.bottom = of.bottom = cf.bottom = mStableBottom;
-                } else {
-                    pf.left = mContentLeft;
-                    pf.top = mContentTop;
-                    pf.right = mContentRight;
-                    pf.bottom = mContentBottom;
-                    if (win.isVoiceInteraction()) {
-                        df.left = of.left = cf.left = mVoiceContentLeft;
-                        df.top = of.top = cf.top = mVoiceContentTop;
-                        df.right = of.right = cf.right = mVoiceContentRight;
-                        df.bottom = of.bottom = cf.bottom = mVoiceContentBottom;
-                    } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
-                        df.left = of.left = cf.left = mDockLeft;
-                        df.top = of.top = cf.top = mDockTop;
-                        df.right = of.right = cf.right = mDockRight;
-                        df.bottom = of.bottom = cf.bottom = mDockBottom;
-                    } else {
-                        df.left = of.left = cf.left = mContentLeft;
-                        df.top = of.top = cf.top = mContentTop;
-                        df.right = of.right = cf.right = mContentRight;
-                        df.bottom = of.bottom = cf.bottom = mContentBottom;
-                    }
-                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
-                        vf.left = mCurLeft;
-                        vf.top = mCurTop;
-                        vf.right = mCurRight;
-                        vf.bottom = mCurBottom;
-                    } else {
-                        vf.set(cf);
-                    }
-                }
-            }
-        }
-
-        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
-        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
-            df.left = df.top = -10000;
-            df.right = df.bottom = 10000;
-            if (attrs.type != TYPE_WALLPAPER) {
-                of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
-                of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
-            }
-        }
-
-        if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
-                + ": sim=#" + Integer.toHexString(sim)
-                + " attach=" + attached + " type=" + attrs.type
-                + String.format(" flags=0x%08x", fl)
-                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
-                + " of=" + of.toShortString()
-                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
-                + " dcf=" + dcf.toShortString()
-                + " sf=" + sf.toShortString());
-
-        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf);
-
-        // Dock windows carve out the bottom of the screen, so normal windows
-        // can't appear underneath them.
-        if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw()
-                && !win.getGivenInsetsPendingLw()) {
-            setLastInputMethodWindowLw(null, null);
-            offsetInputMethodWindowLw(win);
-        }
-        if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleOrBehindKeyguardLw()
-                && !win.getGivenInsetsPendingLw()) {
-            offsetVoiceInputWindowLw(win);
-        }
-    }
-
-    private void offsetInputMethodWindowLw(WindowState win) {
-        int top = win.getContentFrameLw().top;
-        top += win.getGivenContentInsetsLw().top;
-        if (mContentBottom > top) {
-            mContentBottom = top;
-        }
-        if (mVoiceContentBottom > top) {
-            mVoiceContentBottom = top;
-        }
-        top = win.getVisibleFrameLw().top;
-        top += win.getGivenVisibleInsetsLw().top;
-        if (mCurBottom > top) {
-            mCurBottom = top;
-        }
-        if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
-                + mDockBottom + " mContentBottom="
-                + mContentBottom + " mCurBottom=" + mCurBottom);
-    }
-
-    private void offsetVoiceInputWindowLw(WindowState win) {
-        final int gravity = win.getAttrs().gravity;
-        switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER)
-                << Gravity.AXIS_X_SHIFT)) {
-            case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_X_SHIFT: {
-                int right = win.getContentFrameLw().right - win.getGivenContentInsetsLw().right;
-                if (mVoiceContentLeft < right) {
-                    mVoiceContentLeft = right;
-                }
-            } break;
-            case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_X_SHIFT: {
-                int left = win.getContentFrameLw().left - win.getGivenContentInsetsLw().left;
-                if (mVoiceContentRight < left) {
-                    mVoiceContentRight = left;
-                }
-            } break;
-        }
-        switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER)
-                << Gravity.AXIS_Y_SHIFT)) {
-            case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_Y_SHIFT: {
-                int bottom = win.getContentFrameLw().bottom - win.getGivenContentInsetsLw().bottom;
-                if (mVoiceContentTop < bottom) {
-                    mVoiceContentTop = bottom;
-                }
-            } break;
-            case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_Y_SHIFT: {
-                int top = win.getContentFrameLw().top - win.getGivenContentInsetsLw().top;
-                if (mVoiceContentBottom < top) {
-                    mVoiceContentBottom = top;
-                }
-            } break;
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void finishLayoutLw() {
-        return;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
-        mTopFullscreenOpaqueWindowState = null;
-        mAppsToBeHidden.clear();
-        mAppsThatDismissKeyguard.clear();
-        mForceStatusBar = false;
-        mForceStatusBarFromKeyguard = false;
-        mForcingShowNavBar = false;
-        mForcingShowNavBarLayer = -1;
-
-        mHideLockScreen = false;
-        mAllowLockscreenWhenOn = false;
-        mDismissKeyguard = DISMISS_KEYGUARD_NONE;
-        mShowingLockscreen = false;
-        mShowingDream = false;
-        mWinShowWhenLocked = null;
-        mKeyguardSecure = isKeyguardSecure();
-        mKeyguardSecureIncludingHidden = mKeyguardSecure
-                && (mKeyguardDelegate != null && mKeyguardDelegate.isShowing());
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
-            WindowState attached) {
-
-        if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
-                + win.isVisibleOrBehindKeyguardLw());
-        final int fl = PolicyControl.getWindowFlags(win, attrs);
-        if (mTopFullscreenOpaqueWindowState == null
-                && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
-            mForcingShowNavBar = true;
-            mForcingShowNavBarLayer = win.getSurfaceLayer();
-        }
-        if (attrs.type == TYPE_STATUS_BAR && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-            mForceStatusBarFromKeyguard = true;
-        }
-        if (mTopFullscreenOpaqueWindowState == null &&
-                win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
-            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
-                if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                    mForceStatusBarFromKeyguard = true;
-                } else {
-                    mForceStatusBar = true;
-                }
-            }
-            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                mShowingLockscreen = true;
-            }
-            boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
-                    && attrs.type < FIRST_SYSTEM_WINDOW;
-            if (attrs.type == TYPE_DREAM) {
-                // If the lockscreen was showing when the dream started then wait
-                // for the dream to draw before hiding the lockscreen.
-                if (!mDreamingLockscreen
-                        || (win.isVisibleLw() && win.hasDrawnLw())) {
-                    mShowingDream = true;
-                    appWindow = true;
-                }
-            }
-
-            final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
-            final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
-            final IApplicationToken appToken = win.getAppToken();
-
-            // For app windows that are not attached, we decide if all windows in the app they
-            // represent should be hidden or if we should hide the lockscreen. For attached app
-            // windows we defer the decision to the window it is attached to.
-            if (appWindow && attached == null) {
-                if (showWhenLocked) {
-                    // Remove any previous windows with the same appToken.
-                    mAppsToBeHidden.remove(appToken);
-                    mAppsThatDismissKeyguard.remove(appToken);
-                    if (mAppsToBeHidden.isEmpty()) {
-                        if (dismissKeyguard && !mKeyguardSecure) {
-                            mAppsThatDismissKeyguard.add(appToken);
-                        } else {
-                            mWinShowWhenLocked = win;
-                            mHideLockScreen = true;
-                            mForceStatusBarFromKeyguard = false;
-                        }
-                    }
-                } else if (dismissKeyguard) {
-                    if (mKeyguardSecure) {
-                        mAppsToBeHidden.add(appToken);
-                    } else {
-                        mAppsToBeHidden.remove(appToken);
-                    }
-                    mAppsThatDismissKeyguard.add(appToken);
-                } else {
-                    mAppsToBeHidden.add(appToken);
-                }
-                if (attrs.x == 0 && attrs.y == 0
-                        && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
-                        && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
-                    mTopFullscreenOpaqueWindowState = win;
-                    if (!mAppsThatDismissKeyguard.isEmpty() &&
-                            mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG,
-                                "Setting mDismissKeyguard true by win " + win);
-                        mDismissKeyguard = mWinDismissingKeyguard == win ?
-                                DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
-                        mWinDismissingKeyguard = win;
-                        mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
-                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG,
-                                "Setting mHideLockScreen to true by win " + win);
-                        mHideLockScreen = true;
-                        mForceStatusBarFromKeyguard = false;
-                    }
-                    if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
-                        mAllowLockscreenWhenOn = true;
-                    }
-                }
-
-                if (mWinShowWhenLocked != null &&
-                        mWinShowWhenLocked.getAppToken() != win.getAppToken()) {
-                    win.hideLw(false);
-                }
-            }
-        }
-    }
-
-    /** {@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;
-
-        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
-                ? mTopFullscreenOpaqueWindowState.getAttrs()
-                : null;
-
-        // If we are not currently showing a dream then remember the current
-        // lockscreen state.  We will use this to determine whether the dream
-        // started while the lockscreen was showing and remember this state
-        // while the dream is showing.
-        if (!mShowingDream) {
-            mDreamingLockscreen = mShowingLockscreen;
-        }
-
-        if (mStatusBar != null) {
-            if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
-                    + " forcefkg=" + mForceStatusBarFromKeyguard
-                    + " top=" + mTopFullscreenOpaqueWindowState);
-            if (mForceStatusBar || mForceStatusBarFromKeyguard) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
-                if (mStatusBarController.setBarShowingLw(true)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT;
-                }
-                // Maintain fullscreen layout until incoming animation is complete.
-                topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
-                // Transient status bar on the lockscreen is not allowed
-                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
-                    mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
-                            mLastSystemUiFlags, mLastSystemUiFlags);
-                }
-            } else if (mTopFullscreenOpaqueWindowState != null) {
-                final int fl = PolicyControl.getWindowFlags(null, lp);
-                if (localLOGV) {
-                    Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
-                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
-                    Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
-                            + " lp.flags=0x" + Integer.toHexString(fl));
-                }
-                topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
-                        || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
-                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
-                // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
-                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
-                // case though.
-                if (mStatusBarController.isTransientShowing()) {
-                    if (mStatusBarController.setBarShowingLw(true)) {
-                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
-                    }
-                } else if (topIsFullscreen) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
-                    if (mStatusBarController.setBarShowingLw(false)) {
-                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
-                    } else {
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
-                    }
-                } else {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
-                    if (mStatusBarController.setBarShowingLw(true)) {
-                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
-                    }
-                }
-            }
-        }
-
-        if (mTopIsFullscreen != topIsFullscreen) {
-            if (!topIsFullscreen) {
-                // Force another layout when status bar becomes fully shown.
-                changes |= FINISH_LAYOUT_REDO_LAYOUT;
-            }
-            mTopIsFullscreen = topIsFullscreen;
-        }
-
-        // Hide the key guard if a visible window explicitly specifies that it wants to be
-        // displayed when the screen is locked.
-        if (mKeyguardDelegate != null && mStatusBar != null) {
-            if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
-                    + mHideLockScreen);
-            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardSecure) {
-                mKeyguardHidden = true;
-                if (setKeyguardOccludedLw(true)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-                if (mKeyguardDelegate.isShowing()) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mKeyguardDelegate.keyguardDone(false, false);
-                        }
-                    });
-                }
-            } else if (mHideLockScreen) {
-                mKeyguardHidden = true;
-                if (setKeyguardOccludedLw(true)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-            } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
-                // This is the case of keyguard isSecure() and not mHideLockScreen.
-                if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
-                    // Only launch the next keyguard unlock window once per window.
-                    mKeyguardHidden = false;
-                    if (setKeyguardOccludedLw(false)) {
-                        changes |= FINISH_LAYOUT_REDO_LAYOUT
-                                | FINISH_LAYOUT_REDO_CONFIG
-                                | FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mKeyguardDelegate.dismiss();
-                        }
-                    });
-                }
-            } else {
-                mWinDismissingKeyguard = null;
-                mKeyguardHidden = false;
-                if (setKeyguardOccludedLw(false)) {
-                    changes |= FINISH_LAYOUT_REDO_LAYOUT
-                            | FINISH_LAYOUT_REDO_CONFIG
-                            | FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-            }
-        }
-
-        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
-            // If the navigation bar has been hidden or shown, we need to do another
-            // layout pass to update that window.
-            changes |= FINISH_LAYOUT_REDO_LAYOUT;
-        }
-
-        // update since mAllowLockscreenWhenOn might have changed
-        updateLockScreenTimeout();
-        return changes;
-    }
-
-    /**
-     * Updates the occluded state of the Keyguard.
-     *
-     * @return Whether the flags have changed and we have to redo the layout.
-     */
-    private boolean setKeyguardOccludedLw(boolean isOccluded) {
-        boolean wasOccluded = mKeyguardOccluded;
-        boolean showing = mKeyguardDelegate.isShowing();
-        if (wasOccluded && !isOccluded && showing) {
-            mKeyguardOccluded = false;
-            mKeyguardDelegate.setOccluded(false);
-            mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
-            mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
-            return true;
-        } else if (!wasOccluded && isOccluded && showing) {
-            mKeyguardOccluded = true;
-            mKeyguardDelegate.setOccluded(true);
-            mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
-            mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    private boolean isStatusBarKeyguard() {
-        return mStatusBar != null
-                && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
-    }
-
-    @Override
-    public boolean allowAppAnimationsLw() {
-        if (isStatusBarKeyguard() || mShowingDream) {
-            // If keyguard or dreams is currently visible, no reason to animate behind it.
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
-        mFocusedWindow = newFocus;
-        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
-            // If the navigation bar has been hidden or shown, we need to do another
-            // layout pass to update that window.
-            return FINISH_LAYOUT_REDO_LAYOUT;
-        }
-        return 0;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-        // lid changed state
-        final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
-        if (newLidState == mLidState) {
-            return;
-        }
-
-        mLidState = newLidState;
-        applyLidSwitchState();
-        updateRotation(true);
-
-        if (lidOpen) {
-            wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch);
-        } else if (!mLidControlsSleep) {
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
-        }
-    }
-
-    @Override
-    public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
-        int lensCoverState = lensCovered ? CAMERA_LENS_COVERED : CAMERA_LENS_UNCOVERED;
-        if (mCameraLensCoverState == lensCoverState) {
-            return;
-        }
-        if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
-                lensCoverState == CAMERA_LENS_UNCOVERED) {
-            Intent intent;
-            final boolean keyguardActive = mKeyguardDelegate == null ? false :
-                    mKeyguardDelegate.isShowing();
-            if (keyguardActive) {
-                intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
-            } else {
-                intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
-            }
-            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens);
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
-        }
-        mCameraLensCoverState = lensCoverState;
-    }
-
-    void setHdmiPlugged(boolean plugged) {
-        if (mHdmiPlugged != plugged) {
-            mHdmiPlugged = plugged;
-            updateRotation(true, true);
-            Intent intent = new Intent(ACTION_HDMI_PLUGGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
-            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-        }
-    }
-
-    void initializeHdmiState() {
-        boolean plugged = false;
-        // watch for HDMI plug messages if the hdmi switch exists
-        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
-            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
-
-            final String filename = "/sys/class/switch/hdmi/state";
-            FileReader reader = null;
-            try {
-                reader = new FileReader(filename);
-                char[] buf = new char[15];
-                int n = reader.read(buf);
-                if (n > 1) {
-                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
-                }
-            } catch (IOException ex) {
-                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
-            } catch (NumberFormatException ex) {
-                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
-            } finally {
-                if (reader != null) {
-                    try {
-                        reader.close();
-                    } catch (IOException ex) {
-                    }
-                }
-            }
-        }
-        // This dance forces the code in setHdmiPlugged to run.
-        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
-        mHdmiPlugged = !plugged;
-        setHdmiPlugged(!mHdmiPlugged);
-    }
-
-    final Object mScreenshotLock = new Object();
-    ServiceConnection mScreenshotConnection = null;
-
-    final Runnable mScreenshotTimeout = new Runnable() {
-        @Override public void run() {
-            synchronized (mScreenshotLock) {
-                if (mScreenshotConnection != null) {
-                    mContext.unbindService(mScreenshotConnection);
-                    mScreenshotConnection = null;
-                }
-            }
-        }
-    };
-
-    // Assume this is called from the Handler thread.
-    private void takeScreenshot() {
-        synchronized (mScreenshotLock) {
-            if (mScreenshotConnection != null) {
-                return;
-            }
-            ComponentName cn = new ComponentName("com.android.systemui",
-                    "com.android.systemui.screenshot.TakeScreenshotService");
-            Intent intent = new Intent();
-            intent.setComponent(cn);
-            ServiceConnection conn = new ServiceConnection() {
-                @Override
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                    synchronized (mScreenshotLock) {
-                        if (mScreenshotConnection != this) {
-                            return;
-                        }
-                        Messenger messenger = new Messenger(service);
-                        Message msg = Message.obtain(null, 1);
-                        final ServiceConnection myConn = this;
-                        Handler h = new Handler(mHandler.getLooper()) {
-                            @Override
-                            public void handleMessage(Message msg) {
-                                synchronized (mScreenshotLock) {
-                                    if (mScreenshotConnection == myConn) {
-                                        mContext.unbindService(mScreenshotConnection);
-                                        mScreenshotConnection = null;
-                                        mHandler.removeCallbacks(mScreenshotTimeout);
-                                    }
-                                }
-                            }
-                        };
-                        msg.replyTo = new Messenger(h);
-                        msg.arg1 = msg.arg2 = 0;
-                        if (mStatusBar != null && mStatusBar.isVisibleLw())
-                            msg.arg1 = 1;
-                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
-                            msg.arg2 = 1;
-                        try {
-                            messenger.send(msg);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-                @Override
-                public void onServiceDisconnected(ComponentName name) {}
-            };
-            if (mContext.bindServiceAsUser(
-                    intent, conn, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
-                mScreenshotConnection = conn;
-                mHandler.postDelayed(mScreenshotTimeout, 10000);
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
-        if (!mSystemBooted) {
-            // If we have not yet booted, don't let key events do anything.
-            return 0;
-        }
-
-        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
-        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-        final boolean canceled = event.isCanceled();
-        final int keyCode = event.getKeyCode();
-
-        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
-
-        // If screen is off then we treat the case where the keyguard is open but hidden
-        // the same as if it were open and in front.
-        // This will prevent any keys other than the power button from waking the screen
-        // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (mKeyguardDelegate == null ? false :
-                                            (interactive ?
-                                                isKeyguardShowingAndNotOccluded() :
-                                                mKeyguardDelegate.isShowing()));
-
-        if (DEBUG_INPUT) {
-            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
-                    + " policyFlags=" + Integer.toHexString(policyFlags));
-        }
-
-        // Basic policy based on interactive state.
-        int result;
-        boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
-                || event.isWakeKey();
-        if (interactive || (isInjected && !isWakeKey)) {
-            // When the device is interactive or the key is injected pass the
-            // key to the application.
-            result = ACTION_PASS_TO_USER;
-            isWakeKey = false;
-        } else if (!interactive && shouldDispatchInputWhenNonInteractive()) {
-            // If we're currently dozing with the screen on and the keyguard showing, pass the key
-            // to the application but preserve its wake key status to make sure we still move
-            // from dozing to fully interactive if we would normally go from off to fully
-            // interactive.
-            result = ACTION_PASS_TO_USER;
-        } else {
-            // When the screen is off and the key is not injected, determine whether
-            // to wake the device but don't pass the key to the application.
-            result = 0;
-            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
-                isWakeKey = false;
-            }
-        }
-
-        // If the key would be handled globally, just return the result, don't worry about special
-        // key processing.
-        if (isValidGlobalKey(keyCode)
-                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
-            if (isWakeKey) {
-                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
-            }
-            return result;
-        }
-
-        boolean useHapticFeedback = down
-                && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
-                && event.getRepeatCount() == 0;
-
-        // Handle special keys.
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                    if (down) {
-                        if (interactive && !mScreenshotChordVolumeDownKeyTriggered
-                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mScreenshotChordVolumeDownKeyTriggered = true;
-                            mScreenshotChordVolumeDownKeyTime = event.getDownTime();
-                            mScreenshotChordVolumeDownKeyConsumed = false;
-                            cancelPendingPowerKeyAction();
-                            interceptScreenshotChord();
-                        }
-                    } else {
-                        mScreenshotChordVolumeDownKeyTriggered = false;
-                        cancelPendingScreenshotChordAction();
-                    }
-                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                    if (down) {
-                        if (interactive && !mScreenshotChordVolumeUpKeyTriggered
-                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mScreenshotChordVolumeUpKeyTriggered = true;
-                            cancelPendingPowerKeyAction();
-                            cancelPendingScreenshotChordAction();
-                        }
-                    } else {
-                        mScreenshotChordVolumeUpKeyTriggered = false;
-                        cancelPendingScreenshotChordAction();
-                    }
-                }
-                if (down) {
-                    TelecomManager telecomManager = getTelecommService();
-                    if (telecomManager != null) {
-                        if (telecomManager.isRinging()) {
-                            // If an incoming call is ringing, either VOLUME key means
-                            // "silence ringer".  We handle these keys here, rather than
-                            // in the InCallScreen, to make sure we'll respond to them
-                            // even if the InCallScreen hasn't come to the foreground yet.
-                            // Look for the DOWN event here, to agree with the "fallback"
-                            // behavior in the InCallScreen.
-                            Log.i(TAG, "interceptKeyBeforeQueueing:"
-                                  + " VOLUME key-down while ringing: Silence ringer!");
-
-                            // Silence the ringer.  (It's safe to call this
-                            // even if the ringer has already been silenced.)
-                            telecomManager.silenceRinger();
-
-                            // And *don't* pass this key thru to the current activity
-                            // (which is probably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
-                            break;
-                        }
-                        if (telecomManager.isInCall()
-                                && (result & ACTION_PASS_TO_USER) == 0) {
-                            // If we are in call but we decided not to pass the key to
-                            // the application, just pass it to the session service.
-
-                            MediaSessionLegacyHelper.getHelper(mContext)
-                                    .sendVolumeKeyEvent(event, false);
-                            break;
-                        }
-                    }
-
-                    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)
-                                .sendVolumeKeyEvent(event, true);
-                        break;
-                    }
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_ENDCALL: {
-                result &= ~ACTION_PASS_TO_USER;
-                if (down) {
-                    TelecomManager telecomManager = getTelecommService();
-                    boolean hungUp = false;
-                    if (telecomManager != null) {
-                        hungUp = telecomManager.endCall();
-                    }
-                    if (interactive && !hungUp) {
-                        mEndCallKeyHandled = false;
-                        mHandler.postDelayed(mEndCallLongPress,
-                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
-                    } else {
-                        mEndCallKeyHandled = true;
-                    }
-                } else {
-                    if (!mEndCallKeyHandled) {
-                        mHandler.removeCallbacks(mEndCallLongPress);
-                        if (!canceled) {
-                            if ((mEndcallBehavior
-                                    & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
-                                if (goHome()) {
-                                    break;
-                                }
-                            }
-                            if ((mEndcallBehavior
-                                    & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                                mPowerManager.goToSleep(event.getEventTime(),
-                                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                                isWakeKey = false;
-                            }
-                        }
-                    }
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_POWER: {
-                result &= ~ACTION_PASS_TO_USER;
-                isWakeKey = false; // wake-up will be handled separately
-                if (down) {
-                    interceptPowerKeyDown(event, interactive);
-                } else {
-                    interceptPowerKeyUp(event, interactive, canceled);
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_SLEEP: {
-                result &= ~ACTION_PASS_TO_USER;
-                if (!mPowerManager.isInteractive()) {
-                    useHapticFeedback = false; // suppress feedback if already non-interactive
-                }
-                mPowerManager.goToSleep(event.getEventTime(),
-                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                isWakeKey = false;
-                break;
-            }
-
-            case KeyEvent.KEYCODE_WAKEUP: {
-                result &= ~ACTION_PASS_TO_USER;
-                isWakeKey = true;
-                break;
-            }
-
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
-                    // If the global session is active pass all media keys to it
-                    // instead of the active window.
-                    result &= ~ACTION_PASS_TO_USER;
-                }
-                if ((result & ACTION_PASS_TO_USER) == 0) {
-                    // Only do this if we would otherwise not pass it to the user. In that
-                    // case, the PhoneWindow class will do the same thing, except it will
-                    // only do it if the showing app doesn't process the key on its own.
-                    // Note that we need to make a copy of the key event here because the
-                    // original key event will be recycled when we return.
-                    mBroadcastWakeLock.acquire();
-                    Message msg = mHandler.obtainMessage(MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
-                            new KeyEvent(event));
-                    msg.setAsynchronous(true);
-                    msg.sendToTarget();
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_CALL: {
-                if (down) {
-                    TelecomManager telecomManager = getTelecommService();
-                    if (telecomManager != null) {
-                        if (telecomManager.isRinging()) {
-                            Log.i(TAG, "interceptKeyBeforeQueueing:"
-                                  + " CALL key-down while ringing: Answer the call!");
-                            telecomManager.acceptRingingCall();
-
-                            // And *don't* pass this key thru to the current activity
-                            // (which is presumably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
-                        }
-                    }
-                }
-                break;
-            }
-            case KeyEvent.KEYCODE_VOICE_ASSIST: {
-                // Only do this if we would otherwise not pass it to the user. In that case,
-                // interceptKeyBeforeDispatching would apply a similar but different policy in
-                // order to invoke voice assist actions. Note that we need to make a copy of the
-                // key event here because the original key event will be recycled when we return.
-                if ((result & ACTION_PASS_TO_USER) == 0 && !down) {
-                    mBroadcastWakeLock.acquire();
-                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK,
-                            keyguardActive ? 1 : 0, 0);
-                    msg.setAsynchronous(true);
-                    msg.sendToTarget();
-                }
-            }
-        }
-
-        if (useHapticFeedback) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-
-        if (isWakeKey) {
-            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
-        }
-
-        return result;
-    }
-
-    /**
-     * Returns true if the key can have global actions attached to it.
-     * We reserve all power management keys for the system since they require
-     * very careful handling.
-     */
-    private static boolean isValidGlobalKey(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_POWER:
-            case KeyEvent.KEYCODE_WAKEUP:
-            case KeyEvent.KEYCODE_SLEEP:
-                return false;
-            default:
-                return true;
-        }
-    }
-
-    /**
-     * When the screen is off we ignore some keys that might otherwise typically
-     * be considered wake keys.  We filter them out here.
-     *
-     * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it
-     * is always considered a wake key.
-     */
-    private boolean isWakeKeyWhenScreenOff(int keyCode) {
-        switch (keyCode) {
-            // ignore volume keys unless docked
-            case KeyEvent.KEYCODE_VOLUME_UP:
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_MUTE:
-                return mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
-
-            // ignore media and camera keys
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-            case KeyEvent.KEYCODE_CAMERA:
-                return false;
-        }
-        return true;
-    }
-
-
-    /** {@inheritDoc} */
-    @Override
-    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
-        if ((policyFlags & FLAG_WAKE) != 0) {
-            if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) {
-                return 0;
-            }
-        }
-
-        if (shouldDispatchInputWhenNonInteractive()) {
-            return ACTION_PASS_TO_USER;
-        }
-
-        // If we have not passed the action up and we are in theater mode without dreaming,
-        // there will be no dream to intercept the touch and wake into ambient.  The device should
-        // wake up in this case.
-        if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
-            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming);
-        }
-
-        return 0;
-    }
-
-    private boolean shouldDispatchInputWhenNonInteractive() {
-        // Send events to keyguard while the screen is on.
-        if (isKeyguardShowingAndNotOccluded() && mDisplay != null
-                && mDisplay.getState() != Display.STATE_OFF) {
-            return true;
-        }
-
-        // Send events to a dozing dream even if the screen is off since the dream
-        // is in control of the state of the screen.
-        IDreamManager dreamManager = getDreamManager();
-
-        try {
-            if (dreamManager != null && dreamManager.isDreaming()) {
-                return true;
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException when checking if dreaming", e);
-        }
-
-        // Otherwise, consume events since the user can't see what is being
-        // interacted with.
-        return false;
-    }
-
-    void dispatchMediaKeyWithWakeLock(KeyEvent event) {
-        if (DEBUG_INPUT) {
-            Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
-        }
-
-        if (mHavePendingMediaKeyRepeatWithWakeLock) {
-            if (DEBUG_INPUT) {
-                Slog.d(TAG, "dispatchMediaKeyWithWakeLock: canceled repeat");
-            }
-
-            mHandler.removeMessages(MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK);
-            mHavePendingMediaKeyRepeatWithWakeLock = false;
-            mBroadcastWakeLock.release(); // pending repeat was holding onto the wake lock
-        }
-
-        dispatchMediaKeyWithWakeLockToAudioService(event);
-
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && event.getRepeatCount() == 0) {
-            mHavePendingMediaKeyRepeatWithWakeLock = true;
-
-            Message msg = mHandler.obtainMessage(
-                    MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK, event);
-            msg.setAsynchronous(true);
-            mHandler.sendMessageDelayed(msg, ViewConfiguration.getKeyRepeatTimeout());
-        } else {
-            mBroadcastWakeLock.release();
-        }
-    }
-
-    void dispatchMediaKeyRepeatWithWakeLock(KeyEvent event) {
-        mHavePendingMediaKeyRepeatWithWakeLock = false;
-
-        KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(event,
-                SystemClock.uptimeMillis(), 1, event.getFlags() | KeyEvent.FLAG_LONG_PRESS);
-        if (DEBUG_INPUT) {
-            Slog.d(TAG, "dispatchMediaKeyRepeatWithWakeLock: " + repeatEvent);
-        }
-
-        dispatchMediaKeyWithWakeLockToAudioService(repeatEvent);
-        mBroadcastWakeLock.release();
-    }
-
-    void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
-        if (ActivityManagerNative.isSystemReady()) {
-            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
-        }
-    }
-
-    void launchVoiceAssistWithWakeLock(boolean keyguardActive) {
-        Intent voiceIntent =
-            new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-        voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive);
-        mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
-        mBroadcastWakeLock.release();
-    }
-
-    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
-                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
-            } else {
-                try {
-                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
-                            ServiceManager.getService(Context.UI_MODE_SERVICE));
-                    mUiMode = uiModeService.getCurrentModeType();
-                } catch (RemoteException e) {
-                }
-            }
-            updateRotation(true);
-            synchronized (mLock) {
-                updateOrientationListenerLp();
-            }
-        }
-    };
-
-    BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
-                if (mKeyguardDelegate != null) {
-                    mKeyguardDelegate.onDreamingStarted();
-                }
-            } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
-                if (mKeyguardDelegate != null) {
-                    mKeyguardDelegate.onDreamingStopped();
-                }
-            }
-        }
-    };
-
-    BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-                // tickle the settings observer: this first ensures that we're
-                // observing the relevant settings for the newly-active user,
-                // and then updates our own bookkeeping based on the now-
-                // current user.
-                mSettingsObserver.onChange(false);
-
-                // force a re-application of focused window sysui visibility.
-                // the window may never have been shown for this user
-                // e.g. the keyguard when going through the new-user setup flow
-                synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-                    mLastSystemUiFlags = 0;
-                    updateSystemUiVisibilityLw();
-                }
-            }
-        }
-    };
-
-    private final Runnable mRequestTransientNav = new Runnable() {
-        @Override
-        public void run() {
-            requestTransientBars(mNavigationBar);
-        }
-    };
-
-    private void requestTransientBars(WindowState swipeTarget) {
-        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
-            if (!isUserSetupComplete()) {
-                // Swipe-up for navigation bar is disabled during setup
-                return;
-            }
-            boolean sb = mStatusBarController.checkShowTransientBarLw();
-            boolean nb = mNavigationBarController.checkShowTransientBarLw();
-            if (sb || nb) {
-                WindowState barTarget = sb ? mStatusBar : mNavigationBar;
-                if (sb ^ nb && barTarget != swipeTarget) {
-                    if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
-                    return;
-                }
-                if (sb) mStatusBarController.showTransient();
-                if (nb) mNavigationBarController.showTransient();
-                mImmersiveModeConfirmation.confirmCurrentPrompt();
-                updateSystemUiVisibilityLw();
-            }
-        }
-    }
-
-    // Called on the PowerManager's Notifier thread.
-    @Override
-    public void goingToSleep(int why) {
-        EventLog.writeEvent(70000, 0);
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
-
-        // We must get this work done here because the power manager will drop
-        // the wake lock and let the system suspend once this function returns.
-        synchronized (mLock) {
-            mAwake = false;
-            mKeyguardDrawComplete = false;
-            updateWakeGestureListenerLp();
-            updateOrientationListenerLp();
-            updateLockScreenTimeout();
-        }
-
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.onScreenTurnedOff(why);
-        }
-    }
-
-    private void wakeUpFromPowerKey(long eventTime) {
-        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
-    }
-
-    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
-        if (!wakeInTheaterMode && isTheaterModeEnabled()) {
-            return false;
-        }
-
-        mPowerManager.wakeUp(wakeTime);
-        return true;
-    }
-
-    // Called on the PowerManager's Notifier thread.
-    @Override
-    public void wakingUp() {
-        EventLog.writeEvent(70000, 1);
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
-
-        // Since goToSleep performs these functions synchronously, we must
-        // do the same here.  We cannot post this work to a handler because
-        // that might cause it to become reordered with respect to what
-        // may happen in a future call to goToSleep.
-        synchronized (mLock) {
-            mAwake = true;
-            mKeyguardDrawComplete = false;
-            if (mKeyguardDelegate != null) {
-                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
-                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
-            }
-
-            updateWakeGestureListenerLp();
-            updateOrientationListenerLp();
-            updateLockScreenTimeout();
-        }
-
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.onScreenTurnedOn(mKeyguardDelegateCallback);
-            // ... eventually calls finishKeyguardDrawn
-        } else {
-            if (DEBUG_WAKEUP) Slog.d(TAG, "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
-            finishKeyguardDrawn();
-        }
-    }
-
-    private void finishKeyguardDrawn() {
-        synchronized (mLock) {
-            if (!mAwake || mKeyguardDrawComplete) {
-                return; // spurious
-            }
-
-            mKeyguardDrawComplete = true;
-            if (mKeyguardDelegate != null) {
-                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
-            }
-        }
-
-        finishScreenTurningOn();
-    }
-
-    // Called on the DisplayManager's DisplayPowerController thread.
-    @Override
-    public void screenTurnedOff() {
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
-
-        synchronized (mLock) {
-            mScreenOnEarly = false;
-            mScreenOnFully = false;
-            mWindowManagerDrawComplete = false;
-            mScreenOnListener = null;
-            updateOrientationListenerLp();
-        }
-    }
-
-    // Called on the DisplayManager's DisplayPowerController thread.
-    @Override
-    public void screenTurningOn(final ScreenOnListener screenOnListener) {
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
-
-        synchronized (mLock) {
-            mScreenOnEarly = true;
-            mScreenOnFully = false;
-            mWindowManagerDrawComplete = false;
-            mScreenOnListener = screenOnListener;
-            updateOrientationListenerLp();
-        }
-
-        mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
-                WAITING_FOR_DRAWN_TIMEOUT);
-        // ... eventually calls finishWindowsDrawn
-    }
-
-    private void finishWindowsDrawn() {
-        synchronized (mLock) {
-            if (!mScreenOnEarly || mWindowManagerDrawComplete) {
-                return; // spurious
-            }
-
-            mWindowManagerDrawComplete = true;
-        }
-
-        finishScreenTurningOn();
-    }
-
-    private void finishScreenTurningOn() {
-        final ScreenOnListener listener;
-        final boolean enableScreen;
-        synchronized (mLock) {
-            if (DEBUG_WAKEUP) Slog.d(TAG,
-                    "finishScreenTurningOn: mAwake=" + mAwake
-                            + ", mScreenOnEarly=" + mScreenOnEarly
-                            + ", mScreenOnFully=" + mScreenOnFully
-                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
-                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
-
-            if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
-                    || (mAwake && !mKeyguardDrawComplete)) {
-                return; // spurious or not ready yet
-            }
-
-            if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
-            listener = mScreenOnListener;
-            mScreenOnListener = null;
-            mScreenOnFully = true;
-
-            // Remember the first time we draw the keyguard so we know when we're done with
-            // the main part of booting and can enable the screen and hide boot messages.
-            if (!mKeyguardDrawnOnce && mAwake) {
-                mKeyguardDrawnOnce = true;
-                enableScreen = true;
-                if (mBootMessageNeedsHiding) {
-                    mBootMessageNeedsHiding = false;
-                    hideBootMessages();
-                }
-            } else {
-                enableScreen = false;
-            }
-        }
-
-        if (listener != null) {
-            listener.onScreenOn();
-        }
-
-        if (enableScreen) {
-            try {
-                mWindowManager.enableScreenIfNeeded();
-            } catch (RemoteException unhandled) {
-            }
-        }
-    }
-
-    private void handleHideBootMessage() {
-        synchronized (mLock) {
-            if (!mKeyguardDrawnOnce) {
-                mBootMessageNeedsHiding = true;
-                return; // keyguard hasn't drawn the first time yet, not done booting
-            }
-        }
-
-        if (mBootMsgDialog != null) {
-            if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: dismissing");
-            mBootMsgDialog.dismiss();
-            mBootMsgDialog = null;
-        }
-    }
-
-    @Override
-    public boolean isScreenOn() {
-        return mScreenOnFully;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void enableKeyguard(boolean enabled) {
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.setKeyguardEnabled(enabled);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.verifyUnlock(callback);
-        }
-    }
-
-    private boolean isKeyguardShowingAndNotOccluded() {
-        if (mKeyguardDelegate == null) return false;
-        return mKeyguardDelegate.isShowing() && !mKeyguardOccluded;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isKeyguardLocked() {
-        return keyguardOn();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isKeyguardSecure() {
-        if (mKeyguardDelegate == null) return false;
-        return mKeyguardDelegate.isSecure();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean inKeyguardRestrictedKeyInputMode() {
-        if (mKeyguardDelegate == null) return false;
-        return mKeyguardDelegate.isInputRestricted();
-    }
-
-    @Override
-    public void dismissKeyguardLw() {
-        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
-            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    // ask the keyguard to prompt the user to authenticate if necessary
-                    mKeyguardDelegate.dismiss();
-                }
-            });
-        }
-    }
-
-    public void notifyActivityDrawnForKeyguardLw() {
-        if (mKeyguardDelegate != null) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mKeyguardDelegate.onActivityDrawn();
-                }
-            });
-        }
-    }
-
-    @Override
-    public boolean isKeyguardDrawnLw() {
-        synchronized (mLock) {
-            return mKeyguardDrawnOnce;
-        }
-    }
-
-    @Override
-    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
-        if (mKeyguardDelegate != null) {
-            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
-            mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration);
-        }
-    }
-
-    void sendCloseSystemWindows() {
-        sendCloseSystemWindows(mContext, null);
-    }
-
-    void sendCloseSystemWindows(String reason) {
-        sendCloseSystemWindows(mContext, reason);
-    }
-
-    static void sendCloseSystemWindows(Context context, String reason) {
-        if (ActivityManagerNative.isSystemReady()) {
-            try {
-                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-
-    @Override
-    public int rotationForOrientationLw(int orientation, int lastRotation) {
-        if (false) {
-            Slog.v(TAG, "rotationForOrientationLw(orient="
-                        + orientation + ", last=" + lastRotation
-                        + "); user=" + mUserRotation + " "
-                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
-                            ? "USER_ROTATION_LOCKED" : "")
-                        );
-        }
-
-        if (mForceDefaultOrientation) {
-            return Surface.ROTATION_0;
-        }
-
-        synchronized (mLock) {
-            int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
-            if (sensorRotation < 0) {
-                sensorRotation = lastRotation;
-            }
-
-            final int preferredRotation;
-            if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
-                // Ignore sensor when lid switch is open and rotation is forced.
-                preferredRotation = mLidOpenRotation;
-            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
-                    && (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {
-                // Ignore sensor when in car dock unless explicitly enabled.
-                // This case can override the behavior of NOSENSOR, and can also
-                // enable 180 degree rotation while docked.
-                preferredRotation = mCarDockEnablesAccelerometer
-                        ? sensorRotation : mCarDockRotation;
-            } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
-                    || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
-                    || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
-                    && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
-                // Ignore sensor when in desk dock unless explicitly enabled.
-                // This case can override the behavior of NOSENSOR, and can also
-                // enable 180 degree rotation while docked.
-                preferredRotation = mDeskDockEnablesAccelerometer
-                        ? sensorRotation : mDeskDockRotation;
-            } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
-                // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
-                // Note that the dock orientation overrides the HDMI orientation.
-                preferredRotation = mDemoHdmiRotation;
-            } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
-                    && mUndockedHdmiRotation >= 0) {
-                // Ignore sensor when plugged into HDMI and an undocked orientation has
-                // been specified in the configuration (only for legacy devices without
-                // full multi-display support).
-                // Note that the dock orientation overrides the HDMI orientation.
-                preferredRotation = mUndockedHdmiRotation;
-            } else if (mDemoRotationLock) {
-                // Ignore sensor when demo rotation lock is enabled.
-                // Note that the dock orientation and HDMI rotation lock override this.
-                preferredRotation = mDemoRotation;
-            } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
-                // Application just wants to remain locked in the last rotation.
-                preferredRotation = lastRotation;
-            } else if (!mSupportAutoRotation) {
-                // If we don't support auto-rotation then bail out here and ignore
-                // the sensor and any rotation lock settings.
-                preferredRotation = -1;
-            } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
-                            && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
-                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
-                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
-                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
-                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
-                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
-                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
-                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
-                // Otherwise, use sensor only if requested by the application or enabled
-                // by default for USER or UNSPECIFIED modes.  Does not apply to NOSENSOR.
-                if (mAllowAllRotations < 0) {
-                    // Can't read this during init() because the context doesn't
-                    // have display metrics at that time so we cannot determine
-                    // tablet vs. phone then.
-                    mAllowAllRotations = mContext.getResources().getBoolean(
-                            com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
-                }
-                if (sensorRotation != Surface.ROTATION_180
-                        || mAllowAllRotations == 1
-                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
-                    preferredRotation = sensorRotation;
-                } else {
-                    preferredRotation = lastRotation;
-                }
-            } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
-                    && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
-                // Apply rotation lock.  Does not apply to NOSENSOR.
-                // The idea is that the user rotation expresses a weak preference for the direction
-                // of gravity and as NOSENSOR is never affected by gravity, then neither should
-                // NOSENSOR be affected by rotation lock (although it will be affected by docks).
-                preferredRotation = mUserRotation;
-            } else {
-                // No overriding preference.
-                // We will do exactly what the application asked us to do.
-                preferredRotation = -1;
-            }
-
-            switch (orientation) {
-                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-                    // Return portrait unless overridden.
-                    if (isAnyPortrait(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    return mPortraitRotation;
-
-                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-                    // Return landscape unless overridden.
-                    if (isLandscapeOrSeascape(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    return mLandscapeRotation;
-
-                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-                    // Return reverse portrait unless overridden.
-                    if (isAnyPortrait(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    return mUpsideDownRotation;
-
-                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-                    // Return seascape unless overridden.
-                    if (isLandscapeOrSeascape(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    return mSeascapeRotation;
-
-                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
-                case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
-                    // Return either landscape rotation.
-                    if (isLandscapeOrSeascape(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    if (isLandscapeOrSeascape(lastRotation)) {
-                        return lastRotation;
-                    }
-                    return mLandscapeRotation;
-
-                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
-                    // Return either portrait rotation.
-                    if (isAnyPortrait(preferredRotation)) {
-                        return preferredRotation;
-                    }
-                    if (isAnyPortrait(lastRotation)) {
-                        return lastRotation;
-                    }
-                    return mPortraitRotation;
-
-                default:
-                    // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
-                    // just return the preferred orientation we already calculated.
-                    if (preferredRotation >= 0) {
-                        return preferredRotation;
-                    }
-                    return Surface.ROTATION_0;
-            }
-        }
-    }
-
-    @Override
-    public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation) {
-        switch (orientation) {
-            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                return isAnyPortrait(rotation);
-
-            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
-                return isLandscapeOrSeascape(rotation);
-
-            default:
-                return true;
-        }
-    }
-
-    @Override
-    public void setRotationLw(int rotation) {
-        mOrientationListener.setCurrentRotation(rotation);
-    }
-
-    private boolean isLandscapeOrSeascape(int rotation) {
-        return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
-    }
-
-    private boolean isAnyPortrait(int rotation) {
-        return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
-    }
-
-    @Override
-    public int getUserRotationMode() {
-        return Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
-                        WindowManagerPolicy.USER_ROTATION_FREE :
-                                WindowManagerPolicy.USER_ROTATION_LOCKED;
-    }
-
-    // User rotation: to be used when all else fails in assigning an orientation to the device
-    @Override
-    public void setUserRotationMode(int mode, int rot) {
-        ContentResolver res = mContext.getContentResolver();
-
-        // mUserRotationMode and mUserRotation will be assigned by the content observer
-        if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
-            Settings.System.putIntForUser(res,
-                    Settings.System.USER_ROTATION,
-                    rot,
-                    UserHandle.USER_CURRENT);
-            Settings.System.putIntForUser(res,
-                    Settings.System.ACCELEROMETER_ROTATION,
-                    0,
-                    UserHandle.USER_CURRENT);
-        } else {
-            Settings.System.putIntForUser(res,
-                    Settings.System.ACCELEROMETER_ROTATION,
-                    1,
-                    UserHandle.USER_CURRENT);
-        }
-    }
-
-    @Override
-    public void setSafeMode(boolean safeMode) {
-        mSafeMode = safeMode;
-        performHapticFeedbackLw(null, safeMode
-                ? HapticFeedbackConstants.SAFE_MODE_ENABLED
-                : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
-    }
-
-    static long[] getLongIntArray(Resources r, int resid) {
-        int[] ar = r.getIntArray(resid);
-        if (ar == null) {
-            return null;
-        }
-        long[] out = new long[ar.length];
-        for (int i=0; i<ar.length; i++) {
-            out[i] = ar[i];
-        }
-        return out;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void systemReady() {
-        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
-        mKeyguardDelegate.onSystemReady();
-
-        readCameraLensCoverState();
-        updateUiMode();
-        synchronized (mLock) {
-            updateOrientationListenerLp();
-            mSystemReady = true;
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    updateSettings();
-                }
-            });
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void systemBooted() {
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.bindService(mContext);
-            mKeyguardDelegate.onBootCompleted();
-        }
-        synchronized (mLock) {
-            mSystemBooted = true;
-        }
-        wakingUp();
-        screenTurningOn(null);
-    }
-
-    ProgressDialog mBootMsgDialog = null;
-
-    /** {@inheritDoc} */
-    @Override
-    public void showBootMessage(final CharSequence msg, final boolean always) {
-        mHandler.post(new Runnable() {
-            @Override public void run() {
-                if (mBootMsgDialog == null) {
-                    int theme;
-                    if (mContext.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_WATCH)) {
-                        theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
-                    } else if (mContext.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_TELEVISION)) {
-                        theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
-                    } else {
-                        theme = 0;
-                    }
-
-                    mBootMsgDialog = new ProgressDialog(mContext, theme) {
-                        // This dialog will consume all events coming in to
-                        // it, to avoid it trying to do things too early in boot.
-                        @Override public boolean dispatchKeyEvent(KeyEvent event) {
-                            return true;
-                        }
-                        @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) {
-                            return true;
-                        }
-                        @Override public boolean dispatchTouchEvent(MotionEvent ev) {
-                            return true;
-                        }
-                        @Override public boolean dispatchTrackballEvent(MotionEvent ev) {
-                            return true;
-                        }
-                        @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) {
-                            return true;
-                        }
-                        @Override public boolean dispatchPopulateAccessibilityEvent(
-                                AccessibilityEvent event) {
-                            return true;
-                        }
-                    };
-                    if (mContext.getPackageManager().isUpgrade()) {
-                        mBootMsgDialog.setTitle(R.string.android_upgrading_title);
-                    } else {
-                        mBootMsgDialog.setTitle(R.string.android_start_title);
-                    }
-                    mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
-                    mBootMsgDialog.setIndeterminate(true);
-                    mBootMsgDialog.getWindow().setType(
-                            WindowManager.LayoutParams.TYPE_BOOT_PROGRESS);
-                    mBootMsgDialog.getWindow().addFlags(
-                            WindowManager.LayoutParams.FLAG_DIM_BEHIND
-                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
-                    mBootMsgDialog.getWindow().setDimAmount(1);
-                    WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
-                    lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-                    mBootMsgDialog.getWindow().setAttributes(lp);
-                    mBootMsgDialog.setCancelable(false);
-                    mBootMsgDialog.show();
-                }
-                mBootMsgDialog.setMessage(msg);
-            }
-        });
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void hideBootMessages() {
-        mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void userActivity() {
-        // ***************************************
-        // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
-        // ***************************************
-        // THIS IS CALLED FROM DEEP IN THE POWER MANAGER
-        // WITH ITS LOCKS HELD.
-        //
-        // This code must be VERY careful about the locks
-        // it acquires.
-        // In fact, the current code acquires way too many,
-        // and probably has lurking deadlocks.
-
-        synchronized (mScreenLockTimeout) {
-            if (mLockScreenTimerActive) {
-                // reset the timer
-                mHandler.removeCallbacks(mScreenLockTimeout);
-                mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
-            }
-        }
-    }
-
-    class ScreenLockTimeout implements Runnable {
-        Bundle options;
-
-        @Override
-        public void run() {
-            synchronized (this) {
-                if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
-                if (mKeyguardDelegate != null) {
-                    mKeyguardDelegate.doKeyguardTimeout(options);
-                }
-                mLockScreenTimerActive = false;
-                options = null;
-            }
-        }
-
-        public void setLockOptions(Bundle options) {
-            this.options = options;
-        }
-    }
-
-    ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
-
-    @Override
-    public void lockNow(Bundle options) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        mHandler.removeCallbacks(mScreenLockTimeout);
-        if (options != null) {
-            // In case multiple calls are made to lockNow, we don't wipe out the options
-            // until the runnable actually executes.
-            mScreenLockTimeout.setLockOptions(options);
-        }
-        mHandler.post(mScreenLockTimeout);
-    }
-
-    private void updateLockScreenTimeout() {
-        synchronized (mScreenLockTimeout) {
-            boolean enable = (mAllowLockscreenWhenOn && mAwake &&
-                    mKeyguardDelegate != null && mKeyguardDelegate.isSecure());
-            if (mLockScreenTimerActive != enable) {
-                if (enable) {
-                    if (localLOGV) Log.v(TAG, "setting lockscreen timer");
-                    mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
-                } else {
-                    if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
-                    mHandler.removeCallbacks(mScreenLockTimeout);
-                }
-                mLockScreenTimerActive = enable;
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void enableScreenAfterBoot() {
-        readLidState();
-        applyLidSwitchState();
-        updateRotation(true);
-    }
-
-    private void applyLidSwitchState() {
-        if (mLidState == LID_CLOSED && mLidControlsSleep) {
-            mPowerManager.goToSleep(SystemClock.uptimeMillis(),
-                    PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
-                    PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-        }
-
-        synchronized (mLock) {
-            updateWakeGestureListenerLp();
-        }
-    }
-
-    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
-            mWindowManager.updateRotation(alwaysSendConfiguration, false);
-        } catch (RemoteException e) {
-            // Ignore
-        }
-    }
-
-    void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
-        try {
-            //set orientation on WindowManager
-            mWindowManager.updateRotation(alwaysSendConfiguration, forceRelayout);
-        } catch (RemoteException e) {
-            // Ignore
-        }
-    }
-
-    /**
-     * Return an Intent to launch the currently active dock app as home.  Returns
-     * null if the standard home should be launched, which is the case if any of the following is
-     * true:
-     * <ul>
-     *  <li>The device is not in either car mode or desk mode
-     *  <li>The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false
-     *  <li>The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false
-     *  <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME
-     *  <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME
-     * </ul>
-     * @return A dock intent.
-     */
-    Intent createHomeDockIntent() {
-        Intent intent = null;
-
-        // What home does is based on the mode, not the dock state.  That
-        // is, when in car mode you should be taken to car home regardless
-        // of whether we are actually in a car dock.
-        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
-            if (ENABLE_CAR_DOCK_HOME_CAPTURE) {
-                intent = mCarDockIntent;
-            }
-        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
-            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) {
-            return null;
-        }
-
-        ActivityInfo ai = null;
-        ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
-                intent,
-                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
-                mCurrentUserId);
-        if (info != null) {
-            ai = info.activityInfo;
-        }
-        if (ai != null
-                && ai.metaData != null
-                && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
-            intent = new Intent(intent);
-            intent.setClassName(ai.packageName, ai.name);
-            return intent;
-        }
-
-        return null;
-    }
-
-    void startDockOrHome() {
-        awakenDreams();
-
-        Intent dock = createHomeDockIntent();
-        if (dock != null) {
-            try {
-                mContext.startActivityAsUser(dock, UserHandle.CURRENT);
-                return;
-            } catch (ActivityNotFoundException e) {
-            }
-        }
-
-        mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
-    }
-
-    /**
-     * goes to the home screen
-     * @return whether it did anything
-     */
-    boolean goHome() {
-        if (false) {
-            // This code always brings home to the front.
-            try {
-                ActivityManagerNative.getDefault().stopAppSwitches();
-            } catch (RemoteException e) {
-            }
-            sendCloseSystemWindows();
-            startDockOrHome();
-        } else {
-            // This code brings home to the front or, if it is already
-            // at the front, puts the device to sleep.
-            try {
-                if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) {
-                    /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
-                    Log.d(TAG, "UTS-TEST-MODE");
-                } else {
-                    ActivityManagerNative.getDefault().stopAppSwitches();
-                    sendCloseSystemWindows();
-                    Intent dock = createHomeDockIntent();
-                    if (dock != null) {
-                        int result = ActivityManagerNative.getDefault()
-                                .startActivityAsUser(null, null, dock,
-                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
-                                        null, null, 0,
-                                        ActivityManager.START_FLAG_ONLY_IF_NEEDED,
-                                        null, null, UserHandle.USER_CURRENT);
-                        if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
-                            return false;
-                        }
-                    }
-                }
-                int result = ActivityManagerNative.getDefault()
-                        .startActivityAsUser(null, null, mHomeIntent,
-                                mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                                null, null, 0,
-                                ActivityManager.START_FLAG_ONLY_IF_NEEDED,
-                                null, null, UserHandle.USER_CURRENT);
-                if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
-                    return false;
-                }
-            } catch (RemoteException ex) {
-                // bummer, the activity manager, which is in this process, is dead
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void setCurrentOrientationLw(int newOrientation) {
-        synchronized (mLock) {
-            if (newOrientation != mCurrentAppOrientation) {
-                mCurrentAppOrientation = newOrientation;
-                updateOrientationListenerLp();
-            }
-        }
-    }
-
-    private void performAuditoryFeedbackForAccessibilityIfNeed() {
-        if (!isGlobalAccessibilityGestureEnabled()) {
-            return;
-        }
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(
-                Context.AUDIO_SERVICE);
-        if (audioManager.isSilentMode()) {
-            return;
-        }
-        Ringtone ringTone = RingtoneManager.getRingtone(mContext,
-                Settings.System.DEFAULT_NOTIFICATION_URI);
-        ringTone.setStreamType(AudioManager.STREAM_MUSIC);
-        ringTone.play();
-    }
-
-    private boolean isTheaterModeEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.THEATER_MODE_ON, 0) == 1;
-    }
-
-    private boolean isGlobalAccessibilityGestureEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
-    }
-
-    @Override
-    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
-        if (!mVibrator.hasVibrator()) {
-            return false;
-        }
-        final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
-        if (hapticsDisabled && !always) {
-            return false;
-        }
-        long[] pattern = null;
-        switch (effectId) {
-            case HapticFeedbackConstants.LONG_PRESS:
-                pattern = mLongPressVibePattern;
-                break;
-            case HapticFeedbackConstants.VIRTUAL_KEY:
-                pattern = mVirtualKeyVibePattern;
-                break;
-            case HapticFeedbackConstants.KEYBOARD_TAP:
-                pattern = mKeyboardTapVibePattern;
-                break;
-            case HapticFeedbackConstants.CLOCK_TICK:
-                pattern = mClockTickVibePattern;
-                break;
-            case HapticFeedbackConstants.CALENDAR_DATE:
-                pattern = mCalendarDateVibePattern;
-                break;
-            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
-                pattern = mSafeModeDisabledVibePattern;
-                break;
-            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
-                pattern = mSafeModeEnabledVibePattern;
-                break;
-            default:
-                return false;
-        }
-        int owningUid;
-        String owningPackage;
-        if (win != null) {
-            owningUid = win.getOwningUid();
-            owningPackage = win.getOwningPackage();
-        } else {
-            owningUid = android.os.Process.myUid();
-            owningPackage = mContext.getOpPackageName();
-        }
-        if (pattern.length == 1) {
-            // One-shot vibration
-            mVibrator.vibrate(owningUid, owningPackage, pattern[0], VIBRATION_ATTRIBUTES);
-        } else {
-            // Pattern vibration
-            mVibrator.vibrate(owningUid, owningPackage, pattern, -1, VIBRATION_ATTRIBUTES);
-        }
-        return true;
-    }
-
-    @Override
-    public void keepScreenOnStartedLw() {
-    }
-
-    @Override
-    public void keepScreenOnStoppedLw() {
-        if (isKeyguardShowingAndNotOccluded()) {
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
-        }
-    }
-
-    private int updateSystemUiVisibilityLw() {
-        // If there is no window focused, there will be nobody to handle the events
-        // anyway, so just hang on in whatever state we're in until things settle down.
-        final WindowState win = mFocusedWindow != null ? mFocusedWindow
-                : mTopFullscreenOpaqueWindowState;
-        if (win == null) {
-            return 0;
-        }
-        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
-            // We are updating at a point where the keyguard has gotten
-            // focus, but we were last in a state where the top window is
-            // hiding it.  This is probably because the keyguard as been
-            // shown while the top window was displayed, so we want to ignore
-            // it here because this is just a very transient change and it
-            // will quickly lose focus once it correctly gets hidden.
-            return 0;
-        }
-
-        int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
-                & ~mResettingSystemUiFlags
-                & ~mForceClearedSystemUiFlags;
-        if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
-            tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
-        }
-        final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
-        final int diff = visibility ^ mLastSystemUiFlags;
-        final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
-        if (diff == 0 && mLastFocusNeedsMenu == needsMenu
-                && mFocusedApp == win.getAppToken()) {
-            return 0;
-        }
-        mLastSystemUiFlags = visibility;
-        mLastFocusNeedsMenu = needsMenu;
-        mFocusedApp = win.getAppToken();
-        mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        IStatusBarService statusbar = getStatusBarService();
-                        if (statusbar != null) {
-                            statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString());
-                            statusbar.topAppWindowChanged(needsMenu);
-                        }
-                    } catch (RemoteException e) {
-                        // re-acquire status bar service next time it is needed.
-                        mStatusBarService = null;
-                    }
-                }
-            });
-        return diff;
-    }
-
-    private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
-        // apply translucent bar vis flags
-        WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
-                ? mStatusBar
-                : mTopFullscreenOpaqueWindowState;
-        vis = mStatusBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
-        vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
-
-        // prevent status bar interaction from clearing certain flags
-        boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR;
-        if (statusBarHasFocus && !isStatusBarKeyguard()) {
-            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
-                    | View.SYSTEM_UI_FLAG_IMMERSIVE
-                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-            if (mHideLockScreen) {
-                flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
-            }
-            vis = (vis & ~flags) | (oldVis & flags);
-        }
-
-        if (!areTranslucentBarsAllowed() && transWin != mStatusBar) {
-            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
-                    | View.SYSTEM_UI_TRANSPARENT);
-        }
-
-        // update status bar
-        boolean immersiveSticky =
-                (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
-        boolean hideStatusBarWM =
-                mTopFullscreenOpaqueWindowState != null &&
-                (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
-                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
-        boolean hideStatusBarSysui =
-                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
-        boolean hideNavBarSysui =
-                (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
-
-        boolean transientStatusBarAllowed =
-                mStatusBar != null && (
-                hideStatusBarWM
-                || (hideStatusBarSysui && immersiveSticky)
-                || statusBarHasFocus);
-
-        boolean transientNavBarAllowed =
-                mNavigationBar != null &&
-                hideNavBarSysui && immersiveSticky;
-
-        boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
-                && !transientStatusBarAllowed && hideStatusBarSysui;
-        boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
-                && !transientNavBarAllowed;
-        if (denyTransientStatus || denyTransientNav) {
-            // clear the clearable flags instead
-            clearClearableFlagsLw();
-        }
-
-        vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
-
-        // update navigation bar
-        boolean oldImmersiveMode = isImmersiveMode(oldVis);
-        boolean newImmersiveMode = isImmersiveMode(vis);
-        if (win != null && oldImmersiveMode != newImmersiveMode) {
-            final String pkg = win.getOwningPackage();
-            mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode,
-                    isUserSetupComplete());
-        }
-
-        vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
-
-        return vis;
-    }
-
-    private void clearClearableFlagsLw() {
-        int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
-        if (newVal != mResettingSystemUiFlags) {
-            mResettingSystemUiFlags = newVal;
-            mWindowManagerFuncs.reevaluateStatusBarVisibility();
-        }
-    }
-
-    private boolean isImmersiveMode(int vis) {
-        final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-        return mNavigationBar != null
-                && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
-                && (vis & flags) != 0
-                && canHideNavigationBar();
-    }
-
-    /**
-     * @return whether the navigation or status bar can be made translucent
-     *
-     * This should return true unless touch exploration is not enabled or
-     * R.boolean.config_enableTranslucentDecor is false.
-     */
-    private boolean areTranslucentBarsAllowed() {
-        return mTranslucentDecorEnabled
-                && !mAccessibilityManager.isTouchExplorationEnabled();
-    }
-
-    // Use this instead of checking config_showNavigationBar so that it can be consistently
-    // overridden by qemu.hw.mainkeys in the emulator.
-    @Override
-    public boolean hasNavigationBar() {
-        return mHasNavigationBar;
-    }
-
-    @Override
-    public void setLastInputMethodWindowLw(WindowState ime, WindowState target) {
-        mLastInputMethodWindow = ime;
-        mLastInputMethodTargetWindow = target;
-    }
-
-    @Override
-    public int getInputMethodWindowVisibleHeightLw() {
-        return mDockBottom - mCurBottom;
-    }
-
-    @Override
-    public void setCurrentUserLw(int newUserId) {
-        mCurrentUserId = newUserId;
-        if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.setCurrentUser(newUserId);
-        }
-        if (mStatusBarService != null) {
-            try {
-                mStatusBarService.setCurrentUser(newUserId);
-            } catch (RemoteException e) {
-                // oh well
-            }
-        }
-        setLastInputMethodWindowLw(null, null);
-    }
-
-    @Override
-    public boolean canMagnifyWindow(int windowType) {
-        switch (windowType) {
-            case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
-            case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG:
-            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
-            case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isTopLevelWindow(int windowType) {
-        if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
-                && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-            return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
-        }
-        return true;
-    }
-
-    @Override
-    public void dump(String prefix, PrintWriter pw, String[] args) {
-        pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
-                pw.print(" mSystemReady="); pw.print(mSystemReady);
-                pw.print(" mSystemBooted="); pw.println(mSystemBooted);
-        pw.print(prefix); pw.print("mLidState="); pw.print(mLidState);
-                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
-                pw.print(" mCameraLensCoverState="); pw.print(mCameraLensCoverState);
-                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
-        if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
-                || mForceClearedSystemUiFlags != 0) {
-            pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
-                    pw.print(Integer.toHexString(mLastSystemUiFlags));
-                    pw.print(" mResettingSystemUiFlags=0x");
-                    pw.print(Integer.toHexString(mResettingSystemUiFlags));
-                    pw.print(" mForceClearedSystemUiFlags=0x");
-                    pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
-        }
-        if (mLastFocusNeedsMenu) {
-            pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
-                    pw.println(mLastFocusNeedsMenu);
-        }
-        pw.print(prefix); pw.print("mWakeGestureEnabledSetting=");
-                pw.println(mWakeGestureEnabledSetting);
-
-        pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation);
-        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
-                pw.print(" mDockMode="); pw.print(mDockMode);
-                pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
-                pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
-        pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
-                pw.print(" mUserRotation="); pw.print(mUserRotation);
-                pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
-        pw.print(prefix); pw.print("mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
-        pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
-                pw.print(mCarDockEnablesAccelerometer);
-                pw.print(" mDeskDockEnablesAccelerometer=");
-                pw.println(mDeskDockEnablesAccelerometer);
-        pw.print(prefix); pw.print("mLidKeyboardAccessibility=");
-                pw.print(mLidKeyboardAccessibility);
-                pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
-                pw.print(" mLidControlsSleep="); pw.println(mLidControlsSleep);
-        pw.print(prefix);
-                pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
-                pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
-        pw.print(prefix);
-                pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior);
-                pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior);
-        pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput);
-        pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
-        pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
-                pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
-        pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
-                pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
-        pw.print(prefix); pw.print("mOrientationSensorEnabled=");
-                pw.println(mOrientationSensorEnabled);
-        pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
-                pw.print(","); pw.print(mOverscanScreenTop);
-                pw.print(") "); pw.print(mOverscanScreenWidth);
-                pw.print("x"); pw.println(mOverscanScreenHeight);
-        if (mOverscanLeft != 0 || mOverscanTop != 0
-                || mOverscanRight != 0 || mOverscanBottom != 0) {
-            pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
-                    pw.print(" top="); pw.print(mOverscanTop);
-                    pw.print(" right="); pw.print(mOverscanRight);
-                    pw.print(" bottom="); pw.println(mOverscanBottom);
-        }
-        pw.print(prefix); pw.print("mRestrictedOverscanScreen=(");
-                pw.print(mRestrictedOverscanScreenLeft);
-                pw.print(","); pw.print(mRestrictedOverscanScreenTop);
-                pw.print(") "); pw.print(mRestrictedOverscanScreenWidth);
-                pw.print("x"); pw.println(mRestrictedOverscanScreenHeight);
-        pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
-                pw.print(","); pw.print(mUnrestrictedScreenTop);
-                pw.print(") "); pw.print(mUnrestrictedScreenWidth);
-                pw.print("x"); pw.println(mUnrestrictedScreenHeight);
-        pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft);
-                pw.print(","); pw.print(mRestrictedScreenTop);
-                pw.print(") "); pw.print(mRestrictedScreenWidth);
-                pw.print("x"); pw.println(mRestrictedScreenHeight);
-        pw.print(prefix); pw.print("mStableFullscreen=("); pw.print(mStableFullscreenLeft);
-                pw.print(","); pw.print(mStableFullscreenTop);
-                pw.print(")-("); pw.print(mStableFullscreenRight);
-                pw.print(","); pw.print(mStableFullscreenBottom); pw.println(")");
-        pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
-                pw.print(","); pw.print(mStableTop);
-                pw.print(")-("); pw.print(mStableRight);
-                pw.print(","); pw.print(mStableBottom); pw.println(")");
-        pw.print(prefix); pw.print("mSystem=("); pw.print(mSystemLeft);
-                pw.print(","); pw.print(mSystemTop);
-                pw.print(")-("); pw.print(mSystemRight);
-                pw.print(","); pw.print(mSystemBottom); pw.println(")");
-        pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
-                pw.print(","); pw.print(mCurTop);
-                pw.print(")-("); pw.print(mCurRight);
-                pw.print(","); pw.print(mCurBottom); pw.println(")");
-        pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft);
-                pw.print(","); pw.print(mContentTop);
-                pw.print(")-("); pw.print(mContentRight);
-                pw.print(","); pw.print(mContentBottom); pw.println(")");
-        pw.print(prefix); pw.print("mVoiceContent=("); pw.print(mVoiceContentLeft);
-                pw.print(","); pw.print(mVoiceContentTop);
-                pw.print(")-("); pw.print(mVoiceContentRight);
-                pw.print(","); pw.print(mVoiceContentBottom); pw.println(")");
-        pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
-                pw.print(","); pw.print(mDockTop);
-                pw.print(")-("); pw.print(mDockRight);
-                pw.print(","); pw.print(mDockBottom); pw.println(")");
-        pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
-                pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
-        pw.print(prefix); pw.print("mShowingLockscreen="); pw.print(mShowingLockscreen);
-                pw.print(" mShowingDream="); pw.print(mShowingDream);
-                pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
-        if (mLastInputMethodWindow != null) {
-            pw.print(prefix); pw.print("mLastInputMethodWindow=");
-                    pw.println(mLastInputMethodWindow);
-        }
-        if (mLastInputMethodTargetWindow != null) {
-            pw.print(prefix); pw.print("mLastInputMethodTargetWindow=");
-                    pw.println(mLastInputMethodTargetWindow);
-        }
-        if (mStatusBar != null) {
-            pw.print(prefix); pw.print("mStatusBar=");
-                    pw.println(mStatusBar);
-            pw.print(prefix); pw.print("isStatusBarKeyguard=");
-                    pw.print(isStatusBarKeyguard());
-        }
-        if (mNavigationBar != null) {
-            pw.print(prefix); pw.print("mNavigationBar=");
-                    pw.println(mNavigationBar);
-        }
-        if (mFocusedWindow != null) {
-            pw.print(prefix); pw.print("mFocusedWindow=");
-                    pw.println(mFocusedWindow);
-        }
-        if (mFocusedApp != null) {
-            pw.print(prefix); pw.print("mFocusedApp=");
-                    pw.println(mFocusedApp);
-        }
-        if (mWinDismissingKeyguard != null) {
-            pw.print(prefix); pw.print("mWinDismissingKeyguard=");
-                    pw.println(mWinDismissingKeyguard);
-        }
-        if (mTopFullscreenOpaqueWindowState != null) {
-            pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
-                    pw.println(mTopFullscreenOpaqueWindowState);
-        }
-        if (mForcingShowNavBar) {
-            pw.print(prefix); pw.print("mForcingShowNavBar=");
-                    pw.println(mForcingShowNavBar); pw.print( "mForcingShowNavBarLayer=");
-                    pw.println(mForcingShowNavBarLayer);
-        }
-        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
-                pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
-        pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
-                pw.print(" mForceStatusBarFromKeyguard=");
-                pw.println(mForceStatusBarFromKeyguard);
-        pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
-                pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
-                pw.print(" mHomePressed="); pw.println(mHomePressed);
-        pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
-                pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
-                pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
-        pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior);
-                pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior);
-                pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior);
-        pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation);
-                pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
-        pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
-                pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
-        pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
-                pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
-        pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
-
-        mGlobalKeyManager.dump(prefix, pw);
-        mStatusBarController.dump(pw, prefix);
-        mNavigationBarController.dump(pw, prefix);
-        PolicyControl.dump(prefix, pw);
-
-        if (mWakeGestureListener != null) {
-            mWakeGestureListener.dump(pw, prefix);
-        }
-        if (mOrientationListener != null) {
-            mOrientationListener.dump(pw, prefix);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/Policy.java b/policy/src/com/android/internal/policy/impl/Policy.java
deleted file mode 100644
index 42bfc5f..0000000
--- a/policy/src/com/android/internal/policy/impl/Policy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.util.Log;
-import android.view.FallbackEventHandler;
-import android.view.LayoutInflater;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.policy.IPolicy;
-
-/**
- * {@hide}
- */
-
-// Simple implementation of the policy interface that spawns the right
-// set of objects
-public class Policy implements IPolicy {
-    private static final String TAG = "PhonePolicy";
-
-    private static final String[] preload_classes = {
-        "com.android.internal.policy.impl.PhoneLayoutInflater",
-        "com.android.internal.policy.impl.PhoneWindow",
-        "com.android.internal.policy.impl.PhoneWindow$1",
-        "com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
-        "com.android.internal.policy.impl.PhoneWindow$DecorView",
-        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
-        "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
-    };
-
-    static {
-        // For performance reasons, preload some policy specific classes when
-        // the policy gets loaded.
-        for (String s : preload_classes) {
-            try {
-                Class.forName(s);
-            } catch (ClassNotFoundException ex) {
-                Log.e(TAG, "Could not preload class for phone policy: " + s);
-            }
-        }
-    }
-
-    public Window makeNewWindow(Context context) {
-        return new PhoneWindow(context);
-    }
-
-    public LayoutInflater makeNewLayoutInflater(Context context) {
-        return new PhoneLayoutInflater(context);
-    }
-
-    public WindowManagerPolicy makeNewWindowManager() {
-        return new PhoneWindowManager();
-    }
-
-    public FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return new PhoneFallbackEventHandler(context);
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
deleted file mode 100644
index 9abd906..0000000
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerPolicy.WindowState;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-/**
- * Runtime adjustments applied to the global window policy.
- *
- * This includes forcing immersive mode behavior for one or both system bars (based on a package
- * list) and permanently disabling immersive mode confirmations for specific packages.
- *
- * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
- * e.g.
- *   to force immersive mode everywhere:
- *     "immersive.full=*"
- *   to force transient status for all apps except a specific package:
- *     "immersive.status=apps,-com.package"
- *   to disable the immersive mode confirmations for specific packages:
- *     "immersive.preconfirms=com.package.one,com.package.two"
- *
- * Separate multiple name-value pairs with ':'
- *   e.g. "immersive.status=apps:immersive.preconfirms=*"
- */
-public class PolicyControl {
-    private static String TAG = "PolicyControl";
-    private static boolean DEBUG = false;
-
-    private static final String NAME_IMMERSIVE_FULL = "immersive.full";
-    private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
-    private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
-    private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
-
-    private static String sSettingValue;
-    private static Filter sImmersivePreconfirmationsFilter;
-    private static Filter sImmersiveStatusFilter;
-    private static Filter sImmersiveNavigationFilter;
-
-    public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
-        attrs = attrs != null ? attrs : win.getAttrs();
-        int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.STATUS_BAR_TRANSLUCENT);
-        }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
-            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.NAVIGATION_BAR_TRANSLUCENT);
-        }
-        return vis;
-    }
-
-    public static int getWindowFlags(WindowState win, LayoutParams attrs) {
-        attrs = attrs != null ? attrs : win.getAttrs();
-        int flags = attrs.flags;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
-            flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
-                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
-        }
-        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
-            flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-        }
-        return flags;
-    }
-
-    public static int adjustClearableFlags(WindowState win, int clearableFlags) {
-        final LayoutParams attrs = win != null ? win.getAttrs() : null;
-        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
-            clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
-        }
-        return clearableFlags;
-    }
-
-    public static boolean disableImmersiveConfirmation(String pkg) {
-        return (sImmersivePreconfirmationsFilter != null
-                && sImmersivePreconfirmationsFilter.matches(pkg))
-                || ActivityManager.isRunningInTestHarness();
-    }
-
-    public static void reloadFromSetting(Context context) {
-        if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
-        String value = null;
-        try {
-            value = Settings.Global.getStringForUser(context.getContentResolver(),
-                    Settings.Global.POLICY_CONTROL,
-                    UserHandle.USER_CURRENT);
-            if (sSettingValue != null && sSettingValue.equals(value)) return;
-            setFilters(value);
-            sSettingValue = value;
-        } catch (Throwable t) {
-            Slog.w(TAG, "Error loading policy control, value=" + value, t);
-        }
-    }
-
-    public static void dump(String prefix, PrintWriter pw) {
-        dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
-        dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
-        dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
-    }
-
-    private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
-        if (filter == null) {
-            pw.println("null");
-        } else {
-            filter.dump(pw); pw.println();
-        }
-    }
-
-    private static void setFilters(String value) {
-        if (DEBUG) Slog.d(TAG, "setFilters: " + value);
-        sImmersiveStatusFilter = null;
-        sImmersiveNavigationFilter = null;
-        sImmersivePreconfirmationsFilter = null;
-        if (value != null) {
-            String[] nvps = value.split(":");
-            for (String nvp : nvps) {
-                int i = nvp.indexOf('=');
-                if (i == -1) continue;
-                String n = nvp.substring(0, i);
-                String v = nvp.substring(i + 1);
-                if (n.equals(NAME_IMMERSIVE_FULL)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
-                    if (sImmersivePreconfirmationsFilter == null) {
-                        sImmersivePreconfirmationsFilter = f;
-                    }
-                } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveStatusFilter = f;
-                } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
-                    Filter f = Filter.parse(v);
-                    sImmersiveNavigationFilter = f;
-                    if (sImmersivePreconfirmationsFilter == null) {
-                        sImmersivePreconfirmationsFilter = f;
-                    }
-                } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
-                    Filter f = Filter.parse(v);
-                    sImmersivePreconfirmationsFilter = f;
-                }
-            }
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
-            Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
-            Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
-        }
-    }
-
-    private static class Filter {
-        private static final String ALL = "*";
-        private static final String APPS = "apps";
-
-        private final ArraySet<String> mWhitelist;
-        private final ArraySet<String> mBlacklist;
-
-        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
-            mWhitelist = whitelist;
-            mBlacklist = blacklist;
-        }
-
-        boolean matches(LayoutParams attrs) {
-            if (attrs == null) return false;
-            boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
-                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-            if (isApp && mBlacklist.contains(APPS)) return false;
-            if (onBlacklist(attrs.packageName)) return false;
-            if (isApp && mWhitelist.contains(APPS)) return true;
-            return onWhitelist(attrs.packageName);
-        }
-
-        boolean matches(String packageName) {
-            return !onBlacklist(packageName) && onWhitelist(packageName);
-        }
-
-        private boolean onBlacklist(String packageName) {
-            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
-        }
-
-        private boolean onWhitelist(String packageName) {
-            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
-        }
-
-        void dump(PrintWriter pw) {
-            pw.print("Filter[");
-            dump("whitelist", mWhitelist, pw); pw.print(',');
-            dump("blacklist", mBlacklist, pw); pw.print(']');
-        }
-
-        private void dump(String name, ArraySet<String> set, PrintWriter pw) {
-            pw.print(name); pw.print("=(");
-            final int n = set.size();
-            for (int i = 0; i < n; i++) {
-                if (i > 0) pw.print(',');
-                pw.print(set.valueAt(i));
-            }
-            pw.print(')');
-        }
-
-        @Override
-        public String toString() {
-            StringWriter sw = new StringWriter();
-            dump(new PrintWriter(sw, true));
-            return sw.toString();
-        }
-
-        // value = comma-delimited list of tokens, where token = (package name|apps|*)
-        // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
-        static Filter parse(String value) {
-            if (value == null) return null;
-            ArraySet<String> whitelist = new ArraySet<String>();
-            ArraySet<String> blacklist = new ArraySet<String>();
-            for (String token : value.split(",")) {
-                token = token.trim();
-                if (token.startsWith("-") && token.length() > 1) {
-                    token = token.substring(1);
-                    blacklist.add(token);
-                } else {
-                    whitelist.add(token);
-                }
-            }
-            return new Filter(whitelist, blacklist);
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
deleted file mode 100644
index 3490bd4..0000000
--- a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.LinearLayout;
-
-/**
- * A vertical linear layout.  However, instead of drawing the background
- * behnd the items, it draws the background outside the items based on the
- * padding.  If there isn't enough room to draw both, it clips the background
- * instead of the contents.
- */
-public class RecentApplicationsBackground extends LinearLayout {
-    private static final String TAG = "RecentApplicationsBackground";
-
-    private boolean mBackgroundSizeChanged;
-    private Drawable mBackground;
-    private Rect mTmp0 = new Rect();
-    private Rect mTmp1 = new Rect();
-
-    public RecentApplicationsBackground(Context context) {
-        this(context, null);
-        init();
-    }
-
-    public RecentApplicationsBackground(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
-    }
-
-    private void init() {
-        mBackground = getBackground();
-        setBackgroundDrawable(null);
-        setPadding(0, 0, 0, 0);
-        setGravity(Gravity.CENTER);
-    }
-
-    @Override
-    protected boolean setFrame(int left, int top, int right, int bottom) {
-        setWillNotDraw(false);
-        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
-            mBackgroundSizeChanged = true;
-        }
-        return super.setFrame(left, top, right, bottom);
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return who == mBackground || super.verifyDrawable(who);
-    }
-
-    @Override
-    public void jumpDrawablesToCurrentState() {
-        super.jumpDrawablesToCurrentState();
-        if (mBackground != null) mBackground.jumpToCurrentState();
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        Drawable d = mBackground;
-        if (d != null && d.isStateful()) {
-            d.setState(getDrawableState());
-        }
-        super.drawableStateChanged();
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        final Drawable background = mBackground;
-        if (background != null) {
-            if (mBackgroundSizeChanged) {
-                mBackgroundSizeChanged = false;
-                Rect chld = mTmp0;
-                Rect bkg = mTmp1;
-                mBackground.getPadding(bkg);
-                getChildBounds(chld);
-                // This doesn't clamp to this view's bounds, which is what we want,
-                // so that the drawing is clipped.
-                final int top = chld.top - bkg.top;
-                final int bottom = chld.bottom + bkg.bottom;
-                // The background here is a gradient that wants to
-                // extend the full width of the screen (whatever that
-                // may be).
-                int left, right;
-                if (false) {
-                    // This limits the width of the drawable.
-                    left = chld.left - bkg.left;
-                    right = chld.right + bkg.right;
-                } else {
-                    // This expands it to full width.
-                    left = 0;
-                    right = getRight();
-                }
-                background.setBounds(left, top, right, bottom);
-            }
-        }
-        mBackground.draw(canvas);
-
-        if (false) {
-            android.graphics.Paint p = new android.graphics.Paint();
-            p.setColor(0x88ffff00);
-            canvas.drawRect(background.getBounds(), p);
-        }
-        canvas.drawARGB((int)(0.75*0xff), 0, 0, 0);
-
-        super.draw(canvas);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mBackground.setCallback(this);
-        setWillNotDraw(false);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mBackground.setCallback(null);
-    }
-    
-    private void getChildBounds(Rect r) {
-        r.left = r.top = Integer.MAX_VALUE;
-        r.bottom = r.right = Integer.MIN_VALUE;
-        final int N = getChildCount();
-        for (int i=0; i<N; i++) {
-            View v = getChildAt(i);
-            if (v.getVisibility() == View.VISIBLE) {
-                r.left = Math.min(r.left, v.getLeft());
-                r.top = Math.min(r.top, v.getTop());
-                r.right = Math.max(r.right, v.getRight());
-                r.bottom = Math.max(r.bottom, v.getBottom());
-            }
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
deleted file mode 100644
index bb898f7..0000000
--- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-
-import java.net.URISyntaxException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager extends ContentObserver {
-    
-    private static final String TAG = "ShortcutManager";
-    
-    private static final int COLUMN_SHORTCUT = 0;
-    private static final int COLUMN_INTENT = 1;
-    private static final String[] sProjection = new String[] {
-        Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
-    };
-
-    private Context mContext;
-    private Cursor mCursor;
-    /** Map of a shortcut to its intent. */
-    private SparseArray<Intent> mShortcutIntents;
-    
-    public ShortcutManager(Context context, Handler handler) {
-        super(handler);
-        
-        mContext = context;
-        mShortcutIntents = new SparseArray<Intent>();
-    }
-
-    /** Observes the provider of shortcut+intents */
-    public void observe() {
-        mCursor = mContext.getContentResolver().query(
-                Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
-        mCursor.registerContentObserver(this);
-        updateShortcuts();
-    }
-
-    @Override
-    public void onChange(boolean selfChange) {
-        updateShortcuts();
-    }
-    
-    private void updateShortcuts() {
-        Cursor c = mCursor;
-        if (!c.requery()) {
-            Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
-            return;
-        }
-
-        mShortcutIntents.clear();
-        while (c.moveToNext()) {
-            int shortcut = c.getInt(COLUMN_SHORTCUT);
-            if (shortcut == 0) continue;
-            String intentURI = c.getString(COLUMN_INTENT);
-            Intent intent = null;
-            try {
-                intent = Intent.getIntent(intentURI);
-            } catch (URISyntaxException e) {
-                Log.w(TAG, "Intent URI for shortcut invalid.", e);
-            }
-            if (intent == null) continue;
-            mShortcutIntents.put(shortcut, intent);
-        }
-    }
-    
-    /**
-     * Gets the shortcut intent for a given keycode+modifier. Make sure you
-     * strip whatever modifier is used for invoking shortcuts (for example,
-     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
-     * 'Sym' bit from the modifiers before calling this method.
-     * <p>
-     * This will first try an exact match (with modifiers), and then try a
-     * match without modifiers (primary character on a key).
-     * 
-     * @param kcm The key character map of the device on which the key was pressed.
-     * @param keyCode The key code.
-     * @param metaState The meta state, omitting any modifiers that were used
-     * to invoke the shortcut.
-     * @return The intent that matches the shortcut, or null if not found.
-     */
-    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
-        Intent intent = null;
-
-        // First try the exact keycode (with modifiers).
-        int shortcut = kcm.get(keyCode, metaState);
-        if (shortcut != 0) {
-            intent = mShortcutIntents.get(shortcut);
-        }
-
-        // Next try the primary character on that key.
-        if (intent == null) {
-            shortcut = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
-            if (shortcut != 0) {
-                intent = mShortcutIntents.get(shortcut);
-            }
-        }
-
-        return intent;
-    }
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
deleted file mode 100644
index 4ff9315..0000000
--- a/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
+++ /dev/null
@@ -1,197 +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.internal.policy.impl;
-
-import android.content.Context;
-import android.util.Slog;
-import android.view.MotionEvent;
-import android.view.WindowManagerPolicy.PointerEventListener;
-
-/*
- * Listens for system-wide input gestures, firing callbacks when detected.
- * @hide
- */
-public class SystemGesturesPointerEventListener implements PointerEventListener {
-    private static final String TAG = "SystemGestures";
-    private static final boolean DEBUG = false;
-    private static final long SWIPE_TIMEOUT_MS = 500;
-    private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
-    private static final int UNTRACKED_POINTER = -1;
-
-    private static final int SWIPE_NONE = 0;
-    private static final int SWIPE_FROM_TOP = 1;
-    private static final int SWIPE_FROM_BOTTOM = 2;
-    private static final int SWIPE_FROM_RIGHT = 3;
-
-    private final int mSwipeStartThreshold;
-    private final int mSwipeDistanceThreshold;
-    private final Callbacks mCallbacks;
-    private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS];
-    private final float[] mDownX = new float[MAX_TRACKED_POINTERS];
-    private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
-    private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
-
-    int screenHeight;
-    int screenWidth;
-    private int mDownPointers;
-    private boolean mSwipeFireable;
-    private boolean mDebugFireable;
-
-    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
-        mCallbacks = checkNull("callbacks", callbacks);
-        mSwipeStartThreshold = checkNull("context", context).getResources()
-                .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mSwipeDistanceThreshold = mSwipeStartThreshold;
-        if (DEBUG) Slog.d(TAG,  "mSwipeStartThreshold=" + mSwipeStartThreshold
-                + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold);
-    }
-
-    private static <T> T checkNull(String name, T arg) {
-        if (arg == null) {
-            throw new IllegalArgumentException(name + " must not be null");
-        }
-        return arg;
-    }
-
-    @Override
-    public void onPointerEvent(MotionEvent event) {
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                mSwipeFireable = true;
-                mDebugFireable = true;
-                mDownPointers = 0;
-                captureDown(event, 0);
-                break;
-            case MotionEvent.ACTION_POINTER_DOWN:
-                captureDown(event, event.getActionIndex());
-                if (mDebugFireable) {
-                    mDebugFireable = event.getPointerCount() < 5;
-                    if (!mDebugFireable) {
-                        if (DEBUG) Slog.d(TAG, "Firing debug");
-                        mCallbacks.onDebug();
-                    }
-                }
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mSwipeFireable) {
-                    final int swipe = detectSwipe(event);
-                    mSwipeFireable = swipe == SWIPE_NONE;
-                    if (swipe == SWIPE_FROM_TOP) {
-                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
-                        mCallbacks.onSwipeFromTop();
-                    } else if (swipe == SWIPE_FROM_BOTTOM) {
-                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
-                        mCallbacks.onSwipeFromBottom();
-                    } else if (swipe == SWIPE_FROM_RIGHT) {
-                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
-                        mCallbacks.onSwipeFromRight();
-                    }
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mSwipeFireable = false;
-                mDebugFireable = false;
-                break;
-            default:
-                if (DEBUG) Slog.d(TAG, "Ignoring " + event);
-        }
-    }
-
-    private void captureDown(MotionEvent event, int pointerIndex) {
-        final int pointerId = event.getPointerId(pointerIndex);
-        final int i = findIndex(pointerId);
-        if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
-                " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
-        if (i != UNTRACKED_POINTER) {
-            mDownX[i] = event.getX(pointerIndex);
-            mDownY[i] = event.getY(pointerIndex);
-            mDownTime[i] = event.getEventTime();
-            if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
-                    " down x=" + mDownX[i] + " y=" + mDownY[i]);
-        }
-    }
-
-    private int findIndex(int pointerId) {
-        for (int i = 0; i < mDownPointers; i++) {
-            if (mDownPointerId[i] == pointerId) {
-                return i;
-            }
-        }
-        if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) {
-            return UNTRACKED_POINTER;
-        }
-        mDownPointerId[mDownPointers++] = pointerId;
-        return mDownPointers - 1;
-    }
-
-    private int detectSwipe(MotionEvent move) {
-        final int historySize = move.getHistorySize();
-        final int pointerCount = move.getPointerCount();
-        for (int p = 0; p < pointerCount; p++) {
-            final int pointerId = move.getPointerId(p);
-            final int i = findIndex(pointerId);
-            if (i != UNTRACKED_POINTER) {
-                for (int h = 0; h < historySize; h++) {
-                    final long time = move.getHistoricalEventTime(h);
-                    final float x = move.getHistoricalX(p, h);
-                    final float y = move.getHistoricalY(p,  h);
-                    final int swipe = detectSwipe(i, time, x, y);
-                    if (swipe != SWIPE_NONE) {
-                        return swipe;
-                    }
-                }
-                final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
-                if (swipe != SWIPE_NONE) {
-                    return swipe;
-                }
-            }
-        }
-        return SWIPE_NONE;
-    }
-
-    private int detectSwipe(int i, long time, float x, float y) {
-        final float fromX = mDownX[i];
-        final float fromY = mDownY[i];
-        final long elapsed = time - mDownTime[i];
-        if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
-                + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
-        if (fromY <= mSwipeStartThreshold
-                && y > fromY + mSwipeDistanceThreshold
-                && elapsed < SWIPE_TIMEOUT_MS) {
-            return SWIPE_FROM_TOP;
-        }
-        if (fromY >= screenHeight - mSwipeStartThreshold
-                && y < fromY - mSwipeDistanceThreshold
-                && elapsed < SWIPE_TIMEOUT_MS) {
-            return SWIPE_FROM_BOTTOM;
-        }
-        if (fromX >= screenWidth - mSwipeStartThreshold
-                && x < fromX - mSwipeDistanceThreshold
-                && elapsed < SWIPE_TIMEOUT_MS) {
-            return SWIPE_FROM_RIGHT;
-        }
-        return SWIPE_NONE;
-    }
-
-    interface Callbacks {
-        void onSwipeFromTop();
-        void onSwipeFromBottom();
-        void onSwipeFromRight();
-        void onDebug();
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java b/policy/src/com/android/internal/policy/impl/WakeGestureListener.java
deleted file mode 100644
index 9396c2c..0000000
--- a/policy/src/com/android/internal/policy/impl/WakeGestureListener.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.os.Handler;
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.TriggerEvent;
-import android.hardware.TriggerEventListener;
-
-import java.io.PrintWriter;
-
-/**
- * Watches for wake gesture sensor events then invokes the listener.
- */
-public abstract class WakeGestureListener {
-    private static final String TAG = "WakeGestureListener";
-
-    private final SensorManager mSensorManager;
-    private final Handler mHandler;
-
-    private final Object mLock = new Object();
-
-    private boolean mTriggerRequested;
-    private Sensor mSensor;
-
-    public WakeGestureListener(Context context, Handler handler) {
-        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
-        mHandler = handler;
-
-        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE);
-    }
-
-    public abstract void onWakeUp();
-
-    public boolean isSupported() {
-        synchronized (mLock) {
-            return mSensor != null;
-        }
-    }
-
-    public void requestWakeUpTrigger() {
-        synchronized (mLock) {
-            if (mSensor != null && !mTriggerRequested) {
-                mTriggerRequested = true;
-                mSensorManager.requestTriggerSensor(mListener, mSensor);
-            }
-        }
-    }
-
-    public void cancelWakeUpTrigger() {
-        synchronized (mLock) {
-            if (mSensor != null && mTriggerRequested) {
-                mTriggerRequested = false;
-                mSensorManager.cancelTriggerSensor(mListener, mSensor);
-            }
-        }
-    }
-
-    public void dump(PrintWriter pw, String prefix) {
-        synchronized (mLock) {
-            pw.println(prefix + TAG);
-            prefix += "  ";
-            pw.println(prefix + "mTriggerRequested=" + mTriggerRequested);
-            pw.println(prefix + "mSensor=" + mSensor);
-        }
-    }
-
-    private final TriggerEventListener mListener = new TriggerEventListener() {
-        @Override
-        public void onTrigger(TriggerEvent event) {
-            synchronized (mLock) {
-                mTriggerRequested = false;
-                mHandler.post(mWakeUpRunnable);
-            }
-        }
-    };
-
-    private final Runnable mWakeUpRunnable = new Runnable() {
-        @Override
-        public void run() {
-            onWakeUp();
-        }
-    };
-}
diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
deleted file mode 100644
index 704da33..0000000
--- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Handler;
-import android.os.SystemProperties;
-import android.util.FloatMath;
-import android.util.Log;
-import android.util.Slog;
-import android.util.TimeUtils;
-
-import java.io.PrintWriter;
-
-/**
- * A special helper class used by the WindowManager
- * for receiving notifications from the SensorManager when
- * the orientation of the device has changed.
- *
- * NOTE: If changing anything here, please run the API demo
- * "App/Activity/Screen Orientation" to ensure that all orientation
- * modes still work correctly.
- *
- * You can also visualize the behavior of the WindowOrientationListener.
- * Refer to frameworks/base/tools/orientationplot/README.txt for details.
- *
- * @hide
- */
-public abstract class WindowOrientationListener {
-    private static final String TAG = "WindowOrientationListener";
-    private static final boolean LOG = SystemProperties.getBoolean(
-            "debug.orientation.log", false);
-
-    private static final boolean USE_GRAVITY_SENSOR = false;
-
-    private Handler mHandler;
-    private SensorManager mSensorManager;
-    private boolean mEnabled;
-    private int mRate;
-    private Sensor mSensor;
-    private SensorEventListenerImpl mSensorEventListener;
-    private int mCurrentRotation = -1;
-
-    private final Object mLock = new Object();
-
-    /**
-     * Creates a new WindowOrientationListener.
-     * 
-     * @param context for the WindowOrientationListener.
-     * @param handler Provides the Looper for receiving sensor updates.
-     */
-    public WindowOrientationListener(Context context, Handler handler) {
-        this(context, handler, SensorManager.SENSOR_DELAY_UI);
-    }
-    
-    /**
-     * Creates a new WindowOrientationListener.
-     * 
-     * @param context for the WindowOrientationListener.
-     * @param handler Provides the Looper for receiving sensor updates.
-     * @param rate at which sensor events are processed (see also
-     * {@link android.hardware.SensorManager SensorManager}). Use the default
-     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
-     * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
-     *
-     * This constructor is private since no one uses it.
-     */
-    private WindowOrientationListener(Context context, Handler handler, int rate) {
-        mHandler = handler;
-        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
-        mRate = rate;
-        mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
-                ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
-        if (mSensor != null) {
-            // Create listener only if sensors do exist
-            mSensorEventListener = new SensorEventListenerImpl();
-        }
-    }
-
-    /**
-     * Enables the WindowOrientationListener so it will monitor the sensor and call
-     * {@link #onProposedRotationChanged(int)} when the device orientation changes.
-     */
-    public void enable() {
-        synchronized (mLock) {
-            if (mSensor == null) {
-                Log.w(TAG, "Cannot detect sensors. Not enabled");
-                return;
-            }
-            if (mEnabled == false) {
-                if (LOG) {
-                    Log.d(TAG, "WindowOrientationListener enabled");
-                }
-                mSensorEventListener.resetLocked();
-                mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
-                mEnabled = true;
-            }
-        }
-    }
-
-    /**
-     * Disables the WindowOrientationListener.
-     */
-    public void disable() {
-        synchronized (mLock) {
-            if (mSensor == null) {
-                Log.w(TAG, "Cannot detect sensors. Invalid disable");
-                return;
-            }
-            if (mEnabled == true) {
-                if (LOG) {
-                    Log.d(TAG, "WindowOrientationListener disabled");
-                }
-                mSensorManager.unregisterListener(mSensorEventListener);
-                mEnabled = false;
-            }
-        }
-    }
-
-    /**
-     * Sets the current rotation.
-     *
-     * @param rotation The current rotation.
-     */
-    public void setCurrentRotation(int rotation) {
-        synchronized (mLock) {
-            mCurrentRotation = rotation;
-        }
-    }
-
-    /**
-     * Gets the proposed rotation.
-     *
-     * This method only returns a rotation if the orientation listener is certain
-     * of its proposal.  If the rotation is indeterminate, returns -1.
-     *
-     * @return The proposed rotation, or -1 if unknown.
-     */
-    public int getProposedRotation() {
-        synchronized (mLock) {
-            if (mEnabled) {
-                return mSensorEventListener.getProposedRotationLocked();
-            }
-            return -1;
-        }
-    }
-
-    /**
-     * Returns true if sensor is enabled and false otherwise
-     */
-    public boolean canDetectOrientation() {
-        synchronized (mLock) {
-            return mSensor != null;
-        }
-    }
-
-    /**
-     * Called when the rotation view of the device has changed.
-     *
-     * This method is called whenever the orientation becomes certain of an orientation.
-     * It is called each time the orientation determination transitions from being
-     * uncertain to being certain again, even if it is the same orientation as before.
-     *
-     * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
-     * @see android.view.Surface
-     */
-    public abstract void onProposedRotationChanged(int rotation);
-
-    public void dump(PrintWriter pw, String prefix) {
-        synchronized (mLock) {
-            pw.println(prefix + TAG);
-            prefix += "  ";
-            pw.println(prefix + "mEnabled=" + mEnabled);
-            pw.println(prefix + "mCurrentRotation=" + mCurrentRotation);
-            pw.println(prefix + "mSensor=" + mSensor);
-            pw.println(prefix + "mRate=" + mRate);
-
-            if (mSensorEventListener != null) {
-                mSensorEventListener.dumpLocked(pw, prefix);
-            }
-        }
-    }
-
-    /**
-     * This class filters the raw accelerometer data and tries to detect actual changes in
-     * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
-     * but here's the outline:
-     *
-     *  - Low-pass filter the accelerometer vector in cartesian coordinates.  We do it in
-     *    cartesian space because the orientation calculations are sensitive to the
-     *    absolute magnitude of the acceleration.  In particular, there are singularities
-     *    in the calculation as the magnitude approaches 0.  By performing the low-pass
-     *    filtering early, we can eliminate most spurious high-frequency impulses due to noise.
-     *
-     *  - Convert the acceleromter vector from cartesian to spherical coordinates.
-     *    Since we're dealing with rotation of the device, this is the sensible coordinate
-     *    system to work in.  The zenith direction is the Z-axis, the direction the screen
-     *    is facing.  The radial distance is referred to as the magnitude below.
-     *    The elevation angle is referred to as the "tilt" below.
-     *    The azimuth angle is referred to as the "orientation" below (and the azimuth axis is
-     *    the Y-axis).
-     *    See http://en.wikipedia.org/wiki/Spherical_coordinate_system for reference.
-     *
-     *  - If the tilt angle is too close to horizontal (near 90 or -90 degrees), do nothing.
-     *    The orientation angle is not meaningful when the device is nearly horizontal.
-     *    The tilt angle thresholds are set differently for each orientation and different
-     *    limits are applied when the device is facing down as opposed to when it is facing
-     *    forward or facing up.
-     *
-     *  - When the orientation angle reaches a certain threshold, consider transitioning
-     *    to the corresponding orientation.  These thresholds have some hysteresis built-in
-     *    to avoid oscillations between adjacent orientations.
-     *
-     *  - Wait for the device to settle for a little bit.  Once that happens, issue the
-     *    new orientation proposal.
-     *
-     * Details are explained inline.
-     *
-     * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
-     * signal processing background.
-     */
-    final class SensorEventListenerImpl implements SensorEventListener {
-        // We work with all angles in degrees in this class.
-        private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
-
-        // Number of nanoseconds per millisecond.
-        private static final long NANOS_PER_MS = 1000000;
-
-        // Indices into SensorEvent.values for the accelerometer sensor.
-        private static final int ACCELEROMETER_DATA_X = 0;
-        private static final int ACCELEROMETER_DATA_Y = 1;
-        private static final int ACCELEROMETER_DATA_Z = 2;
-
-        // The minimum amount of time that a predicted rotation must be stable before it
-        // is accepted as a valid rotation proposal.  This value can be quite small because
-        // the low-pass filter already suppresses most of the noise so we're really just
-        // looking for quick confirmation that the last few samples are in agreement as to
-        // the desired orientation.
-        private static final long PROPOSAL_SETTLE_TIME_NANOS = 40 * NANOS_PER_MS;
-
-        // The minimum amount of time that must have elapsed since the device last exited
-        // the flat state (time since it was picked up) before the proposed rotation
-        // can change.
-        private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS;
-
-        // The minimum amount of time that must have elapsed since the device stopped
-        // swinging (time since device appeared to be in the process of being put down
-        // or put away into a pocket) before the proposed rotation can change.
-        private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS;
-
-        // The minimum amount of time that must have elapsed since the device stopped
-        // undergoing external acceleration before the proposed rotation can change.
-        private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
-                500 * NANOS_PER_MS;
-
-        // If the tilt angle remains greater than the specified angle for a minimum of
-        // the specified time, then the device is deemed to be lying flat
-        // (just chillin' on a table).
-        private static final float FLAT_ANGLE = 75;
-        private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS;
-
-        // If the tilt angle has increased by at least delta degrees within the specified amount
-        // of time, then the device is deemed to be swinging away from the user
-        // down towards flat (tilt = 90).
-        private static final float SWING_AWAY_ANGLE_DELTA = 20;
-        private static final long SWING_TIME_NANOS = 300 * NANOS_PER_MS;
-
-        // The maximum sample inter-arrival time in milliseconds.
-        // If the acceleration samples are further apart than this amount in time, we reset the
-        // state of the low-pass filter and orientation properties.  This helps to handle
-        // boundary conditions when the device is turned on, wakes from suspend or there is
-        // a significant gap in samples.
-        private static final long MAX_FILTER_DELTA_TIME_NANOS = 1000 * NANOS_PER_MS;
-
-        // The acceleration filter time constant.
-        //
-        // This time constant is used to tune the acceleration filter such that
-        // impulses and vibrational noise (think car dock) is suppressed before we
-        // try to calculate the tilt and orientation angles.
-        //
-        // The filter time constant is related to the filter cutoff frequency, which is the
-        // frequency at which signals are attenuated by 3dB (half the passband power).
-        // Each successive octave beyond this frequency is attenuated by an additional 6dB.
-        //
-        // Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz
-        // is given by Fc = 1 / (2pi * t).
-        //
-        // The higher the time constant, the lower the cutoff frequency, so more noise
-        // will be suppressed.
-        //
-        // Filtering adds latency proportional the time constant (inversely proportional
-        // to the cutoff frequency) so we don't want to make the time constant too
-        // large or we can lose responsiveness.  Likewise we don't want to make it too
-        // small or we do a poor job suppressing acceleration spikes.
-        // Empirically, 100ms seems to be too small and 500ms is too large.
-        private static final float FILTER_TIME_CONSTANT_MS = 200.0f;
-
-        /* State for orientation detection. */
-
-        // Thresholds for minimum and maximum allowable deviation from gravity.
-        //
-        // If the device is undergoing external acceleration (being bumped, in a car
-        // that is turning around a corner or a plane taking off) then the magnitude
-        // may be substantially more or less than gravity.  This can skew our orientation
-        // detection by making us think that up is pointed in a different direction.
-        //
-        // Conversely, if the device is in freefall, then there will be no gravity to
-        // measure at all.  This is problematic because we cannot detect the orientation
-        // without gravity to tell us which way is up.  A magnitude near 0 produces
-        // singularities in the tilt and orientation calculations.
-        //
-        // In both cases, we postpone choosing an orientation.
-        //
-        // However, we need to tolerate some acceleration because the angular momentum
-        // of turning the device can skew the observed acceleration for a short period of time.
-        private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2
-        private static final float ACCELERATION_TOLERANCE = 4; // m/s^2
-        private static final float MIN_ACCELERATION_MAGNITUDE =
-                SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE;
-        private static final float MAX_ACCELERATION_MAGNITUDE =
-            SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
-
-        // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
-        // when screen is facing the sky or ground), we completely ignore orientation data.
-        private static final int MAX_TILT = 75;
-
-        // The tilt angle range in degrees for each orientation.
-        // Beyond these tilt angles, we don't even consider transitioning into the
-        // specified orientation.  We place more stringent requirements on unnatural
-        // orientations than natural ones to make it less likely to accidentally transition
-        // into those states.
-        // The first value of each pair is negative so it applies a limit when the device is
-        // facing down (overhead reading in bed).
-        // The second value of each pair is positive so it applies a limit when the device is
-        // facing up (resting on a table).
-        // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
-        // how close to vertical the device must be in order to change orientation.
-        private final int[][] TILT_TOLERANCE = new int[][] {
-            /* ROTATION_0   */ { -25, 70 },
-            /* ROTATION_90  */ { -25, 65 },
-            /* ROTATION_180 */ { -25, 60 },
-            /* ROTATION_270 */ { -25, 65 }
-        };
-
-        // The tilt angle below which we conclude that the user is holding the device
-        // overhead reading in bed and lock into that state.
-        private final int TILT_OVERHEAD_ENTER = -40;
-
-        // The tilt angle above which we conclude that the user would like a rotation
-        // change to occur and unlock from the overhead state.
-        private final int TILT_OVERHEAD_EXIT = -15;
-
-        // The gap angle in degrees between adjacent orientation angles for hysteresis.
-        // This creates a "dead zone" between the current orientation and a proposed
-        // adjacent orientation.  No orientation proposal is made when the orientation
-        // angle is within the gap between the current orientation and the adjacent
-        // orientation.
-        private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
-
-        // Timestamp and value of the last accelerometer sample.
-        private long mLastFilteredTimestampNanos;
-        private float mLastFilteredX, mLastFilteredY, mLastFilteredZ;
-
-        // The last proposed rotation, -1 if unknown.
-        private int mProposedRotation;
-
-        // Value of the current predicted rotation, -1 if unknown.
-        private int mPredictedRotation;
-
-        // Timestamp of when the predicted rotation most recently changed.
-        private long mPredictedRotationTimestampNanos;
-
-        // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed).
-        private long mFlatTimestampNanos;
-        private boolean mFlat;
-
-        // Timestamp when the device last appeared to be swinging.
-        private long mSwingTimestampNanos;
-        private boolean mSwinging;
-
-        // Timestamp when the device last appeared to be undergoing external acceleration.
-        private long mAccelerationTimestampNanos;
-        private boolean mAccelerating;
-
-        // Whether we are locked into an overhead usage mode.
-        private boolean mOverhead;
-
-        // History of observed tilt angles.
-        private static final int TILT_HISTORY_SIZE = 40;
-        private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
-        private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
-        private int mTiltHistoryIndex;
-
-        public int getProposedRotationLocked() {
-            return mProposedRotation;
-        }
-
-        public void dumpLocked(PrintWriter pw, String prefix) {
-            pw.println(prefix + "mProposedRotation=" + mProposedRotation);
-            pw.println(prefix + "mPredictedRotation=" + mPredictedRotation);
-            pw.println(prefix + "mLastFilteredX=" + mLastFilteredX);
-            pw.println(prefix + "mLastFilteredY=" + mLastFilteredY);
-            pw.println(prefix + "mLastFilteredZ=" + mLastFilteredZ);
-            pw.println(prefix + "mTiltHistory={last: " + getLastTiltLocked() + "}");
-            pw.println(prefix + "mFlat=" + mFlat);
-            pw.println(prefix + "mSwinging=" + mSwinging);
-            pw.println(prefix + "mAccelerating=" + mAccelerating);
-            pw.println(prefix + "mOverhead=" + mOverhead);
-        }
-
-        @Override
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        }
-
-        @Override
-        public void onSensorChanged(SensorEvent event) {
-            int proposedRotation;
-            int oldProposedRotation;
-
-            synchronized (mLock) {
-                // The vector given in the SensorEvent points straight up (towards the sky) under
-                // ideal conditions (the phone is not accelerating).  I'll call this up vector
-                // elsewhere.
-                float x = event.values[ACCELEROMETER_DATA_X];
-                float y = event.values[ACCELEROMETER_DATA_Y];
-                float z = event.values[ACCELEROMETER_DATA_Z];
-
-                if (LOG) {
-                    Slog.v(TAG, "Raw acceleration vector: "
-                            + "x=" + x + ", y=" + y + ", z=" + z
-                            + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
-                }
-
-                // Apply a low-pass filter to the acceleration up vector in cartesian space.
-                // Reset the orientation listener state if the samples are too far apart in time
-                // or when we see values of (0, 0, 0) which indicates that we polled the
-                // accelerometer too soon after turning it on and we don't have any data yet.
-                final long now = event.timestamp;
-                final long then = mLastFilteredTimestampNanos;
-                final float timeDeltaMS = (now - then) * 0.000001f;
-                final boolean skipSample;
-                if (now < then
-                        || now > then + MAX_FILTER_DELTA_TIME_NANOS
-                        || (x == 0 && y == 0 && z == 0)) {
-                    if (LOG) {
-                        Slog.v(TAG, "Resetting orientation listener.");
-                    }
-                    resetLocked();
-                    skipSample = true;
-                } else {
-                    final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
-                    x = alpha * (x - mLastFilteredX) + mLastFilteredX;
-                    y = alpha * (y - mLastFilteredY) + mLastFilteredY;
-                    z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
-                    if (LOG) {
-                        Slog.v(TAG, "Filtered acceleration vector: "
-                                + "x=" + x + ", y=" + y + ", z=" + z
-                                + ", magnitude=" + FloatMath.sqrt(x * x + y * y + z * z));
-                    }
-                    skipSample = false;
-                }
-                mLastFilteredTimestampNanos = now;
-                mLastFilteredX = x;
-                mLastFilteredY = y;
-                mLastFilteredZ = z;
-
-                boolean isAccelerating = false;
-                boolean isFlat = false;
-                boolean isSwinging = false;
-                if (!skipSample) {
-                    // Calculate the magnitude of the acceleration vector.
-                    final float magnitude = FloatMath.sqrt(x * x + y * y + z * z);
-                    if (magnitude < NEAR_ZERO_MAGNITUDE) {
-                        if (LOG) {
-                            Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
-                        }
-                        clearPredictedRotationLocked();
-                    } else {
-                        // Determine whether the device appears to be undergoing external
-                        // acceleration.
-                        if (isAcceleratingLocked(magnitude)) {
-                            isAccelerating = true;
-                            mAccelerationTimestampNanos = now;
-                        }
-
-                        // Calculate the tilt angle.
-                        // This is the angle between the up vector and the x-y plane (the plane of
-                        // the screen) in a range of [-90, 90] degrees.
-                        //   -90 degrees: screen horizontal and facing the ground (overhead)
-                        //     0 degrees: screen vertical
-                        //    90 degrees: screen horizontal and facing the sky (on table)
-                        final int tiltAngle = (int) Math.round(
-                                Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
-                        addTiltHistoryEntryLocked(now, tiltAngle);
-
-                        // Determine whether the device appears to be flat or swinging.
-                        if (isFlatLocked(now)) {
-                            isFlat = true;
-                            mFlatTimestampNanos = now;
-                        }
-                        if (isSwingingLocked(now, tiltAngle)) {
-                            isSwinging = true;
-                            mSwingTimestampNanos = now;
-                        }
-
-                        // If the tilt angle is too close to horizontal then we cannot determine
-                        // the orientation angle of the screen.
-                        if (tiltAngle <= TILT_OVERHEAD_ENTER) {
-                            mOverhead = true;
-                        } else if (tiltAngle >= TILT_OVERHEAD_EXIT) {
-                            mOverhead = false;
-                        }
-                        if (mOverhead) {
-                            if (LOG) {
-                                Slog.v(TAG, "Ignoring sensor data, device is overhead: "
-                                        + "tiltAngle=" + tiltAngle);
-                            }
-                            clearPredictedRotationLocked();
-                        } else if (Math.abs(tiltAngle) > MAX_TILT) {
-                            if (LOG) {
-                                Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
-                                        + "tiltAngle=" + tiltAngle);
-                            }
-                            clearPredictedRotationLocked();
-                        } else {
-                            // Calculate the orientation angle.
-                            // This is the angle between the x-y projection of the up vector onto
-                            // the +y-axis, increasing clockwise in a range of [0, 360] degrees.
-                            int orientationAngle = (int) Math.round(
-                                    -Math.atan2(-x, y) * RADIANS_TO_DEGREES);
-                            if (orientationAngle < 0) {
-                                // atan2 returns [-180, 180]; normalize to [0, 360]
-                                orientationAngle += 360;
-                            }
-
-                            // Find the nearest rotation.
-                            int nearestRotation = (orientationAngle + 45) / 90;
-                            if (nearestRotation == 4) {
-                                nearestRotation = 0;
-                            }
-
-                            // Determine the predicted orientation.
-                            if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
-                                    && isOrientationAngleAcceptableLocked(nearestRotation,
-                                            orientationAngle)) {
-                                updatePredictedRotationLocked(now, nearestRotation);
-                                if (LOG) {
-                                    Slog.v(TAG, "Predicted: "
-                                            + "tiltAngle=" + tiltAngle
-                                            + ", orientationAngle=" + orientationAngle
-                                            + ", predictedRotation=" + mPredictedRotation
-                                            + ", predictedRotationAgeMS="
-                                                    + ((now - mPredictedRotationTimestampNanos)
-                                                            * 0.000001f));
-                                }
-                            } else {
-                                if (LOG) {
-                                    Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
-                                            + "tiltAngle=" + tiltAngle
-                                            + ", orientationAngle=" + orientationAngle);
-                                }
-                                clearPredictedRotationLocked();
-                            }
-                        }
-                    }
-                }
-                mFlat = isFlat;
-                mSwinging = isSwinging;
-                mAccelerating = isAccelerating;
-
-                // Determine new proposed rotation.
-                oldProposedRotation = mProposedRotation;
-                if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
-                    mProposedRotation = mPredictedRotation;
-                }
-                proposedRotation = mProposedRotation;
-
-                // Write final statistics about where we are in the orientation detection process.
-                if (LOG) {
-                    Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation
-                            + ", proposedRotation=" + proposedRotation
-                            + ", predictedRotation=" + mPredictedRotation
-                            + ", timeDeltaMS=" + timeDeltaMS
-                            + ", isAccelerating=" + isAccelerating
-                            + ", isFlat=" + isFlat
-                            + ", isSwinging=" + isSwinging
-                            + ", isOverhead=" + mOverhead
-                            + ", timeUntilSettledMS=" + remainingMS(now,
-                                    mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
-                            + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
-                                    mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
-                            + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
-                                    mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
-                            + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
-                                    mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
-                }
-            }
-
-            // Tell the listener.
-            if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
-                if (LOG) {
-                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + proposedRotation
-                            + ", oldProposedRotation=" + oldProposedRotation);
-                }
-                onProposedRotationChanged(proposedRotation);
-            }
-        }
-
-        /**
-         * Returns true if the tilt angle is acceptable for a given predicted rotation.
-         */
-        private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
-            return tiltAngle >= TILT_TOLERANCE[rotation][0]
-                    && tiltAngle <= TILT_TOLERANCE[rotation][1];
-        }
-
-        /**
-         * Returns true if the orientation angle is acceptable for a given predicted rotation.
-         *
-         * This function takes into account the gap between adjacent orientations
-         * for hysteresis.
-         */
-        private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) {
-            // If there is no current rotation, then there is no gap.
-            // The gap is used only to introduce hysteresis among advertised orientation
-            // changes to avoid flapping.
-            final int currentRotation = mCurrentRotation;
-            if (currentRotation >= 0) {
-                // If the specified rotation is the same or is counter-clockwise adjacent
-                // to the current rotation, then we set a lower bound on the orientation angle.
-                // For example, if currentRotation is ROTATION_0 and proposed is ROTATION_90,
-                // then we want to check orientationAngle > 45 + GAP / 2.
-                if (rotation == currentRotation
-                        || rotation == (currentRotation + 1) % 4) {
-                    int lowerBound = rotation * 90 - 45
-                            + ADJACENT_ORIENTATION_ANGLE_GAP / 2;
-                    if (rotation == 0) {
-                        if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) {
-                            return false;
-                        }
-                    } else {
-                        if (orientationAngle < lowerBound) {
-                            return false;
-                        }
-                    }
-                }
-
-                // If the specified rotation is the same or is clockwise adjacent,
-                // then we set an upper bound on the orientation angle.
-                // For example, if currentRotation is ROTATION_0 and rotation is ROTATION_270,
-                // then we want to check orientationAngle < 315 - GAP / 2.
-                if (rotation == currentRotation
-                        || rotation == (currentRotation + 3) % 4) {
-                    int upperBound = rotation * 90 + 45
-                            - ADJACENT_ORIENTATION_ANGLE_GAP / 2;
-                    if (rotation == 0) {
-                        if (orientationAngle <= 45 && orientationAngle > upperBound) {
-                            return false;
-                        }
-                    } else {
-                        if (orientationAngle > upperBound) {
-                            return false;
-                        }
-                    }
-                }
-            }
-            return true;
-        }
-
-        /**
-         * Returns true if the predicted rotation is ready to be advertised as a
-         * proposed rotation.
-         */
-        private boolean isPredictedRotationAcceptableLocked(long now) {
-            // The predicted rotation must have settled long enough.
-            if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
-                return false;
-            }
-
-            // The last flat state (time since picked up) must have been sufficiently long ago.
-            if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) {
-                return false;
-            }
-
-            // The last swing state (time since last movement to put down) must have been
-            // sufficiently long ago.
-            if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {
-                return false;
-            }
-
-            // The last acceleration state must have been sufficiently long ago.
-            if (now < mAccelerationTimestampNanos
-                    + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
-                return false;
-            }
-
-            // Looks good!
-            return true;
-        }
-
-        private void resetLocked() {
-            mLastFilteredTimestampNanos = Long.MIN_VALUE;
-            mProposedRotation = -1;
-            mFlatTimestampNanos = Long.MIN_VALUE;
-            mFlat = false;
-            mSwingTimestampNanos = Long.MIN_VALUE;
-            mSwinging = false;
-            mAccelerationTimestampNanos = Long.MIN_VALUE;
-            mAccelerating = false;
-            mOverhead = false;
-            clearPredictedRotationLocked();
-            clearTiltHistoryLocked();
-        }
-
-        private void clearPredictedRotationLocked() {
-            mPredictedRotation = -1;
-            mPredictedRotationTimestampNanos = Long.MIN_VALUE;
-        }
-
-        private void updatePredictedRotationLocked(long now, int rotation) {
-            if (mPredictedRotation != rotation) {
-                mPredictedRotation = rotation;
-                mPredictedRotationTimestampNanos = now;
-            }
-        }
-
-        private boolean isAcceleratingLocked(float magnitude) {
-            return magnitude < MIN_ACCELERATION_MAGNITUDE
-                    || magnitude > MAX_ACCELERATION_MAGNITUDE;
-        }
-
-        private void clearTiltHistoryLocked() {
-            mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
-            mTiltHistoryIndex = 1;
-        }
-
-        private void addTiltHistoryEntryLocked(long now, float tilt) {
-            mTiltHistory[mTiltHistoryIndex] = tilt;
-            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now;
-            mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE;
-            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE;
-        }
-
-        private boolean isFlatLocked(long now) {
-            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
-                if (mTiltHistory[i] < FLAT_ANGLE) {
-                    break;
-                }
-                if (mTiltHistoryTimestampNanos[i] + FLAT_TIME_NANOS <= now) {
-                    // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS.
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private boolean isSwingingLocked(long now, float tilt) {
-            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
-                if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) {
-                    break;
-                }
-                if (mTiltHistory[i] + SWING_AWAY_ANGLE_DELTA <= tilt) {
-                    // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS.
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private int nextTiltHistoryIndexLocked(int index) {
-            index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1;
-            return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1;
-        }
-
-        private float getLastTiltLocked() {
-            int index = nextTiltHistoryIndexLocked(mTiltHistoryIndex);
-            return index >= 0 ? mTiltHistory[index] : Float.NaN;
-        }
-
-        private float remainingMS(long now, long until) {
-            return now >= until ? 0 : (until - now) * 0.000001f;
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
deleted file mode 100644
index 6e8f550..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ /dev/null
@@ -1,332 +0,0 @@
-package com.android.internal.policy.impl.keyguard;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.graphics.PixelFormat;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Slog;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowManagerPolicy.OnKeyguardExitResult;
-
-import com.android.internal.policy.IKeyguardExitCallback;
-import com.android.internal.policy.IKeyguardService;
-import com.android.internal.policy.IKeyguardShowCallback;
-
-/**
- * A local class that keeps a cache of keyguard state that can be restored in the event
- * keyguard crashes. It currently also allows runtime-selectable
- * local or remote instances of keyguard.
- */
-public class KeyguardServiceDelegate {
-    public static final String KEYGUARD_PACKAGE = "com.android.systemui";
-    public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";
-
-    private static final String TAG = "KeyguardServiceDelegate";
-    private static final boolean DEBUG = true;
-
-    protected KeyguardServiceWrapper mKeyguardService;
-    private final Context mContext;
-    private final View mScrim; // shown if keyguard crashes
-    private final KeyguardState mKeyguardState = new KeyguardState();
-    private ShowListener mShowListenerWhenConnect;
-
-    /* package */ static final class KeyguardState {
-        KeyguardState() {
-            // Assume keyguard is showing and secure until we know for sure. This is here in
-            // the event something checks before the service is actually started.
-            // KeyguardService itself should default to this state until the real state is known.
-            showing = true;
-            showingAndNotOccluded = true;
-            secure = true;
-            deviceHasKeyguard = true;
-        }
-        boolean showing;
-        boolean showingAndNotOccluded;
-        boolean inputRestricted;
-        boolean occluded;
-        boolean secure;
-        boolean dreaming;
-        boolean systemIsReady;
-        boolean deviceHasKeyguard;
-        public boolean enabled;
-        public boolean dismissable;
-        public int offReason;
-        public int currentUser;
-        public boolean screenIsOn;
-        public boolean bootCompleted;
-    };
-
-    public interface ShowListener {
-        public void onShown(IBinder windowToken);
-    }
-
-    // A delegate class to map a particular invocation with a ShowListener object.
-    private final class KeyguardShowDelegate extends IKeyguardShowCallback.Stub {
-        private ShowListener mShowListener;
-
-        KeyguardShowDelegate(ShowListener showListener) {
-            mShowListener = showListener;
-        }
-
-        @Override
-        public void onShown(IBinder windowToken) throws RemoteException {
-            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
-            if (mShowListener != null) {
-                mShowListener.onShown(windowToken);
-            }
-            hideScrim();
-        }
-    };
-
-    // A delegate class to map a particular invocation with an OnKeyguardExitResult object.
-    private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub {
-        private OnKeyguardExitResult mOnKeyguardExitResult;
-
-        KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) {
-            mOnKeyguardExitResult = onKeyguardExitResult;
-        }
-
-        @Override
-        public void onKeyguardExitResult(boolean success) throws RemoteException {
-            if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****");
-            if (mOnKeyguardExitResult != null) {
-                mOnKeyguardExitResult.onKeyguardExitResult(success);
-            }
-        }
-    };
-
-    public KeyguardServiceDelegate(Context context) {
-        mContext = context;
-        mScrim = createScrim(context);
-    }
-
-    public void bindService(Context context) {
-        Intent intent = new Intent();
-        intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
-        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
-                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
-            Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
-            mKeyguardState.showing = false;
-            mKeyguardState.showingAndNotOccluded = false;
-            mKeyguardState.secure = false;
-            mKeyguardState.deviceHasKeyguard = false;
-            hideScrim();
-        } else {
-            if (DEBUG) Log.v(TAG, "*** Keyguard started");
-        }
-    }
-
-    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
-            mKeyguardService = new KeyguardServiceWrapper(mContext,
-                    IKeyguardService.Stub.asInterface(service));
-            if (mKeyguardState.systemIsReady) {
-                // If the system is ready, it means keyguard crashed and restarted.
-                mKeyguardService.onSystemReady();
-                // This is used to hide the scrim once keyguard displays.
-                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(
-                        mShowListenerWhenConnect));
-                mShowListenerWhenConnect = null;
-            }
-            if (mKeyguardState.bootCompleted) {
-                mKeyguardService.onBootCompleted();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
-            mKeyguardService = null;
-        }
-
-    };
-
-    public boolean isShowing() {
-        if (mKeyguardService != null) {
-            mKeyguardState.showing = mKeyguardService.isShowing();
-        }
-        return mKeyguardState.showing;
-    }
-
-    public boolean isInputRestricted() {
-        if (mKeyguardService != null) {
-            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
-        }
-        return mKeyguardState.inputRestricted;
-    }
-
-    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
-        if (mKeyguardService != null) {
-            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
-        }
-    }
-
-    public void keyguardDone(boolean authenticated, boolean wakeup) {
-        if (mKeyguardService != null) {
-            mKeyguardService.keyguardDone(authenticated, wakeup);
-        }
-    }
-
-    public void setOccluded(boolean isOccluded) {
-        if (mKeyguardService != null) {
-            mKeyguardService.setOccluded(isOccluded);
-        }
-        mKeyguardState.occluded = isOccluded;
-    }
-
-    public void dismiss() {
-        if (mKeyguardService != null) {
-            mKeyguardService.dismiss();
-        }
-    }
-
-    public boolean isSecure() {
-        if (mKeyguardService != null) {
-            mKeyguardState.secure = mKeyguardService.isSecure();
-        }
-        return mKeyguardState.secure;
-    }
-
-    public void onDreamingStarted() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onDreamingStarted();
-        }
-        mKeyguardState.dreaming = true;
-    }
-
-    public void onDreamingStopped() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onDreamingStopped();
-        }
-        mKeyguardState.dreaming = false;
-    }
-
-    public void onScreenTurnedOn(final ShowListener showListener) {
-        if (mKeyguardService != null) {
-            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + showListener + ")");
-            mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(showListener));
-        } else {
-            // try again when we establish a connection
-            Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!");
-            // This shouldn't happen, but if it does, show the scrim immediately and
-            // invoke the listener's callback after the service actually connects.
-            mShowListenerWhenConnect = showListener;
-            showScrim();
-        }
-        mKeyguardState.screenIsOn = true;
-    }
-
-    public void onScreenTurnedOff(int why) {
-        if (mKeyguardService != null) {
-            mKeyguardService.onScreenTurnedOff(why);
-        }
-        mKeyguardState.offReason = why;
-        mKeyguardState.screenIsOn = false;
-    }
-
-    public void setKeyguardEnabled(boolean enabled) {
-        if (mKeyguardService != null) {
-            mKeyguardService.setKeyguardEnabled(enabled);
-        }
-        mKeyguardState.enabled = enabled;
-    }
-
-    public void onSystemReady() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onSystemReady();
-        } else {
-            mKeyguardState.systemIsReady = true;
-        }
-    }
-
-    public void doKeyguardTimeout(Bundle options) {
-        if (mKeyguardService != null) {
-            mKeyguardService.doKeyguardTimeout(options);
-        }
-    }
-
-    public void setCurrentUser(int newUserId) {
-        if (mKeyguardService != null) {
-            mKeyguardService.setCurrentUser(newUserId);
-        }
-        mKeyguardState.currentUser = newUserId;
-    }
-
-    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
-        if (mKeyguardService != null) {
-            mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
-        }
-    }
-
-    private static final View createScrim(Context context) {
-        View view = new View(context);
-
-        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
-                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
-                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
-                ;
-
-        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
-        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
-        lp.setTitle("KeyguardScrim");
-        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        wm.addView(view, lp);
-        // Disable pretty much everything in statusbar until keyguard comes back and we know
-        // the state of the world.
-        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
-                | View.STATUS_BAR_DISABLE_BACK
-                | View.STATUS_BAR_DISABLE_RECENT
-                | View.STATUS_BAR_DISABLE_EXPAND
-                | View.STATUS_BAR_DISABLE_SEARCH);
-        return view;
-    }
-
-    public void showScrim() {
-        if (!mKeyguardState.deviceHasKeyguard) return;
-        mScrim.post(new Runnable() {
-            @Override
-            public void run() {
-                mScrim.setVisibility(View.VISIBLE);
-            }
-        });
-    }
-
-    public void hideScrim() {
-        mScrim.post(new Runnable() {
-            @Override
-            public void run() {
-                mScrim.setVisibility(View.GONE);
-            }
-        });
-    }
-
-    public void onBootCompleted() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onBootCompleted();
-        }
-        mKeyguardState.bootCompleted = true;
-    }
-
-    public void onActivityDrawn() {
-        if (mKeyguardService != null) {
-            mKeyguardService.onActivityDrawn();
-        }
-    }
-}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
deleted file mode 100644
index b3b7684..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java
+++ /dev/null
@@ -1,206 +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.internal.policy.impl.keyguard;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.internal.policy.IKeyguardExitCallback;
-import com.android.internal.policy.IKeyguardService;
-import com.android.internal.policy.IKeyguardShowCallback;
-import com.android.internal.policy.IKeyguardStateCallback;
-
-/**
- * A wrapper class for KeyguardService.  It implements IKeyguardService to ensure the interface
- * remains consistent.
- *
- */
-public class KeyguardServiceWrapper implements IKeyguardService {
-    private KeyguardStateMonitor mKeyguardStateMonitor;
-    private IKeyguardService mService;
-    private String TAG = "KeyguardServiceWrapper";
-
-    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
-        mService = service;
-        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
-    }
-
-    @Override // Binder interface
-    public void verifyUnlock(IKeyguardExitCallback callback) {
-        try {
-            mService.verifyUnlock(callback);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void keyguardDone(boolean authenticated, boolean wakeup) {
-        try {
-            mService.keyguardDone(authenticated, wakeup);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void setOccluded(boolean isOccluded) {
-        try {
-            mService.setOccluded(isOccluded);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override
-    public void addStateMonitorCallback(IKeyguardStateCallback callback) {
-        try {
-            mService.addStateMonitorCallback(callback);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void dismiss() {
-        try {
-            mService.dismiss();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onDreamingStarted() {
-        try {
-            mService.onDreamingStarted();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onDreamingStopped() {
-        try {
-            mService.onDreamingStopped();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onScreenTurnedOff(int reason) {
-        try {
-            mService.onScreenTurnedOff(reason);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onScreenTurnedOn(IKeyguardShowCallback result) {
-        try {
-            mService.onScreenTurnedOn(result);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void setKeyguardEnabled(boolean enabled) {
-        try {
-            mService.setKeyguardEnabled(enabled);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onSystemReady() {
-        try {
-            mService.onSystemReady();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void doKeyguardTimeout(Bundle options) {
-        try {
-            mService.doKeyguardTimeout(options);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void setCurrentUser(int userId) {
-        mKeyguardStateMonitor.setCurrentUser(userId);
-        try {
-            mService.setCurrentUser(userId);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onBootCompleted() {
-        try {
-            mService.onBootCompleted();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
-        try {
-            mService.startKeyguardExitAnimation(startTime, fadeoutDuration);
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public void onActivityDrawn() {
-        try {
-            mService.onActivityDrawn();
-        } catch (RemoteException e) {
-            Slog.w(TAG , "Remote Exception", e);
-        }
-    }
-
-    @Override // Binder interface
-    public IBinder asBinder() {
-        return mService.asBinder();
-    }
-
-    public boolean isShowing() {
-        return mKeyguardStateMonitor.isShowing();
-    }
-
-    public boolean isSecure() {
-        return mKeyguardStateMonitor.isSecure();
-    }
-
-    public boolean isInputRestricted() {
-        return mKeyguardStateMonitor.isInputRestricted();
-    }
-}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
deleted file mode 100644
index 6f9c617..0000000
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStateMonitor.java
+++ /dev/null
@@ -1,86 +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.internal.policy.impl.keyguard;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.internal.policy.IKeyguardService;
-import com.android.internal.policy.IKeyguardStateCallback;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * Maintains a cached copy of Keyguard's state.
- * @hide
- */
-public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
-    private static final String TAG = "KeyguardStateMonitor";
-
-    // These cache the current state of Keyguard to improve performance and avoid deadlock. After
-    // Keyguard changes its state, it always triggers a layout in window manager. Because
-    // IKeyguardStateCallback is synchronous and because these states are declared volatile, it's
-    // guaranteed that window manager picks up the new state all the time in the layout caused by
-    // the state change of Keyguard.
-    private volatile boolean mIsShowing;
-    private volatile boolean mSimSecure;
-    private volatile boolean mInputRestricted;
-
-    private final LockPatternUtils mLockPatternUtils;
-
-    public KeyguardStateMonitor(Context context, IKeyguardService service) {
-        mLockPatternUtils = new LockPatternUtils(context);
-        mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
-        try {
-            service.addStateMonitorCallback(this);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Remote Exception", e);
-        }
-    }
-
-    public boolean isShowing() {
-        return mIsShowing;
-    }
-
-    public boolean isSecure() {
-        return mLockPatternUtils.isSecure() || mSimSecure;
-    }
-
-    public boolean isInputRestricted() {
-        return mInputRestricted;
-    }
-
-    @Override // Binder interface
-    public void onShowingStateChanged(boolean showing) {
-        mIsShowing = showing;
-    }
-
-    @Override // Binder interface
-    public void onSimSecureStateChanged(boolean simSecure) {
-        mSimSecure = simSecure;
-    }
-
-    public void setCurrentUser(int userId) {
-        mLockPatternUtils.setCurrentUser(userId);
-    }
-
-    @Override // Binder interface
-    public void onInputRestrictedStateChanged(boolean inputRestricted) {
-        mInputRestricted = inputRestricted;
-    }
-}
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/package.html b/policy/src/com/android/internal/policy/impl/package.html
deleted file mode 100644
index c9f96a6..0000000
--- a/policy/src/com/android/internal/policy/impl/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-
-{@hide}
-
-</body>
diff --git a/preloaded-classes b/preloaded-classes
index 7686431..c8d8c5d 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1172,6 +1172,7 @@
 android.telecom.InCallService
 android.telephony.PhoneNumberUtils
 android.telephony.Rlog
+android.telephony.SignalStrength
 android.telephony.SubscriptionManager
 android.telephony.TelephonyManager
 android.text.AndroidBidi
@@ -2631,7 +2632,6 @@
 javax.microedition.khronos.opengles.GL11ExtensionPack
 javax.net.DefaultSocketFactory
 javax.net.SocketFactory
-javax.net.ssl.DefaultHostnameVerifier
 javax.net.ssl.DistinguishedNameParser
 javax.net.ssl.HostnameVerifier
 javax.net.ssl.HttpsURLConnection
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 4e89566..c6afa2c 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -58,15 +58,14 @@
     Allocation mAdaptedAllocation;
     int mSize;
 
-    boolean mConstrainedLOD;
-    boolean mConstrainedFace;
-    boolean mConstrainedY;
-    boolean mConstrainedZ;
     boolean mReadAllowed = true;
     boolean mWriteAllowed = true;
+    boolean mAutoPadding = false;
+    int mSelectedX;
     int mSelectedY;
     int mSelectedZ;
     int mSelectedLOD;
+    int mSelectedArray[];
     Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
 
     int mCurrentDimX;
@@ -272,6 +271,17 @@
     }
 
     /**
+     * @hide
+     * Enable/Disable AutoPadding for Vec3 elements.
+     *
+     * @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding
+     *
+     */
+    public void setAutoPadding(boolean useAutoPadding) {
+        mAutoPadding = useAutoPadding;
+    }
+
+    /**
      * Get the size of the Allocation in bytes.
      *
      * @return size of the Allocation in bytes.
@@ -787,6 +797,7 @@
         copy1DRangeFromUnchecked(xoff, count, data);
     }
 
+
     /**
      * This is only intended to be used by auto-generated code reflected from
      * the RenderScript script files.
@@ -796,12 +807,33 @@
      * @param fp
      */
     public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
+        setFromFieldPacker(xoff, 0, 0, component_number, fp);
+    }
+
+    /**
+     * @hide
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files.
+     *
+     * @param xoff
+     * @param yoff
+     * @param zoff
+     * @param component_number
+     * @param fp
+     */
+    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
         mRS.validate();
         if (component_number >= mType.mElement.mElements.length) {
             throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
         }
         if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset must be >= 0.");
+            throw new RSIllegalArgumentException("Offset x must be >= 0.");
+        }
+        if(yoff < 0) {
+            throw new RSIllegalArgumentException("Offset y must be >= 0.");
+        }
+        if(zoff < 0) {
+            throw new RSIllegalArgumentException("Offset z must be >= 0.");
         }
 
         final byte[] data = fp.getData();
@@ -814,11 +846,11 @@
                                                " does not match component size " + eSize + ".");
         }
 
-        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
-                                     component_number, data, data_length);
+        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                                   component_number, data, data_length);
     }
 
-    private void data1DChecks(int off, int count, int len, int dataSize) {
+    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
         mRS.validate();
         if(off < 0) {
             throw new RSIllegalArgumentException("Offset must be >= 0.");
@@ -830,8 +862,14 @@
             throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
                                                ", got " + count + " at offset " + off + ".");
         }
-        if(len < dataSize) {
-            throw new RSIllegalArgumentException("Array too small for allocation type.");
+        if(usePadding) {
+            if(len < dataSize / 4 * 3) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        } else {
+            if(len < dataSize) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
         }
     }
 
@@ -853,8 +891,14 @@
                                           Element.DataType dt, int arrayLen) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         final int dataSize = mType.mElement.getBytesSize() * count;
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt);
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1031,8 +1075,24 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1193,8 +1253,24 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFromUnchecked");
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, arrayLen * dt.mSize, dt);
+                              array, sizeBytes, dt,
+                              mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1209,7 +1285,7 @@
      * @param w Width of the region to update
      * @param h Height of the region to update
      * @param d Depth of the region to update
-     * @param data to be placed into the allocation
+     * @param array to be placed into the allocation
      */
     public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFrom");
@@ -1267,7 +1343,11 @@
                 "Size of output array cannot be smaller than size of allocation.");
         }
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), array, dt);
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1333,6 +1413,45 @@
     }
 
     /**
+     * @hide
+     * This is only intended to be used by auto-generated code reflected from
+     * the RenderScript script files and should not be used by developers.
+     *
+     * @param xoff
+     * @param yoff
+     * @param zoff
+     * @param component_number
+     * @param array
+     */
+    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
+        mRS.validate();
+        if (component_number >= mType.mElement.mElements.length) {
+            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
+        }
+        if(xoff < 0) {
+            throw new RSIllegalArgumentException("Offset x must be >= 0.");
+        }
+        if(yoff < 0) {
+            throw new RSIllegalArgumentException("Offset y must be >= 0.");
+        }
+        if(zoff < 0) {
+            throw new RSIllegalArgumentException("Offset z must be >= 0.");
+        }
+
+        final byte[] data = fp.getData();
+        int data_length = fp.getPos();
+        int eSize = mType.mElement.mElements[component_number].getBytesSize();
+        eSize *= mType.mElement.mArraySizes[component_number];
+
+        if (data_length != eSize) {
+            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+                                               " does not match component size " + eSize + ".");
+        }
+
+        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                                   component_number, data, data_length);
+    }
+    /**
      * Resize a 1D allocation.  The contents of the allocation are preserved.
      * If new elements are allocated objects are created with null contents and
      * the new region is otherwise undefined.
@@ -1364,6 +1483,318 @@
         updateCacheInfo(mType);
     }
 
+    private void copy1DRangeToUnchecked(int off, int count, Object array,
+                                        Element.DataType dt, int arrayLen) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeToUnchecked");
+        final int dataSize = mType.mElement.getBytesSize() * count;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            usePadding = true;
+        }
+        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+                              mType.mElement.mType.mSize, usePadding);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The dest data array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, Object array) {
+        copy1DRangeToUnchecked(off, count, array,
+                               validateObjectIsPrimitiveArray(array, false),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * guarantee that the Allocation is compatible with the input buffer.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
+        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * and will generate exceptions if the Allocation type does not
+     * match the component type of the array passed in.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param array The source data array.
+     */
+    public void copy1DRangeTo(int off, int count, Object array) {
+        copy1DRangeToUnchecked(off, count, array,
+                               validateObjectIsPrimitiveArray(array, true),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * and will generate exceptions if the Allocation type is not a 32 bit
+     * integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeTo(int off, int count, int[] d) {
+        validateIsInt32();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * and will generate exceptions if the Allocation type is not a 16 bit
+     * integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeTo(int off, int count, short[] d) {
+        validateIsInt16();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * and will generate exceptions if the Allocation type is not an 8 bit
+     * integer type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array
+     */
+    public void copy1DRangeTo(int off, int count, byte[] d) {
+        validateIsInt8();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
+    }
+
+    /**
+     * @hide
+     * Copy part of this Allocation into an array.  This method does not
+     * and will generate exceptions if the Allocation type is not a 32 bit float
+     * type.
+     *
+     * @param off The offset of the first element to be copied.
+     * @param count The number of elements to be copied.
+     * @param d the source data array.
+     */
+    public void copy1DRangeTo(int off, int count, float[] d) {
+        validateIsFloat32();
+        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
+    }
+
+
+    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
+                                Element.DataType dt, int arrayLen) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeToUnchecked");
+        mRS.validate();
+        validate2DRange(xoff, yoff, w, h);
+        final int dataSize = mType.mElement.getBytesSize() * w * h;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param array Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
+        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
+                               validateObjectIsPrimitiveArray(array, true),
+                               java.lang.reflect.Array.getLength(array));
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
+        validateIsInt8();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_8, data.length);
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
+        validateIsInt16();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_16, data.length);
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
+        validateIsInt32();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.SIGNED_32, data.length);
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param data Dest Array to be copied into
+     */
+    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
+        validateIsFloat32();
+        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
+                               Element.DataType.FLOAT_32, data.length);
+    }
+
+
+    /**
+     * @hide
+     *
+     */
+    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
+                                        Object array, Element.DataType dt, int arrayLen) {
+        Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeToUnchecked");
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+        // AutoPadding for Vec3 Element
+        boolean usePadding = false;
+        int sizeBytes = arrayLen * dt.mSize;
+        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+            if (dataSize / 4 * 3 > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+            usePadding = true;
+            sizeBytes = dataSize;
+        } else {
+            if (dataSize > sizeBytes) {
+                throw new RSIllegalArgumentException("Array too small for allocation type.");
+            }
+        }
+        mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
+                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
+        Trace.traceEnd(RenderScript.TRACE_TAG);
+    }
+
+    /**
+     * @hide
+     * Copy from a rectangular region in this Allocation into an array.
+     *
+     * @param xoff X offset of the region to copy in this Allocation
+     * @param yoff Y offset of the region to copy in this Allocation
+     * @param zoff Z offset of the region to copy in this Allocation
+     * @param w Width of the region to copy
+     * @param h Height of the region to copy
+     * @param d Depth of the region to copy
+     * @param array Dest Array to be copied into
+     */
+    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
+        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
+                                 validateObjectIsPrimitiveArray(array, true),
+                                 java.lang.reflect.Array.getLength(array));
+    }
 
     // creation
 
@@ -1882,4 +2313,15 @@
         }
     }
 
+    /**
+     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
+     *
+     */
+    @Override
+    public void destroy() {
+        if((mUsage & USAGE_IO_OUTPUT) != 0) {
+            setSurface(null);
+        }
+        super.destroy();
+    }
 }
diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java
index 3522a52..183726f 100644
--- a/rs/java/android/renderscript/AllocationAdapter.java
+++ b/rs/java/android/renderscript/AllocationAdapter.java
@@ -21,76 +21,20 @@
  *
  **/
 public class AllocationAdapter extends Allocation {
-    AllocationAdapter(long id, RenderScript rs, Allocation alloc) {
+    Type mWindow;
+
+    AllocationAdapter(long id, RenderScript rs, Allocation alloc, Type t) {
         super(id, rs, alloc.mType, alloc.mUsage);
         mAdaptedAllocation = alloc;
+        mWindow = t;
     }
 
+    /*
     long getID(RenderScript rs) {
         throw new RSInvalidStateException(
             "This operation is not supported with adapters at this time.");
     }
-
-    /**
-     * @hide
-     */
-    public void subData(int xoff, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subElementData(int xoff, int component_number, FieldPacker fp) {
-        super.setFromFieldPacker(xoff, component_number, fp);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, int[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, short[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, byte[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData1D(int off, int count, float[] d) {
-        super.copy1DRangeFrom(off, count, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void subData2D(int xoff, int yoff, int w, int h, float[] d) {
-        super.copy2DRangeFrom(xoff, yoff, w, h, d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(int[] d) {
-        super.copyTo(d);
-    }
-    /**
-     * @hide
-     */
-    public void readData(float[] d) {
-        super.copyTo(d);
-    }
+    */
 
     void initLOD(int lod) {
         if (lod < 0) {
@@ -125,6 +69,28 @@
         mSelectedZ = 0;
     }
 
+    private void updateOffsets() {
+        int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+
+        if (mSelectedArray != null) {
+            if (mSelectedArray.length > 0) {
+                a1 = mSelectedArray[0];
+            }
+            if (mSelectedArray.length > 1) {
+                a2 = mSelectedArray[2];
+            }
+            if (mSelectedArray.length > 2) {
+                a3 = mSelectedArray[2];
+            }
+            if (mSelectedArray.length > 3) {
+                a4 = mSelectedArray[3];
+            }
+        }
+        mRS.nAllocationAdapterOffset(getID(mRS), mSelectedX, mSelectedY, mSelectedZ,
+                                     mSelectedLOD, mSelectedFace.mID, a1, a2, a3, a4);
+
+    }
+
     /**
      * Set the active LOD.  The LOD must be within the range for the
      * type being adapted.  The base allocation must have mipmaps.
@@ -138,11 +104,13 @@
         if (!mAdaptedAllocation.getType().hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the allocation type does not include mipmaps.");
         }
-        if (!mConstrainedLOD) {
+        if (mWindow.hasMipmaps()) {
             throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
         }
 
         initLOD(lod);
+        mSelectedLOD = lod;
+        updateOffsets();
     }
 
     /**
@@ -155,14 +123,38 @@
         if (!mAdaptedAllocation.getType().hasFaces()) {
             throw new RSInvalidStateException("Cannot set Face when the allocation type does not include faces.");
         }
-        if (!mConstrainedFace) {
-            throw new RSInvalidStateException("Cannot set LOD when the adapter includes mipmaps.");
+        if (mWindow.hasFaces()) {
+            throw new RSInvalidStateException("Cannot set face when the adapter includes faces.");
         }
         if (cf == null) {
             throw new RSIllegalArgumentException("Cannot set null face.");
         }
 
         mSelectedFace = cf;
+        updateOffsets();
+    }
+
+
+    /**
+     * @hide
+     * Set the active X.  The x value must be within the range for
+     * the allocation being adapted.
+     *
+     * @param x The x to make active.
+     */
+    public void setX(int x) {
+        if (mAdaptedAllocation.getType().getX() <= x) {
+            throw new RSInvalidStateException("Cannot set X greater than dimension of allocation.");
+        }
+        if (mWindow.getX() == mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set X when the adapter includes X.");
+        }
+        if ((mWindow.getX() + x) >= mAdaptedAllocation.getType().getX()) {
+            throw new RSInvalidStateException("Cannot set (X + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedX = x;
+        updateOffsets();
     }
 
     /**
@@ -179,11 +171,15 @@
         if (mAdaptedAllocation.getType().getY() <= y) {
             throw new RSInvalidStateException("Cannot set Y greater than dimension of allocation.");
         }
-        if (!mConstrainedY) {
+        if (mWindow.getY() == mAdaptedAllocation.getType().getY()) {
             throw new RSInvalidStateException("Cannot set Y when the adapter includes Y.");
         }
+        if ((mWindow.getY() + y) >= mAdaptedAllocation.getType().getY()) {
+            throw new RSInvalidStateException("Cannot set (Y + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedY = y;
+        updateOffsets();
     }
 
     /**
@@ -200,35 +196,112 @@
         if (mAdaptedAllocation.getType().getZ() <= z) {
             throw new RSInvalidStateException("Cannot set Z greater than dimension of allocation.");
         }
-        if (!mConstrainedZ) {
+        if (mWindow.getZ() == mAdaptedAllocation.getType().getZ()) {
             throw new RSInvalidStateException("Cannot set Z when the adapter includes Z.");
         }
+        if ((mWindow.getZ() + z) >= mAdaptedAllocation.getType().getZ()) {
+            throw new RSInvalidStateException("Cannot set (Z + window) which would be larger than dimension of allocation.");
+        }
 
         mSelectedZ = z;
+        updateOffsets();
+    }
+
+    /**
+     * @hide
+     */
+    public void setArray(int arrayNum, int arrayVal) {
+        if (mAdaptedAllocation.getType().getArray(arrayNum) == 0) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the allocation type does not include arrayNum dim.");
+        }
+        if (mAdaptedAllocation.getType().getArray(arrayNum) <= arrayVal) {
+            throw new RSInvalidStateException("Cannot set arrayNum greater than dimension of allocation.");
+        }
+        if (mWindow.getArray(arrayNum) == mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set arrayNum when the adapter includes arrayNum.");
+        }
+        if ((mWindow.getArray(arrayNum) + arrayVal) >= mAdaptedAllocation.getType().getArray(arrayNum)) {
+            throw new RSInvalidStateException("Cannot set (arrayNum + window) which would be larger than dimension of allocation.");
+        }
+
+        mSelectedArray[arrayNum] = arrayVal;
+        updateOffsets();
     }
 
     static public AllocationAdapter create1D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = true;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createX(rs, a.getElement(), a.getType().getX());
+        return createTyped(rs, a, t);
     }
 
+
     static public AllocationAdapter create2D(RenderScript rs, Allocation a) {
         rs.validate();
-        AllocationAdapter aa = new AllocationAdapter(0, rs, a);
-        aa.mConstrainedLOD = true;
-        aa.mConstrainedFace = true;
-        aa.mConstrainedY = false;
-        aa.mConstrainedZ = true;
-        aa.initLOD(0);
-        return aa;
+        Type t = Type.createXY(rs, a.getElement(), a.getType().getX(), a.getType().getY());
+        return createTyped(rs, a, t);
     }
 
+    /**
+     * @hide
+     *
+     * Create an arbitrary window into the base allocation
+     * The type describes the shape of the window.
+     *
+     * Any dimensions present in the type must be equal or smaller
+     * to the dimensions in the source allocation.  A dimension
+     * present in the allocation that is not present in the type
+     * will be constrained away with the selectors
+     *
+     * If a dimension is present in the type and allcation one of
+     * two things will happen
+     *
+     * If the type is smaller than the allocation a window will be
+     * created, the selected value in the adapter for that dimension
+     * will act as the base address and the type will describe the
+     * size of the view starting at that point.
+     *
+     * If the type and allocation dimension are of the same size
+     * then setting the selector for the dimension will be an error.
+     */
+    static public AllocationAdapter createTyped(RenderScript rs, Allocation a, Type t) {
+        rs.validate();
+
+        if (a.mAdaptedAllocation != null) {
+            throw new RSInvalidStateException("Adapters cannot be nested.");
+        }
+
+        if (!a.getType().getElement().equals(t.getElement())) {
+            throw new RSInvalidStateException("Element must match Allocation type.");
+        }
+
+        if (t.hasFaces() || t.hasMipmaps()) {
+            throw new RSInvalidStateException("Adapters do not support window types with Mipmaps or Faces.");
+        }
+
+        Type at = a.getType();
+        if ((t.getX() > at.getX()) ||
+            (t.getY() > at.getY()) ||
+            (t.getZ() > at.getZ()) ||
+            (t.getArrayCount() > at.getArrayCount())) {
+
+            throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+        }
+
+        if (t.getArrayCount() > 0) {
+            for (int i = 0; i < t.getArray(i); i++) {
+                if (t.getArray(i) > at.getArray(i)) {
+                    throw new RSInvalidStateException("Type cannot have dimension larger than the source allocation.");
+                }
+            }
+        }
+
+        // Create the object
+        long id = rs.nAllocationAdapterCreate(a.getID(rs), t.getID(rs));
+        if (id == 0) {
+            throw new RSRuntimeException("AllocationAdapter creation failed.");
+        }
+        return new AllocationAdapter(id, rs, a, t);
+    }
 
     /**
      * Override the Allocation resize.  Resizing adapters is not
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index c6b5b0d..287b3f1 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -118,7 +118,10 @@
      */
     public enum DataType {
         NONE (0, 0),
-        //FLOAT_16 (1, 2),
+        /**
+         *     @hide
+         */
+        FLOAT_16 (1, 2),
         FLOAT_32 (2, 4),
         FLOAT_64 (3, 8),
         SIGNED_8 (4, 1),
@@ -386,6 +389,16 @@
         return rs.mElement_I64;
     }
 
+    /**
+     *     @hide
+     */
+    public static Element F16(RenderScript rs) {
+        if(rs.mElement_F16 == null) {
+            rs.mElement_F16 = createUser(rs, DataType.FLOAT_16);
+        }
+        return rs.mElement_F16;
+    }
+
     public static Element F32(RenderScript rs) {
         if(rs.mElement_F32 == null) {
             rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
@@ -520,6 +533,36 @@
         return rs.mElement_RGBA_8888;
     }
 
+    /**
+     *     @hide
+     */
+    public static Element F16_2(RenderScript rs) {
+        if(rs.mElement_HALF_2 == null) {
+            rs.mElement_HALF_2 = createVector(rs, DataType.FLOAT_16, 2);
+        }
+        return rs.mElement_HALF_2;
+    }
+
+    /**
+     *     @hide
+     */
+    public static Element F16_3(RenderScript rs) {
+        if(rs.mElement_FLOAT_3 == null) {
+            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_16, 3);
+        }
+        return rs.mElement_HALF_3;
+    }
+
+    /**
+     *     @hide
+     */
+    public static Element F16_4(RenderScript rs) {
+        if(rs.mElement_HALF_4 == null) {
+            rs.mElement_HALF_4 = createVector(rs, DataType.FLOAT_16, 4);
+        }
+        return rs.mElement_HALF_4;
+    }
+
     public static Element F32_2(RenderScript rs) {
         if(rs.mElement_FLOAT_2 == null) {
             rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 20b07e7..0f967fc 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -241,8 +241,7 @@
                 addI64(0);
                 addI64(0);
                 addI64(0);
-            }
-            else {
+            } else {
                 addI32((int)obj.getID(null));
             }
         } else {
@@ -619,6 +618,289 @@
         return mPos;
     }
 
+    private static void addToPack(FieldPacker fp, Object obj) {
+        if (obj instanceof Boolean) {
+            fp.addBoolean(((Boolean)obj).booleanValue());
+            return;
+        }
+
+        if (obj instanceof Byte) {
+            fp.addI8(((Byte)obj).byteValue());
+            return;
+        }
+
+        if (obj instanceof Short) {
+            fp.addI16(((Short)obj).shortValue());
+            return;
+        }
+
+        if (obj instanceof Integer) {
+            fp.addI32(((Integer)obj).intValue());
+            return;
+        }
+
+        if (obj instanceof Long) {
+            fp.addI64(((Long)obj).longValue());
+            return;
+        }
+
+        if (obj instanceof Float) {
+            fp.addF32(((Float)obj).floatValue());
+            return;
+        }
+
+        if (obj instanceof Double) {
+            fp.addF64(((Double)obj).doubleValue());
+            return;
+        }
+
+        if (obj instanceof Byte2) {
+            fp.addI8((Byte2)obj);
+            return;
+        }
+
+        if (obj instanceof Byte3) {
+            fp.addI8((Byte3)obj);
+            return;
+        }
+
+        if (obj instanceof Byte4) {
+            fp.addI8((Byte4)obj);
+            return;
+        }
+
+        if (obj instanceof Short2) {
+            fp.addI16((Short2)obj);
+            return;
+        }
+
+        if (obj instanceof Short3) {
+            fp.addI16((Short3)obj);
+            return;
+        }
+
+        if (obj instanceof Short4) {
+            fp.addI16((Short4)obj);
+            return;
+        }
+
+        if (obj instanceof Int2) {
+            fp.addI32((Int2)obj);
+            return;
+        }
+
+        if (obj instanceof Int3) {
+            fp.addI32((Int3)obj);
+            return;
+        }
+
+        if (obj instanceof Int4) {
+            fp.addI32((Int4)obj);
+            return;
+        }
+
+        if (obj instanceof Long2) {
+            fp.addI64((Long2)obj);
+            return;
+        }
+
+        if (obj instanceof Long3) {
+            fp.addI64((Long3)obj);
+            return;
+        }
+
+        if (obj instanceof Long4) {
+            fp.addI64((Long4)obj);
+            return;
+        }
+
+        if (obj instanceof Float2) {
+            fp.addF32((Float2)obj);
+            return;
+        }
+
+        if (obj instanceof Float3) {
+            fp.addF32((Float3)obj);
+            return;
+        }
+
+        if (obj instanceof Float4) {
+            fp.addF32((Float4)obj);
+            return;
+        }
+
+        if (obj instanceof Double2) {
+            fp.addF64((Double2)obj);
+            return;
+        }
+
+        if (obj instanceof Double3) {
+            fp.addF64((Double3)obj);
+            return;
+        }
+
+        if (obj instanceof Double4) {
+            fp.addF64((Double4)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix2f) {
+            fp.addMatrix((Matrix2f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix3f) {
+            fp.addMatrix((Matrix3f)obj);
+            return;
+        }
+
+        if (obj instanceof Matrix4f) {
+            fp.addMatrix((Matrix4f)obj);
+            return;
+        }
+
+        if (obj instanceof BaseObj) {
+            fp.addObj((BaseObj)obj);
+            return;
+        }
+    }
+
+    private static int getPackedSize(Object obj) {
+        if (obj instanceof Boolean) {
+            return 1;
+        }
+
+        if (obj instanceof Byte) {
+            return 1;
+        }
+
+        if (obj instanceof Short) {
+            return 2;
+        }
+
+        if (obj instanceof Integer) {
+            return 4;
+        }
+
+        if (obj instanceof Long) {
+            return 8;
+        }
+
+        if (obj instanceof Float) {
+            return 4;
+        }
+
+        if (obj instanceof Double) {
+            return 8;
+        }
+
+        if (obj instanceof Byte2) {
+            return 2;
+        }
+
+        if (obj instanceof Byte3) {
+            return 3;
+        }
+
+        if (obj instanceof Byte4) {
+            return 4;
+        }
+
+        if (obj instanceof Short2) {
+            return 4;
+        }
+
+        if (obj instanceof Short3) {
+            return 6;
+        }
+
+        if (obj instanceof Short4) {
+            return 8;
+        }
+
+        if (obj instanceof Int2) {
+            return 8;
+        }
+
+        if (obj instanceof Int3) {
+            return 12;
+        }
+
+        if (obj instanceof Int4) {
+            return 16;
+        }
+
+        if (obj instanceof Long2) {
+            return 16;
+        }
+
+        if (obj instanceof Long3) {
+            return 24;
+        }
+
+        if (obj instanceof Long4) {
+            return 32;
+        }
+
+        if (obj instanceof Float2) {
+            return 8;
+        }
+
+        if (obj instanceof Float3) {
+            return 12;
+        }
+
+        if (obj instanceof Float4) {
+            return 16;
+        }
+
+        if (obj instanceof Double2) {
+            return 16;
+        }
+
+        if (obj instanceof Double3) {
+            return 24;
+        }
+
+        if (obj instanceof Double4) {
+            return 32;
+        }
+
+        if (obj instanceof Matrix2f) {
+            return 16;
+        }
+
+        if (obj instanceof Matrix3f) {
+            return 36;
+        }
+
+        if (obj instanceof Matrix4f) {
+            return 64;
+        }
+
+        if (obj instanceof BaseObj) {
+            if (RenderScript.sPointerSize == 8) {
+                return 32;
+            } else {
+                return 4;
+            }
+        }
+
+        return 0;
+    }
+
+    static FieldPacker createFieldPack(Object[] args) {
+        int len = 0;
+        for (Object arg : args) {
+            len += getPackedSize(arg);
+        }
+        FieldPacker fp = new FieldPacker(len);
+        for (Object arg : args) {
+            addToPack(fp, arg);
+        }
+        return fp;
+    }
+
     private final byte mData[];
     private int mPos;
     private int mLen;
diff --git a/rs/java/android/renderscript/Path.java b/rs/java/android/renderscript/Path.java
deleted file mode 100644
index f3502aa..0000000
--- a/rs/java/android/renderscript/Path.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.renderscript;
-
-/**
- * @hide
- *
- */
-public class Path extends BaseObj {
-
-    public enum Primitive {
-        QUADRATIC_BEZIER(0),
-        CUBIC_BEZIER(1);
-
-        int mID;
-        Primitive(int id) {
-            mID = id;
-        }
-    }
-
-    Allocation mVertexBuffer;
-    Allocation mLoopBuffer;
-    Primitive mPrimitive;
-    float mQuality;
-    boolean mCoverageToAlpha;
-
-    Path(long id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) {
-        super(id, rs);
-        mVertexBuffer = vtx;
-        mLoopBuffer = loop;
-        mPrimitive = p;
-        mQuality = q;
-    }
-
-    public Allocation getVertexAllocation() {
-        return mVertexBuffer;
-    }
-
-    public Allocation getLoopAllocation() {
-        return mLoopBuffer;
-    }
-
-    public Primitive getPrimitive() {
-        return mPrimitive;
-    }
-
-    @Override
-    void updateFromNative() {
-    }
-
-
-    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
-        long id = rs.nPathCreate(p.mID, false, vtx.getID(rs), 0, quality);
-        Path newPath = new Path(id, rs, p, null, null, quality);
-        return newPath;
-    }
-
-    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
-        return null;
-    }
-
-    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
-        return null;
-    }
-
-    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
-        return null;
-    }
-
-
-}
-
-
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index e86c461..4bb4eee 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -24,7 +24,6 @@
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.SurfaceTexture;
-import android.os.Process;
 import android.util.Log;
 import android.view.Surface;
 import android.os.SystemProperties;
@@ -302,6 +301,55 @@
         rsnContextResume(mContext);
     }
 
+    native long rsnClosureCreate(long con, long kernelID, long returnValue,
+        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
+        long[] depFieldIDs);
+    synchronized long nClosureCreate(long kernelID, long returnValue,
+        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
+        long[] depFieldIDs) {
+      validate();
+      return rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
+          sizes, depClosures, depFieldIDs);
+    }
+
+    native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes);
+    synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
+        long[] fieldIDs, long[] values, int[] sizes) {
+      validate();
+      return rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
+          values, sizes);
+    }
+
+    native void rsnClosureSetArg(long con, long closureID, int index,
+      long value, int size);
+    synchronized void nClosureSetArg(long closureID, int index, long value,
+        int size) {
+      validate();
+      rsnClosureSetArg(mContext, closureID, index, value, size);
+    }
+
+    native void rsnClosureSetGlobal(long con, long closureID, long fieldID,
+        long value, int size);
+    // Does this have to be synchronized?
+    synchronized void nClosureSetGlobal(long closureID, long fieldID,
+        long value, int size) {
+      validate(); // TODO: is this necessary?
+      rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
+    }
+
+    native long rsnScriptGroup2Create(long con, String cachePath, long[] closures);
+    synchronized long nScriptGroup2Create(String cachePath, long[] closures) {
+      validate();
+      return rsnScriptGroup2Create(mContext, cachePath, closures);
+    }
+
+    native void rsnScriptGroup2Execute(long con, long groupID);
+    synchronized void nScriptGroup2Execute(long groupID) {
+      validate();
+      rsnScriptGroup2Execute(mContext, groupID);
+    }
+
     native void rsnAssignName(long con, long obj, byte[] name);
     synchronized void nAssignName(long obj, byte[] name) {
         validate();
@@ -436,16 +484,18 @@
     }
 
 
-    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt);
-    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt) {
+    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
-    native void rsnAllocationElementData1D(long con,long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementData1D(long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
+    native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationElementData(long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes) {
         validate();
-        rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
+        rsnAllocationElementData(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
     }
 
     native void rsnAllocationData2D(long con,
@@ -469,11 +519,13 @@
     }
 
     native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt);
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
@@ -501,33 +553,56 @@
     }
 
     native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt);
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
+                            dt.mID, mSize, usePadding);
     }
 
-    native void rsnAllocationRead(long con, long id, Object d, int dt);
-    synchronized void nAllocationRead(long id, Object d, Element.DataType dt) {
+    native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
+    synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead(mContext, id, d, dt.mID);
+        rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
     }
 
     native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
-                                    int sizeBytes, int dt);
+                                    int sizeBytes, int dt, int mSize, boolean usePadding);
     synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
-                                        int sizeBytes, Element.DataType dt) {
+                                        int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
+                                         int mip, int compIdx, byte[] d, int sizeBytes);
+    synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
+                                             int mip, int compIdx, byte[] d, int sizeBytes) {
+        validate();
+        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
     }
 
     native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt);
+                                    int w, int h, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
     synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
         validate();
-        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
+    }
+
+    native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
+                                    int mSize, boolean usePadding);
+    synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+                                        int mSize, boolean usePadding) {
+        validate();
+        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
     }
 
     native long  rsnAllocationGetType(long con, long id);
@@ -542,6 +617,20 @@
         rsnAllocationResize1D(mContext, id, dimX);
     }
 
+    native long  rsnAllocationAdapterCreate(long con, long allocId, long typeId);
+    synchronized long nAllocationAdapterCreate(long allocId, long typeId) {
+        validate();
+        return rsnAllocationAdapterCreate(mContext, allocId, typeId);
+    }
+
+    native void  rsnAllocationAdapterOffset(long con, long id, int x, int y, int z,
+                                            int mip, int face, int a1, int a2, int a3, int a4);
+    synchronized void nAllocationAdapterOffset(long id, int x, int y, int z,
+                                               int mip, int face, int a1, int a2, int a3, int a4) {
+        validate();
+        rsnAllocationAdapterOffset(mContext, id, x, y, z, mip, face, a1, a2, a3, a4);
+    }
+
     native long rsnFileA3DCreateFromAssetStream(long con, long assetStream);
     synchronized long nFileA3DCreateFromAssetStream(long assetStream) {
         validate();
@@ -605,52 +694,14 @@
         validate();
         rsnScriptInvoke(mContext, id, slot);
     }
-    native void rsnScriptForEach(long con, long id, int slot, long ain, long aout, byte[] params);
-    native void rsnScriptForEach(long con, long id, int slot, long ain, long aout);
-    native void rsnScriptForEachClipped(long con, long id, int slot, long ain, long aout, byte[] params,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend);
-    native void rsnScriptForEachClipped(long con, long id, int slot, long ain, long aout,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend);
-    synchronized void nScriptForEach(long id, int slot, long ain, long aout, byte[] params) {
+
+    native void rsnScriptForEach(long con, long id, int slot, long[] ains,
+                                 long aout, byte[] params, int[] limits);
+
+    synchronized void nScriptForEach(long id, int slot, long[] ains, long aout,
+                                     byte[] params, int[] limits) {
         validate();
-        if (params == null) {
-            rsnScriptForEach(mContext, id, slot, ain, aout);
-        } else {
-            rsnScriptForEach(mContext, id, slot, ain, aout, params);
-        }
-    }
-
-    synchronized void nScriptForEachClipped(long id, int slot, long ain, long aout, byte[] params,
-                                            int xstart, int xend, int ystart, int yend, int zstart, int zend) {
-        validate();
-        if (params == null) {
-            rsnScriptForEachClipped(mContext, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend);
-        } else {
-            rsnScriptForEachClipped(mContext, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend);
-        }
-    }
-
-    /**
-     * Multi-input code.
-     *
-     */
-
-    // @hide
-    native void rsnScriptForEachMultiClipped(long con, long id, int slot, long[] ains, long aout, byte[] params,
-                                             int xstart, int xend, int ystart, int yend, int zstart, int zend);
-    // @hide
-    native void rsnScriptForEachMultiClipped(long con, long id, int slot, long[] ains, long aout,
-                                             int xstart, int xend, int ystart, int yend, int zstart, int zend);
-
-    // @hide
-    synchronized void nScriptForEachMultiClipped(long id, int slot, long[] ains, long aout, byte[] params,
-                                                 int xstart, int xend, int ystart, int yend, int zstart, int zend) {
-        validate();
-        if (params == null) {
-            rsnScriptForEachMultiClipped(mContext, id, slot, ains, aout, xstart, xend, ystart, yend, zstart, zend);
-        } else {
-            rsnScriptForEachMultiClipped(mContext, id, slot, ains, aout, params, xstart, xend, ystart, yend, zstart, zend);
-        }
+        rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
     }
 
     native void rsnScriptInvokeV(long con, long id, int slot, byte[] params);
@@ -743,6 +794,12 @@
         return rsnScriptKernelIDCreate(mContext, sid, slot, sig);
     }
 
+    native long  rsnScriptInvokeIDCreate(long con, long sid, int slot);
+    synchronized long nScriptInvokeIDCreate(long sid, int slot) {
+        validate();
+        return rsnScriptInvokeIDCreate(mContext, sid, slot);
+    }
+
     native long  rsnScriptFieldIDCreate(long con, long sid, int slot);
     synchronized long nScriptFieldIDCreate(long sid, int slot) {
         validate();
@@ -850,14 +907,59 @@
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
-    native long rsnPathCreate(long con, int prim, boolean isStatic, long vtx, long loop, float q);
-    synchronized long nPathCreate(int prim, boolean isStatic, long vtx, long loop, float q) {
+    native void rsnScriptIntrinsicBLAS_Single(long con, long id, int func, int TransA,
+                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                              float alpha, long A, long B, float beta, long C, int incX, int incY,
+                                              int KL, int KU);
+    synchronized void nScriptIntrinsicBLAS_Single(long id, int func, int TransA,
+                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                  float alpha, long A, long B, float beta, long C, int incX, int incY,
+                                                  int KL, int KU) {
         validate();
-        return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
+        rsnScriptIntrinsicBLAS_Single(mContext, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU);
     }
 
+    native void rsnScriptIntrinsicBLAS_Double(long con, long id, int func, int TransA,
+                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                              double alpha, long A, long B, double beta, long C, int incX, int incY,
+                                              int KL, int KU);
+    synchronized void nScriptIntrinsicBLAS_Double(long id, int func, int TransA,
+                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                  double alpha, long A, long B, double beta, long C, int incX, int incY,
+                                                  int KL, int KU) {
+        validate();
+        rsnScriptIntrinsicBLAS_Double(mContext, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Complex(long con, long id, int func, int TransA,
+                                               int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                               float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
+                                               int KL, int KU);
+    synchronized void nScriptIntrinsicBLAS_Complex(long id, int func, int TransA,
+                                                   int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                                   float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
+                                                   int KL, int KU) {
+        validate();
+        rsnScriptIntrinsicBLAS_Complex(mContext, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU);
+    }
+
+    native void rsnScriptIntrinsicBLAS_Z(long con, long id, int func, int TransA,
+                                         int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                         double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
+                                         int KL, int KU);
+    synchronized void nScriptIntrinsicBLAS_Z(long id, int func, int TransA,
+                                             int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
+                                             double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
+                                             int KL, int KU) {
+        validate();
+        rsnScriptIntrinsicBLAS_Z(mContext, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU);
+    }
+
+
     long     mDev;
     long     mContext;
+    private boolean mDestroyed = false;
+
     @SuppressWarnings({"FieldCanBeLocal"})
     MessageThread mMessageThread;
 
@@ -869,6 +971,7 @@
     Element mElement_I32;
     Element mElement_U64;
     Element mElement_I64;
+    Element mElement_F16;
     Element mElement_F32;
     Element mElement_F64;
     Element mElement_BOOLEAN;
@@ -892,6 +995,10 @@
     Element mElement_RGBA_4444;
     Element mElement_RGBA_8888;
 
+    Element mElement_HALF_2;
+    Element mElement_HALF_3;
+    Element mElement_HALF_4;
+
     Element mElement_FLOAT_2;
     Element mElement_FLOAT_3;
     Element mElement_FLOAT_4;
@@ -1040,8 +1147,10 @@
      * their priority to LOW to avoid starving forground processes.
      */
     public enum Priority {
-        LOW (Process.THREAD_PRIORITY_BACKGROUND + (5 * Process.THREAD_PRIORITY_LESS_FAVORABLE)),
-        NORMAL (Process.THREAD_PRIORITY_DISPLAY);
+        // These values used to represent official thread priority values
+        // now they are simply enums to be used by the runtime side
+        LOW (15),
+        NORMAL (-8);
 
         int mID;
         Priority(int id) {
@@ -1295,6 +1404,38 @@
         nContextFinish();
     }
 
+    private void helpDestroy() {
+        boolean shouldDestroy = false;
+        synchronized(this) {
+            if (!mDestroyed) {
+                shouldDestroy = true;
+                mDestroyed = true;
+            }
+        }
+
+        if (shouldDestroy) {
+            nContextFinish();
+
+            nContextDeinitToClient(mContext);
+            mMessageThread.mRun = false;
+            try {
+                mMessageThread.join();
+            } catch(InterruptedException e) {
+            }
+
+            nContextDestroy();
+
+            nDeviceDestroy(mDev);
+            mDev = 0;
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        helpDestroy();
+        super.finalize();
+    }
+
+
     /**
      * Destroys this RenderScript context.  Once this function is called,
      * using this context or any objects belonging to this context is
@@ -1303,19 +1444,7 @@
      */
     public void destroy() {
         validate();
-        nContextFinish();
-
-        nContextDeinitToClient(mContext);
-        mMessageThread.mRun = false;
-        try {
-            mMessageThread.join();
-        } catch(InterruptedException e) {
-        }
-
-        nContextDestroy();
-
-        nDeviceDestroy(mDev);
-        mDev = 0;
+        helpDestroy();
     }
 
     boolean isAlive() {
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index c49ef94..d352130 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -48,7 +48,8 @@
     /**
      * Only to be used by generated reflected classes.
      */
-    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
+    protected KernelID createKernelID(int slot, int sig, Element ein,
+                                      Element eout) {
         KernelID k = mKIDs.get(slot);
         if (k != null) {
             return k;
@@ -65,6 +66,46 @@
     }
 
     /**
+     * @hide Pending API review
+     * InvokeID is an identifier for an invoke function. It is used
+     * as an identifier for ScriptGroup creation.
+     *
+     * This class should not be directly created. Instead use the method in the
+     * reflected or intrinsic code "getInvokeID_funcname()".
+     *
+     */
+    public static final class InvokeID extends BaseObj {
+        Script mScript;
+        int mSlot;
+        InvokeID(long id, RenderScript rs, Script s, int slot) {
+            super(id, rs);
+            mScript = s;
+            mSlot = slot;
+        }
+    }
+
+    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
+    /**
+     * @hide Pending API review
+     * Only to be used by generated reflected classes.
+     */
+    protected InvokeID createInvokeID(int slot) {
+        InvokeID i = mIIDs.get(slot);
+        if (i != null) {
+            return i;
+        }
+
+        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
+        if (id == 0) {
+            throw new RSDriverException("Failed to create KernelID");
+        }
+
+        i = new InvokeID(id, mRS, this, slot);
+        mIIDs.put(slot, i);
+        return i;
+    }
+
+    /**
      * FieldID is an identifier for a Script + exported field pair. It is used
      * as an identifier for ScriptGroup creation.
      *
@@ -127,59 +168,56 @@
      * Only intended for use by generated reflected code.
      *
      */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
-        mRS.validate();
-        mRS.validateObject(ain);
-        mRS.validateObject(aout);
-        if (ain == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-        long in_id = 0;
-        if (ain != null) {
-            in_id = ain.getID(mRS);
-        }
-        long out_id = 0;
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-        mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params);
+    protected void forEach(int slot, Allocation ain, Allocation aout,
+                           FieldPacker v) {
+        forEach(slot, ain, aout, v, null);
     }
 
     /**
      * Only intended for use by generated reflected code.
      *
      */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
+    protected void forEach(int slot, Allocation ain, Allocation aout,
+                           FieldPacker v, LaunchOptions sc) {
+        // TODO: Is this necessary if nScriptForEach calls validate as well?
         mRS.validate();
         mRS.validateObject(ain);
         mRS.validateObject(aout);
+
         if (ain == null && aout == null) {
             throw new RSIllegalArgumentException(
                 "At least one of ain or aout is required to be non-null.");
         }
 
-        if (sc == null) {
-            forEach(slot, ain, aout, v);
-            return;
-        }
-        long in_id = 0;
+        long[] in_ids = null;
         if (ain != null) {
-            in_id = ain.getID(mRS);
+            in_ids    = mInIdsBuffer;
+            in_ids[0] = ain.getID(mRS);
         }
+
         long out_id = 0;
         if (aout != null) {
             out_id = aout.getID(mRS);
         }
+
         byte[] params = null;
         if (v != null) {
             params = v.getData();
         }
-        mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend);
+
+        int[] limits = null;
+        if (sc != null) {
+            limits = new int[6];
+
+            limits[0] = sc.xstart;
+            limits[1] = sc.xend;
+            limits[2] = sc.ystart;
+            limits[3] = sc.yend;
+            limits[4] = sc.zstart;
+            limits[5] = sc.zend;
+        }
+
+        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
     }
 
     /**
@@ -187,8 +225,9 @@
      *
      * @hide
      */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout, FieldPacker v) {
-        forEach(slot, ains, aout, v, new LaunchOptions());
+    protected void forEach(int slot, Allocation[] ains, Allocation aout,
+                           FieldPacker v) {
+        forEach(slot, ains, aout, v, null);
     }
 
     /**
@@ -196,24 +235,20 @@
      *
      * @hide
      */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout, FieldPacker v, LaunchOptions sc) {
+    protected void forEach(int slot, Allocation[] ains, Allocation aout,
+                           FieldPacker v, LaunchOptions sc) {
+        // TODO: Is this necessary if nScriptForEach calls validate as well?
         mRS.validate();
-
         for (Allocation ain : ains) {
           mRS.validateObject(ain);
         }
-
         mRS.validateObject(aout);
+
         if (ains == null && aout == null) {
             throw new RSIllegalArgumentException(
                 "At least one of ain or aout is required to be non-null.");
         }
 
-        if (sc == null) {
-            forEach(slot, ains, aout, v);
-            return;
-        }
-
         long[] in_ids = new long[ains.length];
         for (int index = 0; index < ains.length; ++index) {
             in_ids[index] = ains[index].getID(mRS);
@@ -223,15 +258,33 @@
         if (aout != null) {
             out_id = aout.getID(mRS);
         }
+
         byte[] params = null;
         if (v != null) {
             params = v.getData();
         }
-        mRS.nScriptForEachMultiClipped(getID(mRS), slot, in_ids, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend);
+
+        int[] limits = null;
+        if (sc != null) {
+            limits = new int[6];
+
+            limits[0] = sc.xstart;
+            limits[1] = sc.xend;
+            limits[2] = sc.ystart;
+            limits[3] = sc.yend;
+            limits[4] = sc.zstart;
+            limits[5] = sc.zend;
+        }
+
+        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
     }
 
+    long[] mInIdsBuffer;
+
     Script(long id, RenderScript rs) {
         super(id, rs);
+
+        mInIdsBuffer = new long[1];
     }
 
 
@@ -243,11 +296,17 @@
         mRS.validate();
         mRS.validateObject(va);
         if (va != null) {
-            if (mRS.getApplicationContext().getApplicationInfo().targetSdkVersion >= 20) {
+
+            android.content.Context context = mRS.getApplicationContext();
+
+            if (context.getApplicationInfo().targetSdkVersion >= 20) {
                 final Type t = va.mType;
-                if (t.hasMipmaps() || t.hasFaces() || (t.getY() != 0) || (t.getZ() != 0)) {
+                if (t.hasMipmaps() || t.hasFaces() || (t.getY() != 0) ||
+                    (t.getZ() != 0)) {
+
                     throw new RSIllegalArgumentException(
-                        "API 20+ only allows simple 1D allocations to be used with bind.");
+                        "API 20+ only allows simple 1D allocations to be " +
+                        "used with bind.");
                 }
             }
             mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot);
@@ -378,11 +437,14 @@
         protected Allocation mAllocation;
 
         protected void init(RenderScript rs, int dimx) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
+            mAllocation = Allocation.createSized(rs, mElement, dimx,
+                                                 Allocation.USAGE_SCRIPT);
         }
 
         protected void init(RenderScript rs, int dimx, int usages) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
+            mAllocation =
+                Allocation.createSized(rs, mElement, dimx,
+                                       Allocation.USAGE_SCRIPT | usages);
         }
 
         protected FieldBase() {
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
new file mode 100644
index 0000000..113b896
--- /dev/null
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -0,0 +1,368 @@
+package android.renderscript;
+
+import android.util.Log;
+import android.util.Pair;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+      errors above.
+
+   2) You can update current.txt by executing the following command:
+         make update-api
+
+To submit the revised current.txt to the main Android repository,
+you will need approval.
+******************************
+
+   @hide Pending Android public API approval.
+ */
+public class ScriptGroup2 extends BaseObj {
+
+  public static class Closure extends BaseObj {
+    private Allocation mReturnValue;
+    private Map<Script.FieldID, Object> mBindings;
+
+    private Future mReturnFuture;
+    private Map<Script.FieldID, Future> mGlobalFuture;
+
+    private FieldPacker mFP;
+
+    private static final String TAG = "Closure";
+
+    public Closure(long id, RenderScript rs) {
+      super(id, rs);
+    }
+
+    public Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
+        Object[] args, Map<Script.FieldID, Object> globals) {
+      super(0, rs);
+
+      mReturnValue = Allocation.createTyped(rs, returnType);
+      mBindings = new HashMap<Script.FieldID, Object>();
+      mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+      int numValues = args.length + globals.size();
+
+      long[] fieldIDs = new long[numValues];
+      long[] values = new long[numValues];
+      int[] sizes = new int[numValues];
+      long[] depClosures = new long[numValues];
+      long[] depFieldIDs = new long[numValues];
+
+      int i;
+      for (i = 0; i < args.length; i++) {
+        Object obj = args[i];
+        fieldIDs[i] = 0;
+        if (obj instanceof UnboundValue) {
+          UnboundValue unbound = (UnboundValue)obj;
+          unbound.addReference(this, i);
+        } else {
+          retrieveValueAndDependenceInfo(rs, i, args[i], values, sizes,
+              depClosures, depFieldIDs);
+        }
+      }
+
+      for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+        Object obj = entry.getValue();
+        Script.FieldID fieldID = entry.getKey();
+        fieldIDs[i] = fieldID.getID(rs);
+        if (obj instanceof UnboundValue) {
+          UnboundValue unbound = (UnboundValue)obj;
+          unbound.addReference(this, fieldID);
+        } else {
+          retrieveValueAndDependenceInfo(rs, i, obj, values,
+              sizes, depClosures, depFieldIDs);
+        }
+        i++;
+      }
+
+      long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs),
+          fieldIDs, values, sizes, depClosures, depFieldIDs);
+
+      setID(id);
+    }
+
+    public Closure(RenderScript rs, Script.InvokeID invokeID,
+        Object[] args, Map<Script.FieldID, Object> globals) {
+      super(0, rs);
+      mFP = FieldPacker.createFieldPack(args);
+
+      mBindings = new HashMap<Script.FieldID, Object>();
+      mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+      int numValues = globals.size();
+
+      long[] fieldIDs = new long[numValues];
+      long[] values = new long[numValues];
+      int[] sizes = new int[numValues];
+      long[] depClosures = new long[numValues];
+      long[] depFieldIDs = new long[numValues];
+
+      int i = 0;
+      for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+        Object obj = entry.getValue();
+        Script.FieldID fieldID = entry.getKey();
+        fieldIDs[i] = fieldID.getID(rs);
+        if (obj instanceof UnboundValue) {
+          UnboundValue unbound = (UnboundValue)obj;
+          unbound.addReference(this, fieldID);
+        } else {
+          // TODO(yangni): Verify obj not a future.
+          retrieveValueAndDependenceInfo(rs, i, obj, values,
+              sizes, depClosures, depFieldIDs);
+        }
+        i++;
+      }
+
+      long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
+          values, sizes);
+
+      setID(id);
+    }
+
+    private static void retrieveValueAndDependenceInfo(RenderScript rs,
+        int index, Object obj, long[] values, int[] sizes, long[] depClosures,
+        long[] depFieldIDs) {
+
+      if (obj instanceof Future) {
+        Future f = (Future)obj;
+        obj = f.getValue();
+        depClosures[index] = f.getClosure().getID(rs);
+        Script.FieldID fieldID = f.getFieldID();
+        depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
+        if (obj == null) {
+          // Value is originally created by the owner closure
+          values[index] = 0;
+          sizes[index] = 0;
+          return;
+        }
+      } else {
+        depClosures[index] = 0;
+        depFieldIDs[index] = 0;
+      }
+
+      ValueAndSize vs = new ValueAndSize(rs, obj);
+      values[index] = vs.value;
+      sizes[index] = vs.size;
+    }
+
+    public Future getReturn() {
+      if (mReturnFuture == null) {
+        mReturnFuture = new Future(this, null, mReturnValue);
+      }
+
+      return mReturnFuture;
+    }
+
+    public Future getGlobal(Script.FieldID field) {
+      Future f = mGlobalFuture.get(field);
+
+      if (f == null) {
+        // If the field is not bound to this closure, this will return a future
+        // without an associated value (reference). So this is not working for
+        // cross-module (cross-script) linking in this case where a field not
+        // explicitly bound.
+        f = new Future(this, field, mBindings.get(field));
+        mGlobalFuture.put(field, f);
+      }
+
+      return f;
+    }
+
+    void setArg(int index, Object obj) {
+      ValueAndSize vs = new ValueAndSize(mRS, obj);
+      mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
+    }
+
+    void setGlobal(Script.FieldID fieldID, Object obj) {
+      ValueAndSize vs = new ValueAndSize(mRS, obj);
+      mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
+    }
+
+    private static final class ValueAndSize {
+      public ValueAndSize(RenderScript rs, Object obj) {
+        if (obj instanceof Allocation) {
+          value = ((Allocation)obj).getID(rs);
+          size = -1;
+        } else if (obj instanceof Boolean) {
+          value = ((Boolean)obj).booleanValue() ? 1 : 0;
+          size = 4;
+        } else if (obj instanceof Integer) {
+          value = ((Integer)obj).longValue();
+          size = 4;
+        } else if (obj instanceof Long) {
+          value = ((Long)obj).longValue();
+          size = 8;
+        } else if (obj instanceof Float) {
+          value = ((Float)obj).longValue();
+          size = 4;
+        } else if (obj instanceof Double) {
+          value = ((Double)obj).longValue();
+          size = 8;
+        }
+      }
+      public long value;
+      public int size;
+    }
+  }
+
+  public static class Future {
+    Closure mClosure;
+    Script.FieldID mFieldID;
+    Object mValue;
+
+    Future(Closure closure, Script.FieldID fieldID, Object value) {
+      mClosure = closure;
+      mFieldID = fieldID;
+      mValue = value;
+    }
+
+    Closure getClosure() { return mClosure; }
+    Script.FieldID getFieldID() { return mFieldID; }
+    Object getValue() { return mValue; }
+  }
+
+  public static class UnboundValue {
+    // Either mFieldID or mArgIndex should be set but not both.
+    List<Pair<Closure, Script.FieldID>> mFieldID;
+    // -1 means unset. Legal values are 0 .. n-1, where n is the number of
+    // arguments for the referencing closure.
+    List<Pair<Closure, Integer>> mArgIndex;
+
+    UnboundValue() {
+      mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
+      mArgIndex = new ArrayList<Pair<Closure, Integer>>();
+    }
+
+    void addReference(Closure closure, int index) {
+      mArgIndex.add(Pair.create(closure, Integer.valueOf(index)));
+    }
+
+    void addReference(Closure closure, Script.FieldID fieldID) {
+      mFieldID.add(Pair.create(closure, fieldID));
+    }
+
+    void set(Object value) {
+      for (Pair<Closure, Integer> p : mArgIndex) {
+        Closure closure = p.first;
+        int index = p.second.intValue();
+        closure.setArg(index, value);
+      }
+      for (Pair<Closure, Script.FieldID> p : mFieldID) {
+        Closure closure = p.first;
+        Script.FieldID fieldID = p.second;
+        closure.setGlobal(fieldID, value);
+      }
+    }
+  }
+
+  List<Closure> mClosures;
+  List<UnboundValue> mInputs;
+  Future[] mOutputs;
+
+  private static final String TAG = "ScriptGroup2";
+
+  public ScriptGroup2(long id, RenderScript rs) {
+    super(id, rs);
+  }
+
+  ScriptGroup2(RenderScript rs, List<Closure> closures,
+      List<UnboundValue> inputs, Future[] outputs) {
+    super(0, rs);
+    mClosures = closures;
+    mInputs = inputs;
+    mOutputs = outputs;
+
+    long[] closureIDs = new long[closures.size()];
+    for (int i = 0; i < closureIDs.length; i++) {
+      closureIDs[i] = closures.get(i).getID(rs);
+    }
+    long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs);
+    setID(id);
+  }
+
+  public Object[] execute(Object... inputs) {
+    if (inputs.length < mInputs.size()) {
+      Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+          "less than expected " + mInputs.size());
+      return null;
+    }
+
+    if (inputs.length > mInputs.size()) {
+      Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+          "more than expected " + mInputs.size());
+    }
+
+    for (int i = 0; i < mInputs.size(); i++) {
+      Object obj = inputs[i];
+      if (obj instanceof Future || obj instanceof UnboundValue) {
+        Log.e(TAG, this.toString() + ": input " + i +
+            " is a future or unbound value");
+        return null;
+      }
+      UnboundValue unbound = mInputs.get(i);
+      unbound.set(obj);
+    }
+
+    mRS.nScriptGroup2Execute(getID(mRS));
+
+    Object[] outputObjs = new Object[mOutputs.length];
+    int i = 0;
+    for (Future f : mOutputs) {
+      outputObjs[i++] = f.getValue();
+    }
+    return outputObjs;
+  }
+
+  /**
+     @hide Pending Android public API approval.
+   */
+  public static final class Builder {
+    RenderScript mRS;
+    List<Closure> mClosures;
+    List<UnboundValue> mInputs;
+
+    private static final String TAG = "ScriptGroup2.Builder";
+
+    public Builder(RenderScript rs) {
+      mRS = rs;
+      mClosures = new ArrayList<Closure>();
+      mInputs = new ArrayList<UnboundValue>();
+    }
+
+    public Closure addKernel(Script.KernelID k, Type returnType, Object[] args,
+        Map<Script.FieldID, Object> globalBindings) {
+      Closure c = new Closure(mRS, k, returnType, args, globalBindings);
+      mClosures.add(c);
+      return c;
+    }
+
+    public Closure addInvoke(Script.InvokeID invoke, Object[] args,
+        Map<Script.FieldID, Object> globalBindings) {
+      Closure c = new Closure(mRS, invoke, args, globalBindings);
+      mClosures.add(c);
+      return c;
+    }
+
+    public UnboundValue addInput() {
+      UnboundValue unbound = new UnboundValue();
+      mInputs.add(unbound);
+      return unbound;
+    }
+
+    public ScriptGroup2 create(Future... outputs) {
+      ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
+      return ret;
+    }
+
+  }
+}
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
new file mode 100644
index 0000000..90d2300
--- /dev/null
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -0,0 +1,1489 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.annotation.IntDef;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ * BLAS
+ *
+ * @hide
+ **/
+public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
+    private Allocation mLUT;
+
+    private ScriptIntrinsicBLAS(long id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    private static final int RsBlas_sdsdot = 1;
+    private static final int RsBlas_dsdot = 2;
+    private static final int RsBlas_sdot = 3;
+    private static final int RsBlas_ddot = 4;
+    private static final int RsBlas_cdotu_sub = 5;
+    private static final int RsBlas_cdotc_sub = 6;
+    private static final int RsBlas_zdotu_sub = 7;
+    private static final int RsBlas_zdotc_sub = 8;
+    private static final int RsBlas_snrm2 = 9;
+    private static final int RsBlas_sasum = 10;
+    private static final int RsBlas_dnrm2 = 11;
+    private static final int RsBlas_dasum = 12;
+    private static final int RsBlas_scnrm2 = 13;
+    private static final int RsBlas_scasum = 14;
+    private static final int RsBlas_dznrm2 = 15;
+    private static final int RsBlas_dzasum = 16;
+    private static final int RsBlas_isamax = 17;
+    private static final int RsBlas_idamax = 18;
+    private static final int RsBlas_icamax = 19;
+    private static final int RsBlas_izamax = 20;
+    private static final int RsBlas_sswap = 21;
+    private static final int RsBlas_scopy = 22;
+    private static final int RsBlas_saxpy = 23;
+    private static final int RsBlas_dswap = 24;
+    private static final int RsBlas_dcopy = 25;
+    private static final int RsBlas_daxpy = 26;
+    private static final int RsBlas_cswap = 27;
+    private static final int RsBlas_ccopy = 28;
+    private static final int RsBlas_caxpy = 29;
+    private static final int RsBlas_zswap = 30;
+    private static final int RsBlas_zcopy = 31;
+    private static final int RsBlas_zaxpy = 32;
+    private static final int RsBlas_srotg = 33;
+    private static final int RsBlas_srotmg = 34;
+    private static final int RsBlas_srot = 35;
+    private static final int RsBlas_srotm = 36;
+    private static final int RsBlas_drotg = 37;
+    private static final int RsBlas_drotmg = 38;
+    private static final int RsBlas_drot = 39;
+    private static final int RsBlas_drotm = 40;
+    private static final int RsBlas_sscal = 41;
+    private static final int RsBlas_dscal = 42;
+    private static final int RsBlas_cscal = 43;
+    private static final int RsBlas_zscal = 44;
+    private static final int RsBlas_csscal = 45;
+    private static final int RsBlas_zdscal = 46;
+    private static final int RsBlas_sgemv = 47;
+    private static final int RsBlas_sgbmv = 48;
+    private static final int RsBlas_strmv = 49;
+    private static final int RsBlas_stbmv = 50;
+    private static final int RsBlas_stpmv = 51;
+    private static final int RsBlas_strsv = 52;
+    private static final int RsBlas_stbsv = 53;
+    private static final int RsBlas_stpsv = 54;
+    private static final int RsBlas_dgemv = 55;
+    private static final int RsBlas_dgbmv = 56;
+    private static final int RsBlas_dtrmv = 57;
+    private static final int RsBlas_dtbmv = 58;
+    private static final int RsBlas_dtpmv = 59;
+    private static final int RsBlas_dtrsv = 60;
+    private static final int RsBlas_dtbsv = 61;
+    private static final int RsBlas_dtpsv = 62;
+    private static final int RsBlas_cgemv = 63;
+    private static final int RsBlas_cgbmv = 64;
+    private static final int RsBlas_ctrmv = 65;
+    private static final int RsBlas_ctbmv = 66;
+    private static final int RsBlas_ctpmv = 67;
+    private static final int RsBlas_ctrsv = 68;
+    private static final int RsBlas_ctbsv = 69;
+    private static final int RsBlas_ctpsv = 70;
+    private static final int RsBlas_zgemv = 71;
+    private static final int RsBlas_zgbmv = 72;
+    private static final int RsBlas_ztrmv = 73;
+    private static final int RsBlas_ztbmv = 74;
+    private static final int RsBlas_ztpmv = 75;
+    private static final int RsBlas_ztrsv = 76;
+    private static final int RsBlas_ztbsv = 77;
+    private static final int RsBlas_ztpsv = 78;
+    private static final int RsBlas_ssymv = 79;
+    private static final int RsBlas_ssbmv = 80;
+    private static final int RsBlas_sspmv = 81;
+    private static final int RsBlas_sger = 82;
+    private static final int RsBlas_ssyr = 83;
+    private static final int RsBlas_sspr = 84;
+    private static final int RsBlas_ssyr2 = 85;
+    private static final int RsBlas_sspr2 = 86;
+    private static final int RsBlas_dsymv = 87;
+    private static final int RsBlas_dsbmv = 88;
+    private static final int RsBlas_dspmv = 89;
+    private static final int RsBlas_dger = 90;
+    private static final int RsBlas_dsyr = 91;
+    private static final int RsBlas_dspr = 92;
+    private static final int RsBlas_dsyr2 = 93;
+    private static final int RsBlas_dspr2 = 94;
+    private static final int RsBlas_chemv = 95;
+    private static final int RsBlas_chbmv = 96;
+    private static final int RsBlas_chpmv = 97;
+    private static final int RsBlas_cgeru = 98;
+    private static final int RsBlas_cgerc = 99;
+    private static final int RsBlas_cher = 100;
+    private static final int RsBlas_chpr = 101;
+    private static final int RsBlas_cher2 = 102;
+    private static final int RsBlas_chpr2 = 103;
+    private static final int RsBlas_zhemv = 104;
+    private static final int RsBlas_zhbmv = 105;
+    private static final int RsBlas_zhpmv = 106;
+    private static final int RsBlas_zgeru = 107;
+    private static final int RsBlas_zgerc = 108;
+    private static final int RsBlas_zher = 109;
+    private static final int RsBlas_zhpr = 110;
+    private static final int RsBlas_zher2 = 111;
+    private static final int RsBlas_zhpr2 = 112;
+    private static final int RsBlas_sgemm = 113;
+    private static final int RsBlas_ssymm = 114;
+    private static final int RsBlas_ssyrk = 115;
+    private static final int RsBlas_ssyr2k = 116;
+    private static final int RsBlas_strmm = 117;
+    private static final int RsBlas_strsm = 118;
+    private static final int RsBlas_dgemm = 119;
+    private static final int RsBlas_dsymm = 120;
+    private static final int RsBlas_dsyrk = 121;
+    private static final int RsBlas_dsyr2k = 122;
+    private static final int RsBlas_dtrmm = 123;
+    private static final int RsBlas_dtrsm = 124;
+    private static final int RsBlas_cgemm = 125;
+    private static final int RsBlas_csymm = 126;
+    private static final int RsBlas_csyrk = 127;
+    private static final int RsBlas_csyr2k = 128;
+    private static final int RsBlas_ctrmm = 129;
+    private static final int RsBlas_ctrsm = 130;
+    private static final int RsBlas_zgemm = 131;
+    private static final int RsBlas_zsymm = 132;
+    private static final int RsBlas_zsyrk = 133;
+    private static final int RsBlas_zsyr2k = 134;
+    private static final int RsBlas_ztrmm = 135;
+    private static final int RsBlas_ztrsm = 136;
+    private static final int RsBlas_chemm = 137;
+    private static final int RsBlas_cherk = 138;
+    private static final int RsBlas_cher2k = 139;
+    private static final int RsBlas_zhemm = 140;
+    private static final int RsBlas_zherk = 141;
+    private static final int RsBlas_zher2k = 142;
+
+    /**
+     */
+    public static ScriptIntrinsicBLAS create(RenderScript rs) {
+        long id = rs.nScriptIntrinsicCreate(13, Element.U32(rs).getID(rs));
+        return new ScriptIntrinsicBLAS(id, rs);
+    }
+
+    @IntDef({NO_TRANSPOSE, TRANSPOSE, CONJ_TRANSPOSE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Transpose {}
+
+    @IntDef({UPPER, LOWER})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Uplo {}
+
+    @IntDef({NON_UNIT, UNIT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Diag {}
+
+    @IntDef({LEFT, RIGHT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Side {}
+
+    public static final int NO_TRANSPOSE = 111;
+    public static final int TRANSPOSE = 112;
+    public static final int CONJ_TRANSPOSE = 113;
+
+    public static final int UPPER = 121;
+    public static final int LOWER = 122;
+
+    public static final int NON_UNIT = 131;
+    public static final int UNIT = 132;
+
+    public static final int LEFT = 141;
+    public static final int RIGHT = 142;
+
+    static void validateSide(@Side int Side) {
+        if (Side != LEFT && Side != RIGHT) {
+            throw new RSRuntimeException("Invalid side passed to BLAS");
+        }
+    }
+
+    static void validateTranspose(@Transpose int Trans) {
+        if (Trans != NO_TRANSPOSE && Trans != TRANSPOSE &&
+            Trans != CONJ_TRANSPOSE) {
+            throw new RSRuntimeException("Invalid transpose passed to BLAS");
+        }
+    }
+
+    static void validateConjTranspose(@Transpose int Trans) {
+        if (Trans != NO_TRANSPOSE &&
+            Trans != CONJ_TRANSPOSE) {
+            throw new RSRuntimeException("Invalid transpose passed to BLAS");
+        }
+    }
+
+    static void validateDiag(@Diag int Diag) {
+        if (Diag != NON_UNIT && Diag != UNIT) {
+            throw new RSRuntimeException("Invalid diag passed to BLAS");
+        }
+    }
+
+    static void validateUplo(@Uplo int Uplo) {
+        if (Uplo != LEFT && Uplo != RIGHT) {
+            throw new RSRuntimeException("Invalid uplo passed to BLAS");
+        }
+    }
+
+
+    /**
+     * Level 2 BLAS
+     */
+
+    static void validateGEMV(Element e, int TransA, Allocation A, Allocation X, int incX, Allocation Y, int incY) {
+        validateTranspose(TransA);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = -1, expectedYDim = -1;
+        if (TransA == NO_TRANSPOSE) {
+            expectedXDim = 1 + (N - 1) * incX;
+            expectedYDim = 1 + (M - 1) * incY;
+        } else {
+            expectedXDim = 1 + (M - 1) * incX;
+            expectedYDim = 1 + (N - 1) * incY;
+        }
+        if (X.getType().getX() != expectedXDim ||
+            Y.getType().getY() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GEMV");
+        }
+    }
+    void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+
+    void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, KL, KU);
+    }
+    void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, KL, KU);
+    }
+    void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, KL, KU);
+    }
+    void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
+        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
+        if (KL < 0 || KU < 0) {
+            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
+        }
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, KL, KU);
+    }
+
+    static void validateTRMV(Element e, @Transpose int TransA, Allocation A, Allocation X, int incX) {
+        validateTranspose(TransA);
+        int N = A.getType().getY();
+        if (A.getType().getX() != N) {
+            throw new RSRuntimeException("A must be a square matrix for TRMV");
+        }
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for TRMV");
+        }
+    }
+
+    static int validateTPMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation Ap, Allocation X, int incX) {
+        validateTranspose(TransA);
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+        }
+
+        return N;
+    }
+
+    void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
+        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV
+        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV
+        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV
+        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBMV has the same requirements as TRMV
+        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+
+    }
+    void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+
+    }
+    void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+
+    }
+    void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
+        // TRSV is the same as TRMV
+        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+
+    }
+    void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV
+        validateTRMV(Element.F32(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV
+        validateTRMV(Element.F64(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, A.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV
+        validateTRMV(Element.F32_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
+        // TBSV is the same as TRMV
+        validateTRMV(Element.F64_2(mRS), TransA, A, X, incX);
+        int N = A.getType().getY();
+        if (K < 0) {
+            throw new RSRuntimeException("Number of diagonals must be positive");
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, A.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, incX, 0, 0, 0);
+    }
+    void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+    void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
+        // TPSV is same as TPMV
+        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, Ap.getID(mRS), X.getID(mRS), 0, 0, 0, incX, 0, 0, 0);
+    }
+
+    /**
+     * Level 2, S and D only
+     */
+    static int validateSYMV(Element e, @Uplo int Uplo, Allocation A, Allocation X, Allocation Y, int incX, int incY) {
+        validateUplo(Uplo);
+        int N = A.getType().getY();
+        if (A.getType().getX() != N) {
+            throw new RSRuntimeException("A must be a square matrix for SYMV");
+        }
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e) ) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (incX <= 0 || incY <= 0) {
+            throw new RSRuntimeException("Vector increments must be greater than 0");
+        }
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
+        }
+        return N;
+    }
+    static int validateSPMV(Element e, @Uplo int Uplo, Allocation Ap, Allocation X, int incX, Allocation Y, int incY) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+
+        return N;
+    }
+    static void validateGER(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e) ) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        if (N < 1 || M < 1) {
+            throw new RSRuntimeException("M and N must be 1 or greater for GER");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GER");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GER");
+        }
+
+
+    }
+    static int validateSYR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation A) {
+        validateUplo(Uplo);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        int N = A.getType().getX();
+
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+        if (N != A.getType().getY()) {
+            throw new RSRuntimeException("A must be a symmetric matrix");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
+        }
+        return N;
+    }
+    static int validateSPR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Ap) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+
+        return N;
+    }
+
+    static int validateSYR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateUplo(Uplo);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int N = A.getType().getX();
+
+        if (N != A.getType().getY()) {
+            throw new RSRuntimeException("A must be a symmetric matrix");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
+        }
+        return N;
+
+    }
+    static int validateSPR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        validateUplo(Uplo);
+        if (!Ap.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        if (Ap.getType().getY() > 1) {
+            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
+        }
+
+        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
+        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
+            throw new RSRuntimeException("Invalid dimension for Ap");
+        }
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
+        }
+
+        return N;
+    }
+
+    void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV
+        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
+        int N = validateSPMV(Element.F32(mRS), Uplo, Ap, X, incX, Y, incY);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, Ap.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sger, 0, 0, 0, 0, 0, M, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0.f, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), A.getID(mRS), 0.f, 0, incX, 0, 0, 0);
+    }
+    void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+        int N = validateSPR(Element.F32(mRS), Uplo, X, incX, Ap);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Ap.getID(mRS), 0.f, 0, incX, 0, 0, 0);
+    }
+    void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int N = validateSYR2(Element.F32(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        int N = validateSPR2(Element.F32(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, Ap.getID(mRS), incX, incY, 0, 0);
+    }
+    void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        // SBMV is the same as SYMV
+        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, A.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
+        int N = validateSPMV(Element.F64(mRS), Uplo, Ap, X, incX, Y, incY);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, Ap.getID(mRS), X.getID(mRS), beta, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dger, 0, 0, 0, 0, 0, M, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0.f, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), A.getID(mRS), 0.f, 0, incX, 0, 0, 0);
+    }
+    void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+        int N = validateSPR(Element.F64(mRS), Uplo, X, incX, Ap);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Ap.getID(mRS), 0.f, 0, incX, 0, 0, 0);
+    }
+    void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        int N = validateSYR2(Element.F64(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        int N = validateSPR2(Element.F64(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, X.getID(mRS), Y.getID(mRS), 0, Ap.getID(mRS), incX, incY, 0, 0);
+    }
+
+
+    /**
+     * Level 2, C and Z only
+     */
+
+    static void validateGERU(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !X.getType().getElement().isCompatible(e) ||
+            !Y.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
+            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
+        }
+
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+
+        int expectedXDim = 1 + (N - 1) * incX;
+        if (X.getType().getX() != expectedXDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
+        }
+        int expectedYDim = 1 + (N - 1) * incY;
+        if (Y.getType().getX() != expectedYDim) {
+            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
+        }
+
+    }
+
+    void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HEMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HBMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+        if (K < 0) {
+            throw new RSRuntimeException("K must be 0 or greater for HBMV");
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
+        // HPMV is the same as SPR2
+        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, Ap.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as GERU
+        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
+        // same as SYR
+        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, A.getID(mRS), incX, 0, 0, 0);
+    }
+    void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
+        // equivalent to SPR for validation
+        int N = validateSPR(Element.F32_2(mRS), Uplo, X, incX, Ap);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, Ap.getID(mRS), incX, 0, 0, 0);
+    }
+    void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as SYR2
+        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        // same as SPR2
+        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, Ap.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HEMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HBMV is the same as SYR2 validation-wise
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+        if (K < 0) {
+            throw new RSRuntimeException("K must be 0 or greater for HBMV");
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, A.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
+        // HPMV is the same as SPR2
+        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, Ap.getID(mRS), X.getID(mRS), beta.x, beta.y, Y.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as GERU
+        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
+        int M = A.getType().getY();
+        int N = A.getType().getX();
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
+        // same as SYR
+        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, A.getID(mRS), incX, 0, 0, 0);
+    }
+    void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
+        // equivalent to SPR for validation
+        int N = validateSPR(Element.F64_2(mRS), Uplo, X, incX, Ap);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, X.getID(mRS), 0, 0, 0, Ap.getID(mRS), incX, 0, 0, 0);
+    }
+    void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
+        // same as SYR2
+        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, A.getID(mRS), incX, incY, 0, 0);
+    }
+    void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
+        // same as SPR2
+        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, X.getID(mRS), Y.getID(mRS), 0, 0, Ap.getID(mRS), incX, incY, 0, 0);
+    }
+
+
+    /**
+     * Level 3 BLAS
+     */
+
+    static void validateL3(Element e, int TransA, int TransB, int Side, Allocation A, Allocation B, Allocation C) {
+        int aX = -1, aY = -1, bX = -1, bY = -1, cX = -1, cY = -1;
+        if ((A != null && !A.getType().getElement().isCompatible(e)) ||
+            (B != null && !B.getType().getElement().isCompatible(e)) ||
+            (C != null && !C.getType().getElement().isCompatible(e))) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (C != null) {
+            cX = C.getType().getY();
+            cY = C.getType().getX();
+        }
+        if (Side == RIGHT) {
+            if (B != null) {
+                bX = A.getType().getY();
+                bY = A.getType().getX();
+            }
+            if (A != null) {
+                aX = B.getType().getY();
+                aY = B.getType().getX();
+            }
+        } else {
+            if (A != null) {
+                if (TransA == TRANSPOSE) {
+                    aY = A.getType().getY();
+                    aX = A.getType().getX();
+                } else {
+                    aX = A.getType().getY();
+                    aY = A.getType().getX();
+                }
+            }
+            if (B != null) {
+                if (TransB == TRANSPOSE) {
+                    bY = B.getType().getY();
+                    bX = B.getType().getX();
+                } else {
+                    bX = B.getType().getY();
+                    bY = B.getType().getX();
+                }
+            }
+        }
+        if (A != null && B != null && C != null) {
+            if (aY != bX || aX != cX || bY != cY) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
+        } else if (A != null && C != null) {
+            // A and C only
+            if (aX != cY || aY != cX) {
+                throw new RSRuntimeException("Called BLAS with invalid dimensions");
+            }
+        } else if (A != null && B != null) {
+            // A and B only
+        }
+
+    }
+
+    public void SGEMM(@Transpose int TransA, @Transpose int TransB, float alpha, Allocation A,
+                      Allocation B, float beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F32(mRS), TransA, TransB, 0, A, B, C);
+
+        int M = -1, N = -1, K = -1;
+        if (TransA == TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB == TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, A.getID(mRS), B.getID(mRS),
+                                        beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void DGEMM(@Transpose int TransA, @Transpose int TransB, double alpha, Allocation A,
+                      Allocation B, double beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F64(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA == TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB == TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, A.getID(mRS), B.getID(mRS),
+                                        beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void CGEMM(@Transpose int TransA, @Transpose int TransB, Float2 alpha, Allocation A,
+                      Allocation B, Float2 beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F32_2(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA == TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB == TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
+                                         beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    public void ZGEMM(@Transpose int TransA, @Transpose int TransB, Double2 alpha, Allocation A,
+                      Allocation B, Double2 beta, Allocation C) {
+        validateTranspose(TransA);
+        validateTranspose(TransB);
+        validateL3(Element.F64_2(mRS), TransA, TransB, 0, A, B, C);
+        int M = -1, N = -1, K = -1;
+        if (TransA == TRANSPOSE) {
+            M = A.getType().getX();
+            K = A.getType().getY();
+        } else {
+            M = A.getType().getY();
+            K = A.getType().getX();
+        }
+        if (TransB == TRANSPOSE) {
+            N = B.getType().getY();
+        } else {
+            N = B.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
+                                   beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    public void SSYMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A,
+                      Allocation B, float beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        validateL3(Element.F32(mRS), 0, 0, Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, A.getID(mRS), B.getID(mRS),
+                                        beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void DSYMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A,
+                      Allocation B, double beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        validateL3(Element.F64(mRS), 0, 0, Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, A.getID(mRS), B.getID(mRS),
+                                        beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void CSYMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A,
+                      Allocation B, Float2 beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        validateL3(Element.F32_2(mRS), 0, 0, Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
+                                         beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZSYMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A,
+                      Allocation B, Double2 beta, Allocation C) {
+        validateSide(Side);
+        validateUplo(Uplo);
+        validateL3(Element.F64_2(mRS), 0, 0, Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS),
+                                   beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    public void SSYRK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F32(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), 0, beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    public void DSYRK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F64(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), 0, beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, float alphaX, float alphaY, Allocation A, float betaX, float betaY, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F32_2(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alphaX, alphaY, A.getID(mRS), 0, betaX, betaY,
+                                         C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, double alphaX, double alphaY, Allocation A, double betaX, double betaY, Allocation C) {
+        validateTranspose(Trans);
+        validateUplo(Uplo);
+        validateL3(Element.F64_2(mRS), Trans, 0, 0, A, null, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alphaX, alphaY, A.getID(mRS), 0, betaX, betaY,
+                                   C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    static void validateSYR2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
+        validateTranspose(Trans);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        int Cdim = -1;
+        // A is n x k if no transpose, k x n if transpose
+        // C is n x n
+        if (Trans == TRANSPOSE) {
+            // check columns versus C
+            Cdim = A.getType().getX();
+        } else {
+            // check rows versus C
+            Cdim = A.getType().getY();
+        }
+        if (C.getType().getX() != Cdim && C.getType().getY() != Cdim) {
+            throw new RSRuntimeException("Invalid symmetric matrix in SYR2K");
+        }
+        // A dims == B dims
+        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
+            throw new RSRuntimeException("Invalid A and B in SYR2K");
+        }
+    }
+    public void SSYR2K(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F32(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void DSYR2K(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F64(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F32_2(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
+        validateUplo(Uplo);
+        validateSYR2K(Element.F64_2(mRS), Trans, A, B, C);
+        int K = -1;
+        if (Trans == TRANSPOSE) {
+            K = A.getType().getY();
+        } else {
+            K = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
+        validateSide(Side);
+        validateTranspose(TransA);
+        int aX = -1, aY = -1, bX = -1, bY = -1;
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        if (TransA == TRANSPOSE) {
+            aY = A.getType().getY();
+            aX = A.getType().getX();
+        } else {
+            aY = A.getType().getX();
+            aX = A.getType().getY();
+        }
+        bX = B.getType().getY();
+        bY = B.getType().getX();
+        if (Side == LEFT) {
+            if (aX == 0 || aY != bX) {
+                throw new RSRuntimeException("Called TRMM with invalid matrices");
+            }
+        } else {
+            if (bY != aX || aY == 0) {
+                throw new RSRuntimeException("Called TRMM with invalid matrices");
+            }
+        }
+    }
+    public void STRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F32(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, A.getID(mRS), B.getID(mRS), 0.f, 0, 0, 0, 0, 0);
+    }
+    public void DTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F64(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, A.getID(mRS), B.getID(mRS), 0.f, 0, 0, 0, 0, 0);
+    }
+    public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                         alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
+    }
+    public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                   alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
+    }
+
+    static void validateTRSM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
+        int adim = -1, bX = -1, bY = -1;
+        validateSide(Side);
+        validateTranspose(TransA);
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        adim = A.getType().getX();
+        if (adim != A.getType().getY()) {
+            // this may be unnecessary, the restriction could potentially be relaxed
+            // A needs to contain at least that symmetric matrix but could theoretically be larger
+            // for now we assume adapters are sufficient, will reevaluate in the future
+            throw new RSRuntimeException("Called TRSM with a non-symmetric matrix A");
+        }
+        bX = B.getType().getY();
+        bY = B.getType().getX();
+        if (Side == LEFT) {
+            // A is M*M
+            if (adim != bY) {
+                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
+            }
+        } else {
+            // A is N*N
+            if (adim != bX) {
+                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
+            }
+        }
+    }
+    public void STRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F32(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
+    }
+    public void DTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F64(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                        alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
+    }
+    public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                         alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
+    }
+    public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
+        validateUplo(Uplo);
+        validateDiag(Diag);
+        validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+                                   alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
+    }
+
+    static void validateHEMM(Element e, @Side int Side, Allocation A, Allocation B, Allocation C) {
+        validateSide(Side);
+
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+
+        // A must be square; can potentially be relaxed similar to TRSM
+        int adim = A.getType().getX();
+        if (adim != A.getType().getY()) {
+            throw new RSRuntimeException("Called HEMM with non-square A");
+        }
+        if ((Side == LEFT && adim != B.getType().getY()) ||
+            (Side == RIGHT && adim != B.getType().getX())) {
+            throw new RSRuntimeException("Called HEMM with invalid B");
+        }
+        if (B.getType().getX() != C.getType().getX() ||
+            B.getType().getY() != C.getType().getY()) {
+            throw new RSRuntimeException("Called HEMM with mismatched B and C");
+        }
+    }
+    public void CHEMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
+                                         alpha, 0, A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZHEMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
+                                   alpha, 0, A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    static void validateHERK(Element e, @Transpose int Trans, Allocation A, Allocation C) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        validateConjTranspose(Trans);
+        int cdim = C.getType().getX();
+        if (cdim != C.getType().getY()) {
+            throw new RSRuntimeException("Called HERK with non-square C");
+        }
+        if (Trans == NO_TRANSPOSE) {
+            if (cdim != A.getType().getX()) {
+                throw new RSRuntimeException("Called HERK with invalid A");
+            }
+        } else {
+            if (cdim != A.getType().getY()) {
+                throw new RSRuntimeException("Called HERK with invalid A");
+            }
+        }
+    }
+    public void CHERK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHERK(Element.F32_2(mRS), Trans, A, C);
+        int k = 0;
+        if (Trans == TRANSPOSE) {
+            k = A.getType().getY();
+        } else {
+            k = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
+                                         alpha, 0, A.getID(mRS), 0, beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZHERK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHERK(Element.F64_2(mRS), Trans, A, C);
+        int k = 0;
+        if (Trans == TRANSPOSE) {
+            k = A.getType().getY();
+        } else {
+            k = A.getType().getX();
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
+                                   alpha, 0, A.getID(mRS), 0, beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+    static void validateHER2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
+        if (!A.getType().getElement().isCompatible(e) ||
+            !B.getType().getElement().isCompatible(e) ||
+            !C.getType().getElement().isCompatible(e)) {
+            throw new RSRuntimeException("Called BLAS with wrong Element type");
+        }
+        validateConjTranspose(Trans);
+        int cdim = C.getType().getX();
+        if (cdim != C.getType().getY()) {
+            throw new RSRuntimeException("Called HER2K with non-square C");
+        }
+        if (Trans == NO_TRANSPOSE) {
+            if (A.getType().getY() != cdim) {
+                throw new RSRuntimeException("Called HER2K with invalid matrices");
+            }
+        } else {
+            if (A.getType().getX() != cdim) {
+                throw new RSRuntimeException("Called HER2K with invalid matrices");
+            }
+        }
+        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
+            throw new RSRuntimeException("Called HER2K with invalid A and B matrices");
+        }
+    }
+    public void CHER2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, float beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHER2K(Element.F32_2(mRS), Trans, A, B, C);
+        int k = 0;
+        if (Trans == NO_TRANSPOSE) {
+            k = A.getType().getX();
+        } else {
+            k = A.getType().getY();
+        }
+        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
+                                         A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+    public void ZHER2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, double beta, Allocation C) {
+        validateUplo(Uplo);
+        validateHER2K(Element.F64_2(mRS), Trans, A, B, C);
+        int k = 0;
+        if (Trans == NO_TRANSPOSE) {
+            k = A.getType().getX();
+        } else {
+            k = A.getType().getY();
+        }
+        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
+                                   A.getID(mRS), B.getID(mRS), beta, 0, C.getID(mRS), 0, 0, 0, 0);
+    }
+
+
+
+}
diff --git a/rs/java/android/renderscript/ScriptIntrinsicResize.java b/rs/java/android/renderscript/ScriptIntrinsicResize.java
index d6764cc..cee4c33 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicResize.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicResize.java
@@ -29,6 +29,8 @@
     /**
      * Supported elements types are {@link Element#U8}, {@link
      * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}
+     * {@link Element#F32}, {@link Element#F32_2}, {@link
+     * Element#F32_3}, {@link Element#F32_4}
      *
      * @param rs The RenderScript context
      *
@@ -52,7 +54,11 @@
         if (!e.isCompatible(Element.U8(mRS)) &&
             !e.isCompatible(Element.U8_2(mRS)) &&
             !e.isCompatible(Element.U8_3(mRS)) &&
-            !e.isCompatible(Element.U8_4(mRS))) {
+            !e.isCompatible(Element.U8_4(mRS)) &&
+            !e.isCompatible(Element.F32(mRS)) &&
+            !e.isCompatible(Element.F32_2(mRS)) &&
+            !e.isCompatible(Element.F32_3(mRS)) &&
+            !e.isCompatible(Element.F32_4(mRS))) {
             throw new RSIllegalArgumentException("Unsuported element type.");
         }
 
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index 98aeaa9..a58e42c 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -52,6 +52,9 @@
     int mDimYuv;
     int mElementCount;
     Element mElement;
+    int mArrays[];
+
+    static final int mMaxArrays = 4;
 
     public enum CubemapFace {
         POSITIVE_X (0),
@@ -146,6 +149,30 @@
         return mElementCount;
     }
 
+    /**
+     * @hide
+     */
+    public int getArray(int dim) {
+        if ((dim < 0) || (dim >= mMaxArrays)) {
+            throw new RSIllegalArgumentException("Array dimension out of range.");
+        }
+
+        if (mArrays == null || dim >= mArrays.length) {
+            // Dimension in range but no array for that dimension allocated
+            return 0;
+        }
+
+        return mArrays[dim];
+    }
+
+    /**
+     * @hide
+     */
+    public int getArrayCount() {
+        if (mArrays != null) return mArrays.length;
+        return 0;
+    }
+
     void calcElementCount() {
         boolean hasLod = hasMipmaps();
         int x = getX();
@@ -180,6 +207,13 @@
 
             count += x * y * z * faces;
         }
+
+        if (mArrays != null) {
+            for (int ct = 0; ct < mArrays.length; ct++) {
+                count *= mArrays[ct];
+            }
+        }
+
         mElementCount = count;
     }
 
@@ -296,6 +330,7 @@
         boolean mDimMipmaps;
         boolean mDimFaces;
         int mYuv;
+        int[] mArray = new int[mMaxArrays];
 
         Element mElement;
 
@@ -341,6 +376,22 @@
             return this;
         }
 
+        /**
+         * @hide
+         *
+         * @param dim
+         * @param value
+         *
+         * @return Builder
+         */
+        public Builder setArray(int dim, int value) {
+            if(dim < 0 || dim >= mMaxArrays) {
+                throw new RSIllegalArgumentException("Array dimension out of range.");
+            }
+            mArray[dim] = value;
+            return this;
+        }
+
         public Builder setMipmaps(boolean value) {
             mDimMipmaps = value;
             return this;
@@ -405,6 +456,16 @@
                 }
             }
 
+            int[] arrays = null;
+            for (int ct = mMaxArrays - 1; ct >= 0; ct--) {
+                if (mArray[ct] != 0 && arrays == null) {
+                    arrays = new int[ct];
+                }
+                if ((mArray[ct] == 0) && (arrays != null)) {
+                    throw new RSInvalidStateException("Array dimensions must be contigous from 0.");
+                }
+            }
+
             long id = mRS.nTypeCreate(mElement.getID(mRS),
                                      mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
             Type t = new Type(id, mRS);
@@ -415,6 +476,7 @@
             t.mDimMipmaps = mDimMipmaps;
             t.mDimFaces = mDimFaces;
             t.mDimYuv = mYuv;
+            t.mArrays = arrays;
 
             t.calcElementCount();
             return t;
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index f1ddc07..94f0859 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -5,27 +5,30 @@
     android_renderscript_RenderScript.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-        libandroid_runtime \
-        libandroidfw \
-        libnativehelper \
-        libRS \
-        libcutils \
-        liblog \
-        libskia \
-        libutils \
-        libui \
-        libgui
+    libandroid_runtime \
+    libandroidfw \
+    libnativehelper \
+    libRS \
+    libcutils \
+    liblog \
+    libskia \
+    libutils \
+    libui \
+    libgui \
+    libjnigraphics
 
 LOCAL_STATIC_LIBRARIES :=
 
 rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
 
 LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	frameworks/rs \
-	$(rs_generated_include_dir)
+    $(JNI_H_INCLUDE) \
+    frameworks/rs \
+    frameworks/base/core/jni \
+    $(rs_generated_include_dir)
 
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
 LOCAL_MODULE:= librs_jni
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 5f5b65e..59161e7 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -22,8 +22,7 @@
 #include <unistd.h>
 #include <math.h>
 #include <utils/misc.h>
-
-#include <SkBitmap.h>
+#include <inttypes.h>
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetManager.h>
@@ -34,6 +33,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
 #include "android_runtime/android_util_AssetManager.h"
+#include "android/graphics/GraphicsJNI.h"
 
 #include <rs.h>
 #include <rsEnv.h>
@@ -43,17 +43,22 @@
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
 //#define LOG_API ALOGE
-#define LOG_API(...)
+static constexpr bool kLogApi = false;
 
 using namespace android;
 
+template <typename... T>
+void UNUSED(T... t) {}
+
 #define PER_ARRAY_TYPE(flag, fnc, readonly, ...) {                                      \
     jint len = 0;                                                                       \
-    void *ptr = NULL;                                                                   \
+    void *ptr = nullptr;                                                                \
+    void *srcPtr = nullptr;                                                             \
     size_t typeBytes = 0;                                                               \
     jint relFlag = 0;                                                                   \
     if (readonly) {                                                                     \
         /* The on-release mode should only be JNI_ABORT for read-only accesses. */      \
+        /* readonly = true, also indicates we are copying to the allocation   . */      \
         relFlag = JNI_ABORT;                                                            \
     }                                                                                   \
     switch(dataType) {                                                                  \
@@ -61,14 +66,50 @@
         len = _env->GetArrayLength((jfloatArray)data);                                  \
         ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
         typeBytes = 4;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag);     \
         return;                                                                         \
     case RS_TYPE_FLOAT_64:                                                              \
         len = _env->GetArrayLength((jdoubleArray)data);                                 \
         ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
         typeBytes = 8;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag);  \
         return;                                                                         \
     case RS_TYPE_SIGNED_8:                                                              \
@@ -76,7 +117,25 @@
         len = _env->GetArrayLength((jbyteArray)data);                                   \
         ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
         typeBytes = 1;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag);         \
         return;                                                                         \
     case RS_TYPE_SIGNED_16:                                                             \
@@ -84,7 +143,25 @@
         len = _env->GetArrayLength((jshortArray)data);                                  \
         ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
         typeBytes = 2;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag);     \
         return;                                                                         \
     case RS_TYPE_SIGNED_32:                                                             \
@@ -92,7 +169,25 @@
         len = _env->GetArrayLength((jintArray)data);                                    \
         ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
         typeBytes = 4;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag);           \
         return;                                                                         \
     case RS_TYPE_SIGNED_64:                                                             \
@@ -100,19 +195,38 @@
         len = _env->GetArrayLength((jlongArray)data);                                   \
         ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
         typeBytes = 8;                                                                  \
-        fnc(__VA_ARGS__);                                                               \
+        if (usePadding) {                                                               \
+            srcPtr = ptr;                                                               \
+            len = len / 3 * 4;                                                          \
+            if (count == 0) {                                                           \
+                count = len / 4;                                                        \
+            }                                                                           \
+            ptr = malloc (len * typeBytes);                                             \
+            if (readonly) {                                                             \
+                copyWithPadding(ptr, srcPtr, mSize, count);                             \
+                fnc(__VA_ARGS__);                                                       \
+            } else {                                                                    \
+                fnc(__VA_ARGS__);                                                       \
+                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
+            }                                                                           \
+            free(ptr);                                                                  \
+            ptr = srcPtr;                                                               \
+        } else {                                                                        \
+            fnc(__VA_ARGS__);                                                           \
+        }                                                                               \
         _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag);        \
         return;                                                                         \
     default:                                                                            \
         break;                                                                          \
     }                                                                                   \
+    UNUSED(len, ptr, srcPtr, typeBytes, relFlag);                                       \
 }
 
 
 class AutoJavaStringToUTF8 {
 public:
     AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
-        fCStr = env->GetStringUTFChars(str, NULL);
+        fCStr = env->GetStringUTFChars(str, nullptr);
         fLength = env->GetStringUTFLength(str);
     }
     ~AutoJavaStringToUTF8() {
@@ -132,14 +246,14 @@
 public:
     AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
     : mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
-        mCStrings = NULL;
-        mSizeArray = NULL;
+        mCStrings = nullptr;
+        mSizeArray = nullptr;
         if (stringsLength > 0) {
             mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
             mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
             for (jsize ct = 0; ct < stringsLength; ct ++) {
                 jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
-                mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
+                mCStrings[ct] = mEnv->GetStringUTFChars(s, nullptr);
                 mSizeArray[ct] = mEnv->GetStringUTFLength(s);
             }
         }
@@ -167,30 +281,308 @@
 // ---------------------------------------------------------------------------
 
 static jfieldID gContextId = 0;
-static jfieldID gNativeBitmapID = 0;
-static jfieldID gTypeNativeCache = 0;
 
 static void _nInit(JNIEnv *_env, jclass _this)
 {
     gContextId             = _env->GetFieldID(_this, "mContext", "J");
-
-    jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
-    gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
 }
 
 // ---------------------------------------------------------------------------
 
+static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) {
+    int sizeBytesPad = mSize * 4;
+    int sizeBytes = mSize * 3;
+    uint8_t *dst = static_cast<uint8_t *>(ptr);
+    uint8_t *src = static_cast<uint8_t *>(srcPtr);
+    for (int i = 0; i < count; i++) {
+        memcpy(dst, src, sizeBytes);
+        dst += sizeBytesPad;
+        src += sizeBytes;
+    }
+}
+
+static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) {
+    int sizeBytesPad = mSize * 4;
+    int sizeBytes = mSize * 3;
+    uint8_t *dst = static_cast<uint8_t *>(ptr);
+    uint8_t *src = static_cast<uint8_t *>(srcPtr);
+    for (int i = 0; i < count; i++) {
+        memcpy(dst, src, sizeBytes);
+        dst += sizeBytes;
+        src += sizeBytesPad;
+    }
+}
+
+
+// ---------------------------------------------------------------------------
 static void
 nContextFinish(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextFinish, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextFinish, con(%p)", (RsContext)con);
+    }
     rsContextFinish((RsContext)con);
 }
 
+static jlong
+nClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong kernelID,
+               jlong returnValue, jlongArray fieldIDArray,
+               jlongArray valueArray, jintArray sizeArray,
+               jlongArray depClosureArray, jlongArray depFieldIDArray) {
+  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
+  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
+  RsScriptFieldID* fieldIDs =
+      (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * fieldIDs_length);
+  for (int i = 0; i< fieldIDs_length; i++) {
+    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
+  }
+
+  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
+  jsize values_length = _env->GetArrayLength(valueArray);
+  uintptr_t* values = (uintptr_t*)alloca(sizeof(uintptr_t) * values_length);
+  for (int i = 0; i < values_length; i++) {
+    values[i] = (uintptr_t)jValues[i];
+  }
+
+  jint* sizes = _env->GetIntArrayElements(sizeArray, nullptr);
+  jsize sizes_length = _env->GetArrayLength(sizeArray);
+
+  jlong* jDepClosures =
+      _env->GetLongArrayElements(depClosureArray, nullptr);
+  jsize depClosures_length = _env->GetArrayLength(depClosureArray);
+  RsClosure* depClosures =
+      (RsClosure*)alloca(sizeof(RsClosure) * depClosures_length);
+  for (int i = 0; i < depClosures_length; i++) {
+    depClosures[i] = (RsClosure)jDepClosures[i];
+  }
+
+  jlong* jDepFieldIDs =
+      _env->GetLongArrayElements(depFieldIDArray, nullptr);
+  jsize depFieldIDs_length = _env->GetArrayLength(depFieldIDArray);
+  RsScriptFieldID* depFieldIDs =
+      (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * depFieldIDs_length);
+  for (int i = 0; i < depClosures_length; i++) {
+    depFieldIDs[i] = (RsClosure)jDepFieldIDs[i];
+  }
+
+  return (jlong)(uintptr_t)rsClosureCreate(
+      (RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
+      fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
+      (size_t*)sizes, (size_t)sizes_length,
+      depClosures, (size_t)depClosures_length,
+      depFieldIDs, (size_t)depFieldIDs_length);
+}
+
+static jlong
+nInvokeClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong invokeID,
+                     jbyteArray paramArray, jlongArray fieldIDArray, jlongArray valueArray,
+                     jintArray sizeArray) {
+  jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
+  jsize jParamLength = _env->GetArrayLength(paramArray);
+
+  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
+  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
+  RsScriptFieldID* fieldIDs =
+      (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * fieldIDs_length);
+  for (int i = 0; i< fieldIDs_length; i++) {
+    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
+  }
+
+  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
+  jsize values_length = _env->GetArrayLength(valueArray);
+  uintptr_t* values = (uintptr_t*)alloca(sizeof(uintptr_t) * values_length);
+  for (int i = 0; i < values_length; i++) {
+    values[i] = (uintptr_t)jValues[i];
+  }
+
+  jint* sizes = _env->GetIntArrayElements(sizeArray, nullptr);
+  jsize sizes_length = _env->GetArrayLength(sizeArray);
+
+  return (jlong)(uintptr_t)rsInvokeClosureCreate(
+      (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
+      fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
+      (size_t*)sizes, (size_t)sizes_length);
+}
+
+static void
+nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
+               jint index, jlong value, jint size) {
+  rsClosureSetArg((RsContext)con, (RsClosure)closureID, (uint32_t)index,
+                  (uintptr_t)value, (size_t)size);
+}
+
+static void
+nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
+                  jlong fieldID, jlong value, jint size) {
+  rsClosureSetGlobal((RsContext)con, (RsClosure)closureID,
+                     (RsScriptFieldID)fieldID, (uintptr_t)value, (size_t)size);
+}
+
+static long
+nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
+                    jstring cacheDir, jlongArray closureArray) {
+  AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+
+  jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
+  jsize numClosures = _env->GetArrayLength(closureArray);
+  RsClosure* closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
+  for (int i = 0; i < numClosures; i++) {
+    closures[i] = (RsClosure)jClosures[i];
+  }
+
+  return (jlong)(uintptr_t)rsScriptGroup2Create(
+      (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(),
+      closures, numClosures);
+}
+
+static void
+nScriptGroup2Execute(JNIEnv *_env, jobject _this, jlong con, jlong groupID) {
+  rsScriptGroupExecute((RsContext)con, (RsScriptGroup2)groupID);
+}
+
+static void
+nScriptIntrinsicBLAS_Single(JNIEnv *_env, jobject _this, jlong con, jlong id, jint func, jint TransA,
+                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
+                            jfloat alpha, jlong A, jlong B, jfloat beta, jlong C, jint incX, jint incY,
+                            jint KL, jint KU) {
+    RsBlasCall call;
+    memset(&call, 0, sizeof(call));
+    call.func = (RsBlasFunction)func;
+    call.transA = (RsBlasTranspose)TransA;
+    call.transB = (RsBlasTranspose)TransB;
+    call.side = (RsBlasSide)Side;
+    call.uplo = (RsBlasUplo)Uplo;
+    call.diag = (RsBlasDiag)Diag;
+    call.M = M;
+    call.N = N;
+    call.K = K;
+    call.alpha.f = alpha;
+    call.beta.f = beta;
+    call.incX = incX;
+    call.incY = incY;
+    call.KL = KL;
+    call.KU = KU;
+
+    RsAllocation in_allocs[3];
+    in_allocs[0] = (RsAllocation)A;
+    in_allocs[1] = (RsAllocation)B;
+    in_allocs[2] = (RsAllocation)C;
+
+    rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
+                         in_allocs, sizeof(in_allocs), nullptr,
+                         &call, sizeof(call), nullptr, 0);
+}
+
+static void
+nScriptIntrinsicBLAS_Double(JNIEnv *_env, jobject _this, jlong con, jlong id, jint func, jint TransA,
+                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
+                            jdouble alpha, jlong A, jlong B, jdouble beta, jlong C, jint incX, jint incY,
+                            jint KL, jint KU) {
+    RsBlasCall call;
+    memset(&call, 0, sizeof(call));
+    call.func = (RsBlasFunction)func;
+    call.transA = (RsBlasTranspose)TransA;
+    call.transB = (RsBlasTranspose)TransB;
+    call.side = (RsBlasSide)Side;
+    call.uplo = (RsBlasUplo)Uplo;
+    call.diag = (RsBlasDiag)Diag;
+    call.M = M;
+    call.N = N;
+    call.K = K;
+    call.alpha.d = alpha;
+    call.beta.d = beta;
+    call.incX = incX;
+    call.incY = incY;
+    call.KL = KL;
+    call.KU = KU;
+
+    RsAllocation in_allocs[3];
+    in_allocs[0] = (RsAllocation)A;
+    in_allocs[1] = (RsAllocation)B;
+    in_allocs[2] = (RsAllocation)C;
+
+    rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
+                         in_allocs, sizeof(in_allocs), nullptr,
+                         &call, sizeof(call), nullptr, 0);
+}
+
+static void
+nScriptIntrinsicBLAS_Complex(JNIEnv *_env, jobject _this, jlong con, jlong id, jint func, jint TransA,
+                             jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
+                             jfloat alphaX, jfloat alphaY, jlong A, jlong B, jfloat betaX,
+                             jfloat betaY, jlong C, jint incX, jint incY, jint KL, jint KU) {
+    RsBlasCall call;
+    memset(&call, 0, sizeof(call));
+    call.func = (RsBlasFunction)func;
+    call.transA = (RsBlasTranspose)TransA;
+    call.transB = (RsBlasTranspose)TransB;
+    call.side = (RsBlasSide)Side;
+    call.uplo = (RsBlasUplo)Uplo;
+    call.diag = (RsBlasDiag)Diag;
+    call.M = M;
+    call.N = N;
+    call.K = K;
+    call.alpha.c.r = alphaX;
+    call.alpha.c.i = alphaY;
+    call.beta.c.r = betaX;
+    call.beta.c.r = betaY;
+    call.incX = incX;
+    call.incY = incY;
+    call.KL = KL;
+    call.KU = KU;
+
+    RsAllocation in_allocs[3];
+    in_allocs[0] = (RsAllocation)A;
+    in_allocs[1] = (RsAllocation)B;
+    in_allocs[2] = (RsAllocation)C;
+
+    rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
+                         in_allocs, sizeof(in_allocs), nullptr,
+                         &call, sizeof(call), nullptr, 0);
+}
+
+static void
+nScriptIntrinsicBLAS_Z(JNIEnv *_env, jobject _this, jlong con, jlong id, jint func, jint TransA,
+                       jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
+                       jdouble alphaX, jdouble alphaY, jlong A, jlong B, jdouble betaX,
+                       jdouble betaY, jlong C, jint incX, jint incY, jint KL, jint KU) {
+    RsBlasCall call;
+    memset(&call, 0, sizeof(call));
+    call.func = (RsBlasFunction)func;
+    call.transA = (RsBlasTranspose)TransA;
+    call.transB = (RsBlasTranspose)TransB;
+    call.side = (RsBlasSide)Side;
+    call.uplo = (RsBlasUplo)Uplo;
+    call.diag = (RsBlasDiag)Diag;
+    call.M = M;
+    call.N = N;
+    call.K = K;
+    call.alpha.z.r = alphaX;
+    call.alpha.z.i = alphaY;
+    call.beta.z.r = betaX;
+    call.beta.z.r = betaY;
+    call.incX = incX;
+    call.incY = incY;
+    call.KL = KL;
+    call.KU = KU;
+
+    RsAllocation in_allocs[3];
+    in_allocs[0] = (RsAllocation)A;
+    in_allocs[1] = (RsAllocation)B;
+    in_allocs[2] = (RsAllocation)C;
+
+    rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
+                         in_allocs, sizeof(in_allocs), nullptr,
+                         &call, sizeof(call), nullptr, 0);
+}
+
+
 static void
 nAssignName(JNIEnv *_env, jobject _this, jlong con, jlong obj, jbyteArray str)
 {
-    LOG_API("nAssignName, con(%p), obj(%p)", (RsContext)con, (void *)obj);
+    if (kLogApi) {
+        ALOGD("nAssignName, con(%p), obj(%p)", (RsContext)con, (void *)obj);
+    }
     jint len = _env->GetArrayLength(str);
     jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
     rsAssignName((RsContext)con, (void *)obj, (const char *)cptr, len);
@@ -200,11 +592,13 @@
 static jstring
 nGetName(JNIEnv *_env, jobject _this, jlong con, jlong obj)
 {
-    LOG_API("nGetName, con(%p), obj(%p)", (RsContext)con, (void *)obj);
-    const char *name = NULL;
+    if (kLogApi) {
+        ALOGD("nGetName, con(%p), obj(%p)", (RsContext)con, (void *)obj);
+    }
+    const char *name = nullptr;
     rsaGetName((RsContext)con, (void *)obj, &name);
-    if(name == NULL || strlen(name) == 0) {
-        return NULL;
+    if(name == nullptr || strlen(name) == 0) {
+        return nullptr;
     }
     return _env->NewStringUTF(name);
 }
@@ -212,7 +606,9 @@
 static void
 nObjDestroy(JNIEnv *_env, jobject _this, jlong con, jlong obj)
 {
-    LOG_API("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
+    if (kLogApi) {
+        ALOGD("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
+    }
     rsObjDestroy((RsContext)con, (void *)obj);
 }
 
@@ -221,28 +617,36 @@
 static jlong
 nDeviceCreate(JNIEnv *_env, jobject _this)
 {
-    LOG_API("nDeviceCreate");
+    if (kLogApi) {
+        ALOGD("nDeviceCreate");
+    }
     return (jlong)(uintptr_t)rsDeviceCreate();
 }
 
 static void
 nDeviceDestroy(JNIEnv *_env, jobject _this, jlong dev)
 {
-    LOG_API("nDeviceDestroy");
+    if (kLogApi) {
+        ALOGD("nDeviceDestroy");
+    }
     return rsDeviceDestroy((RsDevice)dev);
 }
 
 static void
 nDeviceSetConfig(JNIEnv *_env, jobject _this, jlong dev, jint p, jint value)
 {
-    LOG_API("nDeviceSetConfig  dev(%p), param(%i), value(%i)", (void *)dev, p, value);
+    if (kLogApi) {
+        ALOGD("nDeviceSetConfig  dev(%p), param(%i), value(%i)", (void *)dev, p, value);
+    }
     return rsDeviceSetConfig((RsDevice)dev, (RsDeviceParam)p, value);
 }
 
 static jlong
 nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint flags, jint sdkVer, jint contextType)
 {
-    LOG_API("nContextCreate");
+    if (kLogApi) {
+        ALOGD("nContextCreate");
+    }
     return (jlong)(uintptr_t)rsContextCreate((RsDevice)dev, 0, sdkVer, (RsContextType)contextType, flags);
 }
 
@@ -266,14 +670,18 @@
     sc.samplesPref = samplesPref;
     sc.samplesQ = samplesQ;
 
-    LOG_API("nContextCreateGL");
+    if (kLogApi) {
+        ALOGD("nContextCreateGL");
+    }
     return (jlong)(uintptr_t)rsContextCreateGL((RsDevice)dev, ver, sdkVer, sc, dpi);
 }
 
 static void
 nContextSetPriority(JNIEnv *_env, jobject _this, jlong con, jint p)
 {
-    LOG_API("ContextSetPriority, con(%p), priority(%i)", (RsContext)con, p);
+    if (kLogApi) {
+        ALOGD("ContextSetPriority, con(%p), priority(%i)", (RsContext)con, p);
+    }
     rsContextSetPriority((RsContext)con, p);
 }
 
@@ -282,10 +690,13 @@
 static void
 nContextSetSurface(JNIEnv *_env, jobject _this, jlong con, jint width, jint height, jobject wnd)
 {
-    LOG_API("nContextSetSurface, con(%p), width(%i), height(%i), surface(%p)", (RsContext)con, width, height, (Surface *)wnd);
+    if (kLogApi) {
+        ALOGD("nContextSetSurface, con(%p), width(%i), height(%i), surface(%p)", (RsContext)con,
+              width, height, (Surface *)wnd);
+    }
 
-    ANativeWindow * window = NULL;
-    if (wnd == NULL) {
+    ANativeWindow * window = nullptr;
+    if (wnd == nullptr) {
 
     } else {
         window = android_view_Surface_getNativeWindow(_env, wnd).get();
@@ -297,28 +708,36 @@
 static void
 nContextDestroy(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextDestroy, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextDestroy, con(%p)", (RsContext)con);
+    }
     rsContextDestroy((RsContext)con);
 }
 
 static void
 nContextDump(JNIEnv *_env, jobject _this, jlong con, jint bits)
 {
-    LOG_API("nContextDump, con(%p)  bits(%i)", (RsContext)con, bits);
+    if (kLogApi) {
+        ALOGD("nContextDump, con(%p)  bits(%i)", (RsContext)con, bits);
+    }
     rsContextDump((RsContext)con, bits);
 }
 
 static void
 nContextPause(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextPause, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextPause, con(%p)", (RsContext)con);
+    }
     rsContextPause((RsContext)con);
 }
 
 static void
 nContextResume(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextResume, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextResume, con(%p)", (RsContext)con);
+    }
     rsContextResume((RsContext)con);
 }
 
@@ -326,7 +745,9 @@
 static jstring
 nContextGetErrorMessage(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextGetErrorMessage, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextGetErrorMessage, con(%p)", (RsContext)con);
+    }
     char buf[1024];
 
     size_t receiveLen;
@@ -336,7 +757,7 @@
                                  &receiveLen, sizeof(receiveLen),
                                  &subID, sizeof(subID));
     if (!id && receiveLen) {
-        ALOGV("message receive buffer too small.  %i", receiveLen);
+        ALOGV("message receive buffer too small.  %zu", receiveLen);
     }
     return _env->NewStringUTF(buf);
 }
@@ -345,8 +766,10 @@
 nContextGetUserMessage(JNIEnv *_env, jobject _this, jlong con, jintArray data)
 {
     jint len = _env->GetArrayLength(data);
-    LOG_API("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
+    if (kLogApi) {
+        ALOGD("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
+    }
+    jint *ptr = _env->GetIntArrayElements(data, nullptr);
     size_t receiveLen;
     uint32_t subID;
     int id = rsContextGetMessage((RsContext)con,
@@ -354,7 +777,7 @@
                                  &receiveLen, sizeof(receiveLen),
                                  &subID, sizeof(subID));
     if (!id && receiveLen) {
-        ALOGV("message receive buffer too small.  %i", receiveLen);
+        ALOGV("message receive buffer too small.  %zu", receiveLen);
     }
     _env->ReleaseIntArrayElements(data, ptr, 0);
     return (jint)id;
@@ -363,8 +786,10 @@
 static jint
 nContextPeekMessage(JNIEnv *_env, jobject _this, jlong con, jintArray auxData)
 {
-    LOG_API("nContextPeekMessage, con(%p)", (RsContext)con);
-    jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL);
+    if (kLogApi) {
+        ALOGD("nContextPeekMessage, con(%p)", (RsContext)con);
+    }
+    jint *auxDataPtr = _env->GetIntArrayElements(auxData, nullptr);
     size_t receiveLen;
     uint32_t subID;
     int id = rsContextPeekMessage((RsContext)con, &receiveLen, sizeof(receiveLen),
@@ -377,26 +802,32 @@
 
 static void nContextInitToClient(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextInitToClient, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextInitToClient, con(%p)", (RsContext)con);
+    }
     rsContextInitToClient((RsContext)con);
 }
 
 static void nContextDeinitToClient(JNIEnv *_env, jobject _this, jlong con)
 {
-    LOG_API("nContextDeinitToClient, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nContextDeinitToClient, con(%p)", (RsContext)con);
+    }
     rsContextDeinitToClient((RsContext)con);
 }
 
 static void
 nContextSendMessage(JNIEnv *_env, jobject _this, jlong con, jint id, jintArray data)
 {
-    jint *ptr = NULL;
+    jint *ptr = nullptr;
     jint len = 0;
     if (data) {
         len = _env->GetArrayLength(data);
-        ptr = _env->GetIntArrayElements(data, NULL);
+        ptr = _env->GetIntArrayElements(data, nullptr);
     }
-    LOG_API("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
+    if (kLogApi) {
+        ALOGD("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
+    }
     rsContextSendMessage((RsContext)con, id, (const uint8_t *)ptr, len * sizeof(int));
     if (data) {
         _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
@@ -406,10 +837,15 @@
 
 
 static jlong
-nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jboolean norm, jint size)
+nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jboolean norm,
+               jint size)
 {
-    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con, type, kind, norm, size);
-    return (jlong)(uintptr_t)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind, norm, size);
+    if (kLogApi) {
+        ALOGD("nElementCreate, con(%p), type(%" PRId64 "), kind(%i), norm(%i), size(%i)", (RsContext)con,
+              type, kind, norm, size);
+    }
+    return (jlong)(uintptr_t)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind,
+                                             norm, size);
 }
 
 static jlong
@@ -417,10 +853,12 @@
                 jlongArray _ids, jobjectArray _names, jintArray _arraySizes)
 {
     int fieldCount = _env->GetArrayLength(_ids);
-    LOG_API("nElementCreate2, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nElementCreate2, con(%p)", (RsContext)con);
+    }
 
-    jlong *jIds = _env->GetLongArrayElements(_ids, NULL);
-    jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
+    jlong *jIds = _env->GetLongArrayElements(_ids, nullptr);
+    jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, nullptr);
 
     RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
     uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
@@ -452,7 +890,9 @@
 nElementGetNativeData(JNIEnv *_env, jobject _this, jlong con, jlong id, jintArray _elementData)
 {
     int dataSize = _env->GetArrayLength(_elementData);
-    LOG_API("nElementGetNativeData, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nElementGetNativeData, con(%p)", (RsContext)con);
+    }
 
     // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
     assert(dataSize == 5);
@@ -474,13 +914,16 @@
                        jintArray _arraySizes)
 {
     uint32_t dataSize = _env->GetArrayLength(_IDs);
-    LOG_API("nElementGetSubElements, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nElementGetSubElements, con(%p)", (RsContext)con);
+    }
 
     uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
     const char **names = (const char **)malloc(dataSize * sizeof(const char *));
     uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
 
-    rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes, (uint32_t)dataSize);
+    rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
+                             (uint32_t)dataSize);
 
     for(uint32_t i = 0; i < dataSize; i++) {
         const jlong id = (jlong)(uintptr_t)ids[i];
@@ -501,10 +944,13 @@
 nTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
             jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces, jint yuv)
 {
-    LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
-            (RsContext)con, eid, dimx, dimy, dimz, mips, faces, yuv);
+    if (kLogApi) {
+        ALOGD("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
+              (RsContext)con, (void*)eid, dimx, dimy, dimz, mips, faces, yuv);
+    }
 
-    return (jlong)(uintptr_t)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips, faces, yuv);
+    return (jlong)(uintptr_t)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips,
+                                          faces, yuv);
 }
 
 static void
@@ -515,7 +961,9 @@
     int elementCount = _env->GetArrayLength(_typeData);
 
     assert(elementCount == 6);
-    LOG_API("nTypeGetNativeData, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nTypeGetNativeData, con(%p)", (RsContext)con);
+    }
 
     uintptr_t typeData[6];
     rsaTypeGetNativeData((RsContext)con, (RsType)id, typeData, 6);
@@ -529,27 +977,39 @@
 // -----------------------------------
 
 static jlong
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage, jlong pointer)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage,
+                       jlong pointer)
 {
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jlong)(uintptr_t) rsAllocationCreateTyped((RsContext)con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uintptr_t)pointer);
+    if (kLogApi) {
+        ALOGD("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)",
+              (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
+    }
+    return (jlong)(uintptr_t) rsAllocationCreateTyped((RsContext)con, (RsType)type,
+                                                      (RsAllocationMipmapControl)mips,
+                                                      (uint32_t)usage, (uintptr_t)pointer);
 }
 
 static void
 nAllocationSyncAll(JNIEnv *_env, jobject _this, jlong con, jlong a, jint bits)
 {
-    LOG_API("nAllocationSyncAll, con(%p), a(%p), bits(0x%08x)", (RsContext)con, (RsAllocation)a, bits);
+    if (kLogApi) {
+        ALOGD("nAllocationSyncAll, con(%p), a(%p), bits(0x%08x)", (RsContext)con, (RsAllocation)a,
+              bits);
+    }
     rsAllocationSyncAll((RsContext)con, (RsAllocation)a, (RsAllocationUsageType)bits);
 }
 
 static jobject
 nAllocationGetSurface(JNIEnv *_env, jobject _this, jlong con, jlong a)
 {
-    LOG_API("nAllocationGetSurface, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
+    if (kLogApi) {
+        ALOGD("nAllocationGetSurface, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
+    }
 
-    IGraphicBufferProducer *v = (IGraphicBufferProducer *)rsAllocationGetSurface((RsContext)con, (RsAllocation)a);
+    IGraphicBufferProducer *v = (IGraphicBufferProducer *)rsAllocationGetSurface((RsContext)con,
+                                                                                 (RsAllocation)a);
     sp<IGraphicBufferProducer> bp = v;
-    v->decStrong(NULL);
+    v->decStrong(nullptr);
 
     jobject o = android_view_Surface_createFromIGraphicBufferProducer(_env, bp);
     return o;
@@ -558,28 +1018,35 @@
 static void
 nAllocationSetSurface(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject sur)
 {
-    LOG_API("nAllocationSetSurface, con(%p), alloc(%p), surface(%p)",
-            (RsContext)con, (RsAllocation)alloc, (Surface *)sur);
+    if (kLogApi) {
+        ALOGD("nAllocationSetSurface, con(%p), alloc(%p), surface(%p)", (RsContext)con,
+              (RsAllocation)alloc, (Surface *)sur);
+    }
 
     sp<Surface> s;
     if (sur != 0) {
         s = android_view_Surface_getSurface(_env, sur);
     }
 
-    rsAllocationSetSurface((RsContext)con, (RsAllocation)alloc, static_cast<ANativeWindow *>(s.get()));
+    rsAllocationSetSurface((RsContext)con, (RsAllocation)alloc,
+                           static_cast<ANativeWindow *>(s.get()));
 }
 
 static void
 nAllocationIoSend(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
 {
-    LOG_API("nAllocationIoSend, con(%p), alloc(%p)", (RsContext)con, alloc);
+    if (kLogApi) {
+        ALOGD("nAllocationIoSend, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
+    }
     rsAllocationIoSend((RsContext)con, (RsAllocation)alloc);
 }
 
 static void
 nAllocationIoReceive(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
 {
-    LOG_API("nAllocationIoReceive, con(%p), alloc(%p)", (RsContext)con, alloc);
+    if (kLogApi) {
+        ALOGD("nAllocationIoReceive, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
+    }
     rsAllocationIoReceive((RsContext)con, (RsAllocation)alloc);
 }
 
@@ -587,15 +1054,18 @@
 static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
 {
-    LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", (RsContext)con, (RsAllocation)alloc);
+    if (kLogApi) {
+        ALOGD("nAllocationGenerateMipmaps, con(%p), a(%p)", (RsContext)con, (RsAllocation)alloc);
+    }
     rsAllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
 }
 
 static jlong
-nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage)
+nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
+                            jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -608,10 +1078,11 @@
 }
 
 static jlong
-nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage)
+nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
+                                        jint mip, jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -624,10 +1095,11 @@
 }
 
 static jlong
-nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip, jobject jbitmap, jint usage)
+nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
+                                jobject jbitmap, jint usage)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -643,7 +1115,7 @@
 nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
     int w = bitmap.width();
     int h = bitmap.height();
@@ -660,7 +1132,7 @@
 nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
 {
     SkBitmap const * nativeBitmap =
-            (SkBitmap const *)_env->GetLongField(jbitmap, gNativeBitmapID);
+            GraphicsJNI::getSkBitmap(_env, jbitmap);
     const SkBitmap& bitmap(*nativeBitmap);
 
     bitmap.lockPixels();
@@ -670,46 +1142,56 @@
     bitmap.notifyPixelsChanged();
 }
 
-static void ReleaseBitmapCallback(void *bmp)
-{
-    SkBitmap const * nativeBitmap = (SkBitmap const *)bmp;
-    nativeBitmap->unlockPixels();
-}
-
-
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType)
+                  jint count, jobject data, jint sizeBytes, jint dataType, jint mSize,
+                  jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
-            (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes, dataType);
-    PER_ARRAY_TYPE(NULL, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+    if (kLogApi) {
+        ALOGD("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
+              "dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes,
+              dataType);
+    }
+    PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true,
+                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
 }
 
-// Copies from the Java array data into the Allocation pointed to by alloc.
 static void
-//    native void rsnAllocationElementData1D(long con, long id, int xoff, int compIdx, byte[] d, int sizeBytes);
-nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
+nAllocationElementData(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                       jint xoff, jint yoff, jint zoff,
+                       jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
 {
     jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation1DElementData((RsContext)con, (RsAllocation)alloc, offset, lod, ptr, sizeBytes, compIdx);
+    if (kLogApi) {
+        ALOGD("nAllocationElementData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
+              "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
+              sizeBytes);
+    }
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    rsAllocationElementData((RsContext)con, (RsAllocation)alloc,
+                            xoff, yoff, zoff,
+                            lod, ptr, sizeBytes, compIdx);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
+
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType)
+                  jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize,
+                  jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
-            (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    PER_ARRAY_TYPE(NULL, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+    if (kLogApi) {
+        ALOGD("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
+              "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
+    }
+    int count = w * h;
+    PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true,
+                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
 }
 
 // Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -722,11 +1204,13 @@
                         jlong srcAlloc, jint srcXoff, jint srcYoff,
                         jint srcMip, jint srcFace)
 {
-    LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), dstFace(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
+    if (kLogApi) {
+        ALOGD("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
+              " dstMip(%i), dstFace(%i), width(%i), height(%i),"
+              " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
+              (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
+              width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
+    }
 
     rsAllocationCopy2DRange((RsContext)con,
                             (RsAllocation)dstAlloc,
@@ -741,12 +1225,18 @@
 // Copies from the Java object data into the Allocation pointed to by _alloc.
 static void
 nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i), h(%i), d(%i), sizeBytes(%i)",
-            (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes);
-    PER_ARRAY_TYPE(NULL, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    if (kLogApi) {
+        ALOGD("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
+              " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
+              lod, w, h, d, sizeBytes);
+    }
+    int count = w * h * d;
+    PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true,
+                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
 }
 
 // Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -759,11 +1249,13 @@
                         jlong srcAlloc, jint srcXoff, jint srcYoff, jint srcZoff,
                         jint srcMip)
 {
-    LOG_API("nAllocationData3D_alloc, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip);
+    if (kLogApi) {
+        ALOGD("nAllocationData3D_alloc, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
+              " dstMip(%i), width(%i), height(%i),"
+              " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i)",
+              (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip,
+              width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip);
+    }
 
     rsAllocationCopy3DRange((RsContext)con,
                             (RsAllocation)dstAlloc,
@@ -776,50 +1268,136 @@
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
-nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType)
+nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType,
+                jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes);
+    if (kLogApi) {
+        ALOGD("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
+    }
+    int count = 0;
+    PER_ARRAY_TYPE(0, rsAllocationRead, false,
+                   (RsContext)con, alloc, ptr, len * typeBytes);
 }
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
 nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, int sizeBytes, int dataType)
+                  jint count, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
-            (RsContext)con, alloc, offset, count, sizeBytes, dataType);
-    PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+    if (kLogApi) {
+        ALOGD("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
+              "dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType);
+    }
+    PER_ARRAY_TYPE(0, rsAllocation1DRead, false,
+                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+}
+
+// Copies from the Element in the Allocation pointed to by _alloc into the Java array data.
+static void
+nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                       jint xoff, jint yoff, jint zoff,
+                       jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    if (kLogApi) {
+        ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
+              "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
+              sizeBytes);
+    }
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    rsAllocationElementRead((RsContext)con, (RsAllocation)alloc,
+                            xoff, yoff, zoff,
+                            lod, ptr, sizeBytes, compIdx);
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
 // Copies from the Allocation pointed to by _alloc into the Java object data.
 static void
 nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, int sizeBytes, int dataType)
+                  jint w, jint h, jobject data, jint sizeBytes, jint dataType,
+                  jint mSize, jboolean usePadding)
 {
     RsAllocation *alloc = (RsAllocation *)_alloc;
     RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
-            (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+    if (kLogApi) {
+        ALOGD("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
+              "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
+    }
+    int count = w * h;
+    PER_ARRAY_TYPE(0, rsAllocation2DRead, false,
+                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+}
+
+// Copies from the Allocation pointed to by _alloc into the Java object data.
+static void
+nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                  jint w, jint h, jint d, jobject data, int sizeBytes, int dataType,
+                  jint mSize, jboolean usePadding)
+{
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    if (kLogApi) {
+        ALOGD("nAllocation3DRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
+              " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
+              lod, w, h, d, sizeBytes);
+    }
+    int count = w * h * d;
+    PER_ARRAY_TYPE(nullptr, rsAllocation3DRead, false,
+                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
 }
 
 static jlong
 nAllocationGetType(JNIEnv *_env, jobject _this, jlong con, jlong a)
 {
-    LOG_API("nAllocationGetType, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
+    if (kLogApi) {
+        ALOGD("nAllocationGetType, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
+    }
     return (jlong)(uintptr_t) rsaAllocationGetType((RsContext)con, (RsAllocation)a);
 }
 
 static void
 nAllocationResize1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint dimX)
 {
-    LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i)", (RsContext)con, (RsAllocation)alloc, dimX);
+    if (kLogApi) {
+        ALOGD("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i)", (RsContext)con,
+              (RsAllocation)alloc, dimX);
+    }
     rsAllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
 }
 
+
+static jlong
+nAllocationAdapterCreate(JNIEnv *_env, jobject _this, jlong con, jlong basealloc, jlong type)
+{
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterCreate, con(%p), base(%p), type(%p)",
+              (RsContext)con, (RsAllocation)basealloc, (RsElement)type);
+    }
+    return (jlong)(uintptr_t) rsAllocationAdapterCreate((RsContext)con, (RsType)type,
+                                                        (RsAllocation)basealloc);
+
+}
+
+static void
+nAllocationAdapterOffset(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                        jint x, jint y, jint z, jint face, jint lod,
+                        jint a1, jint a2, jint a3, jint a4)
+{
+    uint32_t params[] = {
+        (uint32_t)x, (uint32_t)y, (uint32_t)z, (uint32_t)face,
+        (uint32_t)lod, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4
+    };
+    if (kLogApi) {
+        ALOGD("nAllocationAdapterOffset, con(%p), alloc(%p), x(%i), y(%i), z(%i), face(%i), lod(%i), arrays(%i %i %i %i)",
+              (RsContext)con, (RsAllocation)alloc, x, y, z, face, lod, a1, a2, a3, a4);
+    }
+    rsAllocationAdapterOffset((RsContext)con, (RsAllocation)alloc,
+                              params, sizeof(params));
+}
+
+
 // -----------------------------------
 
 static jlong
@@ -836,13 +1414,13 @@
 nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
 {
     AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
-    if (mgr == NULL) {
+    if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
     Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
-    if (asset == NULL) {
+    if (asset == nullptr) {
         return 0;
     }
 
@@ -924,13 +1502,13 @@
                      jfloat fontSize, jint dpi)
 {
     AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
-    if (mgr == NULL) {
+    if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
     Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
-    if (asset == NULL) {
+    if (asset == nullptr) {
         return 0;
     }
 
@@ -947,21 +1525,29 @@
 static void
 nScriptBindAllocation(JNIEnv *_env, jobject _this, jlong con, jlong script, jlong alloc, jint slot)
 {
-    LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", (RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
+    if (kLogApi) {
+        ALOGD("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", (RsContext)con,
+              (RsScript)script, (RsAllocation)alloc, slot);
+    }
     rsScriptBindAllocation((RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
 }
 
 static void
 nScriptSetVarI(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jint val)
 {
-    LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con, (void *)script, slot, val);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con, (void *)script,
+              slot, val);
+    }
     rsScriptSetVarI((RsContext)con, (RsScript)script, slot, val);
 }
 
 static jint
 nScriptGetVarI(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot)
 {
-    LOG_API("nScriptGetVarI, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptGetVarI, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     int value = 0;
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, &value, sizeof(value));
     return value;
@@ -970,21 +1556,29 @@
 static void
 nScriptSetVarObj(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val)
 {
-    LOG_API("nScriptSetVarObj, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con, (void *)script, slot, val);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarObj, con(%p), s(%p), slot(%i), val(%" PRId64 ")", (RsContext)con, (void *)script,
+              slot, val);
+    }
     rsScriptSetVarObj((RsContext)con, (RsScript)script, slot, (RsObjectBase)val);
 }
 
 static void
 nScriptSetVarJ(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val)
 {
-    LOG_API("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%lli)", (RsContext)con, (void *)script, slot, val);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%" PRId64 ")", (RsContext)con, (void *)script,
+              slot, val);
+    }
     rsScriptSetVarJ((RsContext)con, (RsScript)script, slot, val);
 }
 
 static jlong
 nScriptGetVarJ(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot)
 {
-    LOG_API("nScriptGetVarJ, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptGetVarJ, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jlong value = 0;
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, &value, sizeof(value));
     return value;
@@ -993,14 +1587,19 @@
 static void
 nScriptSetVarF(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, float val)
 {
-    LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", (RsContext)con, (void *)script, slot, val);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", (RsContext)con, (void *)script,
+              slot, val);
+    }
     rsScriptSetVarF((RsContext)con, (RsScript)script, slot, val);
 }
 
 static jfloat
 nScriptGetVarF(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot)
 {
-    LOG_API("nScriptGetVarF, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptGetVarF, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jfloat value = 0;
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, &value, sizeof(value));
     return value;
@@ -1009,14 +1608,19 @@
 static void
 nScriptSetVarD(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, double val)
 {
-    LOG_API("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", (RsContext)con, (void *)script, slot, val);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", (RsContext)con, (void *)script,
+              slot, val);
+    }
     rsScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
 }
 
 static jdouble
 nScriptGetVarD(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot)
 {
-    LOG_API("nScriptGetVarD, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptGetVarD, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jdouble value = 0;
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, &value, sizeof(value));
     return value;
@@ -1025,9 +1629,11 @@
 static void
 nScriptSetVarV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data)
 {
-    LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
     rsScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
@@ -1035,21 +1641,26 @@
 static void
 nScriptGetVarV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data)
 {
-    LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, 0);
 }
 
 static void
-nScriptSetVarVE(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data, jlong elem, jintArray dims)
+nScriptSetVarVE(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data,
+                jlong elem, jintArray dims)
 {
-    LOG_API("nScriptSetVarVE, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptSetVarVE, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
     jint dimsLen = _env->GetArrayLength(dims) * sizeof(int);
-    jint *dimsPtr = _env->GetIntArrayElements(dims, NULL);
+    jint *dimsPtr = _env->GetIntArrayElements(dims, nullptr);
     rsScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
                      (const uint32_t*) dimsPtr, dimsLen);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
@@ -1060,7 +1671,9 @@
 static void
 nScriptSetTimeZone(JNIEnv *_env, jobject _this, jlong con, jlong script, jbyteArray timeZone)
 {
-    LOG_API("nScriptCSetTimeZone, con(%p), s(%p)", (RsContext)con, (void *)script);
+    if (kLogApi) {
+        ALOGD("nScriptCSetTimeZone, con(%p), s(%p)", (RsContext)con, (void *)script);
+    }
 
     jint length = _env->GetArrayLength(timeZone);
     jbyte* timeZone_ptr;
@@ -1076,174 +1689,111 @@
 static void
 nScriptInvoke(JNIEnv *_env, jobject _this, jlong con, jlong obj, jint slot)
 {
-    LOG_API("nScriptInvoke, con(%p), script(%p)", (RsContext)con, (void *)obj);
+    if (kLogApi) {
+        ALOGD("nScriptInvoke, con(%p), script(%p)", (RsContext)con, (void *)obj);
+    }
     rsScriptInvoke((RsContext)con, (RsScript)obj, slot);
 }
 
 static void
 nScriptInvokeV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data)
 {
-    LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    if (kLogApi) {
+        ALOGD("nScriptInvokeV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
+    }
     jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
     rsScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
 static void
-nScriptForEach(JNIEnv *_env, jobject _this, jlong con,
-               jlong script, jint slot, jlong ain, jlong aout)
+nScriptForEach(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
+               jlongArray ains, jlong aout, jbyteArray params,
+               jintArray limits)
 {
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, NULL, 0, NULL, 0);
-}
-static void
-nScriptForEachV(JNIEnv *_env, jobject _this, jlong con,
-                jlong script, jint slot, jlong ain, jlong aout, jbyteArray params)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, ptr, len, NULL, 0);
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachClipped(JNIEnv *_env, jobject _this, jlong con,
-                      jlong script, jint slot, jlong ain, jlong aout,
-                      jint xstart, jint xend,
-                      jint ystart, jint yend, jint zstart, jint zend)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, NULL, 0, &sc, sizeof(sc));
-}
-
-static void
-nScriptForEachClippedV(JNIEnv *_env, jobject _this, jlong con,
-                       jlong script, jint slot, jlong ain, jlong aout,
-                       jbyteArray params, jint xstart, jint xend,
-                       jint ystart, jint yend, jint zstart, jint zend)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, ptr, len, &sc, sizeof(sc));
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachMultiClipped(JNIEnv *_env, jobject _this, jlong con,
-                      jlong script, jint slot, jlongArray ains, jlong aout,
-                      jint xstart, jint xend,
-                      jint ystart, jint yend, jint zstart, jint zend)
-{
-    LOG_API("nScriptForEachMultiClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-
-    jint   in_len = _env->GetArrayLength(ains);
-    jlong* in_ptr = _env->GetLongArrayElements(ains, NULL);
-
-    RsAllocation *in_allocs = NULL;
-
-    if (sizeof(RsAllocation) == sizeof(jlong)) {
-      in_allocs = (RsAllocation*)in_ptr;
-
-    } else {
-      // Convert from 64-bit jlong types to the native pointer type.
-
-      in_allocs = new RsAllocation[in_len];
-
-      for (int index = in_len; --index >= 0;) {
-        in_allocs[index] = (RsAllocation)in_ptr[index];
-      }
+    if (kLogApi) {
+        ALOGD("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
     }
 
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
+    jint   in_len = 0;
+    jlong *in_ptr = nullptr;
 
-    rsScriptForEachMulti((RsContext)con, (RsScript)script, slot, in_allocs, in_len, (RsAllocation)aout, NULL, 0, &sc, sizeof(sc));
+    RsAllocation *in_allocs = nullptr;
 
-    if (sizeof(RsAllocation) != sizeof(jlong)) {
-      delete[] in_allocs;
+    if (ains != nullptr) {
+        in_len = _env->GetArrayLength(ains);
+        in_ptr = _env->GetLongArrayElements(ains, nullptr);
+
+        if (sizeof(RsAllocation) == sizeof(jlong)) {
+            in_allocs = (RsAllocation*)in_ptr;
+
+        } else {
+            // Convert from 64-bit jlong types to the native pointer type.
+
+            in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
+
+            for (int index = in_len; --index >= 0;) {
+                in_allocs[index] = (RsAllocation)in_ptr[index];
+            }
+        }
     }
 
-    _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-}
+    jint   param_len = 0;
+    jbyte *param_ptr = nullptr;
 
-static void
-nScriptForEachMultiClippedV(JNIEnv *_env, jobject _this, jlong con,
-                       jlong script, jint slot, jlongArray ains, jlong aout,
-                       jbyteArray params, jint xstart, jint xend,
-                       jint ystart, jint yend, jint zstart, jint zend)
-{
-    LOG_API("nScriptForEachMultiClippedV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-
-    jint   in_len = _env->GetArrayLength(ains);
-    jlong* in_ptr = _env->GetLongArrayElements(ains, NULL);
-
-    RsAllocation *in_allocs = NULL;
-
-    if (sizeof(RsAllocation) == sizeof(jlong)) {
-      in_allocs = (RsAllocation*)in_ptr;
-
-    } else {
-      // Convert from 64-bit jlong types to the native pointer type.
-
-      in_allocs = new RsAllocation[in_len];
-
-      for (int index = in_len; --index >= 0;) {
-        in_allocs[index] = (RsAllocation)in_ptr[index];
-      }
+    if (params != nullptr) {
+        param_len = _env->GetArrayLength(params);
+        param_ptr = _env->GetByteArrayElements(params, nullptr);
     }
 
-    jint   param_len = _env->GetArrayLength(params);
-    jbyte* param_ptr = _env->GetByteArrayElements(params, NULL);
+    RsScriptCall sc, *sca = nullptr;
+    uint32_t sc_size = 0;
 
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    rsScriptForEachMulti((RsContext)con, (RsScript)script, slot, in_allocs, in_len, (RsAllocation)aout, param_ptr, param_len, &sc, sizeof(sc));
+    jint  limit_len = 0;
+    jint *limit_ptr = nullptr;
 
-    if (sizeof(RsAllocation) != sizeof(jlong)) {
-      delete[] in_allocs;
+    if (limits != nullptr) {
+        limit_len = _env->GetArrayLength(limits);
+        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
+
+        assert(limit_len == 6);
+        UNUSED(limit_len);  // As the assert might not be compiled.
+
+        sc.xStart     = limit_ptr[0];
+        sc.xEnd       = limit_ptr[1];
+        sc.yStart     = limit_ptr[2];
+        sc.yEnd       = limit_ptr[3];
+        sc.zStart     = limit_ptr[4];
+        sc.zEnd       = limit_ptr[5];
+        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
+        sc.arrayStart = 0;
+        sc.arrayEnd = 0;
+        sc.array2Start = 0;
+        sc.array2End = 0;
+        sc.array3Start = 0;
+        sc.array3End = 0;
+        sc.array4Start = 0;
+        sc.array4End = 0;
+
+        sca = &sc;
     }
 
-    _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-    _env->ReleaseByteArrayElements(params, param_ptr, JNI_ABORT);
+    rsScriptForEachMulti((RsContext)con, (RsScript)script, slot,
+                         in_allocs, in_len, (RsAllocation)aout,
+                         param_ptr, param_len, sca, sc_size);
+
+    if (ains != nullptr) {
+        _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
+    }
+
+    if (params != nullptr) {
+        _env->ReleaseByteArrayElements(params, param_ptr, JNI_ABORT);
+    }
+
+    if (limits != nullptr) {
+        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
+    }
 }
 
 // -----------------------------------
@@ -1253,12 +1803,14 @@
                jstring resName, jstring cacheDir,
                jbyteArray scriptRef, jint length)
 {
-    LOG_API("nScriptCCreate, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nScriptCCreate, con(%p)", (RsContext)con);
+    }
 
     AutoJavaStringToUTF8 resNameUTF(_env, resName);
     AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
     jlong ret = 0;
-    jbyte* script_ptr = NULL;
+    jbyte* script_ptr = nullptr;
     jint _exception = 0;
     jint remaining;
     if (!scriptRef) {
@@ -1300,21 +1852,40 @@
 static jlong
 nScriptIntrinsicCreate(JNIEnv *_env, jobject _this, jlong con, jint id, jlong eid)
 {
-    LOG_API("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", (RsContext)con, id, (void *)eid);
+    if (kLogApi) {
+        ALOGD("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", (RsContext)con, id,
+              (void *)eid);
+    }
     return (jlong)(uintptr_t)rsScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
 }
 
 static jlong
 nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig)
 {
-    LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con, (void *)sid, slot, sig);
+    if (kLogApi) {
+        ALOGD("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con,
+              (void *)sid, slot, sig);
+    }
     return (jlong)(uintptr_t)rsScriptKernelIDCreate((RsContext)con, (RsScript)sid, slot, sig);
 }
 
 static jlong
+nScriptInvokeIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
+{
+    if (kLogApi) {
+        ALOGD("nScriptInvokeIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con,
+              (void *)sid, slot);
+    }
+    return (jlong)(uintptr_t)rsScriptInvokeIDCreate((RsContext)con, (RsScript)sid, slot);
+}
+
+static jlong
 nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
 {
-    LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
+    if (kLogApi) {
+        ALOGD("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid,
+              slot);
+    }
     return (jlong)(uintptr_t)rsScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
 }
 
@@ -1322,38 +1893,40 @@
 nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels, jlongArray _src,
     jlongArray _dstk, jlongArray _dstf, jlongArray _types)
 {
-    LOG_API("nScriptGroupCreate, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nScriptGroupCreate, con(%p)", (RsContext)con);
+    }
 
     jint kernelsLen = _env->GetArrayLength(_kernels);
-    jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, NULL);
+    jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
     RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
     for(int i = 0; i < kernelsLen; ++i) {
         kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
     }
 
     jint srcLen = _env->GetArrayLength(_src);
-    jlong *jSrcPtr = _env->GetLongArrayElements(_src, NULL);
+    jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
     RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
     for(int i = 0; i < srcLen; ++i) {
         srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
     }
 
     jint dstkLen = _env->GetArrayLength(_dstk);
-    jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, NULL);
+    jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
     RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
     for(int i = 0; i < dstkLen; ++i) {
         dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
     }
 
     jint dstfLen = _env->GetArrayLength(_dstf);
-    jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, NULL);
+    jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
     RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
     for(int i = 0; i < dstfLen; ++i) {
         dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
     }
 
     jint typesLen = _env->GetArrayLength(_types);
-    jlong *jTypesPtr = _env->GetLongArrayElements(_types, NULL);
+    jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
     RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
     for(int i = 0; i < typesLen; ++i) {
         typesPtr[i] = (RsType)jTypesPtr[i];
@@ -1382,23 +1955,29 @@
 static void
 nScriptGroupSetInput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
 {
-    LOG_API("nScriptGroupSetInput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-        (void *)gid, (void *)kid, (void *)alloc);
+    if (kLogApi) {
+        ALOGD("nScriptGroupSetInput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
+              (void *)gid, (void *)kid, (void *)alloc);
+    }
     rsScriptGroupSetInput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid, (RsAllocation)alloc);
 }
 
 static void
 nScriptGroupSetOutput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
 {
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-        (void *)gid, (void *)kid, (void *)alloc);
+    if (kLogApi) {
+        ALOGD("nScriptGroupSetOutput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
+              (void *)gid, (void *)kid, (void *)alloc);
+    }
     rsScriptGroupSetOutput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid, (RsAllocation)alloc);
 }
 
 static void
 nScriptGroupExecute(JNIEnv *_env, jobject _this, jlong con, jlong gid)
 {
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p)", (RsContext)con, (void *)gid);
+    if (kLogApi) {
+        ALOGD("nScriptGroupSetOutput, con(%p) group(%p)", (RsContext)con, (void *)gid);
+    }
     rsScriptGroupExecute((RsContext)con, (RsScriptGroup)gid);
 }
 
@@ -1411,7 +1990,9 @@
                     jint srcFunc, jint destFunc,
                     jint depthFunc)
 {
-    LOG_API("nProgramStoreCreate, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nProgramStoreCreate, con(%p)", (RsContext)con);
+    }
     return (jlong)(uintptr_t)rsProgramStoreCreate((RsContext)con, colorMaskR, colorMaskG, colorMaskB, colorMaskA,
                                       depthMask, ditherEnable, (RsBlendSrcFunc)srcFunc,
                                       (RsBlendDstFunc)destFunc, (RsDepthFunc)depthFunc);
@@ -1422,21 +2003,30 @@
 static void
 nProgramBindConstants(JNIEnv *_env, jobject _this, jlong con, jlong vpv, jint slot, jlong a)
 {
-    LOG_API("nProgramBindConstants, con(%p), vpf(%p), sloat(%i), a(%p)", (RsContext)con, (RsProgramVertex)vpv, slot, (RsAllocation)a);
+    if (kLogApi) {
+        ALOGD("nProgramBindConstants, con(%p), vpf(%p), sloat(%i), a(%p)", (RsContext)con,
+              (RsProgramVertex)vpv, slot, (RsAllocation)a);
+    }
     rsProgramBindConstants((RsContext)con, (RsProgram)vpv, slot, (RsAllocation)a);
 }
 
 static void
 nProgramBindTexture(JNIEnv *_env, jobject _this, jlong con, jlong vpf, jint slot, jlong a)
 {
-    LOG_API("nProgramBindTexture, con(%p), vpf(%p), slot(%i), a(%p)", (RsContext)con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
+    if (kLogApi) {
+        ALOGD("nProgramBindTexture, con(%p), vpf(%p), slot(%i), a(%p)", (RsContext)con,
+              (RsProgramFragment)vpf, slot, (RsAllocation)a);
+    }
     rsProgramBindTexture((RsContext)con, (RsProgramFragment)vpf, slot, (RsAllocation)a);
 }
 
 static void
 nProgramBindSampler(JNIEnv *_env, jobject _this, jlong con, jlong vpf, jint slot, jlong a)
 {
-    LOG_API("nProgramBindSampler, con(%p), vpf(%p), slot(%i), a(%p)", (RsContext)con, (RsProgramFragment)vpf, slot, (RsSampler)a);
+    if (kLogApi) {
+        ALOGD("nProgramBindSampler, con(%p), vpf(%p), slot(%i), a(%p)", (RsContext)con,
+              (RsProgramFragment)vpf, slot, (RsSampler)a);
+    }
     rsProgramBindSampler((RsContext)con, (RsProgramFragment)vpf, slot, (RsSampler)a);
 }
 
@@ -1447,7 +2037,7 @@
                        jobjectArray texNames, jlongArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
-    jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
+    jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
     jint paramLen = _env->GetArrayLength(params);
 
     int texCount = _env->GetArrayLength(texNames);
@@ -1455,7 +2045,9 @@
     const char ** nameArray = names.c_str();
     size_t* sizeArray = names.c_str_len();
 
-    LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
+    if (kLogApi) {
+        ALOGD("nProgramFragmentCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
+    }
 
     uintptr_t * paramPtr = (uintptr_t*) malloc(sizeof(uintptr_t) * paramLen);
     for(int i = 0; i < paramLen; ++i) {
@@ -1478,10 +2070,12 @@
                      jobjectArray texNames, jlongArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
-    jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
+    jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
     jint paramLen = _env->GetArrayLength(params);
 
-    LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
+    if (kLogApi) {
+        ALOGD("nProgramVertexCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
+    }
 
     int texCount = _env->GetArrayLength(texNames);
     AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
@@ -1507,7 +2101,10 @@
 static jlong
 nProgramRasterCreate(JNIEnv *_env, jobject _this, jlong con, jboolean pointSprite, jint cull)
 {
-    LOG_API("nProgramRasterCreate, con(%p), pointSprite(%i), cull(%i)", (RsContext)con, pointSprite, cull);
+    if (kLogApi) {
+        ALOGD("nProgramRasterCreate, con(%p), pointSprite(%i), cull(%i)", (RsContext)con,
+              pointSprite, cull);
+    }
     return (jlong)(uintptr_t)rsProgramRasterCreate((RsContext)con, pointSprite, (RsCullMode)cull);
 }
 
@@ -1517,35 +2114,46 @@
 static void
 nContextBindRootScript(JNIEnv *_env, jobject _this, jlong con, jlong script)
 {
-    LOG_API("nContextBindRootScript, con(%p), script(%p)", (RsContext)con, (RsScript)script);
+    if (kLogApi) {
+        ALOGD("nContextBindRootScript, con(%p), script(%p)", (RsContext)con, (RsScript)script);
+    }
     rsContextBindRootScript((RsContext)con, (RsScript)script);
 }
 
 static void
 nContextBindProgramStore(JNIEnv *_env, jobject _this, jlong con, jlong pfs)
 {
-    LOG_API("nContextBindProgramStore, con(%p), pfs(%p)", (RsContext)con, (RsProgramStore)pfs);
+    if (kLogApi) {
+        ALOGD("nContextBindProgramStore, con(%p), pfs(%p)", (RsContext)con, (RsProgramStore)pfs);
+    }
     rsContextBindProgramStore((RsContext)con, (RsProgramStore)pfs);
 }
 
 static void
 nContextBindProgramFragment(JNIEnv *_env, jobject _this, jlong con, jlong pf)
 {
-    LOG_API("nContextBindProgramFragment, con(%p), pf(%p)", (RsContext)con, (RsProgramFragment)pf);
+    if (kLogApi) {
+        ALOGD("nContextBindProgramFragment, con(%p), pf(%p)", (RsContext)con,
+              (RsProgramFragment)pf);
+    }
     rsContextBindProgramFragment((RsContext)con, (RsProgramFragment)pf);
 }
 
 static void
 nContextBindProgramVertex(JNIEnv *_env, jobject _this, jlong con, jlong pf)
 {
-    LOG_API("nContextBindProgramVertex, con(%p), pf(%p)", (RsContext)con, (RsProgramVertex)pf);
+    if (kLogApi) {
+        ALOGD("nContextBindProgramVertex, con(%p), pf(%p)", (RsContext)con, (RsProgramVertex)pf);
+    }
     rsContextBindProgramVertex((RsContext)con, (RsProgramVertex)pf);
 }
 
 static void
 nContextBindProgramRaster(JNIEnv *_env, jobject _this, jlong con, jlong pf)
 {
-    LOG_API("nContextBindProgramRaster, con(%p), pf(%p)", (RsContext)con, (RsProgramRaster)pf);
+    if (kLogApi) {
+        ALOGD("nContextBindProgramRaster, con(%p), pf(%p)", (RsContext)con, (RsProgramRaster)pf);
+    }
     rsContextBindProgramRaster((RsContext)con, (RsProgramRaster)pf);
 }
 
@@ -1556,7 +2164,9 @@
 nSamplerCreate(JNIEnv *_env, jobject _this, jlong con, jint magFilter, jint minFilter,
                jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
 {
-    LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nSamplerCreate, con(%p)", (RsContext)con);
+    }
     return (jlong)(uintptr_t)rsSamplerCreate((RsContext)con,
                                  (RsSamplerValue)magFilter,
                                  (RsSamplerValue)minFilter,
@@ -1569,36 +2179,28 @@
 // ---------------------------------------------------------------------------
 
 static jlong
-nPathCreate(JNIEnv *_env, jobject _this, jlong con, jint prim, jboolean isStatic, jlong _vtx, jlong _loop, jfloat q) {
-    LOG_API("nPathCreate, con(%p)", (RsContext)con);
-
-    jlong id = (jlong)(uintptr_t)rsPathCreate((RsContext)con, (RsPathPrimitive)prim, isStatic,
-                                   (RsAllocation)_vtx,
-                                   (RsAllocation)_loop, q);
-    return id;
-}
-
-static jlong
 nMeshCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _vtx, jlongArray _idx, jintArray _prim)
 {
-    LOG_API("nMeshCreate, con(%p)", (RsContext)con);
+    if (kLogApi) {
+        ALOGD("nMeshCreate, con(%p)", (RsContext)con);
+    }
 
     jint vtxLen = _env->GetArrayLength(_vtx);
-    jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, NULL);
+    jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, nullptr);
     RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
     for(int i = 0; i < vtxLen; ++i) {
         vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
     }
 
     jint idxLen = _env->GetArrayLength(_idx);
-    jlong *jIdxPtr = _env->GetLongArrayElements(_idx, NULL);
+    jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
     RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
     for(int i = 0; i < idxLen; ++i) {
         idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
     }
 
     jint primLen = _env->GetArrayLength(_prim);
-    jint *primPtr = _env->GetIntArrayElements(_prim, NULL);
+    jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
 
     jlong id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
                                (RsAllocation *)vtxPtr, vtxLen,
@@ -1616,7 +2218,9 @@
 static jint
 nMeshGetVertexBufferCount(JNIEnv *_env, jobject _this, jlong con, jlong mesh)
 {
-    LOG_API("nMeshGetVertexBufferCount, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    if (kLogApi) {
+        ALOGD("nMeshGetVertexBufferCount, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    }
     jint vtxCount = 0;
     rsaMeshGetVertexBufferCount((RsContext)con, (RsMesh)mesh, &vtxCount);
     return vtxCount;
@@ -1625,7 +2229,9 @@
 static jint
 nMeshGetIndexCount(JNIEnv *_env, jobject _this, jlong con, jlong mesh)
 {
-    LOG_API("nMeshGetIndexCount, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    if (kLogApi) {
+        ALOGD("nMeshGetIndexCount, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    }
     jint idxCount = 0;
     rsaMeshGetIndexCount((RsContext)con, (RsMesh)mesh, &idxCount);
     return idxCount;
@@ -1634,7 +2240,9 @@
 static void
 nMeshGetVertices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jlongArray _ids, jint numVtxIDs)
 {
-    LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    if (kLogApi) {
+        ALOGD("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    }
 
     RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numVtxIDs * sizeof(RsAllocation));
     rsaMeshGetVertices((RsContext)con, (RsMesh)mesh, allocs, (uint32_t)numVtxIDs);
@@ -1650,7 +2258,9 @@
 static void
 nMeshGetIndices(JNIEnv *_env, jobject _this, jlong con, jlong mesh, jlongArray _idxIds, jintArray _primitives, jint numIndices)
 {
-    LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    if (kLogApi) {
+        ALOGD("nMeshGetVertices, con(%p), Mesh(%p)", (RsContext)con, (RsMesh)mesh);
+    }
 
     RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numIndices * sizeof(RsAllocation));
     uint32_t *prims= (uint32_t*)malloc((uint32_t)numIndices * sizeof(uint32_t));
@@ -1704,6 +2314,10 @@
 {"rsnContextPause",                  "(J)V",                                  (void*)nContextPause },
 {"rsnContextResume",                 "(J)V",                                  (void*)nContextResume },
 {"rsnContextSendMessage",            "(JI[I)V",                               (void*)nContextSendMessage },
+{"rsnClosureCreate",                 "(JJJ[J[J[I[J[J)J",                      (void*)nClosureCreate },
+{"rsnInvokeClosureCreate",           "(JJ[B[J[J[I)J",                         (void*)nInvokeClosureCreate },
+{"rsnClosureSetArg",                 "(JJIJI)V",                              (void*)nClosureSetArg },
+{"rsnClosureSetGlobal",              "(JJJJI)V",                              (void*)nClosureSetGlobal },
 {"rsnAssignName",                    "(JJ[B)V",                               (void*)nAssignName },
 {"rsnGetName",                       "(JJ)Ljava/lang/String;",                (void*)nGetName },
 {"rsnObjDestroy",                    "(JJ)V",                                 (void*)nObjDestroy },
@@ -1740,29 +2354,31 @@
 {"rsnAllocationSetSurface",          "(JJLandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
 {"rsnAllocationIoSend",              "(JJ)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationIoReceive",           "(JJ)V",                                 (void*)nAllocationIoReceive },
-{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;II)V",          (void*)nAllocationData1D },
-{"rsnAllocationElementData1D",       "(JJIII[BI)V",                           (void*)nAllocationElementData1D },
-{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;II)V",       (void*)nAllocationData2D },
+{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationData1D },
+{"rsnAllocationElementData",         "(JJIIIII[BI)V",                         (void*)nAllocationElementData },
+{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationData2D },
 {"rsnAllocationData2D",              "(JJIIIIIIJIIII)V",                      (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;II)V",      (void*)nAllocationData3D },
+{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationData3D },
 {"rsnAllocationData3D",              "(JJIIIIIIIJIIII)V",                     (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead",                "(JJLjava/lang/Object;I)V",              (void*)nAllocationRead },
-{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;II)V",          (void*)nAllocationRead1D },
-{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;II)V",       (void*)nAllocationRead2D },
+{"rsnAllocationRead",                "(JJLjava/lang/Object;IIZ)V",            (void*)nAllocationRead },
+{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationRead1D },
+{"rsnAllocationElementRead",         "(JJIIIII[BI)V",                         (void*)nAllocationElementRead },
+{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationRead2D },
+{"rsnAllocationRead3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationRead3D },
 {"rsnAllocationGetType",             "(JJ)J",                                 (void*)nAllocationGetType},
 {"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
 {"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
 
+{"rsnAllocationAdapterCreate",       "(JJJ)J",                                (void*)nAllocationAdapterCreate },
+{"rsnAllocationAdapterOffset",       "(JJIIIIIIIII)V",                        (void*)nAllocationAdapterOffset },
+
 {"rsnScriptBindAllocation",          "(JJJI)V",                               (void*)nScriptBindAllocation },
 {"rsnScriptSetTimeZone",             "(JJ[B)V",                               (void*)nScriptSetTimeZone },
 {"rsnScriptInvoke",                  "(JJI)V",                                (void*)nScriptInvoke },
 {"rsnScriptInvokeV",                 "(JJI[B)V",                              (void*)nScriptInvokeV },
-{"rsnScriptForEach",                 "(JJIJJ)V",                              (void*)nScriptForEach },
-{"rsnScriptForEach",                 "(JJIJJ[B)V",                            (void*)nScriptForEachV },
-{"rsnScriptForEachClipped",          "(JJIJJIIIIII)V",                        (void*)nScriptForEachClipped },
-{"rsnScriptForEachClipped",          "(JJIJJ[BIIIIII)V",                      (void*)nScriptForEachClippedV },
-{"rsnScriptForEachMultiClipped",     "(JJI[JJIIIIII)V",                       (void*)nScriptForEachMultiClipped },
-{"rsnScriptForEachMultiClipped",     "(JJI[JJ[BIIIIII)V",                     (void*)nScriptForEachMultiClippedV },
+
+{"rsnScriptForEach",                 "(JJI[JJ[B[I)V",                         (void*)nScriptForEach },
+
 {"rsnScriptSetVarI",                 "(JJII)V",                               (void*)nScriptSetVarI },
 {"rsnScriptGetVarI",                 "(JJI)I",                                (void*)nScriptGetVarI },
 {"rsnScriptSetVarJ",                 "(JJIJ)V",                               (void*)nScriptSetVarJ },
@@ -1779,11 +2395,19 @@
 {"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)J",  (void*)nScriptCCreate },
 {"rsnScriptIntrinsicCreate",         "(JIJ)J",                                (void*)nScriptIntrinsicCreate },
 {"rsnScriptKernelIDCreate",          "(JJII)J",                               (void*)nScriptKernelIDCreate },
+{"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
 {"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
+{"rsnScriptGroup2Create",            "(JLjava/lang/String;[J)J",               (void*)nScriptGroup2Create },
 {"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
+{"rsnScriptGroup2Execute",           "(JJ)V",                                 (void*)nScriptGroup2Execute },
+
+{"rsnScriptIntrinsicBLAS_Single",    "(JJIIIIIIIIIFJJFJIIII)V",               (void*)nScriptIntrinsicBLAS_Single },
+{"rsnScriptIntrinsicBLAS_Double",    "(JJIIIIIIIIIDJJDJIIII)V",               (void*)nScriptIntrinsicBLAS_Double },
+{"rsnScriptIntrinsicBLAS_Complex",   "(JJIIIIIIIIIFFJJFFJIIII)V",             (void*)nScriptIntrinsicBLAS_Complex },
+{"rsnScriptIntrinsicBLAS_Z",         "(JJIIIIIIIIIDDJJDDJIIII)V",             (void*)nScriptIntrinsicBLAS_Z },
 
 {"rsnProgramStoreCreate",            "(JZZZZZZIII)J",                         (void*)nProgramStoreCreate },
 
@@ -1803,7 +2427,6 @@
 
 {"rsnSamplerCreate",                 "(JIIIIIF)J",                            (void*)nSamplerCreate },
 
-{"rsnPathCreate",                    "(JIZJJF)J",                             (void*)nPathCreate },
 {"rsnMeshCreate",                    "(J[J[J[I)J",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(JJ)I",                                 (void*)nMeshGetVertexBufferCount },
@@ -1824,14 +2447,14 @@
 
 jint JNI_OnLoad(JavaVM* vm, void* reserved)
 {
-    JNIEnv* env = NULL;
+    JNIEnv* env = nullptr;
     jint result = -1;
 
     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
         ALOGE("ERROR: GetEnv failed\n");
         goto bail;
     }
-    assert(env != NULL);
+    assert(env != nullptr);
 
     if (registerFuncs(env) < 0) {
         ALOGE("ERROR: Renderscript native registration failed\n");
diff --git a/services/Android.mk b/services/Android.mk
index 3c94f43..da85528 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -48,10 +48,6 @@
 
 LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
-    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
 LOCAL_MODULE:= libandroid_servers
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 93c65f3..a712d78 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -944,7 +944,9 @@
 
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
-                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                PackageManager.GET_SERVICES 
+                  | PackageManager.GET_META_DATA 
+                  | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 mCurrentUserId);
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
diff --git a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
index b68b09f..bc76191 100644
--- a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
@@ -69,8 +69,7 @@
             return true;
         }
 
-        final float firstMagnitude =
-            (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY);
+        final float firstMagnitude = (float) Math.hypot(firstDeltaX, firstDeltaY);
         final float firstXNormalized =
             (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
         final float firstYNormalized =
@@ -83,8 +82,7 @@
             return true;
         }
 
-        final float secondMagnitude =
-            (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY);
+        final float secondMagnitude = (float) Math.hypot(secondDeltaX, secondDeltaY);
         final float secondXNormalized =
             (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
         final float secondYNormalized =
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index c8b080e..b4613d6 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.Property;
 import android.util.Slog;
+import android.util.TypedValue;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MagnificationSpec;
@@ -110,7 +111,6 @@
     private static final int STATE_MAGNIFIED_INTERACTION = 4;
 
     private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
-    private static final int MULTI_TAP_TIME_SLOP_ADJUSTMENT = 50;
 
     private static final int MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED = 1;
     private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 2;
@@ -135,9 +135,8 @@
 
     private final AccessibilityManagerService mAms;
 
-    private final int mTapTimeSlop = ViewConfiguration.getTapTimeout();
-    private final int mMultiTapTimeSlop =
-            ViewConfiguration.getDoubleTapTimeout() - MULTI_TAP_TIME_SLOP_ADJUSTMENT;
+    private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
+    private final int mMultiTapTimeSlop;
     private final int mTapDistanceSlop;
     private final int mMultiTapDistanceSlop;
 
@@ -192,6 +191,9 @@
         mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mAms = service;
 
+        mMultiTapTimeSlop = ViewConfiguration.getDoubleTapTimeout()
+                + mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
         mLongAnimationDuration = context.getResources().getInteger(
                 com.android.internal.R.integer.config_longAnimTime);
         mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -481,15 +483,20 @@
         private static final float MIN_SCALE = 1.3f;
         private static final float MAX_SCALE = 5.0f;
 
-        private static final float SCALING_THRESHOLD = 0.3f;
-
         private final ScaleGestureDetector mScaleGestureDetector;
         private final GestureDetector mGestureDetector;
 
+        private final float mScalingThreshold;
+
         private float mInitialScaleFactor = -1;
         private boolean mScaling;
 
         public MagnifiedContentInteractonStateHandler(Context context) {
+            final TypedValue scaleValue = new TypedValue();
+            context.getResources().getValue(
+                    com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
+                    scaleValue, false);
+            mScalingThreshold = scaleValue.getFloat();
             mScaleGestureDetector = new ScaleGestureDetector(context, this);
             mScaleGestureDetector.setQuickScaleEnabled(false);
             mGestureDetector = new GestureDetector(context, this);
@@ -537,7 +544,7 @@
                     mInitialScaleFactor = detector.getScaleFactor();
                 } else {
                     final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
-                    if (Math.abs(deltaScale) > SCALING_THRESHOLD) {
+                    if (Math.abs(deltaScale) > mScalingThreshold) {
                         mScaling = true;
                         return true;
                     }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7623514..da11dad 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2837,10 +2837,10 @@
         return providersUpdated;
     }
 
-    private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
+    private boolean removeProvidersForPackageLocked(String pkgName, int userId) {
         boolean removed = false;
 
-        int N = mProviders.size();
+        final int N = mProviders.size();
         for (int i = N - 1; i >= 0; i--) {
             Provider provider = mProviders.get(i);
             if (pkgName.equals(provider.info.provider.getPackageName())
@@ -2849,11 +2849,16 @@
                 removed = true;
             }
         }
+        return removed;
+    }
+
+    private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
+        boolean removed = removeProvidersForPackageLocked(pkgName, userId);
 
         // Delete the hosts for this package too
         // By now, we have removed any AppWidgets that were in any hosts here,
         // so we don't need to worry about sending DISABLE broadcasts to them.
-        N = mHosts.size();
+        final int N = mHosts.size();
         for (int i = N - 1; i >= 0; i--) {
             Host host = mHosts.get(i);
             if (pkgName.equals(host.id.packageName)
@@ -2925,13 +2930,30 @@
             synchronized (mLock) {
                 boolean providersChanged = false;
 
+                ArraySet<String> previousPackages = new ArraySet<String>();
+                final int providerCount = mProviders.size();
+                for (int i = 0; i < providerCount; ++i) {
+                    Provider provider = mProviders.get(i);
+                    if (provider.getUserId() == userId) {
+                        previousPackages.add(provider.id.componentName.getPackageName());
+                    }
+                }
+
                 final int packageCount = packages.size();
                 for (int i = 0; i < packageCount; i++) {
                     String packageName = packages.get(i);
+                    previousPackages.remove(packageName);
                     providersChanged |= updateProvidersForPackageLocked(packageName,
                             userId, null);
                 }
 
+                // Some packages are no longer whitelisted.
+                final int removedCount = previousPackages.size();
+                for (int i = 0; i < removedCount; ++i) {
+                    providersChanged |= removeProvidersForPackageLocked(
+                            previousPackages.valueAt(i), userId);
+                }
+
                 if (providersChanged) {
                     saveGroupStateAsync(userId);
                     scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
@@ -3142,10 +3164,10 @@
             if (parentId != callerId) {
                 return false;
             }
-            return isProviderWhitelListed(packageName, profileId);
+            return isProviderWhiteListed(packageName, profileId);
         }
 
-        public boolean isProviderWhitelListed(String packageName, int profileId) {
+        public boolean isProviderWhiteListed(String packageName, int profileId) {
             DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
                     DevicePolicyManagerInternal.class);
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c1e4994..8fcdd39 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -157,9 +157,9 @@
 public class BackupManagerService {
 
     private static final String TAG = "BackupManagerService";
-    private static final boolean DEBUG = true;
-    private static final boolean MORE_DEBUG = false;
-    private static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
+    static final boolean DEBUG = true;
+    static final boolean MORE_DEBUG = false;
+    static final boolean DEBUG_SCHEDULING = MORE_DEBUG || true;
 
     // System-private key used for backing up an app's widget state.  Must
     // begin with U+FFxx by convention (we reserve all keys starting
@@ -195,17 +195,6 @@
     static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
     static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 
-    // How often we perform a backup pass.  Privileged external callers can
-    // trigger an immediate pass.
-    private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
-
-    // Random variation in backup scheduling time to avoid server load spikes
-    private static final int FUZZ_MILLIS = 5 * 60 * 1000;
-
-    // The amount of time between the initial provisioning of the device and
-    // the first backup pass.
-    private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
-
     // Retry interval for clear/init when the transport is unavailable
     private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
 
@@ -299,7 +288,6 @@
     volatile boolean mBackupRunning;
     volatile boolean mConnecting;
     volatile long mLastBackupPass;
-    volatile long mNextBackupPass;
 
     // For debugging, we maintain a progress trace of operations during backup
     static final boolean DEBUG_BACKUP_TRACE = true;
@@ -381,7 +369,7 @@
                 if (mProvisioned && !wasProvisioned && mEnabled) {
                     // we're now good to go, so start the backup alarms
                     if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups");
-                    startBackupAlarmsLocked(FIRST_BACKUP_INTERVAL);
+                    KeyValueBackupJob.schedule(mContext);
                     scheduleNextFullBackupJob();
                 }
             }
@@ -613,7 +601,7 @@
         return token;
     }
 
-    // High level policy: apps are ineligible for backup if certain conditions apply
+    // High level policy: apps are generally ineligible for backup if certain conditions apply
     public static boolean appIsEligibleForBackup(ApplicationInfo app) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
@@ -640,7 +628,7 @@
             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
         }
 
-        // No agent means we do full backups for it
+        // No agent or fullBackupOnly="true" means we do indeed perform full-data backups for it
         return true;
     }
 
@@ -657,7 +645,6 @@
             case MSG_RUN_BACKUP:
             {
                 mLastBackupPass = System.currentTimeMillis();
-                mNextBackupPass = mLastBackupPass + BACKUP_INTERVAL;
 
                 IBackupTransport transport = getTransport(mCurrentTransport);
                 if (transport == null) {
@@ -1279,7 +1266,23 @@
                     for (int i = 0; i < N; i++) {
                         String pkgName = in.readUTF();
                         long lastBackup = in.readLong();
-                        schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                        try {
+                            PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+                            if (appGetsFullBackup(pkg)
+                                    && appIsEligibleForBackup(pkg.applicationInfo)) {
+                                schedule.add(new FullBackupEntry(pkgName, lastBackup));
+                            } else {
+                                if (DEBUG) {
+                                    Slog.i(TAG, "Package " + pkgName
+                                            + " no longer eligible for full backup");
+                                }
+                            }
+                        } catch (NameNotFoundException e) {
+                            if (DEBUG) {
+                                Slog.i(TAG, "Package " + pkgName
+                                        + " not installed; dropping from full backup");
+                            }
+                        }
                     }
                     Collections.sort(schedule);
                 } catch (Exception e) {
@@ -1302,7 +1305,7 @@
                 schedule = new ArrayList<FullBackupEntry>(N);
                 for (int i = 0; i < N; i++) {
                     PackageInfo info = apps.get(i);
-                    if (appGetsFullBackup(info)) {
+                    if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
                         schedule.add(new FullBackupEntry(info.packageName, 0));
                     }
                 }
@@ -1774,11 +1777,11 @@
                     addPackageParticipantsLocked(pkgList);
                 }
                 // If they're full-backup candidates, add them there instead
+                final long now = System.currentTimeMillis();
                 for (String packageName : pkgList) {
                     try {
                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
-                        long now = System.currentTimeMillis();
-                        if (appGetsFullBackup(app)) {
+                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob();
                         }
@@ -1865,7 +1868,8 @@
     boolean tryBindTransport(ServiceInfo info) {
         try {
             PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
-            if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+            if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                    != 0) {
                 return bindTransport(info);
             } else {
                 Slog.w(TAG, "Transport package " + info.packageName + " not privileged");
@@ -2474,7 +2478,7 @@
             BackupRequest request = mQueue.get(0);
             mQueue.remove(0);
 
-            Slog.d(TAG, "starting agent for backup of " + request);
+            Slog.d(TAG, "starting key/value backup of " + request);
             addBackupTrace("launch agent for " + request.packageName);
 
             // Verify that the requested app exists; it might be something that
@@ -2485,13 +2489,24 @@
             try {
                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                         PackageManager.GET_SIGNATURES);
-                if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
                     // The manifest has changed but we had a stale backup request pending.
                     // This won't happen again because the app won't be requesting further
                     // backups.
                     Slog.i(TAG, "Package " + request.packageName
                             + " no longer supports backup; skipping");
-                    addBackupTrace("skipping - no agent, completion is noop");
+                    addBackupTrace("skipping - not eligible, completion is noop");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                    return;
+                }
+
+                if (appGetsFullBackup(mCurrentPackage)) {
+                    // It's possible that this app *formerly* was enqueued for key/value backup,
+                    // but has since been updated and now only supports the full-data path.
+                    // Don't proceed with a key/value backup for it in this case.
+                    Slog.i(TAG, "Package " + request.packageName
+                            + " requests full-data rather than key/value; skipping");
+                    addBackupTrace("skipping - fullBackupOnly, completion is noop");
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
@@ -2777,7 +2792,22 @@
 
         @Override
         public void operationComplete() {
-            // Okay, the agent successfully reported back to us!
+            // The agent reported back to us!
+
+            if (mBackupData == null) {
+                // This callback was racing with our timeout, so we've cleaned up the
+                // agent state already and are on to the next thing.  We have nothing
+                // further to do here: agent state having been cleared means that we've
+                // initiated the appropriate next operation.
+                final String pkg = (mCurrentPackage != null)
+                        ? mCurrentPackage.packageName : "[none]";
+                if (DEBUG) {
+                    Slog.i(TAG, "Callback after agent teardown: " + pkg);
+                }
+                addBackupTrace("late opComplete; curPkg = " + pkg);
+                return;
+            }
+
             final String pkgName = mCurrentPackage.packageName;
             final long filepos = mBackupDataName.length();
             FileDescriptor fd = mBackupData.getFileDescriptor();
@@ -2923,12 +2953,22 @@
         void revertAndEndBackup() {
             if (MORE_DEBUG) Slog.i(TAG, "Reverting backup queue - restaging everything");
             addBackupTrace("transport error; reverting");
+
+            // We want to reset the backup schedule based on whatever the transport suggests
+            // by way of retry/backoff time.
+            long delay;
+            try {
+                delay = mTransport.requestBackupTime();
+            } catch (Exception e) {
+                Slog.w(TAG, "Unable to contact transport for recommended backoff");
+                delay = 0;  // use the scheduler's default
+            }
+            KeyValueBackupJob.schedule(mContext, delay);
+
             for (BackupRequest request : mOriginalQueue) {
                 dataChangedImpl(request.packageName);
             }
-            // We also want to reset the backup schedule based on whatever
-            // the transport suggests by way of retry/backoff time.
-            restartBackupAlarm();
+
         }
 
         void agentErrorCleanup() {
@@ -2961,15 +3001,6 @@
             }
         }
 
-        void restartBackupAlarm() {
-            addBackupTrace("setting backup trigger");
-            synchronized (mQueueLock) {
-                try {
-                    startBackupAlarmsLocked(mTransport.requestBackupTime());
-                } catch (RemoteException e) { /* cannot happen */ }
-            }
-        }
-
         void executeNextState(BackupState nextState) {
             if (MORE_DEBUG) Slog.i(TAG, " => executing next step on "
                     + this + " nextState=" + nextState);
@@ -3196,7 +3227,7 @@
                     final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
                     final boolean sendApk = mIncludeApks
                             && !isSharedStorage
-                            && ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
+                            && ((app.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) == 0)
                             && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
                                 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
 
@@ -3831,6 +3862,14 @@
                             Slog.d(TAG, "Ignoring non-agent system package " + pkg);
                         }
                         continue;
+                    } else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+                        // Cull any packages in the 'stopped' state: they've either just been
+                        // installed or have explicitly been force-stopped by the user.  In both
+                        // cases we do not want to launch them for backup.
+                        if (MORE_DEBUG) {
+                            Slog.d(TAG, "Ignoring stopped package " + pkg);
+                        }
+                        continue;
                     }
                     mPackages.add(info);
                 } catch (NameNotFoundException e) {
@@ -3870,6 +3909,16 @@
                     return;
                 }
 
+                // Don't proceed unless we have already established package metadata
+                // for the current dataset via a key/value backup pass.
+                File stateDir = new File(mBaseStateDir, transport.transportDirName());
+                File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
+                if (pmState.length() <= 0) {
+                    Slog.i(TAG, "Full backup requested but dataset not yet initialized "
+                            + "via k/v backup pass; ignoring");
+                    return;
+                }
+
                 // Set up to send data to the transport
                 final int N = mPackages.size();
                 for (int i = 0; i < N; i++) {
@@ -8095,6 +8144,9 @@
                 }
             }
         }
+
+        // ...and schedule a backup pass if necessary
+        KeyValueBackupJob.schedule(mContext);
     }
 
     // Note: packageName is currently unused, but may be in the future
@@ -8229,16 +8281,16 @@
 
         if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
         synchronized (mQueueLock) {
-            // Because the alarms we are using can jitter, and we want an *immediate*
-            // backup pass to happen, we restart the timer beginning with "next time,"
-            // then manually fire the backup trigger intent ourselves.
-            startBackupAlarmsLocked(BACKUP_INTERVAL);
+            // Fire the intent that kicks off the whole shebang...
             try {
                 mRunBackupIntent.send();
             } catch (PendingIntent.CanceledException e) {
                 // should never happen
                 Slog.e(TAG, "run-backup intent cancelled!");
             }
+
+            // ...and cancel any pending scheduled job, because we've just superseded it
+            KeyValueBackupJob.cancel(mContext);
         }
     }
 
@@ -8514,13 +8566,13 @@
             synchronized (mQueueLock) {
                 if (enable && !wasEnabled && mProvisioned) {
                     // if we've just been enabled, start scheduling backup passes
-                    startBackupAlarmsLocked(BACKUP_INTERVAL);
+                    KeyValueBackupJob.schedule(mContext);
                     scheduleNextFullBackupJob();
                 } else if (!enable) {
                     // No longer enabled, so stop running backups
                     if (DEBUG) Slog.i(TAG, "Opting out of backup");
 
-                    mAlarmManager.cancel(mRunBackupIntent);
+                    KeyValueBackupJob.cancel(mContext);
 
                     // This also constitutes an opt-out, so we wipe any data for
                     // this device from the backend.  We start that process with
@@ -8574,19 +8626,6 @@
          */
     }
 
-    private void startBackupAlarmsLocked(long delayBeforeFirstBackup) {
-        // We used to use setInexactRepeating(), but that may be linked to
-        // backups running at :00 more often than not, creating load spikes.
-        // Schedule at an exact time for now, and also add a bit of "fuzz".
-
-        Random random = new Random();
-        long when = System.currentTimeMillis() + delayBeforeFirstBackup +
-                random.nextInt(FUZZ_MILLIS);
-        mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when,
-                BACKUP_INTERVAL + random.nextInt(FUZZ_MILLIS), mRunBackupIntent);
-        mNextBackupPass = when;
-    }
-
     // Report whether the backup mechanism is currently enabled
     public boolean isBackupEnabled() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupEnabled");
@@ -9167,6 +9206,8 @@
             // check whether there is data for it in the current dataset, falling back
             // to the ancestral dataset if not.
             long token = getAvailableRestoreToken(packageName);
+            if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName
+                    + " token=" + Long.toHexString(token));
 
             // If we didn't come up with a place to look -- no ancestral dataset and
             // the app has never been backed up from this device -- there's nothing
@@ -9292,7 +9333,7 @@
             if (mBackupRunning) pw.println("Backup currently running");
             pw.println("Last backup pass started: " + mLastBackupPass
                     + " (now = " + System.currentTimeMillis() + ')');
-            pw.println("  next scheduled: " + mNextBackupPass);
+            pw.println("  next scheduled: " + KeyValueBackupJob.nextScheduled());
 
             pw.println("Available transports:");
             final String[] transports = listAllTransports();
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
new file mode 100644
index 0000000..dc1c9d5
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.app.AlarmManager;
+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.os.RemoteException;
+import android.util.Slog;
+
+import java.util.Random;
+
+/**
+ * Job for scheduling key/value backup work.  This module encapsulates all
+ * of the policy around when those backup passes are executed.
+ */
+public class KeyValueBackupJob extends JobService {
+    private static final String TAG = "KeyValueBackupJob";
+    private static ComponentName sKeyValueJobService =
+            new ComponentName("android", KeyValueBackupJob.class.getName());
+    private static final int JOB_ID = 0x5039;
+
+    // Once someone asks for a backup, this is how long we hold off, batching
+    // up additional requests, before running the actual backup pass.  Privileged
+    // callers can always trigger an immediate pass via BackupManager.backupNow().
+    private static final long BATCH_INTERVAL = 4 * AlarmManager.INTERVAL_HOUR;
+
+    // Random variation in next-backup scheduling time to avoid server load spikes
+    private static final int FUZZ_MILLIS = 10 * 60 * 1000;
+
+    // Don't let the job scheduler defer forever; give it a (lenient) deadline
+    private static final long MAX_DEFERRAL = 1 * AlarmManager.INTERVAL_HOUR;
+
+    private static boolean sScheduled = false;
+    private static long sNextScheduled = 0;
+
+    public static void schedule(Context ctx) {
+        schedule(ctx, 0);
+    }
+
+    public static void schedule(Context ctx, long delay) {
+        synchronized (KeyValueBackupJob.class) {
+            if (!sScheduled) {
+                if (delay <= 0) {
+                    delay = BATCH_INTERVAL + new Random().nextInt(FUZZ_MILLIS);
+                }
+                if (BackupManagerService.DEBUG_SCHEDULING) {
+                    Slog.v(TAG, "Scheduling k/v pass in "
+                            + (delay / 1000 / 60) + " minutes");
+                }
+                JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+                JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService)
+                        .setMinimumLatency(delay)
+                        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .setOverrideDeadline(delay + MAX_DEFERRAL);
+                js.schedule(builder.build());
+
+                sNextScheduled = System.currentTimeMillis() + delay;
+                sScheduled = true;
+            }
+        }
+    }
+
+    public static void cancel(Context ctx) {
+        synchronized (KeyValueBackupJob.class) {
+            JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+            js.cancel(JOB_ID);
+            sNextScheduled = 0;
+            sScheduled = false;
+        }
+    }
+
+    public static long nextScheduled() {
+        synchronized (KeyValueBackupJob.class) {
+            return sNextScheduled;
+        }
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        synchronized (KeyValueBackupJob.class) {
+            sNextScheduled = 0;
+            sScheduled = false;
+        }
+
+        // Time to run a key/value backup!
+        Trampoline service = BackupManagerService.getInstance();
+        try {
+            service.backupNow();
+        } catch (RemoteException e) {}
+
+        // This was just a trigger; ongoing wakelock management is done by the
+        // rest of the backup system.
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // Intentionally empty; the job starting was just a trigger
+        return false;
+    }
+
+}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 8bd7132..2e84fbe 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -318,6 +318,8 @@
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
         BackupManagerService svc = mService;
         if (svc != null) {
             svc.dump(fd, pw, args);
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 5c45201..1a0fa34 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -9,6 +9,6 @@
     java/com/android/server/EventLogTags.logtags \
     java/com/android/server/am/EventLogTags.logtags
 
-LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 65a5c23..7d156df 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1606,7 +1606,7 @@
         if (mLastAlarmDeliveryTime <= 0) {
             return false;
         }
-        if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {
+        if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime < nowELAPSED) {
             // This is just a little paranoia, if somehow we have pending non-wakeup alarms
             // and the next delivery time is in the past, then just deliver them all.  This
             // avoids bugs where we get stuck in a loop trying to poll for alarms.
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 42a5195..17b4939 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -813,7 +813,8 @@
                                 .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
                         if (appInfo != null) {
                             pkgUid = appInfo.uid;
-                            isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+                            isPrivileged = (appInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
                         } else {
                             if ("media".equals(packageName)) {
                                 pkgUid = Process.MEDIA_UID;
@@ -996,7 +997,8 @@
                     ApplicationInfo appInfo = ActivityThread.getPackageManager()
                             .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
                     if (appInfo != null) {
-                        isPrivileged = (appInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+                        isPrivileged = (appInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
                     }
                 } else {
                     // Could not load data, don't add to cache so it will be loaded later.
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index bc31450..e6dc1c7 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -46,7 +46,6 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -292,7 +291,7 @@
                         }
                         canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
                         canvas.restore();
-                        atlasMap[mapIndex++] = bitmap.mNativeBitmap;
+                        atlasMap[mapIndex++] = bitmap.getSkBitmap();
                         atlasMap[mapIndex++] = entry.x;
                         atlasMap[mapIndex++] = entry.y;
                         atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 912a181..b3b4651 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -626,6 +626,22 @@
                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);
                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);
                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
+
+            } else if ("unplug".equals(args[0])) {
+                if (!mUpdatesStopped) {
+                    mLastBatteryProps.set(mBatteryProps);
+                }
+                mBatteryProps.chargerAcOnline = false;
+                mBatteryProps.chargerUsbOnline = false;
+                mBatteryProps.chargerWirelessOnline = false;
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mUpdatesStopped = true;
+                    processValuesLocked(false);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+
             } else if (args.length == 3 && "set".equals(args[0])) {
                 String key = args[1];
                 String value = args[2];
@@ -662,6 +678,7 @@
                 } catch (NumberFormatException ex) {
                     pw.println("Bad value: " + value);
                 }
+
             } else if (args.length == 1 && "reset".equals(args[0])) {
                 long ident = Binder.clearCallingIdentity();
                 try {
@@ -676,6 +693,7 @@
             } else {
                 pw.println("Dump current battery state, or:");
                 pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
+                pw.println("  unplug");
                 pw.println("  reset");
             }
         }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 32a6a2f..ef51ad6 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -55,8 +55,6 @@
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.List;
-import java.util.Vector;
 
 class BluetoothManagerService extends IBluetoothManager.Stub {
     private static final String TAG = "BluetoothManagerService";
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b72b29d..45694518 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
@@ -27,6 +26,7 @@
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -48,7 +48,6 @@
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
 import android.net.LinkProperties.CompareResult;
-import android.net.MobileDataStateTracker;
 import android.net.Network;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
@@ -59,12 +58,10 @@
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
-import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
 import android.net.Proxy;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
-import android.net.SamplingDataTracker;
 import android.net.UidRange;
 import android.net.Uri;
 import android.os.Binder;
@@ -101,6 +98,7 @@
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
 import com.android.internal.telephony.DctConstants;
 import com.android.internal.util.AsyncChannel;
@@ -153,9 +151,6 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
 
-    // network sampling debugging
-    private static final boolean SAMPLE_DBG = false;
-
     private static final boolean LOGD_RULES = false;
 
     // TODO: create better separation between radio types and network types
@@ -166,33 +161,10 @@
     private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
             "android.telephony.apn-restore";
 
-    // Default value if FAIL_FAST_TIME_MS is not set
-    private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000;
-    // system property that can override DEFAULT_FAIL_FAST_TIME_MS
-    private static final String FAIL_FAST_TIME_MS =
-            "persist.radio.fail_fast_time_ms";
-
-    private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED =
-            "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED";
-
-    private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0;
-
     // How long to delay to removal of a pending intent based request.
     // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
     private final int mReleasePendingIntentDelayMs;
 
-    private PendingIntent mSampleIntervalElapsedIntent;
-
-    // Set network sampling interval at 12 minutes, this way, even if the timers get
-    // aggregated, it will fire at around 15 minutes, which should allow us to
-    // aggregate this timer with other timers (specially the socket keep alive timers)
-    private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60);
-
-    // start network sampling a minute after booting ...
-    private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60);
-
-    AlarmManager mAlarmManager;
-
     private Tethering mTethering;
 
     private final PermissionMonitor mPermissionMonitor;
@@ -212,13 +184,6 @@
     /** Set of ifaces that are costly. */
     private HashSet<String> mMeteredIfaces = Sets.newHashSet();
 
-    /**
-     * Sometimes we want to refer to the individual network state
-     * trackers separately, and sometimes we just want to treat them
-     * abstractly.
-     */
-    private NetworkStateTracker mNetTrackers[];
-
     private Context mContext;
     private int mNetworkPreference;
     // 0 is full bad, 100 is full good
@@ -278,28 +243,11 @@
     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
 
     /**
-     * used internally to set external dependency met/unmet
-     * arg1 = ENABLED (met) or DISABLED (unmet)
-     * arg2 = NetworkType
-     */
-    private static final int EVENT_SET_DEPENDENCY_MET = 10;
-
-    /**
      * used internally to send a sticky broadcast delayed.
      */
     private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11;
 
     /**
-     * Used internally to disable fail fast of mobile data
-     */
-    private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
-
-    /**
-     * used internally to indicate that data sampling interval is up
-     */
-    private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
-
-    /**
      * PAC manager has received new port.
      */
     private static final int EVENT_PROXY_HAS_CHANGED = 16;
@@ -419,8 +367,6 @@
 
     private DataConnectionStats mDataConnectionStats;
 
-    private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
-
     TelephonyManager mTelephonyManager;
 
     // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
@@ -650,9 +596,6 @@
                 com.android.internal.R.integer.config_networkTransitionTimeout);
         mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
-        mNetTrackers = new NetworkStateTracker[
-                ConnectivityManager.MAX_NETWORK_TYPE+1];
-
         mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
 
         // TODO: What is the "correct" way to do determine if this is a wifi only device?
@@ -740,23 +683,6 @@
         mDataConnectionStats = new DataConnectionStats(mContext);
         mDataConnectionStats.startMonitoring();
 
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
-        mContext.registerReceiver(
-                new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        String action = intent.getAction();
-                        if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) {
-                            mHandler.sendMessage(mHandler.obtainMessage
-                                    (EVENT_SAMPLE_INTERVAL_ELAPSED));
-                        }
-                    }
-                },
-                new IntentFilter(filter));
-
         mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
 
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -782,15 +708,6 @@
         throw new IllegalStateException("No free netIds");
     }
 
-    private boolean teardown(NetworkStateTracker netTracker) {
-        if (netTracker.teardown()) {
-            netTracker.setTeardownRequested(true);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
     private NetworkState getFilteredNetworkState(int networkType, int uid) {
         NetworkInfo info = null;
         LinkProperties lp = null;
@@ -1350,22 +1267,6 @@
         return true;
     }
 
-    public void setDataDependency(int networkType, boolean met) {
-        enforceConnectivityInternalPermission();
-
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
-                (met ? ENABLED : DISABLED), networkType));
-    }
-
-    private void handleSetDependencyMet(int networkType, boolean met) {
-        if (mNetTrackers[networkType] != null) {
-            if (DBG) {
-                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
-            }
-            mNetTrackers[networkType].setDependencyMet(met);
-        }
-    }
-
     private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
         public void onUidRulesChanged(int uid, int uidRules) {
@@ -1406,21 +1307,6 @@
             if (LOGD_RULES) {
                 log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
             }
-
-            // kick off connectivity change broadcast for active network, since
-            // global background policy change is radical.
-            // TODO: Dead code; remove.
-            //
-            // final int networkType = mActiveDefaultNetwork;
-            // if (isNetworkTypeValid(networkType)) {
-            //     final NetworkStateTracker tracker = mNetTrackers[networkType];
-            //     if (tracker != null) {
-            //         final NetworkInfo info = tracker.getNetworkInfo();
-            //         if (info != null && info.isConnected()) {
-            //             sendConnectedBroadcast(info);
-            //         }
-            //     }
-            // }
         }
     };
 
@@ -1536,14 +1422,6 @@
     }
 
     void systemReady() {
-        // start network sampling ..
-        Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
-        intent.setPackage(mContext.getPackageName());
-
-        mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
-                SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0);
-        setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
-
         loadGlobalProxy();
 
         synchronized(this) {
@@ -2015,66 +1893,6 @@
                     }
                     break;
                 }
-                case NetworkStateTracker.EVENT_STATE_CHANGED: {
-                    info = (NetworkInfo) msg.obj;
-                    NetworkInfo.State state = info.getState();
-
-                    if (VDBG || (state == NetworkInfo.State.CONNECTED) ||
-                            (state == NetworkInfo.State.DISCONNECTED) ||
-                            (state == NetworkInfo.State.SUSPENDED)) {
-                        log("ConnectivityChange for " +
-                            info.getTypeName() + ": " +
-                            state + "/" + info.getDetailedState());
-                    }
-
-                    EventLogTags.writeConnectivityStateChanged(
-                            info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
-
-                    if (info.isConnectedToProvisioningNetwork()) {
-                        /**
-                         * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
-                         * for now its an in between network, its a network that
-                         * is actually a default network but we don't want it to be
-                         * announced as such to keep background applications from
-                         * trying to use it. It turns out that some still try so we
-                         * take the additional step of clearing any default routes
-                         * to the link that may have incorrectly setup by the lower
-                         * levels.
-                         */
-                        LinkProperties lp = getLinkPropertiesForType(info.getType());
-                        if (DBG) {
-                            log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
-                        }
-
-                        // Clear any default routes setup by the radio so
-                        // any activity by applications trying to use this
-                        // connection will fail until the provisioning network
-                        // is enabled.
-                        /*
-                        for (RouteInfo r : lp.getRoutes()) {
-                            removeRoute(lp, r, TO_DEFAULT_TABLE,
-                                        mNetTrackers[info.getType()].getNetwork().netId);
-                        }
-                        */
-                    } else if (state == NetworkInfo.State.DISCONNECTED) {
-                    } else if (state == NetworkInfo.State.SUSPENDED) {
-                    } else if (state == NetworkInfo.State.CONNECTED) {
-                    //    handleConnect(info);
-                    }
-                    notifyLockdownVpn(null);
-                    break;
-                }
-                case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
-                    info = (NetworkInfo) msg.obj;
-                    // TODO: Temporary allowing network configuration
-                    //       change not resetting sockets.
-                    //       @see bug/4455071
-                    /*
-                    handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()],
-                            false);
-                    */
-                    break;
-                }
             }
         }
     }
@@ -2439,34 +2257,11 @@
                     handleDeprecatedGlobalHttpProxy();
                     break;
                 }
-                case EVENT_SET_DEPENDENCY_MET: {
-                    boolean met = (msg.arg1 == ENABLED);
-                    handleSetDependencyMet(msg.arg2, met);
-                    break;
-                }
                 case EVENT_SEND_STICKY_BROADCAST_INTENT: {
                     Intent intent = (Intent)msg.obj;
                     sendStickyBroadcast(intent);
                     break;
                 }
-                case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: {
-                    int tag = mEnableFailFastMobileDataTag.get();
-                    if (msg.arg1 == tag) {
-                        MobileDataStateTracker mobileDst =
-                            (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE];
-                        if (mobileDst != null) {
-                            mobileDst.setEnableFailFastMobileData(msg.arg2);
-                        }
-                    } else {
-                        log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1
-                                + " != tag:" + tag);
-                    }
-                    break;
-                }
-                case EVENT_SAMPLE_INTERVAL_ELAPSED: {
-                    handleNetworkSamplingTimeout();
-                    break;
-                }
                 case EVENT_PROXY_HAS_CHANGED: {
                     handleApplyDefaultProxy((ProxyInfo)msg.obj);
                     break;
@@ -2979,7 +2774,6 @@
      * Return the information of the ongoing legacy VPN. This method is used
      * by VpnSettings and not available in ConnectivityManager. Permissions
      * are checked in Vpn class.
-     * @hide
      */
     @Override
     public LegacyVpnInfo getLegacyVpnInfo() {
@@ -2991,6 +2785,56 @@
     }
 
     /**
+     * Return the information of all ongoing VPNs. This method is used by NetworkStatsService
+     * and not available in ConnectivityManager.
+     */
+    @Override
+    public VpnInfo[] getAllVpnInfo() {
+        enforceConnectivityInternalPermission();
+        if (mLockdownEnabled) {
+            return new VpnInfo[0];
+        }
+
+        synchronized(mVpns) {
+            List<VpnInfo> infoList = new ArrayList<>();
+            for (int i = 0; i < mVpns.size(); i++) {
+                VpnInfo info = createVpnInfo(mVpns.valueAt(i));
+                if (info != null) {
+                    infoList.add(info);
+                }
+            }
+            return infoList.toArray(new VpnInfo[infoList.size()]);
+        }
+    }
+
+    /**
+     * @return VPN information for accounting, or null if we can't retrieve all required
+     *         information, e.g primary underlying iface.
+     */
+    @Nullable
+    private VpnInfo createVpnInfo(Vpn vpn) {
+        VpnInfo info = vpn.getVpnInfo();
+        if (info == null) {
+            return null;
+        }
+        Network[] underlyingNetworks = vpn.getUnderlyingNetworks();
+        // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
+        // the underlyingNetworks list.
+        if (underlyingNetworks == null) {
+            NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+            if (defaultNetwork != null && defaultNetwork.linkProperties != null) {
+                info.primaryUnderlyingIface = getDefaultNetwork().linkProperties.getInterfaceName();
+            }
+        } else if (underlyingNetworks.length > 0) {
+            LinkProperties linkProperties = getLinkProperties(underlyingNetworks[0]);
+            if (linkProperties != null) {
+                info.primaryUnderlyingIface = linkProperties.getInterfaceName();
+            }
+        }
+        return info.primaryUnderlyingIface == null ? null : info;
+    }
+
+    /**
      * Returns the information of the ongoing VPN. This method is used by VpnDialogs and
      * not available in ConnectivityManager.
      * Permissions are checked in Vpn class.
@@ -3066,14 +2910,6 @@
         }
     }
 
-    public void supplyMessenger(int networkType, Messenger messenger) {
-        enforceConnectivityInternalPermission();
-
-        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
-            mNetTrackers[networkType].supplyMessenger(messenger);
-        }
-    }
-
     public int findConnectionTypeForIface(String iface) {
         enforceConnectivityInternalPermission();
 
@@ -3091,23 +2927,6 @@
         return ConnectivityManager.TYPE_NONE;
     }
 
-    /**
-     * Have mobile data fail fast if enabled.
-     *
-     * @param enabled DctConstants.ENABLED/DISABLED
-     */
-    private void setEnableFailFastMobileData(int enabled) {
-        int tag;
-
-        if (enabled == DctConstants.ENABLED) {
-            tag = mEnableFailFastMobileDataTag.incrementAndGet();
-        } else {
-            tag = mEnableFailFastMobileDataTag.get();
-        }
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag,
-                         enabled));
-    }
-
     @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
@@ -3392,69 +3211,6 @@
         }
     };
 
-    /* Infrastructure for network sampling */
-
-    private void handleNetworkSamplingTimeout() {
-
-        if (SAMPLE_DBG) log("Sampling interval elapsed, updating statistics ..");
-
-        // initialize list of interfaces ..
-        Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
-                new HashMap<String, SamplingDataTracker.SamplingSnapshot>();
-        for (NetworkStateTracker tracker : mNetTrackers) {
-            if (tracker != null) {
-                String ifaceName = tracker.getNetworkInterfaceName();
-                if (ifaceName != null) {
-                    mapIfaceToSample.put(ifaceName, null);
-                }
-            }
-        }
-
-        // Read samples for all interfaces
-        SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample);
-
-        // process samples for all networks
-        for (NetworkStateTracker tracker : mNetTrackers) {
-            if (tracker != null) {
-                String ifaceName = tracker.getNetworkInterfaceName();
-                SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName);
-                if (ss != null) {
-                    // end the previous sampling cycle
-                    tracker.stopSampling(ss);
-                    // start a new sampling cycle ..
-                    tracker.startSampling(ss);
-                }
-            }
-        }
-
-        if (SAMPLE_DBG) log("Done.");
-
-        int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
-                DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
-
-        if (SAMPLE_DBG) {
-            log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
-        }
-
-        setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
-    }
-
-    /**
-     * Sets a network sampling alarm.
-     */
-    void setAlarm(int timeoutInMilliseconds, PendingIntent intent) {
-        long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
-        int alarmType;
-        if (Resources.getSystem().getBoolean(
-                R.bool.config_networkSamplingWakesDevice)) {
-            alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
-        } else {
-            alarmType = AlarmManager.ELAPSED_REALTIME;
-        }
-        mAlarmManager.set(alarmType, wakeupTime, intent);
-    }
-
     private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
             new HashMap<Messenger, NetworkFactoryInfo>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
@@ -4513,8 +4269,13 @@
     public boolean setUnderlyingNetworksForVpn(Network[] networks) {
         throwIfLockdownEnabled();
         int user = UserHandle.getUserId(Binder.getCallingUid());
+        boolean success;
         synchronized (mVpns) {
-            return mVpns.get(user).setUnderlyingNetworks(networks);
+            success = mVpns.get(user).setUnderlyingNetworks(networks);
         }
+        if (success) {
+            notifyIfacesChanged();
+        }
+        return success;
     }
 }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index f04487e..983d83a 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -216,3 +216,8 @@
 # ---------------------------
 2755 fstrim_start (time|2|3)
 2756 fstrim_finish (time|2|3)
+
+# ---------------------------
+# AudioService.java
+# ---------------------------
+40000 volume_changed (stream|1), (prev_level|1), (level|1), (max_level|1), (caller|3)
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index be83b9b..16834855 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -60,8 +60,6 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
-import android.location.GpsMeasurementsEvent;
-import android.location.GpsNavigationMessageEvent;
 import android.location.IGpsMeasurementsListener;
 import android.location.IGpsNavigationMessageListener;
 import android.location.IGpsStatusListener;
@@ -1452,14 +1450,13 @@
         if (receiver == null) {
             receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
                     hideFromAppOps);
-            mReceivers.put(binder, receiver);
-
             try {
                 receiver.getListener().asBinder().linkToDeath(receiver, 0);
             } catch (RemoteException e) {
                 Slog.e(TAG, "linkToDeath failed:", e);
                 return null;
             }
+            mReceivers.put(binder, receiver);
         }
         return receiver;
     }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 77662cc..53c87a2 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import android.app.admin.DevicePolicyManager;
+import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -45,10 +47,10 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -81,6 +83,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_STARTING);
+        filter.addAction(Intent.ACTION_USER_REMOVED);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -117,6 +120,11 @@
             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mStorage.prefetchUser(userHandle);
+            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                if (userHandle > 0) {
+                    removeUser(userHandle);
+                }
             }
         }
     };
@@ -179,6 +187,31 @@
                 setString("migrated_user_specific", "true", 0);
                 Slog.i(TAG, "Migrated per-user lock settings to new location");
             }
+
+            // Migrates biometric weak such that the fallback mechanism becomes the primary.
+            if (getString("migrated_biometric_weak", null, 0) == null) {
+                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+                List<UserInfo> users = um.getUsers();
+                for (int i = 0; i < users.size(); i++) {
+                    int userId = users.get(i).id;
+                    long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
+                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                            userId);
+                    long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
+                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                            userId);
+                    if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
+                        setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
+                                alternateType,
+                                userId);
+                    }
+                    setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
+                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+                            userId);
+                }
+                setString("migrated_biometric_weak", "true", 0);
+                Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
+            }
         } catch (RemoteException re) {
             Slog.e(TAG, "Unable to migrate old data", re);
         }
@@ -194,6 +227,7 @@
 
     private final void checkReadPermission(String requestedKey, int userId) {
         final int callingUid = Binder.getCallingUid();
+
         for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
             String key = READ_PROFILE_PROTECTED_SETTINGS[i];
             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
@@ -203,6 +237,16 @@
                         + requestedKey + " for user " + userId);
             }
         }
+
+        for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
+            String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
+            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("uid=" + callingUid
+                        + " needs permission " + PERMISSION + " to read "
+                        + requestedKey + " for user " + userId);
+            }
+        }
     }
 
     @Override
@@ -225,13 +269,16 @@
 
     private void setStringUnchecked(String key, int userId, String value) {
         mStorage.writeKeyValue(key, value, userId);
+        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
+            BackupManager.dataChanged("com.android.providers.settings");
+        }
     }
 
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
         checkReadPermission(key, userId);
 
-        String value = mStorage.readKeyValue(key, null, userId);
+        String value = getStringUnchecked(key, null, userId);
         return TextUtils.isEmpty(value) ?
                 defaultValue : (value.equals("1") || value.equals("true"));
     }
@@ -240,7 +287,7 @@
     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
         checkReadPermission(key, userId);
 
-        String value = mStorage.readKeyValue(key, null, userId);
+        String value = getStringUnchecked(key, null, userId);
         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
     }
 
@@ -248,6 +295,14 @@
     public String getString(String key, String defaultValue, int userId) throws RemoteException {
         checkReadPermission(key, userId);
 
+        return getStringUnchecked(key, defaultValue, userId);
+    }
+
+    public String getStringUnchecked(String key, String defaultValue, int userId) {
+        if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
+            return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
+        }
+
         return mStorage.readKeyValue(key, defaultValue, userId);
     }
 
@@ -370,7 +425,7 @@
         }
 
         try {
-            if (mLockPatternUtils.isLockPatternEnabled()) {
+            if (mLockPatternUtils.isLockPatternEnabled(userId)) {
                 if (checkPattern(password, userId)) {
                     return true;
                 }
@@ -379,7 +434,7 @@
         }
 
         try {
-            if (mLockPatternUtils.isLockPasswordEnabled()) {
+            if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
                 if (checkPassword(password, userId)) {
                     return true;
                 }
@@ -390,10 +445,7 @@
         return false;
     }
 
-    @Override
-    public void removeUser(int userId) {
-        checkWritePermission(userId);
-
+    private void removeUser(int userId) {
         mStorage.removeUser(userId);
 
         final KeyStore ks = KeyStore.getInstance();
@@ -420,12 +472,23 @@
         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
     };
 
-    // These are protected with a read permission
+    // Reading these settings needs the profile permission
     private static final String[] READ_PROFILE_PROTECTED_SETTINGS = new String[] {
         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
         Secure.LOCK_SCREEN_OWNER_INFO
     };
 
+    // Reading these settings needs the same permission as checking the password
+    private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
+            LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
+            LockPatternUtils.PASSWORD_HISTORY_KEY,
+    };
+
+    private static final String[] SETTINGS_TO_BACKUP = new String[] {
+        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+        Secure.LOCK_SCREEN_OWNER_INFO
+    };
+
     private IMountService getMountService() {
         final IBinder service = ServiceManager.getService("mount");
         if (service != null) {
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index c03bb58..d81daa9 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -238,12 +238,21 @@
 
     public void writePatternHash(byte[] hash, int userId) {
         writeFile(getLockPatternFilename(userId), hash);
+        clearPasswordHash(userId);
+    }
+
+    private void clearPatternHash(int userId) {
+        writeFile(getLockPatternFilename(userId), null);
     }
 
     public void writePasswordHash(byte[] hash, int userId) {
         writeFile(getLockPasswordFilename(userId), hash);
+        clearPatternHash(userId);
     }
 
+    private void clearPasswordHash(int userId) {
+        writeFile(getLockPasswordFilename(userId), null);
+    }
 
     @VisibleForTesting
     String getLockPatternFilename(int userId) {
@@ -279,16 +288,15 @@
         return userId;
     }
 
-
     public void removeUser(int userId) {
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final UserInfo parentInfo = um.getProfileParent(userId);
 
-        synchronized (mFileWriteLock) {
-            if (parentInfo == null) {
-                // This user owns its lock settings files - safe to delete them
+        if (parentInfo == null) {
+            // This user owns its lock settings files - safe to delete them
+            synchronized (mFileWriteLock) {
                 String name = getLockPasswordFilename(userId);
                 File file = new File(name);
                 if (file.exists()) {
diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java
new file mode 100644
index 0000000..3418930
--- /dev/null
+++ b/services/core/java/com/android/server/MidiService.java
@@ -0,0 +1,649 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.XmlResourceParser;
+import android.media.midi.IMidiDeviceListener;
+import android.media.midi.IMidiDeviceServer;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceService;
+import android.media.midi.MidiDeviceStatus;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class MidiService extends IMidiManager.Stub {
+    private static final String TAG = "MidiService";
+
+    private final Context mContext;
+
+    // list of all our clients, keyed by Binder token
+    private final HashMap<IBinder, Client> mClients = new HashMap<IBinder, Client>();
+
+    // list of all devices, keyed by MidiDeviceInfo
+    private final HashMap<MidiDeviceInfo, Device> mDevicesByInfo
+            = new HashMap<MidiDeviceInfo, Device>();
+
+    // list of all devices, keyed by IMidiDeviceServer
+    private final HashMap<IBinder, Device> mDevicesByServer = new HashMap<IBinder, Device>();
+
+    // used for assigning IDs to MIDI devices
+    private int mNextDeviceId = 1;
+
+    private final PackageManager mPackageManager;
+
+    // PackageMonitor for listening to package changes
+    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageAdded(String packageName, int uid) {
+            addPackageDeviceServers(packageName);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            removePackageDeviceServers(packageName);
+            addPackageDeviceServers(packageName);
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            removePackageDeviceServers(packageName);
+        }
+    };
+
+    private final class Client implements IBinder.DeathRecipient {
+        // Binder token for this client
+        private final IBinder mToken;
+        // This client's UID
+        private final int mUid;
+        // This client's PID
+        private final int mPid;
+        // List of all receivers for this client
+        private final ArrayList<IMidiDeviceListener> mListeners
+                = new ArrayList<IMidiDeviceListener>();
+
+        public Client(IBinder token) {
+            mToken = token;
+            mUid = Binder.getCallingUid();
+            mPid = Binder.getCallingPid();
+        }
+
+        public int getUid() {
+            return mUid;
+        }
+
+        public void addListener(IMidiDeviceListener listener) {
+            mListeners.add(listener);
+        }
+
+        public void removeListener(IMidiDeviceListener listener) {
+            mListeners.remove(listener);
+            if (mListeners.size() == 0) {
+                removeClient(mToken);
+            }
+        }
+
+        public void deviceAdded(Device device) {
+            // ignore private devices that our client cannot access
+            if (!device.isUidAllowed(mUid)) return;
+
+            MidiDeviceInfo deviceInfo = device.getDeviceInfo();
+            try {
+                for (IMidiDeviceListener listener : mListeners) {
+                    listener.onDeviceAdded(deviceInfo);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "remote exception", e);
+            }
+        }
+
+        public void deviceRemoved(Device device) {
+            // ignore private devices that our client cannot access
+            if (!device.isUidAllowed(mUid)) return;
+
+            MidiDeviceInfo deviceInfo = device.getDeviceInfo();
+            try {
+                for (IMidiDeviceListener listener : mListeners) {
+                    listener.onDeviceRemoved(deviceInfo);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "remote exception", e);
+            }
+        }
+
+        public void deviceStatusChanged(Device device, MidiDeviceStatus status) {
+            // ignore private devices that our client cannot access
+            if (!device.isUidAllowed(mUid)) return;
+
+            try {
+                for (IMidiDeviceListener listener : mListeners) {
+                    listener.onDeviceStatusChanged(status);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "remote exception", e);
+            }
+        }
+
+        public void binderDied() {
+            removeClient(mToken);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("Client: UID: ");
+            sb.append(mUid);
+            sb.append(" PID: ");
+            sb.append(mPid);
+            sb.append(" listener count: ");
+            sb.append(mListeners.size());
+            return sb.toString();
+        }
+    }
+
+    private Client getClient(IBinder token) {
+        synchronized (mClients) {
+            Client client = mClients.get(token);
+            if (client == null) {
+                client = new Client(token);
+
+                try {
+                    token.linkToDeath(client, 0);
+                } catch (RemoteException e) {
+                    return null;
+                }
+                mClients.put(token, client);
+            }
+            return client;
+        }
+    }
+
+    private void removeClient(IBinder token) {
+        mClients.remove(token);
+    }
+
+    private final class Device implements IBinder.DeathRecipient {
+        private final IMidiDeviceServer mServer;
+        private final MidiDeviceInfo mDeviceInfo;
+        private MidiDeviceStatus mDeviceStatus;
+        private IBinder mDeviceStatusToken;
+        // ServiceInfo for the device's MidiDeviceServer implementation (virtual devices only)
+        private final ServiceInfo mServiceInfo;
+        // UID of device implementation
+        private final int mUid;
+
+        public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
+                ServiceInfo serviceInfo, int uid) {
+            mServer = server;
+            mDeviceInfo = deviceInfo;
+            mServiceInfo = serviceInfo;
+            mUid = uid;
+        }
+
+        public MidiDeviceInfo getDeviceInfo() {
+            return mDeviceInfo;
+        }
+
+        public MidiDeviceStatus getDeviceStatus() {
+            return mDeviceStatus;
+        }
+
+        public void setDeviceStatus(IBinder token, MidiDeviceStatus status) {
+            mDeviceStatus = status;
+
+            if (mDeviceStatusToken == null && token != null) {
+                // register a death recipient so we can clear the status when the device dies
+                try {
+                    token.linkToDeath(new IBinder.DeathRecipient() {
+                        @Override
+                        public void binderDied() {
+                            // reset to default status and clear the token
+                            mDeviceStatus = new MidiDeviceStatus(mDeviceInfo);
+                            mDeviceStatusToken = null;
+                            notifyDeviceStatusChanged(Device.this, mDeviceStatus);
+                        }
+                    }, 0);
+                    mDeviceStatusToken = token;
+                } catch (RemoteException e) {
+                    // reset to default status
+                    mDeviceStatus = new MidiDeviceStatus(mDeviceInfo);
+                }
+            }
+        }
+
+        public IMidiDeviceServer getDeviceServer() {
+            return mServer;
+        }
+
+        public ServiceInfo getServiceInfo() {
+            return mServiceInfo;
+        }
+
+        public String getPackageName() {
+            return (mServiceInfo == null ? null : mServiceInfo.packageName);
+        }
+
+        public int getUid() {
+            return mUid;
+        }
+
+        public boolean isUidAllowed(int uid) {
+            return (!mDeviceInfo.isPrivate() || mUid == uid);
+        }
+
+        public void binderDied() {
+            synchronized (mDevicesByInfo) {
+                removeDeviceLocked(this);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("Device: ");
+            sb.append(mDeviceInfo);
+            sb.append(" UID: ");
+            sb.append(mUid);
+            return sb.toString();
+        }
+    }
+
+    public MidiService(Context context) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mPackageMonitor.register(context, null, true);
+
+        Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
+        List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent,
+                PackageManager.GET_META_DATA);
+        if (resolveInfos != null) {
+            int count = resolveInfos.size();
+            for (int i = 0; i < count; i++) {
+                ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+                if (serviceInfo != null) {
+                    addPackageDeviceServer(serviceInfo);
+                }
+            }
+        }
+   }
+
+    @Override
+    public void registerListener(IBinder token, IMidiDeviceListener listener) {
+        Client client = getClient(token);
+        if (client == null) return;
+        client.addListener(listener);
+    }
+
+    @Override
+    public void unregisterListener(IBinder token, IMidiDeviceListener listener) {
+        Client client = getClient(token);
+        if (client == null) return;
+        client.removeListener(listener);
+    }
+
+    private static final MidiDeviceInfo[] EMPTY_DEVICE_INFO_ARRAY = new MidiDeviceInfo[0];
+
+    public MidiDeviceInfo[] getDeviceList() {
+        ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>();
+        int uid = Binder.getCallingUid();
+
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                if (device.isUidAllowed(uid)) {
+                    deviceInfos.add(device.getDeviceInfo());
+                }
+            }
+        }
+
+        return deviceInfos.toArray(EMPTY_DEVICE_INFO_ARRAY);
+    }
+
+    @Override
+    public IMidiDeviceServer openDevice(IBinder token, MidiDeviceInfo deviceInfo) {
+        Device device = mDevicesByInfo.get(deviceInfo);
+        if (device == null) {
+            Log.e(TAG, "device not found in openDevice: " + deviceInfo);
+            return null;
+        }
+
+        if (!device.isUidAllowed(Binder.getCallingUid())) {
+            throw new SecurityException("Attempt to open private device with wrong UID");
+        }
+
+        return device.getDeviceServer();
+    }
+
+    @Override
+    public MidiDeviceInfo registerDeviceServer(IMidiDeviceServer server, int numInputPorts,
+            int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
+            Bundle properties, int type) {
+        int uid = Binder.getCallingUid();
+        if (type != MidiDeviceInfo.TYPE_VIRTUAL && uid != Process.SYSTEM_UID) {
+            throw new SecurityException("only system can create non-virtual devices");
+        }
+
+        synchronized (mDevicesByInfo) {
+            return addDeviceLocked(type, numInputPorts, numOutputPorts, inputPortNames,
+                    outputPortNames, properties, server, null, false, uid);
+        }
+    }
+
+    @Override
+    public void unregisterDeviceServer(IMidiDeviceServer server) {
+        synchronized (mDevicesByInfo) {
+            Device device = mDevicesByServer.get(server.asBinder());
+            if (device != null) {
+                removeDeviceLocked(device);
+            }
+        }
+    }
+
+    @Override
+    public MidiDeviceInfo getServiceDeviceInfo(String packageName, String className) {
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                 ServiceInfo serviceInfo = device.getServiceInfo();
+                 if (serviceInfo != null &&
+                        packageName.equals(serviceInfo.packageName) &&
+                        className.equals(serviceInfo.name)) {
+                    return device.getDeviceInfo();
+                }
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public MidiDeviceStatus getDeviceStatus(MidiDeviceInfo deviceInfo) {
+        Device device = mDevicesByInfo.get(deviceInfo);
+        if (device == null) {
+            throw new IllegalArgumentException("no such device for " + deviceInfo);
+        }
+        return device.getDeviceStatus();
+    }
+
+    @Override
+    public void setDeviceStatus(IBinder token, MidiDeviceStatus status) {
+        MidiDeviceInfo deviceInfo = status.getDeviceInfo();
+        Device device = mDevicesByInfo.get(deviceInfo);
+        if (device == null) {
+            // Just return quietly here if device no longer exists
+            return;
+        }
+        if (Binder.getCallingUid() != device.getUid()) {
+            throw new SecurityException("setDeviceStatus() caller UID " + Binder.getCallingUid()
+                    + " does not match device's UID " + device.getUid());
+        }
+        device.setDeviceStatus(token, status);
+        notifyDeviceStatusChanged(device, status);
+    }
+
+    private void notifyDeviceStatusChanged(Device device, MidiDeviceStatus status) {
+        synchronized (mClients) {
+            for (Client c : mClients.values()) {
+                c.deviceStatusChanged(device, status);
+            }
+        }
+    }
+
+    // synchronize on mDevicesByInfo
+    private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts,
+            String[] inputPortNames, String[] outputPortNames, Bundle properties,
+            IMidiDeviceServer server, ServiceInfo serviceInfo,
+            boolean isPrivate, int uid) {
+
+        int id = mNextDeviceId++;
+        MidiDeviceInfo deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts,
+                inputPortNames, outputPortNames, properties, isPrivate);
+        Device device = new Device(server, deviceInfo, serviceInfo, uid);
+
+        if (server != null) {
+            IBinder binder = server.asBinder();
+            try {
+                binder.linkToDeath(device, 0);
+            } catch (RemoteException e) {
+                return null;
+            }
+            mDevicesByServer.put(binder, device);
+        }
+        mDevicesByInfo.put(deviceInfo, device);
+
+        synchronized (mClients) {
+            for (Client c : mClients.values()) {
+                c.deviceAdded(device);
+            }
+        }
+
+        return deviceInfo;
+    }
+
+    // synchronize on mDevicesByInfo
+    private void removeDeviceLocked(Device device) {
+        if (mDevicesByInfo.remove(device.getDeviceInfo()) != null) {
+            IMidiDeviceServer server = device.getDeviceServer();
+            if (server != null) {
+                mDevicesByServer.remove(server);
+            }
+
+            synchronized (mClients) {
+                for (Client c : mClients.values()) {
+                    c.deviceRemoved(device);
+                }
+            }
+        }
+    }
+
+    private void addPackageDeviceServers(String packageName) {
+        PackageInfo info;
+
+        try {
+            info = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+            return;
+        }
+
+        ServiceInfo[] services = info.services;
+        if (services == null) return;
+        for (int i = 0; i < services.length; i++) {
+            addPackageDeviceServer(services[i]);
+        }
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    private void addPackageDeviceServer(ServiceInfo serviceInfo) {
+        XmlResourceParser parser = null;
+
+        try {
+            parser = serviceInfo.loadXmlMetaData(mPackageManager,
+                    MidiDeviceService.SERVICE_INTERFACE);
+            if (parser == null) return;
+
+            Bundle properties = null;
+            int numInputPorts = 0;
+            int numOutputPorts = 0;
+            boolean isPrivate = false;
+            ArrayList<String> inputPortNames = new ArrayList<String>();
+            ArrayList<String> outputPortNames = new ArrayList<String>();
+
+            while (true) {
+                int eventType = parser.next();
+                if (eventType == XmlPullParser.END_DOCUMENT) {
+                    break;
+                } else if (eventType == XmlPullParser.START_TAG) {
+                    String tagName = parser.getName();
+                    if ("device".equals(tagName)) {
+                        if (properties != null) {
+                            Log.w(TAG, "nested <device> elements in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        properties = new Bundle();
+                        properties.putParcelable(MidiDeviceInfo.PROPERTY_SERVICE_INFO, serviceInfo);
+                        numInputPorts = 0;
+                        numOutputPorts = 0;
+                        isPrivate = false;
+
+                        int count = parser.getAttributeCount();
+                        for (int i = 0; i < count; i++) {
+                            String name = parser.getAttributeName(i);
+                            String value = parser.getAttributeValue(i);
+                            if ("private".equals(name)) {
+                                isPrivate = "true".equals(value);
+                            } else {
+                                properties.putString(name, value);
+                            }
+                        }
+                    } else if ("input-port".equals(tagName)) {
+                        if (properties == null) {
+                            Log.w(TAG, "<input-port> outside of <device> in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        numInputPorts++;
+
+                        String portName = null;
+                        int count = parser.getAttributeCount();
+                        for (int i = 0; i < count; i++) {
+                            String name = parser.getAttributeName(i);
+                            String value = parser.getAttributeValue(i);
+                            if ("name".equals(name)) {
+                                portName = value;
+                                break;
+                            }
+                        }
+                        inputPortNames.add(portName);
+                    } else if ("output-port".equals(tagName)) {
+                        if (properties == null) {
+                            Log.w(TAG, "<output-port> outside of <device> in metadata for "
+                                + serviceInfo.packageName);
+                            continue;
+                        }
+                        numOutputPorts++;
+
+                        String portName = null;
+                        int count = parser.getAttributeCount();
+                        for (int i = 0; i < count; i++) {
+                            String name = parser.getAttributeName(i);
+                            String value = parser.getAttributeValue(i);
+                            if ("name".equals(name)) {
+                                portName = value;
+                                break;
+                            }
+                        }
+                        outputPortNames.add(portName);
+                    }
+                } else if (eventType == XmlPullParser.END_TAG) {
+                    String tagName = parser.getName();
+                    if ("device".equals(tagName)) {
+                        if (properties != null) {
+                            if (numInputPorts == 0 && numOutputPorts == 0) {
+                                Log.w(TAG, "<device> with no ports in metadata for "
+                                    + serviceInfo.packageName);
+                                continue;
+                            }
+
+                            int uid;
+                            try {
+                                ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+                                        serviceInfo.packageName, 0);
+                                uid = appInfo.uid;
+                            } catch (PackageManager.NameNotFoundException e) {
+                                Log.e(TAG, "could not fetch ApplicationInfo for "
+                                        + serviceInfo.packageName);
+                                continue;
+                            }
+
+                            synchronized (mDevicesByInfo) {
+                                addDeviceLocked(MidiDeviceInfo.TYPE_VIRTUAL,
+                                    numInputPorts, numOutputPorts,
+                                    inputPortNames.toArray(EMPTY_STRING_ARRAY),
+                                    outputPortNames.toArray(EMPTY_STRING_ARRAY),
+                                    properties, null, serviceInfo, isPrivate, uid);
+                            }
+                            // setting properties to null signals that we are no longer
+                            // processing a <device>
+                            properties = null;
+                            inputPortNames.clear();
+                            outputPortNames.clear();
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Unable to load component info " + serviceInfo.toString(), e);
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+
+    private void removePackageDeviceServers(String packageName) {
+        synchronized (mDevicesByInfo) {
+            for (Device device : mDevicesByInfo.values()) {
+                if (packageName.equals(device.getPackageName())) {
+                    removeDeviceLocked(device);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+
+        pw.println("MIDI Manager State:");
+        pw.increaseIndent();
+
+        pw.println("Devices:");
+        pw.increaseIndent();
+        for (Device device : mDevicesByInfo.values()) {
+            pw.println(device.toString());
+        }
+        pw.decreaseIndent();
+
+        pw.println("Clients:");
+        pw.increaseIndent();
+        for (Client client : mClients.values()) {
+            pw.println(client.toString());
+        }
+        pw.decreaseIndent();
+    }
+}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 6c981c0..1e3b46b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -76,9 +76,8 @@
 import com.android.server.pm.UserManagerService;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
+import libcore.util.HexEncoding;
 
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.DecoderException;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -892,8 +891,7 @@
 
         // Temporary workaround for http://b/17945169.
         Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
-        SystemProperties.set("persist.sys.language", locale.getLanguage());
-        SystemProperties.set("persist.sys.country", locale.getCountry());
+        SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
     }
 
     /**
@@ -2204,25 +2202,21 @@
         }
     }
 
-    private String toHex(String password) {
+    private static String toHex(String password) {
         if (password == null) {
-            return new String();
+            return "";
         }
         byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
-        return new String(Hex.encodeHex(bytes));
+        return new String(HexEncoding.encode(bytes));
     }
 
-    private String fromHex(String hexPassword) {
+    private static String fromHex(String hexPassword) throws IllegalArgumentException {
         if (hexPassword == null) {
             return null;
         }
 
-        try {
-            byte[] bytes = Hex.decodeHex(hexPassword.toCharArray());
-            return new String(bytes, StandardCharsets.UTF_8);
-        } catch (DecoderException e) {
-            return null;
-        }
+        final byte[] bytes = HexEncoding.decode(hexPassword.toCharArray(), false);
+        return new String(bytes, StandardCharsets.UTF_8);
     }
 
     @Override
@@ -2424,9 +2418,16 @@
         final NativeDaemonEvent event;
         try {
             event = mConnector.execute("cryptfs", "getpw");
+            if ("-1".equals(event.getMessage())) {
+                // -1 equals no password
+                return null;
+            }
             return fromHex(event.getMessage());
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Invalid response to getPassword");
+            return null;
         }
     }
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 0437a2a..7b542be 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -24,9 +24,6 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
-import static android.net.RouteInfo.RTN_THROW;
-import static android.net.RouteInfo.RTN_UNICAST;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
@@ -38,6 +35,7 @@
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
+import android.app.ActivityManagerNative;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetworkManagementEventObserver;
@@ -61,6 +59,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -70,9 +69,12 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.HexDump;
 import com.android.internal.util.Preconditions;
 import com.android.server.NativeDaemonConnector.Command;
 import com.android.server.NativeDaemonConnector.SensitiveArg;
@@ -87,8 +89,6 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
 import java.net.NetworkInterface;
@@ -145,6 +145,7 @@
         public static final int InterfaceAddressChange    = 614;
         public static final int InterfaceDnsServerInfo    = 615;
         public static final int RouteChange               = 616;
+        public static final int StrictCleartext           = 617;
     }
 
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
@@ -174,12 +175,19 @@
     private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
 
     private Object mQuotaLock = new Object();
+
     /** Set of interfaces with active quotas. */
+    @GuardedBy("mQuotaLock")
     private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
     /** Set of interfaces with active alerts. */
+    @GuardedBy("mQuotaLock")
     private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
     /** Set of UIDs with active reject rules. */
+    @GuardedBy("mQuotaLock")
     private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+    /** Set of UIDs with cleartext penalties. */
+    @GuardedBy("mQuotaLock")
+    private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
 
     private Object mIdleTimerLock = new Object();
     /** Set of interfaces with active idle timers. */
@@ -198,6 +206,7 @@
 
     private volatile boolean mBandwidthControlEnabled;
     private volatile boolean mFirewallEnabled;
+    private volatile boolean mStrictEnabled;
 
     private boolean mMobileActivityFromRadio = false;
     private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
@@ -495,11 +504,18 @@
             }
         }
 
+        try {
+            mConnector.execute("strict", "enable");
+            mStrictEnabled = true;
+        } catch (NativeDaemonConnectorException e) {
+            Log.wtf(TAG, "Failed strict enable", e);
+        }
+
         // push any existing quota or UID rules
         synchronized (mQuotaLock) {
             int size = mActiveQuotas.size();
             if (size > 0) {
-                Slog.d(TAG, "pushing " + size + " active quota rules");
+                Slog.d(TAG, "Pushing " + size + " active quota rules");
                 final HashMap<String, Long> activeQuotas = mActiveQuotas;
                 mActiveQuotas = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
@@ -509,7 +525,7 @@
 
             size = mActiveAlerts.size();
             if (size > 0) {
-                Slog.d(TAG, "pushing " + size + " active alert rules");
+                Slog.d(TAG, "Pushing " + size + " active alert rules");
                 final HashMap<String, Long> activeAlerts = mActiveAlerts;
                 mActiveAlerts = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
@@ -519,13 +535,23 @@
 
             size = mUidRejectOnQuota.size();
             if (size > 0) {
-                Slog.d(TAG, "pushing " + size + " active uid rules");
+                Slog.d(TAG, "Pushing " + size + " active UID rules");
                 final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
                 mUidRejectOnQuota = new SparseBooleanArray();
                 for (int i = 0; i < uidRejectOnQuota.size(); i++) {
                     setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
                 }
             }
+
+            size = mUidCleartextPolicy.size();
+            if (size > 0) {
+                Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
+                final SparseIntArray local = mUidCleartextPolicy;
+                mUidCleartextPolicy = new SparseIntArray();
+                for (int i = 0; i < local.size(); i++) {
+                    setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
+                }
+            }
         }
 
         // TODO: Push any existing firewall state
@@ -792,6 +818,14 @@
                     }
                     throw new IllegalStateException(errorMessage);
                     // break;
+            case NetdResponseCode.StrictCleartext:
+                final int uid = Integer.parseInt(cooked[1]);
+                final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
+                try {
+                    ActivityManagerNative.getDefault().notifyCleartextNetwork(uid, firstPacket);
+                } catch (RemoteException ignored) {
+                }
+                break;
             default: break;
             }
             return false;
@@ -1674,6 +1708,49 @@
     }
 
     @Override
+    public void setUidCleartextNetworkPolicy(int uid, int policy) {
+        if (Binder.getCallingUid() != uid) {
+            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        }
+
+        synchronized (mQuotaLock) {
+            final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
+            if (oldPolicy == policy) {
+                return;
+            }
+
+            if (!mStrictEnabled) {
+                // Module isn't enabled yet; stash the requested policy away to
+                // apply later once the daemon is connected.
+                mUidCleartextPolicy.put(uid, policy);
+                return;
+            }
+
+            final String policyString;
+            switch (policy) {
+                case StrictMode.NETWORK_POLICY_ACCEPT:
+                    policyString = "accept";
+                    break;
+                case StrictMode.NETWORK_POLICY_LOG:
+                    policyString = "log";
+                    break;
+                case StrictMode.NETWORK_POLICY_REJECT:
+                    policyString = "reject";
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown policy " + policy);
+            }
+
+            try {
+                mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
+                mUidCleartextPolicy.put(uid, policy);
+            } catch (NativeDaemonConnectorException e) {
+                throw e.rethrowAsParcelableException();
+            }
+        }
+    }
+
+    @Override
     public boolean isBandwidthControlEnabled() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         return mBandwidthControlEnabled;
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index d6abce9..a0d305c 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -25,7 +25,6 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 39aa972..f4c6225 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -38,7 +38,6 @@
 import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 4fbf23b..d153233 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -736,50 +736,47 @@
     }
 
     public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
+        log("notifySignalStrengthForSubscriber: subId=" + subId
+                + " signalStrength=" + signalStrength);
         if (!checkNotifyPermission("notifySignalStrength()")) {
+            log("notifySignalStrengthForSubscriber: permission check failure");
             return;
         }
-        if (VDBG) {
-            log("notifySignalStrengthForSubscriber: subId=" + subId
-                + " signalStrength=" + signalStrength);
-            toStringLogSSC("notifySignalStrengthForSubscriber");
-        }
+        toStringLogSSC("notifySignalStrengthForSubscriber");
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
             if (validatePhoneId(phoneId)) {
-                if (VDBG) log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
+                log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
                 mSignalStrength[phoneId] = signalStrength;
                 for (Record r : mRecords) {
-                    if (VDBG) {
-                        log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
-                                + " phoneId=" + phoneId + " ss=" + signalStrength);
-                    }
+                    log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
+                            + " phoneId=" + phoneId + " ss=" + signalStrength);
                     if (r.matchPhoneStateListenerEvent(
                                 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
-                            if (DBG) {
-                                log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
-                                        + " subId=" + subId + " phoneId=" + phoneId
-                                        + " ss=" + signalStrength);
-                            }
+                            log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
+                                    + " subId=" + subId + " phoneId=" + phoneId
+                                    + " ss=" + signalStrength);
                             r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
                         } catch (RemoteException ex) {
+                            log("notifySignalStrengthForSubscriber: Exception while calling callback!!");
                             mRemoveList.add(r.binder);
                         }
+                    } else {
+                        log("notifySignalStrengthForSubscriber: no match for LISTEN_SIGNAL_STRENGTHS");
                     }
                     if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
                             idMatch(r.subId, subId, phoneId)){
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
-                            if (DBG) {
-                                log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
-                                        + " subId=" + subId + " phoneId=" + phoneId
-                                        + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
-                            }
+                            log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
+                                    + " subId=" + subId + " phoneId=" + phoneId
+                                    + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
                             r.callback.onSignalStrengthChanged(ss);
                         } catch (RemoteException ex) {
+                            log("notifySignalStrengthForSubscriber: Exception in deprecated LISTEN_SIGNAL_STRENGTH");
                             mRemoveList.add(r.binder);
                         }
                     }
@@ -787,6 +784,7 @@
             } else {
                 log("notifySignalStrengthForSubscriber: invalid phoneId=" + phoneId);
             }
+            log("notifySignalStrengthForSubscriber: done with all records");
             handleRemoveListLocked();
         }
         broadcastSignalStrengthChanged(signalStrength, subId);
diff --git a/services/core/java/com/android/server/TwilightCalculator.java b/services/core/java/com/android/server/TwilightCalculator.java
index a5c93b5..5839b16 100644
--- a/services/core/java/com/android/server/TwilightCalculator.java
+++ b/services/core/java/com/android/server/TwilightCalculator.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.text.format.DateUtils;
-import android.util.FloatMath;
 
 /** @hide */
 public class TwilightCalculator {
@@ -75,24 +74,24 @@
         final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
 
         // true anomaly
-        final float trueAnomaly = meanAnomaly + C1 * FloatMath.sin(meanAnomaly) + C2
-                * FloatMath.sin(2 * meanAnomaly) + C3 * FloatMath.sin(3 * meanAnomaly);
+        final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2
+                * Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly);
 
         // ecliptic longitude
-        final float solarLng = trueAnomaly + 1.796593063f + (float) Math.PI;
+        final double solarLng = trueAnomaly + 1.796593063d + Math.PI;
 
         // solar transit in days since 2000
         final double arcLongitude = -longitude / 360;
         float n = Math.round(daysSince2000 - J0 - arcLongitude);
-        double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053f * FloatMath.sin(meanAnomaly)
-                + -0.0069f * FloatMath.sin(2 * solarLng);
+        double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly)
+                + -0.0069d * Math.sin(2 * solarLng);
 
         // declination of sun
-        double solarDec = Math.asin(FloatMath.sin(solarLng) * FloatMath.sin(OBLIQUITY));
+        double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY));
 
         final double latRad = latiude * DEGREES_TO_RADIANS;
 
-        double cosHourAngle = (FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
+        double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
                 * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
         // The day or night never ends for the given date and location, if this value is out of
         // range.
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index d1b4569..aeacd45 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -31,6 +31,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
@@ -63,7 +64,7 @@
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
     private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    int mNightMode = UiModeManager.MODE_NIGHT_NO;
+    private int mNightMode = UiModeManager.MODE_NIGHT_NO;
 
     private boolean mCarModeEnabled = false;
     private boolean mCharging = false;
@@ -157,6 +158,7 @@
     public void onStart() {
         final Context context = getContext();
         mTwilightManager = getLocalService(TwilightManager.class);
+
         final PowerManager powerManager =
                 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -168,20 +170,23 @@
 
         mConfiguration.setToDefaults();
 
-        mDefaultUiModeType = context.getResources().getInteger(
+        final Resources res = context.getResources();
+        mDefaultUiModeType = res.getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
-        mCarModeKeepsScreenOn = (context.getResources().getInteger(
+        mCarModeKeepsScreenOn = (res.getInteger(
                 com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1);
-        mDeskModeKeepsScreenOn = (context.getResources().getInteger(
+        mDeskModeKeepsScreenOn = (res.getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
-        mTelevision = context.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_TELEVISION) ||
-            context.getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_LEANBACK);
-        mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
 
+        final PackageManager pm = context.getPackageManager();
+        mTelevision = pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+        mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+        final int defaultNightMode = res.getInteger(
+                com.android.internal.R.integer.config_defaultNightMode);
         mNightMode = Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+                Settings.Secure.UI_NIGHT_MODE, defaultNightMode);
 
         mTwilightManager.registerListener(mTwilightListener, mHandler);
 
@@ -245,7 +250,7 @@
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    if (isDoingNightModeLocked() && mNightMode != mode) {
+                    if (mNightMode != mode) {
                         Settings.Secure.putInt(getContext().getContentResolver(),
                                 Settings.Secure.UI_NIGHT_MODE, mode);
                         mNightMode = mode;
@@ -309,10 +314,6 @@
         }
     }
 
-    boolean isDoingNightModeLocked() {
-        return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    }
-
     void setCarModeLocked(boolean enabled, int flags) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
@@ -354,17 +355,13 @@
         } else if (isDeskDockState(mDockState)) {
             uiMode = Configuration.UI_MODE_TYPE_DESK;
         }
-        if (mCarModeEnabled) {
-            if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                updateComputedNightModeLocked();
-                uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
-                        : Configuration.UI_MODE_NIGHT_NO;
-            } else {
-                uiMode |= mNightMode << 4;
-            }
+
+        if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+            updateComputedNightModeLocked();
+            uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
+                    : Configuration.UI_MODE_NIGHT_NO;
         } else {
-            // Disabling the car mode clears the night mode.
-            uiMode = (uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | Configuration.UI_MODE_NIGHT_NO;
+            uiMode |= mNightMode << 4;
         }
 
         if (LOG) {
@@ -618,7 +615,7 @@
 
     void updateTwilight() {
         synchronized (mLock) {
-            if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+            if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
                 updateComputedNightModeLocked();
                 updateLocked(0, 0);
             }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 8e46c4d..794e1b0 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -106,8 +106,8 @@
         }
 
         public void scheduleCheckLocked() {
-            if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) {
-                // If the target looper is or just recently was idling, then
+            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
+                // If the target looper has recently been polling, then
                 // there is no reason to enqueue our checker on it since that
                 // is as good as it not being deadlocked.  This avoid having
                 // to do a context switch to check the thread.  Note that we
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index bffbb4c2..0de8c8d 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -16,10 +16,7 @@
 
 package com.android.server;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -219,6 +216,7 @@
 
         mWakeLock.acquire();
 
+        Log.i(TAG, "MSG_NEW_DEVICE_STATE ");
         Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
                 mHeadsetState, newName);
         mHandler.sendMessage(msg);
@@ -286,14 +284,16 @@
                 return;
             }
 
-            if (LOG)
-                Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));
+            if (LOG) {
+                Slog.v(TAG, "headsetName: " + headsetName +
+                        (state == 1 ? " connected" : " disconnected"));
+            }
 
             if (outDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(outDevice, state, headsetName);
+              mAudioManager.setWiredDeviceConnectionState(outDevice, state, "", headsetName);
             }
             if (inDevice != 0) {
-              mAudioManager.setWiredDeviceConnectionState(inDevice, state, headsetName);
+              mAudioManager.setWiredDeviceConnectionState(inDevice, state, "", headsetName);
             }
         }
     }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e52b2bf..9339b35 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3083,7 +3083,8 @@
             try {
                 PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
                 if (packageInfo != null
-                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+                        && (packageInfo.applicationInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                     return true;
                 }
             } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index aefbf60..fc95b00 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -33,6 +35,7 @@
 import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
@@ -67,14 +70,15 @@
 import android.util.TimeUtils;
 
 public final class ActiveServices {
-    static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
-    static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
-    static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
-    static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
-    static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
-    static final boolean LOG_SERVICE_START_STOP = false;
-    static final String TAG = ActivityManagerService.TAG;
-    static final String TAG_MU = ActivityManagerService.TAG_MU;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+    private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+    private static final String TAG_SERVICE_EXECUTING = TAG + POSTFIX_SERVICE_EXECUTING;
+
+    private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
+    private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
+
+    private static final boolean LOG_SERVICE_START_STOP = false;
 
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
@@ -206,11 +210,12 @@
 
         void ensureNotStartingBackground(ServiceRecord r) {
             if (mStartingBackground.remove(r)) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "No longer background starting: " + r);
                 rescheduleDelayedStarts();
             }
             if (mDelayedStartList.remove(r)) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
             }
         }
 
@@ -229,16 +234,17 @@
             while (mDelayedStartList.size() > 0
                     && mStartingBackground.size() < mMaxStartingBackground) {
                 ServiceRecord r = mDelayedStartList.remove(0);
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "REM FR DELAY LIST (exec next): " + r);
                 if (r.pendingStarts.size() <= 0) {
                     Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
                             + " delayedStop=" + r.delayedStop);
                 }
                 if (DEBUG_DELAYED_SERVICE) {
                     if (mDelayedStartList.size() > 0) {
-                        Slog.v(TAG, "Remaining delayed list:");
+                        Slog.v(TAG_SERVICE, "Remaining delayed list:");
                         for (int i=0; i<mDelayedStartList.size(); i++) {
-                            Slog.v(TAG, "  #" + i + ": " + mDelayedStartList.get(i));
+                            Slog.v(TAG_SERVICE, "  #" + i + ": " + mDelayedStartList.get(i));
                         }
                     }
                 }
@@ -248,7 +254,7 @@
             if (mStartingBackground.size() > 0) {
                 ServiceRecord next = mStartingBackground.get(0);
                 long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
-                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Top bg start is " + next
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Top bg start is " + next
                         + ", can delay others up to " + when);
                 Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
                 sendMessageAtTime(msg, when);
@@ -298,7 +304,7 @@
     ComponentName startServiceLocked(IApplicationThread caller,
             Intent service, String resolvedType,
             int callingPid, int callingUid, int userId) {
-        if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
         final boolean callerFg;
@@ -337,7 +343,7 @@
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null, r.userId);
         if (unscheduleServiceRestartLocked(r, callingUid, false)) {
-            if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
         }
         r.lastActivity = SystemClock.uptimeMillis();
         r.startRequested = true;
@@ -360,29 +366,30 @@
                 // service is started.  This is especially the case for receivers, which
                 // may start a service in onReceive() to do some additional work and have
                 // initialized some global state as part of that.
-                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG, "Potential start delay of " + r + " in "
-                        + proc);
+                if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+                        + r + " in " + proc);
                 if (r.delayed) {
                     // This service is already scheduled for a delayed start; just leave
                     // it still waiting.
-                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
+                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
                     return r.name;
                 }
                 if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                     // Something else is starting, delay!
-                    Slog.i(TAG, "Delaying start of: " + r);
+                    Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                     smap.mDelayedStartList.add(r);
                     r.delayed = true;
                     return r.name;
                 }
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
                 addToStarting = true;
             } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                 // We slightly loosen when we will enqueue this new service as a background
                 // starting service we are waiting for, to also include processes that are
                 // currently running other services or receivers.
                 addToStarting = true;
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Not delaying, but counting as bg: " + r);
             } else if (DEBUG_DELAYED_STARTS) {
                 StringBuilder sb = new StringBuilder(128);
                 sb.append("Not potential delay (state=").append(proc.curProcState)
@@ -394,16 +401,17 @@
                 }
                 sb.append("): ");
                 sb.append(r.toString());
-                Slog.v(TAG, sb.toString());
+                Slog.v(TAG_SERVICE, sb.toString());
             }
         } else if (DEBUG_DELAYED_STARTS) {
             if (callerFg) {
-                Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+                Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
                         + callingUid + " pid=" + callingPid + "): " + r);
             } else if (r.app != null) {
-                Slog.v(TAG, "Not potential delay (cur app=" + r.app + "): " + r);
+                Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
             } else {
-                Slog.v(TAG, "Not potential delay (user " + r.userId + " not started): " + r);
+                Slog.v(TAG_SERVICE,
+                        "Not potential delay (user " + r.userId + " not started): " + r);
             }
         }
 
@@ -432,9 +440,9 @@
             if (DEBUG_DELAYED_SERVICE) {
                 RuntimeException here = new RuntimeException("here");
                 here.fillInStackTrace();
-                Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
+                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
             } else if (DEBUG_DELAYED_STARTS) {
-                Slog.v(TAG, "Starting background (first=" + first + "): " + r);
+                Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
             }
             if (first) {
                 smap.rescheduleDelayedStarts();
@@ -451,7 +459,7 @@
             // If service isn't actually running, but is is being held in the
             // delayed list, then we need to keep it started but note that it
             // should be stopped once no longer delayed.
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
             service.delayedStop = true;
             return;
         }
@@ -469,7 +477,7 @@
 
     int stopServiceLocked(IApplicationThread caller, Intent service,
             String resolvedType, int userId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "stopService: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service
                 + " type=" + resolvedType);
 
         final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -525,7 +533,7 @@
 
     boolean stopServiceTokenLocked(ComponentName className, IBinder token,
             int startId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "stopServiceToken: " + className
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
                 + " " + token + " startId=" + startId);
         ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
         if (r != null) {
@@ -687,7 +695,7 @@
     int bindServiceLocked(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
             IServiceConnection connection, int flags, int userId) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
                 + " type=" + resolvedType + " conn=" + connection.asBinder()
                 + " flags=0x" + Integer.toHexString(flags));
         final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
@@ -751,7 +759,7 @@
 
         try {
             if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "BIND SERVICE WHILE RESTART PENDING: "
                         + s);
             }
 
@@ -819,7 +827,7 @@
                 mAm.updateOomAdjLocked(s.app);
             }
 
-            if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
                     + ": received=" + b.intent.received
                     + " apps=" + b.intent.apps.size()
                     + " doRebind=" + b.intent.doRebind);
@@ -857,7 +865,7 @@
     void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
         final long origId = Binder.clearCallingIdentity();
         try {
-            if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                     + " " + intent + ": " + service);
             if (r != null) {
                 Intent.FilterComparison filter
@@ -873,14 +881,14 @@
                             ConnectionRecord c = clist.get(i);
                             if (!filter.equals(c.binding.intent.intent)) {
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Not publishing to: " + c);
+                                        TAG_SERVICE, "Not publishing to: " + c);
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Bound intent: " + c.binding.intent.intent);
+                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                 if (DEBUG_SERVICE) Slog.v(
-                                        TAG, "Published intent: " + intent);
+                                        TAG_SERVICE, "Published intent: " + intent);
                                 continue;
                             }
-                            if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
+                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                             try {
                                 c.conn.connected(r.name, service);
                             } catch (Exception e) {
@@ -901,7 +909,7 @@
 
     boolean unbindServiceLocked(IServiceConnection connection) {
         IBinder binder = connection.asBinder();
-        if (DEBUG_SERVICE) Slog.v(TAG, "unbindService: conn=" + binder);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
         ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
         if (clist == null) {
             Slog.w(TAG, "Unbind failed: could not find connection for "
@@ -945,7 +953,7 @@
                 Intent.FilterComparison filter
                         = new Intent.FilterComparison(intent);
                 IntentBindRecord b = r.bindings.get(filter);
-                if (DEBUG_SERVICE) Slog.v(TAG, "unbindFinished in " + r
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
                         + " at " + b + ": apps="
                         + (b != null ? b.apps.size() : 0));
 
@@ -1012,7 +1020,7 @@
             String resolvedType, int callingPid, int callingUid, int userId,
             boolean createIfNeeded, boolean callingFromFg) {
         ServiceRecord r = null;
-        if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
 
         userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
@@ -1036,7 +1044,7 @@
                 ServiceInfo sInfo =
                     rInfo != null ? rInfo.serviceInfo : null;
                 if (sInfo == null) {
-                    Slog.w(TAG, "Unable to start service " + service + " U=" + userId +
+                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                           ": not found");
                     return null;
                 }
@@ -1110,9 +1118,9 @@
     }
 
     private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
-        if (DEBUG_SERVICE) Slog.v(TAG, ">>> EXECUTING "
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
                 + why + " of " + r + " in app " + r.app);
-        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, ">>> EXECUTING "
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
                 + why + " of " + r.shortName);
         long now = SystemClock.uptimeMillis();
         if (r.executeNesting == 0) {
@@ -1155,7 +1163,7 @@
                 i.hasBound = true;
                 i.doRebind = false;
             } catch (RemoteException e) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                 return false;
             }
         }
@@ -1336,17 +1344,18 @@
             return null;
         }
 
-        if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
 
         // We are now bringing the service up, so no longer in the
         // restarting state.
         if (mRestartingServices.remove(r)) {
+            r.resetRestartCounter();
             clearRestartingIfNeededLocked(r);
         }
 
         // Make sure this service is no longer considered delayed, we are starting it now.
         if (r.delayed) {
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
             getServiceMap(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
@@ -1429,7 +1438,8 @@
             // Oh and hey we've already been asked to stop!
             r.delayedStop = false;
             if (r.startRequested) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Applying delayed stop (in bring up): " + r);
                 stopServiceLocked(r);
             }
         }
@@ -1508,7 +1518,7 @@
         sendServiceArgsLocked(r, execInFg, true);
 
         if (r.delayed) {
-            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
             getServiceMap(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
@@ -1517,7 +1527,8 @@
             // Oh and hey we've already been asked to stop!
             r.delayedStop = false;
             if (r.startRequested) {
-                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
+                        "Applying delayed stop (from start): " + r);
                 stopServiceLocked(r);
             }
         }
@@ -1533,7 +1544,7 @@
         while (r.pendingStarts.size() > 0) {
             try {
                 ServiceRecord.StartItem si = r.pendingStarts.remove(0);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to: "
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
                         + r + " " + r.intent + " args=" + si.intent);
                 if (si.intent == null && N > 1) {
                     // If somehow we got a dummy null intent in the middle,
@@ -1565,7 +1576,7 @@
             } catch (RemoteException e) {
                 // Remote process gone...  we'll let the normal cleanup take
                 // care of this.
-                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while scheduling start: " + r);
                 break;
             } catch (Exception e) {
                 Slog.w(TAG, "Unexpected exception", e);
@@ -1635,7 +1646,7 @@
         if (r.app != null && r.app.thread != null) {
             for (int i=r.bindings.size()-1; i>=0; i--) {
                 IntentBindRecord ibr = r.bindings.valueAt(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
                         + ": hasBound=" + ibr.hasBound);
                 if (ibr.hasBound) {
                     try {
@@ -1653,7 +1664,7 @@
             }
         }
 
-        if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent);
         r.destroyTime = SystemClock.uptimeMillis();
         if (LOG_SERVICE_START_STOP) {
             EventLogTags.writeAmDestroyService(
@@ -1670,7 +1681,7 @@
         for (int i=mPendingServices.size()-1; i>=0; i--) {
             if (mPendingServices.get(i) == r) {
                 mPendingServices.remove(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r);
             }
         }
 
@@ -1703,11 +1714,11 @@
                 }
             } else {
                 if (DEBUG_SERVICE) Slog.v(
-                    TAG, "Removed service that has no process: " + r);
+                    TAG_SERVICE, "Removed service that has no process: " + r);
             }
         } else {
             if (DEBUG_SERVICE) Slog.v(
-                TAG, "Removed service that is not running: " + r);
+                TAG_SERVICE, "Removed service that is not running: " + r);
         }
 
         if (r.bindings.size() > 0) {
@@ -1774,7 +1785,7 @@
         }
 
         if (!c.serviceDead) {
-            if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
                     + ": shouldUnbind=" + b.intent.hasBound);
             if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                     && b.intent.hasBound) {
@@ -1901,19 +1912,20 @@
 
     private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
             boolean finishing) {
-        if (DEBUG_SERVICE) Slog.v(TAG, "<<< DONE EXECUTING " + r
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
                 + ": nesting=" + r.executeNesting
                 + ", inDestroying=" + inDestroying + ", app=" + r.app);
-        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG, "<<< DONE EXECUTING " + r.shortName);
+        else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
+                "<<< DONE EXECUTING " + r.shortName);
         r.executeNesting--;
         if (r.executeNesting <= 0) {
             if (r.app != null) {
-                if (DEBUG_SERVICE) Slog.v(TAG,
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                         "Nesting at 0 of " + r.shortName);
                 r.app.execServicesFg = false;
                 r.app.executingServices.remove(r);
                 if (r.app.executingServices.size() == 0) {
-                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
+                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                             "No more executingServices of " + r.shortName);
                     mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                 } else if (r.executeFg) {
@@ -1926,7 +1938,7 @@
                     }
                 }
                 if (inDestroying) {
-                    if (DEBUG_SERVICE) Slog.v(TAG,
+                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                             "doneExecuting remove destroying " + r);
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
@@ -2140,13 +2152,13 @@
             sr.executeNesting = 0;
             sr.forceClearTracker();
             if (mDestroyingServices.remove(sr)) {
-                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
             }
 
             final int numClients = sr.bindings.size();
             for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
                 IntentBindRecord b = sr.bindings.valueAt(bindingi);
-                if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Killing binding " + b
                         + ": shouldUnbind=" + b.hasBound);
                 b.binder = null;
                 b.requested = b.received = b.hasBound = false;
@@ -2280,7 +2292,7 @@
             if (sr.app == app) {
                 sr.forceClearTracker();
                 mDestroyingServices.remove(i);
-                if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove destroying " + sr);
+                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
new file mode 100644
index 0000000..ae4006d
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -0,0 +1,85 @@
+/*
+ * 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.am;
+
+/**
+ * Common class for the various debug {@link android.util.Log} output configuration in the activity
+ * manager package.
+ */
+class ActivityManagerDebugConfig {
+
+    // All output logs in the activity manager package use the {@link #TAG_AM} string for tagging
+    // their log output. This makes it easy to identify the origin of the log message when sifting
+    // through a large amount of log output from multiple sources. However, it also makes trying
+    // to figure-out the origin of a log message while debugging the activity manager a little
+    // painful. By setting this constant to true, log messages from the activity manager package
+    // will be tagged with their class names instead fot the generic tag.
+    static final boolean TAG_WITH_CLASS_NAME = false;
+
+    // While debugging it is sometimes useful to have the category name of the log prepended to the
+    // base log tag to make sifting through logs with the same base tag easier. By setting this
+    // constant to true, the category name of the log point will be prepended to the log tag.
+    static final boolean PREPEND_CATEGORY_NAME = false;
+
+    // Default log tag for the activity manager package.
+    static final String TAG_AM = "ActivityManager";
+
+    // Enable all debug log categories.
+    static final boolean DEBUG_ALL = false;
+
+    // Available log categories in the activity manager package.
+    static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
+    static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
+    static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
+    static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
+    static final boolean DEBUG_FOCUS = false;
+    static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+    static final boolean DEBUG_LRU = DEBUG_ALL || false;
+    static final boolean DEBUG_MU = DEBUG_ALL || false;
+    static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+    static final boolean DEBUG_PSS = DEBUG_ALL || false;
+    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+    static final boolean DEBUG_STACK = DEBUG_ALL || false;
+    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+
+    static final String POSTFIX_BACKUP = (PREPEND_CATEGORY_NAME) ? "_Backup" : "";
+    static final String POSTFIX_BROADCAST = (PREPEND_CATEGORY_NAME) ? "_Broadcast" : "";
+    static final String POSTFIX_CLEANUP = (PREPEND_CATEGORY_NAME) ? "_Cleanup" : "";
+    static final String POSTFIX_MU = "_MU";
+    static final String POSTFIX_SERVICE = (PREPEND_CATEGORY_NAME) ? "_Service" : "";
+    static final String POSTFIX_SERVICE_EXECUTING =
+            (PREPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
old mode 100755
new mode 100644
index e8f3757..e7952c1
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -30,6 +30,7 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import android.Manifest;
@@ -55,16 +56,20 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.SparseIntArray;
 
+import android.view.Display;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.DumpHeapActivity;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
@@ -87,6 +92,7 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -169,6 +175,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPermissionController;
+import android.os.IProcessInfoService;
 import android.os.IRemoteCallback;
 import android.os.IUserManager;
 import android.os.Looper;
@@ -241,41 +248,39 @@
     // File that stores last updated system version and called preboot receivers
     static final String CALLED_PRE_BOOTS_FILENAME = "called_pre_boots.dat";
 
-    static final String TAG = "ActivityManager";
-    static final String TAG_MU = "ActivityManagerServiceMU";
-    static final boolean DEBUG = false;
-    static final boolean localLOGV = DEBUG;
-    static final boolean DEBUG_BACKUP = localLOGV || false;
-    static final boolean DEBUG_BROADCAST = localLOGV || false;
-    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
-    static final boolean DEBUG_CLEANUP = localLOGV || false;
-    static final boolean DEBUG_CONFIGURATION = localLOGV || false;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+    private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
+    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
+    private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+
+    // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
+    static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
     static final boolean DEBUG_FOCUS = false;
-    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
-    static final boolean DEBUG_MU = localLOGV || false;
-    static final boolean DEBUG_OOM_ADJ = localLOGV || false;
-    static final boolean DEBUG_LRU = localLOGV || false;
-    static final boolean DEBUG_PAUSE = localLOGV || false;
-    static final boolean DEBUG_POWER = localLOGV || false;
+    static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+    static final boolean DEBUG_MU = DEBUG_ALL || false;
+    static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+    static final boolean DEBUG_LRU = DEBUG_ALL || false;
+    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+    static final boolean DEBUG_POWER = DEBUG_ALL || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
-    static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false;
-    static final boolean DEBUG_PROCESSES = localLOGV || false;
-    static final boolean DEBUG_PROVIDER = localLOGV || false;
-    static final boolean DEBUG_RESULTS = localLOGV || false;
-    static final boolean DEBUG_SERVICE = localLOGV || false;
-    static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
-    static final boolean DEBUG_STACK = localLOGV || false;
-    static final boolean DEBUG_SWITCH = localLOGV || false;
-    static final boolean DEBUG_TASKS = localLOGV || false;
-    static final boolean DEBUG_THUMBNAILS = localLOGV || false;
-    static final boolean DEBUG_TRANSITION = localLOGV || false;
-    static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
-    static final boolean DEBUG_USER_LEAVING = localLOGV || false;
-    static final boolean DEBUG_VISBILITY = localLOGV || false;
-    static final boolean DEBUG_PSS = localLOGV || false;
-    static final boolean DEBUG_LOCKSCREEN = localLOGV || false;
-    static final boolean DEBUG_RECENTS = localLOGV || false;
+    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
+    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
+    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
+    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
+    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
+    static final boolean DEBUG_STACK = DEBUG_ALL || false;
+    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
+    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
+    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+    static final boolean DEBUG_PSS = DEBUG_ALL || false;
+    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
+    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
 
@@ -293,9 +298,6 @@
 
     static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
-    // Maximum number recent bitmaps to keep in memory.
-    static final int MAX_RECENT_BITMAPS = 3;
-
     // Amount of time after a call to stopAppSwitches() during which we will
     // prevent further untrusted switches from happening.
     static final long APP_SWITCH_DELAY_TIME = 5*1000;
@@ -402,24 +404,12 @@
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
         final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
-        if (DEBUG_BACKGROUND_BROADCAST) {
-            Slog.i(TAG, "Broadcast intent " + intent + " on "
-                    + (isFg ? "foreground" : "background")
-                    + " queue");
-        }
+        if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
+                "Broadcast intent " + intent + " on "
+                + (isFg ? "foreground" : "background") + " queue");
         return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
     }
 
-    BroadcastRecord broadcastRecordForReceiverLocked(IBinder receiver) {
-        for (BroadcastQueue queue : mBroadcastQueues) {
-            BroadcastRecord r = queue.getMatchingOrderedReceiver(receiver);
-            if (r != null) {
-                return r;
-            }
-        }
-        return null;
-    }
-
     /**
      * Activity we have told the window manager to have key focus.
      */
@@ -428,8 +418,7 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    ArrayList<TaskRecord> mRecentTasks;
-    ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
+    private final RecentTasks mRecentTasks;
 
     /**
      * For addAppTask: cached of the last activity component that was added.
@@ -451,23 +440,28 @@
         public final Bundle extras;
         public final Intent intent;
         public final String hint;
+        public final IResultReceiver receiver;
         public final int userHandle;
         public boolean haveResult = false;
         public Bundle result = null;
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, int _userHandle) {
+                String _hint, IResultReceiver _receiver, int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
+            receiver = _receiver;
             userHandle = _userHandle;
         }
         @Override
         public void run() {
             Slog.w(TAG, "getAssistContextExtras failed: timeout retrieving from " + activity);
-            synchronized (this) {
-                haveResult = true;
-                notifyAll();
+            synchronized (ActivityManagerService.this) {
+                synchronized (this) {
+                    haveResult = true;
+                    notifyAll();
+                }
+                pendingAssistExtrasTimedOutLocked(this);
             }
         }
     }
@@ -1129,6 +1123,11 @@
     boolean mAutoStopProfiler = false;
     int mProfileType = 0;
     String mOpenGlTraceApp = null;
+    final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+    String mMemWatchDumpProcName;
+    String mMemWatchDumpFile;
+    int mMemWatchDumpPid;
+    int mMemWatchDumpUid;
 
     final long[] mTmpLong = new long[1];
 
@@ -1211,7 +1210,7 @@
 
         AppDeathRecipient(ProcessRecord app, int pid,
                 IApplicationThread thread) {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "New death recipient " + this
                 + " for thread " + thread.asBinder());
             mApp = app;
@@ -1221,7 +1220,7 @@
 
         @Override
         public void binderDied() {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "Death received in " + this
                 + " for thread " + mAppThread.asBinder());
             synchronized(ActivityManagerService.this) {
@@ -1270,6 +1269,9 @@
     static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
     static final int DISMISS_DIALOG_MSG = 48;
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 49;
+    static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 50;
+    static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 51;
+    static final int DELETE_DUMPHEAP_MSG = 52;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1755,7 +1757,7 @@
             }
             case ENTER_ANIMATION_COMPLETE_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
+                    ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
                     if (r != null && r.app != null && r.app.thread != null) {
                         try {
                             r.app.thread.scheduleEnterAnimationComplete(r.appToken);
@@ -1807,6 +1809,95 @@
                 }
                 break;
             }
+            case NOTIFY_CLEARTEXT_NETWORK_MSG: {
+                final int uid = msg.arg1;
+                final byte[] firstPacket = (byte[]) msg.obj;
+
+                synchronized (mPidsSelfLocked) {
+                    for (int i = 0; i < mPidsSelfLocked.size(); i++) {
+                        final ProcessRecord p = mPidsSelfLocked.valueAt(i);
+                        if (p.uid == uid) {
+                            try {
+                                p.thread.notifyCleartextNetwork(firstPacket);
+                            } catch (RemoteException ignored) {
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            case POST_DUMP_HEAP_NOTIFICATION_MSG: {
+                final String procName;
+                final int uid;
+                final long memLimit;
+                synchronized (ActivityManagerService.this) {
+                    procName = mMemWatchDumpProcName;
+                    uid = mMemWatchDumpUid;
+                    Long limit = mMemWatchProcesses.get(procName);
+                    memLimit = limit != null ? limit : 0;
+                }
+                if (procName == null) {
+                    return;
+                }
+
+                if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
+                        + procName + "/" + uid);
+
+                INotificationManager inm = NotificationManager.getService();
+                if (inm == null) {
+                    return;
+                }
+
+                String text = mContext.getString(R.string.dump_heap_notification, procName);
+                Notification notification = new Notification();
+                notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+                notification.when = 0;
+                notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL;
+                notification.tickerText = text;
+                notification.defaults = 0; // please be quiet
+                notification.sound = null;
+                notification.vibrate = null;
+                notification.color = mContext.getResources().getColor(
+                        com.android.internal.R.color.system_notification_accent_color);
+                Intent deleteIntent = new Intent();
+                deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+                notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
+                        deleteIntent, 0, UserHandle.OWNER);
+                Intent intent = new Intent();
+                intent.setClassName("android", DumpHeapActivity.class.getName());
+                intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
+                intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+                int userId = UserHandle.getUserId(uid);
+                notification.setLatestEventInfo(mContext, text,
+                        mContext.getText(R.string.dump_heap_notification_detail),
+                        PendingIntent.getActivityAsUser(mContext, 0, intent,
+                                PendingIntent.FLAG_CANCEL_CURRENT, null,
+                                new UserHandle(userId)));
+
+                try {
+                    int[] outId = new int[1];
+                    inm.enqueueNotificationWithTag("android", "android", null,
+                            R.string.dump_heap_notification,
+                            notification, outId, userId);
+                } catch (RuntimeException e) {
+                    Slog.w(ActivityManagerService.TAG,
+                            "Error showing notification for dump heap", e);
+                } catch (RemoteException e) {
+                }
+            } break;
+            case DELETE_DUMPHEAP_MSG: {
+                revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
+                        DumpHeapActivity.JAVA_URI,
+                        Intent.FLAG_GRANT_READ_URI_PERMISSION
+                                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                        UserHandle.myUserId());
+                synchronized (ActivityManagerService.this) {
+                    mMemWatchDumpFile = null;
+                    mMemWatchDumpProcName = null;
+                    mMemWatchDumpPid = -1;
+                    mMemWatchDumpUid = -1;
+                }
+            } break;
             }
         }
     };
@@ -1850,9 +1941,14 @@
                     synchronized (ActivityManagerService.this) {
                         if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
                                 + (SystemClock.uptimeMillis()-start) + "ms");
-                        mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
-                                memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                                memInfo.getKernelUsedSizeKb(), nativeTotalPss);
+                        final long cachedKb = memInfo.getCachedSizeKb();
+                        final long freeKb = memInfo.getFreeSizeKb();
+                        final long zramKb = memInfo.getZramTotalSizeKb();
+                        final long kernelKb = memInfo.getKernelUsedSizeKb();
+                        EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
+                                kernelKb*1024, nativeTotalPss*1024);
+                        mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
+                                nativeTotalPss);
                     }
                 }
 
@@ -1888,7 +1984,7 @@
                             if (pss != 0 && proc.thread != null && proc.setProcState == procState
                                     && proc.pid == pid && proc.lastPssTime == lastPssTime) {
                                 num++;
-                                recordPssSample(proc, procState, pss, tmp[0],
+                                recordPssSampleLocked(proc, procState, pss, tmp[0],
                                         SystemClock.uptimeMillis());
                             }
                         }
@@ -1910,6 +2006,7 @@
                 ServiceManager.addService("cpuinfo", new CpuBinder(this));
             }
             ServiceManager.addService("permission", new PermissionController(this));
+            ServiceManager.addService("processinfo", new ProcessInfoService(this));
 
             ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                     "android", STOCK_PM_FLAGS);
@@ -2113,8 +2210,9 @@
 
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
-        mStackSupervisor = new ActivityStackSupervisor(this);
-        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
+        mRecentTasks = new RecentTasks(this);
+        mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
+        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);
 
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
@@ -2236,31 +2334,33 @@
             if (MONITOR_CPU_USAGE &&
                     mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
                 mLastCpuTime.set(now);
-                haveNewCpuStats = true;
                 mProcessCpuTracker.update();
-                //Slog.i(TAG, mProcessCpu.printCurrentState());
-                //Slog.i(TAG, "Total CPU usage: "
-                //        + mProcessCpu.getTotalCpuPercent() + "%");
+                if (mProcessCpuTracker.hasGoodLastStats()) {
+                    haveNewCpuStats = true;
+                    //Slog.i(TAG, mProcessCpu.printCurrentState());
+                    //Slog.i(TAG, "Total CPU usage: "
+                    //        + mProcessCpu.getTotalCpuPercent() + "%");
 
-                // Slog the cpu usage if the property is set.
-                if ("true".equals(SystemProperties.get("events.cpu"))) {
-                    int user = mProcessCpuTracker.getLastUserTime();
-                    int system = mProcessCpuTracker.getLastSystemTime();
-                    int iowait = mProcessCpuTracker.getLastIoWaitTime();
-                    int irq = mProcessCpuTracker.getLastIrqTime();
-                    int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
-                    int idle = mProcessCpuTracker.getLastIdleTime();
+                    // Slog the cpu usage if the property is set.
+                    if ("true".equals(SystemProperties.get("events.cpu"))) {
+                        int user = mProcessCpuTracker.getLastUserTime();
+                        int system = mProcessCpuTracker.getLastSystemTime();
+                        int iowait = mProcessCpuTracker.getLastIoWaitTime();
+                        int irq = mProcessCpuTracker.getLastIrqTime();
+                        int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
+                        int idle = mProcessCpuTracker.getLastIdleTime();
 
-                    int total = user + system + iowait + irq + softIrq + idle;
-                    if (total == 0) total = 1;
+                        int total = user + system + iowait + irq + softIrq + idle;
+                        if (total == 0) total = 1;
 
-                    EventLog.writeEvent(EventLogTags.CPU,
-                            ((user+system+iowait+irq+softIrq) * 100) / total,
-                            (user * 100) / total,
-                            (system * 100) / total,
-                            (iowait * 100) / total,
-                            (irq * 100) / total,
-                            (softIrq * 100) / total);
+                        EventLog.writeEvent(EventLogTags.CPU,
+                                ((user+system+iowait+irq+softIrq) * 100) / total,
+                                (user * 100) / total,
+                                (system * 100) / total,
+                                (iowait * 100) / total,
+                                (irq * 100) / total,
+                                (softIrq * 100) / total);
+                    }
                 }
             }
 
@@ -2269,8 +2369,10 @@
             synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
                     if (haveNewCpuStats) {
-                        if (mOnBattery) {
-                            int perc = bstats.startAddingCpuLocked();
+                        final int perc = bstats.startAddingCpuLocked();
+                        if (perc >= 0) {
+                            int remainUTime = 0;
+                            int remainSTime = 0;
                             int totalUTime = 0;
                             int totalSTime = 0;
                             final int N = mProcessCpuTracker.countStats();
@@ -2282,31 +2384,38 @@
                                 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
                                 int otherUTime = (st.rel_utime*perc)/100;
                                 int otherSTime = (st.rel_stime*perc)/100;
-                                totalUTime += otherUTime;
-                                totalSTime += otherSTime;
+                                remainUTime += otherUTime;
+                                remainSTime += otherSTime;
+                                totalUTime += st.rel_utime;
+                                totalSTime += st.rel_stime;
                                 if (pr != null) {
                                     BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
                                                 pr.info.uid, pr.processName);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
-                                    pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
+                                    pr.curCpuTime += st.rel_utime + st.rel_stime;
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         st.batteryStats = ps = bstats.getProcessStatsLocked(
                                                 bstats.mapUid(st.uid), st.name);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
                                 }
                             }
-                            bstats.finishAddingCpuLocked(perc, totalUTime,
-                                    totalSTime, cpuSpeedTimes);
+                            final int userTime = mProcessCpuTracker.getLastUserTime();
+                            final int systemTime = mProcessCpuTracker.getLastSystemTime();
+                            final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime();
+                            final int irqTime = mProcessCpuTracker.getLastIrqTime();
+                            final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime();
+                            final int idleTime = mProcessCpuTracker.getLastIdleTime();
+                            bstats.finishAddingCpuLocked(perc, remainUTime,
+                                    remainSTime, totalUTime, totalSTime, userTime, systemTime,
+                                    iowaitTime, irqTime, softIrqTime, idleTime, cpuSpeedTimes);
                         }
                     }
                 }
@@ -2367,8 +2476,7 @@
             } else {
                 finishRunningVoiceLocked();
             }
-            mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity");
-            if (r != null) {
+            if (r != null && mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
             applyUpdateLockStateLocked(r);
@@ -2392,6 +2500,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked(null);
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
+                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
                 }
             }
         }
@@ -2411,7 +2520,7 @@
     public void notifyActivityDrawn(IBinder token) {
         if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
         synchronized (this) {
-            ActivityRecord r= mStackSupervisor.isInAnyStackLocked(token);
+            ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
             if (r != null) {
                 r.task.stack.notifyActivityDrawnLocked(r);
             }
@@ -3642,7 +3751,7 @@
         final Intent intent;
         final int userId;
         synchronized (this) {
-            task = recentTaskForIdLocked(taskId);
+            task = mRecentTasks.taskForIdLocked(taskId);
             if (task == null) {
                 throw new IllegalArgumentException("Task " + taskId + " not found.");
             }
@@ -3700,518 +3809,6 @@
         return ret;
     }
 
-    //explicitly remove thd old information in mRecentTasks when removing existing user.
-    private void removeRecentTasksForUserLocked(int userId) {
-        if(userId <= 0) {
-            Slog.i(TAG, "Can't remove recent task on user " + userId);
-            return;
-        }
-
-        for (int i = mRecentTasks.size() - 1; i >= 0; --i) {
-            TaskRecord tr = mRecentTasks.get(i);
-            if (tr.userId == userId) {
-                if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
-                        + " when finishing user" + userId);
-                mRecentTasks.remove(i);
-                tr.removedFromRecents();
-            }
-        }
-
-        // Remove tasks from persistent storage.
-        notifyTaskPersisterLocked(null, true);
-    }
-
-    // Sort by taskId
-    private Comparator<TaskRecord> mTaskRecordComparator = new Comparator<TaskRecord>() {
-        @Override
-        public int compare(TaskRecord lhs, TaskRecord rhs) {
-            return rhs.taskId - lhs.taskId;
-        }
-    };
-
-    // Extract the affiliates of the chain containing mRecentTasks[start].
-    private int processNextAffiliateChainLocked(int start) {
-        final TaskRecord startTask = mRecentTasks.get(start);
-        final int affiliateId = startTask.mAffiliatedTaskId;
-
-        // Quick identification of isolated tasks. I.e. those not launched behind.
-        if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
-                startTask.mNextAffiliate == null) {
-            // There is still a slim chance that there are other tasks that point to this task
-            // and that the chain is so messed up that this task no longer points to them but
-            // the gain of this optimization outweighs the risk.
-            startTask.inRecents = true;
-            return start + 1;
-        }
-
-        // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
-        mTmpRecents.clear();
-        for (int i = mRecentTasks.size() - 1; i >= start; --i) {
-            final TaskRecord task = mRecentTasks.get(i);
-            if (task.mAffiliatedTaskId == affiliateId) {
-                mRecentTasks.remove(i);
-                mTmpRecents.add(task);
-            }
-        }
-
-        // Sort them all by taskId. That is the order they were create in and that order will
-        // always be correct.
-        Collections.sort(mTmpRecents, mTaskRecordComparator);
-
-        // Go through and fix up the linked list.
-        // The first one is the end of the chain and has no next.
-        final TaskRecord first = mTmpRecents.get(0);
-        first.inRecents = true;
-        if (first.mNextAffiliate != null) {
-            Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
-            first.setNextAffiliate(null);
-            notifyTaskPersisterLocked(first, false);
-        }
-        // Everything in the middle is doubly linked from next to prev.
-        final int tmpSize = mTmpRecents.size();
-        for (int i = 0; i < tmpSize - 1; ++i) {
-            final TaskRecord next = mTmpRecents.get(i);
-            final TaskRecord prev = mTmpRecents.get(i + 1);
-            if (next.mPrevAffiliate != prev) {
-                Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
-                        " setting prev=" + prev);
-                next.setPrevAffiliate(prev);
-                notifyTaskPersisterLocked(next, false);
-            }
-            if (prev.mNextAffiliate != next) {
-                Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
-                        " setting next=" + next);
-                prev.setNextAffiliate(next);
-                notifyTaskPersisterLocked(prev, false);
-            }
-            prev.inRecents = true;
-        }
-        // The last one is the beginning of the list and has no prev.
-        final TaskRecord last = mTmpRecents.get(tmpSize - 1);
-        if (last.mPrevAffiliate != null) {
-            Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
-            last.setPrevAffiliate(null);
-            notifyTaskPersisterLocked(last, false);
-        }
-
-        // Insert the group back into mRecentTasks at start.
-        mRecentTasks.addAll(start, mTmpRecents);
-
-        // Let the caller know where we left off.
-        return start + tmpSize;
-    }
-
-    /**
-     * Update the recent tasks lists: make sure tasks should still be here (their
-     * applications / activities still exist), update their availability, fixup ordering
-     * of affiliations.
-     */
-    void cleanupRecentTasksLocked(int userId) {
-        if (mRecentTasks == null) {
-            // Happens when called from the packagemanager broadcast before boot.
-            return;
-        }
-
-        final HashMap<ComponentName, ActivityInfo> availActCache = new HashMap<>();
-        final HashMap<String, ApplicationInfo> availAppCache = new HashMap<>();
-        final IPackageManager pm = AppGlobals.getPackageManager();
-        final ActivityInfo dummyAct = new ActivityInfo();
-        final ApplicationInfo dummyApp = new ApplicationInfo();
-
-        int N = mRecentTasks.size();
-
-        int[] users = userId == UserHandle.USER_ALL
-                ? getUsersLocked() : new int[] { userId };
-        for (int user : users) {
-            for (int i = 0; i < N; i++) {
-                TaskRecord task = mRecentTasks.get(i);
-                if (task.userId != user) {
-                    // Only look at tasks for the user ID of interest.
-                    continue;
-                }
-                if (task.autoRemoveRecents && task.getTopActivity() == null) {
-                    // This situation is broken, and we should just get rid of it now.
-                    mRecentTasks.remove(i);
-                    task.removedFromRecents();
-                    i--;
-                    N--;
-                    Slog.w(TAG, "Removing auto-remove without activity: " + task);
-                    continue;
-                }
-                // Check whether this activity is currently available.
-                if (task.realActivity != null) {
-                    ActivityInfo ai = availActCache.get(task.realActivity);
-                    if (ai == null) {
-                        try {
-                            ai = pm.getActivityInfo(task.realActivity,
-                                    PackageManager.GET_UNINSTALLED_PACKAGES
-                                    | PackageManager.GET_DISABLED_COMPONENTS, user);
-                        } catch (RemoteException e) {
-                            // Will never happen.
-                            continue;
-                        }
-                        if (ai == null) {
-                            ai = dummyAct;
-                        }
-                        availActCache.put(task.realActivity, ai);
-                    }
-                    if (ai == dummyAct) {
-                        // This could be either because the activity no longer exists, or the
-                        // app is temporarily gone.  For the former we want to remove the recents
-                        // entry; for the latter we want to mark it as unavailable.
-                        ApplicationInfo app = availAppCache.get(task.realActivity.getPackageName());
-                        if (app == null) {
-                            try {
-                                app = pm.getApplicationInfo(task.realActivity.getPackageName(),
-                                        PackageManager.GET_UNINSTALLED_PACKAGES
-                                        | PackageManager.GET_DISABLED_COMPONENTS, user);
-                            } catch (RemoteException e) {
-                                // Will never happen.
-                                continue;
-                            }
-                            if (app == null) {
-                                app = dummyApp;
-                            }
-                            availAppCache.put(task.realActivity.getPackageName(), app);
-                        }
-                        if (app == dummyApp || (app.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            // Doesn't exist any more!  Good-bye.
-                            mRecentTasks.remove(i);
-                            task.removedFromRecents();
-                            i--;
-                            N--;
-                            Slog.w(TAG, "Removing no longer valid recent: " + task);
-                            continue;
-                        } else {
-                            // Otherwise just not available for now.
-                            if (task.isAvailable) {
-                                if (DEBUG_RECENTS) Slog.d(TAG, "Making recent unavailable: "
-                                        + task);
-                            }
-                            task.isAvailable = false;
-                        }
-                    } else {
-                        if (!ai.enabled || !ai.applicationInfo.enabled
-                                || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            if (task.isAvailable) {
-                                if (DEBUG_RECENTS) Slog.d(TAG, "Making recent unavailable: "
-                                        + task + " (enabled=" + ai.enabled + "/"
-                                        + ai.applicationInfo.enabled +  " flags="
-                                        + Integer.toHexString(ai.applicationInfo.flags) + ")");
-                            }
-                            task.isAvailable = false;
-                        } else {
-                            if (!task.isAvailable) {
-                                if (DEBUG_RECENTS) Slog.d(TAG, "Making recent available: "
-                                        + task);
-                            }
-                            task.isAvailable = true;
-                        }
-                    }
-                }
-            }
-        }
-
-        // Verify the affiliate chain for each task.
-        for (int i = 0; i < N; i = processNextAffiliateChainLocked(i)) {
-        }
-
-        mTmpRecents.clear();
-        // mRecentTasks is now in sorted, affiliated order.
-    }
-
-    private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
-        int N = mRecentTasks.size();
-        TaskRecord top = task;
-        int topIndex = taskIndex;
-        while (top.mNextAffiliate != null && topIndex > 0) {
-            top = top.mNextAffiliate;
-            topIndex--;
-        }
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at "
-                + topIndex + " from intial " + taskIndex);
-        // Find the end of the chain, doing a sanity check along the way.
-        boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
-        int endIndex = topIndex;
-        TaskRecord prev = top;
-        while (endIndex < N) {
-            TaskRecord cur = mRecentTasks.get(endIndex);
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @"
-                    + endIndex + " " + cur);
-            if (cur == top) {
-                // Verify start of the chain.
-                if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
-                    Slog.wtf(TAG, "Bad chain @" + endIndex
-                            + ": first task has next affiliate: " + prev);
-                    sane = false;
-                    break;
-                }
-            } else {
-                // Verify middle of the chain's next points back to the one before.
-                if (cur.mNextAffiliate != prev
-                        || cur.mNextAffiliateTaskId != prev.taskId) {
-                    Slog.wtf(TAG, "Bad chain @" + endIndex
-                            + ": middle task " + cur + " @" + endIndex
-                            + " has bad next affiliate "
-                            + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId
-                            + ", expected " + prev);
-                    sane = false;
-                    break;
-                }
-            }
-            if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) {
-                // Chain ends here.
-                if (cur.mPrevAffiliate != null) {
-                    Slog.wtf(TAG, "Bad chain @" + endIndex
-                            + ": last task " + cur + " has previous affiliate "
-                            + cur.mPrevAffiliate);
-                    sane = false;
-                }
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex);
-                break;
-            } else {
-                // Verify middle of the chain's prev points to a valid item.
-                if (cur.mPrevAffiliate == null) {
-                    Slog.wtf(TAG, "Bad chain @" + endIndex
-                            + ": task " + cur + " has previous affiliate "
-                            + cur.mPrevAffiliate + " but should be id "
-                            + cur.mPrevAffiliate);
-                    sane = false;
-                    break;
-                }
-            }
-            if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) {
-                Slog.wtf(TAG, "Bad chain @" + endIndex
-                        + ": task " + cur + " has affiliated id "
-                        + cur.mAffiliatedTaskId + " but should be "
-                        + task.mAffiliatedTaskId);
-                sane = false;
-                break;
-            }
-            prev = cur;
-            endIndex++;
-            if (endIndex >= N) {
-                Slog.wtf(TAG, "Bad chain ran off index " + endIndex
-                        + ": last task " + prev);
-                sane = false;
-                break;
-            }
-        }
-        if (sane) {
-            if (endIndex < taskIndex) {
-                Slog.wtf(TAG, "Bad chain @" + endIndex
-                        + ": did not extend to task " + task + " @" + taskIndex);
-                sane = false;
-            }
-        }
-        if (sane) {
-            // All looks good, we can just move all of the affiliated tasks
-            // to the top.
-            for (int i=topIndex; i<=endIndex; i++) {
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task
-                        + " from " + i + " to " + (i-topIndex));
-                TaskRecord cur = mRecentTasks.remove(i);
-                mRecentTasks.add(i-topIndex, cur);
-            }
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks  " +  topIndex
-                    + " to " + endIndex);
-            return true;
-        }
-
-        // Whoops, couldn't do it.
-        return false;
-    }
-
-    final void addRecentTaskLocked(TaskRecord task) {
-        final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
-                || task.mNextAffiliateTaskId != INVALID_TASK_ID
-                || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
-
-        int N = mRecentTasks.size();
-        // Quick case: check if the top-most recent task is the same.
-        if (!isAffiliated && N > 0 && mRecentTasks.get(0) == task) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task);
-            return;
-        }
-        // Another quick case: check if this is part of a set of affiliated
-        // tasks that are at the top.
-        if (isAffiliated && N > 0 && task.inRecents
-                && task.mAffiliatedTaskId == mRecentTasks.get(0).mAffiliatedTaskId) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + mRecentTasks.get(0)
-                    + " at top when adding " + task);
-            return;
-        }
-        // Another quick case: never add voice sessions.
-        if (task.voiceSession != null) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task);
-            return;
-        }
-
-        boolean needAffiliationFix = false;
-
-        // Slightly less quick case: the task is already in recents, so all we need
-        // to do is move it.
-        if (task.inRecents) {
-            int taskIndex = mRecentTasks.indexOf(task);
-            if (taskIndex >= 0) {
-                if (!isAffiliated) {
-                    // Simple case: this is not an affiliated task, so we just move it to the front.
-                    mRecentTasks.remove(taskIndex);
-                    mRecentTasks.add(0, task);
-                    notifyTaskPersisterLocked(task, false);
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task
-                            + " from " + taskIndex);
-                    return;
-                } else {
-                    // More complicated: need to keep all affiliated tasks together.
-                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
-                        // All went well.
-                        return;
-                    }
-
-                    // Uh oh...  something bad in the affiliation chain, try to rebuild
-                    // everything and then go through our general path of adding a new task.
-                    needAffiliationFix = true;
-                }
-            } else {
-                Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
-                needAffiliationFix = true;
-            }
-        }
-
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
-        trimRecentsForTaskLocked(task, true);
-
-        N = mRecentTasks.size();
-        while (N >= ActivityManager.getMaxRecentTasksStatic()) {
-            final TaskRecord tr = mRecentTasks.remove(N - 1);
-            tr.removedFromRecents();
-            N--;
-        }
-        task.inRecents = true;
-        if (!isAffiliated || needAffiliationFix) {
-            // If this is a simple non-affiliated task, or we had some failure trying to
-            // handle it as part of an affilated task, then just place it at the top.
-            mRecentTasks.add(0, task);
-        } else if (isAffiliated) {
-            // If this is a new affiliated task, then move all of the affiliated tasks
-            // to the front and insert this new one.
-            TaskRecord other = task.mNextAffiliate;
-            if (other == null) {
-                other = task.mPrevAffiliate;
-            }
-            if (other != null) {
-                int otherIndex = mRecentTasks.indexOf(other);
-                if (otherIndex >= 0) {
-                    // Insert new task at appropriate location.
-                    int taskIndex;
-                    if (other == task.mNextAffiliate) {
-                        // We found the index of our next affiliation, which is who is
-                        // before us in the list, so add after that point.
-                        taskIndex = otherIndex+1;
-                    } else {
-                        // We found the index of our previous affiliation, which is who is
-                        // after us in the list, so add at their position.
-                        taskIndex = otherIndex;
-                    }
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at "
-                            + taskIndex + ": " + task);
-                    mRecentTasks.add(taskIndex, task);
-
-                    // Now move everything to the front.
-                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
-                        // All went well.
-                        return;
-                    }
-
-                    // Uh oh...  something bad in the affiliation chain, try to rebuild
-                    // everything and then go through our general path of adding a new task.
-                    needAffiliationFix = true;
-                } else {
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation "
-                            + other);
-                    needAffiliationFix = true;
-                }
-            } else {
-                if (DEBUG_RECENTS) Slog.d(TAG,
-                        "addRecent: adding affiliated task without next/prev:" + task);
-                needAffiliationFix = true;
-            }
-        }
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task);
-
-        if (needAffiliationFix) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations");
-            cleanupRecentTasksLocked(task.userId);
-        }
-    }
-
-    /**
-     * If needed, remove oldest existing entries in recents that are for the same kind
-     * of task as the given one.
-     */
-    int trimRecentsForTaskLocked(TaskRecord task, boolean doTrim) {
-        int N = mRecentTasks.size();
-        final Intent intent = task.intent;
-        final boolean document = intent != null && intent.isDocument();
-
-        int maxRecents = task.maxRecents - 1;
-        for (int i=0; i<N; i++) {
-            final TaskRecord tr = mRecentTasks.get(i);
-            if (task != tr) {
-                if (task.userId != tr.userId) {
-                    continue;
-                }
-                if (i > MAX_RECENT_BITMAPS) {
-                    tr.freeLastThumbnail();
-                }
-                final Intent trIntent = tr.intent;
-                if ((task.affinity == null || !task.affinity.equals(tr.affinity)) &&
-                    (intent == null || !intent.filterEquals(trIntent))) {
-                    continue;
-                }
-                final boolean trIsDocument = trIntent != null && trIntent.isDocument();
-                if (document && trIsDocument) {
-                    // These are the same document activity (not necessarily the same doc).
-                    if (maxRecents > 0) {
-                        --maxRecents;
-                        continue;
-                    }
-                    // Hit the maximum number of documents for this task. Fall through
-                    // and remove this document from recents.
-                } else if (document || trIsDocument) {
-                    // Only one of these is a document. Not the droid we're looking for.
-                    continue;
-                }
-            }
-
-            if (!doTrim) {
-                // If the caller is not actually asking for a trim, just tell them we reached
-                // a point where the trim would happen.
-                return i;
-            }
-
-            // Either task and tr are the same or, their affinities match or their intents match
-            // and neither of them is a document, or they are documents using the same activity
-            // and their maxRecents has been reached.
-            tr.disposeThumbnail();
-            mRecentTasks.remove(i);
-            if (task != tr) {
-                tr.removedFromRecents();
-            }
-            i--;
-            N--;
-            if (task.intent == null) {
-                // If the new recent task we are adding is not fully
-                // specified, then replace it with the existing recent task.
-                task = tr;
-            }
-            notifyTaskPersisterLocked(tr, false);
-        }
-
-        return -1;
-    }
-
     @Override
     public void reportActivityFullyDrawn(IBinder token) {
         synchronized (this) {
@@ -4230,6 +3827,10 @@
             if (r == null) {
                 return;
             }
+            if (r.task != null && r.task.mResizeable) {
+                // Fixed screen orientation isn't supported with resizeable activities.
+                return;
+            }
             final long origId = Binder.clearCallingIdentity();
             mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -4354,11 +3955,10 @@
                 return;
             }
 
-            ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(
-                    mHeavyWeightProcess.activities);
-            for (int i=0; i<activities.size(); i++) {
+            ArrayList<ActivityRecord> activities = new ArrayList<>(mHeavyWeightProcess.activities);
+            for (int i = 0; i < activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
-                if (!r.finishing) {
+                if (!r.finishing && r.isInStackLocked()) {
                     r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
                             null, "finish-heavy", true);
                 }
@@ -4485,7 +4085,7 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r.task == null || r.task.stack == null) {
+                if (r == null) {
                     return false;
                 }
                 return r.task.stack.safelyDestroyActivityLocked(r, "app-req");
@@ -4710,9 +4310,8 @@
                 doLowMem = false;
             }
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
-            if (DEBUG_CLEANUP) Slog.v(
-                TAG, "Dying app: " + app + ", pid: " + pid
-                + ", thread: " + thread.asBinder());
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
             handleAppDiedLocked(app, false, true);
 
             if (doOomAdj) {
@@ -5833,6 +5432,7 @@
             // Take care of any services that are waiting for the process.
             mServices.processStartTimedOutLocked(app);
             app.kill("start timeout", true);
+            removeLruProcessLocked(app);
             if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 try {
@@ -5892,7 +5492,7 @@
 
         // Tell the process all about itself.
 
-        if (localLOGV) Slog.v(
+        if (DEBUG_ALL) Slog.v(
                 TAG, "Binding process pid " + pid + " to record " + app);
 
         final String processName = app.processName;
@@ -5928,7 +5528,7 @@
             Slog.i(TAG, "Launching preboot mode app: " + app);
         }
 
-        if (localLOGV) Slog.v(
+        if (DEBUG_ALL) Slog.v(
             TAG, "New app record " + app
             + " thread=" + thread.asBinder() + " pid=" + pid);
         try {
@@ -6049,7 +5649,8 @@
 
         // Check whether the next backup agent is in this process...
         if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
-            if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
+            if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
+                    "New app is backup target, launching agent for " + app);
             ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
@@ -6123,7 +5724,10 @@
 
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        enforceNotIsolatedCaller("showBootMessage");
+        if (Binder.getCallingUid() != Process.myUid()) {
+            // These days only the core system can call this, so apps can't get in
+            // the way of what we show about running them.
+        }
         mWindowManager.showBootMessage(msg, always);
     }
 
@@ -6177,7 +5781,7 @@
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
                             if (forceStopPackageLocked(pkg, -1, false, false, false, false, false,
-                                    0, "finished booting")) {
+                                    0, "query restart")) {
                                 setResultCode(Activity.RESULT_OK);
                                 return;
                             }
@@ -6187,6 +5791,19 @@
             }
         }, pkgFilter);
 
+        IntentFilter dumpheapFilter = new IntentFilter();
+        dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) {
+                    mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000);
+                } else {
+                    mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+                }
+            }
+        }, dumpheapFilter);
+
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -6316,7 +5933,7 @@
     @Override
     public final void activityStopped(IBinder token, Bundle icicle,
             PersistableBundle persistentState, CharSequence description) {
-        if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token);
 
         // Refuse possible leaked file descriptors
         if (icicle != null && icicle.hasFileDescriptors()) {
@@ -6742,7 +6359,7 @@
                 "setProcessForeground()");
         synchronized(this) {
             boolean changed = false;
-            
+
             synchronized (mPidsSelfLocked) {
                 ProcessRecord pr = mPidsSelfLocked.get(pid);
                 if (pr == null && isForeground) {
@@ -6778,13 +6395,52 @@
                     }
                 }
             }
-            
+
             if (changed) {
                 updateOomAdjLocked();
             }
         }
     }
-    
+
+    // =========================================================
+    // PROCESS INFO
+    // =========================================================
+
+    static class ProcessInfoService extends IProcessInfoService.Stub {
+        final ActivityManagerService mActivityManagerService;
+        ProcessInfoService(ActivityManagerService activityManagerService) {
+            mActivityManagerService = activityManagerService;
+        }
+
+        @Override
+        public void getProcessStatesFromPids(/*in*/ int[] pids, /*out*/ int[] states) {
+            mActivityManagerService.getProcessStatesForPIDs(/*in*/ pids, /*out*/ states);
+        }
+    }
+
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or -1 to indicate that no
+     * process with the given PID exists.
+     */
+    public void getProcessStatesForPIDs(/*in*/ int[] pids, /*out*/ int[] states) {
+        if (pids == null) {
+            throw new NullPointerException("pids");
+        } else if (states == null) {
+            throw new NullPointerException("states");
+        } else if (pids.length != states.length) {
+            throw new IllegalArgumentException("input and output arrays have different lengths!");
+        }
+
+        synchronized (mPidsSelfLocked) {
+            for (int i = 0; i < pids.length; i++) {
+                ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
+                states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT :
+                        pr.curProcState;
+            }
+        }
+    }
+
     // =========================================================
     // PERMISSIONS
     // =========================================================
@@ -6834,7 +6490,7 @@
      * permission is automatically denied.  (Internally a null permission
      * string is used when calling {@link #checkComponentPermission} in cases
      * when only uid-based security is needed.)
-     * 
+     *
      * This can be called with or without the global lock held.
      */
     @Override
@@ -7111,12 +6767,12 @@
             if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                     "Checking grant " + targetPkg + " permission to " + grantUri);
         }
-        
+
         final IPackageManager pm = AppGlobals.getPackageManager();
 
         // If this is not a content: uri, we can't do anything with it.
         if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                     "Can't grant URI permission for non-content URI: " + grantUri);
             return -1;
         }
@@ -7244,7 +6900,7 @@
         // to the uri, and the target doesn't.  Let's now give this to
         // the target.
 
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                 "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
 
         final String authority = grantUri.uri.getAuthority();
@@ -7446,7 +7102,7 @@
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
                     perm.targetUid);
             if (perms != null) {
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                         "Removing " + perm.targetUid + " permission to " + perm.uri);
 
                 perms.remove(perm.uri);
@@ -7559,7 +7215,6 @@
                 return;
             }
 
-            final IPackageManager pm = AppGlobals.getPackageManager();
             final String authority = uri.getAuthority();
             final ProviderInfo pi = getProviderInfoLocked(authority, userId);
             if (pi == null) {
@@ -8015,7 +7670,7 @@
         outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
                 ProcessList.FOREGROUND_APP_ADJ);
     }
-    
+
     // =========================================================
     // TASK MANAGEMENT
     // =========================================================
@@ -8028,7 +7683,7 @@
         synchronized(this) {
             ArrayList<IAppTask> list = new ArrayList<IAppTask>();
             try {
-                if (localLOGV) Slog.v(TAG, "getAppTasks");
+                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
 
                 final int N = mRecentTasks.size();
                 for (int i = 0; i < N; i++) {
@@ -8062,7 +7717,7 @@
         ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
 
         synchronized(this) {
-            if (localLOGV) Slog.v(
+            if (DEBUG_ALL) Slog.v(
                 TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
 
             final boolean allowed = isGetTasksAllowed("getTasks", Binder.getCallingPid(),
@@ -8141,20 +7796,19 @@
                     android.Manifest.permission.GET_DETAILED_TASKS)
                     == PackageManager.PERMISSION_GRANTED;
 
-            final int N = mRecentTasks.size();
-            ArrayList<ActivityManager.RecentTaskInfo> res
-                    = new ArrayList<ActivityManager.RecentTaskInfo>(
-                            maxNum < N ? maxNum : N);
+            final int recentsCount = mRecentTasks.size();
+            ArrayList<ActivityManager.RecentTaskInfo> res =
+                    new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
 
             final Set<Integer> includedUsers;
             if (includeProfiles) {
                 includedUsers = getProfileIdsLocked(userId);
             } else {
-                includedUsers = new HashSet<Integer>();
+                includedUsers = new HashSet<>();
             }
             includedUsers.add(Integer.valueOf(userId));
 
-            for (int i=0; i<N && maxNum > 0; i++) {
+            for (int i = 0; i < recentsCount && maxNum > 0; i++) {
                 TaskRecord tr = mRecentTasks.get(i);
                 // Only add calling user or related users recent tasks
                 if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
@@ -8212,23 +7866,12 @@
         }
     }
 
-    TaskRecord recentTaskForIdLocked(int id) {
-        final int N = mRecentTasks.size();
-            for (int i=0; i<N; i++) {
-                TaskRecord tr = mRecentTasks.get(i);
-                if (tr.taskId == id) {
-                    return tr;
-                }
-            }
-            return null;
-    }
-
     @Override
     public ActivityManager.TaskThumbnail getTaskThumbnail(int id) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnail()");
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id);
+            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, false);
             if (tr != null) {
                 return tr.getTaskThumbnailLocked();
             }
@@ -8293,7 +7936,7 @@
                 TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskId(), ainfo,
                         intent, description);
 
-                int trimIdx = trimRecentsForTaskLocked(task, false);
+                int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
                 if (trimIdx >= 0) {
                     // If this would have caused a trim, then we'll abort because that
                     // means it would be added at the end of the list but then just removed.
@@ -8339,6 +7982,41 @@
     }
 
     @Override
+    public void setTaskResizeable(int taskId, boolean resizeable) {
+        synchronized (this) {
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, false);
+            if (task == null) {
+                Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
+                return;
+            }
+            if (task.mResizeable != resizeable) {
+                task.mResizeable = resizeable;
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
+                mStackSupervisor.resumeTopActivitiesLocked();
+            }
+        }
+    }
+
+    @Override
+    public void resizeTask(int taskId, Rect bounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizeTask()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+                if (task == null) {
+                    Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
+                    return;
+                }
+                mStackSupervisor.resizeTaskLocked(task, bounds);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filename) {
         if (!FileUtils.isValidExtFilename(filename)
                 || !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
@@ -8473,7 +8151,7 @@
      * @return Returns true if the given task was found and removed.
      */
     private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
-        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
         if (tr != null) {
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, killProcess);
@@ -8543,40 +8221,10 @@
         ActivityOptions.abort(options);
     }
 
-    @Override
-    public void moveTaskToBack(int taskId) {
-        enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
-                "moveTaskToBack()");
-
-        synchronized(this) {
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
-            if (tr != null) {
-                if (tr == mStackSupervisor.mLockTaskModeTask) {
-                    mStackSupervisor.showLockTaskToast();
-                    return;
-                }
-                if (DEBUG_STACK) Slog.d(TAG, "moveTaskToBack: moving task=" + tr);
-                ActivityStack stack = tr.stack;
-                if (stack.mResumedActivity != null && stack.mResumedActivity.task == tr) {
-                    if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
-                            Binder.getCallingUid(), -1, -1, "Task to back")) {
-                        return;
-                    }
-                }
-                final long origId = Binder.clearCallingIdentity();
-                try {
-                    stack.moveTaskToBackLocked(taskId);
-                } finally {
-                    Binder.restoreCallingIdentity(origId);
-                }
-            }
-        }
-    }
-
     /**
      * Moves an activity, and all of the other activities within the same task, to the bottom
      * of the history stack.  The activity's order within the task is unchanged.
-     * 
+     *
      * @param token A reference to the activity we wish to move
      * @param nonRoot If false then this only works if the activity is the root
      *                of a task; if true it will work for any activity in a task.
@@ -8634,7 +8282,7 @@
     }
 
     @Override
-    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+    public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                 "createActivityContainer()");
@@ -8642,14 +8290,14 @@
             if (parentActivityToken == null) {
                 throw new IllegalArgumentException("parent token must not be null");
             }
-            ActivityRecord r = ActivityRecord.forToken(parentActivityToken);
+            ActivityRecord r = ActivityRecord.forTokenLocked(parentActivityToken);
             if (r == null) {
                 return null;
             }
             if (callback == null) {
                 throw new IllegalArgumentException("callback must not be null");
             }
-            return mStackSupervisor.createActivityContainer(r, callback);
+            return mStackSupervisor.createVirtualActivityContainer(r, callback);
         }
     }
 
@@ -8663,14 +8311,27 @@
     }
 
     @Override
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException {
+    public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "createStackOnDisplay()");
+        synchronized (this) {
+            final int stackId = mStackSupervisor.getNextStackId();
+            final ActivityStack stack = mStackSupervisor.createStackOnDisplay(stackId, displayId);
+            if (stack == null) {
+                return null;
+            }
+            return stack.mActivityContainer;
+        }
+    }
+
+    @Override
+    public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
-            if (stack != null) {
-                return stack.mActivityContainer;
+            if (stack != null && stack.mActivityContainer.isAttachedLocked()) {
+                return stack.mActivityContainer.getDisplayId();
             }
-            return null;
+            return Display.DEFAULT_DISPLAY;
         }
     }
 
@@ -8695,12 +8356,14 @@
     }
 
     @Override
-    public void resizeStack(int stackBoxId, Rect bounds) {
+    public void resizeStack(int stackId, Rect bounds) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeStackBox()");
+                "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
-            mWindowManager.resizeStack(stackBoxId, bounds);
+            synchronized (this) {
+                mStackSupervisor.resizeStackLocked(stackId, bounds);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8741,7 +8404,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
                 return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
@@ -8773,6 +8436,9 @@
         synchronized (this) {
             pkg = task.intent.getComponent().getPackageName();
         }
+        // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
+        // is initiated by system after the pinning request was shown and locked mode is initiated
+        // by an authorized app directly
         boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
         if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
             StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -8793,7 +8459,9 @@
                                     || (task != mStackSupervisor.getFocusedStack().topTask()))) {
                         throw new IllegalArgumentException("Invalid task, not in foreground");
                     }
-                    mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated,
+                    mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
+                            ActivityManager.LOCK_TASK_MODE_PINNED :
+                            ActivityManager.LOCK_TASK_MODE_LOCKED,
                             "startLockTask");
                 }
             }
@@ -8824,7 +8492,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                final ActivityRecord r = ActivityRecord.forToken(token);
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                 if (r == null) {
                     return;
                 }
@@ -8879,7 +8547,8 @@
             Log.d(TAG, "stopLockTaskMode");
             // Stop lock task
             synchronized (this) {
-                mStackSupervisor.setLockTaskModeLocked(null, false, "stopLockTask");
+                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+                        "stopLockTask");
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -8900,8 +8569,13 @@
 
     @Override
     public boolean isInLockTaskMode() {
+        return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE;
+    }
+
+    @Override
+    public int getLockTaskModeState() {
         synchronized (this) {
-            return mStackSupervisor.isInLockTaskMode();
+            return mStackSupervisor.getLockTaskModeState();
         }
     }
 
@@ -9002,7 +8676,7 @@
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
-        
+
         PathPermission[] pps = cpi.pathPermissions;
         if (pps != null) {
             int i = pps.length;
@@ -9413,11 +9087,13 @@
                             if (DEBUG_PROVIDER) {
                                 Slog.d(TAG, "Installing in existing process " + proc);
                             }
-                            checkTime(startTime, "getContentProviderImpl: scheduling install");
-                            proc.pubProviders.put(cpi.name, cpr);
-                            try {
-                                proc.thread.scheduleInstallProvider(cpi);
-                            } catch (RemoteException e) {
+                            if (!proc.pubProviders.containsKey(cpi.name)) {
+                                checkTime(startTime, "getContentProviderImpl: scheduling install");
+                                proc.pubProviders.put(cpi.name, cpr);
+                                try {
+                                    proc.thread.scheduleInstallProvider(cpi);
+                                } catch (RemoteException e) {
+                                }
                             }
                         } else {
                             checkTime(startTime, "getContentProviderImpl: before start process");
@@ -9567,7 +9243,7 @@
             ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
             if(cpr == null) {
                 //remove from mProvidersByClass
-                if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list");
+                if(DEBUG_ALL) Slog.v(TAG, name+" content provider not found in providers list");
                 return;
             }
 
@@ -9588,7 +9264,7 @@
             }
         }
     }
-    
+
     public final void publishContentProviders(IApplicationThread caller,
             List<ContentProviderHolder> providers) {
         if (providers == null) {
@@ -9982,10 +9658,9 @@
             } finally {
                 // Ensure that whatever happens, we clean up the identity state
                 sCallerIdentity.remove();
+                // Ensure we're done with the provider.
+                removeContentProviderExternalUnchecked(name, null, userId);
             }
-
-            // We've got the fd now, so we're done with the provider.
-            removeContentProviderExternalUnchecked(name, null, userId);
         } else {
             Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
         }
@@ -10071,6 +9746,11 @@
     }
 
     @Override
+    public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
+        mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
+    }
+
+    @Override
     public boolean shutdown(int timeout) {
         if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -10100,7 +9780,7 @@
     }
 
     public final void activitySlept(IBinder token) {
-        if (localLOGV) Slog.v(TAG, "Activity slept: token=" + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity slept: token=" + token);
 
         final long origId = Binder.clearCallingIdentity();
 
@@ -10167,7 +9847,7 @@
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.STOP_APP_SWITCHES);
         }
-        
+
         synchronized(this) {
             mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
                     + APP_SWITCH_DELAY_TIME;
@@ -10177,14 +9857,14 @@
             mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
         }
     }
-    
+
     public void resumeAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.STOP_APP_SWITCHES);
         }
-        
+
         synchronized(this) {
             // Note that we don't execute any pending app switches... we will
             // let those wait until either the timeout, or the next start
@@ -10192,7 +9872,7 @@
             mAppSwitchesAllowedTime = 0;
         }
     }
-    
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
@@ -10220,7 +9900,7 @@
         Slog.w(TAG, name + " request from " + sourceUid + " stopped");
         return false;
     }
-    
+
     public void setDebugApp(String packageName, boolean waitForDebugger,
             boolean persistent) {
         enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
@@ -10436,8 +10116,9 @@
         return true;
     }
 
+    @Override
     public Bundle getAssistContextExtras(int requestType) {
-        PendingAssistExtras pae = enqueueAssistContext(requestType, null, null,
+        PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
                 UserHandle.getCallingUserId());
         if (pae == null) {
             return null;
@@ -10449,30 +10130,30 @@
                 } catch (InterruptedException e) {
                 }
             }
-            if (pae.result != null) {
-                pae.extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, pae.result);
-            }
         }
         synchronized (this) {
+            buildAssistBundleLocked(pae, pae.result);
             mPendingAssistExtras.remove(pae);
             mHandler.removeCallbacks(pae);
         }
         return pae.extras;
     }
 
+    @Override
+    public void requestAssistContextExtras(int requestType, IResultReceiver receiver) {
+        enqueueAssistContext(requestType, null, null, receiver, UserHandle.getCallingUserId());
+    }
+
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            int userHandle) {
+            IResultReceiver receiver, int userHandle) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
-                "getAssistContextExtras()");
-        PendingAssistExtras pae;
-        Bundle extras = new Bundle();
+                "enqueueAssistContext()");
         synchronized (this) {
-            ActivityRecord activity = getFocusedStack().mResumedActivity;
+            ActivityRecord activity = getFocusedStack().topActivity();
             if (activity == null) {
-                Slog.w(TAG, "getAssistContextExtras failed: no resumed activity");
+                Slog.w(TAG, "getAssistContextExtras failed: no top activity");
                 return null;
             }
-            extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             if (activity.app == null || activity.app.thread == null) {
                 Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return null;
@@ -10481,7 +10162,11 @@
                 Slog.w(TAG, "getAssistContextExtras failed: request process same as " + activity);
                 return null;
             }
-            pae = new PendingAssistExtras(activity, extras, intent, hint, userHandle);
+            PendingAssistExtras pae;
+            Bundle extras = new Bundle();
+            extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
+            extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+            pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, userHandle);
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
                         requestType);
@@ -10495,13 +10180,33 @@
         }
     }
 
+    void pendingAssistExtrasTimedOutLocked(PendingAssistExtras pae) {
+        mPendingAssistExtras.remove(pae);
+        if (pae.receiver != null) {
+            // Caller wants result sent back to them.
+            try {
+                pae.receiver.send(0, null);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    private void buildAssistBundleLocked(PendingAssistExtras pae, Bundle result) {
+        if (result != null) {
+            pae.extras.putBundle(Intent.EXTRA_ASSIST_CONTEXT, result);
+        }
+        if (pae.hint != null) {
+            pae.extras.putBoolean(pae.hint, true);
+        }
+    }
+
     public void reportAssistContextExtras(IBinder token, Bundle extras) {
         PendingAssistExtras pae = (PendingAssistExtras)token;
         synchronized (pae) {
             pae.result = extras;
             pae.haveResult = true;
             pae.notifyAll();
-            if (pae.intent == null) {
+            if (pae.intent == null && pae.receiver == null) {
                 // Caller is just waiting for the result.
                 return;
             }
@@ -10509,17 +10214,23 @@
 
         // We are now ready to launch the assist activity.
         synchronized (this) {
+            buildAssistBundleLocked(pae, extras);
             boolean exists = mPendingAssistExtras.remove(pae);
             mHandler.removeCallbacks(pae);
             if (!exists) {
                 // Timed out.
                 return;
             }
+            if (pae.receiver != null) {
+                // Caller wants result sent back to them.
+                try {
+                    pae.receiver.send(0, pae.extras);
+                } catch (RemoteException e) {
+                }
+                return;
+            }
         }
-        pae.intent.replaceExtras(extras);
-        if (pae.hint != null) {
-            pae.intent.putExtra(pae.hint, true);
-        }
+        pae.intent.replaceExtras(pae.extras);
         pae.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_SINGLE_TOP
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -10532,7 +10243,7 @@
     }
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) {
-        return enqueueAssistContext(requestType, intent, hint, userHandle) != null;
+        return enqueueAssistContext(requestType, intent, hint, null, userHandle) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -10561,7 +10272,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(true);
                 if (translucentChanged) {
-                    r.task.stack.releaseBackgroundResources();
+                    r.task.stack.releaseBackgroundResources(r);
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                 }
                 mWindowManager.setAppFullscreen(token, true);
@@ -10588,7 +10299,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(false);
                 if (translucentChanged) {
-                    r.task.stack.convertToTranslucent(r);
+                    r.task.stack.convertActivityToTranslucent(r);
                 }
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                 mWindowManager.setAppFullscreen(token, false);
@@ -11105,9 +10816,68 @@
         }
     }
 
+    final class PreBootContinuation extends IIntentReceiver.Stub {
+        final Intent intent;
+        final Runnable onFinishCallback;
+        final ArrayList<ComponentName> doneReceivers;
+        final List<ResolveInfo> ris;
+        final int[] users;
+        int lastRi = -1;
+        int curRi = 0;
+        int curUser = 0;
+
+        PreBootContinuation(Intent _intent, Runnable _onFinishCallback,
+                ArrayList<ComponentName> _doneReceivers, List<ResolveInfo> _ris, int[] _users) {
+            intent = _intent;
+            onFinishCallback = _onFinishCallback;
+            doneReceivers = _doneReceivers;
+            ris = _ris;
+            users = _users;
+        }
+
+        void go() {
+            if (lastRi != curRi) {
+                ActivityInfo ai = ris.get(curRi).activityInfo;
+                ComponentName comp = new ComponentName(ai.packageName, ai.name);
+                intent.setComponent(comp);
+                doneReceivers.add(comp);
+                lastRi = curRi;
+                CharSequence label = ai.loadLabel(mContext.getPackageManager());
+                showBootMessage(mContext.getString(R.string.android_preparing_apk, label), false);
+            }
+            Slog.i(TAG, "Pre-boot of " + intent.getComponent().toShortString()
+                    + " for user " + users[curUser]);
+            EventLogTags.writeAmPreBoot(users[curUser], intent.getComponent().getPackageName());
+            broadcastIntentLocked(null, null, intent, null, this,
+                    0, null, null, null, AppOpsManager.OP_NONE,
+                    true, false, MY_PID, Process.SYSTEM_UID,
+                    users[curUser]);
+        }
+
+        public void performReceive(Intent intent, int resultCode,
+                String data, Bundle extras, boolean ordered,
+                boolean sticky, int sendingUser) {
+            curUser++;
+            if (curUser >= users.length) {
+                curUser = 0;
+                curRi++;
+                if (curRi >= ris.size()) {
+                    // All done sending broadcasts!
+                    if (onFinishCallback != null) {
+                        // The raw IIntentReceiver interface is called
+                        // with the AM lock held, so redispatch to
+                        // execute our code without the lock.
+                        mHandler.post(onFinishCallback);
+                    }
+                    return;
+                }
+            }
+            go();
+        }
+    }
+
     private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
             ArrayList<ComponentName> doneReceivers, int userId) {
-        boolean waitingUpdate = false;
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         List<ResolveInfo> ris = null;
         try {
@@ -11115,71 +10885,51 @@
                     intent, null, 0, userId);
         } catch (RemoteException e) {
         }
-        if (ris != null) {
-            for (int i=ris.size()-1; i>=0; i--) {
-                if ((ris.get(i).activityInfo.applicationInfo.flags
-                        &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                    ris.remove(i);
-                }
+        if (ris == null) {
+            return false;
+        }
+        for (int i=ris.size()-1; i>=0; i--) {
+            if ((ris.get(i).activityInfo.applicationInfo.flags
+                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
+                ris.remove(i);
             }
-            intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+        }
+        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
 
-            // For User 0, load the version number. When delivering to a new user, deliver
-            // to all receivers.
-            if (userId == UserHandle.USER_OWNER) {
-                ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-                for (int i=0; i<ris.size(); i++) {
-                    ActivityInfo ai = ris.get(i).activityInfo;
-                    ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                    if (lastDoneReceivers.contains(comp)) {
-                        // We already did the pre boot receiver for this app with the current
-                        // platform version, so don't do it again...
-                        ris.remove(i);
-                        i--;
-                        // ...however, do keep it as one that has been done, so we don't
-                        // forget about it when rewriting the file of last done receivers.
-                        doneReceivers.add(comp);
-                    }
-                }
-            }
-
-            // If primary user, send broadcast to all available users, else just to userId
-            final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
-                    : new int[] { userId };
-            for (int i = 0; i < ris.size(); i++) {
+        // For User 0, load the version number. When delivering to a new user, deliver
+        // to all receivers.
+        if (userId == UserHandle.USER_OWNER) {
+            ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+            for (int i=0; i<ris.size(); i++) {
                 ActivityInfo ai = ris.get(i).activityInfo;
                 ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                doneReceivers.add(comp);
-                intent.setComponent(comp);
-                for (int j=0; j<users.length; j++) {
-                    IIntentReceiver finisher = null;
-                    // On last receiver and user, set up a completion callback
-                    if (i == ris.size() - 1 && j == users.length - 1 && onFinishCallback != null) {
-                        finisher = new IIntentReceiver.Stub() {
-                            public void performReceive(Intent intent, int resultCode,
-                                    String data, Bundle extras, boolean ordered,
-                                    boolean sticky, int sendingUser) {
-                                // The raw IIntentReceiver interface is called
-                                // with the AM lock held, so redispatch to
-                                // execute our code without the lock.
-                                mHandler.post(onFinishCallback);
-                            }
-                        };
-                    }
-                    Slog.i(TAG, "Sending system update to " + intent.getComponent()
-                            + " for user " + users[j]);
-                    broadcastIntentLocked(null, null, intent, null, finisher,
-                            0, null, null, null, AppOpsManager.OP_NONE,
-                            true, false, MY_PID, Process.SYSTEM_UID,
-                            users[j]);
-                    if (finisher != null) {
-                        waitingUpdate = true;
-                    }
+                if (false && lastDoneReceivers.contains(comp)) {
+                    // We already did the pre boot receiver for this app with the current
+                    // platform version, so don't do it again...
+                    ris.remove(i);
+                    i--;
+                    // ...however, do keep it as one that has been done, so we don't
+                    // forget about it when rewriting the file of last done receivers.
+                    doneReceivers.add(comp);
                 }
             }
         }
 
-        return waitingUpdate;
+        if (ris.size() <= 0) {
+            return false;
+        }
+
+        // If primary user, send broadcast to all available users, else just to userId
+        final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
+                : new int[] { userId };
+        if (users.length <= 0) {
+            return false;
+        }
+
+        PreBootContinuation cont = new PreBootContinuation(intent, onFinishCallback, doneReceivers,
+                ris, users);
+        cont.go();
+        return true;
     }
 
     public void systemReady(final Runnable goingCallback) {
@@ -11197,12 +10947,11 @@
             // security checks.
             updateCurrentProfileIdsLocked();
 
-            if (mRecentTasks == null) {
-                mRecentTasks = mTaskPersister.restoreTasksLocked();
-                mTaskPersister.restoreTasksFromOtherDeviceLocked();
-                cleanupRecentTasksLocked(UserHandle.USER_ALL);
-                mTaskPersister.startPersisting();
-            }
+            mRecentTasks.clear();
+            mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
+            mTaskPersister.restoreTasksFromOtherDeviceLocked();
+            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
+            mTaskPersister.startPersisting();
 
             // Check to see if there are any update receivers to run.
             if (!mDidUpdate) {
@@ -11215,9 +10964,10 @@
                         synchronized (ActivityManagerService.this) {
                             mDidUpdate = true;
                         }
-                        writeLastDonePreBootReceivers(doneReceivers);
-                        showBootMessage(mContext.getText(R.string.android_upgrading_complete),
+                        showBootMessage(mContext.getText(
+                                R.string.android_upgrading_complete),
                                 false);
+                        writeLastDonePreBootReceivers(doneReceivers);
                         systemReady(goingCallback);
                     }
                 }, doneReceivers, UserHandle.USER_OWNER);
@@ -11244,7 +10994,7 @@
                 }
             }
         }
-        
+
         synchronized(this) {
             if (procsToKill != null) {
                 for (int i=procsToKill.size()-1; i>=0; i--) {
@@ -11253,20 +11003,20 @@
                     removeProcessLocked(proc, true, false, "system update done");
                 }
             }
-            
+
             // Now that we have cleaned up any update processes, we
             // are ready to start launching real processes and know that
             // we won't trample on them any more.
             mProcessesReady = true;
         }
-        
+
         Slog.i(TAG, "System now ready");
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
             SystemClock.uptimeMillis());
 
         synchronized(this) {
             // Make sure we have no pre-ready processes sitting around.
-            
+
             if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 ResolveInfo ri = mContext.getPackageManager()
                         .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
@@ -11350,7 +11100,7 @@
             } catch (RemoteException e) {
             }
 
-            if (!Build.isFingerprintConsistent()) {
+            if (!Build.isBuildConsistent()) {
                 Slog.e(TAG, "Build fingerprint is not consistent, warning user");
                 mHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
             }
@@ -11394,7 +11144,7 @@
                 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
         startAppProblemLocked(app);
         app.stopFreezingAllLocked();
-        return handleAppCrashLocked(app, shortMsg, longMsg, stackTrace);
+        return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace);
     }
 
     private void makeAppNotRespondingLocked(ProcessRecord app,
@@ -11406,12 +11156,12 @@
         startAppProblemLocked(app);
         app.stopFreezingAllLocked();
     }
-    
+
     /**
      * Generate a process error record, suitable for attachment to a ProcessRecord.
-     * 
+     *
      * @param app The ProcessRecord in which the error occurred.
-     * @param condition Crashing, Application Not Responding, etc.  Values are defined in 
+     * @param condition Crashing, Application Not Responding, etc.  Values are defined in
      *                      ActivityManager.AppErrorStateInfo
      * @param activity The activity associated with the crash, if known.
      * @param shortMsg Short message describing the crash.
@@ -11420,7 +11170,7 @@
      *
      * @return Returns a fully-formed AppErrorStateInfo record.
      */
-    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app, 
+    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
             int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
         ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
 
@@ -11449,14 +11199,15 @@
                 app.waitDialog = null;
             }
             if (app.pid > 0 && app.pid != MY_PID) {
-                handleAppCrashLocked(app, null, null, null);
+                handleAppCrashLocked(app, "user-terminated" /*reason*/,
+                        null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/);
                 app.kill("user request after error", true);
             }
         }
     }
 
-    private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg,
-            String stackTrace) {
+    private boolean handleAppCrashLocked(ProcessRecord app, String reason,
+            String shortMsg, String longMsg, String stackTrace) {
         long now = SystemClock.uptimeMillis();
 
         Long crashTime;
@@ -11497,7 +11248,7 @@
             }
             mStackSupervisor.resumeTopActivitiesLocked();
         } else {
-            mStackSupervisor.finishTopRunningActivityLocked(app);
+            mStackSupervisor.finishTopRunningActivityLocked(app, reason);
         }
 
         // Bump up the crash count of any services currently running in the proc.
@@ -11700,8 +11451,12 @@
             sb.append("\n");
             if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
                 sb.append(info.crashInfo.stackTrace);
+                sb.append("\n");
             }
-            sb.append("\n");
+            if (info.message != null) {
+                sb.append(info.message);
+                sb.append("\n");
+            }
 
             // Only buffer up to ~64k.  Various logging bits truncate
             // things at 128k.
@@ -12189,14 +11944,14 @@
                     } else if (app.notResponding) {
                         report = app.notRespondingReport;
                     }
-                    
+
                     if (report != null) {
                         if (errList == null) {
                             errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
                         }
                         errList.add(report);
                     } else {
-                        Slog.w(TAG, "Missing app error report, app = " + app.processName + 
+                        Slog.w(TAG, "Missing app error report, app = " + app.processName +
                                 " crashing = " + app.crashing +
                                 " notResponding = " + app.notResponding);
                     }
@@ -12255,7 +12010,7 @@
                 }
                 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
                     // Generate process state info for running application
-                    ActivityManager.RunningAppProcessInfo currApp = 
+                    ActivityManager.RunningAppProcessInfo currApp =
                         new ActivityManager.RunningAppProcessInfo(app.processName,
                                 app.pid, app.getPackageList());
                     fillInProcMemInfo(app, currApp);
@@ -12337,7 +12092,7 @@
         boolean dumpAll = false;
         boolean dumpClient = false;
         String dumpPackage = null;
-        
+
         int opti = 0;
         while (opti < args.length) {
             String opt = args[opti];
@@ -12827,12 +12582,12 @@
                 }
             }
         }
-        
+
         if (mForegroundProcesses.size() > 0) {
             synchronized (mPidsSelfLocked) {
                 boolean printed = false;
                 for (int i=0; i<mForegroundProcesses.size(); i++) {
-                    ProcessRecord r = mPidsSelfLocked.get( 
+                    ProcessRecord r = mPidsSelfLocked.get(
                             mForegroundProcesses.valueAt(i).pid);
                     if (dumpPackage != null && (r == null
                             || !r.pkgList.containsKey(dumpPackage))) {
@@ -12850,7 +12605,7 @@
                 }
             }
         }
-        
+
         if (mPersistentStartingProcesses.size() > 0) {
             if (needSep) pw.println();
             needSep = true;
@@ -12868,7 +12623,7 @@
             dumpProcessList(pw, this, mRemovedProcesses, "    ",
                     "Removed Norm", "Removed PERS", dumpPackage);
         }
-        
+
         if (mProcessesOnHold.size() > 0) {
             if (needSep) pw.println();
             needSep = true;
@@ -12879,7 +12634,7 @@
         }
 
         needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
-        
+
         if (mProcessCrashTimes.getMap().size() > 0) {
             boolean printed = false;
             long now = SystemClock.uptimeMillis();
@@ -13074,6 +12829,22 @@
                         + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
             }
         }
+        if (mMemWatchProcesses.size() > 0) {
+            pw.println("  Mem watch processes:");
+            for (int i=0; i<mMemWatchProcesses.size(); i++) {
+                if (needSep) {
+                    pw.println();
+                    needSep = false;
+                }
+                pw.print("    "); pw.print(mMemWatchProcesses.keyAt(i));
+                pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
+                pw.println();
+            }
+            pw.print("  mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
+            pw.print("  mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
+            pw.print("  mMemWatchDumpPid="); pw.print(mMemWatchDumpPid);
+                    pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+        }
         if (mOpenGlTraceApp != null) {
             if (dumpPackage == null || dumpPackage.equals(mOpenGlTraceApp)) {
                 if (needSep) {
@@ -13251,7 +13022,7 @@
         ArrayList<String> strings;
         ArrayList<Integer> objects;
         boolean all;
-        
+
         ItemMatcher() {
             all = true;
         }
@@ -13336,7 +13107,7 @@
     protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
         ArrayList<ActivityRecord> activities;
-        
+
         synchronized (this) {
             activities = mStackSupervisor.getDumpActivitiesLocked(name);
         }
@@ -13459,7 +13230,7 @@
         }
 
         needSep = true;
-        
+
         if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
             for (int user=0; user<mStickyBroadcasts.size(); user++) {
                 if (needSep) {
@@ -13494,7 +13265,7 @@
                 }
             }
         }
-        
+
         if (!onlyHistory && dumpAll) {
             pw.println();
             for (BroadcastQueue queue : mBroadcastQueues) {
@@ -13506,7 +13277,7 @@
             needSep = true;
             printedAnything = true;
         }
-        
+
         if (!printedAnything) {
             pw.println("  (nothing)");
         }
@@ -13756,8 +13527,9 @@
                 pw.print("    ");
                 pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
                 pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
-                pw.print(" lastPss="); pw.print(r.lastPss);
-                pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+                pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+                pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
+                pw.println();
                 pw.print(prefix);
                 pw.print("    ");
                 pw.print("cached="); pw.print(r.cached);
@@ -13846,7 +13618,7 @@
         long realtime = SystemClock.elapsedRealtime();
         pw.println("Applications Graphics Acceleration Info:");
         pw.println("Uptime: " + uptime + " Realtime: " + realtime);
-        
+
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = procs.get(i);
             if (r.thread != null) {
@@ -14071,7 +13843,7 @@
         boolean isCompact = false;
         boolean localOnly = false;
         boolean packages = false;
-        
+
         int opti = 0;
         while (opti < args.length) {
             String opt = args[opti];
@@ -14109,7 +13881,7 @@
                 pw.println("Unknown argument: " + opt + "; use -h for help");
             }
         }
-        
+
         final boolean isCheckinRequest = scanArgs(args, "--checkin");
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
@@ -14380,9 +14152,14 @@
             memInfo.readMemInfo();
             if (nativeProcTotalPss > 0) {
                 synchronized (this) {
-                    mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
-                            memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
-                            memInfo.getKernelUsedSizeKb(), nativeProcTotalPss);
+                    final long cachedKb = memInfo.getCachedSizeKb();
+                    final long freeKb = memInfo.getFreeSizeKb();
+                    final long zramKb = memInfo.getZramTotalSizeKb();
+                    final long kernelKb = memInfo.getKernelUsedSizeKb();
+                    EventLogTags.writeAmMeminfo(cachedKb*1024, freeKb*1024, zramKb*1024,
+                            kernelKb*1024, nativeProcTotalPss*1024);
+                    mProcessStats.addSysMemUsageLocked(cachedKb, freeKb, zramKb, kernelKb,
+                            nativeProcTotalPss);
                 }
             }
             if (!brief) {
@@ -14955,7 +14732,7 @@
 
         // If the app is undergoing backup, tell the backup manager about it
         if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
-            if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App "
+            if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
                     + mBackupTarget.appInfo + " died during backup");
             try {
                 IBackupManager bm = IBackupManager.Stub.asInterface(
@@ -14982,7 +14759,7 @@
         }
 
         if (!app.persistent || app.isolated) {
-            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG,
+            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                     "Removing non-persistent process during cleanup: " + app);
             mProcessNames.remove(app.processName, app.uid);
             mIsolatedProcesses.remove(app.uid);
@@ -15000,8 +14777,8 @@
                 restart = true;
             }
         }
-        if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(TAG,
-                "Clean-up removing on hold: " + app);
+        if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(
+                TAG_CLEANUP, "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
         if (app == mHomeProcess) {
@@ -15058,7 +14835,7 @@
         }
         return restart;
     }
-    
+
     // =========================================================
     // SERVICES
     // =========================================================
@@ -15140,7 +14917,7 @@
             return mServices.peekServiceLocked(service, resolvedType);
         }
     }
-    
+
     @Override
     public boolean stopServiceToken(ComponentName className, IBinder token,
             int startId) {
@@ -15363,16 +15140,17 @@
             mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
         }
     }
-    
+
     // =========================================================
     // BACKUP AND RESTORE
     // =========================================================
-    
+
     // Cause the target app to be launched if necessary and its backup agent
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode);
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
+                "bindBackupAgent: app=" + app + " mode=" + backupMode);
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
 
         synchronized(this) {
@@ -15415,7 +15193,7 @@
             // If the process is already attached, schedule the creation of the backup agent now.
             // If it is not yet live, this will be done when it attaches to the framework.
             if (proc.thread != null) {
-                if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc already running: " + proc);
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
                 try {
                     proc.thread.scheduleCreateBackupAgent(app,
                             compatibilityInfoForPackageLocked(app), backupMode);
@@ -15423,20 +15201,20 @@
                     // Will time out on the backup manager side
                 }
             } else {
-                if (DEBUG_BACKUP) Slog.v(TAG, "Agent proc not running, waiting for attach");
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc not running, waiting for attach");
             }
             // Invariants: at this point, the target app process exists and the application
             // is either already running or in the process of coming up.  mBackupTarget and
             // mBackupAppName describe the app, so that when it binds back to the AM we
             // know that it's scheduled for a backup-agent operation.
         }
-        
+
         return true;
     }
 
     @Override
     public void clearPendingBackup() {
-        if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup");
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup");
         enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
 
         synchronized (this) {
@@ -15447,7 +15225,7 @@
 
     // A backup agent has just come up
     public void backupAgentCreated(String agentPackageName, IBinder agent) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName
                 + " = " + agent);
 
         synchronized(this) {
@@ -15474,7 +15252,7 @@
 
     // done with this agent
     public void unbindBackupAgent(ApplicationInfo appInfo) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "unbindBackupAgent: " + appInfo);
+        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo);
         if (appInfo == null) {
             Slog.w(TAG, "unbind backup agent for null app");
             return;
@@ -15516,30 +15294,6 @@
     // BROADCASTS
     // =========================================================
 
-    private final List getStickiesLocked(String action, IntentFilter filter,
-            List cur, int userId) {
-        final ContentResolver resolver = mContext.getContentResolver();
-        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
-        if (stickies == null) {
-            return cur;
-        }
-        final ArrayList<Intent> list = stickies.get(action);
-        if (list == null) {
-            return cur;
-        }
-        int N = list.size();
-        for (int i=0; i<N; i++) {
-            Intent intent = list.get(i);
-            if (filter.match(resolver, intent, true, TAG) >= 0) {
-                if (cur == null) {
-                    cur = new ArrayList<Intent>();
-                }
-                cur.add(intent);
-            }
-        }
-        return cur;
-    }
-
     boolean isPendingBroadcastProcessLocked(int pid) {
         return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
                 || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
@@ -15564,10 +15318,11 @@
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
             IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
         enforceNotIsolatedCaller("registerReceiver");
+        ArrayList<Intent> stickyIntents = null;
+        ProcessRecord callerApp = null;
         int callingUid;
         int callingPid;
         synchronized(this) {
-            ProcessRecord callerApp = null;
             if (caller != null) {
                 callerApp = getRecordForAppLocked(caller);
                 if (callerApp == null) {
@@ -15590,39 +15345,66 @@
                 callingPid = Binder.getCallingPid();
             }
 
-            userId = this.handleIncomingUser(callingPid, callingUid, userId,
+            userId = handleIncomingUser(callingPid, callingUid, userId,
                     true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
 
-            List allSticky = null;
+            Iterator<String> actions = filter.actionsIterator();
+            if (actions == null) {
+                ArrayList<String> noAction = new ArrayList<String>(1);
+                noAction.add(null);
+                actions = noAction.iterator();
+            }
 
-            // Look for any matching sticky broadcasts...
-            Iterator actions = filter.actionsIterator();
-            if (actions != null) {
-                while (actions.hasNext()) {
-                    String action = (String)actions.next();
-                    allSticky = getStickiesLocked(action, filter, allSticky,
-                            UserHandle.USER_ALL);
-                    allSticky = getStickiesLocked(action, filter, allSticky,
-                            UserHandle.getUserId(callingUid));
+            // Collect stickies of users
+            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
+            while (actions.hasNext()) {
+                String action = actions.next();
+                for (int id : userIds) {
+                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
+                    if (stickies != null) {
+                        ArrayList<Intent> intents = stickies.get(action);
+                        if (intents != null) {
+                            if (stickyIntents == null) {
+                                stickyIntents = new ArrayList<Intent>();
+                            }
+                            stickyIntents.addAll(intents);
+                        }
+                    }
                 }
-            } else {
-                allSticky = getStickiesLocked(null, filter, allSticky,
-                        UserHandle.USER_ALL);
-                allSticky = getStickiesLocked(null, filter, allSticky,
-                        UserHandle.getUserId(callingUid));
             }
+        }
 
-            // The first sticky in the list is returned directly back to
-            // the client.
-            Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
-
-            if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
-                    + ": " + sticky);
-
-            if (receiver == null) {
-                return sticky;
+        ArrayList<Intent> allSticky = null;
+        if (stickyIntents != null) {
+            final ContentResolver resolver = mContext.getContentResolver();
+            // Look for any matching sticky broadcasts...
+            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
+                Intent intent = stickyIntents.get(i);
+                // If intent has scheme "content", it will need to acccess
+                // provider that needs to lock mProviderMap in ActivityThread
+                // and also it may need to wait application response, so we
+                // cannot lock ActivityManagerService here.
+                if (filter.match(resolver, intent, true, TAG) >= 0) {
+                    if (allSticky == null) {
+                        allSticky = new ArrayList<Intent>();
+                    }
+                    allSticky.add(intent);
+                }
             }
+        }
 
+        // The first sticky in the list is returned directly back to the client.
+        Intent sticky = allSticky != null ? allSticky.get(0) : null;
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
+        if (receiver == null) {
+            return sticky;
+        }
+
+        synchronized (this) {
+            if (callerApp != null && callerApp.pid == 0) {
+                // Caller already died
+                return null;
+            }
             ReceiverList rl
                 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
             if (rl == null) {
@@ -15683,7 +15465,7 @@
     }
 
     public void unregisterReceiver(IIntentReceiver receiver) {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Unregister receiver: " + receiver);
 
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -15692,11 +15474,11 @@
             synchronized(this) {
                 ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                 if (rl != null) {
-                    if (rl.curBroadcast != null) {
-                        BroadcastRecord r = rl.curBroadcast;
-                        final boolean doNext = finishReceiverLocked(
-                                receiver.asBinder(), r.resultCode, r.resultData,
-                                r.resultExtras, r.resultAbort);
+                    final BroadcastRecord r = rl.curBroadcast;
+                    if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
+                        final boolean doNext = r.queue.finishReceiverLocked(
+                                r, r.resultCode, r.resultData, r.resultExtras,
+                                r.resultAbort, false);
                         if (doNext) {
                             doTrim = true;
                             r.queue.processNextBroadcast(false);
@@ -15733,7 +15515,7 @@
             mReceiverResolver.removeFilter(rl.get(i));
         }
     }
-    
+
     private final void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
         for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
             ProcessRecord r = mLruProcesses.get(i);
@@ -15834,9 +15616,9 @@
         // By default broadcasts do not go to stopped apps.
         intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
 
-        if (DEBUG_BROADCAST_LIGHT) Slog.v(
-            TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
-            + " ordered=" + ordered + " userid=" + userId);
+        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+                + " ordered=" + ordered + " userid=" + userId);
         if ((resultTo != null) && !ordered) {
             Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
         }
@@ -15955,14 +15737,14 @@
                                     forceStopPackageLocked(list[i], -1, false, true, true,
                                             false, false, userId, "storage unmount");
                                 }
-                                cleanupRecentTasksLocked(UserHandle.USER_ALL);
+                                mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                                 sendPackageBroadcastLocked(
                                         IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
                                         userId);
                             }
                             break;
                         case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
-                            cleanupRecentTasksLocked(UserHandle.USER_ALL);
+                            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                             break;
                         case Intent.ACTION_PACKAGE_REMOVED:
                         case Intent.ACTION_PACKAGE_CHANGED:
@@ -16157,10 +15939,10 @@
 
         final boolean replacePending =
                 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
-        
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
                 + " replacePending=" + replacePending);
-        
+
         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
         if (!ordered && NR > 0) {
             // If we are not serializing this broadcast, then send the
@@ -16171,8 +15953,7 @@
                     callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
                     appOp, registeredReceivers, resultTo, resultCode, resultData, map,
                     ordered, sticky, false, userId);
-            if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing parallel broadcast " + r);
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
             final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
             if (!replaced) {
                 queue.enqueueParallelBroadcastLocked(r);
@@ -16261,14 +16042,13 @@
                     callerPackage, callingPid, callingUid, resolvedType,
                     requiredPermission, appOp, receivers, resultTo, resultCode,
                     resultData, map, ordered, sticky, false, userId);
-            if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing ordered broadcast " + r
+
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
-            if (DEBUG_BROADCAST) {
-                int seq = r.intent.getIntExtra("seq", -1);
-                Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
-            }
-            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
+            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
+                    "Enqueueing broadcast " + r.intent.getAction());
+
+            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
             if (!replaced) {
                 queue.enqueueOrderedBroadcastLocked(r);
                 queue.scheduleBroadcastsLocked();
@@ -16387,17 +16167,6 @@
         }
     }
 
-    private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort) {
-        final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
-        if (r == null) {
-            Slog.w(TAG, "finishReceiver called but not found on queue");
-            return false;
-        }
-
-        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
-    }
-
     void backgroundServicesFinishedLocked(int userId) {
         for (BroadcastQueue queue : mBroadcastQueues) {
             queue.backgroundServicesFinishedLocked(userId);
@@ -16405,8 +16174,8 @@
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
-            Bundle resultExtras, boolean resultAbort) {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Finish receiver: " + who);
+            Bundle resultExtras, boolean resultAbort, int flags) {
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
 
         // Refuse possible leaked file descriptors
         if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -16419,7 +16188,9 @@
             BroadcastRecord r;
 
             synchronized(this) {
-                r = broadcastRecordForReceiverLocked(who);
+                BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
+                        ? mFgBroadcastQueue : mBgBroadcastQueue;
+                r = queue.getMatchingOrderedReceiver(who);
                 if (r != null) {
                     doNext = r.queue.finishReceiverLocked(r, resultCode,
                         resultData, resultExtras, resultAbort, true);
@@ -16434,7 +16205,7 @@
             Binder.restoreCallingIdentity(origId);
         }
     }
-    
+
     // =========================================================
     // INSTRUMENTATION
     // =========================================================
@@ -16504,17 +16275,17 @@
 
         return true;
     }
-    
+
     /**
-     * Report errors that occur while attempting to start Instrumentation.  Always writes the 
+     * Report errors that occur while attempting to start Instrumentation.  Always writes the
      * error to the logs, but if somebody is watching, send the report there too.  This enables
      * the "am" command to report errors with more information.
-     * 
+     *
      * @param watcher The IInstrumentationWatcher.  Null if there isn't one.
      * @param cn The component name of the instrumentation.
      * @param report The error report.
      */
-    private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher, 
+    private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
             ComponentName cn, String report) {
         Slog.w(TAG, report);
         try {
@@ -16584,7 +16355,7 @@
     // =========================================================
     // CONFIGURATION
     // =========================================================
-    
+
     public ConfigurationInfo getDeviceConfigurationInfo() {
         ConfigurationInfo config = new ConfigurationInfo();
         synchronized (this) {
@@ -16608,6 +16379,15 @@
         return mStackSupervisor.getFocusedStack();
     }
 
+    @Override
+    public int getFocusedStackId() throws RemoteException {
+        ActivityStack focusedStack = getFocusedStack();
+        if (focusedStack != null) {
+            return focusedStack.getStackId();
+        }
+        return -1;
+    }
+
     public Configuration getConfiguration() {
         Configuration ci;
         synchronized(this) {
@@ -16675,13 +16455,14 @@
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
                     Slog.i(TAG, "Updating configuration to: " + values);
                 }
-                
+
                 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
 
-                if (values.locale != null && !initLocale) {
-                    saveLocaleLocked(values.locale, 
-                                     !values.locale.equals(mConfiguration.locale),
-                                     values.userSetLocale);
+                if (!initLocale && values.locale != null && values.userSetLocale) {
+                    final String languageTag = values.locale.toLanguageTag();
+                    SystemProperties.set("persist.sys.locale", languageTag);
+                    mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
+                            values.locale));
                 }
 
                 mConfigurationSeq++;
@@ -16695,7 +16476,7 @@
                 //mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
-                
+
                 // TODO: If our config changes, should we auto dismiss any currently
                 // showing dialogs?
                 mShowDialogs = shouldShowDialogs(newConfig);
@@ -16784,32 +16565,15 @@
      */
     private static final boolean shouldShowDialogs(Configuration config) {
         return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
-                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
-    }
-
-    /**
-     * Save the locale.  You must be inside a synchronized (this) block.
-     */
-    private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
-        if(isDiff) {
-            SystemProperties.set("user.language", l.getLanguage());
-            SystemProperties.set("user.region", l.getCountry());
-        } 
-
-        if(isPersist) {
-            SystemProperties.set("persist.sys.language", l.getLanguage());
-            SystemProperties.set("persist.sys.country", l.getCountry());
-            SystemProperties.set("persist.sys.localevar", l.getVariant());
-
-            mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));
-        }
+                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
+                && config.navigation == Configuration.NAVIGATION_NONAV);
     }
 
     @Override
     public boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
         synchronized (this) {
-            ActivityRecord srec = ActivityRecord.forToken(token);
-            if (srec.task != null && srec.task.stack != null) {
+            ActivityRecord srec = ActivityRecord.forTokenLocked(token);
+            if (srec != null) {
                 return srec.task.stack.shouldUpRecreateTaskLocked(srec, destAffinity);
             }
         }
@@ -16820,16 +16584,19 @@
             Intent resultData) {
 
         synchronized (this) {
-            final ActivityStack stack = ActivityRecord.getStackLocked(token);
-            if (stack != null) {
-                return stack.navigateUpToLocked(token, destIntent, resultCode, resultData);
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r != null) {
+                return r.task.stack.navigateUpToLocked(r, destIntent, resultCode, resultData);
             }
             return false;
         }
     }
 
     public int getLaunchedFromUid(IBinder activityToken) {
-        ActivityRecord srec = ActivityRecord.forToken(activityToken);
+        ActivityRecord srec;
+        synchronized (this) {
+            srec = ActivityRecord.forTokenLocked(activityToken);
+        }
         if (srec == null) {
             return -1;
         }
@@ -16837,7 +16604,10 @@
     }
 
     public String getLaunchedFromPackage(IBinder activityToken) {
-        ActivityRecord srec = ActivityRecord.forToken(activityToken);
+        ActivityRecord srec;
+        synchronized (this) {
+            srec = ActivityRecord.forTokenLocked(activityToken);
+        }
         if (srec == null) {
             return null;
         }
@@ -17177,7 +16947,7 @@
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
             if (adj > ProcessList.BACKUP_APP_ADJ) {
-                if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
                 adj = ProcessList.BACKUP_APP_ADJ;
                 if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                     procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
@@ -17546,7 +17316,7 @@
         }
 
         app.curRawAdj = adj;
-        
+
         //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
         //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
         if (adj > app.maxAdj) {
@@ -17572,7 +17342,8 @@
     /**
      * Record new PSS sample for a process.
      */
-    void recordPssSample(ProcessRecord proc, int procState, long pss, long uss, long now) {
+    void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
+        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
         if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
@@ -17585,6 +17356,67 @@
         if (procState >= ActivityManager.PROCESS_STATE_HOME) {
             proc.lastCachedPss = pss;
         }
+
+        Long check = mMemWatchProcesses.get(proc.processName);
+        if (check != null) {
+            if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+                boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+                if (!isDebuggable) {
+                    if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                        isDebuggable = true;
+                    }
+                }
+                if (isDebuggable) {
+                    Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
+                    final ProcessRecord myProc = proc;
+                    final File heapdumpFile = DumpHeapProvider.getJavaFile();
+                    mMemWatchDumpProcName = proc.processName;
+                    mMemWatchDumpFile = heapdumpFile.toString();
+                    mMemWatchDumpPid = proc.pid;
+                    mMemWatchDumpUid = proc.uid;
+                    BackgroundThread.getHandler().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            revokeUriPermission(ActivityThread.currentActivityThread()
+                                            .getApplicationThread(),
+                                    DumpHeapActivity.JAVA_URI,
+                                    Intent.FLAG_GRANT_READ_URI_PERMISSION
+                                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                                    UserHandle.myUserId());
+                            ParcelFileDescriptor fd = null;
+                            try {
+                                heapdumpFile.delete();
+                                fd = ParcelFileDescriptor.open(heapdumpFile,
+                                        ParcelFileDescriptor.MODE_CREATE |
+                                                ParcelFileDescriptor.MODE_TRUNCATE |
+                                                ParcelFileDescriptor.MODE_READ_WRITE);
+                                IApplicationThread thread = myProc.thread;
+                                if (thread != null) {
+                                    try {
+                                        if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+                                                + myProc + " to " + heapdumpFile);
+                                        thread.dumpHeap(true, heapdumpFile.toString(), fd);
+                                    } catch (RemoteException e) {
+                                    }
+                                }
+                            } catch (FileNotFoundException e) {
+                                e.printStackTrace();
+                            } finally {
+                                if (fd != null) {
+                                    try {
+                                        fd.close();
+                                    } catch (IOException e) {
+                                    }
+                                }
+                            }
+                        }
+                    });
+                } else {
+                    Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
+                            + ", but debugging not enabled");
+                }
+            }
+        }
     }
 
     /**
@@ -17658,7 +17490,7 @@
             // whatever.
         }
     }
-    
+
     /**
      * Returns true if things are idle enough to perform GCs.
      */
@@ -17672,7 +17504,7 @@
         return !processingBroadcasts
                 && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
     }
-    
+
     /**
      * Perform GCs on all processes that are waiting for it, but only
      * if things are idle.
@@ -17701,11 +17533,11 @@
                     }
                 }
             }
-            
+
             scheduleAppGcsLocked();
         }
     }
-    
+
     /**
      * If all looks good, perform GCs on all processes waiting for them.
      */
@@ -17723,12 +17555,12 @@
      */
     final void scheduleAppGcsLocked() {
         mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
-        
+
         if (mProcessesToGc.size() > 0) {
             // Schedule a GC for the time to the next process.
             ProcessRecord proc = mProcessesToGc.get(0);
             Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
-            
+
             long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
             long now = SystemClock.uptimeMillis();
             if (when < (now+GC_TIMEOUT)) {
@@ -17737,7 +17569,7 @@
             mHandler.sendMessageAtTime(msg, when);
         }
     }
-    
+
     /**
      * Add a process to the array of processes waiting to be GCed.  Keeps the
      * list in sorted order by the last GC time.  The process can't already be
@@ -17757,7 +17589,7 @@
             mProcessesToGc.add(0, proc);
         }
     }
-    
+
     /**
      * Set up to ask a process to GC itself.  This will either do it
      * immediately, or put it on the list of processes to gc the next
@@ -17943,7 +17775,7 @@
                 // states, which well tend to give noisy data.
                 long start = SystemClock.uptimeMillis();
                 long pss = Debug.getPss(app.pid, mTmpLong, null);
-                recordPssSample(app, app.curProcState, pss, mTmpLong[0], now);
+                recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
                 mPendingPssProcesses.remove(app);
                 Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                         + " to " + app.curProcState + ": "
@@ -18763,6 +18595,38 @@
         }
     }
 
+    @Override
+    public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
+        enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+                "setDumpHeapDebugLimit()");
+        synchronized (this) {
+            if (maxMemSize > 0) {
+                mMemWatchProcesses.put(processName, maxMemSize);
+                mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+            } else {
+                mMemWatchProcesses.remove(processName);
+            }
+        }
+    }
+
+    @Override
+    public void dumpHeapFinished(String path) {
+        synchronized (this) {
+            if (Binder.getCallingPid() != mMemWatchDumpPid) {
+                Slog.w(TAG, "dumpHeapFinished: Calling pid " + Binder.getCallingPid()
+                        + " does not match last pid " + mMemWatchDumpPid);
+                return;
+            }
+            if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) {
+                Slog.w(TAG, "dumpHeapFinished: Calling path " + path
+                        + " does not match last path " + mMemWatchDumpFile);
+                return;
+            }
+            if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+            mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+        }
+    }
+
     /** In this method we try to acquire our lock to make sure that we have not deadlocked */
     public void monitor() {
         synchronized (this) { }
@@ -18826,8 +18690,8 @@
         }
     }
 
-    private Set getProfileIdsLocked(int userId) {
-        Set userIds = new HashSet<Integer>();
+    private Set<Integer> getProfileIdsLocked(int userId) {
+        Set<Integer> userIds = new HashSet<Integer>();
         final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
                 userId, false /* enabledOnly */);
         for (UserInfo user : profiles) {
@@ -18886,7 +18750,8 @@
                     return true;
                 }
 
-                mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
+                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
+                        "startUser");
 
                 final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                 if (userInfo == null) {
@@ -19420,7 +19285,7 @@
             }
 
             // Explicitly remove the old information in mRecentTasks.
-            removeRecentTasksForUserLocked(userId);
+            mRecentTasks.removeTasksForUserLocked(userId);
         }
 
         for (int i=0; i<callbacks.size(); i++) {
@@ -19651,7 +19516,7 @@
             synchronized (ActivityManagerService.this) {
                 long origId = Binder.clearCallingIdentity();
                 try {
-                    TaskRecord tr = recentTaskForIdLocked(mTaskId);
+                    TaskRecord tr = mRecentTasks.taskForIdLocked(mTaskId);
                     if (tr == null) {
                         throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                     }
@@ -19678,7 +19543,7 @@
             TaskRecord tr;
             IApplicationThread appThread;
             synchronized (ActivityManagerService.this) {
-                tr = recentTaskForIdLocked(mTaskId);
+                tr = mRecentTasks.taskForIdLocked(mTaskId);
                 if (tr == null) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
@@ -19699,7 +19564,7 @@
             synchronized (ActivityManagerService.this) {
                 long origId = Binder.clearCallingIdentity();
                 try {
-                    TaskRecord tr = recentTaskForIdLocked(mTaskId);
+                    TaskRecord tr = mRecentTasks.taskForIdLocked(mTaskId);
                     if (tr == null) {
                         throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index b1b2a5c..ca2721c 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
 import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
 import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -71,11 +74,11 @@
  * An entry in the history stack, representing an activity.
  */
 final class ActivityRecord {
-    static final String TAG = ActivityManagerService.TAG;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
     final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
 
-    private static final String TAG_ACTIVITY = "activity";
     private static final String ATTR_ID = "id";
     private static final String TAG_INTENT = "intent";
     private static final String ATTR_USERID = "user_id";
@@ -127,6 +130,10 @@
     long pauseTime;         // last time we started pausing the activity
     long launchTickTime;    // base time for launch tick messages
     Configuration configuration; // configuration activity was last running in
+    // Overridden configuration by the activity stack
+    // WARNING: Reference points to {@link ActivityStack#mOverrideConfig}, so its internal state
+    // should never be altered directly.
+    Configuration stackConfigOverride;
     CompatibilityInfo compat;// last used compatibility mode
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
@@ -154,7 +161,6 @@
     int launchMode;         // the launch mode activity attribute.
     boolean visible;        // does this activity's window need to be shown?
     boolean sleeping;       // have we told the activity to sleep?
-    boolean waitingVisible; // true if waiting for a new act to become vis
     boolean nowVisible;     // is this activity's window visible?
     boolean idle;           // has the activity gone idle?
     boolean hasBeenLaunched;// has this activity ever been launched?
@@ -205,6 +211,7 @@
                 pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
                 pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
         pw.print(prefix); pw.print("config="); pw.println(configuration);
+        pw.print(prefix); pw.print("stackConfigOverride="); pw.println(stackConfigOverride);
         if (resultTo != null || resultWho != null) {
             pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
                     pw.print(" resultWho="); pw.print(resultWho);
@@ -293,6 +300,7 @@
                     else TimeUtils.formatDuration(startTime, now, pw);
                     pw.println();
         }
+        final boolean waitingVisible = mStackSupervisor.mWaitingVisibleActivities.contains(this);
         if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
             pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
                     pw.print(" nowVisible="); pw.print(nowVisible);
@@ -312,44 +320,83 @@
     }
 
     static class Token extends IApplicationToken.Stub {
-        final WeakReference<ActivityRecord> weakActivity;
+        private final WeakReference<ActivityRecord> weakActivity;
+        private final ActivityManagerService mService;
 
-        Token(ActivityRecord activity) {
-            weakActivity = new WeakReference<ActivityRecord>(activity);
+        Token(ActivityRecord activity, ActivityManagerService service) {
+            weakActivity = new WeakReference<>(activity);
+            mService = service;
         }
 
-        @Override public void windowsDrawn() {
-            ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                activity.windowsDrawn();
+        @Override
+        public void windowsDrawn() {
+            synchronized (mService) {
+                ActivityRecord r = tokenToActivityRecordLocked(this);
+                if (r != null) {
+                    r.windowsDrawnLocked();
+                }
             }
         }
 
-        @Override public void windowsVisible() {
-            ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                activity.windowsVisible();
+        @Override
+        public void windowsVisible() {
+            synchronized (mService) {
+                ActivityRecord r = tokenToActivityRecordLocked(this);
+                if (r != null) {
+                    r.windowsVisibleLocked();
+                }
             }
         }
 
-        @Override public void windowsGone() {
-            ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                activity.windowsGone();
+        @Override
+        public void windowsGone() {
+            synchronized (mService) {
+                ActivityRecord r = tokenToActivityRecordLocked(this);
+                if (r != null) {
+                    if (DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + r);
+                    r.nowVisible = false;
+                    return;
+                }
             }
         }
 
-        @Override public boolean keyDispatchingTimedOut(String reason) {
-            ActivityRecord activity = weakActivity.get();
-            return activity != null && activity.keyDispatchingTimedOut(reason);
+        @Override
+        public boolean keyDispatchingTimedOut(String reason) {
+            ActivityRecord r;
+            ActivityRecord anrActivity;
+            ProcessRecord anrApp;
+            synchronized (mService) {
+                r = tokenToActivityRecordLocked(this);
+                if (r == null) {
+                    return false;
+                }
+                anrActivity = r.getWaitingHistoryRecordLocked();
+                anrApp = r != null ? r.app : null;
+            }
+            return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
         }
 
-        @Override public long getKeyDispatchingTimeout() {
-            ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                return activity.getKeyDispatchingTimeout();
+        @Override
+        public long getKeyDispatchingTimeout() {
+            synchronized (mService) {
+                ActivityRecord r = tokenToActivityRecordLocked(this);
+                if (r == null) {
+                    return 0;
+                }
+                r = r.getWaitingHistoryRecordLocked();
+                return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
             }
-            return 0;
+        }
+
+        private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
+            if (token == null) {
+                return null;
+            }
+            ActivityRecord r = token.weakActivity.get();
+            if (r == null || r.task == null || r.task.stack == null) {
+                return null;
+            }
+            return r;
         }
 
         @Override
@@ -364,11 +411,11 @@
         }
     }
 
-    static ActivityRecord forToken(IBinder token) {
+    static ActivityRecord forTokenLocked(IBinder token) {
         try {
-            return token != null ? ((Token)token).weakActivity.get() : null;
+            return Token.tokenToActivityRecordLocked((Token)token);
         } catch (ClassCastException e) {
-            Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
+            Slog.w(TAG, "Bad activity token: " + token, e);
             return null;
         }
     }
@@ -384,7 +431,7 @@
             boolean _componentSpecified, ActivityStackSupervisor supervisor,
             ActivityContainer container, Bundle options) {
         service = _service;
-        appToken = new Token(this);
+        appToken = new Token(this, service);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
         launchedFromPackage = _launchedFromPackage;
@@ -394,6 +441,8 @@
         resolvedType = _resolvedType;
         componentSpecified = _componentSpecified;
         configuration = _configuration;
+        stackConfigOverride = (container != null)
+                ? container.mStack.mOverrideConfig : Configuration.EMPTY;
         resultTo = _resultTo;
         resultWho = _resultWho;
         requestCode = _reqCode;
@@ -407,7 +456,6 @@
         keysPaused = false;
         inHistory = false;
         visible = true;
-        waitingVisible = false;
         nowVisible = false;
         idle = false;
         hasBeenLaunched = false;
@@ -474,10 +522,16 @@
 
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window, userId);
+            final boolean translucent = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                    || (!ent.array.hasValue(
+                            com.android.internal.R.styleable.Window_windowIsTranslucent)
+                            && ent.array.getBoolean(
+                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                            false));
             fullscreen = ent != null && !ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowIsFloating, false)
-                    && !ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                    && !translucent;
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
 
@@ -514,13 +568,8 @@
     }
 
     void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
-        if (task != null && task.removeActivity(this)) {
-            if (task != newTask) {
-                task.stack.removeTask(task, "setTask");
-            } else {
-                Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
-                        (newTask == null ? null : newTask.stack));
-            }
+        if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) {
+            task.stack.removeTask(task, "setTask");
         }
         task = newTask;
         setTaskToAffiliateWith(taskToAffiliateWith);
@@ -566,6 +615,10 @@
         return inHistory;
     }
 
+    boolean isInStackLocked() {
+        return task != null && task.stack != null && task.stack.isInStackLocked(this) != null;
+    }
+
     boolean isHomeActivity() {
         return mActivityType == HOME_ACTIVITY_TYPE;
     }
@@ -585,9 +638,10 @@
                         (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
     }
 
-    void makeFinishing() {
+    void makeFinishingLocked() {
         if (!finishing) {
-            if (this == task.stack.getVisibleBehindActivity()) {
+            if (task != null && task.stack != null
+                    && this == task.stack.getVisibleBehindActivity()) {
                 // A finishing activity should not remain as visible in the background
                 mStackSupervisor.requestVisibleBehindLocked(this, false);
             }
@@ -656,8 +710,9 @@
         // stack.
         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
         boolean unsent = true;
-        if ((state == ActivityState.RESUMED || (service.isSleeping()
-                        && task.stack.topRunningActivityLocked(null) == this))
+        if ((state == ActivityState.RESUMED
+                || (service.isSleeping() && task.stack != null
+                    && task.stack.topRunningActivityLocked(null) == this))
                 && app != null && app.thread != null) {
             try {
                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
@@ -665,11 +720,9 @@
                 app.thread.scheduleNewIntent(ar, appToken);
                 unsent = false;
             } catch (RemoteException e) {
-                Slog.w(ActivityManagerService.TAG,
-                        "Exception thrown sending new intent to " + this, e);
+                Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
             } catch (NullPointerException e) {
-                Slog.w(ActivityManagerService.TAG,
-                        "Exception thrown sending new intent to " + this, e);
+                Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
             }
         }
         if (unsent) {
@@ -707,6 +760,17 @@
                             pendingOptions.getCustomExitResId(),
                             pendingOptions.getOnAnimationStartListener());
                     break;
+                case ActivityOptions.ANIM_CLIP_REVEAL:
+                    service.mWindowManager.overridePendingAppTransitionClipReveal(
+                            pendingOptions.getStartX(), pendingOptions.getStartY(),
+                            pendingOptions.getWidth(), pendingOptions.getHeight());
+                    if (intent.getSourceBounds() == null) {
+                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                                pendingOptions.getStartY(),
+                                pendingOptions.getStartX()+pendingOptions.getWidth(),
+                                pendingOptions.getStartY()+pendingOptions.getHeight()));
+                    }
+                    break;
                 case ActivityOptions.ANIM_SCALE_UP:
                     service.mWindowManager.overridePendingAppTransitionScaleUp(
                             pendingOptions.getStartX(), pendingOptions.getStartY(),
@@ -798,7 +862,7 @@
 
     void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
         if (newThumbnail != null) {
-            if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
+            if (DEBUG_THUMBNAILS) Slog.i(TAG,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
             boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
             if (thumbnailUpdated && isPersistable()) {
@@ -819,19 +883,27 @@
     }
 
     boolean continueLaunchTickingLocked() {
-        if (launchTickTime != 0) {
-            final ActivityStack stack = task.stack;
-            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
-            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
-            stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
-            return true;
+        if (launchTickTime == 0) {
+            return false;
         }
-        return false;
+
+        final ActivityStack stack = task.stack;
+        if (stack == null) {
+            return false;
+        }
+
+        Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
+        stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
+        stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
+        return true;
     }
 
     void finishLaunchTickingLocked() {
         launchTickTime = 0;
-        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
+        final ActivityStack stack = task.stack;
+        if (stack != null) {
+            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
+        }
     }
 
     // IApplicationToken
@@ -862,8 +934,8 @@
         if (displayStartTime != 0) {
             reportLaunchTimeLocked(curTime);
         }
-        if (fullyDrawnStartTime != 0) {
-            final ActivityStack stack = task.stack;
+        final ActivityStack stack = task.stack;
+        if (fullyDrawnStartTime != 0 && stack != null) {
             final long thisTime = curTime - fullyDrawnStartTime;
             final long totalTime = stack.mFullyDrawnStartTime != 0
                     ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
@@ -883,18 +955,21 @@
                     TimeUtils.formatDuration(totalTime, sb);
                     sb.append(")");
                 }
-                Log.i(ActivityManagerService.TAG, sb.toString());
+                Log.i(TAG, sb.toString());
             }
             if (totalTime > 0) {
                 //service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
             }
-            fullyDrawnStartTime = 0;
             stack.mFullyDrawnStartTime = 0;
         }
+        fullyDrawnStartTime = 0;
     }
 
     private void reportLaunchTimeLocked(final long curTime) {
         final ActivityStack stack = task.stack;
+        if (stack == null) {
+            return;
+        }
         final long thisTime = curTime - displayStartTime;
         final long totalTime = stack.mLaunchStartTime != 0
                 ? (curTime - stack.mLaunchStartTime) : thisTime;
@@ -914,7 +989,7 @@
                 TimeUtils.formatDuration(totalTime, sb);
                 sb.append(")");
             }
-            Log.i(ActivityManagerService.TAG, sb.toString());
+            Log.i(TAG, sb.toString());
         }
         mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
         if (totalTime > 0) {
@@ -924,69 +999,52 @@
         stack.mLaunchStartTime = 0;
     }
 
-    public void windowsDrawn() {
-        synchronized(service) {
-            if (displayStartTime != 0) {
-                reportLaunchTimeLocked(SystemClock.uptimeMillis());
-            }
-            mStackSupervisor.sendWaitingVisibleReportLocked(this);
-            startTime = 0;
-            finishLaunchTickingLocked();
-            if (task != null) {
-                task.hasBeenVisible = true;
-            }
+    void windowsDrawnLocked() {
+        if (displayStartTime != 0) {
+            reportLaunchTimeLocked(SystemClock.uptimeMillis());
+        }
+        mStackSupervisor.sendWaitingVisibleReportLocked(this);
+        startTime = 0;
+        finishLaunchTickingLocked();
+        if (task != null) {
+            task.hasBeenVisible = true;
         }
     }
 
-    public void windowsVisible() {
-        synchronized(service) {
-            mStackSupervisor.reportActivityVisibleLocked(this);
-            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                    ActivityManagerService.TAG, "windowsVisible(): " + this);
-            if (!nowVisible) {
-                nowVisible = true;
-                lastVisibleTime = SystemClock.uptimeMillis();
-                if (!idle) {
-                    // Instead of doing the full stop routine here, let's just
-                    // hide any activities we now can, and let them stop when
-                    // the normal idle happens.
-                    mStackSupervisor.processStoppingActivitiesLocked(false);
-                } else {
-                    // If this activity was already idle, then we now need to
-                    // make sure we perform the full stop of any activities
-                    // that are waiting to do so.  This is because we won't
-                    // do that while they are still waiting for this one to
-                    // become visible.
-                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
-                    if (N > 0) {
-                        for (int i=0; i<N; i++) {
-                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                            r.waitingVisible = false;
-                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                                    ActivityManagerService.TAG,
-                                    "Was waiting for visible: " + r);
-                        }
-                        mStackSupervisor.mWaitingVisibleActivities.clear();
-                        mStackSupervisor.scheduleIdleLocked();
+    void windowsVisibleLocked() {
+        mStackSupervisor.reportActivityVisibleLocked(this);
+        if (DEBUG_SWITCH) Log.v(TAG, "windowsVisibleLocked(): " + this);
+        if (!nowVisible) {
+            nowVisible = true;
+            lastVisibleTime = SystemClock.uptimeMillis();
+            if (!idle) {
+                // Instead of doing the full stop routine here, let's just hide any activities
+                // we now can, and let them stop when the normal idle happens.
+                mStackSupervisor.processStoppingActivitiesLocked(false);
+            } else {
+                // If this activity was already idle, then we now need to make sure we perform
+                // the full stop of any activities that are waiting to do so. This is because
+                // we won't do that while they are still waiting for this one to become visible.
+                final int size = mStackSupervisor.mWaitingVisibleActivities.size();
+                if (size > 0) {
+                    for (int i = 0; i < size; i++) {
+                        ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
+                        if (DEBUG_SWITCH) Log.v(TAG, "Was waiting for visible: " + r);
                     }
+                    mStackSupervisor.mWaitingVisibleActivities.clear();
+                    mStackSupervisor.scheduleIdleLocked();
                 }
-                service.scheduleAppGcsLocked();
             }
+            service.scheduleAppGcsLocked();
         }
     }
 
-    public void windowsGone() {
-        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
-                ActivityManagerService.TAG, "windowsGone(): " + this);
-        nowVisible = false;
-    }
-
-    private ActivityRecord getWaitingHistoryRecordLocked() {
+    ActivityRecord getWaitingHistoryRecordLocked() {
         // First find the real culprit...  if we are waiting
         // for another app to start, then we have paused dispatching
         // for this activity.
         ActivityRecord r = this;
-        if (r.waitingVisible) {
+        if (mStackSupervisor.mWaitingVisibleActivities.contains(this)) {
             final ActivityStack stack = mStackSupervisor.getFocusedStack();
             // Hmmm, who might we be waiting for?
             r = stack.mResumedActivity;
@@ -1002,24 +1060,6 @@
         return r;
     }
 
-    public boolean keyDispatchingTimedOut(String reason) {
-        ActivityRecord r;
-        ProcessRecord anrApp;
-        synchronized(service) {
-            r = getWaitingHistoryRecordLocked();
-            anrApp = r != null ? r.app : null;
-        }
-        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
-    }
-
-    /** Returns the key dispatching timeout for this application token. */
-    public long getKeyDispatchingTimeout() {
-        synchronized(service) {
-            ActivityRecord r = getWaitingHistoryRecordLocked();
-            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
-        }
-    }
-
     /**
      * This method will return true if the activity is either visible, is becoming visible, is
      * currently pausing, or is resumed.
@@ -1047,14 +1087,14 @@
     }
 
     static void activityResumedLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
         r.icicle = null;
         r.haveState = false;
     }
 
     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null) {
             return INVALID_TASK_ID;
         }
@@ -1067,11 +1107,8 @@
     }
 
     static ActivityRecord isInStackLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
-        if (r != null) {
-            return r.task.stack.isInStackLocked(token);
-        }
-        return null;
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+        return (r != null) ? r.task.stack.isInStackLocked(r) : null;
     }
 
     static ActivityStack getStackLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
old mode 100755
new mode 100644
index 7908da0..be95268
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,9 +16,7 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerService.TAG;
-import static com.android.server.am.ActivityManagerService.localLOGV;
-import static com.android.server.am.ActivityManagerService.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
 import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
@@ -97,6 +95,9 @@
  */
 final class ActivityStack {
 
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
+    private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+
     // Ticks during which we check progress while waiting for an app to launch.
     static final int LAUNCH_TICK = 500;
 
@@ -146,30 +147,31 @@
 
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
+    private final RecentTasks mRecentTasks;
 
     /**
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
      */
-    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
+    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
 
     /**
      * Used for validating app tokens with window manager.
      */
-    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
+    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<>();
 
     /**
      * List of running activities, sorted by recent usage.
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
      */
-    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
 
     /**
      * Animations that for the current transition have requested not to
      * be considered for the transition animation.
      */
-    final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<>();
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -219,6 +221,9 @@
      */
     boolean mConfigWillChange;
 
+    // Whether or not this stack covers the entire screen; by default stacks are full screen
+    boolean mFullscreen = true;
+
     long mLaunchStartTime = 0;
     long mFullyDrawnStartTime = 0;
 
@@ -234,6 +239,11 @@
     /** Run all ActivityStacks through this */
     final ActivityStackSupervisor mStackSupervisor;
 
+    Configuration mOverrideConfig;
+    /** True if the stack was forced to full screen because {@link TaskRecord#mResizeable} is false
+     * and the stack was previously resized. */
+    private boolean mForcedFullscreen = false;
+
     static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
     static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
     static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
@@ -255,9 +265,7 @@
     final Handler mHandler;
 
     final class ActivityStackHandler extends Handler {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
+
         ActivityStackHandler(Looper looper) {
             super(looper);
         }
@@ -337,7 +345,12 @@
         return count;
     }
 
-    ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) {
+    int numTasks() {
+        return mTaskHistory.size();
+    }
+
+    ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
+            RecentTasks recentTasks) {
         mActivityContainer = activityContainer;
         mStackSupervisor = activityContainer.getOuter();
         mService = mStackSupervisor.mService;
@@ -345,6 +358,8 @@
         mWindowManager = mService.mWindowManager;
         mStackId = activityContainer.mStackId;
         mCurrentUser = mService.mCurrentUserId;
+        mRecentTasks = recentTasks;
+        mOverrideConfig = Configuration.EMPTY;
     }
 
     /**
@@ -446,14 +461,20 @@
     }
 
     ActivityRecord isInStackLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
-        if (r != null) {
-            final TaskRecord task = r.task;
-            if (task != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
-                if (task.stack != this) Slog.w(TAG,
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+        return isInStackLocked(r);
+    }
+
+    ActivityRecord isInStackLocked(ActivityRecord r) {
+        if (r == null) {
+            return null;
+        }
+        final TaskRecord task = r.task;
+        if (task != null && task.stack != null
+                && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+            if (task.stack != this) Slog.w(TAG,
                     "Illegal state! task does not point to stack it is in.");
-                return r;
-            }
+            return r;
         }
         return null;
     }
@@ -475,11 +496,20 @@
 
     final void moveToFront(String reason) {
         if (isAttached()) {
-            if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(isHomeStack(), reason);
+            final boolean homeStack = isHomeStack()
+                    || (mActivityContainer.mParentActivity != null
+                        && mActivityContainer.mParentActivity.isHomeActivity());
+            ActivityStack lastFocusStack = null;
+            if (!homeStack) {
+                // Need to move this stack to the front before calling
+                // {@link ActivityStackSupervisor#moveHomeStack} below.
+                lastFocusStack = mStacks.get(mStacks.size() - 1);
+                mStacks.remove(this);
+                mStacks.add(this);
             }
-            mStacks.remove(this);
-            mStacks.add(this);
+            if (isOnHomeDisplay()) {
+                mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
+            }
             final TaskRecord task = topTask();
             if (task != null) {
                 mWindowManager.moveTaskToTop(task.taskId);
@@ -643,7 +673,7 @@
         r.stopped = false;
         mResumedActivity = r;
         r.task.touchActiveTime();
-        mService.addRecentTaskLocked(r.task);
+        mRecentTasks.addLocked(r.task);
         completeResumeLocked(r);
         mStackSupervisor.checkReadyForSleepLocked();
         setLaunchTime(r);
@@ -955,9 +985,7 @@
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
             } else if (prev.app != null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
-                if (prev.waitingVisible) {
-                    prev.waitingVisible = false;
-                    mStackSupervisor.mWaitingVisibleActivities.remove(prev);
+                if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
                     if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
                             TAG, "Complete pause, no longer waiting: " + prev);
                 }
@@ -1116,7 +1144,8 @@
 
         final int numStacks = mStacks.size();
         while (stackNdx < numStacks) {
-            tasks = mStacks.get(stackNdx).mTaskHistory;
+            ActivityStack historyStack = mStacks.get(stackNdx);
+            tasks = historyStack.mTaskHistory;
             final int numTasks = tasks.size();
             while (taskNdx < numTasks) {
                 activities = tasks.get(taskNdx).mActivities;
@@ -1124,7 +1153,7 @@
                 while (activityNdx < numActivities) {
                     final ActivityRecord activity = activities.get(activityNdx);
                     if (!activity.finishing) {
-                        return activity.fullscreen ? null : activity;
+                        return historyStack.mFullscreen && activity.fullscreen ? null : activity;
                     }
                     ++activityNdx;
                 }
@@ -1138,9 +1167,26 @@
         return null;
     }
 
+    private ActivityStack getNextVisibleStackLocked() {
+        ArrayList<ActivityStack> stacks = mStacks;
+        final ActivityRecord parent = mActivityContainer.mParentActivity;
+        if (parent != null) {
+            stacks = parent.task.stack.mStacks;
+        }
+        if (stacks != null) {
+            for (int i = stacks.size() - 1; i >= 0; --i) {
+                ActivityStack stack = stacks.get(i);
+                if (stack != this && stack.isStackVisibleLocked()) {
+                    return stack;
+                }
+            }
+        }
+        return null;
+    }
+
     // Checks if any of the stacks above this one has a fullscreen activity behind it.
     // If so, this stack is hidden, otherwise it is visible.
-    private boolean isStackVisible() {
+    private boolean isStackVisibleLocked() {
         if (!isAttached()) {
             return false;
         }
@@ -1155,11 +1201,18 @@
          * wallpaper to be shown behind it.
          */
         for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
-            final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
-            for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
+            ActivityStack stack = mStacks.get(i);
+            // stack above isn't full screen, so, we assume we're still visible. at some point
+            // we should look at the stack bounds to see if we're occluded even if the stack
+            // isn't fullscreen
+            if (!stack.mFullscreen) {
+                continue;
+            }
+            final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final TaskRecord task = tasks.get(taskNdx);
                 final ArrayList<ActivityRecord> activities = task.mActivities;
-                for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r = activities.get(activityNdx);
 
                     // Conditions for an activity to obscure the stack we're
@@ -1205,7 +1258,7 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
-        boolean behindFullscreen = !isStackVisible();
+        boolean behindFullscreen = !isStackVisibleLocked();
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1328,7 +1381,7 @@
                                     // This case created for transitioning activities from
                                     // translucent to opaque {@link Activity#convertToOpaque}.
                                     if (getVisibleBehindActivity() == r) {
-                                        releaseBackgroundResources();
+                                        releaseBackgroundResources(r);
                                     } else {
                                         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                                             mStackSupervisor.mStoppingActivities.add(r);
@@ -1360,7 +1413,7 @@
         }
     }
 
-    void convertToTranslucent(ActivityRecord r) {
+    void convertActivityToTranslucent(ActivityRecord r) {
         mTranslucentActivityWaiting = r;
         mUndrawnActivitiesBelowTopTranslucent.clear();
         mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
@@ -1459,7 +1512,7 @@
         return result;
     }
 
-    final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
+    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
         if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
         if (!mService.mBooting && !mService.mBooted) {
@@ -1487,8 +1540,17 @@
 
         final TaskRecord prevTask = prev != null ? prev.task : null;
         if (next == null) {
-            // There are no more activities!  Let's just start up the
-            // Launcher...
+            // There are no more activities!
+            final String reason = "noMoreActivities";
+            if (!mFullscreen) {
+                // Try to move focus to the next visible stack with a running activity if this
+                // stack is not covering the entire screen.
+                final ActivityStack stack = getNextVisibleStackLocked();
+                if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
+                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
+                }
+            }
+            // Let's just start up the Launcher...
             ActivityOptions.abort(options);
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -1496,7 +1558,7 @@
             final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                     HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
             return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");
+                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
         }
 
         next.delayedResume = false;
@@ -1525,10 +1587,11 @@
                 // Now the task above it has to return to the home task instead.
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
                 mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-            } else {
-                if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG,
+            } else if (!isOnHomeDisplay()) {
+                return false;
+            } else if (!isHomeStack()){
+                if (DEBUG_STATES) Slog.d(TAG,
                         "resumeTopActivityLocked: Launching home next");
-                // Only resume home if on home display
                 final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                         HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
                 return isOnHomeDisplay() &&
@@ -1638,13 +1701,13 @@
             if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
                     " on new resume");
             requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
-                    null, "no-history", false);
+                    null, "resume-no-history", false);
             mLastNoHistoryActivity = null;
         }
 
         if (prev != null && prev != next) {
-            if (!prev.waitingVisible && next != null && !next.nowVisible) {
-                prev.waitingVisible = true;
+            if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                    && next != null && !next.nowVisible) {
                 mStackSupervisor.mWaitingVisibleActivities.add(prev);
                 if (DEBUG_SWITCH) Slog.v(
                         TAG, "Resuming top, waiting visible to hide: " + prev);
@@ -1661,13 +1724,14 @@
                     mWindowManager.setAppVisibility(prev.appToken, false);
                     if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
                             + prev + ", waitingVisible="
-                            + (prev != null ? prev.waitingVisible : null)
+                            + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                             + ", nowVisible=" + next.nowVisible);
                 } else {
-                    if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "
-                        + prev + ", waitingVisible="
-                        + (prev != null ? prev.waitingVisible : null)
-                        + ", nowVisible=" + next.nowVisible);
+                    if (DEBUG_SWITCH) Slog.v(TAG,
+                            "Previous already visible but still waiting to hide: " + prev
+                                    + ", waitingVisible="
+                                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                                    + ", nowVisible=" + next.nowVisible);
                 }
             }
         }
@@ -1759,7 +1823,7 @@
             next.state = ActivityState.RESUMED;
             mResumedActivity = next;
             next.task.touchActiveTime();
-            mService.addRecentTaskLocked(next.task);
+            mRecentTasks.addLocked(next.task);
             mService.updateLruProcessLocked(next.app, true, null);
             updateLRUListLocked(next);
             mService.updateOomAdjLocked();
@@ -1895,9 +1959,31 @@
         return true;
     }
 
+    private TaskRecord getNextTask(TaskRecord targetTask) {
+        final int index = mTaskHistory.indexOf(targetTask);
+        if (index >= 0) {
+            final int numTasks = mTaskHistory.size();
+            for (int i = index + 1; i < numTasks; ++i) {
+                TaskRecord task = mTaskHistory.get(i);
+                if (task.userId == targetTask.userId) {
+                    return task;
+                }
+            }
+        }
+        return null;
+    }
+
     private void insertTaskAtTop(TaskRecord task) {
+        // If the moving task is over home stack, transfer its return type to next task
+        if (task.isOverHomeStack()) {
+            final TaskRecord nextTask = getNextTask(task);
+            if (nextTask != null) {
+                nextTask.setTaskToReturnTo(task.getTaskToReturnTo());
+            }
+        }
+
         // If this is being moved to the top by another activity or being launched from the home
-        // activity, set mOnTopOfHome accordingly.
+        // activity, set mTaskToReturnTo accordingly.
         if (isOnHomeDisplay()) {
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHome = lastStack.isHomeStack();
@@ -2193,7 +2279,7 @@
                 }
 
                 final int targetTaskId = targetTask.taskId;
-                mWindowManager.setAppGroupId(target.appToken, targetTaskId);
+                mWindowManager.setAppTask(target.appToken, targetTaskId);
 
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
@@ -2218,7 +2304,7 @@
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
 
-                    mWindowManager.setAppGroupId(p.appToken, targetTaskId);
+                    mWindowManager.setAppTask(p.appToken, targetTaskId);
                 }
 
                 mWindowManager.moveTaskToBottom(targetTaskId);
@@ -2237,7 +2323,7 @@
                     // In this case, we want to finish this activity
                     // and everything above it, so be sneaky and pretend
                     // like these are all in the reply chain.
-                    end = numActivities - 1;
+                    end = activities.size() - 1;
                 } else if (replyChainEnd < 0) {
                     end = i;
                 } else {
@@ -2258,7 +2344,8 @@
                     }
                     if (DEBUG_TASKS) Slog.w(TAG,
                             "resetTaskIntendedTask: calling finishActivity on " + p);
-                    if (finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false)) {
+                    if (finishActivityLocked(
+                            p, Activity.RESULT_CANCELED, null, "reset-task", false)) {
                         end--;
                         srcPos--;
                     }
@@ -2335,7 +2422,8 @@
                         if (p.finishing) {
                             continue;
                         }
-                        finishActivityLocked(p, Activity.RESULT_CANCELED, null, "reset", false);
+                        finishActivityLocked(
+                                p, Activity.RESULT_CANCELED, null, "move-affinity", false);
                     }
                 } else {
                     if (taskInsertionPoint < 0) {
@@ -2356,7 +2444,7 @@
                                 new RuntimeException("here").fillInStackTrace());
                         if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
                                 + " in to resetting task " + task);
-                        mWindowManager.setAppGroupId(p.appToken, taskId);
+                        mWindowManager.setAppTask(p.appToken, taskId);
                     }
                     mWindowManager.moveTaskToTop(taskId);
                     if (VALIDATE_TOKENS) {
@@ -2422,9 +2510,11 @@
         }
 
         int taskNdx = mTaskHistory.indexOf(task);
-        do {
-            taskTop = mTaskHistory.get(taskNdx--).getTopActivity();
-        } while (taskTop == null && taskNdx >= 0);
+        if (taskNdx >= 0) {
+            do {
+                taskTop = mTaskHistory.get(taskNdx--).getTopActivity();
+            } while (taskTop == null && taskNdx >= 0);
+        }
 
         if (topOptions != null) {
             // If we got some ActivityOptions from an activity on top that
@@ -2468,20 +2558,44 @@
     private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
         if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) {
             ActivityRecord next = topRunningActivityLocked(null);
+            final String myReason = reason + " adjustFocus";
             if (next != r) {
                 final TaskRecord task = r.task;
                 if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(),
-                            reason + " adjustFocus");
+                    // For non-fullscreen stack, we want to move the focus to the next visible
+                    // stack to prevent the home screen from moving to the top and obscuring
+                    // other visible stacks.
+                    if (!mFullscreen
+                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                        return;
+                    }
+                    // Move the home stack to the top if this stack is fullscreen or there is no
+                    // other visible stack.
+                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), myReason);
                 }
             }
-            ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+
+            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
             if (top != null) {
-                mService.setFocusedActivityLocked(top, reason + " adjustTopFocus");
+                mService.setFocusedActivityLocked(top, myReason);
             }
         }
     }
 
+    private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
+        final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
+        final String myReason = reason + " adjustFocusToNextVisibleStack";
+        if (stack == null) {
+            return false;
+        }
+        final ActivityRecord top = stack.topRunningActivityLocked(null);
+        if (top == null) {
+            return false;
+        }
+        mService.setFocusedActivityLocked(top, myReason);
+        return true;
+    }
+
     final void stopActivityLocked(ActivityRecord r) {
         if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
@@ -2492,7 +2606,7 @@
                         Slog.d(TAG, "no-history finish of " + r);
                     }
                     requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "no-history", false);
+                            "stop-no-history", false);
                 } else {
                     if (DEBUG_STATES) Slog.d(TAG, "Not finishing noHistory " + r
                             + " on stop because we're just sleeping");
@@ -2571,16 +2685,16 @@
         mService.updateOomAdjLocked();
     }
 
-    final void finishTopRunningActivityLocked(ProcessRecord app) {
+    final void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
         ActivityRecord r = topRunningActivityLocked(null);
         if (r != null && r.app == app) {
             // If the top running activity is from this crashing
             // process, then terminate it to avoid getting in a loop.
-            Slog.w(TAG, "  Force finishing activity 1 "
+            Slog.w(TAG, "  Force finishing activity "
                     + r.intent.getComponent().flattenToShortString());
             int taskNdx = mTaskHistory.indexOf(r.task);
             int activityNdx = r.task.mActivities.indexOf(r);
-            finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+            finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
             // Also terminate any activities below it that aren't yet
             // stopped, to avoid a situation where one will get
             // re-start our crashing activity once it gets resumed again.
@@ -2600,9 +2714,9 @@
                         || r.state == ActivityState.PAUSING
                         || r.state == ActivityState.PAUSED) {
                     if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
-                        Slog.w(TAG, "  Force finishing activity 2 "
+                        Slog.w(TAG, "  Force finishing activity "
                                 + r.intent.getComponent().flattenToShortString());
-                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
+                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
                     }
                 }
             }
@@ -2685,7 +2799,7 @@
             return false;
         }
 
-        r.makeFinishing();
+        r.makeFinishingLocked();
         final TaskRecord task = r.task;
         EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                 r.userId, System.identityHashCode(r),
@@ -2788,12 +2902,12 @@
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
             // it right now.
-            r.makeFinishing();
+            r.makeFinishingLocked();
             boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
             if (activityRemoved) {
                 mStackSupervisor.resumeTopActivitiesLocked();
             }
-            if (DEBUG_CONTAINERS) Slog.d(TAG, 
+            if (DEBUG_CONTAINERS) Slog.d(TAG,
                     "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
                     " destroy returned removed=" + activityRemoved);
             return activityRemoved ? null : r;
@@ -2801,7 +2915,7 @@
 
         // Need to go through the full pause cycle to get this
         // activity into the stopped state and then finish it.
-        if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
+        if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
         mStackSupervisor.mFinishingActivities.add(r);
         r.resumeKeyDispatchingLocked();
         mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
@@ -2864,9 +2978,8 @@
         return false;
     }
 
-    final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
+    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
-        final ActivityRecord srec = ActivityRecord.forToken(token);
         final TaskRecord task = srec.task;
         final ArrayList<ActivityRecord> activities = task.mActivities;
         final int start = activities.indexOf(srec);
@@ -2939,7 +3052,7 @@
                     foundParentInTask = false;
                 }
                 requestFinishActivityLocked(parent.appToken, resultCode,
-                        resultData, "navigate-up", true);
+                        resultData, "navigate-top", true);
             }
         }
         Binder.restoreCallingIdentity(origId);
@@ -2951,6 +3064,8 @@
      * representation) and cleaning things up as a result of its hosting
      * processing going away, in which case there is no remaining client-side
      * state to destroy so only the cleanup here is needed.
+     *
+     * Note: Call before #removeActivityFromHistoryLocked.
      */
     final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
             boolean setState) {
@@ -3011,7 +3126,7 @@
     private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
         mStackSupervisor.removeChildActivityContainers(r);
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
-        r.makeFinishing();
+        r.makeFinishingLocked();
         if (DEBUG_ADD_REMOVE) {
             RuntimeException here = new RuntimeException("here");
             here.fillInStackTrace();
@@ -3252,13 +3367,13 @@
     final void activityDestroyedLocked(IBinder token, String reason) {
         final long origId = Binder.clearCallingIdentity();
         try {
-            ActivityRecord r = ActivityRecord.forToken(token);
+            ActivityRecord r = ActivityRecord.forTokenLocked(token);
             if (r != null) {
                 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
             }
             if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
 
-            if (isInStackLocked(token) != null) {
+            if (isInStackLocked(r) != null) {
                 if (r.state == ActivityState.DESTROYING) {
                     cleanUpActivityLocked(r, true, false);
                     removeActivityFromHistoryLocked(r, reason);
@@ -3270,10 +3385,9 @@
         }
     }
 
-    void releaseBackgroundResources() {
+    void releaseBackgroundResources(ActivityRecord r) {
         if (hasVisibleBehindActivity() &&
                 !mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
-            final ActivityRecord r = getVisibleBehindActivity();
             if (r == topRunningActivityLocked(null)) {
                 // Don't release the top activity if it has requested to run behind the next
                 // activity.
@@ -3323,15 +3437,14 @@
     private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
             ProcessRecord app, String listName) {
         int i = list.size();
-        if (DEBUG_CLEANUP) Slog.v(
-            TAG, "Removing app " + app + " from list " + listName
-            + " with " + i + " entries");
+        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+            "Removing app " + app + " from list " + listName + " with " + i + " entries");
         while (i > 0) {
             i--;
             ActivityRecord r = list.get(i);
-            if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r);
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record #" + i + " " + r);
             if (r.app == app) {
-                if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!");
+                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "---> REMOVING this entry!");
                 list.remove(i);
                 removeTimeoutsForActivityLocked(r);
             }
@@ -3353,17 +3466,17 @@
 
         // Clean out the history list.
         int i = numActivities();
-        if (DEBUG_CLEANUP) Slog.v(
-            TAG, "Removing app " + app + " from history with " + i + " entries");
+        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                "Removing app " + app + " from history with " + i + " entries");
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 --i;
-                if (DEBUG_CLEANUP) Slog.v(
-                    TAG, "Record #" + i + " " + r + ": app=" + r.app);
+                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                        "Record #" + i + " " + r + ": app=" + r.app);
                 if (r.app == app) {
-                    boolean remove;
+                    final boolean remove;
                     if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
                         // Don't currently have state for the activity, or
                         // it is finishing -- always remove it.
@@ -3397,12 +3510,10 @@
                                 mService.updateUsageStats(r, false);
                             }
                         }
-                        removeActivityFromHistoryLocked(r, "appDied");
-
                     } else {
                         // We have the current state for this activity, so
                         // it can be restarted later when needed.
-                        if (localLOGV) Slog.v(
+                        if (DEBUG_ALL) Slog.v(
                             TAG, "Keeping entry, setting app to null");
                         if (r.visible) {
                             hasVisibleActivities = true;
@@ -3417,8 +3528,10 @@
                             r.icicle = null;
                         }
                     }
-
                     cleanUpActivityLocked(r, true, true);
+                    if (remove) {
+                        removeActivityFromHistoryLocked(r, "appDied");
+                    }
                 }
             }
         }
@@ -3466,7 +3579,7 @@
         }
     }
 
-    final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord source, Bundle options,
+    final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, Bundle options,
             String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
 
@@ -3474,8 +3587,7 @@
         final int index = mTaskHistory.indexOf(tr);
         if (numTasks == 0 || index < 0)  {
             // nothing to do!
-            if (source != null &&
-                    (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            if (noAnimation) {
                 ActivityOptions.abort(options);
             } else {
                 updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
@@ -3489,8 +3601,7 @@
         moveToFront(reason);
 
         if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
-        if (source != null &&
-                (source.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+        if (noAnimation) {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             ActivityRecord r = topRunningActivityLocked(null);
             if (r != null) {
@@ -3554,9 +3665,17 @@
             }
         }
 
-        if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + taskId);
+        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
 
+        boolean prevIsHome = false;
+        if (tr.isOverHomeStack()) {
+            final TaskRecord nextTask = getNextTask(tr);
+            if (nextTask != null) {
+                nextTask.setTaskToReturnTo(tr.getTaskToReturnTo());
+            } else {
+                prevIsHome = true;
+            }
+        }
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
         updateTaskMovement(tr, false);
@@ -3583,7 +3702,8 @@
         }
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
-        if (task == tr && tr.isOverHomeStack() || numTasks <= 1 && isOnHomeDisplay()) {
+        if (prevIsHome || task == tr && tr.isOverHomeStack()
+                || numTasks <= 1 && isOnHomeDisplay()) {
             if (!mService.mBooting && !mService.mBooted) {
                 // Not ready yet!
                 return false;
@@ -3626,10 +3746,30 @@
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                 "Ensuring correct configuration: " + r);
 
+        // Make sure the current stack override configuration is supported by the top task
+        // before continuing.
+        final TaskRecord topTask = topTask();
+        if (topTask != null && ((topTask.mResizeable && mForcedFullscreen)
+                    || (!topTask.mResizeable && !mFullscreen))) {
+            final boolean prevFullscreen = mFullscreen;
+            final Configuration newOverrideConfig =
+                    mWindowManager.forceStackToFullscreen(mStackId, !topTask.mResizeable);
+            updateOverrideConfiguration(newOverrideConfig);
+            mForcedFullscreen = !prevFullscreen && mFullscreen;
+            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
+                    "Updated stack config to support task=" + topTask
+                            + " resizeable=" + topTask.mResizeable
+                            + " mForcedFullscreen=" + mForcedFullscreen
+                            + " prevFullscreen=" + prevFullscreen
+                            + " mFullscreen=" + mFullscreen);
+        }
+
         // Short circuit: if the two configurations are the exact same
         // object (the common case), then there is nothing to do.
         Configuration newConfig = mService.mConfiguration;
-        if (r.configuration == newConfig && !r.forceNewConfig) {
+        if (r.configuration == newConfig
+                && r.stackConfigOverride == mOverrideConfig
+                && !r.forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                     "Configuration unchanged in " + r);
             return true;
@@ -3645,14 +3785,31 @@
 
         // Okay we now are going to make this activity have the new config.
         // But then we need to figure out how it needs to deal with that.
-        Configuration oldConfig = r.configuration;
+        final Configuration oldConfig = r.configuration;
+        final Configuration oldStackOverride = r.stackConfigOverride;
         r.configuration = newConfig;
+        r.stackConfigOverride = mOverrideConfig;
 
         // Determine what has changed.  May be nothing, if this is a config
         // that has come back from the app after going idle.  In that case
         // we just want to leave the official config object now in the
         // activity and do nothing else.
-        final int changes = oldConfig.diff(newConfig);
+        int stackChanges = oldStackOverride.diff(mOverrideConfig);
+        if (stackChanges == 0) {
+            // {@link Configuration#diff} doesn't catch changes from unset values.
+            // Check for changes we care about.
+            if (oldStackOverride.orientation != mOverrideConfig.orientation) {
+                stackChanges |= ActivityInfo.CONFIG_ORIENTATION;
+            }
+            if (oldStackOverride.screenHeightDp != mOverrideConfig.screenHeightDp
+                    || oldStackOverride.screenWidthDp != mOverrideConfig.screenWidthDp) {
+                stackChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
+            }
+            if (oldStackOverride.smallestScreenWidthDp != mOverrideConfig.smallestScreenWidthDp) {
+                stackChanges |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+            }
+        }
+        final int changes = oldConfig.diff(newConfig) | stackChanges;
         if (changes == 0 && !r.forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                     "Configuration no differences in " + r);
@@ -3714,15 +3871,15 @@
             return false;
         }
 
-        // Default case: the activity can handle this new configuration, so
-        // hand it over.  Note that we don't need to give it the new
-        // configuration, since we always send configuration changes to all
-        // process when they happen so it can just use whatever configuration
-        // it last got.
+        // Default case: the activity can handle this new configuration, so hand it over.
+        // NOTE: We only forward the stack override configuration as the system level configuration
+        // changes is always sent to all processes when they happen so it can just use whatever
+        // system level configuration it last got.
         if (r.app != null && r.app.thread != null) {
             try {
                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
-                r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
+                r.app.thread.scheduleActivityConfigurationChanged(
+                        r.appToken, new Configuration(mOverrideConfig));
             } catch (RemoteException e) {
                 // If process died, whatever.
             }
@@ -3756,8 +3913,9 @@
                     (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
                     + r);
             r.forceNewConfig = false;
-            r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
-                    changes, !andResume, new Configuration(mService.mConfiguration));
+            r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
+                    !andResume, new Configuration(mService.mConfiguration),
+                    new Configuration(mOverrideConfig));
             // Note: don't need to call pauseIfSleepingLocked() here, because
             // the caller will only pass in 'andResume' if this activity is
             // currently resumed, which implies we aren't sleeping.
@@ -3790,7 +3948,7 @@
                 }
             }
         }
-        final ActivityRecord r = ActivityRecord.forToken(token);
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null) {
             return false;
         }
@@ -3842,7 +4000,7 @@
                         }
                     }
                     didSomething = true;
-                    Slog.i(TAG, "  Force finishing activity 3 " + r);
+                    Slog.i(TAG, "  Force finishing activity " + r);
                     if (samePackage) {
                         if (r.app != null) {
                             r.app.removed = true;
@@ -3891,7 +4049,7 @@
                     numRunning++;
                 }
 
-                if (localLOGV) Slog.v(
+                if (DEBUG_ALL) Slog.v(
                     TAG, r.intent.getComponent().flattenToShortString()
                     + ": task=" + r.task);
             }
@@ -3952,7 +4110,7 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.app == app) {
-                    Slog.w(TAG, "  Force finishing activity 4 "
+                    Slog.w(TAG, "  Force finishing activity "
                             + r.intent.getComponent().flattenToShortString());
                     // Force the destroy to skip right to removal.
                     r.app = null;
@@ -4033,8 +4191,14 @@
     }
 
     void removeTask(TaskRecord task, String reason) {
+        removeTask(task, reason, true);
+    }
+
+    void removeTask(TaskRecord task, String reason, boolean removeFromWindowManager) {
         mStackSupervisor.endLockTaskModeIfTaskEnding(task);
-        mWindowManager.removeTask(task.taskId);
+        if (removeFromWindowManager) {
+            mWindowManager.removeTask(task.taskId);
+        }
         final ActivityRecord r = mResumedActivity;
         if (r != null && r.task == task) {
             mResumedActivity = null;
@@ -4062,22 +4226,30 @@
             if (task.autoRemoveFromRecents() || isVoiceSession) {
                 // Task creator asked to remove this when done, or this task was a voice
                 // interaction, so it should not remain on the recent tasks list.
-                mService.mRecentTasks.remove(task);
+                mRecentTasks.remove(task);
                 task.removedFromRecents();
             }
         }
 
         if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack=" + this);
+            final boolean notHomeStack = !isHomeStack();
             if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(!isHomeStack(), reason + " leftTaskHistoryEmpty");
+                String myReason = reason + " leftTaskHistoryEmpty";
+                if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                    mStackSupervisor.moveHomeStack(notHomeStack, myReason);
+                }
             }
             if (mStacks != null) {
                 mStacks.remove(this);
                 mStacks.add(0, this);
             }
-            mActivityContainer.onTaskListEmptyLocked();
+            if (notHomeStack) {
+                mActivityContainer.onTaskListEmptyLocked();
+            }
         }
+
+        task.stack = null;
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
@@ -4090,7 +4262,7 @@
     }
 
     ArrayList<TaskRecord> getAllTasks() {
-        return new ArrayList<TaskRecord>(mTaskHistory);
+        return new ArrayList<>(mTaskHistory);
     }
 
     void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
@@ -4118,4 +4290,14 @@
         return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
                 + " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}";
     }
+
+    boolean updateOverrideConfiguration(Configuration newConfig) {
+        Configuration oldConfig = mOverrideConfig;
+        mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
+        // We override the configuration only when the stack's dimensions are different from
+        // the display. In this manner, we know that if the override configuration is empty,
+        // the stack is necessarily full screen.
+        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+        return !mOverrideConfig.equals(oldConfig);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 32787d8..cbbb11a8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -20,7 +20,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static com.android.server.am.ActivityManagerService.localLOGV;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerService.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
@@ -31,7 +31,6 @@
 import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
 import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityManagerService.TAG;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -63,12 +62,14 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -114,7 +115,9 @@
 import java.util.List;
 
 public final class ActivityStackSupervisor implements DisplayListener {
-    static final boolean DEBUG = ActivityManagerService.DEBUG || false;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
+
+    static final boolean DEBUG = DEBUG_ALL || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
     static final boolean DEBUG_CONTAINERS = DEBUG || false;
@@ -166,6 +169,8 @@
 
     final ActivityManagerService mService;
 
+    private final RecentTasks mRecentTasks;
+
     final ActivityStackSupervisorHandler mHandler;
 
     /** Short cut */
@@ -196,32 +201,30 @@
 
     /** List of activities that are waiting for a new activity to become visible before completing
      * whatever operation they are supposed to do. */
-    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mWaitingVisibleActivities = new ArrayList<>();
 
     /** List of processes waiting to find out about the next visible activity. */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible =
-            new ArrayList<IActivityManager.WaitResult>();
+    final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible = new ArrayList<>();
 
     /** List of processes waiting to find out about the next launched activity. */
-    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched =
-            new ArrayList<IActivityManager.WaitResult>();
+    final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched = new ArrayList<>();
 
     /** List of activities that are ready to be stopped, but waiting for the next activity to
      * settle down before doing so. */
-    final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<>();
 
     /** List of activities that are ready to be finished, but waiting for the previous activity to
      * settle down before doing so.  It contains ActivityRecord objects. */
-    final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mFinishingActivities = new ArrayList<>();
 
     /** List of activities that are in the process of going to sleep. */
-    final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<>();
 
     /** Used on user changes */
-    final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
+    final ArrayList<UserStartedState> mStartingUsers = new ArrayList<>();
 
     /** Used to queue up any background users being started */
-    final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<UserStartedState>();
+    final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<>();
 
     /** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
      * is being brought in front of us. */
@@ -265,9 +268,11 @@
     /** If non-null then the task specified remains in front and no other tasks may be started
      * until the task exits or #stopLockTaskMode() is called. */
     TaskRecord mLockTaskModeTask;
-    /** Whether lock task has been entered by an authorized app and cannot
-     * be exited. */
-    private boolean mLockTaskIsLocked;
+    /** Store the current lock task mode. Possible values:
+     * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
+     * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+     */
+    private int mLockTaskModeState;
     /**
      * Notifies the user when entering/exiting lock-task.
      */
@@ -298,8 +303,9 @@
         }
     }
 
-    public ActivityStackSupervisor(ActivityManagerService service) {
+    public ActivityStackSupervisor(ActivityManagerService service, RecentTasks recentTasks) {
         mService = service;
+        mRecentTasks = recentTasks;
         mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
     }
 
@@ -384,21 +390,26 @@
         return mLastFocusedStack;
     }
 
-    // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
-    // top of all visible stacks.
+    /** Top of all visible stacks is/should always be equal to the focused stack.
+     * Use {@link ActivityStack#isStackVisibleLocked} to determine if a specific
+     * stack is visible or not. */
     boolean isFrontStack(ActivityStack stack) {
+        if (stack == null) {
+            return false;
+        }
+
         final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
         if (parent != null) {
             stack = parent.task.stack;
         }
-        ArrayList<ActivityStack> stacks = stack.mStacks;
-        if (stacks != null && !stacks.isEmpty()) {
-            return stack == stacks.get(stacks.size() - 1);
-        }
-        return false;
+        return stack == mFocusedStack;
     }
 
     void moveHomeStack(boolean toFront, String reason) {
+        moveHomeStack(toFront, reason, null);
+    }
+
+    void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) {
         ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         final int topNdx = stacks.size() - 1;
         if (topNdx <= 0) {
@@ -407,13 +418,17 @@
         ActivityStack topStack = stacks.get(topNdx);
         final boolean homeInFront = topStack == mHomeStack;
         if (homeInFront != toFront) {
-            mLastFocusedStack = topStack;
             stacks.remove(mHomeStack);
             stacks.add(toFront ? topNdx : 0, mHomeStack);
-            mFocusedStack = stacks.get(topNdx);
             if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new="
                     + mFocusedStack);
         }
+
+        if (lastFocusedStack != null) {
+            mLastFocusedStack = lastFocusedStack;
+        }
+        mFocusedStack = stacks.get(topNdx);
+
         EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
                 mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
                 mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
@@ -460,6 +475,16 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
+        return anyTaskForIdLocked(id, true);
+    }
+
+    /**
+     * Returns a {@link TaskRecord} for the input id if available. Null otherwise.
+     * @param id Id of the task we would like returned.
+     * @param restoreFromRecents If the id was not in the active list, but was found in recents,
+     *                           restore the task from recents to the active list.
+     */
+    TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -474,12 +499,16 @@
 
         // Don't give up! Look in recents.
         if (DEBUG_RECENTS) Slog.v(TAG, "Looking for task id=" + id + " in recents");
-        TaskRecord task = mService.recentTaskForIdLocked(id);
+        TaskRecord task = mRecentTasks.taskForIdLocked(id);
         if (task == null) {
             if (DEBUG_RECENTS) Slog.d(TAG, "\tDidn't find task id=" + id + " in recents");
             return null;
         }
 
+        if (!restoreFromRecents) {
+            return task;
+        }
+
         if (!restoreRecentTaskLocked(task)) {
             if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -514,12 +543,12 @@
             if (mCurTaskId <= 0) {
                 mCurTaskId = 1;
             }
-        } while (anyTaskForIdLocked(mCurTaskId) != null);
+        } while (anyTaskForIdLocked(mCurTaskId, false) != null);
         return mCurTaskId;
     }
 
     ActivityRecord resumedAppLocked() {
-        ActivityStack stack = getFocusedStack();
+        ActivityStack stack = mFocusedStack;
         if (stack == null) {
             return null;
         }
@@ -612,7 +641,7 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
-                if (r != null && (!r.nowVisible || r.waitingVisible)) {
+                if (r != null && (!r.nowVisible || mWaitingVisibleActivities.contains(r))) {
                     return false;
                 }
             }
@@ -723,7 +752,7 @@
     }
 
     ActivityRecord topRunningActivityLocked() {
-        final ActivityStack focusedStack = getFocusedStack();
+        final ActivityStack focusedStack = mFocusedStack;
         ActivityRecord r = focusedStack.topRunningActivityLocked(null);
         if (r != null) {
             return r;
@@ -855,6 +884,11 @@
 
         ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
+            if (container != null && container.mParentActivity != null &&
+                    container.mParentActivity.state != ActivityState.RESUMED) {
+                // Cannot start a child activity if the parent is not resumed.
+                return ActivityManager.START_CANCELED;
+            }
             final int realCallingPid = Binder.getCallingPid();
             final int realCallingUid = Binder.getCallingUid();
             int callingPid;
@@ -869,19 +903,19 @@
 
             final ActivityStack stack;
             if (container == null || container.mStack.isOnHomeDisplay()) {
-                stack = getFocusedStack();
+                stack = mFocusedStack;
             } else {
                 stack = container.mStack;
             }
-            stack.mConfigWillChange = config != null
-                    && mService.mConfiguration.diff(config) != 0;
+            stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
             if (DEBUG_CONFIGURATION) Slog.v(TAG,
                     "Starting activity when config will change = " + stack.mConfigWillChange);
 
             final long origId = Binder.clearCallingIdentity();
 
             if (aInfo != null &&
-                    (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+                    (aInfo.applicationInfo.privateFlags
+                            &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Check to see if we already
                 // have another, different heavy-weight process running.
                 if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
@@ -1052,8 +1086,8 @@
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
                     if (aInfo != null &&
-                            (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE)
-                                    != 0) {
+                            (aInfo.applicationInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)  != 0) {
                         throw new IllegalArgumentException(
                                 "FLAG_CANT_SAVE_STATE not supported here");
                     }
@@ -1111,7 +1145,7 @@
         r.launchCount++;
         r.lastLaunchTime = SystemClock.uptimeMillis();
 
-        if (localLOGV) Slog.v(TAG, "Launching: " + r);
+        if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
 
         int idx = app.activities.indexOf(r);
         if (idx < 0) {
@@ -1180,11 +1214,11 @@
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
-                    r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
-                    r.icicle, r.persistentState, results, newIntents, !andResume,
-                    mService.isNextTransitionForward(), profilerInfo);
+                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
+                    r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
+                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
 
-            if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
+            if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
                 // manager will ensure that only activity can run in the main
                 // process of the .apk, which is the only thing that will be
@@ -1350,6 +1384,9 @@
                 return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
             }
             resultRecord = sourceRecord.resultTo;
+            if (resultRecord != null && !resultRecord.isInStackLocked()) {
+                resultRecord = null;
+            }
             resultWho = sourceRecord.resultWho;
             requestCode = sourceRecord.requestCode;
             sourceRecord.resultTo = null;
@@ -1486,7 +1523,7 @@
             outActivity[0] = r;
         }
 
-        final ActivityStack stack = getFocusedStack();
+        final ActivityStack stack = mFocusedStack;
         if (voiceSession == null && (stack.mResumedActivity == null
                 || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
             if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
@@ -1525,25 +1562,27 @@
         return err;
     }
 
-    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
+    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
 
         // On leanback only devices we should keep all activities in the same stack.
         if (!mLeanbackOnlyDevice &&
                 (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
-            if (task != null) {
-                final ActivityStack taskStack = task.stack;
-                if (taskStack.isOnHomeDisplay()) {
-                    if (mFocusedStack != taskStack) {
-                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
+
+            ActivityStack stack;
+
+            if (task != null && task.stack != null) {
+                stack = task.stack;
+                if (stack.isOnHomeDisplay()) {
+                    if (mFocusedStack != stack) {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: Setting " +
                                 "focused stack to r=" + r + " task=" + task);
-                        mFocusedStack = taskStack;
                     } else {
                         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                            "computeStackFocus: Focused stack already=" + mFocusedStack);
                     }
                 }
-                return taskStack;
+                return stack;
             }
 
             final ActivityContainer container = r.mInitialActivityContainer;
@@ -1556,47 +1595,44 @@
             if (mFocusedStack != mHomeStack && (!newTask ||
                     mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+                        "computeStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
             }
 
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
+                stack = homeDisplayStacks.get(stackNdx);
                 if (!stack.isHomeStack()) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Setting focused stack=" + stack);
-                    mFocusedStack = stack;
-                    return mFocusedStack;
+                            "computeStackFocus: Setting focused stack=" + stack);
+                    return stack;
                 }
             }
 
             // Need to create an app stack for this user.
-            int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
-                    " stackId=" + stackId);
-            mFocusedStack = getStack(stackId);
-            return mFocusedStack;
+            stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: New stack r=" + r +
+                    " stackId=" + stack.mStackId);
+            return stack;
         }
         return mHomeStack;
     }
 
-    void setFocusedStack(ActivityRecord r, String reason) {
-        if (r != null) {
-            final TaskRecord task = r.task;
-            boolean isHomeActivity = !r.isApplicationActivity();
-            if (!isHomeActivity && task != null) {
-                isHomeActivity = !task.isApplicationTask();
-            }
-            if (!isHomeActivity && task != null) {
-                final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
-                isHomeActivity = parent != null && parent.isHomeActivity();
-            }
-            moveHomeStack(isHomeActivity, reason);
+    boolean setFocusedStack(ActivityRecord r, String reason) {
+        if (r == null) {
+            // Not sure what you are trying to do, but it is not going to work...
+            return false;
         }
+        final TaskRecord task = r.task;
+        if (task == null || task.stack == null) {
+            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            return false;
+        }
+        task.stack.moveToFront(reason);
+        return true;
     }
 
-    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
+    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
             boolean doResume, Bundle options, TaskRecord inTask) {
         final Intent intent = r.intent;
@@ -1643,7 +1679,8 @@
                 && !launchSingleTask && !launchSingleInstance
                 && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
 
-        if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+        if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
+                && r.resultTo.task.stack != null) {
             // For whatever reason this activity is being launched into a new
             // task...  yet the caller has requested a result back.  Well, that
             // is pretty messed up, so instead immediately send back a cancel
@@ -1691,7 +1728,7 @@
         if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
             ActivityRecord checkedCaller = sourceRecord;
             if (checkedCaller == null) {
-                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
+                checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
             }
             if (!checkedCaller.realActivity.equals(r.realActivity)) {
                 // Caller is not the same as launcher, so always needed.
@@ -1807,6 +1844,7 @@
         ActivityStack targetStack;
 
         intent.setFlags(launchFlags);
+        final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
 
         // We may want to try to place the new activity in to an existing task.  We always
         // do this if the target activity is singleTask or singleInstance; we will also do
@@ -1869,8 +1907,8 @@
                                 intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                             }
                             movedHome = true;
-                            targetStack.moveTaskToFrontLocked(intentActivity.task, r, options,
-                                    "bringingFoundTaskToFront");
+                            targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
+                                    options, "bringingFoundTaskToFront");
                             if ((launchFlags &
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
@@ -2014,7 +2052,7 @@
             // If the activity being launched is the same as the one currently
             // at the top, then we need to check if it should only be launched
             // once.
-            ActivityStack topStack = getFocusedStack();
+            ActivityStack topStack = mFocusedStack;
             ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
             if (top != null && r.resultTo == null) {
                 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
@@ -2044,7 +2082,7 @@
             }
 
         } else {
-            if (r.resultTo != null) {
+            if (r.resultTo != null && r.resultTo.task.stack != null) {
                 r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
                         r.requestCode, Activity.RESULT_CANCELED, null);
             }
@@ -2066,10 +2104,9 @@
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             newTask = true;
-            targetStack = adjustStackFocus(r, newTask);
-            if (!launchTaskBehind) {
-                targetStack.moveToFront("startingNewTask");
-            }
+            targetStack = computeStackFocus(r, newTask);
+            targetStack.moveToFront("startingNewTask");
+
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                         newTaskInfo != null ? newTaskInfo : r.info,
@@ -2100,7 +2137,8 @@
             targetStack.moveToFront("sourceStackToFront");
             final TaskRecord topTask = targetStack.topTask();
             if (topTask != sourceTask) {
-                targetStack.moveTaskToFrontLocked(sourceTask, r, options, "sourceTaskToFront");
+                targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
+                        "sourceTaskToFront");
             }
             if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                 // In this case, we are adding the activity to an existing
@@ -2154,7 +2192,7 @@
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             targetStack = inTask.stack;
-            targetStack.moveTaskToFrontLocked(inTask, r, options, "inTaskToFront");
+            targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, "inTaskToFront");
 
             // Check whether we should actually launch the new activity in to the task,
             // or just reuse the current activity on top.
@@ -2189,7 +2227,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = adjustStackFocus(r, newTask);
+            targetStack = computeStackFocus(r, newTask);
             targetStack.moveToFront("addingToTopTask");
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
@@ -2267,7 +2305,7 @@
     // Checked.
     final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
             Configuration config) {
-        if (localLOGV) Slog.v(TAG, "Activity idle: " + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
 
         ArrayList<ActivityRecord> stops = null;
         ArrayList<ActivityRecord> finishes = null;
@@ -2277,7 +2315,7 @@
         boolean booting = false;
         boolean activityRemoved = false;
 
-        ActivityRecord r = ActivityRecord.forToken(token);
+        ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r != null) {
             if (DEBUG_IDLE) Slog.d(TAG, "activityIdleInternalLocked: Callers=" +
                     Debug.getCallers(4));
@@ -2325,13 +2363,13 @@
         // Atomically retrieve all of the other things to do.
         stops = processStoppingActivitiesLocked(true);
         NS = stops != null ? stops.size() : 0;
-        if ((NF=mFinishingActivities.size()) > 0) {
-            finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
+        if ((NF = mFinishingActivities.size()) > 0) {
+            finishes = new ArrayList<>(mFinishingActivities);
             mFinishingActivities.clear();
         }
 
         if (mStartingUsers.size() > 0) {
-            startingUsers = new ArrayList<UserStartedState>(mStartingUsers);
+            startingUsers = new ArrayList<>(mStartingUsers);
             mStartingUsers.clear();
         }
 
@@ -2340,10 +2378,12 @@
         for (int i = 0; i < NS; i++) {
             r = stops.get(i);
             final ActivityStack stack = r.task.stack;
-            if (r.finishing) {
-                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
-            } else {
-                stack.stopActivityLocked(r);
+            if (stack != null) {
+                if (r.finishing) {
+                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
+                } else {
+                    stack.stopActivityLocked(r);
+                }
             }
         }
 
@@ -2351,7 +2391,10 @@
         // waiting for the next one to start.
         for (int i = 0; i < NF; i++) {
             r = finishes.get(i);
-            activityRemoved |= r.task.stack.destroyActivityLocked(r, true, "finish-idle");
+            final ActivityStack stack = r.task.stack;
+            if (stack != null) {
+                activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
+            }
         }
 
         if (!booting) {
@@ -2465,13 +2508,14 @@
     boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
             Bundle targetOptions) {
         if (targetStack == null) {
-            targetStack = getFocusedStack();
+            targetStack = mFocusedStack;
         }
         // Do targetStack first.
         boolean result = false;
         if (isFrontStack(targetStack)) {
             result = targetStack.resumeTopActivityLocked(target, targetOptions);
         }
+
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2488,13 +2532,13 @@
         return result;
     }
 
-    void finishTopRunningActivityLocked(ProcessRecord app) {
+    void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             final int numStacks = stacks.size();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                stack.finishTopRunningActivityLocked(app);
+                stack.finishTopRunningActivityLocked(app, reason);
             }
         }
     }
@@ -2519,7 +2563,12 @@
             // we'll just indicate that this task returns to the home task.
             task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
         }
-        task.stack.moveTaskToFrontLocked(task, null, options, reason);
+        if (task.stack == null) {
+            Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task="
+                    + task + " to front. Stack is null");
+            return;
+        }
+        task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options, reason);
         if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
                 + task.stack);
     }
@@ -2565,7 +2614,7 @@
         return null;
     }
 
-    ActivityContainer createActivityContainer(ActivityRecord parentActivity,
+    ActivityContainer createVirtualActivityContainer(ActivityRecord parentActivity,
             IActivityContainerCallback callback) {
         ActivityContainer activityContainer =
                 new VirtualActivityContainer(parentActivity, callback);
@@ -2596,16 +2645,85 @@
         }
     }
 
-    private int createStackOnDisplay(int stackId, int displayId) {
+    void resizeStackLocked(int stackId, Rect bounds) {
+        final ActivityStack stack = getStack(stackId);
+        if (stack == null) {
+            Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
+            return;
+        }
+
+        final ActivityRecord r = stack.topRunningActivityLocked(null);
+        if (r != null && !r.task.mResizeable) {
+            Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable.");
+            return;
+        }
+
+        final Configuration overrideConfig = mWindowManager.resizeStack(stackId, bounds);
+        if (stack.updateOverrideConfiguration(overrideConfig)) {
+            if (r != null) {
+                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                ensureActivitiesVisibleLocked(r, 0);
+                if (!updated) {
+                    resumeTopActivitiesLocked(stack, null, null);
+                }
+            }
+        }
+    }
+
+    /** Makes sure the input task is in a stack with the specified bounds by either resizing the
+     * current task stack if it only has one entry, moving the task to a stack that matches the
+     * bounds, or creating a new stack with the required bounds. Also, makes the task resizeable.*/
+    void resizeTaskLocked(TaskRecord task, Rect bounds) {
+        task.mResizeable = true;
+        final ActivityStack currentStack = task.stack;
+        if (currentStack.isHomeStack()) {
+            // Can't move task off the home stack. Sorry!
+            return;
+        }
+
+        final int matchingStackId = mWindowManager.getStackIdWithBounds(bounds);
+        if (matchingStackId != -1) {
+            // There is already a stack with the right bounds!
+            if (currentStack != null && currentStack.mStackId == matchingStackId) {
+                // Nothing to do here. Already in the right stack...
+                return;
+            }
+            // Move task to stack with matching bounds.
+            moveTaskToStackLocked(task.taskId, matchingStackId, true);
+            return;
+        }
+
+        if (currentStack != null && currentStack.numTasks() == 1) {
+            // Just resize the current stack since this is the task in it.
+            resizeStackLocked(currentStack.mStackId, bounds);
+            return;
+        }
+
+        // Create new stack and move the task to it.
+        final int displayId = (currentStack != null && currentStack.mDisplayId != -1)
+                ? currentStack.mDisplayId : Display.DEFAULT_DISPLAY;
+        ActivityStack newStack = createStackOnDisplay(getNextStackId(), displayId);
+
+        if (newStack == null) {
+            Slog.e(TAG, "resizeTaskLocked: Can't create stack for task=" + task);
+            return;
+        }
+        moveTaskToStackLocked(task.taskId, newStack.mStackId, true);
+        resizeStackLocked(newStack.mStackId, bounds);
+    }
+
+    ActivityStack createStackOnDisplay(int stackId, int displayId) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
-            return -1;
+            return null;
         }
 
         ActivityContainer activityContainer = new ActivityContainer(stackId);
         mActivityContainers.put(stackId, activityContainer);
         activityContainer.attachToDisplayLocked(activityDisplay);
-        return stackId;
+        return activityContainer.mStack;
     }
 
     int getNextStackId() {
@@ -2631,7 +2749,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack()) {
+                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
                     stack = tmpStack;
                     break;
                 }
@@ -2642,7 +2760,7 @@
             // We couldn't find a stack to restore the task to. Possible if are restoring recents
             // before an application stack is created...Go ahead and create one on the default
             // display.
-            stack = getStack(createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY));
+            stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
             // Restore home stack to top.
             moveHomeStack(true, "restoreRecentTask");
             if (DEBUG_RECENTS)
@@ -2674,6 +2792,7 @@
     void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
+            Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
             return;
         }
         final ActivityStack stack = getStack(stackId);
@@ -2681,9 +2800,11 @@
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        task.stack.removeTask(task, "moveTaskToStack");
+        mWindowManager.moveTaskToStack(taskId, stackId, toTop);
+        if (task.stack != null) {
+            task.stack.removeTask(task, "moveTaskToStack", false);
+        }
         stack.addTask(task, toTop, true);
-        mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
     }
 
@@ -2933,7 +3054,7 @@
         r.mLaunchTaskBehind = false;
         final TaskRecord task = r.task;
         task.setLastThumbnail(task.stack.screenshotActivities(r));
-        mService.addRecentTaskLocked(task);
+        mRecentTasks.addLocked(task);
         mService.notifyTaskStackChangedLocked();
         mWindowManager.setAppVisibility(r.appToken, false);
     }
@@ -3024,7 +3145,7 @@
     }
 
     boolean switchUserLocked(int userId, UserStartedState uss) {
-        mUserStackInFront.put(mCurrentUser, getFocusedStack().getStackId());
+        mUserStackInFront.put(mCurrentUser, mFocusedStack.getStackId());
         final int restoreStackId = mUserStackInFront.get(userId, HOME_STACK_ID);
         mCurrentUser = userId;
 
@@ -3069,39 +3190,33 @@
     }
 
     final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
-        int N = mStoppingActivities.size();
-        if (N <= 0) return null;
-
         ArrayList<ActivityRecord> stops = null;
 
         final boolean nowVisible = allResumedActivitiesVisible();
-        for (int i=0; i<N; i++) {
-            ActivityRecord s = mStoppingActivities.get(i);
-            if (localLOGV) Slog.v(TAG, "Stopping " + s + ": nowVisible="
-                    + nowVisible + " waitingVisible=" + s.waitingVisible
-                    + " finishing=" + s.finishing);
-            if (s.waitingVisible && nowVisible) {
+        for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord s = mStoppingActivities.get(activityNdx);
+            final boolean waitingVisible = mWaitingVisibleActivities.contains(s);
+            if (DEBUG_ALL) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+                    + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
+            if (waitingVisible && nowVisible) {
                 mWaitingVisibleActivities.remove(s);
-                s.waitingVisible = false;
                 if (s.finishing) {
                     // If this activity is finishing, it is sitting on top of
                     // everyone else but we now know it is no longer needed...
                     // so get rid of it.  Otherwise, we need to go through the
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
-                    if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
+                    if (DEBUG_ALL) Slog.v(TAG, "Before stopping, can hide: " + s);
                     mWindowManager.setAppVisibility(s.appToken, false);
                 }
             }
-            if ((!s.waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
-                if (localLOGV) Slog.v(TAG, "Ready to stop: " + s);
+            if ((!waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
+                if (DEBUG_ALL) Slog.v(TAG, "Ready to stop: " + s);
                 if (stops == null) {
-                    stops = new ArrayList<ActivityRecord>();
+                    stops = new ArrayList<>();
                 }
                 stops.add(s);
-                mStoppingActivities.remove(i);
-                N--;
-                i--;
+                mStoppingActivities.remove(activityNdx);
             }
         }
 
@@ -3154,7 +3269,7 @@
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
-        return getFocusedStack().getDumpActivitiesLocked(name);
+        return mFocusedStack.getDumpActivitiesLocked(name);
     }
 
     static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage,
@@ -3452,10 +3567,10 @@
     }
 
     void showLockTaskToast() {
-        mLockTaskNotify.showToast(mLockTaskIsLocked);
+        mLockTaskNotify.showToast(mLockTaskModeState);
     }
 
-    void setLockTaskModeLocked(TaskRecord task, boolean isLocked, String reason) {
+    void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
         if (task == null) {
             // Take out of lock task mode if necessary
             if (mLockTaskModeTask != null) {
@@ -3479,7 +3594,7 @@
         lockTaskMsg.obj = mLockTaskModeTask.intent.getComponent().getPackageName();
         lockTaskMsg.arg1 = mLockTaskModeTask.userId;
         lockTaskMsg.what = LOCK_TASK_START_MSG;
-        lockTaskMsg.arg2 = !isLocked ? 1 : 0;
+        lockTaskMsg.arg2 = lockTaskModeState;
         mHandler.sendMessage(lockTaskMsg);
     }
 
@@ -3497,8 +3612,8 @@
         }
     }
 
-    boolean isInLockTaskMode() {
-        return mLockTaskModeTask != null;
+    int getLockTaskModeState() {
+        return mLockTaskModeState;
     }
 
     private final class ActivityStackSupervisorHandler extends Handler {
@@ -3590,13 +3705,18 @@
                             mLockTaskNotify = new LockTaskNotify(mService.mContext);
                         }
                         mLockTaskNotify.show(true);
-                        mLockTaskIsLocked = msg.arg2 == 0;
+                        mLockTaskModeState = msg.arg2;
                         if (getStatusBarService() != null) {
-                            int flags =
-                                    StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
-                            if (!mLockTaskIsLocked) {
-                                flags ^= StatusBarManager.DISABLE_HOME
-                                        | StatusBarManager.DISABLE_RECENT;
+                            int flags = 0;
+                            if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+                                flags = StatusBarManager.DISABLE_MASK
+                                        & (~StatusBarManager.DISABLE_BACK);
+                            } else if (mLockTaskModeState ==
+                                    ActivityManager.LOCK_TASK_MODE_PINNED) {
+                                flags = StatusBarManager.DISABLE_MASK
+                                        & (~StatusBarManager.DISABLE_BACK)
+                                        & (~StatusBarManager.DISABLE_HOME)
+                                        & (~StatusBarManager.DISABLE_RECENT);
                             }
                             getStatusBarService().disable(flags, mToken,
                                     mService.mContext.getPackageName());
@@ -3630,7 +3750,8 @@
                             boolean shouldLockKeyguard = Settings.Secure.getInt(
                                     mService.mContext.getContentResolver(),
                                     Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
-                            if (!mLockTaskIsLocked && shouldLockKeyguard) {
+                            if (mLockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
+                                    shouldLockKeyguard) {
                                 mWindowManager.lockNow(null);
                                 mWindowManager.dismissKeyguard();
                                 new LockPatternUtils(mService.mContext)
@@ -3641,6 +3762,8 @@
                         }
                     } catch (RemoteException ex) {
                         throw new RuntimeException(ex);
+                    } finally {
+                        mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
                     }
                 } break;
                 case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
@@ -3664,7 +3787,7 @@
                 } break;
                 case LAUNCH_TASK_BEHIND_COMPLETE: {
                     synchronized (mService) {
-                        ActivityRecord r = ActivityRecord.forToken((IBinder) msg.obj);
+                        ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
                         if (r != null) {
                             handleLaunchTaskBehindCompleteLocked(r);
                         }
@@ -3696,7 +3819,7 @@
         ActivityContainer(int stackId) {
             synchronized (mService) {
                 mStackId = stackId;
-                mStack = new ActivityStack(this);
+                mStack = new ActivityStack(this, mRecentTasks);
                 mIdString = "ActivtyContainer{" + mStackId + "}";
                 if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
             }
@@ -3735,6 +3858,13 @@
         }
 
         @Override
+        public int getStackId() {
+            synchronized (mService) {
+                return mStackId;
+            }
+        }
+
+        @Override
         public boolean injectEvent(InputEvent event) {
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -3788,18 +3918,21 @@
         @Override
         public final int startActivity(Intent intent) {
             mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
-            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
+
             // TODO: Switch to user app stacks here.
-            intent.addFlags(FORCE_NEW_TASK_FLAGS);
             String mimeType = intent.getType();
-            if (mimeType == null && intent.getData() != null
-                    && "content".equals(intent.getData().getScheme())) {
-                mimeType = mService.getProviderMimeType(intent.getData(), userId);
+            final Uri data = intent.getData();
+            if (mimeType == null && data != null && "content".equals(data.getScheme())) {
+                mimeType = mService.getProviderMimeType(data, userId);
             }
-            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0,
-                    0, null, null, null, null, userId, this, null);
+            checkEmbeddedAllowedInner(userId, intent, mimeType);
+
+            intent.addFlags(FORCE_NEW_TASK_FLAGS);
+            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
+                    0, 0, null, null, null, null, userId, this, null);
         }
 
         @Override
@@ -3810,21 +3943,19 @@
                 throw new IllegalArgumentException("Bad PendingIntent object");
             }
 
-            return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
-                    null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
-        }
-
-        private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) {
-            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
-            if (resolvedType == null) {
-                resolvedType = intent.getType();
-                if (resolvedType == null && intent.getData() != null
-                        && "content".equals(intent.getData().getScheme())) {
-                    resolvedType = mService.getProviderMimeType(intent.getData(), userId);
-                }
-            }
+
+            final PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
+            checkEmbeddedAllowedInner(userId, pendingIntent.key.requestIntent,
+                    pendingIntent.key.requestResolvedType);
+
+            return pendingIntent.sendInner(0, null, null, null, null, null, null, 0,
+                    FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
+        }
+
+        private void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
             ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, userId);
             if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
@@ -3832,23 +3963,6 @@
             }
         }
 
-        /** Throw a SecurityException if allowEmbedded is not true */
-        @Override
-        public final void checkEmbeddedAllowed(Intent intent) {
-            checkEmbeddedAllowedInner(intent, null);
-        }
-
-        /** Throw a SecurityException if allowEmbedded is not true */
-        @Override
-        public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
-            if (!(intentSender instanceof PendingIntentRecord)) {
-                throw new IllegalArgumentException("Bad PendingIntent object");
-            }
-            PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
-            checkEmbeddedAllowedInner(pendingIntent.key.requestIntent,
-                    pendingIntent.key.requestResolvedType);
-        }
-
         @Override
         public IBinder asBinder() {
             return this;
@@ -3897,6 +4011,10 @@
         }
 
         void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            detachLocked();
+            deleteActivityContainer(this);
+            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
         @Override
@@ -3985,13 +4103,6 @@
             return false;
         }
 
-        void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-            detachLocked();
-            deleteActivityContainer(this);
-            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
-        }
-
         private void setSurfaceIfReadyLocked() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 65273c9..df833ad 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -19,7 +19,6 @@
 import android.util.ArraySet;
 
 import java.io.PrintWriter;
-import java.util.Iterator;
 
 /**
  * An association between a service and one of its client applications.
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c0928c7..6eacfa9 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -46,7 +46,6 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.List;
@@ -752,14 +751,17 @@
     private void dumpHelp(PrintWriter pw) {
         pw.println("Battery stats (batterystats) dump options:");
         pw.println("  [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
-        pw.println("  [--reset] [--write] [-h] [<package.name>]");
+        pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
         pw.println("  --checkin: format output for a checkin report.");
         pw.println("  --history: show only history data.");
         pw.println("  --history-start <num>: show only history data starting at given time offset.");
         pw.println("  --unplugged: only output data since last unplugged.");
         pw.println("  --charged: only output data since last charged.");
+        pw.println("  --daily: only output full daily data.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
+        pw.println("  --new-daily: immediately create and write new daily stats record.");
+        pw.println("  --read-daily: read-load last written daily stats.");
         pw.println("  <package.name>: optional name of package to filter output by.");
         pw.println("  -h: print this help text.");
         pw.println("Battery stats (batterystats) commands:");
@@ -836,6 +838,8 @@
                     flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
                 } else if ("--charged".equals(arg)) {
                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
+                } else if ("--daily".equals(arg)) {
+                    flags |= BatteryStats.DUMP_DAILY_ONLY;
                 } else if ("--reset".equals(arg)) {
                     synchronized (mStats) {
                         mStats.resetAllStatsCmdLocked();
@@ -848,6 +852,18 @@
                         pw.println("Battery stats written.");
                         noOutput = true;
                     }
+                } else if ("--new-daily".equals(arg)) {
+                    synchronized (mStats) {
+                        mStats.recordDailyStatsLocked();
+                        pw.println("New daily stats written.");
+                        noOutput = true;
+                    }
+                } else if ("--read-daily".equals(arg)) {
+                    synchronized (mStats) {
+                        mStats.readDailyStatsLocked();
+                        pw.println("Last daily stats read.");
+                        noOutput = true;
+                    }
                 } else if ("--enable".equals(arg) || "enable".equals(arg)) {
                     i = doEnableOrDisable(pw, i, args, true);
                     if (i < 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 9b7d0b2..8fe1238 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -27,7 +27,6 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
@@ -40,9 +39,10 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 /**
  * BROADCASTS
  *
@@ -50,11 +50,9 @@
  * foreground priority, and one for normal (background-priority) broadcasts.
  */
 public final class BroadcastQueue {
-    static final String TAG = "BroadcastQueue";
-    static final String TAG_MU = ActivityManagerService.TAG_MU;
-    static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
-    static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
-    static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM;
+    private static final String TAG_MU = TAG + POSTFIX_MU;
+    private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
 
     static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
     static final int MAX_BROADCAST_SUMMARY_HISTORY
@@ -145,7 +143,7 @@
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
                     if (DEBUG_BROADCAST) Slog.v(
-                            TAG, "Received BROADCAST_INTENT_MSG");
+                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                     processNextBroadcast(true);
                 } break;
                 case BROADCAST_TIMEOUT_MSG: {
@@ -187,16 +185,18 @@
 
     public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
         mParallelBroadcasts.add(r);
+        r.enqueueClockTime = System.currentTimeMillis();
     }
 
     public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
         mOrderedBroadcasts.add(r);
+        r.enqueueClockTime = System.currentTimeMillis();
     }
 
     public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
         for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
             if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "***** DROPPING PARALLEL ["
                 + mQueueName + "]: " + r.intent);
                 mParallelBroadcasts.set(i, r);
@@ -209,7 +209,7 @@
     public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
         for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
             if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "***** DROPPING ORDERED ["
                         + mQueueName + "]: " + r.intent);
                 mOrderedBroadcasts.set(i, r);
@@ -221,7 +221,7 @@
 
     private final void processCurBroadcastLocked(BroadcastRecord r,
             ProcessRecord app) throws RemoteException {
-        if (DEBUG_BROADCAST)  Slog.v(TAG,
+        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                 "Process cur broadcast " + r + " for app " + app);
         if (app.thread == null) {
             throw new RemoteException();
@@ -238,7 +238,7 @@
 
         boolean started = false;
         try {
-            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
             mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
@@ -246,12 +246,12 @@
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                     app.repProcState);
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
+            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
         } finally {
             if (!started) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Process cur broadcast " + r + ": NOT STARTED!");
                 r.receiver = null;
                 r.curApp = null;
@@ -305,23 +305,22 @@
                     r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
-
-        r = mPendingBroadcast;
-        if (r != null && r.curApp == app) {
-            if (DEBUG_BROADCAST) Slog.v(TAG,
+        if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "[" + mQueueName + "] skip & discard pending app " + r);
+            r = mPendingBroadcast;
+        }
+
+        if (r != null) {
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
                     r.resultExtras, r.resultAbort, false);
-            reschedule = true;
-        }
-        if (reschedule) {
             scheduleBroadcastsLocked();
         }
     }
 
     public void scheduleBroadcastsLocked() {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                 + mQueueName + "]: current="
                 + mBroadcastsScheduled);
 
@@ -391,8 +390,7 @@
                 // on.  If there are background services currently starting, then we will go into a
                 // special state where we hold off on continuing this broadcast until they are done.
                 if (mService.mServices.hasBackgroundServices(r.userId)) {
-                    Slog.i(ActivityManagerService.TAG, "Delay finish: "
-                            + r.curComponent.flattenToShortString());
+                    Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                     r.state = BroadcastRecord.WAITING_SERVICES;
                     return false;
                 }
@@ -412,7 +410,7 @@
         if (mOrderedBroadcasts.size() > 0) {
             BroadcastRecord br = mOrderedBroadcasts.get(0);
             if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
-                Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+                Slog.i(TAG, "Resuming delayed broadcast");
                 br.curComponent = null;
                 br.state = BroadcastRecord.IDLE;
                 processNextBroadcast(false);
@@ -475,7 +473,7 @@
             int mode = mService.mAppOpsService.noteOperation(r.appOp,
                     filter.receiverList.uid, filter.packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "App op " + r.appOp + " not allowed for broadcast to uid "
                         + filter.receiverList.uid + " pkg " + filter.packageName);
                 skip = true;
@@ -513,14 +511,11 @@
                 }
             }
             try {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    int seq = r.intent.getIntExtra("seq", -1);
-                    Slog.i(TAG, "Delivering to " + filter
-                            + " (seq=" + seq + "): " + r);
-                }
+                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
+                        "Delivering to " + filter + " : " + r);
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                    new Intent(r.intent), r.resultCode, r.resultData,
-                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
+                        new Intent(r.intent), r.resultCode, r.resultData,
+                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                 if (ordered) {
                     r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                 }
@@ -542,7 +537,7 @@
         synchronized(mService) {
             BroadcastRecord r;
 
-            if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
                     + mQueueName + "]: "
                     + mParallelBroadcasts.size() + " broadcasts, "
                     + mOrderedBroadcasts.size() + " ordered broadcasts");
@@ -559,17 +554,17 @@
                 r.dispatchTime = SystemClock.uptimeMillis();
                 r.dispatchClockTime = System.currentTimeMillis();
                 final int N = r.receivers.size();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                         + mQueueName + "] " + r);
                 for (int i=0; i<N; i++) {
                     Object target = r.receivers.get(i);
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                             "Delivering non-ordered on [" + mQueueName + "] to registered "
                             + target + ": " + r);
                     deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                 }
                 addBroadcastToHistoryLocked(r);
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                         + mQueueName + "] " + r);
             }
 
@@ -579,11 +574,9 @@
             // broadcast, then do nothing at this point.  Just in case, we
             // check that the process we're waiting for still exists.
             if (mPendingBroadcast != null) {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    Slog.v(TAG, "processNextBroadcast ["
-                            + mQueueName + "]: waiting for "
-                            + mPendingBroadcast.curApp);
-                }
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                        "processNextBroadcast [" + mQueueName + "]: waiting for "
+                        + mPendingBroadcast.curApp);
 
                 boolean isDead;
                 synchronized (mService.mPidsSelfLocked) {
@@ -649,7 +642,7 @@
                 }
 
                 if (r.state != BroadcastRecord.IDLE) {
-                    if (DEBUG_BROADCAST) Slog.d(TAG,
+                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                             "processNextBroadcast("
                             + mQueueName + ") called when not idle (state="
                             + r.state + ")");
@@ -662,12 +655,9 @@
                     // result if requested...
                     if (r.resultTo != null) {
                         try {
-                            if (DEBUG_BROADCAST) {
-                                int seq = r.intent.getIntExtra("seq", -1);
-                                Slog.i(TAG, "Finishing broadcast ["
-                                        + mQueueName + "] " + r.intent.getAction()
-                                        + " seq=" + seq + " app=" + r.callerApp);
-                            }
+                            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
+                                    "Finishing broadcast [" + mQueueName + "] "
+                                    + r.intent.getAction() + " app=" + r.callerApp);
                             performReceiveLocked(r.callerApp, r.resultTo,
                                 new Intent(r.intent), r.resultCode,
                                 r.resultData, r.resultExtras, false, false, r.userId);
@@ -682,11 +672,11 @@
                         }
                     }
 
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                     cancelBroadcastTimeoutLocked();
 
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
-                            + r);
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
+                            "Finished with ordered broadcast " + r);
 
                     // ... and on to the next...
                     addBroadcastToHistoryLocked(r);
@@ -706,12 +696,12 @@
             if (recIdx == 0) {
                 r.dispatchTime = r.receiverTime;
                 r.dispatchClockTime = System.currentTimeMillis();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
                         + mQueueName + "] " + r);
             }
             if (! mPendingBroadcastTimeoutMessage) {
                 long timeoutTime = r.receiverTime + mTimeoutPeriod;
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "Submitting BROADCAST_TIMEOUT_MSG ["
                         + mQueueName + "] for " + r + " at " + timeoutTime);
                 setBroadcastTimeoutLocked(timeoutTime);
@@ -722,7 +712,7 @@
                 // Simple case: this is a registered receiver who gets
                 // a direct call.
                 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Delivering ordered ["
                         + mQueueName + "] to registered "
                         + filter + ": " + r);
@@ -730,7 +720,7 @@
                 if (r.receiver == null || !r.ordered) {
                     // The receiver has already finished, so schedule to
                     // process the next one.
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                             + mQueueName + "]: ordered="
                             + r.ordered + " receiver=" + r.receiver);
                     r.state = BroadcastRecord.IDLE;
@@ -793,7 +783,7 @@
                 int mode = mService.mAppOpsService.noteOperation(r.appOp,
                         info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
                 if (mode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                             "App op " + r.appOp + " not allowed for broadcast to uid "
                             + info.activityInfo.applicationInfo.uid + " pkg "
                             + info.activityInfo.packageName);
@@ -842,19 +832,18 @@
                             + info.activityInfo.packageName, e);
                 }
                 if (!isAvailable) {
-                    if (DEBUG_BROADCAST) {
-                        Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
-                                + " / " + info.activityInfo.applicationInfo.uid
-                                + " : package no longer available");
-                    }
+                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
+                            "Skipping delivery to " + info.activityInfo.packageName + " / "
+                            + info.activityInfo.applicationInfo.uid
+                            + " : package no longer available");
                     skip = true;
                 }
             }
 
             if (skip) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping delivery of ordered ["
-                        + mQueueName + "] " + r + " for whatever reason");
+                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
+                        "Skipping delivery of ordered [" + mQueueName + "] "
+                        + r + " for whatever reason");
                 r.receiver = null;
                 r.curFilter = null;
                 r.state = BroadcastRecord.IDLE;
@@ -922,7 +911,7 @@
             }
 
             // Not running -- get it started, to be executed when the app comes up.
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
+            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                     "Need to start app ["
                     + mQueueName + "] " + targetProcess + " for broadcast " + r);
             if ((r.curApp=mService.startProcessLocked(targetProcess,
@@ -997,7 +986,7 @@
                 // broadcast timeout message after each receiver finishes.  Instead, we set up
                 // an initial timeout then kick it down the road a little further as needed
                 // when it expires.
-                if (DEBUG_BROADCAST) Slog.v(TAG,
+                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                         "Premature timeout ["
                         + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
                         + timeoutTime);
@@ -1012,7 +1001,7 @@
             // for started services to finish as well before going on.  So if we have actually
             // waited long enough time timeout the broadcast, let's give up on the whole thing
             // and just move on to the next.
-            Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+            Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
                     ? br.curComponent.flattenToShortString() : "(null)"));
             br.curComponent = null;
             br.state = BroadcastRecord.IDLE;
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index b2cfd7a..9a4d7a0 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -52,6 +52,7 @@
     final int appOp;        // an app op that is associated with this broadcast
     final List receivers;   // contains BroadcastFilter and ResolveInfo
     IIntentReceiver resultTo; // who receives final result if non-null
+    long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
     long dispatchClockTime; // the clock time the dispatch started
     long receiverTime;      // when current receiver started for timeouts.
@@ -102,7 +103,9 @@
             pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission);
                     pw.print("  appOp="); pw.println(appOp);
         }
-        pw.print(prefix); pw.print("dispatchClockTime=");
+        pw.print(prefix); pw.print("enqueueClockTime=");
+                pw.print(new Date(enqueueClockTime));
+                pw.print(" dispatchClockTime=");
                 pw.println(new Date(dispatchClockTime));
         pw.print(prefix); pw.print("dispatchTime=");
                 TimeUtils.formatDuration(dispatchTime, now, pw);
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index ec500c2..ce63d75 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.*;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -43,7 +45,7 @@
 import android.util.Xml;
 
 public final class CompatModePackages {
-    private final String TAG = ActivityManagerService.TAG;
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
     private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
 
     private final ActivityManagerService mService;
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index d1682b8..9dd07a9 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -21,9 +21,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
-
 import java.util.HashMap;
 import java.util.Map;
 
diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java
new file mode 100644
index 0000000..a8b639e
--- /dev/null
+++ b/services/core/java/com/android/server/am/DumpHeapProvider.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class DumpHeapProvider extends ContentProvider {
+    static final Object sLock = new Object();
+    static File sHeapDumpJavaFile;
+
+    static public File getJavaFile() {
+        synchronized (sLock) {
+            return sHeapDumpJavaFile;
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        synchronized (sLock) {
+            File dataDir = Environment.getDataDirectory();
+            File systemDir = new File(dataDir, "system");
+            File heapdumpDir = new File(systemDir, "heapdump");
+            heapdumpDir.mkdir();
+            sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin");
+        }
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "application/octet-stream";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        synchronized (sLock) {
+            String path = uri.getEncodedPath();
+            final String tag = Uri.decode(path);
+            if (tag.equals("/java")) {
+                return ParcelFileDescriptor.open(sHeapDumpJavaFile,
+                        ParcelFileDescriptor.MODE_READ_ONLY);
+            } else {
+                throw new FileNotFoundException("Invalid path for " + uri);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index c376744..9a645df 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -95,3 +95,11 @@
 
 # Home Stack brought to front or rear
 30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3)
+
+# Running pre boot receiver
+30045 am_pre_boot (User|1|5),(Package|3)
+
+# Report collection of global memory state
+30046 am_meminfo (CachedKb|2|2),(FreeKb|2|2),(ZramKb|2|2),(KernelKb|2|2),(NativeKb|2|2)
+# Report collection of memory used by a process
+30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(PssKb|2|2),(UssKb|2|2)
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index b3777ed..afde322 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
@@ -44,15 +45,20 @@
         mHandler = new H();
     }
 
-    public void showToast(boolean isLocked) {
-        mHandler.obtainMessage(H.SHOW_TOAST, isLocked ? 1 : 0, 0 /* Not used */).sendToTarget();
+    public void showToast(int lockTaskModeState) {
+        mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget();
     }
 
-    public void handleShowToast(boolean isLocked) {
-        String text = mContext.getString(isLocked
-                ? R.string.lock_to_app_toast_locked : R.string.lock_to_app_toast);
-        if (!isLocked && mAccessibilityManager.isEnabled()) {
-            text = mContext.getString(R.string.lock_to_app_toast_accessible);
+    public void handleShowToast(int lockTaskModeState) {
+        String text = null;
+        if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
+            text = mContext.getString(R.string.lock_to_app_toast_locked);
+        } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
+            text = mContext.getString(mAccessibilityManager.isEnabled()
+                    ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast);
+        }
+        if (text == null) {
+            return;
         }
         if (mLastToast != null) {
             mLastToast.cancel();
@@ -83,7 +89,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case SHOW_TOAST:
-                    handleShowToast(msg.arg1 != 0);
+                    handleShowToast(msg.arg1);
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ffaa03d..7f2cae4 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.app.ActivityManager;
 import android.app.IActivityContainer;
 import android.content.IIntentSender;
@@ -29,10 +32,14 @@
 import android.os.UserHandle;
 import android.util.Slog;
 
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 
 final class PendingIntentRecord extends IIntentSender.Stub {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
+
     final ActivityManagerService owner;
     final Key key;
     final int uid;
@@ -43,7 +50,7 @@
     String stringName;
     String lastTagPrefix;
     String lastTag;
-    
+
     final static class Key {
         final int type;
         final String packageName;
@@ -201,6 +208,13 @@
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
         synchronized(owner) {
+            final ActivityContainer activityContainer = (ActivityContainer)container;
+            if (activityContainer != null && activityContainer.mParentActivity != null &&
+                    activityContainer.mParentActivity.state
+                            != ActivityStack.ActivityState.RESUMED) {
+                // Cannot start a child activity if the parent is not resumed.
+                return ActivityManager.START_CANCELED;
+            }
             if (!canceled) {
                 sent = true;
                 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
@@ -257,13 +271,14 @@
                                         options, userId, container, null);
                             }
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startActivity intent", e);
+                            Slog.w(TAG, "Unable to send startActivity intent", e);
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
-                        key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
-                                key.who, key.requestCode, code, finalIntent);
+                        if (key.activity.task.stack != null) {
+                            key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
+                                    key.who, key.requestCode, code, finalIntent);
+                        }
                         break;
                     case ActivityManager.INTENT_SENDER_BROADCAST:
                         try {
@@ -277,8 +292,7 @@
                                 sendFinish = false;
                             }
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startActivity intent", e);
+                            Slog.w(TAG, "Unable to send startActivity intent", e);
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_SERVICE:
@@ -286,12 +300,11 @@
                             owner.startServiceInPackage(uid,
                                     finalIntent, resolvedType, userId);
                         } catch (RuntimeException e) {
-                            Slog.w(ActivityManagerService.TAG,
-                                    "Unable to send startService intent", e);
+                            Slog.w(TAG, "Unable to send startService intent", e);
                         }
                         break;
                 }
-                
+
                 if (sendFinish) {
                     try {
                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c380160..c7aa94c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
@@ -38,6 +41,8 @@
  * Activity manager code dealing with processes.
  */
 final class ProcessList {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
+
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
     static final int MIN_CRASH_INTERVAL = 60*1000;
@@ -633,8 +638,7 @@
                         LocalSocketAddress.Namespace.RESERVED));
             sLmkdOutputStream = sLmkdSocket.getOutputStream();
         } catch (IOException ex) {
-            Slog.w(ActivityManagerService.TAG,
-                   "lowmemorykiller daemon socket open failed");
+            Slog.w(TAG, "lowmemorykiller daemon socket open failed");
             sLmkdSocket = null;
             return false;
         }
@@ -659,8 +663,7 @@
                 sLmkdOutputStream.write(buf.array(), 0, buf.position());
                 return;
             } catch (IOException ex) {
-                Slog.w(ActivityManagerService.TAG,
-                       "Error writing to lowmemorykiller socket");
+                Slog.w(TAG, "Error writing to lowmemorykiller socket");
 
                 try {
                     sLmkdSocket.close();
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index a6c616a..7cf3b51 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -16,7 +16,11 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.EventLog;
 import android.util.Slog;
 import com.android.internal.app.ProcessStats;
@@ -48,6 +52,8 @@
  * is currently running.
  */
 final class ProcessRecord {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
+
     private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
     final boolean isolated;     // true if this is a special isolated process
@@ -248,8 +254,9 @@
                 pw.println();
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.print(lruSeq);
-                pw.print(" lastPss="); pw.print(lastPss);
-                pw.print(" lastCachedPss="); pw.println(lastCachedPss);
+                pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+                pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+                pw.println();
         pw.print(prefix); pw.print("cached="); pw.print(cached);
                 pw.print(" empty="); pw.println(empty);
         if (serviceb) {
@@ -470,7 +477,7 @@
         }
         return false;
     }
-    
+
     public void stopFreezingAllLocked() {
         int i = activities.size();
         while (i > 0) {
@@ -478,7 +485,7 @@
             activities.get(i).stopFreezingScreenLocked(true);
         }
     }
-    
+
     public void unlinkDeathRecipient() {
         if (deathRecipient != null && thread != null) {
             thread.asBinder().unlinkToDeath(deathRecipient, 0);
@@ -522,8 +529,7 @@
     void kill(String reason, boolean noisy) {
         if (!killedByAm) {
             if (noisy) {
-                Slog.i(ActivityManagerService.TAG, "Killing " + toShortString() + " (adj " + setAdj
-                        + "): " + reason);
+                Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason);
             }
             EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
             Process.killProcessQuiet(pid);
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 55aec65..9634dff 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -445,14 +445,14 @@
         mAm.mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
         Parcel current = Parcel.obtain();
+        synchronized (mAm) {
+            long now = SystemClock.uptimeMillis();
+            mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+            mProcessStats.mTimePeriodEndUptime = now;
+            mProcessStats.writeToParcel(current, now, 0);
+        }
         mWriteLock.lock();
         try {
-            synchronized (mAm) {
-                long now = SystemClock.uptimeMillis();
-                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-                mProcessStats.mTimePeriodEndUptime = now;
-                mProcessStats.writeToParcel(current, now, 0);
-            }
             if (historic != null) {
                 ArrayList<String> files = getCommittedFiles(0, false, true);
                 if (files != null) {
@@ -476,18 +476,18 @@
     public ParcelFileDescriptor getStatsOverTime(long minTime) {
         mAm.mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+        Parcel current = Parcel.obtain();
+        long curTime;
+        synchronized (mAm) {
+            long now = SystemClock.uptimeMillis();
+            mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+            mProcessStats.mTimePeriodEndUptime = now;
+            mProcessStats.writeToParcel(current, now, 0);
+            curTime = mProcessStats.mTimePeriodEndRealtime
+                    - mProcessStats.mTimePeriodStartRealtime;
+        }
         mWriteLock.lock();
         try {
-            Parcel current = Parcel.obtain();
-            long curTime;
-            synchronized (mAm) {
-                long now = SystemClock.uptimeMillis();
-                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
-                mProcessStats.mTimePeriodEndUptime = now;
-                mProcessStats.writeToParcel(current, now, 0);
-                curTime = mProcessStats.mTimePeriodEndRealtime
-                        - mProcessStats.mTimePeriodStartRealtime;
-            }
             if (curTime < minTime) {
                 // Need to add in older stats to reach desired time.
                 ArrayList<String> files = getCommittedFiles(0, false, true);
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
new file mode 100644
index 0000000..04912d0
--- /dev/null
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -0,0 +1,579 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * Class for managing the recent tasks list.
+ */
+class RecentTasks extends ArrayList<TaskRecord> {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
+
+    // Maximum number recent bitmaps to keep in memory.
+    private static final int MAX_RECENT_BITMAPS = 3;
+
+    // Activity manager service.
+    private final ActivityManagerService mService;
+
+    // Mainly to avoid object recreation on multiple calls.
+    private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
+    private final HashMap<ComponentName, ActivityInfo> tmpAvailActCache = new HashMap<>();
+    private final HashMap<String, ApplicationInfo> tmpAvailAppCache = new HashMap<>();
+    private final ActivityInfo tmpActivityInfo = new ActivityInfo();
+    private final ApplicationInfo tmpAppInfo = new ApplicationInfo();
+
+    RecentTasks(ActivityManagerService service) {
+        mService = service;
+    }
+
+    TaskRecord taskForIdLocked(int id) {
+        final int recentsCount = size();
+        for (int i = 0; i < recentsCount; i++) {
+            TaskRecord tr = get(i);
+            if (tr.taskId == id) {
+                return tr;
+            }
+        }
+        return null;
+    }
+
+    /** Remove recent tasks for a user. */
+    void removeTasksForUserLocked(int userId) {
+        if(userId <= 0) {
+            Slog.i(TAG, "Can't remove recent task on user " + userId);
+            return;
+        }
+
+        for (int i = size() - 1; i >= 0; --i) {
+            TaskRecord tr = get(i);
+            if (tr.userId == userId) {
+                if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
+                        + " when finishing user" + userId);
+                remove(i);
+                tr.removedFromRecents();
+            }
+        }
+
+        // Remove tasks from persistent storage.
+        mService.notifyTaskPersisterLocked(null, true);
+    }
+
+    /**
+     * Update the recent tasks lists: make sure tasks should still be here (their
+     * applications / activities still exist), update their availability, fix-up ordering
+     * of affiliations.
+     */
+    void cleanupLocked(int userId) {
+        int recentsCount = size();
+        if (recentsCount == 0) {
+            // Happens when called from the packagemanager broadcast before boot,
+            // or just any empty list.
+            return;
+        }
+
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        final int[] users = (userId == UserHandle.USER_ALL)
+                ? mService.getUsersLocked() : new int[] { userId };
+        for (int userIdx = 0; userIdx < users.length; userIdx++) {
+            final int user = users[userIdx];
+            recentsCount = size() - 1;
+            for (int i = recentsCount; i >= 0; i--) {
+                TaskRecord task = get(i);
+                if (task.userId != user) {
+                    // Only look at tasks for the user ID of interest.
+                    continue;
+                }
+                if (task.autoRemoveRecents && task.getTopActivity() == null) {
+                    // This situation is broken, and we should just get rid of it now.
+                    remove(i);
+                    task.removedFromRecents();
+                    Slog.w(TAG, "Removing auto-remove without activity: " + task);
+                    continue;
+                }
+                // Check whether this activity is currently available.
+                if (task.realActivity != null) {
+                    ActivityInfo ai = tmpAvailActCache.get(task.realActivity);
+                    if (ai == null) {
+                        try {
+                            ai = pm.getActivityInfo(task.realActivity,
+                                    PackageManager.GET_UNINSTALLED_PACKAGES
+                                            | PackageManager.GET_DISABLED_COMPONENTS, user);
+                        } catch (RemoteException e) {
+                            // Will never happen.
+                            continue;
+                        }
+                        if (ai == null) {
+                            ai = tmpActivityInfo;
+                        }
+                        tmpAvailActCache.put(task.realActivity, ai);
+                    }
+                    if (ai == tmpActivityInfo) {
+                        // This could be either because the activity no longer exists, or the
+                        // app is temporarily gone.  For the former we want to remove the recents
+                        // entry; for the latter we want to mark it as unavailable.
+                        ApplicationInfo app = tmpAvailAppCache.get(task.realActivity.getPackageName());
+                        if (app == null) {
+                            try {
+                                app = pm.getApplicationInfo(task.realActivity.getPackageName(),
+                                        PackageManager.GET_UNINSTALLED_PACKAGES
+                                                | PackageManager.GET_DISABLED_COMPONENTS, user);
+                            } catch (RemoteException e) {
+                                // Will never happen.
+                                continue;
+                            }
+                            if (app == null) {
+                                app = tmpAppInfo;
+                            }
+                            tmpAvailAppCache.put(task.realActivity.getPackageName(), app);
+                        }
+                        if (app == tmpAppInfo || (app.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                            // Doesn't exist any more!  Good-bye.
+                            remove(i);
+                            task.removedFromRecents();
+                            Slog.w(TAG, "Removing no longer valid recent: " + task);
+                            continue;
+                        } else {
+                            // Otherwise just not available for now.
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                                    "Making recent unavailable: " + task);
+                            task.isAvailable = false;
+                        }
+                    } else {
+                        if (!ai.enabled || !ai.applicationInfo.enabled
+                                || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                                    "Making recent unavailable: " + task
+                                    + " (enabled=" + ai.enabled + "/" + ai.applicationInfo.enabled
+                                    + " flags=" + Integer.toHexString(ai.applicationInfo.flags)
+                                    + ")");
+                            task.isAvailable = false;
+                        } else {
+                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG,
+                                    "Making recent available: " + task);
+                            task.isAvailable = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Verify the affiliate chain for each task.
+        int i = 0;
+        recentsCount = size();
+        while (i < recentsCount) {
+            i = processNextAffiliateChainLocked(i);
+        }
+        // recent tasks are now in sorted, affiliated order.
+    }
+
+    private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
+        int recentsCount = size();
+        TaskRecord top = task;
+        int topIndex = taskIndex;
+        while (top.mNextAffiliate != null && topIndex > 0) {
+            top = top.mNextAffiliate;
+            topIndex--;
+        }
+        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at "
+                + topIndex + " from intial " + taskIndex);
+        // Find the end of the chain, doing a sanity check along the way.
+        boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
+        int endIndex = topIndex;
+        TaskRecord prev = top;
+        while (endIndex < recentsCount) {
+            TaskRecord cur = get(endIndex);
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @"
+                    + endIndex + " " + cur);
+            if (cur == top) {
+                // Verify start of the chain.
+                if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) {
+                    Slog.wtf(TAG, "Bad chain @" + endIndex
+                            + ": first task has next affiliate: " + prev);
+                    sane = false;
+                    break;
+                }
+            } else {
+                // Verify middle of the chain's next points back to the one before.
+                if (cur.mNextAffiliate != prev
+                        || cur.mNextAffiliateTaskId != prev.taskId) {
+                    Slog.wtf(TAG, "Bad chain @" + endIndex
+                            + ": middle task " + cur + " @" + endIndex
+                            + " has bad next affiliate "
+                            + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId
+                            + ", expected " + prev);
+                    sane = false;
+                    break;
+                }
+            }
+            if (cur.mPrevAffiliateTaskId == INVALID_TASK_ID) {
+                // Chain ends here.
+                if (cur.mPrevAffiliate != null) {
+                    Slog.wtf(TAG, "Bad chain @" + endIndex
+                            + ": last task " + cur + " has previous affiliate "
+                            + cur.mPrevAffiliate);
+                    sane = false;
+                }
+                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex);
+                break;
+            } else {
+                // Verify middle of the chain's prev points to a valid item.
+                if (cur.mPrevAffiliate == null) {
+                    Slog.wtf(TAG, "Bad chain @" + endIndex
+                            + ": task " + cur + " has previous affiliate "
+                            + cur.mPrevAffiliate + " but should be id "
+                            + cur.mPrevAffiliate);
+                    sane = false;
+                    break;
+                }
+            }
+            if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) {
+                Slog.wtf(TAG, "Bad chain @" + endIndex
+                        + ": task " + cur + " has affiliated id "
+                        + cur.mAffiliatedTaskId + " but should be "
+                        + task.mAffiliatedTaskId);
+                sane = false;
+                break;
+            }
+            prev = cur;
+            endIndex++;
+            if (endIndex >= recentsCount) {
+                Slog.wtf(TAG, "Bad chain ran off index " + endIndex
+                        + ": last task " + prev);
+                sane = false;
+                break;
+            }
+        }
+        if (sane) {
+            if (endIndex < taskIndex) {
+                Slog.wtf(TAG, "Bad chain @" + endIndex
+                        + ": did not extend to task " + task + " @" + taskIndex);
+                sane = false;
+            }
+        }
+        if (sane) {
+            // All looks good, we can just move all of the affiliated tasks
+            // to the top.
+            for (int i=topIndex; i<=endIndex; i++) {
+                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task
+                        + " from " + i + " to " + (i-topIndex));
+                TaskRecord cur = remove(i);
+                add(i - topIndex, cur);
+            }
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks  " +  topIndex
+                    + " to " + endIndex);
+            return true;
+        }
+
+        // Whoops, couldn't do it.
+        return false;
+    }
+
+    final void addLocked(TaskRecord task) {
+        final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId
+                || task.mNextAffiliateTaskId != INVALID_TASK_ID
+                || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
+
+        int recentsCount = size();
+        // Quick case: never add voice sessions.
+        if (task.voiceSession != null) {
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task);
+            return;
+        }
+        // Another quick case: check if the top-most recent task is the same.
+        if (!isAffiliated && recentsCount > 0 && get(0) == task) {
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task);
+            return;
+        }
+        // Another quick case: check if this is part of a set of affiliated
+        // tasks that are at the top.
+        if (isAffiliated && recentsCount > 0 && task.inRecents
+                && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) {
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + get(0)
+                    + " at top when adding " + task);
+            return;
+        }
+
+        boolean needAffiliationFix = false;
+
+        // Slightly less quick case: the task is already in recents, so all we need
+        // to do is move it.
+        if (task.inRecents) {
+            int taskIndex = indexOf(task);
+            if (taskIndex >= 0) {
+                if (!isAffiliated) {
+                    // Simple case: this is not an affiliated task, so we just move it to the front.
+                    remove(taskIndex);
+                    add(0, task);
+                    mService.notifyTaskPersisterLocked(task, false);
+                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task
+                            + " from " + taskIndex);
+                    return;
+                } else {
+                    // More complicated: need to keep all affiliated tasks together.
+                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
+                        // All went well.
+                        return;
+                    }
+
+                    // Uh oh...  something bad in the affiliation chain, try to rebuild
+                    // everything and then go through our general path of adding a new task.
+                    needAffiliationFix = true;
+                }
+            } else {
+                Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
+                needAffiliationFix = true;
+            }
+        }
+
+        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
+        trimForTaskLocked(task, true);
+
+        recentsCount = size();
+        final int maxRecents = ActivityManager.getMaxRecentTasksStatic();
+        while (recentsCount >= maxRecents) {
+            final TaskRecord tr = remove(recentsCount - 1);
+            tr.removedFromRecents();
+            recentsCount--;
+        }
+        task.inRecents = true;
+        if (!isAffiliated || needAffiliationFix) {
+            // If this is a simple non-affiliated task, or we had some failure trying to
+            // handle it as part of an affilated task, then just place it at the top.
+            add(0, task);
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task);
+        } else if (isAffiliated) {
+            // If this is a new affiliated task, then move all of the affiliated tasks
+            // to the front and insert this new one.
+            TaskRecord other = task.mNextAffiliate;
+            if (other == null) {
+                other = task.mPrevAffiliate;
+            }
+            if (other != null) {
+                int otherIndex = indexOf(other);
+                if (otherIndex >= 0) {
+                    // Insert new task at appropriate location.
+                    int taskIndex;
+                    if (other == task.mNextAffiliate) {
+                        // We found the index of our next affiliation, which is who is
+                        // before us in the list, so add after that point.
+                        taskIndex = otherIndex+1;
+                    } else {
+                        // We found the index of our previous affiliation, which is who is
+                        // after us in the list, so add at their position.
+                        taskIndex = otherIndex;
+                    }
+                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at "
+                            + taskIndex + ": " + task);
+                    add(taskIndex, task);
+
+                    // Now move everything to the front.
+                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
+                        // All went well.
+                        return;
+                    }
+
+                    // Uh oh...  something bad in the affiliation chain, try to rebuild
+                    // everything and then go through our general path of adding a new task.
+                    needAffiliationFix = true;
+                } else {
+                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation "
+                            + other);
+                    needAffiliationFix = true;
+                }
+            } else {
+                if (DEBUG_RECENTS) Slog.d(TAG,
+                        "addRecent: adding affiliated task without next/prev:" + task);
+                needAffiliationFix = true;
+            }
+        }
+
+        if (needAffiliationFix) {
+            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations");
+            cleanupLocked(task.userId);
+        }
+    }
+
+    /**
+     * If needed, remove oldest existing entries in recents that are for the same kind
+     * of task as the given one.
+     */
+    int trimForTaskLocked(TaskRecord task, boolean doTrim) {
+        int recentsCount = size();
+        final Intent intent = task.intent;
+        final boolean document = intent != null && intent.isDocument();
+
+        int maxRecents = task.maxRecents - 1;
+        for (int i = 0; i < recentsCount; i++) {
+            final TaskRecord tr = get(i);
+            if (task != tr) {
+                if (task.userId != tr.userId) {
+                    continue;
+                }
+                if (i > MAX_RECENT_BITMAPS) {
+                    tr.freeLastThumbnail();
+                }
+                final Intent trIntent = tr.intent;
+                if ((task.affinity == null || !task.affinity.equals(tr.affinity)) &&
+                        (intent == null || !intent.filterEquals(trIntent))) {
+                    continue;
+                }
+                final boolean trIsDocument = trIntent != null && trIntent.isDocument();
+                if (document && trIsDocument) {
+                    // These are the same document activity (not necessarily the same doc).
+                    if (maxRecents > 0) {
+                        --maxRecents;
+                        continue;
+                    }
+                    // Hit the maximum number of documents for this task. Fall through
+                    // and remove this document from recents.
+                } else if (document || trIsDocument) {
+                    // Only one of these is a document. Not the droid we're looking for.
+                    continue;
+                }
+            }
+
+            if (!doTrim) {
+                // If the caller is not actually asking for a trim, just tell them we reached
+                // a point where the trim would happen.
+                return i;
+            }
+
+            // Either task and tr are the same or, their affinities match or their intents match
+            // and neither of them is a document, or they are documents using the same activity
+            // and their maxRecents has been reached.
+            tr.disposeThumbnail();
+            remove(i);
+            if (task != tr) {
+                tr.removedFromRecents();
+            }
+            i--;
+            recentsCount--;
+            if (task.intent == null) {
+                // If the new recent task we are adding is not fully
+                // specified, then replace it with the existing recent task.
+                task = tr;
+            }
+            mService.notifyTaskPersisterLocked(tr, false);
+        }
+
+        return -1;
+    }
+
+    // Sort by taskId
+    private static Comparator<TaskRecord> sTaskRecordComparator = new Comparator<TaskRecord>() {
+        @Override
+        public int compare(TaskRecord lhs, TaskRecord rhs) {
+            return rhs.taskId - lhs.taskId;
+        }
+    };
+
+    // Extract the affiliates of the chain containing recent at index start.
+    private int processNextAffiliateChainLocked(int start) {
+        final TaskRecord startTask = get(start);
+        final int affiliateId = startTask.mAffiliatedTaskId;
+
+        // Quick identification of isolated tasks. I.e. those not launched behind.
+        if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null &&
+                startTask.mNextAffiliate == null) {
+            // There is still a slim chance that there are other tasks that point to this task
+            // and that the chain is so messed up that this task no longer points to them but
+            // the gain of this optimization outweighs the risk.
+            startTask.inRecents = true;
+            return start + 1;
+        }
+
+        // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
+        mTmpRecents.clear();
+        for (int i = size() - 1; i >= start; --i) {
+            final TaskRecord task = get(i);
+            if (task.mAffiliatedTaskId == affiliateId) {
+                remove(i);
+                mTmpRecents.add(task);
+            }
+        }
+
+        // Sort them all by taskId. That is the order they were create in and that order will
+        // always be correct.
+        Collections.sort(mTmpRecents, sTaskRecordComparator);
+
+        // Go through and fix up the linked list.
+        // The first one is the end of the chain and has no next.
+        final TaskRecord first = mTmpRecents.get(0);
+        first.inRecents = true;
+        if (first.mNextAffiliate != null) {
+            Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
+            first.setNextAffiliate(null);
+            mService.notifyTaskPersisterLocked(first, false);
+        }
+        // Everything in the middle is doubly linked from next to prev.
+        final int tmpSize = mTmpRecents.size();
+        for (int i = 0; i < tmpSize - 1; ++i) {
+            final TaskRecord next = mTmpRecents.get(i);
+            final TaskRecord prev = mTmpRecents.get(i + 1);
+            if (next.mPrevAffiliate != prev) {
+                Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
+                        " setting prev=" + prev);
+                next.setPrevAffiliate(prev);
+                mService.notifyTaskPersisterLocked(next, false);
+            }
+            if (prev.mNextAffiliate != next) {
+                Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
+                        " setting next=" + next);
+                prev.setNextAffiliate(next);
+                mService.notifyTaskPersisterLocked(prev, false);
+            }
+            prev.inRecents = true;
+        }
+        // The last one is the beginning of the list and has no prev.
+        final TaskRecord last = mTmpRecents.get(tmpSize - 1);
+        if (last.mPrevAffiliate != null) {
+            Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
+            last.setPrevAffiliate(null);
+            mService.notifyTaskPersisterLocked(last, false);
+        }
+
+        // Insert the group back into mRecentTasks at start.
+        addAll(start, mTmpRecents);
+        mTmpRecents.clear();
+
+        // Let the caller know where we left off.
+        return start + tmpSize;
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 1cb1bb8..6c2e120 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -47,10 +47,15 @@
 import java.util.List;
 import java.util.Objects;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 /**
  * A running application service.
  */
 final class ServiceRecord extends Binder {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ServiceRecord" : TAG_AM;
+
     // Maximum number of delivery attempts before giving up.
     static final int MAX_DELIVERY_COUNT = 3;
 
@@ -487,8 +492,7 @@
                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
                                 outId, userId);
                     } catch (RuntimeException e) {
-                        Slog.w(ActivityManagerService.TAG,
-                                "Error showing notification for service", e);
+                        Slog.w(TAG, "Error showing notification for service", e);
                         // If it gave us a garbage notification, it doesn't
                         // get to be foreground.
                         ams.setServiceForeground(name, ServiceRecord.this,
@@ -517,8 +521,7 @@
                         inm.cancelNotificationWithTag(localPackageName, null,
                                 localForegroundId, userId);
                     } catch (RuntimeException e) {
-                        Slog.w(ActivityManagerService.TAG,
-                                "Error canceling notification for service", e);
+                        Slog.w(TAG, "Error canceling notification for service", e);
                     } catch (RemoteException e) {
                     }
                 }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 24c723f..318cd45 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -99,6 +99,7 @@
 
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
+    private final RecentTasks mRecentTasks;
 
     /** Value determines write delay mode as follows:
      *    < 0 We are Flushing. No delays between writes until the image queue is drained and all
@@ -140,7 +141,8 @@
     // tasks.
     private long mExpiredTasksCleanupTime = Long.MAX_VALUE;
 
-    TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
+    TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor,
+            RecentTasks recentTasks) {
         sTasksDir = new File(systemDir, TASKS_DIRNAME);
         if (!sTasksDir.exists()) {
             if (DEBUG_PERSISTER) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
@@ -161,12 +163,14 @@
 
         mStackSupervisor = stackSupervisor;
         mService = stackSupervisor.mService;
-
+        mRecentTasks = recentTasks;
         mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
     }
 
     void startPersisting() {
-        mLazyTaskWriterThread.start();
+        if (!mLazyTaskWriterThread.isAlive()) {
+            mLazyTaskWriterThread.start();
+        }
     }
 
     private void removeThumbnails(TaskRecord task) {
@@ -725,10 +729,9 @@
                     // {@link TaskRecord.mLastTimeMoved} and drop the oldest recent's vs. just
                     // adding to the back of the list.
                     int spaceLeft =
-                            ActivityManager.getMaxRecentTasksStatic()
-                            - mService.mRecentTasks.size();
+                            ActivityManager.getMaxRecentTasksStatic() - mRecentTasks.size();
                     if (spaceLeft >= tasks.size()) {
-                        mService.mRecentTasks.addAll(mService.mRecentTasks.size(), tasks);
+                        mRecentTasks.addAll(mRecentTasks.size(), tasks);
                         for (int k = tasks.size() - 1; k >= 0; k--) {
                             // Persist new tasks.
                             wakeup(tasks.get(k), false);
@@ -941,10 +944,9 @@
                     if (DEBUG_PERSISTER) Slog.d(TAG, "Looking for obsolete files.");
                     persistentTaskIds.clear();
                     synchronized (mService) {
-                        final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
-                        if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + tasks);
-                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                            final TaskRecord task = tasks.get(taskNdx);
+                        if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + mRecentTasks);
+                        for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                            final TaskRecord task = mRecentTasks.get(taskNdx);
                             if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: task=" + task +
                                     " persistable=" + task.isPersistable);
                             if ((task.isPersistable || task.inRecents)
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 60f8a48..d8d361b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,7 +16,8 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerService.TAG;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
@@ -54,6 +55,8 @@
 import java.util.ArrayList;
 
 final class TaskRecord {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+
     static final String ATTR_TASKID = "task_id";
     private static final String TAG_INTENT = "intent";
     private static final String TAG_AFFINITYINTENT = "affinity_intent";
@@ -79,6 +82,7 @@
     private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
     private static final String ATTR_CALLING_UID = "calling_uid";
     private static final String ATTR_CALLING_PACKAGE = "calling_package";
+    private static final String ATTR_RESIZEABLE = "resizeable";
 
     private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
 
@@ -109,10 +113,12 @@
 
     String stringName;      // caching of toString() result.
     int userId;             // user for which this task was created
-    int creatorUid;         // The app uid that originally created the task
 
     int numFullscreen;      // Number of fullscreen activities.
 
+    boolean mResizeable;    // Activities in the task resizeable. Based on the resizable setting of
+                            // the root activity.
+
     // This represents the last resolved activity values for this task
     // NOTE: This value needs to be persisted with each task
     TaskDescription lastTaskDescription = new TaskDescription();
@@ -176,7 +182,7 @@
         voiceSession = _voiceSession;
         voiceInteractor = _voiceInteractor;
         isAvailable = true;
-        mActivities = new ArrayList<ActivityRecord>();
+        mActivities = new ArrayList<>();
         setIntent(_intent, info);
     }
 
@@ -191,7 +197,7 @@
         voiceSession = null;
         voiceInteractor = null;
         isAvailable = true;
-        mActivities = new ArrayList<ActivityRecord>();
+        mActivities = new ArrayList<>();
         setIntent(_intent, info);
 
         taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -210,15 +216,15 @@
         mCallingPackage = info.packageName;
     }
 
-    TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
-            String _affinity, String _rootAffinity, ComponentName _realActivity,
-            ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents,
-            boolean _askedCompatMode, int _taskType, int _userId, int _effectiveUid,
-            String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
-            long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
-            TaskDescription _lastTaskDescription, int taskAffiliation,
-            int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid,
-            String callingPackage) {
+    private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
+            Intent _affinityIntent, String _affinity, String _rootAffinity,
+            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
+            boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
+            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
+            long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
+            boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
+            int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
+            int callingUid, String callingPackage, boolean resizeable) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -227,7 +233,7 @@
         intent = _intent;
         affinityIntent = _affinityIntent;
         affinity = _affinity;
-        rootAffinity = _affinity;
+        rootAffinity = _rootAffinity;
         voiceSession = null;
         voiceInteractor = null;
         realActivity = _realActivity;
@@ -253,6 +259,7 @@
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
+        mResizeable = resizeable;
     }
 
     void touchActiveTime() {
@@ -303,7 +310,7 @@
                     _intent.setSourceBounds(null);
                 }
             }
-            if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+            if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
                     "Setting Intent of " + this + " to " + _intent);
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
@@ -316,7 +323,7 @@
                 targetIntent.setComponent(targetComponent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
-                if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG,
+                if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
                         "Setting Intent of " + this + " to target " + targetIntent);
                 intent = targetIntent;
                 realActivity = targetComponent;
@@ -352,6 +359,7 @@
         } else {
             autoRemoveRecents = false;
         }
+        mResizeable = info.resizeable;
     }
 
     void setTaskToReturnTo(int taskToReturnTo) {
@@ -492,10 +500,12 @@
     }
 
     ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
-        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord r = mActivities.get(activityNdx);
-            if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
-                return r;
+        if (stack != null) {
+            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = mActivities.get(activityNdx);
+                if (!r.finishing && r != notTop && stack.okToShowLocked(r)) {
+                    return r;
+                }
             }
         }
         return null;
@@ -610,8 +620,8 @@
                 mActivities.remove(activityNdx);
                 --activityNdx;
                 --numActivities;
-            } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
-                    false)) {
+            } else if (stack.finishActivityLocked(
+                    r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
                 --activityNdx;
                 --numActivities;
             }
@@ -658,8 +668,8 @@
                     if (opts != null) {
                         ret.updateOptionsLocked(opts);
                     }
-                    if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear",
-                            false)) {
+                    if (stack != null && stack.finishActivityLocked(
+                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                         --activityNdx;
                         --numActivities;
                     }
@@ -671,8 +681,10 @@
                 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                         && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                     if (!ret.finishing) {
-                        stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null,
-                                "clear", false);
+                        if (stack != null) {
+                            stack.finishActivityLocked(
+                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
+                        }
                         return null;
                     }
                 }
@@ -850,6 +862,7 @@
         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
         out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+        out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
 
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
@@ -911,6 +924,7 @@
         int nextTaskId = INVALID_TASK_ID;
         int callingUid = -1;
         String callingPackage = "";
+        boolean resizeable = false;
 
         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
             final String attrName = in.getAttributeName(attrNdx);
@@ -964,6 +978,8 @@
                 callingUid = Integer.valueOf(attrValue);
             } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
                 callingPackage = attrValue;
+            } else if (ATTR_RESIZEABLE.equals(attrName)) {
+                resizeable = Boolean.valueOf(attrValue);
             } else {
                 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
             }
@@ -993,13 +1009,11 @@
                 }
             }
         }
-
         if (!hasRootAffinity) {
             rootAffinity = affinity;
         } else if ("@".equals(rootAffinity)) {
             rootAffinity = null;
         }
-
         if (effectiveUid <= 0) {
             Intent checkIntent = intent != null ? intent : affinityIntent;
             effectiveUid = 0;
@@ -1025,7 +1039,7 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage);
+                callingUid, callingPackage, resizeable);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
@@ -1121,6 +1135,7 @@
             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
         }
         pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
+                pw.print(" mResizeable="); pw.print(mResizeable);
                 pw.print(" firstActiveTime="); pw.print(lastActiveTime);
                 pw.print(" lastActiveTime="); pw.print(lastActiveTime);
                 pw.print(" (inactive for ");
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 650a837..6e371c1 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -19,7 +19,6 @@
 import android.content.Intent;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.server.am.ActivityManagerService.GrantUri;
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index ae83940..28344df 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -17,7 +17,6 @@
 package com.android.server.am;
 
 import android.content.Intent;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 36263ec..5a66f4a 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -19,6 +19,8 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -26,6 +28,7 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 
 /**
  * Dialog to show when a user switch it about to happen. The intent is to snapshot the screen
@@ -37,8 +40,14 @@
         implements ViewTreeObserver.OnWindowShownListener {
     private static final String TAG = "ActivityManagerUserSwitchingDialog";
 
+    // Time to wait for the onWindowShown() callback before continuing the user switch
+    private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
+
     private final ActivityManagerService mService;
     private final int mUserId;
+    private static final int MSG_START_USER = 1;
+    @GuardedBy("this")
+    private boolean mStartedUser;
 
     public UserSwitchingDialog(ActivityManagerService service, Context context,
             int userId, String userName, boolean aboveSystem) {
@@ -73,15 +82,40 @@
         if (decorView != null) {
             decorView.getViewTreeObserver().addOnWindowShownListener(this);
         }
+        // Add a timeout as a safeguard, in case a race in screen on/off causes the window
+        // callback to never come.
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER),
+                WINDOW_SHOWN_TIMEOUT_MS);
     }
 
     @Override
     public void onWindowShown() {
         // Slog.v(TAG, "onWindowShown called");
-        mService.startUserInForeground(mUserId, this);
-        final View decorView = getWindow().getDecorView();
-        if (decorView != null) {
-            decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+        startUser();
+    }
+
+    void startUser() {
+        synchronized (this) {
+            if (!mStartedUser) {
+                mService.startUserInForeground(mUserId, this);
+                mStartedUser = true;
+                final View decorView = getWindow().getDecorView();
+                if (decorView != null) {
+                    decorView.getViewTreeObserver().removeOnWindowShownListener(this);
+                }
+                mHandler.removeMessages(MSG_START_USER);
+            }
         }
     }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START_USER:
+                    startUser();
+                    break;
+            }
+        }
+    };
 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
new file mode 100644
index 0000000..83ecf91
--- /dev/null
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -0,0 +1,5910 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.audio;
+
+import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
+import static android.media.AudioManager.RINGER_MODE_NORMAL;
+import static android.media.AudioManager.RINGER_MODE_SILENT;
+import static android.media.AudioManager.RINGER_MODE_VIBRATE;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.database.ContentObserver;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPlaybackClient;
+import android.hardware.hdmi.HdmiTvClient;
+import android.hardware.usb.UsbManager;
+import android.media.AudioAttributes;
+import android.media.AudioDevicePort;
+import android.media.AudioSystem;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPort;
+import android.media.AudioRoutesInfo;
+import android.media.IAudioFocusDispatcher;
+import android.media.IAudioRoutesObserver;
+import android.media.IAudioService;
+import android.media.IRemoteControlDisplay;
+import android.media.IRingtonePlayer;
+import android.media.IVolumeController;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.media.VolumePolicy;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.audiopolicy.AudioPolicy;
+import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.audiopolicy.IAudioPolicyCallback;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.provider.Settings.System;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.util.XmlUtils;
+import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * The implementation of the volume manager service.
+ * <p>
+ * This implementation focuses on delivering a responsive UI. Most methods are
+ * asynchronous to external calls. For example, the task of setting a volume
+ * will update our internal state, but in a separate thread will set the system
+ * volume and later persist to the database. Similarly, setting the ringer mode
+ * will update the state and broadcast a change and in a separate thread later
+ * persist the ringer mode.
+ *
+ * @hide
+ */
+public class AudioService extends IAudioService.Stub {
+
+    private static final String TAG = "AudioService";
+
+    /** Debug audio mode */
+    protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
+
+    /** Debug audio policy feature */
+    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
+
+    /** Debug volumes */
+    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
+
+    /** debug calls to devices APIs */
+    protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
+
+    /** How long to delay before persisting a change in volume/ringer mode. */
+    private static final int PERSIST_DELAY = 500;
+
+    /** How long to delay after a volume down event before unmuting a stream */
+    private static final int UNMUTE_STREAM_DELAY = 350;
+
+    /**
+     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
+     */
+    private static final int FLAG_ADJUST_VOLUME = 1;
+
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final AppOpsManager mAppOps;
+
+    // the platform type affects volume and silent mode behavior
+    private final int mPlatformType;
+
+    private boolean isPlatformVoice() {
+        return mPlatformType == AudioSystem.PLATFORM_VOICE;
+    }
+
+    private boolean isPlatformTelevision() {
+        return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
+    }
+
+    /** The controller for the volume UI. */
+    private final VolumeController mVolumeController = new VolumeController();
+    private final ControllerService mControllerService = new ControllerService();
+
+    // sendMsg() flags
+    /** 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. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    // AudioHandler messages
+    private static final int MSG_SET_DEVICE_VOLUME = 0;
+    private static final int MSG_PERSIST_VOLUME = 1;
+    private static final int MSG_PERSIST_RINGER_MODE = 3;
+    private static final int MSG_MEDIA_SERVER_DIED = 4;
+    private static final int MSG_PLAY_SOUND_EFFECT = 5;
+    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
+    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
+    private static final int MSG_SET_FORCE_USE = 8;
+    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
+    private static final int MSG_SET_ALL_VOLUMES = 10;
+    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
+    private static final int MSG_REPORT_NEW_ROUTES = 12;
+    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
+    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
+    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
+    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
+    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
+    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
+    private static final int MSG_SYSTEM_READY = 21;
+    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
+    private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
+    private static final int MSG_UNMUTE_STREAM = 24;
+    // start of messages handled under wakelock
+    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
+    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
+    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
+    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
+    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
+    // end of messages handled under wakelock
+
+    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
+    // Timeout for connection to bluetooth headset service
+    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
+
+    /** @see AudioSystemThread */
+    private AudioSystemThread mAudioSystemThread;
+    /** @see AudioHandler */
+    private AudioHandler mAudioHandler;
+    /** @see VolumeStreamState */
+    private VolumeStreamState[] mStreamStates;
+    private SettingsObserver mSettingsObserver;
+
+    private int mMode = AudioSystem.MODE_NORMAL;
+    // protects mRingerMode
+    private final Object mSettingsLock = new Object();
+
+    private SoundPool mSoundPool;
+    private final Object mSoundEffectsLock = new Object();
+    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
+
+    // Maximum volume adjust steps allowed in a single batch call.
+    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
+
+    /* Sound effect file names  */
+    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
+    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
+
+    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
+     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
+     * uses soundpool (second column) */
+    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
+
+   /** Maximum volume index values for audio streams */
+    private static int[] MAX_STREAM_VOLUME = new int[] {
+        5,  // STREAM_VOICE_CALL
+        7,  // STREAM_SYSTEM
+        7,  // STREAM_RING
+        15, // STREAM_MUSIC
+        7,  // STREAM_ALARM
+        7,  // STREAM_NOTIFICATION
+        15, // STREAM_BLUETOOTH_SCO
+        7,  // STREAM_SYSTEM_ENFORCED
+        15, // STREAM_DTMF
+        15  // STREAM_TTS
+    };
+
+    /** Minimum volume index values for audio streams */
+    private static int[] MIN_STREAM_VOLUME = new int[] {
+        1,  // STREAM_VOICE_CALL
+        0,  // STREAM_SYSTEM
+        0,  // STREAM_RING
+        0,  // STREAM_MUSIC
+        0,  // STREAM_ALARM
+        0,  // STREAM_NOTIFICATION
+        1,  // STREAM_BLUETOOTH_SCO
+        0,  // STREAM_SYSTEM_ENFORCED
+        0,  // STREAM_DTMF
+        0   // STREAM_TTS
+    };
+
+    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
+     * of another stream: This avoids multiplying the volume settings for hidden
+     * stream types that follow other stream behavior for volume settings
+     * NOTE: do not create loops in aliases!
+     * Some streams alias to different streams according to device category (phone or tablet) or
+     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
+     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
+     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
+     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
+    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
+        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
+        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
+        AudioSystem.STREAM_RING,            // STREAM_RING
+        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
+        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
+        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
+        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
+        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
+        AudioSystem.STREAM_RING,            // STREAM_DTMF
+        AudioSystem.STREAM_MUSIC            // STREAM_TTS
+    };
+    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
+        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
+        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
+        AudioSystem.STREAM_MUSIC,       // STREAM_RING
+        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
+        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
+        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
+        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
+        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
+        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
+        AudioSystem.STREAM_MUSIC        // STREAM_TTS
+    };
+    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
+        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
+        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
+        AudioSystem.STREAM_RING,            // STREAM_RING
+        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
+        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
+        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
+        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
+        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
+        AudioSystem.STREAM_RING,            // STREAM_DTMF
+        AudioSystem.STREAM_MUSIC            // STREAM_TTS
+    };
+    private int[] mStreamVolumeAlias;
+
+    /**
+     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
+     * after mapping through mStreamVolumeAlias.
+     */
+    private static final int[] STREAM_VOLUME_OPS = new int[] {
+        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
+        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
+        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
+        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
+        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
+        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
+    };
+
+    private final boolean mUseFixedVolume;
+
+    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
+        public void onError(int error) {
+            switch (error) {
+            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
+                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
+                        SENDMSG_NOOP, 0, 0, null, 0);
+                break;
+            default:
+                break;
+            }
+        }
+    };
+
+    /**
+     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
+     * {@link AudioManager#RINGER_MODE_SILENT}, or
+     * {@link AudioManager#RINGER_MODE_VIBRATE}.
+     */
+    // protected by mSettingsLock
+    private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
+    private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)
+
+    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
+    private int mRingerModeAffectedStreams = 0;
+
+    // Streams currently muted by ringer mode
+    private int mRingerModeMutedStreams;
+
+    /** Streams that can be muted. Do not resolve to aliases when checking.
+     * @see System#MUTE_STREAMS_AFFECTED */
+    private int mMuteAffectedStreams;
+
+    /**
+     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
+     * mVibrateSetting is just maintained during deprecation period but vibration policy is
+     * now only controlled by mHasVibrator and mRingerMode
+     */
+    private int mVibrateSetting;
+
+    // Is there a vibrator
+    private final boolean mHasVibrator;
+
+    // Broadcast receiver for device connections intent broadcasts
+    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
+
+    // Devices currently connected
+    // Use makeDeviceListKey() to make a unique key for this list.
+    private class DeviceListSpec {
+        int mDeviceType;
+        String mDeviceName;
+        String mDeviceAddress;
+
+        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+            mDeviceType = deviceType;
+            mDeviceName = deviceName;
+            mDeviceAddress = deviceAddress;
+        }
+
+        public String toString() {
+            return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
+                    + " address:" + mDeviceAddress + "]";
+        }
+    }
+
+    // Generate a unique key for the mConnectedDevices List by composing the device "type"
+    // and the "address" associated with a specific instance of that device type
+    private String makeDeviceListKey(int device, String deviceAddress) {
+        return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
+    }
+
+    private final HashMap<String, DeviceListSpec> mConnectedDevices =
+            new HashMap<String, DeviceListSpec>();
+
+    // Forced device usage for communications
+    private int mForcedUseForComm;
+
+    // List of binder death handlers for setMode() client processes.
+    // The last process to have called setMode() is at the top of the list.
+    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
+
+    // List of clients having issued a SCO start request
+    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
+
+    // BluetoothHeadset API to control SCO connection
+    private BluetoothHeadset mBluetoothHeadset;
+
+    // Bluetooth headset device
+    private BluetoothDevice mBluetoothHeadsetDevice;
+
+    // Indicate if SCO audio connection is currently active and if the initiator is
+    // audio service (internal) or bluetooth headset (external)
+    private int mScoAudioState;
+    // SCO audio state is not active
+    private static final int SCO_STATE_INACTIVE = 0;
+    // SCO audio activation request waiting for headset service to connect
+    private static final int SCO_STATE_ACTIVATE_REQ = 1;
+    // SCO audio state is active or starting due to a request from AudioManager API
+    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
+    // SCO audio deactivation request waiting for headset service to connect
+    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
+
+    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
+    // in call audio)
+    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
+    // Deactivation request for all SCO connections (initiated by audio mode change)
+    // waiting for headset service to connect
+    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
+
+    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
+    // originated from an app targeting an API version before JB MR2 and raw audio after that.
+    private int mScoAudioMode;
+    // SCO audio mode is undefined
+    private static final int SCO_MODE_UNDEFINED = -1;
+    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
+    private static final int SCO_MODE_VIRTUAL_CALL = 0;
+    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
+    private static final int SCO_MODE_RAW = 1;
+    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
+    private static final int SCO_MODE_VR = 2;
+
+    private static final int SCO_MODE_MAX = 2;
+
+    // Current connection state indicated by bluetooth headset
+    private int mScoConnectionState;
+
+    // true if boot sequence has been completed
+    private boolean mSystemReady;
+    // listener for SoundPool sample load completion indication
+    private SoundPoolCallback mSoundPoolCallBack;
+    // thread for SoundPool listener
+    private SoundPoolListenerThread mSoundPoolListenerThread;
+    // message looper for SoundPool listener
+    private Looper mSoundPoolLooper = null;
+    // volume applied to sound played with playSoundEffect()
+    private static int sSoundEffectVolumeDb;
+    // previous volume adjustment direction received by checkForRingerModeChange()
+    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
+    // Keyguard manager proxy
+    private KeyguardManager mKeyguardManager;
+    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
+    // is controlled by Vol keys.
+    private int  mVolumeControlStream = -1;
+    private final Object mForceControlStreamLock = new Object();
+    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
+    // server process so in theory it is not necessary to monitor the client death.
+    // However it is good to be ready for future evolutions.
+    private ForceControlStreamClient mForceControlStreamClient = null;
+    // Used to play ringtones outside system_server
+    private volatile IRingtonePlayer mRingtonePlayer;
+
+    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
+    private int mDeviceRotation = Surface.ROTATION_0;
+
+    // Request to override default use of A2DP for media.
+    private boolean mBluetoothA2dpEnabled;
+    private final Object mBluetoothA2dpEnabledLock = new Object();
+
+    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
+    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
+    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
+            = new RemoteCallbackList<IAudioRoutesObserver>();
+
+    // Devices for which the volume is fixed and VolumePanel slider should be disabled
+    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
+            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
+            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
+            AudioSystem.DEVICE_OUT_HDMI_ARC |
+            AudioSystem.DEVICE_OUT_SPDIF |
+            AudioSystem.DEVICE_OUT_AUX_LINE;
+    int mFullVolumeDevices = 0;
+
+    // TODO merge orientation and rotation
+    private final boolean mMonitorOrientation;
+    private final boolean mMonitorRotation;
+
+    private boolean mDockAudioMediaEnabled = true;
+
+    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+    // Used when safe volume warning message display is requested by setStreamVolume(). In this
+    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
+    // and used later when/if disableSafeMediaVolume() is called.
+    private StreamVolumeCommand mPendingVolumeCommand;
+
+    private PowerManager.WakeLock mAudioEventWakeLock;
+
+    private final MediaFocusControl mMediaFocusControl;
+
+    // Reference to BluetoothA2dp to query for AbsoluteVolume.
+    private BluetoothA2dp mA2dp;
+    // lock always taken synchronized on mConnectedDevices
+    private final Object mA2dpAvrcpLock = new Object();
+    // If absolute volume is supported in AVRCP device
+    private boolean mAvrcpAbsVolSupported = false;
+
+    private AudioOrientationEventListener mOrientationListener;
+
+    private static Long mLastDeviceConnectMsgTime = new Long(0);
+
+    private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
+    private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
+    private long mLoweredFromNormalToVibrateTime;
+
+    // Intent "extra" data keys.
+    public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
+    public static final String CONNECT_INTENT_KEY_STATE = "state";
+    public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
+    public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
+    public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
+    public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
+    public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
+
+    // Defines the format for the connection "address" for ALSA devices
+    public static String makeAlsaAddressString(int card, int device) {
+        return "card=" + card + ";device=" + device + ";";
+    }
+
+    private final String DEVICE_NAME_A2DP = "a2dp-device";
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Construction
+    ///////////////////////////////////////////////////////////////////////////
+
+    /** @hide */
+    public AudioService(Context context) {
+        mContext = context;
+        mContentResolver = context.getContentResolver();
+        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+
+        mPlatformType = AudioSystem.getPlatformType(context);
+
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
+
+        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
+
+        // Initialize volume
+        int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
+                MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
+        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
+            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
+            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
+        }
+        maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
+                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
+        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
+            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
+            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
+        }
+
+        sSoundEffectVolumeDb = context.getResources().getInteger(
+                com.android.internal.R.integer.config_soundEffectVolumeDb);
+
+        mForcedUseForComm = AudioSystem.FORCE_NONE;
+
+        createAudioSystemThread();
+
+        AudioSystem.setErrorCallback(mAudioSystemCallback);
+
+        boolean cameraSoundForced = readCameraSoundForced();
+        mCameraSoundForced = new Boolean(cameraSoundForced);
+        sendMsg(mAudioHandler,
+                MSG_SET_FORCE_USE,
+                SENDMSG_QUEUE,
+                AudioSystem.FOR_SYSTEM,
+                cameraSoundForced ?
+                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
+                null,
+                0);
+
+        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
+                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
+        // The default safe volume index read here will be replaced by the actual value when
+        // the mcc is read by onConfigureSafeVolume()
+        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+
+        mUseFixedVolume = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
+
+        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
+        // array initialized by updateStreamVolumeAlias()
+        updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
+        readPersistedSettings();
+        mSettingsObserver = new SettingsObserver();
+        createStreamStates();
+
+        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
+                mContext, mVolumeController, this);
+
+        readAndSetLowRamDevice();
+
+        // Call setRingerModeInt() to apply correct mute
+        // state on streams affected by ringer mode.
+        mRingerModeMutedStreams = 0;
+        setRingerModeInt(getRingerModeInternal(), false);
+
+        // Register for device connection intent broadcasts.
+        IntentFilter intentFilter =
+                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
+        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
+        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        // TODO merge orientation and rotation
+        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
+        if (mMonitorOrientation) {
+            Log.v(TAG, "monitoring device orientation");
+            // initialize orientation in AudioSystem
+            setOrientationForAudioSystem();
+        }
+        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
+        if (mMonitorRotation) {
+            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
+                    .getDefaultDisplay().getRotation();
+            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
+
+            mOrientationListener = new AudioOrientationEventListener(mContext);
+            mOrientationListener.enable();
+
+            // initialize rotation in AudioSystem
+            setRotationForAudioSystem();
+        }
+
+        context.registerReceiver(mReceiver, intentFilter);
+
+        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
+    }
+
+    public void systemReady() {
+        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
+                0, 0, null, 0);
+    }
+
+    public void onSystemReady() {
+        mSystemReady = true;
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
+                0, 0, null, 0);
+
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
+        resetBluetoothSco();
+        getBluetoothHeadset();
+        //FIXME: this is to maintain compatibility with deprecated intent
+        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
+                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        sendStickyBroadcastToAll(newIntent);
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+                                    BluetoothProfile.A2DP);
+        }
+
+        mHdmiManager =
+                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
+        if (mHdmiManager != null) {
+            synchronized (mHdmiManager) {
+                mHdmiTvClient = mHdmiManager.getTvClient();
+                if (mHdmiTvClient != null) {
+                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
+                }
+                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
+                mHdmiCecSink = false;
+            }
+        }
+
+        sendMsg(mAudioHandler,
+                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
+                SENDMSG_REPLACE,
+                0,
+                0,
+                TAG,
+                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
+
+        StreamOverride.init(mContext);
+        mControllerService.init();
+    }
+
+    private void createAudioSystemThread() {
+        mAudioSystemThread = new AudioSystemThread();
+        mAudioSystemThread.start();
+        waitForAudioHandlerCreation();
+    }
+
+    /** Waits for the volume handler to be created by the other thread. */
+    private void waitForAudioHandlerCreation() {
+        synchronized(this) {
+            while (mAudioHandler == null) {
+                try {
+                    // Wait for mAudioHandler to be set by the other thread
+                    wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "Interrupted while waiting on volume handler.");
+                }
+            }
+        }
+    }
+
+    private void checkAllAliasStreamVolumes() {
+        synchronized (VolumeStreamState.class) {
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+            for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+                if (streamType != mStreamVolumeAlias[streamType]) {
+                    mStreamStates[streamType].
+                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
+                                            TAG);
+                }
+                // apply stream volume
+                if (!mStreamStates[streamType].mIsMuted) {
+                    mStreamStates[streamType].applyAllVolumes();
+                }
+            }
+        }
+    }
+
+    private void checkAllFixedVolumeDevices()
+    {
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+            mStreamStates[streamType].checkFixedVolumeDevices();
+        }
+    }
+
+    private void checkAllFixedVolumeDevices(int streamType) {
+        mStreamStates[streamType].checkFixedVolumeDevices();
+    }
+
+    private void checkMuteAffectedStreams() {
+        // any stream with a min level > 0 is not muteable by definition
+        for (int i = 0; i < mStreamStates.length; i++) {
+            final VolumeStreamState vss = mStreamStates[i];
+            if (vss.mIndexMin > 0) {
+                mMuteAffectedStreams &= ~(1 << vss.mStreamType);
+            }
+        }
+    }
+
+    private void createStreamStates() {
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
+
+        for (int i = 0; i < numStreamTypes; i++) {
+            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
+        }
+
+        checkAllFixedVolumeDevices();
+        checkAllAliasStreamVolumes();
+        checkMuteAffectedStreams();
+    }
+
+    private void dumpStreamStates(PrintWriter pw) {
+        pw.println("\nStream volumes (device: index)");
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        for (int i = 0; i < numStreamTypes; i++) {
+            pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
+            mStreamStates[i].dump(pw);
+            pw.println("");
+        }
+        pw.print("\n- mute affected streams = 0x");
+        pw.println(Integer.toHexString(mMuteAffectedStreams));
+    }
+
+    private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
+        int dtmfStreamAlias;
+
+        switch (mPlatformType) {
+        case AudioSystem.PLATFORM_VOICE:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
+            dtmfStreamAlias = AudioSystem.STREAM_RING;
+            break;
+        case AudioSystem.PLATFORM_TELEVISION:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
+            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
+            break;
+        default:
+            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
+            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
+        }
+
+        if (isPlatformTelevision()) {
+            mRingerModeAffectedStreams = 0;
+        } else {
+            if (isInCommunication()) {
+                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
+                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
+            } else {
+                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
+            }
+        }
+
+        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
+        if (updateVolumes) {
+            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
+                    caller);
+            // apply stream mute states according to new value of mRingerModeAffectedStreams
+            setRingerModeInt(getRingerModeInternal(), false);
+            sendMsg(mAudioHandler,
+                    MSG_SET_ALL_VOLUMES,
+                    SENDMSG_QUEUE,
+                    0,
+                    0,
+                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
+        }
+    }
+
+    private void readDockAudioSettings(ContentResolver cr)
+    {
+        mDockAudioMediaEnabled = Settings.Global.getInt(
+                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
+
+        sendMsg(mAudioHandler,
+                MSG_SET_FORCE_USE,
+                SENDMSG_QUEUE,
+                AudioSystem.FOR_DOCK,
+                mDockAudioMediaEnabled ?
+                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
+                null,
+                0);
+    }
+
+    private void readPersistedSettings() {
+        final ContentResolver cr = mContentResolver;
+
+        int ringerModeFromSettings =
+                Settings.Global.getInt(
+                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
+        int ringerMode = ringerModeFromSettings;
+        // sanity check in case the settings are restored from a device with incompatible
+        // ringer modes
+        if (!isValidRingerMode(ringerMode)) {
+            ringerMode = AudioManager.RINGER_MODE_NORMAL;
+        }
+        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
+            ringerMode = AudioManager.RINGER_MODE_SILENT;
+        }
+        if (ringerMode != ringerModeFromSettings) {
+            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
+        }
+        if (mUseFixedVolume || isPlatformTelevision()) {
+            ringerMode = AudioManager.RINGER_MODE_NORMAL;
+        }
+        synchronized(mSettingsLock) {
+            mRingerMode = ringerMode;
+            if (mRingerModeExternal == -1) {
+                mRingerModeExternal = mRingerMode;
+            }
+
+            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
+            // are still needed while setVibrateSetting() and getVibrateSetting() are being
+            // deprecated.
+            mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
+                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
+                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
+                                                            : AudioManager.VIBRATE_SETTING_OFF);
+            mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
+                                            AudioManager.VIBRATE_TYPE_RINGER,
+                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
+                                                            : AudioManager.VIBRATE_SETTING_OFF);
+
+            updateRingerModeAffectedStreams();
+            readDockAudioSettings(cr);
+        }
+
+        mMuteAffectedStreams = System.getIntForUser(cr,
+                System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
+                UserHandle.USER_CURRENT);
+
+        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
+                0, UserHandle.USER_CURRENT) == 1;
+        if (mUseFixedVolume) {
+            masterMute = false;
+            AudioSystem.setMasterVolume(1.0f);
+        }
+        AudioSystem.setMasterMute(masterMute);
+        broadcastMasterMuteStatus(masterMute);
+
+        boolean microphoneMute =
+                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
+        AudioSystem.muteMicrophone(microphoneMute);
+
+        // Each stream will read its own persisted settings
+
+        // Broadcast the sticky intents
+        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
+        broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
+
+        // Broadcast vibrate settings
+        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
+
+        // Load settings for the volume controller
+        mVolumeController.loadSettings(cr);
+    }
+
+    private int rescaleIndex(int index, int srcStream, int dstStream) {
+        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
+    }
+
+    private class AudioOrientationEventListener
+            extends OrientationEventListener {
+        public AudioOrientationEventListener(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onOrientationChanged(int orientation) {
+            //Even though we're responding to phone orientation events,
+            //use display rotation so audio stays in sync with video/dialogs
+            int newRotation = ((WindowManager) mContext.getSystemService(
+                    Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
+            if (newRotation != mDeviceRotation) {
+                mDeviceRotation = newRotation;
+                setRotationForAudioSystem();
+            }
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // IPC methods
+    ///////////////////////////////////////////////////////////////////////////
+    /** @see AudioManager#adjustVolume(int, int) */
+    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
+            String callingPackage, String caller) {
+        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
+                caller, Binder.getCallingUid());
+    }
+
+    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
+            String callingPackage, String caller, int uid) {
+        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
+                + ", flags=" + flags + ", caller=" + caller);
+        int streamType;
+        boolean isMute = isMuteAdjust(direction);
+        if (mVolumeControlStream != -1) {
+            streamType = mVolumeControlStream;
+        } else {
+            streamType = getActiveStreamType(suggestedStreamType);
+        }
+        final int resolvedStream = mStreamVolumeAlias[streamType];
+
+        // Play sounds on STREAM_RING only.
+        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
+                resolvedStream != AudioSystem.STREAM_RING) {
+            flags &= ~AudioManager.FLAG_PLAY_SOUND;
+        }
+
+        // For notifications/ring, show the ui before making any adjustments
+        // Don't suppress mute/unmute requests
+        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
+            direction = 0;
+            flags &= ~AudioManager.FLAG_PLAY_SOUND;
+            flags &= ~AudioManager.FLAG_VIBRATE;
+            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
+        }
+
+        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
+    }
+
+    /** @see AudioManager#adjustStreamVolume(int, int, int) */
+    public void adjustStreamVolume(int streamType, int direction, int flags,
+            String callingPackage) {
+        adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
+                Binder.getCallingUid());
+    }
+
+    private void adjustStreamVolume(int streamType, int direction, int flags,
+            String callingPackage, String caller, int uid) {
+        if (mUseFixedVolume) {
+            return;
+        }
+        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
+                + ", flags=" + flags + ", caller=" + caller);
+
+        ensureValidDirection(direction);
+        ensureValidStreamType(streamType);
+
+        boolean isMuteAdjust = isMuteAdjust(direction);
+
+        if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
+            return;
+        }
+
+        // use stream type alias here so that streams with same alias have the same behavior,
+        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
+        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
+        int streamTypeAlias = mStreamVolumeAlias[streamType];
+
+        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
+
+        final int device = getDeviceForStream(streamTypeAlias);
+
+        int aliasIndex = streamState.getIndex(device);
+        boolean adjustVolume = true;
+        int step;
+
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
+        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
+                != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        // reset any pending volume command
+        synchronized (mSafeMediaVolumeState) {
+            mPendingVolumeCommand = null;
+        }
+
+        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
+        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
+               ((device & mFixedVolumeDevices) != 0)) {
+            flags |= AudioManager.FLAG_FIXED_VOLUME;
+
+            // Always toggle between max safe volume and 0 for fixed volume devices where safe
+            // volume is enforced, and max and 0 for the others.
+            // This is simulated by stepping by the full allowed volume range
+            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
+                    (device & mSafeMediaVolumeDevices) != 0) {
+                step = mSafeMediaVolumeIndex;
+            } else {
+                step = streamState.getMaxIndex();
+            }
+            if (aliasIndex != 0) {
+                aliasIndex = step;
+            }
+        } else {
+            // convert one UI step (+/-1) into a number of internal units on the stream alias
+            step = rescaleIndex(10, streamType, streamTypeAlias);
+        }
+
+        // If either the client forces allowing ringer modes for this adjustment,
+        // or the stream type is one that is affected by ringer modes
+        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
+                (streamTypeAlias == getUiSoundsStreamType())) {
+            int ringerMode = getRingerModeInternal();
+            // do not vibrate if already in vibrate mode
+            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+                flags &= ~AudioManager.FLAG_VIBRATE;
+            }
+            // Check if the ringer mode handles this adjustment. If it does we don't
+            // need to adjust the volume further.
+            final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
+            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
+            // If suppressing a volume adjustment in silent mode, display the UI hint
+            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
+                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
+            }
+            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
+            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
+                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
+            }
+        }
+
+        int oldIndex = mStreamStates[streamType].getIndex(device);
+
+        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+            mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
+
+            // Check if volume update should be send to AVRCP
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
+                    }
+                }
+            }
+
+            if (isMuteAdjust) {
+                boolean state;
+                if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
+                    state = !streamState.mIsMuted;
+                } else {
+                    state = direction == AudioManager.ADJUST_MUTE;
+                }
+                if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
+                    setSystemAudioMute(state);
+                }
+                for (int stream = 0; stream < mStreamStates.length; stream++) {
+                    if (streamTypeAlias == mStreamVolumeAlias[stream]) {
+                        mStreamStates[stream].mute(state);
+                    }
+                }
+            } else if ((direction == AudioManager.ADJUST_RAISE) &&
+                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
+                Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
+                mVolumeController.postDisplaySafeVolumeWarning(flags);
+            } else if (streamState.adjustIndex(direction * step, device, caller)
+                    || streamState.mIsMuted) {
+                // Post message to set system volume (it in turn will post a
+                // message to persist).
+                if (streamState.mIsMuted) {
+                    // Unmute the stream if it was previously muted
+                    if (direction == AudioManager.ADJUST_RAISE) {
+                        // unmute immediately for volume up
+                        streamState.mute(false);
+                    } else if (direction == AudioManager.ADJUST_LOWER) {
+                        if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
+                            sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
+                                    streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
+                        }
+                    }
+                }
+                sendMsg(mAudioHandler,
+                        MSG_SET_DEVICE_VOLUME,
+                        SENDMSG_QUEUE,
+                        device,
+                        0,
+                        streamState,
+                        0);
+            }
+
+            // Check if volume update should be sent to Hdmi system audio.
+            int newIndex = mStreamStates[streamType].getIndex(device);
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
+                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
+            }
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    // mHdmiCecSink true => mHdmiPlaybackClient != null
+                    if (mHdmiCecSink &&
+                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                            oldIndex != newIndex) {
+                        synchronized (mHdmiPlaybackClient) {
+                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
+                                    KeyEvent.KEYCODE_VOLUME_UP;
+                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
+                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+                        }
+                    }
+                }
+            }
+        }
+        int index = mStreamStates[streamType].getIndex(device);
+        sendVolumeUpdate(streamType, oldIndex, index, flags);
+    }
+
+    // Called after a delay when volume down is pressed while muted
+    private void onUnmuteStream(int stream, int flags) {
+        VolumeStreamState streamState = mStreamStates[stream];
+        streamState.mute(false);
+
+        final int device = getDeviceForStream(stream);
+        final int index = mStreamStates[stream].getIndex(device);
+        sendVolumeUpdate(stream, index, index, flags);
+    }
+
+    private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
+        if (mHdmiManager == null
+                || mHdmiTvClient == null
+                || oldVolume == newVolume
+                || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
+
+        // Sets the audio volume of AVR when we are in system audio mode. The new volume info
+        // is tranformed to HDMI-CEC commands and passed through CEC bus.
+        synchronized (mHdmiManager) {
+            if (!mHdmiSystemAudioSupported) return;
+            synchronized (mHdmiTvClient) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+    }
+
+    // StreamVolumeCommand contains the information needed to defer the process of
+    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
+    class StreamVolumeCommand {
+        public final int mStreamType;
+        public final int mIndex;
+        public final int mFlags;
+        public final int mDevice;
+
+        StreamVolumeCommand(int streamType, int index, int flags, int device) {
+            mStreamType = streamType;
+            mIndex = index;
+            mFlags = flags;
+            mDevice = device;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
+                    .append(mIndex).append(",flags=").append(mFlags).append(",device=")
+                    .append(mDevice).append('}').toString();
+        }
+    };
+
+    private void onSetStreamVolume(int streamType, int index, int flags, int device,
+            String caller) {
+        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, caller);
+        // setting volume on ui sounds stream type also controls silent mode
+        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
+                (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
+            int newRingerMode;
+            if (index == 0) {
+                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
+                        : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
+                        : AudioManager.RINGER_MODE_NORMAL;
+            } else {
+                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
+            }
+            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
+        }
+    }
+
+    /** @see AudioManager#setStreamVolume(int, int, int) */
+    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
+        setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
+                Binder.getCallingUid());
+    }
+
+    private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
+            String caller, int uid) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
+        ensureValidStreamType(streamType);
+        int streamTypeAlias = mStreamVolumeAlias[streamType];
+        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
+
+        final int device = getDeviceForStream(streamType);
+        int oldIndex;
+
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
+        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
+                != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+
+        synchronized (mSafeMediaVolumeState) {
+            // reset any pending volume command
+            mPendingVolumeCommand = null;
+
+            oldIndex = streamState.getIndex(device);
+
+            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
+
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
+                    }
+                }
+            }
+
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
+                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
+            }
+
+            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
+            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
+                    ((device & mFixedVolumeDevices) != 0)) {
+                flags |= AudioManager.FLAG_FIXED_VOLUME;
+
+                // volume is either 0 or max allowed for fixed volume devices
+                if (index != 0) {
+                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
+                            (device & mSafeMediaVolumeDevices) != 0) {
+                        index = mSafeMediaVolumeIndex;
+                    } else {
+                        index = streamState.getMaxIndex();
+                    }
+                }
+            }
+
+            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
+                mVolumeController.postDisplaySafeVolumeWarning(flags);
+                mPendingVolumeCommand = new StreamVolumeCommand(
+                                                    streamType, index, flags, device);
+            } else {
+                onSetStreamVolume(streamType, index, flags, device, caller);
+                index = mStreamStates[streamType].getIndex(device);
+            }
+        }
+        sendVolumeUpdate(streamType, oldIndex, index, flags);
+    }
+
+    /** @see AudioManager#forceVolumeControlStream(int) */
+    public void forceVolumeControlStream(int streamType, IBinder cb) {
+        synchronized(mForceControlStreamLock) {
+            mVolumeControlStream = streamType;
+            if (mVolumeControlStream == -1) {
+                if (mForceControlStreamClient != null) {
+                    mForceControlStreamClient.release();
+                    mForceControlStreamClient = null;
+                }
+            } else {
+                mForceControlStreamClient = new ForceControlStreamClient(cb);
+            }
+        }
+    }
+
+    private class ForceControlStreamClient implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+
+        ForceControlStreamClient(IBinder cb) {
+            if (cb != null) {
+                try {
+                    cb.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    // Client has died!
+                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
+                    cb = null;
+                }
+            }
+            mCb = cb;
+        }
+
+        public void binderDied() {
+            synchronized(mForceControlStreamLock) {
+                Log.w(TAG, "SCO client died");
+                if (mForceControlStreamClient != this) {
+                    Log.w(TAG, "unregistered control stream client died");
+                } else {
+                    mForceControlStreamClient = null;
+                    mVolumeControlStream = -1;
+                }
+            }
+        }
+
+        public void release() {
+            if (mCb != null) {
+                mCb.unlinkToDeath(this, 0);
+                mCb = null;
+            }
+        }
+    }
+
+    private void sendBroadcastToAll(Intent intent) {
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void sendStickyBroadcastToAll(Intent intent) {
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    // UI update and Broadcast Intent
+    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
+        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
+            streamType = AudioSystem.STREAM_NOTIFICATION;
+        }
+
+        if (streamType == AudioSystem.STREAM_MUSIC) {
+            flags = updateFlagsForSystemAudio(flags);
+        }
+        mVolumeController.postVolumeChanged(streamType, flags);
+    }
+
+    // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
+    // receives volume notification from Audio Receiver.
+    private int updateFlagsForSystemAudio(int flags) {
+        if (mHdmiTvClient != null) {
+            synchronized (mHdmiTvClient) {
+                if (mHdmiSystemAudioSupported &&
+                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
+                    flags &= ~AudioManager.FLAG_SHOW_UI;
+                }
+            }
+        }
+        return flags;
+    }
+
+    // UI update and Broadcast Intent
+    private void sendMasterMuteUpdate(boolean muted, int flags) {
+        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
+        broadcastMasterMuteStatus(muted);
+    }
+
+    private void broadcastMasterMuteStatus(boolean muted) {
+        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        sendStickyBroadcastToAll(intent);
+    }
+
+    /**
+     * Sets the stream state's index, and posts a message to set system volume.
+     * This will not call out to the UI. Assumes a valid stream type.
+     *
+     * @param streamType Type of the stream
+     * @param index Desired volume index of the stream
+     * @param device the device whose volume must be changed
+     * @param force If true, set the volume even if the desired volume is same
+     * as the current volume.
+     */
+    private void setStreamVolumeInt(int streamType,
+                                    int index,
+                                    int device,
+                                    boolean force,
+                                    String caller) {
+        VolumeStreamState streamState = mStreamStates[streamType];
+
+        if (streamState.setIndex(index, device, caller) || force) {
+            // Post message to set system volume (it in turn will post a message
+            // to persist).
+            sendMsg(mAudioHandler,
+                    MSG_SET_DEVICE_VOLUME,
+                    SENDMSG_QUEUE,
+                    device,
+                    0,
+                    streamState,
+                    0);
+        }
+    }
+
+    private void setSystemAudioMute(boolean state) {
+        if (mHdmiManager == null || mHdmiTvClient == null) return;
+        synchronized (mHdmiManager) {
+            if (!mHdmiSystemAudioSupported) return;
+            synchronized (mHdmiTvClient) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mHdmiTvClient.setSystemAudioMute(state);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+    }
+
+    /** get stream mute state. */
+    public boolean isStreamMute(int streamType) {
+        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+            streamType = getActiveStreamType(streamType);
+        }
+        synchronized (VolumeStreamState.class) {
+            return mStreamStates[streamType].mIsMuted;
+        }
+    }
+
+    private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mICallback; // To be notified of client's death
+
+        RmtSbmxFullVolDeathHandler(IBinder cb) {
+            mICallback = cb;
+            try {
+                cb.linkToDeath(this, 0/*flags*/);
+            } catch (RemoteException e) {
+                Log.e(TAG, "can't link to death", e);
+            }
+        }
+
+        boolean isHandlerFor(IBinder cb) {
+            return mICallback.equals(cb);
+        }
+
+        void forget() {
+            try {
+                mICallback.unlinkToDeath(this, 0/*flags*/);
+            } catch (NoSuchElementException e) {
+                Log.e(TAG, "error unlinking to death", e);
+            }
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
+            forceRemoteSubmixFullVolume(false, mICallback);
+        }
+    }
+
+    /**
+     * call must be synchronized on mRmtSbmxFullVolDeathHandlers
+     * @return true if there is a registered death handler, false otherwise */
+    private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
+        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
+        while (it.hasNext()) {
+            final RmtSbmxFullVolDeathHandler handler = it.next();
+            if (handler.isHandlerFor(cb)) {
+                handler.forget();
+                mRmtSbmxFullVolDeathHandlers.remove(handler);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** call synchronized on mRmtSbmxFullVolDeathHandlers */
+    private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
+        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
+        while (it.hasNext()) {
+            if (it.next().isHandlerFor(cb)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private int mRmtSbmxFullVolRefCount = 0;
+    private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
+            new ArrayList<RmtSbmxFullVolDeathHandler>();
+
+    public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
+        if (cb == null) {
+            return;
+        }
+        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
+            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
+            return;
+        }
+        synchronized(mRmtSbmxFullVolDeathHandlers) {
+            boolean applyRequired = false;
+            if (startForcing) {
+                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
+                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
+                    if (mRmtSbmxFullVolRefCount == 0) {
+                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        applyRequired = true;
+                    }
+                    mRmtSbmxFullVolRefCount++;
+                }
+            } else {
+                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
+                    mRmtSbmxFullVolRefCount--;
+                    if (mRmtSbmxFullVolRefCount == 0) {
+                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+                        applyRequired = true;
+                    }
+                }
+            }
+            if (applyRequired) {
+                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
+                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
+                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
+            }
+        }
+    }
+
+    private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
+        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
+                != AppOpsManager.MODE_ALLOWED) {
+            return;
+        }
+        if (mute != AudioSystem.getMasterMute()) {
+            setSystemAudioMute(mute);
+            AudioSystem.setMasterMute(mute);
+            // Post a persist master volume msg
+            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
+                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
+            sendMasterMuteUpdate(mute, flags);
+
+            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
+            sendBroadcastToAll(intent);
+        }
+    }
+
+    /** get master mute state. */
+    public boolean isMasterMute() {
+        return AudioSystem.getMasterMute();
+    }
+
+    public void setMasterMute(boolean mute, int flags, String callingPackage) {
+        setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
+    }
+
+    /** @see AudioManager#getStreamVolume(int) */
+    public int getStreamVolume(int streamType) {
+        ensureValidStreamType(streamType);
+        int device = getDeviceForStream(streamType);
+        synchronized (VolumeStreamState.class) {
+            int index = mStreamStates[streamType].getIndex(device);
+
+            // by convention getStreamVolume() returns 0 when a stream is muted.
+            if (mStreamStates[streamType].mIsMuted) {
+                index = 0;
+            }
+            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
+                    (device & mFixedVolumeDevices) != 0) {
+                index = mStreamStates[streamType].getMaxIndex();
+            }
+            return (index + 5) / 10;
+        }
+    }
+
+    /** @see AudioManager#getStreamMaxVolume(int) */
+    public int getStreamMaxVolume(int streamType) {
+        ensureValidStreamType(streamType);
+        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
+    }
+
+    /** @see AudioManager#getStreamMinVolume(int) */
+    public int getStreamMinVolume(int streamType) {
+        ensureValidStreamType(streamType);
+        return (mStreamStates[streamType].getMinIndex() + 5) / 10;
+    }
+
+    /** Get last audible volume before stream was muted. */
+    public int getLastAudibleStreamVolume(int streamType) {
+        ensureValidStreamType(streamType);
+        int device = getDeviceForStream(streamType);
+        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
+    }
+
+    /** @see AudioManager#getUiSoundsStreamType()  */
+    public int getUiSoundsStreamType() {
+        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
+    }
+
+    /** @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;
+        }
+        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
+            return;
+        }
+
+        AudioSystem.muteMicrophone(on);
+        // Post a persist microphone msg.
+        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
+                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
+    }
+
+    @Override
+    public int getRingerModeExternal() {
+        synchronized(mSettingsLock) {
+            return mRingerModeExternal;
+        }
+    }
+
+    @Override
+    public int getRingerModeInternal() {
+        synchronized(mSettingsLock) {
+            return mRingerMode;
+        }
+    }
+
+    private void ensureValidRingerMode(int ringerMode) {
+        if (!isValidRingerMode(ringerMode)) {
+            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
+        }
+    }
+
+    /** @see AudioManager#isValidRingerMode(int) */
+    public boolean isValidRingerMode(int ringerMode) {
+        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
+    }
+
+    public void setRingerModeExternal(int ringerMode, String caller) {
+        setRingerMode(ringerMode, caller, true /*external*/);
+    }
+
+    public void setRingerModeInternal(int ringerMode, String caller) {
+        enforceVolumeController("setRingerModeInternal");
+        setRingerMode(ringerMode, caller, false /*external*/);
+    }
+
+    private void setRingerMode(int ringerMode, String caller, boolean external) {
+        if (mUseFixedVolume || isPlatformTelevision()) {
+            return;
+        }
+        if (caller == null || caller.length() == 0) {
+            throw new IllegalArgumentException("Bad caller: " + caller);
+        }
+        ensureValidRingerMode(ringerMode);
+        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
+            ringerMode = AudioManager.RINGER_MODE_SILENT;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSettingsLock) {
+                final int ringerModeInternal = getRingerModeInternal();
+                final int ringerModeExternal = getRingerModeExternal();
+                if (external) {
+                    setRingerModeExt(ringerMode);
+                    if (mRingerModeDelegate != null) {
+                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
+                                ringerMode, caller, ringerModeInternal, mVolumePolicy);
+                    }
+                    if (ringerMode != ringerModeInternal) {
+                        setRingerModeInt(ringerMode, true /*persist*/);
+                    }
+                } else /*internal*/ {
+                    if (ringerMode != ringerModeInternal) {
+                        setRingerModeInt(ringerMode, true /*persist*/);
+                    }
+                    if (mRingerModeDelegate != null) {
+                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
+                                ringerMode, caller, ringerModeExternal, mVolumePolicy);
+                    }
+                    setRingerModeExt(ringerMode);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void setRingerModeExt(int ringerMode) {
+        synchronized(mSettingsLock) {
+            if (ringerMode == mRingerModeExternal) return;
+            mRingerModeExternal = ringerMode;
+        }
+        // Send sticky broadcast
+        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
+    }
+
+    private void setRingerModeInt(int ringerMode, boolean persist) {
+        final boolean change;
+        synchronized(mSettingsLock) {
+            change = mRingerMode != ringerMode;
+            mRingerMode = ringerMode;
+        }
+
+        // Mute stream if not previously muted by ringer mode and ringer mode
+        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
+        // Unmute stream if previously muted by ringer mode and ringer mode
+        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
+                || ringerMode == AudioManager.RINGER_MODE_SILENT;
+        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+            final boolean isMuted = isStreamMutedByRingerMode(streamType);
+            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
+            if (isMuted == shouldMute) continue;
+            if (!shouldMute) {
+                // unmute
+                // ring and notifications volume should never be 0 when not silenced
+                // on voice capable devices or devices that support vibration
+                if ((isPlatformVoice() || mHasVibrator) &&
+                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
+                    synchronized (VolumeStreamState.class) {
+                        final VolumeStreamState vss = mStreamStates[streamType];
+                        for (int i = 0; i < vss.mIndexMap.size(); i++) {
+                            int device = vss.mIndexMap.keyAt(i);
+                            int value = vss.mIndexMap.valueAt(i);
+                            if (value == 0) {
+                                vss.setIndex(10, device, TAG);
+                            }
+                        }
+                        // Persist volume for stream ring when it is changed here
+                      final int device = getDeviceForStream(streamType);
+                      sendMsg(mAudioHandler,
+                              MSG_PERSIST_VOLUME,
+                              SENDMSG_QUEUE,
+                              device,
+                              0,
+                              mStreamStates[streamType],
+                              PERSIST_DELAY);
+                    }
+                }
+                mStreamStates[streamType].mute(false);
+                mRingerModeMutedStreams &= ~(1 << streamType);
+            } else {
+                // mute
+                mStreamStates[streamType].mute(true);
+                mRingerModeMutedStreams |= (1 << streamType);
+            }
+        }
+
+        // Post a persist ringer mode msg
+        if (persist) {
+            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
+                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
+        }
+        if (change) {
+            // Send sticky broadcast
+            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
+        }
+    }
+
+    /** @see AudioManager#shouldVibrate(int) */
+    public boolean shouldVibrate(int vibrateType) {
+        if (!mHasVibrator) return false;
+
+        switch (getVibrateSetting(vibrateType)) {
+
+            case AudioManager.VIBRATE_SETTING_ON:
+                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
+
+            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
+                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
+
+            case AudioManager.VIBRATE_SETTING_OFF:
+                // return false, even for incoming calls
+                return false;
+
+            default:
+                return false;
+        }
+    }
+
+    /** @see AudioManager#getVibrateSetting(int) */
+    public int getVibrateSetting(int vibrateType) {
+        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
+        return (mVibrateSetting >> (vibrateType * 2)) & 3;
+    }
+
+    /** @see AudioManager#setVibrateSetting(int, int) */
+    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
+
+        if (!mHasVibrator) return;
+
+        mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
+                vibrateSetting);
+
+        // Broadcast change
+        broadcastVibrateSetting(vibrateType);
+
+    }
+
+    private class SetModeDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+        private int mPid;
+        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
+
+        SetModeDeathHandler(IBinder cb, int pid) {
+            mCb = cb;
+            mPid = pid;
+        }
+
+        public void binderDied() {
+            int newModeOwnerPid = 0;
+            synchronized(mSetModeDeathHandlers) {
+                Log.w(TAG, "setMode() client died");
+                int index = mSetModeDeathHandlers.indexOf(this);
+                if (index < 0) {
+                    Log.w(TAG, "unregistered setMode() client died");
+                } else {
+                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
+                }
+            }
+            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+            // SCO connections not started by the application changing the mode
+            if (newModeOwnerPid != 0) {
+                final long ident = Binder.clearCallingIdentity();
+                disconnectBluetoothSco(newModeOwnerPid);
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        public int getPid() {
+            return mPid;
+        }
+
+        public void setMode(int mode) {
+            mMode = mode;
+        }
+
+        public int getMode() {
+            return mMode;
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    /** @see AudioManager#setMode(int) */
+    public void setMode(int mode, IBinder cb, String callingPackage) {
+        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
+        if (!checkAudioSettingsPermission("setMode()")) {
+            return;
+        }
+
+        if ( (mode == AudioSystem.MODE_IN_CALL) &&
+                (mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.MODIFY_PHONE_STATE)
+                            != PackageManager.PERMISSION_GRANTED)) {
+            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
+            return;
+        }
+
+        int newModeOwnerPid = 0;
+        synchronized(mSetModeDeathHandlers) {
+            if (mode == AudioSystem.MODE_CURRENT) {
+                mode = mMode;
+            }
+            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
+        }
+        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+        // SCO connections not started by the application changing the mode
+        if (newModeOwnerPid != 0) {
+             disconnectBluetoothSco(newModeOwnerPid);
+        }
+    }
+
+    // must be called synchronized on mSetModeDeathHandlers
+    // setModeInt() returns a valid PID if the audio mode was successfully set to
+    // any mode other than NORMAL.
+    private int setModeInt(int mode, IBinder cb, int pid, String caller) {
+        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
+                + caller + ")"); }
+        int newModeOwnerPid = 0;
+        if (cb == null) {
+            Log.e(TAG, "setModeInt() called with null binder");
+            return newModeOwnerPid;
+        }
+
+        SetModeDeathHandler hdlr = null;
+        Iterator iter = mSetModeDeathHandlers.iterator();
+        while (iter.hasNext()) {
+            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
+            if (h.getPid() == pid) {
+                hdlr = h;
+                // Remove from client list so that it is re-inserted at top of list
+                iter.remove();
+                hdlr.getBinder().unlinkToDeath(hdlr, 0);
+                break;
+            }
+        }
+        int status = AudioSystem.AUDIO_STATUS_OK;
+        do {
+            if (mode == AudioSystem.MODE_NORMAL) {
+                // get new mode from client at top the list if any
+                if (!mSetModeDeathHandlers.isEmpty()) {
+                    hdlr = mSetModeDeathHandlers.get(0);
+                    cb = hdlr.getBinder();
+                    mode = hdlr.getMode();
+                    if (DEBUG_MODE) {
+                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
+                                + hdlr.mPid);
+                    }
+                }
+            } else {
+                if (hdlr == null) {
+                    hdlr = new SetModeDeathHandler(cb, pid);
+                }
+                // Register for client death notification
+                try {
+                    cb.linkToDeath(hdlr, 0);
+                } catch (RemoteException e) {
+                    // Client has died!
+                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
+                }
+
+                // Last client to call setMode() is always at top of client list
+                // as required by SetModeDeathHandler.binderDied()
+                mSetModeDeathHandlers.add(0, hdlr);
+                hdlr.setMode(mode);
+            }
+
+            if (mode != mMode) {
+                status = AudioSystem.setPhoneState(mode);
+                if (status == AudioSystem.AUDIO_STATUS_OK) {
+                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
+                    mMode = mode;
+                } else {
+                    if (hdlr != null) {
+                        mSetModeDeathHandlers.remove(hdlr);
+                        cb.unlinkToDeath(hdlr, 0);
+                    }
+                    // force reading new top of mSetModeDeathHandlers stack
+                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
+                    mode = AudioSystem.MODE_NORMAL;
+                }
+            } else {
+                status = AudioSystem.AUDIO_STATUS_OK;
+            }
+        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
+
+        if (status == AudioSystem.AUDIO_STATUS_OK) {
+            if (mode != AudioSystem.MODE_NORMAL) {
+                if (mSetModeDeathHandlers.isEmpty()) {
+                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
+                } else {
+                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
+                }
+            }
+            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+            int device = getDeviceForStream(streamType);
+            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
+            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
+
+            updateStreamVolumeAlias(true /*updateVolumes*/, caller);
+        }
+        return newModeOwnerPid;
+    }
+
+    /** @see AudioManager#getMode() */
+    public int getMode() {
+        return mMode;
+    }
+
+    //==========================================================================================
+    // Sound Effects
+    //==========================================================================================
+
+    private static final String TAG_AUDIO_ASSETS = "audio_assets";
+    private static final String ATTR_VERSION = "version";
+    private static final String TAG_GROUP = "group";
+    private static final String ATTR_GROUP_NAME = "name";
+    private static final String TAG_ASSET = "asset";
+    private static final String ATTR_ASSET_ID = "id";
+    private static final String ATTR_ASSET_FILE = "file";
+
+    private static final String ASSET_FILE_VERSION = "1.0";
+    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
+
+    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
+
+    class LoadSoundEffectReply {
+        public int mStatus = 1;
+    };
+
+    private void loadTouchSoundAssetDefaults() {
+        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
+        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
+            SOUND_EFFECT_FILES_MAP[i][0] = 0;
+            SOUND_EFFECT_FILES_MAP[i][1] = -1;
+        }
+    }
+
+    private void loadTouchSoundAssets() {
+        XmlResourceParser parser = null;
+
+        // only load assets once.
+        if (!SOUND_EFFECT_FILES.isEmpty()) {
+            return;
+        }
+
+        loadTouchSoundAssetDefaults();
+
+        try {
+            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
+
+            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
+            String version = parser.getAttributeValue(null, ATTR_VERSION);
+            boolean inTouchSoundsGroup = false;
+
+            if (ASSET_FILE_VERSION.equals(version)) {
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_GROUP)) {
+                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
+                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
+                            inTouchSoundsGroup = true;
+                            break;
+                        }
+                    }
+                }
+                while (inTouchSoundsGroup) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_ASSET)) {
+                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
+                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
+                        int fx;
+
+                        try {
+                            Field field = AudioManager.class.getField(id);
+                            fx = field.getInt(null);
+                        } catch (Exception e) {
+                            Log.w(TAG, "Invalid touch sound ID: "+id);
+                            continue;
+                        }
+
+                        int i = SOUND_EFFECT_FILES.indexOf(file);
+                        if (i == -1) {
+                            i = SOUND_EFFECT_FILES.size();
+                            SOUND_EFFECT_FILES.add(file);
+                        }
+                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
+                    } else {
+                        break;
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "audio assets file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading touch sound assets", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading touch sound assets", e);
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
+    /** @see AudioManager#playSoundEffect(int) */
+    public void playSoundEffect(int effectType) {
+        playSoundEffectVolume(effectType, -1.0f);
+    }
+
+    /** @see AudioManager#playSoundEffect(int, float) */
+    public void playSoundEffectVolume(int effectType, float volume) {
+        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
+            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
+            return;
+        }
+
+        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
+                effectType, (int) (volume * 1000), null, 0);
+    }
+
+    /**
+     * Loads samples into the soundpool.
+     * This method must be called at first when sound effects are enabled
+     */
+    public boolean loadSoundEffects() {
+        int attempts = 3;
+        LoadSoundEffectReply reply = new LoadSoundEffectReply();
+
+        synchronized (reply) {
+            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
+            while ((reply.mStatus == 1) && (attempts-- > 0)) {
+                try {
+                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
+                }
+            }
+        }
+        return (reply.mStatus == 0);
+    }
+
+    /**
+     *  Unloads samples from the sound pool.
+     *  This method can be called to free some memory when
+     *  sound effects are disabled.
+     */
+    public void unloadSoundEffects() {
+        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    class SoundPoolListenerThread extends Thread {
+        public SoundPoolListenerThread() {
+            super("SoundPoolListenerThread");
+        }
+
+        @Override
+        public void run() {
+
+            Looper.prepare();
+            mSoundPoolLooper = Looper.myLooper();
+
+            synchronized (mSoundEffectsLock) {
+                if (mSoundPool != null) {
+                    mSoundPoolCallBack = new SoundPoolCallback();
+                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
+                }
+                mSoundEffectsLock.notify();
+            }
+            Looper.loop();
+        }
+    }
+
+    private final class SoundPoolCallback implements
+            android.media.SoundPool.OnLoadCompleteListener {
+
+        int mStatus = 1; // 1 means neither error nor last sample loaded yet
+        List<Integer> mSamples = new ArrayList<Integer>();
+
+        public int status() {
+            return mStatus;
+        }
+
+        public void setSamples(int[] samples) {
+            for (int i = 0; i < samples.length; i++) {
+                // do not wait ack for samples rejected upfront by SoundPool
+                if (samples[i] > 0) {
+                    mSamples.add(samples[i]);
+                }
+            }
+        }
+
+        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+            synchronized (mSoundEffectsLock) {
+                int i = mSamples.indexOf(sampleId);
+                if (i >= 0) {
+                    mSamples.remove(i);
+                }
+                if ((status != 0) || mSamples. isEmpty()) {
+                    mStatus = status;
+                    mSoundEffectsLock.notify();
+                }
+            }
+        }
+    }
+
+    /** @see AudioManager#reloadAudioSettings() */
+    public void reloadAudioSettings() {
+        readAudioSettings(false /*userSwitch*/);
+    }
+
+    private void readAudioSettings(boolean userSwitch) {
+        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
+        readPersistedSettings();
+
+        // restore volume settings
+        int numStreamTypes = AudioSystem.getNumStreamTypes();
+        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+            VolumeStreamState streamState = mStreamStates[streamType];
+
+            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
+                continue;
+            }
+
+            streamState.readSettings();
+            synchronized (VolumeStreamState.class) {
+                // unmute stream that was muted but is not affect by mute anymore
+                if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
+                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
+                    streamState.mIsMuted = false;
+                }
+            }
+        }
+
+        // apply new ringer mode before checking volume for alias streams so that streams
+        // muted by ringer mode have the correct volume
+        setRingerModeInt(getRingerModeInternal(), false);
+
+        checkAllFixedVolumeDevices();
+        checkAllAliasStreamVolumes();
+        checkMuteAffectedStreams();
+
+        synchronized (mSafeMediaVolumeState) {
+            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
+                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
+                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
+            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
+                enforceSafeMediaVolume(TAG);
+            }
+        }
+    }
+
+    /** @see AudioManager#setSpeakerphoneOn(boolean) */
+    public void setSpeakerphoneOn(boolean on){
+        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
+            return;
+        }
+
+        if (on) {
+            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
+            }
+            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
+        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
+            mForcedUseForComm = AudioSystem.FORCE_NONE;
+        }
+
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
+    }
+
+    /** @see AudioManager#isSpeakerphoneOn() */
+    public boolean isSpeakerphoneOn() {
+        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
+    }
+
+    /** @see AudioManager#setBluetoothScoOn(boolean) */
+    public void setBluetoothScoOn(boolean on){
+        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
+            return;
+        }
+
+        if (on) {
+            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
+        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
+            mForcedUseForComm = AudioSystem.FORCE_NONE;
+        }
+
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
+        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
+                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
+    }
+
+    /** @see AudioManager#isBluetoothScoOn() */
+    public boolean isBluetoothScoOn() {
+        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
+    }
+
+    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
+    public void setBluetoothA2dpOn(boolean on) {
+        synchronized (mBluetoothA2dpEnabledLock) {
+            mBluetoothA2dpEnabled = on;
+            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
+                    AudioSystem.FOR_MEDIA,
+                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
+                    null, 0);
+        }
+    }
+
+    /** @see AudioManager#isBluetoothA2dpOn() */
+    public boolean isBluetoothA2dpOn() {
+        synchronized (mBluetoothA2dpEnabledLock) {
+            return mBluetoothA2dpEnabled;
+        }
+    }
+
+    /** @see AudioManager#startBluetoothSco() */
+    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+        int scoAudioMode =
+                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
+                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
+        startBluetoothScoInt(cb, scoAudioMode);
+    }
+
+    /** @see AudioManager#startBluetoothScoVirtualCall() */
+    public void startBluetoothScoVirtualCall(IBinder cb) {
+        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
+    }
+
+    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
+        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
+                !mSystemReady) {
+            return;
+        }
+        ScoClient client = getScoClient(cb, true);
+        // The calling identity must be cleared before calling ScoClient.incCount().
+        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
+        // and this must be done on behalf of system server to make sure permissions are granted.
+        // The caller identity must be cleared after getScoClient() because it is needed if a new
+        // client is created.
+        final long ident = Binder.clearCallingIdentity();
+        client.incCount(scoAudioMode);
+        Binder.restoreCallingIdentity(ident);
+    }
+
+    /** @see AudioManager#stopBluetoothSco() */
+    public void stopBluetoothSco(IBinder cb){
+        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
+                !mSystemReady) {
+            return;
+        }
+        ScoClient client = getScoClient(cb, false);
+        // The calling identity must be cleared before calling ScoClient.decCount().
+        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
+        // and this must be done on behalf of system server to make sure permissions are granted.
+        final long ident = Binder.clearCallingIdentity();
+        if (client != null) {
+            client.decCount();
+        }
+        Binder.restoreCallingIdentity(ident);
+    }
+
+
+    private class ScoClient implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+        private int mCreatorPid;
+        private int mStartcount; // number of SCO connections started by this client
+
+        ScoClient(IBinder cb) {
+            mCb = cb;
+            mCreatorPid = Binder.getCallingPid();
+            mStartcount = 0;
+        }
+
+        public void binderDied() {
+            synchronized(mScoClients) {
+                Log.w(TAG, "SCO client died");
+                int index = mScoClients.indexOf(this);
+                if (index < 0) {
+                    Log.w(TAG, "unregistered SCO client died");
+                } else {
+                    clearCount(true);
+                    mScoClients.remove(this);
+                }
+            }
+        }
+
+        public void incCount(int scoAudioMode) {
+            synchronized(mScoClients) {
+                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
+                if (mStartcount == 0) {
+                    try {
+                        mCb.linkToDeath(this, 0);
+                    } catch (RemoteException e) {
+                        // client has already died!
+                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
+                    }
+                }
+                mStartcount++;
+            }
+        }
+
+        public void decCount() {
+            synchronized(mScoClients) {
+                if (mStartcount == 0) {
+                    Log.w(TAG, "ScoClient.decCount() already 0");
+                } else {
+                    mStartcount--;
+                    if (mStartcount == 0) {
+                        try {
+                            mCb.unlinkToDeath(this, 0);
+                        } catch (NoSuchElementException e) {
+                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
+                        }
+                    }
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+                }
+            }
+        }
+
+        public void clearCount(boolean stopSco) {
+            synchronized(mScoClients) {
+                if (mStartcount != 0) {
+                    try {
+                        mCb.unlinkToDeath(this, 0);
+                    } catch (NoSuchElementException e) {
+                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
+                    }
+                }
+                mStartcount = 0;
+                if (stopSco) {
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
+                }
+            }
+        }
+
+        public int getCount() {
+            return mStartcount;
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+
+        public int getPid() {
+            return mCreatorPid;
+        }
+
+        public int totalCount() {
+            synchronized(mScoClients) {
+                int count = 0;
+                int size = mScoClients.size();
+                for (int i = 0; i < size; i++) {
+                    count += mScoClients.get(i).getCount();
+                }
+                return count;
+            }
+        }
+
+        private void requestScoState(int state, int scoAudioMode) {
+            checkScoAudioState();
+            if (totalCount() == 0) {
+                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
+                    // the connection.
+                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
+                    // currently controlled by the same client process.
+                    synchronized(mSetModeDeathHandlers) {
+                        if ((mSetModeDeathHandlers.isEmpty() ||
+                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
+                                (mScoAudioState == SCO_STATE_INACTIVE ||
+                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+                            if (mScoAudioState == SCO_STATE_INACTIVE) {
+                                mScoAudioMode = scoAudioMode;
+                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
+                                    if (mBluetoothHeadsetDevice != null) {
+                                        mScoAudioMode = new Integer(Settings.Global.getInt(
+                                                                mContentResolver,
+                                                                "bluetooth_sco_channel_"+
+                                                                mBluetoothHeadsetDevice.getAddress(),
+                                                                SCO_MODE_VIRTUAL_CALL));
+                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                        }
+                                    } else {
+                                        mScoAudioMode = SCO_MODE_RAW;
+                                    }
+                                }
+                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
+                                    boolean status = false;
+                                    if (mScoAudioMode == SCO_MODE_RAW) {
+                                        status = mBluetoothHeadset.connectAudio();
+                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
+                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                            mBluetoothHeadsetDevice);
+                                    } else if (mScoAudioMode == SCO_MODE_VR) {
+                                        status = mBluetoothHeadset.startVoiceRecognition(
+                                                                           mBluetoothHeadsetDevice);
+                                    }
+
+                                    if (status) {
+                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                    } else {
+                                        broadcastScoConnectionState(
+                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                                    }
+                                } else if (getBluetoothHeadset()) {
+                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                                }
+                            } else {
+                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+                            }
+                        } else {
+                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        }
+                    }
+                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
+                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
+                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
+                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
+                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
+                            boolean status = false;
+                            if (mScoAudioMode == SCO_MODE_RAW) {
+                                status = mBluetoothHeadset.disconnectAudio();
+                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
+                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                            } else if (mScoAudioMode == SCO_MODE_VR) {
+                                        status = mBluetoothHeadset.stopVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
+                            }
+
+                            if (!status) {
+                                mScoAudioState = SCO_STATE_INACTIVE;
+                                broadcastScoConnectionState(
+                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                            }
+                        } else if (getBluetoothHeadset()) {
+                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
+                        }
+                    } else {
+                        mScoAudioState = SCO_STATE_INACTIVE;
+                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                    }
+                }
+            }
+        }
+    }
+
+    private void checkScoAudioState() {
+        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
+                mScoAudioState == SCO_STATE_INACTIVE &&
+                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
+                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
+            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+        }
+    }
+
+    private ScoClient getScoClient(IBinder cb, boolean create) {
+        synchronized(mScoClients) {
+            ScoClient client = null;
+            int size = mScoClients.size();
+            for (int i = 0; i < size; i++) {
+                client = mScoClients.get(i);
+                if (client.getBinder() == cb)
+                    return client;
+            }
+            if (create) {
+                client = new ScoClient(cb);
+                mScoClients.add(client);
+            }
+            return client;
+        }
+    }
+
+    public void clearAllScoClients(int exceptPid, boolean stopSco) {
+        synchronized(mScoClients) {
+            ScoClient savedClient = null;
+            int size = mScoClients.size();
+            for (int i = 0; i < size; i++) {
+                ScoClient cl = mScoClients.get(i);
+                if (cl.getPid() != exceptPid) {
+                    cl.clearCount(stopSco);
+                } else {
+                    savedClient = cl;
+                }
+            }
+            mScoClients.clear();
+            if (savedClient != null) {
+                mScoClients.add(savedClient);
+            }
+        }
+    }
+
+    private boolean getBluetoothHeadset() {
+        boolean result = false;
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+                                    BluetoothProfile.HEADSET);
+        }
+        // If we could not get a bluetooth headset proxy, send a failure message
+        // without delay to reset the SCO audio state and clear SCO clients.
+        // If we could get a proxy, send a delayed failure message that will reset our state
+        // in case we don't receive onServiceConnected().
+        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
+                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
+        return result;
+    }
+
+    private void disconnectBluetoothSco(int exceptPid) {
+        synchronized(mScoClients) {
+            checkScoAudioState();
+            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
+                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
+                if (mBluetoothHeadsetDevice != null) {
+                    if (mBluetoothHeadset != null) {
+                        if (!mBluetoothHeadset.stopVoiceRecognition(
+                                mBluetoothHeadsetDevice)) {
+                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
+                                    SENDMSG_REPLACE, 0, 0, null, 0);
+                        }
+                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
+                            getBluetoothHeadset()) {
+                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
+                    }
+                }
+            } else {
+                clearAllScoClients(exceptPid, true);
+            }
+        }
+    }
+
+    private void resetBluetoothSco() {
+        synchronized(mScoClients) {
+            clearAllScoClients(0, false);
+            mScoAudioState = SCO_STATE_INACTIVE;
+            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        }
+    }
+
+    private void broadcastScoConnectionState(int state) {
+        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
+                SENDMSG_QUEUE, state, 0, null, 0);
+    }
+
+    private void onBroadcastScoConnectionState(int state) {
+        if (state != mScoConnectionState) {
+            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
+            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
+            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
+                    mScoConnectionState);
+            sendStickyBroadcastToAll(newIntent);
+            mScoConnectionState = state;
+        }
+    }
+
+    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
+        new BluetoothProfile.ServiceListener() {
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            BluetoothDevice btDevice;
+            List<BluetoothDevice> deviceList;
+            switch(profile) {
+            case BluetoothProfile.A2DP:
+                synchronized (mConnectedDevices) {
+                    synchronized (mA2dpAvrcpLock) {
+                        mA2dp = (BluetoothA2dp) proxy;
+                        deviceList = mA2dp.getConnectedDevices();
+                        if (deviceList.size() > 0) {
+                            btDevice = deviceList.get(0);
+                            int state = mA2dp.getConnectionState(btDevice);
+                            int delay = checkSendBecomingNoisyIntent(
+                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
+                            queueMsgUnderWakeLock(mAudioHandler,
+                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
+                                    state,
+                                    0,
+                                    btDevice,
+                                    delay);
+                        }
+                    }
+                }
+                break;
+
+            case BluetoothProfile.A2DP_SINK:
+                deviceList = proxy.getConnectedDevices();
+                if (deviceList.size() > 0) {
+                    btDevice = deviceList.get(0);
+                    synchronized (mConnectedDevices) {
+                        int state = proxy.getConnectionState(btDevice);
+                        queueMsgUnderWakeLock(mAudioHandler,
+                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
+                                state,
+                                0,
+                                btDevice,
+                                0 /* delay */);
+                    }
+                }
+                break;
+
+            case BluetoothProfile.HEADSET:
+                synchronized (mScoClients) {
+                    // Discard timeout message
+                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
+                    mBluetoothHeadset = (BluetoothHeadset) proxy;
+                    deviceList = mBluetoothHeadset.getConnectedDevices();
+                    if (deviceList.size() > 0) {
+                        mBluetoothHeadsetDevice = deviceList.get(0);
+                    } else {
+                        mBluetoothHeadsetDevice = null;
+                    }
+                    // Refresh SCO audio state
+                    checkScoAudioState();
+                    // Continue pending action if any
+                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
+                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
+                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
+                        boolean status = false;
+                        if (mBluetoothHeadsetDevice != null) {
+                            switch (mScoAudioState) {
+                            case SCO_STATE_ACTIVATE_REQ:
+                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.connectAudio();
+                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
+                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                } else if (mScoAudioMode == SCO_MODE_VR) {
+                                    status = mBluetoothHeadset.startVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
+                                }
+                                break;
+                            case SCO_STATE_DEACTIVATE_REQ:
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.disconnectAudio();
+                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
+                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                } else if (mScoAudioMode == SCO_MODE_VR) {
+                                    status = mBluetoothHeadset.stopVoiceRecognition(
+                                                                      mBluetoothHeadsetDevice);
+                                }
+                                break;
+                            case SCO_STATE_DEACTIVATE_EXT_REQ:
+                                status = mBluetoothHeadset.stopVoiceRecognition(
+                                        mBluetoothHeadsetDevice);
+                            }
+                        }
+                        if (!status) {
+                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
+                                    SENDMSG_REPLACE, 0, 0, null, 0);
+                        }
+                    }
+                }
+                break;
+
+            default:
+                break;
+            }
+        }
+        public void onServiceDisconnected(int profile) {
+            switch (profile) {
+            case BluetoothProfile.A2DP:
+                synchronized (mConnectedDevices) {
+                    synchronized (mA2dpAvrcpLock) {
+                        // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+                        for(Map.Entry<String, DeviceListSpec> entry
+                                : mConnectedDevices.entrySet()) {
+                            DeviceListSpec deviceSpec = entry.getValue();
+                            if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                                makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
+                            }
+                        }
+                    }
+                }
+                break;
+
+            case BluetoothProfile.A2DP_SINK:
+                synchronized (mConnectedDevices) {
+                    // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
+                    for(Map.Entry<String, DeviceListSpec> entry
+                            : mConnectedDevices.entrySet()) {
+                        DeviceListSpec deviceSpec = entry.getValue();
+                        if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
+                            makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
+                        }
+                    }
+                }
+                break;
+
+            case BluetoothProfile.HEADSET:
+                synchronized (mScoClients) {
+                    mBluetoothHeadset = null;
+                }
+                break;
+
+            default:
+                break;
+            }
+        }
+    };
+
+    private void onCheckMusicActive(String caller) {
+        synchronized (mSafeMediaVolumeState) {
+            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
+                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+
+                if ((device & mSafeMediaVolumeDevices) != 0) {
+                    sendMsg(mAudioHandler,
+                            MSG_CHECK_MUSIC_ACTIVE,
+                            SENDMSG_REPLACE,
+                            0,
+                            0,
+                            caller,
+                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
+                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
+                            (index > mSafeMediaVolumeIndex)) {
+                        // Approximate cumulative active music time
+                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
+                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
+                            setSafeMediaVolumeEnabled(true, caller);
+                            mMusicActiveMs = 0;
+                        }
+                        saveMusicActiveMs();
+                    }
+                }
+            }
+        }
+    }
+
+    private void saveMusicActiveMs() {
+        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
+    }
+
+    private void onConfigureSafeVolume(boolean force, String caller) {
+        synchronized (mSafeMediaVolumeState) {
+            int mcc = mContext.getResources().getConfiguration().mcc;
+            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
+                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
+                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+                boolean safeMediaVolumeEnabled =
+                        SystemProperties.getBoolean("audio.safemedia.force", false)
+                        || mContext.getResources().getBoolean(
+                                com.android.internal.R.bool.config_safe_media_volume_enabled);
+
+                // The persisted state is either "disabled" or "active": this is the state applied
+                // next time we boot and cannot be "inactive"
+                int persistedState;
+                if (safeMediaVolumeEnabled) {
+                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
+                    // The state can already be "inactive" here if the user has forced it before
+                    // the 30 seconds timeout for forced configuration. In this case we don't reset
+                    // it to "active".
+                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
+                        if (mMusicActiveMs == 0) {
+                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                            enforceSafeMediaVolume(caller);
+                        } else {
+                            // We have existing playback time recorded, already confirmed.
+                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+                        }
+                    }
+                } else {
+                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
+                }
+                mMcc = mcc;
+                sendMsg(mAudioHandler,
+                        MSG_PERSIST_SAFE_VOLUME_STATE,
+                        SENDMSG_QUEUE,
+                        persistedState,
+                        0,
+                        null,
+                        0);
+            }
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Internal methods
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Checks if the adjustment should change ringer mode instead of just
+     * adjusting volume. If so, this will set the proper ringer mode and volume
+     * indices on the stream states.
+     */
+    private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
+        final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
+        int result = FLAG_ADJUST_VOLUME;
+        int ringerMode = getRingerModeInternal();
+
+        switch (ringerMode) {
+        case RINGER_MODE_NORMAL:
+            if (direction == AudioManager.ADJUST_LOWER) {
+                if (mHasVibrator) {
+                    // "step" is the delta in internal index units corresponding to a
+                    // change of 1 in UI index units.
+                    // Because of rounding when rescaling from one stream index range to its alias
+                    // index range, we cannot simply test oldIndex == step:
+                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
+                    if (step <= oldIndex && oldIndex < 2 * step) {
+                        ringerMode = RINGER_MODE_VIBRATE;
+                        mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
+                    }
+                } else {
+                    // (oldIndex < step) is equivalent to (old UI index == 0)
+                    if ((oldIndex < step)
+                            && mVolumePolicy.volumeDownToEnterSilent
+                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                        ringerMode = RINGER_MODE_SILENT;
+                    }
+                }
+            } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_MUTE)) {
+                if (mHasVibrator) {
+                    ringerMode = RINGER_MODE_VIBRATE;
+                } else {
+                    ringerMode = RINGER_MODE_SILENT;
+                }
+                // Setting the ringer mode will toggle mute
+                result &= ~FLAG_ADJUST_VOLUME;
+            }
+            break;
+        case RINGER_MODE_VIBRATE:
+            if (!mHasVibrator) {
+                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
+                        "but no vibrator is present");
+                break;
+            }
+            if ((direction == AudioManager.ADJUST_LOWER)) {
+                // This is the case we were muted with the volume turned up
+                if (isTv && oldIndex >= 2 * step && isMuted) {
+                    ringerMode = RINGER_MODE_NORMAL;
+                } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
+                    if (mVolumePolicy.volumeDownToEnterSilent) {
+                        final long diff = SystemClock.uptimeMillis()
+                                - mLoweredFromNormalToVibrateTime;
+                        if (diff > mVolumePolicy.vibrateToSilentDebounce) {
+                            ringerMode = RINGER_MODE_SILENT;
+                        }
+                    } else {
+                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
+                    }
+                }
+            } else if (direction == AudioManager.ADJUST_RAISE
+                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
+                ringerMode = RINGER_MODE_NORMAL;
+            }
+            result &= ~FLAG_ADJUST_VOLUME;
+            break;
+        case RINGER_MODE_SILENT:
+            if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
+                // This is the case we were muted with the volume turned up
+                ringerMode = RINGER_MODE_NORMAL;
+            } else if (direction == AudioManager.ADJUST_RAISE
+                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
+                if (!mVolumePolicy.volumeUpToExitSilent) {
+                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
+                } else {
+                  if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
+                      ringerMode = RINGER_MODE_VIBRATE;
+                  } else {
+                      // If we don't have a vibrator or they were toggling mute
+                      // go straight back to normal.
+                      ringerMode = RINGER_MODE_NORMAL;
+                  }
+                }
+            }
+            result &= ~FLAG_ADJUST_VOLUME;
+            break;
+        default:
+            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
+            break;
+        }
+
+        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
+
+        mPrevVolDirection = direction;
+
+        return result;
+    }
+
+    @Override
+    public boolean isStreamAffectedByRingerMode(int streamType) {
+        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
+    }
+
+    private boolean isStreamMutedByRingerMode(int streamType) {
+        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
+    }
+
+    boolean updateRingerModeAffectedStreams() {
+        int ringerModeAffectedStreams;
+        // make sure settings for ringer mode are consistent with device type: non voice capable
+        // devices (tablets) include media stream in silent mode whereas phones don't.
+        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
+                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
+                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
+                 UserHandle.USER_CURRENT);
+
+        // ringtone, notification and system streams are always affected by ringer mode
+        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
+                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
+                                        (1 << AudioSystem.STREAM_SYSTEM);
+
+        switch (mPlatformType) {
+            case AudioSystem.PLATFORM_TELEVISION:
+                ringerModeAffectedStreams = 0;
+                break;
+            default:
+                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
+                break;
+        }
+
+        synchronized (mCameraSoundForced) {
+            if (mCameraSoundForced) {
+                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+            } else {
+                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+            }
+        }
+        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
+            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
+        } else {
+            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
+        }
+
+        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
+            Settings.System.putIntForUser(mContentResolver,
+                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+                    ringerModeAffectedStreams,
+                    UserHandle.USER_CURRENT);
+            mRingerModeAffectedStreams = ringerModeAffectedStreams;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isStreamAffectedByMute(int streamType) {
+        return (mMuteAffectedStreams & (1 << streamType)) != 0;
+    }
+
+    private void ensureValidDirection(int direction) {
+        switch (direction) {
+            case AudioManager.ADJUST_LOWER:
+            case AudioManager.ADJUST_RAISE:
+            case AudioManager.ADJUST_SAME:
+            case AudioManager.ADJUST_MUTE:
+            case AudioManager.ADJUST_UNMUTE:
+            case AudioManager.ADJUST_TOGGLE_MUTE:
+                break;
+            default:
+                throw new IllegalArgumentException("Bad direction " + direction);
+        }
+    }
+
+    private void ensureValidSteps(int steps) {
+        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
+            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
+        }
+    }
+
+    private void ensureValidStreamType(int streamType) {
+        if (streamType < 0 || streamType >= mStreamStates.length) {
+            throw new IllegalArgumentException("Bad stream type " + streamType);
+        }
+    }
+
+    private boolean isMuteAdjust(int adjust) {
+        return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
+                || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
+    }
+
+    private boolean isInCommunication() {
+        boolean IsInCall = false;
+
+        TelecomManager telecomManager =
+                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+
+        final long ident = Binder.clearCallingIdentity();
+        IsInCall = telecomManager.isInCall();
+        Binder.restoreCallingIdentity(ident);
+
+        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
+    }
+
+    /**
+     * For code clarity for getActiveStreamType(int)
+     * @param delay_ms max time since last STREAM_MUSIC activity to consider
+     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
+     *     in the last "delay_ms" ms.
+     */
+    private boolean isAfMusicActiveRecently(int delay_ms) {
+        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
+                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
+    }
+
+    private int getActiveStreamType(int suggestedStreamType) {
+        switch (mPlatformType) {
+        case AudioSystem.PLATFORM_VOICE:
+            if (isInCommunication()) {
+                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
+                        == AudioSystem.FORCE_BT_SCO) {
+                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
+                    return AudioSystem.STREAM_BLUETOOTH_SCO;
+                } else {
+                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
+                    return AudioSystem.STREAM_VOICE_CALL;
+                }
+            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+                    if (DEBUG_VOL)
+                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
+                    return AudioSystem.STREAM_MUSIC;
+                    } else {
+                        if (DEBUG_VOL)
+                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
+                        return AudioSystem.STREAM_RING;
+                }
+            } else if (isAfMusicActiveRecently(0)) {
+                if (DEBUG_VOL)
+                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
+                return AudioSystem.STREAM_MUSIC;
+            }
+            break;
+        case AudioSystem.PLATFORM_TELEVISION:
+            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+                    // TV always defaults to STREAM_MUSIC
+                    return AudioSystem.STREAM_MUSIC;
+            }
+            break;
+        default:
+            if (isInCommunication()) {
+                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
+                        == AudioSystem.FORCE_BT_SCO) {
+                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
+                    return AudioSystem.STREAM_BLUETOOTH_SCO;
+                } else {
+                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
+                    return AudioSystem.STREAM_VOICE_CALL;
+                }
+            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
+                    StreamOverride.sDelayMs) ||
+                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
+                            StreamOverride.sDelayMs)) {
+                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
+                return AudioSystem.STREAM_NOTIFICATION;
+            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
+                    return AudioSystem.STREAM_MUSIC;
+                } else {
+                    if (DEBUG_VOL) Log.v(TAG,
+                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
+                    return AudioSystem.STREAM_NOTIFICATION;
+                }
+            }
+            break;
+        }
+        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
+                + suggestedStreamType);
+        return suggestedStreamType;
+    }
+
+    private void broadcastRingerMode(String action, int ringerMode) {
+        // Send sticky broadcast
+        Intent broadcast = new Intent(action);
+        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
+        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        sendStickyBroadcastToAll(broadcast);
+    }
+
+    private void broadcastVibrateSetting(int vibrateType) {
+        // Send broadcast
+        if (ActivityManagerNative.isSystemReady()) {
+            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
+            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
+            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
+            sendBroadcastToAll(broadcast);
+        }
+    }
+
+    // Message helper methods
+    /**
+     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
+     * Note that the wake lock needs to be released after the message has been handled.
+     */
+    private void queueMsgUnderWakeLock(Handler handler, int msg,
+            int arg1, int arg2, Object obj, int delay) {
+        final long ident = Binder.clearCallingIdentity();
+        // Always acquire the wake lock as AudioService because it is released by the
+        // message handler.
+        mAudioEventWakeLock.acquire();
+        Binder.restoreCallingIdentity(ident);
+        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
+    }
+
+    private static void sendMsg(Handler handler, int msg,
+            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
+
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+        synchronized (mLastDeviceConnectMsgTime) {
+            long time = SystemClock.uptimeMillis() + delay;
+            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
+            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
+                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
+                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
+                mLastDeviceConnectMsgTime = time;
+            }
+        }
+    }
+
+    boolean checkAudioSettingsPermission(String method) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        String msg = "Audio Settings Permission Denial: " + method + " from pid="
+                + Binder.getCallingPid()
+                + ", uid=" + Binder.getCallingUid();
+        Log.w(TAG, msg);
+        return false;
+    }
+
+    private int getDeviceForStream(int stream) {
+        int device = AudioSystem.getDevicesForStream(stream);
+        if ((device & (device - 1)) != 0) {
+            // Multiple device selection is either:
+            //  - speaker + one other device: give priority to speaker in this case.
+            //  - one A2DP device + another device: happens with duplicated output. In this case
+            // retain the device on the A2DP output as the other must not correspond to an active
+            // selection if not the speaker.
+            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
+            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
+                device = AudioSystem.DEVICE_OUT_SPEAKER;
+            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
+                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
+            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
+                device = AudioSystem.DEVICE_OUT_SPDIF;
+            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
+                device = AudioSystem.DEVICE_OUT_AUX_LINE;
+            } else {
+                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
+            }
+        }
+        return device;
+    }
+
+    /*
+     * A class just for packaging up a set of connection parameters.
+     */
+    private class WiredDeviceConnectionState {
+        public final int mType;
+        public final int mState;
+        public final String mAddress;
+        public final String mName;
+        public final String mCaller;
+
+        public WiredDeviceConnectionState(int type, int state, String address, String name,
+                String caller) {
+            mType = type;
+            mState = state;
+            mAddress = address;
+            mName = name;
+            mCaller = caller;
+        }
+    }
+
+    public void setWiredDeviceConnectionState(int type, int state, String address, String name,
+            String caller) {
+        synchronized (mConnectedDevices) {
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+                        + address + ")");
+            }
+            int delay = checkSendBecomingNoisyIntent(type, state);
+            queueMsgUnderWakeLock(mAudioHandler,
+                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
+                    0,
+                    0,
+                    new WiredDeviceConnectionState(type, state, address, name, caller),
+                    delay);
+        }
+    }
+
+    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
+    {
+        int delay;
+        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
+            throw new IllegalArgumentException("invalid profile " + profile);
+        }
+        synchronized (mConnectedDevices) {
+            if (profile == BluetoothProfile.A2DP) {
+                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
+            } else {
+                delay = 0;
+            }
+            queueMsgUnderWakeLock(mAudioHandler,
+                    (profile == BluetoothProfile.A2DP ?
+                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
+                    state,
+                    0,
+                    device,
+                    delay);
+        }
+        return delay;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Inner classes
+    ///////////////////////////////////////////////////////////////////////////
+
+    // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
+    //  1 mScoclient OR mSafeMediaVolumeState
+    //  2   mSetModeDeathHandlers
+    //  3     mSettingsLock
+    //  4       VolumeStreamState.class
+    //  5         mCameraSoundForced
+    public class VolumeStreamState {
+        private final int mStreamType;
+        private final int mIndexMin;
+        private final int mIndexMax;
+
+        private boolean mIsMuted;
+        private String mVolumeIndexSettingName;
+
+        private final SparseIntArray mIndexMap = new SparseIntArray(8);
+        private final Intent mVolumeChanged;
+
+        private VolumeStreamState(String settingName, int streamType) {
+
+            mVolumeIndexSettingName = settingName;
+
+            mStreamType = streamType;
+            mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
+            mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
+            AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
+
+            readSettings();
+            mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
+            mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+        }
+
+        public String getSettingNameForDevice(int device) {
+            String name = mVolumeIndexSettingName;
+            String suffix = AudioSystem.getOutputDeviceName(device);
+            if (suffix.isEmpty()) {
+                return name;
+            }
+            return name + "_" + suffix;
+        }
+
+        public void readSettings() {
+            synchronized (VolumeStreamState.class) {
+                // force maximum volume on all streams if fixed volume property is set
+                if (mUseFixedVolume) {
+                    mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
+                    return;
+                }
+                // do not read system stream volume from settings: this stream is always aliased
+                // to another stream type and its volume is never persisted. Values in settings can
+                // only be stale values
+                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
+                    int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
+                    synchronized (mCameraSoundForced) {
+                        if (mCameraSoundForced) {
+                            index = mIndexMax;
+                        }
+                    }
+                    mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+                    return;
+                }
+
+                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
+
+                for (int i = 0; remainingDevices != 0; i++) {
+                    int device = (1 << i);
+                    if ((device & remainingDevices) == 0) {
+                        continue;
+                    }
+                    remainingDevices &= ~device;
+
+                    // retrieve current volume for device
+                    String name = getSettingNameForDevice(device);
+                    // if no volume stored for current stream and device, use default volume if default
+                    // device, continue otherwise
+                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
+                            AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
+                    int index = Settings.System.getIntForUser(
+                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
+                    if (index == -1) {
+                        continue;
+                    }
+
+                    mIndexMap.put(device, getValidIndex(10 * index));
+                }
+            }
+        }
+
+        // must be called while synchronized VolumeStreamState.class
+        public void applyDeviceVolume_syncVSS(int device) {
+            int index;
+            if (mIsMuted) {
+                index = 0;
+            } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
+                    || ((device & mFullVolumeDevices) != 0)) {
+                index = (mIndexMax + 5)/10;
+            } else {
+                index = (getIndex(device) + 5)/10;
+            }
+            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
+        }
+
+        public void applyAllVolumes() {
+            synchronized (VolumeStreamState.class) {
+                // apply default volume first: by convention this will reset all
+                // devices volumes in audio policy manager to the supplied value
+                int index;
+                if (mIsMuted) {
+                    index = 0;
+                } else {
+                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
+                }
+                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
+                // then apply device specific volumes
+                for (int i = 0; i < mIndexMap.size(); i++) {
+                    int device = mIndexMap.keyAt(i);
+                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
+                        if (mIsMuted) {
+                            index = 0;
+                        } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                                mAvrcpAbsVolSupported)
+                                    || ((device & mFullVolumeDevices) != 0))
+                        {
+                            index = (mIndexMax + 5)/10;
+                        } else {
+                            index = (mIndexMap.valueAt(i) + 5)/10;
+                        }
+                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
+                    }
+                }
+            }
+        }
+
+        public boolean adjustIndex(int deltaIndex, int device, String caller) {
+            return setIndex(getIndex(device) + deltaIndex, device, caller);
+        }
+
+        public boolean setIndex(int index, int device, String caller) {
+            boolean changed = false;
+            int oldIndex;
+            synchronized (VolumeStreamState.class) {
+                oldIndex = getIndex(device);
+                index = getValidIndex(index);
+                synchronized (mCameraSoundForced) {
+                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
+                        index = mIndexMax;
+                    }
+                }
+                mIndexMap.put(device, index);
+
+                changed = oldIndex != index;
+                if (changed) {
+                    // Apply change to all streams using this one as alias
+                    // if changing volume of current device, also change volume of current
+                    // device on aliased stream
+                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
+                    int numStreamTypes = AudioSystem.getNumStreamTypes();
+                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                        if (streamType != mStreamType &&
+                                mStreamVolumeAlias[streamType] == mStreamType) {
+                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+                            mStreamStates[streamType].setIndex(scaledIndex, device, caller);
+                            if (currentDevice) {
+                                mStreamStates[streamType].setIndex(scaledIndex,
+                                        getDeviceForStream(streamType), caller);
+                            }
+                        }
+                    }
+                }
+            }
+            if (changed) {
+                oldIndex = (oldIndex + 5) / 10;
+                index = (index + 5) / 10;
+                // log base stream changes to the event log
+                if (mStreamVolumeAlias[mStreamType] == mStreamType) {
+                    if (caller == null) {
+                        Log.w(TAG, "No caller for volume_changed event", new Throwable());
+                    }
+                    EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
+                            caller);
+                }
+                // fire changed intents for all streams
+                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
+                sendBroadcastToAll(mVolumeChanged);
+            }
+            return changed;
+        }
+
+        public int getIndex(int device) {
+            synchronized (VolumeStreamState.class) {
+                int index = mIndexMap.get(device, -1);
+                if (index == -1) {
+                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
+                    index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
+                }
+                return index;
+            }
+        }
+
+        public int getMaxIndex() {
+            return mIndexMax;
+        }
+
+        public int getMinIndex() {
+            return mIndexMin;
+        }
+
+        public void setAllIndexes(VolumeStreamState srcStream, String caller) {
+            synchronized (VolumeStreamState.class) {
+                int srcStreamType = srcStream.getStreamType();
+                // apply default device volume from source stream to all devices first in case
+                // some devices are present in this stream state but not in source stream state
+                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
+                index = rescaleIndex(index, srcStreamType, mStreamType);
+                for (int i = 0; i < mIndexMap.size(); i++) {
+                    mIndexMap.put(mIndexMap.keyAt(i), index);
+                }
+                // Now apply actual volume for devices in source stream state
+                SparseIntArray srcMap = srcStream.mIndexMap;
+                for (int i = 0; i < srcMap.size(); i++) {
+                    int device = srcMap.keyAt(i);
+                    index = srcMap.valueAt(i);
+                    index = rescaleIndex(index, srcStreamType, mStreamType);
+
+                    setIndex(index, device, caller);
+                }
+            }
+        }
+
+        public void setAllIndexesToMax() {
+            synchronized (VolumeStreamState.class) {
+                for (int i = 0; i < mIndexMap.size(); i++) {
+                    mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
+                }
+            }
+        }
+
+        public void mute(boolean state) {
+            boolean changed = false;
+            synchronized (VolumeStreamState.class) {
+                if (state != mIsMuted) {
+                    changed = true;
+                    mIsMuted = state;
+
+                    // Set the new mute volume. This propagates the values to
+                    // the audio system, otherwise the volume won't be changed
+                    // at the lower level.
+                    sendMsg(mAudioHandler,
+                            MSG_SET_ALL_VOLUMES,
+                            SENDMSG_QUEUE,
+                            0,
+                            0,
+                            this, 0);
+                }
+            }
+            if (changed) {
+                // Stream mute changed, fire the intent.
+                Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+                intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+                intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
+                sendBroadcastToAll(intent);
+            }
+        }
+
+        public int getStreamType() {
+            return mStreamType;
+        }
+
+        public void checkFixedVolumeDevices() {
+            synchronized (VolumeStreamState.class) {
+                // ignore settings for fixed volume devices: volume should always be at max or 0
+                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
+                    for (int i = 0; i < mIndexMap.size(); i++) {
+                        int device = mIndexMap.keyAt(i);
+                        int index = mIndexMap.valueAt(i);
+                        if (((device & mFullVolumeDevices) != 0)
+                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
+                            mIndexMap.put(device, mIndexMax);
+                        }
+                        applyDeviceVolume_syncVSS(device);
+                    }
+                }
+            }
+        }
+
+        private int getValidIndex(int index) {
+            if (index < mIndexMin) {
+                return mIndexMin;
+            } else if (mUseFixedVolume || index > mIndexMax) {
+                return mIndexMax;
+            }
+
+            return index;
+        }
+
+        private void dump(PrintWriter pw) {
+            pw.print("   Muted: ");
+            pw.println(mIsMuted);
+            pw.print("   Min: ");
+            pw.println((mIndexMin + 5) / 10);
+            pw.print("   Max: ");
+            pw.println((mIndexMax + 5) / 10);
+            pw.print("   Current: ");
+            for (int i = 0; i < mIndexMap.size(); i++) {
+                if (i > 0) {
+                    pw.print(", ");
+                }
+                final int device = mIndexMap.keyAt(i);
+                pw.print(Integer.toHexString(device));
+                final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
+                        : AudioSystem.getOutputDeviceName(device);
+                if (!deviceName.isEmpty()) {
+                    pw.print(" (");
+                    pw.print(deviceName);
+                    pw.print(")");
+                }
+                pw.print(": ");
+                final int index = (mIndexMap.valueAt(i) + 5) / 10;
+                pw.print(index);
+            }
+            pw.println();
+            pw.print("   Devices: ");
+            final int devices = AudioSystem.getDevicesForStream(mStreamType);
+            int device, i = 0, n = 0;
+            // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
+            // (the default device is not returned by getDevicesForStream)
+            while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
+                if ((devices & device) != 0) {
+                    if (n++ > 0) {
+                        pw.print(", ");
+                    }
+                    pw.print(AudioSystem.getOutputDeviceName(device));
+                }
+                i++;
+            }
+        }
+    }
+
+    /** Thread that handles native AudioSystem control. */
+    private class AudioSystemThread extends Thread {
+        AudioSystemThread() {
+            super("AudioService");
+        }
+
+        @Override
+        public void run() {
+            // Set this thread up so the handler will work on it
+            Looper.prepare();
+
+            synchronized(AudioService.this) {
+                mAudioHandler = new AudioHandler();
+
+                // Notify that the handler has been created
+                AudioService.this.notify();
+            }
+
+            // Listen for volume change requests that are set by VolumePanel
+            Looper.loop();
+        }
+    }
+
+    /** Handles internal volume messages in separate volume thread. */
+    private class AudioHandler extends Handler {
+
+        private void setDeviceVolume(VolumeStreamState streamState, int device) {
+
+            synchronized (VolumeStreamState.class) {
+                // Apply volume
+                streamState.applyDeviceVolume_syncVSS(device);
+
+                // Apply change to all streams using this one as alias
+                int numStreamTypes = AudioSystem.getNumStreamTypes();
+                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                    if (streamType != streamState.mStreamType &&
+                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+                        // Make sure volume is also maxed out on A2DP device for aliased stream
+                        // that may have a different device selected
+                        int streamDevice = getDeviceForStream(streamType);
+                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
+                        }
+                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
+                    }
+                }
+            }
+            // Post a persist volume msg
+            sendMsg(mAudioHandler,
+                    MSG_PERSIST_VOLUME,
+                    SENDMSG_QUEUE,
+                    device,
+                    0,
+                    streamState,
+                    PERSIST_DELAY);
+
+        }
+
+        private void setAllVolumes(VolumeStreamState streamState) {
+
+            // Apply volume
+            streamState.applyAllVolumes();
+
+            // Apply change to all streams using this one as alias
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                if (streamType != streamState.mStreamType &&
+                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+                    mStreamStates[streamType].applyAllVolumes();
+                }
+            }
+        }
+
+        private void persistVolume(VolumeStreamState streamState, int device) {
+            if (mUseFixedVolume) {
+                return;
+            }
+            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
+                return;
+            }
+            System.putIntForUser(mContentResolver,
+                      streamState.getSettingNameForDevice(device),
+                      (streamState.getIndex(device) + 5)/ 10,
+                      UserHandle.USER_CURRENT);
+        }
+
+        private void persistRingerMode(int ringerMode) {
+            if (mUseFixedVolume) {
+                return;
+            }
+            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
+        }
+
+        private boolean onLoadSoundEffects() {
+            int status;
+
+            synchronized (mSoundEffectsLock) {
+                if (!mSystemReady) {
+                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
+                    return false;
+                }
+
+                if (mSoundPool != null) {
+                    return true;
+                }
+
+                loadTouchSoundAssets();
+
+                mSoundPool = new SoundPool.Builder()
+                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
+                        .setAudioAttributes(new AudioAttributes.Builder()
+                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                            .build())
+                        .build();
+                mSoundPoolCallBack = null;
+                mSoundPoolListenerThread = new SoundPoolListenerThread();
+                mSoundPoolListenerThread.start();
+                int attempts = 3;
+                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
+                    try {
+                        // Wait for mSoundPoolCallBack to be set by the other thread
+                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+                    } catch (InterruptedException e) {
+                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
+                    }
+                }
+
+                if (mSoundPoolCallBack == null) {
+                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
+                    if (mSoundPoolLooper != null) {
+                        mSoundPoolLooper.quit();
+                        mSoundPoolLooper = null;
+                    }
+                    mSoundPoolListenerThread = null;
+                    mSoundPool.release();
+                    mSoundPool = null;
+                    return false;
+                }
+                /*
+                 * poolId table: The value -1 in this table indicates that corresponding
+                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
+                 * Once loaded, the value in poolId is the sample ID and the same
+                 * sample can be reused for another effect using the same file.
+                 */
+                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
+                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
+                    poolId[fileIdx] = -1;
+                }
+                /*
+                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
+                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
+                 * this indicates we have a valid sample loaded for this effect.
+                 */
+
+                int numSamples = 0;
+                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                    // Do not load sample if this effect uses the MediaPlayer
+                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
+                        continue;
+                    }
+                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
+                        String filePath = Environment.getRootDirectory()
+                                + SOUND_EFFECTS_PATH
+                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
+                        int sampleId = mSoundPool.load(filePath, 0);
+                        if (sampleId <= 0) {
+                            Log.w(TAG, "Soundpool could not load file: "+filePath);
+                        } else {
+                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
+                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
+                            numSamples++;
+                        }
+                    } else {
+                        SOUND_EFFECT_FILES_MAP[effect][1] =
+                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
+                    }
+                }
+                // wait for all samples to be loaded
+                if (numSamples > 0) {
+                    mSoundPoolCallBack.setSamples(poolId);
+
+                    attempts = 3;
+                    status = 1;
+                    while ((status == 1) && (attempts-- > 0)) {
+                        try {
+                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+                            status = mSoundPoolCallBack.status();
+                        } catch (InterruptedException e) {
+                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
+                        }
+                    }
+                } else {
+                    status = -1;
+                }
+
+                if (mSoundPoolLooper != null) {
+                    mSoundPoolLooper.quit();
+                    mSoundPoolLooper = null;
+                }
+                mSoundPoolListenerThread = null;
+                if (status != 0) {
+                    Log.w(TAG,
+                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
+                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
+                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
+                        }
+                    }
+
+                    mSoundPool.release();
+                    mSoundPool = null;
+                }
+            }
+            return (status == 0);
+        }
+
+        /**
+         *  Unloads samples from the sound pool.
+         *  This method can be called to free some memory when
+         *  sound effects are disabled.
+         */
+        private void onUnloadSoundEffects() {
+            synchronized (mSoundEffectsLock) {
+                if (mSoundPool == null) {
+                    return;
+                }
+
+                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
+                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
+                    poolId[fileIdx] = 0;
+                }
+
+                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
+                        continue;
+                    }
+                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
+                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
+                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
+                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
+                    }
+                }
+                mSoundPool.release();
+                mSoundPool = null;
+            }
+        }
+
+        private void onPlaySoundEffect(int effectType, int volume) {
+            synchronized (mSoundEffectsLock) {
+
+                onLoadSoundEffects();
+
+                if (mSoundPool == null) {
+                    return;
+                }
+                float volFloat;
+                // use default if volume is not specified by caller
+                if (volume < 0) {
+                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
+                } else {
+                    volFloat = volume / 1000.0f;
+                }
+
+                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
+                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
+                                        volFloat, volFloat, 0, 0, 1.0f);
+                } else {
+                    MediaPlayer mediaPlayer = new MediaPlayer();
+                    try {
+                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
+                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+                        mediaPlayer.setDataSource(filePath);
+                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
+                        mediaPlayer.prepare();
+                        mediaPlayer.setVolume(volFloat);
+                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+                            public void onCompletion(MediaPlayer mp) {
+                                cleanupPlayer(mp);
+                            }
+                        });
+                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
+                            public boolean onError(MediaPlayer mp, int what, int extra) {
+                                cleanupPlayer(mp);
+                                return true;
+                            }
+                        });
+                        mediaPlayer.start();
+                    } catch (IOException ex) {
+                        Log.w(TAG, "MediaPlayer IOException: "+ex);
+                    } catch (IllegalArgumentException ex) {
+                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
+                    } catch (IllegalStateException ex) {
+                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
+                    }
+                }
+            }
+        }
+
+        private void cleanupPlayer(MediaPlayer mp) {
+            if (mp != null) {
+                try {
+                    mp.stop();
+                    mp.release();
+                } catch (IllegalStateException ex) {
+                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
+                }
+            }
+        }
+
+        private void setForceUse(int usage, int config) {
+            synchronized (mConnectedDevices) {
+                setForceUseInt_SyncDevices(usage, config);
+            }
+        }
+
+        private void onPersistSafeVolumeState(int state) {
+            Settings.Global.putInt(mContentResolver,
+                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                    state);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+
+                case MSG_SET_DEVICE_VOLUME:
+                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
+                    break;
+
+                case MSG_SET_ALL_VOLUMES:
+                    setAllVolumes((VolumeStreamState) msg.obj);
+                    break;
+
+                case MSG_PERSIST_VOLUME:
+                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
+                    break;
+
+                case MSG_PERSIST_MASTER_VOLUME_MUTE:
+                    if (mUseFixedVolume) {
+                        return;
+                    }
+                    Settings.System.putIntForUser(mContentResolver,
+                                                 Settings.System.VOLUME_MASTER_MUTE,
+                                                 msg.arg1,
+                                                 msg.arg2);
+                    break;
+
+                case MSG_PERSIST_RINGER_MODE:
+                    // note that the value persisted is the current ringer mode, not the
+                    // value of ringer mode as of the time the request was made to persist
+                    persistRingerMode(getRingerModeInternal());
+                    break;
+
+                case MSG_MEDIA_SERVER_DIED:
+                    if (!mSystemReady ||
+                            (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
+                        Log.e(TAG, "Media server died.");
+                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
+                                null, 500);
+                        break;
+                    }
+                    Log.e(TAG, "Media server started.");
+
+                    // indicate to audio HAL that we start the reconfiguration phase after a media
+                    // server crash
+                    // Note that we only execute this when the media server
+                    // process restarts after a crash, not the first time it is started.
+                    AudioSystem.setParameters("restarting=true");
+
+                    readAndSetLowRamDevice();
+
+                    // Restore device connection states
+                    synchronized (mConnectedDevices) {
+                        Set set = mConnectedDevices.entrySet();
+                        Iterator i = set.iterator();
+                        while (i.hasNext()) {
+                            Map.Entry device = (Map.Entry)i.next();
+                            AudioSystem.setDeviceConnectionState(
+                                                            ((Integer)device.getKey()).intValue(),
+                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
+                                                            (String)device.getValue(),
+                                                            "unknown-device");
+                        }
+                    }
+                    // Restore call state
+                    AudioSystem.setPhoneState(mMode);
+
+                    // Restore forced usage for communcations and record
+                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
+                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
+                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
+                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
+
+                    // Restore stream volumes
+                    int numStreamTypes = AudioSystem.getNumStreamTypes();
+                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                        VolumeStreamState streamState = mStreamStates[streamType];
+                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
+
+                        streamState.applyAllVolumes();
+                    }
+
+                    // Restore ringer mode
+                    setRingerModeInt(getRingerModeInternal(), false);
+
+                    // Reset device orientation (if monitored for this device)
+                    if (mMonitorOrientation) {
+                        setOrientationForAudioSystem();
+                    }
+                    if (mMonitorRotation) {
+                        setRotationForAudioSystem();
+                    }
+
+                    synchronized (mBluetoothA2dpEnabledLock) {
+                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
+                                mBluetoothA2dpEnabled ?
+                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
+                    }
+
+                    synchronized (mSettingsLock) {
+                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
+                                mDockAudioMediaEnabled ?
+                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
+                    }
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            if (mHdmiTvClient != null) {
+                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
+                            }
+                        }
+                    }
+
+                    synchronized (mAudioPolicies) {
+                        for(AudioPolicyProxy policy : mAudioPolicies.values()) {
+                            policy.connectMixes();
+                        }
+                    }
+
+                    // indicate the end of reconfiguration phase to audio HAL
+                    AudioSystem.setParameters("restarting=false");
+                    break;
+
+                case MSG_UNLOAD_SOUND_EFFECTS:
+                    onUnloadSoundEffects();
+                    break;
+
+                case MSG_LOAD_SOUND_EFFECTS:
+                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
+                    // can take several dozens of milliseconds to complete
+                    boolean loaded = onLoadSoundEffects();
+                    if (msg.obj != null) {
+                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
+                        synchronized (reply) {
+                            reply.mStatus = loaded ? 0 : -1;
+                            reply.notify();
+                        }
+                    }
+                    break;
+
+                case MSG_PLAY_SOUND_EFFECT:
+                    onPlaySoundEffect(msg.arg1, msg.arg2);
+                    break;
+
+                case MSG_BTA2DP_DOCK_TIMEOUT:
+                    // msg.obj  == address of BTA2DP device
+                    synchronized (mConnectedDevices) {
+                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
+                    }
+                    break;
+
+                case MSG_SET_FORCE_USE:
+                case MSG_SET_FORCE_BT_A2DP_USE:
+                    setForceUse(msg.arg1, msg.arg2);
+                    break;
+
+                case MSG_BT_HEADSET_CNCT_FAILED:
+                    resetBluetoothSco();
+                    break;
+
+                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
+                    {   WiredDeviceConnectionState connectState =
+                            (WiredDeviceConnectionState)msg.obj;
+                        onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
+                                connectState.mAddress, connectState.mName, connectState.mCaller);
+                        mAudioEventWakeLock.release();
+                    }
+                    break;
+
+                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
+                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    mAudioEventWakeLock.release();
+                    break;
+
+                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
+                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    mAudioEventWakeLock.release();
+                    break;
+
+                case MSG_REPORT_NEW_ROUTES: {
+                    int N = mRoutesObservers.beginBroadcast();
+                    if (N > 0) {
+                        AudioRoutesInfo routes;
+                        synchronized (mCurAudioRoutes) {
+                            routes = new AudioRoutesInfo(mCurAudioRoutes);
+                        }
+                        while (N > 0) {
+                            N--;
+                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
+                            try {
+                                obs.dispatchAudioRoutesChanged(routes);
+                            } catch (RemoteException e) {
+                            }
+                        }
+                    }
+                    mRoutesObservers.finishBroadcast();
+                    break;
+                }
+
+                case MSG_CHECK_MUSIC_ACTIVE:
+                    onCheckMusicActive((String) msg.obj);
+                    break;
+
+                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
+                    onSendBecomingNoisyIntent();
+                    break;
+
+                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
+                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
+                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
+                            (String) msg.obj);
+                    break;
+                case MSG_PERSIST_SAFE_VOLUME_STATE:
+                    onPersistSafeVolumeState(msg.arg1);
+                    break;
+
+                case MSG_BROADCAST_BT_CONNECTION_STATE:
+                    onBroadcastScoConnectionState(msg.arg1);
+                    break;
+
+                case MSG_SYSTEM_READY:
+                    onSystemReady();
+                    break;
+
+                case MSG_PERSIST_MUSIC_ACTIVE_MS:
+                    final int musicActiveMs = msg.arg1;
+                    Settings.Secure.putIntForUser(mContentResolver,
+                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
+                            UserHandle.USER_CURRENT);
+                    break;
+                case MSG_PERSIST_MICROPHONE_MUTE:
+                    Settings.System.putIntForUser(mContentResolver,
+                                                 Settings.System.MICROPHONE_MUTE,
+                                                 msg.arg1,
+                                                 msg.arg2);
+                    break;
+                case MSG_UNMUTE_STREAM:
+                    onUnmuteStream(msg.arg1, msg.arg2);
+                    break;
+            }
+        }
+    }
+
+    private class SettingsObserver extends ContentObserver {
+
+        SettingsObserver() {
+            super(new Handler());
+            mContentResolver.registerContentObserver(Settings.System.getUriFor(
+                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
+            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
+            //       However there appear to be some missing locks around mRingerModeMutedStreams
+            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
+            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
+            synchronized (mSettingsLock) {
+                if (updateRingerModeAffectedStreams()) {
+                    /*
+                     * Ensure all stream types that should be affected by ringer mode
+                     * are in the proper state.
+                     */
+                    setRingerModeInt(getRingerModeInternal(), false);
+                }
+                readDockAudioSettings(mContentResolver);
+            }
+        }
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeA2dpDeviceAvailable(String address) {
+        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
+        // audio policy manager
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
+        setBluetoothA2dpOnInt(true);
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
+        // Reset A2DP suspend state each time a new sink is connected
+        AudioSystem.setParameters("A2dpSuspended=false");
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
+    }
+
+    private void onSendBecomingNoisyIntent() {
+        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeA2dpDeviceUnavailableNow(String address) {
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = false;
+        }
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+        synchronized (mCurAudioRoutes) {
+            // Remove A2DP routes as well
+            if (mCurAudioRoutes.bluetoothName != null) {
+                mCurAudioRoutes.bluetoothName = null;
+                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                        SENDMSG_NOOP, 0, 0, null, 0);
+            }
+        }
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeA2dpDeviceUnavailableLater(String address) {
+        // prevent any activity on the A2DP audio output to avoid unwanted
+        // reconnection of the sink.
+        AudioSystem.setParameters("A2dpSuspended=true");
+        // the device will be made unavailable later, so consider it disconnected right away
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+        // send the delayed message to make the device unavailable later
+        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
+        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
+
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeA2dpSrcAvailable(String address) {
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.put(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
+                                   address));
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void makeA2dpSrcUnavailable(String address) {
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
+        mConnectedDevices.remove(
+                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private void cancelA2dpDeviceTimeout() {
+        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
+    }
+
+    // must be called synchronized on mConnectedDevices
+    private boolean hasScheduledA2dpDockTimeout() {
+        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
+    }
+
+    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
+    {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
+        }
+        if (btDevice == null) {
+            return;
+        }
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+
+        synchronized (mConnectedDevices) {
+            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                           btDevice.getAddress());
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
+
+            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+                if (btDevice.isBluetoothDock()) {
+                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
+                        // introduction of a delay for transient disconnections of docks when
+                        // power is rapidly turned off/on, this message will be canceled if
+                        // we reconnect the dock under a preset delay
+                        makeA2dpDeviceUnavailableLater(address);
+                        // the next time isConnected is evaluated, it will be false for the dock
+                    }
+                } else {
+                    makeA2dpDeviceUnavailableNow(address);
+                }
+                synchronized (mCurAudioRoutes) {
+                    if (mCurAudioRoutes.bluetoothName != null) {
+                        mCurAudioRoutes.bluetoothName = null;
+                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                                SENDMSG_NOOP, 0, 0, null, 0);
+                    }
+                }
+            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+                if (btDevice.isBluetoothDock()) {
+                    // this could be a reconnection after a transient disconnection
+                    cancelA2dpDeviceTimeout();
+                    mDockAddress = address;
+                } else {
+                    // this could be a connection of another A2DP device before the timeout of
+                    // a dock: cancel the dock timeout, and make the dock unavailable now
+                    if(hasScheduledA2dpDockTimeout()) {
+                        cancelA2dpDeviceTimeout();
+                        makeA2dpDeviceUnavailableNow(mDockAddress);
+                    }
+                }
+                makeA2dpDeviceAvailable(address);
+                synchronized (mCurAudioRoutes) {
+                    String name = btDevice.getAliasName();
+                    if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
+                        mCurAudioRoutes.bluetoothName = name;
+                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                                SENDMSG_NOOP, 0, 0, null, 0);
+                    }
+                }
+            }
+        }
+    }
+
+    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
+    {
+        if (DEBUG_VOL) {
+            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
+        }
+        if (btDevice == null) {
+            return;
+        }
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+
+        synchronized (mConnectedDevices) {
+            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
+            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            boolean isConnected = deviceSpec != null;
+
+            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
+                makeA2dpSrcUnavailable(address);
+            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
+                makeA2dpSrcAvailable(address);
+            }
+        }
+    }
+
+    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
+        // address is not used for now, but may be used when multiple a2dp devices are supported
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = support;
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_RING], 0);
+        }
+    }
+
+    private boolean handleDeviceConnection(boolean connect, int device, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
+                    + " address:" + address + " name:" + deviceName + ")");
+        }
+        synchronized (mConnectedDevices) {
+            String deviceKey = makeDeviceListKey(device, address);
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceKey:" + deviceKey);
+            }
+            DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+            boolean isConnected = deviceSpec != null;
+            if (DEBUG_DEVICES) {
+                Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
+            }
+            if (connect && !isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+                return true;
+            } else if (!connect && isConnected) {
+                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                        address, deviceName);
+                mConnectedDevices.remove(deviceKey);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
+    // sent if none of these devices is connected.
+    // Access synchronized on mConnectedDevices
+    int mBecomingNoisyIntentDevices =
+            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
+            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
+            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
+            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
+
+    // must be called before removing the device from mConnectedDevices
+    // Called synchronized on mConnectedDevices
+    private int checkSendBecomingNoisyIntent(int device, int state) {
+        int delay = 0;
+        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
+            int devices = 0;
+            for (String key : mConnectedDevices.keySet()) {
+                int dev = mConnectedDevices.get(key).mDeviceType;
+                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
+                        && ((dev & mBecomingNoisyIntentDevices) != 0)) {
+                    devices |= dev;
+                }
+            }
+            if (devices == device) {
+                sendMsg(mAudioHandler,
+                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
+                        SENDMSG_REPLACE,
+                        0,
+                        0,
+                        null,
+                        0);
+                delay = 1000;
+            }
+        }
+
+        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
+                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
+                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
+            synchronized (mLastDeviceConnectMsgTime) {
+                long time = SystemClock.uptimeMillis();
+                if (mLastDeviceConnectMsgTime > time) {
+                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
+                }
+            }
+        }
+        return delay;
+    }
+
+    private void sendDeviceConnectionIntent(int device, int state, String address,
+            String deviceName) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
+                    " state:0x" + Integer.toHexString(state) + " address:" + address +
+                    " name:" + deviceName + ");");
+        }
+        Intent intent = new Intent();
+
+        intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
+        intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
+        intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
+
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+        int connType = 0;
+
+        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
+            connType = AudioRoutesInfo.MAIN_HEADSET;
+            intent.setAction(Intent.ACTION_HEADSET_PLUG);
+            intent.putExtra("microphone", 1);
+        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
+                   device == AudioSystem.DEVICE_OUT_LINE) {
+            /*do apps care about line-out vs headphones?*/
+            connType = AudioRoutesInfo.MAIN_HEADPHONES;
+            intent.setAction(Intent.ACTION_HEADSET_PLUG);
+            intent.putExtra("microphone", 0);
+        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
+                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
+            connType = AudioRoutesInfo.MAIN_HDMI;
+            configureHdmiPlugIntent(intent, state);
+        } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
+            connType = AudioRoutesInfo.MAIN_USB;
+        }
+
+        synchronized (mCurAudioRoutes) {
+            if (connType != 0) {
+                int newConn = mCurAudioRoutes.mainType;
+                if (state != 0) {
+                    newConn |= connType;
+                } else {
+                    newConn &= ~connType;
+                }
+                if (newConn != mCurAudioRoutes.mainType) {
+                    mCurAudioRoutes.mainType = newConn;
+                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+                            SENDMSG_NOOP, 0, 0, null, 0);
+                }
+            }
+        }
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void onSetWiredDeviceConnectionState(int device, int state, String address,
+            String deviceName, String caller) {
+        if (DEBUG_DEVICES) {
+            Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
+                    + " state:" + Integer.toHexString(state)
+                    + " address:" + address
+                    + " deviceName:" + deviceName
+                    + " caller: " + caller + ");");
+        }
+
+        synchronized (mConnectedDevices) {
+            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
+                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
+                    (device == AudioSystem.DEVICE_OUT_LINE))) {
+                setBluetoothA2dpOnInt(true);
+            }
+            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
+                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
+                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
+            handleDeviceConnection(state == 1, device, address, deviceName);
+            if (state != 0) {
+                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
+                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
+                    (device == AudioSystem.DEVICE_OUT_LINE)) {
+                    setBluetoothA2dpOnInt(false);
+                }
+                if ((device & mSafeMediaVolumeDevices) != 0) {
+                    sendMsg(mAudioHandler,
+                            MSG_CHECK_MUSIC_ACTIVE,
+                            SENDMSG_REPLACE,
+                            0,
+                            0,
+                            caller,
+                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                }
+                // Television devices without CEC service apply software volume on HDMI output
+                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
+                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+                    checkAllFixedVolumeDevices();
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            if (mHdmiPlaybackClient != null) {
+                                mHdmiCecSink = false;
+                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
+                            }
+                        }
+                    }
+                }
+            } else {
+                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
+                    if (mHdmiManager != null) {
+                        synchronized (mHdmiManager) {
+                            mHdmiCecSink = false;
+                        }
+                    }
+                }
+            }
+            if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
+                sendDeviceConnectionIntent(device, state, address, deviceName);
+            }
+        }
+    }
+
+    private void configureHdmiPlugIntent(Intent intent, int state) {
+        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
+        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
+        if (state == 1) {
+            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
+            int[] portGeneration = new int[1];
+            int status = AudioSystem.listAudioPorts(ports, portGeneration);
+            if (status == AudioManager.SUCCESS) {
+                for (AudioPort port : ports) {
+                    if (port instanceof AudioDevicePort) {
+                        final AudioDevicePort devicePort = (AudioDevicePort) port;
+                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
+                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
+                            // format the list of supported encodings
+                            int[] formats = devicePort.formats();
+                            if (formats.length > 0) {
+                                ArrayList<Integer> encodingList = new ArrayList(1);
+                                for (int format : formats) {
+                                    // a format in the list can be 0, skip it
+                                    if (format != AudioFormat.ENCODING_INVALID) {
+                                        encodingList.add(format);
+                                    }
+                                }
+                                int[] encodingArray = new int[encodingList.size()];
+                                for (int i = 0 ; i < encodingArray.length ; i++) {
+                                    encodingArray[i] = encodingList.get(i);
+                                }
+                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
+                            }
+                            // find the maximum supported number of channels
+                            int maxChannels = 0;
+                            for (int mask : devicePort.channelMasks()) {
+                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
+                                if (channelCount > maxChannels) {
+                                    maxChannels = channelCount;
+                                }
+                            }
+                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* cache of the address of the last dock the device was connected to */
+    private String mDockAddress;
+
+    /**
+     * Receiver for misc intent broadcasts the Phone app cares about.
+     */
+    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            int outDevice;
+            int inDevice;
+            int state;
+
+            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
+                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                int config;
+                switch (dockState) {
+                    case Intent.EXTRA_DOCK_STATE_DESK:
+                        config = AudioSystem.FORCE_BT_DESK_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_CAR:
+                        config = AudioSystem.FORCE_BT_CAR_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
+                        config = AudioSystem.FORCE_ANALOG_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
+                        config = AudioSystem.FORCE_DIGITAL_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
+                    default:
+                        config = AudioSystem.FORCE_NONE;
+                }
+                // Low end docks have a menu to enable or disable audio
+                // (see mDockAudioMediaEnabled)
+                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
+                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
+                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+                }
+                mDockState = dockState;
+            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
+                                               BluetoothProfile.STATE_DISCONNECTED);
+                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+                String address = null;
+
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (btDevice == null) {
+                    return;
+                }
+
+                address = btDevice.getAddress();
+                BluetoothClass btClass = btDevice.getBluetoothClass();
+                if (btClass != null) {
+                    switch (btClass.getDeviceClass()) {
+                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+                        break;
+                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                        break;
+                    }
+                }
+
+                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+                    address = "";
+                }
+
+                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
+                boolean success =
+                    handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
+                    handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
+                if (success) {
+                    synchronized (mScoClients) {
+                        if (connected) {
+                            mBluetoothHeadsetDevice = btDevice;
+                        } else {
+                            mBluetoothHeadsetDevice = null;
+                            resetBluetoothSco();
+                        }
+                    }
+                }
+            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+                boolean broadcast = false;
+                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
+                synchronized (mScoClients) {
+                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
+                    // broadcast intent if the connection was initated by AudioService
+                    if (!mScoClients.isEmpty() &&
+                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
+                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
+                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+                        broadcast = true;
+                    }
+                    switch (btState) {
+                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                        }
+                        break;
+                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+                        mScoAudioState = SCO_STATE_INACTIVE;
+                        clearAllScoClients(0, false);
+                        break;
+                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
+                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+                        }
+                    default:
+                        // do not broadcast CONNECTING or invalid state
+                        broadcast = false;
+                        break;
+                    }
+                }
+                if (broadcast) {
+                    broadcastScoConnectionState(scoAudioState);
+                    //FIXME: this is to maintain compatibility with deprecated intent
+                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
+                    sendStickyBroadcastToAll(newIntent);
+                }
+            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+                if (mMonitorRotation) {
+                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
+                    mOrientationListener.enable();
+                }
+                AudioSystem.setParameters("screen_state=on");
+            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+                if (mMonitorRotation) {
+                    //reduce wakeups (save current) by only listening when display is on
+                    mOrientationListener.disable();
+                }
+                AudioSystem.setParameters("screen_state=off");
+            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                handleConfigurationChanged(context);
+            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
+                // attempt to stop music playback for background user
+                sendMsg(mAudioHandler,
+                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
+                        SENDMSG_REPLACE,
+                        0,
+                        0,
+                        null,
+                        0);
+                // the current audio focus owner is no longer valid
+                mMediaFocusControl.discardAudioFocusOwner();
+
+                // load volume settings for new user
+                readAudioSettings(true /*userSwitch*/);
+                // preserve STREAM_MUSIC volume from one user to the next.
+                sendMsg(mAudioHandler,
+                        MSG_SET_ALL_VOLUMES,
+                        SENDMSG_QUEUE,
+                        0,
+                        0,
+                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+            }
+        }
+    } // end class AudioServiceBroadcastReceiver
+
+    //==========================================================================================
+    // RemoteControlDisplay / RemoteControlClient / Remote info
+    //==========================================================================================
+    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
+            ComponentName listenerComp) {
+        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
+    }
+
+    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+    }
+
+    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
+    }
+
+    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
+    }
+
+    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
+            boolean wantsSync) {
+        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
+    }
+
+    @Override
+    public void setRemoteStreamVolume(int index) {
+        enforceVolumeController("set the remote stream volume");
+        mMediaFocusControl.setRemoteStreamVolume(index);
+    }
+
+    //==========================================================================================
+    // Audio Focus
+    //==========================================================================================
+    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
+            IAudioPolicyCallback pcb) {
+        // permission checks
+        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
+            if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
+                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
+                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                }
+            } else {
+                // only a registered audio policy can be used to lock focus
+                synchronized (mAudioPolicies) {
+                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
+                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
+                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                    }
+                }
+            }
+        }
+
+        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
+                clientId, callingPackageName, flags);
+    }
+
+    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
+        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
+    }
+
+    public void unregisterAudioFocusClient(String clientId) {
+        mMediaFocusControl.unregisterAudioFocusClient(clientId);
+    }
+
+    public int getCurrentAudioFocus() {
+        return mMediaFocusControl.getCurrentAudioFocus();
+    }
+
+    private boolean readCameraSoundForced() {
+        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
+                mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_camera_sound_forced);
+    }
+
+    //==========================================================================================
+    // Device orientation
+    //==========================================================================================
+    /**
+     * Handles device configuration changes that may map to a change in the orientation
+     * or orientation.
+     * Monitoring orientation and rotation is optional, and is defined by the definition and value
+     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
+     */
+    private void handleConfigurationChanged(Context context) {
+        try {
+            // reading new orientation "safely" (i.e. under try catch) in case anything
+            // goes wrong when obtaining resources and configuration
+            Configuration config = context.getResources().getConfiguration();
+            // TODO merge rotation and orientation
+            if (mMonitorOrientation) {
+                int newOrientation = config.orientation;
+                if (newOrientation != mDeviceOrientation) {
+                    mDeviceOrientation = newOrientation;
+                    setOrientationForAudioSystem();
+                }
+            }
+            sendMsg(mAudioHandler,
+                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
+                    SENDMSG_REPLACE,
+                    0,
+                    0,
+                    TAG,
+                    0);
+
+            boolean cameraSoundForced = readCameraSoundForced();
+            synchronized (mSettingsLock) {
+                boolean cameraSoundForcedChanged = false;
+                synchronized (mCameraSoundForced) {
+                    if (cameraSoundForced != mCameraSoundForced) {
+                        mCameraSoundForced = cameraSoundForced;
+                        cameraSoundForcedChanged = true;
+                    }
+                }
+                if (cameraSoundForcedChanged) {
+                    if (!isPlatformTelevision()) {
+                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+                        if (cameraSoundForced) {
+                            s.setAllIndexesToMax();
+                            mRingerModeAffectedStreams &=
+                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+                        } else {
+                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
+                            mRingerModeAffectedStreams |=
+                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+                        }
+                        // take new state into account for streams muted by ringer mode
+                        setRingerModeInt(getRingerModeInternal(), false);
+                    }
+
+                    sendMsg(mAudioHandler,
+                            MSG_SET_FORCE_USE,
+                            SENDMSG_QUEUE,
+                            AudioSystem.FOR_SYSTEM,
+                            cameraSoundForced ?
+                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
+                            null,
+                            0);
+
+                    sendMsg(mAudioHandler,
+                            MSG_SET_ALL_VOLUMES,
+                            SENDMSG_QUEUE,
+                            0,
+                            0,
+                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
+                }
+            }
+            mVolumeController.setLayoutDirection(config.getLayoutDirection());
+        } catch (Exception e) {
+            Log.e(TAG, "Error handling configuration change: ", e);
+        }
+    }
+
+    private void setOrientationForAudioSystem() {
+        switch (mDeviceOrientation) {
+            case Configuration.ORIENTATION_LANDSCAPE:
+                //Log.i(TAG, "orientation is landscape");
+                AudioSystem.setParameters("orientation=landscape");
+                break;
+            case Configuration.ORIENTATION_PORTRAIT:
+                //Log.i(TAG, "orientation is portrait");
+                AudioSystem.setParameters("orientation=portrait");
+                break;
+            case Configuration.ORIENTATION_SQUARE:
+                //Log.i(TAG, "orientation is square");
+                AudioSystem.setParameters("orientation=square");
+                break;
+            case Configuration.ORIENTATION_UNDEFINED:
+                //Log.i(TAG, "orientation is undefined");
+                AudioSystem.setParameters("orientation=undefined");
+                break;
+            default:
+                Log.e(TAG, "Unknown orientation");
+        }
+    }
+
+    private void setRotationForAudioSystem() {
+        switch (mDeviceRotation) {
+            case Surface.ROTATION_0:
+                AudioSystem.setParameters("rotation=0");
+                break;
+            case Surface.ROTATION_90:
+                AudioSystem.setParameters("rotation=90");
+                break;
+            case Surface.ROTATION_180:
+                AudioSystem.setParameters("rotation=180");
+                break;
+            case Surface.ROTATION_270:
+                AudioSystem.setParameters("rotation=270");
+                break;
+            default:
+                Log.e(TAG, "Unknown device rotation");
+        }
+    }
+
+
+    // Handles request to override default use of A2DP for media.
+    // Must be called synchronized on mConnectedDevices
+    public void setBluetoothA2dpOnInt(boolean on) {
+        synchronized (mBluetoothA2dpEnabledLock) {
+            mBluetoothA2dpEnabled = on;
+            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
+            setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
+                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
+        }
+    }
+
+    // Must be called synchronized on mConnectedDevices
+    private void setForceUseInt_SyncDevices(int usage, int config) {
+        switch (usage) {
+            case AudioSystem.FOR_MEDIA:
+                if (config == AudioSystem.FORCE_NO_BT_A2DP) {
+                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
+                } else { // config == AudioSystem.FORCE_NONE
+                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
+                }
+                break;
+            case AudioSystem.FOR_DOCK:
+                if (config == AudioSystem.FORCE_ANALOG_DOCK) {
+                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
+                } else { // config == AudioSystem.FORCE_NONE
+                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
+                }
+                break;
+            default:
+                // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
+        }
+        AudioSystem.setForceUse(usage, config);
+    }
+
+    @Override
+    public void setRingtonePlayer(IRingtonePlayer player) {
+        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
+        mRingtonePlayer = player;
+    }
+
+    @Override
+    public IRingtonePlayer getRingtonePlayer() {
+        return mRingtonePlayer;
+    }
+
+    @Override
+    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
+        synchronized (mCurAudioRoutes) {
+            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
+            mRoutesObservers.register(observer);
+            return routes;
+        }
+    }
+
+
+    //==========================================================================================
+    // Safe media volume management.
+    // MUSIC stream volume level is limited when headphones are connected according to safety
+    // regulation. When the user attempts to raise the volume above the limit, a warning is
+    // displayed and the user has to acknowlegde before the volume is actually changed.
+    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
+    // property. Platforms with a different limit must set this property accordingly in their
+    // overlay.
+    //==========================================================================================
+
+    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
+    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
+    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
+    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
+    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
+    // (when user opts out).
+    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
+    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
+    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
+    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
+    private Integer mSafeMediaVolumeState;
+
+    private int mMcc = 0;
+    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
+    private int mSafeMediaVolumeIndex;
+    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
+    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
+                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
+    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
+    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
+    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
+    private int mMusicActiveMs;
+    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
+    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
+    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
+
+    private void setSafeMediaVolumeEnabled(boolean on, String caller) {
+        synchronized (mSafeMediaVolumeState) {
+            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
+                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
+                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                    enforceSafeMediaVolume(caller);
+                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+                    mMusicActiveMs = 1;  // nonzero = confirmed
+                    saveMusicActiveMs();
+                    sendMsg(mAudioHandler,
+                            MSG_CHECK_MUSIC_ACTIVE,
+                            SENDMSG_REPLACE,
+                            0,
+                            0,
+                            caller,
+                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                }
+            }
+        }
+    }
+
+    private void enforceSafeMediaVolume(String caller) {
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        int devices = mSafeMediaVolumeDevices;
+        int i = 0;
+
+        while (devices != 0) {
+            int device = 1 << i++;
+            if ((device & devices) == 0) {
+                continue;
+            }
+            int index = streamState.getIndex(device);
+            if (index > mSafeMediaVolumeIndex) {
+                streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
+                sendMsg(mAudioHandler,
+                        MSG_SET_DEVICE_VOLUME,
+                        SENDMSG_QUEUE,
+                        device,
+                        0,
+                        streamState,
+                        0);
+            }
+            devices &= ~device;
+        }
+    }
+
+    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
+        synchronized (mSafeMediaVolumeState) {
+            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
+                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
+                    ((device & mSafeMediaVolumeDevices) != 0) &&
+                    (index > mSafeMediaVolumeIndex)) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    @Override
+    public void disableSafeMediaVolume(String callingPackage) {
+        enforceVolumeController("disable the safe media volume");
+        synchronized (mSafeMediaVolumeState) {
+            setSafeMediaVolumeEnabled(false, callingPackage);
+            if (mPendingVolumeCommand != null) {
+                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
+                                  mPendingVolumeCommand.mIndex,
+                                  mPendingVolumeCommand.mFlags,
+                                  mPendingVolumeCommand.mDevice,
+                                  callingPackage);
+                mPendingVolumeCommand = null;
+            }
+        }
+    }
+
+    //==========================================================================================
+    // Hdmi Cec system audio mode.
+    // If Hdmi Cec's system audio mode is on, audio service should send the volume change
+    // to HdmiControlService so that the audio receiver can handle it.
+    //==========================================================================================
+
+    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
+        public void onComplete(int status) {
+            if (mHdmiManager != null) {
+                synchronized (mHdmiManager) {
+                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
+                    // Television devices without CEC service apply software volume on HDMI output
+                    if (isPlatformTelevision() && !mHdmiCecSink) {
+                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+                    }
+                    checkAllFixedVolumeDevices();
+                }
+            }
+        }
+    };
+
+    // If HDMI-CEC system audio is supported
+    private boolean mHdmiSystemAudioSupported = false;
+    // Set only when device is tv.
+    private HdmiTvClient mHdmiTvClient;
+    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
+    // cached HdmiControlManager interface
+    private HdmiControlManager mHdmiManager;
+    // Set only when device is a set-top box.
+    private HdmiPlaybackClient mHdmiPlaybackClient;
+    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
+    private boolean mHdmiCecSink;
+
+    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
+
+    @Override
+    public int setHdmiSystemAudioSupported(boolean on) {
+        int device = AudioSystem.DEVICE_NONE;
+        if (mHdmiManager != null) {
+            synchronized (mHdmiManager) {
+                if (mHdmiTvClient == null) {
+                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
+                    return device;
+                }
+
+                synchronized (mHdmiTvClient) {
+                    if (mHdmiSystemAudioSupported != on) {
+                        mHdmiSystemAudioSupported = on;
+                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
+                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
+                                     AudioSystem.FORCE_NONE);
+                    }
+                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
+                }
+            }
+        }
+        return device;
+    }
+
+    @Override
+    public boolean isHdmiSystemAudioSupported() {
+        return mHdmiSystemAudioSupported;
+    }
+
+    //==========================================================================================
+    // Accessibility: taking touch exploration into account for selecting the default
+    //   stream override timeout when adjusting volume
+    //==========================================================================================
+    private static class StreamOverride
+            implements AccessibilityManager.TouchExplorationStateChangeListener {
+
+        // AudioService.getActiveStreamType() will return:
+        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
+        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
+        // stopped
+        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
+        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
+
+        static int sDelayMs;
+
+        static void init(Context ctxt) {
+            AccessibilityManager accessibilityManager =
+                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
+            updateDefaultStreamOverrideDelay(
+                    accessibilityManager.isTouchExplorationEnabled());
+            accessibilityManager.addTouchExplorationStateChangeListener(
+                    new StreamOverride());
+        }
+
+        @Override
+        public void onTouchExplorationStateChanged(boolean enabled) {
+            updateDefaultStreamOverrideDelay(enabled);
+        }
+
+        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
+            if (touchExploreEnabled) {
+                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
+            } else {
+                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
+            }
+            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
+                    + " stream override delay is now " + sDelayMs + " ms");
+        }
+    }
+
+    //==========================================================================================
+    // Camera shutter sound policy.
+    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
+    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
+    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
+    //==========================================================================================
+
+    // cached value of com.android.internal.R.bool.config_camera_sound_forced
+    private Boolean mCameraSoundForced;
+
+    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
+    public boolean isCameraSoundForced() {
+        synchronized (mCameraSoundForced) {
+            return mCameraSoundForced;
+        }
+    }
+
+    private static final String[] RINGER_MODE_NAMES = new String[] {
+            "SILENT",
+            "VIBRATE",
+            "NORMAL"
+    };
+
+    private void dumpRingerMode(PrintWriter pw) {
+        pw.println("\nRinger mode: ");
+        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
+        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
+        pw.print("- ringer mode affected streams = 0x");
+        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
+        pw.print("- ringer mode muted streams = 0x");
+        pw.println(Integer.toHexString(mRingerModeMutedStreams));
+        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+        mMediaFocusControl.dump(pw);
+        dumpStreamStates(pw);
+        dumpRingerMode(pw);
+        pw.println("\nAudio routes:");
+        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
+        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
+
+        pw.println("\nOther state:");
+        pw.print("  mVolumeController="); pw.println(mVolumeController);
+        pw.print("  mSafeMediaVolumeState=");
+        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
+        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
+        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
+        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
+        pw.print("  mMcc="); pw.println(mMcc);
+        pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
+        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
+        pw.print("  mControllerService="); pw.println(mControllerService);
+        pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
+
+        dumpAudioPolicies(pw);
+    }
+
+    private static String safeMediaVolumeStateToString(Integer state) {
+        switch(state) {
+            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
+            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
+            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
+            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
+        }
+        return null;
+    }
+
+    // Inform AudioFlinger of our device's low RAM attribute
+    private static void readAndSetLowRamDevice()
+    {
+        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
+        if (status != 0) {
+            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
+        }
+    }
+
+    private void enforceVolumeController(String action) {
+        if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
+            return;
+        }
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                "Only SystemUI can " + action);
+    }
+
+    @Override
+    public void setVolumeController(final IVolumeController controller) {
+        enforceVolumeController("set the volume controller");
+
+        // return early if things are not actually changing
+        if (mVolumeController.isSameBinder(controller)) {
+            return;
+        }
+
+        // dismiss the old volume controller
+        mVolumeController.postDismiss();
+        if (controller != null) {
+            // we are about to register a new controller, listen for its death
+            try {
+                controller.asBinder().linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        if (mVolumeController.isSameBinder(controller)) {
+                            Log.w(TAG, "Current remote volume controller died, unregistering");
+                            setVolumeController(null);
+                        }
+                    }
+                }, 0);
+            } catch (RemoteException e) {
+                // noop
+            }
+        }
+        mVolumeController.setController(controller);
+        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
+    }
+
+    @Override
+    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
+        enforceVolumeController("notify about volume controller visibility");
+
+        // return early if the controller is not current
+        if (!mVolumeController.isSameBinder(controller)) {
+            return;
+        }
+
+        mVolumeController.setVisible(visible);
+        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
+    }
+
+    @Override
+    public void setVolumePolicy(VolumePolicy policy) {
+        enforceVolumeController("set volume policy");
+        if (policy != null) {
+            mVolumePolicy = policy;
+        }
+    }
+
+    public static class VolumeController {
+        private static final String TAG = "VolumeController";
+
+        private IVolumeController mController;
+        private boolean mVisible;
+        private long mNextLongPress;
+        private int mLongPressTimeout;
+
+        public void setController(IVolumeController controller) {
+            mController = controller;
+            mVisible = false;
+        }
+
+        public void loadSettings(ContentResolver cr) {
+            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
+                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
+        }
+
+        public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
+            if (isMute) {
+                return false;
+            }
+            boolean suppress = false;
+            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
+                final long now = SystemClock.uptimeMillis();
+                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
+                    // ui will become visible
+                    if (mNextLongPress < now) {
+                        mNextLongPress = now + mLongPressTimeout;
+                    }
+                    suppress = true;
+                } else if (mNextLongPress > 0) {  // in a long-press
+                    if (now > mNextLongPress) {
+                        // long press triggered, no more suppression
+                        mNextLongPress = 0;
+                    } else {
+                        // keep suppressing until the long press triggers
+                        suppress = true;
+                    }
+                }
+            }
+            return suppress;
+        }
+
+        public void setVisible(boolean visible) {
+            mVisible = visible;
+        }
+
+        public boolean isSameBinder(IVolumeController controller) {
+            return Objects.equals(asBinder(), binder(controller));
+        }
+
+        public IBinder asBinder() {
+            return binder(mController);
+        }
+
+        private static IBinder binder(IVolumeController controller) {
+            return controller == null ? null : controller.asBinder();
+        }
+
+        @Override
+        public String toString() {
+            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
+        }
+
+        public void postDisplaySafeVolumeWarning(int flags) {
+            if (mController == null)
+                return;
+            try {
+                mController.displaySafeVolumeWarning(flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
+            }
+        }
+
+        public void postVolumeChanged(int streamType, int flags) {
+            if (mController == null)
+                return;
+            try {
+                mController.volumeChanged(streamType, flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling volumeChanged", e);
+            }
+        }
+
+        public void postMasterMuteChanged(int flags) {
+            if (mController == null)
+                return;
+            try {
+                mController.masterMuteChanged(flags);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling masterMuteChanged", e);
+            }
+        }
+
+        public void setLayoutDirection(int layoutDirection) {
+            if (mController == null)
+                return;
+            try {
+                mController.setLayoutDirection(layoutDirection);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling setLayoutDirection", e);
+            }
+        }
+
+        public void postDismiss() {
+            if (mController == null)
+                return;
+            try {
+                mController.dismiss();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error calling dismiss", e);
+            }
+        }
+    }
+
+    /**
+     * Interface for system components to get some extra functionality through
+     * LocalServices.
+     */
+    final class AudioServiceInternal extends AudioManagerInternal {
+        @Override
+        public void setRingerModeDelegate(RingerModeDelegate delegate) {
+            mRingerModeDelegate = delegate;
+            if (mRingerModeDelegate != null) {
+                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
+            }
+        }
+
+        @Override
+        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
+                String callingPackage, int uid) {
+            // direction and stream type swap here because the public
+            // adjustSuggested has a different order than the other methods.
+            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
+                    callingPackage, uid);
+        }
+
+        @Override
+        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
+                String callingPackage, int uid) {
+            adjustStreamVolume(streamType, direction, flags, callingPackage,
+                    callingPackage, uid);
+        }
+
+        @Override
+        public void setStreamVolumeForUid(int streamType, int direction, int flags,
+                String callingPackage, int uid) {
+            setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
+        }
+
+        @Override
+        public int getRingerModeInternal() {
+            return AudioService.this.getRingerModeInternal();
+        }
+
+        @Override
+        public void setRingerModeInternal(int ringerMode, String caller) {
+            AudioService.this.setRingerModeInternal(ringerMode, caller);
+        }
+
+        @Override
+        public int getVolumeControllerUid() {
+            return mControllerService.mUid;
+        }
+    }
+
+    //==========================================================================================
+    // Audio policy management
+    //==========================================================================================
+    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
+            boolean hasFocusListener) {
+        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
+                + " with config:" + policyConfig);
+        String regId = null;
+        // error handling
+        boolean hasPermissionForPolicy =
+                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
+                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+        if (!hasPermissionForPolicy) {
+            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
+                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
+            return null;
+        }
+
+        synchronized (mAudioPolicies) {
+            try {
+                if (mAudioPolicies.containsKey(pcb.asBinder())) {
+                    Slog.e(TAG, "Cannot re-register policy");
+                    return null;
+                }
+                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
+                pcb.asBinder().linkToDeath(app, 0/*flags*/);
+                regId = app.getRegistrationId();
+                mAudioPolicies.put(pcb.asBinder(), app);
+            } catch (RemoteException e) {
+                // audio policy owner has already died!
+                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
+                        " binder death", e);
+                return null;
+            }
+        }
+        return regId;
+    }
+
+    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
+        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
+        synchronized (mAudioPolicies) {
+            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
+            if (app == null) {
+                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
+                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
+                return;
+            } else {
+                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
+            }
+            app.release();
+        }
+        // TODO implement clearing mix attribute matching info in native audio policy
+    }
+
+    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
+        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
+                + " policy " +  pcb.asBinder());
+        // error handling
+        boolean hasPermissionForPolicy =
+                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
+                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+        if (!hasPermissionForPolicy) {
+            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
+                    + Binder.getCallingPid() + " / uid "
+                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
+            return AudioManager.ERROR;
+        }
+
+        synchronized (mAudioPolicies) {
+            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
+                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
+                return AudioManager.ERROR;
+            }
+            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
+            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
+                // is there already one policy managing ducking?
+                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
+                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
+                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
+                        return AudioManager.ERROR;
+                    }
+                }
+            }
+            app.mFocusDuckBehavior = duckingBehavior;
+            mMediaFocusControl.setDuckingInExtPolicyAvailable(
+                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
+        }
+        return AudioManager.SUCCESS;
+    }
+
+    private void dumpAudioPolicies(PrintWriter pw) {
+        pw.println("\nAudio policies:");
+        synchronized (mAudioPolicies) {
+            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
+                pw.println(policy.toLogFriendlyString());
+            }
+        }
+    }
+
+    //======================
+    // Audio policy proxy
+    //======================
+    /**
+     * This internal class inherits from AudioPolicyConfig, each instance contains all the
+     * mixes of an AudioPolicy and their configurations.
+     */
+    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
+        private static final String TAG = "AudioPolicyProxy";
+        AudioPolicyConfig mConfig;
+        IAudioPolicyCallback mPolicyToken;
+        boolean mHasFocusListener;
+        /**
+         * Audio focus ducking behavior for an audio policy.
+         * This variable reflects the value that was successfully set in
+         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
+         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
+         * is handling ducking for audio focus.
+         */
+        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
+
+        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
+                boolean hasFocusListener) {
+            super(config);
+            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
+            mPolicyToken = token;
+            mHasFocusListener = hasFocusListener;
+            if (mHasFocusListener) {
+                mMediaFocusControl.addFocusFollower(mPolicyToken);
+            }
+            connectMixes();
+        }
+
+        public void binderDied() {
+            synchronized (mAudioPolicies) {
+                Log.i(TAG, "audio policy " + mPolicyToken + " died");
+                release();
+                mAudioPolicies.remove(mPolicyToken.asBinder());
+            }
+        }
+
+        String getRegistrationId() {
+            return getRegistration();
+        }
+
+        void release() {
+            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
+                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
+            }
+            if (mHasFocusListener) {
+                mMediaFocusControl.removeFocusFollower(mPolicyToken);
+            }
+            AudioSystem.registerPolicyMixes(mMixes, false);
+        }
+
+        void connectMixes() {
+            AudioSystem.registerPolicyMixes(mMixes, true);
+        }
+    };
+
+    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
+            new HashMap<IBinder, AudioPolicyProxy>();
+    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
+
+    private class ControllerService extends ContentObserver {
+        private int mUid;
+        private ComponentName mComponent;
+
+        public ControllerService() {
+            super(null);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
+        }
+
+        public void init() {
+            onChange(true);
+            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            mUid = 0;
+            mComponent = null;
+            final String setting = Settings.Secure.getString(mContentResolver,
+                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
+            if (setting == null) return;
+            try {
+                mComponent = ComponentName.unflattenFromString(setting);
+                if (mComponent == null) return;
+                mUid = mContext.getPackageManager()
+                        .getApplicationInfo(mComponent.getPackageName(), 0).uid;
+            } catch (Exception e) {
+                Log.w(TAG, "Error loading controller service", e);
+            }
+            if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
new file mode 100644
index 0000000..49be879
--- /dev/null
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -0,0 +1,333 @@
+/*
+ * 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.audio;
+
+import android.annotation.NonNull;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.IAudioFocusDispatcher;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.server.audio.MediaFocusControl.AudioFocusDeathHandler;
+
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ * Class to handle all the information about a user of audio focus. The lifecycle of each
+ * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
+ * stack to its release.
+ */
+public class FocusRequester {
+
+    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
+    private static final String TAG = "MediaFocusControl";
+    private static final boolean DEBUG = false;
+
+    private AudioFocusDeathHandler mDeathHandler;
+    private final IAudioFocusDispatcher mFocusDispatcher; // may be null
+    private final IBinder mSourceRef;
+    private final String mClientId;
+    private final String mPackageName;
+    private final int mCallingUid;
+    private final MediaFocusControl mFocusController; // never null
+    /**
+     * the audio focus gain request that caused the addition of this object in the focus stack.
+     */
+    private final int mFocusGainRequest;
+    /**
+     * the flags associated with the gain request that qualify the type of grant (e.g. accepting
+     * delay vs grant must be immediate)
+     */
+    private final int mGrantFlags;
+    /**
+     * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
+     *  it never lost focus.
+     */
+    private int mFocusLossReceived;
+    /**
+     * the audio attributes associated with the focus request
+     */
+    private final AudioAttributes mAttributes;
+
+    /**
+     * Class constructor
+     * @param aa
+     * @param focusRequest
+     * @param grantFlags
+     * @param afl
+     * @param source
+     * @param id
+     * @param hdlr
+     * @param pn
+     * @param uid
+     * @param ctlr cannot be null
+     */
+    FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
+            IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
+            String pn, int uid, @NonNull MediaFocusControl ctlr) {
+        mAttributes = aa;
+        mFocusDispatcher = afl;
+        mSourceRef = source;
+        mClientId = id;
+        mDeathHandler = hdlr;
+        mPackageName = pn;
+        mCallingUid = uid;
+        mFocusGainRequest = focusRequest;
+        mGrantFlags = grantFlags;
+        mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+        mFocusController = ctlr;
+    }
+
+
+    boolean hasSameClient(String otherClient) {
+        try {
+            return mClientId.compareTo(otherClient) == 0;
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    boolean isLockedFocusOwner() {
+        return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
+    }
+
+    boolean hasSameBinder(IBinder ib) {
+        return (mSourceRef != null) && mSourceRef.equals(ib);
+    }
+
+    boolean hasSamePackage(String pack) {
+        try {
+            return mPackageName.compareTo(pack) == 0;
+        } catch (NullPointerException e) {
+            return false;
+        }
+    }
+
+    boolean hasSameUid(int uid) {
+        return mCallingUid == uid;
+    }
+
+    String getClientId() {
+        return mClientId;
+    }
+
+    int getGainRequest() {
+        return mFocusGainRequest;
+    }
+
+    int getGrantFlags() {
+        return mGrantFlags;
+    }
+
+    AudioAttributes getAudioAttributes() {
+        return mAttributes;
+    }
+
+
+    private static String focusChangeToString(int focus) {
+        switch(focus) {
+            case AudioManager.AUDIOFOCUS_NONE:
+                return "none";
+            case AudioManager.AUDIOFOCUS_GAIN:
+                return "GAIN";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                return "GAIN_TRANSIENT";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                return "GAIN_TRANSIENT_MAY_DUCK";
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+                return "GAIN_TRANSIENT_EXCLUSIVE";
+            case AudioManager.AUDIOFOCUS_LOSS:
+                return "LOSS";
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                return "LOSS_TRANSIENT";
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                return "LOSS_TRANSIENT_CAN_DUCK";
+            default:
+                return "[invalid focus change" + focus + "]";
+        }
+    }
+
+    private String focusGainToString() {
+        return focusChangeToString(mFocusGainRequest);
+    }
+
+    private String focusLossToString() {
+        return focusChangeToString(mFocusLossReceived);
+    }
+
+    private static String flagsToString(int flags) {
+        String msg = new String();
+        if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) != 0) {
+            msg += "DELAY_OK";
+        }
+        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0)     {
+            if (!msg.isEmpty()) { msg += "|"; }
+            msg += "LOCK";
+        }
+        if ((flags & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) != 0) {
+            if (!msg.isEmpty()) { msg += "|"; }
+            msg += "PAUSES_ON_DUCKABLE_LOSS";
+        }
+        return msg;
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("  source:" + mSourceRef
+                + " -- pack: " + mPackageName
+                + " -- client: " + mClientId
+                + " -- gain: " + focusGainToString()
+                + " -- flags: " + flagsToString(mGrantFlags)
+                + " -- loss: " + focusLossToString()
+                + " -- uid: " + mCallingUid
+                + " -- attr: " + mAttributes);
+    }
+
+
+    void release() {
+        try {
+            if (mSourceRef != null && mDeathHandler != null) {
+                mSourceRef.unlinkToDeath(mDeathHandler, 0);
+                mDeathHandler = null;
+            }
+        } catch (java.util.NoSuchElementException e) {
+            Log.e(TAG, "FocusRequester.release() hit ", e);
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        release();
+        super.finalize();
+    }
+
+    /**
+     * For a given audio focus gain request, return the audio focus loss type that will result
+     * from it, taking into account any previous focus loss.
+     * @param gainRequest
+     * @return the audio focus loss type that matches the gain request
+     */
+    private int focusLossForGainRequest(int gainRequest) {
+        switch(gainRequest) {
+            case AudioManager.AUDIOFOCUS_GAIN:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                    case AudioManager.AUDIOFOCUS_NONE:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                    case AudioManager.AUDIOFOCUS_NONE:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+                switch(mFocusLossReceived) {
+                    case AudioManager.AUDIOFOCUS_NONE:
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
+                    case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                        return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+                    case AudioManager.AUDIOFOCUS_LOSS:
+                        return AudioManager.AUDIOFOCUS_LOSS;
+                }
+            default:
+                Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
+                        return AudioManager.AUDIOFOCUS_NONE;
+        }
+    }
+
+    /**
+     * Called synchronized on MediaFocusControl.mAudioFocusLock
+     */
+    void handleExternalFocusGain(int focusGain) {
+        int focusLoss = focusLossForGainRequest(focusGain);
+        handleFocusLoss(focusLoss);
+    }
+
+    /**
+     * Called synchronized on MediaFocusControl.mAudioFocusLock
+     */
+    void handleFocusGain(int focusGain) {
+        try {
+            mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+            mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
+                    AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+            if (mFocusDispatcher != null) {
+                if (DEBUG) {
+                    Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
+                        + mClientId);
+                }
+                mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
+            }
+        } catch (android.os.RemoteException e) {
+            Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
+        }
+    }
+
+    /**
+     * Called synchronized on MediaFocusControl.mAudioFocusLock
+     */
+    void handleFocusLoss(int focusLoss) {
+        try {
+            if (focusLoss != mFocusLossReceived) {
+                mFocusLossReceived = focusLoss;
+                // before dispatching a focus loss, check if the following conditions are met:
+                // 1/ the framework is not supposed to notify the focus loser on a DUCK loss
+                // 2/ it is a DUCK loss
+                // 3/ the focus loser isn't flagged as pausing in a DUCK loss
+                // if they are, do not notify the focus loser
+                if (!mFocusController.mustNotifyFocusOwnerOnDuck()
+                        && mFocusLossReceived == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+                        && (mGrantFlags
+                                & AudioManager.AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) == 0) {
+                    if (DEBUG) {
+                        Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
+                                + " to " + mClientId + ", to be handled externally");
+                    }
+                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
+                            toAudioFocusInfo(), false /* wasDispatched */);
+                    return;
+                }
+                if (mFocusDispatcher != null) {
+                    if (DEBUG) {
+                        Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to "
+                            + mClientId);
+                    }
+                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
+                            toAudioFocusInfo(), true /* wasDispatched */);
+                    mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId);
+                }
+            }
+        } catch (android.os.RemoteException e) {
+            Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
+        }
+    }
+
+    AudioFocusInfo toAudioFocusInfo() {
+        return new AudioFocusInfo(mAttributes, mClientId, mPackageName,
+                mFocusGainRequest, mFocusLossReceived, mGrantFlags);
+    }
+}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
new file mode 100644
index 0000000..fcdd9d9
--- /dev/null
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -0,0 +1,2197 @@
+/*
+ * 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.audio;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.PendingIntent.OnFinished;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IAudioFocusDispatcher;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteControlDisplay;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
+import android.media.audiopolicy.IAudioPolicyCallback;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.Slog;
+import android.view.KeyEvent;
+
+import com.android.server.audio.PlayerRecord.RemotePlaybackState;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Stack;
+
+/**
+ * @hide
+ *
+ */
+public class MediaFocusControl implements OnFinished {
+
+    private static final String TAG = "MediaFocusControl";
+
+    /** Debug remote control client/display feature */
+    protected static final boolean DEBUG_RC = false;
+    /** Debug volumes */
+    protected static final boolean DEBUG_VOL = false;
+
+    /** Used to alter media button redirection when the phone is ringing. */
+    private boolean mIsRinging = false;
+
+    private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final MediaEventHandler mEventHandler;
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final AudioService.VolumeController mVolumeController;
+    private final AppOpsManager mAppOps;
+    private final KeyguardManager mKeyguardManager;
+    private final AudioService mAudioService;
+    private final NotificationListenerObserver mNotifListenerObserver;
+
+    protected MediaFocusControl(Looper looper, Context cntxt,
+            AudioService.VolumeController volumeCtrl, AudioService as) {
+        mEventHandler = new MediaEventHandler(looper);
+        mContext = cntxt;
+        mContentResolver = mContext.getContentResolver();
+        mVolumeController = volumeCtrl;
+        mAudioService = as;
+
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        int maxMusicLevel = as.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        mMainRemote = new RemotePlaybackState(-1, maxMusicLevel, maxMusicLevel);
+
+        // Register for phone state monitoring
+        TelephonyManager tmgr = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mNotifListenerObserver = new NotificationListenerObserver();
+
+        mHasRemotePlayback = false;
+        mMainRemoteIsActive = false;
+
+        PlayerRecord.setMediaFocusControl(this);
+
+        postReevaluateRemote();
+    }
+
+    protected void dump(PrintWriter pw) {
+        dumpFocusStack(pw);
+        dumpRCStack(pw);
+        dumpRCCStack(pw);
+        dumpRCDList(pw);
+    }
+
+    //==========================================================================================
+    // Management of RemoteControlDisplay registration permissions
+    //==========================================================================================
+    private final static Uri ENABLED_NOTIFICATION_LISTENERS_URI =
+            Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+    private class NotificationListenerObserver extends ContentObserver {
+
+        NotificationListenerObserver() {
+            super(mEventHandler);
+            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (!ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri) || selfChange) {
+                return;
+            }
+            if (DEBUG_RC) { Log.d(TAG, "NotificationListenerObserver.onChange()"); }
+            postReevaluateRemoteControlDisplays();
+        }
+    }
+
+    private final static int RCD_REG_FAILURE = 0;
+    private final static int RCD_REG_SUCCESS_PERMISSION = 1;
+    private final static int RCD_REG_SUCCESS_ENABLED_NOTIF = 2;
+
+    /**
+     * Checks a caller's authorization to register an IRemoteControlDisplay.
+     * Authorization is granted if one of the following is true:
+     * <ul>
+     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL permission</li>
+     * <li>the caller's listener is one of the enabled notification listeners</li>
+     * </ul>
+     * @return RCD_REG_FAILURE if it's not safe to proceed with the IRemoteControlDisplay
+     *     registration.
+     */
+    private int checkRcdRegistrationAuthorization(ComponentName listenerComp) {
+        // MEDIA_CONTENT_CONTROL permission check
+        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
+            if (DEBUG_RC) { Log.d(TAG, "ok to register Rcd: has MEDIA_CONTENT_CONTROL permission");}
+            return RCD_REG_SUCCESS_PERMISSION;
+        }
+
+        // ENABLED_NOTIFICATION_LISTENERS settings check
+        if (listenerComp != null) {
+            // this call is coming from an app, can't use its identity to read secure settings
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                final int currentUser = ActivityManager.getCurrentUser();
+                final String enabledNotifListeners = Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                        currentUser);
+                if (enabledNotifListeners != null) {
+                    final String[] components = enabledNotifListeners.split(":");
+                    for (int i=0; i<components.length; i++) {
+                        final ComponentName component =
+                                ComponentName.unflattenFromString(components[i]);
+                        if (component != null) {
+                            if (listenerComp.equals(component)) {
+                                if (DEBUG_RC) { Log.d(TAG, "ok to register RCC: " + component +
+                                        " is authorized notification listener"); }
+                                return RCD_REG_SUCCESS_ENABLED_NOTIF;
+                            }
+                        }
+                    }
+                }
+                if (DEBUG_RC) { Log.d(TAG, "not ok to register RCD, " + listenerComp +
+                        " is not in list of ENABLED_NOTIFICATION_LISTENERS"); }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        return RCD_REG_FAILURE;
+    }
+
+    protected boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
+            ComponentName listenerComp) {
+        int reg = checkRcdRegistrationAuthorization(listenerComp);
+        if (reg != RCD_REG_FAILURE) {
+            registerRemoteControlDisplay_int(rcd, w, h, listenerComp);
+            return true;
+        } else {
+            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+                    " or be an enabled NotificationListenerService for registerRemoteController");
+            return false;
+        }
+    }
+
+    protected boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        int reg = checkRcdRegistrationAuthorization(null);
+        if (reg != RCD_REG_FAILURE) {
+            registerRemoteControlDisplay_int(rcd, w, h, null);
+            return true;
+        } else {
+            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+                    " to register IRemoteControlDisplay");
+            return false;
+        }
+    }
+
+    private void postReevaluateRemoteControlDisplays() {
+        sendMsg(mEventHandler, MSG_REEVALUATE_RCD, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    private void onReevaluateRemoteControlDisplays() {
+        if (DEBUG_RC) { Log.d(TAG, "onReevaluateRemoteControlDisplays()"); }
+        // read which components are enabled notification listeners
+        final int currentUser = ActivityManager.getCurrentUser();
+        final String enabledNotifListeners = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                currentUser);
+        if (DEBUG_RC) { Log.d(TAG, " > enabled list: " + enabledNotifListeners); }
+        synchronized(mAudioFocusLock) {
+            synchronized(mPRStack) {
+                // check whether the "enable" status of each RCD with a notification listener
+                // has changed
+                final String[] enabledComponents;
+                if (enabledNotifListeners == null) {
+                    enabledComponents = null;
+                } else {
+                    enabledComponents = enabledNotifListeners.split(":");
+                }
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di =
+                            displayIterator.next();
+                    if (di.mClientNotifListComp != null) {
+                        boolean wasEnabled = di.mEnabled;
+                        di.mEnabled = isComponentInStringArray(di.mClientNotifListComp,
+                                enabledComponents);
+                        if (wasEnabled != di.mEnabled){
+                            try {
+                                // tell the RCD whether it's enabled
+                                di.mRcDisplay.setEnabled(di.mEnabled);
+                                // tell the RCCs about the change for this RCD
+                                enableRemoteControlDisplayForClient_syncRcStack(
+                                        di.mRcDisplay, di.mEnabled);
+                                // when enabling, refresh the information on the display
+                                if (di.mEnabled) {
+                                    sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
+                                            di.mArtworkExpectedWidth /*arg1*/,
+                                            di.mArtworkExpectedHeight/*arg2*/,
+                                            di.mRcDisplay /*obj*/, 0/*delay*/);
+                                }
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Error en/disabling RCD: ", e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @param comp a non-null ComponentName
+     * @param enabledArray may be null
+     * @return
+     */
+    private boolean isComponentInStringArray(ComponentName comp, String[] enabledArray) {
+        if (enabledArray == null || enabledArray.length == 0) {
+            if (DEBUG_RC) { Log.d(TAG, " > " + comp + " is NOT enabled"); }
+            return false;
+        }
+        final String compString = comp.flattenToString();
+        for (int i=0; i<enabledArray.length; i++) {
+            if (compString.equals(enabledArray[i])) {
+                if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is enabled"); }
+                return true;
+            }
+        }
+        if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is NOT enabled"); }
+        return false;
+    }
+
+    //==========================================================================================
+    // Internal event handling
+    //==========================================================================================
+
+    // event handler messages
+    private static final int MSG_RCDISPLAY_CLEAR = 1;
+    private static final int MSG_RCDISPLAY_UPDATE = 2;
+    private static final int MSG_REEVALUATE_REMOTE = 3;
+    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
+    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
+    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 6;
+    private static final int MSG_RCC_SEEK_REQUEST = 7;
+    private static final int MSG_RCC_UPDATE_METADATA = 8;
+    private static final int MSG_RCDISPLAY_INIT_INFO = 9;
+    private static final int MSG_REEVALUATE_RCD = 10;
+    private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
+
+    // sendMsg() flags
+    /** 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. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    private static void sendMsg(Handler handler, int msg,
+            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
+
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
+    }
+
+    private class MediaEventHandler extends Handler {
+        MediaEventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_RCDISPLAY_CLEAR:
+                    onRcDisplayClear();
+                    break;
+
+                case MSG_RCDISPLAY_UPDATE:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayUpdate( (PlayerRecord) msg.obj, msg.arg1);
+                    break;
+
+                case MSG_REEVALUATE_REMOTE:
+                    onReevaluateRemote();
+                    break;
+
+                case MSG_RCC_NEW_VOLUME_OBS:
+                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
+                            (IRemoteVolumeObserver)msg.obj /* rvo */);
+                    break;
+
+                case MSG_RCDISPLAY_INIT_INFO:
+                    // msg.obj is guaranteed to be non null
+                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
+                            msg.arg1/*w*/, msg.arg2/*h*/);
+                    break;
+
+                case MSG_REEVALUATE_RCD:
+                    onReevaluateRemoteControlDisplays();
+                    break;
+
+                case MSG_UNREGISTER_MEDIABUTTONINTENT:
+                    unregisterMediaButtonIntent( (PendingIntent) msg.obj );
+                    break;
+            }
+        }
+    }
+
+
+    //==========================================================================================
+    // AudioFocus
+    //==========================================================================================
+
+    private final static Object mAudioFocusLock = new Object();
+
+    private final static Object mRingingLock = new Object();
+
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (state == TelephonyManager.CALL_STATE_RINGING) {
+                //Log.v(TAG, " CALL_STATE_RINGING");
+                synchronized(mRingingLock) {
+                    mIsRinging = true;
+                }
+            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
+                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
+                synchronized(mRingingLock) {
+                    mIsRinging = false;
+                }
+            }
+        }
+    };
+
+    /**
+     * Discard the current audio focus owner.
+     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
+     * focus), remove it from the stack, and clear the remote control display.
+     */
+    protected void discardAudioFocusOwner() {
+        synchronized(mAudioFocusLock) {
+            if (!mFocusStack.empty()) {
+                // notify the current focus owner it lost focus after removing it from stack
+                final FocusRequester exFocusOwner = mFocusStack.pop();
+                exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
+                exFocusOwner.release();
+            }
+        }
+    }
+
+    /**
+     * Called synchronized on mAudioFocusLock
+     */
+    private void notifyTopOfAudioFocusStack() {
+        // notify the top of the stack it gained focus
+        if (!mFocusStack.empty()) {
+            if (canReassignAudioFocus()) {
+                mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
+            }
+        }
+    }
+
+    /**
+     * Focus is requested, propagate the associated loss throughout the stack.
+     * @param focusGain the new focus gain that will later be added at the top of the stack
+     */
+    private void propagateFocusLossFromGain_syncAf(int focusGain) {
+        // going through the audio focus stack to signal new focus, traversing order doesn't
+        // matter as all entries respond to the same external focus gain
+        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+        while(stackIterator.hasNext()) {
+            stackIterator.next().handleExternalFocusGain(focusGain);
+        }
+    }
+
+    private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the audio focus stack
+     */
+    private void dumpFocusStack(PrintWriter pw) {
+        pw.println("\nAudio Focus stack entries (last is top of stack):");
+        synchronized(mAudioFocusLock) {
+            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                stackIterator.next().dump(pw);
+            }
+        }
+        pw.println("\n Notify on duck: " + mNotifyFocusOwnerOnDuck +"\n");
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove a focus listener from the focus stack.
+     * @param clientToRemove the focus listener
+     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
+     *   focus, notify the next item in the stack it gained focus.
+     */
+    private void removeFocusStackEntry(String clientToRemove, boolean signal,
+            boolean notifyFocusFollowers) {
+        // is the current top of the focus stack abandoning focus? (because of request, not death)
+        if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
+        {
+            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
+            FocusRequester fr = mFocusStack.pop();
+            fr.release();
+            if (notifyFocusFollowers) {
+                final AudioFocusInfo afi = fr.toAudioFocusInfo();
+                afi.clearLossReceived();
+                notifyExtPolicyFocusLoss_syncAf(afi, false);
+            }
+            if (signal) {
+                // notify the new top of the stack it gained focus
+                notifyTopOfAudioFocusStack();
+            }
+        } else {
+            // focus is abandoned by a client that's not at the top of the stack,
+            // no need to update focus.
+            // (using an iterator on the stack so we can safely remove an entry after having
+            //  evaluated it, traversal order doesn't matter here)
+            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+            while(stackIterator.hasNext()) {
+                FocusRequester fr = stackIterator.next();
+                if(fr.hasSameClient(clientToRemove)) {
+                    Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
+                            + clientToRemove);
+                    stackIterator.remove();
+                    fr.release();
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mAudioFocusLock
+     * Remove focus listeners from the focus stack for a particular client when it has died.
+     */
+    private void removeFocusStackEntryForClient(IBinder cb) {
+        // is the owner of the audio focus part of the client to remove?
+        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
+                mFocusStack.peek().hasSameBinder(cb);
+        // (using an iterator on the stack so we can safely remove an entry after having
+        //  evaluated it, traversal order doesn't matter here)
+        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+        while(stackIterator.hasNext()) {
+            FocusRequester fr = stackIterator.next();
+            if(fr.hasSameBinder(cb)) {
+                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
+                stackIterator.remove();
+                // the client just died, no need to unlink to its death
+            }
+        }
+        if (isTopOfStackForClientToRemove) {
+            // we removed an entry at the top of the stack:
+            //  notify the new top of the stack it gained focus.
+            notifyTopOfAudioFocusStack();
+        }
+    }
+
+    /**
+     * Helper function:
+     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
+     * The implementation guarantees that a state where focus cannot be immediately reassigned
+     * implies that an "locked" focus owner is at the top of the focus stack.
+     * Modifications to the implementation that break this assumption will cause focus requests to
+     * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
+     */
+    private boolean canReassignAudioFocus() {
+        // focus requests are rejected during a phone call or when the phone is ringing
+        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
+        if (!mFocusStack.isEmpty() && isLockedFocusOwner(mFocusStack.peek())) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isLockedFocusOwner(FocusRequester fr) {
+        return (fr.hasSameClient(AudioSystem.IN_VOICE_COMM_FOCUS_ID) || fr.isLockedFocusOwner());
+    }
+
+    /**
+     * Helper function
+     * Pre-conditions: focus stack is not empty, there is one or more locked focus owner
+     *                 at the top of the focus stack
+     * Push the focus requester onto the audio focus stack at the first position immediately
+     * following the locked focus owners.
+     * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
+     *     {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
+     */
+    private int pushBelowLockedFocusOwners(FocusRequester nfr) {
+        int lastLockedFocusOwnerIndex = mFocusStack.size();
+        for (int index = mFocusStack.size()-1; index >= 0; index--) {
+            if (isLockedFocusOwner(mFocusStack.elementAt(index))) {
+                lastLockedFocusOwnerIndex = index;
+            }
+        }
+        if (lastLockedFocusOwnerIndex == mFocusStack.size()) {
+            // this should not happen, but handle it and log an error
+            Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
+                    new Exception());
+            // no exclusive owner, push at top of stack, focus is granted, propagate change
+            propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
+            mFocusStack.push(nfr);
+            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+        } else {
+            mFocusStack.insertElementAt(nfr, lastLockedFocusOwnerIndex);
+            return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+        }
+    }
+
+    /**
+     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
+     * stack if necessary.
+     */
+    protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
+        private IBinder mCb; // To be notified of client's death
+
+        AudioFocusDeathHandler(IBinder cb) {
+            mCb = cb;
+        }
+
+        public void binderDied() {
+            synchronized(mAudioFocusLock) {
+                Log.w(TAG, "  AudioFocus   audio focus client died");
+                removeFocusStackEntryForClient(mCb);
+            }
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+    /**
+     * Indicates whether to notify an audio focus owner when it loses focus
+     * with {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK} if it will only duck.
+     * This variable being false indicates an AudioPolicy has been registered and has signaled
+     * it will handle audio ducking.
+     */
+    private boolean mNotifyFocusOwnerOnDuck = true;
+
+    protected void setDuckingInExtPolicyAvailable(boolean available) {
+        mNotifyFocusOwnerOnDuck = !available;
+    }
+
+    boolean mustNotifyFocusOwnerOnDuck() { return mNotifyFocusOwnerOnDuck; }
+
+    private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();
+
+    void addFocusFollower(IAudioPolicyCallback ff) {
+        if (ff == null) {
+            return;
+        }
+        synchronized(mAudioFocusLock) {
+            boolean found = false;
+            for (IAudioPolicyCallback pcb : mFocusFollowers) {
+                if (pcb.asBinder().equals(ff.asBinder())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (found) {
+                return;
+            } else {
+                mFocusFollowers.add(ff);
+            }
+        }
+    }
+
+    void removeFocusFollower(IAudioPolicyCallback ff) {
+        if (ff == null) {
+            return;
+        }
+        synchronized(mAudioFocusLock) {
+            for (IAudioPolicyCallback pcb : mFocusFollowers) {
+                if (pcb.asBinder().equals(ff.asBinder())) {
+                    mFocusFollowers.remove(pcb);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Called synchronized on mAudioFocusLock
+     */
+    void notifyExtPolicyFocusGrant_syncAf(AudioFocusInfo afi, int requestResult) {
+        for (IAudioPolicyCallback pcb : mFocusFollowers) {
+            try {
+                // oneway
+                pcb.notifyAudioFocusGrant(afi, requestResult);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
+                        + pcb.asBinder(), e);
+            }
+        }
+    }
+
+    /**
+     * Called synchronized on mAudioFocusLock
+     */
+    void notifyExtPolicyFocusLoss_syncAf(AudioFocusInfo afi, boolean wasDispatched) {
+        for (IAudioPolicyCallback pcb : mFocusFollowers) {
+            try {
+                // oneway
+                pcb.notifyAudioFocusLoss(afi, wasDispatched);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Can't call newAudioFocusLoser() on IAudioPolicyCallback "
+                        + pcb.asBinder(), e);
+            }
+        }
+    }
+
+    protected int getCurrentAudioFocus() {
+        synchronized(mAudioFocusLock) {
+            if (mFocusStack.empty()) {
+                return AudioManager.AUDIOFOCUS_NONE;
+            } else {
+                return mFocusStack.peek().getGainRequest();
+            }
+        }
+    }
+
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
+    protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
+        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId + " req=" + focusChangeHint +
+                "flags=0x" + Integer.toHexString(flags));
+        // we need a valid binder callback for clients
+        if (!cb.pingBinder()) {
+            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
+                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
+            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        }
+
+        synchronized(mAudioFocusLock) {
+            boolean focusGrantDelayed = false;
+            if (!canReassignAudioFocus()) {
+                if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                } else {
+                    // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
+                    // granted right now, so the requester will be inserted in the focus stack
+                    // to receive focus later
+                    focusGrantDelayed = true;
+                }
+            }
+
+            // handle the potential premature death of the new holder of the focus
+            // (premature death == death before abandoning focus)
+            // Register for client death notification
+            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+            try {
+                cb.linkToDeath(afdh, 0);
+            } catch (RemoteException e) {
+                // client has already died!
+                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
+                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+            }
+
+            if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
+                // if focus is already owned by this client and the reason for acquiring the focus
+                // hasn't changed, don't do anything
+                final FocusRequester fr = mFocusStack.peek();
+                if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
+                    // unlink death handler so it can be gc'ed.
+                    // linkToDeath() creates a JNI global reference preventing collection.
+                    cb.unlinkToDeath(afdh, 0);
+                    notifyExtPolicyFocusGrant_syncAf(fr.toAudioFocusInfo(),
+                            AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+                }
+                // the reason for the audio focus request has changed: remove the current top of
+                // stack and respond as if we had a new focus owner
+                if (!focusGrantDelayed) {
+                    mFocusStack.pop();
+                    // the entry that was "popped" is the same that was "peeked" above
+                    fr.release();
+                }
+            }
+
+            // focus requester might already be somewhere below in the stack, remove it
+            removeFocusStackEntry(clientId, false /* signal */, false /*notifyFocusFollowers*/);
+
+            final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
+                    clientId, afdh, callingPackageName, Binder.getCallingUid(), this);
+            if (focusGrantDelayed) {
+                // focusGrantDelayed being true implies we can't reassign focus right now
+                // which implies the focus stack is not empty.
+                final int requestResult = pushBelowLockedFocusOwners(nfr);
+                if (requestResult != AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
+                    notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), requestResult);
+                }
+                return requestResult;
+            } else {
+                // propagate the focus change through the stack
+                if (!mFocusStack.empty()) {
+                    propagateFocusLossFromGain_syncAf(focusChangeHint);
+                }
+
+                // push focus requester at the top of the audio focus stack
+                mFocusStack.push(nfr);
+            }
+            notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
+                    AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+
+        }//synchronized(mAudioFocusLock)
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+    /**
+     * @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener, AudioAttributes)
+     * */
+    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa) {
+        // AudioAttributes are currently ignored, to be used for zones
+        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
+        try {
+            // this will take care of notifying the new focus owner if needed
+            synchronized(mAudioFocusLock) {
+                removeFocusStackEntry(clientId, true /*signal*/, true /*notifyFocusFollowers*/);
+            }
+        } catch (java.util.ConcurrentModificationException cme) {
+            // Catching this exception here is temporary. It is here just to prevent
+            // a crash seen when the "Silent" notification is played. This is believed to be fixed
+            // but this try catch block is left just to be safe.
+            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
+            cme.printStackTrace();
+        }
+
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+    }
+
+
+    protected void unregisterAudioFocusClient(String clientId) {
+        synchronized(mAudioFocusLock) {
+            removeFocusStackEntry(clientId, false, true /*notifyFocusFollowers*/);
+        }
+    }
+
+
+    //==========================================================================================
+    // RemoteControl
+    //==========================================================================================
+    /**
+     * No-op if the key code for keyEvent is not a valid media key
+     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
+     * @param keyEvent the key event to send
+     */
+    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
+    }
+
+    /**
+     * No-op if the key code for keyEvent is not a valid media key
+     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
+     * @param keyEvent the key event to send
+     */
+    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
+        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
+    }
+
+    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        // sanity check on the incoming key event
+        if (!isValidMediaKeyEvent(keyEvent)) {
+            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
+            return;
+        }
+        // event filtering for telephony
+        synchronized(mRingingLock) {
+            synchronized(mPRStack) {
+                if ((mMediaReceiverForCalls != null) &&
+                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
+                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
+                    return;
+                }
+            }
+        }
+        // event filtering based on voice-based interactions
+        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
+            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
+        } else {
+            dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to the telephony package.
+     * Precondition: mMediaReceiverForCalls != null
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Handles the dispatching of the media button events to one of the registered listeners,
+     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
+     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+        synchronized(mPRStack) {
+            if (!mPRStack.empty()) {
+                // send the intent that was registered by the client
+                try {
+                    mPRStack.peek().getMediaButtonIntent().send(mContext,
+                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
+                            keyIntent, this, mEventHandler);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending pending intent " + mPRStack.peek());
+                    e.printStackTrace();
+                }
+            } else {
+                // legacy behavior when nobody registered their media button event receiver
+                //    through AudioManager
+                if (needWakeLock) {
+                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
+                            null, mKeyEventDone,
+                            mEventHandler, Activity.RESULT_OK, null, null);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
+    /**
+     * The different actions performed in response to a voice button key event.
+     */
+    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
+    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
+    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
+
+    private final Object mVoiceEventLock = new Object();
+    private boolean mVoiceButtonDown;
+    private boolean mVoiceButtonHandled;
+
+    /**
+     * Filter key events that may be used for voice-based interactions
+     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
+     *    media buttons that can be used to trigger voice-based interactions.
+     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
+     *     is dispatched.
+     */
+    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        if (DEBUG_RC) {
+            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
+        }
+
+        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
+        int keyAction = keyEvent.getAction();
+        synchronized (mVoiceEventLock) {
+            if (keyAction == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    // initial down
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled
+                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                    // long-press, start voice-based interactions
+                    mVoiceButtonHandled = true;
+                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
+                }
+            } else if (keyAction == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    // voice button up
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
+                    }
+                }
+            }
+        }//synchronized (mVoiceEventLock)
+
+        // take action after media button event filtering for voice-based interactions
+        switch (voiceButtonAction) {
+            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
+                break;
+            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
+                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
+                // then start the voice-based interactions
+                startVoiceBasedInteractions(needWakeLock);
+                break;
+            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
+                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
+                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
+                break;
+        }
+    }
+
+    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
+        // send DOWN event
+        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+        // send UP event
+        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
+        dispatchMediaKeyEvent(keyEvent, needWakeLock);
+
+    }
+
+    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            return false;
+        }
+        return KeyEvent.isMediaKey(keyEvent.getKeyCode());
+    }
+
+    /**
+     * Checks whether the given key code is one that can trigger the launch of voice-based
+     *   interactions.
+     * @param keyCode the key code associated with the key event
+     * @return true if the key is one of the supported voice-based interaction triggers
+     */
+    private static boolean isValidVoiceInputKeyCode(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tell the system to start voice-based interactions / voice commands
+     */
+    private void startVoiceBasedInteractions(boolean needWakeLock) {
+        Intent voiceIntent = null;
+        // select which type of search to launch:
+        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
+        //    with EXTRA_SECURE set to true if the device is securely locked
+        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+        if (!isLocked && pm.isScreenOn()) {
+            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+        } else {
+            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                    isLocked && mKeyguardManager.isKeyguardSecure());
+            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+        }
+        // start the search activity
+        if (needWakeLock) {
+            mMediaEventWakeLock.acquire();
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (voiceIntent != null) {
+                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+            }
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "No activity for search: " + e);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+            if (needWakeLock) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    }
+
+    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
+
+    // only set when wakelock was acquired, no need to check value when received
+    private static final String EXTRA_WAKELOCK_ACQUIRED =
+            "android.media.AudioService.WAKELOCK_ACQUIRED";
+
+    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
+            int resultCode, String resultData, Bundle resultExtras) {
+        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
+            mMediaEventWakeLock.release();
+        }
+    }
+
+    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            if (intent == null) {
+                return;
+            }
+            Bundle extras = intent.getExtras();
+            if (extras == null) {
+                return;
+            }
+            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
+                mMediaEventWakeLock.release();
+            }
+        }
+    };
+
+    /**
+     * Synchronization on mCurrentRcLock always inside a block synchronized on mPRStack
+     */
+    private final Object mCurrentRcLock = new Object();
+    /**
+     * The one remote control client which will receive a request for display information.
+     * This object may be null.
+     * Access protected by mCurrentRcLock.
+     */
+    private IRemoteControlClient mCurrentRcClient = null;
+    /**
+     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
+     * if mCurrentRcClient is null
+     */
+    private PendingIntent mCurrentRcClientIntent = null;
+
+    private final static int RC_INFO_NONE = 0;
+    private final static int RC_INFO_ALL =
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
+        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
+
+    /**
+     * A monotonically increasing generation counter for mCurrentRcClient.
+     * Only accessed with a lock on mCurrentRcLock.
+     * No value wrap-around issues as we only act on equal values.
+     */
+    private int mCurrentRcClientGen = 0;
+
+
+    /**
+     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
+     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
+     * every time we need this info.
+     */
+    private RemotePlaybackState mMainRemote;
+    /**
+     * Indicates whether the "main" RemoteControlClient is considered active.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mMainRemoteIsActive;
+    /**
+     * Indicates whether there is remote playback going on. True even if there is no "active"
+     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
+     * handles remote playback.
+     * Use synchronized on mMainRemote.
+     */
+    private boolean mHasRemotePlayback;
+
+    /**
+     * The stack of remote control event receivers.
+     * All read and write operations on mPRStack are synchronized.
+     */
+    private final Stack<PlayerRecord> mPRStack = new Stack<PlayerRecord>();
+
+    /**
+     * The component the telephony package can register so telephony calls have priority to
+     * handle media button events
+     */
+    private ComponentName mMediaReceiverForCalls = null;
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control focus stack
+     */
+    private void dumpRCStack(PrintWriter pw) {
+        pw.println("\nRemote Control stack entries (last is top of stack):");
+        synchronized(mPRStack) {
+            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+            while(stackIterator.hasNext()) {
+                stackIterator.next().dump(pw, true);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the remote control stack, focusing
+     * on RemoteControlClient data
+     */
+    private void dumpRCCStack(PrintWriter pw) {
+        pw.println("\nRemote Control Client stack entries (last is top of stack):");
+        synchronized(mPRStack) {
+            Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+            while(stackIterator.hasNext()) {
+                stackIterator.next().dump(pw, false);
+            }
+            synchronized(mCurrentRcLock) {
+                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
+            }
+        }
+        synchronized (mMainRemote) {
+            pw.println("\nRemote Volume State:");
+            pw.println("  has remote: " + mHasRemotePlayback);
+            pw.println("  is remote active: " + mMainRemoteIsActive);
+            pw.println("  rccId: " + mMainRemote.mRccId);
+            pw.println("  volume handling: "
+                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
+                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
+            pw.println("  volume: " + mMainRemote.mVolume);
+            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Display in the log the current entries in the list of remote control displays
+     */
+    private void dumpRCDList(PrintWriter pw) {
+        pw.println("\nRemote Control Display list entries:");
+        synchronized(mPRStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = displayIterator.next();
+                pw.println("  IRCD: " + di.mRcDisplay +
+                        "  -- w:" + di.mArtworkExpectedWidth +
+                        "  -- h:" + di.mArtworkExpectedHeight +
+                        "  -- wantsPosSync:" + di.mWantsPositionSync +
+                        "  -- " + (di.mEnabled ? "enabled" : "disabled"));
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Push the new media button receiver "near" the top of the PlayerRecord stack.
+     * "Near the top" is defined as:
+     *   - at the top if the current PlayerRecord at the top is not playing
+     *   - below the entries at the top of the stack that correspond to the playing PlayerRecord
+     *     otherwise
+     * Called synchronized on mPRStack
+     * precondition: mediaIntent != null
+     * @return true if the top of mPRStack was changed, false otherwise
+     */
+    private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
+            ComponentName target, IBinder token) {
+        if (mPRStack.empty()) {
+            mPRStack.push(new PlayerRecord(mediaIntent, target, token));
+            return true;
+        } else if (mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
+            // already at top of stack
+            return false;
+        }
+        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
+                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
+            return false;
+        }
+        PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
+        boolean topChanged = false;
+        PlayerRecord prse = null;
+        int lastPlayingIndex = mPRStack.size();
+        int inStackIndex = -1;
+        try {
+            // go through the stack from the top to figure out who's playing, and the position
+            // of this media button receiver (note that it may not be in the stack)
+            for (int index = mPRStack.size()-1; index >= 0; index--) {
+                prse = mPRStack.elementAt(index);
+                if (prse.isPlaybackActive()) {
+                    lastPlayingIndex = index;
+                }
+                if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
+                    inStackIndex = index;
+                }
+            }
+
+            if (inStackIndex == -1) {
+                // is not in stack
+                prse = new PlayerRecord(mediaIntent, target, token);
+                // it's new so it's not playing (no RemoteControlClient to give a playstate),
+                // therefore it goes after the ones with active playback
+                mPRStack.add(lastPlayingIndex, prse);
+            } else {
+                // is in the stack
+                if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
+                    prse = mPRStack.elementAt(inStackIndex);
+                    // remove it from its old location in the stack
+                    mPRStack.removeElementAt(inStackIndex);
+                    if (prse.isPlaybackActive()) {
+                        // and put it at the top
+                        mPRStack.push(prse);
+                    } else {
+                        // and put it after the ones with active playback
+                        if (inStackIndex > lastPlayingIndex) {
+                            mPRStack.add(lastPlayingIndex, prse);
+                        } else {
+                            mPRStack.add(lastPlayingIndex - 1, prse);
+                        }
+                    }
+                }
+            }
+
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification or bad index
+            Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
+                    + " size=" + mPRStack.size()
+                    + " accessing media button stack", e);
+        }
+
+        return (topChanged);
+    }
+
+    /**
+     * Helper function:
+     * Remove the remote control receiver from the RC focus stack.
+     * Called synchronized on mPRStack
+     * precondition: pi != null
+     */
+    private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) {
+        try {
+            for (int index = mPRStack.size()-1; index >= 0; index--) {
+                final PlayerRecord prse = mPRStack.elementAt(index);
+                if (prse.hasMatchingMediaButtonIntent(pi)) {
+                    prse.destroy();
+                    // ok to remove element while traversing the stack since we're leaving the loop
+                    mPRStack.removeElementAt(index);
+                    break;
+                }
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // not expected to happen, indicates improper concurrent modification
+            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mPRStack
+     */
+    private boolean isCurrentRcController(PendingIntent pi) {
+        if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(pi)) {
+            return true;
+        }
+        return false;
+    }
+
+    //==========================================================================================
+    // Remote control display / client
+    //==========================================================================================
+    /**
+     * Update the remote control displays with the new "focused" client generation
+     */
+    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        synchronized(mPRStack) {
+            if (mRcDisplays.size() > 0) {
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = displayIterator.next();
+                    try {
+                        di.mRcDisplay.setCurrentClientId(
+                                newClientGeneration, newMediaIntent, clearing);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
+                        di.release();
+                        displayIterator.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the remote control clients with the new "focused" client generation
+     */
+    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
+        // (using an iterator on the stack so we can safely remove an entry if needed,
+        //  traversal order doesn't matter here as we update all entries)
+        Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+        while(stackIterator.hasNext()) {
+            PlayerRecord se = stackIterator.next();
+            if ((se != null) && (se.getRcc() != null)) {
+                try {
+                    se.getRcc().setCurrentClientGenerationId(newClientGeneration);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
+                    stackIterator.remove();
+                    se.unlinkToRcClientDeath();
+                }
+            }
+        }
+    }
+
+    /**
+     * Update the displays and clients with the new "focused" client generation and name
+     * @param newClientGeneration the new generation value matching a client update
+     * @param newMediaIntent the media button event receiver associated with the client.
+     *    May be null, which implies there is no registered media button event receiver.
+     * @param clearing true if the new client generation value maps to a remote control update
+     *    where the display should be cleared.
+     */
+    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
+            PendingIntent newMediaIntent, boolean clearing) {
+        // send the new valid client generation ID to all displays
+        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
+        // send the new valid client generation ID to all clients
+        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_CLEAR event
+     */
+    private void onRcDisplayClear() {
+        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
+
+        synchronized(mPRStack) {
+            synchronized(mCurrentRcLock) {
+                mCurrentRcClientGen++;
+                // synchronously update the displays and clients with the new client generation
+                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                        null /*newMediaIntent*/, true /*clearing*/);
+            }
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_UPDATE event
+     */
+    private void onRcDisplayUpdate(PlayerRecord prse, int flags /* USED ?*/) {
+        synchronized(mPRStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(prse.getRcc()))) {
+                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
+
+                    mCurrentRcClientGen++;
+                    // synchronously update the displays and clients with
+                    //      the new client generation
+                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+                            prse.getMediaButtonIntent() /*newMediaIntent*/,
+                            false /*clearing*/);
+
+                    // tell the current client that it needs to send info
+                    try {
+                        //TODO change name to informationRequestForAllDisplays()
+                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                } else {
+                    // the remote control display owner has changed between the
+                    // the message to update the display was sent, and the time it
+                    // gets to be processed (now)
+                }
+            }
+        }
+    }
+
+    /**
+     * Called when processing MSG_RCDISPLAY_INIT_INFO event
+     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
+     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
+     */
+    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
+        synchronized(mPRStack) {
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClient != null) {
+                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
+                    try {
+                        // synchronously update the new RCD with the current client generation
+                        // and matching PendingIntent
+                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
+                                false);
+
+                        // tell the current RCC that it needs to send info, but only to the new RCD
+                        try {
+                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Current valid remote client is dead: ", e);
+                            mCurrentRcClient = null;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mPRStack
+     */
+    private void clearRemoteControlDisplay_syncPrs() {
+        synchronized(mCurrentRcLock) {
+            mCurrentRcClient = null;
+        }
+        // will cause onRcDisplayClear() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+    }
+
+    /**
+     * Helper function for code readability: only to be called from
+     *    checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for
+     *    this method.
+     * Preconditions:
+     *    - called synchronized on mPRStack
+     *    - mPRStack.isEmpty() is false
+     */
+    private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
+        PlayerRecord prse = mPRStack.peek();
+        int infoFlagsAboutToBeUsed = infoChangedFlags;
+        // this is where we enforce opt-in for information display on the remote controls
+        //   with the new AudioManager.registerRemoteControlClient() API
+        if (prse.getRcc() == null) {
+            //Log.w(TAG, "Can't update remote control display with null remote control client");
+            clearRemoteControlDisplay_syncPrs();
+            return;
+        }
+        synchronized(mCurrentRcLock) {
+            if (!prse.getRcc().equals(mCurrentRcClient)) {
+                // new RC client, assume every type of information shall be queried
+                infoFlagsAboutToBeUsed = RC_INFO_ALL;
+            }
+            mCurrentRcClient = prse.getRcc();
+            mCurrentRcClientIntent = prse.getMediaButtonIntent();
+        }
+        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
+        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
+                infoFlagsAboutToBeUsed /* arg1 */, 0, prse /* obj, != null */) );
+    }
+
+    /**
+     * Helper function:
+     * Called synchronized on mPRStack
+     * Check whether the remote control display should be updated, triggers the update if required
+     * @param infoChangedFlags the flags corresponding to the remote control client information
+     *     that has changed, if applicable (checking for the update conditions might trigger a
+     *     clear, rather than an update event).
+     */
+    private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
+        // determine whether the remote control display should be refreshed
+        // if the player record stack is empty, there is nothing to display, so clear the RC display
+        if (mPRStack.isEmpty()) {
+            clearRemoteControlDisplay_syncPrs();
+            return;
+        }
+
+        // this is where more rules for refresh go
+
+        // refresh conditions were verified: update the remote controls
+        // ok to call: synchronized on mPRStack, mPRStack is not empty
+        updateRemoteControlDisplay_syncPrs(infoChangedFlags);
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
+     * precondition: mediaIntent != null
+     */
+    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
+            IBinder token) {
+        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mPRStack) {
+            if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) {
+                // new RC client, assume every type of information shall be queried
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
+     * precondition: mediaIntent != null, eventReceiver != null
+     */
+    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
+    {
+        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
+
+        synchronized(mPRStack) {
+            boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+            removeMediaButtonReceiver_syncPrs(mediaIntent);
+            if (topOfStackWillChange) {
+                // current RC client will change, assume every type of info needs to be queried
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+            }
+        }
+    }
+
+    protected void unregisterMediaButtonIntentAsync(final PendingIntent mediaIntent) {
+        mEventHandler.sendMessage(
+                mEventHandler.obtainMessage(MSG_UNREGISTER_MEDIABUTTONINTENT, 0, 0,
+                        mediaIntent));
+    }
+
+    /**
+     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
+     * precondition: c != null
+     */
+    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
+            return;
+        }
+        synchronized(mPRStack) {
+            mMediaReceiverForCalls = c;
+        }
+    }
+
+    /**
+     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
+     */
+    protected void unregisterMediaButtonEventReceiverForCalls() {
+        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
+                != PackageManager.PERMISSION_GRANTED) {
+            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
+            return;
+        }
+        synchronized(mPRStack) {
+            mMediaReceiverForCalls = null;
+        }
+    }
+
+    /**
+     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
+     * @return the unique ID of the PlayerRecord associated with the RemoteControlClient
+     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
+     *     without modifying the RC stack, but while still causing the display to refresh (will
+     *     become blank as a result of this)
+     */
+    protected int registerRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient, String callingPackageName) {
+        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized(mPRStack) {
+            // store the new display information
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
+                        prse.resetControllerInfoForRcc(rcClient, callingPackageName,
+                                Binder.getCallingUid());
+
+                        if (rcClient == null) {
+                            break;
+                        }
+
+                        rccId = prse.getRccId();
+
+                        // there is a new (non-null) client:
+                        //     give the new client the displays (if any)
+                        if (mRcDisplays.size() > 0) {
+                            plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc());
+                        }
+                        break;
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+
+            // if the eventReceiver is at the top of the stack
+            // then check for potential refresh of the remote controls
+            if (isCurrentRcController(mediaIntent)) {
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+            }
+        }//synchronized(mPRStack)
+        return rccId;
+    }
+
+    /**
+     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
+     * rcClient is guaranteed non-null
+     */
+    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
+            IRemoteControlClient rcClient) {
+        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
+        synchronized(mPRStack) {
+            boolean topRccChange = false;
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
+                            && rcClient.equals(prse.getRcc())) {
+                        // we found the IRemoteControlClient to unregister
+                        prse.resetControllerInfoForNoRcc();
+                        topRccChange = (index == mPRStack.size()-1);
+                        // there can only be one matching RCC in the RC stack, we're done
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+            if (topRccChange) {
+                // no more RCC for the RCD, check for potential refresh of the remote controls
+                checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+            }
+        }
+    }
+
+
+    /**
+     * A class to encapsulate all the information about a remote control display.
+     * After instanciation, init() must always be called before the object is added in the list
+     * of displays.
+     * Before being removed from the list of displays, release() must always be called (otherwise
+     * it will leak death handlers).
+     */
+    private class DisplayInfoForServer implements IBinder.DeathRecipient {
+        /** may never be null */
+        private final IRemoteControlDisplay mRcDisplay;
+        private final IBinder mRcDisplayBinder;
+        private int mArtworkExpectedWidth = -1;
+        private int mArtworkExpectedHeight = -1;
+        private boolean mWantsPositionSync = false;
+        private ComponentName mClientNotifListComp;
+        private boolean mEnabled = true;
+
+        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
+            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
+            mRcDisplay = rcd;
+            mRcDisplayBinder = rcd.asBinder();
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+
+        public boolean init() {
+            try {
+                mRcDisplayBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                // remote control display is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
+                return false;
+            }
+            return true;
+        }
+
+        public void release() {
+            try {
+                mRcDisplayBinder.unlinkToDeath(this, 0);
+            } catch (java.util.NoSuchElementException e) {
+                // not much we can do here, the display should have been unregistered anyway
+                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
+            }
+        }
+
+        public void binderDied() {
+            synchronized(mPRStack) {
+                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
+                // remove the display from the list
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = displayIterator.next();
+                    if (di.mRcDisplay == mRcDisplay) {
+                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
+                        displayIterator.remove();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * The remote control displays.
+     * Access synchronized on mPRStack
+     */
+    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
+
+    /**
+     * Plug each registered display into the specified client
+     * @param rcc, guaranteed non null
+     */
+    private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = displayIterator.next();
+            try {
+                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
+                        di.mArtworkExpectedHeight);
+                if (di.mWantsPositionSync) {
+                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
+            }
+        }
+    }
+
+    private void enableRemoteControlDisplayForClient_syncRcStack(IRemoteControlDisplay rcd,
+            boolean enabled) {
+        // let all the remote control clients know whether the given display is enabled
+        //   (so the remote control stack traversal order doesn't matter).
+        final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+        while(stackIterator.hasNext()) {
+            PlayerRecord prse = stackIterator.next();
+            if(prse.getRcc() != null) {
+                try {
+                    prse.getRcc().enableRemoteControlDisplay(rcd, enabled);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error connecting RCD to client: ", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Is the remote control display interface already registered
+     * @param rcd
+     * @return true if the IRemoteControlDisplay is already in the list of displays
+     */
+    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = displayIterator.next();
+            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Register an IRemoteControlDisplay.
+     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
+     * at the top of the stack to update the new display with its information.
+     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay to register. No effect if null.
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param listenerComp the component for the listener interface, may be null if it's not needed
+     *   to verify it belongs to one of the enabled notification listeners
+     */
+    private void registerRemoteControlDisplay_int(IRemoteControlDisplay rcd, int w, int h,
+            ComponentName listenerComp) {
+        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
+        synchronized(mAudioFocusLock) {
+            synchronized(mPRStack) {
+                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
+                    return;
+                }
+                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
+                di.mEnabled = true;
+                di.mClientNotifListComp = listenerComp;
+                if (!di.init()) {
+                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
+                    return;
+                }
+                // add RCD to list of displays
+                mRcDisplays.add(di);
+
+                // let all the remote control clients know there is a new display (so the remote
+                //   control stack traversal order doesn't matter).
+                Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+                while(stackIterator.hasNext()) {
+                    PlayerRecord prse = stackIterator.next();
+                    if(prse.getRcc() != null) {
+                        try {
+                            prse.getRcc().plugRemoteControlDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error connecting RCD to client: ", e);
+                        }
+                    }
+                }
+
+                // we have a new display, of which all the clients are now aware: have it be
+                // initialized wih the current gen ID and the current client info, do not
+                // reset the information for the other (existing) displays
+                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
+                        w /*arg1*/, h /*arg2*/,
+                        rcd /*obj*/, 0/*delay*/);
+            }
+        }
+    }
+
+    /**
+     * Unregister an IRemoteControlDisplay.
+     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
+     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
+     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
+     */
+    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
+        synchronized(mPRStack) {
+            if (rcd == null) {
+                return;
+            }
+
+            boolean displayWasPluggedIn = false;
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext() && !displayWasPluggedIn) {
+                final DisplayInfoForServer di = displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    displayWasPluggedIn = true;
+                    di.release();
+                    displayIterator.remove();
+                }
+            }
+
+            if (displayWasPluggedIn) {
+                // disconnect this remote control display from all the clients, so the remote
+                //   control stack traversal order doesn't matter
+                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final PlayerRecord prse = stackIterator.next();
+                    if(prse.getRcc() != null) {
+                        try {
+                            prse.getRcc().unplugRemoteControlDisplay(rcd);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
+                        }
+                    }
+                }
+            } else {
+                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
+            }
+        }
+    }
+
+    /**
+     * Update the size of the artwork used by an IRemoteControlDisplay.
+     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mPRStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            boolean artworkSizeUpdate = false;
+            while (displayIterator.hasNext() && !artworkSizeUpdate) {
+                final DisplayInfoForServer di = displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
+                        di.mArtworkExpectedWidth = w;
+                        di.mArtworkExpectedHeight = h;
+                        artworkSizeUpdate = true;
+                    }
+                }
+            }
+            if (artworkSizeUpdate) {
+                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
+                // stack traversal order doesn't matter
+                final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final PlayerRecord prse = stackIterator.next();
+                    if(prse.getRcc() != null) {
+                        try {
+                            prse.getRcc().setBitmapSizeForDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
+     * playback position to verify that the estimated position has not drifted from the actual
+     * position. By default the check is not performed.
+     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
+     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
+     *     or disabled. Not null.
+     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
+     *     to the framework will regularly compare the estimated playback position with the actual
+     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
+     *     detected.
+     */
+    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
+            boolean wantsSync) {
+        synchronized(mPRStack) {
+            boolean rcdRegistered = false;
+            // store the information about this display
+            // (display stack traversal order doesn't matter).
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    di.mWantsPositionSync = wantsSync;
+                    rcdRegistered = true;
+                    break;
+                }
+            }
+            if (!rcdRegistered) {
+                return;
+            }
+            // notify all current RemoteControlClients
+            // (stack traversal order doesn't matter as we notify all RCCs)
+            final Iterator<PlayerRecord> stackIterator = mPRStack.iterator();
+            while (stackIterator.hasNext()) {
+                final PlayerRecord prse = stackIterator.next();
+                if (prse.getRcc() != null) {
+                    try {
+                        prse.getRcc().setWantsSyncForDisplay(rcd, wantsSync);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
+                    }
+                }
+            }
+        }
+    }
+
+    // handler for MSG_RCC_NEW_VOLUME_OBS
+    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        synchronized(mPRStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if (prse.getRccId() == rccId) {
+                        prse.mRemoteVolumeObs = rvo;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+    }
+
+    /**
+     * Checks if a remote client is active on the supplied stream type. Update the remote stream
+     * volume state if found and playing
+     * @param streamType
+     * @return false if no remote playing is currently playing
+     */
+    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
+        synchronized(mPRStack) {
+            // iterating from top of stack as active playback is more likely on entries at the top
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    if ((prse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
+                            && isPlaystateActive(prse.mPlaybackState.mState)
+                            && (prse.mPlaybackStream == streamType)) {
+                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
+                                + ", vol =" + prse.mPlaybackVolume);
+                        synchronized (mMainRemote) {
+                            mMainRemote.mRccId = prse.getRccId();
+                            mMainRemote.mVolume = prse.mPlaybackVolume;
+                            mMainRemote.mVolumeMax = prse.mPlaybackVolumeMax;
+                            mMainRemote.mVolumeHandling = prse.mPlaybackVolumeHandling;
+                            mMainRemoteIsActive = true;
+                        }
+                        return true;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+            }
+        }
+        synchronized (mMainRemote) {
+            mMainRemoteIsActive = false;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the given playback state is considered "active", i.e. it describes a state
+     * where playback is happening, or about to
+     * @param playState the playback state to evaluate
+     * @return true if active, false otherwise (inactive or unknown)
+     */
+    protected static boolean isPlaystateActive(int playState) {
+        switch (playState) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private void sendVolumeUpdateToRemote(int rccId, int direction) {
+        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
+        if (direction == 0) {
+            // only handling discrete events
+            return;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mPRStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (prse.getRccId() == rccId) {
+                        rvo = prse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(direction, -1);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching relative volume update", e);
+            }
+        }
+    }
+
+    protected int getRemoteStreamMaxVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolumeMax;
+        }
+    }
+
+    protected int getRemoteStreamVolume() {
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return 0;
+            }
+            return mMainRemote.mVolume;
+        }
+    }
+
+    protected void setRemoteStreamVolume(int vol) {
+        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
+        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        synchronized (mMainRemote) {
+            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
+                return;
+            }
+            rccId = mMainRemote.mRccId;
+        }
+        IRemoteVolumeObserver rvo = null;
+        synchronized (mPRStack) {
+            // The stack traversal order doesn't matter because there is only one stack entry
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mPRStack.size()-1; index >= 0; index--) {
+                    final PlayerRecord prse = mPRStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (prse.getRccId() == rccId) {
+                        rvo = prse.mRemoteVolumeObs;
+                        break;
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
+            }
+        }
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(0, vol);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching absolute volume update", e);
+            }
+        }
+    }
+
+    /**
+     * Call to make AudioService reevaluate whether it's in a mode where remote players should
+     * have their volume controlled. In this implementation this is only to reset whether
+     * VolumePanel should display remote volumes
+     */
+    protected void postReevaluateRemote() {
+        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    private void onReevaluateRemote() {
+        // TODO This was used to notify VolumePanel if there was remote playback
+        // in the stack. This is now in MediaSessionService. More code should be
+        // removed.
+    }
+
+}
diff --git a/services/core/java/com/android/server/audio/PlayerRecord.java b/services/core/java/com/android/server/audio/PlayerRecord.java
new file mode 100644
index 0000000..e98f12e
--- /dev/null
+++ b/services/core/java/com/android/server/audio/PlayerRecord.java
@@ -0,0 +1,360 @@
+/*
+ * 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.audio;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.media.AudioManager;
+import android.media.IRemoteControlClient;
+import android.media.IRemoteVolumeObserver;
+import android.media.RemoteControlClient;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ * Class to handle all the information about a media player, encapsulating information
+ * about its use RemoteControlClient, playback type and volume... The lifecycle of each
+ * instance is managed by android.media.MediaFocusControl, from its addition to the player stack
+ * stack to its release.
+ */
+class PlayerRecord implements DeathRecipient {
+
+    // on purpose not using this classe's name, as it will only be used from MediaFocusControl
+    private static final String TAG = "MediaFocusControl";
+    private static final boolean DEBUG = false;
+
+    /**
+     * A global counter for RemoteControlClient identifiers
+     */
+    private static int sLastRccId = 0;
+
+    public static MediaFocusControl sController;
+
+    /**
+     * The target for the ACTION_MEDIA_BUTTON events.
+     * Always non null. //FIXME verify
+     */
+    final private PendingIntent mMediaIntent;
+    /**
+     * The registered media button event receiver.
+     */
+    final private ComponentName mReceiverComponent;
+
+    private int mRccId = -1;
+
+    /**
+     * A non-null token implies this record tracks a "live" player whose death is being monitored.
+     */
+    private IBinder mToken;
+    private String mCallingPackageName;
+    private int mCallingUid;
+    /**
+     * Provides access to the information to display on the remote control.
+     * May be null (when a media button event receiver is registered,
+     *     but no remote control client has been registered) */
+    private IRemoteControlClient mRcClient;
+    private RcClientDeathHandler mRcClientDeathHandler;
+    /**
+     * Information only used for non-local playback
+     */
+    //FIXME private?
+    public int mPlaybackType;
+    public int mPlaybackVolume;
+    public int mPlaybackVolumeMax;
+    public int mPlaybackVolumeHandling;
+    public int mPlaybackStream;
+    public RccPlaybackState mPlaybackState;
+    public IRemoteVolumeObserver mRemoteVolumeObs;
+
+
+    protected static class RccPlaybackState {
+        public int mState;
+        public long mPositionMs;
+        public float mSpeed;
+
+        public RccPlaybackState(int state, long positionMs, float speed) {
+            mState = state;
+            mPositionMs = positionMs;
+            mSpeed = speed;
+        }
+
+        public void reset() {
+            mState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
+            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
+        }
+
+        @Override
+        public String toString() {
+            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
+        }
+
+        private String posToString() {
+            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
+                return "PLAYBACK_POSITION_INVALID";
+            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
+            } else {
+                return (String.valueOf(mPositionMs) + "ms");
+            }
+        }
+
+        private String stateToString() {
+            switch (mState) {
+                case RemoteControlClient.PLAYSTATE_NONE:
+                    return "PLAYSTATE_NONE";
+                case RemoteControlClient.PLAYSTATE_STOPPED:
+                    return "PLAYSTATE_STOPPED";
+                case RemoteControlClient.PLAYSTATE_PAUSED:
+                    return "PLAYSTATE_PAUSED";
+                case RemoteControlClient.PLAYSTATE_PLAYING:
+                    return "PLAYSTATE_PLAYING";
+                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                    return "PLAYSTATE_FAST_FORWARDING";
+                case RemoteControlClient.PLAYSTATE_REWINDING:
+                    return "PLAYSTATE_REWINDING";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                    return "PLAYSTATE_SKIPPING_FORWARDS";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                    return "PLAYSTATE_SKIPPING_BACKWARDS";
+                case RemoteControlClient.PLAYSTATE_BUFFERING:
+                    return "PLAYSTATE_BUFFERING";
+                case RemoteControlClient.PLAYSTATE_ERROR:
+                    return "PLAYSTATE_ERROR";
+                default:
+                    return "[invalid playstate]";
+            }
+        }
+    }
+
+
+    /**
+     * Inner class to monitor remote control client deaths, and remove the client for the
+     * remote control stack if necessary.
+     */
+    private class RcClientDeathHandler implements IBinder.DeathRecipient {
+        final private IBinder mCb; // To be notified of client's death
+        //FIXME needed?
+        final private PendingIntent mMediaIntent;
+
+        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
+            mCb = cb;
+            mMediaIntent = pi;
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "  RemoteControlClient died");
+            // remote control client died, make sure the displays don't use it anymore
+            //  by setting its remote control client to null
+            sController.registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
+            // the dead client was maybe handling remote playback, the controller should reevaluate
+            sController.postReevaluateRemote();
+        }
+
+        public IBinder getBinder() {
+            return mCb;
+        }
+    }
+
+
+    protected static class RemotePlaybackState {
+        int mRccId;
+        int mVolume;
+        int mVolumeMax;
+        int mVolumeHandling;
+
+        protected RemotePlaybackState(int id, int vol, int volMax) {
+            mRccId = id;
+            mVolume = vol;
+            mVolumeMax = volMax;
+            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+        }
+    }
+
+
+    void dump(PrintWriter pw, boolean registrationInfo) {
+        if (registrationInfo) {
+            pw.println("  pi: " + mMediaIntent +
+                    " -- pack: " + mCallingPackageName +
+                    "  -- ercvr: " + mReceiverComponent +
+                    "  -- client: " + mRcClient +
+                    "  -- uid: " + mCallingUid +
+                    "  -- type: " + mPlaybackType +
+                    "  state: " + mPlaybackState);
+        } else {
+            // emphasis on state
+            pw.println("  uid: " + mCallingUid +
+                    "  -- id: " + mRccId +
+                    "  -- type: " + mPlaybackType +
+                    "  -- state: " + mPlaybackState +
+                    "  -- vol handling: " + mPlaybackVolumeHandling +
+                    "  -- vol: " + mPlaybackVolume +
+                    "  -- volMax: " + mPlaybackVolumeMax +
+                    "  -- volObs: " + mRemoteVolumeObs);
+        }
+    }
+
+
+    static protected void setMediaFocusControl(MediaFocusControl mfc) {
+        sController = mfc;
+    }
+
+    /** precondition: mediaIntent != null */
+    protected PlayerRecord(PendingIntent mediaIntent, ComponentName eventReceiver, IBinder token)
+    {
+        mMediaIntent = mediaIntent;
+        mReceiverComponent = eventReceiver;
+        mToken = token;
+        mCallingUid = -1;
+        mRcClient = null;
+        mRccId = ++sLastRccId;
+        mPlaybackState = new RccPlaybackState(
+                RemoteControlClient.PLAYSTATE_STOPPED,
+                RemoteControlClient.PLAYBACK_POSITION_INVALID,
+                RemoteControlClient.PLAYBACK_SPEED_1X);
+
+        resetPlaybackInfo();
+        if (mToken != null) {
+            try {
+                mToken.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                sController.unregisterMediaButtonIntentAsync(mMediaIntent);
+            }
+        }
+    }
+
+    //---------------------------------------------
+    // Accessors
+    protected int getRccId() {
+        return mRccId;
+    }
+
+    protected IRemoteControlClient getRcc() {
+        return mRcClient;
+    }
+
+    protected ComponentName getMediaButtonReceiver() {
+        return mReceiverComponent;
+    }
+
+    protected PendingIntent getMediaButtonIntent() {
+        return mMediaIntent;
+    }
+
+    protected boolean hasMatchingMediaButtonIntent(PendingIntent pi) {
+        if (mToken != null) {
+            return mMediaIntent.equals(pi);
+        } else {
+            if (mReceiverComponent != null) {
+                return mReceiverComponent.equals(pi.getIntent().getComponent());
+            } else {
+                return false;
+            }
+        }
+    }
+
+    protected boolean isPlaybackActive() {
+        return MediaFocusControl.isPlaystateActive(mPlaybackState.mState);
+    }
+
+    //---------------------------------------------
+    // Modify the records stored in the instance
+    protected void resetControllerInfoForRcc(IRemoteControlClient rcClient,
+            String callingPackageName, int uid) {
+        // already had a remote control client?
+        if (mRcClientDeathHandler != null) {
+            // stop monitoring the old client's death
+            unlinkToRcClientDeath();
+        }
+        // save the new remote control client
+        mRcClient = rcClient;
+        mCallingPackageName = callingPackageName;
+        mCallingUid = uid;
+        if (rcClient == null) {
+            // here mcse.mRcClientDeathHandler is null;
+            resetPlaybackInfo();
+        } else {
+            IBinder b = mRcClient.asBinder();
+            RcClientDeathHandler rcdh =
+                    new RcClientDeathHandler(b, mMediaIntent);
+            try {
+                b.linkToDeath(rcdh, 0);
+            } catch (RemoteException e) {
+                // remote control client is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+                mRcClient = null;
+            }
+            mRcClientDeathHandler = rcdh;
+        }
+    }
+
+    protected void resetControllerInfoForNoRcc() {
+        // stop monitoring the RCC death
+        unlinkToRcClientDeath();
+        // reset the RCC-related fields
+        mRcClient = null;
+        mCallingPackageName = null;
+    }
+
+    public void resetPlaybackInfo() {
+        mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
+        mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+        mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+        mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+        mPlaybackStream = AudioManager.STREAM_MUSIC;
+        mPlaybackState.reset();
+        mRemoteVolumeObs = null;
+    }
+
+    //---------------------------------------------
+    public void unlinkToRcClientDeath() {
+        if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+            try {
+                mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+                mRcClientDeathHandler = null;
+            } catch (java.util.NoSuchElementException e) {
+                // not much we can do here
+                Log.e(TAG, "Error in unlinkToRcClientDeath()", e);
+            }
+        }
+    }
+
+    // FIXME rename to "release"? (as in FocusRequester class)
+    public void destroy() {
+        unlinkToRcClientDeath();
+        if (mToken != null) {
+            mToken.unlinkToDeath(this, 0);
+            mToken = null;
+        }
+    }
+
+    @Override
+    public void binderDied() {
+        sController.unregisterMediaButtonIntentAsync(mMediaIntent);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        destroy(); // unlink exception handled inside method
+        super.finalize();
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3fa21d0..a9eaeee 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -22,16 +22,13 @@
 import java.net.Inet4Address;
 
 import android.content.Context;
-import android.net.IConnectivityManager;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkAgent;
-import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Messenger;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.util.Slog;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 87f78c1..d0e1665 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -24,9 +24,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.ProxyInfo;
 import android.net.TrafficStats;
@@ -54,7 +51,6 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.server.ConnectivityService;
 import com.android.server.connectivity.NetworkAgentInfo;
 
 import java.io.IOException;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 5ff7022..f9b6270 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -40,9 +40,7 @@
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8533f69..7f47678 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,12 +17,8 @@
 package com.android.server.connectivity;
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
-import static android.os.UserHandle.PER_USER_RANGE;
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
 import android.Manifest;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -33,7 +29,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -74,6 +69,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
 import com.android.server.net.BaseNetworkObserver;
 
@@ -727,6 +723,7 @@
                 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
                     mStatusIntent = null;
                     mVpnUsers = null;
+                    mConfig = null;
                     mInterface = null;
                     if (mConnection != null) {
                         mContext.unbindService(mConnection);
@@ -812,6 +809,21 @@
         return mConfig.underlyingNetworks;
     }
 
+    /**
+     * This method should only be called by ConnectivityService. Because it doesn't
+     * have enough data to fill VpnInfo.primaryUnderlyingIface field.
+     */
+    public synchronized VpnInfo getVpnInfo() {
+        if (!isRunningLocked()) {
+            return null;
+        }
+
+        VpnInfo info = new VpnInfo();
+        info.ownerUid = mOwnerUID;
+        info.vpnIface = mInterface;
+        return info;
+    }
+
     public synchronized boolean appliesToUid(int uid) {
         if (!isRunningLocked()) {
             return false;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 165148b..ea461e5 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -25,7 +25,6 @@
 import android.content.IContentService;
 import android.content.ISyncStatusObserver;
 import android.content.PeriodicSync;
-import android.content.pm.PackageManager;
 import android.content.SyncAdapterType;
 import android.content.SyncInfo;
 import android.content.SyncRequest;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 6dcbc42..1ea9673 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -702,6 +702,11 @@
         }
 
         for (AccountAndUser account : accounts) {
+            // If userId is specified, do not sync accounts of other users
+            if (userId >= UserHandle.USER_OWNER && account.userId >= UserHandle.USER_OWNER
+                    && userId != account.userId) {
+                continue;
+            }
             // Compile a list of authorities that have sync adapters.
             // For each authority sync each account that matches a sync adapter.
             final HashSet<String> syncableAuthorities = new HashSet<String>();
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 0d5f240..f154c73 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -18,6 +18,7 @@
 
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
+import android.app.backup.BackupManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -670,6 +671,7 @@
                     new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+        queueBackup();
     }
 
     public int getIsSyncable(Account account, int userId, String providerName) {
@@ -1035,6 +1037,7 @@
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         mContext.sendBroadcast(ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED);
+        queueBackup();
     }
 
     public boolean getMasterSyncAutomatically(int userId) {
@@ -2810,4 +2813,12 @@
                 .append(")\n");
         }
     }
+
+    /**
+     * Let the BackupManager know that account sync settings have changed. This will trigger
+     * {@link com.android.server.backup.SystemBackupAgent} to run.
+     */
+    public void queueBackup() {
+        BackupManager.dataChanged("android");
+    }
 }
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index d919bf6..93d37f1 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -52,20 +52,9 @@
     // auto-brightness adjustment setting.
     private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
 
-    // Light sensor event rate in milliseconds.
-    private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
-
     // Period of time in which to consider light samples in milliseconds.
     private static final int AMBIENT_LIGHT_HORIZON = 10000;
 
-    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
-    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
-    // when adapting to brighter or darker environments.  This parameter controls how quickly
-    // brightness changes occur in response to an observed change in light level that exceeds the
-    // hysteresis threshold.
-    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
-    private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
-
     // Hysteresis constraints for brightening or darkening.
     // The recent lux must have changed by at least this fraction relative to the
     // current ambient lux before a change will be considered.
@@ -121,6 +110,22 @@
     private final int mScreenBrightnessRangeMaximum;
     private final float mDozeScaleFactor;
 
+    // Light sensor event rate in milliseconds.
+    private final int mLightSensorRate;
+
+    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
+    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
+    // when adapting to brighter or darker environments.  This parameter controls how quickly
+    // brightness changes occur in response to an observed change in light level that exceeds the
+    // hysteresis threshold.
+    private final long mBrighteningLightDebounceConfig;
+    private final long mDarkeningLightDebounceConfig;
+
+    // If true immediately after the screen is turned on the controller will try to adjust the
+    // brightness based on the current sensor reads. If false, the controller will collect more data
+    // and only then decide whether to change brightness.
+    private final boolean mResetAmbientLuxAfterWarmUpConfig;
+
     // Amount of time to delay auto-brightness after screen on while waiting for
     // the light sensor to warm-up in milliseconds.
     // May be 0 if no warm-up is required.
@@ -176,7 +181,9 @@
 
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
-            int brightnessMin, int brightnessMax, float dozeScaleFactor) {
+            int brightnessMin, int brightnessMax, float dozeScaleFactor,
+            int lightSensorRate, long brighteningLightDebounceConfig,
+            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) {
         mCallbacks = callbacks;
         mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
@@ -185,9 +192,13 @@
         mScreenBrightnessRangeMaximum = brightnessMax;
         mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
         mDozeScaleFactor = dozeScaleFactor;
+        mLightSensorRate = lightSensorRate;
+        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
+        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
+        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
 
         mHandler = new AutomaticBrightnessHandler(looper);
-        mAmbientLightRingBuffer = new AmbientLightRingBuffer();
+        mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
 
         if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -226,6 +237,9 @@
         pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
         pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
         pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
+        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
+        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
+        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
 
         pw.println();
         pw.println("Automatic Brightness Controller State:");
@@ -252,13 +266,13 @@
                 mLightSensorEnabled = true;
                 mLightSensorEnableTime = SystemClock.uptimeMillis();
                 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
-                        LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
+                        mLightSensorRate * 1000, mHandler);
                 return true;
             }
         } else {
             if (mLightSensorEnabled) {
                 mLightSensorEnabled = false;
-                mAmbientLuxValid = false;
+                mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
                 mRecentLightSamples = 0;
                 mAmbientLightRingBuffer.clear();
                 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
@@ -347,7 +361,7 @@
             }
             earliestValidTime = mAmbientLightRingBuffer.getTime(i);
         }
-        return earliestValidTime + BRIGHTENING_LIGHT_DEBOUNCE;
+        return earliestValidTime + mBrighteningLightDebounceConfig;
     }
 
     private long nextAmbientLightDarkeningTransition(long time) {
@@ -359,7 +373,7 @@
             }
             earliestValidTime = mAmbientLightRingBuffer.getTime(i);
         }
-        return earliestValidTime + DARKENING_LIGHT_DEBOUNCE;
+        return earliestValidTime + mDarkeningLightDebounceConfig;
     }
 
     private void updateAmbientLux() {
@@ -420,7 +434,7 @@
         // should be enough time to decide whether we should actually transition to the new
         // weighted ambient lux or not.
         nextTransitionTime =
-                nextTransitionTime > time ? nextTransitionTime : time + LIGHT_SENSOR_RATE_MILLIS;
+                nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
         if (DEBUG) {
             Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
                     + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
@@ -559,8 +573,6 @@
         // Proportional extra capacity of the buffer beyond the expected number of light samples
         // in the horizon
         private static final float BUFFER_SLACK = 1.5f;
-        private static final int DEFAULT_CAPACITY =
-            (int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / LIGHT_SENSOR_RATE_MILLIS);
         private float[] mRingLux;
         private long[] mRingTime;
         private int mCapacity;
@@ -571,8 +583,8 @@
         private int mEnd;
         private int mCount;
 
-        public AmbientLightRingBuffer() {
-            this(DEFAULT_CAPACITY);
+        public AmbientLightRingBuffer(long lightSensorRate) {
+            this((int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate));
         }
 
         public AmbientLightRingBuffer(int initialCapacity) {
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 6e61e41..bb4dbc3 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -25,7 +25,6 @@
 import java.nio.FloatBuffer;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManagerInternal;
@@ -37,7 +36,6 @@
 import android.opengl.EGLSurface;
 import android.opengl.GLES20;
 import android.opengl.GLES11Ext;
-import android.util.FloatMath;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface.OutOfResourcesException;
@@ -48,7 +46,6 @@
 import libcore.io.Streams;
 
 import com.android.server.LocalServices;
-import com.android.internal.R;
 
 /**
  * <p>
@@ -372,13 +369,13 @@
             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
 
             // Draw the frame.
-            float one_minus_level = 1 - level;
-            float cos = FloatMath.cos((float)Math.PI * one_minus_level);
-            float sign = cos < 0 ? -1 : 1;
-            float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
-            float saturation = FloatMath.pow(level, 4);
-            float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
-            float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+            double one_minus_level = 1 - level;
+            double cos = Math.cos(Math.PI * one_minus_level);
+            double sign = cos < 0 ? -1 : 1;
+            float opacity = (float) -Math.pow(one_minus_level, 2) + 1;
+            float saturation = (float) Math.pow(level, 4);
+            float scale = (float) ((-Math.pow(one_minus_level, 2) + 1) * 0.1d + 0.9d);
+            float gamma = (float) ((0.5d * sign * Math.pow(cos, 2) + 0.5d) * 0.9d + 0.1d);
             drawFaded(opacity, 1.f / gamma, saturation, scale);
             if (checkGlErrors("drawFrame")) {
                 return false;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 09dc477..5f0ad9f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -46,7 +46,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -832,6 +831,24 @@
         }
     }
 
+    private void setDisplayOffsetsInternal(int displayId, int x, int y) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            if (display.getDisplayOffsetXLocked() != x
+                    || display.getDisplayOffsetYLocked() != y) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
+                            + x + ", " + y + ")");
+                }
+                display.setDisplayOffsetsLocked(x, y);
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mDefaultViewport.valid = false;
         mExternalTouchViewport.valid = false;
@@ -1513,5 +1530,10 @@
                 float requestedRefreshRate, boolean inTraversal) {
             setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal);
         }
+
+        @Override
+        public void setDisplayOffsets(int displayId, int x, int y) {
+            setDisplayOffsetsInternal(displayId, x, y);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 78610ff..cf1f4b0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -302,6 +302,15 @@
         mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
 
+        int lightSensorRate = resources.getInteger(
+                com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
+        long brighteningLightDebounce = resources.getInteger(
+                com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
+        long darkeningLightDebounce = resources.getInteger(
+                com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
+        boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
+                com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
+
         if (mUseSoftwareAutoBrightnessConfig) {
             int[] lux = resources.getIntArray(
                     com.android.internal.R.array.config_autoBrightnessLevels);
@@ -336,7 +345,9 @@
                 mAutomaticBrightnessController = new AutomaticBrightnessController(this,
                         handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
                         lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
-                        mScreenBrightnessRangeMaximum, dozeScaleFactor);
+                        mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
+                        brighteningLightDebounce, darkeningLightDebounce,
+                        autoBrightnessResetAmbientLuxAfterWarmUp);
             }
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index fc068af..c97bdb6 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -19,7 +19,6 @@
 import com.android.server.lights.Light;
 
 import android.content.Context;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6c57eec..3bb7818 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -76,6 +76,10 @@
     // The pending requested refresh rate. 0 if no request is pending.
     private float mRequestedRefreshRate;
 
+    // The display offsets to apply to the display projection.
+    private int mDisplayOffsetX;
+    private int mDisplayOffsetY;
+
     // Temporary rectangle used when needed.
     private final Rect mTempLayerStackRect = new Rect();
     private final Rect mTempDisplayRect = new Rect();
@@ -313,6 +317,10 @@
         mTempDisplayRect.set(displayRectLeft, displayRectTop,
                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
 
+        mTempDisplayRect.left += mDisplayOffsetX;
+        mTempDisplayRect.right += mDisplayOffsetX;
+        mTempDisplayRect.top += mDisplayOffsetY;
+        mTempDisplayRect.bottom += mDisplayOffsetY;
         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
@@ -356,10 +364,34 @@
         return mRequestedRefreshRate;
     }
 
+    /**
+     * Gets the burn-in offset in X.
+     */
+    public int getDisplayOffsetXLocked() {
+        return mDisplayOffsetX;
+    }
+
+    /**
+     * Gets the burn-in offset in Y.
+     */
+    public int getDisplayOffsetYLocked() {
+        return mDisplayOffsetY;
+    }
+
+    /**
+     * Sets the burn-in offsets.
+     */
+    public void setDisplayOffsetsLocked(int x, int y) {
+        mDisplayOffsetX = x;
+        mDisplayOffsetY = y;
+    }
+
     public void dumpLocked(PrintWriter pw) {
         pw.println("mDisplayId=" + mDisplayId);
         pw.println("mLayerStack=" + mLayerStack);
         pw.println("mHasContent=" + mHasContent);
+        pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
+        pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
                 mPrimaryDisplayDevice.getNameLocked() : "null"));
         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 5b6f35b..af9f456 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -355,7 +355,7 @@
             if (mWindow != null) {
                 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
                 ipw.increaseIndent();
-                DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, 200);
+                DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, "", 200);
             }
         }
 
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 9ca5fda..3f4eab9 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -153,7 +153,7 @@
     }
 
     @Override
-    public void dump(PrintWriter pw) {
+    public void dump(PrintWriter pw, String prefix) {
         pw.println("mWindowVisible=" + mWindowVisible);
         pw.println("mWindowX=" + mWindowX);
         pw.println("mWindowY=" + mWindowY);
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index c939861..f163555 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -123,7 +123,7 @@
             pw.println("mDisplayController:");
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
             ipw.increaseIndent();
-            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
+            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, "", 200);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index dbb59b2..31c1eea 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -209,7 +209,7 @@
     }
 
     @Override
-    public void dump(PrintWriter pw) {
+    public void dump(PrintWriter pw, String prefix) {
         pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
         pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
         pw.println("mWfdEnabled=" + mWfdEnabled);
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 4521c28..458928f 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -137,10 +137,10 @@
 
         DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
             @Override
-            public void dump(PrintWriter pw) {
+            public void dump(PrintWriter pw, String prefix) {
                 mController.dump(pw);
             }
-        }, pw, 200);
+        }, pw, "", 200);
     }
 
     private boolean isDreamingInternal() {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 2941574..b398f41 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,15 +16,12 @@
 
 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.Looper;
+import android.os.MessageQueue;
 import android.os.RemoteException;
-import android.provider.Settings;
 import android.service.fingerprint.FingerprintManager;
 import android.util.ArrayMap;
 import android.util.Slog;
@@ -34,12 +31,10 @@
 import android.service.fingerprint.FingerprintUtils;
 import android.service.fingerprint.IFingerprintService;
 import android.service.fingerprint.IFingerprintServiceReceiver;
+import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.USE_FINGERPRINT;
 
-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.
@@ -68,14 +63,13 @@
         }
     };
     private Context mContext;
+    private int mHalDeviceId;
 
     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;
@@ -113,17 +107,17 @@
     public FingerprintService(Context context) {
         super(context);
         mContext = context;
-        nativeInit(this);
+        nativeInit(Looper.getMainLooper().getQueue(), 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);
+    static native int nativeEnroll(int timeout);
+    static native int nativeEnrollCancel();
+    static native int nativeRemove(int fingerprintId);
+    static native int nativeOpenHal();
+    static native int nativeCloseHal();
+    static native void nativeInit(MessageQueue queue, FingerprintService service);
 
     // JNI methods for communicating from HAL to clients
     void notify(int msg, int arg1, int arg2) {
@@ -131,11 +125,13 @@
     }
 
     void handleNotify(int msg, int arg1, int arg2) {
-        Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
+        Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
+                + ", " + mClients.size() + " clients");
         for (int i = 0; i < mClients.size(); i++) {
+            if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i));
             ClientData clientData = mClients.valueAt(i);
             if (clientData == null || clientData.receiver == null) {
-                if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
+                if (DEBUG) Slog.v(TAG, "clientData is invalid!!");
                 continue;
             }
             switch (msg) {
@@ -282,26 +278,27 @@
         mClients.remove(token);
     }
 
-    void checkPermission(String permisison) {
-        // TODO
+    void checkPermission(String permission) {
+        getContext().enforceCallingOrSelfPermission(permission, "Must have "
+                + permission + " permission.");
     }
 
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
         @Override // Binder call
         public void enroll(IBinder token, long timeout, int userId) {
-            checkPermission(ENROLL_FINGERPRINT);
+            checkPermission(MANAGE_FINGERPRINT);
             startEnroll(token, timeout, userId);
         }
 
         @Override // Binder call
         public void enrollCancel(IBinder token,int userId) {
-            checkPermission(ENROLL_FINGERPRINT);
+            checkPermission(MANAGE_FINGERPRINT);
             startEnrollCancel(token, userId);
         }
 
         @Override // Binder call
         public void remove(IBinder token, int fingerprintId, int userId) {
-            checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
+            checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
             startRemove(token, fingerprintId, userId);
         }
 
@@ -317,12 +314,25 @@
             checkPermission(USE_FINGERPRINT);
             removeListener(token, userId);
         }
+
+        @Override // Binder call
+        public boolean isHardwareDetected() {
+            checkPermission(USE_FINGERPRINT);
+            return mHalDeviceId != 0;
+        }
+
+        @Override
+        public void rename(int fpId, String name) {
+            checkPermission(MANAGE_FINGERPRINT);
+            // TODO
+        }
     }
 
     @Override
     public void onStart() {
        publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
-       nativeOpenHal();
+       mHalDeviceId = nativeOpenHal();
+       if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
     }
 
 }
diff --git a/services/core/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
index c0eee69..0074119 100644
--- a/services/core/java/com/android/server/firewall/SenderFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderFilter.java
@@ -45,7 +45,8 @@
 
         IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            return (pm.getFlagsForUid(callerUid) & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+            return (pm.getPrivateFlagsForUid(callerUid) & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                    != 0;
         } catch (RemoteException ex) {
             Slog.e(IntentFirewall.TAG, "Remote exception while retrieving uid flags",
                     ex);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0c86aed..e434f39 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -214,6 +214,10 @@
     //     values which denotes the device type in HDMI Spec 1.4.
     static final String PROPERTY_DEVICE_TYPE = "ro.hdmi.device_type";
 
+    // Set to false to allow playback device to go to suspend mode even
+    // when it's an active source. True by default.
+    static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
+
     static final int RECORDING_TYPE_DIGITAL_RF = 1;
     static final int RECORDING_TYPE_ANALOGUE_RF = 2;
     static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
diff --git a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
index 77ffe0b..2c1a7d5 100644
--- a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
+++ b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
@@ -17,8 +17,6 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
-import android.util.Slog;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index a8f6954..1e43670 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -38,9 +38,11 @@
 
     // Used to keep the device awake while it is the active source. For devices that
     // cannot wake up via CEC commands, this address the inconvenience of having to
-    // turn them on.
+    // turn them on. True by default, and can be disabled (i.e. device can go to sleep
+    // in active device status) by explicitly setting the system property
+    // persist.sys.hdmi.keep_awake to false.
     // Lazily initialized - should call getWakeLock() to get the instance.
-    private WakeLock mWakeLock;
+    private ActiveWakeLock mWakeLock;
 
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -142,19 +144,30 @@
         mIsActiveSource = on;
         if (on) {
             getWakeLock().acquire();
-            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
         } else {
             getWakeLock().release();
-            HdmiLogger.debug("Wake lock released");
         }
     }
 
     @ServiceThreadOnly
-    private WakeLock getWakeLock() {
+    private ActiveWakeLock getWakeLock() {
         assertRunOnServiceThread();
         if (mWakeLock == null) {
-            mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-            mWakeLock.setReferenceCounted(false);
+            if (SystemProperties.getBoolean(Constants.PROPERTY_KEEP_AWAKE, true)) {
+                mWakeLock = new SystemWakeLock();
+            } else {
+                // Create a dummy lock object that doesn't do anything about wake lock,
+                // hence allows the device to go to sleep even if it's the active source.
+                mWakeLock = new ActiveWakeLock() {
+                    @Override
+                    public void acquire() { }
+                    @Override
+                    public void release() { }
+                    @Override
+                    public boolean isHeld() { return false; }
+                };
+                HdmiLogger.debug("No wakelock is used to keep the display on.");
+            }
         }
         return mWakeLock;
     }
@@ -258,4 +271,36 @@
         super.dump(pw);
         pw.println("mIsActiveSource: " + mIsActiveSource);
     }
+
+    // Wrapper interface over PowerManager.WakeLock
+    private interface ActiveWakeLock {
+        void acquire();
+        void release();
+        boolean isHeld();
+    }
+
+    private class SystemWakeLock implements ActiveWakeLock {
+        private final WakeLock mWakeLock;
+        public SystemWakeLock() {
+            mWakeLock = mService.getPowerManager().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+            mWakeLock.setReferenceCounted(false);
+        }
+
+        @Override
+        public void acquire() {
+            mWakeLock.acquire();
+            HdmiLogger.debug("active source: %b. Wake lock acquired", mIsActiveSource);
+        }
+
+        @Override
+        public void release() {
+            mWakeLock.release();
+            HdmiLogger.debug("Wake lock released");
+        }
+
+        @Override
+        public boolean isHeld() {
+            return mWakeLock.isHeld();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8241cdc..7c93e56 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,8 +30,6 @@
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
 
-import android.annotation.Nullable;
-import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
@@ -41,10 +39,8 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
-import android.media.tv.TvInputManager;
 import android.media.tv.TvInputManager.TvInputCallback;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.provider.Settings.Global;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -55,8 +51,6 @@
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
-import com.android.server.SystemService;
-
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -208,7 +202,6 @@
                 reason != HdmiControlService.INITIATED_BY_BOOT_UP);
         mLocalDeviceAddresses = initLocalDeviceAddresses();
         launchDeviceDiscovery();
-        startQueuedActions();
     }
 
 
@@ -881,7 +874,7 @@
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
         // 1. Enable/disable ARC circuit.
-        mService.setAudioReturnChannel(getAvrDeviceInfo().getPortId(), enabled);
+        setAudioReturnChannel(enabled);
         // 2. Notify arc status to audio service.
         notifyArcStatusToAudioService(enabled);
         // 3. Update arc status;
@@ -889,6 +882,18 @@
         return oldStatus;
     }
 
+    /**
+     * Switch hardware ARC circuit in the system.
+     */
+    @ServiceThreadOnly
+    void setAudioReturnChannel(boolean enabled) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
+        if (avr != null) {
+            mService.setAudioReturnChannel(avr.getPortId(), enabled);
+        }
+    }
+
     @ServiceThreadOnly
     private void updateArcFeatureStatus(int portId, boolean isConnected) {
         assertRunOnServiceThread();
@@ -904,7 +909,7 @@
         // Note that we don't set any name to ARC.
         mService.getAudioManager().setWiredDeviceConnectionState(
                 AudioSystem.DEVICE_OUT_HDMI_ARC,
-                enabled ? 1 : 0, "");
+                enabled ? 1 : 0, "", "");
     }
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
index 3883200..f19b19b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
+++ b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
@@ -20,7 +20,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
 /**
  * A handler class for MHL control command. It converts user's command into MHL command and pass it
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 1bbd038..f7555e9 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -262,6 +262,7 @@
         // Turn off system audio mode and update settings.
         tv().setSystemAudioMode(false, true);
         if (tv().isArcEstabilished()) {
+            tv().setAudioReturnChannel(false);
             addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 31322a9..cbbf91b 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -17,7 +17,6 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
-import android.util.Slog;
 
 /**
  * Base feature action class for &lt;Request ARC Initiation&gt;/&lt;Request ARC Termination&gt;.
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 7b71027..8e2ca18 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -22,7 +22,6 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index ca56886..7d76fc0 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 
-import com.android.server.job.JobSchedulerService;
 import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 5ae6300..7c41abbc 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -22,10 +22,8 @@
 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
-import com.android.internal.R;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
 
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
@@ -72,7 +70,6 @@
 import android.provider.Telephony.Carriers;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.SmsMessage;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
@@ -91,7 +88,6 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Date;
-import java.util.List;
 import java.util.Map.Entry;
 import java.util.Properties;
 
@@ -395,7 +391,7 @@
 
     private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
         @Override
-        public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
+        public void addGpsStatusListener(IGpsStatusListener listener) {
             mListenerHelper.addListener(listener);
         }
 
@@ -681,7 +677,7 @@
         mListenerHelper = new GpsStatusListenerHelper(mHandler) {
             @Override
             protected boolean isAvailableInPlatform() {
-                return GpsLocationProvider.isSupported();
+                return isSupported();
             }
 
             @Override
@@ -914,7 +910,7 @@
         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
             @Override
             public void run() {
-                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
+                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
                 byte[] data = xtraDownloader.downloadXtraData();
                 if (data != null) {
                     if (DEBUG) {
@@ -1025,6 +1021,9 @@
             if (mC2KServerHost != null) {
                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
             }
+
+            mGpsMeasurementsProvider.onGpsEnabledChanged();
+            mGpsNavigationMessageProvider.onGpsEnabledChanged();
         } else {
             synchronized (mLock) {
                 mEnabled = false;
@@ -1058,6 +1057,9 @@
 
         // do this before releasing wakelock
         native_cleanup();
+
+        mGpsMeasurementsProvider.onGpsEnabledChanged();
+        mGpsNavigationMessageProvider.onGpsEnabledChanged();
     }
 
     @Override
@@ -1477,9 +1479,7 @@
         }
 
         if (wasNavigating != mNavigating) {
-            mListenerHelper.onGpsEnabledChanged(mNavigating);
-            mGpsMeasurementsProvider.onGpsEnabledChanged(mNavigating);
-            mGpsNavigationMessageProvider.onGpsEnabledChanged(mNavigating);
+            mListenerHelper.onStatusChanged(mNavigating);
 
             // send an intent to notify that the GPS has been enabled or disabled
             Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
diff --git a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
index 0514e0c..b327ca2 100644
--- a/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GpsMeasurementsProvider.java
@@ -33,7 +33,7 @@
         extends RemoteListenerHelper<IGpsMeasurementsListener> {
     private static final String TAG = "GpsMeasurementsProvider";
 
-    public GpsMeasurementsProvider(Handler handler) {
+    protected GpsMeasurementsProvider(Handler handler) {
         super(handler, TAG);
     }
 
@@ -49,15 +49,19 @@
     }
 
     public void onCapabilitiesUpdated(boolean isGpsMeasurementsSupported) {
-        int status = isGpsMeasurementsSupported ?
-                GpsMeasurementsEvent.STATUS_READY :
-                GpsMeasurementsEvent.STATUS_NOT_SUPPORTED;
-        setSupported(isGpsMeasurementsSupported, new StatusChangedOperation(status));
+        setSupported(isGpsMeasurementsSupported);
+        updateResult();
+    }
+
+    public void onGpsEnabledChanged() {
+        if (tryUpdateRegistrationWithService()) {
+            updateResult();
+        }
     }
 
     @Override
     protected ListenerOperation<IGpsMeasurementsListener> getHandlerOperation(int result) {
-        final int status;
+        int status;
         switch (result) {
             case RESULT_SUCCESS:
                 status = GpsMeasurementsEvent.STATUS_READY;
@@ -70,6 +74,8 @@
             case RESULT_GPS_LOCATION_DISABLED:
                 status = GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
                 break;
+            case RESULT_UNKNOWN:
+                return null;
             default:
                 Log.v(TAG, "Unhandled addListener result: " + result);
                 return null;
@@ -77,15 +83,8 @@
         return new StatusChangedOperation(status);
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
-        int status = enabled ?
-                GpsMeasurementsEvent.STATUS_READY :
-                GpsMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
-        foreach(new StatusChangedOperation(status));
-    }
-
-    private class StatusChangedOperation implements ListenerOperation<IGpsMeasurementsListener> {
+    private static class StatusChangedOperation
+            implements ListenerOperation<IGpsMeasurementsListener> {
         private final int mStatus;
 
         public StatusChangedOperation(int status) {
diff --git a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
index 13d22fc..e6bbe56 100644
--- a/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GpsNavigationMessageProvider.java
@@ -33,7 +33,7 @@
         extends RemoteListenerHelper<IGpsNavigationMessageListener> {
     private static final String TAG = "GpsNavigationMessageProvider";
 
-    public GpsNavigationMessageProvider(Handler handler) {
+    protected GpsNavigationMessageProvider(Handler handler) {
         super(handler, TAG);
     }
 
@@ -50,15 +50,19 @@
     }
 
     public void onCapabilitiesUpdated(boolean isGpsNavigationMessageSupported) {
-        int status = isGpsNavigationMessageSupported ?
-                GpsNavigationMessageEvent.STATUS_READY :
-                GpsNavigationMessageEvent.STATUS_NOT_SUPPORTED;
-        setSupported(isGpsNavigationMessageSupported, new StatusChangedOperation(status));
+        setSupported(isGpsNavigationMessageSupported);
+        updateResult();
+    }
+
+    public void onGpsEnabledChanged() {
+        if (tryUpdateRegistrationWithService()) {
+            updateResult();
+        }
     }
 
     @Override
     protected ListenerOperation<IGpsNavigationMessageListener> getHandlerOperation(int result) {
-        final int status;
+        int status;
         switch (result) {
             case RESULT_SUCCESS:
                 status = GpsNavigationMessageEvent.STATUS_READY;
@@ -71,6 +75,8 @@
             case RESULT_GPS_LOCATION_DISABLED:
                 status = GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
                 break;
+            case RESULT_UNKNOWN:
+                return null;
             default:
                 Log.v(TAG, "Unhandled addListener result: " + result);
                 return null;
@@ -78,15 +84,7 @@
         return new StatusChangedOperation(status);
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
-        int status = enabled ?
-                GpsNavigationMessageEvent.STATUS_READY :
-                GpsNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
-        foreach(new StatusChangedOperation(status));
-    }
-
-    private class StatusChangedOperation
+    private static class StatusChangedOperation
             implements ListenerOperation<IGpsNavigationMessageListener> {
         private final int mStatus;
 
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
index 376b4a5..53ff6c2 100644
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
@@ -24,14 +24,9 @@
  * Implementation of a handler for {@link IGpsStatusListener}.
  */
 abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
-    public GpsStatusListenerHelper(Handler handler) {
+    protected GpsStatusListenerHelper(Handler handler) {
         super(handler, "GpsStatusListenerHelper");
-
-        Operation nullOperation = new Operation() {
-            @Override
-            public void execute(IGpsStatusListener iGpsStatusListener) throws RemoteException {}
-        };
-        setSupported(GpsLocationProvider.isSupported(), nullOperation);
+        setSupported(GpsLocationProvider.isSupported());
     }
 
     @Override
@@ -47,10 +42,9 @@
         return null;
     }
 
-    @Override
-    protected void handleGpsEnabledChanged(boolean enabled) {
+    public void onStatusChanged(boolean isNavigating) {
         Operation operation;
-        if (enabled) {
+        if (isNavigating) {
             operation = new Operation() {
                 @Override
                 public void execute(IGpsStatusListener listener) throws RemoteException {
@@ -114,5 +108,5 @@
         foreach(operation);
     }
 
-    private abstract class Operation implements ListenerOperation<IGpsStatusListener> { }
+    private interface Operation extends ListenerOperation<IGpsStatusListener> {}
 }
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index a5eef6a..3585049 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -16,21 +16,13 @@
 
 package com.android.server.location;
 
-import android.content.Context;
-import android.net.Proxy;
-import android.net.http.AndroidHttpClient;
 import android.text.TextUtils;
 import android.util.Log;
 
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.params.ConnRouteParams;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import libcore.io.Streams;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 import java.util.Properties;
 import java.util.Random;
@@ -46,15 +38,12 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String DEFAULT_USER_AGENT = "Android";
 
-    private final Context mContext;
     private final String[] mXtraServers;
     // to load balance our server requests
     private int mNextServerIndex;
     private final String mUserAgent;
 
-    GpsXtraDownloader(Context context, Properties properties) {
-        mContext = context;
-
+    GpsXtraDownloader(Properties properties) {
         // read XTRA servers from the Properties object
         int count = 0;
         String server1 = properties.getProperty("XTRA_SERVER_1");
@@ -75,7 +64,6 @@
         if (count == 0) {
             Log.e(TAG, "No XTRA servers were specified in the GPS configuration");
             mXtraServers = null;
-            return;
         } else {
             mXtraServers = new String[count];
             count = 0;
@@ -90,9 +78,6 @@
     }
 
     byte[] downloadXtraData() {
-        String proxyHost = Proxy.getHost(mContext);
-        int proxyPort = Proxy.getPort(mContext);
-        boolean useProxy = (proxyHost != null && proxyPort != -1);
         byte[] result = null;
         int startIndex = mNextServerIndex;
 
@@ -102,7 +87,7 @@
 
         // load balance our requests among the available servers
         while (result == null) {
-            result = doDownload(mXtraServers[mNextServerIndex], useProxy, proxyHost, proxyPort);
+            result = doDownload(mXtraServers[mNextServerIndex]);
 
             // increment mNextServerIndex and wrap around if necessary
             mNextServerIndex++;
@@ -116,65 +101,32 @@
         return result;
     }
 
-    protected byte[] doDownload(String url, boolean isProxySet,
-            String proxyHost, int proxyPort) {
+    protected byte[] doDownload(String url) {
         if (DEBUG) Log.d(TAG, "Downloading XTRA data from " + url);
 
-        AndroidHttpClient client = null;
+        HttpURLConnection connection = null;
         try {
-            if (DEBUG) Log.d(TAG, "XTRA user agent: " + mUserAgent);
-            client = AndroidHttpClient.newInstance(mUserAgent);
-            HttpUriRequest req = new HttpGet(url);
-
-            if (isProxySet) {
-                HttpHost proxy = new HttpHost(proxyHost, proxyPort);
-                ConnRouteParams.setDefaultProxy(req.getParams(), proxy);
-            }
-
-            req.addHeader(
+            connection = (HttpURLConnection) (new URL(url)).openConnection();
+            connection.setRequestProperty(
                     "Accept",
                     "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
-
-            req.addHeader(
+            connection.setRequestProperty(
                     "x-wap-profile",
                     "http://www.openmobilealliance.org/tech/profiles/UAPROF/ccppschema-20021212#");
 
-            HttpResponse response = client.execute(req);
-            StatusLine status = response.getStatusLine();
-            if (status.getStatusCode() != 200) { // HTTP 200 is success.
-                if (DEBUG) Log.d(TAG, "HTTP error: " + status.getReasonPhrase());
+            connection.connect();
+            int statusCode = connection.getResponseCode();
+            if (statusCode != HttpURLConnection.HTTP_OK) {
+                if (DEBUG) Log.d(TAG, "HTTP error downloading gps XTRA: " + statusCode);
                 return null;
             }
 
-            HttpEntity entity = response.getEntity();
-            byte[] body = null;
-            if (entity != null) {
-                try {
-                    if (entity.getContentLength() > 0) {
-                        body = new byte[(int) entity.getContentLength()];
-                        DataInputStream dis = new DataInputStream(entity.getContent());
-                        try {
-                            dis.readFully(body);
-                        } finally {
-                            try {
-                                dis.close();
-                            } catch (IOException e) {
-                                Log.e(TAG, "Unexpected IOException.", e);
-                            }
-                        }
-                    }
-                } finally {
-                    if (entity != null) {
-                        entity.consumeContent();
-                    }
-                }
-            }
-            return body;
-        } catch (Exception e) {
-            if (DEBUG) Log.d(TAG, "error " + e);
+            return Streams.readFully(connection.getInputStream());
+        } catch (IOException ioe) {
+            if (DEBUG) Log.d(TAG, "Error downloading gps XTRA: ", ioe);
         } finally {
-            if (client != null) {
-                client.close();
+            if (connection != null) {
+                connection.disconnect();
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 402b601..ec2828b 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -26,26 +26,31 @@
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A helper class, that handles operations in remote listeners, and tracks for remote process death.
  */
 abstract class RemoteListenerHelper<TListener extends IInterface> {
+
     protected static final int RESULT_SUCCESS = 0;
     protected static final int RESULT_NOT_AVAILABLE = 1;
     protected static final int RESULT_NOT_SUPPORTED = 2;
     protected static final int RESULT_GPS_LOCATION_DISABLED = 3;
     protected static final int RESULT_INTERNAL_ERROR = 4;
+    protected static final int RESULT_UNKNOWN = 5;
 
     private final Handler mHandler;
     private final String mTag;
 
-    private final HashMap<IBinder, LinkedListener> mListenerMap = new HashMap<>();
+    private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
 
     private boolean mIsRegistered;
     private boolean mHasIsSupported;
     private boolean mIsSupported;
 
+    private int mLastReportedResult = RESULT_UNKNOWN;
+
     protected RemoteListenerHelper(Handler handler, String name) {
         Preconditions.checkNotNull(name);
         mHandler = handler;
@@ -110,33 +115,11 @@
         }
     }
 
-    public void onGpsEnabledChanged(boolean enabled) {
-        // handle first the sub-class implementation, so any error in registration can take
-        // precedence
-        handleGpsEnabledChanged(enabled);
-        synchronized (mListenerMap) {
-            if (!enabled) {
-                tryUnregister();
-                return;
-            }
-            if (mListenerMap.isEmpty()) {
-                return;
-            }
-            if (tryRegister()) {
-                // registration was successful, there is no need to update the state
-                return;
-            }
-            ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
-            foreachUnsafe(operation);
-        }
-    }
-
     protected abstract boolean isAvailableInPlatform();
     protected abstract boolean isGpsEnabled();
     protected abstract boolean registerWithService();
     protected abstract void unregisterFromService();
     protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
-    protected abstract void handleGpsEnabledChanged(boolean enabled);
 
     protected interface ListenerOperation<TListener extends IInterface> {
         void execute(TListener listener) throws RemoteException;
@@ -148,11 +131,40 @@
         }
     }
 
-    protected void setSupported(boolean value, ListenerOperation<TListener> notifier) {
+    protected void setSupported(boolean value) {
         synchronized (mListenerMap) {
             mHasIsSupported = true;
             mIsSupported = value;
-            foreachUnsafe(notifier);
+        }
+    }
+
+    protected boolean tryUpdateRegistrationWithService() {
+        synchronized (mListenerMap) {
+            if (!isGpsEnabled()) {
+                tryUnregister();
+                return true;
+            }
+            if (mListenerMap.isEmpty()) {
+                return true;
+            }
+            if (tryRegister()) {
+                // registration was successful, there is no need to update the state
+                return true;
+            }
+            ListenerOperation<TListener> operation = getHandlerOperation(RESULT_INTERNAL_ERROR);
+            foreachUnsafe(operation);
+            return false;
+        }
+    }
+
+    protected void updateResult() {
+        synchronized (mListenerMap) {
+            int newResult = calculateCurrentResultUnsafe();
+            if (mLastReportedResult == newResult) {
+                return;
+            }
+            foreachUnsafe(getHandlerOperation(newResult));
+            mLastReportedResult = newResult;
         }
     }
 
@@ -183,6 +195,24 @@
         mIsRegistered = false;
     }
 
+    private int calculateCurrentResultUnsafe() {
+        // update statuses we already know about, starting from the ones that will never change
+        if (!isAvailableInPlatform()) {
+            return RESULT_NOT_AVAILABLE;
+        }
+        if (!mHasIsSupported || mListenerMap.isEmpty()) {
+            // we'll update once we have a supported status available
+            return RESULT_UNKNOWN;
+        }
+        if (!mIsSupported) {
+            return RESULT_NOT_SUPPORTED;
+        }
+        if (!isGpsEnabled()) {
+            return RESULT_GPS_LOCATION_DISABLED;
+        }
+        return RESULT_SUCCESS;
+    }
+
     private class LinkedListener implements IBinder.DeathRecipient {
         private final TListener mListener;
 
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 53ae1ab..b5036db 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,7 +17,6 @@
 package com.android.server.media;
 
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
@@ -28,6 +27,9 @@
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
+import android.media.routing.IMediaRouter;
+import android.media.routing.IMediaRouterDelegate;
+import android.media.routing.IMediaRouterStateCallback;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.media.session.ISessionController;
@@ -35,11 +37,9 @@
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
 import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.media.AudioAttributes;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.DeadObjectException;
@@ -58,7 +58,6 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.UUID;
 
 /**
  * This is the system implementation of a Session. Apps will interact with the
@@ -91,7 +90,6 @@
     private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService mService;
-    private final boolean mUseMasterVolume;
 
     private final Object mLock = new Object();
     private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
@@ -141,8 +139,6 @@
         mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
-        mUseMasterVolume = service.getContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     /**
@@ -246,77 +242,30 @@
         if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
-        boolean isMute = direction == MediaSessionManager.DIRECTION_MUTE;
-        if (direction > 1) {
-            direction = 1;
-        } else if (direction < -1) {
-            direction = -1;
-        }
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
-            if (mUseMasterVolume) {
-                // If this device only uses master volume and playback is local
-                // just adjust the master volume and return.
-                boolean isMasterMute = mAudioManager.isMasterMute();
-                if (isMute) {
-                    mAudioManagerInternal.setMasterMuteForUid(!isMasterMute,
-                            flags, packageName, mService.mICallback, uid);
-                } else {
-                    mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
-                            uid);
-                    if (isMasterMute) {
-                        mAudioManagerInternal.setMasterMuteForUid(false,
-                                flags, packageName, mService.mICallback, uid);
-                    }
-                }
-                return;
-            }
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
-            boolean isStreamMute = mAudioManager.isStreamMute(stream);
             if (useSuggested) {
                 if (AudioSystem.isStreamActive(stream, 0)) {
-                    if (isMute) {
-                        mAudioManager.setStreamMute(stream, !isStreamMute);
-                    } else {
-                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
-                                flags, packageName, uid);
-                        if (isStreamMute && direction != 0) {
-                            mAudioManager.setStreamMute(stream, false);
-                        }
-                    }
+                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
+                            flags, packageName, uid);
                 } else {
                     flags |= previousFlagPlaySound;
-                    isStreamMute =
-                            mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE);
-                    if (isMute) {
-                        mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                                !isStreamMute);
-                    } else {
-                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
-                                AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
-                                uid);
-                        if (isStreamMute && direction != 0) {
-                            mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
-                                    false);
-                        }
-                    }
+                    mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
+                            uid);
                 }
             } else {
-                if (isMute) {
-                    mAudioManager.setStreamMute(stream, !isStreamMute);
-                } else {
-                    mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
-                            packageName, uid);
-                    if (isStreamMute && direction != 0) {
-                        mAudioManager.setStreamMute(stream, false);
-                    }
-                }
+                mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
+                        packageName, uid);
             }
         } else {
             if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
                 // Nothing to do, the volume cannot be changed
                 return;
             }
-            if (isMute) {
+            if (direction == AudioManager.ADJUST_TOGGLE_MUTE
+                    || direction == AudioManager.ADJUST_MUTE
+                    || direction == AudioManager.ADJUST_UNMUTE) {
                 Log.w(TAG, "Muting remote playback is not supported");
                 return;
             }
@@ -768,6 +717,11 @@
         }
 
         @Override
+        public void setMediaRouter(IMediaRouter router) {
+            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
+        }
+
+        @Override
         public void setMediaButtonReceiver(PendingIntent pi) {
             mMediaButtonReceiver = pi;
         }
@@ -854,6 +808,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
 
@@ -868,6 +823,7 @@
             }
             if (typeChanged) {
                 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+                mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
     }
@@ -1239,6 +1195,13 @@
         public boolean isTransportControlEnabled() {
             return MediaSessionRecord.this.isTransportControlEnabled();
         }
+
+        @Override
+        public IMediaRouterDelegate createMediaRouterDelegate(
+                IMediaRouterStateCallback callback) {
+            // todo
+            return null;
+        }
     }
 
     private class MessageHandler extends Handler {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 77a1fa9..a530dfa 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.media.AudioManager;
+import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.IRemoteVolumeController;
@@ -38,9 +39,7 @@
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
 import android.media.session.ISessionManager;
-import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -59,6 +58,7 @@
 import android.util.SparseArray;
 import android.view.KeyEvent;
 
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.Watchdog.Monitor;
@@ -89,11 +89,10 @@
     private final Object mLock = new Object();
     private final MessageHandler mHandler = new MessageHandler();
     private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final boolean mUseMasterVolume;
 
     private KeyguardManager mKeyguardManager;
     private IAudioService mAudioService;
-    private AudioManager mAudioManager;
+    private AudioManagerInternal mAudioManagerInternal;
     private ContentResolver mContentResolver;
     private SettingsObserver mSettingsObserver;
 
@@ -109,22 +108,21 @@
         mPriorityStack = new MediaSessionStack();
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        mUseMasterVolume = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
         Watchdog.getInstance().addMonitor(this);
-        updateUser();
         mKeyguardManager =
                 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
         mAudioService = getAudioService();
-        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+        mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mContentResolver = getContext().getContentResolver();
         mSettingsObserver = new SettingsObserver();
         mSettingsObserver.observe();
+
+        updateUser();
     }
 
     private IAudioService getAudioService() {
@@ -333,6 +331,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
+        if (isCurrentVolumeController(uid)) return;
         if (getContext()
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                     != PackageManager.PERMISSION_GRANTED
@@ -342,7 +341,18 @@
         }
     }
 
-    private void enforceStatusBarPermission(String action, int pid, int uid) {
+    private boolean isCurrentVolumeController(int uid) {
+        if (mAudioManagerInternal != null) {
+            final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
+            if (vcuid > 0 && uid == vcuid) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void enforceSystemUiPermission(String action, int pid, int uid) {
+        if (isCurrentVolumeController(uid)) return;
         if (getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 pid, uid) != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Only system ui may " + action);
@@ -453,11 +463,6 @@
         return -1;
     }
 
-    private boolean isSessionDiscoverable(MediaSessionRecord record) {
-        // TODO probably want to check more than if it's active.
-        return record.isActive();
-    }
-
     private void pushSessionsChanged(int userId) {
         synchronized (mLock) {
             List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
@@ -501,6 +506,12 @@
         UserRecord user = mUserRecords.get(record.getUserId());
         if (receiver != null && user != null) {
             user.mLastMediaButtonReceiver = receiver;
+            ComponentName component = receiver.getIntent().getComponent();
+            if (component != null && record.getPackageName().equals(component.getPackageName())) {
+                Settings.Secure.putStringForUser(mContentResolver,
+                        Settings.System.MEDIA_BUTTON_RECEIVER, component.flattenToString(),
+                        record.getUserId());
+            }
         }
     }
 
@@ -511,14 +522,17 @@
     final class UserRecord {
         private final int mUserId;
         private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+        private final Context mContext;
         private PendingIntent mLastMediaButtonReceiver;
+        private ComponentName mRestoredMediaButtonReceiver;
 
         public UserRecord(Context context, int userId) {
+            mContext = context;
             mUserId = userId;
+            restoreMediaButtonReceiver();
         }
 
         public void startLocked() {
-            // nothing for now
         }
 
         public void stopLocked() {
@@ -548,6 +562,7 @@
             pw.println(prefix + "Record for user " + mUserId);
             String indent = prefix + "  ";
             pw.println(indent + "MediaButtonReceiver:" + mLastMediaButtonReceiver);
+            pw.println(indent + "Restored ButtonReceiver:" + mRestoredMediaButtonReceiver);
             int size = mSessions.size();
             pw.println(indent + size + " Sessions:");
             for (int i = 0; i < size; i++) {
@@ -556,6 +571,19 @@
                 pw.println(indent + mSessions.get(i).toString());
             }
         }
+
+        private void restoreMediaButtonReceiver() {
+            String receiverName = Settings.Secure.getStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
+            if (!TextUtils.isEmpty(receiverName)) {
+                ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
+                if (eventReceiver == null) {
+                    // an invalid name was persisted
+                    return;
+                }
+                mRestoredMediaButtonReceiver = eventReceiver;
+            }
+        }
     }
 
     final class SessionsListenerRecord implements IBinder.DeathRecipient {
@@ -718,13 +746,18 @@
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
+            if (DEBUG) {
+                Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+                        + keyEvent);
+            }
 
             try {
                 synchronized (mLock) {
                     // If we don't have a media button receiver to fall back on
                     // include non-playing sessions for dispatching
-                    boolean useNotPlayingSessions = mUserRecords.get(
-                            ActivityManager.getCurrentUser()).mLastMediaButtonReceiver == null;
+                    UserRecord ur = mUserRecords.get(ActivityManager.getCurrentUser());
+                    boolean useNotPlayingSessions = ur.mLastMediaButtonReceiver == null
+                            && ur.mRestoredMediaButtonReceiver == null;
                     MediaSessionRecord session = mPriorityStack
                             .getDefaultMediaButtonSession(mCurrentUserId, useNotPlayingSessions);
                     if (isVoiceKey(keyEvent.getKeyCode())) {
@@ -760,7 +793,7 @@
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                enforceStatusBarPermission("listen for volume changes", pid, uid);
+                enforceSystemUiPermission("listen for volume changes", pid, uid);
                 mRvc = rvc;
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -798,7 +831,7 @@
                 pw.println("User Records:");
                 count = mUserRecords.size();
                 for (int i = 0; i < count; i++) {
-                    UserRecord user = mUserRecords.get(i);
+                    UserRecord user = mUserRecords.get(mUserRecords.keyAt(i));
                     user.dumpLocked(pw, "");
                 }
             }
@@ -846,32 +879,8 @@
                 }
                 try {
                     String packageName = getContext().getOpPackageName();
-                    if (mUseMasterVolume) {
-                        boolean isMasterMute = mAudioService.isMasterMute();
-                        if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioService.setMasterMute(!isMasterMute, flags, packageName, mICallback);
-                        } else {
-                            mAudioService.adjustMasterVolume(direction, flags, packageName);
-                            // Do not call setMasterMute when direction = 0 which is used just to
-                            // show the UI.
-                            if (isMasterMute && direction != 0) {
-                                mAudioService.setMasterMute(false, flags, packageName, mICallback);
-                            }
-                        }
-                    } else {
-                        boolean isStreamMute = mAudioService.isStreamMute(suggestedStream);
-                        if (direction == MediaSessionManager.DIRECTION_MUTE) {
-                            mAudioManager.setStreamMute(suggestedStream, !isStreamMute);
-                        } else {
-                            mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
-                                    flags, packageName);
-                            // Do not call setStreamMute when direction = 0 which is used just to
-                            // show the UI.
-                            if (isStreamMute && direction != 0) {
-                                mAudioManager.setStreamMute(suggestedStream, false);
-                            }
-                        }
-                    }
+                    mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+                            flags, packageName, TAG);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error adjusting default volume.", e);
                 }
@@ -929,9 +938,12 @@
                 // Launch the last PendingIntent we had with priority
                 int userId = ActivityManager.getCurrentUser();
                 UserRecord user = mUserRecords.get(userId);
-                if (user.mLastMediaButtonReceiver != null) {
+                if (user.mLastMediaButtonReceiver != null
+                        || user.mRestoredMediaButtonReceiver != null) {
                     if (DEBUG) {
-                        Log.d(TAG, "Sending media key to last known PendingIntent");
+                        Log.d(TAG, "Sending media key to last known PendingIntent "
+                                + user.mLastMediaButtonReceiver + " or restored Intent "
+                                + user.mRestoredMediaButtonReceiver);
                     }
                     if (needWakeLock) {
                         mKeyEventReceiver.aquireWakeLockLocked();
@@ -939,9 +951,15 @@
                     Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
                     mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
                     try {
-                        user.mLastMediaButtonReceiver.send(getContext(),
-                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                                mediaButtonIntent, mKeyEventReceiver, null);
+                        if (user.mLastMediaButtonReceiver != null) {
+                            user.mLastMediaButtonReceiver.send(getContext(),
+                                    needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                    mediaButtonIntent, mKeyEventReceiver, null);
+                        } else {
+                            mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
+                            getContext().sendBroadcastAsUser(mediaButtonIntent,
+                                    new UserHandle(userId));
+                        }
                     } catch (CanceledException e) {
                         Log.i(TAG, "Error sending key event to media button receiver "
                                 + user.mLastMediaButtonReceiver, e);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index bfdc400..a029b0e 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -33,9 +33,7 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
 import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -45,9 +43,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 
 /**
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index b5a450d..90e26d8 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -24,25 +24,19 @@
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.server.net.DelayedDiskWrite;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.EOFException;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Inet4Address;
-import java.util.Map;
 
 public class IpConfigStore {
     private static final String TAG = "IpConfigStore";
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2be591b..cc0fcf5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,9 +28,7 @@
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 import static android.net.NetworkPolicy.CYCLE_NONE;
@@ -46,7 +44,6 @@
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.dumpPolicy;
 import static android.net.NetworkPolicyManager.dumpRules;
-import static android.net.NetworkTemplate.MATCH_ETHERNET;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
 import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
@@ -60,7 +57,6 @@
 import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
-import static android.telephony.TelephonyManager.SIM_STATE_READY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.Preconditions.checkNotNull;
@@ -122,7 +118,6 @@
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.text.format.Time;
 import android.util.ArrayMap;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 3ac20f7..20f5f97 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -22,10 +22,8 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_REMOVED;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
-import android.net.ConnectivityManager;
 import android.net.NetworkIdentity;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index d5d7667..6490865 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -31,6 +31,7 @@
 import android.util.MathUtils;
 import android.util.Slog;
 
+import com.android.internal.net.VpnInfo;
 import com.android.internal.util.FileRotator;
 import com.android.internal.util.IndentingPrintWriter;
 import com.google.android.collect.Sets;
@@ -163,7 +164,8 @@
      * snapshot is considered bootstrap, and is not counted as delta.
      */
     public void recordSnapshotLocked(NetworkStats snapshot,
-            Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
+            Map<String, NetworkIdentitySet> ifaceIdent, VpnInfo[] vpnArray,
+            long currentTimeMillis) {
         final HashSet<String> unknownIfaces = Sets.newHashSet();
 
         // skip recording when snapshot missing
@@ -182,6 +184,12 @@
         final long end = currentTimeMillis;
         final long start = end - delta.getElapsedRealtime();
 
+        if (vpnArray != null) {
+            for (VpnInfo info : vpnArray) {
+                delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface);
+            }
+        }
+
         NetworkStats.Entry entry = null;
         for (int i = 0; i < delta.size(); i++) {
             entry = delta.getValues(i, entry);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 856a076..0b596aa 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -111,6 +111,7 @@
 import android.util.TrustedTime;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.VpnInfo;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FileRotator;
 import com.android.internal.util.IndentingPrintWriter;
@@ -855,6 +856,20 @@
         return ident;
     }
 
+    private void recordSnapshotLocked(long currentTime) throws RemoteException {
+        // snapshot and record current counters; read UID stats first to
+        // avoid overcounting dev stats.
+        final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+        final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
+        final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
+
+        VpnInfo[] vpnArray = mConnManager.getAllVpnInfo();
+        mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, null, currentTime);
+        mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime);
+        mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+        mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+    }
+
     /**
      * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
      * so we have baseline values without double-counting.
@@ -864,17 +879,7 @@
                 : System.currentTimeMillis();
 
         try {
-            // snapshot and record current counters; read UID stats first to
-            // avoid overcounting dev stats.
-            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
-            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
-            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
-
-            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
-            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
-            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-
+            recordSnapshotLocked(currentTime);
         } catch (IllegalStateException e) {
             Slog.w(TAG, "problem reading network stats: " + e);
         } catch (RemoteException e) {
@@ -918,17 +923,7 @@
                 : System.currentTimeMillis();
 
         try {
-            // snapshot and record current counters; read UID stats first to
-            // avoid overcounting dev stats.
-            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
-            final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt();
-            final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
-
-            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
-            mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime);
-            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime);
-
+            recordSnapshotLocked(currentTime);
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem reading network stats", e);
             return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f49d77d..0c71d5f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -50,10 +50,12 @@
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -64,6 +66,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -124,6 +127,8 @@
 public class NotificationManagerService extends SystemService {
     static final String TAG = "NotificationService";
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
+            && SystemProperties.getBoolean("debug.child_notifs", false);
 
     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
 
@@ -179,6 +184,7 @@
 
     private IActivityManager mAm;
     AudioManager mAudioManager;
+    AudioManagerInternal mAudioManagerInternal;
     StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
 
@@ -207,7 +213,7 @@
     private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
     private ComponentName mEffectsSuppressor;
     private int mListenerHints;  // right now, all hints are global
-    private int mInterruptionFilter;  // current ZEN mode as communicated to listeners
+    private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
 
     // for enabling and disabling notification pulse behavior
     private boolean mScreenOn = true;
@@ -997,6 +1003,7 @@
 
             // Grab our optional AudioService
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -1023,6 +1030,7 @@
     private void updateListenerHintsLocked() {
         final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
         if (hints == mListenerHints) return;
+        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
         mListenerHints = hints;
         scheduleListenerHintsChanged(hints);
     }
@@ -1031,6 +1039,7 @@
         final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
                 ? mListenersDisablingEffects.valueAt(0).component : null;
         if (Objects.equals(suppressor, mEffectsSuppressor)) return;
+        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
         mEffectsSuppressor = suppressor;
         mZenModeHelper.setEffectsSuppressed(suppressor != null);
         getContext().sendBroadcast(new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)
@@ -1469,7 +1478,7 @@
 
         @Override
         public ZenModeConfig getZenModeConfig() {
-            enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
+            enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
             return mZenModeHelper.getConfig();
         }
 
@@ -1480,6 +1489,17 @@
         }
 
         @Override
+        public void setZenMode(int mode) throws RemoteException {
+            enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mZenModeHelper.setZenMode(mode, "NotificationManager");
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void notifyConditions(String pkg, IConditionProvider provider,
                 Condition[] conditions) {
             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
@@ -1494,13 +1514,13 @@
 
         @Override
         public void requestZenModeConditions(IConditionListener callback, int relevance) {
-            enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
+            enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions");
             mConditionProviders.requestZenModeConditions(callback, relevance);
         }
 
         @Override
         public void setZenModeCondition(Condition condition) {
-            enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
+            enforceSystemOrSystemUIOrVolume("INotificationManager.setZenModeCondition");
             final long identity = Binder.clearCallingIdentity();
             try {
                 mConditionProviders.setZenModeCondition(condition, "binderCall");
@@ -1521,6 +1541,16 @@
             return mConditionProviders.getAutomaticZenModeConditions();
         }
 
+        private void enforceSystemOrSystemUIOrVolume(String message) {
+            if (mAudioManagerInternal != null) {
+                final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
+                if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
+                    return;
+                }
+            }
+            enforceSystemOrSystemUI(message);
+        }
+
         private void enforceSystemOrSystemUI(String message) {
             if (isCallerSystem()) return;
             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1542,7 +1572,7 @@
 
         @Override
         public ComponentName getEffectsSuppressor() {
-            enforceSystemOrSystemUI("INotificationManager.getEffectsSuppressor");
+            enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
             return mEffectsSuppressor;
         }
 
@@ -1559,7 +1589,7 @@
 
         @Override
         public boolean isSystemConditionProviderEnabled(String path) {
-            enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
+            enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
             return mConditionProviders.isSystemConditionProviderEnabled(path);
         }
     };
@@ -1981,35 +2011,37 @@
      */
     private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
             NotificationRecord old, int callingUid, int callingPid) {
-        // No optimizations are possible if listeners want groups.
-        if (mListeners.notificationGroupsDesired()) {
-            return false;
-        }
-
-        StatusBarNotification sbn = r.sbn;
-        String group = sbn.getGroupKey();
-        boolean isSummary = sbn.getNotification().isGroupSummary();
-        boolean isChild = sbn.getNotification().isGroupChild();
-
-        NotificationRecord summary = mSummaryByGroupKey.get(group);
-        if (isChild && summary != null) {
-            // Child with an active summary -> ignore
-            if (DBG) {
-                Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
-                        + summary.getKey());
+        if (!ENABLE_CHILD_NOTIFICATIONS) {
+            // No optimizations are possible if listeners want groups.
+            if (mListeners.notificationGroupsDesired()) {
+                return false;
             }
-            // Make sure we don't leave an old version of the notification around.
-            if (old != null) {
+
+            StatusBarNotification sbn = r.sbn;
+            String group = sbn.getGroupKey();
+            boolean isSummary = sbn.getNotification().isGroupSummary();
+            boolean isChild = sbn.getNotification().isGroupChild();
+
+            NotificationRecord summary = mSummaryByGroupKey.get(group);
+            if (isChild && summary != null) {
+                // Child with an active summary -> ignore
                 if (DBG) {
-                    Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
+                    Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
+                            + summary.getKey());
                 }
-                cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
+                // Make sure we don't leave an old version of the notification around.
+                if (old != null) {
+                    if (DBG) {
+                        Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
+                    }
+                    cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
+                }
+                return true;
+            } else if (isSummary) {
+                // Summary -> cancel children
+                cancelGroupChildrenLocked(r, callingUid, callingPid, null,
+                        REASON_GROUP_OPTIMIZATION);
             }
-            return true;
-        } else if (isSummary) {
-            // Summary -> cancel children
-            cancelGroupChildrenLocked(r, callingUid, callingPid, null,
-                    REASON_GROUP_OPTIMIZATION);
         }
         return false;
     }
@@ -2560,8 +2592,8 @@
             @Override
             public void run() {
                 String listenerName = listener == null ? null : listener.component.toShortString();
-                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId,
-                        mustHaveFlags, mustNotHaveFlags, reason, listenerName);
+                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
+                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
 
                 synchronized (mNotificationList) {
                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 8278c4f..e029c58 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -49,7 +49,7 @@
     // WARNING: Aggregated stats can grow unboundedly with pkg+id+tag.
     // Don't enable on production builds.
     private static final boolean ENABLE_AGGREGATED_IN_MEMORY_STATS = false;
-    private static final boolean ENABLE_SQLITE_LOG = false;
+    private static final boolean ENABLE_SQLITE_LOG = true;
 
     private static final AggregatedStats[] EMPTY_AGGREGATED_STATS = new AggregatedStats[0];
 
@@ -222,7 +222,7 @@
 
         public void collect(SingleNotificationStats singleNotificationStats) {
             posttimeMs.addSample(
-	            SystemClock.elapsedRealtime() - singleNotificationStats.posttimeElapsedMs);
+                    SystemClock.elapsedRealtime() - singleNotificationStats.posttimeElapsedMs);
             if (singleNotificationStats.posttimeToDismissMs >= 0) {
                 posttimeToDismissMs.addSample(singleNotificationStats.posttimeToDismissMs);
             }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6a96f85..518e223 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -24,7 +24,6 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
 import org.xmlpull.v1.XmlPullParser;
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 11d00cf..5eb318b 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -219,7 +219,7 @@
             return null;
         }
 
-        if (INFO) Slog.i(TAG, "Validating: " + key);
+        if (INFO) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId());
         final LinkedList<String> pendingLookups = new LinkedList<String>();
         for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
             final String handle = people[personIdx];
@@ -443,7 +443,10 @@
                         final String cacheKey = getCacheKey(mContext.getUserId(), handle);
                         mPeopleCache.put(cacheKey, lookupResult);
                     }
+                    if (DEBUG) Slog.d(TAG, "lookup contactAffinity is " + lookupResult.getAffinity());
                     mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity());
+                } else {
+                    if (DEBUG) Slog.d(TAG, "lookupResult is null");
                 }
             }
             if (DEBUG) {
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index dda0b37..1fc967f 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -24,8 +24,8 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.IConditionProvider;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
-import android.util.ArraySet;
 import android.util.Slog;
 
 import java.io.PrintWriter;
@@ -57,6 +57,8 @@
     private static final int TYPE_CONFIG = 11;
     private static final int TYPE_NOT_INTERCEPTED = 12;
     private static final int TYPE_DISABLE_EFFECTS = 13;
+    private static final int TYPE_SUPPRESSOR_CHANGED = 14;
+    private static final int TYPE_LISTENER_HINTS_CHANGED = 15;
 
     private static int sNext;
     private static int sSize;
@@ -121,6 +123,17 @@
         append(TYPE_DISABLE_EFFECTS, record.getKey() + "," + reason);
     }
 
+    public static void traceEffectsSuppressorChanged(ComponentName oldSuppressor,
+            ComponentName newSuppressor) {
+        append(TYPE_SUPPRESSOR_CHANGED, componentToString(oldSuppressor) + "->"
+            + componentToString(newSuppressor));
+    }
+
+    public static void traceListenerHintsChanged(int oldHints, int newHints, int listenerCount) {
+        append(TYPE_LISTENER_HINTS_CHANGED, hintsToString(oldHints) + "->"
+            + hintsToString(newHints) + ",listeners=" + listenerCount);
+    }
+
     private static String subscribeResult(IConditionProvider provider, RemoteException e) {
         return provider == null ? "no provider" : e != null ? e.getMessage() : "ok";
     }
@@ -140,6 +153,8 @@
             case TYPE_CONFIG: return "config";
             case TYPE_NOT_INTERCEPTED: return "not_intercepted";
             case TYPE_DISABLE_EFFECTS: return "disable_effects";
+            case TYPE_SUPPRESSOR_CHANGED: return "suppressor_changed";
+            case TYPE_LISTENER_HINTS_CHANGED: return "listener_hints_changed";
             default: return "unknown";
         }
     }
@@ -162,6 +177,14 @@
         }
     }
 
+    private static String hintsToString(int hints) {
+        switch (hints) {
+            case 0 : return "none";
+            case NotificationListenerService.HINT_HOST_DISABLE_EFFECTS : return "disable_effects";
+            default: return Integer.toString(hints);
+        }
+    }
+
     private static String componentToString(ComponentName component) {
         return component != null ? component.toShortString() : null;
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 841fc21..a985b01 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -31,6 +31,7 @@
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
+import android.media.VolumePolicy;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -334,7 +335,7 @@
 
     @Override  // RingerModeDelegate
     public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeExternal) {
+            int ringerModeExternal, VolumePolicy policy) {
         final boolean isChange = ringerModeOld != ringerModeNew;
 
         int ringerModeExternalOut = ringerModeNew;
@@ -342,7 +343,7 @@
         int newZen = -1;
         switch (ringerModeNew) {
             case AudioManager.RINGER_MODE_SILENT:
-                if (isChange) {
+                if (isChange && policy.doNotDisturbWhenSilent) {
                     if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
                         newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
                     }
@@ -371,7 +372,7 @@
 
     @Override  // RingerModeDelegate
     public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeInternal) {
+            int ringerModeInternal, VolumePolicy policy) {
         int ringerModeInternalOut = ringerModeNew;
         final boolean isChange = ringerModeOld != ringerModeNew;
         final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index a335d3a..0e0096d 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -18,7 +18,6 @@
 package com.android.server.pm;
 
 
-import java.io.PrintWriter;
 import com.android.server.IntentResolver;
 import java.util.List;
 
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
index 8f0f935..e87546c 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/GrantedPermissions.java
@@ -21,13 +21,15 @@
 
 class GrantedPermissions {
     int pkgFlags;
+    int pkgPrivateFlags;
 
     ArraySet<String> grantedPermissions = new ArraySet<String>();
 
     int[] gids;
 
-    GrantedPermissions(int pkgFlags) {
+    GrantedPermissions(int pkgFlags, int pkgPrivateFlags) {
         setFlags(pkgFlags);
+        setPrivateFlags(pkgPrivateFlags);
     }
 
     @SuppressWarnings("unchecked")
@@ -43,8 +45,12 @@
     void setFlags(int pkgFlags) {
         this.pkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
-                        | ApplicationInfo.FLAG_PRIVILEGED
-                        | ApplicationInfo.FLAG_FORWARD_LOCK
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
     }
+
+    void setPrivateFlags(int pkgPrivateFlags) {
+        this.pkgPrivateFlags = pkgPrivateFlags
+                & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+                        | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 31c604f..5cde8ea 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -83,13 +83,14 @@
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode) {
+            String instructionSet, boolean vmSafeMode, boolean debuggable) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
 
-        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode);
+        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode,
+                debuggable);
     }
 
     public int idmap(String targetApkPath, String overlayApkPath, int uid) {
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
new file mode 100644
index 0000000..79e7a20
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * Provides various methods for obtaining and converting of instruction sets.
+ *
+ * @hide
+ */
+public class InstructionSets {
+    private static final String PREFERRED_INSTRUCTION_SET =
+            VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);;
+    public static String[] getAppDexInstructionSets(ApplicationInfo info) {
+        if (info.primaryCpuAbi != null) {
+            if (info.secondaryCpuAbi != null) {
+                return new String[] {
+                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
+                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+            } else {
+                return new String[] {
+                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
+            }
+        }
+
+        return new String[] { getPreferredInstructionSet() };
+    }
+
+    public static String[] getAppDexInstructionSets(PackageSetting ps) {
+        if (ps.primaryCpuAbiString != null) {
+            if (ps.secondaryCpuAbiString != null) {
+                return new String[] {
+                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
+                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
+            } else {
+                return new String[] {
+                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+            }
+        }
+
+        return new String[] { getPreferredInstructionSet() };
+    }
+
+    public static String getPreferredInstructionSet() {
+        return PREFERRED_INSTRUCTION_SET;
+    }
+
+    /**
+     * Returns the instruction set that should be used to compile dex code. In the presence of
+     * a native bridge this might be different than the one shared libraries use.
+     */
+    public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+        return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa;
+    }
+
+    public static String[] getDexCodeInstructionSets(String[] instructionSets) {
+        ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
+        for (String instructionSet : instructionSets) {
+            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+        }
+        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+    }
+
+    /**
+     * Returns deduplicated list of supported instructions for dex code.
+     */
+    public static String[] getAllDexCodeInstructionSets() {
+        String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
+        for (int i = 0; i < supportedInstructionSets.length; i++) {
+            String abi = Build.SUPPORTED_ABIS[i];
+            supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
+        }
+        return getDexCodeInstructionSets(supportedInstructionSets);
+    }
+
+    public static List<String> getAllInstructionSets() {
+        final String[] allAbis = Build.SUPPORTED_ABIS;
+        final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
+
+        for (String abi : allAbis) {
+            final String instructionSet = VMRuntime.getInstructionSet(abi);
+            if (!allInstructionSets.contains(instructionSet)) {
+                allInstructionSets.add(instructionSet);
+            }
+        }
+
+        return allInstructionSets;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 4a8e318..aa63932 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
-import android.os.Binder;
 import android.util.ArraySet;
 import android.util.Base64;
 import android.util.Slog;
@@ -415,9 +414,9 @@
         // Get the package's known keys and KeySets
         ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
         ArraySet<Long> deletableKeys = new ArraySet<Long>();
-        ArraySet<Long> knownKeys = null;
-        for (Long ks : deletableKeySets) {
-            knownKeys = mKeySetMapping.get(ks);
+        final int origDksSize = deletableKeySets.size();
+        for (int i = 0; i < origDksSize; i++) {
+            ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
             if (knownKeys != null) {
                 deletableKeys.addAll(knownKeys);
             }
@@ -430,9 +429,9 @@
             }
             ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
             deletableKeySets.removeAll(knownKeySets);
-            knownKeys = new ArraySet<Long>();
-            for (Long ks : knownKeySets) {
-                knownKeys = mKeySetMapping.get(ks);
+            final int kksSize = knownKeySets.size();
+            for (int i = 0; i < kksSize; i++) {
+                ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
                 if (knownKeys != null) {
                     deletableKeys.removeAll(knownKeys);
                 }
@@ -441,18 +440,22 @@
 
         // The remaining keys and KeySets are not relied on by any other
         // application and so can be safely deleted.
-        for (Long ks : deletableKeySets) {
+        final int dksSize = deletableKeySets.size();
+        for (int i = 0; i < dksSize; i++) {
+            Long ks = deletableKeySets.valueAt(i);
             mKeySets.delete(ks);
             mKeySetMapping.delete(ks);
         }
-        for (Long keyId : deletableKeys) {
-            mPublicKeys.delete(keyId);
+        final int dkSize = deletableKeys.size();
+        for (int i = 0; i < dkSize; i++) {
+            mPublicKeys.delete(deletableKeys.valueAt(i));
         }
 
         // Now remove the deleted KeySets from each package's signingKeySets
         for (String pkgName : mPackages.keySet()) {
             PackageSetting p = mPackages.get(pkgName);
-            for (Long ks : deletableKeySets) {
+            for (int i = 0; i < dksSize; i++) {
+                Long ks = deletableKeySets.valueAt(i);
                 p.keySetData.removeSigningKeySet(ks);
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
new file mode 100644
index 0000000..2dbce0a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+
+/**
+ * Helper class for running dexopt command on packages.
+ */
+final class PackageDexOptimizer {
+    static final String TAG = "PackageManager.DexOptimizer";
+    static final int DEX_OPT_SKIPPED = 0;
+    static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_DEFERRED = 2;
+    static final int DEX_OPT_FAILED = -1;
+
+    private final PackageManagerService mPackageManagerService;
+    private ArraySet<PackageParser.Package> mDeferredDexOpt;
+
+    PackageDexOptimizer(PackageManagerService packageManagerService) {
+        this.mPackageManagerService = packageManagerService;
+    }
+
+    /**
+     * Performs dexopt on all code paths and libraries of the specified package for specified
+     * instruction sets.
+     *
+     * <p>Calls to {@link com.android.server.pm.Installer#dexopt} are synchronized on
+     * {@link PackageManagerService#mInstallLock}.
+     */
+    int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
+            boolean forceDex, boolean defer, boolean inclDependencies) {
+        ArraySet<String> done;
+        if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
+            done = new ArraySet<String>();
+            done.add(pkg.packageName);
+        } else {
+            done = null;
+        }
+        synchronized (mPackageManagerService.mInstallLock) {
+            return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+        }
+    }
+
+    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
+            boolean forceDex, boolean defer, ArraySet<String> done) {
+        final String[] instructionSets = targetInstructionSets != null ?
+                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+
+        if (done != null) {
+            done.add(pkg.packageName);
+            if (pkg.usesLibraries != null) {
+                performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
+            }
+            if (pkg.usesOptionalLibraries != null) {
+                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
+                        done);
+            }
+        }
+
+        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+            return DEX_OPT_SKIPPED;
+        }
+
+        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
+        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+        boolean performedDexOpt = false;
+        // There are three basic cases here:
+        // 1.) we need to dexopt, either because we are forced or it is needed
+        // 2.) we are deferring a needed dexopt
+        // 3.) we are skipping an unneeded dexopt
+        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+            if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+                continue;
+            }
+
+            for (String path : paths) {
+                try {
+                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+                    // package or the one we find does not match the image checksum (i.e. it was
+                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+                    // odex file and it matches the checksum of the image but not its base address,
+                    // meaning we need to move it.
+                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+                            pkg.packageName, dexCodeInstructionSet, defer);
+                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
+                        Log.i(TAG, "Running dexopt on: " + path + " pkg="
+                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+                                + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable);
+                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+                                !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
+                                vmSafeMode, debuggable);
+
+                        if (ret < 0) {
+                            // Don't bother running dexopt again if we failed, it will probably
+                            // just result in an error again. Also, don't bother dexopting for other
+                            // paths & ISAs.
+                            return DEX_OPT_FAILED;
+                        }
+
+                        performedDexOpt = true;
+                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
+                                !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
+
+                        if (ret < 0) {
+                            // Don't bother running patchoat again if we failed, it will probably
+                            // just result in an error again. Also, don't bother dexopting for other
+                            // paths & ISAs.
+                            return DEX_OPT_FAILED;
+                        }
+
+                        performedDexOpt = true;
+                    }
+
+                    // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+                    // paths and instruction sets. We'll deal with them all together when we process
+                    // our list of deferred dexopts.
+                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
+                        addPackageForDeferredDexopt(pkg);
+                        return DEX_OPT_DEFERRED;
+                    }
+                } catch (FileNotFoundException e) {
+                    Slog.w(TAG, "Apk not found for dexopt: " + path);
+                    return DEX_OPT_FAILED;
+                } catch (IOException e) {
+                    Slog.w(TAG, "IOException reading apk: " + path, e);
+                    return DEX_OPT_FAILED;
+                } catch (StaleDexCacheError e) {
+                    Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+                    return DEX_OPT_FAILED;
+                } catch (Exception e) {
+                    Slog.w(TAG, "Exception when doing dexopt : ", e);
+                    return DEX_OPT_FAILED;
+                }
+            }
+
+            // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+            // it isn't required. We therefore mark that this package doesn't need dexopt unless
+            // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+            // it.
+            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+        }
+
+        // If we've gotten here, we're sure that no error occurred and that we haven't
+        // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
+        // we've skipped all of them because they are up to date. In both cases this
+        // package doesn't need dexopt any longer.
+        return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+    }
+
+    private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
+            boolean forceDex, boolean defer, ArraySet<String> done) {
+        for (String libName : libs) {
+            PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
+                    libName);
+            if (libPkg != null && !done.contains(libName)) {
+                performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
+            }
+        }
+    }
+
+    /**
+     * Clears set of deferred dexopt packages.
+     * @return content of dexopt set if it was not empty
+     */
+    public ArraySet<PackageParser.Package> clearDeferredDexOptPackages() {
+        ArraySet<PackageParser.Package> result = mDeferredDexOpt;
+        mDeferredDexOpt = null;
+        return result;
+    }
+
+    public void addPackageForDeferredDexopt(PackageParser.Package pkg) {
+        if (mDeferredDexOpt == null) {
+            mDeferredDexOpt = new ArraySet<PackageParser.Package>();
+        }
+        mDeferredDexOpt.add(pkg);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cc0a30a..7df7eb3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,6 +55,10 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 
 import android.util.ArrayMap;
 
@@ -184,7 +188,6 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
@@ -213,7 +216,6 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.DexFile;
-import dalvik.system.StaleDexCacheError;
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
@@ -323,13 +325,8 @@
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
 
-    private static String sPreferredInstructionSet;
-
     final ServiceThread mHandlerThread;
 
-    private static final String IDMAP_PREFIX = "/data/resource-cache/";
-    private static final String IDMAP_SUFFIX = "@idmap";
-
     final PackageHandler mHandler;
 
     /**
@@ -466,8 +463,7 @@
 
     final PackageInstallerService mInstallerService;
 
-    ArraySet<PackageParser.Package> mDeferredDexOpt = null;
-
+    private final PackageDexOptimizer mPackageDexOptimizer;
     // Cache of users who need badging.
     SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
 
@@ -1050,7 +1046,7 @@
                                         res.pkg.applicationInfo.packageName, null, updateUsers);
 
                                 // treat asec-hosted packages like removable media on upgrade
-                                if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
+                                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                                     if (DEBUG_INSTALL) {
                                         Slog.i(TAG, "upgrading pkg " + res.pkg
                                                 + " is ASEC-hosted -> AVAILABLE");
@@ -1299,17 +1295,17 @@
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
-                ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
 
         // TODO: add a property to control this?
         long dexOptLRUThresholdInMinutes;
@@ -1338,6 +1334,7 @@
         }
 
         mInstaller = installer;
+        mPackageDexOptimizer = new PackageDexOptimizer(this);
 
         getDefaultDisplayMetrics(context, mMetrics);
 
@@ -1438,9 +1435,10 @@
                 Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
             }
 
-            final List<String> allInstructionSets = getAllInstructionSets();
+            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
             final String[] dexCodeInstructionSets =
-                getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
+                    getDexCodeInstructionSets(
+                            allInstructionSets.toArray(new String[allInstructionSets.size()]));
 
             /**
              * Ensure all external libraries have had dexopt run on them.
@@ -2124,6 +2122,7 @@
                 pkg = new PackageParser.Package(packageName);
                 pkg.applicationInfo.packageName = packageName;
                 pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
+                pkg.applicationInfo.privateFlags = ps.pkgPrivateFlags;
                 pkg.applicationInfo.dataDir =
                         getDataPathForPackage(packageName, 0).getPath();
                 pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
@@ -2334,6 +2333,19 @@
         return null;
     }
 
+    /**
+     * @hide
+     */
+    PackageParser.Package findSharedNonSystemLibrary(String libName) {
+        synchronized (mPackages) {
+            PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName);
+            if (lib != null && lib.apk != null) {
+                return mPackages.get(lib.apk);
+            }
+        }
+        return null;
+    }
+
     @Override
     public FeatureInfo[] getSystemAvailableFeatures() {
         Collection<FeatureInfo> featSet;
@@ -2966,7 +2978,7 @@
         }
         // reader
         synchronized (mPackages) {
-            final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
+            final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
             if (suid == null) {
                 return -1;
             }
@@ -2990,6 +3002,21 @@
     }
 
     @Override
+    public int getPrivateFlagsForUid(int uid) {
+        synchronized (mPackages) {
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+            if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+                return sus.pkgPrivateFlags;
+            } else if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+                return ps.pkgPrivateFlags;
+            }
+        }
+        return 0;
+    }
+
+    @Override
     public boolean isUidPrivileged(int uid) {
         uid = UserHandle.getAppId(uid);
         // reader
@@ -3381,7 +3408,7 @@
                 if (resolveInfo != null) {
                     List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                     result.add(resolveInfo);
-                    return result;
+                    return filterIfNotPrimaryUser(result, userId);
                 }
                 // Check for cross profile results.
                 resolveInfo = queryCrossProfileIntents(
@@ -3394,17 +3421,38 @@
                     result.add(resolveInfo);
                     Collections.sort(result, mResolvePrioritySorter);
                 }
-                return result;
+                return filterIfNotPrimaryUser(result, userId);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
-                return mActivities.queryIntentForPackage(intent, resolvedType, flags,
-                        pkg.activities, userId);
+                return filterIfNotPrimaryUser(
+                        mActivities.queryIntentForPackage(
+                                intent, resolvedType, flags, pkg.activities, userId),
+                        userId);
             }
             return new ArrayList<ResolveInfo>();
         }
     }
 
+    /**
+     * Filter out activities with primaryUserOnly flag set, when current user is not the owner.
+     *
+     * @return filtered list
+     */
+    private List<ResolveInfo> filterIfNotPrimaryUser(List<ResolveInfo> resolveInfos, int userId) {
+        if (userId == UserHandle.USER_OWNER) {
+            return resolveInfos;
+        }
+        for (int i = resolveInfos.size() - 1; i >= 0; i--) {
+            ResolveInfo info = resolveInfos.get(i);
+            if ((info.activityInfo.flags & ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
+                resolveInfos.remove(i);
+            }
+        }
+        return resolveInfos;
+    }
+
+
     private ResolveInfo querySkipCurrentProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
             int flags, int sourceUserId) {
@@ -4288,9 +4336,9 @@
             // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
             // it needs to drop FLAG_PRIVILEGED.
             if (locationIsPrivileged(scanFile)) {
-                updatedPkg.pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+                updatedPkg.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             } else {
-                updatedPkg.pkgFlags &= ~ApplicationInfo.FLAG_PRIVILEGED;
+                updatedPkg.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             }
 
             if (ps != null && !ps.codePath.equals(scanFile)) {
@@ -4310,6 +4358,8 @@
                                 + " to " + scanFile);
                         updatedPkg.codePath = scanFile;
                         updatedPkg.codePathString = scanFile.toString();
+                        updatedPkg.resourcePath = scanFile;
+                        updatedPkg.resourcePathString = scanFile.toString();
                     }
                     updatedPkg.pkg = pkg;
                     throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, null);
@@ -4352,7 +4402,7 @@
 
             // An updated privileged app will not have the PARSE_IS_PRIVILEGED
             // flag set initially
-            if ((updatedPkg.pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+            if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
                 parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
             }
         }
@@ -4577,8 +4627,7 @@
 
         final ArraySet<PackageParser.Package> pkgs;
         synchronized (mPackages) {
-            pkgs = mDeferredDexOpt;
-            mDeferredDexOpt = null;
+            pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
         }
 
         if (pkgs != null) {
@@ -4734,8 +4783,8 @@
         }
         PackageParser.Package p = pkg;
         synchronized (mInstallLock) {
-            performDexOptLI(p, null /* instruction sets */, false /* force dex */,
-                            false /* defer */, true /* include dependencies */);
+            mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
+                    false /* force dex */, false /* defer */, true /* include dependencies */);
         }
     }
 
@@ -4784,8 +4833,9 @@
 
         synchronized (mInstallLock) {
             final String[] instructionSets = new String[] { targetInstructionSet };
-            return performDexOptLI(p, instructionSets, false /* force dex */, false /* defer */,
-                    true /* include dependencies */) == DEX_OPT_PERFORMED;
+            int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
+                    false /* forceDex */, false /* defer */, true /* inclDependencies */);
+            return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
         }
     }
 
@@ -4812,226 +4862,6 @@
         mPackageUsage.write(true);
     }
 
-    private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
-             boolean forceDex, boolean defer, ArraySet<String> done) {
-        for (int i=0; i<libs.size(); i++) {
-            PackageParser.Package libPkg;
-            String libName;
-            synchronized (mPackages) {
-                libName = libs.get(i);
-                SharedLibraryEntry lib = mSharedLibraries.get(libName);
-                if (lib != null && lib.apk != null) {
-                    libPkg = mPackages.get(lib.apk);
-                } else {
-                    libPkg = null;
-                }
-            }
-            if (libPkg != null && !done.contains(libName)) {
-                performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
-            }
-        }
-    }
-
-    static final int DEX_OPT_SKIPPED = 0;
-    static final int DEX_OPT_PERFORMED = 1;
-    static final int DEX_OPT_DEFERRED = 2;
-    static final int DEX_OPT_FAILED = -1;
-
-    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            boolean forceDex, boolean defer, ArraySet<String> done) {
-        final String[] instructionSets = targetInstructionSets != null ?
-                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
-
-        if (done != null) {
-            done.add(pkg.packageName);
-            if (pkg.usesLibraries != null) {
-                performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
-            }
-            if (pkg.usesOptionalLibraries != null) {
-                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);
-            }
-        }
-
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
-            return DEX_OPT_SKIPPED;
-        }
-
-        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-
-        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
-        boolean performedDexOpt = false;
-        // There are three basic cases here:
-        // 1.) we need to dexopt, either because we are forced or it is needed
-        // 2.) we are defering a needed dexopt
-        // 3.) we are skipping an unneeded dexopt
-        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-            if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
-                continue;
-            }
-
-            for (String path : paths) {
-                try {
-                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
-                    // patckage or the one we find does not match the image checksum (i.e. it was
-                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
-                    // odex file and it matches the checksum of the image but not its base address,
-                    // meaning we need to move it.
-                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
-                            pkg.packageName, dexCodeInstructionSet, defer);
-                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
-                        Log.i(TAG, "Running dexopt on: " + path + " pkg="
-                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
-                                + " vmSafeMode=" + vmSafeMode);
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, dexCodeInstructionSet, vmSafeMode);
-
-                        if (ret < 0) {
-                            // Don't bother running dexopt again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
-                            return DEX_OPT_FAILED;
-                        }
-
-                        performedDexOpt = true;
-                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
-                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, dexCodeInstructionSet);
-
-                        if (ret < 0) {
-                            // Don't bother running patchoat again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
-                            return DEX_OPT_FAILED;
-                        }
-
-                        performedDexOpt = true;
-                    }
-
-                    // We're deciding to defer a needed dexopt. Don't bother dexopting for other
-                    // paths and instruction sets. We'll deal with them all together when we process
-                    // our list of deferred dexopts.
-                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
-                        if (mDeferredDexOpt == null) {
-                            mDeferredDexOpt = new ArraySet<PackageParser.Package>();
-                        }
-                        mDeferredDexOpt.add(pkg);
-                        return DEX_OPT_DEFERRED;
-                    }
-                } catch (FileNotFoundException e) {
-                    Slog.w(TAG, "Apk not found for dexopt: " + path);
-                    return DEX_OPT_FAILED;
-                } catch (IOException e) {
-                    Slog.w(TAG, "IOException reading apk: " + path, e);
-                    return DEX_OPT_FAILED;
-                } catch (StaleDexCacheError e) {
-                    Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
-                    return DEX_OPT_FAILED;
-                } catch (Exception e) {
-                    Slog.w(TAG, "Exception when doing dexopt : ", e);
-                    return DEX_OPT_FAILED;
-                }
-            }
-
-            // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
-            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
-            // it isn't required. We therefore mark that this package doesn't need dexopt unless
-            // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
-            // it.
-            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
-        }
-
-        // If we've gotten here, we're sure that no error occurred and that we haven't
-        // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
-        // we've skipped all of them because they are up to date. In both cases this
-        // package doesn't need dexopt any longer.
-        return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
-    }
-
-    private static String[] getAppDexInstructionSets(ApplicationInfo info) {
-        if (info.primaryCpuAbi != null) {
-            if (info.secondaryCpuAbi != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    private static String[] getAppDexInstructionSets(PackageSetting ps) {
-        if (ps.primaryCpuAbiString != null) {
-            if (ps.secondaryCpuAbiString != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
-                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    private static String getPreferredInstructionSet() {
-        if (sPreferredInstructionSet == null) {
-            sPreferredInstructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
-        }
-
-        return sPreferredInstructionSet;
-    }
-
-    private static List<String> getAllInstructionSets() {
-        final String[] allAbis = Build.SUPPORTED_ABIS;
-        final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
-
-        for (String abi : allAbis) {
-            final String instructionSet = VMRuntime.getInstructionSet(abi);
-            if (!allInstructionSets.contains(instructionSet)) {
-                allInstructionSets.add(instructionSet);
-            }
-        }
-
-        return allInstructionSets;
-    }
-
-    /**
-     * Returns the instruction set that should be used to compile dex code. In the presence of
-     * a native bridge this might be different than the one shared libraries use.
-     */
-    private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
-        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
-        return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
-    }
-
-    private static String[] getDexCodeInstructionSets(String[] instructionSets) {
-        ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
-        for (String instructionSet : instructionSets) {
-            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
-        }
-        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
-    }
-
-    /**
-     * Returns deduplicated list of supported instructions for dex code.
-     */
-    public static String[] getAllDexCodeInstructionSets() {
-        String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
-        for (int i = 0; i < supportedInstructionSets.length; i++) {
-            String abi = Build.SUPPORTED_ABIS[i];
-            supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
-        }
-        return getDexCodeInstructionSets(supportedInstructionSets);
-    }
-
     @Override
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
@@ -5047,25 +4877,14 @@
         synchronized (mInstallLock) {
             final String[] instructionSets = new String[] {
                     getPrimaryInstructionSet(pkg.applicationInfo) };
-            final int res = performDexOptLI(pkg, instructionSets, true, false, true);
-            if (res != DEX_OPT_PERFORMED) {
+            final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
+                    true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+            if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
                 throw new IllegalStateException("Failed to dexopt: " + res);
             }
         }
     }
 
-    private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
-                                boolean forceDex, boolean defer, boolean inclDependencies) {
-        ArraySet<String> done;
-        if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
-            done = new ArraySet<String>();
-            done.add(pkg.packageName);
-        } else {
-            done = null;
-        }
-        return performDexOptLI(pkg, instructionSets,  forceDex, defer, done);
-    }
-
     private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
         if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -5081,10 +4900,6 @@
         return true;
     }
 
-    File getDataPathForUser(int userId) {
-        return new File(mUserAppDataDir.getAbsolutePath() + File.separator + userId);
-    }
-
     private File getDataPathForPackage(String packageName, int userId) {
         /*
          * Until we fully support multiple users, return the directory we
@@ -5292,7 +5107,7 @@
         }
 
         if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_PRIVILEGED;
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
 
         if (mCustomResolverComponentName != null &&
@@ -5366,7 +5181,7 @@
         // writer
         synchronized (mPackages) {
             if (pkg.mSharedUserId != null) {
-                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
+                suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
                 if (suid == null) {
                     throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                             "Creating application package " + pkg.packageName
@@ -5440,7 +5255,8 @@
                     destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
                     pkg.applicationInfo.primaryCpuAbi,
                     pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.applicationInfo.flags, user, false);
+                    pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
+                    user, false);
             if (pkgSetting == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                         "Creating application package " + pkg.packageName + " failed");
@@ -5751,7 +5567,7 @@
             // pass once we've determined ABI below.
             setNativeLibraryPaths(pkg);
 
-            final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg);
+            final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
             final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
             final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
 
@@ -5927,8 +5743,9 @@
         }
 
         if ((scanFlags & SCAN_NO_DEX) == 0) {
-            if (performDexOptLI(pkg, null /* instruction sets */, forceDex,
-                    (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+            int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
+                    forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+            if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                 throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
             }
         }
@@ -6002,8 +5819,10 @@
             if ((scanFlags & SCAN_NO_DEX) == 0) {
                 for (int i = 0; i < clientLibPkgs.size(); i++) {
                     PackageParser.Package clientPkg = clientLibPkgs.get(i);
-                    if (performDexOptLI(clientPkg, null /* instruction sets */, forceDex,
-                            (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+                    int result = mPackageDexOptimizer.performDexOpt(clientPkg,
+                            null /* instruction sets */, forceDex,
+                            (scanFlags & SCAN_DEFER_DEX) != 0, false);
+                    if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                         throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
                                 "scanPackageLI failed to dexopt clientLibPkgs");
                     }
@@ -6472,14 +6291,15 @@
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
                         Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
 
-                        if (performDexOptLI(ps.pkg, null /* instruction sets */, forceDexOpt,
-                                deferDexOpt, true) == DEX_OPT_FAILED) {
+                        int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
+                                null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+                        if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                             ps.primaryCpuAbiString = null;
                             ps.pkg.applicationInfo.primaryCpuAbi = null;
                             return;
                         } else {
                             mInstaller.rmdex(ps.codePathString,
-                                             getDexCodeInstructionSet(getPreferredInstructionSet()));
+                                    getDexCodeInstructionSet(getPreferredInstructionSet()));
                         }
                     }
                 }
@@ -6552,7 +6372,7 @@
         final String codePath = pkg.codePath;
         final File codeFile = new File(codePath);
         final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);
-        final boolean asecApp = isForwardLocked(info) || isExternal(info);
+        final boolean asecApp = info.isForwardLocked() || isExternal(info);
 
         info.nativeLibraryRootDir = null;
         info.nativeLibraryRootRequiresIsa = false;
@@ -9387,6 +9207,25 @@
         }
     }
 
+    private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+        if (!allCodePaths.isEmpty()) {
+            if (instructionSets == null) {
+                throw new IllegalStateException("instructionSet == null");
+            }
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String codePath : allCodePaths) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                    int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
+                    if (retCode < 0) {
+                        Slog.w(TAG, "Couldn't remove dex file for package: "
+                                + " at location " + codePath + ", retcode=" + retCode);
+                        // we don't consider this to be a failure of the core package deletion
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Logic to handle installation of non-ASEC applications, including copying
      * and renaming logic.
@@ -9599,23 +9438,7 @@
             }
 
             cleanUp();
-
-            if (!allCodePaths.isEmpty()) {
-                if (instructionSets == null) {
-                    throw new IllegalStateException("instructionSet == null");
-                }
-                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-                for (String codePath : allCodePaths) {
-                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                        if (retCode < 0) {
-                            Slog.w(TAG, "Couldn't remove dex file for package: "
-                                    + " at location " + codePath + ", retcode=" + retCode);
-                            // we don't consider this to be a failure of the core package deletion
-                        }
-                    }
-                }
-            }
+            removeDexFiles(allCodePaths, instructionSets);
         }
 
         boolean doPostDeleteLI(boolean delete) {
@@ -9920,31 +9743,10 @@
 
         private void cleanUpResourcesLI(List<String> allCodePaths) {
             cleanUp();
-
-            if (!allCodePaths.isEmpty()) {
-                if (instructionSets == null) {
-                    throw new IllegalStateException("instructionSet == null");
-                }
-                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-                for (String codePath : allCodePaths) {
-                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                        if (retCode < 0) {
-                            Slog.w(TAG, "Couldn't remove dex file for package: "
-                                    + " at location " + codePath + ", retcode=" + retCode);
-                            // we don't consider this to be a failure of the core package deletion
-                        }
-                    }
-                }
-            }
+            removeDexFiles(allCodePaths, instructionSets);
         }
 
-        boolean matchContainer(String app) {
-            if (cid.startsWith(app)) {
-                return true;
-            }
-            return false;
-        }
+
 
         String getPackageName() {
             return getAsecPackageName(cid);
@@ -10154,7 +9956,7 @@
             PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
                     System.currentTimeMillis(), user);
 
-            updateSettingsLI(newPackage, installerPackageName, null, null, res);
+            updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -10262,7 +10064,7 @@
 
             // If deleted package lived in a container, give users a chance to
             // relinquish resources before killing.
-            if (isForwardLocked(deletedPackage) || isExternal(deletedPackage)) {
+            if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
                 if (DEBUG_INSTALL) {
                     Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
                 }
@@ -10276,7 +10078,8 @@
             try {
                 final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
+                        user);
                 updatedSettings = true;
             } catch (PackageManagerException e) {
                 res.setError("Package couldn't be installed in " + pkg.codePath, e);
@@ -10303,7 +10106,7 @@
                 // Parse old package
                 boolean oldOnSd = isExternal(deletedPackage);
                 int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
-                        (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+                        (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
                         (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
                 int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
                 try {
@@ -10335,7 +10138,8 @@
         boolean disabledSystem = false;
         boolean updatedSettings = false;
         parseFlags |= PackageParser.PARSE_IS_SYSTEM;
-        if ((deletedPackage.applicationInfo.flags&ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+        if ((deletedPackage.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+                != 0) {
             parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
         }
         String packageName = deletedPackage.packageName;
@@ -10405,7 +10209,8 @@
             }
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
+                        user);
                 updatedSettings = true;
             }
 
@@ -10441,7 +10246,7 @@
 
     private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
             int[] allUsers, boolean[] perUserInstalled,
-            PackageInstalledInfo res) {
+            PackageInstalledInfo res, UserHandle user) {
         String pkgName = newPackage.packageName;
         synchronized (mPackages) {
             //write settings. the installStatus will be incomplete at this stage.
@@ -10460,13 +10265,13 @@
             // For system-bundled packages, we assume that installing an upgraded version
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
-            if (isSystemApp(newPackage)) {
-                // NB: implicit assumption that system package upgrades apply to all users
-                if (DEBUG_INSTALL) {
-                    Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
-                }
-                PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (ps != null) {
+            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            if (ps != null) {
+                if (isSystemApp(newPackage)) {
+                    // NB: implicit assumption that system package upgrades apply to all users
+                    if (DEBUG_INSTALL) {
+                        Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
+                    }
                     if (res.origUsers != null) {
                         for (int userHandle : res.origUsers) {
                             ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
@@ -10486,6 +10291,13 @@
                         // upcoming call to mSettings.writeLPr().
                     }
                 }
+                // It's implied that when a user requests installation, they want the app to be
+                // installed and enabled.
+                int userId = user.getIdentifier();
+                if (userId != UserHandle.USER_ALL) {
+                    ps.setInstalled(true, userId);
+                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+                }
             }
             res.name = pkgName;
             res.uid = newPackage.applicationInfo.uid;
@@ -10692,18 +10504,6 @@
         }
     }
 
-    private static boolean isForwardLocked(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
-    }
-
-    private static boolean isForwardLocked(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
-    }
-
-    private boolean isForwardLocked(PackageSetting ps) {
-        return (ps.pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
-    }
-
     private static boolean isMultiArch(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
     }
@@ -10729,7 +10529,7 @@
     }
 
     private static boolean isPrivilegedApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 
     private static boolean isSystemApp(ApplicationInfo info) {
@@ -10757,7 +10557,7 @@
         if (isExternal(ps)) {
             installFlags |= PackageManager.INSTALL_EXTERNAL;
         }
-        if (isForwardLocked(ps)) {
+        if (ps.isForwardLocked()) {
             installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
         }
         return installFlags;
@@ -11611,7 +11411,7 @@
             if (ps != null) {
                 libDirRoot = ps.legacyNativeLibraryPathString;
             }
-            if (p != null && (isExternal(p) || isForwardLocked(p))) {
+            if (p != null && (isExternal(p) || p.isForwardLocked())) {
                 String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
                 if (secureContainerId != null) {
                     asecPath = PackageHelper.getSdFilesystem(secureContainerId);
@@ -11625,7 +11425,7 @@
                 Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
                 return false;
             }
-            if (isForwardLocked(p)) {
+            if (p.isForwardLocked()) {
                 publicSrcDir = applicationInfo.getBaseResourcePath();
             }
         }
@@ -12198,7 +11998,7 @@
                     return;
                 }
             }
-            mSettings.writePackageRestrictionsLPr(userId);
+            scheduleWritePackageRestrictionsLocked(userId);
             components = mPendingBroadcasts.get(userId, packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
@@ -12965,7 +12765,7 @@
                     }
 
                     final AsecInstallArgs args = new AsecInstallArgs(cid,
-                            getAppDexInstructionSets(ps), isForwardLocked(ps));
+                            getAppDexInstructionSets(ps), ps.isForwardLocked());
                     // The package status is changed only if the code path
                     // matches between settings and the container id.
                     if (ps.codePathString != null
@@ -13247,7 +13047,7 @@
                             Slog.w(TAG, "No move required. Trying to move to same location");
                             returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
                         } else {
-                            if (isForwardLocked(pkg)) {
+                            if (pkg.isForwardLocked()) {
                                 currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
                                 newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
                             }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 696aa34..06d842a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,10 +32,10 @@
     PackageSetting(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            int pVersionCode, int pkgFlags) {
+            int pVersionCode, int pkgFlags, int privateFlags) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags);
+                pVersionCode, pkgFlags, privateFlags);
     }
 
     /**
@@ -62,6 +62,10 @@
     }
 
     public boolean isPrivileged() {
-        return (pkgFlags & ApplicationInfo.FLAG_PRIVILEGED) != 0;
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+    }
+
+    public boolean isForwardLocked() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 1dcadb4..4b8ca42 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -112,8 +112,8 @@
     PackageSettingBase(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            int pVersionCode, int pkgFlags) {
-        super(pkgFlags);
+            int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
+        super(pkgFlags, pkgPrivateFlags);
         this.name = name;
         this.realName = realName;
         init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
diff --git a/services/core/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
index 5d30e76..bb0dba1 100644
--- a/services/core/java/com/android/server/pm/PendingPackage.java
+++ b/services/core/java/com/android/server/pm/PendingPackage.java
@@ -24,10 +24,10 @@
     PendingPackage(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString, int sharedId,
-            int pVersionCode, int pkgFlags) {
+            int pVersionCode, int pkgFlags, int pkgPrivateFlags) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags);
+                pVersionCode, pkgFlags, pkgPrivateFlags);
         this.sharedId = sharedId;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index 9c8a9bd..ef29cb3 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm;
 
-import java.io.PrintWriter;
-
 import com.android.server.IntentResolver;
 
 public class PersistentPreferredIntentResolver
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 81302b9..1ff6fb8 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -16,15 +16,12 @@
 
 package com.android.server.pm;
 
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
 
-import com.android.internal.util.XmlUtils;
-
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -35,13 +32,22 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 /**
- * Centralized access to SELinux MMAC (middleware MAC) implementation.
+ * Centralized access to SELinux MMAC (middleware MAC) implementation. This
+ * class is responsible for loading the appropriate mac_permissions.xml file
+ * as well as providing an interface for assigning seinfo values to apks.
+ *
  * {@hide}
  */
 public final class SELinuxMMAC {
@@ -51,11 +57,9 @@
     private static final boolean DEBUG_POLICY = false;
     private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
 
-    // Signature seinfo values read from policy.
-    private static HashMap<Signature, Policy> sSigSeinfo = new HashMap<Signature, Policy>();
-
-    // Default seinfo read from policy.
-    private static String sDefaultSeinfo = null;
+    // All policy stanzas read from mac_permissions.xml. This is also the lock
+    // to synchronize access during policy load and access attempts.
+    private static final List<Policy> sPolicies = new ArrayList<Policy>();
 
     // Data policy override version file.
     private static final String DATA_VERSION_FILE =
@@ -94,285 +98,289 @@
     private static final String SEAPP_HASH_FILE =
             Environment.getDataDirectory().toString() + "/system/seapp_hash";
 
-
-    // Signature policy stanzas
-    static class Policy {
-        private String seinfo;
-        private final HashMap<String, String> pkgMap;
-
-        Policy() {
-            seinfo = null;
-            pkgMap = new HashMap<String, String>();
-        }
-
-        void putSeinfo(String seinfoValue) {
-            seinfo = seinfoValue;
-        }
-
-        void putPkg(String pkg, String seinfoValue) {
-            pkgMap.put(pkg, seinfoValue);
-        }
-
-        // Valid policy stanza means there exists a global
-        // seinfo value or at least one package policy.
-        boolean isValid() {
-            return (seinfo != null) || (!pkgMap.isEmpty());
-        }
-
-        String checkPolicy(String pkgName) {
-            // Check for package name seinfo value first.
-            String seinfoValue = pkgMap.get(pkgName);
-            if (seinfoValue != null) {
-                return seinfoValue;
-            }
-
-            // Return the global seinfo value.
-            return seinfo;
-        }
-    }
-
-    private static void flushInstallPolicy() {
-        sSigSeinfo.clear();
-        sDefaultSeinfo = null;
-    }
-
+    /**
+     * Load the mac_permissions.xml file containing all seinfo assignments used to
+     * label apps. The loaded mac_permissions.xml file is determined by the
+     * MAC_PERMISSIONS class variable which is set at class load time which itself
+     * is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
+     * the proper structure of a mac_permissions.xml file consult the source code
+     * located at external/sepolicy/mac_permissions.xml.
+     *
+     * @return boolean indicating if policy was correctly loaded. A value of false
+     *         typically indicates a structural problem with the xml or incorrectly
+     *         constructed policy stanzas. A value of true means that all stanzas
+     *         were loaded successfully; no partial loading is possible.
+     */
     public static boolean readInstallPolicy() {
-        // Temp structures to hold the rules while we parse the xml file.
-        // We add all the rules together once we know there's no structural problems.
-        HashMap<Signature, Policy> sigSeinfo = new HashMap<Signature, Policy>();
-        String defaultSeinfo = null;
+        // Temp structure to hold the rules while we parse the xml file. We add
+        // all the rules once we know there's no problems.
+        List<Policy> policies = new ArrayList<>();
+
+        // A separate structure to hold the default stanza. We need to add this to
+        // the end of the policies list structure.
+        Policy defaultPolicy = null;
+
+        // Track sets of known policy certs so we can enforce rules across stanzas.
+        Set<Set<Signature>> knownCerts = new HashSet<>();
 
         FileReader policyFile = null;
+        XmlPullParser parser = Xml.newPullParser();
         try {
             policyFile = new FileReader(MAC_PERMISSIONS);
             Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS);
 
-            XmlPullParser parser = Xml.newPullParser();
             parser.setInput(policyFile);
+            parser.nextTag();
+            parser.require(XmlPullParser.START_TAG, null, "policy");
 
-            XmlUtils.beginDocument(parser, "policy");
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
                 }
 
                 String tagName = parser.getName();
                 if ("signer".equals(tagName)) {
-                    String cert = parser.getAttributeValue(null, "signature");
-                    if (cert == null) {
-                        Slog.w(TAG, "<signer> without signature at "
-                               + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
+                    Policy signerPolicy = readSignerOrThrow(parser);
+                    // Return of a Policy instance ensures certain invariants have
+                    // passed, however, we still want to do some cross policy checking.
+                    // Thus, check that we haven't seen the certs in another stanza.
+                    Set<Signature> certs = signerPolicy.getSignatures();
+                    if (knownCerts.contains(certs)) {
+                        String msg = "Separate stanzas have identical certs";
+                        throw new IllegalStateException(msg);
                     }
-                    Signature signature;
-                    try {
-                        signature = new Signature(cert);
-                    } catch (IllegalArgumentException e) {
-                        Slog.w(TAG, "<signer> with bad signature at "
-                               + parser.getPositionDescription(), e);
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    Policy policy = readPolicyTags(parser);
-                    if (policy.isValid()) {
-                        sigSeinfo.put(signature, policy);
-                    }
+                    knownCerts.add(certs);
+                    policies.add(signerPolicy);
                 } else if ("default".equals(tagName)) {
-                    // Value is null if default tag is absent or seinfo tag is malformed.
-                    defaultSeinfo = readSeinfoTag(parser);
-                    if (DEBUG_POLICY_INSTALL)
-                        Slog.i(TAG, "<default> tag assigned seinfo=" + defaultSeinfo);
-
+                    Policy defPolicy = readDefaultOrThrow(parser);
+                    // Return of a Policy instance ensures certain invariants have
+                    // passed, however, we still want to do some cross policy checking.
+                    // Thus, check that we haven't already seen a default stanza.
+                    if (defaultPolicy != null) {
+                        String msg = "Multiple default stanzas identified";
+                        throw new IllegalStateException(msg);
+                    }
+                    defaultPolicy = defPolicy;
                 } else {
-                    XmlUtils.skipCurrentTag(parser);
+                    skip(parser);
                 }
             }
-        } catch (XmlPullParserException xpe) {
-            Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, xpe);
+        } catch (IllegalStateException | IllegalArgumentException |
+                XmlPullParserException ex) {
+            StringBuilder sb = new StringBuilder("Exception @");
+            sb.append(parser.getPositionDescription());
+            sb.append(" while parsing ");
+            sb.append(MAC_PERMISSIONS);
+            sb.append(":");
+            sb.append(ex);
+            Slog.w(TAG, sb.toString());
             return false;
         } catch (IOException ioe) {
-            Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, ioe);
+            Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS, ioe);
             return false;
         } finally {
             IoUtils.closeQuietly(policyFile);
         }
 
-        flushInstallPolicy();
-        sSigSeinfo = sigSeinfo;
-        sDefaultSeinfo = defaultSeinfo;
+        // Add the default policy to the end if there is one. This will ensure that
+        // the default stanza is consulted last when performing policy lookups.
+        if (defaultPolicy != null) {
+            policies.add(defaultPolicy);
+        }
+
+        synchronized (sPolicies) {
+            sPolicies.clear();
+            sPolicies.addAll(policies);
+        }
 
         return true;
     }
 
-    private static Policy readPolicyTags(XmlPullParser parser) throws
-            IOException, XmlPullParserException {
+    /**
+     * Loop over a signer tag looking for seinfo, package and cert tags. A {@link Policy}
+     * instance will be created and returned in the process. During the pass all other
+     * tag elements will be skipped.
+     *
+     * @param parser an XmlPullParser object representing a signer element.
+     * @return the constructed {@link Policy} instance
+     * @throws IOException
+     * @throws XmlPullParserException
+     * @throws IllegalArgumentException if any of the validation checks fail while
+     *         parsing tag values.
+     * @throws IllegalStateException if any of the invariants fail when constructing
+     *         the {@link Policy} instance.
+     */
+    private static Policy readSignerOrThrow(XmlPullParser parser) throws IOException,
+            XmlPullParserException {
 
-        int type;
-        int outerDepth = parser.getDepth();
-        Policy policy = new Policy();
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && (type != XmlPullParser.END_TAG
-                   || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG
-                || type == XmlPullParser.TEXT) {
+        parser.require(XmlPullParser.START_TAG, null, "signer");
+        Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
+
+        // Check for a cert attached to the signer tag. We allow a signature
+        // to appear as an attribute as well as those attached to cert tags.
+        String cert = parser.getAttributeValue(null, "signature");
+        if (cert != null) {
+            pb.addSignature(cert);
+        }
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
                 continue;
             }
 
             String tagName = parser.getName();
             if ("seinfo".equals(tagName)) {
-                String seinfo = parseSeinfo(parser);
-                if (seinfo != null) {
-                    policy.putSeinfo(seinfo);
-                }
-                XmlUtils.skipCurrentTag(parser);
+                String seinfo = parser.getAttributeValue(null, "value");
+                pb.setGlobalSeinfoOrThrow(seinfo);
+                readSeinfo(parser);
             } else if ("package".equals(tagName)) {
-                String pkg = parser.getAttributeValue(null, "name");
-                if (!validatePackageName(pkg)) {
-                    Slog.w(TAG, "<package> without valid name at "
-                           + parser.getPositionDescription());
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                }
-
-                String seinfo = readSeinfoTag(parser);
-                if (seinfo != null) {
-                    policy.putPkg(pkg, seinfo);
-                }
+                readPackageOrThrow(parser, pb);
+            } else if ("cert".equals(tagName)) {
+                String sig = parser.getAttributeValue(null, "signature");
+                pb.addSignature(sig);
+                readCert(parser);
             } else {
-                XmlUtils.skipCurrentTag(parser);
+                skip(parser);
             }
         }
-        return policy;
+
+        return pb.build();
     }
 
-    private static String readSeinfoTag(XmlPullParser parser) throws
-            IOException, XmlPullParserException {
+    /**
+     * Loop over a default element looking for seinfo child tags. A {@link Policy}
+     * instance will be created and returned in the process. All other tags encountered
+     * will be skipped.
+     *
+     * @param parser an XmlPullParser object representing a default element.
+     * @return the constructed {@link Policy} instance
+     * @throws IOException
+     * @throws XmlPullParserException
+     * @throws IllegalArgumentException if any of the validation checks fail while
+     *         parsing tag values.
+     * @throws IllegalStateException if any of the invariants fail when constructing
+     *         the {@link Policy} instance.
+     */
+    private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
+            XmlPullParserException {
 
-        int type;
-        int outerDepth = parser.getDepth();
-        String seinfo = null;
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && (type != XmlPullParser.END_TAG
-                   || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG
-                || type == XmlPullParser.TEXT) {
+        parser.require(XmlPullParser.START_TAG, null, "default");
+        Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
+        pb.setAsDefaultPolicy();
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
                 continue;
             }
 
             String tagName = parser.getName();
             if ("seinfo".equals(tagName)) {
-                seinfo = parseSeinfo(parser);
+                String seinfo = parser.getAttributeValue(null, "value");
+                pb.setGlobalSeinfoOrThrow(seinfo);
+                readSeinfo(parser);
+            } else {
+                skip(parser);
             }
-            XmlUtils.skipCurrentTag(parser);
         }
-        return seinfo;
-    }
 
-    private static String parseSeinfo(XmlPullParser parser) {
-
-        String seinfoValue = parser.getAttributeValue(null, "value");
-        if (!validateValue(seinfoValue)) {
-            Slog.w(TAG, "<seinfo> without valid value at "
-                   + parser.getPositionDescription());
-            seinfoValue = null;
-        }
-        return seinfoValue;
+        return pb.build();
     }
 
     /**
-     * General validation routine for package names.
-     * Returns a boolean indicating if the passed string
-     * is a valid android package name.
+     * Loop over a package element looking for seinfo child tags. If found return the
+     * value attribute of the seinfo tag, otherwise return null. All other tags encountered
+     * will be skipped.
+     *
+     * @param parser an XmlPullParser object representing a package element.
+     * @param pb a Policy.PolicyBuilder instance to build
+     * @throws IOException
+     * @throws XmlPullParserException
+     * @throws IllegalArgumentException if any of the validation checks fail while
+     *         parsing tag values.
+     * @throws IllegalStateException if there is a duplicate seinfo tag for the current
+     *         package tag.
      */
-    private static boolean validatePackageName(String name) {
-        if (name == null)
-            return false;
+    private static void readPackageOrThrow(XmlPullParser parser, Policy.PolicyBuilder pb) throws
+            IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, null, "package");
+        String pkgName = parser.getAttributeValue(null, "name");
 
-        final int N = name.length();
-        boolean hasSep = false;
-        boolean front = true;
-        for (int i=0; i<N; i++) {
-            final char c = name.charAt(i);
-            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
-                front = false;
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (!front) {
-                if ((c >= '0' && c <= '9') || c == '_') {
-                    continue;
-                }
+
+            String tagName = parser.getName();
+            if ("seinfo".equals(tagName)) {
+                String seinfo = parser.getAttributeValue(null, "value");
+                pb.addInnerPackageMapOrThrow(pkgName, seinfo);
+                readSeinfo(parser);
+            } else {
+                skip(parser);
             }
-            if (c == '.') {
-                hasSep = true;
-                front = true;
-                continue;
-            }
-            return false;
         }
-        return hasSep;
+    }
+
+    private static void readCert(XmlPullParser parser) throws IOException,
+            XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, null, "cert");
+        parser.nextTag();
+    }
+
+    private static void readSeinfo(XmlPullParser parser) throws IOException,
+            XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, null, "seinfo");
+        parser.nextTag();
+    }
+
+    private static void skip(XmlPullParser p) throws IOException, XmlPullParserException {
+        if (p.getEventType() != XmlPullParser.START_TAG) {
+            throw new IllegalStateException();
+        }
+        int depth = 1;
+        while (depth != 0) {
+            switch (p.next()) {
+            case XmlPullParser.END_TAG:
+                depth--;
+                break;
+            case XmlPullParser.START_TAG:
+                depth++;
+                break;
+            }
+        }
     }
 
     /**
-     * General validation routine for tag values.
-     * Returns a boolean indicating if the passed string
-     * contains only letters or underscores.
-     */
-    private static boolean validateValue(String name) {
-        if (name == null)
-            return false;
-
-        final int N = name.length();
-        if (N == 0)
-            return false;
-
-        for (int i = 0; i < N; i++) {
-            final char c = name.charAt(i);
-            if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c != '_')) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Labels a package based on an seinfo tag from install policy.
-     * The label is attached to the ApplicationInfo instance of the package.
+     * Applies a security label to a package based on an seinfo tag taken from a matched
+     * policy. All signature based policy stanzas are consulted first and, if no match
+     * is found, the default policy stanza is then consulted. The security label is
+     * attached to the ApplicationInfo instance of the package in the event that a matching
+     * policy was found.
+     *
      * @param pkg object representing the package to be labeled.
-     * @return boolean which determines whether a non null seinfo label
-     *         was assigned to the package. A null value simply meaning that
-     *         no policy matched.
+     * @return boolean which determines whether a non null seinfo label was assigned
+     *         to the package. A null value simply represents that no policy matched.
      */
     public static boolean assignSeinfoValue(PackageParser.Package pkg) {
-
-        // We just want one of the signatures to match.
-        for (Signature s : pkg.mSignatures) {
-            if (s == null)
-                continue;
-
-            Policy policy = sSigSeinfo.get(s);
-            if (policy != null) {
-                String seinfo = policy.checkPolicy(pkg.packageName);
+        synchronized (sPolicies) {
+            for (Policy policy : sPolicies) {
+                String seinfo = policy.getMatchedSeinfo(pkg);
                 if (seinfo != null) {
                     pkg.applicationInfo.seinfo = seinfo;
-                    if (DEBUG_POLICY_INSTALL)
-                        Slog.i(TAG, "package (" + pkg.packageName +
-                               ") labeled with seinfo=" + seinfo);
-
+                    if (DEBUG_POLICY_INSTALL) {
+                        Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
+                               "seinfo=" + seinfo);
+                    }
                     return true;
                 }
             }
         }
 
-        // If we have a default seinfo value then great, otherwise
-        // we set a null object and that is what we started with.
-        pkg.applicationInfo.seinfo = sDefaultSeinfo;
-        if (DEBUG_POLICY_INSTALL)
-            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with seinfo="
-                   + (sDefaultSeinfo == null ? "null" : sDefaultSeinfo));
-
-        return (sDefaultSeinfo != null);
+        if (DEBUG_POLICY_INSTALL) {
+            Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
+                   "seinfo will remain null");
+        }
+        return false;
     }
 
     /**
@@ -477,3 +485,312 @@
         return false;
     }
 }
+
+/**
+ * Holds valid policy representations of individual stanzas from a mac_permissions.xml
+ * file. Each instance can further be used to assign seinfo values to apks using the
+ * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
+ * {@link PolicyBuilder} pattern class, where each instance is validated against a set
+ * of invariants before being built and returned. Each instance can be guaranteed to
+ * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
+ * file.
+ * </p>
+ * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
+ * signer based Policy instance.
+ * </p>
+ * <pre>
+ * {@code
+ * Policy policy = new Policy.PolicyBuilder()
+ *         .addSignature("308204a8...")
+ *         .addSignature("483538c8...")
+ *         .setGlobalSeinfoOrThrow("paltform")
+ *         .addInnerPackageMapOrThrow("com.foo.", "bar")
+ *         .addInnerPackageMapOrThrow("com.foo.other", "bar")
+ *         .build();
+ * }
+ * </pre>
+ * <p>
+ * An example of how to use {@link Policy.PolicyBuilder} to create a default based Policy
+ * instance.
+ * </p>
+ * <pre>
+ * {@code
+ * Policy policy = new Policy.PolicyBuilder()
+ *         .setAsDefaultPolicy()
+ *         .setGlobalSeinfoOrThrow("defualt")
+ *         .build();
+ * }
+ * </pre>
+ */
+final class Policy {
+
+    private final String mSeinfo;
+    private final boolean mDefaultStanza;
+    private final Set<Signature> mCerts;
+    private final Map<String, String> mPkgMap;
+
+    // Use the PolicyBuilder pattern to instantiate
+    private Policy(PolicyBuilder builder) {
+        mSeinfo = builder.mSeinfo;
+        mDefaultStanza = builder.mDefaultStanza;
+        mCerts = Collections.unmodifiableSet(builder.mCerts);
+        mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
+    }
+
+    /**
+     * Return all the certs stored with this policy stanza.
+     *
+     * @return A set of Signature objects representing all the certs stored
+     *         with the policy.
+     */
+    public Set<Signature> getSignatures() {
+        return mCerts;
+    }
+
+    /**
+     * <p>
+     * Determine the seinfo value to assign to an apk. The appropriate seinfo value
+     * is determined using the following steps:
+     * </p>
+     * <ul>
+     *   <li> If this Policy instance is defined as a default stanza:
+     *       <ul><li>Return the global seinfo value</li></ul>
+     *   </li>
+     *   <li> If this Policy instance is defined as a signer stanza:
+     *     <ul>
+     *       <li> All certs used to sign the apk and all certs stored with this policy
+     *         instance are tested for set equality. If this fails then null is returned.
+     *       </li>
+     *       <li> If all certs match then an appropriate inner package stanza is
+     *         searched based on package name alone. If matched, the stored seinfo
+     *         value for that mapping is returned.
+     *       </li>
+     *       <li> If all certs matched and no inner package stanza matches then return
+     *         the global seinfo value. The returned value can be null in this case.
+     *       </li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     * <p>
+     * In all cases, a return value of null should be interpreted as the apk failing
+     * to match this Policy instance; i.e. failing this policy stanza.
+     * </p>
+     * @param pkg the apk to check given as a PackageParser.Package object
+     * @return A string representing the seinfo matched during policy lookup.
+     *         A value of null can also be returned if no match occured.
+     */
+    public String getMatchedSeinfo(PackageParser.Package pkg) {
+        if (!mDefaultStanza) {
+            // Check for exact signature matches across all certs.
+            Signature[] certs = mCerts.toArray(new Signature[0]);
+            if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+                return null;
+            }
+
+            // Check for inner package name matches given that the
+            // signature checks already passed.
+            String seinfoValue = mPkgMap.get(pkg.packageName);
+            if (seinfoValue != null) {
+                return seinfoValue;
+            }
+        }
+
+        // Return the global seinfo value (even if it's null).
+        return mSeinfo;
+    }
+
+    /**
+     * A nested builder class to create {@link Policy} instances. A {@link Policy}
+     * class instance represents one valid policy stanza found in a mac_permissions.xml
+     * file. A valid policy stanza is defined to be either a signer or default stanza
+     * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
+     * {@link #build} method ensures a set of invariants are upheld enforcing the correct
+     * stanza structure before returning a valid Policy object.
+     */
+    public static final class PolicyBuilder {
+
+        private String mSeinfo;
+        private boolean mDefaultStanza;
+        private final Set<Signature> mCerts;
+        private final Map<String, String> mPkgMap;
+
+        public PolicyBuilder() {
+            mCerts = new HashSet<Signature>(2);
+            mPkgMap = new HashMap<String, String>(2);
+        }
+
+        /**
+         * Sets this stanza as a defualt stanza. All policy stanzas are assumed to
+         * be signer stanzas unless this method is explicitly called. Default stanzas
+         * are treated differently with respect to allowable child tags, ordering and
+         * when and how policy decisions are enforced.
+         *
+         * @return The reference to this PolicyBuilder.
+         */
+        public PolicyBuilder setAsDefaultPolicy() {
+            mDefaultStanza = true;
+            return this;
+        }
+
+        /**
+         * Adds a signature to the set of certs used for validation checks. The purpose
+         * being that all contained certs will need to be matched against all certs
+         * contained with an apk.
+         *
+         * @param cert the signature to add given as a String.
+         * @return The reference to this PolicyBuilder.
+         * @throws IllegalArgumentException if the cert value fails validation;
+         *         null or is an invalid hex-encoded ASCII string.
+         */
+        public PolicyBuilder addSignature(String cert) {
+            if (cert == null) {
+                String err = "Invalid signature value " + cert;
+                throw new IllegalArgumentException(err);
+            }
+
+            mCerts.add(new Signature(cert));
+            return this;
+        }
+
+        /**
+         * Set the global seinfo tag for this policy stanza. The global seinfo tag
+         * represents the seinfo element that is used in one of two ways depending on
+         * its context. When attached to a signer tag the global seinfo represents an
+         * assignment when there isn't a further inner package refinement in policy.
+         * When used with a default tag, it represents the only allowable assignment
+         * value.
+         *
+         * @param seinfo the seinfo value given as a String.
+         * @return The reference to this PolicyBuilder.
+         * @throws IllegalArgumentException if the seinfo value fails validation;
+         *         null, zero length or contains non-valid characters [^a-zA-Z_\._0-9].
+         * @throws IllegalStateException if an seinfo value has already been found
+         */
+        public PolicyBuilder setGlobalSeinfoOrThrow(String seinfo) {
+            if (!validateValue(seinfo)) {
+                String err = "Invalid seinfo value " + seinfo;
+                throw new IllegalArgumentException(err);
+            }
+
+            if (mSeinfo != null && !mSeinfo.equals(seinfo)) {
+                String err = "Duplicate seinfo tag found";
+                throw new IllegalStateException(err);
+            }
+
+            mSeinfo = seinfo;
+            return this;
+        }
+
+        /**
+         * Create a package name to seinfo value mapping. Each mapping represents
+         * the seinfo value that will be assigned to the described package name.
+         * These localized mappings allow the global seinfo to be overriden. This
+         * mapping provides no value when used in conjunction with a default stanza;
+         * enforced through the {@link #build} method.
+         *
+         * @param pkgName the android package name given to the app
+         * @param seinfo the seinfo value that will be assigned to the passed pkgName
+         * @return The reference to this PolicyBuilder.
+         * @throws IllegalArgumentException if the seinfo value fails validation;
+         *         null, zero length or contains non-valid characters [^a-zA-Z_\.0-9].
+         *         Or, if the package name isn't a valid android package name.
+         * @throws IllegalStateException if trying to reset a package mapping with a
+         *         different seinfo value.
+         */
+        public PolicyBuilder addInnerPackageMapOrThrow(String pkgName, String seinfo) {
+            if (!validateValue(pkgName)) {
+                String err = "Invalid package name " + pkgName;
+                throw new IllegalArgumentException(err);
+            }
+            if (!validateValue(seinfo)) {
+                String err = "Invalid seinfo value " + seinfo;
+                throw new IllegalArgumentException(err);
+            }
+
+            String pkgValue = mPkgMap.get(pkgName);
+            if (pkgValue != null && !pkgValue.equals(seinfo)) {
+                String err = "Conflicting seinfo value found";
+                throw new IllegalStateException(err);
+            }
+
+            mPkgMap.put(pkgName, seinfo);
+            return this;
+        }
+
+        /**
+         * General validation routine for the attribute strings of an element. Checks
+         * if the string is non-null, positive length and only contains [a-zA-Z_\.0-9].
+         *
+         * @param name the string to validate.
+         * @return boolean indicating if the string was valid.
+         */
+        private boolean validateValue(String name) {
+            if (name == null)
+                return false;
+
+            // Want to match on [0-9a-zA-Z_.]
+            if (!name.matches("\\A[\\.\\w]+\\z")) {
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * <p>
+         * Create a {@link Policy} instance based on the current configuration. This
+         * method checks for certain policy invariants used to enforce certain guarantees
+         * about the expected structure of a policy stanza.
+         * Those invariants are:
+         * </p>
+         *    <ul>
+         *      <li> If a default stanza
+         *        <ul>
+         *          <li> an attached global seinfo tag must be present </li>
+         *          <li> no signatures and no package names can be present </li>
+         *        </ul>
+         *      </li>
+         *      <li> If a signer stanza
+         *        <ul>
+         *           <li> at least one cert must be found </li>
+         *           <li> either a global seinfo value is present OR at least one
+         *           inner package mapping must be present. </li>
+         *        </ul>
+         *      </li>
+         *    </ul>
+         *
+         * @return an instance of {@link Policy} with the options set from this builder
+         * @throws IllegalStateException if an invariant is violated.
+         */
+        public Policy build() {
+            Policy p = new Policy(this);
+
+            if (p.mDefaultStanza) {
+                if (p.mSeinfo == null) {
+                    String err = "Missing global seinfo tag with default stanza.";
+                    throw new IllegalStateException(err);
+                }
+                if (p.mCerts.size() != 0) {
+                    String err = "Certs not allowed with default stanza.";
+                    throw new IllegalStateException(err);
+                }
+                if (!p.mPkgMap.isEmpty()) {
+                    String err = "Inner package mappings not allowed with default stanza.";
+                    throw new IllegalStateException(err);
+                }
+            } else {
+                if (p.mCerts.size() == 0) {
+                    String err = "Missing certs with signer tag. Expecting at least one.";
+                    throw new IllegalStateException(err);
+                }
+                if ((p.mSeinfo == null) && (p.mPkgMap.isEmpty())) {
+                    String err = "Missing seinfo OR package tags with signer tag. At " +
+                            "least one must be present.";
+                    throw new IllegalStateException(err);
+                }
+            }
+
+            return p;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 524f638..d353494 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -281,11 +281,11 @@
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
-            int pkgFlags, UserHandle user, boolean add) {
+            int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {
         final String name = pkg.packageName;
         PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
                 resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
-                pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);
+                pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true /* allowInstall */);
         return p;
     }
 
@@ -311,13 +311,13 @@
     }
 
     SharedUserSetting getSharedUserLPw(String name,
-            int pkgFlags, boolean create) {
+            int pkgFlags, int pkgPrivateFlags, boolean create) {
         SharedUserSetting s = mSharedUsers.get(name);
         if (s == null) {
             if (!create) {
                 return null;
             }
-            s = new SharedUserSetting(name, pkgFlags);
+            s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
             s.userId = newUserIdLPw(s);
             Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
             // < 0 means we couldn't assign a userid; fall out and return
@@ -373,7 +373,7 @@
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.secondaryCpuAbiString,
-                p.appId, p.versionCode, p.pkgFlags);
+                p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -388,7 +388,7 @@
 
     PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
-            String cpuAbiOverrideString, int uid, int vc, int pkgFlags) {
+            String cpuAbiOverrideString, int uid, int vc, int pkgFlags, int pkgPrivateFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.appId == uid) {
@@ -400,7 +400,7 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath,
                 legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                cpuAbiOverrideString, vc, pkgFlags);
+                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags);
         p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
@@ -409,7 +409,7 @@
         return null;
     }
 
-    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+    SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
         SharedUserSetting s = mSharedUsers.get(name);
         if (s != null) {
             if (s.userId == uid) {
@@ -419,7 +419,7 @@
                     "Adding duplicate shared user, keeping first: " + name);
             return null;
         }
-        s = new SharedUserSetting(name, pkgFlags);
+        s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
         s.userId = uid;
         if (addUserIdLPw(uid, s, name)) {
             mSharedUsers.put(name, s);
@@ -469,7 +469,7 @@
     private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
-            int vc, int pkgFlags, UserHandle installUser, boolean add,
+            int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add,
             boolean allowInstall) {
         PackageSetting p = mPackages.get(name);
         UserManagerService userManager = UserManagerService.getInstance();
@@ -511,9 +511,8 @@
                 // If what we are scanning is a system (and possibly privileged) package,
                 // then make it so, regardless of whether it was previously installed only
                 // in the data partition.
-                final int sysPrivFlags = pkgFlags
-                        & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PRIVILEGED);
-                p.pkgFlags |= sysPrivFlags;
+                p.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
+                p.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
             }
         }
         if (p == null) {
@@ -521,7 +520,7 @@
                 // We are consuming the data from an existing package.
                 p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
                         legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                        null /* cpuAbiOverrideString */, vc, pkgFlags);
+                        null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
                 if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                         + name + " is adopting original package " + origPackage.name);
                 // Note that we will retain the new package's signature so
@@ -539,7 +538,7 @@
             } else {
                 p = new PackageSetting(name, realName, codePath, resourcePath,
                         legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                        null /* cpuAbiOverrideString */, vc, pkgFlags);
+                        null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
                 p.setTimeStamp(codePath.lastModified());
                 p.sharedUser = sharedUser;
                 // If this is not a system app, it starts out stopped.
@@ -1818,7 +1817,8 @@
             serializer.attribute(null, "cpuAbiOverride", pkg.cpuAbiOverrideString);
         }
 
-        serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+        serializer.attribute(null, "publicFlags", Integer.toString(pkg.pkgFlags));
+        serializer.attribute(null, "privateFlags", Integer.toString(pkg.pkgPrivateFlags));
         serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
         serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
         serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
@@ -2127,8 +2127,8 @@
                 PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
                         (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
                         pp.legacyNativeLibraryPathString, pp.primaryCpuAbiString,
-                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, null,
-                        true /* add */, false /* allowInstall */);
+                        pp.secondaryCpuAbiString, pp.versionCode, pp.pkgFlags, pp.pkgPrivateFlags,
+                        null, true /* add */, false /* allowInstall */);
                 if (p == null) {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unable to create application package for " + pp.name);
@@ -2596,14 +2596,15 @@
         }
 
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
         final File codePathFile = new File(codePathStr);
         if (PackageManagerService.locationIsPrivileged(codePathFile)) {
-            pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
+            pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
         PackageSetting ps = new PackageSetting(name, realName, codePathFile,
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
-                secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags);
+                secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -2662,6 +2663,11 @@
         mDisabledSysPackages.put(name, ps);
     }
 
+    private static int PRE_M_APP_INFO_FLAG_HIDDEN = 1<<27;
+    private static int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1<<28;
+    private static int PRE_M_APP_INFO_FLAG_FORWARD_LOCK = 1<<29;
+    private static int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1<<30;
+
     private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
         String name = null;
         String realName = null;
@@ -2678,6 +2684,7 @@
         String installerPackageName = null;
         String uidError = null;
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         long timeStamp = 0;
         long firstInstallTime = 0;
         long lastUpdateTime = 0;
@@ -2713,22 +2720,54 @@
             }
             installerPackageName = parser.getAttributeValue(null, "installer");
 
-            systemStr = parser.getAttributeValue(null, "flags");
+            systemStr = parser.getAttributeValue(null, "publicFlags");
             if (systemStr != null) {
                 try {
                     pkgFlags = Integer.parseInt(systemStr);
                 } catch (NumberFormatException e) {
                 }
-            } else {
-                // For backward compatibility
-                systemStr = parser.getAttributeValue(null, "system");
+                systemStr = parser.getAttributeValue(null, "privateFlags");
                 if (systemStr != null) {
-                    pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
-                            : 0;
+                    try {
+                        pkgPrivateFlags = Integer.parseInt(systemStr);
+                    } catch (NumberFormatException e) {
+                    }
+                }
+            } else {
+                // Pre-M -- both public and private flags were stored in one "flags" field.
+                systemStr = parser.getAttributeValue(null, "flags");
+                if (systemStr != null) {
+                    try {
+                        pkgFlags = Integer.parseInt(systemStr);
+                    } catch (NumberFormatException e) {
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_HIDDEN) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_FORWARD_LOCK) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
+                    }
+                    if ((pkgFlags & PRE_M_APP_INFO_FLAG_PRIVILEGED) != 0) {
+                        pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+                    }
+                    pkgFlags &= ~(PRE_M_APP_INFO_FLAG_HIDDEN
+                            | PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE
+                            | PRE_M_APP_INFO_FLAG_FORWARD_LOCK
+                            | PRE_M_APP_INFO_FLAG_PRIVILEGED);
                 } else {
-                    // Old settings that don't specify system... just treat
-                    // them as system, good enough.
-                    pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+                    // For backward compatibility
+                    systemStr = parser.getAttributeValue(null, "system");
+                    if (systemStr != null) {
+                        pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+                                : 0;
+                    } else {
+                        // Old settings that don't specify system... just treat
+                        // them as system, good enough.
+                        pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+                    }
                 }
             }
             String timeStampStr = parser.getAttributeValue(null, "ft");
@@ -2781,7 +2820,8 @@
             } else if (userId > 0) {
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                         new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
-                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags);
+                        secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
+                        pkgPrivateFlags);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
                             + userId + " pkg=" + packageSetting);
@@ -2800,7 +2840,7 @@
                     packageSetting = new PendingPackage(name.intern(), realName, new File(
                             codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                             primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                            userId, versionCode, pkgFlags);
+                            userId, versionCode, pkgFlags, pkgPrivateFlags);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
                     packageSetting.lastUpdateTime = lastUpdateTime;
@@ -2967,6 +3007,7 @@
         String name = null;
         String idStr = null;
         int pkgFlags = 0;
+        int pkgPrivateFlags = 0;
         SharedUserSetting su = null;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
@@ -2985,7 +3026,8 @@
                                 + " has bad userId " + idStr + " at "
                                 + parser.getPositionDescription());
             } else {
-                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+                if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
+                        == null) {
                     PackageManagerService
                             .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
                                     + parser.getPositionDescription());
@@ -3302,9 +3344,12 @@
         ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
         ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
         ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
-        ApplicationInfo.FLAG_PRIVILEGED, "PRIVILEGED",
-        ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
-        ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+    };
+
+    static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
     };
 
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
@@ -3391,6 +3436,8 @@
                 pw.println(ps.pkg.applicationInfo.toString());
             pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
                     FLAG_DUMP_SPEC); pw.println();
+            pw.print(prefix); pw.print("  priavateFlags="); printFlags(pw,
+                    ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
             pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
             if (ps.pkg.mOperationPending) {
                 pw.print(prefix); pw.println("  mOperationPending=true");
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2b406f7..d95739c 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -28,14 +28,16 @@
 
     // flags that are associated with this uid, regardless of any package flags
     int uidFlags;
+    int uidPrivateFlags;
 
     final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
 
     final PackageSignatures signatures = new PackageSignatures();
 
-    SharedUserSetting(String _name, int _pkgFlags) {
-        super(_pkgFlags);
+    SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
+        super(_pkgFlags, _pkgPrivateFlags);
         uidFlags =  _pkgFlags;
+        uidPrivateFlags = _pkgPrivateFlags;
         name = _name;
     }
 
@@ -55,12 +57,20 @@
                 }
                 setFlags(aggregatedFlags);
             }
+            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
+                int aggregatedPrivateFlags = uidPrivateFlags;
+                for (PackageSetting ps : packages) {
+                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
+                }
+                setPrivateFlags(aggregatedPrivateFlags);
+            }
         }
     }
 
     void addPackage(PackageSetting packageSetting) {
         if (packages.add(packageSetting)) {
             setFlags(this.pkgFlags | packageSetting.pkgFlags);
+            setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d484b8f..e4f5e7d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -30,14 +28,14 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.Debug;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IUserManager;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -113,6 +111,7 @@
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
     private static final String USER_PHOTO_FILENAME = "photo.png";
+    private static final String USER_PHOTO_FILENAME_TMP = USER_PHOTO_FILENAME + ".tmp";
 
     private static final String RESTRICTIONS_FILE_PREFIX = "res_";
     private static final String XML_SUFFIX = ".xml";
@@ -134,6 +133,8 @@
     // BACKOFF_INC_INTERVAL times.
     private static final int[] BACKOFF_TIMES = { 0, 30*1000, 60*1000, 5*60*1000, 30*60*1000 };
 
+    static final int WRITE_USER_MSG = 1;
+    static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds
 
     private final Context mContext;
     private final PackageManagerService mPm;
@@ -210,7 +211,7 @@
         mPm = pm;
         mInstallLock = installLock;
         mPackagesLock = packagesLock;
-        mHandler = new Handler();
+        mHandler = new MainHandler();
         synchronized (mInstallLock) {
             synchronized (mPackagesLock) {
                 mUsersDir = new File(dataDir, USER_INFO_DIR);
@@ -433,7 +434,8 @@
     }
 
     @Override
-    public Bitmap getUserIcon(int userId) {
+    public ParcelFileDescriptor getUserIcon(int userId) {
+        String iconPath;
         synchronized (mPackagesLock) {
             UserInfo info = mUsers.get(userId);
             if (info == null || info.partial) {
@@ -448,8 +450,16 @@
             if (info.iconPath == null) {
                 return null;
             }
-            return BitmapFactory.decodeFile(info.iconPath);
+            iconPath = info.iconPath;
         }
+
+        try {
+            return ParcelFileDescriptor.open(
+                    new File(iconPath), ParcelFileDescriptor.MODE_READ_ONLY);
+        } catch (FileNotFoundException e) {
+            Log.e(LOG_TAG, "Couldn't find icon file", e);
+        }
+        return null;
     }
 
     public void makeInitialized(int userId) {
@@ -461,7 +471,7 @@
             }
             if ((info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
                 info.flags |= UserInfo.FLAG_INITIALIZED;
-                writeUserLocked(info);
+                scheduleWriteUserLocked(info);
             }
         }
     }
@@ -529,7 +539,7 @@
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
-            writeUserLocked(mUsers.get(userId));
+            scheduleWriteUserLocked(mUsers.get(userId));
         }
     }
 
@@ -572,6 +582,7 @@
         try {
             File dir = new File(mUsersDir, Integer.toString(info.id));
             File file = new File(dir, USER_PHOTO_FILENAME);
+            File tmp = new File(dir, USER_PHOTO_FILENAME_TMP);
             if (!dir.exists()) {
                 dir.mkdir();
                 FileUtils.setPermissions(
@@ -580,7 +591,8 @@
                         -1, -1);
             }
             FileOutputStream os;
-            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(file))) {
+            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, os = new FileOutputStream(tmp))
+                    && tmp.renameTo(file)) {
                 info.iconPath = file.getAbsolutePath();
             }
             try {
@@ -588,6 +600,7 @@
             } catch (IOException ioe) {
                 // What the ... !
             }
+            tmp.delete();
         } catch (FileNotFoundException e) {
             Slog.w(LOG_TAG, "Error setting photo for user ", e);
         }
@@ -695,7 +708,7 @@
             UserInfo user = mUsers.get(UserHandle.USER_OWNER);
             if ("Primary".equals(user.name)) {
                 user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name);
-                writeUserLocked(user);
+                scheduleWriteUserLocked(user);
             }
             userVersion = 1;
         }
@@ -705,7 +718,7 @@
             UserInfo user = mUsers.get(UserHandle.USER_OWNER);
             if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
                 user.flags |= UserInfo.FLAG_INITIALIZED;
-                writeUserLocked(user);
+                scheduleWriteUserLocked(user);
             }
             userVersion = 2;
         }
@@ -748,6 +761,13 @@
         writeUserLocked(primary);
     }
 
+    private void scheduleWriteUserLocked(UserInfo userInfo) {
+        if (!mHandler.hasMessages(WRITE_USER_MSG, userInfo)) {
+            Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userInfo);
+            mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
+        }
+    }
+
     /*
      * Writes the user file in this format:
      *
@@ -897,6 +917,7 @@
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
         writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+        writeBoolean(serializer, restrictions, UserManager.DISALLOW_WALLPAPER);
         serializer.endTag(null, TAG_RESTRICTIONS);
     }
 
@@ -951,12 +972,6 @@
                 lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L);
                 profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
                         UserInfo.NO_PROFILE_GROUP_ID);
-                if (profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-                    // This attribute was added and renamed during development of L.
-                    // TODO Remove upgrade path by 1st May 2014
-                    profileGroupId = readIntAttribute(parser, "relatedGroupId",
-                            UserInfo.NO_PROFILE_GROUP_ID);
-                }
                 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                 if ("true".equals(valueString)) {
                     partial = true;
@@ -1049,6 +1064,7 @@
         readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
         readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
         readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
+        readBoolean(parser, restrictions, UserManager.DISALLOW_WALLPAPER);
     }
 
     private void readBoolean(XmlPullParser parser, Bundle restrictions,
@@ -1191,14 +1207,13 @@
                     if (parent != null) {
                         if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
                             parent.profileGroupId = parent.id;
-                            writeUserLocked(parent);
+                            scheduleWriteUserLocked(parent);
                         }
                         userInfo.profileGroupId = parent.profileGroupId;
                     }
-                    writeUserLocked(userInfo);
                     mPm.createNewUserLILPw(userId, userPath);
                     userInfo.partial = false;
-                    writeUserLocked(userInfo);
+                    scheduleWriteUserLocked(userInfo);
                     updateUserIdsLocked();
                     Bundle restrictions = new Bundle();
                     mUserRestrictions.append(userId, restrictions);
@@ -1523,12 +1538,12 @@
                 }
                 if (passwordToHash(pin, pinState.salt).equals(pinState.pinHash)) {
                     pinState.failedAttempts = 0;
-                    writeUserLocked(mUsers.get(userId));
+                    scheduleWriteUserLocked(mUsers.get(userId));
                     return UserManager.PIN_VERIFICATION_SUCCESS;
                 } else {
                     pinState.failedAttempts++;
                     pinState.lastAttemptTime = System.currentTimeMillis();
-                    writeUserLocked(mUsers.get(userId));
+                    scheduleWriteUserLocked(mUsers.get(userId));
                     return waitTime;
                 }
             }
@@ -1592,7 +1607,8 @@
                 try {
                     for (ApplicationInfo appInfo : apps) {
                         if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
-                                && (appInfo.flags & ApplicationInfo.FLAG_HIDDEN) != 0) {
+                                && (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
+                                        != 0) {
                             mPm.setApplicationHiddenSettingAsUser(appInfo.packageName, false,
                                     userHandle);
                         }
@@ -1786,7 +1802,8 @@
     public int getUserHandle(int userSerialNumber) {
         synchronized (mPackagesLock) {
             for (int userId : mUserIds) {
-                if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
+                UserInfo info = getUserInfoLocked(userId);
+                if (info != null && info.serialNumber == userSerialNumber) return userId;
             }
             // Not found
             return -1;
@@ -1827,7 +1844,7 @@
             }
             if (now > EPOCH_PLUS_30_YEARS) {
                 user.lastLoggedInTime = now;
-                writeUserLocked(user);
+                scheduleWriteUserLocked(user);
             }
         }
     }
@@ -1904,4 +1921,22 @@
             }
         }
     }
+
+    final class MainHandler extends Handler {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case WRITE_USER_MSG:
+                    removeMessages(WRITE_USER_MSG, msg.obj);
+                    synchronized (mPackagesLock) {
+                        int userId = ((UserInfo) msg.obj).id;
+                        UserInfo userInfo = mUsers.get(userId);
+                        if (userInfo != null) {
+                            writeUserLocked(userInfo);
+                        }
+                    }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
new file mode 100644
index 0000000..e972ec7
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -0,0 +1,284 @@
+/*
+ * 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.policy;
+
+import android.app.StatusBarManager;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy.WindowState;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import java.io.PrintWriter;
+
+/**
+ * Controls state/behavior specific to a system bar window.
+ */
+public class BarController {
+    private static final boolean DEBUG = false;
+
+    private static final int TRANSIENT_BAR_NONE = 0;
+    private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
+    private static final int TRANSIENT_BAR_SHOWING = 2;
+    private static final int TRANSIENT_BAR_HIDING = 3;
+
+    private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
+
+    protected final String mTag;
+    private final int mTransientFlag;
+    private final int mUnhideFlag;
+    private final int mTranslucentFlag;
+    private final int mStatusBarManagerId;
+    private final int mTranslucentWmFlag;
+    protected final Handler mHandler;
+    private final Object mServiceAquireLock = new Object();
+    protected IStatusBarService mStatusBarService;
+
+    private WindowState mWin;
+    private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
+    private int mTransientBarState;
+    private boolean mPendingShow;
+    private long mLastTranslucent;
+
+    public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
+            int statusBarManagerId, int translucentWmFlag) {
+        mTag = "BarController." + tag;
+        mTransientFlag = transientFlag;
+        mUnhideFlag = unhideFlag;
+        mTranslucentFlag = translucentFlag;
+        mStatusBarManagerId = statusBarManagerId;
+        mTranslucentWmFlag = translucentWmFlag;
+        mHandler = new Handler();
+    }
+
+    public void setWindow(WindowState win) {
+        mWin = win;
+    }
+
+    public void showTransient() {
+        if (mWin != null) {
+            setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
+        }
+    }
+
+    public boolean isTransientShowing() {
+        return mTransientBarState == TRANSIENT_BAR_SHOWING;
+    }
+
+    public boolean isTransientShowRequested() {
+        return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
+    }
+
+    public boolean wasRecentlyTranslucent() {
+        return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
+    }
+
+    public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
+        if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
+                (vis & mTransientFlag) == 0) {
+            // sysui requests hide
+            setTransientBarState(TRANSIENT_BAR_HIDING);
+            setBarShowingLw(false);
+        } else if (mWin != null && (oldVis & mUnhideFlag) != 0 && (vis & mUnhideFlag) == 0) {
+            // sysui ready to unhide
+            setBarShowingLw(true);
+        }
+    }
+
+    public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
+        if (mWin != null) {
+            if (win != null && (win.getAttrs().privateFlags
+                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
+                int fl = PolicyControl.getWindowFlags(win, null);
+                if ((fl & mTranslucentWmFlag) != 0) {
+                    vis |= mTranslucentFlag;
+                } else {
+                    vis &= ~mTranslucentFlag;
+                }
+                if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+                    vis |= View.SYSTEM_UI_TRANSPARENT;
+                } else {
+                    vis &= ~View.SYSTEM_UI_TRANSPARENT;
+                }
+            } else {
+                vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
+                vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
+            }
+        }
+        return vis;
+    }
+
+    public boolean setBarShowingLw(final boolean show) {
+        if (mWin == null) return false;
+        if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
+            mPendingShow = true;
+            return false;
+        }
+        final boolean wasVis = mWin.isVisibleLw();
+        final boolean wasAnim = mWin.isAnimatingLw();
+        final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
+        final int state = computeStateLw(wasVis, wasAnim, mWin, change);
+        final boolean stateChanged = updateStateLw(state);
+        return change || stateChanged;
+    }
+
+    private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+        if (win.hasDrawnLw()) {
+            final boolean vis = win.isVisibleLw();
+            final boolean anim = win.isAnimatingLw();
+            if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
+                return StatusBarManager.WINDOW_STATE_HIDDEN;
+            } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) {
+                return StatusBarManager.WINDOW_STATE_SHOWING;
+            } else if (change) {
+                if (wasVis && vis && !wasAnim && anim) {
+                    return StatusBarManager.WINDOW_STATE_HIDING;
+                } else {
+                    return StatusBarManager.WINDOW_STATE_SHOWING;
+                }
+            }
+        }
+        return mState;
+    }
+
+    private boolean updateStateLw(final int state) {
+        if (state != mState) {
+            mState = state;
+            if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.setWindowState(mStatusBarManagerId, state);
+                        }
+                    } catch (RemoteException e) {
+                        if (DEBUG) Slog.w(mTag, "Error posting window state", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+            return true;
+        }
+        return false;
+    }
+
+    public boolean checkHiddenLw() {
+        if (mWin != null && mWin.hasDrawnLw()) {
+            if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
+                updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
+            }
+            if (mTransientBarState == TRANSIENT_BAR_HIDING && !mWin.isVisibleLw()) {
+                // Finished animating out, clean up and reset style
+                setTransientBarState(TRANSIENT_BAR_NONE);
+                if (mPendingShow) {
+                    setBarShowingLw(true);
+                    mPendingShow = false;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean checkShowTransientBarLw() {
+        if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
+            return false;
+        } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
+            return false;
+        } else if (mWin == null) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
+            return false;
+        } else if (mWin.isDisplayedLw()) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar already visible");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
+        if (mWin == null) return vis;
+        if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
+            if (transientAllowed) {
+                vis |= mTransientFlag;
+                if ((oldVis & mTransientFlag) == 0) {
+                    vis |= mUnhideFlag;  // tell sysui we're ready to unhide
+                }
+                setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
+            } else {
+                setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
+            }
+        }
+        if (mTransientBarState != TRANSIENT_BAR_NONE) {
+            vis |= mTransientFlag;  // ignore clear requests until transition completes
+            vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
+        }
+        if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
+                ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
+            mLastTranslucent = SystemClock.uptimeMillis();
+        }
+        return vis;
+    }
+
+    private void setTransientBarState(int state) {
+        if (mWin != null && state != mTransientBarState) {
+            if (mTransientBarState == TRANSIENT_BAR_SHOWING || state == TRANSIENT_BAR_SHOWING) {
+                mLastTranslucent = SystemClock.uptimeMillis();
+            }
+            mTransientBarState = state;
+            if (DEBUG) Slog.d(mTag, "mTransientBarState: " + transientBarStateToString(state));
+        }
+    }
+
+    protected IStatusBarService getStatusBarService() {
+        synchronized (mServiceAquireLock) {
+            if (mStatusBarService == null) {
+                mStatusBarService = IStatusBarService.Stub.asInterface(
+                        ServiceManager.getService("statusbar"));
+            }
+            return mStatusBarService;
+        }
+    }
+
+    private static String transientBarStateToString(int state) {
+        if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
+        if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+        if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
+        if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
+        throw new IllegalArgumentException("Unknown state " + state);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        if (mWin != null) {
+            pw.print(prefix); pw.println(mTag);
+            pw.print(prefix); pw.print("  "); pw.print("mState"); pw.print('=');
+            pw.println(StatusBarManager.windowStateToString(mState));
+            pw.print(prefix); pw.print("  "); pw.print("mTransientBar"); pw.print('=');
+            pw.println(transientBarStateToString(mTransientBarState));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
new file mode 100644
index 0000000..b99c436
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.policy;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.Build;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.view.Display;
+
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
+    private static final String TAG = "BurnInProtection";
+
+    // Default value when max burnin radius is not set.
+    public static final int BURN_IN_MAX_RADIUS_DEFAULT = -1;
+
+    private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+    private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
+
+    private static final String ACTION_BURN_IN_PROTECTION =
+            "android.internal.policy.action.BURN_IN_PROTECTION";
+
+    private static final int BURN_IN_SHIFT_STEP = 2;
+
+    private boolean mBurnInProtectionActive;
+
+    private final int mMinHorizontalBurnInOffset;
+    private final int mMaxHorizontalBurnInOffset;
+    private final int mMinVerticalBurnInOffset;
+    private final int mMaxVerticalBurnInOffset;
+
+    private final int mBurnInRadiusMaxSquared;
+
+    private int mLastBurnInXOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mXOffsetDirection = 1;
+    private int mLastBurnInYOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mYOffsetDirection = 1;
+
+    private final AlarmManager mAlarmManager;
+    private final PendingIntent mBurnInProtectionIntent;
+    private final DisplayManagerInternal mDisplayManagerInternal;
+    private final Display mDisplay;
+
+    private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateBurnInProtection();
+        }
+    };
+    
+    public BurnInProtectionHelper(Context context, int minHorizontalOffset,
+            int maxHorizontalOffset, int minVerticalOffset, int maxVerticalOffset,
+            int maxOffsetRadius) {
+        final Resources resources = context.getResources();
+        mMinHorizontalBurnInOffset = minHorizontalOffset;
+        mMaxHorizontalBurnInOffset = maxHorizontalOffset;
+        mMinVerticalBurnInOffset = minVerticalOffset;
+        mMaxVerticalBurnInOffset = maxHorizontalOffset;
+        if (maxOffsetRadius != BURN_IN_MAX_RADIUS_DEFAULT) {
+            mBurnInRadiusMaxSquared = maxOffsetRadius * maxOffsetRadius;
+        } else {
+            mBurnInRadiusMaxSquared = BURN_IN_MAX_RADIUS_DEFAULT;
+        }
+
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        context.registerReceiver(mBurnInProtectionReceiver,
+                new IntentFilter(ACTION_BURN_IN_PROTECTION));
+        Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
+        intent.setPackage(context.getPackageName());
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
+                intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        DisplayManager displayManager =
+                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        displayManager.registerDisplayListener(this, null /* handler */);
+    }
+
+    public void startBurnInProtection() {
+        if (!mBurnInProtectionActive) {
+            mBurnInProtectionActive = true;
+            updateBurnInProtection();
+        }
+    }
+
+    private void updateBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            adjustOffsets();
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
+                    mLastBurnInXOffset, mLastBurnInYOffset);
+            // Next adjustment at least ten seconds in the future.
+            long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+            // And aligned to the minute.
+            next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+                    + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+        } else {
+            mAlarmManager.cancel(mBurnInProtectionIntent);
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
+        }
+    }
+
+    public void cancelBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            mBurnInProtectionActive = false;
+            updateBurnInProtection();
+        }
+    }
+
+    /**
+     * Gently shifts current burn-in offsets, minimizing the change for the user.
+     *
+     * Shifts are applied in following fashion:
+     * 1) shift horizontally from minimum to the maximum;
+     * 2) shift vertically by one from minimum to the maximum;
+     * 3) shift horizontally from maximum to the minimum;
+     * 4) shift vertically by one from minimum to the maximum.
+     * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
+     *
+     * On top of that, stay within specified radius. If the shift distance from the center is
+     * higher than the radius, skip these values and go the next position that is within the radius.
+     */
+    private void adjustOffsets() {
+        do {
+            // By default, let's just shift the X offset.
+            final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
+            mLastBurnInXOffset += xChange;
+            if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
+                    || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
+                // Whoops, we went too far horizontally. Let's retract..
+                mLastBurnInXOffset -= xChange;
+                // change horizontal direction..
+                mXOffsetDirection *= -1;
+                // and let's shift the Y offset.
+                final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
+                mLastBurnInYOffset += yChange;
+                if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
+                        || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
+                    // Whoops, we went to far vertically. Let's retract..
+                    mLastBurnInYOffset -= yChange;
+                    // and change vertical direction.
+                    mYOffsetDirection *= -1;
+                }
+            }
+            // If we are outside of the radius, let's try again.
+        } while (mBurnInRadiusMaxSquared != BURN_IN_MAX_RADIUS_DEFAULT
+                && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
+                        > mBurnInRadiusMaxSquared);
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + TAG);
+        prefix += "  ";
+        pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
+        pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
+                + mMaxHorizontalBurnInOffset + ")");
+        pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
+                + mMaxVerticalBurnInOffset + ")");
+        pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
+        pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
+                + mLastBurnInYOffset + ")");
+        pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
+                + mYOffsetDirection + ")");
+    }
+
+    @Override
+    public void onDisplayAdded(int i) {
+    }
+
+    @Override
+    public void onDisplayRemoved(int i) {
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        if (displayId == mDisplay.getDisplayId()) {
+            if (mDisplay.getState() == Display.STATE_DOZE
+                    || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+                startBurnInProtection();
+            } else {
+                cancelBurnInProtection();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
new file mode 100644
index 0000000..da9c001
--- /dev/null
+++ b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2012 Google 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.server.policy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.speech.tts.TextToSpeech;
+import android.util.MathUtils;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class EnableAccessibilityController {
+
+    private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
+    private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
+
+    public static final int MESSAGE_SPEAK_WARNING = 1;
+    public static final int MESSAGE_SPEAK_ENABLE_CANCELED = 2;
+    public static final int MESSAGE_ENABLE_ACCESSIBILITY = 3;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MESSAGE_SPEAK_WARNING: {
+                    String text = mContext.getString(R.string.continue_to_enable_accessibility);
+                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
+                } break;
+                case MESSAGE_SPEAK_ENABLE_CANCELED: {
+                    String text = mContext.getString(R.string.enable_accessibility_canceled);
+                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
+                } break;
+                case MESSAGE_ENABLE_ACCESSIBILITY: {
+                    enableAccessibility();
+                    mTone.play();
+                    mTts.speak(mContext.getString(R.string.accessibility_enabled),
+                            TextToSpeech.QUEUE_FLUSH, null);
+                } break;
+            }
+        }
+    };
+
+    private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
+            ServiceManager.getService("window"));
+
+    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
+            .Stub.asInterface(ServiceManager.getService("accessibility"));
+
+
+    private final Context mContext;
+    private final Runnable mOnAccessibilityEnabledCallback;
+    private final UserManager mUserManager;
+    private final TextToSpeech mTts;
+    private final Ringtone mTone;
+
+    private final float mTouchSlop;
+
+    private boolean mDestroyed;
+    private boolean mCanceled;
+
+    private float mFirstPointerDownX;
+    private float mFirstPointerDownY;
+    private float mSecondPointerDownX;
+    private float mSecondPointerDownY;
+
+    public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
+        mContext = context;
+        mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
+            @Override
+            public void onInit(int status) {
+                if (mDestroyed) {
+                    mTts.shutdown();
+                }
+            }
+        });
+        mTone = RingtoneManager.getRingtone(context, Settings.System.DEFAULT_NOTIFICATION_URI);
+        mTone.setStreamType(AudioManager.STREAM_MUSIC);
+        mTouchSlop = context.getResources().getDimensionPixelSize(
+                R.dimen.accessibility_touch_slop);
+    }
+
+    public static boolean canEnableAccessibilityViaGesture(Context context) {
+        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
+        // Accessibility is enabled and there is an enabled speaking
+        // accessibility service, then we have nothing to do.
+        if (accessibilityManager.isEnabled()
+                && !accessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()) {
+            return false;
+        }
+        // If the global gesture is enabled and there is a speaking service
+        // installed we are good to go, otherwise there is nothing to do.
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1
+                && !getInstalledSpeakingAccessibilityServices(context).isEmpty();
+    }
+
+    private static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
+            Context context) {
+        List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
+        services.addAll(AccessibilityManager.getInstance(context)
+                .getInstalledAccessibilityServiceList());
+        Iterator<AccessibilityServiceInfo> iterator = services.iterator();
+        while (iterator.hasNext()) {
+            AccessibilityServiceInfo service = iterator.next();
+            if ((service.feedbackType & AccessibilityServiceInfo.FEEDBACK_SPOKEN) == 0) {
+                iterator.remove();
+            }
+        }
+        return services;
+    }
+
+    public void onDestroy() {
+        mDestroyed = true;
+    }
+
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
+                && event.getPointerCount() == 2) {
+            mFirstPointerDownX = event.getX(0);
+            mFirstPointerDownY = event.getY(0);
+            mSecondPointerDownX = event.getX(1);
+            mSecondPointerDownY = event.getY(1);
+            mHandler.sendEmptyMessageDelayed(MESSAGE_SPEAK_WARNING,
+                    SPEAK_WARNING_DELAY_MILLIS);
+            mHandler.sendEmptyMessageDelayed(MESSAGE_ENABLE_ACCESSIBILITY,
+                   ENABLE_ACCESSIBILITY_DELAY_MILLIS);
+            return true;
+        }
+        return false;
+    }
+
+    public boolean onTouchEvent(MotionEvent event) {
+        final int pointerCount = event.getPointerCount();
+        final int action = event.getActionMasked();
+        if (mCanceled) {
+            if (action == MotionEvent.ACTION_UP) {
+                mCanceled = false;
+            }
+            return true;
+        }
+        switch (action) {
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                if (pointerCount > 2) {
+                    cancel();
+                }
+            } break;
+            case MotionEvent.ACTION_MOVE: {
+                final float firstPointerMove = MathUtils.dist(event.getX(0),
+                        event.getY(0), mFirstPointerDownX, mFirstPointerDownY);
+                if (Math.abs(firstPointerMove) > mTouchSlop) {
+                    cancel();
+                }
+                final float secondPointerMove = MathUtils.dist(event.getX(1),
+                        event.getY(1), mSecondPointerDownX, mSecondPointerDownY);
+                if (Math.abs(secondPointerMove) > mTouchSlop) {
+                    cancel();
+                }
+            } break;
+            case MotionEvent.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_CANCEL: {
+                cancel();
+            } break;
+        }
+        return true;
+    }
+
+    private void cancel() {
+        mCanceled = true;
+        if (mHandler.hasMessages(MESSAGE_SPEAK_WARNING)) {
+            mHandler.removeMessages(MESSAGE_SPEAK_WARNING);
+        } else if (mHandler.hasMessages(MESSAGE_ENABLE_ACCESSIBILITY)) {
+            mHandler.sendEmptyMessage(MESSAGE_SPEAK_ENABLE_CANCELED);
+        }
+        mHandler.removeMessages(MESSAGE_ENABLE_ACCESSIBILITY);
+    }
+
+    private void enableAccessibility() {
+        List<AccessibilityServiceInfo> services = getInstalledSpeakingAccessibilityServices(
+                mContext);
+        if (services.isEmpty()) {
+            return;
+        }
+        boolean keyguardLocked = false;
+        try {
+            keyguardLocked = mWindowManager.isKeyguardLocked();
+        } catch (RemoteException re) {
+            /* ignore */
+        }
+
+        final boolean hasMoreThanOneUser = mUserManager.getUsers().size() > 1;
+
+        AccessibilityServiceInfo service = services.get(0);
+        boolean enableTouchExploration = (service.flags
+                & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+        // Try to find a service supporting explore by touch.
+        if (!enableTouchExploration) {
+            final int serviceCount = services.size();
+            for (int i = 1; i < serviceCount; i++) {
+                AccessibilityServiceInfo candidate = services.get(i);
+                if ((candidate.flags & AccessibilityServiceInfo
+                        .FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0) {
+                    enableTouchExploration = true;
+                    service = candidate;
+                    break;
+                }
+            }
+        }
+
+        ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
+        ComponentName componentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+        if (!keyguardLocked || !hasMoreThanOneUser) {
+            final int userId = ActivityManager.getCurrentUser();
+            String enabledServiceString = componentName.flattenToString();
+            ContentResolver resolver = mContext.getContentResolver();
+            // Enable one speaking accessibility service.
+            Settings.Secure.putStringForUser(resolver,
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                    enabledServiceString, userId);
+            // Allow the services we just enabled to toggle touch exploration.
+            Settings.Secure.putStringForUser(resolver,
+                    Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                    enabledServiceString, userId);
+            // Enable touch exploration.
+            if (enableTouchExploration) {
+                Settings.Secure.putIntForUser(resolver, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
+                        1, userId);
+            }
+            // Enable accessibility script injection (AndroidVox) for web content.
+            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+                    1, userId);
+            // Turn on accessibility mode last.
+            Settings.Secure.putIntForUser(resolver, Settings.Secure.ACCESSIBILITY_ENABLED,
+                    1, userId);
+        } else if (keyguardLocked) {
+            try {
+                mAccessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
+                        componentName, enableTouchExploration);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+
+        mOnAccessibilityEnabledCallback.run();
+    }
+}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
new file mode 100644
index 0000000..d768fe3
--- /dev/null
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -0,0 +1,1238 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import com.android.internal.app.AlertController;
+import com.android.internal.app.AlertController.AlertParams;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicy.WindowManagerFuncs;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper to show the global actions dialog.  Each item is an {@link Action} that
+ * may show depending on whether the keyguard is showing, and whether the device
+ * is provisioned.
+ */
+class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
+
+    private static final String TAG = "GlobalActions";
+
+    private static final boolean SHOW_SILENT_TOGGLE = true;
+
+    /* Valid settings for global actions keys.
+     * see config.xml config_globalActionList */
+    private static final String GLOBAL_ACTION_KEY_POWER = "power";
+    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+    private static final String GLOBAL_ACTION_KEY_USERS = "users";
+    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
+
+    private final Context mContext;
+    private final WindowManagerFuncs mWindowManagerFuncs;
+    private final AudioManager mAudioManager;
+    private final IDreamManager mDreamManager;
+
+    private ArrayList<Action> mItems;
+    private GlobalActionsDialog mDialog;
+
+    private Action mSilentModeAction;
+    private ToggleAction mAirplaneModeOn;
+
+    private MyAdapter mAdapter;
+
+    private boolean mKeyguardShowing = false;
+    private boolean mDeviceProvisioned = false;
+    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
+    private boolean mIsWaitingForEcmExit = false;
+    private boolean mHasTelephony;
+    private boolean mHasVibrator;
+    private final boolean mShowSilentToggle;
+
+    /**
+     * @param context everything needs a context :(
+     */
+    public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
+        mContext = context;
+        mWindowManagerFuncs = windowManagerFuncs;
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.getService(DreamService.DREAM_SERVICE));
+
+        // receive broadcasts
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
+        context.registerReceiver(mBroadcastReceiver, filter);
+
+        ConnectivityManager cm = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        // get notified of phone state changes
+        TelephonyManager telephonyManager =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
+                mAirplaneModeObserver);
+        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = vibrator != null && vibrator.hasVibrator();
+
+        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
+    }
+
+    /**
+     * Show the global actions dialog (creating if necessary)
+     * @param keyguardShowing True if keyguard is showing
+     */
+    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+        mKeyguardShowing = keyguardShowing;
+        mDeviceProvisioned = isDeviceProvisioned;
+        if (mDialog != null) {
+            mDialog.dismiss();
+            mDialog = null;
+            // Show delayed, so that the dismiss of the previous dialog completes
+            mHandler.sendEmptyMessage(MESSAGE_SHOW);
+        } else {
+            handleShow();
+        }
+    }
+
+    private void awakenIfNecessary() {
+        if (mDreamManager != null) {
+            try {
+                if (mDreamManager.isDreaming()) {
+                    mDreamManager.awaken();
+                }
+            } catch (RemoteException e) {
+                // we tried
+            }
+        }
+    }
+
+    private void handleShow() {
+        awakenIfNecessary();
+        mDialog = createDialog();
+        prepareDialog();
+
+        // If we only have 1 item and it's a simple press action, just do this action.
+        if (mAdapter.getCount() == 1
+                && mAdapter.getItem(0) instanceof SinglePressAction
+                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
+            ((SinglePressAction) mAdapter.getItem(0)).onPress();
+        } else {
+            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+            attrs.setTitle("GlobalActions");
+            mDialog.getWindow().setAttributes(attrs);
+            mDialog.show();
+            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+        }
+    }
+
+    /**
+     * Create the global actions dialog.
+     * @return A new dialog.
+     */
+    private GlobalActionsDialog createDialog() {
+        // Simple toggle style if there's no vibrator, otherwise use a tri-state
+        if (!mHasVibrator) {
+            mSilentModeAction = new SilentModeToggleAction();
+        } else {
+            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
+        }
+        mAirplaneModeOn = new ToggleAction(
+                R.drawable.ic_lock_airplane_mode,
+                R.drawable.ic_lock_airplane_mode_off,
+                R.string.global_actions_toggle_airplane_mode,
+                R.string.global_actions_airplane_mode_on_status,
+                R.string.global_actions_airplane_mode_off_status) {
+
+            void onToggle(boolean on) {
+                if (mHasTelephony && Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                    mIsWaitingForEcmExit = true;
+                    // Launch ECM exit dialog
+                    Intent ecmDialogIntent =
+                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivity(ecmDialogIntent);
+                } else {
+                    changeAirplaneModeSystemSetting(on);
+                }
+            }
+
+            @Override
+            protected void changeStateFromPress(boolean buttonOn) {
+                if (!mHasTelephony) return;
+
+                // In ECM mode airplane state cannot be changed
+                if (!(Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                    mState = buttonOn ? State.TurningOn : State.TurningOff;
+                    mAirplaneState = mState;
+                }
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+        onAirplaneModeChanged();
+
+        mItems = new ArrayList<Action>();
+        String[] defaultActions = mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_globalActionsList);
+
+        ArraySet<String> addedKeys = new ArraySet<String>();
+        for (int i = 0; i < defaultActions.length; i++) {
+            String actionKey = defaultActions[i];
+            if (addedKeys.contains(actionKey)) {
+                // If we already have added this, don't add it again.
+                continue;
+            }
+            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+                mItems.add(new PowerAction());
+            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+                mItems.add(mAirplaneModeOn);
+            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
+                if (Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
+                    mItems.add(getBugReportAction());
+                }
+            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
+                if (mShowSilentToggle) {
+                    mItems.add(mSilentModeAction);
+                }
+            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
+                if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+                    addUsersToMenu(mItems);
+                }
+            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+                mItems.add(getSettingsAction());
+            } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
+                mItems.add(getLockdownAction());
+            } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
+                mItems.add(getVoiceAssistAction());
+            } else {
+                Log.e(TAG, "Invalid global action key " + actionKey);
+            }
+            // Add here so we don't add more than one.
+            addedKeys.add(actionKey);
+        }
+
+        mAdapter = new MyAdapter();
+
+        AlertParams params = new AlertParams(mContext);
+        params.mAdapter = mAdapter;
+        params.mOnClickListener = this;
+        params.mForceInverseBackground = true;
+
+        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
+        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
+
+        dialog.getListView().setItemsCanFocus(true);
+        dialog.getListView().setLongClickable(true);
+        dialog.getListView().setOnItemLongClickListener(
+                new AdapterView.OnItemLongClickListener() {
+                    @Override
+                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
+                            long id) {
+                        final Action action = mAdapter.getItem(position);
+                        if (action instanceof LongPressAction) {
+                            return ((LongPressAction) action).onLongPress();
+                        }
+                        return false;
+                    }
+        });
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+
+        dialog.setOnDismissListener(this);
+
+        return dialog;
+    }
+
+    private final class PowerAction extends SinglePressAction implements LongPressAction {
+        private PowerAction() {
+            super(com.android.internal.R.drawable.ic_lock_power_off,
+                R.string.global_action_power_off);
+        }
+
+        @Override
+        public boolean onLongPress() {
+            mWindowManagerFuncs.rebootSafeMode(true);
+            return true;
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            // shutdown by making sure radio and power are handled accordingly.
+            mWindowManagerFuncs.shutdown(false /* confirm */);
+        }
+    }
+
+    private Action getBugReportAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
+                R.string.bugreport_title) {
+
+            public void onPress() {
+                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+                builder.setTitle(com.android.internal.R.string.bugreport_title);
+                builder.setMessage(com.android.internal.R.string.bugreport_message);
+                builder.setNegativeButton(com.android.internal.R.string.cancel, null);
+                builder.setPositiveButton(com.android.internal.R.string.report,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                // don't actually trigger the bugreport if we are running stability
+                                // tests via monkey
+                                if (ActivityManager.isUserAMonkey()) {
+                                    return;
+                                }
+                                // Add a little delay before executing, to give the
+                                // dialog a chance to go away before it takes a
+                                // screenshot.
+                                mHandler.postDelayed(new Runnable() {
+                                    @Override public void run() {
+                                        try {
+                                            ActivityManagerNative.getDefault()
+                                                    .requestBugReport();
+                                        } catch (RemoteException e) {
+                                        }
+                                    }
+                                }, 500);
+                            }
+                        });
+                AlertDialog dialog = builder.create();
+                dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+                dialog.show();
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+
+            @Override
+            public String getStatus() {
+                return mContext.getString(
+                        com.android.internal.R.string.bugreport_status,
+                        Build.VERSION.RELEASE,
+                        Build.ID);
+            }
+        };
+    }
+
+    private Action getSettingsAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+                R.string.global_action_settings) {
+
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Settings.ACTION_SETTINGS);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getVoiceAssistAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
+                R.string.global_action_voice_assist) {
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getLockdownAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
+                R.string.global_action_lockdown) {
+
+            @Override
+            public void onPress() {
+                new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+                try {
+                    WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error while trying to lock device.", e);
+                }
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+    }
+
+    private UserInfo getCurrentUser() {
+        try {
+            return ActivityManagerNative.getDefault().getCurrentUser();
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    private boolean isCurrentUserOwner() {
+        UserInfo currentUser = getCurrentUser();
+        return currentUser == null || currentUser.isPrimary();
+    }
+
+    private void addUsersToMenu(ArrayList<Action> items) {
+        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (um.isUserSwitcherEnabled()) {
+            List<UserInfo> users = um.getUsers();
+            UserInfo currentUser = getCurrentUser();
+            for (final UserInfo user : users) {
+                if (user.supportsSwitchTo()) {
+                    boolean isCurrentUser = currentUser == null
+                            ? user.id == 0 : (currentUser.id == user.id);
+                    Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
+                            : null;
+                    SinglePressAction switchToUser = new SinglePressAction(
+                            com.android.internal.R.drawable.ic_menu_cc, icon,
+                            (user.name != null ? user.name : "Primary")
+                            + (isCurrentUser ? " \u2714" : "")) {
+                        public void onPress() {
+                            try {
+                                ActivityManagerNative.getDefault().switchUser(user.id);
+                            } catch (RemoteException re) {
+                                Log.e(TAG, "Couldn't switch user " + re);
+                            }
+                        }
+
+                        public boolean showDuringKeyguard() {
+                            return true;
+                        }
+
+                        public boolean showBeforeProvisioning() {
+                            return false;
+                        }
+                    };
+                    items.add(switchToUser);
+                }
+            }
+        }
+    }
+
+    private void prepareDialog() {
+        refreshSilentMode();
+        mAirplaneModeOn.updateState(mAirplaneState);
+        mAdapter.notifyDataSetChanged();
+        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        if (mShowSilentToggle) {
+            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mRingerModeReceiver, filter);
+        }
+    }
+
+    private void refreshSilentMode() {
+        if (!mHasVibrator) {
+            final boolean silentModeOn =
+                    mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
+            ((ToggleAction)mSilentModeAction).updateState(
+                    silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onDismiss(DialogInterface dialog) {
+        if (mShowSilentToggle) {
+            try {
+                mContext.unregisterReceiver(mRingerModeReceiver);
+            } catch (IllegalArgumentException ie) {
+                // ignore this
+                Log.w(TAG, ie);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void onClick(DialogInterface dialog, int which) {
+        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
+            dialog.dismiss();
+        }
+        mAdapter.getItem(which).onPress();
+    }
+
+    /**
+     * The adapter used for the list within the global actions dialog, taking
+     * into account whether the keyguard is showing via
+     * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
+     * via {@link GlobalActions#mDeviceProvisioned}.
+     */
+    private class MyAdapter extends BaseAdapter {
+
+        public int getCount() {
+            int count = 0;
+
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                count++;
+            }
+            return count;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItem(position).isEnabled();
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        public Action getItem(int position) {
+
+            int filteredPos = 0;
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (mKeyguardShowing && !action.showDuringKeyguard()) {
+                    continue;
+                }
+                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+                    continue;
+                }
+                if (filteredPos == position) {
+                    return action;
+                }
+                filteredPos++;
+            }
+
+            throw new IllegalArgumentException("position " + position
+                    + " out of range of showable actions"
+                    + ", filtered count=" + getCount()
+                    + ", keyguardshowing=" + mKeyguardShowing
+                    + ", provisioned=" + mDeviceProvisioned);
+        }
+
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            Action action = getItem(position);
+            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
+        }
+    }
+
+    // note: the scheme below made more sense when we were planning on having
+    // 8 different things in the global actions dialog.  seems overkill with
+    // only 3 items now, but may as well keep this flexible approach so it will
+    // be easy should someone decide at the last minute to include something
+    // else, such as 'enable wifi', or 'enable bluetooth'
+
+    /**
+     * What each item in the global actions dialog must be able to support.
+     */
+    private interface Action {
+        /**
+         * @return Text that will be announced when dialog is created.  null
+         *     for none.
+         */
+        CharSequence getLabelForAccessibility(Context context);
+
+        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
+
+        void onPress();
+
+        /**
+         * @return whether this action should appear in the dialog when the keygaurd
+         *    is showing.
+         */
+        boolean showDuringKeyguard();
+
+        /**
+         * @return whether this action should appear in the dialog before the
+         *   device is provisioned.
+         */
+        boolean showBeforeProvisioning();
+
+        boolean isEnabled();
+    }
+
+    /**
+     * An action that also supports long press.
+     */
+    private interface LongPressAction extends Action {
+        boolean onLongPress();
+    }
+
+    /**
+     * A single press action maintains no state, just responds to a press
+     * and takes an action.
+     */
+    private static abstract class SinglePressAction implements Action {
+        private final int mIconResId;
+        private final Drawable mIcon;
+        private final int mMessageResId;
+        private final CharSequence mMessage;
+
+        protected SinglePressAction(int iconResId, int messageResId) {
+            mIconResId = iconResId;
+            mMessageResId = messageResId;
+            mMessage = null;
+            mIcon = null;
+        }
+
+        protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
+            mIconResId = iconResId;
+            mMessageResId = 0;
+            mMessage = message;
+            mIcon = icon;
+        }
+
+        protected SinglePressAction(int iconResId, CharSequence message) {
+            mIconResId = iconResId;
+            mMessageResId = 0;
+            mMessage = message;
+            mIcon = null;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        public String getStatus() {
+            return null;
+        }
+
+        abstract public void onPress();
+
+        public CharSequence getLabelForAccessibility(Context context) {
+            if (mMessage != null) {
+                return mMessage;
+            } else {
+                return context.getString(mMessageResId);
+            }
+        }
+
+        public View create(
+                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final String status = getStatus();
+            if (!TextUtils.isEmpty(status)) {
+                statusView.setText(status);
+            } else {
+                statusView.setVisibility(View.GONE);
+            }
+            if (mIcon != null) {
+                icon.setImageDrawable(mIcon);
+                icon.setScaleType(ScaleType.CENTER_CROP);
+            } else if (mIconResId != 0) {
+                icon.setImageDrawable(context.getDrawable(mIconResId));
+            }
+            if (mMessage != null) {
+                messageView.setText(mMessage);
+            } else {
+                messageView.setText(mMessageResId);
+            }
+
+            return v;
+        }
+    }
+
+    /**
+     * A toggle action knows whether it is on or off, and displays an icon
+     * and status message accordingly.
+     */
+    private static abstract class ToggleAction implements Action {
+
+        enum State {
+            Off(false),
+            TurningOn(true),
+            TurningOff(true),
+            On(false);
+
+            private final boolean inTransition;
+
+            State(boolean intermediate) {
+                inTransition = intermediate;
+            }
+
+            public boolean inTransition() {
+                return inTransition;
+            }
+        }
+
+        protected State mState = State.Off;
+
+        // prefs
+        protected int mEnabledIconResId;
+        protected int mDisabledIconResid;
+        protected int mMessageResId;
+        protected int mEnabledStatusMessageResId;
+        protected int mDisabledStatusMessageResId;
+
+        /**
+         * @param enabledIconResId The icon for when this action is on.
+         * @param disabledIconResid The icon for when this action is off.
+         * @param essage The general information message, e.g 'Silent Mode'
+         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
+         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
+         */
+        public ToggleAction(int enabledIconResId,
+                int disabledIconResid,
+                int message,
+                int enabledStatusMessageResId,
+                int disabledStatusMessageResId) {
+            mEnabledIconResId = enabledIconResId;
+            mDisabledIconResid = disabledIconResid;
+            mMessageResId = message;
+            mEnabledStatusMessageResId = enabledStatusMessageResId;
+            mDisabledStatusMessageResId = disabledStatusMessageResId;
+        }
+
+        /**
+         * Override to make changes to resource IDs just before creating the
+         * View.
+         */
+        void willCreate() {
+
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return context.getString(mMessageResId);
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            willCreate();
+
+            View v = inflater.inflate(R
+                            .layout.global_actions_item, parent, false);
+
+            ImageView icon = (ImageView) v.findViewById(R.id.icon);
+            TextView messageView = (TextView) v.findViewById(R.id.message);
+            TextView statusView = (TextView) v.findViewById(R.id.status);
+            final boolean enabled = isEnabled();
+
+            if (messageView != null) {
+                messageView.setText(mMessageResId);
+                messageView.setEnabled(enabled);
+            }
+
+            boolean on = ((mState == State.On) || (mState == State.TurningOn));
+            if (icon != null) {
+                icon.setImageDrawable(context.getDrawable(
+                        (on ? mEnabledIconResId : mDisabledIconResid)));
+                icon.setEnabled(enabled);
+            }
+
+            if (statusView != null) {
+                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
+                statusView.setVisibility(View.VISIBLE);
+                statusView.setEnabled(enabled);
+            }
+            v.setEnabled(enabled);
+
+            return v;
+        }
+
+        public final void onPress() {
+            if (mState.inTransition()) {
+                Log.w(TAG, "shouldn't be able to toggle when in transition");
+                return;
+            }
+
+            final boolean nowOn = !(mState == State.On);
+            onToggle(nowOn);
+            changeStateFromPress(nowOn);
+        }
+
+        public boolean isEnabled() {
+            return !mState.inTransition();
+        }
+
+        /**
+         * Implementations may override this if their state can be in on of the intermediate
+         * states until some notification is received (e.g airplane mode is 'turning off' until
+         * we know the wireless connections are back online
+         * @param buttonOn Whether the button was turned on or off
+         */
+        protected void changeStateFromPress(boolean buttonOn) {
+            mState = buttonOn ? State.On : State.Off;
+        }
+
+        abstract void onToggle(boolean on);
+
+        public void updateState(State state) {
+            mState = state;
+        }
+    }
+
+    private class SilentModeToggleAction extends ToggleAction {
+        public SilentModeToggleAction() {
+            super(R.drawable.ic_audio_vol_mute,
+                    R.drawable.ic_audio_vol,
+                    R.string.global_action_toggle_silent_mode,
+                    R.string.global_action_silent_mode_on_status,
+                    R.string.global_action_silent_mode_off_status);
+        }
+
+        void onToggle(boolean on) {
+            if (on) {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+            } else {
+                mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+            }
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+    }
+
+    private static class SilentModeTriStateAction implements Action, View.OnClickListener {
+
+        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+
+        private final AudioManager mAudioManager;
+        private final Handler mHandler;
+        private final Context mContext;
+
+        SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
+            mAudioManager = audioManager;
+            mHandler = handler;
+            mContext = context;
+        }
+
+        private int ringerModeToIndex(int ringerMode) {
+            // They just happen to coincide
+            return ringerMode;
+        }
+
+        private int indexToRingerMode(int index) {
+            // They just happen to coincide
+            return index;
+        }
+
+        @Override
+        public CharSequence getLabelForAccessibility(Context context) {
+            return null;
+        }
+
+        public View create(Context context, View convertView, ViewGroup parent,
+                LayoutInflater inflater) {
+            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
+
+            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
+            for (int i = 0; i < 3; i++) {
+                View itemView = v.findViewById(ITEM_IDS[i]);
+                itemView.setSelected(selectedIndex == i);
+                // Set up click handler
+                itemView.setTag(i);
+                itemView.setOnClickListener(this);
+            }
+            return v;
+        }
+
+        public void onPress() {
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        public boolean isEnabled() {
+            return true;
+        }
+
+        void willCreate() {
+        }
+
+        public void onClick(View v) {
+            if (!(v.getTag() instanceof Integer)) return;
+
+            int index = (Integer) v.getTag();
+            mAudioManager.setRingerMode(indexToRingerMode(index));
+            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+        }
+    }
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
+                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
+                if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
+                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
+                }
+            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+                // Airplane mode can be changed after ECM exits if airplane toggle button
+                // is pressed during ECM mode
+                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
+                        mIsWaitingForEcmExit) {
+                    mIsWaitingForEcmExit = false;
+                    changeAirplaneModeSystemSetting(true);
+                }
+            }
+        }
+    };
+
+    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onServiceStateChanged(ServiceState serviceState) {
+            if (!mHasTelephony) return;
+            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
+            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
+            mAirplaneModeOn.updateState(mAirplaneState);
+            mAdapter.notifyDataSetChanged();
+        }
+    };
+
+    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
+            }
+        }
+    };
+
+    private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            onAirplaneModeChanged();
+        }
+    };
+
+    private static final int MESSAGE_DISMISS = 0;
+    private static final int MESSAGE_REFRESH = 1;
+    private static final int MESSAGE_SHOW = 2;
+    private static final int DIALOG_DISMISS_DELAY = 300; // ms
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MESSAGE_DISMISS:
+                if (mDialog != null) {
+                    mDialog.dismiss();
+                    mDialog = null;
+                }
+                break;
+            case MESSAGE_REFRESH:
+                refreshSilentMode();
+                mAdapter.notifyDataSetChanged();
+                break;
+            case MESSAGE_SHOW:
+                handleShow();
+                break;
+            }
+        }
+    };
+
+    private void onAirplaneModeChanged() {
+        // Let the service state callbacks handle the state.
+        if (mHasTelephony) return;
+
+        boolean airplaneModeOn = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                0) == 1;
+        mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
+        mAirplaneModeOn.updateState(mAirplaneState);
+    }
+
+    /**
+     * Change the airplane mode system setting
+     */
+    private void changeAirplaneModeSystemSetting(boolean on) {
+        Settings.Global.putInt(
+                mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON,
+                on ? 1 : 0);
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+        intent.putExtra("state", on);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        if (!mHasTelephony) {
+            mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
+        }
+    }
+
+    private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
+        private final Context mContext;
+        private final int mWindowTouchSlop;
+        private final AlertController mAlert;
+        private final MyAdapter mAdapter;
+
+        private EnableAccessibilityController mEnableAccessibilityController;
+
+        private boolean mIntercepted;
+        private boolean mCancelOnUp;
+
+        public GlobalActionsDialog(Context context, AlertParams params) {
+            super(context, getDialogTheme(context));
+            mContext = context;
+            mAlert = new AlertController(mContext, this, getWindow());
+            mAdapter = (MyAdapter) params.mAdapter;
+            mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
+            params.apply(mAlert);
+        }
+
+        private static int getDialogTheme(Context context) {
+            TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+                    outValue, true);
+            return outValue.resourceId;
+        }
+
+        @Override
+        protected void onStart() {
+            // If global accessibility gesture can be performed, we will take care
+            // of dismissing the dialog on touch outside. This is because the dialog
+            // is dismissed on the first down while the global gesture is a long press
+            // with two fingers anywhere on the screen.
+            if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
+                mEnableAccessibilityController = new EnableAccessibilityController(mContext,
+                        new Runnable() {
+                    @Override
+                    public void run() {
+                        dismiss();
+                    }
+                });
+                super.setCanceledOnTouchOutside(false);
+            } else {
+                mEnableAccessibilityController = null;
+                super.setCanceledOnTouchOutside(true);
+            }
+
+            super.onStart();
+        }
+
+        @Override
+        protected void onStop() {
+            if (mEnableAccessibilityController != null) {
+                mEnableAccessibilityController.onDestroy();
+            }
+            super.onStop();
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent event) {
+            if (mEnableAccessibilityController != null) {
+                final int action = event.getActionMasked();
+                if (action == MotionEvent.ACTION_DOWN) {
+                    View decor = getWindow().getDecorView();
+                    final int eventX = (int) event.getX();
+                    final int eventY = (int) event.getY();
+                    if (eventX < -mWindowTouchSlop
+                            || eventY < -mWindowTouchSlop
+                            || eventX >= decor.getWidth() + mWindowTouchSlop
+                            || eventY >= decor.getHeight() + mWindowTouchSlop) {
+                        mCancelOnUp = true;
+                    }
+                }
+                try {
+                    if (!mIntercepted) {
+                        mIntercepted = mEnableAccessibilityController.onInterceptTouchEvent(event);
+                        if (mIntercepted) {
+                            final long now = SystemClock.uptimeMillis();
+                            event = MotionEvent.obtain(now, now,
+                                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+                            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+                            mCancelOnUp = true;
+                        }
+                    } else {
+                        return mEnableAccessibilityController.onTouchEvent(event);
+                    }
+                } finally {
+                    if (action == MotionEvent.ACTION_UP) {
+                        if (mCancelOnUp) {
+                            cancel();
+                        }
+                        mCancelOnUp = false;
+                        mIntercepted = false;
+                    }
+                }
+            }
+            return super.dispatchTouchEvent(event);
+        }
+
+        public ListView getListView() {
+            return mAlert.getListView();
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mAlert.installContent();
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                for (int i = 0; i < mAdapter.getCount(); ++i) {
+                    CharSequence label =
+                            mAdapter.getItem(i).getLabelForAccessibility(getContext());
+                    if (label != null) {
+                        event.getText().add(label);
+                    }
+                }
+            }
+            return super.dispatchPopulateAccessibilityEvent(event);
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyDown(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (mAlert.onKeyUp(keyCode, event)) {
+                return true;
+            }
+            return super.onKeyUp(keyCode, event);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
new file mode 100644
index 0000000..e08c004
--- /dev/null
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -0,0 +1,145 @@
+/*
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Stores a mapping of global keys.
+ * <p>
+ * A global key will NOT go to the foreground application and instead only ever be sent via targeted
+ * broadcast to the specified component. The action of the intent will be
+ * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with
+ * {@link Intent#EXTRA_KEY_EVENT}.
+ */
+final class GlobalKeyManager {
+
+    private static final String TAG = "GlobalKeyManager";
+
+    private static final String TAG_GLOBAL_KEYS = "global_keys";
+    private static final String ATTR_VERSION = "version";
+    private static final String TAG_KEY = "key";
+    private static final String ATTR_KEY_CODE = "keyCode";
+    private static final String ATTR_COMPONENT = "component";
+
+    private static final int GLOBAL_KEY_FILE_VERSION = 1;
+
+    private SparseArray<ComponentName> mKeyMapping;
+
+    public GlobalKeyManager(Context context) {
+        mKeyMapping = new SparseArray<ComponentName>();
+        loadGlobalKeys(context);
+    }
+
+    /**
+     * Broadcasts an intent if the keycode is part of the global key mapping.
+     *
+     * @param context context used to broadcast the event
+     * @param keyCode keyCode which triggered this function
+     * @param event keyEvent which trigged this function
+     * @return {@code true} if this was handled
+     */
+    boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
+        if (mKeyMapping.size() > 0) {
+            ComponentName component = mKeyMapping.get(keyCode);
+            if (component != null) {
+                Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
+                        .setComponent(component)
+                        .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                        .putExtra(Intent.EXTRA_KEY_EVENT, event);
+                context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the key will be handled globally.
+     */
+    boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) {
+        return mKeyMapping.get(keyCode) != null;
+    }
+
+    private void loadGlobalKeys(Context context) {
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getXml(com.android.internal.R.xml.global_keys);
+            XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS);
+            int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
+            if (GLOBAL_KEY_FILE_VERSION == version) {
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (TAG_KEY.equals(element)) {
+                        String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
+                        String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
+                        int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
+                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            mKeyMapping.put(keyCode, ComponentName.unflattenFromString(
+                                    componentName));
+                        }
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "global keys file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading global keys file", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading global keys file", e);
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        final int numKeys = mKeyMapping.size();
+        if (numKeys == 0) {
+            pw.print(prefix); pw.println("mKeyMapping.size=0");
+            return;
+        }
+        pw.print(prefix); pw.println("mKeyMapping={");
+        for (int i = 0; i < numKeys; ++i) {
+            pw.print("  ");
+            pw.print(prefix);
+            pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i)));
+            pw.print("=");
+            pw.println(mKeyMapping.valueAt(i).flattenToString());
+        }
+        pw.print(prefix); pw.println("}");
+    }
+}
diff --git a/services/core/java/com/android/server/policy/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
new file mode 100644
index 0000000..4658344
--- /dev/null
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.TableMaskFilter;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.content.res.Resources;
+import android.content.Context;
+
+/**
+ * Various utilities shared amongst the Launcher's classes.
+ */
+final class IconUtilities {
+    private static final String TAG = "IconUtilities";
+
+    private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
+
+    private int mIconWidth = -1;
+    private int mIconHeight = -1;
+    private int mIconTextureWidth = -1;
+    private int mIconTextureHeight = -1;
+
+    private final Paint mPaint = new Paint();
+    private final Paint mBlurPaint = new Paint();
+    private final Paint mGlowColorPressedPaint = new Paint();
+    private final Paint mGlowColorFocusedPaint = new Paint();
+    private final Rect mOldBounds = new Rect();
+    private final Canvas mCanvas = new Canvas();
+    private final DisplayMetrics mDisplayMetrics;
+
+    private int mColorIndex = 0;
+
+    public IconUtilities(Context context) {
+        final Resources resources = context.getResources();
+        DisplayMetrics metrics = mDisplayMetrics = resources.getDisplayMetrics();
+        final float density = metrics.density;
+        final float blurPx = 5 * density;
+
+        mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
+        mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
+
+        mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
+
+        TypedValue value = new TypedValue();
+        mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
+                android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
+        mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
+        mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
+                android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
+        mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
+
+        ColorMatrix cm = new ColorMatrix();
+        cm.setSaturation(0.2f);
+
+        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+                Paint.FILTER_BITMAP_FLAG));
+    }
+
+    public Drawable createIconDrawable(Drawable src) {
+        Bitmap scaled = createIconBitmap(src);
+
+        StateListDrawable result = new StateListDrawable();
+
+        result.addState(new int[] { android.R.attr.state_focused },
+                new BitmapDrawable(createSelectedBitmap(scaled, false)));
+        result.addState(new int[] { android.R.attr.state_pressed },
+                new BitmapDrawable(createSelectedBitmap(scaled, true)));
+        result.addState(new int[0], new BitmapDrawable(scaled));
+
+        result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight);
+        return result;
+    }
+
+    /**
+     * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
+     * of two sized ARGB_8888 bitmap that can be used as a gl texture.
+     */
+    private Bitmap createIconBitmap(Drawable icon) {
+        int width = mIconWidth;
+        int height = mIconHeight;
+
+        if (icon instanceof PaintDrawable) {
+            PaintDrawable painter = (PaintDrawable) icon;
+            painter.setIntrinsicWidth(width);
+            painter.setIntrinsicHeight(height);
+        } else if (icon instanceof BitmapDrawable) {
+            // Ensure the bitmap has a density.
+            BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+            Bitmap bitmap = bitmapDrawable.getBitmap();
+            if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
+                bitmapDrawable.setTargetDensity(mDisplayMetrics);
+            }
+        }
+        int sourceWidth = icon.getIntrinsicWidth();
+        int sourceHeight = icon.getIntrinsicHeight();
+
+        if (sourceWidth > 0 && sourceHeight > 0) {
+            // There are intrinsic sizes.
+            if (width < sourceWidth || height < sourceHeight) {
+                // It's too big, scale it down.
+                final float ratio = (float) sourceWidth / sourceHeight;
+                if (sourceWidth > sourceHeight) {
+                    height = (int) (width / ratio);
+                } else if (sourceHeight > sourceWidth) {
+                    width = (int) (height * ratio);
+                }
+            } else if (sourceWidth < width && sourceHeight < height) {
+                // It's small, use the size they gave us.
+                width = sourceWidth;
+                height = sourceHeight;
+            }
+        }
+
+        // no intrinsic size --> use default size
+        int textureWidth = mIconTextureWidth;
+        int textureHeight = mIconTextureHeight;
+
+        final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
+                Bitmap.Config.ARGB_8888);
+        final Canvas canvas = mCanvas;
+        canvas.setBitmap(bitmap);
+
+        final int left = (textureWidth-width) / 2;
+        final int top = (textureHeight-height) / 2;
+
+        if (false) {
+            // draw a big box for the icon for debugging
+            canvas.drawColor(sColors[mColorIndex]);
+            if (++mColorIndex >= sColors.length) mColorIndex = 0;
+            Paint debugPaint = new Paint();
+            debugPaint.setColor(0xffcccc00);
+            canvas.drawRect(left, top, left+width, top+height, debugPaint);
+        }
+
+        mOldBounds.set(icon.getBounds());
+        icon.setBounds(left, top, left+width, top+height);
+        icon.draw(canvas);
+        icon.setBounds(mOldBounds);
+
+        return bitmap;
+    }
+
+    private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) {
+        final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight,
+                Bitmap.Config.ARGB_8888);
+        final Canvas dest = new Canvas(result);
+
+        dest.drawColor(0, PorterDuff.Mode.CLEAR);
+
+        int[] xy = new int[2];
+        Bitmap mask = src.extractAlpha(mBlurPaint, xy);
+
+        dest.drawBitmap(mask, xy[0], xy[1],
+                pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint);
+
+        mask.recycle();
+
+        dest.drawBitmap(src, 0, 0, mPaint);
+        dest.setBitmap(null);
+
+        return result;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
new file mode 100644
index 0000000..e720f3e
--- /dev/null
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -0,0 +1,349 @@
+/*
+ * 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.policy;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import com.android.internal.R;
+
+/**
+ *  Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
+ *  entering immersive mode.
+ */
+public class ImmersiveModeConfirmation {
+    private static final String TAG = "ImmersiveModeConfirmation";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
+    private static final String CONFIRMED = "confirmed";
+
+    private final Context mContext;
+    private final H mHandler;
+    private final long mShowDelayMs;
+    private final long mPanicThresholdMs;
+    private final SparseBooleanArray mUserPanicResets = new SparseBooleanArray();
+
+    private boolean mConfirmed;
+    private ClingWindowView mClingWindow;
+    private long mPanicTime;
+    private WindowManager mWindowManager;
+    private int mCurrentUserId;
+
+    public ImmersiveModeConfirmation(Context context) {
+        mContext = context;
+        mHandler = new H();
+        mShowDelayMs = getNavBarExitDuration() * 3;
+        mPanicThresholdMs = context.getResources()
+                .getInteger(R.integer.config_immersive_mode_confirmation_panic);
+        mWindowManager = (WindowManager)
+                mContext.getSystemService(Context.WINDOW_SERVICE);
+    }
+
+    private long getNavBarExitDuration() {
+        Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit);
+        return exit != null ? exit.getDuration() : 0;
+    }
+
+    public void loadSetting(int currentUserId) {
+        mConfirmed = false;
+        mCurrentUserId = currentUserId;
+        if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s",
+                mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false)));
+        String value = null;
+        try {
+            value = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
+                    UserHandle.USER_CURRENT);
+            mConfirmed = CONFIRMED.equals(value);
+            if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed);
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error loading confirmations, value=" + value, t);
+        }
+    }
+
+    private void saveSetting() {
+        if (DEBUG) Slog.d(TAG, "saveSetting()");
+        try {
+            final String value = mConfirmed ? CONFIRMED : null;
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
+                    value,
+                    UserHandle.USER_CURRENT);
+            if (DEBUG) Slog.d(TAG, "Saved value=" + value);
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t);
+        }
+    }
+
+    public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
+            boolean userSetupComplete) {
+        mHandler.removeMessages(H.SHOW);
+        if (isImmersiveMode) {
+            final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
+            if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
+                    disabled, mConfirmed));
+            if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) {
+                mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
+            }
+        } else {
+            mHandler.sendEmptyMessage(H.HIDE);
+        }
+    }
+
+    public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
+        if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
+            // turning the screen back on within the panic threshold
+            mHandler.sendEmptyMessage(H.PANIC);
+            return mClingWindow == null;
+        }
+        if (isScreenOn && inImmersiveMode) {
+            // turning the screen off, remember if we were in immersive mode
+            mPanicTime = time;
+        } else {
+            mPanicTime = 0;
+        }
+        return false;
+    }
+
+    public void confirmCurrentPrompt() {
+        if (mClingWindow != null) {
+            if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()");
+            mHandler.post(mConfirm);
+        }
+    }
+
+    private void handlePanic() {
+        if (DEBUG) Slog.d(TAG, "handlePanic()");
+        if (mUserPanicResets.get(mCurrentUserId, false)) return;  // already reset for panic
+        mUserPanicResets.put(mCurrentUserId, true);
+        mConfirmed = false;
+        saveSetting();
+    }
+
+    private void handleHide() {
+        if (mClingWindow != null) {
+            if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
+            mWindowManager.removeView(mClingWindow);
+            mClingWindow = null;
+        }
+    }
+
+    public WindowManager.LayoutParams getClingWindowLayoutParams() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                0
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                ,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.setTitle("ImmersiveModeConfirmation");
+        lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
+        return lp;
+    }
+
+    public FrameLayout.LayoutParams getBubbleLayoutParams() {
+        return new FrameLayout.LayoutParams(
+                mContext.getResources().getDimensionPixelSize(
+                        R.dimen.immersive_mode_cling_width),
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+    }
+
+    private class ClingWindowView extends FrameLayout {
+        private static final int BGCOLOR = 0x80000000;
+        private static final int OFFSET_DP = 96;
+        private static final int ANIMATION_DURATION = 250;
+
+        private final Runnable mConfirm;
+        private final ColorDrawable mColor = new ColorDrawable(0);
+        private final Interpolator mInterpolator;
+        private ValueAnimator mColorAnim;
+        private ViewGroup mClingLayout;
+
+        private Runnable mUpdateLayoutRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mClingLayout != null && mClingLayout.getParent() != null) {
+                    mClingLayout.setLayoutParams(getBubbleLayoutParams());
+                }
+            }
+        };
+
+        private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                    post(mUpdateLayoutRunnable);
+                }
+            }
+        };
+
+        public ClingWindowView(Context context, Runnable confirm) {
+            super(context);
+            mConfirm = confirm;
+            setBackground(mColor);
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+            mInterpolator = AnimationUtils
+                    .loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in);
+        }
+
+        @Override
+        public void onAttachedToWindow() {
+            super.onAttachedToWindow();
+
+            DisplayMetrics metrics = new DisplayMetrics();
+            mWindowManager.getDefaultDisplay().getMetrics(metrics);
+            float density = metrics.density;
+
+            // create the confirmation cling
+            mClingLayout = (ViewGroup)
+                    View.inflate(getContext(), R.layout.immersive_mode_cling, null);
+
+            final Button ok = (Button) mClingLayout.findViewById(R.id.ok);
+            ok.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mConfirm.run();
+                }
+            });
+            addView(mClingLayout, getBubbleLayoutParams());
+
+            if (ActivityManager.isHighEndGfx()) {
+                final View cling = mClingLayout;
+                cling.setAlpha(0f);
+                cling.setTranslationY(-OFFSET_DP * density);
+
+                postOnAnimation(new Runnable() {
+                    @Override
+                    public void run() {
+                        cling.animate()
+                                .alpha(1f)
+                                .translationY(0)
+                                .setDuration(ANIMATION_DURATION)
+                                .setInterpolator(mInterpolator)
+                                .withLayer()
+                                .start();
+
+                        mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR);
+                        mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                            @Override
+                            public void onAnimationUpdate(ValueAnimator animation) {
+                                final int c = (Integer) animation.getAnimatedValue();
+                                mColor.setColor(c);
+                            }
+                        });
+                        mColorAnim.setDuration(ANIMATION_DURATION);
+                        mColorAnim.setInterpolator(mInterpolator);
+                        mColorAnim.start();
+                    }
+                });
+            } else {
+                mColor.setColor(BGCOLOR);
+            }
+
+            mContext.registerReceiver(mReceiver,
+                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+        }
+
+        @Override
+        public void onDetachedFromWindow() {
+            mContext.unregisterReceiver(mReceiver);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent motion) {
+            return true;
+        }
+    }
+
+    private void handleShow() {
+        if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
+
+        mClingWindow = new ClingWindowView(mContext, mConfirm);
+
+        // we will be hiding the nav bar, so layout as if it's already hidden
+        mClingWindow.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+              | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+        // show the confirmation
+        WindowManager.LayoutParams lp = getClingWindowLayoutParams();
+        mWindowManager.addView(mClingWindow, lp);
+    }
+
+    private final Runnable mConfirm = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Slog.d(TAG, "mConfirm.run()");
+            if (!mConfirmed) {
+                mConfirmed = true;
+                saveSetting();
+            }
+            handleHide();
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int SHOW = 1;
+        private static final int HIDE = 2;
+        private static final int PANIC = 3;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case SHOW:
+                    handleShow();
+                    break;
+                case HIDE:
+                    handleHide();
+                    break;
+                case PANIC:
+                    handlePanic();
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.java
new file mode 100644
index 0000000..ed5dc6f
--- /dev/null
+++ b/services/core/java/com/android/server/policy/LogDecelerateInterpolator.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.server.policy;
+
+import android.view.animation.Interpolator;
+
+public class LogDecelerateInterpolator implements Interpolator {
+
+    private int mBase;
+    private int mDrift;
+    private final float mLogScale;
+
+    public LogDecelerateInterpolator(int base, int drift) {
+        mBase = base;
+        mDrift = drift;
+
+        mLogScale = 1f / computeLog(1, mBase, mDrift);
+    }
+
+    private static float computeLog(float t, int base, int drift) {
+        return (float) -Math.pow(base, -t) + 1 + (drift * t);
+    }
+
+    @Override
+    public float getInterpolation(float t) {
+        return computeLog(t, mBase, mDrift) * mLogScale;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
new file mode 100644
index 0000000..cdd6c7f
--- /dev/null
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -0,0 +1,6502 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.AppOpsManager;
+import android.app.IUiModeManager;
+import android.app.ProgressDialog;
+import android.app.SearchManager;
+import android.app.StatusBarManager;
+import android.app.UiModeManager;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.media.session.MediaSessionLegacyHelper;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.FactoryTest;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UEventObserver;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.speech.RecognizerIntent;
+import android.telecom.TelecomManager;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
+import android.view.IApplicationToken;
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyCharacterMap;
+import android.view.KeyCharacterMap.FallbackAction;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.PhoneWindow;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerInternal;
+import android.view.WindowManagerPolicy;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.AnimationUtils;
+import com.android.internal.R;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.widget.PointerLocationView;
+import com.android.server.LocalServices;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate;
+import com.android.server.policy.keyguard.KeyguardServiceDelegate.ShowListener;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.List;
+
+import static android.view.WindowManager.LayoutParams.*;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
+
+/**
+ * WindowManagerPolicy implementation for the Android phone UI.  This
+ * introduces a new method suffix, Lp, for an internal lock of the
+ * PhoneWindowManager.  This is used to protect some internal state, and
+ * can be acquired with either the Lw and Li lock held, so has the restrictions
+ * of both of those when held.
+ */
+public class PhoneWindowManager implements WindowManagerPolicy {
+    static final String TAG = "WindowManager";
+    static final boolean DEBUG = false;
+    static final boolean localLOGV = false;
+    static final boolean DEBUG_INPUT = false;
+    static final boolean DEBUG_KEYGUARD = false;
+    static final boolean DEBUG_LAYOUT = false;
+    static final boolean DEBUG_STARTING_WINDOW = false;
+    static final boolean DEBUG_WAKEUP = false;
+    static final boolean SHOW_STARTING_ANIMATIONS = true;
+    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
+
+    // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
+    // No longer recommended for desk docks; still useful in car docks.
+    static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
+    static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+
+    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;
+    static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
+    static final int SHORT_PRESS_POWER_GO_HOME = 4;
+
+    static final int LONG_PRESS_POWER_NOTHING = 0;
+    static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
+    static final int LONG_PRESS_POWER_SHUT_OFF = 2;
+    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
+
+    static final int MULTI_PRESS_POWER_NOTHING = 0;
+    static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
+    static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
+
+    // These need to match the documentation/constant in
+    // core/res/res/values/config.xml
+    static final int LONG_PRESS_HOME_NOTHING = 0;
+    static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 1;
+    static final int LONG_PRESS_HOME_ASSIST = 2;
+
+    static final int DOUBLE_TAP_HOME_NOTHING = 0;
+    static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
+
+    static final int APPLICATION_MEDIA_SUBLAYER = -2;
+    static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
+    static final int APPLICATION_PANEL_SUBLAYER = 1;
+    static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
+
+    static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
+    static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
+    static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+    static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
+    static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
+
+    /**
+     * These are the system UI flags that, when changing, can cause the layout
+     * of the screen to change.
+     */
+    static final int SYSTEM_UI_CHANGING_LAYOUT =
+              View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+            | View.SYSTEM_UI_FLAG_FULLSCREEN
+            | View.STATUS_BAR_TRANSLUCENT
+            | View.NAVIGATION_BAR_TRANSLUCENT
+            | View.SYSTEM_UI_TRANSPARENT;
+
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
+
+    /**
+     * Keyguard stuff
+     */
+    private WindowState mKeyguardScrim;
+    private boolean mKeyguardHidden;
+    private boolean mKeyguardDrawnOnce;
+
+    /* Table of Application Launch keys.  Maps from key codes to intent categories.
+     *
+     * These are special keys that are used to launch particular kinds of applications,
+     * such as a web browser.  HID defines nearly a hundred of them in the Consumer (0x0C)
+     * usage page.  We don't support quite that many yet...
+     */
+    static SparseArray<String> sApplicationLaunchKeyCategories;
+    static {
+        sApplicationLaunchKeyCategories = new SparseArray<String>();
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC);
+        sApplicationLaunchKeyCategories.append(
+                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
+    }
+
+    /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
+    static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
+
+    /**
+     * Lock protecting internal state.  Must not call out into window
+     * manager with lock held.  (This lock will be acquired in places
+     * where the window manager is calling in with its own lock held.)
+     */
+    private final Object mLock = new Object();
+
+    Context mContext;
+    IWindowManager mWindowManager;
+    WindowManagerFuncs mWindowManagerFuncs;
+    WindowManagerInternal mWindowManagerInternal;
+    PowerManager mPowerManager;
+    DreamManagerInternal mDreamManagerInternal;
+    IStatusBarService mStatusBarService;
+    boolean mPreloadedRecentApps;
+    final Object mServiceAquireLock = new Object();
+    Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
+    SearchManager mSearchManager;
+    AccessibilityManager mAccessibilityManager;
+    BurnInProtectionHelper mBurnInProtectionHelper;
+
+    // Vibrator pattern for haptic feedback of a long press.
+    long[] mLongPressVibePattern;
+
+    // Vibrator pattern for haptic feedback of virtual key press.
+    long[] mVirtualKeyVibePattern;
+
+    // Vibrator pattern for a short vibration.
+    long[] mKeyboardTapVibePattern;
+
+    // Vibrator pattern for a short vibration when tapping on an hour/minute tick of a Clock.
+    long[] mClockTickVibePattern;
+
+    // Vibrator pattern for a short vibration when tapping on a day/month/year date of a Calendar.
+    long[] mCalendarDateVibePattern;
+
+    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
+    long[] mSafeModeDisabledVibePattern;
+
+    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
+    long[] mSafeModeEnabledVibePattern;
+
+    /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
+    boolean mEnableShiftMenuBugReports = false;
+
+    boolean mSafeMode;
+    WindowState mStatusBar = null;
+    int mStatusBarHeight;
+    WindowState mNavigationBar = null;
+    boolean mHasNavigationBar = false;
+    boolean mCanHideNavigationBar = false;
+    boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
+    boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*?
+    int[] mNavigationBarHeightForRotation = new int[4];
+    int[] mNavigationBarWidthForRotation = new int[4];
+
+    boolean mBootMessageNeedsHiding;
+    KeyguardServiceDelegate mKeyguardDelegate;
+    final Runnable mWindowManagerDrawCallback = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
+            mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);
+        }
+    };
+    final ShowListener mKeyguardDelegateCallback = new ShowListener() {
+        @Override
+        public void onShown(IBinder windowToken) {
+            if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onShown.");
+            mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+        }
+    };
+
+    GlobalActions mGlobalActions;
+    Handler mHandler;
+    WindowState mLastInputMethodWindow = null;
+    WindowState mLastInputMethodTargetWindow = null;
+
+    // FIXME This state is shared between the input reader and handler thread.
+    // Technically it's broken and buggy but it has been like this for many years
+    // and we have not yet seen any problems.  Someday we'll rewrite this logic
+    // so that only one thread is involved in handling input policy.  Unfortunately
+    // it's on a critical path for power management so we can't just post the work to the
+    // handler thread.  We'll need to resolve this someday by teaching the input dispatcher
+    // to hold wakelocks during dispatch and eliminating the critical path.
+    volatile boolean mPowerKeyHandled;
+    volatile boolean mBeganFromNonInteractive;
+    volatile int mPowerKeyPressCounter;
+    volatile boolean mEndCallKeyHandled;
+
+    boolean mRecentsVisible;
+    int mRecentAppsHeldModifiers;
+    boolean mLanguageSwitchKeyPressed;
+
+    int mLidState = LID_ABSENT;
+    int mCameraLensCoverState = CAMERA_LENS_COVER_ABSENT;
+    boolean mHaveBuiltInKeyboard;
+
+    boolean mSystemReady;
+    boolean mSystemBooted;
+    boolean mHdmiPlugged;
+    IUiModeManager mUiModeManager;
+    int mUiMode;
+    int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    int mLidOpenRotation;
+    int mCarDockRotation;
+    int mDeskDockRotation;
+    int mUndockedHdmiRotation;
+    int mDemoHdmiRotation;
+    boolean mDemoHdmiRotationLock;
+    int mDemoRotation;
+    boolean mDemoRotationLock;
+
+    boolean mWakeGestureEnabledSetting;
+    MyWakeGestureListener mWakeGestureListener;
+
+    // Default display does not rotate, apps that require non-default orientation will have to
+    // have the orientation emulated.
+    private boolean mForceDefaultOrientation = false;
+
+    int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
+    int mUserRotation = Surface.ROTATION_0;
+    boolean mAccelerometerDefault;
+
+    boolean mSupportAutoRotation;
+    int mAllowAllRotations = -1;
+    boolean mCarDockEnablesAccelerometer;
+    boolean mDeskDockEnablesAccelerometer;
+    int mLidKeyboardAccessibility;
+    int mLidNavigationAccessibility;
+    boolean mLidControlsSleep;
+    int mShortPressOnPowerBehavior;
+    int mLongPressOnPowerBehavior;
+    int mDoublePressOnPowerBehavior;
+    int mTriplePressOnPowerBehavior;
+    boolean mAwake;
+    boolean mScreenOnEarly;
+    boolean mScreenOnFully;
+    ScreenOnListener mScreenOnListener;
+    boolean mKeyguardDrawComplete;
+    boolean mWindowManagerDrawComplete;
+    boolean mOrientationSensorEnabled = false;
+    int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    boolean mHasSoftInput = false;
+    boolean mTranslucentDecorEnabled = true;
+    boolean mUseTvRouting;
+
+    int mPointerLocationMode = 0; // guarded by mLock
+
+    // The last window we were told about in focusChanged.
+    WindowState mFocusedWindow;
+    IApplicationToken mFocusedApp;
+
+    PointerLocationView mPointerLocationView;
+
+    // The current size of the screen; really; extends into the overscan area of
+    // the screen and doesn't account for any system elements like the status bar.
+    int mOverscanScreenLeft, mOverscanScreenTop;
+    int mOverscanScreenWidth, mOverscanScreenHeight;
+    // The current visible size of the screen; really; (ir)regardless of whether the status
+    // bar can be hidden but not extending into the overscan area.
+    int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
+    int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
+    // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate.
+    int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop;
+    int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight;
+    // The current size of the screen; these may be different than (0,0)-(dw,dh)
+    // if the status bar can't be hidden; in that case it effectively carves out
+    // that area of the display from all other windows.
+    int mRestrictedScreenLeft, mRestrictedScreenTop;
+    int mRestrictedScreenWidth, mRestrictedScreenHeight;
+    // During layout, the current screen borders accounting for any currently
+    // visible system UI elements.
+    int mSystemLeft, mSystemTop, mSystemRight, mSystemBottom;
+    // For applications requesting stable content insets, these are them.
+    int mStableLeft, mStableTop, mStableRight, mStableBottom;
+    // For applications requesting stable content insets but have also set the
+    // fullscreen window flag, these are the stable dimensions without the status bar.
+    int mStableFullscreenLeft, mStableFullscreenTop;
+    int mStableFullscreenRight, mStableFullscreenBottom;
+    // During layout, the current screen borders with all outer decoration
+    // (status bar, input method dock) accounted for.
+    int mCurLeft, mCurTop, mCurRight, mCurBottom;
+    // During layout, the frame in which content should be displayed
+    // to the user, accounting for all screen decoration except for any
+    // space they deem as available for other content.  This is usually
+    // the same as mCur*, but may be larger if the screen decor has supplied
+    // content insets.
+    int mContentLeft, mContentTop, mContentRight, mContentBottom;
+    // During layout, the frame in which voice content should be displayed
+    // to the user, accounting for all screen decoration except for any
+    // space they deem as available for other content.
+    int mVoiceContentLeft, mVoiceContentTop, mVoiceContentRight, mVoiceContentBottom;
+    // During layout, the current screen borders along which input method
+    // windows are placed.
+    int mDockLeft, mDockTop, mDockRight, mDockBottom;
+    // During layout, the layer at which the doc window is placed.
+    int mDockLayer;
+    // During layout, this is the layer of the status bar.
+    int mStatusBarLayer;
+    int mLastSystemUiFlags;
+    // Bits that we are in the process of clearing, so we want to prevent
+    // them from being set by applications until everything has been updated
+    // to have them clear.
+    int mResettingSystemUiFlags = 0;
+    // Bits that we are currently always keeping cleared.
+    int mForceClearedSystemUiFlags = 0;
+    // What we last reported to system UI about whether the compatibility
+    // menu needs to be displayed.
+    boolean mLastFocusNeedsMenu = false;
+
+    FakeWindow mHideNavFakeWindow = null;
+
+    static final Rect mTmpParentFrame = new Rect();
+    static final Rect mTmpDisplayFrame = new Rect();
+    static final Rect mTmpOverscanFrame = new Rect();
+    static final Rect mTmpContentFrame = new Rect();
+    static final Rect mTmpVisibleFrame = new Rect();
+    static final Rect mTmpDecorFrame = new Rect();
+    static final Rect mTmpStableFrame = new Rect();
+    static final Rect mTmpNavigationFrame = new Rect();
+
+    WindowState mTopFullscreenOpaqueWindowState;
+    WindowState mTopFullscreenOpaqueOrDimmingWindowState;
+    HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
+    HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
+    boolean mTopIsFullscreen;
+    boolean mForceStatusBar;
+    boolean mForceStatusBarFromKeyguard;
+    boolean mHideLockScreen;
+    boolean mForcingShowNavBar;
+    int mForcingShowNavBarLayer;
+
+    // States of keyguard dismiss.
+    private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
+    private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
+    private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
+    int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+
+    /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
+     * 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;
+    boolean mKeyguardSecure;
+    boolean mKeyguardSecureIncludingHidden;
+    volatile boolean mKeyguardOccluded;
+    boolean mHomePressed;
+    boolean mHomeConsumed;
+    boolean mHomeDoubleTapPending;
+    Intent mHomeIntent;
+    Intent mCarDockIntent;
+    Intent mDeskDockIntent;
+    boolean mSearchKeyShortcutPending;
+    boolean mConsumeSearchKeyUp;
+    boolean mAssistKeyLongPressed;
+    boolean mPendingMetaAction;
+
+    // support for activating the lock screen while the screen is on
+    boolean mAllowLockscreenWhenOn;
+    int mLockScreenTimeout;
+    boolean mLockScreenTimerActive;
+
+    // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
+    int mEndcallBehavior;
+
+    // Behavior of POWER button while in-call and screen on.
+    // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
+    int mIncallPowerBehavior;
+
+    Display mDisplay;
+
+    int mLandscapeRotation = 0;  // default landscape rotation
+    int mSeascapeRotation = 0;   // "other" landscape rotation, 180 degrees from mLandscapeRotation
+    int mPortraitRotation = 0;   // default portrait rotation
+    int mUpsideDownRotation = 0; // "other" portrait rotation
+
+    int mOverscanLeft = 0;
+    int mOverscanTop = 0;
+    int mOverscanRight = 0;
+    int mOverscanBottom = 0;
+
+    // What we do when the user long presses on home
+    private int mLongPressOnHomeBehavior;
+
+    // What we do when the user double-taps on home
+    private int mDoubleTapOnHomeBehavior;
+
+    // Allowed theater mode wake actions
+    private boolean mAllowTheaterModeWakeFromKey;
+    private boolean mAllowTheaterModeWakeFromPowerKey;
+    private boolean mAllowTheaterModeWakeFromMotion;
+    private boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming;
+    private boolean mAllowTheaterModeWakeFromCameraLens;
+    private boolean mAllowTheaterModeWakeFromLidSwitch;
+    private boolean mAllowTheaterModeWakeFromWakeGesture;
+
+    // Whether to support long press from power button in non-interactive mode
+    private boolean mSupportLongPressPowerWhenNonInteractive;
+
+    // Whether to go to sleep entering theater mode from power button
+    private boolean mGoToSleepOnButtonPressTheaterMode;
+
+    // Screenshot trigger states
+    // Time to volume and power must be pressed within this interval of each other.
+    private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
+    // Increase the chord delay when taking a screenshot from the keyguard
+    private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
+    private boolean mScreenshotChordEnabled;
+    private boolean mScreenshotChordVolumeDownKeyTriggered;
+    private long mScreenshotChordVolumeDownKeyTime;
+    private boolean mScreenshotChordVolumeDownKeyConsumed;
+    private boolean mScreenshotChordVolumeUpKeyTriggered;
+    private boolean mScreenshotChordPowerKeyTriggered;
+    private long mScreenshotChordPowerKeyTime;
+
+    /* The number of steps between min and max brightness */
+    private static final int BRIGHTNESS_STEPS = 10;
+
+    SettingsObserver mSettingsObserver;
+    ShortcutManager mShortcutManager;
+    PowerManager.WakeLock mBroadcastWakeLock;
+    PowerManager.WakeLock mPowerKeyWakeLock;
+    boolean mHavePendingMediaKeyRepeatWithWakeLock;
+
+    private int mCurrentUserId;
+
+    // Maps global key codes to the components that will handle them.
+    private GlobalKeyManager mGlobalKeyManager;
+
+    // Fallback actions by key code.
+    private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
+            new SparseArray<KeyCharacterMap.FallbackAction>();
+
+    private final LogDecelerateInterpolator mLogDecelerateInterpolator
+            = new LogDecelerateInterpolator(100, 0);
+
+    private static final int MSG_ENABLE_POINTER_LOCATION = 1;
+    private static final int MSG_DISABLE_POINTER_LOCATION = 2;
+    private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
+    private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
+    private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
+    private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6;
+    private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7;
+    private static final int MSG_DISPATCH_SHOW_RECENTS = 9;
+    private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
+    private static final int MSG_HIDE_BOOT_MESSAGE = 11;
+    private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
+    private static final int MSG_POWER_DELAYED_PRESS = 13;
+    private static final int MSG_POWER_LONG_PRESS = 14;
+
+    private class PolicyHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ENABLE_POINTER_LOCATION:
+                    enablePointerLocation();
+                    break;
+                case MSG_DISABLE_POINTER_LOCATION:
+                    disablePointerLocation();
+                    break;
+                case MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK:
+                    dispatchMediaKeyWithWakeLock((KeyEvent)msg.obj);
+                    break;
+                case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK:
+                    dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj);
+                    break;
+                case MSG_DISPATCH_SHOW_RECENTS:
+                    showRecentApps(false);
+                    break;
+                case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS:
+                    showGlobalActionsInternal();
+                    break;
+                case MSG_KEYGUARD_DRAWN_COMPLETE:
+                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete");
+                    finishKeyguardDrawn();
+                    break;
+                case MSG_KEYGUARD_DRAWN_TIMEOUT:
+                    Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
+                    finishKeyguardDrawn();
+                    break;
+                case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
+                    if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
+                    finishWindowsDrawn();
+                    break;
+                case MSG_HIDE_BOOT_MESSAGE:
+                    handleHideBootMessage();
+                    break;
+                case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
+                    launchVoiceAssistWithWakeLock(msg.arg1 != 0);
+                    break;
+                case MSG_POWER_DELAYED_PRESS:
+                    powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
+                    finishPowerKeyPress();
+                    break;
+                case MSG_POWER_LONG_PRESS:
+                    powerLongPress();
+                    break;
+            }
+        }
+    }
+
+    private UEventObserver mHDMIObserver = new UEventObserver() {
+        @Override
+        public void onUEvent(UEventObserver.UEvent event) {
+            setHdmiPlugged("1".equals(event.get("SWITCH_STATE")));
+        }
+    };
+
+    class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        void observe() {
+            // Observe all users' changes
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.END_BUTTON_BEHAVIOR), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.ACCELEROMETER_ROTATION), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.USER_ROTATION), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_OFF_TIMEOUT), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.POINTER_LOCATION), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.POLICY_CONTROL), false, this,
+                    UserHandle.USER_ALL);
+            updateSettings();
+        }
+
+        @Override public void onChange(boolean selfChange) {
+            updateSettings();
+            updateRotation(false);
+        }
+    }
+
+    class MyWakeGestureListener extends WakeGestureListener {
+        MyWakeGestureListener(Context context, Handler handler) {
+            super(context, handler);
+        }
+
+        @Override
+        public void onWakeUp() {
+            synchronized (mLock) {
+                if (shouldEnableWakeGestureLp()) {
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+                    wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture);
+                }
+            }
+        }
+    }
+
+    class MyOrientationListener extends WindowOrientationListener {
+        MyOrientationListener(Context context, Handler handler) {
+            super(context, handler);
+        }
+
+        @Override
+        public void onProposedRotationChanged(int rotation) {
+            if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
+            updateRotation(false);
+        }
+    }
+    MyOrientationListener mOrientationListener;
+
+    private final StatusBarController mStatusBarController = new StatusBarController();
+
+    private final BarController mNavigationBarController = new BarController("NavigationBar",
+            View.NAVIGATION_BAR_TRANSIENT,
+            View.NAVIGATION_BAR_UNHIDE,
+            View.NAVIGATION_BAR_TRANSLUCENT,
+            StatusBarManager.WINDOW_NAVIGATION_BAR,
+            WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+
+    private ImmersiveModeConfirmation mImmersiveModeConfirmation;
+
+    private SystemGesturesPointerEventListener mSystemGestures;
+
+    IStatusBarService getStatusBarService() {
+        synchronized (mServiceAquireLock) {
+            if (mStatusBarService == null) {
+                mStatusBarService = IStatusBarService.Stub.asInterface(
+                        ServiceManager.getService("statusbar"));
+            }
+            return mStatusBarService;
+        }
+    }
+
+    /*
+     * We always let the sensor be switched on by default except when
+     * the user has explicitly disabled sensor based rotation or when the
+     * screen is switched off.
+     */
+    boolean needSensorRunningLp() {
+        if (mSupportAutoRotation) {
+            if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
+                // If the application has explicitly requested to follow the
+                // orientation, then we need to turn the sensor on.
+                return true;
+            }
+        }
+        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
+                (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+                        || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
+                        || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
+            // enable accelerometer if we are docked in a dock that enables accelerometer
+            // orientation management,
+            return true;
+        }
+        if (mUserRotationMode == USER_ROTATION_LOCKED) {
+            // If the setting for using the sensor by default is enabled, then
+            // we will always leave it on.  Note that the user could go to
+            // a window that forces an orientation that does not use the
+            // sensor and in theory we could turn it off... however, when next
+            // turning it on we won't have a good value for the current
+            // orientation for a little bit, which can cause orientation
+            // changes to lag, so we'd like to keep it always on.  (It will
+            // still be turned off when the screen is off.)
+            return false;
+        }
+        return mSupportAutoRotation;
+    }
+
+    /*
+     * Various use cases for invoking this function
+     * screen turning off, should always disable listeners if already enabled
+     * screen turned on and current app has sensor based orientation, enable listeners
+     * if not already enabled
+     * screen turned on and current app does not have sensor orientation, disable listeners if
+     * already enabled
+     * screen turning on and current app has sensor based orientation, enable listeners if needed
+     * screen turning on and current app has nosensor based orientation, do nothing
+     */
+    void updateOrientationListenerLp() {
+        if (!mOrientationListener.canDetectOrientation()) {
+            // If sensor is turned off or nonexistent for some reason
+            return;
+        }
+        //Could have been invoked due to screen turning on or off or
+        //change of the currently visible window's orientation
+        if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly
+                + ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation
+                + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled);
+        boolean disable = true;
+        if (mScreenOnEarly && mAwake) {
+            if (needSensorRunningLp()) {
+                disable = false;
+                //enable listener if not already enabled
+                if (!mOrientationSensorEnabled) {
+                    mOrientationListener.enable();
+                    if(localLOGV) Slog.v(TAG, "Enabling listeners");
+                    mOrientationSensorEnabled = true;
+                }
+            }
+        }
+        //check if sensors need to be disabled
+        if (disable && mOrientationSensorEnabled) {
+            mOrientationListener.disable();
+            if(localLOGV) Slog.v(TAG, "Disabling listeners");
+            mOrientationSensorEnabled = false;
+        }
+    }
+
+    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
+        // Hold a wake lock until the power key is released.
+        if (!mPowerKeyWakeLock.isHeld()) {
+            mPowerKeyWakeLock.acquire();
+        }
+
+        // Cancel multi-press detection timeout.
+        if (mPowerKeyPressCounter != 0) {
+            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
+        }
+
+        // Detect user pressing the power button in panic when an application has
+        // taken over the whole screen.
+        boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
+                SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags));
+        if (panic) {
+            mHandler.post(mRequestTransientNav);
+        }
+
+        // Latch power key state to detect screenshot chord.
+        if (interactive && !mScreenshotChordPowerKeyTriggered
+                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+            mScreenshotChordPowerKeyTriggered = true;
+            mScreenshotChordPowerKeyTime = event.getDownTime();
+            interceptScreenshotChord();
+        }
+
+        // Stop ringing or end call if configured to do so when power is pressed.
+        TelecomManager telecomManager = getTelecommService();
+        boolean hungUp = false;
+        if (telecomManager != null) {
+            if (telecomManager.isRinging()) {
+                // Pressing Power while there's a ringing incoming
+                // call should silence the ringer.
+                telecomManager.silenceRinger();
+            } else if ((mIncallPowerBehavior
+                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+                    && telecomManager.isInCall() && interactive) {
+                // Otherwise, if "Power button ends call" is enabled,
+                // the Power button will hang up any current active call.
+                hungUp = telecomManager.endCall();
+            }
+        }
+
+        // If the power key has still not yet been handled, then detect short
+        // press, long press, or multi press and decide what to do.
+        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
+                || mScreenshotChordVolumeUpKeyTriggered;
+        if (!mPowerKeyHandled) {
+            if (interactive) {
+                // When interactive, we're already awake.
+                // Wait for a long press or for the button to be released to decide what to do.
+                if (hasLongPressOnPowerBehavior()) {
+                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg,
+                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                }
+            } else {
+                wakeUpFromPowerKey(event.getDownTime());
+
+                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
+                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg,
+                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                    mBeganFromNonInteractive = true;
+                } else {
+                    final int maxCount = getMaxMultiPressPowerCount();
+
+                    if (maxCount <= 1) {
+                        mPowerKeyHandled = true;
+                    } else {
+                        mBeganFromNonInteractive = true;
+                    }
+                }
+            }
+        }
+    }
+
+    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
+        final boolean handled = canceled || mPowerKeyHandled;
+        mScreenshotChordPowerKeyTriggered = false;
+        cancelPendingScreenshotChordAction();
+        cancelPendingPowerKeyAction();
+
+        if (!handled) {
+            // Figure out how to handle the key now that it has been released.
+            mPowerKeyPressCounter += 1;
+
+            final int maxCount = getMaxMultiPressPowerCount();
+            final long eventTime = event.getDownTime();
+            if (mPowerKeyPressCounter < maxCount) {
+                // This could be a multi-press.  Wait a little bit longer to confirm.
+                // Continue holding the wake lock.
+                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
+                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
+                return;
+            }
+
+            // No other actions.  Handle it immediately.
+            powerPress(eventTime, interactive, mPowerKeyPressCounter);
+        }
+
+        // Done.  Reset our state.
+        finishPowerKeyPress();
+    }
+
+    private void finishPowerKeyPress() {
+        mBeganFromNonInteractive = false;
+        mPowerKeyPressCounter = 0;
+        if (mPowerKeyWakeLock.isHeld()) {
+            mPowerKeyWakeLock.release();
+        }
+    }
+
+    private void cancelPendingPowerKeyAction() {
+        if (!mPowerKeyHandled) {
+            mPowerKeyHandled = true;
+            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
+        }
+    }
+
+    private void powerPress(long eventTime, boolean interactive, int count) {
+        if (mScreenOnEarly && !mScreenOnFully) {
+            Slog.i(TAG, "Suppressed redundant power key press while "
+                    + "already in the process of turning the screen on.");
+            return;
+        }
+
+        if (count == 2) {
+            powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
+        } else if (count == 3) {
+            powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
+        } else if (interactive && !mBeganFromNonInteractive) {
+            switch (mShortPressOnPowerBehavior) {
+                case SHORT_PRESS_POWER_NOTHING:
+                    break;
+                case SHORT_PRESS_POWER_GO_TO_SLEEP:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                    break;
+                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+                    break;
+                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+                    launchHomeFromHotKey();
+                    break;
+                case SHORT_PRESS_POWER_GO_HOME:
+                    launchHomeFromHotKey();
+                    break;
+            }
+        }
+    }
+
+    private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) {
+        switch (behavior) {
+            case MULTI_PRESS_POWER_NOTHING:
+                break;
+            case MULTI_PRESS_POWER_THEATER_MODE:
+                if (isTheaterModeEnabled()) {
+                    Slog.i(TAG, "Toggling theater mode off.");
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 0);
+                    if (!interactive) {
+                        wakeUpFromPowerKey(eventTime);
+                    }
+                } else {
+                    Slog.i(TAG, "Toggling theater mode on.");
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 1);
+
+                    if (mGoToSleepOnButtonPressTheaterMode && interactive) {
+                        mPowerManager.goToSleep(eventTime,
+                                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                    }
+                }
+                break;
+            case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
+                Slog.i(TAG, "Starting brightness boost.");
+                if (!interactive) {
+                    wakeUpFromPowerKey(eventTime);
+                }
+                mPowerManager.boostScreenBrightness(eventTime);
+                break;
+        }
+    }
+
+    private int getMaxMultiPressPowerCount() {
+        if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
+            return 3;
+        }
+        if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
+            return 2;
+        }
+        return 1;
+    }
+
+    private void powerLongPress() {
+        final int behavior = getResolvedLongPressOnPowerBehavior();
+        switch (behavior) {
+        case LONG_PRESS_POWER_NOTHING:
+            break;
+        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+            mPowerKeyHandled = true;
+            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
+                performAuditoryFeedbackForAccessibilityIfNeed();
+            }
+            showGlobalActionsInternal();
+            break;
+        case LONG_PRESS_POWER_SHUT_OFF:
+        case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
+            mPowerKeyHandled = true;
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
+            break;
+        }
+    }
+
+    private int getResolvedLongPressOnPowerBehavior() {
+        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
+            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
+        }
+        return mLongPressOnPowerBehavior;
+    }
+
+    private boolean hasLongPressOnPowerBehavior() {
+        return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
+    }
+
+    private void interceptScreenshotChord() {
+        if (mScreenshotChordEnabled
+                && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
+                && !mScreenshotChordVolumeUpKeyTriggered) {
+            final long now = SystemClock.uptimeMillis();
+            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mScreenshotChordPowerKeyTime
+                            + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mScreenshotChordVolumeDownKeyConsumed = true;
+                cancelPendingPowerKeyAction();
+
+                mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
+            }
+        }
+    }
+
+    private long getScreenshotChordLongPressDelay() {
+        if (mKeyguardDelegate.isShowing()) {
+            // Double the time it takes to take a screenshot from the keyguard
+            return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+        }
+        return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
+    }
+
+    private void cancelPendingScreenshotChordAction() {
+        mHandler.removeCallbacks(mScreenshotRunnable);
+    }
+
+    private final Runnable mEndCallLongPress = new Runnable() {
+        @Override
+        public void run() {
+            mEndCallKeyHandled = true;
+            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
+                performAuditoryFeedbackForAccessibilityIfNeed();
+            }
+            showGlobalActionsInternal();
+        }
+    };
+
+    private final Runnable mScreenshotRunnable = new Runnable() {
+        @Override
+        public void run() {
+            takeScreenshot();
+        }
+    };
+
+    @Override
+    public void showGlobalActions() {
+        mHandler.removeMessages(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
+        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
+    }
+
+    void showGlobalActionsInternal() {
+        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+        if (mGlobalActions == null) {
+            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
+        }
+        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
+        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
+        if (keyguardShowing) {
+            // since it took two seconds of long press to bring this up,
+            // poke the wake lock so they have some time to see the dialog.
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+        }
+    }
+
+    boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    boolean isUserSetupComplete() {
+        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    private void handleShortPressOnHome() {
+        // If there's a dream running then use home to escape the dream
+        // but don't actually go home.
+        if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
+            mDreamManagerInternal.stopDream(false /*immediate*/);
+            return;
+        }
+
+        // Go home!
+        launchHomeFromHotKey();
+    }
+
+    private void handleLongPressOnHome() {
+        if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
+            mHomeConsumed = true;
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+
+            if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
+                toggleRecentApps();
+            } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST) {
+                launchAssistAction();
+            }
+        }
+    }
+
+    private void handleDoubleTapOnHome() {
+        if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+            mHomeConsumed = true;
+            toggleRecentApps();
+        }
+    }
+
+    private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mHomeDoubleTapPending) {
+                mHomeDoubleTapPending = false;
+                handleShortPressOnHome();
+            }
+        }
+    };
+
+    private boolean isRoundWindow() {
+        return mContext.getResources().getBoolean(com.android.internal.R.bool.config_windowIsRound)
+                || (Build.HARDWARE.contains("goldfish")
+                && SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false));
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void init(Context context, IWindowManager windowManager,
+            WindowManagerFuncs windowManagerFuncs) {
+        mContext = context;
+        mWindowManager = windowManager;
+        mWindowManagerFuncs = windowManagerFuncs;
+        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+        mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+
+        // Init display burn-in protection
+        boolean burnInProtectionEnabled = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableBurnInProtection);
+        // Allow a system property to override this. Used by developer settings.
+        boolean burnInProtectionDevMode =
+                SystemProperties.getBoolean("persist.debug.force_burn_in", false);
+        if (burnInProtectionEnabled || burnInProtectionDevMode) {
+            final int minHorizontal;
+            final int maxHorizontal;
+            final int minVertical;
+            final int maxVertical;
+            final int maxRadius;
+            if (burnInProtectionDevMode) {
+                minHorizontal = -8;
+                maxHorizontal = 8;
+                minVertical = -8;
+                maxVertical = -4;
+                maxRadius = (isRoundWindow()) ? 6 : -1;
+            } else {
+                Resources resources = context.getResources();
+                minHorizontal = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+                maxHorizontal = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+                minVertical = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+                maxVertical = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+                maxRadius = resources.getInteger(
+                        com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+            }
+            mBurnInProtectionHelper = new BurnInProtectionHelper(
+                    context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius);
+        }
+
+        mHandler = new PolicyHandler();
+        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
+        mOrientationListener = new MyOrientationListener(mContext, mHandler);
+        try {
+            mOrientationListener.setCurrentRotation(windowManager.getRotation());
+        } catch (RemoteException ex) { }
+        mSettingsObserver = new SettingsObserver(mHandler);
+        mSettingsObserver.observe();
+        mShortcutManager = new ShortcutManager(context);
+        mUiMode = context.getResources().getInteger(
+                com.android.internal.R.integer.config_defaultUiModeType);
+        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
+        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
+        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
+        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
+        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
+        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                "PhoneWindowManager.mBroadcastWakeLock");
+        mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                "PhoneWindowManager.mPowerKeyWakeLock");
+        mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
+        mSupportAutoRotation = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_supportAutoRotation);
+        mLidOpenRotation = readRotation(
+                com.android.internal.R.integer.config_lidOpenRotation);
+        mCarDockRotation = readRotation(
+                com.android.internal.R.integer.config_carDockRotation);
+        mDeskDockRotation = readRotation(
+                com.android.internal.R.integer.config_deskDockRotation);
+        mUndockedHdmiRotation = readRotation(
+                com.android.internal.R.integer.config_undockedHdmiRotation);
+        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
+        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
+        mLidKeyboardAccessibility = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lidKeyboardAccessibility);
+        mLidNavigationAccessibility = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lidNavigationAccessibility);
+        mLidControlsSleep = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_lidControlsSleep);
+        mTranslucentDecorEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableTranslucentDecor);
+
+        mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
+        mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey
+                || mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
+        mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
+        mAllowTheaterModeWakeFromMotionWhenNotDreaming = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming);
+        mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
+        mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
+        mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
+
+        mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
+
+        mSupportLongPressPowerWhenNonInteractive = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_supportLongPressPowerWhenNonInteractive);
+
+        mShortPressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_shortPressOnPowerBehavior);
+        mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnPowerBehavior);
+        mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_doublePressOnPowerBehavior);
+        mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_triplePressOnPowerBehavior);
+
+        mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
+
+        readConfigurationDependentBehaviors();
+
+        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+
+        // register for dock events
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
+        filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE);
+        filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
+        filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
+        filter.addAction(Intent.ACTION_DOCK_EVENT);
+        Intent intent = context.registerReceiver(mDockReceiver, filter);
+        if (intent != null) {
+            // Retrieve current sticky dock event broadcast.
+            mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
+        }
+
+        // register for dream-related broadcasts
+        filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DREAMING_STARTED);
+        filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        context.registerReceiver(mDreamReceiver, filter);
+
+        // register for multiuser-relevant broadcasts
+        filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+        context.registerReceiver(mMultiuserReceiver, filter);
+
+        // monitor for system gestures
+        mSystemGestures = new SystemGesturesPointerEventListener(context,
+                new SystemGesturesPointerEventListener.Callbacks() {
+                    @Override
+                    public void onSwipeFromTop() {
+                        if (mStatusBar != null) {
+                            requestTransientBars(mStatusBar);
+                        }
+                    }
+                    @Override
+                    public void onSwipeFromBottom() {
+                        if (mNavigationBar != null && mNavigationBarOnBottom) {
+                            requestTransientBars(mNavigationBar);
+                        }
+                    }
+                    @Override
+                    public void onSwipeFromRight() {
+                        if (mNavigationBar != null && !mNavigationBarOnBottom) {
+                            requestTransientBars(mNavigationBar);
+                        }
+                    }
+                    @Override
+                    public void onDebug() {
+                        // no-op
+                    }
+                });
+        mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
+        mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
+
+        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_longPressVibePattern);
+        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_virtualKeyVibePattern);
+        mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_keyboardTapVibePattern);
+        mClockTickVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_clockTickVibePattern);
+        mCalendarDateVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_calendarDateVibePattern);
+        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_safeModeDisabledVibePattern);
+        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_safeModeEnabledVibePattern);
+
+        mScreenshotChordEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableScreenshotChord);
+
+        mGlobalKeyManager = new GlobalKeyManager(mContext);
+
+        // Controls rotation and the like.
+        initializeHdmiState();
+
+        // Match current screen state.
+        if (!mPowerManager.isInteractive()) {
+            goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+        }
+
+        mWindowManagerInternal.registerAppTransitionListener(
+                mStatusBarController.getAppTransitionListener());
+    }
+
+    /**
+     * Read values from config.xml that may be overridden depending on
+     * the configuration of the device.
+     * eg. Disable long press on home goes to recents on sw600dp.
+     */
+    private void readConfigurationDependentBehaviors() {
+        mLongPressOnHomeBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnHomeBehavior);
+        if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
+                mLongPressOnHomeBehavior > LONG_PRESS_HOME_ASSIST) {
+            mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+        }
+
+        mDoubleTapOnHomeBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_doubleTapOnHomeBehavior);
+        if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING ||
+                mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+            mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+        }
+    }
+
+    @Override
+    public void setInitialDisplaySize(Display display, int width, int height, int density) {
+        // This method might be called before the policy has been fully initialized
+        // or for other displays we don't care about.
+        if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+            return;
+        }
+        mDisplay = display;
+
+        final Resources res = mContext.getResources();
+        int shortSize, longSize;
+        if (width > height) {
+            shortSize = height;
+            longSize = width;
+            mLandscapeRotation = Surface.ROTATION_0;
+            mSeascapeRotation = Surface.ROTATION_180;
+            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
+                mPortraitRotation = Surface.ROTATION_90;
+                mUpsideDownRotation = Surface.ROTATION_270;
+            } else {
+                mPortraitRotation = Surface.ROTATION_270;
+                mUpsideDownRotation = Surface.ROTATION_90;
+            }
+        } else {
+            shortSize = width;
+            longSize = height;
+            mPortraitRotation = Surface.ROTATION_0;
+            mUpsideDownRotation = Surface.ROTATION_180;
+            if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
+                mLandscapeRotation = Surface.ROTATION_270;
+                mSeascapeRotation = Surface.ROTATION_90;
+            } else {
+                mLandscapeRotation = Surface.ROTATION_90;
+                mSeascapeRotation = Surface.ROTATION_270;
+            }
+        }
+
+        mStatusBarHeight =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+
+        // Height of the navigation bar when presented horizontally at bottom
+        mNavigationBarHeightForRotation[mPortraitRotation] =
+        mNavigationBarHeightForRotation[mUpsideDownRotation] =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
+        mNavigationBarHeightForRotation[mLandscapeRotation] =
+        mNavigationBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height_landscape);
+
+        // Width of the navigation bar when presented vertically along one side
+        mNavigationBarWidthForRotation[mPortraitRotation] =
+        mNavigationBarWidthForRotation[mUpsideDownRotation] =
+        mNavigationBarWidthForRotation[mLandscapeRotation] =
+        mNavigationBarWidthForRotation[mSeascapeRotation] =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
+
+        // SystemUI (status bar) layout policy
+        int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
+        int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;
+
+        // Allow the navigation bar to move on non-square small devices (phones).
+        mNavigationBarCanMove = width != height && shortSizeDp < 600;
+
+        mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
+        // Allow a system property to override this. Used by the emulator.
+        // See also hasNavigationBar().
+        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+        if ("1".equals(navBarOverride)) {
+            mHasNavigationBar = false;
+        } else if ("0".equals(navBarOverride)) {
+            mHasNavigationBar = true;
+        }
+
+        // For demo purposes, allow the rotation of the HDMI display to be controlled.
+        // By default, HDMI locks rotation to landscape.
+        if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
+            mDemoHdmiRotation = mPortraitRotation;
+        } else {
+            mDemoHdmiRotation = mLandscapeRotation;
+        }
+        mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+
+        // For demo purposes, allow the rotation of the remote display to be controlled.
+        // By default, remote display locks rotation to landscape.
+        if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
+            mDemoRotation = mPortraitRotation;
+        } else {
+            mDemoRotation = mLandscapeRotation;
+        }
+        mDemoRotationLock = SystemProperties.getBoolean(
+                "persist.demo.rotationlock", false);
+
+        // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
+        // http://developer.android.com/guide/practices/screens_support.html#range
+        mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 &&
+                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
+                // For debug purposes the next line turns this feature off with:
+                // $ adb shell setprop config.override_forced_orient true
+                // $ adb shell wm size reset
+                !"true".equals(SystemProperties.get("config.override_forced_orient"));
+    }
+
+    /**
+     * @return whether the navigation bar can be hidden, e.g. the device has a
+     *         navigation bar and touch exploration is not enabled
+     */
+    private boolean canHideNavigationBar() {
+        return mHasNavigationBar
+                && !mAccessibilityManager.isTouchExplorationEnabled();
+    }
+
+    @Override
+    public boolean isDefaultOrientationForced() {
+        return mForceDefaultOrientation;
+    }
+
+    @Override
+    public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+        if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+            mOverscanLeft = left;
+            mOverscanTop = top;
+            mOverscanRight = right;
+            mOverscanBottom = bottom;
+        }
+    }
+
+    public void updateSettings() {
+        ContentResolver resolver = mContext.getContentResolver();
+        boolean updateRotation = false;
+        synchronized (mLock) {
+            mEndcallBehavior = Settings.System.getIntForUser(resolver,
+                    Settings.System.END_BUTTON_BEHAVIOR,
+                    Settings.System.END_BUTTON_BEHAVIOR_DEFAULT,
+                    UserHandle.USER_CURRENT);
+            mIncallPowerBehavior = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+                    Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
+                    UserHandle.USER_CURRENT);
+
+            // Configure wake gesture.
+            boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.WAKE_GESTURE_ENABLED, 0,
+                    UserHandle.USER_CURRENT) != 0;
+            if (mWakeGestureEnabledSetting != wakeGestureEnabledSetting) {
+                mWakeGestureEnabledSetting = wakeGestureEnabledSetting;
+                updateWakeGestureListenerLp();
+            }
+
+            // Configure rotation lock.
+            int userRotation = Settings.System.getIntForUser(resolver,
+                    Settings.System.USER_ROTATION, Surface.ROTATION_0,
+                    UserHandle.USER_CURRENT);
+            if (mUserRotation != userRotation) {
+                mUserRotation = userRotation;
+                updateRotation = true;
+            }
+            int userRotationMode = Settings.System.getIntForUser(resolver,
+                    Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
+                            WindowManagerPolicy.USER_ROTATION_FREE :
+                                    WindowManagerPolicy.USER_ROTATION_LOCKED;
+            if (mUserRotationMode != userRotationMode) {
+                mUserRotationMode = userRotationMode;
+                updateRotation = true;
+                updateOrientationListenerLp();
+            }
+
+            if (mSystemReady) {
+                int pointerLocation = Settings.System.getIntForUser(resolver,
+                        Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
+                if (mPointerLocationMode != pointerLocation) {
+                    mPointerLocationMode = pointerLocation;
+                    mHandler.sendEmptyMessage(pointerLocation != 0 ?
+                            MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
+                }
+            }
+            // use screen off timeout setting as the timeout for the lockscreen
+            mLockScreenTimeout = Settings.System.getIntForUser(resolver,
+                    Settings.System.SCREEN_OFF_TIMEOUT, 0, UserHandle.USER_CURRENT);
+            String imId = Settings.Secure.getStringForUser(resolver,
+                    Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.USER_CURRENT);
+            boolean hasSoftInput = imId != null && imId.length() > 0;
+            if (mHasSoftInput != hasSoftInput) {
+                mHasSoftInput = hasSoftInput;
+                updateRotation = true;
+            }
+            if (mImmersiveModeConfirmation != null) {
+                mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
+            }
+            PolicyControl.reloadFromSetting(mContext);
+        }
+        if (updateRotation) {
+            updateRotation(true);
+        }
+    }
+
+    private void updateWakeGestureListenerLp() {
+        if (shouldEnableWakeGestureLp()) {
+            mWakeGestureListener.requestWakeUpTrigger();
+        } else {
+            mWakeGestureListener.cancelWakeUpTrigger();
+        }
+    }
+
+    private boolean shouldEnableWakeGestureLp() {
+        return mWakeGestureEnabledSetting && !mAwake
+                && (!mLidControlsSleep || mLidState != LID_CLOSED)
+                && mWakeGestureListener.isSupported();
+    }
+
+    private void enablePointerLocation() {
+        if (mPointerLocationView == null) {
+            mPointerLocationView = new PointerLocationView(mContext);
+            mPointerLocationView.setPrintCoords(false);
+            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                    WindowManager.LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.MATCH_PARENT);
+            lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+            lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+            if (ActivityManager.isHighEndGfx()) {
+                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+                lp.privateFlags |=
+                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
+            }
+            lp.format = PixelFormat.TRANSLUCENT;
+            lp.setTitle("PointerLocation");
+            WindowManager wm = (WindowManager)
+                    mContext.getSystemService(Context.WINDOW_SERVICE);
+            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+            wm.addView(mPointerLocationView, lp);
+            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
+        }
+    }
+
+    private void disablePointerLocation() {
+        if (mPointerLocationView != null) {
+            mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
+            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+            wm.removeView(mPointerLocationView);
+            mPointerLocationView = null;
+        }
+    }
+
+    private int readRotation(int resID) {
+        try {
+            int rotation = mContext.getResources().getInteger(resID);
+            switch (rotation) {
+                case 0:
+                    return Surface.ROTATION_0;
+                case 90:
+                    return Surface.ROTATION_90;
+                case 180:
+                    return Surface.ROTATION_180;
+                case 270:
+                    return Surface.ROTATION_270;
+            }
+        } catch (Resources.NotFoundException e) {
+            // fall through
+        }
+        return -1;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
+        int type = attrs.type;
+
+        outAppOp[0] = AppOpsManager.OP_NONE;
+
+        if (!((type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW)
+                || (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW)
+                || (type >= FIRST_SYSTEM_WINDOW && type <= LAST_SYSTEM_WINDOW))) {
+            return WindowManagerGlobal.ADD_INVALID_TYPE;
+        }
+
+        if (type < FIRST_SYSTEM_WINDOW || type > LAST_SYSTEM_WINDOW) {
+            // Window manager will make sure these are okay.
+            return WindowManagerGlobal.ADD_OKAY;
+        }
+        String permission = null;
+        switch (type) {
+            case TYPE_TOAST:
+                // XXX right now the app process has complete control over
+                // this...  should introduce a token to let the system
+                // monitor/control what they are doing.
+                outAppOp[0] = AppOpsManager.OP_TOAST_WINDOW;
+                break;
+            case TYPE_DREAM:
+            case TYPE_INPUT_METHOD:
+            case TYPE_WALLPAPER:
+            case TYPE_PRIVATE_PRESENTATION:
+            case TYPE_VOICE_INTERACTION:
+            case TYPE_ACCESSIBILITY_OVERLAY:
+                // The window manager will check these.
+                break;
+            case TYPE_PHONE:
+            case TYPE_PRIORITY_PHONE:
+            case TYPE_SYSTEM_ALERT:
+            case TYPE_SYSTEM_ERROR:
+            case TYPE_SYSTEM_OVERLAY:
+                permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
+                outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+                break;
+            default:
+                permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+        }
+        if (permission != null) {
+            if (mContext.checkCallingOrSelfPermission(permission)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+            }
+        }
+        return WindowManagerGlobal.ADD_OKAY;
+    }
+
+    @Override
+    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
+
+        // If this switch statement is modified, modify the comment in the declarations of
+        // the type in {@link WindowManager.LayoutParams} as well.
+        switch (attrs.type) {
+            default:
+                // These are the windows that by default are shown only to the user that created
+                // them. If this needs to be overridden, set
+                // {@link WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS} in
+                // {@link WindowManager.LayoutParams}. Note that permission
+                // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
+                if ((attrs.privateFlags & PRIVATE_FLAG_SHOW_FOR_ALL_USERS) == 0) {
+                    return true;
+                }
+                break;
+
+            // These are the windows that by default are shown to all users. However, to
+            // protect against spoofing, check permissions below.
+            case TYPE_APPLICATION_STARTING:
+            case TYPE_BOOT_PROGRESS:
+            case TYPE_DISPLAY_OVERLAY:
+            case TYPE_HIDDEN_NAV_CONSUMER:
+            case TYPE_KEYGUARD_SCRIM:
+            case TYPE_KEYGUARD_DIALOG:
+            case TYPE_MAGNIFICATION_OVERLAY:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_NAVIGATION_BAR_PANEL:
+            case TYPE_PHONE:
+            case TYPE_POINTER:
+            case TYPE_PRIORITY_PHONE:
+            case TYPE_SEARCH_BAR:
+            case TYPE_STATUS_BAR:
+            case TYPE_STATUS_BAR_PANEL:
+            case TYPE_STATUS_BAR_SUB_PANEL:
+            case TYPE_SYSTEM_DIALOG:
+            case TYPE_VOLUME_OVERLAY:
+            case TYPE_PRIVATE_PRESENTATION:
+                break;
+        }
+
+        // Check if third party app has set window to system window type.
+        return mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
+                        != PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
+        switch (attrs.type) {
+            case TYPE_SYSTEM_OVERLAY:
+            case TYPE_SECURE_SYSTEM_OVERLAY:
+                // These types of windows can't receive input events.
+                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+                attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+                break;
+            case TYPE_STATUS_BAR:
+
+                // If the Keyguard is in a hidden state (occluded by another window), we force to
+                // remove the wallpaper and keyguard flag so that any change in-flight after setting
+                // the keyguard as occluded wouldn't set these flags again.
+                // See {@link #processKeyguardSetHiddenResultLw}.
+                if (mKeyguardHidden) {
+                    attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+                    attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+                }
+                break;
+        }
+
+        if (attrs.type != TYPE_STATUS_BAR) {
+            // The status bar is the only window allowed to exhibit keyguard behavior.
+            attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+        }
+
+        if (ActivityManager.isHighEndGfx()
+                && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        }
+    }
+
+    void readLidState() {
+        mLidState = mWindowManagerFuncs.getLidState();
+    }
+
+    private void readCameraLensCoverState() {
+        mCameraLensCoverState = mWindowManagerFuncs.getCameraLensCoverState();
+    }
+
+    private boolean isHidden(int accessibilityMode) {
+        switch (accessibilityMode) {
+            case 1:
+                return mLidState == LID_CLOSED;
+            case 2:
+                return mLidState == LID_OPEN;
+            default:
+                return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void adjustConfigurationLw(Configuration config, int keyboardPresence,
+            int navigationPresence) {
+        mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0;
+
+        readConfigurationDependentBehaviors();
+        readLidState();
+        applyLidSwitchState();
+
+        if (config.keyboard == Configuration.KEYBOARD_NOKEYS
+                || (keyboardPresence == PRESENCE_INTERNAL
+                        && isHidden(mLidKeyboardAccessibility))) {
+            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES;
+            if (!mHasSoftInput) {
+                config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES;
+            }
+        }
+
+        if (config.navigation == Configuration.NAVIGATION_NONAV
+                || (navigationPresence == PRESENCE_INTERNAL
+                        && isHidden(mLidNavigationAccessibility))) {
+            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int windowTypeToLayerLw(int type) {
+        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
+            return 2;
+        }
+        switch (type) {
+        case TYPE_PRIVATE_PRESENTATION:
+            return 2;
+        case TYPE_WALLPAPER:
+            // wallpaper is at the bottom, though the window manager may move it.
+            return 2;
+        case TYPE_PHONE:
+            return 3;
+        case TYPE_SEARCH_BAR:
+            return 4;
+        case TYPE_VOICE_INTERACTION:
+            // voice interaction layer is almost immediately above apps.
+            return 5;
+        case TYPE_SYSTEM_DIALOG:
+            return 6;
+        case TYPE_TOAST:
+            // toasts and the plugged-in battery thing
+            return 7;
+        case TYPE_PRIORITY_PHONE:
+            // SIM errors and unlock.  Not sure if this really should be in a high layer.
+            return 8;
+        case TYPE_DREAM:
+            // used for Dreams (screensavers with TYPE_DREAM windows)
+            return 9;
+        case TYPE_SYSTEM_ALERT:
+            // like the ANR / app crashed dialogs
+            return 10;
+        case TYPE_INPUT_METHOD:
+            // on-screen keyboards and other such input method user interfaces go here.
+            return 11;
+        case TYPE_INPUT_METHOD_DIALOG:
+            // on-screen keyboards and other such input method user interfaces go here.
+            return 12;
+        case TYPE_KEYGUARD_SCRIM:
+            // the safety window that shows behind keyguard while keyguard is starting
+            return 13;
+        case TYPE_STATUS_BAR_SUB_PANEL:
+            return 14;
+        case TYPE_STATUS_BAR:
+            return 15;
+        case TYPE_STATUS_BAR_PANEL:
+            return 16;
+        case TYPE_KEYGUARD_DIALOG:
+            return 17;
+        case TYPE_VOLUME_OVERLAY:
+            // the on-screen volume indicator and controller shown when the user
+            // changes the device volume
+            return 18;
+        case TYPE_SYSTEM_OVERLAY:
+            // the on-screen volume indicator and controller shown when the user
+            // changes the device volume
+            return 19;
+        case TYPE_NAVIGATION_BAR:
+            // the navigation bar, if available, shows atop most things
+            return 20;
+        case TYPE_NAVIGATION_BAR_PANEL:
+            // some panels (e.g. search) need to show on top of the navigation bar
+            return 21;
+        case TYPE_SYSTEM_ERROR:
+            // system-level error dialogs
+            return 22;
+        case TYPE_MAGNIFICATION_OVERLAY:
+            // used to highlight the magnified portion of a display
+            return 23;
+        case TYPE_DISPLAY_OVERLAY:
+            // used to simulate secondary display devices
+            return 24;
+        case TYPE_DRAG:
+            // the drag layer: input for drag-and-drop is associated with this window,
+            // which sits above all other focusable windows
+            return 25;
+        case TYPE_ACCESSIBILITY_OVERLAY:
+            // overlay put by accessibility services to intercept user interaction
+            return 26;
+        case TYPE_SECURE_SYSTEM_OVERLAY:
+            return 27;
+        case TYPE_BOOT_PROGRESS:
+            return 28;
+        case TYPE_POINTER:
+            // the (mouse) pointer layer
+            return 29;
+        case TYPE_HIDDEN_NAV_CONSUMER:
+            return 30;
+        }
+        Log.e(TAG, "Unknown window type: " + type);
+        return 2;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int subWindowTypeToLayerLw(int type) {
+        switch (type) {
+        case TYPE_APPLICATION_PANEL:
+        case TYPE_APPLICATION_ATTACHED_DIALOG:
+            return APPLICATION_PANEL_SUBLAYER;
+        case TYPE_APPLICATION_MEDIA:
+            return APPLICATION_MEDIA_SUBLAYER;
+        case TYPE_APPLICATION_MEDIA_OVERLAY:
+            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+        case TYPE_APPLICATION_SUB_PANEL:
+            return APPLICATION_SUB_PANEL_SUBLAYER;
+        }
+        Log.e(TAG, "Unknown sub-window type: " + type);
+        return 0;
+    }
+
+    @Override
+    public int getMaxWallpaperLayer() {
+        return windowTypeToLayerLw(TYPE_STATUS_BAR);
+    }
+
+    @Override
+    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
+        if (mHasNavigationBar) {
+            // For a basic navigation bar, when we are in landscape mode we place
+            // the navigation bar to the side.
+            if (mNavigationBarCanMove && fullWidth > fullHeight) {
+                return fullWidth - mNavigationBarWidthForRotation[rotation];
+            }
+        }
+        return fullWidth;
+    }
+
+    @Override
+    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
+        if (mHasNavigationBar) {
+            // For a basic navigation bar, when we are in portrait mode we place
+            // the navigation bar to the bottom.
+            if (!mNavigationBarCanMove || fullWidth < fullHeight) {
+                return fullHeight - mNavigationBarHeightForRotation[rotation];
+            }
+        }
+        return fullHeight;
+    }
+
+    @Override
+    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
+        return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation);
+    }
+
+    @Override
+    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
+        // There is a separate status bar at the top of the display.  We don't count that as part
+        // of the fixed decor, since it can hide; however, for purposes of configurations,
+        // we do want to exclude it since applications can't generally use that part
+        // of the screen.
+        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
+    }
+
+    @Override
+    public boolean isForceHiding(WindowManager.LayoutParams attrs) {
+        return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+                (isKeyguardHostWindow(attrs) &&
+                        (mKeyguardDelegate != null && mKeyguardDelegate.isShowing())) ||
+                (attrs.type == TYPE_KEYGUARD_SCRIM);
+    }
+
+    @Override
+    public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
+        return attrs.type == TYPE_STATUS_BAR;
+    }
+
+    @Override
+    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
+        switch (attrs.type) {
+            case TYPE_STATUS_BAR:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_WALLPAPER:
+            case TYPE_DREAM:
+            case TYPE_KEYGUARD_SCRIM:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    public WindowState getWinShowWhenLockedLw() {
+        return mWinShowWhenLocked;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public View addStartingWindow(IBinder appToken, String packageName, int theme,
+            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
+            int icon, int logo, int windowFlags) {
+        if (!SHOW_STARTING_ANIMATIONS) {
+            return null;
+        }
+        if (packageName == null) {
+            return null;
+        }
+
+        WindowManager wm = null;
+        View view = null;
+
+        try {
+            Context context = mContext;
+            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName
+                    + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
+                    + Integer.toHexString(theme));
+            if (theme != context.getThemeResId() || labelRes != 0) {
+                try {
+                    context = context.createPackageContext(packageName, 0);
+                    context.setTheme(theme);
+                } catch (PackageManager.NameNotFoundException e) {
+                    // Ignore
+                }
+            }
+
+            Window win = new PhoneWindow(context);
+            final TypedArray ta = win.getWindowStyle();
+            if (ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowDisablePreview, false)
+                || ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {
+                return null;
+            }
+
+            Resources r = context.getResources();
+            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
+
+            win.setType(
+                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+            // Force the window flags: this is a fake window, so it is not really
+            // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
+            // flag because we do know that the next window will take input
+            // focus, so we want to get the IME window up on top of us right away.
+            win.setFlags(
+                windowFlags|
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
+                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                windowFlags|
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
+                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+            win.setDefaultIcon(icon);
+            win.setDefaultLogo(logo);
+
+            win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
+                    WindowManager.LayoutParams.MATCH_PARENT);
+
+            final WindowManager.LayoutParams params = win.getAttributes();
+            params.token = appToken;
+            params.packageName = packageName;
+            params.windowAnimations = win.getWindowStyle().getResourceId(
+                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+            params.privateFlags |=
+                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
+            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+
+            if (!compatInfo.supportsScreen()) {
+                params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+            }
+
+            params.setTitle("Starting " + packageName);
+
+            wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+            view = win.getDecorView();
+
+            if (win.isFloating()) {
+                // Whoops, there is no way to display an animation/preview
+                // of such a thing!  After all that work...  let's skip it.
+                // (Note that we must do this here because it is in
+                // getDecorView() where the theme is evaluated...  maybe
+                // we should peek the floating attribute from the theme
+                // earlier.)
+                return null;
+            }
+
+            if (DEBUG_STARTING_WINDOW) Slog.d(
+                TAG, "Adding starting window for " + packageName
+                + " / " + appToken + ": "
+                + (view.getParent() != null ? view : null));
+
+            wm.addView(view, params);
+
+            // Only return the view if it was successfully added to the
+            // window manager... which we can tell by it having a parent.
+            return view.getParent() != null ? view : null;
+        } catch (WindowManager.BadTokenException e) {
+            // ignore
+            Log.w(TAG, appToken + " already running, starting window not displayed. " +
+                    e.getMessage());
+        } catch (RuntimeException e) {
+            // don't crash if something else bad happens, for example a
+            // failure loading resources because we are loading from an app
+            // on external storage that has been unmounted.
+            Log.w(TAG, appToken + " failed creating starting window", e);
+        } finally {
+            if (view != null && view.getParent() == null) {
+                Log.w(TAG, "view not successfully added to wm, removing view");
+                wm.removeViewImmediate(view);
+            }
+        }
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void removeStartingWindow(IBinder appToken, View window) {
+        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": "
+                + window + " Callers=" + Debug.getCallers(4));
+
+        if (window != null) {
+            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+            wm.removeView(window);
+        }
+    }
+
+    /**
+     * Preflight adding a window to the system.
+     *
+     * Currently enforces that three window types are singletons:
+     * <ul>
+     * <li>STATUS_BAR_TYPE</li>
+     * <li>KEYGUARD_TYPE</li>
+     * </ul>
+     *
+     * @param win The window to be added
+     * @param attrs Information about the window to be added
+     *
+     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
+     * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
+     */
+    @Override
+    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
+        switch (attrs.type) {
+            case TYPE_STATUS_BAR:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                if (mStatusBar != null) {
+                    if (mStatusBar.isAlive()) {
+                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                    }
+                }
+                mStatusBar = win;
+                mStatusBarController.setWindow(win);
+                break;
+            case TYPE_NAVIGATION_BAR:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                if (mNavigationBar != null) {
+                    if (mNavigationBar.isAlive()) {
+                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                    }
+                }
+                mNavigationBar = win;
+                mNavigationBarController.setWindow(win);
+                if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+                break;
+            case TYPE_NAVIGATION_BAR_PANEL:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                break;
+            case TYPE_STATUS_BAR_PANEL:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                break;
+            case TYPE_STATUS_BAR_SUB_PANEL:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "PhoneWindowManager");
+                break;
+            case TYPE_KEYGUARD_SCRIM:
+                if (mKeyguardScrim != null) {
+                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                }
+                mKeyguardScrim = win;
+                break;
+        }
+        return WindowManagerGlobal.ADD_OKAY;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void removeWindowLw(WindowState win) {
+        if (mStatusBar == win) {
+            mStatusBar = null;
+            mStatusBarController.setWindow(null);
+            mKeyguardDelegate.showScrim();
+        } else if (mKeyguardScrim == win) {
+            Log.v(TAG, "Removing keyguard scrim");
+            mKeyguardScrim = null;
+        } if (mNavigationBar == win) {
+            mNavigationBar = null;
+            mNavigationBarController.setWindow(null);
+        }
+    }
+
+    static final boolean PRINT_ANIM = false;
+
+    /** {@inheritDoc} */
+    @Override
+    public int selectAnimationLw(WindowState win, int transit) {
+        if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
+              + ": transit=" + transit);
+        if (win == mStatusBar) {
+            boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+            if (transit == TRANSIT_EXIT
+                    || transit == TRANSIT_HIDE) {
+                return isKeyguard ? -1 : R.anim.dock_top_exit;
+            } else if (transit == TRANSIT_ENTER
+                    || transit == TRANSIT_SHOW) {
+                return isKeyguard ? -1 : R.anim.dock_top_enter;
+            }
+        } else if (win == mNavigationBar) {
+            // This can be on either the bottom or the right.
+            if (mNavigationBarOnBottom) {
+                if (transit == TRANSIT_EXIT
+                        || transit == TRANSIT_HIDE) {
+                    return R.anim.dock_bottom_exit;
+                } else if (transit == TRANSIT_ENTER
+                        || transit == TRANSIT_SHOW) {
+                    return R.anim.dock_bottom_enter;
+                }
+            } else {
+                if (transit == TRANSIT_EXIT
+                        || transit == TRANSIT_HIDE) {
+                    return R.anim.dock_right_exit;
+                } else if (transit == TRANSIT_ENTER
+                        || transit == TRANSIT_SHOW) {
+                    return R.anim.dock_right_enter;
+                }
+            }
+        }
+
+        if (transit == TRANSIT_PREVIEW_DONE) {
+            if (win.hasAppShownWindows()) {
+                if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
+                return com.android.internal.R.anim.app_starting_exit;
+            }
+        } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
+                && transit == TRANSIT_ENTER) {
+            // Special case: we are animating in a dream, while the keyguard
+            // is shown.  We don't want an animation on the dream, because
+            // we need it shown immediately with the keyguard animating away
+            // to reveal it.
+            return -1;
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void selectRotationAnimationLw(int anim[]) {
+        if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
+                + mTopFullscreenOpaqueWindowState + " rotationAnimation="
+                + (mTopFullscreenOpaqueWindowState == null ?
+                        "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation));
+        if (mTopFullscreenOpaqueWindowState != null && mTopIsFullscreen) {
+            switch (mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) {
+                case ROTATION_ANIMATION_CROSSFADE:
+                    anim[0] = R.anim.rotation_animation_xfade_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_JUMPCUT:
+                    anim[0] = R.anim.rotation_animation_jump_exit;
+                    anim[1] = R.anim.rotation_animation_enter;
+                    break;
+                case ROTATION_ANIMATION_ROTATE:
+                default:
+                    anim[0] = anim[1] = 0;
+                    break;
+            }
+        } else {
+            anim[0] = anim[1] = 0;
+        }
+    }
+
+    @Override
+    public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+            boolean forceDefault) {
+        switch (exitAnimId) {
+            case R.anim.rotation_animation_xfade_exit:
+            case R.anim.rotation_animation_jump_exit:
+                // These are the only cases that matter.
+                if (forceDefault) {
+                    return false;
+                }
+                int anim[] = new int[2];
+                selectRotationAnimationLw(anim);
+                return (exitAnimId == anim[0] && enterAnimId == anim[1]);
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    public Animation createForceHideEnterAnimation(boolean onWallpaper,
+            boolean goingToNotificationShade) {
+        if (goingToNotificationShade) {
+            return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
+        }
+
+        AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ?
+                    R.anim.lock_screen_behind_enter_wallpaper :
+                    R.anim.lock_screen_behind_enter);
+
+        // TODO: Use XML interpolators when we have log interpolators available in XML.
+        final List<Animation> animations = set.getAnimations();
+        for (int i = animations.size() - 1; i >= 0; --i) {
+            animations.get(i).setInterpolator(mLogDecelerateInterpolator);
+        }
+
+        return set;
+    }
+
+
+    @Override
+    public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
+        if (goingToNotificationShade) {
+            return null;
+        } else {
+            return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_wallpaper_exit);
+        }
+    }
+
+    private static void awakenDreams() {
+        IDreamManager dreamManager = getDreamManager();
+        if (dreamManager != null) {
+            try {
+                dreamManager.awaken();
+            } catch (RemoteException e) {
+                // fine, stay asleep then
+            }
+        }
+    }
+
+    static IDreamManager getDreamManager() {
+        return IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+    }
+
+    TelecomManager getTelecommService() {
+        return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+    }
+
+    static IAudioService getAudioService() {
+        IAudioService audioService = IAudioService.Stub.asInterface(
+                ServiceManager.checkService(Context.AUDIO_SERVICE));
+        if (audioService == null) {
+            Log.w(TAG, "Unable to find IAudioService interface.");
+        }
+        return audioService;
+    }
+
+    boolean keyguardOn() {
+        return isKeyguardShowingAndNotOccluded() || inKeyguardRestrictedKeyInputMode();
+    }
+
+    private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
+            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
+            WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+        };
+
+    /** {@inheritDoc} */
+    @Override
+    public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
+        final boolean keyguardOn = keyguardOn();
+        final int keyCode = event.getKeyCode();
+        final int repeatCount = event.getRepeatCount();
+        final int metaState = event.getMetaState();
+        final int flags = event.getFlags();
+        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+        final boolean canceled = event.isCanceled();
+
+        if (DEBUG_INPUT) {
+            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
+                    + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed
+                    + " canceled=" + canceled);
+        }
+
+        // If we think we might have a volume down & power key chord on the way
+        // but we're not sure, then tell the dispatcher to wait a little while and
+        // try again later before dispatching.
+        if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
+                final long now = SystemClock.uptimeMillis();
+                final long timeoutTime = mScreenshotChordVolumeDownKeyTime
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                if (now < timeoutTime) {
+                    return timeoutTime - now;
+                }
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                    && mScreenshotChordVolumeDownKeyConsumed) {
+                if (!down) {
+                    mScreenshotChordVolumeDownKeyConsumed = false;
+                }
+                return -1;
+            }
+        }
+
+        // Cancel any pending meta actions if we see any other keys being pressed between the down
+        // of the meta key and its corresponding up.
+        if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
+            mPendingMetaAction = false;
+        }
+
+        // First we always handle the home key here, so applications
+        // can never break it, although if keyguard is on, we do let
+        // it handle it, because that gives us the correct 5 second
+        // timeout.
+        if (keyCode == KeyEvent.KEYCODE_HOME) {
+
+            // If we have released the home key, and didn't do anything else
+            // while it was pressed, then it is time to go home!
+            if (!down) {
+                cancelPreloadRecentApps();
+
+                mHomePressed = false;
+                if (mHomeConsumed) {
+                    mHomeConsumed = false;
+                    return -1;
+                }
+
+                if (canceled) {
+                    Log.i(TAG, "Ignoring HOME; event canceled.");
+                    return -1;
+                }
+
+                // If an incoming call is ringing, HOME is totally disabled.
+                // (The user is already on the InCallUI at this point,
+                // and his ONLY options are to answer or reject the call.)
+                TelecomManager telecomManager = getTelecommService();
+                if (telecomManager != null && telecomManager.isRinging()) {
+                    Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+                    return -1;
+                }
+
+                // Delay handling home if a double-tap is possible.
+                if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
+                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
+                    mHomeDoubleTapPending = true;
+                    mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
+                            ViewConfiguration.getDoubleTapTimeout());
+                    return -1;
+                }
+
+                handleShortPressOnHome();
+                return -1;
+            }
+
+            // If a system window has focus, then it doesn't make sense
+            // right now to interact with applications.
+            WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
+            if (attrs != null) {
+                final int type = attrs.type;
+                if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM
+                        || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
+                        || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                    // the "app" is keyguard, so give it the key
+                    return 0;
+                }
+                final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
+                for (int i=0; i<typeCount; i++) {
+                    if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
+                        // don't do anything, but also don't pass it to the app
+                        return -1;
+                    }
+                }
+            }
+
+            // Remember that home is pressed and handle special actions.
+            if (repeatCount == 0) {
+                mHomePressed = true;
+                if (mHomeDoubleTapPending) {
+                    mHomeDoubleTapPending = false;
+                    mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
+                    handleDoubleTapOnHome();
+                } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI
+                        || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+                    preloadRecentApps();
+                }
+            } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                if (!keyguardOn) {
+                    handleLongPressOnHome();
+                }
+            }
+            return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
+            // Hijack modified menu keys for debugging features
+            final int chordBug = KeyEvent.META_SHIFT_ON;
+
+            if (down && repeatCount == 0) {
+                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
+                    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
+                            null, null, null, 0, null, null);
+                    return -1;
+                } else if (SHOW_PROCESSES_ON_ALT_MENU &&
+                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+                    Intent service = new Intent();
+                    service.setClassName(mContext, "com.android.server.LoadAverageService");
+                    ContentResolver res = mContext.getContentResolver();
+                    boolean shown = Settings.Global.getInt(
+                            res, Settings.Global.SHOW_PROCESSES, 0) != 0;
+                    if (!shown) {
+                        mContext.startService(service);
+                    } else {
+                        mContext.stopService(service);
+                    }
+                    Settings.Global.putInt(
+                            res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
+                    return -1;
+                }
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+            if (down) {
+                if (repeatCount == 0) {
+                    mSearchKeyShortcutPending = true;
+                    mConsumeSearchKeyUp = false;
+                }
+            } else {
+                mSearchKeyShortcutPending = false;
+                if (mConsumeSearchKeyUp) {
+                    mConsumeSearchKeyUp = false;
+                    return -1;
+                }
+            }
+            return 0;
+        } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
+            if (!keyguardOn) {
+                if (down && repeatCount == 0) {
+                    preloadRecentApps();
+                } else if (!down) {
+                    toggleRecentApps();
+                }
+            }
+            return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
+            if (down) {
+                if (repeatCount == 0) {
+                    mAssistKeyLongPressed = false;
+                } else if (repeatCount == 1) {
+                    mAssistKeyLongPressed = true;
+                    if (!keyguardOn) {
+                         launchAssistLongPressAction();
+                    }
+                }
+            } else {
+                if (mAssistKeyLongPressed) {
+                    mAssistKeyLongPressed = false;
+                } else {
+                    if (!keyguardOn) {
+                        launchAssistAction();
+                    }
+                }
+            }
+            return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
+            if (!down) {
+                Intent voiceIntent;
+                if (!keyguardOn) {
+                    voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+                } else {
+                    voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+                    voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
+                }
+                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
+            if (down && repeatCount == 0) {
+                mHandler.post(mScreenshotRunnable);
+            }
+            return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
+                || keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN) {
+            if (down) {
+                int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
+
+                // Disable autobrightness if it's on
+                int auto = Settings.System.getIntForUser(
+                        mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS_MODE,
+                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                        UserHandle.USER_CURRENT_OR_SELF);
+                if (auto != 0) {
+                    Settings.System.putIntForUser(mContext.getContentResolver(),
+                            Settings.System.SCREEN_BRIGHTNESS_MODE,
+                            Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+                            UserHandle.USER_CURRENT_OR_SELF);
+                }
+
+                int min = mPowerManager.getMinimumScreenBrightnessSetting();
+                int max = mPowerManager.getMaximumScreenBrightnessSetting();
+                int step = (max - min + BRIGHTNESS_STEPS - 1) / BRIGHTNESS_STEPS * direction;
+                int brightness = Settings.System.getIntForUser(mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS,
+                        mPowerManager.getDefaultScreenBrightnessSetting(),
+                        UserHandle.USER_CURRENT_OR_SELF);
+                brightness += step;
+                // Make sure we don't go beyond the limits.
+                brightness = Math.min(max, brightness);
+                brightness = Math.max(min, brightness);
+
+                Settings.System.putIntForUser(mContext.getContentResolver(),
+                        Settings.System.SCREEN_BRIGHTNESS, brightness,
+                        UserHandle.USER_CURRENT_OR_SELF);
+                mContext.startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
+                        UserHandle.CURRENT_OR_SELF);
+            }
+            return -1;
+        } else if (KeyEvent.isMetaKey(keyCode)) {
+            if (down) {
+                mPendingMetaAction = true;
+            } else if (mPendingMetaAction) {
+                launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD);
+            }
+            return -1;
+        }
+
+        // Shortcuts are invoked through Search+key, so intercept those here
+        // Any printing key that is chorded with Search should be consumed
+        // even if no shortcut was invoked.  This prevents text from being
+        // inadvertently inserted when using a keyboard that has built-in macro
+        // shortcut keys (that emit Search+x) and some of them are not registered.
+        if (mSearchKeyShortcutPending) {
+            final KeyCharacterMap kcm = event.getKeyCharacterMap();
+            if (kcm.isPrintingKey(keyCode)) {
+                mConsumeSearchKeyUp = true;
+                mSearchKeyShortcutPending = false;
+                if (down && repeatCount == 0 && !keyguardOn) {
+                    Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
+                    if (shortcutIntent != null) {
+                        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        try {
+                            mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+                        } catch (ActivityNotFoundException ex) {
+                            Slog.w(TAG, "Dropping shortcut key combination because "
+                                    + "the activity to which it is registered was not found: "
+                                    + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex);
+                        }
+                    } else {
+                        Slog.i(TAG, "Dropping unregistered shortcut key combination: "
+                                + "SEARCH+" + KeyEvent.keyCodeToString(keyCode));
+                    }
+                }
+                return -1;
+            }
+        }
+
+        // Invoke shortcuts using Meta.
+        if (down && repeatCount == 0 && !keyguardOn
+                && (metaState & KeyEvent.META_META_ON) != 0) {
+            final KeyCharacterMap kcm = event.getKeyCharacterMap();
+            if (kcm.isPrintingKey(keyCode)) {
+                Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode,
+                        metaState & ~(KeyEvent.META_META_ON
+                                | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON));
+                if (shortcutIntent != null) {
+                    shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    try {
+                        mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+                    } catch (ActivityNotFoundException ex) {
+                        Slog.w(TAG, "Dropping shortcut key combination because "
+                                + "the activity to which it is registered was not found: "
+                                + "META+" + KeyEvent.keyCodeToString(keyCode), ex);
+                    }
+                    return -1;
+                }
+            }
+        }
+
+        // Handle application launch keys.
+        if (down && repeatCount == 0 && !keyguardOn) {
+            String category = sApplicationLaunchKeyCategories.get(keyCode);
+            if (category != null) {
+                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                try {
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                } catch (ActivityNotFoundException ex) {
+                    Slog.w(TAG, "Dropping application launch key because "
+                            + "the activity to which it is registered was not found: "
+                            + "keyCode=" + keyCode + ", category=" + category, ex);
+                }
+                return -1;
+            }
+        }
+
+        // Display task switcher for ALT-TAB.
+        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
+            if (mRecentAppsHeldModifiers == 0 && !keyguardOn) {
+                final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+                if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
+                    mRecentAppsHeldModifiers = shiftlessModifiers;
+                    showRecentApps(true);
+                    return -1;
+                }
+            }
+        } else if (!down && mRecentAppsHeldModifiers != 0
+                && (metaState & mRecentAppsHeldModifiers) == 0) {
+            mRecentAppsHeldModifiers = 0;
+            hideRecentApps(true, false);
+        }
+
+        // Handle keyboard language switching.
+        if (down && repeatCount == 0
+                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
+                        || (keyCode == KeyEvent.KEYCODE_SPACE
+                                && (metaState & KeyEvent.META_CTRL_MASK) != 0))) {
+            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
+            return -1;
+        }
+        if (mLanguageSwitchKeyPressed && !down
+                && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
+                        || keyCode == KeyEvent.KEYCODE_SPACE)) {
+            mLanguageSwitchKeyPressed = false;
+            return -1;
+        }
+
+        if (isValidGlobalKey(keyCode)
+                && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
+            return -1;
+        }
+
+        // Reserve all the META modifier combos for system behavior
+        if ((metaState & KeyEvent.META_META_ON) != 0) {
+            return -1;
+        }
+
+        // Let the application handle the key.
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
+        // Note: This method is only called if the initial down was unhandled.
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
+                    + ", flags=" + event.getFlags()
+                    + ", keyCode=" + event.getKeyCode()
+                    + ", scanCode=" + event.getScanCode()
+                    + ", metaState=" + event.getMetaState()
+                    + ", repeatCount=" + event.getRepeatCount()
+                    + ", policyFlags=" + policyFlags);
+        }
+
+        KeyEvent fallbackEvent = null;
+        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+            final KeyCharacterMap kcm = event.getKeyCharacterMap();
+            final int keyCode = event.getKeyCode();
+            final int metaState = event.getMetaState();
+            final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
+                    && event.getRepeatCount() == 0;
+
+            // Check for fallback actions specified by the key character map.
+            final FallbackAction fallbackAction;
+            if (initialDown) {
+                fallbackAction = kcm.getFallbackAction(keyCode, metaState);
+            } else {
+                fallbackAction = mFallbackActions.get(keyCode);
+            }
+
+            if (fallbackAction != null) {
+                if (DEBUG_INPUT) {
+                    Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode
+                            + " metaState=" + Integer.toHexString(fallbackAction.metaState));
+                }
+
+                final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
+                fallbackEvent = KeyEvent.obtain(
+                        event.getDownTime(), event.getEventTime(),
+                        event.getAction(), fallbackAction.keyCode,
+                        event.getRepeatCount(), fallbackAction.metaState,
+                        event.getDeviceId(), event.getScanCode(),
+                        flags, event.getSource(), null);
+
+                if (!interceptFallback(win, fallbackEvent, policyFlags)) {
+                    fallbackEvent.recycle();
+                    fallbackEvent = null;
+                }
+
+                if (initialDown) {
+                    mFallbackActions.put(keyCode, fallbackAction);
+                } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                    mFallbackActions.remove(keyCode);
+                    fallbackAction.recycle();
+                }
+            }
+        }
+
+        if (DEBUG_INPUT) {
+            if (fallbackEvent == null) {
+                Slog.d(TAG, "No fallback.");
+            } else {
+                Slog.d(TAG, "Performing fallback: " + fallbackEvent);
+            }
+        }
+        return fallbackEvent;
+    }
+
+    private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
+        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
+        if ((actions & ACTION_PASS_TO_USER) != 0) {
+            long delayMillis = interceptKeyBeforeDispatching(
+                    win, fallbackEvent, policyFlags);
+            if (delayMillis == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void launchAssistLongPressAction() {
+        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
+
+        // launch the search activity
+        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            // TODO: This only stops the factory-installed search manager.
+            // Need to formalize an API to handle others
+            SearchManager searchManager = getSearchManager();
+            if (searchManager != null) {
+                searchManager.stopSearch();
+            }
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        } catch (ActivityNotFoundException e) {
+            Slog.w(TAG, "No activity to handle assist long press action.", e);
+        }
+    }
+
+    private void launchAssistAction() {
+        launchAssistAction(null);
+    }
+
+    private void launchAssistAction(String hint) {
+        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
+        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+        if (intent != null) {
+            if (hint != null) {
+                intent.putExtra(hint, true);
+            }
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            try {
+                mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            } catch (ActivityNotFoundException e) {
+                Slog.w(TAG, "No activity to handle assist action.", e);
+            }
+        }
+    }
+
+    private SearchManager getSearchManager() {
+        if (mSearchManager == null) {
+            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        }
+        return mSearchManager;
+    }
+
+    private void preloadRecentApps() {
+        mPreloadedRecentApps = true;
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.preloadRecentApps();
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when preloading recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
+    private void cancelPreloadRecentApps() {
+        if (mPreloadedRecentApps) {
+            mPreloadedRecentApps = false;
+            try {
+                IStatusBarService statusbar = getStatusBarService();
+                if (statusbar != null) {
+                    statusbar.cancelPreloadRecentApps();
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException when cancelling recent apps preload", e);
+                // re-acquire status bar service next time it is needed.
+                mStatusBarService = null;
+            }
+        }
+    }
+
+    private void toggleRecentApps() {
+        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.toggleRecentApps();
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when toggling recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
+    @Override
+    public void showRecentApps() {
+        mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS);
+        mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS);
+    }
+
+    private void showRecentApps(boolean triggeredFromAltTab) {
+        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.showRecentApps(triggeredFromAltTab);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when showing recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
+    private void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHome) {
+        mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+        try {
+            IStatusBarService statusbar = getStatusBarService();
+            if (statusbar != null) {
+                statusbar.hideRecentApps(triggeredFromAltTab, triggeredFromHome);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when closing recent apps", e);
+            // re-acquire status bar service next time it is needed.
+            mStatusBarService = null;
+        }
+    }
+
+    /**
+     * A home key -> launch home action was detected.  Take the appropriate action
+     * given the situation with the keyguard.
+     */
+    void launchHomeFromHotKey() {
+        if (isKeyguardShowingAndNotOccluded()) {
+            // don't launch home if keyguard showing
+        } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
+            // when in keyguard restricted mode, must first verify unlock
+            // before launching home
+            mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
+                @Override
+                public void onKeyguardExitResult(boolean success) {
+                    if (success) {
+                        try {
+                            ActivityManagerNative.getDefault().stopAppSwitches();
+                        } catch (RemoteException e) {
+                        }
+                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+                        startDockOrHome(true /*fromHomeKey*/);
+                    }
+                }
+            });
+        } else {
+            // no keyguard stuff to worry about, just launch home!
+            try {
+                ActivityManagerNative.getDefault().stopAppSwitches();
+            } catch (RemoteException e) {
+            }
+            if (mRecentsVisible) {
+                // Hide Recents and notify it to launch Home
+                awakenDreams();
+                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+                hideRecentApps(false, true);
+            } else {
+                // Otherwise, just launch Home
+                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+                startDockOrHome(true /*fromHomeKey*/);
+            }
+        }
+    }
+
+    private final Runnable mClearHideNavigationFlag = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+                // Clear flags.
+                mForceClearedSystemUiFlags &=
+                        ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            }
+            mWindowManagerFuncs.reevaluateStatusBarVisibility();
+        }
+    };
+
+    /**
+     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
+     * to determine when the nav bar should be shown and prevent applications from
+     * receiving those touches.
+     */
+    final class HideNavInputEventReceiver extends InputEventReceiver {
+        public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            boolean handled = false;
+            try {
+                if (event instanceof MotionEvent
+                        && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+                    final MotionEvent motionEvent = (MotionEvent)event;
+                    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+                        // When the user taps down, we re-show the nav bar.
+                        boolean changed = false;
+                        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+                            // Any user activity always causes us to show the
+                            // navigation controls, if they had been hidden.
+                            // We also clear the low profile and only content
+                            // flags so that tapping on the screen will atomically
+                            // restore all currently hidden screen decorations.
+                            int newVal = mResettingSystemUiFlags |
+                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                                    View.SYSTEM_UI_FLAG_LOW_PROFILE |
+                                    View.SYSTEM_UI_FLAG_FULLSCREEN;
+                            if (mResettingSystemUiFlags != newVal) {
+                                mResettingSystemUiFlags = newVal;
+                                changed = true;
+                            }
+                            // We don't allow the system's nav bar to be hidden
+                            // again for 1 second, to prevent applications from
+                            // spamming us and keeping it from being shown.
+                            newVal = mForceClearedSystemUiFlags |
+                                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+                            if (mForceClearedSystemUiFlags != newVal) {
+                                mForceClearedSystemUiFlags = newVal;
+                                changed = true;
+                                mHandler.postDelayed(mClearHideNavigationFlag, 1000);
+                            }
+                        }
+                        if (changed) {
+                            mWindowManagerFuncs.reevaluateStatusBarVisibility();
+                        }
+                    }
+                }
+            } finally {
+                finishInputEvent(event, handled);
+            }
+        }
+    }
+    final InputEventReceiver.Factory mHideNavInputEventReceiverFactory =
+            new InputEventReceiver.Factory() {
+        @Override
+        public InputEventReceiver createInputEventReceiver(
+                InputChannel inputChannel, Looper looper) {
+            return new HideNavInputEventReceiver(inputChannel, looper);
+        }
+    };
+
+    @Override
+    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.
+        mResettingSystemUiFlags &= visibility;
+        // Clear any bits in the new visibility that are currently being
+        // force cleared, before reporting it.
+        return visibility & ~mResettingSystemUiFlags
+                & ~mForceClearedSystemUiFlags;
+    }
+
+    @Override
+    public void getInsetHintLw(WindowManager.LayoutParams attrs, Rect outContentInsets,
+            Rect outStableInsets) {
+        final int fl = PolicyControl.getWindowFlags(null, attrs);
+        final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+        final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
+
+        if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
+                == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+            int availRight, availBottom;
+            if (canHideNavigationBar() &&
+                    (systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+                availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+            } else {
+                availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
+                availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
+            }
+            if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+                if ((fl & FLAG_FULLSCREEN) != 0) {
+                    outContentInsets.set(mStableFullscreenLeft, mStableFullscreenTop,
+                            availRight - mStableFullscreenRight,
+                            availBottom - mStableFullscreenBottom);
+                } else {
+                    outContentInsets.set(mStableLeft, mStableTop,
+                            availRight - mStableRight, availBottom - mStableBottom);
+                }
+            } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
+                outContentInsets.setEmpty();
+            } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
+                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
+                outContentInsets.set(mCurLeft, mCurTop,
+                        availRight - mCurRight, availBottom - mCurBottom);
+            } else {
+                outContentInsets.set(mCurLeft, mCurTop,
+                        availRight - mCurRight, availBottom - mCurBottom);
+            }
+
+            outStableInsets.set(mStableLeft, mStableTop,
+                    availRight - mStableRight, availBottom - mStableBottom);
+            return;
+        }
+        outContentInsets.setEmpty();
+        outStableInsets.setEmpty();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
+                              int displayRotation) {
+        final int overscanLeft, overscanTop, overscanRight, overscanBottom;
+        if (isDefaultDisplay) {
+            switch (displayRotation) {
+                case Surface.ROTATION_90:
+                    overscanLeft = mOverscanTop;
+                    overscanTop = mOverscanRight;
+                    overscanRight = mOverscanBottom;
+                    overscanBottom = mOverscanLeft;
+                    break;
+                case Surface.ROTATION_180:
+                    overscanLeft = mOverscanRight;
+                    overscanTop = mOverscanBottom;
+                    overscanRight = mOverscanLeft;
+                    overscanBottom = mOverscanTop;
+                    break;
+                case Surface.ROTATION_270:
+                    overscanLeft = mOverscanBottom;
+                    overscanTop = mOverscanLeft;
+                    overscanRight = mOverscanTop;
+                    overscanBottom = mOverscanRight;
+                    break;
+                default:
+                    overscanLeft = mOverscanLeft;
+                    overscanTop = mOverscanTop;
+                    overscanRight = mOverscanRight;
+                    overscanBottom = mOverscanBottom;
+                    break;
+            }
+        } else {
+            overscanLeft = 0;
+            overscanTop = 0;
+            overscanRight = 0;
+            overscanBottom = 0;
+        }
+        mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
+        mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
+        mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
+        mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
+        mSystemLeft = 0;
+        mSystemTop = 0;
+        mSystemRight = displayWidth;
+        mSystemBottom = displayHeight;
+        mUnrestrictedScreenLeft = overscanLeft;
+        mUnrestrictedScreenTop = overscanTop;
+        mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
+        mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
+        mRestrictedScreenLeft = mUnrestrictedScreenLeft;
+        mRestrictedScreenTop = mUnrestrictedScreenTop;
+        mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
+        mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
+        mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
+                = mCurLeft = mUnrestrictedScreenLeft;
+        mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
+                = mCurTop = mUnrestrictedScreenTop;
+        mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
+                = mCurRight = displayWidth - overscanRight;
+        mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
+                = mCurBottom = displayHeight - overscanBottom;
+        mDockLayer = 0x10000000;
+        mStatusBarLayer = -1;
+
+        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
+        final Rect pf = mTmpParentFrame;
+        final Rect df = mTmpDisplayFrame;
+        final Rect of = mTmpOverscanFrame;
+        final Rect vf = mTmpVisibleFrame;
+        final Rect dcf = mTmpDecorFrame;
+        pf.left = df.left = of.left = vf.left = mDockLeft;
+        pf.top = df.top = of.top = vf.top = mDockTop;
+        pf.right = df.right = of.right = vf.right = mDockRight;
+        pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
+        dcf.setEmpty();  // Decor frame N/A for system bars.
+
+        if (isDefaultDisplay) {
+            // For purposes of putting out fake window up to steal focus, we will
+            // drive nav being hidden only by whether it is requested.
+            final int sysui = mLastSystemUiFlags;
+            boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+            boolean navTranslucent = (sysui
+                    & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
+            boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+            boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+            boolean navAllowedHidden = immersive || immersiveSticky;
+            navTranslucent &= !immersiveSticky;  // transient trumps translucent
+            boolean isKeyguardShowing = isStatusBarKeyguard() && !mHideLockScreen;
+            if (!isKeyguardShowing) {
+                navTranslucent &= areTranslucentBarsAllowed();
+            }
+
+            // When the navigation bar isn't visible, we put up a fake
+            // input window to catch all touch events.  This way we can
+            // detect when the user presses anywhere to bring back the nav
+            // bar and ensure the application doesn't see the event.
+            if (navVisible || navAllowedHidden) {
+                if (mHideNavFakeWindow != null) {
+                    mHideNavFakeWindow.dismiss();
+                    mHideNavFakeWindow = null;
+                }
+            } else if (mHideNavFakeWindow == null) {
+                mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
+                        mHandler.getLooper(), mHideNavInputEventReceiverFactory,
+                        "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0,
+                        0, false, false, true);
+            }
+
+            // For purposes of positioning and showing the nav bar, if we have
+            // decided that it can't be hidden (because of the screen aspect ratio),
+            // then take that into account.
+            navVisible |= !canHideNavigationBar();
+
+            boolean updateSysUiVisibility = false;
+            if (mNavigationBar != null) {
+                boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
+                // Force the navigation bar to its appropriate place and
+                // size.  We need to do this directly, instead of relying on
+                // it to bubble up from the nav bar, because this needs to
+                // change atomically with screen rotations.
+                mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
+                if (mNavigationBarOnBottom) {
+                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
+                    int top = displayHeight - overscanBottom
+                            - mNavigationBarHeightForRotation[displayRotation];
+                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
+                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
+                    if (transientNavBarShowing) {
+                        mNavigationBarController.setBarShowingLw(true);
+                    } else if (navVisible) {
+                        mNavigationBarController.setBarShowingLw(true);
+                        mDockBottom = mTmpNavigationFrame.top;
+                        mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
+                        mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
+                    } else {
+                        // We currently want to hide the navigation UI.
+                        mNavigationBarController.setBarShowingLw(false);
+                    }
+                    if (navVisible && !navTranslucent && !navAllowedHidden
+                            && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTranslucent()) {
+                        // If the opaque nav bar is currently requested to be visible,
+                        // and not in the process of animating on or off, then
+                        // we can tell the app that it is covered by it.
+                        mSystemBottom = mTmpNavigationFrame.top;
+                    }
+                } else {
+                    // Landscape screen; nav bar goes to the right.
+                    int left = displayWidth - overscanRight
+                            - mNavigationBarWidthForRotation[displayRotation];
+                    mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
+                    mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
+                    if (transientNavBarShowing) {
+                        mNavigationBarController.setBarShowingLw(true);
+                    } else if (navVisible) {
+                        mNavigationBarController.setBarShowingLw(true);
+                        mDockRight = mTmpNavigationFrame.left;
+                        mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+                        mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
+                    } else {
+                        // We currently want to hide the navigation UI.
+                        mNavigationBarController.setBarShowingLw(false);
+                    }
+                    if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw()
+                            && !mNavigationBarController.wasRecentlyTranslucent()) {
+                        // If the nav bar is currently requested to be visible,
+                        // and not in the process of animating on or off, then
+                        // we can tell the app that it is covered by it.
+                        mSystemRight = mTmpNavigationFrame.left;
+                    }
+                }
+                // Make sure the content and current rectangles are updated to
+                // account for the restrictions from the navigation bar.
+                mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+                mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+                mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+                mContentRight = mVoiceContentRight = mCurRight = mDockRight;
+                mStatusBarLayer = mNavigationBar.getSurfaceLayer();
+                // And compute the final frame.
+                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
+                        mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
+                        mTmpNavigationFrame);
+                if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+                if (mNavigationBarController.checkHiddenLw()) {
+                    updateSysUiVisibility = true;
+                }
+            }
+            if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
+                    mDockLeft, mDockTop, mDockRight, mDockBottom));
+
+            // decide where the status bar goes ahead of time
+            if (mStatusBar != null) {
+                // apply any navigation bar insets
+                pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+                pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+                pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
+                        + mUnrestrictedScreenTop;
+                vf.left = mStableLeft;
+                vf.top = mStableTop;
+                vf.right = mStableRight;
+                vf.bottom = mStableBottom;
+
+                mStatusBarLayer = mStatusBar.getSurfaceLayer();
+
+                // Let the status bar determine its size.
+                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf);
+
+                // For layout, the status bar is always at the top with our fixed height.
+                mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
+
+                boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+                boolean statusBarTranslucent = (sysui
+                        & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
+                if (!isKeyguardShowing) {
+                    statusBarTranslucent &= areTranslucentBarsAllowed();
+                }
+
+                // If the status bar is hidden, we don't want to cause
+                // windows behind it to scroll.
+                if (mStatusBar.isVisibleLw() && !statusBarTransient) {
+                    // Status bar may go away, so the screen area it occupies
+                    // is available to apps but just covering them when the
+                    // status bar is visible.
+                    mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
+
+                    mContentTop = mVoiceContentTop = mCurTop = mDockTop;
+                    mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+                    mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
+                    mContentRight = mVoiceContentRight = mCurRight = mDockRight;
+
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
+                        String.format(
+                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+                            mDockLeft, mDockTop, mDockRight, mDockBottom,
+                            mContentLeft, mContentTop, mContentRight, mContentBottom,
+                            mCurLeft, mCurTop, mCurRight, mCurBottom));
+                }
+                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
+                        && !statusBarTransient && !statusBarTranslucent
+                        && !mStatusBarController.wasRecentlyTranslucent()) {
+                    // If the opaque status bar is currently requested to be visible,
+                    // and not in the process of animating on or off, then
+                    // we can tell the app that it is covered by it.
+                    mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
+                }
+                if (mStatusBarController.checkHiddenLw()) {
+                    updateSysUiVisibility = true;
+                }
+            }
+            if (updateSysUiVisibility) {
+                updateSystemUiVisibilityLw();
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int getSystemDecorLayerLw() {
+        if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
+        if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
+        return 0;
+    }
+
+    @Override
+    public void getContentRectLw(Rect r) {
+        r.set(mContentLeft, mContentTop, mContentRight, mContentBottom);
+    }
+
+    void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
+            boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
+        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
+            // Here's a special case: if this attached window is a panel that is
+            // above the dock window, and the window it is attached to is below
+            // the dock window, then the frames we computed for the window it is
+            // attached to can not be used because the dock is effectively part
+            // of the underlying window and the attached window is floating on top
+            // of the whole thing.  So, we ignore the attached window and explicitly
+            // compute the frames that would be appropriate without the dock.
+            df.left = of.left = cf.left = vf.left = mDockLeft;
+            df.top = of.top = cf.top = vf.top = mDockTop;
+            df.right = of.right = cf.right = vf.right = mDockRight;
+            df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
+        } else {
+            // The effective display frame of the attached window depends on
+            // whether it is taking care of insetting its content.  If not,
+            // we need to use the parent's content frame so that the entire
+            // window is positioned within that content.  Otherwise we can use
+            // the overscan frame and let the attached window take care of
+            // positioning its content appropriately.
+            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                // Set the content frame of the attached window to the parent's decor frame
+                // (same as content frame when IME isn't present) if specifically requested by
+                // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
+                // Otherwise, use the overscan frame.
+                cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
+                        ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
+            } else {
+                // If the window is resizing, then we want to base the content
+                // frame on our attached content frame to resize...  however,
+                // things can be tricky if the attached window is NOT in resize
+                // mode, in which case its content frame will be larger.
+                // Ungh.  So to deal with that, make sure the content frame
+                // we end up using is not covering the IM dock.
+                cf.set(attached.getContentFrameLw());
+                if (attached.isVoiceInteraction()) {
+                    if (cf.left < mVoiceContentLeft) cf.left = mVoiceContentLeft;
+                    if (cf.top < mVoiceContentTop) cf.top = mVoiceContentTop;
+                    if (cf.right > mVoiceContentRight) cf.right = mVoiceContentRight;
+                    if (cf.bottom > mVoiceContentBottom) cf.bottom = mVoiceContentBottom;
+                } else if (attached.getSurfaceLayer() < mDockLayer) {
+                    if (cf.left < mContentLeft) cf.left = mContentLeft;
+                    if (cf.top < mContentTop) cf.top = mContentTop;
+                    if (cf.right > mContentRight) cf.right = mContentRight;
+                    if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
+                }
+            }
+            df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
+            of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
+            vf.set(attached.getVisibleFrameLw());
+        }
+        // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
+        // window should be positioned relative to its parent or the entire
+        // screen.
+        pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
+                ? attached.getFrameLw() : df);
+    }
+
+    private void applyStableConstraints(int sysui, int fl, Rect r) {
+        if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+            // If app is requesting a stable layout, don't let the
+            // content insets go below the stable values.
+            if ((fl & FLAG_FULLSCREEN) != 0) {
+                if (r.left < mStableFullscreenLeft) r.left = mStableFullscreenLeft;
+                if (r.top < mStableFullscreenTop) r.top = mStableFullscreenTop;
+                if (r.right > mStableFullscreenRight) r.right = mStableFullscreenRight;
+                if (r.bottom > mStableFullscreenBottom) r.bottom = mStableFullscreenBottom;
+            } else {
+                if (r.left < mStableLeft) r.left = mStableLeft;
+                if (r.top < mStableTop) r.top = mStableTop;
+                if (r.right > mStableRight) r.right = mStableRight;
+                if (r.bottom > mStableBottom) r.bottom = mStableBottom;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void layoutWindowLw(WindowState win, WindowState attached) {
+        // we've already done the status bar
+        final WindowManager.LayoutParams attrs = win.getAttrs();
+        if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) ||
+                win == mNavigationBar) {
+            return;
+        }
+        final boolean isDefaultDisplay = win.isDefaultDisplay();
+        final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
+                (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
+        if (needsToOffsetInputMethodTarget) {
+            if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
+            offsetInputMethodWindowLw(mLastInputMethodWindow);
+        }
+
+        final int fl = PolicyControl.getWindowFlags(win, attrs);
+        final int sim = attrs.softInputMode;
+        final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+
+        final Rect pf = mTmpParentFrame;
+        final Rect df = mTmpDisplayFrame;
+        final Rect of = mTmpOverscanFrame;
+        final Rect cf = mTmpContentFrame;
+        final Rect vf = mTmpVisibleFrame;
+        final Rect dcf = mTmpDecorFrame;
+        final Rect sf = mTmpStableFrame;
+        dcf.setEmpty();
+
+        final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
+                && mNavigationBar != null && mNavigationBar.isVisibleLw());
+
+        final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+
+        if (isDefaultDisplay) {
+            sf.set(mStableLeft, mStableTop, mStableRight, mStableBottom);
+        } else {
+            sf.set(mOverscanLeft, mOverscanTop, mOverscanRight, mOverscanBottom);
+        }
+
+        if (!isDefaultDisplay) {
+            if (attached != null) {
+                // If this window is attached to another, our display
+                // frame is the same as the one we are attached to.
+                setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
+            } else {
+                // Give the window full screen.
+                pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                pf.right = df.right = of.right = cf.right
+                        = mOverscanScreenLeft + mOverscanScreenWidth;
+                pf.bottom = df.bottom = of.bottom = cf.bottom
+                        = mOverscanScreenTop + mOverscanScreenHeight;
+            }
+        } else  if (attrs.type == TYPE_INPUT_METHOD || attrs.type == TYPE_VOICE_INTERACTION) {
+            pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
+            pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
+            pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
+            // IM dock windows layout below the nav bar...
+            pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+            // ...with content insets above the nav bar
+            cf.bottom = vf.bottom = mStableBottom;
+            // IM dock windows always go to the bottom of the screen.
+            attrs.gravity = Gravity.BOTTOM;
+            mDockLayer = win.getSurfaceLayer();
+        } else if (win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+            pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+            pf.top = df.top = of.top = mUnrestrictedScreenTop;
+            pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+            pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
+            cf.left = vf.left = mStableLeft;
+            cf.top = vf.top = mStableTop;
+            cf.right = vf.right = mStableRight;
+            vf.bottom = mStableBottom;
+            cf.bottom = mContentBottom;
+        } else {
+
+            // Default policy decor for the default display
+            dcf.left = mSystemLeft;
+            dcf.top = mSystemTop;
+            dcf.right = mSystemRight;
+            dcf.bottom = mSystemBottom;
+            final boolean inheritTranslucentDecor = (attrs.privateFlags
+                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
+            final boolean isAppWindow =
+                    attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW &&
+                    attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+            final boolean topAtRest =
+                    win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
+            if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
+                if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
+                        && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
+                        && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0
+                        && (fl & WindowManager.LayoutParams.
+                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+                    // Ensure policy decor includes status bar
+                    dcf.top = mStableTop;
+                }
+                if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0
+                        && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+                        && (fl & WindowManager.LayoutParams.
+                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+                    // Ensure policy decor includes navigation bar
+                    dcf.bottom = mStableBottom;
+                    dcf.right = mStableRight;
+                }
+            }
+
+            if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
+                    == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+                            + "): IN_SCREEN, INSET_DECOR");
+                // This is the case for a normal activity window: we want it
+                // to cover all of the screen space, and it can take care of
+                // moving its contents to account for screen decorations that
+                // intrude into that space.
+                if (attached != null) {
+                    // If this window is attached to another, our display
+                    // frame is the same as the one we are attached to.
+                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
+                } else {
+                    if (attrs.type == TYPE_STATUS_BAR_PANEL
+                            || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
+                        // Status bar panels are the only windows who can go on top of
+                        // the status bar.  They are protected by the STATUS_BAR_SERVICE
+                        // permission, so they have the same privileges as the status
+                        // bar itself.
+                        //
+                        // However, they should still dodge the navigation bar if it exists.
+
+                        pf.left = df.left = of.left = hasNavBar
+                                ? mDockLeft : mUnrestrictedScreenLeft;
+                        pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                        pf.right = df.right = of.right = hasNavBar
+                                ? mRestrictedScreenLeft+mRestrictedScreenWidth
+                                : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        pf.bottom = df.bottom = of.bottom = hasNavBar
+                                ? mRestrictedScreenTop+mRestrictedScreenHeight
+                                : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+
+                        if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
+                                        "Laying out status bar window: (%d,%d - %d,%d)",
+                                        pf.left, pf.top, pf.right, pf.bottom));
+                    } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
+                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        // Asking to layout into the overscan region, so give it that pure
+                        // unrestricted area.
+                        pf.left = df.left = of.left = mOverscanScreenLeft;
+                        pf.top = df.top = of.top = mOverscanScreenTop;
+                        pf.right = df.right = of.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                        pf.bottom = df.bottom = of.bottom = mOverscanScreenTop
+                                + mOverscanScreenHeight;
+                    } else if (canHideNavigationBar()
+                            && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                            && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                        // Asking for layout as if the nav bar is hidden, lets the
+                        // application extend into the unrestricted overscan screen area.  We
+                        // only do this for application windows to ensure no window that
+                        // can be above the nav bar can do this.
+                        pf.left = df.left = mOverscanScreenLeft;
+                        pf.top = df.top = mOverscanScreenTop;
+                        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+                        // We need to tell the app about where the frame inside the overscan
+                        // is, so it can inset its content by that amount -- it didn't ask
+                        // to actually extend itself into the overscan region.
+                        of.left = mUnrestrictedScreenLeft;
+                        of.top = mUnrestrictedScreenTop;
+                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                    } else {
+                        pf.left = df.left = mRestrictedOverscanScreenLeft;
+                        pf.top = df.top = mRestrictedOverscanScreenTop;
+                        pf.right = df.right = mRestrictedOverscanScreenLeft
+                                + mRestrictedOverscanScreenWidth;
+                        pf.bottom = df.bottom = mRestrictedOverscanScreenTop
+                                + mRestrictedOverscanScreenHeight;
+                        // We need to tell the app about where the frame inside the overscan
+                        // is, so it can inset its content by that amount -- it didn't ask
+                        // to actually extend itself into the overscan region.
+                        of.left = mUnrestrictedScreenLeft;
+                        of.top = mUnrestrictedScreenTop;
+                        of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                        of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                    }
+
+                    if ((fl & FLAG_FULLSCREEN) == 0) {
+                        if (win.isVoiceInteraction()) {
+                            cf.left = mVoiceContentLeft;
+                            cf.top = mVoiceContentTop;
+                            cf.right = mVoiceContentRight;
+                            cf.bottom = mVoiceContentBottom;
+                        } else {
+                            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                                cf.left = mDockLeft;
+                                cf.top = mDockTop;
+                                cf.right = mDockRight;
+                                cf.bottom = mDockBottom;
+                            } else {
+                                cf.left = mContentLeft;
+                                cf.top = mContentTop;
+                                cf.right = mContentRight;
+                                cf.bottom = mContentBottom;
+                            }
+                        }
+                    } else {
+                        // Full screen windows are always given a layout that is as if the
+                        // status bar and other transient decors are gone.  This is to avoid
+                        // bad states when moving from a window that is not hding the
+                        // status bar to one that is.
+                        cf.left = mRestrictedScreenLeft;
+                        cf.top = mRestrictedScreenTop;
+                        cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
+                        cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
+                    }
+                    applyStableConstraints(sysUiFl, fl, cf);
+                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                        vf.left = mCurLeft;
+                        vf.top = mCurTop;
+                        vf.right = mCurRight;
+                        vf.bottom = mCurBottom;
+                    } else {
+                        vf.set(cf);
+                    }
+                }
+            } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
+                    & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): IN_SCREEN");
+                // A window that has requested to fill the entire screen just
+                // gets everything, period.
+                if (attrs.type == TYPE_STATUS_BAR_PANEL
+                        || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
+                    pf.left = df.left = of.left = cf.left = hasNavBar
+                            ? mDockLeft : mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = hasNavBar
+                                        ? mRestrictedScreenLeft+mRestrictedScreenWidth
+                                        : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar
+                                          ? mRestrictedScreenTop+mRestrictedScreenHeight
+                                          : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
+                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
+                                    pf.left, pf.top, pf.right, pf.bottom));
+                } else if (attrs.type == TYPE_NAVIGATION_BAR
+                        || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
+                    // The navigation bar has Real Ultimate Power.
+                    pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = mUnrestrictedScreenLeft
+                            + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop
+                            + mUnrestrictedScreenHeight;
+                    if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
+                                    "Laying out navigation bar window: (%d,%d - %d,%d)",
+                                    pf.left, pf.top, pf.right, pf.bottom));
+                } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
+                                || attrs.type == TYPE_BOOT_PROGRESS)
+                        && ((fl & FLAG_FULLSCREEN) != 0)) {
+                    // Fullscreen secure system overlays get what they ask for.
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
+                            + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
+                            + mOverscanScreenHeight;
+                } else if (attrs.type == TYPE_BOOT_PROGRESS) {
+                    // Boot progress screen always covers entire display.
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
+                            + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
+                            + mOverscanScreenHeight;
+                } else if (attrs.type == TYPE_WALLPAPER) {
+                    // The wallpaper also has Real Ultimate Power, but we want to tell
+                    // it about the overscan area.
+                    pf.left = df.left = mOverscanScreenLeft;
+                    pf.top = df.top = mOverscanScreenTop;
+                    pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+                    of.left = cf.left = mUnrestrictedScreenLeft;
+                    of.top = cf.top = mUnrestrictedScreenTop;
+                    of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                    of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+                } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
+                        && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                        && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                    // Asking to layout into the overscan region, so give it that pure
+                    // unrestricted area.
+                    pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
+                    pf.right = df.right = of.right = cf.right
+                            = mOverscanScreenLeft + mOverscanScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom
+                            = mOverscanScreenTop + mOverscanScreenHeight;
+                } else if (canHideNavigationBar()
+                        && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+                        && (attrs.type == TYPE_STATUS_BAR
+                            || attrs.type == TYPE_TOAST
+                            || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                            && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
+                    // Asking for layout as if the nav bar is hidden, lets the
+                    // application extend into the unrestricted screen area.  We
+                    // only do this for application windows (or toasts) to ensure no window that
+                    // can be above the nav bar can do this.
+                    // XXX This assumes that an app asking for this will also
+                    // ask for layout in only content.  We can't currently figure out
+                    // what the screen would be if only laying out to hide the nav bar.
+                    pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mUnrestrictedScreenLeft
+                            + mUnrestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
+                            + mUnrestrictedScreenHeight;
+                } else {
+                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
+                            + mRestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
+                            + mRestrictedScreenHeight;
+                }
+
+                applyStableConstraints(sysUiFl, fl, cf);
+
+                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                    vf.left = mCurLeft;
+                    vf.top = mCurTop;
+                    vf.right = mCurRight;
+                    vf.bottom = mCurBottom;
+                } else {
+                    vf.set(cf);
+                }
+            } else if (attached != null) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): attached to " + attached);
+                // A child window should be placed inside of the same visible
+                // frame that its parent had.
+                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf);
+            } else {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
+                        "): normal window");
+                // Otherwise, a normal window must be placed inside the content
+                // of all screen decorations.
+                if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+                    // Status bar panels are the only windows who can go on top of
+                    // the status bar.  They are protected by the STATUS_BAR_SERVICE
+                    // permission, so they have the same privileges as the status
+                    // bar itself.
+                    pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
+                    pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
+                    pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
+                            + mRestrictedScreenWidth;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
+                            + mRestrictedScreenHeight;
+                } else if (attrs.type == TYPE_TOAST || attrs.type == TYPE_SYSTEM_ALERT
+                        || attrs.type == TYPE_VOLUME_OVERLAY) {
+                    // These dialogs are stable to interim decor changes.
+                    pf.left = df.left = of.left = cf.left = mStableLeft;
+                    pf.top = df.top = of.top = cf.top = mStableTop;
+                    pf.right = df.right = of.right = cf.right = mStableRight;
+                    pf.bottom = df.bottom = of.bottom = cf.bottom = mStableBottom;
+                } else {
+                    pf.left = mContentLeft;
+                    pf.top = mContentTop;
+                    pf.right = mContentRight;
+                    pf.bottom = mContentBottom;
+                    if (win.isVoiceInteraction()) {
+                        df.left = of.left = cf.left = mVoiceContentLeft;
+                        df.top = of.top = cf.top = mVoiceContentTop;
+                        df.right = of.right = cf.right = mVoiceContentRight;
+                        df.bottom = of.bottom = cf.bottom = mVoiceContentBottom;
+                    } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                        df.left = of.left = cf.left = mDockLeft;
+                        df.top = of.top = cf.top = mDockTop;
+                        df.right = of.right = cf.right = mDockRight;
+                        df.bottom = of.bottom = cf.bottom = mDockBottom;
+                    } else {
+                        df.left = of.left = cf.left = mContentLeft;
+                        df.top = of.top = cf.top = mContentTop;
+                        df.right = of.right = cf.right = mContentRight;
+                        df.bottom = of.bottom = cf.bottom = mContentBottom;
+                    }
+                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                        vf.left = mCurLeft;
+                        vf.top = mCurTop;
+                        vf.right = mCurRight;
+                        vf.bottom = mCurBottom;
+                    } else {
+                        vf.set(cf);
+                    }
+                }
+            }
+        }
+
+        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
+            df.left = df.top = -10000;
+            df.right = df.bottom = 10000;
+            if (attrs.type != TYPE_WALLPAPER) {
+                of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
+                of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
+            }
+        }
+
+        if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+                + ": sim=#" + Integer.toHexString(sim)
+                + " attach=" + attached + " type=" + attrs.type
+                + String.format(" flags=0x%08x", fl)
+                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
+                + " of=" + of.toShortString()
+                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
+                + " dcf=" + dcf.toShortString()
+                + " sf=" + sf.toShortString());
+
+        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf);
+
+        // Dock windows carve out the bottom of the screen, so normal windows
+        // can't appear underneath them.
+        if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw()
+                && !win.getGivenInsetsPendingLw()) {
+            setLastInputMethodWindowLw(null, null);
+            offsetInputMethodWindowLw(win);
+        }
+        if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleOrBehindKeyguardLw()
+                && !win.getGivenInsetsPendingLw()) {
+            offsetVoiceInputWindowLw(win);
+        }
+    }
+
+    private void offsetInputMethodWindowLw(WindowState win) {
+        int top = win.getDisplayFrameLw().top;
+        top += win.getGivenContentInsetsLw().top;
+        if (mContentBottom > top) {
+            mContentBottom = top;
+        }
+        if (mVoiceContentBottom > top) {
+            mVoiceContentBottom = top;
+        }
+        top = win.getVisibleFrameLw().top;
+        top += win.getGivenVisibleInsetsLw().top;
+        if (mCurBottom > top) {
+            mCurBottom = top;
+        }
+        if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
+                + mDockBottom + " mContentBottom="
+                + mContentBottom + " mCurBottom=" + mCurBottom);
+    }
+
+    private void offsetVoiceInputWindowLw(WindowState win) {
+        int top = win.getDisplayFrameLw().top;
+        top += win.getGivenContentInsetsLw().top;
+        if (mVoiceContentBottom > top) {
+            mVoiceContentBottom = top;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void finishLayoutLw() {
+        return;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
+        mTopFullscreenOpaqueWindowState = null;
+        mTopFullscreenOpaqueOrDimmingWindowState = null;
+        mAppsToBeHidden.clear();
+        mAppsThatDismissKeyguard.clear();
+        mForceStatusBar = false;
+        mForceStatusBarFromKeyguard = false;
+        mForcingShowNavBar = false;
+        mForcingShowNavBarLayer = -1;
+
+        mHideLockScreen = false;
+        mAllowLockscreenWhenOn = false;
+        mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+        mShowingLockscreen = false;
+        mShowingDream = false;
+        mWinShowWhenLocked = null;
+        mKeyguardSecure = isKeyguardSecure();
+        mKeyguardSecureIncludingHidden = mKeyguardSecure
+                && (mKeyguardDelegate != null && mKeyguardDelegate.isShowing());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    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);
+        if (mTopFullscreenOpaqueWindowState == null
+                && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) {
+            mForcingShowNavBar = true;
+            mForcingShowNavBarLayer = win.getSurfaceLayer();
+        }
+        if (attrs.type == TYPE_STATUS_BAR && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+            mForceStatusBarFromKeyguard = true;
+        }
+        if (mTopFullscreenOpaqueWindowState == null &&
+                win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) {
+            if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
+                if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                    mForceStatusBarFromKeyguard = true;
+                } else {
+                    mForceStatusBar = true;
+                }
+            }
+            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                mShowingLockscreen = true;
+            }
+            boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
+                    && attrs.type < FIRST_SYSTEM_WINDOW;
+            if (attrs.type == TYPE_DREAM) {
+                // If the lockscreen was showing when the dream started then wait
+                // for the dream to draw before hiding the lockscreen.
+                if (!mDreamingLockscreen
+                        || (win.isVisibleLw() && win.hasDrawnLw())) {
+                    mShowingDream = true;
+                    appWindow = true;
+                }
+            }
+
+            final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
+            final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
+            if (appWindow) {
+                final IApplicationToken appToken = win.getAppToken();
+                if (showWhenLocked) {
+                    // Remove any previous windows with the same appToken.
+                    mAppsToBeHidden.remove(appToken);
+                    mAppsThatDismissKeyguard.remove(appToken);
+                    if (mAppsToBeHidden.isEmpty()) {
+                        if (dismissKeyguard && !mKeyguardSecure) {
+                            mAppsThatDismissKeyguard.add(appToken);
+                        } else {
+                            mWinShowWhenLocked = win;
+                            mHideLockScreen = true;
+                            mForceStatusBarFromKeyguard = false;
+                        }
+                    }
+                } else if (dismissKeyguard) {
+                    if (mKeyguardSecure) {
+                        mAppsToBeHidden.add(appToken);
+                    } else {
+                        mAppsToBeHidden.remove(appToken);
+                    }
+                    mAppsThatDismissKeyguard.add(appToken);
+                } else {
+                    mAppsToBeHidden.add(appToken);
+                }
+                if (attrs.x == 0 && attrs.y == 0
+                        && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+                        && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
+                    mTopFullscreenOpaqueWindowState = win;
+                    if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
+                        mTopFullscreenOpaqueOrDimmingWindowState = win;
+                    }
+                    if (!mAppsThatDismissKeyguard.isEmpty() &&
+                            mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG,
+                                "Setting mDismissKeyguard true by win " + win);
+                        mDismissKeyguard = mWinDismissingKeyguard == win ?
+                                DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
+                        mWinDismissingKeyguard = win;
+                        mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
+                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG,
+                                "Setting mHideLockScreen to true by win " + win);
+                        mHideLockScreen = true;
+                        mForceStatusBarFromKeyguard = false;
+                    }
+                    if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
+                        mAllowLockscreenWhenOn = true;
+                    }
+                }
+
+                if (mWinShowWhenLocked != null &&
+                        mWinShowWhenLocked.getAppToken() != win.getAppToken()) {
+                    win.hideLw(false);
+                }
+            }
+        }
+        if (mTopFullscreenOpaqueOrDimmingWindowState == null
+                && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()
+                && win.isDimming()) {
+            mTopFullscreenOpaqueOrDimmingWindowState = win;
+        }
+    }
+
+    /** {@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;
+
+        final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
+                ? mTopFullscreenOpaqueWindowState.getAttrs()
+                : null;
+
+        // If we are not currently showing a dream then remember the current
+        // lockscreen state.  We will use this to determine whether the dream
+        // started while the lockscreen was showing and remember this state
+        // while the dream is showing.
+        if (!mShowingDream) {
+            mDreamingLockscreen = mShowingLockscreen;
+        }
+
+        if (mStatusBar != null) {
+            if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
+                    + " forcefkg=" + mForceStatusBarFromKeyguard
+                    + " top=" + mTopFullscreenOpaqueWindowState);
+            if (mForceStatusBar || mForceStatusBarFromKeyguard) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
+                if (mStatusBarController.setBarShowingLw(true)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                }
+                // Maintain fullscreen layout until incoming animation is complete.
+                topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
+                // Transient status bar on the lockscreen is not allowed
+                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
+                    mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
+                            mLastSystemUiFlags, mLastSystemUiFlags);
+                }
+            } else if (mTopFullscreenOpaqueWindowState != null) {
+                final int fl = PolicyControl.getWindowFlags(null, lp);
+                if (localLOGV) {
+                    Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
+                            + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
+                    Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+                            + " lp.flags=0x" + Integer.toHexString(fl));
+                }
+                topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
+                        || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+                // The subtle difference between the window for mTopFullscreenOpaqueWindowState
+                // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
+                // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
+                // case though.
+                if (mStatusBarController.isTransientShowing()) {
+                    if (mStatusBarController.setBarShowingLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    }
+                } else if (topIsFullscreen) {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
+                    if (mStatusBarController.setBarShowingLw(false)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    } else {
+                        if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
+                    }
+                } else {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
+                    if (mStatusBarController.setBarShowingLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT;
+                    }
+                }
+            }
+        }
+
+        if (mTopIsFullscreen != topIsFullscreen) {
+            if (!topIsFullscreen) {
+                // Force another layout when status bar becomes fully shown.
+                changes |= FINISH_LAYOUT_REDO_LAYOUT;
+            }
+            mTopIsFullscreen = topIsFullscreen;
+        }
+
+        // Hide the key guard if a visible window explicitly specifies that it wants to be
+        // displayed when the screen is locked.
+        if (mKeyguardDelegate != null && mStatusBar != null) {
+            if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
+                    + mHideLockScreen);
+            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardSecure) {
+                mKeyguardHidden = true;
+                if (setKeyguardOccludedLw(true)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+                if (mKeyguardDelegate.isShowing()) {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mKeyguardDelegate.keyguardDone(false, false);
+                        }
+                    });
+                }
+            } else if (mHideLockScreen) {
+                mKeyguardHidden = true;
+                if (setKeyguardOccludedLw(true)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+            } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
+                // This is the case of keyguard isSecure() and not mHideLockScreen.
+                if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
+                    // Only launch the next keyguard unlock window once per window.
+                    mKeyguardHidden = false;
+                    if (setKeyguardOccludedLw(false)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT
+                                | FINISH_LAYOUT_REDO_CONFIG
+                                | FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mKeyguardDelegate.dismiss();
+                        }
+                    });
+                }
+            } else {
+                mWinDismissingKeyguard = null;
+                mKeyguardHidden = false;
+                if (setKeyguardOccludedLw(false)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+            }
+        }
+
+        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+            // If the navigation bar has been hidden or shown, we need to do another
+            // layout pass to update that window.
+            changes |= FINISH_LAYOUT_REDO_LAYOUT;
+        }
+
+        // update since mAllowLockscreenWhenOn might have changed
+        updateLockScreenTimeout();
+        return changes;
+    }
+
+    /**
+     * Updates the occluded state of the Keyguard.
+     *
+     * @return Whether the flags have changed and we have to redo the layout.
+     */
+    private boolean setKeyguardOccludedLw(boolean isOccluded) {
+        boolean wasOccluded = mKeyguardOccluded;
+        boolean showing = mKeyguardDelegate.isShowing();
+        if (wasOccluded && !isOccluded && showing) {
+            mKeyguardOccluded = false;
+            mKeyguardDelegate.setOccluded(false);
+            mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+            mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            return true;
+        } else if (!wasOccluded && isOccluded && showing) {
+            mKeyguardOccluded = true;
+            mKeyguardDelegate.setOccluded(true);
+            mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+            mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isStatusBarKeyguard() {
+        return mStatusBar != null
+                && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+    }
+
+    @Override
+    public boolean allowAppAnimationsLw() {
+        if (isStatusBarKeyguard() || mShowingDream) {
+            // If keyguard or dreams is currently visible, no reason to animate behind it.
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
+        mFocusedWindow = newFocus;
+        if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+            // If the navigation bar has been hidden or shown, we need to do another
+            // layout pass to update that window.
+            return FINISH_LAYOUT_REDO_LAYOUT;
+        }
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+        // lid changed state
+        final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
+        if (newLidState == mLidState) {
+            return;
+        }
+
+        mLidState = newLidState;
+        applyLidSwitchState();
+        updateRotation(true);
+
+        if (lidOpen) {
+            wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch);
+        } else if (!mLidControlsSleep) {
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+        }
+    }
+
+    @Override
+    public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
+        int lensCoverState = lensCovered ? CAMERA_LENS_COVERED : CAMERA_LENS_UNCOVERED;
+        if (mCameraLensCoverState == lensCoverState) {
+            return;
+        }
+        if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
+                lensCoverState == CAMERA_LENS_UNCOVERED) {
+            Intent intent;
+            final boolean keyguardActive = mKeyguardDelegate == null ? false :
+                    mKeyguardDelegate.isShowing();
+            if (keyguardActive) {
+                intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+            } else {
+                intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+            }
+            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens);
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+        }
+        mCameraLensCoverState = lensCoverState;
+    }
+
+    void setHdmiPlugged(boolean plugged) {
+        if (mHdmiPlugged != plugged) {
+            mHdmiPlugged = plugged;
+            updateRotation(true, true);
+            Intent intent = new Intent(ACTION_HDMI_PLUGGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
+            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+        }
+    }
+
+    void initializeHdmiState() {
+        boolean plugged = false;
+        // watch for HDMI plug messages if the hdmi switch exists
+        if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
+            mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
+
+            final String filename = "/sys/class/switch/hdmi/state";
+            FileReader reader = null;
+            try {
+                reader = new FileReader(filename);
+                char[] buf = new char[15];
+                int n = reader.read(buf);
+                if (n > 1) {
+                    plugged = 0 != Integer.parseInt(new String(buf, 0, n-1));
+                }
+            } catch (IOException ex) {
+                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
+            } catch (NumberFormatException ex) {
+                Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex);
+            } finally {
+                if (reader != null) {
+                    try {
+                        reader.close();
+                    } catch (IOException ex) {
+                    }
+                }
+            }
+        }
+        // This dance forces the code in setHdmiPlugged to run.
+        // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
+        mHdmiPlugged = !plugged;
+        setHdmiPlugged(!mHdmiPlugged);
+    }
+
+    final Object mScreenshotLock = new Object();
+    ServiceConnection mScreenshotConnection = null;
+
+    final Runnable mScreenshotTimeout = new Runnable() {
+        @Override public void run() {
+            synchronized (mScreenshotLock) {
+                if (mScreenshotConnection != null) {
+                    mContext.unbindService(mScreenshotConnection);
+                    mScreenshotConnection = null;
+                }
+            }
+        }
+    };
+
+    // Assume this is called from the Handler thread.
+    private void takeScreenshot() {
+        synchronized (mScreenshotLock) {
+            if (mScreenshotConnection != null) {
+                return;
+            }
+            ComponentName cn = new ComponentName("com.android.systemui",
+                    "com.android.systemui.screenshot.TakeScreenshotService");
+            Intent intent = new Intent();
+            intent.setComponent(cn);
+            ServiceConnection conn = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    synchronized (mScreenshotLock) {
+                        if (mScreenshotConnection != this) {
+                            return;
+                        }
+                        Messenger messenger = new Messenger(service);
+                        Message msg = Message.obtain(null, 1);
+                        final ServiceConnection myConn = this;
+                        Handler h = new Handler(mHandler.getLooper()) {
+                            @Override
+                            public void handleMessage(Message msg) {
+                                synchronized (mScreenshotLock) {
+                                    if (mScreenshotConnection == myConn) {
+                                        mContext.unbindService(mScreenshotConnection);
+                                        mScreenshotConnection = null;
+                                        mHandler.removeCallbacks(mScreenshotTimeout);
+                                    }
+                                }
+                            }
+                        };
+                        msg.replyTo = new Messenger(h);
+                        msg.arg1 = msg.arg2 = 0;
+                        if (mStatusBar != null && mStatusBar.isVisibleLw())
+                            msg.arg1 = 1;
+                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
+                            msg.arg2 = 1;
+                        try {
+                            messenger.send(msg);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                }
+                @Override
+                public void onServiceDisconnected(ComponentName name) {}
+            };
+            if (mContext.bindServiceAsUser(
+                    intent, conn, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
+                mScreenshotConnection = conn;
+                mHandler.postDelayed(mScreenshotTimeout, 10000);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        if (!mSystemBooted) {
+            // If we have not yet booted, don't let key events do anything.
+            return 0;
+        }
+
+        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
+        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+        final boolean canceled = event.isCanceled();
+        final int keyCode = event.getKeyCode();
+
+        final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
+
+        // If screen is off then we treat the case where the keyguard is open but hidden
+        // the same as if it were open and in front.
+        // This will prevent any keys other than the power button from waking the screen
+        // when the keyguard is hidden by another activity.
+        final boolean keyguardActive = (mKeyguardDelegate == null ? false :
+                                            (interactive ?
+                                                isKeyguardShowingAndNotOccluded() :
+                                                mKeyguardDelegate.isShowing()));
+
+        if (DEBUG_INPUT) {
+            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
+                    + " policyFlags=" + Integer.toHexString(policyFlags));
+        }
+
+        // Basic policy based on interactive state.
+        int result;
+        boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
+                || event.isWakeKey();
+        if (interactive || (isInjected && !isWakeKey)) {
+            // When the device is interactive or the key is injected pass the
+            // key to the application.
+            result = ACTION_PASS_TO_USER;
+            isWakeKey = false;
+        } else if (!interactive && shouldDispatchInputWhenNonInteractive()) {
+            // If we're currently dozing with the screen on and the keyguard showing, pass the key
+            // to the application but preserve its wake key status to make sure we still move
+            // from dozing to fully interactive if we would normally go from off to fully
+            // interactive.
+            result = ACTION_PASS_TO_USER;
+        } else {
+            // When the screen is off and the key is not injected, determine whether
+            // to wake the device but don't pass the key to the application.
+            result = 0;
+            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+                isWakeKey = false;
+            }
+        }
+
+        // If the key would be handled globally, just return the result, don't worry about special
+        // key processing.
+        if (isValidGlobalKey(keyCode)
+                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
+            if (isWakeKey) {
+                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+            }
+            return result;
+        }
+
+        boolean useHapticFeedback = down
+                && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+                && event.getRepeatCount() == 0;
+
+        // Handle special keys.
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                if (mUseTvRouting) {
+                    // On TVs volume keys never go to the foreground app
+                    result &= ~ACTION_PASS_TO_USER;
+                }
+                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+                    if (down) {
+                        if (interactive && !mScreenshotChordVolumeDownKeyTriggered
+                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+                            mScreenshotChordVolumeDownKeyTriggered = true;
+                            mScreenshotChordVolumeDownKeyTime = event.getDownTime();
+                            mScreenshotChordVolumeDownKeyConsumed = false;
+                            cancelPendingPowerKeyAction();
+                            interceptScreenshotChord();
+                        }
+                    } else {
+                        mScreenshotChordVolumeDownKeyTriggered = false;
+                        cancelPendingScreenshotChordAction();
+                    }
+                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+                    if (down) {
+                        if (interactive && !mScreenshotChordVolumeUpKeyTriggered
+                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+                            mScreenshotChordVolumeUpKeyTriggered = true;
+                            cancelPendingPowerKeyAction();
+                            cancelPendingScreenshotChordAction();
+                        }
+                    } else {
+                        mScreenshotChordVolumeUpKeyTriggered = false;
+                        cancelPendingScreenshotChordAction();
+                    }
+                }
+                if (down) {
+                    TelecomManager telecomManager = getTelecommService();
+                    if (telecomManager != null) {
+                        if (telecomManager.isRinging()) {
+                            // If an incoming call is ringing, either VOLUME key means
+                            // "silence ringer".  We handle these keys here, rather than
+                            // in the InCallScreen, to make sure we'll respond to them
+                            // even if the InCallScreen hasn't come to the foreground yet.
+                            // Look for the DOWN event here, to agree with the "fallback"
+                            // behavior in the InCallScreen.
+                            Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                  + " VOLUME key-down while ringing: Silence ringer!");
+
+                            // Silence the ringer.  (It's safe to call this
+                            // even if the ringer has already been silenced.)
+                            telecomManager.silenceRinger();
+
+                            // And *don't* pass this key thru to the current activity
+                            // (which is probably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
+                            break;
+                        }
+                        if (telecomManager.isInCall()
+                                && (result & ACTION_PASS_TO_USER) == 0) {
+                            // If we are in call but we decided not to pass the key to
+                            // the application, just pass it to the session service.
+
+                            MediaSessionLegacyHelper.getHelper(mContext)
+                                    .sendVolumeKeyEvent(event, false);
+                            break;
+                        }
+                    }
+
+                    if ((result & ACTION_PASS_TO_USER) == 0) {
+                        if (mUseTvRouting) {
+                            dispatchDirectAudioEvent(event);
+                        } else {
+                            // 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)
+                                    .sendVolumeKeyEvent(event, true);
+                        }
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_ENDCALL: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (down) {
+                    TelecomManager telecomManager = getTelecommService();
+                    boolean hungUp = false;
+                    if (telecomManager != null) {
+                        hungUp = telecomManager.endCall();
+                    }
+                    if (interactive && !hungUp) {
+                        mEndCallKeyHandled = false;
+                        mHandler.postDelayed(mEndCallLongPress,
+                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                    } else {
+                        mEndCallKeyHandled = true;
+                    }
+                } else {
+                    if (!mEndCallKeyHandled) {
+                        mHandler.removeCallbacks(mEndCallLongPress);
+                        if (!canceled) {
+                            if ((mEndcallBehavior
+                                    & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+                                if (goHome()) {
+                                    break;
+                                }
+                            }
+                            if ((mEndcallBehavior
+                                    & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+                                mPowerManager.goToSleep(event.getEventTime(),
+                                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                                isWakeKey = false;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_POWER: {
+                result &= ~ACTION_PASS_TO_USER;
+                isWakeKey = false; // wake-up will be handled separately
+                if (down) {
+                    interceptPowerKeyDown(event, interactive);
+                } else {
+                    interceptPowerKeyUp(event, interactive, canceled);
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_SLEEP: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (!mPowerManager.isInteractive()) {
+                    useHapticFeedback = false; // suppress feedback if already non-interactive
+                }
+                mPowerManager.goToSleep(event.getEventTime(),
+                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                isWakeKey = false;
+                break;
+            }
+
+            case KeyEvent.KEYCODE_WAKEUP: {
+                result &= ~ACTION_PASS_TO_USER;
+                isWakeKey = true;
+                break;
+            }
+
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
+                    // If the global session is active pass all media keys to it
+                    // instead of the active window.
+                    result &= ~ACTION_PASS_TO_USER;
+                }
+                if ((result & ACTION_PASS_TO_USER) == 0) {
+                    // Only do this if we would otherwise not pass it to the user. In that
+                    // case, the PhoneWindow class will do the same thing, except it will
+                    // only do it if the showing app doesn't process the key on its own.
+                    // Note that we need to make a copy of the key event here because the
+                    // original key event will be recycled when we return.
+                    mBroadcastWakeLock.acquire();
+                    Message msg = mHandler.obtainMessage(MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
+                            new KeyEvent(event));
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_CALL: {
+                if (down) {
+                    TelecomManager telecomManager = getTelecommService();
+                    if (telecomManager != null) {
+                        if (telecomManager.isRinging()) {
+                            Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                  + " CALL key-down while ringing: Answer the call!");
+                            telecomManager.acceptRingingCall();
+
+                            // And *don't* pass this key thru to the current activity
+                            // (which is presumably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
+                        }
+                    }
+                }
+                break;
+            }
+            case KeyEvent.KEYCODE_VOICE_ASSIST: {
+                // Only do this if we would otherwise not pass it to the user. In that case,
+                // interceptKeyBeforeDispatching would apply a similar but different policy in
+                // order to invoke voice assist actions. Note that we need to make a copy of the
+                // key event here because the original key event will be recycled when we return.
+                if ((result & ACTION_PASS_TO_USER) == 0 && !down) {
+                    mBroadcastWakeLock.acquire();
+                    Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK,
+                            keyguardActive ? 1 : 0, 0);
+                    msg.setAsynchronous(true);
+                    msg.sendToTarget();
+                }
+            }
+        }
+
+        if (useHapticFeedback) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
+
+        if (isWakeKey) {
+            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the key can have global actions attached to it.
+     * We reserve all power management keys for the system since they require
+     * very careful handling.
+     */
+    private static boolean isValidGlobalKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_POWER:
+            case KeyEvent.KEYCODE_WAKEUP:
+            case KeyEvent.KEYCODE_SLEEP:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * When the screen is off we ignore some keys that might otherwise typically
+     * be considered wake keys.  We filter them out here.
+     *
+     * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it
+     * is always considered a wake key.
+     */
+    private boolean isWakeKeyWhenScreenOff(int keyCode) {
+        switch (keyCode) {
+            // ignore volume keys unless docked
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE:
+                return mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+            // ignore media and camera keys
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
+            case KeyEvent.KEYCODE_CAMERA:
+                return false;
+        }
+        return true;
+    }
+
+
+    /** {@inheritDoc} */
+    @Override
+    public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+        if ((policyFlags & FLAG_WAKE) != 0) {
+            if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) {
+                return 0;
+            }
+        }
+
+        if (shouldDispatchInputWhenNonInteractive()) {
+            return ACTION_PASS_TO_USER;
+        }
+
+        // If we have not passed the action up and we are in theater mode without dreaming,
+        // there will be no dream to intercept the touch and wake into ambient.  The device should
+        // wake up in this case.
+        if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
+            wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming);
+        }
+
+        return 0;
+    }
+
+    private boolean shouldDispatchInputWhenNonInteractive() {
+        // Send events to keyguard while the screen is on.
+        if (isKeyguardShowingAndNotOccluded() && mDisplay != null
+                && mDisplay.getState() != Display.STATE_OFF) {
+            return true;
+        }
+
+        // Send events to a dozing dream even if the screen is off since the dream
+        // is in control of the state of the screen.
+        IDreamManager dreamManager = getDreamManager();
+
+        try {
+            if (dreamManager != null && dreamManager.isDreaming()) {
+                return true;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException when checking if dreaming", e);
+        }
+
+        // Otherwise, consume events since the user can't see what is being
+        // interacted with.
+        return false;
+    }
+
+    private void dispatchDirectAudioEvent(KeyEvent event) {
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return;
+        }
+        int keyCode = event.getKeyCode();
+        int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND;
+        String pkgName = mContext.getOpPackageName();
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_UP:
+                try {
+                    getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
+                }
+                break;
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+                try {
+                    getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
+                            AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
+                }
+                break;
+            case KeyEvent.KEYCODE_VOLUME_MUTE:
+                try {
+                    if (event.getRepeatCount() == 0) {
+                        getAudioService().adjustSuggestedStreamVolume(
+                                AudioManager.ADJUST_TOGGLE_MUTE,
+                                AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
+                }
+                break;
+        }
+    }
+
+    void dispatchMediaKeyWithWakeLock(KeyEvent event) {
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
+        }
+
+        if (mHavePendingMediaKeyRepeatWithWakeLock) {
+            if (DEBUG_INPUT) {
+                Slog.d(TAG, "dispatchMediaKeyWithWakeLock: canceled repeat");
+            }
+
+            mHandler.removeMessages(MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK);
+            mHavePendingMediaKeyRepeatWithWakeLock = false;
+            mBroadcastWakeLock.release(); // pending repeat was holding onto the wake lock
+        }
+
+        dispatchMediaKeyWithWakeLockToAudioService(event);
+
+        if (event.getAction() == KeyEvent.ACTION_DOWN
+                && event.getRepeatCount() == 0) {
+            mHavePendingMediaKeyRepeatWithWakeLock = true;
+
+            Message msg = mHandler.obtainMessage(
+                    MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK, event);
+            msg.setAsynchronous(true);
+            mHandler.sendMessageDelayed(msg, ViewConfiguration.getKeyRepeatTimeout());
+        } else {
+            mBroadcastWakeLock.release();
+        }
+    }
+
+    void dispatchMediaKeyRepeatWithWakeLock(KeyEvent event) {
+        mHavePendingMediaKeyRepeatWithWakeLock = false;
+
+        KeyEvent repeatEvent = KeyEvent.changeTimeRepeat(event,
+                SystemClock.uptimeMillis(), 1, event.getFlags() | KeyEvent.FLAG_LONG_PRESS);
+        if (DEBUG_INPUT) {
+            Slog.d(TAG, "dispatchMediaKeyRepeatWithWakeLock: " + repeatEvent);
+        }
+
+        dispatchMediaKeyWithWakeLockToAudioService(repeatEvent);
+        mBroadcastWakeLock.release();
+    }
+
+    void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
+        if (ActivityManagerNative.isSystemReady()) {
+            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
+        }
+    }
+
+    void launchVoiceAssistWithWakeLock(boolean keyguardActive) {
+        Intent voiceIntent =
+            new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+        voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive);
+        mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
+        mBroadcastWakeLock.release();
+    }
+
+    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
+                mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            } else {
+                try {
+                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
+                            ServiceManager.getService(Context.UI_MODE_SERVICE));
+                    mUiMode = uiModeService.getCurrentModeType();
+                } catch (RemoteException e) {
+                }
+            }
+            updateRotation(true);
+            synchronized (mLock) {
+                updateOrientationListenerLp();
+            }
+        }
+    };
+
+    BroadcastReceiver mDreamReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.onDreamingStarted();
+                }
+            } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.onDreamingStopped();
+                }
+            }
+        }
+    };
+
+    BroadcastReceiver mMultiuserReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+                // tickle the settings observer: this first ensures that we're
+                // observing the relevant settings for the newly-active user,
+                // and then updates our own bookkeeping based on the now-
+                // current user.
+                mSettingsObserver.onChange(false);
+
+                // force a re-application of focused window sysui visibility.
+                // the window may never have been shown for this user
+                // e.g. the keyguard when going through the new-user setup flow
+                synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+                    mLastSystemUiFlags = 0;
+                    updateSystemUiVisibilityLw();
+                }
+            }
+        }
+    };
+
+    private final Runnable mRequestTransientNav = new Runnable() {
+        @Override
+        public void run() {
+            requestTransientBars(mNavigationBar);
+        }
+    };
+
+    private void requestTransientBars(WindowState swipeTarget) {
+        synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+            if (!isUserSetupComplete()) {
+                // Swipe-up for navigation bar is disabled during setup
+                return;
+            }
+            boolean sb = mStatusBarController.checkShowTransientBarLw();
+            boolean nb = mNavigationBarController.checkShowTransientBarLw();
+            if (sb || nb) {
+                // Don't show status bar when swiping on already visible navigation bar
+                if (!nb && swipeTarget == mNavigationBar) {
+                    if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
+                    return;
+                }
+                if (sb) mStatusBarController.showTransient();
+                if (nb) mNavigationBarController.showTransient();
+                mImmersiveModeConfirmation.confirmCurrentPrompt();
+                updateSystemUiVisibilityLw();
+            }
+        }
+    }
+
+    // Called on the PowerManager's Notifier thread.
+    @Override
+    public void goingToSleep(int why) {
+        EventLog.writeEvent(70000, 0);
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
+
+        // We must get this work done here because the power manager will drop
+        // the wake lock and let the system suspend once this function returns.
+        synchronized (mLock) {
+            mAwake = false;
+            mKeyguardDrawComplete = false;
+            updateWakeGestureListenerLp();
+            updateOrientationListenerLp();
+            updateLockScreenTimeout();
+        }
+
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.onScreenTurnedOff(why);
+        }
+    }
+
+    private void wakeUpFromPowerKey(long eventTime) {
+        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
+    }
+
+    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
+        if (!wakeInTheaterMode && isTheaterModeEnabled()) {
+            return false;
+        }
+
+        mPowerManager.wakeUp(wakeTime);
+        return true;
+    }
+
+    // Called on the PowerManager's Notifier thread.
+    @Override
+    public void wakingUp() {
+        EventLog.writeEvent(70000, 1);
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
+
+        // Since goToSleep performs these functions synchronously, we must
+        // do the same here.  We cannot post this work to a handler because
+        // that might cause it to become reordered with respect to what
+        // may happen in a future call to goToSleep.
+        synchronized (mLock) {
+            mAwake = true;
+            mKeyguardDrawComplete = false;
+            if (mKeyguardDelegate != null) {
+                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
+            }
+
+            updateWakeGestureListenerLp();
+            updateOrientationListenerLp();
+            updateLockScreenTimeout();
+        }
+
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.onScreenTurnedOn(mKeyguardDelegateCallback);
+            // ... eventually calls finishKeyguardDrawn
+        } else {
+            if (DEBUG_WAKEUP) Slog.d(TAG, "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
+            finishKeyguardDrawn();
+        }
+    }
+
+    private void finishKeyguardDrawn() {
+        synchronized (mLock) {
+            if (!mAwake || mKeyguardDrawComplete) {
+                return; // spurious
+            }
+
+            mKeyguardDrawComplete = true;
+            if (mKeyguardDelegate != null) {
+                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+            }
+        }
+
+        finishScreenTurningOn();
+    }
+
+    // Called on the DisplayManager's DisplayPowerController thread.
+    @Override
+    public void screenTurnedOff() {
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+
+        synchronized (mLock) {
+            mScreenOnEarly = false;
+            mScreenOnFully = false;
+            mWindowManagerDrawComplete = false;
+            mScreenOnListener = null;
+            updateOrientationListenerLp();
+        }
+    }
+
+    // Called on the DisplayManager's DisplayPowerController thread.
+    @Override
+    public void screenTurningOn(final ScreenOnListener screenOnListener) {
+        if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+
+        synchronized (mLock) {
+            mScreenOnEarly = true;
+            mScreenOnFully = false;
+            mWindowManagerDrawComplete = false;
+            mScreenOnListener = screenOnListener;
+            updateOrientationListenerLp();
+        }
+
+        mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
+                WAITING_FOR_DRAWN_TIMEOUT);
+        // ... eventually calls finishWindowsDrawn
+    }
+
+    private void finishWindowsDrawn() {
+        synchronized (mLock) {
+            if (!mScreenOnEarly || mWindowManagerDrawComplete) {
+                return; // spurious
+            }
+
+            mWindowManagerDrawComplete = true;
+        }
+
+        finishScreenTurningOn();
+    }
+
+    private void finishScreenTurningOn() {
+        final ScreenOnListener listener;
+        final boolean enableScreen;
+        synchronized (mLock) {
+            if (DEBUG_WAKEUP) Slog.d(TAG,
+                    "finishScreenTurningOn: mAwake=" + mAwake
+                            + ", mScreenOnEarly=" + mScreenOnEarly
+                            + ", mScreenOnFully=" + mScreenOnFully
+                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
+
+            if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
+                    || (mAwake && !mKeyguardDrawComplete)) {
+                return; // spurious or not ready yet
+            }
+
+            if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
+            listener = mScreenOnListener;
+            mScreenOnListener = null;
+            mScreenOnFully = true;
+
+            // Remember the first time we draw the keyguard so we know when we're done with
+            // the main part of booting and can enable the screen and hide boot messages.
+            if (!mKeyguardDrawnOnce && mAwake) {
+                mKeyguardDrawnOnce = true;
+                enableScreen = true;
+                if (mBootMessageNeedsHiding) {
+                    mBootMessageNeedsHiding = false;
+                    hideBootMessages();
+                }
+            } else {
+                enableScreen = false;
+            }
+        }
+
+        if (listener != null) {
+            listener.onScreenOn();
+        }
+
+        if (enableScreen) {
+            try {
+                mWindowManager.enableScreenIfNeeded();
+            } catch (RemoteException unhandled) {
+            }
+        }
+    }
+
+    private void handleHideBootMessage() {
+        synchronized (mLock) {
+            if (!mKeyguardDrawnOnce) {
+                mBootMessageNeedsHiding = true;
+                return; // keyguard hasn't drawn the first time yet, not done booting
+            }
+        }
+
+        if (mBootMsgDialog != null) {
+            if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: dismissing");
+            mBootMsgDialog.dismiss();
+            mBootMsgDialog = null;
+        }
+    }
+
+    @Override
+    public boolean isScreenOn() {
+        return mScreenOnFully;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void enableKeyguard(boolean enabled) {
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.setKeyguardEnabled(enabled);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.verifyUnlock(callback);
+        }
+    }
+
+    private boolean isKeyguardShowingAndNotOccluded() {
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isShowing() && !mKeyguardOccluded;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isKeyguardLocked() {
+        return keyguardOn();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean isKeyguardSecure() {
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isSecure();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean inKeyguardRestrictedKeyInputMode() {
+        if (mKeyguardDelegate == null) return false;
+        return mKeyguardDelegate.isInputRestricted();
+    }
+
+    @Override
+    public void dismissKeyguardLw() {
+        if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    // ask the keyguard to prompt the user to authenticate if necessary
+                    mKeyguardDelegate.dismiss();
+                }
+            });
+        }
+    }
+
+    public void notifyActivityDrawnForKeyguardLw() {
+        if (mKeyguardDelegate != null) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mKeyguardDelegate.onActivityDrawn();
+                }
+            });
+        }
+    }
+
+    @Override
+    public boolean isKeyguardDrawnLw() {
+        synchronized (mLock) {
+            return mKeyguardDrawnOnce;
+        }
+    }
+
+    @Override
+    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
+        if (mKeyguardDelegate != null) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
+            mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration);
+        }
+    }
+
+    void sendCloseSystemWindows() {
+        PhoneWindow.sendCloseSystemWindows(mContext, null);
+    }
+
+    void sendCloseSystemWindows(String reason) {
+        PhoneWindow.sendCloseSystemWindows(mContext, reason);
+    }
+
+    @Override
+    public int rotationForOrientationLw(int orientation, int lastRotation) {
+        if (false) {
+            Slog.v(TAG, "rotationForOrientationLw(orient="
+                        + orientation + ", last=" + lastRotation
+                        + "); user=" + mUserRotation + " "
+                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
+                            ? "USER_ROTATION_LOCKED" : "")
+                        );
+        }
+
+        if (mForceDefaultOrientation) {
+            return Surface.ROTATION_0;
+        }
+
+        synchronized (mLock) {
+            int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
+            if (sensorRotation < 0) {
+                sensorRotation = lastRotation;
+            }
+
+            final int preferredRotation;
+            if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
+                // Ignore sensor when lid switch is open and rotation is forced.
+                preferredRotation = mLidOpenRotation;
+            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
+                    && (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) {
+                // Ignore sensor when in car dock unless explicitly enabled.
+                // This case can override the behavior of NOSENSOR, and can also
+                // enable 180 degree rotation while docked.
+                preferredRotation = mCarDockEnablesAccelerometer
+                        ? sensorRotation : mCarDockRotation;
+            } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+                    || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
+                    || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
+                    && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
+                // Ignore sensor when in desk dock unless explicitly enabled.
+                // This case can override the behavior of NOSENSOR, and can also
+                // enable 180 degree rotation while docked.
+                preferredRotation = mDeskDockEnablesAccelerometer
+                        ? sensorRotation : mDeskDockRotation;
+            } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+                // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
+                // Note that the dock orientation overrides the HDMI orientation.
+                preferredRotation = mDemoHdmiRotation;
+            } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+                    && mUndockedHdmiRotation >= 0) {
+                // Ignore sensor when plugged into HDMI and an undocked orientation has
+                // been specified in the configuration (only for legacy devices without
+                // full multi-display support).
+                // Note that the dock orientation overrides the HDMI orientation.
+                preferredRotation = mUndockedHdmiRotation;
+            } else if (mDemoRotationLock) {
+                // Ignore sensor when demo rotation lock is enabled.
+                // Note that the dock orientation and HDMI rotation lock override this.
+                preferredRotation = mDemoRotation;
+            } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+                // Application just wants to remain locked in the last rotation.
+                preferredRotation = lastRotation;
+            } else if (!mSupportAutoRotation) {
+                // If we don't support auto-rotation then bail out here and ignore
+                // the sensor and any rotation lock settings.
+                preferredRotation = -1;
+            } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
+                            && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
+                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
+                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
+                                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
+                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
+                    || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
+                // Otherwise, use sensor only if requested by the application or enabled
+                // by default for USER or UNSPECIFIED modes.  Does not apply to NOSENSOR.
+                if (mAllowAllRotations < 0) {
+                    // Can't read this during init() because the context doesn't
+                    // have display metrics at that time so we cannot determine
+                    // tablet vs. phone then.
+                    mAllowAllRotations = mContext.getResources().getBoolean(
+                            com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
+                }
+                if (sensorRotation != Surface.ROTATION_180
+                        || mAllowAllRotations == 1
+                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
+                    preferredRotation = sensorRotation;
+                } else {
+                    preferredRotation = lastRotation;
+                }
+            } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
+                    && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+                // Apply rotation lock.  Does not apply to NOSENSOR.
+                // The idea is that the user rotation expresses a weak preference for the direction
+                // of gravity and as NOSENSOR is never affected by gravity, then neither should
+                // NOSENSOR be affected by rotation lock (although it will be affected by docks).
+                preferredRotation = mUserRotation;
+            } else {
+                // No overriding preference.
+                // We will do exactly what the application asked us to do.
+                preferredRotation = -1;
+            }
+
+            switch (orientation) {
+                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+                    // Return portrait unless overridden.
+                    if (isAnyPortrait(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    return mPortraitRotation;
+
+                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+                    // Return landscape unless overridden.
+                    if (isLandscapeOrSeascape(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    return mLandscapeRotation;
+
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+                    // Return reverse portrait unless overridden.
+                    if (isAnyPortrait(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    return mUpsideDownRotation;
+
+                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+                    // Return seascape unless overridden.
+                    if (isLandscapeOrSeascape(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    return mSeascapeRotation;
+
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+                case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
+                    // Return either landscape rotation.
+                    if (isLandscapeOrSeascape(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    if (isLandscapeOrSeascape(lastRotation)) {
+                        return lastRotation;
+                    }
+                    return mLandscapeRotation;
+
+                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+                case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
+                    // Return either portrait rotation.
+                    if (isAnyPortrait(preferredRotation)) {
+                        return preferredRotation;
+                    }
+                    if (isAnyPortrait(lastRotation)) {
+                        return lastRotation;
+                    }
+                    return mPortraitRotation;
+
+                default:
+                    // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
+                    // just return the preferred orientation we already calculated.
+                    if (preferredRotation >= 0) {
+                        return preferredRotation;
+                    }
+                    return Surface.ROTATION_0;
+            }
+        }
+    }
+
+    @Override
+    public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation) {
+        switch (orientation) {
+            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
+            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+                return isAnyPortrait(rotation);
+
+            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
+            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+                return isLandscapeOrSeascape(rotation);
+
+            default:
+                return true;
+        }
+    }
+
+    @Override
+    public void setRotationLw(int rotation) {
+        mOrientationListener.setCurrentRotation(rotation);
+    }
+
+    private boolean isLandscapeOrSeascape(int rotation) {
+        return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
+    }
+
+    private boolean isAnyPortrait(int rotation) {
+        return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
+    }
+
+    @Override
+    public int getUserRotationMode() {
+        return Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
+                        WindowManagerPolicy.USER_ROTATION_FREE :
+                                WindowManagerPolicy.USER_ROTATION_LOCKED;
+    }
+
+    // User rotation: to be used when all else fails in assigning an orientation to the device
+    @Override
+    public void setUserRotationMode(int mode, int rot) {
+        ContentResolver res = mContext.getContentResolver();
+
+        // mUserRotationMode and mUserRotation will be assigned by the content observer
+        if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
+            Settings.System.putIntForUser(res,
+                    Settings.System.USER_ROTATION,
+                    rot,
+                    UserHandle.USER_CURRENT);
+            Settings.System.putIntForUser(res,
+                    Settings.System.ACCELEROMETER_ROTATION,
+                    0,
+                    UserHandle.USER_CURRENT);
+        } else {
+            Settings.System.putIntForUser(res,
+                    Settings.System.ACCELEROMETER_ROTATION,
+                    1,
+                    UserHandle.USER_CURRENT);
+        }
+    }
+
+    @Override
+    public void setSafeMode(boolean safeMode) {
+        mSafeMode = safeMode;
+        performHapticFeedbackLw(null, safeMode
+                ? HapticFeedbackConstants.SAFE_MODE_ENABLED
+                : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
+    }
+
+    static long[] getLongIntArray(Resources r, int resid) {
+        int[] ar = r.getIntArray(resid);
+        if (ar == null) {
+            return null;
+        }
+        long[] out = new long[ar.length];
+        for (int i=0; i<ar.length; i++) {
+            out[i] = ar[i];
+        }
+        return out;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void systemReady() {
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
+        mKeyguardDelegate.onSystemReady();
+
+        readCameraLensCoverState();
+        updateUiMode();
+        synchronized (mLock) {
+            updateOrientationListenerLp();
+            mSystemReady = true;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    updateSettings();
+                }
+            });
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void systemBooted() {
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.bindService(mContext);
+            mKeyguardDelegate.onBootCompleted();
+        }
+        synchronized (mLock) {
+            mSystemBooted = true;
+        }
+        wakingUp();
+        screenTurningOn(null);
+    }
+
+    ProgressDialog mBootMsgDialog = null;
+
+    /** {@inheritDoc} */
+    @Override
+    public void showBootMessage(final CharSequence msg, final boolean always) {
+        mHandler.post(new Runnable() {
+            @Override public void run() {
+                if (mBootMsgDialog == null) {
+                    int theme;
+                    if (mContext.getPackageManager().hasSystemFeature(
+                            PackageManager.FEATURE_WATCH)) {
+                        theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
+                    } else if (mContext.getPackageManager().hasSystemFeature(
+                            PackageManager.FEATURE_TELEVISION)) {
+                        theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
+                    } else {
+                        theme = 0;
+                    }
+
+                    mBootMsgDialog = new ProgressDialog(mContext, theme) {
+                        // This dialog will consume all events coming in to
+                        // it, to avoid it trying to do things too early in boot.
+                        @Override public boolean dispatchKeyEvent(KeyEvent event) {
+                            return true;
+                        }
+                        @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+                            return true;
+                        }
+                        @Override public boolean dispatchTouchEvent(MotionEvent ev) {
+                            return true;
+                        }
+                        @Override public boolean dispatchTrackballEvent(MotionEvent ev) {
+                            return true;
+                        }
+                        @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+                            return true;
+                        }
+                        @Override public boolean dispatchPopulateAccessibilityEvent(
+                                AccessibilityEvent event) {
+                            return true;
+                        }
+                    };
+                    if (mContext.getPackageManager().isUpgrade()) {
+                        mBootMsgDialog.setTitle(R.string.android_upgrading_title);
+                    } else {
+                        mBootMsgDialog.setTitle(R.string.android_start_title);
+                    }
+                    mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+                    mBootMsgDialog.setIndeterminate(true);
+                    mBootMsgDialog.getWindow().setType(
+                            WindowManager.LayoutParams.TYPE_BOOT_PROGRESS);
+                    mBootMsgDialog.getWindow().addFlags(
+                            WindowManager.LayoutParams.FLAG_DIM_BEHIND
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
+                    mBootMsgDialog.getWindow().setDimAmount(1);
+                    WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
+                    lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+                    mBootMsgDialog.getWindow().setAttributes(lp);
+                    mBootMsgDialog.setCancelable(false);
+                    mBootMsgDialog.show();
+                }
+                mBootMsgDialog.setMessage(msg);
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void hideBootMessages() {
+        mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void userActivity() {
+        // ***************************************
+        // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+        // ***************************************
+        // THIS IS CALLED FROM DEEP IN THE POWER MANAGER
+        // WITH ITS LOCKS HELD.
+        //
+        // This code must be VERY careful about the locks
+        // it acquires.
+        // In fact, the current code acquires way too many,
+        // and probably has lurking deadlocks.
+
+        synchronized (mScreenLockTimeout) {
+            if (mLockScreenTimerActive) {
+                // reset the timer
+                mHandler.removeCallbacks(mScreenLockTimeout);
+                mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
+            }
+        }
+    }
+
+    class ScreenLockTimeout implements Runnable {
+        Bundle options;
+
+        @Override
+        public void run() {
+            synchronized (this) {
+                if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
+                if (mKeyguardDelegate != null) {
+                    mKeyguardDelegate.doKeyguardTimeout(options);
+                }
+                mLockScreenTimerActive = false;
+                options = null;
+            }
+        }
+
+        public void setLockOptions(Bundle options) {
+            this.options = options;
+        }
+    }
+
+    ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout();
+
+    @Override
+    public void lockNow(Bundle options) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+        mHandler.removeCallbacks(mScreenLockTimeout);
+        if (options != null) {
+            // In case multiple calls are made to lockNow, we don't wipe out the options
+            // until the runnable actually executes.
+            mScreenLockTimeout.setLockOptions(options);
+        }
+        mHandler.post(mScreenLockTimeout);
+    }
+
+    private void updateLockScreenTimeout() {
+        synchronized (mScreenLockTimeout) {
+            boolean enable = (mAllowLockscreenWhenOn && mAwake &&
+                    mKeyguardDelegate != null && mKeyguardDelegate.isSecure());
+            if (mLockScreenTimerActive != enable) {
+                if (enable) {
+                    if (localLOGV) Log.v(TAG, "setting lockscreen timer");
+                    mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
+                } else {
+                    if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
+                    mHandler.removeCallbacks(mScreenLockTimeout);
+                }
+                mLockScreenTimerActive = enable;
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void enableScreenAfterBoot() {
+        readLidState();
+        applyLidSwitchState();
+        updateRotation(true);
+    }
+
+    private void applyLidSwitchState() {
+        if (mLidState == LID_CLOSED && mLidControlsSleep) {
+            mPowerManager.goToSleep(SystemClock.uptimeMillis(),
+                    PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
+                    PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+        }
+
+        synchronized (mLock) {
+            updateWakeGestureListenerLp();
+        }
+    }
+
+    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
+            mWindowManager.updateRotation(alwaysSendConfiguration, false);
+        } catch (RemoteException e) {
+            // Ignore
+        }
+    }
+
+    void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
+        try {
+            //set orientation on WindowManager
+            mWindowManager.updateRotation(alwaysSendConfiguration, forceRelayout);
+        } catch (RemoteException e) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Return an Intent to launch the currently active dock app as home.  Returns
+     * null if the standard home should be launched, which is the case if any of the following is
+     * true:
+     * <ul>
+     *  <li>The device is not in either car mode or desk mode
+     *  <li>The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false
+     *  <li>The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false
+     *  <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME
+     *  <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME
+     * </ul>
+     * @return A dock intent.
+     */
+    Intent createHomeDockIntent() {
+        Intent intent = null;
+
+        // What home does is based on the mode, not the dock state.  That
+        // is, when in car mode you should be taken to car home regardless
+        // of whether we are actually in a car dock.
+        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
+            if (ENABLE_CAR_DOCK_HOME_CAPTURE) {
+                intent = mCarDockIntent;
+            }
+        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
+            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) {
+            return null;
+        }
+
+        ActivityInfo ai = null;
+        ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
+                intent,
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
+                mCurrentUserId);
+        if (info != null) {
+            ai = info.activityInfo;
+        }
+        if (ai != null
+                && ai.metaData != null
+                && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
+            intent = new Intent(intent);
+            intent.setClassName(ai.packageName, ai.name);
+            return intent;
+        }
+
+        return null;
+    }
+
+    void startDockOrHome(boolean fromHomeKey) {
+        awakenDreams();
+
+        Intent dock = createHomeDockIntent();
+        if (dock != null) {
+            try {
+                if (fromHomeKey) {
+                    dock.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
+                }
+                mContext.startActivityAsUser(dock, UserHandle.CURRENT);
+                return;
+            } catch (ActivityNotFoundException e) {
+            }
+        }
+
+        Intent intent;
+
+        if (fromHomeKey) {
+            intent = new Intent(mHomeIntent);
+            intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
+        } else {
+            intent = mHomeIntent;
+        }
+
+        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+    }
+
+    /**
+     * goes to the home screen
+     * @return whether it did anything
+     */
+    boolean goHome() {
+        if (false) {
+            // This code always brings home to the front.
+            try {
+                ActivityManagerNative.getDefault().stopAppSwitches();
+            } catch (RemoteException e) {
+            }
+            sendCloseSystemWindows();
+            startDockOrHome(false /*fromHomeKey*/);
+        } else {
+            // This code brings home to the front or, if it is already
+            // at the front, puts the device to sleep.
+            try {
+                if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) {
+                    /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry.
+                    Log.d(TAG, "UTS-TEST-MODE");
+                } else {
+                    ActivityManagerNative.getDefault().stopAppSwitches();
+                    sendCloseSystemWindows();
+                    Intent dock = createHomeDockIntent();
+                    if (dock != null) {
+                        int result = ActivityManagerNative.getDefault()
+                                .startActivityAsUser(null, null, dock,
+                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                        null, null, 0,
+                                        ActivityManager.START_FLAG_ONLY_IF_NEEDED,
+                                        null, null, UserHandle.USER_CURRENT);
+                        if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
+                            return false;
+                        }
+                    }
+                }
+                int result = ActivityManagerNative.getDefault()
+                        .startActivityAsUser(null, null, mHomeIntent,
+                                mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                null, null, 0,
+                                ActivityManager.START_FLAG_ONLY_IF_NEEDED,
+                                null, null, UserHandle.USER_CURRENT);
+                if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
+                    return false;
+                }
+            } catch (RemoteException ex) {
+                // bummer, the activity manager, which is in this process, is dead
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void setCurrentOrientationLw(int newOrientation) {
+        synchronized (mLock) {
+            if (newOrientation != mCurrentAppOrientation) {
+                mCurrentAppOrientation = newOrientation;
+                updateOrientationListenerLp();
+            }
+        }
+    }
+
+    private void performAuditoryFeedbackForAccessibilityIfNeed() {
+        if (!isGlobalAccessibilityGestureEnabled()) {
+            return;
+        }
+        AudioManager audioManager = (AudioManager) mContext.getSystemService(
+                Context.AUDIO_SERVICE);
+        if (audioManager.isSilentMode()) {
+            return;
+        }
+        Ringtone ringTone = RingtoneManager.getRingtone(mContext,
+                Settings.System.DEFAULT_NOTIFICATION_URI);
+        ringTone.setStreamType(AudioManager.STREAM_MUSIC);
+        ringTone.play();
+    }
+
+    private boolean isTheaterModeEnabled() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.THEATER_MODE_ON, 0) == 1;
+    }
+
+    private boolean isGlobalAccessibilityGestureEnabled() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
+    }
+
+    @Override
+    public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
+        if (!mVibrator.hasVibrator()) {
+            return false;
+        }
+        final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
+        if (hapticsDisabled && !always) {
+            return false;
+        }
+        long[] pattern = null;
+        switch (effectId) {
+            case HapticFeedbackConstants.LONG_PRESS:
+                pattern = mLongPressVibePattern;
+                break;
+            case HapticFeedbackConstants.VIRTUAL_KEY:
+                pattern = mVirtualKeyVibePattern;
+                break;
+            case HapticFeedbackConstants.KEYBOARD_TAP:
+                pattern = mKeyboardTapVibePattern;
+                break;
+            case HapticFeedbackConstants.CLOCK_TICK:
+                pattern = mClockTickVibePattern;
+                break;
+            case HapticFeedbackConstants.CALENDAR_DATE:
+                pattern = mCalendarDateVibePattern;
+                break;
+            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
+                pattern = mSafeModeDisabledVibePattern;
+                break;
+            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
+                pattern = mSafeModeEnabledVibePattern;
+                break;
+            default:
+                return false;
+        }
+        int owningUid;
+        String owningPackage;
+        if (win != null) {
+            owningUid = win.getOwningUid();
+            owningPackage = win.getOwningPackage();
+        } else {
+            owningUid = android.os.Process.myUid();
+            owningPackage = mContext.getOpPackageName();
+        }
+        if (pattern.length == 1) {
+            // One-shot vibration
+            mVibrator.vibrate(owningUid, owningPackage, pattern[0], VIBRATION_ATTRIBUTES);
+        } else {
+            // Pattern vibration
+            mVibrator.vibrate(owningUid, owningPackage, pattern, -1, VIBRATION_ATTRIBUTES);
+        }
+        return true;
+    }
+
+    @Override
+    public void keepScreenOnStartedLw() {
+    }
+
+    @Override
+    public void keepScreenOnStoppedLw() {
+        if (isKeyguardShowingAndNotOccluded()) {
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+        }
+    }
+
+    private int updateSystemUiVisibilityLw() {
+        // If there is no window focused, there will be nobody to handle the events
+        // anyway, so just hang on in whatever state we're in until things settle down.
+        final WindowState win = mFocusedWindow != null ? mFocusedWindow
+                : mTopFullscreenOpaqueWindowState;
+        if (win == null) {
+            return 0;
+        }
+        if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) {
+            // We are updating at a point where the keyguard has gotten
+            // focus, but we were last in a state where the top window is
+            // hiding it.  This is probably because the keyguard as been
+            // shown while the top window was displayed, so we want to ignore
+            // it here because this is just a very transient change and it
+            // will quickly lose focus once it correctly gets hidden.
+            return 0;
+        }
+
+        int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
+                & ~mResettingSystemUiFlags
+                & ~mForceClearedSystemUiFlags;
+        if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
+            tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
+        }
+        tmpVisibility = updateLightStatusBarLw(tmpVisibility);
+        final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
+        final int diff = visibility ^ mLastSystemUiFlags;
+        final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
+        if (diff == 0 && mLastFocusNeedsMenu == needsMenu
+                && mFocusedApp == win.getAppToken()) {
+            return 0;
+        }
+        mLastSystemUiFlags = visibility;
+        mLastFocusNeedsMenu = needsMenu;
+        mFocusedApp = win.getAppToken();
+        mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.setSystemUiVisibility(visibility, 0xffffffff, win.toString());
+                            statusbar.topAppWindowChanged(needsMenu);
+                        }
+                    } catch (RemoteException e) {
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        return diff;
+    }
+
+    private int updateLightStatusBarLw(int vis) {
+        WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
+                ? mStatusBar
+                : mTopFullscreenOpaqueOrDimmingWindowState;
+
+        if (statusColorWin != null) {
+            if (statusColorWin == mTopFullscreenOpaqueWindowState) {
+                // If the top fullscreen-or-dimming window is also the top fullscreen, respect
+                // its light flag.
+                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+                vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
+                        & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            } else if (statusColorWin != null && statusColorWin.isDimming()) {
+                // Otherwise if it's dimming, clear the light flag.
+                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            }
+        }
+        return vis;
+    }
+
+    private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+        // apply translucent bar vis flags
+        WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
+                ? mStatusBar
+                : mTopFullscreenOpaqueWindowState;
+        vis = mStatusBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
+        vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
+
+        // prevent status bar interaction from clearing certain flags
+        boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR;
+        if (statusBarHasFocus && !isStatusBarKeyguard()) {
+            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            if (mHideLockScreen) {
+                flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
+            }
+            vis = (vis & ~flags) | (oldVis & flags);
+        }
+
+        if (!areTranslucentBarsAllowed() && transWin != mStatusBar) {
+            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
+                    | View.SYSTEM_UI_TRANSPARENT);
+        }
+
+        // update status bar
+        boolean immersiveSticky =
+                (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+        boolean hideStatusBarWM =
+                mTopFullscreenOpaqueWindowState != null &&
+                (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
+                        & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+        boolean hideStatusBarSysui =
+                (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+        boolean hideNavBarSysui =
+                (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+
+        boolean transientStatusBarAllowed =
+                mStatusBar != null && (
+                hideStatusBarWM
+                || (hideStatusBarSysui && immersiveSticky)
+                || statusBarHasFocus);
+
+        boolean transientNavBarAllowed =
+                mNavigationBar != null &&
+                hideNavBarSysui && immersiveSticky;
+
+        boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
+                && !transientStatusBarAllowed && hideStatusBarSysui;
+        boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
+                && !transientNavBarAllowed;
+        if (denyTransientStatus || denyTransientNav) {
+            // clear the clearable flags instead
+            clearClearableFlagsLw();
+            vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
+        }
+
+        vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
+
+        // update navigation bar
+        boolean oldImmersiveMode = isImmersiveMode(oldVis);
+        boolean newImmersiveMode = isImmersiveMode(vis);
+        if (win != null && oldImmersiveMode != newImmersiveMode) {
+            final String pkg = win.getOwningPackage();
+            mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode,
+                    isUserSetupComplete());
+        }
+
+        vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
+
+        return vis;
+    }
+
+    private void clearClearableFlagsLw() {
+        int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
+        if (newVal != mResettingSystemUiFlags) {
+            mResettingSystemUiFlags = newVal;
+            mWindowManagerFuncs.reevaluateStatusBarVisibility();
+        }
+    }
+
+    private boolean isImmersiveMode(int vis) {
+        final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        return mNavigationBar != null
+                && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                && (vis & flags) != 0
+                && canHideNavigationBar();
+    }
+
+    /**
+     * @return whether the navigation or status bar can be made translucent
+     *
+     * This should return true unless touch exploration is not enabled or
+     * R.boolean.config_enableTranslucentDecor is false.
+     */
+    private boolean areTranslucentBarsAllowed() {
+        return mTranslucentDecorEnabled
+                && !mAccessibilityManager.isTouchExplorationEnabled();
+    }
+
+    // Use this instead of checking config_showNavigationBar so that it can be consistently
+    // overridden by qemu.hw.mainkeys in the emulator.
+    @Override
+    public boolean hasNavigationBar() {
+        return mHasNavigationBar;
+    }
+
+    @Override
+    public void setLastInputMethodWindowLw(WindowState ime, WindowState target) {
+        mLastInputMethodWindow = ime;
+        mLastInputMethodTargetWindow = target;
+    }
+
+    @Override
+    public int getInputMethodWindowVisibleHeightLw() {
+        return mDockBottom - mCurBottom;
+    }
+
+    @Override
+    public void setCurrentUserLw(int newUserId) {
+        mCurrentUserId = newUserId;
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.setCurrentUser(newUserId);
+        }
+        if (mStatusBarService != null) {
+            try {
+                mStatusBarService.setCurrentUser(newUserId);
+            } catch (RemoteException e) {
+                // oh well
+            }
+        }
+        setLastInputMethodWindowLw(null, null);
+    }
+
+    @Override
+    public boolean canMagnifyWindow(int windowType) {
+        switch (windowType) {
+            case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
+            case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG:
+            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
+            case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isTopLevelWindow(int windowType) {
+        if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW
+                && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+            return (windowType == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG);
+        }
+        return true;
+    }
+
+    @Override
+    public void dump(String prefix, PrintWriter pw, String[] args) {
+        pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
+                pw.print(" mSystemReady="); pw.print(mSystemReady);
+                pw.print(" mSystemBooted="); pw.println(mSystemBooted);
+        pw.print(prefix); pw.print("mLidState="); pw.print(mLidState);
+                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
+                pw.print(" mCameraLensCoverState="); pw.print(mCameraLensCoverState);
+                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
+        if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
+                || mForceClearedSystemUiFlags != 0) {
+            pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
+                    pw.print(Integer.toHexString(mLastSystemUiFlags));
+                    pw.print(" mResettingSystemUiFlags=0x");
+                    pw.print(Integer.toHexString(mResettingSystemUiFlags));
+                    pw.print(" mForceClearedSystemUiFlags=0x");
+                    pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
+        }
+        if (mLastFocusNeedsMenu) {
+            pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
+                    pw.println(mLastFocusNeedsMenu);
+        }
+        pw.print(prefix); pw.print("mWakeGestureEnabledSetting=");
+                pw.println(mWakeGestureEnabledSetting);
+
+        pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation);
+        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
+                pw.print(" mDockMode="); pw.print(mDockMode);
+                pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
+                pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
+        pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
+                pw.print(" mUserRotation="); pw.print(mUserRotation);
+                pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
+        pw.print(prefix); pw.print("mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
+        pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
+                pw.print(mCarDockEnablesAccelerometer);
+                pw.print(" mDeskDockEnablesAccelerometer=");
+                pw.println(mDeskDockEnablesAccelerometer);
+        pw.print(prefix); pw.print("mLidKeyboardAccessibility=");
+                pw.print(mLidKeyboardAccessibility);
+                pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
+                pw.print(" mLidControlsSleep="); pw.println(mLidControlsSleep);
+        pw.print(prefix);
+                pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
+                pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
+        pw.print(prefix);
+                pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior);
+                pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior);
+        pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput);
+        pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
+        pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
+                pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
+        pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
+                pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
+        pw.print(prefix); pw.print("mOrientationSensorEnabled=");
+                pw.println(mOrientationSensorEnabled);
+        pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
+                pw.print(","); pw.print(mOverscanScreenTop);
+                pw.print(") "); pw.print(mOverscanScreenWidth);
+                pw.print("x"); pw.println(mOverscanScreenHeight);
+        if (mOverscanLeft != 0 || mOverscanTop != 0
+                || mOverscanRight != 0 || mOverscanBottom != 0) {
+            pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
+                    pw.print(" top="); pw.print(mOverscanTop);
+                    pw.print(" right="); pw.print(mOverscanRight);
+                    pw.print(" bottom="); pw.println(mOverscanBottom);
+        }
+        pw.print(prefix); pw.print("mRestrictedOverscanScreen=(");
+                pw.print(mRestrictedOverscanScreenLeft);
+                pw.print(","); pw.print(mRestrictedOverscanScreenTop);
+                pw.print(") "); pw.print(mRestrictedOverscanScreenWidth);
+                pw.print("x"); pw.println(mRestrictedOverscanScreenHeight);
+        pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
+                pw.print(","); pw.print(mUnrestrictedScreenTop);
+                pw.print(") "); pw.print(mUnrestrictedScreenWidth);
+                pw.print("x"); pw.println(mUnrestrictedScreenHeight);
+        pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft);
+                pw.print(","); pw.print(mRestrictedScreenTop);
+                pw.print(") "); pw.print(mRestrictedScreenWidth);
+                pw.print("x"); pw.println(mRestrictedScreenHeight);
+        pw.print(prefix); pw.print("mStableFullscreen=("); pw.print(mStableFullscreenLeft);
+                pw.print(","); pw.print(mStableFullscreenTop);
+                pw.print(")-("); pw.print(mStableFullscreenRight);
+                pw.print(","); pw.print(mStableFullscreenBottom); pw.println(")");
+        pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
+                pw.print(","); pw.print(mStableTop);
+                pw.print(")-("); pw.print(mStableRight);
+                pw.print(","); pw.print(mStableBottom); pw.println(")");
+        pw.print(prefix); pw.print("mSystem=("); pw.print(mSystemLeft);
+                pw.print(","); pw.print(mSystemTop);
+                pw.print(")-("); pw.print(mSystemRight);
+                pw.print(","); pw.print(mSystemBottom); pw.println(")");
+        pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
+                pw.print(","); pw.print(mCurTop);
+                pw.print(")-("); pw.print(mCurRight);
+                pw.print(","); pw.print(mCurBottom); pw.println(")");
+        pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft);
+                pw.print(","); pw.print(mContentTop);
+                pw.print(")-("); pw.print(mContentRight);
+                pw.print(","); pw.print(mContentBottom); pw.println(")");
+        pw.print(prefix); pw.print("mVoiceContent=("); pw.print(mVoiceContentLeft);
+                pw.print(","); pw.print(mVoiceContentTop);
+                pw.print(")-("); pw.print(mVoiceContentRight);
+                pw.print(","); pw.print(mVoiceContentBottom); pw.println(")");
+        pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
+                pw.print(","); pw.print(mDockTop);
+                pw.print(")-("); pw.print(mDockRight);
+                pw.print(","); pw.print(mDockBottom); pw.println(")");
+        pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
+                pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
+        pw.print(prefix); pw.print("mShowingLockscreen="); pw.print(mShowingLockscreen);
+                pw.print(" mShowingDream="); pw.print(mShowingDream);
+                pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
+        if (mLastInputMethodWindow != null) {
+            pw.print(prefix); pw.print("mLastInputMethodWindow=");
+                    pw.println(mLastInputMethodWindow);
+        }
+        if (mLastInputMethodTargetWindow != null) {
+            pw.print(prefix); pw.print("mLastInputMethodTargetWindow=");
+                    pw.println(mLastInputMethodTargetWindow);
+        }
+        if (mStatusBar != null) {
+            pw.print(prefix); pw.print("mStatusBar=");
+                    pw.print(mStatusBar); pw.print(" isStatusBarKeyguard=");
+                    pw.println(isStatusBarKeyguard());
+        }
+        if (mNavigationBar != null) {
+            pw.print(prefix); pw.print("mNavigationBar=");
+                    pw.println(mNavigationBar);
+        }
+        if (mFocusedWindow != null) {
+            pw.print(prefix); pw.print("mFocusedWindow=");
+                    pw.println(mFocusedWindow);
+        }
+        if (mFocusedApp != null) {
+            pw.print(prefix); pw.print("mFocusedApp=");
+                    pw.println(mFocusedApp);
+        }
+        if (mWinDismissingKeyguard != null) {
+            pw.print(prefix); pw.print("mWinDismissingKeyguard=");
+                    pw.println(mWinDismissingKeyguard);
+        }
+        if (mTopFullscreenOpaqueWindowState != null) {
+            pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
+                    pw.println(mTopFullscreenOpaqueWindowState);
+        }
+        if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
+            pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
+                    pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
+        }
+        if (mForcingShowNavBar) {
+            pw.print(prefix); pw.print("mForcingShowNavBar=");
+                    pw.println(mForcingShowNavBar); pw.print( "mForcingShowNavBarLayer=");
+                    pw.println(mForcingShowNavBarLayer);
+        }
+        pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
+                pw.print(" mHideLockScreen="); pw.println(mHideLockScreen);
+        pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
+                pw.print(" mForceStatusBarFromKeyguard=");
+                pw.println(mForceStatusBarFromKeyguard);
+        pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
+                pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
+                pw.print(" mHomePressed="); pw.println(mHomePressed);
+        pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
+                pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
+                pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
+        pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior);
+                pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior);
+                pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior);
+        pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation);
+                pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
+        pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
+                pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
+        pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
+                pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
+        pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
+
+        mGlobalKeyManager.dump(prefix, pw);
+        mStatusBarController.dump(pw, prefix);
+        mNavigationBarController.dump(pw, prefix);
+        PolicyControl.dump(prefix, pw);
+
+        if (mWakeGestureListener != null) {
+            mWakeGestureListener.dump(pw, prefix);
+        }
+        if (mOrientationListener != null) {
+            mOrientationListener.dump(pw, prefix);
+        }
+        if (mBurnInProtectionHelper != null) {
+            mBurnInProtectionHelper.dump(prefix, pw);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
new file mode 100644
index 0000000..dbafc42
--- /dev/null
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -0,0 +1,258 @@
+/*
+ * 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.policy;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.WindowState;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Runtime adjustments applied to the global window policy.
+ *
+ * This includes forcing immersive mode behavior for one or both system bars (based on a package
+ * list) and permanently disabling immersive mode confirmations for specific packages.
+ *
+ * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs.
+ * e.g.
+ *   to force immersive mode everywhere:
+ *     "immersive.full=*"
+ *   to force transient status for all apps except a specific package:
+ *     "immersive.status=apps,-com.package"
+ *   to disable the immersive mode confirmations for specific packages:
+ *     "immersive.preconfirms=com.package.one,com.package.two"
+ *
+ * Separate multiple name-value pairs with ':'
+ *   e.g. "immersive.status=apps:immersive.preconfirms=*"
+ */
+public class PolicyControl {
+    private static String TAG = "PolicyControl";
+    private static boolean DEBUG = false;
+
+    private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+    private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+    private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+    private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
+
+    private static String sSettingValue;
+    private static Filter sImmersivePreconfirmationsFilter;
+    private static Filter sImmersiveStatusFilter;
+    private static Filter sImmersiveNavigationFilter;
+
+    public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+        attrs = attrs != null ? attrs : win.getAttrs();
+        int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.STATUS_BAR_TRANSLUCENT);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
+            vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.NAVIGATION_BAR_TRANSLUCENT);
+        }
+        return vis;
+    }
+
+    public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+        attrs = attrs != null ? attrs : win.getAttrs();
+        int flags = attrs.flags;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+            flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+                    | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+        }
+        if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
+            flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+        }
+        return flags;
+    }
+
+    public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+        final LayoutParams attrs = win != null ? win.getAttrs() : null;
+        if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
+            clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+        }
+        return clearableFlags;
+    }
+
+    public static boolean disableImmersiveConfirmation(String pkg) {
+        return (sImmersivePreconfirmationsFilter != null
+                && sImmersivePreconfirmationsFilter.matches(pkg))
+                || ActivityManager.isRunningInTestHarness();
+    }
+
+    public static void reloadFromSetting(Context context) {
+        if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+        String value = null;
+        try {
+            value = Settings.Global.getStringForUser(context.getContentResolver(),
+                    Settings.Global.POLICY_CONTROL,
+                    UserHandle.USER_CURRENT);
+            if (sSettingValue != null && sSettingValue.equals(value)) return;
+            setFilters(value);
+            sSettingValue = value;
+        } catch (Throwable t) {
+            Slog.w(TAG, "Error loading policy control, value=" + value, t);
+        }
+    }
+
+    public static void dump(String prefix, PrintWriter pw) {
+        dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
+        dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
+        dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
+    }
+
+    private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
+        if (filter == null) {
+            pw.println("null");
+        } else {
+            filter.dump(pw); pw.println();
+        }
+    }
+
+    private static void setFilters(String value) {
+        if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+        sImmersiveStatusFilter = null;
+        sImmersiveNavigationFilter = null;
+        sImmersivePreconfirmationsFilter = null;
+        if (value != null) {
+            String[] nvps = value.split(":");
+            for (String nvp : nvps) {
+                int i = nvp.indexOf('=');
+                if (i == -1) continue;
+                String n = nvp.substring(0, i);
+                String v = nvp.substring(i + 1);
+                if (n.equals(NAME_IMMERSIVE_FULL)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+                    if (sImmersivePreconfirmationsFilter == null) {
+                        sImmersivePreconfirmationsFilter = f;
+                    }
+                } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveStatusFilter = f;
+                } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+                    Filter f = Filter.parse(v);
+                    sImmersiveNavigationFilter = f;
+                    if (sImmersivePreconfirmationsFilter == null) {
+                        sImmersivePreconfirmationsFilter = f;
+                    }
+                } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
+                    Filter f = Filter.parse(v);
+                    sImmersivePreconfirmationsFilter = f;
+                }
+            }
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+            Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+            Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
+        }
+    }
+
+    private static class Filter {
+        private static final String ALL = "*";
+        private static final String APPS = "apps";
+
+        private final ArraySet<String> mWhitelist;
+        private final ArraySet<String> mBlacklist;
+
+        private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+            mWhitelist = whitelist;
+            mBlacklist = blacklist;
+        }
+
+        boolean matches(LayoutParams attrs) {
+            if (attrs == null) return false;
+            boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+            if (isApp && mBlacklist.contains(APPS)) return false;
+            if (onBlacklist(attrs.packageName)) return false;
+            if (isApp && mWhitelist.contains(APPS)) return true;
+            return onWhitelist(attrs.packageName);
+        }
+
+        boolean matches(String packageName) {
+            return !onBlacklist(packageName) && onWhitelist(packageName);
+        }
+
+        private boolean onBlacklist(String packageName) {
+            return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+        }
+
+        private boolean onWhitelist(String packageName) {
+            return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+        }
+
+        void dump(PrintWriter pw) {
+            pw.print("Filter[");
+            dump("whitelist", mWhitelist, pw); pw.print(',');
+            dump("blacklist", mBlacklist, pw); pw.print(']');
+        }
+
+        private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+            pw.print(name); pw.print("=(");
+            final int n = set.size();
+            for (int i = 0; i < n; i++) {
+                if (i > 0) pw.print(',');
+                pw.print(set.valueAt(i));
+            }
+            pw.print(')');
+        }
+
+        @Override
+        public String toString() {
+            StringWriter sw = new StringWriter();
+            dump(new PrintWriter(sw, true));
+            return sw.toString();
+        }
+
+        // value = comma-delimited list of tokens, where token = (package name|apps|*)
+        // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
+        static Filter parse(String value) {
+            if (value == null) return null;
+            ArraySet<String> whitelist = new ArraySet<String>();
+            ArraySet<String> blacklist = new ArraySet<String>();
+            for (String token : value.split(",")) {
+                token = token.trim();
+                if (token.startsWith("-") && token.length() > 1) {
+                    token = token.substring(1);
+                    blacklist.add(token);
+                } else {
+                    whitelist.add(token);
+                }
+            }
+            return new Filter(whitelist, blacklist);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/RecentApplicationsBackground.java b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
new file mode 100644
index 0000000..694a110
--- /dev/null
+++ b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * A vertical linear layout.  However, instead of drawing the background
+ * behnd the items, it draws the background outside the items based on the
+ * padding.  If there isn't enough room to draw both, it clips the background
+ * instead of the contents.
+ */
+public class RecentApplicationsBackground extends LinearLayout {
+    private static final String TAG = "RecentApplicationsBackground";
+
+    private boolean mBackgroundSizeChanged;
+    private Drawable mBackground;
+    private Rect mTmp0 = new Rect();
+    private Rect mTmp1 = new Rect();
+
+    public RecentApplicationsBackground(Context context) {
+        this(context, null);
+        init();
+    }
+
+    public RecentApplicationsBackground(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        mBackground = getBackground();
+        setBackgroundDrawable(null);
+        setPadding(0, 0, 0, 0);
+        setGravity(Gravity.CENTER);
+    }
+
+    @Override
+    protected boolean setFrame(int left, int top, int right, int bottom) {
+        setWillNotDraw(false);
+        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
+            mBackgroundSizeChanged = true;
+        }
+        return super.setFrame(left, top, right, bottom);
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mBackground || super.verifyDrawable(who);
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+        if (mBackground != null) mBackground.jumpToCurrentState();
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        Drawable d = mBackground;
+        if (d != null && d.isStateful()) {
+            d.setState(getDrawableState());
+        }
+        super.drawableStateChanged();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final Drawable background = mBackground;
+        if (background != null) {
+            if (mBackgroundSizeChanged) {
+                mBackgroundSizeChanged = false;
+                Rect chld = mTmp0;
+                Rect bkg = mTmp1;
+                mBackground.getPadding(bkg);
+                getChildBounds(chld);
+                // This doesn't clamp to this view's bounds, which is what we want,
+                // so that the drawing is clipped.
+                final int top = chld.top - bkg.top;
+                final int bottom = chld.bottom + bkg.bottom;
+                // The background here is a gradient that wants to
+                // extend the full width of the screen (whatever that
+                // may be).
+                int left, right;
+                if (false) {
+                    // This limits the width of the drawable.
+                    left = chld.left - bkg.left;
+                    right = chld.right + bkg.right;
+                } else {
+                    // This expands it to full width.
+                    left = 0;
+                    right = getRight();
+                }
+                background.setBounds(left, top, right, bottom);
+            }
+        }
+        mBackground.draw(canvas);
+
+        if (false) {
+            android.graphics.Paint p = new android.graphics.Paint();
+            p.setColor(0x88ffff00);
+            canvas.drawRect(background.getBounds(), p);
+        }
+        canvas.drawARGB((int)(0.75*0xff), 0, 0, 0);
+
+        super.draw(canvas);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mBackground.setCallback(this);
+        setWillNotDraw(false);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mBackground.setCallback(null);
+    }
+    
+    private void getChildBounds(Rect r) {
+        r.left = r.top = Integer.MAX_VALUE;
+        r.bottom = r.right = Integer.MIN_VALUE;
+        final int N = getChildCount();
+        for (int i=0; i<N; i++) {
+            View v = getChildAt(i);
+            if (v.getVisibility() == View.VISIBLE) {
+                r.left = Math.min(r.left, v.getLeft());
+                r.top = Math.min(r.top, v.getTop());
+                r.right = Math.max(r.right, v.getRight());
+                r.bottom = Math.max(r.bottom, v.getBottom());
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
new file mode 100644
index 0000000..76f56bc
--- /dev/null
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+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.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyCharacterMap;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Manages quick launch shortcuts by:
+ * <li> Keeping the local copy in sync with the database (this is an observer)
+ * <li> Returning a shortcut-matching intent to clients
+ */
+class ShortcutManager {
+    private static final String TAG = "ShortcutManager";
+
+    private static final String TAG_BOOKMARKS = "bookmarks";
+    private static final String TAG_BOOKMARK = "bookmark";
+
+    private static final String ATTRIBUTE_PACKAGE = "package";
+    private static final String ATTRIBUTE_CLASS = "class";
+    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
+    private static final String ATTRIBUTE_CATEGORY = "category";
+
+    private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
+
+    private final Context mContext;
+    
+    public ShortcutManager(Context context) {
+        mContext = context;
+        loadShortcuts();
+    }
+
+    /**
+     * Gets the shortcut intent for a given keycode+modifier. Make sure you
+     * strip whatever modifier is used for invoking shortcuts (for example,
+     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
+     * 'Sym' bit from the modifiers before calling this method.
+     * <p>
+     * This will first try an exact match (with modifiers), and then try a
+     * match without modifiers (primary character on a key).
+     * 
+     * @param kcm The key character map of the device on which the key was pressed.
+     * @param keyCode The key code.
+     * @param metaState The meta state, omitting any modifiers that were used
+     * to invoke the shortcut.
+     * @return The intent that matches the shortcut, or null if not found.
+     */
+    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
+        ShortcutInfo shortcut = null;
+
+        // First try the exact keycode (with modifiers).
+        int shortcutChar = kcm.get(keyCode, metaState);
+        if (shortcutChar != 0) {
+            shortcut = mShortcuts.get(shortcutChar);
+        }
+
+        // Next try the primary character on that key.
+        if (shortcut == null) {
+            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+            if (shortcutChar != 0) {
+                shortcut = mShortcuts.get(shortcutChar);
+            }
+        }
+
+        return (shortcut != null) ? shortcut.intent : null;
+    }
+
+    private void loadShortcuts() {
+        PackageManager packageManager = mContext.getPackageManager();
+        try {
+            XmlResourceParser parser = mContext.getResources().getXml(
+                    com.android.internal.R.xml.bookmarks);
+            XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                if (!TAG_BOOKMARK.equals(parser.getName())) {
+                    break;
+                }
+
+                String packageName = parser.getAttributeValue(null, ATTRIBUTE_PACKAGE);
+                String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
+                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
+                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+
+                if (TextUtils.isEmpty(shortcutName)) {
+                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
+                    continue;
+                }
+
+                final int shortcutChar = shortcutName.charAt(0);
+
+                final Intent intent;
+                final String title;
+                if (packageName != null && className != null) {
+                    ActivityInfo info = null;
+                    ComponentName componentName = new ComponentName(packageName, className);
+                    try {
+                        info = packageManager.getActivityInfo(componentName, 0);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        String[] packages = packageManager.canonicalToCurrentPackageNames(
+                                new String[] { packageName });
+                        componentName = new ComponentName(packages[0], className);
+                        try {
+                            info = packageManager.getActivityInfo(componentName, 0);
+                        } catch (PackageManager.NameNotFoundException e1) {
+                            Log.w(TAG, "Unable to add bookmark: " + packageName
+                                    + "/" + className, e);
+                            continue;
+                        }
+                    }
+
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
+                    intent.setComponent(componentName);
+                    title = info.loadLabel(packageManager).toString();
+                } else if (categoryName != null) {
+                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
+                    title = "";
+                } else {
+                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+                            + ": missing package/class or category attributes");
+                    continue;
+                }
+
+                ShortcutInfo shortcut = new ShortcutInfo(title, intent);
+                mShortcuts.put(shortcutChar, shortcut);
+            }
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        } catch (IOException e) {
+            Log.w(TAG, "Got exception parsing bookmarks.", e);
+        }
+    }
+
+    private static final class ShortcutInfo {
+        public final String title;
+        public final Intent intent;
+
+        public ShortcutInfo(String title, Intent intent) {
+            this.title = title;
+            this.intent = intent;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
new file mode 100644
index 0000000..d1b50da
--- /dev/null
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.policy;
+
+import android.app.StatusBarManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Interpolator;
+import android.view.animation.TranslateAnimation;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import static android.view.WindowManagerInternal.*;
+
+/**
+ * Implements status bar specific behavior.
+ */
+public class StatusBarController extends BarController {
+
+    private static final long TRANSITION_DURATION = 120L;
+
+    private final AppTransitionListener mAppTransitionListener
+            = new AppTransitionListener() {
+
+        @Override
+        public void onAppTransitionPendingLocked() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.appTransitionPending();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is pending", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
+                final Animation openAnimation, final Animation closeAnimation) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            long startTime = calculateStatusBarTransitionStartTime(openAnimation,
+                                    closeAnimation);
+                            statusbar.appTransitionStarting(startTime, TRANSITION_DURATION);
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is starting", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onAppTransitionCancelledLocked() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.appTransitionCancelled();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is cancelled", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+    };
+
+    public StatusBarController() {
+        super("StatusBar",
+                View.STATUS_BAR_TRANSIENT,
+                View.STATUS_BAR_UNHIDE,
+                View.STATUS_BAR_TRANSLUCENT,
+                StatusBarManager.WINDOW_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+    }
+
+    public AppTransitionListener getAppTransitionListener() {
+        return mAppTransitionListener;
+    }
+
+    /**
+     * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
+     * calculates the timings for the corresponding status bar transition.
+     *
+     * @return the desired start time of the status bar transition, in uptime millis
+     */
+    private long calculateStatusBarTransitionStartTime(Animation openAnimation,
+            Animation closeAnimation) {
+        if (openAnimation != null && closeAnimation != null) {
+            TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
+            TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
+            if (openTranslateAnimation != null) {
+
+                // Some interpolators are extremely quickly mostly finished, but not completely. For
+                // our purposes, we need to find the fraction for which ther interpolator is mostly
+                // there, and use that value for the calculation.
+                float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
+                return SystemClock.uptimeMillis()
+                        + openTranslateAnimation.getStartOffset()
+                        + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
+            } else if (closeTranslateAnimation != null) {
+                return SystemClock.uptimeMillis();
+            } else {
+                return SystemClock.uptimeMillis();
+            }
+        } else {
+            return SystemClock.uptimeMillis();
+        }
+    }
+
+    /**
+     * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
+     *
+     * @return the found animation, {@code null} otherwise
+     */
+    private TranslateAnimation findTranslateAnimation(Animation animation) {
+        if (animation instanceof TranslateAnimation) {
+            return (TranslateAnimation) animation;
+        } else if (animation instanceof AnimationSet) {
+            AnimationSet set = (AnimationSet) animation;
+            for (int i = 0; i < set.getAnimations().size(); i++) {
+                Animation a = set.getAnimations().get(i);
+                if (a instanceof TranslateAnimation) {
+                    return (TranslateAnimation) a;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
+     * {@code interpolator(t + eps) > 0.99}.
+     */
+    private float findAlmostThereFraction(Interpolator interpolator) {
+        float val = 0.5f;
+        float adj = 0.25f;
+        while (adj >= 0.01f) {
+            if (interpolator.getInterpolation(val) < 0.99f) {
+                val += adj;
+            } else {
+                val -= adj;
+            }
+            adj /= 2;
+        }
+        return val;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
new file mode 100644
index 0000000..cfa631f
--- /dev/null
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -0,0 +1,197 @@
+/*
+ * 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.policy;
+
+import android.content.Context;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+/*
+ * Listens for system-wide input gestures, firing callbacks when detected.
+ * @hide
+ */
+public class SystemGesturesPointerEventListener implements PointerEventListener {
+    private static final String TAG = "SystemGestures";
+    private static final boolean DEBUG = false;
+    private static final long SWIPE_TIMEOUT_MS = 500;
+    private static final int MAX_TRACKED_POINTERS = 32;  // max per input system
+    private static final int UNTRACKED_POINTER = -1;
+
+    private static final int SWIPE_NONE = 0;
+    private static final int SWIPE_FROM_TOP = 1;
+    private static final int SWIPE_FROM_BOTTOM = 2;
+    private static final int SWIPE_FROM_RIGHT = 3;
+
+    private final int mSwipeStartThreshold;
+    private final int mSwipeDistanceThreshold;
+    private final Callbacks mCallbacks;
+    private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS];
+    private final float[] mDownX = new float[MAX_TRACKED_POINTERS];
+    private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
+    private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
+
+    int screenHeight;
+    int screenWidth;
+    private int mDownPointers;
+    private boolean mSwipeFireable;
+    private boolean mDebugFireable;
+
+    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+        mCallbacks = checkNull("callbacks", callbacks);
+        mSwipeStartThreshold = checkNull("context", context).getResources()
+                .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mSwipeDistanceThreshold = mSwipeStartThreshold;
+        if (DEBUG) Slog.d(TAG,  "mSwipeStartThreshold=" + mSwipeStartThreshold
+                + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold);
+    }
+
+    private static <T> T checkNull(String name, T arg) {
+        if (arg == null) {
+            throw new IllegalArgumentException(name + " must not be null");
+        }
+        return arg;
+    }
+
+    @Override
+    public void onPointerEvent(MotionEvent event) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mSwipeFireable = true;
+                mDebugFireable = true;
+                mDownPointers = 0;
+                captureDown(event, 0);
+                break;
+            case MotionEvent.ACTION_POINTER_DOWN:
+                captureDown(event, event.getActionIndex());
+                if (mDebugFireable) {
+                    mDebugFireable = event.getPointerCount() < 5;
+                    if (!mDebugFireable) {
+                        if (DEBUG) Slog.d(TAG, "Firing debug");
+                        mCallbacks.onDebug();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mSwipeFireable) {
+                    final int swipe = detectSwipe(event);
+                    mSwipeFireable = swipe == SWIPE_NONE;
+                    if (swipe == SWIPE_FROM_TOP) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromTop");
+                        mCallbacks.onSwipeFromTop();
+                    } else if (swipe == SWIPE_FROM_BOTTOM) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromBottom");
+                        mCallbacks.onSwipeFromBottom();
+                    } else if (swipe == SWIPE_FROM_RIGHT) {
+                        if (DEBUG) Slog.d(TAG, "Firing onSwipeFromRight");
+                        mCallbacks.onSwipeFromRight();
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mSwipeFireable = false;
+                mDebugFireable = false;
+                break;
+            default:
+                if (DEBUG) Slog.d(TAG, "Ignoring " + event);
+        }
+    }
+
+    private void captureDown(MotionEvent event, int pointerIndex) {
+        final int pointerId = event.getPointerId(pointerIndex);
+        final int i = findIndex(pointerId);
+        if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
+                " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
+        if (i != UNTRACKED_POINTER) {
+            mDownX[i] = event.getX(pointerIndex);
+            mDownY[i] = event.getY(pointerIndex);
+            mDownTime[i] = event.getEventTime();
+            if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
+                    " down x=" + mDownX[i] + " y=" + mDownY[i]);
+        }
+    }
+
+    private int findIndex(int pointerId) {
+        for (int i = 0; i < mDownPointers; i++) {
+            if (mDownPointerId[i] == pointerId) {
+                return i;
+            }
+        }
+        if (mDownPointers == MAX_TRACKED_POINTERS || pointerId == MotionEvent.INVALID_POINTER_ID) {
+            return UNTRACKED_POINTER;
+        }
+        mDownPointerId[mDownPointers++] = pointerId;
+        return mDownPointers - 1;
+    }
+
+    private int detectSwipe(MotionEvent move) {
+        final int historySize = move.getHistorySize();
+        final int pointerCount = move.getPointerCount();
+        for (int p = 0; p < pointerCount; p++) {
+            final int pointerId = move.getPointerId(p);
+            final int i = findIndex(pointerId);
+            if (i != UNTRACKED_POINTER) {
+                for (int h = 0; h < historySize; h++) {
+                    final long time = move.getHistoricalEventTime(h);
+                    final float x = move.getHistoricalX(p, h);
+                    final float y = move.getHistoricalY(p,  h);
+                    final int swipe = detectSwipe(i, time, x, y);
+                    if (swipe != SWIPE_NONE) {
+                        return swipe;
+                    }
+                }
+                final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p));
+                if (swipe != SWIPE_NONE) {
+                    return swipe;
+                }
+            }
+        }
+        return SWIPE_NONE;
+    }
+
+    private int detectSwipe(int i, long time, float x, float y) {
+        final float fromX = mDownX[i];
+        final float fromY = mDownY[i];
+        final long elapsed = time - mDownTime[i];
+        if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i]
+                + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed);
+        if (fromY <= mSwipeStartThreshold
+                && y > fromY + mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_TOP;
+        }
+        if (fromY >= screenHeight - mSwipeStartThreshold
+                && y < fromY - mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_BOTTOM;
+        }
+        if (fromX >= screenWidth - mSwipeStartThreshold
+                && x < fromX - mSwipeDistanceThreshold
+                && elapsed < SWIPE_TIMEOUT_MS) {
+            return SWIPE_FROM_RIGHT;
+        }
+        return SWIPE_NONE;
+    }
+
+    interface Callbacks {
+        void onSwipeFromTop();
+        void onSwipeFromBottom();
+        void onSwipeFromRight();
+        void onDebug();
+    }
+}
diff --git a/services/core/java/com/android/server/policy/WakeGestureListener.java b/services/core/java/com/android/server/policy/WakeGestureListener.java
new file mode 100644
index 0000000..1d5d7ba
--- /dev/null
+++ b/services/core/java/com/android/server/policy/WakeGestureListener.java
@@ -0,0 +1,100 @@
+/*
+ * 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.policy;
+
+import android.os.Handler;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+
+import java.io.PrintWriter;
+
+/**
+ * Watches for wake gesture sensor events then invokes the listener.
+ */
+public abstract class WakeGestureListener {
+    private static final String TAG = "WakeGestureListener";
+
+    private final SensorManager mSensorManager;
+    private final Handler mHandler;
+
+    private final Object mLock = new Object();
+
+    private boolean mTriggerRequested;
+    private Sensor mSensor;
+
+    public WakeGestureListener(Context context, Handler handler) {
+        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        mHandler = handler;
+
+        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE);
+    }
+
+    public abstract void onWakeUp();
+
+    public boolean isSupported() {
+        synchronized (mLock) {
+            return mSensor != null;
+        }
+    }
+
+    public void requestWakeUpTrigger() {
+        synchronized (mLock) {
+            if (mSensor != null && !mTriggerRequested) {
+                mTriggerRequested = true;
+                mSensorManager.requestTriggerSensor(mListener, mSensor);
+            }
+        }
+    }
+
+    public void cancelWakeUpTrigger() {
+        synchronized (mLock) {
+            if (mSensor != null && mTriggerRequested) {
+                mTriggerRequested = false;
+                mSensorManager.cancelTriggerSensor(mListener, mSensor);
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        synchronized (mLock) {
+            pw.println(prefix + TAG);
+            prefix += "  ";
+            pw.println(prefix + "mTriggerRequested=" + mTriggerRequested);
+            pw.println(prefix + "mSensor=" + mSensor);
+        }
+    }
+
+    private final TriggerEventListener mListener = new TriggerEventListener() {
+        @Override
+        public void onTrigger(TriggerEvent event) {
+            synchronized (mLock) {
+                mTriggerRequested = false;
+                mHandler.post(mWakeUpRunnable);
+            }
+        }
+    };
+
+    private final Runnable mWakeUpRunnable = new Runnable() {
+        @Override
+        public void run() {
+            onWakeUp();
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
new file mode 100644
index 0000000..0118127
--- /dev/null
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -0,0 +1,800 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+
+/**
+ * A special helper class used by the WindowManager
+ * for receiving notifications from the SensorManager when
+ * the orientation of the device has changed.
+ *
+ * NOTE: If changing anything here, please run the API demo
+ * "App/Activity/Screen Orientation" to ensure that all orientation
+ * modes still work correctly.
+ *
+ * You can also visualize the behavior of the WindowOrientationListener.
+ * Refer to frameworks/base/tools/orientationplot/README.txt for details.
+ *
+ * @hide
+ */
+public abstract class WindowOrientationListener {
+    private static final String TAG = "WindowOrientationListener";
+    private static final boolean LOG = SystemProperties.getBoolean(
+            "debug.orientation.log", false);
+
+    private static final boolean USE_GRAVITY_SENSOR = false;
+
+    private Handler mHandler;
+    private SensorManager mSensorManager;
+    private boolean mEnabled;
+    private int mRate;
+    private Sensor mSensor;
+    private SensorEventListenerImpl mSensorEventListener;
+    private int mCurrentRotation = -1;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Creates a new WindowOrientationListener.
+     * 
+     * @param context for the WindowOrientationListener.
+     * @param handler Provides the Looper for receiving sensor updates.
+     */
+    public WindowOrientationListener(Context context, Handler handler) {
+        this(context, handler, SensorManager.SENSOR_DELAY_UI);
+    }
+    
+    /**
+     * Creates a new WindowOrientationListener.
+     * 
+     * @param context for the WindowOrientationListener.
+     * @param handler Provides the Looper for receiving sensor updates.
+     * @param rate at which sensor events are processed (see also
+     * {@link android.hardware.SensorManager SensorManager}). Use the default
+     * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
+     * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
+     *
+     * This constructor is private since no one uses it.
+     */
+    private WindowOrientationListener(Context context, Handler handler, int rate) {
+        mHandler = handler;
+        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        mRate = rate;
+        mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
+                ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
+        if (mSensor != null) {
+            // Create listener only if sensors do exist
+            mSensorEventListener = new SensorEventListenerImpl();
+        }
+    }
+
+    /**
+     * Enables the WindowOrientationListener so it will monitor the sensor and call
+     * {@link #onProposedRotationChanged(int)} when the device orientation changes.
+     */
+    public void enable() {
+        synchronized (mLock) {
+            if (mSensor == null) {
+                Log.w(TAG, "Cannot detect sensors. Not enabled");
+                return;
+            }
+            if (mEnabled == false) {
+                if (LOG) {
+                    Log.d(TAG, "WindowOrientationListener enabled");
+                }
+                mSensorEventListener.resetLocked();
+                mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
+                mEnabled = true;
+            }
+        }
+    }
+
+    /**
+     * Disables the WindowOrientationListener.
+     */
+    public void disable() {
+        synchronized (mLock) {
+            if (mSensor == null) {
+                Log.w(TAG, "Cannot detect sensors. Invalid disable");
+                return;
+            }
+            if (mEnabled == true) {
+                if (LOG) {
+                    Log.d(TAG, "WindowOrientationListener disabled");
+                }
+                mSensorManager.unregisterListener(mSensorEventListener);
+                mEnabled = false;
+            }
+        }
+    }
+
+    /**
+     * Sets the current rotation.
+     *
+     * @param rotation The current rotation.
+     */
+    public void setCurrentRotation(int rotation) {
+        synchronized (mLock) {
+            mCurrentRotation = rotation;
+        }
+    }
+
+    /**
+     * Gets the proposed rotation.
+     *
+     * This method only returns a rotation if the orientation listener is certain
+     * of its proposal.  If the rotation is indeterminate, returns -1.
+     *
+     * @return The proposed rotation, or -1 if unknown.
+     */
+    public int getProposedRotation() {
+        synchronized (mLock) {
+            if (mEnabled) {
+                return mSensorEventListener.getProposedRotationLocked();
+            }
+            return -1;
+        }
+    }
+
+    /**
+     * Returns true if sensor is enabled and false otherwise
+     */
+    public boolean canDetectOrientation() {
+        synchronized (mLock) {
+            return mSensor != null;
+        }
+    }
+
+    /**
+     * Called when the rotation view of the device has changed.
+     *
+     * This method is called whenever the orientation becomes certain of an orientation.
+     * It is called each time the orientation determination transitions from being
+     * uncertain to being certain again, even if it is the same orientation as before.
+     *
+     * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
+     * @see android.view.Surface
+     */
+    public abstract void onProposedRotationChanged(int rotation);
+
+    public void dump(PrintWriter pw, String prefix) {
+        synchronized (mLock) {
+            pw.println(prefix + TAG);
+            prefix += "  ";
+            pw.println(prefix + "mEnabled=" + mEnabled);
+            pw.println(prefix + "mCurrentRotation=" + mCurrentRotation);
+            pw.println(prefix + "mSensor=" + mSensor);
+            pw.println(prefix + "mRate=" + mRate);
+
+            if (mSensorEventListener != null) {
+                mSensorEventListener.dumpLocked(pw, prefix);
+            }
+        }
+    }
+
+    /**
+     * This class filters the raw accelerometer data and tries to detect actual changes in
+     * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
+     * but here's the outline:
+     *
+     *  - Low-pass filter the accelerometer vector in cartesian coordinates.  We do it in
+     *    cartesian space because the orientation calculations are sensitive to the
+     *    absolute magnitude of the acceleration.  In particular, there are singularities
+     *    in the calculation as the magnitude approaches 0.  By performing the low-pass
+     *    filtering early, we can eliminate most spurious high-frequency impulses due to noise.
+     *
+     *  - Convert the acceleromter vector from cartesian to spherical coordinates.
+     *    Since we're dealing with rotation of the device, this is the sensible coordinate
+     *    system to work in.  The zenith direction is the Z-axis, the direction the screen
+     *    is facing.  The radial distance is referred to as the magnitude below.
+     *    The elevation angle is referred to as the "tilt" below.
+     *    The azimuth angle is referred to as the "orientation" below (and the azimuth axis is
+     *    the Y-axis).
+     *    See http://en.wikipedia.org/wiki/Spherical_coordinate_system for reference.
+     *
+     *  - If the tilt angle is too close to horizontal (near 90 or -90 degrees), do nothing.
+     *    The orientation angle is not meaningful when the device is nearly horizontal.
+     *    The tilt angle thresholds are set differently for each orientation and different
+     *    limits are applied when the device is facing down as opposed to when it is facing
+     *    forward or facing up.
+     *
+     *  - When the orientation angle reaches a certain threshold, consider transitioning
+     *    to the corresponding orientation.  These thresholds have some hysteresis built-in
+     *    to avoid oscillations between adjacent orientations.
+     *
+     *  - Wait for the device to settle for a little bit.  Once that happens, issue the
+     *    new orientation proposal.
+     *
+     * Details are explained inline.
+     *
+     * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
+     * signal processing background.
+     */
+    final class SensorEventListenerImpl implements SensorEventListener {
+        // We work with all angles in degrees in this class.
+        private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
+
+        // Number of nanoseconds per millisecond.
+        private static final long NANOS_PER_MS = 1000000;
+
+        // Indices into SensorEvent.values for the accelerometer sensor.
+        private static final int ACCELEROMETER_DATA_X = 0;
+        private static final int ACCELEROMETER_DATA_Y = 1;
+        private static final int ACCELEROMETER_DATA_Z = 2;
+
+        // The minimum amount of time that a predicted rotation must be stable before it
+        // is accepted as a valid rotation proposal.  This value can be quite small because
+        // the low-pass filter already suppresses most of the noise so we're really just
+        // looking for quick confirmation that the last few samples are in agreement as to
+        // the desired orientation.
+        private static final long PROPOSAL_SETTLE_TIME_NANOS = 40 * NANOS_PER_MS;
+
+        // The minimum amount of time that must have elapsed since the device last exited
+        // the flat state (time since it was picked up) before the proposed rotation
+        // can change.
+        private static final long PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS = 500 * NANOS_PER_MS;
+
+        // The minimum amount of time that must have elapsed since the device stopped
+        // swinging (time since device appeared to be in the process of being put down
+        // or put away into a pocket) before the proposed rotation can change.
+        private static final long PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS = 300 * NANOS_PER_MS;
+
+        // The minimum amount of time that must have elapsed since the device stopped
+        // undergoing external acceleration before the proposed rotation can change.
+        private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
+                500 * NANOS_PER_MS;
+
+        // If the tilt angle remains greater than the specified angle for a minimum of
+        // the specified time, then the device is deemed to be lying flat
+        // (just chillin' on a table).
+        private static final float FLAT_ANGLE = 75;
+        private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS;
+
+        // If the tilt angle has increased by at least delta degrees within the specified amount
+        // of time, then the device is deemed to be swinging away from the user
+        // down towards flat (tilt = 90).
+        private static final float SWING_AWAY_ANGLE_DELTA = 20;
+        private static final long SWING_TIME_NANOS = 300 * NANOS_PER_MS;
+
+        // The maximum sample inter-arrival time in milliseconds.
+        // If the acceleration samples are further apart than this amount in time, we reset the
+        // state of the low-pass filter and orientation properties.  This helps to handle
+        // boundary conditions when the device is turned on, wakes from suspend or there is
+        // a significant gap in samples.
+        private static final long MAX_FILTER_DELTA_TIME_NANOS = 1000 * NANOS_PER_MS;
+
+        // The acceleration filter time constant.
+        //
+        // This time constant is used to tune the acceleration filter such that
+        // impulses and vibrational noise (think car dock) is suppressed before we
+        // try to calculate the tilt and orientation angles.
+        //
+        // The filter time constant is related to the filter cutoff frequency, which is the
+        // frequency at which signals are attenuated by 3dB (half the passband power).
+        // Each successive octave beyond this frequency is attenuated by an additional 6dB.
+        //
+        // Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz
+        // is given by Fc = 1 / (2pi * t).
+        //
+        // The higher the time constant, the lower the cutoff frequency, so more noise
+        // will be suppressed.
+        //
+        // Filtering adds latency proportional the time constant (inversely proportional
+        // to the cutoff frequency) so we don't want to make the time constant too
+        // large or we can lose responsiveness.  Likewise we don't want to make it too
+        // small or we do a poor job suppressing acceleration spikes.
+        // Empirically, 100ms seems to be too small and 500ms is too large.
+        private static final float FILTER_TIME_CONSTANT_MS = 200.0f;
+
+        /* State for orientation detection. */
+
+        // Thresholds for minimum and maximum allowable deviation from gravity.
+        //
+        // If the device is undergoing external acceleration (being bumped, in a car
+        // that is turning around a corner or a plane taking off) then the magnitude
+        // may be substantially more or less than gravity.  This can skew our orientation
+        // detection by making us think that up is pointed in a different direction.
+        //
+        // Conversely, if the device is in freefall, then there will be no gravity to
+        // measure at all.  This is problematic because we cannot detect the orientation
+        // without gravity to tell us which way is up.  A magnitude near 0 produces
+        // singularities in the tilt and orientation calculations.
+        //
+        // In both cases, we postpone choosing an orientation.
+        //
+        // However, we need to tolerate some acceleration because the angular momentum
+        // of turning the device can skew the observed acceleration for a short period of time.
+        private static final float NEAR_ZERO_MAGNITUDE = 1; // m/s^2
+        private static final float ACCELERATION_TOLERANCE = 4; // m/s^2
+        private static final float MIN_ACCELERATION_MAGNITUDE =
+                SensorManager.STANDARD_GRAVITY - ACCELERATION_TOLERANCE;
+        private static final float MAX_ACCELERATION_MAGNITUDE =
+            SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
+
+        // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
+        // when screen is facing the sky or ground), we completely ignore orientation data.
+        private static final int MAX_TILT = 75;
+
+        // The tilt angle range in degrees for each orientation.
+        // Beyond these tilt angles, we don't even consider transitioning into the
+        // specified orientation.  We place more stringent requirements on unnatural
+        // orientations than natural ones to make it less likely to accidentally transition
+        // into those states.
+        // The first value of each pair is negative so it applies a limit when the device is
+        // facing down (overhead reading in bed).
+        // The second value of each pair is positive so it applies a limit when the device is
+        // facing up (resting on a table).
+        // The ideal tilt angle is 0 (when the device is vertical) so the limits establish
+        // how close to vertical the device must be in order to change orientation.
+        private final int[][] TILT_TOLERANCE = new int[][] {
+            /* ROTATION_0   */ { -25, 70 },
+            /* ROTATION_90  */ { -25, 65 },
+            /* ROTATION_180 */ { -25, 60 },
+            /* ROTATION_270 */ { -25, 65 }
+        };
+
+        // The tilt angle below which we conclude that the user is holding the device
+        // overhead reading in bed and lock into that state.
+        private final int TILT_OVERHEAD_ENTER = -40;
+
+        // The tilt angle above which we conclude that the user would like a rotation
+        // change to occur and unlock from the overhead state.
+        private final int TILT_OVERHEAD_EXIT = -15;
+
+        // The gap angle in degrees between adjacent orientation angles for hysteresis.
+        // This creates a "dead zone" between the current orientation and a proposed
+        // adjacent orientation.  No orientation proposal is made when the orientation
+        // angle is within the gap between the current orientation and the adjacent
+        // orientation.
+        private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
+
+        // Timestamp and value of the last accelerometer sample.
+        private long mLastFilteredTimestampNanos;
+        private float mLastFilteredX, mLastFilteredY, mLastFilteredZ;
+
+        // The last proposed rotation, -1 if unknown.
+        private int mProposedRotation;
+
+        // Value of the current predicted rotation, -1 if unknown.
+        private int mPredictedRotation;
+
+        // Timestamp of when the predicted rotation most recently changed.
+        private long mPredictedRotationTimestampNanos;
+
+        // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed).
+        private long mFlatTimestampNanos;
+        private boolean mFlat;
+
+        // Timestamp when the device last appeared to be swinging.
+        private long mSwingTimestampNanos;
+        private boolean mSwinging;
+
+        // Timestamp when the device last appeared to be undergoing external acceleration.
+        private long mAccelerationTimestampNanos;
+        private boolean mAccelerating;
+
+        // Whether we are locked into an overhead usage mode.
+        private boolean mOverhead;
+
+        // History of observed tilt angles.
+        private static final int TILT_HISTORY_SIZE = 40;
+        private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
+        private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
+        private int mTiltHistoryIndex;
+
+        public int getProposedRotationLocked() {
+            return mProposedRotation;
+        }
+
+        public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.println(prefix + "mProposedRotation=" + mProposedRotation);
+            pw.println(prefix + "mPredictedRotation=" + mPredictedRotation);
+            pw.println(prefix + "mLastFilteredX=" + mLastFilteredX);
+            pw.println(prefix + "mLastFilteredY=" + mLastFilteredY);
+            pw.println(prefix + "mLastFilteredZ=" + mLastFilteredZ);
+            pw.println(prefix + "mTiltHistory={last: " + getLastTiltLocked() + "}");
+            pw.println(prefix + "mFlat=" + mFlat);
+            pw.println(prefix + "mSwinging=" + mSwinging);
+            pw.println(prefix + "mAccelerating=" + mAccelerating);
+            pw.println(prefix + "mOverhead=" + mOverhead);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            int proposedRotation;
+            int oldProposedRotation;
+
+            synchronized (mLock) {
+                // The vector given in the SensorEvent points straight up (towards the sky) under
+                // ideal conditions (the phone is not accelerating).  I'll call this up vector
+                // elsewhere.
+                float x = event.values[ACCELEROMETER_DATA_X];
+                float y = event.values[ACCELEROMETER_DATA_Y];
+                float z = event.values[ACCELEROMETER_DATA_Z];
+
+                if (LOG) {
+                    Slog.v(TAG, "Raw acceleration vector: "
+                            + "x=" + x + ", y=" + y + ", z=" + z
+                            + ", magnitude=" + Math.sqrt(x * x + y * y + z * z));
+                }
+
+                // Apply a low-pass filter to the acceleration up vector in cartesian space.
+                // Reset the orientation listener state if the samples are too far apart in time
+                // or when we see values of (0, 0, 0) which indicates that we polled the
+                // accelerometer too soon after turning it on and we don't have any data yet.
+                final long now = event.timestamp;
+                final long then = mLastFilteredTimestampNanos;
+                final float timeDeltaMS = (now - then) * 0.000001f;
+                final boolean skipSample;
+                if (now < then
+                        || now > then + MAX_FILTER_DELTA_TIME_NANOS
+                        || (x == 0 && y == 0 && z == 0)) {
+                    if (LOG) {
+                        Slog.v(TAG, "Resetting orientation listener.");
+                    }
+                    resetLocked();
+                    skipSample = true;
+                } else {
+                    final float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS);
+                    x = alpha * (x - mLastFilteredX) + mLastFilteredX;
+                    y = alpha * (y - mLastFilteredY) + mLastFilteredY;
+                    z = alpha * (z - mLastFilteredZ) + mLastFilteredZ;
+                    if (LOG) {
+                        Slog.v(TAG, "Filtered acceleration vector: "
+                                + "x=" + x + ", y=" + y + ", z=" + z
+                                + ", magnitude=" + Math.sqrt(x * x + y * y + z * z));
+                    }
+                    skipSample = false;
+                }
+                mLastFilteredTimestampNanos = now;
+                mLastFilteredX = x;
+                mLastFilteredY = y;
+                mLastFilteredZ = z;
+
+                boolean isAccelerating = false;
+                boolean isFlat = false;
+                boolean isSwinging = false;
+                if (!skipSample) {
+                    // Calculate the magnitude of the acceleration vector.
+                    final float magnitude = (float) Math.sqrt(x * x + y * y + z * z);
+                    if (magnitude < NEAR_ZERO_MAGNITUDE) {
+                        if (LOG) {
+                            Slog.v(TAG, "Ignoring sensor data, magnitude too close to zero.");
+                        }
+                        clearPredictedRotationLocked();
+                    } else {
+                        // Determine whether the device appears to be undergoing external
+                        // acceleration.
+                        if (isAcceleratingLocked(magnitude)) {
+                            isAccelerating = true;
+                            mAccelerationTimestampNanos = now;
+                        }
+
+                        // Calculate the tilt angle.
+                        // This is the angle between the up vector and the x-y plane (the plane of
+                        // the screen) in a range of [-90, 90] degrees.
+                        //   -90 degrees: screen horizontal and facing the ground (overhead)
+                        //     0 degrees: screen vertical
+                        //    90 degrees: screen horizontal and facing the sky (on table)
+                        final int tiltAngle = (int) Math.round(
+                                Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
+                        addTiltHistoryEntryLocked(now, tiltAngle);
+
+                        // Determine whether the device appears to be flat or swinging.
+                        if (isFlatLocked(now)) {
+                            isFlat = true;
+                            mFlatTimestampNanos = now;
+                        }
+                        if (isSwingingLocked(now, tiltAngle)) {
+                            isSwinging = true;
+                            mSwingTimestampNanos = now;
+                        }
+
+                        // If the tilt angle is too close to horizontal then we cannot determine
+                        // the orientation angle of the screen.
+                        if (tiltAngle <= TILT_OVERHEAD_ENTER) {
+                            mOverhead = true;
+                        } else if (tiltAngle >= TILT_OVERHEAD_EXIT) {
+                            mOverhead = false;
+                        }
+                        if (mOverhead) {
+                            if (LOG) {
+                                Slog.v(TAG, "Ignoring sensor data, device is overhead: "
+                                        + "tiltAngle=" + tiltAngle);
+                            }
+                            clearPredictedRotationLocked();
+                        } else if (Math.abs(tiltAngle) > MAX_TILT) {
+                            if (LOG) {
+                                Slog.v(TAG, "Ignoring sensor data, tilt angle too high: "
+                                        + "tiltAngle=" + tiltAngle);
+                            }
+                            clearPredictedRotationLocked();
+                        } else {
+                            // Calculate the orientation angle.
+                            // This is the angle between the x-y projection of the up vector onto
+                            // the +y-axis, increasing clockwise in a range of [0, 360] degrees.
+                            int orientationAngle = (int) Math.round(
+                                    -Math.atan2(-x, y) * RADIANS_TO_DEGREES);
+                            if (orientationAngle < 0) {
+                                // atan2 returns [-180, 180]; normalize to [0, 360]
+                                orientationAngle += 360;
+                            }
+
+                            // Find the nearest rotation.
+                            int nearestRotation = (orientationAngle + 45) / 90;
+                            if (nearestRotation == 4) {
+                                nearestRotation = 0;
+                            }
+
+                            // Determine the predicted orientation.
+                            if (isTiltAngleAcceptableLocked(nearestRotation, tiltAngle)
+                                    && isOrientationAngleAcceptableLocked(nearestRotation,
+                                            orientationAngle)) {
+                                updatePredictedRotationLocked(now, nearestRotation);
+                                if (LOG) {
+                                    Slog.v(TAG, "Predicted: "
+                                            + "tiltAngle=" + tiltAngle
+                                            + ", orientationAngle=" + orientationAngle
+                                            + ", predictedRotation=" + mPredictedRotation
+                                            + ", predictedRotationAgeMS="
+                                                    + ((now - mPredictedRotationTimestampNanos)
+                                                            * 0.000001f));
+                                }
+                            } else {
+                                if (LOG) {
+                                    Slog.v(TAG, "Ignoring sensor data, no predicted rotation: "
+                                            + "tiltAngle=" + tiltAngle
+                                            + ", orientationAngle=" + orientationAngle);
+                                }
+                                clearPredictedRotationLocked();
+                            }
+                        }
+                    }
+                }
+                mFlat = isFlat;
+                mSwinging = isSwinging;
+                mAccelerating = isAccelerating;
+
+                // Determine new proposed rotation.
+                oldProposedRotation = mProposedRotation;
+                if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
+                    mProposedRotation = mPredictedRotation;
+                }
+                proposedRotation = mProposedRotation;
+
+                // Write final statistics about where we are in the orientation detection process.
+                if (LOG) {
+                    Slog.v(TAG, "Result: currentRotation=" + mCurrentRotation
+                            + ", proposedRotation=" + proposedRotation
+                            + ", predictedRotation=" + mPredictedRotation
+                            + ", timeDeltaMS=" + timeDeltaMS
+                            + ", isAccelerating=" + isAccelerating
+                            + ", isFlat=" + isFlat
+                            + ", isSwinging=" + isSwinging
+                            + ", isOverhead=" + mOverhead
+                            + ", timeUntilSettledMS=" + remainingMS(now,
+                                    mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
+                            + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
+                                    mAccelerationTimestampNanos + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS)
+                            + ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
+                                    mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
+                            + ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
+                                    mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
+                }
+            }
+
+            // Tell the listener.
+            if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
+                if (LOG) {
+                    Slog.v(TAG, "Proposed rotation changed!  proposedRotation=" + proposedRotation
+                            + ", oldProposedRotation=" + oldProposedRotation);
+                }
+                onProposedRotationChanged(proposedRotation);
+            }
+        }
+
+        /**
+         * Returns true if the tilt angle is acceptable for a given predicted rotation.
+         */
+        private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
+            return tiltAngle >= TILT_TOLERANCE[rotation][0]
+                    && tiltAngle <= TILT_TOLERANCE[rotation][1];
+        }
+
+        /**
+         * Returns true if the orientation angle is acceptable for a given predicted rotation.
+         *
+         * This function takes into account the gap between adjacent orientations
+         * for hysteresis.
+         */
+        private boolean isOrientationAngleAcceptableLocked(int rotation, int orientationAngle) {
+            // If there is no current rotation, then there is no gap.
+            // The gap is used only to introduce hysteresis among advertised orientation
+            // changes to avoid flapping.
+            final int currentRotation = mCurrentRotation;
+            if (currentRotation >= 0) {
+                // If the specified rotation is the same or is counter-clockwise adjacent
+                // to the current rotation, then we set a lower bound on the orientation angle.
+                // For example, if currentRotation is ROTATION_0 and proposed is ROTATION_90,
+                // then we want to check orientationAngle > 45 + GAP / 2.
+                if (rotation == currentRotation
+                        || rotation == (currentRotation + 1) % 4) {
+                    int lowerBound = rotation * 90 - 45
+                            + ADJACENT_ORIENTATION_ANGLE_GAP / 2;
+                    if (rotation == 0) {
+                        if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) {
+                            return false;
+                        }
+                    } else {
+                        if (orientationAngle < lowerBound) {
+                            return false;
+                        }
+                    }
+                }
+
+                // If the specified rotation is the same or is clockwise adjacent,
+                // then we set an upper bound on the orientation angle.
+                // For example, if currentRotation is ROTATION_0 and rotation is ROTATION_270,
+                // then we want to check orientationAngle < 315 - GAP / 2.
+                if (rotation == currentRotation
+                        || rotation == (currentRotation + 3) % 4) {
+                    int upperBound = rotation * 90 + 45
+                            - ADJACENT_ORIENTATION_ANGLE_GAP / 2;
+                    if (rotation == 0) {
+                        if (orientationAngle <= 45 && orientationAngle > upperBound) {
+                            return false;
+                        }
+                    } else {
+                        if (orientationAngle > upperBound) {
+                            return false;
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Returns true if the predicted rotation is ready to be advertised as a
+         * proposed rotation.
+         */
+        private boolean isPredictedRotationAcceptableLocked(long now) {
+            // The predicted rotation must have settled long enough.
+            if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
+                return false;
+            }
+
+            // The last flat state (time since picked up) must have been sufficiently long ago.
+            if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) {
+                return false;
+            }
+
+            // The last swing state (time since last movement to put down) must have been
+            // sufficiently long ago.
+            if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {
+                return false;
+            }
+
+            // The last acceleration state must have been sufficiently long ago.
+            if (now < mAccelerationTimestampNanos
+                    + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
+                return false;
+            }
+
+            // Looks good!
+            return true;
+        }
+
+        private void resetLocked() {
+            mLastFilteredTimestampNanos = Long.MIN_VALUE;
+            mProposedRotation = -1;
+            mFlatTimestampNanos = Long.MIN_VALUE;
+            mFlat = false;
+            mSwingTimestampNanos = Long.MIN_VALUE;
+            mSwinging = false;
+            mAccelerationTimestampNanos = Long.MIN_VALUE;
+            mAccelerating = false;
+            mOverhead = false;
+            clearPredictedRotationLocked();
+            clearTiltHistoryLocked();
+        }
+
+        private void clearPredictedRotationLocked() {
+            mPredictedRotation = -1;
+            mPredictedRotationTimestampNanos = Long.MIN_VALUE;
+        }
+
+        private void updatePredictedRotationLocked(long now, int rotation) {
+            if (mPredictedRotation != rotation) {
+                mPredictedRotation = rotation;
+                mPredictedRotationTimestampNanos = now;
+            }
+        }
+
+        private boolean isAcceleratingLocked(float magnitude) {
+            return magnitude < MIN_ACCELERATION_MAGNITUDE
+                    || magnitude > MAX_ACCELERATION_MAGNITUDE;
+        }
+
+        private void clearTiltHistoryLocked() {
+            mTiltHistoryTimestampNanos[0] = Long.MIN_VALUE;
+            mTiltHistoryIndex = 1;
+        }
+
+        private void addTiltHistoryEntryLocked(long now, float tilt) {
+            mTiltHistory[mTiltHistoryIndex] = tilt;
+            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = now;
+            mTiltHistoryIndex = (mTiltHistoryIndex + 1) % TILT_HISTORY_SIZE;
+            mTiltHistoryTimestampNanos[mTiltHistoryIndex] = Long.MIN_VALUE;
+        }
+
+        private boolean isFlatLocked(long now) {
+            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
+                if (mTiltHistory[i] < FLAT_ANGLE) {
+                    break;
+                }
+                if (mTiltHistoryTimestampNanos[i] + FLAT_TIME_NANOS <= now) {
+                    // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS.
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean isSwingingLocked(long now, float tilt) {
+            for (int i = mTiltHistoryIndex; (i = nextTiltHistoryIndexLocked(i)) >= 0; ) {
+                if (mTiltHistoryTimestampNanos[i] + SWING_TIME_NANOS < now) {
+                    break;
+                }
+                if (mTiltHistory[i] + SWING_AWAY_ANGLE_DELTA <= tilt) {
+                    // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS.
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private int nextTiltHistoryIndexLocked(int index) {
+            index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1;
+            return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1;
+        }
+
+        private float getLastTiltLocked() {
+            int index = nextTiltHistoryIndexLocked(mTiltHistoryIndex);
+            return index >= 0 ? mTiltHistory[index] : Float.NaN;
+        }
+
+        private float remainingMS(long now, long until) {
+            return now >= until ? 0 : (until - now) * 0.000001f;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
new file mode 100644
index 0000000..75c33af
--- /dev/null
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -0,0 +1,335 @@
+package com.android.server.policy.keyguard;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy.OnKeyguardExitResult;
+
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardShowCallback;
+
+/**
+ * A local class that keeps a cache of keyguard state that can be restored in the event
+ * keyguard crashes. It currently also allows runtime-selectable
+ * local or remote instances of keyguard.
+ */
+public class KeyguardServiceDelegate {
+    private static final String TAG = "KeyguardServiceDelegate";
+    private static final boolean DEBUG = true;
+
+    protected KeyguardServiceWrapper mKeyguardService;
+    private final Context mContext;
+    private final View mScrim; // shown if keyguard crashes
+    private final KeyguardState mKeyguardState = new KeyguardState();
+    private ShowListener mShowListenerWhenConnect;
+
+    /* package */ static final class KeyguardState {
+        KeyguardState() {
+            // Assume keyguard is showing and secure until we know for sure. This is here in
+            // the event something checks before the service is actually started.
+            // KeyguardService itself should default to this state until the real state is known.
+            showing = true;
+            showingAndNotOccluded = true;
+            secure = true;
+            deviceHasKeyguard = true;
+        }
+        boolean showing;
+        boolean showingAndNotOccluded;
+        boolean inputRestricted;
+        boolean occluded;
+        boolean secure;
+        boolean dreaming;
+        boolean systemIsReady;
+        boolean deviceHasKeyguard;
+        public boolean enabled;
+        public boolean dismissable;
+        public int offReason;
+        public int currentUser;
+        public boolean screenIsOn;
+        public boolean bootCompleted;
+    };
+
+    public interface ShowListener {
+        public void onShown(IBinder windowToken);
+    }
+
+    // A delegate class to map a particular invocation with a ShowListener object.
+    private final class KeyguardShowDelegate extends IKeyguardShowCallback.Stub {
+        private ShowListener mShowListener;
+
+        KeyguardShowDelegate(ShowListener showListener) {
+            mShowListener = showListener;
+        }
+
+        @Override
+        public void onShown(IBinder windowToken) throws RemoteException {
+            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
+            if (mShowListener != null) {
+                mShowListener.onShown(windowToken);
+            }
+            hideScrim();
+        }
+    };
+
+    // A delegate class to map a particular invocation with an OnKeyguardExitResult object.
+    private final class KeyguardExitDelegate extends IKeyguardExitCallback.Stub {
+        private OnKeyguardExitResult mOnKeyguardExitResult;
+
+        KeyguardExitDelegate(OnKeyguardExitResult onKeyguardExitResult) {
+            mOnKeyguardExitResult = onKeyguardExitResult;
+        }
+
+        @Override
+        public void onKeyguardExitResult(boolean success) throws RemoteException {
+            if (DEBUG) Log.v(TAG, "**** onKeyguardExitResult(" + success +") CALLED ****");
+            if (mOnKeyguardExitResult != null) {
+                mOnKeyguardExitResult.onKeyguardExitResult(success);
+            }
+        }
+    };
+
+    public KeyguardServiceDelegate(Context context) {
+        mContext = context;
+        mScrim = createScrim(context);
+    }
+
+    public void bindService(Context context) {
+        Intent intent = new Intent();
+        final Resources resources = context.getApplicationContext().getResources();
+
+        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
+                resources.getString(com.android.internal.R.string.config_keyguardComponent));
+        intent.setComponent(keyguardComponent);
+
+        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
+                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+            Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
+            mKeyguardState.showing = false;
+            mKeyguardState.showingAndNotOccluded = false;
+            mKeyguardState.secure = false;
+            mKeyguardState.deviceHasKeyguard = false;
+            hideScrim();
+        } else {
+            if (DEBUG) Log.v(TAG, "*** Keyguard started");
+        }
+    }
+
+    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
+            mKeyguardService = new KeyguardServiceWrapper(mContext,
+                    IKeyguardService.Stub.asInterface(service));
+            if (mKeyguardState.systemIsReady) {
+                // If the system is ready, it means keyguard crashed and restarted.
+                mKeyguardService.onSystemReady();
+                // This is used to hide the scrim once keyguard displays.
+                mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(
+                        mShowListenerWhenConnect));
+                mShowListenerWhenConnect = null;
+            }
+            if (mKeyguardState.bootCompleted) {
+                mKeyguardService.onBootCompleted();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
+            mKeyguardService = null;
+        }
+
+    };
+
+    public boolean isShowing() {
+        if (mKeyguardService != null) {
+            mKeyguardState.showing = mKeyguardService.isShowing();
+        }
+        return mKeyguardState.showing;
+    }
+
+    public boolean isInputRestricted() {
+        if (mKeyguardService != null) {
+            mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
+        }
+        return mKeyguardState.inputRestricted;
+    }
+
+    public void verifyUnlock(final OnKeyguardExitResult onKeyguardExitResult) {
+        if (mKeyguardService != null) {
+            mKeyguardService.verifyUnlock(new KeyguardExitDelegate(onKeyguardExitResult));
+        }
+    }
+
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
+        if (mKeyguardService != null) {
+            mKeyguardService.keyguardDone(authenticated, wakeup);
+        }
+    }
+
+    public void setOccluded(boolean isOccluded) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setOccluded(isOccluded);
+        }
+        mKeyguardState.occluded = isOccluded;
+    }
+
+    public void dismiss() {
+        if (mKeyguardService != null) {
+            mKeyguardService.dismiss();
+        }
+    }
+
+    public boolean isSecure() {
+        if (mKeyguardService != null) {
+            mKeyguardState.secure = mKeyguardService.isSecure();
+        }
+        return mKeyguardState.secure;
+    }
+
+    public void onDreamingStarted() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onDreamingStarted();
+        }
+        mKeyguardState.dreaming = true;
+    }
+
+    public void onDreamingStopped() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onDreamingStopped();
+        }
+        mKeyguardState.dreaming = false;
+    }
+
+    public void onScreenTurnedOn(final ShowListener showListener) {
+        if (mKeyguardService != null) {
+            if (DEBUG) Log.v(TAG, "onScreenTurnedOn(showListener = " + showListener + ")");
+            mKeyguardService.onScreenTurnedOn(new KeyguardShowDelegate(showListener));
+        } else {
+            // try again when we establish a connection
+            Slog.w(TAG, "onScreenTurnedOn(): no keyguard service!");
+            // This shouldn't happen, but if it does, show the scrim immediately and
+            // invoke the listener's callback after the service actually connects.
+            mShowListenerWhenConnect = showListener;
+            showScrim();
+        }
+        mKeyguardState.screenIsOn = true;
+    }
+
+    public void onScreenTurnedOff(int why) {
+        if (mKeyguardService != null) {
+            mKeyguardService.onScreenTurnedOff(why);
+        }
+        mKeyguardState.offReason = why;
+        mKeyguardState.screenIsOn = false;
+    }
+
+    public void setKeyguardEnabled(boolean enabled) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setKeyguardEnabled(enabled);
+        }
+        mKeyguardState.enabled = enabled;
+    }
+
+    public void onSystemReady() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onSystemReady();
+        } else {
+            mKeyguardState.systemIsReady = true;
+        }
+    }
+
+    public void doKeyguardTimeout(Bundle options) {
+        if (mKeyguardService != null) {
+            mKeyguardService.doKeyguardTimeout(options);
+        }
+    }
+
+    public void setCurrentUser(int newUserId) {
+        if (mKeyguardService != null) {
+            mKeyguardService.setCurrentUser(newUserId);
+        }
+        mKeyguardState.currentUser = newUserId;
+    }
+
+    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
+        if (mKeyguardService != null) {
+            mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration);
+        }
+    }
+
+    private static final View createScrim(Context context) {
+        View view = new View(context);
+
+        int flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+                | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
+                ;
+
+        final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
+        final int type = WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+        lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
+        lp.setTitle("KeyguardScrim");
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.addView(view, lp);
+        // Disable pretty much everything in statusbar until keyguard comes back and we know
+        // the state of the world.
+        view.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME
+                | View.STATUS_BAR_DISABLE_BACK
+                | View.STATUS_BAR_DISABLE_RECENT
+                | View.STATUS_BAR_DISABLE_EXPAND
+                | View.STATUS_BAR_DISABLE_SEARCH);
+        return view;
+    }
+
+    public void showScrim() {
+        if (!mKeyguardState.deviceHasKeyguard) return;
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    public void hideScrim() {
+        mScrim.post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.setVisibility(View.GONE);
+            }
+        });
+    }
+
+    public void onBootCompleted() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onBootCompleted();
+        }
+        mKeyguardState.bootCompleted = true;
+    }
+
+    public void onActivityDrawn() {
+        if (mKeyguardService != null) {
+            mKeyguardService.onActivityDrawn();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
new file mode 100644
index 0000000..2dc685b
--- /dev/null
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -0,0 +1,206 @@
+/*
+ * 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.policy.keyguard;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardExitCallback;
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardStateCallback;
+
+/**
+ * A wrapper class for KeyguardService.  It implements IKeyguardService to ensure the interface
+ * remains consistent.
+ *
+ */
+public class KeyguardServiceWrapper implements IKeyguardService {
+    private KeyguardStateMonitor mKeyguardStateMonitor;
+    private IKeyguardService mService;
+    private String TAG = "KeyguardServiceWrapper";
+
+    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
+        mService = service;
+        mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
+    }
+
+    @Override // Binder interface
+    public void verifyUnlock(IKeyguardExitCallback callback) {
+        try {
+            mService.verifyUnlock(callback);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
+        try {
+            mService.keyguardDone(authenticated, wakeup);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void setOccluded(boolean isOccluded) {
+        try {
+            mService.setOccluded(isOccluded);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override
+    public void addStateMonitorCallback(IKeyguardStateCallback callback) {
+        try {
+            mService.addStateMonitorCallback(callback);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void dismiss() {
+        try {
+            mService.dismiss();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onDreamingStarted() {
+        try {
+            mService.onDreamingStarted();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onDreamingStopped() {
+        try {
+            mService.onDreamingStopped();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onScreenTurnedOff(int reason) {
+        try {
+            mService.onScreenTurnedOff(reason);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onScreenTurnedOn(IKeyguardShowCallback result) {
+        try {
+            mService.onScreenTurnedOn(result);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void setKeyguardEnabled(boolean enabled) {
+        try {
+            mService.setKeyguardEnabled(enabled);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onSystemReady() {
+        try {
+            mService.onSystemReady();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void doKeyguardTimeout(Bundle options) {
+        try {
+            mService.doKeyguardTimeout(options);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void setCurrentUser(int userId) {
+        mKeyguardStateMonitor.setCurrentUser(userId);
+        try {
+            mService.setCurrentUser(userId);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onBootCompleted() {
+        try {
+            mService.onBootCompleted();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
+        try {
+            mService.startKeyguardExitAnimation(startTime, fadeoutDuration);
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public void onActivityDrawn() {
+        try {
+            mService.onActivityDrawn();
+        } catch (RemoteException e) {
+            Slog.w(TAG , "Remote Exception", e);
+        }
+    }
+
+    @Override // Binder interface
+    public IBinder asBinder() {
+        return mService.asBinder();
+    }
+
+    public boolean isShowing() {
+        return mKeyguardStateMonitor.isShowing();
+    }
+
+    public boolean isSecure() {
+        return mKeyguardStateMonitor.isSecure();
+    }
+
+    public boolean isInputRestricted() {
+        return mKeyguardStateMonitor.isInputRestricted();
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
new file mode 100644
index 0000000..926090e
--- /dev/null
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -0,0 +1,86 @@
+/*
+ * 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.policy.keyguard;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardService;
+import com.android.internal.policy.IKeyguardStateCallback;
+import com.android.internal.widget.LockPatternUtils;
+
+/**
+ * Maintains a cached copy of Keyguard's state.
+ * @hide
+ */
+public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
+    private static final String TAG = "KeyguardStateMonitor";
+
+    // These cache the current state of Keyguard to improve performance and avoid deadlock. After
+    // Keyguard changes its state, it always triggers a layout in window manager. Because
+    // IKeyguardStateCallback is synchronous and because these states are declared volatile, it's
+    // guaranteed that window manager picks up the new state all the time in the layout caused by
+    // the state change of Keyguard.
+    private volatile boolean mIsShowing;
+    private volatile boolean mSimSecure;
+    private volatile boolean mInputRestricted;
+
+    private final LockPatternUtils mLockPatternUtils;
+
+    public KeyguardStateMonitor(Context context, IKeyguardService service) {
+        mLockPatternUtils = new LockPatternUtils(context);
+        mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser());
+        try {
+            service.addStateMonitorCallback(this);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Remote Exception", e);
+        }
+    }
+
+    public boolean isShowing() {
+        return mIsShowing;
+    }
+
+    public boolean isSecure() {
+        return mLockPatternUtils.isSecure() || mSimSecure;
+    }
+
+    public boolean isInputRestricted() {
+        return mInputRestricted;
+    }
+
+    @Override // Binder interface
+    public void onShowingStateChanged(boolean showing) {
+        mIsShowing = showing;
+    }
+
+    @Override // Binder interface
+    public void onSimSecureStateChanged(boolean simSecure) {
+        mSimSecure = simSecure;
+    }
+
+    public void setCurrentUser(int userId) {
+        mLockPatternUtils.setCurrentUser(userId);
+    }
+
+    @Override // Binder interface
+    public void onInputRestrictedStateChanged(boolean inputRestricted) {
+        mInputRestricted = inputRestricted;
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9786b42..66c2f5f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -128,6 +128,7 @@
     private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
+    private static final int WAKE_LOCK_DRAW = 1 << 7;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -1398,12 +1399,15 @@
                     case PowerManager.DOZE_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DOZE;
                         break;
+                    case PowerManager.DRAW_WAKE_LOCK:
+                        mWakeLockSummary |= WAKE_LOCK_DRAW;
+                        break;
                 }
             }
 
             // Cancel wake locks that make no sense based on the current state.
             if (mWakefulness != WAKEFULNESS_DOZING) {
-                mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+                mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
             }
             if (mWakefulness == WAKEFULNESS_ASLEEP
                     || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
@@ -1422,6 +1426,9 @@
                     mWakeLockSummary |= WAKE_LOCK_CPU;
                 }
             }
+            if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+                mWakeLockSummary |= WAKE_LOCK_CPU;
+            }
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
@@ -1845,6 +1852,10 @@
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                 mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+                if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
+                        && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+                    mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+                }
                 mDisplayPowerRequest.dozeScreenBrightness =
                         mDozeScreenBrightnessOverrideFromDreamManager;
             } else {
@@ -2712,6 +2723,8 @@
                     return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
                 case PowerManager.DOZE_WAKE_LOCK:
                     return "DOZE_WAKE_LOCK                ";
+                case PowerManager.DRAW_WAKE_LOCK:
+                    return "DRAW_WAKE_LOCK                ";
                 default:
                     return "???                           ";
             }
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index ddf02e9..2b2b2ac 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -34,7 +34,6 @@
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -265,7 +264,7 @@
     }
 
     @Override
-    public boolean launchAssistAction(int requestType, String hint, int userHandle) {
+    public boolean launchAssistAction(String hint, int userHandle) {
         ComponentName comp = getAssistIntent(userHandle);
         if (comp == null) {
             return false;
@@ -275,7 +274,8 @@
             Intent intent = new Intent(Intent.ACTION_ASSIST);
             intent.setComponent(comp);
             IActivityManager am = ActivityManagerNative.getDefault();
-            return am.launchAssistIntent(intent, requestType, hint, userHandle);
+            return am.launchAssistIntent(intent, ActivityManager.ASSIST_CONTEXT_BASIC, hint,
+                    userHandle);
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index cf2ed07..f6df757 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -454,6 +454,35 @@
         }
     }
 
+    @Override
+    public void appTransitionPending() {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionPending();
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionCancelled();
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
+    public void appTransitionStarting(long statusBarAnimationsStartTime,
+            long statusBarAnimationsDuration) {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionStarting(
+                        statusBarAnimationsStartTime, statusBarAnimationsDuration);
+            } catch (RemoteException ex) {}
+        }
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
@@ -625,7 +654,6 @@
         }
     }
 
-
     // ================================================================================
     // Can be called from any thread
     // ================================================================================
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 111c09b..b819993 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -18,8 +18,7 @@
 
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
-import com.android.server.pm.PackageManagerService;
-
+import com.android.server.pm.InstructionSets;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -341,7 +340,7 @@
     }
 
     private static boolean isBootImageOnDisk() {
-        for (String instructionSet : PackageManagerService.getAllDexCodeInstructionSets()) {
+        for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) {
             if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 57b204d..0109313 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -40,6 +40,7 @@
 import android.service.trust.ITrustAgentService;
 import android.service.trust.ITrustAgentServiceCallback;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -359,6 +360,8 @@
                         mSetTrustAgentFeaturesToken = new Binder();
                         mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
                     }
+                } else {
+                    mTrustAgentService.onConfigure(Collections.EMPTY_LIST, null);
                 }
                 final long maxTimeToLock = dpm.getMaximumTimeToLock(null);
                 if (maxTimeToLock != mMaximumTimeToLock) {
@@ -395,6 +398,7 @@
     }
 
     public void destroy() {
+        mContext.unregisterReceiver(mBroadcastReceiver);
         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
 
         if (!mBound) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 50b2262..ac8ad30 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -55,11 +55,9 @@
 import android.view.KeyEvent;
 import android.view.Surface;
 
-import com.android.internal.os.SomeArgs;
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -104,7 +102,6 @@
     };
     private int mCurrentIndex = 0;
     private int mCurrentMaxIndex = 0;
-    private final boolean mUseMasterVolume;
 
     // TODO: Should handle STANDBY case.
     private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
@@ -119,8 +116,6 @@
         mContext = context;
         mListener = listener;
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        mUseMasterVolume = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_useMasterVolume);
         mHal.init();
     }
 
@@ -141,12 +136,10 @@
             } else {
                 Slog.w(TAG, "HdmiControlService is not available");
             }
-            if (!mUseMasterVolume) {
-                final IntentFilter filter = new IntentFilter();
-                filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
-                filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
-                mContext.registerReceiver(mVolumeReceiver, filter);
-            }
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+            filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+            mContext.registerReceiver(mVolumeReceiver, filter);
             updateVolume();
         }
     }
@@ -547,7 +540,7 @@
     }
 
     private float getMediaStreamVolume() {
-        return mUseMasterVolume ? 1.0f : ((float) mCurrentIndex / (float) mCurrentMaxIndex);
+        return (float) mCurrentIndex / (float) mCurrentMaxIndex;
     }
 
     private class Connection implements IBinder.DeathRecipient {
@@ -699,15 +692,14 @@
 
         private void findAudioSinkFromAudioPolicy(List<AudioDevicePort> sinks) {
             sinks.clear();
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return;
             }
             int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if ((devicePort.type() & sinkDevice) != 0) {
-                    sinks.add(devicePort);
+            for (AudioDevicePort port : devicePorts) {
+                if ((port.type() & sinkDevice) != 0) {
+                    sinks.add(port);
                 }
             }
         }
@@ -716,14 +708,13 @@
             if (type == AudioManager.DEVICE_NONE) {
                 return null;
             }
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return null;
             }
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if (devicePort.type() == type && devicePort.address().equals(address)) {
-                    return devicePort;
+            for (AudioDevicePort port : devicePorts) {
+                if (port.type() == type && port.address().equals(address)) {
+                    return port;
                 }
             }
             return null;
diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index 7f7aae3..1135dfe 100644
--- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -47,7 +47,6 @@
 
     private static final String TAG = "ConfigUpdateInstallReceiver";
 
-    private static final String EXTRA_CONTENT_PATH = "CONTENT_PATH";
     private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH";
     private static final String EXTRA_SIGNATURE = "SIGNATURE";
     private static final String EXTRA_VERSION_NUMBER = "VERSION";
diff --git a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 24318df..4e53687 100644
--- a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Base64;
@@ -48,39 +47,6 @@
         super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
     }
 
-    private void backupContexts(File contexts) {
-        new File(contexts, versionPath).renameTo(
-                new File(contexts, versionPath + "_backup"));
-
-        new File(contexts, macPermissionsPath).renameTo(
-                new File(contexts, macPermissionsPath + "_backup"));
-
-        new File(contexts, seappContextsPath).renameTo(
-                new File(contexts, seappContextsPath + "_backup"));
-
-        new File(contexts, propertyContextsPath).renameTo(
-                new File(contexts, propertyContextsPath + "_backup"));
-
-        new File(contexts, fileContextsPath).renameTo(
-                new File(contexts, fileContextsPath + "_backup"));
-
-        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) {
-        new File(updateDir, versionPath).renameTo(new File(contexts, versionPath));
-        new File(updateDir, macPermissionsPath).renameTo(new File(contexts, macPermissionsPath));
-        new File(updateDir, seappContextsPath).renameTo(new File(contexts, seappContextsPath));
-        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 {
         int value = 0;
         for (int i=0; i < 4; i++) {
@@ -108,17 +74,27 @@
         writeUpdate(updateDir, destination, Base64.decode(chunk, Base64.DEFAULT));
     }
 
+    private void deleteRecursive(File fileOrDirectory) {
+        if (fileOrDirectory.isDirectory())
+            for (File child : fileOrDirectory.listFiles())
+                deleteRecursive(child);
+        fileOrDirectory.delete();
+    }
+
     private void unpackBundle() throws IOException {
         BufferedInputStream stream = new BufferedInputStream(new FileInputStream(updateContent));
+        File tmp = new File(updateDir.getParentFile(), "tmp");
         try {
             int[] chunkLengths = readChunkLengths(stream);
-            installFile(new File(updateDir, versionPath), stream, chunkLengths[0]);
-            installFile(new File(updateDir, macPermissionsPath), stream, chunkLengths[1]);
-            installFile(new File(updateDir, seappContextsPath), stream, chunkLengths[2]);
-            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]);
+            deleteRecursive(tmp);
+            tmp.mkdirs();
+            installFile(new File(tmp, versionPath), stream, chunkLengths[0]);
+            installFile(new File(tmp, macPermissionsPath), stream, chunkLengths[1]);
+            installFile(new File(tmp, seappContextsPath), stream, chunkLengths[2]);
+            installFile(new File(tmp, propertyContextsPath), stream, chunkLengths[3]);
+            installFile(new File(tmp, fileContextsPath), stream, chunkLengths[4]);
+            installFile(new File(tmp, sepolicyPath), stream, chunkLengths[5]);
+            installFile(new File(tmp, serviceContextsPath), stream, chunkLengths[6]);
         } finally {
             IoUtils.closeQuietly(stream);
         }
@@ -126,22 +102,22 @@
 
     private void applyUpdate() throws IOException, ErrnoException {
         Slog.i(TAG, "Applying SELinux policy");
-        File contexts = new File(updateDir.getParentFile(), "contexts");
+        File backup = new File(updateDir.getParentFile(), "backup");
         File current = new File(updateDir.getParentFile(), "current");
-        File update = new File(updateDir.getParentFile(), "update");
         File tmp = new File(updateDir.getParentFile(), "tmp");
         if (current.exists()) {
-            Os.symlink(updateDir.getPath(), update.getPath());
-            Os.rename(update.getPath(), current.getPath());
-        } else {
-            Os.symlink(updateDir.getPath(), current.getPath());
+            deleteRecursive(backup);
+            Os.rename(current.getPath(), backup.getPath());
         }
-        contexts.mkdirs();
-        backupContexts(contexts);
-        copyUpdate(contexts);
-        Os.symlink(contexts.getPath(), tmp.getPath());
-        Os.rename(tmp.getPath(), current.getPath());
-        SystemProperties.set("selinux.reload_policy", "1");
+        try {
+            Os.rename(tmp.getPath(), current.getPath());
+            SystemProperties.set("selinux.reload_policy", "1");
+        } catch (ErrnoException e) {
+            Slog.e(TAG, "Could not update selinux policy: ", e);
+            if (backup.exists()) {
+                Os.rename(backup.getPath(), current.getPath());
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index bd2e923..99cf8df 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
 import android.app.IWallpaperManager;
 import android.app.IWallpaperManagerCallback;
@@ -164,6 +165,7 @@
     final IWindowManager mIWindowManager;
     final IPackageManager mIPackageManager;
     final MyPackageMonitor mMonitor;
+    final AppOpsManager mAppOpsManager;
     WallpaperData mLastWallpaper;
 
     /**
@@ -478,6 +480,7 @@
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mIPackageManager = AppGlobals.getPackageManager();
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
@@ -613,8 +616,12 @@
         }
     }
 
-    public void clearWallpaper() {
+    public void clearWallpaper(String callingPackage) {
         if (DEBUG) Slog.v(TAG, "clearWallpaper");
+        checkPermission(android.Manifest.permission.SET_WALLPAPER);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
         }
@@ -622,6 +629,9 @@
 
     void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
         WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            return;
+        }
         File f = new File(getWallpaperDir(userId), WALLPAPER);
         if (f.exists()) {
             f.delete();
@@ -668,6 +678,10 @@
                 Binder.restoreCallingIdentity(ident);
             }
             for (UserInfo user: users) {
+                // ignore managed profiles
+                if (user.isManagedProfile()) {
+                    continue;
+                }
                 WallpaperData wd = mWallpaperMap.get(user.id);
                 if (wd == null) {
                     // User hasn't started yet, so load her settings to peek at the wallpaper
@@ -690,8 +704,12 @@
         return p;
     }
 
-    public void setDimensionHints(int width, int height) throws RemoteException {
+    public void setDimensionHints(int width, int height, String callingPackage)
+            throws RemoteException {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -733,19 +751,30 @@
     public int getWidthHint() throws RemoteException {
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
-            return wallpaper.width;
+            if (wallpaper != null) {
+                return wallpaper.width;
+            } else {
+                return 0;
+            }
         }
     }
 
     public int getHeightHint() throws RemoteException {
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
-            return wallpaper.height;
+            if (wallpaper != null) {
+                return wallpaper.height;
+            } else {
+                return 0;
+            }
         }
     }
 
-    public void setDisplayPadding(Rect padding) {
+    public void setDisplayPadding(Rect padding, String callingPackage) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+        if (!isWallpaperSupported(callingPackage)) {
+            return;
+        }
         synchronized (mLock) {
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -791,6 +820,9 @@
                 wallpaperUserId = UserHandle.getUserId(callingUid);
             }
             WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
+            if (wallpaper == null) {
+                return null;
+            }
             try {
                 if (outParams != null) {
                     outParams.putInt("width", wallpaper.width);
@@ -814,15 +846,18 @@
         int userId = UserHandle.getCallingUserId();
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(userId);
-            if (wallpaper.connection != null) {
+            if (wallpaper != null && wallpaper.connection != null) {
                 return wallpaper.connection.mInfo;
             }
             return null;
         }
     }
 
-    public ParcelFileDescriptor setWallpaper(String name) {
+    public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
+        if (!isWallpaperSupported(callingPackage)) {
+            return null;
+        }
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper");
             int userId = UserHandle.getCallingUserId();
@@ -868,6 +903,13 @@
         return null;
     }
 
+    public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
+        if (isWallpaperSupported(callingPackage)) {
+            setWallpaperComponent(name);
+        }
+    }
+
+    // ToDo: Remove this version of the function
     public void setWallpaperComponent(ComponentName name) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
         synchronized (mLock) {
@@ -1097,6 +1139,15 @@
         }
     }
 
+    /**
+     * Certain user types do not support wallpapers (e.g. managed profiles). The check is
+     * implemented through through the OP_WRITE_WALLPAPER AppOp.
+     */
+    public boolean isWallpaperSupported(String callingPackage) {
+        return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
+                callingPackage) == AppOpsManager.MODE_ALLOWED;
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1135,6 +1186,8 @@
             out.endTag(null, "wp");
 
             out.endDocument();
+            stream.flush();
+            FileUtils.sync(stream);
             stream.close();
             journal.commit();
         } catch (IOException e) {
@@ -1172,7 +1225,7 @@
 
     private void loadSettingsLocked(int userId) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
-        
+
         JournaledFile journal = makeJournaledFile(userId);
         FileInputStream stream = null;
         File file = journal.chooseForRead();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 08754f9..b5d4caf 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -397,8 +397,6 @@
 
         private final class MagnifiedViewport {
 
-            private static final int DEFAUTLT_BORDER_WIDTH_DIP = 5;
-
             private final SparseArray<WindowState> mTempWindowStates =
                     new SparseArray<WindowState>();
 
@@ -411,6 +409,8 @@
             private final Region mMagnifiedBounds = new Region();
             private final Region mOldMagnifiedBounds = new Region();
 
+            private final Path mCircularPath;
+
             private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
 
             private final WindowManager mWindowManager;
@@ -425,12 +425,22 @@
 
             public MagnifiedViewport() {
                 mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
-                mBorderWidth = TypedValue.applyDimension(
-                        TypedValue.COMPLEX_UNIT_DIP, DEFAUTLT_BORDER_WIDTH_DIP,
-                                mContext.getResources().getDisplayMetrics());
+                mBorderWidth = mContext.getResources().getDimension(
+                        com.android.internal.R.dimen.accessibility_magnification_indicator_width);
                 mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
                 mDrawBorderInset = (int) mBorderWidth / 2;
                 mWindow = new ViewportWindow(mContext);
+
+                if (mContext.getResources().getBoolean(
+                            com.android.internal.R.bool.config_windowIsRound)) {
+                    mCircularPath = new Path();
+                    mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
+                    final int centerXY = mTempPoint.x / 2;
+                    mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
+                } else {
+                    mCircularPath = null;
+                }
+
                 recomputeBoundsLocked();
             }
 
@@ -459,6 +469,10 @@
                 Region availableBounds = mTempRegion1;
                 availableBounds.set(0, 0, screenWidth, screenHeight);
 
+                if (mCircularPath != null) {
+                    availableBounds.setPath(mCircularPath, availableBounds);
+                }
+
                 Region nonMagnifiedBounds = mTempRegion4;
                 nonMagnifiedBounds.set(0, 0, 0, 0);
 
@@ -606,9 +620,8 @@
                 final int windowCount = windowList.size();
                 for (int i = 0; i < windowCount; i++) {
                     WindowState windowState = windowList.get(i);
-                    if ((windowState.isOnScreen() || windowState.mAttrs.type == WindowManager
-                            .LayoutParams.TYPE_UNIVERSE_BACKGROUND)
-                            && !windowState.mWinAnimator.mEnterAnimationPending) {
+                    if (windowState.isOnScreen() &&
+                            !windowState.mWinAnimator.mEnterAnimationPending) {
                         outWindows.put(windowState.mLayer, windowState);
                     }
                 }
@@ -1237,7 +1250,6 @@
                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
                     && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
                     && windowType != WindowManager.LayoutParams.TYPE_POINTER
-                    && windowType != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
                     && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c0d54e1..4c06cbe 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -22,6 +22,7 @@
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.util.Slog;
 import android.view.WindowManager;
@@ -30,15 +31,22 @@
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
 import android.view.animation.ClipRectAnimation;
+import android.view.animation.ClipRectLRAnimation;
+import android.view.animation.ClipRectTBAnimation;
 import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.TranslateAnimation;
+import android.view.animation.TranslateXAnimation;
+import android.view.animation.TranslateYAnimation;
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.server.AttributeCache;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
+import static android.view.WindowManagerInternal.AppTransitionListener;
 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
@@ -134,6 +142,7 @@
     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
     private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
     private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
+    private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
     private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
 
     // These are the possible states for the enter/exit activities during a thumbnail transition
@@ -169,19 +178,26 @@
     private final Interpolator mDecelerateInterpolator;
     private final Interpolator mThumbnailFadeInInterpolator;
     private final Interpolator mThumbnailFadeOutInterpolator;
-    private final Interpolator mThumbnailFastOutSlowInInterpolator;
+    private final Interpolator mLinearOutSlowInInterpolator;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private final LinearInterpolator mLinearInterpolator;
 
     private int mCurrentUserId = 0;
 
+    private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
+
     AppTransition(Context context, Handler h) {
         mContext = context;
         mH = h;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mLinearInterpolator = new LinearInterpolator();
         mConfigShortAnimTime = context.getResources().getInteger(
                 com.android.internal.R.integer.config_shortAnimTime);
         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.decelerate_cubic);
-        mThumbnailFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_slow_in);
         mThumbnailFadeInInterpolator = new Interpolator() {
             @Override
             public float getInterpolation(float input) {
@@ -276,12 +292,18 @@
     void prepare() {
         if (!isRunning()) {
             mAppTransitionState = APP_STATE_IDLE;
+            notifyAppTransitionPendingLocked();
         }
     }
 
-    void goodToGo() {
+    void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) {
         mNextAppTransition = TRANSIT_UNSET;
         mAppTransitionState = APP_STATE_RUNNING;
+        notifyAppTransitionStartingLocked(
+                openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null,
+                closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null,
+                openingAppAnimator != null ? openingAppAnimator.animation : null,
+                closingAppAnimator != null ? closingAppAnimator.animation : null);
     }
 
     void clear() {
@@ -294,6 +316,38 @@
         setAppTransition(AppTransition.TRANSIT_UNSET);
         clear();
         setReady();
+        notifyAppTransitionCancelledLocked();
+    }
+
+    void registerListenerLocked(AppTransitionListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void notifyAppTransitionFinishedLocked(AppWindowAnimator animator) {
+        IBinder token = animator != null ? animator.mAppToken.token : null;
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionFinishedLocked(token);
+        }
+    }
+
+    private void notifyAppTransitionPendingLocked() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionPendingLocked();
+        }
+    }
+
+    private void notifyAppTransitionCancelledLocked() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionCancelledLocked();
+        }
+    }
+
+    private void notifyAppTransitionStartingLocked(IBinder openToken,
+            IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation,
+                    closeAnimation);
+        }
     }
 
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
@@ -447,6 +501,83 @@
         return a;
     }
 
+    private Animation createClipRevealAnimationLocked(int transit, boolean enter,
+                                                      int appWidth, int appHeight) {
+        final Animation anim;
+        if (enter) {
+            // Reveal will expand and move faster in horizontal direction
+
+            // Start from size of launch icon, expand to full width/height
+            Animation clipAnimLR = new ClipRectLRAnimation(
+                    (appWidth - mNextAppTransitionStartWidth) / 2,
+                    (appWidth + mNextAppTransitionStartWidth) / 2, 0, appWidth);
+            clipAnimLR.setInterpolator(mLinearOutSlowInInterpolator);
+            clipAnimLR.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+            Animation clipAnimTB = new ClipRectTBAnimation(
+                    (appHeight - mNextAppTransitionStartHeight) / 2,
+                    (appHeight + mNextAppTransitionStartHeight) / 2, 0, appHeight);
+            clipAnimTB.setInterpolator(mFastOutSlowInInterpolator);
+            clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+
+            // Start from middle of launch icon area, move to 0, 0
+            int startMiddleX = mNextAppTransitionStartX +
+                    (mNextAppTransitionStartWidth - appWidth) / 2;
+            int startMiddleY = mNextAppTransitionStartY +
+                    (mNextAppTransitionStartHeight - appHeight) / 2;
+
+            TranslateXAnimation translateX = new TranslateXAnimation(
+                    Animation.ABSOLUTE, startMiddleX, Animation.ABSOLUTE, 0);
+            translateX.setInterpolator(mLinearOutSlowInInterpolator);
+            translateX.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+            TranslateYAnimation translateY = new TranslateYAnimation(
+                    Animation.ABSOLUTE, startMiddleY, Animation.ABSOLUTE, 0);
+            translateY.setInterpolator(mFastOutSlowInInterpolator);
+            translateY.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+
+            // Quick fade-in from icon to app window
+            final int alphaDuration = 100;
+            AlphaAnimation alpha = new AlphaAnimation(0.1f, 1);
+            alpha.setDuration(alphaDuration);
+            alpha.setInterpolator(mLinearInterpolator);
+
+            AnimationSet set = new AnimationSet(false);
+            set.addAnimation(clipAnimLR);
+            set.addAnimation(clipAnimTB);
+            set.addAnimation(translateX);
+            set.addAnimation(translateY);
+            set.addAnimation(alpha);
+            set.initialize(appWidth, appHeight, appWidth, appHeight);
+            anim = set;
+        } else {
+            final long duration;
+            switch (transit) {
+                case TRANSIT_ACTIVITY_OPEN:
+                case TRANSIT_ACTIVITY_CLOSE:
+                    duration = mConfigShortAnimTime;
+                    break;
+                default:
+                    duration = DEFAULT_APP_TRANSITION_DURATION;
+                    break;
+            }
+            if (transit == TRANSIT_WALLPAPER_INTRA_OPEN ||
+                    transit == TRANSIT_WALLPAPER_INTRA_CLOSE) {
+                // If we are on top of the wallpaper, we need an animation that
+                // correctly handles the wallpaper staying static behind all of
+                // the animated elements.  To do this, will just have the existing
+                // element fade out.
+                anim = new AlphaAnimation(1, 0);
+                anim.setDetachWallpaper(true);
+            } else {
+                // For normal animations, the exiting element just holds in place.
+                anim = new AlphaAnimation(1, 1);
+            }
+            anim.setInterpolator(mDecelerateInterpolator);
+            anim.setDuration(duration);
+            anim.setFillAfter(true);
+        }
+        return anim;
+    }
+
     /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
@@ -522,14 +653,14 @@
             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
                     mNextAppTransitionStartX + (thumbWidth / 2f),
                     mNextAppTransitionStartY + (thumbHeight / 2f));
-            scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+            scale.setInterpolator(mFastOutSlowInInterpolator);
             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
             Animation alpha = new AlphaAnimation(1, 0);
             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
             Animation translate = new TranslateAnimation(0, 0, 0, -unscaledStartY +
                     mNextAppTransitionInsets.top);
-            translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+            translate.setInterpolator(mFastOutSlowInInterpolator);
             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
 
             // This AnimationSet uses the Interpolators assigned above.
@@ -543,14 +674,14 @@
             Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
                     mNextAppTransitionStartX + (thumbWidth / 2f),
                     mNextAppTransitionStartY + (thumbHeight / 2f));
-            scale.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+            scale.setInterpolator(mFastOutSlowInInterpolator);
             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
             Animation alpha = new AlphaAnimation(0f, 1f);
             alpha.setInterpolator(mThumbnailFadeInInterpolator);
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
             Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
                     mNextAppTransitionInsets.top, 0);
-            translate.setInterpolator(mThumbnailFastOutSlowInInterpolator);
+            translate.setInterpolator(mFastOutSlowInInterpolator);
             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
 
             // This AnimationSet uses the Interpolators assigned above.
@@ -562,7 +693,7 @@
 
         }
         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, 0,
-                mThumbnailFastOutSlowInInterpolator);
+                mFastOutSlowInInterpolator);
     }
 
     /**
@@ -698,7 +829,7 @@
         int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
                 THUMBNAIL_APP_TRANSITION_DURATION);
         return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
-                mThumbnailFastOutSlowInInterpolator);
+                mFastOutSlowInInterpolator);
     }
 
     /**
@@ -845,6 +976,14 @@
                     "applyAnimation:"
                             + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
                             + " transit=" + transit + " Callers=" + Debug.getCallers(3));
+        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
+            a = createClipRevealAnimationLocked(transit, enter,
+                    containingFrame.right - containingFrame.left,
+                    containingFrame.bottom - containingFrame.top);
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "applyAnimation:"
+                            + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
+                            + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
             a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
@@ -987,6 +1126,19 @@
         }
     }
 
+    void overridePendingAppTransitionClipReveal(int startX, int startY,
+                                                int startWidth, int startHeight) {
+        if (isTransitionSet()) {
+            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
+            mNextAppTransitionStartX = startX;
+            mNextAppTransitionStartY = startY;
+            mNextAppTransitionStartWidth = startWidth;
+            mNextAppTransitionStartHeight = startHeight;
+            postAnimationCallback();
+            mNextAppTransitionCallback = null;
+        }
+    }
+
     void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
                                            IRemoteCallback startedCallback, boolean scaleUp) {
         if (isTransitionSet()) {
@@ -1130,32 +1282,34 @@
     }
 
     @Override
-    public void dump(PrintWriter pw) {
-        pw.print(" " + this);
-        pw.print("  mAppTransitionState="); pw.println(appStateToString());
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.println(this);
+        pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
         if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
-            pw.print("  mNextAppTransitionType="); pw.println(transitTypeToString());
+            pw.print(prefix); pw.print("mNextAppTransitionType=");
+                    pw.println(transitTypeToString());
         }
         switch (mNextAppTransitionType) {
             case NEXT_TRANSIT_TYPE_CUSTOM:
-                pw.print("  mNextAppTransitionPackage=");
+                pw.print(prefix); pw.print("mNextAppTransitionPackage=");
                         pw.println(mNextAppTransitionPackage);
-                pw.print("  mNextAppTransitionEnter=0x");
+                pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
                         pw.print(Integer.toHexString(mNextAppTransitionEnter));
                         pw.print(" mNextAppTransitionExit=0x");
                         pw.println(Integer.toHexString(mNextAppTransitionExit));
                 break;
             case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
-                pw.print("  mNextAppTransitionPackage=");
+                pw.print(prefix); pw.print("mNextAppTransitionPackage=");
                         pw.println(mNextAppTransitionPackage);
-                pw.print("  mNextAppTransitionInPlace=0x");
+                pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
                         pw.print(Integer.toHexString(mNextAppTransitionInPlace));
                 break;
             case NEXT_TRANSIT_TYPE_SCALE_UP:
-                pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+                pw.print(prefix); pw.print("mNextAppTransitionStartX=");
+                        pw.print(mNextAppTransitionStartX);
                         pw.print(" mNextAppTransitionStartY=");
                         pw.println(mNextAppTransitionStartY);
-                pw.print("  mNextAppTransitionStartWidth=");
+                pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
                         pw.print(mNextAppTransitionStartWidth);
                         pw.print(" mNextAppTransitionStartHeight=");
                         pw.println(mNextAppTransitionStartHeight);
@@ -1164,22 +1318,23 @@
             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
             case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
-                pw.print("  mNextAppTransitionThumbnail=");
+                pw.print(prefix); pw.print("mNextAppTransitionThumbnail=");
                         pw.print(mNextAppTransitionThumbnail);
                         pw.print(" mNextAppTransitionStartX=");
                         pw.print(mNextAppTransitionStartX);
                         pw.print(" mNextAppTransitionStartY=");
                         pw.println(mNextAppTransitionStartY);
-                        pw.print(" mNextAppTransitionStartWidth=");
+                pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
                         pw.print(mNextAppTransitionStartWidth);
                         pw.print(" mNextAppTransitionStartHeight=");
                         pw.println(mNextAppTransitionStartHeight);
-                pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
+                pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
+                        pw.println(mNextAppTransitionScaleUp);
                 break;
         }
         if (mNextAppTransitionCallback != null) {
-            pw.print("  mNextAppTransitionCallback=");
-            pw.println(mNextAppTransitionCallback);
+            pw.print(prefix); pw.print("mNextAppTransitionCallback=");
+                    pw.println(mNextAppTransitionCallback);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 5c81126..a58f30d 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import android.graphics.Matrix;
-import android.os.RemoteException;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -142,6 +141,10 @@
         }
     }
 
+    public boolean isAnimating() {
+        return animation != null || mAppToken.inPendingTransaction;
+    }
+
     public void clearThumbnail() {
         if (thumbnail != null) {
             thumbnail.destroy();
@@ -312,23 +315,7 @@
         for (int i = 0; i < numAllAppWinAnimators; i++) {
             mAllAppWinAnimators.get(i).finishExit();
         }
-        if (mAppToken.mLaunchTaskBehind) {
-            try {
-                mService.mActivityManager.notifyLaunchTaskBehindComplete(mAppToken.token);
-            } catch (RemoteException e) {
-            }
-            mAppToken.mLaunchTaskBehind = false;
-        } else {
-            mAppToken.updateReportedVisibilityLocked();
-            if (mAppToken.mEnteringAnimation) {
-                mAppToken.mEnteringAnimation = false;
-                try {
-                    mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
+        mService.mAppTransition.notifyAppTransitionFinishedLocked(this);
         return false;
     }
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index da25c53..a04f6cb 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -52,7 +52,7 @@
 
     final boolean voiceInteraction;
 
-    int groupId = -1;
+    Task mTask;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     boolean layoutConfigChanges;
@@ -107,7 +107,7 @@
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
-    boolean mDeferRemoval;
+    boolean mIsExiting;
 
     boolean mLaunchTaskBehind;
     boolean mEnteringAnimation;
@@ -252,6 +252,21 @@
         return false;
     }
 
+    void removeAppFromTaskLocked() {
+        mIsExiting = false;
+        removeAllWindows();
+
+        // Use local variable because removeAppToken will null out mTask.
+        final Task task = mTask;
+        if (task != null) {
+            if (!task.removeAppToken(this)) {
+                Slog.e(WindowManagerService.TAG, "removeAppFromTaskLocked: token=" + this
+                        + " not found.");
+            }
+            task.mStack.mExitingAppTokens.remove(this);
+        }
+    }
+
     @Override
     void removeAllWindows() {
         for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
@@ -266,8 +281,10 @@
                 Slog.w(WindowManagerService.TAG, "removeAllWindows: removing win=" + win);
             }
 
-            win.mService.removeWindowLocked(win.mSession, win);
+            service.removeWindowLocked(win.mSession, win);
         }
+        allAppWindows.clear();
+        windows.clear();
     }
 
     @Override
@@ -279,8 +296,8 @@
         if (allAppWindows.size() > 0) {
             pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
         }
-        pw.print(prefix); pw.print("groupId="); pw.print(groupId);
-                pw.print(" appFullscreen="); pw.print(appFullscreen);
+        pw.print(prefix); pw.print("task="); pw.println(mTask);
+        pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
                 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
         pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
                 pw.print(" clientHidden="); pw.print(clientHidden);
@@ -304,11 +321,11 @@
             pw.print(prefix); pw.print("inPendingTransaction=");
                     pw.println(inPendingTransaction);
         }
-        if (startingData != null || removed || firstWindowDrawn || mDeferRemoval) {
+        if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
                     pw.print(" removed="); pw.print(removed);
                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
-                    pw.print(" mDeferRemoval="); pw.println(mDeferRemoval);
+                    pw.print(" mIsExiting="); pw.println(mIsExiting);
         }
         if (startingWindow != null || startingView != null
                 || startingDisplayed || startingMoved) {
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index 9fdfc47..7c2da2d 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -50,9 +50,10 @@
     private int mRotation;
     private boolean mVisible;
     private boolean mDimensionsUnequal = false;
+    private int mMaskThickness;
 
     public CircularDisplayMask(Display display, SurfaceSession session, int zOrder,
-            int screenOffset) {
+            int screenOffset, int maskThickness) {
         mScreenSize = new Point();
         display.getSize(mScreenSize);
         if (mScreenSize.x != mScreenSize.y) {
@@ -84,6 +85,7 @@
         mPaint.setAntiAlias(true);
         mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
         mScreenOffset = screenOffset;
+        mMaskThickness = maskThickness;
     }
 
     private void drawIfNeeded() {
@@ -121,8 +123,8 @@
         int circleRadius = mScreenSize.x / 2;
         c.drawColor(Color.BLACK);
 
-        // The radius is reduced by 1 to provide an anti aliasing effect on the display edges.
-        c.drawCircle(circleRadius, circleRadius, circleRadius - 1, mPaint);
+        // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the display edges.
+        c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint);
         mSurface.unlockCanvasAndPost(c);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f57adaf..f073c23 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -241,22 +241,24 @@
                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
             }
         }
+        if (mTapDetector != null) {
+            mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
+        }
     }
 
-    void switchUserStacks(int newUserId) {
+    void switchUserStacks() {
         final WindowList windows = getWindowList();
         for (int i = 0; i < windows.size(); i++) {
             final WindowState win = windows.get(i);
             if (win.isHiddenFromUserLocked()) {
-                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
-                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
-                        + win.mOwnerUid);
+                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing, hiding " + win
+                        + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid);
                 win.hideLw(false);
             }
         }
 
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).switchUser(newUserId);
+            mStacks.get(stackNdx).switchUser();
         }
     }
 
@@ -327,16 +329,10 @@
                     AppTokenList tokens = task.mAppTokens;
                     for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
                         AppWindowToken wtoken = tokens.get(tokenNdx);
-                        if (wtoken.mDeferRemoval) {
-                            stack.mExitingAppTokens.remove(wtoken);
-                            wtoken.mDeferRemoval = false;
-                            mService.removeAppFromTaskLocked(wtoken);
+                        if (wtoken.mIsExiting) {
+                            wtoken.removeAppFromTaskLocked();
                         }
                     }
-                    if (task.mDeferRemoval) {
-                        task.mDeferRemoval = false;
-                        mService.removeTaskLocked(task);
-                    }
                 }
             }
         }
@@ -345,6 +341,12 @@
         }
     }
 
+    static int deltaRotation(int oldRotation, int newRotation) {
+        int delta = newRotation - oldRotation;
+        if (delta < 0) delta += 4;
+        return delta;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
         final String subPrefix = "  " + prefix;
@@ -384,7 +386,7 @@
             ArrayList<Task> tasks = stack.getTasks();
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
-                pw.print("    mTaskId="); pw.println(task.taskId);
+                pw.print("    mTaskId="); pw.println(task.mTaskId);
                 AppTokenList tokens = task.mAppTokens;
                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 62f2b48..4c8a6f9 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -25,7 +25,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.util.Slog;
 import android.view.Display;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
@@ -93,7 +92,9 @@
         }
         c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
         mSurfaceControl.setPosition(0, 0);
-        mOverlay.setBounds(0, 0, mScreenSize.x, mScreenSize.y);
+        // Always draw the overlay with square dimensions
+        int size = Math.max(mScreenSize.x, mScreenSize.y);
+        mOverlay.setBounds(0, 0, size, size);
         mOverlay.draw(c);
         mSurface.unlockCanvasAndPost(c);
     }
diff --git a/services/core/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java
index f1f5fe8..826fe97 100644
--- a/services/core/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java
@@ -16,14 +16,14 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface.OutOfResourcesException;
@@ -35,14 +35,17 @@
 
 class FocusedStackFrame {
     private static final String TAG = "FocusedStackFrame";
-    private static final int THICKNESS = 10;
+    private static final boolean DEBUG = false;
+    private static final int THICKNESS = 2;
     private static final float ALPHA = 0.3f;
 
     private final SurfaceControl mSurfaceControl;
     private final Surface mSurface = new Surface();
+    private final Paint mInnerPaint = new Paint();
+    private final Paint mOuterPaint = new Paint();
+    private final Rect mBounds = new Rect();
     private final Rect mLastBounds = new Rect();
-    final Rect mBounds = new Rect();
-    private final Rect mTmpDrawRect = new Rect();
+    private int mLayer = -1;
 
     public FocusedStackFrame(Display display, SurfaceSession session) {
         SurfaceControl ctrl = null;
@@ -60,83 +63,84 @@
         } catch (OutOfResourcesException e) {
         }
         mSurfaceControl = ctrl;
+
+        mInnerPaint.setStyle(Paint.Style.STROKE);
+        mInnerPaint.setStrokeWidth(THICKNESS);
+        mInnerPaint.setColor(Color.WHITE);
+        mOuterPaint.setStyle(Paint.Style.STROKE);
+        mOuterPaint.setStrokeWidth(THICKNESS);
+        mOuterPaint.setColor(Color.BLACK);
     }
 
-    private void draw(Rect bounds, int color) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "draw: bounds=" + bounds.toShortString() +
-                " color=" + Integer.toHexString(color));
-        mTmpDrawRect.set(bounds);
+    private void draw() {
+        if (mLastBounds.isEmpty()) {
+            // Currently unset. Set it.
+            mLastBounds.set(mBounds);
+        }
+
+        if (DEBUG) Slog.i(TAG, "draw: mBounds=" + mBounds + " mLastBounds=" + mLastBounds);
+
         Canvas c = null;
         try {
-            c = mSurface.lockCanvas(mTmpDrawRect);
+            c = mSurface.lockCanvas(mLastBounds);
         } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         } catch (Surface.OutOfResourcesException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         }
         if (c == null) {
+            if (DEBUG) Slog.w(TAG, "Canvas is null...");
             return;
         }
 
-        final int w = bounds.width();
-        final int h = bounds.height();
-
-        // Top
-        mTmpDrawRect.set(0, 0, w, THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Left (not including Top or Bottom stripe).
-        mTmpDrawRect.set(0, THICKNESS, THICKNESS, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Right (not including Top or Bottom stripe).
-        mTmpDrawRect.set(w - THICKNESS, THICKNESS, w, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Bottom
-        mTmpDrawRect.set(0, h - THICKNESS, w, h);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-
+        c.drawRect(0, 0, mBounds.width(), mBounds.height(), mOuterPaint);
+        c.drawRect(THICKNESS, THICKNESS, mBounds.width() - THICKNESS, mBounds.height() - THICKNESS,
+                mInnerPaint);
+        if (DEBUG) Slog.w(TAG, "c.width=" + c.getWidth() + " c.height=" + c.getHeight()
+                + " c.clip=" + c .getClipBounds());
         mSurface.unlockCanvasAndPost(c);
+        mLastBounds.set(mBounds);
     }
 
-    private void positionSurface(Rect bounds) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "positionSurface: bounds=" + bounds.toShortString());
-        mSurfaceControl.setSize(bounds.width(), bounds.height());
-        mSurfaceControl.setPosition(bounds.left, bounds.top);
+    private void setupSurface(boolean visible) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setupSurface");
+        SurfaceControl.openTransaction();
+        try {
+            if (visible) {
+                mSurfaceControl.setPosition(mBounds.left, mBounds.top);
+                mSurfaceControl.setSize(mBounds.width(), mBounds.height());
+                mSurfaceControl.show();
+            } else {
+                mSurfaceControl.hide();
+            }
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setupSurface");
+        }
+    }
+
+    void setVisibility(TaskStack stack) {
+        if (stack == null || stack.isFullscreen()) {
+            setupSurface(false);
+        } else {
+            stack.getBounds(mBounds);
+            setupSurface(true);
+            if (!mBounds.equals(mLastBounds)) {
+                draw();
+            }
+        }
     }
 
     // Note: caller responsible for being inside
     // Surface.openTransaction() / closeTransaction()
-    public void setVisibility(boolean on) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "setVisibility: on=" + on +
-                " mLastBounds=" + mLastBounds.toShortString() +
-                " mBounds=" + mBounds.toShortString());
-        if (mSurfaceControl == null) {
+    void setLayer(int layer) {
+        if (mLayer == layer) {
             return;
         }
-        if (on) {
-            if (!mLastBounds.equals(mBounds)) {
-                // Erase the previous rectangle.
-                positionSurface(mLastBounds);
-                draw(mLastBounds, Color.TRANSPARENT);
-                // Draw the latest rectangle.
-                positionSurface(mBounds);
-                draw(mBounds, Color.WHITE);
-                // Update the history.
-                mLastBounds.set(mBounds);
-            }
-            mSurfaceControl.show();
-        } else {
-            mSurfaceControl.hide();
-        }
-    }
-
-    public void setBounds(TaskStack stack) {
-        stack.getBounds(mBounds);
-        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
-    }
-
-    public void setLayer(int layer) {
-        mSurfaceControl.setLayer(layer);
+        mLayer = layer;
+        mSurfaceControl.setLayer(mLayer);
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 27ac32a..55dd911 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -239,9 +239,6 @@
         // As an optimization, we could try to prune the list of windows but this turns
         // out to be difficult because only the native code knows for sure which window
         // currently has touch focus.
-        final WindowStateAnimator universeBackground = mService.mAnimator.mUniverseBackground;
-        final int aboveUniverseLayer = mService.mAnimator.mAboveUniverseLayer;
-        boolean addedUniverse = false;
         boolean disableWallpaperTouchEvents = false;
 
         // If there's a drag in flight, provide a pseudowindow to catch drag input
@@ -299,20 +296,8 @@
                     mService.mDragState.sendDragStartedIfNeededLw(child);
                 }
 
-                if (universeBackground != null && !addedUniverse
-                        && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) {
-                    final WindowState u = universeBackground.mWin;
-                    if (u.mInputChannel != null && u.mInputWindowHandle != null) {
-                        addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags,
-                                u.mAttrs.type, true, u == mInputFocus, false);
-                    }
-                    addedUniverse = true;
-                }
-
-                if (child.mWinAnimator != universeBackground) {
-                    addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible,
-                            hasFocus, hasWallpaper);
-                }
+                addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible, hasFocus,
+                        hasWallpaper);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index f79896b..7dd716e 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -291,12 +291,6 @@
         return mSurfaceControl != null;
     }
 
-    static int deltaRotation(int oldRotation, int newRotation) {
-        int delta = newRotation - oldRotation;
-        if (delta < 0) delta += 4;
-        return delta;
-    }
-
     private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
         if (mSurfaceControl != null) {
             matrix.getValues(mTmpFloats);
@@ -352,7 +346,7 @@
         // Compute the transformation matrix that must be applied
         // to the snapshot to make it stay in the same original position
         // with the current screen rotation.
-        int delta = deltaRotation(rotation, Surface.ROTATION_0);
+        int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
         createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
         if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
@@ -391,7 +385,7 @@
         boolean firstStart = false;
 
         // Figure out how the screen has moved from the original rotation.
-        int delta = deltaRotation(mCurRotation, mOriginalRotation);
+        int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
 
         if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null
                 && (!dismissing || delta != Surface.ROTATION_0)) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index a4dfd8a4..487483e9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -446,20 +446,6 @@
         mService.wallpaperCommandComplete(window, result);
     }
 
-    public void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
-            float dsdx, float dtdx, float dsdy, float dtdy) {
-        synchronized(mService.mWindowMap) {
-            long ident = Binder.clearCallingIdentity();
-            try {
-                mService.setUniverseTransformLocked(
-                        mService.windowForClientLocked(this, window, true),
-                        alpha, offx, offy, dsdx, dtdx, dsdy, dtdy);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
-
     public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized(mService.mWindowMap) {
             final long identity = Binder.clearCallingIdentity();
@@ -475,6 +461,16 @@
         return mService.getWindowId(window);
     }
 
+    @Override
+    public void pokeDrawLock(IBinder window) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mService.pokeDrawLock(this, window);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     void windowAddedLocked() {
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/StackTapPointerEventListener.java b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
index 8938358..1a85993 100644
--- a/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
@@ -31,7 +31,7 @@
     private float mDownX;
     private float mDownY;
     private int mPointerId;
-    final private Region mTouchExcludeRegion;
+    final private Region mTouchExcludeRegion = new Region();
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
 
@@ -39,7 +39,6 @@
             DisplayContent displayContent) {
         mService = service;
         mDisplayContent = displayContent;
-        mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
         DisplayInfo info = displayContent.getDisplayInfo();
         mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
     }
@@ -58,8 +57,8 @@
                     int index = motionEvent.findPointerIndex(mPointerId);
                     if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
                             || index < 0
-                            || (motionEvent.getX(index) - mDownX) > mMotionSlop
-                            || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
+                            || Math.abs(motionEvent.getX(index) - mDownX) > mMotionSlop
+                            || Math.abs(motionEvent.getY(index) - mDownY) > mMotionSlop) {
                         mPointerId = -1;
                     }
                 }
@@ -72,12 +71,15 @@
                 if (mPointerId == motionEvent.getPointerId(index)) {
                     final int x = (int)motionEvent.getX(index);
                     final int y = (int)motionEvent.getY(index);
-                    if ((motionEvent.getEventTime() - motionEvent.getDownTime())
-                            < TAP_TIMEOUT_MSEC
-                            && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
-                            && !mTouchExcludeRegion.contains(x, y)) {
-                        mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
-                                mDisplayContent).sendToTarget();
+                    synchronized(this) {
+                        if ((motionEvent.getEventTime() - motionEvent.getDownTime())
+                                < TAP_TIMEOUT_MSEC
+                                && Math.abs(x - mDownX) < mMotionSlop
+                                && Math.abs(y - mDownY) < mMotionSlop
+                                && !mTouchExcludeRegion.contains(x, y)) {
+                            mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
+                                    mDisplayContent).sendToTarget();
+                        }
                     }
                     mPointerId = -1;
                 }
@@ -85,4 +87,10 @@
             }
         }
     }
+
+    void setTouchExcludeRegion(Region newRegion) {
+        synchronized (this) {
+           mTouchExcludeRegion.set(newRegion);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b49b87c..b8f26c9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,22 +17,25 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.WindowManagerService.TAG;
+import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 
 import android.util.EventLog;
 import android.util.Slog;
+import com.android.server.EventLogTags;
 
 class Task {
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
-    final int taskId;
+    final int mTaskId;
     final int mUserId;
     boolean mDeferRemoval = false;
+    final WindowManagerService mService;
 
-    Task(AppWindowToken wtoken, TaskStack stack, int userId) {
-        taskId = wtoken.groupId;
-        mAppTokens.add(wtoken);
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service) {
+        mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
+        mService = service;
     }
 
     DisplayContent getDisplayContent() {
@@ -41,22 +44,60 @@
 
     void addAppToken(int addPos, AppWindowToken wtoken) {
         final int lastPos = mAppTokens.size();
-        for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
-            if (mAppTokens.get(pos).removed) {
-                // addPos assumes removed tokens are actually gone.
-                ++addPos;
+        if (addPos >= lastPos) {
+            addPos = lastPos;
+        } else {
+            for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
+                if (mAppTokens.get(pos).removed) {
+                    // addPos assumes removed tokens are actually gone.
+                    ++addPos;
+                }
             }
         }
         mAppTokens.add(addPos, wtoken);
+        wtoken.mTask = this;
         mDeferRemoval = false;
     }
 
+    void removeLocked() {
+        if (!mAppTokens.isEmpty() && mStack.isAnimating()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+            mDeferRemoval = true;
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        mDeferRemoval = false;
+        mStack.removeTask(this);
+        mService.mTaskIdToTask.delete(mTaskId);
+    }
+
+    void moveTaskToStack(TaskStack stack, boolean toTop) {
+        if (stack == mStack) {
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+                + " from stack=" + mStack);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        if (mStack != null) {
+            mStack.removeTask(this);
+        }
+        stack.addTask(this, toTop);
+    }
+
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
-            EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
+            EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, mTaskId,
                     "removeAppToken: last token");
+            if (mDeferRemoval) {
+                removeLocked();
+            }
         }
+        wtoken.mTask = null;
+        /* Leave mTaskId for now, it might be useful for debug
+        wtoken.mTaskId = -1;
+         */
         return removed;
     }
 
@@ -68,6 +109,6 @@
 
     @Override
     public String toString() {
-        return "{taskId=" + taskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
+        return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 238c77e..6d09f55 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -19,11 +19,15 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerService.TAG;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Debug;
+import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.Surface;
+
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -49,6 +53,8 @@
 
     /** For comparison with DisplayContent bounds. */
     private Rect mTmpRect = new Rect();
+    /** For handling display rotations. */
+    private Rect mTmpRect2 = new Rect();
 
     /** Content limits relative to the DisplayContent this sits in. */
     private Rect mBounds = new Rect();
@@ -78,9 +84,24 @@
     /** Detach this stack from its display when animation completes. */
     boolean mDeferDetach;
 
+    // Contains configurations settings that are different from the global configuration due to
+    // stack specific operations. E.g. {@link #setBounds}.
+    Configuration mOverrideConfig;
+    // True if the stack was forced to fullscreen disregarding the override configuration.
+    private boolean mForceFullscreen;
+    // The {@link #mBounds} before the stack was forced to fullscreen. Will be restored as the
+    // stack bounds once the stack is no longer forced to fullscreen.
+    final private Rect mPreForceFullscreenBounds;
+
+    // Device rotation as of the last time {@link #mBounds} was set.
+    int mRotation;
+
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
+        mOverrideConfig = Configuration.EMPTY;
+        mForceFullscreen = false;
+        mPreForceFullscreenBounds = new Rect();
         // TODO: remove bounds from log, they are always 0.
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
                 mBounds.right, mBounds.bottom);
@@ -95,8 +116,6 @@
     }
 
     void resizeWindows() {
-        final boolean underStatusBar = mBounds.top == 0;
-
         final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
@@ -109,27 +128,40 @@
                                 "setBounds: Resizing " + win);
                         resizingWindows.add(win);
                     }
-                    win.mUnderStatusBar = underStatusBar;
                 }
             }
         }
     }
 
+    /** Set the stack bounds. Passing in null sets the bounds to fullscreen. */
     boolean setBounds(Rect bounds) {
         boolean oldFullscreen = mFullscreen;
+        int rotation = Surface.ROTATION_0;
         if (mDisplayContent != null) {
             mDisplayContent.getLogicalDisplayRect(mTmpRect);
-            mFullscreen = mTmpRect.equals(bounds);
+            rotation = mDisplayContent.getDisplayInfo().rotation;
+            if (bounds == null) {
+                bounds = mTmpRect;
+                mFullscreen = true;
+            } else {
+                bounds.intersect(mTmpRect); // ensure bounds are entirely within the display rect
+                mFullscreen = mTmpRect.equals(bounds);
+            }
         }
 
-        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) {
+        if (bounds == null) {
+            // Can't set to fullscreen if we don't have a display to get bounds from...
+            return false;
+        }
+        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
             return false;
         }
 
         mDimLayer.setBounds(bounds);
         mAnimationBackgroundSurface.setBounds(bounds);
         mBounds.set(bounds);
-
+        mRotation = rotation;
+        updateOverrideConfiguration();
         return true;
     }
 
@@ -137,10 +169,67 @@
         out.set(mBounds);
     }
 
+    private void updateOverrideConfiguration() {
+        final Configuration serviceConfig = mService.mCurConfiguration;
+        if (mFullscreen) {
+            mOverrideConfig = Configuration.EMPTY;
+            return;
+        }
+
+        if (mOverrideConfig == Configuration.EMPTY) {
+            mOverrideConfig  = new Configuration();
+        }
+
+        // TODO(multidisplay): Update Dp to that of display stack is on.
+        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        mOverrideConfig.screenWidthDp =
+                Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+        mOverrideConfig.screenHeightDp =
+                Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+        mOverrideConfig.smallestScreenWidthDp =
+                Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+        mOverrideConfig.orientation =
+                (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+                        ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+    }
+
     void updateDisplayInfo() {
-        if (mFullscreen && mDisplayContent != null) {
+        if (mFullscreen) {
+            setBounds(null);
+        } else if (mDisplayContent != null) {
+            final int newRotation = mDisplayContent.getDisplayInfo().rotation;
+            if (mRotation == newRotation) {
+                return;
+            }
+
+            // Device rotation changed. We don't want the stack to move around on the screen when
+            // this happens, so update the stack bounds so it stays in the same place.
+            final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation);
             mDisplayContent.getLogicalDisplayRect(mTmpRect);
-            setBounds(mTmpRect);
+            switch (rotationDelta) {
+                case Surface.ROTATION_0:
+                    mTmpRect2.set(mBounds);
+                    break;
+                case Surface.ROTATION_90:
+                    mTmpRect2.top = mTmpRect.bottom - mBounds.right;
+                    mTmpRect2.left = mBounds.top;
+                    mTmpRect2.right = mTmpRect2.left + mBounds.height();
+                    mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
+                    break;
+                case Surface.ROTATION_180:
+                    mTmpRect2.top = mTmpRect.bottom - mBounds.bottom;
+                    mTmpRect2.left = mTmpRect.right - mBounds.right;
+                    mTmpRect2.right = mTmpRect2.left + mBounds.width();
+                    mTmpRect2.bottom = mTmpRect2.top + mBounds.height();
+                    break;
+                case Surface.ROTATION_270:
+                    mTmpRect2.top = mBounds.left;
+                    mTmpRect2.left = mTmpRect.right - mBounds.bottom;
+                    mTmpRect2.right = mTmpRect2.left + mBounds.height();
+                    mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
+                    break;
+            }
+            setBounds(mTmpRect2);
         }
     }
 
@@ -148,6 +237,28 @@
         return mFullscreen;
     }
 
+    /** Forces the stack to fullscreen if input is true, else un-forces the stack from fullscreen.
+     * Returns true if something happened.
+     */
+    boolean forceFullscreen(boolean forceFullscreen) {
+        if (mForceFullscreen == forceFullscreen) {
+            return false;
+        }
+        mForceFullscreen = forceFullscreen;
+        if (forceFullscreen) {
+            if (mFullscreen) {
+                return false;
+            }
+            mPreForceFullscreenBounds.set(mBounds);
+            return setBounds(null);
+        } else {
+            if (!mFullscreen || mPreForceFullscreenBounds.isEmpty()) {
+                return false;
+            }
+            return setBounds(mPreForceFullscreenBounds);
+        }
+    }
+
     boolean isAnimating() {
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
@@ -191,8 +302,10 @@
         mTasks.add(stackNdx, task);
 
         task.mStack = this;
-        mDisplayContent.moveStack(this, true);
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx);
+        if (toTop) {
+            mDisplayContent.moveStack(this, true);
+        }
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, stackNdx);
     }
 
     void moveTaskToTop(Task task) {
@@ -222,6 +335,13 @@
             }
             mDisplayContent.layoutNeeded = true;
         }
+        for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
+            final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
+            if (wtoken.mTask == task) {
+                wtoken.mIsExiting = false;
+                mExitingAppTokens.remove(appNdx);
+            }
+        }
     }
 
     void attachDisplayContent(DisplayContent displayContent) {
@@ -244,7 +364,7 @@
             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));
+                    mService.removeWindowInnerLocked(appWindows.get(winNdx));
                     doAnotherLayoutPass = true;
                 }
             }
@@ -336,18 +456,24 @@
 
     void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
         // Only set dim params on the highest dimmed layer.
-        final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator;
         // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
-        if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
-                || !existingDimWinAnimator.mSurfaceShown
-                || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+        if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null
+                || !mDimWinAnimator.mSurfaceShown
+                || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
             mDimWinAnimator = newWinAnimator;
+            if (mDimWinAnimator.mWin.mAppToken == null
+                    && !mFullscreen && mDisplayContent != null) {
+                // Dim should cover the entire screen for system windows.
+                mDisplayContent.getLogicalDisplayRect(mTmpRect);
+                mDimLayer.setBounds(mTmpRect);
+            }
         }
     }
 
     void stopDimmingIfNeeded() {
         if (!mDimmingTag && isDimming()) {
             mDimWinAnimator = null;
+            mDimLayer.setBounds(mBounds);
         }
     }
 
@@ -362,7 +488,7 @@
         }
     }
 
-    void switchUser(int userId) {
+    void switchUser() {
         int top = mTasks.size();
         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
             Task task = mTasks.get(taskNdx);
@@ -391,7 +517,7 @@
         }
         if (mDimLayer.isDimming()) {
             pw.print(prefix); pw.println("mDimLayer:");
-            mDimLayer.printTo(prefix, pw);
+            mDimLayer.printTo(prefix + " ", pw);
             pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
         }
         if (!mExitingAppTokens.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 64713d9..46fa38a 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -30,8 +30,6 @@
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
 
 import android.content.Context;
-import android.os.Debug;
-import android.os.SystemClock;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -41,6 +39,7 @@
 import android.view.WindowManagerPolicy;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
+import android.view.Choreographer;
 
 import com.android.server.wm.WindowManagerService.LayoutFields;
 
@@ -61,9 +60,13 @@
     final Context mContext;
     final WindowManagerPolicy mPolicy;
 
+    /** Is any window animating? */
     boolean mAnimating;
 
-    final Runnable mAnimationRunnable;
+    /** Is any app window animating? */
+    boolean mAppWindowAnimating;
+
+    final Choreographer.FrameCallback mAnimationFrameCallback;
 
     /** Time of current animation step. Reset on each iteration */
     long mCurrentTime;
@@ -78,9 +81,6 @@
      * seen. If multiple windows satisfy this, use the lowest window. */
     WindowState mWindowDetachedWallpaper = null;
 
-    WindowStateAnimator mUniverseBackground = null;
-    int mAboveUniverseLayer = 0;
-
     int mBulkUpdateParams = 0;
     Object mLastWindowFreezeSource;
 
@@ -118,12 +118,11 @@
         mContext = service.mContext;
         mPolicy = service.mPolicy;
 
-        mAnimationRunnable = new Runnable() {
-            @Override
-            public void run() {
+        mAnimationFrameCallback = new Choreographer.FrameCallback() {
+            public void doFrame(long frameTimeNs) {
                 synchronized (mService.mWindowMap) {
                     mService.mAnimationScheduled = false;
-                    animateLocked();
+                    animateLocked(frameTimeNs);
                 }
             }
         };
@@ -149,35 +148,6 @@
         mDisplayContentsAnimators.delete(displayId);
     }
 
-    void hideWallpapersLocked(final WindowState w) {
-        final WindowState wallpaperTarget = mService.mWallpaperTarget;
-        final WindowState lowerWallpaperTarget = mService.mLowerWallpaperTarget;
-        final ArrayList<WindowToken> wallpaperTokens = mService.mWallpaperTokens;
-
-        if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
-            final int numTokens = wallpaperTokens.size();
-            for (int i = numTokens - 1; i >= 0; i--) {
-                final WindowToken token = wallpaperTokens.get(i);
-                final int numWindows = token.windows.size();
-                for (int j = numWindows - 1; j >= 0; j--) {
-                    final WindowState wallpaper = token.windows.get(j);
-                    final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
-                    if (!winAnimator.mLastHidden) {
-                        winAnimator.hide();
-                        mService.dispatchWallpaperVisibility(wallpaper, false);
-                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
-                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
-                    }
-                }
-                if (WindowManagerService.DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG,
-                        "Hiding wallpaper " + token + " from " + w
-                        + " target=" + wallpaperTarget + " lower=" + lowerWallpaperTarget
-                        + "\n" + Debug.getCallers(5, "  "));
-                token.hidden = true;
-            }
-        }
-    }
-
     private void updateAppWindowsLocked(int displayId) {
         ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -190,7 +160,7 @@
                     final boolean wasAnimating = appAnimator.animation != null
                             && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                     if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                        mAnimating = true;
+                        mAnimating = mAppWindowAnimating = true;
                     } else if (wasAnimating) {
                         // stopped animating, do one more pass through the layout
                         setAppLayoutChanges(appAnimator,
@@ -209,7 +179,7 @@
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                 if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                    mAnimating = true;
+                    mAnimating = mAppWindowAnimating = true;
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
@@ -624,15 +594,16 @@
 
 
     /** Locked on mService.mWindowMap. */
-    private void animateLocked() {
+    private void animateLocked(long frameTimeNs) {
         if (!mInitialized) {
             return;
         }
 
-        mCurrentTime = SystemClock.uptimeMillis();
+        mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
         boolean wasAnimating = mAnimating;
         mAnimating = false;
+        mAppWindowAnimating = false;
         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
         }
@@ -794,6 +765,7 @@
             } else if (dumpAll) {
                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
             }
+            pw.println();
         }
 
         pw.println();
@@ -814,10 +786,6 @@
             pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
                 pw.println(mWindowDetachedWallpaper);
         }
-        if (mUniverseBackground != null) {
-            pw.print(prefix); pw.print("mUniverseBackground="); pw.print(mUniverseBackground);
-                    pw.print(" mAboveUniverseLayer="); pw.println(mAboveUniverseLayer);
-        }
     }
 
     int getPendingLayoutChanges(final int displayId) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 089d897..99bad07 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 import static android.view.WindowManager.LayoutParams.*;
 
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -29,8 +30,6 @@
 import android.view.IWindowSessionCallback;
 import android.view.WindowContentFrameStats;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.policy.impl.PhoneWindowManager;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -45,6 +44,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.input.InputManagerService;
 import com.android.server.power.ShutdownThread;
+import com.android.server.policy.PhoneWindowManager;
 
 import android.Manifest;
 import android.app.ActivityManagerNative;
@@ -65,11 +65,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
@@ -128,7 +126,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
@@ -137,7 +134,6 @@
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.view.animation.Transformation;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -153,6 +149,7 @@
 import java.net.Socket;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -181,7 +178,6 @@
     static final boolean DEBUG_CONFIGURATION = false;
     static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
-    static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
@@ -194,6 +190,7 @@
     static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
+    static final boolean DEBUG_POWER = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -283,12 +280,6 @@
     // The name of the boot animation service in init.rc.
     private static final String BOOT_ANIMATION_SERVICE = "bootanim";
 
-    /** Minimum value for attachStack and resizeStack weight value */
-    public static final float STACK_WEIGHT_MIN = 0.2f;
-
-    /** Maximum value for attachStack and resizeStack weight value */
-    public static final float STACK_WEIGHT_MAX = 0.8f;
-
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
@@ -338,12 +329,13 @@
     final boolean mHaveInputMethods;
 
     final boolean mHasPermanentDpad;
+    final long mDrawLockTimeoutMillis;
 
     final boolean mAllowBootMessages;
 
     final boolean mLimitedAlphaCompositing;
 
-    final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
+    final WindowManagerPolicy mPolicy = new PhoneWindowManager();
 
     final IActivityManager mActivityManager;
 
@@ -419,7 +411,7 @@
      * This is set when we have run out of memory, and will either be an empty
      * list or contain windows that need to be force removed.
      */
-    ArrayList<WindowState> mForceRemoves;
+    final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
 
     /**
      * Windows that clients are waiting to have drawn.
@@ -504,7 +496,12 @@
     int mLastDisplayFreezeDuration = 0;
     Object mLastFinishedFreezeSource = null;
     boolean mWaitingForConfig = false;
-    boolean mWindowsFreezingScreen = false;
+
+    final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
+    final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
+    final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
+    private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
     int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -555,6 +552,10 @@
     WindowState mInputMethodWindow = null;
     final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
 
+    /** Temporary list for comparison. Always clear this after use so we don't end up with
+     * orphaned windows references */
+    final ArrayList<WindowState> mTmpWindows = new ArrayList<>();
+
     boolean mHardKeyboardAvailable;
     boolean mShowImeWithHardKeyboard;
     OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
@@ -584,7 +585,7 @@
         }
     }
 
-    final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
+    private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
 
     // If non-null, this is the currently visible window that is associated
     // with the wallpaper.
@@ -613,6 +614,13 @@
     static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
     boolean mAnimateWallpaperWithTarget;
 
+    // We give a wallpaper up to 1000ms to finish drawing before playing app transitions.
+    static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 1000;
+    static final int WALLPAPER_DRAW_NORMAL = 0;
+    static final int WALLPAPER_DRAW_PENDING = 1;
+    static final int WALLPAPER_DRAW_TIMEOUT = 2;
+    int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+
     AppWindowToken mFocusedApp = null;
 
     PowerManager mPowerManager;
@@ -687,11 +695,11 @@
 
     final WindowAnimator mAnimator;
 
-    SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+    SparseArray<Task> mTaskIdToTask = new SparseArray<>();
 
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
      * DisplayContent.getStacks(). */
-    SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
+    SparseArray<TaskStack> mStackIdToStack = new SparseArray<>();
 
     private final PointerEventDispatcher mPointerEventDispatcher;
 
@@ -786,6 +794,35 @@
     // For example, when this flag is true, there will be no wallpaper service.
     final boolean mOnlyCore;
 
+    /** Listener to notify activity manager about app transitions. */
+    private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
+            = new WindowManagerInternal.AppTransitionListener() {
+
+        @Override
+        public void onAppTransitionFinishedLocked(IBinder token) {
+            AppWindowToken atoken = findAppWindowToken(token);
+            if (atoken == null) {
+                return;
+            }
+            if (atoken.mLaunchTaskBehind) {
+                try {
+                    mActivityManager.notifyLaunchTaskBehindComplete(atoken.token);
+                } catch (RemoteException e) {
+                }
+                atoken.mLaunchTaskBehind = false;
+            } else {
+                atoken.updateReportedVisibilityLocked();
+                if (atoken.mEnteringAnimation) {
+                    atoken.mEnteringAnimation = false;
+                    try {
+                        mActivityManager.notifyEnterAnimationComplete(atoken.token);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+    };
+
     public static WindowManagerService main(final Context context,
             final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs,
@@ -808,9 +845,6 @@
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
 
                 mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
-                mAnimator.mAboveUniverseLayer = mPolicy.getAboveUniverseLayer()
-                        * TYPE_LAYER_MULTIPLIER
-                        + TYPE_LAYER_OFFSET;
             }
         }, 0);
     }
@@ -827,6 +861,8 @@
                 com.android.internal.R.bool.config_hasPermanentDpad);
         mInTouchMode = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_defaultInTouchMode);
+        mDrawLockTimeoutMillis = context.getResources().getInteger(
+                com.android.internal.R.integer.config_drawLockTimeoutMillis);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplaySettings = new DisplaySettings();
@@ -865,6 +901,7 @@
         mScreenFrozenLock.setReferenceCounted(false);
 
         mAppTransition = new AppTransition(context, mH);
+        mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
 
         mActivityManager = ActivityManagerNative.getDefault();
         mBatteryStats = BatteryStatsService.getService();
@@ -1699,7 +1736,7 @@
         return true;
     }
 
-    final boolean isWallpaperVisible(WindowState wallpaperTarget) {
+    private boolean isWallpaperVisible(WindowState wallpaperTarget) {
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
                 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
@@ -1713,10 +1750,35 @@
                 || mLowerWallpaperTarget != null;
     }
 
-    static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
-    static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
+    void hideWallpapersLocked(final WindowState winGoingAway) {
+        if (mWallpaperTarget != null &&
+                (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
+            return;
+        }
 
-    int adjustWallpaperWindowsLocked() {
+        for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+            final WindowToken token = mWallpaperTokens.get(i);
+            for (int j = token.windows.size() - 1; j >= 0; j--) {
+                final WindowState wallpaper = token.windows.get(j);
+                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+                if (!winAnimator.mLastHidden) {
+                    winAnimator.hide();
+                    dispatchWallpaperVisibility(wallpaper, false);
+                    final DisplayContent displayContent = wallpaper.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.pendingLayoutChanges |=
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+            }
+            if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
+                    + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
+                    + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
+            token.hidden = true;
+        }
+    }
+
+    boolean adjustWallpaperWindowsLocked() {
         mInnerFields.mWallpaperMayChange = false;
         boolean targetChanged = false;
 
@@ -1895,7 +1957,7 @@
             // AND any starting window associated with it, AND below the
             // maximum layer the policy allows for wallpapers.
             while (foundI > 0) {
-                WindowState wb = windows.get(foundI-1);
+                WindowState wb = windows.get(foundI - 1);
                 if (wb.mBaseLayer < maxLayer &&
                         wb.mAttachedWindow != foundW &&
                         (foundW.mAttachedWindow == null ||
@@ -1921,7 +1983,7 @@
         } else {
             // Okay i is the position immediately above the wallpaper.  Look at
             // what is below it for later.
-            foundW = foundI > 0 ? windows.get(foundI-1) : null;
+            foundW = foundI > 0 ? windows.get(foundI - 1) : null;
         }
 
         if (visible) {
@@ -1943,44 +2005,37 @@
 
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
-        int changed = 0;
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+        boolean changed = false;
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowToken token = mWallpaperTokens.get(curTokenNdx);
             if (token.hidden == visible) {
                 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
                         "Wallpaper token " + token + " hidden=" + !visible);
-                changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED;
                 token.hidden = !visible;
-                // Need to do a layout to ensure the wallpaper now has the
-                // correct size.
+                // Need to do a layout to ensure the wallpaper now has the correct size.
                 getDefaultDisplayContentLocked().layoutNeeded = true;
             }
 
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            final WindowList tokenWindows = token.windows;
+            for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = tokenWindows.get(wallpaperNdx);
 
                 if (visible) {
                     updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
 
-                // First, make sure the client has the current visibility
-                // state.
+                // First, make sure the client has the current visibility state.
                 dispatchWallpaperVisibility(wallpaper, visible);
 
-                wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
+                wallpaper.mWinAnimator.mAnimLayer =
+                        wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
                 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
 
-                // First, if this window is at the current index, then all
-                // is well.
+                // First, if this window is at the current index, then all is well.
                 if (wallpaper == foundW) {
                     foundI--;
-                    foundW = foundI > 0
-                            ? windows.get(foundI-1) : null;
+                    foundW = foundI > 0 ? windows.get(foundI - 1) : null;
                     continue;
                 }
 
@@ -2016,52 +2071,24 @@
 
                 windows.add(insertionIndex, wallpaper);
                 mWindowsChanged = true;
-                changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
+                changed = true;
             }
         }
 
-        /*
-        final TaskStack targetStack =
-                mWallpaperTarget == null ? null : mWallpaperTarget.getStack();
-        if ((changed & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0 &&
-                targetStack != null && !targetStack.isHomeStack()) {
-            // If the wallpaper target is not on the home stack then make sure that all windows
-            // from other non-home stacks are above the wallpaper.
-            for (i = foundI - 1; i >= 0; --i) {
-                WindowState win = windows.get(i);
-                if (!win.isVisibleLw()) {
-                    continue;
-                }
-                final TaskStack winStack = win.getStack();
-                if (winStack != null && !winStack.isHomeStack() && winStack != targetStack) {
-                    windows.remove(i);
-                    windows.add(foundI + 1, win);
-                }
-            }
-        }
-        */
-
-        if (targetChanged && DEBUG_WALLPAPER_LIGHT) {
-            Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
-                    + " lower=" + mLowerWallpaperTarget + " upper="
-                    + mUpperWallpaperTarget);
-        }
+        if (targetChanged && DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target="
+                + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
+                + mUpperWallpaperTarget);
 
         return changed;
     }
 
     void setWallpaperAnimLayerAdjustmentLocked(int adj) {
-        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
-                "Setting wallpaper layer adj to " + adj);
+        if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
         mWallpaperAnimLayerAdjustment = adj;
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
                 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
@@ -2195,14 +2222,10 @@
             }
         }
 
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) {
                     WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
                     winAnimator.computeShownFrameLocked();
@@ -2234,7 +2257,7 @@
         }
     }
 
-    void updateWallpaperVisibilityLocked() {
+    private void updateWallpaperVisibilityLocked() {
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
         final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
         if (displayContent == null) {
@@ -2244,21 +2267,18 @@
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
 
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
+        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+            WindowToken token = mWallpaperTokens.get(curTokenNdx);
             if (token.hidden == visible) {
                 token.hidden = !visible;
                 // Need to do a layout to ensure the wallpaper now has the
                 // correct size.
-                getDefaultDisplayContentLocked().layoutNeeded = true;
+                displayContent.layoutNeeded = true;
             }
 
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            final WindowList windows = token.windows;
+            for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                WindowState wallpaper = windows.get(wallpaperNdx);
                 if (visible) {
                     updateWallpaperOffsetLocked(wallpaper, dw, dh, false);
                 }
@@ -2672,7 +2692,7 @@
             }
         }
 
-        removeWindowInnerLocked(session, win);
+        removeWindowInnerLocked(win);
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && updateOrientationFromAppTokensLocked(false)) {
@@ -2682,7 +2702,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    void removeWindowInnerLocked(Session session, WindowState win) {
+    void removeWindowInnerLocked(WindowState win) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2692,7 +2712,7 @@
             WindowState cwin = win.mChildWindows.get(i);
             Slog.w(TAG, "Force-removing child win " + cwin + " from container "
                     + win);
-            removeWindowInnerLocked(cwin.mSession, cwin);
+            removeWindowInnerLocked(cwin);
         }
 
         win.mRemoved = true;
@@ -2916,14 +2936,10 @@
         if (window == mWallpaperTarget || window == mLowerWallpaperTarget
                 || window == mUpperWallpaperTarget) {
             boolean doWait = sync;
-            int curTokenIndex = mWallpaperTokens.size();
-            while (curTokenIndex > 0) {
-                curTokenIndex--;
-                WindowToken token = mWallpaperTokens.get(curTokenIndex);
-                int curWallpaperIndex = token.windows.size();
-                while (curWallpaperIndex > 0) {
-                    curWallpaperIndex--;
-                    WindowState wallpaper = token.windows.get(curWallpaperIndex);
+            for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+                final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
+                for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
+                    WindowState wallpaper = windows.get(wallpaperNdx);
                     try {
                         wallpaper.mClient.dispatchWallpaperCommand(action,
                                 x, y, z, extras, sync);
@@ -2942,37 +2958,6 @@
         return null;
     }
 
-    public void setUniverseTransformLocked(WindowState window, float alpha,
-            float offx, float offy, float dsdx, float dtdx, float dsdy, float dtdy) {
-        Transformation transform = window.mWinAnimator.mUniverseTransform;
-        transform.setAlpha(alpha);
-        Matrix matrix = transform.getMatrix();
-        matrix.getValues(mTmpFloats);
-        mTmpFloats[Matrix.MTRANS_X] = offx;
-        mTmpFloats[Matrix.MTRANS_Y] = offy;
-        mTmpFloats[Matrix.MSCALE_X] = dsdx;
-        mTmpFloats[Matrix.MSKEW_Y] = dtdx;
-        mTmpFloats[Matrix.MSKEW_X] = dsdy;
-        mTmpFloats[Matrix.MSCALE_Y] = dtdy;
-        matrix.setValues(mTmpFloats);
-        final DisplayContent displayContent = window.getDisplayContent();
-        if (displayContent == null) {
-            return;
-        }
-
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final RectF dispRect = new RectF(0, 0,
-                displayInfo.logicalWidth, displayInfo.logicalHeight);
-        matrix.mapRect(dispRect);
-        window.mGivenTouchableRegion.set(0, 0,
-                displayInfo.logicalWidth, displayInfo.logicalHeight);
-        window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
-                (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
-        window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-        displayContent.layoutNeeded = true;
-        performLayoutAndPlaceSurfacesLocked();
-    }
-
     public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized (mWindowMap) {
             if (mAccessibilityController != null) {
@@ -2992,6 +2977,15 @@
         }
     }
 
+    public void pokeDrawLock(Session session, IBinder token) {
+        synchronized (mWindowMap) {
+            WindowState window = windowForClientLocked(session, token, false);
+            if (window != null) {
+                window.pokeDrawLockLw(mDrawLockTimeoutMillis);
+            }
+        }
+    }
+
     public int relayoutWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
@@ -3592,13 +3586,13 @@
                                 false /*updateInputWindows*/);
                     }
 
-                    if (delayed) {
-                        if (displayContent != null) {
-                            displayContent.mExitingTokens.add(wtoken);
-                        }
+                    if (delayed && displayContent != null) {
+                        displayContent.mExitingTokens.add(wtoken);
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
+                } else if (wtoken.windowType == TYPE_WALLPAPER) {
+                    mWallpaperTokens.remove(wtoken);
                 }
 
                 mInputMonitor.updateInputWindowsLw(true /*force*/);
@@ -3609,15 +3603,15 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) {
-        if (DEBUG_STACK) Slog.i(TAG, "createTask: taskId=" + taskId + " stackId=" + stackId
+    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken) {
+        if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
                 + " atoken=" + atoken);
         final TaskStack stack = mStackIdToStack.get(stackId);
         if (stack == null) {
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(atoken, stack, userId);
+        Task task = new Task(taskId, stack, userId, this);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */);
         return task;
@@ -3654,7 +3648,6 @@
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-            atoken.groupId = taskId;
             atoken.appFullscreen = fullscreen;
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
@@ -3666,10 +3659,9 @@
 
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
-                createTask(taskId, stackId, userId, atoken);
-            } else {
-                task.addAppToken(addPos, atoken);
+                task = createTaskLocked(taskId, stackId, userId, atoken);
             }
+            task.addAppToken(addPos, atoken);
 
             mTokenMap.put(token.asBinder(), atoken);
 
@@ -3682,28 +3674,27 @@
     }
 
     @Override
-    public void setAppGroupId(IBinder token, int groupId) {
+    public void setAppTask(IBinder token, int taskId) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "setAppGroupId()")) {
+                "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
 
         synchronized(mWindowMap) {
             final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
-                Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
+                Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
                 return;
             }
-            final Task oldTask = mTaskIdToTask.get(atoken.groupId);
+            final Task oldTask = atoken.mTask;
             oldTask.removeAppToken(atoken);
 
-            atoken.groupId = groupId;
-            Task newTask = mTaskIdToTask.get(groupId);
+            Task newTask = mTaskIdToTask.get(taskId);
             if (newTask == null) {
-                newTask = createTask(groupId, oldTask.mStack.mStackId, oldTask.mUserId, atoken);
-            } else {
-                newTask.mAppTokens.add(atoken);
+                newTask =
+                        createTaskLocked(taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken);
             }
+            newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
         }
     }
 
@@ -3719,14 +3710,12 @@
 
         // TODO(multidisplay): Change to the correct display.
         final WindowList windows = getDefaultWindowListLocked();
-        int pos = windows.size() - 1;
-        while (pos >= 0) {
+        for (int pos = windows.size() - 1; pos >= 0; --pos) {
             WindowState win = windows.get(pos);
-            pos--;
             if (win.mAppToken != null) {
                 // We hit an application window. so the orientation will be determined by the
                 // app window. No point in continuing further.
-                return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+                return (mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
             }
             if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) {
                 continue;
@@ -3738,9 +3727,9 @@
             }
 
             if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req);
-            return (mLastWindowForcedOrientation=req);
+            return (mLastWindowForcedOrientation = req);
         }
-        return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        return (mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
     }
 
     public int getOrientationFromAppTokensLocked() {
@@ -3798,14 +3787,12 @@
                 // to use the orientation behind it, then just take whatever
                 // orientation it has and ignores whatever is under it.
                 lastFullscreen = atoken.appFullscreen;
-                if (lastFullscreen
-                        && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                if (lastFullscreen && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
                             + " -- full screen, return " + or);
                     return or;
                 }
-                // If this application has requested an explicit orientation,
-                // then use it.
+                // If this application has requested an explicit orientation, then use it.
                 if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                         && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
@@ -3841,6 +3828,9 @@
 
     private Configuration updateOrientationFromAppTokensLocked(
             Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
+        if (!mDisplayReady) {
+            return null;
+        }
         Configuration config = null;
 
         if (updateOrientationFromAppTokensLocked(false)) {
@@ -3859,20 +3849,19 @@
             // the value of the previous configuration.
             mTempConfiguration.setToDefaults();
             mTempConfiguration.fontScale = currentConfig.fontScale;
-            if (computeScreenConfigurationLocked(mTempConfiguration)) {
-                if (currentConfig.diff(mTempConfiguration) != 0) {
-                    mWaitingForConfig = true;
-                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                    displayContent.layoutNeeded = true;
-                    int anim[] = new int[2];
-                    if (displayContent.isDimming()) {
-                        anim[0] = anim[1] = 0;
-                    } else {
-                        mPolicy.selectRotationAnimationLw(anim);
-                    }
-                    startFreezingDisplayLocked(false, anim[0], anim[1]);
-                    config = new Configuration(mTempConfiguration);
+            computeScreenConfigurationLocked(mTempConfiguration);
+            if (currentConfig.diff(mTempConfiguration) != 0) {
+                mWaitingForConfig = true;
+                final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                displayContent.layoutNeeded = true;
+                int anim[] = new int[2];
+                if (displayContent.isDimming()) {
+                    anim[0] = anim[1] = 0;
+                } else {
+                    mPolicy.selectRotationAnimationLw(anim);
                 }
+                startFreezingDisplayLocked(false, anim[0], anim[1]);
+                config = new Configuration(mTempConfiguration);
             }
         }
 
@@ -3987,7 +3976,7 @@
     void setFocusedStackFrame() {
         final TaskStack stack;
         if (mFocusedApp != null) {
-            Task task = mTaskIdToTask.get(mFocusedApp.groupId);
+            final Task task = mFocusedApp.mTask;
             stack = task.mStack;
             final DisplayContent displayContent = task.getDisplayContent();
             if (displayContent != null) {
@@ -3996,20 +3985,7 @@
         } else {
             stack = null;
         }
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame");
-        SurfaceControl.openTransaction();
-        try {
-            if (stack == null) {
-                mFocusedStackFrame.setVisibility(false);
-            } else {
-                mFocusedStackFrame.setBounds(stack);
-                final boolean multipleStacks = !stack.isFullscreen();
-                mFocusedStackFrame.setVisibility(multipleStacks);
-            }
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame");
-        }
+        mFocusedStackFrame.setVisibility(stack);
     }
 
     @Override
@@ -4037,6 +4013,15 @@
             if (changed) {
                 mFocusedApp = newFocus;
                 mInputMonitor.setFocusedAppLw(newFocus);
+                setFocusedStackFrame();
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedApp");
+                SurfaceControl.openTransaction();
+                try {
+                    setFocusedStackLayer();
+                } finally {
+                    SurfaceControl.closeTransaction();
+                    if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedApp");
+                }
             }
 
             if (moveFocusNow && changed) {
@@ -4079,6 +4064,8 @@
                 mAppTransition.prepare();
                 mStartingIconInTransition = false;
                 mSkipAppTransitionAnimation = false;
+            }
+            if (mAppTransition.isTransitionSet()) {
                 mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
                 mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, 5000);
             }
@@ -4109,6 +4096,15 @@
     }
 
     @Override
+    public void overridePendingAppTransitionClipReveal(int startX, int startY,
+            int startWidth, int startHeight) {
+        synchronized(mWindowMap) {
+            mAppTransition.overridePendingAppTransitionClipReveal(startX, startY, startWidth,
+                    startHeight);
+        }
+    }
+
+    @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
             int startY, IRemoteCallback startedCallback, boolean scaleUp) {
         synchronized(mWindowMap) {
@@ -4334,8 +4330,13 @@
                         + " ShowWallpaper="
                         + ent.array.getBoolean(
                                 com.android.internal.R.styleable.Window_windowShowWallpaper, false));
-                if (ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+                final boolean windowIsTranslucentDefined = ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent);
+                final boolean windowIsTranslucent = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                final boolean windowSwipeToDismiss = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+                if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
                     return;
                 }
                 if (ent.array.getBoolean(
@@ -4644,6 +4645,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
+            wtoken.inPendingTransaction = false;
             setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,
                     true, wtoken.voiceInteraction);
             wtoken.updateReportedVisibilityLocked();
@@ -4711,7 +4713,7 @@
                 if (mAppsFreezingScreen == 1) {
                     startFreezingDisplayLocked(false, 0, 0);
                     mH.removeMessages(H.APP_FREEZE_TIMEOUT);
-                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000);
+                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
             }
             final int N = wtoken.allAppWindows.size();
@@ -4766,17 +4768,6 @@
         }
     }
 
-    void removeAppFromTaskLocked(AppWindowToken wtoken) {
-        wtoken.removeAllWindows();
-
-        final Task task = mTaskIdToTask.get(wtoken.groupId);
-        if (task != null) {
-            if (!task.removeAppToken(wtoken)) {
-                Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found.");
-            }
-        }
-    }
-
     @Override
     public void removeAppToken(IBinder token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4811,20 +4802,20 @@
                         + " animating=" + wtoken.mAppAnimator.animating);
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: "
                         + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
-                final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
+                final TaskStack stack = wtoken.mTask.mStack;
                 if (delayed && !wtoken.allAppWindows.isEmpty()) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
                     stack.mExitingAppTokens.add(wtoken);
-                    wtoken.mDeferRemoval = true;
+                    wtoken.mIsExiting = true;
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
-                    removeAppFromTaskLocked(wtoken);
+                    wtoken.removeAppFromTaskLocked();
                 }
 
                 wtoken.removed = true;
@@ -4867,28 +4858,6 @@
         }
     }
 
-    private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
-        WindowList windows = token.windows;
-        final int NW = windows.size();
-        if (NW > 0) {
-            mWindowsChanged = true;
-        }
-        for (int i = 0; i < NW; i++) {
-            WindowState win = windows.get(i);
-            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
-            win.getWindowList().remove(win);
-            int j = win.mChildWindows.size();
-            while (j > 0) {
-                j--;
-                WindowState cwin = win.mChildWindows.get(j);
-                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
-                        "Tmp removing child window " + cwin);
-                cwin.getWindowList().remove(cwin);
-            }
-        }
-        return NW > 0;
-    }
-
     void dumpAppTokensLocked() {
         final int numStacks = mStackIdToStack.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
@@ -4898,7 +4867,7 @@
             final int numTasks = tasks.size();
             for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
                 final Task task = tasks.get(taskNdx);
-                Slog.v(TAG, "    Task #" + task.taskId + " activities from bottom to top:");
+                Slog.v(TAG, "    Task #" + task.mTaskId + " activities from bottom to top:");
                 AppTokenList tokens = task.mAppTokens;
                 final int numTokens = tokens.size();
                 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
@@ -4920,90 +4889,20 @@
         }
     }
 
-    private int findAppWindowInsertionPointLocked(AppWindowToken target) {
-        final int taskId = target.groupId;
-        Task targetTask = mTaskIdToTask.get(taskId);
-        if (targetTask == null) {
-            Slog.w(TAG, "findAppWindowInsertionPointLocked: no Task for " + target + " taskId="
-                    + taskId);
-            return 0;
-        }
-        DisplayContent displayContent = targetTask.getDisplayContent();
-        if (displayContent == null) {
-            Slog.w(TAG, "findAppWindowInsertionPointLocked: no DisplayContent for " + target);
-            return 0;
-        }
-        final WindowList windows = displayContent.getWindowList();
-        final int NW = windows.size();
-
-        boolean found = false;
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = tasks.get(taskNdx);
-            if (!found && task.taskId != taskId) {
-                continue;
-            }
-            AppTokenList tokens = task.mAppTokens;
-            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                if (!found && wtoken == target) {
-                    found = true;
-                }
-                if (found) {
-                    // Find the first app token below the new position that has
-                    // a window displayed.
-                    if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows in " + wtoken.token);
-                    if (wtoken.sendingToBottom) {
-                        if (DEBUG_REORDER) Slog.v(TAG, "Skipping token -- currently sending to bottom");
-                        continue;
-                    }
-                    for (int i = wtoken.windows.size() - 1; i >= 0; --i) {
-                        WindowState win = wtoken.windows.get(i);
-                        for (int j = win.mChildWindows.size() - 1; j >= 0; --j) {
-                            WindowState cwin = win.mChildWindows.get(j);
-                            if (cwin.mSubLayer >= 0) {
-                                for (int pos = NW - 1; pos >= 0; pos--) {
-                                    if (windows.get(pos) == cwin) {
-                                        if (DEBUG_REORDER) Slog.v(TAG,
-                                                "Found child win @" + (pos + 1));
-                                        return pos + 1;
-                                    }
-                                }
-                            }
-                        }
-                        for (int pos = NW - 1; pos >= 0; pos--) {
-                            if (windows.get(pos) == win) {
-                                if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos + 1));
-                                return pos + 1;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        // Never put an app window underneath wallpaper.
-        for (int pos = NW - 1; pos >= 0; pos--) {
-            if (windows.get(pos).mIsWallpaper) {
-                if (DEBUG_REORDER) Slog.v(TAG, "Found wallpaper @" + pos);
-                return pos + 1;
-            }
-        }
-        return 0;
-    }
-
     private final int reAddWindowLocked(int index, WindowState win) {
         final WindowList windows = win.getWindowList();
+        // Adding child windows relies on mChildWindows being ordered by mSubLayer.
         final int NCW = win.mChildWindows.size();
-        boolean added = false;
+        boolean winAdded = false;
         for (int j=0; j<NCW; j++) {
             WindowState cwin = win.mChildWindows.get(j);
-            if (!added && cwin.mSubLayer >= 0) {
+            if (!winAdded && cwin.mSubLayer >= 0) {
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
                         + index + ": " + cwin);
                 win.mRebuilding = false;
                 windows.add(index, win);
                 index++;
-                added = true;
+                winAdded = true;
             }
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
                     + index + ": " + cwin);
@@ -5011,7 +4910,7 @@
             windows.add(index, cwin);
             index++;
         }
-        if (!added) {
+        if (!winAdded) {
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
                     + index + ": " + win);
             win.mRebuilding = false;
@@ -5036,41 +4935,40 @@
         return index;
     }
 
-    void tmpRemoveTaskWindowsLocked(Task task) {
-        AppTokenList tokens = task.mAppTokens;
-        for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-            tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
-        }
-    }
 
     void moveStackWindowsLocked(DisplayContent displayContent) {
-        // First remove all of the windows from the list.
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            tmpRemoveTaskWindowsLocked(tasks.get(taskNdx));
-        }
+        final WindowList windows = displayContent.getWindowList();
+        mTmpWindows.addAll(windows);
 
-        // And now add them back at the correct place.
-        // Where to start adding?
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            if (numTokens == 0) {
-                continue;
-            }
-            int pos = findAppWindowInsertionPointLocked(tokens.get(0));
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                if (wtoken != null) {
-                    final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
-                    if (newPos != pos) {
-                        displayContent.layoutNeeded = true;
-                    }
-                    pos = newPos;
-                }
+        rebuildAppWindowListLocked(displayContent);
+
+        // Set displayContent.layoutNeeded if window order changed.
+        final int tmpSize = mTmpWindows.size();
+        final int winSize = windows.size();
+        int tmpNdx = 0, winNdx = 0;
+        while (tmpNdx < tmpSize && winNdx < winSize) {
+            // Skip over all exiting windows, they've been moved out of order.
+            WindowState tmp;
+            do {
+                tmp = mTmpWindows.get(tmpNdx++);
+            } while (tmpNdx < tmpSize && tmp.mAppToken != null && tmp.mAppToken.mIsExiting);
+
+            WindowState win;
+            do {
+                win = windows.get(winNdx++);
+            } while (winNdx < winSize && win.mAppToken != null && win.mAppToken.mIsExiting);
+
+            if (tmp != win) {
+                // Window order changed.
+                displayContent.layoutNeeded = true;
+                break;
             }
         }
+        if (tmpNdx != winNdx) {
+            // One list was different from the other.
+            displayContent.layoutNeeded = true;
+        }
+        mTmpWindows.clear();
 
         if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                 false /*updateInputWindows*/)) {
@@ -5193,30 +5091,6 @@
         mStackIdToStack.remove(stackId);
     }
 
-    void removeTaskLocked(Task task) {
-        final int taskId = task.taskId;
-        final TaskStack stack = task.mStack;
-        if (!task.mAppTokens.isEmpty() && stack.isAnimating()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
-            task.mDeferRemoval = true;
-            return;
-        }
-        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
-        task.mDeferRemoval = false;
-        stack.removeTask(task);
-        mTaskIdToTask.delete(task.taskId);
-
-        final ArrayList<AppWindowToken> exitingApps = stack.mExitingAppTokens;
-        for (int appNdx = exitingApps.size() - 1; appNdx >= 0; --appNdx) {
-            final AppWindowToken wtoken = exitingApps.get(appNdx);
-            if (wtoken.groupId == taskId) {
-                wtoken.mDeferRemoval = false;
-                exitingApps.remove(appNdx);
-            }
-        }
-    }
-
     public void removeTask(int taskId) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -5224,7 +5098,7 @@
                 if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
                 return;
             }
-            removeTaskLocked(task);
+            task.removeLocked();
         }
     }
 
@@ -5234,6 +5108,7 @@
                     + " to " + (toTop ? "top" : "bottom"));
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "addTask: could not find taskId=" + taskId);
                 return;
             }
             TaskStack stack = mStackIdToStack.get(stackId);
@@ -5244,7 +5119,33 @@
         }
     }
 
-    public void resizeStack(int stackId, Rect bounds) {
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: moving taskId=" + taskId
+                    + " to stackId=" + stackId + " at " + (toTop ? "top" : "bottom"));
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: could not find taskId=" + taskId);
+                return;
+            }
+            TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: could not find stackId=" + stackId);
+                return;
+            }
+            task.moveTaskToStack(stack, toTop);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.layoutNeeded = true;
+            performLayoutAndPlaceSurfacesLocked();
+        }
+    }
+
+    /**
+     * Re-sizes the specified stack and its containing windows.
+     * Returns a {@link Configuration} object that contains configurations settings
+     * that should be overridden due to the operation.
+     */
+    public Configuration resizeStack(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
@@ -5256,6 +5157,7 @@
                 stack.getDisplayContent().layoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
             }
+            return new Configuration(stack.mOverrideConfig);
         }
     }
 
@@ -5268,6 +5170,44 @@
         bounds.setEmpty();
     }
 
+    /** Returns the id of an application (non-home stack) stack that match the input bounds.
+     * -1 if no stack matches.*/
+    public int getStackIdWithBounds(Rect bounds) {
+        Rect stackBounds = new Rect();
+        synchronized (mWindowMap) {
+            for (int i = mStackIdToStack.size() - 1; i >= 0; --i) {
+                TaskStack stack = mStackIdToStack.valueAt(i);
+                if (stack.mStackId != HOME_STACK_ID) {
+                    stack.getBounds(stackBounds);
+                    if (stackBounds.equals(bounds)) {
+                        return stack.mStackId;
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
+    /** Forces the stack to fullscreen if input is true, else un-forces the stack from fullscreen.
+     * Returns a {@link Configuration} object that contains configurations settings
+     * that should be overridden due to the operation.
+     */
+    public Configuration forceStackToFullscreen(int stackId, boolean forceFullscreen) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("resizeStack: stackId " + stackId
+                        + " not found.");
+            }
+            if (stack.forceFullscreen(forceFullscreen)) {
+                stack.resizeWindows();
+                stack.getDisplayContent().layoutNeeded = true;
+                performLayoutAndPlaceSurfacesLocked();
+            }
+            return new Configuration(stack.mOverrideConfig);
+        }
+    }
+
     // -------------------------------------------------------------
     // Misc IWindowSession methods
     // -------------------------------------------------------------
@@ -5628,7 +5568,7 @@
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                displayContent.switchUserStacks(newUserId);
+                displayContent.switchUserStacks();
                 rebuildAppWindowListLocked(displayContent);
             }
             performLayoutAndPlaceSurfacesLocked();
@@ -5926,13 +5866,15 @@
                     if (mCircularDisplayMask == null) {
                         int screenOffset = mContext.getResources().getDimensionPixelSize(
                                 com.android.internal.R.dimen.circular_display_mask_offset);
+                        int maskThickness = mContext.getResources().getDimensionPixelSize(
+                                com.android.internal.R.dimen.circular_display_mask_thickness);
 
                         mCircularDisplayMask = new CircularDisplayMask(
                                 getDefaultDisplayContentLocked().getDisplay(),
                                 mFxSession,
                                 mPolicy.windowTypeToLayerLw(
                                         WindowManager.LayoutParams.TYPE_POINTER)
-                                        * TYPE_LAYER_MULTIPLIER + 10, screenOffset);
+                                        * TYPE_LAYER_MULTIPLIER + 10, screenOffset, maskThickness);
                     }
                     mCircularDisplayMask.setVisibility(true);
                 } else if (mCircularDisplayMask != null) {
@@ -6187,9 +6129,13 @@
                     }
 
                     if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
-                            ws.isDisplayedLw()) {
+                            ws.isDisplayedLw() && winAnim.mSurfaceShown) {
                         screenshotReady = true;
                     }
+
+                    if (ws.isFullscreen(dw, dh) && ws.isOpaqueDrawn()){
+                        break;
+                    }
                 }
 
                 if (appToken != null && appWin == null) {
@@ -6485,7 +6431,7 @@
         mAltOrientation = altOrientation;
         mPolicy.setRotationLw(mRotation);
 
-        mWindowsFreezingScreen = true;
+        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
@@ -6502,13 +6448,12 @@
         screenRotationAnimation =
                 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
 
-        // We need to update our screen size information to match the new
-        // rotation.  Note that this is redundant with the later call to
-        // sendNewConfiguration() that must be called after this function
-        // returns...  however we need to do the screen size part of that
-        // before then so we have the correct size to use when initializing
-        // the rotation animation for the new rotation.
-        computeScreenConfigurationLocked(null);
+        // We need to update our screen size information to match the new rotation. If the rotation
+        // has actually changed then this method will return true and, according to the comment at
+        // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
+        // By updating the Display info here it will be available to
+        // computeScreenConfigurationLocked later.
+        updateDisplayAndOrientationLocked();
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!inTransaction) {
@@ -7057,9 +7002,11 @@
 
     public Configuration computeNewConfiguration() {
         synchronized (mWindowMap) {
+            if (!mDisplayReady) {
+                return null;
+            }
             Configuration config = computeNewConfigurationLocked();
-            if (config == null && mWaitingForConfig) {
-                // Nothing changed but we are waiting for something... stop that!
+            if (mWaitingForConfig) {
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
                 performLayoutAndPlaceSurfacesLocked();
@@ -7071,9 +7018,7 @@
     Configuration computeNewConfigurationLocked() {
         Configuration config = new Configuration();
         config.fontScale = 0;
-        if (!computeScreenConfigurationLocked(config)) {
-            return null;
-        }
+        computeScreenConfigurationLocked(config);
         return config;
     }
 
@@ -7180,11 +7125,8 @@
         return sw;
     }
 
-    boolean computeScreenConfigurationLocked(Configuration config) {
-        if (!mDisplayReady) {
-            return false;
-        }
-
+    /** Do not call if mDisplayReady == false */
+    DisplayInfo updateDisplayAndOrientationLocked() {
         // TODO(multidisplay): For now, apply Configuration to main screen only.
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
 
@@ -7214,11 +7156,6 @@
             }
         }
 
-        if (config != null) {
-            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
-                    Configuration.ORIENTATION_LANDSCAPE;
-        }
-
         // Update application display metrics.
         final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
         final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
@@ -7235,94 +7172,104 @@
             displayInfo.getAppMetrics(mDisplayMetrics);
             mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                     displayContent.getDisplayId(), displayInfo);
+            displayContent.mBaseDisplayRect.set(0, 0, dw, dh);
         }
         if (false) {
             Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
         }
 
-        final DisplayMetrics dm = mDisplayMetrics;
-        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
+        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
                 mCompatDisplayMetrics);
+        return displayInfo;
+    }
 
-        if (config != null) {
-            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
-                    / dm.density);
-            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
-                    / dm.density);
-            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
+    /** Do not call if mDisplayReady == false */
+    void computeScreenConfigurationLocked(Configuration config) {
+        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();
 
-            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
-            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
-            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
-            config.densityDpi = displayContent.mBaseDisplayDensity;
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
+        config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
+                Configuration.ORIENTATION_LANDSCAPE;
+        config.screenWidthDp =
+                (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) / mDisplayMetrics.density);
+        config.screenHeightDp =
+                (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) / mDisplayMetrics.density);
+        final boolean rotated = (mRotation == Surface.ROTATION_90
+                || mRotation == Surface.ROTATION_270);
+        computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, mDisplayMetrics.density,
+                config);
 
-            // Update the configuration based on available input devices, lid switch,
-            // and platform configuration.
-            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-            config.keyboard = Configuration.KEYBOARD_NOKEYS;
-            config.navigation = Configuration.NAVIGATION_NONAV;
+        config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
+        config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
+        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated,
+                mDisplayMetrics, dw, dh);
+        config.densityDpi = displayInfo.logicalDensityDpi;
 
-            int keyboardPresence = 0;
-            int navigationPresence = 0;
-            final InputDevice[] devices = mInputManager.getInputDevices();
-            final int len = devices.length;
-            for (int i = 0; i < len; i++) {
-                InputDevice device = devices[i];
-                if (!device.isVirtual()) {
-                    final int sources = device.getSources();
-                    final int presenceFlag = device.isExternal() ?
-                            WindowManagerPolicy.PRESENCE_EXTERNAL :
-                                    WindowManagerPolicy.PRESENCE_INTERNAL;
+        // Update the configuration based on available input devices, lid switch,
+        // and platform configuration.
+        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+        config.keyboard = Configuration.KEYBOARD_NOKEYS;
+        config.navigation = Configuration.NAVIGATION_NONAV;
 
-                    if (mIsTouchDevice) {
-                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
-                                InputDevice.SOURCE_TOUCHSCREEN) {
-                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
-                        }
-                    } else {
-                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+        int keyboardPresence = 0;
+        int navigationPresence = 0;
+        final InputDevice[] devices = mInputManager.getInputDevices();
+        final int len = devices.length;
+        for (int i = 0; i < len; i++) {
+            InputDevice device = devices[i];
+            if (!device.isVirtual()) {
+                final int sources = device.getSources();
+                final int presenceFlag = device.isExternal() ?
+                        WindowManagerPolicy.PRESENCE_EXTERNAL :
+                                WindowManagerPolicy.PRESENCE_INTERNAL;
+
+                if (mIsTouchDevice) {
+                    if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
+                            InputDevice.SOURCE_TOUCHSCREEN) {
+                        config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
                     }
+                } else {
+                    config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+                }
 
-                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
-                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
-                        navigationPresence |= presenceFlag;
-                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
-                            && config.navigation == Configuration.NAVIGATION_NONAV) {
-                        config.navigation = Configuration.NAVIGATION_DPAD;
-                        navigationPresence |= presenceFlag;
-                    }
+                if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
+                    config.navigation = Configuration.NAVIGATION_TRACKBALL;
+                    navigationPresence |= presenceFlag;
+                } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
+                        && config.navigation == Configuration.NAVIGATION_NONAV) {
+                    config.navigation = Configuration.NAVIGATION_DPAD;
+                    navigationPresence |= presenceFlag;
+                }
 
-                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
-                        config.keyboard = Configuration.KEYBOARD_QWERTY;
-                        keyboardPresence |= presenceFlag;
-                    }
+                if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
+                    config.keyboard = Configuration.KEYBOARD_QWERTY;
+                    keyboardPresence |= presenceFlag;
                 }
             }
-
-            if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {
-                config.navigation = Configuration.NAVIGATION_DPAD;
-                navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
-            }
-
-            // Determine whether a hard keyboard is available and enabled.
-            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
-            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
-                mHardKeyboardAvailable = hardKeyboardAvailable;
-                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
-                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
-            }
-            if (mShowImeWithHardKeyboard) {
-                config.keyboard = Configuration.KEYBOARD_NOKEYS;
-            }
-
-            // Let the policy update hidden states.
-            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
-            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
-            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
-            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
         }
 
-        return true;
+        if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) {
+            config.navigation = Configuration.NAVIGATION_DPAD;
+            navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
+        }
+
+        // Determine whether a hard keyboard is available and enabled.
+        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
+        if (hardKeyboardAvailable != mHardKeyboardAvailable) {
+            mHardKeyboardAvailable = hardKeyboardAvailable;
+            mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+            mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+        }
+        if (mShowImeWithHardKeyboard) {
+            config.keyboard = Configuration.KEYBOARD_NOKEYS;
+        }
+
+        // Let the policy update hidden states.
+        config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+        config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
+        config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
+        mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
     }
 
     public boolean isHardKeyboardAvailable() {
@@ -7618,6 +7565,7 @@
 
         public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
         public static final int RESET_ANR_MESSAGE = 38;
+        public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39;
 
         @Override
         public void handleMessage(Message msg) {
@@ -7853,6 +7801,7 @@
                     // TODO(multidisplay): Can non-default displays rotate?
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "Window freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final WindowList windows = getDefaultWindowListLocked();
                         int i = windows.size();
                         while (i > 0) {
@@ -7872,8 +7821,12 @@
 
                 case APP_TRANSITION_TIMEOUT: {
                     synchronized (mWindowMap) {
-                        if (mAppTransition.isTransitionSet()) {
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
+                        if (mAppTransition.isTransitionSet() || !mOpeningApps.isEmpty()
+                                    || !mClosingApps.isEmpty()) {
+                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT."
+                                    + " isTransitionSet()=" + mAppTransition.isTransitionSet()
+                                    + " mOpeningApps.size()=" + mOpeningApps.size()
+                                    + " mClosingApps.size()=" + mClosingApps.size());
                             mAppTransition.setTimeout();
                             performLayoutAndPlaceSurfacesLocked();
                         }
@@ -7920,6 +7873,7 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
+                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
                         final int numStacks = mStackIdToStack.size();
                         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
@@ -8062,16 +8016,16 @@
                     break;
 
                 case TAP_OUTSIDE_STACK: {
-//                    int stackId;
-//                    synchronized (mWindowMap) {
-//                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
-//                    }
-//                    if (stackId >= 0) {
-//                        try {
-//                            mActivityManager.setFocusedStack(stackId);
-//                        } catch (RemoteException e) {
-//                        }
-//                    }
+                    int stackId;
+                    synchronized (mWindowMap) {
+                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
+                    }
+                    if (stackId >= 0) {
+                        try {
+                            mActivityManager.setFocusedStack(stackId);
+                        } catch (RemoteException e) {
+                        }
+                    }
                 }
                 break;
                 case NOTIFY_ACTIVITY_DRAWN:
@@ -8134,6 +8088,17 @@
                     }
                 }
                 break;
+                case WALLPAPER_DRAW_PENDING_TIMEOUT: {
+                    synchronized (mWindowMap) {
+                        if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
+                            mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
+                            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+                                    "*** WALLPAPER DRAW TIMEOUT");
+                            performLayoutAndPlaceSurfacesLocked();
+                        }
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
@@ -8451,17 +8416,17 @@
     // displayContent must not be null
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
+        if (!mDisplayReady) {
+            return;
+        }
         configureDisplayPolicyLocked(displayContent);
         displayContent.layoutNeeded = true;
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
         mTempConfiguration.fontScale = mCurConfiguration.fontScale;
-        if (computeScreenConfigurationLocked(mTempConfiguration)) {
-            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
-                configChanged = true;
-            }
-        }
+        computeScreenConfigurationLocked(mTempConfiguration);
+        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
 
         if (configChanged) {
             mWaitingForConfig = true;
@@ -8587,7 +8552,7 @@
                 numRemoved++;
                 continue;
             } else if (lastBelow == i-1) {
-                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
+                if (w.mAttrs.type == TYPE_WALLPAPER) {
                     lastBelow = i;
                 }
             }
@@ -8622,7 +8587,7 @@
                 final int numTokens = tokens.size();
                 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (wtoken.mDeferRemoval) {
+                    if (wtoken.mIsExiting) {
                         continue;
                     }
                     i = reAddAppWindowsLocked(displayContent, i, wtoken);
@@ -8632,6 +8597,7 @@
 
         i -= lastBelow;
         if (i != numRemoved) {
+            displayContent.layoutNeeded = true;
             Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
                     numRemoved + " windows but added " + i,
                     new RuntimeException("here").fillInStackTrace());
@@ -8652,6 +8618,7 @@
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
+        Arrays.fill(mRebuildTmp, null);
     }
 
     private final void assignLayersLocked(WindowList windows) {
@@ -8760,29 +8727,24 @@
 
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
         mInLayout = true;
-        boolean recoveringMemory = false;
 
-        try {
-            if (mForceRemoves != null) {
-                recoveringMemory = true;
-                // Wait a little bit for things to settle down, and off we go.
-                for (int i=0; i<mForceRemoves.size(); i++) {
-                    WindowState ws = mForceRemoves.get(i);
-                    Slog.i(TAG, "Force removing: " + ws);
-                    removeWindowInnerLocked(ws.mSession, ws);
-                }
-                mForceRemoves = null;
-                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
-                Object tmp = new Object();
-                synchronized (tmp) {
-                    try {
-                        tmp.wait(250);
-                    } catch (InterruptedException e) {
-                    }
+        boolean recoveringMemory = false;
+        if (!mForceRemoves.isEmpty()) {
+            recoveringMemory = true;
+            // Wait a little bit for things to settle down, and off we go.
+            while (!mForceRemoves.isEmpty()) {
+                WindowState ws = mForceRemoves.remove(0);
+                Slog.i(TAG, "Force removing: " + ws);
+                removeWindowInnerLocked(ws);
+            }
+            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
+            Object tmp = new Object();
+            synchronized (tmp) {
+                try {
+                    tmp.wait(250);
+                } catch (InterruptedException e) {
                 }
             }
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception while force removing for memory", e);
         }
 
         try {
@@ -8840,8 +8802,6 @@
                     + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
         }
 
-        WindowStateAnimator universeBackground = null;
-
         mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
         if (isDefaultDisplay) {
             // Not needed on non-default displays.
@@ -8898,8 +8858,8 @@
             if (!gone || !win.mHaveFrame || win.mLayoutNeeded
                     || ((win.isConfigChanged() || win.setInsetsChanged()) &&
                             ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                            win.mAppToken != null && win.mAppToken.layoutConfigChanges))
-                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
+                            (win.mHasSurface && win.mAppToken != null &&
+                            win.mAppToken.layoutConfigChanges)))) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
@@ -8923,16 +8883,6 @@
                     if (topAttached < 0) topAttached = i;
                 }
             }
-            if (win.mViewVisibility == View.VISIBLE
-                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
-                    && universeBackground == null) {
-                universeBackground = win.mWinAnimator;
-            }
-        }
-
-        if (mAnimator.mUniverseBackground  != universeBackground) {
-            mFocusMayChange = true;
-            mAnimator.mUniverseBackground = universeBackground;
         }
 
         boolean attachedBehindDream = false;
@@ -8998,8 +8948,8 @@
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;
-            if (!mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = true;
+            if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
                 // when we first froze the display.
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
@@ -9023,10 +8973,7 @@
                 "Checking " + NN + " opening apps (frozen="
                 + mDisplayFrozen + " timeout="
                 + mAppTransition.isTimeout() + ")...");
-        if (!mDisplayFrozen && !mAppTransition.isTimeout()) {
-            // If the display isn't frozen, wait to do anything until
-            // all of the apps are ready.  Otherwise just go because
-            // we'll unfreeze the display when everyone is ready.
+        if (!mAppTransition.isTimeout()) {
             for (i=0; i<NN && goodToGo; i++) {
                 AppWindowToken wtoken = mOpeningApps.valueAt(i);
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -9039,6 +8986,39 @@
                     goodToGo = false;
                 }
             }
+            if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
+                boolean wallpaperGoodToGo = true;
+                for (int curTokenIndex = mWallpaperTokens.size() - 1;
+                        curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
+                    WindowToken token = mWallpaperTokens.get(curTokenIndex);
+                    for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
+                            curWallpaperIndex--) {
+                        WindowState wallpaper = token.windows.get(curWallpaperIndex);
+                        if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
+                            // We've told this wallpaper to be visible, but it is not drawn yet
+                            wallpaperGoodToGo = false;
+                            if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
+                                // wait for this wallpaper until it is drawn or timeout
+                                goodToGo = false;
+                            }
+                            if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
+                                mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
+                                mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+                                mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
+                                        WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+                            }
+                            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+                                    "Wallpaper should be visible but has not been drawn yet. " +
+                                    "mWallpaperDrawState=" + mWallpaperDrawState);
+                            break;
+                        }
+                    }
+                }
+                if (wallpaperGoodToGo) {
+                    mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+                    mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+                }
+            }
         }
         if (goodToGo) {
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
@@ -9046,7 +9026,6 @@
             if (mSkipAppTransitionAnimation) {
                 transit = AppTransition.TRANSIT_UNSET;
             }
-            mAppTransition.goodToGo();
             mStartingIconInTransition = false;
             mSkipAppTransitionAnimation = false;
 
@@ -9199,6 +9178,7 @@
                     for (int j = 0; j < N; j++) {
                         appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
                     }
+                    mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
                     mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
                 }
             }
@@ -9221,6 +9201,7 @@
                     appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
                 }
                 mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
                 if (animLp != null) {
                     int layer = -1;
@@ -9257,6 +9238,7 @@
                 if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
                     scheduleRemoveStartingWindowLocked(wtoken);
                 }
+                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
                 if (animLp != null) {
                     int layer = -1;
@@ -9341,6 +9323,7 @@
                 }
             }
 
+            mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
             mAppTransition.postAnimationCallback();
             mAppTransition.clear();
 
@@ -9470,14 +9453,12 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @param w WindowState this method is applied to.
-     * @param currentTime The time which animations use for calculating transitions.
+     *  @param w WindowState this method is applied to.
      * @param innerDw Width of app window.
      * @param innerDh Height of app window.
      */
-    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
-                                         final int innerDw, final int innerDh) {
+    private void handleNotObscuredLocked(final WindowState w,
+            final int innerDw, final int innerDh) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
@@ -9596,8 +9577,6 @@
                     + Debug.getCallers(3));
         }
 
-        final long currentTime = SystemClock.uptimeMillis();
-
         int i;
         boolean updateInputWindowsNeeded = false;
 
@@ -9688,8 +9667,7 @@
 
                     if ((displayContent.pendingLayoutChanges &
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                            (adjustWallpaperWindowsLocked() &
-                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                            adjustWallpaperWindowsLocked()) {
                         assignLayersLocked(windows);
                         displayContent.layoutNeeded = true;
                     }
@@ -9720,15 +9698,12 @@
                     // it is animating.
                     displayContent.pendingLayoutChanges = 0;
 
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
-                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
-
                     if (isDefaultDisplay) {
                         mPolicy.beginPostLayoutPolicyLw(dw, dh);
                         for (i = windows.size() - 1; i >= 0; i--) {
                             WindowState w = windows.get(i);
                             if (w.mHasSurface) {
-                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.mAttachedWindow);
+                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
                             }
                         }
                         displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
@@ -9757,7 +9732,7 @@
                     // Update effect.
                     w.mObscured = mInnerFields.mObscured;
                     if (!mInnerFields.mObscured) {
-                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
+                        handleNotObscuredLocked(w, innerDw, innerDh);
                     }
 
                     if (stack != null && !stack.testDimmingTag()) {
@@ -9806,7 +9781,7 @@
                     if (w.mHasSurface && !w.isHiddenFromUserLocked()) {
                         // Take care of the window being ready to display.
                         final boolean committed =
-                                winAnimator.commitFinishDrawingLocked(currentTime);
+                                winAnimator.commitFinishDrawingLocked();
                         if (isDefaultDisplay && committed) {
                             if (w.mAttrs.type == TYPE_DREAM) {
                                 // HACK: When a dream is shown, it may at that
@@ -9931,7 +9906,7 @@
                     defaultDisplay.pendingLayoutChanges);
         }
 
-        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
+        if (!mAnimator.mAppWindowAnimating && mAppTransition.isRunning()) {
             // We have finished the animation of an app transition.  To do
             // this, we have delayed a lot of operations like showing and
             // hiding apps, moving apps in Z-order, etc.  The app token list
@@ -9994,8 +9969,8 @@
                 "With display frozen, orientationChangeComplete="
                 + mInnerFields.mOrientationChangeComplete);
         if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen) {
-                mWindowsFreezingScreen = false;
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
                 mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
@@ -10044,7 +10019,7 @@
             for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
                 AppWindowToken token = exitingAppTokens.get(i);
                 if (!token.hasVisible && !mClosingApps.contains(token) &&
-                        (!token.mDeferRemoval || token.allAppWindows.isEmpty())) {
+                        (!token.mIsExiting || token.allAppWindows.isEmpty())) {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
@@ -10052,12 +10027,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    removeAppFromTaskLocked(token);
-                    exitingAppTokens.remove(i);
-                    final Task task = mTaskIdToTask.get(token.groupId);
-                    if (task != null && task.mDeferRemoval && task.mAppTokens.isEmpty()) {
-                        removeTaskLocked(task);
-                    }
+                    token.removeAppFromTaskLocked();
                 }
             }
         }
@@ -10110,7 +10080,9 @@
             if (mAllowTheaterModeWakeFromLayout
                     || Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
+                if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                    Slog.v(TAG, "Turning screen on after layout!");
+                }
                 mPowerManager.wakeUp(SystemClock.uptimeMillis());
             }
             mTurnOnScreen = false;
@@ -10141,7 +10113,7 @@
             DisplayContentList displayList = new DisplayContentList();
             for (i = 0; i < N; i++) {
                 WindowState w = mPendingRemoveTmp[i];
-                removeWindowInnerLocked(w.mSession, w);
+                removeWindowInnerLocked(w);
                 final DisplayContent displayContent = w.getDisplayContent();
                 if (displayContent != null && !displayList.contains(displayContent)) {
                     displayList.add(displayContent);
@@ -10244,8 +10216,7 @@
     void scheduleAnimationLocked() {
         if (!mAnimationScheduled) {
             mAnimationScheduled = true;
-            mChoreographer.postCallback(
-                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
+            mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
         }
     }
 
@@ -10281,7 +10252,7 @@
         } else {
             mInnerFields.mOrientationChangeComplete = true;
             mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
-            if (mWindowsFreezingScreen) {
+            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                 doRequest = true;
             }
         }
@@ -10318,10 +10289,6 @@
         EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
                 winAnimator.mSession.mPid, operation);
 
-        if (mForceRemoves == null) {
-            mForceRemoves = new ArrayList<WindowState>();
-        }
-
         long callingIdentity = Binder.clearCallingIdentity();
         try {
             // There was some problem...   first, do a sanity check of the
@@ -10481,11 +10448,6 @@
     }
 
     private WindowState computeFocusedWindowLocked() {
-        if (mAnimator.mUniverseBackground != null
-                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
-            return mAnimator.mUniverseBackground.mWin;
-        }
-
         final int displayCount = mDisplayContents.size();
         for (int i = 0; i < displayCount; i++) {
             final DisplayContent displayContent = mDisplayContents.valueAt(i);
@@ -10508,6 +10470,10 @@
                 + ", flags=" + win.mAttrs.flags
                 + ", canReceive=" + win.canReceiveKeys());
 
+            if (!win.canReceiveKeys()) {
+                continue;
+            }
+
             AppWindowToken wtoken = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
@@ -10517,10 +10483,6 @@
                 continue;
             }
 
-            if (!win.canReceiveKeys()) {
-                continue;
-            }
-
             // Descend through all of the app tokens and find the first that either matches
             // win.mAppToken (return win) or mFocusedApp (return null).
             if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
@@ -10626,13 +10588,15 @@
             return;
         }
 
-        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
-                || mClientFreezingScreen) {
+        if (mWaitingForConfig || mAppsFreezingScreen > 0
+                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
+                || mClientFreezingScreen || !mOpeningApps.isEmpty()) {
             if (DEBUG_ORIENTATION) Slog.d(TAG,
                 "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
                 + ", mAppsFreezingScreen=" + mAppsFreezingScreen
                 + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
-                + ", mClientFreezingScreen=" + mClientFreezingScreen);
+                + ", mClientFreezingScreen=" + mClientFreezingScreen
+                + ", mOpeningApps.size()=" + mOpeningApps.size());
             return;
         }
 
@@ -10674,15 +10638,13 @@
                 scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
-                screenRotationAnimation = null;
-                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
+                mAnimator.setScreenRotationAnimationLocked(displayId, null);
                 updateRotation = true;
             }
         } else {
             if (screenRotationAnimation != null) {
                 screenRotationAnimation.kill();
-                screenRotationAnimation = null;
-                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
+                mAnimator.setScreenRotationAnimationLocked(displayId, null);
             }
             updateRotation = true;
         }
@@ -10949,7 +10911,7 @@
 
     void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
         pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
-        if (mTokenMap.size() > 0) {
+        if (!mTokenMap.isEmpty()) {
             pw.println("  All tokens:");
             Iterator<WindowToken> it = mTokenMap.values().iterator();
             while (it.hasNext()) {
@@ -10963,7 +10925,7 @@
                 }
             }
         }
-        if (mWallpaperTokens.size() > 0) {
+        if (!mWallpaperTokens.isEmpty()) {
             pw.println();
             pw.println("  Wallpaper tokens:");
             for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
@@ -10978,7 +10940,7 @@
                 }
             }
         }
-        if (mFinishedStarting.size() > 0) {
+        if (!mFinishedStarting.isEmpty()) {
             pw.println();
             pw.println("  Finishing start of application tokens:");
             for (int i=mFinishedStarting.size()-1; i>=0; i--) {
@@ -10993,7 +10955,7 @@
                 }
             }
         }
-        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
+        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
             pw.println();
             if (mOpeningApps.size() > 0) {
                 pw.print("  mOpeningApps="); pw.println(mOpeningApps);
@@ -11228,7 +11190,7 @@
             pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
                     pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
             pw.println("  mLayoutToAnim:");
-            mAppTransition.dump(pw);
+            mAppTransition.dump(pw, "    ");
         }
     }
 
@@ -11784,5 +11746,12 @@
                 WindowManagerService.this.removeWindowToken(token);
             }
         }
+
+        @Override
+        public void registerAppTransitionListener(AppTransitionListener listener) {
+            synchronized (mWindowMap) {
+                mAppTransition.registerListenerLocked(listener);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 021a6e4..f94ed77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,30 +16,33 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-
 import android.app.AppOpsManager;
 import android.os.Debug;
+import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.util.TimeUtils;
 import android.view.Display;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
+
 import com.android.server.input.InputWindowHandle;
 
 import android.content.Context;
@@ -130,7 +133,8 @@
 
     int mLayoutSeq = -1;
 
-    Configuration mConfiguration = null;
+    private Configuration mConfiguration = Configuration.EMPTY;
+    private Configuration mOverrideConfig = Configuration.EMPTY;
     // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
     // Used only on {@link #TYPE_KEYGUARD}.
     private boolean mConfigHasChanged;
@@ -231,7 +235,8 @@
 
     final Rect mParentFrame = new Rect();
 
-    // The entire screen area of the device.
+    // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
+    // screen area of the device.
     final Rect mDisplayFrame = new Rect();
 
     // The region of the display frame that the display type supports displaying content on. This
@@ -341,9 +346,14 @@
     /** When true this window can be displayed on screens owther than mOwnerUid's */
     private boolean mShowToOwnerOnly;
 
-    /** When true this window is at the top of the screen and should be layed out to extend under
-     * the status bar */
-    boolean mUnderStatusBar = true;
+    /**
+     * Wake lock for drawing.
+     * Even though it's slightly more expensive to do so, we will use a separate wake lock
+     * for each app that is requesting to draw while dozing so that we can accurately track
+     * who is preventing the system from suspending.
+     * This lock is only acquired on first use.
+     */
+    PowerManager.WakeLock mDrawLock;
 
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
@@ -407,28 +417,26 @@
             mAttachedWindow = attachedWindow;
             if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow);
 
-            int children_size = mAttachedWindow.mChildWindows.size();
-            if (children_size == 0) {
-                mAttachedWindow.mChildWindows.add(this);
+            final WindowList childWindows = mAttachedWindow.mChildWindows;
+            final int numChildWindows = childWindows.size();
+            if (numChildWindows == 0) {
+                childWindows.add(this);
             } else {
-                for (int i = 0; i < children_size; i++) {
-                    WindowState child = (WindowState)mAttachedWindow.mChildWindows.get(i);
-                    if (this.mSubLayer < child.mSubLayer) {
-                        mAttachedWindow.mChildWindows.add(i, this);
+                boolean added = false;
+                for (int i = 0; i < numChildWindows; i++) {
+                    final int childSubLayer = childWindows.get(i).mSubLayer;
+                    if (mSubLayer < childSubLayer
+                            || (mSubLayer == childSubLayer && childSubLayer < 0)) {
+                        // We insert the child window into the list ordered by the sub-layer. For
+                        // same sub-layers, the negative one should go below others; the positive
+                        // one should go above others.
+                        childWindows.add(i, this);
+                        added = true;
                         break;
-                    } else if (this.mSubLayer > child.mSubLayer) {
-                        continue;
-                    }
-
-                    if (this.mBaseLayer <= child.mBaseLayer) {
-                        mAttachedWindow.mChildWindows.add(i, this);
-                        break;
-                    } else {
-                        continue;
                     }
                 }
-                if (children_size == mAttachedWindow.mChildWindows.size()) {
-                    mAttachedWindow.mChildWindows.add(this);
+                if (!added) {
+                    childWindows.add(this);
                 }
             }
 
@@ -510,16 +518,22 @@
 
         TaskStack stack = mAppToken != null ? getStack() : null;
         if (stack != null && !stack.isFullscreen()) {
-            getStackBounds(stack, mContainingFrame);
-            if (mUnderStatusBar) {
-                mContainingFrame.top = pf.top;
+            stack.getBounds(mContainingFrame);
+            final WindowState imeWin = mService.mInputMethodWindow;
+            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
+                    && mContainingFrame.bottom > cf.bottom) {
+                // IME is up and obscuring this window. Adjust the window position so it is visible.
+                mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
             }
+            // Make sure the containing frame is within the content frame so we don't layout
+            // resized window under screen decorations.
+            mContainingFrame.intersect(cf);
+            mDisplayFrame.set(mContainingFrame);
         } else {
             mContainingFrame.set(pf);
+            mDisplayFrame.set(df);
         }
 
-        mDisplayFrame.set(df);
-
         final int pw = mContainingFrame.width();
         final int ph = mContainingFrame.height();
 
@@ -577,9 +591,6 @@
         final int fw = mFrame.width();
         final int fh = mFrame.height();
 
-        //System.out.println("In: w=" + w + " h=" + h + " container=" +
-        //                   container + " x=" + mAttrs.x + " y=" + mAttrs.y);
-
         float x, y;
         if (mEnforceSizeCompat) {
             x = mAttrs.x * mGlobalScale;
@@ -589,14 +600,15 @@
             y = mAttrs.y;
         }
 
+        // Make sure window fits in containing frame required by {@link Gravity#apply} call.
+        w = Math.min(w, pw);
+        h = Math.min(h, ph);
         Gravity.apply(mAttrs.gravity, w, h, mContainingFrame,
                 (int) (x + mAttrs.horizontalMargin * pw),
                 (int) (y + mAttrs.verticalMargin * ph), mFrame);
 
-        //System.out.println("Out: " + mFrame);
-
-        // Now make sure the window fits in the overall display.
-        Gravity.applyDisplay(mAttrs.gravity, df, mFrame);
+        // Now make sure the window fits in the overall display frame.
+        Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
@@ -794,14 +806,14 @@
     TaskStack getStack() {
         AppWindowToken wtoken = mAppToken == null ? mService.mFocusedApp : mAppToken;
         if (wtoken != null) {
-            Task task = mService.mTaskIdToTask.get(wtoken.groupId);
+            Task task = wtoken.mTask;
             if (task != null) {
                 if (task.mStack != null) {
                     return task.mStack;
                 }
                 Slog.e(TAG, "getStack: mStack null for task=" + task);
             } else {
-                Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId
+                Slog.e(TAG, "getStack: " + this + " couldn't find task for " + wtoken
                     + " Callers=" + Debug.getCallers(4));
             }
         }
@@ -809,10 +821,7 @@
     }
 
     void getStackBounds(Rect bounds) {
-        getStackBounds(getStack(), bounds);
-    }
-
-    private void getStackBounds(TaskStack stack, Rect bounds) {
+        final TaskStack stack = getStack();
         if (stack != null) {
             stack.getBounds(bounds);
             return;
@@ -1078,9 +1087,13 @@
     }
 
     boolean isConfigChanged() {
-        boolean configChanged = mConfiguration != mService.mCurConfiguration
-                && (mConfiguration == null
-                        || (mConfiguration.diff(mService.mCurConfiguration) != 0));
+        final TaskStack stack = getStack();
+        final Configuration overrideConfig =
+                (stack != null) ? stack.mOverrideConfig : Configuration.EMPTY;
+        final Configuration serviceConfig = mService.mCurConfiguration;
+        boolean configChanged =
+                (mConfiguration != serviceConfig && mConfiguration.diff(serviceConfig) != 0)
+                || (mOverrideConfig != overrideConfig && !mOverrideConfig.equals(overrideConfig));
 
         if ((mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
             // Retain configuration changed status until resetConfiguration called.
@@ -1109,8 +1122,10 @@
         }
     }
 
-    void setConfiguration(final Configuration newConfig) {
+    private void setConfiguration(
+            final Configuration newConfig, final Configuration newOverrideConfig) {
         mConfiguration = newConfig;
+        mOverrideConfig = newOverrideConfig;
         mConfigHasChanged = false;
     }
 
@@ -1272,6 +1287,33 @@
         }
     }
 
+    public void pokeDrawLockLw(long timeout) {
+        if (isVisibleOrAdding()) {
+            if (mDrawLock == null) {
+                // We want the tag name to be somewhat stable so that it is easier to correlate
+                // in wake lock statistics.  So in particular, we don't want to include the
+                // window's hash code as in toString().
+                CharSequence tag = mAttrs.getTitle();
+                if (tag == null) {
+                    tag = mAttrs.packageName;
+                }
+                mDrawLock = mService.mPowerManager.newWakeLock(
+                        PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
+                mDrawLock.setReferenceCounted(false);
+                mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
+            }
+            // Each call to acquire resets the timeout.
+            if (DEBUG_POWER) {
+                Slog.d(TAG, "pokeDrawLock: poking draw lock on behalf of visible window owned by "
+                        + mAttrs.packageName);
+            }
+            mDrawLock.acquire(timeout);
+        } else if (DEBUG_POWER) {
+            Slog.d(TAG, "pokeDrawLock: suppressed draw lock request for invisible window "
+                    + "owned by " + mAttrs.packageName);
+        }
+    }
+
     @Override
     public boolean isAlive() {
         return mClient.asBinder().isBinderAlive();
@@ -1291,6 +1333,15 @@
         return displayContent.isDefaultDisplay;
     }
 
+    @Override
+    public boolean isDimming() {
+        TaskStack stack = getStack();
+        if (stack == null) {
+            return false;
+        }
+        return stack.isDimming(mWinAnimator);
+    }
+
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
         mShowToOwnerOnly = showToOwnerOnly;
     }
@@ -1386,12 +1437,15 @@
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
             boolean configChanged = isConfigChanged();
+            final TaskStack stack = getStack();
+            final Configuration overrideConfig =
+                    (stack != null) ? stack.mOverrideConfig : Configuration.EMPTY;
             if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
                 Slog.i(TAG, "Sending new config to window " + this + ": "
-                        + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH
-                        + " / " + mService.mCurConfiguration);
+                        + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH + " / config="
+                        + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
             }
-            setConfiguration(mService.mCurConfiguration);
+            setConfiguration(mService.mCurConfiguration, overrideConfig);
             if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
                 Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
 
@@ -1463,7 +1517,11 @@
     }
 
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        final TaskStack stack = getStack();
         pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
+                if (stack != null) {
+                    pw.print(" stackId="); pw.print(stack.mStackId);
+                }
                 pw.print(" mSession="); pw.print(mSession);
                 pw.print(" mClient="); pw.println(mClient.asBinder());
         pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
@@ -1547,6 +1605,9 @@
                 pw.print(prefix); pw.print("touchable region="); pw.println(region);
             }
             pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
+            if (mOverrideConfig != Configuration.EMPTY) {
+                pw.print(prefix); pw.print("mOverrideConfig="); pw.println(mOverrideConfig);
+            }
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownFrame="); mShownFrame.printShortString(pw);
@@ -1626,6 +1687,9 @@
                     pw.print(" mWallpaperDisplayOffsetY=");
                     pw.println(mWallpaperDisplayOffsetY);
         }
+        if (mDrawLock != null) {
+            pw.println("mDrawLock=" + mDrawLock);
+        }
     }
 
     String makeInputChannelName() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c2d8004..ac1b0f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -53,21 +53,16 @@
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
-import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
-import com.android.internal.R;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-class WinAnimatorList extends ArrayList<WindowStateAnimator> {
-}
-
 /**
  * Keep track of animations and surface operations for a single WindowState.
  **/
@@ -85,10 +80,6 @@
     final Context mContext;
     final boolean mIsWallpaper;
 
-    // If this is a universe background window, this is the transformation
-    // it is applying to the rest of the universe.
-    final Transformation mUniverseTransform = new Transformation();
-
     // Currently running animation.
     boolean mAnimating;
     boolean mLocalAnimating;
@@ -189,7 +180,7 @@
 
     int mAttrType;
 
-    public WindowStateAnimator(final WindowState win) {
+    WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
         mService = service;
@@ -247,9 +238,7 @@
     boolean isAnimating() {
         return mAnimation != null
                 || (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)
-                || (mAppAnimator != null &&
-                        (mAppAnimator.animation != null
-                                || mAppAnimator.mAppToken.inPendingTransaction));
+                || (mAppAnimator != null && mAppAnimator.isAnimating());
     }
 
     /** Is the window animating the DummyAnimation? */
@@ -486,7 +475,7 @@
             mService.mPendingRemove.add(mWin);
             mWin.mRemoveOnExit = false;
         }
-        mAnimator.hideWallpapersLocked(mWin);
+        mService.hideWallpapersLocked(mWin);
     }
 
     void hide() {
@@ -527,7 +516,7 @@
     }
 
     // This must be called while inside a transaction.
-    boolean commitFinishDrawingLocked(long currentTime) {
+    boolean commitFinishDrawingLocked() {
         if (DEBUG_STARTING_WINDOW &&
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
             Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
@@ -542,9 +531,9 @@
         mDrawState = READY_TO_SHOW;
         final AppWindowToken atoken = mWin.mAppToken;
         if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
-            performShowLocked();
+            return performShowLocked();
         }
-        return true;
+        return false;
     }
 
     static class SurfaceTrace extends SurfaceControl {
@@ -984,7 +973,7 @@
                     }
                     mSurfaceControl.destroy();
                 }
-                mAnimator.hideWallpapersLocked(mWin);
+                mService.hideWallpapersLocked(mWin);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Exception thrown when destroying Window " + this
                     + " surface " + mSurfaceControl + " session " + mSession
@@ -1010,7 +999,7 @@
                     WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
                 }
                 mPendingDestroySurface.destroy();
-                mAnimator.hideWallpapersLocked(mWin);
+                mService.hideWallpapersLocked(mWin);
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Exception thrown when destroying Window "
@@ -1096,9 +1085,6 @@
             if (appTransformation != null) {
                 tmpMatrix.postConcat(appTransformation.getMatrix());
             }
-            if (mAnimator.mUniverseBackground != null) {
-                tmpMatrix.postConcat(mAnimator.mUniverseBackground.mUniverseTransform.getMatrix());
-            }
             if (screenAnimation) {
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
@@ -1153,6 +1139,8 @@
                     mShownAlpha *= appTransformation.getAlpha();
                     if (appTransformation.hasClipRect()) {
                         mClipRect.set(appTransformation.getClipRect());
+                        // Account for non-fullscreen windows
+                        mClipRect.offset(frame.left, frame.top);
                         if (mWin.mHScale > 0) {
                             mClipRect.left /= mWin.mHScale;
                             mClipRect.right /= mWin.mHScale;
@@ -1164,9 +1152,6 @@
                         mHasClipRect = true;
                     }
                 }
-                if (mAnimator.mUniverseBackground != null) {
-                    mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
-                }
                 if (screenAnimation) {
                     mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
                 }
@@ -1192,15 +1177,12 @@
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
 
-        final boolean applyUniverseTransformation = (mAnimator.mUniverseBackground != null
-                && mWin.mAttrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
-                && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer);
         MagnificationSpec spec = null;
         //TODO (multidisplay): Magnification is supported only for the default display.
         if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
             spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
         }
-        if (applyUniverseTransformation || spec != null) {
+        if (spec != null) {
             final Rect frame = mWin.mFrame;
             final float tmpFloats[] = mService.mTmpFloats;
             final Matrix tmpMatrix = mWin.mTmpMatrix;
@@ -1208,10 +1190,6 @@
             tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);
             tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
 
-            if (applyUniverseTransformation) {
-                tmpMatrix.postConcat(mAnimator.mUniverseBackground.mUniverseTransform.getMatrix());
-            }
-
             if (spec != null && !spec.isNop()) {
                 tmpMatrix.postScale(spec.scale, spec.scale);
                 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
@@ -1231,9 +1209,6 @@
             mWin.mShownFrame.set(x, y, x + w, y + h);
 
             mShownAlpha = mAlpha;
-            if (applyUniverseTransformation) {
-                mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
-            }
         } else {
             mWin.mShownFrame.set(mWin.mFrame);
             if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
@@ -1301,17 +1276,9 @@
                     displayInfo.logicalHeight - w.mCompatFrame.top);
         } else if (w.mLayer >= mService.mSystemDecorLayer) {
             // Above the decor layer is easy, just use the entire window.
-            // Unless we have a universe background...  in which case all the
-            // windows need to be cropped by the screen, so they don't cover
-            // the universe background.
-            if (mAnimator.mUniverseBackground == null) {
-                w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
-            } else {
-                applyDecorRect(mService.mScreenRect);
-            }
-        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
-                || w.mDecorFrame.isEmpty()) {
-            // The universe background isn't cropped, nor windows without policy decor.
+            w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
+        } else if (w.mDecorFrame.isEmpty()) {
+            // Windows without policy decor aren't cropped.
             w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
         } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.mAnimating) {
             // If we're animating, the wallpaper crop should only be updated at the end of the
@@ -1482,7 +1449,7 @@
             hide();
         } else if (w.mAttachedHidden || !w.isOnScreen()) {
             hide();
-            mAnimator.hideWallpapersLocked(w);
+            mService.hideWallpapersLocked(w);
 
             // If we are waiting for this window to handle an
             // orientation change, well, it is hidden, so
@@ -1654,13 +1621,8 @@
         }
         if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
-            RuntimeException e = null;
-            if (!WindowManagerService.HIDE_STACK_CRAWLS) {
-                e = new RuntimeException();
-                e.fillInStackTrace();
-            }
             Slog.v(TAG, "performShow on " + this
-                    + ": mDrawState=" + mDrawState + " readyForDisplay="
+                    + ": mDrawState=" + drawStateToString() + " readyForDisplay="
                     + mWin.isReadyForDisplayIgnoringKeyguard()
                     + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING)
                     + " during animation: policyVis=" + mWin.mPolicyVisibility
@@ -1671,7 +1633,8 @@
                     + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
                     + " animating=" + mAnimating
                     + " tok animating="
-                    + (mAppAnimator != null ? mAppAnimator.animating : false), e);
+                    + (mAppAnimator != null ? mAppAnimator.animating : false) + " Callers="
+                    + Debug.getCallers(3));
         }
         if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) {
             if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
@@ -1932,11 +1895,6 @@
             pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
                     pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
         }
-        if (mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
-            pw.print(prefix); pw.print("mUniverseTransform=");
-                    mUniverseTransform.printShortString(pw);
-                    pw.println();
-        }
         if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
             pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
                     pw.print(" mAlpha="); pw.print(mAlpha);
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 1a672e68..bbeee8c 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -85,6 +85,7 @@
                     "removeAllWindows: removing win=" + win);
             win.mService.removeWindowLocked(win.mSession, win);
         }
+        windows.clear();
     }
 
     void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index d81cdd9..7b74e91 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -2,7 +2,7 @@
 # files
 LOCAL_REL_DIR := core/jni
 
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 
 LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
@@ -22,13 +22,12 @@
     $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
     $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
     $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
     $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
     $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
     $(LOCAL_REL_DIR)/onload.cpp
 
-include external/stlport/libstlport.mk
-
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
     frameworks/base/services \
@@ -37,8 +36,8 @@
     frameworks/native/services \
     libcore/include \
     libcore/include/libsuspend \
-	$(call include-path-for, libhardware)/hardware \
-	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+    $(call include-path-for, libhardware)/hardware \
+    $(call include-path-for, libhardware_legacy)/hardware_legacy \
 
 LOCAL_SHARED_LIBRARIES += \
     libandroid_runtime \
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index a58b00bce..3fd0f84 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -21,7 +21,9 @@
 #include "jni.h"
 #include <utils/Log.h>
 #include <utils/misc.h>
+#include <utils/String8.h>
 
+#include <dirent.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
@@ -80,8 +82,8 @@
 class AlarmImplTimerFd : public AlarmImpl
 {
 public:
-    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd) :
-        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd) { }
+    AlarmImplTimerFd(int fds[N_ANDROID_TIMERFDS], int epollfd, int rtc_id) :
+        AlarmImpl(fds, N_ANDROID_TIMERFDS), epollfd(epollfd), rtc_id(rtc_id) { }
     ~AlarmImplTimerFd();
 
     int set(int type, struct timespec *ts);
@@ -90,6 +92,7 @@
 
 private:
     int epollfd;
+    int rtc_id;
 };
 
 AlarmImpl::AlarmImpl(int *fds_, size_t n_fds) : fds(new int[n_fds]),
@@ -170,9 +173,16 @@
         return -1;
     }
 
-    fd = open("/dev/rtc0", O_RDWR);
+    if (rtc_id < 0) {
+        ALOGV("Not setting RTC because wall clock RTC was not found");
+        errno = ENODEV;
+        return -1;
+    }
+
+    android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
+    fd = open(rtc_dev.string(), O_RDWR);
     if (fd < 0) {
-        ALOGV("Unable to open RTC driver: %s\n", strerror(errno));
+        ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
         return res;
     }
 
@@ -283,6 +293,66 @@
     return reinterpret_cast<jlong>(ret);
 }
 
+static const char rtc_sysfs[] = "/sys/class/rtc";
+
+static bool rtc_is_hctosys(unsigned int rtc_id)
+{
+    android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",
+            rtc_sysfs, rtc_id);
+
+    FILE *file = fopen(hctosys_path.string(), "re");
+    if (!file) {
+        ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));
+        return false;
+    }
+
+    unsigned int hctosys;
+    bool ret = false;
+    int err = fscanf(file, "%u", &hctosys);
+    if (err == EOF)
+        ALOGE("failed to read from %s: %s", hctosys_path.string(),
+                strerror(errno));
+    else if (err == 0)
+        ALOGE("%s did not have expected contents", hctosys_path.string());
+    else
+        ret = hctosys;
+
+    fclose(file);
+    return ret;
+}
+
+static int wall_clock_rtc()
+{
+    DIR *dir = opendir(rtc_sysfs);
+    if (!dir) {
+        ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
+        return -1;
+    }
+
+    struct dirent *dirent;
+    while (errno = 0, dirent = readdir(dir)) {
+        unsigned int rtc_id;
+        int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
+
+        if (matched < 0)
+            break;
+        else if (matched != 1)
+            continue;
+
+        if (rtc_is_hctosys(rtc_id)) {
+            ALOGV("found wall clock RTC %u", rtc_id);
+            return rtc_id;
+        }
+    }
+
+    if (errno == 0)
+        ALOGW("no wall clock RTC found");
+    else
+        ALOGE("failed to enumerate RTCs: %s", strerror(errno));
+
+    return -1;
+}
+
 static jlong init_timerfd()
 {
     int epollfd;
@@ -290,7 +360,7 @@
 
     epollfd = epoll_create(N_ANDROID_TIMERFDS);
     if (epollfd < 0) {
-        ALOGV("epoll_create(%u) failed: %s", N_ANDROID_TIMERFDS,
+        ALOGV("epoll_create(%zu) failed: %s", N_ANDROID_TIMERFDS,
                 strerror(errno));
         return 0;
     }
@@ -308,7 +378,7 @@
         }
     }
 
-    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd);
+    AlarmImpl *ret = new AlarmImplTimerFd(fds, epollfd, wall_clock_rtc());
 
     for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
         epoll_event event;
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 3696e24..e4f242e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -29,8 +29,12 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
+// Disable warnings for Skia.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
 #include <SkCanvas.h>
 #include <SkBitmap.h>
+#pragma GCC diagnostic pop
 
 namespace android {
 
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 3a50ff7..f5121cd 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-static jlong halOpen(JNIEnv *env, jobject obj) {
+static jlong halOpen(JNIEnv* /* env */, jobject /* obj */) {
     hw_module_t const* module;
     consumerir_device_t *dev;
     int err;
@@ -50,7 +50,7 @@
     return reinterpret_cast<jlong>(dev);
 }
 
-static jint halTransmit(JNIEnv *env, jobject obj, jlong halObject,
+static jint halTransmit(JNIEnv *env, jobject /* obj */, jlong halObject,
    jint carrierFrequency, jintArray pattern) {
     int ret;
 
@@ -66,7 +66,7 @@
     return reinterpret_cast<jint>(ret);
 }
 
-static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject obj,
+static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */,
     jlong halObject) {
     consumerir_device_t *dev = reinterpret_cast<consumerir_device_t*>(halObject);
     consumerir_freq_range_t *ranges;
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
index b889b78..d48d159 100644
--- a/services/core/jni/com_android_server_SerialService.cpp
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -34,7 +34,7 @@
     jmethodID mConstructor;
 } gParcelFileDescriptorOffsets;
 
-static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
+static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */, jstring path)
 {
     const char *pathStr = env->GetStringUTFChars(path, NULL);
 
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 0625544..c50d63c 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -25,7 +25,7 @@
 
 namespace android {
 
-static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) {
+static void android_server_SystemServer_nativeInit(JNIEnv* /* env */, jobject /* clazz */) {
     char propBuf[PROPERTY_VALUE_MAX];
     property_get("system_init.startsensorservice", propBuf, "1");
     if (strcmp(propBuf, "1") == 0) {
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index 3551733..a1bff9d 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -41,20 +41,12 @@
     jmethodID mConstructor;
 } gParcelFileDescriptorOffsets;
 
-static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
-    if (env->ExceptionCheck()) {
-        ALOGE("An exception was thrown by callback '%s'.", methodName);
-        LOGE_EX(env);
-        env->ExceptionClear();
-    }
-}
-
 static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index)
 {
     char buffer[256];
 
     buffer[0] = 0;
-    int length = ioctl(fd, cmd, buffer);
+    ioctl(fd, cmd, buffer);
     if (buffer[0]) {
         jstring obj = env->NewStringUTF(buffer);
         env->SetObjectArrayElement(strArray, index, obj);
@@ -63,7 +55,8 @@
 }
 
 
-static jobjectArray android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv *env, jobject thiz)
+static jobjectArray android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv *env,
+                                                                        jobject /* thiz */)
 {
     int fd = open(DRIVER_NAME, O_RDWR);
     if (fd < 0) {
@@ -85,7 +78,7 @@
     return strArray;
 }
 
-static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobject thiz)
+static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobject /* thiz */)
 {
     int fd = open(DRIVER_NAME, O_RDWR);
     if (fd < 0) {
@@ -100,7 +93,8 @@
         gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
 }
 
-static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv *env, jobject thiz)
+static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv* /* env */,
+                                                                 jobject /* thiz */)
 {
     int fd = open(DRIVER_NAME, O_RDWR);
     if (fd < 0) {
@@ -112,7 +106,7 @@
     return (result == 1);
 }
 
-static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv *env, jobject thiz)
+static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobject /* thiz */)
 {
     int fd = open(DRIVER_NAME, O_RDWR);
     if (fd < 0) {
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 32c3f95..ee50ff9 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -148,7 +148,7 @@
     return 0;
 }
 
-static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv *env, jobject thiz)
+static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv* /* env */, jobject thiz)
 {
     struct usb_host_context* context = usb_host_init();
     if (!context) {
@@ -159,7 +159,8 @@
     usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
 }
 
-static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject thiz, jstring deviceName)
+static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
+                                                        jstring deviceName)
 {
     const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
     struct usb_device* device = usb_device_open(deviceNameStr);
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
new file mode 100644
index 0000000..94853b8
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "UsbMidiDeviceJNI"
+#define LOG_NDEBUG 0
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sound/asound.h>
+
+namespace android
+{
+
+static jclass sFileDescriptorClass;
+
+static jint
+android_server_UsbMidiDevice_get_subdevice_count(JNIEnv *env, jobject /* thiz */,
+        jint card, jint device)
+{
+    char    path[100];
+
+    snprintf(path, sizeof(path), "/dev/snd/controlC%d", card);
+    int fd = open(path, O_RDWR);
+    if (fd < 0) {
+        ALOGE("could not open %s", path);
+        return 0;
+    }
+
+    struct snd_rawmidi_info info;
+    memset(&info, 0, sizeof(info));
+    info.device = device;
+    int ret = ioctl(fd, SNDRV_CTL_IOCTL_RAWMIDI_INFO, &info);
+    close(fd);
+
+    if (ret < 0) {
+        ALOGE("SNDRV_CTL_IOCTL_RAWMIDI_INFO failed, errno: %d path: %s", errno, path);
+        return -1;
+    }
+
+    ALOGD("subdevices_count: %d", info.subdevices_count);
+    return info.subdevices_count;
+}
+
+static jobjectArray
+android_server_UsbMidiDevice_open(JNIEnv *env, jobject /* thiz */, jint card, jint device,
+        jint subdevice_count)
+{
+    char    path[100];
+
+    snprintf(path, sizeof(path), "/dev/snd/midiC%dD%d", card, device);
+
+    jobjectArray fds = env->NewObjectArray(subdevice_count, sFileDescriptorClass, NULL);
+    if (!fds) {
+        return NULL;
+    }
+
+    // to support multiple subdevices we open the same file multiple times
+    for (int i = 0; i < subdevice_count; i++) {
+        int fd = open(path, O_RDWR);
+        if (fd < 0) {
+            ALOGE("open failed on %s for index %d", path, i);
+            return NULL;
+        }
+
+        jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+        env->SetObjectArrayElement(fds, i, fileDescriptor);
+        env->DeleteLocalRef(fileDescriptor);
+    }
+
+    return fds;
+}
+
+static JNINativeMethod method_table[] = {
+    { "nativeGetSubdeviceCount", "(II)I", (void*)android_server_UsbMidiDevice_get_subdevice_count },
+    { "nativeOpen", "(III)[Ljava/io/FileDescriptor;", (void*)android_server_UsbMidiDevice_open },
+};
+
+int register_android_server_UsbMidiDevice(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("java/io/FileDescriptor");
+    if (clazz == NULL) {
+        ALOGE("Can't find java/io/FileDescriptor");
+        return -1;
+    }
+    sFileDescriptorClass = (jclass)env->NewGlobalRef(clazz);;
+
+    clazz = env->FindClass("com/android/server/usb/UsbMidiDevice");
+    if (clazz == NULL) {
+        ALOGE("Can't find com/android/server/usb/UsbMidiDevice");
+        return -1;
+    }
+
+    return jniRegisterNativeMethods(env, "com/android/server/usb/UsbMidiDevice",
+            method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 2b3f74a..fb1166b 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -29,18 +29,18 @@
 namespace android
 {
 
-static jboolean vibratorExists(JNIEnv *env, jobject clazz)
+static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
 {
     return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE;
 }
 
-static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
+static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
 {
     // ALOGI("vibratorOn\n");
     vibrator_on(timeout_ms);
 }
 
-static void vibratorOff(JNIEnv *env, jobject clazz)
+static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
 {
     // ALOGI("vibratorOff\n");
     vibrator_off();
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index 2a16dfe..7faeb49 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -226,12 +226,12 @@
         jniThrowNullPointerException(env, "address");
     } else {
         if (add) {
-            if (error = ifc_add_address(name, address, jPrefixLength)) {
+            if ((error = ifc_add_address(name, address, jPrefixLength)) != 0) {
                 ALOGE("Cannot add address %s/%d on interface %s (%s)", address, jPrefixLength, name,
                       strerror(-error));
             }
         } else {
-            if (error = ifc_del_address(name, address, jPrefixLength)) {
+            if ((error = ifc_del_address(name, address, jPrefixLength)) != 0) {
                 ALOGE("Cannot del address %s/%d on interface %s (%s)", address, jPrefixLength, name,
                       strerror(-error));
             }
@@ -258,7 +258,7 @@
     }
 }
 
-static jint create(JNIEnv *env, jobject thiz, jint mtu)
+static jint create(JNIEnv *env, jobject /* thiz */, jint mtu)
 {
     int tun = create_interface(mtu);
     if (tun < 0) {
@@ -268,7 +268,7 @@
     return tun;
 }
 
-static jstring getName(JNIEnv *env, jobject thiz, jint tun)
+static jstring getName(JNIEnv *env, jobject /* thiz */, jint tun)
 {
     char name[IFNAMSIZ];
     if (get_interface_name(name, tun) < 0) {
@@ -278,7 +278,7 @@
     return env->NewStringUTF(name);
 }
 
-static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+static jint setAddresses(JNIEnv *env, jobject /* thiz */, jstring jName,
         jstring jAddresses)
 {
     const char *name = NULL;
@@ -311,7 +311,7 @@
     return count;
 }
 
-static void reset(JNIEnv *env, jobject thiz, jstring jName)
+static void reset(JNIEnv *env, jobject /* thiz */, jstring jName)
 {
     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
     if (!name) {
@@ -324,7 +324,7 @@
     env->ReleaseStringUTFChars(jName, name);
 }
 
-static jint check(JNIEnv *env, jobject thiz, jstring jName)
+static jint check(JNIEnv *env, jobject /* thiz */, jstring jName)
 {
     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
     if (!name) {
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a35af91..f2d0f06 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -408,6 +408,7 @@
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    (void)res; // Don't scream about unused variable in the LOG_NDEBUG case
     return 0;
 }
 
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
index f943d16..11388d8 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -137,6 +137,7 @@
 int register_android_server_InputApplicationHandle(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "com/android/server/input/InputApplicationHandle",
             gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
+    (void) res;  // Faked use when LOG_NDEBUG.
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
     jclass clazz;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index cddca92..7c5980a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -350,14 +350,14 @@
     }
 }
 
-status_t NativeInputManager::registerInputChannel(JNIEnv* env,
+status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
         const sp<InputChannel>& inputChannel,
         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
     return mInputManager->getDispatcher()->registerInputChannel(
             inputChannel, inputWindowHandle, monitor);
 }
 
-status_t NativeInputManager::unregisterInputChannel(JNIEnv* env,
+status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */,
         const sp<InputChannel>& inputChannel) {
     return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
 }
@@ -428,7 +428,7 @@
     } // release lock
 }
 
-sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t deviceId) {
+sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t /* deviceId */) {
     AutoMutex _l(mLock);
 
     sp<PointerController> controller = mLocked.pointerController.promote();
@@ -548,7 +548,7 @@
 }
 
 void NativeInputManager::notifySwitch(nsecs_t when,
-        uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) {
+        uint32_t switchValues, uint32_t switchMask, uint32_t /* policyFlags */) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     ALOGD("notifySwitch - when=%lld, switchValues=0x%08x, switchMask=0x%08x, policyFlags=0x%x",
             when, switchValues, switchMask, policyFlags);
@@ -1006,7 +1006,7 @@
 
 // ----------------------------------------------------------------------------
 
-static jlong nativeInit(JNIEnv* env, jclass clazz,
+static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
         jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
     if (messageQueue == NULL) {
@@ -1020,7 +1020,7 @@
     return reinterpret_cast<jlong>(im);
 }
 
-static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
+static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     status_t result = im->getInputManager()->start();
@@ -1029,8 +1029,8 @@
     }
 }
 
-static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jlong ptr, jboolean external,
-        jint displayId, jint orientation,
+static void nativeSetDisplayViewport(JNIEnv* /* env */, jclass /* clazz */, jlong ptr,
+        jboolean external, jint displayId, jint orientation,
         jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
         jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom,
         jint deviceWidth, jint deviceHeight) {
@@ -1052,7 +1052,7 @@
     im->setDisplayViewport(external, v);
 }
 
-static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
+static jint nativeGetScanCodeState(JNIEnv* /* env */, jclass /* clazz */,
         jlong ptr, jint deviceId, jint sourceMask, jint scanCode) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1060,7 +1060,7 @@
             deviceId, uint32_t(sourceMask), scanCode);
 }
 
-static jint nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
+static jint nativeGetKeyCodeState(JNIEnv* /* env */, jclass /* clazz */,
         jlong ptr, jint deviceId, jint sourceMask, jint keyCode) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1068,7 +1068,7 @@
             deviceId, uint32_t(sourceMask), keyCode);
 }
 
-static jint nativeGetSwitchState(JNIEnv* env, jclass clazz,
+static jint nativeGetSwitchState(JNIEnv* /* env */, jclass /* clazz */,
         jlong ptr, jint deviceId, jint sourceMask, jint sw) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1076,7 +1076,7 @@
             deviceId, uint32_t(sourceMask), sw);
 }
 
-static jboolean nativeHasKeys(JNIEnv* env, jclass clazz,
+static jboolean nativeHasKeys(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jint deviceId, jint sourceMask, jintArray keyCodes, jbooleanArray outFlags) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1106,7 +1106,7 @@
 }
 
 static void handleInputChannelDisposed(JNIEnv* env,
-        jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data) {
+        jobject /* inputChannelObj */, const sp<InputChannel>& inputChannel, void* data) {
     NativeInputManager* im = static_cast<NativeInputManager*>(data);
 
     ALOGW("Input channel object '%s' was disposed without first being unregistered with "
@@ -1114,7 +1114,7 @@
     im->unregisterInputChannel(env, inputChannel);
 }
 
-static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
+static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1143,7 +1143,7 @@
     }
 }
 
-static void nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
+static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobject inputChannelObj) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1164,14 +1164,14 @@
     }
 }
 
-static void nativeSetInputFilterEnabled(JNIEnv* env, jclass clazz,
+static void nativeSetInputFilterEnabled(JNIEnv* /* env */, jclass /* clazz */,
         jlong ptr, jboolean enabled) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled);
 }
 
-static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz,
+static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,
         jint syncMode, jint timeoutMillis, jint policyFlags) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1203,36 +1203,36 @@
     }
 }
 
-static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
+static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobjectArray windowHandleObjArray) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setInputWindows(env, windowHandleObjArray);
 }
 
-static void nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
+static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobject applicationHandleObj) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setFocusedApplication(env, applicationHandleObj);
 }
 
-static void nativeSetInputDispatchMode(JNIEnv* env,
-        jclass clazz, jlong ptr, jboolean enabled, jboolean frozen) {
+static void nativeSetInputDispatchMode(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jboolean enabled, jboolean frozen) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setInputDispatchMode(enabled, frozen);
 }
 
-static void nativeSetSystemUiVisibility(JNIEnv* env,
-        jclass clazz, jlong ptr, jint visibility) {
+static void nativeSetSystemUiVisibility(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jint visibility) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setSystemUiVisibility(visibility);
 }
 
 static jboolean nativeTransferTouchFocus(JNIEnv* env,
-        jclass clazz, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
+        jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     sp<InputChannel> fromChannel =
@@ -1252,15 +1252,15 @@
     }
 }
 
-static void nativeSetPointerSpeed(JNIEnv* env,
-        jclass clazz, jlong ptr, jint speed) {
+static void nativeSetPointerSpeed(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jint speed) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setPointerSpeed(speed);
 }
 
-static void nativeSetShowTouches(JNIEnv* env,
-        jclass clazz, jlong ptr, jboolean enabled) {
+static void nativeSetShowTouches(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jboolean enabled) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->setShowTouches(enabled);
@@ -1279,7 +1279,7 @@
 }
 
 static void nativeVibrate(JNIEnv* env,
-        jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj,
+        jclass /* clazz */, jlong ptr, jint deviceId, jlongArray patternObj,
         jint repeat, jint token) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1303,30 +1303,30 @@
     im->getInputManager()->getReader()->vibrate(deviceId, pattern, patternSize, repeat, token);
 }
 
-static void nativeCancelVibrate(JNIEnv* env,
-        jclass clazz, jlong ptr, jint deviceId, jint token) {
+static void nativeCancelVibrate(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jint deviceId, jint token) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
 }
 
-static void nativeReloadKeyboardLayouts(JNIEnv* env,
-        jclass clazz, jlong ptr) {
+static void nativeReloadKeyboardLayouts(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->getInputManager()->getReader()->requestRefreshConfiguration(
             InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS);
 }
 
-static void nativeReloadDeviceAliases(JNIEnv* env,
-        jclass clazz, jlong ptr) {
+static void nativeReloadDeviceAliases(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->getInputManager()->getReader()->requestRefreshConfiguration(
             InputReaderConfiguration::CHANGE_DEVICE_ALIAS);
 }
 
-static jstring nativeDump(JNIEnv* env, jclass clazz, jlong ptr) {
+static jstring nativeDump(JNIEnv* env, jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     String8 dump;
@@ -1334,7 +1334,7 @@
     return env->NewStringUTF(dump.string());
 }
 
-static void nativeMonitor(JNIEnv* env, jclass clazz, jlong ptr) {
+static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     im->getInputManager()->getReader()->monitor();
@@ -1416,6 +1416,7 @@
 int register_android_server_InputManager(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "com/android/server/input/InputManagerService",
             gInputManagerMethods, NELEM(gInputManagerMethods));
+    (void) res;  // Faked use when LOG_NDEBUG.
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
     // Callbacks
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index 46ec1f4..01c51cf 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -227,6 +227,7 @@
 int register_android_server_InputWindowHandle(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "com/android/server/input/InputWindowHandle",
             gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
+    (void) res;  // Faked use when LOG_NDEBUG.
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
     jclass clazz;
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index d51e044..b2b2783 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -60,7 +60,7 @@
     }
 }
 
-static jlong init_native(JNIEnv *env, jobject clazz)
+static jlong init_native(JNIEnv* /* env */, jobject /* clazz */)
 {
     int err;
     hw_module_t* module;
@@ -93,7 +93,7 @@
     return (jlong)devices;
 }
 
-static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr)
+static void finalize_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr)
 {
     Devices* devices = (Devices*)ptr;
     if (devices == NULL) {
@@ -103,7 +103,7 @@
     free(devices);
 }
 
-static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr,
+static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
         jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
 {
     Devices* devices = (Devices*)ptr;
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 37a3eaa..049e455 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -698,14 +698,14 @@
   // TODO: inject any device context if when needed
 }
 
-static jboolean IsSupported(JNIEnv* env, jclass clazz) {
+static jboolean IsSupported(JNIEnv* /* env */, jclass /* clazz */) {
   if (sFlpInterface == NULL) {
     return JNI_FALSE;
   }
   return JNI_TRUE;
 }
 
-static jint GetBatchSize(JNIEnv* env, jobject object) {
+static jint GetBatchSize(JNIEnv* env, jobject /* object */) {
   if(sFlpInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -715,7 +715,7 @@
 
 static void StartBatching(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jint id,
     jobject optionsObject) {
   if(sFlpInterface == NULL || optionsObject == NULL) {
@@ -730,7 +730,7 @@
 
 static void UpdateBatchingOptions(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jint id,
     jobject optionsObject) {
   if(sFlpInterface == NULL || optionsObject == NULL) {
@@ -743,7 +743,7 @@
   ThrowOnError(env, result, __FUNCTION__);
 }
 
-static void StopBatching(JNIEnv* env, jobject object, jint id) {
+static void StopBatching(JNIEnv* env, jobject /* object */, jint id) {
   if(sFlpInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -751,7 +751,7 @@
   sFlpInterface->stop_batching(id);
 }
 
-static void Cleanup(JNIEnv* env, jobject object) {
+static void Cleanup(JNIEnv* env, jobject /* object */) {
   if(sFlpInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -774,7 +774,7 @@
   }
 }
 
-static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
+static void GetBatchedLocation(JNIEnv* env, jobject /* object */, jint lastNLocations) {
   if(sFlpInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -782,7 +782,7 @@
   sFlpInterface->get_batched_location(lastNLocations);
 }
 
-static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
+static void InjectLocation(JNIEnv* env, jobject /* object */, jobject locationObject) {
   if(locationObject == NULL) {
     ALOGE("Invalid location for injection: %p", locationObject);
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
@@ -806,7 +806,7 @@
   return sFlpDiagnosticInterface != NULL;
 }
 
-static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
+static void InjectDiagnosticData(JNIEnv* env, jobject /* object */, jstring stringData) {
   if(stringData == NULL) {
     ALOGE("Invalid diagnostic data for injection: %p", stringData);
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
@@ -830,7 +830,7 @@
   return sFlpDeviceContextInterface != NULL;
 }
 
-static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
+static void InjectDeviceContext(JNIEnv* env, jobject /* object */, jint enabledMask) {
   if(sFlpDeviceContextInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -845,7 +845,7 @@
 
 static void AddGeofences(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jobjectArray geofenceRequestsArray) {
   if(geofenceRequestsArray == NULL) {
     ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
@@ -885,7 +885,7 @@
   }
 }
 
-static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
+static void PauseGeofence(JNIEnv* env, jobject /* object */, jint geofenceId) {
   if(sFlpGeofencingInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
   }
@@ -895,7 +895,7 @@
 
 static void ResumeGeofence(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jint geofenceId,
     jint monitorTransitions) {
   if(sFlpGeofencingInterface == NULL) {
@@ -907,7 +907,7 @@
 
 static void ModifyGeofenceOption(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jint geofenceId,
     jint lastTransition,
     jint monitorTransitions,
@@ -931,7 +931,7 @@
 
 static void RemoveGeofences(
     JNIEnv* env,
-    jobject object,
+    jobject /* object */,
     jintArray geofenceIdsArray) {
   if(sFlpGeofencingInterface == NULL) {
     ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 8183321..0cd6eb5 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -214,7 +214,7 @@
 
     size_t status_size = agps_status->size;
     if (status_size == sizeof(AGpsStatus_v3)) {
-      ALOGV("AGpsStatus is V3: %d", status_size);
+      ALOGV("AGpsStatus is V3: %zd", status_size);
       switch (agps_status->addr.ss_family)
       {
       case AF_INET:
@@ -256,7 +256,7 @@
           break;
       }
     } else if (status_size >= sizeof(AGpsStatus_v2)) {
-      ALOGV("AGpsStatus is V2+: %d", status_size);
+      ALOGV("AGpsStatus is V2+: %zd", status_size);
       // for back-compatibility reasons we check in v2 that the data structure size is greater or
       // equal to the declared size in gps.h
       uint32_t ipaddr = agps_status->ipaddr;
@@ -266,12 +266,12 @@
           isSupported = true;
       }
     } else if (status_size >= sizeof(AGpsStatus_v1)) {
-        ALOGV("AGpsStatus is V1+: %d", status_size);
+        ALOGV("AGpsStatus is V1+: %zd", status_size);
         // because we have to check for >= with regards to v2, we also need to relax the check here
         // and only make sure that the size is at least what we expect
         isSupported = true;
     } else {
-        ALOGE("Invalid size of AGpsStatus found: %d.", status_size);
+        ALOGE("Invalid size of AGpsStatus found: %zd.", status_size);
     }
 
     if (isSupported) {
@@ -509,7 +509,8 @@
     }
 }
 
-static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
+static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* /* env */,
+                                                                  jclass /* clazz */) {
     if (sGpsInterface != NULL) {
         return JNI_TRUE;
     } else {
@@ -543,14 +544,15 @@
     return JNI_TRUE;
 }
 
-static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
+static void android_location_GpsLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface)
         sGpsInterface->cleanup();
 }
 
-static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
-        jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
+static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* /* env */,
+        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
+        jint preferred_time)
 {
     if (sGpsInterface) {
         if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
@@ -564,7 +566,7 @@
         return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
+static jboolean android_location_GpsLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface) {
         if (sGpsInterface->start() == 0) {
@@ -577,7 +579,7 @@
         return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
+static jboolean android_location_GpsLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
 {
     if (sGpsInterface) {
         if (sGpsInterface->stop() == 0) {
@@ -590,13 +592,15 @@
         return JNI_FALSE;
 }
 
-static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
+static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* /* env */,
+                                                                    jobject /* obj */,
+                                                                    jint flags)
 {
     if (sGpsInterface)
         sGpsInterface->delete_aiding_data(flags);
 }
 
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
+static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
         jintArray maskArray)
 {
@@ -627,8 +631,8 @@
     return (jint) num_svs;
 }
 
-static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(JNIEnv* env,
-        jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
+static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
+        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
 {
     AGpsRefLocation location;
 
@@ -655,7 +659,7 @@
 }
 
 static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
-        jobject obj, jbyteArray ni_msg, jint size)
+        jobject /* obj */, jbyteArray ni_msg, jint size)
 {
     size_t sz;
 
@@ -671,8 +675,8 @@
     env->ReleaseByteArrayElements(ni_msg,b,0);
 }
 
-static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
-        jobject obj, jint type, jstring  setid_string)
+static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+                                                             jint type, jstring  setid_string)
 {
     if (!sAGpsRilInterface) {
         ALOGE("no AGPS RIL interface in agps_set_id");
@@ -684,7 +688,7 @@
     env->ReleaseStringUTFChars(setid_string, setid);
 }
 
-static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
                                             jbyteArray nmeaArray, jint buffer_size)
 {
     // this should only be called from within a call to reportNmea
@@ -697,21 +701,22 @@
     return (jint) length;
 }
 
-static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
         jlong time, jlong timeReference, jint uncertainty)
 {
     if (sGpsInterface)
         sGpsInterface->inject_time(time, timeReference, uncertainty);
 }
 
-static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
-        jdouble latitude, jdouble longitude, jfloat accuracy)
+static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
+        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
 {
     if (sGpsInterface)
         sGpsInterface->inject_location(latitude, longitude, accuracy);
 }
 
-static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
+static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* /* env */,
+                                                                   jobject /* obj */)
 {
     if (sGpsXtraInterface != NULL) {
         return JNI_TRUE;
@@ -720,7 +725,7 @@
     }
 }
 
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
         jbyteArray data, jint length)
 {
     if (!sGpsXtraInterface) {
@@ -734,7 +739,7 @@
 }
 
 static void android_location_GpsLocationProvider_agps_data_conn_open(
-        JNIEnv* env, jobject obj, jstring apn, jint apnIpType)
+        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
 {
     if (!sAGpsInterface) {
         ALOGE("no AGPS interface in agps_data_conn_open");
@@ -753,13 +758,14 @@
     } else if (interface_size == sizeof(AGpsInterface_v1)) {
         sAGpsInterface->data_conn_open(apnStr);
     } else {
-        ALOGE("Invalid size of AGpsInterface found: %d.", interface_size);
+        ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
     }
 
     env->ReleaseStringUTFChars(apn, apnStr);
 }
 
-static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
+static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
+                                                                       jobject /* obj */)
 {
     if (!sAGpsInterface) {
         ALOGE("no AGPS interface in agps_data_conn_closed");
@@ -768,7 +774,8 @@
     sAGpsInterface->data_conn_closed();
 }
 
-static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
+static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
+                                                                       jobject /* obj */)
 {
     if (!sAGpsInterface) {
         ALOGE("no AGPS interface in agps_data_conn_failed");
@@ -777,7 +784,7 @@
     sAGpsInterface->data_conn_failed();
 }
 
-static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
         jint type, jstring hostname, jint port)
 {
     if (!sAGpsInterface) {
@@ -789,8 +796,8 @@
     env->ReleaseStringUTFChars(hostname, c_hostname);
 }
 
-static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
-      jint notifId, jint response)
+static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* /* env */,
+      jobject /* obj */, jint notifId, jint response)
 {
     if (!sGpsNiInterface) {
         ALOGE("no NI interface in send_ni_response");
@@ -800,8 +807,8 @@
     sGpsNiInterface->respond(notifId, response);
 }
 
-static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
-{
+static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env,
+                                                                       jobject /* obj */) {
     jstring result = NULL;
     if (sGpsDebugInterface) {
         const size_t maxLength = 2047;
@@ -814,7 +821,7 @@
     return result;
 }
 
-static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject obj,
+static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
         jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
 {
 
@@ -837,16 +844,17 @@
     }
 }
 
-static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* env,
-          jobject obj) {
+static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* /* env */,
+                                                                           jobject /* obj */)
+{
     if (sGpsGeofencingInterface != NULL) {
         return JNI_TRUE;
     }
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* env, jobject obj,
-        jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
+static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
         jint last_transition, jint monitor_transition, jint notification_responsiveness,
         jint unknown_timer) {
     if (sGpsGeofencingInterface != NULL) {
@@ -860,8 +868,8 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* env, jobject obj,
-        jint geofence_id) {
+static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->remove_geofence_area(geofence_id);
         return JNI_TRUE;
@@ -871,8 +879,8 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* env, jobject obj,
-        jint geofence_id) {
+static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->pause_geofence(geofence_id);
         return JNI_TRUE;
@@ -882,8 +890,8 @@
     return JNI_FALSE;
 }
 
-static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env, jobject obj,
-        jint geofence_id, jint monitor_transition) {
+static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id, jint monitor_transition) {
     if (sGpsGeofencingInterface != NULL) {
         sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
         return JNI_TRUE;
@@ -1253,7 +1261,7 @@
         env->DeleteLocalRef(gpsMeasurementsEventClass);
         env->DeleteLocalRef(gpsMeasurementsEvent);
     } else {
-        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%d", data->size);
+        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
     }
 }
 
@@ -1304,7 +1312,7 @@
     size_t dataLength = message->data_length;
     uint8_t* data = message->data;
     if (dataLength == 0 || data == NULL) {
-        ALOGE("Invalid Navigation Message found: data=%p, length=%d", data, dataLength);
+        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
         return NULL;
     }
 
@@ -1363,7 +1371,7 @@
         env->DeleteLocalRef(navigationMessageEventClass);
         env->DeleteLocalRef(navigationMessageEvent);
     } else {
-        ALOGE("Invalid GpsNavigationMessage size found: %d", message->size);
+        ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
     }
 }
 
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 33e0bd7..6dcdd9d 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -112,17 +112,17 @@
     }
 }
 
-static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
     ScopedUtfChars name(env, nameStr);
     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
 }
 
-static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
     ScopedUtfChars name(env, nameStr);
     release_wake_lock(name.c_str());
 }
 
-static void nativeSetInteractive(JNIEnv *env, jclass clazz, jboolean enable) {
+static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
     if (gPowerModule) {
         if (enable) {
             ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
@@ -134,7 +134,7 @@
     }
 }
 
-static void nativeSetAutoSuspend(JNIEnv *env, jclass clazz, jboolean enable) {
+static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
     if (enable) {
         ALOGD_IF_SLOW(100, "Excessive delay in autosuspend_enable() while turning screen off");
         autosuspend_enable();
@@ -189,6 +189,7 @@
 int register_android_server_PowerManagerService(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
             gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+    (void) res;  // Faked use when LOG_NDEBUG.
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
 
     // Callbacks
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index dcb5199..507bc9c 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -688,6 +688,7 @@
     int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
             gTvInputHalMethods, NELEM(gTvInputHalMethods));
     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    (void)res; // Don't complain about unused variable in the LOG_NDEBUG case
 
     jclass clazz;
     FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 7b2e408..7db7414 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -32,6 +32,7 @@
 int register_android_server_SerialService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_UsbDeviceManager(JNIEnv* env);
+int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
@@ -46,7 +47,7 @@
 
 using namespace android;
 
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
 {
     JNIEnv* env = NULL;
     jint result = -1;
@@ -65,6 +66,7 @@
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
     register_android_server_UsbDeviceManager(env);
+    register_android_server_UsbMidiDevice(env);
     register_android_server_UsbHostManager(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 9fd0e09..ea59d4b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,18 +39,21 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 
 /**
  * Stores and restores state for the Device and Profile owners. By definition there can be
  * only one device owner, but there may be a profile owner for each user.
  */
-public class DeviceOwner {
+class DeviceOwner {
     private static final String TAG = "DevicePolicyManagerService";
 
     private static final String DEVICE_OWNER_XML = "device_owner.xml";
     private static final String TAG_DEVICE_OWNER = "device-owner";
+    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
     private static final String TAG_PROFILE_OWNER = "profile-owner";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
@@ -66,6 +69,9 @@
     // Internal state for the device owner package.
     private OwnerInfo mDeviceOwner;
 
+    // Internal state for the device initializer package.
+    private OwnerInfo mDeviceInitializer;
+
     // Internal state for the profile owner packages.
     private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
 
@@ -102,12 +108,11 @@
     }
 
     /**
-     * @deprecated Use a component name instead of package name
-     * Creates an instance of the device owner object with the profile owner set.
+     * Creates an instance of the device owner object with the device initializer set.
      */
-    static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
+    static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
         DeviceOwner owner = new DeviceOwner();
-        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
+        owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
         return owner;
     }
 
@@ -136,11 +141,24 @@
         mDeviceOwner = null;
     }
 
-    /**
-     * @deprecated
-     */
-    void setProfileOwner(String packageName, String ownerName, int userId) {
-        mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
+    String getDeviceInitializerPackageName() {
+        return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
+    }
+
+    String getDeviceInitializerName() {
+        return mDeviceInitializer != null ? mDeviceInitializer.name : null;
+    }
+
+    void setDeviceInitializer(String packageName, String ownerName) {
+        mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+    }
+
+    void clearDeviceInitializer() {
+        mDeviceInitializer = null;
+    }
+
+    boolean hasDeviceInitializer() {
+        return mDeviceInitializer != null;
     }
 
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -151,16 +169,6 @@
         mProfileOwners.remove(userId);
     }
 
-    /**
-     * @deprecated Use getProfileOwnerComponent
-     * @param userId
-     * @return
-     */
-    String getProfileOwnerPackageName(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.packageName : null;
-    }
-
     ComponentName getProfileOwnerComponent(int userId) {
         OwnerInfo profileOwner = mProfileOwners.get(userId);
         return profileOwner != null ? profileOwner.admin : null;
@@ -207,6 +215,7 @@
         return false;
     }
 
+    @VisibleForTesting
     void readOwnerFile() {
         try {
             InputStream input = openRead();
@@ -223,6 +232,10 @@
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     mDeviceOwner = new OwnerInfo(name, packageName);
+                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceInitializer = new OwnerInfo(name, packageName);
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -259,6 +272,7 @@
         }
     }
 
+    @VisibleForTesting
     void writeOwnerFile() {
         synchronized (this) {
             writeOwnerFileLocked();
@@ -282,6 +296,16 @@
                 out.endTag(null, TAG_DEVICE_OWNER);
             }
 
+            // Write device initializer tag
+            if (mDeviceInitializer != null) {
+                out.startTag(null, TAG_DEVICE_INITIALIZER);
+                out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
+                if (mDeviceInitializer.name != null) {
+                    out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
+                }
+                out.endTag(null, TAG_DEVICE_INITIALIZER);
+            }
+
             // Write profile owner tags
             if (mProfileOwners.size() > 0) {
                 for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
@@ -329,10 +353,10 @@
         }
     }
 
-    static class OwnerInfo {
-        public String name;
-        public String packageName;
-        public ComponentName admin;
+    private static class OwnerInfo {
+        public final String name;
+        public final String packageName;
+        public final ComponentName admin;
 
         public OwnerInfo(String name, String packageName) {
             this.name = name;
@@ -345,5 +369,23 @@
             this.admin = admin;
             this.packageName = admin.getPackageName();
         }
+        public void dump(String prefix, PrintWriter pw) {
+            pw.println(prefix + "admin=" + admin);
+            pw.println(prefix + "name=" + name);
+            pw.println();
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        if (mDeviceOwner != null) {
+            pw.println(prefix + "Device Owner: ");
+            mDeviceOwner.dump(prefix + "  ", pw);
+        }
+        if (mProfileOwners != null) {
+            for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
+                pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
+                entry.getValue().dump(prefix + "  ", pw);
+            }
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 40e2056..8e3eaaf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
@@ -48,8 +49,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
 import android.hardware.usb.UsbManager;
 import android.media.AudioManager;
 import android.media.IAudioService;
@@ -77,6 +80,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.security.Credentials;
+import android.security.IKeyChainAliasCallback;
 import android.security.IKeyChainService;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
@@ -98,6 +102,7 @@
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -176,6 +181,14 @@
         DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS);
     }
 
+    // The following user restrictions cannot be changed by any active admin, including device
+    // owner and profile owner.
+    private static final Set<String> IMMUTABLE_USER_RESTRICTIONS;
+    static {
+        IMMUTABLE_USER_RESTRICTIONS = new HashSet();
+        IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER);
+    }
+
     private static final Set<String> SECURE_SETTINGS_WHITELIST;
     private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST;
     private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
@@ -193,14 +206,13 @@
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
-        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.BLUETOOTH_ON);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.MODE_RINGER);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.NETWORK_PREFERENCE);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
-        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_ON);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY);
+        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
     }
 
     final Context mContext;
@@ -1138,13 +1150,15 @@
             boolean ownsProfile = (getProfileOwner(userHandle) != null
                     && getProfileOwner(userHandle).getPackageName()
                         .equals(admin.info.getPackageName()));
+            boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
+                    && !hasUserSetupCompleted(userHandle);
 
             if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
-                if (ownsDevice) {
+                if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
                     return admin;
                 }
             } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
-                if (ownsDevice || ownsProfile) {
+                if (ownsDevice || ownsProfile || ownsInitialization) {
                     return admin;
                 }
             } else {
@@ -1518,11 +1532,11 @@
         // a sanity check in case the two get out of sync; this should
         // never normally happen.
         LockPatternUtils utils = new LockPatternUtils(mContext);
-        if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
+        if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
             Slog.w(LOG_TAG, "Active password quality 0x"
                     + Integer.toHexString(policy.mActivePasswordQuality)
                     + " does not match actual quality 0x"
-                    + Integer.toHexString(utils.getActivePasswordQuality()));
+                    + Integer.toHexString(utils.getActivePasswordQuality(userHandle)));
             policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
             policy.mActivePasswordLength = 0;
             policy.mActivePasswordUpperCase = 0;
@@ -1578,15 +1592,16 @@
     void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
         // Ensure the status of the camera is synced down to the system. Interested native services
         // should monitor this value and act accordingly.
-        boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
+        String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle;
+        boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false);
         boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
         if (cameraDisabled != systemState) {
             long token = Binder.clearCallingIdentity();
             try {
                 String value = cameraDisabled ? "1" : "0";
                 if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
-                        + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
-                SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
+                        + cameraPropertyForUser + "] = " + value);
+                SystemProperties.set(cameraPropertyForUser, value);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1897,7 +1912,7 @@
                 return;
             }
             if (admin.getUid() != Binder.getCallingUid()) {
-                // If trying to remove device owner, refuse when the caller is not the owner.
+                // Active device owners must remain active admins.
                 if (isDeviceOwner(adminReceiver.getPackageName())) {
                     return;
                 }
@@ -1913,17 +1928,15 @@
         }
     }
 
-    public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
+    public void setPasswordQuality(ComponentName who, int quality) {
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
-        enforceCrossUserPermission(userHandle);
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordQuality != quality) {
@@ -1962,15 +1975,13 @@
         }
     }
 
-    public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumLength(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLength != length) {
@@ -2009,15 +2020,13 @@
         }
     }
 
-    public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
+    public void setPasswordHistoryLength(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordHistoryLength != length) {
@@ -2056,18 +2065,14 @@
         }
     }
 
-    public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
+    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-            if (timeout < 0) {
-                throw new IllegalArgumentException("Timeout must be >= 0 ms");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
             // Calling this API automatically bumps the expiration date
@@ -2225,15 +2230,13 @@
         }
     }
 
-    public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordUpperCase != length) {
@@ -2272,12 +2275,10 @@
         }
     }
 
-    public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
-        enforceCrossUserPermission(userHandle);
+    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLowerCase != length) {
@@ -2316,15 +2317,13 @@
         }
     }
 
-    public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumLetters(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLetters != length) {
@@ -2354,6 +2353,9 @@
                 final int N = policy.mAdminList.size();
                 for (int i=0; i<N; i++) {
                     ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                        continue;
+                    }
                     if (length < admin.minimumPasswordLetters) {
                         length = admin.minimumPasswordLetters;
                     }
@@ -2363,15 +2365,13 @@
         }
     }
 
-    public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumNumeric(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNumeric != length) {
@@ -2401,6 +2401,9 @@
                 final int N = policy.mAdminList.size();
                 for (int i = 0; i < N; i++) {
                     ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                        continue;
+                    }
                     if (length < admin.minimumPasswordNumeric) {
                         length = admin.minimumPasswordNumeric;
                     }
@@ -2410,15 +2413,13 @@
         }
     }
 
-    public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumSymbols(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordSymbols != length) {
@@ -2448,6 +2449,9 @@
                 final int N = policy.mAdminList.size();
                 for (int i=0; i<N; i++) {
                     ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                        continue;
+                    }
                     if (length < admin.minimumPasswordSymbols) {
                         length = admin.minimumPasswordSymbols;
                     }
@@ -2457,15 +2461,13 @@
         }
     }
 
-    public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
+    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNonLetter != length) {
@@ -2495,6 +2497,9 @@
                 final int N = policy.mAdminList.size();
                 for (int i=0; i<N; i++) {
                     ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                        continue;
+                    }
                     if (length < admin.minimumPasswordNonLetter) {
                         length = admin.minimumPasswordNonLetter;
                     }
@@ -2521,8 +2526,7 @@
 
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
                     || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
                 return false;
@@ -2555,15 +2559,13 @@
         }
     }
 
-    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who,
@@ -2631,11 +2633,11 @@
         return strictestAdmin;
     }
 
-    public boolean resetPassword(String passwordOrNull, int flags, int userHandle) {
+    public boolean resetPassword(String passwordOrNull, int flags) {
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "reset the password");
 
         String password = passwordOrNull != null ? passwordOrNull : "";
@@ -2744,9 +2746,9 @@
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
             if (!TextUtils.isEmpty(password)) {
-                utils.saveLockPassword(password, quality, false, userHandle);
+                utils.saveLockPassword(password, quality, userHandle);
             } else {
-                utils.clearLock(false, userHandle);
+                utils.clearLock(userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
@@ -2766,15 +2768,13 @@
         return true;
     }
 
-    public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
+    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
             if (ap.maximumTimeToUnlock != timeMs) {
@@ -2953,9 +2953,7 @@
 
     @Override
     public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         }
@@ -2980,6 +2978,63 @@
         return false;
     }
 
+    @Override
+    public void choosePrivateKeyAlias(final int uid, final String host, int port, final String url,
+            final String alias, final IBinder response) {
+        // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
+        if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+            return;
+        }
+
+        final UserHandle caller = Binder.getCallingUserHandle();
+        final ComponentName profileOwner = getProfileOwner(caller.getIdentifier());
+
+        if (profileOwner == null) {
+            sendPrivateKeyAliasResponse(null, response);
+            return;
+        }
+
+        Intent intent = new Intent(DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS);
+        intent.setComponent(profileOwner);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, uid);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_HOST, host);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_PORT, port);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URL, url);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias);
+        intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response);
+
+        final long id = Binder.clearCallingIdentity();
+        try {
+            mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final String chosenAlias = getResultData();
+                    sendPrivateKeyAliasResponse(chosenAlias, response);
+                }
+            }, null, Activity.RESULT_OK, null, null);
+        } finally {
+            Binder.restoreCallingIdentity(id);
+        }
+    }
+
+    private void sendPrivateKeyAliasResponse(final String alias, final IBinder responseBinder) {
+        final IKeyChainAliasCallback keyChainAliasResponse =
+                IKeyChainAliasCallback.Stub.asInterface(responseBinder);
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                try {
+                    keyChainAliasResponse.alias(alias);
+                } catch (Exception e) {
+                    // Catch everything (not just RemoteException): caller could throw a
+                    // RuntimeException back across processes.
+                    Log.e(LOG_TAG, "error while responding to callback", e);
+                }
+                return null;
+            }
+        }.execute();
+    }
+
     private void wipeDataLocked(boolean wipeExtRequested, String reason) {
         // If the SD card is encrypted and non-removable, we have to force a wipe.
         boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
@@ -3233,15 +3288,12 @@
     }
 
     public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
-            String exclusionList, int userHandle) {
+            String exclusionList) {
         if (!mHasFeature) {
             return null;
         }
-        enforceCrossUserPermission(userHandle);
         synchronized(this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
+            Preconditions.checkNotNull(who, "ComponentName is null");
 
             // Only check if owner has set global proxy. We don't allow other users to set it.
             DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -3263,7 +3315,7 @@
             // If the user is not the owner, don't set the global proxy. Fail silently.
             if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
                 Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
-                        + userHandle + " is not permitted.");
+                        + UserHandle.getCallingUserId() + " is not permitted.");
                 return null;
             }
             if (proxySpec == null) {
@@ -3373,16 +3425,14 @@
      * Set the storage encryption request for a single admin.  Returns the new total request
      * status (for all admins).
      */
-    public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
+    public int setStorageEncryption(ComponentName who, boolean encrypt) {
         if (!mHasFeature) {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Only owner can set storage encryption
             if (userHandle != UserHandle.USER_OWNER
                     || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
@@ -3509,15 +3559,13 @@
     /**
      * Set whether the screen capture is disabled for the user managed by the specified admin.
      */
-    public void setScreenCaptureDisabled(ComponentName who, int userHandle, boolean disabled) {
+    public void setScreenCaptureDisabled(ComponentName who, boolean disabled) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (ap.disableScreenCapture != disabled) {
@@ -3568,15 +3616,13 @@
     /**
      * Set whether auto time is required by the specified admin (must be device owner).
      */
-    public void setAutoTimeRequired(ComponentName who, int userHandle, boolean required) {
+    public void setAutoTimeRequired(ComponentName who, boolean required) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             if (admin.requireAutoTime != required) {
@@ -3612,22 +3658,21 @@
 
     /**
      * The system property used to share the state of the camera. The native camera service
-     * is expected to read this property and act accordingly.
+     * is expected to read this property and act accordingly. The userId should be appended
+     * to this key.
      */
-    public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
+    public static final String SYSTEM_PROP_DISABLE_CAMERA_PREFIX = "sys.secpolicy.camera.off_";
 
     /**
      * Disables all device cameras according to the specified admin.
      */
-    public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
+    public void setCameraDisabled(ComponentName who, boolean disabled) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
             if (ap.disableCamera != disabled) {
@@ -3668,16 +3713,14 @@
     /**
      * Selectively disable keyguard features.
      */
-    public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
+    public void setKeyguardDisabledFeatures(ComponentName who, int which) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "disable keyguard features");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             if (ap.disabledKeyguardFeatures != which) {
@@ -3821,9 +3864,7 @@
 
     @Override
     public void clearDeviceOwner(String packageName) {
-        if (packageName == null) {
-            throw new NullPointerException("packageName is null");
-        }
+        Preconditions.checkNotNull(packageName, "packageName is null");
         try {
             int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
             if (uid != Binder.getCallingUid()) {
@@ -3850,6 +3891,110 @@
     }
 
     @Override
+    public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
+            String ownerName) {
+        if (!mHasFeature) {
+            return false;
+        }
+        if (initializer == null || !DeviceOwner.isInstalled(
+                initializer.getPackageName(), mContext.getPackageManager())) {
+            throw new IllegalArgumentException("Invalid component name " + initializer
+                    + " for device initializer");
+        }
+        synchronized (this) {
+            enforceCanSetDeviceInitializer(who);
+
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+                throw new IllegalStateException(
+                        "Trying to set device initializer but device initializer is already set.");
+            }
+
+            if (mDeviceOwner == null) {
+                // Device owner state does not exist, create it.
+                mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
+                        initializer.getPackageName(), ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                // Device owner already exists, update it.
+                mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            }
+        }
+    }
+
+    private void enforceCanSetDeviceInitializer(ComponentName who) {
+        if (who == null) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
+            if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+                throw new IllegalStateException(
+                        "Trying to set device initializer but device is already provisioned.");
+            }
+        } else {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+    }
+
+    @Override
+    public boolean isDeviceInitializer(String packageName) {
+        if (!mHasFeature) {
+            return false;
+        }
+        synchronized (this) {
+            return mDeviceOwner != null
+                    && mDeviceOwner.hasDeviceInitializer()
+                    && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+        }
+    }
+
+    @Override
+    public String getDeviceInitializer() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+                return mDeviceOwner.getDeviceInitializerPackageName();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void clearDeviceInitializer(ComponentName who) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+
+        ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
+
+        if (admin.getUid() != Binder.getCallingUid()) {
+            throw new SecurityException("Admin " + who + " is not owned by uid "
+                    + Binder.getCallingUid());
+        }
+
+        if (!isDeviceInitializer(admin.info.getPackageName())
+                && !isDeviceOwner(admin.info.getPackageName())) {
+            throw new SecurityException(
+                    "clearDeviceInitializer can only be called by the device initializer/owner");
+        }
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                if (mDeviceOwner != null) {
+                    mDeviceOwner.clearDeviceInitializer();
+                    mDeviceOwner.writeOwnerFile();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
         if (!mHasFeature) {
             return false;
@@ -3922,7 +4067,7 @@
         Bundle userRestrictions = mUserManager.getUserRestrictions();
         mUserManager.setUserRestrictions(new Bundle(), userHandle);
         if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
-            audioManager.setMasterMute(false);
+            audioManager.setMasterMute(false, 0);
         }
         if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
             audioManager.setMicrophoneMute(false);
@@ -3944,16 +4089,58 @@
     }
 
     @Override
+    public boolean setUserEnabled(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            int userId = UserHandle.getCallingUserId();
+
+            ActiveAdmin activeAdmin =
+                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
+                throw new SecurityException(
+                        "This method can only be called by device initializers");
+            }
+
+            long id = Binder.clearCallingIdentity();
+            try {
+                if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
+                    IPackageManager ipm = AppGlobals.getPackageManager();
+                    ipm.setComponentEnabledSetting(who,
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                            PackageManager.DONT_KILL_APP, userId);
+
+                    removeActiveAdmin(who, userId);
+                }
+
+                if (userId == UserHandle.USER_OWNER) {
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.DEVICE_PROVISIONED, 1);
+                }
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.USER_SETUP_COMPLETE, 1, userId);
+            } catch (RemoteException e) {
+                Log.i(LOG_TAG, "Can't talk to package manager", e);
+                return false;
+            } finally {
+                restoreCallingIdentity(id);
+            }
+            return true;
+        }
+    }
+
+    @Override
     public void setProfileEnabled(ComponentName who) {
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Check if this is the profile owner who is calling
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             int userId = UserHandle.getCallingUserId();
@@ -3975,12 +4162,8 @@
 
     @Override
     public void setProfileName(ComponentName who, String profileName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int userId = UserHandle.getCallingUserId();
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
-
         // Check if this is the profile owner (includes device owner).
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -4042,16 +4225,18 @@
     }
 
     /**
-     * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in
-     * which case we allow it if no account is associated with the device.
+     * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
+     * we also allow it if no accounts or additional users are present on the device.
      */
     private boolean allowedToSetDeviceOwnerOnDevice() {
-        int callingId = Binder.getCallingUid();
-        if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
-            return AccountManager.get(mContext).getAccounts().length == 0;
-        } else {
-            return !hasUserSetupCompleted(UserHandle.USER_OWNER);
+        if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+            return true;
         }
+
+        int callingId = Binder.getCallingUid();
+        return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
+                && mUserManager.getUserCount() == 1
+                && AccountManager.get(mContext).getAccounts().length == 0;
     }
 
     private void enforceCrossUserPermission(int userHandle) {
@@ -4128,7 +4313,9 @@
 
         synchronized (this) {
             p.println("Current Device Policy Manager state:");
-
+            if (mDeviceOwner != null) {
+                mDeviceOwner.dump("  ", pw);
+            }
             int userCount = mUserData.size();
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -4156,12 +4343,9 @@
     @Override
     public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4178,12 +4362,9 @@
 
     @Override
     public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4200,12 +4381,9 @@
 
     @Override
     public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4218,19 +4396,15 @@
     }
 
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
-            PersistableBundle args, int userHandle) {
+            PersistableBundle args) {
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        Preconditions.checkNotNull(admin, "admin is null");
+        Preconditions.checkNotNull(agent, "agent is null");
+        final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "set trust agent configuration");
         synchronized (this) {
-            if (admin == null) {
-                throw new NullPointerException("admin is null");
-            }
-            if (agent == null) {
-                throw new NullPointerException("agent is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args));
@@ -4244,10 +4418,8 @@
         if (!mHasFeature) {
             return null;
         }
+        Preconditions.checkNotNull(agent, "agent null");
         enforceCrossUserPermission(userHandle);
-        if (agent == null) {
-            throw new NullPointerException("agent is null");
-        }
 
         synchronized (this) {
             final String componentName = agent.flattenToString();
@@ -4300,10 +4472,8 @@
 
     @Override
     public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userHandle = UserHandle.getCallingUserId();
@@ -4325,11 +4495,9 @@
     }
 
     public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4352,11 +4520,9 @@
     }
 
     public void clearCrossProfileIntentFilters(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
@@ -4397,8 +4563,7 @@
                 try {
                     ApplicationInfo applicationInfo = pm.getApplicationInfo(enabledPackage,
                             PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
-                    systemService = (applicationInfo.flags
-                            & ApplicationInfo.FLAG_SYSTEM) != 0;
+                    systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 } catch (RemoteException e) {
                     Log.i(LOG_TAG, "Can't talk to package managed", e);
                 }
@@ -4427,9 +4592,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         if (packageList != null) {
             int userId = UserHandle.getCallingUserId();
@@ -4474,10 +4637,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4532,15 +4692,10 @@
                     IPackageManager pm = AppGlobals.getPackageManager();
                     if (installedServices != null) {
                         for (AccessibilityServiceInfo service : installedServices) {
-                            String packageName = service.getResolveInfo().serviceInfo.packageName;
-                            try {
-                                ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName,
-                                        PackageManager.GET_UNINSTALLED_PACKAGES, userId);
-                                if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                                    result.add(packageName);
-                                }
-                            } catch (RemoteException e) {
-                                Log.i(LOG_TAG, "Accessibility service in missing package", e);
+                            ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
+                            ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+                            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                                result.add(serviceInfo.packageName);
                             }
                         }
                     }
@@ -4587,9 +4742,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         // TODO When InputMethodManager supports per user calls remove
         //      this restriction.
@@ -4632,10 +4785,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4691,16 +4841,10 @@
                     IPackageManager pm = AppGlobals.getPackageManager();
                     if (imes != null) {
                         for (InputMethodInfo ime : imes) {
-                            String packageName = ime.getPackageName();
-                            try {
-                                ApplicationInfo applicationInfo = pm.getApplicationInfo(
-                                        packageName, PackageManager.GET_UNINSTALLED_PACKAGES,
-                                        userId);
-                                if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                                    result.add(packageName);
-                                }
-                            } catch (RemoteException e) {
-                                Log.i(LOG_TAG, "Input method for missing package", e);
+                            ServiceInfo serviceInfo = ime.getServiceInfo();
+                            ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+                            if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                                result.add(serviceInfo.packageName);
                             }
                         }
                     }
@@ -4714,10 +4858,8 @@
 
     @Override
     public UserHandle createUser(ComponentName who, String name) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4768,10 +4910,8 @@
 
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4785,10 +4925,8 @@
 
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4809,12 +4947,10 @@
 
     @Override
     public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4828,12 +4964,10 @@
 
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
         final int userHandle = user.getIdentifier();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName());
@@ -4841,6 +4975,9 @@
                     && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
                 throw new SecurityException("Profile owners cannot set user restriction " + key);
             }
+            if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
+                throw new SecurityException("User restriction " + key + " cannot be changed");
+            }
             boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
 
             IAudioService iAudioService = null;
@@ -4855,7 +4992,7 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(true, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(true, 0, who.getPackageName(), null);
+                        iAudioService.setMasterMute(true, 0, who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -4920,7 +5057,7 @@
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
                         iAudioService.setMicrophoneMute(false, who.getPackageName());
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(false, 0, who.getPackageName(), null);
+                        iAudioService.setMasterMute(false, 0, who.getPackageName());
                     }
                 } catch (RemoteException re) {
                     Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
@@ -4933,11 +5070,9 @@
     @Override
     public boolean setApplicationHidden(ComponentName who, String packageName,
             boolean hidden) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4956,11 +5091,9 @@
 
     @Override
     public boolean isApplicationHidden(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4979,11 +5112,8 @@
 
     @Override
     public void enableSystemApp(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5024,11 +5154,8 @@
 
     @Override
     public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5056,15 +5183,14 @@
                 if (activitiesToEnable != null) {
                     for (ResolveInfo info : activitiesToEnable) {
                         if (info.activityInfo != null) {
-
-                            if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
-                                throw new IllegalArgumentException(
-                                        "Only system apps can be enabled this way.");
+                            String packageName = info.activityInfo.packageName;
+                            if (isSystemApp(pm, packageName, primaryUser.id)) {
+                                numberOfAppsInstalled++;
+                                pm.installExistingPackageAsUser(packageName, userId);
+                            } else {
+                                Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+                                        + " system app");
                             }
-
-
-                            numberOfAppsInstalled++;
-                            pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
                         }
                     }
                 }
@@ -5083,7 +5209,11 @@
             throws RemoteException {
         ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
                 userId);
-        return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
+        if (appInfo == null) {
+            throw new IllegalArgumentException("The application " + packageName +
+                    " is not present on this device");
+        }
+        return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
     @Override
@@ -5092,10 +5222,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (disabled) {
@@ -5133,12 +5261,9 @@
     @Override
     public void setUninstallBlocked(ComponentName who, String packageName,
             boolean uninstallBlocked) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userId = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5185,10 +5310,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (admin.disableCallerId != disabled) {
@@ -5203,12 +5326,8 @@
         if (!mHasFeature) {
             return false;
         }
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             return admin.disableCallerId;
@@ -5229,13 +5348,11 @@
      * Sets which packages may enter lock task mode.
      *
      * This function can only be called by the device owner.
-     * @param components The list of components allowed to enter lock task mode.
+     * @param packages The list of packages allowed to enter lock task mode.
      */
     public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
@@ -5257,15 +5374,13 @@
      * This function returns the list of components allowed to start the task lock mode.
      */
     public String[] getLockTaskPackages(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
             DevicePolicyData policy = getUserData(userHandle);
-            return policy.mLockTaskPackages.toArray(new String[0]);
+            return policy.mLockTaskPackages.toArray(new String[policy.mLockTaskPackages.size()]);
         }
     }
 
@@ -5321,16 +5436,27 @@
     @Override
     public void setGlobalSetting(ComponentName who, String setting, String value) {
         final ContentResolver contentResolver = mContext.getContentResolver();
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
-                throw new SecurityException(String.format(
-                        "Permission denial: device owners cannot update %1$s", setting));
+                // BLUETOOTH_ON and WIFI_ON used to be supported but not any more. We do not want to
+                // throw a SecurityException not to break apps.
+                if (!Settings.Global.BLUETOOTH_ON.equals(setting)
+                        && !Settings.Global.WIFI_ON.equals(setting)) {
+                    throw new SecurityException(String.format(
+                            "Permission denial: device owners cannot update %1$s", setting));
+                }
+            }
+
+            if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
+                // ignore if it contradicts an existing policy
+                long timeMs = getMaximumTimeToLock(who, UserHandle.getCallingUserId());
+                if (timeMs > 0 && timeMs < Integer.MAX_VALUE) {
+                    return;
+                }
             }
 
             long id = Binder.clearCallingIdentity();
@@ -5344,13 +5470,11 @@
 
     @Override
     public void setSecureSetting(ComponentName who, String setting, String value) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         final ContentResolver contentResolver = mContext.getContentResolver();
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -5375,18 +5499,14 @@
 
     @Override
     public void setMasterVolumeMuted(ComponentName who, boolean on) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IAudioService iAudioService = IAudioService.Stub.asInterface(
                     ServiceManager.getService(Context.AUDIO_SERVICE));
-            try{
-                iAudioService.setMasterMute(on, 0, who.getPackageName(), null);
+            try {
+                iAudioService.setMasterMute(on, 0, who.getPackageName());
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Failed to setMasterMute", re);
             }
@@ -5395,12 +5515,8 @@
 
     @Override
     public boolean isMasterVolumeMuted(ComponentName who) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             AudioManager audioManager =
@@ -5409,6 +5525,22 @@
         }
     }
 
+    @Override
+    public void setUserIcon(ComponentName who, Bitmap icon) {
+        synchronized (this) {
+            Preconditions.checkNotNull(who, "ComponentName is null");
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+            int userId = UserHandle.getCallingUserId();
+            long id = Binder.clearCallingIdentity();
+            try {
+                mUserManager.setUserIcon(userId, icon);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+    }
+
     /**
      * We need to update the internal state of whether a user has completed setup once. After
      * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
@@ -5508,4 +5640,15 @@
             }
         }
     }
+
+    /**
+     * Returns true if specified admin is allowed to limit passwords and has a
+     * {@code passwordQuality} of at least {@code minPasswordQuality}
+     */
+    private static boolean isLimitPasswordAllowed(ActiveAdmin admin, int minPasswordQuality) {
+        if (admin.passwordQuality < minPasswordQuality) {
+            return false;
+        }
+        return admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0705fbd..a0c7f86 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -26,16 +26,11 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.media.AudioService;
-import android.media.tv.TvInputManager;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
-import android.os.Handler;
-import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -44,22 +39,19 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.service.dreams.DreamService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 import android.webkit.WebViewFactory;
 
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
-import com.android.internal.os.Zygote;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
-import com.android.server.am.BatteryStatsService;
+import com.android.server.audio.AudioService;
 import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -69,11 +61,11 @@
 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;
 import com.android.server.media.MediaSessionService;
 import com.android.server.media.projection.MediaProjectionManagerService;
+import com.android.server.MidiService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
@@ -410,6 +402,8 @@
         ConsumerIrService consumerIr = null;
         AudioService audioService = null;
         MmsServiceBroker mmsService = null;
+        EntropyMixer entropyMixer = null;
+        MidiService midiService = null;
 
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
@@ -436,7 +430,7 @@
             ServiceManager.addService("telephony.registry", telephonyRegistry);
 
             Slog.i(TAG, "Entropy Mixer");
-            ServiceManager.addService("entropy", new EntropyMixer(context));
+            entropyMixer = new EntropyMixer(context);
 
             mContentResolver = context.getContentResolver();
 
@@ -523,26 +517,24 @@
         LockSettingsService lockSettings = null;
         AssetAtlasService atlas = null;
         MediaRouterService mediaRouter = null;
+        MidiService midi = null;
 
         // Bring up services needed for UI.
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-            //if (!disableNonCoreServices) { // TODO: View depends on these; mock them?
-            if (true) {
-                try {
-                    Slog.i(TAG, "Input Method Service");
-                    imm = new InputMethodManagerService(context, wm);
-                    ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
-                } catch (Throwable e) {
-                    reportWtf("starting Input Manager Service", e);
-                }
+            try {
+                Slog.i(TAG, "Input Method Service");
+                imm = new InputMethodManagerService(context, wm);
+                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
+            } catch (Throwable e) {
+                reportWtf("starting Input Manager Service", e);
+            }
 
-                try {
-                    Slog.i(TAG, "Accessibility Manager");
-                    ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
-                            new AccessibilityManagerService(context));
-                } catch (Throwable e) {
-                    reportWtf("starting Accessibility Manager", e);
-                }
+            try {
+                Slog.i(TAG, "Accessibility Manager");
+                ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
+                        new AccessibilityManagerService(context));
+            } catch (Throwable e) {
+                reportWtf("starting Accessibility Manager", e);
             }
         }
 
@@ -833,6 +825,16 @@
                 }
             }
 
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "MIDI Service");
+                    ServiceManager.addService(Context.MIDI_SERVICE,
+                            new MidiService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting MIDI Service", e);
+                }
+            }
+
             mSystemServiceManager.startService(TwilightService.class);
 
             mSystemServiceManager.startService(UiModeManagerService.class);
diff --git a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
index 218f899..946d28e 100644
--- a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
+++ b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
@@ -16,35 +16,20 @@
 
 package com.android.server.restrictions;
 
-import android.Manifest;
-import android.accounts.IAccountAuthenticator;
 import android.app.AppGlobals;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.app.admin.IDevicePolicyManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.IRestrictionsManager;
 import android.content.RestrictionsManager;
-import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.PersistableBundle;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index beb353a..c198900 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -20,7 +20,6 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isA;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
index 8e8e4e6..ca270e7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
@@ -65,7 +65,7 @@
         sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.USER_SETUP_COMPLETE, 0);
-        sDpm.setProfileOwner(context.getPackageName(), "Test", UserHandle.myUserId());
+        sDpm.setProfileOwner(sAdminReceiver, "Test", UserHandle.myUserId());
         Settings.Secure.putInt(context.getContentResolver(),
                 Settings.Secure.USER_SETUP_COMPLETE, 1);
         // Remove the admin if already registered. It's async, so add it back
@@ -132,4 +132,4 @@
         Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
         assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText);
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
index f913b97..7c3014c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.devicepolicy;
 
+import android.content.ComponentName;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -32,7 +33,7 @@
 public class DeviceOwnerTest extends AndroidTestCase {
 
     private ByteArrayInputStream mInputStreamForTest;
-    private ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
+    private final ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
 
     @SmallTest
     public void testDeviceOwnerOnly() throws Exception {
@@ -46,13 +47,15 @@
 
         assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
         assertEquals("owner", in.getDeviceOwnerName());
-        assertNull(in.getProfileOwnerPackageName(1));
+        assertNull(in.getProfileOwnerComponent(1));
     }
 
     @SmallTest
     public void testProfileOwnerOnly() throws Exception {
         DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
-        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
+        ComponentName admin = new ComponentName(
+            "some.profile.owner.package", "some.profile.owner.package.Class");
+        out.setProfileOwner(admin, "some-company", 1);
         out.writeOwnerFile();
 
         mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
@@ -61,16 +64,24 @@
 
         assertNull(in.getDeviceOwnerPackageName());
         assertNull(in.getDeviceOwnerName());
-        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals(admin, in.getProfileOwnerComponent(1));
         assertEquals("some-company", in.getProfileOwnerName(1));
     }
 
     @SmallTest
     public void testDeviceAndProfileOwners() throws Exception {
         DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
+        ComponentName profileAdmin = new ComponentName(
+            "some.profile.owner.package", "some.profile.owner.package.Class");
+        ComponentName otherProfileAdmin = new ComponentName(
+            "some.other.profile.owner", "some.other.profile.owner.OtherClass");
+        // Old code used package name rather than component name, so the class
+        // bit could be empty.
+        ComponentName legacyComponentName = new ComponentName("legacy.profile.owner.package", "");
         out.setDeviceOwner("some.device.owner.package", "owner");
-        out.setProfileOwner("some.profile.owner.package", "some-company", 1);
-        out.setProfileOwner("some.other.profile.owner", "some-other-company", 2);
+        out.setProfileOwner(profileAdmin, "some-company", 1);
+        out.setProfileOwner(otherProfileAdmin, "some-other-company", 2);
+        out.setProfileOwner(legacyComponentName, "legacy-company", 3);
         out.writeOwnerFile();
 
         mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
@@ -80,9 +91,10 @@
 
         assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
         assertEquals("owner", in.getDeviceOwnerName());
-        assertEquals("some.profile.owner.package", in.getProfileOwnerPackageName(1));
+        assertEquals(profileAdmin, in.getProfileOwnerComponent(1));
         assertEquals("some-company", in.getProfileOwnerName(1));
-        assertEquals("some.other.profile.owner", in.getProfileOwnerPackageName(2));
+        assertEquals(otherProfileAdmin, in.getProfileOwnerComponent(2));
         assertEquals("some-other-company", in.getProfileOwnerName(2));
+        assertEquals(legacyComponentName, in.getProfileOwnerComponent(3));
     }
-}
\ No newline at end of file
+}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 5f639ab..869d6e1 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -81,6 +81,17 @@
         return event;
     }
 
+    private boolean isStatefulEvent(int eventType) {
+        switch (eventType) {
+            case UsageEvents.Event.MOVE_TO_FOREGROUND:
+            case UsageEvents.Event.MOVE_TO_BACKGROUND:
+            case UsageEvents.Event.END_OF_DAY:
+            case UsageEvents.Event.CONTINUE_PREVIOUS_DAY:
+                return true;
+        }
+        return false;
+    }
+
     void update(String packageName, long timeStamp, int eventType) {
         UsageStats usageStats = getOrCreateUsageStats(packageName);
 
@@ -93,7 +104,11 @@
                 usageStats.mTotalTimeInForeground += timeStamp - usageStats.mLastTimeUsed;
             }
         }
-        usageStats.mLastEvent = eventType;
+
+        if (isStatefulEvent(eventType)) {
+            usageStats.mLastEvent = eventType;
+        }
+
         usageStats.mLastTimeUsed = timeStamp;
         usageStats.mEndTimeStamp = timeStamp;
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 26ced03..235567c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -378,26 +378,27 @@
                 }
             }
 
-            try {
-                IntervalStats stats = new IntervalStats();
-                ArrayList<T> results = new ArrayList<>();
-                for (int i = startIndex; i <= endIndex; i++) {
-                    final AtomicFile f = intervalStats.valueAt(i);
+            final IntervalStats stats = new IntervalStats();
+            final ArrayList<T> results = new ArrayList<>();
+            for (int i = startIndex; i <= endIndex; i++) {
+                final AtomicFile f = intervalStats.valueAt(i);
 
-                    if (DEBUG) {
-                        Slog.d(TAG, "Reading stat file " + f.getBaseFile().getAbsolutePath());
-                    }
+                if (DEBUG) {
+                    Slog.d(TAG, "Reading stat file " + f.getBaseFile().getAbsolutePath());
+                }
 
+                try {
                     UsageStatsXml.read(f, stats);
                     if (beginTime < stats.endTime) {
                         combiner.combine(stats, false, results);
                     }
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to read usage stats file", e);
+                    // We continue so that we return results that are not
+                    // corrupt.
                 }
-                return results;
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to read usage stats file", e);
-                return null;
             }
+            return results;
         }
     }
 
@@ -450,6 +451,10 @@
             mCal.addDays(-7);
             pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_DAILY],
                     mCal.getTimeInMillis());
+
+            // We must re-index our file list or we will be trying to read
+            // deleted files.
+            indexFilesLocked();
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 485b2a2..5eefe6a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -488,6 +488,23 @@
         }
 
         @Override
+        public void reportEvent(String packageName, int userId, int eventType) {
+            if (packageName == null) {
+                Slog.w(TAG, "Event reported without a package name");
+                return;
+            }
+
+            UsageEvents.Event event = new UsageEvents.Event();
+            event.mPackage = packageName;
+
+            // This will later be converted to system time.
+            event.mTimeStamp = SystemClock.elapsedRealtime();
+
+            event.mEventType = eventType;
+            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+        }
+
+        @Override
         public void reportConfigurationChange(Configuration config, int userId) {
             if (config == null) {
                 Slog.w(TAG, "Configuration event reported with a null config");
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index ef95a7b..bfb71c5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -191,7 +191,7 @@
             statsOut.events.clear();
         }
 
-        statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
+        statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
 
         int eventCode;
         int outerDepth = parser.getDepth();
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 6596781..75fa030 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -570,6 +570,8 @@
                 return "CONTINUE_PREVIOUS_DAY";
             case UsageEvents.Event.CONFIGURATION_CHANGE:
                 return "CONFIGURATION_CHANGE";
+            case UsageEvents.Event.INTERACTION:
+                return "INTERACTION";
             default:
                 return "UNKNOWN";
         }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
new file mode 100644
index 0000000..23e1970
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -0,0 +1,523 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbInterface;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.media.midi.MidiDeviceInfo;
+import android.os.FileObserver;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.alsa.AlsaCardsParser;
+import com.android.internal.alsa.AlsaDevicesParser;
+import com.android.server.audio.AudioService;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+/**
+ * UsbAlsaManager manages USB audio and MIDI devices.
+ */
+public final class UsbAlsaManager {
+    private static final String TAG = UsbAlsaManager.class.getSimpleName();
+    private static final boolean DEBUG = true;
+
+    private static final String ALSA_DIRECTORY = "/dev/snd/";
+
+    private final Context mContext;
+    private IAudioService mAudioService;
+
+    private final AlsaCardsParser mCardsParser = new AlsaCardsParser();
+    private final AlsaDevicesParser mDevicesParser = new AlsaDevicesParser();
+
+    // this is needed to map USB devices to ALSA Audio Devices, especially to remove an
+    // ALSA device when we are notified that its associated USB device has been removed.
+
+    private final HashMap<UsbDevice,UsbAudioDevice>
+        mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();
+
+    private final HashMap<UsbDevice,UsbMidiDevice>
+        mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();
+
+    private final HashMap<String,AlsaDevice>
+        mAlsaDevices = new HashMap<String,AlsaDevice>();
+
+    private UsbAudioDevice mAccessoryAudioDevice = null;
+
+    // UsbMidiDevice for USB peripheral mode (gadget) device
+    private UsbMidiDevice mPeripheralMidiDevice = null;
+
+    private final class AlsaDevice {
+        public static final int TYPE_UNKNOWN = 0;
+        public static final int TYPE_PLAYBACK = 1;
+        public static final int TYPE_CAPTURE = 2;
+        public static final int TYPE_MIDI = 3;
+
+        public int mCard;
+        public int mDevice;
+        public int mType;
+
+        public AlsaDevice(int type, int card, int device) {
+            mType = type;
+            mCard = card;
+            mDevice = device;
+        }
+
+        public boolean equals(Object obj) {
+            if (! (obj instanceof AlsaDevice)) {
+                return false;
+            }
+            AlsaDevice other = (AlsaDevice)obj;
+            return (mType == other.mType && mCard == other.mCard && mDevice == other.mDevice);
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("AlsaDevice: [card: " + mCard);
+            sb.append(", device: " + mDevice);
+            sb.append(", type: " + mType);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+    private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,
+            FileObserver.CREATE | FileObserver.DELETE) {
+        public void onEvent(int event, String path) {
+            switch (event) {
+                case FileObserver.CREATE:
+                    alsaFileAdded(path);
+                    break;
+                case FileObserver.DELETE:
+                    alsaFileRemoved(path);
+                    break;
+            }
+        }
+    };
+
+    /* package */ UsbAlsaManager(Context context) {
+        mContext = context;
+
+        // initial scan
+        mCardsParser.scan();
+    }
+
+    public void systemReady() {
+        mAudioService = IAudioService.Stub.asInterface(
+                        ServiceManager.getService(Context.AUDIO_SERVICE));
+
+        mAlsaObserver.startWatching();
+
+        // add existing alsa devices
+        File[] files = new File(ALSA_DIRECTORY).listFiles();
+        for (int i = 0; i < files.length; i++) {
+            alsaFileAdded(files[i].getName());
+        }
+    }
+
+    // Notifies AudioService when a device is added or removed
+    // audioDevice - the AudioDevice that was added or removed
+    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
+    private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
+        }
+
+        if (mAudioService == null) {
+            Slog.e(TAG, "no AudioService");
+            return;
+        }
+
+        // FIXME Does not yet handle the case where the setting is changed
+        // after device connection.  Ideally we should handle the settings change
+        // in SettingsObserver. Here we should log that a USB device is connected
+        // and disconnected with its address (card , device) and force the
+        // connection or disconnection when the setting changes.
+        int isDisabled = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
+        if (isDisabled != 0) {
+            return;
+        }
+
+        int state = (enabled ? 1 : 0);
+        int alsaCard = audioDevice.mCard;
+        int alsaDevice = audioDevice.mDevice;
+        if (alsaCard < 0 || alsaDevice < 0) {
+            Slog.e(TAG, "Invalid alsa card or device alsaCard: " + alsaCard +
+                        " alsaDevice: " + alsaDevice);
+            return;
+        }
+
+        String address = AudioService.makeAlsaAddressString(alsaCard, alsaDevice);
+        try {
+            // Playback Device
+            if (audioDevice.mHasPlayback) {
+                int device = (audioDevice == mAccessoryAudioDevice ?
+                        AudioSystem.DEVICE_OUT_USB_ACCESSORY :
+                        AudioSystem.DEVICE_OUT_USB_DEVICE);
+                if (DEBUG) {
+                    Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
+                            " addr:" + address + " name:" + audioDevice.mDeviceName);
+                }
+                mAudioService.setWiredDeviceConnectionState(
+                        device, state, address, audioDevice.mDeviceName, TAG);
+            }
+
+            // Capture Device
+            if (audioDevice.mHasCapture) {
+               int device = (audioDevice == mAccessoryAudioDevice ?
+                        AudioSystem.DEVICE_IN_USB_ACCESSORY :
+                        AudioSystem.DEVICE_IN_USB_DEVICE);
+                mAudioService.setWiredDeviceConnectionState(
+                        device, state, address, audioDevice.mDeviceName, TAG);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException in setWiredDeviceConnectionState");
+        }
+    }
+
+    private AlsaDevice waitForAlsaDevice(int card, int device, int type) {
+        AlsaDevice testDevice = new AlsaDevice(type, card, device);
+
+        // This value was empirically determined.
+        final int kWaitTime = 2500; // ms
+
+        synchronized(mAlsaDevices) {
+            long timeout = SystemClock.elapsedRealtime() + kWaitTime;
+            do {
+                if (mAlsaDevices.values().contains(testDevice)) {
+                    return testDevice;
+                }
+                long waitTime = timeout - SystemClock.elapsedRealtime();
+                if (waitTime > 0) {
+                    try {
+                        mAlsaDevices.wait(waitTime);
+                    } catch (InterruptedException e) {
+                        Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
+                    }
+                }
+            } while (timeout > SystemClock.elapsedRealtime());
+        }
+
+        Slog.e(TAG, "waitForAlsaDevice failed for " + testDevice);
+        return null;
+    }
+
+    private void alsaFileAdded(String name) {
+        int type = AlsaDevice.TYPE_UNKNOWN;
+        int card = -1, device = -1;
+
+        if (name.startsWith("pcmC")) {
+            if (name.endsWith("p")) {
+                type = AlsaDevice.TYPE_PLAYBACK;
+            } else if (name.endsWith("c")) {
+                type = AlsaDevice.TYPE_CAPTURE;
+            }
+        } else if (name.startsWith("midiC")) {
+            type = AlsaDevice.TYPE_MIDI;
+        }
+
+        if (type != AlsaDevice.TYPE_UNKNOWN) {
+            try {
+                int c_index = name.indexOf('C');
+                int d_index = name.indexOf('D');
+                int end = name.length();
+                if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {
+                    // skip trailing 'p' or 'c'
+                    end--;
+                }
+                card = Integer.parseInt(name.substring(c_index + 1, d_index));
+                device = Integer.parseInt(name.substring(d_index + 1, end));
+            } catch (Exception e) {
+                Slog.e(TAG, "Could not parse ALSA file name " + name, e);
+                return;
+            }
+            synchronized(mAlsaDevices) {
+                if (mAlsaDevices.get(name) == null) {
+                    AlsaDevice alsaDevice = new AlsaDevice(type, card, device);
+                    Slog.d(TAG, "Adding ALSA device " + alsaDevice);
+                    mAlsaDevices.put(name, alsaDevice);
+                    mAlsaDevices.notifyAll();
+                }
+            }
+        }
+    }
+
+    private void alsaFileRemoved(String path) {
+        synchronized(mAlsaDevices) {
+            AlsaDevice device = mAlsaDevices.remove(path);
+            if (device != null) {
+                Slog.d(TAG, "ALSA device removed: " + device);
+            }
+        }
+    }
+
+    /*
+     * Select the default device of the specified card.
+     */
+    /* package */ UsbAudioDevice selectAudioCard(int card) {
+        if (DEBUG) {
+            Slog.d(TAG, "selectAudioCard() card:" + card);
+        }
+        if (!mCardsParser.isCardUsb(card)) {
+            // Don't. AudioPolicyManager has logic for falling back to internal devices.
+            return null;
+        }
+
+        mDevicesParser.scan();
+        int device = mDevicesParser.getDefaultDeviceNum(card);
+
+        boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card);
+        boolean hasCapture = mDevicesParser.hasCaptureDevices(card);
+        int deviceClass =
+            (mCardsParser.isCardUsb(card)
+                ? UsbAudioDevice.kAudioDeviceClass_External
+                : UsbAudioDevice.kAudioDeviceClass_Internal) |
+            UsbAudioDevice.kAudioDeviceMeta_Alsa;
+
+        // Playback device file needed/present?
+        if (hasPlayback && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_PLAYBACK) == null)) {
+            return null;
+        }
+
+        // Capture device file needed/present?
+        if (hasCapture && (waitForAlsaDevice(card, device, AlsaDevice.TYPE_CAPTURE) == null)) {
+            return null;
+        }
+
+        if (DEBUG) {
+            Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
+        }
+
+        UsbAudioDevice audioDevice =
+                new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
+        AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
+        audioDevice.mDeviceName = cardRecord.mCardName;
+        audioDevice.mDeviceDescription = cardRecord.mCardDescription;
+
+        notifyDeviceState(audioDevice, true);
+
+        return audioDevice;
+    }
+
+    /* package */ UsbAudioDevice selectDefaultDevice() {
+        if (DEBUG) {
+            Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
+        }
+        mCardsParser.scan();
+        return selectAudioCard(mCardsParser.getDefaultCard());
+    }
+
+    /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
+       if (DEBUG) {
+          Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
+                  "nm:" + usbDevice.getProductName());
+        }
+
+        // Is there an audio interface in there?
+        boolean isAudioDevice = false;
+
+        // FIXME - handle multiple configurations?
+        int interfaceCount = usbDevice.getInterfaceCount();
+        for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < interfaceCount;
+                ntrfaceIndex++) {
+            UsbInterface ntrface = usbDevice.getInterface(ntrfaceIndex);
+            if (ntrface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
+                isAudioDevice = true;
+            }
+        }
+        if (!isAudioDevice) {
+            return;
+        }
+
+        ArrayList<AlsaCardsParser.AlsaCardRecord> prevScanRecs = mCardsParser.getScanRecords();
+        mCardsParser.scan();
+
+        int addedCard = -1;
+        ArrayList<AlsaCardsParser.AlsaCardRecord>
+            newScanRecs = mCardsParser.getNewCardRecords(prevScanRecs);
+        if (newScanRecs.size() > 0) {
+            // This is where we select the just connected device
+            // NOTE - to switch to prefering the first-connected device, just always
+            // take the else clause below.
+            addedCard = newScanRecs.get(0).mCardNum;
+        } else {
+            addedCard = mCardsParser.getDefaultUsbCard();
+        }
+
+        // If the default isn't a USB device, let the existing "select internal mechanism"
+        // handle the selection.
+        if (mCardsParser.isCardUsb(addedCard)) {
+            UsbAudioDevice audioDevice = selectAudioCard(addedCard);
+            if (audioDevice != null) {
+                mAudioDevices.put(usbDevice, audioDevice);
+            }
+
+            // look for MIDI devices
+
+            // Don't need to call mDevicesParser.scan() because selectAudioCard() does this above.
+            // Uncomment this next line if that behavior changes in the fugure.
+            // mDevicesParser.scan()
+
+            boolean hasMidi = mDevicesParser.hasMIDIDevices(addedCard);
+            if (hasMidi) {
+                int device = mDevicesParser.getDefaultDeviceNum(addedCard);
+                AlsaDevice alsaDevice = waitForAlsaDevice(addedCard, device, AlsaDevice.TYPE_MIDI);
+                if (alsaDevice != null) {
+                    Bundle properties = new Bundle();
+                    String manufacturer = usbDevice.getManufacturerName();
+                    String product = usbDevice.getProductName();
+                    String name;
+                    if (manufacturer == null || manufacturer.isEmpty()) {
+                        name = product;
+                    } else if (product == null || product.isEmpty()) {
+                        name = manufacturer;
+                    } else {
+                        name = manufacturer + " " + product;
+                    }
+                    properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
+                    properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
+                    properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+                    properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+                            usbDevice.getSerialNumber());
+                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
+                    properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, alsaDevice.mDevice);
+                    properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+                    UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
+                            alsaDevice.mCard, alsaDevice.mDevice);
+                    if (usbMidiDevice != null) {
+                        mMidiDevices.put(usbDevice, usbMidiDevice);
+                    }
+                }
+            }
+        }
+    }
+
+    /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
+        if (DEBUG) {
+          Slog.d(TAG, "deviceRemoved(): " + usbDevice.getManufacturerName() +
+                  " " + usbDevice.getProductName());
+        }
+
+        UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
+        if (audioDevice != null) {
+            if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
+                notifyDeviceState(audioDevice, false);
+
+                // if there any external devices left, select one of them
+                selectDefaultDevice();
+            }
+        }
+        UsbMidiDevice usbMidiDevice = mMidiDevices.remove(usbDevice);
+        if (usbMidiDevice != null) {
+            IoUtils.closeQuietly(usbMidiDevice);
+        }
+    }
+
+   /* package */ void setAccessoryAudioState(boolean enabled, int card, int device) {
+       if (DEBUG) {
+            Slog.d(TAG, "setAccessoryAudioState " + enabled + " " + card + " " + device);
+        }
+        if (enabled) {
+            mAccessoryAudioDevice = new UsbAudioDevice(card, device, true, false,
+                    UsbAudioDevice.kAudioDeviceClass_External);
+            notifyDeviceState(mAccessoryAudioDevice, true);
+        } else if (mAccessoryAudioDevice != null) {
+            notifyDeviceState(mAccessoryAudioDevice, false);
+            mAccessoryAudioDevice = null;
+        }
+    }
+
+   /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
+        if (enabled) {
+            Bundle properties = new Bundle();
+            Resources r = mContext.getResources();
+            properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
+                    com.android.internal.R.string.usb_midi_peripheral_manufacturer_name));
+            properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, r.getString(
+                    com.android.internal.R.string.usb_midi_peripheral_model_name));
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
+            properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
+            mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
+        } else if (mPeripheralMidiDevice != null) {
+            IoUtils.closeQuietly(mPeripheralMidiDevice);
+            mPeripheralMidiDevice = null;
+        }
+   }
+
+    //
+    // Devices List
+    //
+    public ArrayList<UsbAudioDevice> getConnectedDevices() {
+        ArrayList<UsbAudioDevice> devices = new ArrayList<UsbAudioDevice>(mAudioDevices.size());
+        for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+            devices.add(entry.getValue());
+        }
+        return devices;
+    }
+
+    //
+    // Logging
+    //
+    public void dump(FileDescriptor fd, PrintWriter pw) {
+        pw.println("  USB Audio Devices:");
+        for (UsbDevice device : mAudioDevices.keySet()) {
+            pw.println("    " + device.getDeviceName() + ": " + mAudioDevices.get(device));
+        }
+        pw.println("  USB MIDI Devices:");
+        for (UsbDevice device : mMidiDevices.keySet()) {
+            pw.println("    " + device.getDeviceName() + ": " + mMidiDevices.get(device));
+        }
+    }
+
+    public void logDevicesList(String title) {
+      if (DEBUG) {
+          for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+              Slog.i(TAG, "UsbDevice-------------------");
+              Slog.i(TAG, "" + (entry != null ? entry.getKey() : "[none]"));
+              Slog.i(TAG, "UsbAudioDevice--------------");
+              Slog.i(TAG, "" + entry.getValue());
+          }
+      }
+  }
+
+  // This logs a more terse (and more readable) version of the devices list
+  public void logDevices(String title) {
+      if (DEBUG) {
+          Slog.i(TAG, title);
+          for (HashMap.Entry<UsbDevice,UsbAudioDevice> entry : mAudioDevices.entrySet()) {
+              Slog.i(TAG, entry.getValue().toShortString());
+          }
+      }
+  }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbAudioDevice.java b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
new file mode 100644
index 0000000..bdd28e4
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbAudioDevice.java
@@ -0,0 +1,66 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+public final class UsbAudioDevice {
+    private static final String TAG = "UsbAudioDevice";
+    protected static final boolean DEBUG = false;
+
+    public int mCard;
+    public int mDevice;
+    public boolean mHasPlayback;
+    public boolean mHasCapture;
+
+    // Device "class" flags
+    public static final int kAudioDeviceClassMask = 0x00FFFFFF;
+    public static final int kAudioDeviceClass_Undefined = 0x00000000;
+    public static final int kAudioDeviceClass_Internal = 0x00000001;
+    public static final int kAudioDeviceClass_External = 0x00000002;
+    // Device meta-data flags
+    public static final int kAudioDeviceMetaMask = 0xFF000000;
+    public static final int kAudioDeviceMeta_Alsa = 0x80000000;
+    // This member is a combination of the above bit-flags
+    public int mDeviceClass;
+
+    public String mDeviceName = "";
+    public String mDeviceDescription = "";
+
+    public UsbAudioDevice(int card, int device,
+            boolean hasPlayback, boolean hasCapture, int deviceClass) {
+        mCard = card;
+        mDevice = device;
+        mHasPlayback = hasPlayback;
+        mHasCapture = hasCapture;
+        mDeviceClass = deviceClass;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("UsbAudioDevice: [card: " + mCard);
+        sb.append(", device: " + mDevice);
+        sb.append(", name: " + mDeviceName);
+        sb.append(", hasPlayback: " + mHasPlayback);
+        sb.append(", hasCapture: " + mHasCapture);
+        sb.append(", class: 0x" + Integer.toHexString(mDeviceClass) + "]");
+        return sb.toString();
+    }
+
+    public String toShortString() {
+        return "[card:" + mCard + " device:" + mDevice + " " + mDeviceName + "]";
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/UsbAudioManager.java b/services/usb/java/com/android/server/usb/UsbAudioManager.java
deleted file mode 100644
index bb45ee8..0000000
--- a/services/usb/java/com/android/server/usb/UsbAudioManager.java
+++ /dev/null
@@ -1,197 +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 an
- * limitations under the License.
- */
-
-package com.android.server.usb;
-
-import android.alsa.AlsaCardsParser;
-import android.alsa.AlsaDevicesParser;
-import android.content.Context;
-import android.content.Intent;
-import android.hardware.usb.UsbConstants;
-import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
-import android.media.AudioManager;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-/**
- * UsbAudioManager manages USB audio devices.
- */
-public class UsbAudioManager {
-    private static final String TAG = UsbAudioManager.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    private final Context mContext;
-
-    private final class AudioDevice {
-        public int mCard;
-        public int mDevice;
-        public boolean mHasPlayback;
-        public boolean mHasCapture;
-        public boolean mHasMIDI;
-
-        public AudioDevice(int card, int device,
-                boolean hasPlayback, boolean hasCapture, boolean hasMidi) {
-            mCard = card;
-            mDevice = device;
-            mHasPlayback = hasPlayback;
-            mHasCapture = hasCapture;
-            mHasMIDI = hasMidi;
-        }
-
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("AudioDevice: [card: " + mCard);
-            sb.append(", device: " + mDevice);
-            sb.append(", hasPlayback: " + mHasPlayback);
-            sb.append(", hasCapture: " + mHasCapture);
-            sb.append(", hasMidi: " + mHasMIDI);
-            sb.append("]");
-            return sb.toString();
-        }
-    }
-
-    private final HashMap<UsbDevice,AudioDevice> mAudioDevices
-            = new HashMap<UsbDevice,AudioDevice>();
-
-    /* package */ UsbAudioManager(Context context) {
-        mContext = context;
-    }
-
-    // Broadcasts the arrival/departure of a USB audio interface
-    // audioDevice - the AudioDevice that was added or removed
-    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
-    private void sendDeviceNotification(AudioDevice audioDevice, boolean enabled) {
-        // send a sticky broadcast containing current USB state
-        Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        intent.putExtra("state", enabled ? 1 : 0);
-        intent.putExtra("card", audioDevice.mCard);
-        intent.putExtra("device", audioDevice.mDevice);
-        intent.putExtra("hasPlayback", audioDevice.mHasPlayback);
-        intent.putExtra("hasCapture", audioDevice.mHasCapture);
-        intent.putExtra("hasMIDI", audioDevice.mHasMIDI);
-        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private boolean waitForAlsaFile(int card, int device, boolean capture) {
-        // These values were empirically determined.
-        final int kNumRetries = 5;
-        final int kSleepTime = 500; // ms
-        String alsaDevPath = "/dev/snd/pcmC" + card + "D" + device + (capture ? "c" : "p");
-        File alsaDevFile = new File(alsaDevPath);
-        boolean exists = false;
-        for (int retry = 0; !exists && retry < kNumRetries; retry++) {
-            exists = alsaDevFile.exists();
-            if (!exists) {
-                try {
-                    Thread.sleep(kSleepTime);
-                } catch (IllegalThreadStateException ex) {
-                    Slog.d(TAG, "usb: IllegalThreadStateException while waiting for ALSA file.");
-                } catch (java.lang.InterruptedException ex) {
-                    Slog.d(TAG, "usb: InterruptedException while waiting for ALSA file.");
-                }
-            }
-        }
-
-        return exists;
-    }
-
-    /* package */ void deviceAdded(UsbDevice usbDevice) {
-        // Is there an audio interface in there?
-        boolean isAudioDevice = false;
-
-        // FIXME - handle multiple configurations?
-        int interfaceCount = usbDevice.getInterfaceCount();
-        for (int ntrfaceIndex = 0; !isAudioDevice && ntrfaceIndex < interfaceCount;
-                ntrfaceIndex++) {
-            UsbInterface ntrface = usbDevice.getInterface(ntrfaceIndex);
-            if (ntrface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
-                isAudioDevice = true;
-            }
-        }
-        if (!isAudioDevice) {
-            return;
-        }
-
-        //TODO(pmclean) The "Parser" objects inspect files in "/proc/asound" which we presume is
-        // present, unlike the waitForAlsaFile() which waits on a file in /dev/snd. It is not
-        // clear why this works, or that it can be relied on going forward.  Needs further
-        // research.
-        AlsaCardsParser cardsParser = new AlsaCardsParser();
-        cardsParser.scan();
-        // cardsParser.Log();
-
-        // But we need to parse the device to determine its capabilities.
-        AlsaDevicesParser devicesParser = new AlsaDevicesParser();
-        devicesParser.scan();
-        // devicesParser.Log();
-
-        // The protocol for now will be to select the last-connected (highest-numbered)
-        // Alsa Card.
-        int card = cardsParser.getNumCardRecords() - 1;
-        int device = 0;
-
-        boolean hasPlayback = devicesParser.hasPlaybackDevices(card);
-        boolean hasCapture = devicesParser.hasCaptureDevices(card);
-        boolean hasMidi = devicesParser.hasMIDIDevices(card);
-
-        // Playback device file needed/present?
-        if (hasPlayback &&
-            !waitForAlsaFile(card, device, false)) {
-            return;
-        }
-
-        // Capture device file needed/present?
-        if (hasCapture &&
-            !waitForAlsaFile(card, device, true)) {
-            return;
-        }
-
-        if (DEBUG) {
-            Slog.d(TAG,
-                    "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
-        }
-
-        AudioDevice audioDevice = new AudioDevice(card, device, hasPlayback, hasCapture, hasMidi);
-        mAudioDevices.put(usbDevice, audioDevice);
-        sendDeviceNotification(audioDevice, true);
-    }
-
-    /* package */ void deviceRemoved(UsbDevice device) {
-       if (DEBUG) {
-          Slog.d(TAG, "deviceRemoved(): " + device);
-        }
-
-        AudioDevice audioDevice = mAudioDevices.remove(device);
-        if (audioDevice != null) {
-            sendDeviceNotification(audioDevice, false);
-        }
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw) {
-        pw.println("  USB AudioDevices:");
-        for (UsbDevice device : mAudioDevices.keySet()) {
-            pw.println("    " + device.getDeviceName() + ": " + mAudioDevices.get(device));
-        }
-    }
-}
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index 1cf00d2..8849acd 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
@@ -31,8 +30,11 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.Base64;
+
 import com.android.server.FgThread;
 
 import java.lang.Thread;
@@ -46,7 +48,7 @@
 import java.security.MessageDigest;
 import java.util.Arrays;
 
-public class UsbDebuggingManager implements Runnable {
+public class UsbDebuggingManager {
     private static final String TAG = "UsbDebuggingManager";
     private static final boolean DEBUG = false;
 
@@ -57,86 +59,135 @@
 
     private final Context mContext;
     private final Handler mHandler;
-    private Thread mThread;
+    private UsbDebuggingThread mThread;
     private boolean mAdbEnabled = false;
     private String mFingerprints;
-    private LocalSocket mSocket = null;
-    private OutputStream mOutputStream = null;
 
     public UsbDebuggingManager(Context context) {
         mHandler = new UsbDebuggingHandler(FgThread.get().getLooper());
         mContext = context;
     }
 
-    private void listenToSocket() throws IOException {
-        try {
-            byte[] buffer = new byte[BUFFER_SIZE];
-            LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
-                                         LocalSocketAddress.Namespace.RESERVED);
-            InputStream inputStream = null;
+    class UsbDebuggingThread extends Thread {
+        private boolean mStopped;
+        private LocalSocket mSocket;
+        private OutputStream mOutputStream;
+        private InputStream mInputStream;
 
-            mSocket = new LocalSocket();
-            mSocket.connect(address);
+        UsbDebuggingThread() {
+            super(TAG);
+        }
 
-            mOutputStream = mSocket.getOutputStream();
-            inputStream = mSocket.getInputStream();
-
+        @Override
+        public void run() {
+            if (DEBUG) Slog.d(TAG, "Entering thread");
             while (true) {
-                int count = inputStream.read(buffer);
-                if (count < 0) {
-                    break;
+                synchronized (this) {
+                    if (mStopped) {
+                        if (DEBUG) Slog.d(TAG, "Exiting thread");
+                        return;
+                    }
+                    try {
+                        openSocketLocked();
+                    } catch (Exception e) {
+                        /* Don't loop too fast if adbd dies, before init restarts it */
+                        SystemClock.sleep(1000);
+                    }
                 }
-
-                if (buffer[0] == 'P' && buffer[1] == 'K') {
-                    String key = new String(Arrays.copyOfRange(buffer, 2, count));
-                    Slog.d(TAG, "Received public key: " + key);
-                    Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
-                    msg.obj = key;
-                    mHandler.sendMessage(msg);
-                }
-                else {
-                    Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2))));
-                    break;
+                try {
+                    listenToSocket();
+                } catch (Exception e) {
+                    /* Don't loop too fast if adbd dies, before init restarts it */
+                    SystemClock.sleep(1000);
                 }
             }
-        } finally {
-            closeSocket();
         }
-    }
 
-    @Override
-    public void run() {
-        while (mAdbEnabled) {
+        private void openSocketLocked() throws IOException {
             try {
-                listenToSocket();
-            } catch (Exception e) {
-                /* Don't loop too fast if adbd dies, before init restarts it */
-                SystemClock.sleep(1000);
+                LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
+                        LocalSocketAddress.Namespace.RESERVED);
+                mInputStream = null;
+
+                if (DEBUG) Slog.d(TAG, "Creating socket");
+                mSocket = new LocalSocket();
+                mSocket.connect(address);
+
+                mOutputStream = mSocket.getOutputStream();
+                mInputStream = mSocket.getInputStream();
+            } catch (IOException ioe) {
+                closeSocketLocked();
+                throw ioe;
             }
         }
-    }
 
-    private void closeSocket() {
-        try {
-            mOutputStream.close();
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed closing output stream: " + e);
-        }
-
-        try {
-            mSocket.close();
-        } catch (IOException ex) {
-            Slog.e(TAG, "Failed closing socket: " + ex);
-        }
-    }
-
-    private void sendResponse(String msg) {
-        if (mOutputStream != null) {
+        private void listenToSocket() throws IOException {
             try {
-                mOutputStream.write(msg.getBytes());
+                byte[] buffer = new byte[BUFFER_SIZE];
+                while (true) {
+                    int count = mInputStream.read(buffer);
+                    if (count < 0) {
+                        break;
+                    }
+
+                    if (buffer[0] == 'P' && buffer[1] == 'K') {
+                        String key = new String(Arrays.copyOfRange(buffer, 2, count));
+                        Slog.d(TAG, "Received public key: " + key);
+                        Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
+                        msg.obj = key;
+                        mHandler.sendMessage(msg);
+                    } else {
+                        Slog.e(TAG, "Wrong message: "
+                                + (new String(Arrays.copyOfRange(buffer, 0, 2))));
+                        break;
+                    }
+                }
+            } finally {
+                synchronized (this) {
+                    closeSocketLocked();
+                }
             }
-            catch (IOException ex) {
-                Slog.e(TAG, "Failed to write response:", ex);
+        }
+
+        private void closeSocketLocked() {
+            if (DEBUG) Slog.d(TAG, "Closing socket");
+            try {
+                if (mOutputStream != null) {
+                    mOutputStream.close();
+                    mOutputStream = null;
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed closing output stream: " + e);
+            }
+
+            try {
+                if (mSocket != null) {
+                    mSocket.close();
+                    mSocket = null;
+                }
+            } catch (IOException ex) {
+                Slog.e(TAG, "Failed closing socket: " + ex);
+            }
+        }
+
+        /** Call to stop listening on the socket and exit the thread. */
+        void stopListening() {
+            synchronized (this) {
+                mStopped = true;
+                closeSocketLocked();
+            }
+        }
+
+        void sendResponse(String msg) {
+            synchronized (this) {
+                if (!mStopped && mOutputStream != null) {
+                    try {
+                        mOutputStream.write(msg.getBytes());
+                    }
+                    catch (IOException ex) {
+                        Slog.e(TAG, "Failed to write response:", ex);
+                    }
+                }
             }
         }
     }
@@ -161,7 +212,7 @@
 
                     mAdbEnabled = true;
 
-                    mThread = new Thread(UsbDebuggingManager.this, TAG);
+                    mThread = new UsbDebuggingThread();
                     mThread.start();
 
                     break;
@@ -171,16 +222,12 @@
                         break;
 
                     mAdbEnabled = false;
-                    closeSocket();
 
-                    try {
-                        mThread.join();
-                    } catch (Exception ex) {
+                    if (mThread != null) {
+                        mThread.stopListening();
+                        mThread = null;
                     }
 
-                    mThread = null;
-                    mOutputStream = null;
-                    mSocket = null;
                     break;
 
                 case MESSAGE_ADB_ALLOW: {
@@ -197,19 +244,33 @@
                         writeKey(key);
                     }
 
-                    sendResponse("OK");
+                    if (mThread != null) {
+                        mThread.sendResponse("OK");
+                    }
                     break;
                 }
 
                 case MESSAGE_ADB_DENY:
-                    sendResponse("NO");
+                    if (mThread != null) {
+                        mThread.sendResponse("NO");
+                    }
                     break;
 
                 case MESSAGE_ADB_CONFIRM: {
+                    if ("trigger_restart_min_framework".equals(
+                            SystemProperties.get("vold.decrypt"))) {
+                        Slog.d(TAG, "Deferring adb confirmation until after vold decrypt");
+                        if (mThread != null) {
+                            mThread.sendResponse("NO");
+                        }
+                        break;
+                    }
                     String key = (String)msg.obj;
                     String fingerprints = getFingerprints(key);
                     if ("".equals(fingerprints)) {
-                        sendResponse("NO");
+                        if (mThread != null) {
+                            mThread.sendResponse("NO");
+                        }
                         break;
                     }
                     mFingerprints = fingerprints;
@@ -279,7 +340,7 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
             try {
-                mContext.startActivity(intent);
+                mContext.startActivityAsUser(intent, UserHandle.OWNER);
                 return true;
             } catch (ActivityNotFoundException e) {
                 Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e);
@@ -379,7 +440,7 @@
 
     public void dump(FileDescriptor fd, PrintWriter pw) {
         pw.println("  USB Debugging State:");
-        pw.println("    Connected to adbd: " + (mOutputStream != null));
+        pw.println("    Connected to adbd: " + (mThread != null));
         pw.println("    Last key received: " + mFingerprints);
         pw.println("    User keys:");
         try {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index f3fa747..b7ed8d1 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -30,7 +30,6 @@
 import android.database.ContentObserver;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
-import android.media.AudioManager;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -85,6 +84,8 @@
             "/sys/class/android_usb/android0/f_rndis/ethaddr";
     private static final String AUDIO_SOURCE_PCM_PATH =
             "/sys/class/android_usb/android0/f_audio_source/pcm";
+    private static final String MIDI_ALSA_PATH =
+            "/sys/class/android_usb/android0/f_midi/alsa";
 
     private static final int MSG_UPDATE_STATE = 0;
     private static final int MSG_ENABLE_ADB = 1;
@@ -124,9 +125,11 @@
     private boolean mUseUsbNotification;
     private boolean mAdbEnabled;
     private boolean mAudioSourceEnabled;
+    private boolean mMidiEnabled;
     private Map<String, List<Pair<String, String>>> mOemModeMap;
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
+    private final UsbAlsaManager mUsbAlsaManager;
 
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
@@ -159,8 +162,9 @@
         }
     };
 
-    public UsbDeviceManager(Context context) {
+    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
         mContext = context;
+        mUsbAlsaManager = alsaManager;
         mContentResolver = context.getContentResolver();
         PackageManager pm = mContext.getPackageManager();
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
@@ -594,19 +598,15 @@
             boolean enabled = containsFunction(mCurrentFunctions,
                     UsbManager.USB_FUNCTION_AUDIO_SOURCE);
             if (enabled != mAudioSourceEnabled) {
-                // send a sticky broadcast containing current USB state
-                Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
-                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                intent.putExtra("state", (enabled ? 1 : 0));
+                int card = -1;
+                int device = -1;
+
                 if (enabled) {
                     Scanner scanner = null;
                     try {
                         scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
-                        int card = scanner.nextInt();
-                        int device = scanner.nextInt();
-                        intent.putExtra("card", card);
-                        intent.putExtra("device", device);
+                        card = scanner.nextInt();
+                        device = scanner.nextInt();
                     } catch (FileNotFoundException e) {
                         Slog.e(TAG, "could not open audio source PCM file", e);
                     } finally {
@@ -615,11 +615,36 @@
                         }
                     }
                 }
-                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+                mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
                 mAudioSourceEnabled = enabled;
             }
         }
 
+        private void updateMidiFunction() {
+            boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
+            if (enabled != mMidiEnabled) {
+                int card = -1;
+                int device = -1;
+
+                if (enabled) {
+                    Scanner scanner = null;
+                    try {
+                        scanner = new Scanner(new File(MIDI_ALSA_PATH));
+                        card = scanner.nextInt();
+                        device = scanner.nextInt();
+                    } catch (FileNotFoundException e) {
+                        Slog.e(TAG, "could not open MIDI PCM file", e);
+                    } finally {
+                        if (scanner != null) {
+                            scanner.close();
+                        }
+                    }
+                }
+                mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
+                mMidiEnabled = enabled;
+            }
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -638,6 +663,7 @@
                     if (mBootCompleted) {
                         updateUsbState();
                         updateAudioSourceFunction();
+                        updateMidiFunction();
                     }
                     break;
                 case MSG_ENABLE_ADB:
@@ -653,6 +679,7 @@
                     updateAdbNotification();
                     updateUsbState();
                     updateAudioSourceFunction();
+                    updateMidiFunction();
                     break;
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
@@ -703,6 +730,8 @@
                     id = com.android.internal.R.string.usb_mtp_notification_title;
                 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
                     id = com.android.internal.R.string.usb_ptp_notification_title;
+                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI)) {
+                    id = com.android.internal.R.string.usb_midi_notification_title;
                 } else if (containsFunction(mCurrentFunctions,
                         UsbManager.USB_FUNCTION_MASS_STORAGE)) {
                     id = com.android.internal.R.string.usb_cd_installer_notification_title;
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index e769bda..5b58051 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -17,7 +17,6 @@
 package com.android.server.usb;
 
 import android.content.Context;
-import android.content.Intent;
 import android.hardware.usb.UsbConfiguration;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
@@ -25,13 +24,11 @@
 import android.hardware.usb.UsbInterface;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -60,16 +57,16 @@
     private ArrayList<UsbInterface> mNewInterfaces;
     private ArrayList<UsbEndpoint> mNewEndpoints;
 
-    private UsbAudioManager mUsbAudioManager;
+    private final UsbAlsaManager mUsbAlsaManager;
 
     @GuardedBy("mLock")
     private UsbSettingsManager mCurrentSettings;
 
-    public UsbHostManager(Context context) {
+    public UsbHostManager(Context context, UsbAlsaManager alsaManager) {
         mContext = context;
         mHostBlacklist = context.getResources().getStringArray(
                 com.android.internal.R.array.config_usbHostBlacklist);
-        mUsbAudioManager = new UsbAudioManager(context);
+        mUsbAlsaManager = alsaManager;
     }
 
     public void setCurrentSettings(UsbSettingsManager settings) {
@@ -222,7 +219,7 @@
                 mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
                 Slog.d(TAG, "Added device " + mNewDevice);
                 getCurrentSettings().deviceAttached(mNewDevice);
-                mUsbAudioManager.deviceAdded(mNewDevice);
+                mUsbAlsaManager.usbDeviceAdded(mNewDevice);
             } else {
                 Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
             }
@@ -238,7 +235,7 @@
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
-                mUsbAudioManager.deviceRemoved(device);
+                mUsbAlsaManager.usbDeviceRemoved(device);
                 getCurrentSettings().deviceDetached(device);
             }
         }
@@ -290,7 +287,6 @@
                 pw.println("    " + name + ": " + mDevices.get(name));
             }
         }
-        mUsbAudioManager.dump(fd, pw);
     }
 
     private native void monitorUsbHostBus();
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
new file mode 100644
index 0000000..f23bb93
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -0,0 +1,183 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.content.Context;
+import android.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiDispatcher;
+import android.media.midi.MidiManager;
+import android.media.midi.MidiReceiver;
+import android.media.midi.MidiSender;
+import android.os.Bundle;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructPollfd;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public final class UsbMidiDevice implements Closeable {
+    private static final String TAG = "UsbMidiDevice";
+
+    private MidiDeviceServer mServer;
+
+    private final MidiReceiver[] mInputPortReceivers;
+
+    private static final int BUFFER_SIZE = 512;
+
+    // for polling multiple FileDescriptors for MIDI events
+    private final StructPollfd[] mPollFDs;
+    // streams for reading from ALSA driver
+    private final FileInputStream[] mInputStreams;
+    // streams for writing to ALSA driver
+    private final FileOutputStream[] mOutputStreams;
+
+    public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
+        // FIXME - support devices with different number of input and output ports
+        int subDevices = nativeGetSubdeviceCount(card, device);
+        if (subDevices <= 0) {
+            Log.e(TAG, "nativeGetSubdeviceCount failed");
+            return null;
+        }
+
+        // FIXME - support devices with different number of input and output ports
+        FileDescriptor[] fileDescriptors = nativeOpen(card, device, subDevices);
+        if (fileDescriptors == null) {
+            Log.e(TAG, "nativeOpen failed");
+            return null;
+        }
+
+        UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+        if (!midiDevice.register(context, properties)) {
+            IoUtils.closeQuietly(midiDevice);
+            Log.e(TAG, "createDeviceServer failed");
+            return null;
+        }
+        return midiDevice;
+    }
+
+    private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
+        int inputCount = inputFiles.length;
+        int outputCount = outputFiles.length;
+
+        mPollFDs = new StructPollfd[inputCount];
+        mInputStreams = new FileInputStream[inputCount];
+        for (int i = 0; i < inputCount; i++) {
+            FileDescriptor fd = inputFiles[i];
+            StructPollfd pollfd = new StructPollfd();
+            pollfd.fd = fd;
+            pollfd.events = (short)OsConstants.POLLIN;
+            mPollFDs[i] = pollfd;
+            mInputStreams[i] = new FileInputStream(fd);
+        }
+
+        mOutputStreams = new FileOutputStream[outputCount];
+        for (int i = 0; i < outputCount; i++) {
+            mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
+        }
+
+        mInputPortReceivers = new MidiReceiver[inputCount];
+        for (int port = 0; port < inputCount; port++) {
+            final int portF = port;
+            mInputPortReceivers[port] = new MidiReceiver() {
+                @Override
+                public void onReceive(byte[] data, int offset, int count, long timestamp)
+                        throws IOException {
+                    // FIXME - timestamps are ignored, future posting not supported yet.
+                    mOutputStreams[portF].write(data, offset, count);
+                }
+            };
+        }
+    }
+
+    private boolean register(Context context, Bundle properties) {
+        MidiManager midiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
+        if (midiManager == null) {
+            Log.e(TAG, "No MidiManager in UsbMidiDevice.create()");
+            return false;
+        }
+
+        int outputCount = mOutputStreams.length;
+        mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount,
+                null, null, properties, MidiDeviceInfo.TYPE_USB, null);
+        if (mServer == null) {
+            return false;
+        }
+        final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
+
+        // FIXME can we only run this when we have a dispatcher that has listeners?
+        new Thread() {
+            @Override
+            public void run() {
+                byte[] buffer = new byte[BUFFER_SIZE];
+                try {
+                    boolean done = false;
+                    while (!done) {
+                        // look for a readable FileDescriptor
+                        for (int index = 0; index < mPollFDs.length; index++) {
+                            StructPollfd pfd = mPollFDs[index];
+                            if ((pfd.revents & OsConstants.POLLIN) != 0) {
+                                // clear readable flag
+                                pfd.revents = 0;
+
+                                int count = mInputStreams[index].read(buffer);
+                                outputReceivers[index].send(buffer, 0, count);
+                            } else if ((pfd.revents & (OsConstants.POLLERR
+                                                        | OsConstants.POLLHUP)) != 0) {
+                                done = true;
+                            }
+                        }
+
+                        // wait until we have a readable port
+                        Os.poll(mPollFDs, -1 /* infinite timeout */);
+                     }
+                } catch (IOException e) {
+                    Log.d(TAG, "reader thread exiting");
+                } catch (ErrnoException e) {
+                    Log.d(TAG, "reader thread exiting");
+                }
+            }
+        }.start();
+
+        return true;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (mServer != null) {
+            mServer.close();
+        }
+
+        for (int i = 0; i < mInputStreams.length; i++) {
+            mInputStreams[i].close();
+        }
+        for (int i = 0; i < mOutputStreams.length; i++) {
+            mOutputStreams[i].close();
+        }
+    }
+
+    private static native int nativeGetSubdeviceCount(int card, int device);
+    private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
+}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index fd83f92..fda8076 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -73,6 +73,7 @@
 
     private UsbDeviceManager mDeviceManager;
     private UsbHostManager mHostManager;
+    private final UsbAlsaManager mAlsaManager;
 
     private final Object mLock = new Object();
 
@@ -95,12 +96,14 @@
     public UsbService(Context context) {
         mContext = context;
 
+        mAlsaManager = new UsbAlsaManager(context);
+
         final PackageManager pm = mContext.getPackageManager();
         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
-            mHostManager = new UsbHostManager(context);
+            mHostManager = new UsbHostManager(context, mAlsaManager);
         }
         if (new File("/sys/class/android_usb").exists()) {
-            mDeviceManager = new UsbDeviceManager(context);
+            mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
         }
 
         setCurrentUser(UserHandle.USER_OWNER);
@@ -137,6 +140,8 @@
     }
 
     public void systemReady() {
+        mAlsaManager.systemReady();
+
         if (mDeviceManager != null) {
             mDeviceManager.systemReady();
         }
@@ -305,6 +310,7 @@
         if (mHostManager != null) {
             mHostManager.dump(fd, pw);
         }
+        mAlsaManager.dump(fd, pw);
 
         synchronized (mLock) {
             for (int i = 0; i < mSettingsByUser.size(); i++) {
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 37b5c51..bfd1f13 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -27,7 +27,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f5d4867..6b8c49c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -39,7 +39,6 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
@@ -130,12 +129,14 @@
         }
 
         public void initForUser(int userHandle) {
-            if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle);
+            if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
             String curInteractorStr = Settings.Secure.getStringForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
             ComponentName curRecognizer = getCurRecognizer(userHandle);
             VoiceInteractionServiceInfo curInteractorInfo = null;
+            if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
+                    + " curRecognizer=" + curRecognizer);
             if (curInteractorStr == null && curRecognizer != null
                     && !ActivityManager.isLowRamDeviceStatic()) {
                 // If there is no interactor setting, that means we are upgrading
@@ -149,6 +150,8 @@
                     // Looks good!  We'll apply this one.  To make it happen, we clear the
                     // recognizer so that we don't think we have anything set and will
                     // re-apply the settings.
+                    if (DEBUG) Slog.d(TAG, "No set interactor, found avail: "
+                            + curInteractorInfo.getServiceInfo().name);
                     curRecognizer = null;
                 }
             }
@@ -157,6 +160,7 @@
             // enabled; if it is, turn it off.
             if (ActivityManager.isLowRamDeviceStatic() && curInteractorStr != null) {
                 if (!TextUtils.isEmpty(curInteractorStr)) {
+                    if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor");
                     setCurInteractor(null, userHandle);
                     curInteractorStr = "";
                 }
@@ -179,8 +183,11 @@
                 }
                 // If the apps for the currently set components still exist, then all is okay.
                 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
+                    if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!");
                     return;
                 }
+                if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor ("
+                        + interactorInfo + ")");
             }
 
             // Initializing settings, look for an interactor first (but only on non-svelte).
@@ -317,7 +324,7 @@
             if (TextUtils.isEmpty(curInteractor)) {
                 return null;
             }
-            if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor
+            if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
                     + " user=" + userHandle);
             return ComponentName.unflattenFromString(curInteractor);
         }
@@ -326,7 +333,7 @@
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
                     Settings.Secure.VOICE_INTERACTION_SERVICE,
                     comp != null ? comp.flattenToShortString() : "", userHandle);
-            if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp
+            if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp
                     + " user=" + userHandle);
         }
 
@@ -364,7 +371,7 @@
             if (TextUtils.isEmpty(curRecognizer)) {
                 return null;
             }
-            if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
+            if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
                     + " user=" + userHandle);
             return ComponentName.unflattenFromString(curRecognizer);
         }
@@ -373,12 +380,12 @@
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
                     Settings.Secure.VOICE_RECOGNITION_SERVICE,
                     comp != null ? comp.flattenToShortString() : "", userHandle);
-            if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp
+            if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
                     + " user=" + userHandle);
         }
 
         @Override
-        public void startSession(IVoiceInteractionService service, Bundle args) {
+        public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
             synchronized (this) {
                 if (mImpl == null || mImpl.mService == null
                         || service.asBinder() != mImpl.mService.asBinder()) {
@@ -389,7 +396,7 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.startSessionLocked(callingPid, callingUid, args);
+                    mImpl.showSessionLocked(callingPid, callingUid, args, flags);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -417,6 +424,42 @@
         }
 
         @Override
+        public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "showSessionFromSession without running voice interaction service");
+                    return false;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
+        public boolean hideSessionFromSession(IBinder token) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
+                    return false;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.hideSessionLocked(callingPid, callingUid);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
         public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
             synchronized (this) {
                 if (mImpl == null) {
@@ -426,9 +469,6 @@
                 final int callingPid = Binder.getCallingPid();
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
-                if (!SystemProperties.getBoolean("persist.test.voice_interaction", false)) {
-                    throw new SecurityException("Voice interaction not supported");
-                }
                 try {
                     return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
                             intent, resolvedType);
@@ -696,7 +736,7 @@
             @Override
             public void onSomePackagesChanged() {
                 int userHandle = getChangingUserId();
-                if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle);
+                if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
 
                 ComponentName curInteractor = getCurInteractor(userHandle);
                 ComponentName curRecognizer = getCurRecognizer(userHandle);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index b36b611..9e92867 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -26,7 +26,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -35,19 +34,17 @@
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.IVoiceInteractionSessionService;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.util.Slog;
 import android.view.IWindowManager;
-import android.view.WindowManager;
 
 import com.android.internal.app.IVoiceInteractor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-class VoiceInteractionManagerServiceImpl {
+class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
 
     final boolean mValid;
@@ -64,7 +61,7 @@
     boolean mBound = false;
     IVoiceInteractionService mService;
 
-    SessionConnection mActiveSession;
+    VoiceInteractionSessionConnection mActiveSession;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -100,91 +97,6 @@
         }
     };
 
-    final class SessionConnection implements ServiceConnection {
-        final IBinder mToken = new Binder();
-        final Bundle mArgs;
-        boolean mBound;
-        IVoiceInteractionSessionService mService;
-        IVoiceInteractionSession mSession;
-        IVoiceInteractor mInteractor;
-
-        SessionConnection(Bundle args) {
-            mArgs = args;
-            Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
-            serviceIntent.setComponent(mSessionComponentName);
-            mBound = mContext.bindServiceAsUser(serviceIntent, this,
-                    Context.BIND_AUTO_CREATE, new UserHandle(mUser));
-            if (mBound) {
-                try {
-                    mIWindowManager.addWindowToken(mToken,
-                            WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed adding window token", e);
-                }
-            } else {
-                Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
-            }
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (mLock) {
-                mService = IVoiceInteractionSessionService.Stub.asInterface(service);
-                if (mActiveSession == this) {
-                    try {
-                        mService.newSession(mToken, mArgs);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed adding window token", e);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            mService = null;
-        }
-
-        public void cancel() {
-            if (mBound) {
-                if (mSession != null) {
-                    try {
-                        mSession.destroy();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Voice interation session already dead");
-                    }
-                }
-                if (mSession != null) {
-                    try {
-                        mAm.finishVoiceTask(mSession);
-                    } catch (RemoteException e) {
-                    }
-                }
-                mContext.unbindService(this);
-                try {
-                    mIWindowManager.removeWindowToken(mToken);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed removing window token", e);
-                }
-                mBound = false;
-                mService = null;
-                mSession = null;
-                mInteractor = null;
-            }
-        }
-
-        public void dump(String prefix, PrintWriter pw) {
-            pw.print(prefix); pw.print("mToken="); pw.println(mToken);
-            pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
-            pw.print(prefix); pw.print("mBound="); pw.println(mBound);
-            if (mBound) {
-                pw.print(prefix); pw.print("mService="); pw.println(mService);
-                pw.print(prefix); pw.print("mSession="); pw.println(mSession);
-                pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
-            }
-        }
-    };
-
     VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
             int userHandle, ComponentName service) {
         mContext = context;
@@ -222,12 +134,16 @@
         mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
     }
 
-    public void startSessionLocked(int callingPid, int callingUid, Bundle args) {
-        if (mActiveSession != null) {
-            mActiveSession.cancel();
-            mActiveSession = null;
+    public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
+        if (mActiveSession == null) {
+            mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
+                    mUser, mContext, this, callingPid, callingUid);
         }
-        mActiveSession = new SessionConnection(args);
+        return mActiveSession.showLocked(args, flags);
+    }
+
+    public boolean hideSessionLocked(int callingPid, int callingUid) {
+        return mActiveSession.hideLocked();
     }
 
     public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -236,8 +152,7 @@
             Slog.w(TAG, "deliverNewSession does not match active session");
             return false;
         }
-        mActiveSession.mSession = session;
-        mActiveSession.mInteractor = interactor;
+        mActiveSession.deliverNewSessionLocked(session, interactor);
         return true;
     }
 
@@ -327,4 +242,11 @@
             Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
         }
     }
+
+    @Override
+    public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
+        synchronized (mLock) {
+            finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken);
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
new file mode 100644
index 0000000..30d97b9
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.voiceinteraction;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.AssistContent;
+import android.app.IActivityManager;
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VoiceInteractionService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+final class VoiceInteractionSessionConnection implements ServiceConnection {
+    final static String TAG = "VoiceInteractionServiceManager";
+
+    final IBinder mToken = new Binder();
+    final Object mLock;
+    final ComponentName mSessionComponentName;
+    final Intent mBindIntent;
+    final int mUser;
+    final Context mContext;
+    final Callback mCallback;
+    final int mCallingPid;
+    final int mCallingUid;
+    final IActivityManager mAm;
+    final IWindowManager mIWindowManager;
+    final IBinder mPermissionOwner;
+    boolean mShown;
+    Bundle mShowArgs;
+    int mShowFlags;
+    boolean mBound;
+    boolean mFullyBound;
+    boolean mCanceled;
+    IVoiceInteractionSessionService mService;
+    IVoiceInteractionSession mSession;
+    IVoiceInteractor mInteractor;
+    boolean mHaveAssistData;
+    Bundle mAssistData;
+
+    public interface Callback {
+        public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
+    }
+
+    final ServiceConnection mFullConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+        }
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    };
+
+    final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            synchronized (mLock) {
+                if (mShown) {
+                    mHaveAssistData = true;
+                    mAssistData = resultData;
+                    deliverAssistData();
+                }
+            }
+        }
+    };
+
+    public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
+            Context context, Callback callback, int callingPid, int callingUid) {
+        mLock = lock;
+        mSessionComponentName = component;
+        mUser = user;
+        mContext = context;
+        mCallback = callback;
+        mCallingPid = callingPid;
+        mCallingUid = callingUid;
+        mAm = ActivityManagerNative.getDefault();
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
+        IBinder permOwner = null;
+        try {
+            permOwner = mAm.newUriPermissionOwner("voicesession:"
+                    + component.flattenToShortString());
+        } catch (RemoteException e) {
+            Slog.w("voicesession", "AM dead", e);
+        }
+        mPermissionOwner = permOwner;
+        mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+        mBindIntent.setComponent(mSessionComponentName);
+        mBound = mContext.bindServiceAsUser(mBindIntent, this,
+                Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+        if (mBound) {
+            try {
+                mIWindowManager.addWindowToken(mToken,
+                        WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed adding window token", e);
+            }
+        } else {
+            Slog.w(TAG, "Failed binding to voice interaction session service "
+                    + mSessionComponentName);
+        }
+    }
+
+    public boolean showLocked(Bundle args, int flags) {
+        if (mBound) {
+            if (!mFullyBound) {
+                mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
+                        Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
+                        new UserHandle(mUser));
+            }
+            mShown = true;
+            mShowArgs = args;
+            mShowFlags = flags;
+            if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
+                try {
+                    mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                            mAssistReceiver);
+                } catch (RemoteException e) {
+                }
+            } else {
+                mHaveAssistData = false;
+                mAssistData = null;
+            }
+            if (mSession != null) {
+                try {
+                    mSession.show(mShowArgs, mShowFlags);
+                    mShowArgs = null;
+                    mShowFlags = 0;
+                } catch (RemoteException e) {
+                }
+                deliverAssistData();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    void grantUriPermission(Uri uri, int mode, int srcUid, int destUid, String destPkg) {
+        if (!"content".equals(uri.getScheme())) {
+            return;
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            // This will throw SecurityException for us.
+            mAm.checkGrantUriPermission(srcUid, null, ContentProvider.getUriWithoutUserId(uri),
+                    mode, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(srcUid)));
+            // No security exception, do the grant.
+            int sourceUserId = ContentProvider.getUserIdFromUri(uri, mUser);
+            uri = ContentProvider.getUriWithoutUserId(uri);
+            mAm.grantUriPermissionFromOwner(mPermissionOwner, srcUid, destPkg,
+                    uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, mUser);
+        } catch (RemoteException e) {
+        } catch (SecurityException e) {
+            Slog.w(TAG, "Can't propagate permission", e);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+    }
+
+    void grantClipDataItemPermission(ClipData.Item item, int mode, int srcUid, int destUid,
+            String destPkg) {
+        if (item.getUri() != null) {
+            grantUriPermission(item.getUri(), mode, srcUid, destUid, destPkg);
+        }
+        Intent intent = item.getIntent();
+        if (intent != null && intent.getData() != null) {
+            grantUriPermission(intent.getData(), mode, srcUid, destUid, destPkg);
+        }
+    }
+
+    void grantClipDataPermissions(ClipData data, int mode, int srcUid, int destUid,
+            String destPkg) {
+        final int N = data.getItemCount();
+        for (int i=0; i<N; i++) {
+            grantClipDataItemPermission(data.getItemAt(i), mode, srcUid, destUid, destPkg);
+        }
+    }
+
+    void deliverAssistData() {
+        if (mSession == null || !mHaveAssistData) {
+            return;
+        }
+        if (mAssistData != null) {
+            int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
+            if (uid >= 0) {
+                Bundle assistContext = mAssistData.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+                if (assistContext != null) {
+                    AssistContent content = AssistContent.getAssistContent(assistContext);
+                    if (content != null) {
+                        Intent intent = content.getIntent();
+                        if (intent != null) {
+                            ClipData data = intent.getClipData();
+                            if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
+                                grantClipDataPermissions(data, intent.getFlags(), uid,
+                                        mCallingUid, mSessionComponentName.getPackageName());
+                            }
+                        }
+                        ClipData data = content.getClipData();
+                        if (data != null) {
+                            grantClipDataPermissions(data, Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                                    uid, mCallingUid, mSessionComponentName.getPackageName());
+                        }
+                    }
+                }
+            }
+        }
+        try {
+            mSession.handleAssist(mAssistData);
+            mAssistData = null;
+            mHaveAssistData = false;
+        } catch (RemoteException e) {
+        }
+    }
+
+    public boolean hideLocked() {
+        if (mBound) {
+            if (mShown) {
+                mShown = false;
+                mShowArgs = null;
+                mShowFlags = 0;
+                mHaveAssistData = false;
+                mAssistData = null;
+                if (mSession != null) {
+                    try {
+                        mSession.hide();
+                    } catch (RemoteException e) {
+                    }
+                }
+                try {
+                    mAm.revokeUriPermissionFromOwner(mPermissionOwner, null,
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION
+                                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                            mUser);
+                } catch (RemoteException e) {
+                }
+            }
+            if (mFullyBound) {
+                mContext.unbindService(mFullConnection);
+                mFullyBound = false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public boolean deliverNewSessionLocked(IVoiceInteractionSession session,
+            IVoiceInteractor interactor) {
+        mSession = session;
+        mInteractor = interactor;
+        if (mShown) {
+            try {
+                session.show(mShowArgs, mShowFlags);
+                mShowArgs = null;
+                mShowFlags = 0;
+            } catch (RemoteException e) {
+            }
+            if (mHaveAssistData) {
+                try {
+                    session.handleAssist(mAssistData);
+                    mAssistData = null;
+                    mHaveAssistData = false;
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        synchronized (mLock) {
+            mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+            if (!mCanceled) {
+                try {
+                    mService.newSession(mToken, mShowArgs, mShowFlags);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed adding window token", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        mCallback.sessionConnectionGone(this);
+        mService = null;
+    }
+
+    public void cancel() {
+        mCanceled = true;
+        if (mBound) {
+            if (mSession != null) {
+                try {
+                    mSession.destroy();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Voice interation session already dead");
+                }
+            }
+            if (mSession != null) {
+                try {
+                    mAm.finishVoiceTask(mSession);
+                } catch (RemoteException e) {
+                }
+            }
+            mContext.unbindService(this);
+            try {
+                mIWindowManager.removeWindowToken(mToken);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed removing window token", e);
+            }
+            mBound = false;
+            mService = null;
+            mSession = null;
+            mInteractor = null;
+        }
+        if (mFullyBound) {
+            mContext.unbindService(mFullConnection);
+            mFullyBound = false;
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+        pw.print(prefix); pw.print("mShown="); pw.println(mShown);
+        pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs);
+        pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags));
+        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+        if (mBound) {
+            pw.print(prefix); pw.print("mService="); pw.println(mService);
+            pw.print(prefix); pw.print("mSession="); pw.println(mSession);
+            pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
+        }
+        pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
+        if (mHaveAssistData) {
+            pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
+        }
+    }
+};
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 98217f7..f7a19f8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1056,14 +1056,11 @@
     /**
      * Informs listeners that this {@code Connection} has processed a character in the post-dial
      * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence;
-     * (b) it has encountered a "wait" character; and (c) it wishes to signal Telecom to play
-     * the corresponding DTMF tone locally.
+     * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally.
      *
      * @param nextChar The DTMF character that was just processed by the {@code Connection}.
-     *
-     * @hide
      */
-    public final void setNextPostDialWaitChar(char nextChar) {
+    public final void setNextPostDialChar(char nextChar) {
         checkImmutable();
         for (Listener l : mListeners) {
             l.onPostDialChar(this, nextChar);
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 43a92cb..a9b725b 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -60,11 +60,16 @@
                 mPendingConnections.remove(connection);
                 // Unconditionally initialize the connection ...
                 connection.setConnectionCapabilities(parcel.getConnectionCapabilities());
-                connection.setAddress(
-                        parcel.getHandle(), parcel.getHandlePresentation());
-                connection.setCallerDisplayName(
-                        parcel.getCallerDisplayName(),
-                        parcel.getCallerDisplayNamePresentation());
+                if (parcel.getHandle() != null
+                    || parcel.getState() != Connection.STATE_DISCONNECTED) {
+                    connection.setAddress(parcel.getHandle(), parcel.getHandlePresentation());
+                }
+                if (parcel.getCallerDisplayName() != null
+                    || parcel.getState() != Connection.STATE_DISCONNECTED) {
+                    connection.setCallerDisplayName(
+                            parcel.getCallerDisplayName(),
+                            parcel.getCallerDisplayNamePresentation());
+                }
                 // Set state after handle so that the client can identify the connection.
                 if (parcel.getState() == Connection.STATE_DISCONNECTED) {
                     connection.setDisconnected(parcel.getDisconnectCause());
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8be3e66..b40afbf 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -77,12 +77,24 @@
             "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
 
     /**
+     * The {@link android.content.Intent} action used to show the call accessibility settings page.
+     */
+    public static final String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS =
+            "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
+
+    /**
      * The {@link android.content.Intent} action used to show the call settings page.
      */
     public static final String ACTION_SHOW_CALL_SETTINGS =
             "android.telecom.action.SHOW_CALL_SETTINGS";
 
     /**
+     * The {@link android.content.Intent} action used to show the respond via SMS settings page.
+     */
+    public static final String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS =
+            "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
+
+    /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
      * @hide
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index dbd48d9..b39b4c7 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * CellIdentity is to represent a unique CDMA cell
  */
@@ -137,27 +139,25 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mNetworkId * primeNum) + (mSystemId * primeNum) + (mBasestationId * primeNum) +
-                (mLatitude * primeNum) + (mLongitude * primeNum);
+        return Objects.hash(mNetworkId, mSystemId, mBasestationId, mLatitude, mLongitude);
     }
 
     @Override
     public boolean equals(Object other) {
-        if (super.equals(other)) {
-            try {
-                CellIdentityCdma o = (CellIdentityCdma)other;
-                return mNetworkId == o.mNetworkId &&
-                        mSystemId == o.mSystemId &&
-                        mBasestationId == o.mBasestationId &&
-                        mLatitude == o.mLatitude &&
-                        mLongitude == o.mLongitude;
-            } catch (ClassCastException e) {
-                return false;
-            }
-        } else {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof CellIdentityCdma)) {
             return false;
         }
+
+        CellIdentityCdma o = (CellIdentityCdma) other;
+        return mNetworkId == o.mNetworkId &&
+                mSystemId == o.mSystemId &&
+                mBasestationId == o.mBasestationId &&
+                mLatitude == o.mLatitude &&
+                mLongitude == o.mLongitude;
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 6f8cc91..90d2aa0 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * CellIdentity to represent a unique GSM cell
  */
@@ -113,25 +115,24 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum);
+        return Objects.hash(mMcc, mMnc, mLac, mCid);
     }
 
     @Override
     public boolean equals(Object other) {
-        if (super.equals(other)) {
-            try {
-                CellIdentityGsm o = (CellIdentityGsm)other;
-                return mMcc == o.mMcc &&
-                        mMnc == o.mMnc &&
-                        mLac == o.mLac &&
-                        mCid == o.mCid;
-            } catch (ClassCastException e) {
-                return false;
-            }
-        } else {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof CellIdentityGsm)) {
             return false;
         }
+
+        CellIdentityGsm o = (CellIdentityGsm) other;
+        return mMcc == o.mMcc &&
+                mMnc == o.mMnc &&
+                mLac == o.mLac &&
+                mCid == o.mCid;
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 72578a4..1e7ac08 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * CellIdentity is to represent a unique LTE cell
  */
@@ -117,27 +119,25 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mMcc * primeNum) + (mMnc * primeNum) + (mCi * primeNum) + (mPci * primeNum) +
-                (mTac * primeNum);
+        return Objects.hash(mMcc, mMnc, mCi, mPci, mTac);
     }
 
     @Override
     public boolean equals(Object other) {
-        if (super.equals(other)) {
-            try {
-                CellIdentityLte o = (CellIdentityLte)other;
-                return mMcc == o.mMcc &&
-                        mMnc == o.mMnc &&
-                        mCi == o.mCi &&
-                        mPci == o.mPci &&
-                        mTac == o.mTac;
-            } catch (ClassCastException e) {
-                return false;
-            }
-        } else {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof CellIdentityLte)) {
             return false;
         }
+
+        CellIdentityLte o = (CellIdentityLte) other;
+        return mMcc == o.mMcc &&
+                mMnc == o.mMnc &&
+                mCi == o.mCi &&
+                mPci == o.mPci &&
+                mTac == o.mTac;
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 2f8fa42..56ee8c9 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.telephony.Rlog;
 
+import java.util.Objects;
+
 /**
  * CellIdentity to represent a unique UMTS cell
  */
@@ -118,27 +120,25 @@
 
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
-                (mPsc * primeNum);
+        return Objects.hash(mMcc, mMnc, mLac, mCid, mPsc);
     }
 
     @Override
     public boolean equals(Object other) {
-        if (super.equals(other)) {
-            try {
-                CellIdentityWcdma o = (CellIdentityWcdma)other;
-                return mMcc == o.mMcc &&
-                        mMnc == o.mMnc &&
-                        mLac == o.mLac &&
-                        mCid == o.mCid &&
-                        mPsc == o.mPsc;
-            } catch (ClassCastException e) {
-                return false;
-            }
-        } else {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof CellIdentityWcdma)) {
             return false;
         }
+
+        CellIdentityWcdma o = (CellIdentityWcdma) other;
+        return mMcc == o.mMcc &&
+                mMnc == o.mMnc &&
+                mLac == o.mLac &&
+                mCid == o.mCid &&
+                mPsc == o.mPsc;
     }
 
     @Override
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 3572846..aae3ff6 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -37,8 +37,6 @@
 import android.text.style.TtsSpan;
 import android.util.SparseIntArray;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
 
 import java.util.Locale;
@@ -1143,6 +1141,7 @@
      *
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static String formatNumber(String source) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
         formatNumber(text, getFormatTypeForLocale(Locale.getDefault()));
@@ -1161,6 +1160,7 @@
      * @hide
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static String formatNumber(String source, int defaultFormattingType) {
         SpannableStringBuilder text = new SpannableStringBuilder(source);
         formatNumber(text, defaultFormattingType);
@@ -1176,6 +1176,7 @@
      *
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static int getFormatTypeForLocale(Locale locale) {
         String country = locale.getCountry();
 
@@ -1192,6 +1193,7 @@
      *
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static void formatNumber(Editable text, int defaultFormattingType) {
         int formatType = defaultFormattingType;
 
@@ -1240,6 +1242,7 @@
      *
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static void formatNanpNumber(Editable text) {
         int length = text.length();
         if (length > "+1-nnn-nnn-nnnn".length()) {
@@ -1355,6 +1358,7 @@
      *
      * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
      */
+    @Deprecated
     public static void formatJapaneseNumber(Editable text) {
         JapanesePhoneNumberFormatter.format(text);
     }
@@ -1376,32 +1380,52 @@
     }
 
     /**
-     * Format the given phoneNumber to the E.164 representation.
-     * <p>
-     * The given phone number must have an area code and could have a country
-     * code.
-     * <p>
-     * The defaultCountryIso is used to validate the given number and generate
-     * the E.164 phone number if the given number doesn't have a country code.
+     * Formats the specified {@code phoneNumber} to the E.164 representation.
      *
-     * @param phoneNumber
-     *            the phone number to format
-     * @param defaultCountryIso
-     *            the ISO 3166-1 two letters country code
-     * @return the E.164 representation, or null if the given phone number is
-     *         not valid.
+     * @param phoneNumber the phone number to format.
+     * @param defaultCountryIso the ISO 3166-1 two letters country code.
+     * @return the E.164 representation, or null if the given phone number is not valid.
      */
     public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) {
+        return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.E164);
+    }
+
+    /**
+     * Formats the specified {@code phoneNumber} to the RFC3966 representation.
+     *
+     * @param phoneNumber the phone number to format.
+     * @param defaultCountryIso the ISO 3166-1 two letters country code.
+     * @return the RFC3966 representation, or null if the given phone number is not valid.
+     */
+    public static String formatNumberToRFC3966(String phoneNumber, String defaultCountryIso) {
+        return formatNumberInternal(phoneNumber, defaultCountryIso, PhoneNumberFormat.RFC3966);
+    }
+
+    /**
+     * Formats the raw phone number (string) using the specified {@code formatIdentifier}.
+     * <p>
+     * The given phone number must have an area code and could have a country code.
+     * <p>
+     * The defaultCountryIso is used to validate the given number and generate the formatted number
+     * if the specified number doesn't have a country code.
+     *
+     * @param rawPhoneNumber The phone number to format.
+     * @param defaultCountryIso The ISO 3166-1 two letters country code.
+     * @param formatIdentifier The (enum) identifier of the desired format.
+     * @return the formatted representation, or null if the specified number is not valid.
+     */
+    private static String formatNumberInternal(
+            String rawPhoneNumber, String defaultCountryIso, PhoneNumberFormat formatIdentifier) {
+
         PhoneNumberUtil util = PhoneNumberUtil.getInstance();
-        String result = null;
         try {
-            PhoneNumber pn = util.parse(phoneNumber, defaultCountryIso);
-            if (util.isValidNumber(pn)) {
-                result = util.format(pn, PhoneNumberFormat.E164);
+            PhoneNumber phoneNumber = util.parse(rawPhoneNumber, defaultCountryIso);
+            if (util.isValidNumber(phoneNumber)) {
+                return util.format(phoneNumber, formatIdentifier);
             }
-        } catch (NumberParseException e) {
-        }
-        return result;
+        } catch (NumberParseException ignored) { }
+
+        return null;
     }
 
     /**
@@ -2421,9 +2445,13 @@
     }
 
     private static String getCurrentIdp(boolean useNanp) {
-        // in case, there is no IDD is found, we shouldn't convert it.
-        String ps = SystemProperties.get(
-                PROPERTY_OPERATOR_IDP_STRING, useNanp ? NANP_IDP_STRING : PLUS_SIGN_STRING);
+        String ps = null;
+        if (useNanp) {
+            ps = NANP_IDP_STRING;
+        } else {
+            // in case, there is no IDD is found, we shouldn't convert it.
+            ps = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, PLUS_SIGN_STRING);
+        }
         return ps;
     }
 
@@ -2514,7 +2542,7 @@
      *
      * @param number SIP address of the form "username@domainname"
      *               (or the URI-escaped equivalent "username%40domainname")
-     * @see isUriNumber
+     * @see #isUriNumber
      *
      * @hide
      */
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 8f4a92b..611dd7bd 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -27,13 +27,10 @@
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
-import android.telephony.SubscriptionManager;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 
 import com.android.internal.telephony.IPhoneStateListener;
-import com.android.internal.telephony.PhoneConstants;
-
 import java.util.List;
 
 /**
@@ -233,8 +230,7 @@
 
     /**
      * Create a PhoneStateListener for the Phone with the default subscription.
-     * This class requires Looper.myLooper() not return null. To supply your
-     * own non-null looper use PhoneStateListener(Looper looper) below.
+     * This class requires Looper.myLooper() not return null.
      */
     public PhoneStateListener() {
         this(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, Looper.myLooper());
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index a85df15..f246416 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -16,10 +16,8 @@
 
 package android.telephony;
 
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseDisconnectCause;
 
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 87529fe..31c9a9e 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -16,10 +16,8 @@
 
 package android.telephony;
 
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.net.LinkProperties;
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index aca94e9..08aec08 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,8 +32,6 @@
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyProperties;
-
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b96f528..eef91e1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -42,9 +42,7 @@
 
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -2277,11 +2275,7 @@
      * Returns a constant indicating the call state (cellular) on the device.
      */
     public int getCallState() {
-        try {
-            return getTelecomService().getCallState();
-        } catch (RemoteException | NullPointerException e) {
-            return CALL_STATE_IDLE;
-        }
+        return getCallState(getDefaultSubscription());
     }
 
     /**
@@ -3732,6 +3726,34 @@
     }
 
     /**
+     * Whether the device supports configuring the DTMF tone length.
+     *
+     * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise.
+     */
+    public boolean canChangeDtmfToneLength() {
+        try {
+            return getITelephony().canChangeDtmfToneLength();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
+        }
+        return false;
+    }
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the device is a world phone, and {@code false} otherwise.
+     */
+    public boolean isWorldPhone() {
+        try {
+            return getITelephony().isWorldPhone();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
+        }
+        return false;
+    }
+
+    /**
      * This function retrieves value for setting "name+subId", and if that is not found
      * retrieves value for setting "name", and if that is not found uses def as default
      *
diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java
index 313bc82..a3889b2 100644
--- a/telephony/java/android/telephony/gsm/GsmCellLocation.java
+++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java
@@ -40,9 +40,9 @@
      * Initialize the object from a bundle.
      */
     public GsmCellLocation(Bundle bundle) {
-        mLac = bundle.getInt("lac", mLac);
-        mCid = bundle.getInt("cid", mCid);
-        mPsc = bundle.getInt("psc", mPsc);
+        mLac = bundle.getInt("lac", -1);
+        mCid = bundle.getInt("cid", -1);
+        mPsc = bundle.getInt("psc", -1);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index aae7617..c754068 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -34,7 +34,6 @@
 import android.text.TextUtils;
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
-import android.util.Log;
 
 /**
  * Helper class to make it easier to run asynchronous caller-id lookup queries.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62c8746..3769dee 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -863,11 +863,25 @@
     /**
      * Whether video calling has been enabled by the user.
      *
-     * @return {@code True} if the user has enabled video calling, {@code false} otherwise.
+     * @return {@code true} if the user has enabled video calling, {@code false} otherwise.
      */
     boolean isVideoCallingEnabled();
 
     /**
+     * Whether the DTMF tone length can be changed.
+     *
+     * @return {@code true} if the DTMF tone length can be changed.
+     */
+    boolean canChangeDtmfToneLength();
+
+    /**
+     * Whether the device is a world phone.
+     *
+     * @return {@code true} if the devices is a world phone.
+     */
+    boolean isWorldPhone();
+
+    /**
      * Get IMS Registration Status
      */
     boolean isImsRegistered();
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 92cd468..85a489b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.telephony;
 
-import android.content.Intent;
-
 /**
  * The intents that the telephony services broadcast.
  *
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index c89208d..0fccfa5 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -204,9 +204,4 @@
      * 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/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 3d763c7..3c4da9e 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -107,7 +107,7 @@
     }
 
     /**
-     * @param context : the context that will be delagated.
+     * @param context : the context that will be delegated.
      * @param filePrefix : a prefix with which database and file names will be
      * prefixed.
      */
@@ -118,8 +118,8 @@
     }
 
     /**
-     * @param context : the context that will be delagated.
-     * @param fileContext : the context that file and db methods will be delgated to
+     * @param context : the context that will be delegated.
+     * @param fileContext : the context that file and db methods will be delegated to
      * @param filePrefix : a prefix with which database and file names will be
      * prefixed.
      */
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index 67a0bc2..1b854b0 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -564,7 +564,7 @@
         final int fromX = xy[0];
         final int fromY = xy[1];
         
-        int distance = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+        int distance = (int) Math.hypot(deltaX, deltaY);
 
         drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
 
@@ -617,7 +617,7 @@
         int deltaX = fromX - toX;
         int deltaY = fromY - toY;
         
-        int distance = (int)Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+        int distance = (int)Math.hypot(deltaX, deltaY);
         drag(test, fromX, toX, fromY, toY, distance);
         
         return distance;
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 3378872..cfbebba 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -480,6 +480,11 @@
     }
 
     @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public int checkPermission(String permission, int pid, int uid) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/CropFilter.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/CropFilter.java
index 91fe21c..6c0f353 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/CropFilter.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/CropFilter.java
@@ -20,7 +20,6 @@
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.util.FloatMath;
 
 import androidx.media.filterfw.Filter;
 import androidx.media.filterfw.FrameImage2D;
@@ -90,8 +89,8 @@
         // Pull input frame
         FrameImage2D inputImage = getConnectedInputPort("image").pullFrame().asFrameImage2D();
         int[] inDims = inputImage.getDimensions();
-        int[] croppedDims = { (int)FloatMath.ceil(mCropRect.xEdge().length() * inDims[0]),
-                              (int)FloatMath.ceil(mCropRect.yEdge().length() * inDims[1]) };
+        int[] croppedDims = { (int)Math.ceil(mCropRect.xEdge().length() * inDims[0]),
+                              (int)Math.ceil(mCropRect.yEdge().length() * inDims[1]) };
         int[] outDims = { getOutputWidth(croppedDims[0], croppedDims[1]),
                 getOutputHeight(croppedDims[0], croppedDims[1]) };
         FrameImage2D outputImage = outPort.fetchAvailableFrame(outDims).asFrameImage2D();
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
index bc0e4e4..5f3d0d9 100644
--- a/tests/CoreTests/android/Android.mk
+++ b/tests/CoreTests/android/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_SRC_FILES := \
 	$(call all-subdir-java-files)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
+LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt org.apache.http.legacy
 
 LOCAL_PACKAGE_NAME := CoreTests
 
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
index 8331f0c..bf46d15 100644
--- a/tests/CoreTests/android/AndroidManifest.xml
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -35,6 +35,7 @@
     
     <application>
         <uses-library android:name="android.test.runner" />
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
     </application>
 
     <instrumentation
diff --git a/tests/CoreTests/android/core/InetAddrTest.java b/tests/CoreTests/android/core/InetAddrTest.java
deleted file mode 100644
index c7b89e1..0000000
--- a/tests/CoreTests/android/core/InetAddrTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import junit.framework.TestCase;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Random;
-
-import android.test.suitebuilder.annotation.Suppress;
-
-/**
- * Tests InetAddr class by checking methods to resolve domains to IP addresses
- * and by checking if the class returns correct addresses for local host address
- * and host name.
- */
-@Suppress
-public class InetAddrTest extends TestCase {
-    private static final String[] HOSTS = {
-            "localhost", "www.google.com", "www.slashdot.org", "www.wikipedia.org",
-            "www.paypal.com", "www.cnn.com", "www.yahoo.com", "www.amazon.com",
-            "www.ebay.com", "www.android.com"
-    };
-
-    public void testInetAddr() throws Exception {
-        byte[] raw;
-
-        InetAddress ia = InetAddress.getByName("localhost");
-
-        raw = ia.getAddress();
-
-        assertEquals(127, raw[0]);
-        assertEquals(0, raw[1]);
-        assertEquals(0, raw[2]);
-        assertEquals(1, raw[3]);
-
-        ia = InetAddress.getByName("127.0.0.1");
-
-        raw = ia.getAddress();
-
-        assertEquals(127, raw[0]);
-        assertEquals(0, raw[1]);
-        assertEquals(0, raw[2]);
-        assertEquals(1, raw[3]);
-
-        ia = InetAddress.getByName(null);
-
-        try {
-            InetAddress.getByName(".0.0.1");
-            fail("expected ex");
-        } catch (UnknownHostException ex) {
-            // expected
-        }
-
-        try {
-            InetAddress.getByName("thereisagoodchancethisdomaindoesnotexist.weirdtld");
-            fail("expected ex");
-        } catch (UnknownHostException ex) {
-            // expected
-        }
-
-        try {
-            InetAddress.getByName("127.0.0.");
-            fail("expected ex");
-        } catch (UnknownHostException ex) {
-            // expected
-        }
-
-        Random random = new Random();
-        int count = 0;
-        for (int i = 0; i < 100; i++) {
-            int index = random.nextInt(HOSTS.length);
-            try {
-                InetAddress.getByName(HOSTS[index]);
-                count++;
-                try {
-                    Thread.sleep(50);
-                } catch (InterruptedException ex) {
-                }
-            } catch (UnknownHostException ex) {
-            }
-        }
-        assertEquals("Not all host lookups succeeded", 100, count);
-    }
-}
diff --git a/tests/CoreTests/android/core/ProxyTest.java b/tests/CoreTests/android/core/ProxyTest.java
deleted file mode 100644
index 12acfe8..0000000
--- a/tests/CoreTests/android/core/ProxyTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import org.apache.http.HttpHost;
-
-import android.content.Context;
-import android.net.Proxy;
-import android.test.AndroidTestCase;
-
-/**
- * Proxy tests
- */
-public class ProxyTest extends AndroidTestCase {
-    private Context mContext;
-    private HttpHost mHttpHost;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext = getContext();
-        mHttpHost = null;
-        String proxyHost = Proxy.getHost(mContext);
-        int proxyPort = Proxy.getPort(mContext);
-        if (proxyHost != null) {
-            mHttpHost = new HttpHost(proxyHost, proxyPort, "http");
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    /**
-     * Bad url parameter should not cause any exception.
-     */
-    public void testProxyGetPreferredHttpHost_UrlBad() throws Exception {
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, null));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, ""));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad:\\"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "bad://#"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "://#"));
-    }
-
-    /**
-     * Proxy (if available) should be returned when url parameter is not localhost.
-     */
-    public void testProxyGetPreferredHttpHost_UrlNotlLocalhost() throws Exception {
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://example.com/"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "http://192.168.0.1/"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "file:///foo/bar"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "rtsp://example.com/"));
-        assertEquals(mHttpHost, Proxy.getPreferredHttpHost(mContext, "javascript:alert(1)"));
-    }
-
-    /**
-     * No proxy should be returned when url parameter is localhost.
-     */
-    public void testProxyGetPreferredHttpHost_UrlLocalhost() throws Exception {
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://localhost/hej.html"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1/hej.html"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:80/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "http://127.0.0.1:8080/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://127.0.0.1/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "rtsp://localhost/"));
-        assertNull(Proxy.getPreferredHttpHost(mContext, "https://localhost/"));
-    }
-}
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
deleted file mode 100644
index b06790b..0000000
--- a/tests/CoreTests/android/core/SSLSocketTest.java
+++ /dev/null
@@ -1,1094 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import junit.framework.TestCase;
-
-import com.android.org.conscrypt.FileClientSessionCache;
-import com.android.org.conscrypt.OpenSSLContextImpl;
-import com.android.org.conscrypt.SSLClientSessionCache;
-import org.apache.commons.codec.binary.Base64;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.security.KeyStore;
-import java.security.KeyManagementException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * SSL integration tests that hit real servers.
- */
-public class SSLSocketTest extends TestCase {
-
-    private static SSLSocketFactory clientFactory =
-            (SSLSocketFactory) SSLSocketFactory.getDefault();
-
-    /**
-     * Does a number of HTTPS requests on some host and consumes the response.
-     * We don't use the HttpsUrlConnection class, but do this on our own
-     * with the SSLSocket class. This gives us a chance to test the basic
-     * behavior of SSL.
-     *
-     * @param host      The host name the request is being sent to.
-     * @param port      The port the request is being sent to.
-     * @param path      The path being requested (e.g. "/index.html").
-     * @param outerLoop The number of times we reconnect and do the request.
-     * @param innerLoop The number of times we do the request for each
-     *                  connection (using HTTP keep-alive).
-     * @param delay     The delay after each request (in seconds).
-     * @throws IOException When a problem occurs.
-     */
-    private void fetch(SSLSocketFactory socketFactory, String host, int port,
-            boolean secure, String path, int outerLoop, int innerLoop,
-            int delay, int timeout) throws IOException {
-        InetSocketAddress address = new InetSocketAddress(host, port);
-
-        for (int i = 0; i < outerLoop; i++) {
-            // Connect to the remote host
-            Socket socket = secure ? socketFactory.createSocket()
-                    : new Socket();
-            if (timeout >= 0) {
-                socket.setKeepAlive(true);
-                socket.setSoTimeout(timeout * 1000);
-            }
-            socket.connect(address);
-
-            // Get the streams
-            OutputStream output = socket.getOutputStream();
-            PrintWriter writer = new PrintWriter(output);
-
-            try {
-                DataInputStream input = new DataInputStream(socket.getInputStream());
-                try {
-                    for (int j = 0; j < innerLoop; j++) {
-                        android.util.Log.d("SSLSocketTest",
-                                "GET https://" + host + path + " HTTP/1.1");
-
-                        // Send a request
-                        writer.println("GET https://" + host + path + " HTTP/1.1\r");
-                        writer.println("Host: " + host + "\r");
-                        writer.println("Connection: " +
-                                (j == innerLoop - 1 ? "Close" : "Keep-Alive")
-                                + "\r");
-                        writer.println("\r");
-                        writer.flush();
-
-                        int length = -1;
-                        boolean chunked = false;
-
-                        String line = input.readLine();
-
-                        if (line == null) {
-                            throw new IOException("No response from server");
-                            // android.util.Log.d("SSLSocketTest", "No response from server");
-                        }
-
-                        // Consume the headers, check content length and encoding type
-                        while (line != null && line.length() != 0) {
-//                    System.out.println(line);
-                            int dot = line.indexOf(':');
-                            if (dot != -1) {
-                                String key = line.substring(0, dot).trim();
-                                String value = line.substring(dot + 1).trim();
-
-                                if ("Content-Length".equalsIgnoreCase(key)) {
-                                    length = Integer.valueOf(value);
-                                } else if ("Transfer-Encoding".equalsIgnoreCase(key)) {
-                                    chunked = "Chunked".equalsIgnoreCase(value);
-                                }
-
-                            }
-                            line = input.readLine();
-                        }
-
-                        assertTrue("Need either content length or chunked encoding", length != -1
-                                || chunked);
-
-                        // Consume the content itself
-                        if (chunked) {
-                            length = Integer.parseInt(input.readLine(), 16);
-                            while (length != 0) {
-                                byte[] buffer = new byte[length];
-                                input.readFully(buffer);
-                                input.readLine();
-                                length = Integer.parseInt(input.readLine(), 16);
-                            }
-                            input.readLine();
-                        } else {
-                            byte[] buffer = new byte[length];
-                            input.readFully(buffer);
-                        }
-
-                        // Sleep for the given number of seconds
-                        try {
-                            Thread.sleep(delay * 1000);
-                        } catch (InterruptedException ex) {
-                            // Shut up!
-                        }
-                    }
-                } finally {
-                    input.close();
-                }
-            } finally {
-                writer.close();
-            }
-            // Close the connection
-            socket.close();
-        }
-    }
-
-    /**
-     * Invokes fetch() with the default socket factory.
-     */
-    private void fetch(String host, int port, boolean secure, String path,
-            int outerLoop, int innerLoop,
-            int delay, int timeout) throws IOException {
-        fetch(clientFactory, host, port, secure, path, outerLoop, innerLoop,
-                delay, timeout);
-    }
-
-    /**
-     * Does a single request for each of the hosts. Consumes the response.
-     *
-     * @throws IOException If a problem occurs.
-     */
-    public void testSimple() throws IOException {
-        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 1, 0, 60);
-        fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
-        fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
-        fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * closed in between.
-     *
-     * @throws IOException If a problem occurs.
-     */
-    public void testRepeatedClose() throws IOException {
-        fetch("www.fortify.net", 443, true, "/sslcheck.html", 10, 1, 0, 60);
-        fetch("mail.google.com", 443, true, "/mail/", 10, 1, 0, 60);
-        fetch("www.paypal.com", 443, true, "/", 10, 1, 0, 60);
-        fetch("www.yellownet.ch", 443, true, "/", 10, 1, 0, 60);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * kept alive in between.
-     *
-     * @throws IOException If a problem occurs.
-     */
-    public void testRepeatedKeepAlive() throws IOException {
-        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 0, 60);
-        fetch("mail.google.com", 443, true, "/mail/", 1, 10, 0, 60);
-
-        // These two don't accept keep-alive
-        // fetch("www.paypal.com", 443, "/", 1, 10);
-        // fetch("www.yellownet.ch", 443, "/", 1, 10);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * closed in between. Waits a couple of seconds after each request, but
-     * stays within a reasonable timeout. Expectation is that the connection
-     * stays open.
-     *
-     * @throws IOException If a problem occurs.
-     */
-    public void testShortTimeout() throws IOException {
-        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 5, 60);
-        fetch("mail.google.com", 443, true, "/mail/", 1, 10, 5, 60);
-
-        // These two don't accept keep-alive
-        // fetch("www.paypal.com", 443, "/", 1, 10);
-        // fetch("www.yellownet.ch", 443, "/", 1, 10);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * kept alive in between. Waits a longer time after each request.
-     * Expectation is that the host closes the connection.
-     */
-    public void testLongTimeout() {
-        // Seems to have a veeeery long timeout.
-        // fetch("www.fortify.net", 443, "/sslcheck.html", 1, 2, 60);
-
-        // Google has a 60s timeout, so 90s of waiting should trigger it.
-        try {
-            fetch("mail.google.com", 443, true, "/mail/", 1, 2, 90, 180);
-            fail("Oops - timeout expected.");
-        } catch (IOException ex) {
-            // Expected.
-        }
-
-        // These two don't accept keep-alive
-        // fetch("www.paypal.com", 443, "/", 1, 10);
-        // fetch("www.yellownet.ch", 443, "/", 1, 10);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * closed in between. Waits a longer time after each request. Expectation is
-     * that the host closes the connection.
-     */
-    // These two need manual interaction to reproduce...
-    public void xxtestBrokenConnection() {
-        try {
-            fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 2, 60, 60);
-            fail("Oops - timeout expected.");
-        } catch (IOException ex) {
-            android.util.Log.d("SSLSocketTest", "Exception", ex);
-            // Expected.
-        }
-
-        // These two don't accept keep-alive
-        // fetch("www.paypal.com", 443, "/", 1, 10);
-        // fetch("www.yellownet.ch", 443, "/", 1, 10);
-    }
-
-    /**
-     * Does repeated requests for each of the hosts, with the connection being
-     * closed in between. Waits a longer time after each request. Expectation is
-     * that the host closes the connection.
-     */
-    // These two need manual interaction to reproduce...
-    public void xxtestBrokenConnection2() {
-        try {
-            fetch("www.heise.de", 80, false, "/index.html", 1, 2, 60, 60);
-            fail("Oops - timeout expected.");
-        } catch (IOException ex) {
-            android.util.Log.d("SSLSocketTest", "Exception", ex);
-            // Expected.
-        }
-
-        // These two don't accept keep-alive
-        // fetch("www.paypal.com", 443, "/", 1, 10);
-        // fetch("www.yellownet.ch", 443, "/", 1, 10);
-    }
-
-    /**
-     * Regression test for 865926: SSLContext.init() should
-     * use default values for null arguments.
-     */
-    public void testContextInitNullArgs() throws Exception {
-            SSLContext ctx = SSLContext.getInstance("TLS");
-            ctx.init(null, null, null);
-    }
-
-    /**
-     * Regression test for 963650: javax.net.ssl.KeyManager has no implemented
-     * (documented?) algorithms.
-     */
-    public void testDefaultAlgorithms() throws Exception {
-            SSLContext ctx = SSLContext.getInstance("TLS");
-            KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
-            KeyStore ks = KeyStore.getInstance("BKS");
-
-            assertEquals("X509", kmf.getAlgorithm());
-            assertEquals("X509", KeyManagerFactory.getDefaultAlgorithm());
-
-            assertEquals("BKS", ks.getType());
-            assertEquals("BKS", KeyStore.getDefaultType());
-    }
-
-    /**
-     * Regression test for problem where close() resulted in a hand if
-     * a different thread was sitting in a blocking read or write.
-     */
-    public void testMultithreadedClose() throws Exception {
-            InetSocketAddress address = new InetSocketAddress("www.fortify.net", 443);
-            final Socket socket = clientFactory.createSocket();
-            socket.connect(address);
-
-            Thread reader = new Thread() {
-                @Override
-                public void run() {
-                    try {
-                        byte[] buffer = new byte[512];
-                        InputStream stream = socket.getInputStream();
-                        socket.getInputStream().read(buffer);
-                    } catch (Exception ex) {
-                        android.util.Log.d("SSLSocketTest",
-                                "testMultithreadedClose() reader got " + ex.toString());
-                    }
-                }
-            };
-
-            Thread closer = new Thread() {
-                @Override
-                public void run() {
-                    try {
-                        Thread.sleep(5000);
-                        socket.close();
-                    } catch (Exception ex) {
-                        android.util.Log.d("SSLSocketTest",
-                                "testMultithreadedClose() closer got " + ex.toString());
-                    }
-                }
-            };
-
-            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting reader...");
-            reader.start();
-            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting closer...");
-            closer.start();
-
-            long t1 = System.currentTimeMillis();
-            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining reader...");
-            reader.join(30000);
-            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining closer...");
-            closer.join(30000);
-            long t2 = System.currentTimeMillis();
-
-            assertTrue("Concurrent close() hangs", t2 - t1 < 30000);
-    }
-
-    private int multithreadedFetchRuns;
-
-    private int multithreadedFetchWins;
-
-    private Random multithreadedFetchRandom = new Random();
-
-    /**
-     * Regression test for problem where multiple threads with multiple SSL
-     * connection would cause problems due to either missing native locking
-     * or the slowness of the SSL connections.
-     */
-    public void testMultithreadedFetch() {
-        Thread[] threads = new Thread[10];
-
-        for (int i = 0; i < threads.length; i++) {
-            threads[i] = new Thread() {
-                @Override
-                public void run() {
-                    for (int i = 0; i < 10; i++) {
-                        try {
-                            multithreadedFetchRuns++;
-                            switch (multithreadedFetchRandom.nextInt(4)) {
-                                case 0: {
-                                    fetch("www.fortify.net", 443,
-                                            true, "/sslcheck.html", 1, 1, 0, 60);
-                                    break;
-                                }
-
-                                case 1: {
-                                    fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
-                                    break;
-                                }
-
-                                case 2: {
-                                    fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
-                                    break;
-                                }
-
-                                case 3: {
-                                    fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
-                                    break;
-                                }
-                            }
-                            multithreadedFetchWins++;
-                        } catch (Exception ex) {
-                            android.util.Log.d("SSLSocketTest",
-                                    "testMultithreadedFetch() got Exception", ex);
-                        }
-                    }
-                }
-            };
-            threads[i].start();
-
-            android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() started thread #" + i);
-        }
-
-        for (int i = 0; i < threads.length; i++) {
-            try {
-                threads[i].join();
-                android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() joined thread #" + i);
-            } catch (InterruptedException ex) {
-                // Not interested.
-            }
-        }
-
-        assertTrue("At least 95% of multithreaded SSL connections must succeed",
-                multithreadedFetchWins >= (multithreadedFetchRuns * 95) / 100);
-    }
-
-    // -------------------------------------------------------------------------
-    // Regression test for #1204316: Missing client cert unit test. Passes on
-    // both Android and the RI. To use on the RI, install Apache Commons and
-    // replace the references to the base64-encoded keys by the JKS versions.
-    // -------------------------------------------------------------------------
-    
-    /** 
-     * Defines the keystore contents for the server, JKS version. Holds just a
-     * single self-generated key. The subject name is "Test Server".
-     */
-    private static final String SERVER_KEYS_JKS = 
-        "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFfBeAAAArowggK2MA4GCisGAQQBKgIRAQEFAASC" +
-        "AqI2kp5XjnF8YZkhcF92YsJNQkvsmH7zqMM87j23zSoV4DwyE3XeC/gZWq1ToScIhoqZkzlbWcu4" +
-        "T/Zfc/DrfGk/rKbBL1uWKGZ8fMtlZk8KoAhxZk1JSyJvdkyKxqmzUbxk1OFMlN2VJNu97FPVH+du" +
-        "dvjTvmpdoM81INWBW/1fZJeQeDvn4mMbbe0IxgpiLnI9WSevlaDP/sm1X3iO9yEyzHLL+M5Erspo" +
-        "Cwa558fOu5DdsICMXhvDQxjWFKFhPHnKtGe+VvwkG9/bAaDgx3kfhk0w5zvdnkKb+8Ed9ylNRzdk" +
-        "ocAa/mxlMTOsTvDKXjjsBupNPIIj7OP4GNnZaxkJjSs98pEO67op1GX2qhy6FSOPNuq8k/65HzUc" +
-        "PYn6voEeh6vm02U/sjEnzRevQ2+2wXoAdp0EwtQ/DlMe+NvcwPGWKuMgX4A4L93DZGb04N2VmAU3" +
-        "YLOtZwTO0LbuWrcCM/q99G/7LcczkxIVrO2I/rh8RXVczlf9QzcrFObFv4ATuspWJ8xG7DhsMbnk" +
-        "rT94Pq6TogYeoz8o8ZMykesAqN6mt/9+ToIemmXv+e+KU1hI5oLwWMnUG6dXM6hIvrULY6o+QCPH" +
-        "172YQJMa+68HAeS+itBTAF4Clm/bLn6reHCGGU6vNdwU0lYldpiOj9cB3t+u2UuLo6tiFWjLf5Zs" +
-        "EQJETd4g/EK9nHxJn0GAKrWnTw7pEHQJ08elzUuy04C/jEEG+4QXU1InzS4o/kR0Sqz2WTGDoSoq" +
-        "ewuPRU5bzQs/b9daq3mXrnPtRBL6HfSDAdpTK76iHqLCGdqx3avHjVSBm4zFvEuYBCev+3iKOBmg" +
-        "yh7eQRTjz4UOWfy85omMBr7lK8PtfVBDzOXpasxS0uBgdUyBDX4tO6k9jZ8a1kmQRQAAAAEABVgu" +
-        "NTA5AAACSDCCAkQwggGtAgRIR8SKMA0GCSqGSIb3DQEBBAUAMGkxCzAJBgNVBAYTAlVTMRMwEQYD" +
-        "VQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMH" +
-        "QW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBTZXJ2ZXIwHhcNMDgwNjA1MTA0ODQyWhcNMDgwOTAzMTA0" +
-        "ODQyWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8w" +
-        "DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGf" +
-        "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwoC6chqCI84rj1PrXuJgbiit4EV909zR6N0jNlYfg" +
-        "itwB39bP39wH03rFm8T59b3mbSptnGmCIpLZn25KPPFsYD3JJ+wFlmiUdEP9H05flfwtFQJnw9uT" +
-        "3rRIdYVMPcQ3RoZzwAMliGr882I2thIDbA6xjGU/1nRIdvk0LtxH3QIDAQABMA0GCSqGSIb3DQEB" +
-        "BAUAA4GBAJn+6YgUlY18Ie+0+Vt8oEi81DNi/bfPrAUAh63fhhBikx/3R9dl3wh09Z6p7cIdNxjW" +
-        "n2ll+cRW9eqF7z75F0Omm0C7/KAEPjukVbszmzeU5VqzkpSt0j84YWi+TfcHRrfvhLbrlmGITVpY" +
-        "ol5pHLDyqGmDs53pgwipWqsn/nEXEBgj3EoqPeqHbDf7YaP8h/5BSt0=";
-
-    /** 
-     * Defines the keystore contents for the server, BKS version. Holds just a
-     * single self-generated key. The subject name is "Test Server".
-     */
-    private static final String SERVER_KEYS_BKS = 
-        "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" +
-        "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
-        "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
-        "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" +
-        "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
-        "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" +
-        "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" +
-        "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" +
-        "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" +
-        "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" +
-        "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" +
-        "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" +
-        "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" +
-        "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" +
-        "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" +
-        "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" +
-        "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" +
-        "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" +
-        "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" +
-        "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" +
-        "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" +
-        "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" +
-        "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
-        "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
-    
-    /** 
-     * Defines the keystore contents for the client, JKS version. Holds just a
-     * single self-generated key. The subject name is "Test Client".
-     */
-    private static final String CLIENT_KEYS_JKS = 
-        "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFhyMAAAArkwggK1MA4GCisGAQQBKgIRAQEFAASC" +
-        "AqGVSfXolBStZy4nnRNn4fAr+S7kfU2BS23wwW8uB2Ru3GvtLzlK9q08Gvq/LNqBafjyFTVL5FV5" +
-        "SED/8YomO5a98GpskSeRvytCiTBLJdgGhws5TOGekgIAcBROPGIyOtJPQ0HfOQs+BqgzGDHzHQhw" +
-        "u/8Tm6yQwiP+W/1I9B1QnaEztZA3mhTyMMJsmsFTYroGgAog885D5Cmzd8sYGfxec3R6I+xcmBAY" +
-        "eibR5kGpWwt1R+qMvRrtBqh5r6WSKhCBNax+SJVbtUNRiKyjKccdJg6fGqIWWeivwYTy0OhjA6b4" +
-        "NiZ/ZZs5pxFGWUj/Rlp0RYy8fCF6aw5/5s4Bf4MI6dPSqMG8Hf7sJR91GbcELyzPdM0h5lNavgit" +
-        "QPEzKeuDrGxhY1frJThBsNsS0gxeu+OgfJPEb/H4lpYX5IvuIGbWKcxoO9zq4/fimIZkdA8A+3eY" +
-        "mfDaowvy65NBVQPJSxaOyFhLHfeLqOeCsVENAea02vA7andZHTZehvcrqyKtm+z8ncHGRC2H9H8O" +
-        "jKwKHfxxrYY/jMAKLl00+PBb3kspO+BHI2EcQnQuMw/zr83OR9Meq4TJ0TMuNkApZELAeFckIBbS" +
-        "rBr8NNjAIfjuCTuKHhsTFWiHfk9ZIzigxXagfeDRiyVc6khOuF/bGorj23N2o7Rf3uLoU6PyXWi4" +
-        "uhctR1aL6NzxDoK2PbYCeA9hxbDv8emaVPIzlVwpPK3Ruvv9mkjcOhZ74J8bPK2fQmbplbOljcZi" +
-        "tZijOfzcO/11JrwhuJZRA6wanTqHoujgChV9EukVrmbWGGAcewFnAsSbFXIik7/+QznXaDIt5NgL" +
-        "H/Bcz4Z/fdV7Ae1eUaxKXdPbI//4J+8liVT/d8awjW2tldIaDlmGMR3aoc830+3mAAAAAQAFWC41" +
-        "MDkAAAJIMIICRDCCAa0CBEhHxLgwDQYJKoZIhvcNAQEEBQAwaTELMAkGA1UEBhMCVVMxEzARBgNV" +
-        "BAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01UVjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdB" +
-        "bmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVudDAeFw0wODA2MDUxMDQ5MjhaFw0wODA5MDMxMDQ5" +
-        "MjhaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzAN" +
-        "BgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBDbGllbnQwgZ8w" +
-        "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIK3Q+KiFbmCGg422TAo4gggdhMH6FJhiuz8DxRyeMKR" +
-        "UAfP4MK0wtc8N42waZ6OKvxpBFUy0BRfBsX0GD4Ku99yu9/tavSigTraeJtwV3WWRRjIqk7L3wX5" +
-        "cmgS2KSD43Y0rNUKrko26lnt9N4qiYRBSj+tcAN3Lx9+ptqk1LApAgMBAAEwDQYJKoZIhvcNAQEE" +
-        "BQADgYEANb7Q1GVSuy1RPJ0FmiXoMYCCtvlRLkmJphwxovK0cAQK12Vll+yAzBhHiQHy/RA11mng" +
-        "wYudC7u3P8X/tBT8GR1Yk7QW3KgFyPafp3lQBBCraSsfrjKj+dCLig1uBLUr4f68W8VFWZWWTHqp" +
-        "NMGpCX6qmjbkJQLVK/Yfo1ePaUexPSOX0G9m8+DoV3iyNw6at01NRw==";
-
-    /** 
-     * Defines the keystore contents for the client, BKS version. Holds just a
-     * single self-generated key. The subject name is "Test Client".
-     */
-    private static final String CLIENT_KEYS_BKS = 
-        "AAAAAQAAABT4Rka6fxbFps98Y5k2VilmbibNkQAABfQEAAVteWtleQAAARpYl+POAAAAAQAFWC41" +
-        "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU9TANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
-        "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
-        "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgQ2xpZW50MB4XDTA4MDYwNTExNTg0NVoXDTA4MDkw" +
-        "MzExNTg0NVowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
-        "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVu" +
-        "dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApUvmWsQDHPpbDKK13Yez2/q54tTOmRml/qva" +
-        "2K6dZjkjSTW0iRuk7ztaVEvdJpfVIDv1oBsCI51ttyLHROy1epjF+GoL74mJb7fkcd0VOoSOTjtD" +
-        "+3GgZkHPAm5YmUYxiJXqxKKJJqMCTIW46eJaA2nAep9QIwZ14/NFAs4ObV8CAwEAATANBgkqhkiG" +
-        "9w0BAQUFAAOBgQCJrCr3hZQFDlLIfsSKI1/w+BLvyf4fubOid0pBxfklR8KBNPTiqjSmu7pd/C/F" +
-        "1FR8CdZUDoPflZHCOU+fj5r5KUC1HyigY/tEUvlforBpfB0uCF+tXW4DbUfOWhfMtLV4nCOJOOZg" +
-        "awfZLJWBJouLKOp427vDftxTSB+Ks8YjlgAAAqwAAAAU+NH6TtrzjyDdCXm5B6Vo7xX5G4YAAAZx" +
-        "EAUkcZtmykn7YdaYxC1jRFJ+GEJpC8nZVg83QClVuCSIS8a5f8Hl44Bk4oepOZsPzhtz3RdVzDVi" +
-        "RFfoyZFsrk9F5bDTVJ6sQbb/1nfJkLhZFXokka0vND5AXMSoD5Bj1Fqem3cK7fSUyqKvFoRKC3XD" +
-        "FQvhqoam29F1rbl8FaYdPvhhZo8TfZQYUyUKwW+RbR44M5iHPx+ykieMe/C/4bcM3z8cwIbYI1aO" +
-        "gjQKS2MK9bs17xaDzeAh4sBKrskFGrDe+2dgvrSKdoakJhLTNTBSG6m+rzqMSCeQpafLKMSjTSSz" +
-        "+KoQ9bLyax8cbvViGGju0SlVhquloZmKOfHr8TukIoV64h3uCGFOVFtQjCYDOq6NbfRvMh14UVF5" +
-        "zgDIGczoD9dMoULWxBmniGSntoNgZM+QP6Id7DBasZGKfrHIAw3lHBqcvB5smemSu7F4itRoa3D8" +
-        "N7hhUEKAc+xA+8NKmXfiCBoHfPHTwDvt4IR7gWjeP3Xv5vitcKQ/MAfO5RwfzkYCXQ3FfjfzmsE1" +
-        "1IfLRDiBj+lhQSulhRVStKI88Che3M4JUNGKllrc0nt1pWa1vgzmUhhC4LSdm6trTHgyJnB6OcS9" +
-        "t2furYjK88j1AuB4921oxMxRm8c4Crq8Pyuf+n3YKi8Pl2BzBtw++0gj0ODlgwut8SrVj66/nvIB" +
-        "jN3kLVahR8nZrEFF6vTTmyXi761pzq9yOVqI57wJGx8o3Ygox1p+pWUPl1hQR7rrhUbgK/Q5wno9" +
-        "uJk07h3IZnNxE+/IKgeMTP/H4+jmyT4mhsexJ2BFHeiKF1KT/FMcJdSi+ZK5yoNVcYuY8aZbx0Ef" +
-        "lHorCXAmLFB0W6Cz4KPP01nD9YBB4olxiK1t7m0AU9zscdivNiuUaB5OIEr+JuZ6dNw=";    
-    /** 
-     * Defines the password for the keystore.
-     */
-    private static final String PASSWORD = "android";
-            
-    /** 
-     * Implements basically a dummy TrustManager. It stores the certificate
-     * chain it sees, so it can later be queried.
-     */
-    class TestTrustManager implements X509TrustManager {
-        
-        private X509Certificate[] chain;
-        
-        private String authType;
-        
-        public void checkClientTrusted(X509Certificate[] chain, String authType) {
-            this.chain = chain;
-            this.authType = authType;
-        }
-
-        public void checkServerTrusted(X509Certificate[] chain, String authType) {
-            this.chain = chain;
-            this.authType = authType;
-        }
-
-        public X509Certificate[] getAcceptedIssuers() {
-            return new X509Certificate[0];
-        }
-
-        public X509Certificate[] getChain() {
-            return chain;
-        }
-        
-        public String getAuthType() {
-            return authType;
-        }
-        
-    }
-    
-    /** 
-     * Implements a test SSL socket server. It wait for a connection on a given
-     * port, requests client authentication (if specified), and read 256 bytes
-     * from the socket. 
-     */
-    class TestServer implements Runnable {
-
-        public static final int CLIENT_AUTH_NONE = 0;
-
-        public static final int CLIENT_AUTH_WANTED = 1;
-
-        public static final int CLIENT_AUTH_NEEDED = 2;
-        
-        private TestTrustManager trustManager;
-
-        private Exception exception;
-
-        private int port;
-        
-        private int clientAuth;
-        
-        private boolean provideKeys;
-
-        public TestServer(int port, boolean provideKeys, int clientAuth) {
-            this.port = port;
-            this.clientAuth = clientAuth;
-            this.provideKeys = provideKeys;
-            
-            trustManager = new TestTrustManager(); 
-        }
-        
-        public void run() {
-            try {
-                KeyManager[] keyManagers = provideKeys
-                        ? getKeyManagers(SERVER_KEYS_BKS) : null;
-                TrustManager[] trustManagers = new TrustManager[] {
-                        trustManager };
-
-                SSLContext sslContext = SSLContext.getInstance("TLS");
-                sslContext.init(keyManagers, trustManagers, null);
-                
-                SSLServerSocket serverSocket
-                        = (SSLServerSocket) sslContext.getServerSocketFactory()
-                        .createServerSocket();
-                
-                if (clientAuth == CLIENT_AUTH_WANTED) {
-                    serverSocket.setWantClientAuth(true);
-                } else if (clientAuth == CLIENT_AUTH_NEEDED) {
-                    serverSocket.setNeedClientAuth(true);
-                } else {
-                    serverSocket.setWantClientAuth(false);
-                }
-                
-                serverSocket.bind(new InetSocketAddress(port));
-                
-                SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
-
-                InputStream stream = clientSocket.getInputStream();
-
-                for (int i = 0; i < 256; i++) {
-                    int j = stream.read();
-                    if (i != j) {
-                        throw new RuntimeException("Error reading socket,"
-                                + " expected " + i + ", got " + j);
-                    }
-                }
-                
-                stream.close();
-                clientSocket.close();
-                serverSocket.close();
-                
-            } catch (Exception ex) {
-                exception = ex;
-            }
-        }
-
-        public Exception getException() {
-            return exception;
-        }
-        
-        public X509Certificate[] getChain() {
-            return trustManager.getChain();
-        }
-        
-    }
-
-    /** 
-     * Implements a test SSL socket client. It open a connection to localhost on
-     * a given port and writes 256 bytes to the socket. 
-     */
-    class TestClient implements Runnable {
-        
-        private TestTrustManager trustManager;
-
-        private Exception exception;
-        
-        private int port;
-        
-        private boolean provideKeys;
-        
-        public TestClient(int port, boolean provideKeys) {
-            this.port = port;
-            this.provideKeys = provideKeys;
-            
-            trustManager = new TestTrustManager(); 
-        }
-        
-        public void run() {
-            try {
-                KeyManager[] keyManagers = provideKeys
-                        ? getKeyManagers(CLIENT_KEYS_BKS) : null;
-                TrustManager[] trustManagers = new TrustManager[] {
-                        trustManager };
-
-                SSLContext sslContext = SSLContext.getInstance("TLS");
-                sslContext.init(keyManagers, trustManagers, null);
-                
-                SSLSocket socket = (SSLSocket) sslContext.getSocketFactory()
-                        .createSocket();
-
-                socket.connect(new InetSocketAddress(port));
-                socket.startHandshake();
-
-                OutputStream stream = socket.getOutputStream();
-                
-                for (int i = 0; i < 256; i++) {
-                    stream.write(i);
-                }
-                
-                stream.flush();
-                stream.close();
-                socket.close();
-                
-            } catch (Exception ex) {
-                exception = ex;
-            }
-        }
-
-        public Exception getException() {
-            return exception;
-        }
-
-        public X509Certificate[] getChain() {
-            return trustManager.getChain();
-        }
-        
-    }
-    
-    /**
-     * Loads a keystore from a base64-encoded String. Returns the KeyManager[]
-     * for the result.
-     */
-    private KeyManager[] getKeyManagers(String keys) throws Exception {
-        byte[] bytes = new Base64().decode(keys.getBytes());                    
-        InputStream inputStream = new ByteArrayInputStream(bytes);
-        
-        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
-        keyStore.load(inputStream, PASSWORD.toCharArray());
-        inputStream.close();
-        
-        String algorithm = KeyManagerFactory.getDefaultAlgorithm();
-        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
-        keyManagerFactory.init(keyStore, PASSWORD.toCharArray());
-        
-        return keyManagerFactory.getKeyManagers();
-    }
-
-    /**
-     * Implements the actual test case. Launches a server and a client, requires
-     * client authentication and checks the certificates afterwards (not in the
-     * usual sense, we just make sure that we got the expected certificates,
-     * because our self-signed test certificates are not valid.)
-     */
-    public void testClientAuth() {
-        try {
-            TestServer server = new TestServer(8088, true, TestServer.CLIENT_AUTH_WANTED);
-            TestClient client = new TestClient(8088, true);
-            
-            Thread serverThread = new Thread(server);
-            Thread clientThread = new Thread(client);
-            
-            serverThread.start();
-            clientThread.start();
-            
-            serverThread.join();
-            clientThread.join();
-            
-            // The server must have completed without an exception.
-            if (server.getException() != null) {
-                throw new RuntimeException(server.getException());
-            }
-
-            // The client must have completed without an exception.
-            if (client.getException() != null) {
-                throw new RuntimeException(client.getException());
-            }
-            
-            // Caution: The clientChain is the certificate chain from our
-            // client object. It contains the server certificates, of course!
-            X509Certificate[] clientChain = client.getChain();
-            assertTrue("Client cert chain must not be null", clientChain != null);
-            assertTrue("Client cert chain must not be empty", clientChain.length != 0);
-            assertEquals("CN=Test Server, OU=Android, O=Google, L=MTV, ST=California, C=US", clientChain[0].getSubjectDN().toString());
-            // Important part ------^
-            
-            // Caution: The serverChain is the certificate chain from our
-            // server object. It contains the client certificates, of course!
-            X509Certificate[] serverChain = server.getChain();
-            assertTrue("Server cert chain must not be null", serverChain != null);
-            assertTrue("Server cert chain must not be empty", serverChain.length != 0);
-            assertEquals("CN=Test Client, OU=Android, O=Google, L=MTV, ST=California, C=US", serverChain[0].getSubjectDN().toString());
-            // Important part ------^
-            
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    // -------------------------------------------------------------------------
-    private SSLSocket handshakeSocket;
-
-    private Exception handshakeException;
-
-    
-    public void testSSLHandshakeHangTimeout() {
-        
-        Thread thread = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    SSLSocket socket = (SSLSocket)clientFactory.createSocket(
-                            "www.heise.de", 80);
-                    socket.setSoTimeout(5000);
-                    socket.startHandshake();
-                    socket.close();
-                } catch (Exception ex) {
-                    handshakeException = ex;
-                }
-            }
-        };
-        
-        thread.start();
-        
-        try {
-            thread.join(10000);
-        } catch (InterruptedException ex) {
-            // Ignore.
-        }
-        
-        if (handshakeException == null) {
-            fail("SSL handshake should have failed.");
-        }
-    }
-
-    public void testSSLHandshakeHangClose() {
-        
-        Thread thread = new Thread() {
-            @Override
-            public void run() {
-                try {
-                    handshakeSocket = (SSLSocket)clientFactory.createSocket(
-                            "www.heise.de", 80);
-                    handshakeSocket.startHandshake();
-                } catch (Exception ex) {
-                    handshakeException = ex;
-                }
-            }
-        };
-        
-        thread.start();
-
-        
-        try {
-            Thread.sleep(5000);
-            try {
-                handshakeSocket.close();
-            } catch (Exception ex) {
-                throw new RuntimeException(ex);
-            }
-
-            thread.join(5000);
-        } catch (InterruptedException ex) {
-            // Ignore.
-        }
-        
-        if (handshakeException == null) {
-            fail("SSL handshake should have failed.");
-        }
-    }
-
-    /**
-     * Tests our in-memory and persistent caching support.
-     */
-    public void testClientSessionCaching() throws IOException,
-            KeyManagementException {
-        OpenSSLContextImpl context = new OpenSSLContextImpl();
-
-        // Cache size = 2.
-        FakeClientSessionCache fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null);
-        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
-        SSLSocketFactory socketFactory = context.engineGetSocketFactory();
-        context.engineGetClientSessionContext().setSessionCacheSize(2);
-        makeRequests(socketFactory);
-        List<String> smallCacheOps = Arrays.asList(
-                "get www.fortify.net",
-                "put www.fortify.net",
-                "get www.paypal.com",
-                "put www.paypal.com",
-                "get www.yellownet.ch",
-                "put www.yellownet.ch",
-
-                // At this point, all in-memory cache requests should miss,
-                // but the sessions will still be in the persistent cache.
-                "get www.fortify.net",
-                "get www.paypal.com",
-                "get www.yellownet.ch"
-        );
-        assertEquals(smallCacheOps, fakeCache.ops);
-
-        // Cache size = 3.
-        fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null);
-        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
-        socketFactory = context.engineGetSocketFactory();
-        context.engineGetClientSessionContext().setSessionCacheSize(3);
-        makeRequests(socketFactory);
-        List<String> bigCacheOps = Arrays.asList(
-                "get www.fortify.net",
-                "put www.fortify.net",
-                "get www.paypal.com",
-                "put www.paypal.com",
-                "get www.yellownet.ch",
-                "put www.yellownet.ch"
-
-                // At this point, all results should be in the in-memory
-                // cache, and the persistent cache shouldn't be hit anymore.
-        );
-        assertEquals(bigCacheOps, fakeCache.ops);
-
-        // Cache size = 4.
-        fakeCache = new FakeClientSessionCache();
-        context.engineInit(null, null, null);
-        context.engineGetClientSessionContext().setPersistentCache(fakeCache);
-        socketFactory = context.engineGetSocketFactory();
-        context.engineGetClientSessionContext().setSessionCacheSize(4);
-        makeRequests(socketFactory);
-        assertEquals(bigCacheOps, fakeCache.ops);
-    }
-
-    /**
-     * Executes sequence of requests twice using given socket factory.
-     */
-    private void makeRequests(SSLSocketFactory socketFactory)
-            throws IOException {
-        for (int i = 0; i < 2; i++) {
-            fetch(socketFactory, "www.fortify.net", 443, true, "/sslcheck.html",
-                    1, 1, 0, 60);
-            fetch(socketFactory, "www.paypal.com", 443, true, "/",
-                    1, 1, 0, 60);
-            fetch(socketFactory, "www.yellownet.ch", 443, true, "/",
-                    1, 1, 0, 60);
-        }
-    }
-
-    /**
-     * Fake in the sense that it doesn't actually persist anything.
-     */
-    static class FakeClientSessionCache implements SSLClientSessionCache {
-
-        List<String> ops = new ArrayList<String>();
-        Map<String, byte[]> sessions = new HashMap<String, byte[]>();
-
-        public byte[] getSessionData(String host, int port) {
-            ops.add("get " + host);
-            return sessions.get(host);
-        }
-
-        public void putSessionData(SSLSession session, byte[] sessionData) {
-            String host = session.getPeerHost();
-            System.err.println("length: " + sessionData.length);
-            ops.add("put " + host);
-            sessions.put(host, sessionData);
-        }
-    }
-
-    public void testFileBasedClientSessionCache() throws IOException,
-            KeyManagementException {
-        OpenSSLContextImpl context = new OpenSSLContextImpl();
-        String tmpDir = System.getProperty("java.io.tmpdir");
-        if (tmpDir == null) {
-            fail("Please set 'java.io.tmpdir' system property.");
-        }
-        File cacheDir = new File(tmpDir
-                + "/" + SSLSocketTest.class.getName() + "/cache");
-        deleteDir(cacheDir);
-        SSLClientSessionCache fileCache
-                = FileClientSessionCache.usingDirectory(cacheDir);
-        try {
-            ClientSessionCacheProxy cacheProxy
-                    = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null);
-            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
-            SSLSocketFactory socketFactory = context.engineGetSocketFactory();
-            context.engineGetClientSessionContext().setSessionCacheSize(1);
-            makeRequests(socketFactory);
-            List<String> expected = Arrays.asList(
-                    "unsuccessful get www.fortify.net",
-                    "put www.fortify.net",
-                    "unsuccessful get www.paypal.com",
-                    "put www.paypal.com",
-                    "unsuccessful get www.yellownet.ch",
-                    "put www.yellownet.ch",
-
-                    // At this point, all in-memory cache requests should miss,
-                    // but the sessions will still be in the persistent cache.
-                    "successful get www.fortify.net",
-                    "successful get www.paypal.com",
-                    "successful get www.yellownet.ch"
-            );
-            assertEquals(expected, cacheProxy.ops);
-
-            // Try again now that file-based cache is populated.
-            fileCache = FileClientSessionCache.usingDirectory(cacheDir);
-            cacheProxy = new ClientSessionCacheProxy(fileCache);
-            context.engineInit(null, null, null);
-            context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
-            socketFactory = context.engineGetSocketFactory();
-            context.engineGetClientSessionContext().setSessionCacheSize(1);
-            makeRequests(socketFactory);
-            expected = Arrays.asList(
-                    "successful get www.fortify.net",
-                    "successful get www.paypal.com",
-                    "successful get www.yellownet.ch",
-                    "successful get www.fortify.net",
-                    "successful get www.paypal.com",
-                    "successful get www.yellownet.ch"
-            );
-            assertEquals(expected, cacheProxy.ops);
-        } finally {
-            deleteDir(cacheDir);
-        }
-    }
-
-    private static void deleteDir(File directory) {
-        if (!directory.exists()) {
-            return;
-        }
-        for (File file : directory.listFiles()) {
-            file.delete();
-        }
-        directory.delete();
-    }
-
-    static class ClientSessionCacheProxy implements SSLClientSessionCache {
-
-        final SSLClientSessionCache delegate;
-        final List<String> ops = new ArrayList<String>();
-
-        ClientSessionCacheProxy(SSLClientSessionCache delegate) {
-            this.delegate = delegate;
-        }
-
-        public byte[] getSessionData(String host, int port) {
-            byte[] sessionData = delegate.getSessionData(host, port);
-            ops.add((sessionData == null ? "unsuccessful" : "successful")
-                    + " get " + host);
-            return sessionData;
-        }
-
-        public void putSessionData(SSLSession session, byte[] sessionData) {
-            delegate.putSessionData(session, sessionData);
-            ops.add("put " + session.getPeerHost());
-        }
-    }
-
-    public static void main(String[] args) throws KeyManagementException, IOException {
-        new SSLSocketTest().testFileBasedClientSessionCache();
-    }
-}
diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java
deleted file mode 100644
index 9db6077..0000000
--- a/tests/CoreTests/android/core/SocketTest.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.nio.channels.SocketChannel;
-import java.util.concurrent.Semaphore;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-/**
- * Regression tests for various socket related problems. And a few general
- * socket tests.
- */
-public class SocketTest extends TestCase {
-
-    private static final String NON_EXISTING_ADDRESS = "123.123.123.123";
-
-    private static final String KNOW_GOOD_ADDRESS = "209.85.129.147";
-
-    private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1";
-    
-    // Test for basic bind/connect/accept behavior.
-    @SmallTest
-    public void testSocketSimple() throws Exception {
-        ServerSocket ss;
-        Socket s, s1;
-        int port;
-
-        IOException lastEx = null;
-
-        ss = new ServerSocket();
-
-        for (port = 9900; port < 9999; port++) {
-            try {
-                ss.bind(new InetSocketAddress("127.0.0.1", port));
-                lastEx = null;
-                break;
-            } catch (IOException ex) {
-                lastEx = ex;
-            }
-        }
-
-        if (lastEx != null) {
-            throw lastEx;
-        }
-
-        s = new Socket("127.0.0.1", port);
-
-        s1 = ss.accept();
-
-        s.getOutputStream().write(0xa5);
-
-        assertEquals(0xa5, s1.getInputStream().read());
-
-        s1.getOutputStream().write(0x5a);
-        assertEquals(0x5a, s.getInputStream().read());
-    }
-    
-    // Regression test for #820068: Wildcard address
-    @SmallTest
-    public void testWildcardAddress() throws Exception {
-        Socket s2 = new Socket();
-        s2.bind(new InetSocketAddress((InetAddress) null, 12345));
-        byte[] addr = s2.getLocalAddress().getAddress();
-        for (int i = 0; i < 4; i++) {
-            assertEquals("Not the wildcard address", 0, addr[i]);
-        }
-    }
-    
-    // Regression test for #865753: server sockets not closing properly
-    @SmallTest
-    public void testServerSocketClose() throws Exception {
-        ServerSocket s3 = new ServerSocket(23456);
-        s3.close();
-        ServerSocket s4 = new ServerSocket(23456);
-        s4.close();
-    }
-    
-    // Regression test for #876985: SO_REUSEADDR not working properly
-    
-    private Exception serverError = null;
-    
-    @LargeTest
-    public void testSetReuseAddress() throws IOException {
-        InetSocketAddress addr = new InetSocketAddress(8383);
-
-        final ServerSocket serverSock = new ServerSocket();
-        serverSock.setReuseAddress(true);
-        serverSock.bind(addr);
-
-        final Semaphore semThreadEnd = new Semaphore(0);
-        new Thread() {
-            @Override
-            public void run() {
-                try {
-                    Socket sock = serverSock.accept();
-                    sock.getInputStream().read();
-                    sock.close();
-                } catch (IOException e) {
-                    serverError = e;
-                }
-                semThreadEnd.release();
-            }
-        }.start();
-
-        // Give the server a bit of time for startup
-        try {
-            Thread.sleep(2000);
-        } catch (InterruptedException ex) {
-            // Ignored.
-        }
-        
-        Socket client = new Socket("localhost", 8383);
-        client.getOutputStream().write(1);
-        // Just leave this connection open from the client side. It will be
-        // closed from the server side so the server stays in the TIME_WAIT
-        // state for a while. setReuseAddress() should be able to handle this.
-
-        try {
-            semThreadEnd.acquire();
-        } catch (InterruptedException e) {
-            // ignore
-        }
-        serverSock.close();
-
-        ServerSocket serverSock2 = new ServerSocket();
-        serverSock2.setReuseAddress(true);
-        serverSock2.bind(addr);
-        serverSock2.close();
-        
-        if (serverError != null) {
-            throw new RuntimeException("Server must complete without error", serverError);
-        }
-    }
-
-    // Regression for 916701, a wrong exception was thrown after timeout of
-    // a ServerSocket.
-    @LargeTest
-    public void testTimeoutException() throws IOException {
-        ServerSocket s = new ServerSocket(9800);
-        s.setSoTimeout(2000);
-        try {
-            s.accept();
-        } catch (SocketTimeoutException e) {
-            // this is ok.
-        }
-    }
-
-    // Regression for issue 1001980, openening a SocketChannel threw an Exception
-    @SmallTest
-    public void testNativeSocketChannelOpen() throws IOException {
-        SocketChannel.open();
-    }
-
-// Regression test for issue 1018016, connecting ignored a set timeout.
-//
-// Disabled because test behaves differently depending on networking
-// environment. It works fine in the emulator and one the device with
-// WLAN, but when 3G comes into play, the possible existence of a
-// proxy makes it fail.
-//
-//    @LargeTest
-//    public void testSocketSetSOTimeout() throws IOException {
-//        Socket sock = new Socket();
-//        int timeout = 5000;
-//        long start = System.currentTimeMillis();
-//        try {
-//            sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
-//        } catch (SocketTimeoutException e) {
-//            // expected
-//            long delay = System.currentTimeMillis() - start;
-//            if (Math.abs(delay - timeout) > 1000) {
-//                fail("timeout was not accurate. expected: " + timeout
-//                        + " actual: " + delay + " miliseconds.");
-//            }
-//        } finally {
-//            try {
-//                sock.close();
-//            } catch (IOException ioe) {
-//                // ignore
-//            }
-//        }
-//    }
-    
-    /**
-     * Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1)
-     * appear to be broken in the M5 SDK.
-     * 
-     * Tests that a connection given a ip-addressv4 such as 192.168.100.100 does
-     * not fail - sdk m5 seems only to accept dns names instead of ip numbers.
-     * ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is
-     * used to test the connection.
-     */
-
-// Commenting out this test since it is flaky, even at the best of times.  See
-// #1191317 for Info.
-    @Suppress
-    public void disable_testConnectWithIP4IPAddr() {
-        // call a Google Web server
-        InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS,
-                80);
-        Socket clntSckt = new Socket();
-        try {
-            clntSckt.connect(scktAddrss, 5000);
-        } catch (Throwable e) {
-            fail("connection problem:" + e.getClass().getName() + ": "
-                    + e.getMessage());
-        } finally {
-            try {
-                clntSckt.close();
-            } catch (Exception e) {
-                // ignore
-            }
-        }
-    }
-
-    
-    // Regression test for #1058962: Socket.close() does not cause
-    // socket.connect() to return immediately.
-    private Socket client;
-    
-    private Exception error;
-    
-    private boolean connected;
-
-// This test isn't working now, but really should work.
-// TODO Enable this test again.
-
-    @Suppress
-    public void disable_testSocketConnectClose() {
-        try {
-            client = new Socket();
-            
-            new Thread() {
-                @Override
-                public void run() {
-                    try {
-                        client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357));
-                    } catch (Exception ex) {
-                        error = ex;
-                    }
-                    
-                    connected = true;
-                }
-            }.start();
-            
-            Thread.sleep(1000);
-            
-            Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error);
-            Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected);
-            
-            client.close();
-            
-            Thread.sleep(1000);
-
-            if (error == null) {
-                fail("Socket connect still ongoing");
-            } else if (!(error instanceof SocketException)) {
-                fail("Socket connect interrupted with wrong error: " + error.toString());
-            }
-            
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-            
-    }
-    
-}
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
index 7177fc8f..1f2b939 100644
--- a/tests/HwAccelerationTest/res/layout/projection_clipping.xml
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -14,13 +14,13 @@
             android:id="@+id/clickable1"
             android:layout_width="100dp"
             android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackground"/>
+            android:background="?android:attr/selectableItemBackgroundBorderless"/>
         <View
             android:id="@+id/clickable2"
             android:translationX="50dp"
             android:translationY="10dp"
             android:layout_width="150dp"
             android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackground"/>
+            android:background="?android:attr/selectableItemBackgroundBorderless"/>
     </FrameLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk
index 4d39728..b7d7f98 100644
--- a/tests/OneMedia/Android.mk
+++ b/tests/OneMedia/Android.mk
@@ -9,6 +9,11 @@
 LOCAL_PACKAGE_NAME := OneMedia
 LOCAL_CERTIFICATE := platform
 
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-media-protocols
+
+LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
+
 LOCAL_PROGUARD_ENABLED := disabled
 
 include $(BUILD_PACKAGE)
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index beafeb4..ef3fad5 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -13,6 +13,8 @@
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:theme="@style/AppTheme" >
+
+        <uses-library android:name="org.apache.http.legacy" android:required="false" />
         <activity
             android:name="com.android.onemedia.OnePlayerActivity"
             android:label="@string/app_name" >
@@ -25,6 +27,15 @@
             android:name="com.android.onemedia.OnePlayerService"
             android:exported="true"
             android:process="com.android.onemedia.service" />
+        <service
+            android:name=".provider.OneMediaRouteProvider"
+            android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE"
+            android:exported="true"
+            android:process="com.android.onemedia.provider">
+            <intent-filter>
+                <action android:name="android.media.routing.MediaRouteService" />
+            </intent-filter>
+          </service>
     </application>
 
 </manifest>
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 2455c9c..141a209 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -19,17 +19,25 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.media.MediaMetadata;
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouter;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.RouteInfo;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.KeyEvent;
 
 import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.OneMRPRenderer;
 import com.android.onemedia.playback.Renderer;
 import com.android.onemedia.playback.RequestUtils;
 
@@ -40,6 +48,7 @@
     private static final String TAG = "PlayerSession";
 
     protected MediaSession mSession;
+    protected MediaRouter mRouter;
     protected Context mContext;
     protected Renderer mRenderer;
     protected MediaSession.Callback mCallback;
@@ -75,11 +84,22 @@
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
 
+        mRouter = new MediaRouter(mContext);
+        mRouter.addSelector(new MediaRouteSelector.Builder()
+                .addRequiredProtocol(MediaPlayerProtocol.class)
+                .build());
+        mRouter.addSelector(new MediaRouteSelector.Builder()
+                .setRequiredFeatures(MediaRouter.ROUTE_FEATURE_LIVE_AUDIO)
+                .setOptionalFeatures(MediaRouter.ROUTE_FEATURE_LIVE_VIDEO)
+                .build());
+        mRouter.setRoutingCallback(new RoutingCallback(), null);
+
         mSession = new MediaSession(mContext, "OneMedia");
         mSession.setCallback(mCallback);
         mSession.setPlaybackState(mPlaybackState);
         mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS
                 | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
+        mSession.setMediaRouter(mRouter);
         mSession.setActive(true);
         updateMetadata();
     }
@@ -97,6 +117,10 @@
             mSession.release();
             mSession = null;
         }
+        if (mRouter != null) {
+            mRouter.release();
+            mRouter = null;
+        }
     }
 
     public void setListener(Listener listener) {
@@ -254,4 +278,63 @@
             mRenderer.onPause();
         }
     }
+
+    private class RoutingCallback extends MediaRouter.RoutingCallback {
+        @Override
+        public void onConnectionStateChanged(int state) {
+            if (state == MediaRouter.CONNECTION_STATE_CONNECTING) {
+                if (mRenderer != null) {
+                    mRenderer.onStop();
+                }
+                mRenderer = null;
+                updateState(PlaybackState.STATE_CONNECTING);
+                return;
+            }
+
+            MediaRouter.ConnectionInfo connection = mRouter.getConnection();
+            if (connection != null) {
+                MediaPlayerProtocol protocol =
+                        connection.getProtocolObject(MediaPlayerProtocol.class);
+                if (protocol != null) {
+                    Log.d(TAG, "Connected to route using media player protocol");
+
+                    protocol.setCallback(new PlayerCallback(), null);
+                    mRenderer = new OneMRPRenderer(protocol);
+                    updateState(PlaybackState.STATE_NONE);
+                    return;
+                }
+            }
+
+            // Use local route
+            mRenderer = new LocalRenderer(mContext, null);
+            mRenderer.registerListener(mRenderListener);
+            updateState(PlaybackState.STATE_NONE);
+        }
+    }
+
+    private class PlayerCallback extends MediaPlayerProtocol.Callback {
+        @Override
+        public void onStatusUpdated(MediaStatus status, Bundle extras) {
+            if (status != null) {
+                Log.d(TAG, "Received status update: " + status.toBundle());
+                switch (status.getPlayerState()) {
+                    case MediaStatus.PLAYER_STATE_BUFFERING:
+                        updateState(PlaybackState.STATE_BUFFERING);
+                        break;
+                    case MediaStatus.PLAYER_STATE_IDLE:
+                        updateState(PlaybackState.STATE_STOPPED);
+                        break;
+                    case MediaStatus.PLAYER_STATE_PAUSED:
+                        updateState(PlaybackState.STATE_PAUSED);
+                        break;
+                    case MediaStatus.PLAYER_STATE_PLAYING:
+                        updateState(PlaybackState.STATE_PLAYING);
+                        break;
+                    case MediaStatus.PLAYER_STATE_UNKNOWN:
+                        updateState(PlaybackState.STATE_NONE);
+                        break;
+                }
+            }
+        }
+    }
 }
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
new file mode 100644
index 0000000..55eb92c
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
@@ -0,0 +1,47 @@
+package com.android.onemedia.playback;
+
+import android.os.Bundle;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
+
+/**
+ * Renderer for communicating with the OneMRP route
+ */
+public class OneMRPRenderer extends Renderer {
+    private final MediaPlayerProtocol mProtocol;
+
+    public OneMRPRenderer(MediaPlayerProtocol protocol) {
+        super(null, null);
+        mProtocol = protocol;
+    }
+
+    @Override
+    public void setContent(Bundle request) {
+        MediaInfo mediaInfo = new MediaInfo(request.getString(RequestUtils.EXTRA_KEY_SOURCE),
+                MediaInfo.STREAM_TYPE_BUFFERED, "audio/mp3");
+        mProtocol.load(mediaInfo, true, 0, null);
+    }
+
+    @Override
+    public boolean onStop() {
+        mProtocol.stop(null);
+        return true;
+    }
+
+    @Override
+    public boolean onPlay() {
+        mProtocol.play(null);
+        return true;
+    }
+
+    @Override
+    public boolean onPause() {
+        mProtocol.pause(null);
+        return true;
+    }
+
+    @Override
+    public long getSeekPosition() {
+        return -1;
+    }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
new file mode 100644
index 0000000..5845e48
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -0,0 +1,270 @@
+/*
+ * 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.onemedia.provider;
+
+import android.media.routing.MediaRouteSelector;
+import android.media.routing.MediaRouteService;
+import android.media.routing.MediaRouter.ConnectionInfo;
+import android.media.routing.MediaRouter.ConnectionRequest;
+import android.media.routing.MediaRouter.DestinationInfo;
+import android.media.routing.MediaRouter.DiscoveryRequest;
+import android.media.routing.MediaRouter.RouteInfo;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.support.media.protocols.MediaPlayerProtocol;
+import android.support.media.protocols.MediaPlayerProtocol.MediaInfo;
+import android.support.media.protocols.MediaPlayerProtocol.MediaStatus;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.Renderer;
+import com.android.onemedia.playback.RequestUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
+ * playing music.
+ */
+public class OneMediaRouteProvider extends MediaRouteService {
+    private static final String TAG = "OneMRP";
+    private static final boolean DEBUG = true;
+
+    private static final String TEST_DESTINATION_ID = "testDestination";
+    private static final String TEST_ROUTE_ID = "testRoute";
+
+    private Renderer mRenderer;
+    private RenderListener mRenderListener;
+    private PlaybackState mPlaybackState;
+    private Handler mHandler;
+
+    private OneStub mStub;
+
+    @Override
+    public void onCreate() {
+        mHandler = new Handler();
+        mRenderer = new LocalRenderer(this, null);
+        mRenderListener = new RenderListener();
+        PlaybackState.Builder bob = new PlaybackState.Builder();
+        bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY);
+        mPlaybackState = bob.build();
+
+        mRenderer.registerListener(mRenderListener);
+    }
+
+    @Override
+    public ClientSession onCreateClientSession(ClientInfo client) {
+        if (client.getUid() != Process.myUid()) {
+            // for testing purposes, only allow connections from this application
+            // since this provider is not fully featured
+            return null;
+        }
+        return new OneSession(client);
+    }
+
+    private final class OneSession extends ClientSession {
+        private final ClientInfo mClient;
+
+        public OneSession(ClientInfo client) {
+            mClient = client;
+        }
+
+        @Override
+        public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) {
+            for (MediaRouteSelector selector : req.getSelectors()) {
+                if (isMatch(selector)) {
+                    DestinationInfo destination = new DestinationInfo.Builder(
+                            TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia")
+                            .setDescription("Test route from OneMedia app.")
+                            .build();
+                    ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
+                    routes.add(new RouteInfo.Builder(
+                            TEST_ROUTE_ID, destination, selector).build());
+                    callback.onDestinationFound(destination, routes);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void onStopDiscovery() {
+        }
+
+        @Override
+        public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) {
+            if (req.getRoute().getId().equals(TEST_ROUTE_ID)) {
+                mStub = new OneStub();
+                ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute())
+                        .setProtocolStub(MediaPlayerProtocol.class, mStub)
+                        .build();
+                callback.onConnected(connection);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void onDisconnect() {
+            mStub = null;
+        }
+
+        private boolean isMatch(MediaRouteSelector selector) {
+            if (!selector.containsProtocol(MediaPlayerProtocol.class)) {
+                return false;
+            }
+            for (String protocol : selector.getRequiredProtocols()) {
+                if (!protocol.equals(MediaPlayerProtocol.class.getName())) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private final class OneStub extends MediaPlayerProtocol.Stub {
+        MediaInfo mMediaInfo;
+
+        public OneStub() {
+            super(mHandler);
+        }
+
+        @Override
+        public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition,
+                Bundle extras) {
+            if (DEBUG) {
+                Log.d(TAG, "Attempting to play " + mediaInfo.getContentId());
+            }
+            // look up the route and send a play command to it
+            mMediaInfo = mediaInfo;
+            Bundle bundle = new Bundle();
+            bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId());
+            mRenderer.setContent(bundle);
+        }
+
+        @Override
+        public void onPlay(Bundle extras) {
+            mRenderer.onPlay();
+        }
+
+        @Override
+        public void onPause(Bundle extras) {
+            mRenderer.onPause();
+        }
+    }
+
+    private class RenderListener implements Renderer.Listener {
+
+        @Override
+        public void onError(int type, int extra, Bundle extras, Throwable error) {
+            Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
+            sendStatusUpdate(PlaybackState.STATE_ERROR);
+        }
+
+        @Override
+        public void onStateChanged(int newState) {
+            long position = -1;
+            if (mRenderer != null) {
+                position = mRenderer.getSeekPosition();
+            }
+            int pbState;
+            float rate = 0;
+            String errorMsg = null;
+            switch (newState) {
+                case Renderer.STATE_ENDED:
+                case Renderer.STATE_STOPPED:
+                    pbState = PlaybackState.STATE_STOPPED;
+                    break;
+                case Renderer.STATE_INIT:
+                case Renderer.STATE_PREPARING:
+                    pbState = PlaybackState.STATE_BUFFERING;
+                    break;
+                case Renderer.STATE_ERROR:
+                    pbState = PlaybackState.STATE_ERROR;
+                    break;
+                case Renderer.STATE_PAUSED:
+                    pbState = PlaybackState.STATE_PAUSED;
+                    break;
+                case Renderer.STATE_PLAYING:
+                    pbState = PlaybackState.STATE_PLAYING;
+                    rate = 1;
+                    break;
+                default:
+                    pbState = PlaybackState.STATE_ERROR;
+                    errorMsg = "unknown state";
+                    break;
+            }
+            PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState);
+            bob.setState(pbState, position, rate, SystemClock.elapsedRealtime());
+            bob.setErrorMessage(errorMsg);
+            mPlaybackState = bob.build();
+
+            sendStatusUpdate(mPlaybackState.getState());
+        }
+
+        @Override
+        public void onBufferingUpdate(int percent) {
+        }
+
+        @Override
+        public void onFocusLost() {
+            Log.d(TAG, "Focus lost, pausing");
+            // Don't update state here, we'll get a separate call to
+            // onStateChanged when it pauses
+            mRenderer.onPause();
+        }
+
+        @Override
+        public void onNextStarted() {
+        }
+
+        private void sendStatusUpdate(int state) {
+            if (mStub != null) {
+                MediaStatus status = new MediaStatus(1, mStub.mMediaInfo);
+                switch (state) {
+                    case PlaybackState.STATE_BUFFERING:
+                    case PlaybackState.STATE_FAST_FORWARDING:
+                    case PlaybackState.STATE_REWINDING:
+                    case PlaybackState.STATE_SKIPPING_TO_NEXT:
+                    case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING);
+                        break;
+                    case PlaybackState.STATE_CONNECTING:
+                    case PlaybackState.STATE_STOPPED:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE);
+                        break;
+                    case PlaybackState.STATE_PAUSED:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED);
+                        break;
+                    case PlaybackState.STATE_PLAYING:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING);
+                        break;
+                    case PlaybackState.STATE_NONE:
+                    case PlaybackState.STATE_ERROR:
+                    default:
+                        status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN);
+                        break;
+                }
+                mStub.sendStatusUpdatedEvent(status, null);
+            }
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/Fountain_v11/Android.mk b/tests/RenderScriptTests/Fountain_v11/Android.mk
index fe7f9e7..ac2690c 100644
--- a/tests/RenderScriptTests/Fountain_v11/Android.mk
+++ b/tests/RenderScriptTests/Fountain_v11/Android.mk
@@ -14,8 +14,6 @@
 # limitations under the License.
 #
 
-ifneq ($(TARGET_SIMULATOR),true)
-
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -28,5 +26,3 @@
 LOCAL_SDK_VERSION := 11
 
 include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/SslLoad/Android.mk b/tests/SslLoad/Android.mk
deleted file mode 100644
index f75be8d..0000000
--- a/tests/SslLoad/Android.mk
+++ /dev/null
@@ -1,10 +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 := SslLoad
-
-include $(BUILD_PACKAGE)
diff --git a/tests/SslLoad/AndroidManifest.xml b/tests/SslLoad/AndroidManifest.xml
deleted file mode 100644
index 497b1c7..0000000
--- a/tests/SslLoad/AndroidManifest.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.sslload">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application>
-        <activity android:name="SslLoad" android:label="SSL Load">
-            <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/SslLoad/src/com/android/sslload/SslLoad.java b/tests/SslLoad/src/com/android/sslload/SslLoad.java
deleted file mode 100644
index 62aa524..0000000
--- a/tests/SslLoad/src/com/android/sslload/SslLoad.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sslload;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Calendar;
-import java.util.Map;
-
-import android.app.Activity;
-import android.content.res.Resources;
-import android.media.MediaPlayer;
-import android.os.Handler;
-import android.os.Vibrator;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.TextView;
-import android.util.Log;
-import android.net.http.AndroidHttpClient;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.HttpResponse;
-
-public class SslLoad extends Activity implements OnClickListener, Runnable {
-
-    private static final String TAG = SslLoad.class.getSimpleName();
-
-    private Button button;
-    private boolean running = false;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        Thread requestThread = new Thread(this);
-        requestThread.setDaemon(true);
-        requestThread.start();
-
-        button = new Button(this);
-        button.setText("GO");
-        button.setOnClickListener(this);
-
-        setContentView(button);
-    }
-    
-    @Override
-    protected void onStop() {
-        super.onStop();
-
-        synchronized (this) {
-            running = false;
-        }
-    }
-
-    public void onClick(View v) {
-        synchronized (this) {
-            running = !running;
-            button.setText(running ? "STOP" : "GO");
-            if (running) {
-                this.notifyAll();
-            }
-        }
-    }
-
-    public void run() {
-        boolean error = false;
-        while (true) {
-            synchronized (this) {
-                while (!running) {
-                    try {
-                        this.wait();
-                    } catch (InterruptedException e) { /* ignored */ }
-                }
-            }
-
-            AndroidHttpClient client = AndroidHttpClient.newInstance(
-                    "Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101");
-            try {
-                // Cert. is for "www.google.com", not "google.com".
-                String url = error ? "https://google.com/"
-                        : "https://www.google.com";
-                client.execute(new HttpGet(url),
-                        new ResponseHandler<Void>() {
-                            public Void handleResponse(HttpResponse response) {
-                                /* ignore */
-                                return null;
-                            }
-                        });
-                Log.i(TAG, "Request succeeded.");
-            } catch (IOException e) {
-                Log.w(TAG, "Request failed.", e);
-            }
-
-            client.close();
-            
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) { /* ignored */ }
-
-            error = !error;
-        }
-    }
-}
diff --git a/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java
index 20648a4..06fbcdc 100644
--- a/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java
+++ b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java
@@ -19,8 +19,10 @@
 import android.speech.tts.SynthesisCallback;
 import android.speech.tts.SynthesisRequest;
 import android.speech.tts.TextToSpeechService;
+import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.logging.Logger;
 
 public class MockableTextToSpeechService extends TextToSpeechService {
 
diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
index 78d4f966..faf6827 100644
--- a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
+++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java
@@ -43,11 +43,18 @@
         IDelegate passThrough = LittleMock.mock(IDelegate.class);
         MockableTextToSpeechService.setMocker(passThrough);
 
+        // For the default voice selection
+        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(passThrough)
+            .onIsLanguageAvailable(
+                    LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString());
+        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(passThrough)
+            .onLoadLanguage(
+                    LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString());
+
         blockingInitAndVerify(MOCK_ENGINE, TextToSpeech.SUCCESS);
         assertEquals(MOCK_ENGINE, mTts.getCurrentEngine());
     }
 
-
     @Override
     public void tearDown() {
         if (mTts != null) {
@@ -77,7 +84,7 @@
         assertEquals(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE, mTts.setLanguage(new Locale("eng", "USA", "variant")));
         LittleMock.verify(delegate, LittleMock.anyTimes()).onIsLanguageAvailable(
             "eng", "USA", "variant");
-        LittleMock.verify(delegate, LittleMock.times(1)).onLoadLanguage(
+        LittleMock.verify(delegate, LittleMock.anyTimes()).onLoadLanguage(
             "eng", "USA", "variant");
     }
 
@@ -147,26 +154,34 @@
     public void testDefaultLanguage_setsVoiceName() throws Exception {
         IDelegate delegate = LittleMock.mock(IDelegate.class);
         MockableTextToSpeechService.setMocker(delegate);
+        Locale defaultLocale = Locale.getDefault();
 
         // ---------------------------------------------------------
         // Test that default language also sets the default voice
         // name
-        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable(
-            LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString());
-        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage(
-            LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString());
+        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).
+            when(delegate).onIsLanguageAvailable(
+                defaultLocale.getISO3Language(),
+                defaultLocale.getISO3Country().toUpperCase(),
+                defaultLocale.getVariant());
+        LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).
+            when(delegate).onLoadLanguage(
+                defaultLocale.getISO3Language(),
+                defaultLocale.getISO3Country(),
+                defaultLocale.getVariant());
+
         blockingCallSpeak("foo bar", delegate);
         ArgumentCaptor<SynthesisRequest> req = LittleMock.createCaptor();
         LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req.capture(),
                 LittleMock.<SynthesisCallback>anyObject());
 
-        Locale defaultLocale = Locale.getDefault();
         assertEquals(defaultLocale.getISO3Language(), req.getValue().getLanguage());
         assertEquals(defaultLocale.getISO3Country(), req.getValue().getCountry());
         assertEquals("", req.getValue().getVariant());
         assertEquals(defaultLocale.toLanguageTag(), req.getValue().getVoiceName());
     }
 
+
     private void blockingCallSpeak(String speech, IDelegate mock) throws
             InterruptedException {
         final CountDownLatch latch = new CountDownLatch(1);
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
index d9a3b61..8e6daea 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
@@ -166,6 +166,9 @@
                 case UsageEvents.Event.CONFIGURATION_CHANGE:
                     return "Config change";
 
+                case UsageEvents.Event.INTERACTION:
+                    return "Interaction";
+
                 default:
                     return "Unknown: " + eventType;
             }
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index a0b0e00..7cddda1 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -14,10 +14,10 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:height="64dp"
-        android:width="64dp"
-        android:viewportHeight="12.25"
-        android:viewportWidth="7.30625" >
+    android:height="64dp"
+    android:viewportHeight="12.25"
+    android:viewportWidth="7.30625"
+    android:width="64dp" >
 
     <group
         android:pivotX="3.65"
@@ -31,14 +31,18 @@
                 l 0, 12.25
                 l-7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            android:name="one"
-            android:fillColor="#ff88ff"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="one"
+                android:fillColor="#ff88ff"
+                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
                 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
                 l-5.046875,0.0 0.0-1.0Z" />
+        </group>
     </group>
     <group
         android:pivotX="3.65"
@@ -52,12 +56,15 @@
                 l 0, 6.125
                 l-7.3, 0
                 z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fillColor="#ff88ff"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+
+        <group
+            android:pivotX="3.65"
+            android:pivotY="6.125"
+            android:rotation="30" >
+            <path
+                android:name="two"
+                android:fillColor="#ff88ff"
+                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
                         q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
                         q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
                         q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -66,6 +73,7 @@
                         q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
                         q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
                         q-0.78125024,0.8125-2.2187502,2.265625Z" />
+        </group>
     </group>
 
 </vector>
\ No newline at end of file
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 06d31a4..36d5d98 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -12,10 +12,19 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <activity android:name="SettingsActivity"
-                android:label="Voice Interaction Settings"
+        <activity android:name="AssistProxyActivity"
+                android:label="Test Assist Proxy"
+                android:theme="@android:style/Theme.NoDisplay"
                 android:excludeFromRecents="true"
-                android:noHistory="true">
+                android:noHistory="true"
+                android:taskAffinity="">
+            <intent-filter>
+                <action android:name="android.intent.action.ASSIST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+        <activity android:name="SettingsActivity"
+                android:label="Voice Interaction Settings">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -44,7 +53,7 @@
             <meta-data android:name="android.speech" android:resource="@xml/recognition_service" />
         </service>
         <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"
-                  android:theme="@android:style/Theme.Material.Light.Voice">
+                  android:theme="@android:style/Theme.Material.Light">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index d55736f..f4648b57 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -32,7 +32,6 @@
         android:layout_weight="1"
         android:layout_marginTop="16dp"
         android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="#ffffffff"
         />
 
     <Button android:id="@+id/complete"
@@ -49,4 +48,11 @@
         android:text="@string/abortVoice"
         />
 
+    <Button android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:text="@string/cancelVoice"
+    />
+
 </LinearLayout>
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index 002f350..10571765 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -15,24 +15,46 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
-    <FrameLayout android:layout_width="fill_parent"
+    <com.android.test.voiceinteraction.AssistVisualizer android:id="@+id/assist_visualizer"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+
+    <FrameLayout android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:padding="8dp">
+        android:fitsSystemWindows="true">
 
-        <LinearLayout android:id="@+id/content"
-            android:layout_width="fill_parent"
-            android:layout_height="match_parent"
+        <FrameLayout android:id="@+id/top_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:orientation="vertical"
+            android:background="#ffffffff"
+            android:elevation="8dp"
+            >
+
+            <Button android:id="@+id/start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top|right"
+                android:text="@string/start"
+                />
+
+        </FrameLayout>
+
+        <LinearLayout android:id="@+id/bottom_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="bottom"
             android:orientation="vertical"
             android:background="#ffffffff"
             android:elevation="8dp"
             >
 
             <TextView android:id="@+id/text"
-                android:layout_width="fill_parent"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginBottom="16dp"
                 android:textAppearance="?android:attr/textAppearanceMedium"
@@ -40,11 +62,6 @@
 
             <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
                     android:orientation="horizontal">
-                <Button android:id="@+id/start"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/start"
-                    />
                 <Button android:id="@+id/confirm"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 7eec90c..9f99c97 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -22,6 +22,7 @@
     <string name="complete">Complete</string>
     <string name="abortVoice">Abort Voice</string>
     <string name="completeVoice">Complete Voice</string>
+    <string name="cancelVoice">Cancel</string>
 
 </resources>
 
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
new file mode 100644
index 0000000..d0c5e36
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.voiceinteraction;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class AssistProxyActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        finish();
+        Intent intent = new Intent(this, MainInteractionService.class);
+        intent.setAction(Intent.ACTION_ASSIST);
+        startService(intent);
+    }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
new file mode 100644
index 0000000..bae19a6
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.voiceinteraction;
+
+import android.annotation.Nullable;
+import android.app.AssistStructure;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public class AssistVisualizer extends View {
+    static final String TAG = "AssistVisualizer";
+
+    AssistStructure mAssistStructure;
+    final Paint mFramePaint = new Paint();
+    final ArrayList<Rect> mTextRects = new ArrayList<>();
+    final int[] mTmpLocation = new int[2];
+
+    public AssistVisualizer(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+        mFramePaint.setColor(0xffff0000);
+        mFramePaint.setStyle(Paint.Style.STROKE);
+        mFramePaint.setStrokeWidth(0);
+    }
+
+    public void setAssistStructure(AssistStructure as) {
+        mAssistStructure = as;
+        mTextRects.clear();
+        final int N = as.getWindowCount();
+        if (N > 0) {
+            AssistStructure.ViewNode window = new AssistStructure.ViewNode();
+            for (int i=0; i<N; i++) {
+                as.getWindowAt(i, window);
+                buildTextRects(window, 0, 0);
+            }
+        }
+    }
+
+    public void clearAssistData() {
+        mAssistStructure = null;
+        mTextRects.clear();
+    }
+
+    void buildTextRects(AssistStructure.ViewNode root, int parentLeft, int parentTop) {
+        if (root.getVisibility() != View.VISIBLE) {
+            return;
+        }
+        int left = parentLeft+root.getLeft();
+        int top = parentTop+root.getTop();
+        Log.d(TAG, "View " + root.getClassName() + ": " + left + ", " + top);
+        if (root.getText() != null) {
+            Rect r = new Rect(left, top, left+root.getWidth(), top+root.getHeight());
+            Log.d(TAG, "Text Rect " + r.toShortString() + ": " + root.getText());
+            mTextRects.add(r);
+        }
+        final int N = root.getChildCount();
+        if (N > 0) {
+            left -= root.getScrollX();
+            top -= root.getScrollY();
+            AssistStructure.ViewNode child = new AssistStructure.ViewNode();
+            for (int i=0; i<N; i++) {
+                root.getChildAt(i, child);
+                buildTextRects(child, left, top);
+            }
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        getLocationOnScreen(mTmpLocation);
+        final int N = mTextRects.size();
+        for (int i=0; i<N; i++) {
+            Rect r = mTextRects.get(i);
+            canvas.drawRect(r.left-mTmpLocation[0], r.top-mTmpLocation[1],
+                    r.right-mTmpLocation[0], r.bottom-mTmpLocation[1], mFramePaint);
+        }
+    }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index 4639114..722b0de 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -16,6 +16,7 @@
 
 package com.android.test.voiceinteraction;
 
+import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.AlwaysOnHotwordDetector;
@@ -74,9 +75,14 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        Bundle args = new Bundle();
-        args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
-        startSession(args);
+        if (isActiveService(this, new ComponentName(this, getClass()))) {
+            Bundle args = new Bundle();
+            args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
+            args.putBundle("assist", intent.getExtras());
+            startSession(args, START_WITH_ASSIST);
+        } else {
+            Log.w(TAG, "Not starting -- not current voice interaction service");
+        }
         stopSelf(startId);
         return START_NOT_STICKY;
     }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index d20906e..bcfc6f4 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -16,6 +16,8 @@
 
 package com.android.test.voiceinteraction;
 
+import android.app.AssistContent;
+import android.app.AssistStructure;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -31,18 +33,24 @@
 
     Intent mStartIntent;
     View mContentView;
+    AssistVisualizer mAssistVisualizer;
+    View mTopContent;
+    View mBottomContent;
     TextView mText;
     Button mStartButton;
     Button mConfirmButton;
     Button mCompleteButton;
     Button mAbortButton;
 
+    AssistStructure mAssistStructure;
+
     static final int STATE_IDLE = 0;
     static final int STATE_LAUNCHING = 1;
     static final int STATE_CONFIRM = 2;
     static final int STATE_COMMAND = 3;
     static final int STATE_ABORT_VOICE = 4;
     static final int STATE_COMPLETE_VOICE = 5;
+    static final int STATE_DONE=6;
 
     int mState = STATE_IDLE;
     Request mPendingRequest;
@@ -52,15 +60,40 @@
     }
 
     @Override
-    public void onCreate(Bundle args) {
+    public void onCreate(Bundle args, int startFlags) {
         super.onCreate(args);
-        showWindow();
+    }
+
+    @Override
+    public void onShow(Bundle args, int showFlags) {
+        super.onShow(args, showFlags);
+        mState = STATE_IDLE;
         mStartIntent = args.getParcelable("intent");
+        if (mAssistVisualizer != null) {
+            mAssistVisualizer.clearAssistData();
+        }
+        updateState();
+    }
+
+    @Override
+    public void onHide() {
+        super.onHide();
+        if (mAssistVisualizer != null) {
+            mAssistVisualizer.clearAssistData();
+        }
+        mState = STATE_DONE;
+        updateState();
     }
 
     @Override
     public View onCreateContentView() {
         mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null);
+        mAssistVisualizer = (AssistVisualizer)mContentView.findViewById(R.id.assist_visualizer);
+        if (mAssistStructure != null) {
+            mAssistVisualizer.setAssistStructure(mAssistStructure);
+        }
+        mTopContent = mContentView.findViewById(R.id.top_content);
+        mBottomContent = mContentView.findViewById(R.id.bottom_content);
         mText = (TextView)mContentView.findViewById(R.id.text);
         mStartButton = (Button)mContentView.findViewById(R.id.start);
         mStartButton.setOnClickListener(this);
@@ -70,11 +103,56 @@
         mCompleteButton.setOnClickListener(this);
         mAbortButton = (Button)mContentView.findViewById(R.id.abort);
         mAbortButton.setOnClickListener(this);
-        updateState();
         return mContentView;
     }
 
+    @Override
+    public void onHandleAssist(Bundle assistBundle) {
+        if (assistBundle != null) {
+            parseAssistData(assistBundle);
+        } else {
+            Log.i(TAG, "onHandleAssist: NO ASSIST BUNDLE");
+        }
+    }
+
+    void parseAssistData(Bundle assistBundle) {
+        if (assistBundle != null) {
+            Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+            if (assistContext != null) {
+                mAssistStructure = AssistStructure.getAssistStructure(assistContext);
+                if (mAssistStructure != null) {
+                    mAssistStructure.dump();
+                    if (mAssistVisualizer != null) {
+                        mAssistVisualizer.setAssistStructure(mAssistStructure);
+                    }
+                }
+                AssistContent content = AssistContent.getAssistContent(assistContext);
+                if (content != null) {
+                    Log.i(TAG, "Assist intent: " + content.getIntent());
+                    Log.i(TAG, "Assist clipdata: " + content.getClipData());
+                }
+                return;
+            }
+        }
+        if (mAssistVisualizer != null) {
+            mAssistVisualizer.clearAssistData();
+        }
+    }
+
     void updateState() {
+        if (mState == STATE_IDLE) {
+            mTopContent.setVisibility(View.VISIBLE);
+            mBottomContent.setVisibility(View.GONE);
+            mAssistVisualizer.setVisibility(View.VISIBLE);
+        } else if (mState == STATE_DONE) {
+            mTopContent.setVisibility(View.GONE);
+            mBottomContent.setVisibility(View.GONE);
+            mAssistVisualizer.setVisibility(View.GONE);
+        } else {
+            mTopContent.setVisibility(View.GONE);
+            mBottomContent.setVisibility(View.VISIBLE);
+            mAssistVisualizer.setVisibility(View.GONE);
+        }
         mStartButton.setEnabled(mState == STATE_IDLE);
         mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND);
         mAbortButton.setEnabled(mState == STATE_ABORT_VOICE);
@@ -93,18 +171,21 @@
                 mPendingRequest.sendCommandResult(true, null);
             }
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
         } else if (v == mAbortButton) {
             mPendingRequest.sendAbortVoiceResult(null);
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
         } else if (v== mCompleteButton) {
             mPendingRequest.sendCompleteVoiceResult(null);
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
+        }
+    }
+
+    @Override
+    public void onComputeInsets(Insets outInsets) {
+        super.onComputeInsets(outInsets);
+        if (mState != STATE_IDLE) {
+            outInsets.contentInsets.top = mBottomContent.getTop();
+            outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT;
         }
     }
 
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index d64eefa..023e0ec 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -18,7 +18,9 @@
 
 import android.app.Activity;
 import android.app.VoiceInteractor;
+import android.content.ComponentName;
 import android.os.Bundle;
+import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
@@ -29,8 +31,10 @@
     static final String TAG = "TestInteractionActivity";
 
     VoiceInteractor mInteractor;
+    VoiceInteractor.Request mCurrentRequest = null;
     Button mAbortButton;
     Button mCompleteButton;
+    Button mCancelButton;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -42,19 +46,23 @@
             return;
         }
 
+        if (!VoiceInteractionService.isActiveService(this,
+                new ComponentName(this, MainInteractionService.class))) {
+            Log.w(TAG, "Not current voice interactor!");
+            finish();
+            return;
+        }
+
         setContentView(R.layout.test_interaction);
         mAbortButton = (Button)findViewById(R.id.abort);
         mAbortButton.setOnClickListener(this);
         mCompleteButton = (Button)findViewById(R.id.complete);
         mCompleteButton.setOnClickListener(this);
-
-        // Framework should take care of these.
-        getWindow().setGravity(Gravity.TOP);
-        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
+        mCancelButton = (Button)findViewById(R.id.cancel);
+        mCancelButton.setOnClickListener(this);
 
         mInteractor = getVoiceInteractor();
-        VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest(
+        mCurrentRequest = new VoiceInteractor.ConfirmationRequest(
                 "This is a confirmation", null) {
             @Override
             public void onCancel() {
@@ -68,7 +76,7 @@
                 getActivity().finish();
             }
         };
-        mInteractor.submitRequest(req);
+        mInteractor.submitRequest(mCurrentRequest);
     }
 
     @Override
@@ -108,6 +116,9 @@
                 }
             };
             mInteractor.submitRequest(req);
+        } else if (v == mCancelButton && mCurrentRequest != null) {
+            Log.i(TAG, "Cancel request");
+            mCurrentRequest.cancel();
         }
     }
 
diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
index 3bd35a7..3791d02 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
@@ -47,17 +47,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
-        try {
-            mAm.moveTaskToBack(-1);
-            fail("IActivityManager.moveTaskToBack did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-        
+
         try {
             mAm.moveTaskBackwards(-1);
             fail("IActivityManager.moveTaskToFront did not throw SecurityException as"
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 62c92a1..e44969d 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -103,7 +103,7 @@
         }
         
         try {
-            mWm.setAppGroupId(null, 0);
+            mWm.setAppTask(null, 0);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index b7f64f6..871e04f 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -15,7 +15,6 @@
 #include <dirent.h>
 #include <errno.h>
 
-static const char* kDefaultLocale = "default";
 static const char* kAssetDir = "assets";
 static const char* kResourceDir = "res";
 static const char* kValuesDir = "values";
@@ -176,7 +175,7 @@
 
 void AaptLocaleValue::setLanguage(const char* languageChars) {
      size_t i = 0;
-     while ((*languageChars) != '\0') {
+     while ((*languageChars) != '\0' && i < sizeof(language)/sizeof(language[0])) {
           language[i++] = tolower(*languageChars);
           languageChars++;
      }
@@ -184,7 +183,7 @@
 
 void AaptLocaleValue::setRegion(const char* regionChars) {
     size_t i = 0;
-    while ((*regionChars) != '\0') {
+    while ((*regionChars) != '\0' && i < sizeof(region)/sizeof(region[0])) {
          region[i++] = toupper(*regionChars);
          regionChars++;
     }
@@ -192,7 +191,7 @@
 
 void AaptLocaleValue::setScript(const char* scriptChars) {
     size_t i = 0;
-    while ((*scriptChars) != '\0') {
+    while ((*scriptChars) != '\0' && i < sizeof(script)/sizeof(script[0])) {
          if (i == 0) {
              script[i++] = toupper(*scriptChars);
          } else {
@@ -204,7 +203,7 @@
 
 void AaptLocaleValue::setVariant(const char* variantChars) {
      size_t i = 0;
-     while ((*variantChars) != '\0') {
+     while ((*variantChars) != '\0' && i < sizeof(variant)/sizeof(variant[0])) {
           variant[i++] = *variantChars;
           variantChars++;
      }
@@ -346,7 +345,8 @@
 
         return ++currentIndex;
     } else {
-        if ((part.length() == 2 || part.length() == 3) && isAlpha(part)) {
+        if ((part.length() == 2 || part.length() == 3)
+               && isAlpha(part) && strcmp("car", part.string())) {
             setLanguage(part);
             if (++currentIndex == size) {
                 return size;
@@ -1241,7 +1241,7 @@
 }
 
 ssize_t
-AaptAssets::slurpResourceZip(Bundle* bundle, const char* filename)
+AaptAssets::slurpResourceZip(Bundle* /* bundle */, const char* filename)
 {
     int count = 0;
     SortedVector<AaptGroupEntry> entries;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index bc9c1f7..c5495a5 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -36,7 +36,6 @@
     Images.cpp \
     Package.cpp \
     pseudolocalize.cpp \
-    qsort_r_compat.c \
     Resource.cpp \
     ResourceFilter.cpp \
     ResourceIdCache.cpp \
@@ -68,6 +67,7 @@
     libziparchive-host
 
 aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER)\"
+aaptCFLAGS += -Wall -Werror
 
 ifeq ($(HOST_OS),linux)
     aaptHostLdLibs += -lrt -ldl -lpthread
@@ -118,6 +118,7 @@
 # Build the host tests: libaapt_tests
 # ==========================================================
 include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libaapt_tests
 LOCAL_CFLAGS += $(aaptCFlags)
@@ -139,10 +140,7 @@
 LOCAL_MODULE := aapt
 LOCAL_CFLAGS += $(aaptCFlags)
 LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
-LOCAL_C_INCLUDES += \
-    $(aaptCIncludes) \
-    bionic \
-    external/stlport/stlport
+LOCAL_C_INCLUDES += $(aaptCIncludes)
 LOCAL_SHARED_LIBRARIES := \
     libandroidfw \
     libutils \
@@ -151,7 +149,6 @@
     liblog \
     libz
 LOCAL_STATIC_LIBRARIES := \
-    libstlport_static \
     libexpat_static
 
 include $(BUILD_EXECUTABLE)
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 3fa131e..8a0a39c 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -215,14 +215,15 @@
             goto bail;
         }
 
+#ifdef HAVE_ANDROID_OS
+        static const bool kHaveAndroidOs = true;
+#else
+        static const bool kHaveAndroidOs = false;
+#endif
         const ResTable& res = assets.getResources(false);
-        if (&res == NULL) {
-            printf("\nNo resource table found.\n");
-        } else {
-#ifndef HAVE_ANDROID_OS
+        if (!kHaveAndroidOs) {
             printf("\nResource table:\n");
             res.print(false);
-#endif
         }
 
         Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -620,10 +621,7 @@
     assets.setConfiguration(config);
 
     const ResTable& res = assets.getResources(false);
-    if (&res == NULL) {
-        fprintf(stderr, "ERROR: dump failed because no resource table was found\n");
-        return 1;
-    } else if (res.getError() != NO_ERROR) {
+    if (res.getError() != NO_ERROR) {
         fprintf(stderr, "ERROR: dump failed because the resource table is invalid/corrupt.\n");
         return 1;
     }
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index c4cf6bc..6c39d1d 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -101,4 +101,4 @@
     time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
     time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
     return sourceDate > destDate;
-}
\ No newline at end of file
+}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5d4a6ac..063b4e6 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -14,7 +14,8 @@
 #include <png.h>
 #include <zlib.h>
 
-#define NOISY(x) //x
+// Change this to true for noisy debug output.
+static const bool kIsDebug = false;
 
 static void
 png_write_aapt_file(png_structp png_ptr, png_bytep data, png_size_t length)
@@ -28,7 +29,7 @@
 
 
 static void
-png_flush_aapt_file(png_structp png_ptr)
+png_flush_aapt_file(png_structp /* png_ptr */)
 {
 }
 
@@ -156,11 +157,13 @@
 
     png_read_end(read_ptr, read_info);
 
-    NOISY(printf("Image %s: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
-                 imageName,
-                 (int)outImageInfo->width, (int)outImageInfo->height,
-                 bit_depth, color_type,
-                 interlace_type, compression_type));
+    if (kIsDebug) {
+        printf("Image %s: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
+                imageName,
+                (int)outImageInfo->width, (int)outImageInfo->height,
+                bit_depth, color_type,
+                interlace_type, compression_type);
+    }
 
     png_get_IHDR(read_ptr, read_info, &outImageInfo->width,
        &outImageInfo->height, &bit_depth, &color_type,
@@ -330,7 +333,7 @@
 }
 
 static status_t get_horizontal_layout_bounds_ticks(
-        png_bytep row, int width, bool transparent, bool required,
+        png_bytep row, int width, bool transparent, bool /* required */,
         int32_t* outLeft, int32_t* outRight, const char** outError)
 {
     int i;
@@ -368,7 +371,7 @@
 }
 
 static status_t get_vertical_layout_bounds_ticks(
-        png_bytepp rows, int offset, int height, bool transparent, bool required,
+        png_bytepp rows, int offset, int height, bool transparent, bool /* required */,
         int32_t* outTop, int32_t* outBottom, const char** outError)
 {
     int i;
@@ -478,8 +481,9 @@
 
     // assuming the image is a round rect, compute the radius by marching
     // diagonally from the top left corner towards the center
-    image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
-            max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+    image->outlineAlpha = std::max(
+        max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+        max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
 
     int diagonalInset = 0;
     find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
@@ -493,13 +497,15 @@
      */
     image->outlineRadius = 3.4142f * diagonalInset;
 
-    NOISY(printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
-            image->outlineInsetsLeft,
-            image->outlineInsetsTop,
-            image->outlineInsetsRight,
-            image->outlineInsetsBottom,
-            image->outlineRadius,
-            image->outlineAlpha));
+    if (kIsDebug) {
+        printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
+                image->outlineInsetsLeft,
+                image->outlineInsetsTop,
+                image->outlineInsetsRight,
+                image->outlineInsetsBottom,
+                image->outlineRadius,
+                image->outlineAlpha);
+    }
 }
 
 
@@ -533,41 +539,6 @@
     return (color[3]<<24) | (color[0]<<16) | (color[1]<<8) | color[2];
 }
 
-static void select_patch(
-    int which, int front, int back, int size, int* start, int* end)
-{
-    switch (which) {
-    case 0:
-        *start = 0;
-        *end = front-1;
-        break;
-    case 1:
-        *start = front;
-        *end = back-1;
-        break;
-    case 2:
-        *start = back;
-        *end = size-1;
-        break;
-    }
-}
-
-static uint32_t get_color(image_info* image, int hpatch, int vpatch)
-{
-    int left, right, top, bottom;
-    select_patch(
-        hpatch, image->xDivs[0], image->xDivs[1],
-        image->width, &left, &right);
-    select_patch(
-        vpatch, image->yDivs[0], image->yDivs[1],
-        image->height, &top, &bottom);
-    //printf("Selecting h=%d v=%d: (%d,%d)-(%d,%d)\n",
-    //       hpatch, vpatch, left, top, right, bottom);
-    const uint32_t c = get_color(image->rows, left, top, right, bottom);
-    NOISY(printf("Color in (%d,%d)-(%d,%d): #%08x\n", left, top, right, bottom, c));
-    return c;
-}
-
 static status_t do_9patch(const char* imageName, image_info* image)
 {
     image->is9Patch = true;
@@ -672,8 +643,10 @@
                                || image->layoutBoundsBottom != 0;
 
     if (image->haveLayoutBounds) {
-        NOISY(printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop,
-                image->layoutBoundsRight, image->layoutBoundsBottom));
+        if (kIsDebug) {
+            printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop,
+                    image->layoutBoundsRight, image->layoutBoundsBottom);
+        }
     }
 
     // use opacity of pixels to estimate the round rect outline
@@ -695,12 +668,14 @@
         image->info9Patch.paddingBottom = H - 2 - image->info9Patch.paddingBottom;
     }
 
-    NOISY(printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
-                 xDivs[0], xDivs[1],
-                 yDivs[0], yDivs[1]));
-    NOISY(printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
-                 image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
-                 image->info9Patch.paddingTop, image->info9Patch.paddingBottom));
+    if (kIsDebug) {
+        printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
+                xDivs[0], xDivs[1],
+                yDivs[0], yDivs[1]);
+        printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
+                image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
+                image->info9Patch.paddingTop, image->info9Patch.paddingBottom);
+    }
 
     // Remove frame from image.
     image->rows = (png_bytepp)malloc((H-2) * sizeof(png_bytep));
@@ -782,7 +757,10 @@
             }
             c = get_color(image->rows, left, top, right - 1, bottom - 1);
             image->colors[colorIndex++] = c;
-            NOISY(if (c != Res_png_9patch::NO_COLOR) hasColor = true);
+            if (kIsDebug) {
+                if (c != Res_png_9patch::NO_COLOR)
+                    hasColor = true;
+            }
             left = right;
         }
         top = bottom;
@@ -885,7 +863,7 @@
                 break;
             }
             if (i == (w - 1)) {
-                NOISY(printf("\n"));
+                printf("\n");
             }
         }
     }
@@ -915,8 +893,10 @@
     // 2. Every pixel has A == 255 (opaque)
     // 3. There are no more than 256 distinct RGBA colors
 
-    // NOISY(printf("Initial image data:\n"));
-    // dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA);
+    if (kIsDebug) {
+        printf("Initial image data:\n");
+        dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA);
+    }
 
     for (j = 0; j < h; j++) {
         png_bytep row = imageInfo.rows[j];
@@ -932,15 +912,19 @@
             maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation);
             maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation);
             if (maxGrayDeviation > odev) {
-                NOISY(printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
-                             maxGrayDeviation, i, j, rr, gg, bb, aa));
+                if (kIsDebug) {
+                    printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
+                            maxGrayDeviation, i, j, rr, gg, bb, aa);
+                }
             }
 
             // Check if image is really grayscale
             if (isGrayscale) {
                 if (rr != gg || rr != bb) {
-                     NOISY(printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
-                                  i, j, rr, gg, bb, aa));
+                    if (kIsDebug) {
+                        printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
+                                i, j, rr, gg, bb, aa);
+                    }
                     isGrayscale = false;
                 }
             }
@@ -948,8 +932,10 @@
             // Check if image is really opaque
             if (isOpaque) {
                 if (aa != 0xff) {
-                    NOISY(printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
-                                 i, j, rr, gg, bb, aa));
+                    if (kIsDebug) {
+                        printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
+                                i, j, rr, gg, bb, aa);
+                    }
                     isOpaque = false;
                 }
             }
@@ -971,7 +957,9 @@
                 *out++ = idx;
                 if (!match) {
                     if (num_colors == 256) {
-                        NOISY(printf("Found 257th color at %d, %d\n", i, j));
+                        if (kIsDebug) {
+                            printf("Found 257th color at %d, %d\n", i, j);
+                        }
                         isPalette = false;
                     } else {
                         colors[num_colors++] = col;
@@ -986,12 +974,14 @@
     int bpp = isOpaque ? 3 : 4;
     int paletteSize = w * h + bpp * num_colors;
 
-    NOISY(printf("isGrayscale = %s\n", isGrayscale ? "true" : "false"));
-    NOISY(printf("isOpaque = %s\n", isOpaque ? "true" : "false"));
-    NOISY(printf("isPalette = %s\n", isPalette ? "true" : "false"));
-    NOISY(printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
-                 paletteSize, 2 * w * h, bpp * w * h));
-    NOISY(printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance));
+    if (kIsDebug) {
+        printf("isGrayscale = %s\n", isGrayscale ? "true" : "false");
+        printf("isOpaque = %s\n", isOpaque ? "true" : "false");
+        printf("isPalette = %s\n", isPalette ? "true" : "false");
+        printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
+                paletteSize, 2 * w * h, bpp * w * h);
+        printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance);
+    }
 
     // Choose the best color type for the image.
     // 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel
@@ -1068,7 +1058,6 @@
                       png_structp write_ptr, png_infop write_info,
                       image_info& imageInfo, int grayscaleTolerance)
 {
-    bool optimize = true;
     png_uint_32 width, height;
     int color_type;
     int bit_depth, interlace_type, compression_type;
@@ -1094,8 +1083,10 @@
 
     png_set_compression_level(write_ptr, Z_BEST_COMPRESSION);
 
-    NOISY(printf("Writing image %s: w = %d, h = %d\n", imageName,
-          (int) imageInfo.width, (int) imageInfo.height));
+    if (kIsDebug) {
+        printf("Writing image %s: w = %d, h = %d\n", imageName,
+                (int) imageInfo.width, (int) imageInfo.height);
+    }
 
     png_color rgbPalette[256];
     png_byte alphaPalette[256];
@@ -1112,24 +1103,26 @@
         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
     }
 
-    switch (color_type) {
-    case PNG_COLOR_TYPE_PALETTE:
-        NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
-                     imageName, paletteEntries,
-                     hasTransparency ? " (with alpha)" : ""));
-        break;
-    case PNG_COLOR_TYPE_GRAY:
-        NOISY(printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName));
-        break;
-    case PNG_COLOR_TYPE_GRAY_ALPHA:
-        NOISY(printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName));
-        break;
-    case PNG_COLOR_TYPE_RGB:
-        NOISY(printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName));
-        break;
-    case PNG_COLOR_TYPE_RGB_ALPHA:
-        NOISY(printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName));
-        break;
+    if (kIsDebug) {
+        switch (color_type) {
+        case PNG_COLOR_TYPE_PALETTE:
+            printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
+                    imageName, paletteEntries,
+                    hasTransparency ? " (with alpha)" : "");
+            break;
+        case PNG_COLOR_TYPE_GRAY:
+            printf("Image %s is opaque gray, using PNG_COLOR_TYPE_GRAY\n", imageName);
+            break;
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            printf("Image %s is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA\n", imageName);
+            break;
+        case PNG_COLOR_TYPE_RGB:
+            printf("Image %s is opaque RGB, using PNG_COLOR_TYPE_RGB\n", imageName);
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            printf("Image %s is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA\n", imageName);
+            break;
+        }
     }
 
     png_set_IHDR(write_ptr, write_info, imageInfo.width, imageInfo.height,
@@ -1158,7 +1151,9 @@
                 : (png_byte*)"npOl\0npTc";
 
         // base 9 patch data
-        NOISY(printf("Adding 9-patch info...\n"));
+        if (kIsDebug) {
+            printf("Adding 9-patch info...\n");
+        }
         strcpy((char*)unknowns[p_index].name, "npTc");
         unknowns[p_index].data = (png_byte*)imageInfo.serialize9patch();
         unknowns[p_index].size = imageInfo.info9Patch.serializedSize();
@@ -1214,8 +1209,10 @@
     }
     png_write_image(write_ptr, rows);
 
-//     NOISY(printf("Final image data:\n"));
-//     dump_image(imageInfo.width, imageInfo.height, rows, color_type);
+    if (kIsDebug) {
+        printf("Final image data:\n");
+        dump_image(imageInfo.width, imageInfo.height, rows, color_type);
+    }
 
     png_write_end(write_ptr, write_info);
 
@@ -1231,13 +1228,50 @@
        &bit_depth, &color_type, &interlace_type,
        &compression_type, NULL);
 
-    NOISY(printf("Image written: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
-                 (int)width, (int)height, bit_depth, color_type, interlace_type,
-                 compression_type));
+    if (kIsDebug) {
+        printf("Image written: w=%d, h=%d, d=%d, colors=%d, inter=%d, comp=%d\n",
+                (int)width, (int)height, bit_depth, color_type, interlace_type,
+                compression_type);
+    }
 }
 
-status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
-                         const sp<AaptFile>& file, String8* outNewLeafName)
+static bool read_png_protected(png_structp read_ptr, String8& printableName, png_infop read_info,
+                               const sp<AaptFile>& file, FILE* fp, image_info* imageInfo) {
+    if (setjmp(png_jmpbuf(read_ptr))) {
+        return false;
+    }
+
+    png_init_io(read_ptr, fp);
+
+    read_png(printableName.string(), read_ptr, read_info, imageInfo);
+
+    const size_t nameLen = file->getPath().length();
+    if (nameLen > 6) {
+        const char* name = file->getPath().string();
+        if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
+            if (do_9patch(printableName.string(), imageInfo) != NO_ERROR) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+static bool write_png_protected(png_structp write_ptr, String8& printableName, png_infop write_info,
+                                image_info* imageInfo, const Bundle* bundle) {
+    if (setjmp(png_jmpbuf(write_ptr))) {
+        return false;
+    }
+
+    write_png(printableName.string(), write_ptr, write_info, *imageInfo,
+              bundle->getGrayscaleTolerance());
+
+    return true;
+}
+
+status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */,
+                         const sp<AaptFile>& file, String8* /* outNewLeafName */)
 {
     String8 ext(file->getPath().getPathExtension());
 
@@ -1267,8 +1301,6 @@
 
     status_t error = UNKNOWN_ERROR;
 
-    const size_t nameLen = file->getPath().length();
-
     fp = fopen(file->getSourceFile().string(), "rb");
     if (fp == NULL) {
         fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
@@ -1286,23 +1318,10 @@
         goto bail;
     }
 
-    if (setjmp(png_jmpbuf(read_ptr))) {
+    if (!read_png_protected(read_ptr, printableName, read_info, file, fp, &imageInfo)) {
         goto bail;
     }
 
-    png_init_io(read_ptr, fp);
-
-    read_png(printableName.string(), read_ptr, read_info, &imageInfo);
-
-    if (nameLen > 6) {
-        const char* name = file->getPath().string();
-        if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
-            if (do_9patch(printableName.string(), &imageInfo) != NO_ERROR) {
-                goto bail;
-            }
-        }
-    }
-
     write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, (png_error_ptr)NULL,
                                         (png_error_ptr)NULL);
     if (!write_ptr)
@@ -1319,14 +1338,10 @@
     png_set_write_fn(write_ptr, (void*)file.get(),
                      png_write_aapt_file, png_flush_aapt_file);
 
-    if (setjmp(png_jmpbuf(write_ptr)))
-    {
+    if (!write_png_protected(write_ptr, printableName, write_info, &imageInfo, bundle)) {
         goto bail;
     }
 
-    write_png(printableName.string(), write_ptr, write_info, imageInfo,
-              bundle->getGrayscaleTolerance());
-
     error = NO_ERROR;
 
     if (bundle->getVerbose()) {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 18b8e1e..8b416aa 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -69,7 +69,7 @@
         "        [-S resource-sources [-S resource-sources ...]] \\\n"
         "        [-F apk-file] [-J R-file-dir] \\\n"
         "        [--product product1,product2,...] \\\n"
-        "        [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
+        "        [-c CONFIGS] [--preferred-density DENSITY] \\\n"
         "        [--split CONFIGS [--split CONFIGS]] \\\n"
         "        [--feature-of package [--feature-after package]] \\\n"
         "        [raw-files-dir [raw-files-dir] ...] \\\n"
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index dc16e35..cb244ec 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -402,7 +402,6 @@
 
 ssize_t processJarFile(ZipFile* jar, ZipFile* out)
 {
-    status_t err;
     size_t N = jar->getNumEntries();
     size_t count = 0;
     for (size_t i=0; i<N; i++) {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index e2e83e4..36299c2 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -20,15 +20,20 @@
 
 #include <algorithm>
 
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
 #  define ZD_TYPE ssize_t
+#  define STATUST(x) x
 #else
 #  define ZD "%ld"
 #  define ZD_TYPE long
+#  define STATUST(x) (status_t)x
 #endif
 
-#define NOISY(x) // x
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
 
 // Number of threads to use for preprocessing images.
 static const size_t MAX_THREADS = 4;
@@ -129,15 +134,17 @@
             String8 leaf(group->getLeaf());
             mLeafName = String8(leaf);
             mParams = file->getGroupEntry().toParams();
-            NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
-                   group->getPath().string(), mParams.mcc, mParams.mnc,
-                   mParams.language[0] ? mParams.language[0] : '-',
-                   mParams.language[1] ? mParams.language[1] : '-',
-                   mParams.country[0] ? mParams.country[0] : '-',
-                   mParams.country[1] ? mParams.country[1] : '-',
-                   mParams.orientation, mParams.uiMode,
-                   mParams.density, mParams.touchscreen, mParams.keyboard,
-                   mParams.inputFlags, mParams.navigation));
+            if (kIsDebug) {
+                printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
+                        group->getPath().string(), mParams.mcc, mParams.mnc,
+                        mParams.language[0] ? mParams.language[0] : '-',
+                        mParams.language[1] ? mParams.language[1] : '-',
+                        mParams.country[0] ? mParams.country[0] : '-',
+                        mParams.country[1] ? mParams.country[1] : '-',
+                        mParams.orientation, mParams.uiMode,
+                        mParams.density, mParams.touchscreen, mParams.keyboard,
+                        mParams.inputFlags, mParams.navigation);
+            }
             mPath = "res";
             mPath.appendPath(file->getGroupEntry().toDirName(mResType));
             mPath.appendPath(leaf);
@@ -148,7 +155,9 @@
                 return UNKNOWN_ERROR;
             }
 
-            NOISY(printf("file name=%s\n", mBaseName.string()));
+            if (kIsDebug) {
+                printf("file name=%s\n", mBaseName.string());
+            }
 
             return NO_ERROR;
         }
@@ -326,7 +335,7 @@
         assets->addResource(it.getLeafName(), resPath, it.getFile(), type8);
     }
 
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 class PreProcessImageWorkUnit : public WorkQueue::WorkUnit {
@@ -376,7 +385,7 @@
             hasErrors = true;
         }
     }
-    return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
+    return (hasErrors || (res < NO_ERROR)) ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 static void collect_files(const sp<AaptDir>& dir,
@@ -401,27 +410,35 @@
 
         if (index < 0) {
             sp<ResourceTypeSet> set = new ResourceTypeSet();
-            NOISY(printf("Creating new resource type set for leaf %s with group %s (%p)\n",
-                    leafName.string(), group->getPath().string(), group.get()));
+            if (kIsDebug) {
+                printf("Creating new resource type set for leaf %s with group %s (%p)\n",
+                        leafName.string(), group->getPath().string(), group.get());
+            }
             set->add(leafName, group);
             resources->add(resType, set);
         } else {
             sp<ResourceTypeSet> set = resources->valueAt(index);
             index = set->indexOfKey(leafName);
             if (index < 0) {
-                NOISY(printf("Adding to resource type set for leaf %s group %s (%p)\n",
-                        leafName.string(), group->getPath().string(), group.get()));
+                if (kIsDebug) {
+                    printf("Adding to resource type set for leaf %s group %s (%p)\n",
+                            leafName.string(), group->getPath().string(), group.get());
+                }
                 set->add(leafName, group);
             } else {
                 sp<AaptGroup> existingGroup = set->valueAt(index);
-                NOISY(printf("Extending to resource type set for leaf %s group %s (%p)\n",
-                        leafName.string(), group->getPath().string(), group.get()));
+                if (kIsDebug) {
+                    printf("Extending to resource type set for leaf %s group %s (%p)\n",
+                            leafName.string(), group->getPath().string(), group.get());
+                }
                 for (size_t j=0; j<files.size(); j++) {
-                    NOISY(printf("Adding file %s in group %s resType %s\n",
-                        files.valueAt(j)->getSourceFile().string(),
-                        files.keyAt(j).toDirName(String8()).string(),
-                        resType.string()));
-                    status_t err = existingGroup->addFile(files.valueAt(j));
+                    if (kIsDebug) {
+                        printf("Adding file %s in group %s resType %s\n",
+                                files.valueAt(j)->getSourceFile().string(),
+                                files.keyAt(j).toDirName(String8()).string(),
+                                resType.string());
+                    }
+                    existingGroup->addFile(files.valueAt(j));
                 }
             }
         }
@@ -436,12 +453,16 @@
 
     for (int i=0; i<N; i++) {
         sp<AaptDir> d = dirs.itemAt(i);
-        NOISY(printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
-                d->getLeaf().string()));
+        if (kIsDebug) {
+            printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
+                    d->getLeaf().string());
+        }
         collect_files(d, resources);
 
         // don't try to include the res dir
-        NOISY(printf("Removing dir leaf %s\n", d->getLeaf().string()));
+        if (kIsDebug) {
+            printf("Removing dir leaf %s\n", d->getLeaf().string());
+        }
         ass->removeDir(d->getLeaf());
     }
 }
@@ -536,7 +557,7 @@
                     String8(parser.getElementName(&len)).string(), attr);
             return ATTR_LEADING_SPACES;
         }
-        if (str[len-1] == ' ') {
+        if (len != 0 && str[len-1] == ' ') {
             fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not end with a space.\n",
                     path.string(), parser.getLineNumber(),
                     String8(parser.getElementName(&len)).string(), attr);
@@ -699,9 +720,11 @@
     XMLNode::attribute_entry* existingEntry = node->editAttribute(ns, attr);
     if (existingEntry != NULL) {
         if (replaceExisting) {
-            NOISY(printf("Info: AndroidManifest.xml already defines %s (in %s);"
-                         " overwriting existing value from manifest.\n",
-                         String8(attr).string(), String8(ns).string()));
+            if (kIsDebug) {
+                printf("Info: AndroidManifest.xml already defines %s (in %s);"
+                        " overwriting existing value from manifest.\n",
+                        String8(attr).string(), String8(ns).string());
+            }
             existingEntry->string = String16(value);
             return true;
         }
@@ -760,7 +783,9 @@
         } else {
             className += name;
         }
-        NOISY(printf("Qualifying class '%s' to '%s'", name.string(), className.string()));
+        if (kIsDebug) {
+            printf("Qualifying class '%s' to '%s'", name.string(), className.string());
+        }
         attr->string.setTo(String16(className));
     }
 }
@@ -864,7 +889,10 @@
         }
         String8 origPackage(attr->string);
         attr->string.setTo(String16(manifestPackageNameOverride));
-        NOISY(printf("Overriding package '%s' to be '%s'\n", origPackage.string(), manifestPackageNameOverride));
+        if (kIsDebug) {
+            printf("Overriding package '%s' to be '%s'\n", origPackage.string(),
+                    manifestPackageNameOverride);
+        }
 
         // Make class names fully qualified
         sp<XMLNode> application = root->getChildElement(String16(), String16("application"));
@@ -1129,8 +1157,9 @@
         return err;
     }
 
-    NOISY(printf("Creating resources for package %s\n",
-                 assets->getPackage().string()));
+    if (kIsDebug) {
+        printf("Creating resources for package %s\n", assets->getPackage().string());
+    }
 
     ResourceTable::PackageType packageType = ResourceTable::App;
     if (bundle->getBuildSharedLibrary()) {
@@ -1147,7 +1176,9 @@
         return err;
     }
 
-    NOISY(printf("Found %d included resource packages\n", (int)table.size()));
+    if (kIsDebug) {
+        printf("Found %d included resource packages\n", (int)table.size());
+    }
 
     // Standard flags for compiled XML and optional UTF-8 encoding
     int xmlFlags = XML_COMPILE_STANDARD_RESOURCE;
@@ -2052,7 +2083,7 @@
 
 static status_t writeResourceLoadedCallbackForLayoutClasses(
     FILE* fp, const sp<AaptAssets>& assets,
-    const sp<AaptSymbols>& symbols, int indent, bool includePrivate)
+    const sp<AaptSymbols>& symbols, int indent, bool /* includePrivate */)
 {
     String16 attr16("attr");
     String16 package16(assets->getPackage());
@@ -2356,7 +2387,7 @@
 
     indent--;
     fprintf(fp, "%s};\n", getIndentSpace(indent));
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 static status_t writeTextLayoutClasses(
@@ -2442,7 +2473,7 @@
                     package16.string(), package16.size(), &typeSpecFlags);
                 //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
                 //    String8(attr16).string(), String8(name16).string(), typeSpecFlags);
-                const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
+                //const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
 
                 fprintf(fp,
                         "int styleable %s_%s %d\n",
@@ -2452,7 +2483,7 @@
         }
     }
 
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 static status_t writeSymbolClass(
@@ -2783,7 +2814,7 @@
 
 void
 addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName,
-        const char* pkg, const String8& srcName, int line)
+        const char* /* pkg */, const String8& srcName, int line)
 {
     String8 rule("-keepclassmembers class * { *** ");
     rule += memberName;
@@ -3123,7 +3154,7 @@
 }
 
 status_t
-writeDependencyPreReqs(Bundle* bundle, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw)
+writeDependencyPreReqs(Bundle* /* bundle */, const sp<AaptAssets>& assets, FILE* fp, bool includeRaw)
 {
     status_t deps = -1;
     deps += writePathsToFile(assets->getFullResPaths(), fp);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index e000a1d..941a288 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -18,7 +18,24 @@
 #include <utils/TypeHelpers.h>
 #include <stdarg.h>
 
-#define NOISY(x) //x
+// SSIZE: mingw does not have signed size_t == ssize_t.
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+#if HAVE_PRINTF_ZD
+#  define SSIZE(x) x
+#  define STATUST(x) x
+#else
+#  define SSIZE(x) (signed size_t)x
+#  define STATUST(x) (status_t)x
+#endif
+
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
+
+#if PRINT_STRING_METRICS
+static const bool kPrintStringMetrics = true;
+#else
+static const bool kPrintStringMetrics = false;
+#endif
 
 static const char* kAttrPrivateType = "^attr-private";
 
@@ -92,9 +109,11 @@
     if (table->modifyForCompat(bundle, resourceName, target, root) != NO_ERROR) {
         return UNKNOWN_ERROR;
     }
-    
-    NOISY(printf("Input XML Resource:\n"));
-    NOISY(root->print());
+
+    if (kIsDebug) {
+        printf("Input XML Resource:\n");
+        root->print();
+    }
     err = root->flatten(target,
             (options&XML_COMPILE_STRIP_COMMENTS) != 0,
             (options&XML_COMPILE_STRIP_RAW_VALUES) != 0);
@@ -102,19 +121,18 @@
         return err;
     }
 
-    NOISY(printf("Output XML Resource:\n"));
-    NOISY(ResXMLTree tree;
+    if (kIsDebug) {
+        printf("Output XML Resource:\n");
+        ResXMLTree tree;
         tree.setTo(target->getData(), target->getSize());
-        printXMLBlock(&tree));
+        printXMLBlock(&tree);
+    }
 
     target->setCompressionMethod(ZipEntry::kCompressDeflated);
     
     return err;
 }
 
-#undef NOISY
-#define NOISY(x) //x
-
 struct flag_entry
 {
     const char16_t* name;
@@ -583,7 +601,7 @@
                         const String16& itemIdent,
                         int32_t curFormat,
                         bool isFormatted,
-                        const String16& product,
+                        const String16& /* product */,
                         PseudolocalizationMethod pseudolocalize,
                         const bool overwrite,
                         ResourceTable* outTable)
@@ -599,16 +617,18 @@
     if (err != NO_ERROR) {
         return err;
     }
-    
-    NOISY(printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
-                 " pid=%s, bag=%s, id=%s: %s\n",
-                 config.language[0], config.language[1],
-                 config.country[0], config.country[1],
-                 config.orientation, config.density,
-                 String8(parentIdent).string(),
-                 String8(ident).string(),
-                 String8(itemIdent).string(),
-                 String8(str).string()));
+
+    if (kIsDebug) {
+        printf("Adding resource bag entry l=%c%c c=%c%c orien=%d d=%d "
+                " pid=%s, bag=%s, id=%s: %s\n",
+                config.language[0], config.language[1],
+                config.country[0], config.country[1],
+                config.orientation, config.density,
+                String8(parentIdent).string(),
+                String8(ident).string(),
+                String8(itemIdent).string(),
+                String8(str).string());
+    }
 
     err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
                            myPackage, curType, ident, parentIdent, itemIdent, str,
@@ -744,11 +764,13 @@
         }
     }
 
-    NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
-                 config.language[0], config.language[1],
-                 config.country[0], config.country[1],
-                 config.orientation, config.density,
-                 String8(ident).string(), String8(str).string()));
+    if (kIsDebug) {
+        printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
+                config.language[0], config.language[1],
+                config.country[0], config.country[1],
+                config.orientation, config.density,
+                String8(ident).string(), String8(str).string());
+    }
 
     err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
                              myPackage, curType, ident, str, &spans, &config,
@@ -1717,7 +1739,7 @@
         }
     }
 
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 ResourceTable::ResourceTable(Bundle* bundle, const String16& assetsPackage, ResourceTable::PackageType type)
@@ -1785,7 +1807,7 @@
         }
 
         const ResTable& featureTable = featureAssetManager.getResources(false);
-        mTypeIdOffset = max(mTypeIdOffset,
+        mTypeIdOffset = std::max(mTypeIdOffset,
                 findLargestTypeIdForPackage(featureTable, mAssetsPackage)); 
     }
 
@@ -1856,7 +1878,7 @@
                                  const String16& bagParent,
                                  const ResTable_config* params,
                                  bool overlay,
-                                 bool replace, bool isId)
+                                 bool replace, bool /* isId */)
 {
     status_t result = NO_ERROR;
 
@@ -2163,22 +2185,25 @@
         ref.string(), ref.size(), &package, &type, &name,
         defType, defPackage ? defPackage:&mAssetsPackage,
         outErrorMsg, &refOnlyPublic)) {
-        NOISY(printf("Expanding resource: ref=%s\n",
-                     String8(ref).string()));
-        NOISY(printf("Expanding resource: defType=%s\n",
-                     defType ? String8(*defType).string() : "NULL"));
-        NOISY(printf("Expanding resource: defPackage=%s\n",
-                     defPackage ? String8(*defPackage).string() : "NULL"));
-        NOISY(printf("Expanding resource: ref=%s\n", String8(ref).string()));
-        NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
-                     String8(package).string(), String8(type).string(),
-                     String8(name).string()));
+        if (kIsDebug) {
+            printf("Expanding resource: ref=%s\n", String8(ref).string());
+            printf("Expanding resource: defType=%s\n",
+                    defType ? String8(*defType).string() : "NULL");
+            printf("Expanding resource: defPackage=%s\n",
+                    defPackage ? String8(*defPackage).string() : "NULL");
+            printf("Expanding resource: ref=%s\n", String8(ref).string());
+            printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
+                    String8(package).string(), String8(type).string(),
+                    String8(name).string());
+        }
         return 0;
     }
     uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
-    NOISY(printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
-                 String8(package).string(), String8(type).string(),
-                 String8(name).string(), res));
+    if (kIsDebug) {
+        printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
+                String8(package).string(), String8(type).string(),
+                String8(name).string(), res);
+    }
     if (res == 0) {
         if (outErrorMsg)
             *outErrorMsg = "No resource found that matches the given name";
@@ -2245,9 +2270,11 @@
             } else {
                 configStr = "(null)";
             }
-            NOISY(printf("Adding to pool string style #%d config %s: %s\n",
-                    style != NULL ? style->size() : 0,
-                    configStr.string(), String8(finalStr).string()));
+            if (kIsDebug) {
+                printf("Adding to pool string style #%zu config %s: %s\n",
+                        style != NULL ? style->size() : 0U,
+                        configStr.string(), String8(finalStr).string());
+            }
             if (style != NULL && style->size() > 0) {
                 outValue->data = pool->add(finalStr, *style, configTypeName, config);
             } else {
@@ -2676,20 +2703,16 @@
     const String8 defaultLocale;
 
     // For all strings...
-    for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin();
-         nameIter != mLocalizations.end();
-         nameIter++) {
-        const map<String8, SourcePos>& configSrcMap = nameIter->second;
+    for (const auto& nameIter : mLocalizations) {
+        const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
 
         // Look for strings with no default localization
         if (configSrcMap.count(defaultLocale) == 0) {
             SourcePos().warning("string '%s' has no default translation.",
-                    String8(nameIter->first).string());
+                    String8(nameIter.first).string());
             if (mBundle->getVerbose()) {
-                for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin();
-                    locales != configSrcMap.end();
-                    locales++) {
-                    locales->second.printf("locale %s found", locales->first.string());
+                for (const auto& locale : configSrcMap) {
+                    locale.second.printf("locale %s found", locale.first.string());
                 }
             }
             // !!! TODO: throw an error here in some circumstances
@@ -2700,8 +2723,8 @@
             const char* allConfigs = mBundle->getConfigurations().string();
             const char* start = allConfigs;
             const char* comma;
-            
-            set<String8> missingConfigs;
+
+            std::set<String8> missingConfigs;
             AaptLocaleValue locale;
             do {
                 String8 config;
@@ -2735,13 +2758,11 @@
 
             if (!missingConfigs.empty()) {
                 String8 configStr;
-                for (set<String8>::iterator iter = missingConfigs.begin();
-                     iter != missingConfigs.end();
-                     iter++) {
-                    configStr.appendFormat(" %s", iter->string());
+                for (const auto& iter : missingConfigs) {
+                    configStr.appendFormat(" %s", iter.string());
                 }
                 SourcePos().warning("string '%s' is missing %u required localizations:%s",
-                        String8(nameIter->first).string(),
+                        String8(nameIter.first).string(),
                         (unsigned int)missingConfigs.size(),
                         configStr.string());
             }
@@ -2914,9 +2935,9 @@
         const size_t typeStringsStart = data->getSize();
         sp<AaptFile> strFile = p->getTypeStringsData();
         ssize_t amt = data->writeData(strFile->getData(), strFile->getSize());
-        #if PRINT_STRING_METRICS
-        fprintf(stderr, "**** type strings: %d\n", amt);
-        #endif
+        if (kPrintStringMetrics) {
+            fprintf(stderr, "**** type strings: %zd\n", SSIZE(amt));
+        }
         strAmt += amt;
         if (amt < 0) {
             return amt;
@@ -2924,9 +2945,9 @@
         const size_t keyStringsStart = data->getSize();
         strFile = p->getKeyStringsData();
         amt = data->writeData(strFile->getData(), strFile->getSize());
-        #if PRINT_STRING_METRICS
-        fprintf(stderr, "**** key strings: %d\n", amt);
-        #endif
+        if (kPrintStringMetrics) {
+            fprintf(stderr, "**** key strings: %zd\n", SSIZE(amt));
+        }
         strAmt += amt;
         if (amt < 0) {
             return amt;
@@ -3022,36 +3043,41 @@
 
             // We need to write one type chunk for each configuration for
             // which we have entries in this type.
-            const SortedVector<ConfigDescription> uniqueConfigs(t->getUniqueConfigs());
-            const size_t NC = uniqueConfigs.size();
+            SortedVector<ConfigDescription> uniqueConfigs;
+            if (t != NULL) {
+                uniqueConfigs = t->getUniqueConfigs();
+            }
             
             const size_t typeSize = sizeof(ResTable_type) + sizeof(uint32_t)*N;
             
+            const size_t NC = uniqueConfigs.size();
             for (size_t ci=0; ci<NC; ci++) {
                 const ConfigDescription& config = uniqueConfigs[ci];
 
-                NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
-                     "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                     "sw%ddp w%ddp h%ddp dir:%d\n",
-                      ti+1,
-                      config.mcc, config.mnc,
-                      config.language[0] ? config.language[0] : '-',
-                      config.language[1] ? config.language[1] : '-',
-                      config.country[0] ? config.country[0] : '-',
-                      config.country[1] ? config.country[1] : '-',
-                      config.orientation,
-                      config.uiMode,
-                      config.touchscreen,
-                      config.density,
-                      config.keyboard,
-                      config.inputFlags,
-                      config.navigation,
-                      config.screenWidth,
-                      config.screenHeight,
-                      config.smallestScreenWidthDp,
-                      config.screenWidthDp,
-                      config.screenHeightDp,
-                      config.layoutDirection));
+                if (kIsDebug) {
+                    printf("Writing config %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
+                        "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
+                        "sw%ddp w%ddp h%ddp layout:%d\n",
+                        ti + 1,
+                        config.mcc, config.mnc,
+                        config.language[0] ? config.language[0] : '-',
+                        config.language[1] ? config.language[1] : '-',
+                        config.country[0] ? config.country[0] : '-',
+                        config.country[1] ? config.country[1] : '-',
+                        config.orientation,
+                        config.uiMode,
+                        config.touchscreen,
+                        config.density,
+                        config.keyboard,
+                        config.inputFlags,
+                        config.navigation,
+                        config.screenWidth,
+                        config.screenHeight,
+                        config.smallestScreenWidthDp,
+                        config.screenWidthDp,
+                        config.screenHeightDp,
+                        config.screenLayout);
+                }
                       
                 if (filterable && !filter->match(config)) {
                     continue;
@@ -3073,28 +3099,30 @@
                 tHeader->entryCount = htodl(N);
                 tHeader->entriesStart = htodl(typeSize);
                 tHeader->config = config;
-                NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c "
-                     "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                     "sw%ddp w%ddp h%ddp dir:%d\n",
-                      ti+1,
-                      tHeader->config.mcc, tHeader->config.mnc,
-                      tHeader->config.language[0] ? tHeader->config.language[0] : '-',
-                      tHeader->config.language[1] ? tHeader->config.language[1] : '-',
-                      tHeader->config.country[0] ? tHeader->config.country[0] : '-',
-                      tHeader->config.country[1] ? tHeader->config.country[1] : '-',
-                      tHeader->config.orientation,
-                      tHeader->config.uiMode,
-                      tHeader->config.touchscreen,
-                      tHeader->config.density,
-                      tHeader->config.keyboard,
-                      tHeader->config.inputFlags,
-                      tHeader->config.navigation,
-                      tHeader->config.screenWidth,
-                      tHeader->config.screenHeight,
-                      tHeader->config.smallestScreenWidthDp,
-                      tHeader->config.screenWidthDp,
-                      tHeader->config.screenHeightDp,
-                      tHeader->config.layoutDirection));
+                if (kIsDebug) {
+                    printf("Writing type %zu config: imsi:%d/%d lang:%c%c cnt:%c%c "
+                        "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
+                        "sw%ddp w%ddp h%ddp layout:%d\n",
+                        ti + 1,
+                        tHeader->config.mcc, tHeader->config.mnc,
+                        tHeader->config.language[0] ? tHeader->config.language[0] : '-',
+                        tHeader->config.language[1] ? tHeader->config.language[1] : '-',
+                        tHeader->config.country[0] ? tHeader->config.country[0] : '-',
+                        tHeader->config.country[1] ? tHeader->config.country[1] : '-',
+                        tHeader->config.orientation,
+                        tHeader->config.uiMode,
+                        tHeader->config.touchscreen,
+                        tHeader->config.density,
+                        tHeader->config.keyboard,
+                        tHeader->config.inputFlags,
+                        tHeader->config.navigation,
+                        tHeader->config.screenWidth,
+                        tHeader->config.screenHeight,
+                        tHeader->config.smallestScreenWidthDp,
+                        tHeader->config.screenWidthDp,
+                        tHeader->config.screenHeightDp,
+                        tHeader->config.screenLayout);
+                }
                 tHeader->config.swapHtoD();
 
                 // Build the entries inside of this type.
@@ -3189,10 +3217,10 @@
 
     ssize_t amt = (dest->getSize()-strStart);
     strAmt += amt;
-    #if PRINT_STRING_METRICS
-    fprintf(stderr, "**** value strings: %d\n", amt);
-    fprintf(stderr, "**** total strings: %d\n", strAmt);
-    #endif
+    if (kPrintStringMetrics) {
+        fprintf(stderr, "**** value strings: %zd\n", SSIZE(amt));
+        fprintf(stderr, "**** total strings: %zd\n", SSIZE(strAmt));
+    }
 
     for (pi=0; pi<flatPackages.size(); pi++) {
         err = dest->writeData(flatPackages[pi]->getData(),
@@ -3207,13 +3235,10 @@
         (((uint8_t*)dest->getData()) + dataStart);
     header->header.size = htodl(dest->getSize() - dataStart);
 
-    NOISY(aout << "Resource table:"
-          << HexDump(dest->getData(), dest->getSize()) << endl);
-
-    #if PRINT_STRING_METRICS
-    fprintf(stderr, "**** total resource table size: %d / %d%% strings\n",
-        dest->getSize(), (strAmt*100)/dest->getSize());
-    #endif
+    if (kPrintStringMetrics) {
+        fprintf(stderr, "**** total resource table size: %zu / %zu%% strings\n",
+                dest->getSize(), (size_t)(strAmt*100)/dest->getSize());
+    }
     
     return NO_ERROR;
 }
@@ -3221,7 +3246,9 @@
 status_t ResourceTable::flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs) {
     // Write out the library table if necessary
     if (libs.size() > 0) {
-        NOISY(fprintf(stderr, "Writing library reference table\n"));
+        if (kIsDebug) {
+            fprintf(stderr, "Writing library reference table\n");
+        }
 
         const size_t libStart = dest->getSize();
         const size_t count = libs.size();
@@ -3238,9 +3265,11 @@
         for (size_t i = 0; i < count; i++) {
             const size_t entryStart = dest->getSize();
             sp<Package> libPackage = libs[i];
-            NOISY(fprintf(stderr, "  Entry %s -> 0x%02x\n",
+            if (kIsDebug) {
+                fprintf(stderr, "  Entry %s -> 0x%02x\n",
                         String8(libPackage->getName()).string(),
-                        (uint8_t)libPackage->getAssignedId()));
+                        (uint8_t)libPackage->getAssignedId());
+            }
 
             ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(
                     entryStart, sizeof(ResTable_lib_entry));
@@ -3488,9 +3517,11 @@
         if (it.isId) {
             if (!table->hasBagOrEntry(key, &id16, &package)) {
                 String16 value("false");
-                NOISY(fprintf(stderr, "Generating %s:id/%s\n",
-                        String8(package).string(),
-                        String8(key).string()));
+                if (kIsDebug) {
+                    fprintf(stderr, "Generating %s:id/%s\n",
+                            String8(package).string(),
+                            String8(key).string());
+                }
                 status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
                                                id16, key, value);
                 if (err != NO_ERROR) {
@@ -3523,7 +3554,7 @@
 }
 
 status_t ResourceTable::Entry::assignResourceIds(ResourceTable* table,
-                                                 const String16& package)
+                                                 const String16& /* package */)
 {
     bool hasErrors = false;
     
@@ -3556,7 +3587,7 @@
             }
         }
     }
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
@@ -3615,22 +3646,20 @@
     return NO_ERROR;
 }
 
-ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic)
+ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp<AaptFile>& data, bool isPublic)
 {
     size_t amt = 0;
     ResTable_entry header;
     memset(&header, 0, sizeof(header));
     header.size = htods(sizeof(header));
-    const type ty = this != NULL ? mType : TYPE_ITEM;
-    if (this != NULL) {
-        if (ty == TYPE_BAG) {
-            header.flags |= htods(header.FLAG_COMPLEX);
-        }
-        if (isPublic) {
-            header.flags |= htods(header.FLAG_PUBLIC);
-        }
-        header.key.index = htodl(mNameIndex);
+    const type ty = mType;
+    if (ty == TYPE_BAG) {
+        header.flags |= htods(header.FLAG_COMPLEX);
     }
+    if (isPublic) {
+        header.flags |= htods(header.FLAG_PUBLIC);
+    }
+    header.key.index = htodl(mNameIndex);
     if (ty != TYPE_BAG) {
         status_t err = data->writeData(&header, sizeof(header));
         if (err != NO_ERROR) {
@@ -3805,10 +3834,11 @@
     
     sp<Entry> e = c->getEntries().valueFor(cdesc);
     if (e == NULL) {
-        if (config != NULL) {
-            NOISY(printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
+        if (kIsDebug) {
+            if (config != NULL) {
+                printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
-                    "sw%ddp w%ddp h%ddp dir:%d\n",
+                    "sw%ddp w%ddp h%ddp layout:%d\n",
                       sourcePos.file.string(), sourcePos.line,
                       config->mcc, config->mnc,
                       config->language[0] ? config->language[0] : '-',
@@ -3826,10 +3856,11 @@
                       config->smallestScreenWidthDp,
                       config->screenWidthDp,
                       config->screenHeightDp,
-                      config->layoutDirection));
-        } else {
-            NOISY(printf("New entry at %s:%d: NULL config\n",
-                      sourcePos.file.string(), sourcePos.line));
+                      config->screenLayout);
+            } else {
+                printf("New entry at %s:%d: NULL config\n",
+                        sourcePos.file.string(), sourcePos.line);
+            }
         }
         e = new Entry(entry, sourcePos);
         c->addEntry(cdesc, e);
@@ -3968,7 +3999,7 @@
         j++;
     }
 
-    return hasError ? UNKNOWN_ERROR : NO_ERROR;
+    return hasError ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 ResourceTable::Package::Package(const String16& name, size_t packageId)
@@ -4032,9 +4063,6 @@
         return UNKNOWN_ERROR;
     }
 
-    NOISY(aout << "Setting restable string pool: "
-          << HexDump(data->getData(), data->getSize()) << endl);
-
     status_t err = strings->setTo(data->getData(), data->getSize());
     if (err == NO_ERROR) {
         const size_t N = strings->size();
@@ -4313,7 +4341,7 @@
         }
         item->evaluating = true;
         res = stringToValue(outValue, NULL, item->value, false, false, item->bagKeyId);
-        NOISY(
+        if (kIsDebug) {
             if (res) {
                 printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
                        resID, attrID, String8(getEntry(resID)->getName()).string(),
@@ -4322,7 +4350,7 @@
                 printf("getItemValue of #%08x[#%08x]: failed\n",
                        resID, attrID);
             }
-        );
+        }
         item->evaluating = false;
     }
     return res;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eef0ae1..9644224 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -17,8 +17,6 @@
 #include "StringPool.h"
 #include "Symbol.h"
 
-using namespace std;
-
 class XMLNode;
 class ResourceTable;
 
@@ -29,7 +27,7 @@
     XML_COMPILE_STRIP_WHITESPACE = 1<<3,
     XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
     XML_COMPILE_UTF8 = 1<<5,
-    
+
     XML_COMPILE_STANDARD_RESOURCE =
             XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
             | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
@@ -116,7 +114,7 @@
      * and would mess up iteration order for the existing
      * resources.
      */
-    queue<CompileResourceWorkItem>& getWorkQueue() {
+    std::queue<CompileResourceWorkItem>& getWorkQueue() {
         return mWorkQueue;
     }
 
@@ -587,10 +585,10 @@
     size_t mNumLocal;
     SourcePos mCurrentXmlPos;
     Bundle* mBundle;
-    
+
     // key = string resource name, value = set of locales in which that name is defined
-    map<String16, map<String8, SourcePos> > mLocalizations;
-    queue<CompileResourceWorkItem> mWorkQueue;
+    std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+    std::queue<CompileResourceWorkItem> mWorkQueue;
 };
 
 #endif
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 2727b3d..a18e9f1 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -3,23 +3,28 @@
 //
 // Build resource files from raw assets.
 //
-
 #include "StringPool.h"
-#include "ResourceTable.h"
 
 #include <utils/ByteOrder.h>
 #include <utils/SortedVector.h>
-#include "qsort_r_compat.h"
 
+#include <algorithm>
+
+#include "ResourceTable.h"
+
+// SSIZE: mingw does not have signed size_t == ssize_t.
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
 #  define ZD_TYPE ssize_t
+#  define SSIZE(x) x
 #else
 #  define ZD "%ld"
 #  define ZD_TYPE long
+#  define SSIZE(x) (signed size_t)x
 #endif
 
-#define NOISY(x) //x
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
 
 #if __cplusplus >= 201103L
 void strcpy16_htod(char16_t* dst, const char16_t* src)
@@ -152,8 +157,10 @@
 
     if (configTypeName != NULL) {
         entry& ent = mEntries.editItemAt(eidx);
-        NOISY(printf("*** adding config type name %s, was %s\n",
-                configTypeName->string(), ent.configTypeName.string()));
+        if (kIsDebug) {
+            printf("*** adding config type name %s, was %s\n",
+                    configTypeName->string(), ent.configTypeName.string());
+        }
         if (ent.configTypeName.size() <= 0) {
             ent.configTypeName = *configTypeName;
         } else if (ent.configTypeName != *configTypeName) {
@@ -169,14 +176,18 @@
             int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
             if (cmp >= 0) {
                 if (cmp > 0) {
-                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
+                    if (kIsDebug) {
+                        printf("*** inserting config: %s\n", config->toString().string());
+                    }
                     ent.configs.insertAt(*config, addPos);
                 }
                 break;
             }
         }
         if (addPos >= ent.configs.size()) {
-            NOISY(printf("*** adding config: %s\n", config->toString().string()));
+            if (kIsDebug) {
+                printf("*** adding config: %s\n", config->toString().string());
+            }
             ent.configs.add(*config);
         }
     }
@@ -193,9 +204,11 @@
         ent.indices.add(pos);
     }
 
-    NOISY(printf("Adding string %s to pool: pos=%d eidx=%d vidx=%d\n",
-            String8(value).string(), pos, eidx, vidx));
-    
+    if (kIsDebug) {
+        printf("Adding string %s to pool: pos=%zd eidx=%zd vidx=%zd\n",
+                String8(value).string(), SSIZE(pos), SSIZE(eidx), SSIZE(vidx));
+    }
+
     return pos;
 }
 
@@ -234,12 +247,15 @@
     return NO_ERROR;
 }
 
-int StringPool::config_sort(void* state, const void* lhs, const void* rhs)
+StringPool::ConfigSorter::ConfigSorter(const StringPool& pool) : pool(pool)
 {
-    StringPool* pool = (StringPool*)state;
-    const entry& lhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(lhs)]];
-    const entry& rhe = pool->mEntries[pool->mEntryArray[*static_cast<const size_t*>(rhs)]];
-    return lhe.compare(rhe);
+}
+
+bool StringPool::ConfigSorter::operator()(size_t l, size_t r)
+{
+    const StringPool::entry& lhe = pool.mEntries[pool.mEntryArray[l]];
+    const StringPool::entry& rhe = pool.mEntries[pool.mEntryArray[r]];
+    return lhe.compare(rhe) < 0;
 }
 
 void StringPool::sortByConfig()
@@ -259,12 +275,14 @@
     }
 
     // Sort the array.
-    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
-    // Vector::sort uses insertion sort, which is very slow for this data set.
-    // Use quicksort instead because we don't need a stable sort here.
-    qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
-    //newPosToOriginalPos.sort(config_sort, this);
-    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
+    if (kIsDebug) {
+        printf("SORTING STRINGS BY CONFIGURATION...\n");
+    }
+    ConfigSorter sorter(*this);
+    std::sort(newPosToOriginalPos.begin(), newPosToOriginalPos.end(), sorter);
+    if (kIsDebug) {
+        printf("DONE SORTING STRINGS BY CONFIGURATION.\n");
+    }
 
     // Create the reverse mapping from the original position in the array
     // to the new position where it appears in the sorted array.  This is
@@ -467,9 +485,9 @@
 
             strncpy((char*)strings, encStr, encSize+1);
         } else {
-            uint16_t* strings = (uint16_t*)dat;
+            char16_t* strings = (char16_t*)dat;
 
-            ENCODE_LENGTH(strings, sizeof(uint16_t), strSize)
+            ENCODE_LENGTH(strings, sizeof(char16_t), strSize)
 
             strcpy16_htod(strings, ent.value);
         }
@@ -561,9 +579,13 @@
     for (i=0; i<ENTRIES; i++) {
         entry& ent = mEntries.editItemAt(mEntryArray[i]);
         *index++ = htodl(ent.offset);
-        NOISY(printf("Writing entry #%d: \"%s\" ent=%d off=%d\n", i,
-                String8(ent.value).string(),
-                mEntryArray[i], ent.offset));
+        if (kIsDebug) {
+            printf("Writing entry #%zu: \"%s\" ent=%zu off=%zu\n",
+                    i,
+                    String8(ent.value).string(),
+                    mEntryArray[i],
+                    ent.offset);
+        }
     }
 
     // Write style index array.
@@ -579,8 +601,10 @@
 {
     const Vector<size_t>* indices = offsetsForString(val);
     ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
-    NOISY(printf("Offset for string %s: %d (%s)\n", String8(val).string(), res,
-            res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8()));
+    if (kIsDebug) {
+        printf("Offset for string %s: %zd (%s)\n", String8(val).string(), SSIZE(res),
+                res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8());
+    }
     return res;
 }
 
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index a9c7bec..dbe8c85 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -141,7 +141,14 @@
     const Vector<size_t>* offsetsForString(const String16& val) const;
 
 private:
-    static int config_sort(void* state, const void* lhs, const void* rhs);
+    class ConfigSorter
+    {
+    public:
+        explicit ConfigSorter(const StringPool&);
+        bool operator()(size_t l, size_t r);
+    private:
+        const StringPool& pool;
+    };
 
     const bool                              mUTF8;
 
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 899fb63..b38b2ed 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -16,8 +16,26 @@
 #define O_BINARY 0
 #endif
 
-#define NOISY(x) //x
-#define NOISY_PARSE(x) //x
+// SSIZE: mingw does not have signed size_t == ssize_t.
+// STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
+#if HAVE_PRINTF_ZD
+#  define SSIZE(x) x
+#  define STATUST(x) x
+#else
+#  define SSIZE(x) (signed size_t)x
+#  define STATUST(x) (status_t)x
+#endif
+
+// Set to true for noisy debug output.
+static const bool kIsDebug = false;
+// Set to true for noisy debug output of parsing.
+static const bool kIsDebugParse = false;
+
+#if PRINT_STRING_METRICS
+static const bool kPrintStringMetrics = true;
+#else
+static const bool kPrintStringMetrics = false;
+#endif
 
 const char* const RESOURCES_ROOT_NAMESPACE = "http://schemas.android.com/apk/res/";
 const char* const RESOURCES_ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
@@ -56,7 +74,10 @@
     size_t prefixSize;
     bool isPublic = true;
     if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) {
-        NOISY(printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(), String8(appPackage).string()));
+        if (kIsDebug) {
+            printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(),
+                   String8(appPackage).string());
+        }
         isPublic = true;
         return appPackage;
     } else if (namespaceUri.startsWith(RESOURCES_PREFIX)) {
@@ -180,7 +201,7 @@
     return NO_ERROR;
 }
 
-status_t parseStyledString(Bundle* bundle,
+status_t parseStyledString(Bundle* /* bundle */,
                            const char* fileName,
                            ResXMLTree* inXml,
                            const String16& endTag,
@@ -557,8 +578,10 @@
     }
     root->removeWhitespace(stripAll, cDataTags);
 
-    NOISY(printf("Input XML from %s:\n", (const char*)file->getPrintableSource()));
-    NOISY(root->print());
+    if (kIsDebug) {
+        printf("Input XML from %s:\n", (const char*)file->getPrintableSource());
+        root->print();
+    }
     sp<AaptFile> rsc = new AaptFile(String8(), AaptGroupEntry(), String8());
     status_t err = root->flatten(rsc, !keepComments, false);
     if (err != NO_ERROR) {
@@ -569,8 +592,10 @@
         return err;
     }
 
-    NOISY(printf("Output XML:\n"));
-    NOISY(printXMLBlock(outTree));
+    if (kIsDebug) {
+        printf("Output XML:\n");
+        printXMLBlock(outTree);
+    }
 
     return NO_ERROR;
 }
@@ -850,11 +875,13 @@
     } else {
         mAttributeOrder.removeItem(e.index);
     }
-    NOISY(printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
-            String8(getElementName()).string(),
-            String8(mAttributes.itemAt(attrIdx).name).string(),
-            String8(mAttributes.itemAt(attrIdx).string).string(),
-            resId));
+    if (kIsDebug) {
+        printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
+                String8(getElementName()).string(),
+                String8(mAttributes.itemAt(attrIdx).name).string(),
+                String8(mAttributes.itemAt(attrIdx).string).string(),
+                resId);
+    }
     mAttributes.editItemAt(attrIdx).nameResId = resId;
     mAttributeOrder.add(resId, attrIdx);
 }
@@ -965,9 +992,11 @@
                                   e.nameResId, NULL, &defPackage, table, &ac)) {
                 hasErrors = true;
             }
-            NOISY(printf("Attr %s: type=0x%x, str=%s\n",
-                   String8(e.name).string(), e.value.dataType,
-                   String8(e.string).string()));
+            if (kIsDebug) {
+                printf("Attr %s: type=0x%x, str=%s\n",
+                        String8(e.name).string(), e.value.dataType,
+                        String8(e.string).string());
+            }
         }
     }
     const size_t N = mChildren.size();
@@ -977,7 +1006,7 @@
             hasErrors = true;
         }
     }
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 status_t XMLNode::assignResourceIds(const sp<AaptAssets>& assets,
@@ -992,15 +1021,17 @@
         for (size_t i=0; i<N; i++) {
             const attribute_entry& e = mAttributes.itemAt(i);
             if (e.ns.size() <= 0) continue;
-            bool nsIsPublic;
+            bool nsIsPublic = true;
             String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic));
-            NOISY(printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
-                    String8(getElementName()).string(),
-                    String8(e.name).string(),
-                    String8(e.string).string(),
-                    String8(e.ns).string(),
-                    (nsIsPublic) ? "public" : "private",
-                    String8(pkg).string()));
+            if (kIsDebug) {
+                printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
+                        String8(getElementName()).string(),
+                        String8(e.name).string(),
+                        String8(e.string).string(),
+                        String8(e.ns).string(),
+                        (nsIsPublic) ? "public" : "private",
+                        String8(pkg).string());
+            }
             if (pkg.size() <= 0) continue;
             uint32_t res = table != NULL
                 ? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic)
@@ -1009,8 +1040,10 @@
                                       attr.string(), attr.size(),
                                       pkg.string(), pkg.size());
             if (res != 0) {
-                NOISY(printf("XML attribute name %s: resid=0x%08x\n",
-                             String8(e.name).string(), res));
+                if (kIsDebug) {
+                    printf("XML attribute name %s: resid=0x%08x\n",
+                            String8(e.name).string(), res);
+                }
                 setAttributeResID(i, res);
             } else {
                 SourcePos(mFilename, getStartLineNumber()).error(
@@ -1028,7 +1061,7 @@
         }
     }
 
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 sp<XMLNode> XMLNode::clone() const {
@@ -1070,18 +1103,7 @@
     // Next collect all remainibng strings.
     collect_strings(&strings, &resids, stripComments, stripRawValues);
 
-#if 0  // No longer compiles
-    NOISY(printf("Found strings:\n");
-        const size_t N = strings.size();
-        for (size_t i=0; i<N; i++) {
-            printf("%s\n", String8(strings.entryAt(i).string).string());
-        }
-    );
-#endif    
-
     sp<AaptFile> stringPool = strings.createStringBlock();
-    NOISY(aout << "String pool:"
-          << HexDump(stringPool->getData(), stringPool->getSize()) << endl);
 
     ResXMLTree_header header;
     memset(&header, 0, sizeof(header));
@@ -1112,17 +1134,13 @@
 
     void* data = dest->editData();
     ResXMLTree_header* hd = (ResXMLTree_header*)(((uint8_t*)data)+basePos);
-    size_t size = dest->getSize()-basePos;
     hd->header.size = htodl(dest->getSize()-basePos);
 
-    NOISY(aout << "XML resource:"
-          << HexDump(dest->getData(), dest->getSize()) << endl);
-
-    #if PRINT_STRING_METRICS
-    fprintf(stderr, "**** total xml size: %d / %d%% strings (in %s)\n",
-        dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
-        dest->getPath().string());
-    #endif
+    if (kPrintStringMetrics) {
+        fprintf(stderr, "**** total xml size: %zu / %zu%% strings (in %s)\n",
+                dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
+                dest->getPath().string());
+    }
         
     return NO_ERROR;
 }
@@ -1195,7 +1213,9 @@
 void XMLCALL
 XMLNode::startNamespace(void *userData, const char *prefix, const char *uri)
 {
-    NOISY_PARSE(printf("Start Namespace: %s %s\n", prefix, uri));
+    if (kIsDebugParse) {
+        printf("Start Namespace: %s %s\n", prefix, uri);
+    }
     ParseState* st = (ParseState*)userData;
     sp<XMLNode> node = XMLNode::newNamespace(st->filename, 
             String16(prefix != NULL ? prefix : ""), String16(uri));
@@ -1211,7 +1231,9 @@
 void XMLCALL
 XMLNode::startElement(void *userData, const char *name, const char **atts)
 {
-    NOISY_PARSE(printf("Start Element: %s\n", name));
+    if (kIsDebugParse) {
+        printf("Start Element: %s\n", name);
+    }
     ParseState* st = (ParseState*)userData;
     String16 ns16, name16;
     splitName(name, &ns16, &name16);
@@ -1237,7 +1259,9 @@
 void XMLCALL
 XMLNode::characterData(void *userData, const XML_Char *s, int len)
 {
-    NOISY_PARSE(printf("CDATA: \"%s\"\n", String8(s, len).string()));
+    if (kIsDebugParse) {
+        printf("CDATA: \"%s\"\n", String8(s, len).string());
+    }
     ParseState* st = (ParseState*)userData;
     sp<XMLNode> node = NULL;
     if (st->stack.size() == 0) {
@@ -1264,7 +1288,9 @@
 void XMLCALL
 XMLNode::endElement(void *userData, const char *name)
 {
-    NOISY_PARSE(printf("End Element: %s\n", name));
+    if (kIsDebugParse) {
+        printf("End Element: %s\n", name);
+    }
     ParseState* st = (ParseState*)userData;
     sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
     node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
@@ -1284,7 +1310,9 @@
 XMLNode::endNamespace(void *userData, const char *prefix)
 {
     const char* nonNullPrefix = prefix != NULL ? prefix : "";
-    NOISY_PARSE(printf("End Namespace: %s\n", prefix));
+    if (kIsDebugParse) {
+        printf("End Namespace: %s\n", prefix);
+    }
     ParseState* st = (ParseState*)userData;
     sp<XMLNode> node = st->stack.itemAt(st->stack.size()-1);
     node->setEndLineNumber(XML_GetCurrentLineNumber(st->parser));
@@ -1296,7 +1324,9 @@
 void XMLCALL
 XMLNode::commentData(void *userData, const char *comment)
 {
-    NOISY_PARSE(printf("Comment: %s\n", comment));
+    if (kIsDebugParse) {
+        printf("Comment: %s\n", comment);
+    }
     ParseState* st = (ParseState*)userData;
     if (st->pendingComment.size() > 0) {
         st->pendingComment.append(String16("\n"));
@@ -1393,8 +1423,10 @@
             }
             if (idx < 0) {
                 idx = outPool->add(attr.name);
-                NOISY(printf("Adding attr %s (resid 0x%08x) to pool: idx=%d\n",
-                        String8(attr.name).string(), id, idx));
+                if (kIsDebug) {
+                    printf("Adding attr %s (resid 0x%08x) to pool: idx=%zd\n",
+                            String8(attr.name).string(), id, SSIZE(idx));
+                }
                 if (id != 0) {
                     while ((ssize_t)outResIds->size() <= idx) {
                         outResIds->add(0);
@@ -1403,8 +1435,9 @@
                 }
             }
             attr.namePoolIdx = idx;
-            NOISY(printf("String %s offset=0x%08x\n",
-                         String8(attr.name).string(), idx));
+            if (kIsDebug) {
+                printf("String %s offset=0x%08zd\n", String8(attr.name).string(), SSIZE(idx));
+            }
         }
     }
 
diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp
index b575988..54a8e9c 100644
--- a/tools/aapt/ZipEntry.cpp
+++ b/tools/aapt/ZipEntry.cpp
@@ -141,33 +141,15 @@
  *
  * Initializes the CDE and the LFH.
  */
-status_t ZipEntry::initFromExternal(const ZipFile* pZipFile,
+status_t ZipEntry::initFromExternal(const ZipFile* /* pZipFile */,
     const ZipEntry* pEntry)
 {
-    /*
-     * Copy everything in the CDE over, then fix up the hairy bits.
-     */
-    memcpy(&mCDE, &pEntry->mCDE, sizeof(mCDE));
-
-    if (mCDE.mFileNameLength > 0) {
-        mCDE.mFileName = new unsigned char[mCDE.mFileNameLength+1];
-        if (mCDE.mFileName == NULL)
-            return NO_MEMORY;
-        strcpy((char*) mCDE.mFileName, (char*)pEntry->mCDE.mFileName);
-    }
-    if (mCDE.mFileCommentLength > 0) {
-        mCDE.mFileComment = new unsigned char[mCDE.mFileCommentLength+1];
-        if (mCDE.mFileComment == NULL)
-            return NO_MEMORY;
-        strcpy((char*) mCDE.mFileComment, (char*)pEntry->mCDE.mFileComment);
-    }
-    if (mCDE.mExtraFieldLength > 0) {
-        /* we null-terminate this, though it may not be a string */
-        mCDE.mExtraField = new unsigned char[mCDE.mExtraFieldLength+1];
-        if (mCDE.mExtraField == NULL)
-            return NO_MEMORY;
-        memcpy(mCDE.mExtraField, pEntry->mCDE.mExtraField,
-            mCDE.mExtraFieldLength+1);
+    mCDE = pEntry->mCDE;
+    // Check whether we got all the memory needed.
+    if ((mCDE.mFileNameLength > 0 && mCDE.mFileName == NULL) ||
+            (mCDE.mFileCommentLength > 0 && mCDE.mFileComment == NULL) ||
+            (mCDE.mExtraFieldLength > 0 && mCDE.mExtraField == NULL)) {
+        return NO_MEMORY;
     }
 
     /* construct the LFH from the CDE */
@@ -356,7 +338,7 @@
  */
 void ZipEntry::setModWhen(time_t when)
 {
-#ifdef HAVE_LOCALTIME_R
+#if !defined(_WIN32)
     struct tm tmResult;
 #endif
     time_t even;
@@ -368,7 +350,7 @@
     even = (time_t)(((unsigned long)(when) + 1) & (~1));
 
     /* expand */
-#ifdef HAVE_LOCALTIME_R
+#if !defined(_WIN32)
     ptm = localtime_r(&even, &tmResult);
 #else
     ptm = localtime(&even);
@@ -694,3 +676,60 @@
         ALOGD("  comment: '%s'\n", mFileComment);
 }
 
+/*
+ * Copy-assignment operator for CentralDirEntry.
+ */
+ZipEntry::CentralDirEntry& ZipEntry::CentralDirEntry::operator=(const ZipEntry::CentralDirEntry& src) {
+    if (this == &src) {
+        return *this;
+    }
+
+    // Free up old data.
+    delete[] mFileName;
+    delete[] mExtraField;
+    delete[] mFileComment;
+
+    // Copy scalars.
+    mVersionMadeBy = src.mVersionMadeBy;
+    mVersionToExtract = src.mVersionToExtract;
+    mGPBitFlag = src.mGPBitFlag;
+    mCompressionMethod = src.mCompressionMethod;
+    mLastModFileTime = src.mLastModFileTime;
+    mLastModFileDate = src.mLastModFileDate;
+    mCRC32 = src.mCRC32;
+    mCompressedSize = src.mCompressedSize;
+    mUncompressedSize = src.mUncompressedSize;
+    mFileNameLength = src.mFileNameLength;
+    mExtraFieldLength = src.mExtraFieldLength;
+    mFileCommentLength = src.mFileCommentLength;
+    mDiskNumberStart = src.mDiskNumberStart;
+    mInternalAttrs = src.mInternalAttrs;
+    mExternalAttrs = src.mExternalAttrs;
+    mLocalHeaderRelOffset = src.mLocalHeaderRelOffset;
+
+    // Copy strings, if necessary.
+    if (mFileNameLength > 0) {
+        mFileName = new unsigned char[mFileNameLength + 1];
+        if (mFileName != NULL)
+            strcpy((char*)mFileName, (char*)src.mFileName);
+    } else {
+        mFileName = NULL;
+    }
+    if (mFileCommentLength > 0) {
+        mFileComment = new unsigned char[mFileCommentLength + 1];
+        if (mFileComment != NULL)
+            strcpy((char*)mFileComment, (char*)src.mFileComment);
+    } else {
+        mFileComment = NULL;
+    }
+    if (mExtraFieldLength > 0) {
+        /* we null-terminate this, though it may not be a string */
+        mExtraField = new unsigned char[mExtraFieldLength + 1];
+        if (mExtraField != NULL)
+            memcpy(mExtraField, src.mExtraField, mExtraFieldLength + 1);
+    } else {
+        mExtraField = NULL;
+    }
+
+    return *this;
+}
diff --git a/tools/aapt/ZipEntry.h b/tools/aapt/ZipEntry.h
index c2f3227..287a540 100644
--- a/tools/aapt/ZipEntry.h
+++ b/tools/aapt/ZipEntry.h
@@ -298,6 +298,8 @@
         status_t read(FILE* fp);
         status_t write(FILE* fp);
 
+        CentralDirEntry& operator=(const CentralDirEntry& src);
+
         // unsigned long mSignature;
         unsigned short  mVersionMadeBy;
         unsigned short  mVersionToExtract;
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 8057068..36f4e73 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -676,8 +676,6 @@
 status_t ZipFile::copyDataToFp(FILE* dstFp,
     const void* data, size_t size, unsigned long* pCRC32)
 {
-    size_t count;
-
     *pCRC32 = crc32(0L, Z_NULL, 0);
     if (size > 0) {
         *pCRC32 = crc32(*pCRC32, (const unsigned char*)data, size);
diff --git a/tools/aapt/qsort_r_compat.c b/tools/aapt/qsort_r_compat.c
deleted file mode 100644
index 2a8dbe8..0000000
--- a/tools/aapt/qsort_r_compat.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include "qsort_r_compat.h"
-
-/*
- * Note: This code is only used on the host, and is primarily here for
- * Mac OS compatibility. Apparently, glibc and Apple's libc disagree on
- * the parameter order for qsort_r.
- */
-
-#if HAVE_BSD_QSORT_R
-
-/*
- * BSD qsort_r parameter order is as we have defined here.
- */
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    qsort_r(base, nel, width, thunk, compar);
-}
-
-#elif HAVE_GNU_QSORT_R
-
-/*
- * GNU qsort_r parameter order places the thunk parameter last.
- */
-
-struct compar_data {
-    void* thunk;
-    int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b, void* data) {
-    struct compar_data* compar_data = (struct compar_data*)data;
-    return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    struct compar_data compar_data;
-    compar_data.thunk = thunk;
-    compar_data.compar = compar;
-    qsort_r(base, nel, width, compar_wrapper, &compar_data);
-}
-
-#else
-
-/*
- * Emulate qsort_r using thread local storage to access the thunk data.
- */
-
-#include <cutils/threads.h>
-
-static thread_store_t compar_data_key = THREAD_STORE_INITIALIZER;
-
-struct compar_data {
-    void* thunk;
-    int (*compar)(void*, const void* , const void*);
-};
-
-static int compar_wrapper(const void* a, const void* b) {
-    struct compar_data* compar_data = (struct compar_data*)thread_store_get(&compar_data_key);
-    return compar_data->compar(compar_data->thunk, a, b);
-}
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void*)) {
-    struct compar_data compar_data;
-    compar_data.thunk = thunk;
-    compar_data.compar = compar;
-    thread_store_set(&compar_data_key, &compar_data, NULL);
-    qsort(base, nel, width, compar_wrapper);
-}
-
-#endif
diff --git a/tools/aapt/qsort_r_compat.h b/tools/aapt/qsort_r_compat.h
deleted file mode 100644
index e14f999..0000000
--- a/tools/aapt/qsort_r_compat.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Provides a portable version of qsort_r, called qsort_r_compat, which is a
- * reentrant variant of qsort that passes a user data pointer to its comparator.
- * This implementation follows the BSD parameter convention.
- */
-
-#ifndef ___QSORT_R_COMPAT_H
-#define ___QSORT_R_COMPAT_H
-
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void qsort_r_compat(void* base, size_t nel, size_t width, void* thunk,
-        int (*compar)(void*, const void* , const void* ));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // ___QSORT_R_COMPAT_H
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index e795d818..ef3860c 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -76,3 +76,9 @@
     EXPECT_TRUE(TestParse("sw600dp-v8", &config));
     EXPECT_EQ(String8("sw600dp-v13"), config.toString());
 }
+
+TEST(AaptConfigTest, TestParsingOfCarAttribute) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("car", &config));
+    EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
+}
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 45dd23b..14c9f95 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -228,7 +228,8 @@
         }
 #endif
 
-#ifdef OS_CASE_SENSITIVE
+        // aidl assumes case-insensitivity on Mac Os and Windows.
+#if defined(__linux__)
         valid = (expected == p);
 #else
         valid = !strcasecmp(expected.c_str(), p);
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 393d2ec..5c6d870 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -48,8 +48,9 @@
 
 
 class Field():
-    def __init__(self, clazz, raw, blame):
+    def __init__(self, clazz, line, raw, blame):
         self.clazz = clazz
+        self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
 
@@ -73,8 +74,9 @@
 
 
 class Method():
-    def __init__(self, clazz, raw, blame):
+    def __init__(self, clazz, line, raw, blame):
         self.clazz = clazz
+        self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
 
@@ -110,8 +112,9 @@
 
 
 class Class():
-    def __init__(self, pkg, raw, blame):
+    def __init__(self, pkg, line, raw, blame):
         self.pkg = pkg
+        self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
         self.ctors = []
@@ -129,10 +132,14 @@
 
         if "extends" in raw:
             self.extends = raw[raw.index("extends")+1]
+            self.extends_path = self.extends.split(".")
         else:
             self.extends = None
+            self.extends_path = []
 
         self.fullname = self.pkg.name + "." + self.fullname
+        self.fullname_path = self.fullname.split(".")
+
         self.name = self.fullname[self.fullname.rindex(".")+1:]
 
     def __repr__(self):
@@ -140,75 +147,110 @@
 
 
 class Package():
-    def __init__(self, raw, blame):
+    def __init__(self, line, raw, blame):
+        self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
 
         raw = raw.split()
         self.name = raw[raw.index("package")+1]
+        self.name_path = self.name.split(".")
 
     def __repr__(self):
         return self.raw
 
 
-def parse_api(fn):
+def _parse_stream(f, clazz_cb=None):
+    line = 0
     api = {}
     pkg = None
     clazz = None
     blame = None
 
     re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
+    for raw in f:
+        line += 1
+        raw = raw.rstrip()
+        match = re_blame.match(raw)
+        if match is not None:
+            blame = match.groups()[0:2]
+            raw = match.groups()[2]
+        else:
+            blame = None
 
-    with open(fn) as f:
-        for raw in f.readlines():
-            raw = raw.rstrip()
-            match = re_blame.match(raw)
-            if match is not None:
-                blame = match.groups()[0:2]
-                raw = match.groups()[2]
-            else:
-                blame = None
-
-            if raw.startswith("package"):
-                pkg = Package(raw, blame)
-            elif raw.startswith("  ") and raw.endswith("{"):
-                clazz = Class(pkg, raw, blame)
+        if raw.startswith("package"):
+            pkg = Package(line, raw, blame)
+        elif raw.startswith("  ") and raw.endswith("{"):
+            # When provided with class callback, we treat as incremental
+            # parse and don't build up entire API
+            if clazz and clazz_cb:
+                clazz_cb(clazz)
+            clazz = Class(pkg, line, raw, blame)
+            if not clazz_cb:
                 api[clazz.fullname] = clazz
-            elif raw.startswith("    ctor"):
-                clazz.ctors.append(Method(clazz, raw, blame))
-            elif raw.startswith("    method"):
-                clazz.methods.append(Method(clazz, raw, blame))
-            elif raw.startswith("    field"):
-                clazz.fields.append(Field(clazz, raw, blame))
+        elif raw.startswith("    ctor"):
+            clazz.ctors.append(Method(clazz, line, raw, blame))
+        elif raw.startswith("    method"):
+            clazz.methods.append(Method(clazz, line, raw, blame))
+        elif raw.startswith("    field"):
+            clazz.fields.append(Field(clazz, line, raw, blame))
+
+    # Handle last trailing class
+    if clazz and clazz_cb:
+        clazz_cb(clazz)
 
     return api
 
 
+class Failure():
+    def __init__(self, sig, clazz, detail, error, rule, msg):
+        self.sig = sig
+        self.error = error
+        self.rule = rule
+        self.msg = msg
+
+        if error:
+            self.head = "Error %s" % (rule) if rule else "Error"
+            dump = "%s%s:%s %s" % (format(fg=RED, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+        else:
+            self.head = "Warning %s" % (rule) if rule else "Warning"
+            dump = "%s%s:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+
+        self.line = clazz.line
+        blame = clazz.blame
+        if detail is not None:
+            dump += "\n    in " + repr(detail)
+            self.line = detail.line
+            blame = detail.blame
+        dump += "\n    in " + repr(clazz)
+        dump += "\n    in " + repr(clazz.pkg)
+        dump += "\n    at line " + repr(self.line)
+        if blame is not None:
+            dump += "\n    last modified by %s in %s" % (blame[1], blame[0])
+
+        self.dump = dump
+
+    def __repr__(self):
+        return self.dump
+
+
 failures = {}
 
-def _fail(clazz, detail, msg):
+def _fail(clazz, detail, error, rule, msg):
     """Records an API failure to be processed later."""
     global failures
 
     sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
     sig = sig.replace(" deprecated ", " ")
 
-    res = msg
-    blame = clazz.blame
-    if detail is not None:
-        res += "\n    in " + repr(detail)
-        blame = detail.blame
-    res += "\n    in " + repr(clazz)
-    res += "\n    in " + repr(clazz.pkg)
-    if blame is not None:
-        res += "\n    last modified by %s in %s" % (blame[1], blame[0])
-    failures[sig] = res
+    failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
 
-def warn(clazz, detail, msg):
-    _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg))
 
-def error(clazz, detail, msg):
-    _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg))
+def warn(clazz, detail, rule, msg):
+    _fail(clazz, detail, False, rule, msg)
+
+def error(clazz, detail, rule, msg):
+    _fail(clazz, detail, True, rule, msg)
 
 
 def verify_constants(clazz):
@@ -218,13 +260,13 @@
     for f in clazz.fields:
         if "static" in f.split and "final" in f.split:
             if re.match("[A-Z0-9_]+", f.name) is None:
-                error(clazz, f, "Constant field names should be FOO_NAME")
+                error(clazz, f, "C2", "Constant field names must be FOO_NAME")
 
 
 def verify_enums(clazz):
     """Enums are bad, mmkay?"""
     if "extends java.lang.Enum" in clazz.raw:
-        error(clazz, None, "Enums are not allowed")
+        error(clazz, None, "F5", "Enums are not allowed")
 
 
 def verify_class_names(clazz):
@@ -234,9 +276,9 @@
     if re.match("android\.R\.[a-z]+", clazz.fullname): return
 
     if re.search("[A-Z]{2,}", clazz.name) is not None:
-        warn(clazz, None, "Class name style should be Mtp not MTP")
+        warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
     if re.match("[^A-Z]", clazz.name):
-        error(clazz, None, "Class must start with uppercase char")
+        error(clazz, None, "S1", "Class must start with uppercase char")
 
 
 def verify_method_names(clazz):
@@ -247,9 +289,9 @@
 
     for m in clazz.methods:
         if re.search("[A-Z]{2,}", m.name) is not None:
-            warn(clazz, m, "Method name style should be getMtu() instead of getMTU()")
+            warn(clazz, m, "S1", "Method names with acronyms should be getMtu() instead of getMTU()")
         if re.match("[^a-z]", m.name):
-            error(clazz, m, "Method name must start with lowercase char")
+            error(clazz, m, "S1", "Method name must start with lowercase char")
 
 
 def verify_callbacks(clazz):
@@ -259,17 +301,17 @@
     if clazz.fullname == "android.speech.tts.SynthesisCallback": return
 
     if clazz.name.endswith("Callbacks"):
-        error(clazz, None, "Class name must not be plural")
+        error(clazz, None, "L1", "Callback class names should be singular")
     if clazz.name.endswith("Observer"):
-        warn(clazz, None, "Class should be named FooCallback")
+        warn(clazz, None, "L1", "Class should be named FooCallback")
 
     if clazz.name.endswith("Callback"):
         if "interface" in clazz.split:
-            error(clazz, None, "Callback must be abstract class to enable extension in future API levels")
+            error(clazz, None, "CL3", "Callbacks must be abstract class to enable extension in future API levels")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
-                error(clazz, m, "Callback method names must be onFoo() style")
+                error(clazz, m, "L1", "Callback method names must be onFoo() style")
 
 
 def verify_listeners(clazz):
@@ -281,16 +323,16 @@
 
     if clazz.name.endswith("Listener"):
         if " abstract class " in clazz.raw:
-            error(clazz, None, "Listener should be an interface, otherwise renamed Callback")
+            error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
-                error(clazz, m, "Listener method names must be onFoo() style")
+                error(clazz, m, "L1", "Listener method names must be onFoo() style")
 
         if len(clazz.methods) == 1 and clazz.name.startswith("On"):
             m = clazz.methods[0]
             if (m.name + "Listener").lower() != clazz.name.lower():
-                error(clazz, m, "Single listener method name should match class name")
+                error(clazz, m, "L1", "Single listener method name must match class name")
 
 
 def verify_actions(clazz):
@@ -308,7 +350,7 @@
         if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
             if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower():
                 if not f.name.startswith("ACTION_"):
-                    error(clazz, f, "Intent action constant name must be ACTION_FOO")
+                    error(clazz, f, "C3", "Intent action constant name must be ACTION_FOO")
                 else:
                     if clazz.fullname == "android.content.Intent":
                         prefix = "android.intent.action"
@@ -320,7 +362,7 @@
                         prefix = clazz.pkg.name + ".action"
                     expected = prefix + "." + f.name[7:]
                     if f.value != expected:
-                        error(clazz, f, "Inconsistent action value; expected %s" % (expected))
+                        error(clazz, f, "C4", "Inconsistent action value; expected %s" % (expected))
 
 
 def verify_extras(clazz):
@@ -340,7 +382,7 @@
         if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
             if "_EXTRA" in f.name or "EXTRA_" in f.name or ".extra" in f.value.lower():
                 if not f.name.startswith("EXTRA_"):
-                    error(clazz, f, "Intent extra must be EXTRA_FOO")
+                    error(clazz, f, "C3", "Intent extra must be EXTRA_FOO")
                 else:
                     if clazz.pkg.name == "android.content" and clazz.name == "Intent":
                         prefix = "android.intent.extra"
@@ -350,7 +392,7 @@
                         prefix = clazz.pkg.name + ".extra"
                     expected = prefix + "." + f.name[6:]
                     if f.value != expected:
-                        error(clazz, f, "Inconsistent extra value; expected %s" % (expected))
+                        error(clazz, f, "C4", "Inconsistent extra value; expected %s" % (expected))
 
 
 def verify_equals(clazz):
@@ -359,7 +401,7 @@
     eq = "equals" in methods
     hc = "hashCode" in methods
     if eq != hc:
-        error(clazz, None, "Must override both equals and hashCode; missing one")
+        error(clazz, None, "M8", "Must override both equals and hashCode; missing one")
 
 
 def verify_parcelable(clazz):
@@ -370,17 +412,17 @@
         describe = [ i for i in clazz.methods if i.name == "describeContents" ]
 
         if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
-            error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
+            error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
 
 
 def verify_protected(clazz):
-    """Verify that no protected methods are allowed."""
+    """Verify that no protected methods or fields are allowed."""
     for m in clazz.methods:
         if "protected" in m.split:
-            error(clazz, m, "No protected methods; must be public")
+            error(clazz, m, "M7", "Protected methods not allowed; must be public")
     for f in clazz.fields:
         if "protected" in f.split:
-            error(clazz, f, "No protected fields; must be public")
+            error(clazz, f, "M7", "Protected fields not allowed; must be public")
 
 
 def verify_fields(clazz):
@@ -410,18 +452,18 @@
             elif clazz.fullname.startswith("android.util.Mutable"):
                 pass
             else:
-                error(clazz, f, "Bare fields must be marked final; consider adding accessors")
+                error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
 
         if not "static" in f.split:
             if not re.match("[a-z]([a-zA-Z]+)?", f.name):
-                error(clazz, f, "Non-static fields must be named with myField style")
+                error(clazz, f, "S1", "Non-static fields must be named using myField style")
 
         if re.match("[ms][A-Z]", f.name):
-            error(clazz, f, "Don't expose your internal objects")
+            error(clazz, f, "F1", "Internal objects must not be exposed")
 
         if re.match("[A-Z_]+", f.name):
             if "static" not in f.split or "final" not in f.split:
-                error(clazz, f, "Constants must be marked static final")
+                error(clazz, f, "C2", "Constants must be marked static final")
 
 
 def verify_register(clazz):
@@ -434,34 +476,34 @@
             if m.name.startswith("register"):
                 other = "unregister" + m.name[8:]
                 if other not in methods:
-                    error(clazz, m, "Missing unregister method")
+                    error(clazz, m, "L2", "Missing unregister method")
             if m.name.startswith("unregister"):
                 other = "register" + m.name[10:]
                 if other not in methods:
-                    error(clazz, m, "Missing register method")
+                    error(clazz, m, "L2", "Missing register method")
 
             if m.name.startswith("add") or m.name.startswith("remove"):
-                error(clazz, m, "Callback methods should be named register/unregister")
+                error(clazz, m, "L3", "Callback methods should be named register/unregister")
 
         if "Listener" in m.raw:
             if m.name.startswith("add"):
                 other = "remove" + m.name[3:]
                 if other not in methods:
-                    error(clazz, m, "Missing remove method")
+                    error(clazz, m, "L2", "Missing remove method")
             if m.name.startswith("remove") and not m.name.startswith("removeAll"):
                 other = "add" + m.name[6:]
                 if other not in methods:
-                    error(clazz, m, "Missing add method")
+                    error(clazz, m, "L2", "Missing add method")
 
             if m.name.startswith("register") or m.name.startswith("unregister"):
-                error(clazz, m, "Listener methods should be named add/remove")
+                error(clazz, m, "L3", "Listener methods should be named add/remove")
 
 
 def verify_sync(clazz):
     """Verify synchronized methods aren't exposed."""
     for m in clazz.methods:
         if "synchronized" in m.split:
-            error(clazz, m, "Internal lock exposed")
+            error(clazz, m, "M5", "Internal locks must not be exposed")
 
 
 def verify_intent_builder(clazz):
@@ -473,7 +515,7 @@
             if m.name.startswith("create") and m.name.endswith("Intent"):
                 pass
             else:
-                error(clazz, m, "Methods creating an Intent should be named createFooIntent()")
+                error(clazz, m, "FW1", "Methods creating an Intent must be named createFooIntent()")
 
 
 def verify_helper_classes(clazz):
@@ -483,57 +525,45 @@
     if "extends android.app.Service" in clazz.raw:
         test_methods = True
         if not clazz.name.endswith("Service"):
-            error(clazz, None, "Inconsistent class name; should be FooService")
+            error(clazz, None, "CL4", "Inconsistent class name; should be FooService")
 
         found = False
         for f in clazz.fields:
             if f.name == "SERVICE_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "Inconsistent interface constant; expected %s" % (clazz.fullname))
-
-        if not found:
-            warn(clazz, None, "Missing SERVICE_INTERFACE constant")
-
-        if "abstract" in clazz.split and not clazz.fullname.startswith("android.service."):
-            warn(clazz, None, "Services extended by developers should be under android.service")
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
 
     if "extends android.content.ContentProvider" in clazz.raw:
         test_methods = True
         if not clazz.name.endswith("Provider"):
-            error(clazz, None, "Inconsistent class name; should be FooProvider")
+            error(clazz, None, "CL4", "Inconsistent class name; should be FooProvider")
 
         found = False
         for f in clazz.fields:
             if f.name == "PROVIDER_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "Inconsistent interface name; expected %s" % (clazz.fullname))
-
-        if not found:
-            warn(clazz, None, "Missing PROVIDER_INTERFACE constant")
-
-        if "abstract" in clazz.split and not clazz.fullname.startswith("android.provider."):
-            warn(clazz, None, "Providers extended by developers should be under android.provider")
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
 
     if "extends android.content.BroadcastReceiver" in clazz.raw:
         test_methods = True
         if not clazz.name.endswith("Receiver"):
-            error(clazz, None, "Inconsistent class name; should be FooReceiver")
+            error(clazz, None, "CL4", "Inconsistent class name; should be FooReceiver")
 
     if "extends android.app.Activity" in clazz.raw:
         test_methods = True
         if not clazz.name.endswith("Activity"):
-            error(clazz, None, "Inconsistent class name; should be FooActivity")
+            error(clazz, None, "CL4", "Inconsistent class name; should be FooActivity")
 
     if test_methods:
         for m in clazz.methods:
             if "final" in m.split: continue
             if not re.match("on[A-Z]", m.name):
                 if "abstract" in m.split:
-                    error(clazz, m, "Methods implemented by developers must be named onFoo()")
+                    warn(clazz, m, None, "Methods implemented by developers should be named onFoo()")
                 else:
-                    warn(clazz, m, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
+                    warn(clazz, m, None, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
 
 
 def verify_builder(clazz):
@@ -543,7 +573,7 @@
     if not clazz.name.endswith("Builder"): return
 
     if clazz.name != "Builder":
-        warn(clazz, None, "Builder should be defined as inner class")
+        warn(clazz, None, None, "Builder should be defined as inner class")
 
     has_build = False
     for m in clazz.methods:
@@ -555,26 +585,26 @@
         if m.name.startswith("clear"): continue
 
         if m.name.startswith("with"):
-            error(clazz, m, "Builder methods names must follow setFoo() style")
+            warn(clazz, m, None, "Builder methods names should use setFoo() style")
 
         if m.name.startswith("set"):
             if not m.typ.endswith(clazz.fullname):
-                warn(clazz, m, "Methods should return the builder")
+                warn(clazz, m, "M4", "Methods must return the builder object")
 
     if not has_build:
-        warn(clazz, None, "Missing build() method")
+        warn(clazz, None, None, "Missing build() method")
 
 
 def verify_aidl(clazz):
     """Catch people exposing raw AIDL."""
     if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw:
-        error(clazz, None, "Exposing raw AIDL interface")
+        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
 
 
 def verify_internal(clazz):
     """Catch people exposing internal classes."""
     if clazz.pkg.name.startswith("com.android"):
-        error(clazz, None, "Exposing internal class")
+        error(clazz, None, None, "Internal classes must not be exposed")
 
 
 def verify_layering(clazz):
@@ -609,38 +639,56 @@
     for f in clazz.fields:
         ir = rank(f.typ)
         if ir and ir < cr:
-            warn(clazz, f, "Field type violates package layering")
+            warn(clazz, f, "FW6", "Field type violates package layering")
 
     for m in clazz.methods:
         ir = rank(m.typ)
         if ir and ir < cr:
-            warn(clazz, m, "Method return type violates package layering")
+            warn(clazz, m, "FW6", "Method return type violates package layering")
         for arg in m.args:
             ir = rank(arg)
             if ir and ir < cr:
-                warn(clazz, m, "Method argument type violates package layering")
+                warn(clazz, m, "FW6", "Method argument type violates package layering")
 
 
-def verify_boolean(clazz, api):
-    """Catches people returning boolean from getFoo() style methods.
-    Ignores when matching setFoo() is present."""
+def verify_boolean(clazz):
+    """Verifies that boolean accessors are named correctly.
+    For example, hasFoo() and setHasFoo()."""
 
-    methods = [ m.name for m in clazz.methods ]
+    def is_get(m): return len(m.args) == 0 and m.typ == "boolean"
+    def is_set(m): return len(m.args) == 1 and m.args[0] == "boolean"
 
-    builder = clazz.fullname + ".Builder"
-    builder_methods = []
-    if builder in api:
-        builder_methods = [ m.name for m in api[builder].methods ]
+    gets = [ m for m in clazz.methods if is_get(m) ]
+    sets = [ m for m in clazz.methods if is_set(m) ]
+
+    def error_if_exists(methods, trigger, expected, actual):
+        for m in methods:
+            if m.name == actual:
+                error(clazz, m, "M6", "Symmetric method for %s must be named %s" % (trigger, expected))
 
     for m in clazz.methods:
-        if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
-            setter = "set" + m.name[3:]
-            if setter in methods:
-                pass
-            elif builder is not None and setter in builder_methods:
-                pass
-            else:
-                warn(clazz, m, "Methods returning boolean should be named isFoo, hasFoo, areFoo")
+        if is_get(m):
+            if re.match("is[A-Z]", m.name):
+                target = m.name[2:]
+                expected = "setIs" + target
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+            elif re.match("has[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "setHas" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "set" + target)
+            elif re.match("get[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "set" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+
+        if is_set(m):
+            if re.match("set[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "get" + target
+                error_if_exists(sets, m.name, expected, "is" + target)
+                error_if_exists(sets, m.name, expected, "has" + target)
 
 
 def verify_collections(clazz):
@@ -651,10 +699,10 @@
            "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
     for m in clazz.methods:
         if m.typ in bad:
-            error(clazz, m, "Return type is concrete collection; should be interface")
+            error(clazz, m, "CL2", "Return type is concrete collection; must be higher-level interface")
         for arg in m.args:
             if arg in bad:
-                error(clazz, m, "Argument is concrete collection; should be interface")
+                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
 
 
 def verify_flags(clazz):
@@ -669,49 +717,291 @@
 
             scope = f.name[0:f.name.index("FLAG_")]
             if val & known[scope]:
-                warn(clazz, f, "Found overlapping flag constant value")
+                warn(clazz, f, "C1", "Found overlapping flag constant value")
             known[scope] |= val
 
 
-def verify_style(api):
-    """Find all style issues in the given API level."""
-    global failures
+def verify_exception(clazz):
+    """Verifies that methods don't throw generic exceptions."""
+    for m in clazz.methods:
+        if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw:
+            error(clazz, m, "S1", "Methods must not throw generic exceptions")
 
+
+def verify_google(clazz):
+    """Verifies that APIs never reference Google."""
+
+    if re.search("google", clazz.raw, re.IGNORECASE):
+        error(clazz, None, None, "Must never reference Google")
+
+    test = []
+    test.extend(clazz.ctors)
+    test.extend(clazz.fields)
+    test.extend(clazz.methods)
+
+    for t in test:
+        if re.search("google", t.raw, re.IGNORECASE):
+            error(clazz, t, None, "Must never reference Google")
+
+
+def verify_bitset(clazz):
+    """Verifies that we avoid using heavy BitSet."""
+
+    for f in clazz.fields:
+        if f.typ == "java.util.BitSet":
+            error(clazz, f, None, "Field type must not be heavy BitSet")
+
+    for m in clazz.methods:
+        if m.typ == "java.util.BitSet":
+            error(clazz, m, None, "Return type must not be heavy BitSet")
+        for arg in m.args:
+            if arg == "java.util.BitSet":
+                error(clazz, m, None, "Argument type must not be heavy BitSet")
+
+
+def verify_manager(clazz):
+    """Verifies that FooManager is only obtained from Context."""
+
+    if not clazz.name.endswith("Manager"): return
+
+    for c in clazz.ctors:
+        error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
+
+
+def verify_boxed(clazz):
+    """Verifies that methods avoid boxed primitives."""
+
+    boxed = ["java.lang.Number","java.lang.Byte","java.lang.Double","java.lang.Float","java.lang.Integer","java.lang.Long","java.lang.Short"]
+
+    for c in clazz.ctors:
+        for arg in c.args:
+            if arg in boxed:
+                error(clazz, c, "M11", "Must avoid boxed primitives")
+
+    for f in clazz.fields:
+        if f.typ in boxed:
+            error(clazz, f, "M11", "Must avoid boxed primitives")
+
+    for m in clazz.methods:
+        if m.typ in boxed:
+            error(clazz, m, "M11", "Must avoid boxed primitives")
+        for arg in m.args:
+            if arg in boxed:
+                error(clazz, m, "M11", "Must avoid boxed primitives")
+
+
+def verify_static_utils(clazz):
+    """Verifies that helper classes can't be constructed."""
+    if clazz.fullname.startswith("android.opengl"): return
+    if re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+    if len(clazz.fields) > 0: return
+    if len(clazz.methods) == 0: return
+
+    for m in clazz.methods:
+        if "static" not in m.split:
+            return
+
+    # At this point, we have no fields, and all methods are static
+    if len(clazz.ctors) > 0:
+        error(clazz, None, None, "Fully-static utility classes must not have constructor")
+
+
+def verify_overload_args(clazz):
+    """Verifies that method overloads add new arguments at the end."""
+    if clazz.fullname.startswith("android.opengl"): return
+
+    overloads = collections.defaultdict(list)
+    for m in clazz.methods:
+        if "deprecated" in m.split: continue
+        overloads[m.name].append(m)
+
+    for name, methods in overloads.items():
+        if len(methods) <= 1: continue
+
+        # Look for arguments common across all overloads
+        def cluster(args):
+            count = collections.defaultdict(int)
+            res = set()
+            for i in range(len(args)):
+                a = args[i]
+                res.add("%s#%d" % (a, count[a]))
+                count[a] += 1
+            return res
+
+        common_args = cluster(methods[0].args)
+        for m in methods:
+            common_args = common_args & cluster(m.args)
+
+        if len(common_args) == 0: continue
+
+        # Require that all common arguments are present at start of signature
+        locked_sig = None
+        for m in methods:
+            sig = m.args[0:len(common_args)]
+            if not common_args.issubset(cluster(sig)):
+                warn(clazz, m, "M2", "Expected common arguments [%s] at beginning of overloaded method" % (", ".join(common_args)))
+            elif not locked_sig:
+                locked_sig = sig
+            elif locked_sig != sig:
+                error(clazz, m, "M2", "Expected consistent argument ordering between overloads: %s..." % (", ".join(locked_sig)))
+
+
+def verify_callback_handlers(clazz):
+    """Verifies that methods adding listener/callback have overload
+    for specifying delivery thread."""
+
+    # Ignore UI packages which assume main thread
+    skip = [
+        "animation",
+        "view",
+        "graphics",
+        "transition",
+        "widget",
+        "webkit",
+    ]
+    for s in skip:
+        if s in clazz.pkg.name_path: return
+        if s in clazz.extends_path: return
+
+    # Ignore UI classes which assume main thread
+    if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+        for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+            if s in clazz.fullname: return
+    if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+        for s in ["Loader"]:
+            if s in clazz.fullname: return
+
+    found = {}
+    by_name = collections.defaultdict(list)
+    for m in clazz.methods:
+        if m.name.startswith("unregister"): continue
+        if m.name.startswith("remove"): continue
+        if re.match("on[A-Z]+", m.name): continue
+
+        by_name[m.name].append(m)
+
+        for a in m.args:
+            if a.endswith("Listener") or a.endswith("Callback") or a.endswith("Callbacks"):
+                found[m.name] = m
+
+    for f in found.values():
+        takes_handler = False
+        for m in by_name[f.name]:
+            if "android.os.Handler" in m.args:
+                takes_handler = True
+        if not takes_handler:
+            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
+
+
+def verify_context_first(clazz):
+    """Verifies that methods accepting a Context keep it the first argument."""
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if len(m.args) > 1 and m.args[0] != "android.content.Context":
+            if "android.content.Context" in m.args[1:]:
+                error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
+
+
+def verify_listener_last(clazz):
+    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if "Listener" in m.name or "Callback" in m.name: continue
+        found = False
+        for a in m.args:
+            if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
+                found = True
+            elif found and a != "android.os.Handler":
+                warn(clazz, m, "M3", "Listeners should always be at end of argument list")
+
+
+def verify_resource_names(clazz):
+    """Verifies that resource names have consistent case."""
+    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+    # Resources defined by files are foo_bar_baz
+    if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
+        for f in clazz.fields:
+            if re.match("[a-z1-9_]+$", f.name): continue
+            error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
+
+    # Resources defined inside files are fooBarBaz
+    if clazz.name in ["array","attr","id","bool","fraction","integer"]:
+        for f in clazz.fields:
+            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("layout_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("state_[a-z_]*$", f.name): continue
+
+            if re.match("[a-z][a-zA-Z1-9]*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be fooBarBaz style")
+
+    # Styles are FooBar_Baz
+    if clazz.name in ["style"]:
+        for f in clazz.fields:
+            if re.match("[A-Z][A-Za-z1-9]+(_[A-Z][A-Za-z1-9]+?)*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
+
+
+def examine_clazz(clazz):
+    """Find all style issues in the given class."""
+    if clazz.pkg.name.startswith("java"): return
+    if clazz.pkg.name.startswith("junit"): return
+    if clazz.pkg.name.startswith("org.apache"): return
+    if clazz.pkg.name.startswith("org.xml"): return
+    if clazz.pkg.name.startswith("org.json"): return
+    if clazz.pkg.name.startswith("org.w3c"): return
+
+    verify_constants(clazz)
+    verify_enums(clazz)
+    verify_class_names(clazz)
+    verify_method_names(clazz)
+    verify_callbacks(clazz)
+    verify_listeners(clazz)
+    verify_actions(clazz)
+    verify_extras(clazz)
+    verify_equals(clazz)
+    verify_parcelable(clazz)
+    verify_protected(clazz)
+    verify_fields(clazz)
+    verify_register(clazz)
+    verify_sync(clazz)
+    verify_intent_builder(clazz)
+    verify_helper_classes(clazz)
+    verify_builder(clazz)
+    verify_aidl(clazz)
+    verify_internal(clazz)
+    verify_layering(clazz)
+    verify_boolean(clazz)
+    verify_collections(clazz)
+    verify_flags(clazz)
+    verify_exception(clazz)
+    verify_google(clazz)
+    verify_bitset(clazz)
+    verify_manager(clazz)
+    verify_boxed(clazz)
+    verify_static_utils(clazz)
+    verify_overload_args(clazz)
+    verify_callback_handlers(clazz)
+    verify_context_first(clazz)
+    verify_listener_last(clazz)
+    verify_resource_names(clazz)
+
+
+def examine_stream(stream):
+    """Find all style issues in the given API stream."""
+    global failures
+    failures = {}
+    _parse_stream(stream, examine_clazz)
+    return failures
+
+
+def examine_api(api):
+    """Find all style issues in the given parsed API."""
+    global failures
     failures = {}
     for key in sorted(api.keys()):
-        clazz = api[key]
-
-        if clazz.pkg.name.startswith("java"): continue
-        if clazz.pkg.name.startswith("junit"): continue
-        if clazz.pkg.name.startswith("org.apache"): continue
-        if clazz.pkg.name.startswith("org.xml"): continue
-        if clazz.pkg.name.startswith("org.json"): continue
-        if clazz.pkg.name.startswith("org.w3c"): continue
-
-        verify_constants(clazz)
-        verify_enums(clazz)
-        verify_class_names(clazz)
-        verify_method_names(clazz)
-        verify_callbacks(clazz)
-        verify_listeners(clazz)
-        verify_actions(clazz)
-        verify_extras(clazz)
-        verify_equals(clazz)
-        verify_parcelable(clazz)
-        verify_protected(clazz)
-        verify_fields(clazz)
-        verify_register(clazz)
-        verify_sync(clazz)
-        verify_intent_builder(clazz)
-        verify_helper_classes(clazz)
-        verify_builder(clazz)
-        verify_aidl(clazz)
-        verify_internal(clazz)
-        verify_layering(clazz)
-        verify_boolean(clazz, api)
-        verify_collections(clazz)
-        verify_flags(clazz)
-
+        examine_clazz(api[key])
     return failures
 
 
@@ -749,49 +1039,52 @@
         prev_clazz = prev[key]
 
         if not class_exists(cur, prev_clazz):
-            error(prev_clazz, None, "Class removed or incompatible change")
+            error(prev_clazz, None, None, "Class removed or incompatible change")
             continue
 
         cur_clazz = cur[key]
 
         for test in prev_clazz.ctors:
             if not ctor_exists(cur, cur_clazz, test):
-                error(prev_clazz, prev_ctor, "Constructor removed or incompatible change")
+                error(prev_clazz, prev_ctor, None, "Constructor removed or incompatible change")
 
         methods = all_methods(prev, prev_clazz)
         for test in methods:
             if not method_exists(cur, cur_clazz, test):
-                error(prev_clazz, test, "Method removed or incompatible change")
+                error(prev_clazz, test, None, "Method removed or incompatible change")
 
         for test in prev_clazz.fields:
             if not field_exists(cur, cur_clazz, test):
-                error(prev_clazz, test, "Field removed or incompatible change")
+                error(prev_clazz, test, None, "Field removed or incompatible change")
 
     return failures
 
 
-cur = parse_api(sys.argv[1])
-cur_fail = verify_style(cur)
+if __name__ == "__main__":
+    with open(sys.argv[1]) as f:
+        cur_fail = examine_stream(f)
 
-if len(sys.argv) > 2:
-    prev = parse_api(sys.argv[2])
-    prev_fail = verify_style(prev)
+    if len(sys.argv) > 2:
+        with open(sys.argv[2]) as f:
+            prev_fail = examine_stream(f)
 
-    # ignore errors from previous API level
-    for p in prev_fail:
-        if p in cur_fail:
-            del cur_fail[p]
+        # ignore errors from previous API level
+        for p in prev_fail:
+            if p in cur_fail:
+                del cur_fail[p]
 
-    # look for compatibility issues
-    compat_fail = verify_compat(cur, prev)
+        """
+        # NOTE: disabled because of memory pressure
+        # look for compatibility issues
+        compat_fail = verify_compat(cur, prev)
 
-    print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-    for f in sorted(compat_fail):
-        print compat_fail[f]
+        print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+        for f in sorted(compat_fail):
+            print compat_fail[f]
+            print
+        """
+
+    print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+    for f in sorted(cur_fail):
+        print cur_fail[f]
         print
-
-
-print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-for f in sorted(cur_fail):
-    print cur_fail[f]
-    print
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 8d24d38..970b9d0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -76,13 +76,6 @@
     // ---- Public Helper methods ----
 
     /**
-     * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
-     */
-    public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
-        return sManager.getDelegate(bitmap.mNativeBitmap);
-    }
-
-    /**
      * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
      */
     public static Bitmap_Delegate getDelegate(long native_bitmap) {
@@ -187,19 +180,6 @@
         return createBitmap(delegate, createFlags, density.getDpiValue());
     }
 
-    /**
-     * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
-     */
-    public static BufferedImage getImage(Bitmap bitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
-        if (delegate == null) {
-            return null;
-        }
-
-        return delegate.mImage;
-    }
-
     public static int getBufferedImageType(int nativeBitmapConfig) {
         switch (Config.nativeToConfig(nativeBitmapConfig)) {
             case ALPHA_8:
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index f42f48f..1105c7b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -661,9 +661,8 @@
         float[] src = new float[] { radius, 0.f, 0.f, radius };
         d.mapVectors(src, 0, src, 0, 2);
 
-        float l1 = getPointLength(src, 0);
-        float l2 = getPointLength(src, 2);
-
+        float l1 = (float) Math.hypot(src[0], src[1]);
+        float l2 = (float) Math.hypot(src[2], src[3]);
         return (float) Math.sqrt(l1 * l2);
     }
 
@@ -918,10 +917,6 @@
          }
      }
 
-     private static float getPointLength(float[] src, int index) {
-         return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
-     }
-
     /**
      * multiply two matrices and store them in a 3rd.
      * <p/>This in effect does dest = a*b
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7b07404..8ffd1d8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -251,7 +251,7 @@
     @LayoutlibDelegate
     /*package*/ static int getFlags(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -264,7 +264,7 @@
     @LayoutlibDelegate
     /*package*/ static void setFlags(Paint thisPaint, int flags) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -280,7 +280,7 @@
     @LayoutlibDelegate
     /*package*/ static int getHinting(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return Paint.HINTING_ON;
         }
@@ -291,7 +291,7 @@
     @LayoutlibDelegate
     /*package*/ static void setHinting(Paint thisPaint, int mode) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -337,7 +337,7 @@
     @LayoutlibDelegate
     /*package*/ static int getColor(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -348,7 +348,7 @@
     @LayoutlibDelegate
     /*package*/ static void setColor(Paint thisPaint, int color) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -359,7 +359,7 @@
     @LayoutlibDelegate
     /*package*/ static int getAlpha(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -370,7 +370,7 @@
     @LayoutlibDelegate
     /*package*/ static void setAlpha(Paint thisPaint, int a) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -381,7 +381,7 @@
     @LayoutlibDelegate
     /*package*/ static float getStrokeWidth(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 1.f;
         }
@@ -392,7 +392,7 @@
     @LayoutlibDelegate
     /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -403,7 +403,7 @@
     @LayoutlibDelegate
     /*package*/ static float getStrokeMiter(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 1.f;
         }
@@ -414,7 +414,7 @@
     @LayoutlibDelegate
     /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -441,14 +441,14 @@
     @LayoutlibDelegate
     /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
     }
 
     @LayoutlibDelegate
     /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -459,7 +459,7 @@
     @LayoutlibDelegate
     /*package*/ static float getTextSize(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 1.f;
         }
@@ -470,7 +470,7 @@
     @LayoutlibDelegate
     /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -482,7 +482,7 @@
     @LayoutlibDelegate
     /*package*/ static float getTextScaleX(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 1.f;
         }
@@ -493,7 +493,7 @@
     @LayoutlibDelegate
     /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -505,7 +505,7 @@
     @LayoutlibDelegate
     /*package*/ static float getTextSkewX(Paint thisPaint) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 1.f;
         }
@@ -516,7 +516,7 @@
     @LayoutlibDelegate
     /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
@@ -528,7 +528,7 @@
     @LayoutlibDelegate
     /*package*/ static float ascent(Paint thisPaint) {
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -545,7 +545,7 @@
     @LayoutlibDelegate
     /*package*/ static float descent(Paint thisPaint) {
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -562,7 +562,7 @@
     @LayoutlibDelegate
     /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -573,7 +573,7 @@
     @LayoutlibDelegate
     /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -599,7 +599,7 @@
     /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
             int count, int bidiFlags) {
         // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return 0;
         }
@@ -1232,7 +1232,7 @@
 
     private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
         // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.getNativeInstance());
         if (delegate == null) {
             return;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 80179ee..eb29835 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -184,7 +184,7 @@
 
                         float _x = pt2[0];
                         float _y = pt2[1];
-                        float distance = (float) Math.sqrt(_x * _x + _y * _y);
+                        float distance = (float) Math.hypot(_x, _y);
 
                         data[index++] = getGradientColor(distance / mRadius);
                     }
diff --git a/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
new file mode 100644
index 0000000..24e4b54
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
@@ -0,0 +1,193 @@
+/*
+ * 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.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+// Based on the native implementation of GreedyLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class GreedyLineBreaker extends LineBreaker {
+
+    public GreedyLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+            @NonNull TabStops tabStops) {
+        super(primitives, lineWidth, tabStops);
+    }
+
+    @Override
+    public void computeBreaks(LineBreaks lineBreaks) {
+        BreakInfo breakInfo = new BreakInfo();
+        int lineNum = 0;
+        float width = 0, printedWidth = 0;
+        boolean breakFound = false, goodBreakFound = false;
+        int breakIndex = 0, goodBreakIndex = 0;
+        float breakWidth = 0, goodBreakWidth = 0;
+        int firstTabIndex = Integer.MAX_VALUE;
+
+        float maxWidth = mLineWidth.getLineWidth(lineNum);
+
+        int numPrimitives = mPrimitives.size();
+        // greedily fit as many characters as possible on each line
+        // loop over all primitives, and choose the best break point
+        // (if possible, a break point without splitting a word)
+        // after going over the maximum length
+        for (int i = 0; i < numPrimitives; i++) {
+            Primitive p = mPrimitives.get(i);
+
+            // update the current line width
+            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+                width += p.width;
+                if (p.type == PrimitiveType.BOX) {
+                    printedWidth = width;
+                }
+            } else if (p.type == PrimitiveType.VARIABLE) {
+                width = mTabStops.width(width);
+                // keep track of first tab character in the region we are examining
+                // so we can determine whether or not a line contains a tab
+                firstTabIndex = Math.min(firstTabIndex, i);
+            }
+
+            // find the best break point for the characters examined so far
+            if (printedWidth > maxWidth) {
+                //noinspection StatementWithEmptyBody
+                if (breakFound || goodBreakFound) {
+                    if (goodBreakFound) {
+                        // a true line break opportunity existed in the characters examined so far,
+                        // so there is no need to split a word
+                        i = goodBreakIndex; // no +1 because of i++
+                        lineNum++;
+                        maxWidth = mLineWidth.getLineWidth(lineNum);
+                        breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+                        breakInfo.mWidthsList.add(goodBreakWidth);
+                        breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+                        firstTabIndex = Integer.MAX_VALUE;
+                    } else {
+                        // must split a word because there is no other option
+                        i = breakIndex; // no +1 because of i++
+                        lineNum++;
+                        maxWidth = mLineWidth.getLineWidth(lineNum);
+                        breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+                        breakInfo.mWidthsList.add(breakWidth);
+                        breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+                        firstTabIndex = Integer.MAX_VALUE;
+                    }
+                    printedWidth = width = 0;
+                    goodBreakFound = breakFound = false;
+                    goodBreakWidth = breakWidth = 0;
+                    continue;
+                } else {
+                    // no choice, keep going... must make progress by putting at least one
+                    // character on a line, even if part of that character is cut off --
+                    // there is no other option
+                }
+            }
+
+            // update possible break points
+            if (p.type == PrimitiveType.PENALTY &&
+                    p.penalty < PENALTY_INFINITY) {
+                // this does not handle penalties with width
+
+                // handle forced line break
+                if (p.penalty == -PENALTY_INFINITY) {
+                    lineNum++;
+                    maxWidth = mLineWidth.getLineWidth(lineNum);
+                    breakInfo.mBreaksList.add(p.location);
+                    breakInfo.mWidthsList.add(printedWidth);
+                    breakInfo.mFlagsList.add(firstTabIndex < i);
+                    firstTabIndex = Integer.MAX_VALUE;
+                    printedWidth = width = 0;
+                    goodBreakFound = breakFound = false;
+                    goodBreakWidth = breakWidth = 0;
+                    continue;
+                }
+                if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+                    breakFound = true;
+                    breakIndex = i;
+                    breakWidth = printedWidth;
+                }
+                if (i > goodBreakIndex && printedWidth <= maxWidth) {
+                    goodBreakFound = true;
+                    goodBreakIndex = i;
+                    goodBreakWidth = printedWidth;
+                }
+            } else if (p.type == PrimitiveType.WORD_BREAK) {
+                // only do this if necessary -- we don't want to break words
+                // when possible, but sometimes it is unavoidable
+                if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
+                    breakFound = true;
+                    breakIndex = i;
+                    breakWidth = printedWidth;
+                }
+            }
+        }
+
+        if (breakFound || goodBreakFound) {
+            // output last break if there are more characters to output
+            if (goodBreakFound) {
+                breakInfo.mBreaksList.add(mPrimitives.get(goodBreakIndex).location);
+                breakInfo.mWidthsList.add(goodBreakWidth);
+                breakInfo.mFlagsList.add(firstTabIndex < goodBreakIndex);
+            } else {
+                breakInfo.mBreaksList.add(mPrimitives.get(breakIndex).location);
+                breakInfo.mWidthsList.add(breakWidth);
+                breakInfo.mFlagsList.add(firstTabIndex < breakIndex);
+            }
+        }
+        breakInfo.copyTo(lineBreaks);
+    }
+
+    private static class BreakInfo {
+        List<Integer> mBreaksList = new ArrayList<Integer>();
+        List<Float> mWidthsList = new ArrayList<Float>();
+        List<Boolean> mFlagsList = new ArrayList<Boolean>();
+
+        public void copyTo(LineBreaks lineBreaks) {
+            if (lineBreaks.breaks.length != mBreaksList.size()) {
+                lineBreaks.breaks = new int[mBreaksList.size()];
+                lineBreaks.widths = new float[mWidthsList.size()];
+                lineBreaks.flags = new boolean[mFlagsList.size()];
+            }
+
+            int i = 0;
+            for (int b : mBreaksList) {
+                lineBreaks.breaks[i] = b;
+                i++;
+            }
+            i = 0;
+            for (float b : mWidthsList) {
+                lineBreaks.widths[i] = b;
+                i++;
+            }
+            i = 0;
+            for (boolean b : mFlagsList) {
+                lineBreaks.flags[i] = b;
+                i++;
+            }
+
+            mBreaksList = null;
+            mWidthsList = null;
+            mFlagsList = null;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineBreaker.java b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
new file mode 100644
index 0000000..8be3635
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineBreaker.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 android.text;
+
+import android.text.StaticLayout.LineBreaks;
+import com.android.annotations.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+// Based on the native implementation of LineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public abstract class LineBreaker {
+
+    protected final @NonNull List<Primitive> mPrimitives;
+    protected final @NonNull LineWidth mLineWidth;
+    protected final @NonNull TabStops mTabStops;
+
+    public LineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+            @NonNull TabStops tabStops) {
+        mPrimitives = Collections.unmodifiableList(primitives);
+        mLineWidth = lineWidth;
+        mTabStops = tabStops;
+    }
+
+    @NonNull
+    public abstract void computeBreaks(@NonNull LineBreaks breakInfo);
+}
diff --git a/tools/layoutlib/bridge/src/android/text/LineWidth.java b/tools/layoutlib/bridge/src/android/text/LineWidth.java
new file mode 100644
index 0000000..2ea886d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/LineWidth.java
@@ -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.text;
+
+// Based on the native implementation of LineWidth in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class LineWidth {
+    private final float mFirstWidth;
+    private final int mFirstWidthLineCount;
+    private float mRestWidth;
+
+    public LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) {
+        mFirstWidth = firstWidth;
+        mFirstWidthLineCount = firstWidthLineCount;
+        mRestWidth = restWidth;
+    }
+
+    public float getLineWidth(int line) {
+        return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
new file mode 100644
index 0000000..d5d7798
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
@@ -0,0 +1,262 @@
+/*
+ * 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.text;
+
+import com.android.annotations.NonNull;
+
+import android.text.Primitive.PrimitiveType;
+import android.text.StaticLayout.LineBreaks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import static android.text.Primitive.PrimitiveType.PENALTY_INFINITY;
+
+
+// Based on the native implementation of OptimizingLineBreaker in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+/**
+ * A more complex version of line breaking where we try to prevent the right edge from being too
+ * jagged.
+ */
+public class OptimizingLineBreaker extends LineBreaker {
+
+    public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
+            @NonNull TabStops tabStops) {
+        super(primitives, lineWidth, tabStops);
+    }
+
+    @Override
+    public void computeBreaks(@NonNull LineBreaks breakInfo) {
+        int numBreaks = mPrimitives.size();
+        assert numBreaks > 0;
+        if (numBreaks == 1) {
+            // This can be true only if it's an empty paragraph.
+            Primitive p = mPrimitives.get(0);
+            assert p.type == PrimitiveType.PENALTY;
+            breakInfo.breaks = new int[]{0};
+            breakInfo.widths = new float[]{p.width};
+            breakInfo.flags = new boolean[]{false};
+            return;
+        }
+        Node[] opt = new Node[numBreaks];
+        opt[0] = new Node(-1, 0, 0, 0, false);
+        opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false);
+
+        ArrayList<Integer> active = new ArrayList<Integer>();
+        active.add(0);
+        int lastBreak = 0;
+        for (int i = 0; i < numBreaks; i++) {
+            Primitive p = mPrimitives.get(i);
+            if (p.type == PrimitiveType.PENALTY) {
+                boolean finalBreak = (i + 1 == numBreaks);
+                Node bestBreak = null;
+
+                for (ListIterator<Integer> it = active.listIterator(); it.hasNext();
+                        /* incrementing done in loop */) {
+                    int pos = it.next();
+                    int lines = opt[pos].mPrevCount;
+                    float maxWidth = mLineWidth.getLineWidth(lines);
+                    // we have to compute metrics every time --
+                    // we can't really pre-compute this stuff and just deal with breaks
+                    // because of the way tab characters work, this makes it computationally
+                    // harder, but this way, we can still optimize while treating tab characters
+                    // correctly
+                    LineMetrics lineMetrics = computeMetrics(pos, i);
+                    if (lineMetrics.mPrintedWidth <= maxWidth) {
+                        float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth,
+                                finalBreak, p.penalty) + opt[pos].mDemerits;
+                        if (bestBreak == null || demerits < bestBreak.mDemerits) {
+                            if (bestBreak == null) {
+                                bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits,
+                                        lineMetrics.mPrintedWidth, lineMetrics.mHasTabs);
+                            } else {
+                                bestBreak.mPrev = pos;
+                                bestBreak.mPrevCount = opt[pos].mPrevCount + 1;
+                                bestBreak.mDemerits = demerits;
+                                bestBreak.mWidth = lineMetrics.mPrintedWidth;
+                                bestBreak.mHasTabs = lineMetrics.mHasTabs;
+                            }
+                        }
+                    } else {
+                        it.remove();
+                    }
+                }
+                if (p.penalty == -PENALTY_INFINITY) {
+                    active.clear();
+                }
+                if (bestBreak != null) {
+                    opt[i] = bestBreak;
+                    active.add(i);
+                    lastBreak = i;
+                }
+                if (active.isEmpty()) {
+                    // we can't give up!
+                    LineMetrics lineMetrics = new LineMetrics();
+                    int lines = opt[lastBreak].mPrevCount;
+                    float maxWidth = mLineWidth.getLineWidth(lines);
+                    int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics);
+                    opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/,
+                            lineMetrics.mWidth, lineMetrics.mHasTabs);
+                    active.add(breakIndex);
+                    lastBreak = breakIndex;
+                    i = breakIndex; // incremented by i++
+                }
+            }
+        }
+
+        int idx = numBreaks - 1;
+        int count = opt[idx].mPrevCount;
+        resize(breakInfo, count);
+        while (opt[idx].mPrev != -1) {
+            count--;
+            assert count >=0;
+
+            breakInfo.breaks[count] = mPrimitives.get(idx).location;
+            breakInfo.widths[count] = opt[idx].mWidth;
+            breakInfo.flags [count] = opt[idx].mHasTabs;
+            idx = opt[idx].mPrev;
+        }
+    }
+
+    private static void resize(LineBreaks lineBreaks, int size) {
+        if (lineBreaks.breaks.length == size) {
+            return;
+        }
+        int[] breaks = new int[size];
+        float[] widths = new float[size];
+        boolean[] flags = new boolean[size];
+
+        int toCopy = Math.min(size, lineBreaks.breaks.length);
+        System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy);
+        System.arraycopy(lineBreaks.widths, 0, widths, 0, toCopy);
+        System.arraycopy(lineBreaks.flags, 0, flags, 0, toCopy);
+
+        lineBreaks.breaks = breaks;
+        lineBreaks.widths = widths;
+        lineBreaks.flags = flags;
+    }
+
+    @NonNull
+    private LineMetrics computeMetrics(int start, int end) {
+        boolean f = false;
+        float w = 0, pw = 0;
+        for (int i = start; i < end; i++) {
+            Primitive p = mPrimitives.get(i);
+            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+                w += p.width;
+                if (p.type == PrimitiveType.BOX) {
+                    pw = w;
+                }
+            } else if (p.type == PrimitiveType.VARIABLE) {
+                w = mTabStops.width(w);
+                f = true;
+            }
+        }
+        return new LineMetrics(w, pw, f);
+    }
+
+    private static float computeDemerits(float maxWidth, float width, boolean finalBreak,
+            float penalty) {
+        float deviation = finalBreak ? 0 : maxWidth - width;
+        return (deviation * deviation) + penalty;
+    }
+
+    /**
+     * @return the last break position or -1 if failed.
+     */
+    @SuppressWarnings("ConstantConditions")  // method too complex to be analyzed.
+    private int desperateBreak(int start, int limit, float maxWidth,
+            @NonNull LineMetrics lineMetrics) {
+        float w = 0, pw = 0;
+        boolean breakFound = false;
+        int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE;
+        for (int i = start; i < limit; i++) {
+            Primitive p = mPrimitives.get(i);
+
+            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
+                w += p.width;
+                if (p.type == PrimitiveType.BOX) {
+                    pw = w;
+                }
+            } else if (p.type == PrimitiveType.VARIABLE) {
+                w = mTabStops.width(w);
+                firstTabIndex = Math.min(firstTabIndex, i);
+            }
+
+            if (pw > maxWidth && breakFound) {
+                break;
+            }
+
+            // must make progress
+            if (i > start &&
+                    (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) {
+                breakFound = true;
+                breakIndex = i;
+            }
+        }
+
+        if (breakFound) {
+            lineMetrics.mWidth = w;
+            lineMetrics.mPrintedWidth = pw;
+            lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex);
+            return breakIndex;
+        } else {
+            return -1;
+        }
+    }
+
+    private static class LineMetrics {
+        /** Actual width of the line. */
+        float mWidth;
+        /** Width of the line minus trailing whitespace. */
+        float mPrintedWidth;
+        boolean mHasTabs;
+
+        public LineMetrics() {
+        }
+
+        public LineMetrics(float width, float printedWidth, boolean hasTabs) {
+            mWidth = width;
+            mPrintedWidth = printedWidth;
+            mHasTabs = hasTabs;
+        }
+    }
+
+    /**
+     * A struct to store the info about a break.
+     */
+    @SuppressWarnings("SpellCheckingInspection")  // For the word struct.
+    private static class Node {
+        // -1 for the first node.
+        int mPrev;
+        // number of breaks so far.
+        int mPrevCount;
+        float mDemerits;
+        float mWidth;
+        boolean mHasTabs;
+
+        public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) {
+            mPrev = prev;
+            mPrevCount = prevCount;
+            mDemerits = demerits;
+            mWidth = width;
+            mHasTabs = hasTabs;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/text/Primitive.java b/tools/layoutlib/bridge/src/android/text/Primitive.java
new file mode 100644
index 0000000..ce77601
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/Primitive.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 android.text;
+
+import com.android.annotations.NonNull;
+
+// Based on the native implementation of Primitive in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class Primitive {
+    public final @NonNull PrimitiveType type;
+    public final int location;
+    // The following fields don't make sense for all types.
+    // Box and Glue have width only.
+    // Penalty has both width and penalty.
+    // Word_break has penalty only.
+    public final float width;
+    public final float penalty;
+
+    /**
+     * Use {@code PrimitiveType#getNewPrimitive()}
+     */
+    private Primitive(@NonNull PrimitiveType type, int location, float width, float penalty) {
+        this.type = type;
+        this.location = location;
+        this.width = width;
+        this.penalty = penalty;
+    }
+
+    public static enum PrimitiveType {
+        /**
+         * Something with a constant width that is to be typeset - like a character.
+         */
+        BOX,
+        /**
+         * Blank space with fixed width.
+         */
+        GLUE,
+        /**
+         * Aesthetic cost indicating how desirable breaking at this point will be. A penalty of
+         * {@link #PENALTY_INFINITY} means a forced non-break, whereas a penalty of negative
+         * {@code #PENALTY_INFINITY} means a forced break.
+         * <p/>
+         * Currently, it only stores penalty with values 0 or -infinity.
+         */
+        PENALTY,
+        /**
+         * For tabs - variable width space.
+         */
+        VARIABLE,
+        /**
+         * Possible breakpoints within a word. Think of this as a high cost {@link #PENALTY}.
+         */
+        WORD_BREAK;
+
+        public Primitive getNewPrimitive(int location) {
+            assert this == VARIABLE;
+            return new Primitive(this, location, 0f, 0f);
+        }
+
+        public Primitive getNewPrimitive(int location, float value) {
+            assert this == BOX || this == GLUE || this == WORD_BREAK;
+            if (this == BOX || this == GLUE) {
+                return new Primitive(this, location, value, 0f);
+            } else {
+                return new Primitive(this, location, 0f, value);
+            }
+        }
+
+        public Primitive getNewPrimitive(int location, float width, float penalty) {
+            assert this == PENALTY;
+            return new Primitive(this, location, width, penalty);
+        }
+
+        // forced non-break, negative infinity is forced break.
+        public static final float PENALTY_INFINITY = 1e7f;
+    }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index b0d79a8..e24b3d5 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -1,12 +1,15 @@
 package android.text;
 
+import com.android.annotations.NonNull;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
-import java.text.CharacterIterator;
-import java.util.Arrays;
-import java.util.Locale;
+import android.text.StaticLayout.LineBreaks;
+import android.text.Primitive.PrimitiveType;
 
-import com.ibm.icu.lang.UCharacter;
+import java.util.ArrayList;
+import java.util.List;
+
 import com.ibm.icu.text.BreakIterator;
 import com.ibm.icu.util.ULocale;
 import javax.swing.text.Segment;
@@ -20,36 +23,112 @@
  */
 public class StaticLayout_Delegate {
 
-    /**
-     * Fills the recycle array with positions that are suitable to break the text at. The array
-     * must be terminated by '-1'.
-     */
+    private static final char CHAR_SPACE     = 0x20;
+    private static final char CHAR_TAB       = 0x09;
+    private static final char CHAR_NEWLINE   = 0x0A;
+    private static final char CHAR_ZWSP      = 0x200B;  // Zero width space.
+
+    // ---- Builder delegate manager ----
+    private static final DelegateManager<Builder> sBuilderManager =
+        new DelegateManager<Builder>(Builder.class);
+
     @LayoutlibDelegate
-    /*package*/ static int[] nLineBreakOpportunities(String locale, char[] text, int length,
-            int[] recycle) {
-        BreakIterator iterator = BreakIterator.getLineInstance(new ULocale(locale));
-        Segment segment = new Segment(text, 0, length);
-        iterator.setText(segment);
-        if (recycle == null) {
-            // Because 42 is the answer to everything.
-            recycle = new int[42];
+    /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
+            int length, float firstWidth, int firstWidthLineCount, float restWidth,
+            int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+            int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
+
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+        // compute all possible breakpoints.
+        BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
+        it.setText(new Segment(inputText, 0, length));
+        // average word length in english is 5. So, initialize the possible breaks with a guess.
+        List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
+        int loc;
+        it.first();
+        while ((loc = it.next()) != BreakIterator.DONE) {
+            breaks.add(loc);
         }
-        int breakOpp = iterator.first();
-        recycle[0] = breakOpp;
-        //noinspection ConstantConditions
-        assert BreakIterator.DONE == -1;
-        for (int i = 1; breakOpp != BreakIterator.DONE; ++i) {
-            if (i >= recycle.length) {
-                recycle = doubleSize(recycle);
-            }
-            assert (i < recycle.length);
-            breakOpp = iterator.next();
-            recycle[i] = breakOpp;
+
+        LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
+        TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
+        List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks);
+        LineBreaker lineBreaker;
+        if (optimize) {
+            lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator);
+        } else {
+            lineBreaker = new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator);
         }
-        return recycle;
+        lineBreaker.computeBreaks(recycle);
+        return recycle.breaks.length;
     }
 
-    private static int[] doubleSize(int[] array) {
-        return Arrays.copyOf(array, array.length * 2);
+    /**
+     * Compute metadata each character - things which help in deciding if it's possible to break
+     * at a point or not.
+     */
+    @NonNull
+    private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths,
+            int length, @NonNull List<Integer> breaks) {
+        // Initialize the list with a guess of the number of primitives:
+        // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars)
+        List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833)));
+        int breaksSize = breaks.size();
+        int breakIndex = 0;
+        for (int i = 0; i < length; i++) {
+            char c = text[i];
+            if (c == CHAR_SPACE || c == CHAR_ZWSP) {
+                primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i]));
+            } else if (c == CHAR_TAB) {
+                primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i));
+            } else if (c != CHAR_NEWLINE) {
+                while (breakIndex < breaksSize && breaks.get(breakIndex) < i) {
+                    breakIndex++;
+                }
+                Primitive p;
+                if (widths[i] != 0) {
+                    if (breakIndex < breaksSize && breaks.get(breakIndex) == i) {
+                        p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0);
+                    } else {
+                        p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0);
+                    }
+                    primitives.add(p);
+                }
+
+                primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i]));
+            }
+        }
+        // final break at end of everything
+        primitives.add(
+                PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
+        return primitives;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static long nNewBuilder() {
+        return sBuilderManager.addNewDelegate(new Builder());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFinishBuilder(long nativeBuilder) {
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nFreeBuilder(long nativeBuilder) {
+        sBuilderManager.removeJavaReferenceFor(nativeBuilder);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+        builder.mLocale = locale;
+    }
+
+    /**
+     * Java representation of the native Builder class. It currently only stores the locale
+     * set by nBuilderSetLocale.
+     */
+    static class Builder {
+        String mLocale;
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/text/TabStops.java b/tools/layoutlib/bridge/src/android/text/TabStops.java
new file mode 100644
index 0000000..cff6b93
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/text/TabStops.java
@@ -0,0 +1,44 @@
+/*
+ * 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.text;
+
+import com.android.annotations.Nullable;
+
+// Based on the native implementation of TabStops in
+// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
+public class TabStops {
+    @Nullable
+    private int[] mStops;
+    private final int mTabWidth;
+
+    public TabStops(@Nullable int[] stops, int defaultTabWidth) {
+        mTabWidth = defaultTabWidth;
+        mStops = stops;
+    }
+
+    public float width(float widthSoFar) {
+        if (mStops != null) {
+            for (int i : mStops) {
+                if (i > widthSoFar) {
+                    return i;
+                }
+            }
+        }
+        // find the next tabStop after widthSoFar.
+        return (int) ((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
deleted file mode 100644
index 8b4c60b..0000000
--- a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.util.FloatMath
- *
- * Through the layoutlib_create tool, the original native methods of FloatMath have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
- * around to map int to instance of the delegate.
- *
- */
-/*package*/ final class FloatMath_Delegate {
-
-    /** Prevents instantiation. */
-    private FloatMath_Delegate() {}
-
-    /**
-     * Returns the float conversion of the most positive (i.e. closest to
-     * positive infinity) integer value which is less than the argument.
-     *
-     * @param value to be converted
-     * @return the floor of value
-     */
-    @LayoutlibDelegate
-    /*package*/ static float floor(float value) {
-        return (float)Math.floor(value);
-    }
-
-    /**
-     * Returns the float conversion of the most negative (i.e. closest to
-     * negative infinity) integer value which is greater than the argument.
-     *
-     * @param value to be converted
-     * @return the ceiling of value
-     */
-    @LayoutlibDelegate
-    /*package*/ static float ceil(float value) {
-        return (float)Math.ceil(value);
-    }
-
-    /**
-     * Returns the closest float approximation of the sine of the argument.
-     *
-     * @param angle to compute the cosine of, in radians
-     * @return the sine of angle
-     */
-    @LayoutlibDelegate
-    /*package*/ static  float sin(float angle) {
-        return (float)Math.sin(angle);
-    }
-
-    /**
-     * Returns the closest float approximation of the cosine of the argument.
-     *
-     * @param angle to compute the cosine of, in radians
-     * @return the cosine of angle
-     */
-    @LayoutlibDelegate
-    /*package*/ static float cos(float angle) {
-        return (float)Math.cos(angle);
-    }
-
-    /**
-     * Returns the closest float approximation of the square root of the
-     * argument.
-     *
-     * @param value to compute sqrt of
-     * @return the square root of value
-     */
-    @LayoutlibDelegate
-    /*package*/ static float sqrt(float value) {
-        return (float)Math.sqrt(value);
-    }
-
-    /**
-     * Returns the closest float approximation of the raising "e" to the power
-     * of the argument.
-     *
-     * @param value to compute the exponential of
-     * @return the exponential of value
-     */
-    @LayoutlibDelegate
-    /*package*/ static float exp(float value) {
-        return (float)Math.exp(value);
-    }
-
-    /**
-     * Returns the closest float approximation of the result of raising {@code
-     * x} to the power of {@code y}.
-     *
-     * @param x the base of the operation.
-     * @param y the exponent of the operation.
-     * @return {@code x} to the power of {@code y}.
-     */
-    @LayoutlibDelegate
-    /*package*/ static float pow(float x, float y) {
-        return (float)Math.pow(x, y);
-    }
-
-    /**
-     * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
-     * {@code y}</i><sup>{@code 2}</sup>{@code )}.
-     *
-     * @param x a float number
-     * @param y a float number
-     * @return the hypotenuse
-     */
-    @LayoutlibDelegate
-    /*package*/ static float hypot(float x, float y) {
-        return (float)Math.sqrt(x*x + y*y);
-    }
-}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 5176419..32305a0 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -215,6 +215,12 @@
     }
 
     @Override
+    public void overridePendingAppTransitionClipReveal(int startX, int startY,
+            int startWidth, int startHeight) throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
             IRemoteCallback startedCallback, boolean scaleUp) throws RemoteException {
         // TODO Auto-generated method stub
@@ -293,7 +299,7 @@
     }
 
     @Override
-    public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
+    public void setAppTask(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
diff --git a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
index 38846bd..a0db7bf 100644
--- a/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/ShadowPainter.java
@@ -65,6 +65,9 @@
     @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
     public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
             float shadowOpacity, int shadowRgb) {
+        if (shadowSize == 0) {
+            return source;
+        }
 
         // This code is based on
         //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 78242a8..823b247 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -120,6 +120,11 @@
     }
 
     @Override
+    public ActionMode onWindowStartingActionMode(Callback callback, int type) {
+        return null;
+    }
+
+    @Override
     public void onActionModeStarted(ActionMode mode) {
 
     }
diff --git a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java b/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
deleted file mode 100644
index 0100dc5..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/policy/PolicyManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderAction;
-
-import android.content.Context;
-import android.view.BridgeInflater;
-import android.view.FallbackEventHandler;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManagerPolicy;
-
-/**
- * Custom implementation of PolicyManager that does nothing to run in LayoutLib.
- *
- */
-public class PolicyManager {
-
-    public static Window makeNewWindow(Context context) {
-        // this will likely crash somewhere beyond so we log it.
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Call to PolicyManager.makeNewWindow is not supported", null);
-        return null;
-    }
-
-    public static LayoutInflater makeNewLayoutInflater(Context context) {
-        return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback());
-    }
-
-    public static WindowManagerPolicy makeNewWindowManager() {
-        // this will likely crash somewhere beyond so we log it.
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Call to PolicyManager.makeNewWindowManager is not supported", null);
-        return null;
-    }
-
-    public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
-        return new FallbackEventHandler() {
-            @Override
-            public void setView(View v) {
-            }
-
-            @Override
-            public void preDispatchKeyEvent(KeyEvent event) {
-            }
-
-            @Override
-            public boolean dispatchKeyEvent(KeyEvent event) {
-                return false;
-            }
-        };
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 4d2c2fc..c6d60f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -181,7 +181,7 @@
      */
     private static LayoutLog sCurrentLog = sDefaultLog;
 
-    private static final int LAST_SUPPORTED_FEATURE = Features.PREFERENCES_RENDERING;
+    private static final int LAST_SUPPORTED_FEATURE = Features.RENDER_ALL_DRAWABLE_STATES;
 
     @Override
     public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index e0f87fd..feb2590 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -86,11 +86,14 @@
     }
 
     @Override
-    public Result render(long timeout) {
+    public Result render(long timeout, boolean forceMeasure) {
         try {
             Bridge.prepareThread();
             mLastResult = mSession.acquire(timeout);
             if (mLastResult.isSuccess()) {
+                if (forceMeasure) {
+                    mSession.invalidateRenderingSize();
+                }
                 mLastResult = mSession.render(false /*freshRender*/);
             }
         } finally {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index aa4b560..179a8e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -16,7 +16,6 @@
 
 package com.android.layoutlib.bridge.android;
 
-import android.os.IBinder;
 import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -64,6 +63,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
@@ -73,6 +73,7 @@
 import android.view.BridgeInflater;
 import android.view.Display;
 import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -496,6 +497,34 @@
         throw new UnsupportedOperationException("Unsupported Service: " + service);
     }
 
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        if (serviceClass.equals(LayoutInflater.class)) {
+            return LAYOUT_INFLATER_SERVICE;
+        }
+
+        if (serviceClass.equals(TextServicesManager.class)) {
+            return TEXT_SERVICES_MANAGER_SERVICE;
+        }
+
+        if (serviceClass.equals(WindowManager.class)) {
+            return WINDOW_SERVICE;
+        }
+
+        if (serviceClass.equals(PowerManager.class)) {
+            return POWER_SERVICE;
+        }
+
+        if (serviceClass.equals(DisplayManager.class)) {
+            return DISPLAY_SERVICE;
+        }
+
+        if (serviceClass.equals(AccessibilityManager.class)) {
+            return ACCESSIBILITY_SERVICE;
+        }
+
+        throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
+    }
 
     @Override
     public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
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 0f51d00..4289689 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
@@ -191,12 +191,6 @@
     }
 
     @Override
-    public void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
-            float dsdx, float dtdx, float dsdy, float dtdy) {
-        // pass for now.
-    }
-
-    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
@@ -212,4 +206,9 @@
         // pass for now.
         return null;
     }
+
+    @Override
+    public void pokeDrawLock(IBinder window) {
+        // pass for now.
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
new file mode 100644
index 0000000..2f45473
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -0,0 +1,41 @@
+/*
+ * 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.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.SessionParams.Key;
+
+/**
+ * This contains all known keys for the {@link RenderParams#getFlag(Key)}.
+ * <p/>
+ * The IDE has its own copy of this class which may be newer or older than this one.
+ * <p/>
+ * Constants should never be modified or removed from this class.
+ */
+public final class RenderParamsFlags {
+
+    public static final Key<String> FLAG_KEY_ROOT_TAG =
+            new Key<String>("rootTag", String.class);
+    public static final Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+            new Key<Boolean>("disableBitmapCaching", Boolean.class);
+    public static final Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
+            new Key<Boolean>("recyclerViewSupport", Boolean.class);
+    public static final Key<Boolean> FLAG_KEY_RENDER_ALL_DRAWABLE_STATES =
+            new Key<Boolean>("renderAllDrawableStates", Boolean.class);
+
+    // Disallow instances.
+    private RenderParamsFlags() {}
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
deleted file mode 100644
index 22b5192..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ /dev/null
@@ -1,37 +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.layoutlib.bridge.android;
-
-import com.android.ide.common.rendering.api.SessionParams;
-
-/**
- * This contains all known keys for the {@link SessionParams#getFlag(SessionParams.Key)}.
- * <p/>
- * The IDE has its own copy of this class which may be newer or older than this one.
- * <p/>
- * Constants should never be modified or removed from this class.
- */
-public final class SessionParamsFlags {
-
-    public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
-            new SessionParams.Key<String>("rootTag", String.class);
-    public static final SessionParams.Key<Boolean> FLAG_KEY_RECYCLER_VIEW_SUPPORT =
-            new SessionParams.Key<Boolean>("recyclerViewSupport", Boolean.class);
-
-    // Disallow instances.
-    private SessionParamsFlags() {}
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index 1d47333..b72329a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -23,7 +23,7 @@
 import com.android.ide.common.rendering.api.SessionParams;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 
 import android.content.Context;
 import android.view.View;
@@ -104,7 +104,7 @@
 
     @Nullable
     private static Object createAdapter(@NonNull SessionParams params) throws ReflectionException {
-        Boolean ideSupport = params.getFlag(SessionParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
+        Boolean ideSupport = params.getFlag(RenderParamsFlags.FLAG_KEY_RECYCLER_VIEW_SUPPORT);
         if (ideSupport != Boolean.TRUE) {
             return null;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 3a0321a..c34f9b5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -35,6 +35,7 @@
 import java.awt.Color;
 import java.awt.Composite;
 import java.awt.Graphics2D;
+import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
@@ -615,8 +616,22 @@
                 return;
             }
 
-            int width = layer.getImage().getWidth();
-            int height = layer.getImage().getHeight();
+            int width;
+            int height;
+            Rectangle clipBounds = originalGraphics.getClipBounds();
+            if (clipBounds != null) {
+                if (clipBounds.width == 0 || clipBounds.height == 0) {
+                    // Clip is 0 so no need to paint anything.
+                    return;
+                }
+                // If we have clipBounds available, use them as they will always be
+                // smaller than the full layer size.
+                width = clipBounds.width;
+                height = clipBounds.height;
+            } else {
+                width = layer.getImage().getWidth();
+                height = layer.getImage().getHeight();
+            }
 
             // Create a temporary image to which the color filter will be applied.
             BufferedImage image = new BufferedImage(width, height,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 6513c5f..3dee1e2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -22,12 +22,14 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
 import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.resources.ResourceType;
 
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
 import android.view.AttachInfo_Accessor;
 import android.view.View.MeasureSpec;
 import android.widget.FrameLayout;
@@ -36,6 +38,9 @@
 import java.awt.Color;
 import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
@@ -68,11 +73,37 @@
             return Status.ERROR_NOT_A_DRAWABLE.createResult();
         }
 
+        Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+
+        final Boolean allStates =
+                params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES);
+        if (allStates == Boolean.TRUE) {
+            final List<BufferedImage> result;
+
+            if (d instanceof StateListDrawable) {
+                result = new ArrayList<BufferedImage>();
+                final StateListDrawable stateList = (StateListDrawable) d;
+                for (int i = 0; i < stateList.getStateCount(); i++) {
+                    final Drawable stateDrawable = stateList.getStateDrawable(i);
+                    result.add(renderImage(hardwareConfig, stateDrawable, context));
+                }
+            } else {
+                result = Collections.singletonList(renderImage(hardwareConfig, d, context));
+            }
+
+            return Status.SUCCESS.createResult(result);
+        } else {
+            BufferedImage image = renderImage(hardwareConfig, d, context);
+            return Status.SUCCESS.createResult(image);
+        }
+    }
+
+    private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d,
+            BridgeContext context) {
         // create a simple FrameLayout
         FrameLayout content = new FrameLayout(context);
 
         // get the actual Drawable object to draw
-        Drawable d = ResourceHelper.getDrawable(drawableResource, context);
         content.setBackground(d);
 
         // set the AttachInfo on the root view.
@@ -80,8 +111,27 @@
 
 
         // measure
-        int w = hardwareConfig.getScreenWidth();
-        int h = hardwareConfig.getScreenHeight();
+        int w = d.getIntrinsicWidth();
+        int h = d.getIntrinsicHeight();
+
+        final int screenWidth = hardwareConfig.getScreenWidth();
+        final int screenHeight = hardwareConfig.getScreenHeight();
+
+        if (w == -1 || h == -1) {
+            // Use screen size when either intrinsic width or height isn't available
+            w = screenWidth;
+            h = screenHeight;
+        } else if (w > screenWidth || h > screenHeight) {
+            // If image wouldn't fit to the screen, resize it to avoid cropping.
+
+            // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight
+            double scale = Math.min((double) screenWidth / w, (double) screenHeight / h);
+
+            // scale * w / scale * h = w / h, so, proportions are preserved.
+            w = (int) Math.floor(scale * w);
+            h = (int) Math.floor(scale * h);
+        }
+
         int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
         int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
         content.measure(w_spec, h_spec);
@@ -105,8 +155,7 @@
 
         // and draw
         content.draw(canvas);
-
-        return Status.SUCCESS.createResult(image);
+        return image;
     }
 
     protected BufferedImage getImage(int w, int h) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index b6b63b1..c9aa400 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -52,7 +52,7 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.android.RenderParamsFlags;
 import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
 import com.android.layoutlib.bridge.bars.BridgeActionBar;
 import com.android.layoutlib.bridge.bars.AppCompatActionBar;
@@ -403,7 +403,7 @@
             // it can instantiate the custom Fragment.
             Fragment_Delegate.setProjectCallback(params.getProjectCallback());
 
-            String rootTag = params.getFlag(SessionParamsFlags.FLAG_KEY_ROOT_TAG);
+            String rootTag = params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG);
             boolean isPreference = "PreferenceScreen".equals(rootTag);
             View view;
             if (isPreference) {
@@ -554,7 +554,14 @@
                 // draw the views
                 // create the BufferedImage into which the layout will be rendered.
                 boolean newImage = false;
-                if (newRenderSize || mCanvas == null) {
+
+                // When disableBitmapCaching is true, we do not reuse mImage and
+                // we create a new one in every render.
+                // This is useful when mImage is just a wrapper of Graphics2D so
+                // it doesn't get cached.
+                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
+                    RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
                     if (params.getImageFactory() != null) {
                         mImage = params.getImageFactory().getImage(
                                 mMeasuredScreenWidth,
@@ -581,8 +588,12 @@
                     Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
                             true /*isMutable*/, hardwareConfig.getDensity());
 
-                    // create a Canvas around the Android bitmap
-                    mCanvas = new Canvas(bitmap);
+                    if (mCanvas == null) {
+                        // create a Canvas around the Android bitmap
+                        mCanvas = new Canvas(bitmap);
+                    } else {
+                        mCanvas.setBitmap(bitmap);
+                    }
                     mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
                 }
 
@@ -1634,7 +1645,7 @@
         return null;
     }
 
-    private void invalidateRenderingSize() {
+    public void invalidateRenderingSize() {
         mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 98acd2f..f5e8292 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -230,7 +230,6 @@
         "android.os.SystemProperties",
         "android.text.AndroidBidi",
         "android.text.StaticLayout",
-        "android.util.FloatMath",
         "android.view.Display",
         "libcore.icu.DateIntervalFormat",
         "libcore.icu.ICU",
@@ -255,7 +254,6 @@
             "android.view.SurfaceView",                        "android.view._Original_SurfaceView",
             "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
             "android.webkit.WebView",                          "android.webkit._Original_WebView",
-            "com.android.internal.policy.PolicyManager",       "com.android.internal.policy._Original_PolicyManager",
         };
 
     /**
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index 9ff56d6..1b1f63e 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_SRC_FILES := \
 	Main.cpp
 
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
 
 #LOCAL_C_INCLUDES +=
 
@@ -36,10 +36,9 @@
 
 LOCAL_MODULE := pbkdf2gen
 LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
 LOCAL_SRC_FILES := pbkdf2gen.cpp
 LOCAL_LDLIBS += -ldl
-LOCAL_C_INCLUDES := external/openssl/include $(LOCAL_C_INCLUDES)
 LOCAL_STATIC_LIBRARIES := libcrypto_static
 
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index b2152e8..64808c0 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -89,7 +89,7 @@
         "   Prints the OBB signature information of a file.\n\n", gProgName);
 }
 
-void doAdd(const char* filename, struct PackageInfo* info) {
+void doAdd(const char* filename, PackageInfo* info) {
     ObbFile *obb = new ObbFile();
     if (obb->readFrom(filename)) {
         fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
@@ -182,7 +182,7 @@
 {
     int opt;
     int option_index = 0;
-    struct PackageInfo package_info;
+    PackageInfo package_info;
 
     int result = 1;    // pessimistically assume an error.
 
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 533b8bc..6263463 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -21,37 +21,37 @@
 
 /**
  * Record of energy and activity information from controller and
- * underlying wifi stack state.Timestamp the record with system
- * time
+ * underlying wifi stack state. Timestamp the record with elapsed
+ * real-time.
  * @hide
  */
 public final class WifiActivityEnergyInfo implements Parcelable {
+    private final long mTimestamp;
     private final int mStackState;
     private final int mControllerTxTimeMs;
     private final int mControllerRxTimeMs;
     private final int mControllerIdleTimeMs;
     private final int mControllerEnergyUsed;
-    private final long timestamp;
 
     public static final int STACK_STATE_INVALID = 0;
     public static final int STACK_STATE_STATE_ACTIVE = 1;
     public static final int STACK_STATE_STATE_SCANNING = 2;
     public static final int STACK_STATE_STATE_IDLE = 3;
 
-    public WifiActivityEnergyInfo(int stackState, int txTime, int rxTime,
-                                  int idleTime, int energyUsed) {
+    public WifiActivityEnergyInfo(long timestamp, int stackState,
+                                  int txTime, int rxTime, int idleTime, int energyUsed) {
+        mTimestamp = timestamp;
         mStackState = stackState;
         mControllerTxTimeMs = txTime;
         mControllerRxTimeMs = rxTime;
         mControllerIdleTimeMs = idleTime;
         mControllerEnergyUsed = energyUsed;
-        timestamp = System.currentTimeMillis();
     }
 
     @Override
     public String toString() {
         return "WifiActivityEnergyInfo{"
-            + " timestamp=" + timestamp
+            + " timestamp=" + mTimestamp
             + " mStackState=" + mStackState
             + " mControllerTxTimeMs=" + mControllerTxTimeMs
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
@@ -63,13 +63,14 @@
     public static final Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
             new Parcelable.Creator<WifiActivityEnergyInfo>() {
         public WifiActivityEnergyInfo createFromParcel(Parcel in) {
+            long timestamp = in.readLong();
             int stackState = in.readInt();
             int txTime = in.readInt();
             int rxTime = in.readInt();
             int idleTime = in.readInt();
             int energyUsed = in.readInt();
-            return new WifiActivityEnergyInfo(stackState, txTime, rxTime,
-                    idleTime, energyUsed);
+            return new WifiActivityEnergyInfo(timestamp, stackState,
+                    txTime, rxTime, idleTime, energyUsed);
         }
         public WifiActivityEnergyInfo[] newArray(int size) {
             return new WifiActivityEnergyInfo[size];
@@ -77,6 +78,7 @@
     };
 
     public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mTimestamp);
         out.writeInt(mStackState);
         out.writeInt(mControllerTxTimeMs);
         out.writeInt(mControllerRxTimeMs);
@@ -127,7 +129,7 @@
      * @return timestamp(wall clock) of record creation
      */
     public long getTimeStamp() {
-        return timestamp;
+        return mTimestamp;
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 872eb6f..7e04f2b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -17,6 +17,7 @@
 package android.net.wifi;
 
 import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.ProxyInfo;
@@ -397,12 +398,34 @@
 
     /**
      * @hide
+     * Universal name for app creating the configuration
+     *    see {#link {@link PackageManager#getNameForUid(int)}
+     */
+    @SystemApi
+    public String creatorName;
+
+    /**
+     * @hide
+     * Universal name for app updating the configuration
+     *    see {#link {@link PackageManager#getNameForUid(int)}
+     */
+    @SystemApi
+    public String lastUpdateName;
+
+    /**
+     * @hide
      * Uid used by autoJoin
      */
     public String autoJoinBSSID;
 
     /**
      * @hide
+     * Status of user approval for connection
+     */
+    public int userApproved = USER_UNSPECIFIED;
+
+    /**
+     * @hide
      * BSSID list on which this configuration was seen.
      * TODO: prevent this list to grow infinitely, age-out the results
      */
@@ -648,6 +671,28 @@
     /** @hide */
     public static final int AUTO_JOIN_DELETED  = 200;
 
+    // States for the userApproved field
+    /**
+     * @hide
+     * User hasn't specified if connection is okay
+     */
+    public static final int USER_UNSPECIFIED = 0;
+    /**
+     * @hide
+     * User has approved this for connection
+     */
+    public static final int USER_APPROVED = 1;
+    /**
+     * @hide
+     * User has banned this from connection
+     */
+    public static final int USER_BANNED = 2;
+    /**
+     * @hide
+     * Waiting for user input
+     */
+    public static final int USER_PENDING = 3;
+
     /**
      * @hide
      */
@@ -901,6 +946,8 @@
         ephemeral = false;
         validatedInternetAccess = false;
         mIpConfiguration = new IpConfiguration();
+        lastUpdateUid = -1;
+        creatorUid = -1;
     }
 
     /**
@@ -956,6 +1003,15 @@
     }
 
     /**
+     * Helper function, idenfity if a configuration should be treated as an enterprise network
+     * @hide
+     */
+    public boolean isEnterprise() {
+        return allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+            allowedKeyManagement.get(KeyMgmt.IEEE8021X);
+    }
+
+    /**
      * most recent time we have seen this configuration
      * @return most recent scanResult
      * @hide
@@ -1173,7 +1229,6 @@
         sbuf.append("IP config:\n");
         sbuf.append(mIpConfiguration.toString());
 
-        if (this.creatorUid != 0)  sbuf.append(" uid=" + Integer.toString(creatorUid));
         if (this.autoJoinBSSID != null) sbuf.append(" autoJoinBSSID=" + autoJoinBSSID);
         long now_ms = System.currentTimeMillis();
         if (this.blackListTimestamp != 0) {
@@ -1185,6 +1240,12 @@
                 sbuf.append(" blackListed: ").append(Long.toString(diff/1000)).append( "sec");
             }
         }
+        if (creatorUid != 0)  sbuf.append(" cuid=" + Integer.toString(creatorUid));
+        if (creatorName != null) sbuf.append(" cname=" + creatorName);
+        if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
+        if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
+        sbuf.append("userApproved=" + userApprovedAsString(userApproved));
+
         if (this.lastConnected != 0) {
             sbuf.append('\n');
             long diff = now_ms - this.lastConnected;
@@ -1321,6 +1382,20 @@
         return SSID;
     }
 
+    /** @hide **/
+    public static String userApprovedAsString(int userApproved) {
+        switch (userApproved) {
+            case USER_APPROVED:
+                return "USER_APPROVED";
+            case USER_BANNED:
+                return "USER_BANNED";
+            case USER_UNSPECIFIED:
+                return "USER_UNSPECIFIED";
+            default:
+                return "INVALID";
+        }
+    }
+
     /**
      * Get an identifier for associating credentials with this config
      * @param current configuration contains values for additional fields
@@ -1591,6 +1666,8 @@
             lastConnectUid = source.lastConnectUid;
             lastUpdateUid = source.lastUpdateUid;
             creatorUid = source.creatorUid;
+            creatorName = source.creatorName;
+            lastUpdateName = source.lastUpdateName;
             peerWifiConfiguration = source.peerWifiConfiguration;
             blackListTimestamp = source.blackListTimestamp;
             lastConnected = source.lastConnected;
@@ -1617,6 +1694,7 @@
                     = source.autoJoinUseAggressiveJoinAttemptThreshold;
             autoJoinBailedDueToLowRssi = source.autoJoinBailedDueToLowRssi;
             dirty = source.dirty;
+            userApproved = source.userApproved;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
         }
     }
@@ -1672,6 +1750,8 @@
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
+        dest.writeString(creatorName);
+        dest.writeString(lastUpdateName);
         dest.writeLong(blackListTimestamp);
         dest.writeLong(lastConnectionFailure);
         dest.writeLong(lastRoamingFailure);
@@ -1692,6 +1772,7 @@
         dest.writeInt(numUserTriggeredJoinAttempts);
         dest.writeInt(autoJoinUseAggressiveJoinAttemptThreshold);
         dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0);
+        dest.writeInt(userApproved);
         dest.writeInt(numNoInternetAccessReports);
     }
 
@@ -1743,6 +1824,8 @@
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();
+                config.creatorName = in.readString();
+                config.lastUpdateName = in.readString();
                 config.blackListTimestamp = in.readLong();
                 config.lastConnectionFailure = in.readLong();
                 config.lastRoamingFailure = in.readLong();
@@ -1763,6 +1846,7 @@
                 config.numUserTriggeredJoinAttempts = in.readInt();
                 config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
                 config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
+                config.userApproved = in.readInt();
                 config.numNoInternetAccessReports = in.readInt();
                 return config;
             }
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
index 7fac7cf..1de4fd8 100644
--- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -18,12 +18,6 @@
 
 import android.os.Parcelable;
 import android.os.Parcel;
-import android.text.TextUtils;
-import java.util.HashMap;
-import java.util.Date;
-import java.util.ArrayList;
-
-import java.util.BitSet;
 
 /**
  * A class representing link layer statistics collected over a Wifi Interface.
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 40d40bb..b292c22 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -86,6 +86,28 @@
     public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
 
     /**
+     * Broadcast intent action indicating that the credential of a Wi-Fi network
+     * has been changed. One extra provides the ssid of the network. Another
+     * extra provides the event type, whether the credential is saved or forgot.
+     * @hide
+     */
+    @SystemApi
+    public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
+            "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+    /** @hide */
+    @SystemApi
+    public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+    /** @hide */
+    @SystemApi
+    public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+    /** @hide */
+    @SystemApi
+    public static final int WIFI_CREDENTIAL_SAVED = 0;
+    /** @hide */
+    @SystemApi
+    public static final int WIFI_CREDENTIAL_FORGOT = 1;
+
+    /**
      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
      * enabling, disabling, or unknown. One extra provides this state as an int.
      * Another extra provides the previous state, if available.
diff --git a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
index c7d62e5..9b2fdc8 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConnectionStatistics.java
@@ -21,8 +21,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.HashMap;
-
 /**
  * Connection Statistics For a WiFi Network.
  * @hide
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index fea934f..cecd738 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -417,11 +417,6 @@
         public void onPeriodChanged(int periodInMs);
         /**
          * reports results retrieved from background scan and single shot scans
-         * @deprecated in favor of {@link #onResults(ScanData[])}
-         */
-        public void onResults(ScanResult[] results);
-        /**
-         * reports results retrieved from background scan and single shot scans
          */
         public void onResults(ScanData[] results);
         /**
@@ -452,12 +447,12 @@
     }
     /**
      * reports currently available scan results on appropriate listeners
+     * @return true if all scan results were reported correctly
      */
-    public ScanResult[] getScanResults() {
+    public boolean getScanResults() {
         validateChannel();
         Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
-        // return reply.what == CMD_OP_SUCCEEDED;
-        return null;
+        return reply.what == CMD_OP_SUCCEEDED;
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index d65d03e..92c7e36 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -77,6 +77,7 @@
 
     public boolean setDeviceType(int deviceType) {
         if (deviceType >= WFD_SOURCE && deviceType <= SOURCE_OR_PRIMARY_SINK) {
+            mDeviceInfo &= ~DEVICE_TYPE;
             mDeviceInfo |= deviceType;
             return true;
         }
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 0a7230f..a100aed 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -20,9 +20,7 @@
 import android.os.Parcelable;
 import android.os.Parcel;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
index bbf5fc6..427c84c 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
@@ -18,8 +18,6 @@
 
 import android.os.Parcelable;
 import android.os.Parcel;
-import android.util.Log;
-
 import java.util.HashMap;
 
 /**
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
index f84ac88..c08877e 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
@@ -17,7 +17,6 @@
 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;
@@ -25,7 +24,6 @@
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.util.List;
 
 
 /** @hide */